-
Notifications
You must be signed in to change notification settings - Fork 14.8k
[SCEV] Try to re-use pointer LCSSA phis when expanding SCEVs. #147824
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
e3cceac
d2a44bc
324d15f
d943379
a91517b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,6 +18,7 @@ | |
#include "llvm/ADT/SmallSet.h" | ||
#include "llvm/Analysis/InstructionSimplify.h" | ||
#include "llvm/Analysis/LoopInfo.h" | ||
#include "llvm/Analysis/ScalarEvolutionPatternMatch.h" | ||
#include "llvm/Analysis/TargetTransformInfo.h" | ||
#include "llvm/Analysis/ValueTracking.h" | ||
#include "llvm/IR/DataLayout.h" | ||
|
@@ -42,6 +43,7 @@ cl::opt<unsigned> llvm::SCEVCheapExpansionBudget( | |
"controls the budget that is considered cheap (default = 4)")); | ||
|
||
using namespace PatternMatch; | ||
using namespace SCEVPatternMatch; | ||
|
||
PoisonFlags::PoisonFlags(const Instruction *I) { | ||
NUW = false; | ||
|
@@ -1224,18 +1226,44 @@ Value *SCEVExpander::expandAddRecExprLiterally(const SCEVAddRecExpr *S) { | |
} | ||
|
||
Value *SCEVExpander::tryToReuseLCSSAPhi(const SCEVAddRecExpr *S) { | ||
Type *STy = S->getType(); | ||
const Loop *L = S->getLoop(); | ||
BasicBlock *EB = L->getExitBlock(); | ||
if (!EB || !EB->getSinglePredecessor() || | ||
!SE.DT.dominates(EB, Builder.GetInsertBlock())) | ||
return nullptr; | ||
|
||
for (auto &PN : EB->phis()) { | ||
if (!SE.isSCEVable(PN.getType()) || PN.getType() != S->getType()) | ||
if (!SE.isSCEVable(PN.getType())) | ||
continue; | ||
auto *ExitV = SE.getSCEV(&PN); | ||
if (S == ExitV) | ||
return &PN; | ||
auto *ExitSCEV = SE.getSCEV(&PN); | ||
if (!isa<SCEVAddRecExpr>(ExitSCEV)) | ||
continue; | ||
Type *PhiTy = PN.getType(); | ||
if (STy->isIntegerTy() && PhiTy->isPointerTy()) | ||
ExitSCEV = SE.getPtrToIntExpr(ExitSCEV, STy); | ||
else if (S->getType() != PN.getType()) | ||
continue; | ||
|
||
// Check if we can re-use the existing PN, by adjusting it with an expanded | ||
// offset, if the offset is simpler. | ||
const SCEV *Diff = SE.getMinusSCEV(S, ExitSCEV); | ||
const SCEV *Op = Diff; | ||
match(Diff, m_scev_Mul(m_scev_AllOnes(), m_SCEV(Op))); | ||
match(Op, m_scev_PtrToInt(m_SCEV(Op))); | ||
if (!isa<SCEVConstant, SCEVUnknown>(Op)) | ||
continue; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we limit this to just constant offsets (and use computeConstantDifference)? This check excludes one particularly bad case, but other complex expansions may also be non-profitable. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agreed that checking just for not containing add-recs might be a bit over-optimistic. Restricting to constant difference on the other hand would mean we miss other profitable cases. I added a restricted this now to only allow SCEVConstant/SCEVUnknown values, and PtrToInt/negations of those. This should cover all cases I found for now, on a large test set with vectorization enabled . |
||
|
||
assert(Diff->getType()->isIntegerTy() && | ||
"difference must be of integer type"); | ||
Value *DiffV = expand(Diff); | ||
Value *BaseV = &PN; | ||
nikic marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if (PhiTy->isPointerTy()) { | ||
if (STy->isPointerTy()) | ||
return Builder.CreatePtrAdd(BaseV, DiffV); | ||
BaseV = Builder.CreatePtrToInt(BaseV, DiffV->getType()); | ||
} | ||
return Builder.CreateAdd(BaseV, DiffV); | ||
} | ||
|
||
return nullptr; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 | ||
; RUN: opt -p loop-idiom -S %s | FileCheck %s | ||
|
||
declare void @foo() | ||
declare void @bar() | ||
|
||
define void @scev_expand_ptrtoint(i8 %x, ptr %start) { | ||
; CHECK-LABEL: define void @scev_expand_ptrtoint( | ||
; CHECK-SAME: i8 [[X:%.*]], ptr [[START:%.*]]) { | ||
; CHECK-NEXT: [[ENTRY:.*]]: | ||
; CHECK-NEXT: [[START1:%.*]] = ptrtoint ptr [[START]] to i64 | ||
; CHECK-NEXT: br label %[[LOOP_1_HEADER:.*]] | ||
; CHECK: [[LOOP_1_HEADER]]: | ||
; CHECK-NEXT: [[PTR_IV_1:%.*]] = phi ptr [ [[START]], %[[ENTRY]] ], [ [[PTR_IV_1_NEXT:%.*]], %[[LOOP_1_LATCH:.*]] ] | ||
; CHECK-NEXT: [[C:%.*]] = icmp ule i8 [[X]], 1 | ||
; CHECK-NEXT: br i1 [[C]], label %[[LOOP_1_LATCH]], label %[[MIDDLE:.*]] | ||
; CHECK: [[LOOP_1_LATCH]]: | ||
; CHECK-NEXT: [[PTR_IV_1_NEXT]] = getelementptr i8, ptr [[PTR_IV_1]], i64 1 | ||
; CHECK-NEXT: br label %[[LOOP_1_HEADER]] | ||
; CHECK: [[MIDDLE]]: | ||
; CHECK-NEXT: [[PTR_IV_1_LCSSA:%.*]] = phi ptr [ [[PTR_IV_1]], %[[LOOP_1_HEADER]] ] | ||
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[X]], 0 | ||
; CHECK-NEXT: [[CMP_EXT:%.*]] = zext i1 [[CMP]] to i64 | ||
; CHECK-NEXT: [[GEP_START:%.*]] = getelementptr i8, ptr [[PTR_IV_1_LCSSA]], i64 [[CMP_EXT]] | ||
; CHECK-NEXT: br label %[[LOOP_2_HEADER:.*]] | ||
; CHECK: [[LOOP_2_HEADER]]: | ||
; CHECK-NEXT: [[INDVAR:%.*]] = phi i64 [ [[INDVAR_NEXT:%.*]], %[[LOOP_2_LATCH:.*]] ], [ 0, %[[MIDDLE]] ] | ||
; CHECK-NEXT: [[PTR_IV_2:%.*]] = phi ptr [ [[GEP_START]], %[[MIDDLE]] ], [ [[PTR_IV_2_NEXT:%.*]], %[[LOOP_2_LATCH]] ] | ||
; CHECK-NEXT: switch i8 [[X]], label %[[LOOP_2_LATCH]] [ | ||
; CHECK-NEXT: i8 1, label %[[LOOP_3_PREHEADER:.*]] | ||
; CHECK-NEXT: i8 4, label %[[LOOP_3_PREHEADER]] | ||
; CHECK-NEXT: ] | ||
; CHECK: [[LOOP_3_PREHEADER]]: | ||
; CHECK-NEXT: [[INDVAR_LCSSA:%.*]] = phi i64 [ [[INDVAR]], %[[LOOP_2_HEADER]] ], [ [[INDVAR]], %[[LOOP_2_HEADER]] ] | ||
; CHECK-NEXT: [[PTR_IV_2_LCSSA:%.*]] = phi ptr [ [[PTR_IV_2]], %[[LOOP_2_HEADER]] ], [ [[PTR_IV_2]], %[[LOOP_2_HEADER]] ] | ||
; CHECK-NEXT: [[TMP0:%.*]] = sub i64 0, [[START1]] | ||
; CHECK-NEXT: [[TMP1:%.*]] = ptrtoint ptr [[PTR_IV_1_LCSSA]] to i64 | ||
; CHECK-NEXT: [[TMP2:%.*]] = add i64 [[TMP1]], [[TMP0]] | ||
; CHECK-NEXT: [[TMP3:%.*]] = add i64 [[TMP2]], 1 | ||
; CHECK-NEXT: [[TMP4:%.*]] = add i64 [[CMP_EXT]], [[TMP3]] | ||
; CHECK-NEXT: [[TMP5:%.*]] = add i64 [[INDVAR_LCSSA]], [[TMP4]] | ||
; CHECK-NEXT: [[SCEVGEP:%.*]] = getelementptr i8, ptr [[START]], i64 [[TMP5]] | ||
; CHECK-NEXT: [[STRLEN:%.*]] = call i64 @strlen(ptr [[SCEVGEP]]) | ||
; CHECK-NEXT: br label %[[LOOP_3:.*]] | ||
; CHECK: [[LOOP_2_LATCH]]: | ||
; CHECK-NEXT: [[PTR_IV_2_NEXT]] = getelementptr i8, ptr [[PTR_IV_2]], i64 1 | ||
; CHECK-NEXT: [[INDVAR_NEXT]] = add i64 [[INDVAR]], 1 | ||
; CHECK-NEXT: br label %[[LOOP_2_HEADER]] | ||
; CHECK: [[LOOP_3]]: | ||
; CHECK-NEXT: [[IV_3:%.*]] = phi i64 [ [[IV_3_NEXT:%.*]], %[[LOOP_3]] ], [ 1, %[[LOOP_3_PREHEADER]] ] | ||
; CHECK-NEXT: [[GEP:%.*]] = getelementptr i8, ptr [[PTR_IV_2_LCSSA]], i64 [[IV_3]] | ||
; CHECK-NEXT: [[TMP6:%.*]] = load i8, ptr [[GEP]], align 1 | ||
; CHECK-NEXT: [[EC:%.*]] = icmp eq i8 [[TMP6]], 0 | ||
; CHECK-NEXT: [[IV_3_NEXT]] = add i64 [[IV_3]], 1 | ||
; CHECK-NEXT: br i1 true, label %[[EXIT:.*]], label %[[LOOP_3]] | ||
; CHECK: [[EXIT]]: | ||
; CHECK-NEXT: ret void | ||
; | ||
entry: | ||
br label %loop.1.header | ||
|
||
loop.1.header: | ||
%ptr.iv.1 = phi ptr [ %start, %entry ], [ %ptr.iv.1.next, %loop.1.latch ] | ||
%c = icmp ule i8 %x, 1 | ||
br i1 %c, label %loop.1.latch, label %middle | ||
|
||
loop.1.latch: | ||
%ptr.iv.1.next = getelementptr i8, ptr %ptr.iv.1, i64 1 | ||
br label %loop.1.header | ||
|
||
middle: | ||
%cmp = icmp eq i8 %x, 0 | ||
%cmp.ext = zext i1 %cmp to i64 | ||
%gep.start = getelementptr i8, ptr %ptr.iv.1, i64 %cmp.ext | ||
br label %loop.2.header | ||
|
||
loop.2.header: | ||
%ptr.iv.2 = phi ptr [ %gep.start, %middle ], [ %ptr.iv.2.next, %loop.2.latch ] | ||
switch i8 %x, label %loop.2.latch [ | ||
i8 1, label %loop.3 | ||
i8 4, label %loop.3 | ||
] | ||
|
||
loop.2.latch: | ||
%ptr.iv.2.next = getelementptr i8, ptr %ptr.iv.2, i64 1 | ||
br label %loop.2.header | ||
|
||
loop.3: | ||
%iv.3 = phi i64 [ 1, %loop.2.header ], [ 1, %loop.2.header ], [ %iv.3.next, %loop.3 ] | ||
%gep = getelementptr i8, ptr %ptr.iv.2, i64 %iv.3 | ||
%1 = load i8, ptr %gep, align 1 | ||
%ec = icmp eq i8 %1, 0 | ||
%iv.3.next = add i64 %iv.3, 1 | ||
br i1 %ec, label %exit, label %loop.3 | ||
|
||
exit: | ||
ret void | ||
} |
Uh oh!
There was an error while loading. Please reload this page.