Closed shepmaster closed 8 years ago
@shepmaster: I'm gonna take a look into this.
Both sts
and lds
use the F32DM
instruction format from AVRInstrFormats.td
. This is probably not a coincidence.
If we use llvm-mc
to assemble the assembly file:
(test.s
):
main:
ldi r24, 1
ldi r25, 0
sts COUNTER+1, r25
sts COUNTER, r24
ret
llvm-mc test.s -arch=avr -mcpu=atmega328p -filetype=obj -o test.o
We also get the same result. This is not a codegen problem but an MC problem.
The exact same problem comes up when COUNTER
is not even defined. I think this is a problem with relocations.
What should be happening is that when a symbol such as COUNTER
is used, a relocation is created to fix up the sts
instruction symbol address + 1
. Until the object is linked, the unresolved bits in the instruction would still be 0
, which looks like this case.
objdump -r
shows that the object file has no relocations. This is probably the problem.
When AVR-GCC compiles this snippet:
sts 3, r5
sts 255, r7
sts SYMBOL+1, r25
It generates this
00000000 <foo>:
00000000 <foo>:
0: 50 92 03 00 sts 0x0003, r5
4: 70 92 ff 00 sts 0x00FF, r7
8: 90 93 00 00 sts 0x0000, r25
a: R_AVR_16 SYMBOL+0x1
We should also be generating an R_AVR_16
reloc in this case.
Fixed as of c97cbe5.
What was happening is that we said that the instruction opcode is i16imm
- a 16-bit immediate.
For some reason, LLVM doesn't give us an error when a relocatable expression is used in this context, even though LLVM doesn't know how to lower it into machine code.
This was fixed by adding a new addr16
operand type, and writing an MC encoder to handle the case where the operand is an expression, in which case, a fixup_16
is generated, which gets lowered into an R_AVR_16
relocation during ELF file creation.
This is likely going to be a problem for a few different instructions which expect immediates but can have expressions.
I will look into this and fix them up.
This was an exciting, informative whirlwind conversation you had with yourself! Thank you for tracking it here so I could attempt to understand it. Maybe more importantly, thank you for fixing it ^_^.
This IR:
Produces this output from
llc -march=avr -mcpu=atmega328p < global.ll
:Which seems correct. However, the actual object (from
llc -march=avr -mcpu=atmega328p global.ll -filetype=obj
), disassembled withobjdump
shows:Note that both
sts
instructions are writing to the same memory location, clobbering half of the value and not updating the other half.I see the same issue when loading 16-bit values as well.