mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-02-01 05:01:59 +01:00
Revert "[SCCP] Remove forcedconstant, go to overdefined instead"
This causes a crash for the reproducer below enum { a }; enum b { c, d }; e; static _Bool g(struct f *h, enum b i) { i &&j(); return a; } static k(char h, enum b i) { _Bool l = g(e, i); l; } m(h) { k(h, c); g(h, d); } This reverts commit aadb635e04854220064b77cc10d0e6772f5492fd.
This commit is contained in:
parent
7f1e47f301
commit
0a70c800cd
@ -85,13 +85,19 @@ class LatticeVal {
|
||||
/// constant - This LLVM Value has a specific constant value.
|
||||
constant,
|
||||
|
||||
/// forcedconstant - This LLVM Value was thought to be undef until
|
||||
/// ResolvedUndefsIn. This is treated just like 'constant', but if merged
|
||||
/// with another (different) constant, it goes to overdefined, instead of
|
||||
/// asserting.
|
||||
forcedconstant,
|
||||
|
||||
/// overdefined - This instruction is not known to be constant, and we know
|
||||
/// it has a value.
|
||||
overdefined
|
||||
};
|
||||
|
||||
/// Val: This stores the current lattice value along with the Constant* for
|
||||
/// the constant if this is a 'constant' value.
|
||||
/// the constant if this is a 'constant' or 'forcedconstant' value.
|
||||
PointerIntPair<Constant *, 2, LatticeValueTy> Val;
|
||||
|
||||
LatticeValueTy getLatticeValue() const {
|
||||
@ -103,7 +109,9 @@ public:
|
||||
|
||||
bool isUnknown() const { return getLatticeValue() == unknown; }
|
||||
|
||||
bool isConstant() const { return getLatticeValue() == constant; }
|
||||
bool isConstant() const {
|
||||
return getLatticeValue() == constant || getLatticeValue() == forcedconstant;
|
||||
}
|
||||
|
||||
bool isOverdefined() const { return getLatticeValue() == overdefined; }
|
||||
|
||||
@ -123,15 +131,26 @@ public:
|
||||
|
||||
/// markConstant - Return true if this is a change in status.
|
||||
bool markConstant(Constant *V) {
|
||||
if (getLatticeValue() == constant) { // Constant
|
||||
if (getLatticeValue() == constant) { // Constant but not forcedconstant.
|
||||
assert(getConstant() == V && "Marking constant with different value");
|
||||
return false;
|
||||
}
|
||||
|
||||
assert(isUnknown());
|
||||
Val.setInt(constant);
|
||||
assert(V && "Marking constant with NULL");
|
||||
Val.setPointer(V);
|
||||
if (isUnknown()) {
|
||||
Val.setInt(constant);
|
||||
assert(V && "Marking constant with NULL");
|
||||
Val.setPointer(V);
|
||||
} else {
|
||||
assert(getLatticeValue() == forcedconstant &&
|
||||
"Cannot move from overdefined to constant!");
|
||||
// Stay at forcedconstant if the constant is the same.
|
||||
if (V == getConstant()) return false;
|
||||
|
||||
// Otherwise, we go to overdefined. Assumptions made based on the
|
||||
// forced value are possibly wrong. Assuming this is another constant
|
||||
// could expose a contradiction.
|
||||
Val.setInt(overdefined);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -151,6 +170,12 @@ public:
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void markForcedConstant(Constant *V) {
|
||||
assert(isUnknown() && "Can't force a defined value!");
|
||||
Val.setInt(forcedconstant);
|
||||
Val.setPointer(V);
|
||||
}
|
||||
|
||||
ValueLatticeElement toValueLattice() const {
|
||||
if (isOverdefined())
|
||||
return ValueLatticeElement::getOverdefined();
|
||||
@ -396,7 +421,7 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
// pushToWorkList - Helper for markConstant/markOverdefined
|
||||
// pushToWorkList - Helper for markConstant/markForcedConstant/markOverdefined
|
||||
void pushToWorkList(LatticeVal &IV, Value *V) {
|
||||
if (IV.isOverdefined())
|
||||
return OverdefinedInstWorkList.push_back(V);
|
||||
@ -418,6 +443,14 @@ private:
|
||||
return markConstant(ValueState[V], V, C);
|
||||
}
|
||||
|
||||
void markForcedConstant(Value *V, Constant *C) {
|
||||
assert(!V->getType()->isStructTy() && "structs should use mergeInValue");
|
||||
LatticeVal &IV = ValueState[V];
|
||||
IV.markForcedConstant(C);
|
||||
LLVM_DEBUG(dbgs() << "markForcedConstant: " << *C << ": " << *V << '\n');
|
||||
pushToWorkList(IV, V);
|
||||
}
|
||||
|
||||
// markOverdefined - Make a value be marked as "overdefined". If the
|
||||
// value is not already overdefined, add it to the overdefined instruction
|
||||
// work list so that the users of the instruction are updated later.
|
||||
@ -999,10 +1032,8 @@ void SCCPSolver::visitBinaryOperator(Instruction &I) {
|
||||
}
|
||||
|
||||
// If something is undef, wait for it to resolve.
|
||||
if (!V1State.isOverdefined() && !V2State.isOverdefined()) {
|
||||
|
||||
if (!V1State.isOverdefined() && !V2State.isOverdefined())
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise, one of our operands is overdefined. Try to produce something
|
||||
// better than overdefined with some tricks.
|
||||
@ -1418,8 +1449,10 @@ void SCCPSolver::Solve() {
|
||||
/// constraints on the condition of the branch, as that would impact other users
|
||||
/// of the value.
|
||||
///
|
||||
/// This scan also checks for values that use undefs. It conservatively marks
|
||||
/// them as overdefined.
|
||||
/// This scan also checks for values that use undefs, whose results are actually
|
||||
/// defined. For example, 'zext i8 undef to i32' should produce all zeros
|
||||
/// conservatively, as "(zext i8 X -> i32) & 0xFF00" must always return zero,
|
||||
/// even if X isn't defined.
|
||||
bool SCCPSolver::ResolvedUndefsIn(Function &F) {
|
||||
for (BasicBlock &BB : F) {
|
||||
if (!BBExecutable.count(&BB))
|
||||
@ -1442,6 +1475,7 @@ bool SCCPSolver::ResolvedUndefsIn(Function &F) {
|
||||
// tracked as precisely as their operands.
|
||||
if (isa<ExtractValueInst>(I) || isa<InsertValueInst>(I))
|
||||
continue;
|
||||
|
||||
// Send the results of everything else to overdefined. We could be
|
||||
// more precise than this but it isn't worth bothering.
|
||||
for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) {
|
||||
@ -1461,13 +1495,195 @@ bool SCCPSolver::ResolvedUndefsIn(Function &F) {
|
||||
// 2. It could be constant-foldable.
|
||||
// Because of the way we solve return values, tracked calls must
|
||||
// never be marked overdefined in ResolvedUndefsIn.
|
||||
if (CallSite CS = CallSite(&I))
|
||||
if (CallSite CS = CallSite(&I)) {
|
||||
if (Function *F = CS.getCalledFunction())
|
||||
if (TrackedRetVals.count(F))
|
||||
continue;
|
||||
|
||||
markOverdefined(&I);
|
||||
return true;
|
||||
// If the call is constant-foldable, we mark it overdefined because
|
||||
// we do not know what return values are valid.
|
||||
markOverdefined(&I);
|
||||
return true;
|
||||
}
|
||||
|
||||
// extractvalue is safe; check here because the argument is a struct.
|
||||
if (isa<ExtractValueInst>(I))
|
||||
continue;
|
||||
|
||||
// Compute the operand LatticeVals, for convenience below.
|
||||
// Anything taking a struct is conservatively assumed to require
|
||||
// overdefined markings.
|
||||
if (I.getOperand(0)->getType()->isStructTy()) {
|
||||
markOverdefined(&I);
|
||||
return true;
|
||||
}
|
||||
LatticeVal Op0LV = getValueState(I.getOperand(0));
|
||||
LatticeVal Op1LV;
|
||||
if (I.getNumOperands() == 2) {
|
||||
if (I.getOperand(1)->getType()->isStructTy()) {
|
||||
markOverdefined(&I);
|
||||
return true;
|
||||
}
|
||||
|
||||
Op1LV = getValueState(I.getOperand(1));
|
||||
}
|
||||
// If this is an instructions whose result is defined even if the input is
|
||||
// not fully defined, propagate the information.
|
||||
Type *ITy = I.getType();
|
||||
switch (I.getOpcode()) {
|
||||
case Instruction::Add:
|
||||
case Instruction::Sub:
|
||||
case Instruction::Trunc:
|
||||
case Instruction::FPTrunc:
|
||||
case Instruction::BitCast:
|
||||
break; // Any undef -> undef
|
||||
case Instruction::FSub:
|
||||
case Instruction::FAdd:
|
||||
case Instruction::FMul:
|
||||
case Instruction::FDiv:
|
||||
case Instruction::FRem:
|
||||
// Floating-point binary operation: be conservative.
|
||||
if (Op0LV.isUnknown() && Op1LV.isUnknown())
|
||||
markForcedConstant(&I, Constant::getNullValue(ITy));
|
||||
else
|
||||
markOverdefined(&I);
|
||||
return true;
|
||||
case Instruction::FNeg:
|
||||
break; // fneg undef -> undef
|
||||
case Instruction::ZExt:
|
||||
case Instruction::SExt:
|
||||
case Instruction::FPToUI:
|
||||
case Instruction::FPToSI:
|
||||
case Instruction::FPExt:
|
||||
case Instruction::PtrToInt:
|
||||
case Instruction::IntToPtr:
|
||||
case Instruction::SIToFP:
|
||||
case Instruction::UIToFP:
|
||||
// undef -> 0; some outputs are impossible
|
||||
markForcedConstant(&I, Constant::getNullValue(ITy));
|
||||
return true;
|
||||
case Instruction::Mul:
|
||||
case Instruction::And:
|
||||
// Both operands undef -> undef
|
||||
if (Op0LV.isUnknown() && Op1LV.isUnknown())
|
||||
break;
|
||||
// undef * X -> 0. X could be zero.
|
||||
// undef & X -> 0. X could be zero.
|
||||
markForcedConstant(&I, Constant::getNullValue(ITy));
|
||||
return true;
|
||||
case Instruction::Or:
|
||||
// Both operands undef -> undef
|
||||
if (Op0LV.isUnknown() && Op1LV.isUnknown())
|
||||
break;
|
||||
// undef | X -> -1. X could be -1.
|
||||
markForcedConstant(&I, Constant::getAllOnesValue(ITy));
|
||||
return true;
|
||||
case Instruction::Xor:
|
||||
// undef ^ undef -> 0; strictly speaking, this is not strictly
|
||||
// necessary, but we try to be nice to people who expect this
|
||||
// behavior in simple cases
|
||||
if (Op0LV.isUnknown() && Op1LV.isUnknown()) {
|
||||
markForcedConstant(&I, Constant::getNullValue(ITy));
|
||||
return true;
|
||||
}
|
||||
// undef ^ X -> undef
|
||||
break;
|
||||
case Instruction::SDiv:
|
||||
case Instruction::UDiv:
|
||||
case Instruction::SRem:
|
||||
case Instruction::URem:
|
||||
// X / undef -> undef. No change.
|
||||
// X % undef -> undef. No change.
|
||||
if (Op1LV.isUnknown()) break;
|
||||
|
||||
// X / 0 -> undef. No change.
|
||||
// X % 0 -> undef. No change.
|
||||
if (Op1LV.isConstant() && Op1LV.getConstant()->isZeroValue())
|
||||
break;
|
||||
|
||||
// undef / X -> 0. X could be maxint.
|
||||
// undef % X -> 0. X could be 1.
|
||||
markForcedConstant(&I, Constant::getNullValue(ITy));
|
||||
return true;
|
||||
case Instruction::AShr:
|
||||
// X >>a undef -> undef.
|
||||
if (Op1LV.isUnknown()) break;
|
||||
|
||||
// Shifting by the bitwidth or more is undefined.
|
||||
if (Op1LV.isConstant()) {
|
||||
if (auto *ShiftAmt = Op1LV.getConstantInt())
|
||||
if (ShiftAmt->getLimitedValue() >=
|
||||
ShiftAmt->getType()->getScalarSizeInBits())
|
||||
break;
|
||||
}
|
||||
|
||||
// undef >>a X -> 0
|
||||
markForcedConstant(&I, Constant::getNullValue(ITy));
|
||||
return true;
|
||||
case Instruction::LShr:
|
||||
case Instruction::Shl:
|
||||
// X << undef -> undef.
|
||||
// X >> undef -> undef.
|
||||
if (Op1LV.isUnknown()) break;
|
||||
|
||||
// Shifting by the bitwidth or more is undefined.
|
||||
if (Op1LV.isConstant()) {
|
||||
if (auto *ShiftAmt = Op1LV.getConstantInt())
|
||||
if (ShiftAmt->getLimitedValue() >=
|
||||
ShiftAmt->getType()->getScalarSizeInBits())
|
||||
break;
|
||||
}
|
||||
|
||||
// undef << X -> 0
|
||||
// undef >> X -> 0
|
||||
markForcedConstant(&I, Constant::getNullValue(ITy));
|
||||
return true;
|
||||
case Instruction::Select:
|
||||
Op1LV = getValueState(I.getOperand(1));
|
||||
// undef ? X : Y -> X or Y. There could be commonality between X/Y.
|
||||
if (Op0LV.isUnknown()) {
|
||||
if (!Op1LV.isConstant()) // Pick the constant one if there is any.
|
||||
Op1LV = getValueState(I.getOperand(2));
|
||||
} else if (Op1LV.isUnknown()) {
|
||||
// c ? undef : undef -> undef. No change.
|
||||
Op1LV = getValueState(I.getOperand(2));
|
||||
if (Op1LV.isUnknown())
|
||||
break;
|
||||
// Otherwise, c ? undef : x -> x.
|
||||
} else {
|
||||
// Leave Op1LV as Operand(1)'s LatticeValue.
|
||||
}
|
||||
|
||||
if (Op1LV.isConstant())
|
||||
markForcedConstant(&I, Op1LV.getConstant());
|
||||
else
|
||||
markOverdefined(&I);
|
||||
return true;
|
||||
case Instruction::Load:
|
||||
// A load here means one of two things: a load of undef from a global,
|
||||
// a load from an unknown pointer. Either way, having it return undef
|
||||
// is okay.
|
||||
break;
|
||||
case Instruction::ICmp:
|
||||
// X == undef -> undef. Other comparisons get more complicated.
|
||||
Op0LV = getValueState(I.getOperand(0));
|
||||
Op1LV = getValueState(I.getOperand(1));
|
||||
|
||||
if ((Op0LV.isUnknown() || Op1LV.isUnknown()) &&
|
||||
cast<ICmpInst>(&I)->isEquality())
|
||||
break;
|
||||
markOverdefined(&I);
|
||||
return true;
|
||||
case Instruction::Call:
|
||||
case Instruction::Invoke:
|
||||
case Instruction::CallBr:
|
||||
llvm_unreachable("Call-like instructions should have be handled early");
|
||||
default:
|
||||
// If we don't know what should happen here, conservatively mark it
|
||||
// overdefined.
|
||||
markOverdefined(&I);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Check to see if we have a branch or switch on an undefined value. If so
|
||||
|
@ -1,4 +1,4 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
|
||||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
|
||||
; RUN: opt < %s -S -ipsccp | FileCheck %s
|
||||
|
||||
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
|
||||
@ -7,9 +7,7 @@ target triple = "x86_64-unknown-linux-gnu"
|
||||
define i64 @fn2() {
|
||||
; CHECK-LABEL: define {{[^@]+}}@fn2()
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: [[CONV:%.*]] = sext i32 undef to i64
|
||||
; CHECK-NEXT: [[DIV:%.*]] = sdiv i64 8, [[CONV]]
|
||||
; CHECK-NEXT: [[CALL2:%.*]] = call i64 @fn1(i64 [[DIV]])
|
||||
; CHECK-NEXT: [[CALL2:%.*]] = call i64 @fn1(i64 undef)
|
||||
; CHECK-NEXT: ret i64 [[CALL2]]
|
||||
;
|
||||
entry:
|
||||
@ -23,8 +21,7 @@ define internal i64 @fn1(i64 %p1) {
|
||||
; CHECK-LABEL: define {{[^@]+}}@fn1
|
||||
; CHECK-SAME: (i64 [[P1:%.*]])
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i64 [[P1]], 0
|
||||
; CHECK-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i64 [[P1]], i64 [[P1]]
|
||||
; CHECK-NEXT: [[COND:%.*]] = select i1 undef, i64 undef, i64 undef
|
||||
; CHECK-NEXT: ret i64 [[COND]]
|
||||
;
|
||||
entry:
|
||||
|
@ -11,8 +11,7 @@ define void @fn2(i32* %P) {
|
||||
; CHECK: for.cond1:
|
||||
; CHECK-NEXT: br i1 false, label [[IF_END]], label [[IF_END]]
|
||||
; CHECK: if.end:
|
||||
; CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* null, align 4
|
||||
; CHECK-NEXT: [[CALL:%.*]] = call i32 @fn1(i32 [[TMP0]])
|
||||
; CHECK-NEXT: [[CALL:%.*]] = call i32 @fn1(i32 undef)
|
||||
; CHECK-NEXT: store i32 [[CALL]], i32* [[P]]
|
||||
; CHECK-NEXT: br label [[FOR_COND1:%.*]]
|
||||
;
|
||||
@ -34,8 +33,7 @@ define internal i32 @fn1(i32 %p1) {
|
||||
; CHECK-LABEL: define {{[^@]+}}@fn1
|
||||
; CHECK-SAME: (i32 [[P1:%.*]])
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i32 [[P1]], 0
|
||||
; CHECK-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i32 [[P1]], i32 [[P1]]
|
||||
; CHECK-NEXT: [[COND:%.*]] = select i1 undef, i32 undef, i32 undef
|
||||
; CHECK-NEXT: ret i32 [[COND]]
|
||||
;
|
||||
entry:
|
||||
|
@ -1,12 +1,8 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
||||
; RUN: opt < %s -sccp -S | FileCheck %s
|
||||
; RUN: opt < %s -sccp -S | \
|
||||
; RUN: grep "ret i1 false"
|
||||
|
||||
define i1 @foo() {
|
||||
; CHECK-LABEL: @foo(
|
||||
; CHECK-NEXT: [[X:%.*]] = and i1 false, undef
|
||||
; CHECK-NEXT: ret i1 [[X]]
|
||||
;
|
||||
%X = and i1 false, undef ; <i1> [#uses=1]
|
||||
ret i1 %X
|
||||
%X = and i1 false, undef ; <i1> [#uses=1]
|
||||
ret i1 %X
|
||||
}
|
||||
|
||||
|
@ -18,13 +18,7 @@ define i101 @array() {
|
||||
}
|
||||
|
||||
; CHECK-LABEL: @large_aggregate
|
||||
; CHECK-NEXT: %B = load i101, i101* undef
|
||||
; CHECK-NEXT: %D = and i101 %B, 1
|
||||
; CHECK-NEXT: %DD = or i101 %D, 1
|
||||
; CHECK-NEXT: %G = getelementptr i101, i101* getelementptr inbounds ([6 x i101], [6 x i101]* @Y, i32 0, i32 5), i101 %DD
|
||||
; CHECK-NEXT: %L3 = load i101, i101* %G
|
||||
; CHECK-NEXT: ret i101 %L3
|
||||
;
|
||||
; CHECK-NEXT: ret i101 undef
|
||||
define i101 @large_aggregate() {
|
||||
%B = load i101, i101* undef
|
||||
%D = and i101 %B, 1
|
||||
@ -35,22 +29,6 @@ define i101 @large_aggregate() {
|
||||
ret i101 %L3
|
||||
}
|
||||
|
||||
; CHECK-LABEL: define i101 @large_aggregate_2() {
|
||||
; CHECK-NEXT: %D = and i101 undef, 1
|
||||
; CHECK-NEXT: %DD = or i101 %D, 1
|
||||
; CHECK-NEXT: %G = getelementptr i101, i101* getelementptr inbounds ([6 x i101], [6 x i101]* @Y, i32 0, i32 5), i101 %DD
|
||||
; CHECK-NEXT: %L3 = load i101, i101* %G
|
||||
; CHECK-NEXT: ret i101 %L3
|
||||
;
|
||||
define i101 @large_aggregate_2() {
|
||||
%D = and i101 undef, 1
|
||||
%DD = or i101 %D, 1
|
||||
%F = getelementptr [6 x i101], [6 x i101]* @Y, i32 0, i32 5
|
||||
%G = getelementptr i101, i101* %F, i101 %DD
|
||||
%L3 = load i101, i101* %G
|
||||
ret i101 %L3
|
||||
}
|
||||
|
||||
; CHECK-LABEL: @index_too_large
|
||||
; CHECK-NEXT: store i101* getelementptr (i101, i101* getelementptr ([6 x i101], [6 x i101]* @Y, i32 0, i32 -1), i101 9224497936761618431), i101** undef
|
||||
; CHECK-NEXT: ret void
|
||||
|
@ -1,39 +1,23 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
||||
; RUN: opt < %s -ipsccp -S | FileCheck %s
|
||||
; RUN: opt < %s -ipsccp -S | not grep global
|
||||
|
||||
@G = internal global i66 undef
|
||||
|
||||
|
||||
|
||||
define void @foo() {
|
||||
; CHECK-LABEL: @foo(
|
||||
; CHECK-NEXT: [[X:%.*]] = load i66, i66* @G
|
||||
; CHECK-NEXT: store i66 [[X]], i66* @G
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
%X = load i66, i66* @G
|
||||
store i66 %X, i66* @G
|
||||
ret void
|
||||
%X = load i66, i66* @G
|
||||
store i66 %X, i66* @G
|
||||
ret void
|
||||
}
|
||||
|
||||
define i66 @bar() {
|
||||
; CHECK-LABEL: @bar(
|
||||
; CHECK-NEXT: [[V:%.*]] = load i66, i66* @G
|
||||
; CHECK-NEXT: [[C:%.*]] = icmp eq i66 [[V]], 17
|
||||
; CHECK-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
|
||||
; CHECK: T:
|
||||
; CHECK-NEXT: store i66 17, i66* @G
|
||||
; CHECK-NEXT: ret i66 17
|
||||
; CHECK: F:
|
||||
; CHECK-NEXT: store i66 123, i66* @G
|
||||
; CHECK-NEXT: ret i66 0
|
||||
;
|
||||
%V = load i66, i66* @G
|
||||
%C = icmp eq i66 %V, 17
|
||||
br i1 %C, label %T, label %F
|
||||
%V = load i66, i66* @G
|
||||
%C = icmp eq i66 %V, 17
|
||||
br i1 %C, label %T, label %F
|
||||
T:
|
||||
store i66 17, i66* @G
|
||||
ret i66 %V
|
||||
store i66 17, i66* @G
|
||||
ret i66 %V
|
||||
F:
|
||||
store i66 123, i66* @G
|
||||
ret i66 0
|
||||
store i66 123, i66* @G
|
||||
ret i66 0
|
||||
}
|
||||
|
@ -1,29 +1,21 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
||||
; RUN: opt < %s -sccp -S | FileCheck %s
|
||||
; RUN: opt < %s -sccp -S | not grep select
|
||||
|
||||
@A = constant i32 10
|
||||
|
||||
define i712 @test1() {
|
||||
; CHECK-LABEL: @test1(
|
||||
; CHECK-NEXT: [[BB:%.*]] = and i64 ptrtoint (i32* @A to i64), undef
|
||||
; CHECK-NEXT: [[C:%.*]] = icmp sge i64 [[BB]], 0
|
||||
; CHECK-NEXT: [[X:%.*]] = select i1 [[C]], i712 0, i712 1
|
||||
; CHECK-NEXT: ret i712 [[X]]
|
||||
;
|
||||
%P = getelementptr i32, i32* @A, i32 0
|
||||
%B = ptrtoint i32* %P to i64
|
||||
%BB = and i64 %B, undef
|
||||
%C = icmp sge i64 %BB, 0
|
||||
%X = select i1 %C, i712 0, i712 1
|
||||
ret i712 %X
|
||||
%P = getelementptr i32, i32* @A, i32 0
|
||||
%B = ptrtoint i32* %P to i64
|
||||
%BB = and i64 %B, undef
|
||||
%C = icmp sge i64 %BB, 0
|
||||
%X = select i1 %C, i712 0, i712 1
|
||||
ret i712 %X
|
||||
}
|
||||
|
||||
|
||||
|
||||
define i712 @test2(i1 %C) {
|
||||
; CHECK-LABEL: @test2(
|
||||
; CHECK-NEXT: ret i712 0
|
||||
;
|
||||
%X = select i1 %C, i712 0, i712 undef
|
||||
ret i712 %X
|
||||
%X = select i1 %C, i712 0, i712 undef
|
||||
ret i712 %X
|
||||
}
|
||||
|
||||
|
||||
|
@ -141,12 +141,10 @@ define double @test_struct({ double, double } %test) {
|
||||
; Constant range for %x is [47, 302)
|
||||
; CHECK-LABEL: @f5
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: %cmp = icmp sgt i32 %x, undef
|
||||
; CHECK-NEXT: %cmp2 = icmp ne i32 undef, %x
|
||||
; CHECK-NEXT: %res1 = select i1 %cmp, i32 1, i32 2
|
||||
; CHECK-NEXT: %res2 = select i1 %cmp2, i32 3, i32 4
|
||||
; CHECK-NEXT: %res = add i32 %res1, %res2
|
||||
; CHECK-NEXT: ret i32 %res
|
||||
; CHECK-NEXT: %cmp = icmp sgt i32 %x, undef
|
||||
; CHECK-NEXT: %res1 = select i1 %cmp, i32 1, i32 2
|
||||
; CHECK-NEXT: %res = add i32 %res1, 3
|
||||
; CHECK-NEXT: ret i32 %res
|
||||
define internal i32 @f5(i32 %x) {
|
||||
entry:
|
||||
%cmp = icmp sgt i32 %x, undef
|
||||
|
@ -56,9 +56,7 @@ define void @test3a() {
|
||||
ret void
|
||||
}
|
||||
; CHECK-LABEL: define void @test3a(
|
||||
; CHECK-NEXT: %X = load i32, i32* @G
|
||||
; CHECK-NEXT: store i32 %X, i32* @G
|
||||
; CHECK-NEXT: ret void
|
||||
; CHECK-NEXT: ret void
|
||||
|
||||
|
||||
define i32 @test3b() {
|
||||
@ -73,17 +71,9 @@ F:
|
||||
ret i32 0
|
||||
}
|
||||
; CHECK-LABEL: define i32 @test3b(
|
||||
; CHECK-NEXT: %V = load i32, i32* @G
|
||||
; CHECK-NEXT: %C = icmp eq i32 %V, 17
|
||||
; CHECK-NEXT: br i1 %C, label %T, label %F
|
||||
; CHECK-NOT: store
|
||||
; CHECK: ret i32 0
|
||||
|
||||
; CHECK-LABEL: T:
|
||||
; CHECK-NEXT: store i32 17, i32* @G
|
||||
; CHECK-NEXT: ret i32 17
|
||||
|
||||
; CHECK-LABEL: F:
|
||||
; CHECK-NEXT: store i32 123, i32* @G
|
||||
; CHECK-NEXT: ret i32 0
|
||||
|
||||
;;======================== test4
|
||||
|
||||
@ -236,11 +226,8 @@ define i32 @test10a() nounwind {
|
||||
entry:
|
||||
%call = call i32 @test10b(i32 undef)
|
||||
ret i32 %call
|
||||
|
||||
; CHECK-LABEL: define i32 @test10a(
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: %call = call i32 @test10b(i32 undef)
|
||||
; CHECK-NEXT: ret i32 %call
|
||||
; CHECK: ret i32 0
|
||||
}
|
||||
|
||||
define internal i32 @test10b(i32 %x) nounwind {
|
||||
@ -248,9 +235,7 @@ entry:
|
||||
%r = and i32 %x, 1
|
||||
ret i32 %r
|
||||
; CHECK-LABEL: define internal i32 @test10b(
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: %r = and i32 undef, 1
|
||||
; CHECK-NEXT: ret i32 %r
|
||||
; CHECK: ret i32 undef
|
||||
}
|
||||
|
||||
;;======================== test11
|
||||
@ -259,8 +244,7 @@ define i64 @test11a() {
|
||||
%xor = xor i64 undef, undef
|
||||
ret i64 %xor
|
||||
; CHECK-LABEL: define i64 @test11a
|
||||
; CHECK-NEXT: %xor = xor i64 undef, undef
|
||||
; CHECK-NEXT: ret i64 %xor
|
||||
; CHECK: ret i64 0
|
||||
}
|
||||
|
||||
define i64 @test11b() {
|
||||
@ -268,9 +252,9 @@ define i64 @test11b() {
|
||||
%call2 = call i64 @llvm.ctpop.i64(i64 %call1)
|
||||
ret i64 %call2
|
||||
; CHECK-LABEL: define i64 @test11b
|
||||
; CHECK-NEXT: [[call1:%.*]] = call i64 @test11a()
|
||||
; CHECK-NEXT: [[call2:%.*]] = call i64 @llvm.ctpop.i64(i64 [[call1]])
|
||||
; CHECK-NEXT: ret i64 [[call2]]
|
||||
; CHECK: %[[call1:.*]] = call i64 @test11a()
|
||||
; CHECK-NOT: call i64 @llvm.ctpop.i64
|
||||
; CHECK-NEXT: ret i64 0
|
||||
}
|
||||
|
||||
declare i64 @llvm.ctpop.i64(i64)
|
||||
|
@ -1,47 +1,39 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
||||
; RUN: opt < %s -sccp -S | FileCheck %s
|
||||
|
||||
; Test that SCCP has basic knowledge of when and/or/mul nuke overdefined values.
|
||||
|
||||
; CHECK-LABEL: test
|
||||
; CHECK: ret i32 0
|
||||
define i32 @test(i32 %X) {
|
||||
; CHECK-LABEL: @test(
|
||||
; CHECK-NEXT: ret i32 0
|
||||
;
|
||||
%Y = and i32 %X, 0
|
||||
ret i32 %Y
|
||||
}
|
||||
|
||||
; CHECK-LABEL: test2
|
||||
; CHECK: ret i32 -1
|
||||
define i32 @test2(i32 %X) {
|
||||
; CHECK-LABEL: @test2(
|
||||
; CHECK-NEXT: ret i32 -1
|
||||
;
|
||||
%Y = or i32 -1, %X
|
||||
ret i32 %Y
|
||||
}
|
||||
|
||||
; CHECK-LABEL: test3
|
||||
; CHECK: ret i32 0
|
||||
define i32 @test3(i32 %X) {
|
||||
; CHECK-LABEL: @test3(
|
||||
; CHECK-NEXT: [[Y:%.*]] = and i32 undef, [[X:%.*]]
|
||||
; CHECK-NEXT: ret i32 [[Y]]
|
||||
;
|
||||
%Y = and i32 undef, %X
|
||||
ret i32 %Y
|
||||
}
|
||||
|
||||
; CHECK-LABEL: test4
|
||||
; CHECK: ret i32 -1
|
||||
define i32 @test4(i32 %X) {
|
||||
; CHECK-LABEL: @test4(
|
||||
; CHECK-NEXT: [[Y:%.*]] = or i32 [[X:%.*]], undef
|
||||
; CHECK-NEXT: ret i32 [[Y]]
|
||||
;
|
||||
%Y = or i32 %X, undef
|
||||
ret i32 %Y
|
||||
}
|
||||
|
||||
; X * 0 = 0 even if X is overdefined.
|
||||
; CHECK-LABEL: test5
|
||||
; CHECK: ret i32 0
|
||||
define i32 @test5(i32 %foo) {
|
||||
; CHECK-LABEL: @test5(
|
||||
; CHECK-NEXT: ret i32 0
|
||||
;
|
||||
%patatino = mul i32 %foo, 0
|
||||
ret i32 %patatino
|
||||
}
|
||||
|
@ -1,4 +1,3 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
||||
; RUN: opt -S -ipsccp < %s | FileCheck %s
|
||||
|
||||
declare void @foo()
|
||||
@ -6,25 +5,9 @@ declare void @goo()
|
||||
declare void @patatino()
|
||||
|
||||
define void @test1(i32 %t) {
|
||||
; CHECK-LABEL: @test1(
|
||||
; CHECK-NEXT: [[CHOICE:%.*]] = icmp eq i32 undef, -1
|
||||
; CHECK-NEXT: switch i1 [[CHOICE]], label [[FIRST:%.*]] [
|
||||
; CHECK-NEXT: i1 false, label [[SECOND:%.*]]
|
||||
; CHECK-NEXT: i1 true, label [[THIRD:%.*]]
|
||||
; CHECK-NEXT: ]
|
||||
; CHECK: first:
|
||||
; CHECK-NEXT: call void @foo()
|
||||
; CHECK-NEXT: ret void
|
||||
; CHECK: second:
|
||||
; CHECK-NEXT: call void @goo()
|
||||
; CHECK-NEXT: ret void
|
||||
; CHECK: third:
|
||||
; CHECK-NEXT: call void @patatino()
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
%choice = icmp eq i32 undef, -1
|
||||
switch i1 %choice, label %first [i1 0, label %second
|
||||
i1 1, label %third]
|
||||
i1 1, label %third]
|
||||
first:
|
||||
call void @foo()
|
||||
ret void
|
||||
@ -35,3 +18,10 @@ third:
|
||||
call void @patatino()
|
||||
ret void
|
||||
}
|
||||
|
||||
; CHECK: define void @test1(i32 %t) {
|
||||
; CHECK-NEXT: br label %second
|
||||
; CHECK: second:
|
||||
; CHECK-NEXT: call void @goo()
|
||||
; CHECK-NEXT: ret void
|
||||
; CHECK-NEXT: }
|
||||
|
@ -1,89 +1,68 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
||||
; RUN: opt < %s -sccp -S | FileCheck %s
|
||||
|
||||
; CHECK-LABEL: shift_undef_64
|
||||
define void @shift_undef_64(i64* %p) {
|
||||
; CHECK-LABEL: @shift_undef_64(
|
||||
; CHECK-NEXT: [[R1:%.*]] = lshr i64 -1, 4294967296
|
||||
; CHECK-NEXT: store i64 [[R1]], i64* [[P:%.*]]
|
||||
; CHECK-NEXT: [[R2:%.*]] = ashr i64 -1, 4294967297
|
||||
; CHECK-NEXT: store i64 [[R2]], i64* [[P]]
|
||||
; CHECK-NEXT: [[R3:%.*]] = shl i64 -1, 4294967298
|
||||
; CHECK-NEXT: store i64 [[R3]], i64* [[P]]
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
%r1 = lshr i64 -1, 4294967296 ; 2^32
|
||||
; CHECK: store i64 undef
|
||||
store i64 %r1, i64* %p
|
||||
|
||||
%r2 = ashr i64 -1, 4294967297 ; 2^32 + 1
|
||||
; CHECK: store i64 undef
|
||||
store i64 %r2, i64* %p
|
||||
|
||||
%r3 = shl i64 -1, 4294967298 ; 2^32 + 2
|
||||
; CHECK: store i64 undef
|
||||
store i64 %r3, i64* %p
|
||||
|
||||
ret void
|
||||
}
|
||||
|
||||
; CHECK-LABEL: shift_undef_65
|
||||
define void @shift_undef_65(i65* %p) {
|
||||
; CHECK-LABEL: @shift_undef_65(
|
||||
; CHECK-NEXT: [[R1:%.*]] = lshr i65 2, -18446744073709551615
|
||||
; CHECK-NEXT: store i65 [[R1]], i65* [[P:%.*]]
|
||||
; CHECK-NEXT: [[R2:%.*]] = ashr i65 4, -18446744073709551615
|
||||
; CHECK-NEXT: store i65 [[R2]], i65* [[P]]
|
||||
; CHECK-NEXT: [[R3:%.*]] = shl i65 1, -18446744073709551615
|
||||
; CHECK-NEXT: store i65 [[R3]], i65* [[P]]
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
%r1 = lshr i65 2, 18446744073709551617
|
||||
; CHECK: store i65 undef
|
||||
store i65 %r1, i65* %p
|
||||
|
||||
%r2 = ashr i65 4, 18446744073709551617
|
||||
; CHECK: store i65 undef
|
||||
store i65 %r2, i65* %p
|
||||
|
||||
%r3 = shl i65 1, 18446744073709551617
|
||||
; CHECK: store i65 undef
|
||||
store i65 %r3, i65* %p
|
||||
|
||||
ret void
|
||||
}
|
||||
|
||||
; CHECK-LABEL: shift_undef_256
|
||||
define void @shift_undef_256(i256* %p) {
|
||||
; CHECK-LABEL: @shift_undef_256(
|
||||
; CHECK-NEXT: [[R1:%.*]] = lshr i256 2, 18446744073709551617
|
||||
; CHECK-NEXT: store i256 [[R1]], i256* [[P:%.*]]
|
||||
; CHECK-NEXT: [[R2:%.*]] = ashr i256 4, 18446744073709551618
|
||||
; CHECK-NEXT: store i256 [[R2]], i256* [[P]]
|
||||
; CHECK-NEXT: [[R3:%.*]] = shl i256 1, 18446744073709551619
|
||||
; CHECK-NEXT: store i256 [[R3]], i256* [[P]]
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
%r1 = lshr i256 2, 18446744073709551617
|
||||
; CHECK: store i256 undef
|
||||
store i256 %r1, i256* %p
|
||||
|
||||
%r2 = ashr i256 4, 18446744073709551618
|
||||
; CHECK: store i256 undef
|
||||
store i256 %r2, i256* %p
|
||||
|
||||
%r3 = shl i256 1, 18446744073709551619
|
||||
; CHECK: store i256 undef
|
||||
store i256 %r3, i256* %p
|
||||
|
||||
ret void
|
||||
}
|
||||
|
||||
; CHECK-LABEL: shift_undef_511
|
||||
define void @shift_undef_511(i511* %p) {
|
||||
; CHECK-LABEL: @shift_undef_511(
|
||||
; CHECK-NEXT: [[R1:%.*]] = lshr i511 -1, 1208925819614629174706276
|
||||
; CHECK-NEXT: store i511 [[R1]], i511* [[P:%.*]]
|
||||
; CHECK-NEXT: [[R2:%.*]] = ashr i511 -2, 1208925819614629174706200
|
||||
; CHECK-NEXT: store i511 [[R2]], i511* [[P]]
|
||||
; CHECK-NEXT: [[R3:%.*]] = shl i511 -3, 1208925819614629174706180
|
||||
; CHECK-NEXT: store i511 [[R3]], i511* [[P]]
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
%r1 = lshr i511 -1, 1208925819614629174706276 ; 2^80 + 100
|
||||
; CHECK: store i511 undef
|
||||
store i511 %r1, i511* %p
|
||||
|
||||
%r2 = ashr i511 -2, 1208925819614629174706200
|
||||
; CHECK: store i511 undef
|
||||
store i511 %r2, i511* %p
|
||||
|
||||
%r3 = shl i511 -3, 1208925819614629174706180
|
||||
; CHECK: store i511 undef
|
||||
store i511 %r3, i511* %p
|
||||
|
||||
ret void
|
||||
|
@ -1,15 +1,12 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
||||
; RUN: opt -sccp -S < %s | FileCheck %s
|
||||
|
||||
|
||||
; PR6940
|
||||
define double @test1() {
|
||||
; CHECK-LABEL: @test1(
|
||||
; CHECK-NEXT: [[T:%.*]] = sitofp i32 undef to double
|
||||
; CHECK-NEXT: ret double [[T]]
|
||||
;
|
||||
%t = sitofp i32 undef to double
|
||||
ret double %t
|
||||
; CHECK-LABEL: @test1(
|
||||
; CHECK: ret double 0.0
|
||||
}
|
||||
|
||||
|
||||
@ -17,72 +14,6 @@ define double @test1() {
|
||||
; Check that lots of stuff doesn't get turned into undef.
|
||||
define i32 @test2() nounwind readnone ssp {
|
||||
; CHECK-LABEL: @test2(
|
||||
; CHECK-NEXT: init:
|
||||
; CHECK-NEXT: br label [[CONTROL_OUTER_OUTER:%.*]]
|
||||
; CHECK: control.outer.loopexit.us-lcssa:
|
||||
; CHECK-NEXT: br label [[CONTROL_OUTER_LOOPEXIT:%.*]]
|
||||
; CHECK: control.outer.loopexit:
|
||||
; CHECK-NEXT: br label [[CONTROL_OUTER_OUTER_BACKEDGE:%.*]]
|
||||
; CHECK: control.outer.outer:
|
||||
; CHECK-NEXT: [[SWITCHCOND_0_PH_PH:%.*]] = phi i32 [ 2, [[INIT:%.*]] ], [ 3, [[CONTROL_OUTER_OUTER_BACKEDGE]] ]
|
||||
; CHECK-NEXT: [[I_0_PH_PH:%.*]] = phi i32 [ undef, [[INIT]] ], [ [[I_0_PH_PH_BE:%.*]], [[CONTROL_OUTER_OUTER_BACKEDGE]] ]
|
||||
; CHECK-NEXT: [[TMP4:%.*]] = icmp eq i32 [[I_0_PH_PH]], 0
|
||||
; CHECK-NEXT: br i1 [[TMP4]], label [[CONTROL_OUTER_OUTER_SPLIT_US:%.*]], label [[CONTROL_OUTER_OUTER_CONTROL_OUTER_OUTER_SPLIT_CRIT_EDGE:%.*]]
|
||||
; CHECK: control.outer.outer.control.outer.outer.split_crit_edge:
|
||||
; CHECK-NEXT: br label [[CONTROL_OUTER:%.*]]
|
||||
; CHECK: control.outer.outer.split.us:
|
||||
; CHECK-NEXT: br label [[CONTROL_OUTER_US:%.*]]
|
||||
; CHECK: control.outer.us:
|
||||
; CHECK-NEXT: [[A_0_PH_US:%.*]] = phi i32 [ [[SWITCHCOND_0_US:%.*]], [[BB3_US:%.*]] ], [ 4, [[CONTROL_OUTER_OUTER_SPLIT_US]] ]
|
||||
; CHECK-NEXT: [[SWITCHCOND_0_PH_US:%.*]] = phi i32 [ [[A_0_PH_US]], [[BB3_US]] ], [ [[SWITCHCOND_0_PH_PH]], [[CONTROL_OUTER_OUTER_SPLIT_US]] ]
|
||||
; CHECK-NEXT: br label [[CONTROL_US:%.*]]
|
||||
; CHECK: bb3.us:
|
||||
; CHECK-NEXT: br label [[CONTROL_OUTER_US]]
|
||||
; CHECK: bb0.us:
|
||||
; CHECK-NEXT: br label [[CONTROL_US]]
|
||||
; CHECK: control.us:
|
||||
; CHECK-NEXT: [[SWITCHCOND_0_US]] = phi i32 [ [[A_0_PH_US]], [[BB0_US:%.*]] ], [ [[SWITCHCOND_0_PH_US]], [[CONTROL_OUTER_US]] ]
|
||||
; CHECK-NEXT: switch i32 [[SWITCHCOND_0_US]], label [[CONTROL_OUTER_LOOPEXIT_US_LCSSA_US:%.*]] [
|
||||
; CHECK-NEXT: i32 0, label [[BB0_US]]
|
||||
; CHECK-NEXT: i32 1, label [[BB1_US_LCSSA_US:%.*]]
|
||||
; CHECK-NEXT: i32 3, label [[BB3_US]]
|
||||
; CHECK-NEXT: i32 4, label [[BB4_US_LCSSA_US:%.*]]
|
||||
; CHECK-NEXT: ]
|
||||
; CHECK: control.outer.loopexit.us-lcssa.us:
|
||||
; CHECK-NEXT: br label [[CONTROL_OUTER_LOOPEXIT]]
|
||||
; CHECK: bb1.us-lcssa.us:
|
||||
; CHECK-NEXT: br label [[BB1:%.*]]
|
||||
; CHECK: bb4.us-lcssa.us:
|
||||
; CHECK-NEXT: br label [[BB4:%.*]]
|
||||
; CHECK: control.outer:
|
||||
; CHECK-NEXT: [[A_0_PH:%.*]] = phi i32 [ [[NEXTID17:%.*]], [[BB3:%.*]] ], [ 4, [[CONTROL_OUTER_OUTER_CONTROL_OUTER_OUTER_SPLIT_CRIT_EDGE]] ]
|
||||
; CHECK-NEXT: [[SWITCHCOND_0_PH:%.*]] = phi i32 [ 0, [[BB3]] ], [ [[SWITCHCOND_0_PH_PH]], [[CONTROL_OUTER_OUTER_CONTROL_OUTER_OUTER_SPLIT_CRIT_EDGE]] ]
|
||||
; CHECK-NEXT: br label [[CONTROL:%.*]]
|
||||
; CHECK: control:
|
||||
; CHECK-NEXT: [[SWITCHCOND_0:%.*]] = phi i32 [ [[A_0_PH]], [[BB0:%.*]] ], [ [[SWITCHCOND_0_PH]], [[CONTROL_OUTER]] ]
|
||||
; CHECK-NEXT: switch i32 [[SWITCHCOND_0]], label [[CONTROL_OUTER_LOOPEXIT_US_LCSSA:%.*]] [
|
||||
; CHECK-NEXT: i32 0, label [[BB0]]
|
||||
; CHECK-NEXT: i32 1, label [[BB1_US_LCSSA:%.*]]
|
||||
; CHECK-NEXT: i32 3, label [[BB3]]
|
||||
; CHECK-NEXT: i32 4, label [[BB4_US_LCSSA:%.*]]
|
||||
; CHECK-NEXT: ]
|
||||
; CHECK: bb4.us-lcssa:
|
||||
; CHECK-NEXT: br label [[BB4]]
|
||||
; CHECK: bb4:
|
||||
; CHECK-NEXT: br label [[CONTROL_OUTER_OUTER_BACKEDGE]]
|
||||
; CHECK: control.outer.outer.backedge:
|
||||
; CHECK-NEXT: [[I_0_PH_PH_BE]] = phi i32 [ 1, [[BB4]] ], [ 0, [[CONTROL_OUTER_LOOPEXIT]] ]
|
||||
; CHECK-NEXT: br label [[CONTROL_OUTER_OUTER]]
|
||||
; CHECK: bb3:
|
||||
; CHECK-NEXT: [[NEXTID17]] = add i32 [[SWITCHCOND_0]], -2
|
||||
; CHECK-NEXT: br label [[CONTROL_OUTER]]
|
||||
; CHECK: bb0:
|
||||
; CHECK-NEXT: br label [[CONTROL]]
|
||||
; CHECK: bb1.us-lcssa:
|
||||
; CHECK-NEXT: br label [[BB1]]
|
||||
; CHECK: bb1:
|
||||
; CHECK-NEXT: ret i32 0
|
||||
;
|
||||
init:
|
||||
br label %control.outer.outer
|
||||
|
||||
@ -115,13 +46,16 @@ bb3.us: ; preds = %control.us
|
||||
bb0.us: ; preds = %control.us
|
||||
br label %control.us
|
||||
|
||||
; CHECK: control.us: ; preds = %bb0.us, %control.outer.us
|
||||
; CHECK-NEXT: %switchCond.0.us = phi i32
|
||||
; CHECK-NEXT: switch i32 %switchCond.0.us
|
||||
control.us: ; preds = %bb0.us, %control.outer.us
|
||||
%switchCond.0.us = phi i32 [ %A.0.ph.us, %bb0.us ], [ %switchCond.0.ph.us, %control.outer.us ] ; <i32> [#uses=2]
|
||||
switch i32 %switchCond.0.us, label %control.outer.loopexit.us-lcssa.us [
|
||||
i32 0, label %bb0.us
|
||||
i32 1, label %bb1.us-lcssa.us
|
||||
i32 3, label %bb3.us
|
||||
i32 4, label %bb4.us-lcssa.us
|
||||
i32 0, label %bb0.us
|
||||
i32 1, label %bb1.us-lcssa.us
|
||||
i32 3, label %bb3.us
|
||||
i32 4, label %bb4.us-lcssa.us
|
||||
]
|
||||
|
||||
control.outer.loopexit.us-lcssa.us: ; preds = %control.us
|
||||
@ -141,10 +75,10 @@ control.outer: ; preds = %bb3, %control.outer
|
||||
control: ; preds = %bb0, %control.outer
|
||||
%switchCond.0 = phi i32 [ %A.0.ph, %bb0 ], [ %switchCond.0.ph, %control.outer ] ; <i32> [#uses=2]
|
||||
switch i32 %switchCond.0, label %control.outer.loopexit.us-lcssa [
|
||||
i32 0, label %bb0
|
||||
i32 1, label %bb1.us-lcssa
|
||||
i32 3, label %bb3
|
||||
i32 4, label %bb4.us-lcssa
|
||||
i32 0, label %bb0
|
||||
i32 1, label %bb1.us-lcssa
|
||||
i32 3, label %bb3
|
||||
i32 4, label %bb4.us-lcssa
|
||||
]
|
||||
|
||||
bb4.us-lcssa: ; preds = %control
|
||||
@ -174,105 +108,83 @@ bb1: ; preds = %bb1.us-lcssa, %bb1.
|
||||
; Make sure SCCP honors the xor "idiom"
|
||||
; rdar://9956541
|
||||
define i32 @test3() {
|
||||
; CHECK-LABEL: @test3(
|
||||
; CHECK-NEXT: [[T:%.*]] = xor i32 undef, undef
|
||||
; CHECK-NEXT: ret i32 [[T]]
|
||||
;
|
||||
%t = xor i32 undef, undef
|
||||
ret i32 %t
|
||||
; CHECK-LABEL: @test3(
|
||||
; CHECK: ret i32 0
|
||||
}
|
||||
|
||||
; Be conservative with FP ops
|
||||
define double @test4(double %x) {
|
||||
; CHECK-LABEL: @test4(
|
||||
; CHECK-NEXT: [[T:%.*]] = fadd double [[X:%.*]], undef
|
||||
; CHECK-NEXT: ret double [[T]]
|
||||
;
|
||||
%t = fadd double %x, undef
|
||||
ret double %t
|
||||
; CHECK-LABEL: @test4(
|
||||
; CHECK: fadd double %x, undef
|
||||
}
|
||||
|
||||
; Make sure casts produce a possible value
|
||||
define i32 @test5() {
|
||||
; CHECK-LABEL: @test5(
|
||||
; CHECK-NEXT: [[T:%.*]] = sext i8 undef to i32
|
||||
; CHECK-NEXT: ret i32 [[T]]
|
||||
;
|
||||
%t = sext i8 undef to i32
|
||||
ret i32 %t
|
||||
; CHECK-LABEL: @test5(
|
||||
; CHECK: ret i32 0
|
||||
}
|
||||
|
||||
; Make sure ashr produces a possible value
|
||||
define i32 @test6() {
|
||||
; CHECK-LABEL: @test6(
|
||||
; CHECK-NEXT: [[T:%.*]] = ashr i32 undef, 31
|
||||
; CHECK-NEXT: ret i32 [[T]]
|
||||
;
|
||||
%t = ashr i32 undef, 31
|
||||
ret i32 %t
|
||||
; CHECK-LABEL: @test6(
|
||||
; CHECK: ret i32 0
|
||||
}
|
||||
|
||||
; Make sure lshr produces a possible value
|
||||
define i32 @test7() {
|
||||
; CHECK-LABEL: @test7(
|
||||
; CHECK-NEXT: [[T:%.*]] = lshr i32 undef, 31
|
||||
; CHECK-NEXT: ret i32 [[T]]
|
||||
;
|
||||
%t = lshr i32 undef, 31
|
||||
ret i32 %t
|
||||
; CHECK-LABEL: @test7(
|
||||
; CHECK: ret i32 0
|
||||
}
|
||||
|
||||
; icmp eq with undef simplifies to undef
|
||||
define i1 @test8() {
|
||||
; CHECK-LABEL: @test8(
|
||||
; CHECK-NEXT: [[T:%.*]] = icmp eq i32 undef, -1
|
||||
; CHECK-NEXT: ret i1 [[T]]
|
||||
;
|
||||
%t = icmp eq i32 undef, -1
|
||||
ret i1 %t
|
||||
; CHECK-LABEL: @test8(
|
||||
; CHECK: ret i1 undef
|
||||
}
|
||||
|
||||
; Make sure we don't conclude that relational comparisons simplify to undef
|
||||
define i1 @test9() {
|
||||
; CHECK-LABEL: @test9(
|
||||
; CHECK-NEXT: [[T:%.*]] = icmp ugt i32 undef, -1
|
||||
; CHECK-NEXT: ret i1 [[T]]
|
||||
;
|
||||
%t = icmp ugt i32 undef, -1
|
||||
ret i1 %t
|
||||
; CHECK-LABEL: @test9(
|
||||
; CHECK: icmp ugt
|
||||
}
|
||||
|
||||
; Make sure we handle extractvalue
|
||||
define i64 @test10() {
|
||||
; CHECK-LABEL: @test10(
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: [[E:%.*]] = extractvalue { i64, i64 } undef, 1
|
||||
; CHECK-NEXT: ret i64 [[E]]
|
||||
;
|
||||
define i64 @test10() {
|
||||
entry:
|
||||
%e = extractvalue { i64, i64 } undef, 1
|
||||
ret i64 %e
|
||||
; CHECK-LABEL: @test10(
|
||||
; CHECK: ret i64 undef
|
||||
}
|
||||
|
||||
@GV = external global i32
|
||||
|
||||
define i32 @test11(i1 %tobool) {
|
||||
; CHECK-LABEL: @test11(
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: [[SHR4:%.*]] = ashr i32 undef, zext (i1 icmp eq (i32* bitcast (i32 (i1)* @test11 to i32*), i32* @GV) to i32)
|
||||
; CHECK-NEXT: ret i32 [[SHR4]]
|
||||
;
|
||||
entry:
|
||||
%shr4 = ashr i32 undef, zext (i1 icmp eq (i32* bitcast (i32 (i1)* @test11 to i32*), i32* @GV) to i32)
|
||||
ret i32 %shr4
|
||||
; CHECK-LABEL: @test11(
|
||||
; CHECK: ret i32 0
|
||||
}
|
||||
|
||||
; Test unary ops
|
||||
define double @test12(double %x) {
|
||||
; CHECK-LABEL: @test12(
|
||||
; CHECK-NEXT: [[T:%.*]] = fneg double undef
|
||||
; CHECK-NEXT: ret double [[T]]
|
||||
;
|
||||
%t = fneg double undef
|
||||
ret double %t
|
||||
; CHECK-LABEL: @test12(
|
||||
; CHECK: double undef
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user