Skip to content

Commit ba3ce9f

Browse files
committed
fixup! address review comments
1. Added 10+ negative tests. 2. Added positive tests for non-float types. 3. Strengthning checks in recognize function 4. clang-format changes 5. Addressed other review comments
1 parent 6125286 commit ba3ce9f

File tree

3 files changed

+810
-37
lines changed

3 files changed

+810
-37
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ class FunctionPass;
4646
class GetElementPtrInst;
4747
class ImplicitControlFlowTracking;
4848
class LoadInst;
49+
class Loop;
4950
class SelectInst;
5051
class LoopInfo;
5152
class MemDepResult;

llvm/lib/Transforms/Scalar/GVN.cpp

Lines changed: 138 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@
3434
#include "llvm/Analysis/InstructionPrecedenceTracking.h"
3535
#include "llvm/Analysis/InstructionSimplify.h"
3636
#include "llvm/Analysis/Loads.h"
37-
#include "llvm/Analysis/LoopInfo.h"
3837
#include "llvm/Analysis/MemoryBuiltins.h"
3938
#include "llvm/Analysis/MemoryDependenceAnalysis.h"
4039
#include "llvm/Analysis/MemorySSA.h"
@@ -3334,31 +3333,64 @@ void GVNPass::assignValNumForDeadCode() {
33343333
}
33353334
}
33363335

