I've created a test case that panics on msp430 in debug/release mode:
fn do_shift(val: &u64, amt: &u8) -> u64 {
// compiler_builtins::int::shift::__ashldi3(*val, *amt as u32)
*val << *amt
}
fn shift_test() {
let my_u64: u64 = 1;
let my_shift: u8 = 0;
if black_box(do_shift(black_box(&my_u64), black_box(&my_shift))) != 1 {
panic!()
}
}
If I call compiler_builtins::int::shift::__ashldi3(*val, *amt as u32) directly, shift_test does not panic. Relevant assembly code:
.Ltmp6:
.loc 1 46 18 is_stmt 1
mov 6(r12), r15
mov 4(r12), r14
mov 2(r12), r13
mov 0(r12), r12
mov.b 0(r11), r11
.Ltmp7:
.loc 1 38 5
mov r11, 0(r1)
clr 2(r1)
call #_ZN17compiler_builtins3int5shift9__ashldi317h573dd44357b45ab3E
However, if I let LLVM lower the shift to a builtin, shift_test tends to panic:
.Ltmp7:
.loc 1 46 18 is_stmt 1
mov.b 0(r12), r12
.Ltmp8:
.loc 1 39 5
and #63, r12
mov r12, 0(r1)
.Ltmp9:
.loc 1 46 18
mov 0(r15), r12
mov 2(r15), r13
mov 4(r15), r14
mov 6(r15), r15
.Ltmp10:
.loc 1 39 5
call #__ashldi3
Notice that the call to __ashldi3 only sets up one 64-bit worth and a 16-bit int's worth of argument. This is correct for __ashldi3 as specified in compiler-rt. However, we call the compiler-builtins version in both cases (compiled with -Zbuild-std=core), which excepts a 32-bit int's worth of argument. The second code snippet does not do this, and therefore when compiler_builtins::int::shift::__ashldi3 is called it reads garbage for the top 16-bits of the shl argument. This causes subtle breakage and pain, possibly many instructions away from the call :).
AVR doesn't appear to have this problem because apparently there's an dedicated pass to ensuring that calls to __ashldi3 and friends aren't emitted into assembly files. MSP430 doesn't have such a pass. Which makes me confused as to why #513 was needed in the first place, but that's for another time.
This leaves msp430 as the only platform which would use at the very least the shift builtins where sizeof(int) isn't 4. I'm not sure how to fix this:
- The code emission for LLVM is correct for C/C++ code.
- Changing MSP430 to a 32-bit int will never be accepted on the LLVM side.
- On the other hand, going through every single function that uses an
int where this crate uses a u32 and adding conditional compilation seems invasive.
- On the other, other hand, I don't want to go the
build-std-features route to disable compiler_builtins because I'm trying to remove nightly features from the msp430 backend, not add them.
__ashldi3 does exist in libgcc:
$ nm /opt/toolchains/lib/gcc/msp430-elf/9.3.1/libgcc.a 2> /dev/null | grep __ashldi3
00000000 T __ashldi3
- ... but I can't confirm that all affected builtins (ones using
int args) are in libgcc for MSP430. I'd rather see compiler-builtins correctly support 16-bit int input arguments rather than hardcode a 32-bit one. Maybe adding an msp430_expand wrapper is possible- i.e. expand 16-bit ints to 32-bit before sending to __ashldi3? That seems like it could be done in a semver-compat manner somehow?
I've created a test case that panics on msp430 in debug/release mode:
If I call
compiler_builtins::int::shift::__ashldi3(*val, *amt as u32)directly,shift_testdoes not panic. Relevant assembly code:However, if I let LLVM lower the shift to a builtin,
shift_testtends to panic:Notice that the call to
__ashldi3only sets up one 64-bit worth and a 16-bitint's worth of argument. This is correct for__ashldi3as specified incompiler-rt. However, we call thecompiler-builtinsversion in both cases (compiled with-Zbuild-std=core), which excepts a 32-bitint's worth of argument. The second code snippet does not do this, and therefore whencompiler_builtins::int::shift::__ashldi3is called it reads garbage for the top 16-bits of theshlargument. This causes subtle breakage and pain, possibly many instructions away from the call :).AVR doesn't appear to have this problem because apparently there's an dedicated pass to ensuring that calls to
__ashldi3and friends aren't emitted into assembly files. MSP430 doesn't have such a pass. Which makes me confused as to why #513 was needed in the first place, but that's for another time.This leaves msp430 as the only platform which would use at the very least the shift builtins where
sizeof(int)isn't 4. I'm not sure how to fix this:intwhere this crate uses au32and adding conditional compilation seems invasive.build-std-featuresroute to disablecompiler_builtinsbecause I'm trying to remove nightly features from the msp430 backend, not add them.__ashldi3does exist inlibgcc:intargs) are inlibgccfor MSP430. I'd rather seecompiler-builtinscorrectly support 16-bit int input arguments rather than hardcode a 32-bit one. Maybe adding anmsp430_expandwrapper is possible- i.e. expand 16-bit ints to 32-bit before sending to__ashldi3? That seems like it could be done in a semver-compat manner somehow?