From 21e1c3943f8bf281c8d2aa7115ecd6aa007d73e1 Mon Sep 17 00:00:00 2001 From: Denis Bakhvalov Date: Mon, 8 Jul 2019 18:03:43 +0000 Subject: [PATCH] [SCEV] Fix for PR42397. SCEVExpander wrongly adds nsw to shl instruction. Change-Id: I76c9f628c092ae3e6e78ebdaf55cec726e25d692 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@365363 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Analysis/ScalarEvolutionExpander.cpp | 8 +++-- unittests/Analysis/ScalarEvolutionTest.cpp | 41 ++++++++++++++++++++++ 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/lib/Analysis/ScalarEvolutionExpander.cpp b/lib/Analysis/ScalarEvolutionExpander.cpp index 16d0bd64bf0..e8a95d35482 100644 --- a/lib/Analysis/ScalarEvolutionExpander.cpp +++ b/lib/Analysis/ScalarEvolutionExpander.cpp @@ -838,9 +838,13 @@ Value *SCEVExpander::visitMulExpr(const SCEVMulExpr *S) { if (match(W, m_Power2(RHS))) { // Canonicalize Prod*(1<isVectorTy() && "vector types are not SCEVable"); + auto NWFlags = S->getNoWrapFlags(); + // clear nsw flag if shl will produce poison value. + if (RHS->logBase2() == RHS->getBitWidth() - 1) + NWFlags = ScalarEvolution::clearFlags(NWFlags, SCEV::FlagNSW); Prod = InsertBinop(Instruction::Shl, Prod, - ConstantInt::get(Ty, RHS->logBase2()), - S->getNoWrapFlags(), /*IsSafeToHoist*/ true); + ConstantInt::get(Ty, RHS->logBase2()), NWFlags, + /*IsSafeToHoist*/ true); } else { Prod = InsertBinop(Instruction::Mul, Prod, W, S->getNoWrapFlags(), /*IsSafeToHoist*/ true); diff --git a/unittests/Analysis/ScalarEvolutionTest.cpp b/unittests/Analysis/ScalarEvolutionTest.cpp index 1d74fb12844..fb8f6689ca7 100644 --- a/unittests/Analysis/ScalarEvolutionTest.cpp +++ b/unittests/Analysis/ScalarEvolutionTest.cpp @@ -1637,5 +1637,46 @@ TEST_F(ScalarEvolutionsTest, SCEVExpandInsertCanonicalIV) { TestMatchingCanonicalIV(GetAR2, ARBitWidth); } +TEST_F(ScalarEvolutionsTest, SCEVExpanderShlNSW) { + + auto checkOneCase = [this](std::string &&str) { + LLVMContext C; + SMDiagnostic Err; + std::unique_ptr 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(&Entry.front()); + BinaryOperator *And = cast(*Load->user_begin()); + + ScalarEvolution SE = buildSE(*F); + const SCEV *AndSCEV = SE.getSCEV(And); + EXPECT_TRUE(isa(AndSCEV)); + EXPECT_TRUE(cast(AndSCEV)->hasNoSignedWrap()); + + SCEVExpander Exp(SE, M->getDataLayout(), "expander"); + auto *I = cast(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 " + "} "); +} + } // end anonymous namespace } // end namespace llvm -- 2.50.1