jbush001 / NyuziToolchain

Port of LLVM/Clang C compiler to Nyuzi parallel processor architecture
Other
62 stars 28 forks source link

csmith program result does not match host #68

Closed jbush001 closed 7 years ago

jbush001 commented 7 years ago

This program:

https://gist.github.com/jbush001/a34e2515ff496f794795750c839f7195

Returns different results on the host vs. in the emulator:

host checksum: 5a7c858c emulator checksum: 2a86936e

jbush001 commented 7 years ago

May be related to #60

jbush001 commented 7 years ago

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.

jbush001 commented 7 years ago

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
}
jbush001 commented 7 years ago

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
jbush001 commented 7 years ago

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
}
jbush001 commented 7 years ago

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.

https://github.com/jbush001/NyuziToolchain/blob/8ac4914d4f171273ce6b894fc16496d5bfc52c0b/tools/clang/lib/Sema/SemaExpr.cpp#L1235

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.

https://github.com/jbush001/NyuziToolchain/blob/8ac4914d4f171273ce6b894fc16496d5bfc52c0b/tools/clang/lib/Sema/SemaExpr.cpp#L1244