-
Notifications
You must be signed in to change notification settings - Fork 14.4k
[DirectX] Support the CBufferLoadLegacy operation #128699
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@llvm/pr-subscribers-tablegen @llvm/pr-subscribers-backend-directx Author: Justin Bogner (bogner) ChangesFixes #112992 Full diff: https://github.com/llvm/llvm-project/pull/128699.diff 9 Files Affected:
diff --git a/llvm/docs/DirectX/DXILResources.rst b/llvm/docs/DirectX/DXILResources.rst
index 80e3c2c11153d..91dcd5c8d5214 100644
--- a/llvm/docs/DirectX/DXILResources.rst
+++ b/llvm/docs/DirectX/DXILResources.rst
@@ -277,7 +277,7 @@ Examples:
Accessing Resources as Memory
-----------------------------
-*relevant types: Buffers, CBuffer, and Textures*
+*relevant types: Buffers and Textures*
Loading and storing from resources is generally represented in LLVM using
operations on memory that is only accessible via a handle object. Given a
@@ -321,12 +321,11 @@ Examples:
Loads, Samples, and Gathers
---------------------------
-*relevant types: Buffers, CBuffers, and Textures*
+*relevant types: Buffers and Textures*
-All load, sample, and gather operations in DXIL return a `ResRet`_ type, and
-CBuffer loads return a similar `CBufRet`_ type. These types are structs
-containing 4 elements of some basic type, and in the case of `ResRet` a 5th
-element that is used by the `CheckAccessFullyMapped`_ operation. Some of these
+All load, sample, and gather operations in DXIL return a `ResRet`_ type. These
+types are structs containing 4 elements of some basic type, and a 5th element
+that is used by the `CheckAccessFullyMapped`_ operation. Some of these
operations, like `RawBufferLoad`_ include a mask and/or alignment that tell us
some information about how to interpret those four values.
@@ -632,3 +631,118 @@ Examples:
target("dx.RawBuffer", i8, 1, 0, 0) %buffer,
i32 %index, i32 0, <4 x double> %data)
+Constant Buffer Loads
+---------------------
+
+*relevant types: CBuffers*
+
+The `CBufferLoadLegacy`_ operation, which despite the name is the only
+supported way to load from a cbuffer in any DXIL version, loads a single "row"
+of a cbuffer, which is exactly 16 bytes. The return value of the operation is
+represented by a `CBufRet`_ type, which has variants for 2 64-bit values, 4
+32-bit values, and 8 16-bit values.
+
+We represent these in LLVM IR with 3 separate operations, which return a
+2-element, 4-element, or 8-element struct respectively.
+
+.. _CBufferLoadLegacy: https://github.com/microsoft/DirectXShaderCompiler/blob/main/docs/DXIL.rst#cbufferLoadLegacy
+.. _CBufRet: https://github.com/microsoft/DirectXShaderCompiler/blob/main/docs/DXIL.rst#cbufferloadlegacy
+
+.. list-table:: ``@llvm.dx.resource.load.cbufferrow.4``
+ :header-rows: 1
+
+ * - Argument
+ -
+ - Type
+ - Description
+ * - Return value
+ -
+ - A struct of 4 32-bit values
+ - A single row of a cbuffer, interpreted as 4 32-bit values
+ * - ``%buffer``
+ - 0
+ - ``target(dx.CBuffer, ...)``
+ - The buffer to load from
+ * - ``%index``
+ - 1
+ - ``i32``
+ - Index into the buffer
+
+Examples:
+
+.. code-block:: llvm
+
+ %ret = call {float, float, float, float}
+ @llvm.dx.resource.load.cbufferrow.4(
+ target("dx.CBuffer", target("dx.Layout", {float}, 4, 0)) %buffer,
+ i32 %index)
+ %ret = call {i32, i32, i32, i32}
+ @llvm.dx.resource.load.cbufferrow.4(
+ target("dx.CBuffer", target("dx.Layout", {i32}, 4, 0)) %buffer,
+ i32 %index)
+
+.. list-table:: ``@llvm.dx.resource.load.cbufferrow.2``
+ :header-rows: 1
+
+ * - Argument
+ -
+ - Type
+ - Description
+ * - Return value
+ -
+ - A struct of 2 64-bit values
+ - A single row of a cbuffer, interpreted as 2 64-bit values
+ * - ``%buffer``
+ - 0
+ - ``target(dx.CBuffer, ...)``
+ - The buffer to load from
+ * - ``%index``
+ - 1
+ - ``i32``
+ - Index into the buffer
+
+Examples:
+
+.. code-block:: llvm
+
+ %ret = call {double, double}
+ @llvm.dx.resource.load.cbufferrow.2(
+ target("dx.CBuffer", target("dx.Layout", {double}, 8, 0)) %buffer,
+ i32 %index)
+ %ret = call {i64, i64}
+ @llvm.dx.resource.load.cbufferrow.2(
+ target("dx.CBuffer", target("dx.Layout", {i64}, 4, 0)) %buffer,
+ i32 %index)
+
+.. list-table:: ``@llvm.dx.resource.load.cbufferrow.8``
+ :header-rows: 1
+
+ * - Argument
+ -
+ - Type
+ - Description
+ * - Return value
+ -
+ - A struct of 8 16-bit values
+ - A single row of a cbuffer, interpreted as 8 16-bit values
+ * - ``%buffer``
+ - 0
+ - ``target(dx.CBuffer, ...)``
+ - The buffer to load from
+ * - ``%index``
+ - 1
+ - ``i32``
+ - Index into the buffer
+
+Examples:
+
+.. code-block:: llvm
+
+ %ret = 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,
+ i32 %index)
+ %ret = call {i16, i16, i16, i16, i16, i16, i16, i16}
+ @llvm.dx.resource.load.cbufferrow.8(
+ target("dx.CBuffer", target("dx.Layout", {i16}, 2, 0)) %buffer,
+ i32 %index)
diff --git a/llvm/include/llvm/IR/IntrinsicsDirectX.td b/llvm/include/llvm/IR/IntrinsicsDirectX.td
index beed84b144cec..87de68cb3ad4f 100644
--- a/llvm/include/llvm/IR/IntrinsicsDirectX.td
+++ b/llvm/include/llvm/IR/IntrinsicsDirectX.td
@@ -45,6 +45,21 @@ def int_dx_resource_store_rawbuffer
[], [llvm_any_ty, llvm_i32_ty, llvm_i32_ty, llvm_any_ty],
[IntrWriteMem]>;
+// dx.resource.load.cbufferrow encodes the number of elements returned in the
+// function name. The total size of the return should always be 128 bits.
+def int_dx_resource_load_cbufferrow_8
+ : DefaultAttrsIntrinsic<
+ [llvm_any_ty, llvm_any_ty, llvm_any_ty, llvm_any_ty,
+ llvm_any_ty, llvm_any_ty, llvm_any_ty, llvm_any_ty],
+ [llvm_any_ty, llvm_i32_ty], [IntrReadMem]>;
+def int_dx_resource_load_cbufferrow_4
+ : DefaultAttrsIntrinsic<
+ [llvm_any_ty, llvm_any_ty, llvm_any_ty, llvm_any_ty],
+ [llvm_any_ty, llvm_i32_ty], [IntrReadMem]>;
+def int_dx_resource_load_cbufferrow_2
+ : DefaultAttrsIntrinsic<[llvm_any_ty, llvm_any_ty],
+ [llvm_any_ty, llvm_i32_ty], [IntrReadMem]>;
+
def int_dx_resource_updatecounter
: DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_any_ty, llvm_i8_ty],
[IntrInaccessibleMemOrArgMemOnly]>;
diff --git a/llvm/lib/Target/DirectX/DXIL.td b/llvm/lib/Target/DirectX/DXIL.td
index d59e28c37b91d..74fd62a028b09 100644
--- a/llvm/lib/Target/DirectX/DXIL.td
+++ b/llvm/lib/Target/DirectX/DXIL.td
@@ -46,6 +46,12 @@ def ResRetDoubleTy : DXILOpParamType;
def ResRetInt16Ty : DXILOpParamType;
def ResRetInt32Ty : DXILOpParamType;
def ResRetInt64Ty : DXILOpParamType;
+def CBufRetHalfTy : DXILOpParamType;
+def CBufRetFloatTy : DXILOpParamType;
+def CBufRetDoubleTy : DXILOpParamType;
+def CBufRetInt16Ty : DXILOpParamType;
+def CBufRetInt32Ty : DXILOpParamType;
+def CBufRetInt64Ty : DXILOpParamType;
def HandleTy : DXILOpParamType;
def ResBindTy : DXILOpParamType;
def ResPropsTy : DXILOpParamType;
@@ -816,6 +822,19 @@ def CreateHandle : DXILOp<57, createHandle> {
let attributes = [Attributes<DXIL1_0, [ReadOnly]>];
}
+def CBufferLoadLegacy : DXILOp<59, cbufferLoadLegacy> {
+ let Doc = "reads from a TypedBuffer";
+ // Handle, Index
+ let arguments = [HandleTy, Int32Ty];
+ let result = OverloadTy;
+ let overloads = [Overloads<DXIL1_0, [
+ CBufRetHalfTy, CBufRetFloatTy, CBufRetDoubleTy, CBufRetInt16Ty,
+ CBufRetInt32Ty, CBufRetInt64Ty
+ ]>];
+ let stages = [Stages<DXIL1_0, [all_stages]>];
+ let attributes = [Attributes<DXIL1_0, [ReadOnly]>];
+}
+
def BufferLoad : DXILOp<68, bufferLoad> {
let Doc = "reads from a TypedBuffer";
// Handle, Coord0, Coord1
diff --git a/llvm/lib/Target/DirectX/DXILOpBuilder.cpp b/llvm/lib/Target/DirectX/DXILOpBuilder.cpp
index 6bbe8d5d12280..f45f86f60100d 100644
--- a/llvm/lib/Target/DirectX/DXILOpBuilder.cpp
+++ b/llvm/lib/Target/DirectX/DXILOpBuilder.cpp
@@ -201,6 +201,30 @@ static StructType *getResRetType(Type *ElementTy) {
return getOrCreateStructType(TypeName, FieldTypes, Ctx);
}
+static StructType *getCBufRetType(Type *ElementTy) {
+ LLVMContext &Ctx = ElementTy->getContext();
+ OverloadKind Kind = getOverloadKind(ElementTy);
+ std::string TypeName = constructOverloadTypeName(Kind, "dx.types.CBufRet.");
+
+ // 64-bit types only have two elements
+ if (ElementTy->isDoubleTy() || ElementTy->isIntegerTy(64))
+ return getOrCreateStructType(
+ TypeName, {ElementTy, ElementTy}, Ctx);
+
+ // 16-bit types pack 8 elements and have .8 in their name to differentiate
+ // from min-precision types.
+ if (ElementTy->isHalfTy() || ElementTy->isIntegerTy(16)) {
+ TypeName += ".8";
+ return getOrCreateStructType(TypeName,
+ {ElementTy, ElementTy, ElementTy, ElementTy,
+ ElementTy, ElementTy, ElementTy, ElementTy},
+ Ctx);
+ }
+
+ return getOrCreateStructType(
+ TypeName, {ElementTy, ElementTy, ElementTy, ElementTy}, Ctx);
+}
+
static StructType *getHandleType(LLVMContext &Ctx) {
return getOrCreateStructType("dx.types.Handle", PointerType::getUnqual(Ctx),
Ctx);
@@ -265,6 +289,18 @@ static Type *getTypeFromOpParamType(OpParamType Kind, LLVMContext &Ctx,
return getResRetType(Type::getInt32Ty(Ctx));
case OpParamType::ResRetInt64Ty:
return getResRetType(Type::getInt64Ty(Ctx));
+ case OpParamType::CBufRetHalfTy:
+ return getCBufRetType(Type::getHalfTy(Ctx));
+ case OpParamType::CBufRetFloatTy:
+ return getCBufRetType(Type::getFloatTy(Ctx));
+ case OpParamType::CBufRetDoubleTy:
+ return getCBufRetType(Type::getDoubleTy(Ctx));
+ case OpParamType::CBufRetInt16Ty:
+ return getCBufRetType(Type::getInt16Ty(Ctx));
+ case OpParamType::CBufRetInt32Ty:
+ return getCBufRetType(Type::getInt32Ty(Ctx));
+ case OpParamType::CBufRetInt64Ty:
+ return getCBufRetType(Type::getInt64Ty(Ctx));
case OpParamType::HandleTy:
return getHandleType(Ctx);
case OpParamType::ResBindTy:
@@ -535,6 +571,10 @@ StructType *DXILOpBuilder::getResRetType(Type *ElementTy) {
return ::getResRetType(ElementTy);
}
+StructType *DXILOpBuilder::getCBufRetType(Type *ElementTy) {
+ return ::getCBufRetType(ElementTy);
+}
+
StructType *DXILOpBuilder::getHandleType() {
return ::getHandleType(IRB.getContext());
}
diff --git a/llvm/lib/Target/DirectX/DXILOpBuilder.h b/llvm/lib/Target/DirectX/DXILOpBuilder.h
index 5fe9f4429a494..0985f2ee7cf1f 100644
--- a/llvm/lib/Target/DirectX/DXILOpBuilder.h
+++ b/llvm/lib/Target/DirectX/DXILOpBuilder.h
@@ -50,6 +50,9 @@ class DXILOpBuilder {
/// Get a `%dx.types.ResRet` type with the given element type.
StructType *getResRetType(Type *ElementTy);
+ /// Get a `%dx.types.CBufRet` type with the given element type.
+ StructType *getCBufRetType(Type *ElementTy);
+
/// Get the `%dx.types.Handle` type.
StructType *getHandleType();
diff --git a/llvm/lib/Target/DirectX/DXILOpLowering.cpp b/llvm/lib/Target/DirectX/DXILOpLowering.cpp
index 83cc4b18824c7..e4239b2bc6628 100644
--- a/llvm/lib/Target/DirectX/DXILOpLowering.cpp
+++ b/llvm/lib/Target/DirectX/DXILOpLowering.cpp
@@ -569,6 +569,32 @@ class OpLowerer {
});
}
+ [[nodiscard]] bool lowerCBufferLoad(Function &F) {
+ IRBuilder<> &IRB = OpBuilder.getIRB();
+
+ return replaceFunction(F, [&](CallInst *CI) -> Error {
+ IRB.SetInsertPoint(CI);
+
+ Type *OldTy = cast<StructType>(CI->getType())->getElementType(0);
+ Type *ScalarTy = OldTy->getScalarType();
+ Type *NewRetTy = OpBuilder.getCBufRetType(ScalarTy);
+
+ Value *Handle =
+ createTmpHandleCast(CI->getArgOperand(0), OpBuilder.getHandleType());
+ Value *Index = CI->getArgOperand(1);
+
+ Expected<CallInst *> OpCall = OpBuilder.tryCreateOp(
+ OpCode::CBufferLoadLegacy, {Handle, Index}, CI->getName(), NewRetTy);
+ if (Error E = OpCall.takeError())
+ return E;
+ if (Error E = replaceNamedStructUses(CI, *OpCall))
+ return E;
+
+ CI->eraseFromParent();
+ return Error::success();
+ });
+ }
+
[[nodiscard]] bool lowerUpdateCounter(Function &F) {
IRBuilder<> &IRB = OpBuilder.getIRB();
Type *Int32Ty = IRB.getInt32Ty();
@@ -796,6 +822,11 @@ class OpLowerer {
case Intrinsic::dx_resource_store_rawbuffer:
HasErrors |= lowerBufferStore(F, /*IsRaw=*/true);
break;
+ case Intrinsic::dx_resource_load_cbufferrow_2:
+ case Intrinsic::dx_resource_load_cbufferrow_4:
+ case Intrinsic::dx_resource_load_cbufferrow_8:
+ HasErrors |= lowerCBufferLoad(F);
+ break;
case Intrinsic::dx_resource_updatecounter:
HasErrors |= lowerUpdateCounter(F);
break;
diff --git a/llvm/test/CodeGen/DirectX/CBufferLoadLegacy-errors.ll b/llvm/test/CodeGen/DirectX/CBufferLoadLegacy-errors.ll
new file mode 100644
index 0000000000000..66dc1d2f36636
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/CBufferLoadLegacy-errors.ll
@@ -0,0 +1,45 @@
+; We use llc for this test so that we don't abort after the first error.
+; RUN: not llc %s -o /dev/null 2>&1 | FileCheck %s
+
+target triple = "dxil-pc-shadermodel6.6-compute"
+
+declare void @f32_user(float)
+declare void @f64_user(double)
+declare void @f16_user(half)
+
+; CHECK: error:
+; 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))
+ @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, i1 false)
+
+ %load = call {double, double, double, double} @llvm.dx.resource.load.cbufferrow.4(
+ target("dx.CBuffer", target("dx.Layout", {double}, 8, 0)) %buffer,
+ i32 0)
+ %data = extractvalue {double, double, double, double} %load, 0
+
+ call void @f64_user(double %data)
+
+ ret void
+}
+
+; CHECK: error:
+; 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))
+ @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, i1 false)
+
+ %load = call {float, float} @llvm.dx.resource.load.cbufferrow.2(
+ target("dx.CBuffer", target("dx.Layout", {float}, 4, 0)) %buffer,
+ i32 0)
+ %data = extractvalue {float, float} %load, 0
+
+ call void @f32_user(float %data)
+
+ 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)
diff --git a/llvm/test/CodeGen/DirectX/CBufferLoadLegacy.ll b/llvm/test/CodeGen/DirectX/CBufferLoadLegacy.ll
new file mode 100644
index 0000000000000..12b02cfd27823
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/CBufferLoadLegacy.ll
@@ -0,0 +1,63 @@
+; RUN: opt -S -dxil-op-lower %s | FileCheck %s
+
+target triple = "dxil-pc-shadermodel6.6-compute"
+
+declare void @f32_user(float)
+declare void @f64_user(double)
+declare void @f16_user(half)
+
+; CHECK-LABEL: define void @loadf32
+define void @loadf32() {
+ %buffer = call target("dx.CBuffer", target("dx.Layout", {float}, 4, 0))
+ @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, i1 false)
+
+ ; 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,
+ i32 0)
+ %data = extractvalue {float, float, float, float} %load, 0
+
+ ; CHECK: [[VAL:%.*]] = extractvalue %dx.types.CBufRet.f32 [[DATA]], 0
+ ; CHECK: call void @f32_user(float [[VAL]])
+ call void @f32_user(float %data)
+
+ ret void
+}
+
+; 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))
+ @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, i1 false)
+
+ ; 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,
+ i32 1)
+ %data = extractvalue {double, double} %load, 1
+
+ ; CHECK: [[VAL:%.*]] = extractvalue %dx.types.CBufRet.f64 [[DATA]], 1
+ ; CHECK: call void @f64_user(double [[VAL]])
+ call void @f64_user(double %data)
+
+ ret void
+}
+
+; CHECK-LABEL: define void @loadf16
+define void @loadf16() {
+ %buffer = call
+ target("dx.CBuffer", target("dx.Layout", {half}, 2, 0))
+ @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, i1 false)
+
+ ; 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,
+ i32 0)
+ %data = extractvalue {half, half, half, half, half, half, half, half} %load, 0
+
+ ; CHECK: [[VAL:%.*]] = extractvalue %dx.types.CBufRet.f16.8 [[DATA]], 0
+ ; CHECK: call void @f16_user(half [[VAL]])
+ call void @f16_user(half %data)
+
+ ret void
+}
diff --git a/llvm/utils/TableGen/DXILEmitter.cpp b/llvm/utils/TableGen/DXILEmitter.cpp
index 70f2aa6522640..525ad4c4c8529 100644
--- a/llvm/utils/TableGen/DXILEmitter.cpp
+++ b/llvm/utils/TableGen/DXILEmitter.cpp
@@ -228,7 +228,13 @@ static StringRef getOverloadKindStr(const Record *R) {
.Case("ResRetDoubleTy", "OverloadKind::DOUBLE")
.Case("ResRetInt16Ty", "OverloadKind::I16")
.Case("ResRetInt32Ty", "OverloadKind::I32")
- .Case("ResRetInt64Ty", "OverloadKind::I64");
+ .Case("ResRetInt64Ty", "OverloadKind::I64")
+ .Case("CBufRetHalfTy", "OverloadKind::HALF")
+ .Case("CBufRetFloatTy", "OverloadKind::FLOAT")
+ .Case("CBufRetDoubleTy", "OverloadKind::DOUBLE")
+ .Case("CBufRetInt16Ty", "OverloadKind::I16")
+ .Case("CBufRetInt32Ty", "OverloadKind::I32")
+ .Case("CBufRetInt64Ty", "OverloadKind::I64");
}
/// Return a string representation of valid overload information denoted
|
@llvm/pr-subscribers-llvm-ir Author: Justin Bogner (bogner) ChangesFixes #112992 Full diff: https://github.com/llvm/llvm-project/pull/128699.diff 9 Files Affected:
diff --git a/llvm/docs/DirectX/DXILResources.rst b/llvm/docs/DirectX/DXILResources.rst
index 80e3c2c11153d..91dcd5c8d5214 100644
--- a/llvm/docs/DirectX/DXILResources.rst
+++ b/llvm/docs/DirectX/DXILResources.rst
@@ -277,7 +277,7 @@ Examples:
Accessing Resources as Memory
-----------------------------
-*relevant types: Buffers, CBuffer, and Textures*
+*relevant types: Buffers and Textures*
Loading and storing from resources is generally represented in LLVM using
operations on memory that is only accessible via a handle object. Given a
@@ -321,12 +321,11 @@ Examples:
Loads, Samples, and Gathers
---------------------------
-*relevant types: Buffers, CBuffers, and Textures*
+*relevant types: Buffers and Textures*
-All load, sample, and gather operations in DXIL return a `ResRet`_ type, and
-CBuffer loads return a similar `CBufRet`_ type. These types are structs
-containing 4 elements of some basic type, and in the case of `ResRet` a 5th
-element that is used by the `CheckAccessFullyMapped`_ operation. Some of these
+All load, sample, and gather operations in DXIL return a `ResRet`_ type. These
+types are structs containing 4 elements of some basic type, and a 5th element
+that is used by the `CheckAccessFullyMapped`_ operation. Some of these
operations, like `RawBufferLoad`_ include a mask and/or alignment that tell us
some information about how to interpret those four values.
@@ -632,3 +631,118 @@ Examples:
target("dx.RawBuffer", i8, 1, 0, 0) %buffer,
i32 %index, i32 0, <4 x double> %data)
+Constant Buffer Loads
+---------------------
+
+*relevant types: CBuffers*
+
+The `CBufferLoadLegacy`_ operation, which despite the name is the only
+supported way to load from a cbuffer in any DXIL version, loads a single "row"
+of a cbuffer, which is exactly 16 bytes. The return value of the operation is
+represented by a `CBufRet`_ type, which has variants for 2 64-bit values, 4
+32-bit values, and 8 16-bit values.
+
+We represent these in LLVM IR with 3 separate operations, which return a
+2-element, 4-element, or 8-element struct respectively.
+
+.. _CBufferLoadLegacy: https://github.com/microsoft/DirectXShaderCompiler/blob/main/docs/DXIL.rst#cbufferLoadLegacy
+.. _CBufRet: https://github.com/microsoft/DirectXShaderCompiler/blob/main/docs/DXIL.rst#cbufferloadlegacy
+
+.. list-table:: ``@llvm.dx.resource.load.cbufferrow.4``
+ :header-rows: 1
+
+ * - Argument
+ -
+ - Type
+ - Description
+ * - Return value
+ -
+ - A struct of 4 32-bit values
+ - A single row of a cbuffer, interpreted as 4 32-bit values
+ * - ``%buffer``
+ - 0
+ - ``target(dx.CBuffer, ...)``
+ - The buffer to load from
+ * - ``%index``
+ - 1
+ - ``i32``
+ - Index into the buffer
+
+Examples:
+
+.. code-block:: llvm
+
+ %ret = call {float, float, float, float}
+ @llvm.dx.resource.load.cbufferrow.4(
+ target("dx.CBuffer", target("dx.Layout", {float}, 4, 0)) %buffer,
+ i32 %index)
+ %ret = call {i32, i32, i32, i32}
+ @llvm.dx.resource.load.cbufferrow.4(
+ target("dx.CBuffer", target("dx.Layout", {i32}, 4, 0)) %buffer,
+ i32 %index)
+
+.. list-table:: ``@llvm.dx.resource.load.cbufferrow.2``
+ :header-rows: 1
+
+ * - Argument
+ -
+ - Type
+ - Description
+ * - Return value
+ -
+ - A struct of 2 64-bit values
+ - A single row of a cbuffer, interpreted as 2 64-bit values
+ * - ``%buffer``
+ - 0
+ - ``target(dx.CBuffer, ...)``
+ - The buffer to load from
+ * - ``%index``
+ - 1
+ - ``i32``
+ - Index into the buffer
+
+Examples:
+
+.. code-block:: llvm
+
+ %ret = call {double, double}
+ @llvm.dx.resource.load.cbufferrow.2(
+ target("dx.CBuffer", target("dx.Layout", {double}, 8, 0)) %buffer,
+ i32 %index)
+ %ret = call {i64, i64}
+ @llvm.dx.resource.load.cbufferrow.2(
+ target("dx.CBuffer", target("dx.Layout", {i64}, 4, 0)) %buffer,
+ i32 %index)
+
+.. list-table:: ``@llvm.dx.resource.load.cbufferrow.8``
+ :header-rows: 1
+
+ * - Argument
+ -
+ - Type
+ - Description
+ * - Return value
+ -
+ - A struct of 8 16-bit values
+ - A single row of a cbuffer, interpreted as 8 16-bit values
+ * - ``%buffer``
+ - 0
+ - ``target(dx.CBuffer, ...)``
+ - The buffer to load from
+ * - ``%index``
+ - 1
+ - ``i32``
+ - Index into the buffer
+
+Examples:
+
+.. code-block:: llvm
+
+ %ret = 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,
+ i32 %index)
+ %ret = call {i16, i16, i16, i16, i16, i16, i16, i16}
+ @llvm.dx.resource.load.cbufferrow.8(
+ target("dx.CBuffer", target("dx.Layout", {i16}, 2, 0)) %buffer,
+ i32 %index)
diff --git a/llvm/include/llvm/IR/IntrinsicsDirectX.td b/llvm/include/llvm/IR/IntrinsicsDirectX.td
index beed84b144cec..87de68cb3ad4f 100644
--- a/llvm/include/llvm/IR/IntrinsicsDirectX.td
+++ b/llvm/include/llvm/IR/IntrinsicsDirectX.td
@@ -45,6 +45,21 @@ def int_dx_resource_store_rawbuffer
[], [llvm_any_ty, llvm_i32_ty, llvm_i32_ty, llvm_any_ty],
[IntrWriteMem]>;
+// dx.resource.load.cbufferrow encodes the number of elements returned in the
+// function name. The total size of the return should always be 128 bits.
+def int_dx_resource_load_cbufferrow_8
+ : DefaultAttrsIntrinsic<
+ [llvm_any_ty, llvm_any_ty, llvm_any_ty, llvm_any_ty,
+ llvm_any_ty, llvm_any_ty, llvm_any_ty, llvm_any_ty],
+ [llvm_any_ty, llvm_i32_ty], [IntrReadMem]>;
+def int_dx_resource_load_cbufferrow_4
+ : DefaultAttrsIntrinsic<
+ [llvm_any_ty, llvm_any_ty, llvm_any_ty, llvm_any_ty],
+ [llvm_any_ty, llvm_i32_ty], [IntrReadMem]>;
+def int_dx_resource_load_cbufferrow_2
+ : DefaultAttrsIntrinsic<[llvm_any_ty, llvm_any_ty],
+ [llvm_any_ty, llvm_i32_ty], [IntrReadMem]>;
+
def int_dx_resource_updatecounter
: DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_any_ty, llvm_i8_ty],
[IntrInaccessibleMemOrArgMemOnly]>;
diff --git a/llvm/lib/Target/DirectX/DXIL.td b/llvm/lib/Target/DirectX/DXIL.td
index d59e28c37b91d..74fd62a028b09 100644
--- a/llvm/lib/Target/DirectX/DXIL.td
+++ b/llvm/lib/Target/DirectX/DXIL.td
@@ -46,6 +46,12 @@ def ResRetDoubleTy : DXILOpParamType;
def ResRetInt16Ty : DXILOpParamType;
def ResRetInt32Ty : DXILOpParamType;
def ResRetInt64Ty : DXILOpParamType;
+def CBufRetHalfTy : DXILOpParamType;
+def CBufRetFloatTy : DXILOpParamType;
+def CBufRetDoubleTy : DXILOpParamType;
+def CBufRetInt16Ty : DXILOpParamType;
+def CBufRetInt32Ty : DXILOpParamType;
+def CBufRetInt64Ty : DXILOpParamType;
def HandleTy : DXILOpParamType;
def ResBindTy : DXILOpParamType;
def ResPropsTy : DXILOpParamType;
@@ -816,6 +822,19 @@ def CreateHandle : DXILOp<57, createHandle> {
let attributes = [Attributes<DXIL1_0, [ReadOnly]>];
}
+def CBufferLoadLegacy : DXILOp<59, cbufferLoadLegacy> {
+ let Doc = "reads from a TypedBuffer";
+ // Handle, Index
+ let arguments = [HandleTy, Int32Ty];
+ let result = OverloadTy;
+ let overloads = [Overloads<DXIL1_0, [
+ CBufRetHalfTy, CBufRetFloatTy, CBufRetDoubleTy, CBufRetInt16Ty,
+ CBufRetInt32Ty, CBufRetInt64Ty
+ ]>];
+ let stages = [Stages<DXIL1_0, [all_stages]>];
+ let attributes = [Attributes<DXIL1_0, [ReadOnly]>];
+}
+
def BufferLoad : DXILOp<68, bufferLoad> {
let Doc = "reads from a TypedBuffer";
// Handle, Coord0, Coord1
diff --git a/llvm/lib/Target/DirectX/DXILOpBuilder.cpp b/llvm/lib/Target/DirectX/DXILOpBuilder.cpp
index 6bbe8d5d12280..f45f86f60100d 100644
--- a/llvm/lib/Target/DirectX/DXILOpBuilder.cpp
+++ b/llvm/lib/Target/DirectX/DXILOpBuilder.cpp
@@ -201,6 +201,30 @@ static StructType *getResRetType(Type *ElementTy) {
return getOrCreateStructType(TypeName, FieldTypes, Ctx);
}
+static StructType *getCBufRetType(Type *ElementTy) {
+ LLVMContext &Ctx = ElementTy->getContext();
+ OverloadKind Kind = getOverloadKind(ElementTy);
+ std::string TypeName = constructOverloadTypeName(Kind, "dx.types.CBufRet.");
+
+ // 64-bit types only have two elements
+ if (ElementTy->isDoubleTy() || ElementTy->isIntegerTy(64))
+ return getOrCreateStructType(
+ TypeName, {ElementTy, ElementTy}, Ctx);
+
+ // 16-bit types pack 8 elements and have .8 in their name to differentiate
+ // from min-precision types.
+ if (ElementTy->isHalfTy() || ElementTy->isIntegerTy(16)) {
+ TypeName += ".8";
+ return getOrCreateStructType(TypeName,
+ {ElementTy, ElementTy, ElementTy, ElementTy,
+ ElementTy, ElementTy, ElementTy, ElementTy},
+ Ctx);
+ }
+
+ return getOrCreateStructType(
+ TypeName, {ElementTy, ElementTy, ElementTy, ElementTy}, Ctx);
+}
+
static StructType *getHandleType(LLVMContext &Ctx) {
return getOrCreateStructType("dx.types.Handle", PointerType::getUnqual(Ctx),
Ctx);
@@ -265,6 +289,18 @@ static Type *getTypeFromOpParamType(OpParamType Kind, LLVMContext &Ctx,
return getResRetType(Type::getInt32Ty(Ctx));
case OpParamType::ResRetInt64Ty:
return getResRetType(Type::getInt64Ty(Ctx));
+ case OpParamType::CBufRetHalfTy:
+ return getCBufRetType(Type::getHalfTy(Ctx));
+ case OpParamType::CBufRetFloatTy:
+ return getCBufRetType(Type::getFloatTy(Ctx));
+ case OpParamType::CBufRetDoubleTy:
+ return getCBufRetType(Type::getDoubleTy(Ctx));
+ case OpParamType::CBufRetInt16Ty:
+ return getCBufRetType(Type::getInt16Ty(Ctx));
+ case OpParamType::CBufRetInt32Ty:
+ return getCBufRetType(Type::getInt32Ty(Ctx));
+ case OpParamType::CBufRetInt64Ty:
+ return getCBufRetType(Type::getInt64Ty(Ctx));
case OpParamType::HandleTy:
return getHandleType(Ctx);
case OpParamType::ResBindTy:
@@ -535,6 +571,10 @@ StructType *DXILOpBuilder::getResRetType(Type *ElementTy) {
return ::getResRetType(ElementTy);
}
+StructType *DXILOpBuilder::getCBufRetType(Type *ElementTy) {
+ return ::getCBufRetType(ElementTy);
+}
+
StructType *DXILOpBuilder::getHandleType() {
return ::getHandleType(IRB.getContext());
}
diff --git a/llvm/lib/Target/DirectX/DXILOpBuilder.h b/llvm/lib/Target/DirectX/DXILOpBuilder.h
index 5fe9f4429a494..0985f2ee7cf1f 100644
--- a/llvm/lib/Target/DirectX/DXILOpBuilder.h
+++ b/llvm/lib/Target/DirectX/DXILOpBuilder.h
@@ -50,6 +50,9 @@ class DXILOpBuilder {
/// Get a `%dx.types.ResRet` type with the given element type.
StructType *getResRetType(Type *ElementTy);
+ /// Get a `%dx.types.CBufRet` type with the given element type.
+ StructType *getCBufRetType(Type *ElementTy);
+
/// Get the `%dx.types.Handle` type.
StructType *getHandleType();
diff --git a/llvm/lib/Target/DirectX/DXILOpLowering.cpp b/llvm/lib/Target/DirectX/DXILOpLowering.cpp
index 83cc4b18824c7..e4239b2bc6628 100644
--- a/llvm/lib/Target/DirectX/DXILOpLowering.cpp
+++ b/llvm/lib/Target/DirectX/DXILOpLowering.cpp
@@ -569,6 +569,32 @@ class OpLowerer {
});
}
+ [[nodiscard]] bool lowerCBufferLoad(Function &F) {
+ IRBuilder<> &IRB = OpBuilder.getIRB();
+
+ return replaceFunction(F, [&](CallInst *CI) -> Error {
+ IRB.SetInsertPoint(CI);
+
+ Type *OldTy = cast<StructType>(CI->getType())->getElementType(0);
+ Type *ScalarTy = OldTy->getScalarType();
+ Type *NewRetTy = OpBuilder.getCBufRetType(ScalarTy);
+
+ Value *Handle =
+ createTmpHandleCast(CI->getArgOperand(0), OpBuilder.getHandleType());
+ Value *Index = CI->getArgOperand(1);
+
+ Expected<CallInst *> OpCall = OpBuilder.tryCreateOp(
+ OpCode::CBufferLoadLegacy, {Handle, Index}, CI->getName(), NewRetTy);
+ if (Error E = OpCall.takeError())
+ return E;
+ if (Error E = replaceNamedStructUses(CI, *OpCall))
+ return E;
+
+ CI->eraseFromParent();
+ return Error::success();
+ });
+ }
+
[[nodiscard]] bool lowerUpdateCounter(Function &F) {
IRBuilder<> &IRB = OpBuilder.getIRB();
Type *Int32Ty = IRB.getInt32Ty();
@@ -796,6 +822,11 @@ class OpLowerer {
case Intrinsic::dx_resource_store_rawbuffer:
HasErrors |= lowerBufferStore(F, /*IsRaw=*/true);
break;
+ case Intrinsic::dx_resource_load_cbufferrow_2:
+ case Intrinsic::dx_resource_load_cbufferrow_4:
+ case Intrinsic::dx_resource_load_cbufferrow_8:
+ HasErrors |= lowerCBufferLoad(F);
+ break;
case Intrinsic::dx_resource_updatecounter:
HasErrors |= lowerUpdateCounter(F);
break;
diff --git a/llvm/test/CodeGen/DirectX/CBufferLoadLegacy-errors.ll b/llvm/test/CodeGen/DirectX/CBufferLoadLegacy-errors.ll
new file mode 100644
index 0000000000000..66dc1d2f36636
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/CBufferLoadLegacy-errors.ll
@@ -0,0 +1,45 @@
+; We use llc for this test so that we don't abort after the first error.
+; RUN: not llc %s -o /dev/null 2>&1 | FileCheck %s
+
+target triple = "dxil-pc-shadermodel6.6-compute"
+
+declare void @f32_user(float)
+declare void @f64_user(double)
+declare void @f16_user(half)
+
+; CHECK: error:
+; 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))
+ @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, i1 false)
+
+ %load = call {double, double, double, double} @llvm.dx.resource.load.cbufferrow.4(
+ target("dx.CBuffer", target("dx.Layout", {double}, 8, 0)) %buffer,
+ i32 0)
+ %data = extractvalue {double, double, double, double} %load, 0
+
+ call void @f64_user(double %data)
+
+ ret void
+}
+
+; CHECK: error:
+; 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))
+ @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, i1 false)
+
+ %load = call {float, float} @llvm.dx.resource.load.cbufferrow.2(
+ target("dx.CBuffer", target("dx.Layout", {float}, 4, 0)) %buffer,
+ i32 0)
+ %data = extractvalue {float, float} %load, 0
+
+ call void @f32_user(float %data)
+
+ 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)
diff --git a/llvm/test/CodeGen/DirectX/CBufferLoadLegacy.ll b/llvm/test/CodeGen/DirectX/CBufferLoadLegacy.ll
new file mode 100644
index 0000000000000..12b02cfd27823
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/CBufferLoadLegacy.ll
@@ -0,0 +1,63 @@
+; RUN: opt -S -dxil-op-lower %s | FileCheck %s
+
+target triple = "dxil-pc-shadermodel6.6-compute"
+
+declare void @f32_user(float)
+declare void @f64_user(double)
+declare void @f16_user(half)
+
+; CHECK-LABEL: define void @loadf32
+define void @loadf32() {
+ %buffer = call target("dx.CBuffer", target("dx.Layout", {float}, 4, 0))
+ @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, i1 false)
+
+ ; 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,
+ i32 0)
+ %data = extractvalue {float, float, float, float} %load, 0
+
+ ; CHECK: [[VAL:%.*]] = extractvalue %dx.types.CBufRet.f32 [[DATA]], 0
+ ; CHECK: call void @f32_user(float [[VAL]])
+ call void @f32_user(float %data)
+
+ ret void
+}
+
+; 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))
+ @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, i1 false)
+
+ ; 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,
+ i32 1)
+ %data = extractvalue {double, double} %load, 1
+
+ ; CHECK: [[VAL:%.*]] = extractvalue %dx.types.CBufRet.f64 [[DATA]], 1
+ ; CHECK: call void @f64_user(double [[VAL]])
+ call void @f64_user(double %data)
+
+ ret void
+}
+
+; CHECK-LABEL: define void @loadf16
+define void @loadf16() {
+ %buffer = call
+ target("dx.CBuffer", target("dx.Layout", {half}, 2, 0))
+ @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, i1 false)
+
+ ; 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,
+ i32 0)
+ %data = extractvalue {half, half, half, half, half, half, half, half} %load, 0
+
+ ; CHECK: [[VAL:%.*]] = extractvalue %dx.types.CBufRet.f16.8 [[DATA]], 0
+ ; CHECK: call void @f16_user(half [[VAL]])
+ call void @f16_user(half %data)
+
+ ret void
+}
diff --git a/llvm/utils/TableGen/DXILEmitter.cpp b/llvm/utils/TableGen/DXILEmitter.cpp
index 70f2aa6522640..525ad4c4c8529 100644
--- a/llvm/utils/TableGen/DXILEmitter.cpp
+++ b/llvm/utils/TableGen/DXILEmitter.cpp
@@ -228,7 +228,13 @@ static StringRef getOverloadKindStr(const Record *R) {
.Case("ResRetDoubleTy", "OverloadKind::DOUBLE")
.Case("ResRetInt16Ty", "OverloadKind::I16")
.Case("ResRetInt32Ty", "OverloadKind::I32")
- .Case("ResRetInt64Ty", "OverloadKind::I64");
+ .Case("ResRetInt64Ty", "OverloadKind::I64")
+ .Case("CBufRetHalfTy", "OverloadKind::HALF")
+ .Case("CBufRetFloatTy", "OverloadKind::FLOAT")
+ .Case("CBufRetDoubleTy", "OverloadKind::DOUBLE")
+ .Case("CBufRetInt16Ty", "OverloadKind::I16")
+ .Case("CBufRetInt32Ty", "OverloadKind::I32")
+ .Case("CBufRetInt64Ty", "OverloadKind::I64");
}
/// Return a string representation of valid overload information denoted
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
@@ -46,6 +46,12 @@ def ResRetDoubleTy : DXILOpParamType; | |||
def ResRetInt16Ty : DXILOpParamType; | |||
def ResRetInt32Ty : DXILOpParamType; | |||
def ResRetInt64Ty : DXILOpParamType; | |||
def CBufRetHalfTy : DXILOpParamType; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why def CBufRetHalfTy : DXILOpParamType;
and not def CBufRetHalfTy : HalfTy;
?
To phrase another way it looks like you have to do these reassociations later in DXILEmitter via .Case("CBufRetHalfTy", "OverloadKind::HALF")
because CBufRetHalfTy is a special type.
Why do the overloads have to be cbuffer types like below?
let overloads = [Overloads<DXIL1_0, [
CBufRetHalfTy, CBufRetFloatTy, CBufRetDoubleTy, CBufRetInt16Ty,
CBufRetInt32Ty, CBufRetInt64Ty
]>];
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
dx.op.cbufferLoadLegacy
returns a named structure containing elements that are half, float, double, int16, int32, or int64, but it names its overload based on the element type. So we have these types:
; 4 32-bit types
%dx.types.CBufRet.f32 = type { float, float, float, float }
%dx.types.CBufRet.i32 = type { i32, i32, i32, i32 }
; 2 64-bit types
%dx.types.CBufRet.f64 = type { double, double }
%dx.types.CBufRet.i64 = type { i64, i64 }
; 8 16-bit types (If -enable-16bit-types is present)
%dx.types.CBufRet.f16.8 = type { half, half, half, half, half, half, half, half }
%dx.types.CBufRet.i16.8 = type { i16, i16, i16, i16, i16, i16, i16, i16 }
and we have these overloads:
declare %dx.types.CBufRet.f32 @dx.op.cbufferLoadLegacy.f32(...)
declare %dx.types.CBufRet.i32 @dx.op.cbufferLoadLegacy.i32(...)
declare %dx.types.CBufRet.f64 @dx.op.cbufferLoadLegacy.f64(...)
declare %dx.types.CBufRet.i64 @dx.op.cbufferLoadLegacy.i64(...)
declare %dx.types.CBufRet.f16 @dx.op.cbufferLoadLegacy.f16(...)
declare %dx.types.CBufRet.i16 @dx.op.cbufferLoadLegacy.i16(...)
The DXILEmitter association is telling us what to name the overloads, and the overloads are cbuffer types in DXIL.td so that we return these structs and not, say, a single half
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. comments are questions only. No changes needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM! Just one copy-paste nit.
llvm/lib/Target/DirectX/DXIL.td
Outdated
@@ -816,6 +822,19 @@ def CreateHandle : DXILOp<57, createHandle> { | |||
let attributes = [Attributes<DXIL1_0, [ReadOnly]>]; | |||
} | |||
|
|||
def CBufferLoadLegacy : DXILOp<59, cbufferLoadLegacy> { | |||
let Doc = "reads from a TypedBuffer"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let Doc = "reads from a TypedBuffer"; | |
let Doc = "reads from a constant buffer"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice catch. I updated this to use the doc wording from DXIL.rst
657eb14
to
fdedca0
Compare
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/198/builds/2343 Here is the relevant piece of the build log for the reference
|
Fixes #112992