~ubuntu-branches/ubuntu/utopic/ardour3/utopic

« back to all changes in this revision

Viewing changes to libs/ardour/sse_functions_64bit.s

  • Committer: Package Import Robot
  • Author(s): Felipe Sateler
  • Date: 2013-09-21 19:05:02 UTC
  • Revision ID: package-import@ubuntu.com-20130921190502-8gsftrku6jnzhd7v
Tags: upstream-3.4~dfsg
Import upstream version 3.4~dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
    Copyright (C) 2005-2006 Paul Davis, John Rigg
 
3
 
 
4
    This program is free software; you can redistribute it and/or modify
 
5
    it under the terms of the GNU General Public License as published by
 
6
    the Free Software Foundation; either version 2 of the License, or
 
7
    (at your option) any later version.
 
8
 
 
9
    This program is distributed in the hope that it will be useful,
 
10
    but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
    GNU General Public License for more details.
 
13
 
 
14
    You should have received a copy of the GNU General Public License
 
15
    along with this program; if not, write to the Free Software
 
16
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
17
 
 
18
        Author: Sampo Savolainen
 
19
        64-bit conversion: John Rigg
 
20
 
 
21
    $Id$
 
22
*/
 
23
 
 
24
 
 
25
#; void x86_sse_mix_buffers_with_gain (float *dst, float *src, unsigned int nframes, float gain);
 
26
 
 
27
.globl x86_sse_mix_buffers_with_gain
 
28
        .type   x86_sse_mix_buffers_with_gain,@function
 
29
 
 
30
x86_sse_mix_buffers_with_gain:
 
31
 
 
32
#; %rdi float   *dst
 
33
#; %rsi float   *src    
 
34
#; %rdx unsigned int nframes
 
35
#; %xmm0 float  gain
 
36
 
 
37
        pushq %rbp
 
38
        movq %rsp, %rbp
 
39
 
 
40
        #; save the registers
 
41
        pushq %rbx
 
42
        pushq %rdi
 
43
        pushq %rsi
 
44
        
 
45
        #; if nframes == 0, go to end
 
46
        cmp     $0, %rdx
 
47
        je      .MBWG_END
 
48
 
 
49
        #; Check for alignment
 
50
 
 
51
        movq %rdi, %rax
 
52
        andq $12, %rax #; mask alignment offset
 
53
 
 
54
        movq %rsi, %rbx
 
55
        andq $12, %rbx #; mask alignment offset
 
56
 
 
57
        cmp %rax, %rbx
 
58
        jne .MBWG_NONALIGN #; if not aligned, calculate manually
 
59
 
 
60
        #; if we are aligned
 
61
        cmp $0, %rbx
 
62
        jz .MBWG_SSE
 
63
        
 
64
        #; Pre-loop, we need to run 1-3 frames "manually" without
 
65
        #; SSE instructions
 
66
 
 
67
.MBWG_PRELOOP:
 
68
        
 
69
        #; gain is already in %xmm0
 
70
        movss (%rsi), %xmm1
 
71
        mulss %xmm0, %xmm1
 
72
        addss (%rdi), %xmm1
 
73
        movss %xmm1, (%rdi)
 
74
 
 
75
        addq $4, %rdi #; dst++
 
76
        addq $4, %rsi #; src++
 
77
        decq %rdx         #; nframes--
 
78
        jz .MBWG_END
 
79
 
 
80
        addq $4, %rbx
 
81
        
 
82
        cmp $16, %rbx #; test if we've reached 16 byte alignment
 
83
        jne .MBWG_PRELOOP
 
84
 
 
85
 
 
86
.MBWG_SSE:
 
87
 
 
88
        cmp $4, %rdx #; we know it's not zero, but if it's not >=4, then
 
89
        jnge .MBWG_NONALIGN #; we jump straight to the "normal" code
 
90
 
 
91
        #; gain is already in %xmm0
 
92
        shufps  $0x00, %xmm0, %xmm0
 
93
 
 
94
 
 
95
.MBWG_SSELOOP:
 
