Fixture 89
bool semantics
C · 3 functions · 4 lanes · 12 of 12 function-lanes behave identically
All 4 lanes recompile and return the same results as the original.
_Bool normalizes any nonzero value to 1 on conversion, which is a real instruction sequence (test/setne), not a no-op cast. Storing into a _Bool and reading it back is therefore lossy in a specific, observable way.
#include <stdint.h>
/* _Bool normalizes any nonzero value to 1 on conversion, which is a real
* instruction sequence (test/setne), not a no-op cast. Storing into a _Bool and
* reading it back is therefore lossy in a specific, observable way. */
__attribute__((noinline)) int32_t
bool_normalizes(int32_t value) {
_Bool flag = (_Bool)value;
return (int32_t)flag;
}
__attribute__((noinline)) int32_t
bool_roundtrip_mask(int32_t value) {
/* Only bit 8 is inspected, but the result is still normalized to 0 or 1. */
_Bool flag = (value & 0x100) != 0;
return flag ? 1000 : 2000;
}
__attribute__((noinline)) int32_t
bool_arithmetic(int32_t a, int32_t b, int32_t c) {
/* Relational operators yield int 0/1; summing them counts satisfied
* predicates without any branch. */
return (a > b) + (b > c) + (c > a) + (_Bool)(a | b | 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/3bool_arithmetic pass 6 lines
// glaurung: bool_arithmetic @ 0x1150
int32_t bool_arithmetic(int32_t arg0, int32_t arg1, int32_t arg2) {
// x86-64 prologue: save rbp
// x86-64 epilogue: restore rbp
return (unsigned int)(((unsigned long)((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)(arg2) == (unsigned int)(arg0)) | (arg2 < arg0)) == 0)))) + ((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) | arg1))) | arg2))) != 0)));
} bool_normalizes pass 7 lines
// glaurung: bool_normalizes @ 0x1100
int32_t bool_normalizes(int32_t arg0) {
int flag;
// x86-64 prologue: save rbp
// x86-64 epilogue: restore rbp
return ((unsigned long)((unsigned int)(arg0)) != 0);
} bool_roundtrip_mask pass 7 lines
// glaurung: bool_roundtrip_mask @ 0x1120
int32_t bool_roundtrip_mask(int32_t arg0) {
int flag;
// x86-64 prologue: save rbp
// x86-64 epilogue: restore rbp
return (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 256))) != 0) ? 1000 : 2000);
} clang -O2
3/3bool_arithmetic pass 4 lines
// glaurung: bool_arithmetic @ 0x1130
int32_t bool_arithmetic(int32_t arg0, int32_t arg1, int32_t arg2) {
return (unsigned int)((((unsigned long)((unsigned int)(((unsigned long)((unsigned int)((arg1 | arg0))) | arg2))) != 0) + (unsigned long)((unsigned int)((((((unsigned int)(arg2) == (unsigned int)(arg0)) | (arg2 < arg0)) == 0) + (unsigned long)((unsigned int)((((((unsigned int)(arg1) == (unsigned int)(arg2)) | (arg1 < arg2)) == 0) + ((((unsigned int)(arg0) == (unsigned int)(arg1)) | (arg0 < arg1)) == 0)))))))));
} bool_normalizes pass 4 lines
// glaurung: bool_normalizes @ 0x1100
int32_t bool_normalizes(int32_t arg0) {
return ((unsigned long)((unsigned int)(arg0)) != 0);
} bool_roundtrip_mask pass 4 lines
// glaurung: bool_roundtrip_mask @ 0x1110
int32_t bool_roundtrip_mask(int32_t arg0) {
return (((unsigned long)((unsigned int)((arg0 & 256))) == 0) ? 2000 : 1000);
} gcc -O0
3/3bool_arithmetic pass 6 lines
// glaurung: bool_arithmetic @ 0x1143
int32_t bool_arithmetic(int32_t arg0, int32_t arg1, int32_t arg2) {
// x86-64 prologue: save rbp
// x86-64 epilogue: restore rbp
return (unsigned int)((((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) | arg1))) | arg2))) != 0) + (unsigned long)((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)(arg2) == (unsigned int)(arg0)) | (arg2 < arg0)) == 0))))));
} bool_normalizes pass 7 lines
// glaurung: bool_normalizes @ 0x10f9
int32_t bool_normalizes(int32_t arg0) {
int flag;
// x86-64 prologue: save rbp
// x86-64 epilogue: restore rbp
return ((unsigned long)((unsigned int)(arg0)) != 0);
} bool_roundtrip_mask pass 11 lines
// glaurung: bool_roundtrip_mask @ 0x1114
int32_t bool_roundtrip_mask(int32_t arg0) {
int flag;
// x86-64 prologue: save rbp
flag = ((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) & 256))) != 0);
if (((unsigned long)((unsigned char)(flag)) == 0)) {
return 2000;
} else {
return 1000;
}
} gcc -O2
3/3bool_arithmetic pass 4 lines
// glaurung: bool_arithmetic @ 0x1130
int32_t bool_arithmetic(int32_t arg0, int32_t arg1, int32_t arg2) {
return (unsigned int)(((unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)((((((unsigned int)(arg0) == (unsigned int)(arg1)) | (arg0 < arg1)) == 0) + ((((unsigned int)(arg1) == (unsigned int)(arg2)) | (arg1 < arg2)) == 0)))) + (arg0 < arg2)))) + 1)) - ((unsigned long)((unsigned long)((unsigned int)(((unsigned long)((unsigned int)((arg1 | arg2))) | arg0)))) < (unsigned long)(1))));
} bool_normalizes pass 4 lines
// glaurung: bool_normalizes @ 0x1100
int32_t bool_normalizes(int32_t arg0) {
return ((unsigned long)((unsigned int)(arg0)) != 0);
} bool_roundtrip_mask pass 4 lines
// glaurung: bool_roundtrip_mask @ 0x1110
int32_t bool_roundtrip_mask(int32_t arg0) {
return (unsigned int)(((unsigned long)((unsigned int)(((unsigned int)((0 - ((unsigned long)((unsigned long)((unsigned int)((arg0 & 256)))) < (unsigned long)(1)))) & 1000))) + 1000));
}