@@ -1345,7 +1345,7 @@ def EmitC_AssignOp : EmitC_Op<"assign", []> {
1345
1345
}
1346
1346
1347
1347
def EmitC_YieldOp : EmitC_Op<"yield",
1348
- [Pure, Terminator, ParentOneOf<["ExpressionOp ", "IfOp ", "ForOp", "SwitchOp"]>]> {
1348
+ [Pure, Terminator, ParentOneOf<["DoOp ", "ExpressionOp ", "ForOp", "IfOp", " SwitchOp", "WhileOp "]>]> {
1349
1349
let summary = "Block termination operation";
1350
1350
let description = [{
1351
1351
The `emitc.yield` terminates its parent EmitC op's region, optionally yielding
@@ -1572,4 +1572,156 @@ def EmitC_SwitchOp : EmitC_Op<"switch", [RecursiveMemoryEffects,
1572
1572
let hasVerifier = 1;
1573
1573
}
1574
1574
1575
+ def EmitC_WhileOp : EmitC_Op<"while",
1576
+ [HasOnlyGraphRegion, RecursiveMemoryEffects, NoRegionArguments, OpAsmOpInterface, NoTerminator]> {
1577
+ let summary = "While operation";
1578
+ let description = [{
1579
+ The `emitc.while` operation represents a C/C++ while loop construct that
1580
+ repeatedly executes a body region as long as a condition region evaluates to
1581
+ true. The operation has two regions:
1582
+
1583
+ 1. A condition region that must yield a boolean value (i1)
1584
+ 2. A body region that contains the loop body
1585
+
1586
+ The condition region is evaluated before each iteration. If it yields true,
1587
+ the body region is executed. The loop terminates when the condition yields
1588
+ false. The condition region must contain exactly one block that terminates
1589
+ with an `emitc.yield` operation producing an i1 value.
1590
+
1591
+ Example:
1592
+
1593
+ ```mlir
1594
+ emitc.func @foo(%arg0 : !emitc.ptr<i32>) {
1595
+ %var = "emitc.variable"() <{value = 0 : i32}> : () -> !emitc.lvalue<i32>
1596
+ %0 = emitc.literal "10" : i32
1597
+ %1 = emitc.literal "1" : i32
1598
+
1599
+ emitc.while {
1600
+ %var_load = load %var : <i32>
1601
+ %res = emitc.cmp le, %var_load, %0 : (i32, i32) -> i1
1602
+ emitc.yield %res : i1
1603
+ } do {
1604
+ emitc.verbatim "printf(\"%d\", *{});" args %arg0 : !emitc.ptr<i32>
1605
+ %var_load = load %var : <i32>
1606
+ %tmp_add = add %var_load, %1 : (i32, i32) -> i32
1607
+ "emitc.assign"(%var, %tmp_add) : (!emitc.lvalue<i32>, i32) -> ()
1608
+ }
1609
+
1610
+ return
1611
+ }
1612
+ ```
1613
+
1614
+ ```c++
1615
+ // Code emitted for the operation above.
1616
+ void foo(int32_t* v1) {
1617
+ int32_t v2 = 0;
1618
+ while (v2 <= 10) {
1619
+ printf("%d", *v1);
1620
+ int32_t v3 = v2;
1621
+ int32_t v4 = v3 + 1;
1622
+ v2 = v4;
1623
+ }
1624
+ return;
1625
+ }
1626
+ ```
1627
+ }];
1628
+
1629
+ let arguments = (ins);
1630
+ let results = (outs);
1631
+ let regions = (region MaxSizedRegion<1>:$conditionRegion,
1632
+ MaxSizedRegion<1>:$bodyRegion);
1633
+
1634
+ let hasCustomAssemblyFormat = 1;
1635
+ let hasVerifier = 1;
1636
+
1637
+ let extraClassDeclaration = [{
1638
+ Operation *getRootOp();
1639
+
1640
+ //===------------------------------------------------------------------===//
1641
+ // OpAsmOpInterface Methods
1642
+ //===------------------------------------------------------------------===//
1643
+
1644
+ /// EmitC ops in the body can omit their 'emitc.' prefix in the assembly.
1645
+ static ::llvm::StringRef getDefaultDialect() {
1646
+ return "emitc";
1647
+ }
1648
+ }];
1649
+ }
1650
+
1651
+ def EmitC_DoOp : EmitC_Op<"do",
1652
+ [RecursiveMemoryEffects, NoRegionArguments, OpAsmOpInterface, NoTerminator]> {
1653
+ let summary = "Do-while operation";
1654
+ let description = [{
1655
+ The `emitc.do` operation represents a C/C++ do-while loop construct that
1656
+ executes a body region first and then repeatedly executes it as long as a
1657
+ condition region evaluates to true. The operation has two regions:
1658
+
1659
+ 1. A body region that contains the loop body
1660
+ 2. A condition region that must yield a boolean value (i1)
1661
+
1662
+ Unlike a while loop, the body region is executed before the first evaluation
1663
+ of the condition. The loop terminates when the condition yields false. The
1664
+ condition region must contain exactly one block that terminates with an
1665
+ `emitc.yield` operation producing an i1 value.
1666
+
1667
+ Example:
1668
+
1669
+ ```mlir
1670
+ emitc.func @foo(%arg0 : !emitc.ptr<i32>) {
1671
+ %var = "emitc.variable"() <{value = 0 : i32}> : () -> !emitc.lvalue<i32>
1672
+ %0 = emitc.literal "10" : i32
1673
+ %1 = emitc.literal "1" : i32
1674
+
1675
+ emitc.do {
1676
+ emitc.verbatim "printf(\"%d\", *{});" args %arg0 : !emitc.ptr<i32>
1677
+ %var_load = load %var : <i32>
1678
+ %tmp_add = add %var_load, %1 : (i32, i32) -> i32
1679
+ "emitc.assign"(%var, %tmp_add) : (!emitc.lvalue<i32>, i32) -> ()
1680
+ } while {
1681
+ %var_load = load %var : <i32>
1682
+ %res = emitc.cmp le, %var_load, %0 : (i32, i32) -> i1
1683
+ emitc.yield %res : i1
1684
+ }
1685
+
1686
+ return
1687
+ }
1688
+ ```
1689
+
1690
+ ```c++
1691
+ // Code emitted for the operation above.
1692
+ void foo(int32_t* v1) {
1693
+ int32_t v2 = 0;
1694
+ do {
1695
+ printf("%d", *v1);
1696
+ int32_t v3 = v2;
1697
+ int32_t v4 = v3 + 1;
1698
+ v2 = v4;
1699
+ } while (v2 <= 10);
1700
+ return;
1701
+ }
1702
+ ```
1703
+ }];
1704
+
1705
+ let arguments = (ins);
1706
+ let results = (outs);
1707
+ let regions = (region MaxSizedRegion<1>:$bodyRegion,
1708
+ MaxSizedRegion<1>:$conditionRegion);
1709
+
1710
+ let hasCustomAssemblyFormat = 1;
1711
+ let hasVerifier = 1;
1712
+
1713
+ let extraClassDeclaration = [{
1714
+ Operation *getRootOp();
1715
+
1716
+ //===------------------------------------------------------------------===//
1717
+ // OpAsmOpInterface Methods
1718
+ //===------------------------------------------------------------------===//
1719
+
1720
+ /// EmitC ops in the body can omit their 'emitc.' prefix in the assembly.
1721
+ static ::llvm::StringRef getDefaultDialect() {
1722
+ return "emitc";
1723
+ }
1724
+ }];
1725
+ }
1726
+
1575
1727
#endif // MLIR_DIALECT_EMITC_IR_EMITC
0 commit comments