| ; RUN: opt -S -mtriple=amdgpu-amd-amdhsa -passes=amdgpu-lower-module-lds -amdgpu-enable-object-linking < %s | FileCheck %s | |
| ; Test the three-way classification of LDS variables: | |
| ; 1. Global-scope (external linkage): standalone external declaration | |
| ; 2. Kernel-scope (internal linkage, single kernel user): wrapped in per-kernel struct | |
| ; 3. Callee-scope (internal linkage, single callee user): wrapped in per-callee struct | |
| ; | |
| ; Also tests that a global-scope variable used by multiple functions produces | |
| ; one metadata entry per (function, variable) pair. | |
| ; Global-scope: external linkage, used by both func and my_kernel. | |
| @lds_global = addrspace(3) global [64 x i32] poison, align 16 | |
| ; Callee-scope: internal linkage, used only by func. | |
| @lds_func_priv = internal addrspace(3) global [32 x float] poison, align 4 | |
| ; Kernel-scope: internal linkage, used only by my_kernel. | |
| @lds_kernel_priv = internal addrspace(3) global [16 x i64] poison, align 8 | |
| declare void @extern_func() | |
| ; Global-scope: remains as external declaration. | |
| ; CHECK-DAG: @lds_global = external addrspace(3) global [64 x i32] | |
| ; Callee-scope: wrapped into per-function struct. | |
| ; CHECK-DAG: @__amdgpu_lds.func = external {{(dso_local )?}}addrspace(3) global %__amdgpu_lds.func.t | |
| ; Kernel-scope: wrapped into per-kernel struct. | |
| ; CHECK-DAG: @__amdgpu_lds.my_kernel = external {{(dso_local )?}}addrspace(3) global %__amdgpu_lds.my_kernel.t | |
| ; Original internal-linkage variables should be removed. | |
| ; CHECK-NOT: @lds_func_priv | |
| ; CHECK-NOT: @lds_kernel_priv | |
| ; func: uses lds_global directly, uses lds_func_priv via struct GEP. | |
| ; CHECK-LABEL: define void @func() | |
| ; CHECK: getelementptr {{.*}} ptr addrspace(3) @lds_global | |
| ; CHECK: getelementptr {{.*}} ptr addrspace(3) @__amdgpu_lds.func | |
| ; my_kernel: uses lds_global directly, uses lds_kernel_priv via struct GEP. | |
| ; CHECK-LABEL: define amdgpu_kernel void @my_kernel() | |
| ; CHECK: getelementptr {{.*}} ptr addrspace(3) @lds_global | |
| ; CHECK: getelementptr {{.*}} ptr addrspace(3) @__amdgpu_lds.my_kernel | |
| ; Metadata: | |
| ; CHECK: !amdgpu.lds.uses = !{{{![0-9]+, ![0-9]+, ![0-9]+, ![0-9]+}}} | |
| ; Function-scope entries (one per struct). | |
| ; CHECK-DAG: !{ptr @my_kernel, ptr addrspace(3) @__amdgpu_lds.my_kernel} | |
| ; CHECK-DAG: !{ptr @func, ptr addrspace(3) @__amdgpu_lds.func} | |
| ; Global-scope entries (one per using function). | |
| ; CHECK-DAG: !{ptr @my_kernel, ptr addrspace(3) @lds_global} | |
| ; CHECK-DAG: !{ptr @func, ptr addrspace(3) @lds_global} | |
| define void @func() { | |
| %gep1 = getelementptr [64 x i32], ptr addrspace(3) @lds_global, i32 0, i32 0 | |
| store i32 1, ptr addrspace(3) %gep1 | |
| %gep2 = getelementptr [32 x float], ptr addrspace(3) @lds_func_priv, i32 0, i32 0 | |
| store float 2.0, ptr addrspace(3) %gep2 | |
| call void @extern_func() | |
| ret void | |
| } | |
| define amdgpu_kernel void @my_kernel() { | |
| %gep1 = getelementptr [64 x i32], ptr addrspace(3) @lds_global, i32 0, i32 0 | |
| store i32 3, ptr addrspace(3) %gep1 | |
| %gep2 = getelementptr [16 x i64], ptr addrspace(3) @lds_kernel_priv, i32 0, i32 0 | |
| store i64 4, ptr addrspace(3) %gep2 | |
| call void @func() | |
| ret void | |
| } |