Fixture 191

indirect table args

C · 4 functions · 4 lanes · 15 of 16 function-lanes behave identically

One lane has a function that returns a different result after decompilation: gcc-O2 (3/4).

Arguments to a call through a function-pointer table.

An indirect call has no single callee to ask which registers it reads, so a dead-code pass with no may-use set for it deletes the argument setup — and the recovered call then passes whatever happens to be in those registers. That output still compiles and still looks plausible; see docs/design/table-dispatch-arguments-2026-08-12.md, where a first attempt at repairing it emitted the right ARITY with the wrong VALUES.

A call through a *proven* table is different: the table's entries are a complete, relocation-proven callee set, so the registers the call may read are the union over that set. This fixture exists to make both halves of that observable — the arity AND the values.

Every entry records the exact arguments it received in the caller's own scratch buffer. 95_function_pointer_table already covers the value the dispatch RETURNS; a witness catches an argument list that is wrong in a way the returned value happens to hide, which is exactly the failure mode above. The count is kept in the caller's buffer rather than a global so it survives the harness rebuilding one function against extern callees, in the same way 189_effectful_select counts its side effect.

t191_computed_args is the NEAR-MISS CONTROL. Its table call passes values this function computed, not the parameters it was handed, so a recovery that names architectural argument registers and lets naming render them as arg1, arg2 produces well-typed, plausible, WRONG output and is caught here.

t191_direct_control is the DEGENERACY CONTROL: the same protocol through a DIRECT call, which the ordinary direct-callee recovery already handles. It must keep passing, so a decompiler cannot satisfy this fixture by making every call conservative.

tests/decompiler_fixtures/src/191_indirect_table_args.c source
#include <stdint.h>

/* Arguments to a call through a function-pointer table.
 *
 * An indirect call has no single callee to ask which registers it reads, so a
 * dead-code pass with no may-use set for it deletes the argument setup — and
 * the recovered call then passes whatever happens to be in those registers.
 * That output still compiles and still looks plausible; see
 * `docs/design/table-dispatch-arguments-2026-08-12.md`, where a first attempt
 * at repairing it emitted the right ARITY with the wrong VALUES.
 *
 * A call through a *proven* table is different: the table's entries are a
 * complete, relocation-proven callee set, so the registers the call may read
 * are the union over that set. This fixture exists to make both halves of that
 * observable — the arity AND the values.
 *
 * Every entry records the exact arguments it received in the caller's own
 * scratch buffer. `95_function_pointer_table` already covers the value the
 * dispatch RETURNS; a witness catches an argument list that is wrong in a way
 * the returned value happens to hide, which is exactly the failure mode above.
 * The count is kept in the caller's buffer rather than a global so it survives
 * the harness rebuilding one function against extern callees, in the same way
 * `189_effectful_select` counts its side effect.
 *
 * `t191_computed_args` is the NEAR-MISS CONTROL. Its table call passes values
 * this function computed, not the parameters it was handed, so a recovery that
 * names architectural argument registers and lets naming render them as
 * `arg1, arg2` produces well-typed, plausible, WRONG output and is caught here.
 *
 * `t191_direct_control` is the DEGENERACY CONTROL: the same protocol through a
 * DIRECT call, which the ordinary direct-callee recovery already handles. It
 * must keep passing, so a decompiler cannot satisfy this fixture by making
 * every call conservative. */

#define T191_SLOT_A 0
#define T191_SLOT_B 1
#define T191_SLOT_CALLS 2
#define T191_SLOT_WITNESS 3

typedef int32_t (*T191Op)(int32_t *witness, int32_t a, int32_t b);

__attribute__((noinline)) static int32_t t191_add(int32_t *witness, int32_t a, int32_t b) {
    witness[T191_SLOT_A] = a;
    witness[T191_SLOT_B] = b;
    witness[T191_SLOT_CALLS] += 1;
    return (int32_t)((uint32_t)a + (uint32_t)b);
}

__attribute__((noinline)) static int32_t t191_sub(int32_t *witness, int32_t a, int32_t b) {
    witness[T191_SLOT_A] = a;
    witness[T191_SLOT_B] = b;
    witness[T191_SLOT_CALLS] += 1;
    return (int32_t)((uint32_t)a - (uint32_t)b);
}

