[Mlir-commits] [mlir] [MLIR][LLVMIR] Restore constant folding for global initializer GEPs (PR #227651)
Henrich Lauko
llvmlistbot at llvm.org
Wed Sep 30 04:33:53 PDT 2026
https://github.com/xlauko updated https://github.com/llvm/llvm-project/pull/227651
>From 0aa508380bc302a50e954e2339d661d02b674973 Mon Sep 17 00:00:00 2001
From: Henrich Lauko <hlauko at nvidia.com>
Date: Wed, 30 Sep 2026 10:36:00 +0000
Subject: [PATCH] [MLIR][LLVMIR] Restore constant folding for global
initializer GEPs
Before #226904, a GEP in a global initializer went through
IRBuilder::CreateGEP, and MLIR's IRBuilder<TargetFolder> folded the result
with ConstantFoldConstant. That combines nested GEPs, folds null and integer
bases, and infers inbounds and nuw when the offset stays within the global.
Building the constant expression directly skipped the folder, so the output
lost those flags.
Fold the constant again. This also applies to inrange GEPs, which used to
bypass the folder; the only visible difference there is that an inbounds
GEP with a non-negative offset now also gets nuw.
CIR's vtable, VTT and constant pointer tests check for the inferred flags
(for example CIR/CodeGen/vtt.cpp) and have failed since #226904.
Assisted-by: Claude Code (Claude Fable 5.1).
---
mlir/lib/Target/LLVMIR/Dialect/LLVMIR/CMakeLists.txt | 1 +
.../Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp | 4 ++++
mlir/test/Target/LLVMIR/llvmir.mlir | 12 +++++++++++-
3 files changed, 16 insertions(+), 1 deletion(-)
diff --git a/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/CMakeLists.txt b/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/CMakeLists.txt
index 616b9fc0fbbaf..99fc9af060083 100644
--- a/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/CMakeLists.txt
+++ b/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/CMakeLists.txt
@@ -20,6 +20,7 @@ add_mlir_translation_library(MLIRLLVMToLLVMIRTranslation
LLVMToLLVMIRTranslation.cpp
LINK_COMPONENTS
+ Analysis
Core
LINK_LIBS PUBLIC
diff --git a/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp b/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp
index 1a9dd3d260ee1..be36d08930eeb 100644
--- a/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp
@@ -19,6 +19,7 @@
#include "mlir/Target/LLVMIR/ModuleTranslation.h"
#include "llvm/ADT/TypeSwitch.h"
+#include "llvm/Analysis/ConstantFolding.h"
#include "llvm/IR/ConstantRange.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DIBuilder.h"
@@ -282,6 +283,9 @@ static LogicalResult convertGEPOp(GEPOp op, llvm::IRBuilderBase &builder,
if (!res)
return op.emitError("failed to lower " + WhyConstExpr +
" to a constant byte offset");
+ // Fold the constant as CreateGEP did through the TargetFolder. This also
+ // infers inbounds and nuw when the offset stays within the global.
+ res = llvm::ConstantFoldConstant(cast<llvm::Constant>(res), dataLayout);
} else {
res = builder.CreateGEP(elementType, base, indices, "", nwFlags);
}
diff --git a/mlir/test/Target/LLVMIR/llvmir.mlir b/mlir/test/Target/LLVMIR/llvmir.mlir
index 5557788b039f7..f29184beb6b4d 100644
--- a/mlir/test/Target/LLVMIR/llvmir.mlir
+++ b/mlir/test/Target/LLVMIR/llvmir.mlir
@@ -122,9 +122,19 @@ llvm.mlir.global internal constant @int_gep() : !llvm.ptr {
llvm.return %gepinit : !llvm.ptr
}
+// CHECK: @i32_array = internal constant [4 x i32] [i32 1, i32 2, i32 3, i32 4]
+llvm.mlir.global internal constant @i32_array(dense<[1, 2, 3, 4]> : tensor<4xi32>) : !llvm.array<4 x i32>
+// The offset is within the global, so the folder infers inbounds and nuw.
+// CHECK: @int_gep_inferred_flags = internal constant ptr getelementptr inbounds nuw (i8, ptr @i32_array, i64 8)
+llvm.mlir.global internal constant @int_gep_inferred_flags() : !llvm.ptr {
+ %addr = llvm.mlir.addressof @i32_array : !llvm.ptr
+ %gepinit = llvm.getelementptr %addr[0, 2] : (!llvm.ptr) -> !llvm.ptr, !llvm.array<4 x i32>
+ llvm.return %gepinit : !llvm.ptr
+}
+
// CHECK: @vt = external constant { [3 x ptr] }
llvm.mlir.global external constant @vt() : !llvm.struct<(array<3 x ptr>)>
-// CHECK: @int_gep_inrange = internal constant ptr getelementptr inbounds inrange(-16, 8) (i8, ptr @vt, i64 16)
+// CHECK: @int_gep_inrange = internal constant ptr getelementptr inbounds nuw inrange(-16, 8) (i8, ptr @vt, i64 16)
llvm.mlir.global internal constant @int_gep_inrange() : !llvm.ptr {
%addr = llvm.mlir.addressof @vt : !llvm.ptr
%gepinit = llvm.getelementptr inbounds inrange <i64, -16, 8> %addr[0, 0, 2] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(array<3 x ptr>)>
More information about the Mlir-commits
mailing list