summaryrefslogtreecommitdiffstats
path: root/source
diff options
context:
space:
mode:
Diffstat (limited to 'source')
-rw-r--r--source/slang/check.cpp14
-rw-r--r--source/slang/emit.cpp8
-rw-r--r--source/slang/ir-insts.h8
-rw-r--r--source/slang/ir.cpp177
-rw-r--r--source/slang/ir.h1
-rw-r--r--source/slang/lower-to-ir.cpp22
-rw-r--r--source/slang/mangle.cpp11
-rw-r--r--source/slang/mangle.h4
-rw-r--r--source/slang/slang.natvis10
-rw-r--r--source/slang/slang.vcxproj1
-rw-r--r--source/slang/slang.vcxproj.filters1
-rw-r--r--source/slang/syntax.cpp4
-rw-r--r--source/slang/syntax.h2
-rw-r--r--source/slang/val-defs.h6
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()