__attribute__((noinline)) static int32_t t191_and(int32_t *witness, int32_t a, int32_t b) {
    witness[T191_SLOT_A] = a;
    witness[T191_SLOT_B] = b;
    witness[T191_SLOT_CALLS] += 1;
    return a & b;
}

__attribute__((noinline)) static int32_t t191_max(int32_t *witness, int32_t a, int32_t b) {
    witness[T191_SLOT_A] = a;
    witness[T191_SLOT_B] = b;
    witness[T191_SLOT_CALLS] += 1;
    return a > b ? a : b;
}

static T191Op const T191_OPS[4] = {t191_add, t191_sub, t191_and, t191_max};

/* The plain shape. At -O2 the compiler leaves the incoming registers alone
 * where it can and shuffles the rest into place BEFORE the bounds check, so the
 * setup is not adjacent to the call and not inside the guarded arm either. */
__attribute__((noinline)) int32_t t191_dispatch(int32_t *scratch, int32_t which,
                                                int32_t a, int32_t b) {
    int32_t produced;
    if (scratch == 0) {
        return -1;
    }
    scratch[T191_SLOT_A] = 0;
    scratch[T191_SLOT_B] = 0;
    scratch[T191_SLOT_CALLS] = 0;
    if (which < 0 || which >= 4) {
        return -1;
    }
    produced = T191_OPS[which](scratch, a, b);
    scratch[T191_SLOT_WITNESS] = produced;
    return produced;
}

/* NEAR-MISS CONTROL: the arguments are computed here, so passing this
 * function's own parameter registers is a different answer with the same
 * shape. */
__attribute__((noinline)) int32_t t191_computed_args(int32_t *scratch, int32_t which,
                                                     int32_t seed) {
    int32_t produced;
    int32_t left;
    int32_t right;
    if (scratch == 0) {
        return -1;
    }
    scratch[T191_SLOT_A] = 0;
    scratch[T191_SLOT_B] = 0;
    scratch[T191_SLOT_CALLS] = 0;
    if (which < 0 || which >= 4) {
        return -1;
    }
    left = (int32_t)((uint32_t)seed * 3u + 1u);
    right = seed ^ 0x5a;
    produced = T191_OPS[which](scratch, left, right);
    scratch[T191_SLOT_WITNESS] = produced;
    return produced;
}

/* The dispatch loop: the accumulator is carried round the back edge and is the
 * argument of the next call, so the reaching value at the call is not the
 * function's entry value for that register. */
__attribute__((noinline)) int32_t t191_fold(int32_t *scratch, const int32_t *selectors,
                                            int32_t count, int32_t seed) {
    int32_t accumulator = seed;
    int32_t index;
    if (scratch == 0 || selectors == 0 || count < 0 || count > 16) {
        return -1;
    }
    scratch[T191_SLOT_A] = 0;
    scratch[T191_SLOT_B] = 0;
    scratch[T191_SLOT_CALLS] = 0;
    for (index = 0; index < count; ++index) {
        int32_t which = selectors[index];
        if (which < 0 || which >= 4) {
            continue;
        }
        accumulator = T191_OPS[which](scratch, accumulator, index + 1);
    }
    scratch[T191_SLOT_WITNESS] = accumulator;
    return accumulator;
}

/* DEGENERACY CONTROL: one entry, called directly. Nothing about the indirect
 * may-use set may disturb the recovery that already works. */
__attribute__((noinline)) int32_t t191_direct_control(int32_t *scratch, int32_t a,
                                                      int32_t b) {
    int32_t produced;
    if (scratch == 0) {
        return -1;
    }
    scratch[T191_SLOT_A] = 0;
    scratch[T191_SLOT_B] = 0;
    scratch[T191_SLOT_CALLS] = 0;
    produced = t191_add(scratch, a, b);
    scratch[T191_SLOT_WITNESS] = produced;
    return produced;
}

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.

gcc -O2

