[llvm] r328790 - [llvm-mca] Correctly set the ReadAdvance information for register use operands.

Andrea Di Biagio via llvm-commits llvm-commits at lists.llvm.org
Thu Mar 29 07:26:56 PDT 2018


Author: adibiagio
Date: Thu Mar 29 07:26:56 2018
New Revision: 328790

URL: http://llvm.org/viewvc/llvm-project?rev=328790&view=rev
Log:
[llvm-mca] Correctly set the ReadAdvance information for register use operands.

The tool was passing the wrong operand index to method
MCSubtargetInfo::getReadAdvanceCycles(). That method requires a "UseIdx", and
not the operand index. This was found when testing X86 code where instructions
had a memory folded operand.

This patch fixes the issue and adds test read-advance-1.s to ensure that
the ReadAfterLd (a ReadAdvance of 3cy) information is correctly used.

Added:
    llvm/trunk/test/tools/llvm-mca/X86/BtVer2/read-advance-1.s
Modified:
    llvm/trunk/tools/llvm-mca/Dispatch.cpp
    llvm/trunk/tools/llvm-mca/InstrBuilder.cpp
    llvm/trunk/tools/llvm-mca/Instruction.cpp
    llvm/trunk/tools/llvm-mca/Instruction.h
    llvm/trunk/tools/llvm-mca/Scheduler.cpp
    llvm/trunk/tools/llvm-mca/Scheduler.h

Added: llvm/trunk/test/tools/llvm-mca/X86/BtVer2/read-advance-1.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-mca/X86/BtVer2/read-advance-1.s?rev=328790&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-mca/X86/BtVer2/read-advance-1.s (added)
+++ llvm/trunk/test/tools/llvm-mca/X86/BtVer2/read-advance-1.s Thu Mar 29 07:26:56 2018
@@ -0,0 +1,46 @@
+# RUN: llvm-mca -mtriple=x86_64-unknown-unknown -mcpu=btver2 -iterations=1 -timeline -resource-pressure=false < %s | FileCheck %s
+
+# The vmul can start executing 3cy in advance. That is beause the first use
+# operand (i.e. %xmm1) is a ReadAfterLd. That means, the memory operand is
+# evaluated before %xmm1.
+
+
+vaddps  %xmm0, %xmm0, %xmm1
+vmulps  (%rdi), %xmm1, %xmm2
+
+
+# CHECK:      Iterations:     1
+# CHECK-NEXT: Instructions:   2
+# CHECK-NEXT: Total Cycles:   10
+# CHECK-NEXT: Dispatch Width: 2
+
+
+# CHECK:      Instruction Info:
+# CHECK-NEXT: [1]: #uOps
+# CHECK-NEXT: [2]: Latency
+# CHECK-NEXT: [3]: RThroughput
+# CHECK-NEXT: [4]: MayLoad
+# CHECK-NEXT: [5]: MayStore
+# CHECK-NEXT: [6]: HasSideEffects
+
+# CHECK:      [1]    [2]    [3]    [4]    [5]    [6]	Instructions:
+# CHECK-NEXT:  1      3     1.00                    	vaddps	%xmm0, %xmm0, %xmm1
+# CHECK-NEXT:  1      7     1.00    *               	vmulps	(%rdi), %xmm1, %xmm2
+
+
+# CHECK:      Timeline view:
+
+# CHECK:      Index	0123456789
+# CHECK:      [0,0]	DeeeER   .	vaddps	%xmm0, %xmm0, %xmm1
+# CHECK-NEXT: [0,1]	DeeeeeeeER	vmulps	(%rdi), %xmm1, %xmm2
+
+
+# CHECK:      Average Wait times (based on the timeline view):
+# CHECK-NEXT: [0]: Executions
+# CHECK-NEXT: [1]: Average time spent waiting in a scheduler's queue
+# CHECK-NEXT: [2]: Average time spent waiting in a scheduler's queue while ready
+# CHECK-NEXT: [3]: Average time elapsed from WB until retire stage
+
+# CHECK:            [0]    [1]    [2]    [3]
+# CHECK-NEXT: 0.     1     1.0    1.0    0.0  	vaddps	%xmm0, %xmm0, %xmm1
+# CHECK-NEXT: 1.     1     1.0    0.0    0.0  	vmulps	(%rdi), %xmm1, %xmm2

Modified: llvm/trunk/tools/llvm-mca/Dispatch.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-mca/Dispatch.cpp?rev=328790&r1=328789&r2=328790&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-mca/Dispatch.cpp (original)
+++ llvm/trunk/tools/llvm-mca/Dispatch.cpp Thu Mar 29 07:26:56 2018
@@ -343,7 +343,7 @@ void DispatchUnit::updateRAWDependencies
   const MCSchedClassDesc *SC = SM.getSchedClassDesc(RD.SchedClassID);
   for (WriteState *WS : DependentWrites) {
     unsigned WriteResID = WS->getWriteResourceID();
-    int ReadAdvance = STI.getReadAdvanceCycles(SC, RD.OpIndex, WriteResID);
+    int ReadAdvance = STI.getReadAdvanceCycles(SC, RD.UseIndex, WriteResID);
     WS->addUser(&RS, ReadAdvance);
   }
   // Prepare the set for another round.

