Fixture 40

quickselect

C · 2 functions · 4 lanes · 8 of 8 function-lanes behave identically

All 4 lanes recompile and return the same results as the original.

Iterative quickselect for the k-th smallest element, plus a median helper. The loop narrows [low, high] from both ends, so the recovered code must keep two independent induction variables and a data-dependent exit.

tests/decompiler_fixtures/src/40_quickselect.c source
#include <stdint.h>

/* Iterative quickselect for the k-th smallest element, plus a median helper.
 * The loop narrows [low, high] from both ends, so the recovered code must keep
 * two independent induction variables and a data-dependent exit. */

#define QSEL_MAX 16

__attribute__((noinline)) int32_t
quickselect_kth(int32_t *values, int32_t count, int32_t k) {
    int32_t low = 0;
    int32_t high;
    int32_t guard;
    if (values == 0 || count <= 0 || count > QSEL_MAX || k < 0 || k >= count) {
        return -1;
    }
    high = count - 1;
    for (guard = 0; guard < QSEL_MAX * 2 && low < high; ++guard) {
        int32_t pivot = values[high];
        int32_t boundary = low;
        int32_t scan;
        for (scan = low; scan < high; ++scan) {
            if (values[scan] <= pivot) {
                int32_t swap = values[boundary];
                values[boundary] = values[scan];
                values[scan] = swap;
                boundary += 1;
            }
        }
        values[high] = values[boundary];
        values[boundary] = pivot;
        if (boundary == k) {
            return values[boundary];
        }
        if (k < boundary) {
            high = boundary - 1;
        } else {
            low = boundary + 1;
        }
    }
    return values[low];
}

__attribute__((noinline)) int32_t
median_of_three(int32_t a, int32_t b, int32_t c) {
    if ((a >= b && a <= c) || (a <= b && a >= c)) {
        return a;
    }
    if ((b >= a && b <= c) || (b <= a && b >= c)) {
        return b;
    }
    return c;
}

Recovered C

Generated by glaurung decompile --style decbench at b47f6b43. baseline.json records the result after recompiling the C and calling it beside the original with seeded inputs.

clang -O0