3/4
t191_computed_args pass 34 lines
// glaurung: t191_computed_args @ 0x11d0
int32_t t191_computed_args(int32_t * arg0, int32_t arg1, int32_t arg2) {
    extern void t191_add(void);
    extern void t191_and(void);
    extern void t191_max(void);
    extern void t191_sub(void);
    static void (*T191_OPS[4])(void) = {
        (void (*)(void))t191_add,
        (void (*)(void))t191_sub,
        (void (*)(void))t191_and,
        (void (*)(void))t191_max,
    };
    int produced;
    int right;
    long local_8;
    int ret;
    long var1;
    long var2;
    if ((arg0 == 0)) {
        return (unsigned int)(-1);
    }
    local_8 = var1;
    var2 = (long)arg0;
    *(long *)(((long)arg0)) = 0;
    *(int *)(((long)arg0 + 0x8)) = 0;
    if (((unsigned long)(3) < (unsigned long)((unsigned long)((unsigned int)(arg1))))) {
        // x86-64 epilogue: tear down frame
        return 0xffffffff;
    }
    ret = ((int (*)(int *, long, long, long))(T191_OPS[(long)(arg1)]))((int *)(arg0), (unsigned long)((unsigned int)(((arg2 + (arg2 * 2)) + 1))), (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg2)) ^ 90))), 0x3e60);
    *(int *)((var2 + 0xc)) = ret;
    // x86-64 epilogue: tear down frame
    return ret;
}
t191_direct_control pass 14 lines
// glaurung: t191_direct_control @ 0x12c0
int32_t t191_direct_control(int32_t * arg0, int32_t arg1, int32_t arg2) {
    extern int t191_add(int *, int, int);
    int produced;
    int ret;
    if ((arg0 == 0)) {
        return 0xffffffff;
    }
    *(long *)(((long)arg0)) = 0;
    *(int *)(((long)arg0 + 0x8)) = 0;
    ret = t191_add((int *)(arg0), arg1, arg2);
    *(int *)(((long)arg0 + 0xc)) = ret;
    return ret;
}
t191_dispatch pass 35 lines
// glaurung: t191_dispatch @ 0x1180
int32_t t191_dispatch(int32_t * arg0, int32_t arg1, int32_t arg2, int32_t arg3) {
    extern void t191_add(void);
    extern void t191_and(void);
    extern void t191_max(void);
    extern void t191_sub(void);
    static void (*T191_OPS[4])(void) = {
        (void (*)(void))t191_add,
        (void (*)(void))t191_sub,
        (void (*)(void))t191_and,
        (void (*)(void))t191_max,
    };
    int produced;
    long local_8;
    int ret;
    long var1;
    long var2;
    long var3;
    if ((arg0 == 0)) {
        return (unsigned int)(-1);
    }
    var1 = (long)(arg1);
    local_8 = var2;
    var3 = (long)arg0;
    *(long *)(((long)arg0)) = 0;
    *(int *)(((long)arg0 + 0x8)) = 0;
    if (((unsigned long)(3) < (unsigned long)((unsigned long)((unsigned int)(arg1))))) {
        // x86-64 epilogue: tear down frame
        return 0xffffffff;
    }
    ret = ((int (*)(int *, long, long, long))(T191_OPS[var1]))((int *)(arg0), (unsigned long)((unsigned int)(arg2)), (unsigned long)((unsigned int)(arg3)), 0x3e60);
    *(int *)((var3 + 0xc)) = ret;
    // x86-64 epilogue: tear down frame
    return ret;
}
t191_fold fail 71 lines
// glaurung: t191_fold @ 0x1230
int32_t t191_fold(int32_t * arg0, const int32_t * arg1, int32_t arg2, int32_t arg3) {
    extern void t191_add(void);
    extern void t191_and(void);
    extern void t191_max(void);
    extern void t191_sub(void);
    static void (*T191_OPS[4])(void) = {
        (void (*)(void))t191_add,
        (void (*)(void))t191_sub,
        (void (*)(void))t191_and,
        (void (*)(void))t191_max,
    };
    int accumulator;
    int which;
    int index;
    long local_10;
    long local_18;
    long local_28;
    long local_8;
    long var1;
    long var13;
    long var14;
    long var16;
    long var18;
    long var2;
    long var23;
    long var3;
    long var4;
    long var5;
    if ((arg0 == 0)) {
        return (unsigned int)(-1);
    }
    local_8 = var1;
    local_10 = var2;
    local_18 = var3;
    var4 = (long)arg1;
    local_28 = var5;
    if ((arg1 == 0)) {
        accumulator = 0xffffffff;
        // x86-64 epilogue: tear down frame
        return 0xffffffff;
    }
    var13 = (unsigned long)((unsigned int)(arg2));
    if (((unsigned long)(16) < (unsigned long)((unsigned long)((unsigned int)(arg2))))) {
        accumulator = 0xffffffff;
        // x86-64 epilogue: tear down frame
        return 0xffffffff;
    }
    *(long *)(((long)arg0)) = 0;
    var14 = (long)arg0;
    accumulator = (unsigned long)((unsigned int)(arg3));
    *(int *)(((long)arg0 + 0x8)) = 0;
    if (((unsigned long)((unsigned int)(arg2)) != 0)) {
        var16 = 0;
        var18 = (unsigned long)((unsigned int)(accumulator));
        do {
            which = (unsigned long)((unsigned int)(*(int *)((var4))));
            var16 = (unsigned long)((unsigned int)((var16 + 1)));
            accumulator = var18;
            if (((unsigned long)((unsigned long)((unsigned int)(which))) <= (unsigned long)(3))) {
                var23 = ((long (*)(long))(T191_OPS[(long)(which)]))(var14);
                accumulator = (unsigned long)((unsigned int)(var23));
            }
            var4 = (var4 + 4);
            var18 = (unsigned long)((unsigned int)(accumulator));
        } while (((unsigned int)(var13) != (unsigned int)(var16)));
    }
    *(int *)((var14 + 0xc)) = accumulator;
    // x86-64 epilogue: tear down frame
    return (unsigned int)(accumulator);
}

