[flang-commits] [flang] d767b55 - [flang][CodeGen] Fix element type of folded insert_on_range initializers (#218587)
via flang-commits
flang-commits at lists.llvm.org
Tue Aug 25 06:30:40 PDT 2026
Author: Christian Ulmann
Date: 2026-08-25T15:30:31+02:00
New Revision: d767b554ddcb63f0d373757f60fcae57ba8280ba
URL: https://github.com/llvm/llvm-project/commit/d767b554ddcb63f0d373757f60fcae57ba8280ba
DIFF: https://github.com/llvm/llvm-project/commit/d767b554ddcb63f0d373757f60fcae57ba8280ba.diff
LOG: [flang][CodeGen] Fix element type of folded insert_on_range initializers (#218587)
`GlobalOpConversion` folds a full-range `fir.insert_on_range` into a
dense constant. When the inserted value comes from a `fir.convert`, the
fold reached through the conversion and built the dense attribute from
the type of the *source* constant. For a `logical(4)` array initialized
to `.true.` this produced
```
llvm.mlir.constant(dense<true> : vector<32768xi1>) : !llvm.array<32768 x i32>
```
where the attribute element type `i1` disagrees with the result element
type `i32`. Translation to LLVM IR ignores the attribute type and uses
the result type, so the emitted global is still correct today, but the
IR is malformed and any consumer that trusts the attribute type sees the
wrong element width.
Build the dense attribute from the converted element type instead. A
logical conversion normalizes its operand to a canonical 0/1 (see
`ConvertOpConversion`), so apply the same normalization here; any other
mismatching conversion is left to the regular lowering.
Note that this is a preparation to strengthen the verifiers of
`llvm.mlir.constant`.
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply at anthropic.com>
Added:
Modified:
flang/lib/Optimizer/CodeGen/CodeGen.cpp
flang/test/Fir/global-initialization.fir
Removed:
################################################################################
diff --git a/flang/lib/Optimizer/CodeGen/CodeGen.cpp b/flang/lib/Optimizer/CodeGen/CodeGen.cpp
index 589b143a6c58b..cb3435a63767c 100644
--- a/flang/lib/Optimizer/CodeGen/CodeGen.cpp
+++ b/flang/lib/Optimizer/CodeGen/CodeGen.cpp
@@ -3755,25 +3755,41 @@ struct GlobalOpConversion : public fir::FIROpConversion<fir::GlobalOp> {
// initialization is on the full range.
auto insertOnRangeOps = gr.front().getOps<fir::InsertOnRangeOp>();
for (auto insertOp : insertOnRangeOps) {
- if (insertOp.isFullRange()) {
- auto seqTyAttr = convertType(insertOp.getType());
- auto *op = insertOp.getVal().getDefiningOp();
- auto constant = mlir::dyn_cast<mlir::arith::ConstantOp>(op);
- if (!constant) {
- auto convertOp = mlir::dyn_cast<fir::ConvertOp>(op);
- if (!convertOp)
- continue;
- constant = mlir::cast<mlir::arith::ConstantOp>(
- convertOp.getValue().getDefiningOp());
- }
- mlir::Type vecType = mlir::VectorType::get(
- insertOp.getType().getShape(), constant.getType());
- auto denseAttr = mlir::DenseElementsAttr::get(
- mlir::cast<mlir::ShapedType>(vecType), constant.getValue());
- rewriter.setInsertionPointAfter(insertOp);
- rewriter.replaceOpWithNewOp<mlir::arith::ConstantOp>(
- insertOp, seqTyAttr, denseAttr);
+ if (!insertOp.isFullRange())
+ continue;
+ // The dense attribute must use the converted element type of the
+ // array, not the type of whatever constant feeds the insertion.
+ mlir::Type elementType = convertType(insertOp.getType().getEleTy());
+ mlir::Value val = insertOp.getVal();
+ // Logical constants reach the insertion through a `fir.convert`.
+ auto convertOp = val.getDefiningOp<fir::ConvertOp>();
+ if (convertOp)
+ val = convertOp.getValue();
+ auto constant = val.getDefiningOp<mlir::arith::ConstantOp>();
+ if (!constant)
+ continue;
+ mlir::TypedAttr valueAttr = constant.getValue();
+ if (valueAttr.getType() != elementType) {
+ // Looking through the `fir.convert` leaves the constant with the
+ // source type. Only an integer<->logical conversion is folded here:
+ // it normalizes any integer operand to a canonical 0/1, see
+ // ConvertOpConversion. Any other mismatching conversion is left to
+ // the regular lowering.
+ auto intAttr = mlir::dyn_cast<mlir::IntegerAttr>(valueAttr);
+ auto intType = mlir::dyn_cast<mlir::IntegerType>(elementType);
+ if (!intAttr || !intType || !convertOp ||
+ (!mlir::isa<fir::LogicalType>(convertOp.getType()) &&
+ !mlir::isa<fir::LogicalType>(convertOp.getValue().getType())))
+ continue;
+ valueAttr = mlir::IntegerAttr::get(
+ intType, intAttr.getValue().isZero() ? 0 : 1);
}
+ auto vecType =
+ mlir::VectorType::get(insertOp.getType().getShape(), elementType);
+ auto denseAttr = mlir::DenseElementsAttr::get(vecType, valueAttr);
+ rewriter.setInsertionPointAfter(insertOp);
+ rewriter.replaceOpWithNewOp<mlir::arith::ConstantOp>(
+ insertOp, convertType(insertOp.getType()), denseAttr);
}
}
diff --git a/flang/test/Fir/global-initialization.fir b/flang/test/Fir/global-initialization.fir
index 98c842c4b7551..a683b46de2541 100644
--- a/flang/test/Fir/global-initialization.fir
+++ b/flang/test/Fir/global-initialization.fir
@@ -41,10 +41,25 @@ fir.global internal @_QEmasklogical : !fir.array<32768x!fir.logical<4>> {
// CHECK: [[VAL0:%.*]] = llvm.mlir.constant(true) : i1
// CHECK: [[VAL1:%.*]] = llvm.mlir.undef : !llvm.array<32768 x i32>
// CHECK: [[VAL2:%.*]] = llvm.mlir.constant(1 : i32) : i32
-// CHECK: [[VAL3:%.*]] = llvm.mlir.constant(dense<true> : vector<32768xi1>) : !llvm.array<32768 x i32>
+// CHECK: [[VAL3:%.*]] = llvm.mlir.constant(dense<1> : vector<32768xi32>) : !llvm.array<32768 x i32>
// CHECK: llvm.return [[VAL3]] : !llvm.array<32768 x i32>
// CHECK: }
+// A logical conversion normalizes any integer operand to a canonical 0/1, not
+// just an `i1` one, so the full-range fold must apply here as well.
+fir.global internal @_QEmasklogicalkind : !fir.array<8x!fir.logical<8>> {
+ %c1_i32 = arith.constant 1 : i32
+ %0 = fir.undefined !fir.array<8x!fir.logical<8>>
+ %1 = fir.convert %c1_i32 : (i32) -> !fir.logical<8>
+ %2 = fir.insert_on_range %0, %1 from (0) to (7) : (!fir.array<8x!fir.logical<8>>, !fir.logical<8>) -> !fir.array<8x!fir.logical<8>>
+ fir.has_value %2 : !fir.array<8x!fir.logical<8>>
+}
+
+// CHECK: llvm.mlir.global internal @_QEmasklogicalkind() {addr_space = 0 : i32} : !llvm.array<8 x i64> {
+// CHECK: [[VAL2:%.*]] = llvm.mlir.constant(dense<1> : vector<8xi64>) : !llvm.array<8 x i64>
+// CHECK: llvm.return [[VAL2]] : !llvm.array<8 x i64>
+// CHECK: }
+
fir.global internal @_QElookforme : !fir.type<_QTt{i:!fir.array<500xi32>,j:!fir.array<500xi32>}> {
%c2_i32 = arith.constant 2 : i32
%c52_i32 = arith.constant 52 : i32
More information about the flang-commits
mailing list