[llvm-dev] Automatically backing up and restoring x18 around function calls on AArch64?

Martin Storsjö via llvm-dev llvm-dev at lists.llvm.org
Fri May 10 01:50:23 PDT 2019

On Fri, 26 Apr 2019, Tim Northover wrote:

> At a high level what you probably need to do is get x18 copied on
> function entry and propagated into every call (or, better, every call
> to a Windows function). Since it's all implicit the place to modify is
> AArch64ISelLowering.cpp.
> LowerFormalArguments could do a CopyFromReg to preserve the value on
> function entry, and probably CopyToReg it into a new virtual register
> so that other basic blocks can access it (via
> MachineRegisterInfo::createVirtualRegister). You'd save the value of
> this virtual register somewhere for later (in
> AArch64MachineFunctionInfo probably).
> LowerCall would then CopyToReg from that vreg andput it back into x18,
> then mark the call as using that register. (using the RegsToPass
> variable, or equivalent). Since you know which functions need x18, you
> can be specific there.

Thanks, I managed to implement this, and it looks pretty promising, and 
not very invasive actually.

For enabling it, my PoC added a new target feature +protect-x18, which 
invokes these codepaths. (This mechanism is what the driver level flag 
-ffixed-x18 boils down to.) Is that sensible, or should I go for a 
cl::opt<bool> like the existing ones in AArch64TargetMachine.cpp?

However, at -O0, global isel is used instead (or fast-isel if that's 
requested). To opt out from global isel for these kinds of functions, I'd 
need to return false in IRTranslator::translateCall (in 

Is there any hook mechanism to the target specific code, where I could 
check the aarch64 specific feature and opt out from global isel? (If I add 
an unconditional "return false" there, falling back on SelectionDAG seems 
to work fine and I get the same behaviour I coded there.)

If fast isel is used and I try to return false from 
AArch64FastISel::fastLowerCall (or if I try to implement the register 
restoration there), I end up with a failed assertion like this:

../lib/CodeGen/TargetRegisterInfo.cpp:192: const 
llvm::TargetRegisterInfo::getMinimalPhysRegClass(unsigned int, llvm::MVT) 
const: Assertion `isPhysicalRegister(reg) && "reg must be a physical 
register"' failed.

Is there some part of the mechanism with virtual registers in the prologue 
that don't quite work with fast isel?

I'll try to complete this, and a few other alternative PoCs, and present 
for both Wine and LLVM to decide between the different ways forward.

// Martin

More information about the llvm-dev mailing list