[llvm] [SeparateConstOffsetFromGEP] Decompose constant xor operand if possible (PR #135788)
Sumanth Gundapaneni via llvm-commits
llvm-commits at lists.llvm.org
Thu Apr 24 06:32:34 PDT 2025
================
@@ -0,0 +1,144 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt -mtriple=amdgcn-amd-amdhsa -passes=separate-const-offset-from-gep \
+; RUN: -S < %s | FileCheck %s
+
+
+; Test with GEP user and known bits: Ensure the transformation occurs when the xor has a GEP user
+define ptr @test_with_gep_user(ptr %ptr) {
+; CHECK-LABEL: define ptr @test_with_gep_user(
+; CHECK-SAME: ptr [[PTR:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[BASE:%.*]] = add i64 0, 0
+; CHECK-NEXT: [[XOR1:%.*]] = xor i64 [[BASE]], 8
+; CHECK-NEXT: [[XOR21:%.*]] = or disjoint i64 [[XOR1]], 16
+; CHECK-NEXT: [[GEP:%.*]] = getelementptr i8, ptr [[PTR]], i64 [[XOR21]]
+; CHECK-NEXT: ret ptr [[GEP]]
+;
+entry:
+ %base = add i64 0,0
+ %xor1 = xor i64 %base, 8
+ %xor2 = xor i64 %base, 24 ; Should be replaced with OR of %xor1 and 16
+ %gep = getelementptr i8, ptr %ptr, i64 %xor2
+ ret ptr %gep
+}
+
+
+; Test with non-GEP user: Ensure the transformation does not occur
+define i32 @test_with_non_gep_user(ptr %ptr) {
+; CHECK-LABEL: define i32 @test_with_non_gep_user(
+; CHECK-SAME: ptr [[PTR:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[BASE:%.*]] = add i32 0, 0
+; CHECK-NEXT: [[XOR1:%.*]] = xor i32 [[BASE]], 8
+; CHECK-NEXT: [[XOR2:%.*]] = xor i32 [[BASE]], 24
+; CHECK-NEXT: [[ADD:%.*]] = add i32 [[XOR2]], 5
+; CHECK-NEXT: ret i32 [[ADD]]
+;
+entry:
+ %base = add i32 0,0
+ %xor1 = xor i32 %base, 8
+ %xor2 = xor i32 %base, 24
+ %add = add i32 %xor2, 5
+ ret i32 %add
+}
+
+; Test with non-constant operand: Ensure the transformation does not occur
+define ptr @test_with_non_constant_operand(i64 %val, i64 %val2, ptr %ptr) {
+; CHECK-LABEL: define ptr @test_with_non_constant_operand(
+; CHECK-SAME: i64 [[VAL:%.*]], i64 [[VAL2:%.*]], ptr [[PTR:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[XOR1:%.*]] = xor i64 [[VAL]], [[VAL2]]
+; CHECK-NEXT: [[XOR2:%.*]] = xor i64 [[VAL]], 24
+; CHECK-NEXT: [[GEP:%.*]] = getelementptr i8, ptr [[PTR]], i64 [[XOR2]]
+; CHECK-NEXT: ret ptr [[GEP]]
+;
+entry:
+ %xor1 = xor i64 %val, %val2 ; Non-constant operand
+ %xor2 = xor i64 %val, 24
+ %gep = getelementptr i8, ptr %ptr, i64 %xor2
+ ret ptr %gep
+}
+
+; Test with unknown disjoint bits: Ensure the transformation does not occur
+define ptr @test_with_unknown_disjoint_bits(i64 %base, ptr %ptr) {
+; CHECK-LABEL: define ptr @test_with_unknown_disjoint_bits(
+; CHECK-SAME: i64 [[BASE:%.*]], ptr [[PTR:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[XOR1:%.*]] = xor i64 [[BASE]], 8
+; CHECK-NEXT: [[XOR21:%.*]] = or disjoint i64 [[XOR1]], 16
+; CHECK-NEXT: [[GEP:%.*]] = getelementptr i8, ptr [[PTR]], i64 [[XOR21]]
+; CHECK-NEXT: ret ptr [[GEP]]
+;
+entry:
+ %xor1 = xor i64 %base, 8
+ %xor2 = xor i64 %base, 24
+ %gep = getelementptr i8, ptr %ptr, i64 %xor2
+ ret ptr %gep
+}
+
+; Test with multiple xor operations in sequence
+define ptr @test_multiple_xors(ptr %ptr) {
+; CHECK-LABEL: define ptr @test_multiple_xors(
+; CHECK-SAME: ptr [[PTR:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[BASE:%.*]] = add i64 2, 0
+; CHECK-NEXT: [[XOR1:%.*]] = xor i64 [[BASE]], 8
+; CHECK-NEXT: [[XOR21:%.*]] = or disjoint i64 [[XOR1]], 16
+; CHECK-NEXT: [[XOR32:%.*]] = or disjoint i64 [[XOR1]], 24
+; CHECK-NEXT: [[XOR43:%.*]] = or disjoint i64 [[XOR1]], 64
+; CHECK-NEXT: [[GEP2:%.*]] = getelementptr i8, ptr [[PTR]], i64 [[XOR21]]
+; CHECK-NEXT: [[GEP3:%.*]] = getelementptr i8, ptr [[PTR]], i64 [[XOR32]]
+; CHECK-NEXT: [[GEP4:%.*]] = getelementptr i8, ptr [[PTR]], i64 [[XOR43]]
+; CHECK-NEXT: ret ptr [[GEP4]]
+;
+entry:
+ %base = add i64 2,0
+ %xor1 = xor i64 %base, 8
+ %xor2 = xor i64 %base, 24 ; Should be replaced with OR
+ %xor3 = xor i64 %base, 32
+ %xor4 = xor i64 %base, 72 ; Should be replaced with OR
+ %gep2 = getelementptr i8, ptr %ptr, i64 %xor2
+ %gep3 = getelementptr i8, ptr %ptr, i64 %xor3
+ %gep4 = getelementptr i8, ptr %ptr, i64 %xor4
+ ret ptr %gep4
+}
+
+
+; Test with operand order variations
+define ptr @test_operand_order(ptr %ptr) {
+; CHECK-LABEL: define ptr @test_operand_order(
+; CHECK-SAME: ptr [[PTR:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[BASE:%.*]] = add i64 2, 0
+; CHECK-NEXT: [[XOR1:%.*]] = xor i64 [[BASE]], 12
+; CHECK-NEXT: [[XOR21:%.*]] = or disjoint i64 [[XOR1]], 12
+; CHECK-NEXT: [[GEP:%.*]] = getelementptr i8, ptr [[PTR]], i64 [[XOR21]]
+; CHECK-NEXT: ret ptr [[GEP]]
+;
+entry:
+ %base = add i64 2,0
+ %xor1 = xor i64 %base, 12
+ %xor2 = xor i64 24, %base ; Operands reversed, should still be replaced
----------------
sgundapa wrote:
Yes. I have a piece of code that checks for constant in both positions. I wrote this test to validate that code. I will remove it and not be more pedantic w.r.t tests.
https://github.com/llvm/llvm-project/pull/135788
More information about the llvm-commits
mailing list