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: [[N1_DEMORGAN:%.*]] = or i4 [[Y:%.*]], [[MASK:%.*]] 56; CHECK-NEXT: [[N1:%.*]] = xor i4 [[N1_DEMORGAN]], -1 57; CHECK-NEXT: [[R:%.*]] = xor i4 [[N1]], [[Y]] 58; CHECK-NEXT: ret i4 [[R]] 59; 60 %notmask = xor i4 %mask, -1 61 %n0 = xor i4 -1, %y ; %x 62 %n1 = and i4 %n0, %notmask 63 %r = xor i4 %n1, %y 64 ret i4 %r 65} 66 67define i4 @in_constant_6_vary_invmask(i4 %y, i4 %mask) { 68; CHECK-LABEL: @in_constant_6_vary_invmask( 69; CHECK-NEXT: [[N0:%.*]] = xor i4 [[Y:%.*]], 6 70; CHECK-NEXT: [[TMP1:%.*]] = and i4 [[N0]], [[MASK:%.*]] 71; CHECK-NEXT: [[R:%.*]] = xor i4 [[TMP1]], 6 72; CHECK-NEXT: ret i4 [[R]] 73; 74 %notmask = xor i4 %mask, -1 75 %n0 = xor i4 %y, 6 ; %x 76 %n1 = and i4 %n0, %notmask 77 %r = xor i4 %n1, %y 78 ret i4 %r 79} 80 81; ============================================================================ ; 82; Commutativity 83; ============================================================================ ; 84 85; Used to make sure that the IR complexity sorting does not interfere. 86declare i4 @gen4() 87 88; FIXME: should the %n1 = and i4 %im, %n0 swapped order pattern be tested? 89 90define i4 @c_1_0_0 (i4 %x, i4 %y, i4 %m) { 91; CHECK-LABEL: @c_1_0_0( 92; CHECK-NEXT: [[N0:%.*]] = xor i4 [[Y:%.*]], [[X:%.*]] 93; CHECK-NEXT: [[TMP1:%.*]] = and i4 [[N0]], [[M:%.*]] 94; CHECK-NEXT: [[R:%.*]] = xor i4 [[TMP1]], [[X]] 95; CHECK-NEXT: ret i4 [[R]] 96; 97 %im = xor i4 %m, -1 98 %n0 = xor i4 %y, %x ; swapped order 99 %n1 = and i4 %n0, %im 100 %r = xor i4 %n1, %y 101 ret i4 %r 102} 103 104define i4 @c_0_1_0 (i4 %x, i4 %y, i4 %m) { 105; CHECK-LABEL: @c_0_1_0( 106; CHECK-NEXT: [[N0:%.*]] = xor i4 [[X:%.*]], [[Y:%.*]] 107; CHECK-NEXT: [[TMP1:%.*]] = and i4 [[N0]], [[M:%.*]] 108; CHECK-NEXT: [[R:%.*]] = xor i4 [[TMP1]], [[Y]] 109; CHECK-NEXT: ret i4 [[R]] 110; 111 %im = xor i4 %m, -1 112 %n0 = xor i4 %x, %y 113 %n1 = and i4 %n0, %im 114 %r = xor i4 %n1, %x ; %x instead of %y 115 ret i4 %r 116} 117 118define i4 @c_0_0_1 (i4 %m) { 119; CHECK-LABEL: @c_0_0_1( 120; CHECK-NEXT: [[X:%.*]] = call i4 @gen4() 121; CHECK-NEXT: [[Y:%.*]] = call i4 @gen4() 122; CHECK-NEXT: [[N0:%.*]] = xor i4 [[X]], [[Y]] 123; CHECK-NEXT: [[TMP1:%.*]] = and i4 [[N0]], [[M:%.*]] 124; CHECK-NEXT: [[R:%.*]] = xor i4 [[TMP1]], [[X]] 125; CHECK-NEXT: ret i4 [[R]] 126; 127 %im = xor i4 %m, -1 128 %x = call i4 @gen4() 129 %y = call i4 @gen4() 130 %n0 = xor i4 %x, %y 131 %n1 = and i4 %n0, %im 132 %r = xor i4 %y, %n1 ; swapped order 133 ret i4 %r 134} 135 136define i4 @c_1_1_0 (i4 %x, i4 %y, i4 %m) { 137; CHECK-LABEL: @c_1_1_0( 138; CHECK-NEXT: [[N0:%.*]] = xor i4 [[Y:%.*]], [[X:%.*]] 139; CHECK-NEXT: [[TMP1:%.*]] = and i4 [[N0]], [[M:%.*]] 140; CHECK-NEXT: [[R:%.*]] = xor i4 [[TMP1]], [[Y]] 141; CHECK-NEXT: ret i4 [[R]] 142; 143 %im = xor i4 %m, -1 144 %n0 = xor i4 %y, %x ; swapped order 145 %n1 = and i4 %n0, %im 146 %r = xor i4 %n1, %x ; %x instead of %y 147 ret i4 %r 148} 149 150define i4 @c_1_0_1 (i4 %x, i4 %m) { 151; CHECK-LABEL: @c_1_0_1( 152; CHECK-NEXT: [[Y:%.*]] = call i4 @gen4() 153; CHECK-NEXT: [[N0:%.*]] = xor i4 [[Y]], [[X:%.*]] 154; CHECK-NEXT: [[TMP1:%.*]] = and i4 [[N0]], [[M:%.*]] 155; CHECK-NEXT: [[R:%.*]] = xor i4 [[TMP1]], [[X]] 156; CHECK-NEXT: ret i4 [[R]] 157; 158 %im = xor i4 %m, -1 159 %y = call i4 @gen4() 160 %n0 = xor i4 %y, %x ; swapped order 161 %n1 = and i4 %n0, %im 162 %r = xor i4 %y, %n1 ; swapped order 163 ret i4 %r 164} 165 166define i4 @c_0_1_1 (i4 %y, i4 %m) { 167; CHECK-LABEL: @c_0_1_1( 168; CHECK-NEXT: [[X:%.*]] = call i4 @gen4() 169; CHECK-NEXT: [[N0:%.*]] = xor i4 [[X]], [[Y:%.*]] 170; CHECK-NEXT: [[TMP1:%.*]] = and i4 [[N0]], [[M:%.*]] 171; CHECK-NEXT: [[R:%.*]] = xor i4 [[TMP1]], [[Y]] 172; CHECK-NEXT: ret i4 [[R]] 173; 174 %im = xor i4 %m, -1 175 %x = call i4 @gen4() 176 %n0 = xor i4 %x, %y 177 %n1 = and i4 %n0, %im 178 %r = xor i4 %x, %n1 ; swapped order, %x instead of %y 179 ret i4 %r 180} 181 182define i4 @c_1_1_1 (i4 %m) { 183; CHECK-LABEL: @c_1_1_1( 184; CHECK-NEXT: [[X:%.*]] = call i4 @gen4() 185; CHECK-NEXT: [[Y:%.*]] = call i4 @gen4() 186; CHECK-NEXT: [[N0:%.*]] = xor i4 [[Y]], [[X]] 187; CHECK-NEXT: [[TMP1:%.*]] = and i4 [[N0]], [[M:%.*]] 188; CHECK-NEXT: [[R:%.*]] = xor i4 [[TMP1]], [[Y]] 189; CHECK-NEXT: ret i4 [[R]] 190; 191 %im = xor i4 %m, -1 192 %x = call i4 @gen4() 193 %y = call i4 @gen4() 194 %n0 = xor i4 %y, %x ; swapped order 195 %n1 = and i4 %n0, %im 196 %r = xor i4 %x, %n1 ; swapped order, %x instead of %y 197 ret i4 %r 198} 199 200define i4 @commutativity_constant_varx_6_invmask(i4 %x, i4 %mask) { 201; CHECK-LABEL: @commutativity_constant_varx_6_invmask( 202; CHECK-NEXT: [[N0:%.*]] = xor i4 [[X:%.*]], 6 203; CHECK-NEXT: [[TMP1:%.*]] = and i4 [[N0]], [[MASK:%.*]] 204; CHECK-NEXT: [[R:%.*]] = xor i4 [[TMP1]], [[X]] 205; CHECK-NEXT: ret i4 [[R]] 206; 207 %notmask = xor i4 %mask, -1 208 %n0 = xor i4 %x, 6 ; %x 209 %n1 = and i4 %notmask, %n0 ; swapped 210 %r = xor i4 %n1, 6 211 ret i4 %r 212} 213 214define i4 @commutativity_constant_6_vary_invmask(i4 %y, i4 %mask) { 215; CHECK-LABEL: @commutativity_constant_6_vary_invmask( 216; CHECK-NEXT: [[N0:%.*]] = xor i4 [[Y:%.*]], 6 217; CHECK-NEXT: [[TMP1:%.*]] = and i4 [[N0]], [[MASK:%.*]] 218; CHECK-NEXT: [[R:%.*]] = xor i4 [[TMP1]], 6 219; CHECK-NEXT: ret i4 [[R]] 220; 221 %notmask = xor i4 %mask, -1 222 %n0 = xor i4 %y, 6 ; %x 223 %n1 = and i4 %notmask, %n0 ; swapped 224 %r = xor i4 %n1, %y 225 ret i4 %r 226} 227 228; ============================================================================ ; 229; Negative tests. Should not be folded. 230; ============================================================================ ; 231 232; One use only. 233 234declare void @use4(i4) 235 236define i4 @n_oneuse_D_is_ok (i4 %x, i4 %y, i4 %m) { 237; CHECK-LABEL: @n_oneuse_D_is_ok( 238; CHECK-NEXT: [[N0:%.*]] = xor i4 [[X:%.*]], [[Y:%.*]] 239; CHECK-NEXT: [[TMP1:%.*]] = and i4 [[N0]], [[M:%.*]] 240; CHECK-NEXT: [[R:%.*]] = xor i4 [[TMP1]], [[X]] 241; CHECK-NEXT: call void @use4(i4 [[N0]]) 242; CHECK-NEXT: ret i4 [[R]] 243; 244 %im = xor i4 %m, -1 245 %n0 = xor i4 %x, %y ; two uses of %n0, THIS IS OK! 246 %n1 = and i4 %n0, %im 247 %r = xor i4 %n1, %y 248 call void @use4(i4 %n0) 249 ret i4 %r 250} 251 252define i4 @n_oneuse_A (i4 %x, i4 %y, i4 %m) { 253; CHECK-LABEL: @n_oneuse_A( 254; CHECK-NEXT: [[IM:%.*]] = xor i4 [[M:%.*]], -1 255; CHECK-NEXT: [[N0:%.*]] = xor i4 [[X:%.*]], [[Y:%.*]] 256; CHECK-NEXT: [[N1:%.*]] = and i4 [[N0]], [[IM]] 257; CHECK-NEXT: [[R:%.*]] = xor i4 [[N1]], [[Y]] 258; CHECK-NEXT: call void @use4(i4 [[N1]]) 259; CHECK-NEXT: ret i4 [[R]] 260; 261 %im = xor i4 %m, -1 262 %n0 = xor i4 %x, %y 263 %n1 = and i4 %n0, %im ; two uses of %n1, which is going to be replaced 264 %r = xor i4 %n1, %y 265 call void @use4(i4 %n1) 266 ret i4 %r 267} 268 269define i4 @n_oneuse_AD (i4 %x, i4 %y, i4 %m) { 270; CHECK-LABEL: @n_oneuse_AD( 271; CHECK-NEXT: [[IM:%.*]] = xor i4 [[M:%.*]], -1 272; CHECK-NEXT: [[N0:%.*]] = xor i4 [[X:%.*]], [[Y:%.*]] 273; CHECK-NEXT: [[N1:%.*]] = and i4 [[N0]], [[IM]] 274; CHECK-NEXT: [[R:%.*]] = xor i4 [[N1]], [[Y]] 275; CHECK-NEXT: call void @use4(i4 [[N0]]) 276; CHECK-NEXT: call void @use4(i4 [[N1]]) 277; CHECK-NEXT: ret i4 [[R]] 278; 279 %im = xor i4 %m, -1 280 %n0 = xor i4 %x, %y 281 %n1 = and i4 %n0, %im ; two uses of %n1, which is going to be replaced 282 %r = xor i4 %n1, %y 283 call void @use4(i4 %n0) 284 call void @use4(i4 %n1) 285 ret i4 %r 286} 287 288; Some third variable is used 289 290define i4 @n_third_var (i4 %x, i4 %y, i4 %z, i4 %m) { 291; CHECK-LABEL: @n_third_var( 292; CHECK-NEXT: [[IM:%.*]] = xor i4 [[M:%.*]], -1 293; CHECK-NEXT: [[N0:%.*]] = xor i4 [[X:%.*]], [[Y:%.*]] 294; CHECK-NEXT: [[N1:%.*]] = and i4 [[N0]], [[IM]] 295; CHECK-NEXT: [[R:%.*]] = xor i4 [[N1]], [[Z:%.*]] 296; CHECK-NEXT: ret i4 [[R]] 297; 298 %im = xor i4 %m, -1 299 %n0 = xor i4 %x, %y 300 %n1 = and i4 %n0, %im 301 %r = xor i4 %n1, %z ; not %x or %y 302 ret i4 %r 303} 304 305define i4 @n_badxor (i4 %x, i4 %y, i4 %m) { 306; CHECK-LABEL: @n_badxor( 307; CHECK-NEXT: [[IM:%.*]] = xor i4 [[M:%.*]], 1 308; CHECK-NEXT: [[N0:%.*]] = xor i4 [[X:%.*]], [[Y:%.*]] 309; CHECK-NEXT: [[N1:%.*]] = and i4 [[N0]], [[IM]] 310; CHECK-NEXT: [[R:%.*]] = xor i4 [[N1]], [[Y]] 311; CHECK-NEXT: ret i4 [[R]] 312; 313 %im = xor i4 %m, 1 ; not -1 314 %n0 = xor i4 %x, %y 315 %n1 = and i4 %n0, %im 316 %r = xor i4 %n1, %y 317 ret i4 %r 318} 319