~ubuntu-branches/ubuntu/vivid/atlas/vivid

« back to all changes in this revision

Viewing changes to tune/blas/gemv/MVTCASES/ATL_sgemvT_8x4_neon.S

  • Committer: Package Import Robot
  • Author(s): Sébastien Villemot
  • Date: 2013-06-11 15:58:16 UTC
  • mfrom: (1.1.3 upstream)
  • mto: (2.2.21 experimental)
  • mto: This revision was merged to the branch mainline in revision 26.
  • Revision ID: package-import@ubuntu.com-20130611155816-b72z8f621tuhbzn0
Tags: upstream-3.10.1
Import upstream version 3.10.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *             Automatically Tuned Linear Algebra Software v3.10.1
 
3
 * Copyright (C) 2011 Md. Majedul Haque Sujon
 
4
 *
 
5
 * Redistribution and use in source and binary forms, with or without
 
6
 * modification, are permitted provided that the following conditions
 
7
 * are met:
 
8
 *   1. Redistributions of source code must retain the above copyright
 
9
 *      notice, this list of conditions and the following disclaimer.
 
10
 *   2. Redistributions in binary form must reproduce the above copyright
 
11
 *      notice, this list of conditions, and the following disclaimer in the
 
12
 *      documentation and/or other materials provided with the distribution.
 
13
 *   3. The name of the ATLAS group or the names of its contributers may
 
14
 *      not be used to endorse or promote products derived from this
 
15
 *      software without specific written permission.
 
16
 *
 
17
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 
18
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 
19
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 
20
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE ATLAS GROUP OR ITS CONTRIBUTORS
 
21
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 
22
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 
23
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 
24
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 
25
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 
26
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 
27
 * POSSIBILITY OF SUCH DAMAGE.
 
28
 *
 
29
 */
 
30
#ifndef ATL_GAS_ARM
 
31
   #error "This routine requires GAS/ARM assembly"
 
32
#endif
 
33
#ifndef ATL_NEON
 
34
   #error "This routine requires an ARM NEON SIMD unit!"
 
35
#endif
 
36
#ifndef ATL_NONIEEE
 
37
   #error "This NEON routine requires turning off IEEE compliance!"
 
38
#endif
 
39
 
 
40
 
 
41
/*  Written and Submitted by Md Majedul Haque Sujon  */
 
42
 
 
43
/* Unroll and Scalar expansion:
 
44
 *      I have tried following unroll factors (MxN): 4x2, 4x4, 8x2, 8x4, 8x6
 
45
 *      I found better performance by using 8x4 (better than 8x6). In case of
 
46
 *      8x6, I need to reuse fp registers which reduce the scalar expansion as
 
47
 *      well as increase the data dependency.
 
48
 *
 
49
 * Prefetch:
 
50
 *      I have tried prefetch with offset 128, 64, 32, 16. Surprisingly, I
 
51
 *      found little variation in performance with the parameter.
 
52
 *
 
53
 *
 
54
 * Splitting clean up into 2 cases:
 
55
 *      I have splitted into two separate cases" TALL and FAT. I provided
 
56
 *      separate implementations for each case.
 
57
 *
 
58
 *      --------------------------------
 
59
 *      |                       |      |
 
60
 *      |                       |      |
 
61
 *      |                       |TALL  |
 
62
 *      |                       |CASE  |
 
63
 *      |                       |      |
 
64
 *      |-----------------------       |
 
65
 *      |       FAT CASE        |      |
 
66
 *      |                       |      |
 
67
 *      --------------------------------
 
68
 *
 
69
 *      For cleanup, I first called TALL case and then FAT case which I beleive
 
70
 *      provide better performance. When lda is not very larger than M,prefetch
 
71
 *      helps TALL case.
 
72
 *
 
73
 *      a) TALL case:
 
74
 *              For remaining N<4, TALL case will execute. To provie better
 
75
 *      performance, I want to use maximum the vector operations as much as
 
76
 *      possible. So,   I implement 3 blocks: N==3, N==2 and N==1. Each block
 
77
 *      uses M unrolled by 8 (remaining M%8 elements will fall into scalar loop)
 
78
 *
 
79
 *      b) FAT case:
 
80
 *              For remaining M < 8, the program will execute FAT cases. I use
 
81
 *      saxpy like implementation (loading X in outer loop and loading A and Yin
 
82
 *      innerloop) for this case for better performance.  It provides decent
 
83
 *      performance in comparison with the scalar implementation.
 
84
 *      Yet, I want to maximumize the use of vector ops. So, I implemented 3
 
85
 *      blocks: for M==4, M==2, M==1 (where in M==4, I used unroll of 4 and
 
86
 *      M==2, I used unroll of 2). Any case with 1<=M<8 will execute like this:
 
87
 *      7=4+2+1, 6=4+2, 5=4+1 ... ...
 
88
 *
 
89
 * Alignment:
 
90
 *      Here, A is the main bottle neck. So, aligning X or Y would not work. I
 
91
 *      beleive, striding access of A ( by lda*4 element) and aligning each
 
92
 *      stride of A would improve the performance. I have implemented code for
 
93
 *      strided access but can't complete the cleanup part.
 
94
 *      -----------------------------------------
 
95
 *      |  |  |  |  |   |  |  |  |    |
 
96
 *      |A |  |  |  |A2 |  |  |  | A3 |
 
97
 *      |  |  |  |  |   |  |  |  |    |
 
98
 *      |  |A |  |  |   |A2|  |  |    |
 
99
 *      -----------------------------------------
 
100
 *
 
101
 *  Future work:
 
102
 *      I will incorporate memory alignment optimization with this code.
 
103
 */
 
