Skip to content

Commit 6b44630

Browse files
authored
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
1 parent b4a1d61 commit 6b44630

File tree

4 files changed

+157
-6
lines changed

4 files changed

+157
-6
lines changed

source/slang/slang-ir-clone.cpp

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@
22
#include "slang-ir-clone.h"
33

44
#include "slang-ir-insts.h"
5+
#include "slang-ir-util.h"
56
#include "slang-ir.h"
7+
#include "slang-mangle.h"
8+
69

710
namespace Slang
811
{
@@ -104,6 +107,61 @@ IRInst* cloneInstAndOperands(IRCloneEnv* env, IRBuilder* builder, IRInst* oldIns
104107
return newInst;
105108
}
106109

110+
// Copy the linkage decoration of oldInst (if present) and specialize it for target.
111+
static void specializeLinkageDecoration(IRInst* target, IRSpecialize* oldInst, IRBuilder* builder)
112+
{
113+
auto gen = as<IRGeneric>(oldInst->getBase());
114+
if (gen)
115+
{
116+
auto genLinkage = gen->findDecoration<IRLinkageDecoration>();
117+
if (genLinkage)
118+
{
119+
bool isExport = as<IRExportDecoration>(genLinkage);
120+
StringBuilder sb;
121+
sb.append(genLinkage->getMangledName());
122+
sb.append("G");
123+
IRSpecialize* specializationProvider = oldInst;
124+
if (auto targetAsSpec = as<IRSpecialize>(target))
125+
{
126+
specializationProvider = targetAsSpec;
127+
}
128+
for (UInt i = 0; i < specializationProvider->getArgCount(); ++i)
129+
{
130+
auto arg = specializationProvider->getArg(i);
131+
sb.append(i);
132+
if (auto typeLinkage = arg->findDecoration<IRLinkageDecoration>())
133+
{
134+
sb.append(typeLinkage->getMangledName());
135+
}
136+
else
137+
{
138+
// getTypeNameHint may produce a name with characters that can't
139+
// be part of an identifier, so we need to filter it afterward.
140+
StringBuilder tmp;
141+
getTypeNameHint(tmp, arg);
142+
emitNameForLinkage(sb, tmp.getUnownedSlice());
143+
}
144+
}
145+
if (auto previousLinkage = target->findDecoration<IRLinkageDecoration>())
146+
{
147+
// Overwrite the previous linkage decoration, since it was not specialized
148+
previousLinkage->setOperand(0, builder->getStringValue(sb.getUnownedSlice()));
149+
}
150+
else
151+
{
152+
if (isExport)
153+
{
154+
builder->addExportDecoration(target, sb.getUnownedSlice());
155+
}
156+
else
157+
{
158+
builder->addImportDecoration(target, sb.getUnownedSlice());
159+
}
160+
}
161+
}
162+
}
163+
}
164+
107165
// The complexity of the second phase of cloning (the
108166
// one that deals with decorations and children) comes
109167
// from the fact that it needs to sequence the two phases
@@ -226,6 +284,11 @@ static void _cloneInstDecorationsAndChildren(
226284
newParam->setFullType(newType);
227285
newParam->sourceLoc = oldParam->sourceLoc;
228286
}
287+
288+
if (auto oldAsSpec = as<IRSpecialize>(oldInst))
289+
{
290+
specializeLinkageDecoration(newInst, oldAsSpec, builder);
291+
}
229292
}
230293

231294
// The public version of `cloneInstDecorationsAndChildren` is then

source/slang/slang-mangle.cpp

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ void emit(ManglingContext* context, String const& value)
3131
context->sb.append(value);
3232
}
3333

