[llvm] Fix/instrumentor indirect on gpu (PR #209835)

via llvm-commits llvm-commits at lists.llvm.org
Wed Jul 15 13:53:07 PDT 2026


https://github.com/jandrovins updated https://github.com/llvm/llvm-project/pull/209835

>From 719922f91e65e9822414c7934dbfe00cd43d9d89 Mon Sep 17 00:00:00 2001
From: "Vincent A. Arcila Larrea" <arcilalarrea1 at llnl.gov>
Date: Tue, 14 Jul 2026 10:04:42 -0700
Subject: [PATCH 1/3] [Instrumentor][FIX] Fix address-space mismatch when
 indirecting call arguments on GPU

When creating indirect call arguments, they are saved in the stack using
alloca, and the pointer to this allocation on GPU targets may have a
different pointer type than what the instrumentation call expects (i.e.
they may live in a different address space). Thus, casting to flat
pointers is necessary.
---
 llvm/lib/Transforms/IPO/Instrumentor.cpp | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/llvm/lib/Transforms/IPO/Instrumentor.cpp b/llvm/lib/Transforms/IPO/Instrumentor.cpp
index 3b52e3e1f4605..bc188e5a4bf8e 100644
--- a/llvm/lib/Transforms/IPO/Instrumentor.cpp
+++ b/llvm/lib/Transforms/IPO/Instrumentor.cpp
@@ -111,6 +111,8 @@ Value *tryToCast(IRBTy &IRB, Value *V, Type *Ty, const DataLayout &DL,
     return V;
   if (VTy->isAggregateType() || VTy->isVectorTy())
     return V;
+  if (VTy->isPointerTy() && Ty->isPointerTy())
+    return IRB.CreatePointerBitCastOrAddrSpaceCast(V, Ty);
   TypeSize RequestedSize = DL.getTypeSizeInBits(Ty);
   TypeSize ValueSize = DL.getTypeSizeInBits(VTy);
   bool ShouldTruncate = RequestedSize < ValueSize;
@@ -126,8 +128,6 @@ Value *tryToCast(IRBTy &IRB, Value *V, Type *Ty, const DataLayout &DL,
                                        /*IsSigned=*/false),
                      Ty, DL, AllowTruncate);
   }
-  if (VTy->isPointerTy() && Ty->isPointerTy())
-    return IRB.CreatePointerBitCastOrAddrSpaceCast(V, Ty);
   if (VTy->isIntegerTy() && Ty->isIntegerTy())
     return IRB.CreateIntCast(V, Ty, /*IsSigned=*/false);
   // Use bit-preserving casts for floating-point values: convert float to int
@@ -797,7 +797,7 @@ CallInst *IRTCallDescription::createLLVMCall(Value *&V,
 
       auto *AI = IIRB.getAlloca(Fn, CallParam->getType());
       IIRB.IRB.CreateStore(CallParam, AI);
-      CallParam = CachedParam = AI;
+      CallParam = CachedParam = tryToCast(IIRB.IRB, AI, IIRB.PtrTy, DL);
     }
   }
 

>From 026f8e26312005bcc0a660ba5e4ae95ef593d274 Mon Sep 17 00:00:00 2001
From: "Vincent A. Arcila Larrea" <arcilalarrea1 at llnl.gov>
Date: Wed, 15 Jul 2026 09:23:48 -0700
Subject: [PATCH 2/3] [Instrumentor] Add test for indirect calls on GPU targets

The test uses the data layout for gfx90a. It checks, among other things,
that the pointers to the stack memory allocated for indirect
calls are casted from addrspace X to address space 0
before being passed to the instrumentor runtime calls.
---
 .../Instrumentor/load_store_gpu_ind.json      | 111 +++++++++
 .../Instrumentor/load_store_gpu_ind.ll        | 221 ++++++++++++++++++
 2 files changed, 332 insertions(+)
 create mode 100644 llvm/test/Instrumentation/Instrumentor/load_store_gpu_ind.json
 create mode 100644 llvm/test/Instrumentation/Instrumentor/load_store_gpu_ind.ll

