// Slang `core` library // Aliases for base types /// @category scalar_types Scalar types typedef half float16_t; /// @category scalar_types typedef float float32_t; /// @category scalar_types typedef double float64_t; /// @category scalar_types typedef int int32_t; /// @category scalar_types typedef uint uint32_t; /// @category scalar_types typedef uintptr_t size_t; /// @category scalar_types typedef uintptr_t usize_t; /// @category scalar_types typedef intptr_t ssize_t; // Modifier for variables that must resolve to compile-time constants // as part of translation. syntax constexpr : ConstExprModifier; // Modifier for variables that should have writes be made // visible at the global-memory scope syntax globallycoherent : GloballyCoherentModifier; /// Modifier to disable inteprolation and force per-vertex passing of a varying attribute. /// /// When a varying attribute passed to the fragment shader is marked `pervertex`, it will /// not be interpolated during rasterization (similar to `nointerpolate` attributes). /// Unlike a plain `nointerpolate` attribute, this modifier indicates that the attribute /// should *only* be acccessed through the `GetAttributeAtVertex()` operation, so access its /// distinct per-vertex values. /// syntax pervertex : PerVertexModifier; /// Modifier to indicate a buffer or texture element type is /// backed by data in an unsigned normalized format. /// /// The `unorm` modifier is only valid on `float` and `vector`s /// with `float` elements. /// /// This modifier does not affect the semantics of any variable, /// parameter, or field that uses it. The semantics of a `float` /// or vector are the same with or without `unorm`. /// /// The `unorm` modifier can be used for the element type of a /// buffer or texture, to indicate that the data that is bound /// to that buffer or texture is in a matching normalized format. /// Some platforms may require a `unorm` qualifier for such buffers /// and textures, and others may operate correctly without it. /// syntax unorm : UNormModifier; /// Modifier to indicate a buffer or texture element type is /// backed by data in an signed normalized format. /// /// The `snorm` modifier is only valid on `float` and `vector`s /// with `float` elements. /// /// This modifier does not affect the semantics of any variable, /// parameter, or field that uses it. The semantics of a `float` /// or vector are the same with or without `snorm`. /// /// The `snorm` modifier can be used for the element type of a /// buffer or texture, to indicate that the data that is bound /// to that buffer or texture is in a matching normalized format. /// Some platforms may require a `unorm` qualifier for such buffers /// and textures, and others may operate correctly without it. /// syntax snorm : SNormModifier; /// Modifier to indicate that a function name should not be mangled /// by the Slang compiler. /// /// The `__extern_cpp` modifier makes a symbol to have unmangled /// name in source/output C++ code. /// syntax __extern_cpp : ExternCppModifier; __magic_type(DefaultInitializableType) interface IDefaultInitializable { __builtin_requirement($( (int)BuiltinRequirementKind::DefaultInitializableConstructor)) __init(); } interface IComparable { __builtin_requirement($( (int)BuiltinRequirementKind::Equals)) bool equals(This other); __builtin_requirement($( (int)BuiltinRequirementKind::LessThan)) bool lessThan(This other); __builtin_requirement($( (int)BuiltinRequirementKind::LessThanOrEquals)) bool lessThanOrEquals(This other); } interface IRangedValue { static const This maxValue; static const This minValue; } __attributeTarget(DeclBase) attribute_syntax [TreatAsDifferentiable] : TreatAsDifferentiableAttribute; interface IArithmetic : IComparable { This add(This other); This sub(This other); This mul(This other); This div(This other); This mod(This other); This neg(); __init(int val); /// Initialize from the same type. __init(This value); } interface ILogical : IComparable { __builtin_requirement($( (int)BuiltinRequirementKind::Shl) ) This shl(int value); __builtin_requirement($( (int)BuiltinRequirementKind::Shr) ) This shr(int value); __builtin_requirement($( (int)BuiltinRequirementKind::BitAnd) ) This bitAnd(This other); __builtin_requirement($( (int)BuiltinRequirementKind::BitOr) ) This bitOr(This other); __builtin_requirement($( (int)BuiltinRequirementKind::BitXor) ) This bitXor(This other); __builtin_requirement($( (int)BuiltinRequirementKind::BitNot) ) This bitNot(); __builtin_requirement($( (int)BuiltinRequirementKind::And) ) This and(This other); __builtin_requirement($( (int)BuiltinRequirementKind::Or) ) This or(This other); __builtin_requirement($( (int)BuiltinRequirementKind::Not) ) This not(); __builtin_requirement($( (int)BuiltinRequirementKind::InitLogicalFromInt) ) __init(int val); } interface IInteger : IArithmetic, ILogical { int toInt(); int64_t toInt64(); uint toUInt(); uint64_t toUInt64(); __init(int val); __init(int64_t val); } interface IFloat : IArithmetic, IDifferentiable { [TreatAsDifferentiable] __init(float value); [TreatAsDifferentiable] float toFloat(); [TreatAsDifferentiable] This add(This other); [TreatAsDifferentiable] This sub(This other); [TreatAsDifferentiable] This mul(This other); [TreatAsDifferentiable] This div(This other); [TreatAsDifferentiable] This mod(This other); [TreatAsDifferentiable] This neg(); [TreatAsDifferentiable] __init(This value); [TreatAsDifferentiable] This scale(T scale); } /// A type that can be used as an operand for builtins [sealed] [builtin] interface __BuiltinType { } /// A type that can be used for arithmetic operations [sealed] [builtin] interface __BuiltinArithmeticType : __BuiltinType, IArithmetic { } /// A type that can be used for logical/bitwise operations [sealed] [builtin] interface __BuiltinLogicalType : __BuiltinType, ILogical { } /// A type that logically has a sign (positive/negative/zero) [sealed] [builtin] interface __BuiltinSignedArithmeticType : __BuiltinArithmeticType {} /// A type that can represent integers [sealed] [builtin] interface __BuiltinIntegerType : __BuiltinArithmeticType, IInteger {} /// A type that can represent non-integers [sealed] [builtin] interface __BuiltinRealType : __BuiltinSignedArithmeticType {} __attributeTarget(AggTypeDecl) attribute_syntax [__NonCopyableType] : NonCopyableTypeAttribute; __attributeTarget(FunctionDeclBase) attribute_syntax [__NoSideEffect] : NoSideEffectAttribute; /// Marks a function for forward-mode differentiation. /// i.e. the compiler will automatically generate a new function /// that computes the jacobian-vector product of the original. __attributeTarget(FunctionDeclBase) attribute_syntax [ForwardDifferentiable] : ForwardDifferentiableAttribute; /// Marks a function for backward-mode differentiation. __attributeTarget(FunctionDeclBase) attribute_syntax [BackwardDifferentiable(order:int = 0)] : BackwardDifferentiableAttribute; __attributeTarget(FunctionDeclBase) attribute_syntax [Differentiable(order:int = 0)] : BackwardDifferentiableAttribute; __intrinsic_op($(kIROp_RequirePrelude)) void __requirePrelude(constexpr String preludeText); __intrinsic_op($(kIROp_RequireGLSLExtension)) void __requireGLSLExtension(constexpr String preludeText); __intrinsic_op($(kIROp_StaticAssert)) void static_assert(constexpr bool condition, NativeString errorMessage); /// Interface to denote types as differentiable. /// Allows for user-specified differential types as /// well as automatic generation, for when the associated type /// hasn't been declared explicitly. /// Note that the requirements must currently be defined in this exact order /// since the auto-diff pass relies on the order to grab the struct keys. /// __magic_type(DifferentiableType) interface IDifferentiable { // Note: the compiler implementation requires the `Differential` associated type to be defined // before anything else. __builtin_requirement($( (int)BuiltinRequirementKind::DifferentialType) ) associatedtype Differential : IDifferentiable; __builtin_requirement($( (int)BuiltinRequirementKind::DZeroFunc) ) static Differential dzero(); __builtin_requirement($( (int)BuiltinRequirementKind::DAddFunc) ) static Differential dadd(Differential, Differential); __builtin_requirement($( (int)BuiltinRequirementKind::DMulFunc) ) __generic static Differential dmul(T, Differential); }; __magic_type(DifferentiablePtrType) interface IDifferentiablePtrType { __builtin_requirement($( (int)BuiltinRequirementKind::DifferentialPtrType) ) associatedtype Differential : IDifferentiablePtrType; }; /// Pair type that serves to wrap the primal and /// differential types of an arbitrary type T. __generic __magic_type(DifferentialPairType) __intrinsic_type($(kIROp_DifferentialPairUserCodeType)) struct DifferentialPair : IDifferentiable { typedef DifferentialPair Differential; typedef T.Differential DifferentialElementType; __intrinsic_op($(kIROp_MakeDifferentialPairUserCode)) __init(T _primal, T.Differential _differential); property p : T { __intrinsic_op($(kIROp_DifferentialPairGetPrimalUserCode)) get; } property v : T { __intrinsic_op($(kIROp_DifferentialPairGetPrimalUserCode)) get; } property d : T.Differential { __intrinsic_op($(kIROp_DifferentialPairGetDifferentialUserCode)) get; } [__unsafeForceInlineEarly] T.Differential getDifferential() { return d; } [__unsafeForceInlineEarly] T getPrimal() { return p; } [__unsafeForceInlineEarly] static Differential dzero() { return Differential(T.dzero(), T.Differential.dzero()); } [__unsafeForceInlineEarly] static Differential dadd(Differential a, Differential b) { return Differential( T.dadd( a.p, b.p ), T.Differential.dadd(a.d, b.d)); } __generic [__unsafeForceInlineEarly] static Differential dmul(U a, Differential b) { return Differential( T.dmul(a, b.p), T.Differential.dmul(a, b.d)); } }; __generic __magic_type(DifferentialPtrPairType) __intrinsic_type($(kIROp_DifferentialPtrPairType)) struct DifferentialPtrPair : IDifferentiablePtrType { typedef DifferentialPtrPair Differential; typedef T.Differential DifferentialElementType; __intrinsic_op($(kIROp_MakeDifferentialPtrPair)) __init(T _primal, T.Differential _differential); property p : T { __intrinsic_op($(kIROp_DifferentialPtrPairGetPrimal)) get; } property v : T { __intrinsic_op($(kIROp_DifferentialPtrPairGetPrimal)) get; } property d : T.Differential { __intrinsic_op($(kIROp_DifferentialPtrPairGetDifferential)) get; } }; /// A type that uses a floating-point representation [sealed] [builtin] [TreatAsDifferentiable] interface __BuiltinFloatingPointType : __BuiltinRealType, IFloat { /// Get the value of the mathematical constant pi in this type. [Differentiable] static This getPi(); } //@ hidden: // A type resulting from an `enum` declaration. [builtin] __magic_type(EnumTypeType) interface __EnumType : ILogical { // The type of tags for this `enum` // // Note: using `__Tag` instead of `Tag` to avoid any // conflict if a user had an `enum` case called `Tag` associatedtype __Tag : __BuiltinIntegerType; __builtin_requirement($( (int)BuiltinRequirementKind::InitLogicalFromInt) ) __init(__Tag value); }; interface IArray { int getCount(); __subscript(int index) -> T { get; } } interface IRWArray : IArray { __subscript(int index)->T { get; set; } } // 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`. // //@hidden: __generic [__unsafeForceInlineEarly] U operator,(T left, U right) { return right; } // The ternary `?:` operator does not short-circuit in HLSL, and Slang no longer // follow that definition for the scalar condition overload, so this declaration just serves // for type-checking purpose only. //@hidden: __generic __intrinsic_op(select) T operator?: (bool condition, T ifTrue, T ifFalse); //@hidden: __generic __intrinsic_op(select) vector operator?:(vector condition, vector ifTrue, vector ifFalse); // Users are advised to use `select` instead if non-short-circuiting behavior is intended. //@public: __generic __intrinsic_op(select) T select(bool condition, T ifTrue, T ifFalse); __generic __intrinsic_op(select) vector select(vector condition, vector ifTrue, vector ifFalse); // Allow real-number types to be cast into each other //@hidden: __intrinsic_op($(kIROp_FloatCast)) T __realCast(U val); //@hidden: __intrinsic_op($(kIROp_CastIntToFloat)) T __realCast(U val); //@hidden: __intrinsic_op($(kIROp_IntCast)) T __intCast(U val); //@hidden: ${{{{ // We are going to use code generation to produce the // declarations for all of our base types. static const int kBaseTypeCount = sizeof(kBaseTypes) / sizeof(kBaseTypes[0]); for (int tt = 0; tt < kBaseTypeCount; ++tt) { }}}} __builtin_type($(int(kBaseTypes[tt].tag))) struct $(kBaseTypes[tt].name) : __BuiltinType ${{{{ switch (kBaseTypes[tt].tag) { case BaseType::Half: case BaseType::Float: case BaseType::Double: }}}} , __BuiltinFloatingPointType , __BuiltinRealType , __BuiltinSignedArithmeticType , __BuiltinArithmeticType ${{{{ break; case BaseType::Int8: case BaseType::Int16: case BaseType::Int: case BaseType::Int64: case BaseType::IntPtr: }}}} , __BuiltinSignedArithmeticType ${{{{ ; // fall through case BaseType::UInt8: case BaseType::UInt16: case BaseType::UInt: case BaseType::UInt64: case BaseType::UIntPtr: }}}} , __BuiltinArithmeticType , __BuiltinIntegerType ${{{{ ; // fall through case BaseType::Bool: }}}} , __BuiltinLogicalType ${{{{ break; default: break; } }}}} { ${{{{ // Declare initializers to convert from various other types for (int ss = 0; ss < kBaseTypeCount; ++ss) { // Don't allow conversion to or from `void` if (kBaseTypes[tt].tag == BaseType::Void) continue; if (kBaseTypes[ss].tag == BaseType::Void) continue; // We need to emit a modifier so that the semantic-checking // layer will know it can use these operations for implicit // conversion. ConversionCost conversionCost = getBaseTypeConversionCost( kBaseTypes[tt], kBaseTypes[ss]); IROp intrinsicOpCode = getBaseTypeConversionOp( kBaseTypes[tt], kBaseTypes[ss]); BuiltinConversionKind builtinConversionKind = kBuiltinConversion_Unknown; if (kBaseTypes[tt].tag == BaseType::Double && kBaseTypes[ss].tag == BaseType::Float) builtinConversionKind = kBuiltinConversion_FloatToDouble; const char* attrib = ""; if ((kBaseTypes[tt].flags & kBaseTypes[ss].flags & FLOAT_MASK) != 0) attrib = "[TreatAsDifferentiable]"; }}}} $(attrib) __intrinsic_op($(intrinsicOpCode)) __implicit_conversion($(conversionCost), $(builtinConversionKind)) __init($(kBaseTypes[ss].name) value); ${{{{ } // Integer type implementations. switch (kBaseTypes[tt].tag) { case BaseType::Bool: }}}} [__unsafeForceInlineEarly] __intrinsic_op($(kIROp_Eql)) bool equals(This other); [__unsafeForceInlineEarly] __intrinsic_op($(kIROp_Less)) bool lessThan(This other); [__unsafeForceInlineEarly] __intrinsic_op($(kIROp_Leq)) bool lessThanOrEquals(This other); [__unsafeForceInlineEarly] This shl(int other) { return __intCast(__shl(__intCast(this), other)); } [__unsafeForceInlineEarly] This shr(int other) { return __intCast(__shr(__intCast(this), other)); } [__unsafeForceInlineEarly] This bitAnd(This other) { return __intCast(__and(__intCast(this), __intCast(other))); } [__unsafeForceInlineEarly] This bitOr(This other) { return __intCast(__or(__intCast(this), __intCast(other))); } [__unsafeForceInlineEarly] __intrinsic_op($(kIROp_And)) This and(This other); [__unsafeForceInlineEarly] __intrinsic_op($(kIROp_Or)) This or(This other); [__unsafeForceInlineEarly] This bitXor(This other) { return __intCast(__xor(__intCast(this), __intCast(other))); } [__unsafeForceInlineEarly] This bitNot() { return __intCast(__not(__intCast(this))); } [__unsafeForceInlineEarly] __intrinsic_op($(kIROp_Not)) This not(); ${{{{ break; case BaseType::UInt8: case BaseType::UInt16: case BaseType::UInt: case BaseType::UInt64: case BaseType::Int8: case BaseType::Int16: case BaseType::Int: case BaseType::Int64: case BaseType::IntPtr: case BaseType::UIntPtr: }}}} // If this is a basic integer type, then define explicit // initializers that take a value of an `enum` type. // // TODO: This should actually be restricted, so that this // only applies `where T.__Tag == Self`, but we don't have // the needed features in our type system to implement // that constraint right now. // __generic __intrinsic_op($(kIROp_IntCast)) __init(T value); // Implementation of the `IInteger` interface. __intrinsic_op($(kIROp_Less)) bool lessThan(This other); __intrinsic_op($(kIROp_Leq)) bool lessThanOrEquals(This other); __intrinsic_op($(kIROp_Eql)) bool equals(This other); __intrinsic_op($(kIROp_Add)) This add(This other); __intrinsic_op($(kIROp_Sub)) This sub(This other); __intrinsic_op($(kIROp_Mul)) This mul(This other); __intrinsic_op($(kIROp_Div)) This div(This other); __intrinsic_op($(kIROp_IRem)) This mod(This other); __intrinsic_op($(kIROp_Neg)) This neg(); __intrinsic_op($(kIROp_Lsh)) This shl(int other); __intrinsic_op($(kIROp_Rsh)) This shr(int other); __intrinsic_op($(kIROp_BitAnd)) This bitAnd(This other); __intrinsic_op($(kIROp_BitOr)) This bitOr(This other); [__unsafeForceInlineEarly] This and(This other) {return __intCast(and(__intCast(this), __intCast(other))); } [__unsafeForceInlineEarly] This or(This other) {return __intCast(__intCast(this) || __intCast(other)); } __intrinsic_op($(kIROp_BitXor)) This bitXor(This other); __intrinsic_op($(kIROp_BitNot)) This bitNot(); [__unsafeForceInlineEarly] This not() {return __intCast(!__intCast(this)); } __intrinsic_op($(kIROp_IntCast)) int toInt(); __intrinsic_op($(kIROp_IntCast)) int64_t toInt64(); __intrinsic_op($(kIROp_IntCast)) uint toUInt(); __intrinsic_op($(kIROp_IntCast)) uint64_t toUInt64(); ${{{{ break; default: break; } // If this is a floating-point type, then we need to // implement the `IFloat` interface, which defines the basic `getPi()` // function that is used to implement generic versions of `degrees()` and // `radians()`. // switch (kBaseTypes[tt].tag) { default: break; case BaseType::Half: case BaseType::Float: case BaseType::Double: }}}} [Differentiable] static $(kBaseTypes[tt].name) getPi() { return $(kBaseTypes[tt].name)(3.14159265358979323846264338328); } __intrinsic_op($(kIROp_Less)) bool lessThan(This other); __intrinsic_op($(kIROp_Leq)) bool lessThanOrEquals(This other); __intrinsic_op($(kIROp_Eql)) bool equals(This other); __intrinsic_op($(kIROp_Add)) This add(This other); __intrinsic_op($(kIROp_Sub)) This sub(This other); __intrinsic_op($(kIROp_Mul)) This mul(This other); __intrinsic_op($(kIROp_Div)) This div(This other); __intrinsic_op($(kIROp_FRem)) This mod(This other); __intrinsic_op($(kIROp_Neg)) This neg(); __intrinsic_op($(kIROp_FloatCast)) float toFloat(); __intrinsic_op($(kIROp_Mul)) This scale(T s) { return __mul(this, __realCast(s)); } typedef $(kBaseTypes[tt].name) Differential; [__unsafeForceInlineEarly] [BackwardDifferentiable] static Differential dzero() { return Differential(0); } [__unsafeForceInlineEarly] [BackwardDifferentiable] static Differential dadd(Differential a, Differential b) { return a + b; } __generic [__unsafeForceInlineEarly] [BackwardDifferentiable] static Differential dmul(U a, Differential b) { return __realCast(a) * b; } ${{{{ break; } // If this is the `void` type, then we want to allow // explicit conversion to it from any other type, using // `(void) someExpression`. // if( kBaseTypes[tt].tag == BaseType::Void ) { }}}} __generic [__readNone] __intrinsic_op($(kIROp_CastToVoid)) __init(T value) {} ${{{{ } }}}} } ${{{{ } // Declare built-in pointer type // (eventually we can have the traditional syntax sugar for this) }}}} //@hidden: __magic_type(NullPtrType) struct NullPtr { }; //@hidden: __magic_type(NoneType) __intrinsic_type($(kIROp_VoidType)) struct __none_t { }; //@public: __generic __magic_type(PtrType) __intrinsic_type($(kIROp_PtrType)) struct Ptr { __generic __intrinsic_op($(kIROp_BitCast)) __init(Ptr ptr); __intrinsic_op($(kIROp_CastIntToPtr)) __init(uint64_t val); __intrinsic_op($(kIROp_CastIntToPtr)) __init(int64_t val); __generic __subscript(TInt index) -> T { // If a 'Ptr[index]' is referred to by a '__ref', call 'kIROp_GetOffsetPtr(index)' __intrinsic_op($(kIROp_GetOffsetPtr)) [nonmutating] ref; } }; //@hidden: __intrinsic_op($(kIROp_Load)) T __load(Ptr ptr); __intrinsic_op($(kIROp_Store)) void __store(Ptr ptr, T val); __intrinsic_op($(kIROp_GetElementPtr)) Ptr __getElementPtr(Ptr ptr, TIndex index); __intrinsic_op($(kIROp_GetOffsetPtr)) Ptr __getOffsetPtr(Ptr ptr, TIndex index); __generic __intrinsic_op($(kIROp_Less)) bool operator <(Ptr p1, Ptr p2); __generic __intrinsic_op($(kIROp_Leq)) bool operator <=(Ptr p1, Ptr p2); __generic __intrinsic_op($(kIROp_Greater)) bool operator>(Ptr p1, Ptr p2); __generic __intrinsic_op($(kIROp_Geq)) bool operator >=(Ptr p1, Ptr p2); __generic __intrinsic_op($(kIROp_Neq)) bool operator !=(Ptr p1, Ptr p2); __generic __intrinsic_op($(kIROp_Eql)) bool operator ==(Ptr p1, Ptr p2); //@public: extension bool : IRangedValue { __generic __implicit_conversion($(kConversionCost_PtrToBool)) __intrinsic_op($(kIROp_CastPtrToBool)) __init(Ptr ptr); __generic __implicit_conversion($(kConversionCost_IntegerTruncate)) [__unsafeForceInlineEarly] __init(T v) { return __slang_noop_cast(v) != __intCast(0); } static const bool maxValue = true; static const bool minValue = false; } extension uint64_t : IRangedValue { __generic __intrinsic_op($(kIROp_CastPtrToInt)) __init(Ptr ptr); static const uint64_t maxValue = 0xFFFFFFFFFFFFFFFFULL; static const uint64_t minValue = 0; } extension int64_t : IRangedValue { __generic __intrinsic_op($(kIROp_CastPtrToInt)) __init(Ptr ptr); static const int64_t maxValue = 0x7FFFFFFFFFFFFFFFLL; static const int64_t minValue = -0x8000000000000000LL; } extension intptr_t : IRangedValue { __generic __intrinsic_op($(kIROp_CastPtrToInt)) __init(Ptr ptr); static const intptr_t maxValue = $(SLANG_PROCESSOR_X86_64?"0x7FFFFFFFFFFFFFFFz":"0x7FFFFFFFz"); static const intptr_t minValue = $(SLANG_PROCESSOR_X86_64?"0x8000000000000000z":"0x80000000z"); static const int size = $(SLANG_PROCESSOR_X86_64?"8":"4"); } extension uintptr_t : IRangedValue { __generic __intrinsic_op($(kIROp_CastPtrToInt)) __init(Ptr ptr); static const uintptr_t maxValue = $(SLANG_PROCESSOR_X86_64?"0xFFFFFFFFFFFFFFFFz":"0xFFFFFFFFz"); static const uintptr_t minValue = 0z; static const int size = $(SLANG_PROCESSOR_X86_64?"8":"4"); } //@hidden: __generic __magic_type(OutType) __intrinsic_type($(kIROp_OutType)) struct Out {}; __generic __magic_type(InOutType) __intrinsic_type($(kIROp_InOutType)) struct InOut {}; __generic __magic_type(RefType) __intrinsic_type($(kIROp_RefType)) struct Ref {}; __generic __magic_type(ConstRefType) __intrinsic_type($(kIROp_ConstRefType)) struct ConstRef {}; typealias __Addr = Ptr; //@public: __generic __magic_type(OptionalType) __intrinsic_type($(kIROp_OptionalType)) struct Optional { property bool hasValue { __intrinsic_op($(kIROp_OptionalHasValue)) get; } property T value { __intrinsic_op($(kIROp_GetOptionalValue)) get; } __implicit_conversion($(kConversionCost_ValToOptional)) __intrinsic_op($(kIROp_MakeOptionalValue)) __init(T val); }; //@hidden: __generic [__unsafeForceInlineEarly] bool operator==(Optional val, __none_t noneVal) { return !val.hasValue; } __generic [__unsafeForceInlineEarly] bool operator!=(Optional val, __none_t noneVal) { return val.hasValue; } __generic [__unsafeForceInlineEarly] bool operator==(__none_t noneVal, Optional val) { return !val.hasValue; } __generic [__unsafeForceInlineEarly] bool operator!=(__none_t noneVal, Optional val) { return val.hasValue; } //@public: __generic __magic_type(TupleType) struct Tuple { __intrinsic_op($(kIROp_MakeTuple)) __init(expand each T); } __intrinsic_op($(kIROp_MakeTuple)) Tuple makeTuple(T v); Tuple concat(Tuple t, Tuple u) { return makeTuple(expand each t, expand each u); } //@hidden: [__unsafeForceInlineEarly] bool __assign(inout bool v, bool newVal) { v = newVal; return newVal; } [__unsafeForceInlineEarly] void __tupleLessKernel(inout bool result, inout bool exit, T a, T b) { if (!exit) { if (a.lessThan(b)) { result = true; exit = true; } else if (!a.equals(b)) { exit = true; } } } [__unsafeForceInlineEarly] void __tupleGreaterKernel(inout bool result, inout bool exit, T a, T b) { if (!exit) { if (!a.lessThanOrEquals(b)) { result = true; exit = true; } else if (!a.equals(b)) { exit = true; } } } //@public: __generic extension Tuple : IComparable { bool lessThan(Tuple other) { bool result = false; bool exit = false; expand __tupleLessKernel(result, exit, each this, each other); return result; } bool lessThanOrEquals(Tuple other) { bool result = false; bool exit = false; expand __tupleGreaterKernel(result, exit, each this, each other); return !result; } bool equals(Tuple other) { bool result = true; expand result && __assign(result, result && (each this).equals(each other)); return result; } } interface IMutatingFunc { [mutating] TR operator()(expand each TP p); } interface IFunc : IMutatingFunc { TR operator()(expand each TP p); } interface IDifferentiableMutatingFunc : IMutatingFunc { [Differentiable] [mutating] TR operator()(expand each TP p); } interface IDifferentiableFunc : IFunc, IDifferentiableMutatingFunc { [Differentiable] TR operator()(expand each TP p); } //@hidden: __generic __magic_type(NativeRefType) __intrinsic_type($(kIROp_NativePtrType)) struct NativeRef { __intrinsic_op($(kIROp_GetNativePtr)) __init(T val); }; __generic __intrinsic_op($(kIROp_ManagedPtrAttach)) void __managed_ptr_attach(__ref T val, NativeRef nativeVal); __generic [__unsafeForceInlineEarly] T __attachToNativeRef(NativeRef nativeVal) { T result; __managed_ptr_attach(result, nativeVal); return result; } //@public: __magic_type(StringType) __intrinsic_type($(kIROp_StringType)) struct String { [require(cpp)] __intrinsic_op($(kIROp_MakeString)) __init(int val); [require(cpp)] __intrinsic_op($(kIROp_MakeString)) __init(uint val); [require(cpp)] __intrinsic_op($(kIROp_MakeString)) __init(int64_t val); [require(cpp)] __intrinsic_op($(kIROp_MakeString)) __init(uint64_t val); [require(cpp)] __intrinsic_op($(kIROp_MakeString)) __init(float val); [require(cpp)] __intrinsic_op($(kIROp_MakeString)) __init(double val); [require(cpp)] int64_t getLength(); property int length { get { return (int)getLength(); } } }; /// @category misc_types typedef String string; /// @category misc_types __magic_type(NativeStringType) __intrinsic_type($(kIROp_NativeStringType)) struct NativeString { [require(cpp)] int getLength() { __target_switch { case cpp: __intrinsic_asm "int(strlen($0))"; } } [require(cpp)] Ptr getBuffer() { __target_switch { case cpp: __intrinsic_asm "(void*)((const char*)($0))"; } } property int length { [__unsafeForceInlineEarly] get{return getLength();} } __intrinsic_op($(kIROp_getNativeStr)) __init(String value); }; extension Ptr { __implicit_conversion($(kConversionCost_PtrToVoidPtr)) [__unsafeForceInlineEarly] __init(NativeString nativeStr) { this = nativeStr.getBuffer(); } __generic __intrinsic_op(0) __implicit_conversion($(kConversionCost_PtrToVoidPtr)) __init(Ptr ptr); __generic __intrinsic_op(0) __implicit_conversion($(kConversionCost_PtrToVoidPtr)) __init(NativeRef ptr); } //@hidden: __magic_type(DynamicType) __intrinsic_type($(kIROp_DynamicType)) struct __Dynamic {}; //@public: extension half : IRangedValue { static const half maxValue = half(65504); static const half minValue = half(-65504); } extension float : IRangedValue { static const float maxValue = 340282346638528859811704183484516925440.0f; static const float minValue = -340282346638528859811704183484516925440.0f; } extension double : IRangedValue { static const double maxValue = bit_cast(0x7fefffffffffffffULL); static const double minValue = bit_cast(0xffefffffffffffffULL); } extension int : IRangedValue { static const int maxValue = 2147483647; static const int minValue = -2147483648; } extension uint : IRangedValue { static const uint maxValue = 4294967295; static const uint minValue = 0; } extension int8_t : IRangedValue { static const int8_t maxValue = 127; static const int8_t minValue = -128; } extension uint8_t : IRangedValue { static const uint8_t maxValue = 255; static const uint8_t minValue = 0; } extension uint16_t : IRangedValue { static const uint16_t maxValue = 65535; static const uint16_t minValue = 0; } extension int16_t : IRangedValue { static const int16_t maxValue = 32767; static const int16_t minValue = -32768; } __generic __magic_type(ArrayExpressionType) struct Array : IRWArray { __intrinsic_op($(kIROp_GetArrayLength)) int getCount(); } /// @category math_types Math types /// An `N` component vector with elements of type `T`. __generic __magic_type(VectorExpressionType) struct vector : IRWArray { /// The element type of the vector typedef T Element; /// Initialize a vector where all elements have the same scalar `value`. [TreatAsDifferentiable] __implicit_conversion($(kConversionCost_ScalarToVector)) __intrinsic_op($(kIROp_MakeVectorFromScalar)) __init(T value); /// Initialize a vector from a value of the same type // TODO: we should revise semantic checking so this kind of "identity" conversion is not required __intrinsic_op(0) [TreatAsDifferentiable] __init(vector value); [ForceInline] int getCount() { return N; } } //@hidden: static const int kRowMajorMatrixLayout = $(SLANG_MATRIX_LAYOUT_ROW_MAJOR); static const int kColumnMajorMatrixLayout = $(SLANG_MATRIX_LAYOUT_COLUMN_MAJOR); //@public: /// A matrix with `R` rows and `C` columns, with elements of type `T`. /// @category math_types Math types __generic __magic_type(MatrixExpressionType) struct matrix : IRWArray> { __intrinsic_op($(kIROp_MakeMatrixFromScalar)) __implicit_conversion($(kConversionCost_ScalarToMatrix)) [TreatAsDifferentiable] __init(T val); /// Initialize a vector from a value of the same type // TODO: we should revise semantic checking so this kind of "identity" conversion is not required __intrinsic_op(0) [TreatAsDifferentiable] __init(This value); [ForceInline] int getCount() { return R; } } //@hidden: __intrinsic_op($(kIROp_Eql)) vector __vectorEql(vector left, vector right); //@public: __generic extension vector : IFloat { [__unsafeForceInlineEarly] bool lessThan(This other) { return this[0] < other[0]; } [__unsafeForceInlineEarly] bool lessThanOrEquals(This other) { return this[0] <= other[0]; } [__unsafeForceInlineEarly] bool equals(This other) { return all(__vectorEql(this, other)); } __intrinsic_op($(kIROp_Add)) This add(This other); __intrinsic_op($(kIROp_Sub)) This sub(This other); __intrinsic_op($(kIROp_Mul)) This mul(This other); __intrinsic_op($(kIROp_Div)) This div(This other); __intrinsic_op($(kIROp_FRem)) This mod(This other); __intrinsic_op($(kIROp_Neg)) This neg(); __intrinsic_op($(kIROp_Mul)) This scale(T1 s); [__unsafeForceInlineEarly] float toFloat() { return __realCast(this[0]); } [OverloadRank(-1)] [__unsafeForceInlineEarly] __init(int v) { this = vector(T(v)); } [OverloadRank(-1)] [__unsafeForceInlineEarly] __init(float v) { this = vector(T(v)); } // IDifferentiable typedef vector Differential; [__unsafeForceInlineEarly] [BackwardDifferentiable] static Differential dzero() { return Differential(__slang_noop_cast(T.dzero())); } [__unsafeForceInlineEarly] [BackwardDifferentiable] static Differential dadd(Differential a, Differential b) { return a + b; } __generic [__unsafeForceInlineEarly] [BackwardDifferentiable] static Differential dmul(U a, Differential b) { return __realCast(a) * b; } } __generic extension matrix : IFloat { [TreatAsDifferentiable][__unsafeForceInlineEarly] bool lessThan(This other) { return this < other; } [TreatAsDifferentiable][__unsafeForceInlineEarly] bool lessThanOrEquals(This other) { return this <= other; } [TreatAsDifferentiable][__unsafeForceInlineEarly] bool equals(This other) { return all(this == other); } [TreatAsDifferentiable] __intrinsic_op($(kIROp_Add)) This add(This other); [TreatAsDifferentiable] __intrinsic_op($(kIROp_Sub)) This sub(This other); [TreatAsDifferentiable] __intrinsic_op($(kIROp_Mul))This mul(This other); [TreatAsDifferentiable] __intrinsic_op($(kIROp_Div)) This div(This other); [TreatAsDifferentiable] __intrinsic_op($(kIROp_FRem)) This mod(This other); [TreatAsDifferentiable] __intrinsic_op($(kIROp_Neg)) This neg(); [TreatAsDifferentiable] __intrinsic_op($(kIROp_Mul)) This scale(T1 s); [TreatAsDifferentiable][__unsafeForceInlineEarly] This scale(T1 s); [TreatAsDifferentiable][__unsafeForceInlineEarly] float toFloat() { return __realCast(this[0][0]); } [OverloadRank(-1)] [TreatAsDifferentiable] [__unsafeForceInlineEarly] __implicit_conversion($(kConversionCost_ScalarIntegerToFloatMatrix)) __init(int v) { this = matrix(T(v)); } [OverloadRank(-1)] [TreatAsDifferentiable] [__unsafeForceInlineEarly] __implicit_conversion($(kConversionCost_ScalarToMatrix)) __init(float v) { this = matrix(T(v)); } // IDifferentiable. typedef matrix Differential; [__unsafeForceInlineEarly] [BackwardDifferentiable] static Differential dzero() { return matrix(__slang_noop_cast(T.dzero())); } [__unsafeForceInlineEarly] [BackwardDifferentiable] static Differential dadd(Differential a, Differential b) { return a + b; } __generic [__unsafeForceInlineEarly] [BackwardDifferentiable] static Differential dmul(U a, Differential b) { return __realCast(a) * b; } } __generic extension matrix { typealias T = int16_t; __implicit_conversion($(kConversionCost_IntegerTruncate)) __init(int value) { this = matrix(T(value)); } } //@hidden: __intrinsic_op(makeVector) __generic vector __makeVector(vector vec1, vector vec2); //@public: __generic extension vector { __generic [__unsafeForceInlineEarly] __init(matrix value) { this = __makeVector(value[0], value[1]); } } __generic extension matrix { [__unsafeForceInlineEarly] __init(vector value) { this[0] = value.xy; this[1] = value.zw; } } //@hidden: ${{{{ static const struct { char const* name; char const* glslPrefix; } kTypes[] = { {"half", "f16"}, {"float", ""}, {"double", "d"}, {"float16_t", "f16"}, {"float32_t", "f32"}, {"float64_t", "f64"}, {"int8_t", "i8"}, {"int16_t", "i16"}, {"int32_t", "i32"}, {"int", "i"}, {"int64_t", "i64"}, {"uint8_t", "u8"}, {"uint16_t", "u16"}, {"uint32_t", "u32"}, {"uint", "u"}, {"uint64_t", "u64"}, {"bool", "b"}, }; static const int kTypeCount = sizeof(kTypes) / sizeof(kTypes[0]); for (int tt = 0; tt < kTypeCount; ++tt) { // Declare HLSL vector types for (int ii = 1; ii <= 4; ++ii) { sb << "typedef vector<" << kTypes[tt].name << "," << ii << "> " << kTypes[tt].name << ii << ";\n"; } // Declare HLSL matrix types for (int rr = 1; rr <= 4; ++rr) for (int cc = 1; cc <= 4; ++cc) { sb << "typedef matrix<" << kTypes[tt].name << "," << rr << "," << cc << "> " << kTypes[tt].name << rr << "x" << cc << ";\n"; } } sb << "\n\n"; sb << "// Cast from vector to T, which is a scalar type\n"; for (int tt = 0; tt < kBaseTypeCount; ++tt) { if(kBaseTypes[tt].tag == BaseType::Void) continue; const char* tname = kBaseTypes[tt].name; sb << "extension " << tname << "\n"; sb << "{\n"; sb << " __implicit_conversion(" << kConversionCost_OneVectorToScalar << ")\n"; sb << " __init(vector<" << tname << ",1> v) { this = v[0]; }\n"; sb << "}\n"; } // Declare additional built-in generic types }}}} //@ public: __generic __intrinsic_type($(kIROp_ConstantBufferType)) __magic_type(ConstantBufferType) struct ConstantBuffer {} ///@category texture_types __generic __intrinsic_type($(kIROp_TextureBufferType)) __magic_type(TextureBufferType) struct TextureBuffer {} __generic __intrinsic_type($(kIROp_ParameterBlockType)) __magic_type(ParameterBlockType) struct ParameterBlock {} /// @category stage_io __generic __magic_type(VerticesType) __intrinsic_type($(kIROp_VerticesType)) [__NonCopyableType] struct OutputVertices { __intrinsic_op($(kIROp_MetalSetVertex)) static void _metalSetVertex(uint index, T val); __intrinsic_op($(kIROp_MeshOutputSet)) static void _setVertex(This v, uint index, T val); __subscript(uint index) -> T { // TODO: Make sure this remains write only, we can't do this with just // a 'set' operation as it's legal to only write to part of the output // buffer, or part of the output buffer at a time. [mutating] [require(glsl_hlsl_metal_spirv, meshshading)] set { __target_switch { case metal: _metalSetVertex(index, newValue); case glsl: _setVertex(this, index, newValue); case hlsl: _setVertex(this, index, newValue); case spirv: _setVertex(this, index, newValue); } } // // If a 'OutputVertices[index]' is referred to by a '__ref', call 'kIROp_MeshOutputRef(index)' [require(glsl_hlsl_spirv, meshshading)] __intrinsic_op($(kIROp_MeshOutputRef)) ref; } }; /// @category stage_io __generic __magic_type(IndicesType) __intrinsic_type($(kIROp_IndicesType)) [__NonCopyableType] struct OutputIndices { __intrinsic_op($(kIROp_MetalSetIndices)) static void __metalSetIndices(uint index, T val); // for some reason only here in the indices array it uses the return value as an actual // operand, while the others use the value of the instruction (the return value) to access // the type of the vertex, as when using the ref there is no third operand __intrinsic_op($(kIROp_MeshOutputSet)) static void __setIndices(This v, uint index, T val); __subscript(uint index) -> T { [mutating] [require(glsl_hlsl_metal_spirv, meshshading)] set { __target_switch { case metal: __metalSetIndices(index, newValue); case glsl: __setIndices(this, index, newValue); case hlsl: __setIndices(this, index, newValue); case spirv: __setIndices(this, index, newValue); } } } }; /// @category stage_io __generic __magic_type(PrimitivesType) __intrinsic_type($(kIROp_PrimitivesType)) [__NonCopyableType] struct OutputPrimitives { __intrinsic_op($(kIROp_MetalSetPrimitive)) static void __metalSetPrimitive(uint index, T val); __intrinsic_op($(kIROp_MeshOutputSet)) static void __setPrimitive(This v, uint index, T val); __subscript(uint index)->T { [mutating] [require(glsl_hlsl_metal_spirv, meshshading)] set { __target_switch { case metal: __metalSetPrimitive(index, newValue); case glsl: __setPrimitive(this, index, newValue); case hlsl: __setPrimitive(this, index, newValue); case spirv: __setPrimitive(this, index, newValue); } } // If a 'OutputPrimitives[index]' is referred to by a '__ref', call 'kIROp_MeshOutputRef(index)' [require(glsl_hlsl_spirv, meshshading)] __intrinsic_op($(kIROp_MeshOutputRef)) ref; } }; //@ public: // Need to add constructors to the types above __generic __extension vector { __intrinsic_op($(kIROp_MakeVector)) __init(T x, T y); } __generic __extension vector { __intrinsic_op($(kIROp_MakeVector)) __init(T x, T y, T z); [__unsafeForceInlineEarly] __intrinsic_op($(kIROp_MakeVector)) __init(vector xy, T z); [__unsafeForceInlineEarly] __intrinsic_op($(kIROp_MakeVector)) __init(T x, vector yz); } __generic __extension vector { __intrinsic_op($(kIROp_MakeVector)) __init(T x, T y, T z, T w); [__unsafeForceInlineEarly] __intrinsic_op($(kIROp_MakeVector)) __init(vector xy, T z, T w); [__unsafeForceInlineEarly] __intrinsic_op($(kIROp_MakeVector)) __init(T x, vector yz, T w); [__unsafeForceInlineEarly] __intrinsic_op($(kIROp_MakeVector)) __init(T x, T y, vector zw); [__unsafeForceInlineEarly] __intrinsic_op($(kIROp_MakeVector)) __init(vector xy, vector zw); [__unsafeForceInlineEarly] __intrinsic_op($(kIROp_MakeVector)) __init(vector xyz, T w); [__unsafeForceInlineEarly] __intrinsic_op($(kIROp_MakeVector)) __init(T x, vector yzw); } ${{{{ // The above extensions are generic in the *type* of the vector, // but explicit in the *size*. We will now declare an extension // for each builtin type that is generic in the size. // for (int tt = 0; tt < kBaseTypeCount; ++tt) { if(kBaseTypes[tt].tag == BaseType::Void) continue; sb << "__generic __extension vector<" << kBaseTypes[tt].name << ",N>\n{\n"; for (int ff = 0; ff < kBaseTypeCount; ++ff) { if(kBaseTypes[ff].tag == BaseType::Void) continue; if( tt != ff ) { auto cost = getBaseTypeConversionCost( kBaseTypes[tt], kBaseTypes[ff]); auto op = getBaseTypeConversionOp( kBaseTypes[tt], kBaseTypes[ff]); // Implicit conversion from a vector of the same // size, but different element type. sb << " __implicit_conversion(" << cost << ")\n"; sb << " __intrinsic_op(" << int(op) << ")\n"; sb << " __init(vector<" << kBaseTypes[ff].name << ",N> value);\n"; // Constructor to make a vector from a scalar of another type. if (cost != kConversionCost_Impossible) { cost += kConversionCost_ScalarToVector; sb << " __implicit_conversion(" << cost << ")\n"; sb << " [__unsafeForceInlineEarly]\n"; sb << " __init(" << kBaseTypes[ff].name << " value) { this = vector<" << kBaseTypes[tt].name << ",N>( " << kBaseTypes[tt].name << "(value)); }\n"; } } } sb << "}\n"; } for( int R = 1; R <= 4; ++R ) for( int C = 1; C <= 4; ++C ) { sb << "__generic __extension matrix\n{\n"; // initialize from R*C scalars if (R == 1 || C == 1) sb << "[require(hlsl)]\n"; sb << "__intrinsic_op(" << int(kIROp_MakeMatrix) << ") __init("; for( int ii = 0; ii < R; ++ii ) for( int jj = 0; jj < C; ++jj ) { if ((ii+jj) != 0) sb << ", "; sb << "T m" << ii << jj; } sb << ");\n"; // Initialize from R C-vectors if (R == 1 || C == 1) sb << "[require(hlsl)]\n"; sb << "__intrinsic_op(" << int(kIROp_MakeMatrix) << ") __init("; for (int ii = 0; ii < R; ++ii) { if(ii != 0) sb << ", "; sb << "vector row" << ii; } sb << ");\n"; // initialize from a matrix of larger size for(int rr = R; rr <= 4; ++rr) for( int cc = C; cc <= 4; ++cc ) { if(rr == R && cc == C) continue; if (R == 1 || C == 1) sb << "[require(hlsl)]\n"; sb << "__intrinsic_op(" << int(kIROp_MatrixReshape) << ") __init(matrix value);\n"; } // Initialize from matrix and vector if (R > 2) { sb << "__init(matrix m, vector row" << (R - 1) << ") "; sb << "{ this = This("; for (int ii = 0; ii < R - 1; ++ii) { sb << "m[" << ii << "], "; } sb << "row" << (R - 1) << "); }\n"; } sb << "}\n"; } for (int tt = 0; tt < kBaseTypeCount; ++tt) { if(kBaseTypes[tt].tag == BaseType::Void) continue; auto toType = kBaseTypes[tt].name; }}}} __generic extension matrix<$(toType),R,C,L> { ${{{{ for (int ff = 0; ff < kBaseTypeCount; ++ff) { if(kBaseTypes[ff].tag == BaseType::Void) continue; if( tt == ff ) continue; auto cost = getBaseTypeConversionCost( kBaseTypes[tt], kBaseTypes[ff]); auto fromType = kBaseTypes[ff].name; auto op = getBaseTypeConversionOp( kBaseTypes[tt], kBaseTypes[ff]); }}}} __implicit_conversion($(cost)) __intrinsic_op($(op)) __init(matrix<$(fromType),R,C,L> value); ${{{{ } }}}} } ${{{{ } }}}} //@ hidden: __generic __intrinsic_op(0) T __slang_noop_cast(U u); //@ public: /// Sampling state for filtered texture fetches. /// @category sampler_types Sampler types __magic_type(SamplerStateType, $(int(SamplerStateFlavor::SamplerState))) __intrinsic_type($(kIROp_SamplerStateType)) struct SamplerState { } /// Sampling state for filtered texture fetches that include a comparison operation before filtering. /// @category sampler_types __magic_type(SamplerStateType, $(int(SamplerStateFlavor::SamplerComparisonState))) __intrinsic_type($(kIROp_SamplerComparisonStateType)) struct SamplerComparisonState { } //@ hidden: ${{{{ for (auto op : intrinsicUnaryOps) { for (auto type : kBaseTypes) { if ((type.flags & op.flags) == 0) continue; char const* resultType = type.name; if (op.flags & BOOL_RESULT) resultType = "bool"; // scalar version sb << "__prefix __intrinsic_op(" << int(op.opCode) << ") " << resultType << " operator" << op.opName << "(" << type.name << " value);\n"; sb << "__intrinsic_op(" << int(op.opCode) << ") " << resultType << " __" << op.funcName << "(" << type.name << " value);\n"; // vector version sb << "__generic "; sb << "__prefix __intrinsic_op(" << int(op.opCode) << ") vector<" << resultType << ",N> operator" << op.opName << "(" << "vector<" << type.name << ",N> value);\n"; // matrix version sb << "__generic "; sb << "__prefix __intrinsic_op(" << int(op.opCode) << ") matrix<" << resultType << ",N,M> operator" << op.opName << "(" << "matrix<" << type.name << ",N,M> value);\n"; } // Synthesize generic versions if(op.interface) { char const* resultType = "T"; if (op.flags & BOOL_RESULT) resultType = "bool"; // scalar version sb << "__generic\n"; sb << "[OverloadRank(10)]"; sb << "__prefix __intrinsic_op(" << int(op.opCode) << ") " << resultType << " operator" << op.opName << "(" << "T value);\n"; // vector version sb << "__generic "; sb << "[OverloadRank(10)]"; sb << "__prefix __intrinsic_op(" << int(op.opCode) << ") vector<" << resultType << ",N> operator" << op.opName << "(vector value);\n"; // matrix version sb << "__generic "; sb << "[OverloadRank(10)]"; sb << "__prefix __intrinsic_op(" << int(op.opCode) << ") matrix<" << resultType << ",N,M> operator" << op.opName << "(matrix value);\n"; } } }}}} __generic __intrinsic_op(0) [require(cpp_cuda_spirv)] __prefix Ref operator*(Ptr value); __generic __intrinsic_op(0) [require(cpp_cuda_spirv)] __prefix Ptr operator&(__ref T value); __generic __intrinsic_op(0) [require(cpp_cuda_spirv)] __Addr __get_addr( __ref T value); __generic __intrinsic_op($(kIROp_GetOffsetPtr)) Ptr operator+(Ptr value, int64_t offset); __generic [__unsafeForceInlineEarly] Ptr operator -(Ptr value, int64_t offset) { return __getOffsetPtr(value, -offset); } __generic [__unsafeForceInlineEarly] __prefix T operator+(T value) { return value; } __generic [__unsafeForceInlineEarly] __prefix vector operator+(vector value) { return value; } __generic [__unsafeForceInlineEarly] __prefix matrix operator+(matrix 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[] = { { "__prefix", "", "value" }, { "__postfix", " let result = value;", "result" }, }; for(auto op : kIncDecOps) for(auto fixity : kIncDecFixities) { }}}} $(fixity.qual) __generic [__unsafeForceInlineEarly] T operator$(op.name)(in out T value) {$(fixity.bodyPrefix) value = value $(op.binOp) T(1); return $(fixity.returnVal); } $(fixity.qual) __generic [__unsafeForceInlineEarly] vector operator$(op.name)(in out vector value) {$(fixity.bodyPrefix) value = value $(op.binOp) T(1); return $(fixity.returnVal); } $(fixity.qual) __generic [__unsafeForceInlineEarly] matrix operator$(op.name)(in out matrix value) {$(fixity.bodyPrefix) value = value $(op.binOp) T(1); return $(fixity.returnVal); } $(fixity.qual) __generic [__unsafeForceInlineEarly] Ptr operator$(op.name)(in out Ptr value) {$(fixity.bodyPrefix) value = value $(op.binOp) 1; return $(fixity.returnVal); } ${{{{ } for (auto op : intrinsicBinaryOps) { for (auto type : kBaseTypes) { if ((type.flags & op.flags) == 0) continue; char const* leftType = type.name; char const* rightType = leftType; char const* resultType = leftType; if (op.flags & BOOL_RESULT) resultType = "bool"; // TODO: We should handle a `SHIFT` flag on the op // by changing `rightType` to `int` in order to // account for the fact that the shift amount should // always have a fixed type independent of the LHS. // // (It is unclear why this change hadn't been made // already, so it is possible that such a change // breaks overload resolution or other parts of // the compiler) // scalar version sb << "__intrinsic_op(" << int(op.opCode) << ") " << resultType << " operator" << op.opName << "(" << leftType << " left, " << rightType << " right);\n"; sb << "__intrinsic_op(" << int(op.opCode) << ") " << resultType << " __" << op.funcName << "(" << leftType << " left, " << rightType << " right);\n"; // vector version sb << "__generic "; 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 "; 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 // is a scalar. This choice serves a few purposes: // // 1. It avoids introducing scalar-to-vector or // scalar-to-matrix promotions before the operator, // which might allow some back ends to produce // more optimal code. // // 2. It avoids concerns about making overload resolution // and the inference rules for `N` and `M` able to // handle the mixed vector/scalar or matrix/scalar case. // // 3. Having explicit overloads for the matrix/scalar cases // here means that we do *not* need to support a general // implicit conversion from scalars to matrices, unless // we decide we want to. // // Note: Case (2) of the motivation shouldn't really apply // any more, because we end up having to support similar // inteference for built-in binary math functions where // vectors and scalars might be combined (and where defining // additional overloads to cover all the combinations doesn't // seem practical or desirable). // // TODO: We should consider whether dropping these extra // overloads is possible and worth it. The optimization // concern (1) could possibly be addressed in specific // back-ends. The issue (3) about not wanting to support // implicit scalar-to-matrix conversion may be moot if // we end up needing to support mixed scalar/matrix input // for builtin in non-operator functions anyway. // scalar-vector and scalar-matrix sb << "__generic "; sb << "__intrinsic_op(" << int(op.opCode) << ") vector<" << resultType << ",N> operator" << op.opName << "(" << leftType << " left, vector<" << rightType << ",N> right);\n"; sb << "__generic "; 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 "; sb << "__intrinsic_op(" << int(op.opCode) << ") vector<" << resultType << ",N> operator" << op.opName << "(vector<" << leftType << ",N> left, " << rightType << " right);\n"; sb << "__generic "; sb << "__intrinsic_op(" << int(op.opCode) << ") matrix<" << resultType << ",N,M> operator" << op.opName << "(matrix<" << leftType << ",N,M> left, " << rightType << " right);\n"; } // Synthesize generic versions if(op.interface) { char const* leftType = "T"; char const* rightType = leftType; char const* resultType = leftType; if (op.flags & BOOL_RESULT) resultType = "bool"; // TODO: handle `SHIFT` // scalar version sb << "__generic\n"; sb << "[OverloadRank(10)]"; sb << "__intrinsic_op(" << int(op.opCode) << ") " << resultType << " operator" << op.opName << "(" << leftType << " left, " << rightType << " right);\n"; // vector version sb << "__generic "; sb << "[OverloadRank(10)]"; 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 "; sb << "[OverloadRank(10)]"; 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 sb << "__generic "; sb << "[OverloadRank(10)]"; sb << "__intrinsic_op(" << int(op.opCode) << ") vector<" << resultType << ",N> operator" << op.opName << "(" << leftType << " left, vector<" << rightType << ",N> right);\n"; sb << "__generic "; sb << "[OverloadRank(10)]"; 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 "; sb << "[OverloadRank(10)]"; sb << "__intrinsic_op(" << int(op.opCode) << ") vector<" << resultType << ",N> operator" << op.opName << "(vector<" << leftType << ",N> left, " << rightType << " right);\n"; sb << "__generic "; sb << "[OverloadRank(10)]"; sb << "__intrinsic_op(" << int(op.opCode) << ") matrix<" << resultType << ",N,M> operator" << op.opName << "(matrix<" << leftType << ",N,M> left, " << rightType << " right);\n"; } } // We will declare the shift operations entirely as generics // rather than try to handle all the pairings of left-hand // and right-hand side types. // static const struct ShiftOpInfo { char const* name; char const* funcName; int op; } kShiftOps[] = { { "<<", "shl", kIROp_Lsh }, { ">>", "shr", kIROp_Rsh }, }; for(auto info : kShiftOps) { }}}} __generic __intrinsic_op($(info.op)) L operator$(info.name)(L left, R right); __generic __intrinsic_op($(info.op)) L __$(info.funcName)(L left, R right); __generic [__unsafeForceInlineEarly] L operator$(info.name)=(in out L left, R right) { left = left $(info.name) right; return left; } __generic __intrinsic_op($(info.op)) vector operator$(info.name)(vector left, vector right); __generic [__unsafeForceInlineEarly] vector operator$(info.name)=(in out vector left, vector right) { left = left $(info.name) right; return left; } __generic __intrinsic_op($(info.op)) matrix operator$(info.name)(matrix left, matrix right); __generic [__unsafeForceInlineEarly] matrix operator$(info.name)=(in out matrix left, matrix right) { left = left $(info.name) right; return left; } __generic __intrinsic_op($(info.op)) vector operator$(info.name)(L left, vector right); __generic __intrinsic_op($(info.op)) matrix operator$(info.name)(L left, matrix right); __generic __intrinsic_op($(info.op)) vector operator$(info.name)(vector left, R right); __generic [__unsafeForceInlineEarly] vector operator$(info.name)=(in out vector left, R right) { left = left $(info.name) right; return left; } __generic __intrinsic_op($(info.op)) matrix operator$(info.name)(matrix left, R right); __generic [__unsafeForceInlineEarly] matrix operator$(info.name)=(in out matrix left, R right) { left = left $(info.name) right; return left; } ${{{{ } static const struct CompoundBinaryOpInfo { char const* name; char const* interface; } kCompoundBinaryOps[] = { { "+", "__BuiltinArithmeticType" }, { "-", "__BuiltinArithmeticType" }, { "*", "__BuiltinArithmeticType" }, { "/", "__BuiltinArithmeticType" }, { "%", "__BuiltinIntegerType" }, { "%", "__BuiltinFloatingPointType" }, { "&", "__BuiltinLogicalType" }, { "|", "__BuiltinLogicalType" }, { "^", "__BuiltinLogicalType" }, }; for( auto op : kCompoundBinaryOps ) { }}}} __generic [__unsafeForceInlineEarly] T operator$(op.name)=(in out T left, T right) { left = left $(op.name) right; return left; } __generic [__unsafeForceInlineEarly] vector operator$(op.name)=(in out vector left, vector right) { left = left $(op.name) right; return left; } __generic [__unsafeForceInlineEarly] vector operator$(op.name)=(in out vector left, T right) { left = left $(op.name) right; return left; } __generic [__unsafeForceInlineEarly] matrix operator$(op.name)=(in out matrix left, matrix right) { left = left $(op.name) right; return left; } __generic [__unsafeForceInlineEarly] matrix operator$(op.name)=(in out matrix left, T right) { left = left $(op.name) right; return left; } ${{{{ } }}}} //@ public: /// Bit cast between types. `T` and `U` must have the same size. /// They can be any scalar, vector, matrix, struct or array types. /// @category conversion __generic [__unsafeForceInlineEarly] __intrinsic_op($(kIROp_BitCast)) T bit_cast(U value); // Create Existential object __generic [__unsafeForceInlineEarly] __intrinsic_op($(kIROp_CreateExistentialObject)) T createDynamicObject(uint typeId, U value); /// Reinterpret type `U` as type `T`. `T` and `U` /// can be any scalar, vector, matrix, struct or array types. /// @category conversion __generic [__unsafeForceInlineEarly] __intrinsic_op($(kIROp_Reinterpret)) T reinterpret(U value); /// Use an otherwise unused value /// This can be used to silence the warning about returning before initializing an out paramter. __generic [__readNone] [ForceInline] __intrinsic_op($(kIROp_Unmodified)) void unused(inout T){} // This can be used to silence the warning about not writing to an inout parameter. __generic [__readNone] [ForceInline] __intrinsic_op($(kIROp_Unmodified)) void unmodified(out T){} // Specialized function /// Given a string returns an integer hash of that string. __intrinsic_op($(kIROp_GetStringHash)) int getStringHash(String string); /// Use will produce a syntax error in downstream compiler /// Useful for testing diagnostics around compilation errors of downstream compiler /// It 'returns' an int so can be used in expressions without the front end complaining. [require(cpp_cuda_glsl_hlsl)] int __SyntaxError() { __target_switch { case cpp: __intrinsic_asm " @ "; case cuda: __intrinsic_asm " @ "; case glsl: __intrinsic_asm " @ "; case hlsl: __intrinsic_asm " @ "; } } //@ hidden: /// For downstream compilers that allow sizeof/alignof/offsetof /// Can't be called in the C/C++ style. Need to use __size_of() as opposed to sizeof(some_type). __generic [__readNone] [require(cpp_cuda)] int __sizeOf() { __intrinsic_asm "sizeof($[0])", T; } __generic [__readNone] [require(cpp_cuda)] int __sizeOf(T v) { __target_switch { case cpp: __intrinsic_asm "sizeof($T0)"; case cuda: __intrinsic_asm "sizeof($T0)"; } } __generic [__readNone] [require(cpp_cuda)] int __alignOf() { __target_switch { case cuda : case cpp : __intrinsic_asm "SLANG_ALIGN_OF($[0])", T; } } __generic [__readNone] [require(cpp_cuda)] int __alignOf(T v) { __target_switch { case cpp: __intrinsic_asm "SLANG_ALIGN_OF($T0)"; case cuda: __intrinsic_asm "SLANG_ALIGN_OF($T0)"; } } // It would be nice to have offsetof equivalent, but it's not clear how that would work in terms of the Slang language. // Here we allow calculating the offset of a field in bytes from an *instance* of the type. __generic [__readNone] [require(cpp_cuda)] int __offsetOf(in T t, in F field) { __target_switch { case cpp: __intrinsic_asm "int(((char*)&($1)) - ((char*)&($0))"; case cuda: __intrinsic_asm "int(((char*)&($1)) - ((char*)&($0)))"; } } /// Mark beginning of "interlocked" operations in a fragment shader. [require(glsl_spirv, GL_ARB_fragment_shader_interlock, fragment)] __intrinsic_op($(kIROp_BeginFragmentShaderInterlock)) void beginInvocationInterlock(); /// Mark end of "interlocked" operations in a fragment shader. [require(glsl_spirv, GL_ARB_fragment_shader_interlock, fragment)] __intrinsic_op($(kIROp_EndFragmentShaderInterlock)) void endInvocationInterlock(); // Operators to apply to `enum` types //@ hidden: __generic __intrinsic_op($(kIROp_Eql)) bool operator==(E left, E right); __generic __intrinsic_op($(kIROp_Neq)) bool operator!=(E left, E right); //@ hidden: // public interfaces for generic arithmetic types. __generic [__unsafeForceInlineEarly] [OverloadRank(-10)] bool operator<(T v0, T v1) { return v0.lessThan(v1); } __generic [__unsafeForceInlineEarly] [OverloadRank(-10)] bool operator>(T v0, T v1) { return v1.lessThan(v0); } __generic [__unsafeForceInlineEarly] [OverloadRank(-10)] bool operator ==(T v0, T v1) { return v0.equals(v1); } __generic [__unsafeForceInlineEarly] [OverloadRank(-10)] bool operator >=(T v0, T v1) { return v1.lessThanOrEquals(v0); } __generic [__unsafeForceInlineEarly] [OverloadRank(-10)] bool operator <=(T v0, T v1) { return v0.lessThanOrEquals(v1); } __generic [__unsafeForceInlineEarly] [OverloadRank(-10)] bool operator !=(T v0, T v1) { return !v0.equals(v1); } ${{{{ const char* arithmeticInterfaces[] = {"IArithmetic", "IFloat"}; const char* attribs[] = {"", "[TreatAsDifferentiable]"}; for (Index i = 0; i < 2; i++) { const auto interfaceName = arithmeticInterfaces[i]; const auto attrib = attribs[i]; Index overloadRank = i - 3; }}}} $(attrib) __generic [__unsafeForceInlineEarly] [OverloadRank($(overloadRank))] T operator +(T v0, T v1) { return v0.add(v1); } $(attrib) __generic [__unsafeForceInlineEarly] [OverloadRank($(overloadRank))] T operator -(T v0, T v1) { return v0.sub(v1); } $(attrib) __generic [__unsafeForceInlineEarly] [OverloadRank($(overloadRank))] T operator *(T v0, T v1) { return v0.mul(v1); } $(attrib) __generic [__unsafeForceInlineEarly] [OverloadRank($(overloadRank))] T operator /(T v0, T v1) { return v0.div(v1); } $(attrib) __generic [__unsafeForceInlineEarly] [OverloadRank($(overloadRank))] T operator %(T v0, T v1) { return v0.mod(v1); } $(attrib) __generic [__unsafeForceInlineEarly] [OverloadRank($(overloadRank))] __prefix T operator -(T v0) { return v0.neg(); } ${{{{ } // foreach ["IArithmetic", "IFloat"] }}}} __generic [__unsafeForceInlineEarly] [OverloadRank(-10)] T operator &(T v0, T v1) { return v0.bitAnd(v1); } __generic [__unsafeForceInlineEarly] [OverloadRank(-10)] T operator &&(T v0, T v1) { return v0.and(v1); } [__unsafeForceInlineEarly] [OverloadRank(-10)] bool and(bool v0, bool v1) { return __and(v0, v1); } [__unsafeForceInlineEarly] [OverloadRank(-10)] __intrinsic_op($(kIROp_And)) vector and(vector v0, vector v1); [__unsafeForceInlineEarly] [OverloadRank(-10)] vector and(bool b, vector v) { return and(vector(b), v); } [__unsafeForceInlineEarly] [OverloadRank(-10)] vector and(vector v, bool b) { return and(v, vector(b)); } [__unsafeForceInlineEarly] [OverloadRank(-10)] bool or(bool v0, bool v1) { return __or(v0, v1); } [__unsafeForceInlineEarly] [OverloadRank(-10)] __intrinsic_op($(kIROp_Or)) vector or(vector v0, vector v1); [__unsafeForceInlineEarly] [OverloadRank(-10)] vector or(bool b, vector v) { return or(vector(b), v); } [__unsafeForceInlineEarly] [OverloadRank(-10)] vector or(vector v, bool b) { return or(v, vector(b)); } __generic [__unsafeForceInlineEarly] [OverloadRank(-10)] T operator |(T v0, T v1) { return v0.bitOr(v1); } __generic [__unsafeForceInlineEarly] [OverloadRank(-10)] T operator ||(T v0, T v1) { return v0.or(v1); } __generic [__unsafeForceInlineEarly] [OverloadRank(-10)] T operator ^(T v0, T v1) { return v0.bitXor(v1); } __generic [__unsafeForceInlineEarly] [OverloadRank(-10)] __prefix T operator ~(T v0) { return v0.bitNot(); } __generic [__unsafeForceInlineEarly] [OverloadRank(-10)] __prefix T operator !(T v0) { return v0.not(); } // The operator overloads defined above already allows Enum types to be used // in logical operators, but we still provide overloads for __EnumTypes and map // them directly to intrinsic op to allow constant propagation at AST level to // work on enum types. __generic [__unsafeForceInlineEarly] __intrinsic_op($(kIROp_BitAnd)) T operator &(T v0, T v1); __generic [__unsafeForceInlineEarly] __intrinsic_op($(kIROp_BitOr)) T operator |(T v0, T v1); __generic [__unsafeForceInlineEarly] __intrinsic_op($(kIROp_BitNot)) __prefix T operator ~(T v0); // IR level type traits. __generic __intrinsic_op($(kIROp_undefined)) T __declVal(); __generic __intrinsic_op($(kIROp_DefaultConstruct)) T __default(); __generic __intrinsic_op($(kIROp_TypeEquals)) bool __type_equals_impl(T t, U u); __generic [__unsafeForceInlineEarly] bool __type_equals(T t, U u) { return __type_equals_impl(__declVal(), __declVal()); } __generic [__unsafeForceInlineEarly] bool __type_equals() { return __type_equals_impl(__declVal(), __declVal()); } __generic __intrinsic_op($(kIROp_IsBool)) bool __isBool_impl(T t); __generic [__unsafeForceInlineEarly] bool __isBool() { return __isBool_impl(__declVal()); } __generic __intrinsic_op($(kIROp_IsInt)) bool __isInt_impl(T t); __generic [__unsafeForceInlineEarly] bool __isInt() { return __isInt_impl(__declVal()); } __generic __intrinsic_op($(kIROp_IsFloat)) bool __isFloat_impl(T t); __generic __intrinsic_op($(kIROp_IsHalf)) bool __isHalf_impl(T t); __generic [__unsafeForceInlineEarly] bool __isFloat() { return __isFloat_impl(__declVal()); } __generic [__unsafeForceInlineEarly] bool __isHalf() { return __isHalf_impl(__declVal()); } __generic __intrinsic_op($(kIROp_IsUnsignedInt)) bool __isUnsignedInt_impl(T t); __generic [__unsafeForceInlineEarly] bool __isUnsignedInt() { return __isUnsignedInt_impl(__declVal()); } __generic __intrinsic_op($(kIROp_IsSignedInt)) bool __isSignedInt_impl(T t); __generic [__unsafeForceInlineEarly] bool __isSignedInt() { return __isSignedInt_impl(__declVal()); } __generic __intrinsic_op($(kIROp_IsVector)) bool __isVector_impl(T t); __generic [__unsafeForceInlineEarly] bool __isVector() { return __isVector_impl(__declVal()); } __generic __intrinsic_op($(kIROp_GetNaturalStride)) int __naturalStrideOf_impl(T v); __generic [__unsafeForceInlineEarly] int __naturalStrideOf() { return __naturalStrideOf_impl(__declVal()); } __intrinsic_op($(kIROp_AlignOf)) int __alignOf_intrinsic_impl(T t); [ForceInline] int __alignOf_intrinsic() { return __alignOf_intrinsic_impl(__default()); } __intrinsic_op($(kIROp_TreatAsDynamicUniform)) T asDynamicUniform(T v); __generic __intrinsic_op( $(kIROp_GetLegalizedSPIRVGlobalParamAddr)) __Addr __getLegalizedSPIRVGlobalParamAddr(T val); __intrinsic_op($(kIROp_RequireComputeDerivative)) void __requireComputeDerivative(); //@ public: /// @category misc_types enum MemoryOrder { Relaxed = $(kIRMemoryOrder_Relaxed), Acquire = $(kIRMemoryOrder_Acquire), Release = $(kIRMemoryOrder_Release), AcquireRelease = $(kIRMemoryOrder_AcquireRelease), SeqCst = $(kIRMemoryOrder_SeqCst), } [sealed] interface IAtomicable {} [sealed] interface IArithmeticAtomicable : IAtomicable, IArithmetic {} [sealed] interface IBitAtomicable : IArithmeticAtomicable, IInteger {} extension int : IBitAtomicable {} extension uint : IBitAtomicable {} extension int64_t : IBitAtomicable {} extension uint64_t : IBitAtomicable {} extension double : IArithmeticAtomicable {} extension float : IArithmeticAtomicable {} extension half : IArithmeticAtomicable {} __magic_type(AtomicType) __intrinsic_type($(kIROp_AtomicType)) [require(cuda_glsl_hlsl_metal_spirv_wgsl)] struct Atomic { __intrinsic_op($(kIROp_AtomicLoad)) [__ref] T load(MemoryOrder order = MemoryOrder.Relaxed); __intrinsic_op($(kIROp_AtomicStore)) [__ref] void store(T newValue, MemoryOrder order = MemoryOrder.Relaxed); __intrinsic_op($(kIROp_AtomicExchange)) [__ref] T exchange(T newValue, MemoryOrder order = MemoryOrder.Relaxed); // returns old value __intrinsic_op($(kIROp_AtomicCompareExchange)) [__ref] T compareExchange( T compareValue, T newValue, MemoryOrder successOrder = MemoryOrder.Relaxed, MemoryOrder failOrder = MemoryOrder.Relaxed); } /// These addtional members are only available when `T` conforms to `IArithmeticAtomicable`. extension Atomic { __intrinsic_op($(kIROp_AtomicAdd)) [__ref] T add(T value, MemoryOrder order = MemoryOrder.Relaxed); // returns original value __intrinsic_op($(kIROp_AtomicSub)) [__ref] T sub(T value, MemoryOrder order = MemoryOrder.Relaxed); // returns original value __intrinsic_op($(kIROp_AtomicMax)) [__ref] T max(T value, MemoryOrder order = MemoryOrder.Relaxed); // returns original value __intrinsic_op($(kIROp_AtomicMin)) [__ref] T min(T value, MemoryOrder order = MemoryOrder.Relaxed); // returns original value } /// These addtional members are only available when `T` conforms to `IBitAtomicable`. extension Atomic { __intrinsic_op($(kIROp_AtomicAnd)) [__ref] T and(T value, MemoryOrder order = MemoryOrder.Relaxed); // returns original value __intrinsic_op($(kIROp_AtomicOr)) [__ref] T or(T value, MemoryOrder order = MemoryOrder.Relaxed); // returns original value __intrinsic_op($(kIROp_AtomicXor)) [__ref] T xor(T value, MemoryOrder order = MemoryOrder.Relaxed); // returns original value __intrinsic_op($(kIROp_AtomicInc)) [__ref] T increment(MemoryOrder order = MemoryOrder.Relaxed); __intrinsic_op($(kIROp_AtomicDec)) [__ref] T decrement(MemoryOrder order = MemoryOrder.Relaxed); } //@ hidden: __generic [ForceInline] T operator +=(__ref Atomic v, T value) { return v.add(value) + value; } __generic [ForceInline] T operator -=(__ref Atomic v, T value) { return v.sub(value) - value; } __generic [ForceInline] T operator &=(__ref Atomic v, T value) { return v.and(value) & value; } __generic [ForceInline] T operator |=(__ref Atomic v, T value) { return v.or(value) | value; } __generic [ForceInline] T operator ^=(__ref Atomic v, T value) { return v.xor(value) ^ value; } __generic [ForceInline] __prefix T operator ++(__ref Atomic v) { return v.increment() + T(1); } __generic [ForceInline] __postfix T operator ++(__ref Atomic v) { return v.increment(); } __generic [ForceInline] __prefix T operator --(__ref Atomic v) { return v.decrement() - T(1); } __generic [ForceInline] __postfix T operator --(__ref Atomic v) { return v.decrement(); } // Binding Attributes __attributeTarget(DeclBase) attribute_syntax [vk_binding(binding: int, set: int = 0)] : GLSLBindingAttribute; __attributeTarget(DeclBase) attribute_syntax [gl_binding(binding: int, set: int = 0)] : GLSLBindingAttribute; __attributeTarget(VarDeclBase) attribute_syntax [vk_shader_record] : ShaderRecordAttribute; __attributeTarget(VarDeclBase) attribute_syntax [shader_record] : ShaderRecordAttribute; __attributeTarget(VarDeclBase) attribute_syntax [vk_push_constant] : PushConstantAttribute; __attributeTarget(VarDeclBase) attribute_syntax [push_constant] : PushConstantAttribute; __attributeTarget(VarDeclBase) attribute_syntax[vk_specialization_constant] : SpecializationConstantAttribute; __attributeTarget(VarDeclBase) attribute_syntax[SpecializationConstant] : SpecializationConstantAttribute; __attributeTarget(VarDeclBase) attribute_syntax[vk_constant_id(location: int)] : VkConstantIdAttribute; __attributeTarget(VarDeclBase) attribute_syntax [vk_location(location : int)] : GLSLLocationAttribute; __attributeTarget(VarDeclBase) attribute_syntax [vk_index(index : int)] : GLSLIndexAttribute; __attributeTarget(FuncDecl) attribute_syntax [vk_spirv_instruction(op : int, set : String = "")] : SPIRVInstructionOpAttribute; __attributeTarget(VarDeclBase) attribute_syntax [vk_input_attachment_index(location : int)] : GLSLInputAttachmentIndexLayoutAttribute; __attributeTarget(FuncDecl) attribute_syntax [spv_target_env_1_3] : SPIRVTargetEnv13Attribute; __attributeTarget(VarDeclBase) attribute_syntax [disable_array_flattening] : DisableArrayFlatteningAttribute; __attributeTarget(EnumDecl) attribute_syntax [UnscopedEnum] : UnscopedEnumAttribute; __attributeTarget(EnumDecl) attribute_syntax[Flags] : FlagsAttribute; // Statement Attributes __attributeTarget(LoopStmt) attribute_syntax [unroll(count: int = 0)] : UnrollAttribute; __attributeTarget(LoopStmt) attribute_syntax [ForceUnroll(count: int = 0)] : ForceUnrollAttribute; __attributeTarget(LoopStmt) attribute_syntax [loop] : LoopAttribute; __attributeTarget(LoopStmt) attribute_syntax [fastopt] : FastOptAttribute; __attributeTarget(LoopStmt) attribute_syntax [allow_uav_condition] : AllowUAVConditionAttribute; __attributeTarget(LoopStmt) attribute_syntax [MaxIters(count)] : MaxItersAttribute; __attributeTarget(IfStmt) attribute_syntax [flatten] : FlattenAttribute; __attributeTarget(IfStmt) __attributeTarget(SwitchStmt) attribute_syntax [branch] : BranchAttribute; __attributeTarget(SwitchStmt) attribute_syntax [forcecase] : ForceCaseAttribute; __attributeTarget(SwitchStmt) attribute_syntax [call] : CallAttribute; // Entry-point Attributes // All Stages __attributeTarget(FuncDecl) attribute_syntax [shader(stage)] : EntryPointAttribute; __attributeTarget(FuncDecl) attribute_syntax [Shader(stage)] : EntryPointAttribute; // Hull Shader __attributeTarget(FuncDecl) attribute_syntax [maxtessfactor(factor: float)] : MaxTessFactorAttribute; __attributeTarget(FuncDecl) attribute_syntax [outputcontrolpoints(count: int)] : OutputControlPointsAttribute; __attributeTarget(FuncDecl) attribute_syntax [outputtopology(topology)] : OutputTopologyAttribute; __attributeTarget(FuncDecl) attribute_syntax [partitioning(mode)] : PartitioningAttribute; __attributeTarget(FuncDecl) attribute_syntax [patchconstantfunc(name)] : PatchConstantFuncAttribute; // Hull/Domain Shader __attributeTarget(FuncDecl) attribute_syntax [domain(domain)] : DomainAttribute; // Geometry Shader __attributeTarget(FuncDecl) attribute_syntax [maxvertexcount(count: int)] : MaxVertexCountAttribute; __attributeTarget(FuncDecl) attribute_syntax [instance(count: int)] : InstanceAttribute; // Fragment ("Pixel") Shader __attributeTarget(FuncDecl) attribute_syntax [earlydepthstencil] : EarlyDepthStencilAttribute; // Compute Shader __attributeTarget(FuncDecl) attribute_syntax [numthreads(x: int, y: int = 1, z: int = 1)] : NumThreadsAttribute; __attributeTarget(FuncDecl) attribute_syntax [NumThreads(x: int, y: int = 1, z: int = 1)] : NumThreadsAttribute; __attributeTarget(FuncDecl) attribute_syntax [WaveSize(numLanes: int)] : WaveSizeAttribute; // __attributeTarget(VarDeclBase) attribute_syntax [__vulkanRayPayload(location : int = -1)] : VulkanRayPayloadAttribute; __attributeTarget(VarDeclBase) attribute_syntax [__vulkanCallablePayload(location : int = -1)] : VulkanCallablePayloadAttribute; __attributeTarget(VarDeclBase) attribute_syntax [__vulkanHitObjectAttributes(location : int = -1)] : VulkanHitObjectAttributesAttribute; __attributeTarget(VarDeclBase) attribute_syntax [__vulkanHitAttributes] : VulkanHitAttributesAttribute; __attributeTarget(FunctionDeclBase) attribute_syntax [mutating] : MutatingAttribute; __attributeTarget(AccessorDecl) attribute_syntax [nonmutating] : NonmutatingAttribute; __attributeTarget(FunctionDeclBase) attribute_syntax [constref] : ConstRefAttribute; __attributeTarget(FunctionDeclBase) attribute_syntax [__ref] : RefAttribute; /// Indicates that a function computes its result as a function of its arguments without loading/storing any memory or other state. /// /// This is equivalent to the LLVM `readnone` function attribute. __attributeTarget(FunctionDeclBase) attribute_syntax [__readNone] : ReadNoneAttribute; enum _AttributeTargets { Struct = $( (int) UserDefinedAttributeTargets::Struct), Var = $( (int) UserDefinedAttributeTargets::Var), Function = $( (int) UserDefinedAttributeTargets::Function), Param = $( (int) UserDefinedAttributeTargets::Param), }; __attributeTarget(StructDecl) attribute_syntax [__AttributeUsage(target : _AttributeTargets)] : AttributeUsageAttribute; __attributeTarget(VarDeclBase) attribute_syntax [format(format : String)] : FormatAttribute; __attributeTarget(VarDeclBase) attribute_syntax [vk_image_format(format : String)] : FormatAttribute; __attributeTarget(Decl) attribute_syntax [allow(diagnostic: String)] : AllowAttribute; __attributeTarget(Decl) attribute_syntax [require(capability)] : RequireCapabilityAttribute; // Linking __attributeTarget(Decl) attribute_syntax [__extern] : ExternAttribute; __attributeTarget(FunctionDeclBase) attribute_syntax [__unsafeForceInlineEarly] : UnsafeForceInlineEarlyAttribute; __attributeTarget(FunctionDeclBase) attribute_syntax [ForceInline] : ForceInlineAttribute; __attributeTarget(FunctionDeclBase) attribute_syntax [OverloadRank] : OverloadRankAttribute; __attributeTarget(FuncDecl) attribute_syntax [DllImport(modulePath: String)] : DllImportAttribute; __attributeTarget(FuncDecl) attribute_syntax [DllExport] : DllExportAttribute; __attributeTarget(FuncDecl) attribute_syntax [TorchEntryPoint] : TorchEntryPointAttribute; __attributeTarget(FuncDecl) attribute_syntax [CudaDeviceExport] : CudaDeviceExportAttribute; __attributeTarget(FuncDecl) attribute_syntax [CudaHost] : CudaHostAttribute; __attributeTarget(FuncDecl) attribute_syntax [CudaKernel] : CudaKernelAttribute; __attributeTarget(FuncDecl) attribute_syntax [CUDADeviceExport] : CudaDeviceExportAttribute; __attributeTarget(FuncDecl) attribute_syntax [CUDAHost] : CudaHostAttribute; __attributeTarget(FuncDecl) attribute_syntax [CUDAKernel] : CudaKernelAttribute; __attributeTarget(FuncDecl) attribute_syntax [AutoPyBindCUDA] : AutoPyBindCudaAttribute; __attributeTarget(AggTypeDecl) attribute_syntax [PyExport(name: String)] : PyExportAttribute; __attributeTarget(InterfaceDecl) attribute_syntax [COM(guid: String)] : ComInterfaceAttribute; // Inheritance Control __attributeTarget(AggTypeDecl) attribute_syntax [sealed] : SealedAttribute; __attributeTarget(AggTypeDecl) attribute_syntax [open] : OpenAttribute; __attributeTarget(InterfaceDecl) attribute_syntax [anyValueSize(size:int)] : AnyValueSizeAttribute; __attributeTarget(InterfaceDecl) attribute_syntax [Specialize] : SpecializeAttribute; __attributeTarget(DeclBase) attribute_syntax [builtin] : BuiltinAttribute; __attributeTarget(DeclBase) attribute_syntax[__AutoDiffBuiltin] : AutoDiffBuiltinAttribute; __attributeTarget(DeclBase) attribute_syntax [__requiresNVAPI] : RequiresNVAPIAttribute; __attributeTarget(AggTypeDecl) attribute_syntax[RequirePrelude(target, prelude:String)] : RequirePreludeAttribute; __attributeTarget(DeclBase) attribute_syntax [__AlwaysFoldIntoUseSiteAttribute] : AlwaysFoldIntoUseSiteAttribute; __attributeTarget(FunctionDeclBase) attribute_syntax [noinline] : NoInlineAttribute; __attributeTarget(StructDecl) attribute_syntax [payload] : PayloadAttribute; __attributeTarget(DeclBase) attribute_syntax [deprecated(message: String)] : DeprecatedAttribute; enum SideEffectBehavior { /// Causes a warning if the method is detected to have side-effects Warn = 0, /// Suppresses the warning Allow = 1 }; __attributeTarget(FunctionDeclBase) attribute_syntax[PreferRecompute(behavior: SideEffectBehavior = SideEffectBehavior.Warn)] : PreferRecomputeAttribute; __attributeTarget(FunctionDeclBase) attribute_syntax [PreferCheckpoint] : PreferCheckpointAttribute; __attributeTarget(DeclBase) attribute_syntax [KnownBuiltin(name : String)] : KnownBuiltinAttribute; __attributeTarget(FunctionDeclBase) attribute_syntax [NonUniformReturn] : NonDynamicUniformAttribute; __attributeTarget(FunctionDeclBase) attribute_syntax [__GLSLRequireShaderInputParameter(parameterNumber:int)] : GLSLRequireShaderInputParameterAttribute; __attributeTarget(FuncDecl) attribute_syntax [DerivativeGroupQuad] : DerivativeGroupQuadAttribute; __attributeTarget(FuncDecl) attribute_syntax [DerivativeGroupLinear] : DerivativeGroupLinearAttribute; __attributeTarget(FuncDecl) attribute_syntax [noRefInline] : NoRefInlineAttribute;