summaryrefslogtreecommitdiffstats
path: root/source/slang/slang-emit-cpp.cpp
diff options
context:
space:
mode:
authorjsmall-nvidia <jsmall@nvidia.com>2022-06-02 14:13:35 -0400
committerGitHub <noreply@github.com>2022-06-02 14:13:35 -0400
commitb39c99661b3ad482bbd419c24991ed325b5738a9 (patch)
tree0f90fecdae10e704b2c1135c48ca5eeafa60b780 /source/slang/slang-emit-cpp.cpp
parentbc6bc56db51d06b92dc63ef9c9e0def6c9760c9e (diff)
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.
Diffstat (limited to 'source/slang/slang-emit-cpp.cpp')
-rw-r--r--source/slang/slang-emit-cpp.cpp91
1 files changed, 78 insertions, 13 deletions
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<IRComPtrType*>(type);
auto baseType = cast<IRType>(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<IREntryPointDecoration>())
@@ -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<IRStringLit>(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