clang -O0

4/4
t191_computed_args pass 43 lines
// glaurung: t191_computed_args @ 0x11b0
int32_t t191_computed_args(int32_t * arg0, int32_t arg1, int32_t arg2) {
    extern void t191_add(void);
    extern void t191_and(void);
    extern void t191_max(void);
    extern void t191_sub(void);
    static void (*T191_OPS[4])(void) = {
        (void (*)(void))t191_add,
        (void (*)(void))t191_sub,
        (void (*)(void))t191_and,
        (void (*)(void))t191_max,
    };
    int left;
    int right;
    int produced;
    int local_4;
    long var12;
    if ((arg0 == 0)) {
        local_4 = -1;
        // x86-64 epilogue: restore rbp
        return (unsigned int)(local_4);
    }
    *(int *)((long)arg0) = 0;
    *(int *)(((long)arg0 + 0x4)) = 0;
    *(int *)(((long)arg0 + 0x8)) = 0;
    if ((0 <= (long)(arg1))) {
        if (((long)(arg1) < 4)) {
            goto L_1219;
        }
    }
    local_4 = -1;
    // x86-64 epilogue: restore rbp
    return (unsigned int)(local_4);
    L_1219: ;
    left = ((arg2 * 3) + 1);
    right = ((unsigned int)(arg2) ^ 90);
    var12 = ((long (*)(int *, long, long))(T191_OPS[(long)(arg1)]))((int *)(arg0), (unsigned long)((unsigned int)(left)), (unsigned long)((unsigned int)(right)));
    produced = var12;
    *(int *)(((long)arg0 + 0xc)) = produced;
    local_4 = produced;
    // x86-64 epilogue: restore rbp
    return (unsigned int)(local_4);
}
t191_direct_control pass 18 lines
// glaurung: t191_direct_control @ 0x1370
int32_t t191_direct_control(int32_t * arg0, int32_t arg1, int32_t arg2) {
    extern int t191_add(int *, int, int);
    int produced;
    int var3;
    // x86-64 prologue: save rbp, frame 32 bytes
    if ((arg0 != 0)) {
        *(int *)((long)arg0) = 0;
        *(int *)(((long)arg0 + 0x4)) = 0;
        *(int *)(((long)arg0 + 0x8)) = 0;
        var3 = t191_add((int *)(arg0), (unsigned long)((unsigned int)(arg1)), (unsigned long)((unsigned int)(arg2)));
        produced = var3;
        *(int *)(((long)arg0 + 0xc)) = produced;
        return (unsigned int)(produced);
    } else {
        return (unsigned int)(-1);
    }
}
t191_dispatch pass 39 lines
// glaurung: t191_dispatch @ 0x1100
int32_t t191_dispatch(int32_t * arg0, int32_t arg1, int32_t arg2, int32_t arg3) {
    extern void t191_add(void);
    extern void t191_and(void);
    extern void t191_max(void);
    extern void t191_sub(void);
    static void (*T191_OPS[4])(void) = {
        (void (*)(void))t191_add,
        (void (*)(void))t191_sub,
        (void (*)(void))t191_and,
        (void (*)(void))t191_max,
    };
    int produced;
    int local_4;
    long var6;
    if ((arg0 == 0)) {
        local_4 = -1;
        // x86-64 epilogue: restore rbp
        return (unsigned int)(local_4);
    }
    *(int *)((long)arg0) = 0;
    *(int *)(((long)arg0 + 0x4)) = 0;
    *(int *)(((long)arg0 + 0x8)) = 0;
    if ((0 <= (long)(arg1))) {
        if (((long)(arg1) < 4)) {
            goto L_116c;
        }
    }
    local_4 = -1;
    // x86-64 epilogue: restore rbp
    return (unsigned int)(local_4);
    L_116c: ;
    var6 = ((long (*)(int *, long, long))(T191_OPS[(long)(arg1)]))((int *)(arg0), (unsigned long)((unsigned int)(arg2)), (unsigned long)((unsigned int)(arg3)));
    produced = var6;
    *(int *)(((long)arg0 + 0xc)) = produced;
    local_4 = produced;
    // x86-64 epilogue: restore rbp
    return (unsigned int)(local_4);
}
t191_fold pass 62 lines
// glaurung: t191_fold @ 0x1270
int32_t t191_fold(int32_t * arg0, const int32_t * arg1, int32_t arg2, int32_t arg3) {
    extern void t191_add(void);
    extern void t191_and(void);
    extern void t191_max(void);
    extern void t191_sub(void);
    static void (*T191_OPS[4])(void) = {
        (void (*)(void))t191_add,
        (void (*)(void))t191_sub,
        (void (*)(void))t191_and,
        (void (*)(void))t191_max,
    };
    int accumulator;
    int index;
    int which;
    int local_4;
    long var13;
    // x86-64 prologue: save rbp, frame 48 bytes
    accumulator = arg3;
    if ((arg0 == 0)) {
        local_4 = -1;
        // x86-64 epilogue: restore rbp
        return (unsigned int)(local_4);
    }
    if ((arg1 == 0)) {
        local_4 = -1;
        // x86-64 epilogue: restore rbp
        return (unsigned int)(local_4);
    }
    if (((long)(arg2) < 0)) {
        local_4 = -1;
        // x86-64 epilogue: restore rbp
        return (unsigned int)(local_4);
    }
    if (((((unsigned long)((unsigned int)(arg2)) == 16) | ((long)(arg2) < 16)) == 0)) {
        local_4 = -1;
        // x86-64 epilogue: restore rbp
        return (unsigned int)(local_4);
    }
    *(int *)((long)arg0) = 0;
    *(int *)(((long)arg0 + 0x4)) = 0;
    *(int *)(((long)arg0 + 0x8)) = 0;
    index = 0;
    while ((index < arg2)) {
        which = arg1[(long)(index)];
        if (((long)(which) < 0)) {
            L_1317: ;
        } else {
            if (((long)(which) < 4)) {
                var13 = ((long (*)(int *, long, long))(T191_OPS[(long)(which)]))((int *)(arg0), (unsigned long)((unsigned int)(accumulator)), (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(index)) + 1))));
                accumulator = var13;
            } else {
                goto L_1317;
            }
        }
        index = ((unsigned int)(index) + 1);
    }
    *(int *)(((long)arg0 + 0xc)) = accumulator;
    local_4 = accumulator;
    // x86-64 epilogue: restore rbp
    return (unsigned int)(local_4);
}

