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 @@ -575,7 +575,8 @@ /// immediately before the CtxI. bool isGuaranteedNotToBeUndefOrPoison(const Value *V, const Instruction *CtxI = nullptr, - const DominatorTree *DT = nullptr); + const DominatorTree *DT = nullptr, + unsigned Depth = 6); /// 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 @@ -4527,7 +4527,11 @@ bool llvm::isGuaranteedNotToBeUndefOrPoison(const Value *V, const Instruction *CtxI, - const DominatorTree *DT) { + const DominatorTree *DT, + unsigned Depth) { + if (!Depth) + return false; + // If the value is a freeze instruction, then it can never // be undef or poison. if (isa(V)) @@ -4536,9 +4540,30 @@ // nor poison if their arguments are not poison/undef. // TODO: Deal with other Constant subclasses. - if (isa(V) || isa(V)) + if (isa(V) || isa(V)) + return true; + + // Consider addrspacecasts that preserve bit representations only. + auto *StrippedV = V->stripPointerCastsSameRepresentation(); + if (isa(StrippedV) || isa(StrippedV) || + isa(StrippedV) || isa(StrippedV)) + // ConstantPointerNull is allowed here, because 'gep inbounds null, 0' is + // also null. return true; + if (auto BI = dyn_cast(V)) + if (isGuaranteedNotToBeUndefOrPoison(BI->getOperand(0), CtxI, DT, + Depth - 1)) + return true; + + auto OpCheck = [&](const Value *V) { + return isGuaranteedNotToBeUndefOrPoison(V, CtxI, DT, Depth - 1); + }; + if (auto GEPI = dyn_cast(V)) { + if (!GEPI->isInBounds() && llvm::all_of(GEPI->operands(), OpCheck)) + return true; + } + if (auto PN = dyn_cast(V)) { if (llvm::all_of(PN->incoming_values(), [](const Use &U) { return isa(U.get()); @@ -4547,9 +4572,12 @@ } if (auto II = dyn_cast(V)) { - if (llvm::all_of(II->operands(), [](const Value *V) { - return isGuaranteedNotToBeUndefOrPoison(V); - })) + if (llvm::all_of(II->operands(), OpCheck)) + return true; + } + + if (auto FI = dyn_cast(V)) { + if (FI->getFastMathFlags().none() && llvm::all_of(FI->operands(), OpCheck)) return true; } 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,6 +19,99 @@ ret i32 %x } +define float @make_const2() { +; CHECK-LABEL: @make_const2( +; CHECK-NEXT: ret float 1.000000e+01 +; + %x = freeze float 10.0 + ret float %x +} + +@glb = constant i32 0 + +define i32* @make_const_glb() { +; CHECK-LABEL: @make_const_glb( +; CHECK-NEXT: ret i32* @glb +; + %k = freeze i32* @glb + ret i32* %k +} + +define i32()* @make_const_fn() { +; CHECK-LABEL: @make_const_fn( +; CHECK-NEXT: ret i32 ()* @make_const +; + %k = freeze i32()* @make_const + ret i32()* %k +} + +define i32* @make_const_null() { +; CHECK-LABEL: @make_const_null( +; CHECK-NEXT: ret i32* null +; + %k = freeze i32* null + ret i32* %k +} + +define void @alloca() { +; CHECK-LABEL: @alloca( +; CHECK-NEXT: [[P:%.*]] = alloca i8 +; CHECK-NEXT: call void @f3(i8* [[P]]) +; CHECK-NEXT: ret void +; + %p = alloca i8 + %y = freeze i8* %p + call void @f3(i8* %y) + ret void +} + +define i8* @gep() { +; 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: ret i8* [[Q]] +; + %p = alloca [4 x i8] + %q = getelementptr [4 x i8], [4 x i8]* %p, i32 0, i32 6 + %q2 = freeze i8* %q + ret i8* %q2 +} + +define i8* @gep_inbounds() { +; 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: ret i8* [[Q]] +; + %p = alloca [4 x i8] + %q = getelementptr inbounds [4 x i8], [4 x i8]* %p, i32 0, i32 0 + %q2 = freeze i8* %q + ret i8* %q2 +} + +define i32* @gep_inbounds_null() { +; CHECK-LABEL: @gep_inbounds_null( +; CHECK-NEXT: ret i32* null +; + %p = getelementptr inbounds i32, i32* null, i32 0 + %k = freeze i32* %p + ret i32* %k +} + +define i1 @fcmp(float %x, float %y) { +; CHECK-LABEL: @fcmp( +; CHECK-NEXT: [[FX:%.*]] = freeze float [[X:%.*]] +; CHECK-NEXT: [[FY:%.*]] = freeze float [[Y:%.*]] +; CHECK-NEXT: [[C:%.*]] = fcmp oeq float [[FX]], [[FY]] +; CHECK-NEXT: ret i1 [[C]] +; + %fx = freeze float %x + %fy = freeze float %y + %c = fcmp oeq float %fx, %fy + %fc = freeze i1 %c + ret i1 %fc +} + define i1 @brcond(i1 %c, i1 %c2) { ; CHECK-LABEL: @brcond( ; CHECK-NEXT: br i1 [[C:%.*]], label [[A:%.*]], label [[B:%.*]] @@ -81,3 +174,4 @@ } declare void @f1(i1) declare void @f2() +declare void @f3(i8*)