]> granicus.if.org Git - llvm/commitdiff
LiveIntervalAnalysis: Fix alias regunit reserved definition
authorMatthias Braun <matze@braunis.de>
Fri, 1 Sep 2017 18:36:26 +0000 (18:36 +0000)
committerMatthias Braun <matze@braunis.de>
Fri, 1 Sep 2017 18:36:26 +0000 (18:36 +0000)
A register in CodeGen can be marked as reserved: In that case we
consider the register always live and do not use (or rather ignore)
kill/dead/undef operand flags.

LiveIntervalAnalysis however tracks liveness per register unit (not per
register). We already needed adjustments for this in r292871 to deal
with super/sub registers. However I did not look at aliased register
there. Looking at ARM:

FPSCR (regunits FPSCR, FPSCR~FPSCR_NZCV) aliases with FPSCR_NZCV
(regunits FPSCR_NZCV, FPSCR~FPSCR_NZCV) hence they share a register unit
(FPSCR~FPSCR_NZCV) that represents the aliased parts of the registers.
This shared register unit was previously considered non-reserved,
however given that we uses of the reserved FPSCR potentially violate
some rules (like uses without defs) we should make FPSCR~FPSCR_NZCV
reserved too and stop tracking liveness for it.

This patch:
- Defines a register unit as reserved when: At least for one root
  register, the root register and all its super registers are reserved.
- Adjust LiveIntervals::computeRegUnitRange() for new reserved
  definition.
- Add MachineRegisterInfo::isReservedRegUnit() to have a canonical way
  of testing.
- Stop computing LiveRanges for reserved register units in HMEditor even
  with UpdateFlags enabled.
- Skip verification of uses of reserved reg units in the machine
  verifier (this usually didn't happen because there would be no cached
  liverange but there is no guarantee for that and I would run into this
  case before the HMEditor tweak, so may as well fix the verifier too).

Note that this should only affect ARMs FPSCR/FPSCR_NZCV registers today;
aliased registers are rarely used, the only other cases are hexagons
P0-P3/P3_0 and C8/USR pairs which are not mixing reserved/non-reserved
registers in an alias.

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

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

include/llvm/CodeGen/MachineRegisterInfo.h
lib/CodeGen/LiveIntervalAnalysis.cpp
lib/CodeGen/MachineRegisterInfo.cpp
lib/CodeGen/MachineVerifier.cpp
test/CodeGen/ARM/no-fpscr-liveness.ll [new file with mode: 0644]

index 8347f00cbc7a4422efbed45a57ca7110c88bf865..5ef0ac90e3c2a758352f7b2bc80c0f7a76a87b89 100644 (file)
@@ -807,6 +807,14 @@ public:
     return getReservedRegs().test(PhysReg);
   }
 
+  /// Returns true when the given register unit is considered reserved.
+  ///
+  /// Register units are considered reserved when for at least one of their
+  /// root registers, the root register and all super registers are reserved.
+  /// This currently iterates the register hierarchy and may be slower than
+  /// expected.
+  bool isReservedRegUnit(unsigned Unit) const;
+
   /// isAllocatable - Returns true when PhysReg belongs to an allocatable
   /// register class and it hasn't been reserved.
   ///
