| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,176 @@ | ||
| //===------- llvm/IR/OptBisect/Bisect.cpp - LLVM Bisect support --------===// | ||
| // | ||
| // The LLVM Compiler Infrastructure | ||
| // | ||
| // This file is distributed under the University of Illinois Open Source | ||
| // License. See LICENSE.TXT for details. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
| /// | ||
| /// \file | ||
| /// This file implements support for a bisecting optimizations based on a | ||
| /// command line option. | ||
| /// | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "llvm/Analysis/CallGraphSCCPass.h" | ||
| #include "llvm/Analysis/LazyCallGraph.h" | ||
| #include "llvm/Analysis/LoopInfo.h" | ||
| #include "llvm/IR/Module.h" | ||
| #include "llvm/IR/OptBisect.h" | ||
| #include "llvm/Pass.h" | ||
| #include "llvm/Support/CommandLine.h" | ||
| #include "llvm/Support/raw_ostream.h" | ||
|
|
||
| using namespace llvm; | ||
|
|
||
| static cl::opt<int> OptBisectLimit("opt-bisect-limit", cl::Hidden, | ||
| cl::init(INT_MAX), cl::Optional, | ||
| cl::desc("Maximum optimization to perform")); | ||
|
|
||
| OptBisect::OptBisect() { | ||
| BisectEnabled = OptBisectLimit != INT_MAX; | ||
| } | ||
|
|
||
| static void printPassMessage(const StringRef &Name, int PassNum, | ||
| StringRef TargetDesc, bool Running) { | ||
| StringRef Status = Running ? "" : "NOT "; | ||
| errs() << "BISECT: " << Status << "running pass " | ||
| << "(" << PassNum << ") " << Name << " on " << TargetDesc << "\n"; | ||
| } | ||
|
|
||
| static void printCaseMessage(int CaseNum, StringRef Msg, bool Running) { | ||
| if (Running) | ||
| errs() << "BISECT: running case ("; | ||
| else | ||
| errs() << "BISECT: NOT running case ("; | ||
| errs() << CaseNum << "): " << Msg << "\n"; | ||
| } | ||
|
|
||
| static std::string getDescription(const Module &M) { | ||
| return "module (" + M.getName().str() + ")"; | ||
| } | ||
|
|
||
| static std::string getDescription(const Function &F) { | ||
| return "function (" + F.getName().str() + ")"; | ||
| } | ||
|
|
||
| static std::string getDescription(const BasicBlock &BB) { | ||
| return "basic block (" + BB.getName().str() + ") in function (" + | ||
| BB.getParent()->getName().str() + ")"; | ||
| } | ||
|
|
||
| static std::string getDescription(const Loop &L) { | ||
| // FIXME: I'd like to be able to provide a better description here, but | ||
| // calling L->getHeader() would introduce a new dependency on the | ||
| // LLVMCore library. | ||
| return "loop"; | ||
| } | ||
|
|
||
| static std::string getDescription(const CallGraphSCC &SCC) { | ||
| std::string Desc = "SCC ("; | ||
| bool First = true; | ||
| for (CallGraphNode *CGN : SCC) { | ||
| if (First) | ||
| First = false; | ||
| else | ||
| Desc += ", "; | ||
| Function *F = CGN->getFunction(); | ||
| if (F) | ||
| Desc += F->getName(); | ||
| else | ||
| Desc += "<<null function>>"; | ||
| } | ||
| Desc += ")"; | ||
| return Desc; | ||
| } | ||
|
|
||
| static std::string getDescription(const LazyCallGraph::SCC &SCC) { | ||
| std::string Desc = "SCC ("; | ||
| bool First = true; | ||
| for (LazyCallGraph::Node &CGN : SCC) { | ||
| if (First) | ||
| First = false; | ||
| else | ||
| Desc += ", "; | ||
| Function &F = CGN.getFunction(); | ||
| Desc += F.getName(); | ||
| } | ||
| Desc += ")"; | ||
| return Desc; | ||
| } | ||
|
|
||
| // Force instantiations. | ||
| template bool OptBisect::shouldRunPass(const Pass *, const Module &); | ||
| template bool OptBisect::shouldRunPass(const Pass *, const Function &); | ||
| template bool OptBisect::shouldRunPass(const Pass *, const BasicBlock &); | ||
| template bool OptBisect::shouldRunPass(const Pass *, const Loop &); | ||
| template bool OptBisect::shouldRunPass(const Pass *, const CallGraphSCC &); | ||
| template bool OptBisect::shouldRunPass(const StringRef PassName, | ||
| const Module &); | ||
| template bool OptBisect::shouldRunPass(const StringRef PassName, | ||
| const Function &); | ||
| template bool OptBisect::shouldRunPass(const StringRef PassName, | ||
| const BasicBlock &); | ||
| template bool OptBisect::shouldRunPass(const StringRef PassName, const Loop &); | ||
| template bool OptBisect::shouldRunPass(const StringRef PassName, | ||
| const LazyCallGraph::SCC &); | ||
|
|
||
| template <class UnitT> | ||
| bool OptBisect::shouldRunPass(const Pass *P, const UnitT &U) { | ||
| if (!BisectEnabled) | ||
| return true; | ||
| return checkPass(P->getPassName(), getDescription(U)); | ||
| } | ||
|
|
||
| // Interface function for the new pass manager. | ||
| template <class UnitT> | ||
| bool OptBisect::shouldRunPass(const StringRef PassName, const UnitT &U) { | ||
| if (!BisectEnabled) | ||
| return true; | ||
| return checkPass(PassName, getDescription(U)); | ||
| } | ||
|
|
||
| bool OptBisect::checkPass(const StringRef PassName, | ||
| const StringRef TargetDesc) { | ||
| assert(BisectEnabled); | ||
|
|
||
| int CurBisectNum = ++LastBisectNum; | ||
| bool ShouldRun = (OptBisectLimit == -1 || CurBisectNum <= OptBisectLimit); | ||
| printPassMessage(PassName, CurBisectNum, TargetDesc, ShouldRun); | ||
| return ShouldRun; | ||
| } | ||
|
|
||
| bool OptBisect::shouldRunCase(const Twine &Msg) { | ||
| if (!BisectEnabled) | ||
| return true; | ||
| int CurFuelNum = ++LastBisectNum; | ||
| bool ShouldRun = (OptBisectLimit == -1 || CurFuelNum <= OptBisectLimit); | ||
| printCaseMessage(CurFuelNum, Msg.str(), ShouldRun); | ||
| return ShouldRun; | ||
| } | ||
|
|
||
| bool llvm::skipPassForModule(const StringRef PassName, const Module &M) { | ||
| return !M.getContext().getOptBisect().shouldRunPass(PassName, M); | ||
| } | ||
|
|
||
| bool llvm::skipPassForFunction(const StringRef PassName, const Function &F) { | ||
| return !F.getContext().getOptBisect().shouldRunPass(PassName, F); | ||
| } | ||
| #if 0 | ||
| bool llvm::skipPassForBasicBlock(const StringRef PassName, const BasicBlock &BB) { | ||
| return !BB.getContext().getOptBisect().shouldRunPass(PassName, BB); | ||
| } | ||
|
|
||
| bool llvm::skipPassForLoop(const StringRef PassName, const Loop &L) { | ||
| const Function *F = L.getHeader()->getParent(); | ||
| if (!F) | ||
| return false; | ||
| return !F->getContext().getOptBisect().shouldRunPass(PassName, L); | ||
| } | ||
| #endif | ||
| bool llvm::skipPassForSCC(const StringRef PassName, const LazyCallGraph::SCC &SCC) { | ||
| LLVMContext &Context = SCC.begin()->getFunction().getContext(); | ||
| return !Context.getOptBisect().shouldRunPass(PassName, SCC); | ||
| } | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| #!/usr/bin/env python | ||
|
|
||
| import os | ||
| import sys | ||
| import argparse | ||
| import subprocess | ||
|
|
||
| parser = argparse.ArgumentParser() | ||
|
|
||
| parser.add_argument('--start', type=int, default=0) | ||
| parser.add_argument('--end', type=int, default=(1 << 32)) | ||
| parser.add_argument('--optcmd', default=("opt")) | ||
| parser.add_argument('--filecheckcmd', default=("FileCheck")) | ||
| parser.add_argument('--prefix', default=("CHECK-BISECT")) | ||
| parser.add_argument('--test', default=("")) | ||
|
|
||
| args = parser.parse_args() | ||
|
|
||
| start = args.start | ||
| end = args.end | ||
|
|
||
| opt_command = [args.optcmd, "-O2", "-opt-bisect-limit=%(count)s", "-S", args.test] | ||
| check_command = [args.filecheckcmd, args.test, "--check-prefix=%s" % args.prefix] | ||
| last = None | ||
| while start != end and start != end-1: | ||
| count = int(round(start + (end - start)/2)) | ||
| cmd = [x % {'count':count} for x in opt_command] | ||
| print("opt: " + str(cmd)) | ||
| opt_result = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) | ||
| filecheck_result = subprocess.Popen(check_command, stdin=opt_result.stdout) | ||
| opt_result.stdout.close() | ||
| opt_result.stderr.close() | ||
| filecheck_result.wait() | ||
| if filecheck_result.returncode == 0: | ||
| start = count | ||
| else: | ||
| end = count | ||
|
|
||
| print("Last good count: %d" % start) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,148 @@ | ||
| ; This file verifies the behavior of the OptBisect class, which is used to | ||
| ; diagnose optimization related failures. The tests check various | ||
| ; invocations that result in different sets of optimization passes that | ||
| ; are run in different ways. | ||
| ; | ||
| ; This set of tests exercises the legacy pass manager interface to the OptBisect | ||
| ; class. Because the exact set of optimizations that will be run may | ||
| ; change over time, these tests are written in a more general manner than the | ||
| ; corresponding tests for the new pass manager. | ||
| ; | ||
| ; Don't use NEXT checks or hard-code pass numbering so that this won't fail if | ||
| ; new passes are inserted. | ||
|
|
||
|
|
||
| ; Verify that the file can be compiled to an object file at -O3 with all | ||
| ; skippable passes skipped. | ||
|
|
||
| ; RUN: opt -O3 -opt-bisect-limit=0 < %s | llc -O3 -opt-bisect-limit=0 | ||
|
|
||
|
|
||
| ; Verify that no skippable passes are run with -opt-bisect-limit=0. | ||
|
|
||
| ; RUN: opt -disable-output -disable-verify -O3 -opt-bisect-limit=0 %s 2>&1 \ | ||
| ; RUN: | FileCheck %s --check-prefix=CHECK-SKIP-ALL | ||
| ; CHECK-SKIP-ALL: BISECT: NOT running pass ({{[0-9]+}}) | ||
| ; CHECK-SKIP-ALL-NOT: BISECT: running pass ({{[0-9]+}}) | ||
|
|
||
|
|
||
| ; Verify that we can use the opt-bisect-helper.py script (derived from | ||
| ; utils/bisect) to locate the optimization that inlines the call to | ||
| ; f2() in f3(). | ||
|
|
||
| ; RUN: %python %S/opt-bisect-helper.py --start=0 --end=256 --optcmd=opt \ | ||
| ; RUN: --filecheckcmd=FileCheck --test=%s \ | ||
| ; RUN: --prefix=CHECK-BISECT-INLINE-HELPER \ | ||
| ; RUN: | FileCheck %s --check-prefix=CHECK-BISECT-INLINE-RESULT | ||
| ; The helper script uses this to find the optimization that inlines the call. | ||
| ; CHECK-BISECT-INLINE-HELPER: call i32 @f2() | ||
| ; These checks verifies that the optimization was found. | ||
| ; CHECK-BISECT-INLINE-RESULT-NOT: Last good count: 0 | ||
| ; CHECK-BISECT-INLINE-RESULT: Last good count: {{[0-9]+}} | ||
|
|
||
|
|
||
| ; Test a module pass. | ||
|
|
||
| ; RUN: opt -disable-output -disable-verify -deadargelim -opt-bisect-limit=-1 %s \ | ||
| ; RUN: 2>&1 | FileCheck %s --check-prefix=CHECK-DEADARG | ||
| ; CHECK-DEADARG: BISECT: running pass ({{[0-9]+}}) Dead Argument Elimination on module | ||
|
|
||
| ; RUN: opt -disable-output -disable-verify -deadargelim -opt-bisect-limit=0 %s \ | ||
| ; RUN: 2>&1 | FileCheck %s --check-prefix=CHECK-NOT-DEADARG | ||
| ; CHECK-NOT-DEADARG: BISECT: NOT running pass ({{[0-9]+}}) Dead Argument Elimination on module | ||
|
|
||
|
|
||
| ; Test an SCC pass. | ||
|
|
||
| ; RUN: opt -disable-output -disable-verify -inline -opt-bisect-limit=-1 %s \ | ||
| ; RUN: 2>&1 | FileCheck %s --check-prefix=CHECK-INLINE | ||
| ; CHECK-INLINE: BISECT: running pass ({{[0-9]+}}) Function Integration/Inlining on SCC (<<null function>>) | ||
| ; CHECK-INLINE: BISECT: running pass ({{[0-9]+}}) Function Integration/Inlining on SCC (g) | ||
| ; CHECK-INLINE: BISECT: running pass ({{[0-9]+}}) Function Integration/Inlining on SCC (f1) | ||
| ; CHECK-INLINE: BISECT: running pass ({{[0-9]+}}) Function Integration/Inlining on SCC (f2) | ||
| ; CHECK-INLINE: BISECT: running pass ({{[0-9]+}}) Function Integration/Inlining on SCC (f3) | ||
| ; CHECK-INLINE: BISECT: running pass ({{[0-9]+}}) Function Integration/Inlining on SCC (<<null function>>) | ||
|
|
||
| ; RUN: opt -disable-output -disable-verify -inline -opt-bisect-limit=0 %s \ | ||
| ; RUN: 2>&1 | FileCheck %s --check-prefix=CHECK-NOT-INLINE | ||
| ; CHECK-NOT-INLINE: BISECT: NOT running pass ({{[0-9]+}}) Function Integration/Inlining on SCC (<<null function>>) | ||
| ; CHECK-NOT-INLINE: BISECT: NOT running pass ({{[0-9]+}}) Function Integration/Inlining on SCC (g) | ||
| ; CHECK-NOT-INLINE: BISECT: NOT running pass ({{[0-9]+}}) Function Integration/Inlining on SCC (f1) | ||
| ; CHECK-NOT-INLINE: BISECT: NOT running pass ({{[0-9]+}}) Function Integration/Inlining on SCC (f2) | ||
| ; CHECK-NOT-INLINE: BISECT: NOT running pass ({{[0-9]+}}) Function Integration/Inlining on SCC (f3) | ||
| ; CHECK-NOT-INLINE: BISECT: NOT running pass ({{[0-9]+}}) Function Integration/Inlining on SCC (<<null function>>) | ||
|
|
||
|
|
||
| ; Test a function pass. | ||
|
|
||
| ; RUN: opt -disable-output -disable-verify -early-cse -opt-bisect-limit=-1 \ | ||
| ; RUN: %s 2>&1 | FileCheck %s --check-prefix=CHECK-EARLY-CSE | ||
| ; CHECK-EARLY-CSE: BISECT: running pass ({{[0-9]+}}) Early CSE on function (f1) | ||
| ; CHECK-EARLY-CSE: BISECT: running pass ({{[0-9]+}}) Early CSE on function (f2) | ||
| ; CHECK-EARLY-CSE: BISECT: running pass ({{[0-9]+}}) Early CSE on function (f3) | ||
|
|
||
| ; RUN: opt -disable-output -disable-verify -early-cse -opt-bisect-limit=0 %s \ | ||
| ; RUN: 2>&1 | FileCheck %s --check-prefix=CHECK-NOT-EARLY-CSE | ||
| ; CHECK-NOT-EARLY-CSE: BISECT: NOT running pass ({{[0-9]+}}) Early CSE on function (f1) | ||
| ; CHECK-NOT-EARLY-CSE: BISECT: NOT running pass ({{[0-9]+}}) Early CSE on function (f2) | ||
| ; CHECK-NOT-EARLY-CSE: BISECT: NOT running pass ({{[0-9]+}}) Early CSE on function (f3) | ||
|
|
||
|
|
||
| ; Test a loop pass. | ||
|
|
||
| ; RUN: opt -disable-output -disable-verify -loop-reduce -opt-bisect-limit=-1 \ | ||
| ; RUN: %s 2>&1 | FileCheck %s --check-prefix=CHECK-LOOP-REDUCE | ||
| ; CHECK-LOOP-REDUCE: BISECT: running pass ({{[0-9]+}}) Loop Strength Reduction on loop | ||
| ; CHECK-LOOP-REDUCE: BISECT: running pass ({{[0-9]+}}) Loop Strength Reduction on loop | ||
| ; CHECK-LOOP-REDUCE: BISECT: running pass ({{[0-9]+}}) Loop Strength Reduction on loop | ||
| ; CHECK-LOOP-REDUCE: BISECT: running pass ({{[0-9]+}}) Loop Strength Reduction on loop | ||
| ; CHECK-LOOP-REDUCE: BISECT: running pass ({{[0-9]+}}) Loop Strength Reduction on loop | ||
|
|
||
| ; RUN: opt -disable-output -disable-verify -loop-reduce -opt-bisect-limit=0 \ | ||
| ; RUN: %s 2>&1 | FileCheck %s --check-prefix=CHECK-NOT-LOOP-REDUCE | ||
| ; CHECK-NOT-LOOP-REDUCE: BISECT: NOT running pass ({{[0-9]+}}) Loop Strength Reduction on loop | ||
| ; CHECK-NOT-LOOP-REDUCE: BISECT: NOT running pass ({{[0-9]+}}) Loop Strength Reduction on loop | ||
| ; CHECK-NOT-LOOP-REDUCE: BISECT: NOT running pass ({{[0-9]+}}) Loop Strength Reduction on loop | ||
| ; CHECK-NOT-LOOP-REDUCE: BISECT: NOT running pass ({{[0-9]+}}) Loop Strength Reduction on loop | ||
| ; CHECK-NOT-LOOP-REDUCE: BISECT: NOT running pass ({{[0-9]+}}) Loop Strength Reduction on loop | ||
|
|
||
|
|
||
| declare i32 @g() | ||
|
|
||
| define void @f1() { | ||
| entry: | ||
| br label %loop.0 | ||
| loop.0: | ||
| br i1 undef, label %loop.0.0, label %loop.1 | ||
| loop.0.0: | ||
| br i1 undef, label %loop.0.0, label %loop.0.1 | ||
| loop.0.1: | ||
| br i1 undef, label %loop.0.1, label %loop.0 | ||
| loop.1: | ||
| br i1 undef, label %loop.1, label %loop.1.bb1 | ||
| loop.1.bb1: | ||
| br i1 undef, label %loop.1, label %loop.1.bb2 | ||
| loop.1.bb2: | ||
| br i1 undef, label %end, label %loop.1.0 | ||
| loop.1.0: | ||
| br i1 undef, label %loop.1.0, label %loop.1 | ||
| end: | ||
| ret void | ||
| } | ||
|
|
||
| define i32 @f2() { | ||
| entry: | ||
| ret i32 0 | ||
| } | ||
|
|
||
| define i32 @f3() { | ||
| entry: | ||
| %temp = call i32 @g() | ||
| %icmp = icmp ugt i32 %temp, 2 | ||
| br i1 %icmp, label %bb.true, label %bb.false | ||
| bb.true: | ||
| %temp2 = call i32 @f2() | ||
| ret i32 %temp2 | ||
| bb.false: | ||
| ret i32 0 | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,109 @@ | ||
| ; This file verifies the behavior of the OptBisect class, which is used to | ||
| ; diagnose optimization related failures. The tests check various | ||
| ; invocations that result in different sets of optimization passes that | ||
| ; are run in different ways. | ||
| ; | ||
| ; Because the exact set of optimizations that will be run is expected to | ||
| ; change over time, the checks for disabling passes are written in a | ||
| ; conservative way that avoids assumptions about which specific passes | ||
| ; will be disabled. | ||
|
|
||
| ; RUN: opt -disable-output -disable-verify \ | ||
| ; RUN: -passes=inferattrs -opt-bisect-limit=-1 %s 2>&1 \ | ||
| ; RUN: | FileCheck %s --check-prefix=CHECK-MODULE-PASS | ||
| ; CHECK-MODULE-PASS: BISECT: running pass (1) InferFunctionAttrsPass on module | ||
|
|
||
| ; RUN: opt -disable-output -disable-verify \ | ||
| ; RUN: -passes=inferattrs -opt-bisect-limit=0 %s 2>&1 \ | ||
| ; RUN: | FileCheck %s --check-prefix=CHECK-LIMIT-MODULE-PASS | ||
| ; CHECK-LIMIT-MODULE-PASS: BISECT: NOT running pass (1) InferFunctionAttrsPass on module | ||
|
|
||
| ; RUN: opt -disable-output -disable-verify \ | ||
| ; RUN: -passes=early-cse -opt-bisect-limit=-1 %s 2>&1 \ | ||
| ; RUN: | FileCheck %s --check-prefix=CHECK-FUNCTION-PASS | ||
| ; CHECK-FUNCTION-PASS: BISECT: running pass (1) EarlyCSEPass on function (f1) | ||
| ; CHECK-FUNCTION-PASS: BISECT: running pass (2) EarlyCSEPass on function (f2) | ||
| ; CHECK-FUNCTION-PASS: BISECT: running pass (3) EarlyCSEPass on function (f3) | ||
|
|
||
| ; RUN: opt -disable-output -disable-verify \ | ||
| ; RUN: -passes=early-cse -opt-bisect-limit=2 %s 2>&1 \ | ||
| ; RUN: | FileCheck %s --check-prefix=CHECK-LIMIT-FUNCTION-PASS | ||
| ; CHECK-LIMIT-FUNCTION-PASS: BISECT: running pass (1) EarlyCSEPass on function (f1) | ||
| ; CHECK-LIMIT-FUNCTION-PASS: BISECT: running pass (2) EarlyCSEPass on function (f2) | ||
| ; CHECK-LIMIT-FUNCTION-PASS: BISECT: NOT running pass (3) EarlyCSEPass on function (f3) | ||
|
|
||
| ; RUN: opt -disable-output -disable-verify \ | ||
| ; RUN: -passes=function-attrs -opt-bisect-limit=-1 %s 2>&1 \ | ||
| ; RUN: | FileCheck %s --check-prefix=CHECK-CGSCC-PASS | ||
| ; CHECK-CGSCC-PASS: BISECT: running pass (1) PostOrderFunctionAttrsPass on SCC (f2) | ||
| ; CHECK-CGSCC-PASS: BISECT: running pass (2) PostOrderFunctionAttrsPass on SCC (f3) | ||
| ; CHECK-CGSCC-PASS: BISECT: running pass (3) PostOrderFunctionAttrsPass on SCC (f1) | ||
|
|
||
| ; RUN: opt -disable-output -disable-verify \ | ||
| ; RUN: -passes=function-attrs -opt-bisect-limit=2 %s 2>&1 \ | ||
| ; RUN: | FileCheck %s --check-prefix=CHECK-LIMIT-CGSCC-PASS | ||
| ; CHECK-LIMIT-CGSCC-PASS: BISECT: running pass (1) PostOrderFunctionAttrsPass on SCC (f2) | ||
| ; CHECK-LIMIT-CGSCC-PASS: BISECT: running pass (2) PostOrderFunctionAttrsPass on SCC (f3) | ||
| ; CHECK-LIMIT-CGSCC-PASS: BISECT: NOT running pass (3) PostOrderFunctionAttrsPass on SCC (f1) | ||
|
|
||
| ; RUN: opt -disable-output -disable-verify -opt-bisect-limit=-1 \ | ||
| ; RUN: -passes='inferattrs,cgscc(function-attrs,function(early-cse))' %s 2>&1 \ | ||
| ; RUN: | FileCheck %s --check-prefix=CHECK-MULTI-PASS | ||
| ; CHECK-MULTI-PASS: BISECT: running pass (1) InferFunctionAttrsPass on module | ||
| ; CHECK-MULTI-PASS: BISECT: running pass (2) PostOrderFunctionAttrsPass on SCC (f2) | ||
| ; CHECK-MULTI-PASS: BISECT: running pass (3) EarlyCSEPass on function (f2) | ||
| ; CHECK-MULTI-PASS: BISECT: running pass (4) PostOrderFunctionAttrsPass on SCC (f3) | ||
| ; CHECK-MULTI-PASS: BISECT: running pass (5) EarlyCSEPass on function (f3) | ||
| ; CHECK-MULTI-PASS: BISECT: running pass (6) PostOrderFunctionAttrsPass on SCC (f1) | ||
| ; CHECK-MULTI-PASS: BISECT: running pass (7) EarlyCSEPass on function (f1) | ||
|
|
||
| ; RUN: opt -disable-output -disable-verify -opt-bisect-limit=5 \ | ||
| ; RUN: -passes='inferattrs,cgscc(function-attrs,function(early-cse))' %s 2>&1 \ | ||
| ; RUN: | FileCheck %s --check-prefix=CHECK-LIMIT-MULTI-PASS | ||
| ; CHECK-LIMIT-MULTI-PASS: BISECT: running pass (1) InferFunctionAttrsPass on module | ||
| ; CHECK-LIMIT-MULTI-PASS: BISECT: running pass (2) PostOrderFunctionAttrsPass on SCC (f2) | ||
| ; CHECK-LIMIT-MULTI-PASS: BISECT: running pass (3) EarlyCSEPass on function (f2) | ||
| ; CHECK-LIMIT-MULTI-PASS: BISECT: running pass (4) PostOrderFunctionAttrsPass on SCC (f3) | ||
| ; CHECK-LIMIT-MULTI-PASS: BISECT: running pass (5) EarlyCSEPass on function (f3) | ||
| ; CHECK-LIMIT-MULTI-PASS: BISECT: NOT running pass (6) PostOrderFunctionAttrsPass on SCC (f1) | ||
| ; CHECK-LIMIT-MULTI-PASS: BISECT: NOT running pass (7) EarlyCSEPass on function (f1) | ||
|
|
||
| declare i32 @g() | ||
|
|
||
| define void @f1() { | ||
| entry: | ||
| br label %loop.0 | ||
| loop.0: | ||
| br i1 undef, label %loop.0.0, label %loop.1 | ||
| loop.0.0: | ||
| br i1 undef, label %loop.0.0, label %loop.0.1 | ||
| loop.0.1: | ||
| br i1 undef, label %loop.0.1, label %loop.0 | ||
| loop.1: | ||
| br i1 undef, label %loop.1, label %loop.1.bb1 | ||
| loop.1.bb1: | ||
| br i1 undef, label %loop.1, label %loop.1.bb2 | ||
| loop.1.bb2: | ||
| br i1 undef, label %end, label %loop.1.0 | ||
| loop.1.0: | ||
| br i1 undef, label %loop.1.0, label %loop.1 | ||
| end: | ||
| ret void | ||
| } | ||
|
|
||
| define i32 @f2() { | ||
| entry: | ||
| ret i32 0 | ||
| } | ||
|
|
||
| define i32 @f3() { | ||
| entry: | ||
| %temp = call i32 @g() | ||
| %icmp = icmp ugt i32 %temp, 2 | ||
| br i1 %icmp, label %bb.true, label %bb.false | ||
| bb.true: | ||
| %temp2 = call i32 @f2() | ||
| ret i32 %temp2 | ||
| bb.false: | ||
| ret i32 0 | ||
| } |