2/2
median_of_three pass 39 lines
// glaurung: median_of_three @ 0x12b0
int32_t median_of_three(int32_t arg0, int32_t arg1, int32_t arg2) {
    int local_4;
    if ((arg1 <= arg0)) {
        if ((((unsigned int)(arg0) == (unsigned int)(arg2)) | (arg0 < arg2))) {
            goto L_12ed;
        }
    }
    if (((((unsigned int)(arg0) == (unsigned int)(arg1)) | (arg0 < arg1)) == 0)) {
        goto L_12f8;
    }
    if ((arg0 < arg2)) {
        goto L_12f8;
    }
    L_12ed: ;
    local_4 = arg0;
    // x86-64 epilogue: restore rbp
    return (unsigned int)(local_4);
    L_12f8: ;
    if ((arg0 <= arg1)) {
        if ((((unsigned int)(arg1) == (unsigned int)(arg2)) | (arg1 < arg2))) {
            goto L_1328;
        }
    }
    if (((((unsigned int)(arg1) == (unsigned int)(arg0)) | (arg1 < arg0)) == 0)) {
        goto L_1333;
    }
    if ((arg1 < arg2)) {
        goto L_1333;
    }
    L_1328: ;
    local_4 = arg1;
    // x86-64 epilogue: restore rbp
    return (unsigned int)(local_4);
    L_1333: ;
    local_4 = arg2;
    // x86-64 epilogue: restore rbp
    return (unsigned int)(local_4);
}
quickselect_kth pass 79 lines
// glaurung: quickselect_kth @ 0x1100
int32_t quickselect_kth(int32_t * arg0, int32_t arg1, int32_t arg2) {
    int low;
    int high;
    int guard;
    int pivot;
    int boundary;
    int scan;
    int swap;
    signed char local_35;
    int local_4;
    long var19;
    low = 0;
    if ((arg0 != 0)) {
        if (((((unsigned long)((unsigned int)(arg1)) == 0) | ((long)(arg1) < 0)) == 0)) {
            if (((((unsigned long)((unsigned int)(arg1)) == 16) | ((long)(arg1) < 16)) != 0)) {
                if ((0 <= (long)(arg2))) {
                    if ((arg2 < arg1)) {
                        goto L_1156;
                    }
                }
            }
        }
    }
    local_4 = -1;
    // x86-64 epilogue: restore rbp
    return (unsigned int)(local_4);
    L_1156: ;
    high = ((unsigned int)(arg1) - 1);
    guard = 0;
    L_1166: ;
    local_35 = 0;
    if (((long)(guard) < 32)) {
        local_35 = (low < high);
    }
    if (((unsigned long)((unsigned char)((local_35 & 1))) == 0)) {
        goto L_1292;
    }
    pivot = arg0[(long)(high)];
    boundary = low;
    scan = low;
    L_11ab: ;
    if ((high <= scan)) {
        goto L_1219;
    }
    var19 = (unsigned long)((unsigned int)(arg0[(long)(scan)]));
    if (((((unsigned int)(var19) == (unsigned int)(pivot)) | ((long)((int)(var19)) < (long)(pivot))) != 0)) {
        swap = arg0[(long)(boundary)];
        arg0[(long)(boundary)] = arg0[(long)(scan)];
        arg0[(long)(scan)] = swap;
        boundary = ((unsigned int)(boundary) + 1);
    }
    goto L_120b;
    L_120b: ;
    scan = ((unsigned int)(scan) + 1);
    goto L_11ab;
    L_1219: ;
    arg0[(long)(high)] = arg0[(long)(boundary)];
    arg0[(long)(boundary)] = pivot;
    if (((unsigned int)(boundary) == (unsigned int)(arg2))) {
        local_4 = arg0[(long)(boundary)];
        // x86-64 epilogue: restore rbp
        return (unsigned int)(local_4);
    }
    if ((arg2 < boundary)) {
        high = ((unsigned int)(boundary) - 1);
        goto L_127f;
    }
    low = ((unsigned int)(boundary) + 1);
    L_127f: ;
    goto L_1284;
    L_1284: ;
    guard = ((unsigned int)(guard) + 1);
    goto L_1166;
    L_1292: ;
    local_4 = arg0[(long)(low)];
    // x86-64 epilogue: restore rbp
    return (unsigned int)(local_4);
}

clang -O2

