Skip to content

Commit a5cf99d

Browse files
authored
[mlir][EmitC] Add member access ops (#98460)
This adds an `emitc.member` and `emitc.member_of_ptr` operation for the corresponding member access operators. Furthermore, `emitc.assign` is adjusted to be used with the member access operators.
1 parent c8f2ee7 commit a5cf99d

File tree

6 files changed

+136
-6
lines changed

6 files changed

+136
-6
lines changed

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

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -908,6 +908,48 @@ def EmitC_SubOp : EmitC_BinaryOp<"sub", [CExpression]> {
908908
let hasVerifier = 1;
909909
}
910910

911+
def EmitC_MemberOp : EmitC_Op<"member"> {
912+
let summary = "Member operation";
913+
let description = [{
914+
With the `member` operation the member access operator `.` can be
915+
applied.
916+
917+
Example:
918+
919+
```mlir
920+
%0 = "emitc.member" (%arg0) {member = "a"}
921+
: (!emitc.opaque<"mystruct">) -> i32
922+
```
923+
}];
924+
925+
let arguments = (ins
926+
Arg<StrAttr, "the member to access">:$member,
927+
EmitC_OpaqueType:$operand
928+
);
929+
let results = (outs EmitCType);
930+
}
931+
932+
def EmitC_MemberOfPtrOp : EmitC_Op<"member_of_ptr"> {
933+
let summary = "Member of pointer operation";
934+
let description = [{
935+
With the `member_of_ptr` operation the member access operator `->`
936+
can be applied.
937+
938+
Example:
939+
940+
```mlir
941+
%0 = "emitc.member_of_ptr" (%arg0) {member = "a"}
942+
: (!emitc.ptr<!emitc.opaque<"mystruct">>) -> i32
943+
```
944+
}];
945+
946+
let arguments = (ins
947+
Arg<StrAttr, "the member to access">:$member,
948+
AnyTypeOf<[EmitC_OpaqueType,EmitC_PointerType]>:$operand
949+
);
950+
let results = (outs EmitCType);
951+
}
952+
911953
def EmitC_ConditionalOp : EmitC_Op<"conditional",
912954
[AllTypesMatch<["true_value", "false_value", "result"]>, CExpression]> {
913955
let summary = "Conditional (ternary) operation";

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -213,10 +213,11 @@ LogicalResult emitc::AssignOp::verify() {
213213
Value variable = getVar();
214214
Operation *variableDef = variable.getDefiningOp();
215215
if (!variableDef ||
216-
!llvm::isa<emitc::GetGlobalOp, emitc::SubscriptOp, emitc::VariableOp>(
217-
variableDef))
216+
!llvm::isa<emitc::GetGlobalOp, emitc::MemberOp, emitc::MemberOfPtrOp,
217+
emitc::SubscriptOp, emitc::VariableOp>(variableDef))
218218
return emitOpError() << "requires first operand (" << variable
219-
<< ") to be a get_global, subscript or variable";
219+
<< ") to be a get_global, member, member of pointer, "
220+
"subscript or variable";
220221

221222
Value value = getValue();
222223
if (variable.getType() != value.getType())

mlir/lib/Target/Cpp/TranslateToCpp.cpp

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,12 @@ struct CppEmitter {
183183
// Returns the textual representation of a subscript operation.
184184
std::string getSubscriptName(emitc::SubscriptOp op);
185185

186+
// Returns the textual representation of a member (of object) operation.
187+
std::string createMemberAccess(emitc::MemberOp op);
188+
189+
// Returns the textual representation of a member of pointer operation.
190+
std::string createMemberAccess(emitc::MemberOfPtrOp op);
191+
186192
/// Return the existing or a new label of a Block.
187193
StringRef getOrCreateName(Block &block);
188194

@@ -278,8 +284,8 @@ struct CppEmitter {
278284

279285
/// Determine whether expression \p op should be emitted in a deferred way.
280286
static bool hasDeferredEmission(Operation *op) {
281-
return isa_and_nonnull<emitc::GetGlobalOp, emitc::LiteralOp,
282-
emitc::SubscriptOp>(op);
287+
return isa_and_nonnull<emitc::GetGlobalOp, emitc::LiteralOp, emitc::MemberOp,
288+
emitc::MemberOfPtrOp, emitc::SubscriptOp>(op);
283289
}
284290

285291
/// Determine whether expression \p expressionOp should be emitted inline, i.e.
@@ -1125,6 +1131,22 @@ std::string CppEmitter::getSubscriptName(emitc::SubscriptOp op) {
11251131
return out;
11261132
}
11271133

1134+
std::string CppEmitter::createMemberAccess(emitc::MemberOp op) {
1135+
std::string out;
1136+
llvm::raw_string_ostream ss(out);
1137+
ss << getOrCreateName(op.getOperand());
1138+
ss << "." << op.getMember();
1139+
return out;
1140+
}
1141+
1142+
std::string CppEmitter::createMemberAccess(emitc::MemberOfPtrOp op) {
1143+
std::string out;
1144+
llvm::raw_string_ostream ss(out);
1145+
ss << getOrCreateName(op.getOperand());
1146+
ss << "->" << op.getMember();
1147+
return out;
1148+
}
1149+
11281150
void CppEmitter::cacheDeferredOpResult(Value value, StringRef str) {
11291151
if (!valueMapper.count(value))
11301152
valueMapper.insert(value, str.str());
@@ -1501,6 +1523,14 @@ LogicalResult CppEmitter::emitOperation(Operation &op, bool trailingSemicolon) {
15011523
cacheDeferredOpResult(op.getResult(), op.getValue());
15021524
return success();
15031525
})
1526+
.Case<emitc::MemberOp>([&](auto op) {
1527+
cacheDeferredOpResult(op.getResult(), createMemberAccess(op));
1528+
return success();
1529+
})
1530+
.Case<emitc::MemberOfPtrOp>([&](auto op) {
1531+
cacheDeferredOpResult(op.getResult(), createMemberAccess(op));
1532+
return success();
1533+
})
15041534
.Case<emitc::SubscriptOp>([&](auto op) {
15051535
cacheDeferredOpResult(op.getResult(), getSubscriptName(op));
15061536
return success();

mlir/test/Dialect/EmitC/invalid_ops.mlir

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ func.func @test_misplaced_yield() {
235235
// -----
236236

237237
func.func @test_assign_to_non_variable(%arg1: f32, %arg2: f32) {
238-
// expected-error @+1 {{'emitc.assign' op requires first operand (<block argument> of type 'f32' at index: 1) to be a get_global, subscript or variable}}
238+
// expected-error @+1 {{'emitc.assign' op requires first operand (<block argument> of type 'f32' at index: 1) to be a get_global, member, member of pointer, subscript or variable}}
239239
emitc.assign %arg1 : f32 to %arg2 : f32
240240
return
241241
}
@@ -450,3 +450,19 @@ func.func @use_global() {
450450
%0 = emitc.get_global @myglobal : f32
451451
return
452452
}
453+
454+
// -----
455+
456+
func.func @member(%arg0: i32) {
457+
// expected-error @+1 {{'emitc.member' op operand #0 must be EmitC opaque type, but got 'i32'}}
458+
%0 = "emitc.member" (%arg0) {member = "a"} : (i32) -> i32
459+
return
460+
}
461+
462+
// -----
463+
464+
func.func @member_of_ptr(%arg0: i32) {
465+
// expected-error @+1 {{'emitc.member_of_ptr' op operand #0 must be EmitC opaque type or EmitC pointer type, but got 'i32}}
466+
%0 = "emitc.member_of_ptr" (%arg0) {member = "a"} : (i32) -> i32
467+
return
468+
}

mlir/test/Dialect/EmitC/ops.mlir

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,3 +254,10 @@ func.func @assign_global(%arg0 : i32) {
254254
emitc.assign %arg0 : i32 to %0 : i32
255255
return
256256
}
257+
258+
func.func @member_access(%arg0: !emitc.opaque<"mystruct">, %arg1: !emitc.opaque<"mystruct_ptr">, %arg2: !emitc.ptr<!emitc.opaque<"mystruct">>) {
259+
%0 = "emitc.member" (%arg0) {member = "a"} : (!emitc.opaque<"mystruct">) -> i32
260+
%1 = "emitc.member_of_ptr" (%arg1) {member = "a"} : (!emitc.opaque<"mystruct_ptr">) -> i32
261+
%2 = "emitc.member_of_ptr" (%arg2) {member = "a"} : (!emitc.ptr<!emitc.opaque<"mystruct">>) -> i32
262+
return
263+
}

mlir/test/Target/Cpp/member.mlir

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// RUN: mlir-translate -mlir-to-cpp %s | FileCheck %s -check-prefix=CPP-DEFAULT
2+
3+
func.func @member(%arg0: !emitc.opaque<"mystruct">, %arg1: i32) {
4+
%0 = "emitc.member" (%arg0) {member = "a"} : (!emitc.opaque<"mystruct">) -> i32
5+
emitc.assign %arg1 : i32 to %0 : i32
6+
7+
%1 = "emitc.member" (%arg0) {member = "b"} : (!emitc.opaque<"mystruct">) -> i32
8+
%2 = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> i32
9+
emitc.assign %1 : i32 to %2 : i32
10+
11+
return
12+
}
13+
14+
// CPP-DEFAULT: void member(mystruct [[V0:[^ ]*]], int32_t [[V1:[^ ]*]]) {
15+
// CPP-DEFAULT-NEXT: [[V0:[^ ]*]].a = [[V1:[^ ]*]];
16+
// CPP-DEFAULT-NEXT: int32_t [[V2:[^ ]*]];
17+
// CPP-DEFAULT-NEXT: [[V2:[^ ]*]] = [[V0:[^ ]*]].b;
18+
19+
20+
func.func @member_of_pointer(%arg0: !emitc.ptr<!emitc.opaque<"mystruct">>, %arg1: i32) {
21+
%0 = "emitc.member_of_ptr" (%arg0) {member = "a"} : (!emitc.ptr<!emitc.opaque<"mystruct">>) -> i32
22+
emitc.assign %arg1 : i32 to %0 : i32
23+
24+
%1 = "emitc.member_of_ptr" (%arg0) {member = "b"} : (!emitc.ptr<!emitc.opaque<"mystruct">>) -> i32
25+
%2 = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> i32
26+
emitc.assign %1 : i32 to %2 : i32
27+
28+
return
29+
}
30+
31+
// CPP-DEFAULT: void member_of_pointer(mystruct* [[V0:[^ ]*]], int32_t [[V1:[^ ]*]]) {
32+
// CPP-DEFAULT-NEXT: [[V0:[^ ]*]]->a = [[V1:[^ ]*]];
33+
// CPP-DEFAULT-NEXT: int32_t [[V2:[^ ]*]];
34+
// CPP-DEFAULT-NEXT: [[V2:[^ ]*]] = [[V0:[^ ]*]]->b;

0 commit comments

Comments
 (0)