Fixture 127

inline linkage

C · 3 functions · 4 lanes · 11 of 12 function-lanes behave identically

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

static inline may be emitted, inlined, or both. An address taken of a static inline forces an out-of-line copy to exist, so the same source function can appear zero, one or several times in the object.

tests/decompiler_fixtures/src/127_inline_linkage.c source
#include <stdint.h>

/* static inline may be emitted, inlined, or both. An address taken of a static
 * inline forces an out-of-line copy to exist, so the same source function can
 * appear zero, one or several times in the object. */

static inline int32_t scale(int32_t value, int32_t factor) {
    return (int32_t)((uint32_t)value * (uint32_t)factor);
}

static inline int32_t clamp(int32_t value, int32_t low, int32_t high) {
    if (value < low) {
        return low;
    }
    if (value > high) {
        return high;
    }
    return value;
}

__attribute__((noinline)) int32_t
inline_used_twice(int32_t value, int32_t factor) {
    return scale(value, factor) + scale(factor, value);
}

__attribute__((noinline)) int32_t
inline_address_taken(int32_t value, int32_t low, int32_t high) {
    /* Taking the address forces an out-of-line body to exist. */
    int32_t (*indirect)(int32_t, int32_t, int32_t) = clamp;
    return indirect(value, low, high) + clamp(value, low, high);
}

__attribute__((noinline)) int32_t
inline_in_loop(const int32_t *values, int32_t count) {
    int32_t total = 0;
    int32_t index;
    if (values == 0 || count < 0 || count > 16) {
        return -1;
    }
    for (index = 0; index < count; ++index) {
        total += clamp(scale(values[index], 3), -100, 100);
    }
    return total;
}

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 -O2