diff --git a/llvm/test/Instrumentation/Instrumentor/load_store_gpu_ind.json b/llvm/test/Instrumentation/Instrumentor/load_store_gpu_ind.json
new file mode 100644
index 0000000000000..c939df5b38df6
--- /dev/null
+++ b/llvm/test/Instrumentation/Instrumentor/load_store_gpu_ind.json
@@ -0,0 +1,111 @@
+{
+  "configuration": {
+    "runtime_prefix": "__instrumentor_",
+    "runtime_prefix.description": "The runtime API prefix.",
+    "runtime_stubs_file": "",
+    "runtime_stubs_file.description": "The file into which runtime stubs should be written.",
+    "demangle_function_names": true,
+    "demangle_function_names.description": "Demangle functions names passed to the runtime.",
+    "host_enabled": false,
+    "host_enabled.description": "Instrument non-GPU targets",
+    "gpu_enabled": true,
+    "gpu_enabled.description": "Instrument GPU targets"
+  },
+  "instruction_pre": {
+    "load": {
+      "enabled": true,
+      "pointer": true,
+      "pointer.replace": true,
+      "pointer.description": "The accessed pointer.",
+      "pointer_as": true,
+      "pointer_as.description": "The address space of the accessed pointer.",
+      "base_pointer_info": false,
+      "base_pointer_info.description": "The runtime provided base pointer info.",
+      "value_size": true,
+      "value_size.description": "The size of the loaded value.",
+      "alignment": true,
+      "alignment.description": "The known access alignment.",
+      "value_type_id": true,
+      "value_type_id.description": "The type id of the loaded value.",
+      "atomicity_ordering": true,
+      "atomicity_ordering.description": "The atomicity ordering of the load.",
+      "sync_scope_id": true,
+      "sync_scope_id.description": "The sync scope id of the load.",
+      "is_volatile": true,
+      "is_volatile.description": "Flag indicating a volatile load."
+    },
+    "store": {
+      "enabled": true,
+      "pointer": true,
+      "pointer.replace": true,
+      "pointer.description": "The accessed pointer.",
+      "pointer_as": true,
+      "pointer_as.description": "The address space of the accessed pointer.",
+      "base_pointer_info": false,
+      "base_pointer_info.description": "The runtime provided base pointer info.",
+      "value": true,
+      "value.description": "The stored value.",
+      "value_size": true,
+      "value_size.description": "The size of the stored value.",
+      "alignment": true,
+      "alignment.description": "The known access alignment.",
+      "value_type_id": true,
+      "value_type_id.description": "The type id of the stored value.",
+      "atomicity_ordering": true,
+      "atomicity_ordering.description": "The atomicity ordering of the store.",
+      "sync_scope_id": true,
+      "sync_scope_id.description": "The sync scope id of the store.",
+      "is_volatile": true,
+      "is_volatile.description": "Flag indicating a volatile store."
+    }
+  },
+  "instruction_post": {
+    "load": {
+      "enabled": true,
+      "pointer": true,
+      "pointer.description": "The accessed pointer.",
+      "pointer_as": true,
+      "pointer_as.description": "The address space of the accessed pointer.",
+      "base_pointer_info": false,
+      "base_pointer_info.description": "The runtime provided base pointer info.",
+      "value": true,
+      "value.replace": true,
+      "value.description": "The loaded value.",
+      "value_size": true,
+      "value_size.description": "The size of the loaded value.",
+      "alignment": true,
+      "alignment.description": "The known access alignment.",
+      "value_type_id": true,
+      "value_type_id.description": "The type id of the loaded value.",
+      "atomicity_ordering": true,
+      "atomicity_ordering.description": "The atomicity ordering of the load.",
+      "sync_scope_id": true,
+      "sync_scope_id.description": "The sync scope id of the load.",
+      "is_volatile": true,
+      "is_volatile.description": "Flag indicating a volatile load."
+    },
+    "store": {
+      "enabled": true,
+      "pointer": true,
+      "pointer.description": "The accessed pointer.",
+      "pointer_as": true,
+      "pointer_as.description": "The address space of the accessed pointer.",
+      "base_pointer_info": false,
+      "base_pointer_info.description": "The runtime provided base pointer info.",
+      "value": true,
+      "value.description": "The stored value.",
+      "value_size": true,
+      "value_size.description": "The size of the stored value.",
+      "alignment": true,
+      "alignment.description": "The known access alignment.",
+      "value_type_id": true,
+      "value_type_id.description": "The type id of the stored value.",
+      "atomicity_ordering": true,
+      "atomicity_ordering.description": "The atomicity ordering of the store.",
+      "sync_scope_id": true,
+      "sync_scope_id.description": "The sync scope id of the store.",
+      "is_volatile": true,
+      "is_volatile.description": "Flag indicating a volatile store."
+    }
+  }
+}
diff --git a/llvm/test/Instrumentation/Instrumentor/load_store_gpu_ind.ll b/llvm/test/Instrumentation/Instrumentor/load_store_gpu_ind.ll
new file mode 100644
index 0000000000000..618a7fd3e6c8d
--- /dev/null
+++ b/llvm/test/Instrumentation/Instrumentor/load_store_gpu_ind.ll
@@ -0,0 +1,221 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt < %s -passes=instrumentor -instrumentor-read-config-files=%S/load_store_gpu_ind.json -S | FileCheck %s
+
+target datalayout = "e-m:e-p:64:64-p1:64:64-p2:32:32-p3:32:32-p4:64:64-p5:32:32-p6:32:32-p7:160:256:256:32-p8:128:128:128:48-p9:192:256:256:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64-S32-A5-G1-ni:7:8:9"
+target triple = "amdgcn-amd-amdhsa"
+
+define noundef zeroext i1 @_Z15store_load_boolPb(ptr captures(none) noundef initializes((0, 1)) %A) {
+; CHECK-LABEL: define noundef zeroext i1 @_Z15store_load_boolPb(
+; CHECK-SAME: ptr noundef captures(none) initializes((0, 1)) [[A:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[TMP0:%.*]] = call ptr @__instrumentor_pre_store(ptr [[A]], i32 0, i64 1, i64 1, i64 1, i32 12, i32 0, i8 1, i8 0) #[[ATTR0:[0-9]+]]
+; CHECK-NEXT:    store i8 1, ptr [[TMP0]], align 1
+; CHECK-NEXT:    call void @__instrumentor_post_store(ptr [[A]], i32 0, i64 1, i64 1, i64 1, i32 12, i32 0, i8 1, i8 0) #[[ATTR0]]
+; CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds nuw i8, ptr [[A]], i64 1
+; CHECK-NEXT:    [[TMP1:%.*]] = call ptr @__instrumentor_pre_load(ptr [[ARRAYIDX]], i32 0, i64 1, i64 1, i32 12, i32 0, i8 1, i8 0) #[[ATTR0]]
+; CHECK-NEXT:    [[TMP2:%.*]] = load i8, ptr [[TMP1]], align 1
+; CHECK-NEXT:    [[TMP3:%.*]] = zext i8 [[TMP2]] to i64
+; CHECK-NEXT:    [[TMP4:%.*]] = call i64 @__instrumentor_post_load(ptr [[ARRAYIDX]], i32 0, i64 [[TMP3]], i64 1, i64 1, i32 12, i32 0, i8 1, i8 0) #[[ATTR0]]
+; CHECK-NEXT:    [[TMP5:%.*]] = trunc i64 [[TMP4]] to i8
+; CHECK-NEXT:    [[LOADEDV:%.*]] = trunc nuw i8 [[TMP5]] to i1
+; CHECK-NEXT:    ret i1 [[LOADEDV]]
+;
+entry:
+  store i8 1, ptr %A, align 1
+  %arrayidx = getelementptr inbounds nuw i8, ptr %A, i64 1
+  %0 = load i8, ptr %arrayidx, align 1
+  %loadedv = trunc nuw i8 %0 to i1
+  ret i1 %loadedv
+}
+
+
+define noundef signext i8 @_Z15store_load_charPc(ptr captures(none) noundef initializes((0, 1)) %A) {
+; CHECK-LABEL: define noundef signext i8 @_Z15store_load_charPc(
+; CHECK-SAME: ptr noundef captures(none) initializes((0, 1)) [[A:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[TMP0:%.*]] = call ptr @__instrumentor_pre_store(ptr [[A]], i32 0, i64 1, i64 1, i64 1, i32 12, i32 0, i8 1, i8 0) #[[ATTR0]]
+; CHECK-NEXT:    store i8 1, ptr [[TMP0]], align 1
+; CHECK-NEXT:    call void @__instrumentor_post_store(ptr [[A]], i32 0, i64 1, i64 1, i64 1, i32 12, i32 0, i8 1, i8 0) #[[ATTR0]]
+; CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds nuw i8, ptr [[A]], i64 1
+; CHECK-NEXT:    [[TMP1:%.*]] = call ptr @__instrumentor_pre_load(ptr [[ARRAYIDX]], i32 0, i64 1, i64 1, i32 12, i32 0, i8 1, i8 0) #[[ATTR0]]
+; CHECK-NEXT:    [[TMP2:%.*]] = load i8, ptr [[TMP1]], align 1
+; CHECK-NEXT:    [[TMP3:%.*]] = zext i8 [[TMP2]] to i64
+; CHECK-NEXT:    [[TMP4:%.*]] = call i64 @__instrumentor_post_load(ptr [[ARRAYIDX]], i32 0, i64 [[TMP3]], i64 1, i64 1, i32 12, i32 0, i8 1, i8 0) #[[ATTR0]]
+; CHECK-NEXT:    [[TMP5:%.*]] = trunc i64 [[TMP4]] to i8
+; CHECK-NEXT:    ret i8 [[TMP5]]
+;
+entry:
+  store i8 1, ptr %A, align 1
+  %arrayidx = getelementptr inbounds nuw i8, ptr %A, i64 1
+  %0 = load i8, ptr %arrayidx, align 1
+  ret i8 %0
+}
+
+
+define noundef signext i16 @_Z16store_load_shortPs(ptr captures(none) noundef initializes((0, 2)) %A) {
+; CHECK-LABEL: define noundef signext i16 @_Z16store_load_shortPs(
+; CHECK-SAME: ptr noundef captures(none) initializes((0, 2)) [[A:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[TMP0:%.*]] = call ptr @__instrumentor_pre_store(ptr [[A]], i32 0, i64 2, i64 2, i64 2, i32 12, i32 0, i8 1, i8 0) #[[ATTR0]]
+; CHECK-NEXT:    store i16 2, ptr [[TMP0]], align 2
+; CHECK-NEXT:    call void @__instrumentor_post_store(ptr [[A]], i32 0, i64 2, i64 2, i64 2, i32 12, i32 0, i8 1, i8 0) #[[ATTR0]]
+; CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds nuw i8, ptr [[A]], i64 2
+; CHECK-NEXT:    [[TMP1:%.*]] = call ptr @__instrumentor_pre_load(ptr [[ARRAYIDX]], i32 0, i64 2, i64 2, i32 12, i32 0, i8 1, i8 0) #[[ATTR0]]
+; CHECK-NEXT:    [[TMP2:%.*]] = load i16, ptr [[TMP1]], align 2
+; CHECK-NEXT:    [[TMP3:%.*]] = zext i16 [[TMP2]] to i64
+; CHECK-NEXT:    [[TMP4:%.*]] = call i64 @__instrumentor_post_load(ptr [[ARRAYIDX]], i32 0, i64 [[TMP3]], i64 2, i64 2, i32 12, i32 0, i8 1, i8 0) #[[ATTR0]]
+; CHECK-NEXT:    [[TMP5:%.*]] = trunc i64 [[TMP4]] to i16
+; CHECK-NEXT:    ret i16 [[TMP5]]
+;
+entry:
+  store i16 2, ptr %A, align 2
+  %arrayidx = getelementptr inbounds nuw i8, ptr %A, i64 2
+  %0 = load i16, ptr %arrayidx, align 2
+  ret i16 %0
+}
+
+
+define noundef i32 @_Z14store_load_intPi(ptr captures(none) noundef initializes((0, 4)) %A) {
+; CHECK-LABEL: define noundef i32 @_Z14store_load_intPi(
+; CHECK-SAME: ptr noundef captures(none) initializes((0, 4)) [[A:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[TMP0:%.*]] = call ptr @__instrumentor_pre_store(ptr [[A]], i32 0, i64 3, i64 4, i64 4, i32 12, i32 0, i8 1, i8 0) #[[ATTR0]]
+; CHECK-NEXT:    store i32 3, ptr [[TMP0]], align 4
+; CHECK-NEXT:    call void @__instrumentor_post_store(ptr [[A]], i32 0, i64 3, i64 4, i64 4, i32 12, i32 0, i8 1, i8 0) #[[ATTR0]]
+; CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds nuw i8, ptr [[A]], i64 4
+; CHECK-NEXT:    [[TMP1:%.*]] = call ptr @__instrumentor_pre_load(ptr [[ARRAYIDX]], i32 0, i64 4, i64 4, i32 12, i32 0, i8 1, i8 0) #[[ATTR0]]
+; CHECK-NEXT:    [[TMP2:%.*]] = load i32, ptr [[TMP1]], align 4
+; CHECK-NEXT:    [[TMP3:%.*]] = zext i32 [[TMP2]] to i64
+; CHECK-NEXT:    [[TMP4:%.*]] = call i64 @__instrumentor_post_load(ptr [[ARRAYIDX]], i32 0, i64 [[TMP3]], i64 4, i64 4, i32 12, i32 0, i8 1, i8 0) #[[ATTR0]]
+; CHECK-NEXT:    [[TMP5:%.*]] = trunc i64 [[TMP4]] to i32
+; CHECK-NEXT:    ret i32 [[TMP5]]
+;
+entry:
+  store i32 3, ptr %A, align 4
+  %arrayidx = getelementptr inbounds nuw i8, ptr %A, i64 4
+  %0 = load i32, ptr %arrayidx, align 4
+  ret i32 %0
+}
+
+
+define noundef i64 @_Z15store_load_longPl(ptr captures(none) noundef initializes((0, 8)) %A) {
+; CHECK-LABEL: define noundef i64 @_Z15store_load_longPl(
+; CHECK-SAME: ptr noundef captures(none) initializes((0, 8)) [[A:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[TMP0:%.*]] = call ptr @__instrumentor_pre_store(ptr [[A]], i32 0, i64 4, i64 8, i64 8, i32 12, i32 0, i8 1, i8 0) #[[ATTR0]]
+; CHECK-NEXT:    store i64 4, ptr [[TMP0]], align 8
+; CHECK-NEXT:    call void @__instrumentor_post_store(ptr [[A]], i32 0, i64 4, i64 8, i64 8, i32 12, i32 0, i8 1, i8 0) #[[ATTR0]]
+; CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds nuw i8, ptr [[A]], i64 8
+; CHECK-NEXT:    [[TMP1:%.*]] = call ptr @__instrumentor_pre_load(ptr [[ARRAYIDX]], i32 0, i64 8, i64 8, i32 12, i32 0, i8 1, i8 0) #[[ATTR0]]
+; CHECK-NEXT:    [[TMP2:%.*]] = load i64, ptr [[TMP1]], align 8
+; CHECK-NEXT:    [[TMP3:%.*]] = call i64 @__instrumentor_post_load(ptr [[ARRAYIDX]], i32 0, i64 [[TMP2]], i64 8, i64 8, i32 12, i32 0, i8 1, i8 0) #[[ATTR0]]
+; CHECK-NEXT:    ret i64 [[TMP3]]
+;
+entry:
+  store i64 4, ptr %A, align 8
+  %arrayidx = getelementptr inbounds nuw i8, ptr %A, i64 8
+  %0 = load i64, ptr %arrayidx, align 8
+  ret i64 %0
+}
+
+
+define noundef i128 @_Z20store_load_long_longPx(ptr captures(none) noundef initializes((0, 16)) %A) {
+; CHECK-LABEL: define noundef i128 @_Z20store_load_long_longPx(
+; CHECK-SAME: ptr noundef captures(none) initializes((0, 16)) [[A:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[TMP0:%.*]] = alloca i128, align 8, addrspace(5)
+; CHECK-NEXT:    store i128 5, ptr addrspace(5) [[TMP0]], align 8
+; CHECK-NEXT:    [[TMP1:%.*]] = addrspacecast ptr addrspace(5) [[TMP0]] to ptr
+; CHECK-NEXT:    [[TMP2:%.*]] = call ptr @__instrumentor_pre_store_ind(ptr [[A]], i32 0, ptr [[TMP1]], i64 16, i64 8, i32 12, i32 0, i8 1, i8 0) #[[ATTR0]]
+; CHECK-NEXT:    store i128 5, ptr [[TMP2]], align 8
+; CHECK-NEXT:    call void @__instrumentor_post_store_ind(ptr [[A]], i32 0, ptr [[TMP1]], i64 16, i64 8, i32 12, i32 0, i8 1, i8 0) #[[ATTR0]]
+; CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds nuw i8, ptr [[A]], i64 16
+; CHECK-NEXT:    [[TMP3:%.*]] = call ptr @__instrumentor_pre_load(ptr [[ARRAYIDX]], i32 0, i64 16, i64 8, i32 12, i32 0, i8 1, i8 0) #[[ATTR0]]
+; CHECK-NEXT:    [[TMP6:%.*]] = load i128, ptr [[TMP3]], align 8
+; CHECK-NEXT:    store i128 [[TMP6]], ptr addrspace(5) [[TMP0]], align 8
+; CHECK-NEXT:    [[TMP5:%.*]] = addrspacecast ptr addrspace(5) [[TMP0]] to ptr
+; CHECK-NEXT:    call void @__instrumentor_post_load_ind(ptr [[ARRAYIDX]], i32 0, ptr [[TMP5]], i64 16, i64 8, i32 12, i32 0, i8 1, i8 0) #[[ATTR0]]
+; CHECK-NEXT:    [[TMP4:%.*]] = load i128, ptr [[TMP5]], align 8
+; CHECK-NEXT:    ret i128 [[TMP4]]
+;
+entry:
+  store i128 5, ptr %A, align 8
+  %arrayidx = getelementptr inbounds nuw i8, ptr %A, i64 16
+  %0 = load i128, ptr %arrayidx, align 8
+  ret i128 %0
+}
+
+
+define noundef float @_Z16store_load_floatPf(ptr captures(none) noundef initializes((0, 4)) %A) {
+; CHECK-LABEL: define noundef float @_Z16store_load_floatPf(
+; CHECK-SAME: ptr noundef captures(none) initializes((0, 4)) [[A:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[TMP0:%.*]] = call ptr @__instrumentor_pre_store(ptr [[A]], i32 0, i64 1086324736, i64 4, i64 4, i32 2, i32 0, i8 1, i8 0) #[[ATTR0]]
+; CHECK-NEXT:    store float 6.000000e+00, ptr [[TMP0]], align 4
+; CHECK-NEXT:    call void @__instrumentor_post_store(ptr [[A]], i32 0, i64 1086324736, i64 4, i64 4, i32 2, i32 0, i8 1, i8 0) #[[ATTR0]]
+; CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds nuw i8, ptr [[A]], i64 4
+; CHECK-NEXT:    [[TMP1:%.*]] = call ptr @__instrumentor_pre_load(ptr [[ARRAYIDX]], i32 0, i64 4, i64 4, i32 2, i32 0, i8 1, i8 0) #[[ATTR0]]
+; CHECK-NEXT:    [[TMP2:%.*]] = load float, ptr [[TMP1]], align 4
+; CHECK-NEXT:    [[TMP3:%.*]] = bitcast float [[TMP2]] to i32
+; CHECK-NEXT:    [[TMP4:%.*]] = zext i32 [[TMP3]] to i64
+; CHECK-NEXT:    [[TMP5:%.*]] = call i64 @__instrumentor_post_load(ptr [[ARRAYIDX]], i32 0, i64 [[TMP4]], i64 4, i64 4, i32 2, i32 0, i8 1, i8 0) #[[ATTR0]]
+; CHECK-NEXT:    [[TMP6:%.*]] = trunc i64 [[TMP5]] to i32
+; CHECK-NEXT:    [[TMP7:%.*]] = bitcast i32 [[TMP6]] to float
+; CHECK-NEXT:    ret float [[TMP7]]
+;
+entry:
+  store float 6.000000e+00, ptr %A, align 4
+  %arrayidx = getelementptr inbounds nuw i8, ptr %A, i64 4
+  %0 = load float, ptr %arrayidx, align 4
+  ret float %0
+}
+
+
+define noundef double @_Z17store_load_doublePd(ptr captures(none) noundef initializes((0, 8)) %A) {
+; CHECK-LABEL: define noundef double @_Z17store_load_doublePd(
+; CHECK-SAME: ptr noundef captures(none) initializes((0, 8)) [[A:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[TMP0:%.*]] = call ptr @__instrumentor_pre_store(ptr [[A]], i32 0, i64 4619567317775286272, i64 8, i64 8, i32 3, i32 0, i8 1, i8 0) #[[ATTR0]]
+; CHECK-NEXT:    store double 7.000000e+00, ptr [[TMP0]], align 8
+; CHECK-NEXT:    call void @__instrumentor_post_store(ptr [[A]], i32 0, i64 4619567317775286272, i64 8, i64 8, i32 3, i32 0, i8 1, i8 0) #[[ATTR0]]
+; CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds nuw i8, ptr [[A]], i64 8
+; CHECK-NEXT:    [[TMP1:%.*]] = call ptr @__instrumentor_pre_load(ptr [[ARRAYIDX]], i32 0, i64 8, i64 8, i32 3, i32 0, i8 1, i8 0) #[[ATTR0]]
+; CHECK-NEXT:    [[TMP2:%.*]] = load double, ptr [[TMP1]], align 8
+; CHECK-NEXT:    [[TMP3:%.*]] = bitcast double [[TMP2]] to i64
+; CHECK-NEXT:    [[TMP4:%.*]] = call i64 @__instrumentor_post_load(ptr [[ARRAYIDX]], i32 0, i64 [[TMP3]], i64 8, i64 8, i32 3, i32 0, i8 1, i8 0) #[[ATTR0]]
+; CHECK-NEXT:    [[TMP5:%.*]] = bitcast i64 [[TMP4]] to double
+; CHECK-NEXT:    ret double [[TMP5]]
+;
+entry:
+  store double 7.000000e+00, ptr %A, align 8
+  %arrayidx = getelementptr inbounds nuw i8, ptr %A, i64 8
+  %0 = load double, ptr %arrayidx, align 8
+  ret double %0
+}
+
+
+define noundef x86_fp80 @_Z22store_load_long_doublePe(ptr captures(none) noundef initializes((0, 10)) %A) {
+; CHECK-LABEL: define noundef x86_fp80 @_Z22store_load_long_doublePe(
+; CHECK-SAME: ptr noundef captures(none) initializes((0, 10)) [[A:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[TMP0:%.*]] = alloca x86_fp80, align 16, addrspace(5)
+; CHECK-NEXT:    store x86_fp80 8.000000e+00, ptr addrspace(5) [[TMP0]], align 16
+; CHECK-NEXT:    [[TMP1:%.*]] = addrspacecast ptr addrspace(5) [[TMP0]] to ptr
+; CHECK-NEXT:    [[TMP2:%.*]] = call ptr @__instrumentor_pre_store_ind(ptr [[A]], i32 0, ptr [[TMP1]], i64 10, i64 16, i32 4, i32 0, i8 1, i8 0) #[[ATTR0]]
+; CHECK-NEXT:    store x86_fp80 8.000000e+00, ptr [[TMP2]], align 16
+; CHECK-NEXT:    call void @__instrumentor_post_store_ind(ptr [[A]], i32 0, ptr [[TMP1]], i64 10, i64 16, i32 4, i32 0, i8 1, i8 0) #[[ATTR0]]
+; CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds nuw i8, ptr [[A]], i64 16
+; CHECK-NEXT:    [[TMP3:%.*]] = call ptr @__instrumentor_pre_load(ptr [[ARRAYIDX]], i32 0, i64 10, i64 16, i32 4, i32 0, i8 1, i8 0) #[[ATTR0]]
+; CHECK-NEXT:    [[TMP6:%.*]] = load x86_fp80, ptr [[TMP3]], align 16
+; CHECK-NEXT:    store x86_fp80 [[TMP6]], ptr addrspace(5) [[TMP0]], align 16
+; CHECK-NEXT:    [[TMP5:%.*]] = addrspacecast ptr addrspace(5) [[TMP0]] to ptr
+; CHECK-NEXT:    call void @__instrumentor_post_load_ind(ptr [[ARRAYIDX]], i32 0, ptr [[TMP5]], i64 10, i64 16, i32 4, i32 0, i8 1, i8 0) #[[ATTR0]]
+; CHECK-NEXT:    [[TMP4:%.*]] = load x86_fp80, ptr [[TMP5]], align 16
+; CHECK-NEXT:    ret x86_fp80 [[TMP4]]
+;
+entry:
+  store x86_fp80 0xK40028000000000000000, ptr %A, align 16
+  %arrayidx = getelementptr inbounds nuw i8, ptr %A, i64 16
+  %0 = load x86_fp80, ptr %arrayidx, align 16
+  ret x86_fp80 %0
+}

>From 1feda1f523bb8d1787acbd74ccbcd7eed548870a Mon Sep 17 00:00:00 2001
From: "Vincent A. Arcila Larrea" <arcilalarrea1 at llnl.gov>
Date: Wed, 15 Jul 2026 13:43:39 -0700
Subject: [PATCH 3/3] [Instrumentor] Replace x86_fp80 indirection test with a
 vector case

x86_fp80 is x86-specific and can't actually occur in code compiled
for the amdgcn target this file tests. Use a <4 x i8> vector instead,
which goes through an indirection path.
---
 .../Instrumentor/load_store_gpu_ind.ll        | 38 +++++++++----------
 1 file changed, 19 insertions(+), 19 deletions(-)

diff --git a/llvm/test/Instrumentation/Instrumentor/load_store_gpu_ind.ll b/llvm/test/Instrumentation/Instrumentor/load_store_gpu_ind.ll
index 618a7fd3e6c8d..d17ac79988737 100644
--- a/llvm/test/Instrumentation/Instrumentor/load_store_gpu_ind.ll
+++ b/llvm/test/Instrumentation/Instrumentor/load_store_gpu_ind.ll
@@ -194,28 +194,28 @@ entry:
 }
 
 
-define noundef x86_fp80 @_Z22store_load_long_doublePe(ptr captures(none) noundef initializes((0, 10)) %A) {
-; CHECK-LABEL: define noundef x86_fp80 @_Z22store_load_long_doublePe(
-; CHECK-SAME: ptr noundef captures(none) initializes((0, 10)) [[A:%.*]]) {
+define <4 x i8> @store_load_vec4i8(ptr captures(none) noundef initializes((0, 4)) %A) {
+; CHECK-LABEL: define <4 x i8> @store_load_vec4i8(
+; CHECK-SAME: ptr noundef captures(none) initializes((0, 4)) [[A:%.*]]) {
 ; CHECK-NEXT:  [[ENTRY:.*:]]
-; CHECK-NEXT:    [[TMP0:%.*]] = alloca x86_fp80, align 16, addrspace(5)
-; CHECK-NEXT:    store x86_fp80 8.000000e+00, ptr addrspace(5) [[TMP0]], align 16
+; CHECK-NEXT:    [[TMP0:%.*]] = alloca <4 x i8>, align 4, addrspace(5)
+; CHECK-NEXT:    store <4 x i8> <i8 1, i8 2, i8 3, i8 4>, ptr addrspace(5) [[TMP0]], align 4
 ; CHECK-NEXT:    [[TMP1:%.*]] = addrspacecast ptr addrspace(5) [[TMP0]] to ptr
-; CHECK-NEXT:    [[TMP2:%.*]] = call ptr @__instrumentor_pre_store_ind(ptr [[A]], i32 0, ptr [[TMP1]], i64 10, i64 16, i32 4, i32 0, i8 1, i8 0) #[[ATTR0]]
-; CHECK-NEXT:    store x86_fp80 8.000000e+00, ptr [[TMP2]], align 16
-; CHECK-NEXT:    call void @__instrumentor_post_store_ind(ptr [[A]], i32 0, ptr [[TMP1]], i64 10, i64 16, i32 4, i32 0, i8 1, i8 0) #[[ATTR0]]
-; CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds nuw i8, ptr [[A]], i64 16
-; CHECK-NEXT:    [[TMP3:%.*]] = call ptr @__instrumentor_pre_load(ptr [[ARRAYIDX]], i32 0, i64 10, i64 16, i32 4, i32 0, i8 1, i8 0) #[[ATTR0]]
-; CHECK-NEXT:    [[TMP6:%.*]] = load x86_fp80, ptr [[TMP3]], align 16
-; CHECK-NEXT:    store x86_fp80 [[TMP6]], ptr addrspace(5) [[TMP0]], align 16
+; CHECK-NEXT:    [[TMP2:%.*]] = call ptr @__instrumentor_pre_store_ind(ptr [[A]], i32 0, ptr [[TMP1]], i64 4, i64 1, i32 18, i32 0, i8 1, i8 0) #[[ATTR0]]
+; CHECK-NEXT:    store <4 x i8> <i8 1, i8 2, i8 3, i8 4>, ptr [[TMP2]], align 1
+; CHECK-NEXT:    call void @__instrumentor_post_store_ind(ptr [[A]], i32 0, ptr [[TMP1]], i64 4, i64 1, i32 18, i32 0, i8 1, i8 0) #[[ATTR0]]
+; CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds nuw i8, ptr [[A]], i64 4
+; CHECK-NEXT:    [[TMP3:%.*]] = call ptr @__instrumentor_pre_load(ptr [[ARRAYIDX]], i32 0, i64 4, i64 1, i32 18, i32 0, i8 1, i8 0) #[[ATTR0]]
+; CHECK-NEXT:    [[TMP4:%.*]] = load <4 x i8>, ptr [[TMP3]], align 1
+; CHECK-NEXT:    store <4 x i8> [[TMP4]], ptr addrspace(5) [[TMP0]], align 4
 ; CHECK-NEXT:    [[TMP5:%.*]] = addrspacecast ptr addrspace(5) [[TMP0]] to ptr
-; CHECK-NEXT:    call void @__instrumentor_post_load_ind(ptr [[ARRAYIDX]], i32 0, ptr [[TMP5]], i64 10, i64 16, i32 4, i32 0, i8 1, i8 0) #[[ATTR0]]
-; CHECK-NEXT:    [[TMP4:%.*]] = load x86_fp80, ptr [[TMP5]], align 16
-; CHECK-NEXT:    ret x86_fp80 [[TMP4]]
+; CHECK-NEXT:    call void @__instrumentor_post_load_ind(ptr [[ARRAYIDX]], i32 0, ptr [[TMP5]], i64 4, i64 1, i32 18, i32 0, i8 1, i8 0) #[[ATTR0]]
+; CHECK-NEXT:    [[TMP6:%.*]] = load <4 x i8>, ptr [[TMP5]], align 4
+; CHECK-NEXT:    ret <4 x i8> [[TMP6]]
 ;
 entry:
-  store x86_fp80 0xK40028000000000000000, ptr %A, align 16
-  %arrayidx = getelementptr inbounds nuw i8, ptr %A, i64 16
-  %0 = load x86_fp80, ptr %arrayidx, align 16
-  ret x86_fp80 %0
+  store <4 x i8> <i8 1, i8 2, i8 3, i8 4>, ptr %A, align 1
+  %arrayidx = getelementptr inbounds nuw i8, ptr %A, i64 4
+  %0 = load <4 x i8>, ptr %arrayidx, align 1
+  ret <4 x i8> %0
 }



More information about the llvm-commits mailing list