[llvm] d85b387 - [CodeGen][ARM] Error when writing to specific reserved registers in inline asm

Victor Campos via llvm-commits llvm-commits at lists.llvm.org
Wed Apr 15 06:40:51 PDT 2020


Author: Victor Campos
Date: 2020-04-15T14:40:42+01:00
New Revision: d85b3877dcd283feb6075162765664173cf1488f

URL: https://github.com/llvm/llvm-project/commit/d85b3877dcd283feb6075162765664173cf1488f
DIFF: https://github.com/llvm/llvm-project/commit/d85b3877dcd283feb6075162765664173cf1488f.diff

LOG: [CodeGen][ARM] Error when writing to specific reserved registers in inline asm

Summary:
No error or warning is emitted when specific reserved registers are
written to in inline assembly. Therefore, writes to the program counter
or to the frame pointer, for instance, were permitted, which could have
led to undesirable behaviour.

Example:
  int foo() {
    register int a __asm__("r7"); // r7 = frame-pointer in M-class ARM
    __asm__ __volatile__("mov %0, r1" : "=r"(a) : : );
    return a;
  }

In contrast, GCC issues an error in the same scenario.

This patch detects writes to specific reserved registers in inline
assembly for ARM and emits an error in such case. The detection works
for output and input operands. Clobber operands are not handled here:
they are already covered at a later point in
AsmPrinter::emitInlineAsm(const MachineInstr *MI). The registers
covered are: program counter, frame pointer and base pointer.

This is ARM only. Therefore the implementation of other targets'
counterparts remain open to do.

Reviewers: efriedma

Reviewed By: efriedma

Subscribers: kristof.beyls, hiraditya, danielkiss, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D76848

Added: 
    llvm/test/CodeGen/ARM/inline-asm-reserved-registers.ll

Modified: 
    llvm/include/llvm/CodeGen/TargetRegisterInfo.h
    llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
    llvm/lib/Target/ARM/ARMBaseRegisterInfo.cpp
    llvm/lib/Target/ARM/ARMBaseRegisterInfo.h

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/CodeGen/TargetRegisterInfo.h b/llvm/include/llvm/CodeGen/TargetRegisterInfo.h
index 31704f806ce4..d921c4c9028b 100644
--- a/llvm/include/llvm/CodeGen/TargetRegisterInfo.h
+++ b/llvm/include/llvm/CodeGen/TargetRegisterInfo.h
@@ -489,6 +489,12 @@ class TargetRegisterInfo : public MCRegisterInfo {
     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
index a7e476c96143..22c71961719e 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -8168,6 +8168,21 @@ void SelectionDAGBuilder::visitInlineAsm(const CallBase &Call) {
             : 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 @@ void SelectionDAGBuilder::visitInlineAsm(const CallBase &Call) {
           return;
         }
 
+        if (DetectWriteToReservedRegister())
+          return;
+
         // Add information to the INLINEASM node to know that this register is
         // set.
         OpInfo.AssignedRegs.AddInlineAsmOperands(
@@ -8339,6 +8357,9 @@ void SelectionDAGBuilder::visitInlineAsm(const CallBase &Call) {
         return;
       }
 
+      if (DetectWriteToReservedRegister())
+        return;
+
       SDLoc dl = getCurSDLoc();
 
       OpInfo.AssignedRegs.getCopyToRegs(InOperandVal, DAG, dl, Chain, &Flag,

diff  --git a/llvm/lib/Target/ARM/ARMBaseRegisterInfo.cpp b/llvm/lib/Target/ARM/ARMBaseRegisterInfo.cpp
index d58bef66d0fa..5eaf619dd894 100644
--- a/llvm/lib/Target/ARM/ARMBaseRegisterInfo.cpp
+++ b/llvm/lib/Target/ARM/ARMBaseRegisterInfo.cpp
@@ -224,6 +224,21 @@ isAsmClobberable(const MachineFunction &MF, MCRegister PhysReg) const {
   return !getReservedRegs(MF).test(PhysReg);
 }
 
+bool ARMBaseRegisterInfo::isInlineAsmReadOnlyReg(const MachineFunction &MF,
+                                                 unsigned PhysReg) const {
+  const ARMSubtarget &STI = MF.getSubtarget<ARMSubtarget>();
+  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/lib/Target/ARM/ARMBaseRegisterInfo.h b/llvm/lib/Target/ARM/ARMBaseRegisterInfo.h
index 7dc87daad3d6..0a0907af2141 100644
--- a/llvm/lib/Target/ARM/ARMBaseRegisterInfo.h
+++ b/llvm/lib/Target/ARM/ARMBaseRegisterInfo.h
@@ -135,6 +135,8 @@ class ARMBaseRegisterInfo : public ARMGenRegisterInfo {
   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/test/CodeGen/ARM/inline-asm-reserved-registers.ll b/llvm/test/CodeGen/ARM/inline-asm-reserved-registers.ll
new file mode 100644
index 000000000000..02c86c8b1cf9
--- /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
+}


        


More information about the llvm-commits mailing list