[llvm] [Pipeliner] Use VRMapPhi to generate phi in epilog (PR #211723)

Ikhlas Ajbar via llvm-commits llvm-commits at lists.llvm.org
Thu Jul 23 22:20:55 PDT 2026


https://github.com/iajbar created https://github.com/llvm/llvm-project/pull/211723

When generating a phi in the epilog block corresponding to an existing phi in the loop, the loop value should come from the new phi generated in the kernel block (for a non-phi instruction in the loop) rather than directly from the value map of the previous stage.

The new phis generated by generatePhis for non-phi instructions are stored in VRMapPhi. Thread VRMapPhi through generateExistingPhis and add a helper getMapPhiReg that returns the phi-generated register when available, falling back to VRMap otherwise.

Without this fix, the epilog can pick up the initial prolog value of a loop-carried register instead of the last kernel-iteration value, producing incorrect results for pipelined loops with two or more stages that carry values across iterations. This has been observed on Hexagon with the modulo scheduled epilog of a right-shift-with-carry loop after loop unrolling.

Fixes #208943

>From cca08702a17e26f9d4fc68eaffc8956092644fe7 Mon Sep 17 00:00:00 2001
From: Ikhlas Ajbar <iajbar at quicinc.com>
Date: Thu, 23 Jul 2026 20:01:43 -0700
Subject: [PATCH] [Pipeliner] Use VRMapPhi to generate phi in epilog

When generating a phi in the epilog block corresponding to an existing
phi in the loop, the loop value should come from the new phi generated
in the kernel block (for a non-phi instruction in the loop) rather than
directly from the value map of the previous stage.

The new phis generated by generatePhis for non-phi instructions are
stored in VRMapPhi. Thread VRMapPhi through generateExistingPhis and
add a helper getMapPhiReg that returns the phi-generated register when
available, falling back to VRMap otherwise.

Without this fix, the epilog can pick up the initial prolog value of a
loop-carried register instead of the last kernel-iteration value,
producing incorrect results for pipelined loops with two or more stages
that carry values across iterations. This has been observed on Hexagon
with the modulo scheduled epilog of a right-shift-with-carry loop after
loop unrolling.

Fixes #208943
---
 llvm/include/llvm/CodeGen/ModuloSchedule.h    |  16 +-
 llvm/lib/CodeGen/ModuloSchedule.cpp           |  28 +--
 llvm/test/CodeGen/Hexagon/swp-epilog-carry.ll | 190 ++++++++++++++++++
 .../test/CodeGen/Hexagon/swp-epilog-phi12.mir | 148 ++++++++++++++
 4 files changed, 367 insertions(+), 15 deletions(-)
 create mode 100644 llvm/test/CodeGen/Hexagon/swp-epilog-carry.ll
 create mode 100644 llvm/test/CodeGen/Hexagon/swp-epilog-phi12.mir

diff --git a/llvm/include/llvm/CodeGen/ModuloSchedule.h b/llvm/include/llvm/CodeGen/ModuloSchedule.h
index 87dc77a329a7e..586a3a157f3e0 100644
--- a/llvm/include/llvm/CodeGen/ModuloSchedule.h
+++ b/llvm/include/llvm/CodeGen/ModuloSchedule.h
@@ -197,9 +197,9 @@ class ModuloScheduleExpander {
                       MBBVectorTy &PrologBBs);
   void generateExistingPhis(MachineBasicBlock *NewBB, MachineBasicBlock *BB1,
                             MachineBasicBlock *BB2, MachineBasicBlock *KernelBB,
-                            ValueMapTy *VRMap, InstrMapTy &InstrMap,
-                            unsigned LastStageNum, unsigned CurStageNum,
-                            bool IsLast);
+                            ValueMapTy *VRMap, ValueMapTy *VRMapPhi,
+                            InstrMapTy &InstrMap, unsigned LastStageNum,
+                            unsigned CurStageNum, bool IsLast);
   void generatePhis(MachineBasicBlock *NewBB, MachineBasicBlock *BB1,
                     MachineBasicBlock *BB2, MachineBasicBlock *KernelBB,
                     ValueMapTy *VRMap, ValueMapTy *VRMapPhi,
@@ -233,6 +233,16 @@ class ModuloScheduleExpander {
                              Register NewReg, Register PrevReg = Register());
   bool isLoopCarried(MachineInstr &Phi);
 
+  // Check if register at StageNum is defined by a new phi instruction generated
+  // in kernel or epilog. If found, return register from VRMapPhi. Else return
+  // register from VRMap.
+  Register getMapPhiReg(ValueMapTy *VRMap, ValueMapTy *VRMapPhi,
+                        unsigned StageNum, Register OldReg) {
+    if (Register R = VRMapPhi[StageNum].lookup(OldReg))
+      return R;
+    return VRMap[StageNum].lookup(OldReg);
+  }
+
   /// Return the max. number of stages/iterations that can occur between a
   /// register definition and its uses.
   unsigned getStagesForReg(Register Reg, unsigned CurStage) {
diff --git a/llvm/lib/CodeGen/ModuloSchedule.cpp b/llvm/lib/CodeGen/ModuloSchedule.cpp
index 36db54cc516e7..bd2af691470c4 100644
--- a/llvm/lib/CodeGen/ModuloSchedule.cpp
+++ b/llvm/lib/CodeGen/ModuloSchedule.cpp
@@ -161,7 +161,7 @@ void ModuloScheduleExpander::generatePipelinedLoop() {
   KernelBB->replaceSuccessor(BB, KernelBB);
 
   generateExistingPhis(KernelBB, PrologBBs.back(), KernelBB, KernelBB, VRMap,
-                       InstrMap, MaxStageCount, MaxStageCount, false);
+                       VRMapPhi, InstrMap, MaxStageCount, MaxStageCount, false);
   generatePhis(KernelBB, PrologBBs.back(), KernelBB, KernelBB, VRMap, VRMapPhi,
                InstrMap, MaxStageCount, MaxStageCount, false);
 
@@ -313,7 +313,7 @@ void ModuloScheduleExpander::generateEpilog(
       }
     }
     generateExistingPhis(NewBB, PrologBBs[i - 1], PredBB, KernelBB, VRMap,
-                         InstrMap, LastStage, EpilogStage, i == 1);
+                         VRMapPhi, InstrMap, LastStage, EpilogStage, i == 1);
     generatePhis(NewBB, PrologBBs[i - 1], PredBB, KernelBB, VRMap, VRMapPhi,
                  InstrMap, LastStage, EpilogStage, i == 1);
     PredBB = NewBB;
