[flang-commits] [flang] 0919721 - [flang][MIF] Fix COSHAPE and THIS_IMAGE(coarray) type mismatch for non-i64 kinds (#208429)
via flang-commits
flang-commits at lists.llvm.org
Thu Jul 9 09:49:13 PDT 2026
Author: Kareem Ergawy
Date: 2026-07-09T18:49:08+02:00
New Revision: 09197218036b30cd36a490191e84f0aabd523a8d
URL: https://github.com/llvm/llvm-project/commit/09197218036b30cd36a490191e84f0aabd523a8d
DIFF: https://github.com/llvm/llvm-project/commit/09197218036b30cd36a490191e84f0aabd523a8d.diff
LOG: [flang][MIF] Fix COSHAPE and THIS_IMAGE(coarray) type mismatch for non-i64 kinds (#208429)
Both COSHAPE and THIS_IMAGE(coarray [,team]) return integer arrays whose
element type is determined by the Fortran KIND argument (default: i32).
The lowering code was ignoring resultType in both cases and hardcoding
i64, which caused downstream type mismatches:
- COSHAPE: SimplifyHLFIRIntrinsics assertion in PRODUCT(COSHAPE(y)) when
the product input type (i64) did not match the declared result type
(i32).
- THIS_IMAGE(coarray): MLIR verifier error on arith.cmpi with mismatched
operand types (i64 vs i32) in comparisons like THIS_IMAGE(a) /=
[5,0,-7].
Fix: derive eleTy from resultType in both genCoshape and genThisImage
and propagate it into the mif.* op's result type. In MIFOpConversion,
extract a shared convertI64SeqToEleTy helper that post-converts the i64
scratch buffer written by the PRIF runtime into the
declared-element-type buffer when the two types differ. Both
MIFCoshapeOpConversion and MIFThisImageOpConversion call this helper.
Co-authored-by: Claude Opus 4.7 <noreply at anthropic.com>
Added:
Modified:
flang/lib/Optimizer/Builder/IntrinsicCall.cpp
flang/lib/Optimizer/Transforms/MIFOpConversion.cpp
flang/test/Fir/MIF/coshape.mlir
flang/test/Fir/MIF/this_image.mlir
flang/test/Lower/MIF/coshape.f90
flang/test/Lower/MIF/this_image.f90
Removed:
################################################################################
diff --git a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
index bff561064bc70..2fe81d63f8e49 100644
--- a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
+++ b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
@@ -3602,13 +3602,19 @@ mlir::Value IntrinsicLibrary::genCospi(mlir::Type resultType,
// COSHAPE
fir::ExtendedValue
-IntrinsicLibrary::genCoshape(mlir::Type,
+IntrinsicLibrary::genCoshape(mlir::Type resultType,
llvm::ArrayRef<fir::ExtendedValue> args) {
checkCoarrayEnabled(loc, options);
assert(args.size() == 2);
- return mif::CoshapeOp::create(builder, loc,
- /*coarray*/ fir::getBase(args[0]));
+ // Use the declared Fortran element type (e.g. i32 for default integer kind)
+ // rather than hardcoding i64. MIFCoshapeOpConversion converts the i64 values
+ // written by the prif_coshape runtime to the declared type.
+ mlir::Type eleTy = hlfir::getFortranElementType(resultType);
+ mlir::Type coshapeResultTy = fir::BoxType::get(
+ fir::SequenceType::get({fir::SequenceType::getUnknownExtent()}, eleTy));
+ return mif::CoshapeOp::create(builder, loc, coshapeResultTy,
+ fir::getBase(args[0]));
}
// COUNT
@@ -8349,9 +8355,12 @@ IntrinsicLibrary::genThisImage(mlir::Type resultType,
mlir::Value team = fir::getBase(args[args.size() - 1]);
if (!coarrayIsAbsent && dimIsAbsent) {
- mlir::Value res =
- mif::ThisImageOp::create(builder, loc, fir::getBase(args[0]), team);
- return res;
+ mlir::Type eleTy = hlfir::getFortranElementType(resultType);
+ mlir::Type thisImageResultTy = fir::BoxType::get(
+ fir::SequenceType::get({fir::SequenceType::getUnknownExtent()}, eleTy));
+ return mif::ThisImageOp::create(builder, loc, thisImageResultTy,
+ fir::getBase(args[0]),
+ /*dim=*/mlir::Value{}, team);
}
mlir::Value res;
if (!dimIsAbsent) {
diff --git a/flang/lib/Optimizer/Transforms/MIFOpConversion.cpp b/flang/lib/Optimizer/Transforms/MIFOpConversion.cpp
index 24dfbf4a9ef02..1ceac427818df 100644
--- a/flang/lib/Optimizer/Transforms/MIFOpConversion.cpp
+++ b/flang/lib/Optimizer/Transforms/MIFOpConversion.cpp
@@ -419,6 +419,43 @@ struct MIFInitOpConversion : public mlir::OpRewritePattern<mif::InitOp> {
}
};
+/// After a PRIF call that always writes i64 cosubscripts into a sequence
+/// buffer, convert the buffer to the declared Fortran element type when it
+/// is narrower than i64. Returns \p i64Result unchanged when eleTy == i64Ty;
+/// otherwise allocates a typed buffer, copies with element-wise conversion,
+/// and returns the result widened to \p declaredBoxTy.
+static mlir::Value convertI64SeqToEleTy(fir::FirOpBuilder &builder,
+ mlir::Location loc,
+ mlir::Value i64Result, mlir::Type i64Ty,
+ mlir::Type eleTy, std::int64_t corank,
+ mlir::Type declaredBoxTy) {
+ if (eleTy == i64Ty)
+ return i64Result;
+ mlir::Value i64Buf = fir::BoxAddrOp::create(
+ builder, loc,
+ builder.getRefType(
+ mlir::cast<fir::BoxType>(i64Result.getType()).getEleTy()),
+ i64Result);
+ mlir::Type declaredSeqType = fir::SequenceType::get(
+ static_cast<fir::SequenceType::Extent>(corank), eleTy);
+ mlir::Value declaredBuf = builder.createTemporary(loc, declaredSeqType);
+ mlir::Type indexTy = builder.getIndexType();
+ mlir::Type i64RefTy = builder.getRefType(i64Ty);
+ mlir::Type eleRefTy = builder.getRefType(eleTy);
+ for (std::int64_t i = 0; i < corank; ++i) {
+ mlir::Value idx = builder.createIntegerConstant(loc, indexTy, i);
+ mlir::Value srcAddr =
+ fir::CoordinateOp::create(builder, loc, i64RefTy, i64Buf, idx);
+ mlir::Value i64Val = fir::LoadOp::create(builder, loc, srcAddr);
+ mlir::Value eleVal = builder.createConvert(loc, eleTy, i64Val);
+ mlir::Value dstAddr =
+ fir::CoordinateOp::create(builder, loc, eleRefTy, declaredBuf, idx);
+ fir::StoreOp::create(builder, loc, eleVal, dstAddr);
+ }
+ mlir::Value result = builder.createBox(loc, declaredBuf);
+ return fir::ConvertOp::create(builder, loc, declaredBoxTy, result);
+}
+
/// Convert mif.this_image operation to PRIF runtime call
struct MIFThisImageOpConversion
: public mlir::OpRewritePattern<mif::ThisImageOp> {
@@ -481,6 +518,10 @@ struct MIFThisImageOpConversion
fir::CallOp::create(builder, loc, funcOp, args);
result = fir::ConvertOp::create(builder, loc,
genBoxedSequenceType(i64Ty), result);
+ auto boxResultTy = mlir::cast<fir::BoxType>(op.getResult().getType());
+ mlir::Type eleTy = fir::unwrapSequenceType(boxResultTy.getEleTy());
+ result = convertI64SeqToEleTy(builder, loc, result, i64Ty, eleTy,
+ corank, op.getResult().getType());
}
rewriter.replaceOp(op, result);
} else {
@@ -1190,6 +1231,11 @@ struct MIFCoshapeOpConversion : public mlir::OpRewritePattern<mif::CoshapeOp> {
fir::CallOp::create(builder, loc, funcOp, args);
result = fir::ConvertOp::create(builder, loc, genBoxedSequenceType(i64Ty),
result);
+
+ auto boxResultTy = mlir::cast<fir::BoxType>(op.getResult().getType());
+ mlir::Type eleTy = fir::unwrapSequenceType(boxResultTy.getEleTy());
+ result = convertI64SeqToEleTy(builder, loc, result, i64Ty, eleTy, corank,
+ op.getResult().getType());
rewriter.replaceOp(op, result);
return mlir::success();
}
diff --git a/flang/test/Fir/MIF/coshape.mlir b/flang/test/Fir/MIF/coshape.mlir
index 849a3048d8810..47d46ddb44566 100644
--- a/flang/test/Fir/MIF/coshape.mlir
+++ b/flang/test/Fir/MIF/coshape.mlir
@@ -73,8 +73,62 @@ module attributes {dlti.dl_spec = #dlti.dl_spec<!llvm.ptr<270> = dense<32> : vec
hlfir.destroy %28 : !hlfir.expr<?xi64>
return
}
+
+ // Test that MIFCoshapeOpConversion emits an element-wise i64→i32 conversion
+ // loop when the declared element type
diff ers from the i64 written by
+ // prif_coshape. Models `integer :: c[5,*]` (corank:2, default kind = i32).
+ func.func @test_coshape_i32() {
+ %c1_i64 = arith.constant 1 : i64
+ %c5_i64 = arith.constant 5 : i64
+ %c0 = arith.constant 0 : index
+ %c1 = arith.constant 1 : index
+ %lc = fir.alloca !fir.array<2xi64>
+ %uc = fir.alloca !fir.array<1xi64>
+ %lc0 = fir.coordinate_of %lc, %c0 : (!fir.ref<!fir.array<2xi64>>, index) -> !fir.ref<i64>
+ fir.store %c1_i64 to %lc0 : !fir.ref<i64>
+ %lc1 = fir.coordinate_of %lc, %c1 : (!fir.ref<!fir.array<2xi64>>, index) -> !fir.ref<i64>
+ fir.store %c1_i64 to %lc1 : !fir.ref<i64>
+ %uc0 = fir.coordinate_of %uc, %c0 : (!fir.ref<!fir.array<1xi64>>, index) -> !fir.ref<i64>
+ fir.store %c5_i64 to %uc0 : !fir.ref<i64>
+ %lb = fir.embox %lc : (!fir.ref<!fir.array<2xi64>>) -> !fir.box<!fir.array<2xi64>>
+ %ub = fir.embox %uc : (!fir.ref<!fir.array<1xi64>>) -> !fir.box<!fir.array<1xi64>>
+ %c_ref = fir.address_of(@_QFEc) : !fir.ref<i32>
+ mif.alloc_coarray %c_ref lcobounds %lb ucobounds %ub {uniq_name = "_QFEc"} : (!fir.ref<i32>, !fir.box<!fir.array<2xi64>>, !fir.box<!fir.array<1xi64>>) -> ()
+ %c_decl:2 = hlfir.declare %c_ref {uniq_name = "_QFEc"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+ %cobox = fir.embox %c_decl#0 : (!fir.ref<i32>) -> !fir.box<i32, corank:2>
+ %res = mif.coshape coarray %cobox : (!fir.box<i32, corank:2>) -> !fir.box<!fir.array<?xi32>>
+ return
+ }
}
// CHECK-LABEL: func.func @_QQmain
// CHECK: fir.call @_QMprifPprif_coshape
// CHECK: fir.call @_QMprifPprif_coshape
+
+// CHECK-LABEL: func.func @test_coshape_i32
+// i32 and i64 scratch buffers are hoisted to the function entry block.
+// CHECK-DAG: %[[I32BUF:.*]] = fir.alloca !fir.array<2xi32>
+// CHECK-DAG: %[[I64BUF:.*]] = fir.alloca !fir.array<2xi64>
+// prif_coshape writes i64 values into the i64 buffer.
+// CHECK: fir.call @_QMprifPprif_coshape
+// After the call, `result` is converted to a dynamic-extent i64 box and
+// then its base pointer is extracted for the per-element copy loop.
+// CHECK: %[[I64BOX:.*]] = fir.convert {{.*}} : (!fir.box<!fir.array<2xi64>>) -> !fir.box<!fir.array<?xi64>>
+// CHECK: %[[I64BUFREF:.*]] = fir.box_addr %[[I64BOX]] : (!fir.box<!fir.array<?xi64>>) -> !fir.ref<!fir.array<?xi64>>
+// Loop iteration 0: load i64, truncate to i32, store into i32 buffer.
+// CHECK: %[[C0:.*]] = arith.constant 0 : index
+// CHECK: %[[SRC0:.*]] = fir.coordinate_of %[[I64BUFREF]], %[[C0]] : (!fir.ref<!fir.array<?xi64>>, index) -> !fir.ref<i64>
+// CHECK: %[[VAL0:.*]] = fir.load %[[SRC0]] : !fir.ref<i64>
+// CHECK: %[[CONV0:.*]] = fir.convert %[[VAL0]] : (i64) -> i32
+// CHECK: %[[DST0:.*]] = fir.coordinate_of %[[I32BUF]], %[[C0]] : (!fir.ref<!fir.array<2xi32>>, index) -> !fir.ref<i32>
+// CHECK: fir.store %[[CONV0]] to %[[DST0]] : !fir.ref<i32>
+// Loop iteration 1: same pattern for the second codimension.
+// CHECK: %[[C1:.*]] = arith.constant 1 : index
+// CHECK: %[[SRC1:.*]] = fir.coordinate_of %[[I64BUFREF]], %[[C1]] : (!fir.ref<!fir.array<?xi64>>, index) -> !fir.ref<i64>
+// CHECK: %[[VAL1:.*]] = fir.load %[[SRC1]] : !fir.ref<i64>
+// CHECK: %[[CONV1:.*]] = fir.convert %[[VAL1]] : (i64) -> i32
+// CHECK: %[[DST1:.*]] = fir.coordinate_of %[[I32BUF]], %[[C1]] : (!fir.ref<!fir.array<2xi32>>, index) -> !fir.ref<i32>
+// CHECK: fir.store %[[CONV1]] to %[[DST1]] : !fir.ref<i32>
+// The i32 buffer is boxed and widened to a dynamic-extent result.
+// CHECK: %[[BOX_I32:.*]] = fir.embox %[[I32BUF]] : (!fir.ref<!fir.array<2xi32>>) -> !fir.box<!fir.array<2xi32>>
+// CHECK: fir.convert %[[BOX_I32]] : (!fir.box<!fir.array<2xi32>>) -> !fir.box<!fir.array<?xi32>>
diff --git a/flang/test/Fir/MIF/this_image.mlir b/flang/test/Fir/MIF/this_image.mlir
index d97e2466ce54a..4af6d6cc0d983 100644
--- a/flang/test/Fir/MIF/this_image.mlir
+++ b/flang/test/Fir/MIF/this_image.mlir
@@ -61,7 +61,61 @@
return
}
+ // Test that MIFThisImageOpConversion emits an element-wise i64→i32
+ // conversion loop when the declared element type
diff ers from the i64
+ // written by prif_this_image_with_coarray. Models `integer :: a[2,*]`
+ // (corank:2, default kind = i32).
+ func.func @test_this_image_i32() {
+ %c1_i64 = arith.constant 1 : i64
+ %c2_i64 = arith.constant 2 : i64
+ %c0 = arith.constant 0 : index
+ %c1 = arith.constant 1 : index
+ %lc = fir.alloca !fir.array<2xi64>
+ %uc = fir.alloca !fir.array<1xi64>
+ %lc0 = fir.coordinate_of %lc, %c0 : (!fir.ref<!fir.array<2xi64>>, index) -> !fir.ref<i64>
+ fir.store %c1_i64 to %lc0 : !fir.ref<i64>
+ %lc1 = fir.coordinate_of %lc, %c1 : (!fir.ref<!fir.array<2xi64>>, index) -> !fir.ref<i64>
+ fir.store %c1_i64 to %lc1 : !fir.ref<i64>
+ %uc0 = fir.coordinate_of %uc, %c0 : (!fir.ref<!fir.array<1xi64>>, index) -> !fir.ref<i64>
+ fir.store %c2_i64 to %uc0 : !fir.ref<i64>
+ %lb = fir.embox %lc : (!fir.ref<!fir.array<2xi64>>) -> !fir.box<!fir.array<2xi64>>
+ %ub = fir.embox %uc : (!fir.ref<!fir.array<1xi64>>) -> !fir.box<!fir.array<1xi64>>
+ %a_ref = fir.address_of(@_QFEa2) : !fir.ref<i32>
+ mif.alloc_coarray %a_ref lcobounds %lb ucobounds %ub {uniq_name = "_QFEa2"} : (!fir.ref<i32>, !fir.box<!fir.array<2xi64>>, !fir.box<!fir.array<1xi64>>) -> ()
+ %a_decl:2 = hlfir.declare %a_ref {uniq_name = "_QFEa2"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+ %cobox = fir.embox %a_decl#0 : (!fir.ref<i32>) -> !fir.box<i32, corank:2>
+ %res = mif.this_image coarray %cobox : (!fir.box<i32, corank:2>) -> !fir.box<!fir.array<?xi32>>
+ return
+ }
+
// CHECK-LABEL: func.func @_QQmain
// CHECK: fir.call @_QMprifPprif_this_image_no_coarray
// CHECK: fir.call @_QMprifPprif_this_image_with_coarray
// CHECK: fir.call @_QMprifPprif_this_image_with_dim
+
+// CHECK-LABEL: func.func @test_this_image_i32
+// i32 and i64 scratch buffers are hoisted to the function entry block.
+// CHECK-DAG: %[[I32BUF:.*]] = fir.alloca !fir.array<2xi32>
+// CHECK-DAG: %[[I64BUF:.*]] = fir.alloca !fir.array<2xi64>
+// prif_this_image_with_coarray writes i64 values into the i64 buffer.
+// CHECK: fir.call @_QMprifPprif_this_image_with_coarray
+// After the call the i64 box is widened and its base pointer extracted.
+// CHECK: %[[I64BOX:.*]] = fir.convert {{.*}} : (!fir.box<!fir.array<2xi64>>) -> !fir.box<!fir.array<?xi64>>
+// CHECK: %[[I64BUFREF:.*]] = fir.box_addr %[[I64BOX]] : (!fir.box<!fir.array<?xi64>>) -> !fir.ref<!fir.array<?xi64>>
+// Loop iteration 0: load i64, truncate to i32, store into i32 buffer.
+// CHECK: %[[C0:.*]] = arith.constant 0 : index
+// CHECK: %[[SRC0:.*]] = fir.coordinate_of %[[I64BUFREF]], %[[C0]] : (!fir.ref<!fir.array<?xi64>>, index) -> !fir.ref<i64>
+// CHECK: %[[VAL0:.*]] = fir.load %[[SRC0]] : !fir.ref<i64>
+// CHECK: %[[CONV0:.*]] = fir.convert %[[VAL0]] : (i64) -> i32
+// CHECK: %[[DST0:.*]] = fir.coordinate_of %[[I32BUF]], %[[C0]] : (!fir.ref<!fir.array<2xi32>>, index) -> !fir.ref<i32>
+// CHECK: fir.store %[[CONV0]] to %[[DST0]] : !fir.ref<i32>
+// Loop iteration 1: same pattern for the second codimension.
+// CHECK: %[[C1:.*]] = arith.constant 1 : index
+// CHECK: %[[SRC1:.*]] = fir.coordinate_of %[[I64BUFREF]], %[[C1]] : (!fir.ref<!fir.array<?xi64>>, index) -> !fir.ref<i64>
+// CHECK: %[[VAL1:.*]] = fir.load %[[SRC1]] : !fir.ref<i64>
+// CHECK: %[[CONV1:.*]] = fir.convert %[[VAL1]] : (i64) -> i32
+// CHECK: %[[DST1:.*]] = fir.coordinate_of %[[I32BUF]], %[[C1]] : (!fir.ref<!fir.array<2xi32>>, index) -> !fir.ref<i32>
+// CHECK: fir.store %[[CONV1]] to %[[DST1]] : !fir.ref<i32>
+// The i32 buffer is boxed and widened to a dynamic-extent result.
+// CHECK: %[[BOX_I32:.*]] = fir.embox %[[I32BUF]] : (!fir.ref<!fir.array<2xi32>>) -> !fir.box<!fir.array<2xi32>>
+// CHECK: fir.convert %[[BOX_I32]] : (!fir.box<!fir.array<2xi32>>) -> !fir.box<!fir.array<?xi32>>
diff --git a/flang/test/Lower/MIF/coshape.f90 b/flang/test/Lower/MIF/coshape.f90
index 2cf6d50f084a0..c7ba488bf70dd 100644
--- a/flang/test/Lower/MIF/coshape.f90
+++ b/flang/test/Lower/MIF/coshape.f90
@@ -3,12 +3,19 @@
program test
integer :: res(3)
integer(kind=8) :: res2(3)
+ integer :: res3(3)
integer :: a[2,3:5,*]
- ! CHECK: mif.coshape coarray %[[COARRAY:.*]] : (!fir.box<i32, corank:3>) -> !fir.box<!fir.array<?xi64>>
+ ! COSHAPE without KIND returns default integer kind (4 = i32).
+ ! CHECK: mif.coshape coarray %[[COARRAY:.*]] : (!fir.box<i32, corank:3>) -> !fir.box<!fir.array<?xi32>>
res = coshape(a)
- ! CHECK: mif.coshape coarray %[[COARRAY:.*]] : (!fir.box<i32, corank:3>) -> !fir.box<!fir.array<?xi64>>
+ ! Assignment to integer(kind=8) widens; COSHAPE result type is still i32.
+ ! CHECK: mif.coshape coarray %[[COARRAY:.*]] : (!fir.box<i32, corank:3>) -> !fir.box<!fir.array<?xi32>>
res2 = coshape(a)
+ ! Explicit KIND=8 yields i64 elements.
+ ! CHECK: mif.coshape coarray %[[COARRAY:.*]] : (!fir.box<i32, corank:3>) -> !fir.box<!fir.array<?xi64>>
+ res3 = coshape(a, kind=8)
+
end program
diff --git a/flang/test/Lower/MIF/this_image.f90 b/flang/test/Lower/MIF/this_image.f90
index 95d9ab1dedd39..b026300876b7b 100644
--- a/flang/test/Lower/MIF/this_image.f90
+++ b/flang/test/Lower/MIF/this_image.f90
@@ -12,7 +12,7 @@ program test
! CHECK: mif.this_image team %[[TEAM:.*]] : ({{.*}}) -> i32
i = this_image(TEAM=team)
- ! CHECK: mif.this_image coarray %[[A:.*]] : (!fir.box<i32, corank:2>) -> !fir.box<!fir.array<?xi64>>
+ ! CHECK: mif.this_image coarray %[[A:.*]] : (!fir.box<i32, corank:2>) -> !fir.box<!fir.array<?xi32>>
j = this_image(COARRAY=a)
! CHECK: mif.this_image coarray %[[A:.*]] dim %[[DIM:.*]] : (!fir.box<i32, corank:2>, i32) -> i64
More information about the flang-commits
mailing list