clang -O2

4/4
t191_computed_args pass 40 lines
// glaurung: t191_computed_args @ 0x1140
int32_t t191_computed_args(int32_t * arg0, int32_t arg1, int32_t arg2) {
    extern void t191_add(void);
    extern void t191_and(void);
    extern void t191_max(void);
    extern void t191_sub(void);
    static void (*T191_OPS[4])(void) = {
        (void (*)(void))t191_add,
        (void (*)(void))t191_sub,
        (void (*)(void))t191_and,
        (void (*)(void))t191_max,
    };
    int left;
    int produced;
    int right;
    long local_8;
    long ret;
    long var0;
    long var1;
    long var10;
    long var3;
    local_8 = var0;
    var1 = 0xffffffff;
    ret = 0xffffffff;
    if ((arg0 == 0)) {
        // x86-64 epilogue: tear down frame
        return ret;
    }
    var3 = (long)arg0;
    *(long *)(((long)arg0)) = 0;
    *(int *)(((long)arg0 + 0x8)) = 0;
    ret = var1;
    if (((unsigned long)((unsigned long)((unsigned int)(arg1))) <= (unsigned long)(3))) {
        var10 = ((long (*)(long, long, long))(T191_OPS[(unsigned long)((unsigned int)(arg1))]))(var3, (unsigned long)((unsigned int)(((unsigned long)((unsigned int)((arg2 + (arg2 * 2)))) + 1))), (unsigned long)((unsigned int)((arg2 ^ 90))));
        *(int *)((var3 + 0xc)) = var10;
        ret = var10;
    }
    // x86-64 epilogue: tear down frame
    return ret;
}
t191_direct_control pass 17 lines
// glaurung: t191_direct_control @ 0x1220
int32_t t191_direct_control(int32_t * arg0, int32_t arg1, int32_t arg2) {
    extern int t191_add(int *, int, int);
    int produced;
    int ret;
    long var0;
    if ((arg0 == 0)) {
        return 0xffffffff;
    }
    var0 = (long)arg0;
    *(long *)(((long)arg0)) = 0;
    *(int *)(((long)arg0 + 0x8)) = 0;
    ret = t191_add((int *)(arg0), arg1, arg2);
    *(int *)((var0 + 0xc)) = ret;
    // x86-64 epilogue: tear down frame
    return ret;
}
t191_dispatch pass 37 lines
// glaurung: t191_dispatch @ 0x1100
int32_t t191_dispatch(int32_t * arg0, int32_t arg1, int32_t arg2, int32_t arg3) {
    extern void t191_add(void);
    extern void t191_and(void);
    extern void t191_max(void);
    extern void t191_sub(void);
    static void (*T191_OPS[4])(void) = {
        (void (*)(void))t191_add,
        (void (*)(void))t191_sub,
        (void (*)(void))t191_and,
        (void (*)(void))t191_max,
    };
    int produced;
    long local_8;
    long var0;
    long var1;
    long var3;
    long var6;
    local_8 = var0;
    var1 = 0xffffffff;
    produced = 0xffffffff;
    if ((arg0 == 0)) {
        // x86-64 epilogue: tear down frame
        return produced;
    }
    var3 = (long)arg0;
    *(long *)(((long)arg0)) = 0;
    *(int *)(((long)arg0 + 0x8)) = 0;
    produced = var1;
    if (((unsigned long)((unsigned long)((unsigned int)(arg1))) <= (unsigned long)(3))) {
        var6 = ((long (*)(long, long, long))(T191_OPS[(unsigned long)((unsigned int)(arg1))]))(var3, (unsigned long)((unsigned int)(arg2)), (unsigned long)((unsigned int)(arg3)));
        produced = var6;
        *(int *)((var3 + 0xc)) = var6;
    }
    // x86-64 epilogue: tear down frame
    return produced;
}
t191_fold pass 80 lines
// glaurung: t191_fold @ 0x1190
int32_t t191_fold(int32_t * arg0, const int32_t * arg1, int32_t arg2, int32_t arg3) {
    extern void t191_add(void);
    extern void t191_and(void);
    extern void t191_max(void);
    extern void t191_sub(void);
    static void (*T191_OPS[4])(void) = {
        (void (*)(void))t191_add,
        (void (*)(void))t191_sub,
        (void (*)(void))t191_and,
        (void (*)(void))t191_max,
    };
    int index;
    int accumulator;
    long local_10;
    long local_18;
    long local_20;
    long local_28;
    long local_8;
    long var0;
    long var1;
    long var13;
    long var14;
    long var15;
    long var16;
    long var2;
    long var20;
    long var22;
    long var23;
    long var3;
    long var4;
    long var5;
    long var6;
    long var7;
    local_8 = var0;
    local_10 = var1;
    local_18 = var2;
    local_20 = var3;
    local_28 = var4;
    var5 = (unsigned long)((unsigned int)(arg3));
    var6 = 0xffffffff;
    var7 = 0xffffffff;
    if (((unsigned long)(16) < (unsigned long)((unsigned long)((unsigned int)(arg2))))) {
        // x86-64 epilogue: tear down frame
        return (unsigned int)(var7);
    }
    var13 = (long)arg0;
    var7 = var6;
    if ((arg0 == 0)) {
        // x86-64 epilogue: tear down frame
        return (unsigned int)(var7);
    }
    var14 = (long)arg1;
    var7 = var6;
    if ((arg1 == 0)) {
        // x86-64 epilogue: tear down frame
        return (unsigned int)(var7);
    }
    *(long *)((var13)) = 0;
    *(int *)((var13 + 0x8)) = 0;
    var15 = var5;
    if (((unsigned long)((unsigned int)(arg2)) != 0)) {
        var16 = (unsigned long)((unsigned int)(arg2));
        var20 = var5;
        index = 0;
        do {
            var22 = (unsigned long)((unsigned int)(*(int *)((var14 + index * 4))));
            index = (index + 1);
            if (((unsigned long)(var22) < (unsigned long)(4))) {
                var23 = ((long (*)(long, long, long))(T191_OPS[var22]))(var13, (unsigned long)((unsigned int)(var20)), (unsigned long)((unsigned int)(index)));
                var20 = var23;
            }
            var15 = var20;
        } while ((index != var16));
    }
    *(int *)((var13 + 0xc)) = var15;
    var7 = (unsigned long)((unsigned int)(var15));
    // x86-64 epilogue: tear down frame
    return (unsigned int)(var15);
}