@@ -370,8 +370,9 @@ static bool hasUseAfterLoop(Register Reg, MachineBasicBlock *BB,
 /// creation of new Phis.
 void ModuloScheduleExpander::generateExistingPhis(
     MachineBasicBlock *NewBB, MachineBasicBlock *BB1, MachineBasicBlock *BB2,
-    MachineBasicBlock *KernelBB, ValueMapTy *VRMap, InstrMapTy &InstrMap,
-    unsigned LastStageNum, unsigned CurStageNum, bool IsLast) {
+    MachineBasicBlock *KernelBB, ValueMapTy *VRMap, ValueMapTy *VRMapPhi,
+    InstrMapTy &InstrMap, unsigned LastStageNum, unsigned CurStageNum,
+    bool IsLast) {
   // Compute the stage number for the initial value of the Phi, which
   // comes from the prolog. The prolog to use depends on to which kernel/
   // epilog that we're adding the Phi.
@@ -499,23 +500,26 @@ void ModuloScheduleExpander::generateExistingPhis(
         // contains the last definition of the Phi.
         if (np == 0 && PrevStage == LastStageNum &&
             (StageScheduled != 0 || LoopValStage != 0) &&
-            VRMap[PrevStage - StageDiffAdj].count(LoopVal))
-          PhiOp2 = VRMap[PrevStage - StageDiffAdj][LoopVal];
+            getMapPhiReg(VRMap, VRMapPhi, PrevStage - StageDiffAdj, LoopVal))
+          PhiOp2 =
+              getMapPhiReg(VRMap, VRMapPhi, PrevStage - StageDiffAdj, LoopVal);
         // Use the value defined by the Phi. We add one because we switch
         // from looking at the loop value to the Phi definition.
         else if (np > 0 && PrevStage == LastStageNum &&
-                 VRMap[PrevStage - np + 1].count(Def))
-          PhiOp2 = VRMap[PrevStage - np + 1][Def];
+                 getMapPhiReg(VRMap, VRMapPhi, PrevStage - np + 1, Def))
+          PhiOp2 = getMapPhiReg(VRMap, VRMapPhi, PrevStage - np + 1, Def);
         // Use the loop value defined in the kernel.
         else if (static_cast<unsigned>(LoopValStage) > PrologStage + 1 &&
-                 VRMap[PrevStage - StageDiffAdj - np].count(LoopVal))
-          PhiOp2 = VRMap[PrevStage - StageDiffAdj - np][LoopVal];
+                 getMapPhiReg(VRMap, VRMapPhi, PrevStage - StageDiffAdj - np,
+                              LoopVal))
+          PhiOp2 = getMapPhiReg(VRMap, VRMapPhi, PrevStage - StageDiffAdj - np,
+                                LoopVal);
         // Use the value defined by the Phi, unless we're generating the first
         // epilog and the Phi refers to a Phi in a different stage.
