1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py 2; RUN: llc -mtriple=thumbv8.1m.main-none-none-eabi -O3 -mattr=+mve.fp,+use-mipipeliner -mcpu=cortex-m55 %s -o - -verify-machineinstrs --pipeliner-force-issue-width=10 | FileCheck %s 3 4define void @arm_cmplx_dot_prod_q15(ptr noundef %pSrcA, ptr noundef %pSrcB, i32 noundef %numSamples, ptr nocapture noundef writeonly %realResult, ptr nocapture noundef writeonly %imagResult) { 5; CHECK-LABEL: arm_cmplx_dot_prod_q15: 6; CHECK: @ %bb.0: @ %entry 7; CHECK-NEXT: .save {r4, r5, r6, r7, r8, lr} 8; CHECK-NEXT: push.w {r4, r5, r6, r7, r8, lr} 9; CHECK-NEXT: ldr.w r12, [sp, #24] 10; CHECK-NEXT: cmp r2, #16 11; CHECK-NEXT: blo .LBB0_5 12; CHECK-NEXT: @ %bb.1: @ %while.body.preheader 13; CHECK-NEXT: movs r6, #2 14; CHECK-NEXT: lsrs r7, r2, #3 15; CHECK-NEXT: rsb r6, r6, r2, lsr #3 16; CHECK-NEXT: cmp r7, #2 17; CHECK-NEXT: mov.w r5, #0 18; CHECK-NEXT: csel r7, r6, r5, hs 19; CHECK-NEXT: add.w lr, r7, #1 20; CHECK-NEXT: mov r4, r5 21; CHECK-NEXT: vldrh.u16 q0, [r0], #32 22; CHECK-NEXT: movs r7, #0 23; CHECK-NEXT: mov r8, r5 24; CHECK-NEXT: vldrh.u16 q1, [r1], #32 25; CHECK-NEXT: vmlsldava.s16 r4, r7, q0, q1 26; CHECK-NEXT: vldrh.u16 q2, [r0, #-16] 27; CHECK-NEXT: vmlaldavax.s16 r8, r5, q0, q1 28; CHECK-NEXT: vldrh.u16 q3, [r1, #-16] 29; CHECK-NEXT: vmlsldava.s16 r4, r7, q2, q3 30; CHECK-NEXT: vldrh.u16 q0, [r1], #32 31; CHECK-NEXT: sub.w lr, lr, #1 32; CHECK-NEXT: cmp.w lr, #0 33; CHECK-NEXT: vldrh.u16 q1, [r0], #32 34; CHECK-NEXT: beq .LBB0_3 35; CHECK-NEXT: .p2align 2 36; CHECK-NEXT: .LBB0_2: @ %while.body 37; CHECK-NEXT: @ =>This Inner Loop Header: Depth=1 38; CHECK-NEXT: vmlaldavax.s16 r8, r5, q2, q3 39; CHECK-NEXT: vldrh.u16 q3, [r1, #-16] 40; CHECK-NEXT: vmlsldava.s16 r4, r7, q1, q0 41; CHECK-NEXT: vldrh.u16 q2, [r0, #-16] 42; CHECK-NEXT: vmlaldavax.s16 r8, r5, q1, q0 43; CHECK-NEXT: vldrh.u16 q1, [r0], #32 44; CHECK-NEXT: vmlsldava.s16 r4, r7, q2, q3 45; CHECK-NEXT: vldrh.u16 q0, [r1], #32 46; CHECK-NEXT: le lr, .LBB0_2 47; CHECK-NEXT: .LBB0_3: 48; CHECK-NEXT: vmlaldavax.s16 r8, r5, q2, q3 49; CHECK-NEXT: movs r6, #14 50; CHECK-NEXT: and.w r2, r6, r2, lsl #1 51; CHECK-NEXT: vmlaldavax.s16 r8, r5, q1, q0 52; CHECK-NEXT: vldrh.u16 q2, [r0, #-16] 53; CHECK-NEXT: vmlsldava.s16 r4, r7, q1, q0 54; CHECK-NEXT: vldrh.u16 q0, [r1, #-16] 55; CHECK-NEXT: vmlaldavax.s16 r8, r5, q2, q0 56; CHECK-NEXT: vctp.16 r2 57; CHECK-NEXT: vmlsldava.s16 r4, r7, q2, q0 58; CHECK-NEXT: vpst 59; CHECK-NEXT: vldrht.u16 q1, [r0] 60; CHECK-NEXT: cmp r2, #9 61; CHECK-NEXT: vpsttt 62; CHECK-NEXT: vldrht.u16 q0, [r1] 63; CHECK-NEXT: vmlsldavat.s16 r4, r7, q1, q0 64; CHECK-NEXT: vmlaldavaxt.s16 r8, r5, q1, q0 65; CHECK-NEXT: blo .LBB0_10 66; CHECK-NEXT: @ %bb.4: @ %do.body.1 67; CHECK-NEXT: subs r2, #8 68; CHECK-NEXT: vctp.16 r2 69; CHECK-NEXT: vpstttt 70; CHECK-NEXT: vldrht.u16 q0, [r0, #16] 71; CHECK-NEXT: vldrht.u16 q1, [r1, #16] 72; CHECK-NEXT: vmlsldavat.s16 r4, r7, q0, q1 73; CHECK-NEXT: vmlaldavaxt.s16 r8, r5, q0, q1 74; CHECK-NEXT: b .LBB0_10 75; CHECK-NEXT: .p2align 2 76; CHECK-NEXT: .LBB0_5: @ %if.else 77; CHECK-NEXT: mov.w r4, #0 78; CHECK-NEXT: cbz r2, .LBB0_9 79; CHECK-NEXT: @ %bb.6: @ %while.body14.preheader 80; CHECK-NEXT: lsls r6, r2, #1 81; CHECK-NEXT: mov r5, r4 82; CHECK-NEXT: mov r7, r4 83; CHECK-NEXT: movs r2, #0 84; CHECK-NEXT: dlstp.16 lr, r6 85; CHECK-NEXT: .p2align 2 86; CHECK-NEXT: .LBB0_7: @ %while.body14 87; CHECK-NEXT: @ =>This Inner Loop Header: Depth=1 88; CHECK-NEXT: vldrh.u16 q0, [r0], #16 89; CHECK-NEXT: vldrh.u16 q1, [r1], #16 90; CHECK-NEXT: vmlsldava.s16 r2, r7, q0, q1 91; CHECK-NEXT: vmlaldavax.s16 r4, r5, q0, q1 92; CHECK-NEXT: letp lr, .LBB0_7 93; CHECK-NEXT: @ %bb.8: @ %if.end.loopexit177 94; CHECK-NEXT: mov r8, r4 95; CHECK-NEXT: mov r4, r2 96; CHECK-NEXT: b .LBB0_10 97; CHECK-NEXT: .p2align 2 98; CHECK-NEXT: .LBB0_9: 99; CHECK-NEXT: mov r7, r4 100; CHECK-NEXT: mov.w r8, #0 101; CHECK-NEXT: mov r5, r4 102; CHECK-NEXT: .LBB0_10: @ %if.end 103; CHECK-NEXT: asrl r4, r7, #6 104; CHECK-NEXT: asrl r8, r5, #6 105; CHECK-NEXT: str r4, [r3] 106; CHECK-NEXT: str.w r8, [r12] 107; CHECK-NEXT: pop.w {r4, r5, r6, r7, r8, pc} 108entry: 109 %cmp = icmp ugt i32 %numSamples, 15 110 br i1 %cmp, label %while.body.preheader, label %if.else 111 112while.body.preheader: ; preds = %entry 113 %vecSrcA.0138 = load <8 x i16>, ptr %pSrcA, align 2 114 %vecSrcB.0137 = load <8 x i16>, ptr %pSrcB, align 2 115 %pSrcB.addr.0136 = getelementptr inbounds i16, ptr %pSrcB, i32 8 116 %pSrcA.addr.0135 = getelementptr inbounds i16, ptr %pSrcA, i32 8 117 %shr = lshr i32 %numSamples, 3 118 br label %while.body 119 120while.body: ; preds = %while.body.preheader, %while.body 121 %vecSrcA.0150 = phi <8 x i16> [ %vecSrcA.0, %while.body ], [ %vecSrcA.0138, %while.body.preheader ] 122 %vecSrcB.0149 = phi <8 x i16> [ %vecSrcB.0, %while.body ], [ %vecSrcB.0137, %while.body.preheader ] 123 %pSrcB.addr.0148 = phi ptr [ %pSrcB.addr.0, %while.body ], [ %pSrcB.addr.0136, %while.body.preheader ] 124 %pSrcA.addr.0147 = phi ptr [ %pSrcA.addr.0, %while.body ], [ %pSrcA.addr.0135, %while.body.preheader ] 125 %vecSrcB.0.in146 = phi ptr [ %add.ptr4, %while.body ], [ %pSrcB, %while.body.preheader ] 126 %vecSrcA.0.in145 = phi ptr [ %add.ptr3, %while.body ], [ %pSrcA, %while.body.preheader ] 127 %accImag.0.off32144 = phi i32 [ %12, %while.body ], [ 0, %while.body.preheader ] 128 %accImag.0.off0143 = phi i32 [ %13, %while.body ], [ 0, %while.body.preheader ] 129 %accReal.0.off32142 = phi i32 [ %9, %while.body ], [ 0, %while.body.preheader ] 130 %accReal.0.off0141 = phi i32 [ %10, %while.body ], [ 0, %while.body.preheader ] 131 %blkCnt.0.in140 = phi i32 [ %blkCnt.0, %while.body ], [ %shr, %while.body.preheader ] 132 %blkCnt.0 = add nsw i32 %blkCnt.0.in140, -1 133 %0 = tail call { i32, i32 } @llvm.arm.mve.vmlldava.v8i16(i32 0, i32 1, i32 0, i32 %accReal.0.off0141, i32 %accReal.0.off32142, <8 x i16> %vecSrcA.0150, <8 x i16> %vecSrcB.0149) 134 %1 = extractvalue { i32, i32 } %0, 1 135 %2 = extractvalue { i32, i32 } %0, 0 136 %3 = load <8 x i16>, ptr %pSrcA.addr.0147, align 2 137 %add.ptr3 = getelementptr inbounds i16, ptr %vecSrcA.0.in145, i32 16 138 %4 = tail call { i32, i32 } @llvm.arm.mve.vmlldava.v8i16(i32 0, i32 0, i32 1, i32 %accImag.0.off0143, i32 %accImag.0.off32144, <8 x i16> %vecSrcA.0150, <8 x i16> %vecSrcB.0149) 139 %5 = extractvalue { i32, i32 } %4, 1 140 %6 = extractvalue { i32, i32 } %4, 0 141 %7 = load <8 x i16>, ptr %pSrcB.addr.0148, align 2 142 %add.ptr4 = getelementptr inbounds i16, ptr %vecSrcB.0.in146, i32 16 143 %8 = tail call { i32, i32 } @llvm.arm.mve.vmlldava.v8i16(i32 0, i32 1, i32 0, i32 %2, i32 %1, <8 x i16> %3, <8 x i16> %7) 144 %9 = extractvalue { i32, i32 } %8, 1 145 %10 = extractvalue { i32, i32 } %8, 0 146 %11 = tail call { i32, i32 } @llvm.arm.mve.vmlldava.v8i16(i32 0, i32 0, i32 1, i32 %6, i32 %5, <8 x i16> %3, <8 x i16> %7) 147 %12 = extractvalue { i32, i32 } %11, 1 148 %13 = extractvalue { i32, i32 } %11, 0 149 %pSrcA.addr.0 = getelementptr inbounds i16, ptr %vecSrcA.0.in145, i32 24 150 %pSrcB.addr.0 = getelementptr inbounds i16, ptr %vecSrcB.0.in146, i32 24 151 %vecSrcB.0 = load <8 x i16>, ptr %add.ptr4, align 2 152 %vecSrcA.0 = load <8 x i16>, ptr %add.ptr3, align 2 153 %cmp2 = icmp ugt i32 %blkCnt.0.in140, 2 154 br i1 %cmp2, label %while.body, label %do.body 155 156do.body: ; preds = %while.body 157 %and = shl i32 %numSamples, 1 158 %mul = and i32 %and, 14 159 %14 = extractvalue { i32, i32 } %11, 0 160 %15 = extractvalue { i32, i32 } %11, 1 161 %16 = tail call { i32, i32 } @llvm.arm.mve.vmlldava.v8i16(i32 0, i32 0, i32 1, i32 %14, i32 %15, <8 x i16> %vecSrcA.0, <8 x i16> %vecSrcB.0) 162 %17 = extractvalue { i32, i32 } %16, 0 163 %18 = extractvalue { i32, i32 } %16, 1 164 %19 = load <8 x i16>, ptr %pSrcA.addr.0, align 2 165 %20 = load <8 x i16>, ptr %pSrcB.addr.0, align 2 166 %21 = tail call { i32, i32 } @llvm.arm.mve.vmlldava.v8i16(i32 0, i32 0, i32 1, i32 %17, i32 %18, <8 x i16> %19, <8 x i16> %20) 167 %22 = extractvalue { i32, i32 } %8, 0 168 %23 = extractvalue { i32, i32 } %8, 1 169 %24 = tail call { i32, i32 } @llvm.arm.mve.vmlldava.v8i16(i32 0, i32 1, i32 0, i32 %22, i32 %23, <8 x i16> %vecSrcA.0, <8 x i16> %vecSrcB.0) 170 %25 = extractvalue { i32, i32 } %24, 0 171 %26 = extractvalue { i32, i32 } %24, 1 172 %27 = tail call { i32, i32 } @llvm.arm.mve.vmlldava.v8i16(i32 0, i32 1, i32 0, i32 %25, i32 %26, <8 x i16> %19, <8 x i16> %20) 173 %accImag.1.off32 = extractvalue { i32, i32 } %21, 1 174 %accImag.1.off0 = extractvalue { i32, i32 } %21, 0 175 %accReal.1.off32 = extractvalue { i32, i32 } %27, 1 176 %accReal.1.off0 = extractvalue { i32, i32 } %27, 0 177 %28 = tail call <8 x i1> @llvm.arm.mve.vctp16(i32 %mul) 178 %add.ptr7 = getelementptr inbounds i16, ptr %vecSrcA.0.in145, i32 32 179 %add.ptr8 = getelementptr inbounds i16, ptr %vecSrcB.0.in146, i32 32 180 %29 = tail call <8 x i16> @llvm.masked.load.v8i16.p0(ptr nonnull %add.ptr7, i32 2, <8 x i1> %28, <8 x i16> zeroinitializer) 181 %30 = tail call <8 x i16> @llvm.masked.load.v8i16.p0(ptr nonnull %add.ptr8, i32 2, <8 x i1> %28, <8 x i16> zeroinitializer) 182 %31 = tail call { i32, i32 } @llvm.arm.mve.vmlldava.predicated.v8i16.v8i1(i32 0, i32 1, i32 0, i32 %accReal.1.off0, i32 %accReal.1.off32, <8 x i16> %29, <8 x i16> %30, <8 x i1> %28) 183 %32 = tail call { i32, i32 } @llvm.arm.mve.vmlldava.predicated.v8i16.v8i1(i32 0, i32 0, i32 1, i32 %accImag.1.off0, i32 %accImag.1.off32, <8 x i16> %29, <8 x i16> %30, <8 x i1> %28) 184 %cmp10 = icmp ugt i32 %mul, 8 185 br i1 %cmp10, label %do.body.1, label %if.end.loopexit 186 187do.body.1: ; preds = %do.body 188 %sub9 = add nsw i32 %mul, -8 189 %accImag.1.off32.1 = extractvalue { i32, i32 } %32, 1 190 %accImag.1.off0.1 = extractvalue { i32, i32 } %32, 0 191 %accReal.1.off32.1 = extractvalue { i32, i32 } %31, 1 192 %accReal.1.off0.1 = extractvalue { i32, i32 } %31, 0 193 %33 = tail call <8 x i1> @llvm.arm.mve.vctp16(i32 %sub9) 194 %add.ptr7.1 = getelementptr inbounds i16, ptr %vecSrcA.0.in145, i32 40 195 %add.ptr8.1 = getelementptr inbounds i16, ptr %vecSrcB.0.in146, i32 40 196 %34 = tail call <8 x i16> @llvm.masked.load.v8i16.p0(ptr nonnull %add.ptr7.1, i32 2, <8 x i1> %33, <8 x i16> zeroinitializer) 197 %35 = tail call <8 x i16> @llvm.masked.load.v8i16.p0(ptr nonnull %add.ptr8.1, i32 2, <8 x i1> %33, <8 x i16> zeroinitializer) 198 %36 = tail call { i32, i32 } @llvm.arm.mve.vmlldava.predicated.v8i16.v8i1(i32 0, i32 1, i32 0, i32 %accReal.1.off0.1, i32 %accReal.1.off32.1, <8 x i16> %34, <8 x i16> %35, <8 x i1> %33) 199 %37 = tail call { i32, i32 } @llvm.arm.mve.vmlldava.predicated.v8i16.v8i1(i32 0, i32 0, i32 1, i32 %accImag.1.off0.1, i32 %accImag.1.off32.1, <8 x i16> %34, <8 x i16> %35, <8 x i1> %33) 200 br label %if.end.loopexit 201 202if.else: ; preds = %entry 203 %cmp13120.not = icmp eq i32 %numSamples, 0 204 br i1 %cmp13120.not, label %if.end, label %while.body14.preheader 205 206while.body14.preheader: ; preds = %if.else 207 %mul11 = shl nuw nsw i32 %numSamples, 1 208 br label %while.body14 209 210while.body14: ; preds = %while.body14.preheader, %while.body14 211 %pSrcA.addr.2127 = phi ptr [ %add.ptr16, %while.body14 ], [ %pSrcA, %while.body14.preheader ] 212 %pSrcB.addr.2126 = phi ptr [ %add.ptr17, %while.body14 ], [ %pSrcB, %while.body14.preheader ] 213 %accImag.2.off32125 = phi i32 [ %45, %while.body14 ], [ 0, %while.body14.preheader ] 214 %accImag.2.off0124 = phi i32 [ %46, %while.body14 ], [ 0, %while.body14.preheader ] 215 %accReal.2.off32123 = phi i32 [ %42, %while.body14 ], [ 0, %while.body14.preheader ] 216 %accReal.2.off0122 = phi i32 [ %43, %while.body14 ], [ 0, %while.body14.preheader ] 217 %blkCnt.2121 = phi i32 [ %sub18, %while.body14 ], [ %mul11, %while.body14.preheader ] 218 %38 = tail call <8 x i1> @llvm.arm.mve.vctp16(i32 %blkCnt.2121) 219 %39 = tail call <8 x i16> @llvm.masked.load.v8i16.p0(ptr %pSrcA.addr.2127, i32 2, <8 x i1> %38, <8 x i16> zeroinitializer) 220 %40 = tail call <8 x i16> @llvm.masked.load.v8i16.p0(ptr %pSrcB.addr.2126, i32 2, <8 x i1> %38, <8 x i16> zeroinitializer) 221 %41 = tail call { i32, i32 } @llvm.arm.mve.vmlldava.predicated.v8i16.v8i1(i32 0, i32 1, i32 0, i32 %accReal.2.off0122, i32 %accReal.2.off32123, <8 x i16> %39, <8 x i16> %40, <8 x i1> %38) 222 %42 = extractvalue { i32, i32 } %41, 1 223 %43 = extractvalue { i32, i32 } %41, 0 224 %44 = tail call { i32, i32 } @llvm.arm.mve.vmlldava.predicated.v8i16.v8i1(i32 0, i32 0, i32 1, i32 %accImag.2.off0124, i32 %accImag.2.off32125, <8 x i16> %39, <8 x i16> %40, <8 x i1> %38) 225 %45 = extractvalue { i32, i32 } %44, 1 226 %46 = extractvalue { i32, i32 } %44, 0 227 %add.ptr16 = getelementptr inbounds i16, ptr %pSrcA.addr.2127, i32 8 228 %add.ptr17 = getelementptr inbounds i16, ptr %pSrcB.addr.2126, i32 8 229 %sub18 = add nsw i32 %blkCnt.2121, -8 230 %cmp13 = icmp ugt i32 %blkCnt.2121, 8 231 br i1 %cmp13, label %while.body14, label %if.end.loopexit177 232 233if.end.loopexit: ; preds = %do.body.1, %do.body 234 %.lcssa200 = phi { i32, i32 } [ %31, %do.body ], [ %36, %do.body.1 ] 235 %.lcssa = phi { i32, i32 } [ %32, %do.body ], [ %37, %do.body.1 ] 236 %47 = extractvalue { i32, i32 } %.lcssa200, 1 237 %48 = extractvalue { i32, i32 } %.lcssa200, 0 238 %49 = extractvalue { i32, i32 } %.lcssa, 1 239 %50 = extractvalue { i32, i32 } %.lcssa, 0 240 br label %if.end 241 242if.end.loopexit177: ; preds = %while.body14 243 %51 = extractvalue { i32, i32 } %41, 1 244 %52 = extractvalue { i32, i32 } %41, 0 245 %53 = extractvalue { i32, i32 } %44, 1 246 %54 = extractvalue { i32, i32 } %44, 0 247 br label %if.end 248 249if.end: ; preds = %if.end.loopexit177, %if.else, %if.end.loopexit 250 %accReal.3.off0 = phi i32 [ %48, %if.end.loopexit ], [ 0, %if.else ], [ %52, %if.end.loopexit177 ] 251 %accReal.3.off32 = phi i32 [ %47, %if.end.loopexit ], [ 0, %if.else ], [ %51, %if.end.loopexit177 ] 252 %accImag.3.off0 = phi i32 [ %50, %if.end.loopexit ], [ 0, %if.else ], [ %54, %if.end.loopexit177 ] 253 %accImag.3.off32 = phi i32 [ %49, %if.end.loopexit ], [ 0, %if.else ], [ %53, %if.end.loopexit177 ] 254 %55 = tail call { i32, i32 } @llvm.arm.mve.asrl(i32 %accReal.3.off0, i32 %accReal.3.off32, i32 6) 255 %56 = extractvalue { i32, i32 } %55, 0 256 store i32 %56, ptr %realResult, align 4 257 %57 = tail call { i32, i32 } @llvm.arm.mve.asrl(i32 %accImag.3.off0, i32 %accImag.3.off32, i32 6) 258 %58 = extractvalue { i32, i32 } %57, 0 259 store i32 %58, ptr %imagResult, align 4 260 ret void 261} 262 263declare { i32, i32 } @llvm.arm.mve.vmlldava.v8i16(i32, i32, i32, i32, i32, <8 x i16>, <8 x i16>) #1 264declare <8 x i1> @llvm.arm.mve.vctp16(i32) #1 265declare <8 x i16> @llvm.masked.load.v8i16.p0(ptr, i32 immarg, <8 x i1>, <8 x i16>) #2 266declare { i32, i32 } @llvm.arm.mve.vmlldava.predicated.v8i16.v8i1(i32, i32, i32, i32, i32, <8 x i16>, <8 x i16>, <8 x i1>) #1 267declare { i32, i32 } @llvm.arm.mve.asrl(i32, i32, i32) #1 268