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 @@ -263,6 +263,31 @@ return rewriter.create(loc, ty, base, cv); } + // Find the LLVMFuncOp in whose entry block the alloca should be inserted. + // The order to find the LLVMFuncOp is as follows: + // 1. The parent operation of the current block if it is a LLVMFuncOp. + // 2. The first ancestor that is a LLVMFuncOp. + mlir::LLVM::LLVMFuncOp + getFuncForAllocaInsert(mlir::ConversionPatternRewriter &rewriter) const { + mlir::Operation *parentOp = rewriter.getInsertionBlock()->getParentOp(); + return mlir::isa(parentOp) + ? mlir::cast(parentOp) + : parentOp->getParentOfType(); + } + + // Generate an alloca of size 1 and type \p toTy. + mlir::LLVM::AllocaOp + genAllocaWithType(mlir::Location loc, mlir::Type toTy, unsigned alignment, + mlir::ConversionPatternRewriter &rewriter) const { + auto thisPt = rewriter.saveInsertionPoint(); + mlir::LLVM::LLVMFuncOp func = getFuncForAllocaInsert(rewriter); + rewriter.setInsertionPointToStart(&func.front()); + auto size = genI32Constant(loc, rewriter, 1); + auto al = rewriter.create(loc, toTy, size, alignment); + rewriter.restoreInsertionPoint(thisPt); + return al; + } + fir::LLVMTypeConverter &lowerTy() const { return *static_cast(this->getTypeConverter()); } @@ -1096,31 +1121,6 @@ struct EmboxCommonConversion : public FIROpConversion { using FIROpConversion::FIROpConversion; - // Find the LLVMFuncOp in whose entry block the alloca should be inserted. - // The order to find the LLVMFuncOp is as follows: - // 1. The parent operation of the current block if it is a LLVMFuncOp. - // 2. The first ancestor that is a LLVMFuncOp. - mlir::LLVM::LLVMFuncOp - getFuncForAllocaInsert(mlir::ConversionPatternRewriter &rewriter) const { - mlir::Operation *parentOp = rewriter.getInsertionBlock()->getParentOp(); - return mlir::isa(parentOp) - ? mlir::cast(parentOp) - : parentOp->getParentOfType(); - } - - // Generate an alloca of size 1 and type \p toTy. - mlir::LLVM::AllocaOp - genAllocaWithType(mlir::Location loc, mlir::Type toTy, unsigned alignment, - mlir::ConversionPatternRewriter &rewriter) const { - auto thisPt = rewriter.saveInsertionPoint(); - mlir::LLVM::LLVMFuncOp func = getFuncForAllocaInsert(rewriter); - rewriter.setInsertionPointToStart(&func.front()); - auto size = this->genI32Constant(loc, rewriter, 1); - auto al = rewriter.create(loc, toTy, size, alignment); - rewriter.restoreInsertionPoint(thisPt); - return al; - } - static int getCFIAttr(fir::BoxType boxTy) { auto eleTy = boxTy.getEleTy(); if (eleTy.isa()) @@ -1474,7 +1474,8 @@ if (thisBlock && mlir::isa(thisBlock->getParentOp())) return boxValue; auto boxPtrTy = mlir::LLVM::LLVMPointerType::get(boxValue.getType()); - auto alloca = genAllocaWithType(loc, boxPtrTy, defaultAlign, rewriter); + auto alloca = + this->genAllocaWithType(loc, boxPtrTy, defaultAlign, rewriter); rewriter.create(loc, boxValue, alloca); return alloca; } @@ -2714,12 +2715,29 @@ mlir::LogicalResult matchAndRewrite(fir::LoadOp load, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const override { - // fir.box is a special case because it is considered as an ssa values in - // fir, but it is lowered as a pointer to a descriptor. So fir.ref - // and fir.box end up being the same llvm types and loading a - // fir.ref is actually a no op in LLVM. - if (load.getType().isa()) { - rewriter.replaceOp(load, adaptor.getOperands()[0]); + if (auto boxTy = load.getType().dyn_cast()) { + // fir.box is a special case because it is considered as an ssa values in + // fir, but it is lowered as a pointer to a descriptor. So + // fir.ref and fir.box end up being the same llvm types and + // loading a fir.ref is implemented as taking a snapshot of the + // descriptor value into a new descriptor temp. + auto inputBoxStorage = adaptor.getOperands()[0]; + mlir::Location loc = load.getLoc(); + fir::SequenceType seqTy = fir::unwrapUntilSeqType(boxTy); + mlir::Type eleTy = fir::unwrapPassByRefType(boxTy); + // fir.box of assumed rank and polymorphic entities do not have a storage + // size that is know at compile time. The copy needs to be runtime driven + // depending on the actual dynamic rank or type. + if (eleTy.isa() || (seqTy && seqTy.hasUnknownShape())) + TODO(loc, "loading polymorphic or assumed rank fir.box"); + mlir::Type boxPtrTy = inputBoxStorage.getType(); + auto boxValue = rewriter.create( + loc, boxPtrTy.cast().getElementType(), + inputBoxStorage); + auto newBoxStorage = + genAllocaWithType(loc, boxPtrTy, defaultAlign, rewriter); + rewriter.create(loc, boxValue, newBoxStorage); + rewriter.replaceOp(load, newBoxStorage.getResult()); } else { rewriter.replaceOpWithNewOp( load, convertType(load.getType()), adaptor.getOperands(), 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 @@ -867,15 +867,23 @@ // CHECK-NEXT: llvm.return // CHECK-NEXT: } +func.func private @takes_box(!fir.box>) -> () + func.func @test_load_box(%addr : !fir.ref>>) { %0 = fir.load %addr : !fir.ref>> + fir.call @takes_box(%0) : (!fir.box>) -> () return } -// Loading a `fir.ref> is a no-op -// CHECK-LABEL: llvm.func @test_load_box -// CHECK-SAME: (%{{.*}}: !llvm.ptr>, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, array<1 x array<3 x i{{.*}}>>)>>) { -// CHECK-NEXT: llvm.return +// Loading a `fir.ref> is creating a descriptor copy +// CHECK-LABEL: llvm.func @test_load_box( +// CHECK-SAME: %[[arg0:.*]]: !llvm.ptr>) { +// CHECK-NEXT: %[[c1:.*]] = llvm.mlir.constant(1 : i32) : i32 +// CHECK-NEXT: %[[box_copy:.*]] = llvm.alloca %[[c1]] x !llvm.struct<([[DESC_TYPE]])> +// CHECK-NEXT: %[[box_val:.*]] = llvm.load %[[arg0]] : !llvm.ptr> +// CHECK-NEXT: llvm.store %[[box_val]], %[[box_copy]] : !llvm.ptr> +// CHECK-NEXT: llvm.call @takes_box(%[[box_copy]]) : (!llvm.ptr>) -> () +// CHECK-NEXT: llvm.return // CHECK-NEXT: } // -----