diff --git a/flang/lib/Optimizer/Builder/HLFIRTools.cpp b/flang/lib/Optimizer/Builder/HLFIRTools.cpp index 51ea7305d3d26..f2b084cb760b9 100644 --- a/flang/lib/Optimizer/Builder/HLFIRTools.cpp +++ b/flang/lib/Optimizer/Builder/HLFIRTools.cpp @@ -70,8 +70,9 @@ getExplicitExtents(fir::FortranVariableOpInterface var, return {}; } -// Return explicit lower bounds. For pointers and allocatables, this will not -// read the lower bounds and instead return an empty vector. +// Return explicit lower bounds from a shape result. +// Only fir.shape, fir.shift and fir.shape_shift are currently +// supported as shape. static llvm::SmallVector getExplicitLboundsFromShape(mlir::Value shape) { llvm::SmallVector result; @@ -89,6 +90,9 @@ getExplicitLboundsFromShape(mlir::Value shape) { } return result; } + +// Return explicit lower bounds. For pointers and allocatables, this will not +// read the lower bounds and instead return an empty vector. static llvm::SmallVector getExplicitLbounds(fir::FortranVariableOpInterface var) { if (mlir::Value shape = var.getShape()) @@ -753,9 +757,30 @@ std::pair hlfir::genVariableFirBaseShapeAndParams( } if (entity.isScalar()) return {fir::getBase(exv), mlir::Value{}}; - if (auto variableInterface = entity.getIfVariableInterface()) - return {fir::getBase(exv), - asEmboxShape(loc, builder, exv, variableInterface.getShape())}; + + // Contiguous variables that are represented with a box + // may require the shape to be extracted from the box (i.e. evx), + // because they itself may not have shape specified. + // This happens during late propagationg of contiguous + // attribute, e.g.: + // %9:2 = hlfir.declare %6 + // {fortran_attrs = #fir.var_attrs} : + // (!fir.box>) -> + // (!fir.box>, !fir.box>) + // The extended value is an ArrayBoxValue with base being + // the raw address of the array. + if (auto variableInterface = entity.getIfVariableInterface()) { + mlir::Value shape = variableInterface.getShape(); + if (mlir::isa(fir::getBase(exv).getType()) || + !mlir::isa(entity.getType()) || + // Still use the variable's shape if it is present. + // If it only specifies a shift, then we have to create + // a shape from the exv. + (shape && (shape.getDefiningOp() || + shape.getDefiningOp()))) + return {fir::getBase(exv), + asEmboxShape(loc, builder, exv, variableInterface.getShape())}; + } return {fir::getBase(exv), builder.createShape(loc, exv)}; } diff --git a/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp b/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp index 8721a895b5e05..8f206b5a1ade7 100644 --- a/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp +++ b/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp @@ -414,10 +414,11 @@ class DesignateOpConversion auto attrs = designate.getIsTripletAttr(); for (auto isTriplet : attrs.asArrayRef()) { // Coordinate of the first element are the index and triplets lower - // bounds + // bounds. firstElementIndices.push_back(indices[i]); i = i + (isTriplet ? 3 : 1); } + mlir::Type originalDesignateType = designate.getResult().getType(); const bool isVolatile = fir::isa_volatile_type(originalDesignateType); mlir::Type arrayCoorType = fir::ReferenceType::get(baseEleTy, isVolatile); diff --git a/flang/test/HLFIR/designate-codegen.fir b/flang/test/HLFIR/designate-codegen.fir index da0a1f82b516e..5c3ae202fd3b9 100644 --- a/flang/test/HLFIR/designate-codegen.fir +++ b/flang/test/HLFIR/designate-codegen.fir @@ -213,3 +213,70 @@ func.func @test_polymorphic_array_elt(%arg0: !fir.class>, !fir.class>>) -> !fir.class> // CHECK: return // CHECK: } + +// Test proper generation of fir.array_coor for contiguous box with default lbounds. +func.func @_QPtest_contiguous_derived_default(%arg0: !fir.class>> {fir.bindc_name = "d1", fir.contiguous, fir.optional}) { + %c1 = arith.constant 1 : index + %c16_i32 = arith.constant 16 : i32 + %0 = fir.dummy_scope : !fir.dscope + %1:2 = hlfir.declare %arg0 dummy_scope %0 {fortran_attrs = #fir.var_attrs, uniq_name = "_QFtest_contiguous_derived_defaultEd1"} : (!fir.class>>, !fir.dscope) -> (!fir.class>>, !fir.class>>) + fir.select_type %1#1 : !fir.class>> [#fir.type_is,i:i32}>>, ^bb1, unit, ^bb2] +^bb1: // pred: ^bb0 + %2 = fir.convert %1#1 : (!fir.class>>) -> !fir.box,i:i32}>>> + %3:2 = hlfir.declare %2 {fortran_attrs = #fir.var_attrs, uniq_name = "_QFtest_contiguous_derived_defaultEd1"} : (!fir.box,i:i32}>>>) -> (!fir.box,i:i32}>>>, !fir.box,i:i32}>>>) + %4 = hlfir.designate %3#0 (%c1, %c1) : (!fir.box,i:i32}>>>, index, index) -> !fir.ref,i:i32}>> + %5 = hlfir.designate %4{"i"} : (!fir.ref,i:i32}>>) -> !fir.ref + hlfir.assign %c16_i32 to %5 : i32, !fir.ref + cf.br ^bb3 +^bb2: // pred: ^bb0 + %6:2 = hlfir.declare %1#1 {fortran_attrs = #fir.var_attrs, uniq_name = "_QFtest_contiguous_derived_defaultEd1"} : (!fir.class>>) -> (!fir.class>>, !fir.class>>) + cf.br ^bb3 +^bb3: // 2 preds: ^bb1, ^bb2 + return +} +// CHECK-LABEL: func.func @_QPtest_contiguous_derived_default( +// CHECK: %[[VAL_0:.*]] = arith.constant 1 : index +// CHECK: %[[VAL_9:.*]] = fir.declare %{{.*}} {fortran_attrs = #fir.var_attrs, uniq_name = "_QFtest_contiguous_derived_defaultEd1"} : (!fir.box,i:i32}>>>) -> !fir.box,i:i32}>>> +// CHECK: %[[VAL_10:.*]] = fir.rebox %[[VAL_9]] : (!fir.box,i:i32}>>>) -> !fir.box,i:i32}>>> +// CHECK: %[[VAL_11:.*]] = fir.box_addr %[[VAL_10]] : (!fir.box,i:i32}>>>) -> !fir.ref,i:i32}>>> +// CHECK: %[[VAL_12:.*]] = arith.constant 0 : index +// CHECK: %[[VAL_13:.*]]:3 = fir.box_dims %[[VAL_10]], %[[VAL_12]] : (!fir.box,i:i32}>>>, index) -> (index, index, index) +// CHECK: %[[VAL_14:.*]] = arith.constant 1 : index +// CHECK: %[[VAL_15:.*]]:3 = fir.box_dims %[[VAL_10]], %[[VAL_14]] : (!fir.box,i:i32}>>>, index) -> (index, index, index) +// CHECK: %[[VAL_16:.*]] = fir.shape %[[VAL_13]]#1, %[[VAL_15]]#1 : (index, index) -> !fir.shape<2> +// CHECK: %[[VAL_17:.*]] = fir.array_coor %[[VAL_11]](%[[VAL_16]]) %[[VAL_0]], %[[VAL_0]] : (!fir.ref,i:i32}>>>, !fir.shape<2>, index, index) -> !fir.ref,i:i32}>> + +// Test proper generation of fir.array_coor for contiguous box with non-default lbounds. +func.func @_QPtest_contiguous_derived_lbounds(%arg0: !fir.class>> {fir.bindc_name = "d1", fir.contiguous}) { + %c3 = arith.constant 3 : index + %c1 = arith.constant 1 : index + %c16_i32 = arith.constant 16 : i32 + %0 = fir.dummy_scope : !fir.dscope + %1 = fir.shift %c1, %c3 : (index, index) -> !fir.shift<2> + %2:2 = hlfir.declare %arg0(%1) dummy_scope %0 {fortran_attrs = #fir.var_attrs, uniq_name = "_QFtest_contiguous_derived_lboundsEd1"} : (!fir.class>>, !fir.shift<2>, !fir.dscope) -> (!fir.class>>, !fir.class>>) + fir.select_type %2#1 : !fir.class>> [#fir.type_is,i:i32}>>, ^bb1, unit, ^bb2] +^bb1: // pred: ^bb0 + %3 = fir.convert %2#1 : (!fir.class>>) -> !fir.box,i:i32}>>> + %4:2 = hlfir.declare %3(%1) {fortran_attrs = #fir.var_attrs, uniq_name = "_QFtest_contiguous_derived_lboundsEd1"} : (!fir.box,i:i32}>>>, !fir.shift<2>) -> (!fir.box,i:i32}>>>, !fir.box,i:i32}>>>) + %5 = hlfir.designate %4#0 (%c1, %c3) : (!fir.box,i:i32}>>>, index, index) -> !fir.ref,i:i32}>> + %6 = hlfir.designate %5{"i"} : (!fir.ref,i:i32}>>) -> !fir.ref + hlfir.assign %c16_i32 to %6 : i32, !fir.ref + cf.br ^bb3 +^bb2: // pred: ^bb0 + %7:2 = hlfir.declare %2#1(%1) {fortran_attrs = #fir.var_attrs, uniq_name = "_QFtest_contiguous_derived_lboundsEd1"} : (!fir.class>>, !fir.shift<2>) -> (!fir.class>>, !fir.class>>) + cf.br ^bb3 +^bb3: // 2 preds: ^bb1, ^bb2 + return +} +// CHECK-LABEL: func.func @_QPtest_contiguous_derived_lbounds( +// CHECK: %[[VAL_0:.*]] = arith.constant 3 : index +// CHECK: %[[VAL_1:.*]] = arith.constant 1 : index +// CHECK: %[[VAL_8:.*]] = fir.declare %{{.*}}(%[[VAL_4:.*]]) {fortran_attrs = #fir.var_attrs, uniq_name = "_QFtest_contiguous_derived_lboundsEd1"} : (!fir.box,i:i32}>>>, !fir.shift<2>) -> !fir.box,i:i32}>>> +// CHECK: %[[VAL_9:.*]] = fir.rebox %[[VAL_8]](%[[VAL_4]]) : (!fir.box,i:i32}>>>, !fir.shift<2>) -> !fir.box,i:i32}>>> +// CHECK: %[[VAL_10:.*]] = fir.box_addr %[[VAL_9]] : (!fir.box,i:i32}>>>) -> !fir.ref,i:i32}>>> +// CHECK: %[[VAL_11:.*]] = arith.constant 0 : index +// CHECK: %[[VAL_12:.*]]:3 = fir.box_dims %[[VAL_9]], %[[VAL_11]] : (!fir.box,i:i32}>>>, index) -> (index, index, index) +// CHECK: %[[VAL_13:.*]] = arith.constant 1 : index +// CHECK: %[[VAL_14:.*]]:3 = fir.box_dims %[[VAL_9]], %[[VAL_13]] : (!fir.box,i:i32}>>>, index) -> (index, index, index) +// CHECK: %[[VAL_15:.*]] = fir.shape_shift %[[VAL_1]], %[[VAL_12]]#1, %[[VAL_0]], %[[VAL_14]]#1 : (index, index, index, index) -> !fir.shapeshift<2> +// CHECK: %[[VAL_16:.*]] = fir.array_coor %[[VAL_10]](%[[VAL_15]]) %[[VAL_1]], %[[VAL_0]] : (!fir.ref,i:i32}>>>, !fir.shapeshift<2>, index, index) -> !fir.ref,i:i32}>>