diff options
Diffstat (limited to 'source/slang')
| -rw-r--r-- | source/slang/core.meta.slang | 34 | ||||
| -rw-r--r-- | source/slang/slang-ast-builder.cpp | 10 | ||||
| -rw-r--r-- | source/slang/slang-ast-builder.h | 4 | ||||
| -rw-r--r-- | source/slang/slang-ast-expr.h | 5 | ||||
| -rw-r--r-- | source/slang/slang-ast-iterator.h | 4 | ||||
| -rw-r--r-- | source/slang/slang-ast-support-types.h | 3 | ||||
| -rw-r--r-- | source/slang/slang-ast-type.h | 5 | ||||
| -rw-r--r-- | source/slang/slang-check-conversion.cpp | 19 | ||||
| -rw-r--r-- | source/slang/slang-check-expr.cpp | 6 | ||||
| -rw-r--r-- | source/slang/slang-check-impl.h | 1 | ||||
| -rw-r--r-- | source/slang/slang-emit.cpp | 3 | ||||
| -rw-r--r-- | source/slang/slang-ir-cleanup-void.cpp | 159 | ||||
| -rw-r--r-- | source/slang/slang-ir-cleanup-void.h | 15 | ||||
| -rw-r--r-- | source/slang/slang-language-server-completion.cpp | 2 | ||||
| -rw-r--r-- | source/slang/slang-lower-to-ir.cpp | 5 | ||||
| -rw-r--r-- | source/slang/slang-parser.cpp | 6 |
16 files changed, 278 insertions, 3 deletions
diff --git a/source/slang/core.meta.slang b/source/slang/core.meta.slang index 616511b01..d912fe8ce 100644 --- a/source/slang/core.meta.slang +++ b/source/slang/core.meta.slang @@ -349,6 +349,12 @@ struct NullPtr { }; +__magic_type(NoneType) +__intrinsic_type($(kIROp_VoidType)) +struct __none_t +{ +}; + __generic<T> __magic_type(PtrType) __intrinsic_type($(kIROp_PtrType)) @@ -472,8 +478,36 @@ struct Optional __intrinsic_op($(kIROp_GetOptionalValue)) get; } + + __implicit_conversion($(kConversionCost_ValToOptional)) + __intrinsic_op($(kIROp_MakeOptionalValue)) + __init(T val); }; +__generic<T> +[__unsafeForceInlineEarly] +bool operator==(Optional<T> val, __none_t noneVal) +{ + return !val.hasValue; +} +__generic<T> +[__unsafeForceInlineEarly] +bool operator!=(Optional<T> val, __none_t noneVal) +{ + return val.hasValue; +} +__generic<T> +[__unsafeForceInlineEarly] +bool operator==(__none_t noneVal, Optional<T> val) +{ + return !val.hasValue; +} +__generic<T> +[__unsafeForceInlineEarly] +bool operator!=(__none_t noneVal, Optional<T> val) +{ + return val.hasValue; +} __magic_type(StringType) __intrinsic_type($(kIROp_StringType)) diff --git a/source/slang/slang-ast-builder.cpp b/source/slang/slang-ast-builder.cpp index 2acdc26d3..fa8051171 100644 --- a/source/slang/slang-ast-builder.cpp +++ b/source/slang/slang-ast-builder.cpp @@ -131,6 +131,16 @@ Type* SharedASTBuilder::getNullPtrType() return m_nullPtrType; } +Type* SharedASTBuilder::getNoneType() +{ + if (!m_noneType) + { + auto noneTypeDecl = findMagicDecl("NoneType"); + m_noneType = DeclRefType::create(m_astBuilder, makeDeclRef<Decl>(noneTypeDecl)); + } + return m_noneType; +} + SharedASTBuilder::~SharedASTBuilder() { // Release built in types.. diff --git a/source/slang/slang-ast-builder.h b/source/slang/slang-ast-builder.h index e62e92a7b..d363cb8f6 100644 --- a/source/slang/slang-ast-builder.h +++ b/source/slang/slang-ast-builder.h @@ -33,6 +33,8 @@ public: Type* getDynamicType(); /// Get the NullPtr type Type* getNullPtrType(); + /// Get the NullPtr type + Type* getNoneType(); const ReflectClassInfo* findClassInfo(Name* name); SyntaxClass<NodeBase> findSyntaxClass(Name* name); @@ -74,6 +76,7 @@ protected: Type* m_enumTypeType = nullptr; Type* m_dynamicType = nullptr; Type* m_nullPtrType = nullptr; + Type* m_noneType = nullptr; Type* m_builtinTypes[Index(BaseType::CountOf)]; @@ -139,6 +142,7 @@ public: Type* getBottomType() { return m_sharedASTBuilder->m_bottomType; } Type* getStringType() { return m_sharedASTBuilder->getStringType(); } Type* getNullPtrType() { return m_sharedASTBuilder->getNullPtrType(); } + Type* getNoneType() { return m_sharedASTBuilder->getNoneType(); } 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 2dfd937a4..6f10f2d82 100644 --- a/source/slang/slang-ast-expr.h +++ b/source/slang/slang-ast-expr.h @@ -101,6 +101,11 @@ class NullPtrLiteralExpr : public LiteralExpr SLANG_AST_CLASS(NullPtrLiteralExpr) }; +class NoneLiteralExpr : public LiteralExpr +{ + SLANG_AST_CLASS(NoneLiteralExpr) +}; + class StringLiteralExpr : public LiteralExpr { SLANG_AST_CLASS(StringLiteralExpr) diff --git a/source/slang/slang-ast-iterator.h b/source/slang/slang-ast-iterator.h index 8461ff7a3..233ce9a17 100644 --- a/source/slang/slang-ast-iterator.h +++ b/source/slang/slang-ast-iterator.h @@ -46,6 +46,10 @@ struct ASTIterator { iterator->maybeDispatchCallback(expr); } + void visitNoneLiteralExpr(NoneLiteralExpr* expr) + { + iterator->maybeDispatchCallback(expr); + } void visitIntegerLiteralExpr(IntegerLiteralExpr* expr) { iterator->maybeDispatchCallback(expr); diff --git a/source/slang/slang-ast-support-types.h b/source/slang/slang-ast-support-types.h index f74abc08f..00a4a482c 100644 --- a/source/slang/slang-ast-support-types.h +++ b/source/slang/slang-ast-support-types.h @@ -88,6 +88,9 @@ namespace Slang // Conversion that is lossless and keeps the "kind" of the value the same kConversionCost_RankPromotion = 150, + kConversionCost_NoneToOptional = 150, + kConversionCost_ValToOptional = 150, + kConversionCost_NullPtrToPtr = 150, // Conversions that are lossless, but change "kind" kConversionCost_UnsignedToSignedPromotion = 200, diff --git a/source/slang/slang-ast-type.h b/source/slang/slang-ast-type.h index 7b94cbe6d..0ee0fce2c 100644 --- a/source/slang/slang-ast-type.h +++ b/source/slang/slang-ast-type.h @@ -529,6 +529,11 @@ class PtrTypeBase : public BuiltinType Type* getValueType(); }; +class NoneType : public BuiltinType +{ + SLANG_AST_CLASS(NoneType) +}; + class NullPtrType : public BuiltinType { SLANG_AST_CLASS(NullPtrType) diff --git a/source/slang/slang-check-conversion.cpp b/source/slang/slang-check-conversion.cpp index 6290acbd9..4bcf07b2b 100644 --- a/source/slang/slang-check-conversion.cpp +++ b/source/slang/slang-check-conversion.cpp @@ -773,13 +773,28 @@ namespace Slang { if (outCost) { - *outCost = kConversionCost_None; + *outCost = kConversionCost_NullPtrToPtr; } if (outToExpr) *outToExpr = fromExpr; return true; } - + // none_t can be cast into any Optional<T> type. + if (as<NoneType>(fromType) && as<OptionalType>(toType)) + { + if (outCost) + { + *outCost = kConversionCost_NoneToOptional; + } + if (outToExpr) + { + auto resultExpr = getASTBuilder()->create<MakeOptionalExpr>(); + resultExpr->loc = fromExpr->loc; + resultExpr->type = toType; + *outToExpr = resultExpr; + } + 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 714eba9a3..cb75e3078 100644 --- a/source/slang/slang-check-expr.cpp +++ b/source/slang/slang-check-expr.cpp @@ -822,6 +822,12 @@ namespace Slang return expr; } + Expr* SemanticsExprVisitor::visitNoneLiteralExpr(NoneLiteralExpr* expr) + { + expr->type = m_astBuilder->getNoneType(); + 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 df713d80f..345652263 100644 --- a/source/slang/slang-check-impl.h +++ b/source/slang/slang-check-impl.h @@ -1697,6 +1697,7 @@ namespace Slang Expr* visitIncompleteExpr(IncompleteExpr* expr); Expr* visitBoolLiteralExpr(BoolLiteralExpr* expr); Expr* visitNullPtrLiteralExpr(NullPtrLiteralExpr* expr); + Expr* visitNoneLiteralExpr(NoneLiteralExpr* expr); Expr* visitIntegerLiteralExpr(IntegerLiteralExpr* expr); Expr* visitFloatingPointLiteralExpr(FloatingPointLiteralExpr* expr); Expr* visitStringLiteralExpr(StringLiteralExpr* expr); diff --git a/source/slang/slang-emit.cpp b/source/slang/slang-emit.cpp index da8739a49..f3e78e48f 100644 --- a/source/slang/slang-emit.cpp +++ b/source/slang/slang-emit.cpp @@ -8,6 +8,7 @@ #include "slang-ir-bind-existentials.h" #include "slang-ir-byte-address-legalize.h" #include "slang-ir-collect-global-uniforms.h" +#include "slang-ir-cleanup-void.h" #include "slang-ir-dce.h" #include "slang-ir-dll-export.h" #include "slang-ir-dll-import.h" @@ -745,6 +746,8 @@ Result linkAndOptimizeIR( #endif validateIRModuleIfEnabled(codeGenContext, irModule); + cleanUpVoidType(irModule); + // Lower all bit_cast operations on complex types into leaf-level // bit_cast on basic types. lowerBitCast(targetRequest, irModule); diff --git a/source/slang/slang-ir-cleanup-void.cpp b/source/slang/slang-ir-cleanup-void.cpp new file mode 100644 index 000000000..ac520c1d5 --- /dev/null +++ b/source/slang/slang-ir-cleanup-void.cpp @@ -0,0 +1,159 @@ +// slang-ir-cleanup-void.cpp + +#include "slang-ir-cleanup-void.h" +#include "slang-ir.h" +#include "slang-ir-insts.h" + +namespace Slang +{ + struct CleanUpVoidContext + { + IRModule* module; + + SharedIRBuilder sharedBuilderStorage; + + List<IRInst*> workList; + HashSet<IRInst*> workListSet; + + void addToWorkList( + IRInst* inst) + { + for (auto ii = inst->getParent(); ii; ii = ii->getParent()) + { + if (as<IRGeneric>(ii)) + return; + } + + if (workListSet.Contains(inst)) + return; + + workList.add(inst); + workListSet.Add(inst); + } + + void processInst(IRInst* inst) + { + switch (inst->getOp()) + { + case kIROp_Call: + { + // Remove void argument. + auto call = as<IRCall>(inst); + List<IRInst*> newArgs; + for (UInt i = 0; i < call->getArgCount(); i++) + { + auto arg = call->getArg(i); + if (arg->getDataType() && arg->getDataType()->getOp() == kIROp_VoidType) + { + continue; + } + newArgs.add(arg); + } + if (newArgs.getCount() != (Index)call->getArgCount()) + { + IRBuilder builder(&sharedBuilderStorage); + builder.setInsertBefore(call); + auto newCall = builder.emitCallInst(call->getFullType(), call->getCallee(), newArgs); + call->replaceUsesWith(newCall); + call->removeAndDeallocate(); + inst = newCall; + } + } + break; + case kIROp_Func: + { + // Remove void parameter. + List<IRParam*> paramsToRemove; + auto func = as<IRFunc>(inst); + for (auto param : func->getParams()) + { + if (param->getDataType()->getOp() == kIROp_VoidType) + { + paramsToRemove.add(param); + } + } + IRBuilder builder(&sharedBuilderStorage); + builder.setInsertBefore(func); + for (auto param : paramsToRemove) + { + auto voidVal = builder.getVoidValue(); + param->replaceUsesWith(voidVal); + param->removeAndDeallocate(); + } + } + break; + case kIROp_FuncType: + { + auto funcType = as<IRFuncType>(inst); + List<IRInst*> newOperands; + for (UInt i = 1; i < funcType->getOperandCount(); i++) + { + auto operand = funcType->getOperand(i); + if (operand->getOp() == kIROp_VoidType) + { + continue; + } + newOperands.add(operand); + } + if (newOperands.getCount() != (Index)funcType->getParamCount()) + { + IRBuilder builder(&sharedBuilderStorage); + builder.setInsertBefore(funcType); + auto newFuncType = builder.getFuncType(newOperands.getCount(), (IRType**)newOperands.getBuffer(), funcType->getResultType()); + if (newFuncType != funcType) + { + funcType->replaceUsesWith(newFuncType); + funcType->removeAndDeallocate(); + } + inst = newFuncType; + } + } + break; + case kIROp_StructType: + { + // TODO: cleanup void fields. + } + break; + default: + break; + } + + // TODO: If inst has void type, all uses of it should be replaced with void val. + // We should do this only for a subset of opcodes known to be safe. + + } + + void processModule() + { + SharedIRBuilder* sharedBuilder = &sharedBuilderStorage; + sharedBuilder->init(module); + + // Deduplicate equivalent types. + sharedBuilder->deduplicateAndRebuildGlobalNumberingMap(); + + addToWorkList(module->getModuleInst()); + + while (workList.getCount() != 0) + { + IRInst* inst = workList.getLast(); + + workList.removeLast(); + workListSet.Remove(inst); + + processInst(inst); + + for (auto child = inst->getLastChild(); child; child = child->getPrevInst()) + { + addToWorkList(child); + } + } + } + }; + + void cleanUpVoidType(IRModule* module) + { + CleanUpVoidContext context; + context.module = module; + context.processModule(); + } +} diff --git a/source/slang/slang-ir-cleanup-void.h b/source/slang/slang-ir-cleanup-void.h new file mode 100644 index 000000000..b6c6fc5f7 --- /dev/null +++ b/source/slang/slang-ir-cleanup-void.h @@ -0,0 +1,15 @@ +// slang-ir-cleanup-void.h +#pragma once + +#include "slang-ir.h" + +namespace Slang +{ + struct IRModule; + class DiagnosticSink; + + /// Cleanup all uses of void and void types. + void cleanUpVoidType( + IRModule* module); + +} diff --git a/source/slang/slang-language-server-completion.cpp b/source/slang/slang-language-server-completion.cpp index 4ae5bcb37..ac3cdefc0 100644 --- a/source/slang/slang-language-server-completion.cpp +++ b/source/slang/slang-language-server-completion.cpp @@ -31,7 +31,7 @@ static const char* kStmtKeywords[] = { "extension", "associatedtype", "this", "namespace", "This", "using", "__generic", "__exported", "import", "enum", "break", "continue", "discard", "defer", "cbuffer", "tbuffer", "func", "is", - "as", "nullptr", "true", "false"}; + "as", "nullptr", "none", "true", "false"}; static const char* hlslSemanticNames[] = { "register", diff --git a/source/slang/slang-lower-to-ir.cpp b/source/slang/slang-lower-to-ir.cpp index aef60c9d9..c7fbfda77 100644 --- a/source/slang/slang-lower-to-ir.cpp +++ b/source/slang/slang-lower-to-ir.cpp @@ -3365,6 +3365,11 @@ struct ExprLoweringVisitorBase : ExprVisitor<Derived, LoweredValInfo> return LoweredValInfo::simple(context->irBuilder->getPtrValue(nullptr)); } + LoweredValInfo visitNoneLiteralExpr(NoneLiteralExpr*) + { + return LoweredValInfo::simple(context->irBuilder->getVoidValue()); + } + 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 4baa7211e..7447859c7 100644 --- a/source/slang/slang-parser.cpp +++ b/source/slang/slang-parser.cpp @@ -5031,6 +5031,11 @@ namespace Slang return parser->astBuilder->create<NullPtrLiteralExpr>(); } + static NodeBase* parseNoneExpr(Parser* parser, void* /*userData*/) + { + return parser->astBuilder->create<NoneLiteralExpr>(); + } + static NodeBase* parseTryExpr(Parser* parser, void* /*userData*/) { auto tryExpr = parser->astBuilder->create<TryExpr>(); @@ -6587,6 +6592,7 @@ namespace Slang _makeParseExpr("true", parseTrueExpr), _makeParseExpr("false", parseFalseExpr), _makeParseExpr("nullptr", parseNullPtrExpr), + _makeParseExpr("none", parseNoneExpr), _makeParseExpr("try", parseTryExpr), _makeParseExpr("__TaggedUnion", parseTaggedUnionType), _makeParseExpr("__jvp", parseJVPDifferentiate) |
