diff options
Diffstat (limited to 'source')
| -rw-r--r-- | source/slang/core.meta.slang | 201 | ||||
| -rw-r--r-- | source/slang/hlsl.meta.slang | 45 | ||||
| -rw-r--r-- | source/slang/slang-check-expr.cpp | 10 | ||||
| -rw-r--r-- | source/slang/slang-check-impl.h | 1 | ||||
| -rw-r--r-- | source/slang/slang-check-overload.cpp | 33 | ||||
| -rw-r--r-- | source/slang/slang-compound-intrinsics.h | 80 | ||||
| -rw-r--r-- | source/slang/slang-diagnostic-defs.h | 2 | ||||
| -rw-r--r-- | source/slang/slang-expr-defs.h | 2 | ||||
| -rw-r--r-- | source/slang/slang-lower-to-ir.cpp | 197 | ||||
| -rw-r--r-- | source/slang/slang-mangle.cpp | 8 | ||||
| -rw-r--r-- | source/slang/slang-modifier-defs.h | 12 | ||||
| -rw-r--r-- | source/slang/slang-stdlib.cpp | 25 | ||||
| -rw-r--r-- | source/slang/slang-syntax.h | 1 | ||||
| -rw-r--r-- | source/slang/slang.vcxproj | 1 | ||||
| -rw-r--r-- | source/slang/slang.vcxproj.filters | 3 |
15 files changed, 263 insertions, 358 deletions
diff --git a/source/slang/core.meta.slang b/source/slang/core.meta.slang index f73178322..821905375 100644 --- a/source/slang/core.meta.slang +++ b/source/slang/core.meta.slang @@ -1455,11 +1455,8 @@ for (int tt = 0; tt < kBaseTextureTypeCount; ++tt) } -for (auto op : unaryOps) +for (auto op : intrinsicUnaryOps) { - char const* fixity = (op.flags & POSTFIX) != 0 ? "__postfix " : "__prefix "; - char const* qual = (op.flags & ASSIGNMENT) != 0 ? "in out " : ""; - for (auto type : kBaseTypes) { if ((type.flags & op.flags) == 0) @@ -1469,18 +1466,15 @@ for (auto op : unaryOps) if (op.flags & BOOL_RESULT) resultType = "bool"; // scalar version - sb << fixity; - sb << "__intrinsic_op(" << int(op.opCode) << ") " << resultType << " operator" << op.opName << "(" << qual << type.name << " value);\n"; + sb << "__prefix __intrinsic_op(" << int(op.opCode) << ") " << resultType << " operator" << op.opName << "(" << type.name << " value);\n"; // vector version sb << "__generic<let N : int> "; - sb << fixity; - sb << "__intrinsic_op(" << int(op.opCode) << ") vector<" << resultType << ",N> operator" << op.opName << "(" << qual << "vector<" << type.name << ",N> value);\n"; + sb << "__prefix __intrinsic_op(" << int(op.opCode) << ") vector<" << resultType << ",N> operator" << op.opName << "(" << "vector<" << type.name << ",N> value);\n"; // matrix version sb << "__generic<let N : int, let M : int> "; - sb << fixity; - sb << "__intrinsic_op(" << int(op.opCode) << ") matrix<" << resultType << ",N,M> operator" << op.opName << "(" << qual << "matrix<" << type.name << ",N,M> value);\n"; + sb << "__prefix __intrinsic_op(" << int(op.opCode) << ") matrix<" << resultType << ",N,M> operator" << op.opName << "(" << "matrix<" << type.name << ",N,M> value);\n"; } // Synthesize generic versions @@ -1490,27 +1484,85 @@ for (auto op : unaryOps) if (op.flags & BOOL_RESULT) resultType = "bool"; // scalar version - sb << fixity; sb << "__generic<T : " << op.interface << ">\n"; - sb << "__intrinsic_op(" << int(op.opCode) << ") " << resultType << " operator" << op.opName << "(" << qual << "T value);\n"; + sb << "__prefix __intrinsic_op(" << int(op.opCode) << ") " << resultType << " operator" << op.opName << "(" << "T value);\n"; // vector version sb << "__generic<T : " << op.interface << ", let N : int> "; - sb << fixity; - sb << "__intrinsic_op(" << int(op.opCode) << ") vector<" << resultType << ",N> operator" << op.opName << "(" << qual << "vector<T,N> value);\n"; + sb << "__prefix __intrinsic_op(" << int(op.opCode) << ") vector<" << resultType << ",N> operator" << op.opName << "(vector<T,N> value);\n"; // matrix version sb << "__generic<T : " << op.interface << ", let N : int, let M : int> "; - sb << fixity; - sb << "__intrinsic_op(" << int(op.opCode) << ") matrix<" << resultType << ",N,M> operator" << op.opName << "(" << qual << "matrix<T,N,M> value);\n"; + sb << "__prefix __intrinsic_op(" << int(op.opCode) << ") matrix<" << resultType << ",N,M> operator" << op.opName << "(matrix<T,N,M> value);\n"; } } -for (auto op : binaryOps) +}}}} + +__generic<T : __BuiltinArithmeticType> +[__unsafeForceInlineEarly] +__prefix T operator+(T value) +{ return value; } + +__generic<T : __BuiltinArithmeticType, let N : int> +[__unsafeForceInlineEarly] +__prefix vector<T,N> operator+(vector<T,N> value) +{ return value; } + +__generic<T : __BuiltinArithmeticType, let R : int, let C : int> +[__unsafeForceInlineEarly] +__prefix matrix<T,R,C> operator+(matrix<T,R,C> value) +{ return value; } + +${{{{ + +static const struct IncDecOpInfo +{ + char const* name; + char const* binOp; +} kIncDecOps[] = +{ + { "++", "+" }, + { "--", "-" }, +}; +static const struct IncDecOpFixity +{ + char const* qual; + char const* bodyPrefix; + char const* returnVal; +} kIncDecFixities[] = { - char const* leftQual = ""; - if(op.flags & ASSIGNMENT) leftQual = "in out "; + { "__prefix", "", "value" }, + { "__postfix", " let result = value;", "result" }, +}; +for(auto op : kIncDecOps) +for(auto fixity : kIncDecFixities) +{ +}}}} + +$(fixity.qual) +__generic<T : __BuiltinArithmeticType> +[__unsafeForceInlineEarly] +T operator$(op.name)(in out T value) +{$(fixity.bodyPrefix) value = value $(op.binOp) T(1); return $(fixity.returnVal); } + +$(fixity.qual) +__generic<T : __BuiltinArithmeticType, let N : int> +[__unsafeForceInlineEarly] +vector<T,N> operator$(op.name)(in out vector<T,N> value) +{$(fixity.bodyPrefix) value = value $(op.binOp) T(1); return $(fixity.returnVal); } +$(fixity.qual) +__generic<T : __BuiltinArithmeticType, let R : int, let C : int> +[__unsafeForceInlineEarly] +matrix<T,R,C> operator$(op.name)(in out matrix<T,R,C> value) +{$(fixity.bodyPrefix) value = value $(op.binOp) T(1); return $(fixity.returnVal); } + +${{{{ +} + +for (auto op : intrinsicBinaryOps) +{ for (auto type : kBaseTypes) { if ((type.flags & op.flags) == 0) @@ -1533,15 +1585,15 @@ for (auto op : binaryOps) // the compiler) // scalar version - sb << "__intrinsic_op(" << int(op.opCode) << ") " << resultType << " operator" << op.opName << "(" << leftQual << leftType << " left, " << rightType << " right);\n"; + sb << "__intrinsic_op(" << int(op.opCode) << ") " << resultType << " operator" << op.opName << "(" << leftType << " left, " << rightType << " right);\n"; // vector version sb << "__generic<let N : int> "; - sb << "__intrinsic_op(" << 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 << "(vector<" << leftType << ",N> left, vector<" << rightType << ",N> right);\n"; // matrix version sb << "__generic<let N : int, let M : int> "; - 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"; + sb << "__intrinsic_op(" << int(op.opCode) << ") matrix<" << resultType << ",N,M> operator" << op.opName << "(matrix<" << leftType << ",N,M> left, matrix<" << rightType << ",N,M> right);\n"; // We currently synthesize addiitonal overloads // for the case where one or the other operand @@ -1577,21 +1629,18 @@ for (auto op : binaryOps) // for builtin in non-operator functions anyway. // scalar-vector and scalar-matrix - if (!(op.flags & ASSIGNMENT)) - { - sb << "__generic<let N : int> "; - sb << "__intrinsic_op(" << int(op.opCode) << ") vector<" << resultType << ",N> operator" << op.opName << "(" << leftQual << leftType << " left, vector<" << rightType << ",N> right);\n"; + sb << "__generic<let N : int> "; + sb << "__intrinsic_op(" << int(op.opCode) << ") vector<" << resultType << ",N> operator" << op.opName << "(" << leftType << " left, vector<" << rightType << ",N> right);\n"; - sb << "__generic<let N : int, let M : int> "; - sb << "__intrinsic_op(" << int(op.opCode) << ") matrix<" << resultType << ",N,M> operator" << op.opName << "(" << leftQual << leftType << " left, matrix<" << rightType << ",N,M> right);\n"; - } + sb << "__generic<let N : int, let M : int> "; + sb << "__intrinsic_op(" << int(op.opCode) << ") matrix<" << resultType << ",N,M> operator" << op.opName << "(" << leftType << " left, matrix<" << rightType << ",N,M> right);\n"; // vector-scalar and matrix-scalar sb << "__generic<let N : int> "; - sb << "__intrinsic_op(" << int(op.opCode) << ") vector<" << resultType << ",N> operator" << op.opName << "(" << leftQual << "vector<" << leftType << ",N> left, " << rightType << " right);\n"; + sb << "__intrinsic_op(" << int(op.opCode) << ") vector<" << resultType << ",N> operator" << op.opName << "(vector<" << leftType << ",N> left, " << rightType << " right);\n"; sb << "__generic<let N : int, let M : int> "; - sb << "__intrinsic_op(" << int(op.opCode) << ") matrix<" << resultType << ",N,M> operator" << op.opName << "(" << leftQual << "matrix<" << leftType << ",N,M> left, " << rightType << " right);\n"; + sb << "__intrinsic_op(" << int(op.opCode) << ") matrix<" << resultType << ",N,M> operator" << op.opName << "(matrix<" << leftType << ",N,M> left, " << rightType << " right);\n"; } // Synthesize generic versions @@ -1606,36 +1655,102 @@ for (auto op : binaryOps) // scalar version sb << "__generic<T : " << op.interface << ">\n"; - sb << "__intrinsic_op(" << int(op.opCode) << ") " << resultType << " operator" << op.opName << "(" << leftQual << leftType << " left, " << rightType << " right);\n"; + sb << "__intrinsic_op(" << int(op.opCode) << ") " << resultType << " operator" << op.opName << "(" << leftType << " left, " << rightType << " right);\n"; // vector version sb << "__generic<T : " << op.interface << ", let N : int> "; - sb << "__intrinsic_op(" << 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 << "(vector<" << leftType << ",N> left, vector<" << rightType << ",N> right);\n"; // matrix version sb << "__generic<T : " << op.interface << ", let N : int, let M : int> "; - 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"; + sb << "__intrinsic_op(" << int(op.opCode) << ") matrix<" << resultType << ",N,M> operator" << op.opName << "(matrix<" << leftType << ",N,M> left, matrix<" << rightType << ",N,M> right);\n"; // scalar-vector and scalar-matrix - if (!(op.flags & ASSIGNMENT)) - { - sb << "__generic<T : " << op.interface << ", let N : int> "; - sb << "__intrinsic_op(" << int(op.opCode) << ") vector<" << resultType << ",N> operator" << op.opName << "(" << leftQual << leftType << " left, vector<" << rightType << ",N> right);\n"; + sb << "__generic<T : " << op.interface << ", let N : int> "; + sb << "__intrinsic_op(" << int(op.opCode) << ") vector<" << resultType << ",N> operator" << op.opName << "(" << leftType << " left, vector<" << rightType << ",N> right);\n"; - sb << "__generic<T : " << op.interface << ", let N : int, let M : int> "; - sb << "__intrinsic_op(" << int(op.opCode) << ") matrix<" << resultType << ",N,M> operator" << op.opName << "(" << leftQual << leftType << " left, matrix<" << rightType << ",N,M> right);\n"; - } + sb << "__generic<T : " << op.interface << ", let N : int, let M : int> "; + sb << "__intrinsic_op(" << int(op.opCode) << ") matrix<" << resultType << ",N,M> operator" << op.opName << "(" << leftType << " left, matrix<" << rightType << ",N,M> right);\n"; // vector-scalar and matrix-scalar sb << "__generic<T : " << op.interface << ", let N : int> "; - sb << "__intrinsic_op(" << int(op.opCode) << ") vector<" << resultType << ",N> operator" << op.opName << "(" << leftQual << "vector<" << leftType << ",N> left, " << rightType << " right);\n"; + sb << "__intrinsic_op(" << int(op.opCode) << ") vector<" << resultType << ",N> operator" << op.opName << "(vector<" << leftType << ",N> left, " << rightType << " right);\n"; sb << "__generic<T : " << op.interface << ", let N : int, let M : int> "; - sb << "__intrinsic_op(" << int(op.opCode) << ") matrix<" << resultType << ",N,M> operator" << op.opName << "(" << leftQual << "matrix<" << leftType << ",N,M> left, " << rightType << " right);\n"; + sb << "__intrinsic_op(" << int(op.opCode) << ") matrix<" << resultType << ",N,M> operator" << op.opName << "(matrix<" << leftType << ",N,M> left, " << rightType << " right);\n"; } } + + + static const struct CompoundBinaryOpInfo + { + char const* name; + char const* interface; + } kCompoundBinaryOps[] = + { + { "+", "__BuiltinArithmeticType" }, + { "-", "__BuiltinArithmeticType" }, + { "*", "__BuiltinArithmeticType" }, + { "/", "__BuiltinArithmeticType" }, + { "%", "__BuiltinIntegerType" }, + { "%", "__BuiltinFloatingPointType" }, + { "&", "__BuiltinLogicalType" }, + { "|", "__BuiltinLogicalType" }, + { "^", "__BuiltinLogicalType" }, + { "<<", "__BuiltinIntegerType" }, + { ">>", "__BuiltinIntegerType" }, + }; + for( auto op : kCompoundBinaryOps ) + { + }}}} + + __generic<T : $(op.interface)> + [__unsafeForceInlineEarly] + T operator$(op.name)=(in out T left, T right) + { + left = left $(op.name) right; + return left; + } + + __generic<T : $(op.interface), let N : int> + [__unsafeForceInlineEarly] + vector<T,N> operator$(op.name)=(in out vector<T,N> left, vector<T,N> right) + { + left = left $(op.name) right; + return left; + } + + __generic<T : $(op.interface), let N : int> + [__unsafeForceInlineEarly] + vector<T,N> operator$(op.name)=(in out vector<T,N> left, T right) + { + left = left $(op.name) right; + return left; + } + + __generic<T : $(op.interface), let R : int, let C : int> + [__unsafeForceInlineEarly] + matrix<T,R,C> operator$(op.name)=(in out matrix<T,R,C> left, matrix<T,R,C> right) + { + left = left $(op.name) right; + return left; + } + + __generic<T : $(op.interface), let R : int, let C : int> + [__unsafeForceInlineEarly] + matrix<T,R,C> operator$(op.name)=(in out matrix<T,R,C> left, T right) + { + left = left $(op.name) right; + return left; + } + + ${{{{ + } + }}}} + + // Specialized function __intrinsic_op diff --git a/source/slang/hlsl.meta.slang b/source/slang/hlsl.meta.slang index 2b556c10b..30c86b3eb 100644 --- a/source/slang/hlsl.meta.slang +++ b/source/slang/hlsl.meta.slang @@ -524,16 +524,19 @@ matrix<float,N,M> asfloat(matrix<uint,N,M> x) } // No op -__intrinsic_op($(kCompoundIntrinsicOp_Pos)) -float asfloat(float x); +[__unsafeForceInlineEarly] +float asfloat(float x) +{ return x; } __generic<let N : int> -__intrinsic_op($(kCompoundIntrinsicOp_Pos)) -vector<float,N> asfloat(vector<float,N> x); +[__unsafeForceInlineEarly] +vector<float,N> asfloat(vector<float,N> x) +{ return x; } __generic<let N : int, let M : int> -__intrinsic_op($(kCompoundIntrinsicOp_Pos)) -matrix<float,N,M> asfloat(matrix<float,N,M> x); +[__unsafeForceInlineEarly] +matrix<float,N,M> asfloat(matrix<float,N,M> x) +{ return x; } // Inverse sine (HLSL SM 1.0) __generic<T : __BuiltinFloatingPointType> @@ -599,16 +602,19 @@ matrix<int, N, M> asint(matrix<uint, N, M> x) } // No op -__intrinsic_op($(kCompoundIntrinsicOp_Pos)) -int asint(int x); +[__unsafeForceInlineEarly] +int asint(int x) +{ return x; } __generic<let N : int> -__intrinsic_op($(kCompoundIntrinsicOp_Pos)) -vector<int,N> asint(vector<int,N> x); +[__unsafeForceInlineEarly] +vector<int,N> asint(vector<int,N> x) +{ return x; } __generic<let N : int, let M : int> -__intrinsic_op($(kCompoundIntrinsicOp_Pos)) -matrix<int,N,M> asint(matrix<int,N,M> x); +[__unsafeForceInlineEarly] +matrix<int,N,M> asint(matrix<int,N,M> x) +{ return x; } // Reinterpret bits of double as a uint (HLSL SM 5.0) @@ -657,16 +663,19 @@ matrix<uint, N, M> asuint(matrix<int, N, M> x) MATRIX_MAP_UNARY(uint, N, M, asuint, x); } -__intrinsic_op($(kCompoundIntrinsicOp_Pos)) -uint asuint(uint x); +[__unsafeForceInlineEarly] +uint asuint(uint x) +{ return x; } __generic<let N : int> -__intrinsic_op($(kCompoundIntrinsicOp_Pos)) -vector<uint,N> asuint(vector<uint,N> x); +[__unsafeForceInlineEarly] +vector<uint,N> asuint(vector<uint,N> x) +{ return x; } __generic<let N : int, let M : int> -__intrinsic_op($(kCompoundIntrinsicOp_Pos)) -matrix<uint,N,M> asuint(matrix<uint,N,M> x); +[__unsafeForceInlineEarly] +matrix<uint,N,M> asuint(matrix<uint,N,M> x) +{ return x; } // Inverse tangent (HLSL SM 1.0) __generic<T : __BuiltinFloatingPointType> diff --git a/source/slang/slang-check-expr.cpp b/source/slang/slang-check-expr.cpp index adfc36641..fbe38bac7 100644 --- a/source/slang/slang-check-expr.cpp +++ b/source/slang/slang-check-expr.cpp @@ -359,6 +359,7 @@ namespace Slang } RefPtr<Expr> SemanticsVisitor::createLookupResultExpr( + Name* name, LookupResult const& lookupResult, RefPtr<Expr> baseExpr, SourceLoc loc) @@ -366,6 +367,7 @@ namespace Slang if (lookupResult.isOverloaded()) { auto overloadedExpr = new OverloadedExpr(); + overloadedExpr->name = name; overloadedExpr->loc = loc; overloadedExpr->type = QualType( getSession()->getOverloadedType()); @@ -960,10 +962,11 @@ namespace Slang // declarations on the type and try to call one of them. { + Name* name = getName("operator[]"); LookupResult lookupResult = lookUpMember( getSession(), this, - getName("operator[]"), + name, baseType); if (!lookupResult.isValid()) { @@ -977,7 +980,7 @@ namespace Slang // case the attempt to call it will trigger overload // resolution. RefPtr<Expr> subscriptFuncExpr = createLookupResultExpr( - lookupResult, subscriptExpr->BaseExpression, subscriptExpr->loc); + name, lookupResult, subscriptExpr->BaseExpression, subscriptExpr->loc); RefPtr<InvokeExpr> subscriptCallExpr = new InvokeExpr(); subscriptCallExpr->loc = subscriptExpr->loc; @@ -1181,6 +1184,7 @@ namespace Slang if (lookupResult.isValid()) { return createLookupResultExpr( + expr->name, lookupResult, nullptr, expr->loc); @@ -1531,6 +1535,7 @@ namespace Slang } return createLookupResultExpr( + expr->name, lookupResult, baseExpression, expr->loc); @@ -1638,6 +1643,7 @@ namespace Slang // to in this context... return createLookupResultExpr( + expr->name, lookupResult, expr->BaseExpression, expr->loc); diff --git a/source/slang/slang-check-impl.h b/source/slang/slang-check-impl.h index 8b32f8612..df0080ec1 100644 --- a/source/slang/slang-check-impl.h +++ b/source/slang/slang-check-impl.h @@ -356,6 +356,7 @@ namespace Slang SourceLoc loc); RefPtr<Expr> createLookupResultExpr( + Name* name, LookupResult const& lookupResult, RefPtr<Expr> baseExpr, SourceLoc loc); diff --git a/source/slang/slang-check-overload.cpp b/source/slang/slang-check-overload.cpp index 41aa94a35..92d390bf0 100644 --- a/source/slang/slang-check-overload.cpp +++ b/source/slang/slang-check-overload.cpp @@ -1261,9 +1261,9 @@ namespace Slang if (!first) sb << ", "; first = false; - formatType(sb, GetType(genericValParam)); - sb << " "; sb << getText(genericValParam.GetName()); + sb << ":"; + formatType(sb, GetType(genericValParam)); } else {} @@ -1279,14 +1279,24 @@ namespace Slang static void formatDeclKindPrefix(StringBuilder& sb, Decl* decl) { + if(auto genericDecl = as<GenericDecl>(decl)) + { + decl = genericDecl->inner; + } if(as<FuncDecl>(decl)) { sb << "func "; } } - void SemanticsVisitor::formatDeclResultType(StringBuilder& sb, DeclRef<Decl> const& declRef) + void SemanticsVisitor::formatDeclResultType(StringBuilder& sb, DeclRef<Decl> const& inDeclRef) { + DeclRef<Decl> declRef = inDeclRef; + if(auto genericDeclRef = declRef.as<GenericDecl>()) + { + declRef = DeclRef<Decl>(GetInner(genericDeclRef), genericDeclRef.substitutions); + } + if(as<ConstructorDecl>(declRef)) {} else if(auto callableDeclRef = declRef.as<CallableDecl>()) @@ -1434,10 +1444,19 @@ namespace Slang } Name* funcName = nullptr; - if (auto baseVar = as<VarExpr>(funcExpr)) - funcName = baseVar->name; - else if(auto baseMemberRef = as<MemberExpr>(funcExpr)) - funcName = baseMemberRef->name; + { + Expr* baseExpr = funcExpr; + + if(auto baseGenericApp = as<GenericAppExpr>(baseExpr)) + baseExpr = baseGenericApp->FunctionExpr; + + if (auto baseVar = as<VarExpr>(baseExpr)) + funcName = baseVar->name; + else if(auto baseMemberRef = as<MemberExpr>(baseExpr)) + funcName = baseMemberRef->name; + else if(auto baseOverloaded = as<OverloadedExpr>(baseExpr)) + funcName = baseOverloaded->name; + } String argsList = getCallSignatureString(context); diff --git a/source/slang/slang-compound-intrinsics.h b/source/slang/slang-compound-intrinsics.h deleted file mode 100644 index 682e7bc4a..000000000 --- a/source/slang/slang-compound-intrinsics.h +++ /dev/null @@ -1,80 +0,0 @@ -// slang-compound-intrinsics.h -#pragma once - -// Intrinsic functions in the Slang standard library are marked -// with the `__intrinsic_op(...)` modifier. Many of these map -// one-to-one to instruction opcodes in the Slang IR, and the -// argument to `__intrinsic_op(...)` is the IR instruction -// opcode in that case. -// -// In other cases, we have intrinsic operations like the `+=` or -// `&&` operator that either need to map to multiple IR instructions -// (or more generally, a number of instructions not equal to one), -// or otherwise have complications thake one-to-one lowering -// not possible. -// -// We refer to these as "compound" intrinsic ops, since the common -// case is that they represent a composition of multiple instructions. -// -// In order to not conflict with the opcodes of any IR instructions, -// these compound intrinsic ops will all be identified by *negative* -// integer opcodes. - -// We start by defining an "X-macro" that lists all the compound -// intrinsic ops we support. - -#define FOREACH_COMPOUND_INTRINSIC_OP(M) \ - M(Pos) \ - M(PreInc) \ - M(PreDec) \ - M(PostInc) \ - M(PostDec) \ - M(AddAssign) \ - M(SubAssign) \ - M(MulAssign) \ - M(DivAssign) \ - M(IRemAssign) \ - M(FRemAssign) \ - M(AndAssign) \ - M(OrAssign) \ - M(XorAssign ) \ - M(LshAssign) \ - M(RshAssign) \ - M(Assign) \ - M(And) \ - M(Or) \ - /* end */ - -// We will use a simple type alias to capture the fact that -// a 32-bit integer is sufficient to represent compound -// intrinsic ops (as negative values) plus IR opcode values -// for single-instruction intrinsics (as non-negative values) -// -typedef int32_t IntrinsicOp; - -// Next we use an enumeration declaration as an implementation -// detail, to associate each of the above cases with a (positive) -// integer. -// -enum class _CompoundIntrinsicOpVal : IntrinsicOp -{ -#define DECLARE_COMPOUND_INTRINSIC_OP_VAL(NAME) NAME, - FOREACH_COMPOUND_INTRINSIC_OP(DECLARE_COMPOUND_INTRINSIC_OP_VAL) -#undef DECLARE_COMPOUND_INTRINSIC_OP_VAL -}; - -// Finally, we define a second enumeration that takes the values -// from the first and performs a bitwise negation on them, which -// guarantees we get strictly negative values. - - /// Compound/complex intrinsic operations, which do not map to a single IR instruction. - /// - /// All of the values of this enumeration are guaranteed to be negative, and thus - /// cannot conflict with any valid value of type `IROp` - /// -enum CompoundIntrinsicOp : IntrinsicOp -{ -#define DECLARE_COMPOUND_INTRINSIC_OP(NAME) kCompoundIntrinsicOp_##NAME = ~IntrinsicOp(_CompoundIntrinsicOpVal::NAME), - FOREACH_COMPOUND_INTRINSIC_OP(DECLARE_COMPOUND_INTRINSIC_OP) -#undef DECLARE_COMPOUND_INTRINSIC_OP -}; diff --git a/source/slang/slang-diagnostic-defs.h b/source/slang/slang-diagnostic-defs.h index ff64b023c..2fbd373cc 100644 --- a/source/slang/slang-diagnostic-defs.h +++ b/source/slang/slang-diagnostic-defs.h @@ -329,7 +329,7 @@ DIAGNOSTIC(39999, Error, expectedIntegerConstantNotLiteral, "could not extract v DIAGNOSTIC(39999, Error, noApplicableOverloadForNameWithArgs, "no overload for '$0' applicable to arguments of type $1") DIAGNOSTIC(39999, Error, noApplicableWithArgs, "no overload applicable to arguments of type $0") -DIAGNOSTIC(39999, Error, ambiguousOverloadForNameWithArgs, "ambiguous call to '$0' operation with arguments of type $1") +DIAGNOSTIC(39999, Error, ambiguousOverloadForNameWithArgs, "ambiguous call to '$0' with arguments of type $1") DIAGNOSTIC(39999, Error, ambiguousOverloadWithArgs, "ambiguous call to overloaded operation with arguments of type $0") DIAGNOSTIC(39999, Note, overloadCandidate, "candidate: $0") diff --git a/source/slang/slang-expr-defs.h b/source/slang/slang-expr-defs.h index a7105b07b..725bbb62d 100644 --- a/source/slang/slang-expr-defs.h +++ b/source/slang/slang-expr-defs.h @@ -21,6 +21,8 @@ SIMPLE_SYNTAX_CLASS(VarExpr, DeclRefExpr) // An expression that references an overloaded set of declarations // having the same name. SYNTAX_CLASS(OverloadedExpr, Expr) + // The name that was looked up and found to be overloaded + FIELD(Name*, name) // Optional: the base expression is this overloaded result // arose from a member-reference expression. diff --git a/source/slang/slang-lower-to-ir.cpp b/source/slang/slang-lower-to-ir.cpp index f57e15bc4..029fe23f6 100644 --- a/source/slang/slang-lower-to-ir.cpp +++ b/source/slang/slang-lower-to-ir.cpp @@ -5,7 +5,6 @@ #include "slang-check.h" #include "slang-ir.h" -#include "slang-compound-intrinsics.h" #include "slang-ir-constexpr.h" #include "slang-ir-dce.h" #include "slang-ir-inline.h" @@ -475,7 +474,8 @@ bool isImportedDecl(IRGenContext* context, Decl* decl) return false; } -static bool isInline(Decl* decl) + /// Is `decl` a function that should be force-inlined early in compilation (before linking)? +static bool isForceInlineEarly(Decl* decl) { if(decl->HasModifier<UnsafeForceInlineEarlyAttribute>()) return true; @@ -542,113 +542,6 @@ LoweredValInfo emitCallToVal( } } -LoweredValInfo emitCompoundAssignOp( - IRGenContext* context, - IRType* type, - IROp op, - UInt argCount, - IRInst* const* args) -{ - auto builder = context->irBuilder; - SLANG_UNREFERENCED_PARAMETER(argCount); - SLANG_ASSERT(argCount == 2); - auto leftPtr = args[0]; - auto rightVal = args[1]; - - auto leftVal = builder->emitLoad(leftPtr); - - IRInst* innerArgs[] = { leftVal, rightVal }; - auto innerOp = builder->emitIntrinsicInst(type, op, 2, innerArgs); - - builder->emitStore(leftPtr, innerOp); - - return LoweredValInfo::ptr(leftPtr); -} - -IRInst* getOneValOfType( - IRGenContext* context, - IRType* type) -{ - switch(type->op) - { - case kIROp_IntType: - case kIROp_UIntType: - case kIROp_UInt64Type: - return context->irBuilder->getIntValue(type, 1); - - case kIROp_HalfType: - case kIROp_FloatType: - case kIROp_DoubleType: - return context->irBuilder->getFloatValue(type, 1.0); - - default: - break; - } - - // TODO: should make sure to handle vector and matrix types here - - SLANG_UNEXPECTED("inc/dec type"); - UNREACHABLE_RETURN(nullptr); -} - -LoweredValInfo emitPrefixIncDecOp( - IRGenContext* context, - IRType* type, - IROp op, - UInt argCount, - IRInst* const* args) -{ - auto builder = context->irBuilder; - SLANG_UNREFERENCED_PARAMETER(argCount); - SLANG_ASSERT(argCount == 1); - auto argPtr = args[0]; - - auto preVal = builder->emitLoad(argPtr); - - IRInst* oneVal = getOneValOfType(context, type); - - IRInst* innerArgs[] = { preVal, oneVal }; - auto innerOp = builder->emitIntrinsicInst(type, op, 2, innerArgs); - - builder->emitStore(argPtr, innerOp); - - // For a prefix operator like `++i` we return - // the value after the increment/decrement has - // been applied. In casual terms we "increment - // the varaible, then return its value." - // - return LoweredValInfo::simple(innerOp); -} - -LoweredValInfo emitPostfixIncDecOp( - IRGenContext* context, - IRType* type, - IROp op, - UInt argCount, - IRInst* const* args) -{ - auto builder = context->irBuilder; - SLANG_UNREFERENCED_PARAMETER(argCount); - SLANG_ASSERT(argCount == 1); - auto argPtr = args[0]; - - auto preVal = builder->emitLoad(argPtr); - - IRInst* oneVal = getOneValOfType(context, type); - - IRInst* innerArgs[] = { preVal, oneVal }; - auto innerOp = builder->emitIntrinsicInst(type, op, 2, innerArgs); - - builder->emitStore(argPtr, innerOp); - - // For a postfix operator like `i++` we return - // the value that we read before the increment/decrement - // gets applied. In casual terms we "read - // the variable, then increment it." - // - return LoweredValInfo::simple(preVal); -} - LoweredValInfo lowerRValueExpr( IRGenContext* context, Expr* expr); @@ -739,67 +632,16 @@ LoweredValInfo emitCallToDeclRef( auto funcDecl = funcDeclRef.getDecl(); if(auto intrinsicOpModifier = funcDecl->FindModifier<IntrinsicOpModifier>()) { - // An intrinsic op either maps to a single IR instruction - // (in the case where the opcode value is >= 0), or to - // a `CompountIntrinsicOp` (in the case where it is < 0). + // The intrinsic op maps to a single IR instruction, + // so we will emit an instruction with the chosen + // opcode, and the arguments to the call as its operands. // auto intrinsicOp = getIntrinsicOp(funcDecl, intrinsicOpModifier); - if(intrinsicOp < 0) - { - // We have a compound op, which requires special-case - // handling to generate zero or more IR instructions. - // - auto compoundOp = CompoundIntrinsicOp(intrinsicOp); - switch (compoundOp) - { - case kCompoundIntrinsicOp_Pos: - return LoweredValInfo::simple(args[0]); - -#define CASE(COMPOUND, OP) \ - case COMPOUND: return emitCompoundAssignOp(context, type, OP, argCount, args) - - CASE(kCompoundIntrinsicOp_AddAssign, kIROp_Add); - CASE(kCompoundIntrinsicOp_SubAssign, kIROp_Sub); - CASE(kCompoundIntrinsicOp_MulAssign, kIROp_Mul); - CASE(kCompoundIntrinsicOp_DivAssign, kIROp_Div); - CASE(kCompoundIntrinsicOp_IRemAssign,kIROp_IRem); - CASE(kCompoundIntrinsicOp_FRemAssign,kIROp_FRem); - CASE(kCompoundIntrinsicOp_AndAssign, kIROp_BitAnd); - CASE(kCompoundIntrinsicOp_OrAssign, kIROp_BitOr); - CASE(kCompoundIntrinsicOp_XorAssign, kIROp_BitXor); - CASE(kCompoundIntrinsicOp_LshAssign, kIROp_Lsh); - CASE(kCompoundIntrinsicOp_RshAssign, kIROp_Rsh); - -#undef CASE - -#define CASE(COMPOUND, OP) \ - case COMPOUND: return emitPrefixIncDecOp(context, type, OP, argCount, args) - CASE(kCompoundIntrinsicOp_PreInc, kIROp_Add); - CASE(kCompoundIntrinsicOp_PreDec, kIROp_Sub); -#undef CASE - -#define CASE(COMPOUND, OP) \ - case COMPOUND: return emitPostfixIncDecOp(context, type, OP, argCount, args) - CASE(kCompoundIntrinsicOp_PostInc, kIROp_Add); - CASE(kCompoundIntrinsicOp_PostDec, kIROp_Sub); -#undef CASE - default: - SLANG_UNIMPLEMENTED_X("IR pseudo-op"); - UNREACHABLE_RETURN(LoweredValInfo()); - } - } - else - { - // The intrinsic op maps to a single IR instruction, - // so we will emit an instruction with the chosen - // opcode, and the arguments to the call as its operands. - // - return LoweredValInfo::simple(builder->emitIntrinsicInst( - type, - IROp(intrinsicOp), - argCount, - args)); - } + return LoweredValInfo::simple(builder->emitIntrinsicInst( + type, + IROp(intrinsicOp), + argCount, + args)); } if( auto ctorDeclRef = funcDeclRef.as<ConstructorDecl>() ) @@ -5184,7 +5026,7 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> if(auto initExpr = decl->initExpr) { auto initVal = lowerRValueExpr(context, initExpr); - initVal = materialize(context, initVal); + initVal = LoweredValInfo::simple(getSimpleVal(context, initVal)); setGlobalValue(context, decl, initVal); return initVal; } @@ -6042,7 +5884,22 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> subBuilder->setInsertInto(irFunc); - if (isImportedDecl(decl) && !isInline(decl)) + // If a function is imported from another module then + // we usually don't want to emit it as a definition, and + // will instead only emit a declaration for it with an + // appropriate `[import(...)]` linkage decoration. + // + // However, if the function is marked with `[__unsafeForceInlineEarly]` + // then we need to make sure the IR for its definition is available + // to the mandatory optimization passes. + // + // TODO: The design here means that we will re-emit the inline + // function from its AST in every module that uses it. We should + // instead have logic to clone the target function in from the + // pre-generated IR for the module that defines it (or do some kind + // of minimal linking to bring in the inline functions). + // + if (isImportedDecl(decl) && !isForceInlineEarly(decl)) { // Always emit imported declarations as declarations, // and not definitions. diff --git a/source/slang/slang-mangle.cpp b/source/slang/slang-mangle.cpp index dfb55404e..2ad84d3d3 100644 --- a/source/slang/slang-mangle.cpp +++ b/source/slang/slang-mangle.cpp @@ -273,6 +273,14 @@ namespace Slang if (declRef.is<RefAccessorDecl>()) emitRaw(context, "Ar"); } + // Special case: need a way to tell prefix and postfix unary + // operators apart. + { + if(declRef.getDecl()->HasModifier<PostfixModifier>()) emitRaw(context, "P"); + if(declRef.getDecl()->HasModifier<PrefixModifier>()) emitRaw(context, "p"); + } + + // Are we the "inner" declaration beneath a generic decl? if(parentGenericDeclRef && (parentGenericDeclRef.getDecl()->inner.Ptr() == declRef.getDecl())) { diff --git a/source/slang/slang-modifier-defs.h b/source/slang/slang-modifier-defs.h index 58f2c5af9..7ea1d0101 100644 --- a/source/slang/slang-modifier-defs.h +++ b/source/slang/slang-modifier-defs.h @@ -36,17 +36,9 @@ SYNTAX_CLASS(IntrinsicOpModifier, Modifier) // Token that names the intrinsic op. FIELD(Token, opToken) - // The opcode for the intrinsic operation. + // The IR opcode for the intrinsic operation. // - // If greather than or equal to zero, then `op` - // is an `IROp` and directly identifies an IR - // instruction that the intrinsic should translate to. - // - // If less than zero, then `op` is a `CompoundIntrinsicOp` - // which maps to zero or more IR instructions using - // special-case logic in the IR lowering phase. - // - FIELD_INIT(IntrinsicOp, op, 0) + FIELD_INIT(uint32_t, op, 0) END_SYNTAX_CLASS() // A modifier that marks something as an intrinsic function, diff --git a/source/slang/slang-stdlib.cpp b/source/slang/slang-stdlib.cpp index b23d1970b..1f59b1686 100644 --- a/source/slang/slang-stdlib.cpp +++ b/source/slang/slang-stdlib.cpp @@ -1,7 +1,6 @@ // slang-stdlib.cpp #include "slang-compiler.h" -#include "slang-compound-intrinsics.h" #include "slang-ir.h" #include "slang-syntax.h" @@ -50,8 +49,6 @@ namespace Slang BOOL_RESULT = 1 << 2, BOOL_MASK = 1 << 3, UINT_MASK = 1 << 4, - ASSIGNMENT = 1 << 5, - POSTFIX = 1 << 6, INT_MASK = SINT_MASK | UINT_MASK, ARITHMETIC_MASK = INT_MASK | FLOAT_MASK, @@ -199,20 +196,15 @@ namespace Slang } } - struct OpInfo { IntrinsicOp opCode; char const* opName; char const* interface; unsigned flags; }; + struct IntrinsicOpInfo { IROp opCode; char const* opName; char const* interface; unsigned flags; }; - static const OpInfo unaryOps[] = { - { kCompoundIntrinsicOp_Pos, "+", "__BuiltinArithmeticType", ARITHMETIC_MASK }, + static const IntrinsicOpInfo intrinsicUnaryOps[] = { { kIROp_Neg, "-", "__BuiltinArithmeticType", ARITHMETIC_MASK }, { kIROp_Not, "!", nullptr, BOOL_MASK | BOOL_RESULT }, { kIROp_BitNot, "~", "__BuiltinIntegerType", INT_MASK }, - { kCompoundIntrinsicOp_PreInc, "++", "__BuiltinArithmeticType", ARITHMETIC_MASK | ASSIGNMENT }, - { kCompoundIntrinsicOp_PreDec, "--", "__BuiltinArithmeticType", ARITHMETIC_MASK | ASSIGNMENT }, - { kCompoundIntrinsicOp_PostInc, "++", "__BuiltinArithmeticType", ARITHMETIC_MASK | ASSIGNMENT | POSTFIX }, - { kCompoundIntrinsicOp_PostDec, "--", "__BuiltinArithmeticType", ARITHMETIC_MASK | ASSIGNMENT | POSTFIX }, }; - static const OpInfo binaryOps[] = { + static const IntrinsicOpInfo intrinsicBinaryOps[] = { { kIROp_Add, "+", "__BuiltinArithmeticType", ARITHMETIC_MASK }, { kIROp_Sub, "-", "__BuiltinArithmeticType", ARITHMETIC_MASK }, { kIROp_Mul, "*", "__BuiltinArithmeticType", ARITHMETIC_MASK }, @@ -232,17 +224,6 @@ namespace Slang { kIROp_Less, "<", "__BuiltinArithmeticType", ARITHMETIC_MASK | BOOL_RESULT }, { kIROp_Geq, ">=", "__BuiltinArithmeticType", ARITHMETIC_MASK | BOOL_RESULT }, { kIROp_Leq, "<=", "__BuiltinArithmeticType", ARITHMETIC_MASK | BOOL_RESULT }, - { kCompoundIntrinsicOp_AddAssign, "+=", "__BuiltinArithmeticType", ASSIGNMENT | ARITHMETIC_MASK }, - { kCompoundIntrinsicOp_SubAssign, "-=", "__BuiltinArithmeticType", ASSIGNMENT | ARITHMETIC_MASK }, - { kCompoundIntrinsicOp_MulAssign, "*=", "__BuiltinArithmeticType", ASSIGNMENT | ARITHMETIC_MASK }, - { kCompoundIntrinsicOp_DivAssign, "/=", "__BuiltinArithmeticType", ASSIGNMENT | ARITHMETIC_MASK }, - { kCompoundIntrinsicOp_IRemAssign, "%=", "__BuiltinIntegerType", ASSIGNMENT | INT_MASK }, - { kCompoundIntrinsicOp_FRemAssign, "%=", "__BuiltinFloatingPointType", ASSIGNMENT | FLOAT_MASK }, - { kCompoundIntrinsicOp_AndAssign, "&=", "__BuiltinLogicalType", ASSIGNMENT | LOGICAL_MASK }, - { kCompoundIntrinsicOp_OrAssign, "|=", "__BuiltinLogicalType", ASSIGNMENT | LOGICAL_MASK }, - { kCompoundIntrinsicOp_XorAssign, "^=", "__BuiltinLogicalType", ASSIGNMENT | LOGICAL_MASK }, - { kCompoundIntrinsicOp_LshAssign, "<<=", "__BuiltinIntegerType", ASSIGNMENT | INT_MASK }, - { kCompoundIntrinsicOp_RshAssign, ">>=", "__BuiltinIntegerType", ASSIGNMENT | INT_MASK }, }; String Session::getCoreLibraryCode() diff --git a/source/slang/slang-syntax.h b/source/slang/slang-syntax.h index 9c3945b4d..61219ecd2 100644 --- a/source/slang/slang-syntax.h +++ b/source/slang/slang-syntax.h @@ -2,7 +2,6 @@ #define SLANG_SYNTAX_H #include "../core/slang-basic.h" -#include "slang-compound-intrinsics.h" #include "slang-lexer.h" #include "slang-profile.h" #include "slang-type-system-shared.h" diff --git a/source/slang/slang.vcxproj b/source/slang/slang.vcxproj index 0d702d9f5..027c43a95 100644 --- a/source/slang/slang.vcxproj +++ b/source/slang/slang.vcxproj @@ -193,7 +193,6 @@ <ClInclude Include="slang-check-impl.h" /> <ClInclude Include="slang-check.h" /> <ClInclude Include="slang-compiler.h" /> - <ClInclude Include="slang-compound-intrinsics.h" /> <ClInclude Include="slang-decl-defs.h" /> <ClInclude Include="slang-diagnostic-defs.h" /> <ClInclude Include="slang-diagnostics.h" /> diff --git a/source/slang/slang.vcxproj.filters b/source/slang/slang.vcxproj.filters index a73a74756..9be567654 100644 --- a/source/slang/slang.vcxproj.filters +++ b/source/slang/slang.vcxproj.filters @@ -30,9 +30,6 @@ <ClInclude Include="slang-compiler.h"> <Filter>Header Files</Filter> </ClInclude> - <ClInclude Include="slang-compound-intrinsics.h"> - <Filter>Header Files</Filter> - </ClInclude> <ClInclude Include="slang-decl-defs.h"> <Filter>Header Files</Filter> </ClInclude> |