96
 
 
97
        movaps  (%rsi), %xmm1 #; source => xmm0
 
98
        mulps   %xmm0,  %xmm1 #; apply gain to source
 
99
        addps   (%rdi), %xmm1 #; mix with destination
 
100
        movaps  %xmm1, (%rdi) #; copy result to destination
 
101
        
 
102
        addq $16, %rdi #; dst+=4
 
103
        addq $16, %rsi #; src+=4
 
104
 
 
105
        subq $4, %rdx #; nframes-=4
 
106
        cmp $4, %rdx
 
107
        jge .MBWG_SSELOOP
 
108
 
 
109
        cmp $0, %rdx
 
110
        je .MBWG_END
 
111
 
 
112
        #; if there are remaining frames, the nonalign code will do nicely
 
113
        #; for the rest 1-3 frames.
 
114
        
 
115
.MBWG_NONALIGN:
 
116
        #; not aligned!
 
117
 
 
118
        #; gain is already in %xmm0
 
119
 
 
120
.MBWG_NONALIGNLOOP:
 
121
 
 
122
        movss (%rsi), %xmm1
 
123
        mulss %xmm0, %xmm1
 
124
        addss (%rdi), %xmm1
 
125
        movss %xmm1, (%rdi)
 
126
        
 
127
        addq $4, %rdi
 
128
        addq $4, %rsi
 
129
        
 
130
        decq %rdx
 
131
        jnz .MBWG_NONALIGNLOOP
 
132
 
 
133
.MBWG_END:
 
134
 
 
135
        popq %rsi
 
136
        popq %rdi
 
137
        popq %rbx
 
138
        
 
139
        #; return
 
140
        leave
 
141
        ret
 
142
 
 
143
.size   x86_sse_mix_buffers_with_gain, .-x86_sse_mix_buffers_with_gain
 
144
 
 
145
 
 
146
#; void x86_sse_mix_buffers_no_gain (float *dst, float *src, unsigned int nframes);
 
147
 
 
148
.globl x86_sse_mix_buffers_no_gain
 
149
        .type   x86_sse_mix_buffers_no_gain,@function
 
150
 
 
151
x86_sse_mix_buffers_no_gain:
 
152
 
 
153
#; %rdi float *dst
 
154
#; %rsi float *src
 
155
#; %rdx unsigned int nframes
 
156
 
 
157
        pushq %rbp
 
158
        movq %rsp, %rbp
 
159
 
 
160
        #; save the registers
 
161
        pushq %rbx
 
162
        pushq %rdi
 
163
        pushq %rsi
 
164
        
 
165
        #; the real function
 
166
 
 
167
        #; if nframes == 0, go to end
 
168
        cmp     $0, %rdx
 
169
        je      .MBNG_END
 
170
 
 
171
        #; Check for alignment
 
172
 
 
173
        movq %rdi, %rax
 
174
        andq $12, %rax #; mask alignment offset
 
175
 
 
176
        movq %rsi, %rbx
 
177
        andq $12, %rbx #; mask alignment offset
 
178
 
 
179
        cmp %rax, %rbx
 
180
        jne .MBNG_NONALIGN #; if not aligned, calculate manually
 
181
 
 
182
        cmp $0, %rbx
 
183
        je .MBNG_SSE
 
184
 
 
185
        #; Pre-loop, we need to run 1-3 frames "manually" without
 
186
        #; SSE instructions
 
187
 
 
188
.MBNG_PRELOOP:
 
189
                
 
190
        movss (%rsi), %xmm0
 
191
        addss (%rdi), %xmm0
 
192
        movss %xmm0, (%rdi)
 
193
 
 
194
        addq $4, %rdi #; dst++
 
195
        addq $4, %rsi #; src++
 
196
        decq %rdx         #; nframes--
 
197
        jz      .MBNG_END
 
198
        addq $4, %rbx
 
199
        
 
200
        cmp $16, %rbx #; test if we've reached 16 byte alignment
 
201
        jne .MBNG_PRELOOP
 
202
 
 
203
.MBNG_SSE:
 
