diff options
| author | Yong He <yonghe@outlook.com> | 2022-04-12 15:23:53 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-04-12 15:23:53 -0700 |
| commit | 65c2e7f1ccc6cdb5daec343c7e32b4a9dc463ae4 (patch) | |
| tree | b13a93f5fa621a50ce3c100f018730c882ca3e9c /source/slang | |
| parent | 89560d62f3fb42e0f76cbae76c23eac437b65eba (diff) | |
Support `[DllImport]` (#2181)
* Support `[DllImport]`
* Fix.
* Fix.
* Fix array type emit in cpp.
* Fix.
* Fix.
* Fix
Co-authored-by: Yong He <yhe@nvidia.com>
Diffstat (limited to 'source/slang')
26 files changed, 566 insertions, 129 deletions
diff --git a/source/slang/core.meta.slang b/source/slang/core.meta.slang index c8e05d769..c3e41b8fc 100644 --- a/source/slang/core.meta.slang +++ b/source/slang/core.meta.slang @@ -342,11 +342,18 @@ ${{{{ // Declare built-in pointer type // (eventually we can have the traditional syntax sugar for this) }}}} + +__magic_type(NullPtrType) +struct NullPtr +{ +}; + __generic<T> __magic_type(PtrType) __intrinsic_type($(kIROp_PtrType)) struct Ptr -{}; +{ +}; __generic<T> __magic_type(OutType) @@ -2164,6 +2171,10 @@ attribute_syntax [__extern] : ExternAttribute; __attributeTarget(FunctionDeclBase) attribute_syntax [__unsafeForceInlineEarly] : UnsafeForceInlineEarlyAttribute; +__attributeTarget(FuncDecl) +attribute_syntax [DllImport(modulePath: String)] : DllImportAttribute; + + // Inheritance Control __attributeTarget(AggTypeDecl) attribute_syntax [sealed] : SealedAttribute; @@ -2185,3 +2196,4 @@ attribute_syntax [noinline] : NoInlineAttribute; __attributeTarget(StructDecl) attribute_syntax [payload] : PayloadAttribute; + diff --git a/source/slang/slang-ast-builder.cpp b/source/slang/slang-ast-builder.cpp index 8e1813df3..caf4c020d 100644 --- a/source/slang/slang-ast-builder.cpp +++ b/source/slang/slang-ast-builder.cpp @@ -110,6 +110,16 @@ Type* SharedASTBuilder::getDynamicType() return m_dynamicType; } +Type* SharedASTBuilder::getNullPtrType() +{ + if (!m_nullPtrType) + { + auto nullPtrTypeDecl = findMagicDecl("NullPtrType"); + m_nullPtrType = DeclRefType::create(m_astBuilder, makeDeclRef<Decl>(nullPtrTypeDecl)); + } + return m_nullPtrType; +} + SharedASTBuilder::~SharedASTBuilder() { // Release built in types.. diff --git a/source/slang/slang-ast-builder.h b/source/slang/slang-ast-builder.h index 7af5ae710..0642455c3 100644 --- a/source/slang/slang-ast-builder.h +++ b/source/slang/slang-ast-builder.h @@ -27,6 +27,8 @@ public: Type* getEnumTypeType(); /// Get the __Dynamic type Type* getDynamicType(); + /// Get the NullPtr type + Type* getNullPtrType(); const ReflectClassInfo* findClassInfo(Name* name); SyntaxClass<NodeBase> findSyntaxClass(Name* name); @@ -65,6 +67,7 @@ protected: Type* m_stringType = nullptr; Type* m_enumTypeType = nullptr; Type* m_dynamicType = nullptr; + Type* m_nullPtrType = nullptr; Type* m_builtinTypes[Index(BaseType::CountOf)]; @@ -126,6 +129,7 @@ public: Type* getOverloadedType() { return m_sharedASTBuilder->m_overloadedType; } Type* getErrorType() { return m_sharedASTBuilder->m_errorType; } Type* getStringType() { return m_sharedASTBuilder->getStringType(); } + Type* getNullPtrType() { return m_sharedASTBuilder->getNullPtrType(); } Type* getEnumTypeType() { return m_sharedASTBuilder->getEnumTypeType(); } // Construct the type `Ptr<valueType>`, where `Ptr` diff --git a/source/slang/slang-ast-expr.h b/source/slang/slang-ast-expr.h index b73e07042..a6c1d432c 100644 --- a/source/slang/slang-ast-expr.h +++ b/source/slang/slang-ast-expr.h @@ -88,6 +88,11 @@ class BoolLiteralExpr : public LiteralExpr bool value; }; +class NullPtrLiteralExpr : public LiteralExpr +{ + SLANG_AST_CLASS(NullPtrLiteralExpr) +}; + class StringLiteralExpr : public LiteralExpr { SLANG_AST_CLASS(StringLiteralExpr) diff --git a/source/slang/slang-ast-modifier.cpp b/source/slang/slang-ast-modifier.cpp new file mode 100644 index 000000000..3daa9b056 --- /dev/null +++ b/source/slang/slang-ast-modifier.cpp @@ -0,0 +1,8 @@ +// slang-ast-modifier.cpp +#include "slang-ast-modifier.h" +#include "slang-ast-expr.h" + +namespace Slang +{ + +} // namespace Slang diff --git a/source/slang/slang-ast-modifier.h b/source/slang/slang-ast-modifier.h index 35a8ea317..9a450cc31 100644 --- a/source/slang/slang-ast-modifier.h +++ b/source/slang/slang-ast-modifier.h @@ -920,6 +920,13 @@ class AnyValueSizeAttribute : public Attribute int32_t size; }; +class DllImportAttribute : public Attribute +{ + SLANG_AST_CLASS(DllImportAttribute) + + String modulePath; +}; + /// A `[__requiresNVAPI]` attribute indicates that the declaration being modifed /// requires NVAPI operations for its implementation on D3D. class RequiresNVAPIAttribute : public Attribute diff --git a/source/slang/slang-ast-type.h b/source/slang/slang-ast-type.h index f919e7bc2..fee7f7cac 100644 --- a/source/slang/slang-ast-type.h +++ b/source/slang/slang-ast-type.h @@ -489,6 +489,11 @@ class PtrTypeBase : public BuiltinType Type* getValueType(); }; +class NullPtrType : public BuiltinType +{ + SLANG_AST_CLASS(NullPtrType) +}; + // A true (user-visible) pointer type, e.g., `T*` class PtrType : public PtrTypeBase { diff --git a/source/slang/slang-check-conversion.cpp b/source/slang/slang-check-conversion.cpp index 855590472..a1935d65c 100644 --- a/source/slang/slang-check-conversion.cpp +++ b/source/slang/slang-check-conversion.cpp @@ -753,6 +753,18 @@ namespace Slang return true; } + // nullptr_t can be cast into any pointer type. + if (as<NullPtrType>(fromType) && as<PtrType>(toType)) + { + if (outCost) + { + *outCost = kConversionCost_None; + } + if (outToExpr) + *outToExpr = fromExpr; + return true; + } + // If we are casting to an interface type, then that will succeed // if the "from" type conforms to the interface. // diff --git a/source/slang/slang-check-expr.cpp b/source/slang/slang-check-expr.cpp index 88c4edec5..2290936d8 100644 --- a/source/slang/slang-check-expr.cpp +++ b/source/slang/slang-check-expr.cpp @@ -645,6 +645,12 @@ namespace Slang return expr; } + Expr* SemanticsExprVisitor::visitNullPtrLiteralExpr(NullPtrLiteralExpr* expr) + { + expr->type = m_astBuilder->getNullPtrType(); + return expr; + } + Expr* SemanticsExprVisitor::visitIntegerLiteralExpr(IntegerLiteralExpr* expr) { // The expression might already have a type, determined by its suffix. diff --git a/source/slang/slang-check-impl.h b/source/slang/slang-check-impl.h index 8ea693104..82a0e7453 100644 --- a/source/slang/slang-check-impl.h +++ b/source/slang/slang-check-impl.h @@ -1534,6 +1534,7 @@ namespace Slang {} Expr* visitBoolLiteralExpr(BoolLiteralExpr* expr); + Expr* visitNullPtrLiteralExpr(NullPtrLiteralExpr* expr); Expr* visitIntegerLiteralExpr(IntegerLiteralExpr* expr); Expr* visitFloatingPointLiteralExpr(FloatingPointLiteralExpr* expr); Expr* visitStringLiteralExpr(StringLiteralExpr* expr); diff --git a/source/slang/slang-check-modifier.cpp b/source/slang/slang-check-modifier.cpp index 4594af28d..e597407e2 100644 --- a/source/slang/slang-check-modifier.cpp +++ b/source/slang/slang-check-modifier.cpp @@ -528,6 +528,17 @@ namespace Slang allowAttr->diagnostic = diagnosticInfo; } + else if (auto dllImportAttr = as<DllImportAttribute>(attr)) + { + SLANG_ASSERT(attr->args.getCount() == 1); + + String libraryName; + if (!checkLiteralStringVal(dllImportAttr->args[0], &libraryName)) + { + return false; + } + dllImportAttr->modulePath = libraryName; + } else { if(attr->args.getCount() == 0) diff --git a/source/slang/slang-diagnostic-defs.h b/source/slang/slang-diagnostic-defs.h index b2575b255..2f18038ac 100644 --- a/source/slang/slang-diagnostic-defs.h +++ b/source/slang/slang-diagnostic-defs.h @@ -565,6 +565,8 @@ DIAGNOSTIC(52005, Error, unableToReadFile, "unable to read file '$0'") DIAGNOSTIC(52006, Error, compilerNotDefinedForTransition, "compiler not defined for transition '$0' to '$1'.") +DIAGNOSTIC(53001,Error, invalidTypeMarshallingForImportedDLLSymbol, "invalid type marshalling in imported func $0.") + // // 8xxxx - Issues specific to a particular library/technology/platform/etc. // diff --git a/source/slang/slang-emit-c-like.cpp b/source/slang/slang-emit-c-like.cpp index edadcef48..562a532cd 100644 --- a/source/slang/slang-emit-c-like.cpp +++ b/source/slang/slang-emit-c-like.cpp @@ -159,6 +159,14 @@ void CLikeSourceEmitter::emitDeclarator(DeclaratorInfo* declarator) } break; + case DeclaratorInfo::Flavor::Ref: + { + auto refDeclarator = (RefDeclaratorInfo*)declarator; + m_writer->emit("&"); + emitDeclarator(refDeclarator->next); + } + break; + case DeclaratorInfo::Flavor::LiteralSizedArray: { auto arrayDeclarator = (LiteralSizedArrayDeclaratorInfo*)declarator; @@ -180,8 +188,6 @@ void CLikeSourceEmitter::emitDeclarator(DeclaratorInfo* declarator) emitDeclarator(attributedDeclarator->next); } break; - - default: SLANG_DIAGNOSE_UNEXPECTED(getSink(), SourceLoc(), "unknown declarator flavor"); break; @@ -214,6 +220,8 @@ void CLikeSourceEmitter::emitSimpleType(IRType* type) case kIROp_FloatType: return UnownedStringSlice("float"); case kIROp_DoubleType: return UnownedStringSlice("double"); + + case kIROp_CharType: return UnownedStringSlice("uint8_t"); default: return UnownedStringSlice(); } } @@ -324,7 +332,6 @@ void CLikeSourceEmitter::_emitType(IRType* type, DeclaratorInfo* declarator) } break; } - } void CLikeSourceEmitter::emitWitnessTable(IRWitnessTable* witnessTable) @@ -3305,8 +3312,14 @@ void CLikeSourceEmitter::ensureInstOperandsRec(ComputeEmitActionsContext* ctx, I UInt operandCount = inst->operandCount; auto requiredLevel = EmitAction::Definition; - if (inst->getOp() == kIROp_InterfaceType) + switch (inst->getOp()) + { + case kIROp_InterfaceType: requiredLevel = EmitAction::ForwardDeclaration; + break; + default: + break; + } for(UInt ii = 0; ii < operandCount; ++ii) { @@ -3404,6 +3417,23 @@ void CLikeSourceEmitter::computeEmitActions(IRModule* module, List<EmitAction>& } } +void CLikeSourceEmitter::emitForwardDeclaration(IRInst* inst) +{ + switch (inst->getOp()) + { + case kIROp_Func: + emitFuncDecl(cast<IRFunc>(inst)); + break; + case kIROp_StructType: + m_writer->emit("struct "); + m_writer->emit(getName(inst)); + m_writer->emit(";\n"); + break; + default: + SLANG_UNREACHABLE("emit forward declaration"); + } +} + void CLikeSourceEmitter::executeEmitActions(List<EmitAction> const& actions) { for(auto action : actions) @@ -3411,7 +3441,7 @@ void CLikeSourceEmitter::executeEmitActions(List<EmitAction> const& actions) switch(action.level) { case EmitAction::Level::ForwardDeclaration: - emitFuncDecl(cast<IRFunc>(action.inst)); + emitForwardDeclaration(action.inst); break; case EmitAction::Level::Definition: diff --git a/source/slang/slang-emit-c-like.h b/source/slang/slang-emit-c-like.h index 6a3a31f78..ba2f5b86c 100644 --- a/source/slang/slang-emit-c-like.h +++ b/source/slang/slang-emit-c-like.h @@ -68,6 +68,7 @@ public: { Name, Ptr, + Ref, SizedArray, UnsizedArray, LiteralSizedArray, @@ -110,6 +111,13 @@ public: {} }; + struct RefDeclaratorInfo : ChainedDeclaratorInfo + { + RefDeclaratorInfo(DeclaratorInfo* next) + : ChainedDeclaratorInfo(Flavor::Ref, next) + {} + }; + struct SizedArrayDeclaratorInfo : ChainedDeclaratorInfo { IRInst* elementCount; @@ -147,6 +155,16 @@ public: IRInst* instWithAttributes; }; + struct FuncTypeDeclaratorInfo : ChainedDeclaratorInfo + { + FuncTypeDeclaratorInfo(DeclaratorInfo* next, IRFuncType* funcTypeInst) + : ChainedDeclaratorInfo(Flavor::Attributed, next) + , funcType(funcTypeInst) + {} + + IRFuncType* funcType; + }; + struct ComputeEmitActionsContext; // An action to be performed during code emit. @@ -344,6 +362,7 @@ public: void emitStruct(IRStructType* structType); + /// Emit type attributes that should appear after, e.g., a `struct` keyword void emitPostKeywordTypeAttributes(IRInst* inst) { emitPostKeywordTypeAttributesImpl(inst); } @@ -378,9 +397,12 @@ public: void ensureGlobalInst(ComputeEmitActionsContext* ctx, IRInst* inst, EmitAction::Level requiredLevel); + void emitForwardDeclaration(IRInst* inst); + void computeEmitActions(IRModule* module, List<EmitAction>& ioActions); void executeEmitActions(List<EmitAction> const& actions); + void emitModule(IRModule* module, DiagnosticSink* sink) { m_irModule = module; emitModuleImpl(module, sink); } @@ -458,7 +480,9 @@ public: virtual void emitPostKeywordTypeAttributesImpl(IRInst* inst) { SLANG_UNUSED(inst); } - void _emitType(IRType* type, DeclaratorInfo* declarator); + void _emitFuncTypeDeclaration(IRFuncType* type, IRAttributedType* attributes); + + virtual void _emitType(IRType* type, DeclaratorInfo* declarator); void _emitInst(IRInst* inst); virtual void _emitPrefixTypeAttr(IRAttr* attr); diff --git a/source/slang/slang-emit-cpp.cpp b/source/slang/slang-emit-cpp.cpp index c56190f65..93bc5c979 100644 --- a/source/slang/slang-emit-cpp.cpp +++ b/source/slang/slang-emit-cpp.cpp @@ -217,6 +217,8 @@ static bool _isCppOrCudaTarget(CodeGenTarget target) case kIROp_FloatType: return UnownedStringSlice("float"); case kIROp_DoubleType: return UnownedStringSlice("double"); + case kIROp_CharType: return UnownedStringSlice("char"); + default: return UnownedStringSlice(); } } @@ -429,22 +431,6 @@ SlangResult CPPSourceEmitter::calcTypeName(IRType* type, CodeGenTarget target, S { switch (type->getOp()) { - case kIROp_OutType: - case kIROp_InOutType: - case kIROp_PtrType: - { - auto ptrType = static_cast<IRPtrType*>(type); - SLANG_RETURN_ON_FAIL(calcTypeName(ptrType->getValueType(), target, out)); - out << "*"; - return SLANG_OK; - } - case kIROp_RefType: - { - auto refType = static_cast<IRRefType*>(type); - SLANG_RETURN_ON_FAIL(calcTypeName(refType->getValueType(), target, out)); - out << "&"; - return SLANG_OK; - } case kIROp_HalfType: { // Special case half @@ -501,27 +487,6 @@ SlangResult CPPSourceEmitter::calcTypeName(IRType* type, CodeGenTarget target, S } return SLANG_OK; } - case kIROp_ArrayType: - { - auto arrayType = static_cast<IRArrayType*>(type); - auto elementType = arrayType->getElementType(); - int elementCount = int(getIntVal(arrayType->getElementCount())); - - out << "FixedArray<"; - SLANG_RETURN_ON_FAIL(calcTypeName(elementType, target, out)); - out << ", " << elementCount << ">"; - return SLANG_OK; - } - case kIROp_UnsizedArrayType: - { - auto arrayType = static_cast<IRUnsizedArrayType*>(type); - auto elementType = arrayType->getElementType(); - - out << "Array<"; - SLANG_RETURN_ON_FAIL(calcTypeName(elementType, target, out)); - out << ">"; - return SLANG_OK; - } case kIROp_WitnessTableType: case kIROp_WitnessTableIDType: { @@ -1573,8 +1538,15 @@ SlangResult CPPSourceEmitter::calcFuncName(const HLSLIntrinsic* specOp, StringBu { IRType* paramType = specOp->signatureType->getParamType(0); IRBasicType* basicType = as<IRBasicType>(paramType); - SLANG_ASSERT(basicType); - return calcScalarFuncName(specOp->op, basicType, outBuilder); + if (basicType) + { + return calcScalarFuncName(specOp->op, basicType, outBuilder); + } + else + { + outBuilder << getName(paramType) << HLSLIntrinsic::getInfo(specOp->op).name; + return SLANG_OK; + } } else { @@ -1651,40 +1623,8 @@ CPPSourceEmitter::CPPSourceEmitter(const Desc& desc): //m_semanticUsedFlags = SemanticUsedFlag::GroupID | SemanticUsedFlag::GroupThreadID | SemanticUsedFlag::DispatchThreadID; } -void CPPSourceEmitter::_emitInOutParamType(IRType* type, String const& name, IRType* valueType) -{ - StringSliceLoc nameAndLoc(name.getUnownedSlice()); - - if (auto refType = as<IRRefType>(type)) - { - m_writer->emit("const "); - } - - UnownedStringSlice slice = _getTypeName(valueType); - m_writer->emit(slice); - m_writer->emit("* "); - m_writer->emitName(nameAndLoc); -} - void CPPSourceEmitter::emitParamTypeImpl(IRType* type, String const& name) { - // An `out` or `inout` parameter will have been - // encoded as a parameter of pointer type, so - // we need to decode that here. - // - if (auto outType = as<IROutType>(type)) - { - return _emitInOutParamType(type, name, outType->getValueType()); - } - else if (auto inOutType = as<IRInOutType>(type)) - { - return _emitInOutParamType(type, name, inOutType->getValueType()); - } - else if (auto refType = as<IRRefType>(type)) - { - return _emitInOutParamType(type, name, refType->getValueType()); - } - emitType(type, name); } @@ -2059,15 +1999,69 @@ void CPPSourceEmitter::emitSimpleTypeImpl(IRType* inType) m_writer->emit(slice); } -void CPPSourceEmitter::emitTypeImpl(IRType* type, const StringSliceLoc* nameLoc) +void CPPSourceEmitter::_emitType(IRType* type, DeclaratorInfo* declarator) { - UnownedStringSlice slice = _getTypeName(type); - m_writer->emit(slice); - - if (nameLoc) + switch (type->getOp()) { - m_writer->emit(" "); - m_writer->emitName(*nameLoc); + default: + CLikeSourceEmitter::_emitType(type, declarator); + break; + + case kIROp_PtrType: + case kIROp_InOutType: + case kIROp_OutType: + { + auto ptrType = cast<IRPtrTypeBase>(type); + PtrDeclaratorInfo ptrDeclarator(declarator); + _emitType(ptrType->getValueType(), &ptrDeclarator); + } + break; + case kIROp_RefType: + { + auto ptrType = cast<IRPtrTypeBase>(type); + RefDeclaratorInfo refDeclarator(declarator); + _emitType(ptrType->getValueType(), &refDeclarator); + } + break; + case kIROp_ArrayType: + { + auto arrayType = static_cast<IRArrayType*>(type); + auto elementType = arrayType->getElementType(); + int elementCount = int(getIntVal(arrayType->getElementCount())); + + m_writer->emit("FixedArray<"); + _emitType(elementType, nullptr); + m_writer->emit(", "); + m_writer->emit(elementCount); + m_writer->emit("> "); + emitDeclarator(declarator); + } + break; + case kIROp_UnsizedArrayType: + { + auto arrayType = static_cast<IRUnsizedArrayType*>(type); + auto elementType = arrayType->getElementType(); + + m_writer->emit("Array<"); + _emitType(elementType, nullptr); + m_writer->emit("> "); + emitDeclarator(declarator); + } + break; + case kIROp_FuncType: + { + auto funcType = cast<IRFuncType>(type); + m_writer->emit("Slang_FuncType<"); + _emitType(funcType->getResultType(), nullptr); + for (UInt i = 0; i < funcType->getParamCount(); i++) + { + m_writer->emit(", "); + _emitType(funcType->getParamType(i), nullptr); + } + m_writer->emit("> "); + emitDeclarator(declarator); + } + break; } } @@ -2336,17 +2330,6 @@ bool CPPSourceEmitter::tryEmitInstExprImpl(IRInst* inst, const EmitOpInfo& inOut m_writer->emit("->typeSize)"); return true; } - case kIROp_Copy: - { - m_writer->emit("memcpy("); - emitOperand(inst->getOperand(0), EmitOpInfo::get(EmitOp::General)); - m_writer->emit(", "); - emitOperand(inst->getOperand(1), EmitOpInfo::get(EmitOp::General)); - m_writer->emit(", "); - emitOperand(inst->getOperand(2), EmitOpInfo::get(EmitOp::Postfix)); - m_writer->emit("->typeSize)"); - return true; - } case kIROp_BitCast: { m_writer->emit("(slang_bit_cast<"); @@ -2363,7 +2346,23 @@ bool CPPSourceEmitter::tryEmitInstExprImpl(IRInst* inst, const EmitOpInfo& inOut m_writer->emit(")"); return true; } - + case kIROp_PtrLit: + { + auto ptrVal = as<IRPtrLit>(inst)->value.ptrVal; + if (ptrVal == nullptr) + { + m_writer->emit("nullptr"); + } + else + { + m_writer->emit("reinterpret_cast<"); + emitType(inst->getFullType()); + m_writer->emit(">("); + m_writer->emitUInt64((uint64_t)ptrVal); + m_writer->emit(")"); + } + return true; + } } } @@ -2647,7 +2646,17 @@ void CPPSourceEmitter::_emitForwardDeclarations(const List<EmitAction>& actions) switch (action.level) { case EmitAction::Level::ForwardDeclaration: - emitFuncDecl(cast<IRFunc>(action.inst)); + { + switch (action.inst->getOp()) + { + case kIROp_Func: + case kIROp_StructType: + emitForwardDeclaration(action.inst); + break; + default: + break; + } + } break; case EmitAction::Level::Definition: diff --git a/source/slang/slang-emit-cpp.h b/source/slang/slang-emit-cpp.h index 5ba509e7d..a75fe2caf 100644 --- a/source/slang/slang-emit-cpp.h +++ b/source/slang/slang-emit-cpp.h @@ -56,7 +56,7 @@ protected: virtual void emitParameterGroupImpl(IRGlobalParam* varDecl, IRUniformParameterGroupType* type) SLANG_OVERRIDE; virtual void emitEntryPointAttributesImpl(IRFunc* irFunc, IREntryPointDecoration* entryPointDecor) SLANG_OVERRIDE; virtual void emitSimpleTypeImpl(IRType* type) SLANG_OVERRIDE; - virtual void emitTypeImpl(IRType* type, const StringSliceLoc* nameLoc) SLANG_OVERRIDE; + virtual void _emitType(IRType* type, DeclaratorInfo* declarator) SLANG_OVERRIDE; virtual void emitVectorTypeNameImpl(IRType* elementType, IRIntegerValue elementCount) SLANG_OVERRIDE; virtual bool tryEmitInstExprImpl(IRInst* inst, const EmitOpInfo& inOuterPrec) SLANG_OVERRIDE; virtual void emitPreprocessorDirectivesImpl() SLANG_OVERRIDE; diff --git a/source/slang/slang-emit.cpp b/source/slang/slang-emit.cpp index 067d0a99a..d09217b58 100644 --- a/source/slang/slang-emit.cpp +++ b/source/slang/slang-emit.cpp @@ -9,6 +9,7 @@ #include "slang-ir-byte-address-legalize.h" #include "slang-ir-collect-global-uniforms.h" #include "slang-ir-dce.h" +#include "slang-ir-dll-import.h" #include "slang-ir-entry-point-uniforms.h" #include "slang-ir-entry-point-raw-ptr-params.h" #include "slang-ir-explicit-global-context.h" @@ -682,6 +683,15 @@ Result linkAndOptimizeIR( break; } + switch (target) + { + default: + break; + case CodeGenTarget::HostCPPSource: + generateDllImportFuncs(irModule, sink); + break; + } + // TODO: our current dynamic dispatch pass will remove all uses of witness tables. // If we are going to support function-pointer based, "real" modular dynamic dispatch, // we will need to disable this pass. diff --git a/source/slang/slang-ir-dll-import.cpp b/source/slang/slang-ir-dll-import.cpp new file mode 100644 index 000000000..ed0a3e007 --- /dev/null +++ b/source/slang/slang-ir-dll-import.cpp @@ -0,0 +1,249 @@ +// slang-ir-dll-import.cpp +#include "slang-ir-dll-import.h" + +#include "slang-ir.h" +#include "slang-ir-insts.h" + +namespace Slang +{ + +struct DllImportContext +{ + IRModule* module; + DiagnosticSink* diagnosticSink; + + SharedIRBuilder sharedBuilder; + + IRFunc* loadDllFunc = nullptr; + IRFunc* loadFuncPtrFunc = nullptr; + IRFunc* stringGetBufferFunc = nullptr; + + IRFunc* createBuiltinIntrinsicFunc(UInt paramCount, IRType** paramTypes, IRType* resultType, UnownedStringSlice targetIntrinsic) + { + IRBuilder builder(sharedBuilder); + builder.setInsertInto(module->getModuleInst()); + IRFunc* result = builder.createFunc(); + builder.setInsertInto(result); + auto funcType = builder.getFuncType(paramCount, paramTypes, resultType); + builder.setDataType(result, funcType); + builder.addTargetIntrinsicDecoration( + result, CapabilitySet(CapabilityAtom::CPP), targetIntrinsic); + return result; + } + + IRFunc* getLoadDllFunc() + { + if (!loadDllFunc) + { + IRBuilder builder(sharedBuilder); + builder.setInsertInto(module->getModuleInst()); + IRType* stringType = builder.getStringType(); + loadDllFunc = createBuiltinIntrinsicFunc( + 1, + &stringType, + builder.getPtrType(builder.getVoidType()), + UnownedStringSlice("_slang_rt_load_dll($0)")); + } + return loadDllFunc; + } + + IRFunc* getLoadFuncPtrFunc() + { + if (!loadFuncPtrFunc) + { + IRBuilder builder(sharedBuilder); + builder.setInsertInto(module->getModuleInst()); + + IRType* stringType = builder.getStringType(); + IRType* paramTypes[] = {builder.getPtrType(builder.getVoidType()), stringType}; + loadFuncPtrFunc = createBuiltinIntrinsicFunc( + 2, + paramTypes, + builder.getPtrType(builder.getVoidType()), + UnownedStringSlice("_slang_rt_load_dll_func($0, $1)")); + } + return loadFuncPtrFunc; + } + + IRFunc* getStringGetBufferFunc() + { + if (!stringGetBufferFunc) + { + IRBuilder builder(sharedBuilder); + builder.setInsertInto(module->getModuleInst()); + + IRType* stringType = builder.getStringType(); + IRType* paramTypes[] = {stringType}; + stringGetBufferFunc = createBuiltinIntrinsicFunc( + 1, + paramTypes, + builder.getPtrType(builder.getCharType()), + UnownedStringSlice("const_cast<char*>($0.getBuffer())")); + } + return stringGetBufferFunc; + } + + IRType* getNativeType(IRBuilder& builder, IRType* type) + { + switch (type->getOp()) + { + case kIROp_StringType: + return builder.getPtrType(builder.getCharType()); + default: + return type; + } + } + + IRType* getNativeFuncType(IRBuilder& builder, IRFunc* func) + { + List<IRInst*> nativeParamTypes; + auto declaredFuncType = func->getDataType(); + assert(declaredFuncType->getOp() == kIROp_FuncType); + for (UInt i = 0; i < declaredFuncType->getParamCount(); ++i) + { + auto paramType = declaredFuncType->getParamType(i); + nativeParamTypes.add(getNativeType(builder, as<IRType>(paramType))); + } + IRType* returnType = getNativeType(builder, func->getResultType()); + auto funcType = builder.getFuncType( + nativeParamTypes.getCount(), (IRType**)nativeParamTypes.getBuffer(), returnType); + + return funcType; + } + + void marshalImportRefParameter(IRBuilder& builder, IRParam* param, List<IRInst*>& args) + { + SLANG_UNUSED(builder); + + auto innerType = as<IRPtrTypeBase>(param->getDataType())->getValueType(); + switch (innerType->getOp()) + { + case kIROp_StringType: + { + diagnosticSink->diagnose( + param->sourceLoc, + Diagnostics::invalidTypeMarshallingForImportedDLLSymbol, + param->getParent()->getParent()); + } + break; + default: + args.add(param); + break; + } + } + + void marshalImportParameter(IRBuilder& builder, IRParam* param, List<IRInst*>& args) + { + switch (param->getDataType()->getOp()) + { + case kIROp_InOutType: + case kIROp_RefType: + return marshalImportRefParameter(builder, param, args); + case kIROp_StringType: + { + auto getStringBufferFunc = getStringGetBufferFunc(); + args.add(builder.emitCallInst( + builder.getPtrType(builder.getCharType()), getStringBufferFunc, 1, (IRInst**)¶m)); + } + break; + default: + args.add(param); + break; + } + } + + void processFunc(IRFunc* func, IRDllImportDecoration* dllImportDecoration) + { + assert(func->getFirstBlock() == nullptr); + + IRBuilder builder(sharedBuilder); + + auto nativeType = getNativeFuncType(builder, func); + builder.setInsertInto(module->getModuleInst()); + auto funcPtr = builder.createGlobalVar(nativeType); + builder.setInsertInto(funcPtr); + builder.emitBlock(); + builder.emitReturn(builder.getPtrValue(nullptr)); + + builder.setInsertInto(func); + auto block = builder.emitBlock(); + builder.setInsertInto(block); + + // Emit parameters. + auto declaredFuncType = func->getDataType(); + List<IRParam*> params; + for (UInt i = 0; i < declaredFuncType->getParamCount(); ++i) + { + auto paramType = declaredFuncType->getParamType(i); + params.add(builder.emitParam((IRType*)paramType)); + } + + // Marshal parameters to arguments into native func. + List<IRInst*> args; + for (auto param : params) + { + marshalImportParameter(builder, param, args); + } + IRInst* cmpArgs[] = {builder.emitLoad(nativeType, funcPtr), builder.getPtrValue(nullptr)}; + auto isUninitialized = + builder.emitIntrinsicInst(builder.getBoolType(), kIROp_Eql, 2, cmpArgs); + + auto trueBlock = builder.emitBlock(); + auto afterBlock = builder.emitBlock(); + + builder.setInsertInto(block); + builder.emitIf(isUninitialized, trueBlock, afterBlock); + + builder.setInsertInto(trueBlock); + auto modulePtr = builder.emitCallInst( + builder.getPtrType(builder.getVoidType()), + getLoadDllFunc(), + builder.getStringValue(dllImportDecoration->getLibraryName())); + + IRInst* loadDllFuncArgs[] = { + modulePtr, builder.getStringValue(dllImportDecoration->getFunctionName())}; + auto loadedNativeFuncPtr = builder.emitCallInst( + builder.getPtrType(builder.getVoidType()), getLoadFuncPtrFunc(), 2, loadDllFuncArgs); + builder.emitStore( + funcPtr, builder.emitBitCast(nativeType, loadedNativeFuncPtr)); + builder.emitBranch(afterBlock); + builder.setInsertInto(afterBlock); + + IRType* nativeReturnType = getNativeType(builder, func->getResultType()); + auto nativeFunc = builder.emitLoad(funcPtr); + auto call = builder.emitCallInst(nativeReturnType, nativeFunc, args); + if (declaredFuncType->getResultType()->getOp() != kIROp_VoidType) + { + builder.emitReturn(call); + } + } + + void processModule() + { + for (auto childFunc : module->getGlobalInsts()) + { + switch(childFunc->getOp()) + { + case kIROp_Func: + if (auto dllImportDecoration = childFunc->findDecoration<IRDllImportDecoration>()) + { + processFunc(as<IRFunc>(childFunc), dllImportDecoration); + } + break; + default: + break; + } + } + } +}; + +void generateDllImportFuncs(IRModule* module, DiagnosticSink* sink) +{ + DllImportContext context; + context.module = module; + context.diagnosticSink = sink; + context.sharedBuilder.init(module); + return context.processModule(); +} + +} diff --git a/source/slang/slang-ir-dll-import.h b/source/slang/slang-ir-dll-import.h new file mode 100644 index 000000000..c330f803f --- /dev/null +++ b/source/slang/slang-ir-dll-import.h @@ -0,0 +1,11 @@ +// slang-ir-dll-import.h +#pragma once + +namespace Slang +{ + struct IRModule; + class DiagnosticSink; + /// Generate implementations for functions marked as [DllImport]. + void generateDllImportFuncs(IRModule* module, DiagnosticSink* sink); + +} diff --git a/source/slang/slang-ir-inst-defs.h b/source/slang/slang-ir-inst-defs.h index bcc42ad9e..bce188cfa 100644 --- a/source/slang/slang-ir-inst-defs.h +++ b/source/slang/slang-ir-inst-defs.h @@ -92,7 +92,6 @@ INST(Nop, nop, 0, 0) /* PtrTypeBase */ INST(PtrType, Ptr, 1, 0) INST(RefType, Ref, 1, 0) - // A `PsuedoPtr<T>` logically represents a pointer to a value of type // `T` on a platform that cannot support pointers. The expectation // is that the "pointer" will be legalized away by storing a value @@ -284,7 +283,6 @@ INST(Var, var, 0, 0) INST(Load, load, 1, 0) INST(Store, store, 2, 0) -INST(Copy, copy, 3, 0) INST(FieldExtract, get_field, 2, 0) INST(FieldAddress, get_field_addr, 2, 0) @@ -604,6 +602,10 @@ INST(HighLevelDeclDecoration, highLevelDecl, 1, 0) /// An extern_cpp decoration marks the inst to emit its name without mangling for C++ interop. INST(ExternCppDecoration, externCpp, 1, 0) + /// An dllImport decoration marks a function as imported from a DLL. Slang will generate dynamic function loading logic to use this function at runtime. + INST(DllImportDecoration, dllImport, 2, 0) + + /* Decorations for RTTI objects */ INST(RTTITypeSizeDecoration, RTTI_typeSize, 1, 0) INST(AnyValueSizeDecoration, AnyValueSize, 1, 0) diff --git a/source/slang/slang-ir-insts.h b/source/slang/slang-ir-insts.h index 102c48495..8b4eaf5cb 100644 --- a/source/slang/slang-ir-insts.h +++ b/source/slang/slang-ir-insts.h @@ -430,6 +430,21 @@ struct IRExternCppDecoration : IRDecoration UnownedStringSlice getName() { return getNameOperand()->getStringSlice(); } }; +struct IRDllImportDecoration : IRDecoration +{ + enum + { + kOp = kIROp_DllImportDecoration + }; + IR_LEAF_ISA(DllImportDecoration) + + IRStringLit* getLibraryNameOperand() { return cast<IRStringLit>(getOperand(0)); } + UnownedStringSlice getLibraryName() { return getLibraryNameOperand()->getStringSlice(); } + + IRStringLit* getFunctionNameOperand() { return cast<IRStringLit>(getOperand(1)); } + UnownedStringSlice getFunctionName() { return getFunctionNameOperand()->getStringSlice(); } +}; + struct IRFormatDecoration : IRDecoration { enum { kOp = kIROp_FormatDecoration }; @@ -542,17 +557,6 @@ struct IRAlloca : IRInst IRInst* getAllocSize() { return getOperand(0); } }; -/// Copies `size` bytes from `src` to `dst`. -/// -struct IRCopy : IRInst -{ - IR_LEAF_ISA(Copy) - - IRInst* getDst() { return getOperand(0); } - IRInst* getSrc() { return getOperand(1); } - IRInst* getSize() { return getOperand(2); } -}; - /// Packs a value into an `AnyValue`. /// Return type is `IRAnyValueType`. struct IRPackAnyValue : IRInst @@ -2025,7 +2029,9 @@ public: IRBasicType* getIntType(); IRBasicType* getUIntType(); IRBasicType* getUInt64Type(); + IRBasicType* getCharType(); IRStringType* getStringType(); + IRType* getCapabilitySetType(); IRAssociatedType* getAssociatedType(ArrayView<IRInterfaceType*> constraintTypes); @@ -2194,8 +2200,6 @@ public: IRInst* emitAlloca(IRInst* type, IRInst* rttiObjPtr); - IRInst* emitCopy(IRInst* dst, IRInst* src, IRInst* rttiObjPtr); - IRInst* emitPackAnyValue(IRType* type, IRInst* value); IRInst* emitUnpackAnyValue(IRType* type, IRInst* value); @@ -2811,6 +2815,11 @@ public: addDecoration(value, kIROp_ExternCppDecoration, getStringValue(mangledName)); } + void addDllImportDecoration(IRInst* value, UnownedStringSlice const& libraryName, UnownedStringSlice const& functionName) + { + addDecoration(value, kIROp_DllImportDecoration, getStringValue(libraryName), getStringValue(functionName)); + } + void addEntryPointDecoration(IRInst* value, Profile profile, UnownedStringSlice const& name, UnownedStringSlice const& moduleName) { IRInst* operands[] = { getIntValue(getIntType(), profile.raw), getStringValue(name), getStringValue(moduleName) }; diff --git a/source/slang/slang-ir.cpp b/source/slang/slang-ir.cpp index bb1b0a9d2..09a28e394 100644 --- a/source/slang/slang-ir.cpp +++ b/source/slang/slang-ir.cpp @@ -2466,6 +2466,11 @@ namespace Slang return (IRBasicType*)getType(kIROp_UInt64Type); } + IRBasicType* IRBuilder::getCharType() + { + return (IRBasicType*)getType(kIROp_CharType); + } + IRStringType* IRBuilder::getStringType() { return (IRStringType*)getType(kIROp_StringType); @@ -2962,20 +2967,6 @@ namespace Slang return inst; } - IRInst* IRBuilder::emitCopy(IRInst* dst, IRInst* src, IRInst* rttiObjPtr) - { - IRInst* args[] = { dst, src, rttiObjPtr }; - auto inst = createInst<IRCopy>( - this, - kIROp_Copy, - getVoidType(), - 3, - args); - - addInst(inst); - return inst; - } - IRInst* IRBuilder::emitPackAnyValue(IRType* type, IRInst* value) { auto inst = createInst<IRPackAnyValue>( diff --git a/source/slang/slang-lower-to-ir.cpp b/source/slang/slang-lower-to-ir.cpp index bca8bd5b6..6cdf20af4 100644 --- a/source/slang/slang-lower-to-ir.cpp +++ b/source/slang/slang-lower-to-ir.cpp @@ -1051,6 +1051,11 @@ static void addLinkageDecoration( { builder->addExternCppDecoration(inst, mangledName); } + if (auto dllImportModifier = decl->findModifier<DllImportAttribute>()) + { + auto libraryName = dllImportModifier->modulePath; + builder->addDllImportDecoration(inst, libraryName.getUnownedSlice(), decl->getName()->text.getUnownedSlice()); + } } static void addLinkageDecoration( @@ -3173,6 +3178,11 @@ struct ExprLoweringVisitorBase : ExprVisitor<Derived, LoweredValInfo> return LoweredValInfo::simple(context->irBuilder->getBoolValue(expr->value)); } + LoweredValInfo visitNullPtrLiteralExpr(NullPtrLiteralExpr*) + { + return LoweredValInfo::simple(context->irBuilder->getPtrValue(nullptr)); + } + LoweredValInfo visitIntegerLiteralExpr(IntegerLiteralExpr* expr) { auto type = lowerType(context, expr->type); diff --git a/source/slang/slang-parser.cpp b/source/slang/slang-parser.cpp index c08f5cf34..40bb91d77 100644 --- a/source/slang/slang-parser.cpp +++ b/source/slang/slang-parser.cpp @@ -3551,8 +3551,9 @@ namespace Slang { // User is specifying the class that should be construted auto classNameAndLoc = expectIdentifier(parser); - syntaxClass = parser->astBuilder->findSyntaxClass(classNameAndLoc.name); + + assert(syntaxClass.classInfo); } else { @@ -4822,6 +4823,11 @@ namespace Slang return parseBoolLitExpr(parser, false); } + static NodeBase* parseNullPtrExpr(Parser* parser, void* /*userData*/) + { + return parser->astBuilder->create<NullPtrLiteralExpr>(); + } + static bool _isFinite(double value) { // Lets type pun double to uint64_t, so we can detect special double values @@ -6296,6 +6302,7 @@ namespace Slang _makeParseExpr("This", parseThisTypeExpr), _makeParseExpr("true", parseTrueExpr), _makeParseExpr("false", parseFalseExpr), + _makeParseExpr("nullptr", parseNullPtrExpr), _makeParseExpr("__TaggedUnion", parseTaggedUnionType), }; diff --git a/source/slang/slang-type-system-shared.h b/source/slang/slang-type-system-shared.h index 3b3dc6a91..d0972881a 100644 --- a/source/slang/slang-type-system-shared.h +++ b/source/slang/slang-type-system-shared.h @@ -19,6 +19,7 @@ namespace Slang X(Half) \ X(Float) \ X(Double) \ + X(Char) \ /* end */ enum class BaseType diff --git a/source/slang/slang.cpp b/source/slang/slang.cpp index 2d992ef36..ab4d0749d 100644 --- a/source/slang/slang.cpp +++ b/source/slang/slang.cpp @@ -70,6 +70,7 @@ namespace Slang { { uint8_t(sizeof(uint16_t)), BaseTypeInfo::Flag::FloatingPoint , uint8_t(BaseType::Half) }, { uint8_t(sizeof(float)), BaseTypeInfo::Flag::FloatingPoint , uint8_t(BaseType::Float) }, { uint8_t(sizeof(double)), BaseTypeInfo::Flag::FloatingPoint , uint8_t(BaseType::Double) }, + { uint8_t(sizeof(char)), BaseTypeInfo::Flag::Signed | BaseTypeInfo::Flag::Integer , uint8_t(BaseType::Char) }, }; /* static */bool BaseTypeInfo::check() |
