Fixture 77

lru cache

C · 1 functions · 4 lanes · 3 of 4 function-lanes behave identically

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

A fixed-capacity LRU cache built from parallel arrays with an explicit recency stamp. Lookup promotes; insertion evicts the minimum stamp. Two scans over the same arrays with different reduction operators.

tests/decompiler_fixtures/src/77_lru_cache.c source
#include <stdint.h>

/* A fixed-capacity LRU cache built from parallel arrays with an explicit
 * recency stamp.  Lookup promotes; insertion evicts the minimum stamp.  Two
 * scans over the same arrays with different reduction operators. */

#define LRU_CAPACITY 8

__attribute__((noinline)) int32_t
lru_access(int32_t *keys, int32_t *stamps, int32_t capacity, int32_t key,
           int32_t clock, int32_t *evicted_key) {
    int32_t index;
    int32_t victim = 0;
    if (keys == 0 || stamps == 0 || evicted_key == 0 || capacity < 1 ||
        capacity > LRU_CAPACITY || clock < 0) {
        return -1;
    }
    *evicted_key = -1;
    for (index = 0; index < capacity; ++index) {
        if (keys[index] == key) {
            stamps[index] = clock;
            return 1;
        }
    }
    for (index = 0; index < capacity; ++index) {
        if (keys[index] == 0) {
            keys[index] = key;
            stamps[index] = clock;
            return 0;
        }
        if (stamps[index] < stamps[victim]) {
            victim = index;
        }
    }
    *evicted_key = keys[victim];
    keys[victim] = key;
    stamps[victim] = clock;
    return 2;
}

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

