1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py 2; RUN: llc < %s -mtriple=armv7-none-eabi | FileCheck %s 3 4; PR7158 5define i32 @test_pr7158() nounwind { 6; CHECK-LABEL: test_pr7158: 7; CHECK: @ %bb.0: @ %bb.nph55.bb.nph55.split_crit_edge 8; CHECK-NEXT: .LBB0_1: @ %bb.i19 9; CHECK-NEXT: @ =>This Inner Loop Header: Depth=1 10; CHECK-NEXT: b .LBB0_1 11bb.nph55.bb.nph55.split_crit_edge: 12 br label %bb3 13 14bb3: ; preds = %bb3, %bb.nph55.bb.nph55.split_crit_edge 15 br i1 undef, label %bb.i19, label %bb3 16 17bb.i19: ; preds = %bb.i19, %bb3 18 %0 = insertelement <4 x float> undef, float undef, i32 3 ; <<4 x float>> [#uses=3] 19 %1 = fmul <4 x float> %0, %0 ; <<4 x float>> [#uses=1] 20 %2 = bitcast <4 x float> %1 to <2 x double> ; <<2 x double>> [#uses=0] 21 %3 = fmul <4 x float> %0, undef ; <<4 x float>> [#uses=0] 22 br label %bb.i19 23} 24 25; Check that the DAG combiner does not arbitrarily modify BUILD_VECTORs 26; after legalization. 27define void @test_illegal_build_vector() nounwind { 28; CHECK-LABEL: test_illegal_build_vector: 29; CHECK: @ %bb.0: @ %entry 30entry: 31 store <2 x i64> undef, <2 x i64>* undef, align 16 32 %0 = load <16 x i8>, <16 x i8>* undef, align 16 ; <<16 x i8>> [#uses=1] 33 %1 = or <16 x i8> zeroinitializer, %0 ; <<16 x i8>> [#uses=1] 34 store <16 x i8> %1, <16 x i8>* undef, align 16 35 ret void 36} 37 38; PR22678 39; Check CONCAT_VECTORS DAG combiner pass doesn't introduce illegal types. 40define void @test_pr22678() { 41; CHECK-LABEL: test_pr22678: 42; CHECK: @ %bb.0: 43 %1 = fptoui <16 x float> undef to <16 x i8> 44 store <16 x i8> %1, <16 x i8>* undef 45 ret void 46} 47 48; Radar 8407927: Make sure that VMOVRRD gets optimized away when the result is 49; converted back to be used as a vector type. 50define <4 x i32> @test_vmovrrd_combine() nounwind { 51; CHECK-LABEL: test_vmovrrd_combine: 52; CHECK: @ %bb.0: @ %entry 53; CHECK-NEXT: mov r0, #0 54; CHECK-NEXT: cmp r0, #0 55; CHECK-NEXT: @ implicit-def: $q8 56; CHECK-NEXT: bne .LBB3_2 57; CHECK-NEXT: @ %bb.1: @ %bb1.preheader 58; CHECK-NEXT: vmov.i32 q8, #0x0 59; CHECK-NEXT: vext.8 q8, q8, q8, #4 60; CHECK-NEXT: .LBB3_2: @ %bb2 61; CHECK-NEXT: vmov r0, r1, d16 62; CHECK-NEXT: vmov r2, r3, d17 63; CHECK-NEXT: bx lr 64entry: 65 br i1 undef, label %bb1, label %bb2 66 67bb1: 68 %0 = bitcast <2 x i64> zeroinitializer to <2 x double> 69 %1 = extractelement <2 x double> %0, i32 0 70 %2 = bitcast double %1 to i64 71 %3 = insertelement <1 x i64> undef, i64 %2, i32 0 72 %4 = shufflevector <1 x i64> %3, <1 x i64> undef, <2 x i32> <i32 0, i32 1> 73 %tmp2006.3 = bitcast <2 x i64> %4 to <16 x i8> 74 %5 = shufflevector <16 x i8> %tmp2006.3, <16 x i8> undef, <16 x i32> <i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15, i32 16, i32 17, i32 18, i32 19> 75 %tmp2004.3 = bitcast <16 x i8> %5 to <4 x i32> 76 br i1 undef, label %bb2, label %bb1 77 78bb2: 79 %result = phi <4 x i32> [ undef, %entry ], [ %tmp2004.3, %bb1 ] 80 ret <4 x i32> %result 81} 82 83; Test trying to do a ShiftCombine on illegal types. 84; The vector should be split first. 85define void @lshrIllegalType(<8 x i32>* %A) nounwind { 86; CHECK-LABEL: lshrIllegalType: 87; CHECK: @ %bb.0: 88; CHECK-NEXT: vld1.64 {d16, d17}, [r0:128] 89; CHECK-NEXT: vshr.u32 q8, q8, #3 90; CHECK-NEXT: vst1.32 {d16, d17}, [r0:128]! 91; CHECK-NEXT: vld1.64 {d16, d17}, [r0:128] 92; CHECK-NEXT: vshr.u32 q8, q8, #3 93; CHECK-NEXT: vst1.64 {d16, d17}, [r0:128] 94; CHECK-NEXT: bx lr 95 %tmp1 = load <8 x i32>, <8 x i32>* %A 96 %tmp2 = lshr <8 x i32> %tmp1, < i32 3, i32 3, i32 3, i32 3, i32 3, i32 3, i32 3, i32 3> 97 store <8 x i32> %tmp2, <8 x i32>* %A 98 ret void 99} 100 101; Test folding a binary vector operation with constant BUILD_VECTOR 102; operands with i16 elements. 103define void @test_i16_constant_fold() nounwind optsize { 104; CHECK-LABEL: test_i16_constant_fold: 105; CHECK: @ %bb.0: @ %entry 106; CHECK-NEXT: vmov.i8 d16, #0x1 107; CHECK-NEXT: vst1.8 {d16}, [r0] 108entry: 109 %0 = sext <4 x i1> zeroinitializer to <4 x i16> 110 %1 = add <4 x i16> %0, zeroinitializer 111 %2 = shufflevector <4 x i16> %1, <4 x i16> undef, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7> 112 %3 = add <8 x i16> %2, <i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1, i16 1> 113 %4 = trunc <8 x i16> %3 to <8 x i8> 114 tail call void @llvm.arm.neon.vst1.p0i8.v8i8(i8* undef, <8 x i8> %4, i32 1) 115 unreachable 116} 117 118declare void @llvm.arm.neon.vst1.p0i8.v8i8(i8*, <8 x i8>, i32) nounwind 119 120; Test that loads and stores of i64 vector elements are handled as f64 values 121; so they are not split up into i32 values. Radar 8755338. 122define void @i64_buildvector(i64* %ptr, <2 x i64>* %vp) nounwind { 123; CHECK-LABEL: i64_buildvector: 124; CHECK: @ %bb.0: 125; CHECK-NEXT: vldr d16, [r0] 126; CHECK-NEXT: vst1.64 {d16, d17}, [r1] 127; CHECK-NEXT: bx lr 128 %t0 = load i64, i64* %ptr, align 4 129 %t1 = insertelement <2 x i64> undef, i64 %t0, i32 0 130 store <2 x i64> %t1, <2 x i64>* %vp 131 ret void 132} 133 134define void @i64_insertelement(i64* %ptr, <2 x i64>* %vp) nounwind { 135; CHECK-LABEL: i64_insertelement: 136; CHECK: @ %bb.0: 137; CHECK-NEXT: vld1.64 {d16, d17}, [r1] 138; CHECK-NEXT: vldr d16, [r0] 139; CHECK-NEXT: vst1.64 {d16, d17}, [r1] 140; CHECK-NEXT: bx lr 141 %t0 = load i64, i64* %ptr, align 4 142 %vec = load <2 x i64>, <2 x i64>* %vp 143 %t1 = insertelement <2 x i64> %vec, i64 %t0, i32 0 144 store <2 x i64> %t1, <2 x i64>* %vp 145 ret void 146} 147 148define void @i64_extractelement(i64* %ptr, <2 x i64>* %vp) nounwind { 149; CHECK-LABEL: i64_extractelement: 150; CHECK: @ %bb.0: 151; CHECK-NEXT: vldr d16, [r1] 152; CHECK-NEXT: vstr d16, [r0] 153; CHECK-NEXT: bx lr 154 %vec = load <2 x i64>, <2 x i64>* %vp 155 %t1 = extractelement <2 x i64> %vec, i32 0 156 store i64 %t1, i64* %ptr 157 ret void 158} 159 160; Test trying to do a AND Combine on illegal types. 161define void @andVec(<3 x i8>* %A) nounwind { 162; CHECK-LABEL: andVec: 163; CHECK: @ %bb.0: 164; CHECK-NEXT: .pad #8 165; CHECK-NEXT: sub sp, sp, #8 166; CHECK-NEXT: ldr r1, [r0] 167; CHECK-NEXT: vmov.i16 d17, #0x7 168; CHECK-NEXT: str r1, [sp, #4] 169; CHECK-NEXT: add r1, sp, #4 170; CHECK-NEXT: vld1.32 {d16[0]}, [r1:32] 171; CHECK-NEXT: mov r1, sp 172; CHECK-NEXT: vmovl.u8 q9, d16 173; CHECK-NEXT: vand d16, d18, d17 174; CHECK-NEXT: vorr d17, d16, d16 175; CHECK-NEXT: vuzp.8 d17, d18 176; CHECK-NEXT: vst1.32 {d17[0]}, [r1:32] 177; CHECK-NEXT: vld1.32 {d17[0]}, [r1:32] 178; CHECK-NEXT: vmov.u16 r1, d16[2] 179; CHECK-NEXT: vmovl.u16 q8, d17 180; CHECK-NEXT: vmov.32 r2, d16[0] 181; CHECK-NEXT: strb r1, [r0, #2] 182; CHECK-NEXT: strh r2, [r0] 183; CHECK-NEXT: add sp, sp, #8 184; CHECK-NEXT: bx lr 185 %tmp = load <3 x i8>, <3 x i8>* %A, align 4 186 %and = and <3 x i8> %tmp, <i8 7, i8 7, i8 7> 187 store <3 x i8> %and, <3 x i8>* %A 188 ret void 189} 190 191 192; Test trying to do an OR Combine on illegal types. 193define void @orVec(<3 x i8>* %A) nounwind { 194; CHECK-LABEL: orVec: 195; CHECK: @ %bb.0: 196; CHECK-NEXT: .pad #8 197; CHECK-NEXT: sub sp, sp, #8 198; CHECK-NEXT: ldr r1, [r0] 199; CHECK-NEXT: str r1, [sp, #4] 200; CHECK-NEXT: add r1, sp, #4 201; CHECK-NEXT: vld1.32 {d16[0]}, [r1:32] 202; CHECK-NEXT: mov r1, sp 203; CHECK-NEXT: vmovl.u8 q8, d16 204; CHECK-NEXT: vorr.i16 d16, #0x7 205; CHECK-NEXT: vorr d18, d16, d16 206; CHECK-NEXT: vuzp.8 d18, d19 207; CHECK-NEXT: vst1.32 {d18[0]}, [r1:32] 208; CHECK-NEXT: vld1.32 {d18[0]}, [r1:32] 209; CHECK-NEXT: vmov.u16 r1, d16[2] 210; CHECK-NEXT: vmovl.u16 q8, d18 211; CHECK-NEXT: vmov.32 r2, d16[0] 212; CHECK-NEXT: strb r1, [r0, #2] 213; CHECK-NEXT: strh r2, [r0] 214; CHECK-NEXT: add sp, sp, #8 215; CHECK-NEXT: bx lr 216 %tmp = load <3 x i8>, <3 x i8>* %A, align 4 217 %or = or <3 x i8> %tmp, <i8 7, i8 7, i8 7> 218 store <3 x i8> %or, <3 x i8>* %A 219 ret void 220} 221 222; The following test was hitting an assertion in the DAG combiner when 223; constant folding the multiply because the "sext undef" was translated to 224; a BUILD_VECTOR with i32 0 operands, which did not match the i16 operands 225; of the other BUILD_VECTOR. 226define i16 @foldBuildVectors() { 227; CHECK-LABEL: foldBuildVectors: 228; CHECK: @ %bb.0: 229; CHECK-NEXT: mov r0, #0 230; CHECK-NEXT: bx lr 231 %1 = sext <8 x i8> undef to <8 x i16> 232 %2 = mul <8 x i16> %1, <i16 255, i16 255, i16 255, i16 255, i16 255, i16 255, i16 255, i16 255> 233 %3 = extractelement <8 x i16> %2, i32 0 234 ret i16 %3 235} 236 237; Test that we are generating vrev and vext for reverse shuffles of v8i16 238; shuffles. 239define void @reverse_v8i16(<8 x i16>* %loadaddr, <8 x i16>* %storeaddr) { 240; CHECK-LABEL: reverse_v8i16: 241; CHECK: @ %bb.0: 242; CHECK-NEXT: vld1.64 {d16, d17}, [r0] 243; CHECK-NEXT: vrev64.16 q8, q8 244; CHECK-NEXT: vext.16 q8, q8, q8, #4 245; CHECK-NEXT: vst1.64 {d16, d17}, [r1] 246; CHECK-NEXT: bx lr 247 %v0 = load <8 x i16>, <8 x i16>* %loadaddr 248 %v1 = shufflevector <8 x i16> %v0, <8 x i16> undef, 249 <8 x i32> <i32 7, i32 6, i32 5, i32 4, i32 3, i32 2, i32 1, i32 0> 250 store <8 x i16> %v1, <8 x i16>* %storeaddr 251 ret void 252} 253 254; Test that we are generating vrev and vext for reverse shuffles of v16i8 255; shuffles. 256define void @reverse_v16i8(<16 x i8>* %loadaddr, <16 x i8>* %storeaddr) { 257; CHECK-LABEL: reverse_v16i8: 258; CHECK: @ %bb.0: 259; CHECK-NEXT: vld1.64 {d16, d17}, [r0] 260; CHECK-NEXT: vrev64.8 q8, q8 261; CHECK-NEXT: vext.8 q8, q8, q8, #8 262; CHECK-NEXT: vst1.64 {d16, d17}, [r1] 263; CHECK-NEXT: bx lr 264 %v0 = load <16 x i8>, <16 x i8>* %loadaddr 265 %v1 = shufflevector <16 x i8> %v0, <16 x i8> undef, 266 <16 x i32> <i32 15, i32 14, i32 13, i32 12, i32 11, i32 10, i32 9, i32 8, 267 i32 7, i32 6, i32 5, i32 4, i32 3, i32 2, i32 1, i32 0> 268 store <16 x i8> %v1, <16 x i8>* %storeaddr 269 ret void 270} 271 272; <rdar://problem/14170854>. 273; vldr cannot handle unaligned loads. 274; Fall back to vld1.32, which can, instead of using the general purpose loads 275; followed by a costly sequence of instructions to build the vector register. 276define <8 x i16> @t3(i8 zeroext %xf, i8* nocapture %sp0, i8* nocapture %sp1, i32* nocapture %outp) { 277; CHECK-LABEL: t3: 278; CHECK: @ %bb.0: @ %entry 279; CHECK-NEXT: vld1.32 {d16[0]}, [r1] 280; CHECK-NEXT: vld1.32 {d16[1]}, [r2] 281; CHECK-NEXT: vmull.u8 q8, d16, d16 282; CHECK-NEXT: vmov r0, r1, d16 283; CHECK-NEXT: vmov r2, r3, d17 284; CHECK-NEXT: bx lr 285entry: 286 %pix_sp0.0.cast = bitcast i8* %sp0 to i32* 287 %pix_sp0.0.copyload = load i32, i32* %pix_sp0.0.cast, align 1 288 %pix_sp1.0.cast = bitcast i8* %sp1 to i32* 289 %pix_sp1.0.copyload = load i32, i32* %pix_sp1.0.cast, align 1 290 %vecinit = insertelement <2 x i32> undef, i32 %pix_sp0.0.copyload, i32 0 291 %vecinit1 = insertelement <2 x i32> %vecinit, i32 %pix_sp1.0.copyload, i32 1 292 %0 = bitcast <2 x i32> %vecinit1 to <8 x i8> 293 %vmull.i = tail call <8 x i16> @llvm.arm.neon.vmullu.v8i16(<8 x i8> %0, <8 x i8> %0) 294 ret <8 x i16> %vmull.i 295} 296 297; Function Attrs: nounwind readnone 298declare <8 x i16> @llvm.arm.neon.vmullu.v8i16(<8 x i8>, <8 x i8>) 299 300; Check that (insert_vector_elt (load)) => (vector_load). 301; Thus, check that scalar_to_vector do not interfer with that. 302define <8 x i16> @t4(i8* nocapture %sp0) { 303; CHECK-LABEL: t4: 304; CHECK: @ %bb.0: @ %entry 305; CHECK-NEXT: vld1.32 {d16[0]}, [r0] 306; CHECK-NEXT: vmull.u8 q8, d16, d16 307; CHECK-NEXT: vmov r0, r1, d16 308; CHECK-NEXT: vmov r2, r3, d17 309; CHECK-NEXT: bx lr 310entry: 311 %pix_sp0.0.cast = bitcast i8* %sp0 to i32* 312 %pix_sp0.0.copyload = load i32, i32* %pix_sp0.0.cast, align 1 313 %vec = insertelement <2 x i32> undef, i32 %pix_sp0.0.copyload, i32 0 314 %0 = bitcast <2 x i32> %vec to <8 x i8> 315 %vmull.i = tail call <8 x i16> @llvm.arm.neon.vmullu.v8i16(<8 x i8> %0, <8 x i8> %0) 316 ret <8 x i16> %vmull.i 317} 318 319; Make sure vector load is used for all three loads. 320; Lowering to build vector was breaking the single use property of the load of 321; %pix_sp0.0.copyload. 322define <8 x i16> @t5(i8* nocapture %sp0, i8* nocapture %sp1, i8* nocapture %sp2) { 323; CHECK-LABEL: t5: 324; CHECK: @ %bb.0: @ %entry 325; CHECK-NEXT: vld1.32 {d16[1]}, [r0] 326; CHECK-NEXT: vorr d17, d16, d16 327; CHECK-NEXT: vld1.32 {d16[0]}, [r1] 328; CHECK-NEXT: vld1.32 {d17[0]}, [r2] 329; CHECK-NEXT: vmull.u8 q8, d16, d17 330; CHECK-NEXT: vmov r0, r1, d16 331; CHECK-NEXT: vmov r2, r3, d17 332; CHECK-NEXT: bx lr 333entry: 334 %pix_sp0.0.cast = bitcast i8* %sp0 to i32* 335 %pix_sp0.0.copyload = load i32, i32* %pix_sp0.0.cast, align 1 336 %pix_sp1.0.cast = bitcast i8* %sp1 to i32* 337 %pix_sp1.0.copyload = load i32, i32* %pix_sp1.0.cast, align 1 338 %pix_sp2.0.cast = bitcast i8* %sp2 to i32* 339 %pix_sp2.0.copyload = load i32, i32* %pix_sp2.0.cast, align 1 340 %vec = insertelement <2 x i32> undef, i32 %pix_sp0.0.copyload, i32 1 341 %vecinit1 = insertelement <2 x i32> %vec, i32 %pix_sp1.0.copyload, i32 0 342 %vecinit2 = insertelement <2 x i32> %vec, i32 %pix_sp2.0.copyload, i32 0 343 %0 = bitcast <2 x i32> %vecinit1 to <8 x i8> 344 %1 = bitcast <2 x i32> %vecinit2 to <8 x i8> 345 %vmull.i = tail call <8 x i16> @llvm.arm.neon.vmullu.v8i16(<8 x i8> %0, <8 x i8> %1) 346 ret <8 x i16> %vmull.i 347} 348 349; <rdar://problem/14989896> Make sure we manage to truncate a vector from an 350; illegal type to a legal type. 351define <2 x i8> @test_truncate(<2 x i128> %in) { 352; CHECK-LABEL: test_truncate: 353; CHECK: @ %bb.0: @ %entry 354; CHECK-NEXT: vmov.32 d16[0], r0 355; CHECK-NEXT: mov r0, sp 356; CHECK-NEXT: vld1.32 {d16[1]}, [r0:32] 357; CHECK-NEXT: vmov r0, r1, d16 358; CHECK-NEXT: bx lr 359entry: 360 %res = trunc <2 x i128> %in to <2 x i8> 361 ret <2 x i8> %res 362} 363