summaryrefslogtreecommitdiffstats
path: root/source
diff options
context:
space:
mode:
authorYong He <yonghe@outlook.com>2021-10-21 15:51:18 -0700
committerGitHub <noreply@github.com>2021-10-21 15:51:18 -0700
commit9304c2d04c9bfbae33cc328d404b24aba375aa4f (patch)
tree88473d2ca0b03341f84bca17b359ae45c4becfaa /source
parent66e319e34b99eff0a8d27be524ab4a831437ac1b (diff)
Diagnostic for no type conformance + bug fix. (#1985)
* Diagnostic for no type conformance + bug fix. * Fixes. * Fix. * Include heterogeneous example only with --enable-experimental-projects premake flag Co-authored-by: Yong He <yhe@nvidia.com> Co-authored-by: jsmall-nvidia <jsmall@nvidia.com>
Diffstat (limited to 'source')
-rw-r--r--source/slang/slang-diagnostic-defs.h2
-rw-r--r--source/slang/slang-ir-generics-lowering-context.h24
-rw-r--r--source/slang/slang-ir-lower-generics.cpp32
-rw-r--r--source/slang/slang-ir-specialize-dynamic-associatedtype-lookup.cpp46
4 files changed, 74 insertions, 30 deletions
diff --git a/source/slang/slang-diagnostic-defs.h b/source/slang/slang-diagnostic-defs.h
index 2add5792b..897aa9f6f 100644
--- a/source/slang/slang-diagnostic-defs.h
+++ b/source/slang/slang-diagnostic-defs.h
@@ -545,6 +545,8 @@ DIAGNOSTIC(51090, Error, cannotGenerateCodeForExternComponentType, "cannot gener
DIAGNOSTIC(51091, Error, typeCannotBePlacedInATexture, "type '$0' cannot be placed in a texture.")
DIAGNOSTIC(51092, Error, stageDoesntHaveInputWorld, "'$0' doesn't appear to have any input world")
+DIAGNOSTIC(50100, Error, noTypeConformancesFoundForInterface, "No type conformances are found for interface '$0'. Code generation for current target requires at least one implementation type present in the linkage.")
+
DIAGNOSTIC(52000, Error, multiLevelBreakUnsupported, "control flow appears to require multi-level `break`, which Slang does not yet support")
DIAGNOSTIC(52001, Warning, dxilNotFound, "dxil shared library not found, so 'dxc' output cannot be signed! Shader code will not be runnable in non-development environments.")
diff --git a/source/slang/slang-ir-generics-lowering-context.h b/source/slang/slang-ir-generics-lowering-context.h
index 78dd068b8..c875566b0 100644
--- a/source/slang/slang-ir-generics-lowering-context.h
+++ b/source/slang/slang-ir-generics-lowering-context.h
@@ -103,4 +103,28 @@ namespace Slang
// Ptr(RTTIType).
bool isTypeValue(IRInst* typeInst);
+ template<typename TFunc>
+ void workOnModule(SharedGenericsLoweringContext* sharedContext, const TFunc& func)
+ {
+ SharedIRBuilder* sharedBuilder = &sharedContext->sharedBuilderStorage;
+ sharedBuilder->module = sharedContext->module;
+ sharedBuilder->session = sharedContext->module->session;
+
+ sharedContext->addToWorkList(sharedContext->module->getModuleInst());
+
+ while (sharedContext->workList.getCount() != 0)
+ {
+ IRInst* inst = sharedContext->workList.getLast();
+
+ sharedContext->workList.removeLast();
+ sharedContext->workListSet.Remove(inst);
+
+ func(inst);
+
+ for (auto child = inst->getLastChild(); child; child = child->getPrevInst())
+ {
+ sharedContext->addToWorkList(child);
+ }
+ }
+ }
}
diff --git a/source/slang/slang-ir-lower-generics.cpp b/source/slang/slang-ir-lower-generics.cpp
index 241827561..95046787a 100644
--- a/source/slang/slang-ir-lower-generics.cpp
+++ b/source/slang/slang-ir-lower-generics.cpp
@@ -117,6 +117,36 @@ namespace Slang
cleanUpInterfaceTypes(sharedContext);
}
+ void checkTypeConformanceExists(SharedGenericsLoweringContext* context)
+ {
+ HashSet<IRInst*> implementedInterfaces;
+
+ // Add all interface type that are implemented by at least one type to a set.
+ for (auto inst : context->module->getGlobalInsts())
+ {
+ if (inst->getOp() == kIROp_WitnessTable)
+ {
+ auto interfaceType = cast<IRWitnessTableType>(inst->getDataType())->getConformanceType();
+ implementedInterfaces.Add(interfaceType);
+ }
+ }
+ // Check if an interface type has any implementations.
+ workOnModule(context, [&](IRInst* inst)
+ {
+ if (auto lookupWitnessMethod = as<IRLookupWitnessMethod>(inst))
+ {
+ auto witnessTableType = lookupWitnessMethod->getWitnessTable()->getDataType();
+ auto interfaceType = cast<IRWitnessTableType>(witnessTableType)->getConformanceType();
+ if (!implementedInterfaces.Contains(interfaceType))
+ {
+ context->sink->diagnose(interfaceType->sourceLoc, Diagnostics::noTypeConformancesFoundForInterface, interfaceType);
+ // Add to set to prevent duplicate diagnostic messages.
+ implementedInterfaces.Add(interfaceType);
+ }
+ }
+ });
+ }
+
void lowerGenerics(
TargetRequest* targetReq,
IRModule* module,
@@ -127,6 +157,8 @@ namespace Slang
sharedContext.module = module;
sharedContext.sink = sink;
+ checkTypeConformanceExists(&sharedContext);
+
// Replace all `makeExistential` insts with `makeExistentialWithRTTI`
// before making any other changes. This is necessary because a parameter of
// generic type will be lowered into `AnyValueType`, and after that we can no longer
diff --git a/source/slang/slang-ir-specialize-dynamic-associatedtype-lookup.cpp b/source/slang/slang-ir-specialize-dynamic-associatedtype-lookup.cpp
index 059531107..e2d321ed4 100644
--- a/source/slang/slang-ir-specialize-dynamic-associatedtype-lookup.cpp
+++ b/source/slang/slang-ir-specialize-dynamic-associatedtype-lookup.cpp
@@ -157,44 +157,30 @@ struct AssociatedTypeLookupSpecializationContext
{
if (inst->getRTTIOperand()->getDataType()->getOp() == kIROp_WitnessTableIDType)
{
+ // If the operand is a witness table id, just return the operand.
inst->replaceUsesWith(inst->getRTTIOperand());
inst->removeAndDeallocate();
}
- }
-
- template<typename TFunc>
- void workOnModule(const TFunc& func)
- {
- SharedIRBuilder* sharedBuilder = &sharedContext->sharedBuilderStorage;
- sharedBuilder->module = sharedContext->module;
- sharedBuilder->session = sharedContext->module->session;
-
- sharedContext->addToWorkList(sharedContext->module->getModuleInst());
-
- while (sharedContext->workList.getCount() != 0)
+ else if (inst->getRTTIOperand()->getDataType()->getOp() == kIROp_VectorType)
{
- IRInst* inst = sharedContext->workList.getLast();
-
- sharedContext->workList.removeLast();
- sharedContext->workListSet.Remove(inst);
-
- func(inst);
- if (inst->getOp() == kIROp_lookup_interface_method)
- {
- processLookupInterfaceMethodInst(cast<IRLookupWitnessMethod>(inst));
- }
-
- for (auto child = inst->getLastChild(); child; child = child->getPrevInst())
- {
- sharedContext->addToWorkList(child);
- }
+ // If the operand is a witness table, it is already replaced with a uint2
+ // at this point, where the first element in the uint2 is the id of the
+ // witneess table.
+ auto vectorType = inst->getRTTIOperand()->getDataType();
+ IRBuilder builder;
+ builder.sharedBuilder = &sharedContext->sharedBuilderStorage;
+ builder.setInsertBefore(inst);
+ UInt index = 0;
+ auto id = builder.emitSwizzle(as<IRVectorType>(vectorType)->getElementType(), inst->getRTTIOperand(), 1, &index);
+ inst->replaceUsesWith(id);
+ inst->removeAndDeallocate();
}
}
void processModule()
{
// Replace all `lookup_interface_method():IRWitnessTable` with call to specialized functions.
- workOnModule([this](IRInst* inst)
+ workOnModule(sharedContext, [this](IRInst* inst)
{
if (inst->getOp() == kIROp_lookup_interface_method)
{
@@ -203,7 +189,7 @@ struct AssociatedTypeLookupSpecializationContext
});
// Replace all direct uses of IRWitnessTables with its sequential ID.
- workOnModule([this](IRInst* inst)
+ workOnModule(sharedContext, [this](IRInst* inst)
{
if (inst->getOp() == kIROp_WitnessTable)
{
@@ -252,7 +238,7 @@ struct AssociatedTypeLookupSpecializationContext
}
// `GetSequentialID(WitnessTableIDOperand)` becomes just `WitnessTableIDOperand`.
- workOnModule([this](IRInst* inst)
+ workOnModule(sharedContext, [this](IRInst* inst)
{
if (inst->getOp() == kIROp_GetSequentialID)
{