forked from OSchip/llvm-project
Revert "GVN: merge overflow intrinsics with non-overflow instructions."
This reverts commit r203553, and follow-up commits r203558 and r203574. I will follow this up on the mailinglist to do it in a way that won't cause subtle PRE bugs. llvm-svn: 205009
This commit is contained in:
parent
f01cd6f57b
commit
2074ebd8af
|
@ -111,11 +111,10 @@ namespace {
|
||||||
uint32_t nextValueNumber;
|
uint32_t nextValueNumber;
|
||||||
|
|
||||||
Expression create_expression(Instruction* I);
|
Expression create_expression(Instruction* I);
|
||||||
Expression create_intrinsic_expression(CallInst *C, uint32_t opcode,
|
|
||||||
bool IsCommutative);
|
|
||||||
Expression create_cmp_expression(unsigned Opcode,
|
Expression create_cmp_expression(unsigned Opcode,
|
||||||
CmpInst::Predicate Predicate,
|
CmpInst::Predicate Predicate,
|
||||||
Value *LHS, Value *RHS);
|
Value *LHS, Value *RHS);
|
||||||
|
Expression create_extractvalue_expression(ExtractValueInst* EI);
|
||||||
uint32_t lookup_or_add_call(CallInst* C);
|
uint32_t lookup_or_add_call(CallInst* C);
|
||||||
public:
|
public:
|
||||||
ValueTable() : nextValueNumber(1) { }
|
ValueTable() : nextValueNumber(1) { }
|
||||||
|
@ -189,33 +188,6 @@ Expression ValueTable::create_expression(Instruction *I) {
|
||||||
for (InsertValueInst::idx_iterator II = E->idx_begin(), IE = E->idx_end();
|
for (InsertValueInst::idx_iterator II = E->idx_begin(), IE = E->idx_end();
|
||||||
II != IE; ++II)
|
II != IE; ++II)
|
||||||
e.varargs.push_back(*II);
|
e.varargs.push_back(*II);
|
||||||
} else if (ExtractValueInst *EVI = dyn_cast<ExtractValueInst>(I)) {
|
|
||||||
for (ExtractValueInst::idx_iterator II = EVI->idx_begin(),
|
|
||||||
IE = EVI->idx_end(); II != IE; ++II)
|
|
||||||
e.varargs.push_back(*II);
|
|
||||||
}
|
|
||||||
|
|
||||||
return e;
|
|
||||||
}
|
|
||||||
|
|
||||||
Expression ValueTable::create_intrinsic_expression(CallInst *C, uint32_t opcode,
|
|
||||||
bool IsCommutative) {
|
|
||||||
Expression e;
|
|
||||||
e.opcode = opcode;
|
|
||||||
StructType *ST = cast<StructType>(C->getType());
|
|
||||||
assert(ST);
|
|
||||||
e.type = *ST->element_begin();
|
|
||||||
|
|
||||||
for (unsigned i = 0, ei = C->getNumArgOperands(); i < ei; ++i)
|
|
||||||
e.varargs.push_back(lookup_or_add(C->getArgOperand(i)));
|
|
||||||
if (IsCommutative) {
|
|
||||||
// Ensure that commutative instructions that only differ by a permutation
|
|
||||||
// of their operands get the same value number by sorting the operand value
|
|
||||||
// numbers. Since all commutative instructions have two operands it is more
|
|
||||||
// efficient to sort by hand rather than using, say, std::sort.
|
|
||||||
assert(C->getNumArgOperands() == 2 && "Unsupported commutative instruction!");
|
|
||||||
if (e.varargs[0] > e.varargs[1])
|
|
||||||
std::swap(e.varargs[0], e.varargs[1]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return e;
|
return e;
|
||||||
|
@ -240,6 +212,58 @@ Expression ValueTable::create_cmp_expression(unsigned Opcode,
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Expression ValueTable::create_extractvalue_expression(ExtractValueInst *EI) {
|
||||||
|
assert(EI != 0 && "Not an ExtractValueInst?");
|
||||||
|
Expression e;
|
||||||
|
e.type = EI->getType();
|
||||||
|
e.opcode = 0;
|
||||||
|
|
||||||
|
IntrinsicInst *I = dyn_cast<IntrinsicInst>(EI->getAggregateOperand());
|
||||||
|
if (I != 0 && EI->getNumIndices() == 1 && *EI->idx_begin() == 0 ) {
|
||||||
|
// EI might be an extract from one of our recognised intrinsics. If it
|
||||||
|
// is we'll synthesize a semantically equivalent expression instead on
|
||||||
|
// an extract value expression.
|
||||||
|
switch (I->getIntrinsicID()) {
|
||||||
|
case Intrinsic::sadd_with_overflow:
|
||||||
|
case Intrinsic::uadd_with_overflow:
|
||||||
|
e.opcode = Instruction::Add;
|
||||||
|
break;
|
||||||
|
case Intrinsic::ssub_with_overflow:
|
||||||
|
case Intrinsic::usub_with_overflow:
|
||||||
|
e.opcode = Instruction::Sub;
|
||||||
|
break;
|
||||||
|
case Intrinsic::smul_with_overflow:
|
||||||
|
case Intrinsic::umul_with_overflow:
|
||||||
|
e.opcode = Instruction::Mul;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.opcode != 0) {
|
||||||
|
// Intrinsic recognized. Grab its args to finish building the expression.
|
||||||
|
assert(I->getNumArgOperands() == 2 &&
|
||||||
|
"Expect two args for recognised intrinsics.");
|
||||||
|
e.varargs.push_back(lookup_or_add(I->getArgOperand(0)));
|
||||||
|
e.varargs.push_back(lookup_or_add(I->getArgOperand(1)));
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not a recognised intrinsic. Fall back to producing an extract value
|
||||||
|
// expression.
|
||||||
|
e.opcode = EI->getOpcode();
|
||||||
|
for (Instruction::op_iterator OI = EI->op_begin(), OE = EI->op_end();
|
||||||
|
OI != OE; ++OI)
|
||||||
|
e.varargs.push_back(lookup_or_add(*OI));
|
||||||
|
|
||||||
|
for (ExtractValueInst::idx_iterator II = EI->idx_begin(), IE = EI->idx_end();
|
||||||
|
II != IE; ++II)
|
||||||
|
e.varargs.push_back(*II);
|
||||||
|
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// ValueTable External Functions
|
// ValueTable External Functions
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
@ -373,29 +397,8 @@ uint32_t ValueTable::lookup_or_add(Value *V) {
|
||||||
Instruction* I = cast<Instruction>(V);
|
Instruction* I = cast<Instruction>(V);
|
||||||
Expression exp;
|
Expression exp;
|
||||||
switch (I->getOpcode()) {
|
switch (I->getOpcode()) {
|
||||||
case Instruction::Call: {
|
case Instruction::Call:
|
||||||
CallInst *C = cast<CallInst>(I);
|
return lookup_or_add_call(cast<CallInst>(I));
|
||||||
if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(C)) {
|
|
||||||
switch (II->getIntrinsicID()) {
|
|
||||||
case Intrinsic::sadd_with_overflow:
|
|
||||||
case Intrinsic::uadd_with_overflow:
|
|
||||||
exp = create_intrinsic_expression(C, Instruction::Add, true);
|
|
||||||
break;
|
|
||||||
case Intrinsic::ssub_with_overflow:
|
|
||||||
case Intrinsic::usub_with_overflow:
|
|
||||||
exp = create_intrinsic_expression(C, Instruction::Sub, false);
|
|
||||||
break;
|
|
||||||
case Intrinsic::smul_with_overflow:
|
|
||||||
case Intrinsic::umul_with_overflow:
|
|
||||||
exp = create_intrinsic_expression(C, Instruction::Mul, true);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return lookup_or_add_call(C);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return lookup_or_add_call(C);
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
case Instruction::Add:
|
case Instruction::Add:
|
||||||
case Instruction::FAdd:
|
case Instruction::FAdd:
|
||||||
case Instruction::Sub:
|
case Instruction::Sub:
|
||||||
|
@ -434,9 +437,11 @@ uint32_t ValueTable::lookup_or_add(Value *V) {
|
||||||
case Instruction::ShuffleVector:
|
case Instruction::ShuffleVector:
|
||||||
case Instruction::InsertValue:
|
case Instruction::InsertValue:
|
||||||
case Instruction::GetElementPtr:
|
case Instruction::GetElementPtr:
|
||||||
case Instruction::ExtractValue:
|
|
||||||
exp = create_expression(I);
|
exp = create_expression(I);
|
||||||
break;
|
break;
|
||||||
|
case Instruction::ExtractValue:
|
||||||
|
exp = create_extractvalue_expression(cast<ExtractValueInst>(I));
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
valueNumbering[V] = nextValueNumber;
|
valueNumbering[V] = nextValueNumber;
|
||||||
return nextValueNumber++;
|
return nextValueNumber++;
|
||||||
|
@ -2184,54 +2189,6 @@ bool GVN::propagateEquality(Value *LHS, Value *RHS,
|
||||||
return Changed;
|
return Changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool normalOpAfterIntrinsic(Instruction *I, Value *Repl)
|
|
||||||
{
|
|
||||||
switch (I->getOpcode()) {
|
|
||||||
case Instruction::Add:
|
|
||||||
if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(Repl))
|
|
||||||
return II->getIntrinsicID() == Intrinsic::sadd_with_overflow
|
|
||||||
|| II->getIntrinsicID() == Intrinsic::uadd_with_overflow;
|
|
||||||
return false;
|
|
||||||
case Instruction::Sub:
|
|
||||||
if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(Repl))
|
|
||||||
return II->getIntrinsicID() == Intrinsic::ssub_with_overflow
|
|
||||||
|| II->getIntrinsicID() == Intrinsic::usub_with_overflow;
|
|
||||||
return false;
|
|
||||||
case Instruction::Mul:
|
|
||||||
if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(Repl))
|
|
||||||
return II->getIntrinsicID() == Intrinsic::smul_with_overflow
|
|
||||||
|| II->getIntrinsicID() == Intrinsic::umul_with_overflow;
|
|
||||||
return false;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool intrinsicAterNormalOp(Instruction *I, Value *Repl)
|
|
||||||
{
|
|
||||||
IntrinsicInst *II = dyn_cast<IntrinsicInst>(I);
|
|
||||||
if (!II)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
Instruction *RI = dyn_cast<Instruction>(Repl);
|
|
||||||
if (!RI)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
switch (RI->getOpcode()) {
|
|
||||||
case Instruction::Add:
|
|
||||||
return II->getIntrinsicID() == Intrinsic::sadd_with_overflow
|
|
||||||
|| II->getIntrinsicID() == Intrinsic::uadd_with_overflow;
|
|
||||||
case Instruction::Sub:
|
|
||||||
return II->getIntrinsicID() == Intrinsic::ssub_with_overflow
|
|
||||||
|| II->getIntrinsicID() == Intrinsic::usub_with_overflow;
|
|
||||||
case Instruction::Mul:
|
|
||||||
return II->getIntrinsicID() == Intrinsic::smul_with_overflow
|
|
||||||
|| II->getIntrinsicID() == Intrinsic::umul_with_overflow;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// processInstruction - When calculating availability, handle an instruction
|
/// processInstruction - When calculating availability, handle an instruction
|
||||||
/// by inserting it into the appropriate sets
|
/// by inserting it into the appropriate sets
|
||||||
bool GVN::processInstruction(Instruction *I) {
|
bool GVN::processInstruction(Instruction *I) {
|
||||||
|
@ -2345,27 +2302,6 @@ bool GVN::processInstruction(Instruction *I) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (normalOpAfterIntrinsic(I, repl)) {
|
|
||||||
// An intrinsic followed by a normal operation (e.g. sadd_with_overflow
|
|
||||||
// followed by a sadd): replace the second instruction with an extract.
|
|
||||||
IntrinsicInst *II = cast<IntrinsicInst>(repl);
|
|
||||||
assert(II);
|
|
||||||
repl = ExtractValueInst::Create(II, 0, I->getName() + ".repl", I);
|
|
||||||
} else if (intrinsicAterNormalOp(I, repl)) {
|
|
||||||
// A normal operation followed by an intrinsic (e.g. sadd followed by a
|
|
||||||
// sadd_with_overflow).
|
|
||||||
// Clone the intrinsic, and insert it before the replacing instruction. Then
|
|
||||||
// replace the (current) instruction with the cloned one. In a subsequent
|
|
||||||
// run, the original replacement (the non-intrinsic) will be be replaced by
|
|
||||||
// the new intrinsic.
|
|
||||||
Instruction *RI = dyn_cast<Instruction>(repl);
|
|
||||||
assert(RI);
|
|
||||||
Instruction *newIntrinsic = I->clone();
|
|
||||||
newIntrinsic->setName(I->getName() + ".repl");
|
|
||||||
newIntrinsic->insertBefore(RI);
|
|
||||||
repl = newIntrinsic;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove it!
|
// Remove it!
|
||||||
patchAndReplaceAllUsesWith(I, repl);
|
patchAndReplaceAllUsesWith(I, repl);
|
||||||
if (MD && repl->getType()->getScalarType()->isPointerTy())
|
if (MD && repl->getType()->getScalarType()->isPointerTy())
|
||||||
|
@ -2550,8 +2486,6 @@ bool GVN::performPRE(Function &F) {
|
||||||
predMap.push_back(std::make_pair(static_cast<Value *>(0), P));
|
predMap.push_back(std::make_pair(static_cast<Value *>(0), P));
|
||||||
PREPred = P;
|
PREPred = P;
|
||||||
++NumWithout;
|
++NumWithout;
|
||||||
} else if (predV->getType() != CurInst->getType()) {
|
|
||||||
continue;
|
|
||||||
} else if (predV == CurInst) {
|
} else if (predV == CurInst) {
|
||||||
/* CurInst dominates this predecessor. */
|
/* CurInst dominates this predecessor. */
|
||||||
NumWithout = 2;
|
NumWithout = 2;
|
||||||
|
|
|
@ -1,67 +0,0 @@
|
||||||
; RUN: opt -S -gvn < %s | FileCheck %s
|
|
||||||
|
|
||||||
define i32 @sadd1(i32 %a, i32 %b) #0 {
|
|
||||||
; CHECK-LABEL: @sadd1(
|
|
||||||
entry:
|
|
||||||
%sadd = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %a, i32 %b)
|
|
||||||
%cmp = extractvalue { i32, i1 } %sadd, 1
|
|
||||||
br i1 %cmp, label %if.then, label %if.end
|
|
||||||
|
|
||||||
if.then: ; preds = %entry
|
|
||||||
ret i32 42
|
|
||||||
|
|
||||||
if.end: ; preds = %entry
|
|
||||||
%sadd3 = add i32 %a, %b
|
|
||||||
ret i32 %sadd3
|
|
||||||
; CHECK-NOT: add i32 %a, %b
|
|
||||||
; CHECK: %sadd3.repl = extractvalue { i32, i1 } %sadd, 0
|
|
||||||
; CHECK: ret i32 %sadd3.repl
|
|
||||||
}
|
|
||||||
|
|
||||||
define i32 @sadd2(i32 %a, i32 %b) #0 {
|
|
||||||
entry:
|
|
||||||
%sadd3 = add i32 %a, %b
|
|
||||||
%sadd = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %a, i32 %b)
|
|
||||||
%cmp = extractvalue { i32, i1 } %sadd, 1
|
|
||||||
br i1 %cmp, label %if.then, label %if.end
|
|
||||||
; CHECK-NOT: %sadd3 = add i32 %a, %b
|
|
||||||
; CHECK: %sadd.repl = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %a, i32 %b)
|
|
||||||
; CHECK-NOT: %sadd = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %a, i32 %b)
|
|
||||||
; CHECK: %sadd3.repl = extractvalue { i32, i1 } %sadd.repl, 0
|
|
||||||
|
|
||||||
if.then: ; preds = %entry
|
|
||||||
%sadd4 = add i32 %sadd3, 1
|
|
||||||
ret i32 %sadd4
|
|
||||||
; CHECK: %sadd4 = add i32 %sadd3.repl, 1
|
|
||||||
|
|
||||||
if.end: ; preds = %entry
|
|
||||||
ret i32 %sadd3
|
|
||||||
; CHECK: ret i32 %sadd3.repl
|
|
||||||
}
|
|
||||||
|
|
||||||
; Check if PRE does not crash
|
|
||||||
define i32 @pre(i32 %a, i32 %b) nounwind ssp uwtable {
|
|
||||||
entry:
|
|
||||||
%cmp = icmp sgt i32 %a, 42
|
|
||||||
br i1 %cmp, label %if.then, label %if.end3
|
|
||||||
|
|
||||||
if.then: ; preds = %entry
|
|
||||||
%add = call {i32, i1} @llvm.sadd.with.overflow.i32(i32 %a, i32 %b)
|
|
||||||
%add1 = extractvalue {i32, i1} %add, 0
|
|
||||||
%o = extractvalue {i32, i1} %add, 1
|
|
||||||
%o32 = zext i1 %o to i32
|
|
||||||
%add32 = add i32 %add1, %o32
|
|
||||||
%cmp1 = icmp sgt i32 %add1, 42
|
|
||||||
br i1 %cmp1, label %if.then2, label %if.end3
|
|
||||||
|
|
||||||
if.then2: ; preds = %if.then
|
|
||||||
call void @abort() noreturn
|
|
||||||
unreachable
|
|
||||||
|
|
||||||
if.end3: ; preds = %if.end, %entry
|
|
||||||
%add4 = add i32 %a, %b
|
|
||||||
ret i32 %add4
|
|
||||||
}
|
|
||||||
|
|
||||||
declare void @abort() noreturn
|
|
||||||
declare { i32, i1 } @llvm.sadd.with.overflow.i32(i32, i32) nounwind readnone
|
|
Loading…
Reference in New Issue