2/3
inline_address_taken pass 6 lines
// glaurung: inline_address_taken @ 0x1110
int32_t inline_address_taken(int32_t arg0, int32_t arg1, int32_t arg2) {
    long var1;
    var1 = ((arg0 < arg1) ? arg1 : ((((unsigned int)(arg0) == (unsigned int)(arg2)) | (arg0 < arg2)) ? arg0 : arg2));
    return (unsigned int)((var1 + var1));
}
inline_in_loop fail 260 lines
// glaurung: inline_in_loop @ 0x1120
int32_t inline_in_loop(const int32_t * arg0, int32_t arg1) {
    int index;
    int total;
    long ret;
    int var100;
    int var101;
    int var102;
    int var111;
    int var112;
    int var113;
    int var114;
    int var121;
    int var122;
    int var123;
    int var124;
    int var138;
    int var139;
    int var140;
    int var141;
    int var152;
    int var153;
    int var154;
    int var155;
    int var161;
    int var162;
    int var163;
    int var164;
    int var173;
    int var174;
    int var175;
    int var176;
    int var183;
    int var184;
    int var185;
    int var186;
    long var2;
    int var20;
    int var200;
    int var201;
    int var202;
    int var203;
    int var21;
    int var214;
    int var215;
    int var216;
    int var217;
    int var22;
    int var223;
    int var224;
    int var225;
    int var226;
    int var23;
    int var235;
    int var236;
    int var237;
    int var238;
    int var24;
    int var245;
    int var246;
    int var247;
    int var248;
    int var25;
    int var26;
    int var27;
    long var278;
    long var279;
    long var280;
    long var281;
    long var282;
    long var283;
    long var285;
    long var286;
    int var287;
    int var34;
    int var35;
    int var36;
    int var37;
    int var46;
    int var47;
    int var48;
    int var49;
    long var5;
    int var51;
    int var52;
    int var53;
    int var54;
    int var6;
    int var60;
    int var61;
    int var62;
    int var63;
    int var7;
    int var72;
    int var73;
    int var74;
    int var75;
    int var76;
    int var77;
    int var78;
    int var79;
    int var8;
    int var9;
    int var90;
    int var91;
    int var92;
    int var93;
    int var99;
    ret = 0xffffffff;
    if ((arg0 == 0)) {
        return ret;
    }
    ret = 0xffffffff;
    if (((unsigned long)(16) < (unsigned long)((unsigned long)((unsigned int)(arg1))))) {
        return ret;
    }
    if (((unsigned long)((unsigned int)(arg1)) == 0)) {
        return 0;
    }
    var2 = (unsigned long)((unsigned int)(arg1));
    if (((unsigned long)(4) <= (unsigned long)((unsigned long)((unsigned int)(arg1))))) {
        var5 = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var2)) & -4)));
        var6 = *(int *)(((long)arg0));
        var7 = *(int *)(((long)arg0 + 0x4));
        var8 = *(int *)(((long)arg0 + 0x8));
        var9 = *(int *)(((long)arg0 + 0xc));
        var20 = ((var6 + var6) + var6);
        var21 = ((var7 + var7) + var7);
        var22 = ((var8 + var8) + var8);
        var23 = ((var9 + var9) + var9);
        var24 = 100;
        var25 = 100;
        var26 = 100;
        var27 = 100;
        var34 = (-(var20 < 100));
        var35 = (-(var21 < 100));
        var36 = (-(var22 < 100));
        var37 = (-(var23 < 100));
        var46 = (((~var34) & 100) | (var20 & var34));
        var47 = (((~var35) & 100) | (var21 & var35));
        var48 = (((~var36) & 100) | (var22 & var36));
        var49 = (((~var37) & 100) | (var23 & var37));
        var51 = 0xffffff9c;
        var52 = 0xffffff9c;
        var53 = 0xffffff9c;
        var54 = 0xffffff9c;
        var60 = (-(0xffffff9c < var46));
        var61 = (-(0xffffff9c < var47));
        var62 = (-(0xffffff9c < var48));
        var63 = (-(0xffffff9c < var49));
        var72 = (((~var60) & 0xffffff9c) | (var46 & var60));
        var73 = (((~var61) & 0xffffff9c) | (var47 & var61));
        var74 = (((~var62) & 0xffffff9c) | (var48 & var62));
        var75 = (((~var63) & 0xffffff9c) | (var49 & var63));
        if ((var5 != 4)) {
            var76 = *(int *)(((long)arg0 + 0x10));
            var77 = *(int *)(((long)arg0 + 0x14));
            var78 = *(int *)(((long)arg0 + 0x18));
            var79 = *(int *)(((long)arg0 + 0x1c));
            var90 = ((var76 + var76) + var76);
            var91 = ((var77 + var77) + var77);
            var92 = ((var78 + var78) + var78);
            var93 = ((var79 + var79) + var79);
            var99 = (-(var90 < var24));
            var100 = (-(var91 < var25));
            var101 = (-(var92 < var26));
            var102 = (-(var93 < var27));
            var111 = (((~var99) & var24) | (var90 & var99));
            var112 = (((~var100) & var25) | (var91 & var100));
            var113 = (((~var101) & var26) | (var92 & var101));
            var114 = (((~var102) & var27) | (var93 & var102));
            var121 = (-(var51 < var111));
            var122 = (-(var52 < var112));
            var123 = (-(var53 < var113));
            var124 = (-(var54 < var114));
            var72 = (var72 + (((~var121) & var51) | (var111 & var121)));
            var73 = (var73 + (((~var122) & var52) | (var112 & var122)));
            var74 = (var74 + (((~var123) & var53) | (var113 & var123)));
            var75 = (var75 + (((~var124) & var54) | (var114 & var124)));
            if (((unsigned long)((unsigned int)(var5)) != 8)) {
                var138 = *(int *)(((long)arg0 + 0x20));
                var139 = *(int *)(((long)arg0 + 0x24));
                var140 = *(int *)(((long)arg0 + 0x28));
                var141 = *(int *)(((long)arg0 + 0x2c));
                var152 = ((var138 + var138) + var138);
                var153 = ((var139 + var139) + var139);
                var154 = ((var140 + var140) + var140);
                var155 = ((var141 + var141) + var141);
                var161 = (-(var152 < var24));
                var162 = (-(var153 < var25));
                var163 = (-(var154 < var26));
                var164 = (-(var155 < var27));
                var173 = (((~var161) & var24) | (var152 & var161));
                var174 = (((~var162) & var25) | (var153 & var162));
                var175 = (((~var163) & var26) | (var154 & var163));
                var176 = (((~var164) & var27) | (var155 & var164));
                var183 = (-(var51 < var173));
                var184 = (-(var52 < var174));
                var185 = (-(var53 < var175));
                var186 = (-(var54 < var176));
                var72 = (var72 + (((~var183) & var51) | (var173 & var183)));
                var73 = (var73 + (((~var184) & var52) | (var174 & var184)));
                var74 = (var74 + (((~var185) & var53) | (var175 & var185)));
                var75 = (var75 + (((~var186) & var54) | (var176 & var186)));
                if (((unsigned long)((unsigned int)(var5)) != 12)) {
                    var200 = *(int *)(((long)arg0 + 0x30));
                    var201 = *(int *)(((long)arg0 + 0x34));
                    var202 = *(int *)(((long)arg0 + 0x38));
                    var203 = *(int *)(((long)arg0 + 0x3c));
                    var214 = ((var200 + var200) + var200);
                    var215 = ((var201 + var201) + var201);
                    var216 = ((var202 + var202) + var202);
                    var217 = ((var203 + var203) + var203);
                    var223 = (-(var214 < var24));
                    var224 = (-(var215 < var25));
                    var225 = (-(var216 < var26));
                    var226 = (-(var217 < var27));
                    var235 = (((~var223) & var24) | (var214 & var223));
                    var236 = (((~var224) & var25) | (var215 & var224));
                    var237 = (((~var225) & var26) | (var216 & var225));
                    var238 = (((~var226) & var27) | (var217 & var226));
                    var245 = (-(var51 < var235));
                    var246 = (-(var52 < var236));
                    var247 = (-(var53 < var237));
                    var248 = (-(var54 < var238));
                    var72 = (var72 + (((~var245) & var51) | (var235 & var245)));
                    var73 = (var73 + (((~var246) & var52) | (var236 & var246)));
                    var74 = (var74 + (((~var247) & var53) | (var237 & var247)));
                    var75 = (var75 + (((~var248) & var54) | (var238 & var248)));
                }
            }
        }
        var278 = (unsigned long)((unsigned int)(((var75 + var73) + (var74 + var72))));
        var279 = var278;
        var280 = var5;
        ret = var278;
        if ((var5 == var2)) {
            return ret;
        }
        L_1283: ;
        var281 = 100;
        var282 = 0xffffff9c;
        var283 = var279;
        index = var280;
        do {
            var285 = (unsigned long)((unsigned int)(*(int *)(((long)arg0 + index * 4))));
            var286 = (unsigned long)((unsigned int)((var285 + (var285 * 2))));
            var287 = ((100 <= (long)((int)(var286))) ? var281 : var286);
            total = (var283 + (((long)((int)(var287)) < -99) ? var282 : var287));
            var283 = (unsigned long)((unsigned int)(total));
            index = (index + 1);
            ret = (unsigned long)((unsigned int)(total));
        } while ((var2 != index));
    } else {
        var279 = 0;
        var280 = 0;
        goto L_1283;
    }
    return ret;
}
inline_used_twice pass 6 lines
// glaurung: inline_used_twice @ 0x1100
int32_t inline_used_twice(int32_t arg0, int32_t arg1) {
    long var1;
    var1 = (unsigned long)((unsigned int)((arg0 * arg1)));
    return (unsigned int)((var1 + var1));
}

