From b39c99661b3ad482bbd419c24991ed325b5738a9 Mon Sep 17 00:00:00 2001 From: jsmall-nvidia Date: Thu, 2 Jun 2022 14:13:35 -0400 Subject: COM interfaces with host callable (#2258) * #include an absolute path didn't work - because paths were taken to always be relative. * Use TerminatedUnownedStringSlice for literals in output C++. * Remove Escape/Unescape functions used in slang-token-reader.cpp Add target type of 'host-cpp' etc to map to the target types. * Fix some corner cases around string encoding. * Added unit test for string escaping. Fixed some assorted escaping bugs. * Updated test output. * Added decode test. * Stop using hex output, to get around 'greedy' aspect. Use octal instead. * Added HostHostCallable Small changes to use ArtifactDesc/Info instead of large switches. * Fix C++ emit to handle arbitrary function export. * Add options handling for callable without an output being specified. * Can compile with COM interface. Added example using com interface. * Use the IR Ptr type instead of hack in C++ emit for interfaces. * Fix issue with outputting the COM call when ptr is used. * Fix crash issue on compilation failure. --- source/slang/slang-emit-cpp.cpp | 91 +++++++++++++++++++++++++++++++++++------ 1 file changed, 78 insertions(+), 13 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 482ada394..ddc8b24ed 100644 --- a/source/slang/slang-emit-cpp.cpp +++ b/source/slang/slang-emit-cpp.cpp @@ -544,9 +544,10 @@ SlangResult CPPSourceEmitter::calcTypeName(IRType* type, CodeGenTarget target, S } case kIROp_ComPtrType: { - out << "ComPtr<"; auto comPtrType = static_cast(type); auto baseType = cast(comPtrType->getOperand(0)); + + out << "ComPtr<"; SLANG_RETURN_ON_FAIL(calcTypeName(baseType, target, out)); out << ">"; return SLANG_OK; @@ -1635,6 +1636,12 @@ CPPSourceEmitter::CPPSourceEmitter(const Desc& desc): { m_semanticUsedFlags = 0; //m_semanticUsedFlags = SemanticUsedFlag::GroupID | SemanticUsedFlag::GroupThreadID | SemanticUsedFlag::DispatchThreadID; + + + const auto artifactDesc = ArtifactDesc::makeFromCompileTarget(asExternal(getTarget())); + + // If we have runtime library we can convert to a terminated string slice + m_hasString = (artifactDesc.style == ArtifactStyle::Host); } void CPPSourceEmitter::emitParamTypeImpl(IRType* type, String const& name) @@ -1945,6 +1952,9 @@ void CPPSourceEmitter::emitEntryPointAttributesImpl(IRFunc* irFunc, IREntryPoint void CPPSourceEmitter::emitSimpleFuncImpl(IRFunc* func) { + // Emit function decorations + emitFuncDecorations(func); + auto resultType = func->getResultType(); auto name = getName(func); @@ -1952,7 +1962,6 @@ void CPPSourceEmitter::emitSimpleFuncImpl(IRFunc* func) // Deal with decorations that need // to be emitted as attributes - // We start by emitting the result type and function name. // if (IREntryPointDecoration* entryPointDecor = func->findDecoration()) @@ -2416,16 +2425,23 @@ bool CPPSourceEmitter::tryEmitInstExprImpl(IRInst* inst, const EmitOpInfo& inOut } case kIROp_StringLit: { - m_writer->emit("toTerminatedSlice("); - auto handler = StringEscapeUtil::getHandler(StringEscapeUtil::Style::Cpp); - + StringBuilder buf; const auto slice = as(inst)->getStringSlice(); StringEscapeUtil::appendQuoted(handler, slice, buf); - m_writer->emit(buf); + + if (m_hasString) + { + m_writer->emit("toTerminatedSlice("); + m_writer->emit(buf); + m_writer->emit(")"); + } + else + { + m_writer->emit(buf); + } - m_writer->emit(")"); return true; } case kIROp_PtrLit: @@ -2475,12 +2491,17 @@ void CPPSourceEmitter::emitPreModuleImpl() { if (m_target == CodeGenTarget::CPPSource) { - // NOTE, that this opens an anonymous scope. + // TODO(JS): Previously this opened an anonymous scope for all generated functions + // Unfortunately this is a problem if we are just emitting code that is externally available + // and is not only accessible through entry points. So for now we disable + + // that this opens an anonymous scope. // The scope is closed in `emitModuleImpl` + //m_writer->emit("namespace { // anonymous \n\n"); + // When generating kernel code in C++, put all into an anonymous namespace // This includes any generated types, and generated intrinsics. - m_writer->emit("namespace { // anonymous \n\n"); m_writer->emit("#ifdef SLANG_PRELUDE_NAMESPACE\n"); m_writer->emit("using namespace SLANG_PRELUDE_NAMESPACE;\n"); m_writer->emit("#endif\n\n"); @@ -2526,6 +2547,45 @@ void CPPSourceEmitter::emitPreModuleImpl() } } +/* virtual */void CPPSourceEmitter::emitFuncDecorationsImpl(IRFunc* func) +{ + // Specially handle export, as we don't want to emit it multiple times + if (getTargetReq()->isWholeProgramRequest()) + { + bool isExternC = false; + bool isExported = false; + + // If public/export made it externally visible + for (auto decoration : func->getDecorations()) + { + const auto op = decoration->getOp(); + if (op == kIROp_ExternCppDecoration) + { + isExternC = true; + } + else if (op == kIROp_PublicDecoration || + op == kIROp_HLSLExportDecoration) + { + isExported = true; + } + } + + // TODO(JS): Currently export *also* implies it's extern "C" and we can't list twice + if (isExported) + { + m_writer->emit("SLANG_PRELUDE_EXPORT\n"); + } + else if (isExternC) + { + // It's name is not manged. + m_writer->emit("extern \"C\"\n"); + } + } + + // Use the default for others + Super::emitFuncDecorationsImpl(func); +} + void CPPSourceEmitter::emitOperandImpl(IRInst* inst, EmitOpInfo const& outerPrec) { if (shouldFoldInstIntoUseSites(inst)) @@ -2792,11 +2852,16 @@ void CPPSourceEmitter::emitModuleImpl(IRModule* module, DiagnosticSink* sink) // Emit all witness table definitions. _emitWitnessTableDefinitions(); - if (m_target == CodeGenTarget::CPPSource) - { + // TODO(JS): + // Previously output code was placed in an anonymous namespace + // Now that we can have any function available externally (not just entry points) + // this doesn't work. + + //if (m_target == CodeGenTarget::CPPSource) + //{ // Need to close the anonymous namespace when outputting for C++ kernel. - m_writer->emit("} // anonymous\n\n"); - } + //m_writer->emit("} // anonymous\n\n"); + //} // Finally we need to output dll entry points -- cgit v1.2.3