diff options
Diffstat (limited to 'llvm/unittests/Analysis')
-rw-r--r-- | llvm/unittests/Analysis/ScalarEvolutionTest.cpp | 838 |
1 files changed, 1 insertions, 837 deletions
diff --git a/llvm/unittests/Analysis/ScalarEvolutionTest.cpp b/llvm/unittests/Analysis/ScalarEvolutionTest.cpp index c42ebf656dd..b30eb014636 100644 --- a/llvm/unittests/Analysis/ScalarEvolutionTest.cpp +++ b/llvm/unittests/Analysis/ScalarEvolutionTest.cpp @@ -9,8 +9,8 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/Analysis/AssumptionCache.h" #include "llvm/Analysis/LoopInfo.h" -#include "llvm/Analysis/ScalarEvolutionExpander.h" #include "llvm/Analysis/ScalarEvolutionExpressions.h" +#include "llvm/Analysis/ScalarEvolutionNormalization.h" #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/AsmParser/Parser.h" #include "llvm/IR/Constants.h" @@ -141,72 +141,6 @@ TEST_F(ScalarEvolutionsTest, SimplifiedPHI) { EXPECT_EQ(S1, S2); } -TEST_F(ScalarEvolutionsTest, ExpandPtrTypeSCEV) { - // It is to test the fix for PR30213. It exercises the branch in scev - // expansion when the value in ValueOffsetPair is a ptr and the offset - // is not divisible by the elem type size of value. - auto *I8Ty = Type::getInt8Ty(Context); - auto *I8PtrTy = Type::getInt8PtrTy(Context); - auto *I32Ty = Type::getInt32Ty(Context); - auto *I32PtrTy = Type::getInt32PtrTy(Context); - FunctionType *FTy = - FunctionType::get(Type::getVoidTy(Context), std::vector<Type *>(), false); - Function *F = Function::Create(FTy, Function::ExternalLinkage, "f", M); - BasicBlock *EntryBB = BasicBlock::Create(Context, "entry", F); - BasicBlock *LoopBB = BasicBlock::Create(Context, "loop", F); - BasicBlock *ExitBB = BasicBlock::Create(Context, "exit", F); - BranchInst::Create(LoopBB, EntryBB); - ReturnInst::Create(Context, nullptr, ExitBB); - - // loop: ; preds = %loop, %entry - // %alloca = alloca i32 - // %gep0 = getelementptr i32, i32* %alloca, i32 1 - // %bitcast1 = bitcast i32* %gep0 to i8* - // %gep1 = getelementptr i8, i8* %bitcast1, i32 1 - // %gep2 = getelementptr i8, i8* undef, i32 1 - // %cmp = icmp ult i8* undef, %bitcast1 - // %select = select i1 %cmp, i8* %gep1, i8* %gep2 - // %bitcast2 = bitcast i8* %select to i32* - // br i1 undef, label %loop, label %exit - - const DataLayout &DL = F->getParent()->getDataLayout(); - BranchInst *Br = BranchInst::Create( - LoopBB, ExitBB, UndefValue::get(Type::getInt1Ty(Context)), LoopBB); - AllocaInst *Alloca = new AllocaInst(I32Ty, DL.getAllocaAddrSpace(), - "alloca", Br); - ConstantInt *Ci32 = ConstantInt::get(Context, APInt(32, 1)); - GetElementPtrInst *Gep0 = - GetElementPtrInst::Create(I32Ty, Alloca, Ci32, "gep0", Br); - CastInst *CastA = - CastInst::CreateBitOrPointerCast(Gep0, I8PtrTy, "bitcast1", Br); - GetElementPtrInst *Gep1 = - GetElementPtrInst::Create(I8Ty, CastA, Ci32, "gep1", Br); - GetElementPtrInst *Gep2 = GetElementPtrInst::Create( - I8Ty, UndefValue::get(I8PtrTy), Ci32, "gep2", Br); - CmpInst *Cmp = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_ULT, - UndefValue::get(I8PtrTy), CastA, "cmp", Br); - SelectInst *Sel = SelectInst::Create(Cmp, Gep1, Gep2, "select", Br); - CastInst *CastB = - CastInst::CreateBitOrPointerCast(Sel, I32PtrTy, "bitcast2", Br); - - ScalarEvolution SE = buildSE(*F); - auto *S = SE.getSCEV(CastB); - SCEVExpander Exp(SE, M.getDataLayout(), "expander"); - Value *V = - Exp.expandCodeFor(cast<SCEVAddExpr>(S)->getOperand(1), nullptr, Br); - - // Expect the expansion code contains: - // %0 = bitcast i32* %bitcast2 to i8* - // %uglygep = getelementptr i8, i8* %0, i64 -1 - // %1 = bitcast i8* %uglygep to i32* - EXPECT_TRUE(isa<BitCastInst>(V)); - Instruction *Gep = cast<Instruction>(V)->getPrevNode(); - EXPECT_TRUE(isa<GetElementPtrInst>(Gep)); - EXPECT_TRUE(isa<ConstantInt>(Gep->getOperand(1))); - EXPECT_EQ(cast<ConstantInt>(Gep->getOperand(1))->getSExtValue(), -1); - EXPECT_TRUE(isa<BitCastInst>(Gep->getPrevNode())); -} - static Instruction *getInstructionByName(Function &F, StringRef Name) { for (auto &I : instructions(F)) if (I.getName() == Name) @@ -719,83 +653,6 @@ TEST_F(ScalarEvolutionsTest, SCEVZeroExtendExpr) { SE.getZeroExtendExpr(S, I128Ty); } -// Make sure that SCEV doesn't introduce illegal ptrtoint/inttoptr instructions -TEST_F(ScalarEvolutionsTest, SCEVZeroExtendExprNonIntegral) { - /* - * Create the following code: - * func(i64 addrspace(10)* %arg) - * top: - * br label %L.ph - * L.ph: - * br label %L - * L: - * %phi = phi i64 [i64 0, %L.ph], [ %add, %L2 ] - * %add = add i64 %phi2, 1 - * br i1 undef, label %post, label %L2 - * post: - * %gepbase = getelementptr i64 addrspace(10)* %arg, i64 1 - * #= %gep = getelementptr i64 addrspace(10)* %gepbase, i64 %add =# - * ret void - * - * We will create the appropriate SCEV expression for %gep and expand it, - * then check that no inttoptr/ptrtoint instructions got inserted. - */ - - // Create a module with non-integral pointers in it's datalayout - Module NIM("nonintegral", Context); - std::string DataLayout = M.getDataLayoutStr(); - if (!DataLayout.empty()) - DataLayout += "-"; - DataLayout += "ni:10"; - NIM.setDataLayout(DataLayout); - - Type *T_int1 = Type::getInt1Ty(Context); - Type *T_int64 = Type::getInt64Ty(Context); - Type *T_pint64 = T_int64->getPointerTo(10); - - FunctionType *FTy = - FunctionType::get(Type::getVoidTy(Context), {T_pint64}, false); - Function *F = Function::Create(FTy, Function::ExternalLinkage, "foo", NIM); - - Argument *Arg = &*F->arg_begin(); - - BasicBlock *Top = BasicBlock::Create(Context, "top", F); - BasicBlock *LPh = BasicBlock::Create(Context, "L.ph", F); - BasicBlock *L = BasicBlock::Create(Context, "L", F); - BasicBlock *Post = BasicBlock::Create(Context, "post", F); - - IRBuilder<> Builder(Top); - Builder.CreateBr(LPh); - - Builder.SetInsertPoint(LPh); - Builder.CreateBr(L); - - Builder.SetInsertPoint(L); - PHINode *Phi = Builder.CreatePHI(T_int64, 2); - Value *Add = Builder.CreateAdd(Phi, ConstantInt::get(T_int64, 1), "add"); - Builder.CreateCondBr(UndefValue::get(T_int1), L, Post); - Phi->addIncoming(ConstantInt::get(T_int64, 0), LPh); - Phi->addIncoming(Add, L); - - Builder.SetInsertPoint(Post); - Value *GepBase = - Builder.CreateGEP(T_int64, Arg, ConstantInt::get(T_int64, 1)); - Instruction *Ret = Builder.CreateRetVoid(); - - ScalarEvolution SE = buildSE(*F); - auto *AddRec = - SE.getAddRecExpr(SE.getUnknown(GepBase), SE.getConstant(T_int64, 1), - LI->getLoopFor(L), SCEV::FlagNUW); - - SCEVExpander Exp(SE, NIM.getDataLayout(), "expander"); - Exp.disableCanonicalMode(); - Exp.expandCodeFor(AddRec, T_pint64, Ret); - - // Make sure none of the instructions inserted were inttoptr/ptrtoint. - // The verifier will check this. - EXPECT_FALSE(verifyFunction(*F, &errs())); -} - // Make sure that SCEV invalidates exit limits after invalidating the values it // depends on when we forget a loop. TEST_F(ScalarEvolutionsTest, SCEVExitLimitForgetLoop) { @@ -1122,283 +979,6 @@ TEST_F(ScalarEvolutionsTest, SCEVFoldSumOfTruncs) { EXPECT_EQ(Expr, ZeroConst); } -// Check that we can correctly identify the points at which the SCEV of the -// AddRec can be expanded. -TEST_F(ScalarEvolutionsTest, SCEVExpanderIsSafeToExpandAt) { - /* - * Create the following code: - * func(i64 addrspace(10)* %arg) - * top: - * br label %L.ph - * L.ph: - * br label %L - * L: - * %phi = phi i64 [i64 0, %L.ph], [ %add, %L2 ] - * %add = add i64 %phi2, 1 - * %cond = icmp slt i64 %add, 1000; then becomes 2000. - * br i1 %cond, label %post, label %L2 - * post: - * ret void - * - */ - - // Create a module with non-integral pointers in it's datalayout - Module NIM("nonintegral", Context); - std::string DataLayout = M.getDataLayoutStr(); - if (!DataLayout.empty()) - DataLayout += "-"; - DataLayout += "ni:10"; - NIM.setDataLayout(DataLayout); - - Type *T_int64 = Type::getInt64Ty(Context); - Type *T_pint64 = T_int64->getPointerTo(10); - - FunctionType *FTy = - FunctionType::get(Type::getVoidTy(Context), {T_pint64}, false); - Function *F = Function::Create(FTy, Function::ExternalLinkage, "foo", NIM); - - BasicBlock *Top = BasicBlock::Create(Context, "top", F); - BasicBlock *LPh = BasicBlock::Create(Context, "L.ph", F); - BasicBlock *L = BasicBlock::Create(Context, "L", F); - BasicBlock *Post = BasicBlock::Create(Context, "post", F); - - IRBuilder<> Builder(Top); - Builder.CreateBr(LPh); - - Builder.SetInsertPoint(LPh); - Builder.CreateBr(L); - - Builder.SetInsertPoint(L); - PHINode *Phi = Builder.CreatePHI(T_int64, 2); - auto *Add = cast<Instruction>( - Builder.CreateAdd(Phi, ConstantInt::get(T_int64, 1), "add")); - auto *Limit = ConstantInt::get(T_int64, 1000); - auto *Cond = cast<Instruction>( - Builder.CreateICmp(ICmpInst::ICMP_SLT, Add, Limit, "cond")); - Builder.CreateCondBr(Cond, L, Post); - Phi->addIncoming(ConstantInt::get(T_int64, 0), LPh); - Phi->addIncoming(Add, L); - - Builder.SetInsertPoint(Post); - Builder.CreateRetVoid(); - - ScalarEvolution SE = buildSE(*F); - const SCEV *S = SE.getSCEV(Phi); - EXPECT_TRUE(isa<SCEVAddRecExpr>(S)); - const SCEVAddRecExpr *AR = cast<SCEVAddRecExpr>(S); - EXPECT_TRUE(AR->isAffine()); - EXPECT_FALSE(isSafeToExpandAt(AR, Top->getTerminator(), SE)); - EXPECT_FALSE(isSafeToExpandAt(AR, LPh->getTerminator(), SE)); - EXPECT_TRUE(isSafeToExpandAt(AR, L->getTerminator(), SE)); - EXPECT_TRUE(isSafeToExpandAt(AR, Post->getTerminator(), SE)); -} - -// Check that SCEV expander does not use the nuw instruction -// for expansion. -TEST_F(ScalarEvolutionsTest, SCEVExpanderNUW) { - /* - * Create the following code: - * func(i64 %a) - * entry: - * br false, label %exit, label %body - * body: - * %s1 = add i64 %a, -1 - * br label %exit - * exit: - * %s = add nuw i64 %a, -1 - * ret %s - */ - - // Create a module. - Module M("SCEVExpanderNUW", Context); - - Type *T_int64 = Type::getInt64Ty(Context); - - FunctionType *FTy = - FunctionType::get(Type::getVoidTy(Context), { T_int64 }, false); - Function *F = Function::Create(FTy, Function::ExternalLinkage, "func", M); - Argument *Arg = &*F->arg_begin(); - ConstantInt *C = ConstantInt::get(Context, APInt(64, -1)); - - BasicBlock *Entry = BasicBlock::Create(Context, "entry", F); - BasicBlock *Body = BasicBlock::Create(Context, "body", F); - BasicBlock *Exit = BasicBlock::Create(Context, "exit", F); - - IRBuilder<> Builder(Entry); - ConstantInt *Cond = ConstantInt::get(Context, APInt(1, 0)); - Builder.CreateCondBr(Cond, Exit, Body); - - Builder.SetInsertPoint(Body); - auto *S1 = cast<Instruction>(Builder.CreateAdd(Arg, C, "add")); - Builder.CreateBr(Exit); - - Builder.SetInsertPoint(Exit); - auto *S2 = cast<Instruction>(Builder.CreateAdd(Arg, C, "add")); - S2->setHasNoUnsignedWrap(true); - auto *R = cast<Instruction>(Builder.CreateRetVoid()); - - ScalarEvolution SE = buildSE(*F); - const SCEV *S = SE.getSCEV(S1); - EXPECT_TRUE(isa<SCEVAddExpr>(S)); - SCEVExpander Exp(SE, M.getDataLayout(), "expander"); - auto *I = cast<Instruction>(Exp.expandCodeFor(S, nullptr, R)); - EXPECT_FALSE(I->hasNoUnsignedWrap()); -} - -// Check that SCEV expander does not use the nsw instruction -// for expansion. -TEST_F(ScalarEvolutionsTest, SCEVExpanderNSW) { - /* - * Create the following code: - * func(i64 %a) - * entry: - * br false, label %exit, label %body - * body: - * %s1 = add i64 %a, -1 - * br label %exit - * exit: - * %s = add nsw i64 %a, -1 - * ret %s - */ - - // Create a module. - Module M("SCEVExpanderNSW", Context); - - Type *T_int64 = Type::getInt64Ty(Context); - - FunctionType *FTy = - FunctionType::get(Type::getVoidTy(Context), { T_int64 }, false); - Function *F = Function::Create(FTy, Function::ExternalLinkage, "func", M); - Argument *Arg = &*F->arg_begin(); - ConstantInt *C = ConstantInt::get(Context, APInt(64, -1)); - - BasicBlock *Entry = BasicBlock::Create(Context, "entry", F); - BasicBlock *Body = BasicBlock::Create(Context, "body", F); - BasicBlock *Exit = BasicBlock::Create(Context, "exit", F); - - IRBuilder<> Builder(Entry); - ConstantInt *Cond = ConstantInt::get(Context, APInt(1, 0)); - Builder.CreateCondBr(Cond, Exit, Body); - - Builder.SetInsertPoint(Body); - auto *S1 = cast<Instruction>(Builder.CreateAdd(Arg, C, "add")); - Builder.CreateBr(Exit); - - Builder.SetInsertPoint(Exit); - auto *S2 = cast<Instruction>(Builder.CreateAdd(Arg, C, "add")); - S2->setHasNoSignedWrap(true); - auto *R = cast<Instruction>(Builder.CreateRetVoid()); - - ScalarEvolution SE = buildSE(*F); - const SCEV *S = SE.getSCEV(S1); - EXPECT_TRUE(isa<SCEVAddExpr>(S)); - SCEVExpander Exp(SE, M.getDataLayout(), "expander"); - auto *I = cast<Instruction>(Exp.expandCodeFor(S, nullptr, R)); - EXPECT_FALSE(I->hasNoSignedWrap()); -} - -// Check that SCEV does not save the SCEV -> V -// mapping of SCEV differ from V in NUW flag. -TEST_F(ScalarEvolutionsTest, SCEVCacheNUW) { - /* - * Create the following code: - * func(i64 %a) - * entry: - * %s1 = add i64 %a, -1 - * %s2 = add nuw i64 %a, -1 - * br label %exit - * exit: - * ret %s - */ - - // Create a module. - Module M("SCEVCacheNUW", Context); - - Type *T_int64 = Type::getInt64Ty(Context); - - FunctionType *FTy = - FunctionType::get(Type::getVoidTy(Context), { T_int64 }, false); - Function *F = Function::Create(FTy, Function::ExternalLinkage, "func", M); - Argument *Arg = &*F->arg_begin(); - ConstantInt *C = ConstantInt::get(Context, APInt(64, -1)); - - BasicBlock *Entry = BasicBlock::Create(Context, "entry", F); - BasicBlock *Exit = BasicBlock::Create(Context, "exit", F); - - IRBuilder<> Builder(Entry); - auto *S1 = cast<Instruction>(Builder.CreateAdd(Arg, C, "add")); - auto *S2 = cast<Instruction>(Builder.CreateAdd(Arg, C, "add")); - S2->setHasNoUnsignedWrap(true); - Builder.CreateBr(Exit); - - Builder.SetInsertPoint(Exit); - auto *R = cast<Instruction>(Builder.CreateRetVoid()); - - ScalarEvolution SE = buildSE(*F); - // Get S2 first to move it to cache. - const SCEV *SC2 = SE.getSCEV(S2); - EXPECT_TRUE(isa<SCEVAddExpr>(SC2)); - // Now get S1. - const SCEV *SC1 = SE.getSCEV(S1); - EXPECT_TRUE(isa<SCEVAddExpr>(SC1)); - // Expand for S1, it should use S1 not S2 in spite S2 - // first in the cache. - SCEVExpander Exp(SE, M.getDataLayout(), "expander"); - auto *I = cast<Instruction>(Exp.expandCodeFor(SC1, nullptr, R)); - EXPECT_FALSE(I->hasNoUnsignedWrap()); -} - -// Check that SCEV does not save the SCEV -> V -// mapping of SCEV differ from V in NSW flag. -TEST_F(ScalarEvolutionsTest, SCEVCacheNSW) { - /* - * Create the following code: - * func(i64 %a) - * entry: - * %s1 = add i64 %a, -1 - * %s2 = add nsw i64 %a, -1 - * br label %exit - * exit: - * ret %s - */ - - // Create a module. - Module M("SCEVCacheNUW", Context); - - Type *T_int64 = Type::getInt64Ty(Context); - - FunctionType *FTy = - FunctionType::get(Type::getVoidTy(Context), { T_int64 }, false); - Function *F = Function::Create(FTy, Function::ExternalLinkage, "func", M); - Argument *Arg = &*F->arg_begin(); - ConstantInt *C = ConstantInt::get(Context, APInt(64, -1)); - - BasicBlock *Entry = BasicBlock::Create(Context, "entry", F); - BasicBlock *Exit = BasicBlock::Create(Context, "exit", F); - - IRBuilder<> Builder(Entry); - auto *S1 = cast<Instruction>(Builder.CreateAdd(Arg, C, "add")); - auto *S2 = cast<Instruction>(Builder.CreateAdd(Arg, C, "add")); - S2->setHasNoSignedWrap(true); - Builder.CreateBr(Exit); - - Builder.SetInsertPoint(Exit); - auto *R = cast<Instruction>(Builder.CreateRetVoid()); - - ScalarEvolution SE = buildSE(*F); - // Get S2 first to move it to cache. - const SCEV *SC2 = SE.getSCEV(S2); - EXPECT_TRUE(isa<SCEVAddExpr>(SC2)); - // Now get S1. - const SCEV *SC1 = SE.getSCEV(S1); - EXPECT_TRUE(isa<SCEVAddExpr>(SC1)); - // Expand for S1, it should use S1 not S2 in spite S2 - // first in the cache. - SCEVExpander Exp(SE, M.getDataLayout(), "expander"); - auto *I = cast<Instruction>(Exp.expandCodeFor(SC1, nullptr, R)); - EXPECT_FALSE(I->hasNoSignedWrap()); -} - // Check logic of SCEV expression size computation. TEST_F(ScalarEvolutionsTest, SCEVComputeExpressionSize) { /* @@ -1449,240 +1029,6 @@ TEST_F(ScalarEvolutionsTest, SCEVComputeExpressionSize) { EXPECT_EQ(S2S->getExpressionSize(), 5u); } -TEST_F(ScalarEvolutionsTest, SCEVExpandInsertCanonicalIV) { - LLVMContext C; - SMDiagnostic Err; - - // Expand the addrec produced by GetAddRec into a loop without a canonical IV. - // SCEVExpander will insert one. - auto TestNoCanonicalIV = [&]( - std::function<const SCEV *(ScalarEvolution & SE, Loop * L)> GetAddRec) { - std::unique_ptr<Module> M = - parseAssemblyString("define i32 @test(i32 %limit) { " - "entry: " - " br label %loop " - "loop: " - " %i = phi i32 [ 1, %entry ], [ %i.inc, %loop ] " - " %i.inc = add nsw i32 %i, 1 " - " %cont = icmp slt i32 %i.inc, %limit " - " br i1 %cont, label %loop, label %exit " - "exit: " - " ret i32 %i.inc " - "}", - Err, C); - - assert(M && "Could not parse module?"); - assert(!verifyModule(*M) && "Must have been well formed!"); - - runWithSE(*M, "test", [&](Function &F, LoopInfo &LI, ScalarEvolution &SE) { - auto &I = GetInstByName(F, "i"); - auto *Loop = LI.getLoopFor(I.getParent()); - EXPECT_FALSE(Loop->getCanonicalInductionVariable()); - - auto *AR = GetAddRec(SE, Loop); - unsigned ExpectedCanonicalIVWidth = SE.getTypeSizeInBits(AR->getType()); - - SCEVExpander Exp(SE, M->getDataLayout(), "expander"); - auto *InsertAt = I.getNextNode(); - Exp.expandCodeFor(AR, nullptr, InsertAt); - PHINode *CanonicalIV = Loop->getCanonicalInductionVariable(); - unsigned CanonicalIVBitWidth = - cast<IntegerType>(CanonicalIV->getType())->getBitWidth(); - EXPECT_EQ(CanonicalIVBitWidth, ExpectedCanonicalIVWidth); - }); - }; - - // Expand the addrec produced by GetAddRec into a loop with a canonical IV - // which is narrower than addrec type. - // SCEVExpander will insert a canonical IV of a wider type to expand the - // addrec. - auto TestNarrowCanonicalIV = [&]( - std::function<const SCEV *(ScalarEvolution & SE, Loop * L)> GetAddRec) { - std::unique_ptr<Module> M = parseAssemblyString( - "define i32 @test(i32 %limit) { " - "entry: " - " br label %loop " - "loop: " - " %i = phi i32 [ 1, %entry ], [ %i.inc, %loop ] " - " %canonical.iv = phi i8 [ 0, %entry ], [ %canonical.iv.inc, %loop ] " - " %i.inc = add nsw i32 %i, 1 " - " %canonical.iv.inc = add i8 %canonical.iv, 1 " - " %cont = icmp slt i32 %i.inc, %limit " - " br i1 %cont, label %loop, label %exit " - "exit: " - " ret i32 %i.inc " - "}", - Err, C); - - assert(M && "Could not parse module?"); - assert(!verifyModule(*M) && "Must have been well formed!"); - - runWithSE(*M, "test", [&](Function &F, LoopInfo &LI, ScalarEvolution &SE) { - auto &I = GetInstByName(F, "i"); - - auto *LoopHeaderBB = I.getParent(); - auto *Loop = LI.getLoopFor(LoopHeaderBB); - PHINode *CanonicalIV = Loop->getCanonicalInductionVariable(); - EXPECT_EQ(CanonicalIV, &GetInstByName(F, "canonical.iv")); - - auto *AR = GetAddRec(SE, Loop); - - unsigned ExpectedCanonicalIVWidth = SE.getTypeSizeInBits(AR->getType()); - unsigned CanonicalIVBitWidth = - cast<IntegerType>(CanonicalIV->getType())->getBitWidth(); - EXPECT_LT(CanonicalIVBitWidth, ExpectedCanonicalIVWidth); - - SCEVExpander Exp(SE, M->getDataLayout(), "expander"); - auto *InsertAt = I.getNextNode(); - Exp.expandCodeFor(AR, nullptr, InsertAt); - - // Loop over all of the PHI nodes, looking for the new canonical indvar. - PHINode *NewCanonicalIV = nullptr; - for (BasicBlock::iterator i = LoopHeaderBB->begin(); isa<PHINode>(i); - ++i) { - PHINode *PN = cast<PHINode>(i); - if (PN == &I || PN == CanonicalIV) - continue; - // We expect that the only PHI added is the new canonical IV - EXPECT_FALSE(NewCanonicalIV); - NewCanonicalIV = PN; - } - - // Check that NewCanonicalIV is a canonical IV, i.e {0,+,1} - BasicBlock *Incoming = nullptr, *Backedge = nullptr; - EXPECT_TRUE(Loop->getIncomingAndBackEdge(Incoming, Backedge)); - auto *Start = NewCanonicalIV->getIncomingValueForBlock(Incoming); - EXPECT_TRUE(isa<ConstantInt>(Start)); - EXPECT_TRUE(dyn_cast<ConstantInt>(Start)->isZero()); - auto *Next = NewCanonicalIV->getIncomingValueForBlock(Backedge); - EXPECT_TRUE(isa<BinaryOperator>(Next)); - auto *NextBinOp = dyn_cast<BinaryOperator>(Next); - EXPECT_EQ(NextBinOp->getOpcode(), Instruction::Add); - EXPECT_EQ(NextBinOp->getOperand(0), NewCanonicalIV); - auto *Step = NextBinOp->getOperand(1); - EXPECT_TRUE(isa<ConstantInt>(Step)); - EXPECT_TRUE(dyn_cast<ConstantInt>(Step)->isOne()); - - unsigned NewCanonicalIVBitWidth = - cast<IntegerType>(NewCanonicalIV->getType())->getBitWidth(); - EXPECT_EQ(NewCanonicalIVBitWidth, ExpectedCanonicalIVWidth); - }); - }; - - // Expand the addrec produced by GetAddRec into a loop with a canonical IV - // of addrec width. - // To expand the addrec SCEVExpander should use the existing canonical IV. - auto TestMatchingCanonicalIV = [&]( - std::function<const SCEV *(ScalarEvolution & SE, Loop * L)> GetAddRec, - unsigned ARBitWidth) { - auto ARBitWidthTypeStr = "i" + std::to_string(ARBitWidth); - std::unique_ptr<Module> M = parseAssemblyString( - "define i32 @test(i32 %limit) { " - "entry: " - " br label %loop " - "loop: " - " %i = phi i32 [ 1, %entry ], [ %i.inc, %loop ] " - " %canonical.iv = phi " + ARBitWidthTypeStr + - " [ 0, %entry ], [ %canonical.iv.inc, %loop ] " - " %i.inc = add nsw i32 %i, 1 " - " %canonical.iv.inc = add " + ARBitWidthTypeStr + - " %canonical.iv, 1 " - " %cont = icmp slt i32 %i.inc, %limit " - " br i1 %cont, label %loop, label %exit " - "exit: " - " ret i32 %i.inc " - "}", - Err, C); - - assert(M && "Could not parse module?"); - assert(!verifyModule(*M) && "Must have been well formed!"); - - runWithSE(*M, "test", [&](Function &F, LoopInfo &LI, ScalarEvolution &SE) { - auto &I = GetInstByName(F, "i"); - auto &CanonicalIV = GetInstByName(F, "canonical.iv"); - - auto *LoopHeaderBB = I.getParent(); - auto *Loop = LI.getLoopFor(LoopHeaderBB); - EXPECT_EQ(&CanonicalIV, Loop->getCanonicalInductionVariable()); - unsigned CanonicalIVBitWidth = - cast<IntegerType>(CanonicalIV.getType())->getBitWidth(); - - auto *AR = GetAddRec(SE, Loop); - EXPECT_EQ(ARBitWidth, SE.getTypeSizeInBits(AR->getType())); - EXPECT_EQ(CanonicalIVBitWidth, ARBitWidth); - - SCEVExpander Exp(SE, M->getDataLayout(), "expander"); - auto *InsertAt = I.getNextNode(); - Exp.expandCodeFor(AR, nullptr, InsertAt); - - // Loop over all of the PHI nodes, looking if a new canonical indvar was - // introduced. - PHINode *NewCanonicalIV = nullptr; - for (BasicBlock::iterator i = LoopHeaderBB->begin(); isa<PHINode>(i); - ++i) { - PHINode *PN = cast<PHINode>(i); - if (PN == &I || PN == &CanonicalIV) - continue; - NewCanonicalIV = PN; - } - EXPECT_FALSE(NewCanonicalIV); - }); - }; - - unsigned ARBitWidth = 16; - Type *ARType = IntegerType::get(C, ARBitWidth); - - // Expand {5,+,1} - auto GetAR2 = [&](ScalarEvolution &SE, Loop *L) -> const SCEV * { - return SE.getAddRecExpr(SE.getConstant(APInt(ARBitWidth, 5)), - SE.getOne(ARType), L, SCEV::FlagAnyWrap); - }; - TestNoCanonicalIV(GetAR2); - TestNarrowCanonicalIV(GetAR2); - TestMatchingCanonicalIV(GetAR2, ARBitWidth); -} - -TEST_F(ScalarEvolutionsTest, SCEVExpanderShlNSW) { - - auto checkOneCase = [this](std::string &&str) { - LLVMContext C; - SMDiagnostic Err; - std::unique_ptr<Module> M = parseAssemblyString(str, Err, C); - - assert(M && "Could not parse module?"); - assert(!verifyModule(*M) && "Must have been well formed!"); - - Function *F = M->getFunction("f"); - ASSERT_NE(F, nullptr) << "Could not find function 'f'"; - - BasicBlock &Entry = F->getEntryBlock(); - LoadInst *Load = cast<LoadInst>(&Entry.front()); - BinaryOperator *And = cast<BinaryOperator>(*Load->user_begin()); - - ScalarEvolution SE = buildSE(*F); - const SCEV *AndSCEV = SE.getSCEV(And); - EXPECT_TRUE(isa<SCEVMulExpr>(AndSCEV)); - EXPECT_TRUE(cast<SCEVMulExpr>(AndSCEV)->hasNoSignedWrap()); - - SCEVExpander Exp(SE, M->getDataLayout(), "expander"); - auto *I = cast<Instruction>(Exp.expandCodeFor(AndSCEV, nullptr, And)); - EXPECT_EQ(I->getOpcode(), Instruction::Shl); - EXPECT_FALSE(I->hasNoSignedWrap()); - }; - - checkOneCase("define void @f(i16* %arrayidx) { " - " %1 = load i16, i16* %arrayidx " - " %2 = and i16 %1, -32768 " - " ret void " - "} "); - - checkOneCase("define void @f(i8* %arrayidx) { " - " %1 = load i8, i8* %arrayidx " - " %2 = and i8 %1, -128 " - " ret void " - "} "); -} - TEST_F(ScalarEvolutionsTest, SCEVComputeConstantDifference) { LLVMContext C; SMDiagnostic Err; @@ -1745,186 +1091,4 @@ TEST_F(ScalarEvolutionsTest, SCEVComputeConstantDifference) { }); } -// Test expansion of nested addrecs in CanonicalMode. -// Expanding nested addrecs in canonical mode requiers a canonical IV of a -// type wider than the type of the addrec itself. Currently, SCEVExpander -// just falls back to literal mode for nested addrecs. -TEST_F(ScalarEvolutionsTest, SCEVExpandNonAffineAddRec) { - LLVMContext C; - SMDiagnostic Err; - - // Expand the addrec produced by GetAddRec into a loop without a canonical IV. - auto TestNoCanonicalIV = [&](std::function<const SCEVAddRecExpr *( - ScalarEvolution & SE, Loop * L)> GetAddRec) { - std::unique_ptr<Module> M = - parseAssemblyString("define i32 @test(i32 %limit) { " - "entry: " - " br label %loop " - "loop: " - " %i = phi i32 [ 1, %entry ], [ %i.inc, %loop ] " - " %i.inc = add nsw i32 %i, 1 " - " %cont = icmp slt i32 %i.inc, %limit " - " br i1 %cont, label %loop, label %exit " - "exit: " - " ret i32 %i.inc " - "}", - Err, C); - - assert(M && "Could not parse module?"); - assert(!verifyModule(*M) && "Must have been well formed!"); - - runWithSE(*M, "test", [&](Function &F, LoopInfo &LI, ScalarEvolution &SE) { - auto &I = GetInstByName(F, "i"); - auto *Loop = LI.getLoopFor(I.getParent()); - EXPECT_FALSE(Loop->getCanonicalInductionVariable()); - - auto *AR = GetAddRec(SE, Loop); - EXPECT_FALSE(AR->isAffine()); - - SCEVExpander Exp(SE, M->getDataLayout(), "expander"); - auto *InsertAt = I.getNextNode(); - Value *V = Exp.expandCodeFor(AR, nullptr, InsertAt); - auto *ExpandedAR = SE.getSCEV(V); - // Check that the expansion happened literally. - EXPECT_EQ(AR, ExpandedAR); - }); - }; - - // Expand the addrec produced by GetAddRec into a loop with a canonical IV - // which is narrower than addrec type. - auto TestNarrowCanonicalIV = [&]( - std::function<const SCEVAddRecExpr *(ScalarEvolution & SE, Loop * L)> - GetAddRec) { - std::unique_ptr<Module> M = parseAssemblyString( - "define i32 @test(i32 %limit) { " - "entry: " - " br label %loop " - "loop: " - " %i = phi i32 [ 1, %entry ], [ %i.inc, %loop ] " - " %canonical.iv = phi i8 [ 0, %entry ], [ %canonical.iv.inc, %loop ] " - " %i.inc = add nsw i32 %i, 1 " - " %canonical.iv.inc = add i8 %canonical.iv, 1 " - " %cont = icmp slt i32 %i.inc, %limit " - " br i1 %cont, label %loop, label %exit " - "exit: " - " ret i32 %i.inc " - "}", - Err, C); - - assert(M && "Could not parse module?"); - assert(!verifyModule(*M) && "Must have been well formed!"); - - runWithSE(*M, "test", [&](Function &F, LoopInfo &LI, ScalarEvolution &SE) { - auto &I = GetInstByName(F, "i"); - - auto *LoopHeaderBB = I.getParent(); - auto *Loop = LI.getLoopFor(LoopHeaderBB); - PHINode *CanonicalIV = Loop->getCanonicalInductionVariable(); - EXPECT_EQ(CanonicalIV, &GetInstByName(F, "canonical.iv")); - - auto *AR = GetAddRec(SE, Loop); - EXPECT_FALSE(AR->isAffine()); - - unsigned ExpectedCanonicalIVWidth = SE.getTypeSizeInBits(AR->getType()); - unsigned CanonicalIVBitWidth = - cast<IntegerType>(CanonicalIV->getType())->getBitWidth(); - EXPECT_LT(CanonicalIVBitWidth, ExpectedCanonicalIVWidth); - - SCEVExpander Exp(SE, M->getDataLayout(), "expander"); - auto *InsertAt = I.getNextNode(); - Value *V = Exp.expandCodeFor(AR, nullptr, InsertAt); - auto *ExpandedAR = SE.getSCEV(V); - // Check that the expansion happened literally. - EXPECT_EQ(AR, ExpandedAR); - }); - }; - - // Expand the addrec produced by GetAddRec into a loop with a canonical IV - // of addrec width. - auto TestMatchingCanonicalIV = [&]( - std::function<const SCEVAddRecExpr *(ScalarEvolution & SE, Loop * L)> - GetAddRec, - unsigned ARBitWidth) { - auto ARBitWidthTypeStr = "i" + std::to_string(ARBitWidth); - std::unique_ptr<Module> M = parseAssemblyString( - "define i32 @test(i32 %limit) { " - "entry: " - " br label %loop " - "loop: " - " %i = phi i32 [ 1, %entry ], [ %i.inc, %loop ] " - " %canonical.iv = phi " + ARBitWidthTypeStr + - " [ 0, %entry ], [ %canonical.iv.inc, %loop ] " - " %i.inc = add nsw i32 %i, 1 " - " %canonical.iv.inc = add " + ARBitWidthTypeStr + - " %canonical.iv, 1 " - " %cont = icmp slt i32 %i.inc, %limit " - " br i1 %cont, label %loop, label %exit " - "exit: " - " ret i32 %i.inc " - "}", - Err, C); - - assert(M && "Could not parse module?"); - assert(!verifyModule(*M) && "Must have been well formed!"); - - runWithSE(*M, "test", [&](Function &F, LoopInfo &LI, ScalarEvolution &SE) { - auto &I = GetInstByName(F, "i"); - auto &CanonicalIV = GetInstByName(F, "canonical.iv"); - - auto *LoopHeaderBB = I.getParent(); - auto *Loop = LI.getLoopFor(LoopHeaderBB); - EXPECT_EQ(&CanonicalIV, Loop->getCanonicalInductionVariable()); - unsigned CanonicalIVBitWidth = - cast<IntegerType>(CanonicalIV.getType())->getBitWidth(); - - auto *AR = GetAddRec(SE, Loop); - EXPECT_FALSE(AR->isAffine()); - EXPECT_EQ(ARBitWidth, SE.getTypeSizeInBits(AR->getType())); - EXPECT_EQ(CanonicalIVBitWidth, ARBitWidth); - - SCEVExpander Exp(SE, M->getDataLayout(), "expander"); - auto *InsertAt = I.getNextNode(); - Value *V = Exp.expandCodeFor(AR, nullptr, InsertAt); - auto *ExpandedAR = SE.getSCEV(V); - // Check that the expansion happened literally. - EXPECT_EQ(AR, ExpandedAR); - }); - }; - - unsigned ARBitWidth = 16; - Type *ARType = IntegerType::get(C, ARBitWidth); - - // Expand {5,+,1,+,1} - auto GetAR3 = [&](ScalarEvolution &SE, Loop *L) -> const SCEVAddRecExpr * { - SmallVector<const SCEV *, 3> Ops = {SE.getConstant(APInt(ARBitWidth, 5)), - SE.getOne(ARType), SE.getOne(ARType)}; - return cast<SCEVAddRecExpr>(SE.getAddRecExpr(Ops, L, SCEV::FlagAnyWrap)); - }; - TestNoCanonicalIV(GetAR3); - TestNarrowCanonicalIV(GetAR3); - TestMatchingCanonicalIV(GetAR3, ARBitWidth); - - // Expand {5,+,1,+,1,+,1} - auto GetAR4 = [&](ScalarEvolution &SE, Loop *L) -> const SCEVAddRecExpr * { - SmallVector<const SCEV *, 4> Ops = {SE.getConstant(APInt(ARBitWidth, 5)), - SE.getOne(ARType), SE.getOne(ARType), - SE.getOne(ARType)}; - return cast<SCEVAddRecExpr>(SE.getAddRecExpr(Ops, L, SCEV::FlagAnyWrap)); - }; - TestNoCanonicalIV(GetAR4); - TestNarrowCanonicalIV(GetAR4); - TestMatchingCanonicalIV(GetAR4, ARBitWidth); - - // Expand {5,+,1,+,1,+,1,+,1} - auto GetAR5 = [&](ScalarEvolution &SE, Loop *L) -> const SCEVAddRecExpr * { - SmallVector<const SCEV *, 5> Ops = {SE.getConstant(APInt(ARBitWidth, 5)), - SE.getOne(ARType), SE.getOne(ARType), - SE.getOne(ARType), SE.getOne(ARType)}; - return cast<SCEVAddRecExpr>(SE.getAddRecExpr(Ops, L, SCEV::FlagAnyWrap)); - }; - TestNoCanonicalIV(GetAR5); - TestNarrowCanonicalIV(GetAR5); - TestMatchingCanonicalIV(GetAR5, ARBitWidth); -} - } // end namespace llvm |