From 14867ffc7c6dd78665b332fe2e815c83909eb93e Mon Sep 17 00:00:00 2001 From: Andrzej Warzynski Date: Wed, 10 Nov 2021 13:24:56 +0000 Subject: [PATCH] [flang][CodeGen] Transform `fir.unboxchar` to a sequence of LLVM MLIR This patch extends the `FIRToLLVMLowering` pass in Flang by adding a hook to transform `fir.unboxchar` to a sequence of LLVM MLIR instructions. This is part of the upstreaming effort from the `fir-dev` branch in [1]. [1] https://github.com/flang-compiler/f18-llvm-project Differential Revision: https://reviews.llvm.org/D113747 Originally written by: Co-authored-by: Eric Schweitz Co-authored-by: Jean Perier --- flang/include/flang/Optimizer/Dialect/FIROps.td | 2 +- flang/lib/Optimizer/CodeGen/CodeGen.cpp | 44 +++++++++++++++++++++++-- flang/test/Fir/convert-to-llvm-target.fir | 40 ++++++++++++++++++++++ 3 files changed, 83 insertions(+), 3 deletions(-) diff --git a/flang/include/flang/Optimizer/Dialect/FIROps.td b/flang/include/flang/Optimizer/Dialect/FIROps.td index 57109bc..d0156d3 100644 --- a/flang/include/flang/Optimizer/Dialect/FIROps.td +++ b/flang/include/flang/Optimizer/Dialect/FIROps.td @@ -1030,7 +1030,7 @@ def fir_UnboxCharOp : fir_SimpleOp<"unboxchar", [NoSideEffect]> { ```mlir %45 = ... : !fir.boxchar<1> - %46:2 = fir.unboxchar %45 : (!fir.boxchar<1>) -> (!fir.ref>, i32) + %46:2 = fir.unboxchar %45 : (!fir.boxchar<1>) -> (!fir.ref>, i32) ``` }]; diff --git a/flang/lib/Optimizer/CodeGen/CodeGen.cpp b/flang/lib/Optimizer/CodeGen/CodeGen.cpp index 590be4f..ffc3b0a 100644 --- a/flang/lib/Optimizer/CodeGen/CodeGen.cpp +++ b/flang/lib/Optimizer/CodeGen/CodeGen.cpp @@ -1435,6 +1435,46 @@ struct EmboxCharOpConversion : public FIROpConversion { return success(); } }; + +/// Construct an `llvm.extractvalue` instruction. It will return value at +/// element \p x from \p tuple. +mlir::LLVM::ExtractValueOp +genExtractValueWithIndex(mlir::Location loc, mlir::Value tuple, mlir::Type ty, + mlir::ConversionPatternRewriter &rewriter, + mlir::MLIRContext *ctx, int x) { + auto cx = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(x)); + auto xty = ty.cast().getBody()[x]; + return rewriter.create(loc, xty, tuple, cx); +} + +/// Convert `fir.unboxchar` into two `llvm.extractvalue` instructions. One for +/// the character buffer and one for the buffer length. +struct UnboxCharOpConversion : public FIROpConversion { + using FIROpConversion::FIROpConversion; + + mlir::LogicalResult + matchAndRewrite(fir::UnboxCharOp unboxchar, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter) const override { + MLIRContext *ctx = unboxchar.getContext(); + + mlir::Type lenTy = convertType(unboxchar.getType(1)); + mlir::Value tuple = adaptor.getOperands()[0]; + mlir::Type tupleTy = tuple.getType(); + + mlir::Location loc = unboxchar.getLoc(); + mlir::Value ptrToBuffer = + genExtractValueWithIndex(loc, tuple, tupleTy, rewriter, ctx, 0); + + mlir::LLVM::ExtractValueOp len = + genExtractValueWithIndex(loc, tuple, tupleTy, rewriter, ctx, 1); + mlir::Value lenAfterCast = integerCast(loc, rewriter, lenTy, len); + + rewriter.replaceOp(unboxchar, + ArrayRef{ptrToBuffer, lenAfterCast}); + return success(); + } +}; + } // namespace namespace { @@ -1469,8 +1509,8 @@ public: IsPresentOpConversion, LoadOpConversion, NegcOpConversion, MulcOpConversion, SelectCaseOpConversion, SelectOpConversion, SelectRankOpConversion, SelectTypeOpConversion, StoreOpConversion, - SubcOpConversion, UndefOpConversion, UnreachableOpConversion, - ZeroOpConversion>(typeConverter); + SubcOpConversion, UnboxCharOpConversion, UndefOpConversion, + UnreachableOpConversion, ZeroOpConversion>(typeConverter); mlir::populateStdToLLVMConversionPatterns(typeConverter, pattern); mlir::arith::populateArithmeticToLLVMConversionPatterns(typeConverter, pattern); diff --git a/flang/test/Fir/convert-to-llvm-target.fir b/flang/test/Fir/convert-to-llvm-target.fir index 46e693c..501e687 100644 --- a/flang/test/Fir/convert-to-llvm-target.fir +++ b/flang/test/Fir/convert-to-llvm-target.fir @@ -31,3 +31,43 @@ func @test_embox(%char_array : !fir.ref>) -> () { // INT32: %[[struct_with_buffer:.*]] = llvm.insertvalue %[[char_array]], %[[empty_struct]][0 : i32] : !llvm.struct<(ptr, i32)> // INT32: %{{.*}} = llvm.insertvalue %[[c10_truncated:.*]], %[[struct_with_buffer]][1 : i32] : !llvm.struct<(ptr, i32)> // INT32-NEXT: llvm.return + +// ----- + +// Test fir.unboxchar + +func @unboxchar_i8(%arg0 : !fir.boxchar<1>) -> () { + %0:2 = fir.unboxchar %arg0 : (!fir.boxchar<1>) -> (!fir.ref>, i64) + return +} + +// INT64-LABEL: llvm.func @unboxchar_i8 +// INT64-SAME: %[[box_char:.*]]: !llvm.struct<(ptr, i64)> +// INT64: %{{.*}} = llvm.extractvalue %[[box_char]][0 : i32] : !llvm.struct<(ptr, i64)> +// INT64: %{{.*}} = llvm.extractvalue %[[box_char]][1 : i32] : !llvm.struct<(ptr, i64)> +// INT64-NEXT: llvm.return + +// INT32-LABEL: llvm.func @unboxchar_i8 +// INT32-SAME: %[[box_char:.*]]: !llvm.struct<(ptr, i32)> +// INT32: %{{.*}} = llvm.extractvalue %[[box_char]][0 : i32] : !llvm.struct<(ptr, i32)> +// INT32: %[[len_unextended:.*]] = llvm.extractvalue %[[box_char]][1 : i32] : !llvm.struct<(ptr, i32)> +// INT32: %{{.*}} = llvm.sext %[[len_unextended]] : i32 to i64 +// INT32-NEXT: llvm.return + +func @unboxchar_i32(%arg0 : !fir.boxchar<4>) -> () { + fir.unboxchar %arg0 : (!fir.boxchar<4>) -> (!fir.ref>, i64) + return +} + +// INT64-LABEL: llvm.func @unboxchar_i32 +// INT64-SAME: %[[box_char:.*]]: !llvm.struct<(ptr, i64)> +// INT64: %{{.*}} = llvm.extractvalue %[[box_char]][0 : i32] : !llvm.struct<(ptr, i64)> +// INT64: %{{.*}} = llvm.extractvalue %[[box_char]][1 : i32] : !llvm.struct<(ptr, i64)> +// INT64-NEXT: llvm.return + +// INT32-LABEL: llvm.func @unboxchar_i32 +// INT32-SAME: %[[box_char:.*]]: !llvm.struct<(ptr, i32)> +// INT32: %{{.*}} = llvm.extractvalue %[[box_char]][0 : i32] : !llvm.struct<(ptr, i32)> +// INT32: %[[len_unextended:.*]] = llvm.extractvalue %[[box_char]][1 : i32] : !llvm.struct<(ptr, i32)> +// INT32: %{{.*}} = llvm.sext %[[len_unextended]] : i32 to i64 +// INT32-NEXT: llvm.return -- 2.7.4