Skip to content

Commit 4530af9

Browse files
committed
Rewrite rewriteValueUsesToAddrUses()
1 parent 589fda5 commit 4530af9

File tree

1 file changed

+88
-95
lines changed

1 file changed

+88
-95
lines changed

source/slang/slang-ir-transform-params-to-constref.cpp

Lines changed: 88 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -45,130 +45,123 @@ struct TransformParamsToConstRefContext
4545
{
4646
// The overall strategy here is as follows:
4747
//
48-
// Phase 1
49-
// - Add IRLoad in front of the uses of newAddrInst, since the users need the
50-
// value of the address. Except:
51-
// - In case the user is IRFieldExtract/IRGetElement, rewrite those as
52-
// IRFieldAddress and IRGetElementPtr and consume the base pointer as is
53-
// - Scan transitively the uses of the transformed ops, and add IRLoad
54-
// in front of them as well.
55-
//
56-
// Phase 2
57-
// - Check all translated IRGetElementPtr instructions. If the index is
58-
// a newly translated IRGetElementPtr or IRFieldAddress, add an IRLoad
59-
// to fetch the value of the pointer. This insertion of load may have
60-
// been omitted in Phase 1 due to the exception.
61-
// - Note that doing a separate phase avoids problems with IR
62-
// op rewrite ordering, since all rewrites are already done in Phase 1
63-
//
64-
// In addition, IRStore instructions are also attempted to be
65-
// optimized. See the related comment below.
66-
67-
HashSet<IRInst*> workListSet;
68-
workListSet.add(newAddrInst);
69-
List<IRInst*> workList;
70-
workList.add(newAddrInst);
48+
// - First, insert IRLoad() in front of all uses of newAddrInst. This
49+
// is a value parameter turned into pointer to value. Add all IRLoad()
50+
// instructions in the working set
51+
// - Then, for every inserted IRLoad() instruction, search for
52+
// IRFieldExtract(IRLoad(ptr), ...) and IRGetElement(IRLoad(ptr), ...) patterns,
53+
// and transform these to IRLoad(IRFieldAddress(ptr, ...)) and
54+
// IRLoad(IRGetElementPtr(ptr, ...)), and insert the new IRLoad()
55+
// instructions in the working set
56+
// - Remove also stores to write-once temporary variables that are
57+
// immediately passed into a constref location in a call (see below)
58+
// - If all uses of the inserted IRLoad() were translated, remove the
59+
// IRLoad() to keep this pass clean
60+
61+
List<IRLoad*> workList;
62+
63+
traverseUses(
64+
newAddrInst,
65+
[&](IRUse* use)
66+
{
67+
auto user = use->getUser();
68+
builder.setInsertBefore(user);
69+
IRLoad* loadInst = as<IRLoad>(builder.emitLoad(newAddrInst));
70+
use->set(loadInst);
7171

72-
// List of IR instructions that may require a fixup after the rewrite
73-
// pass. In particular, the index of IRGetElementPtr might use another
74-
// IRGetElementPtr or IRFieldAddress, in which case we need to load the
75-
// value of the pointer
76-
List<IRInst*> postFixList;
72+
workList.add(loadInst);
73+
});
7774

78-
auto _addToWorkList = [&](IRInst* inst)
79-
{
80-
if (workListSet.add(inst))
81-
workList.add(inst);
82-
};
8375
for (Index i = 0; i < workList.getCount(); i++)
8476
{
85-
auto inst = workList[i];
77+
IRLoad* loadInst = workList[i];
78+
bool allUsesTranslated = true;
79+
8680
traverseUses(
87-
inst,
81+
loadInst,
8882
[&](IRUse* use)
8983
{
90-
auto user = use->getUser();
91-
if (workListSet.contains(user))
92-
return;
93-
switch (user->getOp())
84+
IRInst* userInst = use->getUser();
85+
bool useTranslated = false;
86+
87+
switch (userInst->getOp())
9488
{
9589
case kIROp_FieldExtract:
9690
{
97-
// Transform the IRFieldExtract into a IRFieldAddress
98-
if (!isUseBaseAddrOperand(use, user))
99-
break;
100-
auto fieldExtract = as<IRFieldExtract>(user);
101-
builder.setInsertBefore(fieldExtract);
102-
auto fieldAddr = builder.emitFieldAddress(
103-
fieldExtract->getBase(),
104-
fieldExtract->getField());
105-
fieldExtract->replaceUsesWith(fieldAddr);
106-
_addToWorkList(fieldAddr);
107-
return;
91+
if (isUseBaseAddrOperand(use, userInst))
92+
{
93+
// Transform IRFieldExtract(IRLoad(ptr), x)
94+
// ==>
95+
// IRLoad(IRFieldAddr(ptr), x)
96+
97+
auto fieldExtract = as<IRFieldExtract>(userInst);
98+
builder.setInsertBefore(fieldExtract);
99+
auto fieldAddr = builder.emitFieldAddress(
100+
loadInst->getPtr(),
101+
fieldExtract->getField());
102+
auto loadFieldAddr = as<IRLoad>(builder.emitLoad(fieldAddr));
103+
fieldExtract->replaceUsesWith(loadFieldAddr);
104+
fieldExtract->removeAndDeallocate();
105+
106+
workList.add(loadFieldAddr);
107+
useTranslated = true;
108+
}
109+
break;
108110
}
111+
109112
case kIROp_GetElement:
110113
{
111-
// Transform the IRGetElement into a IRGetElementPtr
112-
if (!isUseBaseAddrOperand(use, user))
113-
break;
114-
auto getElement = as<IRGetElement>(user);
115-
builder.setInsertBefore(getElement);
116-
auto elemAddr = builder.emitElementAddress(
117-
getElement->getBase(),
118-
getElement->getIndex());
119-
getElement->replaceUsesWith(elemAddr);
120-
_addToWorkList(elemAddr);
121-
postFixList.add(elemAddr);
122-
return;
114+
if (isUseBaseAddrOperand(use, userInst))
115+
{
116+
// Transform IRGetElement(IRLoad(ptr), x)
117+
// ==>
118+
// IRLoad(IRGetElementPtr(ptr), x)
119+
120+
auto getElement = as<IRGetElement>(userInst);
121+
builder.setInsertBefore(getElement);
122+
auto getElementPtr = builder.emitElementAddress(
123+
loadInst->getPtr(),
124+
getElement->getIndex());
125+
auto loadElementPtr = as<IRLoad>(builder.emitLoad(getElementPtr));
126+
getElement->replaceUsesWith(loadElementPtr);
127+
getElement->removeAndDeallocate();
128+
129+
workList.add(loadElementPtr);
130+
useTranslated = true;
131+
}
132+
break;
123133
}
134+
124135
case kIROp_Store:
125136
{
126137
// If the current value is being stored into a write-once temp var that
127138
// is immediately passed into a constref location in a call, we can get
128139
// rid of the temp var and replace it with `inst` directly.
129140
// (such temp var can be introduced during `updateCallSites` when we
130141
// were processing the callee.)
142+
143+
// Transform IRStore(ptr, load(x)) where ptr has kIROp_TempCallArgImmutableVarDecoration
144+
// IRCall(func, ptr, ...)
131145
//
132-
auto dest = as<IRStore>(user)->getPtr();
133-
if (dest->findDecorationImpl(kIROp_TempCallArgImmutableVarDecoration))
146+
// ==> IRCall(func, x, ...)
147+
148+
auto storeDest = as<IRStore>(userInst)->getPtr();
149+
if (storeDest->findDecorationImpl(kIROp_TempCallArgImmutableVarDecoration))
134150
{
135-
user->removeAndDeallocate();
136-
dest->replaceUsesWith(inst);
137-
dest->removeAndDeallocate();
138-
return;
151+
storeDest->replaceUsesWith(loadInst->getPtr());
152+
userInst->removeAndDeallocate();
153+
storeDest->removeAndDeallocate();
154+
useTranslated = true;
139155
}
140156
break;
141157
}
142158
}
143-
// Insert a load before the user and replace the user with the load
144-
builder.setInsertBefore(user);
145-
auto loadInst = builder.emitLoad(inst);
146-
use->set(loadInst);
159+
160+
allUsesTranslated = allUsesTranslated && useTranslated;
147161
});
148-
}
149162

150-
for (IRInst* inst : postFixList)
151-
{
152-
auto getElementPtr = as<IRGetElementPtr>(inst);
153-
IRInst* indexInst = getElementPtr->getOperand(1);
154-
155-
// We'll only consider index instructions if they were transformed
156-
// previously by this function. This is an extra precaution to avoid
157-
// hiding bugs by other passes, should they also pass pointers
158-
// directly as the IRGetElementPtr index.
159-
if (workListSet.contains(indexInst))
160-
{
161-
switch (indexInst->getOp())
162-
{
163-
case kIROp_FieldAddress:
164-
case kIROp_GetElementPtr:
165-
// additional IRLoad() needed
166-
builder.setInsertBefore(getElementPtr);
167-
auto loadInst = builder.emitLoad(indexInst);
168-
getElementPtr->setOperand(1, loadInst);
169-
break;
170-
}
171-
}
163+
if (allUsesTranslated)
164+
loadInst->removeAndDeallocate();
172165
}
173166
}
174167

0 commit comments

Comments
 (0)