1bcbd26bfSFlorian Hahn //=== ScalarEvolutionExpanderTest.cpp - ScalarEvolutionExpander unit tests ===// 2bcbd26bfSFlorian Hahn // 3bcbd26bfSFlorian Hahn // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4bcbd26bfSFlorian Hahn // See https://llvm.org/LICENSE.txt for license information. 5bcbd26bfSFlorian Hahn // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6bcbd26bfSFlorian Hahn // 7bcbd26bfSFlorian Hahn //===----------------------------------------------------------------------===// 8bcbd26bfSFlorian Hahn 9bcbd26bfSFlorian Hahn #include "llvm/Transforms/Utils/ScalarEvolutionExpander.h" 10bcbd26bfSFlorian Hahn #include "llvm/ADT/SmallVector.h" 11bcbd26bfSFlorian Hahn #include "llvm/Analysis/AssumptionCache.h" 12bcbd26bfSFlorian Hahn #include "llvm/Analysis/LoopInfo.h" 13bcbd26bfSFlorian Hahn #include "llvm/Analysis/ScalarEvolutionExpressions.h" 14bcbd26bfSFlorian Hahn #include "llvm/Analysis/TargetLibraryInfo.h" 15bcbd26bfSFlorian Hahn #include "llvm/AsmParser/Parser.h" 16bcbd26bfSFlorian Hahn #include "llvm/IR/Constants.h" 17bcbd26bfSFlorian Hahn #include "llvm/IR/Dominators.h" 18bcbd26bfSFlorian Hahn #include "llvm/IR/GlobalVariable.h" 19bcbd26bfSFlorian Hahn #include "llvm/IR/IRBuilder.h" 20bcbd26bfSFlorian Hahn #include "llvm/IR/InstIterator.h" 21bcbd26bfSFlorian Hahn #include "llvm/IR/LLVMContext.h" 22bcbd26bfSFlorian Hahn #include "llvm/IR/Module.h" 231d8f2e52SFlorian Hahn #include "llvm/IR/PatternMatch.h" 24bcbd26bfSFlorian Hahn #include "llvm/IR/Verifier.h" 25ba7a92c0SNico Weber #include "llvm/Support/SourceMgr.h" 26bcbd26bfSFlorian Hahn #include "gtest/gtest.h" 27bcbd26bfSFlorian Hahn 28bcbd26bfSFlorian Hahn namespace llvm { 29bcbd26bfSFlorian Hahn 301d8f2e52SFlorian Hahn using namespace PatternMatch; 311d8f2e52SFlorian Hahn 32bcbd26bfSFlorian Hahn // We use this fixture to ensure that we clean up ScalarEvolution before 33bcbd26bfSFlorian Hahn // deleting the PassManager. 34bcbd26bfSFlorian Hahn class ScalarEvolutionExpanderTest : public testing::Test { 35bcbd26bfSFlorian Hahn protected: 36bcbd26bfSFlorian Hahn LLVMContext Context; 37bcbd26bfSFlorian Hahn Module M; 38bcbd26bfSFlorian Hahn TargetLibraryInfoImpl TLII; 39bcbd26bfSFlorian Hahn TargetLibraryInfo TLI; 40bcbd26bfSFlorian Hahn 41bcbd26bfSFlorian Hahn std::unique_ptr<AssumptionCache> AC; 42bcbd26bfSFlorian Hahn std::unique_ptr<DominatorTree> DT; 43bcbd26bfSFlorian Hahn std::unique_ptr<LoopInfo> LI; 44bcbd26bfSFlorian Hahn 45bcbd26bfSFlorian Hahn ScalarEvolutionExpanderTest() : M("", Context), TLII(), TLI(TLII) {} 46bcbd26bfSFlorian Hahn 47bcbd26bfSFlorian Hahn ScalarEvolution buildSE(Function &F) { 48bcbd26bfSFlorian Hahn AC.reset(new AssumptionCache(F)); 49bcbd26bfSFlorian Hahn DT.reset(new DominatorTree(F)); 50bcbd26bfSFlorian Hahn LI.reset(new LoopInfo(*DT)); 51bcbd26bfSFlorian Hahn return ScalarEvolution(F, TLI, *AC, *DT, *LI); 52bcbd26bfSFlorian Hahn } 53bcbd26bfSFlorian Hahn 54bcbd26bfSFlorian Hahn void runWithSE( 55bcbd26bfSFlorian Hahn Module &M, StringRef FuncName, 56bcbd26bfSFlorian Hahn function_ref<void(Function &F, LoopInfo &LI, ScalarEvolution &SE)> Test) { 57bcbd26bfSFlorian Hahn auto *F = M.getFunction(FuncName); 58bcbd26bfSFlorian Hahn ASSERT_NE(F, nullptr) << "Could not find " << FuncName; 59bcbd26bfSFlorian Hahn ScalarEvolution SE = buildSE(*F); 60bcbd26bfSFlorian Hahn Test(*F, *LI, SE); 61bcbd26bfSFlorian Hahn } 62bcbd26bfSFlorian Hahn }; 63bcbd26bfSFlorian Hahn 64bcbd26bfSFlorian Hahn static Instruction &GetInstByName(Function &F, StringRef Name) { 65bcbd26bfSFlorian Hahn for (auto &I : instructions(F)) 66bcbd26bfSFlorian Hahn if (I.getName() == Name) 67bcbd26bfSFlorian Hahn return I; 68bcbd26bfSFlorian Hahn llvm_unreachable("Could not find instructions!"); 69bcbd26bfSFlorian Hahn } 70bcbd26bfSFlorian Hahn 71bcbd26bfSFlorian Hahn TEST_F(ScalarEvolutionExpanderTest, ExpandPtrTypeSCEV) { 72bcbd26bfSFlorian Hahn // It is to test the fix for PR30213. It exercises the branch in scev 73bcbd26bfSFlorian Hahn // expansion when the value in ValueOffsetPair is a ptr and the offset 74bcbd26bfSFlorian Hahn // is not divisible by the elem type size of value. 75bcbd26bfSFlorian Hahn auto *I8Ty = Type::getInt8Ty(Context); 76145aff6dSBjorn Pettersson auto *PtrTy = PointerType::get(Context, 0); 77bcbd26bfSFlorian Hahn auto *I32Ty = Type::getInt32Ty(Context); 78bcbd26bfSFlorian Hahn FunctionType *FTy = 79bcbd26bfSFlorian Hahn FunctionType::get(Type::getVoidTy(Context), std::vector<Type *>(), false); 80bcbd26bfSFlorian Hahn Function *F = Function::Create(FTy, Function::ExternalLinkage, "f", M); 81bcbd26bfSFlorian Hahn BasicBlock *EntryBB = BasicBlock::Create(Context, "entry", F); 82bcbd26bfSFlorian Hahn BasicBlock *LoopBB = BasicBlock::Create(Context, "loop", F); 83bcbd26bfSFlorian Hahn BasicBlock *ExitBB = BasicBlock::Create(Context, "exit", F); 84bcbd26bfSFlorian Hahn BranchInst::Create(LoopBB, EntryBB); 85bcbd26bfSFlorian Hahn ReturnInst::Create(Context, nullptr, ExitBB); 86bcbd26bfSFlorian Hahn 87bcbd26bfSFlorian Hahn // loop: ; preds = %loop, %entry 88bcbd26bfSFlorian Hahn // %alloca = alloca i32 89145aff6dSBjorn Pettersson // %gep0 = getelementptr i32, ptr %alloca, i32 1 90145aff6dSBjorn Pettersson // %gep1 = getelementptr i8, ptr %gep0, i32 1 91145aff6dSBjorn Pettersson // %gep2 = getelementptr i8, ptr undef, i32 1 92145aff6dSBjorn Pettersson // %cmp = icmp ult ptr undef, %gep0 93145aff6dSBjorn Pettersson // %select = select i1 %cmp, ptr %gep1, ptr %gep2 94bcbd26bfSFlorian Hahn // br i1 undef, label %loop, label %exit 95bcbd26bfSFlorian Hahn 969df71d76SNikita Popov const DataLayout &DL = F->getDataLayout(); 97bcbd26bfSFlorian Hahn BranchInst *Br = BranchInst::Create( 98*64b9753dSLee Wei LoopBB, ExitBB, PoisonValue::get(Type::getInt1Ty(Context)), LoopBB); 992b1122eaSJeremy Morse AllocaInst *Alloca = new AllocaInst(I32Ty, DL.getAllocaAddrSpace(), "alloca", 1002b1122eaSJeremy Morse Br->getIterator()); 101bcbd26bfSFlorian Hahn ConstantInt *Ci32 = ConstantInt::get(Context, APInt(32, 1)); 102145aff6dSBjorn Pettersson UndefValue *UndefPtr = UndefValue::get(PtrTy); 103bcbd26bfSFlorian Hahn GetElementPtrInst *Gep0 = 1042b1122eaSJeremy Morse GetElementPtrInst::Create(I32Ty, Alloca, Ci32, "gep0", Br->getIterator()); 105bcbd26bfSFlorian Hahn GetElementPtrInst *Gep1 = 106145aff6dSBjorn Pettersson GetElementPtrInst::Create(I8Ty, Gep0, Ci32, "gep1", Br->getIterator()); 107bcbd26bfSFlorian Hahn GetElementPtrInst *Gep2 = GetElementPtrInst::Create( 108145aff6dSBjorn Pettersson I8Ty, UndefPtr, Ci32, "gep2", Br->getIterator()); 109bcbd26bfSFlorian Hahn CmpInst *Cmp = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_ULT, 110145aff6dSBjorn Pettersson UndefPtr, Gep0, "cmp", Br->getIterator()); 111145aff6dSBjorn Pettersson SelectInst *Select = 1122b1122eaSJeremy Morse SelectInst::Create(Cmp, Gep1, Gep2, "select", Br->getIterator()); 113bcbd26bfSFlorian Hahn 114bcbd26bfSFlorian Hahn ScalarEvolution SE = buildSE(*F); 115145aff6dSBjorn Pettersson const SCEV *S = SE.getSCEV(Select); 1168a567e5fSEli Friedman EXPECT_TRUE(isa<SCEVUnknown>(S)); 117bcbd26bfSFlorian Hahn } 118bcbd26bfSFlorian Hahn 119bcbd26bfSFlorian Hahn // Make sure that SCEV doesn't introduce illegal ptrtoint/inttoptr instructions 120bcbd26bfSFlorian Hahn TEST_F(ScalarEvolutionExpanderTest, SCEVZeroExtendExprNonIntegral) { 121bcbd26bfSFlorian Hahn /* 122bcbd26bfSFlorian Hahn * Create the following code: 123bcbd26bfSFlorian Hahn * func(i64 addrspace(10)* %arg) 124bcbd26bfSFlorian Hahn * top: 125bcbd26bfSFlorian Hahn * br label %L.ph 126bcbd26bfSFlorian Hahn * L.ph: 1272d8d622cSNikita Popov * %gepbase = getelementptr i64 addrspace(10)* %arg, i64 1 128bcbd26bfSFlorian Hahn * br label %L 129bcbd26bfSFlorian Hahn * L: 130bcbd26bfSFlorian Hahn * %phi = phi i64 [i64 0, %L.ph], [ %add, %L2 ] 131bcbd26bfSFlorian Hahn * %add = add i64 %phi2, 1 132bcbd26bfSFlorian Hahn * br i1 undef, label %post, label %L2 133bcbd26bfSFlorian Hahn * post: 134bcbd26bfSFlorian Hahn * #= %gep = getelementptr i64 addrspace(10)* %gepbase, i64 %add =# 135bcbd26bfSFlorian Hahn * ret void 136bcbd26bfSFlorian Hahn * 137bcbd26bfSFlorian Hahn * We will create the appropriate SCEV expression for %gep and expand it, 138bcbd26bfSFlorian Hahn * then check that no inttoptr/ptrtoint instructions got inserted. 139bcbd26bfSFlorian Hahn */ 140bcbd26bfSFlorian Hahn 141bcbd26bfSFlorian Hahn // Create a module with non-integral pointers in it's datalayout 142bcbd26bfSFlorian Hahn Module NIM("nonintegral", Context); 143bcbd26bfSFlorian Hahn std::string DataLayout = M.getDataLayoutStr(); 144bcbd26bfSFlorian Hahn if (!DataLayout.empty()) 145bcbd26bfSFlorian Hahn DataLayout += "-"; 146bcbd26bfSFlorian Hahn DataLayout += "ni:10"; 147bcbd26bfSFlorian Hahn NIM.setDataLayout(DataLayout); 148bcbd26bfSFlorian Hahn 149bcbd26bfSFlorian Hahn Type *T_int1 = Type::getInt1Ty(Context); 150bcbd26bfSFlorian Hahn Type *T_int64 = Type::getInt64Ty(Context); 151e53b28c8SBjorn Pettersson Type *T_pint64 = PointerType::get(Context, 10); 152bcbd26bfSFlorian Hahn 153bcbd26bfSFlorian Hahn FunctionType *FTy = 154bcbd26bfSFlorian Hahn FunctionType::get(Type::getVoidTy(Context), {T_pint64}, false); 155bcbd26bfSFlorian Hahn Function *F = Function::Create(FTy, Function::ExternalLinkage, "foo", NIM); 156bcbd26bfSFlorian Hahn 157bcbd26bfSFlorian Hahn Argument *Arg = &*F->arg_begin(); 158bcbd26bfSFlorian Hahn 159bcbd26bfSFlorian Hahn BasicBlock *Top = BasicBlock::Create(Context, "top", F); 160bcbd26bfSFlorian Hahn BasicBlock *LPh = BasicBlock::Create(Context, "L.ph", F); 161bcbd26bfSFlorian Hahn BasicBlock *L = BasicBlock::Create(Context, "L", F); 162bcbd26bfSFlorian Hahn BasicBlock *Post = BasicBlock::Create(Context, "post", F); 163bcbd26bfSFlorian Hahn 164bcbd26bfSFlorian Hahn IRBuilder<> Builder(Top); 165bcbd26bfSFlorian Hahn Builder.CreateBr(LPh); 166bcbd26bfSFlorian Hahn 167bcbd26bfSFlorian Hahn Builder.SetInsertPoint(LPh); 1682d8d622cSNikita Popov Value *GepBase = 1692d8d622cSNikita Popov Builder.CreateGEP(T_int64, Arg, ConstantInt::get(T_int64, 1)); 170bcbd26bfSFlorian Hahn Builder.CreateBr(L); 171bcbd26bfSFlorian Hahn 172bcbd26bfSFlorian Hahn Builder.SetInsertPoint(L); 173bcbd26bfSFlorian Hahn PHINode *Phi = Builder.CreatePHI(T_int64, 2); 174bcbd26bfSFlorian Hahn Value *Add = Builder.CreateAdd(Phi, ConstantInt::get(T_int64, 1), "add"); 175*64b9753dSLee Wei Builder.CreateCondBr(PoisonValue::get(T_int1), L, Post); 176bcbd26bfSFlorian Hahn Phi->addIncoming(ConstantInt::get(T_int64, 0), LPh); 177bcbd26bfSFlorian Hahn Phi->addIncoming(Add, L); 178bcbd26bfSFlorian Hahn 179bcbd26bfSFlorian Hahn Builder.SetInsertPoint(Post); 180bcbd26bfSFlorian Hahn Instruction *Ret = Builder.CreateRetVoid(); 181bcbd26bfSFlorian Hahn 182bcbd26bfSFlorian Hahn ScalarEvolution SE = buildSE(*F); 183edf46f36SFlorian Hahn const SCEV *AddRec = 184bcbd26bfSFlorian Hahn SE.getAddRecExpr(SE.getUnknown(GepBase), SE.getConstant(T_int64, 1), 185bcbd26bfSFlorian Hahn LI->getLoopFor(L), SCEV::FlagNUW); 186bcbd26bfSFlorian Hahn 187bcbd26bfSFlorian Hahn SCEVExpander Exp(SE, NIM.getDataLayout(), "expander"); 188bcbd26bfSFlorian Hahn Exp.disableCanonicalMode(); 189bcbd26bfSFlorian Hahn Exp.expandCodeFor(AddRec, T_pint64, Ret); 190bcbd26bfSFlorian Hahn 191bcbd26bfSFlorian Hahn // Make sure none of the instructions inserted were inttoptr/ptrtoint. 192bcbd26bfSFlorian Hahn // The verifier will check this. 193bcbd26bfSFlorian Hahn EXPECT_FALSE(verifyFunction(*F, &errs())); 194bcbd26bfSFlorian Hahn } 195bcbd26bfSFlorian Hahn 196bcbd26bfSFlorian Hahn // Check that we can correctly identify the points at which the SCEV of the 197bcbd26bfSFlorian Hahn // AddRec can be expanded. 198bcbd26bfSFlorian Hahn TEST_F(ScalarEvolutionExpanderTest, SCEVExpanderIsSafeToExpandAt) { 199bcbd26bfSFlorian Hahn /* 200bcbd26bfSFlorian Hahn * Create the following code: 201bcbd26bfSFlorian Hahn * func(i64 addrspace(10)* %arg) 202bcbd26bfSFlorian Hahn * top: 203bcbd26bfSFlorian Hahn * br label %L.ph 204bcbd26bfSFlorian Hahn * L.ph: 205bcbd26bfSFlorian Hahn * br label %L 206bcbd26bfSFlorian Hahn * L: 207bcbd26bfSFlorian Hahn * %phi = phi i64 [i64 0, %L.ph], [ %add, %L2 ] 208bcbd26bfSFlorian Hahn * %add = add i64 %phi2, 1 209bcbd26bfSFlorian Hahn * %cond = icmp slt i64 %add, 1000; then becomes 2000. 210bcbd26bfSFlorian Hahn * br i1 %cond, label %post, label %L2 211bcbd26bfSFlorian Hahn * post: 212bcbd26bfSFlorian Hahn * ret void 213bcbd26bfSFlorian Hahn * 214bcbd26bfSFlorian Hahn */ 215bcbd26bfSFlorian Hahn 216bcbd26bfSFlorian Hahn // Create a module with non-integral pointers in it's datalayout 217bcbd26bfSFlorian Hahn Module NIM("nonintegral", Context); 218bcbd26bfSFlorian Hahn std::string DataLayout = M.getDataLayoutStr(); 219bcbd26bfSFlorian Hahn if (!DataLayout.empty()) 220bcbd26bfSFlorian Hahn DataLayout += "-"; 221bcbd26bfSFlorian Hahn DataLayout += "ni:10"; 222bcbd26bfSFlorian Hahn NIM.setDataLayout(DataLayout); 223bcbd26bfSFlorian Hahn 224bcbd26bfSFlorian Hahn Type *T_int64 = Type::getInt64Ty(Context); 225e53b28c8SBjorn Pettersson Type *T_pint64 = PointerType::get(Context, 10); 226bcbd26bfSFlorian Hahn 227bcbd26bfSFlorian Hahn FunctionType *FTy = 228bcbd26bfSFlorian Hahn FunctionType::get(Type::getVoidTy(Context), {T_pint64}, false); 229bcbd26bfSFlorian Hahn Function *F = Function::Create(FTy, Function::ExternalLinkage, "foo", NIM); 230bcbd26bfSFlorian Hahn 231bcbd26bfSFlorian Hahn BasicBlock *Top = BasicBlock::Create(Context, "top", F); 232bcbd26bfSFlorian Hahn BasicBlock *LPh = BasicBlock::Create(Context, "L.ph", F); 233bcbd26bfSFlorian Hahn BasicBlock *L = BasicBlock::Create(Context, "L", F); 234bcbd26bfSFlorian Hahn BasicBlock *Post = BasicBlock::Create(Context, "post", F); 235bcbd26bfSFlorian Hahn 236bcbd26bfSFlorian Hahn IRBuilder<> Builder(Top); 237bcbd26bfSFlorian Hahn Builder.CreateBr(LPh); 238bcbd26bfSFlorian Hahn 239bcbd26bfSFlorian Hahn Builder.SetInsertPoint(LPh); 240bcbd26bfSFlorian Hahn Builder.CreateBr(L); 241bcbd26bfSFlorian Hahn 242bcbd26bfSFlorian Hahn Builder.SetInsertPoint(L); 243bcbd26bfSFlorian Hahn PHINode *Phi = Builder.CreatePHI(T_int64, 2); 244bcbd26bfSFlorian Hahn auto *Add = cast<Instruction>( 245bcbd26bfSFlorian Hahn Builder.CreateAdd(Phi, ConstantInt::get(T_int64, 1), "add")); 246bcbd26bfSFlorian Hahn auto *Limit = ConstantInt::get(T_int64, 1000); 247bcbd26bfSFlorian Hahn auto *Cond = cast<Instruction>( 248bcbd26bfSFlorian Hahn Builder.CreateICmp(ICmpInst::ICMP_SLT, Add, Limit, "cond")); 249bcbd26bfSFlorian Hahn Builder.CreateCondBr(Cond, L, Post); 250bcbd26bfSFlorian Hahn Phi->addIncoming(ConstantInt::get(T_int64, 0), LPh); 251bcbd26bfSFlorian Hahn Phi->addIncoming(Add, L); 252bcbd26bfSFlorian Hahn 253bcbd26bfSFlorian Hahn Builder.SetInsertPoint(Post); 254f75564adSFlorian Hahn Instruction *Ret = Builder.CreateRetVoid(); 255bcbd26bfSFlorian Hahn 256bcbd26bfSFlorian Hahn ScalarEvolution SE = buildSE(*F); 257dcf4b733SNikita Popov SCEVExpander Exp(SE, M.getDataLayout(), "expander"); 258bcbd26bfSFlorian Hahn const SCEV *S = SE.getSCEV(Phi); 259bcbd26bfSFlorian Hahn EXPECT_TRUE(isa<SCEVAddRecExpr>(S)); 260bcbd26bfSFlorian Hahn const SCEVAddRecExpr *AR = cast<SCEVAddRecExpr>(S); 261bcbd26bfSFlorian Hahn EXPECT_TRUE(AR->isAffine()); 262dcf4b733SNikita Popov EXPECT_FALSE(Exp.isSafeToExpandAt(AR, Top->getTerminator())); 263dcf4b733SNikita Popov EXPECT_FALSE(Exp.isSafeToExpandAt(AR, LPh->getTerminator())); 264dcf4b733SNikita Popov EXPECT_TRUE(Exp.isSafeToExpandAt(AR, L->getTerminator())); 265dcf4b733SNikita Popov EXPECT_TRUE(Exp.isSafeToExpandAt(AR, Post->getTerminator())); 266f75564adSFlorian Hahn 267f75564adSFlorian Hahn EXPECT_TRUE(LI->getLoopFor(L)->isLCSSAForm(*DT)); 268f75564adSFlorian Hahn Exp.expandCodeFor(SE.getSCEV(Add), nullptr, Ret); 269f75564adSFlorian Hahn EXPECT_TRUE(LI->getLoopFor(L)->isLCSSAForm(*DT)); 270bcbd26bfSFlorian Hahn } 271bcbd26bfSFlorian Hahn 272bcbd26bfSFlorian Hahn // Check that SCEV expander does not use the nuw instruction 273bcbd26bfSFlorian Hahn // for expansion. 274bcbd26bfSFlorian Hahn TEST_F(ScalarEvolutionExpanderTest, SCEVExpanderNUW) { 275bcbd26bfSFlorian Hahn /* 276bcbd26bfSFlorian Hahn * Create the following code: 277bcbd26bfSFlorian Hahn * func(i64 %a) 278bcbd26bfSFlorian Hahn * entry: 279bcbd26bfSFlorian Hahn * br false, label %exit, label %body 280bcbd26bfSFlorian Hahn * body: 281bcbd26bfSFlorian Hahn * %s1 = add i64 %a, -1 282bcbd26bfSFlorian Hahn * br label %exit 283bcbd26bfSFlorian Hahn * exit: 284bcbd26bfSFlorian Hahn * %s = add nuw i64 %a, -1 285bcbd26bfSFlorian Hahn * ret %s 286bcbd26bfSFlorian Hahn */ 287bcbd26bfSFlorian Hahn 288bcbd26bfSFlorian Hahn // Create a module. 289bcbd26bfSFlorian Hahn Module M("SCEVExpanderNUW", Context); 290bcbd26bfSFlorian Hahn 291bcbd26bfSFlorian Hahn Type *T_int64 = Type::getInt64Ty(Context); 292bcbd26bfSFlorian Hahn 293bcbd26bfSFlorian Hahn FunctionType *FTy = 294bcbd26bfSFlorian Hahn FunctionType::get(Type::getVoidTy(Context), {T_int64}, false); 295bcbd26bfSFlorian Hahn Function *F = Function::Create(FTy, Function::ExternalLinkage, "func", M); 296bcbd26bfSFlorian Hahn Argument *Arg = &*F->arg_begin(); 297bcbd26bfSFlorian Hahn ConstantInt *C = ConstantInt::get(Context, APInt(64, -1)); 298bcbd26bfSFlorian Hahn 299bcbd26bfSFlorian Hahn BasicBlock *Entry = BasicBlock::Create(Context, "entry", F); 300bcbd26bfSFlorian Hahn BasicBlock *Body = BasicBlock::Create(Context, "body", F); 301bcbd26bfSFlorian Hahn BasicBlock *Exit = BasicBlock::Create(Context, "exit", F); 302bcbd26bfSFlorian Hahn 303bcbd26bfSFlorian Hahn IRBuilder<> Builder(Entry); 304bcbd26bfSFlorian Hahn ConstantInt *Cond = ConstantInt::get(Context, APInt(1, 0)); 305bcbd26bfSFlorian Hahn Builder.CreateCondBr(Cond, Exit, Body); 306bcbd26bfSFlorian Hahn 307bcbd26bfSFlorian Hahn Builder.SetInsertPoint(Body); 308bcbd26bfSFlorian Hahn auto *S1 = cast<Instruction>(Builder.CreateAdd(Arg, C, "add")); 309bcbd26bfSFlorian Hahn Builder.CreateBr(Exit); 310bcbd26bfSFlorian Hahn 311bcbd26bfSFlorian Hahn Builder.SetInsertPoint(Exit); 312bcbd26bfSFlorian Hahn auto *S2 = cast<Instruction>(Builder.CreateAdd(Arg, C, "add")); 313bcbd26bfSFlorian Hahn S2->setHasNoUnsignedWrap(true); 314bcbd26bfSFlorian Hahn auto *R = cast<Instruction>(Builder.CreateRetVoid()); 315bcbd26bfSFlorian Hahn 316bcbd26bfSFlorian Hahn ScalarEvolution SE = buildSE(*F); 317bcbd26bfSFlorian Hahn const SCEV *S = SE.getSCEV(S1); 318bcbd26bfSFlorian Hahn EXPECT_TRUE(isa<SCEVAddExpr>(S)); 319bcbd26bfSFlorian Hahn SCEVExpander Exp(SE, M.getDataLayout(), "expander"); 320bcbd26bfSFlorian Hahn auto *I = cast<Instruction>(Exp.expandCodeFor(S, nullptr, R)); 321bcbd26bfSFlorian Hahn EXPECT_FALSE(I->hasNoUnsignedWrap()); 322bcbd26bfSFlorian Hahn } 323bcbd26bfSFlorian Hahn 324bcbd26bfSFlorian Hahn // Check that SCEV expander does not use the nsw instruction 325bcbd26bfSFlorian Hahn // for expansion. 326bcbd26bfSFlorian Hahn TEST_F(ScalarEvolutionExpanderTest, SCEVExpanderNSW) { 327bcbd26bfSFlorian Hahn /* 328bcbd26bfSFlorian Hahn * Create the following code: 329bcbd26bfSFlorian Hahn * func(i64 %a) 330bcbd26bfSFlorian Hahn * entry: 331bcbd26bfSFlorian Hahn * br false, label %exit, label %body 332bcbd26bfSFlorian Hahn * body: 333bcbd26bfSFlorian Hahn * %s1 = add i64 %a, -1 334bcbd26bfSFlorian Hahn * br label %exit 335bcbd26bfSFlorian Hahn * exit: 336bcbd26bfSFlorian Hahn * %s = add nsw i64 %a, -1 337bcbd26bfSFlorian Hahn * ret %s 338bcbd26bfSFlorian Hahn */ 339bcbd26bfSFlorian Hahn 340bcbd26bfSFlorian Hahn // Create a module. 341bcbd26bfSFlorian Hahn Module M("SCEVExpanderNSW", Context); 342bcbd26bfSFlorian Hahn 343bcbd26bfSFlorian Hahn Type *T_int64 = Type::getInt64Ty(Context); 344bcbd26bfSFlorian Hahn 345bcbd26bfSFlorian Hahn FunctionType *FTy = 346bcbd26bfSFlorian Hahn FunctionType::get(Type::getVoidTy(Context), {T_int64}, false); 347bcbd26bfSFlorian Hahn Function *F = Function::Create(FTy, Function::ExternalLinkage, "func", M); 348bcbd26bfSFlorian Hahn Argument *Arg = &*F->arg_begin(); 349bcbd26bfSFlorian Hahn ConstantInt *C = ConstantInt::get(Context, APInt(64, -1)); 350bcbd26bfSFlorian Hahn 351bcbd26bfSFlorian Hahn BasicBlock *Entry = BasicBlock::Create(Context, "entry", F); 352bcbd26bfSFlorian Hahn BasicBlock *Body = BasicBlock::Create(Context, "body", F); 353bcbd26bfSFlorian Hahn BasicBlock *Exit = BasicBlock::Create(Context, "exit", F); 354bcbd26bfSFlorian Hahn 355bcbd26bfSFlorian Hahn IRBuilder<> Builder(Entry); 356bcbd26bfSFlorian Hahn ConstantInt *Cond = ConstantInt::get(Context, APInt(1, 0)); 357bcbd26bfSFlorian Hahn Builder.CreateCondBr(Cond, Exit, Body); 358bcbd26bfSFlorian Hahn 359bcbd26bfSFlorian Hahn Builder.SetInsertPoint(Body); 360bcbd26bfSFlorian Hahn auto *S1 = cast<Instruction>(Builder.CreateAdd(Arg, C, "add")); 361bcbd26bfSFlorian Hahn Builder.CreateBr(Exit); 362bcbd26bfSFlorian Hahn 363bcbd26bfSFlorian Hahn Builder.SetInsertPoint(Exit); 364bcbd26bfSFlorian Hahn auto *S2 = cast<Instruction>(Builder.CreateAdd(Arg, C, "add")); 365bcbd26bfSFlorian Hahn S2->setHasNoSignedWrap(true); 366bcbd26bfSFlorian Hahn auto *R = cast<Instruction>(Builder.CreateRetVoid()); 367bcbd26bfSFlorian Hahn 368bcbd26bfSFlorian Hahn ScalarEvolution SE = buildSE(*F); 369bcbd26bfSFlorian Hahn const SCEV *S = SE.getSCEV(S1); 370bcbd26bfSFlorian Hahn EXPECT_TRUE(isa<SCEVAddExpr>(S)); 371bcbd26bfSFlorian Hahn SCEVExpander Exp(SE, M.getDataLayout(), "expander"); 372bcbd26bfSFlorian Hahn auto *I = cast<Instruction>(Exp.expandCodeFor(S, nullptr, R)); 373bcbd26bfSFlorian Hahn EXPECT_FALSE(I->hasNoSignedWrap()); 374bcbd26bfSFlorian Hahn } 375bcbd26bfSFlorian Hahn 376bcbd26bfSFlorian Hahn // Check that SCEV does not save the SCEV -> V 377bcbd26bfSFlorian Hahn // mapping of SCEV differ from V in NUW flag. 378bcbd26bfSFlorian Hahn TEST_F(ScalarEvolutionExpanderTest, SCEVCacheNUW) { 379bcbd26bfSFlorian Hahn /* 380bcbd26bfSFlorian Hahn * Create the following code: 381bcbd26bfSFlorian Hahn * func(i64 %a) 382bcbd26bfSFlorian Hahn * entry: 383bcbd26bfSFlorian Hahn * %s1 = add i64 %a, -1 384bcbd26bfSFlorian Hahn * %s2 = add nuw i64 %a, -1 385bcbd26bfSFlorian Hahn * br label %exit 386bcbd26bfSFlorian Hahn * exit: 387bcbd26bfSFlorian Hahn * ret %s 388bcbd26bfSFlorian Hahn */ 389bcbd26bfSFlorian Hahn 390bcbd26bfSFlorian Hahn // Create a module. 391bcbd26bfSFlorian Hahn Module M("SCEVCacheNUW", Context); 392bcbd26bfSFlorian Hahn 393bcbd26bfSFlorian Hahn Type *T_int64 = Type::getInt64Ty(Context); 394bcbd26bfSFlorian Hahn 395bcbd26bfSFlorian Hahn FunctionType *FTy = 396bcbd26bfSFlorian Hahn FunctionType::get(Type::getVoidTy(Context), {T_int64}, false); 397bcbd26bfSFlorian Hahn Function *F = Function::Create(FTy, Function::ExternalLinkage, "func", M); 398bcbd26bfSFlorian Hahn Argument *Arg = &*F->arg_begin(); 399bcbd26bfSFlorian Hahn ConstantInt *C = ConstantInt::get(Context, APInt(64, -1)); 400bcbd26bfSFlorian Hahn 401bcbd26bfSFlorian Hahn BasicBlock *Entry = BasicBlock::Create(Context, "entry", F); 402bcbd26bfSFlorian Hahn BasicBlock *Exit = BasicBlock::Create(Context, "exit", F); 403bcbd26bfSFlorian Hahn 404bcbd26bfSFlorian Hahn IRBuilder<> Builder(Entry); 405bcbd26bfSFlorian Hahn auto *S1 = cast<Instruction>(Builder.CreateAdd(Arg, C, "add")); 406bcbd26bfSFlorian Hahn auto *S2 = cast<Instruction>(Builder.CreateAdd(Arg, C, "add")); 407bcbd26bfSFlorian Hahn S2->setHasNoUnsignedWrap(true); 408bcbd26bfSFlorian Hahn Builder.CreateBr(Exit); 409bcbd26bfSFlorian Hahn 410bcbd26bfSFlorian Hahn Builder.SetInsertPoint(Exit); 411bcbd26bfSFlorian Hahn auto *R = cast<Instruction>(Builder.CreateRetVoid()); 412bcbd26bfSFlorian Hahn 413bcbd26bfSFlorian Hahn ScalarEvolution SE = buildSE(*F); 414bcbd26bfSFlorian Hahn // Get S2 first to move it to cache. 415bcbd26bfSFlorian Hahn const SCEV *SC2 = SE.getSCEV(S2); 416bcbd26bfSFlorian Hahn EXPECT_TRUE(isa<SCEVAddExpr>(SC2)); 417bcbd26bfSFlorian Hahn // Now get S1. 418bcbd26bfSFlorian Hahn const SCEV *SC1 = SE.getSCEV(S1); 419bcbd26bfSFlorian Hahn EXPECT_TRUE(isa<SCEVAddExpr>(SC1)); 420bcbd26bfSFlorian Hahn // Expand for S1, it should use S1 not S2 in spite S2 421bcbd26bfSFlorian Hahn // first in the cache. 422bcbd26bfSFlorian Hahn SCEVExpander Exp(SE, M.getDataLayout(), "expander"); 423bcbd26bfSFlorian Hahn auto *I = cast<Instruction>(Exp.expandCodeFor(SC1, nullptr, R)); 424bcbd26bfSFlorian Hahn EXPECT_FALSE(I->hasNoUnsignedWrap()); 425bcbd26bfSFlorian Hahn } 426bcbd26bfSFlorian Hahn 427bcbd26bfSFlorian Hahn // Check that SCEV does not save the SCEV -> V 428bcbd26bfSFlorian Hahn // mapping of SCEV differ from V in NSW flag. 429bcbd26bfSFlorian Hahn TEST_F(ScalarEvolutionExpanderTest, SCEVCacheNSW) { 430bcbd26bfSFlorian Hahn /* 431bcbd26bfSFlorian Hahn * Create the following code: 432bcbd26bfSFlorian Hahn * func(i64 %a) 433bcbd26bfSFlorian Hahn * entry: 434bcbd26bfSFlorian Hahn * %s1 = add i64 %a, -1 435bcbd26bfSFlorian Hahn * %s2 = add nsw i64 %a, -1 436bcbd26bfSFlorian Hahn * br label %exit 437bcbd26bfSFlorian Hahn * exit: 438bcbd26bfSFlorian Hahn * ret %s 439bcbd26bfSFlorian Hahn */ 440bcbd26bfSFlorian Hahn 441bcbd26bfSFlorian Hahn // Create a module. 442bcbd26bfSFlorian Hahn Module M("SCEVCacheNUW", Context); 443bcbd26bfSFlorian Hahn 444bcbd26bfSFlorian Hahn Type *T_int64 = Type::getInt64Ty(Context); 445bcbd26bfSFlorian Hahn 446bcbd26bfSFlorian Hahn FunctionType *FTy = 447bcbd26bfSFlorian Hahn FunctionType::get(Type::getVoidTy(Context), {T_int64}, false); 448bcbd26bfSFlorian Hahn Function *F = Function::Create(FTy, Function::ExternalLinkage, "func", M); 449bcbd26bfSFlorian Hahn Argument *Arg = &*F->arg_begin(); 450bcbd26bfSFlorian Hahn ConstantInt *C = ConstantInt::get(Context, APInt(64, -1)); 451bcbd26bfSFlorian Hahn 452bcbd26bfSFlorian Hahn BasicBlock *Entry = BasicBlock::Create(Context, "entry", F); 453bcbd26bfSFlorian Hahn BasicBlock *Exit = BasicBlock::Create(Context, "exit", F); 454bcbd26bfSFlorian Hahn 455bcbd26bfSFlorian Hahn IRBuilder<> Builder(Entry); 456bcbd26bfSFlorian Hahn auto *S1 = cast<Instruction>(Builder.CreateAdd(Arg, C, "add")); 457bcbd26bfSFlorian Hahn auto *S2 = cast<Instruction>(Builder.CreateAdd(Arg, C, "add")); 458bcbd26bfSFlorian Hahn S2->setHasNoSignedWrap(true); 459bcbd26bfSFlorian Hahn Builder.CreateBr(Exit); 460bcbd26bfSFlorian Hahn 461bcbd26bfSFlorian Hahn Builder.SetInsertPoint(Exit); 462bcbd26bfSFlorian Hahn auto *R = cast<Instruction>(Builder.CreateRetVoid()); 463bcbd26bfSFlorian Hahn 464bcbd26bfSFlorian Hahn ScalarEvolution SE = buildSE(*F); 465bcbd26bfSFlorian Hahn // Get S2 first to move it to cache. 466bcbd26bfSFlorian Hahn const SCEV *SC2 = SE.getSCEV(S2); 467bcbd26bfSFlorian Hahn EXPECT_TRUE(isa<SCEVAddExpr>(SC2)); 468bcbd26bfSFlorian Hahn // Now get S1. 469bcbd26bfSFlorian Hahn const SCEV *SC1 = SE.getSCEV(S1); 470bcbd26bfSFlorian Hahn EXPECT_TRUE(isa<SCEVAddExpr>(SC1)); 471bcbd26bfSFlorian Hahn // Expand for S1, it should use S1 not S2 in spite S2 472bcbd26bfSFlorian Hahn // first in the cache. 473bcbd26bfSFlorian Hahn SCEVExpander Exp(SE, M.getDataLayout(), "expander"); 474bcbd26bfSFlorian Hahn auto *I = cast<Instruction>(Exp.expandCodeFor(SC1, nullptr, R)); 475bcbd26bfSFlorian Hahn EXPECT_FALSE(I->hasNoSignedWrap()); 476bcbd26bfSFlorian Hahn } 477bcbd26bfSFlorian Hahn 478bcbd26bfSFlorian Hahn TEST_F(ScalarEvolutionExpanderTest, SCEVExpandInsertCanonicalIV) { 479bcbd26bfSFlorian Hahn LLVMContext C; 480bcbd26bfSFlorian Hahn SMDiagnostic Err; 481bcbd26bfSFlorian Hahn 482bcbd26bfSFlorian Hahn // Expand the addrec produced by GetAddRec into a loop without a canonical IV. 483bcbd26bfSFlorian Hahn // SCEVExpander will insert one. 484bcbd26bfSFlorian Hahn auto TestNoCanonicalIV = 485bcbd26bfSFlorian Hahn [&](std::function<const SCEV *(ScalarEvolution & SE, Loop * L)> 486bcbd26bfSFlorian Hahn GetAddRec) { 487bcbd26bfSFlorian Hahn std::unique_ptr<Module> M = parseAssemblyString( 488bcbd26bfSFlorian Hahn "define i32 @test(i32 %limit) { " 489bcbd26bfSFlorian Hahn "entry: " 490bcbd26bfSFlorian Hahn " br label %loop " 491bcbd26bfSFlorian Hahn "loop: " 492bcbd26bfSFlorian Hahn " %i = phi i32 [ 1, %entry ], [ %i.inc, %loop ] " 493bcbd26bfSFlorian Hahn " %i.inc = add nsw i32 %i, 1 " 494bcbd26bfSFlorian Hahn " %cont = icmp slt i32 %i.inc, %limit " 495bcbd26bfSFlorian Hahn " br i1 %cont, label %loop, label %exit " 496bcbd26bfSFlorian Hahn "exit: " 497bcbd26bfSFlorian Hahn " ret i32 %i.inc " 498bcbd26bfSFlorian Hahn "}", 499bcbd26bfSFlorian Hahn Err, C); 500bcbd26bfSFlorian Hahn 501bcbd26bfSFlorian Hahn assert(M && "Could not parse module?"); 502bcbd26bfSFlorian Hahn assert(!verifyModule(*M) && "Must have been well formed!"); 503bcbd26bfSFlorian Hahn 504bcbd26bfSFlorian Hahn runWithSE( 505bcbd26bfSFlorian Hahn *M, "test", [&](Function &F, LoopInfo &LI, ScalarEvolution &SE) { 506bcbd26bfSFlorian Hahn auto &I = GetInstByName(F, "i"); 507bcbd26bfSFlorian Hahn auto *Loop = LI.getLoopFor(I.getParent()); 508bcbd26bfSFlorian Hahn EXPECT_FALSE(Loop->getCanonicalInductionVariable()); 509bcbd26bfSFlorian Hahn 510bcbd26bfSFlorian Hahn auto *AR = GetAddRec(SE, Loop); 511bcbd26bfSFlorian Hahn unsigned ExpectedCanonicalIVWidth = 512bcbd26bfSFlorian Hahn SE.getTypeSizeInBits(AR->getType()); 513bcbd26bfSFlorian Hahn 514bcbd26bfSFlorian Hahn SCEVExpander Exp(SE, M->getDataLayout(), "expander"); 515bcbd26bfSFlorian Hahn auto *InsertAt = I.getNextNode(); 516bcbd26bfSFlorian Hahn Exp.expandCodeFor(AR, nullptr, InsertAt); 517bcbd26bfSFlorian Hahn PHINode *CanonicalIV = Loop->getCanonicalInductionVariable(); 518bcbd26bfSFlorian Hahn unsigned CanonicalIVBitWidth = 519bcbd26bfSFlorian Hahn cast<IntegerType>(CanonicalIV->getType())->getBitWidth(); 520bcbd26bfSFlorian Hahn EXPECT_EQ(CanonicalIVBitWidth, ExpectedCanonicalIVWidth); 521bcbd26bfSFlorian Hahn }); 522bcbd26bfSFlorian Hahn }; 523bcbd26bfSFlorian Hahn 524bcbd26bfSFlorian Hahn // Expand the addrec produced by GetAddRec into a loop with a canonical IV 525bcbd26bfSFlorian Hahn // which is narrower than addrec type. 526bcbd26bfSFlorian Hahn // SCEVExpander will insert a canonical IV of a wider type to expand the 527bcbd26bfSFlorian Hahn // addrec. 528bcbd26bfSFlorian Hahn auto TestNarrowCanonicalIV = [&](std::function<const SCEV *( 529bcbd26bfSFlorian Hahn ScalarEvolution & SE, Loop * L)> 530bcbd26bfSFlorian Hahn GetAddRec) { 531bcbd26bfSFlorian Hahn std::unique_ptr<Module> M = parseAssemblyString( 532bcbd26bfSFlorian Hahn "define i32 @test(i32 %limit) { " 533bcbd26bfSFlorian Hahn "entry: " 534bcbd26bfSFlorian Hahn " br label %loop " 535bcbd26bfSFlorian Hahn "loop: " 536bcbd26bfSFlorian Hahn " %i = phi i32 [ 1, %entry ], [ %i.inc, %loop ] " 537bcbd26bfSFlorian Hahn " %canonical.iv = phi i8 [ 0, %entry ], [ %canonical.iv.inc, %loop ] " 538bcbd26bfSFlorian Hahn " %i.inc = add nsw i32 %i, 1 " 539bcbd26bfSFlorian Hahn " %canonical.iv.inc = add i8 %canonical.iv, 1 " 540bcbd26bfSFlorian Hahn " %cont = icmp slt i32 %i.inc, %limit " 541bcbd26bfSFlorian Hahn " br i1 %cont, label %loop, label %exit " 542bcbd26bfSFlorian Hahn "exit: " 543bcbd26bfSFlorian Hahn " ret i32 %i.inc " 544bcbd26bfSFlorian Hahn "}", 545bcbd26bfSFlorian Hahn Err, C); 546bcbd26bfSFlorian Hahn 547bcbd26bfSFlorian Hahn assert(M && "Could not parse module?"); 548bcbd26bfSFlorian Hahn assert(!verifyModule(*M) && "Must have been well formed!"); 549bcbd26bfSFlorian Hahn 550bcbd26bfSFlorian Hahn runWithSE(*M, "test", [&](Function &F, LoopInfo &LI, ScalarEvolution &SE) { 551bcbd26bfSFlorian Hahn auto &I = GetInstByName(F, "i"); 552bcbd26bfSFlorian Hahn 553bcbd26bfSFlorian Hahn auto *LoopHeaderBB = I.getParent(); 554bcbd26bfSFlorian Hahn auto *Loop = LI.getLoopFor(LoopHeaderBB); 555bcbd26bfSFlorian Hahn PHINode *CanonicalIV = Loop->getCanonicalInductionVariable(); 556bcbd26bfSFlorian Hahn EXPECT_EQ(CanonicalIV, &GetInstByName(F, "canonical.iv")); 557bcbd26bfSFlorian Hahn 558bcbd26bfSFlorian Hahn auto *AR = GetAddRec(SE, Loop); 559bcbd26bfSFlorian Hahn 560bcbd26bfSFlorian Hahn unsigned ExpectedCanonicalIVWidth = SE.getTypeSizeInBits(AR->getType()); 561bcbd26bfSFlorian Hahn unsigned CanonicalIVBitWidth = 562bcbd26bfSFlorian Hahn cast<IntegerType>(CanonicalIV->getType())->getBitWidth(); 563bcbd26bfSFlorian Hahn EXPECT_LT(CanonicalIVBitWidth, ExpectedCanonicalIVWidth); 564bcbd26bfSFlorian Hahn 565bcbd26bfSFlorian Hahn SCEVExpander Exp(SE, M->getDataLayout(), "expander"); 566bcbd26bfSFlorian Hahn auto *InsertAt = I.getNextNode(); 567bcbd26bfSFlorian Hahn Exp.expandCodeFor(AR, nullptr, InsertAt); 568bcbd26bfSFlorian Hahn 569bcbd26bfSFlorian Hahn // Loop over all of the PHI nodes, looking for the new canonical indvar. 570bcbd26bfSFlorian Hahn PHINode *NewCanonicalIV = nullptr; 571bcbd26bfSFlorian Hahn for (BasicBlock::iterator i = LoopHeaderBB->begin(); isa<PHINode>(i); 572bcbd26bfSFlorian Hahn ++i) { 573bcbd26bfSFlorian Hahn PHINode *PN = cast<PHINode>(i); 574bcbd26bfSFlorian Hahn if (PN == &I || PN == CanonicalIV) 575bcbd26bfSFlorian Hahn continue; 576bcbd26bfSFlorian Hahn // We expect that the only PHI added is the new canonical IV 577bcbd26bfSFlorian Hahn EXPECT_FALSE(NewCanonicalIV); 578bcbd26bfSFlorian Hahn NewCanonicalIV = PN; 579bcbd26bfSFlorian Hahn } 580bcbd26bfSFlorian Hahn 581bcbd26bfSFlorian Hahn // Check that NewCanonicalIV is a canonical IV, i.e {0,+,1} 582bcbd26bfSFlorian Hahn BasicBlock *Incoming = nullptr, *Backedge = nullptr; 583bcbd26bfSFlorian Hahn EXPECT_TRUE(Loop->getIncomingAndBackEdge(Incoming, Backedge)); 584bcbd26bfSFlorian Hahn auto *Start = NewCanonicalIV->getIncomingValueForBlock(Incoming); 585bcbd26bfSFlorian Hahn EXPECT_TRUE(isa<ConstantInt>(Start)); 586bcbd26bfSFlorian Hahn EXPECT_TRUE(dyn_cast<ConstantInt>(Start)->isZero()); 587bcbd26bfSFlorian Hahn auto *Next = NewCanonicalIV->getIncomingValueForBlock(Backedge); 588bcbd26bfSFlorian Hahn EXPECT_TRUE(isa<BinaryOperator>(Next)); 589bcbd26bfSFlorian Hahn auto *NextBinOp = dyn_cast<BinaryOperator>(Next); 590bcbd26bfSFlorian Hahn EXPECT_EQ(NextBinOp->getOpcode(), Instruction::Add); 591bcbd26bfSFlorian Hahn EXPECT_EQ(NextBinOp->getOperand(0), NewCanonicalIV); 592bcbd26bfSFlorian Hahn auto *Step = NextBinOp->getOperand(1); 593bcbd26bfSFlorian Hahn EXPECT_TRUE(isa<ConstantInt>(Step)); 594bcbd26bfSFlorian Hahn EXPECT_TRUE(dyn_cast<ConstantInt>(Step)->isOne()); 595bcbd26bfSFlorian Hahn 596bcbd26bfSFlorian Hahn unsigned NewCanonicalIVBitWidth = 597bcbd26bfSFlorian Hahn cast<IntegerType>(NewCanonicalIV->getType())->getBitWidth(); 598bcbd26bfSFlorian Hahn EXPECT_EQ(NewCanonicalIVBitWidth, ExpectedCanonicalIVWidth); 599bcbd26bfSFlorian Hahn }); 600bcbd26bfSFlorian Hahn }; 601bcbd26bfSFlorian Hahn 602bcbd26bfSFlorian Hahn // Expand the addrec produced by GetAddRec into a loop with a canonical IV 603bcbd26bfSFlorian Hahn // of addrec width. 604bcbd26bfSFlorian Hahn // To expand the addrec SCEVExpander should use the existing canonical IV. 605bcbd26bfSFlorian Hahn auto TestMatchingCanonicalIV = 606bcbd26bfSFlorian Hahn [&](std::function<const SCEV *(ScalarEvolution & SE, Loop * L)> GetAddRec, 607bcbd26bfSFlorian Hahn unsigned ARBitWidth) { 608bcbd26bfSFlorian Hahn auto ARBitWidthTypeStr = "i" + std::to_string(ARBitWidth); 609bcbd26bfSFlorian Hahn std::unique_ptr<Module> M = parseAssemblyString( 610bcbd26bfSFlorian Hahn "define i32 @test(i32 %limit) { " 611bcbd26bfSFlorian Hahn "entry: " 612bcbd26bfSFlorian Hahn " br label %loop " 613bcbd26bfSFlorian Hahn "loop: " 614bcbd26bfSFlorian Hahn " %i = phi i32 [ 1, %entry ], [ %i.inc, %loop ] " 615bcbd26bfSFlorian Hahn " %canonical.iv = phi " + 616bcbd26bfSFlorian Hahn ARBitWidthTypeStr + 617bcbd26bfSFlorian Hahn " [ 0, %entry ], [ %canonical.iv.inc, %loop ] " 618bcbd26bfSFlorian Hahn " %i.inc = add nsw i32 %i, 1 " 619bcbd26bfSFlorian Hahn " %canonical.iv.inc = add " + 620bcbd26bfSFlorian Hahn ARBitWidthTypeStr + 621bcbd26bfSFlorian Hahn " %canonical.iv, 1 " 622bcbd26bfSFlorian Hahn " %cont = icmp slt i32 %i.inc, %limit " 623bcbd26bfSFlorian Hahn " br i1 %cont, label %loop, label %exit " 624bcbd26bfSFlorian Hahn "exit: " 625bcbd26bfSFlorian Hahn " ret i32 %i.inc " 626bcbd26bfSFlorian Hahn "}", 627bcbd26bfSFlorian Hahn Err, C); 628bcbd26bfSFlorian Hahn 629bcbd26bfSFlorian Hahn assert(M && "Could not parse module?"); 630bcbd26bfSFlorian Hahn assert(!verifyModule(*M) && "Must have been well formed!"); 631bcbd26bfSFlorian Hahn 632bcbd26bfSFlorian Hahn runWithSE( 633bcbd26bfSFlorian Hahn *M, "test", [&](Function &F, LoopInfo &LI, ScalarEvolution &SE) { 634bcbd26bfSFlorian Hahn auto &I = GetInstByName(F, "i"); 635bcbd26bfSFlorian Hahn auto &CanonicalIV = GetInstByName(F, "canonical.iv"); 636bcbd26bfSFlorian Hahn 637bcbd26bfSFlorian Hahn auto *LoopHeaderBB = I.getParent(); 638bcbd26bfSFlorian Hahn auto *Loop = LI.getLoopFor(LoopHeaderBB); 639bcbd26bfSFlorian Hahn EXPECT_EQ(&CanonicalIV, Loop->getCanonicalInductionVariable()); 640bcbd26bfSFlorian Hahn unsigned CanonicalIVBitWidth = 641bcbd26bfSFlorian Hahn cast<IntegerType>(CanonicalIV.getType())->getBitWidth(); 642bcbd26bfSFlorian Hahn 643bcbd26bfSFlorian Hahn auto *AR = GetAddRec(SE, Loop); 644bcbd26bfSFlorian Hahn EXPECT_EQ(ARBitWidth, SE.getTypeSizeInBits(AR->getType())); 645bcbd26bfSFlorian Hahn EXPECT_EQ(CanonicalIVBitWidth, ARBitWidth); 646bcbd26bfSFlorian Hahn 647bcbd26bfSFlorian Hahn SCEVExpander Exp(SE, M->getDataLayout(), "expander"); 648bcbd26bfSFlorian Hahn auto *InsertAt = I.getNextNode(); 649bcbd26bfSFlorian Hahn Exp.expandCodeFor(AR, nullptr, InsertAt); 650bcbd26bfSFlorian Hahn 651bcbd26bfSFlorian Hahn // Loop over all of the PHI nodes, looking if a new canonical 652bcbd26bfSFlorian Hahn // indvar was introduced. 653bcbd26bfSFlorian Hahn PHINode *NewCanonicalIV = nullptr; 654bcbd26bfSFlorian Hahn for (BasicBlock::iterator i = LoopHeaderBB->begin(); 655bcbd26bfSFlorian Hahn isa<PHINode>(i); ++i) { 656bcbd26bfSFlorian Hahn PHINode *PN = cast<PHINode>(i); 657bcbd26bfSFlorian Hahn if (PN == &I || PN == &CanonicalIV) 658bcbd26bfSFlorian Hahn continue; 659bcbd26bfSFlorian Hahn NewCanonicalIV = PN; 660bcbd26bfSFlorian Hahn } 661bcbd26bfSFlorian Hahn EXPECT_FALSE(NewCanonicalIV); 662bcbd26bfSFlorian Hahn }); 663bcbd26bfSFlorian Hahn }; 664bcbd26bfSFlorian Hahn 665bcbd26bfSFlorian Hahn unsigned ARBitWidth = 16; 666bcbd26bfSFlorian Hahn Type *ARType = IntegerType::get(C, ARBitWidth); 667bcbd26bfSFlorian Hahn 668bcbd26bfSFlorian Hahn // Expand {5,+,1} 669bcbd26bfSFlorian Hahn auto GetAR2 = [&](ScalarEvolution &SE, Loop *L) -> const SCEV * { 670bcbd26bfSFlorian Hahn return SE.getAddRecExpr(SE.getConstant(APInt(ARBitWidth, 5)), 671bcbd26bfSFlorian Hahn SE.getOne(ARType), L, SCEV::FlagAnyWrap); 672bcbd26bfSFlorian Hahn }; 673bcbd26bfSFlorian Hahn TestNoCanonicalIV(GetAR2); 674bcbd26bfSFlorian Hahn TestNarrowCanonicalIV(GetAR2); 675bcbd26bfSFlorian Hahn TestMatchingCanonicalIV(GetAR2, ARBitWidth); 676bcbd26bfSFlorian Hahn } 677bcbd26bfSFlorian Hahn 678bcbd26bfSFlorian Hahn TEST_F(ScalarEvolutionExpanderTest, SCEVExpanderShlNSW) { 679bcbd26bfSFlorian Hahn 680bcbd26bfSFlorian Hahn auto checkOneCase = [this](std::string &&str) { 681bcbd26bfSFlorian Hahn LLVMContext C; 682bcbd26bfSFlorian Hahn SMDiagnostic Err; 683bcbd26bfSFlorian Hahn std::unique_ptr<Module> M = parseAssemblyString(str, Err, C); 684bcbd26bfSFlorian Hahn 685bcbd26bfSFlorian Hahn assert(M && "Could not parse module?"); 686bcbd26bfSFlorian Hahn assert(!verifyModule(*M) && "Must have been well formed!"); 687bcbd26bfSFlorian Hahn 688bcbd26bfSFlorian Hahn Function *F = M->getFunction("f"); 689bcbd26bfSFlorian Hahn ASSERT_NE(F, nullptr) << "Could not find function 'f'"; 690bcbd26bfSFlorian Hahn 691bcbd26bfSFlorian Hahn BasicBlock &Entry = F->getEntryBlock(); 692bcbd26bfSFlorian Hahn LoadInst *Load = cast<LoadInst>(&Entry.front()); 693bcbd26bfSFlorian Hahn BinaryOperator *And = cast<BinaryOperator>(*Load->user_begin()); 694bcbd26bfSFlorian Hahn 695bcbd26bfSFlorian Hahn ScalarEvolution SE = buildSE(*F); 696bcbd26bfSFlorian Hahn const SCEV *AndSCEV = SE.getSCEV(And); 697bcbd26bfSFlorian Hahn EXPECT_TRUE(isa<SCEVMulExpr>(AndSCEV)); 698bcbd26bfSFlorian Hahn EXPECT_TRUE(cast<SCEVMulExpr>(AndSCEV)->hasNoSignedWrap()); 699bcbd26bfSFlorian Hahn 700bcbd26bfSFlorian Hahn SCEVExpander Exp(SE, M->getDataLayout(), "expander"); 701bcbd26bfSFlorian Hahn auto *I = cast<Instruction>(Exp.expandCodeFor(AndSCEV, nullptr, And)); 702bcbd26bfSFlorian Hahn EXPECT_EQ(I->getOpcode(), Instruction::Shl); 703bcbd26bfSFlorian Hahn EXPECT_FALSE(I->hasNoSignedWrap()); 704bcbd26bfSFlorian Hahn }; 705bcbd26bfSFlorian Hahn 706bcbd26bfSFlorian Hahn checkOneCase("define void @f(i16* %arrayidx) { " 707bcbd26bfSFlorian Hahn " %1 = load i16, i16* %arrayidx " 708bcbd26bfSFlorian Hahn " %2 = and i16 %1, -32768 " 709bcbd26bfSFlorian Hahn " ret void " 710bcbd26bfSFlorian Hahn "} "); 711bcbd26bfSFlorian Hahn 712bcbd26bfSFlorian Hahn checkOneCase("define void @f(i8* %arrayidx) { " 713bcbd26bfSFlorian Hahn " %1 = load i8, i8* %arrayidx " 714bcbd26bfSFlorian Hahn " %2 = and i8 %1, -128 " 715bcbd26bfSFlorian Hahn " ret void " 716bcbd26bfSFlorian Hahn "} "); 717bcbd26bfSFlorian Hahn } 718bcbd26bfSFlorian Hahn 719bcbd26bfSFlorian Hahn // Test expansion of nested addrecs in CanonicalMode. 720bcbd26bfSFlorian Hahn // Expanding nested addrecs in canonical mode requiers a canonical IV of a 721bcbd26bfSFlorian Hahn // type wider than the type of the addrec itself. Currently, SCEVExpander 722bcbd26bfSFlorian Hahn // just falls back to literal mode for nested addrecs. 723bcbd26bfSFlorian Hahn TEST_F(ScalarEvolutionExpanderTest, SCEVExpandNonAffineAddRec) { 724bcbd26bfSFlorian Hahn LLVMContext C; 725bcbd26bfSFlorian Hahn SMDiagnostic Err; 726bcbd26bfSFlorian Hahn 727bcbd26bfSFlorian Hahn // Expand the addrec produced by GetAddRec into a loop without a canonical IV. 728bcbd26bfSFlorian Hahn auto TestNoCanonicalIV = 729bcbd26bfSFlorian Hahn [&](std::function<const SCEVAddRecExpr *(ScalarEvolution & SE, Loop * L)> 730bcbd26bfSFlorian Hahn GetAddRec) { 731bcbd26bfSFlorian Hahn std::unique_ptr<Module> M = parseAssemblyString( 732bcbd26bfSFlorian Hahn "define i32 @test(i32 %limit) { " 733bcbd26bfSFlorian Hahn "entry: " 734bcbd26bfSFlorian Hahn " br label %loop " 735bcbd26bfSFlorian Hahn "loop: " 736bcbd26bfSFlorian Hahn " %i = phi i32 [ 1, %entry ], [ %i.inc, %loop ] " 737bcbd26bfSFlorian Hahn " %i.inc = add nsw i32 %i, 1 " 738bcbd26bfSFlorian Hahn " %cont = icmp slt i32 %i.inc, %limit " 739bcbd26bfSFlorian Hahn " br i1 %cont, label %loop, label %exit " 740bcbd26bfSFlorian Hahn "exit: " 741bcbd26bfSFlorian Hahn " ret i32 %i.inc " 742bcbd26bfSFlorian Hahn "}", 743bcbd26bfSFlorian Hahn Err, C); 744bcbd26bfSFlorian Hahn 745bcbd26bfSFlorian Hahn assert(M && "Could not parse module?"); 746bcbd26bfSFlorian Hahn assert(!verifyModule(*M) && "Must have been well formed!"); 747bcbd26bfSFlorian Hahn 748bcbd26bfSFlorian Hahn runWithSE(*M, "test", 749bcbd26bfSFlorian Hahn [&](Function &F, LoopInfo &LI, ScalarEvolution &SE) { 750bcbd26bfSFlorian Hahn auto &I = GetInstByName(F, "i"); 751bcbd26bfSFlorian Hahn auto *Loop = LI.getLoopFor(I.getParent()); 752bcbd26bfSFlorian Hahn EXPECT_FALSE(Loop->getCanonicalInductionVariable()); 753bcbd26bfSFlorian Hahn 754bcbd26bfSFlorian Hahn auto *AR = GetAddRec(SE, Loop); 755bcbd26bfSFlorian Hahn EXPECT_FALSE(AR->isAffine()); 756bcbd26bfSFlorian Hahn 757bcbd26bfSFlorian Hahn SCEVExpander Exp(SE, M->getDataLayout(), "expander"); 758bcbd26bfSFlorian Hahn auto *InsertAt = I.getNextNode(); 759bcbd26bfSFlorian Hahn Value *V = Exp.expandCodeFor(AR, nullptr, InsertAt); 760edf46f36SFlorian Hahn const SCEV *ExpandedAR = SE.getSCEV(V); 761bcbd26bfSFlorian Hahn // Check that the expansion happened literally. 762bcbd26bfSFlorian Hahn EXPECT_EQ(AR, ExpandedAR); 763bcbd26bfSFlorian Hahn }); 764bcbd26bfSFlorian Hahn }; 765bcbd26bfSFlorian Hahn 766bcbd26bfSFlorian Hahn // Expand the addrec produced by GetAddRec into a loop with a canonical IV 767bcbd26bfSFlorian Hahn // which is narrower than addrec type. 768bcbd26bfSFlorian Hahn auto TestNarrowCanonicalIV = [&](std::function<const SCEVAddRecExpr *( 769bcbd26bfSFlorian Hahn ScalarEvolution & SE, Loop * L)> 770bcbd26bfSFlorian Hahn GetAddRec) { 771bcbd26bfSFlorian Hahn std::unique_ptr<Module> M = parseAssemblyString( 772bcbd26bfSFlorian Hahn "define i32 @test(i32 %limit) { " 773bcbd26bfSFlorian Hahn "entry: " 774bcbd26bfSFlorian Hahn " br label %loop " 775bcbd26bfSFlorian Hahn "loop: " 776bcbd26bfSFlorian Hahn " %i = phi i32 [ 1, %entry ], [ %i.inc, %loop ] " 777bcbd26bfSFlorian Hahn " %canonical.iv = phi i8 [ 0, %entry ], [ %canonical.iv.inc, %loop ] " 778bcbd26bfSFlorian Hahn " %i.inc = add nsw i32 %i, 1 " 779bcbd26bfSFlorian Hahn " %canonical.iv.inc = add i8 %canonical.iv, 1 " 780bcbd26bfSFlorian Hahn " %cont = icmp slt i32 %i.inc, %limit " 781bcbd26bfSFlorian Hahn " br i1 %cont, label %loop, label %exit " 782bcbd26bfSFlorian Hahn "exit: " 783bcbd26bfSFlorian Hahn " ret i32 %i.inc " 784bcbd26bfSFlorian Hahn "}", 785bcbd26bfSFlorian Hahn Err, C); 786bcbd26bfSFlorian Hahn 787bcbd26bfSFlorian Hahn assert(M && "Could not parse module?"); 788bcbd26bfSFlorian Hahn assert(!verifyModule(*M) && "Must have been well formed!"); 789bcbd26bfSFlorian Hahn 790bcbd26bfSFlorian Hahn runWithSE(*M, "test", [&](Function &F, LoopInfo &LI, ScalarEvolution &SE) { 791bcbd26bfSFlorian Hahn auto &I = GetInstByName(F, "i"); 792bcbd26bfSFlorian Hahn 793bcbd26bfSFlorian Hahn auto *LoopHeaderBB = I.getParent(); 794bcbd26bfSFlorian Hahn auto *Loop = LI.getLoopFor(LoopHeaderBB); 795bcbd26bfSFlorian Hahn PHINode *CanonicalIV = Loop->getCanonicalInductionVariable(); 796bcbd26bfSFlorian Hahn EXPECT_EQ(CanonicalIV, &GetInstByName(F, "canonical.iv")); 797bcbd26bfSFlorian Hahn 798bcbd26bfSFlorian Hahn auto *AR = GetAddRec(SE, Loop); 799bcbd26bfSFlorian Hahn EXPECT_FALSE(AR->isAffine()); 800bcbd26bfSFlorian Hahn 801bcbd26bfSFlorian Hahn unsigned ExpectedCanonicalIVWidth = SE.getTypeSizeInBits(AR->getType()); 802bcbd26bfSFlorian Hahn unsigned CanonicalIVBitWidth = 803bcbd26bfSFlorian Hahn cast<IntegerType>(CanonicalIV->getType())->getBitWidth(); 804bcbd26bfSFlorian Hahn EXPECT_LT(CanonicalIVBitWidth, ExpectedCanonicalIVWidth); 805bcbd26bfSFlorian Hahn 806bcbd26bfSFlorian Hahn SCEVExpander Exp(SE, M->getDataLayout(), "expander"); 807bcbd26bfSFlorian Hahn auto *InsertAt = I.getNextNode(); 808bcbd26bfSFlorian Hahn Value *V = Exp.expandCodeFor(AR, nullptr, InsertAt); 809edf46f36SFlorian Hahn const SCEV *ExpandedAR = SE.getSCEV(V); 810bcbd26bfSFlorian Hahn // Check that the expansion happened literally. 811bcbd26bfSFlorian Hahn EXPECT_EQ(AR, ExpandedAR); 812bcbd26bfSFlorian Hahn }); 813bcbd26bfSFlorian Hahn }; 814bcbd26bfSFlorian Hahn 815bcbd26bfSFlorian Hahn // Expand the addrec produced by GetAddRec into a loop with a canonical IV 816bcbd26bfSFlorian Hahn // of addrec width. 817bcbd26bfSFlorian Hahn auto TestMatchingCanonicalIV = 818bcbd26bfSFlorian Hahn [&](std::function<const SCEVAddRecExpr *(ScalarEvolution & SE, Loop * L)> 819bcbd26bfSFlorian Hahn GetAddRec, 820bcbd26bfSFlorian Hahn unsigned ARBitWidth) { 821bcbd26bfSFlorian Hahn auto ARBitWidthTypeStr = "i" + std::to_string(ARBitWidth); 822bcbd26bfSFlorian Hahn std::unique_ptr<Module> M = parseAssemblyString( 823bcbd26bfSFlorian Hahn "define i32 @test(i32 %limit) { " 824bcbd26bfSFlorian Hahn "entry: " 825bcbd26bfSFlorian Hahn " br label %loop " 826bcbd26bfSFlorian Hahn "loop: " 827bcbd26bfSFlorian Hahn " %i = phi i32 [ 1, %entry ], [ %i.inc, %loop ] " 828bcbd26bfSFlorian Hahn " %canonical.iv = phi " + 829bcbd26bfSFlorian Hahn ARBitWidthTypeStr + 830bcbd26bfSFlorian Hahn " [ 0, %entry ], [ %canonical.iv.inc, %loop ] " 831bcbd26bfSFlorian Hahn " %i.inc = add nsw i32 %i, 1 " 832bcbd26bfSFlorian Hahn " %canonical.iv.inc = add " + 833bcbd26bfSFlorian Hahn ARBitWidthTypeStr + 834bcbd26bfSFlorian Hahn " %canonical.iv, 1 " 835bcbd26bfSFlorian Hahn " %cont = icmp slt i32 %i.inc, %limit " 836bcbd26bfSFlorian Hahn " br i1 %cont, label %loop, label %exit " 837bcbd26bfSFlorian Hahn "exit: " 838bcbd26bfSFlorian Hahn " ret i32 %i.inc " 839bcbd26bfSFlorian Hahn "}", 840bcbd26bfSFlorian Hahn Err, C); 841bcbd26bfSFlorian Hahn 842bcbd26bfSFlorian Hahn assert(M && "Could not parse module?"); 843bcbd26bfSFlorian Hahn assert(!verifyModule(*M) && "Must have been well formed!"); 844bcbd26bfSFlorian Hahn 845bcbd26bfSFlorian Hahn runWithSE( 846bcbd26bfSFlorian Hahn *M, "test", [&](Function &F, LoopInfo &LI, ScalarEvolution &SE) { 847bcbd26bfSFlorian Hahn auto &I = GetInstByName(F, "i"); 848bcbd26bfSFlorian Hahn auto &CanonicalIV = GetInstByName(F, "canonical.iv"); 849bcbd26bfSFlorian Hahn 850bcbd26bfSFlorian Hahn auto *LoopHeaderBB = I.getParent(); 851bcbd26bfSFlorian Hahn auto *Loop = LI.getLoopFor(LoopHeaderBB); 852bcbd26bfSFlorian Hahn EXPECT_EQ(&CanonicalIV, Loop->getCanonicalInductionVariable()); 853bcbd26bfSFlorian Hahn unsigned CanonicalIVBitWidth = 854bcbd26bfSFlorian Hahn cast<IntegerType>(CanonicalIV.getType())->getBitWidth(); 855bcbd26bfSFlorian Hahn 856bcbd26bfSFlorian Hahn auto *AR = GetAddRec(SE, Loop); 857bcbd26bfSFlorian Hahn EXPECT_FALSE(AR->isAffine()); 858bcbd26bfSFlorian Hahn EXPECT_EQ(ARBitWidth, SE.getTypeSizeInBits(AR->getType())); 859bcbd26bfSFlorian Hahn EXPECT_EQ(CanonicalIVBitWidth, ARBitWidth); 860bcbd26bfSFlorian Hahn 861bcbd26bfSFlorian Hahn SCEVExpander Exp(SE, M->getDataLayout(), "expander"); 862bcbd26bfSFlorian Hahn auto *InsertAt = I.getNextNode(); 863bcbd26bfSFlorian Hahn Value *V = Exp.expandCodeFor(AR, nullptr, InsertAt); 864edf46f36SFlorian Hahn const SCEV *ExpandedAR = SE.getSCEV(V); 865bcbd26bfSFlorian Hahn // Check that the expansion happened literally. 866bcbd26bfSFlorian Hahn EXPECT_EQ(AR, ExpandedAR); 867bcbd26bfSFlorian Hahn }); 868bcbd26bfSFlorian Hahn }; 869bcbd26bfSFlorian Hahn 870bcbd26bfSFlorian Hahn unsigned ARBitWidth = 16; 871bcbd26bfSFlorian Hahn Type *ARType = IntegerType::get(C, ARBitWidth); 872bcbd26bfSFlorian Hahn 873bcbd26bfSFlorian Hahn // Expand {5,+,1,+,1} 874bcbd26bfSFlorian Hahn auto GetAR3 = [&](ScalarEvolution &SE, Loop *L) -> const SCEVAddRecExpr * { 875bcbd26bfSFlorian Hahn SmallVector<const SCEV *, 3> Ops = {SE.getConstant(APInt(ARBitWidth, 5)), 876bcbd26bfSFlorian Hahn SE.getOne(ARType), SE.getOne(ARType)}; 877bcbd26bfSFlorian Hahn return cast<SCEVAddRecExpr>(SE.getAddRecExpr(Ops, L, SCEV::FlagAnyWrap)); 878bcbd26bfSFlorian Hahn }; 879bcbd26bfSFlorian Hahn TestNoCanonicalIV(GetAR3); 880bcbd26bfSFlorian Hahn TestNarrowCanonicalIV(GetAR3); 881bcbd26bfSFlorian Hahn TestMatchingCanonicalIV(GetAR3, ARBitWidth); 882bcbd26bfSFlorian Hahn 883bcbd26bfSFlorian Hahn // Expand {5,+,1,+,1,+,1} 884bcbd26bfSFlorian Hahn auto GetAR4 = [&](ScalarEvolution &SE, Loop *L) -> const SCEVAddRecExpr * { 885bcbd26bfSFlorian Hahn SmallVector<const SCEV *, 4> Ops = {SE.getConstant(APInt(ARBitWidth, 5)), 886bcbd26bfSFlorian Hahn SE.getOne(ARType), SE.getOne(ARType), 887bcbd26bfSFlorian Hahn SE.getOne(ARType)}; 888bcbd26bfSFlorian Hahn return cast<SCEVAddRecExpr>(SE.getAddRecExpr(Ops, L, SCEV::FlagAnyWrap)); 889bcbd26bfSFlorian Hahn }; 890bcbd26bfSFlorian Hahn TestNoCanonicalIV(GetAR4); 891bcbd26bfSFlorian Hahn TestNarrowCanonicalIV(GetAR4); 892bcbd26bfSFlorian Hahn TestMatchingCanonicalIV(GetAR4, ARBitWidth); 893bcbd26bfSFlorian Hahn 894bcbd26bfSFlorian Hahn // Expand {5,+,1,+,1,+,1,+,1} 895bcbd26bfSFlorian Hahn auto GetAR5 = [&](ScalarEvolution &SE, Loop *L) -> const SCEVAddRecExpr * { 896bcbd26bfSFlorian Hahn SmallVector<const SCEV *, 5> Ops = {SE.getConstant(APInt(ARBitWidth, 5)), 897bcbd26bfSFlorian Hahn SE.getOne(ARType), SE.getOne(ARType), 898bcbd26bfSFlorian Hahn SE.getOne(ARType), SE.getOne(ARType)}; 899bcbd26bfSFlorian Hahn return cast<SCEVAddRecExpr>(SE.getAddRecExpr(Ops, L, SCEV::FlagAnyWrap)); 900bcbd26bfSFlorian Hahn }; 901bcbd26bfSFlorian Hahn TestNoCanonicalIV(GetAR5); 902bcbd26bfSFlorian Hahn TestNarrowCanonicalIV(GetAR5); 903bcbd26bfSFlorian Hahn TestMatchingCanonicalIV(GetAR5, ARBitWidth); 904bcbd26bfSFlorian Hahn } 905bcbd26bfSFlorian Hahn 9061d8f2e52SFlorian Hahn TEST_F(ScalarEvolutionExpanderTest, ExpandNonIntegralPtrWithNullBase) { 9071d8f2e52SFlorian Hahn LLVMContext C; 9081d8f2e52SFlorian Hahn SMDiagnostic Err; 9091d8f2e52SFlorian Hahn 9101d8f2e52SFlorian Hahn std::unique_ptr<Module> M = 9111d8f2e52SFlorian Hahn parseAssemblyString("target datalayout = " 9121d8f2e52SFlorian Hahn "\"e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:" 9131d8f2e52SFlorian Hahn "128-n8:16:32:64-S128-ni:1-p2:32:8:8:32-ni:2\"" 9141ff25323SNikita Popov "define ptr addrspace(1) @test(i64 %offset) { " 9151ff25323SNikita Popov " %ptr = getelementptr inbounds float, ptr " 9161ff25323SNikita Popov "addrspace(1) null, i64 %offset" 9171ff25323SNikita Popov " ret ptr addrspace(1) %ptr" 9181d8f2e52SFlorian Hahn "}", 9191d8f2e52SFlorian Hahn Err, C); 9201d8f2e52SFlorian Hahn 9211d8f2e52SFlorian Hahn assert(M && "Could not parse module?"); 9221d8f2e52SFlorian Hahn assert(!verifyModule(*M) && "Must have been well formed!"); 9231d8f2e52SFlorian Hahn 9241d8f2e52SFlorian Hahn runWithSE(*M, "test", [&](Function &F, LoopInfo &LI, ScalarEvolution &SE) { 9251d8f2e52SFlorian Hahn auto &I = GetInstByName(F, "ptr"); 9261d8f2e52SFlorian Hahn auto PtrPlus1 = 9271d8f2e52SFlorian Hahn SE.getAddExpr(SE.getSCEV(&I), SE.getConstant(I.getType(), 1)); 9281d8f2e52SFlorian Hahn SCEVExpander Exp(SE, M->getDataLayout(), "expander"); 9291d8f2e52SFlorian Hahn 9301d8f2e52SFlorian Hahn Value *V = Exp.expandCodeFor(PtrPlus1, I.getType(), &I); 9311d8f2e52SFlorian Hahn I.replaceAllUsesWith(V); 9321d8f2e52SFlorian Hahn 93378b8ce40SRoman Lebedev // Check that the expander created: 9341ff25323SNikita Popov // define ptr addrspace(1) @test(i64 %off) { 9351ff25323SNikita Popov // %1 = shl i64 %offset, 2 9361ff25323SNikita Popov // %2 = add nuw nsw i64 %1, 1 9371ff25323SNikita Popov // %uglygep = getelementptr i8, ptr addrspace(1) null, i64 %2 9381ff25323SNikita Popov // %ptr = getelementptr inbounds float, ptr addrspace(1) null, i64 %off 9391ff25323SNikita Popov // ret ptr addrspace(1) %uglygep 94078b8ce40SRoman Lebedev // } 94178b8ce40SRoman Lebedev 9421ff25323SNikita Popov Value *Offset = &*F.arg_begin(); 9431ff25323SNikita Popov auto *GEP = dyn_cast<GetElementPtrInst>(V); 9441d8f2e52SFlorian Hahn EXPECT_TRUE(GEP); 9451ff25323SNikita Popov EXPECT_TRUE(cast<Constant>(GEP->getPointerOperand())->isNullValue()); 9465f2acfb6SRoman Lebedev EXPECT_EQ(GEP->getNumOperands(), 2U); 9471ff25323SNikita Popov EXPECT_TRUE(match( 9481ff25323SNikita Popov GEP->getOperand(1), 9491ff25323SNikita Popov m_Add(m_Shl(m_Specific(Offset), m_SpecificInt(2)), m_SpecificInt(1)))); 9501ff25323SNikita Popov EXPECT_EQ(cast<PointerType>(GEP->getPointerOperand()->getType()) 9511d8f2e52SFlorian Hahn ->getAddressSpace(), 9521d8f2e52SFlorian Hahn cast<PointerType>(I.getType())->getAddressSpace()); 9531d8f2e52SFlorian Hahn EXPECT_FALSE(verifyFunction(F, &errs())); 9541d8f2e52SFlorian Hahn }); 9551d8f2e52SFlorian Hahn } 9561d8f2e52SFlorian Hahn 9574b3ba64bSNikita Popov TEST_F(ScalarEvolutionExpanderTest, GEPFlags) { 9584b3ba64bSNikita Popov LLVMContext C; 9594b3ba64bSNikita Popov SMDiagnostic Err; 9604b3ba64bSNikita Popov StringRef ModStr = R"( 9614b3ba64bSNikita Popov define void @f(ptr %p, i64 %x) { 9624b3ba64bSNikita Popov %gep_inbounds = getelementptr inbounds i8, ptr %p, i64 %x 9634b3ba64bSNikita Popov ret void 9644b3ba64bSNikita Popov })"; 9654b3ba64bSNikita Popov std::unique_ptr<Module> M = parseAssemblyString(ModStr, Err, C); 9664b3ba64bSNikita Popov 9674b3ba64bSNikita Popov assert(M && "Could not parse module?"); 9684b3ba64bSNikita Popov assert(!verifyModule(*M) && "Must have been well formed!"); 9694b3ba64bSNikita Popov 9704b3ba64bSNikita Popov Function *F = M->getFunction("f"); 9714b3ba64bSNikita Popov ASSERT_NE(F, nullptr) << "Could not find function 'f'"; 9724b3ba64bSNikita Popov BasicBlock &Entry = F->getEntryBlock(); 9734b3ba64bSNikita Popov auto *GEP = cast<GetElementPtrInst>(&Entry.front()); 9744b3ba64bSNikita Popov 9754b3ba64bSNikita Popov ScalarEvolution SE = buildSE(*F); 9764b3ba64bSNikita Popov const SCEV *Ptr = SE.getSCEV(F->getArg(0)); 9774b3ba64bSNikita Popov const SCEV *X = SE.getSCEV(F->getArg(1)); 9784b3ba64bSNikita Popov const SCEV *PtrX = SE.getAddExpr(Ptr, X); 9794b3ba64bSNikita Popov 9804b3ba64bSNikita Popov SCEVExpander Exp(SE, M->getDataLayout(), "expander"); 9814b3ba64bSNikita Popov auto *I = cast<Instruction>( 9824b3ba64bSNikita Popov Exp.expandCodeFor(PtrX, nullptr, Entry.getTerminator())); 9834b3ba64bSNikita Popov // Check that the GEP is reused, but the inbounds flag cleared. We don't 9844b3ba64bSNikita Popov // know that the newly introduced use is inbounds. 9854b3ba64bSNikita Popov EXPECT_EQ(I, GEP); 9864b3ba64bSNikita Popov EXPECT_EQ(GEP->getNoWrapFlags(), GEPNoWrapFlags::none()); 9874b3ba64bSNikita Popov } 9884b3ba64bSNikita Popov 989bcbd26bfSFlorian Hahn } // end namespace llvm 990