[flang-commits] [flang] [flang] Use the target index width during FIR-to-LLVM lowering (PR #226424)

Anutosh Bhat via flang-commits flang-commits at lists.llvm.org
Fri Sep 25 05:14:58 PDT 2026


https://github.com/anutosh491 updated https://github.com/llvm/llvm-project/pull/226424

>From 7b8a3627a73a09c53c5e7a3b0a4aac2b23448f5f Mon Sep 17 00:00:00 2001
From: anutosh491 <andersonbhat491 at gmail.com>
Date: Fri, 25 Sep 2026 15:34:33 +0530
Subject: [PATCH] [flang] Use the target index width during FIR-to-LLVM
 lowering

---
 flang/lib/Optimizer/CodeGen/FIROpPatterns.cpp | 14 ++++++++++----
 flang/lib/Optimizer/CodeGen/TypeConverter.cpp | 10 +++++++---
 flang/test/Fir/alloc-32.fir                   | 10 ++++------
 flang/test/Fir/convert-to-llvm-target.fir     | 19 +++++++++++++++++++
 flang/test/Fir/convert-to-llvm.fir            | 18 +++++++++++++++++-
 5 files changed, 57 insertions(+), 14 deletions(-)

diff --git a/flang/lib/Optimizer/CodeGen/FIROpPatterns.cpp b/flang/lib/Optimizer/CodeGen/FIROpPatterns.cpp
index 995a2efba25a4d..6ad44901345338 100644
--- a/flang/lib/Optimizer/CodeGen/FIROpPatterns.cpp
+++ b/flang/lib/Optimizer/CodeGen/FIROpPatterns.cpp
@@ -66,10 +66,16 @@ mlir::Value ConvertFIRToLLVMPattern::integerCast(
     mlir::Location loc, mlir::ConversionPatternRewriter &rewriter,
     mlir::Type ty, mlir::Value val, bool fold) const {
   auto valTy = val.getType();
-  // If the value was not yet lowered, lower its type so that it can
-  // be used in getPrimitiveTypeSizeInBits.
-  if (!mlir::isa<mlir::IntegerType>(valTy))
-    valTy = convertType(valTy);
+  // If the value was not yet lowered, convert it to the LLVM integer type.
+  if (!mlir::isa<mlir::IntegerType>(valTy)) {
+    mlir::Type llvmValTy = convertType(valTy);
+    if (llvmValTy && llvmValTy != valTy) {
+      val = getTypeConverter()->materializeTargetConversion(rewriter, loc,
+                                                            llvmValTy, val);
+      assert(val && "failed to materialize integer target conversion");
+      valTy = llvmValTy;
+    }
+  }
   auto toSize = mlir::LLVM::getPrimitiveTypeSizeInBits(ty);
   auto fromSize = mlir::LLVM::getPrimitiveTypeSizeInBits(valTy);
   if (fold) {
diff --git a/flang/lib/Optimizer/CodeGen/TypeConverter.cpp b/flang/lib/Optimizer/CodeGen/TypeConverter.cpp
index 31194f9c274f36..c901bf4b2f453d 100644
--- a/flang/lib/Optimizer/CodeGen/TypeConverter.cpp
+++ b/flang/lib/Optimizer/CodeGen/TypeConverter.cpp
@@ -37,7 +37,10 @@ static mlir::LowerToLLVMOptions MakeLowerOptions(mlir::ModuleOp module) {
 
   auto options = mlir::LowerToLLVMOptions(module.getContext());
   auto llvmDL = llvm::DataLayout(dataLayoutString);
-  if (llvmDL.getPointerSizeInBits(0) == 32) {
+  bool use32BitIndices = dataLayoutString.empty()
+                             ? fir::getTargetTriple(module).isArch32Bit()
+                             : llvmDL.getPointerSizeInBits(0) == 32;
+  if (use32BitIndices) {
     // FIXME: Should translateDataLayout in the MLIR layer be doing this?
     options.overrideIndexBitwidth(32);
   }
@@ -174,9 +177,10 @@ mlir::Type LLVMTypeConverter::offsetType() const {
   return mlir::IntegerType::get(&getContext(), 32);
 }
 
-// i64 can be used to index into aggregates like arrays
+// Index width follows the LLVM lowering options / data layout (i32 on
+// 32-bit targets, i64 otherwise).
 mlir::Type LLVMTypeConverter::indexType() const {
-  return mlir::IntegerType::get(&getContext(), 64);
+  return mlir::IntegerType::get(&getContext(), getIndexTypeBitwidth());
 }
 
 // fir.type<name(p : TY'...){f : TY...}>  -->  llvm<"%name = { ty... }">
diff --git a/flang/test/Fir/alloc-32.fir b/flang/test/Fir/alloc-32.fir
index a3cbf200c24fcd..0a5325e3b394b6 100644
--- a/flang/test/Fir/alloc-32.fir
+++ b/flang/test/Fir/alloc-32.fir
@@ -18,12 +18,10 @@ func.func @allocmem_scalar_nonchar() -> !fir.heap<i32> {
 
 // CHECK-LABEL: define ptr @allocmem_scalar_dynchar(
 // CHECK-SAME: i32 %[[len:.*]])
-// CHECK: %[[mul1:.*]] = sext i32 %[[len]] to i64
-// CHECK: %[[mul2:.*]] = mul i64 1, %[[mul1]]
-// CHECK: %[[cmp:.*]] = icmp sgt i64 %[[mul2]], 0
-// CHECK: %[[sz:.*]] = select i1 %[[cmp]], i64 %[[mul2]], i64 1
-// CHECK: %[[trunc:.*]] = trunc i64 %[[sz]] to i32
-// CHECK: call ptr @malloc(i32 %[[trunc]])
+// CHECK: %[[mul:.*]] = mul i32 1, %[[len]]
+// CHECK: %[[cmp:.*]] = icmp sgt i32 %[[mul]], 0
+// CHECK: %[[sz:.*]] = select i1 %[[cmp]], i32 %[[mul]], i32 1
+// CHECK: call ptr @malloc(i32 %[[sz]])
 func.func @allocmem_scalar_dynchar(%l : i32) -> !fir.heap<!fir.char<1,?>> {
   %1 = fir.allocmem !fir.char<1,?>(%l : i32)
   return %1 : !fir.heap<!fir.char<1,?>>
diff --git a/flang/test/Fir/convert-to-llvm-target.fir b/flang/test/Fir/convert-to-llvm-target.fir
index 6adc5cd4b737fc..c37c27e4489efa 100644
--- a/flang/test/Fir/convert-to-llvm-target.fir
+++ b/flang/test/Fir/convert-to-llvm-target.fir
@@ -147,3 +147,22 @@ func.func @boxchar_len_i32_i64(%arg0 : !fir.boxchar<4>) -> (i64) {
 // INT32:  %[[len:.*]] = llvm.extractvalue %[[box_char]][1] : !llvm.struct<(ptr, i32)>
 // INT32:  %{{.*}} = llvm.sext %0 : i32 to i64
 // INT32-NEXT:  llvm.return
+
+// -----
+
+// Test that dynamic allocation uses the target index width.
+
+func.func @dynamic_alloca(%extent : index) {
+  %0 = fir.alloca !fir.array<?xi32>, %extent
+  return
+}
+
+// INT64-LABEL: llvm.func @dynamic_alloca
+// INT64-SAME: %[[extent:.*]]: i64
+// INT64: %[[count:.*]] = llvm.mul %[[extent]], %{{.*}} : i64
+// INT64: llvm.alloca %[[count]] x i32 : (i64) -> !llvm.ptr
+
+// INT32-LABEL: llvm.func @dynamic_alloca
+// INT32-SAME: %[[extent:.*]]: i32
+// INT32: %[[count:.*]] = llvm.mul %[[extent]], %{{.*}} : i32
+// INT32: llvm.alloca %[[count]] x i32 : (i32) -> !llvm.ptr
diff --git a/flang/test/Fir/convert-to-llvm.fir b/flang/test/Fir/convert-to-llvm.fir
index d00aae198bf138..5e34c574775d78 100644
--- a/flang/test/Fir/convert-to-llvm.fir
+++ b/flang/test/Fir/convert-to-llvm.fir
@@ -1,6 +1,8 @@
 // RUN: fir-opt --split-input-file --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" %s | FileCheck %s --check-prefixes=CHECK,CHECK-COMDAT,GENERIC
 // RUN: fir-opt --split-input-file --fir-to-llvm-ir="target=aarch64-unknown-linux-gnu" %s | FileCheck %s --check-prefixes=CHECK,CHECK-COMDAT,GENERIC
-// RUN: fir-opt --split-input-file --fir-to-llvm-ir="target=i386-unknown-linux-gnu" %s | FileCheck %s --check-prefixes=CHECK,CHECK-COMDAT,GENERIC
+// The generic checks assume a 64-bit index width. Keep representative i386
+// coverage under a target-specific prefix.
+// RUN: fir-opt --split-input-file --fir-to-llvm-ir="target=i386-unknown-linux-gnu" %s | FileCheck %s --check-prefixes=I386,CHECK-COMDAT
 // RUN: fir-opt --split-input-file --fir-to-llvm-ir="target=powerpc64le-unknown-linux-gnu" %s | FileCheck %s --check-prefixes=CHECK,CHECK-COMDAT,GENERIC
 // RUN: fir-opt --split-input-file --fir-to-llvm-ir="target=x86_64-pc-win32" %s | FileCheck %s --check-prefixes=CHECK,CHECK-COMDAT,GENERIC
 // RUN: fir-opt --split-input-file --fir-to-llvm-ir="target=aarch64-apple-darwin" %s | FileCheck %s --check-prefixes=CHECK,CHECK-NO-COMDAT,GENERIC
@@ -1093,6 +1095,10 @@ func.func @alloca_one() -> !fir.ref<i32> {
 // AMDGPU: [[A:%.*]] = llvm.addrspacecast [[AA]] : !llvm.ptr<5> to !llvm.ptr
 // CHECK: llvm.return [[A]] : !llvm.ptr
 
+// I386-LABEL: llvm.func @alloca_one() -> !llvm.ptr
+// I386: %[[ONE:.*]] = llvm.mlir.constant(1 : i32) : i32
+// I386: llvm.alloca %[[ONE]] x i32 : (i32) -> !llvm.ptr
+
 
 // -----
 
@@ -2128,6 +2134,12 @@ func.func @ext_array_coor5(%arg0: !fir.ref<!fir.array<?xi32>>, %idx1 : index, %i
 // CHECK:           %[[VAL_16:.*]] = llvm.getelementptr nusw|nuw %[[VAL_0]][%[[VAL_13]]] : (!llvm.ptr, i64) -> !llvm.ptr, i32
 // CHECK:         }
 
+// I386-LABEL: llvm.func @ext_array_coor5(
+// I386-SAME: %[[BASE:[^,]+]]: !llvm.ptr, %[[EXTENT:[^,]+]]: i32
+// I386: %[[ONE:.*]] = llvm.mlir.constant(1 : i32) : i32
+// I386: %[[STRIDE:.*]] = llvm.mul %[[ONE]], %[[EXTENT]] overflow<nsw, nuw> : i32
+// I386: llvm.getelementptr nusw|nuw %[[BASE]][%{{.*}}] : (!llvm.ptr, i32) -> !llvm.ptr, i32
+
 // Conversion for 3-d array
 
 func.func @ext_array_coor6(%arg0: !fir.ref<!fir.array<?x?x?xi32>>, %idx1 : index, %idx2 : index, %idx3 : index, %idx4 : index, %idx5 : index) {
@@ -2439,6 +2451,10 @@ func.func @coordinate_box_array_1d(%arg0: !fir.box<!fir.array<10 x f32>>, %arg1:
 // CHECK-NEXT:  %[[SUBOBJECT_ADDR:.*]] = llvm.getelementptr %[[ARRAY_OBJECT]][%[[SUBOJECT_OFFSET]]] : (!llvm.ptr, i64) -> !llvm.ptr, i8
 // CHECK-NEXT:  llvm.return
 
+// I386-LABEL: llvm.func @coordinate_box_array_1d(
+// I386-SAME: %[[BOX:.*]]: !llvm.ptr, %[[COORDINATE:.*]]: i32)
+// I386: llvm.mul %[[COORDINATE]], %{{.*}} overflow<nsw> : i32
+
 // `fir.array` inside a `fir.box` (1d) - dynamic size
 func.func @coordinate_of_box_dynamic_array_1d(%arg0: !fir.box<!fir.array<? x f32>>, %arg1: index) {
   %p = fir.coordinate_of %arg0, %arg1 : (!fir.box<!fir.array<? x f32>>, index) -> !fir.ref<f32>



More information about the flang-commits mailing list