summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
Diffstat (limited to 'source')
-rw-r--r--source/slang/core.meta.slang14
-rw-r--r--source/slang/core.meta.slang.h25
-rw-r--r--source/slang/hlsl.meta.slang20
-rw-r--r--source/slang/hlsl.meta.slang.h20
-rw-r--r--source/slang/slang-check-impl.h2
-rw-r--r--source/slang/slang-compound-intrinsics.h81
-rw-r--r--source/slang/slang-ir-inst-defs.h28
-rw-r--r--source/slang/slang-ir-serialize.cpp7
-rw-r--r--source/slang/slang-ir.cpp30
-rw-r--r--source/slang/slang-ir.h39
-rw-r--r--source/slang/slang-lower-to-ir.cpp83
-rw-r--r--source/slang/slang-modifier-defs.h15
-rw-r--r--source/slang/slang-stdlib.cpp35
-rw-r--r--source/slang/slang-syntax.h2
-rw-r--r--source/slang/slang.vcxproj5
-rw-r--r--source/slang/slang.vcxproj.filters3
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>