diff options
| -rw-r--r-- | source/slang/slang-ir-specialize.cpp | 7 | ||||
| -rw-r--r-- | source/slang/slang-ir.cpp | 29 | ||||
| -rw-r--r-- | source/slang/slang-lower-to-ir.cpp | 6 | ||||
| -rw-r--r-- | source/slang/slang.cpp | 1 | ||||
| -rw-r--r-- | tests/language-feature/generics/struct-generic-value-param-import.slang | 19 | ||||
| -rw-r--r-- | tests/language-feature/generics/struct-generic-value-param.slang | 63 | ||||
| -rw-r--r-- | tests/language-feature/generics/struct-generic-value-param.slang.expected.txt | 4 |
7 files changed, 117 insertions, 12 deletions
diff --git a/source/slang/slang-ir-specialize.cpp b/source/slang/slang-ir-specialize.cpp index d4f236138..cf475f1ff 100644 --- a/source/slang/slang-ir-specialize.cpp +++ b/source/slang/slang-ir-specialize.cpp @@ -267,6 +267,13 @@ struct SpecializationContext IRGeneric* g = generic; for(;;) { + // We can't specialize a generic if it is marked as + // being imported from an external module (in which + // case its definition is not available to us). + // + if(!isDefinition(g)) + return false; + // Given the generic `g`, we will find the value // it appears to return in its body. // diff --git a/source/slang/slang-ir.cpp b/source/slang/slang-ir.cpp index 45cbd65ff..9a44787ff 100644 --- a/source/slang/slang-ir.cpp +++ b/source/slang/slang-ir.cpp @@ -5068,6 +5068,13 @@ namespace Slang // the value they return. for(;;) { + // An instruciton marked `[import(...)]` cannot + // be a definition, since it is claiming that + // the actual body comes from another module. + // + if(val->findDecoration<IRImportDecoration>()) + return false; + auto genericInst = as<IRGeneric>(val); if(!genericInst) break; @@ -5079,13 +5086,12 @@ namespace Slang val = returnVal; } - // TODO: the logic here should probably - // be that anything with an `IRImportDecoration` - // is considered to be a declaration rather than definition. - + // Some cases of instructions have structural + // rules about when they are considered to have + // a definition (e.g., a function must have a body). + // switch (val->op) { - case kIROp_WitnessTable: case kIROp_Func: case kIROp_Generic: return val->getFirstChild() != nullptr; @@ -5093,14 +5099,15 @@ namespace Slang case kIROp_GlobalConstant: return cast<IRGlobalConstant>(val)->getValue() != nullptr; - case kIROp_StructType: - case kIROp_GlobalVar: - case kIROp_GlobalParam: - return true; - default: - return false; + break; } + + // In all other cases, if we have an instruciton + // that has *not* been marked for import, then + // we consider it to be a definition. + + return true; } void markConstExpr( diff --git a/source/slang/slang-lower-to-ir.cpp b/source/slang/slang-lower-to-ir.cpp index 009e776bb..aaa9d1a4c 100644 --- a/source/slang/slang-lower-to-ir.cpp +++ b/source/slang/slang-lower-to-ir.cpp @@ -6711,13 +6711,17 @@ static void ensureAllDeclsRec( // Aggregate types are the main case where we can emit an outer declaration // and not the stuff nested inside of it. // - if(auto containerDecl = as<AggTypeDecl>(decl)) + if(auto containerDecl = as<AggTypeDeclBase>(decl)) { for (auto memberDecl : containerDecl->Members) { ensureAllDeclsRec(context, memberDecl); } } + else if (auto genericDecl = as<GenericDecl>(decl)) + { + ensureAllDeclsRec(context, genericDecl->inner); + } } IRModule* generateIRForTranslationUnit( diff --git a/source/slang/slang.cpp b/source/slang/slang.cpp index aefe70a4a..1f8f79af2 100644 --- a/source/slang/slang.cpp +++ b/source/slang/slang.cpp @@ -1544,6 +1544,7 @@ RefPtr<Module> Linkage::loadModule( RefPtr<TranslationUnitRequest> translationUnit = new TranslationUnitRequest(frontEndReq); translationUnit->compileRequest = frontEndReq; translationUnit->moduleName = name; + translationUnit->sourceLanguage = SourceLanguage::Slang; auto module = translationUnit->getModule(); diff --git a/tests/language-feature/generics/struct-generic-value-param-import.slang b/tests/language-feature/generics/struct-generic-value-param-import.slang new file mode 100644 index 000000000..edc1b0c39 --- /dev/null +++ b/tests/language-feature/generics/struct-generic-value-param-import.slang @@ -0,0 +1,19 @@ +// struct-generic-value-param-import.slang +//TEST_IGNORE_FILE: + +// This file is used by `struct-generic-value-param.slang`, +// and also incidentally tests that a trailing `;` is optional +// for `struct` decalrations in Slang files, including +// any `import`ed code. + +interface IData {} + +struct Data<let kCount : int> : IData +{ + int state; + + [mutating] void doStuff() + { + state++; + } +} diff --git a/tests/language-feature/generics/struct-generic-value-param.slang b/tests/language-feature/generics/struct-generic-value-param.slang new file mode 100644 index 000000000..857468165 --- /dev/null +++ b/tests/language-feature/generics/struct-generic-value-param.slang @@ -0,0 +1,63 @@ +// struct-generic-value-param.slang + +// This test reproduces a few bugs related to declarations +// not being emitted IR and specialized correctly. +// +// First, it tests that a method in a generic `struct` +// gets properly emitted to the IR of its own module. +// +// Second, it tests that witness tables for an empty +// `interface` can be emitted and used to specialize +// code with generic type parameters constrained to +// those interfaces. + +// This file is attempting to stress-test use of a `struct` +// type with a generic value parameter. In particular, it +// it can reproduce a bug that was encountered by a user +// when trying out the feature. + +//TEST(compute):COMPARE_COMPUTE: + +import struct_generic_value_param_import; + +Data<N> makeData<let N : int>( int val ) +{ + Data<N> result = { val }; + return result; +} + +void doThings<D : IData>(D data, inout int v) +{ + v++; +} + +int test(int val) +{ + var data = makeData<4>(val); + + // Note: with the original bug, this call emitted + // as `/* unhandled */(data)` which meant the call + // acted as a no-op. + // + data.doStuff(); + + // Note: with the original bug, this call emitted + // as `/* uhandled */(data, val)` which is also + // a no-op (that happens to use `operator,`). + // + doThings(data, val); + + return data.state + val*16; +} + +//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out,name=outputBuffer +RWStructuredBuffer<int> outputBuffer; + +[numthreads(4, 1, 1)] +void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) +{ + uint tid = dispatchThreadID.x; + int inVal = tid; + int outVal = test(inVal); + outputBuffer[tid] = outVal; +} diff --git a/tests/language-feature/generics/struct-generic-value-param.slang.expected.txt b/tests/language-feature/generics/struct-generic-value-param.slang.expected.txt new file mode 100644 index 000000000..e4511c4c7 --- /dev/null +++ b/tests/language-feature/generics/struct-generic-value-param.slang.expected.txt @@ -0,0 +1,4 @@ +11 +22 +33 +44 |
