diff --git a/llvm/include/llvm/Transforms/IPO/IROutliner.h b/llvm/include/llvm/Transforms/IPO/IROutliner.h --- a/llvm/include/llvm/Transforms/IPO/IROutliner.h +++ b/llvm/include/llvm/Transforms/IPO/IROutliner.h @@ -162,8 +162,9 @@ class IROutliner { public: IROutliner(function_ref GTTI, - function_ref GIRSI) - : getTTI(GTTI), getIRSI(GIRSI) {} + function_ref GIRSI, + function_ref GORE) + : getTTI(GTTI), getIRSI(GIRSI), getORE(GORE) {} bool run(Module &M); private: @@ -277,6 +278,9 @@ /// IRSimilarityIdentifier lambda to retrieve IRSimilarityIdentifier. function_ref getIRSI; + /// The optimization remark emitter for the pass. + function_ref getORE; + /// The memory allocator used to allocate the CodeExtractors. SpecificBumpPtrAllocator ExtractorAllocator; diff --git a/llvm/lib/Transforms/IPO/IROutliner.cpp b/llvm/lib/Transforms/IPO/IROutliner.cpp --- a/llvm/lib/Transforms/IPO/IROutliner.cpp +++ b/llvm/lib/Transforms/IPO/IROutliner.cpp @@ -13,6 +13,7 @@ #include "llvm/Transforms/IPO/IROutliner.h" #include "llvm/Analysis/IRSimilarityIdentifier.h" +#include "llvm/Analysis/OptimizationRemarkEmitter.h" #include "llvm/Analysis/TargetTransformInfo.h" #include "llvm/IR/Attributes.h" #include "llvm/IR/PassManager.h" @@ -216,6 +217,7 @@ DenseMap::iterator GVNToConstantIt; bool Inserted; + // If we have a constant, try to make a new entry in the GVNToConstant. std::tie(GVNToConstantIt, Inserted) = GVNToConstant.insert(std::make_pair(GVN, CST)); @@ -1549,6 +1551,29 @@ if (CurrentGroup.Cost >= CurrentGroup.Benefit && CostModel) { for (OutlinableRegion *OS : CurrentGroup.Regions) OS->reattachCandidate(); + OptimizationRemarkEmitter &ORE = getORE( + *CurrentGroup.Regions[0]->Candidate->getFunction()); + ORE.emit([&]() { + IRSimilarityCandidate *C = CurrentGroup.Regions[0]->Candidate; + OptimizationRemarkMissed R(DEBUG_TYPE, "WouldNotDecreaseSize", + C->frontInstruction()); + R << "did not outline " + << ore::NV(std::to_string(CurrentGroup.Regions.size())) + << " regions due to estimated increase of " + << ore::NV("InstructionIncrease", + std::to_string(static_cast(CurrentGroup.Cost - + CurrentGroup.Benefit))) + << " instructions at locations "; + interleave( + CurrentGroup.Regions.begin(), CurrentGroup.Regions.end(), + [&R](OutlinableRegion *Region) { + R << ore::NV( + "DebugLoc", + Region->Candidate->frontInstruction()->getDebugLoc()); + }, + [&R]() { R << " "; }); + return R; + }); continue; } @@ -1569,11 +1594,35 @@ } } + LLVM_DEBUG(dbgs() << "Outlined " << OutlinedRegions.size() + << " with benefit " << CurrentGroup.Benefit + << " and cost " << CurrentGroup.Cost << "\n"); + CurrentGroup.Regions = std::move(OutlinedRegions); if (CurrentGroup.Regions.empty()) continue; + OptimizationRemarkEmitter &ORE = + getORE(*CurrentGroup.Regions[0]->Call->getFunction()); + ORE.emit([&]() { + IRSimilarityCandidate *C = CurrentGroup.Regions[0]->Candidate; + OptimizationRemark R(DEBUG_TYPE, "Outlined", C->front()->Inst); + R << "outlined " << ore::NV(std::to_string(CurrentGroup.Regions.size())) + << " regions with decrease of " + << ore::NV("Benefit", std::to_string(static_cast( + CurrentGroup.Benefit - CurrentGroup.Cost))) + << " instructions at locations "; + interleave( + CurrentGroup.Regions.begin(), CurrentGroup.Regions.end(), + [&R](OutlinableRegion *Region) { + R << ore::NV("DebugLoc", + Region->Candidate->frontInstruction()->getDebugLoc()); + }, + [&R]() { R << " "; }); + return R; + }); + deduplicateExtractedSections(M, CurrentGroup, FuncsToRemove, OutlinedFunctionNum); } @@ -1599,6 +1648,7 @@ } void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.addRequired(); AU.addRequired(); AU.addRequired(); } @@ -1610,6 +1660,12 @@ if (skipModule(M)) return false; + std::unique_ptr ORE; + auto GORE = [&ORE](Function &F) -> OptimizationRemarkEmitter & { + ORE.reset(new OptimizationRemarkEmitter(&F)); + return *ORE.get(); + }; + auto GTTI = [this](Function &F) -> TargetTransformInfo & { return this->getAnalysis().getTTI(F); }; @@ -1618,7 +1674,7 @@ return this->getAnalysis().getIRSI(); }; - return IROutliner(GTTI, GIRSI).run(M); + return IROutliner(GTTI, GIRSI, GORE).run(M); } PreservedAnalyses IROutlinerPass::run(Module &M, ModuleAnalysisManager &AM) { @@ -1634,7 +1690,14 @@ return AM.getResult(M); }; - if (IROutliner(GTTI, GIRSI).run(M)) + std::unique_ptr ORE; + std::function GORE = + [&ORE](Function &F) -> OptimizationRemarkEmitter & { + ORE.reset(new OptimizationRemarkEmitter(&F)); + return *ORE.get(); + }; + + if (IROutliner(GTTI, GIRSI, GORE).run(M)) return PreservedAnalyses::none(); return PreservedAnalyses::all(); } @@ -1643,6 +1706,7 @@ INITIALIZE_PASS_BEGIN(IROutlinerLegacyPass, "iroutliner", "IR Outliner", false, false) INITIALIZE_PASS_DEPENDENCY(IRSimilarityIdentifierWrapperPass) +INITIALIZE_PASS_DEPENDENCY(OptimizationRemarkEmitterWrapperPass) INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass) INITIALIZE_PASS_END(IROutlinerLegacyPass, "iroutliner", "IR Outliner", false, false) diff --git a/llvm/test/Transforms/IROutliner/opt-remarks.ll b/llvm/test/Transforms/IROutliner/opt-remarks.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/IROutliner/opt-remarks.ll @@ -0,0 +1,184 @@ +; RUN: opt -S -verify -iroutliner -o /dev/null \ +; RUN: -pass-remarks=iroutliner -pass-remarks-missed=iroutliner < %s \ +; RUN: 2>&1 | FileCheck -check-prefix=CHECK %s +; RUN: opt -S -verify -iroutliner -o /dev/null \ +; RUN: -pass-remarks-output=%t < %s +; RUN: cat %t | FileCheck -check-prefix=YAML %s + +; CHECK: remark: :0:0: outlined 2 regions with decrease of 31 instructions at locations +; CHECK-NEXT: remark: :0:0: did not outline 2 regions due to estimated increase of 5 instructions at locations +; CHECK-NEXT: remark: :0:0: did not outline 2 regions due to estimated increase of 9 instructions at locations +; CHECK-NEXT: remark: :0:0: did not outline 2 regions due to estimated increase of 13 instructions at locations +; CHECK-NEXT: remark: :0:0: did not outline 2 regions due to estimated increase of 17 instructions at locations +; CHECK-NEXT: remark: :0:0: did not outline 2 regions due to estimated increase of 21 instructions at locations +; CHECK-NEXT: remark: :0:0: did not outline 2 regions due to estimated increase of 7 instructions at locations + +; YAML: --- !Passed +; YAML-NEXT: Pass: iroutliner +; YAML-NEXT: Name: Outlined +; YAML-NEXT: Function: function3.outlined +; YAML-NEXT: Args: +; YAML-NEXT: - String: 'outlined ' +; YAML-NEXT: - String: '2' +; YAML-NEXT: - String: ' regions with decrease of ' +; YAML-NEXT: - Benefit: '31' +; YAML-NEXT: - String: ' instructions at locations ' +; YAML-NEXT: - DebugLoc: '' +; YAML-NEXT: - String: ' ' +; YAML-NEXT: - DebugLoc: '' +; YAML-NEXT: ... +; YAML-NEXT: --- !Missed +; YAML-NEXT: Pass: iroutliner +; YAML-NEXT: Name: WouldNotDecreaseSize +; YAML-NEXT: Function: function1 +; YAML-NEXT: Args: +; YAML-NEXT: - String: 'did not outline ' +; YAML-NEXT: - String: '2' +; YAML-NEXT: - String: ' regions due to estimated increase of ' +; YAML-NEXT: - InstructionIncrease: '5' +; YAML-NEXT: - String: ' instructions at locations ' +; YAML-NEXT: - DebugLoc: '' +; YAML-NEXT: - String: ' ' +; YAML-NEXT: - DebugLoc: '' +; YAML-NEXT: ... +; YAML-NEXT: --- !Missed +; YAML-NEXT: Pass: iroutliner +; YAML-NEXT: Name: WouldNotDecreaseSize +; YAML-NEXT: Function: function1 +; YAML-NEXT: Args: +; YAML-NEXT: - String: 'did not outline ' +; YAML-NEXT: - String: '2' +; YAML-NEXT: - String: ' regions due to estimated increase of ' +; YAML-NEXT: - InstructionIncrease: '9' +; YAML-NEXT: - String: ' instructions at locations ' +; YAML-NEXT: - DebugLoc: '' +; YAML-NEXT: - String: ' ' +; YAML-NEXT: - DebugLoc: '' +; YAML-NEXT: ... +; YAML-NEXT: --- !Missed +; YAML-NEXT: Pass: iroutliner +; YAML-NEXT: Name: WouldNotDecreaseSize +; YAML-NEXT: Function: function1 +; YAML-NEXT: Args: +; YAML-NEXT: - String: 'did not outline ' +; YAML-NEXT: - String: '2' +; YAML-NEXT: - String: ' regions due to estimated increase of ' +; YAML-NEXT: - InstructionIncrease: '13' +; YAML-NEXT: - String: ' instructions at locations ' +; YAML-NEXT: - DebugLoc: '' +; YAML-NEXT: - String: ' ' +; YAML-NEXT: - DebugLoc: '' +; YAML-NEXT: ... +; YAML-NEXT: --- !Missed +; YAML-NEXT: Pass: iroutliner +; YAML-NEXT: Name: WouldNotDecreaseSize +; YAML-NEXT: Function: function1 +; YAML-NEXT: Args: +; YAML-NEXT: - String: 'did not outline ' +; YAML-NEXT: - String: '2' +; YAML-NEXT: - String: ' regions due to estimated increase of ' +; YAML-NEXT: - InstructionIncrease: '17' +; YAML-NEXT: - String: ' instructions at locations ' +; YAML-NEXT: - DebugLoc: '' +; YAML-NEXT: - String: ' ' +; YAML-NEXT: - DebugLoc: '' +; YAML-NEXT: ... +; YAML-NEXT: --- !Missed +; YAML-NEXT: Pass: iroutliner +; YAML-NEXT: Name: WouldNotDecreaseSize +; YAML-NEXT: Function: function1 +; YAML-NEXT: Args: +; YAML-NEXT: - String: 'did not outline ' +; YAML-NEXT: - String: '2' +; YAML-NEXT: - String: ' regions due to estimated increase of ' +; YAML-NEXT: - InstructionIncrease: '21' +; YAML-NEXT: - String: ' instructions at locations ' +; YAML-NEXT: - DebugLoc: '' +; YAML-NEXT: - String: ' ' +; YAML-NEXT: - DebugLoc: '' +; YAML-NEXT: ... +; YAML-NEXT: --- !Missed +; YAML-NEXT: Pass: iroutliner +; YAML-NEXT: Name: WouldNotDecreaseSize +; YAML-NEXT: Function: function1 +; YAML-NEXT: Args: +; YAML-NEXT: - String: 'did not outline ' +; YAML-NEXT: - String: '2' +; YAML-NEXT: - String: ' regions due to estimated increase of ' +; YAML-NEXT: - InstructionIncrease: '7' +; YAML-NEXT: - String: ' instructions at locations ' +; YAML-NEXT: - DebugLoc: '' +; YAML-NEXT: - String: ' ' +; YAML-NEXT: - DebugLoc: '' +; YAML-NEXT: ... + +define void @function1() #0 { +entry: + %a = alloca i32, align 4 + %b = alloca i32, align 4 + %output = alloca i32, align 4 + %result = alloca i32, align 4 + store i32 2, i32* %a, align 4 + store i32 3, i32* %b, align 4 + %0 = load i32, i32* %a, align 4 + %1 = load i32, i32* %b, align 4 + %add = add i32 %0, %1 + store i32 %add, i32* %output, align 4 + %2 = load i32, i32* %output, align 4 + %3 = load i32, i32* %output, align 4 + %mul = mul i32 %2, %add + store i32 %mul, i32* %result, align 4 + ret void +} + +define void @function2() #0 { +entry: + %a = alloca i32, align 4 + %b = alloca i32, align 4 + %output = alloca i32, align 4 + %result = alloca i32, align 4 + store i32 2, i32* %a, align 4 + store i32 3, i32* %b, align 4 + %0 = load i32, i32* %a, align 4 + %1 = load i32, i32* %b, align 4 + %add = add i32 %0, %1 + store i32 %add, i32* %output, align 4 + %2 = load i32, i32* %output, align 4 + %mul = mul i32 %2, %add + store i32 %mul, i32* %result, align 4 + ret void +} + +define void @function3() #0 { +entry: + %a = alloca i32, align 4 + %b = alloca i32, align 4 + %0 = load i32, i32* %a, align 4 + %1 = load i32, i32* %b, align 4 + %add = add i32 %0, %1 + %mul = mul i32 %0, %1 + %sub = sub i32 %0, %1 + %div = sdiv i32 %0, %1 + %add2 = add i32 %0, %1 + %mul2 = mul i32 %0, %1 + %sub2 = sub i32 %0, %1 + %div2 = sdiv i32 %0, %1 + ret void +} + +define void @function4() #0 { +entry: + %a = alloca i32, align 4 + %b = alloca i32, align 4 + %0 = load i32, i32* %a, align 4 + %1 = load i32, i32* %b, align 4 + %add = add i32 %0, %1 + %mul = mul i32 %0, %1 + %sub = sub i32 %0, %1 + %div = sdiv i32 %0, %1 + %add2 = add i32 %0, %1 + %mul2 = mul i32 %0, %1 + %sub2 = sub i32 %0, %1 + %div2 = sdiv i32 %0, %1 + ret void +}