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 @@ -1388,6 +1388,41 @@ return success(); } }; + +/// Convert `!fir.emboxchar, #n>` into a sequence of +/// instructions that generate `!llvm.struct<(ptr, i64)>`. The 1st element +/// in this struct is a pointer. Its type is determined from `KIND`. The 2nd +/// element is the length of the character buffer (`#n`). +struct EmboxCharOpConversion : public FIROpConversion { + using FIROpConversion::FIROpConversion; + + mlir::LogicalResult + matchAndRewrite(fir::EmboxCharOp emboxChar, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter) const override { + mlir::ValueRange operands = adaptor.getOperands(); + MLIRContext *ctx = emboxChar.getContext(); + + mlir::Value charBuffer = operands[0]; + mlir::Value charBufferLen = operands[1]; + + mlir::Location loc = emboxChar.getLoc(); + mlir::Type llvmStructTy = convertType(emboxChar.getType()); + auto llvmStruct = rewriter.create(loc, llvmStructTy); + + mlir::Type lenTy = + llvmStructTy.cast().getBody()[1]; + mlir::Value lenAfterCast = integerCast(loc, rewriter, lenTy, charBufferLen); + + auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0)); + auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1)); + auto insertBufferOp = rewriter.create( + loc, llvmStructTy, llvmStruct, charBuffer, c0); + rewriter.replaceOpWithNewOp( + emboxChar, llvmStructTy, insertBufferOp, lenAfterCast, c1); + + return success(); + } +}; } // namespace namespace { @@ -1416,13 +1451,14 @@ BoxEleSizeOpConversion, BoxIsAllocOpConversion, BoxIsArrayOpConversion, BoxIsPtrOpConversion, BoxRankOpConversion, CallOpConversion, ConvertOpConversion, DispatchOpConversion, DispatchTableOpConversion, - DTEntryOpConversion, DivcOpConversion, ExtractValueOpConversion, - HasValueOpConversion, GlobalOpConversion, InsertOnRangeOpConversion, - InsertValueOpConversion, IsPresentOpConversion, LoadOpConversion, - NegcOpConversion, MulcOpConversion, SelectCaseOpConversion, - SelectOpConversion, SelectRankOpConversion, StoreOpConversion, - SubcOpConversion, UndefOpConversion, UnreachableOpConversion, - ZeroOpConversion>(typeConverter); + DTEntryOpConversion, DivcOpConversion, EmboxCharOpConversion, + ExtractValueOpConversion, HasValueOpConversion, GlobalOpConversion, + InsertOnRangeOpConversion, InsertValueOpConversion, + IsPresentOpConversion, LoadOpConversion, NegcOpConversion, + MulcOpConversion, SelectCaseOpConversion, SelectOpConversion, + SelectRankOpConversion, StoreOpConversion, SubcOpConversion, + 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 new file mode 100644 --- /dev/null +++ b/flang/test/Fir/convert-to-llvm-target.fir @@ -0,0 +1,33 @@ +// RUN: fir-opt --split-input-file --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" %s | FileCheck %s --check-prefix INT64 +// RUN: fir-opt --split-input-file --fir-to-llvm-ir="target=aarch64-unknown-linux-gnu" %s | FileCheck %s --check-prefixes INT64 +// RUN: fir-opt --split-input-file --fir-to-llvm-ir="target=i386-unknown-linux-gnu" %s | FileCheck %s --check-prefixes INT32 +// RUN: fir-opt --split-input-file --fir-to-llvm-ir="target=powerpc64le-unknown-linux-gn" %s | FileCheck %s --check-prefixes INT64 + +//============================================================================= +// SUMMARY: Tests for FIR --> LLVM MLIR conversion that *depend* on the target +//============================================================================= + +// Test fir.emboxchar + +func @test_embox(%char_array : !fir.ref>) -> () { + %c10 = arith.constant 10 : i64 + %box_char = fir.emboxchar %char_array, %c10 : (!fir.ref>, i64) -> !fir.boxchar<1> + return +} + +// INT64-LABEL: test_embox +// INT64-SAME: (%[[char_array:.*]]: !llvm.ptr) +// INT64: %[[c10:.*]] = llvm.mlir.constant(10 : i64) : i64 +// INT64: %[[empty_struct:.*]] = llvm.mlir.undef : !llvm.struct<(ptr, i{{.*}})> +// INT64: %[[struct_with_buffer:.*]] = llvm.insertvalue %[[char_array]], %[[empty_struct]][0 : i32] : !llvm.struct<(ptr, i{{.*}})> +// INT64: %{{.*}} = llvm.insertvalue %[[c10]], %[[struct_with_buffer]][1 : i32] : !llvm.struct<(ptr, i{{.*}})> +// INT64-NEXT: llvm.return + +// INT32-LABEL: llvm.func @test_embox +// INT32-SAME: %[[char_array:.*]]: !llvm.ptr) +// INT32: %[[c10:.*]] = llvm.mlir.constant(10 : i64) : i64 +// INT32: %[[empty_struct:.*]] = llvm.mlir.undef : !llvm.struct<(ptr, i32)> +// INT32: %[[c10_truncated:.*]] = llvm.trunc %[[c10]] : i64 to i32 +// 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 diff --git a/flang/test/Fir/convert-to-llvm.fir b/flang/test/Fir/convert-to-llvm.fir --- a/flang/test/Fir/convert-to-llvm.fir +++ b/flang/test/Fir/convert-to-llvm.fir @@ -3,6 +3,9 @@ // RUN: fir-opt --split-input-file --fir-to-llvm-ir="target=i386-unknown-linux-gnu" %s | FileCheck %s // RUN: fir-opt --split-input-file --fir-to-llvm-ir="target=powerpc64le-unknown-linux-gn" %s | FileCheck %s +//============================================================================= +// SUMMARY: Tests for FIR --> LLVM MLIR conversion independent of the target +//============================================================================= // Test simple global LLVM conversion