gcc -O0

4/4
t191_computed_args pass 39 lines
// glaurung: t191_computed_args @ 0x12bd
int32_t t191_computed_args(int32_t * arg0, int32_t arg1, int32_t arg2) {
    extern void t191_add(void);
    extern void t191_and(void);
    extern void t191_max(void);
    extern void t191_sub(void);
    static void (*T191_OPS[4])(void) = {
        (void (*)(void))t191_add,
        (void (*)(void))t191_sub,
        (void (*)(void))t191_and,
        (void (*)(void))t191_max,
    };
    int left;
    int right;
    int produced;
    long var23;
    if ((arg0 == 0)) {
        // x86-64 epilogue: restore rbp
        return 0xffffffff;
    }
    *(int *)((long)arg0) = 0;
    *(int *)((arg0 + 1)) = 0;
    *(int *)((arg0 + 2)) = 0;
    if ((0 <= (long)(arg1))) {
        if ((((unsigned long)((unsigned int)(arg1)) == 3) | ((long)(arg1) < 3))) {
            goto L_131d;
        }
    }
    // x86-64 epilogue: restore rbp
    return 0xffffffff;
    L_131d: ;
    left = ((unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg2)) + (unsigned long)((unsigned int)(arg2))))) + (unsigned long)((unsigned int)(arg2)))) + 1);
    right = ((unsigned int)(arg2) ^ 90);
    var23 = ((long (*)(int *, long, long))(T191_OPS[(long)((int)((unsigned long)((unsigned int)(arg1))))]))((int *)(arg0), (unsigned long)((unsigned int)(left)), (unsigned long)((unsigned int)(right)));
    produced = var23;
    *(int *)((arg0 + 3)) = produced;
    // x86-64 epilogue: restore rbp
    return (unsigned int)(produced);
}
t191_direct_control pass 18 lines
// glaurung: t191_direct_control @ 0x145d
int32_t t191_direct_control(int32_t * arg0, int32_t arg1, int32_t arg2) {
    extern int t191_add(int *, int, int);
    int produced;
    int var7;
    // x86-64 prologue: save rbp, frame 32 bytes
    if ((arg0 != 0)) {
        *(int *)((long)arg0) = 0;
        *(int *)((arg0 + 1)) = 0;
        *(int *)((arg0 + 2)) = 0;
        var7 = t191_add((int *)(arg0), (unsigned long)((unsigned int)(arg1)), (unsigned long)((unsigned int)(arg2)));
        produced = var7;
        *(int *)((arg0 + 3)) = produced;
        return (unsigned int)(produced);
    } else {
        return 0xffffffff;
    }
}
t191_dispatch pass 35 lines
// glaurung: t191_dispatch @ 0x121e
int32_t t191_dispatch(int32_t * arg0, int32_t arg1, int32_t arg2, int32_t arg3) {
    extern void t191_add(void);
    extern void t191_and(void);
    extern void t191_max(void);
    extern void t191_sub(void);
    static void (*T191_OPS[4])(void) = {
        (void (*)(void))t191_add,
        (void (*)(void))t191_sub,
        (void (*)(void))t191_and,
        (void (*)(void))t191_max,
    };
    int produced;
    long var12;
    if ((arg0 == 0)) {
        // x86-64 epilogue: restore rbp
        return 0xffffffff;
    }
    *(int *)((long)arg0) = 0;
    *(int *)((arg0 + 1)) = 0;
    *(int *)((arg0 + 2)) = 0;
    if ((0 <= (long)(arg1))) {
        if ((((unsigned long)((unsigned int)(arg1)) == 3) | ((long)(arg1) < 3))) {
            goto L_127e;
        }
    }
    // x86-64 epilogue: restore rbp
    return 0xffffffff;
    L_127e: ;
    var12 = ((long (*)(int *, long, long))(T191_OPS[(long)((int)((unsigned long)((unsigned int)(arg1))))]))((int *)(arg0), (unsigned long)((unsigned int)(arg2)), (unsigned long)((unsigned int)(arg3)));
    produced = var12;
    *(int *)((arg0 + 3)) = produced;
    // x86-64 epilogue: restore rbp
    return (unsigned int)(produced);
}
t191_fold pass 49 lines
// glaurung: t191_fold @ 0x1374
int32_t t191_fold(int32_t * arg0, const int32_t * arg1, int32_t arg2, int32_t arg3) {
    extern void t191_add(void);
    extern void t191_and(void);
    extern void t191_max(void);
    extern void t191_sub(void);
    static void (*T191_OPS[4])(void) = {
        (void (*)(void))t191_add,
        (void (*)(void))t191_sub,
        (void (*)(void))t191_and,
        (void (*)(void))t191_max,
    };
    int accumulator;
    int index;
    int which;
    long var21;
    // x86-64 prologue: save rbp, frame 48 bytes
    accumulator = arg3;
    if ((arg0 == 0)) {
        // x86-64 epilogue: restore rbp
        return 0xffffffff;
    }
    if ((arg1 == 0)) {
        // x86-64 epilogue: restore rbp
        return 0xffffffff;
    }
    if (((long)(arg2) < 0)) {
        // x86-64 epilogue: restore rbp
        return 0xffffffff;
    }
    if (((((unsigned long)((unsigned int)(arg2)) == 16) | ((long)(arg2) < 16)) == 0)) {
        // x86-64 epilogue: restore rbp
        return 0xffffffff;
    }
    *(int *)((long)arg0) = 0;
    *(int *)((arg0 + 1)) = 0;
    *(int *)((arg0 + 2)) = 0;
    for (index = 0; (index < arg2); index++) {
        which = arg1[(long)(index)];
        if ((((long)(which) < 0) || ((((unsigned long)((unsigned int)(which)) == 3) | ((long)(which) < 3)) == 0))) {
        } else {
            var21 = ((long (*)(int *, long, long))(T191_OPS[(long)((int)((unsigned long)((unsigned int)(which))))]))((int *)(arg0), (unsigned long)((unsigned int)(accumulator)), (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(index)) + 1))));
            accumulator = var21;
        }
    }
    *(int *)((arg0 + 3)) = accumulator;
    // x86-64 epilogue: restore rbp
    return (unsigned int)(accumulator);
}

← 213 fixtures