diff options
| author | Jay Kwak <82421531+jkwak-work@users.noreply.github.com> | 2024-06-10 13:29:02 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-06-10 13:29:02 -0700 |
| commit | 72016f9201e4d7820f62e7ef78cee98ed1fc4da0 (patch) | |
| tree | b8d78b954791afd8ad409074cfd6cca96a6d6c79 | |
| parent | 712ce653d4c3d7284dd71389f31540d0da7f144e (diff) | |
Partial implementation of static_assert (#4294)
* Error out for types not supported by texture sample functions
This commit prints errors with a new keyword, `static_assert`, when the
given texture type is not supported for the target.
* Moving the check to linkAndOptimizeIR after specialization is done
* Remove unnecessary change
* Adding test
* Remove kIROp_StaticAssert once processed
* Do not remove StaticAssert because it is needed for the next
specialization
* Remove after iteration of child is done
---------
Co-authored-by: Yong He <yonghe@outlook.com>
| -rw-r--r-- | source/slang/core.meta.slang | 3 | ||||
| -rw-r--r-- | source/slang/slang-diagnostic-defs.h | 5 | ||||
| -rw-r--r-- | source/slang/slang-emit-spirv.cpp | 1 | ||||
| -rw-r--r-- | source/slang/slang-emit.cpp | 49 | ||||
| -rw-r--r-- | source/slang/slang-ir-autodiff-fwd.cpp | 1 | ||||
| -rw-r--r-- | source/slang/slang-ir-inst-defs.h | 1 | ||||
| -rw-r--r-- | source/slang/slang-ir-insts.h | 5 | ||||
| -rw-r--r-- | tests/language-feature/static_assert.slang | 93 |
8 files changed, 158 insertions, 0 deletions
diff --git a/source/slang/core.meta.slang b/source/slang/core.meta.slang index 272e95c85..fcb08984b 100644 --- a/source/slang/core.meta.slang +++ b/source/slang/core.meta.slang @@ -244,6 +244,9 @@ void __requirePrelude(constexpr String preludeText); __intrinsic_op($(kIROp_RequireGLSLExtension)) void __requireGLSLExtension(constexpr String preludeText); +__intrinsic_op($(kIROp_StaticAssert)) +void static_assert(constexpr bool condition, NativeString errorMessage); + /// Interface to denote types as differentiable. /// Allows for user-specified differential types as /// well as automatic generation, for when the associated type diff --git a/source/slang/slang-diagnostic-defs.h b/source/slang/slang-diagnostic-defs.h index 100543864..7fd31a46e 100644 --- a/source/slang/slang-diagnostic-defs.h +++ b/source/slang/slang-diagnostic-defs.h @@ -762,6 +762,11 @@ DIAGNOSTIC(41202, Error, notEqualBitCastSize, "invalid to bit_cast differently s DIAGNOSTIC(41203, Warning, notEqualReinterpretCastSize, "reinterpret<> into not equally sized types: '$0' with size '$1' casted into '$2' with size '$3'") DIAGNOSTIC(41300, Error, byteAddressBufferUnaligned, "invalid alignment `$0` specified for the byte address buffer resource with the element size of `$1`") + +DIAGNOSTIC(41400, Error, staticAssertionFailure, "static assertion failed, $0") +DIAGNOSTIC(41401, Error, staticAssertionFailureWithoutMessage, "static assertion failed.") +DIAGNOSTIC(41402, Error, staticAssertionConditionNotConstant, "condition for static assertion cannot be evaluated at the compile-time.") + // // 5xxxx - Target code generation. // diff --git a/source/slang/slang-emit-spirv.cpp b/source/slang/slang-emit-spirv.cpp index d7c6c64a5..1db323993 100644 --- a/source/slang/slang-emit-spirv.cpp +++ b/source/slang/slang-emit-spirv.cpp @@ -2632,6 +2632,7 @@ struct SPIRVEmitContext } case kIROp_Specialize: case kIROp_MissingReturn: + case kIROp_StaticAssert: break; case kIROp_Var: result = emitVar(parent, inst); diff --git a/source/slang/slang-emit.cpp b/source/slang/slang-emit.cpp index 02dab6dfa..da348fa64 100644 --- a/source/slang/slang-emit.cpp +++ b/source/slang/slang-emit.cpp @@ -362,6 +362,51 @@ void calcRequiredLoweringPassSet(RequiredLoweringPassSet& result, CodeGenContext } } +bool checkStaticAssert(IRInst* inst, DiagnosticSink* sink) +{ + switch (inst->getOp()) + { + case kIROp_StaticAssert: + { + IRInst* condi = inst->getOperand(0); + if (auto condiLit = as<IRBoolLit>(condi)) + { + if (!condiLit->getValue()) + { + IRInst* msg = inst->getOperand(1); + if (auto msgLit = as<IRStringLit>(msg)) + { + sink->diagnose(inst, Diagnostics::staticAssertionFailure, msgLit->getStringSlice()); + } + else + { + sink->diagnose(inst, Diagnostics::staticAssertionFailureWithoutMessage); + } + } + } + else + { + sink->diagnose(condi, Diagnostics::staticAssertionConditionNotConstant); + } + + return true; + } + } + + List<IRInst*> removeList; + for (auto child : inst->getChildren()) + { + if (checkStaticAssert(child, sink)) + removeList.add(child); + } + for (auto child : removeList) + { + child->removeAndDeallocate(); + } + + return false; +} + Result linkAndOptimizeIR( CodeGenContext* codeGenContext, LinkingAndOptimizationOptions const& options, @@ -881,6 +926,10 @@ Result linkAndOptimizeIR( validateIRModuleIfEnabled(codeGenContext, irModule); + // Process `static_assert` after the specialization is done. + // Some information for `static_assert` is available only after the specialization. + checkStaticAssert(irModule->getModuleInst(), sink); + // For HLSL (and fxc/dxc) only, we need to "wrap" any // structured buffers defined over matrix types so // that they instead use an intermediate `struct`. diff --git a/source/slang/slang-ir-autodiff-fwd.cpp b/source/slang/slang-ir-autodiff-fwd.cpp index 299f4655b..492ff0ca1 100644 --- a/source/slang/slang-ir-autodiff-fwd.cpp +++ b/source/slang/slang-ir-autodiff-fwd.cpp @@ -1911,6 +1911,7 @@ InstPair ForwardDiffTranscriber::transcribeInstImpl(IRBuilder* builder, IRInst* case kIROp_RWStructuredBufferGetElementPtr: case kIROp_NonUniformResourceIndex: case kIROp_IsType: + case kIROp_StaticAssert: case kIROp_ImageSubscript: case kIROp_ImageLoad: case kIROp_ImageStore: diff --git a/source/slang/slang-ir-inst-defs.h b/source/slang/slang-ir-inst-defs.h index 37e3d2064..74990ed55 100644 --- a/source/slang/slang-ir-inst-defs.h +++ b/source/slang/slang-ir-inst-defs.h @@ -600,6 +600,7 @@ INST(discard, discard, 0, 0) INST(RequirePrelude, RequirePrelude, 1, 0) INST(RequireGLSLExtension, RequireGLSLExtension, 1, 0) INST(RequireComputeDerivative, RequireComputeDerivative, 0, 0) +INST(StaticAssert, StaticAssert, 2, 0) // TODO: We should consider splitting the basic arithmetic/comparison // ops into cases for signed integers, unsigned integers, and floating-point diff --git a/source/slang/slang-ir-insts.h b/source/slang/slang-ir-insts.h index 301604bf3..9e377fe73 100644 --- a/source/slang/slang-ir-insts.h +++ b/source/slang/slang-ir-insts.h @@ -3249,6 +3249,11 @@ struct IRRequireComputeDerivative : IRInst IR_LEAF_ISA(RequireComputeDerivative) }; +struct IRStaticAssert : IRInst +{ + IR_LEAF_ISA(StaticAssert) +}; + struct IRBuilderSourceLocRAII; struct IRBuilder diff --git a/tests/language-feature/static_assert.slang b/tests/language-feature/static_assert.slang new file mode 100644 index 000000000..55bfa0abb --- /dev/null +++ b/tests/language-feature/static_assert.slang @@ -0,0 +1,93 @@ +//TEST:SIMPLE(filecheck=CHK):-target hlsl -stage compute -entry computeMain +//TEST:SIMPLE(filecheck=CHK):-target glsl -stage compute -entry computeMain +//TEST:SIMPLE(filecheck=CHK):-target spirv -stage compute -entry computeMain +//TEST:SIMPLE(filecheck=HLSL):-target hlsl -stage compute -entry computeMain +//TEST:SIMPLE(filecheck=GLSL):-target glsl -stage compute -entry computeMain +//TEST:SIMPLE(filecheck=SPV):-target spirv -stage compute -entry computeMain + +// TODO: requires changes in parser +//static_assert(true, "PASS_global"); +//static_assert(false, "FAIL_global"); + +__generic<T:IArithmetic> +void TEST_specialize() +{ + static_assert(true, "TEST_specialize true"); + static_assert(T is float, "TEST_specialize T_is_float"); + static_assert(T is int, "TEST_specialize T_is_int"); +} + +void TEST_target_switch() +{ + static_assert(false, "TEST_target_switch all"); + __target_switch + { + case hlsl: + static_assert(false, "TEST_target_switch hlsl"); + return; + case glsl: + static_assert(false, "TEST_target_switch glsl"); + return; + default: + static_assert(false, "TEST_target_switch default"); + return; + } +} + +__generic<T:IArithmetic> +struct MyType +{ + // TODO: requires changes in parser + //static_assert(true, "PASS_struct"); + //static_assert(false, "FAIL_struct"); + + __init() + { + static_assert(true, "MyType init true"); + static_assert(false, "MyType init false"); + } +}; + +__generic<T:IFloat> +extension MyType<T> +{ +}; + +[numthreads(1,1,1)] +void computeMain(int3 dispatchThreadID: SV_DispatchThreadID) +{ + //CHK-NOT:error {{.*}} TEST_specialize + //CHK: error {{.*}} TEST_specialize T_is_int + //CHK-NOT:error {{.*}} TEST_specialize + TEST_specialize<float>(); + + //CHK-NOT:error {{.*}} TEST_specialize + //CHK: error 41400: {{.*}} TEST_specialize T_is_float + //CHK-NOT:error {{.*}} TEST_specialize + TEST_specialize<int>(); + + //HLSL: error {{.*}} TEST_target_switch all + //HLSL: error {{.*}} TEST_target_switch hlsl + //HLSL-NOT: error {{.*}} TEST_target_switch glsl + //HLSL-NOT: error {{.*}} TEST_target_switch default + // + //GLSL: error {{.*}} TEST_target_switch all + //GLSL-NOT: error {{.*}} TEST_target_switch hlsl + //GLSL: error {{.*}} TEST_target_switch glsl + //GLSL-NOT: error {{.*}} TEST_target_switch default + // + //SPV: error {{.*}} TEST_target_switch all + //SPV-NOT: error {{.*}} TEST_target_switch hlsl + //SPV-NOT: error {{.*}} TEST_target_switch glsl + //SPV: error {{.*}} TEST_target_switch default + // + TEST_target_switch(); + + //CHK-NOT: error {{.*}} MyType init true + //CHK: error {{.*}} MyType init false + MyType<float> obj; + + //CHK: ([[#@LINE+1]]): error + static_assert(dispatchThreadID.x == 0, "not constant"); +} + |