Modified: llvm/trunk/tools/llvm-mca/InstrBuilder.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-mca/InstrBuilder.cpp?rev=328790&r1=328789&r2=328790&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-mca/InstrBuilder.cpp (original)
+++ llvm/trunk/tools/llvm-mca/InstrBuilder.cpp Thu Mar 29 07:26:56 2018
@@ -340,6 +340,7 @@ static void populateReads(InstrDesc &ID,
   for (unsigned CurrentUse = 0; CurrentUse < NumExplicitUses; ++CurrentUse) {
     ReadDescriptor &Read = ID.Reads[CurrentUse];
     Read.OpIndex = i + CurrentUse;
+    Read.UseIndex = CurrentUse;
     Read.HasReadAdvanceEntries = HasReadAdvanceEntries;
     Read.SchedClassID = SchedClassID;
     DEBUG(dbgs() << "\t\tOpIdx=" << Read.OpIndex);
@@ -348,6 +349,7 @@ static void populateReads(InstrDesc &ID,
   for (unsigned CurrentUse = 0; CurrentUse < NumImplicitUses; ++CurrentUse) {
     ReadDescriptor &Read = ID.Reads[NumExplicitUses + CurrentUse];
     Read.OpIndex = -1;
+    Read.UseIndex = -1;
     Read.RegisterID = MCDesc.getImplicitUses()[CurrentUse];
     Read.HasReadAdvanceEntries = false;
     Read.SchedClassID = SchedClassID;

Modified: llvm/trunk/tools/llvm-mca/Instruction.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-mca/Instruction.cpp?rev=328790&r1=328789&r2=328790&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-mca/Instruction.cpp (original)
+++ llvm/trunk/tools/llvm-mca/Instruction.cpp Thu Mar 29 07:26:56 2018
@@ -98,9 +98,7 @@ void Instruction::dispatch(unsigned RCUT
   RCUTokenID = RCUToken;
 
   // Check if input operands are already available.
-  if (std::all_of(Uses.begin(), Uses.end(),
-                  [](const UniqueUse &Use) { return Use->isReady(); }))
-    Stage = IS_READY;
+  update();
 }
 
 void Instruction::execute() {
@@ -122,19 +120,22 @@ bool Instruction::isZeroLatency() const
   return Desc.MaxLatency == 0 && Defs.size() == 0 && Uses.size() == 0;
 }
 
+void Instruction::update() {
+  if (!isDispatched())
+    return;
+
+  if (llvm::all_of(Uses, [](const UniqueUse &Use) { return Use->isReady(); }))
+    Stage = IS_READY;
+}
+
 void Instruction::cycleEvent() {
   if (isReady())
     return;
 
   if (isDispatched()) {
-    bool IsReady = true;
-    for (UniqueUse &Use : Uses) {
+    for (UniqueUse &Use : Uses)
       Use->cycleEvent();
-      IsReady &= Use->isReady();
-    }
-
-    if (IsReady)
-      Stage = IS_READY;
+    update();
     return;
   }
 

Modified: llvm/trunk/tools/llvm-mca/Instruction.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-mca/Instruction.h?rev=328790&r1=328789&r2=328790&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-mca/Instruction.h (original)
+++ llvm/trunk/tools/llvm-mca/Instruction.h Thu Mar 29 07:26:56 2018
@@ -60,8 +60,12 @@ struct WriteDescriptor {
 
 /// \brief A register read descriptor.
 struct ReadDescriptor {
-  // This field defaults to -1 if this is an implicit read.
+  // A MCOperand index. This is used by the Dispatch logic to identify register
+  // reads. This field defaults to -1 if this is an implicit read.
   int OpIndex;
+  // The actual "UseIdx". This field defaults to -1 if this is an implicit read.
+  // This is used by the scheduler to solve ReadAdvance queries.
+  int UseIndex;
   // This field is only set if this is an implicit read.
   unsigned RegisterID;
   // Scheduling Class Index. It is used to query the scheduling model for the
@@ -296,6 +300,14 @@ public:
   // all the definitions.
   void execute();
 
+  // Force a transition from the IS_AVAILABLE state to the IS_READY state if
+  // input operands are all ready. State transitions normally occur at the
+  // beginning of a new cycle (see method cycleEvent()). However, the scheduler
+  // may decide to promote instructions from the wait queue to the ready queue
+  // as the result of another issue event.  This method is called every time the
+  // instruction might have changed in state.
+  void update();
+
   bool isDispatched() const { return Stage == IS_AVAILABLE; }
   bool isReady() const { return Stage == IS_READY; }
   bool isExecuting() const { return Stage == IS_EXECUTING; }

Modified: llvm/trunk/tools/llvm-mca/Scheduler.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-mca/Scheduler.cpp?rev=328790&r1=328789&r2=328790&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-mca/Scheduler.cpp (original)
+++ llvm/trunk/tools/llvm-mca/Scheduler.cpp Thu Mar 29 07:26:56 2018
@@ -293,7 +293,10 @@ void Scheduler::cycleEvent(unsigned /* u
 
   updateIssuedQueue();
   updatePendingQueue();
-  issue();
+  bool InstructionsWerePromoted = false;
+  do {
+    InstructionsWerePromoted = issue();
+  } while(InstructionsWerePromoted);
 }
 
 #ifndef NDEBUG
@@ -357,7 +360,40 @@ void Scheduler::issueInstruction(Instruc
   notifyInstructionExecuted(InstrIndex);
 }
 
-void Scheduler::issue() {
+bool Scheduler::promoteToReadyQueue() {
+  // Scan the set of waiting instructions and promote them to the
+  // ready queue if operands are all ready.
+  bool InstructionsWerePromoted = false;
+  for (auto I = WaitQueue.begin(), E = WaitQueue.end(); I != E;) {
+    const QueueEntryTy &Entry = *I;
+
+    // Check if this instruction is now ready. In case, force
+    // a transition in state using method 'update()'.
+    Entry.second->update();
+    bool IsReady = Entry.second->isReady();
+
+    const InstrDesc &Desc = Entry.second->getDesc();
+    bool IsMemOp = Desc.MayLoad || Desc.MayStore;
+    if (IsReady && IsMemOp)
+      IsReady &= LSU->isReady(Entry.first);
+
+    if (IsReady) {
+      notifyInstructionReady(Entry.first);
+      ReadyQueue[Entry.first] = Entry.second;
+      auto ToRemove = I;
+      ++I;
+      WaitQueue.erase(ToRemove);
+      InstructionsWerePromoted = true;
+    } else {
+      ++I;
+    }
+  }
+  
+  return InstructionsWerePromoted;
+}
+
+
+bool Scheduler::issue() {
   std::vector<unsigned> ToRemove;
   for (const QueueEntryTy QueueEntry : ReadyQueue) {
     // Give priority to older instructions in ReadyQueue. The ready queue is
@@ -371,33 +407,27 @@ void Scheduler::issue() {
     ToRemove.emplace_back(InstrIndex);
   }
 
+  if (ToRemove.empty())
+    return false;
+
   for (const unsigned InstrIndex : ToRemove)
     ReadyQueue.erase(InstrIndex);
+
+  // Instructions that have been issued during this cycle might have unblocked
+  // other dependent instructions. Dependent instructions
+  // may be issued during this same cycle if operands have ReadAdvance entries.
+  // Promote those instructions to the ReadyQueue and tell to the caller that
+  // we need another round of 'issue()'.
+  return promoteToReadyQueue();
 }
 
 void Scheduler::updatePendingQueue() {
-  // Scan the set of waiting instructions and promote them to the
-  // ready queue if operands are all ready.
-  for (auto I = WaitQueue.begin(), E = WaitQueue.end(); I != E;) {
-    const QueueEntryTy Entry = *I;
+  // Notify to instructions in the pending queue that a new cycle just
+  // started.
+  for (QueueEntryTy Entry : WaitQueue)
     Entry.second->cycleEvent();
 
-    const InstrDesc &Desc = Entry.second->getDesc();
-    bool IsMemOp = Desc.MayLoad || Desc.MayStore;
-    bool IsReady = Entry.second->isReady();
-    if (IsReady && IsMemOp)
-      IsReady &= LSU->isReady(Entry.first);
-
-    if (IsReady) {
-      notifyInstructionReady(Entry.first);
-      ReadyQueue[Entry.first] = Entry.second;
-      auto ToRemove = I;
-      ++I;
-      WaitQueue.erase(ToRemove);
-    } else {
-      ++I;
-    }
-  }
+  promoteToReadyQueue();
 }
 
 void Scheduler::updateIssuedQueue() {

Modified: llvm/trunk/tools/llvm-mca/Scheduler.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-mca/Scheduler.h?rev=328790&r1=328789&r2=328790&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-mca/Scheduler.h (original)
+++ llvm/trunk/tools/llvm-mca/Scheduler.h Thu Mar 29 07:26:56 2018
@@ -430,9 +430,14 @@ class Scheduler {
   // Notify the Backend that buffered resources were freed.
   void notifyReleasedBuffers(llvm::ArrayRef<uint64_t> Buffers);
 
-  /// Issue instructions from the ready queue by giving priority to older
-  /// instructions.
-  void issue();
+  /// Issue instructions from the ReadyQueue by giving priority to older
+  /// instructions. This method returns true if at least one instruction has
+  /// been promoted in the process from the WaitQueue to the ReadyQueue.
+  bool issue();
+
+  /// Scans the WaitQueue in search of instructions that can be moved to
+  /// the ReadyQueue.
+  bool promoteToReadyQueue();
 
   /// Issue an instruction without updating the ready queue.
   void issueInstruction(Instruction &IS, unsigned InstrIndex);




More information about the llvm-commits mailing list