204
 
 
205
        cmp $4, %rdx #; if there are frames left, but less than 4
 
206
        jnge .MBNG_NONALIGN #; we can't run SSE
 
207
 
 
208
.MBNG_SSELOOP:
 
209
 
 
210
        movaps  (%rsi), %xmm0 #; source => xmm0
 
211
        addps   (%rdi), %xmm0 #; mix with destination
 
212
        movaps  %xmm0, (%rdi) #; copy result to destination
 
213
        
 
214
        addq $16, %rdi #; dst+=4
 
215
        addq $16, %rsi #; src+=4
 
216
 
 
217
        subq $4, %rdx #; nframes-=4
 
218
        cmp $4, %rdx
 
219
        jge .MBNG_SSELOOP
 
220
 
 
221
        cmp $0, %rdx
 
222
        je .MBNG_END
 
223
 
 
224
        #; if there are remaining frames, the nonalign code will do nicely
 
225
        #; for the rest 1-3 frames.
 
226
        
 
227
.MBNG_NONALIGN:
 
228
        #; not aligned!
 
229
 
 
230
        movss (%rsi), %xmm0 #; src => xmm0
 
231
        addss (%rdi), %xmm0 #; xmm0 += dst
 
232
        movss %xmm0, (%rdi) #; xmm0 => dst
 
233
        
 
234
        addq $4, %rdi
 
235
        addq $4, %rsi
 
236
        
 
237
        decq %rdx
 
238
        jnz .MBNG_NONALIGN
 
239
 
 
240
.MBNG_END:
 
241
 
 
242
        popq %rsi
 
243
        popq %rdi
 
244
        popq %rbx
 
245
        
 
246
        #; return
 
247
        leave
 
248
        ret
 
249
 
 
250
.size   x86_sse_mix_buffers_no_gain, .-x86_sse_mix_buffers_no_gain
 
251
 
 
252
 
 
253
#; void x86_sse_apply_gain_to_buffer (float *buf, unsigned int nframes, float gain);
 
254
 
 
255
.globl x86_sse_apply_gain_to_buffer
 
256
        .type   x86_sse_apply_gain_to_buffer,@function
 
257
 
 
258
x86_sse_apply_gain_to_buffer:
 
259
 
 
260
#; %rdi  float          *buf    32(%rbp)
 
261
#; %rsi  unsigned int   nframes
 
262
#; %xmm0 float          gain
 
263
#; %xmm1 float          buf[0]
 
264
 
 
265
        pushq %rbp
 
266
        movq %rsp, %rbp
 
267
 
 
268
        #; save %rdi
 
269
        pushq %rdi
 
270
        
 
271
        #; the real function
 
272
 
 
273
        #; if nframes == 0, go to end
 
274
        movq %rsi, %rcx #; nframes
 
275
        cmp     $0, %rcx
 
276
        je      .AG_END
 
277
 
 
278
        #; set up the gain buffer (gain is already in %xmm0)
 
279
        shufps  $0x00, %xmm0, %xmm0
 
280
        
 
281
        #; Check for alignment
 
282
 
 
283
        movq %rdi, %rdx #; buf => %rdx
 
284
        andq $12, %rdx #; mask bits 1 & 2, result = 0, 4, 8 or 12
 
285
        jz      .AG_SSE #; if buffer IS aligned
 
286
 
 
287
        #; PRE-LOOP
 
288
        #; we iterate 1-3 times, doing normal x87 float comparison
 
289
        #; so we reach a 16 byte aligned "buf" (=%rdi) value
 
290
 
 
291
.AGLP_START:
 
292
 
 
293
        #; Load next value from the buffer into %xmm1
 
294
        movss (%rdi), %xmm1
 
295
        mulss %xmm0, %xmm1
 
296
        movss %xmm1, (%rdi)
 
297
 
 
298
        #; increment buffer, decrement counter
 
299
        addq $4, %rdi #; buf++;
 
300
        
 
301
        decq %rcx   #; nframes--
 
302
        jz      .AG_END #; if we run out of frames, we go to the end
 
