mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-25 12:12:47 +01:00
[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
This commit is contained in:
parent
89e0b77636
commit
4271526a2f
@ -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 @@ public:
|
||||
|
||||
/// 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 @@ public:
|
||||
ConstVal = Other.ConstVal;
|
||||
break;
|
||||
case overdefined:
|
||||
case undefined:
|
||||
case unknown:
|
||||
case undef:
|
||||
break;
|
||||
}
|
||||
Tag = Other.Tag;
|
||||
@ -118,14 +125,16 @@ public:
|
||||
|
||||
static ValueLatticeElement get(Constant *C) {
|
||||
ValueLatticeElement Res;
|
||||
if (!isa<UndefValue>(C))
|
||||
if (isa<UndefValue>(C))
|
||||
Res.markUndef();
|
||||
else
|
||||
Res.markConstant(C);
|
||||
return Res;
|
||||
}
|
||||
static ValueLatticeElement getNot(Constant *C) {
|
||||
ValueLatticeElement Res;
|
||||
if (!isa<UndefValue>(C))
|
||||
Res.markNotConstant(C);
|
||||
assert(!isa<UndefValue>(C) && "!= undef is not supported");
|
||||
Res.markNotConstant(C);
|
||||
return Res;
|
||||
}
|
||||
static ValueLatticeElement getRange(ConstantRange CR) {
|
||||
@ -139,8 +148,9 @@ public:
|
||||
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 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
bool markUndef() {
|
||||
if (isUndef())
|
||||
return false;
|
||||
|
||||
assert(isUnknown());
|
||||
Tag = undef;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool markConstant(Constant *V) {
|
||||
if (isa<UndefValue>(V))
|
||||
return false;
|
||||
return markUndef();
|
||||
|
||||
if (isConstant()) {
|
||||
assert(getConstant() == V && "Marking constant with different value");
|
||||
@ -194,7 +213,7 @@ public:
|
||||
if (ConstantInt *CI = dyn_cast<ConstantInt>(V))
|
||||
return markConstantRange(ConstantRange(CI->getValue()));
|
||||
|
||||
assert(isUndefined());
|
||||
assert(isUnknown() || isUndef());
|
||||
Tag = constant;
|
||||
ConstVal = V;
|
||||
return true;
|
||||
@ -214,7 +233,7 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
assert(isUndefined());
|
||||
assert(isUnknown());
|
||||
Tag = notconstant;
|
||||
ConstVal = V;
|
||||
return true;
|
||||
@ -223,7 +242,7 @@ public:
|
||||
/// 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 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
assert(isUndefined());
|
||||
assert(isUnknown() || isUndef());
|
||||
if (NewR.isEmptySet())
|
||||
return markOverdefined();
|
||||
|
||||
@ -250,21 +269,35 @@ public:
|
||||
/// 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 @@ public:
|
||||
}
|
||||
|
||||
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 @@ public:
|
||||
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())
|
||||
|
@ -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<Constant>(RHS));
|
||||
else
|
||||
else if (!isa<UndefValue>(RHS))
|
||||
return ValueLatticeElement::getNot(cast<Constant>(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<Argument *>(&Arg), const_cast<BasicBlock *>(BB));
|
||||
if (Result.isUndefined())
|
||||
if (Result.isUnknown())
|
||||
continue;
|
||||
OS << "; LatticeVal for: '" << Arg << "' is: " << Result << "\n";
|
||||
}
|
||||
|
@ -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";
|
||||
|
||||
|
@ -434,19 +434,16 @@ private:
|
||||
if (!I.second)
|
||||
return LV; // Common case, already in the map.
|
||||
|
||||
if (auto *C = dyn_cast<Constant>(V)) {
|
||||
// Undef values remain unknown.
|
||||
if (!isa<UndefValue>(V))
|
||||
LV.markConstant(C); // Constants are constant
|
||||
}
|
||||
if (auto *C = dyn_cast<Constant>(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<BlockAddress>(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 @@ CallOverdefined:
|
||||
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<BranchInst>(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<SwitchInst>(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
|
||||
|
@ -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
|
||||
|
61
test/Transforms/JumpThreading/ne-undef.ll
Normal file
61
test/Transforms/JumpThreading/ne-undef.ll
Normal file
@ -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
|
||||
|
||||
}
|
26
test/Transforms/SCCP/float-phis.ll
Normal file
26
test/Transforms/SCCP/float-phis.ll
Normal file
@ -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
|
||||
}
|
61
test/Transforms/SCCP/int-phis.ll
Normal file
61
test/Transforms/SCCP/int-phis.ll
Normal file
@ -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
|
||||
}
|
Loading…
Reference in New Issue
Block a user