104
 
 
105
 
 
106
/* KNOWN ISSUE:
 
107
 *      I found a strange problem with the vector operation. In my TALL case,
 
108
 * When M is very large and N=odd like, 1,2,3 there is a floating point
 
109
 * precision problem. ATLAS tester fails with diff=0.000001 ~ 0.000005.
 
110
 * I have checked my code for errors but failed to find any. If I am right,
 
111
 * there may be 2 sources : a) using VMLA instruction. b) using vector
 
112
 * register as scalar (like: d1[0]) to store and load.
 
113
 * I want to use VFMA(Vector Fused Multiply Accumulate) which would provide
 
114
 * better precision but the tested hardware doesn't support this. Reference for
 
115
 * VFMA:
 
116
 *      http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0489c/CIHEJBIE.html
 
117
 *
 
118
 * Please let me know if you find any problem in my code.
 
119
 * RCW: caused by non-IEEE complaint arithmetic of NEON.
 
120
 *
 
121
 *
 
122
 * -- Thanks,
 
123
 *    Md Majedul Haque Sujon.
 
124
 *
 
125
 */
 
126
 
 
127
 
 
128
#define M r0
 
129
#define N r1
 
130
#define A r2
 
131
#define lda r3
 
132
 
 
133
#define X r4
 
134
#define Y r5
 
135
 
 
136
#define A2 r6
 
137
#define A3 r7
 
138
#define A4 r8
 
139
 
 
140
#define lastX r9
 
141
#define lastY r10
 
142
 
 
143
/* mainly used for indexing, used as other purpose if needed*/
 
144
#define II r11
 
145
/* used mainly to check X addr or Y addr*/
 
146
#define CHKXY r12
 
147
 
 
148
/* mainly used for jump location, used for
 
149
 *other purpose if regs are not available
 
150
 */
 
151
 
 
152
#define JTARGCY r14
 
153
 
 
154
#define SP r13
 
155
 
 
156
#define FSIZE_X 100
 
157
#define FSIZE_Y 104
 
158
 
 
159
 
 
160
/*                      r0      r1              r2              r3
 
161
void ATL_UGEMV(const int M, const int N, const float *A, const int lda, const
 
162
    1st overflow                2nd overflow arg
 
163
float *X                ,float *Y)
 
164
*/
 
165
 
 
166
.code 32
 
167
.fpu neon
 
168
.text
 
169
.align 2
 
170
/* .arm */
 
171
.globl ATL_asmdecor(ATL_UGEMV)
 
172
ATL_asmdecor(ATL_UGEMV):
 
173
.type ATL_asmdecor(ATL_UGEMV), %function
 
174
 
 
175
/* save regs */
 
176
 
 
177
push {r4-r11,r14}
 
178
vpush {q4-q7}
 
179
/* stmDB SP!, {r4-r11,r14} */
 
180
 
 
181
#################################
 
182
/* just for a test. ommited  */
 
183
#################################
 
184
//fmrx lastX, FPSCR
 
185
//push {lastX} // need to add 4 to FSIZE_X, FSIZE_Y
 
186
//mvn II, #0xF
 
187
//and II, II, lastX    /* zero exception bits*/
 
188
//bic II, II, #(1<<24) /* turn off flush-to-zero*/
 
189
//fmxr FPSCR, II
 
190
 
 
191
##############################
 
192
 
 
193
/* load parameter */
 
