Skip to content

Commit b820f34

Browse files
authored
Support initializing an existential value from a generic value. (shader-slang#1503)
* Support initializing an existential value from a generic value. * Remove trailing spaces and clean up debugging code.
1 parent 9abcb6e commit b820f34

21 files changed

+402
-102
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
*.sdf
88
*.ilk
99
*.obj
10+
.clang-format
1011
bin/
1112
intermediate/
1213
build.*/

source/slang/slang-ir-any-value-marshalling.cpp

+7-13
Original file line numberDiff line numberDiff line change
@@ -448,24 +448,18 @@ namespace Slang
448448

449449
sharedContext->addToWorkList(sharedContext->module->getModuleInst());
450450

451-
// Process all instructions and translate all `IRPackAnyValue` and `IRUnpackAnyValue`.
452451
while (sharedContext->workList.getCount() != 0)
453452
{
454-
// We will then iterate until our work list goes dry.
455-
//
456-
while (sharedContext->workList.getCount() != 0)
457-
{
458-
IRInst* inst = sharedContext->workList.getLast();
453+
IRInst* inst = sharedContext->workList.getLast();
459454

460-
sharedContext->workList.removeLast();
461-
sharedContext->workListSet.Remove(inst);
455+
sharedContext->workList.removeLast();
456+
sharedContext->workListSet.Remove(inst);
462457

463-
processInst(inst);
458+
processInst(inst);
464459

465-
for (auto child = inst->getLastChild(); child; child = child->getPrevInst())
466-
{
467-
sharedContext->addToWorkList(child);
468-
}
460+
for (auto child = inst->getLastChild(); child; child = child->getPrevInst())
461+
{
462+
sharedContext->addToWorkList(child);
469463
}
470464
}
471465

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
#include "slang-ir-augment-make-existential.h"
2+
#include "slang-ir-insts.h"
3+
#include "slang-ir.h"
4+
5+
namespace Slang
6+
{
7+
struct AugmentMakeExistentialContext
8+
{
9+
IRModule* module;
10+
11+
SharedIRBuilder sharedBuilderStorage;
12+
13+
List<IRInst*> workList;
14+
HashSet<IRInst*> workListSet;
15+
16+
void addToWorkList(IRInst* inst)
17+
{
18+
if (workListSet.Contains(inst))
19+
return;
20+
21+
workList.add(inst);
22+
workListSet.Add(inst);
23+
}
24+
25+
void processMakeExistential(IRMakeExistential* inst)
26+
{
27+
IRBuilder builderStorage;
28+
auto builder = &builderStorage;
29+
builder->sharedBuilder = &sharedBuilderStorage;
30+
builder->setInsertBefore(inst);
31+
32+
auto augInst = builder->emitMakeExistentialWithRTTI(
33+
inst->getFullType(),
34+
inst->getWrappedValue(),
35+
inst->getWitnessTable(),
36+
inst->getWrappedValue()->getDataType());
37+
inst->replaceUsesWith(augInst);
38+
inst->removeAndDeallocate();
39+
}
40+
41+
void processInst(IRInst* inst)
42+
{
43+
switch (inst->op)
44+
{
45+
case kIROp_MakeExistential:
46+
processMakeExistential((IRMakeExistential*)inst);
47+
break;
48+
default:
49+
break;
50+
}
51+
}
52+
53+
void processModule()
54+
{
55+
SharedIRBuilder* sharedBuilder = &sharedBuilderStorage;
56+
sharedBuilder->module = module;
57+
sharedBuilder->session = module->session;
58+
59+
addToWorkList(module->getModuleInst());
60+
61+
while (workList.getCount() != 0)
62+
{
63+
IRInst* inst = workList.getLast();
64+
65+
workList.removeLast();
66+
workListSet.Remove(inst);
67+
68+
processInst(inst);
69+
70+
for (auto child = inst->getLastChild(); child; child = child->getPrevInst())
71+
{
72+
addToWorkList(child);
73+
}
74+
}
75+
}
76+
};
77+
78+
void augmentMakeExistentialInsts(IRModule* module)
79+
{
80+
AugmentMakeExistentialContext context;
81+
context.module = module;
82+
context.processModule();
83+
}
84+
} // namespace Slang
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// slang-ir-augment-make-existential.h
2+
#pragma once
3+
4+
#include "slang-ir.h"
5+
6+
namespace Slang
7+
{
8+
struct IRModule;
9+
class DiagnosticSink;
10+
11+
/// Augment `MakeExistential(v, w)` insts to `MakeExistentialWithRTTI(v, w, t)`,
12+
/// where v is a concrete typed value, w is a witness table, and t is the type of
13+
/// v.
14+
void augmentMakeExistentialInsts(IRModule* module);
15+
16+
} // namespace Slang

source/slang/slang-ir-generics-lowering-context.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,8 @@ namespace Slang
135135
switch (paramType->op)
136136
{
137137
case kIROp_WitnessTableType:
138-
// Do not translate witness table type.
138+
case kIROp_ExtractExistentialType:
139+
// Do not translate these types.
139140
return (IRType*)paramType;
140141
case kIROp_Param:
141142
{
+111
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
#include "slang-ir-hoist-local-types.h"
2+
3+
#include "slang-ir-insts.h"
4+
#include "slang-ir.h"
5+
6+
namespace Slang
7+
{
8+
struct HoistLocalTypesContext
9+
{
10+
IRModule* module;
11+
DiagnosticSink* sink;
12+
13+
SharedIRBuilder sharedBuilderStorage;
14+
15+
List<IRInst*> workList;
16+
HashSet<IRInst*> workListSet;
17+
18+
void addToWorkList(IRInst* inst)
19+
{
20+
for (auto ii = inst->getParent(); ii; ii = ii->getParent())
21+
{
22+
if (as<IRGeneric>(ii))
23+
return;
24+
}
25+
26+
if (workListSet.Contains(inst))
27+
return;
28+
29+
workList.add(inst);
30+
workListSet.Add(inst);
31+
}
32+
33+
void processInst(IRInst* inst)
34+
{
35+
auto sharedBuilder = &sharedBuilderStorage;
36+
if (!as<IRType>(inst))
37+
return;
38+
if (inst->getParent() == module->getModuleInst())
39+
return;
40+
IRInstKey key = {inst};
41+
if (auto value = sharedBuilder->globalValueNumberingMap.TryGetValue(key))
42+
{
43+
inst->replaceUsesWith(*value);
44+
inst->removeAndDeallocate();
45+
return;
46+
}
47+
IRBuilder builder;
48+
builder.sharedBuilder = sharedBuilder;
49+
builder.setInsertInto(module->getModuleInst());
50+
bool hoistable = true;
51+
ShortList<IRInst*> mappedOperands;
52+
for (UInt i = 0; i < inst->getOperandCount(); i++)
53+
{
54+
IRInstKey opKey = {inst->getOperand(i)};
55+
if (auto value = sharedBuilder->globalValueNumberingMap.TryGetValue(opKey))
56+
{
57+
mappedOperands.add(*value);
58+
}
59+
else
60+
{
61+
hoistable = false;
62+
break;
63+
}
64+
}
65+
if (hoistable)
66+
{
67+
auto newType = builder.getType(
68+
inst->op, mappedOperands.getCount(), mappedOperands.getArrayView().getBuffer());
69+
inst->transferDecorationsTo(newType);
70+
inst->replaceUsesWith(newType);
71+
inst->removeAndDeallocate();
72+
}
73+
}
74+
75+
void processModule()
76+
{
77+
SharedIRBuilder* sharedBuilder = &sharedBuilderStorage;
78+
sharedBuilder->module = module;
79+
sharedBuilder->session = module->session;
80+
81+
// Deduplicate equivalent types and build numbering map for global types.
82+
sharedBuilder->deduplicateAndRebuildGlobalNumberingMap();
83+
84+
addToWorkList(module->getModuleInst());
85+
86+
while (workList.getCount() != 0)
87+
{
88+
IRInst* inst = workList.getLast();
89+
90+
workList.removeLast();
91+
workListSet.Remove(inst);
92+
93+
processInst(inst);
94+
95+
for (auto child = inst->getLastChild(); child; child = child->getPrevInst())
96+
{
97+
addToWorkList(child);
98+
}
99+
}
100+
}
101+
};
102+
103+
void hoistLocalTypes(IRModule* module, DiagnosticSink* sink)
104+
{
105+
HoistLocalTypesContext context;
106+
context.module = module;
107+
context.sink = sink;
108+
context.processModule();
109+
}
110+
111+
} // namespace Slang
+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// slang-ir-hoist-local-types.h
2+
#pragma once
3+
4+
#include "slang-ir.h"
5+
6+
namespace Slang
7+
{
8+
struct IRModule;
9+
class DiagnosticSink;
10+
11+
/// Hoist local types to global scope if possible.
12+
/// Some transformation passes may leave behind local type definitons that
13+
/// can be hoisted to global scope. This pass examines all local type defintions
14+
// and try to hoist them to global scope if the definition is no longer dependent on
15+
// the local context.
16+
void hoistLocalTypes(IRModule* module, DiagnosticSink* sink);
17+
18+
} // namespace Slang

source/slang/slang-ir-inst-defs.h

+4
Original file line numberDiff line numberDiff line change
@@ -573,6 +573,10 @@ INST(HighLevelDeclDecoration, highLevelDecl, 1, 0)
573573
// shows that `C` conforms to `I`.
574574
//
575575
INST(MakeExistential, makeExistential, 2, 0)
576+
// A `MakeExistentialWithRTTI(v, w, t)` is the same with `MakeExistential`,
577+
// but with the type of `v` being an explict operand.
578+
INST(MakeExistentialWithRTTI, makeExistentialWithRTTI, 3, 0)
579+
576580

577581
// A `wrapExistential(v, T0,w0, T1,w0) : T` instruction is similar to `makeExistential`.
578582
// but applies to a value `v` that is of type `BindExistentials(T, T0,w0, ...)`. The

source/slang/slang-ir-insts.h

+16
Original file line numberDiff line numberDiff line change
@@ -1590,6 +1590,16 @@ struct IRMakeExistential : IRInst
15901590
IR_LEAF_ISA(MakeExistential)
15911591
};
15921592

1593+
struct IRMakeExistentialWithRTTI : IRInst
1594+
{
1595+
IRInst* getWrappedValue() { return getOperand(0); }
1596+
IRInst* getWitnessTable() { return getOperand(1); }
1597+
IRInst* getRTTI() { return getOperand(2); }
1598+
1599+
1600+
IR_LEAF_ISA(MakeExistentialWithRTTI)
1601+
};
1602+
15931603
/// Generalizes `IRMakeExistential` by allowing a type with existential sub-fields to be boxed
15941604
struct IRWrapExistential : IRInst
15951605
{
@@ -1927,6 +1937,12 @@ struct IRBuilder
19271937
IRInst* value,
19281938
IRInst* witnessTable);
19291939

1940+
IRInst* emitMakeExistentialWithRTTI(
1941+
IRType* type,
1942+
IRInst* value,
1943+
IRInst* witnessTable,
1944+
IRInst* rtti);
1945+
19301946
IRInst* emitWrapExistential(
19311947
IRType* type,
19321948
IRInst* value,

source/slang/slang-ir-lower-existential.cpp

+13-24
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ namespace Slang
1111
{
1212
SharedGenericsLoweringContext* sharedContext;
1313

14-
void processMakeExistential(IRMakeExistential* inst)
14+
void processMakeExistential(IRMakeExistentialWithRTTI* inst)
1515
{
1616
IRBuilder builderStorage;
1717
auto builder = &builderStorage;
@@ -27,17 +27,11 @@ namespace Slang
2727
auto rttiType = builder->getPtrType(builder->getRTTIType());
2828
auto tupleType = builder->getTupleType(anyValueType, witnessTableType, rttiType);
2929

30-
IRInst* rttiObject = nullptr;
31-
if (valueType->op != kIROp_AnyValueType)
32-
{
33-
rttiObject = sharedContext->maybeEmitRTTIObject(valueType);
34-
rttiObject = builder->emitGetAddress(
35-
builder->getPtrType(builder->getRTTIType()),
36-
rttiObject);
37-
}
38-
else
30+
IRInst* rttiObject = inst->getRTTI();
31+
if (auto type = as<IRType>(rttiObject))
3932
{
40-
rttiObject = valueType;
33+
rttiObject = sharedContext->maybeEmitRTTIObject(type);
34+
rttiObject = builder->emitGetAddress(rttiType, rttiObject);
4135
}
4236
IRInst* packedValue = value;
4337
if (valueType->op != kIROp_AnyValueType)
@@ -87,7 +81,7 @@ namespace Slang
8781

8882
void processInst(IRInst* inst)
8983
{
90-
if (auto makeExistential = as<IRMakeExistential>(inst))
84+
if (auto makeExistential = as<IRMakeExistentialWithRTTI>(inst))
9185
{
9286
processMakeExistential(makeExistential);
9387
}
@@ -119,21 +113,16 @@ namespace Slang
119113

120114
while (sharedContext->workList.getCount() != 0)
121115
{
122-
// We will then iterate until our work list goes dry.
123-
//
124-
while (sharedContext->workList.getCount() != 0)
125-
{
126-
IRInst* inst = sharedContext->workList.getLast();
116+
IRInst* inst = sharedContext->workList.getLast();
127117

128-
sharedContext->workList.removeLast();
129-
sharedContext->workListSet.Remove(inst);
118+
sharedContext->workList.removeLast();
119+
sharedContext->workListSet.Remove(inst);
130120

131-
processInst(inst);
121+
processInst(inst);
132122

133-
for (auto child = inst->getLastChild(); child; child = child->getPrevInst())
134-
{
135-
sharedContext->addToWorkList(child);
136-
}
123+
for (auto child = inst->getLastChild(); child; child = child->getPrevInst())
124+
{
125+
sharedContext->addToWorkList(child);
137126
}
138127
}
139128
}

0 commit comments

Comments
 (0)