xref: /llvm-project/llvm/lib/Analysis/KernelInfo.cpp (revision 57f17319796a1876ba5a82d9bdc0f6f63ab12945)
118f8106fSJoel E. Denny //===- KernelInfo.cpp - Kernel Analysis -----------------------------------===//
218f8106fSJoel E. Denny //
318f8106fSJoel E. Denny // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
418f8106fSJoel E. Denny // See https://llvm.org/LICENSE.txt for license information.
518f8106fSJoel E. Denny // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
618f8106fSJoel E. Denny //
718f8106fSJoel E. Denny //===----------------------------------------------------------------------===//
818f8106fSJoel E. Denny //
918f8106fSJoel E. Denny // This file defines the KernelInfoPrinter class used to emit remarks about
1018f8106fSJoel E. Denny // function properties from a GPU kernel.
1118f8106fSJoel E. Denny //
1218f8106fSJoel E. Denny //===----------------------------------------------------------------------===//
1318f8106fSJoel E. Denny 
1418f8106fSJoel E. Denny #include "llvm/Analysis/KernelInfo.h"
1518f8106fSJoel E. Denny #include "llvm/ADT/SmallString.h"
1618f8106fSJoel E. Denny #include "llvm/ADT/StringExtras.h"
1718f8106fSJoel E. Denny #include "llvm/Analysis/OptimizationRemarkEmitter.h"
18*953354c7SBenjamin Kramer #include "llvm/Analysis/TargetTransformInfo.h"
1918f8106fSJoel E. Denny #include "llvm/IR/DebugInfo.h"
2018f8106fSJoel E. Denny #include "llvm/IR/Dominators.h"
2118f8106fSJoel E. Denny #include "llvm/IR/Instructions.h"
2218f8106fSJoel E. Denny #include "llvm/IR/Metadata.h"
2318f8106fSJoel E. Denny #include "llvm/IR/Module.h"
2418f8106fSJoel E. Denny #include "llvm/IR/PassManager.h"
2518f8106fSJoel E. Denny 
2618f8106fSJoel E. Denny using namespace llvm;
2718f8106fSJoel E. Denny 
2818f8106fSJoel E. Denny #define DEBUG_TYPE "kernel-info"
2918f8106fSJoel E. Denny 
3018f8106fSJoel E. Denny namespace {
3118f8106fSJoel E. Denny 
3218f8106fSJoel E. Denny /// Data structure holding function info for kernels.
3318f8106fSJoel E. Denny class KernelInfo {
3418f8106fSJoel E. Denny   void updateForBB(const BasicBlock &BB, OptimizationRemarkEmitter &ORE);
3518f8106fSJoel E. Denny 
3618f8106fSJoel E. Denny public:
3718f8106fSJoel E. Denny   static void emitKernelInfo(Function &F, FunctionAnalysisManager &FAM,
3818f8106fSJoel E. Denny                              TargetMachine *TM);
3918f8106fSJoel E. Denny 
4018f8106fSJoel E. Denny   /// Whether the function has external linkage and is not a kernel function.
4118f8106fSJoel E. Denny   bool ExternalNotKernel = false;
4218f8106fSJoel E. Denny 
4318f8106fSJoel E. Denny   /// Launch bounds.
4418f8106fSJoel E. Denny   SmallVector<std::pair<StringRef, int64_t>> LaunchBounds;
4518f8106fSJoel E. Denny 
4618f8106fSJoel E. Denny   /// The number of alloca instructions inside the function, the number of those
4718f8106fSJoel E. Denny   /// with allocation sizes that cannot be determined at compile time, and the
4818f8106fSJoel E. Denny   /// sum of the sizes that can be.
4918f8106fSJoel E. Denny   ///
5018f8106fSJoel E. Denny   /// With the current implementation for at least some GPU archs,
5118f8106fSJoel E. Denny   /// AllocasDyn > 0 might not be possible, but we report AllocasDyn anyway in
5218f8106fSJoel E. Denny   /// case the implementation changes.
5318f8106fSJoel E. Denny   int64_t Allocas = 0;
5418f8106fSJoel E. Denny   int64_t AllocasDyn = 0;
5518f8106fSJoel E. Denny   int64_t AllocasStaticSizeSum = 0;
5618f8106fSJoel E. Denny 
5718f8106fSJoel E. Denny   /// Number of direct/indirect calls (anything derived from CallBase).
5818f8106fSJoel E. Denny   int64_t DirectCalls = 0;
5918f8106fSJoel E. Denny   int64_t IndirectCalls = 0;
6018f8106fSJoel E. Denny 
6118f8106fSJoel E. Denny   /// Number of direct calls made from this function to other functions
6218f8106fSJoel E. Denny   /// defined in this module.
6318f8106fSJoel E. Denny   int64_t DirectCallsToDefinedFunctions = 0;
6418f8106fSJoel E. Denny 
6518f8106fSJoel E. Denny   /// Number of direct calls to inline assembly.
6618f8106fSJoel E. Denny   int64_t InlineAssemblyCalls = 0;
6718f8106fSJoel E. Denny 
6818f8106fSJoel E. Denny   /// Number of calls of type InvokeInst.
6918f8106fSJoel E. Denny   int64_t Invokes = 0;
7018f8106fSJoel E. Denny 
7118f8106fSJoel E. Denny   /// Target-specific flat address space.
7218f8106fSJoel E. Denny   unsigned FlatAddrspace;
7318f8106fSJoel E. Denny 
7418f8106fSJoel E. Denny   /// Number of flat address space memory accesses (via load, store, etc.).
7518f8106fSJoel E. Denny   int64_t FlatAddrspaceAccesses = 0;
7618f8106fSJoel E. Denny };
7718f8106fSJoel E. Denny 
7818f8106fSJoel E. Denny } // end anonymous namespace
7918f8106fSJoel E. Denny 
8018f8106fSJoel E. Denny static void identifyCallee(OptimizationRemark &R, const Module *M,
8118f8106fSJoel E. Denny                            const Value *V, StringRef Kind = "") {
8218f8106fSJoel E. Denny   SmallString<100> Name; // might be function name or asm expression
8318f8106fSJoel E. Denny   if (const Function *F = dyn_cast<Function>(V)) {
8418f8106fSJoel E. Denny     if (auto *SubProgram = F->getSubprogram()) {
8518f8106fSJoel E. Denny       if (SubProgram->isArtificial())
8618f8106fSJoel E. Denny         R << "artificial ";
8718f8106fSJoel E. Denny       Name = SubProgram->getName();
8818f8106fSJoel E. Denny     }
8918f8106fSJoel E. Denny   }
9018f8106fSJoel E. Denny   if (Name.empty()) {
9118f8106fSJoel E. Denny     raw_svector_ostream OS(Name);
9218f8106fSJoel E. Denny     V->printAsOperand(OS, /*PrintType=*/false, M);
9318f8106fSJoel E. Denny   }
9418f8106fSJoel E. Denny   if (!Kind.empty())
9518f8106fSJoel E. Denny     R << Kind << " ";
9618f8106fSJoel E. Denny   R << "'" << Name << "'";
9718f8106fSJoel E. Denny }
9818f8106fSJoel E. Denny 
9918f8106fSJoel E. Denny static void identifyFunction(OptimizationRemark &R, const Function &F) {
10018f8106fSJoel E. Denny   identifyCallee(R, F.getParent(), &F, "function");
10118f8106fSJoel E. Denny }
10218f8106fSJoel E. Denny 
10318f8106fSJoel E. Denny static void remarkAlloca(OptimizationRemarkEmitter &ORE, const Function &Caller,
10418f8106fSJoel E. Denny                          const AllocaInst &Alloca,
10518f8106fSJoel E. Denny                          TypeSize::ScalarTy StaticSize) {
10618f8106fSJoel E. Denny   ORE.emit([&] {
10718f8106fSJoel E. Denny     StringRef DbgName;
10818f8106fSJoel E. Denny     DebugLoc Loc;
10918f8106fSJoel E. Denny     bool Artificial = false;
11018f8106fSJoel E. Denny     auto DVRs = findDVRDeclares(&const_cast<AllocaInst &>(Alloca));
11118f8106fSJoel E. Denny     if (!DVRs.empty()) {
11218f8106fSJoel E. Denny       const DbgVariableRecord &DVR = **DVRs.begin();
11318f8106fSJoel E. Denny       DbgName = DVR.getVariable()->getName();
11418f8106fSJoel E. Denny       Loc = DVR.getDebugLoc();
11518f8106fSJoel E. Denny       Artificial = DVR.Variable->isArtificial();
11618f8106fSJoel E. Denny     }
11718f8106fSJoel E. Denny     OptimizationRemark R(DEBUG_TYPE, "Alloca", DiagnosticLocation(Loc),
11818f8106fSJoel E. Denny                          Alloca.getParent());
11918f8106fSJoel E. Denny     R << "in ";
12018f8106fSJoel E. Denny     identifyFunction(R, Caller);
12118f8106fSJoel E. Denny     R << ", ";
12218f8106fSJoel E. Denny     if (Artificial)
12318f8106fSJoel E. Denny       R << "artificial ";
12418f8106fSJoel E. Denny     SmallString<20> ValName;
12518f8106fSJoel E. Denny     raw_svector_ostream OS(ValName);
12618f8106fSJoel E. Denny     Alloca.printAsOperand(OS, /*PrintType=*/false, Caller.getParent());
12718f8106fSJoel E. Denny     R << "alloca ('" << ValName << "') ";
12818f8106fSJoel E. Denny     if (!DbgName.empty())
12918f8106fSJoel E. Denny       R << "for '" << DbgName << "' ";
13018f8106fSJoel E. Denny     else
13118f8106fSJoel E. Denny       R << "without debug info ";
13218f8106fSJoel E. Denny     R << "with ";
13318f8106fSJoel E. Denny     if (StaticSize)
13418f8106fSJoel E. Denny       R << "static size of " << itostr(StaticSize) << " bytes";
13518f8106fSJoel E. Denny     else
13618f8106fSJoel E. Denny       R << "dynamic size";
13718f8106fSJoel E. Denny     return R;
13818f8106fSJoel E. Denny   });
13918f8106fSJoel E. Denny }
14018f8106fSJoel E. Denny 
14118f8106fSJoel E. Denny static void remarkCall(OptimizationRemarkEmitter &ORE, const Function &Caller,
14218f8106fSJoel E. Denny                        const CallBase &Call, StringRef CallKind,
14318f8106fSJoel E. Denny                        StringRef RemarkKind) {
14418f8106fSJoel E. Denny   ORE.emit([&] {
14518f8106fSJoel E. Denny     OptimizationRemark R(DEBUG_TYPE, RemarkKind, &Call);
14618f8106fSJoel E. Denny     R << "in ";
14718f8106fSJoel E. Denny     identifyFunction(R, Caller);
14818f8106fSJoel E. Denny     R << ", " << CallKind << ", callee is ";
14918f8106fSJoel E. Denny     identifyCallee(R, Caller.getParent(), Call.getCalledOperand());
15018f8106fSJoel E. Denny     return R;
15118f8106fSJoel E. Denny   });
15218f8106fSJoel E. Denny }
15318f8106fSJoel E. Denny 
15418f8106fSJoel E. Denny static void remarkFlatAddrspaceAccess(OptimizationRemarkEmitter &ORE,
15518f8106fSJoel E. Denny                                       const Function &Caller,
15618f8106fSJoel E. Denny                                       const Instruction &Inst) {
15718f8106fSJoel E. Denny   ORE.emit([&] {
15818f8106fSJoel E. Denny     OptimizationRemark R(DEBUG_TYPE, "FlatAddrspaceAccess", &Inst);
15918f8106fSJoel E. Denny     R << "in ";
16018f8106fSJoel E. Denny     identifyFunction(R, Caller);
16118f8106fSJoel E. Denny     if (const IntrinsicInst *II = dyn_cast<IntrinsicInst>(&Inst)) {
16218f8106fSJoel E. Denny       R << ", '" << II->getCalledFunction()->getName() << "' call";
16318f8106fSJoel E. Denny     } else {
16418f8106fSJoel E. Denny       R << ", '" << Inst.getOpcodeName() << "' instruction";
16518f8106fSJoel E. Denny     }
16618f8106fSJoel E. Denny     if (!Inst.getType()->isVoidTy()) {
16718f8106fSJoel E. Denny       SmallString<20> Name;
16818f8106fSJoel E. Denny       raw_svector_ostream OS(Name);
16918f8106fSJoel E. Denny       Inst.printAsOperand(OS, /*PrintType=*/false, Caller.getParent());
17018f8106fSJoel E. Denny       R << " ('" << Name << "')";
17118f8106fSJoel E. Denny     }
17218f8106fSJoel E. Denny     R << " accesses memory in flat address space";
17318f8106fSJoel E. Denny     return R;
17418f8106fSJoel E. Denny   });
17518f8106fSJoel E. Denny }
17618f8106fSJoel E. Denny 
17718f8106fSJoel E. Denny void KernelInfo::updateForBB(const BasicBlock &BB,
17818f8106fSJoel E. Denny                              OptimizationRemarkEmitter &ORE) {
17918f8106fSJoel E. Denny   const Function &F = *BB.getParent();
18018f8106fSJoel E. Denny   const Module &M = *F.getParent();
18118f8106fSJoel E. Denny   const DataLayout &DL = M.getDataLayout();
18218f8106fSJoel E. Denny   for (const Instruction &I : BB.instructionsWithoutDebug()) {
18318f8106fSJoel E. Denny     if (const AllocaInst *Alloca = dyn_cast<AllocaInst>(&I)) {
18418f8106fSJoel E. Denny       ++Allocas;
18518f8106fSJoel E. Denny       TypeSize::ScalarTy StaticSize = 0;
18618f8106fSJoel E. Denny       if (std::optional<TypeSize> Size = Alloca->getAllocationSize(DL)) {
18718f8106fSJoel E. Denny         StaticSize = Size->getFixedValue();
1885dae05f6SSimon Pilgrim         assert(StaticSize <=
1895dae05f6SSimon Pilgrim                (TypeSize::ScalarTy)std::numeric_limits<int64_t>::max());
19018f8106fSJoel E. Denny         AllocasStaticSizeSum += StaticSize;
19118f8106fSJoel E. Denny       } else {
19218f8106fSJoel E. Denny         ++AllocasDyn;
19318f8106fSJoel E. Denny       }
19418f8106fSJoel E. Denny       remarkAlloca(ORE, F, *Alloca, StaticSize);
19518f8106fSJoel E. Denny     } else if (const CallBase *Call = dyn_cast<CallBase>(&I)) {
19618f8106fSJoel E. Denny       SmallString<40> CallKind;
19718f8106fSJoel E. Denny       SmallString<40> RemarkKind;
19818f8106fSJoel E. Denny       if (Call->isIndirectCall()) {
19918f8106fSJoel E. Denny         ++IndirectCalls;
20018f8106fSJoel E. Denny         CallKind += "indirect";
20118f8106fSJoel E. Denny         RemarkKind += "Indirect";
20218f8106fSJoel E. Denny       } else {
20318f8106fSJoel E. Denny         ++DirectCalls;
20418f8106fSJoel E. Denny         CallKind += "direct";
20518f8106fSJoel E. Denny         RemarkKind += "Direct";
20618f8106fSJoel E. Denny       }
20718f8106fSJoel E. Denny       if (isa<InvokeInst>(Call)) {
20818f8106fSJoel E. Denny         ++Invokes;
20918f8106fSJoel E. Denny         CallKind += " invoke";
21018f8106fSJoel E. Denny         RemarkKind += "Invoke";
21118f8106fSJoel E. Denny       } else {
21218f8106fSJoel E. Denny         CallKind += " call";
21318f8106fSJoel E. Denny         RemarkKind += "Call";
21418f8106fSJoel E. Denny       }
21518f8106fSJoel E. Denny       if (!Call->isIndirectCall()) {
21618f8106fSJoel E. Denny         if (const Function *Callee = Call->getCalledFunction()) {
21718f8106fSJoel E. Denny           if (!Callee->isIntrinsic() && !Callee->isDeclaration()) {
21818f8106fSJoel E. Denny             ++DirectCallsToDefinedFunctions;
21918f8106fSJoel E. Denny             CallKind += " to defined function";
22018f8106fSJoel E. Denny             RemarkKind += "ToDefinedFunction";
22118f8106fSJoel E. Denny           }
22218f8106fSJoel E. Denny         } else if (Call->isInlineAsm()) {
22318f8106fSJoel E. Denny           ++InlineAssemblyCalls;
22418f8106fSJoel E. Denny           CallKind += " to inline assembly";
22518f8106fSJoel E. Denny           RemarkKind += "ToInlineAssembly";
22618f8106fSJoel E. Denny         }
22718f8106fSJoel E. Denny       }
22818f8106fSJoel E. Denny       remarkCall(ORE, F, *Call, CallKind, RemarkKind);
22918f8106fSJoel E. Denny       if (const AnyMemIntrinsic *MI = dyn_cast<AnyMemIntrinsic>(Call)) {
23018f8106fSJoel E. Denny         if (MI->getDestAddressSpace() == FlatAddrspace) {
23118f8106fSJoel E. Denny           ++FlatAddrspaceAccesses;
23218f8106fSJoel E. Denny           remarkFlatAddrspaceAccess(ORE, F, I);
23318f8106fSJoel E. Denny         } else if (const AnyMemTransferInst *MT =
23418f8106fSJoel E. Denny                        dyn_cast<AnyMemTransferInst>(MI)) {
23518f8106fSJoel E. Denny           if (MT->getSourceAddressSpace() == FlatAddrspace) {
23618f8106fSJoel E. Denny             ++FlatAddrspaceAccesses;
23718f8106fSJoel E. Denny             remarkFlatAddrspaceAccess(ORE, F, I);
23818f8106fSJoel E. Denny           }
23918f8106fSJoel E. Denny         }
24018f8106fSJoel E. Denny       }
24118f8106fSJoel E. Denny     } else if (const LoadInst *Load = dyn_cast<LoadInst>(&I)) {
24218f8106fSJoel E. Denny       if (Load->getPointerAddressSpace() == FlatAddrspace) {
24318f8106fSJoel E. Denny         ++FlatAddrspaceAccesses;
24418f8106fSJoel E. Denny         remarkFlatAddrspaceAccess(ORE, F, I);
24518f8106fSJoel E. Denny       }
24618f8106fSJoel E. Denny     } else if (const StoreInst *Store = dyn_cast<StoreInst>(&I)) {
24718f8106fSJoel E. Denny       if (Store->getPointerAddressSpace() == FlatAddrspace) {
24818f8106fSJoel E. Denny         ++FlatAddrspaceAccesses;
24918f8106fSJoel E. Denny         remarkFlatAddrspaceAccess(ORE, F, I);
25018f8106fSJoel E. Denny       }
25118f8106fSJoel E. Denny     } else if (const AtomicRMWInst *At = dyn_cast<AtomicRMWInst>(&I)) {
25218f8106fSJoel E. Denny       if (At->getPointerAddressSpace() == FlatAddrspace) {
25318f8106fSJoel E. Denny         ++FlatAddrspaceAccesses;
25418f8106fSJoel E. Denny         remarkFlatAddrspaceAccess(ORE, F, I);
25518f8106fSJoel E. Denny       }
25618f8106fSJoel E. Denny     } else if (const AtomicCmpXchgInst *At = dyn_cast<AtomicCmpXchgInst>(&I)) {
25718f8106fSJoel E. Denny       if (At->getPointerAddressSpace() == FlatAddrspace) {
25818f8106fSJoel E. Denny         ++FlatAddrspaceAccesses;
25918f8106fSJoel E. Denny         remarkFlatAddrspaceAccess(ORE, F, I);
26018f8106fSJoel E. Denny       }
26118f8106fSJoel E. Denny     }
26218f8106fSJoel E. Denny   }
26318f8106fSJoel E. Denny }
26418f8106fSJoel E. Denny 
26518f8106fSJoel E. Denny static void remarkProperty(OptimizationRemarkEmitter &ORE, const Function &F,
26618f8106fSJoel E. Denny                            StringRef Name, int64_t Value) {
26718f8106fSJoel E. Denny   ORE.emit([&] {
26818f8106fSJoel E. Denny     OptimizationRemark R(DEBUG_TYPE, Name, &F);
26918f8106fSJoel E. Denny     R << "in ";
27018f8106fSJoel E. Denny     identifyFunction(R, F);
27118f8106fSJoel E. Denny     R << ", " << Name << " = " << itostr(Value);
27218f8106fSJoel E. Denny     return R;
27318f8106fSJoel E. Denny   });
27418f8106fSJoel E. Denny }
27518f8106fSJoel E. Denny 
27618f8106fSJoel E. Denny static std::optional<int64_t> parseFnAttrAsInteger(Function &F,
27718f8106fSJoel E. Denny                                                    StringRef Name) {
27818f8106fSJoel E. Denny   if (!F.hasFnAttribute(Name))
27918f8106fSJoel E. Denny     return std::nullopt;
28018f8106fSJoel E. Denny   return F.getFnAttributeAsParsedInteger(Name);
28118f8106fSJoel E. Denny }
28218f8106fSJoel E. Denny 
28318f8106fSJoel E. Denny void KernelInfo::emitKernelInfo(Function &F, FunctionAnalysisManager &FAM,
28418f8106fSJoel E. Denny                                 TargetMachine *TM) {
28518f8106fSJoel E. Denny   KernelInfo KI;
28618f8106fSJoel E. Denny   TargetTransformInfo &TheTTI = FAM.getResult<TargetIRAnalysis>(F);
28718f8106fSJoel E. Denny   KI.FlatAddrspace = TheTTI.getFlatAddressSpace();
28818f8106fSJoel E. Denny 
28918f8106fSJoel E. Denny   // Record function properties.
29018f8106fSJoel E. Denny   KI.ExternalNotKernel = F.hasExternalLinkage() && !F.hasKernelCallingConv();
29118f8106fSJoel E. Denny   for (StringRef Name : {"omp_target_num_teams", "omp_target_thread_limit"}) {
29218f8106fSJoel E. Denny     if (auto Val = parseFnAttrAsInteger(F, Name))
29318f8106fSJoel E. Denny       KI.LaunchBounds.push_back({Name, *Val});
29418f8106fSJoel E. Denny   }
29518f8106fSJoel E. Denny   TheTTI.collectKernelLaunchBounds(F, KI.LaunchBounds);
29618f8106fSJoel E. Denny 
29718f8106fSJoel E. Denny   auto &ORE = FAM.getResult<OptimizationRemarkEmitterAnalysis>(F);
29818f8106fSJoel E. Denny   for (const auto &BB : F)
29918f8106fSJoel E. Denny     KI.updateForBB(BB, ORE);
30018f8106fSJoel E. Denny 
30118f8106fSJoel E. Denny #define REMARK_PROPERTY(PROP_NAME)                                             \
30218f8106fSJoel E. Denny   remarkProperty(ORE, F, #PROP_NAME, KI.PROP_NAME)
30318f8106fSJoel E. Denny   REMARK_PROPERTY(ExternalNotKernel);
30418f8106fSJoel E. Denny   for (auto LB : KI.LaunchBounds)
30518f8106fSJoel E. Denny     remarkProperty(ORE, F, LB.first, LB.second);
30618f8106fSJoel E. Denny   REMARK_PROPERTY(Allocas);
30718f8106fSJoel E. Denny   REMARK_PROPERTY(AllocasStaticSizeSum);
30818f8106fSJoel E. Denny   REMARK_PROPERTY(AllocasDyn);
30918f8106fSJoel E. Denny   REMARK_PROPERTY(DirectCalls);
31018f8106fSJoel E. Denny   REMARK_PROPERTY(IndirectCalls);
31118f8106fSJoel E. Denny   REMARK_PROPERTY(DirectCallsToDefinedFunctions);
31218f8106fSJoel E. Denny   REMARK_PROPERTY(InlineAssemblyCalls);
31318f8106fSJoel E. Denny   REMARK_PROPERTY(Invokes);
31418f8106fSJoel E. Denny   REMARK_PROPERTY(FlatAddrspaceAccesses);
31518f8106fSJoel E. Denny #undef REMARK_PROPERTY
31618f8106fSJoel E. Denny 
31718f8106fSJoel E. Denny   return;
31818f8106fSJoel E. Denny }
31918f8106fSJoel E. Denny 
32018f8106fSJoel E. Denny PreservedAnalyses KernelInfoPrinter::run(Function &F,
32118f8106fSJoel E. Denny                                          FunctionAnalysisManager &AM) {
32218f8106fSJoel E. Denny   // Skip it if remarks are not enabled as it will do nothing useful.
32318f8106fSJoel E. Denny   if (F.getContext().getDiagHandlerPtr()->isPassedOptRemarkEnabled(DEBUG_TYPE))
32418f8106fSJoel E. Denny     KernelInfo::emitKernelInfo(F, AM, TM);
32518f8106fSJoel E. Denny   return PreservedAnalyses::all();
32618f8106fSJoel E. Denny }
327