@@ -77,6 +77,232 @@ struct LLVMPointerPointerLikeModel
7777};
7878} // namespace
7979
80+ // / Generate a name of a canonical loop nest of the format
81+ // / `<prefix>(_r<idx>_s<idx>)*`. Hereby, `_r<idx>` identifies the region
82+ // / argument index of an operation that has multiple regions, if the operation
83+ // / has multiple regions.
84+ // / `_s<idx>` identifies the position of an operation within a region, where
85+ // / only operations that may potentially contain loops ("container operations"
86+ // / i.e. have region arguments) are counted. Again, it is omitted if there is
87+ // / only one such operation in a region. If there are canonical loops nested
88+ // / inside each other, also may also use the format `_d<num>` where <num> is the
89+ // / nesting depth of the loop.
90+ // /
91+ // / The generated name is a best-effort to make canonical loop unique within an
92+ // / SSA namespace. This also means that regions with IsolatedFromAbove property
93+ // / do not consider any parents or siblings.
94+ static std::string generateLoopNestingName (StringRef prefix,
95+ CanonicalLoopOp op) {
96+ struct Component {
97+ // / If true, this component describes a region operand of an operation (the
98+ // / operand's owner) If false, this component describes an operation located
99+ // / in a parent region
100+ bool isRegionArgOfOp;
101+ bool skip = false ;
102+ bool isUnique = false ;
103+
104+ size_t idx;
105+ Operation *op;
106+ Region *parentRegion;
107+ size_t loopDepth;
108+
109+ Operation *&getOwnerOp () {
110+ assert (isRegionArgOfOp && " Must describe a region operand" );
111+ return op;
112+ }
113+ size_t &getArgIdx () {
114+ assert (isRegionArgOfOp && " Must describe a region operand" );
115+ return idx;
116+ }
117+
118+ Operation *&getContainerOp () {
119+ assert (!isRegionArgOfOp && " Must describe a operation of a region" );
120+ return op;
121+ }
122+ size_t &getOpPos () {
123+ assert (!isRegionArgOfOp && " Must describe a operation of a region" );
124+ return idx;
125+ }
126+ bool isLoopOp () const {
127+ assert (!isRegionArgOfOp && " Must describe a operation of a region" );
128+ return isa<CanonicalLoopOp>(op);
129+ }
130+ Region *&getParentRegion () {
131+ assert (!isRegionArgOfOp && " Must describe a operation of a region" );
132+ return parentRegion;
133+ }
134+ size_t &getLoopDepth () {
135+ assert (!isRegionArgOfOp && " Must describe a operation of a region" );
136+ return loopDepth;
137+ }
138+
139+ void skipIf (bool v = true ) { skip = skip || v; }
140+ };
141+
142+ // List of ancestors, from inner to outer.
143+ // Alternates between
144+ // * region argument of an operation
145+ // * operation within a region
146+ SmallVector<Component> components;
147+
148+ // Gather a list of parent regions and operations, and the position within
149+ // their parent
150+ Operation *o = op.getOperation ();
151+ while (o) {
152+ // Operation within a region
153+ Region *r = o->getParentRegion ();
154+ if (!r)
155+ break ;
156+
157+ llvm::ReversePostOrderTraversal<Block *> traversal (&r->getBlocks ().front ());
158+ size_t idx = 0 ;
159+ bool found = false ;
160+ size_t sequentialIdx = -1 ;
161+ bool isOnlyContainerOp = true ;
162+ for (Block *b : traversal) {
163+ for (Operation &op : *b) {
164+ if (&op == o && !found) {
165+ sequentialIdx = idx;
166+ found = true ;
167+ }
168+ if (op.getNumRegions ()) {
169+ idx += 1 ;
170+ if (idx > 1 )
171+ isOnlyContainerOp = false ;
172+ }
173+ if (found && !isOnlyContainerOp)
174+ break ;
175+ }
176+ }
177+
178+ Component &containerOpInRegion = components.emplace_back ();
179+ containerOpInRegion.isRegionArgOfOp = false ;
180+ containerOpInRegion.isUnique = isOnlyContainerOp;
181+ containerOpInRegion.getContainerOp () = o;
182+ containerOpInRegion.getOpPos () = sequentialIdx;
183+ containerOpInRegion.getParentRegion () = r;
184+
185+ Operation *parent = r->getParentOp ();
186+
187+ // Region argument of an operation
188+ Component ®ionArgOfOperation = components.emplace_back ();
189+ regionArgOfOperation.isRegionArgOfOp = true ;
190+ regionArgOfOperation.isUnique = true ;
191+ regionArgOfOperation.getArgIdx () = 0 ;
192+ regionArgOfOperation.getOwnerOp () = parent;
193+
194+ // The IsolatedFromAbove trait of the parent operation implies that each
195+ // individual region argument has its own separate namespace, so no
196+ // ambiguity.
197+ if (!parent || parent->hasTrait <mlir::OpTrait::IsIsolatedFromAbove>())
198+ break ;
199+
200+ // Component only needed if operation has multiple region operands. Region
201+ // arguments may be optional, but we currently do not consider this.
202+ if (parent->getRegions ().size () > 1 ) {
203+ auto getRegionIndex = [](Operation *o, Region *r) {
204+ for (auto [idx, region] : llvm::enumerate (o->getRegions ())) {
205+ if (®ion == r)
206+ return idx;
207+ }
208+ llvm_unreachable (" Region not child of its parent operation" );
209+ };
210+ regionArgOfOperation.isUnique = false ;
211+ regionArgOfOperation.getArgIdx () = getRegionIndex (parent, r);
212+ }
213+
214+ // next parent
215+ o = parent;
216+ }
217+
218+ // Determine whether a region-argument component is not needed
219+ for (Component &c : components)
220+ c.skipIf (c.isRegionArgOfOp && c.isUnique );
221+
222+ // Find runs of nested loops and determine each loop's depth in the loop nest
223+ size_t numSurroundingLoops = 0 ;
224+ for (Component &c : llvm::reverse (components)) {
225+ if (c.skip )
226+ continue ;
227+
228+ // non-skipped multi-argument operands interrupt the loop nest
229+ if (c.isRegionArgOfOp ) {
230+ numSurroundingLoops = 0 ;
231+ continue ;
232+ }
233+
234+ // Multiple loops in a region means each of them is the outermost loop of a
235+ // new loop nest
236+ if (!c.isUnique )
237+ numSurroundingLoops = 0 ;
238+
239+ c.getLoopDepth () = numSurroundingLoops;
240+
241+ // Next loop is surrounded by one more loop
242+ if (isa<CanonicalLoopOp>(c.getContainerOp ()))
243+ numSurroundingLoops += 1 ;
244+ }
245+
246+ // In loop nests, skip all but the innermost loop that contains the depth
247+ // number
248+ bool isLoopNest = false ;
249+ for (Component &c : components) {
250+ if (c.skip || c.isRegionArgOfOp )
251+ continue ;
252+
253+ if (!isLoopNest && c.getLoopDepth () >= 1 ) {
254+ // Innermost loop of a loop nest of at least two loops
255+ isLoopNest = true ;
256+ } else if (isLoopNest) {
257+ // Non-innermost loop of a loop nest
258+ c.skipIf (c.isUnique );
259+
260+ // If there is no surrounding loop left, this must have been the outermost
261+ // loop; leave loop-nest mode for the next iteration
262+ if (c.getLoopDepth () == 0 )
263+ isLoopNest = false ;
264+ }
265+ }
266+
267+ // Skip non-loop unambiguous regions (but they should interrupt loop nests, so
268+ // we mark them as skipped only after computing loop nests)
269+ for (Component &c : components)
270+ c.skipIf (!c.isRegionArgOfOp && c.isUnique &&
271+ !isa<CanonicalLoopOp>(c.getContainerOp ()));
272+
273+ // Components can be skipped if they are already disambiguated by their parent
274+ // (or does not have a parent)
275+ bool newRegion = true ;
276+ for (Component &c : llvm::reverse (components)) {
277+ c.skipIf (newRegion && c.isUnique );
278+
279+ // non-skipped components disambiguate unique children
280+ if (!c.skip )
281+ newRegion = true ;
282+
283+ // ...except canonical loops that need a suffix for each nest
284+ if (!c.isRegionArgOfOp && c.getContainerOp ())
285+ newRegion = false ;
286+ }
287+
288+ // Compile the nesting name string
289+ SmallString<64 > Name{prefix};
290+ llvm::raw_svector_ostream NameOS (Name);
291+ for (auto &c : llvm::reverse (components)) {
292+ if (c.skip )
293+ continue ;
294+
295+ if (c.isRegionArgOfOp )
296+ NameOS << " _r" << c.getArgIdx ();
297+ else if (c.getLoopDepth () >= 1 )
298+ NameOS << " _d" << c.getLoopDepth ();
299+ else
300+ NameOS << " _s" << c.getOpPos ();
301+ }
302+
303+ return NameOS.str ().str ();
304+ }
305+
80306void OpenMPDialect::initialize () {
81307 addOperations<
82308#define GET_OP_LIST
@@ -3172,67 +3398,7 @@ void NewCliOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
31723398 cliName =
31733399 TypeSwitch<Operation *, std::string>(gen->getOwner ())
31743400 .Case ([&](CanonicalLoopOp op) {
3175- // Find the canonical loop nesting: For each ancestor add a
3176- // "+_r<idx>" suffix (in reverse order)
3177- SmallVector<std::string> components;
3178- Operation *o = op.getOperation ();
3179- while (o) {
3180- if (o->hasTrait <mlir::OpTrait::IsIsolatedFromAbove>())
3181- break ;
3182-
3183- Region *r = o->getParentRegion ();
3184- if (!r)
3185- break ;
3186-
3187- auto getSequentialIndex = [](Region *r, Operation *o) {
3188- llvm::ReversePostOrderTraversal<Block *> traversal (
3189- &r->getBlocks ().front ());
3190- size_t idx = 0 ;
3191- for (Block *b : traversal) {
3192- for (Operation &op : *b) {
3193- if (&op == o)
3194- return idx;
3195- // Only consider operations that are containers as
3196- // possible children
3197- if (!op.getRegions ().empty ())
3198- idx += 1 ;
3199- }
3200- }
3201- llvm_unreachable (" Operation not part of the region" );
3202- };
3203- size_t sequentialIdx = getSequentialIndex (r, o);
3204- components.push_back ((" s" + Twine (sequentialIdx)).str ());
3205-
3206- Operation *parent = r->getParentOp ();
3207- if (!parent)
3208- break ;
3209-
3210- // If the operation has more than one region, also count in
3211- // which of the regions
3212- if (parent->getRegions ().size () > 1 ) {
3213- auto getRegionIndex = [](Operation *o, Region *r) {
3214- for (auto [idx, region] :
3215- llvm::enumerate (o->getRegions ())) {
3216- if (®ion == r)
3217- return idx;
3218- }
3219- llvm_unreachable (" Region not child its parent operation" );
3220- };
3221- size_t regionIdx = getRegionIndex (parent, r);
3222- components.push_back ((" r" + Twine (regionIdx)).str ());
3223- }
3224-
3225- // next parent
3226- o = parent;
3227- }
3228-
3229- SmallString<64 > Name (" canonloop" );
3230- for (const std::string &s : reverse (components)) {
3231- Name += ' _' ;
3232- Name += s;
3233- }
3234-
3235- return Name;
3401+ return generateLoopNestingName (" canonloop" , op);
32363402 })
32373403 .Case ([&](UnrollHeuristicOp op) -> std::string {
32383404 llvm_unreachable (" heuristic unrolling does not generate a loop" );
@@ -3323,7 +3489,8 @@ void CanonicalLoopOp::getAsmBlockNames(OpAsmSetBlockNameFn setNameFn) {
33233489
33243490void CanonicalLoopOp::getAsmBlockArgumentNames (Region ®ion,
33253491 OpAsmSetValueNameFn setNameFn) {
3326- setNameFn (region.getArgument (0 ), " iv" );
3492+ std::string ivName = generateLoopNestingName (" iv" , *this );
3493+ setNameFn (region.getArgument (0 ), ivName);
33273494}
33283495
33293496void CanonicalLoopOp::print (OpAsmPrinter &p) {
0 commit comments