[RFC] Rename LoopOps dialect to SCF (structured control flow)

I propose to rename LoopOps dialect to SCF, which stands for structured control flow. The reason being that the dialect contains “if/else” operation, which is obviously not a loop, and loop.if just looks confusing. The dialect itself was always intended to contain structured control flow operations and can accommodate, e.g. a “switch”.

One repercussion of the renaming is that we may also want to rename loop.parallel into scf.parallel_loop or scf.parallel_for to make clear the operation is a loop.

Alternative names are welcome. I’ve also considered SLCF (structured local control flow) to scope out non-local control flow such as functions and exceptions.

We could call it the “ed” dialect, which is a whole lot easier to use in conversation:

+1 for renaming. Thanks Alex! The dialect name has long been a confusion point. Making it to properly reflect the purpose is quite helpful to avoid further cognitional tolls.

+1 I had a WIP for this a few months back but lost track of it, go for it!

Or another idea which would cut down on the amount of inscrutable TLAs:
break it into 2 dialects “loop” and “branch”
loop.for would combine with loop.while nicely
branch.if would combine with branch.switch and or branch.sign (a switch with 3 alternatives: x<0, x==0, and x>0

Is pronounceability that important? If so, we should consider renaming things like std.br, std.addf and maybe MLIR itself :slight_smile:

I had proposed this earlier a couple of times – to rename this dialect ‘region’. Because all the ops you have here have regions and have to do with regions. A region.for executes a region repeatedly a certain number times. A region.if executes a region / regions conditionally. region.execute / region.once executes a region exactly once. So you get region.for, region.if, region.parallel_for (std.execute_region can become region.execute or region.once).

SCF sounds pretty clumsy - to type, to use, and to say.

1 Like

region sounds like it is the only dialect that supports regions

@ftynse I have several concerns:

  1. Having something which is easy to spell/pronounce, verbally and written.
  2. Having something which is memorable/intuitive so that people (me included) aren’t constantly asking “what is SCF?”.
  3. Something which is easy to find, so that people have a reasonable guess as to where to start if they just have a regular loop.
  4. Something which makes is easy to figure out what else should go in the same dialect.

for instance “Linalg” might not be completely accurate or precise, but it does meet most of the above characteristics.

I am open to concrete suggestions.

scf is three characters, with almost adjacent keys under one hand on a qwerty keyboard; it’s likely faster to type than loop, branch or control. I agree it is rather hard to pronounce for English speakers, hence my question about pronounceability being important. Personally, it’s quite rare that I have to announce the entire IR orally.

One can learn it quickly and control flow is ubiquitous enough so that most newcomers will see it early. Do people constantly ask what is RFC? std? br?

Wouldn’t the documentation entry “Structured/Standard Control Flow (scf)” in the main menu of MLIR documentation suffice?

“ODS” and “DRR” are awful, IMO. “SCF” may not be a barrier in and of itself, but I REALLY want to avoid an alphabet soup of dialects, so I’m bringing up the issue now. :slight_smile: I think there are reasonable choices which avoid the question entirely.

1 Like

I completely agree. I would also like to stick to more descriptive naming - ODS and DRR could use longer names too :slight_smile:

This might be a naive question, but why can’t ‘for’ and ‘if’ be part of standard dialect?

Like I said, I am open to suggestions. So far, I’ve seen the following.

  • “ed”. While I like the reference, I don’t think it really meets your own criteria of “intuitive, easy to find, makes easy to figure out what should go there”.
  • “region”. This sounds like it is the only dialect supporting regions, and that any region-carrying operation belongs there.
  • Split the dialect into “loop” and “branch”. This is beyond the scope of simple renaming I proposed, and likely requires to move std.br and std.cond_br into “branch”. I also cannot position such new dialect with respect to our guidelines on creating a new dialect, sounds like the opposite of “consolidation” point.

The goal of this dialect has always been to model structured control flow using regions and without any affine restrictions.

There was a long and mostly inconclusive discussion when we proposed to move these operations out of Linalg, with a lot of pushback against putting them in standard. At some transient point, we actually did have them there as evidenced by some leftover comments in the code. The conclusion of the live discussion we had was that it made sense to move all “standard” control flow operations, including branches, into a separate dialect (we did not discuss the name though). This aligns with my point of view that we should not have a dialect named “standard” that is essentially “everything-that-does-not-fit-into-another-dialect” but rather a set of better-scoped composable dialects. This idea has made its way into the documentation. Our initial proposal for such a control flow dialect (with cf as prefix) was considered too loop-centric and underwhelmingly minimalist, so we agreed to rename the dialect to loop as suggested during another discussion. This obviously did not age well…

Today, there is a set of operations in the loop dialect (loop.yield, loop.reduce) with names that would likely cause a lot of misunderstanding on their semantics if moved to std.

I think cf or control_flow would be adequate names and then we can move all normal control flow operations, whether structured or lower level, into that dialect. Longer term, we can then also split standard more until it is gone (arithmetics, memory, etc.).

Regarding the long vs. short names: How often do we write mlir code by hand? Should we really optimize for easy typing or rather easy comprehension? Of course, structured_control_flow.for_with_parallel_semantics would impact readability, too. control_flow.parallel_for is still easy to read IMHO.

I’m to blame for those (well ODS at least, DRR was a collaborative bad choice hehe) and mostly there to avoid folks confusing the data format (e.g., TableGen) from the backends. We can start a separate thread for renaming those (DialectGen and RewrireGen ?)

Doesn’t it actually consolidate the branch constructs? Yes you end with 3 dialect but avoid the confusion as to what needs to be in which one (e.g., why is there a std.br if we have a control flow dialect? should switch go to std or control_flow?)

Surprisingly often :slight_smile: It is meant for readability and debugging so I think we could apply some of the same metrics as we would for variable names: cf as variable name would not fly unless it is very local scope (exception for product names are fine, e.g., TF as op set seems good even though tf as variable would be bad), now it may be that after 1 day or looking at one example the name is clear (e.g., cf.loop probably doesn’t refer to “confer loop” or “cold fusion loop”, but I don’t know intuitive - while funnily cfg is very intuitive to me, cf not as much but maybe just due to familiarity).

control_flow could be fine but then it would seem to suggest all control flow should be there. But then again that is OK if all the general / least constrained control flow are there and the dialect specific / more specialized ones are in theirs (e.g. loop vs affine loop). structured_control or regular_control/cf.

Naming is fun: I think post some brainstorming it is actually possible to create a poll and then discuss a narrowed down set. Although naming by committee is probably not good

  • New name A
  • New name B
  • Keep name as is
0 voters

I’d also make the same argument for region. Naming it region doesn’t necessarily mean all region holding ops live there - it’s just a general/less constrained/widely usable set of region holding ops. The rationale would still be copy/paste the following:

“All the ops you have here have regions and have to do with regions. A region.for executes a region repeatedly a certain number times. A region.if executes a region / regions conditionally. region.execute / region.once executes a region exactly once. So you get region.for , region.if , region.parallel_for ( std.execute_region can become region.execute or region.once ).”

Region being a core concept in the IR, I would be afraid of adding confusion with naming an entire dialect with it.

For something as basic as “fundamental control flow abstractions” using a short name like cf seems fine, especially if we can converge br/cond_br and others into it. Of course, that implicitly sets a very high bar for adding ops to that dialect.

I’ll point out that e.g. “br” is an abbreviation, but due to its fundamental status it’s nonproblematic.

I like the idea of MLIR having a “batteries included” set of control flow abstractions, and naming a dialect “cf” to represent that seems compelling.