3336+
// Hoist the chain of operations for the second load to preheader.
3337+
// In this transformation, we hoist the redundant load to the preheader,
3338+
// caching the first value of the iteration. This value is used to compare with
3339+
// the current value of the iteration and update the minimum value.
3340+
// The comparison is done in the loop body using the new select instruction.
3341+
//
3342+
// *** Before transformation ***
3343+
//
3344+
// preheader:
3345+
// ...
3346+
// loop:
3347+
// ...
3348+
// ...
3349+
// %val.first = load <TYPE>, ptr %ptr.first.load, align 4
3350+
// %min.idx.ext = sext i32 %min.idx to i64
3351+
// %ptr.<TYPE>.min = getelementptr <TYPE>, ptr %0, i64 %min.idx.ext
3352+
// %ptr.second.load = getelementptr i8, ptr %ptr.<TYPE>.min, i64 -4
3353+
// %val.current.min = load <TYPE>, ptr %ptr.second.load, align 4
3354+
// ...
3355+
// ...
3356+
// br i1 %cond, label %loop, label %exit
3357+
//
3358+
// *** After transformation ***
3359+
//
3360+
// preheader:
3361+
// %min.idx.ext = sext i32 %min.idx.ext to i64
3362+
// %hoist_gep1 = getelementptr <TYPE>, ptr %0, i64 %min.idx.ext
3363+
// %hoist_gep2 = getelementptr i8, ptr %hoist_gep1, i64 -4
3364+
// %hoisted_load = load <TYPE>, ptr %hoist_gep2, align 4
3365+
// br label %loop
3366+
//
3367+
// loop:
3368+
// %val.first = load <TYPE>, ptr %ptr.first.load, align 4
3369+
// ...
3370+
// (new) %val.current.min = select i1 %cond, <TYPE> %hoisted_load, <TYPE>
3371+
// %val.current.min
3372+
// ...
3373+
// ...
3374+
// br i1 %cond, label %loop, label %exit
33373375
bool GVNPass::transformMinFindingSelectPattern(
33383376
Loop *L, Type *LoadType, BasicBlock *Preheader, BasicBlock *BB, Value *LHS,
3339-
Value *RHS, CmpInst *Comparison, SelectInst *Select, Value *BasePtr,
3377+
Value *LoadVal, CmpInst *Comparison, SelectInst *Select, Value *BasePtr,
33403378
Value *IndexVal, Value *OffsetVal) {
3341-
// Hoist the chain of operations for the second load to preheader.
3342-
// %min.idx.ext = sext i32 %min.idx to i64
3343-
// %ptr.float.min = getelementptr float, ptr %0, i64 %min.idx.ext
3344-
// %ptr.second.load = getelementptr i8, ptr %ptr.float.min, i64 -4
3345-
// %val.current.min = load float, ptr %ptr.second.load, align 4
3346-
IRBuilder<> Builder(Preheader->getTerminator());
33473379

3348-
PHINode *Phi = dyn_cast<PHINode>(IndexVal);
3349-
if (!Phi) {
3350-
LLVM_DEBUG(dbgs() << "GVN: IndexVal is not a PHI node\n");
3351-
return false;
3352-
}
3380+
assert(IndexVal && "IndexVal is null");
3381+
AAResults *AA = VN.getAliasAnalysis();
3382+
assert(AA && "AA is null");
33533383

3354-
Value *InitialMinIndex = Phi->getIncomingValueForBlock(Preheader);
3384+
IRBuilder<> Builder(Preheader->getTerminator());
3385+
Value *InitialMinIndex =
3386+
dyn_cast<PHINode>(IndexVal)->getIncomingValueForBlock(Preheader);
33553387

33563388
// Insert PHI node at the top of this block.
33573389
// This PHI node will be used to memoize the current minimum value so far.
33583390
PHINode *KnownMinPhi = PHINode::Create(LoadType, 2, "known_min", BB->begin());
33593391

33603392
// Hoist the load and build the necessary operations.
3361-
// 1. hoist_0 = sext i32 to i64
3393+
// 1. hoist_0 = sext i32 1 to i64
33623394
Value *HoistedSExt =
33633395
Builder.CreateSExt(InitialMinIndex, Builder.getInt64Ty(), "hoist_sext");
33643396

@@ -3370,12 +3402,40 @@ bool GVNPass::transformMinFindingSelectPattern(
33703402
Value *HoistedGEP2 = Builder.CreateGEP(Builder.getInt8Ty(), HoistedGEP1,
33713403
OffsetVal, "hoist_gep2");
33723404

3405+
MemoryLocation NewLoc = MemoryLocation(
3406+
HoistedGEP2,
3407+
LocationSize::precise(
3408+
L->getHeader()->getDataLayout().getTypeStoreSize(LoadType)));
3409+
// Check if any instruction in the loop clobbers this location.
3410+
bool CanHoist = true;
3411+
for (BasicBlock *BB : L->blocks()) {
3412+
for (Instruction &I : *BB) {
3413+
if (I.mayWriteToMemory()) {
3414+
// Check if this instruction may clobber our hoisted load.
3415+
ModRefInfo MRI = AA->getModRefInfo(&I, NewLoc);
3416+
if (isModOrRefSet(MRI)) {
3417+
LLVM_DEBUG(dbgs() << "GVN: Cannot hoist - may be clobbered by: " << I
3418+
<< "\n");
3419+
CanHoist = false;
3420+
break;
3421+
}
3422+
}
3423+
}
3424+
if (!CanHoist)
3425+
break;
3426+
}
3427+
if (!CanHoist) {
3428+
LLVM_DEBUG(dbgs() << "GVN: Cannot hoist - may be clobbered by some "
3429+
"instruction in the loop.\n");
3430+
return false;
3431+
}
3432+
33733433
// 4. hoisted_load = load float, ptr HoistedGEP2
33743434
LoadInst *NewLoad = Builder.CreateLoad(LoadType, HoistedGEP2, "hoisted_load");
33753435

33763436
// Let the new load now take the place of the old load.
3377-
RHS->replaceAllUsesWith(NewLoad);
3378-
dyn_cast<LoadInst>(RHS)->eraseFromParent();
3437+
LoadVal->replaceAllUsesWith(NewLoad);
3438+
dyn_cast<LoadInst>(LoadVal)->eraseFromParent();
33793439

33803440
// Comparison should now compare the current value and the newly inserted
33813441
// PHI node.
@@ -3390,16 +3450,42 @@ bool GVNPass::transformMinFindingSelectPattern(
33903450
// with (hoisted) NewLoad from the preheader and CurrentMinSelect.
33913451
KnownMinPhi->addIncoming(NewLoad, Preheader);
33923452
KnownMinPhi->addIncoming(CurrentMinSelect, BB);
3393-
LLVM_DEBUG(dbgs() << "Transformed the code\n");
3453+
3454+
if (MSSAU) {
3455+
auto *OrigUse =
3456+
MSSAU->getMemorySSA()->getMemoryAccess(dyn_cast<Instruction>(LoadVal));
3457+
if (OrigUse) {
3458+
MemoryAccess *DefiningAccess = OrigUse->getDefiningAccess();
3459+
MSSAU->createMemoryAccessInBB(NewLoad, DefiningAccess, Preheader,
3460+
MemorySSA::BeforeTerminator);
3461+
}
3462+
}
3463+
LLVM_DEBUG(
3464+
dbgs() << "GVN: Transformed the code for minimum finding pattern.\n");
33943465
return true;
33953466
}
33963467

3468+
// We are looking for the following pattern:
3469+
// loop:
3470+
// ...
3471+
// ...
3472+
// %min.idx = phi i32 [ %initial_min_idx, %entry ], [ %min.idx.next, %loop ]
3473+
// ...
3474+
// %val.first = load <TYPE>, ptr %ptr.first.load, align 4
3475+
// %min.idx.ext = sext i32 %min.idx to i64
3476+
// %ptr.<TYPE>.min = getelementptr <TYPE>, ptr %0, i64 %min.idx.ext
3477+
// %ptr.second.load = getelementptr i8, ptr %ptr.<TYPE>.min, i64 -4
3478+
// %val.current.min = load <TYPE>, ptr %ptr.second.load, align 4
3479+
// %cmp = <CMP_INST> <TYPE> %val.first, %val.current.min
3480+
// ...
3481+
// %min.idx.next = select i1 %cmp, ..., i32 %min.idx
3482+
// ...
3483+
// ...
3484+
// br i1 ..., label %loop, ...
33973485
bool GVNPass::recognizeMinFindingSelectPattern(SelectInst *Select) {
3398-
Value *BasePtr = nullptr, *IndexVal = nullptr, *OffsetVal = nullptr;
3399-
LLVM_DEBUG(
3400-
dbgs()
3401-
<< "GVN: Analyzing select instruction for minimum finding pattern.\n");
3402-
LLVM_DEBUG(dbgs() << "GVN: Select: " << *Select << "\n");
3486+
IRBuilder<> Builder(Select);
3487+
Value *BasePtr = nullptr, *IndexVal = nullptr, *OffsetVal = nullptr,
3488+
*SExt = nullptr;
34033489
BasicBlock *BB = Select->getParent();
34043490

34053491
// If the block is not in a loop, bail out.
@@ -3439,21 +3525,41 @@ bool GVNPass::recognizeMinFindingSelectPattern(SelectInst *Select) {
34393525
return false;
34403526
}
34413527

3442-
if (!match(RHS,
3443-
m_Load(m_GEP(m_GEP(m_Value(BasePtr), m_SExt(m_Value(IndexVal))),
3444-
m_Value(OffsetVal))))) {
3528+
if (!match(RHS, m_Load(m_GEP(m_GEP(m_Value(BasePtr), m_Value(SExt)),
3529+
m_Value(OffsetVal))))) {
34453530
LLVM_DEBUG(dbgs() << "GVN: Not a required load pattern.\n");
34463531
return false;
34473532
}
3533+
// Check if the SExt instruction is a sext instruction.
3534+
SExtInst *SEInst = dyn_cast<SExtInst>(SExt);
3535+
if (!SEInst) {
3536+
LLVM_DEBUG(dbgs() << "GVN: not a sext instruction.\n");
3537+
return false;
3538+
}
3539+
// Check if the "To" and "from" type of the sext instruction are i64 and i32
3540+
// respectively.
3541+
if (SEInst->getType() != Builder.getInt64Ty() ||
3542+
SEInst->getOperand(0)->getType() != Builder.getInt32Ty()) {
3543+
LLVM_DEBUG(
3544+
dbgs()
3545+
<< "GVN: Not matching the required type for sext instruction.\n");
3546+
return false;
3547+
}
3548+
3549+
IndexVal = SEInst->getOperand(0);
3550+
// Check if the IndexVal is a PHI node.
3551+
PHINode *Phi = dyn_cast<PHINode>(IndexVal);
3552+
if (!Phi) {
3553+
LLVM_DEBUG(dbgs() << "GVN: IndexVal is not a PHI node\n");
3554+
return false;
3555+
}
3556+
34483557
LLVM_DEBUG(dbgs() << "GVN: Found minimum finding pattern in Block: "
34493558
<< Select->getParent()->getName() << ".\n");
34503559

3451-
// Get type of load.
3452-
Type *LoadType = dyn_cast<LoadInst>(LHS)->getType();
3453-
LLVM_DEBUG(dbgs() << "GVN: Transforming minimum finding pattern.\n");
3454-
return transformMinFindingSelectPattern(L, LoadType, Preheader, BB, LHS, RHS,
3455-
Comparison, Select, BasePtr, IndexVal,
3456-
OffsetVal);
3560+
return transformMinFindingSelectPattern(L, dyn_cast<LoadInst>(LHS)->getType(),
3561+
Preheader, BB, LHS, RHS, Comparison,
3562+
Select, BasePtr, IndexVal, OffsetVal);
34573563
}
34583564

34593565
class llvm::gvn::GVNLegacyPass : public FunctionPass {

0 commit comments

Comments
 (0)