aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLang Hames <lhames@gmail.com>2011-07-08 01:50:54 +0000
committerLang Hames <lhames@gmail.com>2011-07-08 01:50:54 +0000
commit1fb0955cab05ff71f5bbad523b0374db3b08b201 (patch)
tree1b8acc9ed0797f735863cf293cdb531a05aa5bb6
parent01843361953463519db42e8098dc8b31b45407c8 (diff)
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
-rw-r--r--lib/Transforms/Scalar/GVN.cpp61
-rw-r--r--test/Transforms/GVN/2011-07-07-MatchIntrinsicExtract.ll47
2 files changed, 101 insertions, 7 deletions
diff --git a/lib/Transforms/Scalar/GVN.cpp b/lib/Transforms/Scalar/GVN.cpp
index 759e681f5e..e6bc77fb8e 100644
--- a/lib/Transforms/Scalar/GVN.cpp
+++ b/lib/Transforms/Scalar/GVN.cpp
@@ -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++;
diff --git a/test/Transforms/GVN/2011-07-07-MatchIntrinsicExtract.ll b/test/Transforms/GVN/2011-07-07-MatchIntrinsicExtract.ll
new file mode 100644
index 0000000000..a2ef4ab418
--- /dev/null
+++ b/test/Transforms/GVN/2011-07-07-MatchIntrinsicExtract.ll
@@ -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
+