index 471dcea4bb3903c588e6099b283fae72092c5697..0e240f482a19adf95d9c641ffe98e79b24ea3020 100644 (file)
@@ -269,8 +269,9 @@ void LiveIntervals::computeRegUnitRange(LiveRange &LR, unsigned Unit) {
   // may share super-registers. That's OK because createDeadDefs() is
   // idempotent. It is very rare for a register unit to have multiple roots, so
   // uniquing super-registers is probably not worthwhile.
-  bool IsReserved = true;
+  bool IsReserved = false;
   for (MCRegUnitRootIterator Root(Unit, TRI); Root.isValid(); ++Root) {
+    bool IsRootReserved = true;
     for (MCSuperRegIterator Super(*Root, TRI, /*IncludeSelf=*/true);
          Super.isValid(); ++Super) {
       unsigned Reg = *Super;
@@ -279,9 +280,12 @@ void LiveIntervals::computeRegUnitRange(LiveRange &LR, unsigned Unit) {
       // A register unit is considered reserved if all its roots and all their
       // super registers are reserved.
       if (!MRI->isReserved(Reg))
-        IsReserved = false;
+        IsRootReserved = false;
     }
+    IsReserved |= IsRootReserved;
   }
+  assert(IsReserved == MRI->isReservedRegUnit(Unit) &&
+         "reserved computation mismatch");
 
   // Now extend LR to reach all uses.
   // Ignore uses of reserved registers. We only track defs of those.
@@ -924,7 +928,7 @@ public:
   // kill flags. This is wasteful. Eventually, LiveVariables will strip all kill
   // flags, and postRA passes will use a live register utility instead.
   LiveRange *getRegUnitLI(unsigned Unit) {
-    if (UpdateFlags)
+    if (UpdateFlags && !MRI.isReservedRegUnit(Unit))
       return &LIS.getRegUnit(Unit);
     return LIS.getCachedRegUnit(Unit);
   }
index 9a92ee279cdc98f9545507ccf6c00dbf8ab9812a..be06053f0040604936b077fb78ecccd71e9f2d8a 100644 (file)
@@ -601,3 +601,21 @@ void MachineRegisterInfo::setCalleeSavedRegs(ArrayRef<MCPhysReg> CSRs) {
   UpdatedCSRs.push_back(0);
   IsUpdatedCSRsInitialized = true;
 }
+
+bool MachineRegisterInfo::isReservedRegUnit(unsigned Unit) const {
+  const TargetRegisterInfo *TRI = getTargetRegisterInfo();
+  for (MCRegUnitRootIterator Root(Unit, TRI); Root.isValid(); ++Root) {
+    bool IsRootReserved = true;
+    for (MCSuperRegIterator Super(*Root, TRI, /*IncludeSelf=*/true);
+         Super.isValid(); ++Super) {
+      unsigned Reg = *Super;
+      if (!isReserved(Reg)) {
+        IsRootReserved = false;
+        break;
+      }
+    }
+    if (IsRootReserved)
+      return true;
+  }
+  return false;
+}
index 7429a7f8a86adbc6e3839d5ab3e340032d6ae987..2ecfdd86793dc3785b09668d0e3bc8f0f1eaae32 100644 (file)
@@ -1333,6 +1333,8 @@ void MachineVerifier::checkLiveness(const MachineOperand *MO, unsigned MONum) {
       // Check the cached regunit intervals.
       if (TargetRegisterInfo::isPhysicalRegister(Reg) && !isReserved(Reg)) {
         for (MCRegUnitIterator Units(Reg, TRI); Units.isValid(); ++Units) {
+          if (MRI->isReservedRegUnit(*Units))
+            continue;
           if (const LiveRange *LR = LiveInts->getCachedRegUnit(*Units))
             checkLivenessAtUse(MO, MONum, UseIdx, *LR, *Units);
         }
diff --git a/test/CodeGen/ARM/no-fpscr-liveness.ll b/test/CodeGen/ARM/no-fpscr-liveness.ll
new file mode 100644 (file)
index 0000000..6575ab6
--- /dev/null
@@ -0,0 +1,49 @@
+; RUN: llc -o - %s | FileCheck %s
+; Make sure we do not try to compute liveness for FPSCR which in this case
+; is read before being written to (this is fine because becase FPSCR is
+; reserved).
+target triple = "thumbv7s-apple-ios"
+
+%struct.wibble = type { double }
+
+@global = common global i32 0, align 4
+@global.1 = common global i32 0, align 4
+
+; CHECK-LABEL: eggs:
+; CHECK: sub sp, #8
+; VMRS instruction comes before any other instruction writing FPSCR:
+; CHECK-NEXT: vmrs r0, fpscr
+; ...
+; CHECK: add sp, #8
+; CHECK: bx lr
+define i32 @eggs(double* nocapture readnone %arg) {
+bb:
+  %tmp = alloca %struct.wibble, align 4
+  %tmp1 = bitcast %struct.wibble* %tmp to i8*
+  %tmp2 = tail call i32 @llvm.flt.rounds()
+  %tmp3 = ptrtoint %struct.wibble* %tmp to i32
+  %tmp4 = sitofp i32 %tmp3 to double
+  %tmp5 = fmul double %tmp4, 0x0123456789ABCDEF
+  %tmp6 = fptosi double %tmp5 to i32
+  %tmp7 = fcmp une double %tmp5, 0.000000e+00
+  %tmp8 = sitofp i32 %tmp6 to double
+  %tmp9 = fcmp une double %tmp5, %tmp8
+  %tmp10 = and i1 %tmp7, %tmp9
+  %tmp11 = sext i1 %tmp10 to i32
+  %tmp12 = add nsw i32 %tmp11, %tmp6
+  store i32 %tmp12, i32* @global, align 4
+  %tmp13 = icmp ne i32 %tmp12, 0
+  %tmp14 = icmp ne i32 %tmp2, 0
+  %tmp15 = and i1 %tmp14, %tmp13
+  br i1 %tmp15, label %bb16, label %bb18
+
+bb16:                                             ; preds = %bb
+  %tmp17 = load i32, i32* @global.1, align 4
+  br label %bb18
+
+bb18:                                             ; preds = %bb16, %bb
+  ret i32 undef
+}
+
+declare i32 @llvm.flt.rounds()
+declare i32 @zot(...)