clang -O0

3/3
inline_address_taken pass 15 lines
// glaurung: inline_address_taken @ 0x1160
int32_t inline_address_taken(int32_t arg0, int32_t arg1, int32_t arg2) {
    extern int clamp(int, int, int);
    char * indirect;
    int local_1c;
    long var2;
    int var4;
    // x86-64 prologue: save rbp, frame 32 bytes
    indirect = (char *)((long)(clamp));
    var2 = ((long (*)(long, long, long))(indirect))((unsigned long)((unsigned int)(arg0)), (unsigned long)((unsigned int)(arg1)), (unsigned long)((unsigned int)(arg2)));
    local_1c = var2;
    var4 = clamp((unsigned long)((unsigned int)(arg0)), (unsigned long)((unsigned int)(arg1)), (unsigned long)((unsigned int)(arg2)));
    // x86-64 epilogue: restore rbp
    return (unsigned int)(((unsigned long)((unsigned int)(local_1c)) + (unsigned long)((unsigned int)(var4))));
}
inline_in_loop pass 35 lines
// glaurung: inline_in_loop @ 0x1200
int32_t inline_in_loop(const int32_t * arg0, int32_t arg1) {
    extern int clamp(int, int, int);
    extern int scale(int, int);
    int total;
    int index;
    int local_4;
    int var5;
    int var7;
    // x86-64 prologue: save rbp, frame 32 bytes
    total = 0;
    if ((arg0 == 0)) {
        local_4 = -1;
        // x86-64 epilogue: restore rbp
        return (unsigned int)(local_4);
    }
    if (((long)(arg1) < 0)) {
        local_4 = -1;
        // x86-64 epilogue: restore rbp
        return (unsigned int)(local_4);
    }
    if (((((unsigned long)((unsigned int)(arg1)) == 16) | ((long)(arg1) < 16)) == 0)) {
        local_4 = -1;
        // x86-64 epilogue: restore rbp
        return (unsigned int)(local_4);
    }
    for (index = 0; (index < arg1); index++) {
        var5 = scale((unsigned long)((unsigned int)(arg0[(long)(index)])), 3);
        var7 = clamp((unsigned long)((unsigned int)(var5)), 0xffffff9c, 100);
        total = (var7 + total);
    }
    local_4 = total;
    // x86-64 epilogue: restore rbp
    return (unsigned int)(local_4);
}
inline_used_twice pass 13 lines
// glaurung: inline_used_twice @ 0x1100
int32_t inline_used_twice(int32_t arg0, int32_t arg1) {
    extern int scale(int, int);
    int local_c;
    int var0;
    int var2;
    // x86-64 prologue: save rbp, frame 16 bytes
    var0 = scale((unsigned long)((unsigned int)(arg0)), (unsigned long)((unsigned int)(arg1)));
    local_c = var0;
    var2 = scale((unsigned long)((unsigned int)(arg1)), (unsigned long)((unsigned int)(arg0)));
    // x86-64 epilogue: restore rbp
    return (unsigned int)(((unsigned long)((unsigned int)(local_c)) + (unsigned long)((unsigned int)(var2))));
}

