OSDN Git Service

[ARM64] Teach the ARM64DeadRegisterDefinition pass to respect implicit-defs.
authorLang Hames <lhames@gmail.com>
Thu, 3 Apr 2014 20:51:08 +0000 (20:51 +0000)
committerLang Hames <lhames@gmail.com>
Thu, 3 Apr 2014 20:51:08 +0000 (20:51 +0000)
When rematerializing through truncates, the coalescer may produce instructions
with dead defs, but live implicit-defs of subregs:
E.g.
  %X1<def,dead> = MOVi64imm 2, %W1<imp-def>; %X1:GPR64, %W1:GPR32

These instructions are live, and their definitions should not be rewritten.

Fixes <rdar://problem/16492408>

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@205565 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Target/ARM64/ARM64DeadRegisterDefinitionsPass.cpp
test/CodeGen/ARM64/dead-register-def-bug.ll [new file with mode: 0644]

index 3e410e5..f85dbaa 100644 (file)
@@ -27,6 +27,8 @@ STATISTIC(NumDeadDefsReplaced, "Number of dead definitions replaced");
 namespace {
 class ARM64DeadRegisterDefinitions : public MachineFunctionPass {
 private:
+  const TargetRegisterInfo *TRI;
+  bool implicitlyDefinesSubReg(unsigned Reg, const MachineInstr *MI);
   bool processMachineBasicBlock(MachineBasicBlock *MBB);
 
 public:
@@ -45,6 +47,19 @@ public:
 char ARM64DeadRegisterDefinitions::ID = 0;
 } // end anonymous namespace
 
+bool ARM64DeadRegisterDefinitions::implicitlyDefinesSubReg(
+                                                       unsigned Reg,
+                                                       const MachineInstr *MI) {
+  for (unsigned i = MI->getNumExplicitOperands(), e = MI->getNumOperands();
+       i != e; ++i) {
+    const MachineOperand &MO = MI->getOperand(i);
+    if (MO.isReg() && MO.isDef())
+      if (TRI->isSubRegister(Reg, MO.getReg()))
+        return true;
+  }
+  return false;
+}
+
 bool
 ARM64DeadRegisterDefinitions::processMachineBasicBlock(MachineBasicBlock *MBB) {
   bool Changed = false;
@@ -62,6 +77,11 @@ ARM64DeadRegisterDefinitions::processMachineBasicBlock(MachineBasicBlock *MBB) {
           DEBUG(dbgs() << "    Ignoring, def is tied operand.\n");
           continue;
         }
+        // Don't change the register if there's an implicit def of a subreg.
+        if (implicitlyDefinesSubReg(MO.getReg(), MI)) {
+          DEBUG(dbgs() << "    Ignoring, implicitly defines subregister.\n");
+          continue;
+        }
         // Make sure the instruction take a register class that contains
         // the zero register and replace it if so.
         unsigned NewReg;
@@ -90,6 +110,7 @@ ARM64DeadRegisterDefinitions::processMachineBasicBlock(MachineBasicBlock *MBB) {
 // register. Replace that register with the zero register when possible.
 bool ARM64DeadRegisterDefinitions::runOnMachineFunction(MachineFunction &mf) {
   MachineFunction *MF = &mf;
+  TRI = MF->getTarget().getRegisterInfo();
   bool Changed = false;
   DEBUG(dbgs() << "***** ARM64DeadRegisterDefinitions *****\n");
 
diff --git a/test/CodeGen/ARM64/dead-register-def-bug.ll b/test/CodeGen/ARM64/dead-register-def-bug.ll
new file mode 100644 (file)
index 0000000..1bbcf50
--- /dev/null
@@ -0,0 +1,32 @@
+; RUN: llc -mtriple="arm64-apple-ios" < %s | FileCheck %s
+;
+; Check that the dead register definition pass is considering implicit defs.
+; When rematerializing through truncates, the coalescer may produce instructions
+; with dead defs, but live implicit-defs of subregs:
+; E.g. %X1<def, dead> = MOVi64imm 2, %W1<imp-def>; %X1:GPR64, %W1:GPR32
+; These instructions are live, and their definitions should not be rewritten.
+;
+; <rdar://problem/16492408>
+
+define void @testcase() {
+; CHECK: testcase:
+; CHECK-NOT: orr xzr, xzr, #0x2
+
+bb1:
+  %tmp1 = tail call float @ceilf(float 2.000000e+00)
+  %tmp2 = fptoui float %tmp1 to i64
+  br i1 undef, label %bb2, label %bb3
+
+bb2:
+  tail call void @foo()
+  br label %bb3
+
+bb3:
+  %tmp3 = trunc i64 %tmp2 to i32
+  tail call void @bar(i32 %tmp3)
+  ret void
+}
+
+declare void @foo()
+declare void @bar(i32)
+declare float @ceilf(float) nounwind readnone