[PATCH] D49364: [ARM] Add support for spilling high registers in Thumb1
Petr Pavlu via Phabricator via llvm-commits
llvm-commits at lists.llvm.org
Mon Jul 16 01:40:25 PDT 2018
petpav01 created this revision.
petpav01 added reviewers: olista01, t.p.northover.
Herald added subscribers: llvm-commits, chrib, kristof.beyls, qcolombet.
Herald added a reviewer: javed.absar.
LLVM normally only makes use of low registers in Thumb1 and methods `Thumb1InstrInfo::storeRegToStackSlot()/loadRegFromStackSlot()` are currently able to store/restore only them. However, it is possible in rare cases that a register allocator might need to spill a high register in the middle of a function as well.
Example:
$ cat test.c
void constraint_h(void) {
int i;
asm volatile("@ %0" : : "h" (i) : "r12");
}
$ clang -target arm-none-eabi -march=armv6-m -c test.c
clang-7: [...]/llvm/lib/Target/ARM/Thumb1InstrInfo.cpp:85: virtual void llvm::Thumb1InstrInfo::storeRegToStackSlot(llvm::MachineBasicBlock&, llvm::MachineBasicBlock::iterator, unsigned int, bool, int, const llvm::TargetRegisterClass*, const llvm::TargetRegisterInfo*) const: Assertion `(RC == &ARM::tGPRRegClass || (TargetRegisterInfo::isPhysicalRegister(SrcReg) && isARMLowRegister(SrcReg))) && "Unknown regclass!"' failed.
[...]
The program was compiled at `-O0` and so Fast Register Allocator is used. The following happens in this case:
- Prior to register allocation, MIR looks as follows:
Frame Objects:
fi#0: size=4, align=4, at location [SP]
bb.0.entry:
%1:tgpr = tLDRspi %stack.0.i, 0, 14, $noreg :: (dereferenceable load 4 from %ir.i)
%0:hgpr = COPY %1:tgpr
INLINEASM &"@ $0" [sideeffect] [attdialect], $0:[reguse:hGPR], %0:hgpr, $1:[clobber], implicit-def early-clobber $r12, !3
tBX_RET 14, $noreg
- Fast Register Allocator first satisfies `%0:hgpr` by selecting r12.
- When the scan reaches the `INLINEASM` instruction, the allocator however notices that r12 is clobbered and so it needs to be spilled.
- The allocator calls `Thumb1InstrInfo::storeRegToStackSlot()` to store the register in a stack slot but the method does not know how to do it and aborts. This can also result in a miscompilation if LLVM is built without assertions enabled.
The patch extends `Thumb1InstrInfo::storeRegToStackSlot()` and `loadRegFromStackSlot()` to allow storing and restoring high registers. Since callers of these methods may expect only a single instruction to be added but Thumb1 does not have an instruction that directly stores a high register, the code in each method inserts a pseudo instruction that gets lowered after register allocation in `ThumbRegisterInfo::eliminateFrameIndex()`.
Note: Both the store and load need an additional low register. For instance, the store is implemented as:
mov %lowReg, %spilledHighReg
str %lowReg, ...
This relies on the register scavenger to secure some low register for the sequence. This is possibly problematic when the register pressure is high because `ThumbRegisterInfo::saveScavengerRegister()` currently also tries to make use of high register r12.
Repository:
rL LLVM
https://reviews.llvm.org/D49364
Files:
lib/Target/ARM/ARMInstrThumb.td
lib/Target/ARM/ARMRegisterInfo.td
lib/Target/ARM/Thumb1InstrInfo.cpp
lib/Target/ARM/ThumbRegisterInfo.cpp
lib/Target/ARM/ThumbRegisterInfo.h
test/CodeGen/Thumb/high-reg-spill-expand.mir
test/CodeGen/Thumb/high-reg-spill.mir
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D49364.155628.patch
Type: text/x-patch
Size: 15944 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20180716/eb75f4f3/attachment.bin>
More information about the llvm-commits
mailing list