2/2
median_of_three pass 24 lines
// glaurung: median_of_three @ 0x1210
int32_t median_of_three(int32_t arg0, int32_t arg1, int32_t arg2) {
    long ret;
    int var2;
    ret = (unsigned long)((unsigned int)(arg0));
    if ((arg0 < arg1)) {
        goto L_121b;
    }
    if (((((unsigned int)(ret) == (unsigned int)(arg2)) | ((long)((int)(ret)) < (long)(arg2))) == 0)) {
        goto L_121b;
    }
    L_121a: ;
    return ret;
    L_121b: ;
    if (((((unsigned int)(ret) == (unsigned int)(arg1)) | ((long)((int)(ret)) < (long)(arg1))) == 0)) {
        var2 = (((long)((int)(ret)) < (long)(arg1)) ? arg2 : ((arg1 < arg2) ? arg2 : (unsigned long)((unsigned int)(arg1))));
        return (unsigned int)(((((unsigned int)(ret) == (unsigned int)(arg1)) | ((long)((int)(ret)) < (long)(arg1))) == 0) ? var2 : (((((unsigned int)(arg1) == (unsigned int)(arg2)) | (arg1 < arg2)) == 0) ? var2 : (unsigned long)((unsigned int)(arg1))));
    }
    if (((long)(arg2) <= (long)((int)(ret)))) {
        goto L_121a;
    }
    var2 = (((long)((int)(ret)) < (long)(arg1)) ? arg2 : ((arg1 < arg2) ? arg2 : (unsigned long)((unsigned int)(arg1))));
    return (unsigned int)(((((unsigned int)(ret) == (unsigned int)(arg1)) | ((long)((int)(ret)) < (long)(arg1))) == 0) ? var2 : (((((unsigned int)(arg1) == (unsigned int)(arg2)) | (arg1 < arg2)) == 0) ? var2 : (unsigned long)((unsigned int)(arg1))));
}
quickselect_kth pass 133 lines
// glaurung: quickselect_kth @ 0x1100
int32_t quickselect_kth(int32_t * arg0, int32_t arg1, int32_t arg2) {
    int pivot;
    int boundary;
    int high;
    int guard;
    int swap;
    long var0;
    long var11;
    long var12;
    long var14;
    long var15;
    long var19;
    long var21;
    long var23;
    long var24;
    long var28;
    long var29;
    long var3;
    int var35;
    long var37;
    long var38;
    long var4;
    long var40;
    long var43;
    long var45;
    long var9;
    var0 = 0xffffffff;
    pivot = 0xffffffff;
    if ((arg1 <= arg2)) {
        // x86-64 epilogue: tear down frame
        return pivot;
    }
    pivot = var0;
    if (((long)(arg2) < 0)) {
        // x86-64 epilogue: tear down frame
        return pivot;
    }
    pivot = var0;
    if ((arg0 == 0)) {
        // x86-64 epilogue: tear down frame
        return pivot;
    }
    pivot = var0;
    if (((unsigned long)((unsigned long)((unsigned int)((arg1 - 17)))) < (unsigned long)(0xfffffff0))) {
        // x86-64 epilogue: tear down frame
        return pivot;
    }
    var3 = 0;
    var4 = 0;
    if (((unsigned long)((unsigned long)((unsigned int)(arg1))) < (unsigned long)(2))) {
        // x86-64 epilogue: tear down frame
        return (unsigned int)(*(int *)(((long)arg0 + var4 * 4)));
    }
    var9 = 0;
    boundary = var3;
    var11 = (unsigned long)((unsigned int)((arg1 - 1)));
    L_1140: ;
    var12 = (long)((int)(var11));
    pivot = (unsigned long)((unsigned int)(arg0[(long)((int)(var11))]));
    var14 = (unsigned long)((unsigned int)(boundary));
    if (((long)((int)(var11)) <= (long)(boundary))) {
        goto L_1189;
    }
    var15 = (long)(boundary);
    var19 = (long)(boundary);
    var14 = (unsigned long)((unsigned int)(boundary));
    if (((unsigned long)((unsigned char)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var11)) - boundary))) & 1))) != 0)) {
        var21 = (unsigned long)((unsigned int)(*(int *)(((long)arg0 + var15 * 4))));
        var23 = (unsigned long)((unsigned int)(boundary));
        if (((((unsigned int)(var21) == (unsigned int)(pivot)) | ((long)((int)(var21)) < (long)(pivot))) != 0)) {
            var24 = (unsigned long)((unsigned int)(*(int *)(((long)arg0 + var15 * 4))));
            *(int *)(((long)arg0 + var15 * 4)) = var21;
            *(int *)(((long)arg0 + var15 * 4)) = var24;
            var23 = (unsigned long)((unsigned int)((boundary + 1)));
        }
        var19 = (var15 + 1);
        var14 = var23;
    }
    var28 = var14;
    var29 = var19;
    if ((((~var15) + var12) != 0)) {
        goto L_11c9;
    }
    L_1189: ;
    *(int *)(((long)arg0 + var12 * 4)) = arg0[(long)((int)(var14))];
    arg0[(long)((int)(var14))] = pivot;
    if (((unsigned int)(var14) == (unsigned int)(arg2))) {
        // x86-64 epilogue: tear down frame
        return pivot;
    }
    high = (((((unsigned int)(var14) == (unsigned int)(arg2)) | ((long)((int)(var14)) < (long)(arg2))) == 0) ? (unsigned long)((unsigned int)((var14 - 1))) : var11);
    var35 = ((((unsigned int)(var14) == (unsigned int)(arg2)) | ((long)((int)(var14)) < (long)(arg2))) ? (unsigned long)((unsigned int)((var14 + 1))) : boundary);
    if (((unsigned long)(30) < (unsigned long)((unsigned long)((unsigned int)(var9))))) {
        var4 = (long)((int)(var35));
        // x86-64 epilogue: tear down frame
        return (unsigned int)(arg0[(long)((int)(var35))]);
    }
    var9 = (unsigned long)((unsigned int)((var9 + 1)));
    boundary = var35;
    var11 = (unsigned long)((unsigned int)(high));
    if ((var35 < high)) {
        goto L_1140;
    }
    var4 = (long)((int)(var35));
    // x86-64 epilogue: tear down frame
    return (unsigned int)(arg0[(long)((int)(var35))]);
    L_11c0: ;
    var29 = (var29 + 2);
    var14 = var28;
    if ((var12 == var29)) {
        goto L_1189;
    }
    L_11c9: ;
    var37 = (unsigned long)((unsigned int)(*(int *)(((long)arg0 + var29 * 4))));
    var38 = var28;
    if (((((unsigned int)(var37) == (unsigned int)(pivot)) | ((long)((int)(var37)) < (long)(pivot))) != 0)) {
        var40 = (unsigned long)((unsigned int)(arg0[(long)((int)(var28))]));
        arg0[(long)((int)(var28))] = var37;
        *(int *)(((long)arg0 + var29 * 4)) = var40;
        var38 = (unsigned long)((unsigned int)(((long)((int)(var28)) + 1)));
    }
    var43 = (unsigned long)((unsigned int)(*(int *)(((long)arg0 + var29 * 4 + 0x4))));
    var28 = var38;
    if (((((unsigned int)(var43) == (unsigned int)(pivot)) | ((long)((int)(var43)) < (long)(pivot))) == 0)) {
        goto L_11c0;
    }
    var45 = (unsigned long)((unsigned int)(arg0[(long)((int)(var38))]));
    arg0[(long)((int)(var38))] = var43;
    *(int *)(((long)arg0 + var29 * 4 + 0x4)) = var45;
    var28 = (unsigned long)((unsigned int)(((long)((int)(var38)) + 1)));
    goto L_11c0;
}

