summaryrefslogtreecommitdiffstats
path: root/source
diff options
context:
space:
mode:
Diffstat (limited to 'source')
-rw-r--r--source/slang/check.cpp629
-rw-r--r--source/slang/compiler.h4
-rw-r--r--source/slang/diagnostic-defs.h8
-rw-r--r--source/slang/diagnostics.cpp5
-rw-r--r--source/slang/diagnostics.h4
-rw-r--r--source/slang/emit.cpp2
-rw-r--r--source/slang/ir-constexpr.cpp2
-rw-r--r--source/slang/ir-inst-defs.h2
-rw-r--r--source/slang/ir-insts.h5
-rw-r--r--source/slang/ir.cpp10
-rw-r--r--source/slang/lower-to-ir.cpp208
-rw-r--r--source/slang/syntax.cpp30
-rw-r--r--source/slang/type-defs.h4
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()