@@ -600,6 +600,8 @@ def LoadOp : CIR_Op<"load", [
600
600
}];
601
601
602
602
let extraClassDeclaration = [{
603
+ // TODO(CIR): The final interface here should include an argument for the
604
+ // SyncScope::ID.
603
605
void setAtomic(mlir::cir::MemOrder order);
604
606
}];
605
607
@@ -669,7 +671,7 @@ def StoreOp : CIR_Op<"store", [
669
671
670
672
def ReturnOp : CIR_Op<"return", [ParentOneOf<["FuncOp", "ScopeOp", "IfOp",
671
673
"SwitchOp", "DoWhileOp",
672
- "WhileOp", "ForOp"]>,
674
+ "WhileOp", "ForOp", "CaseOp" ]>,
673
675
Terminator]> {
674
676
let summary = "Return from function";
675
677
let description = [{
@@ -904,7 +906,7 @@ def ConditionOp : CIR_Op<"condition", [
904
906
def YieldOp : CIR_Op<"yield", [ReturnLike, Terminator,
905
907
ParentOneOf<["IfOp", "ScopeOp", "SwitchOp", "WhileOp", "ForOp", "AwaitOp",
906
908
"TernaryOp", "GlobalOp", "DoWhileOp", "TryOp", "ArrayCtor",
907
- "ArrayDtor", "CallOp"]>]> {
909
+ "ArrayDtor", "CallOp", "CaseOp" ]>]> {
908
910
let summary = "Represents the default branching behaviour of a region";
909
911
let description = [{
910
912
The `cir.yield` operation terminates regions on different CIR operations,
@@ -1823,22 +1825,38 @@ def CaseOpKind : I32EnumAttr<
1823
1825
let cppNamespace = "::mlir::cir";
1824
1826
}
1825
1827
1826
- def CaseEltValueListAttr :
1827
- TypedArrayAttrBase<AnyAttr, "cir.switch case value condition"> {
1828
- let constBuilderCall = ?;
1829
- }
1828
+ def CaseOp : CIR_Op<"case", [
1829
+ DeclareOpInterfaceMethods<RegionBranchOpInterface>,
1830
+ RecursivelySpeculatable, AutomaticAllocationScope]> {
1831
+ let summary = "Case operation";
1832
+ let description = [{
1833
+ The `cir.case` operation represents a case within a C/C++ switch.
1834
+ The `cir.case` operation must be in a `cir.switch` operation directly or indirectly.
1830
1835
1831
- def CaseAttr : AttrDef<CIR_Dialect, "Case"> {
1832
- // FIXME: value should probably be optional for more clear "default"
1833
- // representation.
1834
- let parameters = (ins "ArrayAttr":$value, "CaseOpKindAttr":$kind);
1835
- let mnemonic = "case";
1836
- let assemblyFormat = "`<` struct(params) `>`";
1837
- }
1836
+ The `cir.case` have 4 kinds:
1837
+ - `equal, <constant>`: equality of the second case operand against the
1838
+ condition.
1839
+ - `anyof, [constant-list]`: equals to any of the values in a subsequent
1840
+ following list.
1841
+ - `range, [lower-bound, upper-bound]`: the condition is within the closed interval.
1842
+ - `default`: any other value.
1843
+
1844
+ Each case region must be explicitly terminated.
1845
+ }];
1846
+
1847
+ let arguments = (ins ArrayAttr:$value, CaseOpKind:$kind);
1848
+ let regions = (region AnyRegion:$caseRegion);
1849
+
1850
+ let assemblyFormat = "`(` $kind `,` $value `)` $caseRegion attr-dict";
1851
+
1852
+ let hasVerifier = 1;
1838
1853
1839
- def CaseArrayAttr :
1840
- TypedArrayAttrBase<CaseAttr, "cir.switch case array attribute"> {
1841
- let constBuilderCall = ?;
1854
+ let skipDefaultBuilders = 1;
1855
+ let builders = [
1856
+ OpBuilder<(ins "ArrayAttr":$value,
1857
+ "CaseOpKind":$kind,
1858
+ "OpBuilder::InsertPoint &":$insertPoint)>
1859
+ ];
1842
1860
}
1843
1861
1844
1862
def SwitchOp : CIR_Op<"switch",
@@ -1851,45 +1869,136 @@ def SwitchOp : CIR_Op<"switch",
1851
1869
conditionally executing multiple regions of code. The operand to an switch
1852
1870
is an integral condition value.
1853
1871
1854
- A variadic list of "case" attribute operands and regions track the possible
1855
- control flow within `cir.switch`. A `case` must be in one of the following forms:
1856
- - `equal, <constant>`: equality of the second case operand against the
1857
- condition.
1858
- - `anyof, [constant-list]`: equals to any of the values in a subsequent
1859
- following list.
1860
- - `range, [lower-bound, upper-bound]`: the condition is within the closed interval.
1861
- - `default`: any other value.
1872
+ The set of `cir.case` operations and their enclosing `cir.switch`
1873
+ represents the semantics of a C/C++ switch statement. Users can use
1874
+ `collectCases(llvm::SmallVector<CaseOp> &cases)` to collect the `cir.case`
1875
+ operation in the `cir.switch` operation easily.
1862
1876
1863
- Each case region must be explicitly terminated.
1877
+ The `cir.case` operations doesn't have to be in the region of `cir.switch`
1878
+ directly. However, when all the `cir.case` operations lives in the region
1879
+ of `cir.switch` directly and there is no other operations except the ending
1880
+ `cir.yield` operation in the region of `cir.switch` directly, we call the
1881
+ `cir.switch` operation is in a simple form. Users can use
1882
+ `bool isSimpleForm(llvm::SmallVector<CaseOp> &cases)` member function to
1883
+ detect if the `cir.switch` operation is in a simple form. The simple form
1884
+ makes analysis easier to handle the `cir.switch` operation
1885
+ and makes the boundary to give up pretty clear.
1864
1886
1865
- Examples:
1887
+ To make the simple form as common as possible, CIR code generation attaches
1888
+ operations corresponding to the statements that lives between top level
1889
+ cases into the closest `cir.case` operation.
1866
1890
1867
- ```mlir
1868
- cir.switch (%b : i32) [
1869
- case (equal, 20) {
1870
- ...
1871
- cir.yield break
1872
- },
1873
- case (anyof, [1, 2, 3] : i32) {
1874
- ...
1875
- cir.return ...
1891
+ For example,
1892
+
1893
+ ```
1894
+ switch(int cond) {
1895
+ case 4:
1896
+ a++;
1897
+
1898
+ b++;
1899
+ case 5;
1900
+ c++;
1901
+
1902
+ ...
1903
+ }
1904
+ ```
1905
+
1906
+ The statement `b++` is not a sub-statement of the case statement `case 4`.
1907
+ But to make the generated `cir.switch` a simple form, we will attach the
1908
+ statement `b++` into the closest `cir.case` operation. So that the generated
1909
+ code will be like:
1910
+
1911
+ ```
1912
+ cir.switch(int cond) {
1913
+ cir.case(equal, 4) {
1914
+ a++;
1915
+ b++;
1916
+ cir.yield
1876
1917
}
1877
- case (range, [10, 15]) {
1878
- ...
1879
- cir.yield break
1880
- },
1881
- case (default) {
1882
- ...
1883
- cir.yield fallthrough
1918
+ cir.case(equal, 5) {
1919
+ c++;
1920
+ cir.yield
1884
1921
}
1885
- ]
1922
+ ...
1923
+ }
1924
+ ```
1925
+
1926
+ For the same reason, we will hoist the case statement as the substatement
1927
+ of another case statement so that they will be in the same level. For
1928
+ example,
1929
+
1930
+ ```
1931
+ switch(int cond) {
1932
+ case 4:
1933
+ default;
1934
+ case 5;
1935
+ a++;
1936
+ ...
1937
+ }
1938
+ ```
1939
+
1940
+ will be generated as
1941
+
1942
+ ```
1943
+ cir.switch(int cond) {
1944
+ cir.case(equal, 4) {
1945
+ cir.yield
1946
+ }
1947
+ cir.case(default) {
1948
+ cir.yield
1949
+ }
1950
+ cir.case(equal, 5) {
1951
+ a++;
1952
+ cir.yield
1953
+ }
1954
+ ...
1955
+ }
1956
+ ```
1957
+
1958
+ The cir.switch might not be considered "simple" if any of the following is
1959
+ true:
1960
+ - There are case statements of the switch statement lives in other scopes
1961
+ other than the top level compound statement scope. Note that a case
1962
+ statement itself doesn't form a scope.
1963
+ - The sub-statement of the switch statement is not a compound statement.
1964
+ - There are codes before the first case statement. For example,
1965
+
1966
+ ```
1967
+ switch(int cond) {
1968
+ l:
1969
+ b++;
1970
+
1971
+ case 4:
1972
+ a++;
1973
+ break;
1974
+
1975
+ case 5:
1976
+ goto l;
1977
+ ...
1978
+ }
1979
+ ```
1980
+
1981
+ the generated CIR for this non-simple switch would be:
1982
+
1983
+ ```
1984
+ cir.switch(int cond) {
1985
+ cir.label "l"
1986
+ b++;
1987
+ cir.case(4) {
1988
+ a++;
1989
+ cir.break
1990
+ }
1991
+ cir.case(5) {
1992
+ goto "l"
1993
+ }
1994
+ cir.yield
1995
+ }
1886
1996
```
1887
1997
}];
1888
1998
1889
- let arguments = (ins CIR_IntType:$condition,
1890
- OptionalAttr<CaseArrayAttr>:$cases);
1999
+ let arguments = (ins CIR_IntType:$condition);
1891
2000
1892
- let regions = (region VariadicRegion< AnyRegion>:$regions );
2001
+ let regions = (region AnyRegion:$body );
1893
2002
1894
2003
let hasVerifier = 1;
1895
2004
@@ -1901,10 +2010,19 @@ def SwitchOp : CIR_Op<"switch",
1901
2010
1902
2011
let assemblyFormat = [{
1903
2012
custom<SwitchOp>(
1904
- $regions, $cases , $condition, type($condition)
2013
+ $body , $condition, type($condition)
1905
2014
)
1906
2015
attr-dict
1907
2016
}];
2017
+
2018
+ let extraClassDeclaration = [{
2019
+ // Collect cases in the switch.
2020
+ void collectCases(llvm::SmallVector<CaseOp> &cases);
2021
+
2022
+ // Check if the switch is in a simple form. If yes, collect the cases to \param cases.
2023
+ // This is an expensive and need to be used with caution.
2024
+ bool isSimpleForm(llvm::SmallVector<CaseOp> &cases);
2025
+ }];
1908
2026
}
1909
2027
1910
2028
//===----------------------------------------------------------------------===//
0 commit comments