From 62d3e387774255be4d507cca045ac97dabac9970 Mon Sep 17 00:00:00 2001 From: Tim Foley Date: Tue, 11 Dec 2018 15:17:55 -0800 Subject: Decorations are instructions (#748) * Make a test case use IR serialization * Make all IR instructions usable as parents This makes it so that every `IRInst` has the list of children that used to be on `IRParentInst` and eliminates `IRParentInst`. Most places in the code were only checking against `IRParentInst` so that they could know whether there were child instructions to iterate over. This change bloats the size of every instruction by two pointers, but we hope to be able to eliminate that overhead with a better encoding later. * Change IR decorations to be instructions. The main change here is that `IRDecoration` now inherits from `IRInst`, and `IRInst` now has a single linked list that holds both decorations *and* children. At each point where code used to loop over `getChildren()` on an `IRInst`, I checked whether it made sense to leave the operation as processing just the children, or if it should process both decorations and children. The thorniest bit was making sure the logic for inserting an instruction into a parent is correct. For the most part, once IR code is built all insertions are explicitly before/after another instruction, so the ordering can't get messed up. The sticking point is any code that does an explicit `insertAtStart` or `insertAtEnd`, but I surveyed those to make sure they are correct in context, and I also made all insertions bottleneck through one routine that does a better job of asserting the preconditions than what was there before. We may still want a "smart" insertion function at some point so that if somebody does `someDecoration->insertAtEnd(someInst)` the decoration intelligently goes to the end of the decoration list, and not the entire decorations-and-children list. All of the existing decoration types were refactored to provide accessors for their operands, rather than directly exposing fields. In most cases the operands are required to be `IRConstant` nodes of fixed types. Not all of these types need to be kept around in the new approach, but they were left in so that as much existing code as possible can be kept working. The `IRBuilder` was extended with factory functions to make the various decoration types and attach them. All the fields in concrete decorations that were using `StringRepresentation` or `Name` pointers are now using IR-level string operands which provide their value as an `UnownedStringSlice`, so logic that was working with those decoration values needed to be updated here and there. I also needed to add the logic to clone string-literal values to the IR cloning pass, since they are now being used in almost every piece of code. A new type of constant IR instruction for literal pointers was added, to handle the cases where an IR decoration needs an operand that is a raw AST-level pointer. These are even being serialized, although we obviously should not rely on them to round-trip through serialization in the future. Ideally, a follow-on change should add a cleanup pass where we remove any decorations from a module that shouldn't be allowed in the serialized code. The biggest overall cleanup is in the serialization logic, where a lot of code just disappears because it can process the raw "decorations and children" list as the logical children of an IR instruction. The only special cases left are literals (which seem like they will always need special-casing) and global values (because they have a mangled name, which we plan to move into a decoration). One other example of a simplification made possible by this change: the `IRNotePatchConstantFunc` instruction was implemented as an instruction only because it couldn't be encoded as a decoration at the time (it needed to have an operand that referenced an IR function). The IR dumping logic was also updated (which meant a change to the `ir/string-literal` test) to try to make it print out all decorations a bit more systematically now that they are encoded like other instructions. The formatting isn't quite perfect, but it is good enough to be able to read what is going on. I didn't include updates to the validation logic to ensure that decorations are being added in ways that follow the invariants, but that would be a nice thing to add next. * fixup: 64-bit issues * fixup: forward declaration issues --- source/slang/ir.cpp | 609 +++++++++++++++++++++++----------------------------- 1 file changed, 267 insertions(+), 342 deletions(-) (limited to 'source/slang/ir.cpp') 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(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(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( - 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(inst, kIRDecorationOp_HighLevelDecl); - decoration->decl = decl; + auto decoration = createInstWithTrailingArgs( + 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(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, ""); 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(getFirstDecorationOrChild()); + } + + IRDecoration* IRInst::getLastDecoration() + { + IRDecoration* decoration = getFirstDecoration(); + if (!decoration) return nullptr; + + while (auto nextDecoration = decoration->getNextDecoration()) + decoration = nextDecoration; + + return decoration; + } + + IRInstList IRInst::getDecorations() + { + return IRInstList( + 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(lastChild) ? nullptr : lastChild; + } + + IRRate* IRInst::getRate() { if(auto rateQualifiedType = as(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(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(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(clonedValue); - newDecoration->mode = originalDecoration->mode; - } - break; - - case kIRDecorationOp_TargetIntrinsic: - { - auto originalDecoration = (IRTargetIntrinsicDecoration*)dd; - auto newDecoration = context->builder->addDecoration(clonedValue); - newDecoration->targetName = originalDecoration->targetName; - newDecoration->definition = originalDecoration->definition; - } - break; - - case kIRDecorationOp_Semantic: - { - auto originalDecoration = (IRSemanticDecoration*)dd; - auto newDecoration = context->builder->addDecoration(clonedValue); - newDecoration->semanticName = originalDecoration->semanticName; - } - break; - - case kIRDecorationOp_InterpolationMode: - { - auto originalDecoration = (IRInterpolationModeDecoration*)dd; - auto newDecoration = context->builder->addDecoration(clonedValue); - newDecoration->mode = originalDecoration->mode; - } - break; - - case kIRDecorationOp_NameHint: - { - auto originalDecoration = (IRNameHintDecoration*)dd; - auto newDecoration = context->builder->addDecoration(clonedValue); - newDecoration->name = originalDecoration->name; - } - break; - - case kIRDecorationOp_VulkanRayPayload: - { - context->builder->addDecoration(clonedValue); - } - break; - - case kIRDecorationOp_VulkanCallablePayload: - { - context->builder->addDecoration(clonedValue); - } - break; - case kIRDecorationOp_EarlyDepthStencil: - { - context->builder->addDecoration(clonedValue); - } - break; - case kIRDecorationOp_GloballyCoherent: - { - context->builder->addDecoration(clonedValue); - } - break; - case kIRDecorationOp_VulkanHitAttributes: - { - context->builder->addDecoration(clonedValue); - } - break; + return cloneInst(context, builder, originalInst, originalInst); + } - case kIRDecorationOp_RequireGLSLExtension: - { - auto originalDecoration = (IRRequireGLSLExtensionDecoration*)dd; - auto newDecoration = context->builder->addDecoration(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(clonedValue); - newDecoration->languageVersion = originalDecoration->languageVersion; - } - break; + IRBuilder builderStorage = *context->builder; + IRBuilder* builder = &builderStorage; + builder->setInsertInto(clonedValue); - case kIRDecorationOp_ReadNone: - { - context->builder->addDecoration(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(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(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. -- cgit v1.2.3