[llvm] [AMDGPU] Account for inline asm size in inst_pref_size calculation (PR #192306)

Adel Ejjeh via llvm-commits llvm-commits at lists.llvm.org
Wed Apr 15 11:33:14 PDT 2026


https://github.com/adelejjeh created https://github.com/llvm/llvm-project/pull/192306

This PR replaces PR #192133.
 
SIProgramInfo::getFunctionCodeSize() with IsLowerBound=true was completely skipping inline assembly instructions, treating them as zero bytes. This caused amdhsa_inst_pref_size to be severely underestimated for kernels containing inline asm, defeating instruction prefetch on gfx11+.

Use MCExpr label subtraction (.Lfunc_end - func_sym) to compute exact function code size, resolved at assembly time. This avoids inline asm string parsing which cannot reliably estimate code size and risks overestimation (which causes prefetch of unmapped memory and a fatal segfault).

Add a new AMDGPUMCExpr variant (AGVK_InstPrefSize) to compute min(divideCeil(codeSize, 128), maxFieldVal) as a custom MCExpr, following the same pattern as AGVK_Occupancy and AGVK_AlignTo.

Compute inst_pref_size in AMDGPUAsmPrinter::endFunction() where .Lfunc_end has already been emitted in the correct position (after the fix in #191526), and set the bits in ComputePGMRSrc3 before emitting the kernel descriptor.

Remove the IsLowerBound parameter from getFunctionCodeSize() as it is no longer needed for inst_pref_size calculation.

Update existing lit tests, and add a new one. The new lit test checks for the correct constant value of the prefetch size in the object file.

>From 7360907fb3385a01d1bb899bca1038f6c8db9a6e Mon Sep 17 00:00:00 2001
From: Adel Ejjeh <adel.ejjeh at amd.com>
Date: Wed, 15 Apr 2026 13:25:36 -0500
Subject: [PATCH] [AMDGPU] Account for inline asm size in inst_pref_size
 calculation

SIProgramInfo::getFunctionCodeSize() with IsLowerBound=true was
completely skipping inline assembly instructions, treating them as
zero bytes. This caused amdhsa_inst_pref_size to be severely
underestimated for kernels containing inline asm, defeating
instruction prefetch on gfx11+.

Use MCExpr label subtraction (.Lfunc_end - func_sym) to compute
exact function code size, resolved at assembly time. This avoids
inline asm string parsing which cannot reliably estimate code size
and risks overestimation (which causes prefetch of unmapped memory
and a fatal segfault).

Add a new AMDGPUMCExpr variant (AGVK_InstPrefSize) to compute
min(divideCeil(codeSize, 128), maxFieldVal) as a custom MCExpr,
following the same pattern as AGVK_Occupancy and AGVK_AlignTo.

Compute inst_pref_size in AMDGPUAsmPrinter::endFunction() where
.Lfunc_end has already been emitted in the correct position (after
the fix in #191526), and set the bits in ComputePGMRSrc3 before
emitting the kernel descriptor.

Remove the IsLowerBound parameter from getFunctionCodeSize() as it
is no longer needed for inst_pref_size calculation.

Co-Authored-By: Claude Opus 4 (1M context) <noreply at anthropic.com>
---
 llvm/lib/Target/AMDGPU/AMDGPUAsmPrinter.cpp   | 58 ++++++++-----
 .../AMDGPU/MCTargetDesc/AMDGPUMCExpr.cpp      | 38 +++++++++
 .../Target/AMDGPU/MCTargetDesc/AMDGPUMCExpr.h |  8 ++
 llvm/lib/Target/AMDGPU/SIProgramInfo.cpp      | 17 +---
 llvm/lib/Target/AMDGPU/SIProgramInfo.h        |  5 +-
 .../test/CodeGen/AMDGPU/inst-prefetch-hint.ll | 36 ++++++--
 .../AMDGPU/inst-prefetch-inline-asm.ll        | 83 +++++++++++++++++++
 7 files changed, 198 insertions(+), 47 deletions(-)
 create mode 100644 llvm/test/CodeGen/AMDGPU/inst-prefetch-inline-asm.ll

diff --git a/llvm/lib/Target/AMDGPU/AMDGPUAsmPrinter.cpp b/llvm/lib/Target/AMDGPU/AMDGPUAsmPrinter.cpp
index 6ac138f97d970..63ae2f2cc7a0b 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUAsmPrinter.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPUAsmPrinter.cpp
@@ -239,6 +239,42 @@ void AMDGPUAsmPrinter::endFunction(const MachineFunction *MF) {
 
   assert(TM.getTargetTriple().getOS() == Triple::AMDHSA);
 
+  const GCNSubtarget &STM = MF->getSubtarget<GCNSubtarget>();
+  MCContext &Ctx = MF->getContext();
+
+  // Compute inst_pref_size using MCExpr label subtraction for exact code
+  // size. (Lfunc_end - func_sym) gives the exact function code size in bytes.
+  if (isGFX11Plus(STM)) {
+    const MCExpr *CodeSizeExpr = MCBinaryExpr::createSub(
+        MCSymbolRefExpr::create(getFunctionEnd(), OutContext),
+        MCSymbolRefExpr::create(CurrentFnSym, OutContext), OutContext);
+
+    uint32_t Field, Shift, Width;
+    if (isGFX11(STM)) {
+      Field = amdhsa::COMPUTE_PGM_RSRC3_GFX11_INST_PREF_SIZE;
+      Shift = amdhsa::COMPUTE_PGM_RSRC3_GFX11_INST_PREF_SIZE_SHIFT;
+      Width = amdhsa::COMPUTE_PGM_RSRC3_GFX11_INST_PREF_SIZE_WIDTH;
+    } else {
+      Field = amdhsa::COMPUTE_PGM_RSRC3_GFX12_PLUS_INST_PREF_SIZE;
+      Shift = amdhsa::COMPUTE_PGM_RSRC3_GFX12_PLUS_INST_PREF_SIZE_SHIFT;
+      Width = amdhsa::COMPUTE_PGM_RSRC3_GFX12_PLUS_INST_PREF_SIZE_WIDTH;
+    }
+    const MCExpr *InstPrefSizeExpr =
+        AMDGPUMCExpr::createInstPrefSize(CodeSizeExpr, Width, Ctx);
+
+    auto SetBits = [&Ctx](const MCExpr *Dst, const MCExpr *Value, uint32_t Mask,
+                          uint32_t Shift) {
+      const auto *MaskExpr = MCConstantExpr::create(Mask, Ctx);
+      const auto *ShiftExpr = MCConstantExpr::create(Shift, Ctx);
+      auto *Shf = MCBinaryExpr::createShl(Value, ShiftExpr, Ctx);
+      Shf = MCBinaryExpr::createAnd(Shf, MaskExpr, Ctx);
+      return MCBinaryExpr::createOr(Dst, Shf, Ctx);
+    };
+
+    CurrentProgramInfo.ComputePGMRSrc3 = SetBits(
+        CurrentProgramInfo.ComputePGMRSrc3, InstPrefSizeExpr, Field, Shift);
+  }
+
   auto &Streamer = getTargetStreamer()->getStreamer();
   auto &Context = Streamer.getContext();
   auto &ObjectFileInfo = *Context.getObjectFileInfo();
@@ -252,8 +288,6 @@ void AMDGPUAsmPrinter::endFunction(const MachineFunction *MF) {
   Streamer.emitValueToAlignment(Align(64), 0, 1, 0);
   ReadOnlySection.ensureMinAlignment(Align(64));
 
-  const GCNSubtarget &STM = MF->getSubtarget<GCNSubtarget>();
-
   SmallString<128> KernelName;
   getNameWithPrefix(KernelName, &MF->getFunction());
   getTargetStreamer()->EmitAmdhsaKernelDescriptor(
@@ -1318,26 +1352,6 @@ void AMDGPUAsmPrinter::getSIProgramInfo(SIProgramInfo &ProgInfo,
             ", final occupancy is " + Twine(Occupancy));
     F.getContext().diagnose(Diag);
   }
-
-  if (isGFX11Plus(STM)) {
-    uint32_t CodeSizeInBytes = (uint32_t)std::min(
-        ProgInfo.getFunctionCodeSize(MF, true /* IsLowerBound */),
-        (uint64_t)std::numeric_limits<uint32_t>::max());
-    uint32_t CodeSizeInLines = divideCeil(CodeSizeInBytes, 128);
-    uint32_t Field, Shift, Width;
-    if (isGFX11(STM)) {
-      Field = amdhsa::COMPUTE_PGM_RSRC3_GFX11_INST_PREF_SIZE;
-      Shift = amdhsa::COMPUTE_PGM_RSRC3_GFX11_INST_PREF_SIZE_SHIFT;
-      Width = amdhsa::COMPUTE_PGM_RSRC3_GFX11_INST_PREF_SIZE_WIDTH;
-    } else {
-      Field = amdhsa::COMPUTE_PGM_RSRC3_GFX12_PLUS_INST_PREF_SIZE;
-      Shift = amdhsa::COMPUTE_PGM_RSRC3_GFX12_PLUS_INST_PREF_SIZE_SHIFT;
-      Width = amdhsa::COMPUTE_PGM_RSRC3_GFX12_PLUS_INST_PREF_SIZE_WIDTH;
-    }
-    uint64_t InstPrefSize = std::min(CodeSizeInLines, (1u << Width) - 1);
-    ProgInfo.ComputePGMRSrc3 = SetBits(ProgInfo.ComputePGMRSrc3,
-                                       CreateExpr(InstPrefSize), Field, Shift);
-  }
 }
 
 static unsigned getRsrcReg(CallingConv::ID CallConv) {
diff --git a/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUMCExpr.cpp b/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUMCExpr.cpp
index 63437779121a7..c13c926832f41 100644
--- a/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUMCExpr.cpp
+++ b/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUMCExpr.cpp
@@ -15,6 +15,7 @@
 #include "llvm/MC/MCSymbol.h"
 #include "llvm/MC/MCValue.h"
 #include "llvm/Support/KnownBits.h"
+#include "llvm/Support/MathExtras.h"
 #include "llvm/Support/raw_ostream.h"
 #include <optional>
 
@@ -73,6 +74,9 @@ void AMDGPUMCExpr::printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const {
   case AGVK_Occupancy:
     OS << "occupancy(";
     break;
+  case AGVK_InstPrefSize:
+    OS << "instprefsize(";
+    break;
   case AGVK_Lit:
     OS << "lit(";
     break;
@@ -218,6 +222,30 @@ bool AMDGPUMCExpr::evaluateOccupancy(MCValue &Res,
   return true;
 }
 
+bool AMDGPUMCExpr::evaluateInstPrefSize(MCValue &Res,
+                                        const MCAssembler *Asm) const {
+  auto TryGetMCExprValue = [&](const MCExpr *Arg, uint64_t &ConstantValue) {
+    MCValue MCVal;
+    if (!Arg->evaluateAsRelocatable(MCVal, Asm) || !MCVal.isAbsolute())
+      return false;
+
+    ConstantValue = MCVal.getConstant();
+    return true;
+  };
+
+  assert(Args.size() == 2 &&
+         "AMDGPUMCExpr Argument count incorrect for InstPrefSize");
+  uint64_t CodeSizeInBytes = 0, FieldWidth = 0;
+  if (!TryGetMCExprValue(Args[0], CodeSizeInBytes) ||
+      !TryGetMCExprValue(Args[1], FieldWidth))
+    return false;
+
+  uint64_t CodeSizeInLines = divideCeil(CodeSizeInBytes, (uint64_t)128);
+  uint64_t MaxVal = (1u << FieldWidth) - 1;
+  Res = MCValue::get(std::min(CodeSizeInLines, MaxVal));
+  return true;
+}
+
 bool AMDGPUMCExpr::isSymbolUsedInExpression(const MCSymbol *Sym,
                                             const MCExpr *E) {
   switch (E->getKind()) {
@@ -263,6 +291,8 @@ bool AMDGPUMCExpr::evaluateAsRelocatableImpl(MCValue &Res,
     return evaluateTotalNumVGPR(Res, Asm);
   case AGVK_Occupancy:
     return evaluateOccupancy(Res, Asm);
+  case AGVK_InstPrefSize:
+    return evaluateInstPrefSize(Res, Asm);
   case AGVK_Lit:
   case AGVK_Lit64:
     return Args[0]->evaluateAsRelocatable(Res, Asm);
@@ -315,6 +345,13 @@ const AMDGPUMCExpr *AMDGPUMCExpr::createTotalNumVGPR(const MCExpr *NumAGPR,
   return create(AGVK_TotalNumVGPRs, {NumAGPR, NumVGPR}, Ctx);
 }
 
+const AMDGPUMCExpr *
+AMDGPUMCExpr::createInstPrefSize(const MCExpr *CodeSizeBytes,
+                                 unsigned FieldWidth, MCContext &Ctx) {
+  return create(AGVK_InstPrefSize,
+                {CodeSizeBytes, MCConstantExpr::create(FieldWidth, Ctx)}, Ctx);
+}
+
 const AMDGPUMCExpr *AMDGPUMCExpr::createLit(LitModifier Lit, int64_t Value,
                                             MCContext &Ctx) {
   assert(Lit == LitModifier::Lit || Lit == LitModifier::Lit64);
@@ -505,6 +542,7 @@ static void targetOpKnownBitsMapHelper(const MCExpr *Expr, KnownBitsMap &KBM,
   case AMDGPUMCExpr::VariantKind::AGVK_TotalNumVGPRs:
   case AMDGPUMCExpr::VariantKind::AGVK_AlignTo:
   case AMDGPUMCExpr::VariantKind::AGVK_Occupancy:
+  case AMDGPUMCExpr::VariantKind::AGVK_InstPrefSize:
   case AMDGPUMCExpr::VariantKind::AGVK_Lit:
   case AMDGPUMCExpr::VariantKind::AGVK_Lit64: {
     int64_t Val;
diff --git a/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUMCExpr.h b/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUMCExpr.h
index 96bd8f4cf3c13..52c984ac450a7 100644
--- a/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUMCExpr.h
+++ b/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUMCExpr.h
@@ -38,6 +38,7 @@ class AMDGPUMCExpr : public MCTargetExpr {
     AGVK_TotalNumVGPRs,
     AGVK_AlignTo,
     AGVK_Occupancy,
+    AGVK_InstPrefSize,
     AGVK_Lit,
     AGVK_Lit64,
   };
@@ -69,6 +70,7 @@ class AMDGPUMCExpr : public MCTargetExpr {
   bool evaluateTotalNumVGPR(MCValue &Res, const MCAssembler *Asm) const;
   bool evaluateAlignTo(MCValue &Res, const MCAssembler *Asm) const;
   bool evaluateOccupancy(MCValue &Res, const MCAssembler *Asm) const;
+  bool evaluateInstPrefSize(MCValue &Res, const MCAssembler *Asm) const;
 
 public:
   static const AMDGPUMCExpr *
@@ -97,6 +99,12 @@ class AMDGPUMCExpr : public MCTargetExpr {
     return create(VariantKind::AGVK_AlignTo, {Value, Align}, Ctx);
   }
 
+  /// Create an expression for instruction prefetch size computation:
+  /// min(divideCeil(CodeSizeBytes, 128), (1 << FieldWidth) - 1)
+  static const AMDGPUMCExpr *createInstPrefSize(const MCExpr *CodeSizeBytes,
+                                                unsigned FieldWidth,
+                                                MCContext &Ctx);
+
   static const AMDGPUMCExpr *createLit(LitModifier Lit, int64_t Value,
                                        MCContext &Ctx);
 
diff --git a/llvm/lib/Target/AMDGPU/SIProgramInfo.cpp b/llvm/lib/Target/AMDGPU/SIProgramInfo.cpp
index a3f261b87e80b..abc2e01ca1df0 100644
--- a/llvm/lib/Target/AMDGPU/SIProgramInfo.cpp
+++ b/llvm/lib/Target/AMDGPU/SIProgramInfo.cpp
@@ -203,9 +203,8 @@ const MCExpr *SIProgramInfo::getPGMRSrc2(CallingConv::ID CC,
   return MCConstantExpr::create(0, Ctx);
 }
 
-uint64_t SIProgramInfo::getFunctionCodeSize(const MachineFunction &MF,
-                                            bool IsLowerBound) {
-  if (!IsLowerBound && CodeSizeInBytes.has_value())
+uint64_t SIProgramInfo::getFunctionCodeSize(const MachineFunction &MF) {
+  if (CodeSizeInBytes.has_value())
     return *CodeSizeInBytes;
 
   const GCNSubtarget &STM = MF.getSubtarget<GCNSubtarget>();
@@ -214,12 +213,7 @@ uint64_t SIProgramInfo::getFunctionCodeSize(const MachineFunction &MF,
   uint64_t CodeSize = 0;
 
   for (const MachineBasicBlock &MBB : MF) {
-    // The amount of padding to align code can be both underestimated and
-    // overestimated. In case of inline asm used getInstSizeInBytes() will
-    // return a maximum size of a single instruction, where the real size may
-    // differ. At this point CodeSize may be already off.
-    if (!IsLowerBound)
-      CodeSize = alignTo(CodeSize, MBB.getAlignment());
+    CodeSize = alignTo(CodeSize, MBB.getAlignment());
 
     for (const MachineInstr &MI : MBB) {
       // TODO: CodeSize should account for multiple functions.
@@ -227,11 +221,6 @@ uint64_t SIProgramInfo::getFunctionCodeSize(const MachineFunction &MF,
       if (MI.isMetaInstruction())
         continue;
 
-      // We cannot properly estimate inline asm size. It can be as small as zero
-      // if that is just a comment.
-      if (IsLowerBound && MI.isInlineAsm())
-        continue;
-
       CodeSize += TII->getInstSizeInBytes(MI);
     }
   }
diff --git a/llvm/lib/Target/AMDGPU/SIProgramInfo.h b/llvm/lib/Target/AMDGPU/SIProgramInfo.h
index 171c4a313a53b..bfd6b669531ea 100644
--- a/llvm/lib/Target/AMDGPU/SIProgramInfo.h
+++ b/llvm/lib/Target/AMDGPU/SIProgramInfo.h
@@ -105,10 +105,7 @@ struct LLVM_EXTERNAL_VISIBILITY SIProgramInfo {
   void reset(const MachineFunction &MF);
 
   // Get function code size and cache the value.
-  // If \p IsLowerBound is set it returns a minimal code size which is safe
-  // to address.
-  uint64_t getFunctionCodeSize(const MachineFunction &MF,
-                               bool IsLowerBound = false);
+  uint64_t getFunctionCodeSize(const MachineFunction &MF);
 
   /// Compute the value of the ComputePGMRsrc1 register.
   const MCExpr *getComputePGMRSrc1(const GCNSubtarget &ST,
diff --git a/llvm/test/CodeGen/AMDGPU/inst-prefetch-hint.ll b/llvm/test/CodeGen/AMDGPU/inst-prefetch-hint.ll
index 580167076e1f0..14b9d1444a271 100644
--- a/llvm/test/CodeGen/AMDGPU/inst-prefetch-hint.ll
+++ b/llvm/test/CodeGen/AMDGPU/inst-prefetch-hint.ll
@@ -1,10 +1,20 @@
 ; RUN: llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx1100 --amdgpu-memcpy-loop-unroll=100000 < %s | FileCheck --check-prefixes=GCN,GFX11 %s
 ; RUN: llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx1200 --amdgpu-memcpy-loop-unroll=100000 < %s | FileCheck --check-prefixes=GCN,GFX12 %s
 
+;; Verify that inst_pref_size resolves to the correct value in the object file.
+;; COMPUTE_PGM_RSRC3 is at offset 0x2C in each 64-byte kernel descriptor.
+;; GFX11 inst_pref_size is bits [9:4], so value N is encoded as N << 4.
+; RUN: llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx1100 --amdgpu-memcpy-loop-unroll=100000 -filetype=obj < %s -o %t.o
+; RUN: llvm-objdump -s -j .rodata %t.o | FileCheck --check-prefix=OBJ %s
+
+; The inst_pref_size is computed via MCExpr label subtraction
+; (code_end - func_sym), which resolves at assembly/link time.
+; In text output it appears as a symbolic expression.
+
 ; GCN-LABEL: .amdhsa_kernel large
-; GFX11: .amdhsa_inst_pref_size 3
+; GFX11: .amdhsa_inst_pref_size {{.*}}instprefsize({{.*}}large, 6){{.*}}
 ; GFX11: codeLenInByte = 3{{[0-9][0-9]$}}
-; GFX12: .amdhsa_inst_pref_size 4
+; GFX12: .amdhsa_inst_pref_size {{.*}}instprefsize({{.*}}large, 8){{.*}}
 ; GFX12: codeLenInByte = 4{{[0-9][0-9]$}}
 define amdgpu_kernel void @large(ptr addrspace(1) %out, ptr addrspace(1) %in) {
 bb:
@@ -13,20 +23,32 @@ bb:
 }
 
 ; GCN-LABEL: .amdhsa_kernel small
-; GCN: .amdhsa_inst_pref_size 1
-; GCN: codeLenInByte = {{[0-9]$}}
+; GCN: .amdhsa_inst_pref_size {{.*}}instprefsize({{.*}}small, {{[0-9]+}}){{.*}}
+; GCN: codeLenInByte = {{[0-9]+$}}
 define amdgpu_kernel void @small() {
 bb:
   ret void
 }
 
-; Ignore inline asm in size calculation
+; Inline asm is accounted for via MCExpr label subtraction (exact code size).
+; The MCExpr resolves to the correct inst_pref_size at assembly time.
 
 ; GCN-LABEL: .amdhsa_kernel inline_asm
-; GCN: .amdhsa_inst_pref_size 1
-; GCN: codeLenInByte = {{[0-9]$}}
+; GCN: .amdhsa_inst_pref_size {{.*}}instprefsize({{.*}}inline_asm, {{[0-9]+}}){{.*}}
+; GCN: codeLenInByte = {{[0-9]+$}}
 define amdgpu_kernel void @inline_asm() {
 bb:
   call void asm sideeffect ".fill 256, 4, 0", ""()
   ret void
 }
+
+;; Object file checks: verify COMPUTE_PGM_RSRC3 at offset 0x2C in each KD.
+;; COMPUTE_PGM_RSRC3 is the last dword on the 0x0020/0x0060/0x00a0 lines.
+;; GFX11 inst_pref_size is bits [9:4], so value N is encoded as N << 4.
+;;
+;; large: 348 bytes -> pref_size=3 -> 3<<4=0x30
+; OBJ: 0020 {{.*}}30000000
+;; small: 4 bytes -> pref_size=1 -> 1<<4=0x10
+; OBJ: 0060 {{.*}}10000000
+;; inline_asm: 1028 bytes -> pref_size=9 -> 9<<4=0x90
+; OBJ: 00a0 {{.*}}90000000
diff --git a/llvm/test/CodeGen/AMDGPU/inst-prefetch-inline-asm.ll b/llvm/test/CodeGen/AMDGPU/inst-prefetch-inline-asm.ll
new file mode 100644
index 0000000000000..ee344bd320aaf
--- /dev/null
+++ b/llvm/test/CodeGen/AMDGPU/inst-prefetch-inline-asm.ll
@@ -0,0 +1,83 @@
+;; Verify that inline assembly is correctly accounted for in the
+;; inst_pref_size calculation. The inst_pref_size is computed via MCExpr
+;; label subtraction (code_end - func_sym), giving exact code size.
+;; This resolves at assembly time, so we verify via object file checks.
+
+; RUN: llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx1100 -filetype=obj < %s -o %t.o
+; RUN: llvm-objdump -s -j .rodata %t.o | FileCheck --check-prefix=OBJ %s
+; RUN: llvm-readobj --symbols %t.o | FileCheck --check-prefix=SYM %s
+
+;; --- .fill directive: .fill 256, 4, 0 => 1024 bytes + 4 (s_endpgm) = 1028 ---
+;; pref_size = divideCeil(1028, 128) = 9
+
+; SYM:      Name: test_fill
+; SYM-NEXT: Value:
+; SYM-NEXT: Size: 1028
+
+define amdgpu_kernel void @test_fill() {
+  call void asm sideeffect ".fill 256, 4, 0", ""()
+  ret void
+}
+
+;; --- .space directive: .space 1024 => 1024 bytes + 4 = 1028 ---
+;; pref_size = 9
+
+; SYM:      Name: test_space
+; SYM-NEXT: Value:
+; SYM-NEXT: Size: 1028
+
+define amdgpu_kernel void @test_space() {
+  call void asm sideeffect ".space 1024", ""()
+  ret void
+}
+
+;; --- Instructions: 32 x s_nop (4 bytes each) = 128 + 4 = 132 ---
+;; pref_size = divideCeil(132, 128) = 2
+
+; SYM:      Name: test_instructions
+; SYM-NEXT: Value:
+; SYM-NEXT: Size: 132
+
+define amdgpu_kernel void @test_instructions() {
+  call void asm sideeffect "s_nop 0\0As_nop 0\0As_nop 0\0As_nop 0\0As_nop 0\0As_nop 0\0As_nop 0\0As_nop 0\0As_nop 0\0As_nop 0\0As_nop 0\0As_nop 0\0As_nop 0\0As_nop 0\0As_nop 0\0As_nop 0\0As_nop 0\0As_nop 0\0As_nop 0\0As_nop 0\0As_nop 0\0As_nop 0\0As_nop 0\0As_nop 0\0As_nop 0\0As_nop 0\0As_nop 0\0As_nop 0\0As_nop 0\0As_nop 0\0As_nop 0\0As_nop 0", ""()
+  ret void
+}
+
+;; --- Comments emit no bytes: only s_endpgm = 4 bytes ---
+;; pref_size = 1
+
+; SYM:      Name: test_comments
+; SYM-NEXT: Value:
+; SYM-NEXT: Size: 4
+
+define amdgpu_kernel void @test_comments() {
+  call void asm sideeffect "; comment 1\0A; comment 2\0A; comment 3", ""()
+  ret void
+}
+
+;; --- Empty inline asm: only s_endpgm = 4 bytes ---
+;; pref_size = 1
+
+; SYM:      Name: test_empty_asm
+; SYM-NEXT: Value:
+; SYM-NEXT: Size: 4
+
+define amdgpu_kernel void @test_empty_asm() {
+  call void asm sideeffect "", ""()
+  ret void
+}
+
+;; Object file checks: verify COMPUTE_PGM_RSRC3 at offset 0x2C in each
+;; 64-byte kernel descriptor. GFX11 inst_pref_size is bits [9:4].
+;;
+;; test_fill:         1028 bytes -> pref_size=9  -> 9<<4  = 0x90
+;; test_space:        1028 bytes -> pref_size=9  -> 9<<4  = 0x90
+;; test_instructions:  132 bytes -> pref_size=2  -> 2<<4  = 0x20
+;; test_comments:        4 bytes -> pref_size=1  -> 1<<4  = 0x10
+;; test_empty_asm:       4 bytes -> pref_size=1  -> 1<<4  = 0x10
+
+; OBJ: 0020 {{.*}}90000000
+; OBJ: 0060 {{.*}}90000000
+; OBJ: 00a0 {{.*}}20000000
+; OBJ: 00e0 {{.*}}10000000
+; OBJ: 0120 {{.*}}10000000



More information about the llvm-commits mailing list