gcc -O0

3/3
inline_address_taken pass 15 lines
// glaurung: inline_address_taken @ 0x1179
int32_t inline_address_taken(int32_t arg0, int32_t arg1, int32_t arg2) {
    extern int clamp(int, int, int);
    char * indirect;
    long var4;
    long var6;
    int var9;
    // x86-64 prologue: save rbp, frame 8 bytes
    indirect = (char *)((long)(clamp));
    var4 = ((long (*)(long, long, long))(indirect))((unsigned long)((unsigned int)(arg0)), (unsigned long)((unsigned int)(arg1)), (unsigned long)((unsigned int)(arg2)));
    var6 = (unsigned long)((unsigned int)(var4));
    var9 = clamp((unsigned long)((unsigned int)(arg0)), (unsigned long)((unsigned int)(arg1)), (unsigned long)((unsigned int)(arg2)));
    // x86-64 epilogue: restore rbp
    return (unsigned int)((var9 + var6));
}
inline_in_loop pass 30 lines
// glaurung: inline_in_loop @ 0x11ca
int32_t inline_in_loop(const int32_t * arg0, int32_t arg1) {
    extern int clamp(int, int, int);
    extern int scale(int, int);
    int total;
    int index;
    int var7;
    int var9;
    // x86-64 prologue: save rbp, frame 32 bytes
    total = 0;
    if ((arg0 == 0)) {
        // x86-64 epilogue: restore rbp
        return 0xffffffff;
    }
    if (((long)(arg1) < 0)) {
        // x86-64 epilogue: restore rbp
        return 0xffffffff;
    }
    if (((((unsigned long)((unsigned int)(arg1)) == 16) | ((long)(arg1) < 16)) == 0)) {
        // x86-64 epilogue: restore rbp
        return 0xffffffff;
    }
    for (index = 0; (index < arg1); index++) {
        var7 = scale((unsigned long)((unsigned int)(arg0[(long)(index)])), 3);
        var9 = clamp((unsigned long)((unsigned int)(var7)), 0xffffff9c, 100);
        total = (total + var9);
    }
    // x86-64 epilogue: restore rbp
    return (unsigned int)(total);
}
inline_used_twice pass 13 lines
// glaurung: inline_used_twice @ 0x113e
int32_t inline_used_twice(int32_t arg0, int32_t arg1) {
    extern int scale(int, int);
    int var2;
    long var4;
    int var7;
    // x86-64 prologue: save rbp, frame 8 bytes
    var2 = scale((unsigned long)((unsigned int)(arg0)), (unsigned long)((unsigned int)(arg1)));
    var4 = (unsigned long)((unsigned int)(var2));
    var7 = scale((unsigned long)((unsigned int)(arg1)), (unsigned long)((unsigned int)(arg0)));
    // x86-64 epilogue: restore rbp
    return (unsigned int)((var7 + var4));
}

