diff options
Diffstat (limited to 'source')
| -rw-r--r-- | source/slang/check.cpp | 14 | ||||
| -rw-r--r-- | source/slang/emit.cpp | 8 | ||||
| -rw-r--r-- | source/slang/ir-insts.h | 8 | ||||
| -rw-r--r-- | source/slang/ir.cpp | 177 | ||||
| -rw-r--r-- | source/slang/ir.h | 1 | ||||
| -rw-r--r-- | source/slang/lower-to-ir.cpp | 22 | ||||
| -rw-r--r-- | source/slang/mangle.cpp | 11 | ||||
| -rw-r--r-- | source/slang/mangle.h | 4 | ||||
| -rw-r--r-- | source/slang/slang.natvis | 10 | ||||
| -rw-r--r-- | source/slang/slang.vcxproj | 1 | ||||
| -rw-r--r-- | source/slang/slang.vcxproj.filters | 1 | ||||
| -rw-r--r-- | source/slang/syntax.cpp | 4 | ||||
| -rw-r--r-- | source/slang/syntax.h | 2 | ||||
| -rw-r--r-- | source/slang/val-defs.h | 6 |
14 files changed, 210 insertions, 59 deletions
diff --git a/source/slang/check.cpp b/source/slang/check.cpp index 9faad1127..5141d8634 100644 --- a/source/slang/check.cpp +++ b/source/slang/check.cpp @@ -7003,8 +7003,18 @@ namespace Slang } } - // TODO: need to fill in constraints here... - + // create default substitution arguments for constraints + for (auto mm : genericDecl->Members) + { + if (auto genericTypeConstraintDecl = mm.As<GenericTypeConstraintDecl>()) + { + RefPtr<DeclaredSubtypeWitness> witness = new DeclaredSubtypeWitness(); + witness->declRef = makeDeclRef(genericTypeConstraintDecl.Ptr()); + witness->sub = genericTypeConstraintDecl->sub.type; + witness->sup = genericTypeConstraintDecl->sup.type; + subst->args.Add(witness); + } + } return subst; } return parentSubst; diff --git a/source/slang/emit.cpp b/source/slang/emit.cpp index e9a2588d5..080478225 100644 --- a/source/slang/emit.cpp +++ b/source/slang/emit.cpp @@ -4503,8 +4503,12 @@ emitDeclImpl(decl, nullptr); return name; } - // Special case (2): not implemented yet. - + // Special case (2) + if (declRef.GetParent().decl->As<AggTypeDecl>()) + { + name.append(declRef.decl->nameAndLoc.name->text); + return name; + } // General case: name.append(getMangledName(declRef)); return name; diff --git a/source/slang/ir-insts.h b/source/slang/ir-insts.h index 769229962..a8c8383e2 100644 --- a/source/slang/ir-insts.h +++ b/source/slang/ir-insts.h @@ -304,6 +304,8 @@ struct IRWitnessTableEntry : IRUser // to the IR values that satisfy those requirements. struct IRWitnessTable : IRGlobalValue { + RefPtr<GenericDecl> genericDecl; + DeclRef<Decl> subTypeDeclRef, supTypeDeclRef; IRValueList<IRWitnessTableEntry> entries; }; @@ -341,6 +343,7 @@ struct SharedIRBuilder Dictionary<IRInstKey, IRInst*> globalValueNumberingMap; Dictionary<IRConstantKey, IRConstant*> constantMap; + Dictionary<String, IRWitnessTable*> witnessTableMap; }; struct IRBuilderSourceLocRAII; @@ -417,7 +420,7 @@ struct IRBuilder IRValue* const* args); IRModule* createModule(); - + IRFunc* createFunc(); IRGlobalVar* createGlobalVar( IRType* valueType); @@ -427,7 +430,8 @@ struct IRBuilder IRWitnessTable* witnessTable, IRValue* requirementKey, IRValue* satisfyingVal); - + IRWitnessTable* lookupWitnessTable(String mangledName); + void registerWitnessTable(IRWitnessTable* table); IRBlock* createBlock(); IRBlock* emitBlock(); diff --git a/source/slang/ir.cpp b/source/slang/ir.cpp index cd36e8d47..e0f703cbd 100644 --- a/source/slang/ir.cpp +++ b/source/slang/ir.cpp @@ -60,7 +60,8 @@ namespace Slang // clear out the old value if (usedVal) { - *prevLink = nextUse; + if (prevLink) + *prevLink = nextUse; } init(user, usedVal); @@ -934,6 +935,19 @@ namespace Slang return entry; } + IRWitnessTable * IRBuilder::lookupWitnessTable(String mangledName) + { + IRWitnessTable * result; + if (sharedBuilder->witnessTableMap.TryGetValue(mangledName, result)) + return result; + return nullptr; + } + + + void IRBuilder::registerWitnessTable(IRWitnessTable * table) + { + sharedBuilder->witnessTableMap[table->mangledName] = table; + } IRBlock* IRBuilder::createBlock() { @@ -1396,7 +1410,7 @@ namespace Slang struct IRDumpContext { StringBuilder* builder; - int indent; + int indent = 0; UInt idCounter = 1; Dictionary<IRValue*, UInt> mapValueToID; @@ -1588,7 +1602,7 @@ namespace Slang } else if (auto proxyVal = dynamic_cast<IRProxyVal*>(val)) { - dumpOperand(context, proxyVal->inst); + dumpOperand(context, proxyVal->inst.usedValue); } else { @@ -2095,6 +2109,17 @@ namespace Slang dump(context, "}\n"); } + + String dumpIRFunc(IRFunc* func) + { + IRDumpContext dumpContext; + StringBuilder sbDump; + dumpContext.builder = &sbDump; + dumpIRFunc(&dumpContext, func); + auto strFunc = sbDump.ToString(); + return strFunc; + } + void dumpIRGlobalVar( IRDumpContext* context, IRGlobalVar* var) @@ -3199,7 +3224,6 @@ namespace Slang case kIROp_Func: case kIROp_witness_table: return cloneGlobalValue(this, (IRGlobalValue*) originalValue); - case kIROp_boolConst: { IRConstant* c = (IRConstant*)originalValue; @@ -3246,7 +3270,7 @@ namespace Slang { auto proxyVal = witness.Value.As<IRProxyVal>(); SLANG_ASSERT(proxyVal); - return proxyVal->inst; + return proxyVal->inst.usedValue; } } } @@ -3270,16 +3294,20 @@ namespace Slang } } + IRValue* cloneValue( + IRSpecContextBase* context, + IRValue* originalValue); + RefPtr<Val> cloneSubstitutionArg( IRSpecContext* context, Val* val) { if (auto proxyVal = dynamic_cast<IRProxyVal*>(val)) { - auto newIRVal = context->maybeCloneValue(proxyVal->inst); + auto newIRVal = cloneValue(context, proxyVal->inst.usedValue); RefPtr<IRProxyVal> newProxyVal = new IRProxyVal(); - newProxyVal->inst = newIRVal; + newProxyVal->inst.init(nullptr, newIRVal); return newProxyVal; } else if (auto type = dynamic_cast<Type*>(val)) @@ -3307,7 +3335,7 @@ namespace Slang for (auto arg : genSubst->args) { auto newArg = cloneSubstitutionArg(context, arg); - newSubst->args.Add(arg); + newSubst->args.Add(newArg); } return newSubst; } @@ -3436,7 +3464,7 @@ namespace Slang } IRWitnessTable* cloneWitnessTableImpl( - IRSpecContext* context, + IRSpecContextBase* context, IRWitnessTable* originalTable, IROriginalValuesForClone const& originalValues) { @@ -3445,7 +3473,9 @@ namespace Slang auto mangledName = originalTable->mangledName; clonedTable->mangledName = mangledName; - + clonedTable->genericDecl = originalTable->genericDecl; + clonedTable->subTypeDeclRef = originalTable->subTypeDeclRef; + clonedTable->supTypeDeclRef = originalTable->supTypeDeclRef; cloneDecorations(context, clonedTable, originalTable); // Clone the entries in the witness table as well @@ -3463,7 +3493,7 @@ namespace Slang } IRWitnessTable* cloneWitnessTableWithoutRegistering( - IRSpecContext* context, + IRSpecContextBase* context, IRWitnessTable* originalTable) { return cloneWitnessTableImpl(context, originalTable, IROriginalValuesForClone()); @@ -4008,7 +4038,7 @@ namespace Slang SLANG_ASSERT(table); table = cloneWitnessTableWithoutRegistering(context, (IRWitnessTable*)(table)); IRProxyVal * tableVal = new IRProxyVal(); - tableVal->inst = table; + tableVal->inst.init(nullptr, table); paramSubst->witnessTables.Add(KeyValuePair<RefPtr<Type>, RefPtr<Val>>(subtypeWitness->sup, tableVal)); } } @@ -4228,7 +4258,7 @@ namespace Slang // the pointed-to value and not the proxy type-level `Val` // instead. - return context->maybeCloneValue(proxyVal->inst); + return context->maybeCloneValue(proxyVal->inst.usedValue); } else { @@ -4394,6 +4424,69 @@ namespace Slang return newSubst; } + IRFunc* getSpecializedFunc( + IRSharedGenericSpecContext* sharedContext, + IRFunc* genericFunc, + DeclRef<Decl> specDeclRef); + + IRWitnessTable* specializeWitnessTable(IRSharedGenericSpecContext * sharedContext, IRWitnessTable* originalTable, DeclRef<Decl> specDeclRef) + { + // First, we want to see if an existing specialization + // has already been made. To do that we will need to + // compute the mangled name of the specialized function, + // so that we can look for existing declarations. + String specMangledName; + String specializedMangledName = getMangledNameForConformanceWitness(specDeclRef.Substitute(originalTable->subTypeDeclRef), + specDeclRef.Substitute(originalTable->supTypeDeclRef)); + + // TODO: This is a terrible linear search, and we should + // avoid it by building a dictionary ahead of time, + // as is being done for the `IRSpecContext` used above. + // We can probalby use the same basic context, actually. + auto module = originalTable->parentModule; + for (auto gv = module->getFirstGlobalValue(); gv; gv = gv->getNextValue()) + { + if (gv->mangledName == specMangledName) + return (IRWitnessTable*)gv; + } + + RefPtr<Substitutions> newSubst = cloneSubstitutionsForSpecialization( + sharedContext, + specDeclRef.substitutions, + originalTable->genericDecl); + + IRGenericSpecContext context; + context.shared = sharedContext; + context.builder = &sharedContext->builderStorage; + context.subst = newSubst; + + // TODO: other initialization is needed here... + + auto specTable = cloneWitnessTableWithoutRegistering(&context, originalTable); + + // Set up the clone to recognize that it is no longer generic + specTable->mangledName = specMangledName; + specTable->genericDecl = nullptr; + + // Specialization of witness tables should trigger cascading specializations + // of involved functions. + for (auto entry : specTable->entries) + { + if (entry->satisfyingVal.usedValue->op == kIROp_Func) + { + IRFunc* func = (IRFunc*)entry->satisfyingVal.usedValue; + if (func->genericDecl) + entry->satisfyingVal.set(getSpecializedFunc(sharedContext, func, specDeclRef)); + } + + } + // We also need to make sure that we register this specialized + // function under its mangled name, so that later lookup + // steps will find it. + insertGlobalValueSymbol(sharedContext, specTable); + + return specTable; + } IRFunc* getSpecializedFunc( IRSharedGenericSpecContext* sharedContext, @@ -4415,9 +4508,9 @@ namespace Slang // as is being done for the `IRSpecContext` used above. // We can probalby use the same basic context, actually. auto module = genericFunc->parentModule; - for(auto gv = module->getFirstGlobalValue(); gv; gv = gv->getNextValue()) + for (auto gv = module->getFirstGlobalValue(); gv; gv = gv->getNextValue()) { - if(gv->mangledName == specMangledName) + if (gv->mangledName == specMangledName) return (IRFunc*) gv; } @@ -4564,7 +4657,7 @@ namespace Slang // specialization to perform. auto func = workList[count-1]; workList.RemoveAt(count-1); - + // We are going to go ahead and walk through // all the instructions in this function, // and look for `specialize` operations. @@ -4596,32 +4689,40 @@ namespace Slang // specialization here and now. IRSpecialize* specInst = (IRSpecialize*) ii; - // We need to check that the value being specialized is - // a generic function. - auto genericVal = specInst->genericVal.usedValue; - if(genericVal->op != kIROp_Func) - continue; - auto genericFunc = (IRFunc*) genericVal; - if(!genericFunc->genericDecl) - continue; - // Now we extract the specialized decl-ref that will // tell us how to specialize things. - auto specDeclRefVal = (IRDeclRef*) specInst->specDeclRefVal.usedValue; + auto specDeclRefVal = (IRDeclRef*)specInst->specDeclRefVal.usedValue; auto specDeclRef = specDeclRefVal->declRef; - // Okay, we have a candidate for specialization here. - // - // We will first find or construct a specialized version - // of the callee funciton/ - auto specFunc = getSpecializedFunc(sharedContext, genericFunc, specDeclRef); - // - // Then we will replace the use sites for the `specialize` - // instruction with uses of the specialized function. - // - specInst->replaceUsesWith(specFunc); - - specInst->removeAndDeallocate(); + // We need to specialize functions and witness tables + auto genericVal = specInst->genericVal.usedValue; + if (genericVal->op == kIROp_Func) + { + auto genericFunc = (IRFunc*)genericVal; + if (!genericFunc->genericDecl) + continue; + + // Okay, we have a candidate for specialization here. + // + // We will first find or construct a specialized version + // of the callee funciton/ + auto specFunc = getSpecializedFunc(sharedContext, genericFunc, specDeclRef); + // + // Then we will replace the use sites for the `specialize` + // instruction with uses of the specialized function. + // + specInst->replaceUsesWith(specFunc); + + specInst->removeAndDeallocate(); + } + else if (genericVal->op == kIROp_witness_table) + { + // specialize a witness table + auto originalTable = (IRWitnessTable*)genericVal; + auto specWitnessTable = specializeWitnessTable(sharedContext, originalTable, specDeclRef); + specInst->replaceUsesWith(specWitnessTable); + specInst->removeAndDeallocate(); + } } break; diff --git a/source/slang/ir.h b/source/slang/ir.h index 8ca4508ff..c56f8fb62 100644 --- a/source/slang/ir.h +++ b/source/slang/ir.h @@ -471,6 +471,7 @@ void printSlangIRAssembly(StringBuilder& builder, IRModule* module); String getSlangIRAssembly(IRModule* module); void dumpIR(IRModule* module); +String dumpIRFunc(IRFunc* func); } diff --git a/source/slang/lower-to-ir.cpp b/source/slang/lower-to-ir.cpp index 8fc1239cd..1d6da3a3b 100644 --- a/source/slang/lower-to-ir.cpp +++ b/source/slang/lower-to-ir.cpp @@ -2740,10 +2740,6 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> context->getSession(), makeDeclRef(parentDecl)); - - // TODO: if the parent type is generic, then I suppose these - // need to be *generic* witness tables? - // What is the super-type that we have declared we inherit from? RefPtr<Type> superType = inheritanceDecl->base.type; @@ -2758,6 +2754,11 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo> auto witnessTable = context->irBuilder->createWitnessTable(); witnessTable->mangledName = mangledName; + if (parentDecl->ParentDecl) + witnessTable->genericDecl = dynamic_cast<GenericDecl*>(parentDecl->ParentDecl); + witnessTable->subTypeDeclRef = makeDeclRef(parentDecl); + witnessTable->supTypeDeclRef = inheritanceDecl->base.type->AsDeclRefType()->declRef; + // Register the value now, rather than later, to avoid // infinite recursion. context->shared->declValues[inheritanceDecl] = LoweredValInfo::simple(witnessTable); @@ -3713,7 +3714,7 @@ LoweredValInfo ensureDecl( return result; } -IRWitnessTable* findWitnessTable( +IRValue* findWitnessTable( IRGenContext* context, DeclRef<Decl> declRef) { @@ -3724,10 +3725,13 @@ IRWitnessTable* findWitnessTable( return nullptr; } + if (irVal->op == kIROp_specialize) + { + return irVal; + } + if (irVal->op != kIROp_witness_table) { - // TODO: We might eventually have cases of `specialize` called - // on a witness table... SLANG_UNEXPECTED("expected a witness table"); return nullptr; } @@ -3764,7 +3768,7 @@ RefPtr<Val> lowerSubstitutionArg( // up in a reasonably clean fashion. // RefPtr<IRProxyVal> proxyVal = new IRProxyVal(); - proxyVal->inst = irWitnessTable; + proxyVal->inst.init(nullptr, irWitnessTable); return proxyVal; } else @@ -3860,7 +3864,7 @@ LoweredValInfo maybeEmitSpecializeInst(IRGenContext* context, // Otherwise, we need to construct a specialization of the // given declaration. - return LoweredValInfo::simple(context->irBuilder->emitSpecializeInst( + return LoweredValInfo::simple((IRInst*)context->irBuilder->emitSpecializeInst( type, val, declRef)); diff --git a/source/slang/mangle.cpp b/source/slang/mangle.cpp index 0625a6f73..5b8e519b9 100644 --- a/source/slang/mangle.cpp +++ b/source/slang/mangle.cpp @@ -400,6 +400,17 @@ namespace Slang { return getMangledName(makeDeclRef(decl)); } + + String getMangledNameForConformanceWitness( + DeclRef<Decl> sub, + DeclRef<Decl> sup) + { + ManglingContext context; + emitRaw(&context, "_SW"); + emitQualifiedName(&context, sub); + emitQualifiedName(&context, sup); + return context.sb.ProduceString(); + } String getMangledNameForConformanceWitness( Type* sub, diff --git a/source/slang/mangle.h b/source/slang/mangle.h index 65afea741..406796951 100644 --- a/source/slang/mangle.h +++ b/source/slang/mangle.h @@ -16,7 +16,9 @@ namespace Slang String getMangledNameForConformanceWitness( Type* sub, Type* sup); - + String getMangledNameForConformanceWitness( + DeclRef<Decl> sub, + DeclRef<Decl> sup); String getMangledTypeName(Type* type); } diff --git a/source/slang/slang.natvis b/source/slang/slang.natvis index 91e9d0994..d58e733fa 100644 --- a/source/slang/slang.natvis +++ b/source/slang/slang.natvis @@ -35,6 +35,12 @@ <Type Name="Slang::NameLoc"> <DisplayString>{{name={(char*)((*name).text.buffer.pointer+1), s} loc={loc.raw}}}</DisplayString> </Type> + <Type Name="Slang::IRWitnessTableEntry"> + <Expand> + <Item Name="[Key]">requirementKey</Item> + <Item Name="[Val]">satisfyingVal</Item> + </Expand> + </Type> <Type Name="Slang::IRValue"> <DisplayString>{{{op}}}</DisplayString> <Expand> @@ -44,11 +50,13 @@ <ExpandedItem Condition="op==kIROp_decl_ref">(Slang::IRDeclRef*)this</ExpandedItem> <ExpandedItem Condition="op==kIROp_Func">(Slang::IRFunc*)this</ExpandedItem> <ExpandedItem Condition="op==kIROp_Block">(Slang::IRBlock*)this</ExpandedItem> + <ExpandedItem Condition="op==kIROp_witness_table">(Slang::IRWitnessTable*)this</ExpandedItem> + <ExpandedItem Condition="op==kIROp_witness_table_entry">(Slang::IRWitnessTableEntry*)this</ExpandedItem> <Item Name="====Uses====">"-------"</Item> <LinkedListItems> <HeadPointer>firstUse</HeadPointer> <NextPointer>nextUse</NextPointer> - <ValueNode>usedValue</ValueNode> + <ValueNode>user</ValueNode> </LinkedListItems> </Expand> diff --git a/source/slang/slang.vcxproj b/source/slang/slang.vcxproj index 9835640e0..da0d9d9d4 100644 --- a/source/slang/slang.vcxproj +++ b/source/slang/slang.vcxproj @@ -237,6 +237,7 @@ <ClCompile Include="syntax.cpp" /> <ClCompile Include="token.cpp" /> <ClCompile Include="type-layout.cpp" /> + <ClCompile Include="val-defs.cpp" /> <ClCompile Include="vm.cpp" /> </ItemGroup> <ItemGroup> diff --git a/source/slang/slang.vcxproj.filters b/source/slang/slang.vcxproj.filters index f207c6dcd..7bc22ae5d 100644 --- a/source/slang/slang.vcxproj.filters +++ b/source/slang/slang.vcxproj.filters @@ -74,6 +74,7 @@ <ClCompile Include="ir-legalize-types.cpp" /> <ClCompile Include="ast-legalize.cpp" /> <ClCompile Include="legalize-types.cpp" /> + <ClCompile Include="val-defs.cpp" /> </ItemGroup> <ItemGroup> <CustomBuild Include="core.meta.slang" /> diff --git a/source/slang/syntax.cpp b/source/slang/syntax.cpp index 070362ddf..9ca2dc827 100644 --- a/source/slang/syntax.cpp +++ b/source/slang/syntax.cpp @@ -1827,7 +1827,7 @@ void Type::accept(IValVisitor* visitor, void* extra) if(!otherProxy) return false; - return this->inst == otherProxy->inst; + return this->inst.usedValue == otherProxy->inst.usedValue; } String IRProxyVal::ToString() @@ -1837,7 +1837,7 @@ void Type::accept(IValVisitor* visitor, void* extra) int IRProxyVal::GetHashCode() { - auto hash = Slang::GetHashCode(inst); + auto hash = Slang::GetHashCode(inst.usedValue); return hash; } diff --git a/source/slang/syntax.h b/source/slang/syntax.h index 749c5ae32..00e6bd6d3 100644 --- a/source/slang/syntax.h +++ b/source/slang/syntax.h @@ -1167,7 +1167,7 @@ namespace Slang void removeSubstitution(DeclRefBase & declRef, RefPtr<Substitutions> subst); bool hasGenericSubstitutions(RefPtr<Substitutions> subst); RefPtr<GenericSubstitution> getGenericSubstitution(RefPtr<Substitutions> subst); - + // This function substitutes the type arguments referenced in a linked list of substitutions // which head is at `substHead` using the substitutions specified by `subst`. If the linked // list `substHead` does not contain `GlobalGenericParamSubstitution` entries, they will be diff --git a/source/slang/val-defs.h b/source/slang/val-defs.h index f3cdf52a2..4ecd5a51b 100644 --- a/source/slang/val-defs.h +++ b/source/slang/val-defs.h @@ -117,11 +117,15 @@ END_SYNTAX_CLASS() // A value that is used as a proxy when we need to // put an IR-level value into AST types SYNTAX_CLASS(IRProxyVal, Val) - FIELD(IRValue*, inst) + FIELD(IRUse, inst) RAW( virtual bool EqualsVal(Val* val) override; virtual String ToString() override; virtual int GetHashCode() override; + ~IRProxyVal() override + { + inst.clear(); + } ) END_SYNTAX_CLASS() |
