Skip to content

Commit 335a802

Browse files
committed
fixup! [GVN] Support rnflow pattern matching and transform
1 parent b92caf2 commit 335a802

File tree

4 files changed

+160
-151
lines changed

4 files changed

+160
-151
lines changed

llvm/include/llvm/Transforms/Scalar/GVN.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -407,8 +407,13 @@ class GVNPass : public PassInfoMixin<GVNPass> {
407407
void addDeadBlock(BasicBlock *BB);
408408
void assignValNumForDeadCode();
409409
void assignBlockRPONumber(Function &F);
410-
411-
bool optimizeMinMaxFindingSelectPattern(SelectInst *Select);
410+
411+
bool recognizeMinFindingSelectPattern(SelectInst *Select);
412+
bool transformMinFindingSelectPattern(Loop *L, BasicBlock *Preheader,
413+
BasicBlock *BB, Value *LHS, Value *RHS,
414+
CmpInst *Comparison, SelectInst *Select,
415+
Value *BasePtr, Value *IndexVal,
416+
Value *OffsetVal);
412417
};
413418

414419
/// Create a legacy GVN pass.

llvm/lib/Transforms/Scalar/GVN.cpp

Lines changed: 95 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -2744,7 +2744,7 @@ bool GVNPass::processInstruction(Instruction *I) {
27442744
return Changed;
27452745
}
27462746
if (SelectInst *Select = dyn_cast<SelectInst>(I)) {
2747-
if (optimizeMinMaxFindingSelectPattern(Select))
2747+
if (recognizeMinFindingSelectPattern(Select))
27482748
return true;
27492749
}
27502750

@@ -3334,19 +3334,99 @@ void GVNPass::assignValNumForDeadCode() {
33343334
}
33353335
}
33363336

