Skip to content

[mlir][emitc] Rename call op to call_opaque #72494

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Nov 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions mlir/docs/Dialects/emitc.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ ops. Those can be translated to C/C++ via the Cpp emitter.

The following convention is followed:

* If template arguments are passed to an `emitc.call` operation, C++ is
* If template arguments are passed to an `emitc.call_opaque` operation, C++ is
generated.
* If tensors are used, C++ is generated.
* If multiple return values are used within in a functions or an `emitc.call`
operation, C++11 is required.
* If floating-point type template arguments are passed to an `emitc.call`
* If multiple return values are used within in a functions or an
`emitc.call_opaque` operation, C++11 is required.
* If floating-point type template arguments are passed to an `emitc.call_opaque`
operation, C++20 is required.
* Else the generated code is compatible with C99.

Expand Down
18 changes: 10 additions & 8 deletions mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
Original file line number Diff line number Diff line change
Expand Up @@ -92,11 +92,12 @@ def EmitC_ApplyOp : EmitC_Op<"apply", []> {
let hasVerifier = 1;
}

def EmitC_CallOp : EmitC_Op<"call", []> {
let summary = "Call operation";
def EmitC_CallOpaqueOp : EmitC_Op<"call_opaque", []> {
let summary = "Opaque call operation";
let description = [{
The `call` operation represents a C++ function call. The call allows
specifying order of operands and attributes in the call as follows:
The `call_opaque` operation represents a C++ function call. The callee
can be an arbitrary non-empty string. The call allows specifying order
of operands and attributes in the call as follows:

- integer value of index type refers to an operand;
- attribute which will get lowered to constant value in call;
Expand All @@ -105,10 +106,10 @@ def EmitC_CallOp : EmitC_Op<"call", []> {

```mlir
// Custom form defining a call to `foo()`.
%0 = emitc.call "foo" () : () -> i32
%0 = emitc.call_opaque "foo" () : () -> i32

// Generic form of the same operation.
%0 = "emitc.call"() {callee = "foo"} : () -> i32
%0 = "emitc.call_opaque"() {callee = "foo"} : () -> i32
```
}];
let arguments = (ins
Expand Down Expand Up @@ -454,7 +455,8 @@ def EmitC_VariableOp : EmitC_Op<"variable", []> {
%1 = "emitc.variable"() {value = 0 : i32} : () -> i32
%2 = emitc.apply "&"(%0) : (i32) -> !emitc.ptr<i32>
%3 = emitc.apply "&"(%1) : (i32) -> !emitc.ptr<i32>
emitc.call "write"(%2, %3) : (!emitc.ptr<i32>, !emitc.ptr<i32>) -> ()
emitc.call_opaque "write"(%2, %3)
: (!emitc.ptr<i32>, !emitc.ptr<i32>) -> ()
```
}];

Expand All @@ -477,7 +479,7 @@ def EmitC_AssignOp : EmitC_Op<"assign", []> {
```mlir
// Integer variable
%0 = "emitc.variable"(){value = 42 : i32} : () -> i32
%1 = emitc.call "foo"() : () -> (i32)
%1 = emitc.call_opaque "foo"() : () -> (i32)

// Assign emitted as `... = ...;`
"emitc.assign"(%0, %1) : (i32, i32) -> ()
Expand Down
2 changes: 1 addition & 1 deletion mlir/lib/Dialect/EmitC/IR/EmitC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ bool CastOp::areCastCompatible(TypeRange inputs, TypeRange outputs) {
// CallOp
//===----------------------------------------------------------------------===//

LogicalResult emitc::CallOp::verify() {
LogicalResult emitc::CallOpaqueOp::verify() {
// Callee must not be empty.
if (getCallee().empty())
return emitOpError("callee must not be empty");
Expand Down
26 changes: 14 additions & 12 deletions mlir/lib/Target/Cpp/TranslateToCpp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -412,13 +412,14 @@ static LogicalResult printOperation(CppEmitter &emitter, func::CallOp callOp) {
return success();
}

static LogicalResult printOperation(CppEmitter &emitter, emitc::CallOp callOp) {
static LogicalResult printOperation(CppEmitter &emitter,
emitc::CallOpaqueOp callOpaqueOp) {
raw_ostream &os = emitter.ostream();
Operation &op = *callOp.getOperation();
Operation &op = *callOpaqueOp.getOperation();

if (failed(emitter.emitAssignPrefix(op)))
return failure();
os << callOp.getCallee();
os << callOpaqueOp.getCallee();

auto emitArgs = [&](Attribute attr) -> LogicalResult {
if (auto t = dyn_cast<IntegerAttr>(attr)) {
Expand All @@ -441,19 +442,19 @@ static LogicalResult printOperation(CppEmitter &emitter, emitc::CallOp callOp) {
return success();
};

if (callOp.getTemplateArgs()) {
if (callOpaqueOp.getTemplateArgs()) {
os << "<";
if (failed(
interleaveCommaWithError(*callOp.getTemplateArgs(), os, emitArgs)))
if (failed(interleaveCommaWithError(*callOpaqueOp.getTemplateArgs(), os,
emitArgs)))
return failure();
os << ">";
}

os << "(";

LogicalResult emittedArgs =
callOp.getArgs()
? interleaveCommaWithError(*callOp.getArgs(), os, emitArgs)
callOpaqueOp.getArgs()
? interleaveCommaWithError(*callOpaqueOp.getArgs(), os, emitArgs)
: emitter.emitOperands(op);
if (failed(emittedArgs))
return failure();
Expand Down Expand Up @@ -949,10 +950,11 @@ LogicalResult CppEmitter::emitOperation(Operation &op, bool trailingSemicolon) {
.Case<cf::BranchOp, cf::CondBranchOp>(
[&](auto op) { return printOperation(*this, op); })
// EmitC ops.
.Case<emitc::AddOp, emitc::ApplyOp, emitc::AssignOp, emitc::CallOp,
emitc::CastOp, emitc::CmpOp, emitc::ConstantOp, emitc::DivOp,
emitc::ForOp, emitc::IfOp, emitc::IncludeOp, emitc::MulOp,
emitc::RemOp, emitc::SubOp, emitc::VariableOp>(
.Case<emitc::AddOp, emitc::ApplyOp, emitc::AssignOp,
emitc::CallOpaqueOp, emitc::CastOp, emitc::CmpOp,
emitc::ConstantOp, emitc::DivOp, emitc::ForOp, emitc::IfOp,
emitc::IncludeOp, emitc::MulOp, emitc::RemOp, emitc::SubOp,
emitc::VariableOp>(
[&](auto op) { return printOperation(*this, op); })
// Func ops.
.Case<func::CallOp, func::ConstantOp, func::FuncOp, func::ReturnOp>(
Expand Down
28 changes: 14 additions & 14 deletions mlir/test/Conversion/SCFToEmitC/if.mlir
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,35 @@

func.func @test_if(%arg0: i1, %arg1: f32) {
scf.if %arg0 {
%0 = emitc.call "func_const"(%arg1) : (f32) -> i32
%0 = emitc.call_opaque "func_const"(%arg1) : (f32) -> i32
}
return
}
// CHECK-LABEL: func.func @test_if(
// CHECK-SAME: %[[VAL_0:.*]]: i1,
// CHECK-SAME: %[[VAL_1:.*]]: f32) {
// CHECK-NEXT: emitc.if %[[VAL_0]] {
// CHECK-NEXT: %[[VAL_2:.*]] = emitc.call "func_const"(%[[VAL_1]]) : (f32) -> i32
// CHECK-NEXT: %[[VAL_2:.*]] = emitc.call_opaque "func_const"(%[[VAL_1]]) : (f32) -> i32
// CHECK-NEXT: }
// CHECK-NEXT: return
// CHECK-NEXT: }


func.func @test_if_else(%arg0: i1, %arg1: f32) {
scf.if %arg0 {
%0 = emitc.call "func_true"(%arg1) : (f32) -> i32
%0 = emitc.call_opaque "func_true"(%arg1) : (f32) -> i32
} else {
%0 = emitc.call "func_false"(%arg1) : (f32) -> i32
%0 = emitc.call_opaque "func_false"(%arg1) : (f32) -> i32
}
return
}
// CHECK-LABEL: func.func @test_if_else(
// CHECK-SAME: %[[VAL_0:.*]]: i1,
// CHECK-SAME: %[[VAL_1:.*]]: f32) {
// CHECK-NEXT: emitc.if %[[VAL_0]] {
// CHECK-NEXT: %[[VAL_2:.*]] = emitc.call "func_true"(%[[VAL_1]]) : (f32) -> i32
// CHECK-NEXT: %[[VAL_2:.*]] = emitc.call_opaque "func_true"(%[[VAL_1]]) : (f32) -> i32
// CHECK-NEXT: } else {
// CHECK-NEXT: %[[VAL_3:.*]] = emitc.call "func_false"(%[[VAL_1]]) : (f32) -> i32
// CHECK-NEXT: %[[VAL_3:.*]] = emitc.call_opaque "func_false"(%[[VAL_1]]) : (f32) -> i32
// CHECK-NEXT: }
// CHECK-NEXT: return
// CHECK-NEXT: }
Expand All @@ -39,12 +39,12 @@ func.func @test_if_else(%arg0: i1, %arg1: f32) {
func.func @test_if_yield(%arg0: i1, %arg1: f32) {
%0 = arith.constant 0 : i8
%x, %y = scf.if %arg0 -> (i32, f64) {
%1 = emitc.call "func_true_1"(%arg1) : (f32) -> i32
%2 = emitc.call "func_true_2"(%arg1) : (f32) -> f64
%1 = emitc.call_opaque "func_true_1"(%arg1) : (f32) -> i32
%2 = emitc.call_opaque "func_true_2"(%arg1) : (f32) -> f64
scf.yield %1, %2 : i32, f64
} else {
%1 = emitc.call "func_false_1"(%arg1) : (f32) -> i32
%2 = emitc.call "func_false_2"(%arg1) : (f32) -> f64
%1 = emitc.call_opaque "func_false_1"(%arg1) : (f32) -> i32
%2 = emitc.call_opaque "func_false_2"(%arg1) : (f32) -> f64
scf.yield %1, %2 : i32, f64
}
return
Expand All @@ -56,13 +56,13 @@ func.func @test_if_yield(%arg0: i1, %arg1: f32) {
// CHECK-NEXT: %[[VAL_3:.*]] = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> i32
// CHECK-NEXT: %[[VAL_4:.*]] = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> f64
// CHECK-NEXT: emitc.if %[[VAL_0]] {
// CHECK-NEXT: %[[VAL_5:.*]] = emitc.call "func_true_1"(%[[VAL_1]]) : (f32) -> i32
// CHECK-NEXT: %[[VAL_6:.*]] = emitc.call "func_true_2"(%[[VAL_1]]) : (f32) -> f64
// CHECK-NEXT: %[[VAL_5:.*]] = emitc.call_opaque "func_true_1"(%[[VAL_1]]) : (f32) -> i32
// CHECK-NEXT: %[[VAL_6:.*]] = emitc.call_opaque "func_true_2"(%[[VAL_1]]) : (f32) -> f64
// CHECK-NEXT: emitc.assign %[[VAL_5]] : i32 to %[[VAL_3]] : i32
// CHECK-NEXT: emitc.assign %[[VAL_6]] : f64 to %[[VAL_4]] : f64
// CHECK-NEXT: } else {
// CHECK-NEXT: %[[VAL_7:.*]] = emitc.call "func_false_1"(%[[VAL_1]]) : (f32) -> i32
// CHECK-NEXT: %[[VAL_8:.*]] = emitc.call "func_false_2"(%[[VAL_1]]) : (f32) -> f64
// CHECK-NEXT: %[[VAL_7:.*]] = emitc.call_opaque "func_false_1"(%[[VAL_1]]) : (f32) -> i32
// CHECK-NEXT: %[[VAL_8:.*]] = emitc.call_opaque "func_false_2"(%[[VAL_1]]) : (f32) -> f64
// CHECK-NEXT: emitc.assign %[[VAL_7]] : i32 to %[[VAL_3]] : i32
// CHECK-NEXT: emitc.assign %[[VAL_8]] : f64 to %[[VAL_4]] : f64
// CHECK-NEXT: }
Expand Down
4 changes: 2 additions & 2 deletions mlir/test/Dialect/EmitC/attrs.mlir
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
// CHECK-LABEL: func @opaque_attrs() {
func.func @opaque_attrs() {
// CHECK-NEXT: #emitc.opaque<"attr">
emitc.call "f"() {args = [#emitc.opaque<"attr">]} : () -> ()
emitc.call_opaque "f"() {args = [#emitc.opaque<"attr">]} : () -> ()
// CHECK-NEXT: #emitc.opaque<"\22quoted_attr\22">
emitc.call "f"() {args = [#emitc.opaque<"\"quoted_attr\"">]} : () -> ()
emitc.call_opaque "f"() {args = [#emitc.opaque<"\"quoted_attr\"">]} : () -> ()
return
}
24 changes: 12 additions & 12 deletions mlir/test/Dialect/EmitC/invalid_ops.mlir
Original file line number Diff line number Diff line change
Expand Up @@ -25,48 +25,48 @@ func.func @empty_constant() {
// -----

func.func @index_args_out_of_range_1() {
// expected-error @+1 {{'emitc.call' op index argument is out of range}}
emitc.call "test" () {args = [0 : index]} : () -> ()
// expected-error @+1 {{'emitc.call_opaque' op index argument is out of range}}
emitc.call_opaque "test" () {args = [0 : index]} : () -> ()
return
}

// -----

func.func @index_args_out_of_range_2(%arg : i32) {
// expected-error @+1 {{'emitc.call' op index argument is out of range}}
emitc.call "test" (%arg, %arg) {args = [2 : index]} : (i32, i32) -> ()
// expected-error @+1 {{'emitc.call_opaque' op index argument is out of range}}
emitc.call_opaque "test" (%arg, %arg) {args = [2 : index]} : (i32, i32) -> ()
return
}

// -----

func.func @empty_callee() {
// expected-error @+1 {{'emitc.call' op callee must not be empty}}
emitc.call "" () : () -> ()
// expected-error @+1 {{'emitc.call_opaque' op callee must not be empty}}
emitc.call_opaque "" () : () -> ()
return
}

// -----

func.func @nonetype_arg(%arg : i32) {
// expected-error @+1 {{'emitc.call' op array argument has no type}}
emitc.call "nonetype_arg"(%arg) {args = [0 : index, [0, 1, 2]]} : (i32) -> i32
// expected-error @+1 {{'emitc.call_opaque' op array argument has no type}}
emitc.call_opaque "nonetype_arg"(%arg) {args = [0 : index, [0, 1, 2]]} : (i32) -> i32
return
}

// -----

func.func @array_template_arg(%arg : i32) {
// expected-error @+1 {{'emitc.call' op template argument has invalid type}}
emitc.call "nonetype_template_arg"(%arg) {template_args = [[0, 1, 2]]} : (i32) -> i32
// expected-error @+1 {{'emitc.call_opaque' op template argument has invalid type}}
emitc.call_opaque "nonetype_template_arg"(%arg) {template_args = [[0, 1, 2]]} : (i32) -> i32
return
}

// -----

func.func @dense_template_argument(%arg : i32) {
// expected-error @+1 {{'emitc.call' op template argument has invalid type}}
emitc.call "dense_template_argument"(%arg) {template_args = [dense<[1.0, 1.0]> : tensor<2xf32>]} : (i32) -> i32
// expected-error @+1 {{'emitc.call_opaque' op template argument has invalid type}}
emitc.call_opaque "dense_template_argument"(%arg) {template_args = [dense<[1.0, 1.0]> : tensor<2xf32>]} : (i32) -> i32
return
}

Expand Down
18 changes: 9 additions & 9 deletions mlir/test/Dialect/EmitC/ops.mlir
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ emitc.include "test.h"

// CHECK-LABEL: func @f(%{{.*}}: i32, %{{.*}}: !emitc.opaque<"int32_t">) {
func.func @f(%arg0: i32, %f: !emitc.opaque<"int32_t">) {
%1 = "emitc.call"() {callee = "blah"} : () -> i64
emitc.call "foo" (%1) {args = [
%1 = "emitc.call_opaque"() {callee = "blah"} : () -> i64
emitc.call_opaque "foo" (%1) {args = [
0 : index, dense<[0, 1]> : tensor<2xi32>, 0 : index
]} : (i64) -> ()
return
Expand Down Expand Up @@ -100,24 +100,24 @@ func.func @cmp(%arg0 : i32, %arg1 : f32, %arg2 : i64, %arg3 : f64, %arg4 : !emit

func.func @test_if(%arg0: i1, %arg1: f32) {
emitc.if %arg0 {
%0 = emitc.call "func_const"(%arg1) : (f32) -> i32
%0 = emitc.call_opaque "func_const"(%arg1) : (f32) -> i32
}
return
}

func.func @test_if_explicit_yield(%arg0: i1, %arg1: f32) {
emitc.if %arg0 {
%0 = emitc.call "func_const"(%arg1) : (f32) -> i32
%0 = emitc.call_opaque "func_const"(%arg1) : (f32) -> i32
emitc.yield
}
return
}

func.func @test_if_else(%arg0: i1, %arg1: f32) {
emitc.if %arg0 {
%0 = emitc.call "func_true"(%arg1) : (f32) -> i32
%0 = emitc.call_opaque "func_true"(%arg1) : (f32) -> i32
} else {
%0 = emitc.call "func_false"(%arg1) : (f32) -> i32
%0 = emitc.call_opaque "func_false"(%arg1) : (f32) -> i32
}
return
}
Expand All @@ -130,22 +130,22 @@ func.func @test_assign(%arg1: f32) {

func.func @test_for(%arg0 : index, %arg1 : index, %arg2 : index) {
emitc.for %i0 = %arg0 to %arg1 step %arg2 {
%0 = emitc.call "func_const"(%i0) : (index) -> i32
%0 = emitc.call_opaque "func_const"(%i0) : (index) -> i32
}
return
}

func.func @test_for_explicit_yield(%arg0 : index, %arg1 : index, %arg2 : index) {
emitc.for %i0 = %arg0 to %arg1 step %arg2 {
%0 = emitc.call "func_const"(%i0) : (index) -> i32
%0 = emitc.call_opaque "func_const"(%i0) : (index) -> i32
emitc.yield
}
return
}

func.func @test_for_not_index_induction(%arg0 : i16, %arg1 : i16, %arg2 : i16) {
emitc.for %i0 = %arg0 to %arg1 step %arg2 : i16 {
%0 = emitc.call "func_const"(%i0) : (i16) -> i32
%0 = emitc.call_opaque "func_const"(%i0) : (i16) -> i32
}
return
}
26 changes: 13 additions & 13 deletions mlir/test/Dialect/EmitC/types.mlir
Original file line number Diff line number Diff line change
Expand Up @@ -5,37 +5,37 @@
// CHECK-LABEL: func @opaque_types() {
func.func @opaque_types() {
// CHECK-NEXT: !emitc.opaque<"int">
emitc.call "f"() {template_args = [!emitc<opaque<"int">>]} : () -> ()
emitc.call_opaque "f"() {template_args = [!emitc<opaque<"int">>]} : () -> ()
// CHECK-NEXT: !emitc.opaque<"byte">
emitc.call "f"() {template_args = [!emitc<opaque<"byte">>]} : () -> ()
emitc.call_opaque "f"() {template_args = [!emitc<opaque<"byte">>]} : () -> ()
// CHECK-NEXT: !emitc.opaque<"unsigned">
emitc.call "f"() {template_args = [!emitc<opaque<"unsigned">>]} : () -> ()
emitc.call_opaque "f"() {template_args = [!emitc<opaque<"unsigned">>]} : () -> ()
// CHECK-NEXT: !emitc.opaque<"status_t">
emitc.call "f"() {template_args = [!emitc<opaque<"status_t">>]} : () -> ()
emitc.call_opaque "f"() {template_args = [!emitc<opaque<"status_t">>]} : () -> ()
// CHECK-NEXT: !emitc.opaque<"std::vector<std::string>">
emitc.call "f"() {template_args = [!emitc.opaque<"std::vector<std::string>">]} : () -> ()
emitc.call_opaque "f"() {template_args = [!emitc.opaque<"std::vector<std::string>">]} : () -> ()
// CHECK-NEXT: !emitc.opaque<"SmallVector<int*, 4>">
emitc.call "f"() {template_args = [!emitc.opaque<"SmallVector<int*, 4>">]} : () -> ()
emitc.call_opaque "f"() {template_args = [!emitc.opaque<"SmallVector<int*, 4>">]} : () -> ()

return
}

// CHECK-LABEL: func @pointer_types() {
func.func @pointer_types() {
// CHECK-NEXT: !emitc.ptr<i32>
emitc.call "f"() {template_args = [!emitc.ptr<i32>]} : () -> ()
emitc.call_opaque "f"() {template_args = [!emitc.ptr<i32>]} : () -> ()
// CHECK-NEXT: !emitc.ptr<i64>
emitc.call "f"() {template_args = [!emitc.ptr<i64>]} : () -> ()
emitc.call_opaque "f"() {template_args = [!emitc.ptr<i64>]} : () -> ()
// CHECK-NEXT: !emitc.ptr<f32>
emitc.call "f"() {template_args = [!emitc.ptr<f32>]} : () -> ()
emitc.call_opaque "f"() {template_args = [!emitc.ptr<f32>]} : () -> ()
// CHECK-NEXT: !emitc.ptr<f64>
emitc.call "f"() {template_args = [!emitc.ptr<f64>]} : () -> ()
emitc.call_opaque "f"() {template_args = [!emitc.ptr<f64>]} : () -> ()
// CHECK-NEXT: !emitc.ptr<i32>
%0 = emitc.call "f"() : () -> (!emitc.ptr<i32>)
%0 = emitc.call_opaque "f"() : () -> (!emitc.ptr<i32>)
// CHECK-NEXT: (!emitc.ptr<i32>) -> !emitc.ptr<!emitc.ptr<i32>>
%1 = emitc.call "f"(%0) : (!emitc.ptr<i32>) -> (!emitc.ptr<!emitc.ptr<i32>>)
%1 = emitc.call_opaque "f"(%0) : (!emitc.ptr<i32>) -> (!emitc.ptr<!emitc.ptr<i32>>)
// CHECK-NEXT: !emitc.ptr<!emitc.opaque<"int">>
emitc.call "f"() {template_args = [!emitc.ptr<!emitc.opaque<"int">>]} : () -> ()
emitc.call_opaque "f"() {template_args = [!emitc.ptr<!emitc.opaque<"int">>]} : () -> ()

return
}
Loading