[llvm] r335206 - Recommit r333268: [IPSCCP] Use PredicateInfo to propagate facts from cmp instructions.
Florian Hahn via llvm-commits
llvm-commits at lists.llvm.org
Thu Jun 21 00:15:08 PDT 2018
Author: fhahn
Date: Thu Jun 21 00:15:08 2018
New Revision: 335206
URL: http://llvm.org/viewvc/llvm-project?rev=335206&view=rev
Log:
Recommit r333268: [IPSCCP] Use PredicateInfo to propagate facts from cmp instructions.
r335150 should resolve the issues with the clang-with-thin-lto-ubuntu
and clang-with-lto-ubuntu builders.
Original message:
This patch updates IPSCCP to use PredicateInfo to propagate
facts to true branches predicated by EQ and to false branches
predicated by NE.
As a follow up, we should be able to extend it to also propagate additional
facts about nonnull.
Reviewers: davide, mssimpso, dberlin, efriedma
Reviewed By: davide, dberlin
Added:
llvm/trunk/test/Transforms/SCCP/ipsccp-predicated.ll
Modified:
llvm/trunk/include/llvm/Transforms/Scalar/SCCP.h
llvm/trunk/lib/Transforms/IPO/SCCP.cpp
llvm/trunk/lib/Transforms/Scalar/SCCP.cpp
llvm/trunk/test/Other/new-pm-lto-defaults.ll
llvm/trunk/test/Other/opt-O2-pipeline.ll
llvm/trunk/test/Other/opt-O3-pipeline.ll
llvm/trunk/test/Other/opt-Os-pipeline.ll
llvm/trunk/test/Transforms/IPConstantProp/musttail-call.ll
Modified: llvm/trunk/include/llvm/Transforms/Scalar/SCCP.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Transforms/Scalar/SCCP.h?rev=335206&r1=335205&r2=335206&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Transforms/Scalar/SCCP.h (original)
+++ llvm/trunk/include/llvm/Transforms/Scalar/SCCP.h Thu Jun 21 00:15:08 2018
@@ -21,11 +21,13 @@
#ifndef LLVM_TRANSFORMS_SCALAR_SCCP_H
#define LLVM_TRANSFORMS_SCALAR_SCCP_H
+#include "llvm/ADT/STLExtras.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/PassManager.h"
+#include "llvm/Transforms/Utils/PredicateInfo.h"
namespace llvm {
@@ -37,7 +39,9 @@ public:
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
};
-bool runIPSCCP(Module &M, const DataLayout &DL, const TargetLibraryInfo *TLI);
+bool runIPSCCP(
+ Module &M, const DataLayout &DL, const TargetLibraryInfo *TLI,
+ function_ref<std::unique_ptr<PredicateInfo>(Function &)> getPredicateInfo);
} // end namespace llvm
#endif // LLVM_TRANSFORMS_SCALAR_SCCP_H
Modified: llvm/trunk/lib/Transforms/IPO/SCCP.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/IPO/SCCP.cpp?rev=335206&r1=335205&r2=335206&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/IPO/SCCP.cpp (original)
+++ llvm/trunk/lib/Transforms/IPO/SCCP.cpp Thu Jun 21 00:15:08 2018
@@ -1,4 +1,5 @@
#include "llvm/Transforms/IPO/SCCP.h"
+#include "llvm/Analysis/AssumptionCache.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/Transforms/IPO.h"
#include "llvm/Transforms/Scalar/SCCP.h"
@@ -8,7 +9,15 @@ using namespace llvm;
PreservedAnalyses IPSCCPPass::run(Module &M, ModuleAnalysisManager &AM) {
const DataLayout &DL = M.getDataLayout();
auto &TLI = AM.getResult<TargetLibraryAnalysis>(M);
- if (!runIPSCCP(M, DL, &TLI))
+ auto &FAM = AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
+ auto getPredicateInfo =
+ [&FAM](Function &F) -> std::unique_ptr<PredicateInfo> {
+ return make_unique<PredicateInfo>(F,
+ FAM.getResult<DominatorTreeAnalysis>(F),
+ FAM.getResult<AssumptionAnalysis>(F));
+ };
+
+ if (!runIPSCCP(M, DL, &TLI, getPredicateInfo))
return PreservedAnalyses::all();
return PreservedAnalyses::none();
}
@@ -34,10 +43,20 @@ public:
const DataLayout &DL = M.getDataLayout();
const TargetLibraryInfo *TLI =
&getAnalysis<TargetLibraryInfoWrapperPass>().getTLI();
- return runIPSCCP(M, DL, TLI);
+
+ auto getPredicateInfo =
+ [this](Function &F) -> std::unique_ptr<PredicateInfo> {
+ return make_unique<PredicateInfo>(
+ F, this->getAnalysis<DominatorTreeWrapperPass>(F).getDomTree(),
+ this->getAnalysis<AssumptionCacheTracker>().getAssumptionCache(F));
+ };
+
+ return runIPSCCP(M, DL, TLI, getPredicateInfo);
}
void getAnalysisUsage(AnalysisUsage &AU) const override {
+ AU.addRequired<AssumptionCacheTracker>();
+ AU.addRequired<DominatorTreeWrapperPass>();
AU.addRequired<TargetLibraryInfoWrapperPass>();
}
};
@@ -49,6 +68,7 @@ char IPSCCPLegacyPass::ID = 0;
INITIALIZE_PASS_BEGIN(IPSCCPLegacyPass, "ipsccp",
"Interprocedural Sparse Conditional Constant Propagation",
false, false)
+INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)
INITIALIZE_PASS_END(IPSCCPLegacyPass, "ipsccp",
"Interprocedural Sparse Conditional Constant Propagation",
Modified: llvm/trunk/lib/Transforms/Scalar/SCCP.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Scalar/SCCP.cpp?rev=335206&r1=335205&r2=335206&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/Scalar/SCCP.cpp (original)
+++ llvm/trunk/lib/Transforms/Scalar/SCCP.cpp Thu Jun 21 00:15:08 2018
@@ -55,6 +55,7 @@
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/Scalar.h"
+#include "llvm/Transforms/Utils/PredicateInfo.h"
#include <cassert>
#include <utility>
#include <vector>
@@ -248,7 +249,21 @@ class SCCPSolver : public InstVisitor<SC
using Edge = std::pair<BasicBlock *, BasicBlock *>;
DenseSet<Edge> KnownFeasibleEdges;
+ DenseMap<Function *, std::unique_ptr<PredicateInfo>> PredInfos;
+ DenseMap<Value *, SmallPtrSet<User *, 2>> AdditionalUsers;
+
public:
+ void addPredInfo(Function &F, std::unique_ptr<PredicateInfo> PI) {
+ PredInfos[&F] = std::move(PI);
+ }
+
+ const PredicateBase *getPredicateInfoFor(Instruction *I) {
+ auto PI = PredInfos.find(I->getParent()->getParent());
+ if (PI == PredInfos.end())
+ return nullptr;
+ return PI->second->getPredicateInfoFor(I);
+ }
+
SCCPSolver(const DataLayout &DL, const TargetLibraryInfo *tli)
: DL(DL), TLI(tli) {}
@@ -563,6 +578,26 @@ private:
visit(*I);
}
+ // Add U as additional user of V.
+ void addAdditionalUser(Value *V, User *U) {
+ auto Iter = AdditionalUsers.insert({V, {}});
+ Iter.first->second.insert(U);
+ }
+
+ // Mark I's users as changed, including AdditionalUsers.
+ void markUsersAsChanged(Value *I) {
+ for (User *U : I->users())
+ if (auto *UI = dyn_cast<Instruction>(U))
+ OperandChangedState(UI);
+
+ auto Iter = AdditionalUsers.find(I);
+ if (Iter != AdditionalUsers.end()) {
+ for (User *U : Iter->second)
+ if (auto *UI = dyn_cast<Instruction>(U))
+ OperandChangedState(UI);
+ }
+ }
+
private:
friend class InstVisitor<SCCPSolver>;
@@ -1157,6 +1192,59 @@ void SCCPSolver::visitCallSite(CallSite
Function *F = CS.getCalledFunction();
Instruction *I = CS.getInstruction();
+ if (auto *II = dyn_cast<IntrinsicInst>(I)) {
+ if (II->getIntrinsicID() == Intrinsic::ssa_copy) {
+ if (ValueState[I].isOverdefined())
+ return;
+
+ auto *PI = getPredicateInfoFor(I);
+ if (!PI)
+ return;
+
+ auto *PBranch = dyn_cast<PredicateBranch>(getPredicateInfoFor(I));
+ if (!PBranch)
+ return mergeInValue(ValueState[I], I, getValueState(PI->OriginalOp));
+
+ Value *CopyOf = I->getOperand(0);
+ Value *Cond = PBranch->Condition;
+
+ // Everything below relies on the condition being a comparison.
+ auto *Cmp = dyn_cast<CmpInst>(Cond);
+ if (!Cmp)
+ return mergeInValue(ValueState[I], I, getValueState(PI->OriginalOp));
+
+ Value *CmpOp0 = Cmp->getOperand(0);
+ Value *CmpOp1 = Cmp->getOperand(1);
+ if (CopyOf != CmpOp0 && CopyOf != CmpOp1)
+ return mergeInValue(ValueState[I], I, getValueState(PI->OriginalOp));
+
+ if (CmpOp0 != CopyOf)
+ std::swap(CmpOp0, CmpOp1);
+
+ LatticeVal OriginalVal = getValueState(CopyOf);
+ LatticeVal EqVal = getValueState(CmpOp1);
+ LatticeVal &IV = ValueState[I];
+ if (PBranch->TrueEdge && Cmp->getPredicate() == CmpInst::ICMP_EQ) {
+ addAdditionalUser(CmpOp1, I);
+ if (OriginalVal.isConstant())
+ mergeInValue(IV, I, OriginalVal);
+ else
+ mergeInValue(IV, I, EqVal);
+ return;
+ }
+ if (!PBranch->TrueEdge && Cmp->getPredicate() == CmpInst::ICMP_NE) {
+ addAdditionalUser(CmpOp1, I);
+ if (OriginalVal.isConstant())
+ mergeInValue(IV, I, OriginalVal);
+ else
+ mergeInValue(IV, I, EqVal);
+ return;
+ }
+
+ return mergeInValue(IV, I, getValueState(PBranch->OriginalOp));
+ }
+ }
+
// The common case is that we aren't tracking the callee, either because we
// are not doing interprocedural analysis or the callee is indirect, or is
// external. Handle these cases first.
@@ -1268,9 +1356,7 @@ void SCCPSolver::Solve() {
// since all of its users will have already been marked as overdefined
// Update all of the users of this instruction's value.
//
- for (User *U : I->users())
- if (auto *UI = dyn_cast<Instruction>(U))
- OperandChangedState(UI);
+ markUsersAsChanged(I);
}
// Process the instruction work list.
@@ -1287,9 +1373,7 @@ void SCCPSolver::Solve() {
// Update all of the users of this instruction's value.
//
if (I->getType()->isStructTy() || !getValueState(I).isOverdefined())
- for (User *U : I->users())
- if (auto *UI = dyn_cast<Instruction>(U))
- OperandChangedState(UI);
+ markUsersAsChanged(I);
}
// Process the basic block work list.
@@ -1855,8 +1939,9 @@ static void findReturnsToZap(Function &F
}
}
-bool llvm::runIPSCCP(Module &M, const DataLayout &DL,
- const TargetLibraryInfo *TLI) {
+bool llvm::runIPSCCP(
+ Module &M, const DataLayout &DL, const TargetLibraryInfo *TLI,
+ function_ref<std::unique_ptr<PredicateInfo>(Function &)> getPredicateInfo) {
SCCPSolver Solver(DL, TLI);
// Loop over all functions, marking arguments to those with their addresses
@@ -1865,6 +1950,7 @@ bool llvm::runIPSCCP(Module &M, const Da
if (F.isDeclaration())
continue;
+ Solver.addPredInfo(F, getPredicateInfo(F));
// Determine if we can track the function's return values. If so, add the
// function to the solver's set of return-tracked functions.
if (canTrackReturnsInterprocedurally(&F))
@@ -1983,6 +2069,24 @@ bool llvm::runIPSCCP(Module &M, const Da
F.getBasicBlockList().erase(DeadBB);
}
BlocksToErase.clear();
+
+ for (BasicBlock &BB : F) {
+ for (BasicBlock::iterator BI = BB.begin(), E = BB.end(); BI != E;) {
+ Instruction *Inst = &*BI++;
+ if (const PredicateBase *PI = Solver.getPredicateInfoFor(Inst)) {
+ if (auto *II = dyn_cast<IntrinsicInst>(Inst)) {
+ if (II->getIntrinsicID() == Intrinsic::ssa_copy) {
+ Value *Op = II->getOperand(0);
+ Inst->replaceAllUsesWith(Op);
+ Inst->eraseFromParent();
+ continue;
+ }
+ }
+ Inst->replaceAllUsesWith(PI->OriginalOp);
+ Inst->eraseFromParent();
+ }
+ }
+ }
}
// If we inferred constant or undef return values for a function, we replaced
Modified: llvm/trunk/test/Other/new-pm-lto-defaults.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Other/new-pm-lto-defaults.ll?rev=335206&r1=335205&r2=335206&view=diff
==============================================================================
--- llvm/trunk/test/Other/new-pm-lto-defaults.ll (original)
+++ llvm/trunk/test/Other/new-pm-lto-defaults.ll Thu Jun 21 00:15:08 2018
@@ -41,6 +41,8 @@
; CHECK-O2-NEXT: Running analysis: ProfileSummaryAnalysis
; CHECK-O2-NEXT: Running analysis: OptimizationRemarkEmitterAnalysis
; CHECK-O2-NEXT: Running pass: IPSCCPPass
+; CHECK-O2-DAG: Running analysis: AssumptionAnalysis on foo
+; CHECK-O2-DAG: Running analysis: DominatorTreeAnalysis on foo
; CHECK-O2-NEXT: Running pass: CalledValuePropagationPass
; CHECK-O-NEXT: Running pass: ModuleToPostOrderCGSCCPassAdaptor<{{.*}}PostOrderFunctionAttrsPass>
; CHECK-O-NEXT: Running analysis: InnerAnalysisManagerProxy<{{.*}}SCC
@@ -56,8 +58,6 @@
; CHECK-O-NEXT: Running pass: WholeProgramDevirtPass
; CHECK-O2-NEXT: Running pass: GlobalOptPass
; CHECK-O2-NEXT: Running pass: ModuleToFunctionPassAdaptor<{{.*}}PromotePass>
-; CHECK-O2-NEXT: Running analysis: DominatorTreeAnalysis
-; CHECK-O2-NEXT: Running analysis: AssumptionAnalysis
; CHECK-O2-NEXT: Running pass: ConstantMergePass
; CHECK-O2-NEXT: Running pass: DeadArgumentEliminationPass
; CHECK-O2-NEXT: Running pass: ModuleToFunctionPassAdaptor<{{.*}}PassManager{{.*}}>
Modified: llvm/trunk/test/Other/opt-O2-pipeline.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Other/opt-O2-pipeline.ll?rev=335206&r1=335205&r2=335206&view=diff
==============================================================================
--- llvm/trunk/test/Other/opt-O2-pipeline.ll (original)
+++ llvm/trunk/test/Other/opt-O2-pipeline.ll Thu Jun 21 00:15:08 2018
@@ -28,6 +28,7 @@
; CHECK-NEXT: Force set function attributes
; CHECK-NEXT: Infer set function attributes
; CHECK-NEXT: Interprocedural Sparse Conditional Constant Propagation
+; CHECK-NEXT: Unnamed pass: implement Pass::getPassName()
; CHECK-NEXT: Called Value Propagation
; CHECK-NEXT: Global Variable Optimizer
; CHECK-NEXT: Unnamed pass: implement Pass::getPassName()
@@ -273,6 +274,9 @@
; CHECK-NEXT: Module Verifier
; CHECK-NEXT: Bitcode Writer
; CHECK-NEXT: Pass Arguments:
+; CHECK-NEXT: FunctionPass Manager
+; CHECK-NEXT: Dominator Tree Construction
+; CHECK-NEXT: Pass Arguments:
; CHECK-NEXT: Target Library Information
; CHECK-NEXT: FunctionPass Manager
; CHECK-NEXT: Dominator Tree Construction
Modified: llvm/trunk/test/Other/opt-O3-pipeline.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Other/opt-O3-pipeline.ll?rev=335206&r1=335205&r2=335206&view=diff
==============================================================================
--- llvm/trunk/test/Other/opt-O3-pipeline.ll (original)
+++ llvm/trunk/test/Other/opt-O3-pipeline.ll Thu Jun 21 00:15:08 2018
@@ -30,6 +30,7 @@
; CHECK-NEXT: FunctionPass Manager
; CHECK-NEXT: Call-site splitting
; CHECK-NEXT: Interprocedural Sparse Conditional Constant Propagation
+; CHECK-NEXT: Unnamed pass: implement Pass::getPassName()
; CHECK-NEXT: Called Value Propagation
; CHECK-NEXT: Global Variable Optimizer
; CHECK-NEXT: Unnamed pass: implement Pass::getPassName()
@@ -277,6 +278,9 @@
; CHECK-NEXT: Module Verifier
; CHECK-NEXT: Bitcode Writer
; CHECK-NEXT: Pass Arguments:
+; CHECK-NEXT: FunctionPass Manager
+; CHECK-NEXT: Dominator Tree Construction
+; CHECK-NEXT: Pass Arguments:
; CHECK-NEXT: Target Library Information
; CHECK-NEXT: FunctionPass Manager
; CHECK-NEXT: Dominator Tree Construction
Modified: llvm/trunk/test/Other/opt-Os-pipeline.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Other/opt-Os-pipeline.ll?rev=335206&r1=335205&r2=335206&view=diff
==============================================================================
--- llvm/trunk/test/Other/opt-Os-pipeline.ll (original)
+++ llvm/trunk/test/Other/opt-Os-pipeline.ll Thu Jun 21 00:15:08 2018
@@ -28,6 +28,7 @@
; CHECK-NEXT: Force set function attributes
; CHECK-NEXT: Infer set function attributes
; CHECK-NEXT: Interprocedural Sparse Conditional Constant Propagation
+; CHECK-NEXT: Unnamed pass: implement Pass::getPassName()
; CHECK-NEXT: Called Value Propagation
; CHECK-NEXT: Global Variable Optimizer
; CHECK-NEXT: Unnamed pass: implement Pass::getPassName()
@@ -259,6 +260,9 @@
; CHECK-NEXT: Module Verifier
; CHECK-NEXT: Bitcode Writer
; CHECK-NEXT: Pass Arguments:
+; CHECK-NEXT: FunctionPass Manager
+; CHECK-NEXT: Dominator Tree Construction
+; CHECK-NEXT: Pass Arguments:
; CHECK-NEXT: Target Library Information
; CHECK-NEXT: FunctionPass Manager
; CHECK-NEXT: Dominator Tree Construction
Modified: llvm/trunk/test/Transforms/IPConstantProp/musttail-call.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/IPConstantProp/musttail-call.ll?rev=335206&r1=335205&r2=335206&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/IPConstantProp/musttail-call.ll (original)
+++ llvm/trunk/test/Transforms/IPConstantProp/musttail-call.ll Thu Jun 21 00:15:08 2018
@@ -9,7 +9,7 @@ define i8* @start(i8 %v) {
%c1 = icmp eq i8 %v, 0
br i1 %c1, label %true, label %false
true:
- ; CHECK: %ca = musttail call i8* @side_effects(i8 %v)
+ ; CHECK: %ca = musttail call i8* @side_effects(i8 0)
; CHECK: ret i8* %ca
%ca = musttail call i8* @side_effects(i8 %v)
ret i8* %ca
@@ -34,7 +34,7 @@ define internal i8* @side_effects(i8 %v)
; is always `null`.
; The call can't be removed due to `external` call above, though.
- ; CHECK: %ca = musttail call i8* @start(i8 %v)
+ ; CHECK: %ca = musttail call i8* @start(i8 0)
%ca = musttail call i8* @start(i8 %v)
; Thus the result must be returned anyway
Added: llvm/trunk/test/Transforms/SCCP/ipsccp-predicated.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/SCCP/ipsccp-predicated.ll?rev=335206&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/SCCP/ipsccp-predicated.ll (added)
+++ llvm/trunk/test/Transforms/SCCP/ipsccp-predicated.ll Thu Jun 21 00:15:08 2018
@@ -0,0 +1,68 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -ipsccp -S | FileCheck %s
+
+define i32 @test1(i32 %v) {
+; CHECK-LABEL: @test1(
+; CHECK-NEXT: Entry:
+; CHECK-NEXT: [[TOBOOL1:%.*]] = icmp eq i32 [[V:%.*]], 10
+; CHECK-NEXT: br i1 [[TOBOOL1]], label [[T:%.*]], label [[F:%.*]]
+; CHECK: T:
+; CHECK-NEXT: [[R:%.*]] = call i32 @callee(i32 20)
+; CHECK-NEXT: ret i32 [[R]]
+; CHECK: F:
+; CHECK-NEXT: [[X:%.*]] = call i32 @callee(i32 [[V]])
+; CHECK-NEXT: ret i32 [[X]]
+;
+Entry:
+ %tobool1 = icmp eq i32 %v, 10
+ br i1 %tobool1, label %T, label %F
+
+T:
+ %a = add i32 %v, 10
+ %r = call i32 @callee(i32 %a)
+ ret i32 %r
+
+F:
+ %x = call i32 @callee(i32 %v)
+ ret i32 %x
+}
+
+
+define internal i32 @test2(i32 %v, i32 %c) {
+; CHECK-LABEL: @test2(
+; CHECK-NEXT: Entry:
+; CHECK-NEXT: [[TOBOOL1:%.*]] = icmp eq i32 [[V:%.*]], 99
+; CHECK-NEXT: br i1 [[TOBOOL1]], label [[T:%.*]], label [[F:%.*]]
+; CHECK: T:
+; CHECK-NEXT: [[R:%.*]] = call i32 @callee(i32 109)
+; CHECK-NEXT: ret i32 [[R]]
+; CHECK: F:
+; CHECK-NEXT: [[X:%.*]] = call i32 @callee(i32 [[V]])
+; CHECK-NEXT: ret i32 [[X]]
+;
+Entry:
+ %tobool1 = icmp eq i32 %v, %c
+ br i1 %tobool1, label %T, label %F
+
+T:
+ %a = add i32 %v, 10
+ %r = call i32 @callee(i32 %a)
+ ret i32 %r
+
+F:
+ %x = call i32 @callee(i32 %v)
+ ret i32 %x
+}
+
+define i32 @caller_test2(i32 %v) {
+; CHECK-LABEL: @caller_test2(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[R:%.*]] = call i32 @test2(i32 [[V:%.*]], i32 99)
+; CHECK-NEXT: ret i32 [[R]]
+;
+entry:
+ %r = call i32 @test2(i32 %v, i32 99)
+ ret i32 %r
+}
+
+declare i32 @callee(i32)
More information about the llvm-commits
mailing list