Skip to content

Commit f17abc2

Browse files
authored
[mlir][emitc] Add address-of and dereference ops (llvm#72569)
EmitC currently models C's `&` and `*` operators via its `apply` op, which has several drawbacks: - Its pre-lvalue semantics combines dereferencing with memory access. - Representing multiple opcodes (selected by an attribute) in a single op complicates the code by adding a second, attribute-based selection layer on top of MLIR's standard `isa<>` mechanism. This patch adds two distinct, lvalue-based ops to model these C operators. EmitC passes were converted to use the new ops instead of `apply`, which is now deprecated.
1 parent 2697c8c commit f17abc2

File tree

11 files changed

+199
-26
lines changed

11 files changed

+199
-26
lines changed

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

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,37 @@ def EmitC_FileOp
116116
let skipDefaultBuilders = 1;
117117
}
118118

119+
def EmitC_AddressOfOp : EmitC_Op<"address_of", [
120+
CExpressionInterface,
121+
TypesMatchWith<"input and result reference the same type", "reference", "result",
122+
"emitc::PointerType::get(::llvm::cast<emitc::LValueType>($_self).getValueType())">
123+
]> {
124+
let summary = "Address operation";
125+
let description = [{
126+
This operation models the C & (address of) operator for a single operand,
127+
which must be an emitc.lvalue, and returns an emitc pointer to its location.
128+
129+
Example:
130+
131+
```mlir
132+
// Custom form of applying the & operator.
133+
%0 = emitc.address_of %arg0 : (!emitc.lvalue<i32>) -> !emitc.ptr<i32>
134+
```
135+
}];
136+
let arguments = (ins EmitC_LValueType:$reference);
137+
let results = (outs EmitC_PointerType:$result);
138+
let assemblyFormat = [{
139+
$reference `:` qualified(type($reference)) attr-dict
140+
}];
141+
let hasVerifier = 1;
142+
143+
let extraClassDeclaration = [{
144+
bool hasSideEffects() {
145+
return false;
146+
}
147+
}];
148+
}
149+
119150
def EmitC_AddOp : EmitC_BinaryOp<"add", []> {
120151
let summary = "Addition operation";
121152
let description = [{
@@ -140,7 +171,7 @@ def EmitC_AddOp : EmitC_BinaryOp<"add", []> {
140171
}
141172

142173
def EmitC_ApplyOp : EmitC_Op<"apply", [CExpressionInterface]> {
143-
let summary = "Apply operation";
174+
let summary = "Deprecated (use address_of/dereference)";
144175
let description = [{
145176
With the `emitc.apply` operation the operators & (address of) and * (contents of)
146177
can be applied to a single operand.
@@ -439,6 +470,31 @@ def EmitC_ConstantOp
439470
}];
440471
}
441472

473+
def EmitC_DereferenceOp : EmitC_Op<"dereference", [
474+
TypesMatchWith<"input and result reference the same type", "pointer", "result",
475+
"emitc::LValueType::get(::llvm::cast<emitc::PointerType>($_self).getPointee())">
476+
]> {
477+
let summary = "Dereference operation";
478+
let description = [{
479+
This operation models the C * (dereference) operator, which must be of
480+
!emitc.ptr<> type, returning an !emitc.lvalue<> the value pointed to by the
481+
pointer.
482+
483+
Example:
484+
485+
```mlir
486+
// Custom form of the dereference operator.
487+
%0 = emitc.dereference %arg0 : (!emitc.ptr<i32>) -> !emitc.lvalue<i32>
488+
```
489+
}];
490+
let arguments = (ins EmitC_PointerType:$pointer);
491+
let results = (outs EmitC_LValueType:$result);
492+
let assemblyFormat = [{
493+
$pointer `:` qualified(type($pointer)) attr-dict
494+
}];
495+
let hasVerifier = 1;
496+
}
497+
442498
def EmitC_DivOp : EmitC_BinaryOp<"div", []> {
443499
let summary = "Division operation";
444500
let description = [{

mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ static Value calculateMemrefTotalSizeBytes(Location loc, MemRefType memrefType,
122122
return totalSizeBytes.getResult();
123123
}
124124

125-
static emitc::ApplyOp
125+
static emitc::AddressOfOp
126126
createPointerFromEmitcArray(Location loc, OpBuilder &builder,
127127
TypedValue<emitc::ArrayType> arrayValue) {
128128

@@ -133,9 +133,9 @@ createPointerFromEmitcArray(Location loc, OpBuilder &builder,
133133
llvm::SmallVector<mlir::Value> indices(arrayType.getRank(), zeroIndex);
134134
emitc::SubscriptOp subPtr =
135135
emitc::SubscriptOp::create(builder, loc, arrayValue, ValueRange(indices));
136-
emitc::ApplyOp ptr = emitc::ApplyOp::create(
136+
emitc::AddressOfOp ptr = emitc::AddressOfOp::create(
137137
builder, loc, emitc::PointerType::get(arrayType.getElementType()),
138-
builder.getStringAttr("&"), subPtr);
138+
subPtr);
139139

140140
return ptr;
141141
}
@@ -225,12 +225,12 @@ struct ConvertCopy final : public OpConversionPattern<memref::CopyOp> {
225225

226226
auto srcArrayValue =
227227
cast<TypedValue<emitc::ArrayType>>(operands.getSource());
228-
emitc::ApplyOp srcPtr =
228+
emitc::AddressOfOp srcPtr =
229229
createPointerFromEmitcArray(loc, rewriter, srcArrayValue);
230230

231231
auto targetArrayValue =
232232
cast<TypedValue<emitc::ArrayType>>(operands.getTarget());
233-
emitc::ApplyOp targetPtr =
233+
emitc::AddressOfOp targetPtr =
234234
createPointerFromEmitcArray(loc, rewriter, targetArrayValue);
235235

236236
emitc::CallOpaqueOp memCpyCall = emitc::CallOpaqueOp::create(
@@ -319,8 +319,8 @@ struct ConvertGetGlobal final
319319
emitc::GetGlobalOp globalLValue = emitc::GetGlobalOp::create(
320320
rewriter, op.getLoc(), lvalueType, operands.getNameAttr());
321321
emitc::PointerType pointerType = emitc::PointerType::get(resultTy);
322-
rewriter.replaceOpWithNewOp<emitc::ApplyOp>(
323-
op, pointerType, rewriter.getStringAttr("&"), globalLValue);
322+
rewriter.replaceOpWithNewOp<emitc::AddressOfOp>(op, pointerType,
323+
globalLValue);
324324
return success();
325325
}
326326
rewriter.replaceOpWithNewOp<emitc::GetGlobalOp>(op, resultTy,

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

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,21 @@ FailureOr<SmallVector<ReplacementItem>> parseFormatString(
225225
return items;
226226
}
227227

228+
//===----------------------------------------------------------------------===//
229+
// AddressOfOp
230+
//===----------------------------------------------------------------------===//
231+
232+
LogicalResult AddressOfOp::verify() {
233+
emitc::LValueType referenceType = getReference().getType();
234+
emitc::PointerType resultType = getResult().getType();
235+
236+
if (referenceType.getValueType() != resultType.getPointee())
237+
return emitOpError("requires result to be a pointer to the type "
238+
"referenced by operand");
239+
240+
return success();
241+
}
242+
228243
//===----------------------------------------------------------------------===//
229244
// AddOp
230245
//===----------------------------------------------------------------------===//
@@ -379,6 +394,20 @@ LogicalResult emitc::ConstantOp::verify() {
379394

380395
OpFoldResult emitc::ConstantOp::fold(FoldAdaptor adaptor) { return getValue(); }
381396

397+
//===----------------------------------------------------------------------===//
398+
// DereferenceOp
399+
//===----------------------------------------------------------------------===//
400+
401+
LogicalResult DereferenceOp::verify() {
402+
emitc::PointerType pointerType = getPointer().getType();
403+
404+
if (pointerType.getPointee() != getResult().getType().getValueType())
405+
return emitOpError("requires result to be an lvalue of the type "
406+
"pointed to by operand");
407+
408+
return success();
409+
}
410+
382411
//===----------------------------------------------------------------------===//
383412
// ExpressionOp
384413
//===----------------------------------------------------------------------===//

mlir/lib/Target/Cpp/TranslateToCpp.cpp

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ static inline LogicalResult interleaveCommaWithError(const Container &c,
7070
/// imply higher precedence.
7171
static FailureOr<int> getOperatorPrecedence(Operation *operation) {
7272
return llvm::TypeSwitch<Operation *, FailureOr<int>>(operation)
73+
.Case<emitc::AddressOfOp>([&](auto op) { return 15; })
7374
.Case<emitc::AddOp>([&](auto op) { return 12; })
7475
.Case<emitc::ApplyOp>([&](auto op) { return 15; })
7576
.Case<emitc::BitwiseAndOp>([&](auto op) { return 7; })
@@ -396,6 +397,15 @@ static bool shouldBeInlined(ExpressionOp expressionOp) {
396397
return false;
397398
}
398399

400+
static LogicalResult printOperation(CppEmitter &emitter,
401+
emitc::DereferenceOp dereferenceOp) {
402+
std::string out;
403+
llvm::raw_string_ostream ss(out);
404+
ss << "*" << emitter.getOrCreateName(dereferenceOp.getPointer());
405+
emitter.cacheDeferredOpResult(dereferenceOp.getResult(), out);
406+
return success();
407+
}
408+
399409
static LogicalResult printOperation(CppEmitter &emitter,
400410
emitc::GetFieldOp getFieldOp) {
401411
emitter.cacheDeferredOpResult(getFieldOp.getResult(),
@@ -479,6 +489,17 @@ static LogicalResult printConstantOp(CppEmitter &emitter, Operation *operation,
479489
return emitter.emitAttribute(operation->getLoc(), value);
480490
}
481491

492+
static LogicalResult printOperation(CppEmitter &emitter,
493+
emitc::AddressOfOp addressOfOp) {
494+
raw_ostream &os = emitter.ostream();
495+
Operation &op = *addressOfOp.getOperation();
496+
497+
if (failed(emitter.emitAssignPrefix(op)))
498+
return failure();
499+
os << "&";
500+
return emitter.emitOperand(addressOfOp.getReference());
501+
}
502+
482503
static LogicalResult printOperation(CppEmitter &emitter,
483504
emitc::ConstantOp constantOp) {
484505
Operation *operation = constantOp.getOperation();
@@ -1768,14 +1789,14 @@ LogicalResult CppEmitter::emitOperation(Operation &op, bool trailingSemicolon) {
17681789
.Case<cf::BranchOp, cf::CondBranchOp>(
17691790
[&](auto op) { return printOperation(*this, op); })
17701791
// EmitC ops.
1771-
.Case<emitc::AddOp, emitc::ApplyOp, emitc::AssignOp,
1772-
emitc::BitwiseAndOp, emitc::BitwiseLeftShiftOp,
1792+
.Case<emitc::AddressOfOp, emitc::AddOp, emitc::ApplyOp,
1793+
emitc::AssignOp, emitc::BitwiseAndOp, emitc::BitwiseLeftShiftOp,
17731794
emitc::BitwiseNotOp, emitc::BitwiseOrOp,
17741795
emitc::BitwiseRightShiftOp, emitc::BitwiseXorOp, emitc::CallOp,
17751796
emitc::CallOpaqueOp, emitc::CastOp, emitc::ClassOp,
17761797
emitc::CmpOp, emitc::ConditionalOp, emitc::ConstantOp,
1777-
emitc::DeclareFuncOp, emitc::DivOp, emitc::DoOp,
1778-
emitc::ExpressionOp, emitc::FieldOp, emitc::FileOp,
1798+
emitc::DeclareFuncOp, emitc::DereferenceOp, emitc::DivOp,
1799+
emitc::DoOp, emitc::ExpressionOp, emitc::FieldOp, emitc::FileOp,
17791800
emitc::ForOp, emitc::FuncOp, emitc::GetFieldOp,
17801801
emitc::GetGlobalOp, emitc::GlobalOp, emitc::IfOp,
17811802
emitc::IncludeOp, emitc::LiteralOp, emitc::LoadOp,

mlir/test/Conversion/MemRefToEmitC/memref-to-emitc-alloc-copy.mlir

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,14 @@ func.func @alloc_copy(%arg0: memref<999xi32>) {
2626
// CHECK: %[[UNREALIZED_CONVERSION_CAST_1:.*]] = builtin.unrealized_conversion_cast %[[CAST_0]] : !emitc.ptr<i32> to !emitc.array<999xi32>
2727
// CHECK: %[[VAL_1:.*]] = "emitc.constant"() <{value = 0 : index}> : () -> index
2828
// CHECK: %[[SUBSCRIPT_0:.*]] = emitc.subscript %[[UNREALIZED_CONVERSION_CAST_0]]{{\[}}%[[VAL_1]]] : (!emitc.array<999xi32>, index) -> !emitc.lvalue<i32>
29-
// CHECK: %[[APPLY_0:.*]] = emitc.apply "&"(%[[SUBSCRIPT_0]]) : (!emitc.lvalue<i32>) -> !emitc.ptr<i32>
29+
// CHECK: %[[ADDRESS_OF_0:.*]] = emitc.address_of %[[SUBSCRIPT_0]] : !emitc.lvalue<i32>
3030
// CHECK: %[[VAL_2:.*]] = "emitc.constant"() <{value = 0 : index}> : () -> index
3131
// CHECK: %[[SUBSCRIPT_1:.*]] = emitc.subscript %[[UNREALIZED_CONVERSION_CAST_1]]{{\[}}%[[VAL_2]]] : (!emitc.array<999xi32>, index) -> !emitc.lvalue<i32>
32-
// CHECK: %[[APPLY_1:.*]] = emitc.apply "&"(%[[SUBSCRIPT_1]]) : (!emitc.lvalue<i32>) -> !emitc.ptr<i32>
32+
// CHECK: %[[ADDRESS_OF_1:.*]] = emitc.address_of %[[SUBSCRIPT_1]] : !emitc.lvalue<i32>
3333
// CHECK: %[[CALL_OPAQUE_2:.*]] = emitc.call_opaque "sizeof"() {args = [i32]} : () -> !emitc.size_t
3434
// CHECK: %[[VAL_3:.*]] = "emitc.constant"() <{value = 999 : index}> : () -> index
3535
// CHECK: %[[MUL_1:.*]] = emitc.mul %[[CALL_OPAQUE_2]], %[[VAL_3]] : (!emitc.size_t, index) -> !emitc.size_t
36-
// CHECK: emitc.call_opaque "memcpy"(%[[APPLY_1]], %[[APPLY_0]], %[[MUL_1]]) : (!emitc.ptr<i32>, !emitc.ptr<i32>, !emitc.size_t) -> ()
36+
// CHECK: emitc.call_opaque "memcpy"(%[[ADDRESS_OF_1]], %[[ADDRESS_OF_0]], %[[MUL_1]]) : (!emitc.ptr<i32>, !emitc.ptr<i32>, !emitc.size_t) -> ()
3737
// CHECK: %[[CALL_OPAQUE_3:.*]] = emitc.call_opaque "sizeof"() {args = [i32]} : () -> !emitc.size_t
3838
// CHECK: %[[VAL_4:.*]] = "emitc.constant"() <{value = 999 : index}> : () -> index
3939
// CHECK: %[[MUL_2:.*]] = emitc.mul %[[CALL_OPAQUE_3]], %[[VAL_4]] : (!emitc.size_t, index) -> !emitc.size_t
@@ -42,13 +42,13 @@ func.func @alloc_copy(%arg0: memref<999xi32>) {
4242
// CHECK: %[[UNREALIZED_CONVERSION_CAST_2:.*]] = builtin.unrealized_conversion_cast %[[CAST_1]] : !emitc.ptr<i32> to !emitc.array<999xi32>
4343
// CHECK: %[[VAL_5:.*]] = "emitc.constant"() <{value = 0 : index}> : () -> index
4444
// CHECK: %[[SUBSCRIPT_2:.*]] = emitc.subscript %[[UNREALIZED_CONVERSION_CAST_0]]{{\[}}%[[VAL_5]]] : (!emitc.array<999xi32>, index) -> !emitc.lvalue<i32>
45-
// CHECK: %[[APPLY_2:.*]] = emitc.apply "&"(%[[SUBSCRIPT_2]]) : (!emitc.lvalue<i32>) -> !emitc.ptr<i32>
45+
// CHECK: %[[ADDRESS_OF_2:.*]] = emitc.address_of %[[SUBSCRIPT_2]] : !emitc.lvalue<i32>
4646
// CHECK: %[[VAL_6:.*]] = "emitc.constant"() <{value = 0 : index}> : () -> index
4747
// CHECK: %[[SUBSCRIPT_3:.*]] = emitc.subscript %[[UNREALIZED_CONVERSION_CAST_2]]{{\[}}%[[VAL_6]]] : (!emitc.array<999xi32>, index) -> !emitc.lvalue<i32>
48-
// CHECK: %[[APPLY_3:.*]] = emitc.apply "&"(%[[SUBSCRIPT_3]]) : (!emitc.lvalue<i32>) -> !emitc.ptr<i32>
48+
// CHECK: %[[ADDRESS_OF_3:.*]] = emitc.address_of %[[SUBSCRIPT_3]] : !emitc.lvalue<i32>
4949
// CHECK: %[[CALL_OPAQUE_5:.*]] = emitc.call_opaque "sizeof"() {args = [i32]} : () -> !emitc.size_t
5050
// CHECK: %[[VAL_7:.*]] = "emitc.constant"() <{value = 999 : index}> : () -> index
5151
// CHECK: %[[MUL_3:.*]] = emitc.mul %[[CALL_OPAQUE_5]], %[[VAL_7]] : (!emitc.size_t, index) -> !emitc.size_t
52-
// CHECK: emitc.call_opaque "memcpy"(%[[APPLY_3]], %[[APPLY_2]], %[[MUL_3]]) : (!emitc.ptr<i32>, !emitc.ptr<i32>, !emitc.size_t) -> ()
52+
// CHECK: emitc.call_opaque "memcpy"(%[[ADDRESS_OF_3]], %[[ADDRESS_OF_2]], %[[MUL_3]]) : (!emitc.ptr<i32>, !emitc.ptr<i32>, !emitc.size_t) -> ()
5353
// CHECK: return
5454
// CHECK: }

mlir/test/Conversion/MemRefToEmitC/memref-to-emitc-copy.mlir

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,14 @@ func.func @copying(%arg0 : memref<9x4x5x7xf32>, %arg1 : memref<9x4x5x7xf32>) {
1717
// CHECK: %[[UNREALIZED_CONVERSION_CAST_1:.*]] = builtin.unrealized_conversion_cast %[[ARG0]] : memref<9x4x5x7xf32> to !emitc.array<9x4x5x7xf32>
1818
// CHECK: %[[VAL_0:.*]] = "emitc.constant"() <{value = 0 : index}> : () -> index
1919
// CHECK: %[[SUBSCRIPT_0:.*]] = emitc.subscript %[[UNREALIZED_CONVERSION_CAST_1]]{{\[}}%[[VAL_0]], %[[VAL_0]], %[[VAL_0]], %[[VAL_0]]] : (!emitc.array<9x4x5x7xf32>, index, index, index, index) -> !emitc.lvalue<f32>
20-
// CHECK: %[[APPLY_0:.*]] = emitc.apply "&"(%[[SUBSCRIPT_0]]) : (!emitc.lvalue<f32>) -> !emitc.ptr<f32>
20+
// CHECK: %[[ADDRESS_OF_0:.*]] = emitc.address_of %[[SUBSCRIPT_0]] : !emitc.lvalue<f32>
2121
// CHECK: %[[VAL_1:.*]] = "emitc.constant"() <{value = 0 : index}> : () -> index
2222
// CHECK: %[[SUBSCRIPT_1:.*]] = emitc.subscript %[[UNREALIZED_CONVERSION_CAST_0]]{{\[}}%[[VAL_1]], %[[VAL_1]], %[[VAL_1]], %[[VAL_1]]] : (!emitc.array<9x4x5x7xf32>, index, index, index, index) -> !emitc.lvalue<f32>
23-
// CHECK: %[[APPLY_1:.*]] = emitc.apply "&"(%[[SUBSCRIPT_1]]) : (!emitc.lvalue<f32>) -> !emitc.ptr<f32>
23+
// CHECK: %[[ADDRESS_OF_1:.*]] = emitc.address_of %[[SUBSCRIPT_1]] : !emitc.lvalue<f32>
2424
// CHECK: %[[CALL_OPAQUE_0:.*]] = emitc.call_opaque "sizeof"() {args = [f32]} : () -> !emitc.size_t
2525
// CHECK: %[[VAL_2:.*]] = "emitc.constant"() <{value = 1260 : index}> : () -> index
2626
// CHECK: %[[MUL_0:.*]] = emitc.mul %[[CALL_OPAQUE_0]], %[[VAL_2]] : (!emitc.size_t, index) -> !emitc.size_t
27-
// CHECK: emitc.call_opaque "memcpy"(%[[APPLY_1]], %[[APPLY_0]], %[[MUL_0]]) : (!emitc.ptr<f32>, !emitc.ptr<f32>, !emitc.size_t) -> ()
27+
// CHECK: emitc.call_opaque "memcpy"(%[[ADDRESS_OF_1]], %[[ADDRESS_OF_0]], %[[MUL_0]]) : (!emitc.ptr<f32>, !emitc.ptr<f32>, !emitc.size_t) -> ()
2828
// CHECK: return
2929
// CHECK: }
3030

mlir/test/Conversion/MemRefToEmitC/memref-to-emitc.mlir

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ module @globals {
5353
// CHECK-NEXT: emitc.get_global @public_global : !emitc.array<3x7xf32>
5454
%0 = memref.get_global @public_global : memref<3x7xf32>
5555
// CHECK-NEXT: emitc.get_global @__constant_xi32 : !emitc.lvalue<i32>
56-
// CHECK-NEXT: emitc.apply "&"(%1) : (!emitc.lvalue<i32>) -> !emitc.ptr<i32>
56+
// CHECK-NEXT: emitc.address_of %1 : !emitc.lvalue<i32>
5757
%1 = memref.get_global @__constant_xi32 : memref<i32>
5858
return
5959
}

mlir/test/Dialect/EmitC/invalid_ops.mlir

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -914,3 +914,19 @@ func.func @test_for_unmatch_type(%arg0: index) {
914914
) : (index, index, index) -> ()
915915
return
916916
}
917+
918+
// -----
919+
920+
func.func @address_of(%arg0: !emitc.lvalue<i32>) {
921+
// expected-error @+1 {{failed to verify that input and result reference the same type}}
922+
%1 = "emitc.address_of"(%arg0) : (!emitc.lvalue<i32>) -> !emitc.ptr<i8>
923+
return
924+
}
925+
926+
// -----
927+
928+
func.func @dereference(%arg0: !emitc.ptr<i32>) {
929+
// expected-error @+1 {{failed to verify that input and result reference the same type}}
930+
%1 = "emitc.dereference"(%arg0) : (!emitc.ptr<i32>) -> !emitc.lvalue<i8>
931+
return
932+
}

mlir/test/Dialect/EmitC/ops.mlir

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,3 +355,13 @@ func.func @do(%arg0 : !emitc.ptr<i32>) {
355355

356356
return
357357
}
358+
359+
func.func @address_of(%arg0: !emitc.lvalue<i32>) {
360+
%1 = emitc.address_of %arg0 : !emitc.lvalue<i32>
361+
return
362+
}
363+
364+
func.func @dereference(%arg0: !emitc.ptr<i32>) {
365+
%1 = emitc.dereference %arg0 : !emitc.ptr<i32>
366+
return
367+
}

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

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,25 @@ func.func @apply() -> !emitc.ptr<i32> {
105105
return %1 : !emitc.ptr<i32>
106106
}
107107

108+
109+
// CHECK-LABEL: void address_of() {
110+
func.func @address_of() {
111+
// CHECK-NEXT: int32_t [[V1:[^ ]*]];
112+
%0 = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> !emitc.lvalue<i32>
113+
// CHECK-NEXT: int32_t* [[V2:[^ ]*]] = &[[V1]];
114+
%1 = emitc.address_of %0 : !emitc.lvalue<i32>
115+
return
116+
}
117+
118+
// CHECK-LABEL: void dereference
119+
// CHECK-SAME: (int32_t* [[ARG0:[^ ]*]]) {
120+
func.func @dereference(%arg0: !emitc.ptr<i32>) {
121+
// CHECK: int32_t [[V1:[^ ]*]] = *[[ARG0]];
122+
%2 = emitc.dereference %arg0 : !emitc.ptr<i32>
123+
emitc.load %2 : !emitc.lvalue<i32>
124+
return
125+
}
126+
108127
// CHECK: void array_type(int32_t v1[3], float v2[10][20])
109128
func.func @array_type(%arg0: !emitc.array<3xi32>, %arg1: !emitc.array<10x20xf32>) {
110129
return

0 commit comments

Comments
 (0)