gcc -O0

2/2
median_of_three pass 34 lines
// glaurung: median_of_three @ 0x12ba
int32_t median_of_three(int32_t arg0, int32_t arg1, int32_t arg2) {
    if ((arg1 <= arg0)) {
        if ((((unsigned int)(arg0) == (unsigned int)(arg2)) | (arg0 < arg2))) {
            goto L_12eb;
        }
    }
    if (((((unsigned int)(arg0) == (unsigned int)(arg1)) | (arg0 < arg1)) == 0)) {
        goto L_12f0;
    }
    if ((arg0 < arg2)) {
        goto L_12f0;
    }
    L_12eb: ;
    // x86-64 epilogue: restore rbp
    return (unsigned int)(arg0);
    L_12f0: ;
    if ((arg0 <= arg1)) {
        if ((((unsigned int)(arg1) == (unsigned int)(arg2)) | (arg1 < arg2))) {
            // x86-64 epilogue: restore rbp
            return (unsigned int)(arg1);
        }
    }
    if (((((unsigned int)(arg1) == (unsigned int)(arg0)) | (arg1 < arg0)) == 0)) {
        // x86-64 epilogue: restore rbp
        return (unsigned int)(arg2);
    }
    if ((arg1 < arg2)) {
        // x86-64 epilogue: restore rbp
        return (unsigned int)(arg2);
    }
    // x86-64 epilogue: restore rbp
    return (unsigned int)(arg1);
}
quickselect_kth pass 68 lines
// glaurung: quickselect_kth @ 0x10f9
int32_t quickselect_kth(int32_t * arg0, int32_t arg1, int32_t arg2) {
    int low;
    int high;
    int guard;
    int pivot;
    int boundary;
    int scan;
    int swap;
    low = 0;
    if ((arg0 != 0)) {
        if (((((unsigned long)((unsigned int)(arg1)) == 0) | ((long)(arg1) < 0)) == 0)) {
            if (((((unsigned long)((unsigned int)(arg1)) == 16) | ((long)(arg1) < 16)) != 0)) {
                if ((0 <= (long)(arg2))) {
                    if ((arg2 < arg1)) {
                        goto L_113d;
                    }
                }
            }
        }
    }
    // x86-64 epilogue: restore rbp
    return 0xffffffff;
    L_113d: ;
    high = ((unsigned int)(arg1) - 1);
    guard = 0;
    goto L_1290;
    L_1152: ;
    pivot = arg0[(long)(high)];
    boundary = low;
    scan = low;
    goto L_11fe;
    L_117c: ;
    if (((long)((int)(arg0[(long)(scan)])) <= (long)(pivot))) {
        swap = arg0[(long)(boundary)];
        arg0[(long)(boundary)] = arg0[(long)(scan)];
        arg0[(long)(scan)] = swap;
        boundary = (boundary + 1);
    }
    scan = (scan + 1);
    L_11fe: ;
    if ((scan < high)) {
        goto L_117c;
    }
    arg0[(long)(high)] = arg0[(long)(boundary)];
    arg0[(long)(boundary)] = pivot;
    if (((unsigned int)(boundary) == (unsigned int)(arg2))) {
        // x86-64 epilogue: restore rbp
        return (unsigned int)(arg0[(long)(boundary)]);
    }
    if ((arg2 < boundary)) {
        high = ((unsigned int)(boundary) - 1);
        goto L_128c;
    }
    low = ((unsigned int)(boundary) + 1);
    L_128c: ;
    guard = (guard + 1);
    L_1290: ;
    if (((((unsigned long)((unsigned int)(guard)) == 31) | ((long)(guard) < 31)) == 0)) {
        // x86-64 epilogue: restore rbp
        return (unsigned int)(arg0[(long)(low)]);
    }
    if ((low < high)) {
        goto L_1152;
    }
    // x86-64 epilogue: restore rbp
    return (unsigned int)(arg0[(long)(low)]);
}

