[llvm] [SeparateConstOffsetFromGEP] - Restrict simplification of XOR index when its base operand is constant. (PR #175724)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Jan 13 08:26:35 PST 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-transforms
Author: Pawan Nirpal (pawan-nirpal-031)
<details>
<summary>Changes</summary>
Simplifying GEP indices involving XOR with a constant base can lead to incorrect offset separation. This change ensures such cases are excluded from the transformation.
---
Full diff: https://github.com/llvm/llvm-project/pull/175724.diff
2 Files Affected:
- (modified) llvm/lib/Transforms/Scalar/SeparateConstOffsetFromGEP.cpp (+9-1)
- (added) llvm/test/Transforms/SeparateConstOffsetFromGEP/fix-const-xor-gep-simplify.ll (+34)
``````````diff
diff --git a/llvm/lib/Transforms/Scalar/SeparateConstOffsetFromGEP.cpp b/llvm/lib/Transforms/Scalar/SeparateConstOffsetFromGEP.cpp
index dc47b243625b8..10cc056eec0cc 100644
--- a/llvm/lib/Transforms/Scalar/SeparateConstOffsetFromGEP.cpp
+++ b/llvm/lib/Transforms/Scalar/SeparateConstOffsetFromGEP.cpp
@@ -729,8 +729,16 @@ Value *ConstantOffsetExtractor::removeConstOffset(unsigned ChainIndex) {
// with non-disjoint constant bits.
// TODO: The design should be updated to support partial constant
// extraction.
- if (BO->getOpcode() == Instruction::Xor)
+ if (BO->getOpcode() == Instruction::Xor) {
+ if (auto *ConstIOther = dyn_cast<ConstantInt>(TheOther)) {
+ const APInt &DisjointBits = extractDisjointBitsFromXor(BO);
+ const APInt &ConstantValue = ConstIOther->getValue();
+ const APInt &NonDisjointBits = ConstantValue & (~DisjointBits);
+ BO->setOperand(1 - OpNo,
+ ConstantInt::get(BO->getType(), NonDisjointBits));
+ }
return BO;
+ }
// If NextInChain is 0 and not the LHS of a sub, we can simplify the
// sub-expression to be just TheOther.
diff --git a/llvm/test/Transforms/SeparateConstOffsetFromGEP/fix-const-xor-gep-simplify.ll b/llvm/test/Transforms/SeparateConstOffsetFromGEP/fix-const-xor-gep-simplify.ll
new file mode 100644
index 0000000000000..049463b33ac71
--- /dev/null
+++ b/llvm/test/Transforms/SeparateConstOffsetFromGEP/fix-const-xor-gep-simplify.ll
@@ -0,0 +1,34 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt -S -passes='separate-const-offset-from-gep<lower-gep>' %s | FileCheck %s
+
+define ptr @xor-const-test(i32 %0) {
+; CHECK-LABEL: define ptr @xor-const-test(
+; CHECK-SAME: i32 [[TMP0:%.*]]) {
+; CHECK-NEXT: [[BASE:%.*]] = alloca [4 x i32], align 16
+; CHECK-NEXT: [[XOR1:%.*]] = xor i64 0, 0
+; CHECK-NEXT: [[TMP3:%.*]] = shl i64 [[XOR1]], 2
+; CHECK-NEXT: [[UGLYGEP:%.*]] = getelementptr i8, ptr [[BASE]], i64 [[TMP3]]
+; CHECK-NEXT: [[TMP2:%.*]] = getelementptr i8, ptr [[UGLYGEP]], i64 12
+; CHECK-NEXT: ret ptr [[TMP2]]
+;
+ %base = alloca [4 x i32], align 16
+ %xor = xor i64 0, 3
+ %gep = getelementptr [4 x i32], ptr %base, i64 0, i64 %xor
+ ret ptr %gep
+}
+
+define ptr @xor-const-test2(i32 %0) {
+; CHECK-LABEL: define ptr @xor-const-test2(
+; CHECK-SAME: i32 [[TMP0:%.*]]) {
+; CHECK-NEXT: [[BASE:%.*]] = alloca [4 x i32], align 16
+; CHECK-NEXT: [[XOR1:%.*]] = xor i64 2, 2
+; CHECK-NEXT: [[TMP2:%.*]] = shl i64 [[XOR1]], 2
+; CHECK-NEXT: [[UGLYGEP:%.*]] = getelementptr i8, ptr [[BASE]], i64 [[TMP2]]
+; CHECK-NEXT: [[UGLYGEP2:%.*]] = getelementptr i8, ptr [[UGLYGEP]], i64 4
+; CHECK-NEXT: ret ptr [[UGLYGEP2]]
+;
+ %base = alloca [4 x i32], align 16
+ %xor = xor i64 2, 3
+ %gep = getelementptr [4 x i32], ptr %base, i64 0, i64 %xor
+ ret ptr %gep
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/175724
More information about the llvm-commits
mailing list