[llvm-mca] Correctly set aliases for register writes introduced by optimized register...
authorAndrea Di Biagio <Andrea_DiBiagio@sn.scee.net>
Fri, 12 Oct 2018 18:18:53 +0000 (18:18 +0000)
committerAndrea Di Biagio <Andrea_DiBiagio@sn.scee.net>
Fri, 12 Oct 2018 18:18:53 +0000 (18:18 +0000)
This fixes a problem introduced by r344334. A write from a non-zero move
eliminated at register renaming stage was not correctly handled by the PRF. This
would have led to an assertion failure if the processor model declares a PRF
that enables non-zero move elimination.

llvm-svn: 344392

llvm/tools/llvm-mca/include/HardwareUnits/RegisterFile.h
llvm/tools/llvm-mca/lib/HardwareUnits/RegisterFile.cpp
llvm/tools/llvm-mca/lib/Stages/DispatchStage.cpp

index 6a45c70..4b8b623 100644 (file)
@@ -109,12 +109,18 @@ class RegisterFile : public HardwareUnit {
   //
   // Field `AllowMoveElimination` is set for registers that are used as
   // destination by optimizable register moves.
+  //
+  // Field `AliasRegID` is set by writes from register moves that have been
+  // eliminated at register renaming stage. A move eliminated at register
+  // renaming stage is effectively bypassed, and its write aliases the source
+  // register definition.
   struct RegisterRenamingInfo {
     IndexPlusCostPairTy IndexPlusCost;
     llvm::MCPhysReg RenameAs;
+    llvm::MCPhysReg AliasRegID;
     bool AllowMoveElimination;
     RegisterRenamingInfo()
-        : IndexPlusCost(std::make_pair(0U, 1U)), RenameAs(0U),
+        : IndexPlusCost(std::make_pair(0U, 1U)), RenameAs(0U), AliasRegID(0U),
           AllowMoveElimination(false) {}
   };
 
index 481e2e1..4a2a005 100644 (file)
@@ -171,7 +171,8 @@ void RegisterFile::addRegisterWrite(WriteRef Write,
   // implicitly clears the upper portion of the underlying register.
   // If a write clears its super-registers, then it is renamed as `RenameAs`.
   bool IsWriteZero = WS.isWriteZero();
-  bool ShouldAllocatePhysRegs = !IsWriteZero;
+  bool IsEliminated = WS.isEliminated();
+  bool ShouldAllocatePhysRegs = !IsWriteZero && !IsEliminated;
   const RegisterRenamingInfo &RRI = RegisterMappings[RegID].second;
 
   if (RRI.RenameAs && RRI.RenameAs != RegID) {
@@ -187,6 +188,7 @@ void RegisterFile::addRegisterWrite(WriteRef Write,
       if (OtherWrite.getWriteState() &&
           (OtherWrite.getSourceIndex() != Write.getSourceIndex())) {
         // This partial write has a false dependency on RenameAs.
+        assert(!IsEliminated && "Unexpected partial update!");
         WS.setDependentWrite(OtherWrite.getWriteState());
       }
     }
@@ -205,22 +207,33 @@ void RegisterFile::addRegisterWrite(WriteRef Write,
       ZeroRegisters.clearBit(*I);
   }
 
-  // Update the mapping for register RegID including its sub-registers.
-  RegisterMappings[RegID].first = Write;
-  for (MCSubRegIterator I(RegID, &MRI); I.isValid(); ++I)
-    RegisterMappings[*I].first = Write;
+  // If this is move has been eliminated, then the call to tryEliminateMove
+  // should have already updated all the register mappings.
+  if (!IsEliminated) {
+    // Update the mapping for register RegID including its sub-registers.
+    RegisterMappings[RegID].first = Write;
+    RegisterMappings[RegID].second.AliasRegID = 0U;
+    for (MCSubRegIterator I(RegID, &MRI); I.isValid(); ++I) {
+      RegisterMappings[*I].first = Write;
+      RegisterMappings[*I].second.AliasRegID = 0U;
+    }
 
-  // No physical registers are allocated for instructions that are optimized in
-  // hardware. For example, zero-latency data-dependency breaking instructions
-  // don't consume physical registers.
-  if (ShouldAllocatePhysRegs)
-    allocatePhysRegs(RegisterMappings[RegID].second, UsedPhysRegs);
+    // No physical registers are allocated for instructions that are optimized in
+    // hardware. For example, zero-latency data-dependency breaking instructions
+    // don't consume physical registers.
+    if (ShouldAllocatePhysRegs)
+      allocatePhysRegs(RegisterMappings[RegID].second, UsedPhysRegs);
+  }
 
   if (!WS.clearsSuperRegisters())
     return;
 
   for (MCSuperRegIterator I(RegID, &MRI); I.isValid(); ++I) {
-    RegisterMappings[*I].first = Write;
+    if (!IsEliminated) {
+      RegisterMappings[*I].first = Write;
+      RegisterMappings[*I].second.AliasRegID = 0U;
+    }
+
     if (IsWriteZero)
       ZeroRegisters.setBit(*I);
     else
@@ -230,6 +243,11 @@ void RegisterFile::addRegisterWrite(WriteRef Write,
 
 void RegisterFile::removeRegisterWrite(
     const WriteState &WS, MutableArrayRef<unsigned> FreedPhysRegs) {
+  // Early exit if this write was eliminated. A write eliminated at register
+  // renaming stage generates an alias, and it is not added to the PRF.
+  if (WS.isEliminated())
+    return;
+
   unsigned RegID = WS.getRegisterID();
 
   assert(RegID != 0 && "Invalidating an already invalid register?");
@@ -313,10 +331,29 @@ bool RegisterFile::tryEliminateMove(WriteState &WS, const ReadState &RS) {
   if (RMT.AllowZeroMoveEliminationOnly && !IsZeroMove)
     return false;
 
+  MCPhysReg FromReg = RS.getRegisterID();
+  MCPhysReg ToReg = WS.getRegisterID();
+
+  // Construct an alias.
+  MCPhysReg AliasReg = FromReg;
+  if (RRIFrom.RenameAs)
+    AliasReg = RRIFrom.RenameAs;
+
+  const RegisterRenamingInfo &RMAlias = RegisterMappings[AliasReg].second;
+  if (RMAlias.AliasRegID)
+    AliasReg = RMAlias.AliasRegID;
+
+  if (AliasReg != ToReg) {
+    RegisterMappings[ToReg].second.AliasRegID = AliasReg;
+    for (MCSubRegIterator I(ToReg, &MRI); I.isValid(); ++I)
+      RegisterMappings[*I].second.AliasRegID = AliasReg;
+  }
+
   RMT.NumMoveEliminated++;
   if (IsZeroMove)
     WS.setWriteZero();
   WS.setEliminated();
+
   return true;
 }
 
@@ -325,6 +362,12 @@ void RegisterFile::collectWrites(SmallVectorImpl<WriteRef> &Writes,
   assert(RegID && RegID < RegisterMappings.size());
   LLVM_DEBUG(dbgs() << "RegisterFile: collecting writes for register "
                     << MRI.getName(RegID) << '\n');
+
+  // Check if this is an alias.
+  const RegisterRenamingInfo &RRI = RegisterMappings[RegID].second;
+  if (RRI.AliasRegID)
+    RegID = RRI.AliasRegID;
+
   const WriteRef &WR = RegisterMappings[RegID].first;
   if (WR.isValid())
     Writes.push_back(WR);
index c33b860..a6be247 100644 (file)
@@ -101,10 +101,11 @@ Error DispatchStage::dispatch(InstRef IR) {
   }
 
   // Check if this is an optimizable reg-reg move.
+  bool IsEliminated = false;
   if (IS.isOptimizableMove()) {
     assert(IS.getDefs().size() == 1 && "Expected a single input!");
     assert(IS.getUses().size() == 1 && "Expected a single output!");
-    PRF.tryEliminateMove(*IS.getDefs()[0], *IS.getUses()[0]);
+    IsEliminated = PRF.tryEliminateMove(*IS.getDefs()[0], *IS.getUses()[0]);
   }
 
   // A dependency-breaking instruction doesn't have to wait on the register
@@ -113,9 +114,15 @@ Error DispatchStage::dispatch(InstRef IR) {
   // instruction. A dependency-breaking instruction is a zero-latency
   // instruction that doesn't consume hardware resources.
   // An example of dependency-breaking instruction on X86 is a zero-idiom XOR.
-  for (std::unique_ptr<ReadState> &RS : IS.getUses())
-    if (!RS->isIndependentFromDef())
-      updateRAWDependencies(*RS, STI);
+  //
+  // We also don't update data dependencies for instructions that have been
+  // eliminated at register renaming stage.
+  if (!IsEliminated) {
+    for (std::unique_ptr<ReadState> &RS : IS.getUses()) {
+      if (!RS->isIndependentFromDef())
+        updateRAWDependencies(*RS, STI);
+    }
+  }
 
   // By default, a dependency-breaking zero-idiom is expected to be optimized
   // at register renaming stage. That means, no physical register is allocated