318 lines · plain
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py2; RUN: opt < %s -passes=instcombine -S | FileCheck %s3 4; If we have a masked merge, in the form of: (M is not constant)5; ((x ^ y) & ~M) ^ y6; We can de-invert the M:7; ((x ^ y) & M) ^ x8 9define i4 @scalar (i4 %x, i4 %y, i4 %m) {10; CHECK-LABEL: @scalar(11; CHECK-NEXT: [[N0:%.*]] = xor i4 [[X:%.*]], [[Y:%.*]]12; CHECK-NEXT: [[TMP1:%.*]] = and i4 [[N0]], [[M:%.*]]13; CHECK-NEXT: [[R:%.*]] = xor i4 [[TMP1]], [[X]]14; CHECK-NEXT: ret i4 [[R]]15;16 %im = xor i4 %m, -117 %n0 = xor i4 %x, %y18 %n1 = and i4 %n0, %im19 %r = xor i4 %n1, %y20 ret i4 %r21}22 23; ============================================================================ ;24; Various cases with %x and/or %y being a constant25; ============================================================================ ;26 27define i4 @in_constant_varx_mone_invmask(i4 %x, i4 %mask) {28; CHECK-LABEL: @in_constant_varx_mone_invmask(29; CHECK-NEXT: [[N1_DEMORGAN:%.*]] = or i4 [[X:%.*]], [[MASK:%.*]]30; CHECK-NEXT: ret i4 [[N1_DEMORGAN]]31;32 %notmask = xor i4 %mask, -133 %n0 = xor i4 %x, -1 ; %x34 %n1 = and i4 %n0, %notmask35 %r = xor i4 %n1, -136 ret i4 %r37}38 39define i4 @in_constant_varx_6_invmask(i4 %x, i4 %mask) {40; CHECK-LABEL: @in_constant_varx_6_invmask(41; CHECK-NEXT: [[N0:%.*]] = xor i4 [[X:%.*]], 642; CHECK-NEXT: [[TMP1:%.*]] = and i4 [[N0]], [[MASK:%.*]]43; CHECK-NEXT: [[R:%.*]] = xor i4 [[TMP1]], [[X]]44; CHECK-NEXT: ret i4 [[R]]45;46 %notmask = xor i4 %mask, -147 %n0 = xor i4 %x, 6 ; %x48 %n1 = and i4 %n0, %notmask49 %r = xor i4 %n1, 650 ret i4 %r51}52 53define i4 @in_constant_mone_vary_invmask(i4 %y, i4 %mask) {54; CHECK-LABEL: @in_constant_mone_vary_invmask(55; CHECK-NEXT: [[MASK_NOT:%.*]] = xor i4 [[MASK:%.*]], -156; CHECK-NEXT: [[R:%.*]] = or i4 [[Y:%.*]], [[MASK_NOT]]57; CHECK-NEXT: ret i4 [[R]]58;59 %notmask = xor i4 %mask, -160 %n0 = xor i4 -1, %y ; %x61 %n1 = and i4 %n0, %notmask62 %r = xor i4 %n1, %y63 ret i4 %r64}65 66define i4 @in_constant_6_vary_invmask(i4 %y, i4 %mask) {67; CHECK-LABEL: @in_constant_6_vary_invmask(68; CHECK-NEXT: [[N0:%.*]] = xor i4 [[Y:%.*]], 669; CHECK-NEXT: [[TMP1:%.*]] = and i4 [[N0]], [[MASK:%.*]]70; CHECK-NEXT: [[R:%.*]] = xor i4 [[TMP1]], 671; CHECK-NEXT: ret i4 [[R]]72;73 %notmask = xor i4 %mask, -174 %n0 = xor i4 %y, 6 ; %x75 %n1 = and i4 %n0, %notmask76 %r = xor i4 %n1, %y77 ret i4 %r78}79 80; ============================================================================ ;81; Commutativity82; ============================================================================ ;83 84; Used to make sure that the IR complexity sorting does not interfere.85declare i4 @gen4()86 87; FIXME: should the %n1 = and i4 %im, %n0 swapped order pattern be tested?88 89define i4 @c_1_0_0 (i4 %x, i4 %y, i4 %m) {90; CHECK-LABEL: @c_1_0_0(91; CHECK-NEXT: [[N0:%.*]] = xor i4 [[Y:%.*]], [[X:%.*]]92; CHECK-NEXT: [[TMP1:%.*]] = and i4 [[N0]], [[M:%.*]]93; CHECK-NEXT: [[R:%.*]] = xor i4 [[TMP1]], [[X]]94; CHECK-NEXT: ret i4 [[R]]95;96 %im = xor i4 %m, -197 %n0 = xor i4 %y, %x ; swapped order98 %n1 = and i4 %n0, %im99 %r = xor i4 %n1, %y100 ret i4 %r101}102 103define i4 @c_0_1_0 (i4 %x, i4 %y, i4 %m) {104; CHECK-LABEL: @c_0_1_0(105; CHECK-NEXT: [[N0:%.*]] = xor i4 [[X:%.*]], [[Y:%.*]]106; CHECK-NEXT: [[TMP1:%.*]] = and i4 [[N0]], [[M:%.*]]107; CHECK-NEXT: [[R:%.*]] = xor i4 [[TMP1]], [[Y]]108; CHECK-NEXT: ret i4 [[R]]109;110 %im = xor i4 %m, -1111 %n0 = xor i4 %x, %y112 %n1 = and i4 %n0, %im113 %r = xor i4 %n1, %x ; %x instead of %y114 ret i4 %r115}116 117define i4 @c_0_0_1 (i4 %m) {118; CHECK-LABEL: @c_0_0_1(119; CHECK-NEXT: [[X:%.*]] = call i4 @gen4()120; CHECK-NEXT: [[Y:%.*]] = call i4 @gen4()121; CHECK-NEXT: [[N0:%.*]] = xor i4 [[X]], [[Y]]122; CHECK-NEXT: [[TMP1:%.*]] = and i4 [[N0]], [[M:%.*]]123; CHECK-NEXT: [[R:%.*]] = xor i4 [[TMP1]], [[X]]124; CHECK-NEXT: ret i4 [[R]]125;126 %im = xor i4 %m, -1127 %x = call i4 @gen4()128 %y = call i4 @gen4()129 %n0 = xor i4 %x, %y130 %n1 = and i4 %n0, %im131 %r = xor i4 %y, %n1 ; swapped order132 ret i4 %r133}134 135define i4 @c_1_1_0 (i4 %x, i4 %y, i4 %m) {136; CHECK-LABEL: @c_1_1_0(137; CHECK-NEXT: [[N0:%.*]] = xor i4 [[Y:%.*]], [[X:%.*]]138; CHECK-NEXT: [[TMP1:%.*]] = and i4 [[N0]], [[M:%.*]]139; CHECK-NEXT: [[R:%.*]] = xor i4 [[TMP1]], [[Y]]140; CHECK-NEXT: ret i4 [[R]]141;142 %im = xor i4 %m, -1143 %n0 = xor i4 %y, %x ; swapped order144 %n1 = and i4 %n0, %im145 %r = xor i4 %n1, %x ; %x instead of %y146 ret i4 %r147}148 149define i4 @c_1_0_1 (i4 %x, i4 %m) {150; CHECK-LABEL: @c_1_0_1(151; CHECK-NEXT: [[Y:%.*]] = call i4 @gen4()152; CHECK-NEXT: [[N0:%.*]] = xor i4 [[Y]], [[X:%.*]]153; CHECK-NEXT: [[TMP1:%.*]] = and i4 [[N0]], [[M:%.*]]154; CHECK-NEXT: [[R:%.*]] = xor i4 [[TMP1]], [[X]]155; CHECK-NEXT: ret i4 [[R]]156;157 %im = xor i4 %m, -1158 %y = call i4 @gen4()159 %n0 = xor i4 %y, %x ; swapped order160 %n1 = and i4 %n0, %im161 %r = xor i4 %y, %n1 ; swapped order162 ret i4 %r163}164 165define i4 @c_0_1_1 (i4 %y, i4 %m) {166; CHECK-LABEL: @c_0_1_1(167; CHECK-NEXT: [[X:%.*]] = call i4 @gen4()168; CHECK-NEXT: [[N0:%.*]] = xor i4 [[X]], [[Y:%.*]]169; CHECK-NEXT: [[TMP1:%.*]] = and i4 [[N0]], [[M:%.*]]170; CHECK-NEXT: [[R:%.*]] = xor i4 [[TMP1]], [[Y]]171; CHECK-NEXT: ret i4 [[R]]172;173 %im = xor i4 %m, -1174 %x = call i4 @gen4()175 %n0 = xor i4 %x, %y176 %n1 = and i4 %n0, %im177 %r = xor i4 %x, %n1 ; swapped order, %x instead of %y178 ret i4 %r179}180 181define i4 @c_1_1_1 (i4 %m) {182; CHECK-LABEL: @c_1_1_1(183; CHECK-NEXT: [[X:%.*]] = call i4 @gen4()184; CHECK-NEXT: [[Y:%.*]] = call i4 @gen4()185; CHECK-NEXT: [[N0:%.*]] = xor i4 [[Y]], [[X]]186; CHECK-NEXT: [[TMP1:%.*]] = and i4 [[N0]], [[M:%.*]]187; CHECK-NEXT: [[R:%.*]] = xor i4 [[TMP1]], [[Y]]188; CHECK-NEXT: ret i4 [[R]]189;190 %im = xor i4 %m, -1191 %x = call i4 @gen4()192 %y = call i4 @gen4()193 %n0 = xor i4 %y, %x ; swapped order194 %n1 = and i4 %n0, %im195 %r = xor i4 %x, %n1 ; swapped order, %x instead of %y196 ret i4 %r197}198 199define i4 @commutativity_constant_varx_6_invmask(i4 %x, i4 %mask) {200; CHECK-LABEL: @commutativity_constant_varx_6_invmask(201; CHECK-NEXT: [[N0:%.*]] = xor i4 [[X:%.*]], 6202; CHECK-NEXT: [[TMP1:%.*]] = and i4 [[N0]], [[MASK:%.*]]203; CHECK-NEXT: [[R:%.*]] = xor i4 [[TMP1]], [[X]]204; CHECK-NEXT: ret i4 [[R]]205;206 %notmask = xor i4 %mask, -1207 %n0 = xor i4 %x, 6 ; %x208 %n1 = and i4 %notmask, %n0 ; swapped209 %r = xor i4 %n1, 6210 ret i4 %r211}212 213define i4 @commutativity_constant_6_vary_invmask(i4 %y, i4 %mask) {214; CHECK-LABEL: @commutativity_constant_6_vary_invmask(215; CHECK-NEXT: [[N0:%.*]] = xor i4 [[Y:%.*]], 6216; CHECK-NEXT: [[TMP1:%.*]] = and i4 [[N0]], [[MASK:%.*]]217; CHECK-NEXT: [[R:%.*]] = xor i4 [[TMP1]], 6218; CHECK-NEXT: ret i4 [[R]]219;220 %notmask = xor i4 %mask, -1221 %n0 = xor i4 %y, 6 ; %x222 %n1 = and i4 %notmask, %n0 ; swapped223 %r = xor i4 %n1, %y224 ret i4 %r225}226 227; ============================================================================ ;228; Negative tests. Should not be folded.229; ============================================================================ ;230 231; One use only.232 233declare void @use4(i4)234 235define i4 @n_oneuse_D_is_ok (i4 %x, i4 %y, i4 %m) {236; CHECK-LABEL: @n_oneuse_D_is_ok(237; CHECK-NEXT: [[N0:%.*]] = xor i4 [[X:%.*]], [[Y:%.*]]238; CHECK-NEXT: [[TMP1:%.*]] = and i4 [[N0]], [[M:%.*]]239; CHECK-NEXT: [[R:%.*]] = xor i4 [[TMP1]], [[X]]240; CHECK-NEXT: call void @use4(i4 [[N0]])241; CHECK-NEXT: ret i4 [[R]]242;243 %im = xor i4 %m, -1244 %n0 = xor i4 %x, %y ; two uses of %n0, THIS IS OK!245 %n1 = and i4 %n0, %im246 %r = xor i4 %n1, %y247 call void @use4(i4 %n0)248 ret i4 %r249}250 251define i4 @n_oneuse_A (i4 %x, i4 %y, i4 %m) {252; CHECK-LABEL: @n_oneuse_A(253; CHECK-NEXT: [[IM:%.*]] = xor i4 [[M:%.*]], -1254; CHECK-NEXT: [[N0:%.*]] = xor i4 [[X:%.*]], [[Y:%.*]]255; CHECK-NEXT: [[N1:%.*]] = and i4 [[N0]], [[IM]]256; CHECK-NEXT: [[R:%.*]] = xor i4 [[N1]], [[Y]]257; CHECK-NEXT: call void @use4(i4 [[N1]])258; CHECK-NEXT: ret i4 [[R]]259;260 %im = xor i4 %m, -1261 %n0 = xor i4 %x, %y262 %n1 = and i4 %n0, %im ; two uses of %n1, which is going to be replaced263 %r = xor i4 %n1, %y264 call void @use4(i4 %n1)265 ret i4 %r266}267 268define i4 @n_oneuse_AD (i4 %x, i4 %y, i4 %m) {269; CHECK-LABEL: @n_oneuse_AD(270; CHECK-NEXT: [[IM:%.*]] = xor i4 [[M:%.*]], -1271; CHECK-NEXT: [[N0:%.*]] = xor i4 [[X:%.*]], [[Y:%.*]]272; CHECK-NEXT: [[N1:%.*]] = and i4 [[N0]], [[IM]]273; CHECK-NEXT: [[R:%.*]] = xor i4 [[N1]], [[Y]]274; CHECK-NEXT: call void @use4(i4 [[N0]])275; CHECK-NEXT: call void @use4(i4 [[N1]])276; CHECK-NEXT: ret i4 [[R]]277;278 %im = xor i4 %m, -1279 %n0 = xor i4 %x, %y280 %n1 = and i4 %n0, %im ; two uses of %n1, which is going to be replaced281 %r = xor i4 %n1, %y282 call void @use4(i4 %n0)283 call void @use4(i4 %n1)284 ret i4 %r285}286 287; Some third variable is used288 289define i4 @n_third_var (i4 %x, i4 %y, i4 %z, i4 %m) {290; CHECK-LABEL: @n_third_var(291; CHECK-NEXT: [[IM:%.*]] = xor i4 [[M:%.*]], -1292; CHECK-NEXT: [[N0:%.*]] = xor i4 [[X:%.*]], [[Y:%.*]]293; CHECK-NEXT: [[N1:%.*]] = and i4 [[N0]], [[IM]]294; CHECK-NEXT: [[R:%.*]] = xor i4 [[N1]], [[Z:%.*]]295; CHECK-NEXT: ret i4 [[R]]296;297 %im = xor i4 %m, -1298 %n0 = xor i4 %x, %y299 %n1 = and i4 %n0, %im300 %r = xor i4 %n1, %z ; not %x or %y301 ret i4 %r302}303 304define i4 @n_badxor (i4 %x, i4 %y, i4 %m) {305; CHECK-LABEL: @n_badxor(306; CHECK-NEXT: [[IM:%.*]] = xor i4 [[M:%.*]], 1307; CHECK-NEXT: [[N0:%.*]] = xor i4 [[X:%.*]], [[Y:%.*]]308; CHECK-NEXT: [[N1:%.*]] = and i4 [[N0]], [[IM]]309; CHECK-NEXT: [[R:%.*]] = xor i4 [[N1]], [[Y]]310; CHECK-NEXT: ret i4 [[R]]311;312 %im = xor i4 %m, 1 ; not -1313 %n0 = xor i4 %x, %y314 %n1 = and i4 %n0, %im315 %r = xor i4 %n1, %y316 ret i4 %r317}318