summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYong He <yonghe@outlook.com>2025-02-05 22:35:36 -0800
committerGitHub <noreply@github.com>2025-02-05 22:35:36 -0800
commit6b63ff0265ee9bdb8229bb12c71c223c00de0ffa (patch)
tree8010accc99d1f5f20465e8eeb2012f37a6f5534f
parent78f26f076d406a3818800b57afe4d0c2eb166269 (diff)
Allow tuples to work with initializer list. (#6301)
* Allow tuples to work with initiailizer list. * Update definition of C-Style types.
-rw-r--r--docs/proposals/004-initialization.md13
-rw-r--r--source/slang/slang-check-conversion.cpp38
-rw-r--r--source/slang/slang-lower-to-ir.cpp23
-rw-r--r--tests/initializer-list/tuple.slang28
4 files changed, 95 insertions, 7 deletions
diff --git a/docs/proposals/004-initialization.md b/docs/proposals/004-initialization.md
index 9ce143866..20904c650 100644
--- a/docs/proposals/004-initialization.md
+++ b/docs/proposals/004-initialization.md
@@ -198,13 +198,18 @@ void test()
If the above code passes type check, then it will be used as the way to initialize `obj`.
-If the above code does not pass type check, and if there is only one constructor for`MyType` that is synthesized as described in the previous section (and therefore marked as `[Synthesized]`, Slang continues to check if `S` meets the standard of a "legacy C-style struct` type.
-A type is a "legacy C-Style struct" if all of the following conditions are met:
-- It is a user-defined struct type or an enum, a basic scalar, vector or matrix type, e.g. `int`, `float4x4`.
+If the above code does not pass type check, and if there is only one constructor for`MyType` that is synthesized as described in the previous section (and therefore marked as `[Synthesized]`, Slang continues to check if `S` meets the standard of a "legacy C-style struct` type. A type is a "legacy C-Style" type if it is a:
+- Basic scalar type (e.g. `int`, `float`).
+- Enum type.
+- Sized array type where the element type is C-style type.
+- Tuple type where all member types are C-style types.
+- A "C-Style" struct.
+
+A struct is C-Style if all of the following conditions are met:
- It does not inherit from any other types.
- It does not contain any explicit constructors defined by the user.
- All its members have the same visibility as the type itself.
-- All its members are legacy C-Style structs or arrays of legacy C-style structs.
+- All its members are legacy C-Style types.
Note that C-Style structs are allowed to have member default values.
In such case, we perform a legacy "read data" style consumption of the initializer list to synthesize the arguments to call the constructor, so that the following behavior is valid:
diff --git a/source/slang/slang-check-conversion.cpp b/source/slang/slang-check-conversion.cpp
index 6bbdc1477..6dda9c1ea 100644
--- a/source/slang/slang-check-conversion.cpp
+++ b/source/slang/slang-check-conversion.cpp
@@ -238,6 +238,21 @@ bool SemanticsVisitor::isCStyleType(Type* type, HashSet<Type*>& isVisit)
return cacheResult(true);
+ // A tuple type is C-style if all of its members are C-style.
+ if (auto tupleType = as<TupleType>(type))
+ {
+ for (Index i = 0; i < tupleType->getMemberCount(); i++)
+ {
+ auto elementType = tupleType->getMember(i);
+ // Avoid infinite loop in case of circular reference.
+ if (isVisit.contains(elementType))
+ return cacheResult(false);
+ if (!isCStyleType(elementType, isVisit))
+ return cacheResult(false);
+ }
+ return cacheResult(true);
+ }
+
if (auto structDecl = isDeclRefTypeOf<StructDecl>(type).getDecl())
{
// 2. It cannot have inheritance, but inherit from interface is fine.
@@ -299,6 +314,7 @@ bool SemanticsVisitor::isCStyleType(Type* type, HashSet<Type*>& isVisit)
if (!isCStyleType(elementType, isVisit))
return cacheResult(false);
}
+
return cacheResult(true);
}
@@ -700,6 +716,28 @@ bool SemanticsVisitor::_readAggregateValueFromInitializerList(
}
}
}
+ else if (auto tupleType = as<TupleType>(toType))
+ {
+ for (Index ee = 0; ee < tupleType->getMemberCount(); ++ee)
+ {
+ auto elementType = tupleType->getMember(ee);
+ Expr* coercedArg = nullptr;
+ bool argResult = _readValueFromInitializerList(
+ elementType,
+ 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 toDeclRefType = as<DeclRefType>(toType))
{
auto toTypeDeclRef = toDeclRefType->getDeclRef();
diff --git a/source/slang/slang-lower-to-ir.cpp b/source/slang/slang-lower-to-ir.cpp
index cac157f9b..36003dcb2 100644
--- a/source/slang/slang-lower-to-ir.cpp
+++ b/source/slang/slang-lower-to-ir.cpp
@@ -4701,6 +4701,16 @@ struct ExprLoweringVisitorBase : public ExprVisitor<Derived, LoweredValInfo>
{
return LoweredValInfo::simple(getBuilder()->getNullPtrValue(irType));
}
+ else if (auto tupleType = as<TupleType>(type))
+ {
+ List<IRInst*> args;
+ for (Index i = 0; i < tupleType->getMemberCount(); i++)
+ {
+ args.add(getSimpleVal(context, getDefaultVal(tupleType->getMember(i))));
+ }
+ return LoweredValInfo::simple(
+ getBuilder()->emitMakeTuple(irType, args.getCount(), args.getBuffer()));
+ }
else if (auto declRefType = as<DeclRefType>(type))
{
DeclRef<Decl> declRef = declRefType->getDeclRef();
@@ -4925,9 +4935,16 @@ struct ExprLoweringVisitorBase : public ExprVisitor<Derived, LoweredValInfo>
args.add(irDefaultValue);
}
}
-
- return LoweredValInfo::simple(
- getBuilder()->emitMakeStruct(irType, args.getCount(), args.getBuffer()));
+ if (as<TupleType>(type))
+ {
+ return LoweredValInfo::simple(
+ getBuilder()->emitMakeTuple(irType, args.getCount(), args.getBuffer()));
+ }
+ else
+ {
+ return LoweredValInfo::simple(
+ getBuilder()->emitMakeStruct(irType, args.getCount(), args.getBuffer()));
+ }
}
}
diff --git a/tests/initializer-list/tuple.slang b/tests/initializer-list/tuple.slang
new file mode 100644
index 000000000..4da73c0b2
--- /dev/null
+++ b/tests/initializer-list/tuple.slang
@@ -0,0 +1,28 @@
+//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-vk -output-using-type
+//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-output-using-type
+
+Tuple<bool, float> createTuple() {
+ return {};
+}
+
+// We should also enable the following use of initialization list:
+
+Tuple<bool, float> createTuple2() {
+ return {false, 1.0};
+}
+
+
+//TEST_INPUT: set output = out ubuffer(data=[0 0 0 0], stride=4)
+RWStructuredBuffer<float> output;
+
+[numthreads(1, 1, 1)]
+void computeMain()
+{
+ let hit = createTuple();
+ output[0] = hit._1 + 1.0;
+
+ let hit2 = createTuple2();
+ output[1] = hit2._1 + 1.0;
+ // CHECK: 1.0
+ // CHECK: 2.0
+} \ No newline at end of file