summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--source/slang/check.cpp140
-rw-r--r--source/slang/core.meta.slang30
-rw-r--r--source/slang/core.meta.slang.h30
-rw-r--r--source/slang/lookup.cpp8
-rw-r--r--source/slang/lower-to-ir.cpp5
-rw-r--r--source/slang/lower.cpp17
-rw-r--r--tests/bugs/array-size-static-const.hlsl14
-rw-r--r--tests/bugs/empty.slang5
-rw-r--r--tests/bugs/implicit-conversion-binary-op.hlsl16
-rw-r--r--tests/bugs/import-overload-error.hlsl19
-rw-r--r--tests/bugs/import-overload-error.slang4
-rw-r--r--tests/bugs/uav-write-index.hlsl31
-rw-r--r--tests/bugs/vec-init-list.hlsl19
13 files changed, 292 insertions, 46 deletions
diff --git a/source/slang/check.cpp b/source/slang/check.cpp
index 73d464d95..b35dd2662 100644
--- a/source/slang/check.cpp
+++ b/source/slang/check.cpp
@@ -671,6 +671,59 @@ namespace Slang
// we will collect the new arguments here
List<RefPtr<Expr>> coercedArgs;
+ 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?
+ elementCount = fromInitializerListExpr->args.Count();
+ }
+
+ // 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)
+ {
+ RefPtr<Expr> coercedArg;
+ ConversionCost argCost;
+
+ bool argResult = TryCoerceImpl(
+ toElementType,
+ outToExpr ? &coercedArg : nullptr,
+ arg->type,
+ arg,
+ outCost ? &argCost : nullptr);
+
+ // 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 )
+ {
+ 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>())
{
auto toTypeDeclRef = toDeclRefType->declRef;
@@ -804,9 +857,6 @@ namespace Slang
OverloadResolveContext overloadContext;
- List<RefPtr<Expr>> args;
- args.Add(fromExpr);
-
overloadContext.disallowNestedConversions = true;
overloadContext.argCount = 1;
overloadContext.argTypes = &fromType;
@@ -884,7 +934,45 @@ namespace Slang
if(outToExpr)
{
+ // The logic here is a bit ugly, to deal with the fact that
+ // `CompleteOverloadCandidate` will, left to its own devices,
+ // construct a vanilla `InvokeExpr` to represent the call
+ // to the initializer we found, while we *want* it to
+ // create some variety of `ImplicitCastExpr`.
+ //
+ // Now, it just so happens that `CompleteOverloadCandidate`
+ // will use the "original" expression if one is available,
+ // so we'll create one and initialize it here.
+ // We fill in the location and arguments, but not the
+ // base expression (the callee), since that will come
+ // from the selected overload candidate.
+ //
+ auto castExpr = createImplicitCastExpr();
+ castExpr->loc = fromExpr->loc;
+ castExpr->Arguments.Add(fromExpr);
+ //
+ // Next we need to set our cast expression as the "original"
+ // expression and then complete the overload process.
+ //
+ overloadContext.originalExpr = castExpr;
*outToExpr = CompleteOverloadCandidate(overloadContext, *overloadContext.bestCandidate);
+ //
+ // However, the above isn't *quite* enough, because
+ // the process of completing the overload candidate
+ // might overwrite the argument list that was passed
+ // in to overload resolution, and in this case that
+ // "argument list" was just a pointer to `fromExpr`.
+ //
+ // That means we need to clear the argument list and
+ // reload it from `fromExpr` to make sure that we
+ // got the arguments *after* any transformations
+ // were applied.
+ // For right now this probably doesn't matter,
+ // because we don't allow nested implicit conversions,
+ // but I'd rather play it safe.
+ //
+ castExpr->Arguments.Clear();
+ castExpr->Arguments.Add(fromExpr);
}
return true;
@@ -907,22 +995,26 @@ namespace Slang
outCost);
}
- RefPtr<Expr> CreateImplicitCastExpr(
- RefPtr<Type> toType,
- RefPtr<Expr> fromExpr)
+ RefPtr<TypeCastExpr> createImplicitCastExpr()
{
- // In "rewrite" mode, we will generate a different syntax node
- // to indicate that this type-cast was implicitly generated
- // by the compiler, and shouldn't appear in the output code.
- RefPtr<TypeCastExpr> castExpr;
if (isRewriteMode())
{
- castExpr = new HiddenImplicitCastExpr();
+ // In "rewrite" mode, we will generate a different syntax node
+ // to indicate that this type-cast was implicitly generated
+ // by the compiler, and shouldn't appear in the output code.
+ return new HiddenImplicitCastExpr();
}
else
{
- castExpr = new ImplicitCastExpr();
+ return new ImplicitCastExpr();
}
+ }
+
+ RefPtr<Expr> CreateImplicitCastExpr(
+ RefPtr<Type> toType,
+ RefPtr<Expr> fromExpr)
+ {
+ RefPtr<TypeCastExpr> castExpr = createImplicitCastExpr();
auto typeType = new TypeType();
typeType->type = toType;
@@ -2005,7 +2097,17 @@ namespace Slang
auto funcDeclRef = funcDeclRefExpr->declRef;
auto intrinsicMod = funcDeclRef.getDecl()->FindModifier<IntrinsicOpModifier>();
- if (!intrinsicMod) return nullptr;
+ if (!intrinsicMod)
+ {
+ // We can't constant fold anything that doesn't map to a builtin
+ // operation right now.
+ //
+ // TODO: we should really allow constant-folding for anything
+ // that can be lowerd to our bytecode...
+ return nullptr;
+ }
+
+
// Let's not constant-fold operations with more than a certain number of arguments, for simplicity
static const int kMaxArgs = 8;
@@ -2188,16 +2290,16 @@ namespace Slang
}
}
- if (auto invokeExpr = dynamic_cast<InvokeExpr*>(expr))
+ if(auto castExpr = dynamic_cast<TypeCastExpr*>(expr))
{
- auto val = TryConstantFoldExpr(invokeExpr);
- if (val)
+ auto val = TryConstantFoldExpr(castExpr->Arguments[0].Ptr());
+ if(val)
return val;
}
- else if(auto castExpr = dynamic_cast<TypeCastExpr*>(expr))
+ else if (auto invokeExpr = dynamic_cast<InvokeExpr*>(expr))
{
- auto val = TryConstantFoldExpr(castExpr->Arguments[0].Ptr());
- if(val)
+ auto val = TryConstantFoldExpr(invokeExpr);
+ if (val)
return val;
}
diff --git a/source/slang/core.meta.slang b/source/slang/core.meta.slang
index 3755c51c7..3f1a33edc 100644
--- a/source/slang/core.meta.slang
+++ b/source/slang/core.meta.slang
@@ -108,6 +108,9 @@ sb << " __implicit_conversion(" << kConversionCost_ScalarToVector << ")\n";
sb << " __intrinsic_op(" << kIROp_constructVectorFromScalar << ")\n";
sb << " __init(T value);\n";
+// Allow initialization from same type
+sb << " __init(vector<T,N> value);\n";
+
sb << "};\n";
// TODO: Probably need to do similar
@@ -190,13 +193,6 @@ for (int N = 2; N <= 4; ++N)
sb << ");\n";
}
- // initialize from another vector of the same size
- //
- // TODO(tfoley): this overlaps with implicit conversions.
- // We should look for a way that we can define implicit
- // conversions directly in the stdlib instead...
- sb << "__generic<U> __init(vector<U," << N << ">);\n";
-
// Initialize from two vectors, of size M and N-M
for(int M = 2; M <= (N-2); ++M)
{
@@ -230,16 +226,20 @@ for (int tt = 0; tt < kBaseTypeCount; ++tt)
{
if(kBaseTypes[ff].tag == BaseType::Void) continue;
- // We need a constructor to make a vector from a scalar
- // of another type.
if( tt != ff )
{
auto cost = getBaseTypeConversionCost(
kBaseTypes[tt],
kBaseTypes[ff]);
- cost += kConversionCost_ScalarToVector;
+ // Implicit conversion from a vector of the same
+ // size, but different element type.
+ sb << " __implicit_conversion(" << cost << ")\n";
+ sb << " __init(vector<" << kBaseTypes[ff].name << ",N> value);\n";
+
+ // Constructor to make a vector from a scalar of another type.
+ cost += kConversionCost_ScalarToVector;
sb << " __implicit_conversion(" << cost << ")\n";
sb << " __init(" << kBaseTypes[ff].name << " value);\n";
}
@@ -557,8 +557,16 @@ for (int tt = 0; tt < kBaseTextureTypeCount; ++tt)
if(baseShape != TextureType::ShapeCube)
{
+ // TODO: In the case where `access` includes writeability,
+ // this should have both `get` and `set` accessors.
+
// subscript operator
- sb << "__intrinsic_op __subscript(uint" << kBaseTextureTypes[tt].coordCount + isArray << " location) -> T;\n";
+ sb << "__intrinsic_op __subscript(uint";
+ if(kBaseTextureTypes[tt].coordCount + isArray > 1)
+ {
+ sb << kBaseTextureTypes[tt].coordCount + isArray;
+ }
+ sb << " location) -> T;\n";
}
if( !isMultisample )
diff --git a/source/slang/core.meta.slang.h b/source/slang/core.meta.slang.h
index 864196944..900d05b61 100644
--- a/source/slang/core.meta.slang.h
+++ b/source/slang/core.meta.slang.h
@@ -110,6 +110,9 @@ sb << " __implicit_conversion(" << kConversionCost_ScalarToVector << ")\n";
sb << " __intrinsic_op(" << kIROp_constructVectorFromScalar << ")\n";
sb << " __init(T value);\n";
+// Allow initialization from same type
+sb << " __init(vector<T,N> value);\n";
+
sb << "};\n";
// TODO: Probably need to do similar
@@ -193,13 +196,6 @@ for (int N = 2; N <= 4; ++N)
sb << ");\n";
}
- // initialize from another vector of the same size
- //
- // TODO(tfoley): this overlaps with implicit conversions.
- // We should look for a way that we can define implicit
- // conversions directly in the stdlib instead...
- sb << "__generic<U> __init(vector<U," << N << ">);\n";
-
// Initialize from two vectors, of size M and N-M
for(int M = 2; M <= (N-2); ++M)
{
@@ -233,16 +229,20 @@ for (int tt = 0; tt < kBaseTypeCount; ++tt)
{
if(kBaseTypes[ff].tag == BaseType::Void) continue;
- // We need a constructor to make a vector from a scalar
- // of another type.
if( tt != ff )
{
auto cost = getBaseTypeConversionCost(
kBaseTypes[tt],
kBaseTypes[ff]);
- cost += kConversionCost_ScalarToVector;
+ // Implicit conversion from a vector of the same
+ // size, but different element type.
+ sb << " __implicit_conversion(" << cost << ")\n";
+ sb << " __init(vector<" << kBaseTypes[ff].name << ",N> value);\n";
+
+ // Constructor to make a vector from a scalar of another type.
+ cost += kConversionCost_ScalarToVector;
sb << " __implicit_conversion(" << cost << ")\n";
sb << " __init(" << kBaseTypes[ff].name << " value);\n";
}
@@ -560,8 +560,16 @@ for (int tt = 0; tt < kBaseTextureTypeCount; ++tt)
if(baseShape != TextureType::ShapeCube)
{
+ // TODO: In the case where `access` includes writeability,
+ // this should have both `get` and `set` accessors.
+
// subscript operator
- sb << "__intrinsic_op __subscript(uint" << kBaseTextureTypes[tt].coordCount + isArray << " location) -> T;\n";
+ sb << "__intrinsic_op __subscript(uint";
+ if(kBaseTextureTypes[tt].coordCount + isArray > 1)
+ {
+ sb << kBaseTextureTypes[tt].coordCount + isArray;
+ }
+ sb << " location) -> T;\n";
}
if( !isMultisample )
diff --git a/source/slang/lookup.cpp b/source/slang/lookup.cpp
index ccdbe8fbf..95a1b3326 100644
--- a/source/slang/lookup.cpp
+++ b/source/slang/lookup.cpp
@@ -40,6 +40,9 @@ void buildMemberDictionary(ContainerDecl* decl)
decl->memberDictionary.Clear();
decl->transparentMembers.Clear();
+ // are we a generic?
+ GenericDecl* genericDecl = dynamic_cast<GenericDecl*>(decl);
+
for (auto m : decl->Members)
{
auto name = m->getName();
@@ -56,6 +59,11 @@ void buildMemberDictionary(ContainerDecl* decl)
if (!name)
continue;
+ // Ignore the "inner" member of a generic declaration
+ if (genericDecl && m == genericDecl->inner)
+ continue;
+
+
m->nextInContainerWithSameName = nullptr;
Decl* next = nullptr;
diff --git a/source/slang/lower-to-ir.cpp b/source/slang/lower-to-ir.cpp
index b9307b007..2f3456d0c 100644
--- a/source/slang/lower-to-ir.cpp
+++ b/source/slang/lower-to-ir.cpp
@@ -1452,11 +1452,6 @@ struct ExprLoweringVisitorBase : ExprVisitor<Derived, LoweredValInfo>
return ensureDecl(context, expr->declRef);
}
- LoweredValInfo visitTypeCastExpr(TypeCastExpr* expr)
- {
- SLANG_UNIMPLEMENTED_X("codegen for type cast expression");
- }
-
LoweredValInfo visitSelectExpr(SelectExpr* expr)
{
SLANG_UNIMPLEMENTED_X("codegen for select expression");
diff --git a/source/slang/lower.cpp b/source/slang/lower.cpp
index 6d848062c..b620a7837 100644
--- a/source/slang/lower.cpp
+++ b/source/slang/lower.cpp
@@ -956,6 +956,23 @@ struct LoweringVisitor
return LoweredExpr(loweredExpr);
}
+ LoweredExpr visitOverloadedExpr(
+ OverloadedExpr* expr)
+ {
+ // The presence of an overloaded expression in the output
+ // means that some amount of semantic checking failed.
+ // Thus we don't need to worry about semantically transforming
+ // the expression itself, but we *do* want to ensure that any
+ // of the declarations that the user might have been referring
+ // to get lowered so they will appear in the output.
+ for (auto item : expr->lookupResult2.items)
+ {
+ translateDeclRef(item.declRef);
+ }
+
+ return expr;
+ }
+
Name* getName(String const& text)
{
return shared->compileRequest->getNamePool()->getName(text);
diff --git a/tests/bugs/array-size-static-const.hlsl b/tests/bugs/array-size-static-const.hlsl
new file mode 100644
index 000000000..fe15d402d
--- /dev/null
+++ b/tests/bugs/array-size-static-const.hlsl
@@ -0,0 +1,14 @@
+// array-size-static-const.hlsl
+//TEST:COMPARE_HLSL: -profile cs_5_0 -target dxbc-assembly
+
+// The bug in this case is that were have a (hidden)
+// cast from the `uint` constant to `int` to get
+// the size of the array, and this cast was tripping
+// up the constant-folding logic.
+
+static const uint n = 16;
+groupshared float b[n];
+
+[numthreads(1,1,1)]
+void main()
+{}
diff --git a/tests/bugs/empty.slang b/tests/bugs/empty.slang
new file mode 100644
index 000000000..ac4b3b7ca
--- /dev/null
+++ b/tests/bugs/empty.slang
@@ -0,0 +1,5 @@
+//TEST_IGNORE_FILE:
+// empty.slang
+
+// This is just an empty file so that tets
+// that need to `__import` something can.
diff --git a/tests/bugs/implicit-conversion-binary-op.hlsl b/tests/bugs/implicit-conversion-binary-op.hlsl
new file mode 100644
index 000000000..75ff737da
--- /dev/null
+++ b/tests/bugs/implicit-conversion-binary-op.hlsl
@@ -0,0 +1,16 @@
+// implicit-conversion-binary-op.hlsl
+//TEST:COMPARE_HLSL: -profile ps_5_0 -target dxbc-assembly
+
+// Make sure that we can pick resolve the right overload
+// to call when applying a binary operator to vectors
+// with different element types. We should pick
+// the "better" of the two element types, and not
+// get an ambiguity error.
+
+float4 main(
+ float4 a : A,
+ uint4 b : B
+ ) : SV_Target
+{
+ return a * b;
+}
diff --git a/tests/bugs/import-overload-error.hlsl b/tests/bugs/import-overload-error.hlsl
new file mode 100644
index 000000000..328bb5b26
--- /dev/null
+++ b/tests/bugs/import-overload-error.hlsl
@@ -0,0 +1,19 @@
+//TEST:COMPARE_HLSL: -profile cs_5_0 -target dxbc-assembly -no-checking
+
+#ifdef __SLANG__
+__import import_overload_error;
+#else
+
+void foo(int a) {}
+void foo(float b) {}
+
+#endif
+
+void main()
+{
+// Note(tfoley): futzing around with tokens to
+// make sure error message gets reported at a
+// consistent location between languages.
+int a;
+foo();
+}
diff --git a/tests/bugs/import-overload-error.slang b/tests/bugs/import-overload-error.slang
new file mode 100644
index 000000000..e52ce78bb
--- /dev/null
+++ b/tests/bugs/import-overload-error.slang
@@ -0,0 +1,4 @@
+//TEST_IGNORE_FILE:
+
+void foo(int a) {}
+void foo(float b) {}
diff --git a/tests/bugs/uav-write-index.hlsl b/tests/bugs/uav-write-index.hlsl
new file mode 100644
index 000000000..667c73e89
--- /dev/null
+++ b/tests/bugs/uav-write-index.hlsl
@@ -0,0 +1,31 @@
+//TEST:COMPARE_HLSL: -profile cs_5_0 -target dxbc-assembly -no-checking
+
+// Make sure we handle complex UAV write patterns
+
+// Force import of Slang to ensure that some
+// checking takes place:
+#ifdef __SLANG__
+__import empty;
+#endif
+
+struct Bar
+{
+ uint bar;
+};
+
+RWStructuredBuffer<Bar> gUAV : register(u0);
+
+void foo(RWTexture1D<float2> uav)
+{
+ uint index = gUAV.IncrementCounter();
+ gUAV[index].bar = 1;
+ uav[index] = float2(0,0);
+}
+
+RWTexture1D<float2> gUAV2 : register(u1);
+
+[numthreads(1,1,1)]
+void main()
+{
+ foo(gUAV2);
+}
diff --git a/tests/bugs/vec-init-list.hlsl b/tests/bugs/vec-init-list.hlsl
new file mode 100644
index 000000000..be1bc5c6f
--- /dev/null
+++ b/tests/bugs/vec-init-list.hlsl
@@ -0,0 +1,19 @@
+//TEST:COMPARE_HLSL: -profile vs_5_0 -target dxbc-assembly
+
+// Check handling of initializer list for vector
+
+cbuffer C : register(b0)
+{
+ float4 a;
+};
+
+float w0(float x) { return x; }
+float w1(float x) { return x; }
+float w2(float x) { return x; }
+float w3(float x) { return x; }
+
+float4 main() : SV_Position
+{
+ float4 wx = { w0(a.x), w1(a.x), w2(a.x), w3(a.x), };
+ return wx;
+}