292 lines · plain
1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py2; RUN: llc -o - < %s | FileCheck %s3 4target datalayout = "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"5target triple = "armv8-unknown-linux-gnueabihf"6 7define <4 x float> @test(ptr %A) {8; CHECK-LABEL: test:9; CHECK: @ %bb.0:10; CHECK-NEXT: vld1.32 {d16, d17}, [r0]!11; CHECK-NEXT: vld1.32 {d18, d19}, [r0]!12; CHECK-NEXT: vadd.f32 q8, q8, q913; CHECK-NEXT: vld1.32 {d18, d19}, [r0]14; CHECK-NEXT: vadd.f32 q0, q8, q915; CHECK-NEXT: bx lr16 %X = load <4 x float>, ptr %A, align 417 %Y.ptr.elt = getelementptr inbounds float, ptr %A, i32 418 %Y = load <4 x float>, ptr %Y.ptr.elt, align 419 %Z.ptr.elt = getelementptr inbounds float, ptr %A, i32 820 %Z = load <4 x float>, ptr %Z.ptr.elt, align 421 %tmp.sum = fadd <4 x float> %X, %Y22 %sum = fadd <4 x float> %tmp.sum, %Z23 ret <4 x float> %sum24}25 26define <4 x float> @test_stride(ptr %A) {27; CHECK-LABEL: test_stride:28; CHECK: @ %bb.0:29; CHECK-NEXT: mov r1, #2430; CHECK-NEXT: vld1.32 {d16, d17}, [r0], r131; CHECK-NEXT: vld1.32 {d18, d19}, [r0], r132; CHECK-NEXT: vadd.f32 q8, q8, q933; CHECK-NEXT: vld1.32 {d18, d19}, [r0]34; CHECK-NEXT: vadd.f32 q0, q8, q935; CHECK-NEXT: bx lr36 %X = load <4 x float>, ptr %A, align 437 %Y.ptr.elt = getelementptr inbounds float, ptr %A, i32 638 %Y = load <4 x float>, ptr %Y.ptr.elt, align 439 %Z.ptr.elt = getelementptr inbounds float, ptr %A, i32 1240 %Z = load <4 x float>, ptr %Z.ptr.elt, align 441 %tmp.sum = fadd <4 x float> %X, %Y42 %sum = fadd <4 x float> %tmp.sum, %Z43 ret <4 x float> %sum44}45 46define <4 x float> @test_stride_mixed(ptr %A) {47; CHECK-LABEL: test_stride_mixed:48; CHECK: @ %bb.0:49; CHECK-NEXT: mov r1, #2450; CHECK-NEXT: vld1.32 {d16, d17}, [r0], r151; CHECK-NEXT: vld1.32 {d18, d19}, [r0]!52; CHECK-NEXT: vadd.f32 q8, q8, q953; CHECK-NEXT: vld1.32 {d18, d19}, [r0]54; CHECK-NEXT: vadd.f32 q0, q8, q955; CHECK-NEXT: bx lr56 %X = load <4 x float>, ptr %A, align 457 %Y.ptr.elt = getelementptr inbounds float, ptr %A, i32 658 %Y = load <4 x float>, ptr %Y.ptr.elt, align 459 %Z.ptr.elt = getelementptr inbounds float, ptr %A, i32 1060 %Z = load <4 x float>, ptr %Z.ptr.elt, align 461 %tmp.sum = fadd <4 x float> %X, %Y62 %sum = fadd <4 x float> %tmp.sum, %Z63 ret <4 x float> %sum64}65 66; Refrain from using multiple stride registers67define <4 x float> @test_stride_noop(ptr %A) {68; CHECK-LABEL: test_stride_noop:69; CHECK: @ %bb.0:70; CHECK-NEXT: mov r1, #2471; CHECK-NEXT: vld1.32 {d16, d17}, [r0], r172; CHECK-NEXT: mov r1, #3273; CHECK-NEXT: vld1.32 {d18, d19}, [r0], r174; CHECK-NEXT: vadd.f32 q8, q8, q975; CHECK-NEXT: vld1.32 {d18, d19}, [r0]76; CHECK-NEXT: vadd.f32 q0, q8, q977; CHECK-NEXT: bx lr78 %X = load <4 x float>, ptr %A, align 479 %Y.ptr.elt = getelementptr inbounds float, ptr %A, i32 680 %Y = load <4 x float>, ptr %Y.ptr.elt, align 481 %Z.ptr.elt = getelementptr inbounds float, ptr %A, i32 1482 %Z = load <4 x float>, ptr %Z.ptr.elt, align 483 %tmp.sum = fadd <4 x float> %X, %Y84 %sum = fadd <4 x float> %tmp.sum, %Z85 ret <4 x float> %sum86}87 88define <4 x float> @test_positive_initial_offset(ptr %A) {89; CHECK-LABEL: test_positive_initial_offset:90; CHECK: @ %bb.0:91; CHECK-NEXT: add r0, r0, #3292; CHECK-NEXT: vld1.32 {d16, d17}, [r0]!93; CHECK-NEXT: vld1.32 {d18, d19}, [r0]!94; CHECK-NEXT: vadd.f32 q8, q8, q995; CHECK-NEXT: vld1.32 {d18, d19}, [r0]96; CHECK-NEXT: vadd.f32 q0, q8, q997; CHECK-NEXT: bx lr98 %X.ptr.elt = getelementptr inbounds float, ptr %A, i32 899 %X = load <4 x float>, ptr %X.ptr.elt, align 4100 %Y.ptr.elt = getelementptr inbounds float, ptr %A, i32 12101 %Y = load <4 x float>, ptr %Y.ptr.elt, align 4102 %Z.ptr.elt = getelementptr inbounds float, ptr %A, i32 16103 %Z = load <4 x float>, ptr %Z.ptr.elt, align 4104 %tmp.sum = fadd <4 x float> %X, %Y105 %sum = fadd <4 x float> %tmp.sum, %Z106 ret <4 x float> %sum107}108 109define <4 x float> @test_negative_initial_offset(ptr %A) {110; CHECK-LABEL: test_negative_initial_offset:111; CHECK: @ %bb.0:112; CHECK-NEXT: sub r0, r0, #64113; CHECK-NEXT: vld1.32 {d16, d17}, [r0]!114; CHECK-NEXT: vld1.32 {d18, d19}, [r0]!115; CHECK-NEXT: vadd.f32 q8, q8, q9116; CHECK-NEXT: vld1.32 {d18, d19}, [r0]117; CHECK-NEXT: vadd.f32 q0, q8, q9118; CHECK-NEXT: bx lr119 %X.ptr.elt = getelementptr inbounds float, ptr %A, i32 -16120 %X = load <4 x float>, ptr %X.ptr.elt, align 4121 %Y.ptr.elt = getelementptr inbounds float, ptr %A, i32 -12122 %Y = load <4 x float>, ptr %Y.ptr.elt, align 4123 %Z.ptr.elt = getelementptr inbounds float, ptr %A, i32 -8124 %Z = load <4 x float>, ptr %Z.ptr.elt, align 4125 %tmp.sum = fadd <4 x float> %X, %Y126 %sum = fadd <4 x float> %tmp.sum, %Z127 ret <4 x float> %sum128}129 130@global_float_array = external global [128 x float], align 4131define <4 x float> @test_global() {132; CHECK-LABEL: test_global:133; CHECK: @ %bb.0:134; CHECK-NEXT: movw r0, :lower16:global_float_array135; CHECK-NEXT: movt r0, :upper16:global_float_array136; CHECK-NEXT: add r0, r0, #32137; CHECK-NEXT: vld1.32 {d16, d17}, [r0]!138; CHECK-NEXT: vld1.32 {d18, d19}, [r0]!139; CHECK-NEXT: vadd.f32 q8, q8, q9140; CHECK-NEXT: vld1.32 {d18, d19}, [r0]141; CHECK-NEXT: vadd.f32 q0, q8, q9142; CHECK-NEXT: bx lr143 %X = load <4 x float>, ptr getelementptr inbounds ([128 x float], ptr @global_float_array, i32 0, i32 8), align 4144 %Y = load <4 x float>, ptr getelementptr inbounds ([128 x float], ptr @global_float_array, i32 0, i32 12), align 4145 %Z = load <4 x float>, ptr getelementptr inbounds ([128 x float], ptr @global_float_array, i32 0, i32 16), align 4146 %tmp.sum = fadd <4 x float> %X, %Y147 %sum = fadd <4 x float> %tmp.sum, %Z148 ret <4 x float> %sum149}150 151define <4 x float> @test_stack() {152; Use huge alignment to test that ADD would not be converted to OR153; CHECK-LABEL: test_stack:154; CHECK: @ %bb.0:155; CHECK-NEXT: .save {r4, r10, r11, lr}156; CHECK-NEXT: push {r4, r10, r11, lr}157; CHECK-NEXT: .setfp r11, sp, #8158; CHECK-NEXT: add r11, sp, #8159; CHECK-NEXT: .pad #240160; CHECK-NEXT: sub sp, sp, #240161; CHECK-NEXT: bfc sp, #0, #7162; CHECK-NEXT: mov r4, sp163; CHECK-NEXT: mov r0, r4164; CHECK-NEXT: bl external_function165; CHECK-NEXT: vld1.32 {d16, d17}, [r4:128]!166; CHECK-NEXT: vld1.32 {d18, d19}, [r4:128]!167; CHECK-NEXT: vadd.f32 q8, q8, q9168; CHECK-NEXT: vld1.64 {d18, d19}, [r4:128]169; CHECK-NEXT: vadd.f32 q0, q8, q9170; CHECK-NEXT: sub sp, r11, #8171; CHECK-NEXT: pop {r4, r10, r11, pc}172 %array = alloca [32 x float], align 128173 call void @external_function(ptr %array)174 %X = load <4 x float>, ptr %array, align 4175 %Y.ptr.elt = getelementptr inbounds [32 x float], ptr %array, i32 0, i32 4176 %Y = load <4 x float>, ptr %Y.ptr.elt, align 4177 %Z.ptr.elt = getelementptr inbounds [32 x float], ptr %array, i32 0, i32 8178 %Z = load <4 x float>, ptr %Z.ptr.elt, align 4179 %tmp.sum = fadd <4 x float> %X, %Y180 %sum = fadd <4 x float> %tmp.sum, %Z181 ret <4 x float> %sum182}183 184define <2 x double> @test_double(ptr %A) {185; CHECK-LABEL: test_double:186; CHECK: @ %bb.0:187; CHECK-NEXT: add r0, r0, #64188; CHECK-NEXT: vld1.64 {d16, d17}, [r0]!189; CHECK-NEXT: vld1.64 {d18, d19}, [r0]!190; CHECK-NEXT: vadd.f64 d20, d17, d19191; CHECK-NEXT: vadd.f64 d16, d16, d18192; CHECK-NEXT: vld1.64 {d22, d23}, [r0]193; CHECK-NEXT: vadd.f64 d1, d20, d23194; CHECK-NEXT: vadd.f64 d0, d16, d22195; CHECK-NEXT: bx lr196 %X.ptr.elt = getelementptr inbounds double, ptr %A, i32 8197 %X = load <2 x double>, ptr %X.ptr.elt, align 8198 %Y.ptr.elt = getelementptr inbounds double, ptr %A, i32 10199 %Y = load <2 x double>, ptr %Y.ptr.elt, align 8200 %Z.ptr.elt = getelementptr inbounds double, ptr %A, i32 12201 %Z = load <2 x double>, ptr %Z.ptr.elt, align 8202 %tmp.sum = fadd <2 x double> %X, %Y203 %sum = fadd <2 x double> %tmp.sum, %Z204 ret <2 x double> %sum205}206 207define void @test_various_instructions(ptr %A) {208; CHECK-LABEL: test_various_instructions:209; CHECK: @ %bb.0:210; CHECK-NEXT: vld1.32 {d16, d17}, [r0]!211; CHECK-NEXT: vld1.32 {d18, d19}, [r0]!212; CHECK-NEXT: vadd.f32 q8, q8, q9213; CHECK-NEXT: vst1.32 {d16, d17}, [r0]214; CHECK-NEXT: bx lr215 %X = call <4 x float> @llvm.arm.neon.vld1.v4f32.p0(ptr %A, i32 1)216 %Y.ptr.elt = getelementptr inbounds float, ptr %A, i32 4217 %Y = load <4 x float>, ptr %Y.ptr.elt, align 4218 %Z.ptr.elt = getelementptr inbounds float, ptr %A, i32 8219 %Z = fadd <4 x float> %X, %Y220 tail call void @llvm.arm.neon.vst1.p0.v4f32(ptr nonnull %Z.ptr.elt, <4 x float> %Z, i32 4)221 ret void222}223 224define void @test_lsr_geps(ptr %a, ptr %b, i32 %n) {225; CHECK-LABEL: test_lsr_geps:226; CHECK: @ %bb.0: @ %entry227; CHECK-NEXT: cmp r2, #1228; CHECK-NEXT: bxlt lr229; CHECK-NEXT: .LBB10_1: @ %for.body.preheader230; CHECK-NEXT: mov r12, #0231; CHECK-NEXT: .LBB10_2: @ %for.body232; CHECK-NEXT: @ =>This Inner Loop Header: Depth=1233; CHECK-NEXT: add r3, r0, r12234; CHECK-NEXT: subs r2, r2, #1235; CHECK-NEXT: vld1.32 {d16, d17}, [r3]!236; CHECK-NEXT: vld1.32 {d18, d19}, [r3]!237; CHECK-NEXT: vld1.32 {d20, d21}, [r3]!238; CHECK-NEXT: vld1.32 {d22, d23}, [r3]239; CHECK-NEXT: add r3, r1, r12240; CHECK-NEXT: add r12, r12, #64241; CHECK-NEXT: vst1.32 {d16, d17}, [r3]!242; CHECK-NEXT: vst1.32 {d18, d19}, [r3]!243; CHECK-NEXT: vst1.32 {d20, d21}, [r3]!244; CHECK-NEXT: vst1.32 {d22, d23}, [r3]245; CHECK-NEXT: bne .LBB10_2246; CHECK-NEXT: @ %bb.3: @ %for.cond.cleanup247; CHECK-NEXT: bx lr248entry:249 %cmp61 = icmp sgt i32 %n, 0250 br i1 %cmp61, label %for.body.preheader, label %for.cond.cleanup251 252for.body.preheader:253 br label %for.body254 255for.cond.cleanup:256 ret void257 258for.body:259 %lsr.iv1 = phi i32 [ 0, %for.body.preheader ], [ %lsr.iv.next2, %for.body ]260 %lsr.iv = phi i32 [ %n, %for.body.preheader ], [ %lsr.iv.next, %for.body ]261 %uglygep19 = getelementptr i8, ptr %a, i32 %lsr.iv1262 %0 = load <4 x float>, ptr %uglygep19, align 4263 %uglygep16 = getelementptr i8, ptr %a, i32 %lsr.iv1264 %scevgep18 = getelementptr <4 x float>, ptr %uglygep16, i32 1265 %1 = load <4 x float>, ptr %scevgep18, align 4266 %uglygep13 = getelementptr i8, ptr %a, i32 %lsr.iv1267 %scevgep15 = getelementptr <4 x float>, ptr %uglygep13, i32 2268 %2 = load <4 x float>, ptr %scevgep15, align 4269 %uglygep10 = getelementptr i8, ptr %a, i32 %lsr.iv1270 %scevgep12 = getelementptr <4 x float>, ptr %uglygep10, i32 3271 %3 = load <4 x float>, ptr %scevgep12, align 4272 %uglygep8 = getelementptr i8, ptr %b, i32 %lsr.iv1273 tail call void @llvm.arm.neon.vst1.p0.v4f32(ptr %uglygep8, <4 x float> %0, i32 4)274 %uglygep6 = getelementptr i8, ptr %b, i32 %lsr.iv1275 %scevgep7 = getelementptr i8, ptr %uglygep6, i32 16276 tail call void @llvm.arm.neon.vst1.p0.v4f32(ptr nonnull %scevgep7, <4 x float> %1, i32 4)277 %uglygep4 = getelementptr i8, ptr %b, i32 %lsr.iv1278 %scevgep5 = getelementptr i8, ptr %uglygep4, i32 32279 tail call void @llvm.arm.neon.vst1.p0.v4f32(ptr nonnull %scevgep5, <4 x float> %2, i32 4)280 %uglygep = getelementptr i8, ptr %b, i32 %lsr.iv1281 %scevgep = getelementptr i8, ptr %uglygep, i32 48282 tail call void @llvm.arm.neon.vst1.p0.v4f32(ptr nonnull %scevgep, <4 x float> %3, i32 4)283 %lsr.iv.next = add i32 %lsr.iv, -1284 %lsr.iv.next2 = add nuw i32 %lsr.iv1, 64285 %exitcond.not = icmp eq i32 %lsr.iv.next, 0286 br i1 %exitcond.not, label %for.cond.cleanup, label %for.body287}288 289declare void @external_function(ptr)290declare <4 x float> @llvm.arm.neon.vld1.v4f32.p0(ptr, i32) nounwind readonly291declare void @llvm.arm.neon.vst1.p0.v4f32(ptr, <4 x float>, i32) nounwind argmemonly292