Imported Upstream version 3.2.2
[debian/gnuradio] / gnuradio-core / src / lib / filter / ccomplex_dotprod_3dnowext64.S
1 #
2 # Copyright 2002,2005 Free Software Foundation, Inc.
3
4 # This file is part of GNU Radio
5
6 # GNU Radio is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 3, or (at your option)
9 # any later version.
10
11 # GNU Radio is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 # GNU General Public License for more details.
15
16 # You should have received a copy of the GNU General Public License
17 # along with GNU Radio; see the file COPYING.  If not, write to
18 # the Free Software Foundation, Inc., 51 Franklin Street,
19 # Boston, MA 02110-1301, USA.
20
21
22
23 # input and taps are guarenteed to be 16 byte aligned.
24 # n_2_ccomplex_blocks is != 0
25 #       
26 #
27 #  ccomplex_dotprod_generic (const float *input,
28 #                         const float *taps, unsigned n_2_ccomplex_blocks, float *result)
29 #  {
30 #    float sum0 = 0;
31 #    float sum1 = 0;
32 #    float sum2 = 0;
33 #    float sum3 = 0;
34 #  
35 #    do {
36 #  
37 #      sum0 += input[0] * taps[0] - input[1] * taps[1];
38 #      sum1 += input[0] * taps[1] + input[1] * taps[0];
39 #      sum2 += input[2] * taps[2] - input[3] * taps[3];
40 #      sum3 += input[2] * taps[3] + input[3] * taps[2];
41 #  
42 #      input += 4;
43 #      taps += 4;
44 #  
45 #    } while (--n_2_ccomplex_blocks != 0);
46 #  
47 #  
48 #    result[0] = sum0 + sum2;
49 #    result[1] = sum1 + sum3;
50 #  }
51 #               
52
53 # TODO: prefetch and better scheduling
54
55 #include "assembly.h"
56
57         .file   "ccomplex_dotprod_3dnowext64.S"
58         .version        "01.01"
59 .text
60         .p2align 4
61 .globl GLOB_SYMB(ccomplex_dotprod_3dnowext)
62         DEF_FUNC_HEAD(ccomplex_dotprod_3dnowext)
63 GLOB_SYMB(ccomplex_dotprod_3dnowext):
64
65         # intput: rdi, taps: rsi, n_2_ccomplex_blocks: rdx, result: rcx
66
67         mov     %rdx, %rax
68
69
70         # zero accumulators
71         
72         pxor    %mm6, %mm6              # mm6 = 0 0 
73         pxor    %mm7, %mm7              # mm7 = 0 0
74
75         movq    0(%rdi), %mm0
76         movq    0(%rsi), %mm2
77
78         shr     $1, %rax                # rax = n_2_ccomplex_blocks / 2
79
80         movq    8(%rdi), %mm1
81         movq    8(%rsi), %mm3
82         
83
84         jmp     .L1_test
85
86         #
87         # 4 taps / loop
88         # something like ?? cycles / loop
89         #
90         
91         .p2align 4
92 .Loop1: 
93
94 # complex prod: C += A * B,  w/ temp Z
95 #
96 #       movq    0(%rdi), %mmA
97 #       movq    0(%rsi), %mmB
98 #       pswapd  %mmA, %mmZ
99 #       pfmul   %mmB, %mmA
100 #       pfmul   %mmZ, %mmB
101 #       pfpnacc %mmB, %mmA
102 #       pfadd   %mmA, %mmC
103
104
105 # A=mm0, B=mm2, Z=mm4
106 # A'=mm1, B'=mm3, Z'=mm5
107
108         pswapd  %mm0, %mm4
109         pfmul   %mm2, %mm0
110         pswapd  %mm1, %mm5
111         pfmul   %mm4, %mm2
112         pfmul   %mm3, %mm1
113         pfpnacc %mm2, %mm0
114         pfmul   %mm5, %mm3
115         movq    16(%rsi), %mm2
116         pfpnacc %mm3, %mm1
117         movq    24(%rsi), %mm3
118
119         pfadd   %mm0, %mm6
120         movq    16(%rdi), %mm0
121         pfadd   %mm1, %mm7
122         movq    24(%rdi), %mm1
123
124 # unroll
125
126         pswapd  %mm0, %mm4
127         pfmul   %mm2, %mm0
128         pswapd  %mm1, %mm5
129         pfmul   %mm4, %mm2
130         pfmul   %mm3, %mm1
131         pfpnacc %mm2, %mm0
132         pfmul   %mm5, %mm3
133         movq    32(%rsi), %mm2
134         pfpnacc %mm3, %mm1
135         movq    40(%rsi), %mm3
136
137         pfadd   %mm0, %mm6
138         movq    32(%rdi), %mm0
139         pfadd   %mm1, %mm7
140         movq    40(%rdi), %mm1
141
142         add     $32, %rsi
143         add     $32, %rdi
144
145 .L1_test:
146         dec     %rax
147         jge     .Loop1
148
149         # We've handled the bulk of multiplies up to here.
150         # Let's see if original n_2_ccomplex_blocks was odd.
151         # If so, we've got 2 more taps to do.
152         
153         and     $1, %rdx
154         je      .Leven
155         
156         # The count was odd, do 2 more taps.
157         # Note that we've already got mm0/mm2 & mm1/mm3 preloaded
158         # from the main loop.
159         
160 # A=mm0, B=mm2, Z=mm4
161 # A'=mm1, B'=mm3, Z'=mm5
162
163         pswapd  %mm0, %mm4
164         pfmul   %mm2, %mm0
165         pswapd  %mm1, %mm5
166         pfmul   %mm4, %mm2
167         pfmul   %mm3, %mm1
168         pfpnacc %mm2, %mm0
169         pfmul   %mm5, %mm3
170         pfpnacc %mm3, %mm1
171
172         pfadd   %mm0, %mm6
173         pfadd   %mm1, %mm7
174
175 .Leven:
176         # at this point mm6 and mm7 contain partial sums
177         
178         pfadd   %mm7, %mm6
179
180         movq    %mm6, (%rcx)            # result
181
182         femms
183
184         retq
185
186 FUNC_TAIL(ccomplex_dotprod_3dnowext)
187         .ident  "Hand coded x86_64 3DNow!Ext assembly"
188
189
190 #if defined(__linux__) && defined(__ELF__)
191 .section .note.GNU-stack,"",%progbits
192 #endif