From 0ca75fe002f346f6ab9b77f40c0576d2905560f1 Mon Sep 17 00:00:00 2001 From: Yong He Date: Wed, 24 Jun 2020 13:16:11 -0700 Subject: Dynamic dispatch for generic interface requirements. -Lower interfaces into actual `IRInterfaceType` insts. -Lower `DeclRef` into `IRAssociatedType` -Generate proper IRType for generic functions. -Add a test case exercising dynamic dispatching a generic static function through an associated type. -Bug fixes for the test case. --- source/slang/slang-emit-cpp.cpp | 64 ++++++++++++++++++++++------------------- 1 file changed, 35 insertions(+), 29 deletions(-) (limited to 'source/slang/slang-emit-cpp.cpp') diff --git a/source/slang/slang-emit-cpp.cpp b/source/slang/slang-emit-cpp.cpp index 4a59f4cf9..eeace4aa7 100644 --- a/source/slang/slang-emit-cpp.cpp +++ b/source/slang/slang-emit-cpp.cpp @@ -390,12 +390,27 @@ static UnownedStringSlice _getResourceTypePrefix(IROp op) } } +static bool isVoidPtrType(IRType* type) +{ + auto ptrType = as(type); + if (!ptrType) return false; + return ptrType->getValueType()->op == kIROp_VoidType; +} + SlangResult CPPSourceEmitter::calcTypeName(IRType* type, CodeGenTarget target, StringBuilder& out) { switch (type->op) { case kIROp_PtrType: { + if (isVoidPtrType(type)) + { + // A `void*` type will always emit as `void*`. + // `void*` types are generated as a result of generics lowering + // for dynamic dispatch. + out << "void*"; + return SLANG_OK; + } auto ptrType = static_cast(type); SLANG_RETURN_ON_FAIL(calcTypeName(ptrType->getValueType(), target, out)); // TODO(JS): It seems although it says it is a pointer, it can actually be output as a reference @@ -494,7 +509,7 @@ SlangResult CPPSourceEmitter::calcTypeName(IRType* type, CodeGenTarget target, S // struct of function pointers corresponding to the interface type. auto witnessTableType = static_cast(type); auto baseType = cast(witnessTableType->getOperand(0)); - emitType(baseType); + SLANG_RETURN_ON_FAIL(calcTypeName(baseType, target, out)); out << "*"; return SLANG_OK; } @@ -1591,8 +1606,7 @@ void CPPSourceEmitter::emitWitnessTable(IRWitnessTable* witnessTable) { auto interfaceType = cast(witnessTable->getOperand(0)); auto witnessTableItems = witnessTable->getChildren(); - List sortedWitnessTableEntries = getSortedWitnessTableEntries(witnessTable); - _maybeEmitWitnessTableTypeDefinition(interfaceType, sortedWitnessTableEntries); + _maybeEmitWitnessTableTypeDefinition(interfaceType); // Define a global variable for the witness table. m_writer->emit("extern "); @@ -1747,17 +1761,16 @@ void CPPSourceEmitter::emitInterface(IRInterfaceType* interfaceType) /// acoording to the order defined by `interfaceType`. /// void CPPSourceEmitter::_maybeEmitWitnessTableTypeDefinition( - IRInterfaceType* interfaceType, - const List& sortedWitnessTableEntries) + IRInterfaceType* interfaceType) { m_writer->emit("struct "); emitSimpleType(interfaceType); m_writer->emit("\n{\n"); m_writer->indent(); - for (Index i = 0; i < sortedWitnessTableEntries.getCount(); i++) + for (UInt i = 0; i < interfaceType->getOperandCount(); i++) { - auto entry = sortedWitnessTableEntries[i]; - if (auto funcVal = as(entry->satisfyingVal.get())) + auto entry = as(interfaceType->getOperand(i)); + if (auto funcVal = as(entry->getRequirementVal())) { emitType(funcVal->getResultType()); m_writer->emit(" (KernelContext::*"); @@ -1765,33 +1778,35 @@ void CPPSourceEmitter::_maybeEmitWitnessTableTypeDefinition( m_writer->emit(")"); m_writer->emit("("); bool isFirstParam = true; - for (auto param : funcVal->getParams()) + for (UInt p = 0; p < funcVal->getParamCount(); p++) { + auto paramType = funcVal->getParamType(p); + // Ingore TypeType-typed parameters for now. + if (as(paramType)) + continue; + if (!isFirstParam) m_writer->emit(", "); else isFirstParam = false; - if (param->findDecoration()) + auto thisDecor = funcVal->findDecoration(); + if (thisDecor && cast(thisDecor->getOperand(0))->value.intVal == (IRIntegerValue)p) { - m_writer->emit("void* "); - m_writer->emit(getName(param)); + m_writer->emit("void* param"); + m_writer->emit(p); continue; } - emitSimpleFuncParamImpl(param); + emitParamType(paramType, String("param") + String(p)); } m_writer->emit(");\n"); } - else if (auto witnessTableVal = as(entry->getSatisfyingVal())) + else if (auto constraintInterfaceType = as(entry->getRequirementVal())) { - emitType(as(witnessTableVal->getOperand(0))); + emitType(constraintInterfaceType); m_writer->emit("* "); m_writer->emit(getName(entry->requirementKey.get())); m_writer->emit(";\n"); } - else - { - // TODO: handle other witness table entry types. - } } m_writer->dedent(); m_writer->emit("};\n"); @@ -1990,13 +2005,6 @@ void CPPSourceEmitter::emitSimpleValueImpl(IRInst* inst) } } -static bool isVoidPtrType(IRType* type) -{ - auto ptrType = as(type); - if (!ptrType) return false; - return ptrType->getValueType()->op == kIROp_VoidType; -} - void CPPSourceEmitter::emitSimpleFuncParamImpl(IRParam* param) { // Polymorphic types are already translated to void* type in @@ -2004,9 +2012,7 @@ void CPPSourceEmitter::emitSimpleFuncParamImpl(IRParam* param) // emit "void&" instead of "void*" for pointer types. // In the future, we will handle pointer types more properly, // and this override logic will not be necessary. - // For now we special-case this scenario. - if (param->findDecoration() && - isVoidPtrType(param->getDataType())) + if (isVoidPtrType(param->getDataType())) { m_writer->emit("void* "); m_writer->emit(getName(param)); -- cgit v1.2.3