mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-03-03 14:31:10 +00:00
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:
parent
0184336195
commit
1fb0955cab
@ -91,6 +91,7 @@ namespace {
|
|||||||
uint32_t nextValueNumber;
|
uint32_t nextValueNumber;
|
||||||
|
|
||||||
Expression create_expression(Instruction* I);
|
Expression create_expression(Instruction* I);
|
||||||
|
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) { }
|
||||||
@ -141,7 +142,6 @@ template <> struct DenseMapInfo<Expression> {
|
|||||||
// ValueTable Internal Functions
|
// ValueTable Internal Functions
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
|
||||||
Expression ValueTable::create_expression(Instruction *I) {
|
Expression ValueTable::create_expression(Instruction *I) {
|
||||||
Expression e;
|
Expression e;
|
||||||
e.type = I->getType();
|
e.type = I->getType();
|
||||||
@ -150,12 +150,8 @@ Expression ValueTable::create_expression(Instruction *I) {
|
|||||||
OI != OE; ++OI)
|
OI != OE; ++OI)
|
||||||
e.varargs.push_back(lookup_or_add(*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();
|
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)) {
|
} else if (InsertValueInst *E = dyn_cast<InsertValueInst>(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)
|
||||||
@ -165,6 +161,55 @@ Expression ValueTable::create_expression(Instruction *I) {
|
|||||||
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::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
|
// ValueTable External Functions
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
@ -336,11 +381,13 @@ uint32_t ValueTable::lookup_or_add(Value *V) {
|
|||||||
case Instruction::ExtractElement:
|
case Instruction::ExtractElement:
|
||||||
case Instruction::InsertElement:
|
case Instruction::InsertElement:
|
||||||
case Instruction::ShuffleVector:
|
case Instruction::ShuffleVector:
|
||||||
case Instruction::ExtractValue:
|
|
||||||
case Instruction::InsertValue:
|
case Instruction::InsertValue:
|
||||||
case Instruction::GetElementPtr:
|
case Instruction::GetElementPtr:
|
||||||
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++;
|
||||||
|
47
test/Transforms/GVN/2011-07-07-MatchIntrinsicExtract.ll
Normal file
47
test/Transforms/GVN/2011-07-07-MatchIntrinsicExtract.ll
Normal 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
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user