Fixture 96
integer promotion
C · 4 functions · 4 lanes · 16 of 16 function-lanes behave identically
All 4 lanes recompile and return the same results as the original.
Integer promotion and the usual arithmetic conversions. Everything narrower than int promotes to int before arithmetic, so uint8_t * uint8_t is computed in int and can exceed 255 without wrapping.
#include <stdint.h>
/* Integer promotion and the usual arithmetic conversions. Everything narrower
* than int promotes to int before arithmetic, so uint8_t * uint8_t is computed
* in int and can exceed 255 without wrapping. */
__attribute__((noinline)) int32_t
promote_narrow_product(int32_t left, int32_t right) {
uint8_t a = (uint8_t)left;
uint8_t b = (uint8_t)right;
/* Promoted to int: 200 * 200 is 40000, not 64. */
return a * b;
}
__attribute__((noinline)) int32_t
promote_then_truncate(int32_t left, int32_t right) {
uint8_t a = (uint8_t)left;
uint8_t b = (uint8_t)right;
return (int32_t)(uint8_t)(a * b);
}
__attribute__((noinline)) int32_t
short_promotion_sign(int32_t value) {
int16_t narrow = (int16_t)value;
/* Promotes to int, keeping the sign; the addition happens in int. */
return narrow + 1;
}
__attribute__((noinline)) uint32_t
unsigned_conversion_rank(int32_t signed_value, uint32_t unsigned_value) {
/* The signed operand converts to unsigned: the comparison is unsigned. */
return ((uint32_t)signed_value < unsigned_value) ? 1u : 0u;
} 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/4promote_narrow_product pass 10 lines
// glaurung: promote_narrow_product @ 0x1100
int32_t promote_narrow_product(int32_t arg0, int32_t arg1) {
unsigned char a;
unsigned char b;
// x86-64 prologue: save rbp
a = arg0;
b = arg1;
// x86-64 epilogue: restore rbp
return (unsigned int)(((unsigned int)(a) * (unsigned int)(b)));
} promote_then_truncate pass 10 lines
// glaurung: promote_then_truncate @ 0x1130
int32_t promote_then_truncate(int32_t arg0, int32_t arg1) {
unsigned char a;
unsigned char b;
// x86-64 prologue: save rbp
a = arg0;
b = arg1;
// x86-64 epilogue: restore rbp
return (unsigned int)((unsigned char)(((unsigned long)((unsigned int)(((unsigned int)(a) * (unsigned int)(b)))) & 255)));
} short_promotion_sign pass 8 lines
// glaurung: short_promotion_sign @ 0x1160
int32_t short_promotion_sign(int32_t arg0) {
short narrow;
// x86-64 prologue: save rbp
narrow = arg0;
// x86-64 epilogue: restore rbp
return (unsigned int)((narrow + 1));
} unsigned_conversion_rank pass 6 lines
// glaurung: unsigned_conversion_rank @ 0x1180
uint32_t unsigned_conversion_rank(int32_t arg0, uint32_t arg1) {
// x86-64 prologue: save rbp
// x86-64 epilogue: restore rbp
return (((unsigned long)((unsigned long)((unsigned int)(arg0))) < (unsigned long)((unsigned long)(arg1))) ? 1 : 0);
} clang -O2
4/4promote_narrow_product pass 4 lines
// glaurung: promote_narrow_product @ 0x1100
int32_t promote_narrow_product(int32_t arg0, int32_t arg1) {
return (unsigned int)(((unsigned int)((unsigned char)((arg1 & 255))) * (unsigned int)((unsigned char)((arg0 & 255)))));
} promote_then_truncate pass 4 lines
// glaurung: promote_then_truncate @ 0x1110
int32_t promote_then_truncate(int32_t arg0, int32_t arg1) {
return (unsigned int)((unsigned char)(((unsigned long)((unsigned int)((arg0 * arg1))) & 255)));
} short_promotion_sign pass 4 lines
// glaurung: short_promotion_sign @ 0x1120
int32_t short_promotion_sign(int32_t arg0) {
return (unsigned int)(((int)((short)((arg0 & 0xffff))) + 1));
} unsigned_conversion_rank pass 4 lines
// glaurung: unsigned_conversion_rank @ 0x1130
uint32_t unsigned_conversion_rank(int32_t arg0, uint32_t arg1) {
return ((unsigned long)((unsigned long)((unsigned int)(arg0))) < (unsigned long)((unsigned long)(arg1)));
} gcc -O0
4/4promote_narrow_product pass 10 lines
// glaurung: promote_narrow_product @ 0x10f9
int32_t promote_narrow_product(int32_t arg0, int32_t arg1) {
unsigned char a;
unsigned char b;
// x86-64 prologue: save rbp
a = arg0;
b = arg1;
// x86-64 epilogue: restore rbp
return (unsigned int)(((unsigned int)(b) * (unsigned int)(a)));
} promote_then_truncate pass 12 lines
// glaurung: promote_then_truncate @ 0x1120
int32_t promote_then_truncate(int32_t arg0, int32_t arg1) {
unsigned char a;
unsigned char b;
long t60;
// x86-64 prologue: save rbp
a = arg0;
b = arg1;
t60 = ((unsigned long)(a) & 255);
// x86-64 epilogue: restore rbp
return (unsigned int)((unsigned char)(((((t60 * b) & 255) | ((((unsigned char)(((unsigned short)(unsigned char)(t60) * (unsigned short)(unsigned char)(b)) >> 8)) & 255) << 8)) & 255)));
} short_promotion_sign pass 8 lines
// glaurung: short_promotion_sign @ 0x1146
int32_t short_promotion_sign(int32_t arg0) {
short narrow;
// x86-64 prologue: save rbp
narrow = arg0;
// x86-64 epilogue: restore rbp
return (unsigned int)((narrow + 1));
} unsigned_conversion_rank pass 9 lines
// glaurung: unsigned_conversion_rank @ 0x1161
uint32_t unsigned_conversion_rank(int32_t arg0, uint32_t arg1) {
// x86-64 prologue: save rbp
if (((unsigned long)(arg1) <= (unsigned long)((unsigned long)((unsigned int)(arg0))))) {
return 0;
} else {
return 1;
}
} gcc -O2
4/4promote_narrow_product pass 5 lines
// glaurung: promote_narrow_product @ 0x1100
int32_t promote_narrow_product(int32_t arg0, int32_t arg1) {
unsigned char b;
return (unsigned int)(((unsigned int)((unsigned char)((arg0 & 255))) * (unsigned int)((unsigned char)((arg1 & 255)))));
} promote_then_truncate pass 4 lines
// glaurung: promote_then_truncate @ 0x1110
int32_t promote_then_truncate(int32_t arg0, int32_t arg1) {
return (unsigned int)((unsigned char)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) * arg1))) & 255)));
} short_promotion_sign pass 4 lines
// glaurung: short_promotion_sign @ 0x1120
int32_t short_promotion_sign(int32_t arg0) {
return (unsigned int)(((int)((short)((arg0 & 0xffff))) + 1));
} unsigned_conversion_rank pass 4 lines
// glaurung: unsigned_conversion_rank @ 0x1130
uint32_t unsigned_conversion_rank(int32_t arg0, uint32_t arg1) {
return ((unsigned long)((unsigned long)((unsigned int)(arg0))) < (unsigned long)((unsigned long)(arg1)));
}