[clang] [llvm] Explicit types in cbuffer layouts (PR #156919)
Justin Bogner via llvm-commits
llvm-commits at lists.llvm.org
Tue Sep 9 19:07:10 PDT 2025
https://github.com/bogner updated https://github.com/llvm/llvm-project/pull/156919
>From 63ed3bcf4c597a9840b6f94767f8fe19b783f3be Mon Sep 17 00:00:00 2001
From: Justin Bogner <mail at justinbogner.com>
Date: Tue, 19 Aug 2025 13:46:38 -0600
Subject: [PATCH 01/11] [DirectX] Make a test a bit more readable
CHECK-lines ignore whitespace, so we can remove some here and make this
a bit easier to read.
---
llvm/test/CodeGen/DirectX/Metadata/cbuffer_metadata.ll | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/llvm/test/CodeGen/DirectX/Metadata/cbuffer_metadata.ll b/llvm/test/CodeGen/DirectX/Metadata/cbuffer_metadata.ll
index 7ba2ed2988312..f1d28e28dafdc 100644
--- a/llvm/test/CodeGen/DirectX/Metadata/cbuffer_metadata.ll
+++ b/llvm/test/CodeGen/DirectX/Metadata/cbuffer_metadata.ll
@@ -19,11 +19,11 @@ target triple = "dxil-pc-shadermodel6.6-compute"
; PRINT:; Resource Bindings:
; PRINT-NEXT:;
-; PRINT-NEXT:; Name Type Format Dim ID HLSL Bind Count
-; PRINT-NEXT:; ------------------------------ ---------- ------- ----------- ------- -------------- ------
-; PRINT-NEXT:; CB1 cbuffer NA NA CB0 cb0 1
-; PRINT-NEXT:; CB2 cbuffer NA NA CB1 cb1 1
-; PRINT-NEXT:; MyConstants cbuffer NA NA CB2 cb5,space15 1
+; PRINT-NEXT:; Name Type Format Dim ID HLSL Bind Count
+; PRINT-NEXT:; ----
+; PRINT-NEXT:; CB1 cbuffer NA NA CB0 cb0 1
+; PRINT-NEXT:; CB2 cbuffer NA NA CB1 cb1 1
+; PRINT-NEXT:; MyConstants cbuffer NA NA CB2 cb5,space15 1
define void @test() #0 {
>From f26c44a1800c8585578a3484b21071e84b46f153 Mon Sep 17 00:00:00 2001
From: Justin Bogner <mail at justinbogner.com>
Date: Wed, 11 Jun 2025 16:21:41 -0400
Subject: [PATCH 02/11] wip: Update HLSL/CBuffer.h to padding approach
This mostly just works. A couple of notes:
1. We should use explicit padding
2. A couple of the tests have hacks to deal with vector alignment
3. More complicated GEPs probably don't have coverage
---
llvm/lib/Frontend/HLSL/CBuffer.cpp | 32 ++-
llvm/lib/Target/DirectX/DXILCBufferAccess.cpp | 4 -
.../DirectX/CBufferAccess/array-typedgep.ll | 16 +-
.../CodeGen/DirectX/CBufferAccess/arrays.ll | 97 ++++----
.../CodeGen/DirectX/CBufferAccess/float.ll | 6 +-
.../DirectX/CBufferAccess/gep-ce-two-uses.ll | 18 +-
.../CodeGen/DirectX/CBufferAccess/memcpy.ll | 226 ++++--------------
.../CodeGen/DirectX/CBufferAccess/scalars.ll | 34 +--
.../CodeGen/DirectX/CBufferAccess/vectors.ll | 40 ++--
9 files changed, 176 insertions(+), 297 deletions(-)
diff --git a/llvm/lib/Frontend/HLSL/CBuffer.cpp b/llvm/lib/Frontend/HLSL/CBuffer.cpp
index 37c0d912e09ee..b8ecd03d5ddf3 100644
--- a/llvm/lib/Frontend/HLSL/CBuffer.cpp
+++ b/llvm/lib/Frontend/HLSL/CBuffer.cpp
@@ -15,20 +15,29 @@
using namespace llvm;
using namespace llvm::hlsl;
-static size_t getMemberOffset(GlobalVariable *Handle, size_t Index) {
+static bool isPadding(Type *Ty) {
+ // TODO: We should use an explicit padding type rather than array of i8
+ if (const auto *ATy = dyn_cast<ArrayType>(Ty))
+ if (const auto *ITy = dyn_cast<IntegerType>(ATy->getElementType()))
+ return ITy->getBitWidth() == 8;
+ return false;
+}
+
+static SmallVector<size_t> getMemberOffsets(const DataLayout &DL,
+ GlobalVariable *Handle) {
+ SmallVector<size_t> Offsets;
+
auto *HandleTy = cast<TargetExtType>(Handle->getValueType());
assert(HandleTy->getName().ends_with(".CBuffer") && "Not a cbuffer type");
assert(HandleTy->getNumTypeParameters() == 1 && "Expected layout type");
+ auto *LayoutTy = cast<StructType>(HandleTy->getTypeParameter(0));
- auto *LayoutTy = cast<TargetExtType>(HandleTy->getTypeParameter(0));
- assert(LayoutTy->getName().ends_with(".Layout") && "Not a layout type");
+ const StructLayout *SL = DL.getStructLayout(LayoutTy);
+ for (int I = 0, E = LayoutTy->getNumElements(); I < E; ++I)
+ if (!isPadding(LayoutTy->getElementType(I)))
+ Offsets.push_back(SL->getElementOffset(I));
- // Skip the "size" parameter.
- size_t ParamIndex = Index + 1;
- assert(LayoutTy->getNumIntParameters() > ParamIndex &&
- "Not enough parameters");
-
- return LayoutTy->getIntParameter(ParamIndex);
+ return Offsets;
}
std::optional<CBufferMetadata> CBufferMetadata::get(Module &M) {
@@ -45,13 +54,16 @@ std::optional<CBufferMetadata> CBufferMetadata::get(Module &M) {
cast<ValueAsMetadata>(MD->getOperand(0))->getValue());
CBufferMapping &Mapping = Result->Mappings.emplace_back(Handle);
+ SmallVector<size_t> MemberOffsets =
+ getMemberOffsets(M.getDataLayout(), Handle);
+
for (int I = 1, E = MD->getNumOperands(); I < E; ++I) {
Metadata *OpMD = MD->getOperand(I);
// Some members may be null if they've been optimized out.
if (!OpMD)
continue;
auto *V = cast<GlobalVariable>(cast<ValueAsMetadata>(OpMD)->getValue());
- Mapping.Members.emplace_back(V, getMemberOffset(Handle, I - 1));
+ Mapping.Members.emplace_back(V, MemberOffsets[I - 1]);
}
}
diff --git a/llvm/lib/Target/DirectX/DXILCBufferAccess.cpp b/llvm/lib/Target/DirectX/DXILCBufferAccess.cpp
index 44277971acd60..c36efb3034c12 100644
--- a/llvm/lib/Target/DirectX/DXILCBufferAccess.cpp
+++ b/llvm/lib/Target/DirectX/DXILCBufferAccess.cpp
@@ -97,10 +97,6 @@ struct CBufferResource {
(void)Success;
assert(Success && "Offsets into cbuffer globals must be constant");
- if (auto *ATy = dyn_cast<ArrayType>(Member->getValueType()))
- ConstantOffset =
- hlsl::translateCBufArrayOffset(DL, ConstantOffset, ATy);
-
return ConstantOffset.getZExtValue();
}
diff --git a/llvm/test/CodeGen/DirectX/CBufferAccess/array-typedgep.ll b/llvm/test/CodeGen/DirectX/CBufferAccess/array-typedgep.ll
index 52ad0f3df1aba..10ea19df1d177 100644
--- a/llvm/test/CodeGen/DirectX/CBufferAccess/array-typedgep.ll
+++ b/llvm/test/CodeGen/DirectX/CBufferAccess/array-typedgep.ll
@@ -3,24 +3,24 @@
; cbuffer CB : register(b0) {
; float a1[3];
; }
-%__cblayout_CB = type <{ [3 x float] }>
+%__cblayout_CB = type <{ [2 x <{ float, [12 x i8] }>], float }>
- at CB.cb = global target("dx.CBuffer", target("dx.Layout", %__cblayout_CB, 36, 0)) poison
+ at CB.cb = global target("dx.CBuffer", %__cblayout_CB) poison
; CHECK: @CB.cb =
; CHECK-NOT: external {{.*}} addrspace(2) global
- at a1 = external addrspace(2) global [3 x float], align 4
+ at a1 = external addrspace(2) global <{ [2 x <{ float, [12 x i8] }>], float }>, align 4
; CHECK: define void @f
define void @f(ptr %dst) {
entry:
- %CB.cb_h = call target("dx.CBuffer", target("dx.Layout", %__cblayout_CB, 36, 0)) @llvm.dx.resource.handlefrombinding.tdx.CBuffer_tdx.Layout_s___cblayout_CBs_36_0tt(i32 0, i32 0, i32 1, i32 0, ptr null)
- store target("dx.CBuffer", target("dx.Layout", %__cblayout_CB, 36, 0)) %CB.cb_h, ptr @CB.cb, align 4
+ %CB.cb_h = call target("dx.CBuffer", %__cblayout_CB) @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, ptr null)
+ store target("dx.CBuffer", %__cblayout_CB) %CB.cb_h, ptr @CB.cb, align 4
- ; CHECK: [[CB:%.*]] = load target("dx.CBuffer", {{.*}})), ptr @CB.cb
- ; CHECK: [[LOAD:%.*]] = call { float, float, float, float } @llvm.dx.resource.load.cbufferrow.4.{{.*}}(target("dx.CBuffer", {{.*}})) [[CB]], i32 1)
+ ; CHECK: [[CB:%.*]] = load target("dx.CBuffer", %__cblayout_CB), ptr @CB.cb
+ ; CHECK: [[LOAD:%.*]] = call { float, float, float, float } @llvm.dx.resource.load.cbufferrow.4.{{.*}}(target("dx.CBuffer", %__cblayout_CB) [[CB]], i32 1)
; CHECK: [[X:%.*]] = extractvalue { float, float, float, float } [[LOAD]], 0
; CHECK: store float [[X]], ptr %dst
- %a1 = load float, ptr addrspace(2) getelementptr inbounds ([3 x float], ptr addrspace(2) @a1, i32 0, i32 1), align 4
+ %a1 = load float, ptr addrspace(2) getelementptr inbounds (<{ [2 x <{ float, [12 x i8] }>], float }>, ptr addrspace(2) @a1, i32 0, i32 0, i32 1), align 4
store float %a1, ptr %dst, align 32
ret void
diff --git a/llvm/test/CodeGen/DirectX/CBufferAccess/arrays.ll b/llvm/test/CodeGen/DirectX/CBufferAccess/arrays.ll
index db4e14c1336a6..1bdb27d736783 100644
--- a/llvm/test/CodeGen/DirectX/CBufferAccess/arrays.ll
+++ b/llvm/test/CodeGen/DirectX/CBufferAccess/arrays.ll
@@ -1,47 +1,60 @@
; RUN: opt -S -dxil-cbuffer-access -mtriple=dxil--shadermodel6.3-library %s | FileCheck %s
+; TODO: Remove datalayout.
+; This hack forces dxil-compatible alignment of 3-element 32- and 64-bit vectors
+target datalayout = "e-m:e-p:32:32-i1:32-i8:8-i16:16-i32:32-i64:64-f16:16-f32:32-f64:64-n8:16:32:64-v96:32:32-v192:64:64"
+
; cbuffer CB : register(b0) {
-; float a1[3];
-; double3 a2[2];
-; float16_t a3[2][2];
-; uint64_t a4[3];
-; int4 a5[2][3][4];
-; uint16_t a6[1];
-; int64_t a7[2];
-; bool a8[4];
+; float a1[3]; // offset 0, size 4 (+12) * 3
+; double3 a2[2]; // offset 48, size 24 (+8) * 2
+; float16_t a3[2][2]; // offset 112, size 2 (+14) * 4
+; uint64_t a4[3]; // offset 176, size 8 (+8) * 3
+; int4 a5[2][3][4]; // offset 224, size 16 * 24
+; uint16_t a6[1]; // offset 608, size 2 (+14) * 1
+; int64_t a7[2]; // offset 624, size 8 (+8) * 2
+; bool a8[4]; // offset 656, size 4 (+12) * 4
; }
-%__cblayout_CB = type <{ [3 x float], [2 x <3 x double>], [2 x [2 x half]], [3 x i64], [2 x [3 x [4 x <4 x i32>]]], [1 x i16], [2 x i64], [4 x i32] }>
+%__cblayout_CB = type <{
+ <{ [2 x <{ float, [12 x i8] }>], float }>, [12 x i8],
+ <{ [1 x <{ <3 x double>, [8 x i8] }>], <3 x double> }>, [8 x i8],
+ <{ [3 x <{ half, [14 x i8] }>], half }>, [14 x i8],
+ <{ [2 x <{ i64, [8 x i8] }>], i64 }>, [8 x i8],
+ [24 x <4 x i32>],
+ [1 x i16], [14 x i8],
+ <{ [1 x <{ i64, [8 x i8] }>], i64 }>, [8 x i8],
+ <{ [3 x <{ i32, [12 x i8] }>], i32 }>
+}>
- at CB.cb = local_unnamed_addr global target("dx.CBuffer", target("dx.Layout", %__cblayout_CB, 708, 0, 48, 112, 176, 224, 608, 624, 656)) poison
+ at CB.cb = local_unnamed_addr global target("dx.CBuffer", %__cblayout_CB) poison
; CHECK: @CB.cb =
; CHECK-NOT: external {{.*}} addrspace(2) global
- at a1 = external local_unnamed_addr addrspace(2) global [3 x float], align 4
- at a2 = external local_unnamed_addr addrspace(2) global [2 x <3 x double>], align 32
- at a3 = external local_unnamed_addr addrspace(2) global [2 x [2 x half]], align 2
- at a4 = external local_unnamed_addr addrspace(2) global [3 x i64], align 8
- at a5 = external local_unnamed_addr addrspace(2) global [2 x [3 x [4 x <4 x i32>]]], align 16
+ at a1 = external local_unnamed_addr addrspace(2) global <{ [2 x <{ float, [12 x i8] }>], float }>, align 4
+ at a2 = external local_unnamed_addr addrspace(2) global <{ [1 x <{ <3 x double>, [8 x i8] }>], <3 x double> }>, align 32
+ at a3 = external local_unnamed_addr addrspace(2) global <{ [3 x <{ half, [14 x i8] }>], half }>, align 2
+ at a4 = external local_unnamed_addr addrspace(2) global <{ [2 x <{ i64, [8 x i8] }>], i64 }>, align 8
+ at a5 = external local_unnamed_addr addrspace(2) global [24 x <4 x i32>], align 16
@a6 = external local_unnamed_addr addrspace(2) global [1 x i16], align 2
- at a7 = external local_unnamed_addr addrspace(2) global [2 x i64], align 8
- at a8 = external local_unnamed_addr addrspace(2) global [4 x i32], align 4
+ at a7 = external local_unnamed_addr addrspace(2) global <{ [1 x <{ i64, [8 x i8] }>], i64 }>, align 8
+ at a8 = external local_unnamed_addr addrspace(2) global <{ [3 x <{ i32, [12 x i8] }>], i32 }>, align 4
; CHECK: define void @f
define void @f(ptr %dst) {
entry:
- %CB.cb_h.i.i = tail call target("dx.CBuffer", target("dx.Layout", %__cblayout_CB, 708, 0, 48, 112, 176, 224, 608, 624, 656)) @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, ptr null)
- store target("dx.CBuffer", target("dx.Layout", %__cblayout_CB, 708, 0, 48, 112, 176, 224, 608, 624, 656)) %CB.cb_h.i.i, ptr @CB.cb, align 4
+ %CB.cb_h.i.i = tail call target("dx.CBuffer", %__cblayout_CB) @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, ptr null)
+ store target("dx.CBuffer", %__cblayout_CB) %CB.cb_h.i.i, ptr @CB.cb, align 4
- ; CHECK: [[CB:%.*]] = load target("dx.CBuffer", {{.*}})), ptr @CB.cb
- ; CHECK: [[LOAD:%.*]] = call { float, float, float, float } @llvm.dx.resource.load.cbufferrow.4.{{.*}}(target("dx.CBuffer", {{.*}})) [[CB]], i32 1)
+ ; CHECK: [[CB:%.*]] = load target("dx.CBuffer", %__cblayout_CB), ptr @CB.cb
+ ; CHECK: [[LOAD:%.*]] = call { float, float, float, float } @llvm.dx.resource.load.cbufferrow.4.{{.*}}(target("dx.CBuffer", %__cblayout_CB) [[CB]], i32 1)
; CHECK: [[X:%.*]] = extractvalue { float, float, float, float } [[LOAD]], 0
; CHECK: store float [[X]], ptr %dst
- %a1 = load float, ptr addrspace(2) getelementptr inbounds nuw (i8, ptr addrspace(2) @a1, i32 4), align 4
+ %a1 = load float, ptr addrspace(2) getelementptr inbounds nuw (i8, ptr addrspace(2) @a1, i32 16), align 4
store float %a1, ptr %dst, align 32
- ; CHECK: [[CB:%.*]] = load target("dx.CBuffer", {{.*}})), ptr @CB.cb
- ; CHECK: [[LOAD:%.*]] = call { double, double } @llvm.dx.resource.load.cbufferrow.2.{{.*}}(target("dx.CBuffer", {{.*}})) [[CB]], i32 5)
+ ; CHECK: [[CB:%.*]] = load target("dx.CBuffer", %__cblayout_CB), ptr @CB.cb
+ ; CHECK: [[LOAD:%.*]] = call { double, double } @llvm.dx.resource.load.cbufferrow.2.{{.*}}(target("dx.CBuffer", %__cblayout_CB) [[CB]], i32 5)
; CHECK: [[X:%.*]] = extractvalue { double, double } [[LOAD]], 0
; CHECK: [[Y:%.*]] = extractvalue { double, double } [[LOAD]], 1
- ; CHECK: [[LOAD:%.*]] = call { double, double } @llvm.dx.resource.load.cbufferrow.2.{{.*}}(target("dx.CBuffer", {{.*}})) [[CB]], i32 6)
+ ; CHECK: [[LOAD:%.*]] = call { double, double } @llvm.dx.resource.load.cbufferrow.2.{{.*}}(target("dx.CBuffer", %__cblayout_CB) [[CB]], i32 6)
; CHECK: [[Z:%.*]] = extractvalue { double, double } [[LOAD]], 0
; CHECK: [[VEC0:%.*]] = insertelement <3 x double> poison, double [[X]], i32 0
; CHECK: [[VEC1:%.*]] = insertelement <3 x double> [[VEC0]], double [[Y]], i32 1
@@ -52,26 +65,26 @@ entry:
%a2.i = getelementptr inbounds nuw i8, ptr %dst, i32 8
store <3 x double> %a2, ptr %a2.i, align 32
- ; CHECK: [[CB:%.*]] = load target("dx.CBuffer", {{.*}})), ptr @CB.cb
- ; CHECK: [[LOAD:%.*]] = call { half, half, half, half, half, half, half, half } @llvm.dx.resource.load.cbufferrow.8.{{.*}}(target("dx.CBuffer", {{.*}})) [[CB]], i32 8)
+ ; CHECK: [[CB:%.*]] = load target("dx.CBuffer", %__cblayout_CB), ptr @CB.cb
+ ; CHECK: [[LOAD:%.*]] = call { half, half, half, half, half, half, half, half } @llvm.dx.resource.load.cbufferrow.8.{{.*}}(target("dx.CBuffer", %__cblayout_CB) [[CB]], i32 8)
; CHECK: [[X:%.*]] = extractvalue { half, half, half, half, half, half, half, half } [[LOAD]], 0
; CHECK: [[PTR:%.*]] = getelementptr inbounds nuw i8, ptr %dst, i32 32
; CHECK: store half [[X]], ptr [[PTR]]
- %a3 = load half, ptr addrspace(2) getelementptr inbounds nuw (i8, ptr addrspace(2) @a3, i32 6), align 2
+ %a3 = load half, ptr addrspace(2) getelementptr inbounds nuw (i8, ptr addrspace(2) @a3, i32 16), align 2
%a3.i = getelementptr inbounds nuw i8, ptr %dst, i32 32
store half %a3, ptr %a3.i, align 2
- ; CHECK: [[CB:%.*]] = load target("dx.CBuffer", {{.*}})), ptr @CB.cb
- ; CHECK: [[LOAD:%.*]] = call { i64, i64 } @llvm.dx.resource.load.cbufferrow.2.{{.*}}(target("dx.CBuffer", {{.*}})) [[CB]], i32 12)
+ ; CHECK: [[CB:%.*]] = load target("dx.CBuffer", %__cblayout_CB), ptr @CB.cb
+ ; CHECK: [[LOAD:%.*]] = call { i64, i64 } @llvm.dx.resource.load.cbufferrow.2.{{.*}}(target("dx.CBuffer", %__cblayout_CB) [[CB]], i32 12)
; CHECK: [[X:%.*]] = extractvalue { i64, i64 } [[LOAD]], 0
; CHECK: [[PTR:%.*]] = getelementptr inbounds nuw i8, ptr %dst, i32 40
; CHECK: store i64 [[X]], ptr [[PTR]]
- %a4 = load i64, ptr addrspace(2) getelementptr inbounds nuw (i8, ptr addrspace(2) @a4, i32 8), align 8
+ %a4 = load i64, ptr addrspace(2) getelementptr inbounds nuw (i8, ptr addrspace(2) @a4, i32 16), align 8
%a4.i = getelementptr inbounds nuw i8, ptr %dst, i32 40
store i64 %a4, ptr %a4.i, align 8
- ; CHECK: [[CB:%.*]] = load target("dx.CBuffer", {{.*}})), ptr @CB.cb
- ; CHECK: [[LOAD:%.*]] = call { i32, i32, i32, i32 } @llvm.dx.resource.load.cbufferrow.4.{{.*}}(target("dx.CBuffer", {{.*}})) [[CB]], i32 26)
+ ; CHECK: [[CB:%.*]] = load target("dx.CBuffer", %__cblayout_CB), ptr @CB.cb
+ ; CHECK: [[LOAD:%.*]] = call { i32, i32, i32, i32 } @llvm.dx.resource.load.cbufferrow.4.{{.*}}(target("dx.CBuffer", %__cblayout_CB) [[CB]], i32 26)
; CHECK: [[X:%.*]] = extractvalue { i32, i32, i32, i32 } [[LOAD]], 0
; CHECK: [[Y:%.*]] = extractvalue { i32, i32, i32, i32 } [[LOAD]], 1
; CHECK: [[Z:%.*]] = extractvalue { i32, i32, i32, i32 } [[LOAD]], 2
@@ -82,12 +95,12 @@ entry:
; CHECK: [[VEC3:%.*]] = insertelement <4 x i32> [[VEC2]], i32 [[A]], i32 3
; CHECK: [[PTR:%.*]] = getelementptr inbounds nuw i8, ptr %dst, i32 48
; CHECK: store <4 x i32> [[VEC3]], ptr [[PTR]]
- %a5 = load <4 x i32>, ptr addrspace(2) getelementptr inbounds nuw (i8, ptr addrspace(2) @a5, i32 272), align 4
+ %a5 = load <4 x i32>, ptr addrspace(2) getelementptr inbounds nuw (i8, ptr addrspace(2) @a5, i32 192), align 4
%a5.i = getelementptr inbounds nuw i8, ptr %dst, i32 48
store <4 x i32> %a5, ptr %a5.i, align 4
- ; CHECK: [[CB:%.*]] = load target("dx.CBuffer", {{.*}})), ptr @CB.cb
- ; CHECK: [[LOAD:%.*]] = call { i16, i16, i16, i16, i16, i16, i16, i16 } @llvm.dx.resource.load.cbufferrow.8.{{.*}}(target("dx.CBuffer", {{.*}})) [[CB]], i32 38)
+ ; CHECK: [[CB:%.*]] = load target("dx.CBuffer", %__cblayout_CB), ptr @CB.cb
+ ; CHECK: [[LOAD:%.*]] = call { i16, i16, i16, i16, i16, i16, i16, i16 } @llvm.dx.resource.load.cbufferrow.8.{{.*}}(target("dx.CBuffer", %__cblayout_CB) [[CB]], i32 38)
; CHECK: [[X:%.*]] = extractvalue { i16, i16, i16, i16, i16, i16, i16, i16 } [[LOAD]], 0
; CHECK: [[PTR:%.*]] = getelementptr inbounds nuw i8, ptr %dst, i32 64
; CHECK: store i16 [[X]], ptr [[PTR]]
@@ -95,21 +108,21 @@ entry:
%a6.i = getelementptr inbounds nuw i8, ptr %dst, i32 64
store i16 %a6, ptr %a6.i, align 2
- ; CHECK: [[CB:%.*]] = load target("dx.CBuffer", {{.*}})), ptr @CB.cb
- ; CHECK: [[LOAD:%.*]] = call { i64, i64 } @llvm.dx.resource.load.cbufferrow.2.{{.*}}(target("dx.CBuffer", {{.*}})) [[CB]], i32 40)
+ ; CHECK: [[CB:%.*]] = load target("dx.CBuffer", %__cblayout_CB), ptr @CB.cb
+ ; CHECK: [[LOAD:%.*]] = call { i64, i64 } @llvm.dx.resource.load.cbufferrow.2.{{.*}}(target("dx.CBuffer", %__cblayout_CB) [[CB]], i32 40)
; CHECK: [[X:%.*]] = extractvalue { i64, i64 } [[LOAD]], 0
; CHECK: [[PTR:%.*]] = getelementptr inbounds nuw i8, ptr %dst, i32 72
; CHECK: store i64 [[X]], ptr [[PTR]]
- %a7 = load i64, ptr addrspace(2) getelementptr inbounds nuw (i8, ptr addrspace(2) @a7, i32 8), align 8
+ %a7 = load i64, ptr addrspace(2) getelementptr inbounds nuw (i8, ptr addrspace(2) @a7, i32 16), align 8
%a7.i = getelementptr inbounds nuw i8, ptr %dst, i32 72
store i64 %a7, ptr %a7.i, align 8
- ; CHECK: [[CB:%.*]] = load target("dx.CBuffer", {{.*}})), ptr @CB.cb
- ; CHECK: [[LOAD:%.*]] = call { i32, i32, i32, i32 } @llvm.dx.resource.load.cbufferrow.4.{{.*}}(target("dx.CBuffer", {{.*}})) [[CB]], i32 42)
+ ; CHECK: [[CB:%.*]] = load target("dx.CBuffer", %__cblayout_CB), ptr @CB.cb
+ ; CHECK: [[LOAD:%.*]] = call { i32, i32, i32, i32 } @llvm.dx.resource.load.cbufferrow.4.{{.*}}(target("dx.CBuffer", %__cblayout_CB) [[CB]], i32 42)
; CHECK: [[X:%.*]] = extractvalue { i32, i32, i32, i32 } [[LOAD]], 0
; CHECK: [[PTR:%.*]] = getelementptr inbounds nuw i8, ptr %dst, i32 80
; CHECK: store i32 [[X]], ptr [[PTR]]
- %a8 = load i32, ptr addrspace(2) getelementptr inbounds nuw (i8, ptr addrspace(2) @a8, i32 4), align 4, !range !1, !noundef !2
+ %a8 = load i32, ptr addrspace(2) getelementptr inbounds nuw (i8, ptr addrspace(2) @a8, i32 16), align 4, !range !1, !noundef !2
%a8.i = getelementptr inbounds nuw i8, ptr %dst, i32 80
store i32 %a8, ptr %a8.i, align 4
diff --git a/llvm/test/CodeGen/DirectX/CBufferAccess/float.ll b/llvm/test/CodeGen/DirectX/CBufferAccess/float.ll
index d7272b449166d..6f45fb6ae2e24 100644
--- a/llvm/test/CodeGen/DirectX/CBufferAccess/float.ll
+++ b/llvm/test/CodeGen/DirectX/CBufferAccess/float.ll
@@ -2,7 +2,7 @@
%__cblayout_CB = type <{ float }>
- at CB.cb = local_unnamed_addr global target("dx.CBuffer", target("dx.Layout", %__cblayout_CB, 4, 0)) poison
+ at CB.cb = local_unnamed_addr global target("dx.CBuffer", %__cblayout_CB) poison
; CHECK: @CB.cb =
; CHECK-NOT: external {{.*}} addrspace(2) global
@x = external local_unnamed_addr addrspace(2) global float, align 4
@@ -10,8 +10,8 @@
; CHECK: define void @f
define void @f(ptr %dst) {
entry:
- ; CHECK: [[CB:%.*]] = load target("dx.CBuffer", {{.*}})), ptr @CB.cb
- ; CHECK: [[LOAD:%.*]] = call { float, float, float, float } @llvm.dx.resource.load.cbufferrow.4.{{.*}}(target("dx.CBuffer", {{.*}})) [[CB]], i32 0)
+ ; CHECK: [[CB:%.*]] = load target("dx.CBuffer", %__cblayout_CB), ptr @CB.cb
+ ; CHECK: [[LOAD:%.*]] = call { float, float, float, float } @llvm.dx.resource.load.cbufferrow.4.{{.*}}(target("dx.CBuffer", %__cblayout_CB) [[CB]], i32 0)
; CHECK: [[X:%.*]] = extractvalue { float, float, float, float } [[LOAD]], 0
; CHECK: store float [[X]], ptr %dst
%x = load float, ptr addrspace(2) @x, align 4
diff --git a/llvm/test/CodeGen/DirectX/CBufferAccess/gep-ce-two-uses.ll b/llvm/test/CodeGen/DirectX/CBufferAccess/gep-ce-two-uses.ll
index abe087dbe6100..21724d32f10d0 100644
--- a/llvm/test/CodeGen/DirectX/CBufferAccess/gep-ce-two-uses.ll
+++ b/llvm/test/CodeGen/DirectX/CBufferAccess/gep-ce-two-uses.ll
@@ -3,28 +3,28 @@
; cbuffer CB : register(b0) {
; float a1[3];
; }
-%__cblayout_CB = type <{ [3 x float] }>
+%__cblayout_CB = type <{ [2 x <{ float, [12 x i8] }>], float }>
- at CB.cb = local_unnamed_addr global target("dx.CBuffer", target("dx.Layout", %__cblayout_CB, 36, 0)) poison
+ at CB.cb = local_unnamed_addr global target("dx.CBuffer", %__cblayout_CB) poison
; CHECK: @CB.cb =
; CHECK-NOT: external {{.*}} addrspace(2) global
- at a1 = external local_unnamed_addr addrspace(2) global [3 x float], align 4
+ at a1 = external addrspace(2) global <{ [2 x <{ float, [12 x i8] }>], float }>, align 4
; CHECK: define void @f
define void @f(ptr %dst) {
entry:
- ; CHECK: [[CB:%.*]] = load target("dx.CBuffer", {{.*}})), ptr @CB.cb
- ; CHECK: [[LOAD:%.*]] = call { float, float, float, float } @llvm.dx.resource.load.cbufferrow.4.{{.*}}(target("dx.CBuffer", {{.*}})) [[CB]], i32 1)
+ ; CHECK: [[CB:%.*]] = load target("dx.CBuffer", %__cblayout_CB), ptr @CB.cb
+ ; CHECK: [[LOAD:%.*]] = call { float, float, float, float } @llvm.dx.resource.load.cbufferrow.4.{{.*}}(target("dx.CBuffer", %__cblayout_CB) [[CB]], i32 1)
; CHECK: [[X:%.*]] = extractvalue { float, float, float, float } [[LOAD]], 0
; CHECK: store float [[X]], ptr %dst
- %a1 = load float, ptr addrspace(2) getelementptr inbounds nuw (i8, ptr addrspace(2) @a1, i32 4), align 4
+ %a1 = load float, ptr addrspace(2) getelementptr inbounds nuw (i8, ptr addrspace(2) @a1, i32 16), align 4
store float %a1, ptr %dst, align 32
- ; CHECK: [[CB:%.*]] = load target("dx.CBuffer", {{.*}})), ptr @CB.cb
- ; CHECK: [[LOAD:%.*]] = call { float, float, float, float } @llvm.dx.resource.load.cbufferrow.4.{{.*}}(target("dx.CBuffer", {{.*}})) [[CB]], i32 1)
+ ; CHECK: [[CB:%.*]] = load target("dx.CBuffer", %__cblayout_CB), ptr @CB.cb
+ ; CHECK: [[LOAD:%.*]] = call { float, float, float, float } @llvm.dx.resource.load.cbufferrow.4.{{.*}}(target("dx.CBuffer", %__cblayout_CB) [[CB]], i32 1)
; CHECK: [[X:%.*]] = extractvalue { float, float, float, float } [[LOAD]], 0
; CHECK: store float [[X]], ptr %dst
- %a2 = load float, ptr addrspace(2) getelementptr inbounds nuw (i8, ptr addrspace(2) @a1, i32 4), align 4
+ %a2 = load float, ptr addrspace(2) getelementptr inbounds nuw (i8, ptr addrspace(2) @a1, i32 16), align 4
store float %a2, ptr %dst, align 32
ret void
diff --git a/llvm/test/CodeGen/DirectX/CBufferAccess/memcpy.ll b/llvm/test/CodeGen/DirectX/CBufferAccess/memcpy.ll
index a78fdd5037f93..eacad84f7e11d 100644
--- a/llvm/test/CodeGen/DirectX/CBufferAccess/memcpy.ll
+++ b/llvm/test/CodeGen/DirectX/CBufferAccess/memcpy.ll
@@ -1,216 +1,70 @@
; RUN: opt -S -dxil-cbuffer-access -mtriple=dxil--shadermodel6.3-library %s | FileCheck %s
-; cbuffer CB : register(b0) {
-; float a1[3];
-; double3 a2[2];
-; float16_t a3[2][2];
-; uint64_t a4[3];
-; int2 a5[3][2];
-; uint16_t a6[1];
-; int64_t a7[2];
-; bool a8[4];
-; }
-%__cblayout_CB = type <{ [3 x float], [2 x <3 x double>], [2 x [2 x half]], [3 x i64], [3 x [2 x <2 x i32>]], [1 x i16], [2 x i64], [4 x i32] }>
+; TODO: Remove datalayout.
+; This hack forces dxil-compatible alignment of 3-element 32- and 64-bit vectors
+target datalayout = "e-m:e-p:32:32-i1:32-i8:8-i16:16-i32:32-i64:64-f16:16-f32:32-f64:64-n8:16:32:64-v96:32:32-v192:64:64"
- at CB.cb = local_unnamed_addr global target("dx.CBuffer", target("dx.Layout", %__cblayout_CB, 708, 0, 48, 112, 176, 224, 272, 288, 320)) poison
- at a1 = external local_unnamed_addr addrspace(2) global [3 x float], align 4
- at a2 = external local_unnamed_addr addrspace(2) global [2 x <3 x double>], align 32
- at a3 = external local_unnamed_addr addrspace(2) global [2 x [2 x half]], align 2
- at a4 = external local_unnamed_addr addrspace(2) global [3 x i64], align 8
- at a5 = external local_unnamed_addr addrspace(2) global [3 x [2 x <2 x i32>]], align 16
- at a6 = external local_unnamed_addr addrspace(2) global [1 x i16], align 2
- at a7 = external local_unnamed_addr addrspace(2) global [2 x i64], align 8
- at a8 = external local_unnamed_addr addrspace(2) global [4 x i32], align 4
+; cbuffer CB : register(b0) {
+; float4 a1[4]; // offset 0, size 16 * 4
+; float a2[2]; // offset 64, size 4 (+12) * 2
+; double2 a3[2]; // offset 96, size 16 * 2
+%__cblayout_CB = type <{
+ [ 4 x <4 x float> ],
+ <{ [2 x <{ float, [12 x i8] }>], float }>, [12 x i8],
+ [ 2 x <2 x double> ]
+}>
+
+ at CB.cb = local_unnamed_addr global target("dx.CBuffer", %__cblayout_CB) poison
+ at a1 = external local_unnamed_addr addrspace(2) global [ 4 x <4 x float> ], align 4
+ at a2 = external local_unnamed_addr addrspace(2) global <{ [2 x <{ float, [12 x i8] }>], float }>, align 4
+ at a3 = external local_unnamed_addr addrspace(2) global [ 2 x <2 x double> ], align 8
; CHECK: define void @f(
define void @f(ptr %dst) {
entry:
- %CB.cb_h.i.i = tail call target("dx.CBuffer", target("dx.Layout", %__cblayout_CB, 708, 0, 48, 112, 176, 224, 272, 288, 320)) @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, ptr null)
- store target("dx.CBuffer", target("dx.Layout", %__cblayout_CB, 708, 0, 48, 112, 176, 224, 272, 288, 320)) %CB.cb_h.i.i, ptr @CB.cb, align 4
+ %CB.cb_h.i.i = tail call target("dx.CBuffer", %__cblayout_CB) @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, ptr null)
+ store target("dx.CBuffer", %__cblayout_CB) %CB.cb_h.i.i, ptr @CB.cb, align 4
- %a1.copy = alloca [3 x float], align 4
- %a2.copy = alloca [2 x <3 x double>], align 32
- %a3.copy = alloca [2 x [2 x half]], align 2
- %a4.copy = alloca [3 x i64], align 8
- %a5.copy = alloca [3 x [2 x <2 x i32>]], align 16
- %a6.copy = alloca [1 x i16], align 2
- %a7.copy = alloca [2 x i64], align 8
- %a8.copy = alloca [4 x i32], align 4
+ %a1.copy = alloca [4 x <4 x float>], align 4
+ %a3.copy = alloca [2 x <2 x double>], align 8
; Try copying no elements
; CHECK-NOT: memcpy
call void @llvm.memcpy.p0.p2.i32(ptr align 4 %a1.copy, ptr addrspace(2) align 4 @a1, i32 0, i1 false)
; Try copying only the first element
-; CHECK: [[CB:%.*]] = load target("dx.CBuffer", {{.*}})), ptr @CB.cb, align 4
-; CHECK: [[LOAD:%.*]] = call { float, float, float, float } @llvm.dx.resource.load.cbufferrow.4.{{.*}}(target("dx.CBuffer", {{.*}})) [[CB]], i32 0)
+; CHECK: [[CB:%.*]] = load target("dx.CBuffer", %__cblayout_CB), ptr @CB.cb, align 4
+; CHECK: [[LOAD:%.*]] = call { float, float, float, float } @llvm.dx.resource.load.cbufferrow.4.{{.*}}(target("dx.CBuffer", %__cblayout_CB) [[CB]], i32 0)
; CHECK: [[X:%.*]] = extractvalue { float, float, float, float } [[LOAD]], 0
+; CHECK: [[Y:%.*]] = extractvalue { float, float, float, float } [[LOAD]], 1
+; CHECK: [[Z:%.*]] = extractvalue { float, float, float, float } [[LOAD]], 2
+; CHECK: [[A:%.*]] = extractvalue { float, float, float, float } [[LOAD]], 3
+; CHECK: [[UPTO0:%.*]] = insertelement <4 x float> poison, float [[X]], i32 0
+; CHECK: [[UPTO1:%.*]] = insertelement <4 x float> [[UPTO0]], float [[Y]], i32 1
+; CHECK: [[UPTO2:%.*]] = insertelement <4 x float> [[UPTO1]], float [[Z]], i32 2
+; CHECK: [[VALUE:%.*]] = insertelement <4 x float> [[UPTO2]], float [[A]], i32 3
; CHECK: [[DEST:%.*]] = getelementptr inbounds i8, ptr [[A1_COPY:%.*]], i32 0
-; CHECK: store float [[X]], ptr [[DEST]], align 4
- call void @llvm.memcpy.p0.p2.i32(ptr align 4 %a1.copy, ptr addrspace(2) align 4 @a1, i32 4, i1 false)
-; CHECK: [[CB:%.*]] = load target("dx.CBuffer", {{.*}})), ptr @CB.cb, align 4
-; CHECK: [[LOAD:%.*]] = call { float, float, float, float } @llvm.dx.resource.load.cbufferrow.4.{{.*}}(target("dx.CBuffer", {{.*}})) [[CB]], i32 0)
-; CHECK: [[X:%.*]] = extractvalue { float, float, float, float } [[LOAD]], 0
-; CHECK: [[DEST:%.*]] = getelementptr inbounds i8, ptr [[A1_COPY:%.*]], i32 0
-; CHECK: store float [[X]], ptr [[DEST]], align 4
-; CHECK: [[LOAD:%.*]] = call { float, float, float, float } @llvm.dx.resource.load.cbufferrow.4.{{.*}}(target("dx.CBuffer", {{.*}})) [[CB]], i32 1)
-; CHECK: [[Y:%.*]] = extractvalue { float, float, float, float } [[LOAD]], 0
-; CHECK: [[DEST:%.*]] = getelementptr inbounds i8, ptr [[A1_COPY]], i32 4
-; CHECK: store float [[Y]], ptr [[DEST]], align 4
-; CHECK: [[LOAD:%.*]] = call { float, float, float, float } @llvm.dx.resource.load.cbufferrow.4.{{.*}}(target("dx.CBuffer", {{.*}})) [[CB]], i32 2)
-; CHECK: [[Z:%.*]] = extractvalue { float, float, float, float } [[LOAD]], 0
-; CHECK: [[DEST:%.*]] = getelementptr inbounds i8, ptr [[A1_COPY]], i32 8
-; CHECK: store float [[Z]], ptr [[DEST]], align 4
- call void @llvm.memcpy.p0.p2.i32(ptr align 4 %a1.copy, ptr addrspace(2) align 4 @a1, i32 12, i1 false)
+; CHECK: store <4 x float> [[VALUE]], ptr [[DEST]], align 16
+ call void @llvm.memcpy.p0.p2.i32(ptr align 4 %a1.copy, ptr addrspace(2) align 4 @a1, i32 16, i1 false)
-; CHECK: [[CB:%.*]] = load target("dx.CBuffer", {{.*}})), ptr @CB.cb, align 4
-; CHECK: [[LOAD:%.*]] = call { double, double } @llvm.dx.resource.load.cbufferrow.2.{{.*}}(target("dx.CBuffer", {{.*}})) [[CB]], i32 3)
+ ; Try copying the later element
+; CHECK: [[CB:%.*]] = load target("dx.CBuffer", %__cblayout_CB), ptr @CB.cb, align 4
+; CHECK: [[LOAD:%.*]] = call { double, double } @llvm.dx.resource.load.cbufferrow.2.{{.*}}(target("dx.CBuffer", %__cblayout_CB) [[CB]], i32 7)
; CHECK: [[X:%.*]] = extractvalue { double, double } [[LOAD]], 0
; CHECK: [[Y:%.*]] = extractvalue { double, double } [[LOAD]], 1
-; CHECK: [[LOAD:%.*]] = call { double, double } @llvm.dx.resource.load.cbufferrow.2.{{.*}}(target("dx.CBuffer", {{.*}})) [[CB]], i32 4)
-; CHECK: [[Z:%.*]] = extractvalue { double, double } [[LOAD]], 0
-; CHECK: [[UPTO0:%.*]] = insertelement <3 x double> poison, double [[X]], i32 0
-; CHECK: [[UPTO1:%.*]] = insertelement <3 x double> [[UPTO0]], double [[Y]], i32 1
-; CHECK: [[UPTO2:%.*]] = insertelement <3 x double> [[UPTO1]], double [[Z]], i32 2
-; CHECK: [[DEST:%.*]] = getelementptr inbounds i8, ptr [[A2_COPY:%.*]], i32 0
-; CHECK: store <3 x double> [[UPTO2]], ptr [[DEST]], align 32
-; CHECK: [[LOAD:%.*]] = call { double, double } @llvm.dx.resource.load.cbufferrow.2.{{.*}}(target("dx.CBuffer", {{.*}})) [[CB]], i32 5)
-; CHECK: [[X:%.*]] = extractvalue { double, double } [[LOAD]], 0
-; CHECK: [[Y:%.*]] = extractvalue { double, double } [[LOAD]], 1
-; CHECK: [[LOAD:%.*]] = call { double, double } @llvm.dx.resource.load.cbufferrow.2.{{.*}}(target("dx.CBuffer", {{.*}})) [[CB]], i32 6)
-; CHECK: [[Z:%.*]] = extractvalue { double, double } [[LOAD]], 0
-; CHECK: [[UPTO0:%.*]] = insertelement <3 x double> poison, double [[X]], i32 0
-; CHECK: [[UPTO1:%.*]] = insertelement <3 x double> [[UPTO0]], double [[Y]], i32 1
-; CHECK: [[UPTO2:%.*]] = insertelement <3 x double> [[UPTO1]], double [[Z]], i32 2
-; CHECK: [[DEST:%.*]] = getelementptr inbounds i8, ptr [[A2_COPY]], i32 32
-; CHECK: store <3 x double> [[UPTO2]], ptr [[DEST]], align 32
- call void @llvm.memcpy.p0.p2.i32(ptr align 32 %a2.copy, ptr addrspace(2) align 32 @a2, i32 64, i1 false)
-
-; CHECK: [[CB:%.*]] = load target("dx.CBuffer", {{.*}})), ptr @CB.cb, align 4
-; CHECK: [[LOAD:%.*]] = call { half, half, half, half, half, half, half, half } @llvm.dx.resource.load.cbufferrow.8.{{.*}}(target("dx.CBuffer", {{.*}})) [[CB]], i32 7)
-; CHECK: [[X:%.*]] = extractvalue { half, half, half, half, half, half, half, half } [[LOAD]], 0
+; CHECK: [[UPTO0:%.*]] = insertelement <2 x double> poison, double [[X]], i32 0
+; CHECK: [[VALUE:%.*]] = insertelement <2 x double> [[UPTO0]], double [[Y]], i32 1
; CHECK: [[DEST:%.*]] = getelementptr inbounds i8, ptr [[A3_COPY:%.*]], i32 0
-; CHECK: store half [[X]], ptr [[DEST]], align 2
-; CHECK: [[LOAD:%.*]] = call { half, half, half, half, half, half, half, half } @llvm.dx.resource.load.cbufferrow.8.{{.*}}(target("dx.CBuffer", {{.*}})) [[CB]], i32 8)
-; CHECK: [[Y:%.*]] = extractvalue { half, half, half, half, half, half, half, half } [[LOAD]], 0
-; CHECK: [[DEST:%.*]] = getelementptr inbounds i8, ptr [[A3_COPY]], i32 2
-; CHECK: store half [[Y]], ptr [[DEST]], align 2
-; CHECK: [[LOAD:%.*]] = call { half, half, half, half, half, half, half, half } @llvm.dx.resource.load.cbufferrow.8.{{.*}}(target("dx.CBuffer", {{.*}})) [[CB]], i32 9)
-; CHECK: [[X:%.*]] = extractvalue { half, half, half, half, half, half, half, half } [[LOAD]], 0
-; CHECK: [[DEST:%.*]] = getelementptr inbounds i8, ptr [[A3_COPY]], i32 4
-; CHECK: store half [[X]], ptr [[DEST]], align 2
-; CHECK: [[LOAD:%.*]] = call { half, half, half, half, half, half, half, half } @llvm.dx.resource.load.cbufferrow.8.{{.*}}(target("dx.CBuffer", {{.*}})) [[CB]], i32 10)
-; CHECK: [[Y:%.*]] = extractvalue { half, half, half, half, half, half, half, half } [[LOAD]], 0
-; CHECK: [[DEST:%.*]] = getelementptr inbounds i8, ptr [[A3_COPY]], i32 6
-; CHECK: store half [[Y]], ptr [[DEST]], align 2
- call void @llvm.memcpy.p0.p2.i32(ptr align 2 %a3.copy, ptr addrspace(2) align 2 @a3, i32 8, i1 false)
-
-; CHECK: [[CB:%.*]] = load target("dx.CBuffer", {{.*}})), ptr @CB.cb, align 4
-; CHECK: [[LOAD:%.*]] = call { i64, i64 } @llvm.dx.resource.load.cbufferrow.2.{{.*}}(target("dx.CBuffer", {{.*}})) [[CB]], i32 11)
-; CHECK: [[X:%.*]] = extractvalue { i64, i64 } [[LOAD]], 0
-; CHECK: [[DEST:%.*]] = getelementptr inbounds i8, ptr [[A4_COPY:%.*]], i32 0
-; CHECK: store i64 [[X]], ptr [[DEST]], align 8
-; CHECK: [[LOAD:%.*]] = call { i64, i64 } @llvm.dx.resource.load.cbufferrow.2.{{.*}}(target("dx.CBuffer", {{.*}})) [[CB]], i32 12)
-; CHECK: [[Y:%.*]] = extractvalue { i64, i64 } [[LOAD]], 0
-; CHECK: [[DEST:%.*]] = getelementptr inbounds i8, ptr [[A4_COPY]], i32 8
-; CHECK: store i64 [[Y]], ptr [[DEST]], align 8
-; CHECK: [[LOAD:%.*]] = call { i64, i64 } @llvm.dx.resource.load.cbufferrow.2.{{.*}}(target("dx.CBuffer", {{.*}})) [[CB]], i32 13)
-; CHECK: [[Z:%.*]] = extractvalue { i64, i64 } [[LOAD]], 0
-; CHECK: [[DEST:%.*]] = getelementptr inbounds i8, ptr [[A4_COPY]], i32 16
-; CHECK: store i64 [[Z]], ptr [[DEST]], align 8
- call void @llvm.memcpy.p0.p2.i32(ptr align 8 %a4.copy, ptr addrspace(2) align 8 @a4, i32 24, i1 false)
-
-; CHECK: [[CB:%.*]] = load target("dx.CBuffer", {{.*}})), ptr @CB.cb, align 4
-; CHECK: [[LOAD:%.*]] = call { i32, i32, i32, i32 } @llvm.dx.resource.load.cbufferrow.4.{{.*}}(target("dx.CBuffer", {{.*}})) [[CB]], i32 14)
-; CHECK: [[X:%.*]] = extractvalue { i32, i32, i32, i32 } [[LOAD]], 0
-; CHECK: [[Y:%.*]] = extractvalue { i32, i32, i32, i32 } [[LOAD]], 1
-; CHECK: [[UPTO0:%.*]] = insertelement <2 x i32> poison, i32 [[X]], i32 0
-; CHECK: [[UPTO1:%.*]] = insertelement <2 x i32> [[UPTO0]], i32 [[Y]], i32 1
-; CHECK: [[DEST:%.*]] = getelementptr inbounds i8, ptr [[A5_COPY:%.*]], i32 0
-; CHECK: store <2 x i32> [[UPTO1]], ptr [[DEST]], align 8
-; CHECK: [[LOAD:%.*]] = call { i32, i32, i32, i32 } @llvm.dx.resource.load.cbufferrow.4.{{.*}}(target("dx.CBuffer", {{.*}})) [[CB]], i32 15)
-; CHECK: [[X:%.*]] = extractvalue { i32, i32, i32, i32 } [[LOAD]], 0
-; CHECK: [[Y:%.*]] = extractvalue { i32, i32, i32, i32 } [[LOAD]], 1
-; CHECK: [[UPTO0:%.*]] = insertelement <2 x i32> poison, i32 [[X]], i32 0
-; CHECK: [[UPTO1:%.*]] = insertelement <2 x i32> [[UPTO0]], i32 [[Y]], i32 1
-; CHECK: [[DEST:%.*]] = getelementptr inbounds i8, ptr [[A5_COPY]], i32 8
-; CHECK: store <2 x i32> [[UPTO1]], ptr [[DEST]], align 8
-; CHECK: [[LOAD:%.*]] = call { i32, i32, i32, i32 } @llvm.dx.resource.load.cbufferrow.4.{{.*}}(target("dx.CBuffer", {{.*}})) [[CB]], i32 16)
-; CHECK: [[X:%.*]] = extractvalue { i32, i32, i32, i32 } [[LOAD]], 0
-; CHECK: [[Y:%.*]] = extractvalue { i32, i32, i32, i32 } [[LOAD]], 1
-; CHECK: [[UPTO0:%.*]] = insertelement <2 x i32> poison, i32 [[X]], i32 0
-; CHECK: [[UPTO1:%.*]] = insertelement <2 x i32> [[UPTO0]], i32 [[Y]], i32 1
-; CHECK: [[DEST:%.*]] = getelementptr inbounds i8, ptr [[A5_COPY]], i32 16
-; CHECK: store <2 x i32> [[UPTO1]], ptr [[DEST]], align 8
-; CHECK: [[LOAD:%.*]] = call { i32, i32, i32, i32 } @llvm.dx.resource.load.cbufferrow.4.{{.*}}(target("dx.CBuffer", {{.*}})) [[CB]], i32 17)
-; CHECK: [[X:%.*]] = extractvalue { i32, i32, i32, i32 } [[LOAD]], 0
-; CHECK: [[Y:%.*]] = extractvalue { i32, i32, i32, i32 } [[LOAD]], 1
-; CHECK: [[UPTO0:%.*]] = insertelement <2 x i32> poison, i32 [[X]], i32 0
-; CHECK: [[UPTO1:%.*]] = insertelement <2 x i32> [[UPTO0]], i32 [[Y]], i32 1
-; CHECK: [[DEST:%.*]] = getelementptr inbounds i8, ptr [[A5_COPY]], i32 24
-; CHECK: store <2 x i32> [[UPTO1]], ptr [[DEST]], align 8
-; CHECK: [[LOAD:%.*]] = call { i32, i32, i32, i32 } @llvm.dx.resource.load.cbufferrow.4.{{.*}}(target("dx.CBuffer", {{.*}})) [[CB]], i32 18)
-; CHECK: [[X:%.*]] = extractvalue { i32, i32, i32, i32 } [[LOAD]], 0
-; CHECK: [[Y:%.*]] = extractvalue { i32, i32, i32, i32 } [[LOAD]], 1
-; CHECK: [[UPTO0:%.*]] = insertelement <2 x i32> poison, i32 [[X]], i32 0
-; CHECK: [[UPTO1:%.*]] = insertelement <2 x i32> [[UPTO0]], i32 [[Y]], i32 1
-; CHECK: [[DEST:%.*]] = getelementptr inbounds i8, ptr [[A5_COPY]], i32 32
-; CHECK: store <2 x i32> [[UPTO1]], ptr [[DEST]], align 8
-; CHECK: [[LOAD:%.*]] = call { i32, i32, i32, i32 } @llvm.dx.resource.load.cbufferrow.4.{{.*}}(target("dx.CBuffer", {{.*}})) [[CB]], i32 19)
-; CHECK: [[X:%.*]] = extractvalue { i32, i32, i32, i32 } [[LOAD]], 0
-; CHECK: [[Y:%.*]] = extractvalue { i32, i32, i32, i32 } [[LOAD]], 1
-; CHECK: [[UPTO0:%.*]] = insertelement <2 x i32> poison, i32 [[X]], i32 0
-; CHECK: [[UPTO1:%.*]] = insertelement <2 x i32> [[UPTO0]], i32 [[Y]], i32 1
-; CHECK: [[DEST:%.*]] = getelementptr inbounds i8, ptr [[A5_COPY]], i32 40
-; CHECK: store <2 x i32> [[UPTO1]], ptr [[DEST]], align 8
- call void @llvm.memcpy.p0.p2.i32(ptr align 16 %a5.copy, ptr addrspace(2) align 16 @a5, i32 48, i1 false)
-
-; CHECK: [[CB:%.*]] = load target("dx.CBuffer", {{.*}})), ptr @CB.cb, align 4
-; CHECK: [[LOAD:%.*]] = call { i16, i16, i16, i16, i16, i16, i16, i16 } @llvm.dx.resource.load.cbufferrow.8.{{.*}}(target("dx.CBuffer", {{.*}})) [[CB]], i32 17)
-; CHECK: [[X:%.*]] = extractvalue { i16, i16, i16, i16, i16, i16, i16, i16 } [[LOAD]], 0
-; CHECK: [[DEST:%.*]] = getelementptr inbounds i8, ptr [[A6_COPY:%.*]], i32 0
-; CHECK: store i16 [[X]], ptr [[DEST]], align 2
- call void @llvm.memcpy.p0.p2.i32(ptr align 2 %a6.copy, ptr addrspace(2) align 2 @a6, i32 2, i1 false)
-
-; CHECK: [[CB:%.*]] = load target("dx.CBuffer", {{.*}})), ptr @CB.cb, align 4
-; CHECK: [[LOAD:%.*]] = call { i64, i64 } @llvm.dx.resource.load.cbufferrow.2.{{.*}}(target("dx.CBuffer", {{.*}})) [[CB]], i32 18)
-; CHECK: [[X:%.*]] = extractvalue { i64, i64 } [[LOAD]], 0
-; CHECK: [[DEST:%.*]] = getelementptr inbounds i8, ptr [[A7_COPY:%.*]], i32 0
-; CHECK: store i64 [[X]], ptr [[DEST]], align 8
-; CHECK: [[LOAD:%.*]] = call { i64, i64 } @llvm.dx.resource.load.cbufferrow.2.{{.*}}(target("dx.CBuffer", {{.*}})) [[CB]], i32 19)
-; CHECK: [[Y:%.*]] = extractvalue { i64, i64 } [[LOAD]], 0
-; CHECK: [[DEST:%.*]] = getelementptr inbounds i8, ptr [[A7_COPY]], i32 8
-; CHECK: store i64 [[Y]], ptr [[DEST]], align 8
- call void @llvm.memcpy.p0.p2.i32(ptr align 8 %a7.copy, ptr addrspace(2) align 8 @a7, i32 16, i1 false)
-
-; CHECK: [[CB:%.*]] = load target("dx.CBuffer", {{.*}})), ptr @CB.cb, align 4
-; CHECK: [[LOAD:%.*]] = call { i32, i32, i32, i32 } @llvm.dx.resource.load.cbufferrow.4.{{.*}}(target("dx.CBuffer", {{.*}})) [[CB]], i32 20)
-; CHECK: [[X:%.*]] = extractvalue { i32, i32, i32, i32 } [[LOAD]], 0
-; CHECK: [[DEST:%.*]] = getelementptr inbounds i8, ptr [[A8_COPY:%.*]], i32 0
-; CHECK: store i32 [[X]], ptr [[DEST]], align 4
-; CHECK: [[LOAD:%.*]] = call { i32, i32, i32, i32 } @llvm.dx.resource.load.cbufferrow.4.{{.*}}(target("dx.CBuffer", {{.*}})) [[CB]], i32 21)
-; CHECK: [[Y:%.*]] = extractvalue { i32, i32, i32, i32 } [[LOAD]], 0
-; CHECK: [[DEST:%.*]] = getelementptr inbounds i8, ptr [[A8_COPY]], i32 4
-; CHECK: store i32 [[Y]], ptr [[DEST]], align 4
-; CHECK: [[LOAD:%.*]] = call { i32, i32, i32, i32 } @llvm.dx.resource.load.cbufferrow.4.{{.*}}(target("dx.CBuffer", {{.*}})) [[CB]], i32 22)
-; CHECK: [[Z:%.*]] = extractvalue { i32, i32, i32, i32 } [[LOAD]], 0
-; CHECK: [[DEST:%.*]] = getelementptr inbounds i8, ptr [[A8_COPY]], i32 8
-; CHECK: store i32 [[Z]], ptr [[DEST]], align 4
-; CHECK: [[LOAD:%.*]] = call { i32, i32, i32, i32 } @llvm.dx.resource.load.cbufferrow.4.{{.*}}(target("dx.CBuffer", {{.*}})) [[CB]], i32 23)
-; CHECK: [[W:%.*]] = extractvalue { i32, i32, i32, i32 } [[LOAD]], 0
-; CHECK: [[DEST:%.*]] = getelementptr inbounds i8, ptr [[A8_COPY]], i32 12
-; CHECK: store i32 [[W]], ptr [[DEST]], align 4
- call void @llvm.memcpy.p0.p2.i32(ptr align 4 %a8.copy, ptr addrspace(2) align 4 @a8, i32 16, i1 false)
+; CHECK: store <2 x double> [[VALUE]], ptr [[DEST]], align 16
+ call void @llvm.memcpy.p0.p2.i32(ptr align 32 %a3.copy, ptr addrspace(2) align 32 @a3, i32 16, i1 false)
ret void
}
-declare void @llvm.memcpy.p0.p2.i32(ptr noalias writeonly captures(none), ptr addrspace(2) noalias readonly captures(none), i32, i1 immarg)
-
; CHECK-NOT: !hlsl.cbs =
!hlsl.cbs = !{!0}
-!0 = !{ptr @CB.cb, ptr addrspace(2) @a1, ptr addrspace(2) @a2, ptr addrspace(2) @a3, ptr addrspace(2) @a4, ptr addrspace(2) @a5, ptr addrspace(2) @a6, ptr addrspace(2) @a7, ptr addrspace(2) @a8}
+!0 = !{ptr @CB.cb, ptr addrspace(2) @a1, ptr addrspace(2) @a2, ptr addrspace(2) @a3}
!1 = !{i32 0, i32 2}
!2 = !{}
diff --git a/llvm/test/CodeGen/DirectX/CBufferAccess/scalars.ll b/llvm/test/CodeGen/DirectX/CBufferAccess/scalars.ll
index 7857c25d69636..e53ba1c273240 100644
--- a/llvm/test/CodeGen/DirectX/CBufferAccess/scalars.ll
+++ b/llvm/test/CodeGen/DirectX/CBufferAccess/scalars.ll
@@ -11,7 +11,7 @@
; }
%__cblayout_CB = type <{ float, i32, i32, half, i16, double, i64 }>
- at CB.cb = local_unnamed_addr global target("dx.CBuffer", target("dx.Layout", %__cblayout_CB, 32, 0, 4, 8, 12, 14, 16, 24)) poison
+ at CB.cb = local_unnamed_addr global target("dx.CBuffer", %__cblayout_CB) poison
; CHECK: @CB.cb =
; CHECK-NOT: external {{.*}} addrspace(2) global
@a1 = external local_unnamed_addr addrspace(2) global float, align 4
@@ -25,18 +25,18 @@
; CHECK: define void @f
define void @f(ptr %dst) {
entry:
- %CB.cb_h.i.i = tail call target("dx.CBuffer", target("dx.Layout", %__cblayout_CB, 32, 0, 4, 8, 12, 14, 16, 24)) @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, ptr null)
- store target("dx.CBuffer", target("dx.Layout", %__cblayout_CB, 32, 0, 4, 8, 12, 14, 16, 24)) %CB.cb_h.i.i, ptr @CB.cb, align 4
+ %CB.cb_h.i.i = tail call target("dx.CBuffer", %__cblayout_CB) @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, ptr null)
+ store target("dx.CBuffer", %__cblayout_CB) %CB.cb_h.i.i, ptr @CB.cb, align 4
- ; CHECK: [[CB:%.*]] = load target("dx.CBuffer", {{.*}})), ptr @CB.cb
- ; CHECK: [[LOAD:%.*]] = call { float, float, float, float } @llvm.dx.resource.load.cbufferrow.4.{{.*}}(target("dx.CBuffer", {{.*}})) [[CB]], i32 0)
+ ; CHECK: [[CB:%.*]] = load target("dx.CBuffer", %__cblayout_CB), ptr @CB.cb
+ ; CHECK: [[LOAD:%.*]] = call { float, float, float, float } @llvm.dx.resource.load.cbufferrow.4.{{.*}}(target("dx.CBuffer", %__cblayout_CB) [[CB]], i32 0)
; CHECK: [[A1:%.*]] = extractvalue { float, float, float, float } [[LOAD]], 0
; CHECK: store float [[A1]], ptr %dst
%a1 = load float, ptr addrspace(2) @a1, align 4
store float %a1, ptr %dst, align 8
- ; CHECK: [[CB:%.*]] = load target("dx.CBuffer", {{.*}})), ptr @CB.cb
- ; CHECK: [[LOAD:%.*]] = call { i32, i32, i32, i32 } @llvm.dx.resource.load.cbufferrow.4.{{.*}}(target("dx.CBuffer", {{.*}})) [[CB]], i32 0)
+ ; CHECK: [[CB:%.*]] = load target("dx.CBuffer", %__cblayout_CB), ptr @CB.cb
+ ; CHECK: [[LOAD:%.*]] = call { i32, i32, i32, i32 } @llvm.dx.resource.load.cbufferrow.4.{{.*}}(target("dx.CBuffer", %__cblayout_CB) [[CB]], i32 0)
; CHECK: [[A2:%.*]] = extractvalue { i32, i32, i32, i32 } [[LOAD]], 1
; CHECK: [[PTR:%.*]] = getelementptr inbounds nuw i8, ptr %dst, i32 4
; CHECK: store i32 [[A2]], ptr [[PTR]]
@@ -44,8 +44,8 @@ entry:
%a2.i = getelementptr inbounds nuw i8, ptr %dst, i32 4
store i32 %a2, ptr %a2.i, align 4
- ; CHECK: [[CB:%.*]] = load target("dx.CBuffer", {{.*}})), ptr @CB.cb
- ; CHECK: [[LOAD:%.*]] = call { i32, i32, i32, i32 } @llvm.dx.resource.load.cbufferrow.4.{{.*}}(target("dx.CBuffer", {{.*}})) [[CB]], i32 0)
+ ; CHECK: [[CB:%.*]] = load target("dx.CBuffer", %__cblayout_CB), ptr @CB.cb
+ ; CHECK: [[LOAD:%.*]] = call { i32, i32, i32, i32 } @llvm.dx.resource.load.cbufferrow.4.{{.*}}(target("dx.CBuffer", %__cblayout_CB) [[CB]], i32 0)
; CHECK: [[A3:%.*]] = extractvalue { i32, i32, i32, i32 } [[LOAD]], 2
; CHECK: [[PTR:%.*]] = getelementptr inbounds nuw i8, ptr %dst, i32 8
; CHECK: store i32 [[A3]], ptr [[PTR]]
@@ -53,8 +53,8 @@ entry:
%a3.i = getelementptr inbounds nuw i8, ptr %dst, i32 8
store i32 %a3, ptr %a3.i, align 8
- ; CHECK: [[CB:%.*]] = load target("dx.CBuffer", {{.*}})), ptr @CB.cb
- ; CHECK: [[LOAD:%.*]] = call { half, half, half, half, half, half, half, half } @llvm.dx.resource.load.cbufferrow.8.{{.*}}(target("dx.CBuffer", {{.*}})) [[CB]], i32 0)
+ ; CHECK: [[CB:%.*]] = load target("dx.CBuffer", %__cblayout_CB), ptr @CB.cb
+ ; CHECK: [[LOAD:%.*]] = call { half, half, half, half, half, half, half, half } @llvm.dx.resource.load.cbufferrow.8.{{.*}}(target("dx.CBuffer", %__cblayout_CB) [[CB]], i32 0)
; CHECK: [[A4:%.*]] = extractvalue { half, half, half, half, half, half, half, half } [[LOAD]], 6
; CHECK: [[PTR:%.*]] = getelementptr inbounds nuw i8, ptr %dst, i32 12
; CHECK: store half [[A4]], ptr [[PTR]]
@@ -62,8 +62,8 @@ entry:
%a4.i = getelementptr inbounds nuw i8, ptr %dst, i32 12
store half %a4, ptr %a4.i, align 4
- ; CHECK: [[CB:%.*]] = load target("dx.CBuffer", {{.*}})), ptr @CB.cb
- ; CHECK: [[LOAD:%.*]] = call { i16, i16, i16, i16, i16, i16, i16, i16 } @llvm.dx.resource.load.cbufferrow.8.{{.*}}(target("dx.CBuffer", {{.*}})) [[CB]], i32 0)
+ ; CHECK: [[CB:%.*]] = load target("dx.CBuffer", %__cblayout_CB), ptr @CB.cb
+ ; CHECK: [[LOAD:%.*]] = call { i16, i16, i16, i16, i16, i16, i16, i16 } @llvm.dx.resource.load.cbufferrow.8.{{.*}}(target("dx.CBuffer", %__cblayout_CB) [[CB]], i32 0)
; CHECK: [[A5:%.*]] = extractvalue { i16, i16, i16, i16, i16, i16, i16, i16 } [[LOAD]], 7
; CHECK: [[PTR:%.*]] = getelementptr inbounds nuw i8, ptr %dst, i32 14
; CHECK: store i16 [[A5]], ptr [[PTR]]
@@ -71,8 +71,8 @@ entry:
%a5.i = getelementptr inbounds nuw i8, ptr %dst, i32 14
store i16 %a5, ptr %a5.i, align 2
- ; CHECK: [[CB:%.*]] = load target("dx.CBuffer", {{.*}})), ptr @CB.cb
- ; CHECK: [[LOAD:%.*]] = call { double, double } @llvm.dx.resource.load.cbufferrow.2.{{.*}}(target("dx.CBuffer", {{.*}})) [[CB]], i32 1)
+ ; CHECK: [[CB:%.*]] = load target("dx.CBuffer", %__cblayout_CB), ptr @CB.cb
+ ; CHECK: [[LOAD:%.*]] = call { double, double } @llvm.dx.resource.load.cbufferrow.2.{{.*}}(target("dx.CBuffer", %__cblayout_CB) [[CB]], i32 1)
; CHECK: [[A6:%.*]] = extractvalue { double, double } [[LOAD]], 0
; CHECK: [[PTR:%.*]] = getelementptr inbounds nuw i8, ptr %dst, i32 16
; CHECK: store double [[A6]], ptr [[PTR]]
@@ -80,8 +80,8 @@ entry:
%a6.i = getelementptr inbounds nuw i8, ptr %dst, i32 16
store double %a6, ptr %a6.i, align 8
- ; CHECK: [[CB:%.*]] = load target("dx.CBuffer", {{.*}})), ptr @CB.cb
- ; CHECK: [[LOAD:%.*]] = call { i64, i64 } @llvm.dx.resource.load.cbufferrow.2.{{.*}}(target("dx.CBuffer", {{.*}})) [[CB]], i32 1)
+ ; CHECK: [[CB:%.*]] = load target("dx.CBuffer", %__cblayout_CB), ptr @CB.cb
+ ; CHECK: [[LOAD:%.*]] = call { i64, i64 } @llvm.dx.resource.load.cbufferrow.2.{{.*}}(target("dx.CBuffer", %__cblayout_CB) [[CB]], i32 1)
; CHECK: [[A7:%.*]] = extractvalue { i64, i64 } [[LOAD]], 1
; CHECK: [[PTR:%.*]] = getelementptr inbounds nuw i8, ptr %dst, i32 24
; CHECK: store i64 [[A7]], ptr [[PTR]]
diff --git a/llvm/test/CodeGen/DirectX/CBufferAccess/vectors.ll b/llvm/test/CodeGen/DirectX/CBufferAccess/vectors.ll
index 4160008a986af..72ec103e8f246 100644
--- a/llvm/test/CodeGen/DirectX/CBufferAccess/vectors.ll
+++ b/llvm/test/CodeGen/DirectX/CBufferAccess/vectors.ll
@@ -1,5 +1,9 @@
; RUN: opt -S -dxil-cbuffer-access -mtriple=dxil--shadermodel6.3-library %s | FileCheck %s
+; TODO: Remove datalayout.
+; This hack forces dxil-compatible alignment of 3-element 32- and 64-bit vectors
+target datalayout = "e-m:e-p:32:32-i1:32-i8:8-i16:16-i32:32-i64:64-f16:16-f32:32-f64:64-n8:16:32:64-v96:32:32-v192:64:64"
+
; cbuffer CB {
; float3 a1; // offset 0, size 12 (+4)
; double3 a2; // offset 16, size 24
@@ -8,9 +12,9 @@
; int4 a5; // offset 80, size 16
; uint16_t3 a6; // offset 96, size 6 (+10)
; };
-%__cblayout_CB = type <{ <3 x float>, <3 x double>, <2 x half>, <3 x i64>, <4 x i32>, <3 x i16> }>
+%__cblayout_CB = type <{ <3 x float>, [4 x i8], <3 x double>, <2 x half>, [4 x i8], <3 x i64>, [8 x i8], <4 x i32>, <3 x i16> }>
- at CB.cb = local_unnamed_addr global target("dx.CBuffer", target("dx.Layout", %__cblayout_CB, 102, 0, 16, 40, 48, 80, 96)) poison
+ at CB.cb = local_unnamed_addr global target("dx.CBuffer", %__cblayout_CB) poison
; CHECK: @CB.cb =
; CHECK-NOT: external {{.*}} addrspace(2) global
@a1 = external local_unnamed_addr addrspace(2) global <3 x float>, align 16
@@ -23,11 +27,11 @@
; CHECK: define void @f
define void @f(ptr %dst) {
entry:
- %CB.cb_h.i.i = tail call target("dx.CBuffer", target("dx.Layout", %__cblayout_CB, 102, 0, 16, 40, 48, 80, 96)) @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, ptr null)
- store target("dx.CBuffer", target("dx.Layout", %__cblayout_CB, 102, 0, 16, 40, 48, 80, 96)) %CB.cb_h.i.i, ptr @CB.cb, align 4
+ %CB.cb_h.i.i = tail call target("dx.CBuffer", %__cblayout_CB) @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, ptr null)
+ store target("dx.CBuffer", %__cblayout_CB) %CB.cb_h.i.i, ptr @CB.cb, align 4
- ; CHECK: [[CB:%.*]] = load target("dx.CBuffer", {{.*}})), ptr @CB.cb
- ; CHECK: [[LOAD:%.*]] = call { float, float, float, float } @llvm.dx.resource.load.cbufferrow.4.{{.*}}(target("dx.CBuffer", {{.*}})) [[CB]], i32 0)
+ ; CHECK: [[CB:%.*]] = load target("dx.CBuffer", %__cblayout_CB), ptr @CB.cb
+ ; CHECK: [[LOAD:%.*]] = call { float, float, float, float } @llvm.dx.resource.load.cbufferrow.4.{{.*}}(target("dx.CBuffer", %__cblayout_CB) [[CB]], i32 0)
; CHECK: [[X:%.*]] = extractvalue { float, float, float, float } [[LOAD]], 0
; CHECK: [[Y:%.*]] = extractvalue { float, float, float, float } [[LOAD]], 1
; CHECK: [[Z:%.*]] = extractvalue { float, float, float, float } [[LOAD]], 2
@@ -38,11 +42,11 @@ entry:
%a1 = load <3 x float>, ptr addrspace(2) @a1, align 16
store <3 x float> %a1, ptr %dst, align 4
- ; CHECK: [[CB:%.*]] = load target("dx.CBuffer", {{.*}})), ptr @CB.cb
- ; CHECK: [[LOAD:%.*]] = call { double, double } @llvm.dx.resource.load.cbufferrow.2.{{.*}}(target("dx.CBuffer", {{.*}})) [[CB]], i32 1)
+ ; CHECK: [[CB:%.*]] = load target("dx.CBuffer", %__cblayout_CB), ptr @CB.cb
+ ; CHECK: [[LOAD:%.*]] = call { double, double } @llvm.dx.resource.load.cbufferrow.2.{{.*}}(target("dx.CBuffer", %__cblayout_CB) [[CB]], i32 1)
; CHECK: [[X:%.*]] = extractvalue { double, double } [[LOAD]], 0
; CHECK: [[Y:%.*]] = extractvalue { double, double } [[LOAD]], 1
- ; CHECK: [[LOAD:%.*]] = call { double, double } @llvm.dx.resource.load.cbufferrow.2.{{.*}}(target("dx.CBuffer", {{.*}})) [[CB]], i32 2)
+ ; CHECK: [[LOAD:%.*]] = call { double, double } @llvm.dx.resource.load.cbufferrow.2.{{.*}}(target("dx.CBuffer", %__cblayout_CB) [[CB]], i32 2)
; CHECK: [[Z:%.*]] = extractvalue { double, double } [[LOAD]], 0
; CHECK: [[VEC0:%.*]] = insertelement <3 x double> poison, double [[X]], i32 0
; CHECK: [[VEC1:%.*]] = insertelement <3 x double> [[VEC0]], double [[Y]], i32 1
@@ -53,8 +57,8 @@ entry:
%a2.i = getelementptr inbounds nuw i8, ptr %dst, i32 16
store <3 x double> %a2, ptr %a2.i, align 8
- ; CHECK: [[CB:%.*]] = load target("dx.CBuffer", {{.*}})), ptr @CB.cb
- ; CHECK: [[LOAD:%.*]] = call { half, half, half, half, half, half, half, half } @llvm.dx.resource.load.cbufferrow.8.{{.*}}(target("dx.CBuffer", {{.*}})) [[CB]], i32 2)
+ ; CHECK: [[CB:%.*]] = load target("dx.CBuffer", %__cblayout_CB), ptr @CB.cb
+ ; CHECK: [[LOAD:%.*]] = call { half, half, half, half, half, half, half, half } @llvm.dx.resource.load.cbufferrow.8.{{.*}}(target("dx.CBuffer", %__cblayout_CB) [[CB]], i32 2)
; CHECK: [[X:%.*]] = extractvalue { half, half, half, half, half, half, half, half } [[LOAD]], 4
; CHECK: [[Y:%.*]] = extractvalue { half, half, half, half, half, half, half, half } [[LOAD]], 5
; CHECK: [[VEC0:%.*]] = insertelement <2 x half> poison, half [[X]], i32 0
@@ -65,11 +69,11 @@ entry:
%a3.i = getelementptr inbounds nuw i8, ptr %dst, i32 40
store <2 x half> %a3, ptr %a3.i, align 2
- ; CHECK: [[CB:%.*]] = load target("dx.CBuffer", {{.*}})), ptr @CB.cb
- ; CHECK: [[LOAD:%.*]] = call { i64, i64 } @llvm.dx.resource.load.cbufferrow.2.{{.*}}(target("dx.CBuffer", {{.*}})) [[CB]], i32 3)
+ ; CHECK: [[CB:%.*]] = load target("dx.CBuffer", %__cblayout_CB), ptr @CB.cb
+ ; CHECK: [[LOAD:%.*]] = call { i64, i64 } @llvm.dx.resource.load.cbufferrow.2.{{.*}}(target("dx.CBuffer", %__cblayout_CB) [[CB]], i32 3)
; CHECK: [[X:%.*]] = extractvalue { i64, i64 } [[LOAD]], 0
; CHECK: [[Y:%.*]] = extractvalue { i64, i64 } [[LOAD]], 1
- ; CHECK: [[LOAD:%.*]] = call { i64, i64 } @llvm.dx.resource.load.cbufferrow.2.{{.*}}(target("dx.CBuffer", {{.*}})) [[CB]], i32 4)
+ ; CHECK: [[LOAD:%.*]] = call { i64, i64 } @llvm.dx.resource.load.cbufferrow.2.{{.*}}(target("dx.CBuffer", %__cblayout_CB) [[CB]], i32 4)
; CHECK: [[Z:%.*]] = extractvalue { i64, i64 } [[LOAD]], 0
; CHECK: [[VEC0:%.*]] = insertelement <3 x i64> poison, i64 [[X]], i32 0
; CHECK: [[VEC1:%.*]] = insertelement <3 x i64> [[VEC0]], i64 [[Y]], i32 1
@@ -80,8 +84,8 @@ entry:
%a4.i = getelementptr inbounds nuw i8, ptr %dst, i32 48
store <3 x i64> %a4, ptr %a4.i, align 8
- ; CHECK: [[CB:%.*]] = load target("dx.CBuffer", {{.*}})), ptr @CB.cb
- ; CHECK: [[LOAD:%.*]] = call { i32, i32, i32, i32 } @llvm.dx.resource.load.cbufferrow.4.{{.*}}(target("dx.CBuffer", {{.*}})) [[CB]], i32 5)
+ ; CHECK: [[CB:%.*]] = load target("dx.CBuffer", %__cblayout_CB), ptr @CB.cb
+ ; CHECK: [[LOAD:%.*]] = call { i32, i32, i32, i32 } @llvm.dx.resource.load.cbufferrow.4.{{.*}}(target("dx.CBuffer", %__cblayout_CB) [[CB]], i32 5)
; CHECK: [[X:%.*]] = extractvalue { i32, i32, i32, i32 } [[LOAD]], 0
; CHECK: [[Y:%.*]] = extractvalue { i32, i32, i32, i32 } [[LOAD]], 1
; CHECK: [[Z:%.*]] = extractvalue { i32, i32, i32, i32 } [[LOAD]], 2
@@ -96,8 +100,8 @@ entry:
%a5.i = getelementptr inbounds nuw i8, ptr %dst, i32 72
store <4 x i32> %a5, ptr %a5.i, align 4
- ; CHECK: [[CB:%.*]] = load target("dx.CBuffer", {{.*}})), ptr @CB.cb
- ; CHECK: [[LOAD:%.*]] = call { i16, i16, i16, i16, i16, i16, i16, i16 } @llvm.dx.resource.load.cbufferrow.8.{{.*}}(target("dx.CBuffer", {{.*}})) [[CB]], i32 6)
+ ; CHECK: [[CB:%.*]] = load target("dx.CBuffer", %__cblayout_CB), ptr @CB.cb
+ ; CHECK: [[LOAD:%.*]] = call { i16, i16, i16, i16, i16, i16, i16, i16 } @llvm.dx.resource.load.cbufferrow.8.{{.*}}(target("dx.CBuffer", %__cblayout_CB) [[CB]], i32 6)
; CHECK: [[X:%.*]] = extractvalue { i16, i16, i16, i16, i16, i16, i16, i16 } [[LOAD]], 0
; CHECK: [[Y:%.*]] = extractvalue { i16, i16, i16, i16, i16, i16, i16, i16 } [[LOAD]], 1
; CHECK: [[Z:%.*]] = extractvalue { i16, i16, i16, i16, i16, i16, i16, i16 } [[LOAD]], 2
>From db5ebb843a5ed8008be2d82384f51ec96559b828 Mon Sep 17 00:00:00 2001
From: Justin Bogner <mail at justinbogner.com>
Date: Tue, 19 Aug 2025 13:23:42 -0600
Subject: [PATCH 03/11] wip: Hack in 3-element vector alignments
---
clang/lib/Basic/Targets/DirectX.h | 4 +++-
clang/test/CodeGenHLSL/basic-target.c | 2 +-
llvm/lib/Target/DirectX/DirectXTargetMachine.cpp | 4 +++-
llvm/test/CodeGen/DirectX/CBufferAccess/arrays.ll | 4 ----
4 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/clang/lib/Basic/Targets/DirectX.h b/clang/lib/Basic/Targets/DirectX.h
index bd13c9ee0fd05..c47a84bc80ac2 100644
--- a/clang/lib/Basic/Targets/DirectX.h
+++ b/clang/lib/Basic/Targets/DirectX.h
@@ -65,7 +65,9 @@ class LLVM_LIBRARY_VISIBILITY DirectXTargetInfo : public TargetInfo {
PlatformMinVersion = Triple.getOSVersion();
PlatformName = llvm::Triple::getOSTypeName(Triple.getOS());
resetDataLayout("e-m:e-p:32:32-i1:32-i8:8-i16:16-i32:32-i64:64-f16:16-f32:"
- "32-f64:64-n8:16:32:64");
+ "32-f64:64-n8:16:32:64"
+ // HACK: 3-element vectors
+ "-v48:16:16-v96:32:32-v192:64:64");
TheCXXABI.set(TargetCXXABI::GenericItanium);
}
bool useFP16ConversionIntrinsics() const override { return false; }
diff --git a/clang/test/CodeGenHLSL/basic-target.c b/clang/test/CodeGenHLSL/basic-target.c
index c700e06bd5850..b9482df5a0987 100644
--- a/clang/test/CodeGenHLSL/basic-target.c
+++ b/clang/test/CodeGenHLSL/basic-target.c
@@ -6,5 +6,5 @@
// RUN: %clang -cc1 -triple dxil-pc-shadermodel6.0-domain -emit-llvm -o - %s | FileCheck %s
// RUN: %clang -cc1 -triple dxil-pc-shadermodel6.0-geometry -emit-llvm -o - %s | FileCheck %s
-// CHECK: target datalayout = "e-m:e-p:32:32-i1:32-i8:8-i16:16-i32:32-i64:64-f16:16-f32:32-f64:64-n8:16:32:64"
+// CHECK: target datalayout = "e-m:e-p:32:32-i1:32-i8:8-i16:16-i32:32-i64:64-f16:16-f32:32-f64:64-n8:16:32:64-v48:16:16-v96:32:32-v192:64:64"
// CHECK: target triple = "dxilv1.0-pc-shadermodel6.0-{{[a-z]+}}"
diff --git a/llvm/lib/Target/DirectX/DirectXTargetMachine.cpp b/llvm/lib/Target/DirectX/DirectXTargetMachine.cpp
index f5d5a73c926e9..af814cc01995c 100644
--- a/llvm/lib/Target/DirectX/DirectXTargetMachine.cpp
+++ b/llvm/lib/Target/DirectX/DirectXTargetMachine.cpp
@@ -137,7 +137,9 @@ DirectXTargetMachine::DirectXTargetMachine(const Target &T, const Triple &TT,
: CodeGenTargetMachineImpl(
T,
"e-m:e-p:32:32-i1:32-i8:8-i16:16-i32:32-i64:64-f16:16-"
- "f32:32-f64:64-n8:16:32:64",
+ "f32:32-f64:64-n8:16:32:64"
+ // HACK: 3-element vectors
+ "-v48:16:16-v96:32:32-v192:64:64",
TT, CPU, FS, Options, Reloc::Static, CodeModel::Small, OL),
TLOF(std::make_unique<DXILTargetObjectFile>()),
Subtarget(std::make_unique<DirectXSubtarget>(TT, CPU, FS, *this)) {
diff --git a/llvm/test/CodeGen/DirectX/CBufferAccess/arrays.ll b/llvm/test/CodeGen/DirectX/CBufferAccess/arrays.ll
index 1bdb27d736783..e10a809e33be3 100644
--- a/llvm/test/CodeGen/DirectX/CBufferAccess/arrays.ll
+++ b/llvm/test/CodeGen/DirectX/CBufferAccess/arrays.ll
@@ -1,9 +1,5 @@
; RUN: opt -S -dxil-cbuffer-access -mtriple=dxil--shadermodel6.3-library %s | FileCheck %s
-; TODO: Remove datalayout.
-; This hack forces dxil-compatible alignment of 3-element 32- and 64-bit vectors
-target datalayout = "e-m:e-p:32:32-i1:32-i8:8-i16:16-i32:32-i64:64-f16:16-f32:32-f64:64-n8:16:32:64-v96:32:32-v192:64:64"
-
; cbuffer CB : register(b0) {
; float a1[3]; // offset 0, size 4 (+12) * 3
; double3 a2[2]; // offset 48, size 24 (+8) * 2
>From 02c16b65ddbaa253cd09eb7c4b0c5c9715100ab8 Mon Sep 17 00:00:00 2001
From: Justin Bogner <mail at justinbogner.com>
Date: Wed, 11 Jun 2025 11:09:21 -0400
Subject: [PATCH 04/11] wip: Use explicit padding for cbuffer structs
This abandons the `dx.Layout` idea and just uses explicit padding.
Note: this doesn't really work as is. Since the AST still has everything
represented as standard types without the padding, various places will
create GEPs with the wrong offsets and we fail to clean these up. We
need to move some of this logic into Sema and the AST itself.
There are a couple of other things on top of that:
- We can't/shouldn't just use `i8` arrays - we need something explicit.
- The algorithm to add padding in HLSLBufferLayoutBuilder is hacky.
- Reordered fields break stuff, including ones from implicit bindings.
---
clang/lib/CodeGen/CGHLSLRuntime.cpp | 28 +-
clang/lib/CodeGen/CGHLSLRuntime.h | 7 +-
clang/lib/CodeGen/HLSLBufferLayoutBuilder.cpp | 201 +++++++--------
clang/lib/CodeGen/HLSLBufferLayoutBuilder.h | 11 +-
clang/lib/CodeGen/Targets/DirectX.cpp | 7 +-
clang/lib/CodeGen/Targets/SPIR.cpp | 7 +-
clang/test/CodeGenHLSL/ArrayAssignable.hlsl | 10 +-
.../GlobalConstructorFunction.hlsl | 6 +-
clang/test/CodeGenHLSL/resources/cbuffer.hlsl | 244 +++++++++++-------
.../resources/cbuffer_and_namespaces.hlsl | 10 +-
.../resources/cbuffer_with_packoffset.hlsl | 13 +-
...uffer_with_static_global_and_function.hlsl | 2 +-
.../resources/default_cbuffer.hlsl | 11 +-
.../default_cbuffer_with_layout.hlsl | 3 +
14 files changed, 308 insertions(+), 252 deletions(-)
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index d27f3781c69a3..19d6c180e0ed4 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -265,9 +265,9 @@ CGHLSLRuntime::convertHLSLSpecificType(const Type *T,
assert(T->isHLSLSpecificType() && "Not an HLSL specific type!");
// Check if the target has a specific translation for this type first.
- if (llvm::Type *TargetTy =
+ if (llvm::Type *LayoutTy =
CGM.getTargetCodeGenInfo().getHLSLType(CGM, T, Packoffsets))
- return TargetTy;
+ return LayoutTy;
llvm_unreachable("Generic handling of HLSL types is not supported.");
}
@@ -284,10 +284,8 @@ void CGHLSLRuntime::emitBufferGlobalsAndMetadata(const HLSLBufferDecl *BufDecl,
// get the layout struct from constant buffer target type
llvm::Type *BufType = BufGV->getValueType();
- llvm::Type *BufLayoutType =
- cast<llvm::TargetExtType>(BufType)->getTypeParameter(0);
llvm::StructType *LayoutStruct = cast<llvm::StructType>(
- cast<llvm::TargetExtType>(BufLayoutType)->getTypeParameter(0));
+ cast<llvm::TargetExtType>(BufType)->getTypeParameter(0));
// Start metadata list associating the buffer global variable with its
// constatns
@@ -326,6 +324,13 @@ void CGHLSLRuntime::emitBufferGlobalsAndMetadata(const HLSLBufferDecl *BufDecl,
continue;
}
+ // Skip padding.
+ // TODO: We should be more explicit here.
+ if (auto *ATy = dyn_cast<llvm::ArrayType>(*ElemIt))
+ if (auto *ITy = dyn_cast<llvm::IntegerType>(ATy->getElementType()))
+ if (ITy->getBitWidth() == 8)
+ ++ElemIt;
+
assert(ElemIt != LayoutStruct->element_end() &&
"number of elements in layout struct does not match");
llvm::Type *LayoutType = *ElemIt++;
@@ -423,12 +428,11 @@ void CGHLSLRuntime::addBuffer(const HLSLBufferDecl *BufDecl) {
if (BufDecl->hasValidPackoffset())
fillPackoffsetLayout(BufDecl, Layout);
- llvm::TargetExtType *TargetTy =
- cast<llvm::TargetExtType>(convertHLSLSpecificType(
- ResHandleTy, BufDecl->hasValidPackoffset() ? &Layout : nullptr));
+ llvm::Type *LayoutTy = convertHLSLSpecificType(
+ ResHandleTy, BufDecl->hasValidPackoffset() ? &Layout : nullptr);
llvm::GlobalVariable *BufGV = new GlobalVariable(
- TargetTy, /*isConstant*/ false,
- GlobalValue::LinkageTypes::ExternalLinkage, PoisonValue::get(TargetTy),
+ LayoutTy, /*isConstant*/ false,
+ GlobalValue::LinkageTypes::ExternalLinkage, PoisonValue::get(LayoutTy),
llvm::formatv("{0}{1}", BufDecl->getName(),
BufDecl->isCBuffer() ? ".cb" : ".tb"),
GlobalValue::NotThreadLocal);
@@ -448,7 +452,7 @@ void CGHLSLRuntime::addBuffer(const HLSLBufferDecl *BufDecl) {
}
}
-llvm::TargetExtType *
+llvm::StructType *
CGHLSLRuntime::getHLSLBufferLayoutType(const RecordType *StructType) {
const auto Entry = LayoutTypes.find(StructType);
if (Entry != LayoutTypes.end())
@@ -457,7 +461,7 @@ CGHLSLRuntime::getHLSLBufferLayoutType(const RecordType *StructType) {
}
void CGHLSLRuntime::addHLSLBufferLayoutType(const RecordType *StructType,
- llvm::TargetExtType *LayoutTy) {
+ llvm::StructType *LayoutTy) {
assert(getHLSLBufferLayoutType(StructType) == nullptr &&
"layout type for this struct already exist");
LayoutTypes[StructType] = LayoutTy;
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h
index 0582be3d99ec4..814f6820858d9 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.h
+++ b/clang/lib/CodeGen/CGHLSLRuntime.h
@@ -161,10 +161,9 @@ class CGHLSLRuntime {
llvm::Instruction *getConvergenceToken(llvm::BasicBlock &BB);
- llvm::TargetExtType *
- getHLSLBufferLayoutType(const RecordType *LayoutStructTy);
+ llvm::StructType *getHLSLBufferLayoutType(const RecordType *LayoutStructTy);
void addHLSLBufferLayoutType(const RecordType *LayoutStructTy,
- llvm::TargetExtType *LayoutTy);
+ llvm::StructType *LayoutTy);
void emitInitListOpaqueValues(CodeGenFunction &CGF, InitListExpr *E);
std::optional<LValue>
@@ -182,7 +181,7 @@ class CGHLSLRuntime {
HLSLResourceBindingAttr *RBA);
llvm::Triple::ArchType getArch();
- llvm::DenseMap<const clang::RecordType *, llvm::TargetExtType *> LayoutTypes;
+ llvm::DenseMap<const clang::RecordType *, llvm::StructType *> LayoutTypes;
};
} // namespace CodeGen
diff --git a/clang/lib/CodeGen/HLSLBufferLayoutBuilder.cpp b/clang/lib/CodeGen/HLSLBufferLayoutBuilder.cpp
index 838903cdcd1ee..68866fd7bfac4 100644
--- a/clang/lib/CodeGen/HLSLBufferLayoutBuilder.cpp
+++ b/clang/lib/CodeGen/HLSLBufferLayoutBuilder.cpp
@@ -21,33 +21,45 @@ using namespace clang;
using namespace clang::CodeGen;
using llvm::hlsl::CBufferRowSizeInBytes;
-namespace {
-
-// Creates a new array type with the same dimentions but with the new
-// element type.
-static llvm::Type *
-createArrayWithNewElementType(CodeGenModule &CGM,
- const ConstantArrayType *ArrayType,
- llvm::Type *NewElemType) {
- const clang::Type *ArrayElemType = ArrayType->getArrayElementTypeNoTypeQual();
- if (ArrayElemType->isConstantArrayType())
- NewElemType = createArrayWithNewElementType(
- CGM, cast<const ConstantArrayType>(ArrayElemType), NewElemType);
- return llvm::ArrayType::get(NewElemType, ArrayType->getSExtSize());
-}
-
-// Returns the size of a scalar or vector in bytes
-static unsigned getScalarOrVectorSizeInBytes(llvm::Type *Ty) {
- assert(Ty->isVectorTy() || Ty->isIntegerTy() || Ty->isFloatingPointTy());
- if (Ty->isVectorTy()) {
- llvm::FixedVectorType *FVT = cast<llvm::FixedVectorType>(Ty);
- return FVT->getNumElements() *
- (FVT->getElementType()->getScalarSizeInBits() / 8);
+static unsigned getSizeForCBufferElement(const llvm::DataLayout &DL,
+ llvm::Type *Ty) {
+ // TODO: This is a hack, and it doesn't work for structs containing vectors.
+ // We need to get the DataLayout rules correct instead and simply use
+ // `getTypeSizeInBits(Ty) / 8` here.
+ switch (Ty->getTypeID()) {
+ case llvm::Type::ArrayTyID: {
+ llvm::ArrayType *ATy = cast<llvm::ArrayType>(Ty);
+ return ATy->getNumElements() *
+ getSizeForCBufferElement(DL, ATy->getElementType());
+ }
+ case llvm::Type::FixedVectorTyID: {
+ llvm::FixedVectorType *VTy = cast<llvm::FixedVectorType>(Ty);
+ return VTy->getNumElements() *
+ getSizeForCBufferElement(DL, VTy->getElementType());
+ }
+ default:
+ return DL.getTypeSizeInBits(Ty) / 8;
}
- return Ty->getScalarSizeInBits() / 8;
}
-} // namespace
+static llvm::Type *createCBufArrayType(llvm::LLVMContext &Context,
+ const llvm::DataLayout &DL,
+ llvm::Type *EltTy, unsigned ArrayCount) {
+ unsigned EltSize = getSizeForCBufferElement(DL, EltTy);
+ unsigned Padding = llvm::alignTo(EltSize, 16) - EltSize;
+ // If we don't have any padding between elements then we just need the array
+ // itself.
+ if (ArrayCount < 2 || !Padding)
+ return llvm::ArrayType::get(EltTy, ArrayCount);
+
+ auto *PaddingTy =
+ llvm::ArrayType::get(llvm::Type::getInt8Ty(Context), Padding);
+ auto *PaddedEltTy =
+ llvm::StructType::get(Context, {EltTy, PaddingTy}, /*isPacked=*/true);
+ return llvm::StructType::get(
+ Context, {llvm::ArrayType::get(PaddedEltTy, ArrayCount - 1), EltTy},
+ /*IsPacked=*/true);
+}
namespace clang {
namespace CodeGen {
@@ -59,31 +71,26 @@ namespace CodeGen {
// The function iterates over all fields of the record type (including base
// classes) and calls layoutField to converts each field to its corresponding
// LLVM type and to calculate its HLSL constant buffer layout. Any embedded
-// structs (or arrays of structs) are converted to target layout types as well.
+// structs (or arrays of structs) are converted to layout types as well.
//
// When PackOffsets are specified the elements will be placed based on the
// user-specified offsets. Not all elements must have a packoffset/register(c#)
// annotation though. For those that don't, the PackOffsets array will contain
// -1 value instead. These elements must be placed at the end of the layout
// after all of the elements with specific offset.
-llvm::TargetExtType *HLSLBufferLayoutBuilder::createLayoutType(
+llvm::StructType *HLSLBufferLayoutBuilder::createLayoutType(
const RecordType *RT, const llvm::SmallVector<int32_t> *PackOffsets) {
// check if we already have the layout type for this struct
- if (llvm::TargetExtType *Ty =
- CGM.getHLSLRuntime().getHLSLBufferLayoutType(RT))
+ if (llvm::StructType *Ty = CGM.getHLSLRuntime().getHLSLBufferLayoutType(RT))
return Ty;
- SmallVector<unsigned> Layout;
- SmallVector<llvm::Type *> LayoutElements;
+ SmallVector<std::pair<unsigned, llvm::Type *>> Layout;
unsigned Index = 0; // packoffset index
unsigned EndOffset = 0;
SmallVector<std::pair<const FieldDecl *, unsigned>> DelayLayoutFields;
- // reserve first spot in the layout vector for buffer size
- Layout.push_back(0);
-
// iterate over all fields of the record, including fields on base classes
llvm::SmallVector<CXXRecordDecl *> RecordDecls;
RecordDecls.push_back(RT->castAsCXXRecordDecl());
@@ -111,53 +118,52 @@ llvm::TargetExtType *HLSLBufferLayoutBuilder::createLayoutType(
if (!PackOffsets || PO != -1) {
if (!layoutField(FD, EndOffset, FieldOffset, FieldType, PO))
return nullptr;
- Layout.push_back(FieldOffset);
- LayoutElements.push_back(FieldType);
+ Layout.emplace_back(FieldOffset, FieldType);
continue;
}
// Have PackOffset info, but there is no packoffset/register(cX)
// annotation on this field. Delay the layout until after all of the
// other elements with packoffsets/register(cX) are processed.
- DelayLayoutFields.emplace_back(FD, LayoutElements.size());
+ DelayLayoutFields.emplace_back(FD, Layout.size());
// reserve space for this field in the layout vector and elements list
- Layout.push_back(UINT_MAX);
- LayoutElements.push_back(nullptr);
+ Layout.emplace_back(UINT_MAX, nullptr);
}
}
// process delayed layouts
for (auto I : DelayLayoutFields) {
const FieldDecl *FD = I.first;
- const unsigned IndexInLayoutElements = I.second;
- // the first item in layout vector is size, so we need to offset the index
- // by 1
- const unsigned IndexInLayout = IndexInLayoutElements + 1;
- assert(Layout[IndexInLayout] == UINT_MAX &&
- LayoutElements[IndexInLayoutElements] == nullptr);
+ assert(Layout[I.second] == std::pair(UINT_MAX, nullptr));
if (!layoutField(FD, EndOffset, FieldOffset, FieldType))
return nullptr;
- Layout[IndexInLayout] = FieldOffset;
- LayoutElements[IndexInLayoutElements] = FieldType;
+ Layout[I.second] = {FieldOffset, FieldType};
}
- // set the size of the buffer
- Layout[0] = EndOffset;
+ // TODO: Just do this as we go above...
+ // Work out padding so we can create a packed struct for the entire layout.
+ SmallVector<llvm::Type *> PaddedElements;
+ unsigned CurOffset = 0;
+ const llvm::DataLayout &DL = CGM.getDataLayout();
+ llvm::Type *PaddingType = llvm::Type::getInt8Ty(CGM.getLLVMContext());
+ for (const auto &[Offset, Element] : Layout) {
+ assert(Offset >= CurOffset && "Layout out of order?");
+ if (unsigned Padding = Offset - CurOffset)
+ PaddedElements.push_back(llvm::ArrayType::get(PaddingType, Padding));
+ PaddedElements.push_back(Element);
+ CurOffset = Offset + getSizeForCBufferElement(DL, Element);
+ }
- // create the layout struct type; anonymous struct have empty name but
+ // Create the layout struct type; anonymous structs have empty name but
// non-empty qualified name
const auto *Decl = RT->castAsCXXRecordDecl();
std::string Name =
Decl->getName().empty() ? "anon" : Decl->getQualifiedNameAsString();
- llvm::StructType *StructTy =
- llvm::StructType::create(LayoutElements, Name, true);
-
- // create target layout type
- llvm::TargetExtType *NewLayoutTy = llvm::TargetExtType::get(
- CGM.getLLVMContext(), LayoutTypeName, {StructTy}, Layout);
- if (NewLayoutTy)
- CGM.getHLSLRuntime().addHLSLBufferLayoutType(RT, NewLayoutTy);
- return NewLayoutTy;
+
+ llvm::StructType *NewTy = llvm::StructType::create(PaddedElements, Name,
+ /*isPacked=*/true);
+ CGM.getHLSLRuntime().addHLSLBufferLayoutType(RT, NewTy);
+ return NewTy;
}
// The function converts a single field of HLSL Buffer to its corresponding
@@ -174,98 +180,79 @@ llvm::TargetExtType *HLSLBufferLayoutBuilder::createLayoutType(
bool HLSLBufferLayoutBuilder::layoutField(const FieldDecl *FD,
unsigned &EndOffset,
unsigned &FieldOffset,
- llvm::Type *&FieldType,
+ llvm::Type *&FieldLayoutTy,
int Packoffset) {
-
- // Size of element; for arrays this is a size of a single element in the
- // array. Total array size of calculated as (ArrayCount-1) * ArrayStride +
- // ElemSize.
- unsigned ElemSize = 0;
- unsigned ElemOffset = 0;
- unsigned ArrayCount = 1;
- unsigned ArrayStride = 0;
-
unsigned NextRowOffset = llvm::alignTo(EndOffset, CBufferRowSizeInBytes);
+ unsigned FieldSize;
- llvm::Type *ElemLayoutTy = nullptr;
QualType FieldTy = FD->getType();
if (FieldTy->isConstantArrayType()) {
// Unwrap array to find the element type and get combined array size.
QualType Ty = FieldTy;
+ unsigned ArrayCount = 1;
while (Ty->isConstantArrayType()) {
auto *ArrayTy = CGM.getContext().getAsConstantArrayType(Ty);
ArrayCount *= ArrayTy->getSExtSize();
Ty = ArrayTy->getElementType();
}
- // For array of structures, create a new array with a layout type
- // instead of the structure type.
+
+ llvm::Type *NewTy;
if (Ty->isStructureOrClassType()) {
- llvm::Type *NewTy = cast<llvm::TargetExtType>(
- createLayoutType(Ty->getAsCanonical<RecordType>()));
+ NewTy = createLayoutType(Ty->getAsCanonical<RecordType>());
if (!NewTy)
return false;
- assert(isa<llvm::TargetExtType>(NewTy) && "expected target type");
- ElemSize = cast<llvm::TargetExtType>(NewTy)->getIntParameter(0);
- ElemLayoutTy = createArrayWithNewElementType(
- CGM, cast<ConstantArrayType>(FieldTy.getTypePtr()), NewTy);
- } else {
- // Array of vectors or scalars
- ElemSize =
- getScalarOrVectorSizeInBytes(CGM.getTypes().ConvertTypeForMem(Ty));
- ElemLayoutTy = CGM.getTypes().ConvertTypeForMem(FieldTy);
- }
- ArrayStride = llvm::alignTo(ElemSize, CBufferRowSizeInBytes);
- ElemOffset = (Packoffset != -1) ? Packoffset : NextRowOffset;
+ } else
+ NewTy = CGM.getTypes().ConvertTypeForMem(Ty);
+
+ FieldLayoutTy = createCBufArrayType(CGM.getLLVMContext(),
+ CGM.getDataLayout(), NewTy, ArrayCount);
+ FieldOffset = (Packoffset != -1) ? Packoffset : NextRowOffset;
+ FieldSize = CGM.getDataLayout().getTypeSizeInBits(FieldLayoutTy) / 8;
} else if (FieldTy->isStructureOrClassType()) {
// Create a layout type for the structure
- ElemLayoutTy = createLayoutType(
+ FieldLayoutTy = createLayoutType(
cast<RecordType>(FieldTy->getAsCanonical<RecordType>()));
- if (!ElemLayoutTy)
+ if (!FieldLayoutTy)
return false;
- assert(isa<llvm::TargetExtType>(ElemLayoutTy) && "expected target type");
- ElemSize = cast<llvm::TargetExtType>(ElemLayoutTy)->getIntParameter(0);
- ElemOffset = (Packoffset != -1) ? Packoffset : NextRowOffset;
+ FieldOffset = (Packoffset != -1) ? Packoffset : NextRowOffset;
+ FieldSize = CGM.getDataLayout().getTypeSizeInBits(FieldLayoutTy) / 8;
} else {
// scalar or vector - find element size and alignment
unsigned Align = 0;
- ElemLayoutTy = CGM.getTypes().ConvertTypeForMem(FieldTy);
- if (ElemLayoutTy->isVectorTy()) {
+ FieldLayoutTy = CGM.getTypes().ConvertTypeForMem(FieldTy);
+ if (FieldLayoutTy->isVectorTy()) {
// align vectors by sub element size
- const llvm::FixedVectorType *FVT =
- cast<llvm::FixedVectorType>(ElemLayoutTy);
+ const auto *FVT = cast<llvm::FixedVectorType>(FieldLayoutTy);
unsigned SubElemSize = FVT->getElementType()->getScalarSizeInBits() / 8;
- ElemSize = FVT->getNumElements() * SubElemSize;
+ FieldSize = FVT->getNumElements() * SubElemSize;
Align = SubElemSize;
} else {
- assert(ElemLayoutTy->isIntegerTy() || ElemLayoutTy->isFloatingPointTy());
- ElemSize = ElemLayoutTy->getScalarSizeInBits() / 8;
- Align = ElemSize;
+ assert(FieldLayoutTy->isIntegerTy() ||
+ FieldLayoutTy->isFloatingPointTy());
+ FieldSize = FieldLayoutTy->getScalarSizeInBits() / 8;
+ Align = FieldSize;
}
// calculate or get element offset for the vector or scalar
if (Packoffset != -1) {
- ElemOffset = Packoffset;
+ FieldOffset = Packoffset;
} else {
- ElemOffset = llvm::alignTo(EndOffset, Align);
+ FieldOffset = llvm::alignTo(EndOffset, Align);
// if the element does not fit, move it to the next row
- if (ElemOffset + ElemSize > NextRowOffset)
- ElemOffset = NextRowOffset;
+ if (FieldOffset + FieldSize > NextRowOffset)
+ FieldOffset = NextRowOffset;
}
}
// Update end offset of the layout; do not update it if the EndOffset
// is already bigger than the new value (which may happen with unordered
// packoffset annotations)
- unsigned NewEndOffset =
- ElemOffset + (ArrayCount - 1) * ArrayStride + ElemSize;
+ unsigned NewEndOffset = FieldOffset + FieldSize;
EndOffset = std::max<unsigned>(EndOffset, NewEndOffset);
- // add the layout element and offset to the lists
- FieldOffset = ElemOffset;
- FieldType = ElemLayoutTy;
return true;
}
diff --git a/clang/lib/CodeGen/HLSLBufferLayoutBuilder.h b/clang/lib/CodeGen/HLSLBufferLayoutBuilder.h
index 61240b280cfcb..90ccba0801d79 100644
--- a/clang/lib/CodeGen/HLSLBufferLayoutBuilder.h
+++ b/clang/lib/CodeGen/HLSLBufferLayoutBuilder.h
@@ -24,16 +24,13 @@ class CodeGenModule;
class HLSLBufferLayoutBuilder {
private:
CodeGenModule &CGM;
- llvm::StringRef LayoutTypeName;
public:
- HLSLBufferLayoutBuilder(CodeGenModule &CGM, llvm::StringRef LayoutTypeName)
- : CGM(CGM), LayoutTypeName(LayoutTypeName) {}
+ HLSLBufferLayoutBuilder(CodeGenModule &CGM) : CGM(CGM) {}
- // Returns LLVM target extension type with the name LayoutTypeName
- // for given structure type and layout data. The first number in
- // the Layout is the size followed by offsets for each struct element.
- llvm::TargetExtType *
+ // Returns an explicitly padded type for the given structure type and layout
+ // data.
+ llvm::StructType *
createLayoutType(const RecordType *StructType,
const llvm::SmallVector<int32_t> *Packoffsets = nullptr);
diff --git a/clang/lib/CodeGen/Targets/DirectX.cpp b/clang/lib/CodeGen/Targets/DirectX.cpp
index b4cebb9a32aca..c621fb3dd711b 100644
--- a/clang/lib/CodeGen/Targets/DirectX.cpp
+++ b/clang/lib/CodeGen/Targets/DirectX.cpp
@@ -75,10 +75,9 @@ llvm::Type *DirectXTargetCodeGenInfo::getHLSLType(
if (ContainedTy.isNull() || !ContainedTy->isStructureType())
return nullptr;
- llvm::Type *BufferLayoutTy =
- HLSLBufferLayoutBuilder(CGM, "dx.Layout")
- .createLayoutType(ContainedTy->castAsCanonical<RecordType>(),
- Packoffsets);
+ llvm::StructType *BufferLayoutTy =
+ HLSLBufferLayoutBuilder(CGM).createLayoutType(
+ ContainedTy->getAsCanonical<RecordType>(), Packoffsets);
if (!BufferLayoutTy)
return nullptr;
diff --git a/clang/lib/CodeGen/Targets/SPIR.cpp b/clang/lib/CodeGen/Targets/SPIR.cpp
index 53806249ded60..66efeb3bfcd36 100644
--- a/clang/lib/CodeGen/Targets/SPIR.cpp
+++ b/clang/lib/CodeGen/Targets/SPIR.cpp
@@ -498,10 +498,9 @@ llvm::Type *CommonSPIRTargetCodeGenInfo::getHLSLType(
if (ContainedTy.isNull() || !ContainedTy->isStructureType())
return nullptr;
- llvm::Type *BufferLayoutTy =
- HLSLBufferLayoutBuilder(CGM, "spirv.Layout")
- .createLayoutType(ContainedTy->castAsCanonical<RecordType>(),
- Packoffsets);
+ llvm::StructType *BufferLayoutTy =
+ HLSLBufferLayoutBuilder(CGM).createLayoutType(
+ ContainedTy->getAsCanonical<RecordType>(), Packoffsets);
uint32_t StorageClass = /* Uniform storage class */ 2;
return llvm::TargetExtType::get(Ctx, "spirv.VulkanBuffer", {BufferLayoutTy},
{StorageClass, false});
diff --git a/clang/test/CodeGenHLSL/ArrayAssignable.hlsl b/clang/test/CodeGenHLSL/ArrayAssignable.hlsl
index aaa486eff10b7..721721f123ad0 100644
--- a/clang/test/CodeGenHLSL/ArrayAssignable.hlsl
+++ b/clang/test/CodeGenHLSL/ArrayAssignable.hlsl
@@ -5,12 +5,12 @@ struct S {
float f;
};
-// CHECK: [[CBLayout:%.*]] = type <{ [2 x float], [2 x <4 x i32>], [2 x [2 x i32]], [1 x target("dx.Layout", %S, 8, 0, 4)] }>
-// CHECK: @CBArrays.cb = global target("dx.CBuffer", target("dx.Layout", [[CBLayout]], 136, 0, 32, 64, 128))
-// CHECK: @c1 = external hidden addrspace(2) global [2 x float], align 4
+// CHECK: [[CBLayout:%.*]] = type <{ <{ [1 x <{ float, [12 x i8] }>], float }>, [12 x i8], [2 x <4 x i32>], <{ [3 x <{ i32, [12 x i8] }>], i32 }>, [12 x i8], [1 x %S] }>
+// CHECK: @CBArrays.cb = global target("dx.CBuffer", [[CBLayout]])
+// CHECK: @c1 = external hidden addrspace(2) global <{ [1 x <{ float, [12 x i8] }>], float }>, align 4
// CHECK: @c2 = external hidden addrspace(2) global [2 x <4 x i32>], align 16
-// CHECK: @c3 = external hidden addrspace(2) global [2 x [2 x i32]], align 4
-// CHECK: @c4 = external hidden addrspace(2) global [1 x target("dx.Layout", %S, 8, 0, 4)], align 1
+// CHECK: @c3 = external hidden addrspace(2) global <{ [3 x <{ i32, [12 x i8] }>], i32 }>, align 4
+// CHECK: @c4 = external hidden addrspace(2) global [1 x %S], align 1
cbuffer CBArrays : register(b0) {
float c1[2];
diff --git a/clang/test/CodeGenHLSL/GlobalConstructorFunction.hlsl b/clang/test/CodeGenHLSL/GlobalConstructorFunction.hlsl
index b36682e065b3a..df82e8201ba55 100644
--- a/clang/test/CodeGenHLSL/GlobalConstructorFunction.hlsl
+++ b/clang/test/CodeGenHLSL/GlobalConstructorFunction.hlsl
@@ -37,9 +37,9 @@ void main(unsigned GI : SV_GroupIndex) {}
// INLINE-NEXT: alloca
// INLINE-NEXT: store i32 12
// INLINE-NEXT: store i32 13
-// INLINE-NEXT: %[[HANDLE:.*]] = call target("dx.CBuffer", target("dx.Layout", %"__cblayout_$Globals", 4, 0))
-// INLINE-NEXT-SAME: @"llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_tdx.Layout_s___cblayout_$Globalss_4_0tt"(i32 0, i32 0, i32 1, i32 0, i1 false)
-// INLINE-NEXT: store target("dx.CBuffer", target("dx.Layout", %"__cblayout_$Globals", 4, 0)) %[[HANDLE]], ptr @"$Globals.cb", align 4
+// INLINE-NEXT: %[[HANDLE:.*]] = call target("dx.CBuffer", %"__cblayout_$Globals")
+// INLINE-NEXT-SAME: @"llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_s___cblayout_$Globalsst"(i32 0, i32 0, i32 1, i32 0, i1 false, ptr @"$Globals.str")
+// INLINE-NEXT: store target("dx.CBuffer", %"__cblayout_$Globals") %[[HANDLE]], ptr @"$Globals.cb", align 4
// INLINE-NEXT: %0 = call i32 @llvm.dx.flattened.thread.id.in.group()
// INLINE-NEXT: store i32 %
// INLINE-NEXT: store i32 0
diff --git a/clang/test/CodeGenHLSL/resources/cbuffer.hlsl b/clang/test/CodeGenHLSL/resources/cbuffer.hlsl
index 8dcff5dad9d13..7733dd0739c9f 100644
--- a/clang/test/CodeGenHLSL/resources/cbuffer.hlsl
+++ b/clang/test/CodeGenHLSL/resources/cbuffer.hlsl
@@ -1,37 +1,110 @@
// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.3-compute -fnative-half-type -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s
-// CHECK: %__cblayout_CBScalars = type <{ float, double, half, i64, i32, i16, i32, i64 }>
-// CHECK: %__cblayout_CBVectors = type <{ <3 x float>, <3 x double>, <2 x half>, <3 x i64>, <4 x i32>, <3 x i16>, <3 x i64> }>
-// CHECK: %__cblayout_CBArrays = type <{ [3 x float], [2 x <3 x double>], [2 x [2 x half]], [3 x i64], [2 x [3 x [4 x <4 x i32>]]], [1 x i16], [2 x i64], [4 x i32] }>
-// CHECK: %__cblayout_CBStructs = type <{ target("dx.Layout", %A, 8, 0), target("dx.Layout", %B, 14, 0, 8),
-// CHECK-SAME: target("dx.Layout", %C, 24, 0, 16), [5 x target("dx.Layout", %A, 8, 0)],
-// CHECK-SAME: target("dx.Layout", %__cblayout_D, 94, 0), half, <3 x i16> }>
+// CHECK: %__cblayout_CBScalars = type <{
+// CHECK-SAME: float, [4 x i8], double,
+// CHECK-SAME: half, [6 x i8], i64,
+// CHECK-SAME: i32, i16, [2 x i8], i32, [4 x i8],
+// CHECK-SAME: i64
+// CHECK-SAME: }>
+
+// CHECK: %__cblayout_CBVectors = type <{
+// CHECK-SAME: <3 x float>, [4 x i8],
+// CHECK-SAME: <3 x double>, <2 x half>, [4 x i8],
+// CHECK-SAME: <3 x i64>, [8 x i8],
+// CHECK-SAME: <4 x i32>,
+// CHECK-SAME: <3 x i16>, [10 x i8],
+// CHECK-SAME: <3 x i64>
+// CHECK-SAME: }>
+
+// CHECK: %__cblayout_CBArrays = type <{
+// CHECK-SAME: <{ [2 x <{ float, [12 x i8] }>], float }>, [12 x i8],
+// CHECK-SAME: <{ [1 x <{ <3 x double>, [8 x i8] }>], <3 x double> }>, [8 x i8],
+// CHECK-SAME: <{ [3 x <{ half, [14 x i8] }>], half }>, [14 x i8],
+// CHECK-SAME: <{ [2 x <{ i64, [8 x i8] }>], i64 }>, [8 x i8],
+// CHECK-SAME: [24 x <4 x i32>]
+// CHECK-SAME: [1 x i16], [14 x i8],
+// CHECK-SAME: <{ [1 x <{ i64, [8 x i8] }>], i64 }>, [8 x i8],
+// CHECK-SAME: <{ [3 x <{ i32, [12 x i8] }>], i32 }>
+// CHECK-SAME: }>
+
+// CHECK: %__cblayout_CBStructs = type <{
+// CHECK-SAME: %A, [8 x i8],
+
+// TODO: We should have [2 x i8] padding after %B, but we don't correctly handle
+// 2- and 3-element vectors inside structs yet because of DataLayout rules.
+// CHECK-SAME: %B,
+
+// CHECK-SAME: %C, [8 x i8],
+// CHECK-SAME: <{ [4 x <{ %A, [8 x i8] }>], %A }>, [8 x i8],
+// CHECK-SAME: %__cblayout_D, half,
+// CHECK-SAME: <3 x i16>
+// CHECK-SAME: }>
// CHECK: %A = type <{ <2 x float> }>
// CHECK: %B = type <{ <2 x float>, <3 x i16> }>
-// CHECK: %C = type <{ i32, target("dx.Layout", %A, 8, 0) }>
-// CHECK: %__cblayout_D = type <{ [2 x [3 x target("dx.Layout", %B, 14, 0, 8)]] }>
+// CHECK: %C = type <{ i32, [12 x i8], %A }>
+
+// CHECK: %__cblayout_D = type <{ <{ [5 x <{ %B, [2 x i8] }>], %B }> }>
+
+// CHECK: %__cblayout_CBClasses = type <{
+// CHECK-SAME: %K, [12 x i8],
+// CHECK-SAME: %L, [8 x i8],
+// CHECK-SAME: %M, [12 x i8],
+// CHECK-SAME: <{ [9 x <{ %K, [12 x i8] }>], %K }>
+// CHECK-SAME: }>
-// CHECK: %__cblayout_CBClasses = type <{ target("dx.Layout", %K, 4, 0), target("dx.Layout", %L, 8, 0, 4),
-// CHECK-SAME: target("dx.Layout", %M, 68, 0), [10 x target("dx.Layout", %K, 4, 0)] }>
// CHECK: %K = type <{ float }>
// CHECK: %L = type <{ float, float }>
-// CHECK: %M = type <{ [5 x target("dx.Layout", %K, 4, 0)] }>
+// CHECK: %M = type <{ <{ [4 x <{ %K, [12 x i8] }>], %K }> }>
-// CHECK: %__cblayout_CBMix = type <{ [2 x target("dx.Layout", %Test, 8, 0, 4)], float, [3 x [2 x <2 x float>]], float,
-// CHECK-SAME: target("dx.Layout", %anon, 4, 0), double, target("dx.Layout", %anon.0, 8, 0), float, <1 x double>, i16 }>
+// CHECK: %__cblayout_CBMix = type <{
+// CHECK-SAME: <{ [1 x <{ %Test, [8 x i8] }>], %Test }>, float, [4 x i8]
+// CHECK-SAME: <{ [5 x <{ <2 x float>, [8 x i8] }>], <2 x float> }>, float, [4 x i8],
+// CHECK-SAME: %anon, [4 x i8], double,
+// CHECK-SAME: %anon.0, float, [4 x i8],
+// CHECK-SAME: <1 x double>, i16
+// CHECK-SAME: }>
// CHECK: %Test = type <{ float, float }>
// CHECK: %anon = type <{ float }>
// CHECK: %anon.0 = type <{ <2 x i32> }>
-// CHECK: %__cblayout_CB_A = type <{ [2 x double], [3 x <3 x float>], float, [3 x double], half, [1 x <2 x double>], float, [2 x <3 x half>], <3 x half> }>
-// CHECK: %__cblayout_CB_B = type <{ [3 x <3 x double>], <3 x half> }>
-// CHECK: %__cblayout_CB_C = type <{ i32, target("dx.Layout", %F, 96, 0, 16, 28, 32, 56, 64, 80, 84, 90), half, target("dx.Layout", %G, 258, 0, 48, 64, 256), double }>
-
-// CHECK: %F = type <{ double, <3 x float>, float, <3 x double>, half, <2 x double>, float, <3 x half>, <3 x half> }>
-// CHECK: %G = type <{ target("dx.Layout", %E, 36, 0, 8, 16, 20, 22, 24, 32), [1 x float], [2 x target("dx.Layout", %F, 96, 0, 16, 28, 32, 56, 64, 80, 84, 90)], half }>
-// CHECK: %E = type <{ float, double, float, half, i16, i64, i32 }>
+// CHECK: %__cblayout_CB_A = type <{
+// CHECK-SAME: <{ [1 x <{ double, [8 x i8] }>], double }>, [8 x i8],
+// CHECK-SAME: <{ [2 x <{ <3 x float>, [4 x i8] }>], <3 x float> }>, float,
+// CHECK-SAME: <{ [2 x <{ double, [8 x i8] }>], double }>, half, [6 x i8],
+// CHECK-SAME: [1 x <2 x double>],
+// CHECK-SAME: float, [12 x i8],
+// CHECK-SAME: <{ [1 x <{ <3 x half>, [10 x i8] }>], <3 x half> }>, <3 x half>
+// CHECK-SAME: }>
+
+// CHECK: %__cblayout_CB_B = type <{
+// CHECK-SAME: <{ [2 x <{ <3 x double>, [8 x i8] }>], <3 x double> }>, <3 x half>
+// CHECK-SAME: }>
+
+// CHECK: %__cblayout_CB_C = type <{
+// CHECK-SAME: i32, [12 x i8],
+// CHECK-SAME: %F,
+// CHECK-SAME: half, [14 x i8],
+// CHECK-SAME: %G, [6 x i8], double
+// CHECK-SAME: }>
+
+// CHECK: %F = type <{
+// CHECK-SAME: double, [8 x i8],
+// CHECK-SAME: <3 x float>, float,
+// CHECK-SAME: <3 x double>, half, [6 x i8],
+// CHECK-SAME: <2 x double>,
+// CHECK-SAME: float, <3 x half>, <3 x half>
+// CHECK-SAME: }>
+
+// CHECK: %G = type <{
+// CHECK-SAME: %E, [12 x i8],
+// CHECK-SAME: [1 x float], [12 x i8],
+// CHECK-SAME: [2 x %F],
+// CHECK-SAME: half
+// CHECK-SAME: }>
+
+// CHECK: %E = type <{ float, [4 x i8], double, float, half, i16, i64, i32 }>
cbuffer CBScalars : register(b1, space5) {
float a1;
@@ -44,8 +117,7 @@ cbuffer CBScalars : register(b1, space5) {
int64_t a8;
}
-// CHECK: @CBScalars.cb = global target("dx.CBuffer", target("dx.Layout", %__cblayout_CBScalars,
-// CHECK-SAME: 56, 0, 8, 16, 24, 32, 36, 40, 48))
+// CHECK: @CBScalars.cb = global target("dx.CBuffer", %__cblayout_CBScalars)
// CHECK: @a1 = external hidden addrspace(2) global float, align 4
// CHECK: @a2 = external hidden addrspace(2) global double, align 8
// CHECK: @a3 = external hidden addrspace(2) global half, align 2
@@ -67,8 +139,7 @@ cbuffer CBVectors {
// FIXME: add a bool vectors after llvm-project/llvm#91639 is added
}
-// CHECK: @CBVectors.cb = global target("dx.CBuffer", target("dx.Layout", %__cblayout_CBVectors,
-// CHECK-SAME: 136, 0, 16, 40, 48, 80, 96, 112))
+// CHECK: @CBVectors.cb = global target("dx.CBuffer", %__cblayout_CBVectors)
// CHECK: @b1 = external hidden addrspace(2) global <3 x float>, align 16
// CHECK: @b2 = external hidden addrspace(2) global <3 x double>, align 32
// CHECK: @b3 = external hidden addrspace(2) global <2 x half>, align 4
@@ -89,16 +160,15 @@ cbuffer CBArrays : register(b2) {
bool c8[4];
}
-// CHECK: @CBArrays.cb = global target("dx.CBuffer", target("dx.Layout", %__cblayout_CBArrays,
-// CHECK-SAME: 708, 0, 48, 112, 176, 224, 608, 624, 656))
-// CHECK: @c1 = external hidden addrspace(2) global [3 x float], align 4
-// CHECK: @c2 = external hidden addrspace(2) global [2 x <3 x double>], align 32
-// CHECK: @c3 = external hidden addrspace(2) global [2 x [2 x half]], align 2
-// CHECK: @c4 = external hidden addrspace(2) global [3 x i64], align 8
-// CHECK: @c5 = external hidden addrspace(2) global [2 x [3 x [4 x <4 x i32>]]], align 16
+// CHECK: @CBArrays.cb = global target("dx.CBuffer", %__cblayout_CBArrays)
+// CHECK: @c1 = external hidden addrspace(2) global <{ [2 x <{ float, [12 x i8] }>], float }>, align 4
+// CHECK: @c2 = external hidden addrspace(2) global <{ [1 x <{ <3 x double>, [8 x i8] }>], <3 x double> }>, align 32
+// CHECK: @c3 = external hidden addrspace(2) global <{ [3 x <{ half, [14 x i8] }>], half }>, align 2
+// CHECK: @c4 = external hidden addrspace(2) global <{ [2 x <{ i64, [8 x i8] }>], i64 }>, align 8
+// CHECK: @c5 = external hidden addrspace(2) global [24 x <4 x i32>], align 16
// CHECK: @c6 = external hidden addrspace(2) global [1 x i16], align 2
-// CHECK: @c7 = external hidden addrspace(2) global [2 x i64], align 8
-// CHECK: @c8 = external hidden addrspace(2) global [4 x i32], align 4
+// CHECK: @c7 = external hidden addrspace(2) global <{ [1 x <{ i64, [8 x i8] }>], i64 }>, align 8
+// CHECK: @c8 = external hidden addrspace(2) global <{ [3 x <{ i32, [12 x i8] }>], i32 }>, align 4
// CHECK: @CBArrays.str = private unnamed_addr constant [9 x i8] c"CBArrays\00", align 1
typedef uint32_t4 uint32_t8[2];
@@ -110,10 +180,9 @@ cbuffer CBTypedefArray : register(space2) {
T2 t2[2];
}
-// CHECK: @CBTypedefArray.cb = global target("dx.CBuffer", target("dx.Layout", %__cblayout_CBTypedefArray,
-// CHECK-SAME: 128, 0, 64))
-// CHECK: @t1 = external hidden addrspace(2) global [2 x [2 x <4 x i32>]], align 16
-// CHECK: @t2 = external hidden addrspace(2) global [2 x [2 x <4 x i32>]], align 16
+// CHECK: @CBTypedefArray.cb = global target("dx.CBuffer", %__cblayout_CBTypedefArray)
+// CHECK: @t1 = external hidden addrspace(2) global [4 x <4 x i32>], align 16
+// CHECK: @t2 = external hidden addrspace(2) global [4 x <4 x i32>], align 16
// CHECK: @CBTypedefArray.str = private unnamed_addr constant [15 x i8] c"CBTypedefArray\00", align 1
struct Empty {};
@@ -135,13 +204,12 @@ struct D {
Empty es;
};
-// CHECK: @CBStructs.cb = global target("dx.CBuffer", target("dx.Layout", %__cblayout_CBStructs,
-// CHECK-SAME: 246, 0, 16, 32, 64, 144, 238, 240))
-// CHECK: @a = external hidden addrspace(2) global target("dx.Layout", %A, 8, 0), align 1
-// CHECK: @b = external hidden addrspace(2) global target("dx.Layout", %B, 14, 0, 8), align 1
-// CHECK: @c = external hidden addrspace(2) global target("dx.Layout", %C, 24, 0, 16), align 1
-// CHECK: @array_of_A = external hidden addrspace(2) global [5 x target("dx.Layout", %A, 8, 0)], align 1
-// CHECK: @d = external hidden addrspace(2) global target("dx.Layout", %__cblayout_D, 94, 0), align 1
+// CHECK: @CBStructs.cb = global target("dx.CBuffer", %__cblayout_CBStructs)
+// CHECK: @a = external hidden addrspace(2) global %A, align 1
+// CHECK: @b = external hidden addrspace(2) global %B, align 1
+// CHECK: @c = external hidden addrspace(2) global %C, align 1
+// CHECK: @array_of_A = external hidden addrspace(2) global <{ [4 x <{ %A, [8 x i8] }>], %A }>, align 1
+// CHECK: @d = external hidden addrspace(2) global %__cblayout_D, align 1
// CHECK: @e = external hidden addrspace(2) global half, align 2
// CHECK: @f = external hidden addrspace(2) global <3 x i16>, align 8
// CHECK: @CBStructs.str = private unnamed_addr constant [10 x i8] c"CBStructs\00", align 1
@@ -176,27 +244,25 @@ cbuffer CBClasses {
K ka[10];
};
-// CHECK: @CBClasses.cb = global target("dx.CBuffer", target("dx.Layout", %__cblayout_CBClasses,
-// CHECK-SAME: 260, 0, 16, 32, 112))
-// CHECK: @k = external hidden addrspace(2) global target("dx.Layout", %K, 4, 0), align 1
-// CHECK: @l = external hidden addrspace(2) global target("dx.Layout", %L, 8, 0, 4), align 1
-// CHECK: @m = external hidden addrspace(2) global target("dx.Layout", %M, 68, 0), align 1
-// CHECK: @ka = external hidden addrspace(2) global [10 x target("dx.Layout", %K, 4, 0)], align 1
+// CHECK: @CBClasses.cb = global target("dx.CBuffer", %__cblayout_CBClasses)
+// CHECK: @k = external hidden addrspace(2) global %K, align 1
+// CHECK: @l = external hidden addrspace(2) global %L, align 1
+// CHECK: @m = external hidden addrspace(2) global %M, align 1
+// CHECK: @ka = external hidden addrspace(2) global <{ [9 x <{ %K, [12 x i8] }>], %K }>, align 1
// CHECK: @CBClasses.str = private unnamed_addr constant [10 x i8] c"CBClasses\00", align 1
struct Test {
float a, b;
};
-// CHECK: @CBMix.cb = global target("dx.CBuffer", target("dx.Layout", %__cblayout_CBMix,
-// CHECK-SAME: 170, 0, 24, 32, 120, 128, 136, 144, 152, 160, 168))
-// CHECK: @test = external hidden addrspace(2) global [2 x target("dx.Layout", %Test, 8, 0, 4)], align 1
+// CHECK: @CBMix.cb = global target("dx.CBuffer", %__cblayout_CBMix)
+// CHECK: @test = external hidden addrspace(2) global <{ [1 x <{ %Test, [8 x i8] }>], %Test }>, align 1
// CHECK: @f1 = external hidden addrspace(2) global float, align 4
-// CHECK: @f2 = external hidden addrspace(2) global [3 x [2 x <2 x float>]], align 8
+// CHECK: @f2 = external hidden addrspace(2) global <{ [5 x <{ <2 x float>, [8 x i8] }>], <2 x float> }>, align 8
// CHECK: @f3 = external hidden addrspace(2) global float, align 4
-// CHECK: @f4 = external hidden addrspace(2) global target("dx.Layout", %anon, 4, 0), align 1
+// CHECK: @f4 = external hidden addrspace(2) global %anon, align 1
// CHECK: @f5 = external hidden addrspace(2) global double, align 8
-// CHECK: @f6 = external hidden addrspace(2) global target("dx.Layout", %anon.0, 8, 0), align 1
+// CHECK: @f6 = external hidden addrspace(2) global %anon.0, align 1
// CHECK: @f7 = external hidden addrspace(2) global float, align 4
// CHECK: @f8 = external hidden addrspace(2) global <1 x double>, align 8
// CHECK: @f9 = external hidden addrspace(2) global i16, align 2
@@ -215,7 +281,7 @@ cbuffer CBMix {
uint16_t f9;
};
-// CHECK: @CB_A.cb = global target("dx.CBuffer", target("dx.Layout", %__cblayout_CB_A, 188, 0, 32, 76, 80, 120, 128, 144, 160, 182))
+// CHECK: @CB_A.cb = global target("dx.CBuffer", %__cblayout_CB_A)
cbuffer CB_A {
double B0[2];
@@ -229,7 +295,7 @@ cbuffer CB_A {
half3 B8;
}
-// CHECK: @CB_B.cb = global target("dx.CBuffer", target("dx.Layout", %__cblayout_CB_B, 94, 0, 88))
+// CHECK: @CB_B.cb = global target("dx.CBuffer", %__cblayout_CB_B)
cbuffer CB_B {
double3 B9[3];
half3 B10;
@@ -264,7 +330,7 @@ struct G {
half C3;
};
-// CHECK: @CB_C.cb = global target("dx.CBuffer", target("dx.Layout", %__cblayout_CB_C, 400, 0, 16, 112, 128, 392))
+// CHECK: @CB_C.cb = global target("dx.CBuffer", %__cblayout_CB_C)
cbuffer CB_C {
int D0;
F D1;
@@ -275,63 +341,63 @@ cbuffer CB_C {
// CHECK: define internal void @_init_buffer_CBScalars.cb()
// CHECK-NEXT: entry:
-// CHECK-NEXT: %CBScalars.cb_h = call target("dx.CBuffer", target("dx.Layout", %__cblayout_CBScalars, 56, 0, 8, 16, 24, 32, 36, 40, 48))
-// CHECK-SAME: @llvm.dx.resource.handlefrombinding.tdx.CBuffer_tdx.Layout_s___cblayout_CBScalarss_56_0_8_16_24_32_36_40_48tt(i32 5, i32 1, i32 1, i32 0, ptr @CBScalars.str)
-// CHECK-NEXT: store target("dx.CBuffer", target("dx.Layout", %__cblayout_CBScalars, 56, 0, 8, 16, 24, 32, 36, 40, 48)) %CBScalars.cb_h, ptr @CBScalars.cb, align 4
+// CHECK-NEXT: %CBScalars.cb_h = call target("dx.CBuffer", %__cblayout_CBScalars)
+// CHECK-SAME: @llvm.dx.resource.handlefrombinding.tdx.CBuffer_s___cblayout_CBScalarsst(i32 5, i32 1, i32 1, i32 0, ptr @CBScalars.str)
+// CHECK-NEXT: store target("dx.CBuffer", %__cblayout_CBScalars) %CBScalars.cb_h, ptr @CBScalars.cb, align 4
// CHECK: define internal void @_init_buffer_CBVectors.cb()
// CHECK-NEXT: entry:
-// CHECK-NEXT: %CBVectors.cb_h = call target("dx.CBuffer", target("dx.Layout", %__cblayout_CBVectors, 136, 0, 16, 40, 48, 80, 96, 112))
-// CHECK-SAME: @llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_tdx.Layout_s___cblayout_CBVectorss_136_0_16_40_48_80_96_112tt(i32 0, i32 0, i32 1, i32 0, ptr @CBVectors.str)
-// CHECK-NEXT: store target("dx.CBuffer", target("dx.Layout", %__cblayout_CBVectors, 136, 0, 16, 40, 48, 80, 96, 112)) %CBVectors.cb_h, ptr @CBVectors.cb, align 4
+// CHECK-NEXT: %CBVectors.cb_h = call target("dx.CBuffer", %__cblayout_CBVectors)
+// CHECK-SAME: @llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_s___cblayout_CBVectorsst(i32 0, i32 0, i32 1, i32 0, ptr @CBVectors.str)
+// CHECK-NEXT: store target("dx.CBuffer", %__cblayout_CBVectors) %CBVectors.cb_h, ptr @CBVectors.cb, align 4
// CHECK: define internal void @_init_buffer_CBArrays.cb()
// CHECK-NEXT: entry:
-// CHECK-NEXT: %CBArrays.cb_h = call target("dx.CBuffer", target("dx.Layout", %__cblayout_CBArrays, 708, 0, 48, 112, 176, 224, 608, 624, 656))
-// CHECK-SAME: @llvm.dx.resource.handlefrombinding.tdx.CBuffer_tdx.Layout_s___cblayout_CBArrayss_708_0_48_112_176_224_608_624_656tt(i32 0, i32 2, i32 1, i32 0, ptr @CBArrays.str)
-// CHECK-NEXT: store target("dx.CBuffer", target("dx.Layout", %__cblayout_CBArrays, 708, 0, 48, 112, 176, 224, 608, 624, 656)) %CBArrays.cb_h, ptr @CBArrays.cb, align 4
+// CHECK-NEXT: %CBArrays.cb_h = call target("dx.CBuffer", %__cblayout_CBArrays)
+// CHECK-SAME: @llvm.dx.resource.handlefrombinding.tdx.CBuffer_s___cblayout_CBArraysst(i32 0, i32 2, i32 1, i32 0, ptr @CBArrays.str)
+// CHECK-NEXT: store target("dx.CBuffer", %__cblayout_CBArrays) %CBArrays.cb_h, ptr @CBArrays.cb, align 4
// CHECK: define internal void @_init_buffer_CBTypedefArray.cb()
// CHECK-NEXT: entry:
-// CHECK-NEXT: %CBTypedefArray.cb_h = call target("dx.CBuffer", target("dx.Layout", %__cblayout_CBTypedefArray, 128, 0, 64))
-// CHECK-SAME: @llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_tdx.Layout_s___cblayout_CBTypedefArrays_128_0_64tt(i32 1, i32 2, i32 1, i32 0, ptr @CBTypedefArray.str)
-// CHECK-NEXT: store target("dx.CBuffer", target("dx.Layout", %__cblayout_CBTypedefArray, 128, 0, 64)) %CBTypedefArray.cb_h, ptr @CBTypedefArray.cb, align 4
+// CHECK-NEXT: %CBTypedefArray.cb_h = call target("dx.CBuffer", %__cblayout_CBTypedefArray)
+// CHECK-SAME: @llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_s___cblayout_CBTypedefArrayst(i32 1, i32 2, i32 1, i32 0, ptr @CBTypedefArray.str)
+// CHECK-NEXT: store target("dx.CBuffer", %__cblayout_CBTypedefArray) %CBTypedefArray.cb_h, ptr @CBTypedefArray.cb, align 4
// CHECK: define internal void @_init_buffer_CBStructs.cb()
// CHECK-NEXT: entry:
-// CHECK-NEXT: %CBStructs.cb_h = call target("dx.CBuffer", target("dx.Layout", %__cblayout_CBStructs, 246, 0, 16, 32, 64, 144, 238, 240))
-// CHECK-SAME: @llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_tdx.Layout_s___cblayout_CBStructss_246_0_16_32_64_144_238_240tt(i32 2, i32 0, i32 1, i32 0, ptr @CBStructs.str)
-// CHECK-NEXT: store target("dx.CBuffer", target("dx.Layout", %__cblayout_CBStructs, 246, 0, 16, 32, 64, 144, 238, 240)) %CBStructs.cb_h, ptr @CBStructs.cb, align 4
+// CHECK-NEXT: %CBStructs.cb_h = call target("dx.CBuffer", %__cblayout_CBStructs)
+// CHECK-SAME: @llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_s___cblayout_CBStructsst(i32 2, i32 0, i32 1, i32 0, ptr @CBStructs.str)
+// CHECK-NEXT: store target("dx.CBuffer", %__cblayout_CBStructs) %CBStructs.cb_h, ptr @CBStructs.cb, align 4
// CHECK: define internal void @_init_buffer_CBClasses.cb()
// CHECK-NEXT: entry:
-// CHECK-NEXT: %CBClasses.cb_h = call target("dx.CBuffer", target("dx.Layout", %__cblayout_CBClasses, 260, 0, 16, 32, 112))
-// CHECK-SAME: @llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_tdx.Layout_s___cblayout_CBClassess_260_0_16_32_112tt(i32 3, i32 0, i32 1, i32 0, ptr @CBClasses.str)
-// CHECK-NEXT: store target("dx.CBuffer", target("dx.Layout", %__cblayout_CBClasses, 260, 0, 16, 32, 112)) %CBClasses.cb_h, ptr @CBClasses.cb, align 4
+// CHECK-NEXT: %CBClasses.cb_h = call target("dx.CBuffer", %__cblayout_CBClasses)
+// CHECK-SAME: @llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_s___cblayout_CBClassesst(i32 3, i32 0, i32 1, i32 0, ptr @CBClasses.str)
+// CHECK-NEXT: store target("dx.CBuffer", %__cblayout_CBClasses) %CBClasses.cb_h, ptr @CBClasses.cb, align 4
// CHECK: define internal void @_init_buffer_CBMix.cb()
// CHECK-NEXT: entry:
-// CHECK-NEXT: %CBMix.cb_h = call target("dx.CBuffer", target("dx.Layout", %__cblayout_CBMix, 170, 0, 24, 32, 120, 128, 136, 144, 152, 160, 168))
-// CHECK-SAME: @llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_tdx.Layout_s___cblayout_CBMixs_170_0_24_32_120_128_136_144_152_160_168tt(i32 4, i32 0, i32 1, i32 0, ptr @CBMix.str)
-// CHECK-NEXT: store target("dx.CBuffer", target("dx.Layout", %__cblayout_CBMix, 170, 0, 24, 32, 120, 128, 136, 144, 152, 160, 168)) %CBMix.cb_h, ptr @CBMix.cb, align 4
+// CHECK-NEXT: %CBMix.cb_h = call target("dx.CBuffer", %__cblayout_CBMix)
+// CHECK-SAME: @llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_s___cblayout_CBMixst(i32 4, i32 0, i32 1, i32 0, ptr @CBMix.str)
+// CHECK-NEXT: store target("dx.CBuffer", %__cblayout_CBMix) %CBMix.cb_h, ptr @CBMix.cb, align 4
// CHECK: define internal void @_init_buffer_CB_A.cb()
// CHECK-NEXT: entry:
-// CHECK-NEXT: %CB_A.cb_h = call target("dx.CBuffer", target("dx.Layout", %__cblayout_CB_A, 188, 0, 32, 76, 80, 120, 128, 144, 160, 182))
-// CHECK-SAME: @llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_tdx.Layout_s___cblayout_CB_As_188_0_32_76_80_120_128_144_160_182tt(i32 5, i32 0, i32 1, i32 0, ptr @CB_A.str)
-// CHECK-NEXT: store target("dx.CBuffer", target("dx.Layout", %__cblayout_CB_A, 188, 0, 32, 76, 80, 120, 128, 144, 160, 182)) %CB_A.cb_h, ptr @CB_A.cb, align 4
+// CHECK-NEXT: %CB_A.cb_h = call target("dx.CBuffer", %__cblayout_CB_A)
+// CHECK-SAME: @llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_s___cblayout_CB_Ast(i32 5, i32 0, i32 1, i32 0, ptr @CB_A.str)
+// CHECK-NEXT: store target("dx.CBuffer", %__cblayout_CB_A) %CB_A.cb_h, ptr @CB_A.cb, align 4
// CHECK: define internal void @_init_buffer_CB_B.cb()
// CHECK-NEXT: entry:
-// CHECK-NEXT: %CB_B.cb_h = call target("dx.CBuffer", target("dx.Layout", %__cblayout_CB_B, 94, 0, 88))
-// CHECK-SAME: @llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_tdx.Layout_s___cblayout_CB_Bs_94_0_88tt(i32 6, i32 0, i32 1, i32 0, ptr @CB_B.str)
-// CHECK-NEXT: store target("dx.CBuffer", target("dx.Layout", %__cblayout_CB_B, 94, 0, 88)) %CB_B.cb_h, ptr @CB_B.cb, align 4
+// CHECK-NEXT: %CB_B.cb_h = call target("dx.CBuffer", %__cblayout_CB_B)
+// CHECK-SAME: @llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_s___cblayout_CB_Bst(i32 6, i32 0, i32 1, i32 0, ptr @CB_B.str)
+// CHECK-NEXT: store target("dx.CBuffer", %__cblayout_CB_B) %CB_B.cb_h, ptr @CB_B.cb, align 4
// CHECK: define internal void @_init_buffer_CB_C.cb()
// CHECK-NEXT: entry:
-// CHECK-NEXT: %CB_C.cb_h = call target("dx.CBuffer", target("dx.Layout", %__cblayout_CB_C, 400, 0, 16, 112, 128, 392))
-// CHECK-SAME: @llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_tdx.Layout_s___cblayout_CB_Cs_400_0_16_112_128_392tt(i32 7, i32 0, i32 1, i32 0, ptr @CB_C.str)
-// CHECK-NEXT: store target("dx.CBuffer", target("dx.Layout", %__cblayout_CB_C, 400, 0, 16, 112, 128, 392)) %CB_C.cb_h, ptr @CB_C.cb, align 4
+// CHECK-NEXT: %CB_C.cb_h = call target("dx.CBuffer", %__cblayout_CB_C)
+// CHECK-SAME: @llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_s___cblayout_CB_Cst(i32 7, i32 0, i32 1, i32 0, ptr @CB_C.str)
+// CHECK-NEXT: store target("dx.CBuffer", %__cblayout_CB_C) %CB_C.cb_h, ptr @CB_C.cb, align 4
RWBuffer<float> Buf;
diff --git a/clang/test/CodeGenHLSL/resources/cbuffer_and_namespaces.hlsl b/clang/test/CodeGenHLSL/resources/cbuffer_and_namespaces.hlsl
index b7bdce32e6507..af48ab9aaa1dd 100644
--- a/clang/test/CodeGenHLSL/resources/cbuffer_and_namespaces.hlsl
+++ b/clang/test/CodeGenHLSL/resources/cbuffer_and_namespaces.hlsl
@@ -4,18 +4,18 @@
// CHECK: %"n0::n1::__cblayout_A" = type <{ float }>
// CHECK: %"n0::__cblayout_B" = type <{ float }>
-// CHECK: %"n0::n2::__cblayout_C" = type <{ float, target("dx.Layout", %"n0::Foo", 4, 0) }>
+// CHECK: %"n0::n2::__cblayout_C" = type <{ float, [12 x i8], %"n0::Foo" }>
// CHECK: %"n0::Foo" = type <{ float }>
-// CHECK: @A.cb = global target("dx.CBuffer", target("dx.Layout", %"n0::n1::__cblayout_A", 4, 0))
+// CHECK: @A.cb = global target("dx.CBuffer", %"n0::n1::__cblayout_A")
// CHECK: @_ZN2n02n11aE = external hidden addrspace(2) global float, align 4
-// CHECK: @B.cb = global target("dx.CBuffer", target("dx.Layout", %"n0::__cblayout_B", 4, 0))
+// CHECK: @B.cb = global target("dx.CBuffer", %"n0::__cblayout_B")
// CHECK: @_ZN2n01aE = external hidden addrspace(2) global float, align 4
-// CHECK: @C.cb = global target("dx.CBuffer", target("dx.Layout", %"n0::n2::__cblayout_C", 20, 0, 16))
+// CHECK: @C.cb = global target("dx.CBuffer", %"n0::n2::__cblayout_C")
// CHECK: @_ZN2n02n21aE = external hidden addrspace(2) global float, align 4
-// CHECK: external hidden addrspace(2) global target("dx.Layout", %"n0::Foo", 4, 0), align 1
+// CHECK: external hidden addrspace(2) global %"n0::Foo", align 1
namespace n0 {
struct Foo {
diff --git a/clang/test/CodeGenHLSL/resources/cbuffer_with_packoffset.hlsl b/clang/test/CodeGenHLSL/resources/cbuffer_with_packoffset.hlsl
index 7bedd63c9f65d..c39fd75ec6ee4 100644
--- a/clang/test/CodeGenHLSL/resources/cbuffer_with_packoffset.hlsl
+++ b/clang/test/CodeGenHLSL/resources/cbuffer_with_packoffset.hlsl
@@ -2,10 +2,13 @@
// RUN: dxil-pc-shadermodel6.3-compute %s \
// RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s
-// CHECK: %__cblayout_CB = type <{ float, double, <2 x i32> }>
-// CHECK: %__cblayout_CB_1 = type <{ float, <2 x float> }>
+// TODO: Reordering fields doesn't work...
+// XFAIL: *
-// CHECK: @CB.cb = global target("dx.CBuffer", target("dx.Layout", %__cblayout_CB, 176, 16, 168, 88))
+// CHECK: %__cblayout_CB = type <{ [16 x i8], float, [68 x i8], <2 x i32>, [72 x i8], double }>
+// CHECK: %__cblayout_CB_1 = type <{ [80 x i8], <2 x float>, float }>
+
+// CHECK: @CB.cb = global target("dx.CBuffer", %__cblayout_CB)
// CHECK: @a = external hidden addrspace(2) global float, align 4
// CHECK: @b = external hidden addrspace(2) global double, align 8
// CHECK: @c = external hidden addrspace(2) global <2 x i32>, align 8
@@ -17,7 +20,7 @@ cbuffer CB : register(b1, space3) {
int2 c : packoffset(c5.z);
}
-// CHECK: @CB.cb.1 = global target("dx.CBuffer", target("dx.Layout", %__cblayout_CB_1, 92, 88, 80))
+// CHECK: @CB.cb.1 = global target("dx.CBuffer", %__cblayout_CB_1)
// CHECK: @x = external hidden addrspace(2) global float, align 4
// CHECK: @y = external hidden addrspace(2) global <2 x float>, align 8
@@ -30,7 +33,7 @@ cbuffer CB : register(b0) {
// CHECK: define internal void @_init_buffer_CB.cb()
// CHECK-NEXT: entry:
-// CHECK-NEXT: %CB.cb_h = call target("dx.CBuffer", target("dx.Layout", %__cblayout_CB, 176, 16, 168, 88))
+// CHECK-NEXT: %CB.cb_h = call target("dx.CBuffer", %__cblayout_CB)
// CHECK-SAME: @llvm.dx.resource.handlefrombinding.tdx.CBuffer_tdx.Layout_s___cblayout_CBs_176_16_168_88tt(i32 3, i32 1, i32 1, i32 0, ptr @CB.str)
float foo() {
diff --git a/clang/test/CodeGenHLSL/resources/cbuffer_with_static_global_and_function.hlsl b/clang/test/CodeGenHLSL/resources/cbuffer_with_static_global_and_function.hlsl
index fa3405df9e3d3..b8c7babb8d634 100644
--- a/clang/test/CodeGenHLSL/resources/cbuffer_with_static_global_and_function.hlsl
+++ b/clang/test/CodeGenHLSL/resources/cbuffer_with_static_global_and_function.hlsl
@@ -2,7 +2,7 @@
// CHECK: %__cblayout_A = type <{ float }>
-// CHECK: @A.cb = global target("dx.CBuffer", target("dx.Layout", %__cblayout_A, 4, 0))
+// CHECK: @A.cb = global target("dx.CBuffer", %__cblayout_A)
// CHECK: @a = external hidden addrspace(2) global float, align 4
// CHECK-DAG: @_ZL1b = internal global float 3.000000e+00, align 4
// CHECK-NOT: @B.cb
diff --git a/clang/test/CodeGenHLSL/resources/default_cbuffer.hlsl b/clang/test/CodeGenHLSL/resources/default_cbuffer.hlsl
index ad4d92f8afc02..6ad9d4444e4b3 100644
--- a/clang/test/CodeGenHLSL/resources/default_cbuffer.hlsl
+++ b/clang/test/CodeGenHLSL/resources/default_cbuffer.hlsl
@@ -1,19 +1,18 @@
// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.3-compute -fnative-half-type -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,DXIL
// RUN: %clang_cc1 -finclude-default-header -triple spirv-pc-vulkan1.3-compute -fnative-half-type -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,SPIRV
-// DXIL: %"__cblayout_$Globals" = type <{ float, float, target("dx.Layout", %__cblayout_S, 4, 0) }>
-// SPIRV: %"__cblayout_$Globals" = type <{ float, float, target("spirv.Layout", %__cblayout_S, 4, 0) }>
+// CHECK: %"__cblayout_$Globals" = type <{ float, float, [8 x i8], %__cblayout_S }>
// CHECK: %__cblayout_S = type <{ float }>
-// DXIL-DAG: @"$Globals.cb" = global target("dx.CBuffer", target("dx.Layout", %"__cblayout_$Globals", 20, 0, 4, 16))
+// DXIL-DAG: @"$Globals.cb" = global target("dx.CBuffer", %"__cblayout_$Globals")
// DXIL-DAG: @a = external hidden addrspace(2) global float
// DXIL-DAG: @g = external hidden addrspace(2) global float
-// DXIL-DAG: @h = external hidden addrspace(2) global target("dx.Layout", %__cblayout_S, 4, 0), align 4
+// DXIL-DAG: @h = external hidden addrspace(2) global %__cblayout_S, align 4
-// SPIRV-DAG: @"$Globals.cb" = global target("spirv.VulkanBuffer", target("spirv.Layout", %"__cblayout_$Globals", 20, 0, 4, 16), 2, 0)
+// SPIRV-DAG: @"$Globals.cb" = global target("spirv.VulkanBuffer", %"__cblayout_$Globals", 2, 0)
// SPIRV-DAG: @a = external hidden addrspace(12) global float
// SPIRV-DAG: @g = external hidden addrspace(12) global float
-// SPIRV-DAG: @h = external hidden addrspace(12) global target("spirv.Layout", %__cblayout_S, 4, 0), align 8
+// SPIRV-DAG: @h = external hidden addrspace(12) global %__cblayout_S, align 8
struct EmptyStruct {
};
diff --git a/clang/test/CodeGenHLSL/resources/default_cbuffer_with_layout.hlsl b/clang/test/CodeGenHLSL/resources/default_cbuffer_with_layout.hlsl
index 1b2cb0e99aa83..fee3b77c32dd2 100644
--- a/clang/test/CodeGenHLSL/resources/default_cbuffer_with_layout.hlsl
+++ b/clang/test/CodeGenHLSL/resources/default_cbuffer_with_layout.hlsl
@@ -13,6 +13,9 @@
// CHECK-DAG: @e = external hidden addrspace(2) global <4 x float>, align 16
// CHECK-DAG: @s = external hidden addrspace(2) global target("dx.Layout", %S, 8, 0), align 1
+// TODO: Reordering fields doesn't work...
+// XFAIL: *
+
struct S {
float2 v;
};
>From b882ff8223d2edd31f2b017315d42e16b9174f7f Mon Sep 17 00:00:00 2001
From: Justin Bogner <mail at justinbogner.com>
Date: Thu, 7 Aug 2025 15:02:49 -0700
Subject: [PATCH 05/11] wip: Drop layout type from DXILResource
---
llvm/include/llvm/Analysis/DXILResource.h | 21 --------
llvm/lib/Analysis/DXILResource.cpp | 52 ++++++++++++++++---
.../DXILResource/buffer-frombinding.ll | 4 +-
.../CodeGen/DirectX/CBufferAccess/memcpy.ll | 4 --
.../CodeGen/DirectX/CBufferAccess/vectors.ll | 4 --
.../DirectX/CBufferLoadLegacy-errors.ll | 12 ++---
.../test/CodeGen/DirectX/CBufferLoadLegacy.ll | 12 ++---
.../ContainerData/PSVResources-order.ll | 2 +-
.../DirectX/ContainerData/PSVResources.ll | 4 +-
.../DirectX/CreateHandleFromBinding.ll | 2 +-
.../ForwardHandleAccesses/cbuffer-access.ll | 20 +++----
.../CodeGen/DirectX/Metadata/cbuffer-only.ll | 2 +-
.../DirectX/Metadata/cbuffer_metadata.ll | 23 ++++----
13 files changed, 87 insertions(+), 75 deletions(-)
diff --git a/llvm/include/llvm/Analysis/DXILResource.h b/llvm/include/llvm/Analysis/DXILResource.h
index 88ac0a11fe5a2..5d54069ba6a90 100644
--- a/llvm/include/llvm/Analysis/DXILResource.h
+++ b/llvm/include/llvm/Analysis/DXILResource.h
@@ -222,27 +222,6 @@ class AnyResourceExtType : public TargetExtType {
}
};
-/// The dx.Layout target extension type
-///
-/// `target("dx.Layout", <Type>, <size>, [offsets...])`
-class LayoutExtType : public TargetExtType {
-public:
- LayoutExtType() = delete;
- LayoutExtType(const LayoutExtType &) = delete;
- LayoutExtType &operator=(const LayoutExtType &) = delete;
-
- Type *getWrappedType() const { return getTypeParameter(0); }
- uint32_t getSize() const { return getIntParameter(0); }
- uint32_t getOffsetOfElement(int I) const { return getIntParameter(I + 1); }
-
- static bool classof(const TargetExtType *T) {
- return T->getName() == "dx.Layout";
- }
- static bool classof(const Type *T) {
- return isa<TargetExtType>(T) && classof(cast<TargetExtType>(T));
- }
-};
-
//===----------------------------------------------------------------------===//
class ResourceTypeInfo {
diff --git a/llvm/lib/Analysis/DXILResource.cpp b/llvm/lib/Analysis/DXILResource.cpp
index b78cc03e34dbc..8502a86501273 100644
--- a/llvm/lib/Analysis/DXILResource.cpp
+++ b/llvm/lib/Analysis/DXILResource.cpp
@@ -281,6 +281,48 @@ static StructType *getOrCreateElementStruct(Type *ElemType, StringRef Name) {
return StructType::create(ElemType, Name);
}
+static bool isPadding(Type *Ty) {
+ // TODO: we need an explicit padding type here...
+ if (auto *AT = dyn_cast<ArrayType>(Ty))
+ if (AT->getElementType() == Type::getInt8Ty(Ty->getContext()))
+ return true;
+ return false;
+}
+
+static Type *getTypeWithoutPadding(Type *Ty) {
+ // Recursively remove padding from structures.
+ if (auto *ST = dyn_cast<StructType>(Ty)) {
+ LLVMContext &Ctx = Ty->getContext();
+ SmallVector<Type *> ElementTypes;
+ ElementTypes.reserve(ST->getNumElements());
+ for (Type *ElTy : ST->elements()) {
+ if (isPadding(ElTy))
+ continue;
+ ElementTypes.push_back(getTypeWithoutPadding(ElTy));
+ }
+
+ // Handle explicitly padded cbuffer arrays like { [ n x paddedty ], ty }
+ if (ElementTypes.size() == 2)
+ if (auto *AT = dyn_cast<ArrayType>(ElementTypes[0]))
+ if (ElementTypes[1] == AT->getElementType())
+ return ArrayType::get(ElementTypes[1], AT->getNumElements() + 1);
+
+ // If we only have a single element, don't wrap it in a struct.
+ if (ElementTypes.size() == 1)
+ return ElementTypes[0];
+
+ return StructType::get(Ctx, ElementTypes, /*IsPacked=*/false);
+ }
+
+ // Arrays just need to have their element type adjusted.
+ if (auto *AT = dyn_cast<ArrayType>(Ty))
+ return ArrayType::get(getTypeWithoutPadding(AT->getElementType()),
+ AT->getNumElements());
+
+ // Anything else should be good as is.
+ return Ty;
+}
+
StructType *ResourceTypeInfo::createElementStruct(StringRef CBufferName) {
SmallString<64> TypeName;
@@ -334,14 +376,13 @@ StructType *ResourceTypeInfo::createElementStruct(StringRef CBufferName) {
}
case ResourceKind::CBuffer: {
auto *RTy = cast<CBufferExtType>(HandleTy);
- LayoutExtType *LayoutType = cast<LayoutExtType>(RTy->getResourceType());
- StructType *Ty = cast<StructType>(LayoutType->getWrappedType());
SmallString<64> Name = getResourceKindName(Kind);
if (!CBufferName.empty()) {
Name.append(".");
Name.append(CBufferName);
}
- return StructType::create(Ty->elements(), Name);
+ return getOrCreateElementStruct(
+ getTypeWithoutPadding(RTy->getResourceType()), Name);
}
case ResourceKind::Sampler: {
auto *RTy = cast<SamplerExtType>(HandleTy);
@@ -453,11 +494,6 @@ uint32_t ResourceTypeInfo::getCBufferSize(const DataLayout &DL) const {
assert(isCBuffer() && "Not a CBuffer");
Type *ElTy = cast<CBufferExtType>(HandleTy)->getResourceType();
-
- if (auto *LayoutTy = dyn_cast<LayoutExtType>(ElTy))
- return LayoutTy->getSize();
-
- // TODO: What should we do with unannotated arrays?
return DL.getTypeAllocSize(ElTy);
}
diff --git a/llvm/test/Analysis/DXILResource/buffer-frombinding.ll b/llvm/test/Analysis/DXILResource/buffer-frombinding.ll
index aeeb21ebb3201..c2ef4f159f2f7 100644
--- a/llvm/test/Analysis/DXILResource/buffer-frombinding.ll
+++ b/llvm/test/Analysis/DXILResource/buffer-frombinding.ll
@@ -150,7 +150,7 @@ define void @test_typedbuffer() {
; CHECK: Kind: CBuffer
; CHECK: CBuffer size: 4
- %cb1 = call target("dx.CBuffer", target("dx.Layout", {float}, 4, 0))
+ %cb1 = call target("dx.CBuffer", <{ [2 x <{ float, [12 x i8] }>], float }>)
@llvm.dx.resource.handlefrombinding(i32 1, i32 8, i32 1, i32 0, ptr @Constants.str)
; CHECK: Resource [[CB1:[0-9]+]]:
; CHECK: Name: Constants
@@ -161,7 +161,7 @@ define void @test_typedbuffer() {
; CHECK: Size: 1
; CHECK: Class: CBV
; CHECK: Kind: CBuffer
- ; CHECK: CBuffer size: 4
+ ; CHECK: CBuffer size: 36
; CHECK-NOT: Resource {{[0-9]+}}:
diff --git a/llvm/test/CodeGen/DirectX/CBufferAccess/memcpy.ll b/llvm/test/CodeGen/DirectX/CBufferAccess/memcpy.ll
index eacad84f7e11d..872266e96b21a 100644
--- a/llvm/test/CodeGen/DirectX/CBufferAccess/memcpy.ll
+++ b/llvm/test/CodeGen/DirectX/CBufferAccess/memcpy.ll
@@ -1,9 +1,5 @@
; RUN: opt -S -dxil-cbuffer-access -mtriple=dxil--shadermodel6.3-library %s | FileCheck %s
-; TODO: Remove datalayout.
-; This hack forces dxil-compatible alignment of 3-element 32- and 64-bit vectors
-target datalayout = "e-m:e-p:32:32-i1:32-i8:8-i16:16-i32:32-i64:64-f16:16-f32:32-f64:64-n8:16:32:64-v96:32:32-v192:64:64"
-
; cbuffer CB : register(b0) {
; float4 a1[4]; // offset 0, size 16 * 4
; float a2[2]; // offset 64, size 4 (+12) * 2
diff --git a/llvm/test/CodeGen/DirectX/CBufferAccess/vectors.ll b/llvm/test/CodeGen/DirectX/CBufferAccess/vectors.ll
index 72ec103e8f246..3c19f1b628ab0 100644
--- a/llvm/test/CodeGen/DirectX/CBufferAccess/vectors.ll
+++ b/llvm/test/CodeGen/DirectX/CBufferAccess/vectors.ll
@@ -1,9 +1,5 @@
; RUN: opt -S -dxil-cbuffer-access -mtriple=dxil--shadermodel6.3-library %s | FileCheck %s
-; TODO: Remove datalayout.
-; This hack forces dxil-compatible alignment of 3-element 32- and 64-bit vectors
-target datalayout = "e-m:e-p:32:32-i1:32-i8:8-i16:16-i32:32-i64:64-f16:16-f32:32-f64:64-n8:16:32:64-v96:32:32-v192:64:64"
-
; cbuffer CB {
; float3 a1; // offset 0, size 12 (+4)
; double3 a2; // offset 16, size 24
diff --git a/llvm/test/CodeGen/DirectX/CBufferLoadLegacy-errors.ll b/llvm/test/CodeGen/DirectX/CBufferLoadLegacy-errors.ll
index 71dcf11b9dc88..196560f551f5f 100644
--- a/llvm/test/CodeGen/DirectX/CBufferLoadLegacy-errors.ll
+++ b/llvm/test/CodeGen/DirectX/CBufferLoadLegacy-errors.ll
@@ -11,11 +11,11 @@ declare void @f16_user(half)
; CHECK-SAME: in function four64
; CHECK-SAME: Type mismatch between intrinsic and DXIL op
define void @four64() "hlsl.export" {
- %buffer = call target("dx.CBuffer", target("dx.Layout", {double}, 8, 0))
+ %buffer = call target("dx.CBuffer", <{ double }>)
@llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, ptr null)
%load = call {double, double, double, double} @llvm.dx.resource.load.cbufferrow.4(
- target("dx.CBuffer", target("dx.Layout", {double}, 8, 0)) %buffer,
+ target("dx.CBuffer", <{ double }>) %buffer,
i32 0)
%data = extractvalue {double, double, double, double} %load, 0
@@ -28,11 +28,11 @@ define void @four64() "hlsl.export" {
; CHECK-SAME: in function two32
; CHECK-SAME: Type mismatch between intrinsic and DXIL op
define void @two32() "hlsl.export" {
- %buffer = call target("dx.CBuffer", target("dx.Layout", {float}, 4, 0))
+ %buffer = call target("dx.CBuffer", <{ float }>)
@llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, ptr null)
%load = call {float, float} @llvm.dx.resource.load.cbufferrow.2(
- target("dx.CBuffer", target("dx.Layout", {float}, 4, 0)) %buffer,
+ target("dx.CBuffer", <{ float }>) %buffer,
i32 0)
%data = extractvalue {float, float} %load, 0
@@ -41,5 +41,5 @@ define void @two32() "hlsl.export" {
ret void
}
-declare { double, double, double, double } @llvm.dx.resource.load.cbufferrow.4.f64.f64.f64.f64.tdx.CBuffer_tdx.Layout_sl_f64s_8_0tt(target("dx.CBuffer", target("dx.Layout", { double }, 8, 0)), i32)
-declare { float, float } @llvm.dx.resource.load.cbufferrow.2.f32.f32.tdx.CBuffer_tdx.Layout_sl_f32s_4_0tt(target("dx.CBuffer", target("dx.Layout", { float }, 4, 0)), i32)
+declare { double, double, double, double } @llvm.dx.resource.load.cbufferrow.4.f64.f64.f64.f64.tdx.CBuffer_sl_f64st(target("dx.CBuffer", <{ double }>), i32)
+declare { float, float } @llvm.dx.resource.load.cbufferrow.2.f32.f32.tdx.CBuffer_sl_f32st(target("dx.CBuffer", <{ float }>), i32)
diff --git a/llvm/test/CodeGen/DirectX/CBufferLoadLegacy.ll b/llvm/test/CodeGen/DirectX/CBufferLoadLegacy.ll
index d6906516b716d..dd40aa8d8d31c 100644
--- a/llvm/test/CodeGen/DirectX/CBufferLoadLegacy.ll
+++ b/llvm/test/CodeGen/DirectX/CBufferLoadLegacy.ll
@@ -8,12 +8,12 @@ declare void @f16_user(half)
; CHECK-LABEL: define void @loadf32
define void @loadf32() {
- %buffer = call target("dx.CBuffer", target("dx.Layout", {float}, 4, 0))
+ %buffer = call target("dx.CBuffer", <{ float }>)
@llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, ptr null)
; CHECK: [[DATA:%.*]] = call %dx.types.CBufRet.f32 @dx.op.cbufferLoadLegacy.f32(i32 59, %dx.types.Handle %{{.*}}, i32 0)
%load = call {float, float, float, float} @llvm.dx.resource.load.cbufferrow.4(
- target("dx.CBuffer", target("dx.Layout", {float}, 4, 0)) %buffer,
+ target("dx.CBuffer", <{ float }>) %buffer,
i32 0)
%data = extractvalue {float, float, float, float} %load, 0
@@ -27,12 +27,12 @@ define void @loadf32() {
; CHECK-LABEL: define void @loadf64
define void @loadf64() {
%buffer = call
- target("dx.CBuffer", target("dx.Layout", {double, double, double, double}, 64, 0, 8, 16, 24))
+ target("dx.CBuffer", <{ <4 x double> }>)
@llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, ptr null)
; CHECK: [[DATA:%.*]] = call %dx.types.CBufRet.f64 @dx.op.cbufferLoadLegacy.f64(i32 59, %dx.types.Handle %{{.*}}, i32 1)
%load = call {double, double} @llvm.dx.resource.load.cbufferrow.2(
- target("dx.CBuffer", target("dx.Layout", {double, double, double, double}, 64, 0, 8, 16, 24)) %buffer,
+ target("dx.CBuffer", <{ <4 x double> }>) %buffer,
i32 1)
%data = extractvalue {double, double} %load, 1
@@ -46,12 +46,12 @@ define void @loadf64() {
; CHECK-LABEL: define void @loadf16
define void @loadf16() {
%buffer = call
- target("dx.CBuffer", target("dx.Layout", {half}, 2, 0))
+ target("dx.CBuffer", <{ half }>)
@llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, ptr null)
; CHECK: [[DATA:%.*]] = call %dx.types.CBufRet.f16.8 @dx.op.cbufferLoadLegacy.f16(i32 59, %dx.types.Handle %{{.*}}, i32 0)
%load = call {half, half, half, half, half, half, half, half} @llvm.dx.resource.load.cbufferrow.8(
- target("dx.CBuffer", target("dx.Layout", {half}, 2, 0)) %buffer,
+ target("dx.CBuffer", <{ half }>) %buffer,
i32 0)
%data = extractvalue {half, half, half, half, half, half, half, half} %load, 0
diff --git a/llvm/test/CodeGen/DirectX/ContainerData/PSVResources-order.ll b/llvm/test/CodeGen/DirectX/ContainerData/PSVResources-order.ll
index bcf82a67a55df..5cd67be1a4a28 100644
--- a/llvm/test/CodeGen/DirectX/ContainerData/PSVResources-order.ll
+++ b/llvm/test/CodeGen/DirectX/ContainerData/PSVResources-order.ll
@@ -18,7 +18,7 @@ define void @main() #0 {
%srv0 = call target("dx.RawBuffer", i8, 0, 0)
@llvm.dx.resource.handlefrombinding.tdx.RawBuffer_i8_0_0t(
i32 1, i32 8, i32 1, i32 0, ptr null)
- %cbuf = call target("dx.CBuffer", target("dx.Layout", {float}, 4, 0))
+ %cbuf = call target("dx.CBuffer", <{ float }>)
@llvm.dx.resource.handlefrombinding(i32 3, i32 2, i32 1, i32 0, ptr null)
ret void
}
diff --git a/llvm/test/CodeGen/DirectX/ContainerData/PSVResources.ll b/llvm/test/CodeGen/DirectX/ContainerData/PSVResources.ll
index bea03102e4ccf..5f77af3bd9c3d 100644
--- a/llvm/test/CodeGen/DirectX/ContainerData/PSVResources.ll
+++ b/llvm/test/CodeGen/DirectX/ContainerData/PSVResources.ll
@@ -1,4 +1,4 @@
-; RUN: llc %s --filetype=obj -o - | obj2yaml | FileCheck %s
+;\ RUN: llc %s --filetype=obj -o - | obj2yaml | FileCheck %s
; Make sure resource table is created correctly.
; CHECK: Resources:
@@ -14,7 +14,7 @@ define void @main() #0 {
; CHECK: Kind: CBuffer
; CHECK: Flags:
; CHECK: UsedByAtomic64: false
- %cbuf = call target("dx.CBuffer", target("dx.Layout", {float}, 4, 0))
+ %cbuf = call target("dx.CBuffer", <{ float }>)
@llvm.dx.resource.handlefrombinding(i32 3, i32 2, i32 1, i32 0, ptr null)
; ByteAddressBuffer Buf : register(t8, space1)
diff --git a/llvm/test/CodeGen/DirectX/CreateHandleFromBinding.ll b/llvm/test/CodeGen/DirectX/CreateHandleFromBinding.ll
index 38f2de28dbe59..671fcef281314 100644
--- a/llvm/test/CodeGen/DirectX/CreateHandleFromBinding.ll
+++ b/llvm/test/CodeGen/DirectX/CreateHandleFromBinding.ll
@@ -72,7 +72,7 @@ define void @test_bindings() {
; CHECK: call %dx.types.Handle @dx.op.annotateHandle(i32 216, %dx.types.Handle [[BUF5]], %dx.types.ResourceProperties { i32 10, i32 1033 }) #[[#ATTR]]
; cbuffer cb0 : register(b0) { int4 i; float4 f; }
- %cb0 = call target("dx.CBuffer", target("dx.Layout", {<4 x i32>, <4 x float>}, 32, 0, 16))
+ %cb0 = call target("dx.CBuffer", <{ <4 x i32>, <4 x float> }>)
@llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, ptr null)
; CHECK: [[BUF6:%.*]] = call %dx.types.Handle @dx.op.createHandleFromBinding(i32 217, %dx.types.ResBind { i32 0, i32 0, i32 0, i8 2 }, i32 0, i1 false) #[[#ATTR]]
; CHECK: call %dx.types.Handle @dx.op.annotateHandle(i32 216, %dx.types.Handle [[BUF6]], %dx.types.ResourceProperties { i32 13, i32 32 }) #[[#ATTR]]
diff --git a/llvm/test/CodeGen/DirectX/ForwardHandleAccesses/cbuffer-access.ll b/llvm/test/CodeGen/DirectX/ForwardHandleAccesses/cbuffer-access.ll
index 26b157f35a3e4..d67486324d220 100644
--- a/llvm/test/CodeGen/DirectX/ForwardHandleAccesses/cbuffer-access.ll
+++ b/llvm/test/CodeGen/DirectX/ForwardHandleAccesses/cbuffer-access.ll
@@ -4,27 +4,27 @@
%__cblayout_CB2 = type <{ float }>
%struct.Scalars = type { float, i32, i32 }
- at CB.cb = local_unnamed_addr global target("dx.CBuffer", target("dx.Layout", %__cblayout_CB, 12, 0, 4, 8)) poison
- at CB2.cb = local_unnamed_addr global target("dx.CBuffer", target("dx.Layout", %__cblayout_CB2, 4, 0)) poison
+ at CB.cb = local_unnamed_addr global target("dx.CBuffer", %__cblayout_CB) poison
+ at CB2.cb = local_unnamed_addr global target("dx.CBuffer", %__cblayout_CB2) poison
define void @main() local_unnamed_addr #1 {
entry:
; CHECK: [[CB:%.*]] = tail call target({{.*}}) @llvm.dx.resource.handlefrombinding
- %h = tail call target("dx.CBuffer", target("dx.Layout", %__cblayout_CB, 12, 0, 4, 8)) @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, ptr null)
- store target("dx.CBuffer", target("dx.Layout", %__cblayout_CB, 12, 0, 4, 8)) %h, ptr @CB.cb, align 4
+ %h = tail call target("dx.CBuffer", %__cblayout_CB) @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, ptr null)
+ store target("dx.CBuffer", %__cblayout_CB) %h, ptr @CB.cb, align 4
%_ZL3Out_h.i.i = tail call target("dx.RawBuffer", %struct.Scalars, 1, 0) @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, ptr null)
; CHECK-NOT: load target({{.*}}), ptr @CB.cb
- %cb = load target("dx.CBuffer", target("dx.Layout", %__cblayout_CB, 12, 0, 4, 8)), ptr @CB.cb, align 4
+ %cb = load target("dx.CBuffer", %__cblayout_CB), ptr @CB.cb, align 4
; CHECK: call { float, float, float, float } @llvm.dx.resource.load.cbufferrow.4.{{.*}}(target({{.*}}) [[CB]], i32 0)
- %0 = call { float, float, float, float } @llvm.dx.resource.load.cbufferrow.4(target("dx.CBuffer", target("dx.Layout", %__cblayout_CB, 12, 0, 4, 8)) %cb, i32 0)
+ %0 = call { float, float, float, float } @llvm.dx.resource.load.cbufferrow.4(target("dx.CBuffer", %__cblayout_CB) %cb, i32 0)
%1 = extractvalue { float, float, float, float } %0, 0
call void @llvm.dx.resource.store.rawbuffer(target("dx.RawBuffer", %struct.Scalars, 1, 0) %_ZL3Out_h.i.i, i32 0, i32 0, float %1)
-
+
; CHECK: [[CB2:%.*]] = tail call target({{.*}}) @llvm.dx.resource.handlefromimplicitbinding
- %h2 = tail call target("dx.CBuffer", target("dx.Layout", %__cblayout_CB2, 4, 0)) @llvm.dx.resource.handlefromimplicitbinding(i32 100, i32 0, i32 1, i32 0, ptr null)
- store target("dx.CBuffer", target("dx.Layout", %__cblayout_CB2, 4, 0)) %h2, ptr @CB2.cb, align 4
+ %h2 = tail call target("dx.CBuffer", %__cblayout_CB2) @llvm.dx.resource.handlefromimplicitbinding(i32 100, i32 0, i32 1, i32 0, ptr null)
+ store target("dx.CBuffer", %__cblayout_CB2) %h2, ptr @CB2.cb, align 4
; CHECK-NOT: load target({{.*}}), ptr @CB2.cb
- %cb2 = load target("dx.CBuffer", target("dx.Layout", %__cblayout_CB2, 4, 0)), ptr @CB2.cb, align 4
+ %cb2 = load target("dx.CBuffer", %__cblayout_CB2), ptr @CB2.cb, align 4
ret void
}
diff --git a/llvm/test/CodeGen/DirectX/Metadata/cbuffer-only.ll b/llvm/test/CodeGen/DirectX/Metadata/cbuffer-only.ll
index e2a1c09c13038..0b454c12a74a2 100644
--- a/llvm/test/CodeGen/DirectX/Metadata/cbuffer-only.ll
+++ b/llvm/test/CodeGen/DirectX/Metadata/cbuffer-only.ll
@@ -7,7 +7,7 @@
target triple = "dxil-pc-shadermodel6.6-compute"
define void @cbuffer_is_only_binding() {
- %cbuf = call target("dx.CBuffer", target("dx.Layout", {float}, 4, 0))
+ %cbuf = call target("dx.CBuffer", <{ float }>)
@llvm.dx.resource.handlefrombinding(i32 1, i32 8, i32 1, i32 0, ptr null)
; CHECK: %CBuffer = type { float }
diff --git a/llvm/test/CodeGen/DirectX/Metadata/cbuffer_metadata.ll b/llvm/test/CodeGen/DirectX/Metadata/cbuffer_metadata.ll
index f1d28e28dafdc..828df02b48666 100644
--- a/llvm/test/CodeGen/DirectX/Metadata/cbuffer_metadata.ll
+++ b/llvm/test/CodeGen/DirectX/Metadata/cbuffer_metadata.ll
@@ -2,19 +2,24 @@
; RUN: opt -S --passes="dxil-pretty-printer" < %s 2>&1 | FileCheck %s --check-prefix=PRINT
; RUN: llc %s --filetype=asm -o - < %s 2>&1 | FileCheck %s --check-prefixes=CHECK,PRINT
-target datalayout = "e-m:e-p:32:32-i1:32-i8:8-i16:16-i32:32-i64:64-f16:16-f32:32-f64:64-n8:16:32:64"
target triple = "dxil-pc-shadermodel6.6-compute"
%__cblayout_CB1 = type <{ float, i32, double, <2 x i32> }>
- at CB1.cb = global target("dx.CBuffer", target("dx.Layout", %__cblayout_CB1, 24, 0, 4, 8, 16)) poison
+ at CB1.cb = global target("dx.CBuffer", %__cblayout_CB1) poison
@CB1.str = private unnamed_addr constant [4 x i8] c"CB1\00", align 1
-%__cblayout_CB2 = type <{ float, double, float, half, i16, i64, i32 }>
- at CB2.cb = global target("dx.CBuffer", target("dx.Layout", %__cblayout_CB2, 36, 0, 8, 16, 20, 22, 24, 32)) poison
+%__cblayout_CB2 = type <{ float, [4 x i8], double, float, half, i16, i64, i32 }>
+ at CB2.cb = global target("dx.CBuffer", %__cblayout_CB2) poison
@CB2.str = private unnamed_addr constant [4 x i8] c"CB2\00", align 1
-%__cblayout_MyConstants = type <{ double, <3 x float>, float, <3 x double>, half, <2 x double>, float, <3 x half>, <3 x half> }>
- at MyConstants.cb = global target("dx.CBuffer", target("dx.Layout", %__cblayout_MyConstants, 96, 0, 16, 28, 32, 56, 64, 80, 84, 90)) poison
+%__cblayout_MyConstants = type <{
+ double, [8 x i8],
+ <3 x float>, float,
+ <3 x double>, half, [6 x i8],
+ <2 x double>,
+ float, <3 x half>, <3 x half>
+}>
+ at MyConstants.cb = global target("dx.CBuffer", %__cblayout_MyConstants) poison
@MyConstants.str = private unnamed_addr constant [12 x i8] c"MyConstants\00", align 1
; PRINT:; Resource Bindings:
@@ -33,7 +38,7 @@ define void @test() #0 {
; double c;
; int2 d;
; }
- %CB1.cb_h = call target("dx.CBuffer", target("dx.Layout", %__cblayout_CB1, 24, 0, 4, 8, 16))
+ %CB1.cb_h = call target("dx.CBuffer", %__cblayout_CB1)
@llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, ptr @CB1.str)
; cbuffer CB2 : register(b0) {
; float a;
@@ -45,7 +50,7 @@ define void @test() #0 {
; int g;
;}
- %CB2.cb_h = call target("dx.CBuffer", target("dx.Layout", %__cblayout_CB2, 36, 0, 8, 16, 20, 22, 24, 32))
+ %CB2.cb_h = call target("dx.CBuffer", %__cblayout_CB2)
@llvm.dx.resource.handlefrombinding(i32 0, i32 1, i32 1, i32 0, ptr @CB2.str)
; cbuffer CB3 : register(b5) {
; double B0;
@@ -58,7 +63,7 @@ define void @test() #0 {
; half3 B7;
; half3 B8;
; }
- %CB3.cb_h = call target("dx.CBuffer", target("dx.Layout", %__cblayout_MyConstants, 96, 0, 16, 28, 32, 56, 64, 80, 84, 90))
+ %CB3.cb_h = call target("dx.CBuffer", %__cblayout_MyConstants)
@llvm.dx.resource.handlefrombinding(i32 15, i32 5, i32 1, i32 0, ptr @MyConstants.str)
ret void
>From c8864d565302f42c88ea7173dcefc12ed869db20 Mon Sep 17 00:00:00 2001
From: Justin Bogner <mail at justinbogner.com>
Date: Fri, 22 Aug 2025 16:26:15 -0600
Subject: [PATCH 06/11] wip: tweak array subscript handling for cbuffers
---
clang/lib/CodeGen/CGExpr.cpp | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index e8456a44f8367..2aefb1f501a1d 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -4678,6 +4678,26 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E,
emitArraySubscriptGEP(*this, Int8Ty, Addr.emitRawPointer(*this),
ScaledIdx, false, SignedIndices, E->getExprLoc());
Addr = Address(EltPtr, OrigBaseElemTy, EltAlign);
+ } else if (E->getType().getAddressSpace() == LangAS::hlsl_constant) {
+ // This is an array inside of a cbuffer.
+ Addr = EmitPointerWithAlignment(E->getBase(), &EltBaseInfo, &EltTBAAInfo);
+ auto *Idx = EmitIdxAfterBase(/*Promote*/true);
+
+ // ...
+ CharUnits RowAlignedSize = getContext()
+ .getTypeSizeInChars(E->getType())
+ .alignTo(CharUnits::fromQuantity(32));
+
+ llvm::Value *RowAlignedSizeVal =
+ llvm::ConstantInt::get(Idx->getType(), RowAlignedSize.getQuantity());
+ llvm::Value *ScaledIdx = Builder.CreateMul(Idx, RowAlignedSizeVal);
+
+ CharUnits EltAlign =
+ getArrayElementAlign(Addr.getAlignment(), Idx, RowAlignedSize);
+ llvm::Value *EltPtr =
+ emitArraySubscriptGEP(*this, Int8Ty, Addr.emitRawPointer(*this),
+ ScaledIdx, false, SignedIndices, E->getExprLoc());
+ Addr = Address(EltPtr, Addr.getElementType(), EltAlign);
} else if (const Expr *Array = isSimpleArrayDecayOperand(E->getBase())) {
// If this is A[i] where A is an array, the frontend will have decayed the
// base to be a ArrayToPointerDecay implicit cast. While correct, it is
>From e25d62f5ab7aec62645d7469e5ccb0ec589c8984 Mon Sep 17 00:00:00 2001
From: Justin Bogner <mail at justinbogner.com>
Date: Thu, 4 Sep 2025 08:51:46 -0700
Subject: [PATCH 07/11] wip: Handle cbuffer arrays in EmitAggregateCopy
---
clang/lib/CodeGen/CGExprAgg.cpp | 101 +++++++++++++++++++++++++++++++-
1 file changed, 100 insertions(+), 1 deletion(-)
diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp
index b8150a24d45fc..f963121d8fe70 100644
--- a/clang/lib/CodeGen/CGExprAgg.cpp
+++ b/clang/lib/CodeGen/CGExprAgg.cpp
@@ -488,6 +488,59 @@ static bool isTrivialFiller(Expr *E) {
return false;
}
+static CharUnits getArrayElementAlign(CharUnits arrayAlign, llvm::Value *idx,
+ CharUnits eltSize) {
+ // If we have a constant index, we can use the exact offset of the
+ // element we're accessing.
+ if (auto *constantIdx = dyn_cast<llvm::ConstantInt>(idx)) {
+ CharUnits offset = constantIdx->getZExtValue() * eltSize;
+ return arrayAlign.alignmentAtOffset(offset);
+ }
+
+ // Otherwise, use the worst-case alignment for any element.
+ return arrayAlign.alignmentOfArrayElement(eltSize);
+}
+
+[[maybe_unused]]
+static void EmitHLSLCBufferArrayCopy(CodeGenFunction &CGF, Address DestVal,
+ QualType DestTy, Address SrcVal,
+ QualType SrcTy, SourceLocation Loc) {
+ auto *SrcArrTy = cast<ConstantArrayType>(SrcTy);
+
+ // TODO: This is wrong...
+ llvm::IntegerType *IdxTy = llvm::IntegerType::get(CGF.getLLVMContext(), 32);
+
+ QualType ElemTy = SrcArrTy->getElementType();
+ CharUnits RowAlignedSize =
+ CGF.getContext().getTypeSizeInChars(ElemTy).alignTo(
+ CharUnits::fromQuantity(32));
+
+ uint64_t SrcSize = SrcArrTy->getZExtSize();
+ uint64_t DestSize = cast<ConstantArrayType>(DestTy)->getZExtSize();
+ assert(SrcSize == DestSize && "Cannot copy arrays of mismatches size");
+
+ for (uint64_t I = 0; I != SrcSize; ++I) {
+ llvm::ConstantInt *Idx = llvm::ConstantInt::get(IdxTy, I);
+
+ llvm::Value *RowAlignedSizeVal =
+ llvm::ConstantInt::get(IdxTy, RowAlignedSize.getQuantity());
+ llvm::Value *ScaledIdx = CGF.Builder.CreateMul(Idx, RowAlignedSizeVal);
+ CharUnits SrcAlign =
+ getArrayElementAlign(SrcVal.getAlignment(), Idx, RowAlignedSize);
+ Address SrcGEP =
+ CGF.Builder.CreateInBoundsGEP(SrcVal, ScaledIdx, CGF.Int8Ty, SrcAlign);
+
+ CharUnits DestAlign = CGF.getContext().getTypeAlignInChars(DestTy);
+ Address DestGEP = CGF.Builder.CreateInBoundsGEP(
+ DestVal, Idx, CGF.ConvertTypeForMem(DestTy), DestAlign);
+
+ llvm::Value *Load = CGF.Builder.CreateLoad(SrcGEP, "load");
+ //llvm::Value *Cast = CGF.EmitScalarConversion(Load, SrcTy, DestTy, Loc);
+
+ CGF.Builder.CreateStore(Load, DestGEP);
+ }
+}
+
static void EmitHLSLAggregateSplatCast(CodeGenFunction &CGF, Address DestVal,
QualType DestTy, llvm::Value *SrcVal,
QualType SrcTy, SourceLocation Loc) {
@@ -982,7 +1035,18 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
[[fallthrough]];
case CK_HLSLArrayRValue:
- Visit(E->getSubExpr());
+ // if (E->getSubExpr()->getType().getAddressSpace() == LangAS::hlsl_constant) {
+ // Expr *Src = E->getSubExpr();
+ // QualType SrcTy = Src->getType();
+ // LValue LV = CGF.EmitLValue(Src);
+ // QualType DestTy = E->getType();
+ // Address DestVal = Dest.getAddress();
+ // SourceLocation Loc = E->getExprLoc();
+
+ // Address SrcVal = LV.getAggregateAddress();
+ // EmitHLSLCBufferArrayCopy(CGF, DestVal, DestTy, SrcVal, SrcTy, Loc);
+ // } else
+ Visit(E->getSubExpr());
break;
case CK_HLSLAggregateSplatCast: {
Expr *Src = E->getSubExpr();
@@ -2315,6 +2379,41 @@ void CodeGenFunction::EmitAggregateCopy(LValue Dest, LValue Src, QualType Ty,
}
}
+ if (getLangOpts().HLSL && Ty.getAddressSpace() == LangAS::hlsl_constant &&
+ Ty->isArrayType()) {
+ // TODO: What about incomplete array types?
+ auto *ArrTy = cast<ConstantArrayType>(Ty);
+
+ QualType ElemTy = ArrTy->getElementType();
+ CharUnits RowAlignedSize = getContext().getTypeSizeInChars(ElemTy).alignTo(
+ CharUnits::fromQuantity(32));
+
+ for (uint64_t I = 0, E = ArrTy->getZExtSize(); I != E; ++I) {
+ llvm::ConstantInt *Idx = llvm::ConstantInt::get(SizeTy, I);
+
+ llvm::Value *RowAlignedSizeVal =
+ llvm::ConstantInt::get(SizeTy, RowAlignedSize.getQuantity());
+ llvm::Value *ScaledIdx = Builder.CreateMul(Idx, RowAlignedSizeVal);
+ CharUnits SrcAlign =
+ getArrayElementAlign(SrcPtr.getAlignment(), Idx, RowAlignedSize);
+ // Address SrcGEP =
+ // Builder.CreateInBoundsGEP(SrcPtr, ScaledIdx, Int8Ty, SrcAlign);
+ Address SrcGEP = RawAddress(
+ Builder.CreateInBoundsGEP(Int8Ty, SrcPtr.getBasePointer(), ScaledIdx),
+ ConvertTypeForMem(ElemTy), SrcAlign, SrcPtr.isKnownNonNull());
+
+ CharUnits DestAlign = getContext().getTypeAlignInChars(Ty);
+ Address DestGEP = Builder.CreateInBoundsGEP(
+ DestPtr, Idx, ConvertTypeForMem(ElemTy), DestAlign);
+
+ llvm::Value *Load = Builder.CreateLoad(SrcGEP, "load");
+ // TODO: Do we need a cast here to do the right thing recursively?
+ Builder.CreateStore(Load, DestGEP);
+ }
+
+ return;
+ }
+
// Aggregate assignment turns into llvm.memcpy. This is almost valid per
// C99 6.5.16.1p3, which states "If the value being stored in an object is
// read from another object that overlaps in anyway the storage of the first
>From e40fe129ebe4956e97c013048dd0225f960fdec1 Mon Sep 17 00:00:00 2001
From: Justin Bogner <mail at justinbogner.com>
Date: Thu, 4 Sep 2025 08:52:41 -0700
Subject: [PATCH 08/11] wip: Clean up unused code
---
clang/lib/CodeGen/CGExprAgg.cpp | 53 +--------------------------------
1 file changed, 1 insertion(+), 52 deletions(-)
diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp
index f963121d8fe70..724fb880527c4 100644
--- a/clang/lib/CodeGen/CGExprAgg.cpp
+++ b/clang/lib/CodeGen/CGExprAgg.cpp
@@ -501,46 +501,6 @@ static CharUnits getArrayElementAlign(CharUnits arrayAlign, llvm::Value *idx,
return arrayAlign.alignmentOfArrayElement(eltSize);
}
-[[maybe_unused]]
-static void EmitHLSLCBufferArrayCopy(CodeGenFunction &CGF, Address DestVal,
- QualType DestTy, Address SrcVal,
- QualType SrcTy, SourceLocation Loc) {
- auto *SrcArrTy = cast<ConstantArrayType>(SrcTy);
-
- // TODO: This is wrong...
- llvm::IntegerType *IdxTy = llvm::IntegerType::get(CGF.getLLVMContext(), 32);
-
- QualType ElemTy = SrcArrTy->getElementType();
- CharUnits RowAlignedSize =
- CGF.getContext().getTypeSizeInChars(ElemTy).alignTo(
- CharUnits::fromQuantity(32));
-
- uint64_t SrcSize = SrcArrTy->getZExtSize();
- uint64_t DestSize = cast<ConstantArrayType>(DestTy)->getZExtSize();
- assert(SrcSize == DestSize && "Cannot copy arrays of mismatches size");
-
- for (uint64_t I = 0; I != SrcSize; ++I) {
- llvm::ConstantInt *Idx = llvm::ConstantInt::get(IdxTy, I);
-
- llvm::Value *RowAlignedSizeVal =
- llvm::ConstantInt::get(IdxTy, RowAlignedSize.getQuantity());
- llvm::Value *ScaledIdx = CGF.Builder.CreateMul(Idx, RowAlignedSizeVal);
- CharUnits SrcAlign =
- getArrayElementAlign(SrcVal.getAlignment(), Idx, RowAlignedSize);
- Address SrcGEP =
- CGF.Builder.CreateInBoundsGEP(SrcVal, ScaledIdx, CGF.Int8Ty, SrcAlign);
-
- CharUnits DestAlign = CGF.getContext().getTypeAlignInChars(DestTy);
- Address DestGEP = CGF.Builder.CreateInBoundsGEP(
- DestVal, Idx, CGF.ConvertTypeForMem(DestTy), DestAlign);
-
- llvm::Value *Load = CGF.Builder.CreateLoad(SrcGEP, "load");
- //llvm::Value *Cast = CGF.EmitScalarConversion(Load, SrcTy, DestTy, Loc);
-
- CGF.Builder.CreateStore(Load, DestGEP);
- }
-}
-
static void EmitHLSLAggregateSplatCast(CodeGenFunction &CGF, Address DestVal,
QualType DestTy, llvm::Value *SrcVal,
QualType SrcTy, SourceLocation Loc) {
@@ -1035,18 +995,7 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
[[fallthrough]];
case CK_HLSLArrayRValue:
- // if (E->getSubExpr()->getType().getAddressSpace() == LangAS::hlsl_constant) {
- // Expr *Src = E->getSubExpr();
- // QualType SrcTy = Src->getType();
- // LValue LV = CGF.EmitLValue(Src);
- // QualType DestTy = E->getType();
- // Address DestVal = Dest.getAddress();
- // SourceLocation Loc = E->getExprLoc();
-
- // Address SrcVal = LV.getAggregateAddress();
- // EmitHLSLCBufferArrayCopy(CGF, DestVal, DestTy, SrcVal, SrcTy, Loc);
- // } else
- Visit(E->getSubExpr());
+ Visit(E->getSubExpr());
break;
case CK_HLSLAggregateSplatCast: {
Expr *Src = E->getSubExpr();
>From c676edc23a900018a274c70879d4049143a76ed7 Mon Sep 17 00:00:00 2001
From: Justin Bogner <mail at justinbogner.com>
Date: Tue, 9 Sep 2025 13:33:54 -0700
Subject: [PATCH 09/11] update some array assignable tests
---
clang/test/CodeGenHLSL/ArrayAssignable.hlsl | 23 +++++++++++++++------
1 file changed, 17 insertions(+), 6 deletions(-)
diff --git a/clang/test/CodeGenHLSL/ArrayAssignable.hlsl b/clang/test/CodeGenHLSL/ArrayAssignable.hlsl
index 721721f123ad0..8560699ecdc05 100644
--- a/clang/test/CodeGenHLSL/ArrayAssignable.hlsl
+++ b/clang/test/CodeGenHLSL/ArrayAssignable.hlsl
@@ -140,21 +140,32 @@ void arr_assign7() {
// CHECK-LABEL: define hidden void {{.*}}arr_assign8
// CHECK: [[C:%.*]] = alloca [2 x float], align 4
-// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[C]], ptr align 4 {{.*}}, i32 8, i1 false)
-// CHECK-NEXT: call void @llvm.memcpy.p0.p2.i32(ptr align 4 [[C]], ptr addrspace(2) align 4 @c1, i32 8, i1 false)
+// CHECK-NEXT: [[V0:%.*]] = getelementptr inbounds [2 x float], ptr [[C]], i32 0
+// CHECK-NEXT: [[L0:%.*]] = load float, ptr addrspace(2) @c1, align 4
+// CHECK-NEXT: store float [[L0]], ptr [[V0]], align 4
+// CHECK-NEXT: [[V1:%.*]] = getelementptr inbounds [2 x float], ptr [[C]], i32 1
+// CHECK-NEXT: [[L1:%.*]] = load float, ptr addrspace(2) getelementptr inbounds (i8, ptr addrspace(2) @c1, i32 32), align 4
+// CHECK-NEXT: store float [[L1]], ptr [[V1]], align 4
// CHECK-NEXT: ret void
void arr_assign8() {
- float C[2] = {1.0, 2.0};
+ float C[2];
C = c1;
}
+// TODO: A memcpy would actually be valid here, since everything is aligned on
+// 16 byte boundaries.
+//
// CHECK-LABEL: define hidden void {{.*}}arr_assign9
// CHECK: [[C:%.*]] = alloca [2 x <4 x i32>], align 16
-// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 16 [[C]], ptr align 16 {{.*}}, i32 32, i1 false)
-// CHECK-NEXT: call void @llvm.memcpy.p0.p2.i32(ptr align 16 [[C]], ptr addrspace(2) align 16 @c2, i32 32, i1 false)
+// CHECK-NEXT: [[V0:%.*]] = getelementptr inbounds [2 x <4 x i32>], ptr [[C]], i32 0
+// CHECK-NEXT: [[L0:%.*]] = load <4 x i32>, ptr addrspace(2) @c2, align 16
+// CHECK-NEXT: store <4 x i32> [[L0]], ptr [[V0]], align 16
+// CHECK-NEXT: [[V1:%.*]] = getelementptr inbounds [2 x <4 x i32>], ptr [[C]], i32 1
+// CHECK-NEXT: [[L1:%.*]] = load <4 x i32>, ptr addrspace(2) getelementptr inbounds (i8, ptr addrspace(2) @c2, i32 32), align 16
+// CHECK-NEXT: store <4 x i32> [[L1]], ptr [[V1]], align 16
// CHECK-NEXT: ret void
void arr_assign9() {
- int4 C[2] = {1,2,3,4,5,6,7,8};
+ int4 C[2];
C = c2;
}
>From c2ead6d6de42169585d61e672d9d4906d601e54f Mon Sep 17 00:00:00 2001
From: Justin Bogner <mail at justinbogner.com>
Date: Tue, 9 Sep 2025 14:08:37 -0700
Subject: [PATCH 10/11] [DirectX] Fix crash when naming buffers of arrays
DXILResource was falling over trying to name a resource type that
contained an array, such as `StructuredBuffer<float[3][2]>`. Handle this
by walking through array types to gather the dimensions.
---
llvm/lib/Analysis/DXILResource.cpp | 8 ++++++++
llvm/test/CodeGen/DirectX/Metadata/resource-symbols.ll | 9 ++++++++-
2 files changed, 16 insertions(+), 1 deletion(-)
diff --git a/llvm/lib/Analysis/DXILResource.cpp b/llvm/lib/Analysis/DXILResource.cpp
index 8502a86501273..5376656297deb 100644
--- a/llvm/lib/Analysis/DXILResource.cpp
+++ b/llvm/lib/Analysis/DXILResource.cpp
@@ -255,6 +255,12 @@ static void formatTypeName(SmallString<64> &Dest, StringRef Name,
if (!ContainedType)
return;
+ SmallVector<uint64_t> ArrayDimensions;
+ while (ArrayType *AT = dyn_cast<ArrayType>(ContainedType)) {
+ ArrayDimensions.push_back(AT->getNumElements());
+ ContainedType = AT->getElementType();
+ }
+
StringRef ElementName;
ElementType ET = toDXILElementType(ContainedType, IsSigned);
if (ET != ElementType::Invalid) {
@@ -271,6 +277,8 @@ static void formatTypeName(SmallString<64> &Dest, StringRef Name,
DestStream << "<" << ElementName;
if (const FixedVectorType *VTy = dyn_cast<FixedVectorType>(ContainedType))
DestStream << VTy->getNumElements();
+ for (uint64_t Dim : ArrayDimensions)
+ DestStream << "[" << Dim << "]";
DestStream << ">";
}
diff --git a/llvm/test/CodeGen/DirectX/Metadata/resource-symbols.ll b/llvm/test/CodeGen/DirectX/Metadata/resource-symbols.ll
index 4f13f4789cd66..56798c8382d45 100644
--- a/llvm/test/CodeGen/DirectX/Metadata/resource-symbols.ll
+++ b/llvm/test/CodeGen/DirectX/Metadata/resource-symbols.ll
@@ -28,6 +28,11 @@ define void @test() {
@llvm.dx.resource.handlefrombinding(i32 0, i32 10, i32 1, i32 0, ptr @SB.str)
; CHECK: %"StructuredBuffer<struct.S>" = type { %struct.S }
+ ; StructuredBuffer<float[3][2]>
+ %struct1 = call target("dx.RawBuffer", [3 x [2 x float]], 0, 0)
+ @llvm.dx.resource.handlefrombinding(i32 0, i32 12, i32 1, i32 0, ptr null)
+ ; CHECK: %"StructuredBuffer<float[3][2]>" = type { [3 x [2 x float]] }
+
; ByteAddressBuffer
%byteaddr = call target("dx.RawBuffer", i8, 0, 0)
@llvm.dx.resource.handlefrombinding(i32 0, i32 20, i32 1, i32 0, ptr null)
@@ -40,12 +45,14 @@ define void @test() {
; CHECK-NEXT: @[[T1:.*]] = external constant %"Buffer<int32_t>"
; CHECK-NEXT: @[[T2:.*]] = external constant %"Buffer<uint32_t3>"
; CHECK-NEXT: @[[S0:.*]] = external constant %"StructuredBuffer<struct.S>"
+; CHECK-NEXT: @[[S1:.*]] = external constant %"StructuredBuffer<float[3][2]>"
; CHECK-NEXT: @[[B0:.*]] = external constant %ByteAddressBuffer
; CHECK: !{i32 0, ptr @[[T0]], !"A"
; CHECK: !{i32 1, ptr @[[T1]], !""
; CHECK: !{i32 2, ptr @[[T2]], !""
; CHECK: !{i32 3, ptr @[[S0]], !"SB"
-; CHECK: !{i32 4, ptr @[[B0]], !""
+; CHECK: !{i32 4, ptr @[[S1]], !""
+; CHECK: !{i32 5, ptr @[[B0]], !""
attributes #0 = { nocallback nofree nosync nounwind willreturn memory(none) }
>From 8e728c52631a63b4735436c2580f78e8e43a34d6 Mon Sep 17 00:00:00 2001
From: Justin Bogner <mail at justinbogner.com>
Date: Tue, 9 Sep 2025 19:05:41 -0700
Subject: [PATCH 11/11] Rework EmitAggregateCopy to handle structs and
multidimensional arrays
---
clang/lib/CodeGen/CGExpr.cpp | 2 +-
clang/lib/CodeGen/CGExprAgg.cpp | 118 ++++++++++++--------
clang/test/CodeGenHLSL/ArrayAssignable.hlsl | 44 ++++++--
3 files changed, 106 insertions(+), 58 deletions(-)
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 2aefb1f501a1d..ecb0f16994030 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -4686,7 +4686,7 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E,
// ...
CharUnits RowAlignedSize = getContext()
.getTypeSizeInChars(E->getType())
- .alignTo(CharUnits::fromQuantity(32));
+ .alignTo(CharUnits::fromQuantity(16));
llvm::Value *RowAlignedSizeVal =
llvm::ConstantInt::get(Idx->getType(), RowAlignedSize.getQuantity());
diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp
index 724fb880527c4..af615a32e7723 100644
--- a/clang/lib/CodeGen/CGExprAgg.cpp
+++ b/clang/lib/CodeGen/CGExprAgg.cpp
@@ -488,19 +488,6 @@ static bool isTrivialFiller(Expr *E) {
return false;
}
-static CharUnits getArrayElementAlign(CharUnits arrayAlign, llvm::Value *idx,
- CharUnits eltSize) {
- // If we have a constant index, we can use the exact offset of the
- // element we're accessing.
- if (auto *constantIdx = dyn_cast<llvm::ConstantInt>(idx)) {
- CharUnits offset = constantIdx->getZExtValue() * eltSize;
- return arrayAlign.alignmentAtOffset(offset);
- }
-
- // Otherwise, use the worst-case alignment for any element.
- return arrayAlign.alignmentOfArrayElement(eltSize);
-}
-
static void EmitHLSLAggregateSplatCast(CodeGenFunction &CGF, Address DestVal,
QualType DestTy, llvm::Value *SrcVal,
QualType SrcTy, SourceLocation Loc) {
@@ -2293,6 +2280,76 @@ AggValueSlot::Overlap_t CodeGenFunction::getOverlapForBaseInit(
return AggValueSlot::MayOverlap;
}
+static CharUnits
+EmitHLSLCBufferCopy(CodeGenFunction &CGF, Address DestPtr, Address SrcPtr,
+ QualType Ty, SmallVectorImpl<llvm::Value *> &StoreIndices,
+ CharUnits LoadOffset = CharUnits::Zero()) {
+ // For arrays, each member in the cbuffer is aligned to a 16-byte offset.
+ if (const auto *AT = dyn_cast<ArrayType>(Ty)) {
+ // Incomplete array types in cbuffers don't make sense, so this must be a
+ // constant array type.
+ const auto *CAT = cast<ConstantArrayType>(AT);
+
+ QualType ElemTy = CAT->getElementType();
+ uint64_t NElems = CAT->getZExtSize();
+ assert(NElems && "empty array?");
+
+ CharUnits LoadIdx = CharUnits::Zero();
+ StoreIndices.push_back(nullptr);
+ for (uint64_t I = 0; I != NElems; ++I) {
+ LoadIdx = LoadIdx.alignTo(CharUnits::fromQuantity(16));
+
+ StoreIndices.back() = llvm::ConstantInt::get(CGF.SizeTy, I);
+ LoadIdx += EmitHLSLCBufferCopy(CGF, DestPtr, SrcPtr, ElemTy, StoreIndices,
+ LoadOffset + LoadIdx);
+ }
+ StoreIndices.pop_back();
+
+ return LoadIdx;
+ }
+
+ // For structs, we need to adjust for nested arrays
+ if (const auto *RT = dyn_cast<RecordType>(Ty)) {
+ const RecordDecl *Record = RT->getOriginalDecl()->getDefinitionOrSelf();
+ assert(!Record->isUnion() && "Union type in cbuffer?");
+
+ if (Record->field_empty())
+ return CharUnits::Zero();
+
+ uint64_t StoreIdx = 0;
+ CharUnits LoadIdx = CharUnits::Zero();
+ StoreIndices.push_back(nullptr);
+ for (auto *FD : Record->fields()) {
+ QualType FieldTy = FD->getType();
+ LoadIdx = LoadIdx.alignTo(CGF.getContext().getTypeAlignInChars(FieldTy));
+
+ StoreIndices.back() = llvm::ConstantInt::get(CGF.SizeTy, StoreIdx++);
+ LoadIdx += EmitHLSLCBufferCopy(CGF, DestPtr, SrcPtr, FieldTy,
+ StoreIndices, LoadOffset + LoadIdx);
+ }
+ StoreIndices.pop_back();
+
+ return LoadIdx;
+ }
+
+ // We have a leaf, emit the copy.
+ CharUnits Align = CGF.getContext().getTypeAlignInChars(Ty);
+
+ llvm::Type *LLVMTy = CGF.ConvertTypeForMem(Ty);
+ llvm::ConstantInt *LoadOffsetVal =
+ llvm::ConstantInt::get(CGF.SizeTy, LoadOffset.getQuantity());
+ Address SrcGEP =
+ RawAddress(CGF.Builder.CreateInBoundsGEP(
+ CGF.Int8Ty, SrcPtr.getBasePointer(), LoadOffsetVal),
+ LLVMTy, Align, SrcPtr.isKnownNonNull());
+ Address DestGEP =
+ CGF.Builder.CreateInBoundsGEP(DestPtr, StoreIndices, LLVMTy, Align);
+
+ llvm::Value *Load = CGF.Builder.CreateLoad(SrcGEP, "cbuf.load");
+ CGF.Builder.CreateStore(Load, DestGEP);
+ return CGF.getContext().getTypeSizeInChars(Ty);
+}
+
void CodeGenFunction::EmitAggregateCopy(LValue Dest, LValue Src, QualType Ty,
AggValueSlot::Overlap_t MayOverlap,
bool isVolatile) {
@@ -2328,38 +2385,9 @@ void CodeGenFunction::EmitAggregateCopy(LValue Dest, LValue Src, QualType Ty,
}
}
- if (getLangOpts().HLSL && Ty.getAddressSpace() == LangAS::hlsl_constant &&
- Ty->isArrayType()) {
- // TODO: What about incomplete array types?
- auto *ArrTy = cast<ConstantArrayType>(Ty);
-
- QualType ElemTy = ArrTy->getElementType();
- CharUnits RowAlignedSize = getContext().getTypeSizeInChars(ElemTy).alignTo(
- CharUnits::fromQuantity(32));
-
- for (uint64_t I = 0, E = ArrTy->getZExtSize(); I != E; ++I) {
- llvm::ConstantInt *Idx = llvm::ConstantInt::get(SizeTy, I);
-
- llvm::Value *RowAlignedSizeVal =
- llvm::ConstantInt::get(SizeTy, RowAlignedSize.getQuantity());
- llvm::Value *ScaledIdx = Builder.CreateMul(Idx, RowAlignedSizeVal);
- CharUnits SrcAlign =
- getArrayElementAlign(SrcPtr.getAlignment(), Idx, RowAlignedSize);
- // Address SrcGEP =
- // Builder.CreateInBoundsGEP(SrcPtr, ScaledIdx, Int8Ty, SrcAlign);
- Address SrcGEP = RawAddress(
- Builder.CreateInBoundsGEP(Int8Ty, SrcPtr.getBasePointer(), ScaledIdx),
- ConvertTypeForMem(ElemTy), SrcAlign, SrcPtr.isKnownNonNull());
-
- CharUnits DestAlign = getContext().getTypeAlignInChars(Ty);
- Address DestGEP = Builder.CreateInBoundsGEP(
- DestPtr, Idx, ConvertTypeForMem(ElemTy), DestAlign);
-
- llvm::Value *Load = Builder.CreateLoad(SrcGEP, "load");
- // TODO: Do we need a cast here to do the right thing recursively?
- Builder.CreateStore(Load, DestGEP);
- }
-
+ if (getLangOpts().HLSL && Ty.getAddressSpace() == LangAS::hlsl_constant) {
+ SmallVector<llvm::Value *> StoreIndices;
+ EmitHLSLCBufferCopy(*this, DestPtr, SrcPtr, Ty, StoreIndices);
return;
}
diff --git a/clang/test/CodeGenHLSL/ArrayAssignable.hlsl b/clang/test/CodeGenHLSL/ArrayAssignable.hlsl
index 8560699ecdc05..afad227318c3a 100644
--- a/clang/test/CodeGenHLSL/ArrayAssignable.hlsl
+++ b/clang/test/CodeGenHLSL/ArrayAssignable.hlsl
@@ -5,18 +5,18 @@ struct S {
float f;
};
-// CHECK: [[CBLayout:%.*]] = type <{ <{ [1 x <{ float, [12 x i8] }>], float }>, [12 x i8], [2 x <4 x i32>], <{ [3 x <{ i32, [12 x i8] }>], i32 }>, [12 x i8], [1 x %S] }>
+// CHECK: [[CBLayout:%.*]] = type <{ <{ [1 x <{ float, [12 x i8] }>], float }>, [12 x i8], [2 x <4 x i32>], <{ [3 x <{ i32, [12 x i8] }>], i32 }>, [12 x i8], <{ [1 x <{ %S, [8 x i8] }>], %S }> }>
// CHECK: @CBArrays.cb = global target("dx.CBuffer", [[CBLayout]])
// CHECK: @c1 = external hidden addrspace(2) global <{ [1 x <{ float, [12 x i8] }>], float }>, align 4
// CHECK: @c2 = external hidden addrspace(2) global [2 x <4 x i32>], align 16
// CHECK: @c3 = external hidden addrspace(2) global <{ [3 x <{ i32, [12 x i8] }>], i32 }>, align 4
-// CHECK: @c4 = external hidden addrspace(2) global [1 x %S], align 1
+// CHECK: @c4 = external hidden addrspace(2) global <{ [1 x <{ %S, [8 x i8] }>], %S }>, align 1
cbuffer CBArrays : register(b0) {
float c1[2];
int4 c2[2];
int c3[2][2];
- S c4[1];
+ S c4[2];
}
// CHECK-LABEL: define hidden void {{.*}}arr_assign1
@@ -144,7 +144,7 @@ void arr_assign7() {
// CHECK-NEXT: [[L0:%.*]] = load float, ptr addrspace(2) @c1, align 4
// CHECK-NEXT: store float [[L0]], ptr [[V0]], align 4
// CHECK-NEXT: [[V1:%.*]] = getelementptr inbounds [2 x float], ptr [[C]], i32 1
-// CHECK-NEXT: [[L1:%.*]] = load float, ptr addrspace(2) getelementptr inbounds (i8, ptr addrspace(2) @c1, i32 32), align 4
+// CHECK-NEXT: [[L1:%.*]] = load float, ptr addrspace(2) getelementptr inbounds (i8, ptr addrspace(2) @c1, i32 16), align 4
// CHECK-NEXT: store float [[L1]], ptr [[V1]], align 4
// CHECK-NEXT: ret void
void arr_assign8() {
@@ -161,7 +161,7 @@ void arr_assign8() {
// CHECK-NEXT: [[L0:%.*]] = load <4 x i32>, ptr addrspace(2) @c2, align 16
// CHECK-NEXT: store <4 x i32> [[L0]], ptr [[V0]], align 16
// CHECK-NEXT: [[V1:%.*]] = getelementptr inbounds [2 x <4 x i32>], ptr [[C]], i32 1
-// CHECK-NEXT: [[L1:%.*]] = load <4 x i32>, ptr addrspace(2) getelementptr inbounds (i8, ptr addrspace(2) @c2, i32 32), align 16
+// CHECK-NEXT: [[L1:%.*]] = load <4 x i32>, ptr addrspace(2) getelementptr inbounds (i8, ptr addrspace(2) @c2, i32 16), align 16
// CHECK-NEXT: store <4 x i32> [[L1]], ptr [[V1]], align 16
// CHECK-NEXT: ret void
void arr_assign9() {
@@ -171,20 +171,40 @@ void arr_assign9() {
// CHECK-LABEL: define hidden void {{.*}}arr_assign10
// CHECK: [[C:%.*]] = alloca [2 x [2 x i32]], align 4
-// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[C]], ptr align 4 {{.*}}, i32 16, i1 false)
-// CHECK-NEXT: call void @llvm.memcpy.p0.p2.i32(ptr align 4 [[C]], ptr addrspace(2) align 4 @c3, i32 16, i1 false)
+// CHECK-NEXT: [[V0:%.*]] = getelementptr inbounds [2 x [2 x i32]], ptr [[C]], i32 0, i32 0
+// CHECK-NEXT: [[L0:%.*]] = load i32, ptr addrspace(2) @c3, align 4
+// CHECK-NEXT: store i32 [[L0]], ptr [[V0]], align 4
+// CHECK-NEXT: [[V1:%.*]] = getelementptr inbounds [2 x [2 x i32]], ptr [[C]], i32 0, i32 1
+// CHECK-NEXT: [[L1:%.*]] = load i32, ptr addrspace(2) getelementptr inbounds (i8, ptr addrspace(2) @c3, i32 16), align 4
+// CHECK-NEXT: store i32 [[L1]], ptr [[V1]], align 4
+// CHECK-NEXT: [[V2:%.*]] = getelementptr inbounds [2 x [2 x i32]], ptr [[C]], i32 1, i32 0
+// CHECK-NEXT: [[L2:%.*]] = load i32, ptr addrspace(2) getelementptr inbounds (i8, ptr addrspace(2) @c3, i32 32), align 4
+// CHECK-NEXT: store i32 [[L2]], ptr [[V2]], align 4
+// CHECK-NEXT: [[V3:%.*]] = getelementptr inbounds [2 x [2 x i32]], ptr [[C]], i32 1, i32 1
+// CHECK-NEXT: [[L3:%.*]] = load i32, ptr addrspace(2) getelementptr inbounds (i8, ptr addrspace(2) @c3, i32 48), align 4
+// CHECK-NEXT: store i32 [[L3]], ptr [[V3]], align 4
// CHECK-NEXT: ret void
void arr_assign10() {
- int C[2][2] = {1,2,3,4};
+ int C[2][2];
C = c3;
}
// CHECK-LABEL: define hidden void {{.*}}arr_assign11
-// CHECK: [[C:%.*]] = alloca [1 x %struct.S], align 1
-// CHECK: call void @llvm.memcpy.p0.p2.i32(ptr align 1 [[C]], ptr addrspace(2) align 1 @c4, i32 8, i1 false)
+// CHECK: [[C:%.*]] = alloca [2 x %struct.S], align 1
+// CHECK-NEXT: [[V0:%.*]] = getelementptr inbounds [2 x %struct.S], ptr [[C]], i32 0, i32 0
+// CHECK-NEXT: [[L0:%.*]] = load i32, ptr addrspace(2) @c4, align 4
+// CHECK-NEXT: store i32 [[L0]], ptr [[V0]], align 4
+// CHECK-NEXT: [[V1:%.*]] = getelementptr inbounds [2 x %struct.S], ptr [[C]], i32 0, i32 1
+// CHECK-NEXT: [[L1:%.*]] = load float, ptr addrspace(2) getelementptr inbounds (i8, ptr addrspace(2) @c4, i32 4), align 4
+// CHECK-NEXT: store float [[L1]], ptr [[V1]], align 4
+// CHECK-NEXT: [[V2:%.*]] = getelementptr inbounds [2 x %struct.S], ptr [[C]], i32 1, i32 0
+// CHECK-NEXT: [[L2:%.*]] = load i32, ptr addrspace(2) getelementptr inbounds (i8, ptr addrspace(2) @c4, i32 16), align 4
+// CHECK-NEXT: store i32 [[L2]], ptr [[V2]], align 4
+// CHECK-NEXT: [[V3:%.*]] = getelementptr inbounds [2 x %struct.S], ptr [[C]], i32 1, i32 1
+// CHECK-NEXT: [[L3:%.*]] = load float, ptr addrspace(2) getelementptr inbounds (i8, ptr addrspace(2) @c4, i32 20), align 4
+// CHECK-NEXT: store float [[L3]], ptr [[V3]], align 4
// CHECK-NEXT: ret void
void arr_assign11() {
- S s = {1, 2.0};
- S C[1] = {s};
+ S C[2];
C = c4;
}
More information about the llvm-commits
mailing list