Make GVN look through extractvalues for recognised intrinsics. GVN can then CSE ops that match values produced by the intrinsics.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@134677 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Lang Hames 2011-07-08 01:50:54 +00:00
parent 0184336195
commit 1fb0955cab
2 changed files with 101 additions and 7 deletions

View File

@ -91,6 +91,7 @@ namespace {
uint32_t nextValueNumber;
Expression create_expression(Instruction* I);
Expression create_extractvalue_expression(ExtractValueInst* EI);
uint32_t lookup_or_add_call(CallInst* C);
public:
ValueTable() : nextValueNumber(1) { }
@ -141,7 +142,6 @@ template <> struct DenseMapInfo<Expression> {
// ValueTable Internal Functions
//===----------------------------------------------------------------------===//
Expression ValueTable::create_expression(Instruction *I) {
Expression e;
e.type = I->getType();
@ -150,12 +150,8 @@ Expression ValueTable::create_expression(Instruction *I) {
OI != OE; ++OI)
e.varargs.push_back(lookup_or_add(*OI));
if (CmpInst *C = dyn_cast<CmpInst>(I))
if (CmpInst *C = dyn_cast<CmpInst>(I)) {
e.opcode = (C->getOpcode() << 8) | C->getPredicate();
else if (ExtractValueInst *E = dyn_cast<ExtractValueInst>(I)) {
for (ExtractValueInst::idx_iterator II = E->idx_begin(), IE = E->idx_end();
II != IE; ++II)
e.varargs.push_back(*II);
} else if (InsertValueInst *E = dyn_cast<InsertValueInst>(I)) {
for (InsertValueInst::idx_iterator II = E->idx_begin(), IE = E->idx_end();
II != IE; ++II)
@ -165,6 +161,55 @@ Expression ValueTable::create_expression(Instruction *I) {
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::uadd_with_overflow:
e.opcode = Instruction::Add;
break;
case Intrinsic::usub_with_overflow:
e.opcode = Instruction::Sub;
break;
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
//===----------------------------------------------------------------------===//
@ -336,11 +381,13 @@ uint32_t ValueTable::lookup_or_add(Value *V) {
case Instruction::ExtractElement:
case Instruction::InsertElement:
case Instruction::ShuffleVector:
case Instruction::ExtractValue:
case Instruction::InsertValue:
case Instruction::GetElementPtr:
exp = create_expression(I);
break;
case Instruction::ExtractValue:
exp = create_extractvalue_expression(cast<ExtractValueInst>(I));
break;
default:
valueNumbering[V] = nextValueNumber;
return nextValueNumber++;

View File

@ -0,0 +1,47 @@
; RUN: opt < %s -gvn -S | FileCheck %s
;
%0 = type { i64, i1 }
define i64 @test1(i64 %a, i64 %b) nounwind ssp {
entry:
%uadd = tail call %0 @llvm.uadd.with.overflow.i64(i64 %a, i64 %b)
%uadd.0 = extractvalue %0 %uadd, 0
%add1 = add i64 %a, %b
ret i64 %add1
}
; CHECK: @test1
; CHECK-NOT: add1
; CHECK: ret
define i64 @test2(i64 %a, i64 %b) nounwind ssp {
entry:
%usub = tail call %0 @llvm.usub.with.overflow.i64(i64 %a, i64 %b)
%usub.0 = extractvalue %0 %usub, 0
%sub1 = sub i64 %a, %b
ret i64 %sub1
}
; CHECK: @test2
; CHECK-NOT: sub1
; CHECK: ret
define i64 @test3(i64 %a, i64 %b) nounwind ssp {
entry:
%umul = tail call %0 @llvm.umul.with.overflow.i64(i64 %a, i64 %b)
%umul.0 = extractvalue %0 %umul, 0
%mul1 = mul i64 %a, %b
ret i64 %mul1
}
; CHECK: @test3
; CHECK-NOT: mul1
; CHECK: ret
declare void @exit(i32) noreturn
declare %0 @llvm.uadd.with.overflow.i64(i64, i64) nounwind readnone
declare %0 @llvm.usub.with.overflow.i64(i64, i64) nounwind readnone
declare %0 @llvm.umul.with.overflow.i64(i64, i64) nounwind readnone