Skip to content

Commit a955c18

Browse files
committed
[mlir][emitc] Refactor emitc.apply op
The emitc.apply op models both C's address-taking and dereferencing operators using an attribute to select the concrete opcode. This patch replaces emitc.apply with a pair of emitc.address_of and emitc.dereference ops. Unlike emitc.apply, which supported taking the address of the C variables expected to hold SSA values, the new emitc.address_of op limits address taking to the C variables modeled by the dialect by requiring its operand to be defined by an emitc.variable op.
1 parent 1949fe9 commit a955c18

File tree

6 files changed

+111
-69
lines changed

6 files changed

+111
-69
lines changed

mlir/include/mlir/Dialect/EmitC/IR/EmitC.td

Lines changed: 32 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -63,31 +63,23 @@ def EmitC_AddOp : EmitC_BinaryOp<"add", []> {
6363
let hasVerifier = 1;
6464
}
6565

66-
def EmitC_ApplyOp : EmitC_Op<"apply", []> {
67-
let summary = "Apply operation";
66+
def EmitC_AddressOfOp : EmitC_Op<"address_of", []> {
67+
let summary = "Address operation";
6868
let description = [{
69-
With the `apply` operation the operators & (address of) and * (contents of)
70-
can be applied to a single operand.
69+
This operation models the C & (address of) operator for a single operand which
70+
must be an emitc.variable. It returns an emitc pointer to the variable.
7171

7272
Example:
7373

7474
```mlir
7575
// Custom form of applying the & operator.
76-
%0 = emitc.apply "&"(%arg0) : (i32) -> !emitc.ptr<i32>
77-
78-
// Generic form of the same operation.
79-
%0 = "emitc.apply"(%arg0) {applicableOperator = "&"}
80-
: (i32) -> !emitc.ptr<i32>
81-
76+
%0 = emitc.address_of %arg0 : (i32) -> !emitc.ptr<i32>
8277
```
8378
}];
84-
let arguments = (ins
85-
Arg<StrAttr, "the operator to apply">:$applicableOperator,
86-
AnyType:$operand
87-
);
88-
let results = (outs AnyType:$result);
79+
let arguments = (ins AnyType:$var);
80+
let results = (outs EmitC_PointerType:$result);
8981
let assemblyFormat = [{
90-
$applicableOperator `(` $operand `)` attr-dict `:` functional-type($operand, results)
82+
$var attr-dict `:` functional-type($var, $result)
9183
}];
9284
let hasVerifier = 1;
9385
}
@@ -222,6 +214,27 @@ def EmitC_ConstantOp : EmitC_Op<"constant", [ConstantLike]> {
222214
let hasVerifier = 1;
223215
}
224216

217+
def EmitC_DereferenceOp : EmitC_Op<"dereference", []> {
218+
let summary = "Dereference operation";
219+
let description = [{
220+
This operation models the C * (dereference) operator for a single operand which
221+
must be of !emitc.ptr<> type. It returns the value pointed to by the pointer.
222+
223+
Example:
224+
225+
```mlir
226+
// Custom form of applying the & operator.
227+
%0 = emitc.dereference %arg0 : (!emitc.ptr<i32>) -> i32
228+
```
229+
}];
230+
let arguments = (ins EmitC_PointerType:$pointer);
231+
let results = (outs AnyType:$result);
232+
let assemblyFormat = [{
233+
$pointer attr-dict `:` functional-type($pointer, $result)
234+
}];
235+
let hasVerifier = 1;
236+
}
237+
225238
def EmitC_DivOp : EmitC_BinaryOp<"div", []> {
226239
let summary = "Division operation";
227240
let description = [{
@@ -448,12 +461,12 @@ def EmitC_VariableOp : EmitC_Op<"variable", []> {
448461

449462
Since folding is not supported, it can be used with pointers.
450463
As an example, it is valid to create pointers to `variable` operations
451-
by using `apply` operations and pass these to a `call` operation.
464+
by using `address_of` operations and pass these to a `call` operation.
452465
```mlir
453466
%0 = "emitc.variable"() {value = 0 : i32} : () -> i32
454467
%1 = "emitc.variable"() {value = 0 : i32} : () -> i32
455-
%2 = emitc.apply "&"(%0) : (i32) -> !emitc.ptr<i32>
456-
%3 = emitc.apply "&"(%1) : (i32) -> !emitc.ptr<i32>
468+
%2 = emitc.address_of %0 : (i32) -> !emitc.ptr<i32>
469+
%3 = emitc.address_of %1 : (i32) -> !emitc.ptr<i32>
457470
emitc.call "write"(%2, %3) : (!emitc.ptr<i32>, !emitc.ptr<i32>) -> ()
458471
```
459472
}];

mlir/lib/Dialect/EmitC/IR/EmitC.cpp

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -72,23 +72,21 @@ LogicalResult AddOp::verify() {
7272
}
7373

7474
//===----------------------------------------------------------------------===//
75-
// ApplyOp
75+
// AddressOfOp
7676
//===----------------------------------------------------------------------===//
7777

78-
LogicalResult ApplyOp::verify() {
79-
StringRef applicableOperatorStr = getApplicableOperator();
80-
81-
// Applicable operator must not be empty.
82-
if (applicableOperatorStr.empty())
83-
return emitOpError("applicable operator must not be empty");
78+
LogicalResult AddressOfOp::verify() {
79+
Value variable = getVar();
80+
auto variableDef = dyn_cast_if_present<VariableOp>(variable.getDefiningOp());
81+
if (!variableDef)
82+
return emitOpError() << "requires operand to be a variable";
8483

85-
// Only `*` and `&` are supported.
86-
if (applicableOperatorStr != "&" && applicableOperatorStr != "*")
87-
return emitOpError("applicable operator is illegal");
84+
Type variableType = variable.getType();
85+
emitc::PointerType resultType = getResult().getType();
86+
Type pointeeType = resultType.getPointee();
8887

89-
Operation *op = getOperand().getDefiningOp();
90-
if (op && dyn_cast<ConstantOp>(op))
91-
return emitOpError("cannot apply to constant");
88+
if (variableType != pointeeType)
89+
return emitOpError("requires variable to be of type pointed to by result");
9290

9391
return success();
9492
}
@@ -189,6 +187,23 @@ LogicalResult emitc::ConstantOp::verify() {
189187

190188
OpFoldResult emitc::ConstantOp::fold(FoldAdaptor adaptor) { return getValue(); }
191189

190+
//===----------------------------------------------------------------------===//
191+
// DereferenceOp
192+
//===----------------------------------------------------------------------===//
193+
194+
LogicalResult DereferenceOp::verify() {
195+
auto pointer = getPointer();
196+
emitc::PointerType pointerType = pointer.getType();
197+
Type pointeeType = pointerType.getPointee();
198+
Type resultType = getResult().getType();
199+
200+
if (pointeeType != resultType)
201+
return emitOpError()
202+
<< "requires result to be of type pointed to by operand";
203+
204+
return success();
205+
}
206+
192207
//===----------------------------------------------------------------------===//
193208
// ForOp
194209
//===----------------------------------------------------------------------===//

mlir/lib/Target/Cpp/TranslateToCpp.cpp

Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,19 @@ static LogicalResult printConstantOp(CppEmitter &emitter, Operation *operation,
213213
return emitter.emitAttribute(operation->getLoc(), value);
214214
}
215215

216+
static LogicalResult printOperation(CppEmitter &emitter,
217+
emitc::AddressOfOp addressOfOp) {
218+
raw_ostream &os = emitter.ostream();
219+
Operation &op = *addressOfOp.getOperation();
220+
221+
if (failed(emitter.emitAssignPrefix(op)))
222+
return failure();
223+
os << "&";
224+
os << emitter.getOrCreateName(addressOfOp.getOperand());
225+
226+
return success();
227+
}
228+
216229
static LogicalResult printOperation(CppEmitter &emitter,
217230
emitc::ConstantOp constantOp) {
218231
Operation *operation = constantOp.getOperation();
@@ -461,30 +474,30 @@ static LogicalResult printOperation(CppEmitter &emitter, emitc::CallOp callOp) {
461474
return success();
462475
}
463476

464-
static LogicalResult printOperation(CppEmitter &emitter,
465-
emitc::ApplyOp applyOp) {
477+
static LogicalResult printOperation(CppEmitter &emitter, emitc::CastOp castOp) {
466478
raw_ostream &os = emitter.ostream();
467-
Operation &op = *applyOp.getOperation();
479+
Operation &op = *castOp.getOperation();
468480

469481
if (failed(emitter.emitAssignPrefix(op)))
470482
return failure();
471-
os << applyOp.getApplicableOperator();
472-
os << emitter.getOrCreateName(applyOp.getOperand());
483+
os << "(";
484+
if (failed(emitter.emitType(op.getLoc(), op.getResult(0).getType())))
485+
return failure();
486+
os << ") ";
487+
os << emitter.getOrCreateName(castOp.getOperand());
473488

474489
return success();
475490
}
476491

477-
static LogicalResult printOperation(CppEmitter &emitter, emitc::CastOp castOp) {
492+
static LogicalResult printOperation(CppEmitter &emitter,
493+
emitc::DereferenceOp dereferenceOp) {
478494
raw_ostream &os = emitter.ostream();
479-
Operation &op = *castOp.getOperation();
495+
Operation &op = *dereferenceOp.getOperation();
480496

481497
if (failed(emitter.emitAssignPrefix(op)))
482498
return failure();
483-
os << "(";
484-
if (failed(emitter.emitType(op.getLoc(), op.getResult(0).getType())))
485-
return failure();
486-
os << ") ";
487-
os << emitter.getOrCreateName(castOp.getOperand());
499+
os << "*";
500+
os << emitter.getOrCreateName(dereferenceOp.getOperand());
488501

489502
return success();
490503
}
@@ -949,10 +962,11 @@ LogicalResult CppEmitter::emitOperation(Operation &op, bool trailingSemicolon) {
949962
.Case<cf::BranchOp, cf::CondBranchOp>(
950963
[&](auto op) { return printOperation(*this, op); })
951964
// EmitC ops.
952-
.Case<emitc::AddOp, emitc::ApplyOp, emitc::AssignOp, emitc::CallOp,
953-
emitc::CastOp, emitc::CmpOp, emitc::ConstantOp, emitc::DivOp,
954-
emitc::ForOp, emitc::IfOp, emitc::IncludeOp, emitc::MulOp,
955-
emitc::RemOp, emitc::SubOp, emitc::VariableOp>(
965+
.Case<emitc::AddOp, emitc::AddressOfOp, emitc::AssignOp,
966+
emitc::CallOp, emitc::CastOp, emitc::CmpOp, emitc::ConstantOp,
967+
emitc::DereferenceOp, emitc::DivOp, emitc::ForOp, emitc::IfOp,
968+
emitc::IncludeOp, emitc::MulOp, emitc::RemOp, emitc::SubOp,
969+
emitc::VariableOp>(
956970
[&](auto op) { return printOperation(*this, op); })
957971
// Func ops.
958972
.Case<func::CallOp, func::ConstantOp, func::FuncOp, func::ReturnOp>(

mlir/test/Dialect/EmitC/invalid_ops.mlir

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -72,26 +72,18 @@ func.func @dense_template_argument(%arg : i32) {
7272

7373
// -----
7474

75-
func.func @empty_operator(%arg : i32) {
76-
// expected-error @+1 {{'emitc.apply' op applicable operator must not be empty}}
77-
%2 = emitc.apply ""(%arg) : (i32) -> !emitc.ptr<i32>
78-
return
79-
}
80-
81-
// -----
82-
83-
func.func @illegal_operator(%arg : i32) {
84-
// expected-error @+1 {{'emitc.apply' op applicable operator is illegal}}
85-
%2 = emitc.apply "+"(%arg) : (i32) -> !emitc.ptr<i32>
75+
func.func @illegal_address_of_operand() {
76+
%1 = "emitc.constant"(){value = 42: i32} : () -> i32
77+
// expected-error @+1 {{'emitc.address_of' op requires operand to be a variable}}
78+
%2 = emitc.address_of %1 : (i32) -> !emitc.ptr<i32>
8679
return
8780
}
8881

8982
// -----
9083

91-
func.func @illegal_operand() {
92-
%1 = "emitc.constant"(){value = 42: i32} : () -> i32
93-
// expected-error @+1 {{'emitc.apply' op cannot apply to constant}}
94-
%2 = emitc.apply "&"(%1) : (i32) -> !emitc.ptr<i32>
84+
func.func @illegal_dereference_operand(%arg0 : !emitc.ptr<i32>) {
85+
// expected-error @+1 {{'emitc.dereference' op requires result to be of type pointed to by operand}}
86+
%2 = emitc.dereference %arg0 : (!emitc.ptr<i32>) -> (f32)
9587
return
9688
}
9789

mlir/test/Dialect/EmitC/ops.mlir

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,10 @@ func.func @c() {
2525
return
2626
}
2727

28-
func.func @a(%arg0: i32, %arg1: i32) {
29-
%1 = "emitc.apply"(%arg0) {applicableOperator = "&"} : (i32) -> !emitc.ptr<i32>
30-
%2 = emitc.apply "&"(%arg1) : (i32) -> !emitc.ptr<i32>
28+
func.func @a() {
29+
%arg0 = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> i32
30+
%1 = "emitc.address_of"(%arg0) : (i32) -> !emitc.ptr<i32>
31+
%2 = emitc.address_of %arg0 : (i32) -> !emitc.ptr<i32>
3132
return
3233
}
3334

@@ -47,6 +48,12 @@ func.func @div_int(%arg0: i32, %arg1: i32) {
4748
return
4849
}
4950

51+
func.func @dereference(%arg0: !emitc.ptr<i32>) {
52+
%1 = "emitc.dereference"(%arg0) : (!emitc.ptr<i32>) -> (i32)
53+
%2 = emitc.dereference %arg0 : (!emitc.ptr<i32>) -> (i32)
54+
return
55+
}
56+
5057
func.func @div_float(%arg0: f32, %arg1: f32) {
5158
%1 = "emitc.div" (%arg0, %arg1) : (f32, f32) -> f32
5259
return

mlir/test/Target/Cpp/common-cpp.mlir

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,10 +82,11 @@ func.func @opaque_types(%arg0: !emitc.opaque<"bool">, %arg1: !emitc.opaque<"char
8282
return %2 : !emitc.opaque<"status_t">
8383
}
8484

85-
func.func @apply(%arg0: i32) -> !emitc.ptr<i32> {
85+
func.func @apply() -> !emitc.ptr<i32> {
86+
%arg0 = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> i32
8687
// CHECK: int32_t* [[V2]] = &[[V1]];
87-
%0 = emitc.apply "&"(%arg0) : (i32) -> !emitc.ptr<i32>
88+
%0 = emitc.address_of %arg0 : (i32) -> !emitc.ptr<i32>
8889
// CHECK: int32_t [[V3]] = *[[V2]];
89-
%1 = emitc.apply "*"(%0) : (!emitc.ptr<i32>) -> (i32)
90+
%1 = emitc.dereference %0 : (!emitc.ptr<i32>) -> (i32)
9091
return %0 : !emitc.ptr<i32>
9192
}

0 commit comments

Comments
 (0)