diff options
| author | Yong He <yonghe@outlook.com> | 2021-04-16 10:34:26 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-04-16 10:34:26 -0700 |
| commit | 79e92395f8ce3d92c446e3bb3250d19ce33decd5 (patch) | |
| tree | 2ac277fa299200da72cf03a2b5b96338f66aee5d /source/slang/slang-lower-to-ir.cpp | |
| parent | bad484d838590d0a2aaf1b5b8ac820634af2decb (diff) | |
Update `model-viewer` example and fixing compiler bugs. (#1795)
Diffstat (limited to 'source/slang/slang-lower-to-ir.cpp')
| -rw-r--r-- | source/slang/slang-lower-to-ir.cpp | 158 |
1 files changed, 138 insertions, 20 deletions
diff --git a/source/slang/slang-lower-to-ir.cpp b/source/slang/slang-lower-to-ir.cpp index 3c9256178..de5a07c0d 100644 --- a/source/slang/slang-lower-to-ir.cpp +++ b/source/slang/slang-lower-to-ir.cpp @@ -15,6 +15,7 @@ #include "slang-ir-strip.h" #include "slang-ir-validate.h" #include "slang-ir-string-hash.h" +#include "slang-ir-clone.h" #include "slang-mangle.h" #include "slang-type-layout.h" @@ -6098,23 +6099,32 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> auto entry = subBuilder->createInterfaceRequirementEntry( getInterfaceRequirementKey(requirementDecl), nullptr); - IRInst* requirementVal = ensureDecl(subContext, requirementDecl).val; - if (requirementVal) + if (auto inheritance = as<InheritanceDecl>(requirementDecl)) { - switch (requirementVal->getOp()) - { - case kIROp_Func: - case kIROp_Generic: + auto irBaseType = lowerType(context, inheritance->base.type); + auto irWitnessTableType = subBuilder->getWitnessTableType(irBaseType); + entry->setRequirementVal(irWitnessTableType); + } + else + { + IRInst* requirementVal = ensureDecl(subContext, requirementDecl).val; + if (requirementVal) { - // Remove lowered `IRFunc`s since we only care about - // function types. - auto reqType = requirementVal->getFullType(); - entry->setRequirementVal(reqType); - break; - } - default: - entry->setRequirementVal(requirementVal); - break; + switch (requirementVal->getOp()) + { + case kIROp_Func: + case kIROp_Generic: + { + // Remove lowered `IRFunc`s since we only care about + // function types. + auto reqType = requirementVal->getFullType(); + entry->setRequirementVal(reqType); + break; + } + default: + entry->setRequirementVal(requirementVal); + break; + } } } irInterface->setOperand(entryIndex, entry); @@ -6598,6 +6608,34 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> return nullptr; } + static bool isChildOf(IRInst* child, IRInst* parent) + { + while (child && child->getParent() != parent) + child = child->getParent(); + return child != nullptr; + } + static void markInstsToClone(HashSet<IRInst*>& valuesToClone, IRInst* parentBlock, IRInst* value) + { + if (!isChildOf(value, parentBlock)) + return; + if (valuesToClone.Add(value)) + { + for (UInt i = 0; i < value->getOperandCount(); i++) + { + auto operand = value->getOperand(i); + markInstsToClone(valuesToClone, parentBlock, operand); + } + } + for (auto child : value->getChildren()) + markInstsToClone(valuesToClone, parentBlock, child); + auto parent = parentBlock->getParent(); + while (parent && parent != parentBlock) + { + valuesToClone.Add(parent); + parent = parent->getParent(); + } + } + // If any generic declarations have been created by `emitOuterGenerics`, // then finish them off by emitting `return` instructions for the // values that they should produce. @@ -6612,9 +6650,94 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> IRGeneric* parentGeneric) { IRInst* v = val; + + IRInst* returnType = v->getFullType(); + while (parentGeneric) { + // Create a universal type in `outterBlock` that will be used + // as the type of this generic inst. The return value of the + // generic inst will have a specialized type. + // For example, if we have a generic function + // g0 = generic<T> { return f: T->int } + // The type for `g0` should be: + // g0Type = generic<T1> { return IRFuncType{T1->int} } + // with `g0Type`, we can rewrite `g0` into: + // ``` + // g0 : g0Type = generic<T> + // { + // ftype = specialize(g0Type, T); + // return f : ftype; + // } + // ``` + IRBuilder typeBuilder; + typeBuilder.sharedBuilder = subBuilder->sharedBuilder; + IRCloneEnv cloneEnv = {}; + if (returnType) + { + HashSet<IRInst*> valuesToClone; + markInstsToClone(valuesToClone, parentGeneric->getFirstBlock(), returnType); + if (valuesToClone.Count() == 0) + { + // If returnType is independent of generic parameters, set + // the generic inst's type to just `returnType`. + parentGeneric->setFullType((IRType*)returnType); + } + else + { + // In the general case, we need to construct a separate + // generic value for the return type, and set the generic's type + // to the newly construct generic value. + typeBuilder.setInsertBefore(parentGeneric); + auto typeGeneric = typeBuilder.emitGeneric(); + typeBuilder.setInsertInto(typeGeneric); + typeBuilder.emitBlock(); + + for (auto child : parentGeneric->getFirstBlock()->getChildren()) + { + if (valuesToClone.Contains(child)) + { + cloneInst(&cloneEnv, &typeBuilder, child); + } + } + IRInst* clonedReturnType = nullptr; + cloneEnv.mapOldValToNew.TryGetValue(returnType, clonedReturnType); + SLANG_ASSERT(clonedReturnType); + typeBuilder.emitReturn(clonedReturnType); + parentGeneric->setFullType((IRType*)typeGeneric); + returnType = typeGeneric; + } + } + subBuilder->setInsertInto(parentGeneric->getFirstBlock()); +#if 0 + // TODO: we cannot enable this right now as it breaks too many existing code + // that is assuming a generic function type is `IRFuncType` rather than `IRSpecialize`. + if (v->getFullType() != returnType) + { + // We need to rewrite the type of the return value as + // `specialize(returnType, ...)`. + SLANG_ASSERT(returnType->getOp() == kIROp_Generic); + auto oldType = v->getFullType(); + SLANG_ASSERT(isChildOf(oldType, parentGeneric->getFirstBlock())); + + List<IRInst*> specializeArgs; + for (auto param : parentGeneric->getParams()) + { + IRInst* arg = nullptr; + if (cloneEnv.mapOldValToNew.TryGetValue(param, arg)) + { + specializeArgs.add(arg); + } + } + auto specializedType = subBuilder->emitSpecializeInst( + subBuilder->getTypeKind(), + returnType, + (UInt)specializeArgs.getCount(), + specializeArgs.getBuffer()); + oldType->replaceUsesWith(specializedType); + } +#endif subBuilder->emitReturn(v); parentGeneric->moveToEnd(); @@ -7261,11 +7384,6 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> // If this function is defined inside an interface, add a reference to the IRFunc from // the interface's type definition. auto finalVal = finishOuterGenerics(subBuilder, irFunc, outerGeneric); - if (auto genericVal = as<IRGeneric>(finalVal)) - { - auto funcType = lowerFuncType(decl); - genericVal->setFullType((IRType*)funcType); - } return LoweredValInfo::simple(finalVal); } |
