From 1fb0955cab05ff71f5bbad523b0374db3b08b201 Mon Sep 17 00:00:00 2001 From: Lang Hames Date: Fri, 8 Jul 2011 01:50:54 +0000 Subject: [PATCH] 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 --- lib/Transforms/Scalar/GVN.cpp | 61 +++++++++++++++++++--- .../GVN/2011-07-07-MatchIntrinsicExtract.ll | 47 +++++++++++++++++ 2 files changed, 101 insertions(+), 7 deletions(-) create mode 100644 test/Transforms/GVN/2011-07-07-MatchIntrinsicExtract.ll diff --git a/lib/Transforms/Scalar/GVN.cpp b/lib/Transforms/Scalar/GVN.cpp index 759e681f5e8..e6bc77fb8ef 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 { // 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(I)) + if (CmpInst *C = dyn_cast(I)) { e.opcode = (C->getOpcode() << 8) | C->getPredicate(); - else if (ExtractValueInst *E = dyn_cast(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(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(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(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 00000000000..a2ef4ab4185 --- /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 + -- 2.11.0