diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -8312,6 +8312,21 @@ : OpInfo; GetRegistersForValue(DAG, getCurSDLoc(), OpInfo, RefOpInfo); + auto DetectWriteToReservedRegister = [&]() { + const MachineFunction &MF = DAG.getMachineFunction(); + const TargetRegisterInfo &TRI = *MF.getSubtarget().getRegisterInfo(); + for (unsigned Reg : OpInfo.AssignedRegs.Regs) { + if (Register::isPhysicalRegister(Reg) && + !TRI.isAsmClobberable(MF, Reg)) { + const char *RegName = TRI.getName(Reg); + emitInlineAsmError(CS, "write to reserved register '" + + Twine(RegName) + "'"); + return true; + } + } + return false; + }; + switch (OpInfo.Type) { case InlineAsm::isOutput: if (OpInfo.ConstraintType == TargetLowering::C_Memory) { @@ -8337,6 +8352,9 @@ return; } + if (DetectWriteToReservedRegister()) + return; + // Add information to the INLINEASM node to know that this register is // set. OpInfo.AssignedRegs.AddInlineAsmOperands( @@ -8481,6 +8499,9 @@ return; } + if (DetectWriteToReservedRegister()) + return; + SDLoc dl = getCurSDLoc(); OpInfo.AssignedRegs.getCopyToRegs(InOperandVal, DAG, dl, diff --git a/llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp b/llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp --- a/llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp +++ b/llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp @@ -241,6 +241,13 @@ bool AArch64RegisterInfo::isAsmClobberable(const MachineFunction &MF, unsigned PhysReg) const { + // X16/W16 is marked as reserved when Speculative Load Hardening is enabled + // to prevent it from being used in register allocation. However, it should + // still be clobberable in inline assembly as SLH is capable of handling such + // case by implementing a fallback. + if (MF.getFunction().hasFnAttribute(Attribute::SpeculativeLoadHardening) && + (PhysReg == AArch64::X16 || PhysReg == AArch64::W16)) + return true; return !isReservedReg(MF, PhysReg); } diff --git a/llvm/test/CodeGen/Generic/inline-asm-reserved-registers.ll b/llvm/test/CodeGen/Generic/inline-asm-reserved-registers.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/Generic/inline-asm-reserved-registers.ll @@ -0,0 +1,15 @@ +; RUN: not llc -mtriple thumbv6m-arm-none-eabi -frame-pointer=all %s 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR + +; CHECK-ERROR: error: write to reserved register 'R7' +define void @test_framepointer_output(i32 %input) { +entry: + %0 = call i32 asm sideeffect "mov $0, r1", "={r7},r"(i32 %input) + ret void +} + +; CHECK-ERROR: error: write to reserved register 'R7' +define void @test_framepointer_input(i32 %input) { +entry: + %0 = call i32 asm sideeffect "mov $0, $1", "=r,{r7}"(i32 %input) + ret void +}