@@ -470,7 +470,8 @@ def StoreOp : CIR_Op<"store", [
470
470
//===----------------------------------------------------------------------===//
471
471
472
472
def ReturnOp : CIR_Op<"return", [ParentOneOf<["FuncOp", "ScopeOp", "IfOp",
473
- "DoWhileOp", "WhileOp", "ForOp"]>,
473
+ "SwitchOp", "DoWhileOp","WhileOp",
474
+ "ForOp", "CaseOp"]>,
474
475
Terminator]> {
475
476
let summary = "Return from function";
476
477
let description = [{
@@ -609,8 +610,9 @@ def ConditionOp : CIR_Op<"condition", [
609
610
//===----------------------------------------------------------------------===//
610
611
611
612
def YieldOp : CIR_Op<"yield", [ReturnLike, Terminator,
612
- ParentOneOf<["IfOp", "ScopeOp", "WhileOp",
613
- "ForOp", "DoWhileOp"]>]> {
613
+ ParentOneOf<["IfOp", "ScopeOp", "SwitchOp",
614
+ "WhileOp", "ForOp", "CaseOp",
615
+ "DoWhileOp"]>]> {
614
616
let summary = "Represents the default branching behaviour of a region";
615
617
let description = [{
616
618
The `cir.yield` operation terminates regions on different CIR operations,
@@ -753,6 +755,220 @@ def ScopeOp : CIR_Op<"scope", [
753
755
];
754
756
}
755
757
758
+ //===----------------------------------------------------------------------===//
759
+ // SwitchOp
760
+ //===----------------------------------------------------------------------===//
761
+
762
+ def CaseOpKind_DT : I32EnumAttrCase<"Default", 1, "default">;
763
+ def CaseOpKind_EQ : I32EnumAttrCase<"Equal", 2, "equal">;
764
+ def CaseOpKind_AO : I32EnumAttrCase<"Anyof", 3, "anyof">;
765
+ def CaseOpKind_RG : I32EnumAttrCase<"Range", 4, "range">;
766
+
767
+ def CaseOpKind : I32EnumAttr<
768
+ "CaseOpKind",
769
+ "case kind",
770
+ [CaseOpKind_DT, CaseOpKind_EQ, CaseOpKind_AO, CaseOpKind_RG]> {
771
+ let cppNamespace = "::cir";
772
+ }
773
+
774
+ def CaseOp : CIR_Op<"case", [
775
+ DeclareOpInterfaceMethods<RegionBranchOpInterface>,
776
+ RecursivelySpeculatable, AutomaticAllocationScope]> {
777
+ let summary = "Case operation";
778
+ let description = [{
779
+ The `cir.case` operation represents a case within a C/C++ switch.
780
+ The `cir.case` operation must be in a `cir.switch` operation directly
781
+ or indirectly.
782
+
783
+ The `cir.case` have 4 kinds:
784
+ - `equal, <constant>`: equality of the second case operand against the
785
+ condition.
786
+ - `anyof, [constant-list]`: equals to any of the values in a subsequent
787
+ following list.
788
+ - `range, [lower-bound, upper-bound]`: the condition is within the closed
789
+ interval.
790
+ - `default`: any other value.
791
+
792
+ Each case region must be explicitly terminated.
793
+ }];
794
+
795
+ let arguments = (ins ArrayAttr:$value, CaseOpKind:$kind);
796
+ let regions = (region AnyRegion:$caseRegion);
797
+
798
+ let assemblyFormat = "`(` $kind `,` $value `)` $caseRegion attr-dict";
799
+
800
+ let skipDefaultBuilders = 1;
801
+ let builders = [
802
+ OpBuilder<(ins "mlir::ArrayAttr":$value,
803
+ "CaseOpKind":$kind,
804
+ "mlir::OpBuilder::InsertPoint &":$insertPoint)>
805
+ ];
806
+ }
807
+
808
+ def SwitchOp : CIR_Op<"switch",
809
+ [SameVariadicOperandSize,
810
+ DeclareOpInterfaceMethods<RegionBranchOpInterface>,
811
+ RecursivelySpeculatable, AutomaticAllocationScope, NoRegionArguments]> {
812
+ let summary = "Switch operation";
813
+ let description = [{
814
+ The `cir.switch` operation represents C/C++ switch functionality for
815
+ conditionally executing multiple regions of code. The operand to an switch
816
+ is an integral condition value.
817
+
818
+ The set of `cir.case` operations and their enclosing `cir.switch`
819
+ represent the semantics of a C/C++ switch statement. Users can use
820
+ `collectCases(llvm::SmallVector<CaseOp> &cases)` to collect the `cir.case`
821
+ operation in the `cir.switch` operation easily.
822
+
823
+ The `cir.case` operations don't have to be in the region of `cir.switch`
824
+ directly. However, when all the `cir.case` operations live in the region
825
+ of `cir.switch` directly and there are no other operations except the ending
826
+ `cir.yield` operation in the region of `cir.switch` directly, we say the
827
+ `cir.switch` operation is in a simple form. Users can use
828
+ `bool isSimpleForm(llvm::SmallVector<CaseOp> &cases)` member function to
829
+ detect if the `cir.switch` operation is in a simple form. The simple form
830
+ makes it easier for analyses to handle the `cir.switch` operation
831
+ and makes the boundary to give up clear.
832
+
833
+ To make the simple form as common as possible, CIR code generation attaches
834
+ operations corresponding to the statements that lives between top level
835
+ cases into the closest `cir.case` operation.
836
+
837
+ For example,
838
+
839
+ ```
840
+ switch(int cond) {
841
+ case 4:
842
+ a++;
843
+ b++;
844
+ case 5:
845
+ c++;
846
+
847
+ ...
848
+ }
849
+ ```
850
+
851
+ The statement `b++` is not a sub-statement of the case statement `case 4`.
852
+ But to make the generated `cir.switch` a simple form, we will attach the
853
+ statement `b++` into the closest `cir.case` operation. So that the generated
854
+ code will be like:
855
+
856
+ ```
857
+ cir.switch(int cond) {
858
+ cir.case(equal, 4) {
859
+ a++;
860
+ b++;
861
+ cir.yield
862
+ }
863
+ cir.case(equal, 5) {
864
+ c++;
865
+ cir.yield
866
+ }
867
+ ...
868
+ }
869
+ ```
870
+
871
+ For the same reason, we will hoist the case statement as the substatement
872
+ of another case statement so that they will be in the same level. For
873
+ example,
874
+
875
+ ```
876
+ switch(int cond) {
877
+ case 4:
878
+ default;
879
+ case 5:
880
+ a++;
881
+ ...
882
+ }
883
+ ```
884
+
885
+ will be generated as
886
+
887
+ ```
888
+ cir.switch(int cond) {
889
+ cir.case(equal, 4) {
890
+ cir.yield
891
+ }
892
+ cir.case(default) {
893
+ cir.yield
894
+ }
895
+ cir.case(equal, 5) {
896
+ a++;
897
+ cir.yield
898
+ }
899
+ ...
900
+ }
901
+ ```
902
+
903
+ The cir.switch is not be considered "simple" if any of the following is
904
+ true:
905
+ - There are case statements of the switch statement that are scope
906
+ other than the top level compound statement scope. Note that a case
907
+ statement itself doesn't form a scope.
908
+ - The sub-statement of the switch statement is not a compound statement.
909
+ - There is any code before the first case statement. For example,
910
+
911
+ ```
912
+ switch(int cond) {
913
+ l:
914
+ b++;
915
+
916
+ case 4:
917
+ a++;
918
+ break;
919
+
920
+ case 5:
921
+ goto l;
922
+ ...
923
+ }
924
+ ```
925
+
926
+ the generated CIR for this non-simple switch would be:
927
+
928
+ ```
929
+ cir.switch(int cond) {
930
+ cir.label "l"
931
+ b++;
932
+ cir.case(4) {
933
+ a++;
934
+ cir.break
935
+ }
936
+ cir.case(5) {
937
+ goto "l"
938
+ }
939
+ cir.yield
940
+ }
941
+ ```
942
+ }];
943
+
944
+ let arguments = (ins CIR_IntType:$condition);
945
+
946
+ let regions = (region AnyRegion:$body);
947
+
948
+ let skipDefaultBuilders = 1;
949
+ let builders = [
950
+ OpBuilder<(ins "mlir::Value":$condition,
951
+ "BuilderOpStateCallbackRef":$switchBuilder)>
952
+ ];
953
+
954
+ let assemblyFormat = [{
955
+ custom<SwitchOp>(
956
+ $body, $condition, type($condition)
957
+ )
958
+ attr-dict
959
+ }];
960
+
961
+ let extraClassDeclaration = [{
962
+ // Collect cases in the switch.
963
+ void collectCases(llvm::SmallVectorImpl<CaseOp> &cases);
964
+
965
+ // Check if the switch is in a simple form.
966
+ // If yes, collect the cases to \param cases.
967
+ // This is an expensive and need to be used with caution.
968
+ bool isSimpleForm(llvm::SmallVectorImpl<CaseOp> &cases);
969
+ }];
970
+ }
971
+
756
972
//===----------------------------------------------------------------------===//
757
973
// BrOp
758
974
//===----------------------------------------------------------------------===//
0 commit comments