[flang-commits] [flang] e1dd984 - [flang][FIRToMemRef] fix stride calculation for complex lowering (#200035)
via flang-commits
flang-commits at lists.llvm.org
Wed May 27 14:48:06 PDT 2026
Author: Susan Tan (ス-ザン タン)
Date: 2026-05-27T17:48:01-04:00
New Revision: e1dd984a809c9c7b8cc3731e3b8eeb8d01fbc8c1
URL: https://github.com/llvm/llvm-project/commit/e1dd984a809c9c7b8cc3731e3b8eeb8d01fbc8c1
DIFF: https://github.com/llvm/llvm-project/commit/e1dd984a809c9c7b8cc3731e3b8eeb8d01fbc8c1.diff
LOG: [flang][FIRToMemRef] fix stride calculation for complex lowering (#200035)
**Summary**
When `fir.array_coor` targets a projected slice of a complex array (path
0 = real, 1 = imag), FIRToMemRef must not treat the result as a dense
memref.
**Bug:** The pass stopped after fir.convert to `memref<…×complex>` (or
static-shape fast path) and used default/dense strides. Loads/stores
then stepped by sizeof(complex) instead of sizeof(re)/sizeof(im).
**Fix:** For constant `%re/%im` on `complex<T>` storage:
`fir.convert` storage to `memref<…×2×T>` and index the component (0 or
1).
Read layout from `fir.box_dims` on the box (even if the memref shape is
static).
Set each memref stride to `box_dims_byte_stride / sizeof(T)`.
Advised by Cursor
Added:
Modified:
flang/lib/Optimizer/Transforms/FIRToMemRef.cpp
flang/test/Transforms/FIRToMemRef/slice-projected.mlir
Removed:
################################################################################
diff --git a/flang/lib/Optimizer/Transforms/FIRToMemRef.cpp b/flang/lib/Optimizer/Transforms/FIRToMemRef.cpp
index f679f01bc3241..26289c388fd3e 100644
--- a/flang/lib/Optimizer/Transforms/FIRToMemRef.cpp
+++ b/flang/lib/Optimizer/Transforms/FIRToMemRef.cpp
@@ -655,7 +655,6 @@ FIRToMemRef::convertArrayCoorOp(Operation *memOp, fir::ArrayCoorOp arrayCoorOp,
Value convertedVal = *converted;
MemRefType memRefTy = dyn_cast<MemRefType>(convertedVal.getType());
- bool isRebox = firMemref.getDefiningOp<fir::ReboxOp>() != nullptr;
bool isDescriptor = mlir::isa<fir::BaseBoxType>(firMemref.getType()) ||
firMemref.getDefiningOp<fir::BoxAddrOp>() != nullptr;
@@ -669,6 +668,7 @@ FIRToMemRef::convertArrayCoorOp(Operation *memOp, fir::ArrayCoorOp arrayCoorOp,
else if (auto rebox = firMemref.getDefiningOp<fir::ReboxOp>())
collectSliceInfoFrom(rebox, sliceInfo);
auto srcTy = cast<MemRefType>((*converted).getType());
+ std::optional<int64_t> complexPartIdx;
if (sliceInfo.hasProjectedSlice) {
if (auto complexTy = dyn_cast<mlir::ComplexType>(srcTy.getElementType())) {
if (!sliceInfo.projectedSliceStart ||
@@ -680,24 +680,25 @@ FIRToMemRef::convertArrayCoorOp(Operation *memOp, fir::ArrayCoorOp arrayCoorOp,
"0 (real) or 1 (imaginary), bailing out of conversion\n");
return failure();
}
- auto projection = *sliceInfo.projectedSliceStart;
+ complexPartIdx = *sliceInfo.projectedSliceStart;
SmallVector<int64_t> shape(srcTy.getShape());
shape.push_back(2);
- Value compMemref =
+ convertedVal =
fir::ConvertOp::create(
rewriter, loc, MemRefType::get(shape, complexTy.getElementType()),
*converted)
.getResult();
+ memRefTy = cast<MemRefType>(convertedVal.getType());
indices.push_back(
- arith::ConstantIndexOp::create(rewriter, loc, projection));
- return std::pair{compMemref, indices};
+ arith::ConstantIndexOp::create(rewriter, loc, *complexPartIdx));
}
}
// Static shape does not imply contiguous layout for descriptor-backed
- // entities (e.g. boxed array sections with non-unit stride). Keep the
- // reinterpret-cast path so descriptor strides are preserved.
- if (memRefTy.hasStaticShape() && !isRebox && !isDescriptor)
+ // entities (e.g. boxed array sections with non-unit stride). Projected
+ // complex %re/%im also need reinterpret_cast even when the converted type
+ // is statically shaped (e.g. memref<Nx2xT>).
+ if (!complexPartIdx && memRefTy.hasStaticShape() && !isDescriptor)
return std::pair{*converted, indices};
unsigned rank = arrayCoorOp.getIndices().size();
@@ -736,11 +737,14 @@ FIRToMemRef::convertArrayCoorOp(Operation *memOp, fir::ArrayCoorOp arrayCoorOp,
shapeVec.empty() ||
(firMemrefIsBox && !firMemrefIsEmbox);
if (descriptorOwnsLayout) {
- // Rebuild the MemRef view from descriptor metadata instead of from slice
- // triplets. Reached only when firMemref is a fir.box value (case b/c), or
- // for projected slices (case a) where the source remains the box.
- auto boxElementSize =
- fir::BoxEleSizeOp::create(rewriter, loc, indexTy, firMemref);
+ // Complex %re/%im: memref_stride = box_dims_byte_stride / sizeof(T),
+ Value boxElementSize =
+ complexPartIdx
+ ? arith::ConstantIndexOp::create(
+ rewriter, loc,
+ memRefTy.getElementType().getIntOrFloatBitWidth() / 8)
+ : fir::BoxEleSizeOp::create(rewriter, loc, indexTy, firMemref)
+ .getResult();
for (unsigned i = 0; i < rank; ++i) {
Value dim = arith::ConstantIndexOp::create(rewriter, loc, rank - i - 1);
@@ -779,7 +783,11 @@ FIRToMemRef::convertArrayCoorOp(Operation *memOp, fir::ArrayCoorOp arrayCoorOp,
strides.push_back(oneIdx);
}
- assert(strides.size() == sizes.size() && sizes.size() == rank);
+ if (complexPartIdx) {
+ sizes.push_back(arith::ConstantIndexOp::create(rewriter, loc, 2));
+ strides.push_back(arith::ConstantIndexOp::create(rewriter, loc, 1));
+ ++rank;
+ }
int64_t dynamicOffset = ShapedType::kDynamic;
SmallVector<int64_t> dynamicStrides(rank, ShapedType::kDynamic);
@@ -793,7 +801,7 @@ FIRToMemRef::convertArrayCoorOp(Operation *memOp, fir::ArrayCoorOp arrayCoorOp,
Value offset = arith::ConstantIndexOp::create(rewriter, loc, 0);
auto reinterpret = memref::ReinterpretCastOp::create(
- rewriter, loc, memRefTy, *converted, offset, sizes, strides);
+ rewriter, loc, memRefTy, convertedVal, offset, sizes, strides);
Value result = reinterpret->getResult(0);
return std::pair{result, indices};
diff --git a/flang/test/Transforms/FIRToMemRef/slice-projected.mlir b/flang/test/Transforms/FIRToMemRef/slice-projected.mlir
index 17af59086122c..920b0b2185d45 100644
--- a/flang/test/Transforms/FIRToMemRef/slice-projected.mlir
+++ b/flang/test/Transforms/FIRToMemRef/slice-projected.mlir
@@ -1,10 +1,15 @@
// RUN: fir-opt %s --fir-to-memref --allow-unregistered-dialect | FileCheck %s
// Tests for fir.slice with a path component (projected component slice).
-// A projected slice changes the element type of the boxed view, e.g.
-// z%re projects complex<f32> -> f32. The pass bypasses the box descriptor
-// and reinterprets the underlying complex array as memref<...x2xf32>, then
-// appends the component index (0=re, 1=im) as the final memref index.
+// A projected slice changes the logical element type of the boxed view, e.g.
+// z%re maps complex<f32> -> f32 in the box type.
+//
+// FIRToMemRef only lowers array_coor through this path when storage is
+// complex<T> and the slice path is constant 0 (%re) or 1 (%im). It then
+// fir.convert's storage to memref<...x2xT>, appends that component index,
+// and memref.reinterpret_cast's a strided memref<...xT> using fir.box_dims
+// byte strides divided by sizeof(T) (not sizeof(complex<T>) from box_elesize).
+// Derived-type component projections (e.g. a%x) are left for FIR codegen.
//
// Derived from:
// complex, target :: z(4) = 0.
@@ -23,9 +28,23 @@
// CHECK: fir.do_loop [[I:%.*]] =
// CHECK: [[MEMREF:%.*]] = fir.convert %arg0 : (!fir.ref<!fir.array<4xcomplex<f32>>>) -> memref<4xcomplex<f32>>
// CHECK: [[IDX:%.*]] = arith.addi
-// CHECK: [[COMP:%.*]] = fir.convert [[MEMREF]] : (memref<4xcomplex<f32>>) -> memref<4x2xf32>
-// CHECK: arith.constant 0
-// CHECK: memref.load [[COMP]][[[IDX]], {{%.*}}] : memref<4x2xf32>
+// CHECK: [[COMP:%[0-9]+]] = fir.convert [[MEMREF]] : (memref<4xcomplex<f32>>) -> memref<4x2xf32>
+// CHECK: %[[FWD_C_RE:.*]] = arith.constant 0 : index
+// CHECK: %[[FWD_C_SZF32:.*]] = arith.constant 4 : index
+// CHECK: %[[FWD_C_DIM0:.*]] = arith.constant 0 : index
+// CHECK: [[BD:%[0-9]+]]:3 = fir.box_dims %2, %[[FWD_C_DIM0]] : (!fir.box<!fir.array<4xf32>>, index) -> (index, index, index)
+// CHECK: [[STRIDE:%[0-9]+]] = arith.divsi [[BD]]#2, %[[FWD_C_SZF32]] : index
+// Reinterpret applies the embox descriptor layout onto the scalar view:
+// sizes[0] = box extent (section length in f32 slots)
+// sizes[1] = 2 for the (re, im) pair exposed by memref<4x2xf32>
+// strides[0] = box_dims byte_stride / sizeof(f32) (not box_elesize)
+// strides[1] = 1 between adjacent real/imag scalars
+// Without this, memref.load would use dense strides from fir.convert only.
+// CHECK: %[[FWD_C_PAIR:.*]] = arith.constant 2 : index
+// CHECK: %[[FWD_C_COMP_STRIDE:.*]] = arith.constant 1 : index
+// CHECK: %[[FWD_C_OFF:.*]] = arith.constant 0 : index
+// CHECK: [[VIEW:%.*]] = memref.reinterpret_cast [[COMP]] to offset: [%[[FWD_C_OFF]]], sizes: [[[BD]]#1, %[[FWD_C_PAIR]]], strides: [[[STRIDE]], %[[FWD_C_COMP_STRIDE]]] : memref<4x2xf32> to memref<?x?xf32, strided<
+// CHECK: [[LOAD:%[0-9]+]] = memref.load [[VIEW]][[[IDX]], %[[FWD_C_RE]]] : memref<?x?xf32, strided<
func.func @projected_slice_fwd(%arg0: !fir.ref<!fir.array<4xcomplex<f32>>>) {
%c1 = arith.constant 1 : index
%c4 = arith.constant 4 : index
@@ -48,9 +67,18 @@ func.func @projected_slice_fwd(%arg0: !fir.ref<!fir.array<4xcomplex<f32>>>) {
// CHECK: fir.do_loop [[I:%.*]] =
// CHECK: [[MEMREF:%.*]] = fir.convert %arg0 : (!fir.ref<!fir.array<4xcomplex<f32>>>) -> memref<4xcomplex<f32>>
// CHECK: [[IDX:%.*]] = arith.addi
-// CHECK: [[COMP:%.*]] = fir.convert [[MEMREF]] : (memref<4xcomplex<f32>>) -> memref<4x2xf32>
-// CHECK: arith.constant 0
-// CHECK: memref.load [[COMP]][[[IDX]], {{%.*}}] : memref<4x2xf32>
+// CHECK: [[COMP:%[0-9]+]] = fir.convert [[MEMREF]] : (memref<4xcomplex<f32>>) -> memref<4x2xf32>
+// CHECK: %[[BWD_C_RE:.*]] = arith.constant 0 : index
+// CHECK: %[[BWD_C_SZF32:.*]] = arith.constant 4 : index
+// CHECK: %[[BWD_C_DIM0:.*]] = arith.constant 0 : index
+// CHECK: [[BD:%[0-9]+]]:3 = fir.box_dims %2, %[[BWD_C_DIM0]] : (!fir.box<!fir.array<4xf32>>, index) -> (index, index, index)
+// CHECK: [[STRIDE:%[0-9]+]] = arith.divsi [[BD]]#2, %[[BWD_C_SZF32]] : index
+// Same reinterpret as forward; slice triple only changes [[IDX]], not strides.
+// CHECK: %[[BWD_C_PAIR:.*]] = arith.constant 2 : index
+// CHECK: %[[BWD_C_COMP_STRIDE:.*]] = arith.constant 1 : index
+// CHECK: %[[BWD_C_OFF:.*]] = arith.constant 0 : index
+// CHECK: [[VIEW:%.*]] = memref.reinterpret_cast [[COMP]] to offset: [%[[BWD_C_OFF]]], sizes: [[[BD]]#1, %[[BWD_C_PAIR]]], strides: [[[STRIDE]], %[[BWD_C_COMP_STRIDE]]] : memref<4x2xf32> to memref<?x?xf32, strided<
+// CHECK: [[LOAD:%[0-9]+]] = memref.load [[VIEW]][[[IDX]], %[[BWD_C_RE]]] : memref<?x?xf32, strided<
func.func @projected_slice_bwd(%arg0: !fir.ref<!fir.array<4xcomplex<f32>>>) {
%c1 = arith.constant 1 : index
%c4 = arith.constant 4 : index
@@ -74,9 +102,18 @@ func.func @projected_slice_bwd(%arg0: !fir.ref<!fir.array<4xcomplex<f32>>>) {
// CHECK: fir.do_loop [[I:%.*]] =
// CHECK: [[MEMREF:%.*]] = fir.convert %arg0 : (!fir.ref<!fir.array<4xcomplex<f32>>>) -> memref<4xcomplex<f32>>
// CHECK: [[IDX:%.*]] = arith.addi
-// CHECK: [[COMP:%.*]] = fir.convert [[MEMREF]] : (memref<4xcomplex<f32>>) -> memref<4x2xf32>
-// CHECK: arith.constant 1
-// CHECK: memref.store %arg1, [[COMP]][[[IDX]], {{%.*}}] : memref<4x2xf32>
+// CHECK: [[COMP:%[0-9]+]] = fir.convert [[MEMREF]] : (memref<4xcomplex<f32>>) -> memref<4x2xf32>
+// CHECK: %[[IM_C_IM:.*]] = arith.constant 1 : index
+// CHECK: %[[IM_C_SZF32:.*]] = arith.constant 4 : index
+// CHECK: %[[IM_C_DIM0:.*]] = arith.constant 0 : index
+// CHECK: [[BD:%[0-9]+]]:3 = fir.box_dims %2, %[[IM_C_DIM0]] : (!fir.box<!fir.array<4xf32>>, index) -> (index, index, index)
+// CHECK: [[STRIDE:%[0-9]+]] = arith.divsi [[BD]]#2, %[[IM_C_SZF32]] : index
+// Same layout as %re; store uses component index 1 for imaginary.
+// CHECK: %[[IM_C_PAIR:.*]] = arith.constant 2 : index
+// CHECK: %[[IM_C_COMP_STRIDE:.*]] = arith.constant 1 : index
+// CHECK: %[[IM_C_OFF:.*]] = arith.constant 0 : index
+// CHECK: [[VIEW:%.*]] = memref.reinterpret_cast [[COMP]] to offset: [%[[IM_C_OFF]]], sizes: [[[BD]]#1, %[[IM_C_PAIR]]], strides: [[[STRIDE]], %[[IM_C_COMP_STRIDE]]] : memref<4x2xf32> to memref<?x?xf32, strided<
+// CHECK: memref.store %arg1, [[VIEW]][[[IDX]], %[[IM_C_IM]]] : memref<?x?xf32, strided<
func.func @projected_slice_store_im(%arg0: !fir.ref<!fir.array<4xcomplex<f32>>>,
%arg1: f32) {
%c1 = arith.constant 1 : index
@@ -114,9 +151,22 @@ func.func @projected_slice_store_im(%arg0: !fir.ref<!fir.array<4xcomplex<f32>>>,
// CHECK: [[MEMREF:%.*]] = fir.convert %arg0 : (!fir.ref<!fir.array<2x3xcomplex<f32>>>) -> memref<3x2xcomplex<f32>>
// CHECK: [[IDX_I:%.*]] = arith.addi
// CHECK: [[IDX_J:%.*]] = arith.addi
-// CHECK: [[COMP:%.*]] = fir.convert [[MEMREF]] : (memref<3x2xcomplex<f32>>) -> memref<3x2x2xf32>
-// CHECK: arith.constant 0
-// CHECK: memref.load [[COMP]][[[IDX_J]], [[IDX_I]], {{%.*}}] : memref<3x2x2xf32>
+// CHECK: [[COMP:%[0-9]+]] = fir.convert [[MEMREF]] : (memref<3x2xcomplex<f32>>) -> memref<3x2x2xf32>
+// CHECK: %[[D2_C_RE:.*]] = arith.constant 0 : index
+// CHECK: %[[D2_C_SZF32:.*]] = arith.constant 4 : index
+// CHECK: %[[D2_C_DIM1:.*]] = arith.constant 1 : index
+// CHECK: [[BD0:%[0-9]+]]:3 = fir.box_dims %2, %[[D2_C_DIM1]] : (!fir.box<!fir.array<2x3xf32>>, index) -> (index, index, index)
+// CHECK: [[STR0:%[0-9]+]] = arith.divsi [[BD0]]#2, %[[D2_C_SZF32]] : index
+// CHECK: %[[D2_C_DIM0:.*]] = arith.constant 0 : index
+// CHECK: [[BD1:%[0-9]+]]:3 = fir.box_dims %2, %[[D2_C_DIM0]] : (!fir.box<!fir.array<2x3xf32>>, index) -> (index, index, index)
+// CHECK: [[STR1:%[0-9]+]] = arith.divsi [[BD1]]#2, %[[D2_C_SZF32]] : index
+// 2-D embox: two box_dims strides (both / sizeof(f32)), plus pair dim (2, 1).
+// Row-major memref indices are [j, i, 0] after Fortran dim reversal.
+// CHECK: %[[D2_C_PAIR:.*]] = arith.constant 2 : index
+// CHECK: %[[D2_C_COMP_STRIDE:.*]] = arith.constant 1 : index
+// CHECK: %[[D2_C_OFF:.*]] = arith.constant 0 : index
+// CHECK: [[VIEW:%.*]] = memref.reinterpret_cast [[COMP]] to offset: [%[[D2_C_OFF]]], sizes: [[[BD0]]#1, [[BD1]]#1, %[[D2_C_PAIR]]], strides: [[[STR0]], [[STR1]], %[[D2_C_COMP_STRIDE]]] : memref<3x2x2xf32> to memref<?x?x?xf32, strided<
+// CHECK: [[LOAD:%[0-9]+]] = memref.load [[VIEW]][[[IDX_J]], [[IDX_I]], %[[D2_C_RE]]] : memref<?x?x?xf32, strided<
func.func @projected_slice_2d(%arg0: !fir.ref<!fir.array<2x3xcomplex<f32>>>) {
%c1 = arith.constant 1 : index
%c2 = arith.constant 2 : index
@@ -134,6 +184,51 @@ func.func @projected_slice_2d(%arg0: !fir.ref<!fir.array<2x3xcomplex<f32>>>) {
return
}
+// ----------------------------------------------------------------------------
+// Projected slice on a complex descriptor (no embox): array_coor %box[%slice]
+// path %c0 for %re. Strides must be scaled by sizeof(f32), not
+// sizeof(complex<f32>) from fir.box_elesize on the complex box.
+// ----------------------------------------------------------------------------
+// CHECK-LABEL: func.func @projected_slice_complex_box
+// CHECK: fir.do_loop
+// CHECK: fir.do_loop
+// CHECK: [[CB_BOX:%[0-9]+]] = fir.box_addr %arg0 : (!fir.box<!fir.array<?x?xcomplex<f32>>>) -> !fir.ref<!fir.array<?x?xcomplex<f32>>>
+// CHECK: [[CB_REF:%[0-9]+]] = fir.convert [[CB_BOX]] : (!fir.ref<!fir.array<?x?xcomplex<f32>>>) -> memref<?x?xcomplex<f32>>
+// CHECK: [[CB_I:%[0-9]+]] = arith.addi
+// CHECK: [[CB_J:%[0-9]+]] = arith.addi
+// CHECK: [[CB_COMP:%[0-9]+]] = fir.convert [[CB_REF]] : (memref<?x?xcomplex<f32>>) -> memref<?x?x2xf32>
+// CHECK: %[[CB_C_RE:.*]] = arith.constant 0 : index
+// CHECK: %[[CB_C_SZF32:.*]] = arith.constant 4 : index
+// CHECK: %[[CB_C_DIM1:.*]] = arith.constant 1 : index
+// CHECK: [[CB_BD0:%[0-9]+]]:3 = fir.box_dims %arg0, %[[CB_C_DIM1]] : (!fir.box<!fir.array<?x?xcomplex<f32>>>, index) -> (index, index, index)
+// CHECK: [[CB_STR0:%[0-9]+]] = arith.divsi [[CB_BD0]]#2, %[[CB_C_SZF32]] : index
+// CHECK: %[[CB_C_DIM0:.*]] = arith.constant 0 : index
+// CHECK: [[CB_BD1:%[0-9]+]]:3 = fir.box_dims %arg0, %[[CB_C_DIM0]] : (!fir.box<!fir.array<?x?xcomplex<f32>>>, index) -> (index, index, index)
+// CHECK: [[CB_STR1:%[0-9]+]] = arith.divsi [[CB_BD1]]#2, %[[CB_C_SZF32]] : index
+// CHECK-NOT: fir.box_elesize %arg0
+// Complex box (not embox): strides from fir.box_dims on %arg0; divisor sizeof(f32).
+// CHECK: %[[CB_C_PAIR:.*]] = arith.constant 2 : index
+// CHECK: %[[CB_C_COMP_STRIDE:.*]] = arith.constant 1 : index
+// CHECK: %[[CB_C_OFF:.*]] = arith.constant 0 : index
+// CHECK: [[CB_VIEW:%.*]] = memref.reinterpret_cast [[CB_COMP]] to offset: [%[[CB_C_OFF]]], sizes: [[[CB_BD0]]#1, [[CB_BD1]]#1, %[[CB_C_PAIR]]], strides: [[[CB_STR0]], [[CB_STR1]], %[[CB_C_COMP_STRIDE]]] : memref<?x?x2xf32> to memref<?x?x?xf32, strided<
+// Row-major memref indices are [j, i, 0] (see projected_slice_2d).
+// CHECK: [[CB_LOAD:%[0-9]+]] = memref.load [[CB_VIEW]][[[CB_J]], [[CB_I]], %[[CB_C_RE]]] : memref<?x?x?xf32, strided<
+func.func @projected_slice_complex_box(%arg0: !fir.box<!fir.array<?x?xcomplex<f32>>>) {
+ %c0 = arith.constant 0 : index
+ %c1 = arith.constant 1 : index
+ %dim0:3 = fir.box_dims %arg0, %c0 : (!fir.box<!fir.array<?x?xcomplex<f32>>>, index) -> (index, index, index)
+ %dim1:3 = fir.box_dims %arg0, %c1 : (!fir.box<!fir.array<?x?xcomplex<f32>>>, index) -> (index, index, index)
+ %shape = fir.shape %dim0#1, %dim1#1 : (index, index) -> !fir.shape<2>
+ %slice = fir.slice %c1, %dim0#1, %c1, %c1, %dim1#1, %c1 path %c0 : (index, index, index, index, index, index, index) -> !fir.slice<2>
+ fir.do_loop %i = %c1 to %dim0#1 step %c1 unordered {
+ fir.do_loop %j = %c1 to %dim1#1 step %c1 unordered {
+ %coor = fir.array_coor %arg0 [%slice] %i, %j : (!fir.box<!fir.array<?x?xcomplex<f32>>>, !fir.slice<2>, index, index) -> !fir.ref<f32>
+ %val = fir.load %coor : !fir.ref<f32>
+ }
+ }
+ return
+}
+
// ----------------------------------------------------------------------------
// Derived-type component projection: a%x where a : TYPE{x:f64, y:complex<f64>}
//
More information about the flang-commits
mailing list