Skip to content

Commit cdfd884

Browse files
authored
[DXIL] Add DXIL version-specific TableGen specification and implementation of DXIL Ops (llvm#97593)
Update TableGen specification of DXIL Op records in DXIL.td per the current design document. - Facilitate specification of overloads, shader stage and attributes predicated on DXIL Ops predicated DXIL version. Implement functionality to consume in TableGen backend, DXILEmitter, the above specification enhancements, and generate C++ code (in (DXILOperations.inc) that represents properties of DXIL Ops, associated type declarations and corresponding accessor functions. Changes to DXIL Op Lowering pass to consume the DXIL Op representation generated by the TableGen back end. Add mtriple with the required shader model version to commandline of tests.
1 parent 9808f48 commit cdfd884

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

65 files changed

+1086
-381
lines changed

llvm/lib/Target/DirectX/DXIL.td

Lines changed: 501 additions & 161 deletions
Large diffs are not rendered by default.

llvm/lib/Target/DirectX/DXILOpBuilder.cpp

Lines changed: 157 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,16 @@
1515
#include "llvm/IR/Module.h"
1616
#include "llvm/Support/DXILABI.h"
1717
#include "llvm/Support/ErrorHandling.h"
18+
#include <optional>
1819

1920
using namespace llvm;
2021
using namespace llvm::dxil;
2122

2223
constexpr StringLiteral DXILOpNamePrefix = "dx.op.";
2324

2425
namespace {
25-
2626
enum OverloadKind : uint16_t {
27+
UNDEFINED = 0,
2728
VOID = 1,
2829
HALF = 1 << 1,
2930
FLOAT = 1 << 2,
@@ -36,9 +37,27 @@ enum OverloadKind : uint16_t {
3637
UserDefineType = 1 << 9,
3738
ObjectType = 1 << 10,
3839
};
40+
struct Version {
41+
unsigned Major = 0;
42+
unsigned Minor = 0;
43+
};
3944

45+
struct OpOverload {
46+
Version DXILVersion;
47+
uint16_t ValidTys;
48+
};
4049
} // namespace
4150

51+
struct OpStage {
52+
Version DXILVersion;
53+
uint32_t ValidStages;
54+
};
55+
56+
struct OpAttribute {
57+
Version DXILVersion;
58+
uint32_t ValidAttrs;
59+
};
60+
4261
static const char *getOverloadTypeName(OverloadKind Kind) {
4362
switch (Kind) {
4463
case OverloadKind::HALF:
@@ -58,12 +77,13 @@ static const char *getOverloadTypeName(OverloadKind Kind) {
5877
case OverloadKind::I64:
5978
return "i64";
6079
case OverloadKind::VOID:
80+
case OverloadKind::UNDEFINED:
81+
return "void";
6182
case OverloadKind::ObjectType:
6283
case OverloadKind::UserDefineType:
6384
break;
6485
}
6586
llvm_unreachable("invalid overload type for name");
66-
return "void";
6787
}
6888

6989
static OverloadKind getOverloadKind(Type *Ty) {
@@ -131,8 +151,9 @@ struct OpCodeProperty {
131151
dxil::OpCodeClass OpCodeClass;
132152
// Offset in DXILOpCodeClassNameTable.
133153
unsigned OpCodeClassNameOffset;
134-
uint16_t OverloadTys;
135-
llvm::Attribute::AttrKind FuncAttr;
154+
llvm::SmallVector<OpOverload> Overloads;
155+
llvm::SmallVector<OpStage> Stages;
156+
llvm::SmallVector<OpAttribute> Attributes;
136157
int OverloadParamIndex; // parameter index which control the overload.
137158
// When < 0, should be only 1 overload type.
138159
unsigned NumOfParameters; // Number of parameters include return value.
@@ -221,6 +242,45 @@ static Type *getTypeFromParameterKind(ParameterKind Kind, Type *OverloadTy) {
221242
return nullptr;
222243
}
223244

245+
static ShaderKind getShaderKindEnum(Triple::EnvironmentType EnvType) {
246+
switch (EnvType) {
247+
case Triple::Pixel:
248+
return ShaderKind::pixel;
249+
case Triple::Vertex:
250+
return ShaderKind::vertex;
251+
case Triple::Geometry:
252+
return ShaderKind::geometry;
253+
case Triple::Hull:
254+
return ShaderKind::hull;
255+
case Triple::Domain:
256+
return ShaderKind::domain;
257+
case Triple::Compute:
258+
return ShaderKind::compute;
259+
case Triple::Library:
260+
return ShaderKind::library;
261+
case Triple::RayGeneration:
262+
return ShaderKind::raygeneration;
263+
case Triple::Intersection:
264+
return ShaderKind::intersection;
265+
case Triple::AnyHit:
266+
return ShaderKind::anyhit;
267+
case Triple::ClosestHit:
268+
return ShaderKind::closesthit;
269+
case Triple::Miss:
270+
return ShaderKind::miss;
271+
case Triple::Callable:
272+
return ShaderKind::callable;
273+
case Triple::Mesh:
274+
return ShaderKind::mesh;
275+
case Triple::Amplification:
276+
return ShaderKind::amplification;
277+
default:
278+
break;
279+
}
280+
llvm_unreachable(
281+
"Shader Kind Not Found - Invalid DXIL Environment Specified");
282+
}
283+
224284
/// Construct DXIL function type. This is the type of a function with
225285
/// the following prototype
226286
/// OverloadType dx.op.<opclass>.<return-type>(int opcode, <param types>)
@@ -232,7 +292,7 @@ static FunctionType *getDXILOpFunctionType(const OpCodeProperty *Prop,
232292
Type *ReturnTy, Type *OverloadTy) {
233293
SmallVector<Type *> ArgTys;
234294

235-
auto ParamKinds = getOpCodeParameterKind(*Prop);
295+
const ParameterKind *ParamKinds = getOpCodeParameterKind(*Prop);
236296

237297
// Add ReturnTy as return type of the function
238298
ArgTys.emplace_back(ReturnTy);
@@ -249,17 +309,103 @@ static FunctionType *getDXILOpFunctionType(const OpCodeProperty *Prop,
249309
ArgTys[0], ArrayRef<Type *>(&ArgTys[1], ArgTys.size() - 1), false);
250310
}
251311

312+
/// Get index of the property from PropList valid for the most recent
313+
/// DXIL version not greater than DXILVer.
314+
/// PropList is expected to be sorted in ascending order of DXIL version.
315+
template <typename T>
316+
static std::optional<size_t> getPropIndex(ArrayRef<T> PropList,
317+
const VersionTuple DXILVer) {
318+
size_t Index = PropList.size() - 1;
319+
for (auto Iter = PropList.rbegin(); Iter != PropList.rend();
320+
Iter++, Index--) {
321+
const T &Prop = *Iter;
322+
if (VersionTuple(Prop.DXILVersion.Major, Prop.DXILVersion.Minor) <=
323+
DXILVer) {
324+
return Index;
325+
}
326+
}
327+
return std::nullopt;
328+
}
329+
252330
namespace llvm {
253331
namespace dxil {
254332

333+
// No extra checks on TargetTriple need be performed to verify that the
334+
// Triple is well-formed or that the target is supported since these checks
335+
// would have been done at the time the module M is constructed in the earlier
336+
// stages of compilation.
337+
DXILOpBuilder::DXILOpBuilder(Module &M, IRBuilderBase &B) : M(M), B(B) {
338+
Triple TT(Triple(M.getTargetTriple()));
339+
DXILVersion = TT.getDXILVersion();
340+
ShaderStage = TT.getEnvironment();
341+
// Ensure Environment type is known
342+
if (ShaderStage == Triple::UnknownEnvironment) {
343+
report_fatal_error(
344+
Twine(DXILVersion.getAsString()) +
345+
": Unknown Compilation Target Shader Stage specified ",
346+
/*gen_crash_diag*/ false);
347+
}
348+
}
349+
255350
CallInst *DXILOpBuilder::createDXILOpCall(dxil::OpCode OpCode, Type *ReturnTy,
256351
Type *OverloadTy,
257352
SmallVector<Value *> Args) {
353+
258354
const OpCodeProperty *Prop = getOpCodeProperty(OpCode);
355+
std::optional<size_t> OlIndexOrErr =
356+
getPropIndex(ArrayRef(Prop->Overloads), DXILVersion);
357+
if (!OlIndexOrErr.has_value()) {
358+
report_fatal_error(Twine(getOpCodeName(OpCode)) +
359+
": No valid overloads found for DXIL Version - " +
360+
DXILVersion.getAsString(),
361+
/*gen_crash_diag*/ false);
362+
}
363+
uint16_t ValidTyMask = Prop->Overloads[*OlIndexOrErr].ValidTys;
259364

260365
OverloadKind Kind = getOverloadKind(OverloadTy);
261-
if ((Prop->OverloadTys & (uint16_t)Kind) == 0) {
262-
report_fatal_error("Invalid Overload Type", /* gen_crash_diag=*/false);
366+
367+
// Check if the operation supports overload types and OverloadTy is valid
368+
// per the specified types for the operation
369+
if ((ValidTyMask != OverloadKind::UNDEFINED) &&
370+
(ValidTyMask & (uint16_t)Kind) == 0) {
371+
report_fatal_error(Twine("Invalid Overload Type for DXIL operation - ") +
372+
getOpCodeName(OpCode),
373+
/* gen_crash_diag=*/false);
374+
}
375+
376+
// Perform necessary checks to ensure Opcode is valid in the targeted shader
377+
// kind
378+
std::optional<size_t> StIndexOrErr =
379+
getPropIndex(ArrayRef(Prop->Stages), DXILVersion);
380+
if (!StIndexOrErr.has_value()) {
381+
report_fatal_error(Twine(getOpCodeName(OpCode)) +
382+
": No valid stages found for DXIL Version - " +
383+
DXILVersion.getAsString(),
384+
/*gen_crash_diag*/ false);
385+
}
386+
uint16_t ValidShaderKindMask = Prop->Stages[*StIndexOrErr].ValidStages;
387+
388+
// Ensure valid shader stage properties are specified
389+
if (ValidShaderKindMask == ShaderKind::removed) {
390+
report_fatal_error(
391+
Twine(DXILVersion.getAsString()) +
392+
": Unsupported Target Shader Stage for DXIL operation - " +
393+
getOpCodeName(OpCode),
394+
/*gen_crash_diag*/ false);
395+
}
396+
397+
// Shader stage need not be validated since getShaderKindEnum() fails
398+
// for unknown shader stage.
399+
400+
// Verify the target shader stage is valid for the DXIL operation
401+
ShaderKind ModuleStagekind = getShaderKindEnum(ShaderStage);
402+
if (!(ValidShaderKindMask & ModuleStagekind)) {
403+
auto ShaderEnvStr = Triple::getEnvironmentTypeName(ShaderStage);
404+
report_fatal_error(Twine(ShaderEnvStr) +
405+
" : Invalid Shader Stage for DXIL operation - " +
406+
getOpCodeName(OpCode) + " for DXIL Version " +
407+
DXILVersion.getAsString(),
408+
/*gen_crash_diag*/ false);
263409
}
264410

265411
std::string DXILFnName = constructOverloadName(Kind, OverloadTy, *Prop);
@@ -282,40 +428,18 @@ Type *DXILOpBuilder::getOverloadTy(dxil::OpCode OpCode, FunctionType *FT) {
282428
// If DXIL Op has no overload parameter, just return the
283429
// precise return type specified.
284430
if (Prop->OverloadParamIndex < 0) {
285-
auto &Ctx = FT->getContext();
286-
switch (Prop->OverloadTys) {
287-
case OverloadKind::VOID:
288-
return Type::getVoidTy(Ctx);
289-
case OverloadKind::HALF:
290-
return Type::getHalfTy(Ctx);
291-
case OverloadKind::FLOAT:
292-
return Type::getFloatTy(Ctx);
293-
case OverloadKind::DOUBLE:
294-
return Type::getDoubleTy(Ctx);
295-
case OverloadKind::I1:
296-
return Type::getInt1Ty(Ctx);
297-
case OverloadKind::I8:
298-
return Type::getInt8Ty(Ctx);
299-
case OverloadKind::I16:
300-
return Type::getInt16Ty(Ctx);
301-
case OverloadKind::I32:
302-
return Type::getInt32Ty(Ctx);
303-
case OverloadKind::I64:
304-
return Type::getInt64Ty(Ctx);
305-
default:
306-
llvm_unreachable("invalid overload type");
307-
return nullptr;
308-
}
431+
return FT->getReturnType();
309432
}
310433

311-
// Prop->OverloadParamIndex is 0, overload type is FT->getReturnType().
434+
// Consider FT->getReturnType() as default overload type, unless
435+
// Prop->OverloadParamIndex != 0.
312436
Type *OverloadType = FT->getReturnType();
313437
if (Prop->OverloadParamIndex != 0) {
314438
// Skip Return Type.
315439
OverloadType = FT->getParamType(Prop->OverloadParamIndex - 1);
316440
}
317441

318-
auto ParamKinds = getOpCodeParameterKind(*Prop);
442+
const ParameterKind *ParamKinds = getOpCodeParameterKind(*Prop);
319443
auto Kind = ParamKinds[Prop->OverloadParamIndex];
320444
// For ResRet and CBufferRet, OverloadTy is in field of StructType.
321445
if (Kind == ParameterKind::CBufferRet ||

llvm/lib/Target/DirectX/DXILOpBuilder.h

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
#include "DXILConstants.h"
1616
#include "llvm/ADT/SmallVector.h"
17+
#include "llvm/TargetParser/Triple.h"
1718

1819
namespace llvm {
1920
class Module;
@@ -28,11 +29,16 @@ namespace dxil {
2829

2930
class DXILOpBuilder {
3031
public:
31-
DXILOpBuilder(Module &M, IRBuilderBase &B) : M(M), B(B) {}
32+
DXILOpBuilder(Module &M, IRBuilderBase &B);
3233
/// Create an instruction that calls DXIL Op with return type, specified
33-
/// opcode, and call arguments. \param OpCode Opcode of the DXIL Op call
34-
/// constructed \param ReturnTy Return type of the DXIL Op call constructed
34+
/// opcode, and call arguments.
35+
///
36+
/// \param OpCode Opcode of the DXIL Op call constructed
37+
/// \param SMVer Shader Model Version of DXIL Module being constructed.
38+
/// \param StageKind Shader Stage for DXIL Module being constructed.
39+
/// \param ReturnTy Return type of the DXIL Op call constructed
3540
/// \param OverloadTy Overload type of the DXIL Op call constructed
41+
/// \param Args Arguments for the DXIL Op call constructed
3642
/// \return DXIL Op call constructed
3743
CallInst *createDXILOpCall(dxil::OpCode OpCode, Type *ReturnTy,
3844
Type *OverloadTy, SmallVector<Value *> Args);
@@ -42,6 +48,8 @@ class DXILOpBuilder {
4248
private:
4349
Module &M;
4450
IRBuilderBase &B;
51+
VersionTuple DXILVersion;
52+
Triple::EnvironmentType ShaderStage;
4553
};
4654

4755
} // namespace dxil

llvm/test/CodeGen/DirectX/abs.ll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
; RUN: opt -S -dxil-intrinsic-expansion < %s | FileCheck %s --check-prefixes=CHECK,EXPCHECK
2-
; RUN: opt -S -dxil-op-lower < %s | FileCheck %s --check-prefixes=CHECK,DOPCHECK
1+
; RUN: opt -S -dxil-intrinsic-expansion -mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s --check-prefixes=CHECK,EXPCHECK
2+
; RUN: opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s --check-prefixes=CHECK,DOPCHECK
33

44
; Make sure dxil operation function calls for abs are generated for int16_t/int/int64_t.
55

llvm/test/CodeGen/DirectX/acos.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
; RUN: opt -S -dxil-op-lower < %s | FileCheck %s
1+
; RUN: opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s
22

33
; Make sure dxil operation function calls for acos are generated for float and half.
44

llvm/test/CodeGen/DirectX/acos_error.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
; RUN: not opt -S -dxil-op-lower %s 2>&1 | FileCheck %s
1+
; RUN: not opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s 2>&1 | FileCheck %s
22

33
; DXIL operation acos does not support double overload type
44
; CHECK: LLVM ERROR: Invalid Overload

llvm/test/CodeGen/DirectX/asin.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
; RUN: opt -S -dxil-op-lower < %s | FileCheck %s
1+
; RUN: opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s
22

33
; Make sure dxil operation function calls for asin are generated for float and half.
44

llvm/test/CodeGen/DirectX/asin_error.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
; RUN: not opt -S -dxil-op-lower %s 2>&1 | FileCheck %s
1+
; RUN: not opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s 2>&1 | FileCheck %s
22

33
; DXIL operation asin does not support double overload type
44
; CHECK: LLVM ERROR: Invalid Overload

llvm/test/CodeGen/DirectX/atan.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
; RUN: opt -S -dxil-op-lower < %s | FileCheck %s
1+
; RUN: opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s
22

33
; Make sure dxil operation function calls for atan are generated for float and half.
44

llvm/test/CodeGen/DirectX/atan_error.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
; RUN: not opt -S -dxil-op-lower %s 2>&1 | FileCheck %s
1+
; RUN: not opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s 2>&1 | FileCheck %s
22

33
; DXIL operation atan does not support double overload type
44
; CHECK: LLVM ERROR: Invalid Overload

llvm/test/CodeGen/DirectX/ceil.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
; RUN: opt -S -dxil-op-lower < %s | FileCheck %s
1+
; RUN: opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s
22

33
; Make sure dxil operation function calls for ceil are generated for float and half.
44

llvm/test/CodeGen/DirectX/ceil_error.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
; RUN: not opt -S -dxil-op-lower %s 2>&1 | FileCheck %s
1+
; RUN: not opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s 2>&1 | FileCheck %s
22

33
; DXIL operation ceil does not support double overload type
44
; CHECK: LLVM ERROR: Invalid Overload Type

llvm/test/CodeGen/DirectX/clamp.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
; RUN: opt -S -dxil-op-lower < %s | FileCheck %s
1+
; RUN: opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s
22

33
; Make sure dxil operation function calls for clamp/uclamp are generated for half/float/double/i16/i32/i64.
44

llvm/test/CodeGen/DirectX/comput_ids.ll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
; RUN: opt -S -dxil-op-lower < %s | FileCheck %s
1+
; RUN: opt -S -dxil-op-lower %s | FileCheck %s
22

33
; Make sure dxil operation function calls for all ComputeID dxil operations are generated.
44

55
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"
6-
target triple = "dxil-pc-shadermodel6.7-library"
6+
target triple = "dxil-pc-shadermodel6.7-compute"
77

88
; CHECK-LABEL: @test_thread_id(
99
; Function Attrs: noinline nounwind optnone

llvm/test/CodeGen/DirectX/cos.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
; RUN: opt -S -dxil-op-lower < %s | FileCheck %s
1+
; RUN: opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s
22

33
; Make sure dxil operation function calls for cos are generated for float and half.
44

0 commit comments

Comments
 (0)