gcc -O2

2/2
median_of_three pass 41 lines
// glaurung: median_of_three @ 0x11e0
int32_t median_of_three(int32_t arg0, int32_t arg1, int32_t arg2) {
    long ret;
    long var1;
    long var3;
    ret = (unsigned long)((unsigned int)(arg0));
    var1 = (arg1 <= arg0);
    if (((((unsigned int)(arg0) == (unsigned int)(arg2)) | (arg0 < arg2)) == 0)) {
        goto L_11f8;
    }
    if (((unsigned long)((unsigned char)((var1 & 255))) == 0)) {
        goto L_11f8;
    }
    L_11f3: ;
    return ret;
    L_11f8: ;
    var3 = ((((unsigned int)(ret) == (unsigned int)(arg1)) | ((long)((int)(ret)) < (long)(arg1))) & 255);
    if (((long)(arg2) <= (long)((int)(ret)))) {
        if (((unsigned long)((unsigned char)((var3 & 255))) != 0)) {
            goto L_11f3;
        }
    }
    if (((((unsigned int)(arg1) == (unsigned int)(arg2)) | (arg1 < arg2)) == 0)) {
        goto L_1220;
    }
    ret = (unsigned long)((unsigned int)(arg1));
    if (((unsigned long)((unsigned char)((var3 & 255))) != 0)) {
        goto L_11f3;
    }
    if ((arg2 <= arg1)) {
        goto L_1220;
    }
    L_1216: ;
    return (unsigned int)(arg2);
    L_1220: ;
    ret = (unsigned long)((unsigned int)(arg1));
    if (((unsigned long)((unsigned char)((var1 & 255))) == 0)) {
        goto L_1216;
    }
    return ret;
}
quickselect_kth pass 101 lines
// glaurung: quickselect_kth @ 0x1100
int32_t quickselect_kth(int32_t * arg0, int32_t arg1, int32_t arg2) {
    int high;
    int guard;
    int low;
    int scan;
    int pivot;
    int boundary;
    long of_16;
    long sf_16;
    long t204;
    long var0;
    long var1;
    long var14;
    long var17;
    long var18;
    long var2;
    long var22;
    long var23;
    long var24;
    long var26;
    int var28;
    long var8;
    long zf_16;
    var0 = (unsigned long)((unsigned int)((arg1 - 1)));
    if (((unsigned long)(15) < (unsigned long)((unsigned long)((unsigned int)(var0))))) {
        return 0xffffffff;
    }
    var1 = (long)arg0;
    if ((arg0 == 0)) {
        return 0xffffffff;
    }
    var2 = (unsigned long)((unsigned int)(arg2));
    if (((long)(arg2) < 0)) {
        goto L_11c8;
    }
    if ((((unsigned int)(arg1) == (unsigned int)(arg2)) | (arg1 < arg2))) {
        goto L_11c8;
    }
    if (((unsigned long)((unsigned int)(var0)) == 0)) {
        goto L_11af;
    }
    var8 = 0;
    high = var0;
    guard = 0;
    low = 0;
    L_1148: ;
    var14 = (var1 + ((long)(high) * 4));
    scan = var8;
    pivot = (unsigned long)((unsigned int)(*(int *)((var14))));
    var17 = (unsigned long)((unsigned int)(low));
    do {
        var18 = (unsigned long)((unsigned int)(*(int *)((var1 + scan * 4))));
        boundary = var17;
        if (((((unsigned int)(var18) == (unsigned int)(pivot)) | ((long)((int)(var18)) < (long)(pivot))) != 0)) {
            boundary = (unsigned long)((unsigned int)((var17 + 1)));
            var22 = (var1 + ((long)((int)(var17)) * 4));
            var23 = (unsigned long)((unsigned int)(*(int *)((var22))));
            *(int *)((var22)) = var18;
            *(int *)((var1 + scan * 4)) = var23;
        }
        var24 = ((unsigned long)((unsigned int)(scan)) + 1);
        scan = var24;
        var17 = (unsigned long)((unsigned int)(boundary));
    } while (((((unsigned int)(high) == (unsigned int)(var24)) | ((long)(high) < (long)((int)(var24)))) == 0));
    var26 = (var1 + ((long)(boundary) * 4));
    *(int *)((var14)) = *(int *)((var26));
    *(int *)((var26)) = pivot;
    t204 = ((unsigned long)((unsigned int)(boundary)) - var2);
    zf_16 = ((unsigned int)(boundary) == (unsigned int)(var2));
    sf_16 = ((long)((int)(t204)) < 0);
    of_16 = (((long)(boundary) < (long)((int)(var2))) ^ ((long)((int)(t204)) < 0));
    if (((unsigned int)(boundary) == (unsigned int)(var2))) {
        goto L_11b2;
    }
    if ((zf_16 | (sf_16 ^ of_16))) {
        goto L_11c0;
    }
    high = (unsigned long)((unsigned int)((boundary - 1)));
    L_119e: ;
    var28 = (guard + 1);
    guard = (unsigned long)((unsigned int)(var28));
    if (((((unsigned long)((unsigned int)(var28)) == 31) | ((long)((int)(var28)) < 31)) != 0)) {
        if ((low < high)) {
            goto L_1148;
        }
    }
    var1 = (var1 + (var8 * 4));
    L_11af: ;
    pivot = (unsigned long)((unsigned int)(*(int *)((var1))));
    L_11b2: ;
    // x86-64 epilogue: tear down frame
    return (unsigned int)(pivot);
    L_11c0: ;
    low = (unsigned long)((unsigned int)((boundary + 1)));
    var8 = (long)(low);
    goto L_119e;
    L_11c8: ;
    pivot = 0xffffffff;
    goto L_11b2;
}

← 213 fixtures