1 ; RUN: llc -mtriple=arm-eabi -float-abi=soft -mattr=+neon -verify-machineinstrs %s -o - \ 2 ; RUN: | FileCheck %s 3 4 define <8 x i8> @v_dup8(i8 %A) nounwind { 5 ;CHECK-LABEL: v_dup8: 6 ;CHECK: vdup.8 7 %tmp1 = insertelement <8 x i8> zeroinitializer, i8 %A, i32 0 8 %tmp2 = insertelement <8 x i8> %tmp1, i8 %A, i32 1 9 %tmp3 = insertelement <8 x i8> %tmp2, i8 %A, i32 2 10 %tmp4 = insertelement <8 x i8> %tmp3, i8 %A, i32 3 11 %tmp5 = insertelement <8 x i8> %tmp4, i8 %A, i32 4 12 %tmp6 = insertelement <8 x i8> %tmp5, i8 %A, i32 5 13 %tmp7 = insertelement <8 x i8> %tmp6, i8 %A, i32 6 14 %tmp8 = insertelement <8 x i8> %tmp7, i8 %A, i32 7 15 ret <8 x i8> %tmp8 16 } 17 18 define <4 x i16> @v_dup16(i16 %A) nounwind { 19 ;CHECK-LABEL: v_dup16: 20 ;CHECK: vdup.16 21 %tmp1 = insertelement <4 x i16> zeroinitializer, i16 %A, i32 0 22 %tmp2 = insertelement <4 x i16> %tmp1, i16 %A, i32 1 23 %tmp3 = insertelement <4 x i16> %tmp2, i16 %A, i32 2 24 %tmp4 = insertelement <4 x i16> %tmp3, i16 %A, i32 3 25 ret <4 x i16> %tmp4 26 } 27 28 define <2 x i32> @v_dup32(i32 %A) nounwind { 29 ;CHECK-LABEL: v_dup32: 30 ;CHECK: vdup.32 31 %tmp1 = insertelement <2 x i32> zeroinitializer, i32 %A, i32 0 32 %tmp2 = insertelement <2 x i32> %tmp1, i32 %A, i32 1 33 ret <2 x i32> %tmp2 34 } 35 36 define <2 x float> @v_dupfloat(float %A) nounwind { 37 ;CHECK-LABEL: v_dupfloat: 38 ;CHECK: vdup.32 39 %tmp1 = insertelement <2 x float> zeroinitializer, float %A, i32 0 40 %tmp2 = insertelement <2 x float> %tmp1, float %A, i32 1 41 ret <2 x float> %tmp2 42 } 43 44 define <16 x i8> @v_dupQ8(i8 %A) nounwind { 45 ;CHECK-LABEL: v_dupQ8: 46 ;CHECK: vdup.8 47 %tmp1 = insertelement <16 x i8> zeroinitializer, i8 %A, i32 0 48 %tmp2 = insertelement <16 x i8> %tmp1, i8 %A, i32 1 49 %tmp3 = insertelement <16 x i8> %tmp2, i8 %A, i32 2 50 %tmp4 = insertelement <16 x i8> %tmp3, i8 %A, i32 3 51 %tmp5 = insertelement <16 x i8> %tmp4, i8 %A, i32 4 52 %tmp6 = insertelement <16 x i8> %tmp5, i8 %A, i32 5 53 %tmp7 = insertelement <16 x i8> %tmp6, i8 %A, i32 6 54 %tmp8 = insertelement <16 x i8> %tmp7, i8 %A, i32 7 55 %tmp9 = insertelement <16 x i8> %tmp8, i8 %A, i32 8 56 %tmp10 = insertelement <16 x i8> %tmp9, i8 %A, i32 9 57 %tmp11 = insertelement <16 x i8> %tmp10, i8 %A, i32 10 58 %tmp12 = insertelement <16 x i8> %tmp11, i8 %A, i32 11 59 %tmp13 = insertelement <16 x i8> %tmp12, i8 %A, i32 12 60 %tmp14 = insertelement <16 x i8> %tmp13, i8 %A, i32 13 61 %tmp15 = insertelement <16 x i8> %tmp14, i8 %A, i32 14 62 %tmp16 = insertelement <16 x i8> %tmp15, i8 %A, i32 15 63 ret <16 x i8> %tmp16 64 } 65 66 define <8 x i16> @v_dupQ16(i16 %A) nounwind { 67 ;CHECK-LABEL: v_dupQ16: 68 ;CHECK: vdup.16 69 %tmp1 = insertelement <8 x i16> zeroinitializer, i16 %A, i32 0 70 %tmp2 = insertelement <8 x i16> %tmp1, i16 %A, i32 1 71 %tmp3 = insertelement <8 x i16> %tmp2, i16 %A, i32 2 72 %tmp4 = insertelement <8 x i16> %tmp3, i16 %A, i32 3 73 %tmp5 = insertelement <8 x i16> %tmp4, i16 %A, i32 4 74 %tmp6 = insertelement <8 x i16> %tmp5, i16 %A, i32 5 75 %tmp7 = insertelement <8 x i16> %tmp6, i16 %A, i32 6 76 %tmp8 = insertelement <8 x i16> %tmp7, i16 %A, i32 7 77 ret <8 x i16> %tmp8 78 } 79 80 define <4 x i32> @v_dupQ32(i32 %A) nounwind { 81 ;CHECK-LABEL: v_dupQ32: 82 ;CHECK: vdup.32 83 %tmp1 = insertelement <4 x i32> zeroinitializer, i32 %A, i32 0 84 %tmp2 = insertelement <4 x i32> %tmp1, i32 %A, i32 1 85 %tmp3 = insertelement <4 x i32> %tmp2, i32 %A, i32 2 86 %tmp4 = insertelement <4 x i32> %tmp3, i32 %A, i32 3 87 ret <4 x i32> %tmp4 88 } 89 90 define <4 x float> @v_dupQfloat(float %A) nounwind { 91 ;CHECK-LABEL: v_dupQfloat: 92 ;CHECK: vdup.32 93 %tmp1 = insertelement <4 x float> zeroinitializer, float %A, i32 0 94 %tmp2 = insertelement <4 x float> %tmp1, float %A, i32 1 95 %tmp3 = insertelement <4 x float> %tmp2, float %A, i32 2 96 %tmp4 = insertelement <4 x float> %tmp3, float %A, i32 3 97 ret <4 x float> %tmp4 98 } 99 100 ; Check to make sure it works with shuffles, too. 101 102 define <8 x i8> @v_shuffledup8(i8 %A) nounwind { 103 ;CHECK-LABEL: v_shuffledup8: 104 ;CHECK: vdup.8 105 %tmp1 = insertelement <8 x i8> undef, i8 %A, i32 0 106 %tmp2 = shufflevector <8 x i8> %tmp1, <8 x i8> undef, <8 x i32> zeroinitializer 107 ret <8 x i8> %tmp2 108 } 109 110 define <4 x i16> @v_shuffledup16(i16 %A) nounwind { 111 ;CHECK-LABEL: v_shuffledup16: 112 ;CHECK: vdup.16 113 %tmp1 = insertelement <4 x i16> undef, i16 %A, i32 0 114 %tmp2 = shufflevector <4 x i16> %tmp1, <4 x i16> undef, <4 x i32> zeroinitializer 115 ret <4 x i16> %tmp2 116 } 117 118 define <2 x i32> @v_shuffledup32(i32 %A) nounwind { 119 ;CHECK-LABEL: v_shuffledup32: 120 ;CHECK: vdup.32 121 %tmp1 = insertelement <2 x i32> undef, i32 %A, i32 0 122 %tmp2 = shufflevector <2 x i32> %tmp1, <2 x i32> undef, <2 x i32> zeroinitializer 123 ret <2 x i32> %tmp2 124 } 125 126 define <2 x float> @v_shuffledupfloat(float %A) nounwind { 127 ;CHECK-LABEL: v_shuffledupfloat: 128 ;CHECK: vdup.32 129 %tmp1 = insertelement <2 x float> undef, float %A, i32 0 130 %tmp2 = shufflevector <2 x float> %tmp1, <2 x float> undef, <2 x i32> zeroinitializer 131 ret <2 x float> %tmp2 132 } 133 134 define <16 x i8> @v_shuffledupQ8(i8 %A) nounwind { 135 ;CHECK-LABEL: v_shuffledupQ8: 136 ;CHECK: vdup.8 137 %tmp1 = insertelement <16 x i8> undef, i8 %A, i32 0 138 %tmp2 = shufflevector <16 x i8> %tmp1, <16 x i8> undef, <16 x i32> zeroinitializer 139 ret <16 x i8> %tmp2 140 } 141 142 define <8 x i16> @v_shuffledupQ16(i16 %A) nounwind { 143 ;CHECK-LABEL: v_shuffledupQ16: 144 ;CHECK: vdup.16 145 %tmp1 = insertelement <8 x i16> undef, i16 %A, i32 0 146 %tmp2 = shufflevector <8 x i16> %tmp1, <8 x i16> undef, <8 x i32> zeroinitializer 147 ret <8 x i16> %tmp2 148 } 149 150 define <4 x i32> @v_shuffledupQ32(i32 %A) nounwind { 151 ;CHECK-LABEL: v_shuffledupQ32: 152 ;CHECK: vdup.32 153 %tmp1 = insertelement <4 x i32> undef, i32 %A, i32 0 154 %tmp2 = shufflevector <4 x i32> %tmp1, <4 x i32> undef, <4 x i32> zeroinitializer 155 ret <4 x i32> %tmp2 156 } 157 158 define <4 x float> @v_shuffledupQfloat(float %A) nounwind { 159 ;CHECK-LABEL: v_shuffledupQfloat: 160 ;CHECK: vdup.32 161 %tmp1 = insertelement <4 x float> undef, float %A, i32 0 162 %tmp2 = shufflevector <4 x float> %tmp1, <4 x float> undef, <4 x i32> zeroinitializer 163 ret <4 x float> %tmp2 164 } 165 166 define <8 x i8> @vduplane8(<8 x i8>* %A) nounwind { 167 ;CHECK-LABEL: vduplane8: 168 ;CHECK: vdup.8 169 %tmp1 = load <8 x i8>* %A 170 %tmp2 = shufflevector <8 x i8> %tmp1, <8 x i8> undef, <8 x i32> < i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1 > 171 ret <8 x i8> %tmp2 172 } 173 174 define <4 x i16> @vduplane16(<4 x i16>* %A) nounwind { 175 ;CHECK-LABEL: vduplane16: 176 ;CHECK: vdup.16 177 %tmp1 = load <4 x i16>* %A 178 %tmp2 = shufflevector <4 x i16> %tmp1, <4 x i16> undef, <4 x i32> < i32 1, i32 1, i32 1, i32 1 > 179 ret <4 x i16> %tmp2 180 } 181 182 define <2 x i32> @vduplane32(<2 x i32>* %A) nounwind { 183 ;CHECK-LABEL: vduplane32: 184 ;CHECK: vdup.32 185 %tmp1 = load <2 x i32>* %A 186 %tmp2 = shufflevector <2 x i32> %tmp1, <2 x i32> undef, <2 x i32> < i32 1, i32 1 > 187 ret <2 x i32> %tmp2 188 } 189 190 define <2 x float> @vduplanefloat(<2 x float>* %A) nounwind { 191 ;CHECK-LABEL: vduplanefloat: 192 ;CHECK: vdup.32 193 %tmp1 = load <2 x float>* %A 194 %tmp2 = shufflevector <2 x float> %tmp1, <2 x float> undef, <2 x i32> < i32 1, i32 1 > 195 ret <2 x float> %tmp2 196 } 197 198 define <16 x i8> @vduplaneQ8(<8 x i8>* %A) nounwind { 199 ;CHECK-LABEL: vduplaneQ8: 200 ;CHECK: vdup.8 201 %tmp1 = load <8 x i8>* %A 202 %tmp2 = shufflevector <8 x i8> %tmp1, <8 x i8> undef, <16 x i32> < i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1 > 203 ret <16 x i8> %tmp2 204 } 205 206 define <8 x i16> @vduplaneQ16(<4 x i16>* %A) nounwind { 207 ;CHECK-LABEL: vduplaneQ16: 208 ;CHECK: vdup.16 209 %tmp1 = load <4 x i16>* %A 210 %tmp2 = shufflevector <4 x i16> %tmp1, <4 x i16> undef, <8 x i32> < i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1 > 211 ret <8 x i16> %tmp2 212 } 213 214 define <4 x i32> @vduplaneQ32(<2 x i32>* %A) nounwind { 215 ;CHECK-LABEL: vduplaneQ32: 216 ;CHECK: vdup.32 217 %tmp1 = load <2 x i32>* %A 218 %tmp2 = shufflevector <2 x i32> %tmp1, <2 x i32> undef, <4 x i32> < i32 1, i32 1, i32 1, i32 1 > 219 ret <4 x i32> %tmp2 220 } 221 222 define <4 x float> @vduplaneQfloat(<2 x float>* %A) nounwind { 223 ;CHECK-LABEL: vduplaneQfloat: 224 ;CHECK: vdup.32 225 %tmp1 = load <2 x float>* %A 226 %tmp2 = shufflevector <2 x float> %tmp1, <2 x float> undef, <4 x i32> < i32 1, i32 1, i32 1, i32 1 > 227 ret <4 x float> %tmp2 228 } 229 230 define <2 x i64> @foo(<2 x i64> %arg0_int64x1_t) nounwind readnone { 231 entry: 232 %0 = shufflevector <2 x i64> %arg0_int64x1_t, <2 x i64> undef, <2 x i32> <i32 1, i32 1> 233 ret <2 x i64> %0 234 } 235 236 define <2 x i64> @bar(<2 x i64> %arg0_int64x1_t) nounwind readnone { 237 entry: 238 %0 = shufflevector <2 x i64> %arg0_int64x1_t, <2 x i64> undef, <2 x i32> <i32 0, i32 0> 239 ret <2 x i64> %0 240 } 241 242 define <2 x double> @baz(<2 x double> %arg0_int64x1_t) nounwind readnone { 243 entry: 244 %0 = shufflevector <2 x double> %arg0_int64x1_t, <2 x double> undef, <2 x i32> <i32 1, i32 1> 245 ret <2 x double> %0 246 } 247 248 define <2 x double> @qux(<2 x double> %arg0_int64x1_t) nounwind readnone { 249 entry: 250 %0 = shufflevector <2 x double> %arg0_int64x1_t, <2 x double> undef, <2 x i32> <i32 0, i32 0> 251 ret <2 x double> %0 252 } 253 254 ; Radar 7373643 255 ;CHECK-LABEL: redundantVdup: 256 ;CHECK: vmov.i8 257 ;CHECK-NOT: vdup.8 258 ;CHECK: vstr 259 define void @redundantVdup(<8 x i8>* %ptr) nounwind { 260 %1 = insertelement <8 x i8> undef, i8 -128, i32 0 261 %2 = shufflevector <8 x i8> %1, <8 x i8> undef, <8 x i32> zeroinitializer 262 store <8 x i8> %2, <8 x i8>* %ptr, align 8 263 ret void 264 } 265 266 define <4 x i32> @tdupi(i32 %x, i32 %y) { 267 ;CHECK-LABEL: tdupi: 268 ;CHECK: vdup.32 269 %1 = insertelement <4 x i32> undef, i32 %x, i32 0 270 %2 = insertelement <4 x i32> %1, i32 %x, i32 1 271 %3 = insertelement <4 x i32> %2, i32 %x, i32 2 272 %4 = insertelement <4 x i32> %3, i32 %y, i32 3 273 ret <4 x i32> %4 274 } 275 276 define <4 x float> @tdupf(float %x, float %y) { 277 ;CHECK-LABEL: tdupf: 278 ;CHECK: vdup.32 279 %1 = insertelement <4 x float> undef, float %x, i32 0 280 %2 = insertelement <4 x float> %1, float %x, i32 1 281 %3 = insertelement <4 x float> %2, float %x, i32 2 282 %4 = insertelement <4 x float> %3, float %y, i32 3 283 ret <4 x float> %4 284 } 285 286 ; This test checks that when splatting an element from a vector into another, 287 ; the value isn't moved out to GPRs first. 288 define <4 x i32> @tduplane(<4 x i32> %invec) { 289 ;CHECK-LABEL: tduplane: 290 ;CHECK-NOT: vmov {{.*}}, d16[1] 291 ;CHECK: vdup.32 {{.*}}, d16[1] 292 %in = extractelement <4 x i32> %invec, i32 1 293 %1 = insertelement <4 x i32> undef, i32 %in, i32 0 294 %2 = insertelement <4 x i32> %1, i32 %in, i32 1 295 %3 = insertelement <4 x i32> %2, i32 %in, i32 2 296 %4 = insertelement <4 x i32> %3, i32 255, i32 3 297 ret <4 x i32> %4 298 } 299 300 define <2 x float> @check_f32(<4 x float> %v) nounwind { 301 ;CHECK-LABEL: check_f32: 302 ;CHECK: vdup.32 {{.*}}, d{{..}}[1] 303 %x = extractelement <4 x float> %v, i32 3 304 %1 = insertelement <2 x float> undef, float %x, i32 0 305 %2 = insertelement <2 x float> %1, float %x, i32 1 306 ret <2 x float> %2 307 } 308 309 define <2 x i32> @check_i32(<4 x i32> %v) nounwind { 310 ;CHECK-LABEL: check_i32: 311 ;CHECK: vdup.32 {{.*}}, d{{..}}[1] 312 %x = extractelement <4 x i32> %v, i32 3 313 %1 = insertelement <2 x i32> undef, i32 %x, i32 0 314 %2 = insertelement <2 x i32> %1, i32 %x, i32 1 315 ret <2 x i32> %2 316 } 317 318 define <4 x i16> @check_i16(<8 x i16> %v) nounwind { 319 ;CHECK-LABEL: check_i16: 320 ;CHECK: vdup.16 {{.*}}, d{{..}}[3] 321 %x = extractelement <8 x i16> %v, i32 3 322 %1 = insertelement <4 x i16> undef, i16 %x, i32 0 323 %2 = insertelement <4 x i16> %1, i16 %x, i32 1 324 ret <4 x i16> %2 325 } 326 327 define <8 x i8> @check_i8(<16 x i8> %v) nounwind { 328 ;CHECK-LABEL: check_i8: 329 ;CHECK: vdup.8 {{.*}}, d{{..}}[3] 330 %x = extractelement <16 x i8> %v, i32 3 331 %1 = insertelement <8 x i8> undef, i8 %x, i32 0 332 %2 = insertelement <8 x i8> %1, i8 %x, i32 1 333 ret <8 x i8> %2 334 } 335 336 ; Check that an SPR splat produces a vdup. 337 338 define <2 x float> @check_spr_splat2(<2 x float> %p, i16 %q) { 339 ;CHECK-LABEL: check_spr_splat2: 340 ;CHECK: vdup.32 d 341 %conv = sitofp i16 %q to float 342 %splat.splatinsert = insertelement <2 x float> undef, float %conv, i32 0 343 %splat.splat = shufflevector <2 x float> %splat.splatinsert, <2 x float> undef, <2 x i32> zeroinitializer 344 %sub = fsub <2 x float> %splat.splat, %p 345 ret <2 x float> %sub 346 } 347 348 define <4 x float> @check_spr_splat4(<4 x float> %p, i16 %q) { 349 ;CHECK-LABEL: check_spr_splat4: 350 ;CHECK: vdup.32 q 351 %conv = sitofp i16 %q to float 352 %splat.splatinsert = insertelement <4 x float> undef, float %conv, i32 0 353 %splat.splat = shufflevector <4 x float> %splat.splatinsert, <4 x float> undef, <4 x i32> zeroinitializer 354 %sub = fsub <4 x float> %splat.splat, %p 355 ret <4 x float> %sub 356 } 357 358 define <4 x float> @check_spr_splat4_lane1(<4 x float> %p, i16 %q) { 359 ;CHECK-LABEL: check_spr_splat4_lane1: 360 ;CHECK: vdup.32 q{{.*}}, d{{.*}}[1] 361 %conv = sitofp i16 %q to float 362 %splat.splatinsert = insertelement <4 x float> undef, float %conv, i32 1 363 %splat.splat = shufflevector <4 x float> %splat.splatinsert, <4 x float> undef, <4 x i32> <i32 1, i32 1, i32 1, i32 1> 364 %sub = fsub <4 x float> %splat.splat, %p 365 ret <4 x float> %sub 366 } 367