Closed jbush001 closed 7 years ago
May be related to #60
At this line: https://gist.github.com/jbush001/a34e2515ff496f794795750c839f7195#file-incorrect-checksum2-c-L232
The conditional is true on Nyuzi, false on the host. I've simplified it a little. If I add the following printf right before that if:
printf(">>> %d\n", (((safe_rshift_func_uint16_t_u_u((&g_1501[0] != (void*)0), 14)) ^ (safe_lshift_func_uint16_t_u_u((safe_mod_func_int64_t_s_s((((((safe_sub_func_int64_t_s_s((((*l_2011)--) || ((safe_add_func_int8_t_s_s((safe_add_func_int32_t_s_s(3L, (p_11 > l_1997))), g_67)) | 4L)), 0x17B56EDD23D01328LL)) , l_1997) , p_11) || l_2018) == p_10), l_2018)), 1))) ^ p_11) > 4UL);
It prints 1 on the host, 0 on Nyuzi. If I remove the > 4UL, both platforms print -3 as the value of the left hand side.
Sure enough, this test incorrectly prints 0 on Nyuzi:
int check_greater(long long int a)
{
return a > 4UL;
}
int main()
{
printf("%d\n", check_greater(-3)); // CHECK: 1
}
check_greater generates the following assembly:
check_greater:
cmpeq_i s2, s1, 0
bnz s2, .LBB0_1
cmpgt_i s0, s1, 0
and s0, s0, 1
ret
.LBB0_1:
cmpgt_u s0, s0, 4
and s0, s0, 1
ret
Generating LLVM IR with Nyuzi's clang shows signed greater than, which already seems incorrect. It should have been promoted to unsigned:
define i32 @check_greater(i64 %a) {
entry:
%cmp = icmp sgt i64 %a, 4
%conv = zext i1 %cmp to i32
ret i32 %conv
}
Here's what is generated by the host compiler (Apple LLVM version 8.1.0 (clang-802.0.42)):
define i32 @check_greater(i64) {
%2 = icmp ugt i64 %0, 4
%3 = zext i1 %2 to i32
ret i32 %3
}
Not a bug.
I'd worried that comparing the results of output from the host (a 64-bit machine) to Nyuzi (a 32-bit machine) would be a problem, but it seemed to generally work okay until this failure.
The value 4UL that is on the right hand side of the comparison is unsigned long.
On host: sizeof(long int) = 8 On nyuzi: sizeof(long int) = 4
Per the rules C99 6.3.1.8:
"if the operand that has unsigned integer type has rank greater or equal to the rank of the type of the other operand, then the operand with signed integer type is converted to the type of the operand with unsigned integer type."
On the Mac, unsigned long in is 64 bits. The -3 is promoted to an unsigned value (0xfffffffffffffffd). It is now larger than 4, so the value is true.
On Nyuzi, unsigned long is 32 bits.
"if the type of the operand with signed integer type can represent all of the values of the type of the operand with unsigned integer type, then the operand with unsigned integer type is converted to the type of the operand with signed integer type."
The '4' is converted to a wider 64 bit signed type and is now larger than -3.
This program:
https://gist.github.com/jbush001/a34e2515ff496f794795750c839f7195
Returns different results on the host vs. in the emulator:
host checksum: 5a7c858c emulator checksum: 2a86936e