Currently, trying to compile this code:
define i8 @test(i8 %0) { start: %1 = call i8 @llvm.fshl.i8(i8 %0, i8 %0, i8 1) ret i8 %1 } declare i8 @llvm.fshl.i8(i8, i8, i8)
./build/bin/llc -march=avr -mcpu=atmega32u4 test.ll
... will fail, saying:
LLVM ERROR: Cannot select: t9: i8 = ROL t2 t2: i8,ch = CopyFromReg t0, Register:i8 %0 t1: i8 = Register %0
(spotted in the wild at https://github.com/rust-lang/rust/issues/107261)
Curiously, fshl.u16 (and larger types) work, similarly as all fshrs,
which I think is related to the fact that ROLBRd is hard-coded to
require GPR8:$zero in AVRInstrInfo.td.
Now, I'm not really sure why it's been done this way and so I'm not 100%
sure my approach to solving this problem is correct as well - but
adjusting ROLBRd to work similarly as RORBRd seems to do the job.
Following the example from above, we now generate:
lsl r24 adc r24, r1
I've made sure the codegen is alright by cross-checking results using
simavr - I've checked following cases, having lhs as a variable:
- 8-bit left/right rotations where rhs is constant/variable,
- 16-bit left/right rotations where rhs is constant/variable,
- 32-bit left/right rotations where rhs is constant/variable,
... and they all yielded correct results when compared with Rust's
.rotate_left() and .rotate_right().
Why did you remove this test? I think it's useful (r1 vs r17).