From 4878aa36d4aa27df644430139fab2734fde4a000 Mon Sep 17 00:00:00 2001 From: Florian Hahn Date: Sat, 14 Mar 2020 16:50:09 +0000 Subject: [PATCH] [ValueLattice] Add new state for undef constants. This patch adds a new undef lattice state, which is used to represent UndefValue constants or instructions producing undef. The main difference to the unknown state is that merging undef values with constants (or single element constant ranges) produces the constant/constant range, assuming all uses of the merge result will be replaced by the found constant. Contrary, merging non-single element ranges with undef needs to go to overdefined. Using unknown for UndefValues currently causes mis-compiles in CVP/LVI (PR44949) and will become problematic once we use ValueLatticeElement for SCCP. Reviewers: efriedma, reames, davide, nikic Reviewed By: efriedma Differential Revision: https://reviews.llvm.org/D75120 --- llvm/include/llvm/Analysis/ValueLattice.h | 76 ++++++++++++++----- llvm/lib/Analysis/LazyValueInfo.cpp | 12 +-- llvm/lib/Analysis/ValueLattice.cpp | 6 +- llvm/lib/Transforms/Scalar/SCCP.cpp | 51 ++++++------- .../merge-range-and-undef.ll | 11 ++- .../test/Transforms/JumpThreading/ne-undef.ll | 61 +++++++++++++++ llvm/test/Transforms/SCCP/float-phis.ll | 26 +++++++ llvm/test/Transforms/SCCP/int-phis.ll | 61 +++++++++++++++ 8 files changed, 246 insertions(+), 58 deletions(-) create mode 100644 llvm/test/Transforms/JumpThreading/ne-undef.ll create mode 100644 llvm/test/Transforms/SCCP/float-phis.ll create mode 100644 llvm/test/Transforms/SCCP/int-phis.ll diff --git a/llvm/include/llvm/Analysis/ValueLattice.h b/llvm/include/llvm/Analysis/ValueLattice.h index a43231ae2d3ea..bc6bd854c3b13 100644 --- a/llvm/include/llvm/Analysis/ValueLattice.h +++ b/llvm/include/llvm/Analysis/ValueLattice.h @@ -29,7 +29,12 @@ class ValueLatticeElement { /// producing instruction is dead. Caution: We use this as the starting /// state in our local meet rules. In this usage, it's taken to mean /// "nothing known yet". - undefined, + unknown, + + /// This Value is an UndefValue constant or produces undef. Undefined values + /// can be merged with constants (or single element constant ranges), + /// assuming all uses of the result will be replaced. + undef, /// This Value has a specific constant value. (For constant integers, /// constantrange is used instead. Integer typed constantexprs can appear @@ -60,14 +65,15 @@ class ValueLatticeElement { public: // Const and Range are initialized on-demand. - ValueLatticeElement() : Tag(undefined) {} + ValueLatticeElement() : Tag(unknown) {} /// Custom destructor to ensure Range is properly destroyed, when the object /// is deallocated. ~ValueLatticeElement() { switch (Tag) { case overdefined: - case undefined: + case unknown: + case undef: case constant: case notconstant: break; @@ -79,7 +85,7 @@ class ValueLatticeElement { /// Custom copy constructor, to ensure Range gets initialized when /// copying a constant range lattice element. - ValueLatticeElement(const ValueLatticeElement &Other) : Tag(undefined) { + ValueLatticeElement(const ValueLatticeElement &Other) : Tag(unknown) { *this = Other; } @@ -109,7 +115,8 @@ class ValueLatticeElement { ConstVal = Other.ConstVal; break; case overdefined: - case undefined: + case unknown: + case undef: break; } Tag = Other.Tag; @@ -118,14 +125,16 @@ class ValueLatticeElement { static ValueLatticeElement get(Constant *C) { ValueLatticeElement Res; - if (!isa(C)) + if (isa(C)) + Res.markUndef(); + else Res.markConstant(C); return Res; } static ValueLatticeElement getNot(Constant *C) { ValueLatticeElement Res; - if (!isa(C)) - Res.markNotConstant(C); + assert(!isa(C) && "!= undef is not supported"); + Res.markNotConstant(C); return Res; } static ValueLatticeElement getRange(ConstantRange CR) { @@ -139,8 +148,9 @@ class ValueLatticeElement { return Res; } - bool isUndefined() const { return Tag == undefined; } - bool isUnknown() const { return Tag == undefined; } + bool isUndef() const { return Tag == undef; } + bool isUnknown() const { return Tag == unknown; } + bool isUnknownOrUndef() const { return Tag == unknown || Tag == undef; } bool isConstant() const { return Tag == constant; } bool isNotConstant() const { return Tag == notconstant; } bool isConstantRange() const { return Tag == constantrange; } @@ -182,9 +192,18 @@ class ValueLatticeElement { return true; } + bool markUndef() { + if (isUndef()) + return false; + + assert(isUnknown()); + Tag = undef; + return true; + } + bool markConstant(Constant *V) { if (isa(V)) - return false; + return markUndef(); if (isConstant()) { assert(getConstant() == V && "Marking constant with different value"); @@ -194,7 +213,7 @@ class ValueLatticeElement { if (ConstantInt *CI = dyn_cast(V)) return markConstantRange(ConstantRange(CI->getValue())); - assert(isUndefined()); + assert(isUnknown() || isUndef()); Tag = constant; ConstVal = V; return true; @@ -214,7 +233,7 @@ class ValueLatticeElement { return false; } - assert(isUndefined()); + assert(isUnknown()); Tag = notconstant; ConstVal = V; return true; @@ -223,7 +242,7 @@ class ValueLatticeElement { /// Mark the object as constant range with \p NewR. If the object is already a /// constant range, nothing changes if the existing range is equal to \p /// NewR. Otherwise \p NewR must be a superset of the existing range or the - /// object must be undefined. + /// object must be undef. bool markConstantRange(ConstantRange NewR) { if (isConstantRange()) { if (getConstantRange() == NewR) @@ -238,7 +257,7 @@ class ValueLatticeElement { return true; } - assert(isUndefined()); + assert(isUnknown() || isUndef()); if (NewR.isEmptySet()) return markOverdefined(); @@ -250,21 +269,35 @@ class ValueLatticeElement { /// Updates this object to approximate both this object and RHS. Returns /// true if this object has been changed. bool mergeIn(const ValueLatticeElement &RHS, const DataLayout &DL) { - if (RHS.isUndefined() || isOverdefined()) + if (RHS.isUnknown() || isOverdefined()) return false; if (RHS.isOverdefined()) { markOverdefined(); return true; } - if (isUndefined()) { + if (isUndef()) { + assert(!RHS.isUnknown()); + if (RHS.isUndef()) + return false; + if (RHS.isConstant()) + return markConstant(RHS.getConstant()); + if (RHS.isConstantRange() && RHS.getConstantRange().isSingleElement()) + return markConstantRange(RHS.getConstantRange()); + return markOverdefined(); + } + + if (isUnknown()) { + assert(!RHS.isUnknown() && "Unknow RHS should be handled earlier"); *this = RHS; - return !RHS.isUndefined(); + return true; } if (isConstant()) { if (RHS.isConstant() && getConstant() == RHS.getConstant()) return false; + if (RHS.isUndef()) + return false; markOverdefined(); return true; } @@ -277,6 +310,9 @@ class ValueLatticeElement { } assert(isConstantRange() && "New ValueLattice type?"); + if (RHS.isUndef() && getConstantRange().isSingleElement()) + return false; + if (!RHS.isConstantRange()) { // We can get here if we've encountered a constantexpr of integer type // and merge it with a constantrange. @@ -292,12 +328,12 @@ class ValueLatticeElement { return markConstantRange(std::move(NewR)); } - /// Compares this symbolic value with Other using Pred and returns either + // Compares this symbolic value with Other using Pred and returns either /// true, false or undef constants, or nullptr if the comparison cannot be /// evaluated. Constant *getCompare(CmpInst::Predicate Pred, Type *Ty, const ValueLatticeElement &Other) const { - if (isUndefined() || Other.isUndefined()) + if (isUnknownOrUndef() || Other.isUnknownOrUndef()) return UndefValue::get(Ty); if (isConstant() && Other.isConstant()) diff --git a/llvm/lib/Analysis/LazyValueInfo.cpp b/llvm/lib/Analysis/LazyValueInfo.cpp index bad2de9e5f5e0..7ae7a1fd54937 100644 --- a/llvm/lib/Analysis/LazyValueInfo.cpp +++ b/llvm/lib/Analysis/LazyValueInfo.cpp @@ -96,9 +96,9 @@ static ValueLatticeElement intersect(const ValueLatticeElement &A, const ValueLatticeElement &B) { // Undefined is the strongest state. It means the value is known to be along // an unreachable path. - if (A.isUndefined()) + if (A.isUnknown()) return A; - if (B.isUndefined()) + if (B.isUnknown()) return B; // If we gave up for one, but got a useable fact from the other, use it. @@ -1203,7 +1203,7 @@ static ValueLatticeElement getValueFromICmpCondition(Value *Val, ICmpInst *ICI, // false SETNE. if (isTrueDest == (Predicate == ICmpInst::ICMP_EQ)) return ValueLatticeElement::get(cast(RHS)); - else + else if (!isa(RHS)) return ValueLatticeElement::getNot(cast(RHS)); } } @@ -1722,7 +1722,7 @@ ConstantRange LazyValueInfo::getConstantRange(Value *V, BasicBlock *BB, const DataLayout &DL = BB->getModule()->getDataLayout(); ValueLatticeElement Result = getImpl(PImpl, AC, &DL, DT).getValueInBlock(V, BB, CxtI); - if (Result.isUndefined()) + if (Result.isUnknown()) return ConstantRange::getEmpty(Width); if (Result.isConstantRange()) return Result.getConstantRange(); @@ -1761,7 +1761,7 @@ ConstantRange LazyValueInfo::getConstantRangeOnEdge(Value *V, ValueLatticeElement Result = getImpl(PImpl, AC, &DL, DT).getValueOnEdge(V, FromBB, ToBB, CxtI); - if (Result.isUndefined()) + if (Result.isUnknown()) return ConstantRange::getEmpty(Width); if (Result.isConstantRange()) return Result.getConstantRange(); @@ -1991,7 +1991,7 @@ void LazyValueInfoAnnotatedWriter::emitBasicBlockStartAnnot( for (auto &Arg : F->args()) { ValueLatticeElement Result = LVIImpl->getValueInBlock( const_cast(&Arg), const_cast(BB)); - if (Result.isUndefined()) + if (Result.isUnknown()) continue; OS << "; LatticeVal for: '" << Arg << "' is: " << Result << "\n"; } diff --git a/llvm/lib/Analysis/ValueLattice.cpp b/llvm/lib/Analysis/ValueLattice.cpp index a0115a0eec36c..eaf8885cc14ec 100644 --- a/llvm/lib/Analysis/ValueLattice.cpp +++ b/llvm/lib/Analysis/ValueLattice.cpp @@ -10,8 +10,10 @@ namespace llvm { raw_ostream &operator<<(raw_ostream &OS, const ValueLatticeElement &Val) { - if (Val.isUndefined()) - return OS << "undefined"; + if (Val.isUnknown()) + return OS << "unknown"; + if (Val.isUndef()) + return OS << "undef"; if (Val.isOverdefined()) return OS << "overdefined"; diff --git a/llvm/lib/Transforms/Scalar/SCCP.cpp b/llvm/lib/Transforms/Scalar/SCCP.cpp index 2d65b4d5f786a..dcdc3483a9088 100644 --- a/llvm/lib/Transforms/Scalar/SCCP.cpp +++ b/llvm/lib/Transforms/Scalar/SCCP.cpp @@ -434,19 +434,16 @@ class SCCPSolver : public InstVisitor { if (!I.second) return LV; // Common case, already in the map. - if (auto *C = dyn_cast(V)) { - // Undef values remain unknown. - if (!isa(V)) - LV.markConstant(C); // Constants are constant - } + if (auto *C = dyn_cast(V)) + LV.markConstant(C); // Constants are constant - // All others are underdefined by default. + // All others are unknown by default. return LV; } LatticeVal toLatticeVal(const ValueLatticeElement &V, Type *T) { LatticeVal Res; - if (V.isUndefined()) + if (V.isUnknownOrUndef()) return Res; if (V.isConstant()) { @@ -621,7 +618,7 @@ void SCCPSolver::getFeasibleSuccessors(Instruction &TI, if (!CI) { // Overdefined condition variables, and branches on unfoldable constant // conditions, mean the branch could go either way. - if (!BCValue.isUnknown()) + if (!BCValue.isUnknownOrUndef()) Succs[0] = Succs[1] = true; return; } @@ -647,7 +644,7 @@ void SCCPSolver::getFeasibleSuccessors(Instruction &TI, if (!CI) { // Overdefined or unknown condition? // All destinations are executable! - if (!SCValue.isUnknown()) + if (!SCValue.isUnknownOrUndef()) Succs.assign(TI.getNumSuccessors(), true); return; } @@ -664,7 +661,7 @@ void SCCPSolver::getFeasibleSuccessors(Instruction &TI, BlockAddress *Addr = dyn_cast_or_null(getConstant(IBRValue)); if (!Addr) { // Overdefined or unknown condition? // All destinations are executable! - if (!IBRValue.isUnknown()) + if (!IBRValue.isUnknownOrUndef()) Succs.assign(TI.getNumSuccessors(), true); return; } @@ -745,7 +742,7 @@ void SCCPSolver::visitPHINode(PHINode &PN) { Constant *OperandVal = nullptr; for (unsigned i = 0, e = PN.getNumIncomingValues(); i != e; ++i) { LatticeVal IV = getValueState(PN.getIncomingValue(i)); - if (IV.isUnknown()) continue; // Doesn't influence PHI node. + if (IV.isUnknownOrUndef()) continue; // Doesn't influence PHI node. if (!isEdgeFeasible(PN.getIncomingBlock(i), PN.getParent())) continue; @@ -833,7 +830,7 @@ void SCCPSolver::visitCastInst(CastInst &I) { return; // Propagate constant value markConstant(&I, C); - } else if (!OpSt.isUnknown()) + } else if (!OpSt.isUnknownOrUndef()) markOverdefined(&I); } @@ -913,7 +910,7 @@ void SCCPSolver::visitSelectInst(SelectInst &I) { return; LatticeVal CondValue = getValueState(I.getCondition()); - if (CondValue.isUnknown()) + if (CondValue.isUnknownOrUndef()) return; if (ConstantInt *CondCB = getConstantInt(CondValue)) { @@ -933,9 +930,9 @@ void SCCPSolver::visitSelectInst(SelectInst &I) { getConstant(TVal) == getConstant(FVal)) return (void)markConstant(&I, getConstant(FVal)); - if (TVal.isUnknown()) // select ?, undef, X -> X. + if (TVal.isUnknownOrUndef()) // select ?, undef, X -> X. return (void)mergeInValue(&I, FVal); - if (FVal.isUnknown()) // select ?, X, undef -> X. + if (FVal.isUnknownOrUndef()) // select ?, X, undef -> X. return (void)mergeInValue(&I, TVal); markOverdefined(&I); } @@ -986,7 +983,7 @@ void SCCPSolver::visitBinaryOperator(Instruction &I) { } // If something is undef, wait for it to resolve. - if (V1State.isUnknown() || V2State.isUnknown()) + if (V1State.isUnknownOrUndef() || V2State.isUnknownOrUndef()) return; // Otherwise, one of our operands is overdefined. Try to produce something @@ -1010,7 +1007,7 @@ void SCCPSolver::visitBinaryOperator(Instruction &I) { else if (!isOverdefined(V2State)) NonOverdefVal = &V2State; if (NonOverdefVal) { - if (NonOverdefVal->isUnknown()) + if (!isConstant(*NonOverdefVal)) return; if (I.getOpcode() == Instruction::And || @@ -1059,7 +1056,7 @@ void SCCPSolver::visitCmpInst(CmpInst &I) { } // If operands are still unknown, wait for it to resolve. - if ((V1State.isUnknown() || V2State.isUnknown()) && + if ((V1State.isUnknownOrUndef() || V2State.isUnknownOrUndef()) && !isConstant(ValueState[&I])) return; @@ -1076,7 +1073,7 @@ void SCCPSolver::visitGetElementPtrInst(GetElementPtrInst &I) { for (unsigned i = 0, e = I.getNumOperands(); i != e; ++i) { LatticeVal State = getValueState(I.getOperand(i)); - if (State.isUnknown()) + if (State.isUnknownOrUndef()) return; // Operands are not resolved yet. if (isOverdefined(State)) @@ -1136,7 +1133,8 @@ void SCCPSolver::visitLoadInst(LoadInst &I) { return; LatticeVal PtrVal = getValueState(I.getOperand(0)); - if (PtrVal.isUnknown()) return; // The pointer is not resolved yet! + if (PtrVal.isUnknownOrUndef()) + return; // The pointer is not resolved yet! LatticeVal &IV = ValueState[&I]; @@ -1260,7 +1258,7 @@ void SCCPSolver::visitCallSite(CallSite CS) { return markOverdefined(I); // Can't handle struct args. LatticeVal State = getValueState(*AI); - if (State.isUnknown()) + if (State.isUnknownOrUndef()) return; // Operands are not resolved yet. if (isOverdefined(State)) return (void)markOverdefined(I); @@ -1427,14 +1425,14 @@ bool SCCPSolver::ResolvedUndefsIn(Function &F) { // more precise than this but it isn't worth bothering. for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) { LatticeVal &LV = getStructValueState(&I, i); - if (LV.isUnknown()) + if (LV.isUnknownOrUndef()) markOverdefined(LV, &I); } continue; } LatticeVal &LV = getValueState(&I); - if (!LV.isUnknown()) + if (!LV.isUnknownOrUndef()) continue; // There are two reasons a call can have an undef result @@ -1464,7 +1462,7 @@ bool SCCPSolver::ResolvedUndefsIn(Function &F) { Instruction *TI = BB.getTerminator(); if (auto *BI = dyn_cast(TI)) { if (!BI->isConditional()) continue; - if (!getValueState(BI->getCondition()).isUnknown()) + if (!getValueState(BI->getCondition()).isUnknownOrUndef()) continue; // If the input to SCCP is actually branch on undef, fix the undef to @@ -1492,7 +1490,7 @@ bool SCCPSolver::ResolvedUndefsIn(Function &F) { if (IBR->getNumSuccessors() < 1) continue; - if (!getValueState(IBR->getAddress()).isUnknown()) + if (!getValueState(IBR->getAddress()).isUnknownOrUndef()) continue; // If the input to SCCP is actually branch on undef, fix the undef to @@ -1516,7 +1514,8 @@ bool SCCPSolver::ResolvedUndefsIn(Function &F) { } if (auto *SI = dyn_cast(TI)) { - if (!SI->getNumCases() || !getValueState(SI->getCondition()).isUnknown()) + if (!SI->getNumCases() || + !getValueState(SI->getCondition()).isUnknownOrUndef()) continue; // If the input to SCCP is actually switch on undef, fix the undef to diff --git a/llvm/test/Transforms/CorrelatedValuePropagation/merge-range-and-undef.ll b/llvm/test/Transforms/CorrelatedValuePropagation/merge-range-and-undef.ll index 3e8ef5461e7e6..ffc92f5ab45cb 100644 --- a/llvm/test/Transforms/CorrelatedValuePropagation/merge-range-and-undef.ll +++ b/llvm/test/Transforms/CorrelatedValuePropagation/merge-range-and-undef.ll @@ -47,7 +47,8 @@ define i64 @constant_range_and_undef(i1 %cond, i64 %a) { ; CHECK-NEXT: br label [[BB3]] ; CHECK: bb3: ; CHECK-NEXT: [[P:%.*]] = phi i64 [ undef, [[BB1]] ], [ [[R]], [[BB2]] ] -; CHECK-NEXT: ret i64 [[P]] +; CHECK-NEXT: [[RES:%.*]] = and i64 [[P]], 255 +; CHECK-NEXT: ret i64 [[RES]] ; entry: br i1 %cond, label %bb1, label %bb2 @@ -70,7 +71,7 @@ define i64 @constant_range_and_undef2(i1 %c1, i1 %c2, i64 %a) { ; CHECK-NEXT: entry: ; CHECK-NEXT: br i1 [[C1:%.*]], label [[BB1:%.*]], label [[BB2:%.*]] ; CHECK: bb1: -; CHECK-NEXT: [[V1:%.*]] = add nuw nsw i64 undef, undef +; CHECK-NEXT: [[V1:%.*]] = add i64 undef, undef ; CHECK-NEXT: br label [[BB3:%.*]] ; CHECK: bb2: ; CHECK-NEXT: [[V2:%.*]] = and i64 [[A:%.*]], 255 @@ -161,7 +162,8 @@ define i64 @constant_range_and_undef_3_incoming_v1(i1 %c1, i1 %c2, i64 %a) { ; CHECK-NEXT: br label [[BB4]] ; CHECK: bb4: ; CHECK-NEXT: [[P:%.*]] = phi i64 [ [[R]], [[BB1]] ], [ 10, [[BB2]] ], [ undef, [[BB3]] ] -; CHECK-NEXT: ret i64 [[P]] +; CHECK-NEXT: [[RES:%.*]] = and i64 [[P]], 255 +; CHECK-NEXT: ret i64 [[RES]] ; entry: br i1 %c1, label %bb1, label %bb2 @@ -233,7 +235,8 @@ define i64 @constant_range_and_undef_3_incoming_v3(i1 %c1, i1 %c2, i64 %a) { ; CHECK-NEXT: br label [[BB4]] ; CHECK: bb4: ; CHECK-NEXT: [[P:%.*]] = phi i64 [ [[R]], [[BB1]] ], [ undef, [[BB2]] ], [ 10, [[BB3]] ] -; CHECK-NEXT: ret i64 [[P]] +; CHECK-NEXT: [[RES:%.*]] = and i64 [[P]], 255 +; CHECK-NEXT: ret i64 [[RES]] ; entry: br i1 %c1, label %bb1, label %bb2 diff --git a/llvm/test/Transforms/JumpThreading/ne-undef.ll b/llvm/test/Transforms/JumpThreading/ne-undef.ll new file mode 100644 index 0000000000000..cf3c9db651f16 --- /dev/null +++ b/llvm/test/Transforms/JumpThreading/ne-undef.ll @@ -0,0 +1,61 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt -jump-threading -S %s | FileCheck %s + +declare i1 @cond() + +define hidden void @hoge(i1 %c1, i32 %x) { +; CHECK-LABEL: @hoge( +; CHECK-NEXT: bb: +; CHECK-NEXT: br label [[BB13:%.*]] +; CHECK: bb4: +; CHECK-NEXT: [[TMP3:%.*]] = icmp ne i32 [[TMP7:%.*]], undef +; CHECK-NEXT: br i1 [[TMP3]], label [[BB5:%.*]], label [[BB13]] +; CHECK: bb5: +; CHECK-NEXT: br label [[BB6:%.*]] +; CHECK: bb6: +; CHECK-NEXT: [[TMP7]] = phi i32 [ [[TMP7]], [[BB5]] ], [ [[X:%.*]], [[BB8:%.*]] ] +; CHECK-NEXT: [[C:%.*]] = call i1 @cond() +; CHECK-NEXT: br i1 [[C]], label [[BB4:%.*]], label [[BB8]] +; CHECK: bb8: +; CHECK-NEXT: br label [[BB6]] +; CHECK: bb13: +; CHECK-NEXT: ret void +; +bb: + br i1 false, label %bb1, label %bb13 + +bb1: ; preds = %bb + br label %bb2 + +bb2: ; preds = %bb12, %bb1 + %tmp = phi i32 [ 10, %bb1 ], [ %tmp7, %bb12 ] + %tmp3 = icmp ne i32 %tmp, undef + br label %bb4 + +bb4: ; preds = %bb2 + br i1 %tmp3, label %bb5, label %bb13 + +bb5: ; preds = %bb4 + br label %bb6 + +bb6: ; preds = %bb8, %bb5 + %tmp7 = phi i32 [ %tmp, %bb5 ], [ %x, %bb8 ] + %c = call i1 @cond() + br i1 %c, label %bb9, label %bb8 + +bb8: ; preds = %bb6 + br label %bb6 + +bb9: ; preds = %bb6 + br label %bb10 + +bb10: ; preds = %bb9 + br label %bb12 + +bb12: ; preds = %bb10 + br label %bb2 + +bb13: ; preds = %bb4 + ret void + +} diff --git a/llvm/test/Transforms/SCCP/float-phis.ll b/llvm/test/Transforms/SCCP/float-phis.ll new file mode 100644 index 0000000000000..8eef7fa5e0ffe --- /dev/null +++ b/llvm/test/Transforms/SCCP/float-phis.ll @@ -0,0 +1,26 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -sccp -S | FileCheck %s + +declare void @use(i1) + +define void @test(i1 %c) { +; CHECK-LABEL: @test( +; CHECK-NEXT: br label [[DO_BODY:%.*]] +; CHECK: do.body: +; CHECK-NEXT: br i1 [[C:%.*]], label [[DO_BODY]], label [[FOR_COND41:%.*]] +; CHECK: for.cond41: +; CHECK-NEXT: call void @use(i1 true) +; CHECK-NEXT: br label [[FOR_COND41]] +; + br label %do.body + +do.body: ; preds = %do.body, %entry + br i1 %c, label %do.body, label %for.cond41 + +for.cond41: ; preds = %for.cond41, %do.body + %mid.0 = phi float [ 0.000000e+00, %for.cond41 ], [ undef, %do.body ] + %fc = fcmp oeq float %mid.0, 0.000000e+00 + call void @use(i1 %fc) + + br label %for.cond41 +} diff --git a/llvm/test/Transforms/SCCP/int-phis.ll b/llvm/test/Transforms/SCCP/int-phis.ll new file mode 100644 index 0000000000000..64dddeb2d6bdb --- /dev/null +++ b/llvm/test/Transforms/SCCP/int-phis.ll @@ -0,0 +1,61 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -sccp -S | FileCheck %s + +declare void @use(i1) + +define void @read_dmatrix() #0 { +; CHECK-LABEL: @read_dmatrix( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[HEIGHT:%.*]] = alloca i32, align 4 +; CHECK-NEXT: br label [[FOR_COND:%.*]] +; CHECK: for.cond: +; CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* [[HEIGHT]], align 4 +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 0, [[TMP0]] +; CHECK-NEXT: br i1 [[CMP]], label [[FOR_COND6:%.*]], label [[FOR_END16:%.*]] +; CHECK: for.cond6: +; CHECK-NEXT: br label [[FOR_COND]] +; CHECK: for.end16: +; CHECK-NEXT: ret void +; +entry: + %height = alloca i32, align 4 + br label %for.cond + +for.cond: ; preds = %for.cond6, %entry + %j.0 = phi i32 [ undef, %entry ], [ 0, %for.cond6 ] + %0 = load i32, i32* %height, align 4 + %cmp = icmp slt i32 0, %0 + br i1 %cmp, label %for.cond6, label %for.end16 + +for.cond6: ; preds = %for.cond + br label %for.cond + +for.end16: ; preds = %for.cond + %sub21 = sub nsw i32 %j.0, 1 + ret void +} + +declare i1 @cond() + +define void @emptyTT() #0 { +; CHECK-LABEL: @emptyTT( +; CHECK-NEXT: entry: +; CHECK-NEXT: br label [[FOR_COND:%.*]] +; CHECK: for.cond: +; CHECK-NEXT: [[C:%.*]] = call i1 @cond() +; CHECK-NEXT: br i1 [[C]], label [[FOR_COND]], label [[EXIT:%.*]] +; CHECK: exit: +; CHECK-NEXT: ret void +; +entry: + br label %for.cond + +for.cond: ; preds = %for.cond, %entry + %.compoundliteral.sroa.0.0 = phi i64 [ undef, %entry ], [ 0, %for.cond ] + %bf.clear = and i64 %.compoundliteral.sroa.0.0, -67108864 + %c = call i1 @cond() + br i1 %c, label %for.cond, label %exit + +exit: + ret void +}