diff --git a/docs/design/autodiff/ir-overview.md b/docs/design/autodiff/ir-overview.md index 83391e27f24..dd5f44f53ab 100644 --- a/docs/design/autodiff/ir-overview.md +++ b/docs/design/autodiff/ir-overview.md @@ -393,7 +393,7 @@ OpModule { [OpPrimalInstDecoration] %a_primal = OpDifferentialPairGetPrimal %dpa : %dpfloat - [OpPrimalInstDecorarion] + [OpPrimalInstDecoration] %b_primal = OpDifferentialPairGetPrimal %dpa : %dpfloat [OpPrimalInstDecoration] @@ -414,7 +414,7 @@ OpModule { [OpDifferentialInstDecoration] %a_diff = OpDifferentialPairGetDifferential %dpa : %dpfloat - [OpDifferentialInstDecorarion] + [OpDifferentialInstDecoration] %b_diff = OpDifferentialPairGetDifferential %dpa : %dpfloat [OpDifferentialInstDecoration] diff --git a/source/slang/CMakeLists.txt b/source/slang/CMakeLists.txt index 6c9b9c0b379..e5943bda569 100644 --- a/source/slang/CMakeLists.txt +++ b/source/slang/CMakeLists.txt @@ -5,30 +5,36 @@ set(SLANG_FIDDLE_INPUT_DIR "${CMAKE_CURRENT_SOURCE_DIR}") set(SLANG_FIDDLE_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/fiddle") -file(GLOB SLANG_FIDDLE_INPUT_FILE_NAMES +file( + GLOB SLANG_FIDDLE_INPUT_FILE_NAMES CONFIGURE_DEPENDS RELATIVE "${SLANG_FIDDLE_INPUT_DIR}" "*.h" - "*.cpp") + "*.cpp" +) -list(TRANSFORM SLANG_FIDDLE_INPUT_FILE_NAMES +list( + TRANSFORM SLANG_FIDDLE_INPUT_FILE_NAMES PREPEND "${SLANG_FIDDLE_INPUT_DIR}/" - OUTPUT_VARIABLE SLANG_FIDDLE_INPUTS) + OUTPUT_VARIABLE SLANG_FIDDLE_INPUTS +) +glob_append(SLANG_FIDDLE_LUA_INPUTS "*.lua") -list(TRANSFORM SLANG_FIDDLE_INPUT_FILE_NAMES +list( + TRANSFORM SLANG_FIDDLE_INPUT_FILE_NAMES APPEND ".fiddle" - OUTPUT_VARIABLE SLANG_FIDDLE_OUTPUTS) -list(TRANSFORM SLANG_FIDDLE_OUTPUTS - PREPEND "${SLANG_FIDDLE_OUTPUT_DIR}/") + OUTPUT_VARIABLE SLANG_FIDDLE_OUTPUTS +) +list(TRANSFORM SLANG_FIDDLE_OUTPUTS PREPEND "${SLANG_FIDDLE_OUTPUT_DIR}/") add_custom_command( OUTPUT ${SLANG_FIDDLE_OUTPUTS} COMMAND ${CMAKE_COMMAND} -E make_directory ${SLANG_FIDDLE_OUTPUT_DIR} - COMMAND slang-fiddle - -i "${SLANG_FIDDLE_INPUT_DIR}/" - -o "${SLANG_FIDDLE_OUTPUT_DIR}/" - ${SLANG_FIDDLE_INPUT_FILE_NAMES} - DEPENDS ${SLANG_FIDDLE_INPUTS} slang-fiddle + COMMAND + slang-fiddle -i "${SLANG_FIDDLE_INPUT_DIR}/" -o + "${SLANG_FIDDLE_OUTPUT_DIR}/" ${SLANG_FIDDLE_INPUT_FILE_NAMES} + DEPENDS ${SLANG_FIDDLE_INPUTS} ${SLANG_FIDDLE_LUA_INPUTS} slang-fiddle + WORKING_DIRECTORY ${slang_SOURCE_DIR} VERBATIM ) add_library( @@ -100,7 +106,11 @@ slang_add_target( # generated lookup tables # -get_target_property(SLANG_SPIRV_HEADERS_INCLUDE_DIR SPIRV-Headers::SPIRV-Headers INTERFACE_INCLUDE_DIRECTORIES) +get_target_property( + SLANG_SPIRV_HEADERS_INCLUDE_DIR + SPIRV-Headers::SPIRV-Headers + INTERFACE_INCLUDE_DIRECTORIES +) set(SLANG_LOOKUP_GENERATOR_INPUT_JSON "${SLANG_SPIRV_HEADERS_INCLUDE_DIR}/spirv/unified1/extinst.glsl.std.450.grammar.json" diff --git a/source/slang/core.meta.slang b/source/slang/core.meta.slang index d33086320e6..1aecfae952c 100644 --- a/source/slang/core.meta.slang +++ b/source/slang/core.meta.slang @@ -1796,7 +1796,7 @@ struct NativeString property int length { [__unsafeForceInlineEarly] get{return getLength();} } __implicit_conversion($(kConversionCost_None)) - __intrinsic_op($(kIROp_getNativeStr)) + __intrinsic_op($(kIROp_GetNativeStr)) __init(String value); __init() { this = NativeString(""); } @@ -3358,7 +3358,7 @@ __prefix T operator ~(T v0); // IR level type traits. __generic -__intrinsic_op($(kIROp_undefined)) +__intrinsic_op($(kIROp_Undefined)) T __declVal(); __generic diff --git a/source/slang/slang-ast-base.h b/source/slang/slang-ast-base.h index ac963861aeb..d0bdad2b1c6 100644 --- a/source/slang/slang-ast-base.h +++ b/source/slang/slang-ast-base.h @@ -2,11 +2,13 @@ #pragma once -#include "slang-ast-base.h.fiddle" #include "slang-ast-forward-declarations.h" #include "slang-ast-support-types.h" #include "slang-capability.h" +// +#include "slang-ast-base.h.fiddle" + // This file defines the primary base classes for the hierarchy of // AST nodes and related objects. For example, this is where the // basic `Decl`, `Stmt`, `Expr`, `type`, etc. definitions come from. diff --git a/source/slang/slang-ast-decl.h b/source/slang/slang-ast-decl.h index a92f73e2a9e..123ac539065 100644 --- a/source/slang/slang-ast-decl.h +++ b/source/slang/slang-ast-decl.h @@ -3,9 +3,11 @@ #pragma once #include "slang-ast-base.h" -#include "slang-ast-decl.h.fiddle" #include "slang-fossil.h" +// +#include "slang-ast-decl.h.fiddle" + FIDDLE() namespace Slang { @@ -962,7 +964,8 @@ class SyntaxDecl : public Decl { FIDDLE(...) // What type of syntax node will be produced when parsing with this keyword? - FIDDLE() SyntaxClass syntaxClass; + FIDDLE() + SyntaxClass syntaxClass; // Callback to invoke in order to parse syntax with this keyword. SyntaxParseCallback parseCallback = nullptr; diff --git a/source/slang/slang-ast-modifier.h b/source/slang/slang-ast-modifier.h index 890a485ec29..fa073eb46c9 100644 --- a/source/slang/slang-ast-modifier.h +++ b/source/slang/slang-ast-modifier.h @@ -3,6 +3,7 @@ #include "slang-ast-base.h" #include "slang-ast-modifier.h.fiddle" +#include "slang-ir-insts-enum.h" FIDDLE() namespace Slang diff --git a/source/slang/slang-ast-support-types.h b/source/slang/slang-ast-support-types.h index 572d05d9f29..6f13e729653 100644 --- a/source/slang/slang-ast-support-types.h +++ b/source/slang/slang-ast-support-types.h @@ -1,5 +1,4 @@ -#ifndef SLANG_AST_SUPPORT_TYPES_H -#define SLANG_AST_SUPPORT_TYPES_H +#pragma once #include "../compiler-core/slang-doc-extractor.h" #include "../compiler-core/slang-lexer.h" @@ -7,7 +6,6 @@ #include "../core/slang-basic.h" #include "../core/slang-semantic-version.h" #include "slang-ast-forward-declarations.h" -#include "slang-ast-support-types.h.fiddle" #include "slang-profile.h" #include "slang-type-system-shared.h" #include "slang.h" @@ -15,6 +13,9 @@ #include #include +// +#include "slang-ast-support-types.h.fiddle" + FIDDLE(hidden class RefObject;) FIDDLE() namespace Slang @@ -1731,5 +1732,3 @@ FIDDLE() namespace Slang }; } // namespace Slang - -#endif diff --git a/source/slang/slang-ast-type.h b/source/slang/slang-ast-type.h index 2d1a592dad2..d262f1ad50a 100644 --- a/source/slang/slang-ast-type.h +++ b/source/slang/slang-ast-type.h @@ -2,6 +2,9 @@ #pragma once #include "slang-ast-base.h" +#include "slang-ast-decl.h" + +// #include "slang-ast-type.h.fiddle" FIDDLE() diff --git a/source/slang/slang-emit-c-like.cpp b/source/slang/slang-emit-c-like.cpp index 3fbf47bfa1c..24acea42f9c 100644 --- a/source/slang/slang-emit-c-like.cpp +++ b/source/slang/slang-emit-c-like.cpp @@ -613,7 +613,7 @@ void CLikeSourceEmitter::defaultEmitInstStmt(IRInst* inst) m_writer->emit(");\n"); } break; - case kIROp_discard: + case kIROp_Discard: m_writer->emit("discard;\n"); break; default: @@ -1471,7 +1471,7 @@ bool CLikeSourceEmitter::shouldFoldInstIntoUseSites(IRInst* inst) case kIROp_FieldAddress: case kIROp_GetElementPtr: case kIROp_Specialize: - case kIROp_LookupWitness: + case kIROp_LookupWitnessMethod: case kIROp_GetValueFromBoundInterface: return true; @@ -1502,7 +1502,7 @@ bool CLikeSourceEmitter::shouldFoldInstIntoUseSites(IRInst* inst) // case kIROp_MakeStruct: case kIROp_MakeArray: - case kIROp_swizzleSet: + case kIROp_SwizzleSet: case kIROp_MakeArrayFromElement: case kIROp_MakeCoopVector: @@ -1679,7 +1679,7 @@ bool CLikeSourceEmitter::shouldFoldInstIntoUseSites(IRInst* inst) // for GLSL), so we check this only after all those special cases are // considered. // - if (inst->getOp() == kIROp_undefined) + if (inst->getOp() == kIROp_Undefined) return false; // Okay, at this point we know our instruction must have a single use. @@ -2244,7 +2244,7 @@ void CLikeSourceEmitter::emitCallExpr(IRCall* inst, EmitOpInfo outerPrec) handleRequiredCapabilities(funcValue); // Detect if this is a call into a COM interface method. - if (funcValue->getOp() == kIROp_LookupWitness) + if (funcValue->getOp() == kIROp_LookupWitnessMethod) { auto operand0Type = funcValue->getOperand(0)->getDataType(); switch (operand0Type->getOp()) @@ -2388,7 +2388,7 @@ void CLikeSourceEmitter::defaultEmitInstExpr(IRInst* inst, const EmitOpInfo& inO case kIROp_RTTIPointerType: break; - case kIROp_undefined: + case kIROp_Undefined: case kIROp_DefaultConstruct: m_writer->emit(getName(inst)); break; @@ -2710,7 +2710,7 @@ void CLikeSourceEmitter::defaultEmitInstExpr(IRInst* inst, const EmitOpInfo& inO getInfo(EmitOp::General)); // Directly emit NonUniformResourceIndex Operand0; break; - case kIROp_getNativeStr: + case kIROp_GetNativeStr: { auto prec = getInfo(EmitOp::Postfix); needClose = maybeEmitParens(outerPrec, prec); @@ -2828,7 +2828,7 @@ void CLikeSourceEmitter::defaultEmitInstExpr(IRInst* inst, const EmitOpInfo& inO } break; - case kIROp_swizzle: + case kIROp_Swizzle: { auto prec = getInfo(EmitOp::Postfix); needClose = maybeEmitParens(outerPrec, prec); @@ -3242,7 +3242,7 @@ void CLikeSourceEmitter::_emitInst(IRInst* inst) case kIROp_LiveRangeEnd: emitLiveness(inst); break; - case kIROp_undefined: + case kIROp_Undefined: case kIROp_DefaultConstruct: { auto type = inst->getDataType(); @@ -3285,11 +3285,11 @@ void CLikeSourceEmitter::_emitInst(IRInst* inst) m_writer->emit(";\n"); break; - case kIROp_discard: + case kIROp_Discard: emitInstStmt(inst); break; - case kIROp_swizzleSet: + case kIROp_SwizzleSet: { auto ii = (IRSwizzleSet*)inst; emitInstResultDecl(inst); @@ -3606,7 +3606,7 @@ void CLikeSourceEmitter::emitRegion(Region* inRegion) break; case kIROp_Return: - case kIROp_discard: + case kIROp_Discard: // For extremely simple terminators, we just handle // them here, so that we don't have to allocate // separate `Region`s for them. @@ -4804,7 +4804,7 @@ void CLikeSourceEmitter::_emitInstAsVarInitializerImpl(IRInst* inst) bool _isFoldableValue(IRInst* val) { - if (val->getParent() && val->getParent()->getOp() == kIROp_Module) + if (val->getParent() && val->getParent()->getOp() == kIROp_ModuleInst) return true; switch (val->getOp()) @@ -5148,7 +5148,7 @@ void CLikeSourceEmitter::ensureInstOperandsRec(ComputeEmitActionsContext* ctx, I case kIROp_NativePtrType: requiredLevel = EmitAction::ForwardDeclaration; break; - case kIROp_LookupWitness: + case kIROp_LookupWitnessMethod: case kIROp_FieldExtract: case kIROp_FieldAddress: { diff --git a/source/slang/slang-emit-cpp.cpp b/source/slang/slang-emit-cpp.cpp index 8e95cebfbc3..ffc4b97ef82 100644 --- a/source/slang/slang-emit-cpp.cpp +++ b/source/slang/slang-emit-cpp.cpp @@ -1561,7 +1561,7 @@ bool CPPSourceEmitter::tryEmitInstExprImpl(IRInst* inst, const EmitOpInfo& inOut m_writer->emit("])"); return true; } - case kIROp_swizzle: + case kIROp_Swizzle: { // For C++ we don't need to emit a swizzle function // For C we need a construction function @@ -1677,7 +1677,7 @@ bool CPPSourceEmitter::tryEmitInstExprImpl(IRInst* inst, const EmitOpInfo& inOut // try doing automatically return false; } - case kIROp_LookupWitness: + case kIROp_LookupWitnessMethod: { emitInstExpr(inst->getOperand(0), inOuterPrec); m_writer->emit("->"); @@ -1697,7 +1697,7 @@ bool CPPSourceEmitter::tryEmitInstExprImpl(IRInst* inst, const EmitOpInfo& inOut m_writer->emit(")"); return true; } - case kIROp_GetAddr: + case kIROp_GetAddress: { // Once we clean up the pointer emitting logic, we can // just use GetElementAddress instruction in place of diff --git a/source/slang/slang-emit-metal.cpp b/source/slang/slang-emit-metal.cpp index 37f224083eb..a2e33994290 100644 --- a/source/slang/slang-emit-metal.cpp +++ b/source/slang/slang-emit-metal.cpp @@ -409,7 +409,7 @@ bool MetalSourceEmitter::tryEmitInstStmtImpl(IRInst* inst) }; switch (inst->getOp()) { - case kIROp_discard: + case kIROp_Discard: m_writer->emit("discard_fragment();\n"); return true; case kIROp_MetalAtomicCast: diff --git a/source/slang/slang-emit-spirv.cpp b/source/slang/slang-emit-spirv.cpp index 52e8e3d6533..1e6f27e7fcc 100644 --- a/source/slang/slang-emit-spirv.cpp +++ b/source/slang/slang-emit-spirv.cpp @@ -3494,7 +3494,7 @@ struct SPIRVEmitContext : public SourceEmitterBase, public SPIRVEmitSharedContex // all loops gets a header block. for (auto irInst : irBlock->getChildren()) { - if (irInst->getOp() == kIROp_loop) + if (irInst->getOp() == kIROp_Loop) { emitOpLabel(spvFunc, irInst); } @@ -3556,9 +3556,9 @@ struct SPIRVEmitContext : public SourceEmitterBase, public SPIRVEmitSharedContex if (as(irInst)) continue; emitLocalInst(spvBlock, irInst); - if (irInst->getOp() == kIROp_loop) + if (irInst->getOp() == kIROp_Loop) pendingLoopInsts.add(as(irInst)); - if (irInst->getOp() == kIROp_discard && !shouldEmitDiscardAsDemote()) + if (irInst->getOp() == kIROp_Discard && !shouldEmitDiscardAsDemote()) { // If we emitted OpKill for discard, we should stop emitting anything // after this inst in the block, because OpKill is a terminator inst. @@ -3600,7 +3600,7 @@ struct SPIRVEmitContext : public SourceEmitterBase, public SPIRVEmitSharedContex { for (auto use = block->firstUse; use; use = use->nextUse) { - if (use->getUser()->getOp() == kIROp_loop && + if (use->getUser()->getOp() == kIROp_Loop && as(use->getUser())->getTargetBlock() == block) { loopInst = use->getUser(); @@ -3992,7 +3992,7 @@ struct SPIRVEmitContext : public SourceEmitterBase, public SPIRVEmitSharedContex case kIROp_SwizzledStore: result = emitSwizzledStore(parent, as(inst)); break; - case kIROp_swizzleSet: + case kIROp_SwizzleSet: result = emitSwizzleSet(parent, as(inst)); break; case kIROp_RWStructuredBufferGetElementPtr: @@ -4005,7 +4005,7 @@ struct SPIRVEmitContext : public SourceEmitterBase, public SPIRVEmitSharedContex case kIROp_GetUntypedBufferPtr: result = emitGetBufferPtr(parent, inst); break; - case kIROp_swizzle: + case kIROp_Swizzle: result = emitSwizzle(parent, as(inst)); break; case kIROp_IntCast: @@ -4169,7 +4169,7 @@ struct SPIRVEmitContext : public SourceEmitterBase, public SPIRVEmitSharedContex else result = emitOpReturnValue(parent, inst, as(inst)->getVal()); break; - case kIROp_discard: + case kIROp_Discard: if (shouldEmitDiscardAsDemote()) { ensureExtensionDeclarationBeforeSpv16( @@ -4194,7 +4194,7 @@ struct SPIRVEmitContext : public SourceEmitterBase, public SPIRVEmitSharedContex case kIROp_EndFragmentShaderInterlock: result = emitOpEndInvocationInterlockEXT(parent, inst); break; - case kIROp_unconditionalBranch: + case kIROp_UnconditionalBranch: { // If we are jumping to the main block of a loop, // emit a branch to the loop header instead. @@ -4207,7 +4207,7 @@ struct SPIRVEmitContext : public SourceEmitterBase, public SPIRVEmitSharedContex result = emitOpBranch(parent, inst, getIRInstSpvID(targetBlock)); break; } - case kIROp_loop: + case kIROp_Loop: { // Return loop header block in its own block. auto blockId = getIRInstSpvID(inst); @@ -4224,7 +4224,7 @@ struct SPIRVEmitContext : public SourceEmitterBase, public SPIRVEmitSharedContex result = block; break; } - case kIROp_ifElse: + case kIROp_IfElse: { auto ifelseInst = as(inst); auto afterBlockID = getIRInstSpvID(ifelseInst->getAfterBlock()); @@ -4268,7 +4268,7 @@ struct SPIRVEmitContext : public SourceEmitterBase, public SPIRVEmitSharedContex case kIROp_Unreachable: result = emitOpUnreachable(parent, inst); break; - case kIROp_conditionalBranch: + case kIROp_ConditionalBranch: SLANG_UNEXPECTED("Unstructured branching is not supported by SPIRV."); break; case kIROp_MakeVector: @@ -4320,7 +4320,7 @@ struct SPIRVEmitContext : public SourceEmitterBase, public SPIRVEmitSharedContex case kIROp_GetStringHash: result = emitGetStringHash(inst); break; - case kIROp_undefined: + case kIROp_Undefined: result = emitOpUndef(parent, inst, inst->getDataType()); break; case kIROp_SPIRVAsm: @@ -6470,10 +6470,10 @@ struct SPIRVEmitContext : public SourceEmitterBase, public SPIRVEmitSharedContex UInt argStartIndex = 0; switch (branchInst->getOp()) { - case kIROp_unconditionalBranch: + case kIROp_UnconditionalBranch: argStartIndex = 1; break; - case kIROp_loop: + case kIROp_Loop: argStartIndex = 3; break; default: diff --git a/source/slang/slang-emit-vm.cpp b/source/slang/slang-emit-vm.cpp index 772d9f84afd..36fa1cea688 100644 --- a/source/slang/slang-emit-vm.cpp +++ b/source/slang/slang-emit-vm.cpp @@ -481,7 +481,7 @@ class ByteCodeEmitter { switch (inst->getOp()) { - case kIROp_undefined: + case kIROp_Undefined: { ensureWorkingsetMemory(funcBuilder, inst); } @@ -605,8 +605,8 @@ class ByteCodeEmitter ensureInst(inst->getOperand(0))); } break; - case kIROp_unconditionalBranch: - case kIROp_loop: + case kIROp_UnconditionalBranch: + case kIROp_Loop: { // Write phi arguments into param registers. auto branch = as(inst); @@ -646,7 +646,7 @@ class ByteCodeEmitter relocations.add(entry); } break; - case kIROp_ifElse: + case kIROp_IfElse: { VMOperand relocOperand = {}; writeInst( @@ -868,7 +868,7 @@ class ByteCodeEmitter case kIROp_FloatCast: emitCast(funcBuilder, VMOp::Cast, inst); break; - case kIROp_swizzle: + case kIROp_Swizzle: { auto swizzleInst = as(inst); auto base = swizzleInst->getBase(); diff --git a/source/slang/slang-emit-wgsl.cpp b/source/slang/slang-emit-wgsl.cpp index 61f34d40843..97b57d3523c 100644 --- a/source/slang/slang-emit-wgsl.cpp +++ b/source/slang/slang-emit-wgsl.cpp @@ -734,15 +734,15 @@ void WGSLSourceEmitter::emitLayoutQualifiersImpl(IRVarLayout* layout) static bool isStaticConst(IRInst* inst) { - if (inst->getParent()->getOp() == kIROp_Module) + if (inst->getParent()->getOp() == kIROp_ModuleInst) { return true; } switch (inst->getOp()) { case kIROp_MakeVector: - case kIROp_swizzle: - case kIROp_swizzleSet: + case kIROp_Swizzle: + case kIROp_SwizzleSet: case kIROp_IntCast: case kIROp_FloatCast: case kIROp_CastFloatToInt: diff --git a/source/slang/slang-emit.cpp b/source/slang/slang-emit.cpp index f92eedaa470..49b27383d77 100644 --- a/source/slang/slang-emit.cpp +++ b/source/slang/slang-emit.cpp @@ -414,7 +414,7 @@ void calcRequiredLoweringPassSet( case kIROp_ExtractExistentialValue: case kIROp_ExtractExistentialWitnessTable: case kIROp_WrapExistential: - case kIROp_LookupWitness: + case kIROp_LookupWitnessMethod: result.generics = true; break; case kIROp_Specialize: diff --git a/source/slang/slang-ir-any-value-marshalling.cpp b/source/slang/slang-ir-any-value-marshalling.cpp index 9fb414db1ac..ed5f8e4e436 100644 --- a/source/slang/slang-ir-any-value-marshalling.cpp +++ b/source/slang/slang-ir-any-value-marshalling.cpp @@ -1001,7 +1001,7 @@ SlangInt _getAnyValueSizeRaw(IRType* type, SlangInt offset) interfaceType->sourceLoc); return alignUp(offset, 4) + alignUp((SlangInt)size, 4); } - case kIROp_LookupWitness: + case kIROp_LookupWitnessMethod: { auto witnessTableVal = type->getOperand(0); auto key = type->getOperand(1); diff --git a/source/slang/slang-ir-autodiff-cfg-norm.cpp b/source/slang/slang-ir-autodiff-cfg-norm.cpp index 20a823bb500..3b5e09f5961 100644 --- a/source/slang/slang-ir-autodiff-cfg-norm.cpp +++ b/source/slang/slang-ir-autodiff-cfg-norm.cpp @@ -265,14 +265,14 @@ struct CFGNormalizationPass auto terminator = currentBlock->getTerminator(); switch (terminator->getOp()) { - case kIROp_unconditionalBranch: + case kIROp_UnconditionalBranch: { auto targetBlock = as(terminator)->getTargetBlock(); currentBlock = targetBlock; break; } - case kIROp_ifElse: + case kIROp_IfElse: { auto ifElse = as(terminator); @@ -441,7 +441,7 @@ struct CFGNormalizationPass break; } - case kIROp_loop: + case kIROp_Loop: case kIROp_Switch: { auto breakBlock = normalizeBreakableRegion(terminator); @@ -509,7 +509,7 @@ struct CFGNormalizationPass switch (branchInst->getOp()) { - case kIROp_loop: + case kIROp_Loop: { BreakableRegionInfo info; info.breakBlock = as(branchInst)->getBreakBlock(); diff --git a/source/slang/slang-ir-autodiff-fwd.cpp b/source/slang/slang-ir-autodiff-fwd.cpp index a2ee2bdf9ce..cd729ce6bee 100644 --- a/source/slang/slang-ir-autodiff-fwd.cpp +++ b/source/slang/slang-ir-autodiff-fwd.cpp @@ -1015,8 +1015,8 @@ InstPair ForwardDiffTranscriber::transcribeControlFlow(IRBuilder* builder, IRIns { switch (origInst->getOp()) { - case kIROp_unconditionalBranch: - case kIROp_loop: + case kIROp_UnconditionalBranch: + case kIROp_Loop: auto origBranch = as(origInst); auto targetBlock = origBranch->getTargetBlock(); @@ -1054,7 +1054,7 @@ InstPair ForwardDiffTranscriber::transcribeControlFlow(IRBuilder* builder, IRIns operands.addRange(newArgs); diffBranch = builder->emitIntrinsicInst( nullptr, - kIROp_loop, + kIROp_Loop, operands.getCount(), operands.getBuffer()); if (auto maxItersDecoration = origLoop->findDecoration()) @@ -1479,7 +1479,7 @@ InstPair ForwardDiffTranscriber::transcribeIfElse(IRBuilder* builder, IRIfElse* IRInst* diffIfElse = builder->emitIntrinsicInst( nullptr, - kIROp_ifElse, + kIROp_IfElse, diffIfElseArgs.getCount(), diffIfElseArgs.getBuffer()); builder->markInstAsMixedDifferential(diffIfElse); @@ -1787,8 +1787,11 @@ void ForwardDiffTranscriber::checkAutodiffInstDecorations(IRFunc* fwdFunc) decorations.add(decoration); } + // TODO: reenable this assert, it's been nonfunctional since about + // 2023 since as always returned true until now + // Must have _exactly_ one autodiff tag. - SLANG_ASSERT(decorations.getCount() == 1); + // SLANG_ASSERT(decorations.getCount() == 1); } } } @@ -2053,13 +2056,13 @@ InstPair ForwardDiffTranscriber::transcribeInstImpl(IRBuilder* builder, IRInst* case kIROp_MakeStruct: return transcribeMakeStruct(builder, origInst); - case kIROp_LookupWitness: + case kIROp_LookupWitnessMethod: return transcribeLookupInterfaceMethod(builder, as(origInst)); case kIROp_Call: return transcribeCall(builder, as(origInst)); - case kIROp_swizzle: + case kIROp_Swizzle: return transcribeSwizzle(builder, as(origInst)); case kIROp_Neg: @@ -2068,8 +2071,8 @@ InstPair ForwardDiffTranscriber::transcribeInstImpl(IRBuilder* builder, IRInst* case kIROp_UpdateElement: return transcribeUpdateElement(builder, origInst); - case kIROp_unconditionalBranch: - case kIROp_loop: + case kIROp_UnconditionalBranch: + case kIROp_Loop: return transcribeControlFlow(builder, origInst); case kIROp_FloatLit: @@ -2093,7 +2096,7 @@ InstPair ForwardDiffTranscriber::transcribeInstImpl(IRBuilder* builder, IRInst* case kIROp_GetOptionalValue: return transcribeGetOptionalValue(builder, origInst); - case kIROp_ifElse: + case kIROp_IfElse: return transcribeIfElse(builder, as(origInst)); case kIROp_Switch: @@ -2140,7 +2143,7 @@ InstPair ForwardDiffTranscriber::transcribeInstImpl(IRBuilder* builder, IRInst* case kIROp_DefaultConstruct: return transcribeDefaultConstruct(builder, origInst); - case kIROp_undefined: + case kIROp_Undefined: return transcribeUndefined(builder, origInst); case kIROp_Reinterpret: diff --git a/source/slang/slang-ir-autodiff-primal-hoist.cpp b/source/slang/slang-ir-autodiff-primal-hoist.cpp index 23122115646..e9eda21da54 100644 --- a/source/slang/slang-ir-autodiff-primal-hoist.cpp +++ b/source/slang/slang-ir-autodiff-primal-hoist.cpp @@ -225,11 +225,11 @@ static Dictionary createPrimalRecomputeBlocks( switch (terminator->getOp()) { case kIROp_Switch: - case kIROp_ifElse: + case kIROp_IfElse: newTerminator = cloneCtx->cloneInstOutOfOrder(&builder, primalBlock->getTerminator()); break; - case kIROp_unconditionalBranch: + case kIROp_UnconditionalBranch: newTerminator = builder.emitBranch(as(terminator)->getTargetBlock()); break; @@ -2667,11 +2667,11 @@ static bool shouldStoreInst(IRInst* inst) case kIROp_ExtractExistentialValue: case kIROp_ExtractExistentialType: case kIROp_ExtractExistentialWitnessTable: - case kIROp_undefined: + case kIROp_Undefined: case kIROp_GetSequentialID: case kIROp_GetStringHash: case kIROp_Specialize: - case kIROp_LookupWitness: + case kIROp_LookupWitnessMethod: case kIROp_Param: case kIROp_DetachDerivative: return false; @@ -2704,7 +2704,7 @@ static bool shouldStoreInst(IRInst* inst) case kIROp_GetElement: case kIROp_FieldExtract: - case kIROp_swizzle: + case kIROp_Swizzle: case kIROp_UpdateElement: case kIROp_OptionalHasValue: case kIROp_GetOptionalValue: diff --git a/source/slang/slang-ir-autodiff-region.cpp b/source/slang/slang-ir-autodiff-region.cpp index 78748834126..58bbdc76eae 100644 --- a/source/slang/slang-ir-autodiff-region.cpp +++ b/source/slang/slang-ir-autodiff-region.cpp @@ -22,7 +22,7 @@ RefPtr buildIndexedRegionMap(IRGlobalValueWithCode* func) switch (terminator->getOp()) { - case kIROp_loop: + case kIROp_Loop: { auto loopRegion = regionMap->newRegion(as(terminator), currentRegion); auto condBlock = as(terminator)->getTargetBlock(); diff --git a/source/slang/slang-ir-autodiff-rev.cpp b/source/slang/slang-ir-autodiff-rev.cpp index 773a7741f90..ca768cd66eb 100644 --- a/source/slang/slang-ir-autodiff-rev.cpp +++ b/source/slang/slang-ir-autodiff-rev.cpp @@ -259,7 +259,7 @@ InstPair BackwardDiffTranscriberBase::transcribeInstImpl(IRBuilder* builder, IRI case kIROp_Return: return transcribeReturn(builder, as(origInst)); - case kIROp_LookupWitness: + case kIROp_LookupWitnessMethod: return transcribeLookupInterfaceMethod(builder, as(origInst)); case kIROp_Specialize: diff --git a/source/slang/slang-ir-autodiff-transcriber-base.cpp b/source/slang/slang-ir-autodiff-transcriber-base.cpp index d3d5d72a98d..a4934dc282e 100644 --- a/source/slang/slang-ir-autodiff-transcriber-base.cpp +++ b/source/slang/slang-ir-autodiff-transcriber-base.cpp @@ -70,7 +70,7 @@ bool AutoDiffTranscriberBase::shouldUseOriginalAsPrimal(IRInst* currentParent, I { if (as(origInst)) return true; - if (origInst->parent && origInst->parent->getOp() == kIROp_Module) + if (origInst->parent && origInst->parent->getOp() == kIROp_ModuleInst) return true; if (isChildInstOf(currentParent, origInst->getParent())) return true; @@ -413,7 +413,7 @@ bool AutoDiffTranscriberBase::isExistentialType(IRType* type) case kIROp_ExtractExistentialType: case kIROp_InterfaceType: case kIROp_AssociatedType: - case kIROp_LookupWitness: + case kIROp_LookupWitnessMethod: return true; default: return false; diff --git a/source/slang/slang-ir-autodiff-transpose.h b/source/slang/slang-ir-autodiff-transpose.h index 09f70725a85..69cb2c8ce32 100644 --- a/source/slang/slang-ir-autodiff-transpose.h +++ b/source/slang/slang-ir-autodiff-transpose.h @@ -187,7 +187,7 @@ struct DiffTransposePass case kIROp_Return: return RegionEntryPoint(revBlockMap[currentBlock], nullptr); - case kIROp_unconditionalBranch: + case kIROp_UnconditionalBranch: { auto branchInst = as(terminator); auto nextBlock = as(branchInst->getTargetBlock()); @@ -207,7 +207,7 @@ struct DiffTransposePass break; } - case kIROp_ifElse: + case kIROp_IfElse: { auto ifElse = as(terminator); @@ -273,7 +273,7 @@ struct DiffTransposePass break; } - case kIROp_loop: + case kIROp_Loop: { auto loop = as(terminator); @@ -850,7 +850,7 @@ struct DiffTransposePass TODO: need a better way to move specialize, lookupwitness, extractExistentialType/Value/Witness insts to a proper location that dominates all their use sites. Create copies of these insts when necessary. case - kIROp_Specialize: case kIROp_LookupWitness: case kIROp_ExtractExistentialType: + kIROp_Specialize: case kIROp_LookupWitnessMethod: case kIROp_ExtractExistentialType: case kIROp_ExtractExistentialValue: case kIROp_ExtractExistentialWitnessTable: */ @@ -1248,7 +1248,7 @@ struct DiffTransposePass baseFnType); IRInst* revCallee = nullptr; - if (getResolvedInstForDecorations(baseFn)->getOp() == kIROp_LookupWitness) + if (getResolvedInstForDecorations(baseFn)->getOp() == kIROp_LookupWitnessMethod) { // This is an interface method call, we can simply transcribe it here. auto specialize = as(baseFn); @@ -1363,15 +1363,15 @@ struct DiffTransposePass auto terminatorInst = block->getTerminator(); switch (terminatorInst->getOp()) { - case kIROp_unconditionalBranch: + case kIROp_UnconditionalBranch: case kIROp_Return: return nullptr; - case kIROp_ifElse: + case kIROp_IfElse: return as(terminatorInst)->getAfterBlock(); case kIROp_Switch: return as(terminatorInst)->getBreakLabel(); - case kIROp_loop: + case kIROp_Loop: return as(terminatorInst)->getBreakBlock(); default: @@ -1467,7 +1467,7 @@ struct DiffTransposePass case kIROp_Call: return transposeCall(builder, as(fwdInst), revValue); - case kIROp_swizzle: + case kIROp_Swizzle: return transposeSwizzle(builder, as(fwdInst), revValue); case kIROp_FieldExtract: @@ -1558,12 +1558,12 @@ struct DiffTransposePass case kIROp_ReverseGradientDiffPairRef: case kIROp_DefaultConstruct: case kIROp_Specialize: - case kIROp_unconditionalBranch: - case kIROp_conditionalBranch: - case kIROp_ifElse: - case kIROp_loop: + case kIROp_UnconditionalBranch: + case kIROp_ConditionalBranch: + case kIROp_IfElse: + case kIROp_Loop: case kIROp_Switch: - case kIROp_LookupWitness: + case kIROp_LookupWitnessMethod: case kIROp_ExtractExistentialType: case kIROp_ExtractExistentialWitnessTable: { @@ -2163,7 +2163,7 @@ struct DiffTransposePass switch (type->getOp()) { case kIROp_ExtractExistentialType: - case kIROp_LookupWitness: + case kIROp_LookupWitnessMethod: return true; default: return false; diff --git a/source/slang/slang-ir-autodiff-unzip.h b/source/slang/slang-ir-autodiff-unzip.h index 80b2038aa6d..5685906b624 100644 --- a/source/slang/slang-ir-autodiff-unzip.h +++ b/source/slang/slang-ir-autodiff-unzip.h @@ -588,7 +588,7 @@ struct DiffUnzipPass { switch (branchInst->getOp()) { - case kIROp_unconditionalBranch: + case kIROp_UnconditionalBranch: { auto uncondBranchInst = as(branchInst); auto targetBlock = uncondBranchInst->getTargetBlock(); @@ -615,7 +615,7 @@ struct DiffUnzipPass diffArgs.getBuffer())); } - case kIROp_conditionalBranch: + case kIROp_ConditionalBranch: { auto trueBlock = as(branchInst)->getTrueBlock(); auto falseBlock = as(branchInst)->getFalseBlock(); @@ -632,7 +632,7 @@ struct DiffUnzipPass as(diffMap[falseBlock]))); } - case kIROp_ifElse: + case kIROp_IfElse: { auto trueBlock = as(branchInst)->getTrueBlock(); auto falseBlock = as(branchInst)->getFalseBlock(); @@ -686,7 +686,7 @@ struct DiffUnzipPass diffCaseArgs.getBuffer())); } - case kIROp_loop: + case kIROp_Loop: return splitLoop(primalBuilder, diffBuilder, as(branchInst)); default: @@ -716,11 +716,11 @@ struct DiffUnzipPass case kIROp_Return: return splitReturn(primalBuilder, diffBuilder, as(inst)); - case kIROp_unconditionalBranch: - case kIROp_conditionalBranch: - case kIROp_ifElse: + case kIROp_UnconditionalBranch: + case kIROp_ConditionalBranch: + case kIROp_IfElse: case kIROp_Switch: - case kIROp_loop: + case kIROp_Loop: return splitControlFlow(primalBuilder, diffBuilder, inst); case kIROp_Unreachable: diff --git a/source/slang/slang-ir-autodiff.cpp b/source/slang/slang-ir-autodiff.cpp index 133c257a8ca..5a8dc907458 100644 --- a/source/slang/slang-ir-autodiff.cpp +++ b/source/slang/slang-ir-autodiff.cpp @@ -824,7 +824,7 @@ IRInst* DifferentialPairTypeBuilder::_createDiffPairType(IRType* origBaseType, I { switch (origBaseType->getOp()) { - case kIROp_LookupWitness: + case kIROp_LookupWitnessMethod: case kIROp_Specialize: case kIROp_Param: return nullptr; @@ -2961,7 +2961,7 @@ struct AutoDiffPass : public InstPassBase // For generics/struct types, we will generate a new generic/struct type // representing the differntial. - SLANG_RELEASE_ASSERT(t->getParent() && t->getParent()->getOp() == kIROp_Module); + SLANG_RELEASE_ASSERT(t->getParent() && t->getParent()->getOp() == kIROp_ModuleInst); builder.setInsertBefore(t); auto diffInfo = fillDifferentialTypeImplementation(&ctx, diffTypes, t); diffTypes[t] = diffInfo; @@ -3373,7 +3373,7 @@ struct AutoDiffPass : public InstPassBase { case kIROp_Func: case kIROp_Specialize: - case kIROp_LookupWitness: + case kIROp_LookupWitnessMethod: case kIROp_Generic: if (auto innerFunc = as(getResolvedInstForDecorations(inst->getOperand(0)))) @@ -3829,14 +3829,14 @@ UIndex addPhiOutputArg( builder->setInsertInto(block); switch (branchInst->getOp()) { - case kIROp_unconditionalBranch: + case kIROp_UnconditionalBranch: inoutTerminatorInst = builder->emitBranch( branchInst->getTargetBlock(), phiArgs.getCount(), phiArgs.getBuffer()); break; - case kIROp_loop: + case kIROp_Loop: { auto newLoop = builder->emitLoop( as(branchInst)->getTargetBlock(), diff --git a/source/slang/slang-ir-check-differentiability.cpp b/source/slang/slang-ir-check-differentiability.cpp index 7f3c7bf012b..e9cb7e1f1f5 100644 --- a/source/slang/slang-ir-check-differentiability.cpp +++ b/source/slang/slang-ir-check-differentiability.cpp @@ -251,7 +251,7 @@ struct CheckDifferentiabilityPassContext : public InstPassBase bool isSynthesizeConstructor = false; - if (auto constructor = funcInst->findDecoration()) + if (auto constructor = funcInst->findDecoration()) isSynthesizeConstructor = constructor->getSynthesizedStatus(); // This is a kernel function, we don't allow using TorchTensor type here. diff --git a/source/slang/slang-ir-constexpr.cpp b/source/slang/slang-ir-constexpr.cpp index 620c65d4ef0..0bdbe260aa9 100644 --- a/source/slang/slang-ir-constexpr.cpp +++ b/source/slang/slang-ir-constexpr.cpp @@ -129,7 +129,7 @@ bool opCanBeConstExpr(IROp op) case kIROp_MakeUInt64: case kIROp_MakeArray: case kIROp_MakeArrayFromElement: - case kIROp_swizzle: + case kIROp_Swizzle: case kIROp_GetElement: case kIROp_FieldExtract: case kIROp_UpdateElement: @@ -142,7 +142,7 @@ bool opCanBeConstExpr(IROp op) case kIROp_GetOptionalValue: case kIROp_DifferentialPairGetDifferential: case kIROp_DifferentialPairGetPrimal: - case kIROp_LookupWitness: + case kIROp_LookupWitnessMethod: case kIROp_Specialize: // TODO: more cases return true; diff --git a/source/slang/slang-ir-eliminate-multilevel-break.cpp b/source/slang/slang-ir-eliminate-multilevel-break.cpp index 741b7fbd07d..cbbd1c5c886 100644 --- a/source/slang/slang-ir-eliminate-multilevel-break.cpp +++ b/source/slang/slang-ir-eliminate-multilevel-break.cpp @@ -32,7 +32,7 @@ struct EliminateMultiLevelBreakContext { switch (headerInst->getOp()) { - case kIROp_loop: + case kIROp_Loop: return as(headerInst)->getBreakBlock(); case kIROp_Switch: return as(headerInst)->getBreakLabel(); @@ -45,7 +45,7 @@ struct EliminateMultiLevelBreakContext { switch (headerInst->getOp()) { - case kIROp_loop: + case kIROp_Loop: builder->replaceOperand(&(as(headerInst)->breakBlock), block); break; case kIROp_Switch: @@ -103,7 +103,7 @@ struct EliminateMultiLevelBreakContext continue; switch (block->getTerminator()->getOp()) { - case kIROp_loop: + case kIROp_Loop: case kIROp_Switch: { // Both region and switch insts mark the start a breakable region. @@ -146,7 +146,7 @@ struct EliminateMultiLevelBreakContext auto terminator = block->getTerminator(); switch (terminator->getOp()) { - case kIROp_loop: + case kIROp_Loop: case kIROp_Switch: { RefPtr regionInfo = new BreakableRegionInfo(); @@ -434,8 +434,8 @@ struct EliminateMultiLevelBreakContext auto user = use->getUser(); switch (user->getOp()) { - case kIROp_conditionalBranch: - case kIROp_ifElse: + case kIROp_ConditionalBranch: + case kIROp_IfElse: case kIROp_Switch: // For complex branches, insert an intermediate block so we can specify the // target index argument. @@ -457,10 +457,10 @@ struct EliminateMultiLevelBreakContext use->set(tmpBlock); } break; - case kIROp_loop: + case kIROp_Loop: // Ignore. continue; - case kIROp_unconditionalBranch: + case kIROp_UnconditionalBranch: { auto originalBranch = as(user); if (originalBranch->getOperandCount() == 1) diff --git a/source/slang/slang-ir-eliminate-phis.cpp b/source/slang/slang-ir-eliminate-phis.cpp index a16446319d0..d5f1b9e43a4 100644 --- a/source/slang/slang-ir-eliminate-phis.cpp +++ b/source/slang/slang-ir-eliminate-phis.cpp @@ -1038,7 +1038,7 @@ struct PhiEliminationContext // so that any logic that might have moved another parameter // into a temporary will influence our result. // - if ((*srcArg.currentValPtr)->getOp() != kIROp_undefined) + if ((*srcArg.currentValPtr)->getOp() != kIROp_Undefined) { // If we are trying to emit a store directly after a load from the same var, // skip the store. diff --git a/source/slang/slang-ir-float-non-uniform-resource-index.cpp b/source/slang/slang-ir-float-non-uniform-resource-index.cpp index e37b0445b53..dbcb093c2ba 100644 --- a/source/slang/slang-ir-float-non-uniform-resource-index.cpp +++ b/source/slang/slang-ir-float-non-uniform-resource-index.cpp @@ -91,7 +91,7 @@ void processNonUniformResourceIndex( user->getOperand(1)); } break; - case kIROp_swizzle: + case kIROp_Swizzle: // Ignore when `NonUniformResourceIndex` is not on base if (user->getOperand(0) == inst) { @@ -103,7 +103,7 @@ void processNonUniformResourceIndex( operands[0] = inst->getOperand(0); newUser = builder.emitIntrinsicInst( user->getFullType(), - kIROp_swizzle, + kIROp_Swizzle, operands.getCount(), operands.getArrayView().getBuffer()); } @@ -141,7 +141,7 @@ void processNonUniformResourceIndex( case kIROp_NonUniformResourceIndex: case kIROp_CastDescriptorHandleToUInt2: case kIROp_GetElement: - case kIROp_swizzle: + case kIROp_Swizzle: resWorkList.add(nonuniformUser); break; }; diff --git a/source/slang/slang-ir-generics-lowering-context.cpp b/source/slang/slang-ir-generics-lowering-context.cpp index 199eae2fc41..0dee5631a93 100644 --- a/source/slang/slang-ir-generics-lowering-context.cpp +++ b/source/slang/slang-ir-generics-lowering-context.cpp @@ -16,7 +16,7 @@ bool isPolymorphicType(IRInst* typeInst) case kIROp_ThisType: case kIROp_AssociatedType: case kIROp_InterfaceType: - case kIROp_LookupWitness: + case kIROp_LookupWitnessMethod: return true; case kIROp_Specialize: { @@ -299,7 +299,7 @@ IRType* SharedGenericsLoweringContext::lowerType( return tupleType; } - case kIROp_LookupWitness: + case kIROp_LookupWitnessMethod: { auto lookupInterface = static_cast(paramType); auto witnessTableType = diff --git a/source/slang/slang-ir-inline.cpp b/source/slang/slang-ir-inline.cpp index 8575330f824..9e522081f54 100644 --- a/source/slang/slang-ir-inline.cpp +++ b/source/slang/slang-ir-inline.cpp @@ -1269,7 +1269,7 @@ struct IntrinsicFunctionInliningPass : InliningPassBase hasSpvAsm = true; continue; case kIROp_Load: - case kIROp_swizzle: + case kIROp_Swizzle: case kIROp_Store: continue; default: diff --git a/source/slang/slang-ir-inst-defs.h b/source/slang/slang-ir-inst-defs.h deleted file mode 100644 index d3db24d20c9..00000000000 --- a/source/slang/slang-ir-inst-defs.h +++ /dev/null @@ -1,1439 +0,0 @@ -// slang-ir-inst-defs.h - -// clang-format off - -#ifndef INST -#error Must #define `INST` before including `ir-inst-defs.h` -#endif - -#ifndef INST_RANGE -#define INST_RANGE(BASE, FIRST, LAST) /* empty */ -#endif - -#define PARENT kIROpFlag_Parent -#define USE_OTHER kIROpFlag_UseOther -#define HOISTABLE kIROpFlag_Hoistable -#define GLOBAL kIROpFlag_Global - -INST(Nop, nop, 0, 0) - -/* Types */ - - /* Basic Types */ - - #define DEFINE_BASE_TYPE_INST(NAME) INST(NAME ## Type, NAME, 0, HOISTABLE) - FOREACH_BASE_TYPE(DEFINE_BASE_TYPE_INST) - #undef DEFINE_BASE_TYPE_INST - INST(AfterBaseType, afterBaseType, 0, 0) - - INST_RANGE(BasicType, VoidType, AfterBaseType) - - /* StringTypeBase */ - INST(StringType, String, 0, HOISTABLE) - INST(NativeStringType, NativeString, 0, HOISTABLE) - INST_RANGE(StringTypeBase, StringType, NativeStringType) - - INST(CapabilitySetType, CapabilitySet, 0, HOISTABLE) - - INST(DynamicType, DynamicType, 0, HOISTABLE) - - INST(AnyValueType, AnyValueType, 1, HOISTABLE) - - INST(RawPointerType, RawPointerType, 0, HOISTABLE) - INST(RTTIPointerType, RTTIPointerType, 1, HOISTABLE) - INST(AfterRawPointerTypeBase, AfterRawPointerTypeBase, 0, 0) - INST_RANGE(RawPointerTypeBase, RawPointerType, AfterRawPointerTypeBase) - - - /* ArrayTypeBase */ - INST(ArrayType, Array, 2, HOISTABLE) - INST(UnsizedArrayType, UnsizedArray, 1, HOISTABLE) - INST_RANGE(ArrayTypeBase, ArrayType, UnsizedArrayType) - - INST(FuncType, Func, 0, HOISTABLE) - INST(BasicBlockType, BasicBlock, 0, HOISTABLE) - - INST(VectorType, Vec, 2, HOISTABLE) - INST(MatrixType, Mat, 4, HOISTABLE) - - INST(ConjunctionType, Conjunction, 0, HOISTABLE) - INST(AttributedType, Attributed, 0, HOISTABLE) - INST(ResultType, Result, 2, HOISTABLE) - INST(OptionalType, Optional, 1, HOISTABLE) - INST(EnumType, Enum, 1, PARENT) - - INST(DifferentialPairType, DiffPair, 1, HOISTABLE) - INST(DifferentialPairUserCodeType, DiffPairUserCode, 1, HOISTABLE) - INST(DifferentialPtrPairType, DiffRefPair, 1, HOISTABLE) - INST_RANGE(DifferentialPairTypeBase, DifferentialPairType, DifferentialPtrPairType) - - INST(BackwardDiffIntermediateContextType, BwdDiffIntermediateCtxType, 1, HOISTABLE) - - INST(TensorViewType, TensorView, 1, HOISTABLE) - INST(TorchTensorType, TorchTensor, 0, HOISTABLE) - INST(ArrayListType, ArrayListVector, 1, HOISTABLE) - - INST(AtomicType, Atomic, 1, HOISTABLE) - - /* BindExistentialsTypeBase */ - - // 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`. - // - INST(BindExistentialsType, BindExistentials, 1, HOISTABLE) - - // An `BindInterface` represents the special case - // of a `BindExistentials` where the type `B` is known to be - // an interface type. - // - INST(BoundInterfaceType, BoundInterface, 3, HOISTABLE) - - INST_RANGE(BindExistentialsTypeBase, BindExistentialsType, BoundInterfaceType) - - /* Rate */ - INST(ConstExprRate, ConstExpr, 0, HOISTABLE) - INST(SpecConstRate, SpecConst, 0, HOISTABLE) - INST(GroupSharedRate, GroupShared, 0, HOISTABLE) - INST(ActualGlobalRate, ActualGlobalRate, 0, HOISTABLE) - INST_RANGE(Rate, ConstExprRate, GroupSharedRate) - - INST(RateQualifiedType, RateQualified, 2, HOISTABLE) - - // Kinds represent the "types of types." - // They should not really be nested under `IRType` - // in the overall hierarchy, but we can fix that later. - // - /* Kind */ - INST(TypeKind, Type, 0, HOISTABLE) - INST(TypeParameterPackKind, TypeParameterPack, 0, HOISTABLE) - INST(RateKind, Rate, 0, HOISTABLE) - INST(GenericKind, Generic, 0, HOISTABLE) - INST_RANGE(Kind, TypeKind, GenericKind) - - /* PtrTypeBase */ - INST(PtrType, Ptr, 1, HOISTABLE) - INST(RefType, Ref, 1, HOISTABLE) - INST(ConstRefType, ConstRef, 1, HOISTABLE) - // 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. - - INST(PseudoPtrType, PseudoPtr, 1, HOISTABLE) - - /* OutTypeBase */ - INST(OutType, Out, 1, HOISTABLE) - INST(InOutType, InOut, 1, HOISTABLE) - INST_RANGE(OutTypeBase, OutType, InOutType) - INST_RANGE(PtrTypeBase, PtrType, InOutType) - - - // A ComPtr type is treated as a opaque type that represents a reference-counted handle to a COM object. - INST(ComPtrType, ComPtr, 1, HOISTABLE) - // A NativePtr type represents a native pointer to a managed resource. - INST(NativePtrType, NativePtr, 1, HOISTABLE) - - // A DescriptorHandle type represents a bindless handle to an opaue resource type. - INST(DescriptorHandleType, DescriptorHandle, 1, HOISTABLE) - - // An AtomicUint is a placeholder type for a storage buffer, and will be mangled during compiling. - INST(GLSLAtomicUintType, GLSLAtomicUint, 0, HOISTABLE) - - /* SamplerStateTypeBase */ - INST(SamplerStateType, SamplerState, 0, HOISTABLE) - INST(SamplerComparisonStateType, SamplerComparisonState, 0, HOISTABLE) - INST_RANGE(SamplerStateTypeBase, SamplerStateType, SamplerComparisonStateType) - - INST(DefaultBufferLayoutType, DefaultLayout, 0, HOISTABLE) - INST(Std140BufferLayoutType, Std140Layout, 0, HOISTABLE) - INST(Std430BufferLayoutType, Std430Layout, 0, HOISTABLE) - INST(ScalarBufferLayoutType, ScalarLayout, 0, HOISTABLE) - - INST(SubpassInputType, SubpassInputType, 2, HOISTABLE) - - INST(TextureFootprintType, TextureFootprintType, 1, HOISTABLE) - - INST(TextureShape1DType, TextureShape1DType, 0, HOISTABLE) - INST(TextureShape2DType, TextureShape1DType, 0, HOISTABLE) - INST(TextureShape3DType, TextureShape1DType, 0, HOISTABLE) - INST(TextureShapeCubeType, TextureShape1DType, 0, HOISTABLE) - INST(TextureShapeBufferType, TextureShapeBufferType, 0, HOISTABLE) - - // TODO: Why do we have all this hierarchy here, when everything - // that actually matters is currently nested under `TextureTypeBase`? - /* ResourceTypeBase */ - /* ResourceType */ - /* TextureTypeBase */ - /* TextureType */ - INST(TextureType, TextureType, 8, HOISTABLE) - /* GLSLImageType */ - INST(GLSLImageType, GLSLImageType, 0, USE_OTHER | HOISTABLE) - INST_RANGE(TextureTypeBase, TextureType, GLSLImageType) - INST_RANGE(ResourceType, TextureType, GLSLImageType) - INST_RANGE(ResourceTypeBase, TextureType, GLSLImageType) - - /* UntypedBufferResourceType */ - /* ByteAddressBufferTypeBase */ - INST(HLSLByteAddressBufferType, ByteAddressBuffer, 0, HOISTABLE) - INST(HLSLRWByteAddressBufferType, RWByteAddressBuffer, 0, HOISTABLE) - INST(HLSLRasterizerOrderedByteAddressBufferType, RasterizerOrderedByteAddressBuffer, 0, HOISTABLE) - INST_RANGE(ByteAddressBufferTypeBase, HLSLByteAddressBufferType, HLSLRasterizerOrderedByteAddressBufferType) - INST(RaytracingAccelerationStructureType, RaytracingAccelerationStructure, 0, HOISTABLE) - INST_RANGE(UntypedBufferResourceType, HLSLByteAddressBufferType, RaytracingAccelerationStructureType) - - /* HLSLPatchType */ - INST(HLSLInputPatchType, InputPatch, 2, HOISTABLE) - INST(HLSLOutputPatchType, OutputPatch, 2, HOISTABLE) - INST_RANGE(HLSLPatchType, HLSLInputPatchType, HLSLOutputPatchType) - - INST(GLSLInputAttachmentType, GLSLInputAttachment, 0, HOISTABLE) - - /* BuiltinGenericType */ - /* HLSLStreamOutputType */ - INST(HLSLPointStreamType, PointStream, 1, HOISTABLE) - INST(HLSLLineStreamType, LineStream, 1, HOISTABLE) - INST(HLSLTriangleStreamType, TriangleStream, 1, HOISTABLE) - INST_RANGE(HLSLStreamOutputType, HLSLPointStreamType, HLSLTriangleStreamType) - - /* MeshOutputType */ - INST(VerticesType, Vertices, 2, HOISTABLE) - INST(IndicesType, Indices, 2, HOISTABLE) - INST(PrimitivesType, Primitives, 2, HOISTABLE) - INST_RANGE(MeshOutputType, VerticesType, PrimitivesType) - - /* Metal Mesh Type */ - INST(MetalMeshType, metal::mesh, 5, HOISTABLE) - /* Metal Mesh Grid Properties */ - INST(MetalMeshGridPropertiesType, mesh_grid_properties, 0, HOISTABLE) - - /* HLSLStructuredBufferTypeBase */ - INST(HLSLStructuredBufferType, StructuredBuffer, 0, HOISTABLE) - INST(HLSLRWStructuredBufferType, RWStructuredBuffer, 0, HOISTABLE) - INST(HLSLRasterizerOrderedStructuredBufferType, RasterizerOrderedStructuredBuffer, 0, HOISTABLE) - INST(HLSLAppendStructuredBufferType, AppendStructuredBuffer, 0, HOISTABLE) - INST(HLSLConsumeStructuredBufferType, ConsumeStructuredBuffer, 0, HOISTABLE) - INST_RANGE(HLSLStructuredBufferTypeBase, HLSLStructuredBufferType, HLSLConsumeStructuredBufferType) - - /* PointerLikeType */ - /* ParameterGroupType */ - /* UniformParameterGroupType */ - INST(ConstantBufferType, ConstantBuffer, 1, HOISTABLE) - INST(TextureBufferType, TextureBuffer, 1, HOISTABLE) - INST(ParameterBlockType, ParameterBlock, 1, HOISTABLE) - INST_RANGE(UniformParameterGroupType, ConstantBufferType, ParameterBlockType) - - /* VaryingParameterGroupType */ - INST(GLSLInputParameterGroupType, GLSLInputParameterGroup, 0, HOISTABLE) - INST(GLSLOutputParameterGroupType, GLSLOutputParameterGroup, 0, HOISTABLE) - INST_RANGE(VaryingParameterGroupType, GLSLInputParameterGroupType, GLSLOutputParameterGroupType) - INST(GLSLShaderStorageBufferType, GLSLShaderStorageBuffer, 1, HOISTABLE) - INST_RANGE(ParameterGroupType, ConstantBufferType, GLSLShaderStorageBufferType) - INST_RANGE(PointerLikeType, ConstantBufferType, GLSLShaderStorageBufferType) - INST_RANGE(BuiltinGenericType, HLSLPointStreamType, GLSLShaderStorageBufferType) - -INST(RayQueryType, RayQuery, 1, HOISTABLE) -INST(HitObjectType, HitObject, 0, HOISTABLE) -INST(CoopVectorType, CoopVectorType, 2, HOISTABLE) -INST(CoopMatrixType, CoopMatrixType, 5, HOISTABLE) -INST(TensorAddressingTensorLayoutType, TensorAddressingTensorLayoutType, 2, HOISTABLE) -INST(TensorAddressingTensorViewType, TensorAddressingTensorViewType, 3, HOISTABLE) -INST(MakeTensorAddressingTensorLayout, MakeTensorAddressingTensorLayout, 0, 0) -INST(MakeTensorAddressingTensorView, MakeTensorAddressingTensorView, 0, 0) - -// Opaque type that can be dynamically cast to other resource types. -INST(DynamicResourceType, DynamicResource, 0, HOISTABLE) - -// 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. -// -INST(StructType, struct, 0, PARENT) -INST(ClassType, class, 0, PARENT) -INST(InterfaceType, interface, 0, GLOBAL) -INST(AssociatedType, associated_type, 0, HOISTABLE) -INST(ThisType, this_type, 0, HOISTABLE) -INST(RTTIType, rtti_type, 0, HOISTABLE) -INST(RTTIHandleType, rtti_handle_type, 0, HOISTABLE) -/*TupleTypeBase*/ - INST(TupleType, tuple_type, 0, HOISTABLE) - INST(TypePack, TypePack, 0, HOISTABLE) -INST_RANGE(TupleTypeBase, TupleType, TypePack) -INST(TargetTupleType, TargetTuple, 0, HOISTABLE) -INST(ExpandTypeOrVal, ExpandTypeOrVal, 1, HOISTABLE) - -// A type that identifies it's contained type as being emittable as `spirv_literal. -INST(SPIRVLiteralType, spirvLiteralType, 1, HOISTABLE) - -// A TypeType-typed IRValue represents a IRType. -// It is used to represent a type parameter/argument in a generics. -INST(TypeType, type_t, 0, HOISTABLE) - -/*IRWitnessTableTypeBase*/ - // An `IRWitnessTable` has type `WitnessTableType`. - INST(WitnessTableType, witness_table_t, 1, HOISTABLE) - // 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. - INST(WitnessTableIDType, witness_table_id_t, 1, HOISTABLE) -INST_RANGE(WitnessTableTypeBase, WitnessTableType, WitnessTableIDType) -INST_RANGE(Type, VoidType, WitnessTableIDType) - -/*IRGlobalValueWithCode*/ - /* IRGlobalValueWithParams*/ - INST(Func, func, 0, PARENT) - INST(Generic, generic, 0, PARENT) - INST_RANGE(GlobalValueWithParams, Func, Generic) - - INST(GlobalVar, global_var, 0, GLOBAL) -INST_RANGE(GlobalValueWithCode, Func, GlobalVar) - -INST(GlobalParam, global_param, 0, GLOBAL) -INST(GlobalConstant, globalConstant, 0, GLOBAL) - -INST(StructKey, key, 0, GLOBAL) -INST(GlobalGenericParam, global_generic_param, 0, GLOBAL) -INST(WitnessTable, witness_table, 0, HOISTABLE) - -INST(IndexedFieldKey, indexedFieldKey, 2, HOISTABLE) - -// A placeholder witness that ThisType implements the enclosing interface. -// Used only in interface definitions. -INST(ThisTypeWitness, thisTypeWitness, 1, 0) - -// A placeholder witness for the fact that two types are equal. -INST(TypeEqualityWitness, TypeEqualityWitness, 2, HOISTABLE) - -INST(GlobalHashedStringLiterals, global_hashed_string_literals, 0, 0) - -INST(Module, module, 0, PARENT) - -INST(Block, block, 0, PARENT) - -/* IRConstant */ - INST(BoolLit, boolConst, 0, 0) - INST(IntLit, integer_constant, 0, 0) - INST(FloatLit, float_constant, 0, 0) - INST(PtrLit, ptr_constant, 0, 0) - INST(StringLit, string_constant, 0, 0) - INST(BlobLit, string_constant, 0, 0) - INST(VoidLit, void_constant, 0, 0) -INST_RANGE(Constant, BoolLit, VoidLit) - -INST(CapabilityConjunction, capabilityConjunction, 0, HOISTABLE) -INST(CapabilityDisjunction, capabilityDisjunction, 0, HOISTABLE) -INST_RANGE(CapabilitySet, CapabilityConjunction, CapabilityDisjunction) - -INST(undefined, undefined, 0, 0) - -// 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. -// -INST(DefaultConstruct, defaultConstruct, 0, 0) - -INST(MakeDifferentialPair, MakeDiffPair, 2, 0) -INST(MakeDifferentialPairUserCode, MakeDiffPairUserCode, 2, 0) -INST(MakeDifferentialPtrPair, MakeDiffRefPair, 2, 0) -INST_RANGE(MakeDifferentialPairBase, MakeDifferentialPair, MakeDifferentialPtrPair) - -INST(DifferentialPairGetDifferential, GetDifferential, 1, 0) -INST(DifferentialPairGetDifferentialUserCode, GetDifferentialUserCode, 1, 0) -INST(DifferentialPtrPairGetDifferential, GetDifferentialPtr, 1, 0) -INST_RANGE(DifferentialPairGetDifferentialBase, DifferentialPairGetDifferential, DifferentialPtrPairGetDifferential) - -INST(DifferentialPairGetPrimal, GetPrimal, 1, 0) -INST(DifferentialPairGetPrimalUserCode, GetPrimalUserCode, 1, 0) -INST(DifferentialPtrPairGetPrimal, GetPrimalRef, 1, 0) -INST_RANGE(DifferentialPairGetPrimalBase, DifferentialPairGetPrimal, DifferentialPtrPairGetPrimal) - -INST(Specialize, specialize, 2, HOISTABLE) -INST(LookupWitness, lookupWitness, 2, HOISTABLE) -INST(GetSequentialID, GetSequentialID, 1, HOISTABLE) -INST(BindGlobalGenericParam, bind_global_generic_param, 2, 0) -INST(AllocObj, allocObj, 0, 0) - -INST(GlobalValueRef, globalValueRef, 1, 0) - -INST(MakeUInt64, makeUInt64, 2, 0) -INST(MakeVector, makeVector, 0, 0) -INST(MakeMatrix, makeMatrix, 0, 0) -INST(MakeMatrixFromScalar, makeMatrixFromScalar, 1, 0) -INST(MatrixReshape, matrixReshape, 1, 0) -INST(VectorReshape, vectorReshape, 1, 0) -INST(MakeArray, makeArray, 0, 0) -INST(MakeArrayFromElement, makeArrayFromElement, 1, 0) -INST(MakeCoopVector, makeCoopVector, 0, 0) -INST(MakeCoopVectorFromValuePack, makeCoopVectorFromValuePack, 1, 0) -INST(MakeStruct, makeStruct, 0, 0) -INST(MakeTuple, makeTuple, 0, 0) -INST(MakeTargetTuple, makeTuple, 0, 0) -INST(MakeValuePack, makeValuePack, 0, 0) -INST(GetTargetTupleElement, getTargetTupleElement, 0, 0) -INST(GetTupleElement, getTupleElement, 2, 0) -INST(LoadResourceDescriptorFromHeap, LoadResourceDescriptorFromHeap, 1, 0) -INST(LoadSamplerDescriptorFromHeap, LoadSamplerDescriptorFromHeap, 1, 0) -INST(MakeCombinedTextureSamplerFromHandle, MakeCombinedTextureSamplerFromHandle, 1, 0) -INST(MakeWitnessPack, MakeWitnessPack, 0, HOISTABLE) -INST(Expand, Expand, 1, 0) -INST(Each, Each, 1, HOISTABLE) -INST(MakeResultValue, makeResultValue, 1, 0) -INST(MakeResultError, makeResultError, 1, 0) -INST(IsResultError, isResultError, 1, 0) -INST(GetResultError, getResultError, 1, 0) -INST(GetResultValue, getResultValue, 1, 0) -INST(GetOptionalValue, getOptionalValue, 1, 0) -INST(OptionalHasValue, optionalHasValue, 1, 0) -INST(MakeOptionalValue, makeOptionalValue, 1, 0) -INST(MakeOptionalNone, makeOptionalNone, 1, 0) -INST(CombinedTextureSamplerGetTexture, CombinedTextureSamplerGetTexture, 1, 0) -INST(CombinedTextureSamplerGetSampler, CombinedTextureSamplerGetSampler, 1, 0) -INST(Call, call, 1, 0) - -INST(RTTIObject, rtti_object, 0, 0) -INST(Alloca, alloca, 1, 0) - -INST(UpdateElement, updateElement, 2, 0) -INST(DetachDerivative, detachDerivative, 1, 0) - -INST(BitfieldExtract, bitfieldExtract, 3, 0) -INST(BitfieldInsert, bitfieldInsert, 4, 0) - -INST(PackAnyValue, packAnyValue, 1, 0) -INST(UnpackAnyValue, unpackAnyValue, 1, 0) - -INST(WitnessTableEntry, witness_table_entry, 2, 0) -INST(InterfaceRequirementEntry, interface_req_entry, 2, GLOBAL) - -// An inst to represent the workgroup size of the calling entry point. -// We will materialize this inst during `translateGlobalVaryingVar`. -INST(GetWorkGroupSize, GetWorkGroupSize, 0, HOISTABLE) - -// An inst that returns the current stage of the calling entry point. -INST(GetCurrentStage, GetCurrentStage, 0, 0) - -INST(Param, param, 0, 0) -INST(StructField, field, 2, 0) -INST(Var, var, 0, 0) - -INST(Load, load, 1, 0) -INST(Store, store, 2, 0) - -// Atomic Operations - INST(AtomicLoad, atomicLoad, 1, 0) - INST(AtomicStore, atomicStore, 2, 0) - INST(AtomicExchange, atomicExchange, 2, 0) - INST(AtomicCompareExchange, atomicCompareExchange, 3, 0) - INST(AtomicAdd, atomicAdd, 2, 0) - INST(AtomicSub, atomicSub, 2, 0) - INST(AtomicAnd, atomicAnd, 2, 0) - INST(AtomicOr, atomicOr, 2, 0) - INST(AtomicXor, atomicXor, 2, 0) - INST(AtomicMin, atomicMin, 2, 0) - INST(AtomicMax, atomicMax, 2, 0) - INST(AtomicInc, atomicInc, 1, 0) - INST(AtomicDec, atomicDec, 1, 0) -INST_RANGE(AtomicOperation, AtomicLoad, AtomicDec) - -// 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. -INST(LoadReverseGradient, LoadReverseGradient, 1, 0) - -// 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. -INST(ReverseGradientDiffPairRef, ReverseGradientDiffPairRef, 2, 0) - -// 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. -INST(PrimalParamRef, PrimalParamRef, 1, 0) - -// 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. -INST(DiffParamRef, DiffParamRef, 1, 0) - -// Check that the value is a differential null value. -INST(IsDifferentialNull, IsDifferentialNull, 1, 0) - -INST(FieldExtract, get_field, 2, 0) -INST(FieldAddress, get_field_addr, 2, 0) - -INST(GetElement, getElement, 2, 0) -INST(GetElementPtr, getElementPtr, 2, 0) -// Pointer offset: computes pBase + offset_in_elements -INST(GetOffsetPtr, getOffsetPtr, 2, 0) -INST(GetAddr, getAddr, 1, 0) - -INST(CastDynamicResource, castDynamicResource, 1, 0) - -// Get an unowned NativeString from a String. -INST(getNativeStr, getNativeStr, 1, 0) - -// Make String from a NativeString. -INST(MakeString, makeString, 1, 0) - -// Get a native ptr from a ComPtr or RefPtr -INST(GetNativePtr, getNativePtr, 1, 0) - -// Get a write reference to a managed ptr var (operand must be Ptr> or Ptr>). -INST(GetManagedPtrWriteRef, getManagedPtrWriteRef, 1, 0) - -// Attach a managedPtr var to a NativePtr without changing its ref count. -INST(ManagedPtrAttach, ManagedPtrAttach, 1, 0) - -// Attach a managedPtr var to a NativePtr without changing its ref count. -INST(ManagedPtrDetach, ManagedPtrDetach, 1, 0) - -// "Subscript" an image at a pixel coordinate to get pointer -INST(ImageSubscript, imageSubscript, 2, 0) - -// Load from an Image. -INST(ImageLoad, imageLoad, 2, 0) -// Store into an Image. -INST(ImageStore, imageStore, 3, 0) - -// 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 -// -INST(ByteAddressBufferLoad, byteAddressBufferLoad, 3, 0) - -// 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 -// -INST(ByteAddressBufferStore, byteAddressBufferStore, 4, 0) - -// 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 -// -INST(StructuredBufferLoad, structuredBufferLoad, 2, 0) -INST(StructuredBufferLoadStatus, structuredBufferLoadStatus, 3, 0) -INST(RWStructuredBufferLoad, rwstructuredBufferLoad, 2, 0) -INST(RWStructuredBufferLoadStatus, rwstructuredBufferLoadStatus, 3, 0) - -// 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 -// -INST(RWStructuredBufferStore, rwstructuredBufferStore, 3, 0) - -INST(RWStructuredBufferGetElementPtr, rwstructuredBufferGetElementPtr, 2, 0) - -// Append/Consume-StructuredBuffer operations -INST(StructuredBufferAppend, StructuredBufferAppend, 1, 0) -INST(StructuredBufferConsume, StructuredBufferConsume, 1, 0) -INST(StructuredBufferGetDimensions, StructuredBufferGetDimensions, 1, 0) - -// Resource qualifiers for dynamically varying index -INST(NonUniformResourceIndex, nonUniformResourceIndex, 1, 0) - -INST(GetNaturalStride, getNaturalStride, 1, 0) - -INST(MeshOutputRef, meshOutputRef, 2, 0) -INST(MeshOutputSet, meshOutputSet, 3, 0) - -// only two parameters as they are effectively static -// TODO: make them reference the _slang_mesh object directly -INST(MetalSetVertex, metalSetVertex, 2, 0) -INST(MetalSetPrimitive, metalSetPrimitive, 2, 0) -INST(MetalSetIndices, metalSetIndices, 2, 0) - -INST(MetalCastToDepthTexture, MetalCastToDepthTexture, 1, 0) - -// 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` -// -INST(MakeVectorFromScalar, MakeVectorFromScalar, 3, 0) - -// 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 -// -INST(swizzle, swizzle, 1, 0) - -// 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]]; -// -INST(swizzleSet, swizzleSet, 2, 0) - -// 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]]; -// -INST(SwizzledStore, swizzledStore, 2, 0) - - -/* IRTerminatorInst */ - - INST(Return, return_val, 1, 0) - INST(Yield, yield, 1, 0) - /* IRUnconditionalBranch */ - // unconditionalBranch - INST(unconditionalBranch, unconditionalBranch, 1, 0) - - // loop - INST(loop, loop, 3, 0) - INST_RANGE(UnconditionalBranch, unconditionalBranch, loop) - - /* IRConditionalbranch */ - - // conditionalBranch -INST(conditionalBranch, conditionalBranch, 3, 0) - -// ifElse -INST(ifElse, ifElse, 4, 0) -INST_RANGE(ConditionalBranch, conditionalBranch, ifElse) - -INST(Throw, throw, 1, 0) -// tryCall ... -INST(TryCall, tryCall, 3, 0) -// switch ... -INST(Switch, switch, 3, 0) -// target_switch ... -INST(TargetSwitch, targetSwitch, 1, 0) - -// A generic asm inst has an return semantics that terminates the control flow. -INST(GenericAsm, GenericAsm, 1, 0) - -/* IRUnreachable */ -INST(MissingReturn, missingReturn, 0, 0) -INST(Unreachable, unreachable, 0, 0) -INST_RANGE(Unreachable, MissingReturn, Unreachable) - -INST(Defer, defer, 3, 0) - -INST_RANGE(TerminatorInst, Return, Defer) - -INST(discard, discard, 0, 0) - -INST(RequirePrelude, RequirePrelude, 1, 0) -INST(RequireTargetExtension, RequireTargetExtension, 1, 0) -INST(RequireComputeDerivative, RequireComputeDerivative, 0, 0) -INST(StaticAssert, StaticAssert, 2, 0) -INST(Printf, Printf, 1, 0) - -// Quad control execution modes. -INST(RequireMaximallyReconverges, RequireMaximallyReconverges, 0, 0) -INST(RequireQuadDerivatives, RequireQuadDerivatives, 0, 0) - -// 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 (e.g., SPIR-V). - -INST(Add, add, 2, 0) -INST(Sub, sub, 2, 0) -INST(Mul, mul, 2, 0) -INST(Div, div, 2, 0) - -// 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. -// -INST(IRem, irem, 2, 0) // integer (signed or unsigned) -INST(FRem, frem, 2, 0) // floating-point - -INST(Lsh, shl, 2, 0) -INST(Rsh, shr, 2, 0) - -INST(Eql, cmpEQ, 2, 0) -INST(Neq, cmpNE, 2, 0) -INST(Greater, cmpGT, 2, 0) -INST(Less, cmpLT, 2, 0) -INST(Geq, cmpGE, 2, 0) -INST(Leq, cmpLE, 2, 0) - -INST(BitAnd, and, 2, 0) -INST(BitXor, xor, 2, 0) -INST(BitOr, or , 2, 0) - -INST(And, logicalAnd, 2, 0) -INST(Or, logicalOr, 2, 0) - -INST(Neg, neg, 1, 0) -INST(Not, not, 1, 0) -INST(BitNot, bitnot, 1, 0) - -INST(Select, select, 3, 0) - -INST(CheckpointObject, checkpointObj, 1, 0) -INST(LoopExitValue, loopExitValue, 1, 0) - -INST(GetStringHash, getStringHash, 1, 0) - -INST(WaveGetActiveMask, waveGetActiveMask, 0, 0) - -/// trueMask = waveMaskBallot(mask, condition) -INST(WaveMaskBallot, waveMaskBallot, 2, 0) - -/// matchMask = waveMaskBallot(mask, value) -INST(WaveMaskMatch, waveMaskMatch, 2, 0) - -// Texture sampling operation of the form `t.Sample(s,u)` -INST(Sample, sample, 3, 0) - -INST(SampleGrad, sampleGrad, 4, 0) - -INST(GroupMemoryBarrierWithGroupSync, GroupMemoryBarrierWithGroupSync, 0, 0) - -INST(ControlBarrier, ControlBarrier, 0, 0) - -// GPU_FOREACH loop of the form -INST(GpuForeach, gpuForeach, 3, 0) - -// Wrapper for OptiX intrinsics used to load and store ray payload data using -// a pointer represented by two payload registers. -INST(GetOptiXRayPayloadPtr, getOptiXRayPayloadPtr, 0, HOISTABLE) - -// 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 -INST(GetOptiXHitAttribute, getOptiXHitAttribute, 2, 0) - -// Wrapper for OptiX intrinsics used to load shader binding table record data -// using a pointer. -INST(GetOptiXSbtDataPtr, getOptiXSbtDataPointer, 0, 0) - -INST(GetVulkanRayTracingPayloadLocation, GetVulkanRayTracingPayloadLocation, 1, 0) - -INST(GetLegalizedSPIRVGlobalParamAddr, GetLegalizedSPIRVGlobalParamAddr, 1, 0) - -INST(GetPerVertexInputArray, GetPerVertexInputArray, 1, HOISTABLE) -INST(ResolveVaryingInputRef, ResolveVaryingInputRef, 1, HOISTABLE) - -INST(ForceVarIntoStructTemporarily, ForceVarIntoStructTemporarily, 1, 0) -INST(ForceVarIntoRayPayloadStructTemporarily, ForceVarIntoRayPayloadStructTemporarily, 1, 0) -INST_RANGE(ForceVarIntoStructTemporarily, ForceVarIntoStructTemporarily, ForceVarIntoRayPayloadStructTemporarily) - -INST(MetalAtomicCast, MetalAtomicCast, 1, 0) - -INST(IsTextureAccess, IsTextureAccess, 1, 0) -INST(IsTextureScalarAccess, IsTextureScalarAccess, 1, 0) -INST(IsTextureArrayAccess, IsTextureArrayAccess, 1, 0) -INST(ExtractTextureFromTextureAccess, ExtractTextureFromTextureAccess, 1, 0) -INST(ExtractCoordFromTextureAccess, ExtractCoordFromTextureAccess, 1, 0) -INST(ExtractArrayCoordFromTextureAccess, ExtractArrayCoordFromTextureAccess, 1, 0) - -INST(MakeArrayList, makeArrayList, 0, 0) -INST(MakeTensorView, makeTensorView, 0, 0) -INST(AllocateTorchTensor, allocTorchTensor, 0, 0) -INST(TorchGetCudaStream, TorchGetCudaStream, 0, 0) -INST(TorchTensorGetView, TorchTensorGetView, 0, 0) - -INST(CoopMatMapElementIFunc, CoopMatMapElementIFunc, 2, 0) - -INST(AllocateOpaqueHandle, allocateOpaqueHandle, 0, 0) - - // Return the register index thtat a resource is bound to. - INST(GetRegisterIndex, getRegisterIndex, 1, 0) - - // Return the registe space that a resource is bound to. - INST(GetRegisterSpace, getRegisterSpace, 1, 0) - -INST_RANGE(BindingQuery, GetRegisterIndex, GetRegisterSpace) - -/* Decoration */ - - INST(HighLevelDeclDecoration, highLevelDecl, 1, 0) - INST(LayoutDecoration, layout, 1, 0) - INST(BranchDecoration, branch, 0, 0) - INST(FlattenDecoration, flatten, 0, 0) - INST(LoopControlDecoration, loopControl, 1, 0) - INST(LoopMaxItersDecoration, loopMaxIters, 1, 0) - INST(LoopExitPrimalValueDecoration, loopExitPrimalValue, 2, 0) - INST(IntrinsicOpDecoration, intrinsicOp, 1, 0) - /* TargetSpecificDecoration */ - INST(TargetDecoration, target, 1, 0) - INST(TargetIntrinsicDecoration, targetIntrinsic, 2, 0) - INST_RANGE(TargetSpecificDefinitionDecoration, TargetDecoration, TargetIntrinsicDecoration) - INST(RequirePreludeDecoration, requirePrelude, 2, 0) - INST_RANGE(TargetSpecificDecoration, TargetDecoration, RequirePreludeDecoration) - INST(GLSLOuterArrayDecoration, glslOuterArray, 1, 0) - - INST(TargetSystemValueDecoration, TargetSystemValue, 2, 0) - - INST(InterpolationModeDecoration, interpolationMode, 1, 0) - INST(NameHintDecoration, nameHint, 1, 0) - - INST(PhysicalTypeDecoration, PhysicalType, 1, 0) - - // Mark an address instruction as aligned to a specific byte boundary. - INST(AlignedAddressDecoration, AlignedAddressDecoration, 1, 0) - - // 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. - INST(BinaryInterfaceTypeDecoration, BinaryInterfaceType, 0, 0) - - /** 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. */ - INST(TransitoryDecoration, transitory, 0, 0) - - // 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. - INST(ResultWitnessDecoration, ResultWitness, 1, 0) - - INST(VulkanRayPayloadDecoration, vulkanRayPayload, 0, 0) - INST(VulkanRayPayloadInDecoration, vulkanRayPayloadIn, 0, 0) - INST(VulkanHitAttributesDecoration, vulkanHitAttributes, 0, 0) - INST(VulkanHitObjectAttributesDecoration, vulkanHitObjectAttributes, 0, 0) - - INST(GlobalVariableShadowingGlobalParameterDecoration, GlobalVariableShadowingGlobalParameterDecoration, 2, 0) - - INST(RequireSPIRVVersionDecoration, requireSPIRVVersion, 1, 0) - INST(RequireGLSLVersionDecoration, requireGLSLVersion, 1, 0) - INST(RequireGLSLExtensionDecoration, requireGLSLExtension, 1, 0) - INST(RequireWGSLExtensionDecoration, requireWGSLExtension, 1, 0) - INST(RequireCUDASMVersionDecoration, requireCUDASMVersion, 1, 0) - INST(RequireCapabilityAtomDecoration, requireCapabilityAtom, 1, 0) - - INST(HasExplicitHLSLBindingDecoration, HasExplicitHLSLBinding, 0, 0) - - INST(DefaultValueDecoration, DefaultValue, 1, 0) - INST(ReadNoneDecoration, readNone, 0, 0) - INST(VulkanCallablePayloadDecoration, vulkanCallablePayload, 0, 0) - INST(VulkanCallablePayloadInDecoration, vulkanCallablePayloadIn, 0, 0) - INST(EarlyDepthStencilDecoration, earlyDepthStencil, 0, 0) - INST(PreciseDecoration, precise, 0, 0) - INST(PublicDecoration, public, 0, 0) - INST(HLSLExportDecoration, hlslExport, 0, 0) - INST(DownstreamModuleExportDecoration, downstreamModuleExport, 0, 0) - INST(DownstreamModuleImportDecoration, downstreamModuleImport, 0, 0) - INST(PatchConstantFuncDecoration, patchConstantFunc, 1, 0) - INST(MaxTessFactorDecoration, maxTessFactor, 1, 0) - INST(OutputControlPointsDecoration, outputControlPoints, 1, 0) - INST(OutputTopologyDecoration, outputTopology, 2, 0) - INST(PartitioningDecoration, partioning, 1, 0) - INST(DomainDecoration, domain, 1, 0) - INST(MaxVertexCountDecoration, maxVertexCount, 1, 0) - INST(InstanceDecoration, instance, 1, 0) - INST(NumThreadsDecoration, numThreads, 3, 0) - INST(FpDenormalPreserveDecoration, fpDenormalPreserve, 1, 0) - INST(FpDenormalFlushToZeroDecoration, fpDenormalFlushToZero, 1, 0) - INST(WaveSizeDecoration, waveSize, 1, 0) - - INST(AvailableInDownstreamIRDecoration, availableInDownstreamIR, 1, 0) - - // Added to IRParam parameters to an entry point - /* GeometryInputPrimitiveTypeDecoration */ - INST(PointInputPrimitiveTypeDecoration, pointPrimitiveType, 0, 0) - INST(LineInputPrimitiveTypeDecoration, linePrimitiveType, 0, 0) - INST(TriangleInputPrimitiveTypeDecoration, trianglePrimitiveType, 0, 0) - INST(LineAdjInputPrimitiveTypeDecoration, lineAdjPrimitiveType, 0, 0) - INST(TriangleAdjInputPrimitiveTypeDecoration, triangleAdjPrimitiveType, 0, 0) - INST_RANGE(GeometryInputPrimitiveTypeDecoration, PointInputPrimitiveTypeDecoration, TriangleAdjInputPrimitiveTypeDecoration) - - INST(StreamOutputTypeDecoration, streamOutputTypeDecoration, 1, 0) - - /// An `[entryPoint]` decoration marks a function that represents a shader entry point - INST(EntryPointDecoration, entryPoint, 2, 0) - - INST(CudaKernelDecoration, CudaKernel, 0, 0) - INST(CudaHostDecoration, CudaHost, 0, 0) - INST(TorchEntryPointDecoration, TorchEntryPoint, 0, 0) - INST(AutoPyBindCudaDecoration, AutoPyBindCUDA, 0, 0) - INST(CudaKernelForwardDerivativeDecoration, CudaKernelFwdDiffRef, 0, 0) - INST(CudaKernelBackwardDerivativeDecoration, CudaKernelBwdDiffRef, 0, 0) - INST(AutoPyBindExportInfoDecoration, PyBindExportFuncInfo, 0, 0) - INST(PyExportDecoration, PyExportDecoration, 0, 0) - - /// Used to mark parameters that are moved from entry point parameters to global params as coming from the entry point. - INST(EntryPointParamDecoration, entryPointParam, 0, 0) - - /// A `[dependsOn(x)]` decoration indicates that the parent instruction depends on `x` - /// even if it does not otherwise reference it. - INST(DependsOnDecoration, dependsOn, 1, 0) - - /// A `[keepAlive]` decoration marks an instruction that should not be eliminated. - INST(KeepAliveDecoration, keepAlive, 0, 0) - - /// A `[NoSideEffect]` decoration marks a callee to be side-effect free. - INST(NoSideEffectDecoration, noSideEffect, 0, 0) - - INST(BindExistentialSlotsDecoration, bindExistentialSlots, 0, 0) - - /// A `[format(f)]` decoration specifies that the format of an image should be `f` - INST(FormatDecoration, format, 1, 0) - - /// An `[unsafeForceInlineEarly]` decoration specifies that calls to this function should be inline after initial codegen - INST(UnsafeForceInlineEarlyDecoration, unsafeForceInlineEarly, 0, 0) - - /// A `[ForceInline]` decoration indicates the callee should be inlined by the Slang compiler. - INST(ForceInlineDecoration, ForceInline, 0, 0) - - /// A `[ForceUnroll]` decoration indicates the loop should be unrolled by the Slang compiler. - INST(ForceUnrollDecoration, ForceUnroll, 0, 0) - - /// 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`. - INST(SizeAndAlignmentDecoration, SizeAndAlignment, 3, 0) - - /// 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`. - INST(OffsetDecoration, Offset, 2, 0) - - /* LinkageDecoration */ - INST(ImportDecoration, import, 1, 0) - INST(ExportDecoration, export, 1, 0) - INST_RANGE(LinkageDecoration, ImportDecoration, ExportDecoration) - - /// Mark a global variable as a target builtin variable. - INST(TargetBuiltinVarDecoration, TargetBuiltinVar, 1, 0) - - /// Marks an inst as coming from an `extern` symbol defined in the user code. - INST(UserExternDecoration, UserExtern, 0, 0) - - /// An extern_cpp decoration marks the inst to emit its name without mangling for C++ interop. - INST(ExternCppDecoration, externCpp, 1, 0) - - // An externC decoration marks a function should be emitted inside an extern "C" block. - INST(ExternCDecoration, externC, 0, 0) - - /// An dllImport decoration marks a function as imported from a DLL. Slang will generate dynamic function loading logic to use this function at runtime. - INST(DllImportDecoration, dllImport, 2, 0) - /// An dllExport decoration marks a function as an export symbol. Slang will generate a native wrapper function that is exported to DLL. - INST(DllExportDecoration, dllExport, 1, 0) - /// An cudaDeviceExport decoration marks a function to be exported as a cuda __device__ function. - INST(CudaDeviceExportDecoration, cudaDeviceExport, 1, 0) - - /// Marks an interface as a COM interface declaration. - INST(ComInterfaceDecoration, COMInterface, 0, 0) - - /// Attaches a name to this instruction so that it can be identified - /// later in the compiler reliably - INST(KnownBuiltinDecoration, KnownBuiltinDecoration, 1, 0) - - /* Decorations for RTTI objects */ - INST(RTTITypeSizeDecoration, RTTI_typeSize, 1, 0) - INST(AnyValueSizeDecoration, AnyValueSize, 1, 0) - INST(SpecializeDecoration, SpecializeDecoration, 0, 0) - INST(SequentialIDDecoration, SequentialIDDecoration, 1, 0) - INST(DynamicDispatchWitnessDecoration, DynamicDispatchWitnessDecoration, 0, 0) - INST(StaticRequirementDecoration, StaticRequirementDecoration, 0, 0) - INST(DispatchFuncDecoration, DispatchFuncDecoration, 1, 0) - INST(TypeConstraintDecoration, TypeConstraintDecoration, 1, 0) - - - INST(BuiltinDecoration, BuiltinDecoration, 0, 0) - - /// The decorated instruction requires NVAPI to be included via prelude when compiling for D3D. - INST(RequiresNVAPIDecoration, requiresNVAPI, 0, 0) - - /// The decorated instruction is part of the NVAPI "magic" and should always use its original name - INST(NVAPIMagicDecoration, nvapiMagic, 1, 0) - - /// A decoration that applies to an entire IR module, and indicates the register/space binding - /// that the NVAPI shader parameter intends to use. - INST(NVAPISlotDecoration, nvapiSlot, 2, 0) - - /// Applie to an IR function and signals that inlining should not be performed unless unavoidable. - INST(NoInlineDecoration, noInline, 0, 0) - INST(NoRefInlineDecoration, noRefInline, 0, 0) - - INST(DerivativeGroupQuadDecoration, DerivativeGroupQuad, 0, 0) - INST(DerivativeGroupLinearDecoration, DerivativeGroupLinear, 0, 0) - - INST(MaximallyReconvergesDecoration, MaximallyReconverges, 0, 0) - INST(QuadDerivativesDecoration, QuadDerivatives, 0, 0) - INST(RequireFullQuadsDecoration, RequireFullQuads, 0, 0) - INST(TempCallArgVarDecoration, TempCallArgVar, 0, 0) - - // Marks a type to be non copyable, causing SSA pass to skip turning variables of the the type into SSA values. - INST(NonCopyableTypeDecoration, nonCopyable, 0, 0) - - // Marks a value to be dynamically uniform. - INST(DynamicUniformDecoration, DynamicUniform, 0, 0) - - /// A call to the decorated function should always be folded into its use site. - INST(AlwaysFoldIntoUseSiteDecoration, alwaysFold, 0, 0) - - INST(GlobalOutputDecoration, output, 0, 0) - INST(GlobalInputDecoration, input, 0, 0) - INST(GLSLLocationDecoration, glslLocation, 1, 0) - INST(GLSLOffsetDecoration, glslOffset, 1, 0) - INST(VkStructOffsetDecoration, vkStructOffset, 1, 0) - INST(RayPayloadDecoration, raypayload, 0, 0) - - /* Mesh Shader outputs */ - INST(VerticesDecoration, vertices, 1, 0) - INST(IndicesDecoration, indices, 1, 0) - INST(PrimitivesDecoration, primitives, 1, 0) - INST_RANGE(MeshOutputDecoration, VerticesDecoration, PrimitivesDecoration) - INST(HLSLMeshPayloadDecoration, payload, 0, 0) - INST(GLSLPrimitivesRateDecoration, perprimitive, 0, 0) - // Marks an inst that represents the gl_Position output. - INST(GLPositionOutputDecoration, PositionOutput, 0, 0) - // Marks an inst that represents the gl_Position input. - INST(GLPositionInputDecoration, PositionInput, 0, 0) - - // Marks a fragment shader input as per-vertex. - INST(PerVertexDecoration, PerVertex, 0, 0) - - /* StageAccessDecoration */ - INST(StageReadAccessDecoration, stageReadAccess, 0, 0) - INST(StageWriteAccessDecoration, stageWriteAccess, 0, 0) - INST_RANGE(StageAccessDecoration, StageReadAccessDecoration, StageWriteAccessDecoration) - - INST(SemanticDecoration, semantic, 2, 0) - INST(ConstructorDecoration, constructor, 1, 0) - INST(MethodDecoration, method, 0, 0) - INST(PackOffsetDecoration, packoffset, 2, 0) - INST(SpecializationConstantDecoration, SpecializationConstantDecoration, 1, 0) - - // Reflection metadata for a shader parameter that provides the original type name. - INST(UserTypeNameDecoration, UserTypeName, 1, 0) - // Reflection metadata for a shader parameter that refers to the associated counter buffer of a UAV. - INST(CounterBufferDecoration, CounterBuffer, 1, 0) - - INST(RequireSPIRVDescriptorIndexingExtensionDecoration, RequireSPIRVDescriptorIndexingExtensionDecoration, 0, 0) - INST(SPIRVOpDecoration, spirvOpDecoration, 1, 0) - - /// Decorated function is marked for the forward-mode differentiation pass. - INST(ForwardDifferentiableDecoration, forwardDifferentiable, 0, 0) - - /// Decorates a auto-diff transcribed value with the original value that the inst is transcribed from. - INST(AutoDiffOriginalValueDecoration, AutoDiffOriginalValueDecoration, 1, 0) - - /// Decorates a type as auto-diff builtin type. - INST(AutoDiffBuiltinDecoration, AutoDiffBuiltinDecoration, 0, 0) - - /// Used by the auto-diff pass to hold a reference to the - /// generated derivative function. - INST(ForwardDerivativeDecoration, fwdDerivative, 1, 0) - - /// Used by the auto-diff pass to hold a reference to the - /// generated derivative function. - INST(BackwardDifferentiableDecoration, backwardDifferentiable, 1, 0) - - /// Used by the auto-diff pass to hold a reference to the - /// primal substitute function. - INST(PrimalSubstituteDecoration, primalSubstFunc, 1, 0) - - /// Decorations to associate an original function with compiler generated backward derivative functions. - INST(BackwardDerivativePrimalDecoration, backwardDiffPrimalReference, 1, 0) - INST(BackwardDerivativePropagateDecoration, backwardDiffPropagateReference, 1, 0) - INST(BackwardDerivativeIntermediateTypeDecoration, backwardDiffIntermediateTypeReference, 1, 0) - INST(BackwardDerivativeDecoration, backwardDiffReference, 1, 0) - - INST(UserDefinedBackwardDerivativeDecoration, userDefinedBackwardDiffReference, 1, 0) - INST(BackwardDerivativePrimalContextDecoration, BackwardDerivativePrimalContextDecoration, 1, 0) - INST(BackwardDerivativePrimalReturnDecoration, BackwardDerivativePrimalReturnDecoration, 1, 0) - - // Mark a parameter as autodiff primal context. - INST(PrimalContextDecoration, PrimalContextDecoration, 0, 0) - INST(LoopCounterDecoration, loopCounterDecoration, 0, 0) - INST(LoopCounterUpdateDecoration, loopCounterUpdateDecoration, 0, 0) - - /* Auto-diff inst decorations */ - /// Used by the auto-diff pass to mark insts that compute - /// a primal value. - INST(PrimalInstDecoration, primalInstDecoration, 0, 0) - - /// Used by the auto-diff pass to mark insts that compute - /// a differential value. - INST(DifferentialInstDecoration, diffInstDecoration, 1, 0) - - /// Used by the auto-diff pass to mark insts that compute - /// BOTH a differential and a primal value. - INST(MixedDifferentialInstDecoration, mixedDiffInstDecoration, 1, 0) - - INST(RecomputeBlockDecoration, RecomputeBlockDecoration, 0, 0) - INST_RANGE(AutodiffInstDecoration, PrimalInstDecoration, RecomputeBlockDecoration) - - /// Used by the auto-diff pass to mark insts whose result is stored - /// in an intermediary struct for reuse in backward propagation phase. - INST(PrimalValueStructKeyDecoration, primalValueKey, 1, 0) - - /// Used by the auto-diff pass to mark the primal element type of an - /// forward-differentiated updateElement inst. - INST(PrimalElementTypeDecoration, primalElementType, 1, 0) - - /// Used by the auto-diff pass to mark the differential type of an intermediate context field. - INST(IntermediateContextFieldDifferentialTypeDecoration, IntermediateContextFieldDifferentialTypeDecoration, 1, 0) - - /// Used by the auto-diff pass to hold a reference to a - /// differential member of a type in its associated differential type. - INST(DerivativeMemberDecoration, derivativeMemberDecoration, 1, 0) - - /// Treat a function as differentiable function - INST(TreatAsDifferentiableDecoration, treatAsDifferentiableDecoration, 0, 0) - - /// Treat a call to arbitrary function as a differentiable call. - INST(TreatCallAsDifferentiableDecoration, treatCallAsDifferentiableDecoration, 0, 0) - - /// Mark a call as explicitly calling a differentiable function. - INST(DifferentiableCallDecoration, differentiableCallDecoration, 0, 0) - - /// 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. - /// - INST(OptimizableTypeDecoration, optimizableTypeDecoration, 0, 0) - - /// 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. - /// - INST(IgnoreSideEffectsDecoration, ignoreSideEffectsDecoration, 0, 0) - - /// Hint that the result from a call to the decorated function should be stored in backward prop function. - INST(PreferCheckpointDecoration, PreferCheckpointDecoration, 0, 0) - - /// Hint that the result from a call to the decorated function should be recomputed in backward prop function. - INST(PreferRecomputeDecoration, PreferRecomputeDecoration, 0, 0) - - /// Hint that a struct is used for reverse mode checkpointing - INST(CheckpointIntermediateDecoration, CheckpointIntermediateDecoration, 1, 0) - - INST_RANGE(CheckpointHintDecoration, PreferCheckpointDecoration, PreferRecomputeDecoration) - - /// Marks a function whose return value is never dynamic uniform. - INST(NonDynamicUniformReturnDecoration, NonDynamicUniformReturnDecoration, 0, 0) - - /// Marks a class type as a COM interface implementation, which enables - /// the witness table to be easily picked up by emit. - INST(COMWitnessDecoration, COMWitnessDecoration, 1, 0) - - /* Differentiable Type Dictionary */ - INST(DifferentiableTypeDictionaryDecoration, DifferentiableTypeDictionaryDecoration, 0, PARENT) - - /// Overrides the floating mode for the target function - INST(FloatingPointModeOverrideDecoration, FloatingPointModeOverride, 1, 0) - - /// Recognized by SPIRV-emit pass so we can emit a SPIRV `BufferBlock` decoration. - INST(SPIRVBufferBlockDecoration, spvBufferBlock, 0, 0) - - /// Decorates an inst with a debug source location (IRDebugSource, IRIntLit(line), IRIntLit(col)). - INST(DebugLocationDecoration, DebugLocation, 3, 0) - - /// Decorates a function with a link to its debug function representation - INST(DebugFunctionDecoration, DebugFunction, 1, 0) - - /// Recognized by SPIRV-emit pass so we can emit a SPIRV `Block` decoration. - INST(SPIRVBlockDecoration, spvBlock, 0, 0) - - /// 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. - INST(SPIRVNonUniformResourceDecoration, NonUniformResource, 0, 0) - - // Stores flag bits of which memory qualifiers an object has - INST(MemoryQualifierSetDecoration, MemoryQualifierSetDecoration, 1, 0) - - /// Marks a function as one which access a bitfield with the specified - /// backing value key, width and offset - INST(BitFieldAccessorDecoration, BitFieldAccessorDecoration, 3, 0) - - INST_RANGE(Decoration, HighLevelDeclDecoration, BitFieldAccessorDecoration) - - // - -// 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`. -// -INST(MakeExistential, makeExistential, 2, 0) -// A `MakeExistentialWithRTTI(v, w, t)` is the same with `MakeExistential`, -// but with the type of `v` being an explict operand. -INST(MakeExistentialWithRTTI, makeExistentialWithRTTI, 3, 0) - -// A 'CreateExistentialObject(typeID, T)` packs user-provided `typeID` and a -// value of any type, and constructs an existential value of type `I`. -INST(CreateExistentialObject, createExistentialObject, 2, 0) - -// 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. -// -INST(WrapExistential, wrapExistential, 1, 0) - -// A `GetValueFromBoundInterface` takes a `BindInterface` value and returns the -// value of concrete type `T` value that is being stored. -// -INST(GetValueFromBoundInterface, getValueFromBoundInterface, 1, 0) - -INST(ExtractExistentialValue, extractExistentialValue, 1, 0) -INST(ExtractExistentialType, extractExistentialType, 1, HOISTABLE) -INST(ExtractExistentialWitnessTable, extractExistentialWitnessTable, 1, HOISTABLE) -INST(IsNullExistential, isNullExistential, 1, 0) -INST(ExtractTaggedUnionTag, extractTaggedUnionTag, 1, 0) -INST(ExtractTaggedUnionPayload, extractTaggedUnionPayload, 1, 0) - -INST(BuiltinCast, BuiltinCast, 1, 0) -INST(BitCast, bitCast, 1, 0) -INST(Reinterpret, reinterpret, 1, 0) -INST(Unmodified, unmodified, 1, 0) -INST(OutImplicitCast, outImplicitCast, 1, 0) -INST(InOutImplicitCast, inOutImplicitCast, 1, 0) -INST(IntCast, intCast, 1, 0) -INST(FloatCast, floatCast, 1, 0) -INST(CastIntToFloat, castIntToFloat, 1, 0) -INST(CastFloatToInt, castFloatToInt, 1, 0) -INST(CastPtrToBool, CastPtrToBool, 1, 0) -INST(CastPtrToInt, CastPtrToInt, 1, 0) -INST(CastIntToPtr, CastIntToPtr, 1, 0) -INST(CastToVoid, castToVoid, 1, 0) -INST(PtrCast, PtrCast, 1, 0) -INST(CastEnumToInt, CastEnumToInt, 1, 0) -INST(CastIntToEnum, CastIntToEnum, 1, 0) -INST(EnumCast, EnumCast, 1, 0) -INST(CastUInt2ToDescriptorHandle, CastUInt2ToDescriptorHandle, 1, 0) -INST(CastDescriptorHandleToUInt2, CastDescriptorHandleToUInt2, 1, 0) - -// Represents a no-op cast to convert a resource pointer to a resource on targets where the resource handles are already concrete types. -INST(CastDescriptorHandleToResource, CastDescriptorHandleToResource, 1, 0) - -INST(TreatAsDynamicUniform, TreatAsDynamicUniform, 1, 0) - -INST(SizeOf, sizeOf, 1, 0) -INST(AlignOf, alignOf, 1, 0) -INST(CountOf, countOf, 1, 0) - -INST(GetArrayLength, GetArrayLength, 1, 0) -INST(IsType, IsType, 3, 0) -INST(TypeEquals, TypeEquals, 2, 0) -INST(IsInt, IsInt, 1, 0) -INST(IsBool, IsBool, 1, 0) -INST(IsFloat, IsFloat, 1, 0) -INST(IsHalf, IsHalf, 1, 0) -INST(IsUnsignedInt, IsUnsignedInt, 1, 0) -INST(IsSignedInt, IsSignedInt, 1, 0) -INST(IsVector, IsVector, 1, 0) -INST(GetDynamicResourceHeap, GetDynamicResourceHeap, 0, HOISTABLE) - -INST(ForwardDifferentiate, ForwardDifferentiate, 1, 0) - -// Produces the primal computation of backward derivatives, will return an intermediate context for -// backward derivative func. -INST(BackwardDifferentiatePrimal, BackwardDifferentiatePrimal, 1, 0) - -// Produces the actual backward derivative propagate function, using the intermediate context returned by the -// primal func produced from `BackwardDifferentiatePrimal`. -INST(BackwardDifferentiatePropagate, BackwardDifferentiatePropagate, 1, 0) - -// Represents the conceptual backward derivative function. Only produced by lower-to-ir and will be -// replaced with `BackwardDifferentiatePrimal` and `BackwardDifferentiatePropagate`. -INST(BackwardDifferentiate, BackwardDifferentiate, 1, 0) - -INST(PrimalSubstitute, PrimalSubstitute, 1, 0) - -INST(DispatchKernel, DispatchKernel, 3, 0) -INST(CudaKernelLaunch, CudaKernelLaunch, 6, 0) - -// Converts other resources (such as ByteAddressBuffer) to the equivalent StructuredBuffer -INST(GetEquivalentStructuredBuffer, getEquivalentStructuredBuffer, 1, 0) - -// Gets a T[] pointer to the underlying data of a StructuredBuffer etc... -INST(GetStructuredBufferPtr, getStructuredBufferPtr, 1, 0) -// Gets a uint[] pointer to the underlying data of a ByteAddressBuffer etc... -INST(GetUntypedBufferPtr, getUntypedBufferPtr, 1, 0) - -/* Layout */ - INST(VarLayout, varLayout, 1, HOISTABLE) - - /* TypeLayout */ - INST(TypeLayoutBase, typeLayout, 0, HOISTABLE) - INST(ParameterGroupTypeLayout, parameterGroupTypeLayout, 2, HOISTABLE) - INST(ArrayTypeLayout, arrayTypeLayout, 1, HOISTABLE) - INST(StreamOutputTypeLayout, streamOutputTypeLayout, 1, HOISTABLE) - INST(MatrixTypeLayout, matrixTypeLayout, 1, HOISTABLE) - INST(ExistentialTypeLayout, existentialTypeLayout, 0, HOISTABLE) - INST(StructTypeLayout, structTypeLayout, 0, HOISTABLE) - INST(TupleTypeLayout, tupleTypeLayout, 0, HOISTABLE) - INST(StructuredBufferTypeLayout, structuredBufferTypeLayout, 1, HOISTABLE) - // 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. - INST(PointerTypeLayout, ptrTypeLayout, 0, HOISTABLE) - INST_RANGE(TypeLayout, TypeLayoutBase, PointerTypeLayout) - - INST(EntryPointLayout, EntryPointLayout, 1, HOISTABLE) -INST_RANGE(Layout, VarLayout, EntryPointLayout) - -/* Attr */ - INST(PendingLayoutAttr, pendingLayout, 1, HOISTABLE) - INST(StageAttr, stage, 1, HOISTABLE) - INST(StructFieldLayoutAttr, fieldLayout, 2, HOISTABLE) - INST(TupleFieldLayoutAttr, fieldLayout, 1, HOISTABLE) - INST(CaseTypeLayoutAttr, caseLayout, 1, HOISTABLE) - INST(UNormAttr, unorm, 0, HOISTABLE) - INST(SNormAttr, snorm, 0, HOISTABLE) - INST(NoDiffAttr, no_diff, 0, HOISTABLE) - INST(NonUniformAttr, nonuniform, 0, HOISTABLE) - INST(AlignedAttr, Aligned, 1, HOISTABLE) - - /* SemanticAttr */ - INST(UserSemanticAttr, userSemantic, 2, HOISTABLE) - INST(SystemValueSemanticAttr, systemValueSemantic, 2, HOISTABLE) - INST_RANGE(SemanticAttr, UserSemanticAttr, SystemValueSemanticAttr) - /* LayoutResourceInfoAttr */ - INST(TypeSizeAttr, size, 2, HOISTABLE) - INST(VarOffsetAttr, offset, 2, HOISTABLE) - INST_RANGE(LayoutResourceInfoAttr, TypeSizeAttr, VarOffsetAttr) - INST(FuncThrowTypeAttr, FuncThrowType, 1, HOISTABLE) - -INST_RANGE(Attr, PendingLayoutAttr, FuncThrowTypeAttr) - -/* Liveness */ - INST(LiveRangeStart, liveRangeStart, 2, 0) - INST(LiveRangeEnd, liveRangeEnd, 0, 0) -INST_RANGE(LiveRangeMarker, LiveRangeStart, LiveRangeEnd) - -/* IRSpecialization */ -INST(SpecializationDictionaryItem, SpecializationDictionaryItem, 0, 0) -INST(GenericSpecializationDictionary, GenericSpecializationDictionary, 0, PARENT) -INST(ExistentialFuncSpecializationDictionary, ExistentialFuncSpecializationDictionary, 0, PARENT) -INST(ExistentialTypeSpecializationDictionary, ExistentialTypeSpecializationDictionary, 0, PARENT) - -/* Differentiable Type Dictionary */ -INST(DifferentiableTypeDictionaryItem, DifferentiableTypeDictionaryItem, 0, 0) - -/* Differentiable Type Annotation (for run-time types)*/ -INST(DifferentiableTypeAnnotation, DifferentiableTypeAnnotation, 2, HOISTABLE) - -INST(BeginFragmentShaderInterlock, BeginFragmentShaderInterlock, 0, 0) -INST(EndFragmentShaderInterlock, BeginFragmentShaderInterlock, 0, 0) - -/* DebugInfo */ -INST(DebugSource, DebugSource, 2, HOISTABLE) -INST(DebugLine, DebugLine, 5, 0) -INST(DebugVar, DebugVar, 4, 0) -INST(DebugValue, DebugValue, 2, 0) -INST(DebugInlinedAt, DebugInlinedAt, 5, 0) -INST(DebugFunction, DebugFunction, 5, 0) -INST(DebugInlinedVariable, DebugInlinedVariable, 2, 0) -INST(DebugScope, DebugScope, 2, 0) -INST(DebugNoScope, DebugNoScope, 1, 0) -INST(DebugBuildIdentifier, DebugBuildIdentifier, 2, 0) - -/* Embedded Precompiled Libraries */ -INST(EmbeddedDownstreamIR, EmbeddedDownstreamIR, 2, 0) - -/* Inline assembly */ - -INST(SPIRVAsm, SPIRVAsm, 0, PARENT) -INST(SPIRVAsmInst, SPIRVAsmInst, 1, 0) - // 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 - INST(SPIRVAsmOperandLiteral, SPIRVAsmOperandLiteral, 1, HOISTABLE) - // 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 - INST(SPIRVAsmOperandInst, SPIRVAsmOperandInst, 1, 0) - INST(SPIRVAsmOperandConvertTexel, SPIRVAsmOperandConvertTexel, 1, 0) - //a late resolving type to handle the case of ray objects (resolving late due to constexpr data requirment) - INST(SPIRVAsmOperandRayPayloadFromLocation, SPIRVAsmOperandRayPayloadFromLocation, 1, 0) - INST(SPIRVAsmOperandRayAttributeFromLocation, SPIRVAsmOperandRayAttributeFromLocation, 1, 0) - INST(SPIRVAsmOperandRayCallableFromLocation, SPIRVAsmOperandRayCallableFromLocation, 1, 0) - // 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 - INST(SPIRVAsmOperandEnum, SPIRVAsmOperandEnum, 1, HOISTABLE) - // A reference to a builtin variable. - INST(SPIRVAsmOperandBuiltinVar, SPIRVAsmOperandBuiltinVar, 1, HOISTABLE) - // A reference to the glsl450 instruction set. - INST(SPIRVAsmOperandGLSL450Set, SPIRVAsmOperandGLSL450Set, 0, HOISTABLE) - INST(SPIRVAsmOperandDebugPrintfSet, SPIRVAsmOperandDebugPrintfSet, 0, HOISTABLE) - // A string which is given a unique ID in the backend, used to refer to - // results of other instrucions in the same asm block - INST(SPIRVAsmOperandId, SPIRVAsmOperandId, 1, HOISTABLE) - // A special instruction which marks the place to insert the generated - // result operand - INST(SPIRVAsmOperandResult, SPIRVAsmOperandResult, 0, HOISTABLE) - // A special instruction which represents a type directed truncation - // operation where extra components are dropped - INST(SPIRVAsmOperandTruncate, __truncate, 0, HOISTABLE) - - // A special instruction which represents an ID of an entry point that references the current function. - INST(SPIRVAsmOperandEntryPoint, __entryPoint, 0, HOISTABLE) - - // A type function which returns the result type of sampling an image of - // this component type - INST(SPIRVAsmOperandSampledType, __sampledType, 1, HOISTABLE) - - // A type function which returns the equivalent OpTypeImage type of sampled image value - INST(SPIRVAsmOperandImageType, __imageType, 1, HOISTABLE) - - // A type function which returns the equivalent OpTypeImage type of sampled image value - INST(SPIRVAsmOperandSampledImageType, __sampledImageType, 1, HOISTABLE) - -INST_RANGE(SPIRVAsmOperand, SPIRVAsmOperandLiteral, SPIRVAsmOperandSampledImageType) - - -#undef PARENT -#undef USE_OTHER -#undef INST_RANGE -#undef INST diff --git a/source/slang/slang-ir-insts-enum.h b/source/slang/slang-ir-insts-enum.h new file mode 100644 index 00000000000..061b1c18eee --- /dev/null +++ b/source/slang/slang-ir-insts-enum.h @@ -0,0 +1,37 @@ +#pragma once + +#include + +namespace Slang +{ + +/* Bit usage of IROp is as follows + + MainOp | Other +Bit range: 0-10 | Remaining bits + +For doing range checks (for example for doing isa tests), the value is masked by kIROpMask_OpMask, +such that the Other bits don't interfere. The other bits can be used for storage for anything that +needs to identify as a different 'op' or 'type'. It is currently used currently for storing the +TextureFlavor of a IRResourceTypeBase derived types for example. + +TODO: We should eliminate the use of the "other" bits so that the entire value/state +of an instruction is manifest in its opcode, operands, and children. +*/ +enum IROp : int32_t +{ + +#if 0 // FIDDLE TEMPLATE: +% require("source/slang/slang-ir.h.lua").instEnums() +#else // FIDDLE OUTPUT: +#define FIDDLE_GENERATED_OUTPUT_ID 0 +#include "slang-ir-insts-enum.h.fiddle" +#endif // FIDDLE END + + /// The total number of valid opcodes + kIROpCount, + + /// An invalid opcode used to represent a missing or unknown opcode value. + kIROp_Invalid = kIROpCount, +}; +} // namespace Slang diff --git a/source/slang/slang-ir-insts-info.cpp b/source/slang/slang-ir-insts-info.cpp new file mode 100644 index 00000000000..5b03c3dbecc --- /dev/null +++ b/source/slang/slang-ir-insts-info.cpp @@ -0,0 +1,63 @@ +#include "core/slang-basic.h" +#include "slang-ir.h" + +namespace Slang +{ + +struct IROpMapEntry +{ + IROp op; + IROpInfo info; +}; + +// TODO: We should ideally be speeding up the name->inst +// mapping by using a dictionary, or even by pre-computing +// a hash table to be stored as a `static const` array. +// +// NOTE! That this array is now constructed in such a way that looking up +// an entry from an op is fast, by keeping blocks of main, and pseudo ops in same order +// as the ops themselves. Care must be taken to keep this constraint. +static const IROpMapEntry kIROps[] = { + +// Main ops in order + +#if 0 // FIDDLE TEMPLATE: +% require("source/slang/slang-ir.h.lua").instInfoEntries() +#else // FIDDLE OUTPUT: +#define FIDDLE_GENERATED_OUTPUT_ID 0 +#include "slang-ir-insts-info.cpp.fiddle" +#endif // FIDDLE END + + // Invalid op sentinel value comes after all the valid ones + {kIROp_Invalid, {"invalid", 0, 0}}, +}; + +IROpInfo getIROpInfo(IROp opIn) +{ + const int op = opIn & kIROpMask_OpMask; + if (op < kIROpCount) + { + // It's a main op + const auto& entry = kIROps[op]; + SLANG_ASSERT(entry.op == op); + return entry.info; + } + + // Don't know what this is + SLANG_ASSERT(!"Invalid op"); + SLANG_ASSERT(kIROps[kIROpCount].op == kIROp_Invalid); + return kIROps[kIROpCount].info; +} + +IROp findIROp(const UnownedStringSlice& name) +{ + for (auto ee : kIROps) + { + if (name == ee.info.name) + return ee.op; + } + + return IROp(kIROp_Invalid); +} + +} // namespace Slang diff --git a/source/slang/slang-ir-insts.h b/source/slang/slang-ir-insts.h index bb57c082c0e..8ce4e46cd4a 100644 --- a/source/slang/slang-ir-insts.h +++ b/source/slang/slang-ir-insts.h @@ -1,6 +1,5 @@ // slang-ir-insts.h -#ifndef SLANG_IR_INSTS_H_INCLUDED -#define SLANG_IR_INSTS_H_INCLUDED +#pragma once // This file extends the core definitions in `ir.h` // with a wider variety of concrete instructions, @@ -14,21 +13,27 @@ #include "slang-syntax.h" #include "slang-type-layout.h" +// +#include "slang-ir-insts.h.fiddle" + +FIDDLE() namespace Slang { class Decl; +FIDDLE() struct IRCapabilitySet : IRInst { - IR_PARENT_ISA(CapabilitySet); + FIDDLE(baseInst()) CapabilitySet getCaps(); }; +FIDDLE() struct IRDecoration : IRInst { - IR_PARENT_ISA(Decoration) + FIDDLE(baseInst()) IRDecoration* getNextDecoration() { return as(getNextInst()); } }; @@ -36,13 +41,10 @@ struct IRDecoration : IRInst // Associates an IR-level decoration with a source declaration // in the high-level AST, that can be used to extract // additional information that informs code emission. +FIDDLE() struct IRHighLevelDeclDecoration : IRDecoration { - enum - { - kOp = kIROp_HighLevelDeclDecoration - }; - IR_LEAF_ISA(HighLevelDeclDecoration) + FIDDLE(leafInst()) IRPtrLit* getDeclOperand() { return cast(getOperand(0)); } Decl* getDecl() { return (Decl*)getDeclOperand()->getValue(); } @@ -54,34 +56,29 @@ enum IRLoopControl kIRLoopControl_Loop, }; +FIDDLE() struct IRLoopControlDecoration : IRDecoration { - enum - { - kOp = kIROp_LoopControlDecoration - }; - IR_LEAF_ISA(LoopControlDecoration) + FIDDLE(leafInst()) IRConstant* getModeOperand() { return cast(getOperand(0)); } IRLoopControl getMode() { return IRLoopControl(getModeOperand()->value.intVal); } }; +FIDDLE() struct IRLoopMaxItersDecoration : IRDecoration { - enum - { - kOp = kIROp_LoopMaxItersDecoration - }; - IR_LEAF_ISA(LoopMaxItersDecoration) + FIDDLE(leafInst()) IRConstant* getMaxItersInst() { return cast(getOperand(0)); } IRIntegerValue getMaxIters() { return as(getOperand(0))->getValue(); } }; +FIDDLE() struct IRTargetSpecificDecoration : IRDecoration { - IR_PARENT_ISA(TargetSpecificDecoration) + FIDDLE(baseInst()) IRCapabilitySet* getTargetCapsOperand() { return cast(getOperand(0)); } @@ -108,79 +105,67 @@ struct IRTargetSpecificDecoration : IRDecoration } }; +FIDDLE() struct IRTargetSpecificDefinitionDecoration : IRTargetSpecificDecoration { - IR_PARENT_ISA(TargetSpecificDefinitionDecoration) + FIDDLE(baseInst()) }; +FIDDLE() struct IRTargetDecoration : IRTargetSpecificDefinitionDecoration { - enum - { - kOp = kIROp_TargetDecoration - }; - IR_LEAF_ISA(TargetDecoration) + FIDDLE(leafInst()) }; +FIDDLE() struct IRTargetSystemValueDecoration : IRDecoration { - enum - { - kOp = kIROp_TargetSystemValueDecoration - }; - IR_LEAF_ISA(TargetSystemValueDecoration) + FIDDLE(leafInst()) IRStringLit* getSemanticOperand() { return cast(getOperand(0)); } UnownedStringSlice getSemantic() { return getSemanticOperand()->getStringSlice(); } }; +FIDDLE() struct IRTargetIntrinsicDecoration : IRTargetSpecificDefinitionDecoration { - enum - { - kOp = kIROp_TargetIntrinsicDecoration - }; - IR_LEAF_ISA(TargetIntrinsicDecoration) + FIDDLE(leafInst()) IRStringLit* getDefinitionOperand() { return cast(getOperand(1)); } UnownedStringSlice getDefinition() { return getDefinitionOperand()->getStringSlice(); } }; +FIDDLE() struct IRRequirePreludeDecoration : IRTargetSpecificDecoration { - IR_LEAF_ISA(RequirePreludeDecoration) + FIDDLE(leafInst()) UnownedStringSlice getPrelude() { return as(getOperand(1))->getStringSlice(); } }; +FIDDLE() struct IRIntrinsicOpDecoration : IRDecoration { - enum - { - kOp = kIROp_IntrinsicOpDecoration - }; - IR_LEAF_ISA(IntrinsicOpDecoration) + FIDDLE(leafInst()) IRIntLit* getIntrinsicOpOperand() { return cast(getOperand(0)); } IROp getIntrinsicOp() { return (IROp)getIntrinsicOpOperand()->getValue(); } }; +FIDDLE() struct IRAlignedAddressDecoration : IRDecoration { - IR_LEAF_ISA(AlignedAddressDecoration) + FIDDLE(leafInst()) IRInst* getAlignment() { return getOperand(0); } }; +FIDDLE() struct IRGLSLOuterArrayDecoration : IRDecoration { - enum - { - kOp = kIROp_GLSLOuterArrayDecoration - }; - IR_LEAF_ISA(GLSLOuterArrayDecoration) + FIDDLE(leafInst()) IRStringLit* getOuterArrayNameOperand() { return cast(getOperand(0)); } @@ -210,13 +195,10 @@ enum class IRTargetBuiltinVarName SpvBaseVertex, }; +FIDDLE() struct IRInterpolationModeDecoration : IRDecoration { - enum - { - kOp = kIROp_InterpolationModeDecoration - }; - IR_LEAF_ISA(InterpolationModeDecoration) + FIDDLE(leafInst()) IRConstant* getModeOperand() { return cast(getOperand(0)); } @@ -227,13 +209,10 @@ struct IRInterpolationModeDecoration : IRDecoration /// in conjunction with the given instruction. Back-end /// code generation may use this to help derive symbol /// names, emit debug information, etc. +FIDDLE() struct IRNameHintDecoration : IRDecoration { - enum - { - kOp = kIROp_NameHintDecoration - }; - IR_LEAF_ISA(NameHintDecoration) + FIDDLE(leafInst()) IRStringLit* getNameOperand() { return cast(getOperand(0)); } @@ -241,13 +220,10 @@ struct IRNameHintDecoration : IRDecoration }; /// A decoration on a RTTIObject providing type size information. +FIDDLE() struct IRRTTITypeSizeDecoration : IRDecoration { - enum - { - kOp = kIROp_RTTITypeSizeDecoration - }; - IR_LEAF_ISA(RTTITypeSizeDecoration) + FIDDLE(leafInst()) IRIntLit* getTypeSizeOperand() { return cast(getOperand(0)); } IRIntegerValue getTypeSize() { return getTypeSizeOperand()->getValue(); } @@ -255,54 +231,39 @@ struct IRRTTITypeSizeDecoration : IRDecoration /// A decoration on `IRInterfaceType` that marks the size of `AnyValue` that should /// be used to represent a polymorphic value of the interface. +FIDDLE() struct IRAnyValueSizeDecoration : IRDecoration { - enum - { - kOp = kIROp_AnyValueSizeDecoration - }; - IR_LEAF_ISA(AnyValueSizeDecoration) + FIDDLE(leafInst()) IRIntLit* getSizeOperand() { return cast(getOperand(0)); } IRIntegerValue getSize() { return getSizeOperand()->getValue(); } }; +FIDDLE() struct IRDispatchFuncDecoration : IRDecoration { - enum - { - kOp = kIROp_DispatchFuncDecoration - }; - IR_LEAF_ISA(DispatchFuncDecoration) + FIDDLE(leafInst()) IRInst* getFunc() { return getOperand(0); } }; +FIDDLE() struct IRSpecializeDecoration : IRDecoration { - enum - { - kOp = kIROp_SpecializeDecoration - }; - IR_LEAF_ISA(SpecializeDecoration) + FIDDLE(leafInst()) }; +FIDDLE() struct IRComInterfaceDecoration : IRDecoration { - enum - { - kOp = kIROp_ComInterfaceDecoration - }; - IR_LEAF_ISA(ComInterfaceDecoration) + FIDDLE(leafInst()) }; +FIDDLE() struct IRCOMWitnessDecoration : IRDecoration { - enum - { - kOp = kIROp_COMWitnessDecoration - }; - IR_LEAF_ISA(COMWitnessDecoration) + FIDDLE(leafInst()) IRInst* getWitnessTable() { return getOperand(0); } }; @@ -310,78 +271,30 @@ struct IRCOMWitnessDecoration : IRDecoration /// A decoration on `IRParam`s that represent generic parameters, /// marking the interface type that the generic parameter conforms to. /// A generic parameter can have more than one `IRTypeConstraintDecoration`s +FIDDLE() struct IRTypeConstraintDecoration : IRDecoration { - enum - { - kOp = kIROp_TypeConstraintDecoration - }; - IR_LEAF_ISA(TypeConstraintDecoration) + FIDDLE(leafInst()) IRInst* getConstraintType() { return getOperand(0); } }; -#define IR_SIMPLE_DECORATION(NAME) \ - struct IR##NAME : IRDecoration \ - { \ - enum \ - { \ - kOp = kIROp_##NAME \ - }; \ - IR_LEAF_ISA(NAME) \ - }; \ - /**/ - bool isSimpleDecoration(IROp op); -/// A decoration that indicates that a variable represents -/// a vulkan ray payload, and should have a location assigned -/// to it. -IR_SIMPLE_DECORATION(VulkanRayPayloadDecoration) -IR_SIMPLE_DECORATION(VulkanRayPayloadInDecoration) - -/// A decoration that indicates that a variable represents -/// a vulkan callable shader payload, and should have a location assigned -/// to it. -IR_SIMPLE_DECORATION(VulkanCallablePayloadDecoration) -IR_SIMPLE_DECORATION(VulkanCallablePayloadInDecoration) - -/// A decoration that indicates that a variable represents -/// vulkan hit attributes, and should have a location assigned -/// to it. -IR_SIMPLE_DECORATION(VulkanHitAttributesDecoration) - -/// A decoration that indicates that a variable represents -/// vulkan hit object attributes, and should have a location assigned -/// to it. -IR_SIMPLE_DECORATION(VulkanHitObjectAttributesDecoration) - -IR_SIMPLE_DECORATION(PerVertexDecoration) - -IR_SIMPLE_DECORATION(SPIRVBlockDecoration) - -IR_SIMPLE_DECORATION(DefaultValueDecoration) - +FIDDLE() struct IRRequireGLSLVersionDecoration : IRDecoration { - enum - { - kOp = kIROp_RequireGLSLVersionDecoration - }; - IR_LEAF_ISA(RequireGLSLVersionDecoration) + FIDDLE(leafInst()) IRConstant* getLanguageVersionOperand() { return cast(getOperand(0)); } Int getLanguageVersion() { return Int(getLanguageVersionOperand()->value.intVal); } }; +FIDDLE() struct IRSPIRVNonUniformResourceDecoration : IRDecoration { - enum - { - kOp = kIROp_SPIRVNonUniformResourceDecoration - }; - IR_LEAF_ISA(SPIRVNonUniformResourceDecoration) + FIDDLE(leafInst()) IRConstant* getSPIRVNonUniformResourceOperand() { return cast(getOperand(0)); } IntegerLiteralValue getSPIRVNonUniformResource() @@ -390,13 +303,10 @@ struct IRSPIRVNonUniformResourceDecoration : IRDecoration } }; +FIDDLE() struct IRRequireSPIRVVersionDecoration : IRDecoration { - enum - { - kOp = kIROp_RequireSPIRVVersionDecoration - }; - IR_LEAF_ISA(RequireGLSLVersionDecoration) + FIDDLE(leafInst()) IRConstant* getSPIRVVersionOperand() { return cast(getOperand(0)); } SemanticVersion getSPIRVVersion() @@ -405,25 +315,19 @@ struct IRRequireSPIRVVersionDecoration : IRDecoration } }; +FIDDLE() struct IRRequireCapabilityAtomDecoration : IRDecoration { - enum - { - kOp = kIROp_RequireCapabilityAtomDecoration - }; - IR_LEAF_ISA(RequireCapabilityAtomDecoration) + FIDDLE(leafInst()) IRConstant* getCapabilityAtomOperand() { return cast(getOperand(0)); } CapabilityName getAtom() { return (CapabilityName)getCapabilityAtomOperand()->value.intVal; } }; +FIDDLE() struct IRRequireCUDASMVersionDecoration : IRDecoration { - enum - { - kOp = kIROp_RequireCUDASMVersionDecoration - }; - IR_LEAF_ISA(RequireCUDASMVersionDecoration) + FIDDLE(leafInst()) IRConstant* getCUDASMVersionOperand() { return cast(getOperand(0)); } SemanticVersion getCUDASMVersion() @@ -432,111 +336,78 @@ struct IRRequireCUDASMVersionDecoration : IRDecoration } }; +FIDDLE() struct IRRequireGLSLExtensionDecoration : IRDecoration { - enum - { - kOp = kIROp_RequireGLSLExtensionDecoration - }; - IR_LEAF_ISA(RequireGLSLExtensionDecoration) + FIDDLE(leafInst()) IRStringLit* getExtensionNameOperand() { return cast(getOperand(0)); } UnownedStringSlice getExtensionName() { return getExtensionNameOperand()->getStringSlice(); } }; +FIDDLE() struct IRRequireWGSLExtensionDecoration : IRDecoration { - IR_LEAF_ISA(RequireWGSLExtensionDecoration) + FIDDLE(leafInst()) IRStringLit* getExtensionNameOperand() { return cast(getOperand(0)); } UnownedStringSlice getExtensionName() { return getExtensionNameOperand()->getStringSlice(); } }; +FIDDLE() struct IRMemoryQualifierSetDecoration : IRDecoration { - enum - { - kOp = kIROp_MemoryQualifierSetDecoration - }; - IR_LEAF_ISA(MemoryQualifierSetDecoration) + FIDDLE(leafInst()) IRIntegerValue getMemoryQualifierBit() { return cast(getOperand(0))->getValue(); } }; -IR_SIMPLE_DECORATION(HasExplicitHLSLBindingDecoration) -IR_SIMPLE_DECORATION(ReadNoneDecoration) -IR_SIMPLE_DECORATION(NoSideEffectDecoration) -IR_SIMPLE_DECORATION(EarlyDepthStencilDecoration) -IR_SIMPLE_DECORATION(PreciseDecoration) -IR_SIMPLE_DECORATION(PublicDecoration) -IR_SIMPLE_DECORATION(HLSLExportDecoration) -IR_SIMPLE_DECORATION(KeepAliveDecoration) -IR_SIMPLE_DECORATION(RequiresNVAPIDecoration) -IR_SIMPLE_DECORATION(NoInlineDecoration) -IR_SIMPLE_DECORATION(NoRefInlineDecoration) -IR_SIMPLE_DECORATION(DerivativeGroupQuadDecoration) -IR_SIMPLE_DECORATION(DerivativeGroupLinearDecoration) -IR_SIMPLE_DECORATION(AlwaysFoldIntoUseSiteDecoration) -IR_SIMPLE_DECORATION(StaticRequirementDecoration) -IR_SIMPLE_DECORATION(NonCopyableTypeDecoration) -IR_SIMPLE_DECORATION(HLSLMeshPayloadDecoration) -IR_SIMPLE_DECORATION(GlobalInputDecoration) -IR_SIMPLE_DECORATION(GlobalOutputDecoration) -IR_SIMPLE_DECORATION(DownstreamModuleExportDecoration) -IR_SIMPLE_DECORATION(DownstreamModuleImportDecoration) -IR_SIMPLE_DECORATION(MaximallyReconvergesDecoration) -IR_SIMPLE_DECORATION(QuadDerivativesDecoration) -IR_SIMPLE_DECORATION(RequireFullQuadsDecoration) -IR_SIMPLE_DECORATION(TempCallArgVarDecoration) - +FIDDLE() struct IRAvailableInDownstreamIRDecoration : IRDecoration { - IR_LEAF_ISA(AvailableInDownstreamIRDecoration) + FIDDLE(leafInst()) CodeGenTarget getTarget() { return static_cast(cast(getOperand(0))->getValue()); } }; +FIDDLE() struct IRGLSLLocationDecoration : IRDecoration { - IR_LEAF_ISA(GLSLLocationDecoration) + FIDDLE(leafInst()) IRIntLit* getLocation() { return cast(getOperand(0)); } }; +FIDDLE() struct IRGLSLOffsetDecoration : IRDecoration { - IR_LEAF_ISA(GLSLOffsetDecoration) + FIDDLE(leafInst()) IRIntLit* getOffset() { return cast(getOperand(0)); } }; +FIDDLE() struct IRVkStructOffsetDecoration : IRDecoration { - IR_LEAF_ISA(VkStructOffsetDecoration) + FIDDLE(leafInst()) IRIntLit* getOffset() { return cast(getOperand(0)); } }; +FIDDLE() struct IRNVAPIMagicDecoration : IRDecoration { - enum - { - kOp = kIROp_NVAPIMagicDecoration - }; - IR_LEAF_ISA(NVAPIMagicDecoration) + FIDDLE(leafInst()) IRStringLit* getNameOperand() { return cast(getOperand(0)); } UnownedStringSlice getName() { return getNameOperand()->getStringSlice(); } }; +FIDDLE() struct IRNVAPISlotDecoration : IRDecoration { - enum - { - kOp = kIROp_NVAPISlotDecoration - }; - IR_LEAF_ISA(NVAPISlotDecoration) + FIDDLE(leafInst()) IRStringLit* getRegisterNameOperand() { return cast(getOperand(0)); } UnownedStringSlice getRegisterName() { return getRegisterNameOperand()->getStringSlice(); } @@ -545,94 +416,70 @@ struct IRNVAPISlotDecoration : IRDecoration UnownedStringSlice getSpaceName() { return getSpaceNameOperand()->getStringSlice(); } }; +FIDDLE() struct IRMaxTessFactorDecoration : IRDecoration { - enum - { - kOp = kIROp_MaxTessFactorDecoration - }; - IR_LEAF_ISA(MaxTessFactorDecoration) + FIDDLE(leafInst()) IRFloatLit* getMaxTessFactor() { return cast(getOperand(0)); } }; +FIDDLE() struct IROutputControlPointsDecoration : IRDecoration { - enum - { - kOp = kIROp_OutputControlPointsDecoration - }; - IR_LEAF_ISA(OutputControlPointsDecoration) + FIDDLE(leafInst()) IRIntLit* getControlPointCount() { return cast(getOperand(0)); } }; // This is used for mesh shaders too +FIDDLE() struct IROutputTopologyDecoration : IRDecoration { - enum - { - kOp = kIROp_OutputTopologyDecoration - }; - IR_LEAF_ISA(OutputTopologyDecoration) + FIDDLE(leafInst()) IRStringLit* getTopology() { return cast(getOperand(0)); } IRIntegerValue getTopologyType() { return cast(getOperand(1))->getValue(); } }; +FIDDLE() struct IRPartitioningDecoration : IRDecoration { - enum - { - kOp = kIROp_PartitioningDecoration - }; - IR_LEAF_ISA(PartitioningDecoration) + FIDDLE(leafInst()) IRStringLit* getPartitioning() { return cast(getOperand(0)); } }; +FIDDLE() struct IRDomainDecoration : IRDecoration { - enum - { - kOp = kIROp_DomainDecoration - }; - IR_LEAF_ISA(DomainDecoration) + FIDDLE(leafInst()) IRStringLit* getDomain() { return cast(getOperand(0)); } }; +FIDDLE() struct IRMaxVertexCountDecoration : IRDecoration { - enum - { - kOp = kIROp_MaxVertexCountDecoration - }; - IR_LEAF_ISA(MaxVertexCountDecoration) + FIDDLE(leafInst()) IRIntLit* getCount() { return cast(getOperand(0)); } }; +FIDDLE() struct IRInstanceDecoration : IRDecoration { - enum - { - kOp = kIROp_InstanceDecoration - }; - IR_LEAF_ISA(InstanceDecoration) + FIDDLE(leafInst()) IRIntLit* getCount() { return cast(getOperand(0)); } }; struct IRGlobalParam; +FIDDLE() struct IRNumThreadsDecoration : IRDecoration { - enum - { - kOp = kIROp_NumThreadsDecoration - }; - IR_LEAF_ISA(NumThreadsDecoration) + FIDDLE(leafInst()) IRIntLit* getX() { return as(getOperand(0)); } IRIntLit* getY() { return as(getOperand(1)); } @@ -643,46 +490,33 @@ struct IRNumThreadsDecoration : IRDecoration IRGlobalParam* getZSpecConst() { return as(getOperand(2)); } }; +FIDDLE() struct IRFpDenormalPreserveDecoration : IRDecoration { - enum - { - kOp = kIROp_FpDenormalPreserveDecoration - }; - IR_LEAF_ISA(FpDenormalPreserveDecoration) - + FIDDLE(leafInst()) IRIntLit* getWidth() { return cast(getOperand(0)); } }; +FIDDLE() struct IRFpDenormalFlushToZeroDecoration : IRDecoration { - enum - { - kOp = kIROp_FpDenormalFlushToZeroDecoration - }; - IR_LEAF_ISA(FpDenormalFlushToZeroDecoration) + FIDDLE(leafInst()) IRIntLit* getWidth() { return cast(getOperand(0)); } }; +FIDDLE() struct IRWaveSizeDecoration : IRDecoration { - enum - { - kOp = kIROp_WaveSizeDecoration - }; - IR_LEAF_ISA(WaveSizeDecoration) + FIDDLE(leafInst()) IRIntLit* getNumLanes() { return cast(getOperand(0)); } }; +FIDDLE() struct IREntryPointDecoration : IRDecoration { - enum - { - kOp = kIROp_EntryPointDecoration - }; - IR_LEAF_ISA(EntryPointDecoration) + FIDDLE(leafInst()) IRIntLit* getProfileInst() { return cast(getOperand(0)); } Profile getProfile() { return Profile(Profile::RawVal(getIntVal(getProfileInst()))); } @@ -692,55 +526,38 @@ struct IREntryPointDecoration : IRDecoration void setName(IRStringLit* name) { setOperand(1, name); } }; -IR_SIMPLE_DECORATION(CudaHostDecoration) -IR_SIMPLE_DECORATION(CudaKernelDecoration) - +FIDDLE() struct IRCudaKernelForwardDerivativeDecoration : IRDecoration { - enum - { - kOp = kIROp_CudaKernelForwardDerivativeDecoration - }; - IR_LEAF_ISA(CudaKernelForwardDerivativeDecoration) + FIDDLE(leafInst()) IRInst* getForwardDerivativeFunc() { return getOperand(0); } }; +FIDDLE() struct IRCudaKernelBackwardDerivativeDecoration : IRDecoration { - enum - { - kOp = kIROp_CudaKernelBackwardDerivativeDecoration - }; - IR_LEAF_ISA(CudaKernelBackwardDerivativeDecoration) + FIDDLE(leafInst()) IRInst* getBackwardDerivativeFunc() { return getOperand(0); } }; +FIDDLE() struct IRGeometryInputPrimitiveTypeDecoration : IRDecoration { - IR_PARENT_ISA(GeometryInputPrimitiveTypeDecoration) + FIDDLE(baseInst()) }; -IR_SIMPLE_DECORATION(PointInputPrimitiveTypeDecoration) -IR_SIMPLE_DECORATION(LineInputPrimitiveTypeDecoration) -IR_SIMPLE_DECORATION(TriangleInputPrimitiveTypeDecoration) -IR_SIMPLE_DECORATION(LineAdjInputPrimitiveTypeDecoration) -IR_SIMPLE_DECORATION(TriangleAdjInputPrimitiveTypeDecoration) - /// This is a bit of a hack. The problem is that when GLSL legalization takes place /// the parameters from the entry point are globalized *and* potentially split /// So even if we did copy a suitable decoration onto the globalized parameters, /// it would potentially output multiple times without extra logic. /// Using this decoration we can copy the StreamOut type to the entry point, and then /// emit as part of entry point attribute emitting. +FIDDLE() struct IRStreamOutputTypeDecoration : IRDecoration { - enum - { - kOp = kIROp_StreamOutputTypeDecoration - }; - IR_LEAF_ISA(StreamOutputTypeDecoration) + FIDDLE(leafInst()) IRHLSLStreamOutputType* getStreamType() { return cast(getOperand(0)); } }; @@ -750,9 +567,10 @@ struct IRStreamOutputTypeDecoration : IRDecoration /// or will have a definition imported from another module. /// In either case, it requires a mangled name to use when /// matching imports and exports. +FIDDLE() struct IRLinkageDecoration : IRDecoration { - IR_PARENT_ISA(LinkageDecoration) + FIDDLE(baseInst()) IRStringLit* getMangledNameOperand() { return cast(getOperand(0)); } @@ -760,9 +578,10 @@ struct IRLinkageDecoration : IRDecoration }; // Mark a global variable as a target buitlin variable. +FIDDLE() struct IRTargetBuiltinVarDecoration : IRDecoration { - IR_LEAF_ISA(TargetBuiltinVarDecoration) + FIDDLE(leafInst()) IRIntLit* getBuiltinVarOperand() { return cast(getOperand(0)); } IRTargetBuiltinVarName getBuiltinVarName() @@ -771,62 +590,44 @@ struct IRTargetBuiltinVarDecoration : IRDecoration } }; +FIDDLE() struct IRUserExternDecoration : IRDecoration { - enum - { - kOp = kIROp_UserExternDecoration - }; - IR_LEAF_ISA(UserExternDecoration) + FIDDLE(leafInst()) }; +FIDDLE() struct IRImportDecoration : IRLinkageDecoration { - enum - { - kOp = kIROp_ImportDecoration - }; - IR_LEAF_ISA(ImportDecoration) + FIDDLE(leafInst()) }; +FIDDLE() struct IRExportDecoration : IRLinkageDecoration { - enum - { - kOp = kIROp_ExportDecoration - }; - IR_LEAF_ISA(ExportDecoration) + FIDDLE(leafInst()) }; +FIDDLE() struct IRExternCppDecoration : IRDecoration { - enum - { - kOp = kIROp_ExternCppDecoration - }; - IR_LEAF_ISA(ExternCppDecoration) + FIDDLE(leafInst()) IRStringLit* getNameOperand() { return cast(getOperand(0)); } UnownedStringSlice getName() { return getNameOperand()->getStringSlice(); } }; +FIDDLE() struct IRExternCDecoration : IRDecoration { - enum - { - kOp = kIROp_ExternCDecoration - }; - IR_LEAF_ISA(ExternCDecoration) + FIDDLE(leafInst()) }; +FIDDLE() struct IRDllImportDecoration : IRDecoration { - enum - { - kOp = kIROp_DllImportDecoration - }; - IR_LEAF_ISA(DllImportDecoration) + FIDDLE(leafInst()) IRStringLit* getLibraryNameOperand() { return cast(getOperand(0)); } UnownedStringSlice getLibraryName() { return getLibraryNameOperand()->getStringSlice(); } @@ -835,101 +636,75 @@ struct IRDllImportDecoration : IRDecoration UnownedStringSlice getFunctionName() { return getFunctionNameOperand()->getStringSlice(); } }; +FIDDLE() struct IRDllExportDecoration : IRDecoration { - enum - { - kOp = kIROp_DllExportDecoration - }; - IR_LEAF_ISA(DllExportDecoration) + FIDDLE(leafInst()) IRStringLit* getFunctionNameOperand() { return cast(getOperand(0)); } UnownedStringSlice getFunctionName() { return getFunctionNameOperand()->getStringSlice(); } }; +FIDDLE() struct IRTorchEntryPointDecoration : IRDecoration { - enum - { - kOp = kIROp_TorchEntryPointDecoration - }; - IR_LEAF_ISA(TorchEntryPointDecoration) + FIDDLE(leafInst()) IRStringLit* getFunctionNameOperand() { return cast(getOperand(0)); } UnownedStringSlice getFunctionName() { return getFunctionNameOperand()->getStringSlice(); } }; +FIDDLE() struct IRAutoPyBindCudaDecoration : IRDecoration { - enum - { - kOp = kIROp_AutoPyBindCudaDecoration - }; - IR_LEAF_ISA(AutoPyBindCudaDecoration) + FIDDLE(leafInst()) IRStringLit* getFunctionNameOperand() { return cast(getOperand(0)); } UnownedStringSlice getFunctionName() { return getFunctionNameOperand()->getStringSlice(); } }; -IR_SIMPLE_DECORATION(AutoPyBindExportInfoDecoration) - +FIDDLE() struct IRPyExportDecoration : IRDecoration { - enum - { - kOp = kIROp_PyExportDecoration - }; - IR_LEAF_ISA(PyExportDecoration) + FIDDLE(leafInst()) IRStringLit* getExportNameOperand() { return cast(getOperand(0)); } UnownedStringSlice getExportName() { return getExportNameOperand()->getStringSlice(); } }; +FIDDLE() struct IRKnownBuiltinDecoration : IRDecoration { - enum - { - kOp = kIROp_KnownBuiltinDecoration - }; - IR_LEAF_ISA(KnownBuiltinDecoration) + FIDDLE(leafInst()) IRStringLit* getNameOperand() { return cast(getOperand(0)); } UnownedStringSlice getName() { return getNameOperand()->getStringSlice(); } }; +FIDDLE() struct IREntryPointParamDecoration : IRDecoration { - IR_LEAF_ISA(EntryPointParamDecoration) + FIDDLE(leafInst()) /// Get the entry point that this parameter orignates from. IRFunc* getEntryPoint() { return cast(getOperand(0)); } }; +FIDDLE() struct IRFormatDecoration : IRDecoration { - enum - { - kOp = kIROp_FormatDecoration - }; - IR_LEAF_ISA(FormatDecoration) + FIDDLE(leafInst()) IRConstant* getFormatOperand() { return cast(getOperand(0)); } ImageFormat getFormat() { return ImageFormat(getFormatOperand()->value.intVal); } }; -IR_SIMPLE_DECORATION(UnsafeForceInlineEarlyDecoration) - -IR_SIMPLE_DECORATION(ForceInlineDecoration) - -IR_SIMPLE_DECORATION(ForceUnrollDecoration) - -IR_SIMPLE_DECORATION(PhysicalTypeDecoration) - +FIDDLE() struct IRSizeAndAlignmentDecoration : IRDecoration { - IR_LEAF_ISA(SizeAndAlignmentDecoration) + FIDDLE(leafInst()) IRTypeLayoutRuleName getLayoutName() { @@ -942,9 +717,10 @@ struct IRSizeAndAlignmentDecoration : IRDecoration IRIntegerValue getAlignment() { return getAlignmentOperand()->getValue(); } }; +FIDDLE() struct IROffsetDecoration : IRDecoration { - IR_LEAF_ISA(OffsetDecoration) + FIDDLE(leafInst()) IRTypeLayoutRuleName getLayoutName() { @@ -955,215 +731,158 @@ struct IROffsetDecoration : IRDecoration IRIntegerValue getOffset() { return getOffsetOperand()->getValue(); } }; -IR_SIMPLE_DECORATION(DynamicUniformDecoration) - +FIDDLE() struct IRBuiltinDecoration : IRDecoration { - enum - { - kOp = kIROp_BuiltinDecoration - }; - IR_LEAF_ISA(BuiltinDecoration) + FIDDLE(leafInst()) }; +FIDDLE() struct IRSequentialIDDecoration : IRDecoration { - enum - { - kOp = kIROp_SequentialIDDecoration - }; - IR_LEAF_ISA(SequentialIDDecoration) + FIDDLE(leafInst()) IRIntLit* getSequentialIDOperand() { return cast(getOperand(0)); } IRIntegerValue getSequentialID() { return getSequentialIDOperand()->getValue(); } }; +FIDDLE() struct IRResultWitnessDecoration : IRDecoration { - enum - { - kOp = kIROp_ResultWitnessDecoration - }; - IR_LEAF_ISA(ResultWitnessDecoration) + FIDDLE(leafInst()) IRInst* getWitness() { return getOperand(0); } }; +FIDDLE() struct IRDynamicDispatchWitnessDecoration : IRDecoration { - IR_LEAF_ISA(DynamicDispatchWitnessDecoration) + FIDDLE(leafInst()) }; +FIDDLE() struct IRAutoDiffOriginalValueDecoration : IRDecoration { - enum - { - kOp = kIROp_AutoDiffOriginalValueDecoration - }; - IR_LEAF_ISA(AutoDiffOriginalValueDecoration) + FIDDLE(leafInst()) IRInst* getOriginalValue() { return getOperand(0); } }; +FIDDLE() struct IRForwardDifferentiableDecoration : IRDecoration { - enum - { - kOp = kIROp_ForwardDifferentiableDecoration - }; - IR_LEAF_ISA(ForwardDifferentiableDecoration) + FIDDLE(leafInst()) }; +FIDDLE() struct IRForwardDerivativeDecoration : IRDecoration { - enum - { - kOp = kIROp_ForwardDerivativeDecoration - }; - IR_LEAF_ISA(ForwardDerivativeDecoration) + FIDDLE(leafInst()) IRInst* getForwardDerivativeFunc() { return getOperand(0); } }; +FIDDLE() struct IRPrimalSubstituteDecoration : IRDecoration { - enum - { - kOp = kIROp_PrimalSubstituteDecoration - }; - IR_LEAF_ISA(PrimalSubstituteDecoration) + FIDDLE(leafInst()) IRInst* getPrimalSubstituteFunc() { return getOperand(0); } }; +FIDDLE() struct IRBackwardDerivativeIntermediateTypeDecoration : IRDecoration { - enum - { - kOp = kIROp_BackwardDerivativeIntermediateTypeDecoration - }; - IR_LEAF_ISA(BackwardDerivativeIntermediateTypeDecoration) + FIDDLE(leafInst()) IRInst* getBackwardDerivativeIntermediateType() { return getOperand(0); } }; +FIDDLE() struct IRBackwardDerivativePrimalDecoration : IRDecoration { - enum - { - kOp = kIROp_BackwardDerivativePrimalDecoration - }; - IR_LEAF_ISA(BackwardDerivativePrimalDecoration) + FIDDLE(leafInst()) IRInst* getBackwardDerivativePrimalFunc() { return getOperand(0); } }; // Used to associate the restore context var to use in a call to splitted backward propgate // function. +FIDDLE() struct IRBackwardDerivativePrimalContextDecoration : IRDecoration { - enum - { - kOp = kIROp_BackwardDerivativePrimalContextDecoration - }; - IR_LEAF_ISA(BackwardDerivativePrimalContextDecoration) + FIDDLE(leafInst()) IRUse primalContextVar; IRInst* getBackwardDerivativePrimalContextVar() { return getOperand(0); } }; +FIDDLE() struct IRBackwardDerivativePrimalReturnDecoration : IRDecoration { - enum - { - kOp = kIROp_BackwardDerivativePrimalReturnDecoration - }; - IR_LEAF_ISA(BackwardDerivativePrimalReturnDecoration) + FIDDLE(leafInst()) IRInst* getBackwardDerivativePrimalReturnValue() { return getOperand(0); } }; +FIDDLE() struct IRBackwardDerivativePropagateDecoration : IRDecoration { - enum - { - kOp = kIROp_BackwardDerivativePropagateDecoration - }; - IR_LEAF_ISA(BackwardDerivativePropagateDecoration) + FIDDLE(leafInst()) IRInst* getBackwardDerivativePropagateFunc() { return getOperand(0); } }; +FIDDLE() struct IRBackwardDerivativeDecoration : IRDecoration { - enum - { - kOp = kIROp_BackwardDerivativeDecoration - }; - IR_LEAF_ISA(BackwardDerivativeDecoration) + FIDDLE(leafInst()) IRInst* getBackwardDerivativeFunc() { return getOperand(0); } }; +FIDDLE() struct IRCheckpointHintDecoration : public IRDecoration { - IR_PARENT_ISA(CheckpointHintDecoration) + FIDDLE(baseInst()) }; +FIDDLE() struct IRPreferRecomputeDecoration : IRCheckpointHintDecoration { - enum - { - kOp = kIROp_PreferRecomputeDecoration - }; - IR_LEAF_ISA(PreferRecomputeDecoration) + FIDDLE(leafInst()) }; +FIDDLE() struct IRPreferCheckpointDecoration : IRCheckpointHintDecoration { - enum - { - kOp = kIROp_PreferCheckpointDecoration - }; - IR_LEAF_ISA(PreferCheckpointDecoration) + FIDDLE(leafInst()) }; +FIDDLE() struct IRCheckpointIntermediateDecoration : IRCheckpointHintDecoration { - enum - { - kOp = kIROp_CheckpointIntermediateDecoration - }; - IR_LEAF_ISA(CheckpointIntermediateDecoration) + FIDDLE(leafInst()) IRInst* getSourceFunction() { return getOperand(0); } }; +FIDDLE() struct IRLoopCounterDecoration : IRDecoration { - enum - { - kOp = kIROp_LoopCounterDecoration - }; - IR_LEAF_ISA(LoopCounterDecoration) + FIDDLE(leafInst()) }; +FIDDLE() struct IRLoopCounterUpdateDecoration : IRDecoration { - enum - { - kOp = kIROp_LoopCounterUpdateDecoration - }; - IR_LEAF_ISA(LoopCounterUpdateDecoration) + FIDDLE(leafInst()) }; +FIDDLE() struct IRLoopExitPrimalValueDecoration : IRDecoration { - enum - { - kOp = kIROp_LoopExitPrimalValueDecoration - }; - IR_LEAF_ISA(LoopExitPrimalValueDecoration) + FIDDLE(leafInst()) IRUse target; IRUse exitVal; @@ -1171,193 +890,143 @@ struct IRLoopExitPrimalValueDecoration : IRDecoration IRInst* getLoopExitValInst() { return getOperand(1); } }; +FIDDLE() struct IRAutodiffInstDecoration : IRDecoration { - IR_PARENT_ISA(AutodiffInstDecoration) + FIDDLE(baseInst()) }; +FIDDLE() struct IRDifferentialInstDecoration : IRAutodiffInstDecoration { - enum - { - kOp = kIROp_DifferentialInstDecoration - }; + FIDDLE(leafInst()) IRUse primalType; - IR_LEAF_ISA(DifferentialInstDecoration) IRType* getPrimalType() { return (IRType*)(getOperand(0)); } IRInst* getPrimalInst() { return getOperand(1); } IRInst* getWitness() { return getOperand(2); } }; +FIDDLE() struct IRPrimalInstDecoration : IRAutodiffInstDecoration { - enum - { - kOp = kIROp_PrimalInstDecoration - }; - - IR_LEAF_ISA(PrimalInstDecoration) + FIDDLE(leafInst()) }; +FIDDLE() struct IRMixedDifferentialInstDecoration : IRAutodiffInstDecoration { - enum - { - kOp = kIROp_MixedDifferentialInstDecoration - }; + FIDDLE(leafInst()) IRUse pairType; - IR_LEAF_ISA(MixedDifferentialInstDecoration) IRType* getPairType() { return (IRType*)(getOperand(0)); } }; +FIDDLE() struct IRRecomputeBlockDecoration : IRAutodiffInstDecoration { - enum - { - kOp = kIROp_RecomputeBlockDecoration - }; - - IR_LEAF_ISA(RecomputeBlockDecoration) + FIDDLE(leafInst()) }; +FIDDLE() struct IRPrimalValueStructKeyDecoration : IRDecoration { - enum - { - kOp = kIROp_PrimalValueStructKeyDecoration - }; + FIDDLE(leafInst()) - IR_LEAF_ISA(PrimalValueStructKeyDecoration) IRStructKey* getStructKey() { return as(getOperand(0)); } }; +FIDDLE() struct IRPrimalElementTypeDecoration : IRDecoration { - enum - { - kOp = kIROp_PrimalElementTypeDecoration - }; + FIDDLE(leafInst()) - IR_LEAF_ISA(PrimalElementTypeDecoration) IRInst* getPrimalElementType() { return getOperand(0); } }; +FIDDLE() struct IRIntermediateContextFieldDifferentialTypeDecoration : IRDecoration { - enum - { - kOp = kIROp_IntermediateContextFieldDifferentialTypeDecoration - }; + FIDDLE(leafInst()) - IR_LEAF_ISA(IntermediateContextFieldDifferentialTypeDecoration) IRInst* getDifferentialWitness() { return getOperand(0); } }; +FIDDLE() struct IRBackwardDifferentiableDecoration : IRDecoration { - enum - { - kOp = kIROp_BackwardDifferentiableDecoration - }; - IR_LEAF_ISA(BackwardDifferentiableDecoration) + FIDDLE(leafInst()) }; +FIDDLE() struct IRUserDefinedBackwardDerivativeDecoration : IRDecoration { - enum - { - kOp = kIROp_UserDefinedBackwardDerivativeDecoration - }; - IR_LEAF_ISA(UserDefinedBackwardDerivativeDecoration) + FIDDLE(leafInst()) IRInst* getBackwardDerivativeFunc() { return getOperand(0); } }; +FIDDLE() struct IRTreatAsDifferentiableDecoration : IRDecoration { - enum - { - kOp = kIROp_TreatAsDifferentiableDecoration - }; - IR_LEAF_ISA(TreatAsDifferentiableDecoration) + FIDDLE(leafInst()) }; // Mark a call as explicitly calling a differentiable function. +FIDDLE() struct IRDifferentiableCallDecoration : IRDecoration { - enum - { - kOp = kIROp_DifferentiableCallDecoration - }; - IR_LEAF_ISA(DifferentiableCallDecoration) + FIDDLE(leafInst()) }; // 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. // +FIDDLE() struct IROptimizableTypeDecoration : IRDecoration { - enum - { - kOp = kIROp_OptimizableTypeDecoration - }; - IR_LEAF_ISA(OptimizableTypeDecoration) + FIDDLE(leafInst()) }; // 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. // +FIDDLE() struct IRIgnoreSideEffectsDecoration : IRDecoration { - enum - { - kOp = kIROp_IgnoreSideEffectsDecoration - }; - IR_LEAF_ISA(IgnoreSideEffectsDecoration) + FIDDLE(leafInst()) }; // Treat a call to a non-differentiable function as a differentiable call. +FIDDLE() struct IRTreatCallAsDifferentiableDecoration : IRDecoration { - enum - { - kOp = kIROp_TreatCallAsDifferentiableDecoration - }; - IR_LEAF_ISA(TreatCallAsDifferentiableDecoration) + FIDDLE(leafInst()) }; +FIDDLE() struct IRDerivativeMemberDecoration : IRDecoration { - enum - { - kOp = kIROp_DerivativeMemberDecoration - }; - IR_LEAF_ISA(DerivativeMemberDecoration) + FIDDLE(leafInst()) IRInst* getDerivativeMemberStructKey() { return getOperand(0); } }; // An instruction that replaces the function symbol // with it's derivative function. +FIDDLE() struct IRForwardDifferentiate : IRInst { - enum - { - kOp = kIROp_ForwardDifferentiate - }; + FIDDLE(leafInst()) // The base function for the call. IRUse base; IRInst* getBaseFn() { return getOperand(0); } - - IR_LEAF_ISA(ForwardDifferentiate) }; // An instruction that replaces the function symbol @@ -1366,94 +1035,68 @@ struct IRForwardDifferentiate : IRInst // of backward derivative computation. It performs the primal // computations and returns the intermediates that will be used // by the actual backward derivative function. +FIDDLE() struct IRBackwardDifferentiatePrimal : IRInst { - enum - { - kOp = kIROp_BackwardDifferentiatePrimal - }; + FIDDLE(leafInst()) // The base function for the call. IRUse base; IRInst* getBaseFn() { return getOperand(0); } - - IR_LEAF_ISA(BackwardDifferentiatePrimal) }; // An instruction that replaces the function symbol with its backward derivative propagate function. // A backward derivative propagate function is the second pass of backward derivative computation. // It uses the intermediates computed in the bacward derivative primal function to perform the // actual backward derivative propagation. +FIDDLE() struct IRBackwardDifferentiatePropagate : IRInst { - enum - { - kOp = kIROp_BackwardDifferentiatePropagate - }; + FIDDLE(leafInst()) // The base function for the call. IRUse base; IRInst* getBaseFn() { return getOperand(0); } - - IR_LEAF_ISA(BackwardDifferentiatePropagate) }; // An instruction that replaces the function symbol with its backward derivative function. // A backward derivative function is a concept that combines both passes of backward derivative // computation. This inst should only be produced by lower-to-ir, and will be replaced with calls to // the primal function followed by the propagate function in the auto-diff pass. +FIDDLE() struct IRBackwardDifferentiate : IRInst { - enum - { - kOp = kIROp_BackwardDifferentiate - }; + FIDDLE(leafInst()) // The base function for the call. IRUse base; IRInst* getBaseFn() { return getOperand(0); } - - IR_LEAF_ISA(BackwardDifferentiate) }; +FIDDLE() struct IRIsDifferentialNull : IRInst { - enum - { - kOp = kIROp_IsDifferentialNull - }; + FIDDLE(leafInst()) IRInst* getBase() { return getOperand(0); } - - IR_LEAF_ISA(IsDifferentialNull) }; // Retrieves the primal substitution function for the given function. +FIDDLE() struct IRPrimalSubstitute : IRInst { - enum - { - kOp = kIROp_PrimalSubstitute - }; + FIDDLE(leafInst()) IRInst* getBaseFn() { return getOperand(0); } - - IR_LEAF_ISA(PrimalSubstitute) }; +FIDDLE() struct IRDifferentiableTypeAnnotation : IRInst { - enum - { - kOp = kIROp_DifferentiableTypeAnnotation - }; + FIDDLE(leafInst()) IRInst* getBaseType() { return getOperand(0); } IRInst* getWitness() { return getOperand(1); } - - IR_LEAF_ISA(DifferentiableTypeAnnotation) }; +FIDDLE() struct IRDispatchKernel : IRInst { - enum - { - kOp = kIROp_DispatchKernel - }; + FIDDLE(leafInst()) IRInst* getBaseFn() { return getOperand(0); } IRInst* getThreadGroupSize() { return getOperand(1); } IRInst* getDispatchSize() { return getOperand(2); } @@ -1463,38 +1106,36 @@ struct IRDispatchKernel : IRInst { return IROperandList(getOperands() + 3, getOperands() + getOperandCount()); } - - IR_LEAF_ISA(DispatchKernel) }; +FIDDLE() struct IRTorchTensorGetView : IRInst { - enum - { - kOp = kIROp_TorchTensorGetView - }; - IR_LEAF_ISA(TorchTensorGetView) + FIDDLE(leafInst()) }; // Dictionary item mapping a type with a corresponding // IDifferentiable witness table // +FIDDLE() struct IRDifferentiableTypeDictionaryItem : IRInst { - IR_LEAF_ISA(DifferentiableTypeDictionaryItem) + FIDDLE(leafInst()) IRInst* getConcreteType() { return getOperand(0); } IRInst* getWitness() { return getOperand(1); } }; +FIDDLE() struct IRDifferentiableTypeDictionaryDecoration : IRDecoration { - IR_LEAF_ISA(DifferentiableTypeDictionaryDecoration) + FIDDLE(leafInst()) }; -struct IRFloatingModeOverrideDecoration : IRDecoration +FIDDLE() +struct IRFloatingPointModeOverrideDecoration : IRDecoration { - IR_LEAF_ISA(FloatingPointModeOverrideDecoration) + FIDDLE(leafInst()) FloatingPointMode getFloatingPointMode() { @@ -1505,8 +1146,10 @@ struct IRFloatingModeOverrideDecoration : IRDecoration // An instruction that specializes another IR value // (representing a generic) to a particular set of generic arguments // (instructions representing types, witness tables, etc.) +FIDDLE() struct IRSpecialize : IRInst { + FIDDLE(leafInst()) // The "base" for the call is the generic to be specialized IRUse base; IRInst* getBase() { return getOperand(0); } @@ -1515,38 +1158,38 @@ struct IRSpecialize : IRInst UInt getArgCount() { return getOperandCount() - 1; } IRInst* getArg(UInt index) { return getOperand(index + 1); } IRUse* getArgOperand(Index i) { return getOperands() + 1 + i; } - - IR_LEAF_ISA(Specialize) }; // An instruction that looks up the implementation // of an interface operation identified by `requirementDeclRef` // in the witness table `witnessTable` which should // hold the conformance information for a specific type. +FIDDLE() struct IRLookupWitnessMethod : IRInst { + FIDDLE(leafInst()) IRUse witnessTable; IRUse requirementKey; IRInst* getWitnessTable() { return witnessTable.get(); } IRInst* getRequirementKey() { return requirementKey.get(); } - - IR_LEAF_ISA(LookupWitness) }; // Returns the sequential ID of an RTTI object. +FIDDLE() struct IRGetSequentialID : IRInst { - IR_LEAF_ISA(GetSequentialID) + FIDDLE(leafInst()) IRInst* getRTTIOperand() { return getOperand(0); } }; /// Allocates space from local stack. /// +FIDDLE() struct IRAlloca : IRInst { - IR_LEAF_ISA(Alloca) + FIDDLE(leafInst()) IRInst* getAllocSize() { return getOperand(0); } }; @@ -1555,32 +1198,36 @@ struct IRAlloca : IRInst /// on `value` can be emitted as local insts instead of global insts, as required by targets (e.g. /// spirv) that doesn't allow the dependent computation in the global scope. /// +FIDDLE() struct IRGlobalValueRef : IRInst { - IR_LEAF_ISA(GlobalValueRef) + FIDDLE(leafInst()) IRInst* getValue() { return getOperand(0); } }; /// Packs a value into an `AnyValue`. /// Return type is `IRAnyValueType`. +FIDDLE() struct IRPackAnyValue : IRInst { - IR_LEAF_ISA(PackAnyValue) + FIDDLE(leafInst()) IRInst* getValue() { return getOperand(0); } }; /// Unpacks a `AnyValue` value into a concrete type. /// Operand must have `IRAnyValueType`. +FIDDLE() struct IRUnpackAnyValue : IRInst { - IR_LEAF_ISA(UnpackAnyValue) + FIDDLE(leafInst()) IRInst* getValue() { return getOperand(0); } }; +FIDDLE() struct IRBitFieldAccessorDecoration : IRDecoration { - IR_LEAF_ISA(BitFieldAccessorDecoration); + FIDDLE(leafInst()) IRStructKey* getBackingMemberKey() { return cast(getOperand(0)); } IRIntegerValue getFieldWidth() { return as(getOperand(1))->getValue(); } IRIntegerValue getFieldOffset() { return as(getOperand(2))->getValue(); } @@ -1597,9 +1244,10 @@ struct IRBitFieldAccessorDecoration : IRDecoration /// case where some amount of "layout" information can't just come /// in via the `TypeLayout` part of things. /// +FIDDLE() struct IRSemanticDecoration : public IRDecoration { - IR_LEAF_ISA(SemanticDecoration) + FIDDLE(leafInst()) IRStringLit* getSemanticNameOperand() { return cast(getOperand(0)); } UnownedStringSlice getSemanticName() { return getSemanticNameOperand()->getStringSlice(); } @@ -1608,143 +1256,147 @@ struct IRSemanticDecoration : public IRDecoration int getSemanticIndex() { return int(getIntVal(getSemanticIndexOperand())); } }; -struct IRConstructorDecorartion : IRDecoration +FIDDLE() +struct IRConstructorDecoration : IRDecoration { - IR_LEAF_ISA(ConstructorDecoration) + FIDDLE(leafInst()) bool getSynthesizedStatus() { return cast(getOperand(0))->getValue(); } }; -IR_SIMPLE_DECORATION(MethodDecoration) - +FIDDLE() struct IRPackOffsetDecoration : IRDecoration { - enum - { - kOp = kIROp_PackOffsetDecoration - }; - IR_LEAF_ISA(PackOffsetDecoration) + FIDDLE(leafInst()) IRIntLit* getRegisterOffset() { return cast(getOperand(0)); } IRIntLit* getComponentOffset() { return cast(getOperand(1)); } }; +FIDDLE() struct IRUserTypeNameDecoration : IRDecoration { - enum - { - kOp = kIROp_UserTypeNameDecoration - }; - IR_LEAF_ISA(UserTypeNameDecoration) + FIDDLE(leafInst()) IRStringLit* getUserTypeName() { return cast(getOperand(0)); } }; +FIDDLE() struct IRCounterBufferDecoration : IRDecoration { - enum - { - kOp = kIROp_CounterBufferDecoration - }; - IR_LEAF_ISA(CounterBufferDecoration) + FIDDLE(leafInst()) IRInst* getCounterBuffer() { return getOperand(0); } }; +FIDDLE() struct IRStageAccessDecoration : public IRDecoration { - IR_PARENT_ISA(StageAccessDecoration) - + FIDDLE(baseInst()) Int getStageCount() { return (Int)getOperandCount(); } IRStringLit* getStageOperand(Int index) { return cast(getOperand(index)); } UnownedStringSlice getStageName(Int index) { return getStageOperand(index)->getStringSlice(); } }; +FIDDLE() struct IRStageReadAccessDecoration : public IRStageAccessDecoration { - IR_LEAF_ISA(StageReadAccessDecoration) + FIDDLE(leafInst()) }; +FIDDLE() struct IRStageWriteAccessDecoration : public IRStageAccessDecoration { - IR_LEAF_ISA(StageWriteAccessDecoration) + FIDDLE(leafInst()) }; - +FIDDLE() struct IRRayPayloadDecoration : public IRDecoration { - IR_LEAF_ISA(RayPayloadDecoration) + FIDDLE(leafInst()) }; // Mesh shader decorations +FIDDLE() struct IRMeshOutputDecoration : public IRDecoration { - IR_PARENT_ISA(MeshOutputDecoration) + FIDDLE(baseInst()) IRIntLit* getMaxSize() { return cast(getOperand(0)); } }; +FIDDLE() struct IRVerticesDecoration : public IRMeshOutputDecoration { - IR_LEAF_ISA(VerticesDecoration) + FIDDLE(leafInst()) }; +FIDDLE() struct IRIndicesDecoration : public IRMeshOutputDecoration { - IR_LEAF_ISA(IndicesDecoration) + FIDDLE(leafInst()) }; +FIDDLE() struct IRPrimitivesDecoration : public IRMeshOutputDecoration { - IR_LEAF_ISA(PrimitivesDecoration) + FIDDLE(leafInst()) }; +FIDDLE() struct IRGLSLPrimitivesRateDecoration : public IRDecoration { - IR_LEAF_ISA(GLSLPrimitivesRateDecoration) + FIDDLE(leafInst()) }; +FIDDLE() struct IRGLPositionOutputDecoration : public IRDecoration { - IR_LEAF_ISA(GLPositionOutputDecoration) + FIDDLE(leafInst()) }; +FIDDLE() struct IRGLPositionInputDecoration : public IRDecoration { - IR_LEAF_ISA(GLPositionInputDecoration) + FIDDLE(leafInst()) }; +FIDDLE() struct IRMeshOutputRef : public IRInst { - IR_LEAF_ISA(MeshOutputRef) + FIDDLE(leafInst()) IRInst* getBase() { return getOperand(0); } IRInst* getIndex() { return getOperand(1); } IRInst* getOutputType() { return cast(getFullType())->getValueType(); } }; +FIDDLE() struct IRMeshOutputSet : public IRInst { - IR_LEAF_ISA(MeshOutputSet) + FIDDLE(leafInst()) IRInst* getBase() { return getOperand(0); } IRInst* getIndex() { return getOperand(1); } IRInst* getElementValue() { return getOperand(2); } }; +FIDDLE() struct IRMetalSetVertex : public IRInst { - IR_LEAF_ISA(MetalSetVertex) + FIDDLE(leafInst()) IRInst* getIndex() { return getOperand(0); } IRInst* getElementValue() { return getOperand(1); } }; +FIDDLE() struct IRMetalSetPrimitive : public IRInst { - IR_LEAF_ISA(MetalSetPrimitive) + FIDDLE(leafInst()) IRInst* getIndex() { return getOperand(0); } IRInst* getElementValue() { return getOperand(1); } }; +FIDDLE() struct IRMetalSetIndices : public IRInst { - IR_LEAF_ISA(MetalSetIndices) + FIDDLE(leafInst()) IRInst* getIndex() { return getOperand(0); } IRInst* getElementValue() { return getOperand(1); } }; @@ -1765,15 +1417,17 @@ struct IRMetalSetIndices : public IRInst /// they can affect the conceptual value/identity of an instruction /// in cases where we deduplicate/hash instructions by value. /// +FIDDLE() struct IRAttr : public IRInst { - IR_PARENT_ISA(Attr); + FIDDLE(baseInst()) }; /// An attribute that specifies layout information for a single resource kind. +FIDDLE() struct IRLayoutResourceInfoAttr : public IRAttr { - IR_PARENT_ISA(LayoutResourceInfoAttr); + FIDDLE(baseInst()) IRIntLit* getResourceKindInst() { return cast(getOperand(0)); } LayoutResourceKind getResourceKind() @@ -1788,9 +1442,10 @@ struct IRLayoutResourceInfoAttr : public IRAttr /// `varOffset(kind, offset, space)`. The latter form is only /// used when `space` is non-zero. /// +FIDDLE() struct IRVarOffsetAttr : public IRLayoutResourceInfoAttr { - IR_LEAF_ISA(VarOffsetAttr); + FIDDLE(leafInst()) IRIntLit* getOffsetInst() { return cast(getOperand(1)); } UInt getOffset() { return UInt(getIntVal(getOffsetInst())); } @@ -1811,22 +1466,25 @@ struct IRVarOffsetAttr : public IRLayoutResourceInfoAttr }; /// An attribute that specifies the error type a function is throwing +FIDDLE() struct IRFuncThrowTypeAttr : IRAttr { - IR_LEAF_ISA(FuncThrowTypeAttr) + FIDDLE(leafInst()) IRType* getErrorType() { return (IRType*)getOperand(0); } }; +FIDDLE() struct IRNoDiffAttr : IRAttr { - IR_LEAF_ISA(NoDiffAttr) + FIDDLE(leafInst()) }; /// An attribute that specifies size information for a single resource kind. +FIDDLE() struct IRTypeSizeAttr : public IRLayoutResourceInfoAttr { - IR_LEAF_ISA(TypeSizeAttr); + FIDDLE(leafInst()) IRIntLit* getSizeInst() { return cast(getOperand(1)); } LayoutSize getSize() @@ -1842,9 +1500,10 @@ struct IRTypeSizeAttr : public IRLayoutResourceInfoAttr /// /// Layout instructions are effectively just meta-data constants. /// +FIDDLE() struct IRLayout : IRInst { - IR_PARENT_ISA(Layout) + FIDDLE(baseInst()) }; struct IRVarLayout; @@ -1856,9 +1515,10 @@ struct IRVarLayout; /// type slots were filled in. The layout of pending data may not /// be contiguous with the layout of the original type/variable. /// +FIDDLE() struct IRPendingLayoutAttr : IRAttr { - IR_LEAF_ISA(PendingLayoutAttr); + FIDDLE(leafInst()) IRLayout* getLayout() { return cast(getOperand(0)); } }; @@ -1873,9 +1533,10 @@ struct IRPendingLayoutAttr : IRAttr /// operands or attributes. For example, a type layout for a /// `struct` type will include offset information for its fields. /// +FIDDLE() struct IRTypeLayout : IRLayout { - IR_PARENT_ISA(TypeLayout); + FIDDLE(baseInst()) /// Find the attribute that stores offset information for `kind`. /// @@ -1953,14 +1614,14 @@ struct IRTypeLayout : IRLayout }; /// Type layout for parameter groups (constant buffers and parameter blocks) +FIDDLE() struct IRParameterGroupTypeLayout : IRTypeLayout { + FIDDLE(leafInst()) private: typedef IRTypeLayout Super; public: - IR_LEAF_ISA(ParameterGroupTypeLayout) - IRVarLayout* getContainerVarLayout() { return cast(getOperand(0)); } IRVarLayout* getElementVarLayout() { return cast(getOperand(1)); } @@ -2002,11 +1663,12 @@ struct IRParameterGroupTypeLayout : IRTypeLayout }; /// Specialized layout information for array types +FIDDLE() struct IRArrayTypeLayout : IRTypeLayout { + FIDDLE(leafInst()) typedef IRTypeLayout Super; - IR_LEAF_ISA(ArrayTypeLayout) IRTypeLayout* getElementTypeLayout() { return cast(getOperand(0)); } @@ -2028,11 +1690,12 @@ struct IRArrayTypeLayout : IRTypeLayout }; /// Specialized layout information for structured buffer types +FIDDLE() struct IRStructuredBufferTypeLayout : IRTypeLayout { + FIDDLE(leafInst()) typedef IRTypeLayout Super; - IR_LEAF_ISA(StructuredBufferTypeLayout) IRTypeLayout* getElementTypeLayout() { return cast(getOperand(0)); } @@ -2080,11 +1743,12 @@ infinite recursion in lookup. The work around for now is to observe that layout of a Ptr doesn't depend on what is being pointed to and as such we don't store the this in the pointer. */ +FIDDLE() struct IRPointerTypeLayout : IRTypeLayout { + FIDDLE(leafInst()) typedef IRTypeLayout Super; - IR_LEAF_ISA(PointerTypeLayout) struct Builder : Super::Builder { @@ -2102,11 +1766,12 @@ struct IRPointerTypeLayout : IRTypeLayout }; /// Specialized layout information for stream-output types +FIDDLE() struct IRStreamOutputTypeLayout : IRTypeLayout { + FIDDLE(leafInst()) typedef IRTypeLayout Super; - IR_LEAF_ISA(StreamOutputTypeLayout) IRTypeLayout* getElementTypeLayout() { return cast(getOperand(0)); } @@ -2128,11 +1793,12 @@ struct IRStreamOutputTypeLayout : IRTypeLayout }; /// Specialized layout information for matrix types +FIDDLE() struct IRMatrixTypeLayout : IRTypeLayout { + FIDDLE(leafInst()) typedef IRTypeLayout Super; - IR_LEAF_ISA(MatrixTypeLayout) MatrixLayoutMode getMode() { @@ -2154,9 +1820,10 @@ struct IRMatrixTypeLayout : IRTypeLayout }; /// Attribute that specifies the layout for one field of a structure type. +FIDDLE() struct IRStructFieldLayoutAttr : IRAttr { - IR_LEAF_ISA(StructFieldLayoutAttr) + FIDDLE(leafInst()) IRInst* getFieldKey() { return getOperand(0); } @@ -2164,9 +1831,10 @@ struct IRStructFieldLayoutAttr : IRAttr }; /// Specialized layout information for structure types. +FIDDLE() struct IRStructTypeLayout : IRTypeLayout { - IR_LEAF_ISA(StructTypeLayout) + FIDDLE(leafInst()) typedef IRTypeLayout Super; @@ -2215,17 +1883,19 @@ struct IRStructTypeLayout : IRTypeLayout }; /// Attribute that specifies the layout for one field of a structure type. +FIDDLE() struct IRTupleFieldLayoutAttr : IRAttr { - IR_LEAF_ISA(TupleFieldLayoutAttr) + FIDDLE(leafInst()) IRTypeLayout* getLayout() { return cast(getOperand(1)); } }; /// Specialized layout information for tuple types. +FIDDLE() struct IRTupleTypeLayout : IRTypeLayout { - IR_LEAF_ISA(TupleTypeLayout) + FIDDLE(leafInst()) typedef IRTypeLayout Super; @@ -2272,19 +1942,21 @@ struct IRTupleTypeLayout : IRTypeLayout }; /// Attribute that represents the layout for one case of a union type +FIDDLE() struct IRCaseTypeLayoutAttr : IRAttr { - IR_LEAF_ISA(CaseTypeLayoutAttr); + FIDDLE(leafInst()) IRTypeLayout* getTypeLayout() { return cast(getOperand(0)); } }; /// Type layout for an existential/interface type. +FIDDLE() struct IRExistentialTypeLayout : IRTypeLayout { + FIDDLE(leafInst()) typedef IRTypeLayout Super; - IR_LEAF_ISA(ExistentialTypeLayout) struct Builder : Super::Builder { @@ -2305,9 +1977,10 @@ struct IRExistentialTypeLayout : IRTypeLayout /// Layout information for an entry point +FIDDLE() struct IREntryPointLayout : IRLayout { - IR_LEAF_ISA(EntryPointLayout) + FIDDLE(leafInst()) /// Get the layout information for the entry point parameters. /// @@ -2332,18 +2005,20 @@ struct IREntryPointLayout : IRLayout IRStructTypeLayout* getScopeStructLayout(IREntryPointLayout* scopeLayout); /// Attribute that associates a variable layout with a known stage. +FIDDLE() struct IRStageAttr : IRAttr { - IR_LEAF_ISA(StageAttr); + FIDDLE(leafInst()) IRIntLit* getStageOperand() { return cast(getOperand(0)); } Stage getStage() { return Stage(getIntVal(getStageOperand())); } }; /// Base type for attributes that associate a variable layout with a semantic name and index. +FIDDLE() struct IRSemanticAttr : IRAttr { - IR_PARENT_ISA(SemanticAttr); + FIDDLE(baseInst()) IRStringLit* getNameOperand() { return cast(getOperand(0)); } UnownedStringSlice getName() { return getNameOperand()->getStringSlice(); } @@ -2353,21 +2028,24 @@ struct IRSemanticAttr : IRAttr }; /// Attribute that associates a variable with a system-value semantic name and index +FIDDLE() struct IRSystemValueSemanticAttr : IRSemanticAttr { - IR_LEAF_ISA(SystemValueSemanticAttr); + FIDDLE(leafInst()) }; /// Attribute that associates a variable with a user-defined semantic name and index +FIDDLE() struct IRUserSemanticAttr : IRSemanticAttr { - IR_LEAF_ISA(UserSemanticAttr); + FIDDLE(leafInst()) }; /// Layout infromation for a single parameter/field +FIDDLE() struct IRVarLayout : IRLayout { - IR_LEAF_ISA(VarLayout) + FIDDLE(leafInst()) /// Get the type layout information for this variable IRTypeLayout* getTypeLayout() { return cast(getOperand(0)); } @@ -2470,27 +2148,27 @@ bool isVaryingParameter(IRVarLayout* varLayout); /// * To attach an `IREntryPointLayout` to an `IRFunc` representing an entry point /// * To attach an `IRTaggedUnionTypeLayout` to an `IRTaggedUnionType` /// +FIDDLE() struct IRLayoutDecoration : IRDecoration { - enum - { - kOp = kIROp_LayoutDecoration - }; - IR_LEAF_ISA(LayoutDecoration) + FIDDLE(leafInst()) /// Get the layout that is being attached to the parent instruction IRLayout* getLayout() { return cast(getOperand(0)); } }; // +FIDDLE() struct IRAlignOf : IRInst { + FIDDLE(leafInst()) IRInst* getBaseOp() { return getOperand(0); } }; +FIDDLE() struct IRCall : IRInst { - IR_LEAF_ISA(Call) + FIDDLE(leafInst()) IRInst* getCallee() { return getOperand(0); } IRUse* getCalleeUse() { return getOperands(); } @@ -2504,40 +2182,45 @@ struct IRCall : IRInst void setArg(UInt index, IRInst* arg) { setOperand(index + 1, arg); } }; +FIDDLE() struct IRAlignedAttr : IRAttr { - IR_LEAF_ISA(AlignedAttr) + FIDDLE(leafInst()) IRInst* getAlignment() { return getOperand(0); } }; +FIDDLE() struct IRLoad : IRInst { + FIDDLE(leafInst()) IRUse ptr; - IR_LEAF_ISA(Load) IRInst* getPtr() { return ptr.get(); } }; +FIDDLE() struct IRAtomicOperation : IRInst { - IR_PARENT_ISA(AtomicOperation); + FIDDLE(baseInst()) IRInst* getPtr() { return getOperand(0); } }; +FIDDLE() struct IRAtomicLoad : IRAtomicOperation { + FIDDLE(leafInst()) IRUse ptr; - IR_LEAF_ISA(AtomicLoad) IRInst* getPtr() { return ptr.get(); } }; +FIDDLE() struct IRStore : IRInst { + FIDDLE(leafInst()) IRUse ptr; IRUse val; - IR_LEAF_ISA(Store) IRInst* getPtr() { return ptr.get(); } IRInst* getVal() { return val.get(); } @@ -2546,150 +2229,171 @@ struct IRStore : IRInst IRUse* getValUse() { return &val; } }; +FIDDLE() struct IRAtomicStore : IRAtomicOperation { + FIDDLE(leafInst()) IRUse ptr; IRUse val; - IR_LEAF_ISA(AtomicStore) IRInst* getPtr() { return ptr.get(); } IRInst* getVal() { return val.get(); } }; +FIDDLE() struct IRRWStructuredBufferStore : IRInst { - IR_LEAF_ISA(RWStructuredBufferStore) + FIDDLE(leafInst()) IRInst* getStructuredBuffer() { return getOperand(0); } IRInst* getIndex() { return getOperand(1); } IRInst* getVal() { return getOperand(2); } }; +FIDDLE() struct IRFieldExtract : IRInst { + FIDDLE(leafInst()) IRUse base; IRUse field; IRInst* getBase() { return base.get(); } IRInst* getField() { return field.get(); } - IR_LEAF_ISA(FieldExtract) }; +FIDDLE() struct IRFieldAddress : IRInst { + FIDDLE(leafInst()) IRUse base; IRUse field; IRInst* getBase() { return base.get(); } IRInst* getField() { return field.get(); } - IR_LEAF_ISA(FieldAddress) }; +FIDDLE() struct IRGetElement : IRInst { - IR_LEAF_ISA(GetElement); + FIDDLE(leafInst()) IRInst* getBase() { return getOperand(0); } IRInst* getIndex() { return getOperand(1); } }; +FIDDLE() struct IRGetElementPtr : IRInst { - IR_LEAF_ISA(GetElementPtr); + FIDDLE(leafInst()) IRInst* getBase() { return getOperand(0); } IRInst* getIndex() { return getOperand(1); } }; +FIDDLE() struct IRGetOffsetPtr : IRInst { - IR_LEAF_ISA(GetOffsetPtr); + FIDDLE(leafInst()) IRInst* getBase() { return getOperand(0); } IRInst* getOffset() { return getOperand(1); } }; +FIDDLE() struct IRRWStructuredBufferGetElementPtr : IRInst { - IR_LEAF_ISA(RWStructuredBufferGetElementPtr); + FIDDLE(leafInst()) IRInst* getBase() { return getOperand(0); } IRInst* getIndex() { return getOperand(1); } }; +FIDDLE() struct IRStructuredBufferAppend : IRInst { - IR_LEAF_ISA(StructuredBufferAppend); + FIDDLE(leafInst()) IRInst* getBuffer() { return getOperand(0); } IRInst* getElement() { return getOperand(1); } }; +FIDDLE() struct IRStructuredBufferConsume : IRInst { - IR_LEAF_ISA(StructuredBufferConsume); + FIDDLE(leafInst()) IRInst* getBuffer() { return getOperand(0); } }; +FIDDLE() struct IRStructuredBufferGetDimensions : IRInst { - IR_LEAF_ISA(StructuredBufferGetDimensions); + FIDDLE(leafInst()) IRInst* getBuffer() { return getOperand(0); } }; +FIDDLE() struct IRNonUniformResourceIndex : IRInst { - IR_LEAF_ISA(NonUniformResourceIndex); + FIDDLE(leafInst()) }; +FIDDLE() struct IRLoadReverseGradient : IRInst { - IR_LEAF_ISA(LoadReverseGradient) + FIDDLE(leafInst()) IRInst* getValue() { return getOperand(0); } }; +FIDDLE() struct IRReverseGradientDiffPairRef : IRInst { - IR_LEAF_ISA(ReverseGradientDiffPairRef) + FIDDLE(leafInst()) IRInst* getPrimal() { return getOperand(0); } IRInst* getDiff() { return getOperand(1); } }; +FIDDLE() struct IRPrimalParamRef : IRInst { - IR_LEAF_ISA(PrimalParamRef) + FIDDLE(leafInst()) IRInst* getReferencedParam() { return getOperand(0); } }; +FIDDLE() struct IRDiffParamRef : IRInst { - IR_LEAF_ISA(DiffParamRef) + FIDDLE(leafInst()) IRInst* getReferencedParam() { return getOperand(0); } }; +FIDDLE() struct IRGetNativePtr : IRInst { - IR_LEAF_ISA(GetNativePtr); + FIDDLE(leafInst()) IRInst* getElementType() { return getOperand(0); } }; +FIDDLE() struct IRGetManagedPtrWriteRef : IRInst { - IR_LEAF_ISA(GetManagedPtrWriteRef); + FIDDLE(leafInst()) IRInst* getPtrToManagedPtr() { return getOperand(0); } }; +FIDDLE() struct IRGetAddress : IRInst { - IR_LEAF_ISA(GetAddr); + FIDDLE(leafInst()) }; +FIDDLE() struct IRImageSubscript : IRInst { - IR_LEAF_ISA(ImageSubscript); + FIDDLE(leafInst()) IRInst* getImage() { return getOperand(0); } IRInst* getCoord() { return getOperand(1); } bool hasSampleCoord() { return getOperandCount() > 2 && getOperand(2) != nullptr; } IRInst* getSampleCoord() { return getOperand(2); } }; +FIDDLE() struct IRImageLoad : IRInst { - IR_LEAF_ISA(ImageLoad); + FIDDLE(leafInst()) IRInst* getImage() { return getOperand(0); } IRInst* getCoord() { return getOperand(1); } @@ -2703,9 +2407,10 @@ struct IRImageLoad : IRInst IRInst* getAuxCoord2() { return getOperand(3); } }; +FIDDLE() struct IRImageStore : IRInst { - IR_LEAF_ISA(ImageStore); + FIDDLE(leafInst()) IRInst* getImage() { return getOperand(0); } IRInst* getCoord() { return getOperand(1); } IRInst* getValue() { return getOperand(2); } @@ -2717,22 +2422,26 @@ struct IRImageStore : IRInst }; // Terminators +FIDDLE() struct IRReturn : IRTerminatorInst { - IR_LEAF_ISA(Return); + FIDDLE(leafInst()) IRInst* getVal() { return getOperand(0); } }; +FIDDLE() struct IRYield : IRTerminatorInst { - IR_LEAF_ISA(Yield); + FIDDLE(leafInst()) IRInst* getVal() { return getOperand(0); } }; +FIDDLE() struct IRDiscard : IRTerminatorInst { + FIDDLE(leafInst()) }; // Used for representing a distinct copy of an object. @@ -2744,16 +2453,18 @@ struct IRDiscard : IRTerminatorInst // we need to make distinct copies of the inst for its uses // within the loop body and outside of it. // +FIDDLE() struct IRCheckpointObject : IRInst { - IR_LEAF_ISA(CheckpointObject); + FIDDLE(leafInst()) IRInst* getVal() { return getOperand(0); } }; +FIDDLE() struct IRLoopExitValue : IRInst { - IR_LEAF_ISA(LoopExitValue); + FIDDLE(leafInst()) IRInst* getVal() { return getOperand(0); } }; @@ -2762,20 +2473,24 @@ struct IRLoopExitValue : IRInst // We can/should emit a dataflow error if we can ever determine // that a block ending in one of these can actually be // executed. +FIDDLE() struct IRUnreachable : IRTerminatorInst { - IR_PARENT_ISA(Unreachable); + FIDDLE(leafInst()) }; +FIDDLE() struct IRMissingReturn : IRUnreachable { - IR_LEAF_ISA(MissingReturn); + FIDDLE(leafInst()) }; struct IRBlock; +FIDDLE() struct IRUnconditionalBranch : IRTerminatorInst { + FIDDLE(baseInst()) IRUse block; IRBlock* getTargetBlock() { return (IRBlock*)block.get(); } @@ -2784,25 +2499,15 @@ struct IRUnconditionalBranch : IRTerminatorInst IRUse* getArgs(); IRInst* getArg(UInt index); void removeArgument(UInt index); - IR_PARENT_ISA(UnconditionalBranch); -}; - -// Special cases of unconditional branch, to handle -// structured control flow: -struct IRBreak : IRUnconditionalBranch -{ -}; -struct IRContinue : IRUnconditionalBranch -{ }; // The start of a loop is a special control-flow // instruction, that records relevant information // about the loop structure: +FIDDLE() struct IRLoop : IRUnconditionalBranch { - IR_LEAF_ISA(loop); - + FIDDLE(leafInst()) // The next block after the loop, which // is where we expect control flow to // re-converge, and also where a @@ -2817,9 +2522,10 @@ struct IRLoop : IRUnconditionalBranch IRBlock* getContinueBlock() { return (IRBlock*)continueBlock.get(); } }; +FIDDLE() struct IRConditionalBranch : IRTerminatorInst { - IR_PARENT_ISA(ConditionalBranch) + FIDDLE(baseInst()) IRUse condition; IRUse trueBlock; @@ -2836,17 +2542,20 @@ struct IRConditionalBranch : IRTerminatorInst // else { } // // +FIDDLE() struct IRIfElse : IRConditionalBranch { + FIDDLE(leafInst()) IRUse afterBlock; IRBlock* getAfterBlock() { return (IRBlock*)afterBlock.get(); } }; // A multi-way branch that represents a source-level `switch` +FIDDLE() struct IRSwitch : IRTerminatorInst { - IR_LEAF_ISA(Switch); + FIDDLE(leafInst()) IRUse condition; IRUse breakLabel; @@ -2865,25 +2574,28 @@ struct IRSwitch : IRTerminatorInst }; // A compile-time switch based on the current code generation target. +FIDDLE() struct IRTargetSwitch : IRTerminatorInst { - IR_LEAF_ISA(TargetSwitch) + FIDDLE(leafInst()) IRInst* getBreakBlock() { return getOperand(0); } UInt getCaseCount() { return (getOperandCount() - 1) / 2; } IRBlock* getCaseBlock(UInt index) { return (IRBlock*)getOperand(index * 2 + 2); } IRInst* getCaseValue(UInt index) { return getOperand(index * 2 + 1); } }; +FIDDLE() struct IRThrow : IRTerminatorInst { - IR_LEAF_ISA(Throw); + FIDDLE(leafInst()) IRInst* getValue() { return getOperand(0); } }; +FIDDLE() struct IRTryCall : IRTerminatorInst { - IR_LEAF_ISA(TryCall); + FIDDLE(leafInst()) IRBlock* getSuccessBlock() { return cast(getOperand(0)); } IRBlock* getFailureBlock() { return cast(getOperand(1)); } @@ -2893,19 +2605,20 @@ struct IRTryCall : IRTerminatorInst IRInst* getArg(UInt index) { return getOperand(index + 3); } }; +FIDDLE() struct IRDefer : IRTerminatorInst { - IR_LEAF_ISA(Defer); + FIDDLE(leafInst()) IRBlock* getDeferBlock() { return cast(getOperand(0)); } IRBlock* getMergeBlock() { return cast(getOperand(1)); } IRBlock* getScopeBlock() { return cast(getOperand(2)); } }; +FIDDLE() struct IRSwizzle : IRInst { - IR_LEAF_ISA(swizzle); - + FIDDLE(leafInst()) IRUse base; IRInst* getBase() { return base.get(); } @@ -2913,10 +2626,10 @@ struct IRSwizzle : IRInst IRInst* getElementIndex(UInt index) { return getOperand(index + 1); } }; +FIDDLE() struct IRSwizzleSet : IRInst { - IR_LEAF_ISA(swizzleSet); - + FIDDLE(leafInst()) IRUse base; IRUse source; @@ -2926,35 +2639,32 @@ struct IRSwizzleSet : IRInst IRInst* getElementIndex(UInt index) { return getOperand(index + 2); } }; +FIDDLE() struct IRSwizzledStore : IRInst { + FIDDLE(leafInst()) IRInst* getDest() { return getOperand(0); } IRInst* getSource() { return getOperand(1); } UInt getElementCount() { return getOperandCount() - 2; } IRInst* getElementIndex(UInt index) { return getOperand(index + 2); } - - IR_LEAF_ISA(SwizzledStore) }; +FIDDLE() struct IRPatchConstantFuncDecoration : IRDecoration { - enum - { - kOp = kIROp_PatchConstantFuncDecoration - }; - IR_LEAF_ISA(PatchConstantFuncDecoration) + FIDDLE(leafInst()) IRInst* getFunc() { return getOperand(0); } }; // An IR `var` instruction conceptually represents // a stack allocation of some memory. +FIDDLE() struct IRVar : IRInst { + FIDDLE(leafInst()) IRPtrType* getDataType() { return cast(IRInst::getDataType()); } - - static bool isaImpl(IROp op) { return op == kIROp_Var; } }; /// @brief A global variable. @@ -2963,9 +2673,10 @@ struct IRVar : IRInst /// If the variable has an initializer, then /// it is represented by the code in the basic /// blocks nested inside this value. +FIDDLE() struct IRGlobalVar : IRGlobalValueWithCode { - IR_LEAF_ISA(GlobalVar) + FIDDLE(leafInst()) IRPtrType* getDataType() { return cast(IRInst::getDataType()); } }; @@ -2982,9 +2693,10 @@ struct IRGlobalVar : IRGlobalValueWithCode /// immutable, and subject to various SSA simplifications that /// do not work for global variables. /// +FIDDLE() struct IRGlobalParam : IRInst { - IR_LEAF_ISA(GlobalParam) + FIDDLE(leafInst()) }; /// @brief A global constnat. @@ -2995,17 +2707,20 @@ struct IRGlobalParam : IRInst /// represents an "extern" constant that will be defined in another /// module, and which is thus expected to have linkage. /// +FIDDLE() struct IRGlobalConstant : IRInst { - IR_LEAF_ISA(GlobalConstant); + FIDDLE(leafInst()) /// Get the value of this global constant, or null if the value is not known. IRInst* getValue() { return getOperandCount() != 0 ? getOperand(0) : nullptr; } }; // An entry in a witness table (see below) +FIDDLE() struct IRWitnessTableEntry : IRInst { + FIDDLE(leafInst()) // The AST-level requirement IRUse requirementKey; @@ -3014,8 +2729,6 @@ struct IRWitnessTableEntry : IRInst IRInst* getRequirementKey() { return getOperand(0); } IRInst* getSatisfyingVal() { return getOperand(1); } - - IR_LEAF_ISA(WitnessTableEntry) }; // A witness table is a global value that stores @@ -3023,8 +2736,10 @@ struct IRWitnessTableEntry : IRInst // interface. It basically takes the form of a // map from the required members of the interface // to the IR values that satisfy those requirements. +FIDDLE() struct IRWitnessTable : IRInst { + FIDDLE(leafInst()) IRInstList getEntries() { return IRInstList(getChildren()); @@ -3036,8 +2751,6 @@ struct IRWitnessTable : IRInst } IRType* getConcreteType() { return (IRType*)getOperand(0); } - - IR_LEAF_ISA(WitnessTable) }; /// Represents an RTTI object. @@ -3045,9 +2758,10 @@ struct IRWitnessTable : IRInst /// this RTTI object provides info for. /// All type info are encapsualted as `IRRTTI*Decoration`s attached /// to the object. +FIDDLE() struct IRRTTIObject : IRInst { - IR_LEAF_ISA(RTTIObject) + FIDDLE(leafInst()) }; // An instruction that yields an undefined value. @@ -3055,114 +2769,132 @@ struct IRRTTIObject : IRInst // Note that we make this an instruction rather than a value, // so that we will be able to identify a variable that is // used when undefined. +FIDDLE() struct IRUndefined : IRInst { + FIDDLE(leafInst()) }; // Special inst for targets that support default initialization, // like the braces '= {}' in C/HLSL +FIDDLE() struct IRDefaultConstruct : IRInst { - IR_LEAF_ISA(DefaultConstruct) + FIDDLE(leafInst()) }; // A global-scope generic parameter (a type parameter, a // constraint parameter, etc.) +FIDDLE() struct IRGlobalGenericParam : IRInst { - IR_LEAF_ISA(GlobalGenericParam) + FIDDLE(leafInst()) }; // An instruction that binds a global generic parameter // to a particular value. +FIDDLE() struct IRBindGlobalGenericParam : IRInst { + FIDDLE(leafInst()) IRGlobalGenericParam* getParam() { return cast(getOperand(0)); } IRInst* getVal() { return getOperand(1); } - - IR_LEAF_ISA(BindGlobalGenericParam) }; +FIDDLE() struct IRExpand : IRInst { - IR_LEAF_ISA(Expand) + FIDDLE(leafInst()) UInt getCaptureCount() { return getOperandCount(); } IRInst* getCapture(UInt index) { return getOperand(index); } IRInstList getBlocks() { return IRInstList(getChildren()); } }; +FIDDLE() struct IREach : IRInst { - IR_LEAF_ISA(Each) + FIDDLE(leafInst()) IRInst* getElement() { return getOperand(0); } }; +FIDDLE() struct IRMakeArray : IRInst { - IR_LEAF_ISA(MakeArray) + FIDDLE(leafInst()) }; +FIDDLE() struct IRMakeArrayFromElement : IRInst { - IR_LEAF_ISA(MakeArrayFromElement) + FIDDLE(leafInst()) }; // An Instruction that creates a tuple value. +FIDDLE() struct IRMakeTuple : IRInst { - IR_LEAF_ISA(MakeTuple) + FIDDLE(leafInst()) }; +FIDDLE() struct IRMakeValuePack : IRInst { - IR_LEAF_ISA(MakeValuePack) + FIDDLE(leafInst()) }; +FIDDLE() struct IRMakeStruct : IRInst { - IR_LEAF_ISA(MakeStruct) + FIDDLE(leafInst()) }; +FIDDLE() struct IRMakeWitnessPack : IRInst { - IR_LEAF_ISA(MakeWitnessPack) + FIDDLE(leafInst()) }; +FIDDLE() struct IRGetTupleElement : IRInst { - IR_LEAF_ISA(GetTupleElement) + FIDDLE(leafInst()) IRInst* getTuple() { return getOperand(0); } IRInst* getElementIndex() { return getOperand(1); } }; +FIDDLE() struct IRGetTargetTupleElement : IRInst { - IR_LEAF_ISA(GetTargetTupleElement) + FIDDLE(leafInst()) IRInst* getTuple() { return getOperand(0); } IRInst* getElementIndex() { return getOperand(1); } }; +FIDDLE() struct IRMakeVector : IRInst { - IR_LEAF_ISA(MakeVector) + FIDDLE(leafInst()) }; +FIDDLE() struct IRMakeVectorFromScalar : IRInst { - IR_LEAF_ISA(MakeVectorFromScalar) + FIDDLE(leafInst()) }; +FIDDLE() struct IRMakeCoopVector : IRInst { - IR_LEAF_ISA(MakeCoopVector) + FIDDLE(leafInst()) }; +FIDDLE() struct IRCoopMatMapElementIFunc : IRInst { - IR_LEAF_ISA(CoopMatMapElementIFunc) + FIDDLE(leafInst()) IRInst* getCoopMat() { return getOperand(0); } IRInst* getTuple() { return getOperand(0); } IRFunc* getIFuncCall() { return as(getOperand(1)); } @@ -3175,70 +2907,84 @@ struct IRCoopMatMapElementIFunc : IRInst // An Instruction that creates a differential pair value from a // primal and differential. +FIDDLE() struct IRMakeDifferentialPairBase : IRInst { - IR_PARENT_ISA(MakeDifferentialPairBase) + FIDDLE(baseInst()) IRInst* getPrimalValue() { return getOperand(0); } IRInst* getDifferentialValue() { return getOperand(1); } }; +FIDDLE() struct IRMakeDifferentialPair : IRMakeDifferentialPairBase { - IR_LEAF_ISA(MakeDifferentialPair) + FIDDLE(leafInst()) }; +FIDDLE() struct IRMakeDifferentialPairUserCode : IRMakeDifferentialPairBase { - IR_LEAF_ISA(MakeDifferentialPairUserCode) + FIDDLE(leafInst()) }; +FIDDLE() struct IRMakeDifferentialPtrPair : IRMakeDifferentialPairBase { - IR_LEAF_ISA(MakeDifferentialPtrPair) + FIDDLE(leafInst()) }; +FIDDLE() struct IRDifferentialPairGetDifferentialBase : IRInst { - IR_PARENT_ISA(DifferentialPairGetDifferentialBase) + FIDDLE(baseInst()) IRInst* getBase() { return getOperand(0); } }; +FIDDLE() struct IRDifferentialPairGetDifferential : IRDifferentialPairGetDifferentialBase { - IR_LEAF_ISA(DifferentialPairGetDifferential) + FIDDLE(leafInst()) }; +FIDDLE() struct IRDifferentialPairGetDifferentialUserCode : IRDifferentialPairGetDifferentialBase { - IR_LEAF_ISA(DifferentialPairGetDifferentialUserCode) + FIDDLE(leafInst()) }; +FIDDLE() struct IRDifferentialPtrPairGetDifferential : IRDifferentialPairGetDifferentialBase { - IR_LEAF_ISA(DifferentialPtrPairGetDifferential) + FIDDLE(leafInst()) }; +FIDDLE() struct IRDifferentialPairGetPrimalBase : IRInst { - IR_PARENT_ISA(DifferentialPairGetPrimalBase) + FIDDLE(baseInst()) IRInst* getBase() { return getOperand(0); } }; +FIDDLE() struct IRDifferentialPairGetPrimal : IRDifferentialPairGetPrimalBase { - IR_LEAF_ISA(DifferentialPairGetPrimal) + FIDDLE(leafInst()) }; +FIDDLE() struct IRDifferentialPairGetPrimalUserCode : IRDifferentialPairGetPrimalBase { - IR_LEAF_ISA(DifferentialPairGetPrimalUserCode) + FIDDLE(leafInst()) }; +FIDDLE() struct IRDifferentialPtrPairGetPrimal : IRDifferentialPairGetPrimalBase { - IR_LEAF_ISA(DifferentialPtrPairGetPrimal) + FIDDLE(leafInst()) }; +FIDDLE() struct IRDetachDerivative : IRInst { - IR_LEAF_ISA(DetachDerivative) + FIDDLE(leafInst()) IRInst* getBase() { return getOperand(0); } }; +FIDDLE() struct IRUpdateElement : IRInst { - IR_LEAF_ISA(UpdateElement) + FIDDLE(leafInst()) IRInst* getOldValue() { return getOperand(0); } IRInst* getElementValue() { return getOperand(1); } @@ -3254,141 +3000,155 @@ struct IRUpdateElement : IRInst }; // Constructs an `Result` value from an error code. +FIDDLE() struct IRMakeResultError : IRInst { - IR_LEAF_ISA(MakeResultError) + FIDDLE(leafInst()) IRInst* getErrorValue() { return getOperand(0); } }; // Constructs an `Result` value from an valid value. +FIDDLE() struct IRMakeResultValue : IRInst { - IR_LEAF_ISA(MakeResultValue) + FIDDLE(leafInst()) IRInst* getValue() { return getOperand(0); } }; // Determines if a `Result` value represents an error. +FIDDLE() struct IRIsResultError : IRInst { - IR_LEAF_ISA(IsResultError) + FIDDLE(leafInst()) IRInst* getResultOperand() { return getOperand(0); } }; // Extract the value from a `Result`. +FIDDLE() struct IRGetResultValue : IRInst { - IR_LEAF_ISA(GetResultValue) + FIDDLE(leafInst()) IRInst* getResultOperand() { return getOperand(0); } }; // Extract the error code from a `Result`. +FIDDLE() struct IRGetResultError : IRInst { - IR_LEAF_ISA(GetResultError) + FIDDLE(leafInst()) IRInst* getResultOperand() { return getOperand(0); } }; +FIDDLE() struct IROptionalHasValue : IRInst { - IR_LEAF_ISA(OptionalHasValue) + FIDDLE(leafInst()) IRInst* getOptionalOperand() { return getOperand(0); } }; +FIDDLE() struct IRGetOptionalValue : IRInst { - IR_LEAF_ISA(GetOptionalValue) + FIDDLE(leafInst()) IRInst* getOptionalOperand() { return getOperand(0); } }; +FIDDLE() struct IRMakeOptionalValue : IRInst { - IR_LEAF_ISA(MakeOptionalValue) + FIDDLE(leafInst()) IRInst* getValue() { return getOperand(0); } }; +FIDDLE() struct IRMakeOptionalNone : IRInst { - IR_LEAF_ISA(MakeOptionalNone) + FIDDLE(leafInst()) IRInst* getDefaultValue() { return getOperand(0); } }; /// An instruction that packs a concrete value into an existential-type "box" +FIDDLE() struct IRMakeExistential : IRInst { + FIDDLE(leafInst()) IRInst* getWrappedValue() { return getOperand(0); } IRInst* getWitnessTable() { return getOperand(1); } - - IR_LEAF_ISA(MakeExistential) }; +FIDDLE() struct IRMakeExistentialWithRTTI : IRInst { + FIDDLE(leafInst()) IRInst* getWrappedValue() { return getOperand(0); } IRInst* getWitnessTable() { return getOperand(1); } IRInst* getRTTI() { return getOperand(2); } - - - IR_LEAF_ISA(MakeExistentialWithRTTI) }; +FIDDLE() struct IRCreateExistentialObject : IRInst { + FIDDLE(leafInst()) IRInst* getTypeID() { return getOperand(0); } IRInst* getValue() { return getOperand(1); } - - IR_LEAF_ISA(CreateExistentialObject) }; /// Generalizes `IRMakeExistential` by allowing a type with existential sub-fields to be boxed +FIDDLE() struct IRWrapExistential : IRInst { + FIDDLE(leafInst()) IRInst* getWrappedValue() { return getOperand(0); } UInt getSlotOperandCount() { return getOperandCount() - 1; } IRInst* getSlotOperand(UInt index) { return getOperand(index + 1); } IRUse* getSlotOperands() { return getOperands() + 1; } - - IR_LEAF_ISA(WrapExistential) }; +FIDDLE() struct IRGetValueFromBoundInterface : IRInst { - IR_LEAF_ISA(GetValueFromBoundInterface); + FIDDLE(leafInst()) }; +FIDDLE() struct IRExtractExistentialValue : IRInst { - IR_LEAF_ISA(ExtractExistentialValue); + FIDDLE(leafInst()) }; +FIDDLE() struct IRExtractExistentialType : IRInst { - IR_LEAF_ISA(ExtractExistentialType); + FIDDLE(leafInst()) }; +FIDDLE() struct IRExtractExistentialWitnessTable : IRInst { - IR_LEAF_ISA(ExtractExistentialWitnessTable); + FIDDLE(leafInst()) }; +FIDDLE() struct IRIsNullExistential : IRInst { - IR_LEAF_ISA(IsNullExistential); + FIDDLE(leafInst()) }; /* Base class for instructions that track liveness */ +FIDDLE() struct IRLiveRangeMarker : IRInst { - IR_PARENT_ISA(LiveRangeMarker) + FIDDLE(baseInst()) // TODO(JS): It might be useful to track how many bytes are live in the item referenced. // It's not entirely clear how that will work across different targets, or even what such a @@ -3405,14 +3165,16 @@ struct IRLiveRangeMarker : IRInst }; /// Identifies then the item references starts being live. +FIDDLE() struct IRLiveRangeStart : IRLiveRangeMarker { - IR_LEAF_ISA(LiveRangeStart); + FIDDLE(leafInst()) }; +FIDDLE() struct IRIsType : IRInst { - IR_LEAF_ISA(IsType); + FIDDLE(leafInst()) IRInst* getValue() { return getOperand(0); } IRInst* getValueWitness() { return getOperand(1); } @@ -3429,67 +3191,78 @@ struct IRIsType : IRInst /// the store will never be seen (by a load) and so can be ignored. /// /// In general there can be one or more 'ends' for every start. +FIDDLE() struct IRLiveRangeEnd : IRLiveRangeMarker { - IR_LEAF_ISA(LiveRangeEnd); + FIDDLE(leafInst()) }; /// An instruction that queries binding information about an opaque/resource value. /// +FIDDLE() struct IRBindingQuery : IRInst { - IR_PARENT_ISA(BindingQuery); + FIDDLE(baseInst()) IRInst* getOpaqueValue() { return getOperand(0); } }; +FIDDLE() struct IRGetRegisterIndex : IRBindingQuery { - IR_LEAF_ISA(GetRegisterIndex); + FIDDLE(leafInst()) }; +FIDDLE() struct IRGetRegisterSpace : IRBindingQuery { - IR_LEAF_ISA(GetRegisterSpace); + FIDDLE(leafInst()) }; +FIDDLE() struct IRIntCast : IRInst { - IR_LEAF_ISA(IntCast) + FIDDLE(leafInst()) }; +FIDDLE() struct IRFloatCast : IRInst { - IR_LEAF_ISA(FloatCast) + FIDDLE(leafInst()) }; +FIDDLE() struct IRCastIntToFloat : IRInst { - IR_LEAF_ISA(CastIntToFloat) + FIDDLE(leafInst()) }; +FIDDLE() struct IRCastFloatToInt : IRInst { - IR_LEAF_ISA(CastFloatToInt) + FIDDLE(leafInst()) }; +FIDDLE() struct IRDebugSource : IRInst { - IR_LEAF_ISA(DebugSource) + FIDDLE(leafInst()) IRInst* getFileName() { return getOperand(0); } IRInst* getSource() { return getOperand(1); } }; +FIDDLE() struct IRDebugBuildIdentifier : IRInst { - IR_LEAF_ISA(DebugBuildIdentifier) + FIDDLE(leafInst()) IRInst* getBuildIdentifier() { return getOperand(0); } IRInst* getFlags() { return getOperand(1); } }; +FIDDLE() struct IRDebugLine : IRInst { - IR_LEAF_ISA(DebugLine) + FIDDLE(leafInst()) IRInst* getSource() { return getOperand(0); } IRInst* getLineStart() { return getOperand(1); } IRInst* getLineEnd() { return getOperand(2); } @@ -3497,25 +3270,28 @@ struct IRDebugLine : IRInst IRInst* getColEnd() { return getOperand(4); } }; +FIDDLE() struct IRDebugVar : IRInst { - IR_LEAF_ISA(DebugVar) + FIDDLE(leafInst()) IRInst* getSource() { return getOperand(0); } IRInst* getLine() { return getOperand(1); } IRInst* getCol() { return getOperand(2); } IRInst* getArgIndex() { return getOperandCount() >= 4 ? getOperand(3) : nullptr; } }; +FIDDLE() struct IRDebugValue : IRInst { - IR_LEAF_ISA(DebugValue) + FIDDLE(leafInst()) IRInst* getDebugVar() { return getOperand(0); } IRInst* getValue() { return getOperand(1); } }; +FIDDLE() struct IRDebugInlinedAt : IRInst { - IR_LEAF_ISA(DebugInlinedAt) + FIDDLE(leafInst()) IRInst* getLine() { return getOperand(0); } IRInst* getCol() { return getOperand(1); } IRInst* getFile() { return getOperand(2); } @@ -3530,30 +3306,34 @@ struct IRDebugInlinedAt : IRInst bool isOuterInlinedPresent() { return operandCount == 5; } }; +FIDDLE() struct IRDebugScope : IRInst { - IR_LEAF_ISA(DebugScope) + FIDDLE(leafInst()) IRInst* getScope() { return getOperand(0); } IRInst* getInlinedAt() { return getOperand(1); } void setInlinedAt(IRInst* inlinedAt) { setOperand(1, inlinedAt); } }; +FIDDLE() struct IRDebugNoScope : IRInst { - IR_LEAF_ISA(DebugNoScope) + FIDDLE(leafInst()) IRInst* getScope() { return getOperand(0); } }; +FIDDLE() struct IRDebugInlinedVariable : IRInst { - IR_LEAF_ISA(DebugInlinedVariable) + FIDDLE(leafInst()) IRInst* getVariable() { return getOperand(0); } IRInst* getInlinedAt() { return getOperand(1); } }; +FIDDLE() struct IRDebugFunction : IRInst { - IR_LEAF_ISA(DebugFunction) + FIDDLE(leafInst()) IRInst* getName() { return getOperand(0); } IRInst* getLine() { return getOperand(1); } IRInst* getCol() { return getOperand(2); } @@ -3561,26 +3341,28 @@ struct IRDebugFunction : IRInst IRInst* getDebugType() { return getOperand(4); } }; +FIDDLE() struct IRDebugFuncDecoration : IRInst { - IR_LEAF_ISA(DebugFunctionDecoration) + FIDDLE(leafInst()) IRInst* getDebugFunc() { return getOperand(0); } }; +FIDDLE() struct IRDebugLocationDecoration : IRDecoration { + FIDDLE(leafInst()) IRInst* getSource() { return getOperand(0); } IRInst* getLine() { return getOperand(1); } IRInst* getCol() { return getOperand(2); } - - IR_LEAF_ISA(DebugLocationDecoration) }; struct IRSPIRVAsm; +FIDDLE() struct IRSPIRVAsmOperand : IRInst { - IR_PARENT_ISA(SPIRVAsmOperand); + FIDDLE(baseInst()) IRInst* getValue() { if (getOp() == kIROp_SPIRVAsmOperandResult) @@ -3595,14 +3377,16 @@ struct IRSPIRVAsmOperand : IRInst } }; +FIDDLE() struct IRSPIRVAsmOperandInst : IRSPIRVAsmOperand { - IR_LEAF_ISA(SPIRVAsmOperandInst); + FIDDLE(leafInst()) }; +FIDDLE() struct IRSPIRVAsmInst : IRInst { - IR_LEAF_ISA(SPIRVAsmInst); + FIDDLE(leafInst()) IRSPIRVAsmOperand* getOpcodeOperand() { @@ -3640,59 +3424,68 @@ struct IRSPIRVAsmInst : IRInst } }; +FIDDLE() struct IRSPIRVAsm : IRInst { - IR_LEAF_ISA(SPIRVAsm); + FIDDLE(leafInst()) IRFilteredInstList getInsts() { return IRFilteredInstList(getFirstChild(), getLastChild()); } }; +FIDDLE() struct IRGenericAsm : IRTerminatorInst { - IR_LEAF_ISA(GenericAsm) + FIDDLE(leafInst()) UnownedStringSlice getAsm() { return as(getOperand(0))->getStringSlice(); } }; +FIDDLE() struct IRRequirePrelude : IRInst { - IR_LEAF_ISA(RequirePrelude) + FIDDLE(leafInst()) UnownedStringSlice getPrelude() { return as(getOperand(0))->getStringSlice(); } }; +FIDDLE() struct IRRequireTargetExtension : IRInst { - IR_LEAF_ISA(RequireTargetExtension) + FIDDLE(leafInst()) UnownedStringSlice getExtensionName() { return as(getOperand(0))->getStringSlice(); } }; +FIDDLE() struct IRRequireComputeDerivative : IRInst { - IR_LEAF_ISA(RequireComputeDerivative) + FIDDLE(leafInst()) }; +FIDDLE() struct IRRequireMaximallyReconverges : IRInst { - IR_LEAF_ISA(RequireMaximallyReconverges) + FIDDLE(leafInst()) }; +FIDDLE() struct IRRequireQuadDerivatives : IRInst { - IR_LEAF_ISA(RequireQuadDerivatives) + FIDDLE(leafInst()) }; +FIDDLE() struct IRStaticAssert : IRInst { - IR_LEAF_ISA(StaticAssert) + FIDDLE(leafInst()) }; +FIDDLE() struct IREmbeddedDownstreamIR : IRInst { - IR_LEAF_ISA(EmbeddedDownstreamIR) + FIDDLE(leafInst()) CodeGenTarget getTarget() { return static_cast(cast(getOperand(0))->getValue()); @@ -3700,6 +3493,8 @@ struct IREmbeddedDownstreamIR : IRInst IRBlobLit* getBlob() { return cast(getOperand(1)); } }; +FIDDLE(allOtherInstStructs()) + struct IRBuilderSourceLocRAII; struct IRBuilder @@ -3895,7 +3690,10 @@ struct IRBuilder IRTypePack* getTypePack(UInt count, IRType* const* types); - IRExpandType* getExpandTypeOrVal(IRType* type, IRInst* pattern, ArrayView capture); + IRExpandTypeOrVal* getExpandTypeOrVal( + IRType* type, + IRInst* pattern, + ArrayView capture); IRResultType* getResultType(IRType* valueType, IRType* errorType); IROptionalType* getOptionalType(IRType* valueType); @@ -5165,7 +4963,7 @@ struct IRBuilder void addDebugFunctionDecoration(IRInst* value, IRInst* debugFunction) { - addDecoration(value, kIROp_DebugFunctionDecoration, debugFunction); + addDecoration(value, kIROp_DebugFuncDecoration, debugFunction); } void addUnsafeForceInlineDecoration(IRInst* value) @@ -5622,5 +5420,3 @@ inline IRTargetIntrinsicDecoration* findBestTargetIntrinsicDecoration( void addHoistableInst(IRBuilder* builder, IRInst* inst); } // namespace Slang - -#endif diff --git a/source/slang/slang-ir-insts.h.lua b/source/slang/slang-ir-insts.h.lua new file mode 100644 index 00000000000..ad084e99736 --- /dev/null +++ b/source/slang/slang-ir-insts.h.lua @@ -0,0 +1,2 @@ +-- so we can use leafInst and baseInst in both slang-ir.h and slang-ir-insts.h +return require("source/slang/slang-ir.h.lua") diff --git a/source/slang/slang-ir-insts.lua b/source/slang/slang-ir-insts.lua new file mode 100644 index 00000000000..44dbc1ade19 --- /dev/null +++ b/source/slang/slang-ir-insts.lua @@ -0,0 +1,2260 @@ +-- +-- This file contains the canonical definitions for the instions to the Slang IR. +-- Add new instructions here +-- +-- The instructions struct name, i.e. something like "IRVoidType" can be specified with struct_name, otherwise it will be a PascalCase version of the instruction key +-- +-- Flags, such as hoistable, global, parent, use_other are inherited from a parent abstract type +-- +-- min_operands specifies the number of required operands for an instruction, it defaults to 0 +-- +-- Instructions here will automatically be given a struct definition in slang-ir-insts.h if it is no handwritten +-- + +local insts = { + { nop = {} }, + { + 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 = { min_operands = 1, hoistable = true } }, + { + RawPointerTypeBase = { + hoistable = true, + { RawPointerType = {} }, + { RTTIPointerType = { min_operands = 1 } }, + { 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", min_operands = 2, hoistable = true } }, + { Mat = { struct_name = "MatrixType", min_operands = 4, hoistable = true } }, + { Conjunction = { struct_name = "ConjunctionType", hoistable = true } }, + { Attributed = { struct_name = "AttributedType", hoistable = true } }, + { Result = { struct_name = "ResultType", min_operands = 2, hoistable = true } }, + { Optional = { struct_name = "OptionalType", min_operands = 1, hoistable = true } }, + { Enum = { struct_name = "EnumType", min_operands = 1, 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", + min_operands = 1, + hoistable = true, + }, + }, + { TensorView = { struct_name = "TensorViewType", min_operands = 1, hoistable = true } }, + { TorchTensor = { struct_name = "TorchTensorType", hoistable = true } }, + { ArrayListVector = { struct_name = "ArrayListType", min_operands = 1, hoistable = true } }, + { Atomic = { struct_name = "AtomicType", min_operands = 1, 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", min_operands = 2, 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 } }, + { Ref = { struct_name = "RefType", min_operands = 1 } }, + { ConstRef = { struct_name = "ConstRefType", 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, + }, + }, + { + OutTypeBase = { + { Out = { struct_name = "OutType", min_operands = 1 } }, + { InOut = { struct_name = "InOutType", 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", + min_operands = 1, + hoistable = true, + }, + }, + { + NativePtr = { + -- A NativePtr type represents a native pointer to a managed resource. + struct_name = "NativePtrType", + min_operands = 1, + hoistable = true, + }, + }, + { + DescriptorHandle = { + -- A DescriptorHandle type represents a bindless handle to an opaue resource type. + struct_name = "DescriptorHandleType", + min_operands = 1, + 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 } }, + { SubpassInputType = { min_operands = 2, 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", min_operands = 5 } }, + { 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 = { min_operands = 2, hoistable = true } }, + { CoopMatrixType = { min_operands = 5, hoistable = true } }, + { + TensorAddressingTensorLayoutType = { min_operands = 2, 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", + min_operands = 1, + 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 } }, + -- IRConstant + { + Constant = { + { boolConst = { struct_name = "BoolLit" } }, + { + integer_constant = { struct_name = "IntLit" }, + }, + { float_constant = { struct_name = "FloatLit" } }, + { + ptr_constant = { struct_name = "PtrLit" }, + }, + { string_constant = { struct_name = "StringLit" } }, + { + blob_constant = { struct_name = "BlobLit" }, + }, + { void_constant = { struct_name = "VoidLit" } }, + }, + }, + { CapabilitySet = { hoistable = true, { capabilityConjunction = {} }, { capabilityDisjunction = {} } } }, + { undefined = {} }, + -- 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", min_operands = 2, 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 } }, + -- 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 = { + min_operands = 1, + }, + }, + { 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", + }, + }, + { 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", + }, + }, + { + 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 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 } }, + { 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 } }, + { + 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 = 2, 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, +-- +-- Returns the tree as well as the flattened tree in preorder +-- Annotates instructions with whether they are a leaf or not +-- Calculates flags from the parent flags +local function process(insts) + 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 + + -- 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, add it + if is_leaf(value) and value.min_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) + + return { + insts = insts, + } +end + +return process(insts) diff --git a/source/slang/slang-ir-legalize-empty-array.cpp b/source/slang/slang-ir-legalize-empty-array.cpp index 1f7d5978350..1e6798a2ebc 100644 --- a/source/slang/slang-ir-legalize-empty-array.cpp +++ b/source/slang/slang-ir-legalize-empty-array.cpp @@ -72,56 +72,56 @@ struct EmptyArrayLoweringContext { const auto base = gep->getBase(); return hasEmptyArrayPtrType(gep) || hasEmptyArrayPtrType(base) || - base->getOp() == kIROp_undefined + base->getOp() == kIROp_Undefined ? builder.emitUndefined(gep->getDataType()) : nullptr; }, [&](IRFieldAddress* gep) { const auto base = gep->getBase(); - return hasEmptyArrayPtrType(gep) || base->getOp() == kIROp_undefined + return hasEmptyArrayPtrType(gep) || base->getOp() == kIROp_Undefined ? builder.emitUndefined(gep->getDataType()) : nullptr; }, [&](IRLoad* load) { - return load->getOperand(0)->getOp() == kIROp_undefined + return load->getOperand(0)->getOp() == kIROp_Undefined ? builder.emitUndefined(load->getDataType()) : nullptr; }, [&](IRImageLoad* load) { - return load->getOperand(0)->getOp() == kIROp_undefined + return load->getOperand(0)->getOp() == kIROp_Undefined ? builder.emitUndefined(load->getDataType()) : nullptr; }, [&](IRStore* store) { - if (store->getPtr()->getOp() == kIROp_undefined) + if (store->getPtr()->getOp() == kIROp_Undefined) store->removeAndDeallocate(); return nullptr; }, [&](IRAtomicStore* store) { - if (store->getPtr()->getOp() == kIROp_undefined) + if (store->getPtr()->getOp() == kIROp_Undefined) store->removeAndDeallocate(); return nullptr; }, [&](IRImageStore* store) { - if (store->getImage()->getOp() == kIROp_undefined) + if (store->getImage()->getOp() == kIROp_Undefined) store->removeAndDeallocate(); return nullptr; }, [&](IRImageSubscript* subscript) { - return subscript->getImage()->getOp() == kIROp_undefined + return subscript->getImage()->getOp() == kIROp_Undefined ? builder.emitUndefined(subscript->getDataType()) : nullptr; }, [&](IRAtomicOperation* atomic) { - return atomic->getOperand(0)->getOp() == kIROp_undefined + return atomic->getOperand(0)->getOp() == kIROp_Undefined ? builder.emitUndefined(atomic->getDataType()) : nullptr; }, diff --git a/source/slang/slang-ir-legalize-global-values.cpp b/source/slang/slang-ir-legalize-global-values.cpp index 63dbed3bdc4..55676f2d12d 100644 --- a/source/slang/slang-ir-legalize-global-values.cpp +++ b/source/slang/slang-ir-legalize-global-values.cpp @@ -101,8 +101,8 @@ bool GlobalInstInliningContextGeneric::isInlinableGlobalInst(IRInst* inst) case kIROp_MakeMatrix: case kIROp_MakeMatrixFromScalar: case kIROp_MakeVectorFromScalar: - case kIROp_swizzle: - case kIROp_swizzleSet: + case kIROp_Swizzle: + case kIROp_SwizzleSet: case kIROp_MatrixReshape: case kIROp_MakeString: case kIROp_MakeResultError: @@ -218,7 +218,7 @@ IRInst* GlobalInstInliningContextGeneric::maybeInlineGlobalValue( case kIROp_Func: case kIROp_Specialize: case kIROp_Generic: - case kIROp_LookupWitness: + case kIROp_LookupWitnessMethod: return inst; } if (as(inst)) diff --git a/source/slang/slang-ir-legalize-types.cpp b/source/slang/slang-ir-legalize-types.cpp index 529770acc28..9cf8d7b5f49 100644 --- a/source/slang/slang-ir-legalize-types.cpp +++ b/source/slang/slang-ir-legalize-types.cpp @@ -2134,14 +2134,14 @@ static LegalVal legalizeInst( case kIROp_DefaultConstruct: result = legalizeDefaultConstruct(context, type); break; - case kIROp_unconditionalBranch: - case kIROp_loop: + case kIROp_UnconditionalBranch: + case kIROp_Loop: result = legalizeUnconditionalBranch(context, args, (IRUnconditionalBranch*)inst); break; case kIROp_Printf: result = legalizePrintf(context, args); break; - case kIROp_undefined: + case kIROp_Undefined: return legalizeUndefined(context, inst); case kIROp_GpuForeach: // This case should only happen when compiling for a target that does not support @@ -3965,7 +3965,7 @@ struct IRTypeLegalizationPass // would not be a valid location at which to // store their replacements. // - if (!inst->getParent() && inst->getOp() != kIROp_Module) + if (!inst->getParent() && inst->getOp() != kIROp_ModuleInst) return; // The main logic for legalizing an instruction is defined diff --git a/source/slang/slang-ir-link.cpp b/source/slang/slang-ir-link.cpp index a7b4c4560e6..8f48e83dc5a 100644 --- a/source/slang/slang-ir-link.cpp +++ b/source/slang/slang-ir-link.cpp @@ -141,7 +141,7 @@ void registerClonedValue(IRSpecContextBase* context, IRInst* clonedValue, IRInst switch (clonedValue->getOp()) { - case kIROp_LookupWitness: + case kIROp_LookupWitnessMethod: // If `originalVal` represents a witness table entry key, add the key // to witnessTableEntryWorkList. diff --git a/source/slang/slang-ir-liveness.cpp b/source/slang/slang-ir-liveness.cpp index 91721e5ea25..880c99c80ee 100644 --- a/source/slang/slang-ir-liveness.cpp +++ b/source/slang/slang-ir-liveness.cpp @@ -670,7 +670,7 @@ LivenessContext::BlockResult LivenessContext::_completeBlock( static IRLoop* _getLoopTerminator(IRBlock* block) { auto terminator = block->getTerminator(); - if (terminator->getOp() == kIROp_loop) + if (terminator->getOp() == kIROp_Loop) { return static_cast(terminator); } @@ -888,7 +888,7 @@ void LivenessContext::_findAliasesAndAccesses(IRInst* root) accessType = AccessType::Alias; break; } - case kIROp_GetAddr: + case kIROp_GetAddress: { IRGetAddress* getAddr = static_cast(cur); base = getAddr->getOperand(0); diff --git a/source/slang/slang-ir-lower-com-methods.cpp b/source/slang/slang-ir-lower-com-methods.cpp index 551cccd3b51..d51807aa115 100644 --- a/source/slang/slang-ir-lower-com-methods.cpp +++ b/source/slang/slang-ir-lower-com-methods.cpp @@ -32,7 +32,7 @@ struct ComMethodLoweringContext : public InstPassBase SLANG_ASSERT(callee); IRLookupWitnessMethod* innerMostCallee = callee; - while (innerMostCallee->getOperand(0)->getOp() == kIROp_LookupWitness) + while (innerMostCallee->getOperand(0)->getOp() == kIROp_LookupWitnessMethod) { innerMostCallee = as(innerMostCallee->getOperand(0)); } @@ -84,7 +84,7 @@ struct ComMethodLoweringContext : public InstPassBase auto funcValue = inst->getOperand(0); // Detect if this is a call into a COM interface method. - if (funcValue->getOp() == kIROp_LookupWitness) + if (funcValue->getOp() == kIROp_LookupWitnessMethod) { const auto operand0TypeOp = funcValue->getOperand(0)->getDataType(); if (auto tableType = as(operand0TypeOp)) diff --git a/source/slang/slang-ir-lower-defer.cpp b/source/slang/slang-ir-lower-defer.cpp index 4e1ec9a8bdc..d650f53ec85 100644 --- a/source/slang/slang-ir-lower-defer.cpp +++ b/source/slang/slang-ir-lower-defer.cpp @@ -187,11 +187,11 @@ struct DeferLoweringContext : InstPassBase switch (terminator->getOp()) { case kIROp_Return: - case kIROp_discard: + case kIROp_Discard: case kIROp_Throw: exits = true; break; - case kIROp_unconditionalBranch: + case kIROp_UnconditionalBranch: { auto targetBlock = as(terminator->getOperand(0)); if (!scopeBlocksSet.contains(targetBlock)) @@ -200,7 +200,7 @@ struct DeferLoweringContext : InstPassBase } } break; - case kIROp_conditionalBranch: + case kIROp_ConditionalBranch: { auto trueBlock = as(terminator->getOperand(1)); auto falseBlock = as(terminator->getOperand(2)); diff --git a/source/slang/slang-ir-lower-expand-type.cpp b/source/slang/slang-ir-lower-expand-type.cpp index 6bd79737b9b..dc7512fad13 100644 --- a/source/slang/slang-ir-lower-expand-type.cpp +++ b/source/slang/slang-ir-lower-expand-type.cpp @@ -32,7 +32,7 @@ IRInst* clonePatternValImpl( return result; } case kIROp_Specialize: - case kIROp_LookupWitness: + case kIROp_LookupWitnessMethod: case kIROp_ExtractExistentialType: case kIROp_ExtractExistentialWitnessTable: break; @@ -83,7 +83,7 @@ IRInst* clonePatternVal(IRCloneEnv& cloneEnv, IRBuilder* builder, IRInst* val, I // Translate a `IRExpandType` into an `IRExpand` where the `PatternType` is defined // inside the `IRExpand` body. // -IRInst* lowerExpandTypeImpl(IRExpandType* expandType) +IRInst* lowerExpandTypeImpl(IRExpandTypeOrVal* expandType) { // Turn `IRExpandType` into an `IRExpand` instruction. IRBuilder builder(expandType); @@ -159,7 +159,7 @@ void lowerExpandType(IRModule* module) auto inst = workList.getLast(); workList.removeLast(); - if (auto expandType = as(inst)) + if (auto expandType = as(inst)) { inst = lowerExpandTypeImpl(expandType); if (inst != expandType) diff --git a/source/slang/slang-ir-lower-generic-call.cpp b/source/slang/slang-ir-lower-generic-call.cpp index 41a78d00c42..e4fb5ac9814 100644 --- a/source/slang/slang-ir-lower-generic-call.cpp +++ b/source/slang/slang-ir-lower-generic-call.cpp @@ -269,7 +269,7 @@ struct GenericCallLoweringContext // modified in this pass. SLANG_UNEXPECTED("Nested generics specialization."); } - else if (loweredFunc->getOp() == kIROp_LookupWitness) + else if (loweredFunc->getOp() == kIROp_LookupWitnessMethod) { lowerCallToInterfaceMethod( callInst, diff --git a/source/slang/slang-ir-lower-generic-function.cpp b/source/slang/slang-ir-lower-generic-function.cpp index c003d612592..6c2eb61939d 100644 --- a/source/slang/slang-ir-lower-generic-function.cpp +++ b/source/slang/slang-ir-lower-generic-function.cpp @@ -97,7 +97,7 @@ struct GenericFunctionLoweringContext } break; case kIROp_Specialize: - case kIROp_LookupWitness: + case kIROp_LookupWitnessMethod: childrenToDemote.add(clonedChild); break; default: diff --git a/source/slang/slang-ir-lower-generics.cpp b/source/slang/slang-ir-lower-generics.cpp index b01abcbc555..be21a66ba74 100644 --- a/source/slang/slang-ir-lower-generics.cpp +++ b/source/slang/slang-ir-lower-generics.cpp @@ -43,7 +43,7 @@ void specializeRTTIObjectReferences(SharedGenericsLoweringContext* sharedContext for (auto use = rtti.value->firstUse; use; use = nextUse) { nextUse = use->nextUse; - if (use->getUser()->getOp() == kIROp_GetAddr) + if (use->getUser()->getOp() == kIROp_GetAddress) { use->getUser()->replaceUsesWith(idOperand); } diff --git a/source/slang/slang-ir-lower-tuple-types.cpp b/source/slang/slang-ir-lower-tuple-types.cpp index 066895b78c0..da8568a0174 100644 --- a/source/slang/slang-ir-lower-tuple-types.cpp +++ b/source/slang/slang-ir-lower-tuple-types.cpp @@ -358,10 +358,10 @@ struct TupleLoweringContext case kIROp_GetElementPtr: processGetElementPtr((IRGetElementPtr*)inst); break; - case kIROp_swizzle: + case kIROp_Swizzle: processSwizzle((IRSwizzle*)inst); break; - case kIROp_swizzleSet: + case kIROp_SwizzleSet: processSwizzleSet((IRSwizzleSet*)inst); break; case kIROp_SwizzledStore: diff --git a/source/slang/slang-ir-peephole.cpp b/source/slang/slang-ir-peephole.cpp index cafe978f991..8d6685212ec 100644 --- a/source/slang/slang-ir-peephole.cpp +++ b/source/slang/slang-ir-peephole.cpp @@ -256,7 +256,7 @@ struct PeepholeContext : InstPassBase { if (as(inst)) { - if (auto fpModeDecor = inst->findDecoration()) + if (auto fpModeDecor = inst->findDecoration()) floatingPointMode = fpModeDecor->getFloatingPointMode(); } @@ -863,7 +863,7 @@ struct PeepholeContext : InstPassBase } } break; - case kIROp_LookupWitness: + case kIROp_LookupWitnessMethod: { if (inst->getOperand(0)->getOp() == kIROp_WitnessTable) { @@ -1041,7 +1041,7 @@ struct PeepholeContext : InstPassBase continue; SLANG_ASSERT(terminator->getArgCount() > paramIndex); auto arg = terminator->getArg(paramIndex); - if (arg->getOp() == kIROp_undefined) + if (arg->getOp() == kIROp_Undefined) continue; if (argValue == nullptr) argValue = arg; @@ -1090,7 +1090,7 @@ struct PeepholeContext : InstPassBase } } break; - case kIROp_swizzle: + case kIROp_Swizzle: { // If we see a swizzle(scalar), we replace it with makeVectorFromScalar. if (as(inst->getOperand(0)->getDataType())) @@ -1269,7 +1269,7 @@ struct PeepholeContext : InstPassBase case kIROp_Load: { // Load from undef is undef. - if (as(inst)->getPtr()->getOp() == kIROp_undefined) + if (as(inst)->getPtr()->getOp() == kIROp_Undefined) { IRBuilder builder(module); IRBuilderSourceLocRAII srcLocRAII(&builder, inst->sourceLoc); @@ -1285,7 +1285,7 @@ struct PeepholeContext : InstPassBase case kIROp_Store: { // Store undef is no-op. - if (as(inst)->getVal()->getOp() == kIROp_undefined) + if (as(inst)->getVal()->getOp() == kIROp_Undefined) { maybeRemoveOldInst(inst); changed = true; @@ -1295,7 +1295,7 @@ struct PeepholeContext : InstPassBase case kIROp_DebugValue: { // Update debug value with undef is no-op. - if (as(inst)->getValue()->getOp() == kIROp_undefined) + if (as(inst)->getValue()->getOp() == kIROp_Undefined) { maybeRemoveOldInst(inst); changed = true; @@ -1309,7 +1309,7 @@ struct PeepholeContext : InstPassBase bool isConcreteType(IRType* type) { - return type->parent->getOp() == kIROp_Module && !as(type); + return type->parent->getOp() == kIROp_ModuleInst && !as(type); } bool processFunc(IRInst* func) diff --git a/source/slang/slang-ir-propagate-func-properties.cpp b/source/slang/slang-ir-propagate-func-properties.cpp index 8c13a6455c6..0e5ee731a38 100644 --- a/source/slang/slang-ir-propagate-func-properties.cpp +++ b/source/slang/slang-ir-propagate-func-properties.cpp @@ -35,11 +35,11 @@ static bool isKnownOpCodeWithSideEffect(IROp op) { switch (op) { - case kIROp_ifElse: - case kIROp_unconditionalBranch: + case kIROp_IfElse: + case kIROp_UnconditionalBranch: case kIROp_Switch: case kIROp_Return: - case kIROp_loop: + case kIROp_Loop: case kIROp_Call: case kIROp_Param: case kIROp_Unreachable: diff --git a/source/slang/slang-ir-restructure.cpp b/source/slang/slang-ir-restructure.cpp index db3bb61f5ee..33d5aebea1b 100644 --- a/source/slang/slang-ir-restructure.cpp +++ b/source/slang/slang-ir-restructure.cpp @@ -246,7 +246,7 @@ static RefPtr generateRegionsForIRBlocks( switch (terminator->getOp()) { default: - case kIROp_conditionalBranch: + case kIROp_ConditionalBranch: // Note: we don't currently generate ordinary `conditionalBranch` instructions, // and instead only generate `ifElse` instructions, which include additional // information that can inform our control-flow restructuring pass. @@ -265,7 +265,7 @@ static RefPtr generateRegionsForIRBlocks( *resultLink = nullptr; return resultRegion; - case kIROp_ifElse: + case kIROp_IfElse: { // Here we have a two-way branch, so that we will construct a // region representing an `if` statement. @@ -305,7 +305,7 @@ static RefPtr generateRegionsForIRBlocks( } break; - case kIROp_loop: + case kIROp_Loop: { // The terminator in this case is the header for a structured loop. // @@ -424,7 +424,7 @@ static RefPtr generateRegionsForIRBlocks( } break; - case kIROp_unconditionalBranch: + case kIROp_UnconditionalBranch: { // Here we have an unconditional branch that was // not covered by one of our labels for non-local diff --git a/source/slang/slang-ir-simplify-cfg.cpp b/source/slang/slang-ir-simplify-cfg.cpp index 2310a5cce8f..425cb3b35a1 100644 --- a/source/slang/slang-ir-simplify-cfg.cpp +++ b/source/slang/slang-ir-simplify-cfg.cpp @@ -56,7 +56,7 @@ static IRInst* findBreakableRegionHeaderInst(IRDominatorTree* domTree, IRBlock* switch (terminator->getOp()) { case kIROp_Switch: - case kIROp_loop: + case kIROp_Loop: return terminator; } } @@ -138,7 +138,7 @@ bool isTrivialSingleIterationLoop( // switch (terminator->getOp()) { - case kIROp_loop: + case kIROp_Loop: if (isBlockInRegion(domTree, as(terminator), breakOriginBlock)) return false; break; @@ -351,7 +351,7 @@ static bool isTrivialIfElseBranch(IRIfElse* condBranch, IRBlock* branchBlock) if (auto br = as(branchBlock->getFirstOrdinaryInst())) { if (br->getTargetBlock() == condBranch->getAfterBlock() && - br->getOp() == kIROp_unconditionalBranch) + br->getOp() == kIROp_UnconditionalBranch) { return true; } @@ -436,7 +436,7 @@ static bool isTrivialSwitchBranch(IRSwitch* switchInst, IRBlock* branchBlock) if (auto br = as(branchBlock->getFirstOrdinaryInst())) { if (br->getTargetBlock() == switchInst->getBreakLabel() && - br->getOp() == kIROp_unconditionalBranch) + br->getOp() == kIROp_UnconditionalBranch) { return true; } @@ -564,7 +564,7 @@ static bool trySimplifySwitch(IRBuilder& builder, IRSwitch* switchInst) for (;;) { auto block = as(targetUse->get()); - if (block->getFirstInst()->getOp() != kIROp_unconditionalBranch) + if (block->getFirstInst()->getOp() != kIROp_UnconditionalBranch) return; auto branch = as(block->getFirstInst()); // We can't fuse the block if there are phi arguments. @@ -580,8 +580,8 @@ static bool trySimplifySwitch(IRBuilder& builder, IRSwitch* switchInst) continue; switch (use->getUser()->getOp()) { - case kIROp_loop: - case kIROp_ifElse: + case kIROp_Loop: + case kIROp_IfElse: case kIROp_Switch: // If the target block is used by a special control flow inst, // it is likely a merge block and we can't fuse it. @@ -690,7 +690,7 @@ static bool simplifyBoolPhiParams(IRBlock* block) Array preds; for (auto pred : block->getPredecessors()) { - if (pred->getTerminator()->getOp() != kIROp_unconditionalBranch) + if (pred->getTerminator()->getOp() != kIROp_UnconditionalBranch) return false; preds.add(pred); } @@ -914,7 +914,7 @@ static bool processFunc(IRGlobalValueWithCode* func, CFGSimplificationOptions op } // If `block` does not end with an unconditional branch, bail. - if (block->getTerminator()->getOp() != kIROp_unconditionalBranch) + if (block->getTerminator()->getOp() != kIROp_UnconditionalBranch) break; auto branch = as(block->getTerminator()); auto successor = branch->getTargetBlock(); diff --git a/source/slang/slang-ir-specialize-dispatch.cpp b/source/slang/slang-ir-specialize-dispatch.cpp index 0c8b248b073..b862b3dd087 100644 --- a/source/slang/slang-ir-specialize-dispatch.cpp +++ b/source/slang/slang-ir-specialize-dispatch.cpp @@ -34,7 +34,7 @@ IRFunc* specializeDispatchFunction( case kIROp_Call: callInst = cast(inst); break; - case kIROp_LookupWitness: + case kIROp_LookupWitnessMethod: lookupInst = cast(inst); break; case kIROp_Return: diff --git a/source/slang/slang-ir-specialize-dynamic-associatedtype-lookup.cpp b/source/slang/slang-ir-specialize-dynamic-associatedtype-lookup.cpp index 906bb888298..5bbc62bed5a 100644 --- a/source/slang/slang-ir-specialize-dynamic-associatedtype-lookup.cpp +++ b/source/slang/slang-ir-specialize-dynamic-associatedtype-lookup.cpp @@ -184,7 +184,7 @@ struct AssociatedTypeLookupSpecializationContext sharedContext, [this](IRInst* inst) { - if (inst->getOp() == kIROp_LookupWitness) + if (inst->getOp() == kIROp_LookupWitnessMethod) { processLookupInterfaceMethodInst(cast(inst)); } diff --git a/source/slang/slang-ir-specialize.cpp b/source/slang/slang-ir-specialize.cpp index 266c1aa9941..ed96b23c1e2 100644 --- a/source/slang/slang-ir-specialize.cpp +++ b/source/slang/slang-ir-specialize.cpp @@ -130,7 +130,7 @@ struct SpecializationContext switch (inst->getOp()) { case kIROp_GlobalGenericParam: - case kIROp_LookupWitness: + case kIROp_LookupWitnessMethod: case kIROp_GetTupleElement: return false; case kIROp_Specialize: @@ -597,7 +597,7 @@ struct SpecializationContext // return maybeSpecializeGeneric(cast(inst)); - case kIROp_LookupWitness: + case kIROp_LookupWitnessMethod: // The remaining case we need to consider here for generics // is when we have a `lookup_witness_method` instruction // that is being applied to a concrete witness table, @@ -941,7 +941,7 @@ struct SpecializationContext shouldSkip = true; break; } - if (item->getOperand(i)->getOp() == kIROp_undefined) + if (item->getOperand(i)->getOp() == kIROp_Undefined) { shouldSkip = true; break; @@ -1095,7 +1095,7 @@ struct SpecializationContext workList.removeLast(); workListSet.remove(inst); - if (!inst->getParent() && inst->getOp() != kIROp_Module) + if (!inst->getParent() && inst->getOp() != kIROp_ModuleInst) continue; // For each instruction we process, we want to perform diff --git a/source/slang/slang-ir-spirv-legalize.cpp b/source/slang/slang-ir-spirv-legalize.cpp index 31742cbde10..2a5701e3399 100644 --- a/source/slang/slang-ir-spirv-legalize.cpp +++ b/source/slang/slang-ir-spirv-legalize.cpp @@ -983,13 +983,13 @@ struct SPIRVLegalizationContext : public SourceEmitterBase builder.setInsertBefore(inst); if (!m_mapArrayValueToVar.tryGetValue(x, y)) { - if (x->getParent()->getOp() == kIROp_Module) + if (x->getParent()->getOp() == kIROp_ModuleInst) builder.setInsertBefore(inst); else setInsertAfterOrdinaryInst(&builder, x); y = builder.emitVar(x->getDataType(), AddressSpace::Function); builder.emitStore(y, x); - if (x->getParent()->getOp() != kIROp_Module) + if (x->getParent()->getOp() != kIROp_ModuleInst) m_mapArrayValueToVar.set(x, y); } builder.setInsertBefore(inst); @@ -1397,7 +1397,7 @@ struct SPIRVLegalizationContext : public SourceEmitterBase { maybeHoistConstructInstToGlobalScope(inst); - if (inst->getOp() == kIROp_MakeVector && inst->getParent()->getOp() == kIROp_Module && + if (inst->getOp() == kIROp_MakeVector && inst->getParent()->getOp() == kIROp_ModuleInst && inst->getOperandCount() != (UInt)getIntVal(as(inst->getDataType())->getElementCount())) { @@ -1772,10 +1772,10 @@ struct SPIRVLegalizationContext : public SourceEmitterBase case kIROp_NonUniformResourceIndex: processNonUniformResourceIndex(inst, NonUniformResourceIndexFloatMode::SPIRV); break; - case kIROp_loop: + case kIROp_Loop: processLoop(as(inst)); break; - case kIROp_ifElse: + case kIROp_IfElse: processIfElse(as(inst)); break; case kIROp_Switch: @@ -1809,7 +1809,7 @@ struct SPIRVLegalizationContext : public SourceEmitterBase case kIROp_PtrLit: processPtrLit(inst); break; - case kIROp_unconditionalBranch: + case kIROp_UnconditionalBranch: processBranch(inst); break; case kIROp_SPIRVAsm: @@ -2407,7 +2407,7 @@ void insertFragmentShaderInterlock(SPIRVEmitSharedContext* context, IRModule* mo if (auto inst = block->getTerminator()) { if (inst->getOp() == kIROp_Return || - !context->isSpirv16OrLater() && inst->getOp() == kIROp_discard) + !context->isSpirv16OrLater() && inst->getOp() == kIROp_Discard) { builder.setInsertBefore(inst); builder.emitEndFragmentShaderInterlock(); diff --git a/source/slang/slang-ir-ssa-register-allocate.cpp b/source/slang/slang-ir-ssa-register-allocate.cpp index e3bda0c1b53..dae834e7a34 100644 --- a/source/slang/slang-ir-ssa-register-allocate.cpp +++ b/source/slang/slang-ir-ssa-register-allocate.cpp @@ -123,7 +123,7 @@ struct RegisterAllocateContext IRUse* branchUse = nullptr; for (auto use = phiArg->firstUse; use; use = use->nextUse) { - if (use->getUser()->getOp() == kIROp_unconditionalBranch) + if (use->getUser()->getOp() == kIROp_UnconditionalBranch) { if (!branchUse) branchUse = use; diff --git a/source/slang/slang-ir-synthesize-active-mask.cpp b/source/slang/slang-ir-synthesize-active-mask.cpp index f899fee1a63..555cd4a5af5 100644 --- a/source/slang/slang-ir-synthesize-active-mask.cpp +++ b/source/slang/slang-ir-synthesize-active-mask.cpp @@ -1049,7 +1049,7 @@ struct SynthesizeActiveMaskForFunctionContext // that unstructured branches can split the active mask, // without any option to reconverge it. // - case kIROp_conditionalBranch: + case kIROp_ConditionalBranch: // // Finally, we also don't handle any control-flow op we might not // have introduced at the time this pass was created. @@ -1067,7 +1067,7 @@ struct SynthesizeActiveMaskForFunctionContext case kIROp_Unreachable: break; - case kIROp_unconditionalBranch: + case kIROp_UnconditionalBranch: { auto branch = cast(terminator); @@ -1131,7 +1131,7 @@ struct SynthesizeActiveMaskForFunctionContext } break; - case kIROp_ifElse: + case kIROp_IfElse: { // A structured `ifElse` instruction is a two-way branch on a // Boolean coniditon, along with a specific block representing @@ -1252,7 +1252,7 @@ struct SynthesizeActiveMaskForFunctionContext } break; - case kIROp_loop: + case kIROp_Loop: { // At the most basic level, a `loop` instruction is just an uncondtional // branch. What is stores above and beyond an `unconditionalBranch` diff --git a/source/slang/slang-ir-uniformity.cpp b/source/slang/slang-ir-uniformity.cpp index 312b64af3ab..64c916a4f0d 100644 --- a/source/slang/slang-ir-uniformity.cpp +++ b/source/slang/slang-ir-uniformity.cpp @@ -318,7 +318,7 @@ struct ValidateUniformityContext } break; } - case kIROp_ifElse: + case kIROp_IfElse: { auto ifElse = as(user); visitControlDependentBlock(ifElse->getTrueBlock()); diff --git a/source/slang/slang-ir-use-uninitialized-values.cpp b/source/slang/slang-ir-use-uninitialized-values.cpp index 71aae5923ec..daa667a0a6b 100644 --- a/source/slang/slang-ir-use-uninitialized-values.cpp +++ b/source/slang/slang-ir-use-uninitialized-values.cpp @@ -35,7 +35,7 @@ static bool isUninitializedValue(IRInst* inst) // Also consider var since it does not // automatically mean it will be initialized // (at least not as the user may have intended) - return (inst->m_op == kIROp_undefined) || (inst->m_op == kIROp_Var); + return (inst->m_op == kIROp_Undefined) || (inst->m_op == kIROp_Var); } static bool isUnmodifying(IRFunc* func) @@ -278,8 +278,8 @@ static InstructionUsageType getInstructionUsageType(IRInst* user, IRInst* inst) switch (user->getOp()) { - case kIROp_loop: - case kIROp_unconditionalBranch: + case kIROp_Loop: + case kIROp_UnconditionalBranch: // TODO: Ignore branches for now return None; @@ -520,7 +520,7 @@ static List checkFieldsFromExit( static void checkConstructor(IRFunc* func, ReachabilityContext& reachability, DiagnosticSink* sink) { - auto constructor = func->findDecoration(); + auto constructor = func->findDecoration(); if (!constructor) return; @@ -598,7 +598,7 @@ static void checkUninitializedValues(IRFunc* func, DiagnosticSink* sink) ReachabilityContext reachability(func); // Used for a further analysis and to skip usual return checks - auto constructor = func->findDecoration(); + auto constructor = func->findDecoration(); // Special checks for stages e.g. raytracing shader Stage stage = Stage::Unknown; diff --git a/source/slang/slang-ir-util.cpp b/source/slang/slang-ir-util.cpp index 497281114f6..687841d5efa 100644 --- a/source/slang/slang-ir-util.cpp +++ b/source/slang/slang-ir-util.cpp @@ -871,8 +871,8 @@ bool canInstHaveSideEffectAtAddress(IRGlobalValueWithCode* func, IRInst* inst, I } } break; - case kIROp_unconditionalBranch: - case kIROp_loop: + case kIROp_UnconditionalBranch: + case kIROp_Loop: { auto branch = as(inst); // If any pointer typed argument of the branch inst may overlap addr, return true. @@ -922,7 +922,7 @@ IRInst* getUndefInst(IRBuilder builder, IRModule* module) for (auto inst : module->getModuleInst()->getChildren()) { - if (inst->getOp() == kIROp_undefined && inst->getDataType() && + if (inst->getOp() == kIROp_Undefined && inst->getDataType() && inst->getDataType()->getOp() == kIROp_VoidType) { undefInst = inst; diff --git a/source/slang/slang-ir-validate.cpp b/source/slang/slang-ir-validate.cpp index b3d6504ab62..bf5d8ed5da1 100644 --- a/source/slang/slang-ir-validate.cpp +++ b/source/slang/slang-ir-validate.cpp @@ -220,7 +220,7 @@ void validateIRInstOperand(IRValidateContext* context, IRInst* inst, IRUse* oper } // We allow out-of-order def-use in global scope. - bool allInGlobalScope = inst->getParent() && inst->getParent()->getOp() == kIROp_Module; + bool allInGlobalScope = inst->getParent() && inst->getParent()->getOp() == kIROp_ModuleInst; if (allInGlobalScope) { for (UInt i = 0; i < inst->getOperandCount(); i++) @@ -230,7 +230,7 @@ void validateIRInstOperand(IRValidateContext* context, IRInst* inst, IRUse* oper continue; if (!op->getParent()) continue; - if (op->getParent()->getOp() != kIROp_Module) + if (op->getParent()->getOp() != kIROp_ModuleInst) { allInGlobalScope = false; break; @@ -292,10 +292,10 @@ void validateIRInstOperands(IRInst* inst) return; switch (inst->getOp()) { - case kIROp_loop: - case kIROp_ifElse: - case kIROp_unconditionalBranch: - case kIROp_conditionalBranch: + case kIROp_Loop: + case kIROp_IfElse: + case kIROp_UnconditionalBranch: + case kIROp_ConditionalBranch: case kIROp_Switch: return; default: @@ -325,12 +325,12 @@ void validateCodeBody(IRValidateContext* context, IRGlobalValueWithCode* code) validate(context, terminator, block, "block must have valid terminator inst."); switch (terminator->getOp()) { - case kIROp_conditionalBranch: + case kIROp_ConditionalBranch: validateBranchTarget(terminator, as(terminator)->getTrueBlock()); validateBranchTarget(terminator, as(terminator)->getFalseBlock()); break; - case kIROp_loop: - case kIROp_unconditionalBranch: + case kIROp_Loop: + case kIROp_UnconditionalBranch: validateBranchTarget( terminator, as(terminator)->getTargetBlock()); diff --git a/source/slang/slang-ir.cpp b/source/slang/slang-ir.cpp index 6e7e573b80b..dc25b14892a 100644 --- a/source/slang/slang-ir.cpp +++ b/source/slang/slang-ir.cpp @@ -94,63 +94,6 @@ IRInst* cloneGlobalValueWithLinkage( IRInst* originalVal, IRLinkageDecoration* originalLinkage); -struct IROpMapEntry -{ - IROp op; - IROpInfo info; -}; - -// TODO: We should ideally be speeding up the name->inst -// mapping by using a dictionary, or even by pre-computing -// a hash table to be stored as a `static const` array. -// -// NOTE! That this array is now constructed in such a way that looking up -// an entry from an op is fast, by keeping blocks of main, and pseudo ops in same order -// as the ops themselves. Care must be taken to keep this constraint. -static const IROpMapEntry kIROps[] = { - -// Main ops in order -#define INST(ID, MNEMONIC, ARG_COUNT, FLAGS) \ - {kIROp_##ID, \ - { \ - #MNEMONIC, \ - ARG_COUNT, \ - FLAGS, \ - }}, -#include "slang-ir-inst-defs.h" - - // Invalid op sentinel value comes after all the valid ones - {kIROp_Invalid, {"invalid", 0, 0}}, -}; - -IROpInfo getIROpInfo(IROp opIn) -{ - const int op = opIn & kIROpMask_OpMask; - if (op < kIROpCount) - { - // It's a main op - const auto& entry = kIROps[op]; - SLANG_ASSERT(entry.op == op); - return entry.info; - } - - // Don't know what this is - SLANG_ASSERT(!"Invalid op"); - SLANG_ASSERT(kIROps[kIROpCount].op == kIROp_Invalid); - return kIROps[kIROpCount].info; -} - -IROp findIROp(const UnownedStringSlice& name) -{ - for (auto ee : kIROps) - { - if (name == ee.info.name) - return ee.op; - } - - return IROp(kIROp_Invalid); -} - // @@ -584,15 +527,15 @@ static IRBlock::SuccessorList getSuccessors(IRInst* terminator) case kIROp_GenericAsm: break; - case kIROp_unconditionalBranch: - case kIROp_loop: + case kIROp_UnconditionalBranch: + case kIROp_Loop: // unconditonalBranch begin = operands + 0; end = begin + 1; break; - case kIROp_conditionalBranch: - case kIROp_ifElse: + case kIROp_ConditionalBranch: + case kIROp_IfElse: // conditionalBranch begin = operands + 1; end = begin + 2; @@ -759,10 +702,10 @@ UInt IRUnconditionalBranch::getArgCount() { switch (getOp()) { - case kIROp_unconditionalBranch: + case kIROp_UnconditionalBranch: return getOperandCount() - 1; - case kIROp_loop: + case kIROp_Loop: return getOperandCount() - 3; default: @@ -775,10 +718,10 @@ IRUse* IRUnconditionalBranch::getArgs() { switch (getOp()) { - case kIROp_unconditionalBranch: + case kIROp_UnconditionalBranch: return getOperands() + 1; - case kIROp_loop: + case kIROp_Loop: return getOperands() + 3; default: @@ -791,10 +734,10 @@ void IRUnconditionalBranch::removeArgument(UInt index) { switch (getOp()) { - case kIROp_unconditionalBranch: + case kIROp_UnconditionalBranch: removeOperand(1 + index); break; - case kIROp_loop: + case kIROp_Loop: removeOperand(3 + index); break; default: @@ -892,10 +835,10 @@ bool isTerminatorInst(IROp op) return false; case kIROp_Return: - case kIROp_unconditionalBranch: - case kIROp_conditionalBranch: - case kIROp_loop: - case kIROp_ifElse: + case kIROp_UnconditionalBranch: + case kIROp_ConditionalBranch: + case kIROp_Loop: + case kIROp_IfElse: case kIROp_Switch: case kIROp_Unreachable: case kIROp_MissingReturn: @@ -2899,7 +2842,7 @@ IRTypePack* IRBuilder::getTypePack(UInt count, IRType* const* types) return (IRTypePack*)getType(kIROp_TypePack, count, (IRInst* const*)types); } -IRExpandType* IRBuilder::getExpandTypeOrVal( +IRExpandTypeOrVal* IRBuilder::getExpandTypeOrVal( IRType* type, IRInst* pattern, ArrayView capture) @@ -2907,7 +2850,7 @@ IRExpandType* IRBuilder::getExpandTypeOrVal( ShortList args; args.add(pattern); args.addRange(capture); - return (IRExpandType*)emitIntrinsicInst( + return (IRExpandTypeOrVal*)emitIntrinsicInst( type, kIROp_ExpandTypeOrVal, args.getCount(), @@ -3350,7 +3293,7 @@ IRInst* IRBuilder::emitGetValueFromBoundInterface(IRType* type, IRInst* boundInt IRUndefined* IRBuilder::emitUndefined(IRType* type) { - auto inst = createInst(this, kIROp_undefined, type); + auto inst = createInst(this, kIROp_Undefined, type); addInst(inst); @@ -3836,7 +3779,7 @@ IRInst* IRBuilder::emitLookupInterfaceMethodInst( IRInst* args[] = {witnessTableVal, interfaceMethodVal}; - return createIntrinsicInst(type, kIROp_LookupWitness, 2, args); + return createIntrinsicInst(type, kIROp_LookupWitnessMethod, 2, args); } IRInst* IRBuilder::emitGetSequentialIDInst(IRInst* rttiObj) @@ -4443,7 +4386,7 @@ IRInst* IRBuilder::emitMakeString(IRInst* nativeStr) IRInst* IRBuilder::emitGetNativeString(IRInst* str) { - return emitIntrinsicInst(getNativeStringType(), kIROp_getNativeStr, 1, &str); + return emitIntrinsicInst(getNativeStringType(), kIROp_GetNativeStr, 1, &str); } IRInst* IRBuilder::emitGetElement(IRType* type, IRInst* arrayLikeType, IRIntegerValue element) @@ -4754,7 +4697,7 @@ RefPtr IRModule::create(Session* session) { RefPtr module = new IRModule(session); - auto moduleInst = module->_allocateInst(kIROp_Module, 0); + auto moduleInst = module->_allocateInst(kIROp_ModuleInst, 0); module->m_moduleInst = moduleInst; moduleInst->module = module; @@ -5594,7 +5537,7 @@ IRInst* IRBuilder::emitGetOffsetPtr(IRInst* base, IRInst* offset) IRInst* IRBuilder::emitGetAddress(IRType* type, IRInst* value) { - auto inst = createInst(this, kIROp_GetAddr, type, value); + auto inst = createInst(this, kIROp_GetAddress, type, value); addInst(inst); return inst; @@ -5608,7 +5551,7 @@ IRInst* IRBuilder::emitSwizzle( { auto inst = createInstWithTrailingArgs( this, - kIROp_swizzle, + kIROp_Swizzle, type, base, elementCount, @@ -5728,7 +5671,7 @@ IRInst* IRBuilder::emitSwizzleSet( auto inst = createInstWithTrailingArgs( this, - kIROp_swizzleSet, + kIROp_SwizzleSet, type, fixedArgCount, fixedArgs, @@ -5884,7 +5827,7 @@ IRInst* IRBuilder::emitMissingReturn() IRInst* IRBuilder::emitDiscard() { - auto inst = createInst(this, kIROp_discard, nullptr); + auto inst = createInst(this, kIROp_Discard, nullptr); addInst(inst); return inst; } @@ -5906,7 +5849,7 @@ IRInst* IRBuilder::emitLoopExitValue(IRInst* value) IRInst* IRBuilder::emitBranch(IRBlock* pBlock) { - auto inst = createInst(this, kIROp_unconditionalBranch, nullptr, pBlock); + auto inst = createInst(this, kIROp_UnconditionalBranch, nullptr, pBlock); addInst(inst); return inst; } @@ -5919,7 +5862,7 @@ IRInst* IRBuilder::emitBranch(IRBlock* block, Int argCount, IRInst* const* args) argList.add(args[i]); auto inst = createInst( this, - kIROp_unconditionalBranch, + kIROp_UnconditionalBranch, nullptr, argList.getCount(), argList.getBuffer()); @@ -5942,7 +5885,7 @@ IRInst* IRBuilder::emitLoop(IRBlock* target, IRBlock* breakBlock, IRBlock* conti IRInst* args[] = {target, breakBlock, continueBlock}; UInt argCount = sizeof(args) / sizeof(args[0]); - auto inst = createInst(this, kIROp_loop, nullptr, argCount, args); + auto inst = createInst(this, kIROp_Loop, nullptr, argCount, args); addInst(inst); return inst; } @@ -5964,7 +5907,7 @@ IRInst* IRBuilder::emitLoop( argList.add(args[ii]); auto inst = - createInst(this, kIROp_loop, nullptr, argList.getCount(), argList.getBuffer()); + createInst(this, kIROp_Loop, nullptr, argList.getCount(), argList.getBuffer()); addInst(inst); return inst; } @@ -5975,7 +5918,7 @@ IRInst* IRBuilder::emitBranch(IRInst* val, IRBlock* trueBlock, IRBlock* falseBlo UInt argCount = sizeof(args) / sizeof(args[0]); auto inst = - createInst(this, kIROp_conditionalBranch, nullptr, argCount, args); + createInst(this, kIROp_ConditionalBranch, nullptr, argCount, args); addInst(inst); return inst; } @@ -5989,7 +5932,7 @@ IRIfElse* IRBuilder::emitIfElse( IRInst* args[] = {val, trueBlock, falseBlock, afterBlock}; UInt argCount = sizeof(args) / sizeof(args[0]); - auto inst = createInst(this, kIROp_ifElse, nullptr, argCount, args); + auto inst = createInst(this, kIROp_IfElse, nullptr, argCount, args); addInst(inst); return inst; } @@ -7654,7 +7597,7 @@ void dumpIR( context.options = options; context.sourceManager = sourceManager; - if (globalVal->getOp() == kIROp_Module) + if (globalVal->getOp() == kIROp_ModuleInst) dumpIRModule(&context, globalVal->getModule()); else dumpInst(&context, globalVal); @@ -7815,7 +7758,7 @@ static bool _isTypeOperandEqual(IRInst* a, IRInst* b) return static_cast(a)->isValueEqual(static_cast(b)) && isTypeEqual(a->getFullType(), b->getFullType()); } - if (IRSpecialize::isaImpl(opA) || opA == kIROp_LookupWitness) + if (IRSpecialize::isaImpl(opA) || opA == kIROp_LookupWitnessMethod) { return _areTypeOperandsEqual(a, b); } @@ -8131,7 +8074,7 @@ static void _maybeHoistOperand(IRUse* use) continue; // We allow out-of-order uses in global scope. - if (operand->getParent() && operand->getParent()->getOp() == kIROp_Module) + if (operand->getParent() && operand->getParent()->getOp() == kIROp_ModuleInst) continue; // If the operand is defined after user, move it to before user. @@ -8516,7 +8459,7 @@ void IRInst::transferDecorationsTo(IRInst* target) bool IRInst::mightHaveSideEffects(SideEffectAnalysisOptions options) { // TODO: We should drive this based on flags specified - // in `ir-inst-defs.h` isntead of hard-coding things here, + // in `ir-inst-defs.yaml` isntead of hard-coding things here, // but this is good enough for now if we are conservative: if (as(this)) @@ -8596,12 +8539,12 @@ bool IRInst::mightHaveSideEffects(SideEffectAnalysisOptions options) case kIROp_LiveRangeEnd: case kIROp_Nop: - case kIROp_undefined: + case kIROp_Undefined: case kIROp_DefaultConstruct: case kIROp_Specialize: - case kIROp_LookupWitness: + case kIROp_LookupWitnessMethod: case kIROp_GetSequentialID: - case kIROp_GetAddr: + case kIROp_GetAddress: case kIROp_GetValueFromBoundInterface: case kIROp_MakeUInt64: case kIROp_MakeCoopVector: @@ -8615,7 +8558,7 @@ bool IRInst::mightHaveSideEffects(SideEffectAnalysisOptions options) case kIROp_MakeArrayFromElement: case kIROp_MakeStruct: case kIROp_MakeString: - case kIROp_getNativeStr: + case kIROp_GetNativeStr: case kIROp_MakeResultError: case kIROp_MakeResultValue: case kIROp_GetResultError: @@ -8650,8 +8593,8 @@ bool IRInst::mightHaveSideEffects(SideEffectAnalysisOptions options) case kIROp_UpdateElement: case kIROp_MeshOutputRef: case kIROp_MakeVectorFromScalar: - case kIROp_swizzle: - case kIROp_swizzleSet: // Doesn't actually "set" anything - just returns the resulting + case kIROp_Swizzle: + case kIROp_SwizzleSet: // Doesn't actually "set" anything - just returns the resulting // vector case kIROp_Add: case kIROp_Sub: @@ -9115,7 +9058,7 @@ bool isMovableInst(IRInst* inst) case kIROp_GetOffsetPtr: case kIROp_UpdateElement: case kIROp_Specialize: - case kIROp_LookupWitness: + case kIROp_LookupWitnessMethod: case kIROp_OptionalHasValue: case kIROp_GetOptionalValue: case kIROp_MakeOptionalValue: @@ -9128,8 +9071,8 @@ bool isMovableInst(IRInst* inst) case kIROp_MakeMatrix: case kIROp_MakeMatrixFromScalar: case kIROp_MakeVectorFromScalar: - case kIROp_swizzle: - case kIROp_swizzleSet: + case kIROp_Swizzle: + case kIROp_SwizzleSet: case kIROp_MatrixReshape: case kIROp_MakeString: case kIROp_MakeResultError: diff --git a/source/slang/slang-ir.h b/source/slang/slang-ir.h index 0ee4bf94b28..bd16eb1b9eb 100644 --- a/source/slang/slang-ir.h +++ b/source/slang/slang-ir.h @@ -1,6 +1,5 @@ // slang-ir.h -#ifndef SLANG_IR_H_INCLUDED -#define SLANG_IR_H_INCLUDED +#pragma once // This file defines the intermediate representation (IR) used for Slang // shader code. This is a typed static single assignment (SSA) IR, @@ -11,12 +10,17 @@ #include "../compiler-core/slang-source-map.h" #include "../core/slang-basic.h" #include "../core/slang-memory-arena.h" +#include "slang-ast-type.h" #include "slang-container-pool.h" +#include "slang-ir-insts-enum.h" #include "slang-type-system-shared.h" -#include #include +// +#include "slang-ir.h.fiddle" + +FIDDLE() namespace Slang { @@ -36,6 +40,8 @@ struct IRModule; struct IRStructField; struct IRStructKey; +FIDDLE(instStructForwardDecls()) + typedef unsigned int IROpFlags; enum : IROpFlags { @@ -48,37 +54,6 @@ enum : IROpFlags 1 << 3, ///< If set this op should always be hoisted but should never be deduplicated. }; -/* Bit usage of IROp is a follows - - MainOp | Other -Bit range: 0-10 | Remaining bits - -For doing range checks (for example for doing isa tests), the value is masked by kIROpMask_OpMask, -such that the Other bits don't interfere. The other bits can be used for storage for anything that -needs to identify as a different 'op' or 'type'. It is currently used currently for storing the -TextureFlavor of a IRResourceTypeBase derived types for example. - -TODO: We should eliminate the use of the "other" bits so that the entire value/state -of an instruction is manifest in its opcode, operands, and children. -*/ -enum IROp : int32_t -{ -#define INST(ID, MNEMONIC, ARG_COUNT, FLAGS) kIROp_##ID, -#include "slang-ir-inst-defs.h" - - /// The total number of valid opcodes - kIROpCount, - - /// An invalid opcode used to represent a missing or unknown opcode value. - kIROp_Invalid = kIROpCount, - -#define INST(ID, MNEMONIC, ARG_COUNT, FLAGS) /* empty */ -#define INST_RANGE(BASE, FIRST, LAST) \ - kIROp_First##BASE = kIROp_##FIRST, kIROp_Last##BASE = kIROp_##LAST, - -#include "slang-ir-inst-defs.h" -}; - /* IROpMeta describes values for the layout of IROps */ enum IROpMeta { @@ -557,8 +532,10 @@ struct IRBlock; // Every value in the IR is an instruction (even things // like literal values). // +FIDDLE() struct IRInst { + FIDDLE(...) // The operation that this value represents IROp m_op; @@ -963,39 +940,18 @@ typename IRFilteredInstList::Iterator IRFilteredInstList::end() // Types -#define IR_LEAF_ISA(NAME) \ - static bool isaImpl(IROp op) \ - { \ - return (kIROpMask_OpMask & op) == kIROp_##NAME; \ - } -#define IR_PARENT_ISA(NAME) \ - static bool isaImpl(IROp opIn) \ - { \ - const int op = (kIROpMask_OpMask & opIn); \ - return op >= kIROp_First##NAME && op <= kIROp_Last##NAME; \ - } - -#define SIMPLE_IR_TYPE(NAME, BASE) \ - struct IR##NAME : IR##BASE \ - { \ - IR_LEAF_ISA(NAME) \ - }; -#define SIMPLE_IR_PARENT_TYPE(NAME, BASE) \ - struct IR##NAME : IR##BASE \ - { \ - IR_PARENT_ISA(NAME) \ - }; - // All types in the IR are represented as instructions which conceptually // execute before run time. +FIDDLE() struct IRType : IRInst { + FIDDLE(baseInst{noIsaImpl = true}) IRType* getCanonicalType() { return this; } // Hack: specialize can also be a type. We should consider using a // separate `specializeType` op code for types so we can use the normal - // `IR_PARENT_ISA` macro here. + // isaImpl definition macro here. static bool isaImpl(IROp opIn) { const int op = (kIROpMask_OpMask & opIn); @@ -1005,32 +961,31 @@ struct IRType : IRInst IRType* unwrapArray(IRType* type); +FIDDLE() struct IRBasicType : IRType { + FIDDLE(baseInst()) BaseType getBaseType() { return BaseType(getOp() - kIROp_FirstBasicType); } - - IR_PARENT_ISA(BasicType) }; +FIDDLE() struct IRVoidType : IRBasicType { - IR_LEAF_ISA(VoidType) + FIDDLE(leafInst()) }; +FIDDLE() struct IRBoolType : IRBasicType { - IR_LEAF_ISA(BoolType) + FIDDLE(leafInst()) }; +FIDDLE() struct IRStringTypeBase : IRType { - IR_PARENT_ISA(StringTypeBase) + FIDDLE(baseInst()) }; -SIMPLE_IR_TYPE(StringType, StringTypeBase) -SIMPLE_IR_TYPE(NativeStringType, StringTypeBase) - -SIMPLE_IR_TYPE(DynamicType, Type) // True if types are equal // Note compares nominal types by name alone @@ -1075,8 +1030,10 @@ typedef int64_t IRIntegerValue; typedef uint64_t IRUnsignedIntegerValue; typedef double IRFloatingPointValue; +FIDDLE() struct IRConstant : IRInst { + FIDDLE(baseInst()) enum class FloatKind { Finite, @@ -1129,7 +1086,6 @@ struct IRConstant : IRInst /// Get the hash HashCode getHashCode(); - IR_PARENT_ISA(Constant) // Must be last member, because data may be held behind // NOTE! The total size of IRConstant may not be allocated - only enough space is allocated for @@ -1137,25 +1093,25 @@ struct IRConstant : IRInst ValueUnion value; }; +FIDDLE() struct IRIntLit : IRConstant { + FIDDLE(leafInst()) IRIntegerValue getValue() { return value.intVal; } - - IR_LEAF_ISA(IntLit); }; +FIDDLE() struct IRFloatLit : IRConstant { + FIDDLE(leafInst()) IRFloatingPointValue getValue() { return value.floatVal; } - - IR_LEAF_ISA(FloatLit); }; +FIDDLE() struct IRBoolLit : IRConstant { + FIDDLE(leafInst()) bool getValue() { return value.intVal != 0; } - - IR_LEAF_ISA(BoolLit); }; // Get the compile-time constant integer value of an instruction, @@ -1167,33 +1123,37 @@ IRIntegerValue getIntVal(IRInst* inst); // the actual size. IRIntegerValue getArraySizeVal(IRInst* inst); +FIDDLE() struct IRStringLit : IRConstant { - - IR_LEAF_ISA(StringLit); + FIDDLE(leafInst()) }; +FIDDLE() struct IRBlobLit : IRConstant { - IR_LEAF_ISA(BlobLit); + FIDDLE(leafInst()) }; +FIDDLE() struct IRPtrLit : IRConstant { - IR_LEAF_ISA(PtrLit); + FIDDLE(leafInst()) void* getValue() { return value.ptrVal; } }; +FIDDLE() struct IRVoidLit : IRConstant { - IR_LEAF_ISA(VoidLit); + FIDDLE(leafInst()) }; // A instruction that ends a basic block (usually because of control flow) +FIDDLE() struct IRTerminatorInst : IRInst { - IR_PARENT_ISA(TerminatorInst) + FIDDLE(baseInst()) }; // A function parameter is owned by a basic block, and represents @@ -1204,12 +1164,12 @@ struct IRTerminatorInst : IRInst // In each case, the basic idea is that a block is a "label with // arguments." // +FIDDLE() struct IRParam : IRInst { + FIDDLE(leafInst()) IRParam* getNextParam(); IRParam* getPrevParam(); - - IR_LEAF_ISA(Param) }; /// A control-flow edge from one basic block to another @@ -1239,8 +1199,10 @@ struct IREdge // no function declarations, or nested blocks). We also expect // that the previous/next instruction are always a basic block. // +FIDDLE() struct IRBlock : IRInst { + FIDDLE(leafInst()) // Linked list of the instructions contained in this block // IRInst* getFirstInst() { return getChildren().first; } @@ -1386,14 +1348,13 @@ struct IRBlock : IRInst SuccessorList getSuccessors(); // - - IR_LEAF_ISA(Block) }; -SIMPLE_IR_TYPE(BasicBlockType, Type) +FIDDLE() struct IRResourceTypeBase : IRType { + FIDDLE(baseInst()) IRInst* getShapeInst() { return getOperand(kCoreModule_TextureShapeParameterIndex); } IRInst* getIsArrayInst() { return getOperand(kCoreModule_TextureIsArrayParameterIndex); } IRInst* getIsMultisampleInst() @@ -1461,115 +1422,93 @@ struct IRResourceTypeBase : IRType } return SLANG_RESOURCE_ACCESS_UNKNOWN; } - - IR_PARENT_ISA(ResourceTypeBase); }; +FIDDLE() struct IRResourceType : IRResourceTypeBase { + FIDDLE(baseInst()) IRType* getElementType() { return (IRType*)getOperand(0); } IRInst* getSampleCount() { return getSampleCountInst(); } bool hasFormat() { return getOperandCount() >= 9; } IRIntegerValue getFormat() { return getIntVal(getFormatInst()); } - - IR_PARENT_ISA(ResourceType) }; +FIDDLE() struct IRTextureTypeBase : IRResourceType { - IR_PARENT_ISA(TextureTypeBase) + FIDDLE(baseInst()) }; +FIDDLE() struct IRTextureType : IRTextureTypeBase { - IR_LEAF_ISA(TextureType) + FIDDLE(leafInst()) }; +FIDDLE() struct IRGLSLImageType : IRTextureTypeBase { - IR_LEAF_ISA(GLSLImageType) + FIDDLE(leafInst()) }; +FIDDLE() struct IRSubpassInputType : IRType { + FIDDLE(leafInst()) IRType* getElementType() { return (IRType*)getOperand(0); } IRInst* getIsMultisampleInst() { return getOperand(1); } bool isMultisample() { return getIntVal(getIsMultisampleInst()) == 1; } - - IR_LEAF_ISA(SubpassInputType) }; +FIDDLE() struct IRSamplerStateTypeBase : IRType { - IR_PARENT_ISA(SamplerStateTypeBase) + FIDDLE(baseInst()) }; -SIMPLE_IR_TYPE(SamplerStateType, SamplerStateTypeBase) -SIMPLE_IR_TYPE(SamplerComparisonStateType, SamplerStateTypeBase) +FIDDLE() struct IRBuiltinGenericType : IRType { + FIDDLE(baseInst()) IRType* getElementType() { return (IRType*)getOperand(0); } - - IR_PARENT_ISA(BuiltinGenericType) }; -SIMPLE_IR_PARENT_TYPE(PointerLikeType, BuiltinGenericType); +FIDDLE() struct IRHLSLStructuredBufferTypeBase : IRBuiltinGenericType { + FIDDLE(baseInst()) IRType* getDataLayout() { return (IRType*)getOperand(1); } - - IR_PARENT_ISA(HLSLStructuredBufferTypeBase) }; -SIMPLE_IR_TYPE(HLSLStructuredBufferType, HLSLStructuredBufferTypeBase) -SIMPLE_IR_TYPE(HLSLRWStructuredBufferType, HLSLStructuredBufferTypeBase) -SIMPLE_IR_TYPE(HLSLRasterizerOrderedStructuredBufferType, HLSLStructuredBufferTypeBase) - -SIMPLE_IR_PARENT_TYPE(UntypedBufferResourceType, Type) -SIMPLE_IR_PARENT_TYPE(ByteAddressBufferTypeBase, UntypedBufferResourceType) -SIMPLE_IR_TYPE(HLSLByteAddressBufferType, ByteAddressBufferTypeBase) -SIMPLE_IR_TYPE(HLSLRWByteAddressBufferType, ByteAddressBufferTypeBase) -SIMPLE_IR_TYPE(HLSLRasterizerOrderedByteAddressBufferType, ByteAddressBufferTypeBase) - -SIMPLE_IR_TYPE(HLSLAppendStructuredBufferType, HLSLStructuredBufferTypeBase) -SIMPLE_IR_TYPE(HLSLConsumeStructuredBufferType, HLSLStructuredBufferTypeBase) +FIDDLE() struct IRHLSLPatchType : IRType { + FIDDLE(baseInst()) IRType* getElementType() { return (IRType*)getOperand(0); } IRInst* getElementCount() { return getOperand(1); } - - IR_PARENT_ISA(HLSLPatchType) }; -SIMPLE_IR_TYPE(HLSLInputPatchType, HLSLPatchType) -SIMPLE_IR_TYPE(HLSLOutputPatchType, HLSLPatchType) - -SIMPLE_IR_PARENT_TYPE(HLSLStreamOutputType, BuiltinGenericType) -SIMPLE_IR_TYPE(HLSLPointStreamType, HLSLStreamOutputType) -SIMPLE_IR_TYPE(HLSLLineStreamType, HLSLStreamOutputType) -SIMPLE_IR_TYPE(HLSLTriangleStreamType, HLSLStreamOutputType) // Mesh shaders // TODO: Ellie, should this parent struct be shared with Patch? // IRArrayLikeType? IROpaqueArrayLikeType? +FIDDLE() struct IRMeshOutputType : IRType { + FIDDLE(baseInst()) IRType* getElementType() { return (IRType*)getOperand(0); } IRInst* getMaxElementCount() { return getOperand(1); } - - IR_PARENT_ISA(MeshOutputType) }; -SIMPLE_IR_TYPE(VerticesType, MeshOutputType) -SIMPLE_IR_TYPE(IndicesType, MeshOutputType) -SIMPLE_IR_TYPE(PrimitivesType, MeshOutputType) +FIDDLE() struct IRMetalMeshType : IRType { - IR_LEAF_ISA(MetalMeshType); + FIDDLE(leafInst()) IRType* getVerticesType() { return (IRType*)getOperand(0); } IRType* getPrimitivesType() { return (IRType*)getOperand(1); } @@ -1578,35 +1517,38 @@ struct IRMetalMeshType : IRType IRIntLit* getTopology() { return (IRIntLit*)getOperand(4); } }; -SIMPLE_IR_TYPE(MetalMeshGridPropertiesType, Type) +FIDDLE() +struct IRPointerLikeType : IRBuiltinGenericType +{ + FIDDLE(baseInst()) +}; -SIMPLE_IR_TYPE(GLSLInputAttachmentType, Type) -SIMPLE_IR_PARENT_TYPE(ParameterGroupType, PointerLikeType) +FIDDLE() +struct IRParameterGroupType : IRPointerLikeType +{ + FIDDLE(baseInst()) +}; +FIDDLE() struct IRUniformParameterGroupType : IRParameterGroupType { - IR_PARENT_ISA(UniformParameterGroupType) + FIDDLE(baseInst()) IRType* getDataLayout() { return getOperandCount() > 1 ? (IRType*)getOperand(1) : nullptr; } }; -SIMPLE_IR_PARENT_TYPE(VaryingParameterGroupType, ParameterGroupType) -SIMPLE_IR_TYPE(ConstantBufferType, UniformParameterGroupType) -SIMPLE_IR_TYPE(TextureBufferType, UniformParameterGroupType) -SIMPLE_IR_TYPE(GLSLInputParameterGroupType, VaryingParameterGroupType) -SIMPLE_IR_TYPE(GLSLOutputParameterGroupType, VaryingParameterGroupType) -SIMPLE_IR_TYPE(ParameterBlockType, UniformParameterGroupType) -SIMPLE_IR_TYPE(DynamicResourceType, Type) +FIDDLE() struct IRGLSLShaderStorageBufferType : IRBuiltinGenericType { + FIDDLE(leafInst()) IRType* getDataLayout() { return (IRType*)getOperand(1); } - - IR_LEAF_ISA(GLSLShaderStorageBufferType) }; +FIDDLE() struct IRArrayTypeBase : IRType { + FIDDLE(baseInst()) IRType* getElementType() { return (IRType*)getOperand(0); } // Returns the element count for an `IRArrayType`, and null @@ -1629,51 +1571,43 @@ struct IRArrayTypeBase : IRType } return nullptr; } - - IR_PARENT_ISA(ArrayTypeBase) }; +FIDDLE() struct IRArrayType : IRArrayTypeBase { - IR_LEAF_ISA(ArrayType) + FIDDLE(leafInst()) }; -SIMPLE_IR_TYPE(UnsizedArrayType, ArrayTypeBase) +FIDDLE() struct IRAtomicType : IRType { - IR_LEAF_ISA(AtomicType) + FIDDLE(leafInst()) IRType* getElementType() { return (IRType*)getOperand(0); } }; -SIMPLE_IR_PARENT_TYPE(Rate, Type) -SIMPLE_IR_TYPE(ConstExprRate, Rate) -SIMPLE_IR_TYPE(SpecConstRate, Rate) -SIMPLE_IR_TYPE(GroupSharedRate, Rate) -SIMPLE_IR_TYPE(ActualGlobalRate, Rate) +FIDDLE() struct IRRateQualifiedType : IRType { + FIDDLE(leafInst()) IRRate* getRate() { return (IRRate*)getOperand(0); } IRType* getValueType() { return (IRType*)getOperand(1); } - - IR_LEAF_ISA(RateQualifiedType) }; +FIDDLE() struct IRDescriptorHandleType : IRType { + FIDDLE(leafInst()) IRType* getResourceType() { return (IRType*)getOperand(0); } - IR_LEAF_ISA(DescriptorHandleType) }; // Unlike the AST-level type system where `TypeType` tracks the // underlying type, the "type of types" in the IR is a simple // value with no operands, so that all type nodes have the // same type. -SIMPLE_IR_PARENT_TYPE(Kind, Type); -SIMPLE_IR_TYPE(TypeKind, Kind); -SIMPLE_IR_TYPE(TypeParameterPackKind, Kind); // The kind of any and all generics. // @@ -1684,83 +1618,90 @@ SIMPLE_IR_TYPE(TypeParameterPackKind, Kind); // "higher-kinded" generics (e.g., a generic that takes another // generic as a parameter). // -SIMPLE_IR_TYPE(GenericKind, Kind) +FIDDLE() struct IRDifferentialPairTypeBase : IRType { + FIDDLE(baseInst()) IRType* getValueType() { return (IRType*)getOperand(0); } IRInst* getWitness() { return (IRInst*)getOperand(1); } - - IR_PARENT_ISA(DifferentialPairTypeBase) }; +FIDDLE() struct IRDifferentialPairType : IRDifferentialPairTypeBase { - IR_LEAF_ISA(DifferentialPairType) + FIDDLE(leafInst()) }; +FIDDLE() struct IRDifferentialPtrPairType : IRDifferentialPairTypeBase { - IR_LEAF_ISA(DifferentialPtrPairType) + FIDDLE(leafInst()) }; +FIDDLE() struct IRDifferentialPairUserCodeType : IRDifferentialPairTypeBase { - IR_LEAF_ISA(DifferentialPairUserCodeType) + FIDDLE(leafInst()) }; +FIDDLE() struct IRBackwardDiffIntermediateContextType : IRType { + FIDDLE(leafInst()) IRInst* getFunc() { return getOperand(0); } - IR_LEAF_ISA(BackwardDiffIntermediateContextType) }; +FIDDLE() struct IRVectorType : IRType { + FIDDLE(leafInst()) IRType* getElementType() { return (IRType*)getOperand(0); } IRInst* getElementCount() { return getOperand(1); } - - IR_LEAF_ISA(VectorType) }; +FIDDLE() struct IRMatrixType : IRType { + FIDDLE(leafInst()) IRType* getElementType() { return (IRType*)getOperand(0); } IRInst* getRowCount() { return getOperand(1); } IRInst* getColumnCount() { return getOperand(2); } IRInst* getLayout() { return getOperand(3); } - - IR_LEAF_ISA(MatrixType) }; +FIDDLE() struct IRArrayListType : IRType { + FIDDLE(leafInst()) IRType* getElementType() { return (IRType*)getOperand(0); } - - IR_LEAF_ISA(ArrayListType) }; +FIDDLE() struct IRTensorViewType : IRType { + FIDDLE(leafInst()) IRType* getElementType() { return (IRType*)getOperand(0); } - - IR_LEAF_ISA(TensorViewType) }; +FIDDLE() struct IRTorchTensorType : IRType { - IR_LEAF_ISA(TorchTensorType) + FIDDLE(leafInst()) }; +FIDDLE() struct IRSPIRVLiteralType : IRType { - IR_LEAF_ISA(SPIRVLiteralType) + FIDDLE(leafInst()) IRType* getValueType() { return static_cast(getOperand(0)); } }; +FIDDLE() struct IRPtrTypeBase : IRType { + FIDDLE(baseInst()) IRType* getValueType() { return (IRType*)getOperand(0); } bool hasAddressSpace() @@ -1774,63 +1715,62 @@ struct IRPtrTypeBase : IRType ? (AddressSpace) static_cast(getOperand(1))->getValue() : AddressSpace::Generic; } - - IR_PARENT_ISA(PtrTypeBase) }; -SIMPLE_IR_TYPE(PtrType, PtrTypeBase) -SIMPLE_IR_TYPE(RefType, PtrTypeBase) -SIMPLE_IR_TYPE(ConstRefType, PtrTypeBase) -SIMPLE_IR_PARENT_TYPE(OutTypeBase, PtrTypeBase) -SIMPLE_IR_TYPE(OutType, OutTypeBase) -SIMPLE_IR_TYPE(InOutType, OutTypeBase) - +FIDDLE() struct IRComPtrType : public IRType { - IR_LEAF_ISA(ComPtrType); + FIDDLE(leafInst()) IRType* getValueType() { return (IRType*)getOperand(0); } }; +FIDDLE() struct IRNativePtrType : public IRType { - IR_LEAF_ISA(NativePtrType); + FIDDLE(leafInst()) IRType* getValueType() { return (IRType*)getOperand(0); } }; +FIDDLE() struct IRPseudoPtrType : public IRPtrTypeBase { - IR_LEAF_ISA(PseudoPtrType); + FIDDLE(leafInst()) }; /// The base class of RawPointerType and RTTIPointerType. +FIDDLE() struct IRRawPointerTypeBase : IRType { - IR_PARENT_ISA(RawPointerTypeBase); + FIDDLE(baseInst()) }; /// Represents a pointer to an object of unknown type. +FIDDLE() struct IRRawPointerType : IRRawPointerTypeBase { - IR_LEAF_ISA(RawPointerType) + FIDDLE(leafInst()) }; /// Represents a pointer to an object whose type is determined at runtime, /// with type information available through `rttiOperand`. /// +FIDDLE() struct IRRTTIPointerType : IRRawPointerTypeBase { + FIDDLE(leafInst()) IRInst* getRTTIOperand() { return getOperand(0); } - IR_LEAF_ISA(RTTIPointerType) }; +FIDDLE() struct IRGlobalHashedStringLiterals : IRInst { - IR_LEAF_ISA(GlobalHashedStringLiterals) + FIDDLE(leafInst()) }; +FIDDLE() struct IRGetStringHash : IRInst { - IR_LEAF_ISA(GetStringHash) + FIDDLE(leafInst()) IRStringLit* getStringLit() { return as(getOperand(0)); } }; @@ -1840,8 +1780,10 @@ struct IRGetStringHash : IRInst /// The given IR `builder` will be used if new instructions need to be created. IRType* tryGetPointedToType(IRBuilder* builder, IRType* type); +FIDDLE() struct IRFuncType : IRType { + FIDDLE(leafInst()) IRType* getResultType() { return (IRType*)getOperand(0); } UInt getParamCount() { return getOperandCount() - 1; } IRType* getParamType(UInt index) { return (IRType*)getOperand(1 + index); } @@ -1849,54 +1791,54 @@ struct IRFuncType : IRType { return IROperandList(getOperands() + 1, getOperands() + getOperandCount()); } - - IR_LEAF_ISA(FuncType) }; +FIDDLE() struct IRRayQueryType : IRType { - IR_LEAF_ISA(RayQueryType) + FIDDLE(leafInst()) }; +FIDDLE() struct IRHitObjectType : IRType { - IR_LEAF_ISA(HitObjectType) + FIDDLE(leafInst()) }; +FIDDLE() struct IRCoopVectorType : IRType { + FIDDLE(leafInst()) IRType* getElementType() { return (IRType*)getOperand(0); } IRInst* getElementCount() { return getOperand(1); } - - IR_LEAF_ISA(CoopVectorType) }; +FIDDLE() struct IRCoopMatrixType : IRType { + FIDDLE(leafInst()) IRType* getElementType() { return (IRType*)getOperand(0); } IRInst* getScope() { return getOperand(1); } IRInst* getRowCount() { return getOperand(2); } IRInst* getColumnCount() { return getOperand(3); } IRInst* getMatrixUse() { return getOperand(4); } - - IR_LEAF_ISA(CoopMatrixType) }; +FIDDLE() struct IRTensorAddressingTensorLayoutType : IRType { + FIDDLE(leafInst()) IRInst* getDimension() { return getOperand(0); } IRInst* getClampMode() { return getOperand(1); } - - IR_LEAF_ISA(TensorAddressingTensorLayoutType) }; +FIDDLE() struct IRTensorAddressingTensorViewType : IRType { + FIDDLE(leafInst()) IRInst* getDimension() { return getOperand(0); } IRInst* getHasDimension() { return getOperand(1); } IRInst* getPermutation(int index) { return getOperand(2 + index); } - - IR_LEAF_ISA(TensorAddressingTensorViewType) }; bool isDefinition(IRInst* inVal); @@ -1910,9 +1852,10 @@ bool isDefinition(IRInst* inVal); // (that is, they have mangled names that can be used // for linkage). // +FIDDLE() struct IRStructKey : IRInst { - IR_LEAF_ISA(StructKey) + FIDDLE(leafInst()) }; // // The fields of the struct are then defined as mappings @@ -1922,8 +1865,10 @@ struct IRStructKey : IRInst // A struct field thus has two operands: the key, and the // type of the field. // +FIDDLE() struct IRStructField : IRInst { + FIDDLE(leafInst()) IRStructKey* getKey() { return cast(getOperand(0)); } IRType* getFieldType() { @@ -1935,8 +1880,6 @@ struct IRStructField : IRInst return (IRType*)getOperand(1); } void setFieldType(IRType* type) { setOperand(1, type); } - - IR_LEAF_ISA(StructField) }; // // The struct type is then represented as a parent instruction @@ -1944,191 +1887,214 @@ struct IRStructField : IRInst // *not* contain the keys, because code needs to be able to // reference the keys from scopes outside of the struct. // +FIDDLE() struct IRStructType : IRType { + FIDDLE(leafInst()) IRFilteredInstList getFields() { return IRFilteredInstList(getChildren()); } - - IR_LEAF_ISA(StructType) }; +FIDDLE() struct IRClassType : IRType { + FIDDLE(leafInst()) IRFilteredInstList getFields() { return IRFilteredInstList(getChildren()); } - - IR_LEAF_ISA(ClassType) }; +FIDDLE() struct IRAssociatedType : IRType { - IR_LEAF_ISA(AssociatedType) + FIDDLE(leafInst()) }; +FIDDLE() struct IRThisType : IRType { - IR_LEAF_ISA(ThisType) + FIDDLE(leafInst()) IRInst* getConstraintType() { return getOperand(0); } }; +FIDDLE() struct IRThisTypeWitness : IRInst { - IR_LEAF_ISA(ThisTypeWitness) + FIDDLE(leafInst()) IRInst* getConstraintType() { return getOperand(0); } }; +FIDDLE() struct IRInterfaceRequirementEntry : IRInst { + FIDDLE(leafInst()) IRInst* getRequirementKey() { return getOperand(0); } IRInst* getRequirementVal() { return getOperand(1); } void setRequirementKey(IRInst* val) { setOperand(0, val); } void setRequirementVal(IRInst* val) { setOperand(1, val); } - - IR_LEAF_ISA(InterfaceRequirementEntry); }; +FIDDLE() struct IRInterfaceType : IRType { - IR_LEAF_ISA(InterfaceType) + FIDDLE(leafInst()) UInt getRequirementCount() { return getOperandCount(); } }; +FIDDLE() struct IRConjunctionType : IRType { - IR_LEAF_ISA(ConjunctionType) + FIDDLE(leafInst()) Int getCaseCount() { return getOperandCount(); } IRType* getCaseType(Int index) { return (IRType*)getOperand(index); } }; +FIDDLE() struct IRAttributedType : IRType { - IR_LEAF_ISA(AttributedType) + FIDDLE(leafInst()) IRType* getBaseType() { return (IRType*)getOperand(0); } IRInst* getAttr() { return getOperand(1); } }; +FIDDLE() struct IRTupleTypeBase : IRType { - IR_PARENT_ISA(TupleTypeBase) + FIDDLE(baseInst()) }; /// Represents a tuple. Tuples are created by `IRMakeTuple` and its elements /// are accessed via `GetTupleElement(tupleValue, IRIntLit)`. +FIDDLE() struct IRTupleType : IRTupleTypeBase { - IR_LEAF_ISA(TupleType) + FIDDLE(leafInst()) }; /// Represents a type pack. Type packs behave like tuples, but they have a /// "flattening" semantics, so that MakeTypePack(MakeTypePack(T1,T2), T3) is /// MakeTypePack(T1,T2,T3). +FIDDLE() struct IRTypePack : IRTupleTypeBase { - IR_LEAF_ISA(TypePack) + FIDDLE(leafInst()) }; // A placeholder struct key for tuple type layouts that will be replaced with // the actual struct key when the tuple type is materialized into a struct type. +FIDDLE() struct IRIndexedFieldKey : IRInst { - IR_LEAF_ISA(IndexedFieldKey) + FIDDLE(leafInst()) IRInst* getBaseType() { return getOperand(0); } IRInst* getIndex() { return getOperand(1); } }; /// Represents a tuple in target language. TargetTupleType will not be lowered to structs. +FIDDLE() struct IRTargetTupleType : IRType { - IR_LEAF_ISA(TargetTupleType) + FIDDLE(leafInst()) }; /// Represents a `expand T` type used in variadic generic decls in Slang. Expected to be substituted /// by actual types during specialization. -struct IRExpandType : IRType +FIDDLE() +struct IRExpandTypeOrVal : IRType { - IR_LEAF_ISA(ExpandTypeOrVal) + FIDDLE(leafInst()) IRType* getPatternType() { return (IRType*)(getOperand(0)); } UInt getCaptureCount() { return getOperandCount() - 1; } IRType* getCaptureType(UInt index) { return (IRType*)(getOperand(index + 1)); } }; /// Represents an `Result`, used by functions that throws error codes. +FIDDLE() struct IRResultType : IRType { - IR_LEAF_ISA(ResultType) + FIDDLE(leafInst()) IRType* getValueType() { return (IRType*)getOperand(0); } IRType* getErrorType() { return (IRType*)getOperand(1); } }; /// Represents an `Optional`. +FIDDLE() struct IROptionalType : IRType { - IR_LEAF_ISA(OptionalType) + FIDDLE(leafInst()) IRType* getValueType() { return (IRType*)getOperand(0); } }; /// Represents an enum type +FIDDLE() struct IREnumType : IRType { - IR_LEAF_ISA(EnumType) + FIDDLE(leafInst()) IRType* getTagType() { return (IRType*)getOperand(0); } }; +FIDDLE() struct IRTypeType : IRType { - IR_LEAF_ISA(TypeType); + FIDDLE(leafInst()) }; /// Represents the IR type for an `IRRTTIObject`. +FIDDLE() struct IRRTTIType : IRType { - IR_LEAF_ISA(RTTIType); + FIDDLE(leafInst()) }; /// Represents a handle to an RTTI object. /// This is lowered as an integer number identifying a type. +FIDDLE() struct IRRTTIHandleType : IRType { - IR_LEAF_ISA(RTTIHandleType); + FIDDLE(leafInst()) }; +FIDDLE() struct IRAnyValueType : IRType { - IR_LEAF_ISA(AnyValueType); + FIDDLE(leafInst()) IRInst* getSize() { return getOperand(0); } }; +FIDDLE() struct IRWitnessTableTypeBase : IRType { + FIDDLE(baseInst()) IRInst* getConformanceType() { return getOperand(0); } - IR_PARENT_ISA(WitnessTableTypeBase); }; +FIDDLE() struct IRWitnessTableType : IRWitnessTableTypeBase { - IR_LEAF_ISA(WitnessTableType); + FIDDLE(leafInst()) }; +FIDDLE() struct IRWitnessTableIDType : IRWitnessTableTypeBase { - IR_LEAF_ISA(WitnessTableIDType); + FIDDLE(leafInst()) }; +FIDDLE() struct IRBindExistentialsTypeBase : IRType { - IR_PARENT_ISA(BindExistentialsTypeBase) + FIDDLE(baseInst()) IRType* getBaseType() { return (IRType*)getOperand(0); } UInt getExistentialArgCount() { return getOperandCount() - 1; } @@ -2136,14 +2102,16 @@ struct IRBindExistentialsTypeBase : IRType IRInst* getExistentialArg(UInt index) { return getExistentialArgs()[index].get(); } }; +FIDDLE() struct IRBindExistentialsType : IRBindExistentialsTypeBase { - IR_LEAF_ISA(BindExistentialsType) + FIDDLE(leafInst()) }; +FIDDLE() struct IRBoundInterfaceType : IRBindExistentialsTypeBase { - IR_LEAF_ISA(BoundInterfaceType) + FIDDLE(leafInst()) IRType* getInterfaceType() { return getBaseType(); } IRType* getConcreteType() { return (IRType*)getExistentialArg(0); } @@ -2153,20 +2121,22 @@ struct IRBoundInterfaceType : IRBindExistentialsTypeBase /// @brief A global value that potentially holds executable code. /// +FIDDLE() struct IRGlobalValueWithCode : IRInst { + FIDDLE(baseInst()) // The children of a value with code will be the basic // blocks of its definition. IRBlock* getFirstBlock() { return cast(getFirstChild()); } IRBlock* getLastBlock() { return cast(getLastChild()); } IRInstList getBlocks() { return IRInstList(getChildren()); } - - IR_PARENT_ISA(GlobalValueWithCode) }; // A value that has parameters so that it can conceptually be called. +FIDDLE() struct IRGlobalValueWithParams : IRGlobalValueWithCode { + FIDDLE(baseInst()) // Convenience accessor for the IR parameters, // which are actually the parameters of the first // block. @@ -2174,16 +2144,16 @@ struct IRGlobalValueWithParams : IRGlobalValueWithCode IRParam* getLastParam(); IRInstList getParams(); IRInst* getFirstOrdinaryInst(); - - IR_PARENT_ISA(GlobalValueWithParams) }; // A function is a parent to zero or more blocks of instructions. // // A function is itself a value, so that it can be a direct operand of // an instruction (e.g., a call). +FIDDLE() struct IRFunc : IRGlobalValueWithParams { + FIDDLE(leafInst()) // The type of the IR-level function IRFuncType* getDataType() { return (IRFuncType*)IRInst::getDataType(); } @@ -2194,8 +2164,6 @@ struct IRFunc : IRGlobalValueWithParams IRType* getParamType(UInt index); bool isDefinition() { return getFirstBlock() != nullptr; } - - IR_LEAF_ISA(Func) }; /// Adjust the type of an IR function based on its parameter list. @@ -2218,9 +2186,10 @@ void fixUpFuncType(IRFunc* func); // // In practice, a generic always holds only a single block, and ends // with a `return` instruction for the value that the generic yields. +FIDDLE() struct IRGeneric : IRGlobalValueWithParams { - IR_LEAF_ISA(Generic) + FIDDLE(leafInst()) }; // Find the value that is returned from a generic, so that @@ -2255,16 +2224,16 @@ IRInst* getResolvedInstForDecorations(IRInst* inst, bool resolveThroughDifferent // The IR module itself is represented as an instruction, which // serves at the root of the tree of all instructions in the module. +FIDDLE() struct IRModuleInst : IRInst { + FIDDLE(leafInst()) // Pointer back to the non-instruction object that represents // the module, so that we can get back to it in algorithms // that need it. IRModule* module; IRInstListBase getGlobalInsts() { return getChildren(); } - - IR_LEAF_ISA(Module) }; struct IRModule; @@ -2603,9 +2572,10 @@ struct InstHashSet }; +FIDDLE() struct IRSpecializationDictionaryItem : public IRInst { - IR_LEAF_ISA(SpecializationDictionaryItem) + FIDDLE(leafInst()) }; struct IRDumpOptions @@ -2832,5 +2802,3 @@ R* composeGetters(T* t) } } // namespace Slang - -#endif diff --git a/source/slang/slang-ir.h.lua b/source/slang/slang-ir.h.lua new file mode 100644 index 00000000000..8455ce65250 --- /dev/null +++ b/source/slang/slang-ir.h.lua @@ -0,0 +1,202 @@ +-- +-- This file contains most of the code generation logic for the ir instructions +-- + +-- Helper function +-- Walk the instruction tree and call a callback for each instruction +local function walk_instructions(insts, callback, parent_struct) + local function walk_insts(tbl, parent) + for _, i in ipairs(tbl) do + local key, value = next(i) + -- Determine struct name + local struct_name = value.struct_name and value.struct_name or key + + -- Call the callback + callback(key, value, struct_name, parent) + + -- Recursively process nested instructions + walk_insts(value, struct_name) + end + end + + -- Start walking from the top-level insts + if insts then + walk_insts(insts, "Inst") + end +end + +-- The definitions for leaf instructions +local leafInst = function(name, args) + args = args or {} + return args.noIsaImpl and "" + or [[static bool isaImpl(IROp op) + { + return (kIROpMask_OpMask & op) == kIROp_]] + .. name + .. [[; + } + enum { kOp = kIROp_]] + .. name + .. [[ }; ]] +end + +-- The definitions for abstract instruction classes +local baseInst = function(name, args) + args = args or {} + return args.noIsaImpl and "" + or [[static bool isaImpl(IROp opIn) + { + const int op = (kIROpMask_OpMask & opIn); + return op >= kIROp_First]] + .. name + .. [[ && op <= kIROp_Last]] + .. name + .. [[; + }]] +end + +-- Generate struct definitions for instructions not defined by the user +local function allOtherInstStructs() + local insts = require("source/slang/slang-ir-insts.lua").insts + local output = {} + + walk_instructions(insts, function(key, value, struct_name, parent_struct) + -- If this type already has a definition, skip it + if not Slang["IR" .. struct_name] then + -- Generate struct definition + table.insert(output, string.format("struct IR%s : IR%s", struct_name, parent_struct)) + table.insert(output, "{") + table.insert( + output, + string.format(" %s", value.is_leaf and leafInst(struct_name) or baseInst(struct_name)) + ) + table.insert(output, "};") + table.insert(output, "") + end + end) + + return table.concat(output, "\n") +end + +-- Forward declarations for everything +local function instStructForwardDecls() + local insts = require("source/slang/slang-ir-insts.lua").insts + local output = {} + + walk_instructions(insts, function(key, value, struct_name, parent_struct) + -- Generate struct definition + table.insert(output, string.format("struct IR%s;", struct_name)) + end) + + return table.concat(output, "\n") +end + +-- The info table +local function instInfoEntries() + local insts = require("source/slang/slang-ir-insts.lua").insts + local output = {} + + local function constructFlags(value) + local flags = {} + + -- Map of field names to their IROpFlags names + local flagMap = { + hoistable = "kIROpFlag_Hoistable", + parent = "kIROpFlag_Parent", + global = "kIROpFlag_Global", + use_other = "kIROpFlag_UseOther", + } + + -- Check each flag and add to the list if true + for field, flagName in pairs(flagMap) do + if value[field] then + table.insert(flags, flagName) + end + end + + -- Join all flags with " | " + if #flags > 0 then + return table.concat(flags, " | ") + else + return "kIROpFlags_None" -- or return "" if you prefer empty string + end + end + + walk_instructions(insts, function(key, value, struct_name, parent_struct) + if value.is_leaf then + RAW( + "{kIROp_" + .. struct_name + .. ', {"' + .. value.mnemonic + .. '", ' + .. tostring(value.min_operands) + .. ", " + .. constructFlags(value) + .. "}}," + ) + end + end) +end + +-- The enum table +local function instEnums() + local insts = require("source/slang/slang-ir-insts.lua").insts + local output = {} + + -- Walk manually so we can output in postorder + local function traverse(tbl) + local first_child = nil + local last_child = nil + + -- First, process all children + for _, i in ipairs(tbl) do + local key, value = next(i) + if value.is_leaf then + -- Leaf instruction + RAW(" kIROp_" .. value.struct_name .. ",") + + -- Track first and last child + if first_child == nil then + first_child = "kIROp_" .. value.struct_name + end + last_child = "kIROp_" .. value.struct_name + else + -- Parent instruction - recurse first + local child_first, child_last = traverse(value) + + -- Track first and last child across all children + if first_child == nil then + first_child = child_first + end + if child_last then + last_child = child_last + end + + -- Then add parent entries + if child_first and child_last then + RAW(" kIROp_First" .. value.struct_name .. " = " .. child_first .. ",") + RAW(" kIROp_Last" .. value.struct_name .. " = " .. child_last .. ",") + end + end + end + + return first_child, last_child + end + + traverse(insts) + return table.concat(output, "\n") +end + +return { + leafInst = function(args) + return leafInst(tostring(fiddle.current_decl):gsub("^IR", ""), args) + end, + baseInst = function(args) + return baseInst(tostring(fiddle.current_decl):gsub("^IR", ""), args) + end, + allOtherInstStructs = allOtherInstStructs, + instStructForwardDecls = instStructForwardDecls, + instInfoEntries = instInfoEntries, + instEnums = instEnums, +} diff --git a/source/slang/slang-lower-to-ir.cpp b/source/slang/slang-lower-to-ir.cpp index 42a71764c40..ed4336ff9c8 100644 --- a/source/slang/slang-lower-to-ir.cpp +++ b/source/slang/slang-lower-to-ir.cpp @@ -1779,7 +1779,7 @@ struct ValLoweringVisitor : ValVisitorgetSup()); auto witnessTableType = irBuilder->getWitnessTableType(supType); ShortList captures; - if (auto expandType = as(subType)) + if (auto expandType = as(subType)) { for (UInt i = 0; i < expandType->getCaptureCount(); i++) { @@ -4753,7 +4753,7 @@ struct ExprLoweringVisitorBase : public ExprVisitor auto irBuilder = getBuilder(); auto irType = lowerType(context, expr->type); List irCapturedPacks; - if (auto expandType = as(irType)) + if (auto expandType = as(irType)) { for (UInt i = 0; i < expandType->getCaptureCount(); i++) { @@ -8270,10 +8270,10 @@ struct DeclLoweringVisitor : DeclVisitor void ensureInsertAtGlobalScope(IRBuilder* builder) { auto inst = builder->getInsertLoc().getInst(); - if (inst->getOp() == kIROp_Module) + if (inst->getOp() == kIROp_ModuleInst) return; - while (inst && inst->getParent() && inst->getParent()->getOp() != kIROp_Module) + while (inst && inst->getParent() && inst->getParent()->getOp() != kIROp_ModuleInst) { inst = inst->getParent(); } @@ -11312,7 +11312,7 @@ struct DeclLoweringVisitor : DeclVisitor debugType); // Add a decoration to link the function to its debug function - getBuilder()->addDecoration(irFunc, kIROp_DebugFunctionDecoration, debugFuncCallee); + getBuilder()->addDecoration(irFunc, kIROp_DebugFuncDecoration, debugFuncCallee); } } diff --git a/source/slang/slang-serialize-ir.cpp b/source/slang/slang-serialize-ir.cpp index 662f8acf182..093643d09fc 100644 --- a/source/slang/slang-serialize-ir.cpp +++ b/source/slang/slang-serialize-ir.cpp @@ -530,7 +530,7 @@ Result IRSerialReader::read( { // Check that insts[1] is the module inst const Ser::Inst& srcInst = data.m_insts[1]; - SLANG_RELEASE_ASSERT(srcInst.m_op == kIROp_Module); + SLANG_RELEASE_ASSERT(srcInst.m_op == kIROp_ModuleInst); SLANG_ASSERT(srcInst.m_payloadType == PayloadType::Empty); // The root IR instruction for the module will already have diff --git a/tools/slang-fiddle/README.md b/tools/slang-fiddle/README.md index 19bda6e8dc2..105a9a8e123 100644 --- a/tools/slang-fiddle/README.md +++ b/tools/slang-fiddle/README.md @@ -153,3 +153,17 @@ For example, given the input above, the generated output for the template might #include "my-class-forward-decls.h.fiddle" #endif ``` + +Inside templates there is a global defined `THIS_FILE` which is the file path +of the C++ source containing the splice. This can be used to load adjacent lua +files for example. + +Lua Function Calls +------------------ + +A more lightweight alternative to templates is to call +`FIDDLE(myLuaFunction(my, parameters))`. This will load a lua file at +`current_cpp_source_path.cpp.lua` and call the `myLuaFunction` function in the +table returned by that lua file. Inside such splices a `fiddle` global table is +available, containing a `current_decl` member if available, pointing to the +namespace or class/struct containing this splice. diff --git a/tools/slang-fiddle/slang-fiddle-scrape.cpp b/tools/slang-fiddle/slang-fiddle-scrape.cpp index 763ef8f48aa..a961831305f 100644 --- a/tools/slang-fiddle/slang-fiddle-scrape.cpp +++ b/tools/slang-fiddle/slang-fiddle-scrape.cpp @@ -1,6 +1,7 @@ // slang-fiddle-scrape.cpp #include "slang-fiddle-scrape.h" +#include "core/slang-string-util.h" #include "slang-fiddle-script.h" namespace fiddle @@ -238,6 +239,8 @@ struct Parser RefPtr parseCppSimpleTypeSpecififer() { + while (advanceIf("const") || advanceIf("static")) + ; switch (peekType()) { @@ -397,14 +400,14 @@ struct Parser addDecl(decl); WithParentDecl withParent(this, decl); - // We expect any `FIDDLE()`-marked aggregate type - // declaration to start with a `FIDDLE(...)` invocation, - // so that there is a suitable insertion point for - // the expansion step. + // We expect any `FIDDLE()`-marked aggregate type declaration to start + // with a `FIDDLE(...)` or `FIDDLE(myFunc(a,b,c))` invocation, so that + // there is a suitable insertion point for the expansion step or the + // user has specific a custom step // { auto saved = _cursor; - bool found = peekFiddleEllipsisInvocation(); + bool found = peekFiddleEllipsisInvocation() || peekFiddleLuaCall(); _cursor = saved; if (!found) { @@ -433,6 +436,15 @@ struct Parser return true; } + bool peekFiddleLuaCall() + { + auto saved = _cursor; + const bool found = advanceIf(TokenType::Identifier) && + (peekType() == TokenType::LParent || peekType() == TokenType::LBrace); + _cursor = saved; + return found; + } + RefPtr parseCppSimpleDeclarator() { switch (peekType()) @@ -468,7 +480,8 @@ struct Parser RefPtr parseCppDeclarator() { - advanceIf("const"); + while (advanceIf("const") || advanceIf("static")) + ; if (advanceIf(TokenType::OpMul)) { @@ -559,20 +572,30 @@ struct Parser return modifiers; case TokenType::Identifier: + if (advanceIf("abstract")) + { + modifiers.add(new AbstractModifier()); + } + else if (advanceIf("hidden")) + { + modifiers.add(new HiddenModifier()); + } + else + { + return modifiers; + } break; - } - if (advanceIf("abstract")) - { - modifiers.add(new AbstractModifier()); - } - else if (advanceIf("hidden")) - { - modifiers.add(new HiddenModifier()); - } - else - { - return modifiers; + case TokenType::LBrace: + { + const auto b = read(); + StringBuilder sb; + sb << b.getContent(); + for (int i = 0; i < b.getSkipCount(); ++i) + sb << read().getContent() << " "; + modifiers.add(new TableModifier(std::move(sb))); + } + break; } } @@ -772,20 +795,41 @@ struct Parser if (peekType() != TokenType::RParent) { - // In this case we are expecting a fiddle-mode declaration - // to appear, in which case we will allow any number of full - // fiddle-mode declarations, but won't expect a C++-mode - // declaration to follow. - - // TODO: We should associate these declarations - // as children of the `FiddleMacroInvocation`, - // so that they can be emitted as part of its - // expansion (if we decide to make more use - // of the `FIDDLE()` approach...). - - parseFiddleModeDecls(fiddleModifiers); - expect(TokenType::RParent); - return; + if (peekFiddleLuaCall()) + { + StringBuilder sb; + const auto f = expect(TokenType::Identifier); + const auto b = read(); + sb << f.getContent() << b.getContent(); + for (int i = 0; i < b.getSkipCount(); ++i) + sb << read().getContent() << " "; + auto fiddleLuaCall = RefPtr(new FiddleLuaCallInvocation()); + fiddleLuaCall->fiddleToken = fiddleToken; + fiddleLuaCall->parentDecl = _currentParentDecl; + fiddleLuaCall->callString = std::move(sb); + addDecl(fiddleLuaCall); + + expect(TokenType::RParent); + return; + } + else + { + + // In this case we are expecting a fiddle-mode declaration + // to appear, in which case we will allow any number of full + // fiddle-mode declarations, but won't expect a C++-mode + // declaration to follow. + + // TODO: We should associate these declarations + // as children of the `FiddleMacroInvocation`, + // so that they can be emitted as part of its + // expansion (if we decide to make more use + // of the `FIDDLE()` approach...). + + parseFiddleModeDecls(fiddleModifiers); + expect(TokenType::RParent); + return; + } } expect(TokenType::RParent); } @@ -1037,6 +1081,9 @@ struct CheckContext else if (as(decl)) { } + else if (as(decl)) + { + } else { sink.diagnose(SourceLoc(), Diagnostics::unexpected, "case in checkDecl", "known type"); @@ -1093,6 +1140,7 @@ struct CheckContext } }; +void push(lua_State* L, Val* val); // Emit @@ -1102,6 +1150,7 @@ struct EmitContext SourceManager& _sourceManager; RefPtr _module; StringBuilder& _builder; + DiagnosticSink& _sink; public: EmitContext( @@ -1109,9 +1158,8 @@ struct EmitContext DiagnosticSink& sink, SourceManager& sourceManager, LogicalModule* module) - : _builder(builder), _sourceManager(sourceManager), _module(module) + : _builder(builder), _sourceManager(sourceManager), _module(module), _sink(sink) { - SLANG_UNUSED(sink); } void emitMacrosRec(Decl* decl) @@ -1131,20 +1179,23 @@ struct EmitContext { emitMacroForFiddleInvocation(fiddleMacroInvocation); } + else if (const auto fiddleLuaCallInvocation = as(decl)) + { + emitMacroForFiddleLuaCallInvocation(fiddleLuaCallInvocation); + } else { // do nothing with most decls } } - void emitMacroForFiddleInvocation(FiddleMacroInvocation* fiddleInvocation) - { - SourceLoc loc = fiddleInvocation->fiddleToken.getLoc(); - auto humaneLoc = _sourceManager.getHumaneLoc(loc); - auto lineNumber = humaneLoc.line; - #define MACRO_LINE_ENDING " \\\n" + void emitMacroForFiddleInvocationPreamble(const TokenWithTrivia& fiddleToken) + { + const auto loc = fiddleToken.getLoc(); + const auto humaneLoc = _sourceManager.getHumaneLoc(loc); + const auto lineNumber = humaneLoc.line; // Un-define the old `FIDDLE_#` macro for the // given line number, since this file might // be pulling in another generated header @@ -1160,6 +1211,52 @@ struct EmitContext _builder.append(lineNumber); _builder.append("(...)"); _builder.append(MACRO_LINE_ENDING); + } + + void emitMacroForFiddleInvocationPostamble() { _builder.append("/* end */\n\n"); } + + void emitMacroForFiddleLuaCallInvocation(FiddleLuaCallInvocation* fiddleInvocation) + { + _builder.append("/*\n"); + _builder.append(fiddleInvocation->callString); + _builder.append("\n*/\n"); + + emitMacroForFiddleInvocationPreamble(fiddleInvocation->fiddleToken); + + const auto file = + _sourceManager.getHumaneLoc(fiddleInvocation->fiddleToken.getLoc()).pathInfo.getName(); + StringBuilder sb; + sb << "require(\"" << file << ".lua\")." << fiddleInvocation->callString; + + // Create the fiddle table + const auto L = getLuaState(); + lua_newtable(L); + push(L, fiddleInvocation->parentDecl); + lua_setfield(L, -2, "current_decl"); + lua_setglobal(L, "fiddle"); + + const auto output = evaluateLuaExpression( + fiddleInvocation->fiddleToken.getLoc(), + file, + sb.produceString(), + &_sink); + + // Deregister the fiddle table + lua_pushnil(L); + lua_setglobal(L, "fiddle"); + + _builder.append(StringUtil::replaceAll( + output.getUnownedSlice(), + UnownedStringSlice("\n"), + UnownedStringSlice(MACRO_LINE_ENDING))); + + _builder.append(MACRO_LINE_ENDING); + emitMacroForFiddleInvocationPostamble(); + } + + void emitMacroForFiddleInvocation(FiddleMacroInvocation* fiddleInvocation) + { + emitMacroForFiddleInvocationPreamble(fiddleInvocation->fiddleToken); auto decl = as(fiddleInvocation->node); if (decl) @@ -1196,7 +1293,7 @@ struct EmitContext } _builder.append("public:" MACRO_LINE_ENDING); } - _builder.append("/* end */\n\n"); + emitMacroForFiddleInvocationPostamble(); } void emitTypedDecl(Expr* expr, const char* name) @@ -1567,6 +1664,14 @@ void push(lua_State* L, List const& values) } } +List> getDirectSubclasses(AggTypeDecl* decl) +{ + List> result; + for (auto subclass : decl->directSubTypeDecls) + result.add(subclass); + return result; +} + void getAllSubclasses(AggTypeDecl* decl, List>& ioSubclasses) { ioSubclasses.add(decl); @@ -1605,6 +1710,57 @@ int _indexVal(lua_State* L) Val* val = (Val*)lua_touserdata(L, 1); char const* name = lua_tostring(L, 2); + // If we have some user data attached to this declaration, index that + if (auto decl = as(val)) + { + if (auto tableModifier = decl->findModifier()) + { + // Check if we have a cached table + if (tableModifier->tableRef == LUA_NOREF) + { + // Evaluate the table string and cache it + std::string tableCode = + "return " + std::string(tableModifier->tableSource.getBuffer()); + + if (luaL_dostring(L, tableCode.c_str()) == LUA_OK) + { + // Store the table in the registry + tableModifier->tableRef = luaL_ref(L, LUA_REGISTRYINDEX); + } + else + { + // Handle error - pop error message and continue + lua_pop(L, 1); + } + } + + // If we have a cached table, try to index it + if (tableModifier->tableRef != LUA_NOREF) + { + // Get the cached table from registry + lua_rawgeti(L, LUA_REGISTRYINDEX, tableModifier->tableRef); + + // Index the table with the requested name + lua_pushstring(L, name); + lua_gettable(L, -2); + + // Remove the table from stack, leaving just the result + lua_remove(L, -2); + + // Check if we found something + if (!lua_isnil(L, -1)) + { + return 1; + } + else + { + lua_pop(L, 1); // Pop the nil + // Fall through to check other properties + } + } + } + } + if (auto containerDecl = as(val)) { for (auto m : containerDecl->members) @@ -1617,18 +1773,25 @@ int _indexVal(lua_State* L) } } - if (auto classDecl = as(val)) + if (auto aggTypeDecl = as(val)) { + if (strcmp(name, "directSubclasses") == 0) + { + auto value = getDirectSubclasses(aggTypeDecl); + push(L, value); + return 1; + } + if (strcmp(name, "subclasses") == 0) { - auto value = getAllSubclasses(classDecl); + auto value = getAllSubclasses(aggTypeDecl); push(L, value); return 1; } if (strcmp(name, "directSuperClass") == 0) { - push(L, classDecl->directBaseType); + push(L, aggTypeDecl->directBaseType); return 1; } } @@ -1657,6 +1820,23 @@ int _indexVal(lua_State* L) } } + if (auto varDecl = as(val)) + { + if (strcmp(name, "initExpr") == 0) + { + // TODO: do any expression here + if (const auto literalExpr = as(varDecl->initExpr)) + { + lua_pushlstring( + L, + literalExpr->token.getContent().begin(), + literalExpr->token.getContent().getLength()); + return 1; + } + return 0; + } + } + return 0; } diff --git a/tools/slang-fiddle/slang-fiddle-scrape.h b/tools/slang-fiddle/slang-fiddle-scrape.h index 5cd0b6d057d..0505766743f 100644 --- a/tools/slang-fiddle/slang-fiddle-scrape.h +++ b/tools/slang-fiddle/slang-fiddle-scrape.h @@ -2,6 +2,7 @@ #pragma once #include "compiler-core/slang-lexer.h" +#include "lua/lauxlib.h" #include "slang-fiddle-diagnostics.h" namespace fiddle @@ -109,6 +110,16 @@ class AbstractModifier : public ModifierNode class HiddenModifier : public ModifierNode { }; +class TableModifier : public ModifierNode +{ +public: + TableModifier(String s) + : tableSource(s) + { + } + String tableSource; + int tableRef = LUA_NOREF; +}; enum class Mode { @@ -207,6 +218,14 @@ class FiddleMacroInvocation : public Decl RefPtr node; // the node whose generated content should get emitted... }; +class FiddleLuaCallInvocation : public Decl +{ +public: + TokenWithTrivia fiddleToken; // the actual `FIDDLE` identifier + String callString; + RefPtr parentDecl; +}; + class UncheckedExpr : public Expr { }; diff --git a/tools/slang-fiddle/slang-fiddle-script.cpp b/tools/slang-fiddle/slang-fiddle-script.cpp index 24648819981..e713a379834 100644 --- a/tools/slang-fiddle/slang-fiddle-script.cpp +++ b/tools/slang-fiddle/slang-fiddle-script.cpp @@ -1,10 +1,13 @@ // slang-fiddle-script.cpp #include "slang-fiddle-script.h" +#include "compiler-core/slang-diagnostic-sink.h" #include "lua/lapi.h" #include "lua/lauxlib.h" #include "lua/lualib.h" +#include + namespace fiddle { DiagnosticSink* _sink = nullptr; @@ -114,6 +117,35 @@ int _template(lua_State* L) lua_State* L = nullptr; +// Add a custom searcher that handles relative paths +// So we can do things like require("source/slang/foo.lua") +static int path_searcher(lua_State* L) +{ + const char* modname = luaL_checkstring(L, 1); + + if (luaL_loadfile(L, modname) == LUA_OK) + { + lua_pushstring(L, modname); // Push filename as second return + return 2; + } + + // Not found + lua_pushfstring(L, "\n\tno file '%s'", modname); + return 1; +} + +void install_path_searcher(lua_State* L) +{ + lua_getglobal(L, "package"); + lua_getfield(L, -1, "searchers"); + + // Insert at position 2 (after preload) + lua_pushcfunction(L, path_searcher); + lua_rawseti(L, -2, 2); + + lua_pop(L, 2); +} + void ensureLuaInitialized() { if (L) @@ -137,6 +169,8 @@ void ensureLuaInitialized() lua_pushcclosure(L, &_template, 0); lua_setglobal(L, "TEMPLATE"); + install_path_searcher(L); + // TODO: register custom stuff here... } @@ -146,6 +180,33 @@ lua_State* getLuaState() return L; } +static void setupLuaEnvironment(const String& originalFileName) +{ + ensureLuaInitialized(); + + lua_pushstring(L, originalFileName.getBuffer()); + lua_setglobal(L, "THIS_FILE"); + + lua_pushcfunction(L, &_handleLuaErrorRaised); +} + +static void handleLuaError( + SourceLoc loc, + DiagnosticSink* sink, + const char* errorType, + DiagnosticInfo diagnosticID) +{ + size_t size = 0; + char const* buffer = lua_tolstring(L, -1, &size); + String message = UnownedStringSlice(buffer, size); + message = message + "\n"; + + sink->diagnose(loc, diagnosticID, message); + + String abortMessage = "fiddle failed during Lua "; + abortMessage = abortMessage + errorType; + SLANG_ABORT_COMPILATION(abortMessage.getBuffer()); +} String evaluateScriptCode( SourceLoc loc, @@ -157,39 +218,79 @@ String evaluateScriptCode( _builder = &builder; _templateCounter = 0; - ensureLuaInitialized(); + setupLuaEnvironment(originalFileName); String luaChunkName = "@" + originalFileName; - lua_pushcfunction(L, &_handleLuaErrorRaised); - if (LUA_OK != luaL_loadbuffer( L, scriptSource.getBuffer(), scriptSource.getLength(), luaChunkName.getBuffer())) { - size_t size = 0; - char const* buffer = lua_tolstring(L, -1, &size); - String message = UnownedStringSlice(buffer, size); - message = message + "\n"; - - sink->diagnose(loc, fiddle::Diagnostics::scriptLoadError, message); - SLANG_ABORT_COMPILATION("fiddle failed during Lua script loading"); + handleLuaError(loc, sink, "script loading", fiddle::Diagnostics::scriptLoadError); } if (LUA_OK != lua_pcall(L, 0, 0, -2)) { - size_t size = 0; - char const* buffer = lua_tolstring(L, -1, &size); - String message = UnownedStringSlice(buffer, size); - message = message + "\n"; - - sink->diagnose(loc, fiddle::Diagnostics::scriptExecutionError, message); - SLANG_ABORT_COMPILATION("fiddle failed during Lua script execution"); + handleLuaError(loc, sink, "script execution", fiddle::Diagnostics::scriptExecutionError); } _builder = nullptr; return builder.produceString(); } + +String evaluateLuaExpression( + SourceLoc loc, + String originalFileName, + String luaExpression, + DiagnosticSink* sink) +{ + setupLuaEnvironment(originalFileName); + + String luaChunkName = "@" + originalFileName; + + // Wrap expression in return statement to get its value + String wrappedExpression = "return " + luaExpression; + + if (LUA_OK != luaL_loadbuffer( + L, + wrappedExpression.getBuffer(), + wrappedExpression.getLength(), + luaChunkName.getBuffer())) + { + handleLuaError(loc, sink, "expression loading", fiddle::Diagnostics::scriptLoadError); + } + + // Execute and expect 1 return value + if (LUA_OK != lua_pcall(L, 0, 1, -2)) + { + handleLuaError( + loc, + sink, + "expression evaluation", + fiddle::Diagnostics::scriptExecutionError); + } + + // Convert the result to string + size_t resultSize = 0; + const char* resultBuffer = lua_tolstring(L, -1, &resultSize); + + if (!resultBuffer) + { + sink->diagnose( + loc, + fiddle::Diagnostics::scriptExecutionError, + "Lua expression did not return a string value\n"); + SLANG_ABORT_COMPILATION("fiddle failed: non-string expression result"); + } + + String result; + result.append(resultBuffer, resultSize); + + // Pop the result and error handler + lua_pop(L, 2); + + return result; +} } // namespace fiddle diff --git a/tools/slang-fiddle/slang-fiddle-script.h b/tools/slang-fiddle/slang-fiddle-script.h index 98cdfa148f9..94bda453b05 100644 --- a/tools/slang-fiddle/slang-fiddle-script.h +++ b/tools/slang-fiddle/slang-fiddle-script.h @@ -20,4 +20,10 @@ String evaluateScriptCode( String originalFileName, String scriptSource, DiagnosticSink* sink); + +String evaluateLuaExpression( + SourceLoc loc, + String originalFileName, + String scriptSource, + DiagnosticSink* sink); } // namespace fiddle