303
        
 
304
        addq $4, %rdx #; one non-aligned byte less
 
305
        cmp $16, %rdx
 
306
        jne .AGLP_START #; if more non-aligned frames exist, we do a do-over
 
307
 
 
308
.AG_SSE:
 
309
 
 
310
        #; We have reached the 16 byte aligned "buf" ("rdi") value
 
311
 
 
312
        #; Figure out how many loops we should do
 
313
        movq %rcx, %rax #; copy remaining nframes to %rax for division
 
314
        movq $0, %rdx   #; 0 the edx register
 
315
        
 
316
        
 
317
        pushq %rdi
 
318
        movq $4, %rdi
 
319
        divq %rdi #; %rdx = remainder == 0
 
320
        popq %rdi
 
321
 
 
322
        #; %rax = SSE iterations
 
323
        cmp $0, %rax
 
324
        je .AGPOST_START
 
325
 
 
326
        
 
327
.AGLP_SSE:
 
328
 
 
329
        movaps (%rdi), %xmm1
 
330
        mulps %xmm0, %xmm1
 
331
        movaps %xmm1, (%rdi)
 
332
 
 
333
        addq $16, %rdi
 
334
        subq $4, %rcx   #; nframes-=4
 
335
 
 
336
        decq %rax
 
337
        jnz .AGLP_SSE
 
338
 
 
339
        #; Next we need to post-process all remaining frames
 
340
        #; the remaining frame count is in %rcx
 
341
        
 
342
        #; if no remaining frames, jump to the end
 
343
        cmp $0, %rcx
 
344
        andq $3, %rcx #; nframes % 4
 
345
        je .AG_END
 
346
 
 
347
.AGPOST_START:
 
348
 
 
349
        movss (%rdi), %xmm1
 
350
        mulss %xmm0, %xmm1
 
351
        movss %xmm1, (%rdi)
 
352
 
 
353
        #; increment buffer, decrement counter
 
354
        addq $4, %rdi #; buf++;
 
355
        
 
356
        decq %rcx   #; nframes--
 
357
        jnz     .AGPOST_START #; if we run out of frames, we go to the end
 
358
        
 
359
.AG_END:
 
360
 
 
361
 
 
362
        popq %rdi
 
363
        
 
364
        #; return
 
365
        leave
 
366
        ret
 
367
 
 
368
.size   x86_sse_apply_gain_to_buffer, .-x86_sse_apply_gain_to_buffer
 
369
#; end proc
 
370
 
 
371
 
 
372
#; x86_sse_apply_gain_vector(float *buf, float *gain_vector, unsigned int nframes)
 
373
 
 
374
.globl x86_sse_apply_gain_vector
 
375
        .type   x86_sse_apply_gain_vector,@function
 
376
 
 
377
x86_sse_apply_gain_vector:
 
378
 
 
379
#; %rdi float *buf
 
380
#; %rsi float *gain_vector
 
381
#; %rdx unsigned int nframes
 
382
 
 
383
        pushq %rbp
 
384
        movq %rsp, %rbp
 
385
 
 
386
        #; Save registers
 
387
        pushq %rdi
 
388
        pushq %rsi
 
389
        pushq %rbx
 
390
 
 
391
        #; if nframes == 0 go to end
 
392
        cmp $0, %rdx
 
393
        je .AGA_END
 
394
                
 
395
        #; Check alignment
 
396
        movq %rdi, %rax
 
397
        andq $12, %rax
 
398
                
 
399
        movq %rsi, %rbx
 
400
        andq $12, %rbx
 
401
 
 
402
        cmp %rax,%rbx
 
403
        jne .AGA_ENDLOOP
 
404
 
 
405
        cmp $0, %rax
 
406
        jz .AGA_SSE #; if buffers are aligned, jump to the SSE loop
 
407
 
 
408
#; Buffers aren't 16 byte aligned, but they are unaligned by the same amount
 
409
.AGA_ALIGNLOOP:
 
410
                
 
411
        movss (%rdi), %xmm0 #; buf => xmm0
 
