diff --git a/reuse-mlir/src/cxx/IR/ReuseIROps.cpp b/reuse-mlir/src/cxx/IR/ReuseIROps.cpp index 0eaf102..651c6ab 100644 --- a/reuse-mlir/src/cxx/IR/ReuseIROps.cpp +++ b/reuse-mlir/src/cxx/IR/ReuseIROps.cpp @@ -44,6 +44,9 @@ mlir::reuse_ir::LogicalResult ValueToRefOp::verify() { // ProjOp mlir::reuse_ir::LogicalResult ProjOp::verify() { RefType input = getObject().getType(); + if (input.getFreezingKind() != getType().getFreezingKind()) + return emitOpError( + "must return a reference with the same freezing kind as the input"); if (!isProjectable(input.getPointee())) return emitOpError( "must operate on a reference to a composite or an array"); @@ -57,7 +60,7 @@ mlir::reuse_ir::LogicalResult ProjOp::verify() { .Case([&](const ArrayType &ty) { if (getIndex() >= ty.getSizes()[0]) return mlir::Type{}; - if (ty.getSizes().size() == 0) + if (ty.getSizes().size() == 1) return ty.getElementType(); return cast(ArrayType::get( getContext(), ty.getElementType(), ty.getSizes().drop_front())); diff --git a/reuse-mlir/src/cxx/Passes/ConvertReuseIRToLLVM.cpp b/reuse-mlir/src/cxx/Passes/ConvertReuseIRToLLVM.cpp index 9795f24..9075790 100644 --- a/reuse-mlir/src/cxx/Passes/ConvertReuseIRToLLVM.cpp +++ b/reuse-mlir/src/cxx/Passes/ConvertReuseIRToLLVM.cpp @@ -39,6 +39,44 @@ class ReuseIRConvPatternWithLayoutCache : public mlir::OpConversionPattern { cache(cache) {} }; +class ProjOpLowering : public ReuseIRConvPatternWithLayoutCache { +public: + using ReuseIRConvPatternWithLayoutCache::ReuseIRConvPatternWithLayoutCache; + + mlir::reuse_ir::LogicalResult matchAndRewrite( + ProjOp op, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter) const override final { + auto ptrTy = LLVM::LLVMPointerType::get(getContext()); + if (auto pointee = + dyn_cast(op.getObject().getType().getPointee())) { + const CompositeLayout &layout = cache.get(pointee); + rewriter.replaceOpWithNewOp( + op, ptrTy, layout.getLLVMType(getLLVMTypeConverter()), + adaptor.getObject(), + llvm::ArrayRef{0, + layout.getField(op.getIndex()).index}); + return LogicalResult::success(); + } + if (auto pointee = + dyn_cast(op.getObject().getType().getPointee())) { + mlir::Type innerTy; + if (pointee.getSizes().size() == 0) + innerTy = pointee.getElementType(); + else + innerTy = ArrayType::get(getContext(), pointee.getElementType(), + pointee.getSizes().drop_front()); + auto ty = typeConverter->convertType(innerTy); + if (!ty) + return LogicalResult::failure(); + rewriter.replaceOpWithNewOp( + op, ptrTy, ty, adaptor.getObject(), + llvm::ArrayRef{op.getIndex()}); + return LogicalResult::success(); + } + return LogicalResult::failure(); + } +}; + class ValueToRefOpLowering : public ReuseIRConvPatternWithLayoutCache { public: @@ -228,8 +266,8 @@ void ConvertReuseIRToLLVMPass::runOnOperation() { mlir::populateFuncToLLVMConversionPatterns(converter, patterns); patterns.add(converter, &getContext()); - patterns.add(cache, converter, - &getContext()); + patterns.add( + cache, converter, &getContext()); mlir::ConversionTarget target(getContext()); target.addLegalDialect(); target.addLegalOp(); diff --git a/reuse-mlir/test/integration/basic/invalid_projection_kind.mlir b/reuse-mlir/test/integration/basic/invalid_projection_kind.mlir new file mode 100644 index 0000000..80608d8 --- /dev/null +++ b/reuse-mlir/test/integration/basic/invalid_projection_kind.mlir @@ -0,0 +1,13 @@ +// RUN: %not %reuse-opt %s 2>&1 | %FileCheck %s +!test = !reuse_ir.composite, i32> +module @test { + func.func @projection(%0: !reuse_ir.rc) { + %1 = reuse_ir.borrow %0 : + !reuse_ir.rc + -> !reuse_ir.ref + // CHECK: error: 'reuse_ir.proj' op must return a reference with the same freezing kind as the input + %2 = reuse_ir.proj %1[0] : + !reuse_ir.ref -> !reuse_ir.ref, frozen> + return + } +} diff --git a/reuse-mlir/test/integration/lowering/proj_op_lowering.mlir b/reuse-mlir/test/integration/lowering/proj_op_lowering.mlir new file mode 100644 index 0000000..099c657 --- /dev/null +++ b/reuse-mlir/test/integration/lowering/proj_op_lowering.mlir @@ -0,0 +1,33 @@ +// RUN: %reuse-opt %s -convert-reuse-ir-to-llvm | %FileCheck %s +!test = !reuse_ir.composite, i32> +!array = !reuse_ir.array +module @test attributes {dlti.dl_spec = #dlti.dl_spec<#dlti.dl_entry : vector<2xi64>>, #dlti.dl_entry : vector<2xi64>>, #dlti.dl_entry : vector<2xi64>>, #dlti.dl_entry : vector<2xi64>>, #dlti.dl_entry : vector<2xi64>>, #dlti.dl_entry : vector<2xi64>>, #dlti.dl_entry : vector<2xi64>>, #dlti.dl_entry : vector<4xi64>>, #dlti.dl_entry, dense<32> : vector<4xi64>>, #dlti.dl_entry : vector<2xi64>>, #dlti.dl_entry : vector<2xi64>>, #dlti.dl_entry, dense<64> : vector<4xi64>>, #dlti.dl_entry, dense<32> : vector<4xi64>>, #dlti.dl_entry : vector<2xi64>>, #dlti.dl_entry<"dlti.stack_alignment", 128 : i64>, #dlti.dl_entry<"dlti.endianness", "little">>, llvm.data_layout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"} +{ + func.func @composite_projection(%0: !reuse_ir.rc) { + %1 = reuse_ir.borrow %0 : + !reuse_ir.rc + -> !reuse_ir.ref + // CHECK: %[[REG0:[0-9a-z]+]] = llvm.getelementptr %{{[0-9a-z]+}}[0, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(struct<(i32, i32, array<8 x i8>, f128)>, i32, array<12 x i8>)> + %2 = reuse_ir.proj %1[0] : + !reuse_ir.ref -> !reuse_ir.ref, nonfreezing> + // CHECK: %{{[0-9a-z]+}} = llvm.getelementptr %[[REG0]][0, 3] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(i32, i32, array<8 x i8>, f128)> + %3 = reuse_ir.proj %2[2] : + !reuse_ir.ref, nonfreezing> -> !reuse_ir.ref + return + } + func.func @array_projection(%0: !reuse_ir.rc) { + %1 = reuse_ir.borrow %0 : + !reuse_ir.rc + -> !reuse_ir.ref + // CHECK: %[[REG0:[0-9a-z]+]] = llvm.getelementptr %{{[0-9a-z]+}}[13] : (!llvm.ptr) -> !llvm.ptr, !llvm.array<16 x struct<(struct<(i32, i32, array<8 x i8>, f128)>, i32, array<12 x i8>)>> + %2 = reuse_ir.proj %1[13] : + !reuse_ir.ref -> !reuse_ir.ref, nonfreezing> + // CHECK: %[[REG1:[0-9a-z]+]] = llvm.getelementptr %[[REG0]][7] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(struct<(i32, i32, array<8 x i8>, f128)>, i32, array<12 x i8>)> + %3 = reuse_ir.proj %2[7] : + !reuse_ir.ref, nonfreezing> -> !reuse_ir.ref + // CHECK: %{{[0-9a-z]+}} = llvm.getelementptr %[[REG1]][0, 1] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(struct<(i32, i32, array<8 x i8>, f128)>, i32, array<12 x i8>)> + %4 = reuse_ir.proj %3[1] : + !reuse_ir.ref-> !reuse_ir.ref + return + } +}