diff options
| -rw-r--r-- | source/slang/glsl.meta.slang | 9 | ||||
| -rw-r--r-- | source/slang/hlsl.meta.slang | 16 | ||||
| -rw-r--r-- | source/slang/slang-diagnostic-defs.h | 6 | ||||
| -rw-r--r-- | source/slang/slang-ir-constexpr.cpp | 92 | ||||
| -rw-r--r-- | tests/diagnostics/constexpr-error.slang | 9 | ||||
| -rw-r--r-- | tests/diagnostics/constexpr-param.slang | 56 |
6 files changed, 111 insertions, 77 deletions
diff --git a/source/slang/glsl.meta.slang b/source/slang/glsl.meta.slang index 9112c1d2a..f63daf6b0 100644 --- a/source/slang/glsl.meta.slang +++ b/source/slang/glsl.meta.slang @@ -1914,7 +1914,7 @@ public vector<T.Element,4> texture(Sampler1D<T> sampler, float p) __generic<T:ITexelElement> [ForceInline] [require(cpp_glsl_hlsl_spirv, texture_sm_4_0_fragment)] -public vector<T.Element,4> texture(Sampler1D<T> sampler, float p, constexpr float bias) +public vector<T.Element,4> texture(Sampler1D<T> sampler, float p, float bias) { return __vectorReshape2<T.Element, 4>(sampler.SampleBias(p, bias)); } @@ -1950,7 +1950,7 @@ public vector<T.Element,4> texture(_Texture< 0, // isShadow 1, // isCombined format - > sampler, vector<float,Shape.dimensions+isArray> p, constexpr float bias) + > sampler, vector<float,Shape.dimensions+isArray> p, float bias) { return __vectorReshape2<T.Element,4>(sampler.SampleBias(p, bias)); } @@ -3891,7 +3891,7 @@ public vector<T.Element,4> textureGatherOffset(_Texture< 0, // isShadow 1, // isCombined format - > sampler, vector<float,2+isArray> p, constexpr vector<int,2> offset, int comp = 0) + > sampler, vector<float,2+isArray> p, vector<int,2> offset, int comp = 0) { switch (comp) { @@ -3915,11 +3915,12 @@ public vec4 textureGatherOffset(_Texture< 1, // isShadow 1, // isCombined format - > sampler, vector<float,2+isArray> p, float refZ, constexpr vector<int,2> offset) + > sampler, vector<float,2+isArray> p, float refZ, vector<int,2> offset) { return sampler.GatherCmp(p, refZ, offset); } + // ------------------- // textureGatherOffsets // ------------------- diff --git a/source/slang/hlsl.meta.slang b/source/slang/hlsl.meta.slang index 6a1513f9c..fdec4e901 100644 --- a/source/slang/hlsl.meta.slang +++ b/source/slang/hlsl.meta.slang @@ -1064,7 +1064,7 @@ extension _Texture<T,Shape,isArray,isMS,sampleCount,0,isShadow,1,format> [ForceInline] __glsl_extension(GL_ARB_sparse_texture_clamp) [require(cpp_glsl_hlsl_metal_spirv, texture_sm_4_1_clamp_fragment)] - T Sample(vector<float, Shape.dimensions+isArray> location, vector<int, Shape.planeDimensions> offset, float clamp) + T Sample(vector<float, Shape.dimensions+isArray> location, constexpr vector<int, Shape.planeDimensions> offset, float clamp) { __requireComputeDerivative(); __target_switch @@ -1091,7 +1091,7 @@ extension _Texture<T,Shape,isArray,isMS,sampleCount,0,isShadow,1,format> [__readNone] [ForceInline] - T Sample(vector<float, Shape.dimensions+isArray> location, vector<int, Shape.planeDimensions> offset, float clamp, out uint status) + T Sample(vector<float, Shape.dimensions+isArray> location, constexpr vector<int, Shape.planeDimensions> offset, float clamp, out uint status) { __requireComputeDerivative(); __target_switch @@ -3135,7 +3135,7 @@ vector<T.Element,4> __texture_gather_offset( _Texture<T, Shape, isArray, 0, sampleCount, access, isShadow, 0, format> texture, SamplerState s, vector<float, Shape.dimensions+isArray> location, - constexpr vector<int, Shape.planeDimensions> offset, + vector<int, Shape.planeDimensions> offset, int component) { __target_switch @@ -3196,7 +3196,7 @@ __generic<T:ITexelElement, Shape: __ITextureShape, let isArray:int, let sampleCo vector<T.Element,4> __texture_gather_offset( _Texture<T, Shape, isArray, 0, sampleCount, access, isShadow, 1, format> sampler, vector<float, Shape.dimensions+isArray> location, - constexpr vector<int, Shape.planeDimensions> offset, + vector<int, Shape.planeDimensions> offset, int component) { __target_switch @@ -3340,7 +3340,7 @@ vector<T.Element,4> __texture_gatherCmp_offset( SamplerComparisonState s, vector<float, Shape.dimensions+isArray> location, T.Element compareValue, - constexpr vector<int, Shape.planeDimensions> offset) + vector<int, Shape.planeDimensions> offset) { __target_switch { @@ -3386,7 +3386,7 @@ vector<T.Element,4> __texture_gatherCmp_offset( _Texture<T, Shape, isArray, 0, sampleCount, access, isShadow, 1, format> sampler, vector<float, Shape.dimensions+isArray> location, T.Element compareValue, - constexpr vector<int, Shape.planeDimensions> offset) + vector<int, Shape.planeDimensions> offset) { __target_switch { @@ -3532,7 +3532,7 @@ ${{{{ $(samplerParam) vector<float, Shape.dimensions+isArray> location $(compareParam), - constexpr vector<int, Shape.planeDimensions> offset) + vector<int, Shape.planeDimensions> offset) { __target_switch { @@ -3558,6 +3558,7 @@ ${{{{ } } + [ForceInline] [require(hlsl, texture_gather)] vector<T.Element,4> Gather$(compareFunc)$(componentFunc)( @@ -3628,6 +3629,7 @@ ${{{{ ${{{{ } // for (isScalarTexture) }}}} + // End of all Texture Gather diff --git a/source/slang/slang-diagnostic-defs.h b/source/slang/slang-diagnostic-defs.h index 64b1423ac..1f2fdd693 100644 --- a/source/slang/slang-diagnostic-defs.h +++ b/source/slang/slang-diagnostic-defs.h @@ -2442,11 +2442,8 @@ DIAGNOSTIC( "\"index\"] attribute to provide a binding location.") DIAGNOSTIC(40006, Error, unimplementedSystemValueSemantic, "unknown system-value semantic '$0'") - DIAGNOSTIC(49999, Error, unknownSystemValueSemantic, "unknown system-value semantic '$0'") -DIAGNOSTIC(40006, Error, needCompileTimeConstant, "expected a compile-time constant") - DIAGNOSTIC(40007, Internal, irValidationFailed, "IR validation failed: $0") DIAGNOSTIC( @@ -2469,6 +2466,9 @@ DIAGNOSTIC( unconstrainedGenericParameterNotAllowedInDynamicFunction, "unconstrained generic paramter '$0' is not allowed in a dynamic function.") +DIAGNOSTIC(40012, Error, needCompileTimeConstant, "expected a compile-time constant") + +DIAGNOSTIC(40013, Error, argIsNotConstexpr, "arg $0 in '$1' is not a compile-time constant") DIAGNOSTIC( 40020, diff --git a/source/slang/slang-ir-constexpr.cpp b/source/slang/slang-ir-constexpr.cpp index 0bdbe260a..825bc5c98 100644 --- a/source/slang/slang-ir-constexpr.cpp +++ b/source/slang/slang-ir-constexpr.cpp @@ -3,6 +3,7 @@ #include "slang-ir-dominators.h" #include "slang-ir-insts.h" +#include "slang-ir-util.h" #include "slang-ir.h" namespace Slang @@ -59,8 +60,12 @@ bool isConstExpr(IRInst* value) case kIROp_StructKey: case kIROp_WitnessTable: case kIROp_Generic: + case kIROp_GlobalConstant: return true; - + case kIROp_Param: + if (isGenericParam(value)) + return true; + break; default: break; } @@ -156,8 +161,10 @@ bool opCanBeConstExprByForwardPass(IRInst* value) { // TODO: handle call inst here. - if (value->getOp() == kIROp_Param) + if (value->getOp() == kIROp_Param || value->getOp() == kIROp_Specialize) + { return false; + } return opCanBeConstExpr(value->getOp()); } @@ -393,12 +400,6 @@ bool propagateConstExprBackward(PropagateConstExprContext* context, IRGlobalValu // the callee for this call statically, and if so try to propagate // constexpr from the parameters back to the arguments. auto callInst = (IRCall*)ii; - - UInt operandCount = callInst->getOperandCount(); - - UInt firstCallArg = 1; - UInt callArgCount = operandCount - firstCallArg; - auto callee = callInst->getOperand(0); // If we are calling a generic operation, then @@ -423,64 +424,35 @@ bool propagateConstExprBackward(PropagateConstExprContext* context, IRGlobalValu } auto calleeFunc = as<IRFunc>(callee); - if (calleeFunc && isDefinition(calleeFunc)) + auto calleeType = callee->getDataType(); + if (auto caleeFuncType = as<IRFuncType>(calleeType)) { - // We have an IR-level function definition we are calling, - // and thus we can propagate `constexpr` information - // through its `IRParam`s. - - auto calleeFuncType = calleeFunc->getDataType(); - - UInt callParamCount = calleeFuncType->getParamCount(); - SLANG_RELEASE_ASSERT(callParamCount == callArgCount); - - // If the callee has a definition, then we can read `constexpr` - // information off of the parameters of its first IR block. - if (auto calleeFirstBlock = calleeFunc->getFirstBlock()) + UInt operandCount = callInst->getOperandCount(); + UInt firstCallArg = 1; + UInt callArgCount = operandCount - firstCallArg; + auto paramCount = caleeFuncType->getParamCount(); + SLANG_RELEASE_ASSERT(paramCount == callArgCount); + for (UInt pp = 0; pp < paramCount; ++pp) { - UInt paramCounter = 0; - for (auto pp = calleeFirstBlock->getFirstParam(); pp; - pp = pp->getNextParam()) + auto paramType = caleeFuncType->getParamType(pp); + if (isConstExpr(paramType)) { - UInt paramIndex = paramCounter++; - - auto param = pp; - auto arg = callInst->getOperand(firstCallArg + paramIndex); - - if (isConstExpr(param)) + auto arg = callInst->getOperand(firstCallArg + pp); + if (maybeMarkConstExprBackwardPass(context, arg)) { - if (maybeMarkConstExprBackwardPass(context, arg)) - { - changedThisIteration = true; - } + changedThisIteration = true; } - } - } - } - else - { - // If we don't have a concrete callee function - // definition, then we need to extract the - // type of the callee instruction, and try to work - // with that. - // - // Note that this does not allow us to propagate - // `constexpr` information from the body of a callee - // back to call sites. - auto calleeType = callee->getDataType(); - if (auto caleeFuncType = as<IRFuncType>(calleeType)) - { - auto paramCount = caleeFuncType->getParamCount(); - for (UInt pp = 0; pp < paramCount; ++pp) - { - auto paramType = caleeFuncType->getParamType(pp); - auto arg = callInst->getOperand(firstCallArg + pp); - if (isConstExpr(paramType)) + // If arg is not constexpr after this, meaning it can't be + // marked constexpr for some reason, but the param requires + // that. This is not expected. + if (!isConstExpr(arg)) { - if (maybeMarkConstExprBackwardPass(context, arg)) - { - changedThisIteration = true; - } + context->getSink()->diagnose( + callInst->sourceLoc, + Diagnostics::argIsNotConstexpr, + pp + 1, + calleeFunc); + return false; } } } diff --git a/tests/diagnostics/constexpr-error.slang b/tests/diagnostics/constexpr-error.slang index 0a4744b71..a79c71847 100644 --- a/tests/diagnostics/constexpr-error.slang +++ b/tests/diagnostics/constexpr-error.slang @@ -24,7 +24,7 @@ float4 main() : SV_Target result += t.Sample(s, uv, int2(0,0)); // Error: data passed through cbuffer isn't compile-time constant - // CHECK: ([[# @LINE+1]]): error 40006: + // CHECK: ([[# @LINE+1]]): error 40012: result += t.Sample(s, uv, offset); // Error: data computed via conditional isn't compile-time cosntant @@ -33,16 +33,19 @@ float4 main() : SV_Target { ii = 1; } - // CHECK: ([[# @LINE+1]]): error 40006: + // CHECK: ([[# @LINE+1]]): error 40012: result += t.Sample(s, uv, int2(ii)); // Error: data computed in loop isn't compile-time constant // (and loop isn't unroll-able) - // CHECK: ([[# @LINE+1]]): error 40006: + // CHECK: ([[# @LINE+1]]): error 40012: for(uint jj = 0; jj < uv.y; jj++) { result += t.Sample(s, uv, int2(jj)); } + + + return result; }
\ No newline at end of file diff --git a/tests/diagnostics/constexpr-param.slang b/tests/diagnostics/constexpr-param.slang new file mode 100644 index 000000000..d41410b16 --- /dev/null +++ b/tests/diagnostics/constexpr-param.slang @@ -0,0 +1,56 @@ +//DIAGNOSTIC_TEST:SIMPLE(filecheck=CHECK): +//DIAGNOSTIC_TEST:SIMPLE(filecheck=CHECK1): +//DIAGNOSTIC_TEST:SIMPLE(filecheck=CHECK2): + +// Failure to pass compile-time-constant argument +// where it is expected. +// +// Test both callee and nested callee that require constexpr parameters. +// Test both function defined in the same module and external function. + +Texture2D<int> input; +RWTexture2D<int> output; + +int func_with_constexpr_params(constexpr int const_a) +{ + return const_a + const_a; +} + +int func_internal(int a) +{ + // Error: arg passed through isn't compile-time constant + // CHECK: ([[# @LINE+1]]): error 40013: + return func_with_constexpr_params(a); +} + +int func_external(int a) +{ + // CHECK1: ([[# @LINE+1]]): error 40012: + int2 offset = int2(a, a); + int3 location = int3(0, 0, 0); + // Load requires constexpr offset + return input.Load(location, offset); +} + +[shader("compute")] +void Test(uint3 thread_index : SV_DispatchThreadID) +{ + int result = 0; + + // Okay, immediate constant + result += func_with_constexpr_params(1); + + + int ii = 0; + if (thread_index.x > 0) + { + ii = 1; + } + // Pass non-compile-time-constant argument to function that requires constexpr parameter + // CHECK2: ([[# @LINE+1]]): error 40013: + result += func_with_constexpr_params(ii); + + // The nested function calls should issue compile errors + result += func_internal(ii); + result += func_external(ii); +} |
