; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt -passes=instcombine -S < %s | FileCheck %s ; Given: ; add (add (xor %x, -1), %y), C ; Transform it to: ; add (sub %y, %x), C-1 ;------------------------------------------------------------------------------; ; Scalar tests ;------------------------------------------------------------------------------; define i32 @t0(i32 %x, i32 %y) { ; CHECK-LABEL: @t0( ; CHECK-NEXT: [[T2:%.*]] = sub i32 [[Y:%.*]], [[X:%.*]] ; CHECK-NEXT: ret i32 [[T2]] ; %t0 = xor i32 %x, -1 %t1 = add i32 %t0, %y %t2 = add i32 %t1, 1 ret i32 %t2 } define i32 @t12(i32 %x, i32 %y) { ; CHECK-LABEL: @t12( ; CHECK-NEXT: [[TMP1:%.*]] = sub i32 [[Y:%.*]], [[X:%.*]] ; CHECK-NEXT: [[T2:%.*]] = add i32 [[TMP1]], 1 ; CHECK-NEXT: ret i32 [[T2]] ; %t0 = xor i32 %x, -1 %t1 = add i32 %t0, %y %t2 = add i32 %t1, 2 ret i32 %t2 } define i32 @add_not_add_m1(i32 %a, i32 %b) { ; CHECK-LABEL: @add_not_add_m1( ; CHECK-NEXT: [[TMP1:%.*]] = sub i32 [[A:%.*]], [[B:%.*]] ; CHECK-NEXT: [[R:%.*]] = add i32 [[TMP1]], -2 ; CHECK-NEXT: ret i32 [[R]] ; %not = xor i32 %b, -1 %add = add i32 %a, -1 %r = add i32 %add, %not ret i32 %r } ; Unfortunately not matched, because add converted to xor earlier define i32 @add_not_add_intmin(i32 %a, i32 %b) { ; CHECK-LABEL: @add_not_add_intmin( ; CHECK-NEXT: [[NOT:%.*]] = xor i32 [[B:%.*]], -1 ; CHECK-NEXT: [[ADD:%.*]] = xor i32 [[A:%.*]], -2147483648 ; CHECK-NEXT: [[R:%.*]] = add i32 [[ADD]], [[NOT]] ; CHECK-NEXT: ret i32 [[R]] ; %not = xor i32 %b, -1 %add = add i32 %a, -2147483648 %r = add i32 %add, %not ret i32 %r } ;------------------------------------------------------------------------------; ; Vector tests ;------------------------------------------------------------------------------; define <4 x i32> @t1_vec_splat(<4 x i32> %x, <4 x i32> %y) { ; CHECK-LABEL: @t1_vec_splat( ; CHECK-NEXT: [[T2:%.*]] = sub <4 x i32> [[Y:%.*]], [[X:%.*]] ; CHECK-NEXT: ret <4 x i32> [[T2]] ; %t0 = xor <4 x i32> %x, %t1 = add <4 x i32> %t0, %y %t2 = add <4 x i32> %t1, ret <4 x i32> %t2 } define <4 x i32> @t2_vec_poison0(<4 x i32> %x, <4 x i32> %y) { ; CHECK-LABEL: @t2_vec_poison0( ; CHECK-NEXT: [[T2:%.*]] = sub <4 x i32> [[Y:%.*]], [[X:%.*]] ; CHECK-NEXT: ret <4 x i32> [[T2]] ; %t0 = xor <4 x i32> %x, %t1 = add <4 x i32> %t0, %y %t2 = add <4 x i32> %t1, ret <4 x i32> %t2 } define <4 x i32> @t3_vec_poison1(<4 x i32> %x, <4 x i32> %y) { ; CHECK-LABEL: @t3_vec_poison1( ; CHECK-NEXT: [[T2:%.*]] = sub <4 x i32> [[Y:%.*]], [[X:%.*]] ; CHECK-NEXT: ret <4 x i32> [[T2]] ; %t0 = xor <4 x i32> %x, %t1 = add <4 x i32> %t0, %y %t2 = add <4 x i32> %t1, ret <4 x i32> %t2 } define <4 x i32> @t4_vec_poison2(<4 x i32> %x, <4 x i32> %y) { ; CHECK-LABEL: @t4_vec_poison2( ; CHECK-NEXT: [[T2:%.*]] = sub <4 x i32> [[Y:%.*]], [[X:%.*]] ; CHECK-NEXT: ret <4 x i32> [[T2]] ; %t0 = xor <4 x i32> %x, %t1 = add <4 x i32> %t0, %y %t2 = add <4 x i32> %t1, ret <4 x i32> %t2 } define <2 x i32> @add_not_add_m1_vec(<2 x i32> %a, <2 x i32> %b) { ; CHECK-LABEL: @add_not_add_m1_vec( ; CHECK-NEXT: [[TMP1:%.*]] = sub <2 x i32> [[A:%.*]], [[B:%.*]] ; CHECK-NEXT: [[R:%.*]] = add <2 x i32> [[TMP1]], splat (i32 -2) ; CHECK-NEXT: ret <2 x i32> [[R]] ; %not = xor <2 x i32> %b, splat (i32 -1) %add = add <2 x i32> %a, splat (i32 -1) %r = add <2 x i32> %add, %not ret <2 x i32> %r } define <2 x i32> @add_not_add_m1_vec_poison(<2 x i32> %a, <2 x i32> %b) { ; CHECK-LABEL: @add_not_add_m1_vec_poison( ; CHECK-NEXT: [[TMP1:%.*]] = sub <2 x i32> [[A:%.*]], [[B:%.*]] ; CHECK-NEXT: [[R:%.*]] = add <2 x i32> [[TMP1]], splat (i32 -2) ; CHECK-NEXT: ret <2 x i32> [[R]] ; %not = xor <2 x i32> %b, splat (i32 -1) %add = add <2 x i32> %a, %r = add <2 x i32> %add, %not ret <2 x i32> %r } ;------------------------------------------------------------------------------; ; One-use tests ;------------------------------------------------------------------------------; declare void @use32(i32) define i32 @t5(i32 %x, i32 %y) { ; CHECK-LABEL: @t5( ; CHECK-NEXT: [[T0:%.*]] = xor i32 [[X:%.*]], -1 ; CHECK-NEXT: call void @use32(i32 [[T0]]) ; CHECK-NEXT: [[T2:%.*]] = sub i32 [[Y:%.*]], [[X]] ; CHECK-NEXT: ret i32 [[T2]] ; %t0 = xor i32 %x, -1 call void @use32(i32 %t0) %t1 = add i32 %t0, %y %t2 = add i32 %t1, 1 ret i32 %t2 } define i32 @t6(i32 %x, i32 %y) { ; CHECK-LABEL: @t6( ; CHECK-NEXT: [[T0:%.*]] = xor i32 [[X:%.*]], -1 ; CHECK-NEXT: [[T1:%.*]] = add i32 [[Y:%.*]], [[T0]] ; CHECK-NEXT: call void @use32(i32 [[T1]]) ; CHECK-NEXT: [[T2:%.*]] = sub i32 [[Y]], [[X]] ; CHECK-NEXT: ret i32 [[T2]] ; %t0 = xor i32 %x, -1 %t1 = add i32 %t0, %y call void @use32(i32 %t1) %t2 = add i32 %t1, 1 ret i32 %t2 } define i32 @t7(i32 %x, i32 %y) { ; CHECK-LABEL: @t7( ; CHECK-NEXT: [[T0:%.*]] = xor i32 [[X:%.*]], -1 ; CHECK-NEXT: call void @use32(i32 [[T0]]) ; CHECK-NEXT: [[T1:%.*]] = add i32 [[Y:%.*]], [[T0]] ; CHECK-NEXT: call void @use32(i32 [[T1]]) ; CHECK-NEXT: [[T2:%.*]] = sub i32 [[Y]], [[X]] ; CHECK-NEXT: ret i32 [[T2]] ; %t0 = xor i32 %x, -1 call void @use32(i32 %t0) %t1 = add i32 %t0, %y call void @use32(i32 %t1) %t2 = add i32 %t1, 1 ret i32 %t2 } define i32 @t5_5(i32 %x, i32 %y) { ; CHECK-LABEL: @t5_5( ; CHECK-NEXT: [[T0:%.*]] = xor i32 [[X:%.*]], -1 ; CHECK-NEXT: call void @use32(i32 [[T0]]) ; CHECK-NEXT: [[TMP1:%.*]] = sub i32 [[Y:%.*]], [[X]] ; CHECK-NEXT: [[T2:%.*]] = add i32 [[TMP1]], 4 ; CHECK-NEXT: ret i32 [[T2]] ; %t0 = xor i32 %x, -1 call void @use32(i32 %t0) %t1 = add i32 %t0, %y %t2 = add i32 %t1, 5 ret i32 %t2 } define i32 @t6_5(i32 %x, i32 %y) { ; CHECK-LABEL: @t6_5( ; CHECK-NEXT: [[T0:%.*]] = xor i32 [[X:%.*]], -1 ; CHECK-NEXT: [[T1:%.*]] = add i32 [[Y:%.*]], [[T0]] ; CHECK-NEXT: call void @use32(i32 [[T1]]) ; CHECK-NEXT: [[T2:%.*]] = add i32 [[T1]], 5 ; CHECK-NEXT: ret i32 [[T2]] ; %t0 = xor i32 %x, -1 %t1 = add i32 %t0, %y call void @use32(i32 %t1) %t2 = add i32 %t1, 5 ret i32 %t2 } define i32 @t7_5(i32 %x, i32 %y) { ; CHECK-LABEL: @t7_5( ; CHECK-NEXT: [[T0:%.*]] = xor i32 [[X:%.*]], -1 ; CHECK-NEXT: call void @use32(i32 [[T0]]) ; CHECK-NEXT: [[T1:%.*]] = add i32 [[Y:%.*]], [[T0]] ; CHECK-NEXT: call void @use32(i32 [[T1]]) ; CHECK-NEXT: [[T2:%.*]] = add i32 [[T1]], 5 ; CHECK-NEXT: ret i32 [[T2]] ; %t0 = xor i32 %x, -1 call void @use32(i32 %t0) %t1 = add i32 %t0, %y call void @use32(i32 %t1) %t2 = add i32 %t1, 5 ret i32 %t2 } define i32 @t13(i32 %x, i32 %y) { ; CHECK-LABEL: @t13( ; CHECK-NEXT: [[T0:%.*]] = add i32 [[Y:%.*]], 1 ; CHECK-NEXT: call void @use32(i32 [[T0]]) ; CHECK-NEXT: [[TMP1:%.*]] = sub i32 [[Y]], [[X:%.*]] ; CHECK-NEXT: ret i32 [[TMP1]] ; %t0 = add i32 %y, 1 call void @use32(i32 %t0) %t1 = xor i32 %x, -1 %t2 = add i32 %t0, %t1 ret i32 %t2 } define i32 @t13_5(i32 %x, i32 %y) { ; CHECK-LABEL: @t13_5( ; CHECK-NEXT: [[T0:%.*]] = add i32 [[Y:%.*]], 5 ; CHECK-NEXT: call void @use32(i32 [[T0]]) ; CHECK-NEXT: [[T1:%.*]] = xor i32 [[X:%.*]], -1 ; CHECK-NEXT: [[T2:%.*]] = add i32 [[T0]], [[T1]] ; CHECK-NEXT: ret i32 [[T2]] ; %t0 = add i32 %y, 5 call void @use32(i32 %t0) %t1 = xor i32 %x, -1 %t2 = add i32 %t0, %t1 ret i32 %t2 } define i32 @t14(i32 %x, i32 %y) { ; CHECK-LABEL: @t14( ; CHECK-NEXT: [[T1:%.*]] = xor i32 [[X:%.*]], -1 ; CHECK-NEXT: call void @use32(i32 [[T1]]) ; CHECK-NEXT: [[TMP1:%.*]] = sub i32 [[Y:%.*]], [[X]] ; CHECK-NEXT: ret i32 [[TMP1]] ; %t0 = add i32 %y, 1 %t1 = xor i32 %x, -1 call void @use32(i32 %t1) %t2 = add i32 %t0, %t1 ret i32 %t2 } define i32 @t14_5(i32 %x, i32 %y) { ; CHECK-LABEL: @t14_5( ; CHECK-NEXT: [[T1:%.*]] = xor i32 [[X:%.*]], -1 ; CHECK-NEXT: call void @use32(i32 [[T1]]) ; CHECK-NEXT: [[TMP1:%.*]] = sub i32 [[Y:%.*]], [[X]] ; CHECK-NEXT: [[T2:%.*]] = add i32 [[TMP1]], 4 ; CHECK-NEXT: ret i32 [[T2]] ; %t0 = add i32 %y, 5 %t1 = xor i32 %x, -1 call void @use32(i32 %t1) %t2 = add i32 %t0, %t1 ret i32 %t2 } define i32 @t15(i32 %x, i32 %y) { ; CHECK-LABEL: @t15( ; CHECK-NEXT: [[T0:%.*]] = add i32 [[Y:%.*]], 1 ; CHECK-NEXT: call void @use32(i32 [[T0]]) ; CHECK-NEXT: [[T1:%.*]] = xor i32 [[X:%.*]], -1 ; CHECK-NEXT: call void @use32(i32 [[T1]]) ; CHECK-NEXT: [[TMP1:%.*]] = sub i32 [[Y]], [[X]] ; CHECK-NEXT: ret i32 [[TMP1]] ; %t0 = add i32 %y, 1 call void @use32(i32 %t0) %t1 = xor i32 %x, -1 call void @use32(i32 %t1) %t2 = add i32 %t0, %t1 ret i32 %t2 } define i32 @t15_5(i32 %x, i32 %y) { ; CHECK-LABEL: @t15_5( ; CHECK-NEXT: [[T0:%.*]] = add i32 [[Y:%.*]], 5 ; CHECK-NEXT: call void @use32(i32 [[T0]]) ; CHECK-NEXT: [[T1:%.*]] = xor i32 [[X:%.*]], -1 ; CHECK-NEXT: call void @use32(i32 [[T1]]) ; CHECK-NEXT: [[T2:%.*]] = add i32 [[T0]], [[T1]] ; CHECK-NEXT: ret i32 [[T2]] ; %t0 = add i32 %y, 5 call void @use32(i32 %t0) %t1 = xor i32 %x, -1 call void @use32(i32 %t1) %t2 = add i32 %t0, %t1 ret i32 %t2 } ;------------------------------------------------------------------------------; ; Commutativity ;------------------------------------------------------------------------------; declare i32 @gen32() define i32 @t8_commutative0(i32 %x) { ; CHECK-LABEL: @t8_commutative0( ; CHECK-NEXT: [[Y:%.*]] = call i32 @gen32() ; CHECK-NEXT: [[T0:%.*]] = xor i32 [[X:%.*]], -1 ; CHECK-NEXT: call void @use32(i32 [[T0]]) ; CHECK-NEXT: [[T1:%.*]] = add i32 [[Y]], [[T0]] ; CHECK-NEXT: call void @use32(i32 [[T1]]) ; CHECK-NEXT: [[T2:%.*]] = sub i32 [[Y]], [[X]] ; CHECK-NEXT: ret i32 [[T2]] ; %y = call i32 @gen32() %t0 = xor i32 %x, -1 call void @use32(i32 %t0) %t1 = add i32 %y, %t0 ; swapped call void @use32(i32 %t1) %t2 = add i32 %t1, 1 ret i32 %t2 } define i32 @t9_commutative1(i32 %x, i32 %y) { ; CHECK-LABEL: @t9_commutative1( ; CHECK-NEXT: [[T0:%.*]] = xor i32 [[X:%.*]], -1 ; CHECK-NEXT: call void @use32(i32 [[T0]]) ; CHECK-NEXT: [[T1:%.*]] = sub i32 0, [[X]] ; CHECK-NEXT: call void @use32(i32 [[T1]]) ; CHECK-NEXT: [[T2:%.*]] = sub i32 [[Y:%.*]], [[X]] ; CHECK-NEXT: ret i32 [[T2]] ; %t0 = xor i32 %x, -1 call void @use32(i32 %t0) %t1 = add i32 %t0, 1 ; +1 is not last call void @use32(i32 %t1) %t2 = add i32 %t1, %y ; ret i32 %t2 } define i32 @t10_commutative2(i32 %x) { ; CHECK-LABEL: @t10_commutative2( ; CHECK-NEXT: [[Y:%.*]] = call i32 @gen32() ; CHECK-NEXT: [[T0:%.*]] = xor i32 [[X:%.*]], -1 ; CHECK-NEXT: call void @use32(i32 [[T0]]) ; CHECK-NEXT: [[T1:%.*]] = sub i32 0, [[X]] ; CHECK-NEXT: call void @use32(i32 [[T1]]) ; CHECK-NEXT: [[T2:%.*]] = sub i32 [[Y]], [[X]] ; CHECK-NEXT: ret i32 [[T2]] ; %y = call i32 @gen32() %t0 = xor i32 %x, -1 call void @use32(i32 %t0) %t1 = add i32 %t0, 1 ; +1 is not last call void @use32(i32 %t1) %t2 = add i32 %y, %t1 ; swapped ret i32 %t2 } define i32 @add_not_add_m1_commuted(i32 %a, i32 %b) { ; CHECK-LABEL: @add_not_add_m1_commuted( ; CHECK-NEXT: [[TMP1:%.*]] = sub i32 [[A:%.*]], [[B:%.*]] ; CHECK-NEXT: [[R:%.*]] = add i32 [[TMP1]], -2 ; CHECK-NEXT: ret i32 [[R]] ; %not = xor i32 %b, -1 %add = add i32 %a, -1 %r = add i32 %not, %add ret i32 %r } define i32 @add_not_add_m1_assoc(i32 %a, i32 %b) { ; CHECK-LABEL: @add_not_add_m1_assoc( ; CHECK-NEXT: [[TMP1:%.*]] = sub i32 [[A:%.*]], [[B:%.*]] ; CHECK-NEXT: [[R:%.*]] = add i32 [[TMP1]], -2 ; CHECK-NEXT: ret i32 [[R]] ; %not = xor i32 %b, -1 %add = add i32 %not, %a %r = add i32 %add, -1 ret i32 %r } ;------------------------------------------------------------------------------; ; Basic negative tests ;------------------------------------------------------------------------------; define i32 @n11(i32 %x, i32 %y) { ; CHECK-LABEL: @n11( ; CHECK-NEXT: [[T0:%.*]] = xor i32 [[X:%.*]], 2147483647 ; CHECK-NEXT: [[T1:%.*]] = add i32 [[T0]], [[Y:%.*]] ; CHECK-NEXT: [[T2:%.*]] = add i32 [[T1]], 1 ; CHECK-NEXT: ret i32 [[T2]] ; %t0 = xor i32 %x, 2147483647 ; not -1 %t1 = add i32 %t0, %y %t2 = add i32 %t1, 1 ret i32 %t2 }