llvm.org GIT mirror llvm / master test / Transforms / Reassociate / xor_reassoc.ll
master

Tree @master (Download .tar.gz)

xor_reassoc.ll @master

884000e
598198e
 
 
 
 
884000e
598198e
 
 
884000e
598198e
884000e
 
 
 
 
598198e
 
 
 
 
 
 
884000e
598198e
884000e
 
 
 
 
598198e
 
 
 
 
 
 
 
 
884000e
 
 
 
 
598198e
 
 
 
 
 
 
 
 
 
884000e
 
 
 
 
598198e
 
 
 
 
 
 
 
 
 
884000e
 
 
 
 
 
598198e
 
 
 
 
 
 
 
 
 
884000e
 
 
 
 
 
598198e
 
 
 
 
 
 
 
 
884000e
 
 
 
 
 
598198e
 
 
 
 
 
 
 
884000e
 
 
 
 
 
598198e
 
 
 
 
 
 
 
 
884000e
598198e
 
884000e
598198e
 
884000e
 
 
 
598198e
 
 
 
 
 
 
884000e
598198e
 
884000e
 
 
 
598198e
 
 
 
 
 
 
884000e
598198e
 
884000e
 
 
 
 
598198e
 
 
 
 
 
 
884000e
598198e
 
884000e
 
 
 
 
598198e
 
 
 
 
 
 
 
 
884000e
 
 
598198e
 
 
 
 
 
 
 
884000e
 
 
598198e
 
 
 
 
 
 
 
884000e
 
 
598198e
 
 
 
 
 
 
 
884000e
 
 
598198e
 
 
 
 
 
 
 
 
884000e
598198e
 
 
 
884000e
598198e
884000e
 
 
 
 
 
 
598198e
 
 
 
 
 
 
 
 
 
884000e
598198e
884000e
 
 
 
 
 
 
 
598198e
 
 
 
 
 
 
 
 
 
 
 
 
 
884000e
598198e
 
 
 
884000e
 
 
 
 
598198e
 
 
 
 
 
 
 
 
 
 
 
884000e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
598198e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
;RUN: opt -S -reassociate < %s | FileCheck %s

; ==========================================================================
;
;   Xor reassociation general cases
;
; ==========================================================================

; (x | c1) ^ (x | c2) => (x & c3) ^ c3, where c3 = c1^c2
;
define i32 @xor1(i32 %x) {
; CHECK-LABEL: @xor1(
; CHECK-NEXT:    [[AND_RA:%.*]] = and i32 [[X:%.*]], 435
; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[AND_RA]], 435
; CHECK-NEXT:    ret i32 [[XOR]]
;
  %or = or i32 %x, 123
  %or1 = or i32 %x, 456
  %xor = xor i32 %or, %or1
  ret i32 %xor
}

