diff --git a/flang/include/flang/Optimizer/CodeGen/CGOps.td b/flang/include/flang/Optimizer/CodeGen/CGOps.td --- a/flang/include/flang/Optimizer/CodeGen/CGOps.td +++ b/flang/include/flang/Optimizer/CodeGen/CGOps.td @@ -56,14 +56,15 @@ Variadic:$slice, Variadic:$subcomponent, Variadic:$substr, - Variadic:$lenParams + Variadic:$lenParams, + Optional:$tdesc ); let results = (outs BoxOrClassType); let assemblyFormat = [{ $memref (`(`$shape^`)`)? (`origin` $shift^)? (`[`$slice^`]`)? (`path` $subcomponent^)? (`substr` $substr^)? (`typeparams` $lenParams^)? - attr-dict `:` functional-type(operands, results) + (`tdesc` $tdesc^)? attr-dict `:` functional-type(operands, results) }]; let extraClassDeclaration = [{ @@ -82,6 +83,9 @@ return subcomponentOffset() + getSubcomponent().size(); } unsigned lenParamOffset() { return substrOffset() + getSubstr().size(); } + unsigned getTdescOffset() { + return lenParamOffset() + getLenParams().size(); + } }]; } diff --git a/flang/include/flang/Optimizer/Dialect/FIROps.td b/flang/include/flang/Optimizer/Dialect/FIROps.td --- a/flang/include/flang/Optimizer/Dialect/FIROps.td +++ b/flang/include/flang/Optimizer/Dialect/FIROps.td @@ -788,6 +788,10 @@ let extraClassDeclaration = [{ bool hasLenParams() { return !getTypeparams().empty(); } unsigned numLenParams() { return getTypeparams().size(); } + unsigned getTdescOffset() { + return 1 + (getShape() ? 1 : 0) + (getSlice() ? 1 : 0) + + numLenParams(); + } }]; } @@ -1167,7 +1171,7 @@ ``` }]; - let arguments = (ins BoxOrClassType:$val); + let arguments = (ins BoxOrClassType:$box); let results = (outs fir_TypeDescType); } 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 @@ -640,13 +640,9 @@ matchAndRewrite(fir::BoxTypeDescOp boxtypedesc, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const override { mlir::Value box = adaptor.getOperands()[0]; - auto loc = boxtypedesc.getLoc(); - mlir::Type typeTy = - fir::getDescFieldTypeModel()(boxtypedesc.getContext()); - auto result = getValueFromBox(loc, box, typeTy, rewriter, kTypePosInBox); - auto typePtrTy = mlir::LLVM::LLVMPointerType::get(typeTy); - rewriter.replaceOpWithNewOp(boxtypedesc, typePtrTy, - result); + auto typeDescAddr = loadTypeDescAddress( + boxtypedesc.getLoc(), boxtypedesc.getBox().getType(), box, rewriter); + rewriter.replaceOp(boxtypedesc, typeDescAddr); return mlir::success(); } }; @@ -1640,9 +1636,13 @@ matchAndRewrite(fir::EmboxOp embox, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const override { mlir::ValueRange operands = adaptor.getOperands(); + mlir::Value tdesc; + if (embox.getTdesc()) + tdesc = operands[embox.getTdescOffset()]; assert(!embox.getShape() && "There should be no dims on this embox op"); auto [boxTy, dest, eleSize] = consDescriptorPrefix( - embox, rewriter, /*rank=*/0, /*lenParams=*/operands.drop_front(1)); + embox, rewriter, + /*rank=*/0, /*lenParams=*/operands.drop_front(1), tdesc); dest = insertBaseAddress(rewriter, embox.getLoc(), dest, operands[0]); if (isDerivedTypeWithLenParams(boxTy)) { TODO(embox.getLoc(), @@ -1663,9 +1663,12 @@ matchAndRewrite(fir::cg::XEmboxOp xbox, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const override { mlir::ValueRange operands = adaptor.getOperands(); + mlir::Value tdesc; + if (xbox.getTdesc()) + tdesc = operands[xbox.getTdescOffset()]; auto [boxTy, dest, eleSize] = consDescriptorPrefix(xbox, rewriter, xbox.getOutRank(), - operands.drop_front(xbox.lenParamOffset())); + operands.drop_front(xbox.lenParamOffset()), tdesc); // Generate the triples in the dims field of the descriptor auto i64Ty = mlir::IntegerType::get(xbox.getContext(), 64); mlir::Value base = operands[0]; @@ -2414,7 +2417,7 @@ } // Boxed type - get the base pointer from the box - if (baseObjectTy.dyn_cast()) + if (baseObjectTy.dyn_cast()) return doRewriteBox(coor, ty, operands, loc, rewriter); // Reference, pointer or a heap type @@ -2496,7 +2499,7 @@ mlir::Location loc, mlir::ConversionPatternRewriter &rewriter) const { mlir::Type boxObjTy = coor.getBaseType(); - assert(boxObjTy.dyn_cast() && "This is not a `fir.box`"); + assert(boxObjTy.dyn_cast() && "This is not a `fir.box`"); mlir::Value boxBaseAddr = operands[0]; diff --git a/flang/lib/Optimizer/CodeGen/PreCGRewrite.cpp b/flang/lib/Optimizer/CodeGen/PreCGRewrite.cpp --- a/flang/lib/Optimizer/CodeGen/PreCGRewrite.cpp +++ b/flang/lib/Optimizer/CodeGen/PreCGRewrite.cpp @@ -107,7 +107,8 @@ } auto xbox = rewriter.create( loc, embox.getType(), embox.getMemref(), shapeOpers, llvm::None, - llvm::None, llvm::None, llvm::None, embox.getTypeparams()); + llvm::None, llvm::None, llvm::None, embox.getTypeparams(), + embox.getTdesc()); LLVM_DEBUG(llvm::dbgs() << "rewriting " << embox << " to " << xbox << '\n'); rewriter.replaceOp(embox, xbox.getOperation()->getResults()); return mlir::success(); @@ -142,7 +143,8 @@ } auto xbox = rewriter.create( loc, embox.getType(), embox.getMemref(), shapeOpers, shiftOpers, - sliceOpers, subcompOpers, substrOpers, embox.getTypeparams()); + sliceOpers, subcompOpers, substrOpers, embox.getTypeparams(), + embox.getTdesc()); LLVM_DEBUG(llvm::dbgs() << "rewriting " << embox << " to " << xbox << '\n'); rewriter.replaceOp(embox, xbox.getOperation()->getResults()); return mlir::success(); 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 @@ -1486,16 +1486,15 @@ // Test `fir.box_tdesc` conversion. -func.func @box_tdesc(%arg0: !fir.box) { - %0 = fir.box_tdesc %arg0 : (!fir.box) -> !fir.tdesc +func.func @box_tdesc(%arg0: !fir.box>) { + %0 = fir.box_tdesc %arg0 : (!fir.box>) -> !fir.tdesc> return } // CHECK-LABEL: llvm.func @box_tdesc( -// CHECK-SAME: %[[ARG0:.*]]: !llvm.ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}})>>) { -// CHECK: %[[GEP:.*]] = llvm.getelementptr %[[ARG0]][0, 4] : (!llvm.ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}})>>) -> !llvm.ptr -// CHECK: %[[LOAD:.*]] = llvm.load %[[GEP]] : !llvm.ptr -// CHECK: %{{.*}} = llvm.inttoptr %[[LOAD]] : i{{.*}} to !llvm.ptr +// CHECK-SAME: %[[ARG0:.*]]: !llvm.ptr>, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, ptr, array<1 x i{{.*}}>)>>) { +// CHECK: %[[GEP:.*]] = llvm.getelementptr %[[ARG0]][0, 7] : (!llvm.ptr>, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, ptr, array<1 x i{{.*}}>)>>) -> !llvm.ptr> +// CHECK: %[[LOAD:.*]] = llvm.load %[[GEP]] : !llvm.ptr> // ----- diff --git a/flang/test/Lower/allocatable-polymorphic.f90 b/flang/test/Lower/allocatable-polymorphic.f90 --- a/flang/test/Lower/allocatable-polymorphic.f90 +++ b/flang/test/Lower/allocatable-polymorphic.f90 @@ -43,6 +43,7 @@ class(p1), allocatable :: p class(p1), allocatable :: c1, c2 class(p1), allocatable, dimension(:) :: c3, c4 + integer :: i allocate(p) ! allocate as p1 @@ -57,6 +58,14 @@ call c1%proc2() call c2%proc2() + + do i = 1, 10 + call c3(i)%proc2() + end do + + do i = 1, 20 + call c4(i)%proc2() + end do end ! CHECK-LABEL: func.func @_QQmain() @@ -128,11 +137,25 @@ ! Check fir.rebox for fir.class ! CHECK: %[[C1_LOAD:.*]] = fir.load %[[C1]] : !fir.ref>>> ! CHECK: %[[C1_REBOX:.*]] = fir.rebox %[[C1_LOAD]] : (!fir.class>>) -> !fir.class> -! CHECK: fir.dispatch "proc2"(%[[C1_REBOX]] : !fir.class>) (%61 : !fir.class>) {pass_arg_pos = 0 : i32} +! CHECK: fir.dispatch "proc2"(%[[C1_REBOX]] : !fir.class>) (%[[C1_REBOX]] : !fir.class>) {pass_arg_pos = 0 : i32} ! CHECK: %[[C2_LOAD:.*]] = fir.load %[[C2]] : !fir.ref>>> ! CHECK: %[[C2_REBOX:.*]] = fir.rebox %[[C2_LOAD]] : (!fir.class>>) -> !fir.class> -! CHECK: fir.dispatch "proc2"(%[[C2_REBOX]] : !fir.class>) (%63 : !fir.class>) {pass_arg_pos = 0 : i32} +! CHECK: fir.dispatch "proc2"(%[[C2_REBOX]] : !fir.class>) (%[[C2_REBOX]] : !fir.class>) {pass_arg_pos = 0 : i32} + +! CHECK-LABEL: %{{.*}} = fir.do_loop +! CHECK: %[[C3_LOAD:.*]] = fir.load %[[C3]] : !fir.ref>>>> +! CHECK: %[[C3_COORD:.*]] = fir.coordinate_of %[[C3_LOAD]], %{{.*}} : (!fir.class>>>, i64) -> !fir.ref> +! CHECK: %[[C3_TDESC:.*]] = fir.box_tdesc %[[C3_LOAD]] : (!fir.class>>>) -> !fir.tdesc> +! CHECK: %[[C3_EMBOX:.*]] = fir.embox %[[C3_COORD]] tdesc %[[C3_TDESC]] : (!fir.ref>, !fir.tdesc>) -> !fir.class> +! CHECK: fir.dispatch "proc2"(%[[C3_EMBOX]] : !fir.class>) (%[[C3_EMBOX]] : !fir.class>) {pass_arg_pos = 0 : i32} + +! CHECK-LABEL: %{{.*}} = fir.do_loop +! CHECK: %[[C4_LOAD:.*]] = fir.load %[[C4]] : !fir.ref>>>> +! CHECK: %[[C4_COORD:.*]] = fir.coordinate_of %[[C4_LOAD]], %{{.*}} : (!fir.class>>>, i64) -> !fir.ref> +! CHECK: %[[C4_TDESC:.*]] = fir.box_tdesc %[[C4_LOAD]] : (!fir.class>>>) -> !fir.tdesc> +! CHECK: %[[C4_EMBOX:.*]] = fir.embox %[[C4_COORD]] tdesc %[[C4_TDESC]] : (!fir.ref>, !fir.tdesc>) -> !fir.class> +! CHECK: fir.dispatch "proc2"(%[[C4_EMBOX]] : !fir.class>) (%[[C4_EMBOX]] : !fir.class>) {pass_arg_pos = 0 : i32} ! Check code generation of allocate runtime calls for polymoprhic entities. This ! is done from Fortran so we don't have a file full of auto-generated type info @@ -140,9 +163,14 @@ ! LLVM-LABEL: define void @_QQmain() ! LLVM: %[[TMP1:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] } -! LLVM: %[[TMP2:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] } +! LLVM: %[[TMP2:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]], ptr, [1 x i64] } ! LLVM: %[[TMP3:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] } -! LLVM: %[[TMP4:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] } +! LLVM: %[[TMP4:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]], ptr, [1 x i64] } +! LLVM: %[[TMP5:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] } +! LLVM: %[[TMP6:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] } +! LLVM: %[[TMP7:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] } +! LLVM: %[[TMP8:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] } + ! LLVM: %{{.*}} = call {} @_FortranAAllocatableInitDerived(ptr @_QFEp, ptr @_QMpolyE.dt.p1, i32 0, i32 0) ! LLVM: %{{.*}} = call i32 @_FortranAAllocatableAllocate(ptr @_QFEp, i1 false, ptr null, ptr @_QQcl.{{.*}}, i32 {{.*}}) ! LLVM: %{{.*}} = call {} @_FortranAAllocatableInitDerived(ptr @_QFEc1, ptr @_QMpolyE.dt.p1, i32 0, i32 0) @@ -155,20 +183,36 @@ ! LLVM: %{{.*}} = call {} @_FortranAAllocatableInitDerived(ptr @_QFEc4, ptr @_QMpolyE.dt.p2, i32 1, i32 0) ! LLVM: %{{.*}} = call {} @_FortranAAllocatableSetBounds(ptr @_QFEc4, i32 0, i64 1, i64 20) ! LLVM: %{{.*}} = call i32 @_FortranAAllocatableAllocate(ptr @_QFEc4, i1 false, ptr null, ptr @_QQcl.{{.*}}, i32 {{.*}}) -! LLVM: call void %{{.*}}() +! LLVM-COUNT-2: call void %{{.*}}() ! LLVM: %[[C1_LOAD:.*]] = load { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, ptr @_QFEc1 -! LLVM: store { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] } %[[C1_LOAD]], ptr %[[TMP4]] -! LLVM: %[[GEP_TDESC_C1:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, ptr %[[TMP4]], i32 0, i32 7 +! LLVM: store { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] } %[[C1_LOAD]], ptr %[[TMP8]] +! LLVM: %[[GEP_TDESC_C1:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, ptr %[[TMP8]], i32 0, i32 7 ! LLVM: %[[TDESC_C1:.*]] = load ptr, ptr %[[GEP_TDESC_C1]] ! LLVM: %[[BOX0:.*]] = insertvalue { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] } { ptr undef, i64 ptrtoint (ptr getelementptr (%_QMpolyTp1, ptr null, i32 1) to i64), i32 20180515, i8 0, i8 42, i8 0, i8 1, ptr undef, [1 x i64] undef }, ptr %[[TDESC_C1]], 7 ! LLVM: %[[BOX1:.*]] = insertvalue { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] } %[[BOX0]], ptr %{{.*}}, 0 -! LLVM: store { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] } %[[BOX1]], ptr %[[TMP3]] +! LLVM: store { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] } %[[BOX1]], ptr %[[TMP7]] ! LLVM: %[[LOAD_C2:.*]] = load { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, ptr @_QFEc2 -! LLVM: store { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] } %[[LOAD_C2]], ptr %[[TMP2]] -! LLVM: %[[GEP_TDESC_C2:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, ptr %[[TMP2]], i32 0, i32 7 +! LLVM: store { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] } %[[LOAD_C2]], ptr %[[TMP6]] +! LLVM: %[[GEP_TDESC_C2:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, ptr %[[TMP6]], i32 0, i32 7 ! LLVM: %[[TDESC_C2:.*]] = load ptr, ptr %[[GEP_TDESC_C2]] ! LLVM: %[[BOX0:.*]] = insertvalue { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] } { ptr undef, i64 ptrtoint (ptr getelementptr (%_QMpolyTp1, ptr null, i32 1) to i64), i32 20180515, i8 0, i8 42, i8 0, i8 1, ptr undef, [1 x i64] undef }, ptr %[[TDESC_C2]], 7 ! LLVM: %[[BOX1:.*]] = insertvalue { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] } %[[BOX0]], ptr %{{.*}}, 0 +! LLVM: store { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] } %[[BOX1]], ptr %[[TMP5]] + +! LLVM: %[[C3_LOAD:.*]] = load { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]], ptr, [1 x i64] }, ptr @_QFEc3 +! LLVM: store { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]], ptr, [1 x i64] } %[[C3_LOAD]], ptr %[[TMP2]] +! LLVM: %[[GEP_TDESC_C3:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]], ptr, [1 x i64] }, ptr %[[TMP2]], i32 0, i32 8 +! LLVM: %[[TDESC_C3:.*]] = load ptr, ptr %[[GEP_TDESC_C3]] +! LLVM: %[[BOX0:.*]] = insertvalue { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] } { ptr undef, i64 ptrtoint (ptr getelementptr (%_QMpolyTp1, ptr null, i32 1) to i64), i32 20180515, i8 0, i8 42, i8 0, i8 1, ptr undef, [1 x i64] undef }, ptr %[[TDESC_C3]], 7 +! LLVM: %[[BOX1:.*]] = insertvalue { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] } %[[BOX0]], ptr %{{.*}}, 0 ! LLVM: store { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] } %[[BOX1]], ptr %[[TMP1]] + +! LLVM: %[[C4_LOAD:.*]] = load { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]], ptr, [1 x i64] }, ptr @_QFEc4 +! LLVM: store { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]], ptr, [1 x i64] } %[[C4_LOAD]], ptr %[[TMP4]] +! LLVM: %[[GEP_TDESC_C4:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]], ptr, [1 x i64] }, ptr %[[TMP4]], i32 0, i32 8 +! LLVM: %[[TDESC_C4:.*]] = load ptr, ptr %[[GEP_TDESC_C4]] +! LLVM: %[[BOX0:.*]] = insertvalue { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] } { ptr undef, i64 ptrtoint (ptr getelementptr (%_QMpolyTp1, ptr null, i32 1) to i64), i32 20180515, i8 0, i8 42, i8 0, i8 1, ptr undef, [1 x i64] undef }, ptr %[[TDESC_C4]], 7 +! LLVM: %[[BOX1:.*]] = insertvalue { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] } %[[BOX0]], ptr %{{.*}}, 0 +! LLVM: store { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] } %[[BOX1]], ptr %[[TMP3]]