@@ -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