summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRonan <ro.cailleau@gmail.com>2025-04-03 06:17:15 +0200
committerGitHub <noreply@github.com>2025-04-03 04:17:15 +0000
commit6b44630afe4ff180ba608142e9515abcd369775e (patch)
tree67e895172552fd3c73d6830436e30fa157142742
parentb4a1d618b8d850a579af2840db2df6bee312172c (diff)
Fixed generic interface specialization crashes (#6601): (#6688)
* Fixed generic interface specialization crashes: - Add an export decoration to specialized generic interfaces. * Fixed generic interface specialization crashes: - Add an export decoration to specialized generic interfaces. - Use getTypeNameHint(...) instead of a manual mangler. * In cloneInstDecorationsAndChildren: specialize all linkage decorations, not just the exports. - If a linkage decoration is already present, it is not specialized and replaced by the specialized one. - If a specialization uses the TypeNameHint, sanitize it to be used as an identifier. - Use the identifier name sanitizer from slang-mangle. * Added tests/generics/generic-interface-linkage.slang - See #6601 and #6688
-rw-r--r--source/slang/slang-ir-clone.cpp63
-rw-r--r--source/slang/slang-mangle.cpp17
-rw-r--r--source/slang/slang-mangle.h2
-rw-r--r--tests/language-feature/generics/generic-interface-linkage.slang81
4 files changed, 157 insertions, 6 deletions
diff --git a/source/slang/slang-ir-clone.cpp b/source/slang/slang-ir-clone.cpp
index 66af405d6..5bb1c1210 100644
--- a/source/slang/slang-ir-clone.cpp
+++ b/source/slang/slang-ir-clone.cpp
@@ -2,7 +2,10 @@
#include "slang-ir-clone.h"
#include "slang-ir-insts.h"
+#include "slang-ir-util.h"
#include "slang-ir.h"
+#include "slang-mangle.h"
+
namespace Slang
{
@@ -104,6 +107,61 @@ IRInst* cloneInstAndOperands(IRCloneEnv* env, IRBuilder* builder, IRInst* oldIns
return newInst;
}
+// Copy the linkage decoration of oldInst (if present) and specialize it for target.
+static void specializeLinkageDecoration(IRInst* target, IRSpecialize* oldInst, IRBuilder* builder)
+{
+ auto gen = as<IRGeneric>(oldInst->getBase());
+ if (gen)
+ {
+ auto genLinkage = gen->findDecoration<IRLinkageDecoration>();
+ if (genLinkage)
+ {
+ bool isExport = as<IRExportDecoration>(genLinkage);
+ StringBuilder sb;
+ sb.append(genLinkage->getMangledName());
+ sb.append("G");
+ IRSpecialize* specializationProvider = oldInst;
+ if (auto targetAsSpec = as<IRSpecialize>(target))
+ {
+ specializationProvider = targetAsSpec;
+ }
+ for (UInt i = 0; i < specializationProvider->getArgCount(); ++i)
+ {
+ auto arg = specializationProvider->getArg(i);
+ sb.append(i);
+ if (auto typeLinkage = arg->findDecoration<IRLinkageDecoration>())
+ {
+ sb.append(typeLinkage->getMangledName());
+ }
+ else
+ {
+ // getTypeNameHint may produce a name with characters that can't
+ // be part of an identifier, so we need to filter it afterward.
+ StringBuilder tmp;
+ getTypeNameHint(tmp, arg);
+ emitNameForLinkage(sb, tmp.getUnownedSlice());
+ }
+ }
+ if (auto previousLinkage = target->findDecoration<IRLinkageDecoration>())
+ {
+ // Overwrite the previous linkage decoration, since it was not specialized
+ previousLinkage->setOperand(0, builder->getStringValue(sb.getUnownedSlice()));
+ }
+ else
+ {
+ if (isExport)
+ {
+ builder->addExportDecoration(target, sb.getUnownedSlice());
+ }
+ else
+ {
+ builder->addImportDecoration(target, sb.getUnownedSlice());
+ }
+ }
+ }
+ }
+}
+
// The complexity of the second phase of cloning (the
// one that deals with decorations and children) comes
// from the fact that it needs to sequence the two phases
@@ -226,6 +284,11 @@ static void _cloneInstDecorationsAndChildren(
newParam->setFullType(newType);
newParam->sourceLoc = oldParam->sourceLoc;
}
+
+ if (auto oldAsSpec = as<IRSpecialize>(oldInst))
+ {
+ specializeLinkageDecoration(newInst, oldAsSpec, builder);
+ }
}
// The public version of `cloneInstDecorationsAndChildren` is then
diff --git a/source/slang/slang-mangle.cpp b/source/slang/slang-mangle.cpp
index 12e185c8b..63dfffb94 100644
--- a/source/slang/slang-mangle.cpp
+++ b/source/slang/slang-mangle.cpp
@@ -31,7 +31,7 @@ void emit(ManglingContext* context, String const& value)
context->sb.append(value);
}
-void emitNameImpl(ManglingContext* context, UnownedStringSlice str)
+void emitNameForLinkage(StringBuilder& sb, UnownedStringSlice str)
{
Index length = str.getLength();
// If the name consists of only traditional "identifer characters"
@@ -61,8 +61,8 @@ void emitNameImpl(ManglingContext* context, UnownedStringSlice str)
// code points and the number of extended grapheme clusters,
// since the entire name is within the ASCII subset.
//
- emit(context, length);
- context->sb.append(str);
+ sb.append(length);
+ sb.append(str);
}
else
{
@@ -98,9 +98,9 @@ void emitNameImpl(ManglingContext* context, UnownedStringSlice str)
}
}
- context->sb.append("R");
- emit(context, encoded.getLength());
- context->sb.append(encoded);
+ sb.append("R");
+ sb.append(encoded.getLength());
+ sb.append(encoded);
}
// TODO: This logic does not rule out consecutive underscores,
@@ -111,6 +111,11 @@ void emitNameImpl(ManglingContext* context, UnownedStringSlice str)
// target, rather than adding complexity here.
}
+void emitNameImpl(ManglingContext* context, UnownedStringSlice str)
+{
+ emitNameForLinkage(context->sb, str);
+}
+
void emitName(ManglingContext* context, Name* name)
{
String str = getText(name);
diff --git a/source/slang/slang-mangle.h b/source/slang/slang-mangle.h
index cfdbe461b..079f7c02d 100644
--- a/source/slang/slang-mangle.h
+++ b/source/slang/slang-mangle.h
@@ -10,6 +10,8 @@ namespace Slang
{
struct IRSpecialize;
+void emitNameForLinkage(StringBuilder& sb, UnownedStringSlice str);
+
String getMangledName(ASTBuilder* astBuilder, Decl* decl);
String getMangledName(ASTBuilder* astBuilder, DeclRefBase* declRef);
String getMangledNameFromNameString(const UnownedStringSlice& name);
diff --git a/tests/language-feature/generics/generic-interface-linkage.slang b/tests/language-feature/generics/generic-interface-linkage.slang
new file mode 100644
index 000000000..657ac3d48
--- /dev/null
+++ b/tests/language-feature/generics/generic-interface-linkage.slang
@@ -0,0 +1,81 @@
+
+//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-slang -compute -shaderobj -output-using-type
+//TEST(compute, vulkan):COMPARE_COMPUTE(filecheck-buffer=CHECK):-vk -compute -shaderobj -output-using-type
+
+//TEST_INPUT:ubuffer(data=[0 0 0 0 0], stride=4):out,name=outputBuffer
+RWStructuredBuffer<float> outputBuffer;
+
+interface IGetter
+{
+ float get(uint id);
+}
+
+struct GetterImpl : IGetter
+{
+ float[8] data;
+
+ __init(float[8] data)
+ { this.data = data; }
+
+ float get(uint id)
+ {
+ return data[id];
+ }
+}
+interface IFoo<int N>
+{
+ associatedtype Params : IGetter;
+
+ Params bar();
+}
+
+struct FooImpl1: IFoo<8>
+{
+ typealias Params = GetterImpl;
+
+ __init()
+ { }
+
+ Params bar()
+ {
+ float x = outputBuffer[0];
+ return GetterImpl({x, x+1, x+2, x+3, x+4, x+5, x+6, x+7});
+ }
+}
+
+struct FooImpl2: IFoo<8>
+{
+ typealias Params = GetterImpl;
+
+ __init()
+ { }
+
+ Params bar()
+ {
+ float x = 2 * outputBuffer[0];
+ return GetterImpl({x+3, x+5, x+7, x+9, x+11, x+13, x+15, x+17});
+ }
+}
+
+IFoo<8> getFoo(uint id)
+{
+ if (id == 0)
+ return FooImpl1();
+ else
+ return FooImpl2();
+}
+
+float doThing(uint id)
+{
+ IFoo<8> foo = getFoo(id);
+ return foo.bar().get(0);
+}
+
+[shader("compute")]
+void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID)
+{
+ // CHECK: 0
+ outputBuffer[0] = doThing(0);
+ // CHECK: 3
+ outputBuffer[1] = doThing(1);
+} \ No newline at end of file