gcc -O2

3/3
inline_address_taken pass 6 lines
// glaurung: inline_address_taken @ 0x1110
int32_t inline_address_taken(int32_t arg0, int32_t arg1, int32_t arg2) {
    long var1;
    var1 = ((arg1 <= arg0) ? ((((unsigned int)(arg0) == (unsigned int)(arg2)) | (arg0 < arg2)) ? arg0 : arg2) : arg1);
    return (unsigned int)((var1 + var1));
}
inline_in_loop pass 36 lines
// glaurung: inline_in_loop @ 0x1130
int32_t inline_in_loop(const int32_t * arg0, int32_t arg1) {
    int total;
    int index;
    long var1;
    long var10;
    long var12;
    int var13;
    long var7;
    long var8;
    long var9;
    if ((arg0 == 0)) {
        var1 = 0xffffffff;
        return 0xffffffff;
    }
    if (((unsigned long)(16) < (unsigned long)((unsigned long)((unsigned int)(arg1))))) {
        var1 = 0xffffffff;
        return 0xffffffff;
    }
    if (((unsigned long)((unsigned int)(arg1)) == 0)) {
        return 0;
    }
    var7 = (long)((((long)arg0 + ((unsigned long)((unsigned int)((arg1 - 1))) * 4)) + 4));
    var8 = 0;
    var9 = (long)arg0;
    do {
        var10 = (unsigned long)((unsigned int)(*(int *)((var9))));
        var12 = (unsigned long)((unsigned int)((var10 + (var10 * 2))));
        var13 = (((((unsigned long)((unsigned int)(var12)) == 100) | ((long)((int)(var12)) < 100)) == 0) ? 100 : var12);
        var9 = (var9 + 4);
        total = (var8 + (((long)((int)(var13)) < (long)((int)(0xffffff9c))) ? 0xffffff9c : var13));
        var8 = (unsigned long)((unsigned int)(total));
        var1 = (unsigned long)((unsigned int)(total));
    } while ((var7 != var9));
    return (unsigned int)(var1);
}
inline_used_twice pass 6 lines
// glaurung: inline_used_twice @ 0x1100
int32_t inline_used_twice(int32_t arg0, int32_t arg1) {
    long var1;
    var1 = (unsigned long)((unsigned int)((arg0 * arg1)));
    return (unsigned int)((var1 + var1));
}

← 213 fixtures