From 0afa24a3fe7d0e1787cc909f9c7641f477c30e5c Mon Sep 17 00:00:00 2001 From: jsmall-nvidia Date: Fri, 18 Jun 2021 17:09:35 -0400 Subject: StructTag versioning (#1888) * #include an absolute path didn't work - because paths were taken to always be relative. * WIP Abi struct. * Use AbiSystem on SessionDesc. * Use mask/shift constants. * Fix issue causing warning on linux. * Abi -> Api. * Fix typo. * Refactor to use StructTag. * Mechanism to be able to follow fields. * Field adding is working. * WIP with StructTagConverter. * First pass of StructTag appears to work. Still needs diagnostics. * Small tidy up around Field. * Use bit field to record what fields are recorded to remove allocation around the m_stack. Use ScopeStack for RAII. * Return SlangResult instead of pointers. * Use SlangResult with copy. * Split StructTagConverter implementations. * Fix some bugs around lazy converting. * First pass at unit test for StructTag. * Testing StructTag going backwards in time. * First pass as StructTag diagnostics. * Make Traits a namespace. * Fix some issues with Traits not being a class. * Fix 32 bit warning. --- tools/slang-test/unit-test-struct-tag.cpp | 255 ++++++++++++++++++++++++++++++ 1 file changed, 255 insertions(+) create mode 100644 tools/slang-test/unit-test-struct-tag.cpp (limited to 'tools/slang-test/unit-test-struct-tag.cpp') diff --git a/tools/slang-test/unit-test-struct-tag.cpp b/tools/slang-test/unit-test-struct-tag.cpp new file mode 100644 index 000000000..cc22d9b1d --- /dev/null +++ b/tools/slang-test/unit-test-struct-tag.cpp @@ -0,0 +1,255 @@ +// unit-test-struct-tag.cpp + +#include "../../source/core/slang-memory-arena.h" + +#include +#include + +#include "test-context.h" + +#include "../../source/core/slang-random-generator.h" +#include "../../source/core/slang-list.h" + +#include "../../source/compiler-core/slang-struct-tag-system.h" +#include "../../source/compiler-core/slang-struct-tag-converter.h" + +using namespace Slang; + +namespace { // anonymous + +#define TAGGED_STRUCTS(x) \ + x(A) \ + x(B) \ + x(ExtensionA) \ + x(Desc) + +enum class TaggedStruct +{ + TAGGED_STRUCTS(SLANG_STRUCT_TAG_ENUM) +}; + +#define PRIMARY_TAGGED_STRUCT(TYPE_NAME, MAJOR, MINOR) SLANG_PRIMARY_TAGGED_STRUCT_IMPL(TYPE_NAME##MAJOR##_##MINOR, slang::StructTagCategory::Core, TaggedStruct::TYPE_NAME, MAJOR, MINOR) +#define EXTENSION_TAGGED_STRUCT(TYPE_NAME, MAJOR, MINOR) SLANG_EXTENSION_TAGGED_STRUCT_IMPL(TYPE_NAME##MAJOR##_##MINOR, slang::StructTagCategory::Core, TaggedStruct::TYPE_NAME, MAJOR, MINOR) + +struct A0_0 +{ + PRIMARY_TAGGED_STRUCT(A, 0, 0) + + int a = 10; +}; + +struct A0_1 +{ + PRIMARY_TAGGED_STRUCT(A, 0, 1) + + int a = 10; + int b = 20; +}; + +struct B0_0 +{ + PRIMARY_TAGGED_STRUCT(B, 0, 0) + + float v = -1.0f; +}; + +struct B0_1 +{ + PRIMARY_TAGGED_STRUCT(B, 0, 1) + + float v = -1.0f; + float u = 20.0f; +}; + +struct A1_0 +{ + PRIMARY_TAGGED_STRUCT(A, 1, 0) +}; + + +struct ExtensionA0_0 +{ + EXTENSION_TAGGED_STRUCT(ExtensionA, 0, 0) + + int b = 20; +}; + +// I guess a Desc could be implemented as 'Primary' or 'Extension' with what we have, but probably makes more sense +// for 'Desc' like things to be primary + +struct Desc0_0 +{ + EXTENSION_TAGGED_STRUCT(Desc, 0, 0) + int a = 1; +}; + +struct Desc0_1 +{ + EXTENSION_TAGGED_STRUCT(Desc, 0, 1) + int a = 1; + int b = 2; +}; + + +struct A0_2 +{ + PRIMARY_TAGGED_STRUCT(A, 0, 2) + + int a = 10; + int b = 20; + + Desc0_0* descs = nullptr; + Index descsCount = 0; +}; + +} // anonymous + +static RefPtr _createSystem() +{ + RefPtr system = new StructTagSystem; + + { +#define SLANG_STRUCT_TAG_ADD_CATEGORY(x) system->addCategoryInfo(slang::StructTagCategory::x, #x); + SLANG_STRUCT_TAG_CATEGORIES(SLANG_STRUCT_TAG_ADD_CATEGORY) + } + + return system; +} + +static void structTagUnitTest() +{ + SourceManager sourceManager; + sourceManager.initialize(nullptr, nullptr); + + DiagnosticSink sink; + sink.init(&sourceManager, nullptr); + + { + StructTagUtil::TypeInfo info = StructTagUtil::getTypeInfo(A0_1::kStructTag); + + SLANG_CHECK(info.kind == slang::StructTagKind::Primary); + SLANG_CHECK(info.category == slang::StructTagCategory::Core); + SLANG_CHECK(info.majorVersion == 0); + SLANG_CHECK(info.minorVersion == 1); + } + + { + StructTagUtil::TypeInfo info = StructTagUtil::getTypeInfo(ExtensionA0_0::kStructTag); + + SLANG_CHECK(info.kind == slang::StructTagKind::Extension); + SLANG_CHECK(info.category == slang::StructTagCategory::Core); + SLANG_CHECK(info.majorVersion == 0); + SLANG_CHECK(info.minorVersion == 0); + } + + { + // Set up the system with the versions + auto system = _createSystem(); + + system->addType(B0_1::kStructTag, "B", sizeof(B0_1)); + system->addType(A0_1::kStructTag, "A", sizeof(A0_1)); + system->addType(ExtensionA0_0::kStructTag, "ExtensionA", sizeof(ExtensionA0_0)); + + { + //The null operation means we are converting everything that is current (as defined by the system) + + A0_1 a; + ExtensionA0_0 extA; + const slang::StructTag* exts[] = { &extA.structTag }; + a.exts = exts; + a.extsCount = SLANG_COUNT_OF(exts); + + + LazyStructTagConverter converter(system, nullptr, nullptr); + + auto dstA = converter.convertToCurrent(&a); + + // We shouldn't have to convert anything, so we should be done + SLANG_CHECK(dstA == &a); + } + + { + A0_0 a; + ExtensionA0_0 extA; + const slang::StructTag* exts[] = { &extA.structTag }; + a.exts = exts; + a.extsCount = SLANG_COUNT_OF(exts); + + + // Actually do a conversion from past + MemoryArena arena(1024); + LazyStructTagConverter converter(system, &arena, nullptr); + + auto dstA = converter.convertToCurrent(&a); + + SLANG_CHECK(dstA != nullptr); + SLANG_CHECK(dstA->a == 10 && dstA->b == 0); + + SLANG_CHECK(dstA->extsCount == 1); + SLANG_CHECK(((ExtensionA0_0*)dstA->exts[0])->b == 20); + } + } + + // Let's try going from the future backwards + { + // Set up the system with the versions + auto system = _createSystem(); + + system->addType(B0_1::kStructTag, "B", sizeof(B0_1)); + system->addType(A0_2::kStructTag, "A", sizeof(A0_2)); + system->addType(ExtensionA0_0::kStructTag, "ExtensionA", sizeof(ExtensionA0_0)); + system->addType(Desc0_0::kStructTag, "Desc", sizeof(Desc0_0)); + + // Add the fields + { + auto type = system->getType(A0_2::kStructTag); + A0_2 a; + auto field = StructTagTypeTraits::getFieldWithCount(&a, &a.descs, &a.descsCount); + type->m_fields.add(field); + } + + // + + A0_2 a; + Desc0_1 descs[2]; + descs[0].a = 27; + descs[1].a = -1; + + a.descs = (Desc0_0*)descs; + a.descsCount = SLANG_COUNT_OF(descs); + + // Actually do a conversion from future + MemoryArena arena(1024); + LazyStructTagConverter converter(system, &arena, nullptr); + + auto dstA = converter.convertToCurrent(&a); + + SLANG_CHECK(dstA->descsCount == a.descsCount); + + SLANG_CHECK(dstA->descs[0].a == 27 && dstA->descs[1].a == -1); + } + + // Lets try some invalid conversions + + { + // Set up the system with the versions + auto system = _createSystem(); + + system->addType(B0_1::kStructTag, "B", sizeof(B0_1)); + system->addType(A0_2::kStructTag, "A", sizeof(A0_2)); + system->addType(ExtensionA0_0::kStructTag, "ExtensionA", sizeof(ExtensionA0_0)); + system->addType(Desc0_0::kStructTag, "Desc", sizeof(Desc0_0)); + + A1_0 a; + + MemoryArena arena(1024); + LazyStructTagConverter converter(system, &arena, &sink); + + void* dst; + SLANG_CHECK(SLANG_FAILED(converter.convertCurrent(&a, dst))); + + } + +} + +SLANG_UNIT_TEST("StructTag", structTagUnitTest); -- cgit v1.2.3