Fixture 99
char and endianness
C · 4 functions · 4 lanes · 16 of 16 function-lanes behave identically
All 4 lanes recompile and return the same results as the original.
Plain char has implementation-defined signedness, so the same source reads 0x80 as -128 or 128 depending on target. Both spellings are pinned here, and the byte order is observed rather than assumed.
#include <stdint.h>
/* Plain `char` has implementation-defined signedness, so the same source reads
* 0x80 as -128 or 128 depending on target. Both spellings are pinned here, and
* the byte order is observed rather than assumed. */
__attribute__((noinline)) int32_t
plain_char_is_signed(void) {
char probe = (char)0x80;
return probe < 0;
}
__attribute__((noinline)) int32_t
char_widening(int32_t value) {
signed char narrow = (signed char)value;
unsigned char wide = (unsigned char)value;
return (int32_t)narrow * 1000 + (int32_t)wide;
}
__attribute__((noinline)) uint32_t
byte_swap32(uint32_t value) {
return ((value & 0x000000FFu) << 24) | ((value & 0x0000FF00u) << 8) |
((value & 0x00FF0000u) >> 8) | ((value & 0xFF000000u) >> 24);
}
__attribute__((noinline)) uint32_t
load_big_endian(const uint8_t *bytes, int32_t available) {
if (bytes == 0 || available < 4) {
return 0;
}
return ((uint32_t)bytes[0] << 24) | ((uint32_t)bytes[1] << 16) |
((uint32_t)bytes[2] << 8) | (uint32_t)bytes[3];
} 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
4/4byte_swap32 pass 6 lines
// glaurung: byte_swap32 @ 0x1150
uint32_t byte_swap32(uint32_t arg0) {
// 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)(((unsigned long)((unsigned int)(((unsigned long)(arg0) & 255))) << 24))) | (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(((unsigned long)(arg0) & 0xff00))) << 8)))))) | (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(((unsigned long)(arg0) & 0xff0000))) >> 8)))))) | (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(((unsigned long)(arg0) & -0x1000000LL))) >> 24)))));
} char_widening pass 10 lines
// glaurung: char_widening @ 0x1120
int32_t char_widening(int32_t arg0) {
signed char narrow;
unsigned char wide;
// x86-64 prologue: save rbp
narrow = arg0;
wide = arg0;
// x86-64 epilogue: restore rbp
return (unsigned int)(((narrow * 1000) + (unsigned int)(wide)));
} load_big_endian pass 16 lines
// glaurung: load_big_endian @ 0x1190
uint32_t load_big_endian(const uint8_t * arg0, int32_t arg1) {
int local_4;
// x86-64 prologue: save rbp
if ((arg0 == 0)) {
// x86-64 epilogue: restore rbp
return 0;
}
if (((long)(arg1) < 4)) {
// x86-64 epilogue: restore rbp
return 0;
}
local_4 = ((unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(((unsigned int)((unsigned char)(*(char *)((long)arg0))) << 24))) | (unsigned long)((unsigned int)(((unsigned int)((unsigned char)(*(char *)(((long)arg0 + 0x1)))) << 16)))))) | (unsigned long)((unsigned int)(((unsigned int)((unsigned char)(*(char *)(((long)arg0 + 0x2)))) << 8))))) | (unsigned int)((unsigned char)(*(char *)(((long)arg0 + 0x3)))));
// x86-64 epilogue: restore rbp
return (unsigned int)(local_4);
} plain_char_is_signed pass 8 lines
// glaurung: plain_char_is_signed @ 0x1100
int32_t plain_char_is_signed(void) {
signed char probe;
// x86-64 prologue: save rbp
probe = -128;
// x86-64 epilogue: restore rbp
return ((long)(probe) < 0);
} clang -O2
4/4byte_swap32 pass 4 lines
// glaurung: byte_swap32 @ 0x1120
uint32_t byte_swap32(uint32_t arg0) {
return (unsigned int)((((((arg0 & 255) << 24) | (((arg0 >> 8) & 255) << 16)) | (((arg0 >> 16) & 255) << 8)) | ((arg0 >> 24) & 255)));
} char_widening pass 6 lines
// glaurung: char_widening @ 0x1110
int32_t char_widening(int32_t arg0) {
int var0;
var0 = (int)((signed char)((arg0 & 255)));
return (unsigned int)(((unsigned int)((unsigned char)((var0 & 255))) + (var0 * 1000)));
} load_big_endian pass 14 lines
// glaurung: load_big_endian @ 0x1130
uint32_t load_big_endian(const uint8_t * arg0, int32_t arg1) {
long ret;
long var2;
ret = 0;
if ((arg0 != 0)) {
ret = 0;
if ((4 <= (long)(arg1))) {
var2 = (unsigned long)((unsigned int)(*(int *)(((long)arg0))));
ret = (unsigned int)(((((((unsigned int)(var2) & 255) << 24) | ((((unsigned int)(var2) >> 8) & 255) << 16)) | ((((unsigned int)(var2) >> 16) & 255) << 8)) | (((unsigned int)(var2) >> 24) & 255)));
}
}
return ret;
} plain_char_is_signed pass 4 lines
// glaurung: plain_char_is_signed @ 0x1100
int32_t plain_char_is_signed(void) {
return 1;
} gcc -O0
4/4byte_swap32 pass 6 lines
// glaurung: byte_swap32 @ 0x113a
uint32_t byte_swap32(uint32_t arg0) {
// x86-64 prologue: save rbp
// x86-64 epilogue: restore rbp
return (unsigned int)(((unsigned long)((unsigned int)(((unsigned long)(arg0) >> 24))) | (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(((unsigned long)(arg0) << 24))) | (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(((unsigned long)(arg0) << 8))) & 0xff0000)))))) | (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(((unsigned long)(arg0) >> 8))) & 0xff00))))))));
} char_widening pass 10 lines
// glaurung: char_widening @ 0x1111
int32_t char_widening(int32_t arg0) {
signed char narrow;
unsigned char wide;
// x86-64 prologue: save rbp
narrow = arg0;
wide = arg0;
// x86-64 epilogue: restore rbp
return (unsigned int)(((unsigned int)(wide) + (narrow * 1000)));
} load_big_endian pass 14 lines
// glaurung: load_big_endian @ 0x1171
uint32_t load_big_endian(const uint8_t * arg0, int32_t arg1) {
// x86-64 prologue: save rbp
if ((arg0 == 0)) {
// x86-64 epilogue: restore rbp
return 0;
}
if (((((unsigned long)((unsigned int)(arg1)) == 3) | ((long)(arg1) < 3)) != 0)) {
// x86-64 epilogue: restore rbp
return 0;
}
// x86-64 epilogue: restore rbp
return (unsigned int)(((unsigned int)((unsigned char)(((unsigned int)((unsigned char)(arg0[3])) & 255))) | (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(((unsigned int)((unsigned char)(((unsigned int)((unsigned char)(*(char *)((long)arg0))) & 255))) << 24))) | (unsigned long)((unsigned int)(((unsigned int)((unsigned char)(((unsigned int)((unsigned char)(arg0[1])) & 255))) << 16)))))) | (unsigned long)((unsigned int)(((unsigned int)((unsigned char)(((unsigned int)((unsigned char)(arg0[2])) & 255))) << 8))))))));
} plain_char_is_signed pass 8 lines
// glaurung: plain_char_is_signed @ 0x10f9
int32_t plain_char_is_signed(void) {
signed char probe;
// x86-64 prologue: save rbp
probe = -128;
// x86-64 epilogue: restore rbp
return (unsigned int)((unsigned char)((((unsigned long)((unsigned char)(((unsigned int)((unsigned char)(probe)) & 255))) >> 7) & 255)));
} gcc -O2
4/4byte_swap32 pass 4 lines
// glaurung: byte_swap32 @ 0x1130
uint32_t byte_swap32(uint32_t arg0) {
return (unsigned int)((((((arg0 & 255) << 24) | (((arg0 >> 8) & 255) << 16)) | (((arg0 >> 16) & 255) << 8)) | ((arg0 >> 24) & 255)));
} char_widening pass 6 lines
// glaurung: char_widening @ 0x1110
int32_t char_widening(int32_t arg0) {
signed char narrow;
unsigned char wide;
return (unsigned int)((((int)((signed char)((arg0 & 255))) * 1000) + (unsigned int)((unsigned char)((arg0 & 255)))));
} load_big_endian pass 11 lines
// glaurung: load_big_endian @ 0x1140
uint32_t load_big_endian(const uint8_t * arg0, int32_t arg1) {
long var1;
if ((arg0 != 0)) {
if (((((unsigned long)((unsigned int)(arg1)) == 3) | ((long)(arg1) < 3)) == 0)) {
var1 = (unsigned long)((unsigned int)(*(int *)(((long)arg0))));
return (unsigned int)(((((((unsigned int)(var1) & 255) << 24) | ((((unsigned int)(var1) >> 8) & 255) << 16)) | ((((unsigned int)(var1) >> 16) & 255) << 8)) | (((unsigned int)(var1) >> 24) & 255)));
}
}
return 0;
} plain_char_is_signed pass 4 lines
// glaurung: plain_char_is_signed @ 0x1100
int32_t plain_char_is_signed(void) {
return 1;
}