diff --git a/llvm/include/llvm/Analysis/ValueTracking.h b/llvm/include/llvm/Analysis/ValueTracking.h --- a/llvm/include/llvm/Analysis/ValueTracking.h +++ b/llvm/include/llvm/Analysis/ValueTracking.h @@ -600,7 +600,8 @@ /// immediately before the CtxI. bool isGuaranteedNotToBeUndefOrPoison(const Value *V, const Instruction *CtxI = nullptr, - const DominatorTree *DT = nullptr); + const DominatorTree *DT = nullptr, + unsigned Depth = 0); /// Specific patterns of select instructions we can match. enum SelectPatternFlavor { diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -4602,7 +4602,11 @@ bool llvm::isGuaranteedNotToBeUndefOrPoison(const Value *V, const Instruction *CtxI, - const DominatorTree *DT) { + const DominatorTree *DT, + unsigned Depth) { + if (Depth >= MaxDepth) + return false; + // If the value is a freeze instruction, then it can never // be undef or poison. if (isa(V)) @@ -4616,8 +4620,8 @@ if (isa(C) || isa(C)) return false; - // TODO: Add ConstantFP and pointers. - if (isa(C) || isa(C) ) + if (isa(C) || isa(C) || isa(V) || + isa(C) || isa(C)) return true; if (C->getType()->isVectorTy()) @@ -4627,21 +4631,48 @@ return false; } - if (auto PN = dyn_cast(V)) { - if (llvm::all_of(PN->incoming_values(), [](const Use &U) { - return isa(U.get()); - })) - return true; - } + // Strip cast operations from a pointer value. + // Note that stripPointerCastsSameRepresentation can strip off getelementptr + // inbounds with zero offset. To guarantee that the result isn't poison, the + // stripped pointer is checked as it has to be pointing into an allocated + // object or be null `null` to ensure `inbounds` getelement pointers with a + // zero offset could not produce poison. + // It can strip off addrspacecast that do not change bit representation as + // well. We believe that such addrspacecast is equivalent to no-op. + auto *StrippedV = V->stripPointerCastsSameRepresentation(); + if (isa(StrippedV) || isa(StrippedV) || + isa(StrippedV) || isa(StrippedV)) + return true; - if (auto II = dyn_cast(V)) { - if (llvm::all_of(II->operands(), [](const Value *V) { - return isGuaranteedNotToBeUndefOrPoison(V); - })) - return true; - } + auto OpCheck = [&](const Value *V) { + return isGuaranteedNotToBeUndefOrPoison(V, CtxI, DT, Depth + 1); + }; + + if (auto *I = dyn_cast(V)) { + switch (I->getOpcode()) { + case Instruction::GetElementPtr: { + auto *GEPI = dyn_cast(I); + if (!GEPI->isInBounds() && llvm::all_of(GEPI->operands(), OpCheck)) + return true; + break; + } + case Instruction::FCmp: { + auto *FI = dyn_cast(I); + if (FI->getFastMathFlags().none() && + llvm::all_of(FI->operands(), OpCheck)) + return true; + break; + } + case Instruction::BitCast: + case Instruction::PHI: + case Instruction::ICmp: + if (llvm::all_of(I->operands(), OpCheck)) + return true; + break; + default: + break; + } - if (auto I = dyn_cast(V)) { if (programUndefinedIfFullPoison(I) && I->getType()->isIntegerTy(1)) // Note: once we have an agreement that poison is a value-wise concept, // we can remove the isIntegerTy(1) constraint. diff --git a/llvm/test/Transforms/InstSimplify/freeze.ll b/llvm/test/Transforms/InstSimplify/freeze.ll --- a/llvm/test/Transforms/InstSimplify/freeze.ll +++ b/llvm/test/Transforms/InstSimplify/freeze.ll @@ -19,12 +19,9 @@ ret i32 %x } -; TODO: This is not poison. - define float @make_const2() { ; CHECK-LABEL: @make_const2( -; CHECK-NEXT: [[X:%.*]] = freeze float 1.000000e+01 -; CHECK-NEXT: ret float [[X]] +; CHECK-NEXT: ret float 1.000000e+01 ; %x = freeze float 10.0 ret float %x @@ -40,23 +37,17 @@ ret i32* %k } -; TODO: This is not poison. - define i32()* @make_const_fn() { ; CHECK-LABEL: @make_const_fn( -; CHECK-NEXT: [[K:%.*]] = freeze i32 ()* @make_const -; CHECK-NEXT: ret i32 ()* [[K]] +; CHECK-NEXT: ret i32 ()* @make_const ; %k = freeze i32()* @make_const ret i32()* %k } -; TODO: This is not poison. - define i32* @make_const_null() { ; CHECK-LABEL: @make_const_null( -; CHECK-NEXT: [[K:%.*]] = freeze i32* null -; CHECK-NEXT: ret i32* [[K]] +; CHECK-NEXT: ret i32* null ; %k = freeze i32* null ret i32* %k @@ -146,8 +137,7 @@ define void @alloca() { ; CHECK-LABEL: @alloca( ; CHECK-NEXT: [[P:%.*]] = alloca i8 -; CHECK-NEXT: [[Y:%.*]] = freeze i8* [[P]] -; CHECK-NEXT: call void @f3(i8* [[Y]]) +; CHECK-NEXT: call void @f3(i8* [[P]]) ; CHECK-NEXT: ret void ; %p = alloca i8 @@ -160,8 +150,7 @@ ; CHECK-LABEL: @gep( ; CHECK-NEXT: [[P:%.*]] = alloca [4 x i8] ; CHECK-NEXT: [[Q:%.*]] = getelementptr [4 x i8], [4 x i8]* [[P]], i32 0, i32 6 -; CHECK-NEXT: [[Q2:%.*]] = freeze i8* [[Q]] -; CHECK-NEXT: ret i8* [[Q2]] +; CHECK-NEXT: ret i8* [[Q]] ; %p = alloca [4 x i8] %q = getelementptr [4 x i8], [4 x i8]* %p, i32 0, i32 6 @@ -184,8 +173,7 @@ ; CHECK-LABEL: @gep_inbounds( ; CHECK-NEXT: [[P:%.*]] = alloca [4 x i8] ; CHECK-NEXT: [[Q:%.*]] = getelementptr inbounds [4 x i8], [4 x i8]* [[P]], i32 0, i32 0 -; CHECK-NEXT: [[Q2:%.*]] = freeze i8* [[Q]] -; CHECK-NEXT: ret i8* [[Q2]] +; CHECK-NEXT: ret i8* [[Q]] ; %p = alloca [4 x i8] %q = getelementptr inbounds [4 x i8], [4 x i8]* %p, i32 0, i32 0 @@ -208,8 +196,7 @@ define i32* @gep_inbounds_null() { ; CHECK-LABEL: @gep_inbounds_null( -; CHECK-NEXT: [[K:%.*]] = freeze i32* null -; CHECK-NEXT: ret i32* [[K]] +; CHECK-NEXT: ret i32* null ; %p = getelementptr inbounds i32, i32* null, i32 0 %k = freeze i32* %p @@ -256,8 +243,7 @@ ; CHECK-NEXT: [[FX:%.*]] = freeze float [[X:%.*]] ; CHECK-NEXT: [[FY:%.*]] = freeze float [[Y:%.*]] ; CHECK-NEXT: [[C:%.*]] = fcmp oeq float [[FX]], [[FY]] -; CHECK-NEXT: [[FC:%.*]] = freeze i1 [[C]] -; CHECK-NEXT: ret i1 [[FC]] +; CHECK-NEXT: ret i1 [[C]] ; %fx = freeze float %x %fy = freeze float %y @@ -315,8 +301,7 @@ ; CHECK-NEXT: br label [[EXIT]] ; CHECK: EXIT: ; CHECK-NEXT: [[PHI2:%.*]] = phi i32 [ [[A0_FR]], [[BB1]] ], [ [[PHI1]], [[BB2]] ] -; CHECK-NEXT: [[PHI2_FR:%.*]] = freeze i32 [[PHI2]] -; CHECK-NEXT: ret i32 [[PHI2_FR]] +; CHECK-NEXT: ret i32 [[PHI2]] ; ENTRY: %a0.fr = freeze i32 %a0