From 7bcc2b15c8be4aebc6b9b8f05af6db7a451b228b Mon Sep 17 00:00:00 2001 From: Yong He Date: Tue, 10 Nov 2020 14:55:36 -0800 Subject: Use integer RTTI/witness handles in existential tuples. (#1598) * Use integer RTTI/witness handles in existential tuples. * Fix clang error. * Fix IR serialization to use 16bits for opcode. * Undo accidental comment change. * Use variable length encoding for opcode. * Fix compile error. * Fixing issues * Fix code review issues. --- source/slang/slang-ir-lower-generics.cpp | 101 ++++++++++++++++++++++++++++--- 1 file changed, 94 insertions(+), 7 deletions(-) (limited to 'source/slang/slang-ir-lower-generics.cpp') diff --git a/source/slang/slang-ir-lower-generics.cpp b/source/slang/slang-ir-lower-generics.cpp index 89194e594..0253c4df8 100644 --- a/source/slang/slang-ir-lower-generics.cpp +++ b/source/slang/slang-ir-lower-generics.cpp @@ -16,6 +16,96 @@ namespace Slang { + // Replace all uses of RTTI objects with its sequential ID. + void specializeRTTIObjectReferences(SharedGenericsLoweringContext* sharedContext) + { + uint32_t id = 0; + for (auto rtti : sharedContext->mapTypeToRTTIObject) + { + IRBuilder builder; + builder.sharedBuilder = &sharedContext->sharedBuilderStorage; + builder.setInsertBefore(rtti.Value); + IRUse* nextUse = nullptr; + auto idOperand = builder.getIntValue(builder.getUInt64Type(), id); + for (auto use = rtti.Value->firstUse; use; use = nextUse) + { + nextUse = use->nextUse; + if (use->getUser()->op == kIROp_getAddr) + { + use->getUser()->replaceUsesWith(idOperand); + } + } + } + } + + // Replace all WitnessTableID type or RTTIHandleType with uint64. + void cleanUpRTTIHandleTypes(SharedGenericsLoweringContext* sharedContext) + { + List instsToRemove; + for (auto inst : sharedContext->module->getGlobalInsts()) + { + switch (inst->op) + { + case kIROp_WitnessTableIDType: + case kIROp_RTTIHandleType: + { + IRBuilder builder; + builder.sharedBuilder = &sharedContext->sharedBuilderStorage; + builder.setInsertBefore(inst); + inst->replaceUsesWith(builder.getUInt64Type()); + instsToRemove.add(inst); + } + break; + } + } + for (auto inst : instsToRemove) + inst->removeAndDeallocate(); + } + + // Remove all interface types from module. + void cleanUpInterfaceTypes(SharedGenericsLoweringContext* sharedContext) + { + IRBuilder builder; + builder.sharedBuilder = &sharedContext->sharedBuilderStorage; + builder.setInsertInto(sharedContext->module->getModuleInst()); + auto dummyInterfaceObj = builder.getIntValue(builder.getIntType(), 0); + List interfaceInsts; + for (auto inst : sharedContext->module->getGlobalInsts()) + { + if (inst->op == kIROp_InterfaceType) + { + interfaceInsts.add(inst); + } + } + for (auto inst : interfaceInsts) + { + inst->replaceUsesWith(dummyInterfaceObj); + inst->removeAndDeallocate(); + } + } + + // Turn all references of witness table or RTTI objects into integer IDs, generate + // specialized `switch` based dispatch functions based on witness table IDs, and remove + // all original witness table, RTTI object and interface definitions from IR module. + // With these transformations, the resulting code is compatible with D3D/Vulkan where + // no pointers are involved in RTTI / dynamic dispatch logic. + void specializeRTTIObjects(SharedGenericsLoweringContext* sharedContext, DiagnosticSink* sink) + { + specializeDispatchFunctions(sharedContext); + if (sink->getErrorCount() != 0) + return; + + specializeDynamicAssociatedTypeLookup(sharedContext); + if (sink->getErrorCount() != 0) + return; + + specializeRTTIObjectReferences(sharedContext); + + cleanUpRTTIHandleTypes(sharedContext); + + cleanUpInterfaceTypes(sharedContext); + } + void lowerGenerics( TargetRequest* targetReq, IRModule* module, @@ -60,13 +150,10 @@ namespace Slang if (sink->getErrorCount() != 0) return; - specializeDispatchFunctions(&sharedContext); - if (sink->getErrorCount() != 0) - return; - - specializeDynamicAssociatedTypeLookup(&sharedContext); - if (sink->getErrorCount() != 0) - return; + // This optional step replaces all uses of witness tables and RTTI objects with + // sequential IDs. Without this step, we will emit code that uses function pointers and + // real RTTI objects and witness tables. + specializeRTTIObjects(&sharedContext, sink); // We might have generated new temporary variables during lowering. // An SSA pass can clean up unnecessary load/stores. -- cgit v1.2.3