412
        movss (%rsi), %xmm1 #; gain value => xmm1
 
413
        mulss %xmm1, %xmm0  #; xmm1 * xmm0 => xmm0
 
414
        movss %xmm0, (%rdi) #; signal with gain => buf
 
415
 
 
416
        decq %rdx
 
417
        jz .AGA_END
 
418
 
 
419
        addq $4, %rdi #; buf++
 
420
        addq $4, %rsi #; gab++
 
421
        
 
422
        addq $4, %rax
 
423
        cmp $16, %rax
 
424
        jne .AGA_ALIGNLOOP
 
425
        
 
426
#; There are frames left for sure, as that is checked in the beginning
 
427
#; and within the previous loop. BUT, there might be less than 4 frames
 
428
#; to process
 
429
 
 
430
.AGA_SSE:
 
431
        movq %rdx, %rax #; nframes => %rax
 
432
        shr $2, %rax #; unsigned divide by 4
 
433
 
 
434
        cmp $0, %rax  #; Jos toimii ilman t�t�, niin kiva
 
435
        je .AGA_ENDLOOP
 
436
 
 
437
.AGA_SSELOOP:
 
438
        movaps (%rdi), %xmm0
 
439
        movaps (%rsi), %xmm1
 
440
        mulps %xmm1, %xmm0
 
441
        movaps %xmm0, (%rdi)
 
442
 
 
443
        addq $16, %rdi
 
444
        addq $16, %rsi
 
445
 
 
446
        decq %rax
 
447
        jnz .AGA_SSELOOP
 
448
 
 
449
        andq $3, %rdx #; Remaining frames are nframes & 3
 
450
        jz .AGA_END
 
451
 
 
452
 
 
453
#; Inside this loop, we know there are frames left to process
 
454
#; but because either there are < 4 frames left, or the buffers
 
455
#; are not aligned, we can't use the parallel SSE ops
 
456
.AGA_ENDLOOP:
 
457
        movss (%rdi), %xmm0 #; buf => xmm0
 
458
        movss (%rsi), %xmm1 #; gain value => xmm1
 
459
        mulss %xmm1, %xmm0  #; xmm1 * xmm0 => xmm0
 
460
        movss %xmm0, (%rdi) #; signal with gain => buf
 
461
 
 
462
        addq $4,%rdi
 
463
        addq $4,%rsi
 
464
        decq %rdx #; nframes--
 
465
        jnz .AGA_ENDLOOP
 
466
 
 
467
.AGA_END:
 
468
 
 
469
        popq %rbx
 
470
        popq %rsi
 
471
        popq %rdi
 
472
 
 
473
        leave
 
474
        ret
 
475
 
 
476
.size   x86_sse_apply_gain_vector, .-x86_sse_apply_gain_vector
 
477
#; end proc
 
478
 
 
479
 
 
480
#; float x86_sse_compute_peak(float *buf, long nframes, float current);
 
481
 
 
482
.globl x86_sse_compute_peak
 
483
        .type   x86_sse_compute_peak,@function
 
484
 
 
485
        
 
486
x86_sse_compute_peak:
 
487
 
 
488
#; %rdi  float          *buf    32(%rbp)
 
489
#; %rsi  unsigned int   nframes
 
490
#; %xmm0 float          current
 
491
#; %xmm1 float          buf[0]
 
492
 
 
493
        pushq %rbp
 
494
        movq %rsp, %rbp
 
495
 
 
496
        #; save %rdi
 
497
        pushq %rdi
 
498
        
 
499
        #; if nframes == 0, go to end
 
500
        movq %rsi, %rcx #; nframes
 
501
        cmp     $0, %rcx
 
502
        je      .CP_END
 
503
 
 
504
        #; create the "abs" mask in %xmm2
 
505
        pushq   $2147483647
 
506
        movss   (%rsp), %xmm2
 
507
        addq    $8, %rsp
 
508
        shufps  $0x00, %xmm2, %xmm2
 
509
 
 
510
        #; Check for alignment
 
