diff options
| author | Yong He <yonghe@outlook.com> | 2025-02-05 22:35:36 -0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-02-05 22:35:36 -0800 |
| commit | 6b63ff0265ee9bdb8229bb12c71c223c00de0ffa (patch) | |
| tree | 8010accc99d1f5f20465e8eeb2012f37a6f5534f | |
| parent | 78f26f076d406a3818800b57afe4d0c2eb166269 (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.md | 13 | ||||
| -rw-r--r-- | source/slang/slang-check-conversion.cpp | 38 | ||||
| -rw-r--r-- | source/slang/slang-lower-to-ir.cpp | 23 | ||||
| -rw-r--r-- | tests/initializer-list/tuple.slang | 28 |
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 |
