-- -- This file contains the canonical definitions for the instions to the Slang IR. -- -- Add new instructions here. -- -- !! -- !! Please make sure to update the supported module versions in -- !! Slang::IRModule accordingly when modifying this file. -- !! -- -- For a detailed description of the schema, please see docs/design/ir-instruction-definition.md -- local insts = { { nop = {} }, -- This opcode is used as a placeholder if we were ever to deserialize a -- module which contains an instruction we don't have defined in this file, -- it should never appear except immediately after deserialization. { Unrecognized = {} }, { Type = { { BasicType = { hoistable = true, { Void = { struct_name = "VoidType" } }, { Bool = { struct_name = "BoolType" } }, { Int8 = { struct_name = "Int8Type" } }, { Int16 = { struct_name = "Int16Type" } }, { Int = { struct_name = "IntType" } }, { Int64 = { struct_name = "Int64Type" } }, { UInt8 = { struct_name = "UInt8Type" } }, { UInt16 = { struct_name = "UInt16Type" } }, { UInt = { struct_name = "UIntType" } }, { UInt64 = { struct_name = "UInt64Type" } }, { Half = { struct_name = "HalfType" } }, { Float = { struct_name = "FloatType" } }, { Double = { struct_name = "DoubleType" } }, { Char = { struct_name = "CharType" } }, { IntPtr = { struct_name = "IntPtrType" } }, { UIntPtr = { struct_name = "UIntPtrType" } }, }, }, { AfterBaseType = {} }, { StringTypeBase = { hoistable = true, { String = { struct_name = "StringType" } }, { NativeString = { struct_name = "NativeStringType" } }, }, }, { CapabilitySet = { struct_name = "CapabilitySetType", hoistable = true } }, { DynamicType = { hoistable = true } }, { AnyValueType = { operands = { { "size" } }, hoistable = true } }, { RawPointerTypeBase = { hoistable = true, { RawPointerType = {} }, { RTTIPointerType = { operands = { { "rTTIOperand" } } } }, { AfterRawPointerTypeBase = {} }, }, }, { ArrayTypeBase = { hoistable = true, { Array = { struct_name = "ArrayType", min_operands = 2 } }, { UnsizedArray = { struct_name = "UnsizedArrayType", min_operands = 1 } }, }, }, { Func = { struct_name = "FuncType", hoistable = true } }, { BasicBlock = { struct_name = "BasicBlockType", hoistable = true } }, { Vec = { struct_name = "VectorType", operands = { { "elementType", "IRType" }, { "elementCount" } }, hoistable = true } }, { Mat = { struct_name = "MatrixType", operands = { { "elementType", "IRType" }, { "rowCount" }, { "columnCount" }, { "layout" } }, hoistable = true } }, { Conjunction = { struct_name = "ConjunctionType", hoistable = true } }, { Attributed = { struct_name = "AttributedType", operands = { { "baseType", "IRType" }, { "attr" } }, hoistable = true } }, { Result = { struct_name = "ResultType", operands = { { "valueType", "IRType" }, { "errorType", "IRType" } }, hoistable = true } }, { Optional = { struct_name = "OptionalType", operands = { { "valueType", "IRType" } }, hoistable = true } }, { Enum = { struct_name = "EnumType", operands = { { "tagType", "IRType" } }, parent = true } }, { DifferentialPairTypeBase = { hoistable = true, { DiffPair = { struct_name = "DifferentialPairType", min_operands = 1 } }, { DiffPairUserCode = { struct_name = "DifferentialPairUserCodeType", min_operands = 1 } }, { DiffRefPair = { struct_name = "DifferentialPtrPairType", min_operands = 1 } }, }, }, { BwdDiffIntermediateCtxType = { struct_name = "BackwardDiffIntermediateContextType", operands = { { "func" } }, hoistable = true, }, }, { TensorView = { struct_name = "TensorViewType", operands = { { "elementType", "IRType" } }, hoistable = true } }, { TorchTensor = { struct_name = "TorchTensorType", hoistable = true } }, { ArrayListVector = { struct_name = "ArrayListType", operands = { { "elementType", "IRType" } }, hoistable = true } }, { Atomic = { struct_name = "AtomicType", operands = { { "elementType", "IRType" } }, hoistable = true } }, { BindExistentialsTypeBase = { hoistable = true, { BindExistentials = { -- A `BindExistentials` represents -- taking type `B` and binding each of its existential type -- parameters, recursively, with the specified arguments, -- where each `Ti, wi` pair represents the concrete type -- and witness table to plug in for parameter `i`. struct_name = "BindExistentialsType", min_operands = 1, }, }, { BoundInterface = { -- An `BindInterface` represents the special case -- of a `BindExistentials` where the type `B` is known to be -- an interface type. struct_name = "BoundInterfaceType", min_operands = 3, }, }, }, }, { Rate = { hoistable = true, { ConstExpr = { struct_name = "ConstExprRate" } }, { SpecConst = { struct_name = "SpecConstRate" } }, { GroupShared = { struct_name = "GroupSharedRate" } }, { ActualGlobalRate = {} }, }, }, { RateQualified = { struct_name = "RateQualifiedType", operands = { { "rate", "IRRate" }, { "valueType", "IRType" } }, hoistable = true } }, { Kind = { -- Kinds represent the "types of types." -- They should not really be nested under `IRType` -- in the overall hierarchy, but we can fix that later. hoistable = true, { Type = { struct_name = "TypeKind" } }, { TypeParameterPack = { struct_name = "TypeParameterPackKind" } }, { Rate = { struct_name = "RateKind" } }, { Generic = { struct_name = "GenericKind" } }, }, }, { PtrTypeBase = { hoistable = true, { Ptr = { struct_name = "PtrType", min_operands = 1 } }, { RefParam = { struct_name = "RefParamType", min_operands = 1 } }, { BorrowInParam = { struct_name = "BorrowInParamType", min_operands = 1 } }, { PseudoPtr = { -- A `PsuedoPtr` logically represents a pointer to a value of type -- `T` on a platform that cannot support pointers. The expectation -- is that the "pointer" will be legalized away by storing a value -- of type `T` somewhere out-of-line. struct_name = "PseudoPtrType", min_operands = 1, }, }, { OutParamTypeBase = { { OutParam = { struct_name = "OutParamType", min_operands = 1 } }, { BorrowInOutParam = { struct_name = "BorrowInOutParamType", min_operands = 1 } }, }, }, }, }, { ComPtr = { -- A ComPtr type is treated as a opaque type that represents a reference-counted handle to a COM object. struct_name = "ComPtrType", operands = { { "valueType", "IRType" } }, hoistable = true, }, }, { NativePtr = { -- A NativePtr type represents a native pointer to a managed resource. struct_name = "NativePtrType", operands = { { "valueType", "IRType" } }, hoistable = true, }, }, { DescriptorHandle = { -- A DescriptorHandle type represents a bindless handle to an opaue resource type. struct_name = "DescriptorHandleType", operands = { { "resourceType", "IRType" } }, hoistable = true, }, }, { GLSLAtomicUint = { -- An AtomicUint is a placeholder type for a storage buffer, and will be mangled during compiling. struct_name = "GLSLAtomicUintType", hoistable = true, }, }, { SamplerStateTypeBase = { hoistable = true, { SamplerState = { struct_name = "SamplerStateType" } }, { SamplerComparisonState = { struct_name = "SamplerComparisonStateType" } }, }, }, { DefaultLayout = { struct_name = "DefaultBufferLayoutType", hoistable = true } }, { Std140Layout = { struct_name = "Std140BufferLayoutType", hoistable = true } }, { Std430Layout = { struct_name = "Std430BufferLayoutType", hoistable = true } }, { ScalarLayout = { struct_name = "ScalarBufferLayoutType", hoistable = true } }, { CLayout = { struct_name = "CBufferLayoutType", hoistable = true } }, { SubpassInputType = { operands = { { "elementType", "IRType" }, { "isMultisampleInst" } }, hoistable = true } }, { TextureFootprintType = { min_operands = 1, hoistable = true } }, { TextureShape1DType = { hoistable = true } }, { TextureShape2DType = { struct_name = "TextureShape2DType", hoistable = true } }, { TextureShape3DType = { struct_name = "TextureShape3DType", hoistable = true } }, { TextureShapeCubeDType = { struct_name = "TextureShapeCubeType", hoistable = true } }, { TextureShapeBufferType = { hoistable = true } }, { ResourceTypeBase = { -- TODO: Why do we have all this hierarchy here, when everything -- that actually matters is currently nested under `TextureTypeBase`? { ResourceType = { { TextureTypeBase = { { TextureType = { min_operands = 8, hoistable = true }, }, { GLSLImageType = { use_other = true, hoistable = true } }, }, }, }, }, }, }, { UntypedBufferResourceType = { hoistable = true, { ByteAddressBufferTypeBase = { { ByteAddressBuffer = { struct_name = "HLSLByteAddressBufferType" } }, { RWByteAddressBuffer = { struct_name = "HLSLRWByteAddressBufferType" } }, { RasterizerOrderedByteAddressBuffer = { struct_name = "HLSLRasterizerOrderedByteAddressBufferType", }, }, }, }, { RaytracingAccelerationStructure = { struct_name = "RaytracingAccelerationStructureType" } }, }, }, { HLSLPatchType = { hoistable = true, { InputPatch = { struct_name = "HLSLInputPatchType", min_operands = 2 } }, { OutputPatch = { struct_name = "HLSLOutputPatchType", min_operands = 2 } }, }, }, { GLSLInputAttachment = { struct_name = "GLSLInputAttachmentType", hoistable = true } }, { BuiltinGenericType = { hoistable = true, { HLSLStreamOutputType = { { PointStream = { struct_name = "HLSLPointStreamType", min_operands = 1 } }, { LineStream = { struct_name = "HLSLLineStreamType", min_operands = 1 } }, { TriangleStream = { struct_name = "HLSLTriangleStreamType", min_operands = 1 } }, }, }, { MeshOutputType = { { Vertices = { struct_name = "VerticesType", min_operands = 2 } }, { Indices = { struct_name = "IndicesType", min_operands = 2 } }, { Primitives = { struct_name = "PrimitivesType", min_operands = 2 } }, }, }, { ["metal::mesh"] = { struct_name = "MetalMeshType", operands = { { "verticesType", "IRType" }, { "primitivesType", "IRType" }, { "numVertices" }, { "numPrimitives" }, { "topology", "IRIntLit" } } } }, { mesh_grid_properties = { struct_name = "MetalMeshGridPropertiesType" } }, { HLSLStructuredBufferTypeBase = { { StructuredBuffer = { struct_name = "HLSLStructuredBufferType" } }, { RWStructuredBuffer = { struct_name = "HLSLRWStructuredBufferType" } }, { RasterizerOrderedStructuredBuffer = { struct_name = "HLSLRasterizerOrderedStructuredBufferType", }, }, { AppendStructuredBuffer = { struct_name = "HLSLAppendStructuredBufferType" } }, { ConsumeStructuredBuffer = { struct_name = "HLSLConsumeStructuredBufferType" } }, }, }, { PointerLikeType = { { ParameterGroupType = { { UniformParameterGroupType = { { ConstantBuffer = { struct_name = "ConstantBufferType", min_operands = 1, }, }, { TextureBuffer = { struct_name = "TextureBufferType", min_operands = 1 } }, { ParameterBlock = { struct_name = "ParameterBlockType", min_operands = 1, }, }, }, }, { VaryingParameterGroupType = { { GLSLInputParameterGroup = { struct_name = "GLSLInputParameterGroupType", }, }, { GLSLOutputParameterGroup = { struct_name = "GLSLOutputParameterGroupType", }, }, }, }, { GLSLShaderStorageBuffer = { struct_name = "GLSLShaderStorageBufferType", min_operands = 1, }, }, }, }, }, }, }, }, { RayQuery = { -- Types struct_name = "RayQueryType", min_operands = 1, hoistable = true, }, }, { HitObject = { struct_name = "HitObjectType", hoistable = true, }, }, { CoopVectorType = { operands = { { "elementType", "IRType"}, { "elementCount" } }, hoistable = true } }, { CoopMatrixType = { operands = { { "elementType", "IRType"}, { "scope" }, { "rowCount" }, { "columnCount" }, { "matrixUse" } }, hoistable = true } }, { TensorAddressingTensorLayoutType = { operands = { { "dimension"}, { "clampMode" } }, hoistable = true }, }, { TensorAddressingTensorViewType = { min_operands = 3, hoistable = true, }, }, { MakeTensorAddressingTensorLayout = {} }, { MakeTensorAddressingTensorView = {} }, { DynamicResource = { -- Opaque type that can be dynamically cast to other resource types. struct_name = "DynamicResourceType", hoistable = true, }, }, { struct = { -- A user-defined structure declaration at the IR level. -- Unlike in the AST where there is a distinction between -- a `StructDecl` and a `DeclRefType` that refers to it, -- at the IR level the struct declaration and the type -- are the same IR instruction. -- -- This is a parent instruction that holds zero or more -- `field` instructions. struct_name = "StructType", parent = true, }, }, { class = { struct_name = "ClassType", parent = true }, }, { interface = { struct_name = "InterfaceType", global = true } }, { associated_type = { hoistable = true } }, { this_type = { hoistable = true } }, { rtti_type = { struct_name = "RTTIType", hoistable = true } }, { rtti_handle_type = { struct_name = "RTTIHandleType", hoistable = true, }, }, { TupleTypeBase = { hoistable = true, { tuple_type = {} }, { TypePack = {} }, }, }, { TargetTuple = { struct_name = "TargetTupleType", hoistable = true } }, { ExpandTypeOrVal = { min_operands = 1, hoistable = true } }, { spirvLiteralType = { -- A type that identifies it's contained type as being emittable as `spirv_literal. struct_name = "SPIRVLiteralType", operands = { { "valueType", "IRType" } }, hoistable = true, }, }, { type_t = { -- A TypeType-typed IRValue represents a IRType. -- It is used to represent a type parameter/argument in a generics. struct_name = "TypeType", hoistable = true, }, }, { WitnessTableTypeBase = { -- IRWitnessTableTypeBase hoistable = true, { witness_table_t = { -- An `IRWitnessTable` has type `WitnessTableType`. struct_name = "WitnessTableType", min_operands = 1, }, }, { witness_table_id_t = { -- An integer type representing a witness table for targets where -- witness tables are represented as integer IDs. This type is used -- during the lower-generics pass while generating dynamic dispatch -- code and will eventually lower into an uint type. struct_name = "WitnessTableIDType", min_operands = 1, }, }, }, }, }, }, -- IRGlobalValueWithCode { GlobalValueWithCode = { { GlobalValueWithParams = { -- IRGlobalValueWithParams parent = true, { func = {} }, { generic = {} }, }, }, { global_var = { global = true } }, }, }, { global_param = { global = true } }, { globalConstant = { global = true }, }, { key = { struct_name = "StructKey", global = true } }, { global_generic_param = { global = true } }, { witness_table = { hoistable = true } }, { indexedFieldKey = { min_operands = 2, hoistable = true } }, -- A placeholder witness that ThisType implements the enclosing interface. -- Used only in interface definitions. { thisTypeWitness = { min_operands = 1 } }, -- A placeholder witness for the fact that two types are equal. { TypeEqualityWitness = { min_operands = 2, hoistable = true } }, { global_hashed_string_literals = {} }, { module = { struct_name = "ModuleInst", parent = true }, }, { block = { parent = true } }, -- A global inst representing an alias of another symbol, under a different mangled name. -- This inst should be completely eliminated after linking, with its references replaced -- to use the canonical symbol being aliased. { SymbolAlias = { min_operands = 1 } }, -- IRConstant { Constant = { { boolConst = { struct_name = "BoolLit" } }, { integer_constant = { struct_name = "IntLit" }, }, { float_constant = { struct_name = "FloatLit" } }, { ptr_constant = { struct_name = "PtrLit" }, }, { void_constant = { struct_name = "VoidLit" } }, { string_constant = { struct_name = "StringLit" } }, { blob_constant = { struct_name = "BlobLit" }, }, }, }, { CapabilitySet = { hoistable = true, { capabilityConjunction = {} }, { capabilityDisjunction = {} } } }, -- Instructions that represent something with an undefined value. { Undefined = { -- A load from a memory location that is known to be uninitialized. -- -- Primarily used so that the compiler front-end can diagnose an error on such cases. -- -- A given `LoadFromUninitializedMemory` might evaluate to an arbitrary value of its type, -- and an optimization pass may freely decide on a particular value to use and replace -- all uses of the instruction with that value. -- -- If there are multiple distinct `LoadFromUninitializedMemory` instructions, then they -- might each yield a different value, even if they all reference the same memory -- location. -- -- Akin to `freeze(undefined)` in LLVM. -- { LoadFromUninitializedMemory = {} }, -- An undefined value that is infectious. -- -- Semantically, a poison value of some type T can be thought of as a -- hypothetical out-of-band instance of type T, akin to a T-specific NaN -- value (although a poison `float` is distinct from a `float` NaN value...). -- The motivation for this interpretation is that it allows most optimizations -- to ignore the possibility of poison/undefined values, while still being -- semantically correct. -- -- In most cases, an instruction that is executed with a poison value as one -- of its operands yields a poison value as its result. The main exception -- is instructions that only conditionally use an operand, such as `select`, -- and block/function parameters (just because one branch passes a poison -- argument for a parmeter, that doesn't mean the parameter would be poison -- every time the block executes). -- -- Corresponds to the LLVM `poison` instruction. -- { Poison = {} }, }}, -- A `defaultConstruct` operation creates an initialized -- value of the result type, and can only be used for types -- where default construction is a meaningful thing to do. { defaultConstruct = {} }, { MakeDifferentialPairBase = { { MakeDiffPair = { struct_name = "MakeDifferentialPair", min_operands = 2 } }, { MakeDiffPairUserCode = { struct_name = "MakeDifferentialPairUserCode", min_operands = 2 } }, { MakeDiffRefPair = { struct_name = "MakeDifferentialPtrPair", min_operands = 2 }, }, }, }, { DifferentialPairGetDifferentialBase = { { GetDifferential = { struct_name = "DifferentialPairGetDifferential", min_operands = 1 } }, { GetDifferentialUserCode = { struct_name = "DifferentialPairGetDifferentialUserCode", min_operands = 1 }, }, { GetDifferentialPtr = { struct_name = "DifferentialPtrPairGetDifferential", min_operands = 1, }, }, }, }, { DifferentialPairGetPrimalBase = { { GetPrimal = { struct_name = "DifferentialPairGetPrimal", min_operands = 1 }, }, { GetPrimalUserCode = { struct_name = "DifferentialPairGetPrimalUserCode", min_operands = 1, }, }, { GetPrimalRef = { struct_name = "DifferentialPtrPairGetPrimal", min_operands = 1 } }, }, }, { specialize = { min_operands = 2, hoistable = true } }, { lookupWitness = { struct_name = "LookupWitnessMethod", min_operands = 2, hoistable = true } }, { GetSequentialID = { min_operands = 1, hoistable = true } }, { bind_global_generic_param = { min_operands = 2, }, }, { allocObj = {} }, { globalValueRef = { min_operands = 1 } }, { makeUInt64 = { min_operands = 2 } }, { makeVector = {} }, { makeMatrix = {} }, { makeMatrixFromScalar = { min_operands = 1, }, }, { matrixReshape = { min_operands = 1 } }, { vectorReshape = { min_operands = 1, }, }, { makeArray = {} }, { makeArrayFromElement = { min_operands = 1 } }, { makeCoopVector = {} }, { makeCoopVectorFromValuePack = { min_operands = 1 } }, { makeStruct = {} }, { makeTuple = {} }, { makeTargetTuple = { struct_name = "MakeTargetTuple" } }, { makeValuePack = {} }, { getTargetTupleElement = {} }, { getTupleElement = { min_operands = 2, }, }, { LoadResourceDescriptorFromHeap = { min_operands = 1 } }, { LoadSamplerDescriptorFromHeap = { min_operands = 1, }, }, { MakeCombinedTextureSamplerFromHandle = { min_operands = 1 } }, { MakeWitnessPack = { hoistable = true, }, }, { Expand = { min_operands = 1 } }, { Each = { min_operands = 1, hoistable = true, }, }, { makeResultValue = { min_operands = 1 } }, { makeResultError = { min_operands = 1 } }, { isResultError = { min_operands = 1 } }, { getResultError = { min_operands = 1 } }, { getResultValue = { min_operands = 1 } }, { getOptionalValue = { min_operands = 1 } }, { optionalHasValue = { min_operands = 1 } }, { makeOptionalValue = { min_operands = 1 } }, { makeOptionalNone = { min_operands = 1 } }, { CombinedTextureSamplerGetTexture = { min_operands = 1 } }, { CombinedTextureSamplerGetSampler = { min_operands = 1 } }, { call = { min_operands = 1 } }, { rtti_object = { struct_name = "RTTIObject" } }, { alloca = { min_operands = 1 } }, { updateElement = { min_operands = 2 } }, { detachDerivative = { min_operands = 1 } }, { bitfieldExtract = { min_operands = 3 } }, { bitfieldInsert = { min_operands = 4 } }, { packAnyValue = { min_operands = 1 } }, { unpackAnyValue = { min_operands = 1 } }, { witness_table_entry = { min_operands = 2 } }, { interface_req_entry = { struct_name = "InterfaceRequirementEntry", operands = { { "requirementKey" }, { "requirementVal" } }, global = true } }, -- An inst to represent the workgroup size of the calling entry point. -- We will materialize this inst during `translateGlobalVaryingVar`. { GetWorkGroupSize = { hoistable = true } }, -- An inst that returns the current stage of the calling entry point. { GetCurrentStage = {} }, { param = {} }, { field = { struct_name = "StructField", min_operands = 2 } }, { var = {} }, { load = { min_operands = 1 } }, { store = { min_operands = 2 } }, { CUDA_LDG = {min_operands = 1 } }, -- Atomic Operations { AtomicOperation = { { atomicLoad = { min_operands = 1 } }, { atomicStore = { min_operands = 2 }, }, { atomicExchange = { min_operands = 2 } }, { atomicCompareExchange = { min_operands = 3 }, }, { atomicAdd = { min_operands = 2 } }, { atomicSub = { min_operands = 2 }, }, { atomicAnd = { min_operands = 2 } }, { atomicOr = { min_operands = 2 }, }, { atomicXor = { min_operands = 2 } }, { atomicMin = { min_operands = 2 }, }, { atomicMax = { min_operands = 2 } }, { atomicInc = { min_operands = 1 }, }, { atomicDec = { min_operands = 1 } }, }, }, -- Produced and removed during backward auto-diff pass as a temporary placeholder representing the -- currently accumulated derivative to pass to some dOut argument in a nested call. { LoadReverseGradient = { min_operands = 1 } }, -- Produced and removed during backward auto-diff pass as a temporary placeholder containing the -- primal and accumulated derivative values to pass to an inout argument in a nested call. { ReverseGradientDiffPairRef = { min_operands = 2 } }, -- Produced and removed during backward auto-diff pass. This inst is generated by the splitting step -- to represent a reference to an inout parameter for use in the primal part of the computation. { PrimalParamRef = { min_operands = 1 } }, -- Produced and removed during backward auto-diff pass. This inst is generated by the splitting step -- to represent a reference to an inout parameter for use in the back-prop part of the computation. { DiffParamRef = { min_operands = 1 } }, -- Check that the value is a differential null value. { IsDifferentialNull = { min_operands = 1 } }, { get_field = { struct_name = "FieldExtract", min_operands = 2, }, }, { get_field_addr = { struct_name = "FieldAddress", min_operands = 2 } }, { getElement = { min_operands = 2 } }, { getElementPtr = { min_operands = 2 } }, -- Pointer offset: computes pBase + offset_in_elements { getOffsetPtr = { min_operands = 2 } }, { getAddr = { struct_name = "GetAddress", min_operands = 1 } }, { castDynamicResource = { min_operands = 1 } }, -- Get an unowned NativeString from a String. { getNativeStr = { min_operands = 1 } }, -- Make String from a NativeString. { makeString = { min_operands = 1 } }, -- Get a native ptr from a ComPtr or RefPtr { getNativePtr = { min_operands = 1 } }, -- Get a write reference to a managed ptr var (operand must be Ptr> or Ptr>). { getManagedPtrWriteRef = { min_operands = 1 } }, -- Attach a managedPtr var to a NativePtr without changing its ref count. { ManagedPtrAttach = { min_operands = 1 } }, -- Attach a managedPtr var to a NativePtr without changing its ref count. { ManagedPtrDetach = { min_operands = 1 } }, -- "Subscript" an image at a pixel coordinate to get pointer { imageSubscript = { min_operands = 2 } }, -- Load from an Image. { imageLoad = { min_operands = 2 } }, -- Store into an Image. { imageStore = { min_operands = 3 } }, -- Load (almost) arbitrary-type data from a byte-address buffer -- %dst = byteAddressBufferLoad(%buffer, %offset, %alignment) -- where -- - `buffer` is a value of some `ByteAddressBufferTypeBase` type -- - `offset` is an `int` -- - `alignment` is an `int` -- - `dst` is a value of some type containing only ordinary data { byteAddressBufferLoad = { min_operands = 3 } }, -- Store (almost) arbitrary-type data to a byte-address buffer -- byteAddressBufferLoad(%buffer, %offset, %alignment, %src) -- where -- - `buffer` is a value of some `ByteAddressBufferTypeBase` type -- - `offset` is an `int` -- - `alignment` is an `int` -- - `src` is a value of some type containing only ordinary data { byteAddressBufferStore = { min_operands = 4 } }, -- Load data from a structured buffer -- %dst = structuredBufferLoad(%buffer, %index) -- where -- - `buffer` is a value of some `StructuredBufferTypeBase` type with element type T -- - `offset` is an `int` -- - `dst` is a value of type T { structuredBufferLoad = { min_operands = 2 } }, { structuredBufferLoadStatus = { min_operands = 3 } }, { rwstructuredBufferLoad = { struct_name = "RWStructuredBufferLoad", min_operands = 2 } }, { rwstructuredBufferLoadStatus = { struct_name = "RWStructuredBufferLoadStatus", min_operands = 3, }, }, -- Store data to a structured buffer -- structuredBufferLoad(%buffer, %offset, %src) -- where -- - `buffer` is a value of some `StructuredBufferTypeBase` type with element type T -- - `offset` is an `int` -- - `src` is a value of type T { rwstructuredBufferStore = { struct_name = "RWStructuredBufferStore", min_operands = 3 } }, { rwstructuredBufferGetElementPtr = { struct_name = "RWStructuredBufferGetElementPtr", min_operands = 2, }, }, -- Append/Consume-StructuredBuffer operations { StructuredBufferAppend = { min_operands = 1 } }, { StructuredBufferConsume = { min_operands = 1 } }, { StructuredBufferGetDimensions = { min_operands = 1 } }, -- Resource qualifiers for dynamically varying index { nonUniformResourceIndex = { min_operands = 1 } }, { getNaturalStride = { min_operands = 1 } }, { meshOutputRef = { min_operands = 2 } }, { meshOutputSet = { min_operands = 3 } }, -- only two parameters as they are effectively static -- TODO: make them reference the _slang_mesh object directly { metalSetVertex = { min_operands = 2 } }, { metalSetPrimitive = { min_operands = 2 } }, { metalSetIndices = { min_operands = 2 } }, { MetalCastToDepthTexture = { min_operands = 1 } }, -- Construct a vector from a scalar -- %dst = MakeVectorFromScalar %T %N %val -- where -- - `T` is a `Type` -- - `N` is a (compile-time) `Int` -- - `val` is a `T` -- - dst is a `Vec` { MakeVectorFromScalar = { min_operands = 3 } }, -- A swizzle of a vector: -- %dst = swizzle %src %idx0 %idx1 ... -- where: -- - `src` is a vector -- - `dst` is a vector -- - `idx0` through `idx[M-1]` are literal integers { swizzle = { min_operands = 1 } }, -- Setting a vector via swizzle -- -- %dst = swizzle %base %src %idx0 %idx1 ... -- -- where: -- - `base` is a vector -- - `dst` is a vector -- - `src` is a vector -- - `idx0` through `idx[M-1]` are literal integers -- -- The semantics of the op is: -- -- dst = base; -- for(ii : 0 ... M-1 ) -- dst[ii] = src[idx[ii]]; { swizzleSet = { min_operands = 2 } }, -- Store to memory with a swizzle -- -- TODO: eventually this should be reduced to just -- a write mask by moving the actual swizzle to the RHS. -- -- swizzleStore %dst %src %idx0 %idx1 ... -- -- where: -- - `dst` is a vector -- - `src` is a vector -- - `idx0` through `idx[M-1]` are literal integers -- -- The semantics of the op is: -- -- for(ii : 0 ... M-1 ) -- dst[ii] = src[idx[ii]]; { swizzledStore = { min_operands = 2 } }, { TerminatorInst = { { return_val = { struct_name = "Return", min_operands = 1 } }, { yield = { min_operands = 1 } }, { UnconditionalBranch = { -- IRUnconditionalBranch { unconditionalBranch = { -- unconditionalBranch min_operands = 1, }, }, { loop = { -- loop min_operands = 3, }, }, }, }, { ConditionalBranch = { -- IRTerminatorInst { conditionalBranch = { -- conditionalBranch struct_name = "ConditionalBranch", min_operands = 3, }, }, { ifElse = { -- ifElse struct_name = "IfElse", min_operands = 4, }, }, }, }, { throw = { -- IRConditionalbranch min_operands = 1, }, }, { tryCall = { -- tryCall ... min_operands = 3, }, }, { switch = { -- switch ... min_operands = 3, }, }, { targetSwitch = { -- target_switch ... min_operands = 1, }, }, { GenericAsm = { -- A generic asm inst has an return semantics that terminates the control flow. min_operands = 1, }, }, { Unreachable = { { missingReturn = { -- IRUnreachable }, }, { unreachable = {} }, }, }, { defer = { min_operands = 3 } }, }, }, { discard = {} }, { RequirePrelude = { min_operands = 1 }, }, { RequireTargetExtension = { min_operands = 1 } }, { RequireComputeDerivative = {} }, { StaticAssert = { min_operands = 2 } }, { Printf = { min_operands = 1 } }, -- Quad control execution modes. { RequireMaximallyReconverges = {} }, { RequireQuadDerivatives = {} }, -- TODO: We should consider splitting the basic arithmetic/comparison -- ops into cases for signed integers, unsigned integers, and floating-point -- values, to better match downstream targets that want to treat them -- all differently (). { add = { min_operands = 2 } }, { sub = { min_operands = 2 } }, { mul = { min_operands = 2 } }, { div = { min_operands = 2 } }, -- Remainder of division. -- Note: this is distinct from modulus, and we should have a separate -- opcode for `mod` if we ever need to support it. { irem = { struct_name = "IRem", min_operands = 2 } }, { frem = { struct_name = "FRem", min_operands = 2, }, }, { shl = { struct_name = "Lsh", min_operands = 2 }, }, { shr = { struct_name = "Rsh", min_operands = 2 } }, { cmpEQ = { struct_name = "Eql", min_operands = 2 } }, { cmpNE = { struct_name = "Neq", min_operands = 2, }, }, { cmpGT = { struct_name = "Greater", min_operands = 2 }, }, { cmpLT = { struct_name = "Less", min_operands = 2 } }, { cmpGE = { struct_name = "Geq", min_operands = 2 } }, { cmpLE = { struct_name = "Leq", min_operands = 2, }, }, { ["and"] = { struct_name = "BitAnd", min_operands = 2 }, }, { xor = { struct_name = "BitXor", min_operands = 2 } }, { ["or"] = { struct_name = "BitOr", min_operands = 2 } }, { logicalAnd = { struct_name = "And", min_operands = 2, }, }, { logicalOr = { struct_name = "Or", min_operands = 2 }, }, { neg = { min_operands = 1 } }, { ["not"] = { min_operands = 1 }, }, { bitnot = { struct_name = "BitNot", min_operands = 1 } }, { select = { min_operands = 3 } }, { checkpointObj = { struct_name = "CheckpointObject", min_operands = 1, }, }, { loopExitValue = { min_operands = 1 } }, { getStringHash = { operands = { { "stringLit", "IRStringLit" } }, }, }, { waveGetActiveMask = {} }, -- trueMask = waveMaskBallot(mask, condition) { waveMaskBallot = { min_operands = 2 } }, -- matchMask = waveMaskBallot(mask, value) { waveMaskMatch = { min_operands = 2 } }, -- Texture sampling operation of the form `t.Sample(s,u)` { sample = { min_operands = 3 } }, { sampleGrad = { min_operands = 4 } }, { GroupMemoryBarrierWithGroupSync = {} }, { ControlBarrier = {} }, -- GPU_FOREACH loop of the form { gpuForeach = { min_operands = 3 } }, -- Wrapper for OptiX intrinsics used to load and store ray payload data using -- a pointer represented by two payload registers. { getOptiXRayPayloadPtr = { hoistable = true } }, -- Wrapper for OptiX intrinsics used to load a single hit attribute -- Takes two arguments: the type (either float or int), and the hit -- attribute index { getOptiXHitAttribute = { min_operands = 2 } }, -- Wrapper for OptiX intrinsics used to load shader binding table record data -- using a pointer. { getOptiXSbtDataPointer = { struct_name = "GetOptiXSbtDataPtr" } }, { GetVulkanRayTracingPayloadLocation = { min_operands = 1 } }, { GetLegalizedSPIRVGlobalParamAddr = { min_operands = 1 } }, { GetPerVertexInputArray = { min_operands = 1, hoistable = true, }, }, { ResolveVaryingInputRef = { min_operands = 1, hoistable = true } }, { ForceVarIntoStructTemporarilyBase = { { ForceVarIntoStructTemporarily = { min_operands = 1 } }, { ForceVarIntoRayPayloadStructTemporarily = { min_operands = 1, }, }, }, }, { MetalAtomicCast = { min_operands = 1 } }, { IsTextureAccess = { min_operands = 1 } }, { IsTextureScalarAccess = { min_operands = 1 } }, { IsTextureArrayAccess = { min_operands = 1 } }, { ExtractTextureFromTextureAccess = { min_operands = 1 } }, { ExtractCoordFromTextureAccess = { min_operands = 1 } }, { ExtractArrayCoordFromTextureAccess = { min_operands = 1 } }, { makeArrayList = {} }, { makeTensorView = {} }, { allocTorchTensor = { struct_name = "AllocateTorchTensor" } }, { TorchGetCudaStream = {} }, { TorchTensorGetView = {} }, { CoopMatMapElementIFunc = { min_operands = 2 } }, { allocateOpaqueHandle = {} }, { BindingQuery = { { getRegisterIndex = { -- Return the register index thtat a resource is bound to. min_operands = 1, }, }, { getRegisterSpace = { -- Return the registe space that a resource is bound to. min_operands = 1, }, }, }, }, { Decoration = { { highLevelDecl = { struct_name = "HighLevelDeclDecoration", min_operands = 1 }, }, { layout = { struct_name = "LayoutDecoration", min_operands = 1, }, }, { branch = { struct_name = "BranchDecoration" } }, { flatten = { struct_name = "FlattenDecoration", }, }, { loopControl = { struct_name = "LoopControlDecoration", min_operands = 1 } }, { loopMaxIters = { struct_name = "LoopMaxItersDecoration", min_operands = 1 } }, { loopExitPrimalValue = { struct_name = "LoopExitPrimalValueDecoration", min_operands = 2 }, }, { intrinsicOp = { struct_name = "IntrinsicOpDecoration", min_operands = 1, }, }, { TargetSpecificDecoration = { { TargetSpecificDefinitionDecoration = { { target = { struct_name = "TargetDecoration", min_operands = 1 }, }, { targetIntrinsic = { struct_name = "TargetIntrinsicDecoration", min_operands = 2, }, }, }, }, { requirePrelude = { struct_name = "RequirePreludeDecoration", min_operands = 2, }, }, }, }, { glslOuterArray = { struct_name = "GLSLOuterArrayDecoration", min_operands = 1, }, }, { TargetSystemValue = { struct_name = "TargetSystemValueDecoration", min_operands = 2 } }, { interpolationMode = { struct_name = "InterpolationModeDecoration", min_operands = 1 } }, { nameHint = { struct_name = "NameHintDecoration", min_operands = 1 }, }, { PhysicalType = { struct_name = "PhysicalTypeDecoration", min_operands = 1, }, }, { AlignedAddressDecoration = { -- Mark an address instruction as aligned to a specific byte boundary. min_operands = 1, }, }, { BinaryInterfaceType = { -- Marks a type as being used as binary interface (e.g. shader parameters). -- This prevents the legalizeEmptyType() pass from eliminating it on C++/CUDA targets. struct_name = "BinaryInterfaceTypeDecoration", }, }, { transitory = { -- * The decorated _instruction_ is transitory. Such a decoration should NEVER be found on an output instruction a module. -- Typically used mark an instruction so can be specially handled - say when creating a IRConstant literal, and the payload of -- needs to be special cased for lookup. struct_name = "TransitoryDecoration", }, }, { ResultWitness = { -- The result witness table that the functon's return type is a subtype of an interface. -- This is used to keep track of the original witness table in a function that used to -- return an existential value but now returns a concrete type after specialization. struct_name = "ResultWitnessDecoration", min_operands = 1, }, }, -- A decoration that indicates that a variable represents -- a vulkan ray payload, and should have a location assigned -- to it. { vulkanRayPayload = { struct_name = "VulkanRayPayloadDecoration" } }, { vulkanRayPayloadIn = { struct_name = "VulkanRayPayloadInDecoration" } }, -- A decoration that indicates that a variable represents -- vulkan hit attributes, and should have a location assigned -- to it. { vulkanHitAttributes = { struct_name = "VulkanHitAttributesDecoration" } }, -- A decoration that indicates that a variable represents -- vulkan hit object attributes, and should have a location assigned -- to it. { vulkanHitObjectAttributes = { struct_name = "VulkanHitObjectAttributesDecoration" } }, { GlobalVariableShadowingGlobalParameterDecoration = { min_operands = 2 } }, { requireSPIRVVersion = { struct_name = "RequireSPIRVVersionDecoration", min_operands = 1 } }, { requireGLSLVersion = { struct_name = "RequireGLSLVersionDecoration", min_operands = 1, }, }, { requireGLSLExtension = { struct_name = "RequireGLSLExtensionDecoration", min_operands = 1 }, }, { requireWGSLExtension = { struct_name = "RequireWGSLExtensionDecoration", min_operands = 1 } }, { requireCUDASMVersion = { struct_name = "RequireCUDASMVersionDecoration", min_operands = 1 } }, { requireCapabilityAtom = { struct_name = "RequireCapabilityAtomDecoration", min_operands = 1, }, }, { HasExplicitHLSLBinding = { struct_name = "HasExplicitHLSLBindingDecoration" } }, { DefaultValue = { struct_name = "DefaultValueDecoration", min_operands = 1 } }, { readNone = { struct_name = "ReadNoneDecoration" }, }, -- A decoration that indicates that a variable represents -- a vulkan callable shader payload, and should have a location assigned -- to it. { vulkanCallablePayload = { struct_name = "VulkanCallablePayloadDecoration" } }, { vulkanCallablePayloadIn = { struct_name = "VulkanCallablePayloadInDecoration" } }, { earlyDepthStencil = { struct_name = "EarlyDepthStencilDecoration" } }, { precise = { struct_name = "PreciseDecoration" } }, { public = { struct_name = "PublicDecoration" } }, { hlslExport = { struct_name = "HLSLExportDecoration" } }, { downstreamModuleExport = { struct_name = "DownstreamModuleExportDecoration" } }, { downstreamModuleImport = { struct_name = "DownstreamModuleImportDecoration" } }, { patchConstantFunc = { struct_name = "PatchConstantFuncDecoration", min_operands = 1 } }, { maxTessFactor = { struct_name = "MaxTessFactorDecoration", min_operands = 1, }, }, { outputControlPoints = { struct_name = "OutputControlPointsDecoration", min_operands = 1 }, }, { outputTopology = { struct_name = "OutputTopologyDecoration", min_operands = 2 } }, { partioning = { struct_name = "PartitioningDecoration", min_operands = 1 } }, { domain = { struct_name = "DomainDecoration", min_operands = 1, }, }, { maxVertexCount = { struct_name = "MaxVertexCountDecoration", min_operands = 1 }, }, { instance = { struct_name = "InstanceDecoration", min_operands = 1 } }, { numThreads = { struct_name = "NumThreadsDecoration", min_operands = 3 } }, { fpDenormalPreserve = { struct_name = "FpDenormalPreserveDecoration", min_operands = 1 } }, { fpDenormalFlushToZero = { struct_name = "FpDenormalFlushToZeroDecoration", min_operands = 1 } }, { waveSize = { struct_name = "WaveSizeDecoration", min_operands = 1, }, }, { availableInDownstreamIR = { struct_name = "AvailableInDownstreamIRDecoration", min_operands = 1 }, }, { GeometryInputPrimitiveTypeDecoration = { { pointPrimitiveType = { -- Added to IRParam parameters to an entry point struct_name = "PointInputPrimitiveTypeDecoration", }, }, { linePrimitiveType = { struct_name = "LineInputPrimitiveTypeDecoration" } }, { trianglePrimitiveType = { struct_name = "TriangleInputPrimitiveTypeDecoration", }, }, { lineAdjPrimitiveType = { struct_name = "LineAdjInputPrimitiveTypeDecoration" } }, { triangleAdjPrimitiveType = { struct_name = "TriangleAdjInputPrimitiveTypeDecoration", }, }, }, }, { streamOutputTypeDecoration = { min_operands = 1 } }, { entryPoint = { -- An `[entryPoint]` decoration marks a function that represents a shader entry point struct_name = "EntryPointDecoration", min_operands = 2, }, }, { CudaKernel = { struct_name = "CudaKernelDecoration" } }, { CudaHost = { struct_name = "CudaHostDecoration" } }, { TorchEntryPoint = { struct_name = "TorchEntryPointDecoration" } }, { AutoPyBindCUDA = { struct_name = "AutoPyBindCudaDecoration" } }, { CudaKernelFwdDiffRef = { struct_name = "CudaKernelForwardDerivativeDecoration" } }, { CudaKernelBwdDiffRef = { struct_name = "CudaKernelBackwardDerivativeDecoration" } }, { PyBindExportFuncInfo = { struct_name = "AutoPyBindExportInfoDecoration" } }, { PyExportDecoration = {} }, { entryPointParam = { -- Used to mark parameters that are moved from entry point parameters to global params as coming from the entry -- point. struct_name = "EntryPointParamDecoration", }, }, { dependsOn = { -- A `[dependsOn(x)]` decoration indicates that the parent instruction depends on `x` -- even if it does not otherwise reference it. struct_name = "DependsOnDecoration", min_operands = 1, }, }, { keepAlive = { -- A `[keepAlive]` decoration marks an instruction that should not be eliminated. struct_name = "KeepAliveDecoration", }, }, { noSideEffect = { -- A `[NoSideEffect]` decoration marks a callee to be side-effect free. struct_name = "NoSideEffectDecoration", }, }, { bindExistentialSlots = { struct_name = "BindExistentialSlotsDecoration" } }, { format = { -- A `[format(f)]` decoration specifies that the format of an image should be `f` struct_name = "FormatDecoration", min_operands = 1, }, }, { unsafeForceInlineEarly = { -- An `[unsafeForceInlineEarly]` decoration specifies that calls to this function should be inline after initial -- codegen struct_name = "UnsafeForceInlineEarlyDecoration", }, }, { ForceInline = { -- A `[ForceInline]` decoration indicates the callee should be inlined by the Slang compiler. struct_name = "ForceInlineDecoration", }, }, { ForceUnroll = { -- A `[ForceUnroll]` decoration indicates the loop should be unrolled by the Slang compiler. struct_name = "ForceUnrollDecoration", }, }, { SizeAndAlignment = { -- A `[SizeAndAlignment(l,s,a)]` decoration is attached to a type to indicate that is has size `s` and alignment -- `a` under layout rules `l`. struct_name = "SizeAndAlignmentDecoration", min_operands = 3, }, }, { Offset = { -- A `[Offset(l, o)]` decoration is attached to a field to indicate that it has offset `o` in the parent type -- under layout rules `l`. struct_name = "OffsetDecoration", min_operands = 2, }, }, { LinkageDecoration = { { import = { struct_name = "ImportDecoration", min_operands = 1, }, }, { export = { struct_name = "ExportDecoration", min_operands = 1 }, }, }, }, { TargetBuiltinVar = { -- Mark a global variable as a target builtin variable. struct_name = "TargetBuiltinVarDecoration", min_operands = 1, }, }, { UserExtern = { -- Marks an inst as coming from an `extern` symbol defined in the user code. struct_name = "UserExternDecoration", }, }, { externCpp = { -- An extern_cpp decoration marks the inst to emit its name without mangling for C++ interop. struct_name = "ExternCppDecoration", min_operands = 1, }, }, { externC = { -- An externC decoration marks a function should be emitted inside an extern "C" block. struct_name = "ExternCDecoration", }, }, { dllImport = { -- An dllImport decoration marks a function as imported from a DLL. Slang will generate dynamic function loading -- logic to use this function at runtime. struct_name = "DllImportDecoration", min_operands = 2, }, }, { dllExport = { -- An dllExport decoration marks a function as an export symbol. Slang will generate a native wrapper function -- that is exported to DLL. struct_name = "DllExportDecoration", min_operands = 1, }, }, { cudaDeviceExport = { -- An cudaDeviceExport decoration marks a function to be exported as a cuda __device__ function. struct_name = "CudaDeviceExportDecoration", min_operands = 1, }, }, { COMInterface = { -- Marks an interface as a COM interface declaration. struct_name = "ComInterfaceDecoration", }, }, { KnownBuiltinDecoration = { -- Attaches a name to this instruction so that it can be identified -- later in the compiler reliably min_operands = 1, }, }, { RTTI_typeSize = { -- Decorations for RTTI objects struct_name = "RTTITypeSizeDecoration", min_operands = 1, }, }, { AnyValueSize = { struct_name = "AnyValueSizeDecoration", min_operands = 1 }, }, { SpecializeDecoration = {} }, { SequentialIDDecoration = { min_operands = 1 } }, { DynamicDispatchWitnessDecoration = {} }, { StaticRequirementDecoration = {} }, { DispatchFuncDecoration = { min_operands = 1 } }, { TypeConstraintDecoration = { min_operands = 1 } }, { BuiltinDecoration = {} }, { requiresNVAPI = { -- The decorated instruction requires NVAPI to be included via prelude when compiling for D3D. struct_name = "RequiresNVAPIDecoration", }, }, { nvapiMagic = { -- The decorated instruction is part of the NVAPI "magic" and should always use its original name struct_name = "NVAPIMagicDecoration", min_operands = 1, }, }, { nvapiSlot = { -- A decoration that applies to an entire IR module, and indicates the register/space binding -- that the NVAPI shader parameter intends to use. struct_name = "NVAPISlotDecoration", min_operands = 2, }, }, { noInline = { -- Applie to an IR function and signals that inlining should not be performed unless unavoidable. struct_name = "NoInlineDecoration", }, }, { noRefInline = { struct_name = "NoRefInlineDecoration" } }, { DerivativeGroupQuad = { struct_name = "DerivativeGroupQuadDecoration", }, }, { DerivativeGroupLinear = { struct_name = "DerivativeGroupLinearDecoration" } }, { MaximallyReconverges = { struct_name = "MaximallyReconvergesDecoration", }, }, { QuadDerivatives = { struct_name = "QuadDerivativesDecoration" } }, { RequireFullQuads = { struct_name = "RequireFullQuadsDecoration", }, }, -- Marks a var as a temporary local variable to replace references to a `in` parameter from the function body -- This is to support legacy code that modifies an `in` parameter as if it is copied to a local variable. { InParamProxyVar = { struct_name = "InParamProxyVarDecoration", min_operands = 1 } }, { TempCallArgImmutableVar = { struct_name = "TempCallArgImmutableVarDecoration" } }, { TempCallArgVar = { struct_name = "TempCallArgVarDecoration" } }, { nonCopyable = { -- Marks a type to be non copyable, causing SSA pass to skip turning variables of the the type into SSA values. struct_name = "NonCopyableTypeDecoration", }, }, { DisableCopyEliminationDecoration = {} }, { DynamicUniform = { -- Marks a value to be dynamically uniform. struct_name = "DynamicUniformDecoration", }, }, { alwaysFold = { -- A call to the decorated function should always be folded into its use site. struct_name = "AlwaysFoldIntoUseSiteDecoration", }, }, { output = { struct_name = "GlobalOutputDecoration" } }, { input = { struct_name = "GlobalInputDecoration", }, }, { glslLocation = { struct_name = "GLSLLocationDecoration", min_operands = 1 } }, { glslOffset = { struct_name = "GLSLOffsetDecoration", min_operands = 1 } }, { vkStructOffset = { struct_name = "VkStructOffsetDecoration", min_operands = 1 }, }, { raypayload = { struct_name = "RayPayloadDecoration" } }, { MeshOutputDecoration = { -- Mesh Shader outputs { vertices = { struct_name = "VerticesDecoration", min_operands = 1 } }, { indices = { struct_name = "IndicesDecoration", min_operands = 1, }, }, { primitives = { struct_name = "PrimitivesDecoration", min_operands = 1 }, }, }, }, { HLSLMeshPayloadDecoration = { struct_name = "HLSLMeshPayloadDecoration" } }, { perprimitive = { struct_name = "GLSLPrimitivesRateDecoration" } }, { PositionOutput = { -- Marks an inst that represents the gl_Position output. struct_name = "GLPositionOutputDecoration", }, }, { PositionInput = { -- Marks an inst that represents the gl_Position input. struct_name = "GLPositionInputDecoration", }, }, { PerVertex = { -- Marks a fragment shader input as per-vertex. struct_name = "PerVertexDecoration", }, }, { StageAccessDecoration = { { stageReadAccess = { struct_name = "StageReadAccessDecoration" } }, { stageWriteAccess = { struct_name = "StageWriteAccessDecoration" } }, }, }, { semantic = { struct_name = "SemanticDecoration", min_operands = 2 }, }, { constructor = { struct_name = "ConstructorDecoration", min_operands = 1, }, }, { method = { struct_name = "MethodDecoration" } }, { packoffset = { struct_name = "PackOffsetDecoration", min_operands = 2, }, }, { SpecializationConstantDecoration = { min_operands = 1 } }, { UserTypeName = { -- Reflection metadata for a shader parameter that provides the original type name. struct_name = "UserTypeNameDecoration", min_operands = 1, }, }, { CounterBuffer = { -- Reflection metadata for a shader parameter that refers to the associated counter buffer of a UAV. struct_name = "CounterBufferDecoration", min_operands = 1, }, }, { RequireSPIRVDescriptorIndexingExtensionDecoration = {} }, { spirvOpDecoration = { struct_name = "SPIRVOpDecoration", min_operands = 1, }, }, { forwardDifferentiable = { -- Decorated function is marked for the forward-mode differentiation pass. struct_name = "ForwardDifferentiableDecoration", }, }, { AutoDiffOriginalValueDecoration = { -- Decorates a auto-diff transcribed value with the original value that the inst is transcribed from. min_operands = 1, }, }, { AutoDiffBuiltinDecoration = { -- Decorates a type as auto-diff builtin type. }, }, { fwdDerivative = { -- Used by the auto-diff pass to hold a reference to the -- generated derivative function. struct_name = "ForwardDerivativeDecoration", min_operands = 1, }, }, { backwardDifferentiable = { -- Used by the auto-diff pass to hold a reference to the -- generated derivative function. struct_name = "BackwardDifferentiableDecoration", min_operands = 1, }, }, { primalSubstFunc = { -- Used by the auto-diff pass to hold a reference to the -- primal substitute function. struct_name = "PrimalSubstituteDecoration", min_operands = 1, }, }, { backwardDiffPrimalReference = { -- Decorations to associate an original function with compiler generated backward derivative functions. struct_name = "BackwardDerivativePrimalDecoration", min_operands = 1, }, }, { backwardDiffPropagateReference = { struct_name = "BackwardDerivativePropagateDecoration", min_operands = 1, }, }, { backwardDiffIntermediateTypeReference = { struct_name = "BackwardDerivativeIntermediateTypeDecoration", min_operands = 1, }, }, { backwardDiffReference = { struct_name = "BackwardDerivativeDecoration", min_operands = 1 } }, { userDefinedBackwardDiffReference = { struct_name = "UserDefinedBackwardDerivativeDecoration", min_operands = 1, }, }, { BackwardDerivativePrimalContextDecoration = { min_operands = 1 } }, { BackwardDerivativePrimalReturnDecoration = { min_operands = 1 } }, { PrimalContextDecoration = { -- Mark a parameter as autodiff primal context. }, }, { loopCounterDecoration = {} }, { loopCounterUpdateDecoration = {} }, { AutodiffInstDecoration = { -- Auto-diff inst decorations { primalInstDecoration = { -- Used by the auto-diff pass to mark insts that compute -- a primal value. }, }, { diffInstDecoration = { -- Used by the auto-diff pass to mark insts that compute -- a differential value. struct_name = "DifferentialInstDecoration", min_operands = 1, }, }, { mixedDiffInstDecoration = { -- Used by the auto-diff pass to mark insts that compute -- BOTH a differential and a primal value. struct_name = "MixedDifferentialInstDecoration", min_operands = 1, }, }, { RecomputeBlockDecoration = {} }, }, }, { primalValueKey = { -- Used by the auto-diff pass to mark insts whose result is stored -- in an intermediary struct for reuse in backward propagation phase. struct_name = "PrimalValueStructKeyDecoration", min_operands = 1, }, }, { primalElementType = { -- Used by the auto-diff pass to mark the primal element type of an -- forward-differentiated updateElement inst. struct_name = "PrimalElementTypeDecoration", min_operands = 1, }, }, { IntermediateContextFieldDifferentialTypeDecoration = { -- Used by the auto-diff pass to mark the differential type of an intermediate context field. min_operands = 1, }, }, { derivativeMemberDecoration = { -- Used by the auto-diff pass to hold a reference to a -- differential member of a type in its associated differential type. min_operands = 1, }, }, { treatAsDifferentiableDecoration = { -- Treat a function as differentiable function }, }, { treatCallAsDifferentiableDecoration = { -- Treat a call to arbitrary function as a differentiable call. }, }, { differentiableCallDecoration = { -- Mark a call as explicitly calling a differentiable function. }, }, { optimizableTypeDecoration = { -- Mark a type as being eligible for trimming if necessary. If -- any fields don't have any effective loads from them, they can be -- removed. }, }, { ignoreSideEffectsDecoration = { -- Informs the DCE pass to ignore side-effects on this call for -- the purposes of dead code elimination, even if the call does have -- side-effects. }, }, { CheckpointHintDecoration = { { PreferCheckpointDecoration = { -- Hint that the result from a call to the decorated function should be stored in backward prop function. }, }, { PreferRecomputeDecoration = { -- Hint that the result from a call to the decorated function should be recomputed in backward prop function. }, }, { CheckpointIntermediateDecoration = { -- Hint that a struct is used for reverse mode checkpointing min_operands = 1, }, }, }, }, { NonDynamicUniformReturnDecoration = { -- Marks a function whose return value is never dynamic uniform. }, }, { COMWitnessDecoration = { -- Marks a class type as a COM interface implementation, which enables -- the witness table to be easily picked up by emit. min_operands = 1, }, }, { DifferentiableTypeDictionaryDecoration = { -- Differentiable Type Dictionary parent = true, }, }, { FloatingPointModeOverride = { struct_name = "FloatingPointModeOverrideDecoration", -- Overrides the floating mode for the target function min_operands = 1, }, }, { spvBufferBlock = { -- Recognized by SPIRV-emit pass so we can emit a SPIRV `BufferBlock` decoration. struct_name = "SPIRVBufferBlockDecoration", }, }, { DebugLocation = { -- Decorates an inst with a debug source location (IRDebugSource, IRIntLit(line), IRIntLit(col)). struct_name = "DebugLocationDecoration", min_operands = 3, }, }, { DebugFunction = { -- Decorates a function with a link to its debug function representation struct_name = "DebugFuncDecoration", min_operands = 1, }, }, { spvBlock = { -- Recognized by SPIRV-emit pass so we can emit a SPIRV `Block` decoration. struct_name = "SPIRVBlockDecoration", }, }, { NonUniformResource = { -- Decorates a SPIRV-inst as `NonUniformResource` to guarantee non-uniform index lookup of -- - a resource within an array of resources via IRGetElement. -- - an IRLoad that takes a pointer within a memory buffer via IRGetElementPtr. -- - an IRIntCast to a resource that is casted from signed to unsigned or viceversa. -- - an IRGetElementPtr itself when using the pointer on an intrinsic operation. struct_name = "SPIRVNonUniformResourceDecoration", }, }, { MemoryQualifierSetDecoration = { -- Stores flag bits of which memory qualifiers an object has min_operands = 1, }, }, { BitFieldAccessorDecoration = { -- Marks a function as one which access a bitfield with the specified -- backing value key, width and offset min_operands = 3, }, }, }, }, -- Decoration -- A `makeExistential(v : C, w) : I` instruction takes a value `v` of type `C` -- and produces a value of interface type `I` by using the witness `w` which -- shows that `C` conforms to `I`. { makeExistential = { min_operands = 2 } }, -- A `MakeExistentialWithRTTI(v, w, t)` is the same with `MakeExistential`, -- but with the type of `v` being an explict operand. { makeExistentialWithRTTI = { min_operands = 3 } }, -- A 'CreateExistentialObject(typeID, T)` packs user-provided `typeID` and a -- value of any type, and constructs an existential value of type `I`. { createExistentialObject = { min_operands = 2 } }, -- A `wrapExistential(v, T0,w0, T1,w0) : T` instruction is similar to `makeExistential`. -- but applies to a value `v` that is of type `BindExistentials(T, T0,w0, ...)`. The -- result of the `wrapExistentials` operation is a value of type `T`, allowing us to -- "smuggle" a value of specialized type into computations that expect an unspecialized type. { wrapExistential = { min_operands = 1 } }, -- A `GetValueFromBoundInterface` takes a `BindInterface` value and returns the -- value of concrete type `T` value that is being stored. { getValueFromBoundInterface = { min_operands = 1 } }, { extractExistentialValue = { min_operands = 1 } }, { extractExistentialType = { min_operands = 1, hoistable = true } }, { extractExistentialWitnessTable = { min_operands = 1, hoistable = true, }, }, { isNullExistential = { min_operands = 1 } }, { extractTaggedUnionTag = { min_operands = 1 } }, { extractTaggedUnionPayload = { min_operands = 1 } }, { BuiltinCast = { min_operands = 1 } }, { bitCast = { min_operands = 1 } }, { reinterpret = { min_operands = 1 } }, { unmodified = { min_operands = 1 } }, { outImplicitCast = { min_operands = 1 } }, { inOutImplicitCast = { min_operands = 1 } }, { intCast = { min_operands = 1 } }, { floatCast = { min_operands = 1 } }, { castIntToFloat = { min_operands = 1 } }, { castFloatToInt = { min_operands = 1 } }, { CastPtrToBool = { min_operands = 1 } }, { CastPtrToInt = { min_operands = 1 } }, { CastIntToPtr = { min_operands = 1 } }, { castToVoid = { min_operands = 1 } }, { PtrCast = { min_operands = 1 } }, { CastEnumToInt = { min_operands = 1 } }, { CastIntToEnum = { min_operands = 1 } }, { EnumCast = { min_operands = 1 } }, { CastUInt2ToDescriptorHandle = { min_operands = 1 } }, { CastDescriptorHandleToUInt2 = { min_operands = 1 } }, -- Represents a psuedo cast to convert between a logical type (user declared) and a storage Type -- (valid in buffer locations). The operand can either be a value or an address. { CastStorageToLogicalBase = { min_operands = 2, struct_name = "CastStorageToLogicalBase", { CastStorageToLogical = { min_operands = 2, struct_name = "CastStorageToLogical" } }, { CastStorageToLogicalDeref = { min_operands = 2, struct_name = "CastStorageToLogicalDeref" } }, } }, { CastUInt64ToDescriptorHandle = { min_operands = 1 } }, { CastDescriptorHandleToUInt64 = { min_operands = 1 } }, -- Represents a no-op cast to convert a resource pointer to a resource on targets where the resource handles are -- already concrete types. { CastDescriptorHandleToResource = { min_operands = 1 } }, { CastResourceToDescriptorHandle = { min_operands = 1 } }, { TreatAsDynamicUniform = { min_operands = 1 } }, { sizeOf = { min_operands = 1 } }, { alignOf = { min_operands = 1 } }, { countOf = { min_operands = 1 } }, { GetArrayLength = { min_operands = 1 } }, { IsType = { min_operands = 3 } }, { TypeEquals = { min_operands = 2 } }, { IsInt = { min_operands = 1 } }, { IsBool = { min_operands = 1 } }, { IsFloat = { min_operands = 1 } }, { IsHalf = { min_operands = 1 } }, { IsUnsignedInt = { min_operands = 1 } }, { IsSignedInt = { min_operands = 1 } }, { IsVector = { min_operands = 1 } }, { GetDynamicResourceHeap = { hoistable = true } }, { ForwardDifferentiate = { min_operands = 1 } }, -- Produces the primal computation of backward derivatives, will return an intermediate context for -- backward derivative func. { BackwardDifferentiatePrimal = { min_operands = 1 } }, -- Produces the actual backward derivative propagate function, using the intermediate context returned by the -- primal func produced from `BackwardDifferentiatePrimal`. { BackwardDifferentiatePropagate = { min_operands = 1 } }, -- Represents the conceptual backward derivative function. Only produced by lower-to-ir and will be -- replaced with `BackwardDifferentiatePrimal` and `BackwardDifferentiatePropagate`. { BackwardDifferentiate = { min_operands = 1 } }, { PrimalSubstitute = { min_operands = 1 } }, { DispatchKernel = { min_operands = 3 } }, { CudaKernelLaunch = { min_operands = 6 } }, -- Converts other resources (such as ByteAddressBuffer) to the equivalent StructuredBuffer { getEquivalentStructuredBuffer = { min_operands = 1 } }, -- Gets a T[] pointer to the underlying data of a StructuredBuffer etc... { getStructuredBufferPtr = { min_operands = 1 } }, -- Gets a uint[] pointer to the underlying data of a ByteAddressBuffer etc... { getUntypedBufferPtr = { min_operands = 1 } }, { Layout = { hoistable = true, { varLayout = { min_operands = 1 } }, { TypeLayout = { { typeLayout = { struct_name = "TypeLayoutBase" }, }, { parameterGroupTypeLayout = { min_operands = 2 } }, { arrayTypeLayout = { min_operands = 1 }, }, { streamOutputTypeLayout = { min_operands = 1 } }, { matrixTypeLayout = { min_operands = 1 }, }, { existentialTypeLayout = {} }, { structTypeLayout = {} }, { tupleTypeLayout = {} }, { structuredBufferTypeLayout = { min_operands = 1 } }, { ptrTypeLayout = { -- "TODO(JS): Ideally we'd have the layout to the pointed to value type (ie 1 instead of 0 here). But to -- avoid infinite recursion we don't." struct_name = "PointerTypeLayout", }, }, }, }, { EntryPointLayout = { min_operands = 1 } }, }, }, { Attr = { hoistable = true, { pendingLayout = { struct_name = "PendingLayoutAttr", min_operands = 1, }, }, { stage = { struct_name = "StageAttr", min_operands = 1 } }, { structFieldLayout = { struct_name = "StructFieldLayoutAttr", min_operands = 2 } }, { tupleFieldLayout = { struct_name = "TupleFieldLayoutAttr", min_operands = 1 }, }, { caseLayout = { struct_name = "CaseTypeLayoutAttr", min_operands = 1, }, }, { unorm = { struct_name = "UNormAttr" } }, { snorm = { struct_name = "SNormAttr", }, }, { no_diff = { struct_name = "NoDiffAttr" } }, { nonuniform = { struct_name = "NonUniformAttr", }, }, { Aligned = { struct_name = "AlignedAttr", min_operands = 1 } }, { MemoryScope = { struct_name = "MemoryScopeAttr", min_operands = 1 } }, { SemanticAttr = { { userSemantic = { struct_name = "UserSemanticAttr", min_operands = 2 } }, { systemValueSemantic = { struct_name = "SystemValueSemanticAttr", min_operands = 2 } }, }, }, { LayoutResourceInfoAttr = { { size = { struct_name = "TypeSizeAttr", min_operands = 2 } }, { offset = { struct_name = "VarOffsetAttr", min_operands = 2 } }, }, }, { FuncThrowType = { struct_name = "FuncThrowTypeAttr", min_operands = 1 } }, }, }, -- Liveness { LiveRangeMarker = { { liveRangeStart = { min_operands = 2 } }, { liveRangeEnd = {} } }, }, -- IRSpecialization { SpecializationDictionaryItem = {} }, { GenericSpecializationDictionary = { parent = true } }, { ExistentialFuncSpecializationDictionary = { parent = true } }, { ExistentialTypeSpecializationDictionary = { parent = true } }, -- Differentiable Type Dictionary { DifferentiableTypeDictionaryItem = {} }, -- Differentiable Type Annotation (for run-time types) { DifferentiableTypeAnnotation = { min_operands = 2, hoistable = true } }, { BeginFragmentShaderInterlock = {} }, { EndFragmentShaderInterlock = { struct_name = "EndFragmentShaderInterlock" }, }, -- DebugInfo { DebugSource = { min_operands = 3, hoistable = true } }, { DebugLine = { min_operands = 5, }, }, { DebugVar = { min_operands = 4 } }, { DebugValue = { min_operands = 2, }, }, { DebugInlinedAt = { min_operands = 5 } }, { DebugFunction = { min_operands = 5, }, }, { DebugInlinedVariable = { min_operands = 2 } }, { DebugScope = { min_operands = 2, }, }, { DebugNoScope = { min_operands = 1 } }, { DebugBuildIdentifier = { min_operands = 2, }, }, -- Embedded Precompiled Libraries { EmbeddedDownstreamIR = { min_operands = 2 } }, -- Inline assembly { SPIRVAsm = { parent = true } }, { SPIRVAsmInst = { min_operands = 1 } }, { SPIRVAsmOperand = { { SPIRVAsmOperandLiteral = { -- These instruction serve to inform the backend precisely how to emit each -- instruction, consider the difference between emitting a literal integer -- and a reference to a literal integer instruction -- A literal string or 32-bit integer to be passed as operands min_operands = 1, hoistable = true, }, }, { SPIRVAsmOperandInst = { -- A reference to a slang IRInst, either a value or a type -- This isn't hoistable, as we sometimes need to change the used value and -- instructions around the specific asm block min_operands = 1, }, }, { SPIRVAsmOperandConvertTexel = { min_operands = 1 } }, { SPIRVAsmOperandRayPayloadFromLocation = { -- a late resolving type to handle the case of ray objects (resolving late due to constexpr data requirment) min_operands = 1, }, }, { SPIRVAsmOperandRayAttributeFromLocation = { min_operands = 1 } }, { SPIRVAsmOperandRayCallableFromLocation = { min_operands = 1 } }, { SPIRVAsmOperandEnum = { -- A named enumerator, the value is stored as a constant operand -- It may have a second operand, which if present is a type with which to -- construct a constant id to pass, instead of a literal constant min_operands = 1, hoistable = true, }, }, { SPIRVAsmOperandBuiltinVar = { -- A reference to a builtin variable. min_operands = 1, hoistable = true, }, }, { SPIRVAsmOperandGLSL450Set = { -- A reference to the glsl450 instruction set. hoistable = true, }, }, { SPIRVAsmOperandDebugPrintfSet = { hoistable = true } }, { SPIRVAsmOperandId = { -- A string which is given a unique ID in the backend, used to refer to -- results of other instrucions in the same asm block min_operands = 1, hoistable = true, }, }, { SPIRVAsmOperandResult = { -- A special instruction which marks the place to insert the generated -- result operand hoistable = true, }, }, { ["__truncate"] = { -- A special instruction which represents a type directed truncation -- operation where extra components are dropped struct_name = "SPIRVAsmOperandTruncate", hoistable = true, }, }, { ["__entryPoint"] = { -- A special instruction which represents an ID of an entry point that references the current function. struct_name = "SPIRVAsmOperandEntryPoint", hoistable = true, }, }, { ["__sampledType"] = { -- A type function which returns the result type of sampling an image of -- this component type struct_name = "SPIRVAsmOperandSampledType", min_operands = 1, hoistable = true, }, }, { ["__imageType"] = { -- A type function which returns the equivalent OpTypeImage type of sampled image value struct_name = "SPIRVAsmOperandImageType", min_operands = 1, hoistable = true, }, }, { ["__sampledImageType"] = { -- A type function which returns the equivalent OpTypeImage type of sampled image value struct_name = "SPIRVAsmOperandSampledImageType", min_operands = 1, hoistable = true, }, }, }, }, } -- A function to calculate some useful properties and put it in the table, -- -- Annotates instructions with whether they are a leaf or not -- Calculates flags from the parent flags local function process(insts) local stable_names_file = "source/slang/slang-ir-insts-stable-names.lua" local function to_pascal_case(str) local result = str:gsub("_(.)", function(c) return c:upper() end) return result:sub(1, 1):upper() .. result:sub(2) end -- Check if an instruction is a leaf local function is_leaf(inst) for k, v in ipairs(inst) do return false end return true end -- Load stable names if file is provided local name_to_stable_name = loadfile(stable_names_file)() local stable_name_to_inst = {} local max_stable_name = 0 -- Build full path for stable name lookup local function build_path(inst, name) local path = { name } local current = inst.parent_inst while current and current.parent_inst do -- Find the name of current in its parent for _, entry in ipairs(current.parent_inst) do local k, v = next(entry) if v == current then table.insert(path, 1, k) break end end current = current.parent_inst end return table.concat(path, ".") end -- Recursively process instructions local function process_inst(tbl, inherited_flags) inherited_flags = inherited_flags or {} -- Collect flags from current level local current_flags = {} for k, v in pairs(inherited_flags) do current_flags[k] = v end -- Add flags from this table if it has any if tbl.hoistable then current_flags.hoistable = true end if tbl.parent then current_flags.parent = true end if tbl.useOther then current_flags.useOther = true end if tbl.global then current_flags.global = true end -- If we have any children, this will be set to false tbl.is_leaf = true for _, i in ipairs(tbl) do local key, value = next(i) tbl.is_leaf = false if not value.mnemonic then value.mnemonic = key end -- Add struct_name if missing if not value.struct_name then value.struct_name = to_pascal_case(key) end value.parent_inst = tbl -- Apply inherited flags for flag, flag_value in pairs(current_flags) do if value[flag] == nil then value[flag] = flag_value end end -- If it's a leaf and doesn't have min_operands and operands, add min_operands = 0 if is_leaf(value) and value.min_operands == nil and value.operands == nil then value.min_operands = 0 end -- Recursively process children process_inst(value, current_flags) end end -- Process the entire tree process_inst(insts) -- Now add stable names after parent_inst is set local function add_stable_names(tbl) for _, i in ipairs(tbl) do local key, value = next(i) -- Build the full path for this instruction local full_path = build_path(value, key) -- Look up stable name local stable_id = name_to_stable_name[full_path] if stable_id then value.stable_name = stable_id stable_name_to_inst[stable_id] = value if stable_id > max_stable_name then max_stable_name = stable_id end end -- Recursively process children add_stable_names(value) end end -- Add stable names to all instructions add_stable_names(insts) -- Helper function to traverse the instruction tree local function traverse(callback) local function walk_insts(tbl) for _, i in ipairs(tbl) do local _, value = next(i) callback(value) -- Recursively process nested instructions walk_insts(value) end end -- Start walking from the top-level insts walk_insts(insts) end return { insts = insts, stable_name_to_inst = stable_name_to_inst, max_stable_name = max_stable_name, traverse = traverse, } end return process(insts)