diff --git a/flang/lib/Optimizer/CodeGen/CodeGen.cpp b/flang/lib/Optimizer/CodeGen/CodeGen.cpp --- a/flang/lib/Optimizer/CodeGen/CodeGen.cpp +++ b/flang/lib/Optimizer/CodeGen/CodeGen.cpp @@ -1517,6 +1517,29 @@ return rewriter.create(loc, xty, tuple, cx); } +/// Convert `!fir.boxchar_len` to `!llvm.extractvalue` for the 2nd part of the +/// boxchar. +struct BoxCharLenOpConversion : public FIROpConversion { + using FIROpConversion::FIROpConversion; + + mlir::LogicalResult + matchAndRewrite(fir::BoxCharLenOp boxCharLen, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter) const override { + mlir::Value boxChar = adaptor.getOperands()[0]; + mlir::Location loc = boxChar.getLoc(); + mlir::MLIRContext *ctx = boxChar.getContext(); + mlir::Type returnValTy = boxCharLen.getResult().getType(); + + constexpr int boxcharLenIdx = 1; + mlir::LLVM::ExtractValueOp len = genExtractValueWithIndex( + loc, boxChar, boxChar.getType(), rewriter, ctx, boxcharLenIdx); + mlir::Value lenAfterCast = integerCast(loc, rewriter, returnValTy, len); + rewriter.replaceOp(boxCharLen, lenAfterCast); + + return success(); + } +}; + /// Convert `fir.unboxchar` into two `llvm.extractvalue` instructions. One for /// the character buffer and one for the buffer length. struct UnboxCharOpConversion : public FIROpConversion { @@ -1569,7 +1592,7 @@ mlir::OwningRewritePatternList pattern(context); pattern.insert< AbsentOpConversion, AddcOpConversion, AddrOfOpConversion, - AllocaOpConversion, BoxAddrOpConversion, BoxDimsOpConversion, + AllocaOpConversion, BoxAddrOpConversion, BoxCharLenOpConversion, BoxDimsOpConversion, BoxEleSizeOpConversion, BoxIsAllocOpConversion, BoxIsArrayOpConversion, BoxIsPtrOpConversion, BoxRankOpConversion, CallOpConversion, CmpcOpConversion, ConvertOpConversion, DispatchOpConversion, diff --git a/flang/test/Fir/convert-to-llvm-target.fir b/flang/test/Fir/convert-to-llvm-target.fir --- a/flang/test/Fir/convert-to-llvm-target.fir +++ b/flang/test/Fir/convert-to-llvm-target.fir @@ -71,3 +71,79 @@ // 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 + +// ----- + +// Test fir.boxchar_len + +func @boxchar_len_i8_i32(%arg0 : !fir.boxchar<1>) -> () { + fir.boxchar_len %arg0 : (!fir.boxchar<1>) -> i32 + return +} + +// INT64-LABEL: llvm.func @boxchar_len_i8_i32 +// INT64-SAME: %[[box_char:.*]]: !llvm.struct<(ptr, i64)> +// INT64: %[[len:.*]] = llvm.extractvalue %[[box_char]][1 : i32] : !llvm.struct<(ptr, i64)> +// INT64: %{{.*}} = llvm.trunc %[[len]] : i64 to i32 +// INT64-NEXT: llvm.return + +// INT32-LABEL: llvm.func @boxchar_len_i8_i32 +// INT32-SAME: %[[box_char:.*]]: !llvm.struct<(ptr, i32)> +// INT32: %{{.*}} = llvm.extractvalue %[[box_char]][1 : i32] : !llvm.struct<(ptr, i32)> +// INT32-NOT: llvm.trunc +// INT32-NOT: llvm.sext +// INT32-NEXT: llvm.return + +func @boxchar_len_i8_i64(%arg0 : !fir.boxchar<1>) -> () { + fir.boxchar_len %arg0 : (!fir.boxchar<1>) -> i64 + return +} + +// INT64-LABEL: llvm.func @boxchar_len_i8_i64 +// INT64-SAME: %[[box_char:.*]]: !llvm.struct<(ptr, i64)> +// INT64: %{{.*}} = llvm.extractvalue %[[box_char]][1 : i32] : !llvm.struct<(ptr, i64)> +// INT64-NOT: llvm.trunc +// INT64-NOT: llvm.sext +// INT64-NEXT: llvm.return + +// INT32-LABEL: llvm.func @boxchar_len_i8_i64 +// INT32-SAME: %[[box_char:.*]]: !llvm.struct<(ptr, i32)> +// INT32: %[[len:.*]] = llvm.extractvalue %[[box_char]][1 : i32] : !llvm.struct<(ptr, i32)> +// INT32: %{{.*}} = llvm.sext %0 : i32 to i64 +// INT32-NEXT: llvm.return + +func @boxchar_len_i32_i32(%arg0 : !fir.boxchar<4>) -> () { + fir.boxchar_len %arg0 : (!fir.boxchar<4>) -> i32 + return +} + +// INT64-LABEL: llvm.func @boxchar_len_i32_i32 +// INT64-SAME: %[[box_char:.*]]: !llvm.struct<(ptr, i64)> +// INT64: %[[len:.*]] = llvm.extractvalue %[[box_char]][1 : i32] : !llvm.struct<(ptr, i64)> +// INT64: %{{.*}} = llvm.trunc %[[len]] : i64 to i32 +// INT64-NEXT: llvm.return + +// INT32-LABEL: llvm.func @boxchar_len_i32_i32 +// INT32-SAME: %[[box_char:.*]]: !llvm.struct<(ptr, i32)> +// INT32: %{{.*}} = llvm.extractvalue %[[box_char]][1 : i32] : !llvm.struct<(ptr, i32)> +// INT32-NOT: llvm.trunc +// INT32-NOT: llvm.sext +// INT32-NEXT: llvm.return + +func @boxchar_len_i32_i64(%arg0 : !fir.boxchar<4>) -> (i64) { + %0 = fir.boxchar_len %arg0 : (!fir.boxchar<4>) -> i64 + return %0 : i64 +} + +// INT64-LABEL: llvm.func @boxchar_len_i32_i64 +// INT64-SAME: %[[box_char:.*]]: !llvm.struct<(ptr, i64)> +// INT64: %{{.*}} = llvm.extractvalue %[[box_char]][1 : i32] : !llvm.struct<(ptr, i64)> +// INT64-NOT: llvm.trunc +// INT64-NOT: llvm.sext +// INT64-NEXT: llvm.return + +// INT32-LABEL: llvm.func @boxchar_len_i32_i64 +// INT32-SAME: %[[box_char:.*]]: !llvm.struct<(ptr, i32)> +// INT32: %[[len:.*]] = llvm.extractvalue %[[box_char]][1 : i32] : !llvm.struct<(ptr, i32)> +// INT32: %{{.*}} = llvm.sext %0 : i32 to i64 +// INT32-NEXT: llvm.return