From d81c347e0edcbbf181885baf2b13978c28dfc9a8 Mon Sep 17 00:00:00 2001 From: Tim Foley Date: Mon, 12 Jun 2017 12:26:12 -0700 Subject: First pass at support for cross-compilation This is a large change that contains many pieces: - Update the `cross-compile0` test to actually make use of cross compilation. Now the `cross-compile0.hlsl` file contains both HLSL and GLSL source code, and then imports code from `cross-compile0.slang`, which provides a "library" (one function) that can be shared between both the HLSL and GLSL version of things. - Fixed a bug in the support for backslash-escaped newlines. - Added a new `__import` declaration type (replaces the `using` directive that was still around in a vestigial form) An `__import` causes the compiler to look for a Slang source file (currently using the ordinary `#include` lookup logic), and then parse/check the found file as an additional module ("translation unit"), before making its declarations visible in the current scope. - Refactored the main compilation flow to be simpler. There were the `ShaderCompiler` and `ShaderCompilerImpl` classes that weren't relaly doing anything, but added complexity to the whole workflow. - The `render-test` application has been heavily modified to better support testing cross-compilation workflows. At the most basic level we are starting to distinguish pass-through vs. rewriter workflows, and are passing various `#define`s down to the compiler(s) to let the source code be customized as needed for each case. Several annoying corner cases are caused here by having to support the GLSL compilation model, which really wants each entry point in its own specific translation unit, whereas we really want to keep things nicely contained in single files. - Added support for `__intrinsic` operations to have target-specific behavior. This allows a function to be given a different name for some specific target (so a call gets emitted as a call to that other operation). More generally, the library writer can put together an arbitrary format string that will be used in place of expressions that call the given function, e.g.: __intrinsic(hlsl, "$1 - $0") __intrinsic int foo(int a, int b); Given this declaration, a call like `foo(x,y)` will code generate as `x - y` for HLSL, and as `foo(x,y)` for all other targets. Annoying things still to be dealt with: - The way that I'm filtering the user-provided options when passing things down to the compilation of dynamically loaded modules is a bit ad hoc. It would be good to have a systematic notion of which options will be inherited and which won't. There is also more code duplication than I'd like, so we risk having the compiler behave differently when compiling a file at the top level, vs. because of `__import`. - Adding target-specific behavior to intrinsics is all well and good, but the current approach means we can only add this to the original declaration, which limits the ability to easily extend the set of targets. A better approach long-term would be to add a more robust notion of target-based overload resolution (which would happen after semantic checking). Then one mechanism would be used to find the right target-specific overload to use for an operation, and then each (target-specific) definition could use a simpler attribute to intercept code-generation behavior. Note that we might eventually need a similar notion to deal with stage- or profile-specific functions and the overloading behavior around them, so using this for intrinsics doesn't seem like a bad idea. --- source/slang/slang-stdlib.cpp | 79 ++++++++++++++++++++----------------------- 1 file changed, 37 insertions(+), 42 deletions(-) (limited to 'source/slang/slang-stdlib.cpp') diff --git a/source/slang/slang-stdlib.cpp b/source/slang/slang-stdlib.cpp index f74fcd603..494a32e4d 100644 --- a/source/slang/slang-stdlib.cpp +++ b/source/slang/slang-stdlib.cpp @@ -8,16 +8,16 @@ #define LINE_STRING STRINGIZE(__LINE__) enum { kLibIncludeStringLine = __LINE__+1 }; -const char * LibIncludeStringChunks[] = { R"( +const char * LibIncludeStringChunks[] = { R"=( typedef uint UINT; -__generic __intrinsic(Assign) T operator=(out T left, T right); +__generic __intrinsic_op(Assign) T operator=(out T left, T right); -__generic __intrinsic(Sequence) U operator,(T left, U right); +__generic __intrinsic_op(Sequence) U operator,(T left, U right); -__generic __intrinsic(Select) T operator?:(bool condition, T ifTrue, T ifFalse); -__generic __intrinsic(Select) vector operator?:(vector condition, vector ifTrue, vector ifFalse); +__generic __intrinsic_op(Select) T operator?:(bool condition, T ifTrue, T ifFalse); +__generic __intrinsic_op(Select) vector operator?:(vector condition, vector ifTrue, vector ifFalse); __generic __magic_type(HLSLAppendStructuredBufferType) struct AppendStructuredBuffer { @@ -234,7 +234,7 @@ __generic __magic_type(HLSLPointStreamType) struct PointStream {}; __generic __magic_type(HLSLLineStreamType) struct LineStream {}; __generic __magic_type(HLSLLineStreamType) struct TriangleStream {}; -)", R"( +)=", R"=( // Note(tfoley): Trying to systematically add all the HLSL builtins @@ -503,7 +503,7 @@ __generic __intrinsic T fwidth(T x); __generic __intrinsic vector fwidth(vector x); __generic __intrinsic matrix fwidth(matrix x); -)", R"( +)=", R"=( // Get number of samples in render target __intrinsic uint GetRenderTargetSampleCount(); @@ -615,27 +615,27 @@ __intrinsic uint4 msad4(uint reference, uint2 source, uint4 accum); // General inner products // scalar-scalar -__generic __intrinsic(Mul_Scalar_Scalar) T mul(T x, T y); +__generic __intrinsic_op(Mul_Scalar_Scalar) T mul(T x, T y); // scalar-vector and vector-scalar -__generic __intrinsic(Mul_Vector_Scalar) vector mul(vector x, T y); -__generic __intrinsic(Mul_Scalar_Vector) vector mul(T x, vector y); +__generic __intrinsic_op(Mul_Vector_Scalar) vector mul(vector x, T y); +__generic __intrinsic_op(Mul_Scalar_Vector) vector mul(T x, vector y); // scalar-matrix and matrix-scalar -__generic __intrinsic(Mul_Matrix_Scalar) matrix mul(matrix x, T y); -__generic __intrinsic(Mul_Scalar_Matrix) matrix mul(T x, matrix y); +__generic __intrinsic_op(Mul_Matrix_Scalar) matrix mul(matrix x, T y); +__generic __intrinsic_op(Mul_Scalar_Matrix) matrix mul(T x, matrix y); // vector-vector (dot product) -__generic __intrinsic(InnerProduct_Vector_Vector) T mul(vector x, vector y); +__generic __intrinsic_op(InnerProduct_Vector_Vector) T mul(vector x, vector y); // vector-matrix -__generic __intrinsic(InnerProduct_Vector_Matrix) vector mul(vector x, matrix y); +__generic __intrinsic_op(InnerProduct_Vector_Matrix) vector mul(vector x, matrix y); // matrix-vector -__generic __intrinsic(InnerProduct_Matrix_Vector) vector mul(matrix x, vector y); +__generic __intrinsic_op(InnerProduct_Matrix_Vector) vector mul(matrix x, vector y); // matrix-matrix -__generic __intrinsic(InnerProduct_Matrix_Matrix) matrix mul(matrix x, matrix y); +__generic __intrinsic_op(InnerProduct_Matrix_Matrix) matrix mul(matrix x, matrix y); // noise (deprecated) __intrinsic float noise(float x); @@ -759,9 +759,17 @@ __generic __intrinsic vector r __generic __intrinsic matrix rsqrt(matrix x); // Clamp value to [0,1] range -__generic __intrinsic T saturate(T x); -__generic __intrinsic vector saturate(vector x); -__generic __intrinsic matrix saturate(matrix x); +__generic +__intrinsic(glsl, "clamp($0, 0, 1)") __intrinsic +T saturate(T x); + +__generic +__intrinsic(glsl, "clamp($0, 0, 1)") __intrinsic +vector saturate(vector x); + +__generic +__intrinsic(glsl, "clamp($0, 0, 1)") __intrinsic +matrix saturate(matrix x); // Extract sign of value @@ -769,7 +777,7 @@ __generic __intrinsic int sign(T x); __generic __intrinsic vector sign(vector x); __generic __intrinsic matrix sign(matrix x); -)", R"( +)=", R"=( // Sine @@ -853,7 +861,7 @@ __generic __intrinsic vector t __generic __intrinsic matrix trunc(matrix x); -)", R"( +)=", R"=( // Shader model 6.0 stuff @@ -930,13 +938,13 @@ __generic __intrinsic vector WaveReadLaneAt __generic __intrinsic matrix WaveReadLaneAt(matrix expr, int laneIndex); -)", R"( +)=", R"=( // `typedef`s to help with the fact that HLSL has been sorta-kinda case insensitive at various points typedef Texture2D texture2D; #line default -)" }; +)=" }; using namespace CoreLib::Basic; @@ -1522,19 +1530,6 @@ namespace Slang sb << "__intrinsic mat4 operator * (mat4, mat4);\n"; #endif -#if 0 - sb << "__intrinsic(And) bool operator && (bool, bool);\n"; - sb << "__intrinsic(Or) bool operator || (bool, bool);\n"; - - for (auto type : intTypes) - { - sb << "__intrinsic(And) bool operator && (bool, " << type << ");\n"; - sb << "__intrinsic(Or) bool operator || (bool, " << type << ");\n"; - sb << "__intrinsic(And) bool operator && (" << type << ", bool);\n"; - sb << "__intrinsic(Or) bool operator || (" << type << ", bool);\n"; - } -#endif - for (auto op : unaryOps) { for (auto type : kBaseTypes) @@ -1547,17 +1542,17 @@ namespace Slang // scalar version sb << fixity; - sb << "__intrinsic(" << int(op.opCode) << ") " << type.name << " operator" << op.opName << "(" << qual << type.name << " value);\n"; + sb << "__intrinsic_op(" << int(op.opCode) << ") " << type.name << " operator" << op.opName << "(" << qual << type.name << " value);\n"; // vector version sb << "__generic "; sb << fixity; - sb << "__intrinsic(" << int(op.opCode) << ") vector<" << type.name << ",N> operator" << op.opName << "(" << qual << "vector<" << type.name << ",N> value);\n"; + sb << "__intrinsic_op(" << int(op.opCode) << ") vector<" << type.name << ",N> operator" << op.opName << "(" << qual << "vector<" << type.name << ",N> value);\n"; // matrix version sb << "__generic "; sb << fixity; - sb << "__intrinsic(" << int(op.opCode) << ") matrix<" << type.name << ",N,M> operator" << op.opName << "(" << qual << "matrix<" << type.name << ",N,M> value);\n"; + sb << "__intrinsic_op(" << int(op.opCode) << ") matrix<" << type.name << ",N,M> operator" << op.opName << "(" << qual << "matrix<" << type.name << ",N,M> value);\n"; } } @@ -1580,15 +1575,15 @@ namespace Slang // TODO: handle `SHIFT` // scalar version - sb << "__intrinsic(" << int(op.opCode) << ") " << resultType << " operator" << op.opName << "(" << leftQual << leftType << " left, " << rightType << " right);\n"; + sb << "__intrinsic_op(" << int(op.opCode) << ") " << resultType << " operator" << op.opName << "(" << leftQual << leftType << " left, " << rightType << " right);\n"; // vector version sb << "__generic "; - sb << "__intrinsic(" << int(op.opCode) << ") vector<" << resultType << ",N> operator" << op.opName << "(" << leftQual << "vector<" << leftType << ",N> left, vector<" << rightType << ",N> right);\n"; + sb << "__intrinsic_op(" << int(op.opCode) << ") vector<" << resultType << ",N> operator" << op.opName << "(" << leftQual << "vector<" << leftType << ",N> left, vector<" << rightType << ",N> right);\n"; // matrix version sb << "__generic "; - sb << "__intrinsic(" << int(op.opCode) << ") matrix<" << resultType << ",N,M> operator" << op.opName << "(" << leftQual << "matrix<" << leftType << ",N,M> left, matrix<" << rightType << ",N,M> right);\n"; + sb << "__intrinsic_op(" << int(op.opCode) << ") matrix<" << resultType << ",N,M> operator" << op.opName << "(" << leftQual << "matrix<" << leftType << ",N,M> left, matrix<" << rightType << ",N,M> right);\n"; } } -- cgit v1.2.3