diff options
Diffstat (limited to 'source')
| -rw-r--r-- | source/slang/check.cpp | 629 | ||||
| -rw-r--r-- | source/slang/compiler.h | 4 | ||||
| -rw-r--r-- | source/slang/diagnostic-defs.h | 8 | ||||
| -rw-r--r-- | source/slang/diagnostics.cpp | 5 | ||||
| -rw-r--r-- | source/slang/diagnostics.h | 4 | ||||
| -rw-r--r-- | source/slang/emit.cpp | 2 | ||||
| -rw-r--r-- | source/slang/ir-constexpr.cpp | 2 | ||||
| -rw-r--r-- | source/slang/ir-inst-defs.h | 2 | ||||
| -rw-r--r-- | source/slang/ir-insts.h | 5 | ||||
| -rw-r--r-- | source/slang/ir.cpp | 10 | ||||
| -rw-r--r-- | source/slang/lower-to-ir.cpp | 208 | ||||
| -rw-r--r-- | source/slang/syntax.cpp | 30 | ||||
| -rw-r--r-- | source/slang/type-defs.h | 4 |
13 files changed, 676 insertions, 237 deletions
diff --git a/source/slang/check.cpp b/source/slang/check.cpp index 04c41c4b0..2fa4e9bc7 100644 --- a/source/slang/check.cpp +++ b/source/slang/check.cpp @@ -1319,48 +1319,228 @@ namespace Slang return kConversionCost_Explicit; } - // Central engine for implementing implicit coercion logic - bool TryCoerceImpl( - RefPtr<Type> toType, // the target type for conversion - RefPtr<Expr>* outToExpr, // (optional) a place to stuff the target expression - RefPtr<Type> fromType, // the source type for the conversion - RefPtr<Expr> fromExpr, // the source expression - ConversionCost* outCost) // (optional) a place to stuff the conversion cost + bool isEffectivelyScalarForInitializerLists( + RefPtr<Type> type) { - // Easy case: the types are equal - if (toType->Equals(fromType)) + if(type->As<ArrayExpressionType>()) return false; + if(type->As<VectorExpressionType>()) return false; + if(type->As<MatrixExpressionType>()) return false; + + if(type->As<BasicExpressionType>()) { - if (outToExpr) - *outToExpr = fromExpr; - if (outCost) - *outCost = kConversionCost_None; return true; } - // If either type is an error, then let things pass. - if (toType->As<ErrorType>() || fromType->As<ErrorType>()) + if(type->As<ResourceType>()) + { + return true; + } + if(type->As<UntypedBufferResourceType>()) + { + return true; + } + if(type->As<SamplerStateType>()) { - if (outToExpr) - *outToExpr = CreateImplicitCastExpr(toType, fromExpr); - if (outCost) - *outCost = kConversionCost_None; return true; } - // Coercion from an initializer list is allowed for many types - if( auto fromInitializerListExpr = fromExpr.As<InitializerListExpr>()) + if(auto declRefType = type->As<DeclRefType>()) { - auto argCount = fromInitializerListExpr->args.Count(); + if(declRefType->declRef.As<StructDecl>()) + return false; + } - // In the case where we need to build a reuslt expression, - // we will collect the new arguments here - List<RefPtr<Expr>> coercedArgs; + return true; + } + + /// Should the provided expression (from an initializer list) be used directly to initialize `toType`? + bool shouldUseInitializerDirectly( + RefPtr<Type> toType, + RefPtr<Expr> fromExpr) + { + // A nested initializer list should always be used directly. + // + if(fromExpr.As<InitializerListExpr>()) + { + return true; + } + + // If the desired type is a scalar, then we should always initialize + // directly, since it isn't an aggregate. + // + if(isEffectivelyScalarForInitializerLists(toType)) + return true; + + // If the type we are initializing isn't effectively scalar, + // but the initialization expression *is*, then it doesn't + // seem like direct initialization is intended. + // + if(isEffectivelyScalarForInitializerLists(fromExpr->type)) + return false; + + // Once the above cases are handled, the main thing + // we want to check for is whether a direct initialization + // is possible (a type conversion exists). + // + return CanCoerce(toType, fromExpr->type); + } + + bool tryReadArgFromInitializerList( + RefPtr<Type> toType, + RefPtr<Expr>* outToExpr, + RefPtr<InitializerListExpr> fromInitializerListExpr, + UInt &ioInitArgIndex) + { + // First, we will check if we have run out of arguments + // on the initializer list. + // + UInt initArgCount = fromInitializerListExpr->args.Count(); + if(ioInitArgIndex >= initArgCount) + { + // If we are at the end of the initializer list, + // then our ability to read an argument depends + // on whether the type we are trying to read + // is default-initializable. + // + // For now, we will just pretend like everything + // is default-initializable and move along. + return true; + } + + // Okay, we have at least one initializer list expression, + // so we will look at the next expression and decide + // whether to use it to initialize the desired type + // directly (possibly via casts), or as the first sub-expression + // for aggregate initialization. + // + auto firstInitExpr = fromInitializerListExpr->args[ioInitArgIndex]; + if(shouldUseInitializerDirectly(toType, firstInitExpr)) + { + ioInitArgIndex++; + return TryCoerceImpl( + toType, + outToExpr, + firstInitExpr->type, + firstInitExpr, + nullptr); + } + + // If there is somehow an error in one of the initialization + // expressions, then everything could be thrown off and we + // shouldn't keep trying to read arguments. + // + if( IsErrorExpr(firstInitExpr) ) + { + // Stop reading arguments, as if we'd reached + // the end of the list. + // + ioInitArgIndex = initArgCount; + return true; + } + + // The fallback case is to recursively read the + // type from the same list as an aggregate. + // + return tryReadAggregateFromInitializerList( + toType, + outToExpr, + fromInitializerListExpr, + ioInitArgIndex); + } + + bool tryReadAggregateFromInitializerList( + RefPtr<Type> inToType, + RefPtr<Expr>* outToExpr, + RefPtr<InitializerListExpr> fromInitializerListExpr, + UInt &ioArgIndex) + { + auto toType = inToType; + UInt argCount = fromInitializerListExpr->args.Count(); - if (auto toVecType = toType->As<VectorExpressionType>()) + // In the case where we need to build a reuslt expression, + // we will collect the new arguments here + List<RefPtr<Expr>> coercedArgs; + + if(isEffectivelyScalarForInitializerLists(toType)) + { + // For any type that is effectively a non-aggregate, + // we expect to read a single value from the initializer list + // + if(ioArgIndex < argCount) + { + auto arg = fromInitializerListExpr->args[ioArgIndex++]; + return TryCoerceImpl( + toType, + outToExpr, + arg->type, + arg, + nullptr); + } + else + { + // If there wasn't an initialization + // expression to be found, then we need + // to perform default initialization here. + // + // We will let this case come through the front-end + // as an `InitializerListExpr` with zero arguments, + // and then have the IR generation logic deal with + // synthesizing default values. + } + } + else if (auto toVecType = toType->As<VectorExpressionType>()) + { + auto toElementCount = toVecType->elementCount; + auto toElementType = toVecType->elementType; + + UInt elementCount = 0; + if (auto constElementCount = toElementCount.As<ConstantIntVal>()) + { + elementCount = (UInt) constElementCount->value; + } + else + { + // We don't know the element count statically, + // so what are we supposed to be doing? + // + if(outToExpr) + { + getSink()->diagnose(fromInitializerListExpr, Diagnostics::cannotUseInitializerListForVectorOfUnknownSize, toElementCount); + } + return false; + } + + for(UInt ee = 0; ee < elementCount; ++ee) { - auto toElementCount = toVecType->elementCount; - auto toElementType = toVecType->elementType; + RefPtr<Expr> coercedArg; + bool argResult = tryReadArgFromInitializerList( + toElementType, + outToExpr ? &coercedArg : nullptr, + fromInitializerListExpr, + ioArgIndex); + + // No point in trying further if any argument fails + if(!argResult) + return false; + + if( coercedArg ) + { + coercedArgs.Add(coercedArg); + } + } + } + else if(auto toArrayType = toType->As<ArrayExpressionType>()) + { + // TODO(tfoley): If we can compute the size of the array statically, + // then we want to check that there aren't too many initializers present + + auto toElementType = toArrayType->baseType; + if(auto toElementCount = toArrayType->ArrayLength) + { + // In the case of a sized array, we need to check that the number + // of elements being initialized matches what was declared. + // UInt elementCount = 0; if (auto constElementCount = toElementCount.As<ConstantIntVal>()) { @@ -1370,127 +1550,234 @@ namespace Slang { // We don't know the element count statically, // so what are we supposed to be doing? - elementCount = fromInitializerListExpr->args.Count(); + // + if(outToExpr) + { + getSink()->diagnose(fromInitializerListExpr, Diagnostics::cannotUseInitializerListForArrayOfUnknownSize, toElementCount); + } + return false; } - // TODO: need to check that the element count - // for the vector type matches the argument - // count for the initializer list, or else - // fix them up to match. - - for(auto arg : fromInitializerListExpr->args) + for(UInt ee = 0; ee < elementCount; ++ee) { RefPtr<Expr> coercedArg; - ConversionCost argCost; - - bool argResult = TryCoerceImpl( + bool argResult = tryReadArgFromInitializerList( toElementType, outToExpr ? &coercedArg : nullptr, - arg->type, - arg, - outCost ? &argCost : nullptr); + fromInitializerListExpr, + ioArgIndex); // No point in trying further if any argument fails if(!argResult) return false; - // TODO(tfoley): what to do with cost? - // This only matters if/when we allow an initializer list as an argument to - // an overloaded call. - - if( outToExpr ) + if( coercedArg ) { coercedArgs.Add(coercedArg); } } } - // - // TODO(tfoley): How to handle matrices here? - // Should they expect individual scalars, or support - // vectors for the rows? - // - if(auto toDeclRefType = toType->As<DeclRefType>()) + else { - auto toTypeDeclRef = toDeclRefType->declRef; - if(auto toStructDeclRef = toTypeDeclRef.As<StructDecl>()) + // In the case of an unsized array type, we will use the + // number of arguments to the initializer to determine + // the element count. + // + UInt elementCount = 0; + while(ioArgIndex < argCount) { - // Trying to initialize a `struct` type given an initializer list. - // We will go through the fields in order and try to match them - // up with initializer arguments. - + RefPtr<Expr> coercedArg; + bool argResult = tryReadArgFromInitializerList( + toElementType, + outToExpr ? &coercedArg : nullptr, + fromInitializerListExpr, + ioArgIndex); - UInt argIndex = 0; - for(auto fieldDeclRef : getMembersOfType<StructField>(toStructDeclRef)) - { - if(argIndex >= argCount) - { - // We've consumed all the arguments, so we should stop - break; - } + // No point in trying further if any argument fails + if(!argResult) + return false; - auto arg = fromInitializerListExpr->args[argIndex++]; + elementCount++; - // - RefPtr<Expr> coercedArg; - ConversionCost argCost; + if( coercedArg ) + { + coercedArgs.Add(coercedArg); + } + } - bool argResult = TryCoerceImpl( - GetType(fieldDeclRef), - outToExpr ? &coercedArg : nullptr, - arg->type, - arg, - outCost ? &argCost : nullptr); + // We have a new type for the conversion, based on what + // we learned. + toType = getSession()->getArrayType( + toElementType, + new ConstantIntVal(elementCount)); + } + } + else if(auto toMatrixType = toType->As<MatrixExpressionType>()) + { + // In the general case, the initializer list might comprise + // both vectors and scalars. + // + // The traditional HLSL compilers treat any vectors in + // the initializer list exactly equivalent to their sequence + // of scalar elements, and don't care how this might, or + // might not, align with the rows of the matrix. + // + // We will draw a line in the sand and say that an initializer + // list for a matrix will act as if the matrix type were an + // array of vectors for the rows. - // No point in trying further if any argument fails - if(!argResult) - return false; - // TODO(tfoley): what to do with cost? - // This only matters if/when we allow an initializer list as an argument to - // an overloaded call. + UInt rowCount = 0; + auto toRowType = createVectorType( + toMatrixType->getElementType(), + toMatrixType->getColumnCount()); - if( outToExpr ) - { - coercedArgs.Add(coercedArg); - } - } + if (auto constRowCount = dynamic_cast<ConstantIntVal*>(toMatrixType->getRowCount())) + { + rowCount = (UInt) constRowCount->value; + } + else + { + // We don't know the element count statically, + // so what are we supposed to be doing? + // + if(outToExpr) + { + getSink()->diagnose(fromInitializerListExpr, Diagnostics::cannotUseInitializerListForMatrixOfUnknownSize, toMatrixType->getRowCount()); } + return false; } - else if(auto toArrayType = toType->As<ArrayExpressionType>()) + + for(UInt rr = 0; rr < rowCount; ++rr) { - // TODO(tfoley): If we can compute the size of the array statically, - // then we want to check that there aren't too many initializers present + RefPtr<Expr> coercedArg; + bool argResult = tryReadArgFromInitializerList( + toRowType, + outToExpr ? &coercedArg : nullptr, + fromInitializerListExpr, + ioArgIndex); - auto toElementType = toArrayType->baseType; + // No point in trying further if any argument fails + if(!argResult) + return false; - for(auto& arg : fromInitializerListExpr->args) + if( coercedArg ) + { + coercedArgs.Add(coercedArg); + } + } + } + else if(auto toDeclRefType = toType->As<DeclRefType>()) + { + auto toTypeDeclRef = toDeclRefType->declRef; + if(auto toStructDeclRef = toTypeDeclRef.As<StructDecl>()) + { + // Trying to initialize a `struct` type given an initializer list. + // We will go through the fields in order and try to match them + // up with initializer arguments. + // + for(auto fieldDeclRef : getMembersOfType<StructField>(toStructDeclRef)) { RefPtr<Expr> coercedArg; - ConversionCost argCost; - - bool argResult = TryCoerceImpl( - toElementType, - outToExpr ? &coercedArg : nullptr, - arg->type, - arg, - outCost ? &argCost : nullptr); + bool argResult = tryReadArgFromInitializerList( + GetType(fieldDeclRef), + outToExpr ? &coercedArg : nullptr, + fromInitializerListExpr, + ioArgIndex); // No point in trying further if any argument fails if(!argResult) return false; - if( outToExpr ) + if( coercedArg ) { coercedArgs.Add(coercedArg); } } } - else - { - // By default, we don't allow a type to be initialized using - // an initializer list. + } + else + { + // We shouldn't get to this case in practice, + // but just in case we'll consider an initializer + // list invalid if we are trying to read something + // off of it that wasn't handled by the cases above. + // + return false; + } + + // We were able to coerce all the arguments given, and so + // we need to construct a suitable expression to remember the result + // + if(outToExpr) + { + auto toInitializerListExpr = new InitializerListExpr(); + toInitializerListExpr->loc = fromInitializerListExpr->loc; + toInitializerListExpr->type = QualType(toType); + toInitializerListExpr->args = coercedArgs; + + *outToExpr = toInitializerListExpr; + } + + return true; + } + + bool tryCoerceInitializerList( + RefPtr<Type> toType, + RefPtr<Expr>* outToExpr, + RefPtr<InitializerListExpr> fromInitializerListExpr) + { + UInt argCount = fromInitializerListExpr->args.Count(); + UInt argIndex = 0; + + // TODO: we should handle the special case of `{0}` as an initializer + // for arbitrary `struct` types here. + + if(!tryReadAggregateFromInitializerList(toType, outToExpr, fromInitializerListExpr, argIndex)) + return false; + + if(argIndex != argCount) + { + getSink()->diagnose(fromInitializerListExpr, Diagnostics::tooManyInitializers, argIndex, argCount); + } + + return true; + } + + + // Central engine for implementing implicit coercion logic + bool TryCoerceImpl( + RefPtr<Type> toType, // the target type for conversion + RefPtr<Expr>* outToExpr, // (optional) a place to stuff the target expression + RefPtr<Type> fromType, // the source type for the conversion + RefPtr<Expr> fromExpr, // the source expression + ConversionCost* outCost) // (optional) a place to stuff the conversion cost + { + // Easy case: the types are equal + if (toType->Equals(fromType)) + { + if (outToExpr) + *outToExpr = fromExpr; + if (outCost) + *outCost = kConversionCost_None; + return true; + } + + // If either type is an error, then let things pass. + if (toType->As<ErrorType>() || fromType->As<ErrorType>()) + { + if (outToExpr) + *outToExpr = CreateImplicitCastExpr(toType, fromExpr); + if (outCost) + *outCost = kConversionCost_None; + return true; + } + + // Coercion from an initializer list is allowed for many types + if( auto fromInitializerListExpr = fromExpr.As<InitializerListExpr>()) + { + if(!tryCoerceInitializerList(toType, outToExpr, fromInitializerListExpr)) return false; - } // For now, coercion from an initializer list has no cost if(outCost) @@ -1498,19 +1785,6 @@ namespace Slang *outCost = kConversionCost_None; } - // We were able to coerce all the arguments given, and so - // we need to construct a suitable expression to remember the result - if(outToExpr) - { - auto toInitializerListExpr = new InitializerListExpr(); - toInitializerListExpr->loc = fromInitializerListExpr->loc; - toInitializerListExpr->type = QualType(toType); - toInitializerListExpr->args = coercedArgs; - - - *outToExpr = toInitializerListExpr; - } - return true; } @@ -1859,42 +2133,41 @@ namespace Slang void CheckVarDeclCommon(RefPtr<VarDeclBase> varDecl) { - // Check the type, if one was given - TypeExp type = CheckUsableType(varDecl->type); - - // TODO: Additional validation rules on types should go here, - // but we need to deal with the fact that some cases might be - // allowed in one context (e.g., an unsized array parameter) - // but not in othters (e.g., an unsized array field in a struct). - - // Check the initializers, if one was given - RefPtr<Expr> initExpr = CheckTerm(varDecl->initExpr); - - // If a type was given, ... - if (type.Ptr()) + if (function || checkingPhase == CheckingPhase::Header) { - // then coerce any initializer to the type - if (initExpr) + TypeExp typeExp = CheckUsableType(varDecl->type); + varDecl->type = typeExp; + if (varDecl->type.Equals(getSession()->getVoidType())) { - initExpr = Coerce(type.Ptr(), initExpr); + getSink()->diagnose(varDecl, Diagnostics::invalidTypeVoid); } } - else - { - // TODO: infer a type from the initializers - if (!initExpr) - { - getSink()->diagnose(varDecl, Diagnostics::unimplemented, "variable declaration with no type must have initializer"); - } - else + if (checkingPhase == CheckingPhase::Body) + { + if (auto initExpr = varDecl->initExpr) { - getSink()->diagnose(varDecl, Diagnostics::unimplemented, "type inference for variable declaration"); + initExpr = CheckTerm(initExpr); + initExpr = Coerce(varDecl->type.Ptr(), initExpr); + varDecl->initExpr = initExpr; + + // If this is an array variable, then we first want to give + // it a chance to infer an array size from its initializer + // + // TODO(tfoley): May need to extend this to handle the + // multi-dimensional case... + // + maybeInferArraySizeForVariable(varDecl); + // + // Next we want to make sure that the declared (or inferred) + // size for the array meets whatever language-specific + // constraints we want to enforce (e.g., disallow empty + // arrays in specific cases) + // + validateArraySizeForVariable(varDecl); } } - - varDecl->type = type; - varDecl->initExpr = initExpr; + varDecl->SetCheckState(getCheckedState()); } // Fill in default substitutions for the 'subtype' part of a type constraint decl @@ -2535,12 +2808,7 @@ namespace Slang void visitStructField(StructField* field) { - if (field->IsChecked(DeclCheckState::CheckedHeader)) - return; - // TODO: bottleneck through general-case variable checking - - field->type = CheckUsableType(field->type); - field->SetCheckState(getCheckedState()); + CheckVarDeclCommon(field); } bool doesSignatureMatchRequirement( @@ -4295,7 +4563,7 @@ namespace Slang return 1; } - void maybeInferArraySizeForVariable(Variable* varDecl) + void maybeInferArraySizeForVariable(VarDeclBase* varDecl) { // Not an array? auto arrayType = varDecl->type->AsArrayType(); @@ -4309,14 +4577,8 @@ namespace Slang auto initExpr = varDecl->initExpr; if(!initExpr) return; - // Is the initializer an initializer list? - if(auto initializerListExpr = initExpr.As<InitializerListExpr>()) - { - auto argCount = initializerListExpr->args.Count(); - elementCount = new ConstantIntVal(argCount); - } // Is the type of the initializer an array type? - else if(auto arrayInitType = initExpr->type->As<ArrayExpressionType>()) + if(auto arrayInitType = initExpr->type->As<ArrayExpressionType>()) { elementCount = arrayInitType->ArrayLength; } @@ -4333,7 +4595,7 @@ namespace Slang elementCount); } - void ValidateArraySizeForVariable(Variable* varDecl) + void validateArraySizeForVariable(VarDeclBase* varDecl) { auto arrayType = varDecl->type->AsArrayType(); if (!arrayType) return; @@ -4360,48 +4622,7 @@ namespace Slang void visitVariable(Variable* varDecl) { - if (function || checkingPhase == CheckingPhase::Header) - { - TypeExp typeExp = CheckUsableType(varDecl->type); - varDecl->type = typeExp; - if (varDecl->type.Equals(getSession()->getVoidType())) - { - getSink()->diagnose(varDecl, Diagnostics::invalidTypeVoid); - } - } - - if (checkingPhase == CheckingPhase::Body) - { - if (auto initExpr = varDecl->initExpr) - { - initExpr = CheckTerm(initExpr); - varDecl->initExpr = initExpr; - } - - // If this is an array variable, then we first want to give - // it a chance to infer an array size from its initializer - // - // TODO(tfoley): May need to extend this to handle the - // multi-dimensional case... - maybeInferArraySizeForVariable(varDecl); - // - // Next we want to make sure that the declared (or inferred) - // size for the array meets whatever language-specific - // constraints we want to enforce (e.g., disallow empty - // arrays in specific cases) - ValidateArraySizeForVariable(varDecl); - - - if (auto initExpr = varDecl->initExpr) - { - // TODO(tfoley): should coercion of initializer lists be special-cased - // here, or handled as a general case for coercion? - - initExpr = Coerce(varDecl->type.Ptr(), initExpr); - varDecl->initExpr = initExpr; - } - } - varDecl->SetCheckState(getCheckedState()); + CheckVarDeclCommon(varDecl); } void visitWhileStmt(WhileStmt *stmt) diff --git a/source/slang/compiler.h b/source/slang/compiler.h index 1cfb9201d..d2072387e 100644 --- a/source/slang/compiler.h +++ b/source/slang/compiler.h @@ -655,6 +655,10 @@ namespace Slang Type* elementType, IntVal* elementCount); + RefPtr<VectorExpressionType> getVectorType( + RefPtr<Type> elementType, + RefPtr<IntVal> elementCount); + SyntaxClass<RefObject> findSyntaxClass(Name* name); Dictionary<Name*, SyntaxClass<RefObject> > mapNameToSyntaxClass; diff --git a/source/slang/diagnostic-defs.h b/source/slang/diagnostic-defs.h index 96c1366cd..76e59efa3 100644 --- a/source/slang/diagnostic-defs.h +++ b/source/slang/diagnostic-defs.h @@ -283,6 +283,14 @@ DIAGNOSTIC(39999, Fatal, localVariableUsedBeforeDeclared, "local variable '$0' i // 304xx: generics DIAGNOSTIC(30400, Error, genericTypeNeedsArgs, "generic type '$0' used without argument") +// 305xx: initializer lists +DIAGNOSTIC(30500, Error, tooManyInitializers, "too many initializers (expected $0, got $1)"); +DIAGNOSTIC(30501, Error, cannotUseInitializerListForArrayOfUnknownSize, "cannot use initializer list for array of statically unknown size '$0'"); +DIAGNOSTIC(30502, Error, cannotUseInitializerListForVectorOfUnknownSize, "cannot use initializer list for vector of statically unknown size '$0'"); +DIAGNOSTIC(30503, Error, cannotUseInitializerListForMatrixOfUnknownSize, "cannot use initializer list for matrix of statically unknown size '$0' rows"); + + + DIAGNOSTIC(39999, Error, expectedIntegerConstantWrongType, "expected integer constant (found: '$0')") DIAGNOSTIC(39999, Error, expectedIntegerConstantNotConstant, "expression does not evaluate to a compile-time constant") DIAGNOSTIC(39999, Error, expectedIntegerConstantNotLiteral, "could not extract value from integer constant") diff --git a/source/slang/diagnostics.cpp b/source/slang/diagnostics.cpp index 4cad7ce94..9a88c041d 100644 --- a/source/slang/diagnostics.cpp +++ b/source/slang/diagnostics.cpp @@ -61,6 +61,11 @@ void printDiagnosticArg(StringBuilder& sb, Type* type) sb << type->ToString(); } +void printDiagnosticArg(StringBuilder& sb, Val* val) +{ + sb << val->ToString(); +} + void printDiagnosticArg(StringBuilder& sb, TypeExp const& type) { sb << type.type->ToString(); diff --git a/source/slang/diagnostics.h b/source/slang/diagnostics.h index 4c66ba51e..8e5bbcb64 100644 --- a/source/slang/diagnostics.h +++ b/source/slang/diagnostics.h @@ -69,9 +69,10 @@ namespace Slang class Name; class Decl; + struct QualType; class Type; struct TypeExp; - struct QualType; + class Val; enum class CodeGenTarget; enum class Stage : SlangStage; @@ -92,6 +93,7 @@ namespace Slang void printDiagnosticArg(StringBuilder& sb, CodeGenTarget val); void printDiagnosticArg(StringBuilder& sb, Stage val); void printDiagnosticArg(StringBuilder& sb, ProfileVersion val); + void printDiagnosticArg(StringBuilder& sb, Val* val); template<typename T> void printDiagnosticArg(StringBuilder& sb, RefPtr<T> ptr) diff --git a/source/slang/emit.cpp b/source/slang/emit.cpp index 49eaf917b..2e801f0e3 100644 --- a/source/slang/emit.cpp +++ b/source/slang/emit.cpp @@ -3581,7 +3581,7 @@ struct EmitVisitor case kIROp_Construct: case kIROp_makeVector: - case kIROp_makeMatrix: + case kIROp_MakeMatrix: // Simple constructor call if( inst->getOperandCount() == 1 && getTarget(ctx) == CodeGenTarget::HLSL) { diff --git a/source/slang/ir-constexpr.cpp b/source/slang/ir-constexpr.cpp index 684958ffe..163f3d98a 100644 --- a/source/slang/ir-constexpr.cpp +++ b/source/slang/ir-constexpr.cpp @@ -78,7 +78,7 @@ bool opCanBeConstExpr(IROp op) case kIROp_Construct: case kIROp_makeVector: case kIROp_makeArray: - case kIROp_makeMatrix: + case kIROp_MakeMatrix: // TODO: more cases return true; diff --git a/source/slang/ir-inst-defs.h b/source/slang/ir-inst-defs.h index ba1e79b7e..8d7a647f4 100644 --- a/source/slang/ir-inst-defs.h +++ b/source/slang/ir-inst-defs.h @@ -192,7 +192,7 @@ INST(BindGlobalGenericParam, bind_global_generic_param, 2, 0) INST(Construct, construct, 0, 0) INST(makeVector, makeVector, 0, 0) -INST(makeMatrix, makeMatrix, 0, 0) +INST(MakeMatrix, makeMatrix, 0, 0) INST(makeArray, makeArray, 0, 0) INST(makeStruct, makeStruct, 0, 0) diff --git a/source/slang/ir-insts.h b/source/slang/ir-insts.h index cd5407acd..0c56e8244 100644 --- a/source/slang/ir-insts.h +++ b/source/slang/ir-insts.h @@ -816,6 +816,11 @@ struct IRBuilder UInt argCount, IRInst* const* args); + IRInst* emitMakeMatrix( + IRType* type, + UInt argCount, + IRInst* const* args); + IRInst* emitMakeArray( IRType* type, UInt argCount, diff --git a/source/slang/ir.cpp b/source/slang/ir.cpp index 02a6e9f6a..48716bd87 100644 --- a/source/slang/ir.cpp +++ b/source/slang/ir.cpp @@ -1911,6 +1911,14 @@ namespace Slang return emitIntrinsicInst(type, kIROp_makeVector, argCount, args); } + IRInst* IRBuilder::emitMakeMatrix( + IRType* type, + UInt argCount, + IRInst* const* args) + { + return emitIntrinsicInst(type, kIROp_MakeMatrix, argCount, args); + } + IRInst* IRBuilder::emitMakeArray( IRType* type, UInt argCount, @@ -3855,7 +3863,7 @@ namespace Slang case kIROp_lookup_interface_method: case kIROp_Construct: case kIROp_makeVector: - case kIROp_makeMatrix: + case kIROp_MakeMatrix: case kIROp_makeArray: case kIROp_makeStruct: case kIROp_Load: // We are ignoring the possibility of loads from bad addresses, or `volatile` loads diff --git a/source/slang/lower-to-ir.cpp b/source/slang/lower-to-ir.cpp index 388ca884e..b1bc63fa1 100644 --- a/source/slang/lower-to-ir.cpp +++ b/source/slang/lower-to-ir.cpp @@ -1657,6 +1657,127 @@ struct ExprLoweringVisitorBase : ExprVisitor<Derived, LoweredValInfo> return lowerSubExpr(expr->base); } + LoweredValInfo getSimpleDefaultVal(IRType* type) + { + if(auto basicType = as<IRBasicType>(type)) + { + switch( basicType->getBaseType() ) + { + default: + SLANG_UNEXPECTED("missing case for getting IR default value"); + UNREACHABLE_RETURN(LoweredValInfo()); + break; + + case BaseType::Bool: + case BaseType::Int8: + case BaseType::Int16: + case BaseType::Int: + case BaseType::Int64: + case BaseType::UInt8: + case BaseType::UInt16: + case BaseType::UInt: + case BaseType::UInt64: + return LoweredValInfo::simple(getBuilder()->getIntValue(type, 0)); + + case BaseType::Half: + case BaseType::Float: + case BaseType::Double: + return LoweredValInfo::simple(getBuilder()->getFloatValue(type, 0.0)); + } + } + + SLANG_UNEXPECTED("missing case for getting IR default value"); + UNREACHABLE_RETURN(LoweredValInfo()); + } + + LoweredValInfo getDefaultVal(Type* type) + { + auto irType = lowerType(context, type); + if (auto basicType = type->As<BasicExpressionType>()) + { + return getSimpleDefaultVal(irType); + } + else if (auto vectorType = type->As<VectorExpressionType>()) + { + UInt elementCount = (UInt) GetIntVal(vectorType->elementCount); + + auto irDefaultValue = getSimpleVal(context, getDefaultVal(vectorType->elementType)); + + List<IRInst*> args; + for(UInt ee = 0; ee < elementCount; ++ee) + { + args.Add(irDefaultValue); + } + return LoweredValInfo::simple( + getBuilder()->emitMakeVector(irType, args.Count(), args.Buffer())); + } + else if (auto matrixType = type->As<MatrixExpressionType>()) + { + UInt rowCount = (UInt) GetIntVal(matrixType->getRowCount()); + + auto rowType = matrixType->getRowType(); + + auto irDefaultValue = getSimpleVal(context, getDefaultVal(rowType)); + + List<IRInst*> args; + for(UInt rr = 0; rr < rowCount; ++rr) + { + args.Add(irDefaultValue); + } + return LoweredValInfo::simple( + getBuilder()->emitMakeMatrix(irType, args.Count(), args.Buffer())); + } + else if (auto arrayType = type->As<ArrayExpressionType>()) + { + UInt elementCount = (UInt) GetIntVal(arrayType->ArrayLength); + + auto irDefaultElement = getSimpleVal(context, getDefaultVal(arrayType->baseType)); + + List<IRInst*> args; + for(UInt ee = 0; ee < elementCount; ++ee) + { + args.Add(irDefaultElement); + } + + return LoweredValInfo::simple( + getBuilder()->emitMakeArray(irType, args.Count(), args.Buffer())); + } + else if (auto declRefType = type->As<DeclRefType>()) + { + DeclRef<Decl> declRef = declRefType->declRef; + if (auto aggTypeDeclRef = declRef.As<AggTypeDecl>()) + { + List<IRInst*> args; + for (auto ff : getMembersOfType<StructField>(aggTypeDeclRef)) + { + if (ff.getDecl()->HasModifier<HLSLStaticModifier>()) + continue; + + auto irFieldVal = getSimpleVal(context, getDefaultVal(ff)); + args.Add(irFieldVal); + } + + return LoweredValInfo::simple( + getBuilder()->emitMakeStruct(irType, args.Count(), args.Buffer())); + } + } + + SLANG_UNEXPECTED("unexpected type when creating default value"); + UNREACHABLE_RETURN(LoweredValInfo()); + } + + LoweredValInfo getDefaultVal(StructField* decl) + { + if(auto initExpr = decl->initExpr) + { + return lowerRValueExpr(context, initExpr); + } + else + { + return getDefaultVal(decl->type); + } + } + LoweredValInfo visitInitializerListExpr(InitializerListExpr* expr) { // Allocate a temporary of the given type @@ -1666,23 +1787,33 @@ struct ExprLoweringVisitorBase : ExprVisitor<Derived, LoweredValInfo> UInt argCount = expr->args.Count(); + // If the initializer list was empty, then the user was + // asking for default initialization, which should apply + // to (almost) any type. + // + if(argCount == 0) + { + return getDefaultVal(type.type); + } + // Now for each argument in the initializer list, // fill in the appropriate field of the result if (auto arrayType = type->As<ArrayExpressionType>()) { UInt elementCount = (UInt) GetIntVal(arrayType->ArrayLength); - for (UInt ee = 0; ee < elementCount; ++ee) + for (UInt ee = 0; ee < argCount; ++ee) { - if (ee < argCount) - { - auto argExpr = expr->args[ee]; - LoweredValInfo argVal = lowerRValueExpr(context, argExpr); - args.Add(getSimpleVal(context, argVal)); - } - else + auto argExpr = expr->args[ee]; + LoweredValInfo argVal = lowerRValueExpr(context, argExpr); + args.Add(getSimpleVal(context, argVal)); + } + if(elementCount > argCount) + { + auto irDefaultValue = getSimpleVal(context, getDefaultVal(arrayType->baseType)); + for(UInt ee = argCount; ee < elementCount; ++ee) { - SLANG_UNEXPECTED("need to default-initialize array elements"); + args.Add(irDefaultValue); } } @@ -1692,25 +1823,48 @@ struct ExprLoweringVisitorBase : ExprVisitor<Derived, LoweredValInfo> else if (auto vectorType = type->As<VectorExpressionType>()) { UInt elementCount = (UInt) GetIntVal(vectorType->elementCount); - UInt argCounter = 0; - for (UInt ee = 0; ee < elementCount; ++ee) + for (UInt ee = 0; ee < argCount; ++ee) { - UInt argIndex = argCounter++; - if (argIndex < argCount) + auto argExpr = expr->args[ee]; + LoweredValInfo argVal = lowerRValueExpr(context, argExpr); + args.Add(getSimpleVal(context, argVal)); + } + if(elementCount > argCount) + { + auto irDefaultValue = getSimpleVal(context, getDefaultVal(vectorType->elementType)); + for(UInt ee = argCount; ee < elementCount; ++ee) { - auto argExpr = expr->args[argIndex]; - LoweredValInfo argVal = lowerRValueExpr(context, argExpr); - args.Add(getSimpleVal(context, argVal)); + args.Add(irDefaultValue); } - else + } + + return LoweredValInfo::simple( + getBuilder()->emitMakeVector(irType, args.Count(), args.Buffer())); + } + else if (auto matrixType = type->As<MatrixExpressionType>()) + { + UInt rowCount = (UInt) GetIntVal(matrixType->getRowCount()); + + for (UInt rr = 0; rr < argCount; ++rr) + { + auto argExpr = expr->args[rr]; + LoweredValInfo argVal = lowerRValueExpr(context, argExpr); + args.Add(getSimpleVal(context, argVal)); + } + if(rowCount > argCount) + { + auto rowType = matrixType->getRowType(); + auto irDefaultValue = getSimpleVal(context, getDefaultVal(rowType)); + + for(UInt rr = argCount; rr < rowCount; ++rr) { - SLANG_UNEXPECTED("need to default-initialize vector elements"); + args.Add(irDefaultValue); } } return LoweredValInfo::simple( - getBuilder()->emitMakeVector(irType, args.Count(), args.Buffer())); + getBuilder()->emitMakeMatrix(irType, args.Count(), args.Buffer())); } else if (auto declRefType = type->As<DeclRefType>()) { @@ -1732,23 +1886,21 @@ struct ExprLoweringVisitorBase : ExprVisitor<Derived, LoweredValInfo> } else { - SLANG_UNEXPECTED("need to default-initialize struct fields"); + auto irDefaultValue = getSimpleVal(context, getDefaultVal(ff)); + args.Add(irDefaultValue); } } return LoweredValInfo::simple( getBuilder()->emitMakeStruct(irType, args.Count(), args.Buffer())); } - else - { - SLANG_UNEXPECTED("not sure how to initialize this type"); - } - } - else - { - SLANG_UNEXPECTED("not sure how to initialize this type"); } + // If none of the above cases matched, then we had better + // have zero arguments in the initailizer list, in which + // case we are just looking for default initialization. + // + SLANG_UNEXPECTED("unhandled case for initializer list codegen"); UNREACHABLE_RETURN(LoweredValInfo()); } diff --git a/source/slang/syntax.cpp b/source/slang/syntax.cpp index 21b3f92c2..320fc576b 100644 --- a/source/slang/syntax.cpp +++ b/source/slang/syntax.cpp @@ -1241,6 +1241,36 @@ void Type::accept(IValVisitor* visitor, void* extra) return findInnerMostGenericSubstitution(declRef.substitutions)->args[2].As<IntVal>().Ptr(); } + RefPtr<Type> MatrixExpressionType::getRowType() + { + if( !mRowType ) + { + mRowType = getSession()->getVectorType(getElementType(), getColumnCount()); + } + return mRowType; + } + + RefPtr<VectorExpressionType> Session::getVectorType( + RefPtr<Type> elementType, + RefPtr<IntVal> elementCount) + { + auto vectorGenericDecl = findMagicDecl( + this, "Vector").As<GenericDecl>(); + auto vectorTypeDecl = vectorGenericDecl->inner; + + auto substitutions = new GenericSubstitution(); + substitutions->genericDecl = vectorGenericDecl.Ptr(); + substitutions->args.Add(elementType); + substitutions->args.Add(elementCount); + + auto declRef = DeclRef<Decl>(vectorTypeDecl.Ptr(), substitutions); + + return DeclRefType::Create( + this, + declRef)->As<VectorExpressionType>(); + } + + // PtrTypeBase Type* PtrTypeBase::getValueType() diff --git a/source/slang/type-defs.h b/source/slang/type-defs.h index 6e067c990..d9bfecc03 100644 --- a/source/slang/type-defs.h +++ b/source/slang/type-defs.h @@ -314,11 +314,15 @@ RAW( IntVal* getRowCount(); IntVal* getColumnCount(); + RefPtr<Type> getRowType(); virtual String ToString() override; protected: virtual BasicExpressionType* GetScalarType() override; + +private: + RefPtr<Type> mRowType; ) END_SYNTAX_CLASS() |