34-
void emitNameImpl(ManglingContext* context, UnownedStringSlice str)
34+
void emitNameForLinkage(StringBuilder& sb, UnownedStringSlice str)
3535
{
3636
Index length = str.getLength();
3737
// If the name consists of only traditional "identifer characters"
@@ -61,8 +61,8 @@ void emitNameImpl(ManglingContext* context, UnownedStringSlice str)
6161
// code points and the number of extended grapheme clusters,
6262
// since the entire name is within the ASCII subset.
6363
//
64-
emit(context, length);
65-
context->sb.append(str);
64+
sb.append(length);
65+
sb.append(str);
6666
}
6767
else
6868
{
@@ -98,9 +98,9 @@ void emitNameImpl(ManglingContext* context, UnownedStringSlice str)
9898
}
9999
}
100100

101-
context->sb.append("R");
102-
emit(context, encoded.getLength());
103-
context->sb.append(encoded);
101+
sb.append("R");
102+
sb.append(encoded.getLength());
103+
sb.append(encoded);
104104
}
105105

106106
// TODO: This logic does not rule out consecutive underscores,
@@ -111,6 +111,11 @@ void emitNameImpl(ManglingContext* context, UnownedStringSlice str)
111111
// target, rather than adding complexity here.
112112
}
113113

114+
void emitNameImpl(ManglingContext* context, UnownedStringSlice str)
115+
{
116+
emitNameForLinkage(context->sb, str);
117+
}
118+
114119
void emitName(ManglingContext* context, Name* name)
115120
{
116121
String str = getText(name);

source/slang/slang-mangle.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ namespace Slang
1010
{
1111
struct IRSpecialize;
1212

13+
void emitNameForLinkage(StringBuilder& sb, UnownedStringSlice str);
14+
1315
String getMangledName(ASTBuilder* astBuilder, Decl* decl);
1416
String getMangledName(ASTBuilder* astBuilder, DeclRefBase* declRef);
1517
String getMangledNameFromNameString(const UnownedStringSlice& name);
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
2+
//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-slang -compute -shaderobj -output-using-type
3+
//TEST(compute, vulkan):COMPARE_COMPUTE(filecheck-buffer=CHECK):-vk -compute -shaderobj -output-using-type
4+
5+
//TEST_INPUT:ubuffer(data=[0 0 0 0 0], stride=4):out,name=outputBuffer
6+
RWStructuredBuffer<float> outputBuffer;
7+
8+
interface IGetter
9+
{
10+
float get(uint id);
11+
}
12+
13+
struct GetterImpl : IGetter
14+
{
15+
float[8] data;
16+
17+
__init(float[8] data)
18+
{ this.data = data; }
19+
20+
float get(uint id)
21+
{
22+
return data[id];
23+
}
24+
}
25+
interface IFoo<int N>
26+
{
27+
associatedtype Params : IGetter;
28+
29+
Params bar();
30+
}
31+
32+
struct FooImpl1: IFoo<8>
33+
{
34+
typealias Params = GetterImpl;
35+
36+
__init()
37+
{ }
38+
39+
Params bar()
40+
{
41+
float x = outputBuffer[0];
42+
return GetterImpl({x, x+1, x+2, x+3, x+4, x+5, x+6, x+7});
43+
}
44+
}
45+
46+
struct FooImpl2: IFoo<8>
47+
{
48+
typealias Params = GetterImpl;
49+
50+
__init()
51+
{ }
52+
53+
Params bar()
54+
{
55+
float x = 2 * outputBuffer[0];
56+
return GetterImpl({x+3, x+5, x+7, x+9, x+11, x+13, x+15, x+17});
57+
}
58+
}
59+
60+
IFoo<8> getFoo(uint id)
61+
{
62+
if (id == 0)
63+
return FooImpl1();
64+
else
65+
return FooImpl2();
66+
}
67+
68+
float doThing(uint id)
69+
{
70+
IFoo<8> foo = getFoo(id);
71+
return foo.bar().get(0);
72+
}
73+
74+
[shader("compute")]
75+
void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID)
76+
{
77+
// CHECK: 0
78+
outputBuffer[0] = doThing(0);
79+
// CHECK: 3
80+
outputBuffer[1] = doThing(1);
81+
}

0 commit comments

Comments
 (0)