0/1
lru_access fail 113 lines
// glaurung: lru_access @ 0x1100
int32_t lru_access(int32_t * arg0, int32_t * arg1, int32_t arg2, int32_t arg3, int32_t arg4, int32_t * arg5) {
    int victim;
    int index;
    long local_10;
    long ret;
    long var1;
    long var12;
    long var2;
    long var3;
    long var8;
    ret = 0xffffffff;
    if (((long)(arg4) < 0)) {
        return ret;
    }
    if (((unsigned long)((unsigned long)((unsigned int)((arg2 - 9)))) < (unsigned long)(0xfffffff8))) {
        return ret;
    }
    if ((arg0 == 0)) {
        return ret;
    }
    if ((arg1 == 0)) {
        return ret;
    }
    if ((arg5 == 0)) {
        return ret;
    }
    local_10 = var1;
    *(int *)(((long)arg5)) = -1;
    ret = 1;
    if (((unsigned int)(*(int *)(((long)arg0))) != (unsigned int)(arg3))) {
        if (((unsigned long)((unsigned int)(arg2)) != 1)) {
            var2 = 1;
            if (((unsigned int)(*(int *)(((long)arg0 + 0x4))) != (unsigned int)(arg3))) {
                if (((unsigned long)((unsigned int)(arg2)) == 2)) {
                    L_1156: ;
                    var3 = (unsigned long)((unsigned int)(arg2));
                    var8 = 0;
                    victim = 0;
                    L_1170: ;
                    while (((unsigned long)((unsigned int)(*(int *)(((long)arg0 + var8 * 4)))) != 0)) {
                        var12 = (unsigned long)((unsigned int)(var8));
                        if (((long)((int)(arg1[(long)(victim)])) <= (long)((int)(*(int *)(((long)arg1 + var8 * 4)))))) {
                            var12 = (unsigned long)((unsigned int)(victim));
                        }
                        index = (var8 + 1);
                        var8 = (unsigned long)((unsigned int)(index));
                        victim = (unsigned long)((unsigned int)(var12));
                        if ((var3 == index)) {
                            var2 = (long)((int)(var12));
                            *(int *)(((long)arg5)) = arg0[(long)((int)(var12))];
                            arg0[(long)((int)(var12))] = arg3;
                            ret = 2;
                        } else {
                            goto L_1170;
                        }
                        *(int *)(((long)arg1 + var2 * 4)) = arg4;
                        // x86-64 epilogue: tear down frame
                        return ret;
                    }
                    var2 = (unsigned long)((unsigned int)(var8));
                    arg0[(unsigned long)((unsigned int)(var8))] = arg3;
                    ret = 0;
                } else {
                    var2 = 2;
                    if (((unsigned int)(*(int *)(((long)arg0 + 0x8))) != (unsigned int)(arg3))) {
                        if (((unsigned long)((unsigned int)(arg2)) == 3)) {
                            goto L_1156;
                        } else {
                            var2 = 3;
                            if (((unsigned int)(*(int *)(((long)arg0 + 0xc))) != (unsigned int)(arg3))) {
                                if (((unsigned long)((unsigned int)(arg2)) == 4)) {
                                    goto L_1156;
                                } else {
                                    var2 = 4;
                                    if (((unsigned int)(*(int *)(((long)arg0 + 0x10))) != (unsigned int)(arg3))) {
                                        if (((unsigned long)((unsigned int)(arg2)) == 5)) {
                                            goto L_1156;
                                        } else {
                                            var2 = 5;
                                            if (((unsigned int)(*(int *)(((long)arg0 + 0x14))) != (unsigned int)(arg3))) {
                                                if (((unsigned long)((unsigned int)(arg2)) == 6)) {
                                                    goto L_1156;
                                                } else {
                                                    var2 = 6;
                                                    if (((unsigned int)(*(int *)(((long)arg0 + 0x18))) != (unsigned int)(arg3))) {
                                                        if (((unsigned long)((unsigned int)(arg2)) == 7)) {
                                                            goto L_1156;
                                                        } else {
                                                            var2 = 7;
                                                            if (((unsigned int)(*(int *)(((long)arg0 + 0x1c))) != (unsigned int)(arg3))) {
                                                                goto L_1156;
                                                            } else {
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        } else {
            goto L_1156;
        }
    } else {
        var2 = 0;
    }
}

clang -O0

1/1
lru_access pass 64 lines
// glaurung: lru_access @ 0x1100
int32_t lru_access(int32_t * arg0, int32_t * arg1, int32_t arg2, int32_t arg3, int32_t arg4, int32_t * arg5) {
    int victim;
    int index;
    int local_4;
    victim = 0;
    if ((arg0 != 0)) {
        if ((arg1 != 0)) {
            if ((arg5 != 0)) {
                if ((1 <= (long)(arg2))) {
                    if (((((unsigned long)((unsigned int)(arg2)) == 8) | ((long)(arg2) < 8)) != 0)) {
                        if ((0 <= (long)(arg4))) {
                            goto L_116c;
                        }
                    }
                }
            }
        }
    }
    local_4 = -1;
    // x86-64 epilogue: restore rbp
    return (unsigned int)(local_4);
    L_116c: ;
    *(int *)((long)arg5) = -1;
    index = 0;
    L_117d: ;
    if ((arg2 <= index)) {
        goto L_11ca;
    }
    if (((unsigned int)(arg0[(long)(index)]) == (unsigned int)(arg3))) {
        arg1[(long)(index)] = arg4;
        // x86-64 epilogue: restore rbp
        return 1;
    }
    goto L_11bc;
    L_11bc: ;
    index = ((unsigned int)(index) + 1);
    goto L_117d;
    L_11ca: ;
    index = 0;
    L_11d1: ;
    if ((arg2 <= index)) {
        goto L_124c;
    }
    if (((unsigned long)((unsigned int)(arg0[(long)(index)])) == 0)) {
        arg0[(long)(index)] = arg3;
        arg1[(long)(index)] = arg4;
        // x86-64 epilogue: restore rbp
        return 0;
    }
    if (((long)((int)(arg1[(long)(index)])) < (long)((int)(arg1[(long)(victim)])))) {
        victim = index;
    }
    goto L_123e;
    L_123e: ;
    index = ((unsigned int)(index) + 1);
    goto L_11d1;
    L_124c: ;
    *(int *)((long)arg5) = arg0[(long)(victim)];
    arg0[(long)(victim)] = arg3;
    arg1[(long)(victim)] = arg4;
    // x86-64 epilogue: restore rbp
    return 2;
}

gcc -O0

1/1
lru_access pass 58 lines
// glaurung: lru_access @ 0x10f9
int32_t lru_access(int32_t * arg0, int32_t * arg1, int32_t arg2, int32_t arg3, int32_t arg4, int32_t * arg5) {
    int victim;
    int index;
    victim = 0;
    if ((arg0 != 0)) {
        if ((arg1 != 0)) {
            if ((arg5 != 0)) {
                if (((((unsigned long)((unsigned int)(arg2)) == 0) | ((long)(arg2) < 0)) == 0)) {
                    if (((((unsigned long)((unsigned int)(arg2)) == 8) | ((long)(arg2) < 8)) != 0)) {
                        if ((0 <= (long)(arg4))) {
                            goto L_114f;
                        }
                    }
                }
            }
        }
    }
    // x86-64 epilogue: restore rbp
    return 0xffffffff;
    L_114f: ;
    *(int *)((long)arg5) = -1;
    index = 0;
    goto L_11a4;
    L_1162: ;
    if (((unsigned int)(arg3) == (unsigned int)(arg0[(long)(index)]))) {
        arg1[(long)(index)] = arg4;
        // x86-64 epilogue: restore rbp
        return 1;
    }
    index = (index + 1);
    L_11a4: ;
    if ((index < arg2)) {
        goto L_1162;
    }
    index = 0;
    goto L_1248;
    L_11b8: ;
    if (((unsigned long)((unsigned int)(arg0[(long)(index)])) == 0)) {
        arg0[(long)(index)] = arg3;
        arg1[(long)(index)] = arg4;
        // x86-64 epilogue: restore rbp
        return 0;
    }
    if (((long)((int)(arg1[(long)(index)])) < (long)((int)(arg1[(long)(victim)])))) {
        victim = index;
    }
    index = (index + 1);
    L_1248: ;
    if ((index < arg2)) {
        goto L_11b8;
    }
    *(int *)((long)arg5) = arg0[(long)(victim)];
    arg0[(long)(victim)] = arg3;
    arg1[(long)(victim)] = arg4;
    // x86-64 epilogue: restore rbp
    return 2;
}

gcc -O2

1/1
lru_access pass 88 lines
// glaurung: lru_access @ 0x1100
int32_t lru_access(int32_t * arg0, int32_t * arg1, int32_t arg2, int32_t arg3, int32_t arg4, int32_t * arg5) {
    int index;
    int victim;
    long local_10;
    long local_8;
    long var0;
    long var1;
    long var10;
    long var15;
    long var16;
    long var17;
    long var2;
    int var20;
    int var21;
    int var24;
    long var25;
    long var4;
    long var6;
    long var7;
    long var8;
    long var9;
    local_8 = var0;
    local_10 = var1;
    if ((arg0 == 0)) {
        goto L_11dd;
    }
    var2 = (long)arg1;
    if ((arg1 == 0)) {
        goto L_11dd;
    }
    if (((unsigned long)(7) < (unsigned long)((unsigned long)((unsigned int)((arg2 - 1)))))) {
        goto L_11dd;
    }
    if ((arg5 == 0)) {
        goto L_11dd;
    }
    if (((long)(arg4) < 0)) {
        goto L_11dd;
    }
    *(int *)(((long)arg5)) = -1;
    var4 = (unsigned long)((unsigned int)(arg3));
    var6 = 0;
    do {
        var7 = (var6 * 4);
        if (((unsigned int)(*(int *)(((long)arg0 + var6 * 4))) == (unsigned int)(var4))) {
            goto L_11b8;
        }
        var8 = (var6 + 1);
        var6 = var8;
    } while (((((unsigned int)(arg2) == (unsigned int)(var8)) | ((long)(arg2) < (long)((int)(var8)))) == 0));
    var9 = (long)arg0;
    var10 = var2;
    var15 = 0;
    var16 = 0;
    do {
        var17 = (unsigned long)((unsigned int)(*(int *)((var9))));
        if (((unsigned long)((unsigned int)(var17)) == 0)) {
            goto L_11d0;
        }
        var20 = (((long)((int)(*(int *)((var10)))) < (long)((int)(*(int *)((var2 + ((long)((int)(var16)) * 4)))))) ? var15 : var16);
        var21 = (var15 + 1);
        var9 = (var9 + 4);
        var10 = (var10 + 4);
        var15 = (unsigned long)((unsigned int)(var21));
        var16 = (unsigned long)((unsigned int)(var20));
    } while (((((unsigned int)(arg2) == (unsigned int)(var21)) | (arg2 < var21)) == 0));
    var24 = 2;
    var25 = (long)(((long)arg0 + ((long)((int)(var20)) * 4)));
    *(int *)(((long)arg5)) = *(int *)((var25));
    *(int *)((var25)) = var4;
    *(int *)((var2 + ((long)((int)(var20)) * 4))) = arg4;
    L_11ad: ;
    // x86-64 epilogue: tear down frame
    return (unsigned int)(var24);
    L_11b8: ;
    *(int *)((var2 + var7)) = arg4;
    // x86-64 epilogue: tear down frame
    return 1;
    L_11d0: ;
    *(int *)((var9)) = var4;
    *(int *)((var10)) = arg4;
    // x86-64 epilogue: tear down frame
    return (unsigned int)(var17);
    L_11dd: ;
    var24 = 0xffffffff;
    goto L_11ad;
}

← 213 fixtures