diff --git a/llvm/include/llvm/Analysis/MustExecute.h b/llvm/include/llvm/Analysis/MustExecute.h --- a/llvm/include/llvm/Analysis/MustExecute.h +++ b/llvm/include/llvm/Analysis/MustExecute.h @@ -27,6 +27,8 @@ #include "llvm/ADT/DenseSet.h" #include "llvm/Analysis/EHPersonalities.h" #include "llvm/Analysis/InstructionPrecedenceTracking.h" +#include "llvm/IR/PassManager.h" +#include "llvm/Support/raw_ostream.h" namespace llvm { @@ -541,6 +543,23 @@ MustBeExecutedIterator EndIterator; }; +class MustExecutePrinterPass : public PassInfoMixin { + raw_ostream &OS; + +public: + MustExecutePrinterPass(raw_ostream &OS) : OS(OS) {} + PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); +}; + +class MustBeExecutedContextPrinterPass + : public PassInfoMixin { + raw_ostream &OS; + +public: + MustBeExecutedContextPrinterPass(raw_ostream &OS) : OS(OS) {} + PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM); +}; + } // namespace llvm #endif diff --git a/llvm/lib/Analysis/MustExecute.cpp b/llvm/lib/Analysis/MustExecute.cpp --- a/llvm/lib/Analysis/MustExecute.cpp +++ b/llvm/lib/Analysis/MustExecute.cpp @@ -16,9 +16,11 @@ #include "llvm/Analysis/ValueTracking.h" #include "llvm/IR/AssemblyAnnotationWriter.h" #include "llvm/IR/DataLayout.h" +#include "llvm/IR/Dominators.h" #include "llvm/IR/InstIterator.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" +#include "llvm/IR/PassManager.h" #include "llvm/InitializePasses.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FormattedStream.h" @@ -300,30 +302,31 @@ } namespace { - struct MustExecutePrinter : public FunctionPass { +struct MustExecutePrinter : public FunctionPass { - static char ID; // Pass identification, replacement for typeid - MustExecutePrinter() : FunctionPass(ID) { - initializeMustExecutePrinterPass(*PassRegistry::getPassRegistry()); - } - void getAnalysisUsage(AnalysisUsage &AU) const override { - AU.setPreservesAll(); - AU.addRequired(); - AU.addRequired(); - } - bool runOnFunction(Function &F) override; - }; - struct MustBeExecutedContextPrinter : public ModulePass { - static char ID; + static char ID; // Pass identification, replacement for typeid + MustExecutePrinter() : FunctionPass(ID) { + initializeMustExecutePrinterPass(*PassRegistry::getPassRegistry()); + } + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.setPreservesAll(); + AU.addRequired(); + AU.addRequired(); + } + bool runOnFunction(Function &F) override; +}; +struct MustBeExecutedContextPrinter : public ModulePass { + static char ID; - MustBeExecutedContextPrinter() : ModulePass(ID) { - initializeMustBeExecutedContextPrinterPass(*PassRegistry::getPassRegistry()); - } - void getAnalysisUsage(AnalysisUsage &AU) const override { - AU.setPreservesAll(); - } - bool runOnModule(Module &M) override; - }; + MustBeExecutedContextPrinter() : ModulePass(ID) { + initializeMustBeExecutedContextPrinterPass( + *PassRegistry::getPassRegistry()); + } + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.setPreservesAll(); + } + bool runOnModule(Module &M) override; +}; } char MustExecutePrinter::ID = 0; @@ -339,15 +342,16 @@ } char MustBeExecutedContextPrinter::ID = 0; -INITIALIZE_PASS_BEGIN( - MustBeExecutedContextPrinter, "print-must-be-executed-contexts", - "print the must-be-executed-contexed for all instructions", false, true) +INITIALIZE_PASS_BEGIN(MustBeExecutedContextPrinter, + "print-must-be-executed-contexts", + "print the must-be-executed-context for all instructions", + false, true) INITIALIZE_PASS_DEPENDENCY(PostDominatorTreeWrapperPass) INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass) INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass) INITIALIZE_PASS_END(MustBeExecutedContextPrinter, "print-must-be-executed-contexts", - "print the must-be-executed-contexed for all instructions", + "print the must-be-executed-context for all instructions", false, true) ModulePass *llvm::createMustBeExecutedContextPrinter() { @@ -835,3 +839,42 @@ Tail = nullptr; return nullptr; } + +PreservedAnalyses MustExecutePrinterPass::run(Function &F, + FunctionAnalysisManager &AM) { + auto &LI = AM.getResult(F); + auto &DT = AM.getResult(F); + + MustExecuteAnnotatedWriter Writer(F, DT, LI); + F.print(OS, &Writer); + return PreservedAnalyses::all(); +} + +PreservedAnalyses +MustBeExecutedContextPrinterPass::run(Module &M, ModuleAnalysisManager &AM) { + FunctionAnalysisManager &FAM = + AM.getResult(M).getManager(); + GetterTy LIGetter = [&](const Function &F) { + return &FAM.getResult(const_cast(F)); + }; + GetterTy DTGetter = [&](const Function &F) { + return &FAM.getResult(const_cast(F)); + }; + GetterTy PDTGetter = [&](const Function &F) { + return &FAM.getResult(const_cast(F)); + }; + + MustBeExecutedContextExplorer Explorer( + /* ExploreInterBlock */ true, + /* ExploreCFGForward */ true, + /* ExploreCFGBackward */ true, LIGetter, DTGetter, PDTGetter); + + for (Function &F : M) { + for (Instruction &I : instructions(F)) { + OS << "-- Explore context of: " << I << "\n"; + for (const Instruction *CI : Explorer.range(&I)) + OS << " [F: " << CI->getFunction()->getName() << "] " << *CI << "\n"; + } + } + return PreservedAnalyses::all(); +} diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp --- a/llvm/lib/Passes/PassBuilder.cpp +++ b/llvm/lib/Passes/PassBuilder.cpp @@ -51,6 +51,7 @@ #include "llvm/Analysis/MemorySSA.h" #include "llvm/Analysis/ModuleDebugInfoPrinter.h" #include "llvm/Analysis/ModuleSummaryAnalysis.h" +#include "llvm/Analysis/MustExecute.h" #include "llvm/Analysis/ObjCARCAliasAnalysis.h" #include "llvm/Analysis/OptimizationRemarkEmitter.h" #include "llvm/Analysis/PhiValues.h" diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def --- a/llvm/lib/Passes/PassRegistry.def +++ b/llvm/lib/Passes/PassRegistry.def @@ -86,6 +86,7 @@ MODULE_PASS("print", PrintModulePass(dbgs())) MODULE_PASS("print-lcg", LazyCallGraphPrinterPass(dbgs())) MODULE_PASS("print-lcg-dot", LazyCallGraphDOTPrinterPass(dbgs())) +MODULE_PASS("print-must-be-executed-contexts", MustBeExecutedContextPrinterPass(dbgs())) MODULE_PASS("print-stack-safety", StackSafetyGlobalPrinterPass(dbgs())) MODULE_PASS("print", ModuleDebugInfoPrinterPass(dbgs())) MODULE_PASS("rewrite-statepoints-for-gc", RewriteStatepointsForGC()) @@ -276,9 +277,10 @@ FUNCTION_PASS("print", RegionInfoPrinterPass(dbgs())) FUNCTION_PASS("print", ScalarEvolutionPrinterPass(dbgs())) FUNCTION_PASS("print", StackSafetyPrinterPass(dbgs())) -// TODO: rename to print after NPM switch +// TODO: rename to print after NPM switch FUNCTION_PASS("print-alias-sets", AliasSetsPrinterPass(dbgs())) FUNCTION_PASS("print-predicateinfo", PredicateInfoPrinterPass(dbgs())) +FUNCTION_PASS("print-mustexecute", MustExecutePrinterPass(dbgs())) FUNCTION_PASS("reassociate", ReassociatePass()) FUNCTION_PASS("scalarizer", ScalarizerPass()) FUNCTION_PASS("sccp", SCCPPass()) diff --git a/llvm/test/Analysis/MustExecute/const-cond.ll b/llvm/test/Analysis/MustExecute/const-cond.ll --- a/llvm/test/Analysis/MustExecute/const-cond.ll +++ b/llvm/test/Analysis/MustExecute/const-cond.ll @@ -1,46 +1,47 @@ -; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt -disable-output -print-mustexecute %s 2>&1 | FileCheck %s - -; In general the CFG below is easily simplified but this is useful for -; pass ordering issue elimination. -define i1 @const_cond(i32 %high) { -; CHECK-LABEL: @const_cond( -; CHECK-NEXT: entry: -; CHECK-NEXT: br label [[LOOP:%.*]] -; CHECK: loop: -; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ] ; (mustexec in: loop) -; CHECK-NEXT: br i1 true, label [[NEXT:%.*]], label [[NEVER1:%.*]] ; (mustexec in: loop) -; CHECK: next: -; CHECK-NEXT: br i1 false, label [[NEVER2:%.*]], label [[BACKEDGE]] ; (mustexec in: loop) -; CHECK: backedge: -; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1 ; (mustexec in: loop) -; CHECK-NEXT: [[EXIT_TEST:%.*]] = icmp slt i32 [[IV]], [[HIGH:%.*]] ; (mustexec in: loop) -; CHECK-NEXT: br i1 [[EXIT_TEST]], label [[LOOP]], label [[EXIT:%.*]] ; (mustexec in: loop) -; CHECK: exit: -; CHECK-NEXT: ret i1 false -; CHECK: never1: -; CHECK-NEXT: unreachable -; CHECK: never2: -; CHECK-NEXT: unreachable -; -entry: - br label %loop - -loop: - %iv = phi i32 [0, %entry], [%iv.next, %backedge] - br i1 true, label %next, label %never1 -next: - br i1 false, label %never2, label %backedge -backedge: - %iv.next = add nsw nuw i32 %iv, 1 - %exit.test = icmp slt i32 %iv, %high - br i1 %exit.test, label %loop, label %exit - -exit: - ret i1 false -never1: - unreachable -never2: - unreachable -} - +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt -disable-output -print-mustexecute %s 2>&1 | FileCheck %s +; RUN: opt -disable-output -passes=print-mustexecute %s 2>&1 | FileCheck %s + +; In general the CFG below is easily simplified but this is useful for +; pass ordering issue elimination. +define i1 @const_cond(i32 %high) { +; CHECK-LABEL: @const_cond( +; CHECK-NEXT: entry: +; CHECK-NEXT: br label [[LOOP:%.*]] +; CHECK: loop: +; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ] ; (mustexec in: loop) +; CHECK-NEXT: br i1 true, label [[NEXT:%.*]], label [[NEVER1:%.*]] ; (mustexec in: loop) +; CHECK: next: +; CHECK-NEXT: br i1 false, label [[NEVER2:%.*]], label [[BACKEDGE]] ; (mustexec in: loop) +; CHECK: backedge: +; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1 ; (mustexec in: loop) +; CHECK-NEXT: [[EXIT_TEST:%.*]] = icmp slt i32 [[IV]], [[HIGH:%.*]] ; (mustexec in: loop) +; CHECK-NEXT: br i1 [[EXIT_TEST]], label [[LOOP]], label [[EXIT:%.*]] ; (mustexec in: loop) +; CHECK: exit: +; CHECK-NEXT: ret i1 false +; CHECK: never1: +; CHECK-NEXT: unreachable +; CHECK: never2: +; CHECK-NEXT: unreachable +; +entry: + br label %loop + +loop: + %iv = phi i32 [0, %entry], [%iv.next, %backedge] + br i1 true, label %next, label %never1 +next: + br i1 false, label %never2, label %backedge +backedge: + %iv.next = add nsw nuw i32 %iv, 1 + %exit.test = icmp slt i32 %iv, %high + br i1 %exit.test, label %loop, label %exit + +exit: + ret i1 false +never1: + unreachable +never2: + unreachable +} + diff --git a/llvm/test/Analysis/MustExecute/must_be_executed_context.ll b/llvm/test/Analysis/MustExecute/must_be_executed_context.ll --- a/llvm/test/Analysis/MustExecute/must_be_executed_context.ll +++ b/llvm/test/Analysis/MustExecute/must_be_executed_context.ll @@ -1,6 +1,7 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt < %s -print-mustexecute -analyze 2>&1 | FileCheck %s --check-prefix=ME -; RUN: opt < %s -print-must-be-executed-contexts -analyze 2>&1 | FileCheck %s --check-prefix=MBEC +; RUN: opt < %s -print-mustexecute -disable-output 2>&1 | FileCheck %s --check-prefix=ME +; RUN: opt < %s -print-must-be-executed-contexts -disable-output 2>&1 | FileCheck %s --check-prefix=MBEC +; RUN: opt < %s -passes=print-must-be-executed-contexts -disable-output 2>&1 | FileCheck %s --check-prefix=MBEC ; ; void simple_conditional(int c) { ; A();