[Mlir-commits] [mlir] [MLIR][LLVMIR] Restore constant folding for global initializer GEPs (PR #227651)
Henrich Lauko
llvmlistbot at llvm.org
Wed Sep 30 03:36:20 PDT 2026
https://github.com/xlauko created https://github.com/llvm/llvm-project/pull/227651
Before c68a4ca2a920 (#226904), a GEP in a global initializer went through
`IRBuilder::CreateGEP`, and MLIR's `IRBuilder<TargetFolder>` ran the result
through `ConstantFoldConstant`. Besides combining nested GEPs and folding
null or integer bases, that infers `inbounds` when the offset stays within
the global's size and, since `inbounds` implies `nusw`, `nuw` for a
non-negative offset. #226904 builds the constant expression directly and
skips the folder, so those flags disappeared from the output.
Run `ConstantFoldConstant` on the built constant for the non-inrange case.
The inrange path bypassed the TargetFolder before as well and keeps its
output.
CIR's lit tests for vtables, VTTs and constant pointer initializers expect
the inferred `inbounds nuw` (for example CIR/CodeGen/vtt.cpp and
CIR/CodeGenCXX/base-layout.cpp) and have been failing since #226904.
Assisted-by: Claude Code (Claude Fable 5.1).
>From 16a83c314f393bc412b4d1a4cee5c55c96d44e4e 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 c68a4ca2a920 (#226904), a GEP in a global initializer went through
`IRBuilder::CreateGEP`, and MLIR's `IRBuilder<TargetFolder>` ran the result
through `ConstantFoldConstant`. Besides combining nested GEPs and folding
null or integer bases, that infers `inbounds` when the offset stays within
the global's size and, since `inbounds` implies `nusw`, `nuw` for a
non-negative offset. #226904 builds the constant expression directly and
skips the folder, so those flags disappeared from the output.
Run `ConstantFoldConstant` on the built constant for the non-inrange case.
The inrange path bypassed the TargetFolder before as well and keeps its
output.
CIR's lit tests for vtables, VTTs and constant pointer initializers expect
the inferred `inbounds nuw` (for example CIR/CodeGen/vtt.cpp and
CIR/CodeGenCXX/base-layout.cpp) and have been failing since #226904.
Assisted-by: Claude Code (Claude Fable 5.1).
---
mlir/lib/Target/LLVMIR/Dialect/LLVMIR/CMakeLists.txt | 1 +
.../LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp | 6 ++++++
mlir/test/Target/LLVMIR/llvmir.mlir | 10 ++++++++++
3 files changed, 17 insertions(+)
diff --git a/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/CMakeLists.txt b/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/CMakeLists.txt
index 616b9fc0fbbaf5..99fc9af0600837 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 1a9dd3d260ee1a..308f2e998c0c43 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,11 @@ static LogicalResult convertGEPOp(GEPOp op, llvm::IRBuilderBase &builder,
if (!res)
return op.emitError("failed to lower " + WhyConstExpr +
" to a constant byte offset");
+ // CreateGEP used to run this through the TargetFolder. Keep that folding,
+ // which among other things infers inbounds and nuw for an offset that
+ // stays within the global.
+ if (!inrangeAttr)
+ 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 5557788b039f79..4c1b00b33bcfd4 100644
--- a/mlir/test/Target/LLVMIR/llvmir.mlir
+++ b/mlir/test/Target/LLVMIR/llvmir.mlir
@@ -122,6 +122,16 @@ 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)
More information about the Mlir-commits
mailing list