Skip to content

Commit

Permalink
[DxilOp] Allow generation of illegal DXIL operations. (microsoft#6543)
Browse files Browse the repository at this point in the history
This change removes the IsOverloadLegal check in OP::GetOpFunc.

It will permit the generation of illegal DXIL operations. Subsequently,
the validation should catch these illegal DXIL operations if they are
not optimized later in SimplifyDxilCall.


Fixes microsoft#6410
  • Loading branch information
python3kgae authored Apr 26, 2024
1 parent 643523a commit 00cd823
Show file tree
Hide file tree
Showing 4 changed files with 149 additions and 1 deletion.
8 changes: 7 additions & 1 deletion lib/DXIL/DxilOperations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3564,8 +3564,14 @@ void OP::UpdateCache(OpCodeClass opClass, Type *Ty, llvm::Function *F) {
Function *OP::GetOpFunc(OpCode opCode, Type *pOverloadType) {
if (opCode == OpCode::NumOpCodes)
return nullptr;
if (!IsOverloadLegal(opCode, pOverloadType))
if (!pOverloadType)
return nullptr;
// Illegal overloads are generated and eliminated by DXIL op constant
// evaluation for a number of cases where a double overload of an HL intrinsic
// that otherwise does not support double is used for literal values, when
// there is no constant evaluation for the intrinsic in CodeGen.
// Illegal overloads of DXIL intrinsics may survive through to final DXIL,
// but these will be caught by the validator, and this is not a regression.

OpCodeClass opClass = m_OpCodeProps[(unsigned)opCode].opCodeClass;
Function *&F =
Expand Down
62 changes: 62 additions & 0 deletions tools/clang/test/CodeGenDXIL/literal/fmod_const_eval.hlsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// RUN: %dxc -T vs_6_0 %s -E main | FileCheck %s
// RUN: not %dxc -T vs_6_0 %s -E main -DNO_FOLD 2>&1 | FileCheck %s --check-prefixes=NO_FOLD

// The code path generates invalid overload. The invalid overload will either be
// constant folded away, or caught by the validator.

// Ensure fmod is constant evaluated during codegen, or dxil const eval
// TODO: handle fp specials properly, tracked with https://github.com/microsoft/DirectXShaderCompiler/issues/6567


RWBuffer<float4> results : register(u0);

[shader("vertex")]
void main(bool b : B) {
uint i = 0;

// Literal float
// 2.5, -2.5, 2.5, -2.5
// CHECK: call void @dx.op.bufferStore.f32(i32 69, %dx.types.Handle %{{.+}}, i32 0, i32 undef, float 2.500000e+00, float -2.500000e+00, float 2.500000e+00, float -2.500000e+00, i8 15)
results[i++] = float4(fmod(5.5, 3.0),
fmod(-5.5, 3.0),
fmod(5.5, -3.0),
fmod(-5.5, -3.0));

// Explicit float
// 2.5, -2.5, 2.5, -2.5
// CHECK: call void @dx.op.bufferStore.f32(i32 69, %dx.types.Handle %{{.+}}, i32 1, i32 undef, float 2.500000e+00, float -2.500000e+00, float 2.500000e+00, float -2.500000e+00, i8 15)
results[i++] = float4(fmod(5.5f, 3.0f),
fmod(-5.5f, 3.0f),
fmod(5.5f, -3.0f),
fmod(-5.5f, -3.0f));

#ifdef SPECIALS
// Literal float
// 0.0, -0.0, NaN, -NaN
// SPECIALS: call void @dx.op.bufferStore.f32(i32 69, %dx.types.Handle %{{.+}}, i32 2, i32 undef, float 0.000000e+00, -0.000000e+00, float 0x7FF8000000000000, float 0x7FF8000000000000, i8 15)
results[i++] = float4(fmod(0.0, 1.0),
fmod(-0.0, 1.0),
fmod(5.5, 0.0),
fmod(-5.5, 0.0));

// Explicit float
// 0.0, -0.0, NaN, -NaN
// SPECIALS: call void @dx.op.bufferStore.f32(i32 69, %dx.types.Handle %{{.+}}, i32 3, i32 undef, float 0.000000e+00, -0.000000e+00, float 0x7FF8000000000000, float 0x7FF8000000000000, i8 15)
results[i++] = float4(fmod(0.0f, 1.0f),
fmod(-0.0f, 1.0f),
fmod(5.5f, 0.0f),
fmod(-5.5f, 0.0f));

#endif // SPECIALS

#ifdef NO_FOLD
// Currently, we rely on constant folding of DXIL ops to get rid of illegal
// double overloads. If this doesn't happen, we expect a validation error.
// Ternary operator can return literal type, while not being foldable due
// non-constant condition.
// NO_FOLD: error: validation errors
// NO_FOLD: error: DXIL intrinsic overload must be valid.
float result = fmod(-5.5, b ? 1.5 : 0.5);
results[i++] = float4(result, 0, 0, 0);
#endif // NO_FOLD
}
40 changes: 40 additions & 0 deletions tools/clang/test/CodeGenDXIL/literal/length_const_eval.hlsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// RUN: %dxc -T vs_6_0 %s -E main | FileCheck %s
// RUN: not %dxc -T vs_6_0 %s -E main -DNO_FOLD 2>&1 | FileCheck %s --check-prefixes=NO_FOLD

// The code path generates invalid overload. The invalid overload will either be
// constant folded away, or caught by the validator.

// Ensure length is constant evaluated during codegen, or dxil const eval
// TODO: handle fp specials properly, tracked with https://github.com/microsoft/DirectXShaderCompiler/issues/6567

RWBuffer<float4> results : register(u0);

[shader("vertex")]
void main(bool b : B) {
uint i = 0;

// Literal float
// CHECK: call void @dx.op.bufferStore.f32(i32 69, %dx.types.Handle %{{.+}}, i32 0, i32 undef, float 0x3FE6A09E60000000, float 0x4004C8DC20000000, float 0.000000e+00, float 0.000000e+00, i8 15)
results[i++] = float4(length(0.5.xx),
length(-1.5.xxx),
length(0.0.xxxx),
length(-0.0.xxxx));

// Explicit float
// CHECK: call void @dx.op.bufferStore.f32(i32 69, %dx.types.Handle %{{.+}}, i32 1, i32 undef, float 0x3FE6A09E60000000, float 0x4004C8DC20000000, float 0.000000e+00, float 0.000000e+00, i8 15)
results[i++] = float4(length(0.5F.xx),
length(-1.5F.xxx),
length(0.0F.xxxx),
length(-0.0F.xxxx));

#ifdef NO_FOLD
// Currently, we rely on constant folding of DXIL ops to get rid of illegal
// double overloads. If this doesn't happen, we expect a validation error.
// Ternary operator can return literal type, while not being foldable due
// non-constant condition.
// NO_FOLD: error: validation errors
// NO_FOLD: error: DXIL intrinsic overload must be valid.
float result = length((b ? 1.5 : 0.5).xxx);
results[i++] = float4(result, 0, 0, 0);
#endif // NO_FOLD
}
40 changes: 40 additions & 0 deletions tools/clang/test/CodeGenDXIL/literal/normalize_const_eval.hlsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// RUN: %dxc -T vs_6_0 %s -E main | FileCheck %s
// RUN: not %dxc -T vs_6_0 %s -E main -DNO_FOLD 2>&1 | FileCheck %s --check-prefixes=NO_FOLD

// The code path generates invalid overload. The invalid overload will either be
// constant folded away, or caught by the validator.

// Ensure normalize is constant evaluated during codegen, or dxil const eval
// TODO: handle fp specials properly, tracked with https://github.com/microsoft/DirectXShaderCompiler/issues/6567


RWBuffer<float4> results : register(u0);

[shader("vertex")]
void main(bool b : B) {
uint i = 0;

// Literal float
// CHECK: call void @dx.op.bufferStore.f32(i32 69, %dx.types.Handle %{{.+}}, i32 0, i32 undef, float 0x3FE6A09E60000000, float 0xBFE279A740000000, float 0x7FF8000000000000, float 0x7FF8000000000000, i8 15)
results[i++] = float4(normalize(0.5.xx).x,
normalize(-1.5.xxx).x,
normalize(0.0.xxxx).x,
normalize(-0.0.xxxx).x);

// Explicit float
// CHECK: call void @dx.op.bufferStore.f32(i32 69, %dx.types.Handle %{{.+}}, i32 1, i32 undef, float 0x3FE6A09E60000000, float 0xBFE279A740000000, float 0x7FF8000000000000, float 0x7FF8000000000000, i8 15)
results[i++] = float4(normalize(0.5F.xx).x,
normalize(-1.5F.xxx).x,
normalize(0.0F.xxxx).x,
normalize(-0.0F.xxxx).x);

#ifdef NO_FOLD
// Currently, we rely on constant folding of DXIL ops to get rid of illegal
// double overloads. If this doesn't happen, we expect a validation error.
// Ternary operator can return literal type, while not being foldable due
// non-constant condition.
// NO_FOLD: error: validation errors
// NO_FOLD: error: DXIL intrinsic overload must be valid.
results[i++] = normalize((b ? 1.25 : 2.5).xxxx);
#endif // NO_FOLD
}

0 comments on commit 00cd823

Please sign in to comment.