================ @@ -753,6 +755,221 @@ def ScopeOp : CIR_Op<"scope", [ ]; } +//===----------------------------------------------------------------------===// +// SwitchOp +//===----------------------------------------------------------------------===// + +def CaseOpKind_DT : I32EnumAttrCase<"Default", 1, "default">; +def CaseOpKind_EQ : I32EnumAttrCase<"Equal", 2, "equal">; +def CaseOpKind_AO : I32EnumAttrCase<"Anyof", 3, "anyof">; +def CaseOpKind_RG : I32EnumAttrCase<"Range", 4, "range">; + +def CaseOpKind : I32EnumAttr< + "CaseOpKind", + "case kind", + [CaseOpKind_DT, CaseOpKind_EQ, CaseOpKind_AO, CaseOpKind_RG]> { + let cppNamespace = "::cir"; +} + +def CaseOp : CIR_Op<"case", [ + DeclareOpInterfaceMethods<RegionBranchOpInterface>, + RecursivelySpeculatable, AutomaticAllocationScope]> { + let summary = "Case operation"; + let description = [{ + The `cir.case` operation represents a case within a C/C++ switch. + The `cir.case` operation must be in a `cir.switch` operation directly + or indirectly. + + The `cir.case` have 4 kinds: + - `equal, <constant>`: equality of the second case operand against the + condition. + - `anyof, [constant-list]`: equals to any of the values in a subsequent + following list. + - `range, [lower-bound, upper-bound]`: the condition is within the closed + interval. + - `default`: any other value. + + Each case region must be explicitly terminated. + }]; + + let arguments = (ins ArrayAttr:$value, CaseOpKind:$kind); + let regions = (region AnyRegion:$caseRegion); + + let assemblyFormat = "`(` $kind `,` $value `)` $caseRegion attr-dict"; + + let skipDefaultBuilders = 1; + let builders = [ + OpBuilder<(ins "mlir::ArrayAttr":$value, + "CaseOpKind":$kind, + "mlir::OpBuilder::InsertPoint &":$insertPoint)> + ]; +} + +def SwitchOp : CIR_Op<"switch", + [SameVariadicOperandSize, + DeclareOpInterfaceMethods<RegionBranchOpInterface>, + RecursivelySpeculatable, AutomaticAllocationScope, NoRegionArguments]> { + let summary = "Switch operation"; + let description = [{ + The `cir.switch` operation represents C/C++ switch functionality for + conditionally executing multiple regions of code. The operand to an switch + is an integral condition value. + + The set of `cir.case` operations and their enclosing `cir.switch` + represents the semantics of a C/C++ switch statement. Users can use + `collectCases(llvm::SmallVector<CaseOp> &cases)` to collect the `cir.case` + operation in the `cir.switch` operation easily. + + The `cir.case` operations doesn't have to be in the region of `cir.switch` + directly. However, when all the `cir.case` operations lives in the region + of `cir.switch` directly and there is no other operations except the ending + `cir.yield` operation in the region of `cir.switch` directly, we call the + `cir.switch` operation is in a simple form. Users can use + `bool isSimpleForm(llvm::SmallVector<CaseOp> &cases)` member function to + detect if the `cir.switch` operation is in a simple form. The simple form + makes analysis easier to handle the `cir.switch` operation + and makes the boundary to give up pretty clear. + + To make the simple form as common as possible, CIR code generation attaches + operations corresponding to the statements that lives between top level + cases into the closest `cir.case` operation. + + For example, + + ``` + switch(int cond) { + case 4: + a++; + + b++; + case 5; + c++; + + ... + } + ``` + + The statement `b++` is not a sub-statement of the case statement `case 4`. + But to make the generated `cir.switch` a simple form, we will attach the + statement `b++` into the closest `cir.case` operation. So that the generated + code will be like: + + ``` + cir.switch(int cond) { + cir.case(equal, 4) { + a++; + b++; + cir.yield + } + cir.case(equal, 5) { + c++; + cir.yield + } + ... + } + ``` + + For the same reason, we will hoist the case statement as the substatement + of another case statement so that they will be in the same level. For + example, + + ``` + switch(int cond) { + case 4: + default; + case 5; + a++; + ... + } + ``` + + will be generated as + + ``` + cir.switch(int cond) { + cir.case(equal, 4) { + cir.yield + } + cir.case(default) { + cir.yield + } + cir.case(equal, 5) { + a++; + cir.yield + } + ... + } + ``` + + The cir.switch might not be considered "simple" if any of the following is ---------------- Andres-Salamanca wrote:
Done https://github.com/llvm/llvm-project/pull/137106 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits