diff --git a/llvm/include/llvm/Transforms/IPO/Attributor.h b/llvm/include/llvm/Transforms/IPO/Attributor.h --- a/llvm/include/llvm/Transforms/IPO/Attributor.h +++ b/llvm/include/llvm/Transforms/IPO/Attributor.h @@ -109,6 +109,7 @@ #include "llvm/Analysis/LazyCallGraph.h" #include "llvm/Analysis/LoopInfo.h" #include "llvm/Analysis/MustExecute.h" +#include "llvm/Analysis/OptimizationRemarkEmitter.h" #include "llvm/Analysis/PostDominators.h" #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/IR/AbstractCallSite.h" @@ -1066,6 +1067,10 @@ /// NOTE: The mechanics of adding a new "concrete" abstract attribute are /// described in the file comment. struct Attributor { + + using OptimizationRemarkGetter = + function_ref; + /// Constructor /// /// \param Functions The set of functions we are deriving attributes for. @@ -1081,7 +1086,29 @@ bool RewriteSignatures = true) : Allocator(InfoCache.Allocator), Functions(Functions), InfoCache(InfoCache), CGUpdater(CGUpdater), Allowed(Allowed), - DeleteFns(DeleteFns), RewriteSignatures(RewriteSignatures) {} + DeleteFns(DeleteFns), RewriteSignatures(RewriteSignatures), + OREGetter(None), PassName("") {} + + /// Constructor + /// + /// \param Functions The set of functions we are deriving attributes for. + /// \param InfoCache Cache to hold various information accessible for + /// the abstract attributes. + /// \param CGUpdater Helper to update an underlying call graph. + /// \param Allowed If not null, a set limiting the attribute opportunities. + /// \param DeleteFns Whether to delete functions + /// \param OREGetter A callback function that returns an ORE object from a + /// Function pointer. + /// \param PassName The name of the pass emitting remarks. + Attributor(SetVector &Functions, InformationCache &InfoCache, + CallGraphUpdater &CGUpdater, DenseSet *Allowed, + bool DeleteFns, bool RewriteSignatures, + OptimizationRemarkGetter OREGetter, const char *PassName) + : Allocator(InfoCache.Allocator), Functions(Functions), + InfoCache(InfoCache), CGUpdater(CGUpdater), Allowed(Allowed), + DeleteFns(DeleteFns), RewriteSignatures(RewriteSignatures), + OREGetter(Optional(OREGetter)), + PassName(PassName) {} ~Attributor(); @@ -1442,6 +1469,41 @@ const AbstractAttribute &QueryingAA, const Value &V, DepClassTy LivenessDepClass = DepClassTy::OPTIONAL); + /// Emit a remark generically. + /// + /// This template function can be used to generically emit a remark. The + /// RemarkKind should be one of the following: + /// - OptimizationRemark to indicate a successful optimization attempt + /// - OptimizationRemarkMissed to report a failed optimization attempt + /// - OptimizationRemarkAnalysis to provide additional information about an + /// optimization attempt + /// + /// The remark is built using a callback function \p RemarkCB that takes a + /// RemarkKind as input and returns a RemarkKind. + template + void emitRemark(Instruction *I, StringRef RemarkName, + RemarkCallBack &&RemarkCB) const { + if (!OREGetter) + return; + + Function *F = I->getFunction(); + auto &ORE = OREGetter.getValue()(F); + + ORE.emit([&]() { return RemarkCB(RemarkKind(PassName, RemarkName, I)); }); + } + + /// Emit a remark on a function. + template + void emitRemark(Function *F, StringRef RemarkName, + RemarkCallBack &&RemarkCB) const { + if (!OREGetter) + return; + + auto &ORE = OREGetter.getValue()(F); + + ORE.emit([&]() { return RemarkCB(RemarkKind(PassName, RemarkName, F)); }); + } + /// Helper struct used in the communication between an abstract attribute (AA) /// that wants to change the signature of a function and the Attributor which /// applies the changes. The struct is partially initialized with the @@ -1778,6 +1840,12 @@ SmallDenseSet ToBeDeletedInsts; ///} + /// Callback to get an OptimizationRemarkEmitter from a Function *. + Optional OREGetter; + + /// The name of the pass to emit remarks for. + const char *PassName = ""; + friend AADepGraph; }; diff --git a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp --- a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp +++ b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp @@ -5048,6 +5048,11 @@ LLVM_DEBUG(dbgs() << "H2S: Removing malloc call: " << *MallocCall << "\n"); + auto Remark = [&](OptimizationRemark OR) { + return OR << "Moving memory allocation from the heap to the stack."; + }; + A.emitRemark(MallocCall, "HeapToStack", Remark); + Align Alignment; Value *Size; if (isCallocLikeFn(MallocCall, TLI)) { diff --git a/llvm/lib/Transforms/IPO/OpenMPOpt.cpp b/llvm/lib/Transforms/IPO/OpenMPOpt.cpp --- a/llvm/lib/Transforms/IPO/OpenMPOpt.cpp +++ b/llvm/lib/Transforms/IPO/OpenMPOpt.cpp @@ -2597,7 +2597,8 @@ OMPInformationCache InfoCache(M, AG, Allocator, /*CGSCC*/ Functions, OMPInModule.getKernels()); - Attributor A(Functions, InfoCache, CGUpdater, nullptr, true, false); + Attributor A(Functions, InfoCache, CGUpdater, nullptr, true, false, OREGetter, + DEBUG_TYPE); OpenMPOpt OMPOpt(SCC, CGUpdater, OREGetter, InfoCache, A); bool Changed = OMPOpt.run(true); @@ -2652,7 +2653,8 @@ OMPInformationCache InfoCache(*(Functions.back()->getParent()), AG, Allocator, /*CGSCC*/ Functions, OMPInModule.getKernels()); - Attributor A(Functions, InfoCache, CGUpdater, nullptr, false); + Attributor A(Functions, InfoCache, CGUpdater, nullptr, false, true, OREGetter, + DEBUG_TYPE); OpenMPOpt OMPOpt(SCC, CGUpdater, OREGetter, InfoCache, A); bool Changed = OMPOpt.run(false); @@ -2728,7 +2730,8 @@ *(Functions.back()->getParent()), AG, Allocator, /*CGSCC*/ Functions, OMPInModule.getKernels()); - Attributor A(Functions, InfoCache, CGUpdater, nullptr, false); + Attributor A(Functions, InfoCache, CGUpdater, nullptr, false, true, + OREGetter, DEBUG_TYPE); OpenMPOpt OMPOpt(SCC, CGUpdater, OREGetter, InfoCache, A); return OMPOpt.run(false); diff --git a/llvm/test/Transforms/OpenMP/remove_globalization_remarks.ll b/llvm/test/Transforms/OpenMP/remove_globalization_remarks.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/OpenMP/remove_globalization_remarks.ll @@ -0,0 +1,44 @@ +; RUN: opt -passes=openmp-opt -pass-remarks=openmp-opt -disable-output < %s 2>&1 | FileCheck %s +target datalayout = "e-i64:64-i128:128-v16:16-v32:32-n16:32:64" +target triple = "nvptx64" + +@S = external local_unnamed_addr global i8* + +; CHECK: remark: remove_globalization.c:2:2: Moving memory allocation from the heap to the stack. + +define void @kernel() { +entry: + call void @foo() + ret void +} + +define void @foo() { +entry: + %0 = call i8* @__kmpc_alloc_shared(i64 4), !dbg !9 + call void @use(i8* %0) + call void @__kmpc_free_shared(i8* %0) + ret void +} + +define void @use(i8* %x) { +entry: + ret void +} + +declare i8* @__kmpc_alloc_shared(i64) + +declare void @__kmpc_free_shared(i8*) + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4} +!nvvm.annotations = !{!5} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 13.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "remove_globalization.c", directory: "/tmp/remove_globalization.c") +!2 = !{} +!3 = !{i32 2, !"Debug Info Version", i32 3} +!4 = !{i32 1, !"wchar_size", i32 4} +!5 = !{void ()* @kernel, !"kernel", i32 1} +!7 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 1, type: !8, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !2) +!8 = !DISubroutineType(types: !2) +!9 = !DILocation(line: 2, column: 2, scope: !7)