diff --git a/llvm/include/llvm/CodeGen/TargetRegisterInfo.h b/llvm/include/llvm/CodeGen/TargetRegisterInfo.h --- a/llvm/include/llvm/CodeGen/TargetRegisterInfo.h +++ b/llvm/include/llvm/CodeGen/TargetRegisterInfo.h @@ -489,6 +489,12 @@ return true; } + /// Returns true if PhysReg cannot be written to in inline asm statements. + virtual bool isInlineAsmReadOnlyReg(const MachineFunction &MF, + unsigned PhysReg) const { + return false; + } + /// Returns true if PhysReg is unallocatable and constant throughout the /// function. Used by MachineRegisterInfo::isConstantPhysReg(). virtual bool isConstantPhysReg(MCRegister PhysReg) const { return false; } 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 @@ -8168,6 +8168,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.isInlineAsmReadOnlyReg(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) { @@ -8193,6 +8208,9 @@ return; } + if (DetectWriteToReservedRegister()) + return; + // Add information to the INLINEASM node to know that this register is // set. OpInfo.AssignedRegs.AddInlineAsmOperands( @@ -8339,6 +8357,9 @@ return; } + if (DetectWriteToReservedRegister()) + return; + SDLoc dl = getCurSDLoc(); OpInfo.AssignedRegs.getCopyToRegs(InOperandVal, DAG, dl, Chain, &Flag, diff --git a/llvm/lib/Target/ARM/ARMBaseRegisterInfo.h b/llvm/lib/Target/ARM/ARMBaseRegisterInfo.h --- a/llvm/lib/Target/ARM/ARMBaseRegisterInfo.h +++ b/llvm/lib/Target/ARM/ARMBaseRegisterInfo.h @@ -135,6 +135,8 @@ BitVector getReservedRegs(const MachineFunction &MF) const override; bool isAsmClobberable(const MachineFunction &MF, MCRegister PhysReg) const override; + bool isInlineAsmReadOnlyReg(const MachineFunction &MF, + unsigned PhysReg) const override; const TargetRegisterClass * getPointerRegClass(const MachineFunction &MF, diff --git a/llvm/lib/Target/ARM/ARMBaseRegisterInfo.cpp b/llvm/lib/Target/ARM/ARMBaseRegisterInfo.cpp --- a/llvm/lib/Target/ARM/ARMBaseRegisterInfo.cpp +++ b/llvm/lib/Target/ARM/ARMBaseRegisterInfo.cpp @@ -224,6 +224,21 @@ return !getReservedRegs(MF).test(PhysReg); } +bool ARMBaseRegisterInfo::isInlineAsmReadOnlyReg(const MachineFunction &MF, + unsigned PhysReg) const { + const ARMSubtarget &STI = MF.getSubtarget(); + const ARMFrameLowering *TFI = getFrameLowering(MF); + + BitVector Reserved(getNumRegs()); + markSuperRegs(Reserved, ARM::PC); + if (TFI->hasFP(MF)) + markSuperRegs(Reserved, getFramePointerReg(STI)); + if (hasBasePointer(MF)) + markSuperRegs(Reserved, BasePtr); + assert(checkAllSuperRegsMarked(Reserved)); + return Reserved.test(PhysReg); +} + const TargetRegisterClass * ARMBaseRegisterInfo::getLargestLegalSuperClass(const TargetRegisterClass *RC, const MachineFunction &MF) const { diff --git a/llvm/test/CodeGen/ARM/inline-asm-reserved-registers.ll b/llvm/test/CodeGen/ARM/inline-asm-reserved-registers.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/ARM/inline-asm-reserved-registers.ll @@ -0,0 +1,45 @@ +; 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, $1", "={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 +} + +; CHECK-ERROR: error: write to reserved register 'PC' +define void @test_pc_output(i32 %input) { +entry: + %0 = call i32 asm sideeffect "mov $0, $1", "={pc},r"(i32 %input) + ret void +} + +; CHECK-ERROR: error: write to reserved register 'PC' +define void @test_pc_input(i32 %input) { +entry: + %0 = call i32 asm sideeffect "mov $0, $1", "=r,{pc}"(i32 %input) + ret void +} + +; CHECK-ERROR: error: write to reserved register 'R6' +define void @test_basepointer_output(i32 %size, i32 %input) alignstack(8) { +entry: + %vla = alloca i32, i32 %size, align 4 + %0 = call i32 asm sideeffect "mov $0, $1", "={r6},r"(i32 %input) + ret void +} + +; CHECK-ERROR: error: write to reserved register 'R6' +define void @test_basepointer_input(i32 %size, i32 %input) alignstack(8) { +entry: + %vla = alloca i32, i32 %size, align 4 + %0 = call i32 asm sideeffect "mov $0, $1", "=r,{r6}"(i32 %input) + ret void +}