[llvm] [AMDGPU] Explicit instruction prefetch for large entry functions (PR #227995)
Lukas Sommer via llvm-commits
llvm-commits at lists.llvm.org
Tue Oct 6 09:50:30 PDT 2026
================
@@ -0,0 +1,324 @@
+//===- AMDGPUInsertICachePrefetch.cpp - Insert ICache prefetches ---------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+/// \file
+/// Insert instruction-cache prefetches for large AMDHSA entry functions.
+//
+// The prefetch instruction is fire-and-forget: it updates no wave wait counter
+// and returns neither a result nor an error. It is therefore safe to insert
+// after the wait-counter and hazard passes.
+//
+//===----------------------------------------------------------------------===//
+
+#include "AMDGPU.h"
+#include "GCNSubtarget.h"
+#include "MCTargetDesc/AMDGPUMCTargetDesc.h"
+#include "SIMachineFunctionInfo.h"
+#include "SIProgramInfo.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/CodeGen/MachineLoopInfo.h"
+#include "llvm/CodeGen/MachinePostDominators.h"
+#include "llvm/InitializePasses.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/TargetParser/Triple.h"
+
+using namespace llvm;
+
+#define DEBUG_TYPE "amdgpu-insert-icache-prefetch"
+
+static cl::opt<bool>
+ EnableICachePrefetch("amdgpu-icache-prefetch",
+ cl::desc("Insert ICache prefetch instructions"),
+ cl::init(true), cl::Hidden);
+
+static cl::opt<unsigned> ICachePrefetchInitialSize(
+ "amdgpu-icache-prefetch-initial-size",
+ cl::desc("Override the initial instruction prefetch size in bytes"),
+ cl::init(0), cl::Hidden);
+
+static cl::opt<unsigned> ICachePrefetchThreshold(
+ "amdgpu-icache-prefetch-threshold",
+ cl::desc("Override the explicit instruction prefetch threshold in bytes"),
+ cl::init(0), cl::Hidden);
+
+namespace {
+
+class AMDGPUInsertICachePrefetch {
+ MachineLoopInfo &MLI;
+ MachinePostDominatorTree &PDT;
+
+ bool isLoopFreeEntryPostDominator(const MachineBasicBlock &MBB,
+ const MachineBasicBlock &EntryBB) const {
+ return !MLI.getLoopFor(&MBB) && PDT.dominates(&MBB, &EntryBB);
+ }
+
+public:
+ // These analyses describe the final machine CFG at this late insertion
+ // point. CFG-based placement will use them to select loop-free blocks on
+ // the entry block's post-dominator chain.
+ AMDGPUInsertICachePrefetch(MachineLoopInfo &MLI,
+ MachinePostDominatorTree &PDT)
+ : MLI(MLI), PDT(PDT) {}
+
+ bool run(MachineFunction &MF);
+};
+
+class AMDGPUInsertICachePrefetchLegacy : public MachineFunctionPass {
+public:
+ static char ID;
+
+ AMDGPUInsertICachePrefetchLegacy() : MachineFunctionPass(ID) {}
+
+ void getAnalysisUsage(AnalysisUsage &AU) const override {
+ AU.setPreservesCFG();
+ AU.addRequired<MachineLoopInfoWrapperPass>();
+ AU.addRequired<MachinePostDominatorTreeWrapperPass>();
+ MachineFunctionPass::getAnalysisUsage(AU);
+ }
+
+ bool runOnMachineFunction(MachineFunction &MF) override {
+ auto &MLI = getAnalysis<MachineLoopInfoWrapperPass>().getLI();
+ auto &PDT =
+ getAnalysis<MachinePostDominatorTreeWrapperPass>().getPostDomTree();
+ return AMDGPUInsertICachePrefetch(MLI, PDT).run(MF);
+ }
+};
+
+} // end anonymous namespace
+
+struct ICachePrefetchConfig {
+ uint64_t InitialSize;
+ uint64_t Threshold;
+};
+
+static ICachePrefetchConfig getICachePrefetchConfig(const GCNSubtarget &ST) {
+ assert(ST.hasInstPrefSize());
+
+ uint32_t Mask, Shift, Width, CacheLineSize;
+ ST.getInstPrefSizeArgs(Mask, Shift, Width, CacheLineSize);
+ uint64_t DescriptorPrefetchCapacity =
+ ((uint64_t{1} << Width) - 1) * CacheLineSize;
+ uint64_t InitialSize = ICachePrefetchInitialSize.getNumOccurrences()
+ ? ICachePrefetchInitialSize
+ : ST.getInitialInstPrefSize();
+ uint64_t Threshold = ICachePrefetchThreshold.getNumOccurrences()
+ ? ICachePrefetchThreshold
+ : DescriptorPrefetchCapacity;
+
+ if (InitialSize == 0 || InitialSize % CacheLineSize != 0 ||
+ InitialSize > DescriptorPrefetchCapacity)
+ report_fatal_error(
+ Twine("-amdgpu-icache-prefetch-initial-size must be a non-zero "
----------------
sommerlukas wrote:
I've added additional `RUN` lines in `icache-prefetch-config.ll` covering these error conditions.
https://github.com/llvm/llvm-project/pull/227995
More information about the llvm-commits
mailing list