3337-
bool GVNPass::optimizeMinMaxFindingSelectPattern(SelectInst *Select) {
3337+
bool GVNPass::transformMinFindingSelectPattern(Loop *L, BasicBlock *Preheader,
3338+
BasicBlock *BB, Value *LHS,
3339+
Value *RHS, CmpInst *Comparison,
3340+
SelectInst *Select,
3341+
Value *BasePtr, Value *IndexVal,
3342+
Value *OffsetVal) {
3343+
// Hoist the chain of operations for the second load to preheader.
3344+
// %min.idx.ext = sext i32 %min.idx to i64
3345+
// %ptr.float.min = getelementptr float, ptr %0, i64 %min.idx.ext
3346+
// %ptr.second.load = getelementptr i8, ptr %ptr.float.min, i64 -4
3347+
// %val.current.min = load float, ptr %ptr.second.load, align 4
3348+
IRBuilder<> Builder(Preheader->getTerminator());
3349+
3350+
PHINode *Phi = dyn_cast<PHINode>(IndexVal);
3351+
if (!Phi) {
3352+
LLVM_DEBUG(dbgs() << "GVN: IndexVal is not a PHI node\n");
3353+
return false;
3354+
}
3355+
3356+
Value *InitialMinIndex = Phi->getIncomingValueForBlock(Preheader);
3357+
3358+
// Insert PHI node at the top of this block.
3359+
// This PHI node will be used to memoize the current minimum value so far.
3360+
PHINode *KnownMinPhi =
3361+
PHINode::Create(Builder.getFloatTy(), 2, "known_min", BB->begin());
3362+
3363+
// Hoist the load and build the necessary operations.
3364+
// 1. hoist_0 = sext i32 to i64
3365+
Value *HoistedSExt =
3366+
Builder.CreateSExt(InitialMinIndex, Builder.getInt64Ty(), "hoist_sext");
3367+
3368+
// 2. hoist_gep1 = getelementptr float, ptr BasePtr, i64 HoistedSExt
3369+
Value *HoistedGEP1 = Builder.CreateGEP(Builder.getFloatTy(), BasePtr,
3370+
HoistedSExt, "hoist_gep1");
3371+
3372+
// 3. hoist_gep2 = getelementptr i8, ptr HoistedGEP1, i64 OffsetVal
3373+
Value *HoistedGEP2 = Builder.CreateGEP(Builder.getInt8Ty(), HoistedGEP1,
3374+
OffsetVal, "hoist_gep2");
3375+
3376+
// 4. hoisted_load = load float, ptr HoistedGEP2
3377+
LoadInst *NewLoad =
3378+
Builder.CreateLoad(Builder.getFloatTy(), HoistedGEP2, "hoisted_load");
3379+
3380+
// Let the new load now take the place of the old load.
3381+
RHS->replaceAllUsesWith(NewLoad);
3382+
dyn_cast<LoadInst>(RHS)->eraseFromParent();
3383+
3384+
// Comparison should now compare the current value and the newly inserted
3385+
// PHI node.
3386+
Comparison->setOperand(1, KnownMinPhi);
3387+
3388+
// Create new select instruction for selecting the minimum value.
3389+
IRBuilder<> SelectBuilder(BB->getTerminator());
3390+
SelectInst *CurrentMinSelect = dyn_cast<SelectInst>(
3391+
SelectBuilder.CreateSelect(Comparison, LHS, KnownMinPhi, "current_min"));
3392+
3393+
// Populate the newly created PHI node
3394+
// with (hoisted) NewLoad from the preheader and CurrentMinSelect.
3395+
KnownMinPhi->addIncoming(NewLoad, Preheader);
3396+
KnownMinPhi->addIncoming(CurrentMinSelect, BB);
3397+
LLVM_DEBUG(dbgs() << "Transformed the code\n");
3398+
return true;
3399+
}
3400+
3401+
bool GVNPass::recognizeMinFindingSelectPattern(SelectInst *Select) {
3402+
Value *BasePtr = nullptr, *IndexVal = nullptr, *OffsetVal = nullptr;
33383403
LLVM_DEBUG(
33393404
dbgs()
3340-
<< "GVN: Analyzing select instruction for minimum finding pattern\n");
3405+
<< "GVN: Analyzing select instruction for minimum finding pattern.\n");
33413406
LLVM_DEBUG(dbgs() << "GVN: Select: " << *Select << "\n");
3407+
BasicBlock *BB = Select->getParent();
3408+
3409+
// If the block is not in a loop, bail out.
3410+
Loop *L = LI->getLoopFor(BB);
3411+
if (!L) {
3412+
LLVM_DEBUG(dbgs() << "GVN: Could not find loop.\n");
3413+
return false;
3414+
}
3415+
3416+
// If preheader of the loop is not found, bail out.
3417+
BasicBlock *Preheader = L->getLoopPreheader();
3418+
if (!Preheader) {
3419+
LLVM_DEBUG(dbgs() << "GVN: Could not find loop preheader.\n");
3420+
return false;
3421+
}
33423422
Value *Condition = Select->getCondition();
33433423
CmpInst *Comparison = dyn_cast<CmpInst>(Condition);
33443424
if (!Comparison) {
3345-
LLVM_DEBUG(dbgs() << "GVN: Condition is not a comparison\n");
3425+
LLVM_DEBUG(dbgs() << "GVN: Condition is not a comparison.\n");
33463426
return false;
33473427
}
33483428

3349-
// Check if this is ULT comparison.
3429+
// Check if this is less-than comparison.
33503430
CmpInst::Predicate Pred = Comparison->getPredicate();
33513431
if (Pred != CmpInst::ICMP_SLT && Pred != CmpInst::ICMP_ULT &&
33523432
Pred != CmpInst::FCMP_OLT && Pred != CmpInst::FCMP_ULT) {
@@ -3359,99 +3439,24 @@ bool GVNPass::optimizeMinMaxFindingSelectPattern(SelectInst *Select) {
33593439
Value *LHS = Comparison->getOperand(0);
33603440
Value *RHS = Comparison->getOperand(1);
33613441
if (!isa<LoadInst>(LHS) || !isa<LoadInst>(RHS)) {
3362-
LLVM_DEBUG(dbgs() << "GVN: Not both operands are loads\n");
3442+
LLVM_DEBUG(dbgs() << "GVN: Not both operands are loads.\n");
33633443
return false;
33643444
}
33653445

3366-
LLVM_DEBUG(dbgs() << "GVN: Found minimum finding pattern in Block: "
3367-
<< Select->getParent()->getName() << "\n");
3368-
3369-
// Transform the pattern.
3370-
// Hoist the chain of operations for the second load to preheader.
3371-
// Get predecessor of the block containing the select instruction.
3372-
BasicBlock *BB = Select->getParent();
3373-
3374-
// Get preheader of the loop.
3375-
Loop *L = LI->getLoopFor(BB);
3376-
if (!L) {
3377-
LLVM_DEBUG(dbgs() << "GVN: Could not find loop\n");
3378-
return false;
3379-
}
3380-
BasicBlock *Preheader = L->getLoopPreheader();
3381-
if (!Preheader) {
3382-
LLVM_DEBUG(dbgs() << "GVN: Could not find loop preheader\n");
3446+
if (!match(RHS,
3447+
m_Load(m_GEP(m_GEP(m_Value(BasePtr), m_SExt(m_Value(IndexVal))),
3448+
m_Value(OffsetVal))))) {
3449+
LLVM_DEBUG(dbgs() << "GVN: Not a required load pattern.\n");
33833450
return false;
33843451
}
3452+
LLVM_DEBUG(dbgs() << "GVN: Found minimum finding pattern in Block: "
3453+
<< Select->getParent()->getName() << ".\n");
33853454

3386-
// Hoist the chain of operations for the second load to preheader.
3387-
// %90 = sext i32 %.05.i to i64
3388-
// %91 = getelementptr float, ptr %0, i64 %90 ; %0 + (sext i32 %85 to i64)*4
3389-
// %92 = getelementptr i8, ptr %91, i64 -4 ; %0 + (sext i32 %85 to i64)*4 - 4
3390-
// %93 = load float, ptr %92, align 4
3391-
3392-
Value *BasePtr = nullptr, *IndexVal = nullptr, *OffsetVal = nullptr;
3393-
IRBuilder<> Builder(Preheader->getTerminator());
3394-
if (match(RHS,
3395-
m_Load(m_GEP(m_GEP(m_Value(BasePtr), m_SExt(m_Value(IndexVal))),
3396-
m_Value(OffsetVal))))) {
3397-
LLVM_DEBUG(dbgs() << "GVN: Found pattern: " << *RHS << "\n");
3398-
LLVM_DEBUG(dbgs() << "GVN: Found pattern: " << "\n");
3399-
3400-
PHINode *Phi = dyn_cast<PHINode>(IndexVal);
3401-
if (!Phi) {
3402-
LLVM_DEBUG(dbgs() << "GVN: IndexVal is not a PHI node\n");
3403-
return false;
3404-
}
3405-
Value *InitialMinIndex = Phi->getIncomingValueForBlock(Preheader);
3406-
3407-
// Insert PHI node at the top of this block.
3408-
PHINode *KnownMinPhi =
3409-
PHINode::Create(Builder.getFloatTy(), 2, "known_min", BB->begin());
3410-
3411-
// Build the GEP chain in the preheader.
3412-
// 1. hoist_0 = sext i32 to i64
3413-
Value *HoistedSExt =
3414-
Builder.CreateSExt(InitialMinIndex, Builder.getInt64Ty(), "hoist_sext");
3415-
3416-
// 2. hoist_gep1 = getelementptr float, ptr BasePtr, i64 HoistedSExt
3417-
Value *HoistedGEP1 = Builder.CreateGEP(Builder.getFloatTy(), BasePtr,
3418-
HoistedSExt, "hoist_gep1");
3419-
3420-
// 3. hoist_gep2 = getelementptr i8, ptr HoistedGEP1, i64 OffsetVal
3421-
Value *HoistedGEP2 = Builder.CreateGEP(Builder.getInt8Ty(), HoistedGEP1,
3422-
OffsetVal, "hoist_gep2");
3423-
3424-
// 4. hoisted_load = load float, ptr HoistedGEP2
3425-
LoadInst *NewLoad =
3426-
Builder.CreateLoad(Builder.getFloatTy(), HoistedGEP2, "hoisted_load");
3427-
3428-
// Replace all uses of load with new load.
3429-
RHS->replaceAllUsesWith(NewLoad);
3430-
dyn_cast<LoadInst>(RHS)->eraseFromParent();
3431-
3432-
// Replace second operand of comparison with KnownMinPhi.
3433-
Comparison->setOperand(1, KnownMinPhi);
3434-
3435-
// Create new select instruction for selecting the minimum value.
3436-
IRBuilder<> SelectBuilder(BB->getTerminator());
3437-
SelectInst *CurrentMinSelect =
3438-
dyn_cast<SelectInst>(SelectBuilder.CreateSelect(
3439-
Comparison, LHS, KnownMinPhi, "current_min"));
3440-
3441-
// Populate PHI node.
3442-
KnownMinPhi->addIncoming(NewLoad, Preheader);
3443-
KnownMinPhi->addIncoming(CurrentMinSelect, BB);
3444-
LLVM_DEBUG(dbgs() << "Transformed the code\n");
3445-
return true;
3446-
} else {
3447-
LLVM_DEBUG(dbgs() << "GVN: Could not find pattern: " << *RHS << "\n");
3448-
LLVM_DEBUG(dbgs() << "GVN: Could not find pattern: " << "\n");
3449-
return false;
3450-
}
3451-
return false;
3455+
return transformMinFindingSelectPattern(L, Preheader, BB, LHS, RHS,
3456+
Comparison, Select, BasePtr, IndexVal,
3457+
OffsetVal);
34523458
}
34533459

3454-
34553460
class llvm::gvn::GVNLegacyPass : public FunctionPass {
34563461
public:
34573462
static char ID; // Pass identification, replacement for typeid.
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
2+
; RUN: opt -passes=gvn -S < %s | FileCheck %s
3+
4+
define void @test_gvn_min_pattern(ptr %0) {
5+
; CHECK-LABEL: define void @test_gvn_min_pattern(
6+
; CHECK-SAME: ptr [[TMP0:%.*]]) {
7+
; CHECK-NEXT: [[ENTRY:.*]]:
8+
; CHECK-NEXT: [[HOIST_GEP1:%.*]] = getelementptr float, ptr [[TMP0]], i64 1
9+
; CHECK-NEXT: [[HOIST_GEP2:%.*]] = getelementptr i8, ptr [[HOIST_GEP1]], i64 -4
10+
; CHECK-NEXT: [[HOISTED_LOAD:%.*]] = load float, ptr [[HOIST_GEP2]], align 4
11+
; CHECK-NEXT: br label %[[LOOP:.*]]
12+
; CHECK: [[LOOP]]:
13+
; CHECK-NEXT: [[KNOWN_MIN:%.*]] = phi float [ [[HOISTED_LOAD]], %[[ENTRY]] ], [ [[CURRENT_MIN:%.*]], %[[LOOP]] ]
14+
; CHECK-NEXT: [[INDVARS_IV_I:%.*]] = phi i64 [ 1, %[[ENTRY]] ], [ [[INDVARS_IV_NEXT_I:%.*]], %[[LOOP]] ]
15+
; CHECK-NEXT: [[LOOP_COUNTER:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[LOOP_COUNTER_NEXT:%.*]], %[[LOOP]] ]
16+
; CHECK-NEXT: [[MIN_IDX:%.*]] = phi i32 [ 1, %[[ENTRY]] ], [ [[MIN_IDX_NEXT:%.*]], %[[LOOP]] ]
17+
; CHECK-NEXT: [[INDVARS_IV_NEXT_I]] = add nsw i64 [[INDVARS_IV_I]], -1
18+
; CHECK-NEXT: [[PTR_FLOAT_IV:%.*]] = getelementptr float, ptr [[TMP0]], i64 [[INDVARS_IV_I]]
19+
; CHECK-NEXT: [[PTR_FIRST_LOAD:%.*]] = getelementptr i8, ptr [[PTR_FLOAT_IV]], i64 -8
20+
; CHECK-NEXT: [[VAL_FIRST:%.*]] = load float, ptr [[PTR_FIRST_LOAD]], align 4
21+
; CHECK-NEXT: [[MIN_IDX_EXT:%.*]] = sext i32 [[MIN_IDX]] to i64
22+
; CHECK-NEXT: [[PTR_FLOAT_MIN:%.*]] = getelementptr float, ptr [[TMP0]], i64 [[MIN_IDX_EXT]]
23+
; CHECK-NEXT: [[PTR_SECOND_LOAD:%.*]] = getelementptr i8, ptr [[PTR_FLOAT_MIN]], i64 -4
24+
; CHECK-NEXT: [[CMP:%.*]] = fcmp contract olt float [[VAL_FIRST]], [[KNOWN_MIN]]
25+
; CHECK-NEXT: [[NEXT_IDX_TRUNC:%.*]] = trunc nsw i64 [[INDVARS_IV_NEXT_I]] to i32
26+
; CHECK-NEXT: [[MIN_IDX_NEXT]] = select i1 [[CMP]], i32 [[NEXT_IDX_TRUNC]], i32 [[MIN_IDX]]
27+
; CHECK-NEXT: [[LOOP_COUNTER_NEXT]] = add nsw i64 [[LOOP_COUNTER]], -1
28+
; CHECK-NEXT: [[LOOP_CONTINUE:%.*]] = icmp samesign ugt i64 [[LOOP_COUNTER]], 1
29+
; CHECK-NEXT: [[CURRENT_MIN]] = select i1 [[CMP]], float [[VAL_FIRST]], float [[KNOWN_MIN]]
30+
; CHECK-NEXT: br i1 [[LOOP_CONTINUE]], label %[[LOOP]], label %[[EXIT:.*]]
31+
; CHECK: [[EXIT]]:
32+
; CHECK-NEXT: ret void
33+
;
34+
entry:
35+
br label %loop
36+
37+
loop: ; preds = %loop, %entry
38+
%indvars.iv.i = phi i64 [ 1, %entry ], [ %indvars.iv.next.i, %loop ]
39+
%loop.counter = phi i64 [ 0, %entry ], [ %loop.counter.next, %loop ]
40+
%min.idx = phi i32 [ 1, %entry ], [ %min.idx.next, %loop ]
41+
%indvars.iv.next.i = add nsw i64 %indvars.iv.i, -1
42+
%ptr.float.iv = getelementptr float, ptr %0, i64 %indvars.iv.i
43+
%ptr.first.load = getelementptr i8, ptr %ptr.float.iv, i64 -8
44+
%val.first = load float, ptr %ptr.first.load, align 4
45+
%min.idx.ext = sext i32 %min.idx to i64
46+
%ptr.float.min = getelementptr float, ptr %0, i64 %min.idx.ext
47+
%ptr.second.load = getelementptr i8, ptr %ptr.float.min, i64 -4
48+
%val.current.min = load float, ptr %ptr.second.load, align 4
49+
%cmp = fcmp contract olt float %val.first, %val.current.min
50+
%next.idx.trunc = trunc nsw i64 %indvars.iv.next.i to i32
51+
%min.idx.next = select i1 %cmp, i32 %next.idx.trunc, i32 %min.idx
52+
%loop.counter.next = add nsw i64 %loop.counter, -1
53+
%loop.continue = icmp samesign ugt i64 %loop.counter, 1
54+
br i1 %loop.continue, label %loop, label %exit
55+
56+
exit:
57+
ret void
58+
}

llvm/test/Transforms/GVN/PRE/rnflow-gvn-pre.ll

Lines changed: 0 additions & 59 deletions
This file was deleted.

0 commit comments

Comments
 (0)