Fixture 83
ternary chains
C · 3 functions · 4 lanes · 12 of 12 function-lanes behave identically
All 4 lanes recompile and return the same results as the original.
Nested conditional expressions. The conditional operator is right-associative and yields an lvalue-free result whose type is the usual arithmetic conversion of both arms, so an incorrectly widened arm changes the answer.
#include <stdint.h>
/* Nested conditional expressions. The conditional operator is right-associative
* and yields an lvalue-free result whose type is the usual arithmetic
* conversion of both arms, so an incorrectly widened arm changes the answer. */
__attribute__((noinline)) int32_t
classify_ladder(int32_t value) {
return value < -100 ? -3
: value < -10 ? -2
: value < 0 ? -1
: value == 0 ? 0
: value < 10 ? 1
: value < 100 ? 2
: 3;
}
__attribute__((noinline)) uint32_t
ternary_mixed_types(int32_t selector, int32_t signed_arm, uint32_t unsigned_arm) {
/* Both arms convert to unsigned int: the signed arm is converted, not the
* other way round. A negative signed_arm therefore wraps. */
return selector ? (uint32_t)signed_arm : unsigned_arm;
}
__attribute__((noinline)) int32_t
nested_ternary_assignment(int32_t a, int32_t b, int32_t c, int32_t *out) {
int32_t result;
if (out == 0) {
return -1;
}
result = (a > b) ? ((b > c) ? a - c : ((a > c) ? a - b : c - a))
: ((a > c) ? b - c : ((b > c) ? b - a : c - b));
*out = result;
return (a > b) + (b > c) + (a > 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
3/3classify_ladder pass 25 lines
// glaurung: classify_ladder @ 0x1100
int32_t classify_ladder(int32_t arg0) {
int local_10;
int local_14;
// x86-64 prologue: save rbp
if ((-100 <= (long)(arg0))) {
if ((-10 <= (long)(arg0))) {
if ((0 <= (long)(arg0))) {
if (((unsigned long)((unsigned int)(arg0)) != 0)) {
local_14 = ((10 <= (long)(arg0)) ? (((long)(arg0) < 100) ? 2 : 3) : 1);
} else {
local_14 = 0;
}
local_10 = local_14;
} else {
local_10 = 0xffffffff;
}
return (unsigned int)(local_10);
} else {
return 0xfffffffe;
}
} else {
return 0xfffffffd;
}
} nested_ternary_assignment pass 34 lines
// glaurung: nested_ternary_assignment @ 0x11e0
int32_t nested_ternary_assignment(int32_t arg0, int32_t arg1, int32_t arg2, int32_t * arg3) {
int result;
int local_20;
int local_24;
int local_28;
int local_2c;
int local_30;
// x86-64 prologue: save rbp
if ((arg3 != 0)) {
if ((((unsigned int)(arg0) == (unsigned int)(arg1)) | (arg0 < arg1))) {
if ((((unsigned int)(arg0) == (unsigned int)(arg2)) | (arg0 < arg2))) {
local_30 = ((((unsigned int)(arg1) == (unsigned int)(arg2)) | (arg1 < arg2)) ? ((unsigned long)((unsigned int)(arg2)) - (unsigned long)((unsigned int)(arg1))) : ((unsigned long)((unsigned int)(arg1)) - (unsigned long)((unsigned int)(arg0))));
local_2c = local_30;
} else {
local_2c = ((unsigned int)(arg1) - arg2);
}
local_28 = local_2c;
} else {
if ((((unsigned int)(arg1) == (unsigned int)(arg2)) | (arg1 < arg2))) {
local_24 = ((((unsigned int)(arg0) == (unsigned int)(arg2)) | (arg0 < arg2)) ? ((unsigned long)((unsigned int)(arg2)) - (unsigned long)((unsigned int)(arg0))) : ((unsigned long)((unsigned int)(arg0)) - (unsigned long)((unsigned int)(arg1))));
local_20 = local_24;
} else {
local_20 = ((unsigned int)(arg0) - arg2);
}
local_28 = local_20;
}
result = local_28;
*(int *)((long)arg3) = result;
return (unsigned int)(((unsigned long)((unsigned int)((((((unsigned int)(arg0) == (unsigned int)(arg1)) | (arg0 < arg1)) == 0) + ((((unsigned int)(arg1) == (unsigned int)(arg2)) | (arg1 < arg2)) == 0)))) + ((((unsigned int)(arg0) == (unsigned int)(arg2)) | (arg0 < arg2)) == 0)));
} else {
return (unsigned int)(-1);
}
} ternary_mixed_types pass 9 lines
// glaurung: ternary_mixed_types @ 0x11b0
uint32_t ternary_mixed_types(int32_t arg0, int32_t arg1, uint32_t arg2) {
// x86-64 prologue: save rbp
if (((unsigned long)((unsigned int)(arg0)) == 0)) {
return arg2;
} else {
return (unsigned int)(arg1);
}
} clang -O2
3/3classify_ladder pass 22 lines
// glaurung: classify_ladder @ 0x1100
int32_t classify_ladder(int32_t arg0) {
long ret;
ret = 0xfffffffd;
if ((-100 <= (long)(arg0))) {
ret = 0xfffffffe;
if (((long)(arg0) < -10)) {
return ret;
}
if (((long)(arg0) < 0)) {
return 0xffffffff;
}
if (((unsigned long)((unsigned int)(arg0)) == 0)) {
return 0;
}
ret = 1;
if (((unsigned long)(10) <= (unsigned long)((unsigned long)((unsigned int)(arg0))))) {
return (unsigned int)((3 - ((unsigned long)((unsigned long)((unsigned int)(arg0))) < (unsigned long)(100))));
}
}
return ret;
} nested_ternary_assignment pass 25 lines
// glaurung: nested_ternary_assignment @ 0x1150
int32_t nested_ternary_assignment(int32_t arg0, int32_t arg1, int32_t arg2, int32_t * arg3) {
int result;
int var1;
long var2;
if ((arg3 == 0)) {
return 0xffffffff;
}
var1 = ((unsigned int)(arg0) - arg1);
var2 = (unsigned long)((unsigned int)(var1));
if ((((unsigned long)((unsigned int)(var1)) == 0) | (arg0 < arg1))) {
result = ((((unsigned int)(arg0) == (unsigned int)(arg2)) | (arg0 < arg2)) ? ((((unsigned int)(arg1) == (unsigned int)(arg2)) | (arg1 < arg2)) ? (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg2)) - arg1))) : (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg1)) - arg0)))) : (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg1)) - arg2))));
} else {
if ((((unsigned int)(arg1) == (unsigned int)(arg2)) | (arg1 < arg2))) {
result = var2;
if (((((unsigned int)(arg0) == (unsigned int)(arg2)) | (arg0 < arg2)) != 0)) {
result = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg2)) - arg0)));
}
} else {
result = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) - arg2)));
}
}
*(int *)(((long)arg3)) = result;
return (unsigned int)((((((unsigned int)(arg0) == (unsigned int)(arg2)) | (arg0 < arg2)) == 0) + (unsigned long)((unsigned int)((((((unsigned int)(arg1) == (unsigned int)(arg2)) | (arg1 < arg2)) == 0) + ((((unsigned int)(arg0) == (unsigned int)(arg1)) | (arg0 < arg1)) == 0))))));
} ternary_mixed_types pass 4 lines
// glaurung: ternary_mixed_types @ 0x1140
uint32_t ternary_mixed_types(int32_t arg0, int32_t arg1, uint32_t arg2) {
return (((unsigned long)((unsigned int)(arg0)) == 0) ? arg2 : (unsigned long)((unsigned int)(arg1)));
} gcc -O0
3/3classify_ladder pass 29 lines
// glaurung: classify_ladder @ 0x10f9
int32_t classify_ladder(int32_t arg0) {
// x86-64 prologue: save rbp
if (((long)(arg0) < -100)) {
return 0xfffffffd;
} else {
if (((long)(arg0) < -10)) {
return 0xfffffffe;
} else {
if (((long)(arg0) < 0)) {
return 0xffffffff;
} else {
if (((unsigned long)((unsigned int)(arg0)) == 0)) {
return 0;
} else {
if ((((unsigned long)((unsigned int)(arg0)) == 9) | ((long)(arg0) < 9))) {
return 1;
} else {
if (((((unsigned long)((unsigned int)(arg0)) == 99) | ((long)(arg0) < 99)) == 0)) {
return 3;
} else {
return 2;
}
}
}
}
}
}
} nested_ternary_assignment pass 12 lines
// glaurung: nested_ternary_assignment @ 0x117a
int32_t nested_ternary_assignment(int32_t arg0, int32_t arg1, int32_t arg2, int32_t * arg3) {
int result;
// x86-64 prologue: save rbp
if ((arg3 != 0)) {
result = ((((unsigned int)(arg0) == (unsigned int)(arg1)) | (arg0 < arg1)) ? ((((unsigned int)(arg0) == (unsigned int)(arg2)) | (arg0 < arg2)) ? ((((unsigned int)(arg1) == (unsigned int)(arg2)) | (arg1 < arg2)) ? (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg2)) - arg1))) : (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg1)) - arg0)))) : (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg1)) - arg2)))) : ((((unsigned int)(arg1) == (unsigned int)(arg2)) | (arg1 < arg2)) ? ((((unsigned int)(arg0) == (unsigned int)(arg2)) | (arg0 < arg2)) ? (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg2)) - arg0))) : (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) - arg1)))) : (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) - arg2)))));
*(int *)((long)arg3) = result;
return (unsigned int)((((((unsigned int)(arg0) == (unsigned int)(arg2)) | (arg0 < arg2)) == 0) + (unsigned long)((unsigned int)((((((unsigned int)(arg0) == (unsigned int)(arg1)) | (arg0 < arg1)) == 0) + ((((unsigned int)(arg1) == (unsigned int)(arg2)) | (arg1 < arg2)) == 0))))));
} else {
return 0xffffffff;
}
} ternary_mixed_types pass 9 lines
// glaurung: ternary_mixed_types @ 0x1159
uint32_t ternary_mixed_types(int32_t arg0, int32_t arg1, uint32_t arg2) {
// x86-64 prologue: save rbp
if (((unsigned long)((unsigned int)(arg0)) == 0)) {
return arg2;
} else {
return (unsigned int)(arg1);
}
} gcc -O2
3/3classify_ladder pass 22 lines
// glaurung: classify_ladder @ 0x1100
int32_t classify_ladder(int32_t arg0) {
long ret;
if (((long)(arg0) < -100)) {
return 0xfffffffd;
}
if (((long)(arg0) < -10)) {
return 0xfffffffe;
}
if (((long)(arg0) < 0)) {
return 0xffffffff;
}
ret = 0;
if (((unsigned long)((unsigned int)(arg0)) == 0)) {
return ret;
}
ret = 1;
if ((((unsigned long)((unsigned int)(arg0)) == 9) | ((long)(arg0) < 9))) {
return ret;
}
return (unsigned int)((((((unsigned long)((unsigned int)(arg0)) == 99) | ((long)(arg0) < 99)) == 0) + 2));
} nested_ternary_assignment pass 9 lines
// glaurung: nested_ternary_assignment @ 0x1170
int32_t nested_ternary_assignment(int32_t arg0, int32_t arg1, int32_t arg2, int32_t * arg3) {
int result;
if ((arg3 == 0)) {
return 0xffffffff;
}
*(int *)(((long)arg3)) = (((((unsigned int)(arg0) == (unsigned int)(arg1)) | (arg0 < arg1)) == 0) ? ((((unsigned int)(arg1) == (unsigned int)(arg2)) | (arg1 < arg2)) ? (((((unsigned int)(arg0) == (unsigned int)(arg2)) | (arg0 < arg2)) == 0) ? (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) - arg1))) : (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg2)) - arg0)))) : (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) - arg2)))) : ((((unsigned int)(arg0) == (unsigned int)(arg2)) | (arg0 < arg2)) ? (((((unsigned int)(arg1) == (unsigned int)(arg2)) | (arg1 < arg2)) == 0) ? (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg1)) - arg0))) : (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg2)) - arg1)))) : (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg1)) - arg2)))));
return (unsigned int)(((unsigned long)((unsigned int)((((((unsigned int)(arg0) == (unsigned int)(arg1)) | (arg0 < arg1)) == 0) + ((((unsigned int)(arg1) == (unsigned int)(arg2)) | (arg1 < arg2)) == 0)))) + ((((unsigned int)(arg0) == (unsigned int)(arg2)) | (arg0 < arg2)) == 0)));
} ternary_mixed_types pass 4 lines
// glaurung: ternary_mixed_types @ 0x1160
uint32_t ternary_mixed_types(int32_t arg0, int32_t arg1, uint32_t arg2) {
return (((unsigned long)((unsigned int)(arg0)) == 0) ? arg2 : (unsigned long)((unsigned int)(arg1)));
}