Fixture 138
cpp operators
C++ · 3 functions · 4 lanes · 9 of 12 function-lanes behave identically
One lane has a function that returns a different result after decompilation: gcc-O0 (0/3).
Operator overloading turns ordinary-looking syntax into calls. a + b on a class type is a function call with a hidden this or two by-value arguments; a conversion operator inserts a call where the source shows no call at all.
/* 138_cpp_operators.cpp
*
* Operator overloading turns ordinary-looking syntax into calls. `a + b` on a
* class type is a function call with a hidden `this` or two by-value arguments;
* a conversion operator inserts a call where the source shows no call at all.
*/
#include <stdint.h>
namespace {
class Fixed {
public:
int32_t raw;
explicit Fixed(int32_t value) : raw(value) {}
Fixed operator+(const Fixed &other) const {
return Fixed(static_cast<int32_t>(
static_cast<uint32_t>(raw) + static_cast<uint32_t>(other.raw)));
}
Fixed operator*(const Fixed &other) const {
return Fixed(static_cast<int32_t>(
(static_cast<int64_t>(raw) * static_cast<int64_t>(other.raw)) >> 16));
}
Fixed &operator+=(const Fixed &other) {
raw = static_cast<int32_t>(static_cast<uint32_t>(raw) +
static_cast<uint32_t>(other.raw));
return *this;
}
bool operator<(const Fixed &other) const { return raw < other.raw; }
int32_t operator[](int32_t index) const { return (raw >> (index & 15)) & 1; }
/* An implicit conversion: appears as no call in the source. */
operator int32_t() const { return raw >> 16; }
};
} // namespace
extern "C" int32_t cpp_operator_arithmetic(int32_t a, int32_t b) {
Fixed left(a);
Fixed right(b);
Fixed sum = left + right;
Fixed product = left * right;
return sum.raw ^ product.raw;
}
extern "C" int32_t cpp_operator_compound(int32_t seed, int32_t steps) {
Fixed value(seed);
Fixed step(1 << 16);
if (steps < 0 || steps > 16) {
return -1;
}
for (int32_t index = 0; index < steps; ++index) {
value += step;
}
return value.raw;
}
extern "C" int32_t cpp_operator_conversion(int32_t a, int32_t b) {
Fixed left(a);
Fixed right(b);
/* Both operands convert to int32_t through the conversion operator. */
int32_t widened = left + 0;
int32_t compared = (left < right) ? 1 : 0;
return widened * 10 + compared + left[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.
gcc -O0
0/3cpp_operator_arithmetic fail 29 lines
// glaurung: cpp_operator_arithmetic @ 0x126b
int32_t cpp_operator_arithmetic(int32_t arg0, int32_t arg1) {
extern void _ZN12_GLOBAL__N_15FixedC2Ei(char *, int);
extern unsigned int _ZNK12_GLOBAL__N_15FixedmlERKS0_(char *, int *);
extern unsigned int _ZNK12_GLOBAL__N_15FixedplERKS0_(char *, int *);
extern __attribute__((noreturn)) void __stack_chk_fail(void);
unsigned char local_10[4];
unsigned char local_14[4];
unsigned char local_18[4];
long local_8;
unsigned char local_c[4];
long ret;
unsigned int var13;
unsigned int var9;
// x86-64 prologue: save rbp, frame 48 bytes
local_8 = (long)(0x28);
_ZN12_GLOBAL__N_15FixedC2Ei((char *)(&local_18[0]), (unsigned long)((unsigned int)(arg0)));
_ZN12_GLOBAL__N_15FixedC2Ei((char *)(&local_14[0]), (unsigned long)((unsigned int)(arg1)));
var9 = _ZNK12_GLOBAL__N_15FixedplERKS0_((char *)(&local_18[0]), (int *)(&local_14[0]));
*(int *)(&local_10[0]) = var9;
var13 = _ZNK12_GLOBAL__N_15FixedmlERKS0_((char *)(&local_18[0]), (int *)(&local_14[0]));
*(int *)(&local_c[0]) = var13;
ret = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(*(int *)(&local_c[0]))) ^ (unsigned long)((unsigned int)(*(int *)(&local_10[0]))))));
if ((local_8 != 0x28)) {
__stack_chk_fail();
}
// x86-64 epilogue: restore rbp
return ret;
} cpp_operator_compound fail 29 lines
// glaurung: cpp_operator_compound @ 0x12f8
int32_t cpp_operator_compound(int32_t arg0, int32_t arg1) {
extern void _ZN12_GLOBAL__N_15FixedC2Ei(char *, int);
extern long _ZN12_GLOBAL__N_15FixedpLERKS0_(char *, int *);
extern __attribute__((noreturn)) void __stack_chk_fail(void);
int index;
unsigned char local_10[4];
unsigned char local_14[4];
long local_8;
long ret;
long var9;
// x86-64 prologue: save rbp, frame 48 bytes
local_8 = (long)(0x28);
_ZN12_GLOBAL__N_15FixedC2Ei((char *)(&local_14[0]), (unsigned long)((unsigned int)(arg0)));
_ZN12_GLOBAL__N_15FixedC2Ei((char *)(&local_10[0]), 0x10000);
if ((((long)(arg1) < 0) || (((unsigned long)((unsigned int)(arg1)) != 16) && (16 <= (long)(arg1))))) {
ret = 0xffffffff;
} else {
for (index = 0; (index < arg1); index++) {
var9 = _ZN12_GLOBAL__N_15FixedpLERKS0_((char *)(&local_14[0]), (int *)(&local_10[0]));
}
ret = (unsigned long)((unsigned int)(*(int *)(&local_14[0])));
}
if ((local_8 != 0x28)) {
__stack_chk_fail();
}
// x86-64 epilogue: restore rbp
return ret;
} cpp_operator_conversion fail 36 lines
// glaurung: cpp_operator_conversion @ 0x138f
int32_t cpp_operator_conversion(int32_t arg0, int32_t arg1) {
extern void _ZN12_GLOBAL__N_15FixedC2Ei(char *, int);
extern int _ZNK12_GLOBAL__N_15FixedcviEv(char *);
extern int _ZNK12_GLOBAL__N_15FixedixEi(char *, int);
extern int _ZNK12_GLOBAL__N_15FixedltERKS0_(char *, int *);
extern __attribute__((noreturn)) void __stack_chk_fail(void);
int widened;
int compared;
long local_18;
unsigned char local_24[4];
unsigned char local_28[4];
long ret;
int var12;
int var19;
long var25;
int var27;
int var8;
// x86-64 prologue: save rbp, frame 8 bytes
local_18 = (long)(0x28);
_ZN12_GLOBAL__N_15FixedC2Ei((char *)(&local_28[0]), (unsigned long)((unsigned int)(arg0)));
_ZN12_GLOBAL__N_15FixedC2Ei((char *)(&local_24[0]), (unsigned long)((unsigned int)(arg1)));
var8 = _ZNK12_GLOBAL__N_15FixedcviEv((char *)(&local_28[0]));
widened = var8;
var12 = _ZNK12_GLOBAL__N_15FixedltERKS0_((char *)(&local_28[0]), (int *)(&local_24[0]));
compared = (((unsigned long)((unsigned char)((var12 & 255))) == 0) ? 0 : 1);
var19 = ((unsigned int)(((unsigned long)((unsigned int)(widened)) << 2)) + (unsigned int)(widened));
var25 = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var19)) + (unsigned long)((unsigned int)(var19))))) + (unsigned long)((unsigned int)(compared)))));
var27 = _ZNK12_GLOBAL__N_15FixedixEi((char *)(&local_28[0]), 3);
ret = (unsigned long)((unsigned int)((var27 + var25)));
if ((local_18 != 0x28)) {
__stack_chk_fail();
}
// x86-64 epilogue: restore rbp
return ret;
} clang -O0
3/3cpp_operator_arithmetic pass 21 lines
// glaurung: cpp_operator_arithmetic @ 0x1100
__attribute__((no_stack_protector)) int32_t cpp_operator_arithmetic(int32_t arg0, int32_t arg1) {
extern void _ZN12_GLOBAL__N_15FixedC2Ei(char *, int);
extern unsigned int _ZNK12_GLOBAL__N_15FixedmlERKS0_(char *, int *);
extern unsigned int _ZNK12_GLOBAL__N_15FixedplERKS0_(char *, int *);
unsigned char local_10[4];
unsigned char local_18[4];
unsigned char local_20[4];
unsigned char local_28[4];
unsigned int var0;
unsigned int var2;
// x86-64 prologue: save rbp, frame 48 bytes
_ZN12_GLOBAL__N_15FixedC2Ei((char *)(&local_10[0]), (unsigned long)((unsigned int)(arg0)));
_ZN12_GLOBAL__N_15FixedC2Ei((char *)(&local_18[0]), (unsigned long)((unsigned int)(arg1)));
var0 = _ZNK12_GLOBAL__N_15FixedplERKS0_((char *)(&local_10[0]), (int *)(&local_18[0]));
*(int *)(&local_20[0]) = var0;
var2 = _ZNK12_GLOBAL__N_15FixedmlERKS0_((char *)(&local_10[0]), (int *)(&local_18[0]));
*(int *)(&local_28[0]) = var2;
// x86-64 epilogue: restore rbp
return (unsigned int)(((unsigned long)((unsigned int)(*(int *)(&local_20[0]))) ^ *(int *)(&local_28[0])));
} cpp_operator_compound pass 29 lines
// glaurung: cpp_operator_compound @ 0x11f0
__attribute__((no_stack_protector)) int32_t cpp_operator_compound(int32_t arg0, int32_t arg1) {
extern void _ZN12_GLOBAL__N_15FixedC2Ei(char *, int);
extern long _ZN12_GLOBAL__N_15FixedpLERKS0_(char *, int *);
int index;
unsigned char local_10[4];
unsigned char local_18[4];
int local_4;
long var1;
// x86-64 prologue: save rbp, frame 32 bytes
_ZN12_GLOBAL__N_15FixedC2Ei((char *)(&local_10[0]), (unsigned long)((unsigned int)(arg0)));
_ZN12_GLOBAL__N_15FixedC2Ei((char *)(&local_18[0]), 0x10000);
if (((long)(arg1) < 0)) {
local_4 = -1;
// x86-64 epilogue: restore rbp
return (unsigned int)(local_4);
}
if (((((unsigned long)((unsigned int)(arg1)) == 16) | ((long)(arg1) < 16)) == 0)) {
local_4 = -1;
// x86-64 epilogue: restore rbp
return (unsigned int)(local_4);
}
for (index = 0; (index < arg1); index++) {
var1 = _ZN12_GLOBAL__N_15FixedpLERKS0_((char *)(&local_10[0]), (int *)(&local_18[0]));
}
local_4 = *(int *)(&local_10[0]);
// x86-64 epilogue: restore rbp
return (unsigned int)(local_4);
} cpp_operator_conversion pass 25 lines
// glaurung: cpp_operator_conversion @ 0x12a0
__attribute__((no_stack_protector)) int32_t cpp_operator_conversion(int32_t arg0, int32_t arg1) {
extern void _ZN12_GLOBAL__N_15FixedC2Ei(char *, int);
extern int _ZNK12_GLOBAL__N_15FixedcviEv(char *);
extern int _ZNK12_GLOBAL__N_15FixedixEi(char *, int);
extern int _ZNK12_GLOBAL__N_15FixedltERKS0_(char *, int *);
int widened;
int compared;
unsigned char local_10[4];
unsigned char local_18[4];
int local_24;
int var0;
int var16;
int var4;
// x86-64 prologue: save rbp, frame 48 bytes
_ZN12_GLOBAL__N_15FixedC2Ei((char *)(&local_10[0]), (unsigned long)((unsigned int)(arg0)));
_ZN12_GLOBAL__N_15FixedC2Ei((char *)(&local_18[0]), (unsigned long)((unsigned int)(arg1)));
var0 = _ZNK12_GLOBAL__N_15FixedcviEv((char *)(&local_10[0]));
widened = var0;
var4 = _ZNK12_GLOBAL__N_15FixedltERKS0_((char *)(&local_10[0]), (int *)(&local_18[0]));
local_24 = ((widened * 10) + (((unsigned long)((unsigned char)((var4 & 1))) != 0) ? 1 : 0));
var16 = _ZNK12_GLOBAL__N_15FixedixEi((char *)(&local_10[0]), 3);
// x86-64 epilogue: restore rbp
return (unsigned int)(((unsigned long)((unsigned int)(local_24)) + (unsigned long)((unsigned int)(var16))));
} clang -O2
3/3cpp_operator_arithmetic pass 4 lines
// glaurung: cpp_operator_arithmetic @ 0x1100
int32_t cpp_operator_arithmetic(int32_t arg0, int32_t arg1) {
return (unsigned int)((((unsigned long)(((long)(arg1) * (long)(arg0))) >> 16) ^ (unsigned long)((unsigned int)((arg1 + arg0)))));
} cpp_operator_compound pass 13 lines
// glaurung: cpp_operator_compound @ 0x1120
int32_t cpp_operator_compound(int32_t arg0, int32_t arg1) {
int index;
long ret;
ret = 0xffffffff;
if (((unsigned long)(16) < (unsigned long)((unsigned long)((unsigned int)(arg1))))) {
return ret;
}
if (((unsigned long)((unsigned int)(arg1)) == 0)) {
return (unsigned int)(arg0);
}
return (unsigned int)(((unsigned long)((unsigned int)((arg1 << 16))) + arg0));
} cpp_operator_conversion pass 8 lines
// glaurung: cpp_operator_conversion @ 0x1140
int32_t cpp_operator_conversion(int32_t arg0, int32_t arg1) {
int widened;
long var3;
var3 = (unsigned long)((unsigned int)(((int)(arg0) >> 16)));
widened = (var3 + var3);
return (unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(widened)) + ((unsigned long)((unsigned int)(widened)) * 4)))) | (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg0)) >> 3))) & 1)))))) + (arg0 < arg1)));
} gcc -O2
3/3cpp_operator_arithmetic pass 4 lines
// glaurung: cpp_operator_arithmetic @ 0x1100
int32_t cpp_operator_arithmetic(int32_t arg0, int32_t arg1) {
return (unsigned int)(((unsigned long)((unsigned int)((arg0 + arg1))) ^ ((long)(((long)(arg0) * (long)(arg1))) >> 16)));
} cpp_operator_compound pass 8 lines
// glaurung: cpp_operator_compound @ 0x1120
int32_t cpp_operator_compound(int32_t arg0, int32_t arg1) {
int index;
if (((unsigned long)(16) < (unsigned long)((unsigned long)((unsigned int)(arg1))))) {
return 0xffffffff;
}
return (((unsigned long)((unsigned int)(arg1)) == 0) ? arg0 : (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg1)) << 16))) + arg0))));
} cpp_operator_conversion pass 7 lines
// glaurung: cpp_operator_conversion @ 0x1140
int32_t cpp_operator_conversion(int32_t arg0, int32_t arg1) {
int widened;
long var3;
var3 = (unsigned long)((unsigned int)(((int)(arg0) >> 16)));
return (unsigned int)(((unsigned long)((unsigned int)(((arg0 < arg1) + ((unsigned long)((unsigned int)((var3 + (var3 * 4)))) * 2)))) + (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(((int)(arg0) >> 3))) & 1)))));
}