diff --git a/slang.h b/slang.h index 4ed37d88ce..e23a54ef0f 100644 --- a/slang.h +++ b/slang.h @@ -928,6 +928,7 @@ extern "C" NoHLSLBinding, ValidateUniformity, AllowGLSL, + EmitHeader, // Internal diff --git a/source/slang/core.meta.slang b/source/slang/core.meta.slang index 2e878b0653..2ef5ffd6c5 100644 --- a/source/slang/core.meta.slang +++ b/source/slang/core.meta.slang @@ -2577,6 +2577,9 @@ attribute_syntax [AutoPyBindCUDA] : AutoPyBindCudaAttribute; __attributeTarget(AggTypeDecl) attribute_syntax [PyExport(name: String)] : PyExportAttribute; +__attributeTarget(DeclBase) +attribute_syntax [HeaderExport] : HeaderExportAttribute; + __attributeTarget(InterfaceDecl) attribute_syntax [COM(guid: String)] : ComInterfaceAttribute; diff --git a/source/slang/slang-ast-modifier.h b/source/slang/slang-ast-modifier.h index 21661939c1..c79f84cc27 100644 --- a/source/slang/slang-ast-modifier.h +++ b/source/slang/slang-ast-modifier.h @@ -1249,6 +1249,11 @@ class PyExportAttribute : public Attribute String name; }; +class HeaderExportAttribute : public Attribute +{ + SLANG_AST_CLASS(HeaderExportAttribute) +}; + class PreferRecomputeAttribute : public Attribute { SLANG_AST_CLASS(PreferRecomputeAttribute) diff --git a/source/slang/slang-emit-c-like.cpp b/source/slang/slang-emit-c-like.cpp index ceb4e6de0d..5d33d990f1 100644 --- a/source/slang/slang-emit-c-like.cpp +++ b/source/slang/slang-emit-c-like.cpp @@ -1105,7 +1105,23 @@ String CLikeSourceEmitter::getName(IRInst* inst) String name; if(!m_mapInstToName.tryGetValue(inst, name)) { - name = generateName(inst); + // unmangle names, when emitting header + if (isEmmitingHeader()) { + if (auto nameHintDecor = inst->findDecoration()) + { + StringBuilder sb; + for (auto c : nameHintDecor->getName()) { + if (c == '.') + sb.append('_'); + else { + sb.append(c); + } + } + name = sb.produceString(); + } + } else { + name = generateName(inst); + } m_mapInstToName.add(inst, name); } return name; @@ -3320,7 +3336,7 @@ void CLikeSourceEmitter::emitSimpleFuncImpl(IRFunc* func) emitSemantics(func); // TODO: encode declaration vs. definition - if(isDefinition(func)) + if(!isEmmitingHeader() && isDefinition(func)) { m_writer->emit("\n{\n"); m_writer->indent(); @@ -3450,6 +3466,11 @@ bool CLikeSourceEmitter::isTargetIntrinsic(IRInst* inst) return findTargetIntrinsicDefinition(inst, intrinsicDef); } +bool CLikeSourceEmitter::isEmmitingHeader() { + return getTargetProgram()->getOptionSet().getBoolOption(CompilerOptionName::EmitHeader); +} + + bool shouldWrappInExternCBlock(IRFunc* func) { for (auto decor : func->getDecorations()) @@ -3466,6 +3487,11 @@ bool shouldWrappInExternCBlock(IRFunc* func) void CLikeSourceEmitter::emitFunc(IRFunc* func) { + // When emmiting header, skip if should not be emmited. + if (isEmmitingHeader() && !func->findDecoration()) { + return; + } + // Target-intrinsic functions should never be emitted // even if they happen to have a body. // @@ -3513,6 +3539,13 @@ void CLikeSourceEmitter::emitFuncDecorationsImpl(IRFunc* func) void CLikeSourceEmitter::emitStruct(IRStructType* structType) { + // TODO: add similar functionality like markTypeForPyExport for [HeaderExport] + + // When emmiting header, skip if should not be emmited. + if (isEmmitingHeader() && !structType->findDecoration()) { + return; + } + ensureTypePrelude(structType); // If the selected `struct` type is actually an intrinsic @@ -3907,11 +3940,17 @@ void CLikeSourceEmitter::emitGlobalVar(IRGlobalVar* varDecl) m_writer->emit("\n"); emitType(varType, initFuncName); - m_writer->emit("()\n{\n"); - m_writer->indent(); - emitFunctionBody(varDecl); - m_writer->dedent(); - m_writer->emit("}\n"); + + // When emmiting header, emit only declaration. + if (isEmmitingHeader()) { + m_writer->emit(";\n"); + } else { + m_writer->emit("()\n{\n"); + m_writer->indent(); + emitFunctionBody(varDecl); + m_writer->dedent(); + m_writer->emit("}\n"); + } } } diff --git a/source/slang/slang-emit-c-like.h b/source/slang/slang-emit-c-like.h index ee7ce413a8..c369de27f0 100644 --- a/source/slang/slang-emit-c-like.h +++ b/source/slang/slang-emit-c-like.h @@ -362,6 +362,8 @@ class CLikeSourceEmitter: public SourceEmitterBase void emitParamType(IRType* type, String const& name) { emitParamTypeImpl(type, name); } + bool isEmmitingHeader(); + void emitFuncDecl(IRFunc* func); void emitFuncDecl(IRFunc* func, const String& name); diff --git a/source/slang/slang-emit-cpp.cpp b/source/slang/slang-emit-cpp.cpp index 2b1f6ad819..532a7b05b4 100644 --- a/source/slang/slang-emit-cpp.cpp +++ b/source/slang/slang-emit-cpp.cpp @@ -949,7 +949,7 @@ void CPPSourceEmitter::emitSimpleFuncImpl(IRFunc* func) emitSemantics(func); // TODO: encode declaration vs. definition - if (isDefinition(func)) + if (!isEmmitingHeader() && isDefinition(func)) { m_writer->emit("\n{\n"); m_writer->indent(); diff --git a/source/slang/slang-ir-dll-export.cpp b/source/slang/slang-ir-dll-export.cpp index af5f70eb3c..35b02d34ca 100644 --- a/source/slang/slang-ir-dll-export.cpp +++ b/source/slang/slang-ir-dll-export.cpp @@ -24,6 +24,7 @@ struct DllExportContext dllExportDecoration->insertAtStart(wrapper); builder.addNameHintDecoration(wrapper, dllExportDecoration->getFunctionName()); builder.addExternCppDecoration(wrapper, dllExportDecoration->getFunctionName()); + builder.addHeaderExportDecoration(wrapper); builder.addPublicDecoration(wrapper); builder.addKeepAliveDecoration(wrapper); builder.addHLSLExportDecoration(wrapper); diff --git a/source/slang/slang-ir-inst-defs.h b/source/slang/slang-ir-inst-defs.h index 5acb22674e..e8e37294dd 100644 --- a/source/slang/slang-ir-inst-defs.h +++ b/source/slang/slang-ir-inst-defs.h @@ -769,6 +769,7 @@ INST(HighLevelDeclDecoration, highLevelDecl, 1, 0) INST(CudaKernelBackwardDerivativeDecoration, CudaKernelBwdDiffRef, 0, 0) INST(AutoPyBindExportInfoDecoration, PyBindExportFuncInfo, 0, 0) INST(PyExportDecoration, PyExportDecoration, 0, 0) + INST(HeaderExportDecoration, HeaderExportDecoration, 0, 0) /// Used to mark parameters that are moved from entry point parameters to global params as coming from the entry point. INST(EntryPointParamDecoration, entryPointParam, 0, 0) diff --git a/source/slang/slang-ir-insts.h b/source/slang/slang-ir-insts.h index 60730f135c..aa5e33c1a6 100644 --- a/source/slang/slang-ir-insts.h +++ b/source/slang/slang-ir-insts.h @@ -675,6 +675,14 @@ struct IRPyExportDecoration : IRDecoration UnownedStringSlice getExportName() { return getExportNameOperand()->getStringSlice(); } }; +struct IRHeaderExportDecoration : IRDecoration +{ + enum + { + kOp = kIROp_HeaderExportDecoration + }; + IR_LEAF_ISA(HeaderExportDecoration) +}; struct IRKnownBuiltinDecoration : IRDecoration { @@ -4647,6 +4655,11 @@ struct IRBuilder addDecoration(value, kIROp_PyExportDecoration, getStringValue(exportName)); } + void addHeaderExportDecoration(IRInst* value) + { + addDecoration(value, kIROp_HeaderExportDecoration); + } + void addCudaDeviceExportDecoration(IRInst* value, UnownedStringSlice const& functionName) { addDecoration(value, kIROp_CudaDeviceExportDecoration, getStringValue(functionName)); diff --git a/source/slang/slang-lower-to-ir.cpp b/source/slang/slang-lower-to-ir.cpp index 3f776c1a1b..cda952582a 100644 --- a/source/slang/slang-lower-to-ir.cpp +++ b/source/slang/slang-lower-to-ir.cpp @@ -1382,6 +1382,7 @@ static void addLinkageDecoration( else if (as(modifier)) { builder->addCudaKernelDecoration(inst); + builder->addHeaderExportDecoration(inst); builder->addExternCppDecoration(inst, decl->getName()->text.getUnownedSlice()); builder->addHLSLExportDecoration(inst); builder->addKeepAliveDecoration(inst); @@ -1408,6 +1409,11 @@ static void addLinkageDecoration( : decl->getName()->text.getUnownedSlice()); builder->addHLSLExportDecoration(inst); } + else if (as(modifier)) + { + builder->addKeepAliveDecoration(inst); + builder->addHeaderExportDecoration(inst); + } else if (auto knownBuiltinModifier = as(modifier)) { // We add this to the internal instruction, like other name-like diff --git a/source/slang/slang-options.cpp b/source/slang/slang-options.cpp index d9441e6da4..1d24c83509 100644 --- a/source/slang/slang-options.cpp +++ b/source/slang/slang-options.cpp @@ -521,6 +521,7 @@ void initCommandOptions(CommandOptions& options) "except for parameters that has explicit bindings in the input source." }, { OptionKind::ValidateUniformity, "-validate-uniformity", nullptr, "Perform uniformity validation analysis." }, { OptionKind::AllowGLSL, "-allow-glsl", nullptr, "Enable GLSL as an input language." }, + { OptionKind::EmitHeader, "-emit-header", nullptr, "Emits a header instead of the code (for cpp or cuda target)." }, }; _addOptions(makeConstArrayView(experimentalOpts), options); @@ -1664,6 +1665,7 @@ SlangResult OptionsParser::_parse( case OptionKind::NoMangle: case OptionKind::ValidateUniformity: case OptionKind::AllowGLSL: + case OptionKind::EmitHeader: case OptionKind::EmitIr: case OptionKind::DumpIntermediates: case OptionKind::DumpReproOnError: