diff --git a/lib/DXIL/DxilOperations.cpp b/lib/DXIL/DxilOperations.cpp index ddd3279cf9..b3b3aea49f 100644 --- a/lib/DXIL/DxilOperations.cpp +++ b/lib/DXIL/DxilOperations.cpp @@ -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 = diff --git a/tools/clang/test/CodeGenDXIL/literal/fmod_const_eval.hlsl b/tools/clang/test/CodeGenDXIL/literal/fmod_const_eval.hlsl new file mode 100644 index 0000000000..bff10c2a2e --- /dev/null +++ b/tools/clang/test/CodeGenDXIL/literal/fmod_const_eval.hlsl @@ -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 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 +} diff --git a/tools/clang/test/CodeGenDXIL/literal/length_const_eval.hlsl b/tools/clang/test/CodeGenDXIL/literal/length_const_eval.hlsl new file mode 100644 index 0000000000..4e6fbec23f --- /dev/null +++ b/tools/clang/test/CodeGenDXIL/literal/length_const_eval.hlsl @@ -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 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 +} diff --git a/tools/clang/test/CodeGenDXIL/literal/normalize_const_eval.hlsl b/tools/clang/test/CodeGenDXIL/literal/normalize_const_eval.hlsl new file mode 100644 index 0000000000..280bd30465 --- /dev/null +++ b/tools/clang/test/CodeGenDXIL/literal/normalize_const_eval.hlsl @@ -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 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 +}