aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChandler Carruth <chandlerc@gmail.com>2012-12-28 14:23:32 +0000
committerChandler Carruth <chandlerc@gmail.com>2012-12-28 14:23:32 +0000
commitba94204e94ba88f7c897a5a59d1c770b7dc3d04e (patch)
treee05bcd9791e64cfefb8f38b0f5bd936ff7da6c3a
parente949aa1c91132094a9073c82a8aef729fa8c9eca (diff)
Teach the inline cost analysis about calls that can be simplified and
how to propagate constants through insert and extract value instructions. With the recent improvements to instsimplify, this allows inline cost analysis to constant fold through intrinsic functions, including notably the with.overflow intrinsic math routines which often show up inside of STL abstractions. This is yet another piece in the puzzle of breaking down the code for: void f() { std::vector<int> v; v.push_back(1); } But it still isn't enough. There are a pile of bugs in inline cost still blocking this. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@171195 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/Analysis/InlineCost.cpp98
-rw-r--r--test/Transforms/Inline/inline_constprop.ll38
2 files changed, 125 insertions, 11 deletions
diff --git a/lib/Analysis/InlineCost.cpp b/lib/Analysis/InlineCost.cpp
index de89fea119..685050765a 100644
--- a/lib/Analysis/InlineCost.cpp
+++ b/lib/Analysis/InlineCost.cpp
@@ -96,6 +96,7 @@ class CallAnalyzer : public InstVisitor<CallAnalyzer, bool> {
int InstructionCost);
bool isGEPOffsetConstant(GetElementPtrInst &GEP);
bool accumulateGEPOffset(GEPOperator &GEP, APInt &Offset);
+ bool simplifyCallSite(Function *F, CallSite CS);
ConstantInt *stripAndComputeInBoundsConstantOffsets(Value *&V);
// Custom analysis routines.
@@ -124,6 +125,8 @@ class CallAnalyzer : public InstVisitor<CallAnalyzer, bool> {
bool visitBinaryOperator(BinaryOperator &I);
bool visitLoad(LoadInst &I);
bool visitStore(StoreInst &I);
+ bool visitExtractValue(ExtractValueInst &I);
+ bool visitInsertValue(InsertValueInst &I);
bool visitCallSite(CallSite CS);
public:
@@ -610,6 +613,73 @@ bool CallAnalyzer::visitStore(StoreInst &I) {
return false;
}
+bool CallAnalyzer::visitExtractValue(ExtractValueInst &I) {
+ // Constant folding for extract value is trivial.
+ Constant *C = dyn_cast<Constant>(I.getAggregateOperand());
+ if (!C)
+ C = SimplifiedValues.lookup(I.getAggregateOperand());
+ if (C) {
+ SimplifiedValues[&I] = ConstantExpr::getExtractValue(C, I.getIndices());
+ return true;
+ }
+
+ // SROA can look through these but give them a cost.
+ return false;
+}
+
+bool CallAnalyzer::visitInsertValue(InsertValueInst &I) {
+ // Constant folding for insert value is trivial.
+ Constant *AggC = dyn_cast<Constant>(I.getAggregateOperand());
+ if (!AggC)
+ AggC = SimplifiedValues.lookup(I.getAggregateOperand());
+ Constant *InsertedC = dyn_cast<Constant>(I.getInsertedValueOperand());
+ if (!InsertedC)
+ InsertedC = SimplifiedValues.lookup(I.getInsertedValueOperand());
+ if (AggC && InsertedC) {
+ SimplifiedValues[&I] = ConstantExpr::getInsertValue(AggC, InsertedC,
+ I.getIndices());
+ return true;
+ }
+
+ // SROA can look through these but give them a cost.
+ return false;
+}
+
+/// \brief Try to simplify a call site.
+///
+/// Takes a concrete function and callsite and tries to actually simplify it by
+/// analyzing the arguments and call itself with instsimplify. Returns true if
+/// it has simplified the callsite to some other entity (a constant), making it
+/// free.
+bool CallAnalyzer::simplifyCallSite(Function *F, CallSite CS) {
+ // FIXME: Using the instsimplify logic directly for this is inefficient
+ // because we have to continually rebuild the argument list even when no
+ // simplifications can be performed. Until that is fixed with remapping
+ // inside of instsimplify, directly constant fold calls here.
+ if (!canConstantFoldCallTo(F))
+ return false;
+
+ // Try to re-map the arguments to constants.
+ SmallVector<Constant *, 4> ConstantArgs;
+ ConstantArgs.reserve(CS.arg_size());
+ for (CallSite::arg_iterator I = CS.arg_begin(), E = CS.arg_end();
+ I != E; ++I) {
+ Constant *C = dyn_cast<Constant>(*I);
+ if (!C)
+ C = dyn_cast_or_null<Constant>(SimplifiedValues.lookup(*I));
+ if (!C)
+ return false; // This argument doesn't map to a constant.
+
+ ConstantArgs.push_back(C);
+ }
+ if (Constant *C = ConstantFoldCall(F, ConstantArgs)) {
+ SimplifiedValues[CS.getInstruction()] = C;
+ return true;
+ }
+
+ return false;
+}
+
bool CallAnalyzer::visitCallSite(CallSite CS) {
if (CS.isCall() && cast<CallInst>(CS.getInstruction())->canReturnTwice() &&
!F.getFnAttributes().hasAttribute(Attribute::ReturnsTwice)) {
@@ -621,20 +691,26 @@ bool CallAnalyzer::visitCallSite(CallSite CS) {
cast<CallInst>(CS.getInstruction())->hasFnAttr(Attribute::NoDuplicate))
ContainsNoDuplicateCall = true;
- if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(CS.getInstruction())) {
- switch (II->getIntrinsicID()) {
- default:
- return Base::visitCallSite(CS);
+ if (Function *F = CS.getCalledFunction()) {
+ // When we have a concrete function, first try to simplify it directly.
+ if (simplifyCallSite(F, CS))
+ return true;
- case Intrinsic::memset:
- case Intrinsic::memcpy:
- case Intrinsic::memmove:
- // SROA can usually chew through these intrinsics, but they aren't free.
- return false;
+ // Next check if it is an intrinsic we know about.
+ // FIXME: Lift this into part of the InstVisitor.
+ if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(CS.getInstruction())) {
+ switch (II->getIntrinsicID()) {
+ default:
+ return Base::visitCallSite(CS);
+
+ case Intrinsic::memset:
+ case Intrinsic::memcpy:
+ case Intrinsic::memmove:
+ // SROA can usually chew through these intrinsics, but they aren't free.
+ return false;
+ }
}
- }
- if (Function *F = CS.getCalledFunction()) {
if (F == CS.getInstruction()->getParent()->getParent()) {
// This flag will fully abort the analysis, so don't bother with anything
// else.
diff --git a/test/Transforms/Inline/inline_constprop.ll b/test/Transforms/Inline/inline_constprop.ll
index 0b48a7282f..b2a14fe0b7 100644
--- a/test/Transforms/Inline/inline_constprop.ll
+++ b/test/Transforms/Inline/inline_constprop.ll
@@ -111,6 +111,44 @@ bb.false:
ret i32 %sub
}
+declare {i8, i1} @llvm.uadd.with.overflow.i8(i8 %a, i8 %b)
+
+define i8 @caller4(i8 %z) {
+; Check that we can constant fold through intrinsics such as the
+; overflow-detecting arithmetic instrinsics. These are particularly important
+; as they are used heavily in standard library code and generic C++ code where
+; the arguments are oftent constant but complete generality is required.
+;
+; CHECK: @caller4
+; CHECK-NOT: call
+; CHECK: ret i8 -1
+
+entry:
+ %x = call i8 @callee4(i8 254, i8 14, i8 %z)
+ ret i8 %x
+}
+
+define i8 @callee4(i8 %x, i8 %y, i8 %z) {
+ %uadd = call {i8, i1} @llvm.uadd.with.overflow.i8(i8 %x, i8 %y)
+ %o = extractvalue {i8, i1} %uadd, 1
+ br i1 %o, label %bb.true, label %bb.false
+
+bb.true:
+ ret i8 -1
+
+bb.false:
+ ; This block musn't be counted in the inline cost.
+ %z1 = add i8 %z, 1
+ %z2 = add i8 %z1, 1
+ %z3 = add i8 %z2, 1
+ %z4 = add i8 %z3, 1
+ %z5 = add i8 %z4, 1
+ %z6 = add i8 %z5, 1
+ %z7 = add i8 %z6, 1
+ %z8 = add i8 %z7, 1
+ ret i8 %z8
+}
+
define i32 @PR13412.main() {
; This is a somewhat complicated three layer subprogram that was reported to