[RFC] Add std.switch and scf.switch

Branching off the discussion in Switch statement missing, I’d like to add switch ops to the standard and structured control flow dialects.

This would be unstructured control flow based on llvm.switch. Given that branch weights are not present on other std branch operations, I do not think we should add them here at this time. In all other aspects, llvm.switch seems like the right way to model this and I anticipate mostly copying over the code (including the custom switch cases printer/parser).

I believe it should be ok to add this new op to std, despite the ongoing effort to break std into multiple dialects because it is closely related to the existing br and cond_br ops and would move along with them to whatever new dialect we might create (say a “control flow” dialect for unstructured control flow).

This would be the structured version of switch, using regions, as in scf.if and able to yield values, but taking no block arguments.

%x, %y = scf.switch %flag -> (f32, f32) {
    %x_default = ...
    %y_default = ...
    %scf.yield %x_default, %y_default
  } [
    0: {
      %x_0 = ...
      %y_0 = ...
      %scf.yield %x_0, %y_0
    -1: {
      %x_m1 = ...
      %y_m1 = ...
      %scf.yield %x_m1, %y_m1

+1 to these. switch is as natural of a control flow construct as br, cond_br, etc. It’d be nice to finally get this in tree.

– River

std.switch LGTM!
About scf.switch, I wonder about the type of the condition and how pluggable/extensible we should make it? I.e. have you thought about non-integer matching.

Makes sense to me too

+1. These make sense to add.

Looks great! Minor question: for multiple cases sharing the same block, does llvm.switch avoid block replication (in memory)? The pretty printer can of course be changed to something like:

)} [
1, 2, 3, 4, 5, 6, 7: {
      %x_0 = ...
      %y_0 = ...
      %scf.yield %x_0, %y_0
0: {

if $blockDestinations could have the same blocks repeating.

I think your question would be about scf.switch, since it’s using regions? llvm.switch (and the proposed std.switch) just record a block identifier and the arguments, so I’m not sure there’s much value deduping for the complexity it adds, but for the proposed scf.switch, which would contain entire regions, that does seem potentially useful. Maybe each case should have an array of attributes of the flag type rather than a single one.

Given the response, I’m inclined to start the patch for std.switch and continue discussing scf.switch, so we can further explore Mehdi and Uday’s comments

1 Like

Sorry for the delay here. ⚙ D99925 Add a switch operation to the standard dialect adds std.switch