diff options
Diffstat (limited to 'source/slang/slang-ir.cpp')
| -rw-r--r-- | source/slang/slang-ir.cpp | 565 |
1 files changed, 509 insertions, 56 deletions
diff --git a/source/slang/slang-ir.cpp b/source/slang/slang-ir.cpp index 78758d944..89e49816f 100644 --- a/source/slang/slang-ir.cpp +++ b/source/slang/slang-ir.cpp @@ -205,6 +205,24 @@ namespace Slang return nullptr; } + IROperandListBase IRInst::getAllAttrs() + { + // We assume as an invariant that all attributes appear at the end of the operand + // list, after all the non-attribute operands. + // + // We will therefore define a range that ends at the end of the operand list ... + // + IRUse* end = getOperands() + getOperandCount(); + // + // ... and begins after the last non-attribute operand. + // + IRUse* cursor = getOperands(); + while(cursor != end && !as<IRAttr>(cursor->get())) + cursor++; + + return IROperandListBase(cursor, end); + } + // IRConstant IRIntegerValue GetIntVal(IRInst* inst) @@ -696,6 +714,371 @@ namespace Slang } // + // IRTypeLayout + // + + IRTypeSizeAttr* IRTypeLayout::findSizeAttr(LayoutResourceKind kind) + { + // TODO: If we could assume the attributes were sorted + // by `kind`, then we could use a binary search here + // instead of linear. + // + // In practice, the number of entries will be very small, + // so the cost of the linear search should not be too bad. + + for( auto sizeAttr : getSizeAttrs() ) + { + if(sizeAttr->getResourceKind() == kind) + return sizeAttr; + } + return nullptr; + } + + IRTypeLayout* IRTypeLayout::unwrapArray() + { + auto typeLayout = this; + while(auto arrayTypeLayout = as<IRArrayTypeLayout>(typeLayout)) + typeLayout = arrayTypeLayout->getElementTypeLayout(); + return typeLayout; + } + + IRTypeLayout* IRTypeLayout::getPendingDataTypeLayout() + { + if(auto attr = findAttr<IRPendingLayoutAttr>()) + return cast<IRTypeLayout>(attr->getLayout()); + return nullptr; + } + + IROperandList<IRTypeSizeAttr> IRTypeLayout::getSizeAttrs() + { + return findAttrs<IRTypeSizeAttr>(); + } + + IRTypeLayout::Builder::Builder(IRBuilder* irBuilder) + : m_irBuilder(irBuilder) + {} + + void IRTypeLayout::Builder::addResourceUsage( + LayoutResourceKind kind, + LayoutSize size) + { + auto& resInfo = m_resInfos[Int(kind)]; + resInfo.kind = kind; + resInfo.size += size; + } + + void IRTypeLayout::Builder::addResourceUsage(IRTypeSizeAttr* sizeAttr) + { + addResourceUsage( + sizeAttr->getResourceKind(), + sizeAttr->getSize()); + } + + void IRTypeLayout::Builder::addResourceUsageFrom(IRTypeLayout* typeLayout) + { + for( auto sizeAttr : typeLayout->getSizeAttrs() ) + { + addResourceUsage(sizeAttr); + } + } + + IRTypeLayout* IRTypeLayout::Builder::build() + { + IRBuilder* irBuilder = getIRBuilder(); + + List<IRInst*> operands; + + addOperands(operands); + addAttrs(operands); + + return irBuilder->getTypeLayout( + getOp(), + operands); + } + + void IRTypeLayout::Builder::addOperands(List<IRInst*>& operands) + { + addOperandsImpl(operands); + } + + void IRTypeLayout::Builder::addAttrs(List<IRInst*>& operands) + { + auto irBuilder = getIRBuilder(); + + for(auto resInfo : m_resInfos) + { + if(resInfo.kind == LayoutResourceKind::None) + continue; + + IRInst* sizeAttr = irBuilder->getTypeSizeAttr( + resInfo.kind, + resInfo.size); + operands.add(sizeAttr); + } + + if( auto pendingTypeLayout = m_pendingTypeLayout ) + { + operands.add(irBuilder->getPendingLayoutAttr( + pendingTypeLayout)); + } + + addAttrsImpl(operands); + } + + // + // IRParameterGroupTypeLayout + // + + void IRParameterGroupTypeLayout::Builder::addOperandsImpl(List<IRInst*>& ioOperands) + { + ioOperands.add(m_containerVarLayout); + ioOperands.add(m_elementVarLayout); + ioOperands.add(m_offsetElementTypeLayout); + } + + IRParameterGroupTypeLayout* IRParameterGroupTypeLayout::Builder::build() + { + return cast<IRParameterGroupTypeLayout>(Super::Builder::build()); + } + + // + // IRStructTypeLayout + // + + void IRStructTypeLayout::Builder::addAttrsImpl(List<IRInst*>& ioOperands) + { + auto irBuilder = getIRBuilder(); + for(auto field : m_fields) + { + ioOperands.add( + irBuilder->getFieldLayoutAttr(field.key, field.layout)); + } + } + + // + // IRArrayTypeLayout + // + + void IRArrayTypeLayout::Builder::addOperandsImpl(List<IRInst*>& ioOperands) + { + ioOperands.add(m_elementTypeLayout); + } + + // + // IRStreamOutputTypeLayout + // + + void IRStreamOutputTypeLayout::Builder::addOperandsImpl(List<IRInst*>& ioOperands) + { + ioOperands.add(m_elementTypeLayout); + } + + // + // IRMatrixTypeLayout + // + + IRMatrixTypeLayout::Builder::Builder(IRBuilder* irBuilder, MatrixLayoutMode mode) + : Super::Builder(irBuilder) + { + m_modeInst = irBuilder->getIntValue(irBuilder->getIntType(), IRIntegerValue(mode)); + } + + void IRMatrixTypeLayout::Builder::addOperandsImpl(List<IRInst*>& ioOperands) + { + ioOperands.add(m_modeInst); + } + + // + // IRTaggedUnionTypeLayout + // + + IRTaggedUnionTypeLayout::Builder::Builder(IRBuilder* irBuilder, LayoutSize tagOffset) + : Super::Builder(irBuilder) + { + m_tagOffset = irBuilder->getIntValue(irBuilder->getIntType(), tagOffset.raw); + } + + void IRTaggedUnionTypeLayout::Builder::addCaseTypeLayout(IRTypeLayout* typeLayout) + { + m_caseTypeLayoutAttrs.add(getIRBuilder()->getCaseTypeLayoutAttr(typeLayout)); + } + + void IRTaggedUnionTypeLayout::Builder::addOperandsImpl(List<IRInst*>& ioOperands) + { + ioOperands.add(m_tagOffset); + } + + void IRTaggedUnionTypeLayout::Builder::addAttrsImpl(List<IRInst*>& ioOperands) + { + for(auto attr : m_caseTypeLayoutAttrs) + ioOperands.add(attr); + } + + // + // IRVarLayout + // + + bool IRVarLayout::usesResourceKind(LayoutResourceKind kind) + { + // TODO: basing this check on whether or not the + // var layout has an entry for `kind` means that + // we can't just optimize away any entry where + // the offset is zero (which might be a small + // but nice optimization). We could consider shifting + // this test to use the entries on the type layout + // instead (since non-zero resource consumption + // should be an equivalent test). + + return findOffsetAttr(kind) != nullptr; + } + + IRSystemValueSemanticAttr* IRVarLayout::findSystemValueSemanticAttr() + { + return findAttr<IRSystemValueSemanticAttr>(); + } + + IRVarOffsetAttr* IRVarLayout::findOffsetAttr(LayoutResourceKind kind) + { + for( auto offsetAttr : getOffsetAttrs() ) + { + if(offsetAttr->getResourceKind() == kind) + return offsetAttr; + } + return nullptr; + } + + IROperandList<IRVarOffsetAttr> IRVarLayout::getOffsetAttrs() + { + return findAttrs<IRVarOffsetAttr>(); + } + + Stage IRVarLayout::getStage() + { + if(auto stageAttr = findAttr<IRStageAttr>()) + return stageAttr->getStage(); + return Stage::Unknown; + } + + IRVarLayout* IRVarLayout::getPendingVarLayout() + { + if( auto pendingLayoutAttr = findAttr<IRPendingLayoutAttr>() ) + { + return cast<IRVarLayout>(pendingLayoutAttr->getLayout()); + } + return nullptr; + } + + IRVarLayout::Builder::Builder( + IRBuilder* irBuilder, + IRTypeLayout* typeLayout) + : m_irBuilder(irBuilder) + , m_typeLayout(typeLayout) + {} + + bool IRVarLayout::Builder::usesResourceKind(LayoutResourceKind kind) + { + return m_resInfos[Int(kind)].kind != LayoutResourceKind::None; + } + + IRVarLayout::Builder::ResInfo* IRVarLayout::Builder::findOrAddResourceInfo(LayoutResourceKind kind) + { + auto& resInfo = m_resInfos[Int(kind)]; + resInfo.kind = kind; + return &resInfo; + } + + void IRVarLayout::Builder::setSystemValueSemantic(String const& name, UInt index) + { + m_systemValueSemantic = getIRBuilder()->getSystemValueSemanticAttr(name, index); + } + + void IRVarLayout::Builder::setUserSemantic(String const& name, UInt index) + { + m_userSemantic = getIRBuilder()->getUserSemanticAttr(name, index); + } + + void IRVarLayout::Builder::setStage(Stage stage) + { + m_stageAttr = getIRBuilder()->getStageAttr(stage); + } + + void IRVarLayout::Builder::cloneEverythingButOffsetsFrom( + IRVarLayout* that) + { + if(auto systemValueSemantic = that->findAttr<IRSystemValueSemanticAttr>()) + m_systemValueSemantic = systemValueSemantic; + + if(auto userSemantic = that->findAttr<IRUserSemanticAttr>()) + m_userSemantic = userSemantic; + + if(auto stageAttr = that->findAttr<IRStageAttr>()) + m_stageAttr = stageAttr; + } + + IRVarLayout* IRVarLayout::Builder::build() + { + SLANG_ASSERT(m_typeLayout); + + IRBuilder* irBuilder = getIRBuilder(); + + List<IRInst*> operands; + + operands.add(m_typeLayout); + + for(auto resInfo : m_resInfos) + { + if(resInfo.kind == LayoutResourceKind::None) + continue; + + IRInst* varOffsetAttr = irBuilder->getVarOffsetAttr( + resInfo.kind, + resInfo.offset, + resInfo.space); + operands.add(varOffsetAttr); + } + + if(auto semanticAttr = m_userSemantic) + operands.add(semanticAttr); + + if(auto semanticAttr = m_systemValueSemantic) + operands.add(semanticAttr); + + if(auto stageAttr = m_stageAttr) + operands.add(stageAttr); + + if(auto pendingVarLayout = m_pendingVarLayout) + { + IRInst* pendingLayoutAttr = irBuilder->getPendingLayoutAttr( + pendingVarLayout); + operands.add(pendingLayoutAttr); + } + + return irBuilder->getVarLayout(operands); + } + + // + // IREntryPointLayout + // + + IRStructTypeLayout* getScopeStructLayout(IREntryPointLayout* scopeLayout) + { + auto scopeTypeLayout = scopeLayout->getParamsLayout()->getTypeLayout(); + + if( auto constantBufferTypeLayout = as<IRParameterGroupTypeLayout>(scopeTypeLayout) ) + { + scopeTypeLayout = constantBufferTypeLayout->getOffsetElementTypeLayout(); + } + + if( auto structTypeLayout = as<IRStructTypeLayout>(scopeTypeLayout) ) + { + return structTypeLayout; + } + + SLANG_UNEXPECTED("uhandled global-scope binding layout"); + UNREACHABLE_RETURN(nullptr); + } + + // IRBlock* IRBuilder::getBlock() { @@ -3086,79 +3469,149 @@ namespace Slang addDecoration(inst, kIROp_HighLevelDeclDecoration, ptrConst); } - void IRBuilder::addLayoutDecoration(IRInst* value, Layout* layout) + void IRBuilder::addLayoutDecoration(IRInst* value, IRLayout* layout) + { + addDecoration(value, kIROp_LayoutDecoration, layout); + } + + IRTypeSizeAttr* IRBuilder::getTypeSizeAttr( + LayoutResourceKind kind, + LayoutSize size) { - IRLayout* irLayout = getLayout(layout); - addDecoration(value, kIROp_LayoutDecoration, irLayout); + auto kindInst = getIntValue(getIntType(), IRIntegerValue(kind)); + auto sizeInst = getIntValue(getIntType(), IRIntegerValue(size.raw)); + IRInst* operands[] = { kindInst, sizeInst }; + return cast<IRTypeSizeAttr>(findOrEmitHoistableInst( + getVoidType(), + kIROp_TypeSizeAttr, + SLANG_COUNT_OF(operands), + operands)); } - IRLayout* IRBuilder::getLayout(Layout* astLayout) + IRVarOffsetAttr* IRBuilder::getVarOffsetAttr( + LayoutResourceKind kind, + UInt offset, + UInt space) { - if (astLayout == nullptr) - { - return nullptr; - } + IRInst* operands[3]; + UInt operandCount = 0; - IRLayout* irLayout = nullptr; - if(sharedBuilder->layoutMap.TryGetValue(astLayout, irLayout)) - { - SLANG_ASSERT(irLayout->getASTLayout() == astLayout); - return irLayout; - } + auto kindInst = getIntValue(getIntType(), IRIntegerValue(kind)); + operands[operandCount++] = kindInst; + + auto offsetInst = getIntValue(getIntType(), IRIntegerValue(offset)); + operands[operandCount++] = offsetInst; - if (EntryPointLayout* entryPointLayout = as<EntryPointLayout>(astLayout)) + if(space) { - irLayout = createInst<IREntryPointLayout>(this, kIROp_EntryPointLayout, nullptr, getPtrValue(astLayout)); + auto spaceInst = getIntValue(getIntType(), IRIntegerValue(space)); + operands[operandCount++] = spaceInst; } - else if (VarLayout* varLayout = as<VarLayout>(astLayout)) - { - UnownedStringSlice nameSlice; - if (varLayout->getVariable()) - { - Name* name = varLayout->getName(); - if (name) - { - nameSlice = name->text.getUnownedSlice(); - } - } - // Get the name as a literal. - // We use an empty length string, as we can't use a null inst ptr. - // If there was a 'null' instruction then it might make more sense to use that - IRStringLit* nameLit = getStringValue(nameSlice); - - // Layout, name, type layout, absolute layout - IRInst* args[4] = { - getPtrValue(astLayout), - nameLit, - getLayout(varLayout->getTypeLayout()), - getLayout(varLayout->m_absoluteLayout) - }; + return cast<IRVarOffsetAttr>(findOrEmitHoistableInst( + getVoidType(), + kIROp_VarOffsetAttr, + operandCount, + operands)); + } - irLayout = createInst<IRVarLayout>(this, kIROp_VarLayout, nullptr, 4, args); - } - else if (TypeLayout* typeLayout = as<TypeLayout>(astLayout)) - { - irLayout = createInst<IRTypeLayout>(this, kIROp_TypeLayout, nullptr, getPtrValue(astLayout)); - } - else - { - SLANG_UNEXPECTED("Unknown layout type"); - } + IRPendingLayoutAttr* IRBuilder::getPendingLayoutAttr( + IRLayout* pendingLayout) + { + IRInst* operands[] = { pendingLayout }; + + return cast<IRPendingLayoutAttr>(findOrEmitHoistableInst( + getVoidType(), + kIROp_PendingLayoutAttr, + SLANG_COUNT_OF(operands), + operands)); + } + + IRStructFieldLayoutAttr* IRBuilder::getFieldLayoutAttr( + IRStructKey* key, + IRVarLayout* layout) + { + IRInst* operands[] = { key, layout }; + + return cast<IRStructFieldLayoutAttr>(findOrEmitHoistableInst( + getVoidType(), + kIROp_StructFieldLayoutAttr, + SLANG_COUNT_OF(operands), + operands)); + } + + IRCaseTypeLayoutAttr* IRBuilder::getCaseTypeLayoutAttr( + IRTypeLayout* layout) + { + IRInst* operands[] = { layout }; + + return cast<IRCaseTypeLayoutAttr>(findOrEmitHoistableInst( + getVoidType(), + kIROp_CaseTypeLayoutAttr, + SLANG_COUNT_OF(operands), + operands)); + } + + IRSemanticAttr* IRBuilder::getSemanticAttr( + IROp op, + String const& name, + UInt index) + { + auto nameInst = getStringValue(name.getUnownedSlice()); + auto indexInst = getIntValue(getIntType(), index); + + IRInst* operands[] = { nameInst, indexInst }; + + return cast<IRSemanticAttr>(findOrEmitHoistableInst( + getVoidType(), + op, + SLANG_COUNT_OF(operands), + operands)); + } + + IRStageAttr* IRBuilder::getStageAttr(Stage stage) + { + auto stageInst = getIntValue(getIntType(), IRIntegerValue(stage)); + IRInst* operands[] = { stageInst }; + return cast<IRStageAttr>(findOrEmitHoistableInst( + getVoidType(), + kIROp_StageAttr, + SLANG_COUNT_OF(operands), + operands)); + } - SLANG_ASSERT(irLayout); - SLANG_ASSERT(irLayout->getASTLayout() == astLayout); - sharedBuilder->layoutMap[astLayout] = irLayout; + IRTypeLayout* IRBuilder::getTypeLayout(IROp op, List<IRInst*> const& operands) + { + return cast<IRTypeLayout>(findOrEmitHoistableInst( + getVoidType(), + op, + operands.getCount(), + operands.getBuffer())); + } - addGlobalValue(this, irLayout); + IRVarLayout* IRBuilder::getVarLayout(List<IRInst*> const& operands) + { + return cast<IRVarLayout>(findOrEmitHoistableInst( + getVoidType(), + kIROp_VarLayout, + operands.getCount(), + operands.getBuffer())); + } - // need to keep in scope - addRefObjectToFree(astLayout); + IREntryPointLayout* IRBuilder::getEntryPointLayout( + IRVarLayout* paramsLayout, + IRVarLayout* resultLayout) + { + IRInst* operands[] = { paramsLayout, resultLayout }; - return irLayout; + return cast<IREntryPointLayout>(findOrEmitHoistableInst( + getVoidType(), + kIROp_EntryPointLayout, + SLANG_COUNT_OF(operands), + operands)); } // |
