diff options
Diffstat (limited to 'source')
| -rw-r--r-- | source/slang/core.meta.slang | 14 | ||||
| -rw-r--r-- | source/slang/core.meta.slang.h | 25 | ||||
| -rw-r--r-- | source/slang/hlsl.meta.slang | 20 | ||||
| -rw-r--r-- | source/slang/hlsl.meta.slang.h | 20 | ||||
| -rw-r--r-- | source/slang/slang-check-impl.h | 2 | ||||
| -rw-r--r-- | source/slang/slang-compound-intrinsics.h | 81 | ||||
| -rw-r--r-- | source/slang/slang-ir-inst-defs.h | 28 | ||||
| -rw-r--r-- | source/slang/slang-ir-serialize.cpp | 7 | ||||
| -rw-r--r-- | source/slang/slang-ir.cpp | 30 | ||||
| -rw-r--r-- | source/slang/slang-ir.h | 39 | ||||
| -rw-r--r-- | source/slang/slang-lower-to-ir.cpp | 83 | ||||
| -rw-r--r-- | source/slang/slang-modifier-defs.h | 15 | ||||
| -rw-r--r-- | source/slang/slang-stdlib.cpp | 35 | ||||
| -rw-r--r-- | source/slang/slang-syntax.h | 2 | ||||
| -rw-r--r-- | source/slang/slang.vcxproj | 5 | ||||
| -rw-r--r-- | source/slang/slang.vcxproj.filters | 3 |
16 files changed, 234 insertions, 175 deletions
diff --git a/source/slang/core.meta.slang b/source/slang/core.meta.slang index 763bd4a78..7785239a2 100644 --- a/source/slang/core.meta.slang +++ b/source/slang/core.meta.slang @@ -58,8 +58,16 @@ interface __FlagsEnumType : __EnumType { }; -__generic<T,U> __intrinsic_op(Sequence) U operator,(T left, U right); +// The "comma operator" is effectively just a generic function that returns its second +// argument. The left-to-right evaluation order guaranteed by Slang then ensures that +// `left` is evaluated before `right`. +// +__generic<T,U> __intrinsic_op($(kCompoundIntrinsicOp_Sequence)) U operator,(T left, U right); +// The ternary `?:` operator does not short-circuit in HLSL, and Slang continues to +// follow that definition, so that this operator is effectively just an ordinary +// function, rather than a special-case piece of syntax. +// __generic<T> __intrinsic_op(select) T operator?:(bool condition, T ifTrue, T ifFalse); __generic<T, let N : int> __intrinsic_op(select) vector<T,N> operator?:(vector<bool,N> condition, vector<T,N> ifTrue, vector<T,N> ifFalse); @@ -956,7 +964,6 @@ for (int tt = 0; tt < kBaseTextureTypeCount; ++tt) sb << "__target_intrinsic(glsl, \"$ctextureGrad($p, $2, $3, $4)$z\")\n"; -// sb << "__intrinsic_op(sampleGrad)\n"; sb << "T SampleGrad(SamplerState s, "; sb << "float" << kBaseTextureTypes[tt].coordCount + isArray << " location, "; sb << "float" << kBaseTextureTypes[tt].coordCount << " gradX, "; @@ -966,7 +973,6 @@ for (int tt = 0; tt < kBaseTextureTypeCount; ++tt) if( baseShape != TextureFlavor::Shape::ShapeCube ) { sb << "__target_intrinsic(glsl, \"$ctextureGradOffset($p, $2, $3, $4, $5)$z\")\n"; -// sb << "__intrinsic_op(sampleGrad)\n"; sb << "T SampleGrad(SamplerState s, "; sb << "float" << kBaseTextureTypes[tt].coordCount + isArray << " location, "; sb << "float" << kBaseTextureTypes[tt].coordCount << " gradX, "; @@ -1158,7 +1164,7 @@ for (auto op : binaryOps) switch (op.opCode) { case kIROp_Mul: - case kIRPseudoOp_MulAssign: + case kCompoundIntrinsicOp_MulAssign: break; default: diff --git a/source/slang/core.meta.slang.h b/source/slang/core.meta.slang.h index 7cb729722..c681a5f6b 100644 --- a/source/slang/core.meta.slang.h +++ b/source/slang/core.meta.slang.h @@ -58,8 +58,19 @@ SLANG_RAW("interface __FlagsEnumType : __EnumType\n") SLANG_RAW("{\n") SLANG_RAW("};\n") SLANG_RAW("\n") -SLANG_RAW("__generic<T,U> __intrinsic_op(Sequence) U operator,(T left, U right);\n") +SLANG_RAW("// The \"comma operator\" is effectively just a generic function that returns its second\n") +SLANG_RAW("// argument. The left-to-right evaluation order guaranteed by Slang then ensures that\n") +SLANG_RAW("// `left` is evaluated before `right`.\n") +SLANG_RAW("//\n") +SLANG_RAW("__generic<T,U> __intrinsic_op(") +SLANG_SPLICE(kCompoundIntrinsicOp_Sequence +) +SLANG_RAW(") U operator,(T left, U right);\n") SLANG_RAW("\n") +SLANG_RAW("// The ternary `?:` operator does not short-circuit in HLSL, and Slang continues to\n") +SLANG_RAW("// follow that definition, so that this operator is effectively just an ordinary\n") +SLANG_RAW("// function, rather than a special-case piece of syntax.\n") +SLANG_RAW("//\n") SLANG_RAW("__generic<T> __intrinsic_op(select) T operator?:(bool condition, T ifTrue, T ifFalse);\n") SLANG_RAW("__generic<T, let N : int> __intrinsic_op(select) vector<T,N> operator?:(vector<bool,N> condition, vector<T,N> ifTrue, vector<T,N> ifFalse);\n") SLANG_RAW("\n") @@ -142,7 +153,7 @@ for (int tt = 0; tt < kBaseTypeCount; ++tt) // TODO: should this cover the full gamut of integer types? case BaseType::Int: case BaseType::UInt: -SLANG_RAW("#line 145 \"core.meta.slang\"") +SLANG_RAW("#line 153 \"core.meta.slang\"") SLANG_RAW("\n") SLANG_RAW(" __generic<T:__EnumType>\n") SLANG_RAW(" __init(T value);\n") @@ -158,7 +169,7 @@ SLANG_RAW(" __init(T value);\n") // Declare built-in pointer type // (eventually we can have the traditional syntax sugar for this) -SLANG_RAW("#line 160 \"core.meta.slang\"") +SLANG_RAW("#line 168 \"core.meta.slang\"") SLANG_RAW("\n") SLANG_RAW("\n") SLANG_RAW("__generic<T>\n") @@ -220,7 +231,7 @@ sb << " __init(T value);\n"; sb << " __init(vector<T,N> value);\n"; sb << "};\n"; -SLANG_RAW("#line 206 \"core.meta.slang\"") +SLANG_RAW("#line 214 \"core.meta.slang\"") SLANG_RAW("\n") SLANG_RAW("\n") SLANG_RAW("__generic<T = float, let R : int = 4, let C : int = 4>\n") @@ -974,7 +985,6 @@ for (int tt = 0; tt < kBaseTextureTypeCount; ++tt) sb << "__target_intrinsic(glsl, \"$ctextureGrad($p, $2, $3, $4)$z\")\n"; -// sb << "__intrinsic_op(sampleGrad)\n"; sb << "T SampleGrad(SamplerState s, "; sb << "float" << kBaseTextureTypes[tt].coordCount + isArray << " location, "; sb << "float" << kBaseTextureTypes[tt].coordCount << " gradX, "; @@ -984,7 +994,6 @@ for (int tt = 0; tt < kBaseTextureTypeCount; ++tt) if( baseShape != TextureFlavor::Shape::ShapeCube ) { sb << "__target_intrinsic(glsl, \"$ctextureGradOffset($p, $2, $3, $4, $5)$z\")\n"; -// sb << "__intrinsic_op(sampleGrad)\n"; sb << "T SampleGrad(SamplerState s, "; sb << "float" << kBaseTextureTypes[tt].coordCount + isArray << " location, "; sb << "float" << kBaseTextureTypes[tt].coordCount << " gradX, "; @@ -1176,7 +1185,7 @@ for (auto op : binaryOps) switch (op.opCode) { case kIROp_Mul: - case kIRPseudoOp_MulAssign: + case kCompoundIntrinsicOp_MulAssign: break; default: @@ -1207,7 +1216,7 @@ for (auto op : binaryOps) sb << "__intrinsic_op(" << int(op.opCode) << ") matrix<" << resultType << ",N,M> operator" << op.opName << "(" << leftQual << "matrix<" << leftType << ",N,M> left, " << rightType << " right);\n"; } } -SLANG_RAW("#line 1192 \"core.meta.slang\"") +SLANG_RAW("#line 1198 \"core.meta.slang\"") SLANG_RAW("\n") SLANG_RAW("\n") SLANG_RAW("// Operators to apply to `enum` types\n") diff --git a/source/slang/hlsl.meta.slang b/source/slang/hlsl.meta.slang index 986152e92..7c88e530f 100644 --- a/source/slang/hlsl.meta.slang +++ b/source/slang/hlsl.meta.slang @@ -393,13 +393,13 @@ __target_intrinsic(glsl, "uintBitsToFloat") vector<float,N> asfloat(vector<uint,N> x); // No op -__intrinsic_op($(kIRPseudoOp_Pos)) +__intrinsic_op($(kCompoundIntrinsicOp_Pos)) float asfloat(float x); __generic<let N : int> -__intrinsic_op($(kIRPseudoOp_Pos)) +__intrinsic_op($(kCompoundIntrinsicOp_Pos)) vector<float,N> asfloat(vector<float,N> x); __generic<let N : int, let M : int> -__intrinsic_op($(kIRPseudoOp_Pos)) +__intrinsic_op($(kCompoundIntrinsicOp_Pos)) matrix<float,N,M> asfloat(matrix<float,N,M> x); // Pass thru to HLSL @@ -430,13 +430,13 @@ __target_intrinsic(glsl, "ivec$N0($0)") vector<int,N> asint(vector<uint,N> x); // No op -__intrinsic_op($(kIRPseudoOp_Pos)) +__intrinsic_op($(kCompoundIntrinsicOp_Pos)) int asint(int x); __generic<let N : int> -__intrinsic_op($(kIRPseudoOp_Pos)) +__intrinsic_op($(kCompoundIntrinsicOp_Pos)) vector<int,N> asint(vector<int,N> x); __generic<let N : int, let M : int> -__intrinsic_op($(kIRPseudoOp_Pos)) +__intrinsic_op($(kCompoundIntrinsicOp_Pos)) matrix<int,N,M> asint(matrix<int,N,M> x); // Pass thru HLSL @@ -473,13 +473,13 @@ __target_intrinsic(glsl, "uvec$N0($0)") vector<uint,N> asuint(vector<int,N> x); // No op -__intrinsic_op($(kIRPseudoOp_Pos)) +__intrinsic_op($(kCompoundIntrinsicOp_Pos)) uint asuint(uint x); __generic<let N : int> -__intrinsic_op($(kIRPseudoOp_Pos)) +__intrinsic_op($(kCompoundIntrinsicOp_Pos)) vector<uint,N> asuint(vector<uint,N> x); __generic<let N : int, let M : int> -__intrinsic_op($(kIRPseudoOp_Pos)) +__intrinsic_op($(kCompoundIntrinsicOp_Pos)) matrix<uint,N,M> asuint(matrix<uint,N,M> x); // Pass thru HLSL @@ -1431,7 +1431,7 @@ for(auto op : binaryOps) continue; case kIROp_Mul: - case kIRPseudoOp_MulAssign: + case kCompoundIntrinsicOp_MulAssign: break; } diff --git a/source/slang/hlsl.meta.slang.h b/source/slang/hlsl.meta.slang.h index 95e07658f..db0fc2285 100644 --- a/source/slang/hlsl.meta.slang.h +++ b/source/slang/hlsl.meta.slang.h @@ -443,19 +443,19 @@ SLANG_RAW("vector<float,N> asfloat(vector<uint,N> x);\n") SLANG_RAW("\n") SLANG_RAW("// No op\n") SLANG_RAW("__intrinsic_op(") -SLANG_SPLICE(kIRPseudoOp_Pos +SLANG_SPLICE(kCompoundIntrinsicOp_Pos ) SLANG_RAW(")\n") SLANG_RAW("float asfloat(float x);\n") SLANG_RAW("__generic<let N : int>\n") SLANG_RAW("__intrinsic_op(") -SLANG_SPLICE(kIRPseudoOp_Pos +SLANG_SPLICE(kCompoundIntrinsicOp_Pos ) SLANG_RAW(")\n") SLANG_RAW("vector<float,N> asfloat(vector<float,N> x);\n") SLANG_RAW("__generic<let N : int, let M : int>\n") SLANG_RAW("__intrinsic_op(") -SLANG_SPLICE(kIRPseudoOp_Pos +SLANG_SPLICE(kCompoundIntrinsicOp_Pos ) SLANG_RAW(")\n") SLANG_RAW("matrix<float,N,M> asfloat(matrix<float,N,M> x);\n") @@ -489,19 +489,19 @@ SLANG_RAW("vector<int,N> asint(vector<uint,N> x);\n") SLANG_RAW("\n") SLANG_RAW("// No op\n") SLANG_RAW("__intrinsic_op(") -SLANG_SPLICE(kIRPseudoOp_Pos +SLANG_SPLICE(kCompoundIntrinsicOp_Pos ) SLANG_RAW(")\n") SLANG_RAW("int asint(int x);\n") SLANG_RAW("__generic<let N : int>\n") SLANG_RAW("__intrinsic_op(") -SLANG_SPLICE(kIRPseudoOp_Pos +SLANG_SPLICE(kCompoundIntrinsicOp_Pos ) SLANG_RAW(")\n") SLANG_RAW("vector<int,N> asint(vector<int,N> x);\n") SLANG_RAW("__generic<let N : int, let M : int>\n") SLANG_RAW("__intrinsic_op(") -SLANG_SPLICE(kIRPseudoOp_Pos +SLANG_SPLICE(kCompoundIntrinsicOp_Pos ) SLANG_RAW(")\n") SLANG_RAW("matrix<int,N,M> asint(matrix<int,N,M> x);\n") @@ -541,19 +541,19 @@ SLANG_RAW("vector<uint,N> asuint(vector<int,N> x);\n") SLANG_RAW("\n") SLANG_RAW("// No op\n") SLANG_RAW("__intrinsic_op(") -SLANG_SPLICE(kIRPseudoOp_Pos +SLANG_SPLICE(kCompoundIntrinsicOp_Pos ) SLANG_RAW(")\n") SLANG_RAW("uint asuint(uint x);\n") SLANG_RAW("__generic<let N : int>\n") SLANG_RAW("__intrinsic_op(") -SLANG_SPLICE(kIRPseudoOp_Pos +SLANG_SPLICE(kCompoundIntrinsicOp_Pos ) SLANG_RAW(")\n") SLANG_RAW("vector<uint,N> asuint(vector<uint,N> x);\n") SLANG_RAW("__generic<let N : int, let M : int>\n") SLANG_RAW("__intrinsic_op(") -SLANG_SPLICE(kIRPseudoOp_Pos +SLANG_SPLICE(kCompoundIntrinsicOp_Pos ) SLANG_RAW(")\n") SLANG_RAW("matrix<uint,N,M> asuint(matrix<uint,N,M> x);\n") @@ -1507,7 +1507,7 @@ for(auto op : binaryOps) continue; case kIROp_Mul: - case kIRPseudoOp_MulAssign: + case kCompoundIntrinsicOp_MulAssign: break; } diff --git a/source/slang/slang-check-impl.h b/source/slang/slang-check-impl.h index 7027c4671..f026f0ed1 100644 --- a/source/slang/slang-check-impl.h +++ b/source/slang/slang-check-impl.h @@ -80,7 +80,7 @@ namespace Slang struct OperatorOverloadCacheKey { - IROp operatorName; + intptr_t operatorName; BasicTypeKey args[2]; bool operator == (OperatorOverloadCacheKey key) { diff --git a/source/slang/slang-compound-intrinsics.h b/source/slang/slang-compound-intrinsics.h new file mode 100644 index 000000000..4a0b1a109 --- /dev/null +++ b/source/slang/slang-compound-intrinsics.h @@ -0,0 +1,81 @@ +// 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(Sequence) \ + 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-ir-inst-defs.h b/source/slang/slang-ir-inst-defs.h index 00ac21e70..4caa8acf0 100644 --- a/source/slang/slang-ir-inst-defs.h +++ b/source/slang/slang-ir-inst-defs.h @@ -8,10 +8,6 @@ #define INST_RANGE(BASE, FIRST, LAST) /* empty */ #endif -#ifndef PSEUDO_INST -#define PSEUDO_INST(ID) /* empty */ -#endif - #define PARENT kIROpFlag_Parent #define USE_OTHER kIROpFlag_UseOther @@ -516,30 +512,6 @@ INST_RANGE(Layout, VarLayout, EntryPointLayout) INST_RANGE(LayoutResourceInfoAttr, TypeSizeAttr, VarOffsetAttr) INST_RANGE(Attr, PendingLayoutAttr, VarOffsetAttr) -PSEUDO_INST(Pos) -PSEUDO_INST(PreInc) - -PSEUDO_INST(PreDec) -PSEUDO_INST(PostInc) -PSEUDO_INST(PostDec) -PSEUDO_INST(Sequence) -PSEUDO_INST(AddAssign) -PSEUDO_INST(SubAssign) -PSEUDO_INST(MulAssign) -PSEUDO_INST(DivAssign) -PSEUDO_INST(IRemAssign) -PSEUDO_INST(FRemAssign) -PSEUDO_INST(AndAssign) -PSEUDO_INST(OrAssign) -PSEUDO_INST(XorAssign ) -PSEUDO_INST(LshAssign) -PSEUDO_INST(RshAssign) -PSEUDO_INST(Assign) -PSEUDO_INST(And) -PSEUDO_INST(Or) - - -#undef PSEUDO_INST #undef PARENT #undef USE_OTHER #undef INST_RANGE diff --git a/source/slang/slang-ir-serialize.cpp b/source/slang/slang-ir-serialize.cpp index 1b734c6b2..fe997cca8 100644 --- a/source/slang/slang-ir-serialize.cpp +++ b/source/slang/slang-ir-serialize.cpp @@ -12,13 +12,13 @@ namespace Slang { static bool _isTextureTypeBase(IROp opIn) { - const int op = (kIROpMeta_PseudoOpMask & opIn); + const int op = (kIROpMeta_OpMask & opIn); return op >= kIROp_FirstTextureTypeBase && op <= kIROp_LastTextureTypeBase; } static bool _isConstant(IROp opIn) { - const int op = (kIROpMeta_PseudoOpMask & opIn); + const int op = (kIROpMeta_OpMask & opIn); return op >= kIROp_FirstConstant && op <= kIROp_LastConstant; } @@ -293,9 +293,6 @@ Result IRSerialWriter::write(IRModule* module, SourceManager* sourceManager, Opt { IRInst* srcInst = m_insts[i]; Ser::Inst& dstInst = m_serialData->m_insts[i]; - - // Can't be any pseudo ops - SLANG_ASSERT(!isPseudoOp(srcInst->op)); dstInst.m_op = uint8_t(srcInst->op & kIROpMeta_OpMask); dstInst.m_payloadType = PayloadType::Empty; diff --git a/source/slang/slang-ir.cpp b/source/slang/slang-ir.cpp index a30445682..a8f42c326 100644 --- a/source/slang/slang-ir.cpp +++ b/source/slang/slang-ir.cpp @@ -10,9 +10,6 @@ namespace Slang { struct IRSpecContext; - - SLANG_COMPILE_TIME_ASSERT(kIROpCount < kIRPseudoOp_First); - IRInst* cloneGlobalValueWithLinkage( IRSpecContext* context, IRInst* originalVal, @@ -39,31 +36,14 @@ namespace Slang { kIROp_##ID, { #MNEMONIC, ARG_COUNT, FLAGS, } }, #include "slang-ir-inst-defs.h" - // Pseudo ops -#define INST(ID, MNEMONIC, ARG_COUNT, FLAGS) /* empty */ -#define PSEUDO_INST(ID) \ - { kIRPseudoOp_##ID, { #ID, 0, 0 } }, - - // First is 'invalid' + // Invalid op sentinel value comes after all the valid ones { kIROp_Invalid,{ "invalid", 0, 0 } }, - // Then all the other psuedo ops -#include "slang-ir-inst-defs.h" - }; IROpInfo getIROpInfo(IROp opIn) { - const int op = opIn & kIROpMeta_PseudoOpMask; - if ((op & kIROpMeta_IsPseudoOp) && op < kIRPseudoOp_LastPlusOne) - { - // It's a pseudo op - const int index = op - kIRPseudoOp_First; - // Pseudo ops start from kIROpcount - const auto& entry = kIROps[kIROpCount + index]; - SLANG_ASSERT(entry.op == op); - return entry.info; - } - else if (op < kIROpCount) + const int op = opIn & kIROpMeta_OpMask; + if (op < kIROpCount) { // It's a main op const auto& entry = kIROps[op]; @@ -4460,8 +4440,8 @@ namespace Slang return false; } - const IROp opA = IROp(a->op & kIROpMeta_PseudoOpMask); - const IROp opB = IROp(b->op & kIROpMeta_PseudoOpMask); + const IROp opA = IROp(a->op & kIROpMeta_OpMask); + const IROp opB = IROp(b->op & kIROpMeta_OpMask); if (opA != opB) { diff --git a/source/slang/slang-ir.h b/source/slang/slang-ir.h index fbb560a60..9bdc7c3c9 100644 --- a/source/slang/slang-ir.h +++ b/source/slang/slang-ir.h @@ -41,36 +41,27 @@ enum : IROpFlags /* Bit usage of IROp is a follows - MainOp | Pseudo | Other -Bit range: 0-7 | 8 | Remaining bits + MainOp | Other +Bit range: 0-7 | Remaining bits -If an instruction is 'pseudo' (ie shouldn't appear in output IR), then the Pseudo bit is set - and 'Invalid' falls into -this category as well as all pseudo ops. For doing range checks (for example for doing isa tests), the value is masked by kIROpMeta_OpMask, such that the Other bits don't interfere. The other bits can be used for storage for anything that needs to identify as a different 'op' or 'type'. It is currently used currently for storing the TextureFlavor of a IRResourceTypeBase derived types for example. + +TODO: We should eliminate the use of the "other" bits so that the entire value/state +of an instruction is manifest in its opcode, operands, and children. */ enum IROp : int32_t { #define INST(ID, MNEMONIC, ARG_COUNT, FLAGS) \ kIROp_##ID, - #include "slang-ir-inst-defs.h" + /// The total number of valid opcodes kIROpCount, - // We use the range 0x100 to 0x1ff set for pseudo/non main codes - // Instructions that should not appear in valid IR. - - kIROp_Invalid = 0x100, ///< If bit set, then in pseudo/not normal space - kIRPseudoOp_First = kIROp_Invalid, - -#define INST(ID, MNEMONIC, ARG_COUNT, FLAGS) /* empty */ -#define PSEUDO_INST(ID) kIRPseudoOp_##ID, - - kIRPseudoOp_LastPlusOne, - -#include "slang-ir-inst-defs.h" + /// An invalid opcode used to represent a missing or unknown opcode value. + kIROp_Invalid = kIROpCount, #define INST(ID, MNEMONIC, ARG_COUNT, FLAGS) /* empty */ #define INST_RANGE(BASE, FIRST, LAST) \ @@ -83,16 +74,10 @@ enum IROp : int32_t /* IROpMeta describe values for layout of IROp, as well as values for accessing aspects of IROp bits. */ enum IROpMeta { - kIROpMeta_OtherShift = 9, ///< Number of bits for op/pseudo ops (shift right by this to get the other bits) - kIROpMeta_PseudoOpMask = (int32_t(1) << kIROpMeta_OtherShift) - 1, ///< Mask for ops including pseudo ops - kIROpMeta_OpMask = 0xff, ///< Mask for just ops - kIrOpMeta_OtherMask = ~kIROpMeta_PseudoOpMask, ///< Mask for bits that can be used for other purposes than 'op' ('other' bits) - kIROpMeta_IsPseudoOp = kIROp_Invalid, ///< 'And' with op, if set, the op is a pseudo op + kIROpMeta_OtherShift = 8, ///< Number of bits for op (shift right by this to get the other bits) + kIROpMeta_OpMask = 0xff, ///< Mask for just opcode }; -// True if op is pseudo (or invalid which is 'pseudo-like' at least in as so far as current behavior) -SLANG_FORCE_INLINE bool isPseudoOp(IROp op) { return (op & kIROpMeta_IsPseudoOp) != 0; } - IROp findIROp(const UnownedStringSlice& name); // A logical operation/opcode in the IR @@ -602,8 +587,8 @@ typename IRInstList<T>::Iterator IRInstList<T>::end() // Types -#define IR_LEAF_ISA(NAME) static bool isaImpl(IROp op) { return (kIROpMeta_PseudoOpMask & op) == kIROp_##NAME; } -#define IR_PARENT_ISA(NAME) static bool isaImpl(IROp opIn) { const int op = (kIROpMeta_PseudoOpMask & opIn); return op >= kIROp_First##NAME && op <= kIROp_Last##NAME; } +#define IR_LEAF_ISA(NAME) static bool isaImpl(IROp op) { return (kIROpMeta_OpMask & op) == kIROp_##NAME; } +#define IR_PARENT_ISA(NAME) static bool isaImpl(IROp opIn) { const int op = (kIROpMeta_OpMask & opIn); return op >= kIROp_First##NAME && op <= kIROp_Last##NAME; } #define SIMPLE_IR_TYPE(NAME, BASE) struct IR##NAME : IR##BASE { IR_LEAF_ISA(NAME) }; #define SIMPLE_IR_PARENT_TYPE(NAME, BASE) struct IR##NAME : IR##BASE { IR_PARENT_ISA(NAME) }; diff --git a/source/slang/slang-lower-to-ir.cpp b/source/slang/slang-lower-to-ir.cpp index ac02e1dfd..2a04b53b2 100644 --- a/source/slang/slang-lower-to-ir.cpp +++ b/source/slang/slang-lower-to-ir.cpp @@ -5,6 +5,7 @@ #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-insts.h" @@ -478,12 +479,13 @@ LoweredValInfo emitDeclRef( IRInst* getSimpleVal(IRGenContext* context, LoweredValInfo lowered); -IROp getIntrinsicOp( +int32_t getIntrinsicOp( Decl* decl, IntrinsicOpModifier* intrinsicOpMod) { - if (int(intrinsicOpMod->op) != 0) - return intrinsicOpMod->op; + int32_t op = intrinsicOpMod->op; + if(op != 0) + return op; // No specified modifier? Then we need to look it up // based on the name of the declaration... @@ -491,9 +493,10 @@ IROp getIntrinsicOp( auto name = decl->getName(); auto nameText = getUnownedStringSliceText(name); - IROp op = findIROp(nameText); - SLANG_ASSERT(op != kIROp_Invalid); - return op; + IROp irOp = findIROp(nameText); + SLANG_ASSERT(irOp != kIROp_Invalid); + SLANG_ASSERT(int32_t(irOp) >= 0); + return int32_t(irOp); } // Given a `LoweredValInfo` for something callable, along with a @@ -713,16 +716,23 @@ LoweredValInfo emitCallToDeclRef( auto funcDecl = funcDeclRef.getDecl(); if(auto intrinsicOpModifier = funcDecl->FindModifier<IntrinsicOpModifier>()) { - auto op = getIntrinsicOp(funcDecl, intrinsicOpModifier); - - if (isPseudoOp(op)) + // 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). + // + auto intrinsicOp = getIntrinsicOp(funcDecl, intrinsicOpModifier); + if(intrinsicOp < 0) { - switch (op) + // We have a compound op, which requires special-case + // handling to generate zero or more IR instructions. + // + auto compoundOp = CompoundIntrinsicOp(intrinsicOp); + switch (compoundOp) { - case kIRPseudoOp_Pos: + case kCompoundIntrinsicOp_Pos: return LoweredValInfo::simple(args[0]); - case kIRPseudoOp_Sequence: + case kCompoundIntrinsicOp_Sequence: // The main effect of "operator comma" is to enforce // sequencing of its operands, but Slang already // implements a strictly left-to-right evaluation @@ -734,44 +744,49 @@ LoweredValInfo emitCallToDeclRef( #define CASE(COMPOUND, OP) \ case COMPOUND: return emitCompoundAssignOp(context, type, OP, argCount, args) - CASE(kIRPseudoOp_AddAssign, kIROp_Add); - CASE(kIRPseudoOp_SubAssign, kIROp_Sub); - CASE(kIRPseudoOp_MulAssign, kIROp_Mul); - CASE(kIRPseudoOp_DivAssign, kIROp_Div); - CASE(kIRPseudoOp_IRemAssign,kIROp_IRem); - CASE(kIRPseudoOp_FRemAssign,kIROp_FRem); - CASE(kIRPseudoOp_AndAssign, kIROp_BitAnd); - CASE(kIRPseudoOp_OrAssign, kIROp_BitOr); - CASE(kIRPseudoOp_XorAssign, kIROp_BitXor); - CASE(kIRPseudoOp_LshAssign, kIROp_Lsh); - CASE(kIRPseudoOp_RshAssign, kIROp_Rsh); + 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(kIRPseudoOp_PreInc, kIROp_Add); - CASE(kIRPseudoOp_PreDec, kIROp_Sub); + 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(kIRPseudoOp_PostInc, kIROp_Add); - CASE(kIRPseudoOp_PostDec, kIROp_Sub); + CASE(kCompoundIntrinsicOp_PostInc, kIROp_Add); + CASE(kCompoundIntrinsicOp_PostDec, kIROp_Sub); #undef CASE default: SLANG_UNIMPLEMENTED_X("IR pseudo-op"); UNREACHABLE_RETURN(LoweredValInfo()); } } - - return LoweredValInfo::simple(builder->emitIntrinsicInst( - type, - op, - argCount, - args)); + 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)); + } } - // TODO: handle target intrinsic modifier too... if( auto ctorDeclRef = funcDeclRef.as<ConstructorDecl>() ) { diff --git a/source/slang/slang-modifier-defs.h b/source/slang/slang-modifier-defs.h index fb3292e23..bfbb51c1e 100644 --- a/source/slang/slang-modifier-defs.h +++ b/source/slang/slang-modifier-defs.h @@ -33,11 +33,20 @@ SIMPLE_MODIFIER(GloballyCoherent) // SYNTAX_CLASS(IntrinsicOpModifier, Modifier) - // token that names the intrinsic op + // Token that names the intrinsic op. FIELD(Token, opToken) - // The opcode for the intrinsic operation - FIELD_INIT(IROp, op, kIROp_Nop) + // The 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) 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 c1a9d59d2..26a7dbb65 100644 --- a/source/slang/slang-stdlib.cpp +++ b/source/slang/slang-stdlib.cpp @@ -1,6 +1,7 @@ // slang-stdlib.cpp #include "slang-compiler.h" +#include "slang-compound-intrinsics.h" #include "slang-ir.h" #include "slang-syntax.h" @@ -198,17 +199,17 @@ namespace Slang } } - struct OpInfo { int32_t opCode; char const* opName; unsigned flags; }; + struct OpInfo { IntrinsicOp opCode; char const* opName; unsigned flags; }; static const OpInfo unaryOps[] = { - { kIRPseudoOp_Pos, "+", ARITHMETIC_MASK }, + { kCompoundIntrinsicOp_Pos, "+", ARITHMETIC_MASK }, { kIROp_Neg, "-", ARITHMETIC_MASK }, { kIROp_Not, "!", BOOL_MASK | BOOL_RESULT }, { kIROp_BitNot, "~", INT_MASK }, - { kIRPseudoOp_PreInc, "++", ARITHMETIC_MASK | ASSIGNMENT }, - { kIRPseudoOp_PreDec, "--", ARITHMETIC_MASK | ASSIGNMENT }, - { kIRPseudoOp_PostInc, "++", ARITHMETIC_MASK | ASSIGNMENT | POSTFIX }, - { kIRPseudoOp_PostDec, "--", ARITHMETIC_MASK | ASSIGNMENT | POSTFIX }, + { kCompoundIntrinsicOp_PreInc, "++", ARITHMETIC_MASK | ASSIGNMENT }, + { kCompoundIntrinsicOp_PreDec, "--", ARITHMETIC_MASK | ASSIGNMENT }, + { kCompoundIntrinsicOp_PostInc, "++", ARITHMETIC_MASK | ASSIGNMENT | POSTFIX }, + { kCompoundIntrinsicOp_PostDec, "--", ARITHMETIC_MASK | ASSIGNMENT | POSTFIX }, }; static const OpInfo binaryOps[] = { @@ -231,17 +232,17 @@ namespace Slang { kIROp_Less, "<", ARITHMETIC_MASK | BOOL_RESULT }, { kIROp_Geq, ">=", ARITHMETIC_MASK | BOOL_RESULT }, { kIROp_Leq, "<=", ARITHMETIC_MASK | BOOL_RESULT }, - { kIRPseudoOp_AddAssign, "+=", ASSIGNMENT | ARITHMETIC_MASK }, - { kIRPseudoOp_SubAssign, "-=", ASSIGNMENT | ARITHMETIC_MASK }, - { kIRPseudoOp_MulAssign, "*=", ASSIGNMENT | ARITHMETIC_MASK }, - { kIRPseudoOp_DivAssign, "/=", ASSIGNMENT | ARITHMETIC_MASK }, - { kIRPseudoOp_IRemAssign, "%=", ASSIGNMENT | INT_MASK }, - { kIRPseudoOp_FRemAssign, "%=", ASSIGNMENT | FLOAT_MASK }, - { kIRPseudoOp_AndAssign, "&=", ASSIGNMENT | LOGICAL_MASK }, - { kIRPseudoOp_OrAssign, "|=", ASSIGNMENT | LOGICAL_MASK }, - { kIRPseudoOp_XorAssign, "^=", ASSIGNMENT | LOGICAL_MASK }, - { kIRPseudoOp_LshAssign, "<<=", ASSIGNMENT | INT_MASK }, - { kIRPseudoOp_RshAssign, ">>=", ASSIGNMENT | INT_MASK }, + { kCompoundIntrinsicOp_AddAssign, "+=", ASSIGNMENT | ARITHMETIC_MASK }, + { kCompoundIntrinsicOp_SubAssign, "-=", ASSIGNMENT | ARITHMETIC_MASK }, + { kCompoundIntrinsicOp_MulAssign, "*=", ASSIGNMENT | ARITHMETIC_MASK }, + { kCompoundIntrinsicOp_DivAssign, "/=", ASSIGNMENT | ARITHMETIC_MASK }, + { kCompoundIntrinsicOp_IRemAssign, "%=", ASSIGNMENT | INT_MASK }, + { kCompoundIntrinsicOp_FRemAssign, "%=", ASSIGNMENT | FLOAT_MASK }, + { kCompoundIntrinsicOp_AndAssign, "&=", ASSIGNMENT | LOGICAL_MASK }, + { kCompoundIntrinsicOp_OrAssign, "|=", ASSIGNMENT | LOGICAL_MASK }, + { kCompoundIntrinsicOp_XorAssign, "^=", ASSIGNMENT | LOGICAL_MASK }, + { kCompoundIntrinsicOp_LshAssign, "<<=", ASSIGNMENT | INT_MASK }, + { kCompoundIntrinsicOp_RshAssign, ">>=", ASSIGNMENT | INT_MASK }, }; String Session::getCoreLibraryCode() diff --git a/source/slang/slang-syntax.h b/source/slang/slang-syntax.h index 0dd70b1f8..86cc4b902 100644 --- a/source/slang/slang-syntax.h +++ b/source/slang/slang-syntax.h @@ -2,7 +2,7 @@ #define SLANG_SYNTAX_H #include "../core/slang-basic.h" -#include "slang-ir.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 fc1f3c421..3d3fa4375 100644 --- a/source/slang/slang.vcxproj +++ b/source/slang/slang.vcxproj @@ -193,6 +193,7 @@ <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" /> @@ -337,7 +338,7 @@ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">"../../bin/windows-x64/debug/slang-generate" %(Identity)</Command> <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">"../../bin/windows-x86/release/slang-generate" %(Identity)</Command> <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">"../../bin/windows-x64/release/slang-generate" %(Identity)</Command> - <Outputs>%(Identity).h</Outputs> + <Outputs>../../core.meta.slang.h</Outputs> <Message>slang-generate %(Identity)</Message> <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../../bin/windows-x86/debug/slang-generate.exe</AdditionalInputs> <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">../../bin/windows-x64/debug/slang-generate.exe</AdditionalInputs> @@ -350,7 +351,7 @@ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">"../../bin/windows-x64/debug/slang-generate" %(Identity)</Command> <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">"../../bin/windows-x86/release/slang-generate" %(Identity)</Command> <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">"../../bin/windows-x64/release/slang-generate" %(Identity)</Command> - <Outputs>%(Identity).h</Outputs> + <Outputs>../../hlsl.meta.slang.h</Outputs> <Message>slang-generate %(Identity)</Message> <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../../bin/windows-x86/debug/slang-generate.exe</AdditionalInputs> <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">../../bin/windows-x64/debug/slang-generate.exe</AdditionalInputs> diff --git a/source/slang/slang.vcxproj.filters b/source/slang/slang.vcxproj.filters index 754fc8aa6..3764a6f11 100644 --- a/source/slang/slang.vcxproj.filters +++ b/source/slang/slang.vcxproj.filters @@ -30,6 +30,9 @@ <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> |
