[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