[Mlir-commits] [mlir] [mlir][emitc] Add op modelling C expressions (PR #71631)

Simon Camphausen llvmlistbot at llvm.org
Wed Nov 8 06:49:48 PST 2023


================
@@ -246,6 +247,85 @@ def EmitC_DivOp : EmitC_BinaryOp<"div", []> {
   let results = (outs FloatIntegerIndexOrOpaqueType);
 }
 
+def EmitC_ExpressionOp : EmitC_Op<"expression",
+      [HasOnlyGraphRegion, SingleBlockImplicitTerminator<"emitc::YieldOp">,
+       NoRegionArguments]> {
+  let summary = "Expression operation";
+  let description = [{
+    The `expression` operation returns a single SSA value which is yielded by
+    its single-basic-block region. The operation doesn't take any arguments.
+
+    As the operation is to be emitted as a C expression, the operations within
+    its body must form a single Def-Use tree of emitc ops whose result is
+    yielded by a terminating `yield`.
+
+    Example:
+
+    ```mlir
+    %r = emitc.expression : () -> i32 {
+      %0 = emitc.add %a, %b : (i32, i32) -> i32
+      %1 = emitc.call "foo"(%0) : () -> i32
+      %2 = emitc.add %c, %d : (i32, i32) -> i32
+      %3 = emitc.mul %1, %2 : (i32, i32) -> i32
+      yield %3
+    }
+    ```
+
+    May be emitted as
+
+    ```c++
+    int32_t v7 = foo(v1 + v2) * (v3 + v4);
+    ```
+
+    The operations allowed within expression body are emitc.add, emitc.apply,
+    emitc.call, emitc.cast, emitc.cmp, emitc.div, emitc.mul, emitc.rem and
+    emitc.sub.
+
+    When specified, the optional do_not_inline indicates that the expression is
+    to be emitted as seen above, i.e. as the rhs of an EmitC SSA value
+    definition. Otherwise, the expression may be emitted inline, i.e. directly
+    at its use.
+  }];
+
+  let arguments = (ins UnitAttr:$do_not_inline);
+  let results = (outs AnyType);
+  let regions = (region SizedRegion<1>:$region);
+
+  let hasVerifier = 1;
+  let hasCustomAssemblyFormat = 1;
+
+  let extraClassDeclaration = [{
+    static bool isCExpression(Operation &op) {
+      return isa<emitc::AddOp, emitc::ApplyOp, emitc::CallOp, emitc::CastOp,
+                 emitc::CmpOp, emitc::DivOp, emitc::MulOp, emitc::RemOp,
+                 emitc::SubOp>(op);
+    }
+    static bool hasSideEffects(Operation &op) {
+      assert(isCExpression(op) && "Expected a C operator");
+      // Conservatively assume calls to read and write memory.
+      if (isa<emitc::CallOp>(op))
+        return true;
+      // De-referencing reads modifiable memory.
+      auto applyOp = dyn_cast<emitc::ApplyOp>(op);
+      if (applyOp && applyOp.getApplicableOperator() == "*")
+        return true;
+      // Any operator using variables has a side effect of reading memory mutable by
+      // emitc::assign ops.
+      for (Value operand : op.getOperands()) {
+        Operation *def = operand.getDefiningOp();
+        if (def && isa<emitc::VariableOp>(def))
+          return true;
+      }
+      return false;
----------------
simon-camp wrote:

```suggestion
      return llvm::any_of(op.getOperands(),
                          [](Value operand) { Operation *def = operand.getDefiningOp();
                                              return def && isa<emitc::VariableOp>(def); });
```

https://github.com/llvm/llvm-project/pull/71631


More information about the Mlir-commits mailing list