; (x | c1) ^ (x | c2) => (x & c3) ^ c3, where c3 = c1^c2
;
define <2 x i32> @xor1_vec(<2 x i32> %x) {
; CHECK-LABEL: @xor1_vec(
; CHECK-NEXT:    [[AND_RA:%.*]] = and <2 x i32> [[X:%.*]], <i32 435, i32 435>
; CHECK-NEXT:    [[XOR:%.*]] = xor <2 x i32> [[AND_RA]], <i32 435, i32 435>
; CHECK-NEXT:    ret <2 x i32> [[XOR]]
;
  %or = or <2 x i32> %x, <i32 123, i32 123>
  %or1 = or <2 x i32> %x, <i32 456, i32 456>
  %xor = xor <2 x i32> %or, %or1
  ret <2 x i32> %xor
}

; Test rule : (x & c1) ^ (x & c2) = (x & (c1^c2))
; Real testing case : (x & 123) ^ y ^ (x & 345) => (x & 435) ^ y
define i32 @xor2(i32 %x, i32 %y) {
; CHECK-LABEL: @xor2(
; CHECK-NEXT:    [[AND_RA:%.*]] = and i32 [[X:%.*]], 435
; CHECK-NEXT:    [[XOR2:%.*]] = xor i32 [[AND_RA]], [[Y:%.*]]
; CHECK-NEXT:    ret i32 [[XOR2]]
;
  %and = and i32 %x, 123
  %xor = xor i32 %and, %y
  %and1 = and i32 %x, 456
  %xor2 = xor i32 %xor, %and1
  ret i32 %xor2
}

; Test rule : (x & c1) ^ (x & c2) = (x & (c1^c2))
; Real testing case : (x & 123) ^ y ^ (x & 345) => (x & 435) ^ y
define <2 x i32> @xor2_vec(<2 x i32> %x, <2 x i32> %y) {
; CHECK-LABEL: @xor2_vec(
; CHECK-NEXT:    [[AND_RA:%.*]] = and <2 x i32> [[X:%.*]], <i32 435, i32 435>
; CHECK-NEXT:    [[XOR2:%.*]] = xor <2 x i32> [[AND_RA]], [[Y:%.*]]
; CHECK-NEXT:    ret <2 x i32> [[XOR2]]
;
  %and = and <2 x i32> %x, <i32 123, i32 123>
  %xor = xor <2 x i32> %and, %y
  %and1 = and <2 x i32> %x, <i32 456, i32 456>
  %xor2 = xor <2 x i32> %xor, %and1
  ret <2 x i32> %xor2
}

; Test rule: (x | c1) ^ (x & c2) = (x & c3) ^ c1, where c3 = ~c1 ^ c2
;  c3 = ~c1 ^ c2
define i32 @xor3(i32 %x, i32 %y) {
; CHECK-LABEL: @xor3(
; CHECK-NEXT:    [[AND_RA:%.*]] = and i32 [[X:%.*]], -436
; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[Y:%.*]], 123
; CHECK-NEXT:    [[XOR1:%.*]] = xor i32 [[XOR]], [[AND_RA]]
; CHECK-NEXT:    ret i32 [[XOR1]]
;
  %or = or i32 %x, 123
  %xor = xor i32 %or, %y
  %and = and i32 %x, 456
  %xor1 = xor i32 %xor, %and
  ret i32 %xor1
}

; Test rule: (x | c1) ^ (x & c2) = (x & c3) ^ c1, where c3 = ~c1 ^ c2
;  c3 = ~c1 ^ c2
define <2 x i32> @xor3_vec(<2 x i32> %x, <2 x i32> %y) {
; CHECK-LABEL: @xor3_vec(
; CHECK-NEXT:    [[AND_RA:%.*]] = and <2 x i32> [[X:%.*]], <i32 -436, i32 -436>
; CHECK-NEXT:    [[XOR:%.*]] = xor <2 x i32> [[Y:%.*]], <i32 123, i32 123>
; CHECK-NEXT:    [[XOR1:%.*]] = xor <2 x i32> [[XOR]], [[AND_RA]]
; CHECK-NEXT:    ret <2 x i32> [[XOR1]]
;
  %or = or <2 x i32> %x, <i32 123, i32 123>
  %xor = xor <2 x i32> %or, %y
  %and = and <2 x i32> %x, <i32 456, i32 456>
  %xor1 = xor <2 x i32> %xor, %and
  ret <2 x i32> %xor1
}

; Test rule: (x | c1) ^ c2 = (x & ~c1) ^ (c1 ^ c2)
define i32 @xor4(i32 %x, i32 %y) {
; CHECK-LABEL: @xor4(
; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X:%.*]], -124
; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[Y:%.*]], 435
; CHECK-NEXT:    [[XOR1:%.*]] = xor i32 [[XOR]], [[AND]]
; CHECK-NEXT:    ret i32 [[XOR1]]
;
  %and = and i32 %x, -124
  %xor = xor i32 %y, 435
  %xor1 = xor i32 %xor, %and
  ret i32 %xor1
}

; Test rule: (x | c1) ^ c2 = (x & ~c1) ^ (c1 ^ c2)
define <2 x i32> @xor4_vec(<2 x i32> %x, <2 x i32> %y) {
; CHECK-LABEL: @xor4_vec(
; CHECK-NEXT:    [[AND:%.*]] = and <2 x i32> [[X:%.*]], <i32 -124, i32 -124>
; CHECK-NEXT:    [[XOR:%.*]] = xor <2 x i32> [[Y:%.*]], <i32 435, i32 435>
; CHECK-NEXT:    [[XOR1:%.*]] = xor <2 x i32> [[XOR]], [[AND]]
; CHECK-NEXT:    ret <2 x i32> [[XOR1]]
;
  %and = and <2 x i32> %x, <i32 -124, i32 -124>
  %xor = xor <2 x i32> %y, <i32 435, i32 435>
  %xor1 = xor <2 x i32> %xor, %and
  ret <2 x i32> %xor1
}

; ==========================================================================
;
;  Xor reassociation special cases
;
; ==========================================================================

; Special case1:
;  (x | c1) ^ (x & ~c1) = c1
define i32 @xor_special1(i32 %x, i32 %y) {
; CHECK-LABEL: @xor_special1(
; CHECK-NEXT:    [[XOR1:%.*]] = xor i32 [[Y:%.*]], 123
; CHECK-NEXT:    ret i32 [[XOR1]]
;
  %or = or i32 %x, 123
  %xor = xor i32 %or, %y
  %and = and i32 %x, -124
  %xor1 = xor i32 %xor, %and
  ret i32 %xor1
}

; Special case1:
;  (x | c1) ^ (x & ~c1) = c1
define <2 x i32> @xor_special1_vec(<2 x i32> %x, <2 x i32> %y) {
; CHECK-LABEL: @xor_special1_vec(
; CHECK-NEXT:    [[XOR1:%.*]] = xor <2 x i32> [[Y:%.*]], <i32 123, i32 123>
; CHECK-NEXT:    ret <2 x i32> [[XOR1]]
;
  %or = or <2 x i32> %x, <i32 123, i32 123>
  %xor = xor <2 x i32> %or, %y
  %and = and <2 x i32> %x, <i32 -124, i32 -124>
  %xor1 = xor <2 x i32> %xor, %and
  ret <2 x i32> %xor1
}

; Special case1:
;  (x | c1) ^ (x & c1) = x ^ c1
define i32 @xor_special2(i32 %x, i32 %y) {
; CHECK-LABEL: @xor_special2(
; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[X:%.*]], 123
; CHECK-NEXT:    [[XOR1:%.*]] = xor i32 [[XOR]], [[Y:%.*]]
; CHECK-NEXT:    ret i32 [[XOR1]]
;
  %or = or i32 %x, 123
  %xor = xor i32 %or, %y
  %and = and i32 %x, 123
  %xor1 = xor i32 %xor, %and
  ret i32 %xor1
}

; Special case1:
;  (x | c1) ^ (x & c1) = x ^ c1
define <2 x i32> @xor_special2_vec(<2 x i32> %x, <2 x i32> %y) {
; CHECK-LABEL: @xor_special2_vec(
; CHECK-NEXT:    [[XOR:%.*]] = xor <2 x i32> [[X:%.*]], <i32 123, i32 123>
; CHECK-NEXT:    [[XOR1:%.*]] = xor <2 x i32> [[XOR]], [[Y:%.*]]
; CHECK-NEXT:    ret <2 x i32> [[XOR1]]
;
  %or = or <2 x i32> %x, <i32 123, i32 123>
  %xor = xor <2 x i32> %or, %y
  %and = and <2 x i32> %x, <i32 123, i32 123>
  %xor1 = xor <2 x i32> %xor, %and
  ret <2 x i32> %xor1
}

; (x | c1) ^ (x | c1) => 0
define i32 @xor_special3(i32 %x) {
; CHECK-LABEL: @xor_special3(
; CHECK-NEXT:    ret i32 0
;
  %or = or i32 %x, 123
  %or1 = or i32 %x, 123
  %xor = xor i32 %or, %or1
  ret i32 %xor
}

; (x | c1) ^ (x | c1) => 0
define <2 x i32> @xor_special3_vec(<2 x i32> %x) {
; CHECK-LABEL: @xor_special3_vec(
; CHECK-NEXT:    ret <2 x i32> zeroinitializer
;
  %or = or <2 x i32> %x, <i32 123, i32 123>
  %or1 = or <2 x i32> %x, <i32 123, i32 123>
  %xor = xor <2 x i32> %or, %or1
  ret <2 x i32> %xor
}

; (x & c1) ^ (x & c1) => 0
define i32 @xor_special4(i32 %x) {
; CHECK-LABEL: @xor_special4(
; CHECK-NEXT:    ret i32 0
;
  %or = and i32 %x, 123
  %or1 = and i32 123, %x
  %xor = xor i32 %or, %or1
  ret i32 %xor
}

; (x & c1) ^ (x & c1) => 0
define <2 x i32> @xor_special4_vec(<2 x i32> %x) {
; CHECK-LABEL: @xor_special4_vec(
; CHECK-NEXT:    ret <2 x i32> zeroinitializer
;
  %or = and <2 x i32> %x, <i32 123, i32 123>
  %or1 = and <2 x i32> <i32 123, i32 123>, %x
  %xor = xor <2 x i32> %or, %or1
  ret <2 x i32> %xor
}

; ==========================================================================
;
;  Xor reassociation curtail code size
;
; ==========================================================================

; (x | c1) ^ (x | c2) => (x & c3) ^ c3
; is enabled if one of operands has multiple uses
;
define i32 @xor_ra_size1(i32 %x) {
; CHECK-LABEL: @xor_ra_size1(
; CHECK-NEXT:    [[OR:%.*]] = or i32 [[X:%.*]], 123
; CHECK-NEXT:    [[AND_RA:%.*]] = and i32 [[X]], 435
; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[AND_RA]], 435
; CHECK-NEXT:    [[ADD:%.*]] = add i32 [[XOR]], [[OR]]
; CHECK-NEXT:    ret i32 [[ADD]]
;
  %or = or i32 %x, 123
  %or1 = or i32 %x, 456
  %xor = xor i32 %or, %or1

  %add = add i32 %xor, %or
  ret i32 %add
}

; (x | c1) ^ (x | c2) => (x & c3) ^ c3
; is disenabled if bothf operands has multiple uses.
;
define i32 @xor_ra_size2(i32 %x) {
; CHECK-LABEL: @xor_ra_size2(
; CHECK-NEXT:    [[OR:%.*]] = or i32 [[X:%.*]], 123
; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[X]], 456
; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[OR]], [[OR1]]
; CHECK-NEXT:    [[ADD:%.*]] = add i32 [[OR1]], [[OR]]
; CHECK-NEXT:    [[ADD2:%.*]] = add i32 [[ADD]], [[XOR]]
; CHECK-NEXT:    ret i32 [[ADD2]]
;
  %or = or i32 %x, 123
  %or1 = or i32 %x, 456
  %xor = xor i32 %or, %or1

  %add = add i32 %xor, %or
  %add2 = add i32 %add, %or1
  ret i32 %add2

}


; ==========================================================================
;
;  Xor reassociation bugs
;
; ==========================================================================

@xor_bug1_data = external global <{}>, align 4
define void @xor_bug1() {
; CHECK-LABEL: @xor_bug1(
; CHECK-NEXT:    [[TMP1:%.*]] = ptrtoint i32* undef to i64
; CHECK-NEXT:    [[TMP2:%.*]] = xor i64 [[TMP1]], ptrtoint (<{}>* @xor_bug1_data to i64)
; CHECK-NEXT:    ret void
;
  %1 = ptrtoint i32* undef to i64
  %2 = xor i64 %1, ptrtoint (<{}>* @xor_bug1_data to i64)
  %3 = and i64 undef, %2
  ret void
}

; The bug was that when the compiler optimize "(x | c1)" ^ "(x & c2)", it may
; swap the two xor-subexpressions if they are not in canoninical order; however,
; when optimizer swaps two sub-expressions, if forgot to swap the cached value
; of c1 and c2 accordingly, hence cause the problem.
;
define i32 @xor_bug2(i32, i32, i32, i32) {
; CHECK-LABEL: @xor_bug2(
; CHECK-NEXT:    [[TMP5:%.*]] = mul i32 [[TMP0:%.*]], 123
; CHECK-NEXT:    [[TMP6:%.*]] = and i32 [[TMP1:%.*]], 3456789
; CHECK-NEXT:    [[TMP7:%.*]] = or i32 [[TMP6]], 4567890
; CHECK-NEXT:    [[TMP8:%.*]] = and i32 [[TMP2:%.*]], 255
; CHECK-NEXT:    [[AND_RA:%.*]] = and i32 [[TMP1]], -360490541
; CHECK-NEXT:    [[TMP9:%.*]] = xor i32 [[TMP5]], 891034567
; CHECK-NEXT:    [[TMP10:%.*]] = xor i32 [[TMP9]], [[AND_RA]]
; CHECK-NEXT:    [[TMP11:%.*]] = xor i32 [[TMP10]], [[TMP7]]
; CHECK-NEXT:    [[TMP12:%.*]] = and i32 [[TMP3:%.*]], 255
; CHECK-NEXT:    [[TMP13:%.*]] = add i32 [[TMP1]], 32
; CHECK-NEXT:    [[TMP14:%.*]] = add i32 [[TMP13]], [[TMP2]]
; CHECK-NEXT:    [[TMP15:%.*]] = add i32 [[TMP14]], [[TMP8]]
; CHECK-NEXT:    [[TMP16:%.*]] = add i32 [[TMP15]], [[TMP11]]
; CHECK-NEXT:    ret i32 [[TMP16]]
;
  %5 = mul i32 %0, 123
  %6 = add i32 %2, 24
  %7 = add i32 %1, 8
  %8 = and i32 %1, 3456789
  %9 = or i32 %8,  4567890
  %10 = and i32 %1, 543210987
  %11 = or i32 %1, 891034567
  %12 = and i32 %2, 255
  %13 = xor i32 %9, %10
  %14 = xor i32 %11, %13
  %15 = xor i32 %5, %14
  %16 = and i32 %3, 255
  %17 = xor i32 %16, 42
  %18 = add i32 %6, %7
  %19 = add i32 %18, %12
  %20 = add i32 %19, %15
  ret i32 %20
}