diff options
Diffstat (limited to 'source')
| -rw-r--r-- | source/slang/emit.cpp | 80 | ||||
| -rw-r--r-- | source/slang/ir-inst-defs.h | 75 | ||||
| -rw-r--r-- | source/slang/ir-insts.h | 256 | ||||
| -rw-r--r-- | source/slang/ir-legalize-types.cpp | 54 | ||||
| -rw-r--r-- | source/slang/ir-missing-return.cpp | 7 | ||||
| -rw-r--r-- | source/slang/ir-restructure-scoping.cpp | 2 | ||||
| -rw-r--r-- | source/slang/ir-sccp.cpp | 14 | ||||
| -rw-r--r-- | source/slang/ir-serialize.cpp | 438 | ||||
| -rw-r--r-- | source/slang/ir-serialize.h | 9 | ||||
| -rw-r--r-- | source/slang/ir-ssa.cpp | 19 | ||||
| -rw-r--r-- | source/slang/ir-validate.cpp | 11 | ||||
| -rw-r--r-- | source/slang/ir.cpp | 609 | ||||
| -rw-r--r-- | source/slang/ir.h | 340 | ||||
| -rw-r--r-- | source/slang/legalize-types.cpp | 2 | ||||
| -rw-r--r-- | source/slang/lower-to-ir.cpp | 84 | ||||
| -rw-r--r-- | source/slang/slang.natvis | 28 |
16 files changed, 805 insertions, 1223 deletions
diff --git a/source/slang/emit.cpp b/source/slang/emit.cpp index ba1b2177a..d7abbff24 100644 --- a/source/slang/emit.cpp +++ b/source/slang/emit.cpp @@ -1419,7 +1419,7 @@ struct EmitVisitor bool isTargetIntrinsicModifierApplicable( IRTargetIntrinsicDecoration* decoration) { - auto targetName = String(decoration->targetName); + auto targetName = String(decoration->getTargetName()); // If no target name was specified, then the modifier implicitly // applies to all targets. @@ -2170,7 +2170,7 @@ struct EmitVisitor // then use that name instead. if(auto intrinsicDecoration = findTargetIntrinsicDecoration(context, inst)) { - return String(intrinsicDecoration->definition); + return String(intrinsicDecoration->getDefinition()); } // If we have a name hint on the instruction, then we will try to use that @@ -2200,7 +2200,7 @@ struct EmitVisitor // name hint already ends with one. // - String nameHint = nameHintDecoration->name->text; + String nameHint = nameHintDecoration->getName(); nameHint = scrubName(nameHint); StringBuilder sb; @@ -2928,9 +2928,9 @@ struct EmitVisitor EmitContext* /* ctx */, IRInst* inst) { - for (auto dd = inst->firstDecoration; dd; dd = dd->next) + for(auto dd : inst->getDecorations()) { - if (dd->op != kIRDecorationOp_TargetIntrinsic) + if (dd->op != kIROp_TargetIntrinsicDecoration) continue; auto targetIntrinsic = (IRTargetIntrinsicDecoration*)dd; @@ -2978,7 +2978,7 @@ struct EmitVisitor args++; argCount--; - auto name = String(targetIntrinsic->definition); + auto name = String(targetIntrinsic->getDefinition()); if(isOrdinaryName(name)) @@ -3512,19 +3512,19 @@ struct EmitVisitor decoratedValue = getSpecializedValue(specInst); } - for( auto decoration = decoratedValue->firstDecoration; decoration; decoration = decoration->next ) + for( auto decoration : decoratedValue->getDecorations() ) { switch(decoration->op) { default: break; - case kIRDecorationOp_RequireGLSLExtension: - requireGLSLExtension(String(((IRRequireGLSLExtensionDecoration*)decoration)->extensionName)); + case kIROp_RequireGLSLExtensionDecoration: + requireGLSLExtension(String(((IRRequireGLSLExtensionDecoration*)decoration)->getExtensionName())); break; - case kIRDecorationOp_RequireGLSLVersion: - requireGLSLVersion(int(((IRRequireGLSLVersionDecoration*)decoration)->languageVersion)); + case kIROp_RequireGLSLVersionDecoration: + requireGLSLVersion(int(((IRRequireGLSLVersionDecoration*)decoration)->getLanguageVersion())); break; } } @@ -3800,7 +3800,7 @@ struct EmitVisitor auto prec = kEOp_Postfix; needClose = maybeEmitParens(outerPrec, prec); - emit(decoration->outerArrayName); + emit(decoration->getOuterArrayName()); emit("["); emitIROperand(ctx, inst->getOperand(1), mode, kEOp_General); emit("]."); @@ -3968,12 +3968,6 @@ struct EmitVisitor } break; - case kIROp_NotePatchConstantFunc: - { - // No-op - break; - } - case kIROp_Var: { auto ptrType = cast<IRPtrType>(inst->getDataType()); @@ -4108,13 +4102,13 @@ struct EmitVisitor if (auto semanticDecoration = inst->findDecoration<IRSemanticDecoration>()) { Emit(" : "); - emit(semanticDecoration->semanticName); + emit(semanticDecoration->getSemanticName()); return; } if(auto layoutDecoration = inst->findDecoration<IRLayoutDecoration>()) { - auto layout = layoutDecoration->layout; + auto layout = layoutDecoration->getLayout(); if(auto varLayout = layout->dynamicCast<VarLayout>()) { emitIRSemantics(ctx, varLayout); @@ -4137,7 +4131,7 @@ struct EmitVisitor if (!decoration) return nullptr; - return (VarLayout*) decoration->layout; + return (VarLayout*) decoration->getLayout(); } void emitIRLayoutSemantics( @@ -4354,7 +4348,7 @@ struct EmitVisitor // if (auto loopControlDecoration = loopInst->findDecoration<IRLoopControlDecoration>()) { - switch (loopControlDecoration->mode) + switch (loopControlDecoration->getMode()) { case kIRLoopControl_Unroll: // Note: loop unrolling control is only available in HLSL, not GLSL @@ -4468,23 +4462,6 @@ struct EmitVisitor } } - - - IRInst* findFirstInst(IRFunc* irFunc, IROp op) - { - for (auto block : irFunc->getBlocks()) - { - for (auto inst : block->getChildren()) - { - if (inst->op == op) - { - return inst; - } - } - } - return nullptr; - } - void emitAttributeSingleString(const char* name, FuncDecl* entryPoint, Attribute* attrib) { assert(attrib); @@ -4543,11 +4520,11 @@ struct EmitVisitor { SLANG_UNUSED(attrib); - auto irPatchFunc = static_cast<IRNotePatchConstantFunc*>(findFirstInst(irFunc, kIROp_NotePatchConstantFunc)); + auto irPatchFunc = irFunc->findDecoration<IRPatchConstantFuncDecoration>(); assert(irPatchFunc); if (!irPatchFunc) { - SLANG_DIAGNOSE_UNEXPECTED(getSink(), entryPoint->loc, "Unable to find NotePatchConstantFunc instruction"); + SLANG_DIAGNOSE_UNEXPECTED(getSink(), entryPoint->loc, "Unable to find [patchConstantFunc(...)] decoration"); return; } @@ -4897,7 +4874,7 @@ struct EmitVisitor { if (auto layoutDecor = pp->findDecoration<IRLayoutDecoration>()) { - Layout* layout = layoutDecor->layout; + Layout* layout = layoutDecor->getLayout(); VarLayout* varLayout = dynamic_cast<VarLayout*>(layout); if (varLayout) @@ -5053,7 +5030,7 @@ struct EmitVisitor { if( auto layoutDecoration = func->findDecoration<IRLayoutDecoration>() ) { - return layoutDecoration->layout->dynamicCast<EntryPointLayout>(); + return layoutDecoration->getLayout()->dynamicCast<EntryPointLayout>(); } return nullptr; } @@ -5062,7 +5039,7 @@ struct EmitVisitor { if (auto layoutDecoration = func->findDecoration<IRLayoutDecoration>()) { - if (auto entryPointLayout = layoutDecoration->layout->dynamicCast<EntryPointLayout>()) + if (auto entryPointLayout = layoutDecoration->getLayout()->dynamicCast<EntryPointLayout>()) { return entryPointLayout; } @@ -5268,13 +5245,13 @@ struct EmitVisitor bool isGLSL = (ctx->shared->target == CodeGenTarget::GLSL); bool anyModifiers = false; - for(auto dd = varInst->firstDecoration; dd; dd = dd->next) + for(auto dd : varInst->getDecorations()) { - if(dd->op != kIRDecorationOp_InterpolationMode) + if(dd->op != kIROp_InterpolationModeDecoration) continue; auto decoration = (IRInterpolationModeDecoration*)dd; - auto mode = decoration->mode; + auto mode = decoration->getMode(); switch(mode) { @@ -6055,7 +6032,7 @@ struct EmitVisitor // We expect the terminator to be a `return` // instruction with a value. - auto returnInst = (IRReturnVal*) block->getLastInst(); + auto returnInst = (IRReturnVal*) block->getLastDecorationOrChild(); SLANG_RELEASE_ASSERT(returnInst->op == kIROp_ReturnVal); // We will emit the value in the `GlobalConstant` mode, which @@ -6188,12 +6165,9 @@ struct EmitVisitor ensureInstOperand(ctx, inst->getOperand(ii)); } - if(auto parentInst = as<IRParentInst>(inst)) + for(auto child : inst->getDecorationsAndChildren()) { - for(auto child : parentInst->getChildren()) - { - ensureInstOperandsRec(ctx, child); - } + ensureInstOperandsRec(ctx, child); } } diff --git a/source/slang/ir-inst-defs.h b/source/slang/ir-inst-defs.h index 09c11ed16..202e80bcf 100644 --- a/source/slang/ir-inst-defs.h +++ b/source/slang/ir-inst-defs.h @@ -149,45 +149,37 @@ INST(Nop, nop, 0, 0) // This is a parent instruction that holds zero or more // `field` instructions. // -// Note: we are being a bit slippery here, because a `struct` -// instruction is really an `IRParentInst`, but we want it -// to also be caught in any dynamic cast to `IRType`, so we -// ensure that it comes at the *end* of the range for `IRType`, -// and the start of the range for `IRParentInst` (and `IRGlobalValue`) INST(StructType, struct, 0, PARENT) INST_RANGE(Type, VoidType, StructType) -/*IRParentInst*/ +/*IRGlobalValue*/ - /*IRGlobalValue*/ + /*IRGlobalValueWithCode*/ + /* IRGlobalValueWIthParams*/ + INST(Func, func, 0, PARENT) + INST(Generic, generic, 0, PARENT) + INST_RANGE(GlobalValueWithParams, Func, Generic) - /*IRGlobalValueWithCode*/ - /* IRGlobalValueWIthParams*/ - INST(Func, func, 0, PARENT) - INST(Generic, generic, 0, PARENT) - INST_RANGE(GlobalValueWithParams, Func, Generic) + INST(GlobalVar, global_var, 0, 0) + INST(GlobalConstant, global_constant, 0, 0) + INST_RANGE(GlobalValueWithCode, Func, GlobalConstant) - INST(GlobalVar, global_var, 0, 0) - INST(GlobalConstant, global_constant, 0, 0) - INST_RANGE(GlobalValueWithCode, Func, GlobalConstant) + INST(StructKey, key, 0, 0) + INST(GlobalGenericParam, global_generic_param, 0, 0) + INST(WitnessTable, witness_table, 0, 0) - INST(StructKey, key, 0, 0) - INST(GlobalGenericParam, global_generic_param, 0, 0) - INST(WitnessTable, witness_table, 0, 0) +INST_RANGE(GlobalValue, StructType, WitnessTable) - INST_RANGE(GlobalValue, StructType, WitnessTable) +INST(Module, module, 0, PARENT) - INST(Module, module, 0, PARENT) - - INST(Block, block, 0, PARENT) - -INST_RANGE(ParentInst, StructType, Block) +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_RANGE(Constant, BoolLit, StringLit) @@ -363,7 +355,40 @@ INST(SampleGrad, sampleGrad, 4, 0) INST(GroupMemoryBarrierWithGroupSync, GroupMemoryBarrierWithGroupSync, 0, 0) -INST(NotePatchConstantFunc, notePatchConstantFunc, 1, 0) +/* Decoration */ + +INST(HighLevelDeclDecoration, highLevelDecl, 1, 0) + INST(LayoutDecoration, layout, 1, 0) + INST(LoopControlDecoration, loopControl, 1, 0) + /* TargetSpecificDecoration */ + INST(TargetDecoration, target, 1, 0) + INST(TargetIntrinsicDecoration, targetIntrinsic, 2, 0) + INST_RANGE(TargetSpecificDecoration, TargetDecoration, TargetIntrinsicDecoration) + INST(GLSLOuterArrayDecoration, glslOuterArray, 1, 0) + INST(SemanticDecoration, semantic, 1, 0) + INST(InterpolationModeDecoration, interpolationMode, 1, 0) + INST(NameHintDecoration, nameHint, 1, 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) + + INST(VulkanRayPayloadDecoration, vulkanRayPayload, 0, 0) + INST(VulkanHitAttributesDecoration, vulkanHitAttributes, 0, 0) + INST(RequireGLSLVersionDecoration, requireGLSLVersion, 1, 0) + INST(RequireGLSLExtensionDecoration, requireGLSLExtension, 1, 0) + INST(ReadNoneDecoration, readNone, 0, 0) + INST(VulkanCallablePayloadDecoration, vulkanCallablePayload, 0, 0) + INST(EarlyDepthStencilDecoration, earlyDepthStencil, 0, 0) + INST(GloballyCoherentDecoration, globallyCoherent, 0, 0) + INST(PatchConstantFuncDecoration, patchConstantFunc, 1, 0) + +INST_RANGE(Decoration, HighLevelDeclDecoration, PatchConstantFuncDecoration) + + +// + PSEUDO_INST(Pos) PSEUDO_INST(PreInc) diff --git a/source/slang/ir-insts.h b/source/slang/ir-insts.h index 31bc11ca4..c3d21a4bd 100644 --- a/source/slang/ir-insts.h +++ b/source/slang/ir-insts.h @@ -17,22 +17,36 @@ namespace Slang { class Decl; +struct IRDecoration : IRInst +{ + IR_PARENT_ISA(Decoration) + + IRDecoration* getNextDecoration() + { + return as<IRDecoration>(getNextInst()); + } +}; + // 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. struct IRHighLevelDeclDecoration : IRDecoration { - enum { kDecorationOp = kIRDecorationOp_HighLevelDecl }; + enum { kOp = kIROp_HighLevelDeclDecoration }; + IR_LEAF_ISA(HighLevelDeclDecoration) - Decl* decl; + IRPtrLit* getDeclOperand() { return cast<IRPtrLit>(getOperand(0)); } + Decl* getDecl() { return (Decl*) getDeclOperand()->getValue(); } }; // Associates an IR-level decoration with a source layout struct IRLayoutDecoration : IRDecoration { - enum { kDecorationOp = kIRDecorationOp_Layout }; + enum { kOp = kIROp_LayoutDecoration }; + IR_LEAF_ISA(LayoutDecoration) - Layout* layout; + IRPtrLit* getLayoutOperand() { return cast<IRPtrLit>(getOperand(0)); } + Layout* getLayout() { return (Layout*) getLayoutOperand()->getValue(); } }; enum IRLoopControl @@ -42,35 +56,60 @@ enum IRLoopControl struct IRLoopControlDecoration : IRDecoration { - enum { kDecorationOp = kIRDecorationOp_LoopControl }; + enum { kOp = kIROp_LoopControlDecoration }; + IR_LEAF_ISA(LoopControlDecoration) - IRLoopControl mode; + IRConstant* getModeOperand() { return cast<IRConstant>(getOperand(0)); } + + IRLoopControl getMode() + { + return IRLoopControl(getModeOperand()->value.intVal); + } }; struct IRTargetSpecificDecoration : IRDecoration { - // TODO: have a more structured representation of target specifiers - StringRepresentation* targetName; + IR_PARENT_ISA(TargetSpecificDecoration) + + IRStringLit* getTargetNameOperand() { return cast<IRStringLit>(getOperand(0)); } + + UnownedStringSlice getTargetName() + { + return getTargetNameOperand()->getStringSlice(); + } }; struct IRTargetDecoration : IRTargetSpecificDecoration { - enum { kDecorationOp = kIRDecorationOp_Target }; + enum { kOp = kIROp_TargetDecoration }; + IR_LEAF_ISA(TargetDecoration) }; struct IRTargetIntrinsicDecoration : IRTargetSpecificDecoration { - enum { kDecorationOp = kIRDecorationOp_TargetIntrinsic }; + enum { kOp = kIROp_TargetIntrinsicDecoration }; + IR_LEAF_ISA(TargetIntrinsicDecoration) + + IRStringLit* getDefinitionOperand() { return cast<IRStringLit>(getOperand(1)); } - StringRepresentation* definition; + UnownedStringSlice getDefinition() + { + return getDefinitionOperand()->getStringSlice(); + } }; struct IRGLSLOuterArrayDecoration : IRDecoration { - enum { kDecorationOp = kIRDecorationOp_GLSLOuterArray }; + enum { kOp = kIROp_GLSLOuterArrayDecoration }; + IR_LEAF_ISA(GLSLOuterArrayDecoration) + + IRStringLit* getOuterArraynameOperand() { return cast<IRStringLit>(getOperand(0)); } - char const* outerArrayName; + UnownedStringSlice getOuterArrayName() + { + return getOuterArraynameOperand()->getStringSlice(); + } }; // A decoration that marks a field key as having been associated @@ -84,9 +123,15 @@ struct IRGLSLOuterArrayDecoration : IRDecoration // struct IRSemanticDecoration : IRDecoration { - enum { kDecorationOp = kIRDecorationOp_Semantic }; + enum { kOp = kIROp_SemanticDecoration }; + IR_LEAF_ISA(SemanticDecoration) + + IRStringLit* getSemanticNameOperand() { return cast<IRStringLit>(getOperand(0)); } - Name* semanticName; + UnownedStringSlice getSemanticName() + { + return getSemanticNameOperand()->getStringSlice(); + } }; enum class IRInterpolationMode @@ -101,9 +146,15 @@ enum class IRInterpolationMode struct IRInterpolationModeDecoration : IRDecoration { - enum { kDecorationOp = kIRDecorationOp_InterpolationMode }; + enum { kOp = kIROp_InterpolationModeDecoration }; + IR_LEAF_ISA(InterpolationModeDecoration) - IRInterpolationMode mode; + IRConstant* getModeOperand() { return cast<IRConstant>(getOperand(0)); } + + IRInterpolationMode getMode() + { + return IRInterpolationMode(getModeOperand()->value.intVal); + } }; /// A decoration that provides a desired name to be used @@ -112,63 +163,69 @@ struct IRInterpolationModeDecoration : IRDecoration /// names, emit debug information, etc. struct IRNameHintDecoration : IRDecoration { - enum { kDecorationOp = kIRDecorationOp_NameHint }; + enum { kOp = kIROp_NameHintDecoration }; + IR_LEAF_ISA(NameHintDecoration) - Name* name; + IRStringLit* getNameOperand() { return cast<IRStringLit>(getOperand(0)); } + + UnownedStringSlice getName() + { + return getNameOperand()->getStringSlice(); + } }; +#define IR_SIMPLE_DECORATION(NAME) \ + struct IR##NAME : IRDecoration \ + { \ + enum { kOp = kIROp_##NAME }; \ + IR_LEAF_ISA(NAME) \ + }; \ + /**/ + /// A decoration that indicates that a variable represents /// a vulkan ray payload, and should have a location assigned /// to it. -struct IRVulkanRayPayloadDecoration : IRDecoration -{ - enum { kDecorationOp = kIRDecorationOp_VulkanRayPayload }; -}; +IR_SIMPLE_DECORATION(VulkanRayPayloadDecoration) /// A decoration that indicates that a variable represents /// a vulkan callable shader payload, and should have a location assigned /// to it. -struct IRVulkanCallablePayloadDecoration : IRDecoration -{ - enum { kDecorationOp = kIRDecorationOp_VulkanCallablePayload }; -}; +IR_SIMPLE_DECORATION(VulkanCallablePayloadDecoration) /// A decoration that indicates that a variable represents /// vulkan hit attributes, and should have a location assigned /// to it. -struct IRVulkanHitAttributesDecoration : IRDecoration -{ - enum { kDecorationOp = kIRDecorationOp_VulkanHitAttributes }; -}; +IR_SIMPLE_DECORATION(VulkanHitAttributesDecoration) struct IRRequireGLSLVersionDecoration : IRDecoration { - enum { kDecorationOp = kIRDecorationOp_RequireGLSLVersion }; + enum { kOp = kIROp_RequireGLSLVersionDecoration }; + IR_LEAF_ISA(RequireGLSLVersionDecoration) + + IRConstant* getLanguageVersionOperand() { return cast<IRConstant>(getOperand(0)); } - Int languageVersion; + Int getLanguageVersion() + { + return Int(getLanguageVersionOperand()->value.intVal); + } }; struct IRRequireGLSLExtensionDecoration : IRDecoration { - enum { kDecorationOp = kIRDecorationOp_RequireGLSLExtension }; + enum { kOp = kIROp_RequireGLSLExtensionDecoration }; + IR_LEAF_ISA(RequireGLSLExtensionDecoration) - StringRepresentation* extensionName; -}; + IRStringLit* getExtensionNameOperand() { return cast<IRStringLit>(getOperand(0)); } -struct IRReadNoneDecoration : IRDecoration -{ - enum { kDecorationOp = kIRDecorationOp_ReadNone }; -}; - -struct IREarlyDepthStencilDecoration : IRDecoration -{ - enum { kDecorationOp = kIRDecorationOp_EarlyDepthStencil }; + UnownedStringSlice getExtensionName() + { + return getExtensionNameOperand()->getStringSlice(); + } }; -struct IRGloballyCoherentDecoration : IRDecoration -{ - enum { kDecorationOp = kIRDecorationOp_GloballyCoherent }; -}; +IR_SIMPLE_DECORATION(ReadNoneDecoration) +IR_SIMPLE_DECORATION(EarlyDepthStencilDecoration) +IR_SIMPLE_DECORATION(GloballyCoherentDecoration) // An instruction that specializes another IR value // (representing a generic) to a particular set of generic arguments @@ -426,10 +483,12 @@ struct IRSwizzledStore : IRInst }; -struct IRNotePatchConstantFunc: IRInst +struct IRPatchConstantFuncDecoration : IRDecoration { + enum { kOp = kIROp_PatchConstantFuncDecoration }; + IR_LEAF_ISA(PatchConstantFuncDecoration) + IRInst* getFunc() { return getOperand(0); } - IR_LEAF_ISA(NotePatchConstantFunc) }; // An IR `var` instruction conceptually represents @@ -573,7 +632,7 @@ struct IRBuilder // The current parent being inserted into (this might // be the global scope, a function, a block inside // a function, etc.) - IRParentInst* insertIntoParent = nullptr; + IRInst* insertIntoParent = nullptr; // // An instruction in the current parent that we should insert before IRInst* insertBeforeInst = nullptr; @@ -585,7 +644,7 @@ struct IRBuilder // that we are inserting into (if any). IRGlobalValueWithCode* getFunc(); - void setInsertInto(IRParentInst* insertInto); + void setInsertInto(IRInst* insertInto); void setInsertBefore(IRInst* insertBefore); IRBuilderSourceLocRAII* sourceLocInfo = nullptr; @@ -596,6 +655,7 @@ struct IRBuilder IRInst* getIntValue(IRType* type, IRIntegerValue value); IRInst* getFloatValue(IRType* type, IRFloatingPointValue value); IRStringLit* getStringValue(const UnownedStringSlice& slice); + IRPtrLit* getPtrValue(void* value); IRBasicType* getBasicType(BaseType baseType); IRBasicType* getVoidType(); @@ -771,9 +831,6 @@ struct IRBuilder IRParam* emitParam( IRType* type); - IRNotePatchConstantFunc* emitNotePatchConstantFunc( - IRInst* func); - IRVar* emitVar( IRType* type); @@ -902,21 +959,17 @@ struct IRBuilder IRInst* param, IRInst* val); - template<typename T> - T* addDecoration(IRInst* value, IRDecorationOp op) - { - SLANG_ASSERT(getModule()); - auto decorationSize = sizeof(T); - auto decoration = (T*)getModule()->memoryArena.allocateAndZero(decorationSize); - - // TODO: Do we need to run ctor after zeroing? - new(decoration)T(); + IRDecoration* addDecoration(IRInst* value, IROp op, IRInst* const* operands, Int operandCount); - decoration->op = op; + IRDecoration* addDecoration(IRInst* value, IROp op, IRInst* operand) + { + return addDecoration(value, op, &operand, 1); + } - decoration->next = value->firstDecoration; - value->firstDecoration = decoration; - return decoration; + IRDecoration* addDecoration(IRInst* value, IROp op, IRInst* operand0, IRInst* operand1) + { + IRInst* operands[] = { operand0, operand1 }; + return addDecoration(value, op, operands, SLANG_COUNT_OF(operands)); } template <typename T> @@ -925,22 +978,71 @@ struct IRBuilder getModule()->getObjectScopeManager()->addMaybeNull(ptr); return ptr; } - StringRepresentation* addStringToFree(const String& string) + + template<typename T> + void addSimpleDecoration(IRInst* value) { - StringRepresentation* stringRep = string.getStringRepresentation(); - getModule()->getObjectScopeManager()->addMaybeNull(stringRep); - return stringRep; + addDecoration(value, IROp(T::kOp), (IRInst* const*) nullptr, 0); } + void addHighLevelDeclDecoration(IRInst* value, Decl* decl); + void addLayoutDecoration(IRInst* value, Layout* layout); - template<typename T> - T* addDecoration(IRInst* value) + void addNameHintDecoration(IRInst* value, IRStringLit* name) + { + addDecoration(value, kIROp_NameHintDecoration, name); + } + + void addNameHintDecoration(IRInst* value, UnownedStringSlice const& text) + { + addNameHintDecoration(value, getStringValue(text)); + } + + void addGLSLOuterArrayDecoration(IRInst* value, UnownedStringSlice const& text) + { + addDecoration(value, kIROp_GLSLOuterArrayDecoration, getStringValue(text)); + } + + void addInterpolationModeDecoration(IRInst* value, IRInterpolationMode mode) + { + addDecoration(value, kIROp_InterpolationModeDecoration, getIntValue(getIntType(), IRIntegerValue(mode))); + } + + void addLoopControlDecoration(IRInst* value, IRLoopControl mode) + { + addDecoration(value, kIROp_LoopControlDecoration, getIntValue(getIntType(), IRIntegerValue(mode))); + } + + void addSemanticDecoration(IRInst* value, UnownedStringSlice const& text) + { + addDecoration(value, kIROp_SemanticDecoration, getStringValue(text)); + } + + void addTargetIntrinsicDecoration(IRInst* value, UnownedStringSlice const& target, UnownedStringSlice const& definition) + { + addDecoration(value, kIROp_TargetIntrinsicDecoration, getStringValue(target), getStringValue(definition)); + } + + void addTargetDecoration(IRInst* value, UnownedStringSlice const& target) + { + addDecoration(value, kIROp_TargetDecoration, getStringValue(target)); + } + + void addRequireGLSLExtensionDecoration(IRInst* value, UnownedStringSlice const& extensionName) + { + addDecoration(value, kIROp_RequireGLSLExtensionDecoration, getStringValue(extensionName)); + } + + void addRequireGLSLVersionDecoration(IRInst* value, Int version) + { + addDecoration(value, kIROp_RequireGLSLVersionDecoration, getIntValue(getIntType(), IRIntegerValue(version))); + } + + void addPatchConstantFuncDecoration(IRInst* value, IRInst* patchConstantFunc) { - return addDecoration<T>(value, IRDecorationOp(T::kDecorationOp)); + addDecoration(value, kIROp_PatchConstantFuncDecoration, patchConstantFunc); } - IRHighLevelDeclDecoration* addHighLevelDeclDecoration(IRInst* value, Decl* decl); - IRLayoutDecoration* addLayoutDecoration(IRInst* value, Layout* layout); }; // Helper to establish the source location that will be used diff --git a/source/slang/ir-legalize-types.cpp b/source/slang/ir-legalize-types.cpp index b86c9f6e9..46ba59bcd 100644 --- a/source/slang/ir-legalize-types.cpp +++ b/source/slang/ir-legalize-types.cpp @@ -114,12 +114,12 @@ struct IRGlobalNameInfo }; static LegalVal declareVars( - IRTypeLegalizationContext* context, + IRTypeLegalizationContext* context, IROp op, LegalType type, TypeLayout* typeLayout, LegalVarChain* varChain, - String const* nameHint, + UnownedStringSlice nameHint, IRGlobalNameInfo* globalNameInfo); static LegalType legalizeType( @@ -844,17 +844,17 @@ static LegalVal legalizeInst( RefPtr<VarLayout> findVarLayout(IRInst* value) { if (auto layoutDecoration = value->findDecoration<IRLayoutDecoration>()) - return layoutDecoration->layout->dynamicCast<VarLayout>(); + return layoutDecoration->getLayout()->dynamicCast<VarLayout>(); return nullptr; } -static String const* findNameHint(IRInst* inst) +static UnownedStringSlice findNameHint(IRInst* inst) { if( auto nameHintDecoration = inst->findDecoration<IRNameHintDecoration>() ) { - return &nameHintDecoration->name->text; + return nameHintDecoration->getName(); } - return nullptr; + return UnownedStringSlice(); } static LegalVal legalizeLocalVar( @@ -912,7 +912,7 @@ static LegalVal legalizeLocalVar( varChain = &varChainStorage; } - String const* nameHint = findNameHint(irLocalVar); + UnownedStringSlice nameHint = findNameHint(irLocalVar); LegalVal newVal = declareVars(context, kIROp_Var, legalValueType, typeLayout, varChain, nameHint, nullptr); // Remove the old local var. @@ -944,7 +944,7 @@ static LegalVal legalizeParam( context->insertBeforeParam = originalParam; - String const* nameHint = findNameHint(originalParam); + UnownedStringSlice nameHint = findNameHint(originalParam); auto newVal = declareVars(context, kIROp_Param, legalParamType, nullptr, nullptr, nameHint, nullptr); originalParam->removeFromParent(); @@ -1096,10 +1096,10 @@ static void addParamType(List<IRType*>& ioParamTypes, LegalType t) static void legalizeInstsInParent( IRTypeLegalizationContext* context, - IRParentInst* parent) + IRInst* parent) { IRInst* nextChild = nullptr; - for(auto child = parent->getFirstChild(); child; child = nextChild) + for(auto child = parent->getFirstDecorationOrChild(); child; child = nextChild) { nextChild = child->getNextInst(); @@ -1147,25 +1147,13 @@ static LegalVal legalizeFunc( return LegalVal::simple(irFunc); } -static void addNameHint( - IRTypeLegalizationContext* context, - IRInst* inst, - String const& text) -{ - if(text.Length() == 0) - return; - - auto name = context->session->getNameObj(text); - context->builder->addDecoration<IRNameHintDecoration>(inst)->name = name; -} - static LegalVal declareSimpleVar( IRTypeLegalizationContext* context, IROp op, IRType* type, TypeLayout* typeLayout, LegalVarChain* varChain, - String const* nameHint, + UnownedStringSlice nameHint, IRGlobalNameInfo* globalNameInfo) { RefPtr<VarLayout> varLayout = createVarLayout(varChain, typeLayout); @@ -1252,9 +1240,9 @@ static LegalVal declareSimpleVar( builder->addHighLevelDeclDecoration(irVar, varDeclRef.getDecl()); } - if( nameHint ) + if( nameHint.size() ) { - addNameHint(context, irVar, *nameHint); + context->builder->addNameHintDecoration(irVar, nameHint); } } @@ -1267,7 +1255,7 @@ static LegalVal declareVars( LegalType type, TypeLayout* typeLayout, LegalVarChain* varChain, - String const* nameHint, + UnownedStringSlice nameHint, IRGlobalNameInfo* globalNameInfo) { switch (type.flavor) @@ -1329,17 +1317,17 @@ static LegalVal declareVars( newVarChain = &newVarChainStorage; } - String* fieldNameHint = nullptr; + UnownedStringSlice fieldNameHint; String joinedNameHintStorage; - if( nameHint ) + if( nameHint.size() ) { if( auto fieldNameHintDecoration = ee.key->findDecoration<IRNameHintDecoration>() ) { - joinedNameHintStorage.append(*nameHint); + joinedNameHintStorage.append(nameHint); joinedNameHintStorage.append("."); - joinedNameHintStorage.append(fieldNameHintDecoration->name->text); + joinedNameHintStorage.append(fieldNameHintDecoration->getName()); - fieldNameHint = &joinedNameHintStorage; + fieldNameHint = joinedNameHintStorage.getUnownedSlice(); } } @@ -1409,7 +1397,7 @@ static LegalVal legalizeGlobalVar( globalNameInfo.globalVar = irGlobalVar; globalNameInfo.counter = 0; - String const* nameHint = findNameHint(irGlobalVar); + UnownedStringSlice nameHint = findNameHint(irGlobalVar); LegalVal newVal = declareVars(context, kIROp_GlobalVar, legalValueType, typeLayout, varChain, nameHint, &globalNameInfo); // Register the new value as the replacement for the old @@ -1452,7 +1440,7 @@ static LegalVal legalizeGlobalConstant( // TODO: need to handle initializer here! - String const* nameHint = findNameHint(irGlobalConstant); + UnownedStringSlice nameHint = findNameHint(irGlobalConstant); LegalVal newVal = declareVars(context, kIROp_GlobalConstant, legalValueType, nullptr, nullptr, nameHint, &globalNameInfo); // Register the new value as the replacement for the old diff --git a/source/slang/ir-missing-return.cpp b/source/slang/ir-missing-return.cpp index 0396fbce9..c32b71ab6 100644 --- a/source/slang/ir-missing-return.cpp +++ b/source/slang/ir-missing-return.cpp @@ -26,12 +26,9 @@ void checkForMissingReturnsRec( } } - if( auto parentInst = as<IRParentInst>(inst) ) + for( auto childInst : inst->getDecorationsAndChildren() ) { - for( auto childInst : parentInst->getChildren() ) - { - checkForMissingReturnsRec(childInst, sink); - } + checkForMissingReturnsRec(childInst, sink); } } diff --git a/source/slang/ir-restructure-scoping.cpp b/source/slang/ir-restructure-scoping.cpp index 61b56e190..c5e628e71 100644 --- a/source/slang/ir-restructure-scoping.cpp +++ b/source/slang/ir-restructure-scoping.cpp @@ -424,7 +424,7 @@ void fixValueScoping(RegionTree* regionTree) if(!parentRegion) continue; - for(auto inst : block->getChildren()) + for(auto inst : block->getDecorationsAndChildren()) { fixValueScopingForInst(inst, parentRegion, regionTree); } diff --git a/source/slang/ir-sccp.cpp b/source/slang/ir-sccp.cpp index 6c7f637c1..66b370848 100644 --- a/source/slang/ir-sccp.cpp +++ b/source/slang/ir-sccp.cpp @@ -633,7 +633,7 @@ struct SCCPContext // may in turn add other blocks/instructions to // the work lists. // - for( auto inst : block->getChildren() ) + for( auto inst : block->getDecorationsAndChildren() ) { updateValueForInst(inst); } @@ -702,7 +702,7 @@ struct SCCPContext List<IRInst*> instsToRemove; for( auto block : code->getBlocks() ) { - for( auto inst : block->getChildren() ) + for( auto inst : block->getDecorationsAndChildren() ) { // We look for instructions that have a constnat value on // the lattice. @@ -869,7 +869,7 @@ struct SCCPContext // err on the side of allowing unreachable code without // a warning. // - block->removeAndDeallocateAllChildren(); + block->removeAndDeallocateAllDecorationsAndChildren(); } // // At this point every one of our unreachable blocks is empty, @@ -929,14 +929,10 @@ static void applySparseConditionalConstantPropagationRec( } } - if( auto parentInst = as<IRParentInst>(inst) ) + for( auto childInst : inst->getDecorationsAndChildren() ) { - for( auto childInst : parentInst->getChildren() ) - { - applySparseConditionalConstantPropagationRec(shared, childInst); - } + applySparseConditionalConstantPropagationRec(shared, childInst); } - } void applySparseConditionalConstantPropagation( diff --git a/source/slang/ir-serialize.cpp b/source/slang/ir-serialize.cpp index 03e10c8e2..0fc8a0806 100644 --- a/source/slang/ir-serialize.cpp +++ b/source/slang/ir-serialize.cpp @@ -16,12 +16,9 @@ namespace Slang { /* Note that an IRInst can be derived from, but when it derived from it's new members are IRUse variables, and they in effect alias over the operands - and reflected in the operand count. There _could_ be other members after these IRUse -variables, but in practice there do not appear to be. - -The only difference to this is IRParentInst derived types, as it contains IRInstListBase children. Thus IRParentInst derived classes can -have no operands - because it would write over the top of IRInstListBase. BUT they can contain members after the list -types which do this are +variables, but only a few types include extra data, and these do not have any operands: +* IRConstant - Needs special-case handling * IRModuleInst - Presumably we can just set to the module pointer on reconstruction * IRGlobalValue - There are types derived from this type, but they don't add a parameter @@ -44,12 +41,6 @@ bother to check if it's correct, and just casts it. { 0, 0 } // Int64, }; -static bool isParentDerived(IROp opIn) -{ - const int op = (kIROpMeta_PseudoOpMask & opIn); - return op >= kIROp_FirstParentInst && op <= kIROp_LastParentInst; -} - static bool isGlobalValueDerived(IROp opIn) { const int op = (kIROpMeta_PseudoOpMask & opIn); @@ -273,7 +264,6 @@ size_t IRSerialData::calcSizeInBytes() const return _calcArraySize(m_insts) + _calcArraySize(m_childRuns) + - _calcArraySize(m_decorationRuns) + _calcArraySize(m_externalOperands) + _calcArraySize(m_stringTable) + /* Raw source locs */ @@ -293,7 +283,6 @@ void IRSerialData::clear() memset(&m_insts[0], 0, sizeof(Inst)); m_childRuns.Clear(); - m_decorationRuns.Clear(); m_externalOperands.Clear(); m_rawSourceLocs.Clear(); @@ -307,8 +296,6 @@ void IRSerialData::clear() m_stringTable.SetSize(2); m_stringTable[int(kNullStringIndex)] = 0; m_stringTable[int(kEmptyStringIndex)] = 0; - - m_decorationBaseIndex = 0; } template <typename T> @@ -344,10 +331,8 @@ static bool _isEqual(const List<T>& aIn, const List<T>& bIn) bool IRSerialData::operator==(const ThisType& rhs) const { return (this == &rhs) || - (m_decorationBaseIndex == rhs.m_decorationBaseIndex && - _isEqual(m_insts, rhs.m_insts) && + (_isEqual(m_insts, rhs.m_insts) && _isEqual(m_childRuns, rhs.m_childRuns) && - _isEqual(m_decorationRuns, rhs.m_decorationRuns) && _isEqual(m_externalOperands, rhs.m_externalOperands) && _isEqual(m_rawSourceLocs, rhs.m_rawSourceLocs) && _isEqual(m_stringTable, rhs.m_stringTable)); @@ -363,33 +348,6 @@ void IRSerialWriter::_addInstruction(IRInst* inst) // Add to the map m_instMap.Add(inst, Ser::InstIndex(m_insts.Count())); m_insts.Add(inst); - - // Add all the decorations, to the list. - // We don't add to the decoration map, as we only want to do this once all the instructions have been hit - if (inst->firstDecoration) - { - m_instWithFirstDecoration.Add(inst); - - IRDecoration* decor = inst->firstDecoration; - - const int initialNumDecor = int(m_decorations.Count()); - while (decor) - { - m_decorations.Add(decor); - decor = decor->next; - } - - const Ser::SizeType numDecor = Ser::SizeType(int(m_decorations.Count()) - initialNumDecor); - - Ser::InstRun run; - run.m_parentIndex = m_instMap[inst]; - - // NOTE! This isn't quite correct, as we need to correct for when all the instructions are added, this is done at the end - run.m_startInstIndex = Ser::InstIndex(initialNumDecor); - run.m_numChildren = numDecor; - - m_serialData->m_decorationRuns.Add(run); - } } // Find a view index that matches the view by file (and perhaps other characteristics in the future) @@ -433,7 +391,7 @@ Result IRSerialWriter::write(IRModule* module, SourceManager* sourceManager, Opt m_decorations.Clear(); // Stack for parentInst - List<IRParentInst*> parentInstStack; + List<IRInst*> parentInstStack; IRModuleInst* moduleInst = module->getModuleInst(); parentInstStack.Add(moduleInst); @@ -445,7 +403,7 @@ Result IRSerialWriter::write(IRModule* module, SourceManager* sourceManager, Opt while (parentInstStack.Count()) { // If it's in the stack it is assumed it is already in the inst map - IRParentInst* parentInst = parentInstStack.Last(); + IRInst* parentInst = parentInstStack.Last(); parentInstStack.RemoveLast(); SLANG_ASSERT(m_instMap.ContainsKey(parentInst)); @@ -453,7 +411,7 @@ Result IRSerialWriter::write(IRModule* module, SourceManager* sourceManager, Opt // cos we want breadth first so the order of children is the same as their index order, meaning we don't need to store explicit indices const Ser::InstIndex startChildInstIndex = Ser::InstIndex(m_insts.Count()); - IRInstListBase childrenList = parentInst->getChildren(); + IRInstListBase childrenList = parentInst->getDecorationsAndChildren(); for (IRInst* child : childrenList) { // This instruction can't be in the map... @@ -461,11 +419,7 @@ Result IRSerialWriter::write(IRModule* module, SourceManager* sourceManager, Opt _addInstruction(child); - IRParentInst* childAsParent = as<IRParentInst>(child); - if (childAsParent) - { - parentInstStack.Add(childAsParent); - } + parentInstStack.Add(child); } // If it had any children, then store the information about it @@ -480,32 +434,10 @@ Result IRSerialWriter::write(IRModule* module, SourceManager* sourceManager, Opt } } - // Now fix the decorations - { - const int decorationBaseIndex = int(m_insts.Count()); - m_serialData->m_decorationBaseIndex = decorationBaseIndex; - const int numDecorRuns = int(m_serialData->m_decorationRuns.Count()); - - // Work out the total num of decoration - int totalNumDecorations = 0; - if (numDecorRuns) - { - const auto& lastDecorInfo = m_serialData->m_decorationRuns.Last(); - totalNumDecorations = int(lastDecorInfo.m_startInstIndex) + lastDecorInfo.m_numChildren; - } - - // Fix the indices - for (int i = 0; i < numDecorRuns; ++i) - { - Ser::InstRun& info = m_serialData->m_decorationRuns[i]; - info.m_startInstIndex = Ser::InstIndex(decorationBaseIndex + int(info.m_startInstIndex)); - } - - // Set to the right size - m_serialData->m_insts.SetSize(decorationBaseIndex + totalNumDecorations); - // Clear all instructions - memset(m_serialData->m_insts.begin(), 0, sizeof(Ser::Inst) * m_serialData->m_insts.Count()); - } + // Set to the right size + m_serialData->m_insts.SetSize(m_insts.Count()); + // Clear all instructions + memset(m_serialData->m_insts.begin(), 0, sizeof(Ser::Inst) * m_serialData->m_insts.Count()); // Need to set up the actual instructions { @@ -543,6 +475,12 @@ Result IRSerialWriter::write(IRModule* module, SourceManager* sourceManager, Opt dstInst.m_payload.m_int64 = irConst->value.intVal; break; } + case kIROp_PtrLit: + { + dstInst.m_payloadType = PayloadType::Int64; + dstInst.m_payload.m_int64 = (intptr_t) irConst->value.ptrVal; + break; + } case kIROp_FloatLit: { dstInst.m_payloadType = PayloadType::Float64; @@ -616,128 +554,6 @@ Result IRSerialWriter::write(IRModule* module, SourceManager* sourceManager, Opt } } - // Now need to do the decorations - - { - const int decorationBaseIndex = m_serialData->m_decorationBaseIndex; - const int numDecor = int(m_decorations.Count()); - SLANG_ASSERT(decorationBaseIndex + numDecor == int(m_serialData->m_insts.Count())); - - // Have to be able to store in a byte! - SLANG_COMPILE_TIME_ASSERT(kIROpCount + kIRDecorationOp_CountOf < 0x100); - - for (int i = 0; i < numDecor; ++i) - { - IRDecoration* srcDecor = m_decorations[i]; - Ser::Inst& dstInst = m_serialData->m_insts[decorationBaseIndex + i]; - - dstInst.m_op = uint8_t(kIROpCount + srcDecor->op); - - switch (srcDecor->op) - { - case kIRDecorationOp_HighLevelDecl: - { - // TODO! - // Decl* decl; - break; - } - case kIRDecorationOp_Layout: - { - // TODO! - // Layout* layout; - break; - } - case kIRDecorationOp_LoopControl: - { - auto loopDecor = static_cast<IRLoopControlDecoration*>(srcDecor); - - dstInst.m_payloadType = PayloadType::UInt32; - dstInst.m_payload.m_uint32 = uint32_t(loopDecor->mode); - break; - } - case kIRDecorationOp_Target: - { - auto targetDecor = static_cast<IRTargetDecoration*>(srcDecor); - - dstInst.m_payloadType = PayloadType::String_1; - dstInst.m_payload.m_stringIndices[0] = getStringIndex(targetDecor->targetName); - break; - } - case kIRDecorationOp_TargetIntrinsic: - { - auto targetDecor = static_cast<IRTargetIntrinsicDecoration*>(srcDecor); - dstInst.m_payloadType = PayloadType::String_2; - - dstInst.m_payload.m_stringIndices[0] = getStringIndex(targetDecor->targetName); - dstInst.m_payload.m_stringIndices[1] = getStringIndex(targetDecor->definition); - break; - } - case kIRDecorationOp_GLSLOuterArray: - { - auto arrayDecor = static_cast<IRGLSLOuterArrayDecoration*>(srcDecor); - dstInst.m_payloadType = PayloadType::String_1; - - dstInst.m_payload.m_stringIndices[0] = getStringIndex(arrayDecor->outerArrayName); - break; - } - case kIRDecorationOp_Semantic: - { - auto semanticDecor = static_cast<IRSemanticDecoration*>(srcDecor); - - dstInst.m_payloadType = PayloadType::String_1; - dstInst.m_payload.m_stringIndices[0] = getStringIndex(semanticDecor->semanticName); - break; - } - case kIRDecorationOp_InterpolationMode: - { - auto semanticDecor = static_cast<IRInterpolationModeDecoration*>(srcDecor); - dstInst.m_payloadType = PayloadType::UInt32; - dstInst.m_payload.m_uint32 = uint32_t(semanticDecor->mode); - break; - } - case kIRDecorationOp_NameHint: - { - auto nameDecor = static_cast<IRNameHintDecoration*>(srcDecor); - - dstInst.m_payloadType = PayloadType::String_1; - dstInst.m_payload.m_stringIndices[0] = getStringIndex(nameDecor->name); - break; - } - case kIRDecorationOp_VulkanRayPayload: - case kIRDecorationOp_VulkanCallablePayload: - case kIRDecorationOp_VulkanHitAttributes: - case kIRDecorationOp_EarlyDepthStencil: - case kIRDecorationOp_ReadNone: - case kIRDecorationOp_GloballyCoherent: - { - dstInst.m_payloadType = PayloadType::Empty; - break; - } - case kIRDecorationOp_RequireGLSLExtension: - { - auto extDecor = static_cast<IRRequireGLSLExtensionDecoration*>(srcDecor); - - dstInst.m_payloadType = PayloadType::String_1; - dstInst.m_payload.m_stringIndices[0] = getStringIndex(extDecor->extensionName); - break; - } - case kIRDecorationOp_RequireGLSLVersion: - { - auto verDecor = static_cast<IRRequireGLSLVersionDecoration*>(srcDecor); - - dstInst.m_payloadType = PayloadType::UInt32; - dstInst.m_payload.m_uint32 = uint32_t(verDecor->languageVersion); - break; - } - default: - { - SLANG_ASSERT(!"Unhandled decoration type"); - return SLANG_FAIL; - } - } - } - } - // Convert strings into a string table { SerialStringTableUtil::encodeStringTable(m_stringSlicePool, serialData->m_stringTable); @@ -1083,7 +899,6 @@ static size_t _calcInstChunkSize(IRSerialBinary::CompressionType compressionType totalSize += sizeof(Bin::SlangHeader) + _calcInstChunkSize(compressionType, data.m_insts) + _calcChunkSize(compressionType, data.m_childRuns) + - _calcChunkSize(compressionType, data.m_decorationRuns) + _calcChunkSize(compressionType, data.m_externalOperands) + _calcChunkSize(Bin::CompressionType::None, data.m_stringTable) + _calcChunkSize(Bin::CompressionType::None, data.m_rawSourceLocs); @@ -1099,7 +914,6 @@ static size_t _calcInstChunkSize(IRSerialBinary::CompressionType compressionType Bin::SlangHeader slangHeader; slangHeader.m_chunk.m_type = Bin::kSlangFourCc; slangHeader.m_chunk.m_size = uint32_t(sizeof(slangHeader) - sizeof(Bin::Chunk)); - slangHeader.m_decorationBase = uint32_t(data.m_decorationBaseIndex); slangHeader.m_compressionType = uint32_t(Bin::CompressionType::VariableByteLite); stream->Write(&slangHeader, sizeof(slangHeader)); @@ -1107,7 +921,6 @@ static size_t _calcInstChunkSize(IRSerialBinary::CompressionType compressionType SLANG_RETURN_ON_FAIL(_writeInstArrayChunk(compressionType, Bin::kInstFourCc, data.m_insts, stream)); SLANG_RETURN_ON_FAIL(_writeArrayChunk(compressionType, Bin::kChildRunFourCc, data.m_childRuns, stream)); - SLANG_RETURN_ON_FAIL(_writeArrayChunk(compressionType, Bin::kDecoratorRunFourCc, data.m_decorationRuns, stream)); SLANG_RETURN_ON_FAIL(_writeArrayChunk(compressionType, Bin::kExternalOperandsFourCc, data.m_externalOperands, stream)); SLANG_RETURN_ON_FAIL(_writeArrayChunk(Bin::CompressionType::None, Bin::kStringFourCc, data.m_stringTable, stream)); @@ -1430,7 +1243,6 @@ int64_t _calcChunkTotalSize(const IRSerialBinary::Chunk& chunk) stream->Read(&slangHeader.m_chunk + 1, sizeof(slangHeader) - sizeof(chunk)); - dataOut->m_decorationBaseIndex = slangHeader.m_decorationBase; remainingBytes -= _calcChunkTotalSize(chunk); break; } @@ -1441,13 +1253,6 @@ int64_t _calcChunkTotalSize(const IRSerialBinary::Chunk& chunk) remainingBytes -= _calcChunkTotalSize(chunk); break; } - case SLANG_MAKE_COMPRESSED_FOUR_CC(Bin::kDecoratorRunFourCc): - case Bin::kDecoratorRunFourCc: - { - SLANG_RETURN_ON_FAIL(_readArrayChunk(slangHeader, chunk, stream, &bytesRead, dataOut->m_decorationRuns)); - remainingBytes -= _calcChunkTotalSize(chunk); - break; - } case SLANG_MAKE_COMPRESSED_FOUR_CC(Bin::kChildRunFourCc): case Bin::kChildRunFourCc: { @@ -1486,135 +1291,6 @@ int64_t _calcChunkTotalSize(const IRSerialBinary::Chunk& chunk) return SLANG_OK; } -IRDecoration* IRSerialReader::_createDecoration(const Ser::Inst& srcInst) -{ - typedef Ser::Inst::PayloadType PayloadType; - - IRDecorationOp decorOp = IRDecorationOp(srcInst.m_op - kIROpCount); - SLANG_ASSERT(decorOp < kIRDecorationOp_CountOf); - - switch (decorOp) - { - case kIRDecorationOp_HighLevelDecl: - { - // TODO! - // Decl* decl; - return createEmptyDecoration<IRHighLevelDeclDecoration>(m_module); - } - case kIRDecorationOp_Layout: - { - // TODO! - // Layout* layout; - return createEmptyDecoration<IRLayoutDecoration>(m_module); - } - case kIRDecorationOp_LoopControl: - { - auto decor = createEmptyDecoration<IRLoopControlDecoration>(m_module); - SLANG_ASSERT(srcInst.m_payloadType == PayloadType::UInt32); - decor->mode = IRLoopControl(srcInst.m_payload.m_uint32); - return decor; - } - case kIRDecorationOp_Target: - { - auto decor = createEmptyDecoration<IRTargetDecoration>(m_module); - SLANG_ASSERT(srcInst.m_payloadType == PayloadType::String_1); - decor->targetName = m_stringRepresentationCache.getStringRepresentation(StringHandle(srcInst.m_payload.m_stringIndices[0])); - return decor; - } - case kIRDecorationOp_TargetIntrinsic: - { - auto decor = createEmptyDecoration<IRTargetIntrinsicDecoration>(m_module); - SLANG_ASSERT(srcInst.m_payloadType == PayloadType::String_2); - decor->targetName = m_stringRepresentationCache.getStringRepresentation(StringHandle(srcInst.m_payload.m_stringIndices[0])); - decor->definition = m_stringRepresentationCache.getStringRepresentation(StringHandle(srcInst.m_payload.m_stringIndices[1])); - return decor; - } - case kIRDecorationOp_GLSLOuterArray: - { - auto decor = createEmptyDecoration<IRGLSLOuterArrayDecoration>(m_module); - SLANG_ASSERT(srcInst.m_payloadType == PayloadType::String_1); - decor->outerArrayName = m_stringRepresentationCache.getCStr(StringHandle(srcInst.m_payload.m_stringIndices[0])); - return decor; - } - case kIRDecorationOp_Semantic: - { - auto decor = createEmptyDecoration<IRSemanticDecoration>(m_module); - SLANG_ASSERT(srcInst.m_payloadType == PayloadType::String_1); - decor->semanticName = m_stringRepresentationCache.getName(StringHandle(srcInst.m_payload.m_stringIndices[0])); - return decor; - } - case kIRDecorationOp_InterpolationMode: - { - auto decor = createEmptyDecoration<IRInterpolationModeDecoration>(m_module); - SLANG_ASSERT(srcInst.m_payloadType == Ser::Inst::PayloadType::UInt32); - decor->mode = IRInterpolationMode(srcInst.m_payload.m_uint32); - return decor; - } - case kIRDecorationOp_NameHint: - { - auto decor = createEmptyDecoration<IRNameHintDecoration>(m_module); - SLANG_ASSERT(srcInst.m_payloadType == PayloadType::String_1); - decor->name = m_stringRepresentationCache.getName(StringHandle(srcInst.m_payload.m_stringIndices[0])); - return decor; - } - case kIRDecorationOp_VulkanRayPayload: - { - auto decor = createEmptyDecoration<IRVulkanRayPayloadDecoration>(m_module); - SLANG_ASSERT(srcInst.m_payloadType == PayloadType::Empty); - return decor; - } - case kIRDecorationOp_VulkanCallablePayload: - { - auto decor = createEmptyDecoration<IRVulkanCallablePayloadDecoration>(m_module); - SLANG_ASSERT(srcInst.m_payloadType == PayloadType::Empty); - return decor; - } - case kIRDecorationOp_EarlyDepthStencil: - { - auto decor = createEmptyDecoration<IREarlyDepthStencilDecoration>(m_module); - SLANG_ASSERT(srcInst.m_payloadType == PayloadType::Empty); - return decor; - } - case kIRDecorationOp_GloballyCoherent: - { - auto decor = createEmptyDecoration<IRGloballyCoherentDecoration>(m_module); - SLANG_ASSERT(srcInst.m_payloadType == PayloadType::Empty); - return decor; - } - case kIRDecorationOp_VulkanHitAttributes: - { - auto decor = createEmptyDecoration<IRVulkanHitAttributesDecoration>(m_module); - SLANG_ASSERT(srcInst.m_payloadType == PayloadType::Empty); - return decor; - } - case kIRDecorationOp_RequireGLSLExtension: - { - auto decor = createEmptyDecoration<IRRequireGLSLExtensionDecoration>(m_module); - SLANG_ASSERT(srcInst.m_payloadType == PayloadType::String_1); - decor->extensionName = m_stringRepresentationCache.getStringRepresentation(StringHandle(srcInst.m_payload.m_stringIndices[0])); - return decor; - } - case kIRDecorationOp_RequireGLSLVersion: - { - auto decor = createEmptyDecoration<IRRequireGLSLVersionDecoration>(m_module); - SLANG_ASSERT(srcInst.m_payloadType == Ser::Inst::PayloadType::UInt32); - decor->languageVersion = Int(srcInst.m_payload.m_uint32); - return decor; - } - case kIRDecorationOp_ReadNone: - { - auto decor = createEmptyDecoration<IRReadNoneDecoration>(m_module); - SLANG_ASSERT(srcInst.m_payloadType == PayloadType::Empty); - return decor; - } - default: - { - SLANG_ASSERT(!"Unhandled decoration type"); - return nullptr; - } - } -} - /* static */Result IRSerialReader::read(const IRSerialData& data, Session* session, RefPtr<IRModule>& moduleOut) { typedef Ser::Inst::PayloadType PayloadType; @@ -1633,18 +1309,14 @@ IRDecoration* IRSerialReader::_createDecoration(const Ser::Inst& srcInst) // Add all the instructions List<IRInst*> insts; - List<IRDecoration*> decorations; - const int numInsts = data.m_decorationBaseIndex; - const int numDecorations = int(data.m_insts.Count() - numInsts); + const int numInsts = int(data.m_insts.Count()); SLANG_ASSERT(numInsts > 0); insts.SetSize(numInsts); insts[0] = nullptr; - decorations.SetSize(numDecorations); - // 0 holds null // 1 holds the IRModuleInst { @@ -1668,25 +1340,16 @@ IRDecoration* IRSerialReader::_createDecoration(const Ser::Inst& srcInst) const IROp op((IROp)srcInst.m_op); - if (isParentDerived(op)) + if (isGlobalValueDerived(op)) { // Cannot have operands SLANG_ASSERT(srcInst.getNumOperands() == 0); - if (isGlobalValueDerived(op)) - { - IRGlobalValue* globalValueInst = static_cast<IRGlobalValue*>(createEmptyInstWithSize(module, op, sizeof(IRGlobalValue))); - insts[i] = globalValueInst; - // Set the global value - SLANG_ASSERT(srcInst.m_payloadType == PayloadType::String_1); - globalValueInst->mangledName = m_stringRepresentationCache.getName(StringHandle(srcInst.m_payload.m_stringIndices[0])); - } - else - { - // Just needs to big enough to hold IRParentInst - IRParentInst* parentInst = static_cast<IRParentInst*>(createEmptyInstWithSize(module, op, sizeof(IRParentInst))); - insts[i] = parentInst; - } + IRGlobalValue* globalValueInst = static_cast<IRGlobalValue*>(createEmptyInstWithSize(module, op, sizeof(IRGlobalValue))); + insts[i] = globalValueInst; + // Set the global value + SLANG_ASSERT(srcInst.m_payloadType == PayloadType::String_1); + globalValueInst->mangledName = m_stringRepresentationCache.getName(StringHandle(srcInst.m_payload.m_stringIndices[0])); } else { @@ -1714,6 +1377,13 @@ IRDecoration* IRSerialReader::_createDecoration(const Ser::Inst& srcInst) irConst->value.intVal = srcInst.m_payload.m_int64; break; } + case kIROp_PtrLit: + { + SLANG_ASSERT(srcInst.m_payloadType == PayloadType::Int64); + irConst = static_cast<IRConstant*>(createEmptyInstWithSize(module, op, prefixSize + sizeof(void*))); + irConst->value.ptrVal = (void*) (intptr_t) srcInst.m_payload.m_int64; + break; + } case kIROp_FloatLit: { SLANG_ASSERT(srcInst.m_payloadType == PayloadType::Float64); @@ -1808,56 +1478,12 @@ IRDecoration* IRSerialReader::_createDecoration(const Ser::Inst& srcInst) const auto& run = data.m_childRuns[i]; IRInst* inst = insts[int(run.m_parentIndex)]; - IRParentInst* parentInst = as<IRParentInst>(inst); - SLANG_ASSERT(parentInst); for (int j = 0; j < int(run.m_numChildren); ++j) { IRInst* child = insts[j + int(run.m_startInstIndex)]; SLANG_ASSERT(child->parent == nullptr); - //child->parent = parentInst; - child->insertAtEnd(parentInst); - } - } - } - - // Create the decorations - for (int i = 0; i < numDecorations; ++i) - { - IRDecoration* decor = _createDecoration(data.m_insts[i + numInsts]); - if (!decor) - { - return SLANG_FAIL; - } - decorations[i] = decor; - } - - // Associate the decorations with the instructions - - { - const int decorationBaseIndex = m_serialData->m_decorationBaseIndex; - - const int numRuns = int(m_serialData->m_decorationRuns.Count()); - for (int i = 0; i < numRuns; ++i) - { - const Ser::InstRun& run = m_serialData->m_decorationRuns[i]; - - // Decorations must be associated with instructions - SLANG_ASSERT(int(run.m_parentIndex) < decorationBaseIndex); - - IRInst* inst = insts[int(run.m_parentIndex)]; - SLANG_ASSERT(int(run.m_startInstIndex) >= decorationBaseIndex && int(run.m_startInstIndex) + run.m_numChildren <= m_serialData->m_insts.Count()); - - // Calculate the offset in the decoration list, which index 0, is decorationBaseIndex in instruction indices - const int decorStartIndex = int(run.m_startInstIndex) - decorationBaseIndex; - - // Go in reverse order so that linked list is in same order as original - for (int j = int(run.m_numChildren) - 1; j >= 0; --j) - { - IRDecoration* decor = decorations[decorStartIndex + j]; - // And to the linked list on the - decor->next = inst->firstDecoration; - inst->firstDecoration = decor; + child->insertAtEnd(inst); } } } diff --git a/source/slang/ir-serialize.h b/source/slang/ir-serialize.h index ec560233f..c205e7a35 100644 --- a/source/slang/ir-serialize.h +++ b/source/slang/ir-serialize.h @@ -212,14 +212,12 @@ struct IRSerialData size_t calcSizeInBytes() const; /// Ctor - IRSerialData() : - m_decorationBaseIndex(0) + IRSerialData() {} List<Inst> m_insts; ///< The instructions List<InstRun> m_childRuns; ///< Holds the information about children that belong to an instruction - List<InstRun> m_decorationRuns; ///< Holds instruction decorations List<InstIndex> m_externalOperands; ///< Holds external operands (for instructions with more than kNumOperands) @@ -234,8 +232,6 @@ struct IRSerialData List<char> m_debugStrings; ///< All of the debug strings static const PayloadInfo s_payloadInfos[int(Inst::PayloadType::CountOf)]; - - int m_decorationBaseIndex; ///< All decorations insts are at indices >= to this value }; // -------------------------------------------------------------------------- @@ -323,12 +319,10 @@ struct IRSerialBinary static const uint32_t kSlangFourCc = SLANG_FOUR_CC('S', 'L', 'N', 'G'); ///< Holds all the slang specific chunks static const uint32_t kInstFourCc = SLANG_FOUR_CC('S', 'L', 'i', 'n'); - static const uint32_t kDecoratorRunFourCc = SLANG_FOUR_CC('S', 'L', 'd', 'r'); static const uint32_t kChildRunFourCc = SLANG_FOUR_CC('S', 'L', 'c', 'r'); static const uint32_t kExternalOperandsFourCc = SLANG_FOUR_CC('S', 'L', 'e', 'o'); static const uint32_t kCompressedInstFourCc = SLANG_MAKE_COMPRESSED_FOUR_CC(kInstFourCc); - static const uint32_t kCompressedDecoratorRunFourCc = SLANG_MAKE_COMPRESSED_FOUR_CC(kDecoratorRunFourCc); static const uint32_t kCompressedChildRunFourCc = SLANG_MAKE_COMPRESSED_FOUR_CC(kChildRunFourCc); static const uint32_t kCompressedExternalOperandsFourCc = SLANG_MAKE_COMPRESSED_FOUR_CC(kExternalOperandsFourCc); @@ -339,7 +333,6 @@ struct IRSerialBinary struct SlangHeader { Chunk m_chunk; - uint32_t m_decorationBase; uint32_t m_compressionType; ///< Holds the compression type used (if used at all) }; struct ArrayHeader diff --git a/source/slang/ir-ssa.cpp b/source/slang/ir-ssa.cpp index 973030852..d893137de 100644 --- a/source/slang/ir-ssa.cpp +++ b/source/slang/ir-ssa.cpp @@ -364,7 +364,7 @@ void maybeApplyNameHint( { if( !val->findDecoration<IRNameHintDecoration>() ) { - context->getBuilder()->addDecoration<IRNameHintDecoration>(val)->name = nameHint->name; + context->getBuilder()->addNameHintDecoration(val, nameHint->getName()); } } } @@ -838,7 +838,9 @@ void processBlock( } } - blockInfo->builder.setInsertBefore(block->getLastChild()); + auto terminator = block->getTerminator(); + SLANG_ASSERT(terminator); + blockInfo->builder.setInsertBefore(terminator); // Once we are done with all of the instructions // in a block, we can mark it as "filled," which @@ -1066,9 +1068,16 @@ void constructSSA(ConstructSSAContext* context) newArgCount, newArgs.Buffer()); - // Swap decorations over to the new instruction - newTerminator->firstDecoration = oldTerminator->firstDecoration; - oldTerminator->firstDecoration = nullptr; + // Swap decorations (all children, really) over to the new instruction + // + // TODO: We might want to encapsualte this in a reusable subroutine if + // we often need to copy decorations from one instruction to another. + // + while( auto firstChild = oldTerminator->getFirstDecoration() ) + { + firstChild->removeFromParent(); + firstChild->insertAtEnd(newTerminator); + } // A terminator better not have uses, so we shouldn't have // to replace them. diff --git a/source/slang/ir-validate.cpp b/source/slang/ir-validate.cpp index 1f5112a51..924ec71b3 100644 --- a/source/slang/ir-validate.cpp +++ b/source/slang/ir-validate.cpp @@ -35,10 +35,10 @@ namespace Slang void validateIRInstChildren( IRValidateContext* context, - IRParentInst* parent) + IRInst* parent) { IRInst* prevChild = nullptr; - for (auto child = parent->getFirstChild(); child; child = child->getNextInst()) + for(auto child : parent->getDecorationsAndChildren() ) { // We need to check the integrity of the parent/next/prev links of // all of our instructions @@ -53,7 +53,7 @@ namespace Slang // * The last instruction of a block should always be a terminator // * No other instruction should be a terminator // - if(as<IRBlock>(parent) && (child == parent->getLastChild())) + if(as<IRBlock>(parent) && (child == parent->getLastDecorationOrChild())) { validate(context, as<IRTerminatorInst>(child) != nullptr, child, "last instruction in block must be terminator"); } @@ -174,10 +174,7 @@ namespace Slang // If `inst` is itself a parent instruction, then we need to recursively // validate its children. - if (auto parent = as<IRParentInst>(inst)) - { - validateIRInstChildren(context, parent); - } + validateIRInstChildren(context, inst); } void validateIRModule(IRModule* module, DiagnosticSink* sink) diff --git a/source/slang/ir.cpp b/source/slang/ir.cpp index c0715fca3..bc33527cf 100644 --- a/source/slang/ir.cpp +++ b/source/slang/ir.cpp @@ -166,6 +166,19 @@ namespace Slang } } + // IRInstListBase + + void IRInstListBase::Iterator::operator++() + { + if (inst) + { + inst = inst->next; + } + } + + IRInstListBase::Iterator IRInstListBase::begin() { return Iterator(first); } + IRInstListBase::Iterator IRInstListBase::end() { return Iterator(last ? last->next : nullptr); } + // IRUse* IRInst::getOperands() @@ -180,9 +193,9 @@ namespace Slang return (IRUse*)(this + 1); } - IRDecoration* IRInst::findDecorationImpl(IRDecorationOp decorationOp) + IRDecoration* IRInst::findDecorationImpl(IROp decorationOp) { - for( auto dd = firstDecoration; dd; dd = dd->next ) + for(auto dd : getDecorations()) { if(dd->op == decorationOp) return dd; @@ -239,14 +252,31 @@ namespace Slang void IRBlock::addParam(IRParam* param) { - auto lastParam = getLastParam(); - if (lastParam) + // If there are any existing parameters, + // then insert after the last of them. + // + if (auto lastParam = getLastParam()) { param->insertAfter(lastParam); } + // + // Otherwise, if there are any existing + // "ordinary" instructions, insert before + // the first of them. + // + else if(auto firstOrdinary = getFirstOrdinaryInst()) + { + param->insertBefore(firstOrdinary); + } + // + // Otherwise the block currently has neither + // parameters nor orindary instructions, + // so we can safely insert at the end of + // the list of (raw) children. + // else { - param->insertAtStart(this); + param->insertAtEnd(this); } } @@ -585,7 +615,7 @@ namespace Slang } - void IRBuilder::setInsertInto(IRParentInst* insertInto) + void IRBuilder::setInsertInto(IRInst* insertInto) { insertIntoParent = insertInto; insertBeforeInst = nullptr; @@ -620,7 +650,7 @@ namespace Slang // Given two parent instructions, pick the better one to use as as // insertion location for a "hoistable" instruction. // - IRParentInst* mergeCandidateParentsForHoistableInst(IRParentInst* left, IRParentInst* right) + IRInst* mergeCandidateParentsForHoistableInst(IRInst* left, IRInst* right) { // If the candidates are both the same, then who cares? if(left == right) return left; @@ -681,7 +711,7 @@ namespace Slang // If the non-block on the left or right is a descendent of // the other, then that is what we should use. // - IRParentInst* parentNonBlock = nullptr; + IRInst* parentNonBlock = nullptr; for (auto ll = leftNonBlock; ll; ll = ll->getParent()) { if (ll == rightNonBlock) @@ -715,7 +745,7 @@ namespace Slang parentNonBlock = leftNonBlock; } - IRParentInst* parent = parentNonBlock; + IRInst* parent = parentNonBlock; // At this point we've found a non-block parent where we // could stick things, but we have to fix things up in @@ -791,19 +821,6 @@ namespace Slang return inst; } - - IRDecoration* createEmptyDecoration( - IRModule* module, - IRDecorationOp op, - size_t sizeInBytes) - { - SLANG_ASSERT(sizeInBytes >= sizeof(IRDecoration)); - SLANG_ASSERT(module); - IRDecoration* decor = (IRDecoration*)module->memoryArena.allocateAndZero(sizeInBytes); - decor->op = op; - return decor; - } - // Given an instruction that represents a constant, a type, etc. // Try to "hoist" it as far toward the global scope as possible // to insert it at a location where it will be maximally visible. @@ -814,7 +831,7 @@ namespace Slang { // Start with the assumption that we would insert this instruction // into the global scope (the instruction that represents the module) - IRParentInst* parent = builder->getModule()->getModuleInst(); + IRInst* parent = builder->getModule()->getModuleInst(); // The above decision might be invalid, because there might be // one or more operands of the instruction that are defined in @@ -1177,13 +1194,14 @@ namespace Slang return code; } - UnownedStringSlice IRConstant::getStringSlice() const + UnownedStringSlice IRConstant::getStringSlice() { assert(op == kIROp_StringLit); // If the transitory decoration is set, then this is uses the transitoryStringVal for the text storage. // This is typically used when we are using a transitory IRInst held on the stack (such that it can be looked up in cached), // that just points to a string elsewhere, and NOT the typical normal style, where the string is held after the instruction in memory. - if (firstDecoration && firstDecoration->op == kIRDecorationOp_Transitory) + // + if(findDecorationImpl(kIROp_TransitoryDecoration)) { return UnownedStringSlice(value.transitoryStringVal.chars, value.transitoryStringVal.numChars); } @@ -1217,6 +1235,10 @@ namespace Slang // ... we can just compare as bits return value.intVal == rhs.value.intVal; } + case kIROp_PtrLit: + { + return value.ptrVal == rhs.value.ptrVal; + } case kIROp_StringLit: { return getStringSlice() == rhs.getStringSlice(); @@ -1243,6 +1265,10 @@ namespace Slang // ... we can just compare as bits return combineHash(code, Slang::GetHashCode(value.intVal)); } + case kIROp_PtrLit: + { + return combineHash(code, Slang::GetHashCode(value.ptrVal)); + } case kIROp_StringLit: { const UnownedStringSlice slice = getStringSlice(); @@ -1283,6 +1309,10 @@ namespace Slang switch (keyInst.op) { + default: + SLANG_UNEXPECTED("missing case for IR constant"); + break; + case kIROp_BoolLit: case kIROp_IntLit: { @@ -1296,6 +1326,12 @@ namespace Slang irValue->value.floatVal = keyInst.value.floatVal; break; } + case kIROp_PtrLit: + { + irValue = static_cast<IRConstant*>(createInstWithSizeImpl(builder, keyInst.op, keyInst.getFullType(), prefixSize + sizeof(void*))); + irValue->value.ptrVal = keyInst.value.ptrVal; + break; + } case kIROp_StringLit: { const UnownedStringSlice slice = keyInst.getStringSlice(); @@ -1363,8 +1399,10 @@ namespace Slang memset(&keyInst, 0, sizeof(keyInst)); // Mark that this is on the stack... - static IRDecoration stackDecoration = IRDecoration::make(kIRDecorationOp_Transitory); - keyInst.firstDecoration = &stackDecoration; + IRDecoration stackDecoration; + memset(&stackDecoration, 0, sizeof(stackDecoration)); + stackDecoration.op = kIROp_TransitoryDecoration; + stackDecoration.insertAtEnd(&keyInst); keyInst.op = kIROp_StringLit; keyInst.typeUse.usedValue = getStringType(); @@ -1375,6 +1413,19 @@ namespace Slang return static_cast<IRStringLit*>(findOrEmitConstant(this, keyInst)); } + + IRPtrLit* IRBuilder::getPtrValue(void* value) + { + IRType* type = getPtrType(getVoidType()); + + IRConstant keyInst; + memset(&keyInst, 0, sizeof(keyInst)); + keyInst.op = kIROp_PtrLit; + keyInst.typeUse.usedValue = type; + keyInst.value.ptrVal = value; + return (IRPtrLit*) findOrEmitConstant(this, keyInst); + } + IRInst* findOrEmitHoistableInst( IRBuilder* builder, @@ -2162,19 +2213,6 @@ namespace Slang return inst; } - IRNotePatchConstantFunc* IRBuilder::emitNotePatchConstantFunc( - IRInst* func) - { - auto inst = createInst<IRNotePatchConstantFunc>( - this, - kIROp_NotePatchConstantFunc, - nullptr, - func); - - addInst(inst); - return inst; - } - IRInst* IRBuilder::emitFieldExtract( IRType* type, IRInst* base, @@ -2549,18 +2587,40 @@ namespace Slang return inst; } - IRHighLevelDeclDecoration* IRBuilder::addHighLevelDeclDecoration(IRInst* inst, Decl* decl) + IRDecoration* IRBuilder::addDecoration(IRInst* value, IROp op, IRInst* const* operands, Int operandCount) { - auto decoration = addDecoration<IRHighLevelDeclDecoration>(inst, kIRDecorationOp_HighLevelDecl); - decoration->decl = decl; + auto decoration = createInstWithTrailingArgs<IRDecoration>( + this, + op, + getVoidType(), + operandCount, + operands); + + // Decoration order should not, in general, be semantically + // meaningful, so we will elect to insert a new decoration + // at the start of an instruction (constant time) rather + // than at the end of any existing list of deocrations + // (which would take time linear in the number of decorations). + // + // TODO: revisit this if maintaining decoration ordering + // from input source code is desirable. + // + decoration->insertAtStart(value); + return decoration; } - IRLayoutDecoration* IRBuilder::addLayoutDecoration(IRInst* inst, Layout* layout) + + void IRBuilder::addHighLevelDeclDecoration(IRInst* inst, Decl* decl) { - auto decoration = addDecoration<IRLayoutDecoration>(inst); - decoration->layout = addRefObjectToFree(layout); - return decoration; + auto ptrConst = getPtrValue(addRefObjectToFree(decl)); + addDecoration(inst, kIROp_HighLevelDeclDecoration, ptrConst); + } + + void IRBuilder::addLayoutDecoration(IRInst* inst, Layout* layout) + { + auto ptrConst = getPtrValue(addRefObjectToFree(layout)); + addDecoration(inst, kIROp_LayoutDecoration, ptrConst); } // @@ -2905,74 +2965,25 @@ namespace Slang for(; inst; inst = inst->getNextInst()) { dumpInst(context, inst); + dump(context, "\n"); } } + static void dumpInstBody( + IRDumpContext* context, + IRInst* inst); + void dumpIRDecorations( IRDumpContext* context, IRInst* inst) { - for( auto dd = inst->firstDecoration; dd; dd = dd->next ) + for(auto dd : inst->getDecorations()) { - switch( dd->op ) - { - case kIRDecorationOp_Target: - { - auto decoration = (IRTargetDecoration*) dd; - - dump(context, "\n"); - dumpIndent(context); - dump(context, "[target("); - dump(context, StringRepresentation::getData(decoration->targetName)); - dump(context, ")]"); - } - break; + dump(context, "["); + dumpInstBody(context, dd); + dump(context, "]\n"); - case kIRDecorationOp_TargetIntrinsic: - { - auto decoration = (IRTargetIntrinsicDecoration*) dd; - - dump(context, "\n"); - dumpIndent(context); - dump(context, "[targetIntrinsic("); - dump(context, StringRepresentation::getData(decoration->targetName)); - dump(context, ", "); - dump(context, StringRepresentation::getData(decoration->definition)); - dump(context, ")]"); - } - break; - - case kIRDecorationOp_VulkanRayPayload: - { - dump(context, "\n[__vulkanRayPayload]"); - } - break; - case kIRDecorationOp_VulkanCallablePayload: - { - dump(context, "\n[__vulkanCallPayload]"); - } - break; - case kIRDecorationOp_VulkanHitAttributes: - { - dump(context, "\n[__vulkanHitAttributes]"); - } - break; - case kIRDecorationOp_ReadNone: - { - dump(context, "\n[__readNone]"); - } - break; - case kIRDecorationOp_EarlyDepthStencil: - { - dump(context, "\n[earlydepthstencil]"); - } - break; - case kIRDecorationOp_GloballyCoherent: - { - dump(context, "\n[globallycoherent]"); - } - break; - } + dumpIndent(context); } } @@ -2982,7 +2993,6 @@ namespace Slang { auto opInfo = getIROpInfo(code->op); - dump(context, "\n"); dumpIndent(context); dump(context, opInfo.name); dump(context, " "); @@ -3038,11 +3048,10 @@ namespace Slang void dumpIRParentInst( IRDumpContext* context, - IRParentInst* inst) + IRInst* inst) { auto opInfo = getIROpInfo(inst->op); - dump(context, "\n"); dumpIndent(context); dump(context, opInfo.name); dump(context, " "); @@ -3063,9 +3072,10 @@ namespace Slang dump(context, "{\n"); context->indent++; - for (auto child = inst->getFirstChild(); child; child = child->getNextInst()) + for(auto child : inst->getChildren()) { dumpInst(context, child); + dump(context, "\n"); } context->indent--; @@ -3086,19 +3096,19 @@ namespace Slang for (auto ii : witnessTable->getChildren()) { dumpInst(context, ii); + dump(context, "\n"); } context->indent--; dump(context, "}\n"); } - static void dumpInst( + static void dumpInstBody( IRDumpContext* context, IRInst* inst) { if (!inst) { - dumpIndent(context); dump(context, "<null>"); return; } @@ -3121,7 +3131,7 @@ namespace Slang case kIROp_WitnessTable: case kIROp_StructType: - dumpIRParentInst(context, (IRWitnessTable*)inst); + dumpIRParentInst(context, inst); return; case kIROp_WitnessTableEntry: @@ -3133,8 +3143,6 @@ namespace Slang } // Okay, we have a seemingly "ordinary" op now - dumpIndent(context); - auto opInfo = getIROpInfo(op); auto dataType = inst->getDataType(); auto rate = inst->getRate(); @@ -3201,8 +3209,14 @@ namespace Slang } dump(context, ")"); + } - dump(context, "\n"); + static void dumpInst( + IRDumpContext* context, + IRInst* inst) + { + dumpIndent(context); + dumpInstBody(context, inst); } void dumpIRModule( @@ -3212,6 +3226,7 @@ namespace Slang for(auto ii : module->getGlobalInsts()) { dumpInst(context, ii); + dump(context, "\n"); } } @@ -3257,6 +3272,57 @@ namespace Slang // // + IRDecoration* IRInst::getFirstDecoration() + { + return as<IRDecoration>(getFirstDecorationOrChild()); + } + + IRDecoration* IRInst::getLastDecoration() + { + IRDecoration* decoration = getFirstDecoration(); + if (!decoration) return nullptr; + + while (auto nextDecoration = decoration->getNextDecoration()) + decoration = nextDecoration; + + return decoration; + } + + IRInstList<IRDecoration> IRInst::getDecorations() + { + return IRInstList<IRDecoration>( + getFirstDecoration(), + getLastDecoration()); + } + + IRInst* IRInst::getFirstChild() + { + // The children come after any decorations, + // so if there are any decorations, then the + // first child is right after the last decoration. + // + if(auto lastDecoration = getLastDecoration()) + return lastDecoration->getNextInst(); + // + // Otherwise, there must be no decorations, so + // that the first "child or decoration" is a child. + // + return getFirstDecorationOrChild(); + } + + IRInst* IRInst::getLastChild() + { + // The children come after any decorations, so + // that the last item in the list of children + // and decorations is the last child *unless* + // it is a decoration, in which case there are + // no children. + // + auto lastChild = getLastDecorationOrChild(); + return as<IRDecoration>(lastChild) ? nullptr : lastChild; + } + + IRRate* IRInst::getRate() { if(auto rateQualifiedType = as<IRRateQualifiedType>(getFullType())) @@ -3345,13 +3411,13 @@ namespace Slang void IRInst::insertBefore(IRInst* other) { SLANG_ASSERT(other); - insertBefore(other, other->parent); + _insertAt(other->getPrevInst(), other, other->getParent()); } - void IRInst::insertAtStart(IRParentInst* newParent) + void IRInst::insertAtStart(IRInst* newParent) { SLANG_ASSERT(newParent); - insertBefore(newParent->children.first, newParent); + _insertAt(nullptr, newParent->getFirstDecorationOrChild(), newParent); } void IRInst::moveToStart() @@ -3361,52 +3427,49 @@ namespace Slang insertAtStart(p); } - void IRInst::insertBefore(IRInst* other, IRParentInst* newParent) + void IRInst::_insertAt(IRInst* inPrev, IRInst* inNext, IRInst* inParent) { // Make sure this instruction has been removed from any previous parent this->removeFromParent(); - SLANG_ASSERT(other || newParent); - if (!other) other = newParent->children.first; - if (!newParent) newParent = other->parent; - SLANG_ASSERT(newParent); - - auto nn = other; - auto pp = other ? other->getPrevInst() : nullptr; + SLANG_ASSERT(inParent); + SLANG_ASSERT(!inPrev || (inPrev->getNextInst() == inNext) && (inPrev->getParent() == inParent)); + SLANG_ASSERT(!inNext || (inNext->getPrevInst() == inPrev) && (inNext->getParent() == inParent)); - if( pp ) + if( inPrev ) { - pp->next = this; + inPrev->next = this; } else { - newParent->children.first = this; + inParent->m_decorationsAndChildren.first = this; } - if (nn) + if (inNext) { - nn->prev = this; + inNext->prev = this; } else { - newParent->children.last = this; + inParent->m_decorationsAndChildren.last = this; } - this->prev = pp; - this->next = nn; - this->parent = newParent; + this->prev = inPrev; + this->next = inNext; + this->parent = inParent; } void IRInst::insertAfter(IRInst* other) { SLANG_ASSERT(other); - insertAfter(other, other->parent); + + _insertAt(other, other->getNextInst(), other->getParent()); } - void IRInst::insertAtEnd(IRParentInst* newParent) + void IRInst::insertAtEnd(IRInst* newParent) { SLANG_ASSERT(newParent); - insertAfter(newParent->children.last, newParent); + _insertAt(newParent->getLastDecorationOrChild(), nullptr, newParent); } void IRInst::moveToEnd() @@ -3416,42 +3479,6 @@ namespace Slang insertAtEnd(p); } - void IRInst::insertAfter(IRInst* other, IRParentInst* newParent) - { - // Make sure this instruction has been removed from any previous parent - this->removeFromParent(); - - SLANG_ASSERT(other || newParent); - if (!other) other = newParent->children.last; - if (!newParent) newParent = other->parent; - SLANG_ASSERT(newParent); - - auto pp = other; - auto nn = other ? other->next : nullptr; - - if (pp) - { - pp->next = this; - } - else - { - newParent->children.first = this; - } - - if (nn) - { - nn->prev = this; - } - else - { - newParent->children.last = this; - } - - this->prev = pp; - this->next = nn; - this->parent = newParent; - } - // Remove this instruction from its parent block, // and then destroy it (it had better have no uses!) void IRInst::removeFromParent() @@ -3473,7 +3500,7 @@ namespace Slang } else { - oldParent->children.first = nn; + oldParent->m_decorationsAndChildren.first = nn; } if(nn) @@ -3483,7 +3510,7 @@ namespace Slang } else { - oldParent->children.last = pp; + oldParent->m_decorationsAndChildren.last = pp; } prev = nullptr; @@ -3507,23 +3534,16 @@ namespace Slang { removeFromParent(); removeArguments(); - - // If this is a parent instruction then we had - // better remove all its children as well. - // - if(auto parentInst = as<IRParentInst>(this)) - { - parentInst->removeAndDeallocateAllChildren(); - } + removeAndDeallocateAllDecorationsAndChildren(); // Run destructor to be sure... this->~IRInst(); } - void IRParentInst::removeAndDeallocateAllChildren() + void IRInst::removeAndDeallocateAllDecorationsAndChildren() { IRInst* nextChild = nullptr; - for( IRInst* child = getFirstChild(); child; child = nextChild ) + for( IRInst* child = getFirstDecorationOrChild(); child; child = nextChild ) { nextChild = child->getNextInst(); child->removeAndDeallocate(); @@ -4153,8 +4173,7 @@ namespace Slang if(auto outerArrayName = systemValueInfo->outerArrayName) { - auto decoration = builder->addDecoration<IRGLSLOuterArrayDecoration>(globalVariable); - decoration->outerArrayName = outerArrayName; + builder->addGLSLOuterArrayDecoration(globalVariable, UnownedTerminatedStringSlice(outerArrayName)); } } @@ -4689,13 +4708,13 @@ namespace Slang IRInst* val, String const& targetName) { - for( auto dd = val->firstDecoration; dd; dd = dd->next ) + for(auto dd : val->getDecorations()) { - if(dd->op != kIRDecorationOp_TargetIntrinsic) + if(dd->op != kIROp_TargetIntrinsicDecoration) continue; auto decoration = (IRTargetIntrinsicDecoration*) dd; - if(String(decoration->targetName) == targetName) + if(String(decoration->getTargetName()) == targetName) return decoration; } @@ -4864,7 +4883,7 @@ namespace Slang if(!decoration) continue; - if(StringRepresentation::asSlice(decoration->definition) != UnownedStringSlice::fromLiteral("EmitVertex()")) + if(decoration->getDefinition() != UnownedStringSlice::fromLiteral("EmitVertex()")) { continue; } @@ -5340,117 +5359,40 @@ namespace Slang } } - void cloneDecorations( + IRInst* cloneInst( + IRSpecContextBase* context, + IRBuilder* builder, + IRInst* originalInst, + IROriginalValuesForClone const& originalValues); + + IRInst* cloneInst( IRSpecContextBase* context, - IRInst* clonedValue, - IRInst* originalValue) + IRBuilder* builder, + IRInst* originalInst) { - for (auto dd = originalValue->firstDecoration; dd; dd = dd->next) - { - switch (dd->op) - { - case kIRDecorationOp_HighLevelDecl: - { - auto originalDecoration = (IRHighLevelDeclDecoration*)dd; - - context->builder->addHighLevelDeclDecoration(clonedValue, originalDecoration->decl); - } - break; - - case kIRDecorationOp_LoopControl: - { - auto originalDecoration = (IRLoopControlDecoration*)dd; - auto newDecoration = context->builder->addDecoration<IRLoopControlDecoration>(clonedValue); - newDecoration->mode = originalDecoration->mode; - } - break; - - case kIRDecorationOp_TargetIntrinsic: - { - auto originalDecoration = (IRTargetIntrinsicDecoration*)dd; - auto newDecoration = context->builder->addDecoration<IRTargetIntrinsicDecoration>(clonedValue); - newDecoration->targetName = originalDecoration->targetName; - newDecoration->definition = originalDecoration->definition; - } - break; - - case kIRDecorationOp_Semantic: - { - auto originalDecoration = (IRSemanticDecoration*)dd; - auto newDecoration = context->builder->addDecoration<IRSemanticDecoration>(clonedValue); - newDecoration->semanticName = originalDecoration->semanticName; - } - break; - - case kIRDecorationOp_InterpolationMode: - { - auto originalDecoration = (IRInterpolationModeDecoration*)dd; - auto newDecoration = context->builder->addDecoration<IRInterpolationModeDecoration>(clonedValue); - newDecoration->mode = originalDecoration->mode; - } - break; - - case kIRDecorationOp_NameHint: - { - auto originalDecoration = (IRNameHintDecoration*)dd; - auto newDecoration = context->builder->addDecoration<IRNameHintDecoration>(clonedValue); - newDecoration->name = originalDecoration->name; - } - break; - - case kIRDecorationOp_VulkanRayPayload: - { - context->builder->addDecoration<IRVulkanRayPayloadDecoration>(clonedValue); - } - break; - - case kIRDecorationOp_VulkanCallablePayload: - { - context->builder->addDecoration<IRVulkanCallablePayloadDecoration>(clonedValue); - } - break; - case kIRDecorationOp_EarlyDepthStencil: - { - context->builder->addDecoration<IREarlyDepthStencilDecoration>(clonedValue); - } - break; - case kIRDecorationOp_GloballyCoherent: - { - context->builder->addDecoration<IRGloballyCoherentDecoration>(clonedValue); - } - break; - case kIRDecorationOp_VulkanHitAttributes: - { - context->builder->addDecoration<IRVulkanHitAttributesDecoration>(clonedValue); - } - break; + return cloneInst(context, builder, originalInst, originalInst); + } - case kIRDecorationOp_RequireGLSLExtension: - { - auto originalDecoration = (IRRequireGLSLExtensionDecoration*)dd; - auto newDecoration = context->builder->addDecoration<IRRequireGLSLExtensionDecoration>(clonedValue); - newDecoration->extensionName = originalDecoration->extensionName; - } - break; + /// Clone any decorations from `originalValue` onto `clonedValue` + void cloneDecorations( + IRSpecContextBase* context, + IRInst* clonedValue, + IRInst* originalValue) + { + // TODO: In many cases we might be able to use this as a general-purpose + // place to do cloning of *all* the children of an instruction, and + // not just its decorations. We should look to refactor this code + // later. - case kIRDecorationOp_RequireGLSLVersion: - { - auto originalDecoration = (IRRequireGLSLVersionDecoration*)dd; - auto newDecoration = context->builder->addDecoration<IRRequireGLSLVersionDecoration>(clonedValue); - newDecoration->languageVersion = originalDecoration->languageVersion; - } - break; + IRBuilder builderStorage = *context->builder; + IRBuilder* builder = &builderStorage; + builder->setInsertInto(clonedValue); - case kIRDecorationOp_ReadNone: - { - context->builder->addDecoration<IRReadNoneDecoration>(clonedValue); - } - break; - default: - // Don't clone any decorations we don't understand. - break; - } + SLANG_UNUSED(context); + for(auto originalDecoration : originalValue->getDecorations()) + { + cloneInst(context, builder, originalDecoration); } // We will also clone the location here, just because this is a convenient bottleneck @@ -5510,6 +5452,20 @@ namespace Slang } break; + case kIROp_StringLit: + { + IRConstant* c = (IRConstant*)originalValue; + return builder->getStringValue(c->getStringSlice()); + } + break; + + case kIROp_PtrLit: + { + IRConstant* c = (IRConstant*)originalValue; + return builder->getPtrValue(c->value.ptrVal); + } + break; + default: { // In the deafult case, assume that we have some sort of "hoistable" @@ -5596,20 +5552,6 @@ namespace Slang return cloneValue(context, originalValue); } - IRInst* cloneInst( - IRSpecContextBase* context, - IRBuilder* builder, - IRInst* originalInst, - IROriginalValuesForClone const& originalValues); - - IRInst* cloneInst( - IRSpecContextBase* context, - IRBuilder* builder, - IRInst* originalInst) - { - return cloneInst(context, builder, originalInst, originalInst); - } - void cloneGlobalValueWithCodeCommon( IRSpecContextBase* context, IRGlobalValueWithCode* clonedValue, @@ -5652,8 +5594,6 @@ namespace Slang auto mangledName = originalVar->mangledName; clonedVar->mangledName = mangledName; - cloneDecorations(context, clonedVar, originalVar); - VarLayout* layout = nullptr; if (context->globalVarLayouts.TryGetValue(mangledName, layout)) { @@ -5683,8 +5623,6 @@ namespace Slang auto mangledName = originalVal->mangledName; clonedVal->mangledName = mangledName; - cloneDecorations(context, clonedVal, originalVal); - // Clone any code in the body of the constant, since this // represents the initializer. cloneGlobalValueWithCodeCommon( @@ -5707,8 +5645,6 @@ namespace Slang auto mangledName = originalVal->mangledName; clonedVal->mangledName = mangledName; - cloneDecorations(context, clonedVal, originalVal); - // Clone any code in the body of the generic, since this // computes its result value. cloneGlobalValueWithCodeCommon( @@ -5732,15 +5668,13 @@ namespace Slang auto mangledName = originalInst->mangledName; clonedInst->mangledName = mangledName; - cloneDecorations(context, clonedInst, originalInst); - // Set up an IR builder for inserting into the inst IRBuilder builderStorage = *context->builder; IRBuilder* builder = &builderStorage; builder->setInsertInto(clonedInst); // Clone any children of the instruction - for (auto child : originalInst->getChildren()) + for (auto child : originalInst->getDecorationsAndChildren()) { cloneInst(context, builder, child); } @@ -5812,6 +5746,7 @@ namespace Slang IRBuilder* builder = &builderStorage; builder->setInsertInto(clonedValue); + cloneDecorations(context, clonedValue, originalValue); // We will walk through the blocks of the function, and clone each of them. // @@ -5864,10 +5799,10 @@ namespace Slang } - void checkIRDuplicate(IRInst* inst, IRParentInst* moduleInst, Name* mangledName) + void checkIRDuplicate(IRInst* inst, IRInst* moduleInst, Name* mangledName) { #ifdef _DEBUG - for (auto child : moduleInst->getChildren()) + for (auto child : moduleInst->getDecorationsAndChildren()) { if (child == inst) continue; @@ -5898,8 +5833,6 @@ namespace Slang clonedFunc->mangledName = originalFunc->mangledName; clonedFunc->setFullType(cloneType(context, originalFunc->getFullType())); - cloneDecorations(context, clonedFunc, originalFunc); - cloneGlobalValueWithCodeCommon( context, clonedFunc, @@ -6052,13 +5985,13 @@ namespace Slang } TargetSpecializationLevel result = TargetSpecializationLevel::notSpecialized; - for( auto dd = val->firstDecoration; dd; dd = dd->next ) + for(auto dd : val->getDecorations()) { - if(dd->op != kIRDecorationOp_Target) + if(dd->op != kIROp_TargetDecoration) continue; auto decoration = (IRTargetDecoration*) dd; - if(String(decoration->targetName) == targetName) + if(String(decoration->getTargetName()) == targetName) return TargetSpecializationLevel::specializedForTarget; result = TargetSpecializationLevel::specializedForOtherTarget; @@ -6124,7 +6057,7 @@ namespace Slang case kIROp_GlobalConstant: case kIROp_Func: case kIROp_Generic: - return ((IRParentInst*)val)->getFirstChild() != nullptr; + return val->getFirstChild() != nullptr; case kIROp_StructType: case kIROp_GlobalVar: @@ -6704,18 +6637,13 @@ namespace Slang // We do *not* consider generics, or instructions nested under them. return; } - else if(auto parentInst = as<IRParentInst>(inst)) + else { - // For a parent instruction, we will scan through its contents, - // since that will be where the `specialize` instructions are - - for(auto child : parentInst->children) + for(auto child : inst->getChildren()) { addToSpecializationWorkListRec(sharedContext, child); } - } - else - { + // Default case: consider this instruction for specialization. sharedContext->addToWorkList(inst); } @@ -6806,12 +6734,9 @@ namespace Slang // We expect a generic to only ever contain a single block. SLANG_ASSERT(bb == genericVal->getFirstBlock()); - for (auto ii : bb->getChildren()) + // Iterate over the non-parameter ("ordinary") instructions. + for (auto ii : bb->getOrdinaryInsts()) { - // Skip parameters, since they were handled earlier. - if (auto param = as<IRParam>(ii)) - continue; - // The last block of the generic is expected to end with // a `return` instruction for the specialized value that // comes out of the abstraction. diff --git a/source/slang/ir.h b/source/slang/ir.h index 0b75a487f..8183e038a 100644 --- a/source/slang/ir.h +++ b/source/slang/ir.h @@ -137,68 +137,93 @@ struct IRUse void debugValidate(); }; -enum IRDecorationOp : uint16_t -{ - kIRDecorationOp_HighLevelDecl, - kIRDecorationOp_Layout, - kIRDecorationOp_LoopControl, - kIRDecorationOp_Target, - kIRDecorationOp_TargetIntrinsic, - kIRDecorationOp_GLSLOuterArray, - kIRDecorationOp_Semantic, - kIRDecorationOp_InterpolationMode, - kIRDecorationOp_NameHint, - - /** The _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. */ - kIRDecorationOp_Transitory, - kIRDecorationOp_VulkanRayPayload, - kIRDecorationOp_VulkanHitAttributes, - kIRDecorationOp_RequireGLSLVersion, - kIRDecorationOp_RequireGLSLExtension, - kIRDecorationOp_ReadNone, - kIRDecorationOp_VulkanCallablePayload, - - kIRDecorationOp_EarlyDepthStencil, - kIRDecorationOp_GloballyCoherent, - - kIRDecorationOp_CountOf -}; +struct IRBlock; +struct IRDecoration; +struct IRRate; +struct IRType; -// represents an object allocated in an IR memory arena -struct IRObject +// A double-linked list of instruction +struct IRInstListBase { + IRInstListBase() + {} + + IRInstListBase(IRInst* first, IRInst* last) + : first(first) + , last(last) + {} + + + + IRInst* first = nullptr; + IRInst* last = nullptr; + + IRInst* getFirst() { return first; } + IRInst* getLast() { return last; } + + struct Iterator + { + IRInst* inst; + + Iterator() : inst(nullptr) {} + Iterator(IRInst* inst) : inst(inst) {} + + void operator++(); + IRInst* operator*() + { + return inst; + } + + bool operator!=(Iterator const& i) + { + return inst != i.inst; + } + }; + + Iterator begin(); + Iterator end(); }; -// A "decoration" that gets applied to an instruction. -// These usually don't affect semantics, but are useful -// for preserving high-level source information. -struct IRDecoration : public IRObject +// Specialization of `IRInstListBase` for the case where +// we know (or at least expect) all of the instructions +// to be of type `T` +template<typename T> +struct IRInstList : IRInstListBase { - static IRDecoration make(IRDecorationOp opIn, IRDecoration* nextIn = nullptr) + IRInstList() {} + + IRInstList(T* first, T* last) + : IRInstListBase(first, last) + {} + + explicit IRInstList(IRInstListBase const& list) + : IRInstListBase(list) + {} + + T* getFirst() { return (T*) first; } + T* getLast() { return (T*) last; } + + struct Iterator : public IRInstListBase::Iterator { - IRDecoration dec; - dec.next = nextIn; - dec.op = opIn; - return dec; - } + Iterator() {} + Iterator(IRInst* inst) : IRInstListBase::Iterator(inst) {} - // Next decoration attached to the same instruction - IRDecoration* next; + T* operator*() + { + return (T*) inst; + } + }; - IRDecorationOp op; + Iterator begin() { return Iterator(first); } + Iterator end(); }; -struct IRBlock; -struct IRParentInst; -struct IRRate; -struct IRType; + // Every value in the IR is an instruction (even things // like literal values). // -struct IRInst : public IRObject +struct IRInst { // The operation that this value represents IROp op; @@ -220,15 +245,21 @@ struct IRInst : public IRObject // Source location information for this value, if any SourceLoc sourceLoc; - // The linked list of decorations attached to this value - IRDecoration* firstDecoration = nullptr; + // Each instruction can have zero or more "decorations" + // attached to it. A decoration is a specialized kind + // of instruction that either attaches metadata to, + // or modifies the sematnics of, its parent instruction. + // + IRDecoration* getFirstDecoration(); + IRDecoration* getLastDecoration(); + IRInstList<IRDecoration> getDecorations(); // Look up a decoration in the list of decorations - IRDecoration* findDecorationImpl(IRDecorationOp op); + IRDecoration* findDecorationImpl(IROp op); template<typename T> T* findDecoration() { - return (T*) findDecorationImpl(IRDecorationOp(T::kDecorationOp)); + return (T*) findDecorationImpl(IROp(T::kOp)); } // The first use of this value (start of a linked list) @@ -236,9 +267,9 @@ struct IRInst : public IRObject // The parent of this instruction. - IRParentInst* parent; + IRInst* parent; - IRParentInst* getParent() { return parent; } + IRInst* getParent() { return parent; } // The next and previous instructions with the same parent IRInst* next; @@ -247,6 +278,42 @@ struct IRInst : public IRObject IRInst* getNextInst() { return next; } IRInst* getPrevInst() { return prev; } + // An instruction can have zero or more children, although + // only certain instruction opcodes are allowed to have + // children. + // + // For example, a function will have children that are + // its basic blocks, and the basic blocks will have children + // that represent parameters and ordinary executable instructions. + // + IRInst* getFirstChild(); + IRInst* getLastChild(); + IRInstList<IRInst> getChildren() + { + return IRInstList<IRInst>( + getFirstChild(), + getLastChild()); + } + + /// A doubly-linked list containing any decorations and then any children of this instruction. + /// + /// We store both the decorations and children of an instruction + /// in the same list, to conserve space in the instruction itself + /// (rather than storing distinct lists for decorations and children). + /// + // Note: This field is *not* being declared `private` because doing so could + // mess with our required memory layout, where `typeUse` below is assumed + // to be the last field in `IRInst` and to come right before any additional + // `IRUse` values that represent operands. + // + IRInstListBase m_decorationsAndChildren; + + IRInst* getFirstDecorationOrChild() { return m_decorationsAndChildren.first; } + IRInst* getLastDecorationOrChild() { return m_decorationsAndChildren.last; } + IRInstListBase getDecorationsAndChildren() { return m_decorationsAndChildren; } + + void removeAndDeallocateAllDecorationsAndChildren(); + // The type of the result value of this instruction, // or `null` to indicate that the instruction has // no value. @@ -289,17 +356,13 @@ struct IRInst : public IRObject void insertAfter(IRInst* other); // Insert as first/last child of given parent - void insertAtStart(IRParentInst* parent); - void insertAtEnd(IRParentInst* parent); + void insertAtStart(IRInst* parent); + void insertAtEnd(IRInst* parent); // Move to the start/end of current parent void moveToStart(); void moveToEnd(); - // Insert before/after the given instruction, in a specific block - void insertBefore(IRInst* other, IRParentInst* parent); - void insertAfter(IRInst* other, IRParentInst* parent); - // Remove this instruction from its parent block, // but don't delete it, or replace uses. void removeFromParent(); @@ -332,6 +395,16 @@ struct IRInst : public IRObject /// If this instruction is transitively nested inside some IR module, /// this function will return it, and will otherwise return `null`. IRModule* getModule(); + + /// Insert this instruction into `inParent`, after `inPrev` and before `inNext`. + /// + /// `inParent` must be non-null + /// If `inPrev` is non-null it must satisfy `inPrev->getNextInst() == inNext` and `inPrev->getParent() == inParent` + /// If `inNext` is non-null it must satisfy `inNext->getPrevInst() == inPrev` and `inNext->getParent() == inParent` + /// + /// If both `inPrev` and `inNext` are null, then `inParent` must have no (raw) children. + /// + void _insertAt(IRInst* inPrev, IRInst* inNext, IRInst* inParent); }; // `dynamic_cast` equivalent @@ -351,89 +424,15 @@ T* cast(IRInst* inst, T* /* */ = nullptr) return (T*)inst; } +// Now that `IRInst` is defined we can back-fill the `IRInstList<T>` members +// that need to access it. -// A double-linked list of instruction -struct IRInstListBase -{ - IRInstListBase() - {} - - IRInstListBase(IRInst* first, IRInst* last) - : first(first) - , last(last) - {} - - - - IRInst* first = nullptr; - IRInst* last = nullptr; - - IRInst* getFirst() { return first; } - IRInst* getLast() { return last; } - - struct Iterator - { - IRInst* inst; - - Iterator() : inst(nullptr) {} - Iterator(IRInst* inst) : inst(inst) {} - - void operator++() - { - if (inst) - { - inst = inst->next; - } - } - - IRInst* operator*() - { - return inst; - } - - bool operator!=(Iterator const& i) - { - return inst != i.inst; - } - }; - - Iterator begin() { return Iterator(first); } - Iterator end() { return Iterator(last ? last->next : nullptr); } -}; - -// Specialization of `IRInstListBase` for the case where -// we know (or at least expect) all of the instructions -// to be of type `T` template<typename T> -struct IRInstList : IRInstListBase +typename IRInstList<T>::Iterator IRInstList<T>::end() { - IRInstList() {} - - IRInstList(T* first, T* last) - : IRInstListBase(first, last) - {} - - explicit IRInstList(IRInstListBase const& list) - : IRInstListBase(list) - {} - - T* getFirst() { return (T*) first; } - T* getLast() { return (T*) last; } - - struct Iterator : public IRInstListBase::Iterator - { - Iterator() {} - Iterator(IRInst* inst) : IRInstListBase::Iterator(inst) {} - - T* operator*() - { - return (T*) inst; - } - }; + return Iterator(last ? last->next : nullptr); +} - Iterator begin() { return Iterator(first); } - Iterator end() { return Iterator(last ? last->next : nullptr); } -}; // Types @@ -494,16 +493,17 @@ struct IRConstant : IRInst { IRIntegerValue intVal; ///< Used for integrals and boolean IRFloatingPointValue floatVal; + void* ptrVal; /// Either of these types could be set with kIROp_StringLit. - /// Which is used is currently determined with IRDecorationOp - if a kDecorationOp_Transitory is set, then the transitory StringVal is used, else stringVal + /// Which is used is currently determined with decorations - if a kIROp_TransitoryDecoration is set, then the transitory StringVal is used, else stringVal // which relies on chars being held after the struct). StringValue stringVal; StringSliceValue transitoryStringVal; }; /// Returns a string slice (or empty string if not appropriate) - UnownedStringSlice getStringSlice() const; + UnownedStringSlice getStringSlice(); /// True if constants are equal bool equal(IRConstant& rhs); @@ -542,6 +542,13 @@ struct IRStringLit : IRConstant IR_LEAF_ISA(StringLit); }; +struct IRPtrLit : IRConstant +{ + IR_LEAF_ISA(PtrLit); + + void* getValue() { return value.ptrVal; } +}; + // A instruction that ends a basic block (usually because of control flow) struct IRTerminatorInst : IRInst { @@ -564,49 +571,36 @@ struct IRParam : IRInst IR_LEAF_ISA(Param) }; -// A "parent" instruction is one that contains other instructions -// as its children. The most common case of a parent instruction -// is a basic block, but there are other cases (e.g., a function -// is in turn a parent for basic blocks). -struct IRParentInst : IRInst -{ - // The instructions stored under this parent - IRInstListBase children; - - IRInst* getFirstChild() { return children.first; } - IRInst* getLastChild() { return children.last; } - IRInstListBase getChildren() { return children; } - - void removeAndDeallocateAllChildren(); - - IR_PARENT_ISA(ParentInst) -}; - // A basic block is a parent instruction that adds the constraint // that all the children need to be "ordinary" instructions (so // no function declarations, or nested blocks). We also expect // that the previous/next instruction are always a basic block. // -struct IRBlock : IRParentInst +struct IRBlock : IRInst { // Linked list of the instructions contained in this block // - IRInstListBase getChildren() { return children; } - IRInst* getFirstInst() { return children.first; } - IRInst* getLastInst() { return children.last; } + IRInst* getFirstInst() { return getChildren().first; } + IRInst* getLastInst() { return getChildren().last; } // In a valid program, every basic block should end with // a "terminator" instruction. // // This function will return the terminator, if it exists, // or `null` if there is none. - IRTerminatorInst* getTerminator() { return as<IRTerminatorInst>(getLastInst()); } + IRTerminatorInst* getTerminator() { return as<IRTerminatorInst>(getLastDecorationOrChild()); } // We expect that the siblings of a basic block will // always be other basic blocks (we don't allow // mixing of blocks and other instructions in the // same parent). - IRBlock* getPrevBlock() { return cast<IRBlock>(getPrevInst()); } + // + // The exception to this is that decorations on the function + // that contains a block could appear before the first block, + // so we need to be careful to do a dynamic cast (`as`) in + // the `getPrevBlock` case, but don't need to worry about + // it for `getNextBlock`. + IRBlock* getPrevBlock() { return as<IRBlock>(getPrevInst()); } IRBlock* getNextBlock() { return cast<IRBlock>(getNextInst()); } // The parameters of a block are represented by `IRParam` @@ -922,7 +916,7 @@ struct IRFuncType : IRType // A "global value" is an instruction that might have // linkage, so that it can be declared in one module // and then resolved to a definition in another module. -struct IRGlobalValue : IRParentInst +struct IRGlobalValue : IRInst { // The mangled name, for a symbol that should have linkage, // or which might have multiple declarations. @@ -1064,7 +1058,7 @@ IRInst* getResolvedInstForDecorations(IRInst* inst); // The IR module itself is represented as an instruction, which // serves at the root of the tree of all instructions in the module. -struct IRModuleInst : IRParentInst +struct IRModuleInst : IRInst { // Pointer back to the non-instruction object that represents // the module, so that we can get back to it in algorithms @@ -1125,18 +1119,6 @@ IRInst* createEmptyInstWithSize( IRModule* module, IROp op, size_t totalSizeInBytes); - -IRDecoration* createEmptyDecoration( - IRModule* module, - IRDecorationOp op, - size_t sizeInBytes); - -template <typename T> -T* createEmptyDecoration(IRModule* module) -{ - return static_cast<T*>(createEmptyDecoration(module, IRDecorationOp(T::kDecorationOp), sizeof(T))); -} - } diff --git a/source/slang/legalize-types.cpp b/source/slang/legalize-types.cpp index 1f0fe93cb..15d7a4621 100644 --- a/source/slang/legalize-types.cpp +++ b/source/slang/legalize-types.cpp @@ -355,7 +355,7 @@ struct TupleTypeBuilder if(auto nameHintDecoration = originalStructType->findDecoration<IRNameHintDecoration>()) { - builder->addDecoration<IRNameHintDecoration>(ordinaryStructType)->name = nameHintDecoration->name; + builder->addNameHintDecoration(ordinaryStructType, nameHintDecoration->getNameOperand()); } // The new struct type will appear right after the original in the IR, diff --git a/source/slang/lower-to-ir.cpp b/source/slang/lower-to-ir.cpp index 09f463ab6..8af6292e6 100644 --- a/source/slang/lower-to-ir.cpp +++ b/source/slang/lower-to-ir.cpp @@ -1238,39 +1238,39 @@ void addVarDecorations( { if(mod.As<HLSLNoInterpolationModifier>()) { - builder->addDecoration<IRInterpolationModeDecoration>(inst)->mode = IRInterpolationMode::NoInterpolation; + builder->addInterpolationModeDecoration(inst, IRInterpolationMode::NoInterpolation); } else if(mod.As<HLSLNoPerspectiveModifier>()) { - builder->addDecoration<IRInterpolationModeDecoration>(inst)->mode = IRInterpolationMode::NoPerspective; + builder->addInterpolationModeDecoration(inst, IRInterpolationMode::NoPerspective); } else if(mod.As<HLSLLinearModifier>()) { - builder->addDecoration<IRInterpolationModeDecoration>(inst)->mode = IRInterpolationMode::Linear; + builder->addInterpolationModeDecoration(inst, IRInterpolationMode::Linear); } else if(mod.As<HLSLSampleModifier>()) { - builder->addDecoration<IRInterpolationModeDecoration>(inst)->mode = IRInterpolationMode::Sample; + builder->addInterpolationModeDecoration(inst, IRInterpolationMode::Sample); } else if(mod.As<HLSLCentroidModifier>()) { - builder->addDecoration<IRInterpolationModeDecoration>(inst)->mode = IRInterpolationMode::Centroid; + builder->addInterpolationModeDecoration(inst, IRInterpolationMode::Centroid); } else if(mod.As<VulkanRayPayloadAttribute>()) { - builder->addDecoration<IRVulkanRayPayloadDecoration>(inst); + builder->addSimpleDecoration<IRVulkanRayPayloadDecoration>(inst); } else if(mod.As<VulkanCallablePayloadAttribute>()) { - builder->addDecoration<IRVulkanCallablePayloadDecoration>(inst); + builder->addSimpleDecoration<IRVulkanCallablePayloadDecoration>(inst); } else if(mod.As<VulkanHitAttributesAttribute>()) { - builder->addDecoration<IRVulkanHitAttributesDecoration>(inst); + builder->addSimpleDecoration<IRVulkanHitAttributesDecoration>(inst); } else if(mod.As<GloballyCoherentModifier>()) { - builder->addDecoration<IRGloballyCoherentDecoration>(inst); + builder->addSimpleDecoration<IRGloballyCoherentDecoration>(inst); } // TODO: what are other modifiers we need to propagate through? @@ -1294,7 +1294,7 @@ void maybeSetRate( } } -static Name* getNameForNameHint( +static String getNameForNameHint( IRGenContext* context, Decl* decl) { @@ -1311,9 +1311,9 @@ static Name* getNameForNameHint( // There is no point in trying to provide a name hint for something with no name, // or with an empty name if(!leafName) - return nullptr; + return String(); if(leafName->text.Length() == 0) - return nullptr; + return String(); if(auto varDecl = dynamic_cast<VarDeclBase*>(decl)) @@ -1326,7 +1326,7 @@ static Name* getNameForNameHint( // TODO: consider whether global/static variables should // follow different rules. // - return leafName; + return leafName->text; } // For other cases of declaration, we want to consider @@ -1338,9 +1338,9 @@ static Name* getNameForNameHint( parentDecl = genericParentDecl->ParentDecl; auto parentName = getNameForNameHint(context, parentDecl); - if(!parentName) + if(parentName.Length() == 0) { - return leafName; + return leafName->text; } // TODO: at some point we will start giving `ModuleDecl`s names, @@ -1351,11 +1351,11 @@ static Name* getNameForNameHint( // combining the name of the parent and the leaf declaration. StringBuilder sb; - sb.append(parentName->text); + sb.append(parentName); sb.append("."); sb.append(leafName->text); - return context->getSession()->getNameObj(sb.ProduceString()); + return sb.ProduceString(); } /// Try to add an appropriate name hint to the instruction, @@ -1365,10 +1365,10 @@ static void addNameHint( IRInst* inst, Decl* decl) { - Name* name = getNameForNameHint(context, decl); - if(!name) + String name = getNameForNameHint(context, decl); + if(name.Length() == 0) return; - context->irBuilder->addDecoration<IRNameHintDecoration>(inst)->name = name; + context->irBuilder->addNameHintDecoration(inst, name.getUnownedSlice()); } /// Add a name hint based on a fixed string. @@ -1377,8 +1377,7 @@ static void addNameHint( IRInst* inst, char const* text) { - Name* name = context->getSession()->getNameObj(text); - context->irBuilder->addDecoration<IRNameHintDecoration>(inst)->name = name; + context->irBuilder->addNameHintDecoration(inst, UnownedTerminatedStringSlice(text)); } LoweredValInfo createVar( @@ -2410,8 +2409,7 @@ struct StmtLoweringVisitor : StmtVisitor<StmtLoweringVisitor> { if( stmt->FindModifier<UnrollAttribute>() ) { - auto decoration = getBuilder()->addDecoration<IRLoopControlDecoration>(inst); - decoration->mode = kIRLoopControl_Unroll; + getBuilder()->addLoopControlDecoration(inst, kIRLoopControl_Unroll); } // TODO: handle other cases here } @@ -4313,8 +4311,7 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> if (auto semanticModifier = fieldDecl->FindModifier<HLSLSimpleSemantic>()) { - auto semanticDecoration = builder->addDecoration<IRSemanticDecoration>(irFieldKey); - semanticDecoration->semanticName = semanticModifier->name.getName(); + builder->addSemanticDecoration(irFieldKey, semanticModifier->name.getName()->text.getUnownedSlice()); } // We allow a field to be marked as a target intrinsic, @@ -4779,18 +4776,18 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> for (auto targetMod : decl->GetModifiersOfType<TargetIntrinsicModifier>()) { - auto decoration = builder->addDecoration<IRTargetIntrinsicDecoration>(irInst); - decoration->targetName = builder->addStringToFree(targetMod->targetToken.Content); - + String definition; auto definitionToken = targetMod->definitionToken; if (definitionToken.type == TokenType::StringLiteral) { - decoration->definition = builder->addStringToFree(getStringLiteralTokenValue(definitionToken)); + definition = getStringLiteralTokenValue(definitionToken); } else { - decoration->definition = builder->addStringToFree(definitionToken.Content); + definition = definitionToken.Content; } + + builder->addTargetIntrinsicDecoration(irInst, targetMod->targetToken.Content.getUnownedSlice(), definition.getUnownedSlice()); } } @@ -5076,12 +5073,12 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> // Convert the patch constant function into IRInst IRInst* irPatchConstantFunc = getSimpleVal(context, ensureDecl(subContext, patchConstantFunc)); - // Emit the note patch constant func - subContext->irBuilder->emitIntrinsicInst( - nullptr, - kIROp_NotePatchConstantFunc, - 1, - &irPatchConstantFunc); + // Attach a decoration so that our IR function references + // the patch constant function. + // + subContext->irBuilder->addPatchConstantFuncDecoration( + irFunc, + irPatchConstantFunc); } } @@ -5122,8 +5119,7 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> // a specialized definition of the particular function for the given // target, and we need to reflect that at the IR level. - auto decoration = getBuilder()->addDecoration<IRTargetDecoration>(irFunc); - decoration->targetName = getBuilder()->addStringToFree(targetMod->targetToken.Content); + getBuilder()->addTargetDecoration(irFunc, targetMod->targetToken.Content.getUnownedSlice()); } // If this declaration was marked as having a target-specific lowering @@ -5138,23 +5134,21 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> // for(auto extensionMod : decl->GetModifiersOfType<RequiredGLSLExtensionModifier>()) { - auto decoration = getBuilder()->addDecoration<IRRequireGLSLExtensionDecoration>(irFunc); - decoration->extensionName = getBuilder()->addStringToFree(extensionMod->extensionNameToken.Content); + getBuilder()->addRequireGLSLExtensionDecoration(irFunc, extensionMod->extensionNameToken.Content.getUnownedSlice()); } for(auto versionMod : decl->GetModifiersOfType<RequiredGLSLVersionModifier>()) { - auto decoration = getBuilder()->addDecoration<IRRequireGLSLVersionDecoration>(irFunc); - decoration->languageVersion = Int(getIntegerLiteralValue(versionMod->versionNumberToken)); + getBuilder()->addRequireGLSLVersionDecoration(irFunc, Int(getIntegerLiteralValue(versionMod->versionNumberToken))); } if(decl->FindModifier<ReadNoneAttribute>()) { - getBuilder()->addDecoration<IRReadNoneDecoration>(irFunc); + getBuilder()->addSimpleDecoration<IRReadNoneDecoration>(irFunc); } if (decl->FindModifier<EarlyDepthStencilAttribute>()) { - getBuilder()->addDecoration<IREarlyDepthStencilDecoration>(irFunc); + getBuilder()->addSimpleDecoration<IREarlyDepthStencilDecoration>(irFunc); } // For convenience, ensure that any additional global diff --git a/source/slang/slang.natvis b/source/slang/slang.natvis index 247064f3a..0045b8f84 100644 --- a/source/slang/slang.natvis +++ b/source/slang/slang.natvis @@ -93,31 +93,6 @@ </Expand> </Synthetic> <Item Name="[parent]">parent</Item> - <Synthetic Name="[children]" Condition="(op >= Slang::kIROp_FirstParentInst) && (op <= Slang::kIROp_LastParentInst)"> - <Expand> - <LinkedListItems> - <HeadPointer>(*((Slang::IRParentInst*) this)).children.first</HeadPointer> - <NextPointer>next</NextPointer> - <ValueNode>this</ValueNode> - </LinkedListItems> - </Expand> - </Synthetic> - <Synthetic Name="[uses]"> - <Expand> - <LinkedListItems> - <HeadPointer>firstUse</HeadPointer> - <NextPointer>nextUse</NextPointer> - <ValueNode>user</ValueNode> - </LinkedListItems> - </Expand> - </Synthetic> - </Expand> - </Type> - <Type Name="Slang::IRParentInst"> - <DisplayString>{{{op}}}</DisplayString> - <Expand> - <Item Name="[op]">op</Item> - <Item Name="[type]">typeUse.usedValue</Item> <Synthetic Name="[children]"> <Expand> <LinkedListItems> @@ -127,7 +102,6 @@ </LinkedListItems> </Expand> </Synthetic> - <Item Name="[parent]">parent</Item> <Synthetic Name="[uses]"> <Expand> <LinkedListItems> @@ -137,7 +111,7 @@ </LinkedListItems> </Expand> </Synthetic> - </Expand> + </Expand> </Type> <Type Name="Slang::IRGlobalValue"> <DisplayString>{{{op} "{mangledName}"}}</DisplayString> |