194
ldr X,[SP,#FSIZE_X]
 
195
ldr Y,[SP, #FSIZE_Y]
 
196
 
 
197
 
 
198
/* calculate end of X and Y adddress*/
 
199
add lastX, X, M, LSL #2
 
200
add lastY, Y, N, LSL #2
 
201
 
 
202
PLD [X]
 
203
PLD [A]
 
204
 
 
205
/* calculate address of As*/
 
206
add A2, A, lda, LSL #2
 
207
add A3, A2,lda, LSL #2
 
208
add A4, A3, lda, LSL #2
 
209
 
 
210
PLD [A2]
 
211
PLD [A3]
 
212
PLD [A4]
 
213
 
 
214
/* set jump location for TALL case*/
 
215
ldr JTARGCY, =DONE
 
216
 
 
217
/* N<4?  goto TALL case directly */
 
218
cmp N, #4
 
219
BLT N_LESS_4
 
220
 
 
221
/* flag whether it is not only FAT case, need to track for BETA0 */
 
222
EOR JTARGCY, JTARGCY /* JTARGCY =0 */
 
223
 
 
224
/* M<8? goto FAT case directly*/
 
225
cmp M, #8
 
226
BLT M_LESS_8_N_GE_4
 
227
 
 
228
################################################
 
229
/* M >= 8 and N >= 4 */
 
230
/* M_GE8_NGE4: */
 
231
#################################################
 
232
 
 
233
 
 
234
/* M remaining (M/8)*8 */
 
235
mov II, M, LSR #3
 
236
LSL II, II, #3
 
237
/* CHKXY contains X address upto remainder*/
 
238
add CHKXY, X, II, LSL #2
 
239
 
 
240
/* here JTARGCY is used as end of rounded Y address*/
 
241
mov JTARGCY, N, LSR #2
 
242
LSL JTARGCY, JTARGCY, #2
 
243
add JTARGCY, Y, JTARGCY, LSL #2
 
244
 
 
245
/* calculate distance to point next A-s*/
 
246
LSL lda, lda, #2
 
247
sub lda, lda, II
 
248
LSL lda, lda, #2
 
249
 
 
250
/* no available int reg, but A is needed to be saved
 
251
 * otherwise need to use complex calc with multplication
 
252
 * so I saved it  in stack. ....
 
253
 */
 
254
push {A}
 
255
 
 
256
 
 
257
N4_LOOP:
 
258
 
 
259
/* to ommit the EOR in each N loop, I peel one iteration out, and multiply
 
260
 * and save result to these regs. But the effect is so negligible that it
 
261
 * doesn't improve the performance. For simplicity, I skipped those codes here.
 
262
 */
 
263
 
 
264
/* clear reg */
 
265
VEOR q10, q10, q10
 
266
VEOR q11, q11, q11
 
267
VEOR q12, q12, q12
 
268
VEOR q13, q13, q13
 
269
 
 
270
M8_LOOP:
 
271
        /* load x and all 4 A addr*/
 
272
        VLD1.32 {d0,d1,d2,d3}, [X]!     /* q0, q1 */
 
273
        VLD1.32 {d4,d5,d6,d7},[A]!      /* q2, q3 */
 
274
        VLD1.32 {d8,d9,d10,d11},[A2]!   /* q4, q5 */
 
275
        VLD1.32 {d12,d13,d14,d15},[A3]! /* q6, q7 */
 
276
        VLD1.32 {d16,d17,d18,d19},[A4]! /* q8, q9 */
 
277
 
 
278
        /* prefetch*/
 
279
        PLD [X, #64]
 
280
        PLD [A, #64]
 
281
        PLD [A2,#64]
 
282
 
 
283
        VMLA.F32 q10, q2, q0
 
284
        VMLA.F32 q11, q4, q0
 
285
        VMLA.F32 q12, q6, q0
 
286
        VMLA.F32 q13, q8, q0
 
287
 
 
288
        PLD [A3, #64]
 
289
        PLD [A4, #64]
 
290
 
 
291
        VMLA.F32 q10, q3, q1
 
292
        VMLA.F32 q11, q5, q1
 
293
        VMLA.F32 q12, q7, q1
 
294
        VMLA.F32 q13, q9, q1
 
295
 
 
296
        cmp X, CHKXY
 
297
BNE M8_LOOP
 
298
 
 
299
/*  horizontal pairwise add to add all the scalar expansion */
 
300
VPADD.F32 d28,d20,d21
 
301
VPADD.F32 d29,d22,d23
 
302
VPADD.F32 d30,d24,d25
 
303
VPADD.F32 d31,d26,d27
 
304
 
 
305
VPADD.F32 d20,d28,d29
 
306
VPADD.F32 d21,d30,d31
 
307
 
 
308
/* Store result*/
 
309
 
 
310
#ifdef BETA0
 
311
        VST1.32 {d20-d21},[Y]!
 
312
#else
 
313
        VLD1.32 {d22-d23},[Y]
 
314
        VADD.F32 q10, q10, q11
 
315
        VST1.32 {d20-d21},[Y]!
 
316
#endif
 
317
 
 
318
/* add (lda-M)*4 to A-s, here is the effective distanc here */
 
319
 
 
320
add A, A, lda
 
321
add A2,A2,lda
 
322
add A3,A3,lda
 
323
add A4,A4,lda
 
324
 
 
325
/* position X */
 
326
sub X, X, II, LSL#2
 
327
 
 
328
cmp Y, JTARGCY
 
329
BNE N4_LOOP
 
330
 
 
331
 
 
332
#############################################################
 
333
/* Now, there would be two remaining cases: TALL and FAT
 
334
 * I will call TALL case first
 
335
 *
 
336
 *
 
337
 *      --------------------------------
 
338
 *      |                       |      |
 
339
 *      |                       |      |
 
340
 *      |                       |TALL  |
 
341
 *      |                       |CASE  |
 
342
 *      |                       |      |
 
343
 *      |-----------------------       |
 
344
 *      |       FAT CASE        |      |
 
345
 *      |                       |      |
 
346
 *      --------------------------------
 
347
 *
 
348
 *
 
349
 */
 
350
 
 
351
/* what happens to the registers: */
 
352
 
 
353
/* Now, X == init X + {(M/8)*8}*4 , Y== init Y + ((N/4)*4)*4
 
354
 * lda is changed.. need to restore
 
355
 * M, N = unchanged
 
356
 * A = changed...to next position
 
357
 */
 
358
 
 
359
/* CALL the TALL  case: set parameter*/
 
360
/* restore lda:  lda = (lda + II*4 ) / 16  */
 
361
add lda, lda, II, LSL #2
 
362
LSR lda, lda, #4
 
363
 
 
364
/* X, Y is already set, M would be same, N need to set as remainder*/
 
365
subs N, lastY, JTARGCY
 
366
LSR N, N, #2
 
367
 
 
368
/* set A4 as the original A, as A4 is not used and we may need it in FAT case*/
 
369
pop {A4}
 
370
 
 
371
/* parameter for TALL call: */
 
372
 
 
373
/* Now, X == init X + {(M/8)*8}*4 , Y== init Y + ((N/4)*4)*4
 
374
 * lastX, lastY = unchanged
 
375
 * M, lda = original value
 
376
 * N = N % 4
 
377
 * A4 = original A
 
378
 */
 
379
 
 
380
ldr JTARGCY, =FAT_REM
 
381
BNE N_LESS_4    /* N!=0, then goto TALL CASE*/
 
382
 
 
383
 
 
384
/* CALL the FAT case: */
 
385
 
 
386
FAT_REM:
 
387
 
 
388
/* First check whether there is any FAT case, if no.. no need to arrange param*/
 
389
 
 
390
/* M is unchanged from previous operation in TALL*/
 
391
mov II, M, LSR #3
 
392
subs M, M, II, LSL #3   /* M = remainder of M... set flags to check later*/
 
393
 
 
394
BEQ DONE        /* M==0, no FAT case, goto done*/
 
395
 
 
396
/* arrange parameters */
 
397
 
 
398
/* Now, Y==lastY
 
399
 * X == lastX or init X + {(M/8)*8}*4 depending upon the prev call !!!
 
400
 * lastX, lastY = unchanged
 
401
 * M = original M % 8
 
402
 * lda is unchanged
 
403
 * N = remainder,
 
404
 * A = undef ... depend on condition... need to save before
 
405
 * but A4 can be used to save A, as it is not used in TALL case
 
406
 */
 
407
 
 
408
 mov A, A4
 
409
 
 
410
/* parameter for FAT case should be:
 
411
 * X = initial X + {(M/8)*8}*4
 
412
 * Y = initial Y
 
413
 * lda = original lda
 
414
 * A, A2, A3, A4 = follow X
 
415
 * lastX =original.. not changed
 
416
 * lastY = Y + ((N/4)*4)*4
 
417
 * M = original M % 8
 
418
 * N = (original N/4)* 4
 
419
 * Need to handle BETA0
 
420
 */
 
421
 
 
422
ldr X,[SP, #FSIZE_X]    /* load X again, as X is undefined */
 
423
ldr Y,[SP, #FSIZE_Y]    /* load Y again as Y and N is changed */
 
424
 
 
425
 
 
426
add X, X, II, LSL #5    /* X = X + II* 32 */
 
427
add A, A, II, LSL #5    /* A = A + II* 32 */
 
428
 
 
429
add A2, A, lda, LSL #2
 
430
add A3, A2,lda, LSL #2
 
431
add A4, A3, lda, LSL #2
 
432
 
 
433
sub II, lastY, Y        /* II = original N * 4  */
 
434
mov N, II, LSR #4       /* N = original N/4 */
 
435
LSL N, N, #2            /* N = (N/4)*4  */
 
436
 
 
437
add lastY, Y, N , LSL #2
 
438
 
 
439
 
 
440
/* flag for FAT cases to avoid to store for BETA0 */
 
441
mov JTARGCY, #1
 
442
B M_LESS_8_N_GE_4
 
443
 
 
444
###############################################################
 
445
 
 
446
DONE:
 
447
 
 
448
/*
 
449
//pop {lastX}
 
450
//fmxr FPSCR, lastX
 
451
*/
 
452
 
 
453
 
 
454
/* resotore regs */
 
455
vpop {q4-q7}
 
456
pop {r4-r11,r14}
 
457
 
 
458
/* ldmIA can be used instead of pop*/
 
459
/* ldmIA SP!, {r4-r11,r14} */
 
460
 
 
461
bx lr
 
462
 
 
463
 
 
464
###############################################################
 
465
/*  Special case M>=8(currently M is multiple of 8) N<4  */
 
466
/* TALL A */
 
467
 
 
468
/* Handled each case separately: n=3,2,1*/
 
469
 
 
470
###############################################################
 
471
 
 
472
 
 
473
N_LESS_4:
 
474
 
 
475
/* A4 is not used in this case, I reuse it between two calls*/
 
476
 
 
477
/* M<8 ? goto scalar block*/
 
478
cmp M,#8
 
479
BLT M_LESS8_N_LESS4
 
480
 
 
481
/* II =  (M/8)*8 */
 
482
mov II, M, LSR #3
 
483
LSL II, II, #3
 
484
 
 
485
/* CHKXY contains X address upto remainder*/
 
486
add CHKXY, X, II, LSL #2
 
487
 
 
488
 
 
489
/* N < 3? goto N<=2 test */
 
490
cmp N,#3
 
491
BLT N_LESS_3
 
492
 
 
493
######################################
 
494
/* N == 3 */
 
495
######################################
 
496
 
 
497
/* assuming lda, A, A2, A3 in correct position*/
 
498
/* lastX = last element*/
 
499
 
 
500
/* clear regs*/
 
501
VEOR q2, q2, q2
 
502
VEOR q3, q3, q3
 
503
VEOR q4, q4, q4
 
504
VEOR q5, q5, q5
 
505
VEOR q6, q6, q6
 
506
VEOR q7, q7, q7
 
507
 
 
508
M_N3_LOOP:
 
509
        /* load x and all 4 A addr*/
 
510
        VLD1.32 {d0,d1,d2,d3}, [X]!     /* q0, q1 */
 
511
        VLD1.32 {d16,d17,d18,d19},[A]!  /* q8, q9 */
 
512
        VLD1.32 {d20,d21,d22,d23},[A2]! /* q10, q11 */
 
513
        VLD1.32 {d24,d25,d26,d27},[A3]!  /* q12, q13 */
 
514
 
 
515
        PLD [X, #32]
 
516
        PLD [A, #32]
 
517
        PLD [A2,#32]
 
518
        PLD [A3,#32]
 
519
 
 
520
        VMLA.F32 q2, q8,  q0
 
521
        VMLA.F32 q3, q9, q1
 
522
        VMLA.F32 q4, q10, q0
 
523
        VMLA.F32 q5, q11, q1
 
524
        VMLA.F32 q6, q12,  q0
 
525
        VMLA.F32 q7, q13, q1
 
526
 
 
527
        cmp X, CHKXY
 
528
BNE M_N3_LOOP
 
529
 
 
530
/*add up regs */
 
531
 
 
532
VADD.F32 q14,q2,q3
 
533
VADD.F32 q15,q4,q5
 
534
VADD.F32 q0,q6,q7
 
535
 
 
536
/*  horizontal pairwise add to addup scalar expansion */
 
537
 
 
538
VPADD.F32 d20, d28, d29
 
539
VPADD.F32 d21, d30, d31
 
540
VPADD.F32 d23, d0, d1
 
541
 
 
542
VPADD.F32 d25, d20, d21
 
543
VPADD.F32 d26, d23, d24  /* d24 is garbase, not saved in Y*/
 
544
 
 
545
#ifdef BETA0
 
546
        VST1.32 {d25},[Y]!
 
547
        VST1.32 {d26[0]}, [Y]!
 
548
#else
 
549
        VLD1.32 {d28},[Y]!
 
550
        VLD1.32 {d29[0]}, [Y]!
 
551
 
 
552
        VADD.F32 d28, d28, d25
 
553
        VADD.F32 d29,d29,d26
 
554
        sub Y, Y, #12                   /* restore back the prev value*/
 
555
 
 
556
        VST1.32 {d28},    [Y]!
 
557
        VST1.32 {d29[0]}, [Y]!
 
558
#endif
 
559
 
 
560
cmp CHKXY,lastX
 
561
BxEQ JTARGCY
 
562
 
 
563
/* set Y to initial position*/
 
564
sub Y, Y, #12
 
565
 
 
566
/* set effective lda to move around A in loop*/
 
567
sub II, M, II /* number of remaining element*/
 
568
 
 
569
/* call clean up to complete */
 
570
B CLEANUP_M_LESS_8
 
571
 
 
572
 
 
573
N_LESS_3:
 
574
 
 
575
cmp N, #2
 
576
BLT N_EG_1
 
577
 
 
578
###################################################
 
579
/* N == 2 */
 
580
 
 
581
###################################################
 
582
 
 
583
/* assuming X, A, A2, in correct position*/
 
584
 
 
585
/* clear regs*/
 
586
VEOR q2, q2, q2
 
587
VEOR q3, q3, q3
 
588
VEOR q4, q4, q4
 
589
VEOR q5, q5, q5
 
590
 
 
591
 
 
592
M_N2_LOOP:
 
593
        /* load x and all 4 A addr*/
 
594
        VLD1.32 {d0,d1,d2,d3}, [X]!     /* q0, q1 */
 
595
        VLD1.32 {d18,d19,d20,d21},[A]!  /* q9, q10 */
 
596
        VLD1.32 {d22,d23,d24,d25},[A2]! /* q11, q12 */
 
597
 
 
598
        PLD [X, #32]
 
599
        PLD [A, #32]
 
600
        PLD [A2,#32]
 
601
 
 
602
        VMLA.F32 q2, q9,  q0
 
603
        VMLA.F32 q3, q10, q1
 
604
        VMLA.F32 q4, q11, q0
 
605
        VMLA.F32 q5, q12, q1
 
606
 
 
607
        cmp X, CHKXY
 
608
BNE M_N2_LOOP
 
609
 
 
610
VADD.F32 q6, q2, q3
 
611
VADD.F32 q7, q4, q5
 
612
 
 
613
/*  horizontal pairwise add using vpadd */
 
614
/* horizontal add, rd = d18*/
 
615
 
 
616
VPADD.F32 d17, d14, d15
 
617
VPADD.F32 d16, d12, d13
 
618
VPADD.F32 d18, d16, d17
 
619
 
 
620
 
 
621
#ifdef BETA0
 
622
        VST1.32 {d18},[Y]!
 
623
#else
 
624
        VLD1.32 {d4},[Y]
 
625
        VADD.F32 d18, d18, d4
 
626
        VST1.32 {d18},[Y]!
 
627
#endif
 
628
 
 
629
cmp CHKXY,lastX
 
630
BxEQ JTARGCY
 
631
 
 
632
/* set Y to initial position*/
 
633
sub Y, Y, #8
 
634
 
 
635
 
 
636
/* number of remaining element*/
 
637
sub II, M, II
 
638
 
 
639
/* goto cleanup*/
 
640
 
 
641
B CLEANUP_M_LESS_8
 
642
 
 
643
N_EG_1:
 
644
 
 
645
######################################################
 
646
/* N == 1 */
 
647
 
 
648
######################################################
 
649
 
 
650
/* assuming X, A, in correct position*/
 
651
 
 
652
 
 
653
VEOR q2, q2, q2
 
654
VEOR q3, q3, q3
 
655
 
 
656
M_N1_LOOP:
 
657
        /* load x and all 4 A addr*/
 
658
        VLD1.32 {d0,d1,d2,d3}, [X]!     /* q0, q1 */
 
659
        VLD1.32 {d18,d19,d20,d21},[A]!  /* q9, q10 */
 
660
 
 
661
        PLD [X, #32]
 
662
        PLD [A, #32]
 
663
 
 
664
        VMLA.F32 q2, q9,  q0
 
665
        VMLA.F32 q3, q10, q1
 
666
 
 
667
        cmp X, CHKXY
 
668
BNE M_N1_LOOP
 
669
 
 
670
VADD.F32 q6, q2, q3
 
671
VADD.F32 d14,d12,d13
 
672
 
 
673
VPADD.F32 d16, d14, d13 /* d13 garbase but not used to save in Y*/
 
674
 
 
675
 
 
676
#ifdef BETA0
 
677
        VST1.32 {d16[0]},[Y]!
 
678
#else
 
679
        VLD1.32 {d17[0]},[Y]
 
680
        VADD.F32 d18, d16, d17
 
681
 
 
682
        VST1.32 {d18[0]},[Y]!
 
683
#endif
 
684
 
 
685
cmp CHKXY,lastX
 
686
BxEQ JTARGCY
 
687
 
 
688
/* set Y to initial position*/
 
689
sub Y, Y, #4
 
690
 
 
691
sub II, M, II   /* number of remaining element*/
 
692
 
 
693
/* for BETA0, there may be 2 cases:
 
694
 *      1. 1st case falls through from above cases: need to load Y even in BETA0
 
695
 *      2. 2nd case occurs for the 1st time: no load of Y;
 
696
 */
 
697
 
 
698
/* to reduce extra condition check and simplicity
 
699
 * I separated out this two cases
 
700
 */
 
701
 
 
702
CLEANUP_M_LESS_8:
 
703
 
 
704
/* II is the remainder for X */
 
705
 
 
706
/* use A2 to precalculate lda distance*/
 
707
sub A2, lda, II
 
708
LSL A2, A2, #2
 
709
 
 
710
CLEANUP_NL4_LOOP:
 
711
/* clear reg */
 
712
VEOR d2, d2, d2
 
713
 
 
714
CLEANUP_ML8_LOOP:
 
715
 
 
716
    VLD1.32 {d0[0]},[X]!
 
717
    VLD1.32 {d1[0]}, [A]!
 
718
    VMLA.F32 d2, d1, d0
 
719
 
 
720
    cmp X, lastX
 
721
BNE CLEANUP_ML8_LOOP
 
722
 
 
723
/* No need to use BETA0 macro as it's cleanup case  */
 
724
 
 
725
VLD1.32 {d3[0]}, [Y]
 
726
 
 
727
VADD.F32 d3, d3, d2
 
728
VST1.32 {d3[0]},[Y]!
 
729
 
 
730
 
 
731
add A, A, A2
 
732
sub X, X, II, LSL #2
 
733
 
 
734
cmp Y, lastY
 
735
BNE CLEANUP_NL4_LOOP
 
736
 
 
737
Bx JTARGCY
 
738
 
 
739
 
 
740
###############################################
 
741
/* M<8 and N<4 and M_N_scalar loop*/
 
742
/* scaler implementation , not a fall through case*/
 
743
 
 
744
 
 
745
M_LESS8_N_LESS4:
 
746
 
 
747
/* calculate effective lda once before loop */
 
748
sub lda,lda,M
 
749
LSL lda,lda,#2
 
750
 
 
751
 
 
752
NL4_LOOP:
 
753
/* clear reg */
 
754
VEOR d2, d2, d2
 
755
ML8_LOOP:
 
756
    VLD1.32 {d0[0]},[X]!
 
757
    VLD1.32 {d1[0]}, [A]!
 
758
    VMLA.F32 d2, d1, d0
 
759
    cmp X, lastX
 
760
BNE ML8_LOOP
 
761
 
 
762
#ifdef BETA0
 
763
 
 
764
VST1.32 {d2[0]},[Y]!
 
765
 
 
766
#else
 
767
VLD1.32 {d3[0]}, [Y]
 
768
VADD.F32 d3, d3, d2
 
769
VST1.32 {d3[0]},[Y]!
 
770
 
 
771
#endif
 
772
 
 
773
add A, A, lda
 
774
sub X, X, M, LSL #2
 
775
 
 
776
cmp Y, lastY
 
777
BNE NL4_LOOP
 
778
 
 
779
B DONE
 
780
 
 
781
 
 
782
 
 
783
###############################################################
 
784
/* FAT CASE ........... M < 8  N>=4*/
 
785
###############################################################
 
786
 
 
787
 
 
788
/* All of the below implementation is like SAXPY calculation
 
789
 * main idea:  Load all the X at once, now in inner loop load Y,
 
790
 * do computation and store back to Y....
 
791
 * BETA0 need to be handled carefully
 
792
 */
 
793
 
 
794
###############################################################
 
795
 
 
796
 
 
797
/* need to handle Y clean up for 4,2 case */
 
798
/* Special case M<8 and N>=4, saxpy like implementation*/
 
799
 
 
800
M_LESS_8_N_GE_4:
 
801
 
 
802
/* BETA0, then peel 1st iteration,
 
803
 * for 1st iteration, we need to store without load
 
804
 */
 
805
 
 
806
#ifdef BETA0
 
807
 
 
808
/* JTARGCY==1, it is not direct case, FAT is called for cleanup
 
809
 * so, skipped it
 
810
 */
 
811
 
 
812
cmp JTARGCY, #1
 
813
BEQ STR_SKIPPED
 
814
 
 
815
mov CHKXY, Y
 
816
mov II, A
 
817
 
 
818
VLD1.32 {d0[0]},[X]!
 
819
 
 
820
BETA0_M1_PEEL_LOOP:
 
821
 
 
822
    VLD1.32 {d1[0]}, [A]
 
823
    VMUL.F32 d2, d1, d0
 
824
    VST1.32 {d2[0]},[Y]!
 
825
 
 
826
    add A, A, lda, LSL #2
 
827
    cmp Y, lastY
 
828
    BNE BETA0_M1_PEEL_LOOP
 
829
 
 
830
/* restore Y */
 
831
mov Y, CHKXY
 
832
 
 
833
/* restore A,A2,A3,A4 to their updated position */
 
834
mov A, II
 
835
add A, A, #4
 
836
add A2, A2, #4
 
837
add A3, A3, #4
 
838
add A4, A4, #4
 
839
 
 
840
/* 1 M iteration is done*/
 
841
subs M, M, #1
 
842
BEQ DONE       /* M==0, got to DONE */
 
843
 
 
844
STR_SKIPPED:
 
845
 
 
846
#endif
 
847
 
 
848
 
 
849
/* N remaining II= (N/4)*4 */
 
850
mov II, N, LSR #2
 
851
LSL II, II, #2
 
852
/* CHKXY contains Y address upto remainder*/
 
853
add CHKXY, Y, II, LSL #2
 
854
 
 
855
 
 
856
/* M < 4 ? goto M2 case*/
 
857
cmp M, #4
 
858
BLT M2_N_GE4
 
859
 
 
860
/* M >= 4*/
 
861
############################################################
 
862
 
 
863
M4_N_GE4:
 
864
 
 
865
/* M==4, this implementation is better than M4 x N4 unroll... 2 times better*/
 
866
 
 
867
mov JTARGCY, A /* save A in JTARGCY*/
 
868
 
 
869
 
 
870
/* load all X at once*/
 
871
VLD1.32 {d0-d1}, [X]!
 
872
 
 
873
 
 
874
M4_N_Y_LOOP:
 
875
        VLD1.32 {d2-d3},[A]
 
876
        VLD1.32 {d4-d5},[A2]
 
877
        VLD1.32 {d6-d7},[A3]
 
878
        VLD1.32 {d8-d9},[A4]
 
879
 
 
880
        VLD1.32 {d10,d11},[Y]
 
881
        PLD [Y, #32]
 
882
 
 
883
        VMUL.F32 q1,q1,q0
 
884
        VMUL.F32 q2,q2,q0
 
885
        VMUL.F32 q3,q3,q0
 
886
        VMUL.F32 q4,q4,q0
 
887
 
 
888
        VADD.F32 d12,d2,d3
 
889
        VADD.F32 d13,d4,d5
 
890
        VADD.F32 d14,d6,d7
 
891
        VADD.F32 d15,d8,d9
 
892
 
 
893
        VPADD.F32 d16,d12,d13
 
894
        VPADD.F32 d17,d14,d15
 
895
 
 
896
        VADD.F32 q8,q8,q5
 
897
 
 
898
        VST1.32 {d16,d17},[Y]!
 
899
 
 
900
 
 
901
        add A, A, lda, LSL #4
 
902
        add A2,A2,lda, LSL #4
 
903
        add A3,A3,lda, LSL #4
 
904
        add A4,A4,lda, LSL #4
 
905
 
 
906
    cmp Y, CHKXY
 
907
BNE M4_N_Y_LOOP
 
908
 
 
909
 
 
910
/* no cleanup? goto M remaining check */
 
911
cmp Y,lastY
 
912
BEQ M4_M_REM_CHECK
 
913
 
 
914
/* cleanup for M4 case*/
 
915
 
 
916
/* Restore X to previous position*/
 
917
sub X,X, #16
 
918
 
 
919
VLD1.32 {d0-d1}, [X]!
 
920
M4_N1_Y_LOOP:
 
921
    VLD1.32 {d2-d3},[A]
 
922
    VMUL.F32 q1,q1,q0
 
923
 
 
924
    VPADD.F32 d4,d2,d3
 
925
    VPADD.F32 d6,d4,d5  /* d5 garbase, but not used for Y*/
 
926
 
 
927
    VLD1.32 {d8[0]}, [Y]
 
928
    VADD.F32 d6, d6, d8
 
929
    VST1.32 {d6[0]},[Y]!
 
930
 
 
931
    add A, A, lda, LSL #2
 
932
    cmp Y, lastY
 
933
BNE M4_N1_Y_LOOP
 
934
 
 
935
 
 
936
 
 
937
M4_M_REM_CHECK:
 
938
 
 
939
/* restore Y and position A, A2.... */
 
940
 
 
941
sub Y, CHKXY, II, LSL#2
 
942
 
 
943
mov A, JTARGCY /* restore A*/
 
944
 
 
945
add A, A, #16
 
946
add A2, A, lda, LSL #2
 
947
 
 
948
/* find remaining element for X */
 
949
subs II, M, #4
 
950
BEQ DONE       /* M==0, goto DONE*/
 
951
 
 
952
 
 
953
/* II<2? got to M==1 case*/
 
954
cmp II, #2
 
955
BLT M1_N_GE4
 
956
 
 
957
 
 
958
 
 
959
 
 
960
M2_N_GE4:
 
961
 
 
962
/* M<2? then goto SCALAR implementation*/
 
963
cmp M, #2
 
964
BLT M1_N_GE4
 
965
 
 
966
#################################################
 
967
/* case: for M = 7 (4+2+1), 6 (4+2), 2 and N>>4 */
 
968
/* CHKXY ----> has the addr multiple of 4 of Y */
 
969
 
 
970
/* A3, A4 is not used,
 
971
 * A, Y can be stored in A3, A4
 
972
 */
 
973
 
 
974
/* save A and Y*/
 
975
Mov A3, A
 
976
mov A4, Y
 
977
 
 
978
VLD1.32 {d0}, [X]!
 
979
 
 
980
/* X, A multiple of 2 floats*/
 
981
M2_N_Y_LOOP:
 
982
 
 
983
        VLD1.32 {d2},[A]
 
984
        VLD1.32 {d3},[A2]
 
985
 
 
986
        VLD1.32 {d10},[Y]
 
987
 
 
988
        PLD [Y, #32]
 
989
        VMUL.F32 d4,d2,d0
 
990
        VMUL.F32 d5,d3,d0
 
991
 
 
992
        VPADD.F32 d6,d4,d5
 
993
        VADD.F32 d6,d6,d10
 
994
        VST1.32 {d6},[Y]!
 
995
 
 
996
        add A, A, lda, LSL #3
 
997
        add A2,A2,lda, LSL #3
 
998
 
 
999
    cmp Y, CHKXY
 
1000
BNE M2_N_Y_LOOP
 
1001
 
 
1002
 
 
1003
/* cleanup for N
 
1004
 */
 
1005
 
 
1006
/* check no cleanup for Y, goto M check*/
 
1007
cmp Y,lastY
 
1008
BEQ M2_M_REM_CHECK
 
1009
 
 
1010
 
 
1011
/* Restore X to previous position */
 
1012
sub X,X, #8
 
1013
 
 
1014
VLD1.32 {d0}, [X]!
 
1015
 
 
1016
M2_N1_Y_LOOP:
 
1017
    VLD1.32 {d1},[A]
 
1018
    VMUL.F32 d1,d1,d0
 
1019
 
 
1020
    VPADD.F32 d3,d1,d2  // d2 garbase
 
1021
 
 
1022
    VLD1.32 {d4[0]}, [Y]
 
1023
    VADD.F32 d3, d3, d4
 
1024
    VST1.32 {d3[0]},[Y]!
 
1025
 
 
1026
    add A, A, lda, LSL #2
 
1027
    cmp Y, lastY
 
1028
BNE M2_N1_Y_LOOP
 
1029
 
 
1030
/* remaining M check*/
 
1031
 
 
1032
M2_M_REM_CHECK:
 
1033
/* restote A and Y */
 
1034
/* mov A to appropriate position... A += 8*/
 
1035
mov A, A3
 
1036
add A, A, #8
 
1037
mov Y, A4
 
1038
 
 
1039
/* check whether M is done, if not goto SCALAR loops*/
 
1040
cmp lastX,X
 
1041
BNE M1_N_GE4
 
1042
 
 
1043
B DONE
 
1044
 
 
1045
############################################################
 
1046
/* Complete SCALAR implementation for saxpy like case*/
 
1047
/* needed for odd case of M*/
 
1048
 
 
1049
M1_N_GE4:
 
1050
 
 
1051
VLD1.32 {d0[0]},[X]!
 
1052
 
 
1053
NY_LOOP_SCALAR:
 
1054
 
 
1055
    VLD1.32 {d1[0]}, [A]
 
1056
    VMUL.F32 d2, d1, d0
 
1057
 
 
1058
    VLD1.32 {d3[0]}, [Y]
 
1059
    VADD.F32 d3, d3, d2
 
1060
    VST1.32 {d3[0]},[Y]!
 
1061
 
 
1062
    add A, A, lda, LSL #2
 
1063
    cmp Y, lastY
 
1064
 
 
1065
BNE NY_LOOP_SCALAR
 
1066
 
 
1067
B DONE
 
1068