1 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py 2 ; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=+sse4.1 | FileCheck %s --check-prefix=SSE 3 ; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=+avx2 | FileCheck %s --check-prefix=AVX 4 5 ; fold (add x, 0) -> x 6 define <4 x i32> @combine_vec_add_to_zero(<4 x i32> %a) { 7 ; SSE-LABEL: combine_vec_add_to_zero: 8 ; SSE: # %bb.0: 9 ; SSE-NEXT: retq 10 ; 11 ; AVX-LABEL: combine_vec_add_to_zero: 12 ; AVX: # %bb.0: 13 ; AVX-NEXT: retq 14 %1 = add <4 x i32> %a, zeroinitializer 15 ret <4 x i32> %1 16 } 17 18 ; fold ((c1-A)+c2) -> (c1+c2)-A 19 define <4 x i32> @combine_vec_add_constant_sub(<4 x i32> %a) { 20 ; SSE-LABEL: combine_vec_add_constant_sub: 21 ; SSE: # %bb.0: 22 ; SSE-NEXT: movdqa {{.*#+}} xmm1 = [0,2,4,6] 23 ; SSE-NEXT: psubd %xmm0, %xmm1 24 ; SSE-NEXT: movdqa %xmm1, %xmm0 25 ; SSE-NEXT: retq 26 ; 27 ; AVX-LABEL: combine_vec_add_constant_sub: 28 ; AVX: # %bb.0: 29 ; AVX-NEXT: vmovdqa {{.*#+}} xmm1 = [0,2,4,6] 30 ; AVX-NEXT: vpsubd %xmm0, %xmm1, %xmm0 31 ; AVX-NEXT: retq 32 %1 = sub <4 x i32> <i32 0, i32 1, i32 2, i32 3>, %a 33 %2 = add <4 x i32> <i32 0, i32 1, i32 2, i32 3>, %1 34 ret <4 x i32> %2 35 } 36 37 ; fold ((0-A) + B) -> B-A 38 define <4 x i32> @combine_vec_add_neg0(<4 x i32> %a, <4 x i32> %b) { 39 ; SSE-LABEL: combine_vec_add_neg0: 40 ; SSE: # %bb.0: 41 ; SSE-NEXT: psubd %xmm0, %xmm1 42 ; SSE-NEXT: movdqa %xmm1, %xmm0 43 ; SSE-NEXT: retq 44 ; 45 ; AVX-LABEL: combine_vec_add_neg0: 46 ; AVX: # %bb.0: 47 ; AVX-NEXT: vpsubd %xmm0, %xmm1, %xmm0 48 ; AVX-NEXT: retq 49 %1 = sub <4 x i32> zeroinitializer, %a 50 %2 = add <4 x i32> %1, %b 51 ret <4 x i32> %2 52 } 53 54 ; fold (A + (0-B)) -> A-B 55 define <4 x i32> @combine_vec_add_neg1(<4 x i32> %a, <4 x i32> %b) { 56 ; SSE-LABEL: combine_vec_add_neg1: 57 ; SSE: # %bb.0: 58 ; SSE-NEXT: psubd %xmm1, %xmm0 59 ; SSE-NEXT: retq 60 ; 61 ; AVX-LABEL: combine_vec_add_neg1: 62 ; AVX: # %bb.0: 63 ; AVX-NEXT: vpsubd %xmm1, %xmm0, %xmm0 64 ; AVX-NEXT: retq 65 %1 = sub <4 x i32> zeroinitializer, %b 66 %2 = add <4 x i32> %a, %1 67 ret <4 x i32> %2 68 } 69 70 ; fold (A+(B-A)) -> B 71 define <4 x i32> @combine_vec_add_sub0(<4 x i32> %a, <4 x i32> %b) { 72 ; SSE-LABEL: combine_vec_add_sub0: 73 ; SSE: # %bb.0: 74 ; SSE-NEXT: movaps %xmm1, %xmm0 75 ; SSE-NEXT: retq 76 ; 77 ; AVX-LABEL: combine_vec_add_sub0: 78 ; AVX: # %bb.0: 79 ; AVX-NEXT: vmovaps %xmm1, %xmm0 80 ; AVX-NEXT: retq 81 %1 = sub <4 x i32> %b, %a 82 %2 = add <4 x i32> %a, %1 83 ret <4 x i32> %2 84 } 85 86 ; fold ((B-A)+A) -> B 87 define <4 x i32> @combine_vec_add_sub1(<4 x i32> %a, <4 x i32> %b) { 88 ; SSE-LABEL: combine_vec_add_sub1: 89 ; SSE: # %bb.0: 90 ; SSE-NEXT: movaps %xmm1, %xmm0 91 ; SSE-NEXT: retq 92 ; 93 ; AVX-LABEL: combine_vec_add_sub1: 94 ; AVX: # %bb.0: 95 ; AVX-NEXT: vmovaps %xmm1, %xmm0 96 ; AVX-NEXT: retq 97 %1 = sub <4 x i32> %b, %a 98 %2 = add <4 x i32> %1, %a 99 ret <4 x i32> %2 100 } 101 102 ; fold (A+(B-(A+C))) to (B-C) 103 define <4 x i32> @combine_vec_add_sub_add0(<4 x i32> %a, <4 x i32> %b, <4 x i32> %c) { 104 ; SSE-LABEL: combine_vec_add_sub_add0: 105 ; SSE: # %bb.0: 106 ; SSE-NEXT: psubd %xmm2, %xmm1 107 ; SSE-NEXT: movdqa %xmm1, %xmm0 108 ; SSE-NEXT: retq 109 ; 110 ; AVX-LABEL: combine_vec_add_sub_add0: 111 ; AVX: # %bb.0: 112 ; AVX-NEXT: vpsubd %xmm2, %xmm1, %xmm0 113 ; AVX-NEXT: retq 114 %1 = add <4 x i32> %a, %c 115 %2 = sub <4 x i32> %b, %1 116 %3 = add <4 x i32> %a, %2 117 ret <4 x i32> %3 118 } 119 120 ; fold (A+(B-(C+A))) to (B-C) 121 define <4 x i32> @combine_vec_add_sub_add1(<4 x i32> %a, <4 x i32> %b, <4 x i32> %c) { 122 ; SSE-LABEL: combine_vec_add_sub_add1: 123 ; SSE: # %bb.0: 124 ; SSE-NEXT: psubd %xmm2, %xmm1 125 ; SSE-NEXT: movdqa %xmm1, %xmm0 126 ; SSE-NEXT: retq 127 ; 128 ; AVX-LABEL: combine_vec_add_sub_add1: 129 ; AVX: # %bb.0: 130 ; AVX-NEXT: vpsubd %xmm2, %xmm1, %xmm0 131 ; AVX-NEXT: retq 132 %1 = add <4 x i32> %c, %a 133 %2 = sub <4 x i32> %b, %1 134 %3 = add <4 x i32> %a, %2 135 ret <4 x i32> %3 136 } 137 138 ; fold (A+((B-A)+C)) to (B+C) 139 define <4 x i32> @combine_vec_add_sub_add2(<4 x i32> %a, <4 x i32> %b, <4 x i32> %c) { 140 ; SSE-LABEL: combine_vec_add_sub_add2: 141 ; SSE: # %bb.0: 142 ; SSE-NEXT: paddd %xmm2, %xmm1 143 ; SSE-NEXT: movdqa %xmm1, %xmm0 144 ; SSE-NEXT: retq 145 ; 146 ; AVX-LABEL: combine_vec_add_sub_add2: 147 ; AVX: # %bb.0: 148 ; AVX-NEXT: vpaddd %xmm2, %xmm1, %xmm0 149 ; AVX-NEXT: retq 150 %1 = sub <4 x i32> %b, %a 151 %2 = add <4 x i32> %1, %c 152 %3 = add <4 x i32> %a, %2 153 ret <4 x i32> %3 154 } 155 156 ; fold (A+((B-A)-C)) to (B-C) 157 define <4 x i32> @combine_vec_add_sub_add3(<4 x i32> %a, <4 x i32> %b, <4 x i32> %c) { 158 ; SSE-LABEL: combine_vec_add_sub_add3: 159 ; SSE: # %bb.0: 160 ; SSE-NEXT: psubd %xmm2, %xmm1 161 ; SSE-NEXT: movdqa %xmm1, %xmm0 162 ; SSE-NEXT: retq 163 ; 164 ; AVX-LABEL: combine_vec_add_sub_add3: 165 ; AVX: # %bb.0: 166 ; AVX-NEXT: vpsubd %xmm2, %xmm1, %xmm0 167 ; AVX-NEXT: retq 168 %1 = sub <4 x i32> %b, %a 169 %2 = sub <4 x i32> %1, %c 170 %3 = add <4 x i32> %a, %2 171 ret <4 x i32> %3 172 } 173 174 ; fold (A-B)+(C-D) to (A+C)-(B+D) when A or C is constant 175 define <4 x i32> @combine_vec_add_sub_sub(<4 x i32> %a, <4 x i32> %b, <4 x i32> %d) { 176 ; SSE-LABEL: combine_vec_add_sub_sub: 177 ; SSE: # %bb.0: 178 ; SSE-NEXT: paddd {{.*}}(%rip), %xmm0 179 ; SSE-NEXT: paddd %xmm2, %xmm1 180 ; SSE-NEXT: psubd %xmm1, %xmm0 181 ; SSE-NEXT: retq 182 ; 183 ; AVX-LABEL: combine_vec_add_sub_sub: 184 ; AVX: # %bb.0: 185 ; AVX-NEXT: vpaddd {{.*}}(%rip), %xmm0, %xmm0 186 ; AVX-NEXT: vpaddd %xmm2, %xmm1, %xmm1 187 ; AVX-NEXT: vpsubd %xmm1, %xmm0, %xmm0 188 ; AVX-NEXT: retq 189 %1 = sub <4 x i32> %a, %b 190 %2 = sub <4 x i32> <i32 0, i32 1, i32 2, i32 3>, %d 191 %3 = add <4 x i32> %1, %2 192 ret <4 x i32> %3 193 } 194 195 ; fold (a+b) -> (a|b) iff a and b share no bits. 196 define <4 x i32> @combine_vec_add_uniquebits(<4 x i32> %a, <4 x i32> %b) { 197 ; SSE-LABEL: combine_vec_add_uniquebits: 198 ; SSE: # %bb.0: 199 ; SSE-NEXT: andps {{.*}}(%rip), %xmm0 200 ; SSE-NEXT: andps {{.*}}(%rip), %xmm1 201 ; SSE-NEXT: orps %xmm1, %xmm0 202 ; SSE-NEXT: retq 203 ; 204 ; AVX-LABEL: combine_vec_add_uniquebits: 205 ; AVX: # %bb.0: 206 ; AVX-NEXT: vbroadcastss {{.*}}(%rip), %xmm2 207 ; AVX-NEXT: vandps %xmm2, %xmm0, %xmm0 208 ; AVX-NEXT: vbroadcastss {{.*}}(%rip), %xmm2 209 ; AVX-NEXT: vandps %xmm2, %xmm1, %xmm1 210 ; AVX-NEXT: vorps %xmm1, %xmm0, %xmm0 211 ; AVX-NEXT: retq 212 %1 = and <4 x i32> %a, <i32 61680, i32 61680, i32 61680, i32 61680> 213 %2 = and <4 x i32> %b, <i32 3855, i32 3855, i32 3855, i32 3855> 214 %3 = add <4 x i32> %1, %2 215 ret <4 x i32> %3 216 } 217 218 ; fold (add x, shl(0 - y, n)) -> sub(x, shl(y, n)) 219 define <4 x i32> @combine_vec_add_shl_neg0(<4 x i32> %x, <4 x i32> %y) { 220 ; SSE-LABEL: combine_vec_add_shl_neg0: 221 ; SSE: # %bb.0: 222 ; SSE-NEXT: pslld $5, %xmm1 223 ; SSE-NEXT: psubd %xmm1, %xmm0 224 ; SSE-NEXT: retq 225 ; 226 ; AVX-LABEL: combine_vec_add_shl_neg0: 227 ; AVX: # %bb.0: 228 ; AVX-NEXT: vpslld $5, %xmm1, %xmm1 229 ; AVX-NEXT: vpsubd %xmm1, %xmm0, %xmm0 230 ; AVX-NEXT: retq 231 %1 = sub <4 x i32> zeroinitializer, %y 232 %2 = shl <4 x i32> %1, <i32 5, i32 5, i32 5, i32 5> 233 %3 = add <4 x i32> %x, %2 234 ret <4 x i32> %3 235 } 236 237 ; fold (add shl(0 - y, n), x) -> sub(x, shl(y, n)) 238 define <4 x i32> @combine_vec_add_shl_neg1(<4 x i32> %x, <4 x i32> %y) { 239 ; SSE-LABEL: combine_vec_add_shl_neg1: 240 ; SSE: # %bb.0: 241 ; SSE-NEXT: pslld $5, %xmm1 242 ; SSE-NEXT: psubd %xmm1, %xmm0 243 ; SSE-NEXT: retq 244 ; 245 ; AVX-LABEL: combine_vec_add_shl_neg1: 246 ; AVX: # %bb.0: 247 ; AVX-NEXT: vpslld $5, %xmm1, %xmm1 248 ; AVX-NEXT: vpsubd %xmm1, %xmm0, %xmm0 249 ; AVX-NEXT: retq 250 %1 = sub <4 x i32> zeroinitializer, %y 251 %2 = shl <4 x i32> %1, <i32 5, i32 5, i32 5, i32 5> 252 %3 = add <4 x i32> %2, %x 253 ret <4 x i32> %3 254 } 255 256 ; (add z, (and (sbbl x, x), 1)) -> (sub z, (sbbl x, x)) 257 ; and similar xforms where the inner op is either ~0 or 0. 258 define <4 x i32> @combine_vec_add_and_compare(<4 x i32> %a0, <4 x i32> %a1, <4 x i32> %a2) { 259 ; SSE-LABEL: combine_vec_add_and_compare: 260 ; SSE: # %bb.0: 261 ; SSE-NEXT: pcmpeqd %xmm2, %xmm1 262 ; SSE-NEXT: psubd %xmm1, %xmm0 263 ; SSE-NEXT: retq 264 ; 265 ; AVX-LABEL: combine_vec_add_and_compare: 266 ; AVX: # %bb.0: 267 ; AVX-NEXT: vpcmpeqd %xmm2, %xmm1, %xmm1 268 ; AVX-NEXT: vpsubd %xmm1, %xmm0, %xmm0 269 ; AVX-NEXT: retq 270 %1 = icmp eq <4 x i32> %a1, %a2 271 %2 = sext <4 x i1> %1 to <4 x i32> 272 %3 = and <4 x i32> %2, <i32 1, i32 1, i32 1, i32 1> 273 %4 = add <4 x i32> %a0, %3 274 ret <4 x i32> %4 275 } 276 277 ; add (sext i1), X -> sub X, (zext i1) 278 define <4 x i32> @combine_vec_add_sext(<4 x i1> %a0, <4 x i32> %a1) { 279 ; SSE-LABEL: combine_vec_add_sext: 280 ; SSE: # %bb.0: 281 ; SSE-NEXT: pslld $31, %xmm0 282 ; SSE-NEXT: psrad $31, %xmm0 283 ; SSE-NEXT: paddd %xmm1, %xmm0 284 ; SSE-NEXT: retq 285 ; 286 ; AVX-LABEL: combine_vec_add_sext: 287 ; AVX: # %bb.0: 288 ; AVX-NEXT: vpslld $31, %xmm0, %xmm0 289 ; AVX-NEXT: vpsrad $31, %xmm0, %xmm0 290 ; AVX-NEXT: vpaddd %xmm1, %xmm0, %xmm0 291 ; AVX-NEXT: retq 292 %1 = sext <4 x i1> %a0 to <4 x i32> 293 %2 = add <4 x i32> %1, %a1 294 ret <4 x i32> %2 295 } 296 297 ; add (sext i1), X -> sub X, (zext i1) 298 define <4 x i32> @combine_vec_add_sextinreg(<4 x i32> %a0, <4 x i32> %a1) { 299 ; SSE-LABEL: combine_vec_add_sextinreg: 300 ; SSE: # %bb.0: 301 ; SSE-NEXT: pslld $31, %xmm0 302 ; SSE-NEXT: psrad $31, %xmm0 303 ; SSE-NEXT: paddd %xmm1, %xmm0 304 ; SSE-NEXT: retq 305 ; 306 ; AVX-LABEL: combine_vec_add_sextinreg: 307 ; AVX: # %bb.0: 308 ; AVX-NEXT: vpslld $31, %xmm0, %xmm0 309 ; AVX-NEXT: vpsrad $31, %xmm0, %xmm0 310 ; AVX-NEXT: vpaddd %xmm1, %xmm0, %xmm0 311 ; AVX-NEXT: retq 312 %1 = shl <4 x i32> %a0, <i32 31, i32 31, i32 31, i32 31> 313 %2 = ashr <4 x i32> %1, <i32 31, i32 31, i32 31, i32 31> 314 %3 = add <4 x i32> %2, %a1 315 ret <4 x i32> %3 316 } 317