-        else if (VRMap[PrevStage - np].count(Def) &&
+        else if (getMapPhiReg(VRMap, VRMapPhi, PrevStage - np, Def) &&
                  (!LoopDefIsPhi || (PrevStage != LastStageNum) ||
                   (LoopValStage == StageScheduled)))
-          PhiOp2 = VRMap[PrevStage - np][Def];
+          PhiOp2 = getMapPhiReg(VRMap, VRMapPhi, PrevStage - np, Def);
       }
 
       // Check if we can reuse an existing Phi. This occurs when a Phi
diff --git a/llvm/test/CodeGen/Hexagon/swp-epilog-carry.ll b/llvm/test/CodeGen/Hexagon/swp-epilog-carry.ll
new file mode 100644
index 0000000000000..e60c736e0fd77
--- /dev/null
+++ b/llvm/test/CodeGen/Hexagon/swp-epilog-carry.ll
@@ -0,0 +1,190 @@
+; RUN: llc -mtriple=hexagon -mcpu=hexagonv68 -O2 < %s | FileCheck %s
+
+; Regression test for https://github.com/llvm/llvm-project/issues/208943.
+;
+; The pipelined epilog of the unrolled remainder loop must use the carry
+; produced by the last kernel iteration, not the initial carry from the
+; prolog. The buggy code emits an extra "r4 = r5" copy between :endloop0
+; and the epilog packet that clobbers the correct carry.
+
+; CHECK-LABEL: mp_div_2d:
+
+; CHECK-LABEL: %for.body.epil
+; CHECK:      loop0(.[[KERNEL:LBB[0-9]+_[0-9]+]],
+; CHECK:      .[[KERNEL]]:{{.*}}%for.body.epil
+; CHECK:      [[CARRY:r[0-9]+]] |= asl([[PRIOR:r[0-9]+]],r{{[0-9]+}})
+; CHECK-NEXT: [[PRIOR]] = r{{[0-9]+}}
+; CHECK:      :endloop0
+; CHECK-NOT:  [[PRIOR]] = r
+; CHECK:      [[CARRY]] |= asl([[PRIOR]],r{{[0-9]+}})
+; CHECK-NEXT: memw({{.*}}) = [[CARRY]].new
+
+define dso_local i32 @mp_div_2d(ptr noundef %a, i32 noundef %b, ptr noundef %c, ptr noundef %d) #0 {
+entry:
+  %cmp = icmp slt i32 %b, 1
+  %call = tail call i32 @mp_copy(ptr noundef %a, ptr noundef %c)
+  br i1 %cmp, label %if.then, label %if.end3
+
+if.then:
+  %cmp1.not = icmp eq ptr %d, null
+  br i1 %cmp1.not, label %cleanup, label %if.then2
+
+if.then2:
+  tail call void @mp_zero(ptr noundef nonnull %d)
+  br label %cleanup
+
+if.end3:
+  %cmp5.not = icmp eq i32 %call, 0
+  br i1 %cmp5.not, label %if.end7, label %cleanup
+
+if.end7:
+  %cmp8.not = icmp eq ptr %d, null
+  br i1 %cmp8.not, label %if.end14, label %if.then9
+
+if.then9:
+  %call10 = tail call i32 @mp_mod_2d(ptr noundef %a, i32 noundef %b, ptr noundef nonnull %d)
+  %cmp11.not = icmp eq i32 %call10, 0
+  br i1 %cmp11.not, label %if.end14, label %cleanup
+
+if.end14:
+  %cmp15 = icmp samesign ugt i32 %b, 27
+  br i1 %cmp15, label %if.then16, label %if.end17
+
+if.then16:
+  %div = udiv i32 %b, 28
+  tail call void @mp_rshd(ptr noundef %c, i32 noundef %div)
+  br label %if.end17
+
+if.end17:
+  %rem = urem i32 %b, 28
+  %cmp18.not = icmp eq i32 %rem, 0
+  br i1 %cmp18.not, label %if.end26, label %if.then19
+
+if.then19:
+  %notmask = shl nsw i32 -1, %rem
+  %sub = xor i32 %notmask, -1
+  %sub20 = sub nuw nsw i32 28, %rem
+  %0 = load i32, ptr %c, align 4
+  %cmp2455 = icmp sgt i32 %0, 0
+  br i1 %cmp2455, label %for.body.preheader, label %if.end26
+
+for.body.preheader:
+  %dp = getelementptr inbounds nuw i8, ptr %c, i32 12
+  %1 = load ptr, ptr %dp, align 4
+  %2 = getelementptr [4 x i8], ptr %1, i32 %0
+  %add.ptr = getelementptr i8, ptr %2, i32 -4
+  %xtraiter = and i32 %0, 7
+  %3 = icmp ult i32 %0, 8
+  br i1 %3, label %for.body.epil.preheader, label %for.body.preheader.new
+
+for.body.preheader.new:
+  %unroll_iter = and i32 %0, 2147483640
+  br label %for.body
+
+for.body:
+  %r.058 = phi i32 [ 0, %for.body.preheader.new ], [ %and.7, %for.body ]
+  %tmpc.057 = phi ptr [ %add.ptr, %for.body.preheader.new ], [ %incdec.ptr.7, %for.body ]
+  %niter = phi i32 [ 0, %for.body.preheader.new ], [ %niter.next.7, %for.body ]
+  %4 = load i32, ptr %tmpc.057, align 4
+  %shr = lshr i32 %4, %rem
+  %shl25 = shl i32 %r.058, %sub20
+  %or = or i32 %shr, %shl25
+  store i32 %or, ptr %tmpc.057, align 4
+  %incdec.ptr = getelementptr inbounds i8, ptr %tmpc.057, i32 -4
+  %5 = load i32, ptr %incdec.ptr, align 4
+  %shr.1 = lshr i32 %5, %rem
+  %6 = shl i32 %4, %sub20
+  %shl25.1 = and i32 %6, 268435455
+  %or.1 = or i32 %shr.1, %shl25.1
+  store i32 %or.1, ptr %incdec.ptr, align 4
+  %incdec.ptr.1 = getelementptr inbounds i8, ptr %tmpc.057, i32 -8
+  %7 = load i32, ptr %incdec.ptr.1, align 4
+  %shr.2 = lshr i32 %7, %rem
+  %8 = shl i32 %5, %sub20
+  %shl25.2 = and i32 %8, 268435455
+  %or.2 = or i32 %shr.2, %shl25.2
+  store i32 %or.2, ptr %incdec.ptr.1, align 4
+  %incdec.ptr.2 = getelementptr inbounds i8, ptr %tmpc.057, i32 -12
+  %9 = load i32, ptr %incdec.ptr.2, align 4
+  %shr.3 = lshr i32 %9, %rem
+  %10 = shl i32 %7, %sub20
+  %shl25.3 = and i32 %10, 268435455
+  %or.3 = or i32 %shr.3, %shl25.3
+  store i32 %or.3, ptr %incdec.ptr.2, align 4
+  %incdec.ptr.3 = getelementptr inbounds i8, ptr %tmpc.057, i32 -16
+  %11 = load i32, ptr %incdec.ptr.3, align 4
+  %shr.4 = lshr i32 %11, %rem
+  %12 = shl i32 %9, %sub20
+  %shl25.4 = and i32 %12, 268435455
+  %or.4 = or i32 %shr.4, %shl25.4
+  store i32 %or.4, ptr %incdec.ptr.3, align 4
+  %incdec.ptr.4 = getelementptr inbounds i8, ptr %tmpc.057, i32 -20
+  %13 = load i32, ptr %incdec.ptr.4, align 4
+  %shr.5 = lshr i32 %13, %rem
+  %14 = shl i32 %11, %sub20
+  %shl25.5 = and i32 %14, 268435455
+  %or.5 = or i32 %shr.5, %shl25.5
+  store i32 %or.5, ptr %incdec.ptr.4, align 4
+  %incdec.ptr.5 = getelementptr inbounds i8, ptr %tmpc.057, i32 -24
+  %15 = load i32, ptr %incdec.ptr.5, align 4
+  %shr.6 = lshr i32 %15, %rem
+  %16 = shl i32 %13, %sub20
+  %shl25.6 = and i32 %16, 268435455
+  %or.6 = or i32 %shr.6, %shl25.6
+  store i32 %or.6, ptr %incdec.ptr.5, align 4
+  %incdec.ptr.6 = getelementptr inbounds i8, ptr %tmpc.057, i32 -28
+  %17 = load i32, ptr %incdec.ptr.6, align 4
+  %and.7 = and i32 %17, %sub
+  %shr.7 = lshr i32 %17, %rem
+  %18 = shl i32 %15, %sub20
+  %shl25.7 = and i32 %18, 268435455
+  %or.7 = or i32 %shr.7, %shl25.7
+  store i32 %or.7, ptr %incdec.ptr.6, align 4
+  %incdec.ptr.7 = getelementptr inbounds i8, ptr %tmpc.057, i32 -32
+  %niter.next.7 = add i32 %niter, 8
+  %niter.ncmp.7 = icmp eq i32 %niter.next.7, %unroll_iter
+  br i1 %niter.ncmp.7, label %if.end26.loopexit.unr-lcssa, label %for.body
+
+if.end26.loopexit.unr-lcssa:
+  %lcmp.mod.not = icmp eq i32 %xtraiter, 0
+  br i1 %lcmp.mod.not, label %if.end26, label %for.body.epil.preheader
+
+for.body.epil.preheader:
+  %r.058.epil.init = phi i32 [ 0, %for.body.preheader ], [ %and.7, %if.end26.loopexit.unr-lcssa ]
+  %tmpc.057.epil.init = phi ptr [ %add.ptr, %for.body.preheader ], [ %incdec.ptr.7, %if.end26.loopexit.unr-lcssa ]
+  %lcmp.mod59 = icmp ne i32 %xtraiter, 0
+  tail call void @llvm.assume(i1 %lcmp.mod59)
+  br label %for.body.epil
+
+for.body.epil:
+  %r.058.epil = phi i32 [ %and.epil, %for.body.epil ], [ %r.058.epil.init, %for.body.epil.preheader ]
+  %tmpc.057.epil = phi ptr [ %incdec.ptr.epil, %for.body.epil ], [ %tmpc.057.epil.init, %for.body.epil.preheader ]
+  %epil.iter = phi i32 [ %epil.iter.next, %for.body.epil ], [ 0, %for.body.epil.preheader ]
+  %19 = load i32, ptr %tmpc.057.epil, align 4
+  %and.epil = and i32 %19, %sub
+  %shr.epil = lshr i32 %19, %rem
+  %shl25.epil = shl i32 %r.058.epil, %sub20
+  %or.epil = or i32 %shr.epil, %shl25.epil
+  store i32 %or.epil, ptr %tmpc.057.epil, align 4
+  %incdec.ptr.epil = getelementptr inbounds i8, ptr %tmpc.057.epil, i32 -4
+  %epil.iter.next = add i32 %epil.iter, 1
+  %epil.iter.cmp.not = icmp eq i32 %epil.iter.next, %xtraiter
+  br i1 %epil.iter.cmp.not, label %if.end26, label %for.body.epil
+
+if.end26:
+  tail call void @mp_clamp(ptr noundef %c)
+  br label %cleanup
+
+cleanup:
+  %retval.0 = phi i32 [ 0, %if.end26 ], [ %call, %if.then ], [ %call, %if.end3 ], [ %call, %if.then2 ], [ %call10, %if.then9 ]
+  ret i32 %retval.0
+}
+
+declare i32 @mp_copy(ptr noundef, ptr noundef)
+declare void @mp_zero(ptr noundef)
+declare i32 @mp_mod_2d(ptr noundef, i32 noundef, ptr noundef)
+declare void @mp_rshd(ptr noundef, i32 noundef)
+declare void @mp_clamp(ptr noundef)
+declare void @llvm.assume(i1 noundef)
+
+attributes #0 = { nounwind "target-cpu"="hexagonv68" }
diff --git a/llvm/test/CodeGen/Hexagon/swp-epilog-phi12.mir b/llvm/test/CodeGen/Hexagon/swp-epilog-phi12.mir
new file mode 100644
index 0000000000000..6a5d6c9501353
--- /dev/null
+++ b/llvm/test/CodeGen/Hexagon/swp-epilog-phi12.mir
@@ -0,0 +1,148 @@
+# RUN: llc -march=hexagon -run-pass=pipeliner -debug-only=pipeliner %s -o - 2>&1 > /dev/null | FileCheck %s
+
+# Test that the phi in the epilog block generated for an existing phi
+# in the loop, obtains loop value from phi generated in the kernel block.
+# Phis generated in kernel for non-phi instructions in the loop are stored
+# in separate data structure and need to be used during existing phi generation
+# in epilog.
+
+# CHECK: prolog:
+# CHECK: bb.[[BB0:([0-9]+)]]
+# CHECK: %[[REG0:([0-9]+)]]:intregs = L2_loadri_io %{{.*}}%ir.a
+# CHECK: New block
+# CHECK: bb.[[BB1:([0-9]+)]]
+# CHECK: %[[REG1:([0-9]+)]]:intregs = PHI %[[REG0]]:intregs, %{{.*}}
+# CHECK: epilog:
+# CHECK: %{{[0-9]+}}:intregs = PHI %{{[0-9]+}}:intregs, %bb.[[BB0]], %[[REG1]]:intregs, %bb.[[BB1]]
+
+--- |
+  target datalayout = "e-m:e-p:32:32:32-a:0-n16:32-i64:64:64-i32:32:32-i16:16:16-i1:8:8-f32:32:32-f64:64:64-v32:32:32-v64:64:64-v512:512:512-v1024:1024:1024-v2048:2048:2048"
+  target triple = "hexagon"
+
+  define dso_local void @bar(ptr nocapture noundef readonly %i, ptr nocapture noundef readonly %j, ptr nocapture noundef writeonly %k, i32 noundef %l, i32 noundef %m, i32 noundef %n) local_unnamed_addr #0 {
+  entry:
+    %a = getelementptr i8, ptr %i, i32 4
+    %b = getelementptr i8, ptr %i, i32 16
+    %c = getelementptr i8, ptr %k, i32 4
+    %d = getelementptr i8, ptr %k, i32 16
+    ret void
+  }
+
+  attributes #0 = { nofree nosync nounwind memory(readwrite, inaccessiblemem: none) "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="hexagonv69" "target-features"="+v69,-long-calls" }
+
+  !0 = !{!"Simple C/C++ TBAA"}
+
+...
+---
+name:            bar
+alignment:       16
+exposesReturnsTwice: false
+legalized:       false
+regBankSelected: false
+selected:        false
+failedISel:      false
+tracksRegLiveness: true
+isOutlined:      false
+failsVerification: false
+registers:
+  - { id: 0, class: doubleregs, preferred-register: '' }
+  - { id: 1, class: doubleregs, preferred-register: '' }
+  - { id: 2, class: intregs, preferred-register: '' }
+  - { id: 3, class: intregs, preferred-register: '' }
+  - { id: 4, class: intregs, preferred-register: '' }
+  - { id: 5, class: intregs, preferred-register: '' }
+  - { id: 6, class: intregs, preferred-register: '' }
+  - { id: 7, class: intregs, preferred-register: '' }
+  - { id: 8, class: intregs, preferred-register: '' }
+  - { id: 9, class: intregs, preferred-register: '' }
+  - { id: 10, class: intregs, preferred-register: '' }
+  - { id: 11, class: doubleregs, preferred-register: '' }
+  - { id: 12, class: doubleregs, preferred-register: '' }
+  - { id: 13, class: intregs, preferred-register: '' }
+  - { id: 14, class: intregs, preferred-register: '' }
+  - { id: 15, class: intregs, preferred-register: '' }
+  - { id: 16, class: intregs, preferred-register: '' }
+  - { id: 17, class: intregs, preferred-register: '' }
+  - { id: 18, class: doubleregs, preferred-register: '' }
+  - { id: 19, class: intregs, preferred-register: '' }
+  - { id: 20, class: intregs, preferred-register: '' }
+  - { id: 21, class: doubleregs, preferred-register: '' }
+  - { id: 22, class: doubleregs, preferred-register: '' }
+  - { id: 23, class: intregs, preferred-register: '' }
+  - { id: 24, class: doubleregs, preferred-register: '' }
+  - { id: 25, class: intregs, preferred-register: '' }
+  - { id: 26, class: intregs, preferred-register: '' }
+  - { id: 27, class: intregs, preferred-register: '' }
+  - { id: 28, class: doubleregs, preferred-register: '' }
+  - { id: 29, class: intregs, preferred-register: '' }
+  - { id: 30, class: intregs, preferred-register: '' }
+  - { id: 31, class: doubleregs, preferred-register: '' }
+  - { id: 32, class: intregs, preferred-register: '' }
+  - { id: 33, class: intregs, preferred-register: '' }
+  - { id: 34, class: intregs, preferred-register: '' }
+  - { id: 35, class: predregs, preferred-register: '' }
+liveins:
+  - { reg: '$r0', virtual-reg: '%0' }
+  - { reg: '$r1', virtual-reg: '%1' }
+  - { reg: '$r2', virtual-reg: '%2' }
+  - { reg: '$r3', virtual-reg: '%3' }
+  - { reg: '$r4', virtual-reg: '%4' }
+  - { reg: '$r5', virtual-reg: '%5' }
+body:             |
+  bb.0.entry:
+    successors: %bb.1, %bb.3
+    liveins: $r0, $r1, $r2, $r3, $r4, $r5
+
+    %5:intregs = COPY $r5
+    %4:intregs = COPY $r4
+    %3:intregs = COPY $r3
+    %2:intregs = COPY $r2
+    %1:doubleregs = COPY $r1
+    %0:doubleregs = COPY $r0
+    %6:intregs, %7:intregs = L2_loadri_pi %3, 12
+    %8:intregs, %9:intregs = L2_loadri_pi %4, 12
+    %35:predregs = C2_cmpgti %8, 0
+    J2_jumpf %35, %bb.3, implicit-def dead $pc
+    J2_jump %bb.1, implicit-def dead $pc
+
+  bb.1:
+    successors: %bb.2
+
+    J2_loop0r %bb.2, %8, implicit-def $lc0, implicit-def $sa0, implicit-def $usr
+    J2_jump %bb.2, implicit-def $pc
+
+  bb.2:
+    successors: %bb.3, %bb.2
+
+    %10:intregs = PHI %7, %bb.1, %25, %bb.2
+    %11:doubleregs = PHI %0, %bb.1, %18, %bb.2
+    %12:doubleregs = PHI %1, %bb.1, %21, %bb.2
+    %13:intregs = PHI %2, %bb.1, %17, %bb.2
+    %14:intregs = PHI %9, %bb.1, %26, %bb.2
+    %15:intregs = PHI %5, %bb.1, %20, %bb.2
+    %16:intregs = PHI %6, %bb.1, %19, %bb.2
+    %22:doubleregs = M2_cmacs_s1 %12, %15, %13, implicit-def dead $usr_ovf
+    %17:intregs = L2_loadri_io %14, 4 :: (load (s32) from %ir.a + 8, !tbaa !0)
+    %23:intregs, %26:intregs = L2_loadri_pi %14, 8 :: (load (s32) from %ir.b + 8, !tbaa !0)
+    %24:doubleregs = M2_cmacs_s1 %11, %16, %13, implicit-def dead $usr_ovf
+    %18:doubleregs = M2_cmacs_s1 %24, %15, %23, implicit-def dead $usr_ovf
+    %19:intregs = L2_loadri_io %10, -4 :: (load (s32) from %ir.c + 8, !tbaa !0)
+    %20:intregs, %25:intregs = L2_loadri_pi %10, 8 :: (load (s32) from %ir.d + 8, !tbaa !0)
+    %21:doubleregs = M2_cmacs_s1 %22, %19, %23, implicit-def dead $usr_ovf
+    ENDLOOP0 %bb.2, implicit-def $pc, implicit-def $lc0, implicit $sa0, implicit $lc0
+    J2_jump %bb.3, implicit-def dead $pc
+
+  bb.3:
+    %27:intregs = PHI %2, %bb.0, %17, %bb.2
+    %28:doubleregs = PHI %0, %bb.0, %18, %bb.2
+    %29:intregs = PHI %6, %bb.0, %19, %bb.2
+    %30:intregs = PHI %5, %bb.0, %20, %bb.2
+    %31:doubleregs = PHI %1, %bb.0, %21, %bb.2
+    %32:intregs = PHI %9, %bb.0, %26, %bb.2
+    %33:intregs = A2_add %27, %29
+    S2_storerd_io %33, 0, %28
+    %34:intregs = A2_add %30, %32
+    S2_storerd_io %34, 0, %31
+    PS_jmpret $r31, implicit-def dead $pc
+
+...



More information about the llvm-commits mailing list