1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt < %s -instcombine -S | FileCheck %s 3 4; If we have a masked merge, in the form of: (M is not constant) 5; ((x ^ y) & ~M) ^ y 6; We can de-invert the M: 7; ((x ^ y) & M) ^ x 8 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, -1 17 %n0 = xor i4 %x, %y 18 %n1 = and i4 %n0, %im 19 %r = xor i4 %n1, %y 20 ret i4 %r 21} 22 23; ============================================================================ ; 24; Various cases with %x and/or %y being a constant 25; ============================================================================ ; 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, -1 33 %n0 = xor i4 %x, -1 ; %x 34 %n1 = and i4 %n0, %notmask 35 %r = xor i4 %n1, -1 36 ret i4 %r 37} 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:%.*]], 6 42; 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, -1 47 %n0 = xor i4 %x, 6 ; %x 48 %n1 = and i4 %n0, %notmask 49 %r = xor i4 %n1, 6 50 ret i4 %r 51} 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:%.*]], -1 56; CHECK-NEXT: [[R:%.*]] = or i4 [[MASK_NOT]], [[Y:%.*]] 57; CHECK-NEXT: ret i4 [[R]] 58; 59 %notmask = xor i4 %mask, -1 60 %n0 = xor i4 -1, %y ; %x 61 %n1 = and i4 %n0, %notmask 62 %r = xor i4 %n1, %y 63 ret i4 %r 64} 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:%.*]], 6 69; CHECK-NEXT: [[TMP1:%.*]] = and i4 [[N0]], [[MASK:%.*]] 70; CHECK-NEXT: [[R:%.*]] = xor i4 [[TMP1]], 6 71; CHECK-NEXT: ret i4 [[R]] 72; 73 %notmask = xor i4 %mask, -1 74 %n0 = xor i4 %y, 6 ; %x 75 %n1 = and i4 %n0, %notmask 76 %r = xor i4 %n1, %y 77 ret i4 %r 78} 79 80; ============================================================================ ; 81; Commutativity 82; ============================================================================ ; 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, -1 97 %n0 = xor i4 %y, %x ; swapped order 98 %n1 = and i4 %n0, %im 99 %r = xor i4 %n1, %y 100 ret i4 %r 101} 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, -1 111 %n0 = xor i4 %x, %y 112 %n1 = and i4 %n0, %im 113 %r = xor i4 %n1, %x ; %x instead of %y 114 ret i4 %r 115} 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, -1 127 %x = call i4 @gen4() 128 %y = call i4 @gen4() 129 %n0 = xor i4 %x, %y 130 %n1 = and i4 %n0, %im 131 %r = xor i4 %y, %n1 ; swapped order 132 ret i4 %r 133} 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, -1 143 %n0 = xor i4 %y, %x ; swapped order 144 %n1 = and i4 %n0, %im 145 %r = xor i4 %n1, %x ; %x instead of %y 146 ret i4 %r 147} 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, -1 158 %y = call i4 @gen4() 159 %n0 = xor i4 %y, %x ; swapped order 160 %n1 = and i4 %n0, %im 161 %r = xor i4 %y, %n1 ; swapped order 162 ret i4 %r 163} 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, -1 174 %x = call i4 @gen4() 175 %n0 = xor i4 %x, %y 176 %n1 = and i4 %n0, %im 177 %r = xor i4 %x, %n1 ; swapped order, %x instead of %y 178 ret i4 %r 179} 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, -1 191 %x = call i4 @gen4() 192 %y = call i4 @gen4() 193 %n0 = xor i4 %y, %x ; swapped order 194 %n1 = and i4 %n0, %im 195 %r = xor i4 %x, %n1 ; swapped order, %x instead of %y 196 ret i4 %r 197} 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:%.*]], 6 202; 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, -1 207 %n0 = xor i4 %x, 6 ; %x 208 %n1 = and i4 %notmask, %n0 ; swapped 209 %r = xor i4 %n1, 6 210 ret i4 %r 211} 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:%.*]], 6 216; CHECK-NEXT: [[TMP1:%.*]] = and i4 [[N0]], [[MASK:%.*]] 217; CHECK-NEXT: [[R:%.*]] = xor i4 [[TMP1]], 6 218; CHECK-NEXT: ret i4 [[R]] 219; 220 %notmask = xor i4 %mask, -1 221 %n0 = xor i4 %y, 6 ; %x 222 %n1 = and i4 %notmask, %n0 ; swapped 223 %r = xor i4 %n1, %y 224 ret i4 %r 225} 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, -1 244 %n0 = xor i4 %x, %y ; two uses of %n0, THIS IS OK! 245 %n1 = and i4 %n0, %im 246 %r = xor i4 %n1, %y 247 call void @use4(i4 %n0) 248 ret i4 %r 249} 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:%.*]], -1 254; 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, -1 261 %n0 = xor i4 %x, %y 262 %n1 = and i4 %n0, %im ; two uses of %n1, which is going to be replaced 263 %r = xor i4 %n1, %y 264 call void @use4(i4 %n1) 265 ret i4 %r 266} 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:%.*]], -1 271; 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, -1 279 %n0 = xor i4 %x, %y 280 %n1 = and i4 %n0, %im ; two uses of %n1, which is going to be replaced 281 %r = xor i4 %n1, %y 282 call void @use4(i4 %n0) 283 call void @use4(i4 %n1) 284 ret i4 %r 285} 286 287; Some third variable is used 288 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:%.*]], -1 292; 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, -1 298 %n0 = xor i4 %x, %y 299 %n1 = and i4 %n0, %im 300 %r = xor i4 %n1, %z ; not %x or %y 301 ret i4 %r 302} 303 304define i4 @n_badxor (i4 %x, i4 %y, i4 %m) { 305; CHECK-LABEL: @n_badxor( 306; CHECK-NEXT: [[IM:%.*]] = xor i4 [[M:%.*]], 1 307; 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 -1 313 %n0 = xor i4 %x, %y 314 %n1 = and i4 %n0, %im 315 %r = xor i4 %n1, %y 316 ret i4 %r 317} 318