llvm-project
2754e35f - [mlir][EmitC] Support pointer-based memrefs in load/store lowering (#186828)

Commit
36 days ago
[mlir][EmitC] Support pointer-based memrefs in load/store lowering (#186828) ## Problem In the MemRef → EmitC conversion, `memref.load` and `memref.store` assume that the converted memref operand is an `emitc.array`, as defined by the type conversion in `populateMemRefToEmitCTypeConversion`. However, `memref.alloc` is lowered to a `malloc` call returning `emitc.ptr`. When such values are used by `memref.load` or `memref.store`, the conversion framework inserts a bridging `builtin.unrealized_conversion_cast` from `emitc.ptr` to `emitc.array`. These casts have no EmitC representation and therefore remain in the IR after conversion, preventing valid C/C++ emission. ## Solution Extend the `memref.load` and `memref.store` conversions to handle pointer-backed buffers. If the memref operand is defined by an `UnrealizedConversionCastOp` whose input is an `emitc.ptr`, the cast is stripped and the underlying pointer operand is used directly. Since pointer subscripting in EmitC is one-dimensional, the multi-dimensional memref indices are converted to a row-major linear index (matching the default memref layout) using the original `MemRefType` shape before emitting `emitc.subscript`. The existing array-based lowering path remains unchanged. This patch intentionally does ***not*** modify the MemRef → EmitC type conversion rule (`memref → emitc.array`). Instead, the mismatch introduced by `memref.alloc` returning a pointer is handled locally in the `LoadOp` and `StoreOp` conversions. ## Example 1: Single-dimensional store ### Input ```mlir func.func @alloc_store(%arg0: i32, %i: index) { %alloc = memref.alloc() : memref<999xi32> memref.store %arg0, %alloc[%i] : memref<999xi32> return } ``` ### Current lowering ```mlir // AllocOp conversion unchanged -> excluded for brevity %5 = builtin.unrealized_conversion_cast %4 : !emitc.ptr<i32> to !emitc.array<999xi32> %6 = subscript %5[%arg1] assign %arg0 to %6 : <i32> ``` The `unrealized_conversion_cast` remains in the IR. ### Lowering after this patch ```mlir %5 = subscript %4[%arg1] : (!emitc.ptr<i32>, !emitc.size_t) -> !emitc.lvalue<i32> assign %arg0 : i32 to %5 : <i32> ``` The cast is eliminated and pointer subscripting is used directly. ## Example 2: Multi-dimensional store ### Input ```mlir func.func @memref_alloc_store(%v : f32, %i : index, %j : index) { %alloc = memref.alloc() : memref<4x8xf32> memref.store %v, %alloc[%i, %j] : memref<4x8xf32> return } ``` ### Current lowering ```mlir // AllocOp conversion unchanged -> excluded for brevity %5 = builtin.unrealized_conversion_cast %4 : !emitc.ptr<f32> to !emitc.array<4x8xf32> %6 = subscript %5[%arg1, %arg2] : (!emitc.array<4x8xf32>, !emitc.size_t, !emitc.size_t) -> !emitc.lvalue<f32> assign %arg0 : f32 to %6 : <f32> ``` ### Lowering after this patch ```mlir %5 = "emitc.constant"() <{value = 8 : index}> : () -> !emitc.size_t %6 = mul %arg1, %5 : (!emitc.size_t, !emitc.size_t) -> !emitc.size_t %7 = add %6, %arg2 : (!emitc.size_t, !emitc.size_t) -> !emitc.size_t %8 = subscript %4[%7] : (!emitc.ptr<f32>, !emitc.size_t) -> !emitc.lvalue<f32> assign %arg0 : f32 to %8 : <f32> ``` The multi-dimensional indices are converted into a linear row-major index before pointer subscripting. Assisted-by: ChatGPT (refine implementation + tests). I reviewed all code and tests before submission.
Author
Parents
Loading