511
 
 
512
        #;movq 8(%rbp), %rdi #; buf 
 
513
        movq %rdi, %rdx #; buf => %rdx
 
514
        andq $12, %rdx #; mask bits 1 & 2, result = 0, 4, 8 or 12
 
515
        jz      .CP_SSE #; if buffer IS aligned
 
516
 
 
517
        #; PRE-LOOP
 
518
        #; we iterate 1-3 times, doing normal x87 float comparison
 
519
        #; so we reach a 16 byte aligned "buf" (=%rdi) value
 
520
 
 
521
.LP_START:
 
522
 
 
523
        #; Load next value from the buffer
 
524
        movss (%rdi), %xmm1
 
525
        andps %xmm2, %xmm1
 
526
        maxss %xmm1, %xmm0
 
527
 
 
528
        #; increment buffer, decrement counter
 
529
        addq $4, %rdi #; buf++;
 
530
        
 
531
        decq %rcx   #; nframes--
 
532
        jz      .CP_END #; if we run out of frames, we go to the end
 
533
        
 
534
        addq $4, %rdx #; one non-aligned byte less
 
535
        cmp $16, %rdx
 
536
        jne .LP_START #; if more non-aligned frames exist, we do a do-over
 
537
 
 
538
.CP_SSE:
 
539
 
 
540
        #; We have reached the 16 byte aligned "buf" ("rdi") value
 
541
 
 
542
        #; Figure out how many loops we should do
 
543
        movq %rcx, %rax #; copy remaining nframes to %rax for division
 
544
 
 
545
        shr $2,%rax #; unsigned divide by 4
 
546
        jz .POST_START
 
547
 
 
548
        #; %rax = SSE iterations
 
549
 
 
550
        #; current maximum is at %xmm0, but we need to ..
 
551
        shufps $0x00, %xmm0, %xmm0 #; shuffle "current" to all 4 FP's
 
552
 
 
553
        #;prefetcht0 16(%rdi)
 
554
 
 
555
.LP_SSE:
 
556
 
 
557
        movaps (%rdi), %xmm1
 
558
        andps %xmm2, %xmm1
 
559
        maxps %xmm1, %xmm0
 
560
 
 
561
        addq $16, %rdi
 
562
 
 
563
        decq %rax
 
564
        jnz .LP_SSE
 
565
 
 
566
        #; Calculate the maximum value contained in the 4 FP's in %xmm0
 
567
        movaps %xmm0, %xmm1
 
568
        shufps $0x4e, %xmm1, %xmm1 #; shuffle left & right pairs (1234 => 3412)
 
569
        maxps  %xmm1, %xmm0 #; maximums of the two pairs
 
570
        movaps %xmm0, %xmm1
 
571
        shufps $0xb1, %xmm1, %xmm1 #; shuffle the floats inside the two pairs (1234 => 2143)
 
572
        maxps  %xmm1, %xmm0 
 
573
 
 
574
        #; now every float in %xmm0 is the same value, current maximum value
 
575
        
 
576
        #; Next we need to post-process all remaining frames
 
577
        #; the remaining frame count is in %rcx
 
578
        
 
579
        #; if no remaining frames, jump to the end
 
580
 
 
581
        andq $3, %rcx #; nframes % 4
 
582
        jz .CP_END
 
583
 
 
584
.POST_START:
 
585
 
 
586
        movss (%rdi), %xmm1
 
587
        andps %xmm2, %xmm1
 
588
        maxss %xmm1, %xmm0
 
589
        
 
590
        addq $4, %rdi   #; buf++;
 
591
        
 
592
        decq %rcx               #; nframes--;
 
593
        jnz .POST_START
 
594
 
 
595
.CP_END:
 
596
 
 
597
        popq %rdi
 
598
        
 
599
        #; return
 
600
        leave
 
601
        ret
 
602
 
 
603
.size   x86_sse_compute_peak, .-x86_sse_compute_peak
 
604
#; end proc
 
605
 
 
606
#ifdef __ELF__
 
607
.section .note.GNU-stack,"",%progbits
 
608
#endif
 
609