diff --git a/flang/lib/Optimizer/Dialect/FIROps.cpp b/flang/lib/Optimizer/Dialect/FIROps.cpp --- a/flang/lib/Optimizer/Dialect/FIROps.cpp +++ b/flang/lib/Optimizer/Dialect/FIROps.cpp @@ -2327,6 +2327,8 @@ inputEleTy.isa<fir::RecordType>() || outEleTy.isa<mlir::NoneType>() || (inputEleTy.isa<mlir::NoneType>() && outEleTy.isa<fir::RecordType>()) || (getSlice() && inputEleTy.isa<fir::CharacterType>()) || + (getSlice() && fir::isa_complex(inputEleTy) && + outEleTy.isa<mlir::FloatType>()) || areCompatibleCharacterTypes(inputEleTy, outEleTy); if (!typeCanMismatch) return emitOpError( diff --git a/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp b/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp --- a/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp +++ b/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp @@ -364,9 +364,6 @@ auto module = designate->getParentOfType<mlir::ModuleOp>(); fir::FirOpBuilder builder(rewriter, fir::getKindMapping(module)); - if (designate.getComplexPart()) - TODO(loc, "hlfir::designate with complex part"); - hlfir::Entity baseEntity(designate.getMemref()); if (baseEntity.isMutableBox()) @@ -377,6 +374,7 @@ auto [base, shape] = hlfir::genVariableFirBaseShapeAndParams( loc, builder, baseEntity, firBaseTypeParameters); mlir::Type baseEleTy = hlfir::getFortranElementType(base.getType()); + mlir::Type resultEleTy = hlfir::getFortranElementType(designateResultType); mlir::Value fieldIndex; if (designate.getComponent()) { @@ -428,12 +426,7 @@ if (fieldIndex && baseEntity.isArray()) { // array%scalar_comp or array%array_comp(indices) // Generate triples for array(:, :, ...). - auto one = builder.createIntegerConstant(loc, idxTy, 1); - for (auto [lb, ub] : hlfir::genBounds(loc, builder, baseEntity)) { - triples.push_back(builder.createConvert(loc, idxTy, lb)); - triples.push_back(builder.createConvert(loc, idxTy, ub)); - triples.push_back(one); - } + triples = genFullSliceTriples(builder, loc, baseEntity); sliceFields.push_back(fieldIndex); // Add indices in the field path for "array%array_comp(indices)" // case. @@ -464,7 +457,12 @@ builder.create<mlir::arith::SubIOp>(loc, substring[0], one); substring.push_back(designate.getTypeparams()[0]); } - + if (designate.getComplexPart()) { + if (triples.empty()) + triples = genFullSliceTriples(builder, loc, baseEntity); + sliceFields.push_back(builder.createIntegerConstant( + loc, idxTy, *designate.getComplexPart())); + } mlir::Value slice; if (!triples.empty()) slice = @@ -517,6 +515,16 @@ base = fir::factory::CharacterExprHelper{builder, loc}.genSubstringBase( base, designate.getSubstring()[0], resultAddressType); + // Scalar complex part ref + if (designate.getComplexPart()) { + // Sequence types should have already been handled by this point + assert(!designateResultType.isa<fir::SequenceType>()); + auto index = builder.createIntegerConstant(loc, builder.getIndexType(), + *designate.getComplexPart()); + auto coorTy = fir::ReferenceType::get(resultEleTy); + base = builder.create<fir::CoordinateOp>(loc, coorTy, base, index); + } + // Cast/embox the computed scalar address if needed. if (designateResultType.isa<fir::BoxCharType>()) { assert(designate.getTypeparams().size() == 1 && @@ -530,6 +538,24 @@ } return mlir::success(); } + +private: + // Generates triple for full slice + // Used for component and complex part slices when a triple is + // not specified + static llvm::SmallVector<mlir::Value> + genFullSliceTriples(fir::FirOpBuilder &builder, mlir::Location loc, + hlfir::Entity baseEntity) { + llvm::SmallVector<mlir::Value> triples; + mlir::Type idxTy = builder.getIndexType(); + auto one = builder.createIntegerConstant(loc, idxTy, 1); + for (auto [lb, ub] : hlfir::genBounds(loc, builder, baseEntity)) { + triples.push_back(builder.createConvert(loc, idxTy, lb)); + triples.push_back(builder.createConvert(loc, idxTy, ub)); + triples.push_back(one); + } + return triples; + } }; class ParentComponentOpConversion diff --git a/flang/test/Fir/rebox.fir b/flang/test/Fir/rebox.fir --- a/flang/test/Fir/rebox.fir +++ b/flang/test/Fir/rebox.fir @@ -133,6 +133,78 @@ } func.func private @bar_test_rebox_4(!fir.box<!fir.ptr<!fir.array<?x!fir.char<1,10>>>>) +// Testing complex part slice reboxing +// subroutine test_cmplx_2(a) +// complex :: a(:) +// call bar1(a%re) +// end subroutine + +// CHECK-LABEL: define void @test_cmplx_1( +// CHECK-SAME: ptr %[[INBOX:.*]]) +func.func @test_cmplx_1(%arg0: !fir.box<!fir.array<?x!fir.complex<4>>>) { + // CHECK: %[[OUTBOX_ALLOC:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] } + %c1 = arith.constant 1 : index + %c1_i32 = arith.constant 0 : i32 + %c0 = arith.constant 0 : index + %0:3 = fir.box_dims %arg0, %c0 : (!fir.box<!fir.array<?x!fir.complex<4>>>, index) -> (index, index, index) + %1 = fir.slice %c1, %0#1, %c1 path %c1_i32 : (index, index, index, i32) -> !fir.slice<1> + %2 = fir.rebox %arg0 [%1] : (!fir.box<!fir.array<?x!fir.complex<4>>>, !fir.slice<1>) -> !fir.box<!fir.array<?xf32>> + // CHECK: %[[INSTRIDE_0_GEP:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, ptr %[[INBOX]], i32 0, i32 7, i64 0, i32 1 + // CHECK: %[[INSTRIDE_0:.*]] = load i64, ptr %[[INSTRIDE_0_GEP]] + // CHECK: %[[INSTRIDE_1_GEP:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, ptr %[[INBOX]], i32 0, i32 7, i32 0, i32 2 + // CHECK: %[[INSTRIDE_1:.*]] = load i64, ptr %[[INSTRIDE_1_GEP]] + // CHECK: %[[FRONT_GEP:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, ptr %[[INBOX]], i32 0, i32 0 + // CHECK: %[[FRONT_PTR:.*]] = load ptr, ptr %[[FRONT_GEP]] + // CHECK: %[[FIELD_OFFSET_GEP:.*]] = getelementptr { float, float }, ptr %[[FRONT_PTR]], i64 0, i32 0 + // CHECK: %[[FRONT_OFFSET:.*]] = mul i64 0, %[[INSTRIDE_1]] + // CHECK: %[[OFFSET_GEP:.*]] = getelementptr i8, ptr %[[FIELD_OFFSET_GEP]], i64 %[[FRONT_OFFSET]] + // CHECK: %[[SUB_1:.*]] = sub i64 %[[INSTRIDE_0]], 1 + // CHECK: %[[ADD_1:.*]] = add i64 %[[SUB_1]], 1 + // CHECK: %[[DIV_1:.*]] = sdiv i64 %[[ADD_1]], 1 + // CHECK: %[[CHECK_NONZERO:.*]] = icmp sgt i64 %[[DIV_1]], 0 + // CHECK: %[[CHECKED_BOUND:.*]] = select i1 %[[CHECK_NONZERO]], i64 %[[DIV_1]], i64 0 + // CHECK: %[[STRIDE:.*]] = mul i64 1, %[[INSTRIDE_1]] + // CHECK: %[[VAL_BUILD_1:.*]] = insertvalue { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] } { ptr undef, i64 ptrtoint (ptr getelementptr (float, ptr null, i32 1) to i64), i32 {{.*}}, i8 1, i8 27, i8 0, i8 0, [1 x [3 x i64]] [{{\[}}3 x i64] [i64 1, i64 undef, i64 undef]] }, i64 %[[CHECKED_BOUND]], 7, 0, 1 + // CHECK: %[[VAL_BUILD_2:.*]] = insertvalue { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] } %[[VAL_BUILD_1]], i64 %[[STRIDE]], 7, 0, 2 + // CHECK: %[[VAL_BUILD_3:.*]] = insertvalue { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] } %[[VAL_BUILD_2]], ptr %[[OFFSET_GEP]], 0 + // CHECK: store { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] } %[[VAL_BUILD_3]], ptr %[[OUTBOX_ALLOC]] + fir.call @bar1(%2) : (!fir.box<!fir.array<?xf32>>) -> () + // CHECK: call void @bar1(ptr %[[OUTBOX_ALLOC]]) + return +} + +// Testing triple on complex part slice +// subroutine test_cmplx_2(a) +// complex :: a(:) +// call bar1(a(7:60:5)%im) +// end subroutine + +// CHECK-LABEL: define void @test_cmplx_2( +// CHECK-SAME: ptr %[[INBOX:.*]]) +func.func @test_cmplx_2(%arg0: !fir.box<!fir.array<?x!fir.complex<4>>>) { + // CHECK: %[[OUTBOX_ALLOC:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] } + %c7 = arith.constant 7 : index + %c5 = arith.constant 5 : index + %c60 = arith.constant 60 : index + %c1_i32 = arith.constant 1 : i32 + %0 = fir.slice %c7, %c60, %c5 path %c1_i32 : (index, index, index, i32) -> !fir.slice<1> + %1 = fir.rebox %arg0 [%0] : (!fir.box<!fir.array<?x!fir.complex<4>>>, !fir.slice<1>) -> !fir.box<!fir.array<11xf32>> + %2 = fir.convert %1 : (!fir.box<!fir.array<11xf32>>) -> !fir.box<!fir.array<?xf32>> + // CHECK: %[[INSTRIDE_0_GEP:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, ptr %[[INBOX]], i32 0, i32 7, i32 0, i32 2 + // CHECK: %[[INSTRIDE_0:.*]] = load i64, ptr %[[INSTRIDE_0_GEP]] + // CHECK: %[[FRONT_GEP:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, ptr %[[INBOX]], i32 0, i32 0 + // CHECK: %[[FRONT_PTR:.*]] = load ptr, ptr %[[FRONT_GEP]] + // CHECK: %[[FIELD_OFFSET_GEP:.*]] = getelementptr { float, float }, ptr %[[FRONT_PTR]], i64 0, i32 1 + // CHECK: %[[FRONT_OFFSET:.*]] = mul i64 6, %[[INSTRIDE_0]] + // CHECK: %[[OFFSET_GEP:.*]] = getelementptr i8, ptr %[[FIELD_OFFSET_GEP]], i64 %[[FRONT_OFFSET]] + // CHECK: %[[STRIDE:.*]] = mul i64 5, %[[INSTRIDE_0]] + // CHECK: %[[VAL_BUILD_1:.*]] = insertvalue { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] } { ptr undef, i64 ptrtoint (ptr getelementptr (float, ptr null, i32 1) to i64), i32 {{.*}}, i8 1, i8 27, i8 0, i8 0, [1 x [3 x i64]] [{{\[}}3 x i64] [i64 1, i64 11, i64 undef]] }, i64 %[[STRIDE]], 7, 0, 2 + // CHECK: %[[VAL_BUILD_2:.*]] = insertvalue { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] } %[[VAL_BUILD_1]], ptr %[[OFFSET_GEP]], 0 + // CHECK: store { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] } %[[VAL_BUILD_2]], ptr %[[OUTBOX_ALLOC]] + fir.call @bar1(%2) fastmath<contract> : (!fir.box<!fir.array<?xf32>>) -> () + // CHECK: call void @bar1(ptr %[[OUTBOX_ALLOC]]) + return +} // Test reboxing of unlimited polymorphic. diff --git a/flang/test/HLFIR/designate-codegen-complex-part.fir b/flang/test/HLFIR/designate-codegen-complex-part.fir new file mode 100644 --- /dev/null +++ b/flang/test/HLFIR/designate-codegen-complex-part.fir @@ -0,0 +1,83 @@ +// Test code generation to FIR of hlfir.designate operations +// with complex parts. +// RUN: fir-opt %s -convert-hlfir-to-fir | FileCheck %s + +func.func @test_set_scalar(%arg0: !fir.ref<!fir.complex<4>>, %arg1: !fir.ref<f32>) { + %0:2 = hlfir.declare %arg0 {uniq_name = "a"} : (!fir.ref<!fir.complex<4>>) -> (!fir.ref<!fir.complex<4>>, !fir.ref<!fir.complex<4>>) + %1:2 = hlfir.declare %arg1 {uniq_name = "b"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>) + %2 = fir.load %1#0 : !fir.ref<f32> + %3 = hlfir.designate %0#0 imag : (!fir.ref<!fir.complex<4>>) -> !fir.ref<f32> + hlfir.assign %2 to %3 : f32, !fir.ref<f32> + return +} +// CHECK-LABEL: func.func @test_set_scalar( +// CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<!fir.complex<4>>, %[[VAL_1:.*]]: !fir.ref<f32>) { +// CHECK: %[[VAL_2:.*]] = fir.declare %[[VAL_0]] {uniq_name = "a"} : (!fir.ref<!fir.complex<4>>) -> !fir.ref<!fir.complex<4>> +// CHECK: %[[VAL_3:.*]] = fir.declare %[[VAL_1]] {uniq_name = "b"} : (!fir.ref<f32>) -> !fir.ref<f32> +// CHECK: %[[VAL_4:.*]] = fir.load %[[VAL_3]] : !fir.ref<f32> +// CHECK: %[[VAL_5:.*]] = arith.constant 1 : index +// CHECK: %[[VAL_6:.*]] = fir.coordinate_of %[[VAL_2]], %[[VAL_5]] : (!fir.ref<!fir.complex<4>>, index) -> !fir.ref<f32> +// CHECK: fir.store %[[VAL_4]] to %[[VAL_6]] : !fir.ref<f32> + +func.func @test_scalar_at_index(%arg0: !fir.box<!fir.array<?x!fir.complex<4>>>, %arg1: !fir.ref<i32>) { + %0:2 = hlfir.declare %arg0 {uniq_name = "a"} : (!fir.box<!fir.array<?x!fir.complex<4>>>) -> (!fir.box<!fir.array<?x!fir.complex<4>>>, !fir.box<!fir.array<?x!fir.complex<4>>>) + %1:2 = hlfir.declare %arg1 {uniq_name = "b"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>) + %2 = fir.load %1#0 : !fir.ref<i32> + %3 = fir.convert %2 : (i32) -> i64 + %4 = hlfir.designate %0#0 (%3) real : (!fir.box<!fir.array<?x!fir.complex<4>>>, i64) -> !fir.ref<f32> + return +} +// CHECK-LABEL: func.func @test_scalar_at_index( +// CHECK-SAME: %[[VAL_0:.*]]: !fir.box<!fir.array<?x!fir.complex<4>>>, %[[VAL_1:.*]]: !fir.ref<i32>) { +// CHECK: %[[VAL_2:.*]] = fir.declare %[[VAL_0]] {uniq_name = "a"} : (!fir.box<!fir.array<?x!fir.complex<4>>>) -> !fir.box<!fir.array<?x!fir.complex<4>>> +// CHECK: %[[VAL_3:.*]] = fir.rebox %[[VAL_2]] : (!fir.box<!fir.array<?x!fir.complex<4>>>) -> !fir.box<!fir.array<?x!fir.complex<4>>> +// CHECK: %[[VAL_4:.*]] = fir.declare %[[VAL_1]] {uniq_name = "b"} : (!fir.ref<i32>) -> !fir.ref<i32> +// CHECK: %[[VAL_5:.*]] = fir.load %[[VAL_4]] : !fir.ref<i32> +// CHECK: %[[VAL_6:.*]] = fir.convert %[[VAL_5]] : (i32) -> i64 +// CHECK: %[[VAL_7:.*]] = fir.array_coor %[[VAL_2]] %[[VAL_6]] : (!fir.box<!fir.array<?x!fir.complex<4>>>, i64) -> !fir.ref<!fir.complex<4>> +// CHECK: %[[VAL_8:.*]] = arith.constant 0 : index +// CHECK: %[[VAL_9:.*]] = fir.coordinate_of %[[VAL_7]], %[[VAL_8]] : (!fir.ref<!fir.complex<4>>, index) -> !fir.ref<f32> + +func.func @test_complete_slice(%arg0: !fir.box<!fir.array<?x!fir.complex<4>>>) { + %c0 = arith.constant 0 : index + %0:2 = hlfir.declare %arg0 {uniq_name = "a"} : (!fir.box<!fir.array<?x!fir.complex<4>>>) -> (!fir.box<!fir.array<?x!fir.complex<4>>>, !fir.box<!fir.array<?x!fir.complex<4>>>) + %1:3 = fir.box_dims %0#0, %c0 : (!fir.box<!fir.array<?x!fir.complex<4>>>, index) -> (index, index, index) + %2 = fir.shape %1#1 : (index) -> !fir.shape<1> + %3 = hlfir.designate %0#0 imag shape %2 : (!fir.box<!fir.array<?x!fir.complex<4>>>, !fir.shape<1>) -> !fir.box<!fir.array<?xf32>> + return +} +// CHECK-LABEL: func.func @test_complete_slice( +// CHECK-SAME: %[[VAL_0:.*]]: !fir.box<!fir.array<?x!fir.complex<4>>>) { +// CHECK: %[[VAL_1:.*]] = arith.constant 0 : index +// CHECK: %[[VAL_2:.*]] = fir.declare %[[VAL_0]] {uniq_name = "a"} : (!fir.box<!fir.array<?x!fir.complex<4>>>) -> !fir.box<!fir.array<?x!fir.complex<4>>> +// CHECK: %[[VAL_3:.*]] = fir.rebox %[[VAL_2]] : (!fir.box<!fir.array<?x!fir.complex<4>>>) -> !fir.box<!fir.array<?x!fir.complex<4>>> +// CHECK: %[[VAL_4:.*]]:3 = fir.box_dims %[[VAL_3]], %[[VAL_1]] : (!fir.box<!fir.array<?x!fir.complex<4>>>, index) -> (index, index, index) +// CHECK: %[[VAL_5:.*]] = fir.shape %[[VAL_4]]#1 : (index) -> !fir.shape<1> +// CHECK: %[[VAL_6:.*]] = arith.constant 1 : index +// CHECK: %[[VAL_7:.*]] = arith.constant 1 : index +// CHECK: %[[VAL_8:.*]] = arith.constant 0 : index +// CHECK: %[[VAL_9:.*]]:3 = fir.box_dims %[[VAL_2]], %[[VAL_8]] : (!fir.box<!fir.array<?x!fir.complex<4>>>, index) -> (index, index, index) +// CHECK: %[[VAL_10:.*]] = arith.constant 1 : index +// CHECK: %[[VAL_11:.*]] = fir.slice %[[VAL_7]], %[[VAL_9]]#1, %[[VAL_6]] path %[[VAL_10]] : (index, index, index, index) -> !fir.slice<1> +// CHECK: %[[VAL_12:.*]] = fir.rebox %[[VAL_2]] [%[[VAL_11]]] : (!fir.box<!fir.array<?x!fir.complex<4>>>, !fir.slice<1>) -> !fir.box<!fir.array<?xf32>> + +func.func @test_slice_steps(%arg0: !fir.box<!fir.array<?x!fir.complex<4>>>) { + %c3 = arith.constant 3 : index + %c12 = arith.constant 12 : index + %c4 = arith.constant 4 : index + %0:2 = hlfir.declare %arg0 {uniq_name = "a"} : (!fir.box<!fir.array<?x!fir.complex<4>>>) -> (!fir.box<!fir.array<?x!fir.complex<4>>>, !fir.box<!fir.array<?x!fir.complex<4>>>) + %1 = fir.shape %c3 : (index) -> !fir.shape<1> + %2 = hlfir.designate %0#0 (%c4:%c12:%c3) real shape %1 : (!fir.box<!fir.array<?x!fir.complex<4>>>, index, index, index, !fir.shape<1>) -> !fir.box<!fir.array<3xf32>> + return +} +// CHECK-LABEL: func.func @test_slice_steps( +// CHECK-SAME: %[[VAL_0:.*]]: !fir.box<!fir.array<?x!fir.complex<4>>>) { +// CHECK: %[[VAL_1:.*]] = arith.constant 3 : index +// CHECK: %[[VAL_2:.*]] = arith.constant 12 : index +// CHECK: %[[VAL_3:.*]] = arith.constant 4 : index +// CHECK: %[[VAL_4:.*]] = fir.declare %[[VAL_0]] {uniq_name = "a"} : (!fir.box<!fir.array<?x!fir.complex<4>>>) -> !fir.box<!fir.array<?x!fir.complex<4>>> +// CHECK: %[[VAL_5:.*]] = fir.rebox %[[VAL_4]] : (!fir.box<!fir.array<?x!fir.complex<4>>>) -> !fir.box<!fir.array<?x!fir.complex<4>>> +// CHECK: %[[VAL_6:.*]] = fir.shape %[[VAL_1]] : (index) -> !fir.shape<1> +// CHECK: %[[VAL_7:.*]] = arith.constant 0 : index +// CHECK: %[[VAL_8:.*]] = fir.slice %[[VAL_3]], %[[VAL_2]], %[[VAL_1]] path %[[VAL_7]] : (index, index, index, index) -> !fir.slice<1> +// CHECK: %[[VAL_9:.*]] = fir.rebox %[[VAL_4]] [%[[VAL_8]]] : (!fir.box<!fir.array<?x!fir.complex<4>>>, !fir.slice<1>) -> !fir.box<!fir.array<3xf32>>