Imported Upstream version 3.2.2
[debian/gnuradio] / gnuradio-core / src / lib / filter / fcomplex_dotprod_sse.S
1 #
2 # Copyright 2002 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_complex_blocks is != 0
25 #       
26 #
27 #  fcomplex_dotprod_generic (const float *input,
28 #                         const float *taps, unsigned n_2_complex_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];
38 #      sum1 += input[0] * taps[1];
39 #      sum2 += input[1] * taps[2];
40 #      sum3 += input[1] * taps[3];
41 #  
42 #      input += 2;
43 #      taps += 4;
44 #  
45 #    } while (--n_2_complex_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
58         .file   "fcomplex_dotprod_sse.S"
59         .version        "01.01"
60 .text
61         .p2align 4
62 .globl GLOB_SYMB(fcomplex_dotprod_sse)
63         DEF_FUNC_HEAD(fcomplex_dotprod_sse)
64 GLOB_SYMB(fcomplex_dotprod_sse):
65         pushl   %ebp
66         movl    %esp, %ebp
67         movl    8(%ebp), %eax           # input
68         movl    12(%ebp), %edx          # taps
69         movl    16(%ebp), %ecx
70
71         
72         # xmm0 xmm1 xmm2 xmm3 are used to hold taps and the result of mults
73         # xmm4 xmm5 xmm6 xmm7 are used to hold the accumulated results
74
75         xorps   %xmm4, %xmm4            # zero two accumulators
76         xorps   %xmm5, %xmm5            # xmm5 holds zero for use below
77
78         # first handle any non-zero remainder of (n_2_complex_blocks % 4)
79
80         andl    $0x3, %ecx
81         jmp     .L1_test
82
83         .p2align 4
84 .Loop1: 
85
86         movlps  0(%eax), %xmm0
87         shufps  $0x50, %xmm0, %xmm0     # b01010000
88
89         mulps   (%edx), %xmm0
90         addl    $0x10, %edx
91         addl    $8, %eax
92         addps   %xmm0, %xmm4
93 .L1_test:       
94         decl    %ecx
95         jge     .Loop1
96
97         
98         # set up for primary loop which is unrolled 4 times
99         
100         movl    16(%ebp), %ecx
101         movaps  %xmm5, %xmm6            # zero remaining accumulators
102         movaps  %xmm5, %xmm7 
103
104         shrl    $2, %ecx                # n_2_complex_blocks / 4
105         je      .Lcleanup               # if zero, take short path
106
107         # finish setup and loop priming
108
109         movlps  0(%eax), %xmm0
110
111         movaps  %xmm5, %xmm2
112         movaps  %xmm5, %xmm3
113
114         movlps  8(%eax), %xmm1
115         shufps  $0x50, %xmm0, %xmm0
116
117         shufps  $0x50, %xmm1, %xmm1
118
119         # we know ecx is not zero, we checked above,
120         # hence enter loop at top
121
122         .p2align 4
123 .Loop2:
124         addps   %xmm2, %xmm6
125         movlps  0x10(%eax), %xmm2
126
127         addps   %xmm3, %xmm7
128
129         mulps   (%edx), %xmm0
130
131         movlps  0x18(%eax), %xmm3
132         shufps  $0x50, %xmm2, %xmm2
133
134         mulps   0x10(%edx), %xmm1
135
136         shufps  $0x50, %xmm3, %xmm3
137
138         addps   %xmm0, %xmm4
139         movlps  0x20(%eax), %xmm0
140
141         addps   %xmm1, %xmm5
142
143         mulps   0x20(%edx), %xmm2
144         
145         movlps  0x28(%eax), %xmm1
146         shufps  $0x50, %xmm0, %xmm0
147
148         mulps   0x30(%edx), %xmm3
149
150         shufps  $0x50, %xmm1, %xmm1
151
152         addl    $0x40, %edx
153         addl    $0x20, %eax
154         decl    %ecx
155         jne     .Loop2
156
157         # OK, now we've done with all the multiplies, but
158         # we still need to handle the unaccumulated
159         # products in xmm2 and xmm3
160
161         addps   %xmm2, %xmm6
162         addps   %xmm3, %xmm7
163
164         # now we want to add all accumulators into xmm4
165
166         addps   %xmm5, %xmm4
167         addps   %xmm6, %xmm7
168         addps   %xmm7, %xmm4
169
170         
171         # At this point, xmm4 contains 2x2 partial sums.  We need
172         # to compute a "horizontal complex add" across xmm4.  
173         
174 .Lcleanup:                              # xmm4 = r1 i2 r3 i4
175         movl    20(%ebp), %eax          # @result
176         movhlps %xmm4, %xmm0            # xmm0 = ?? ?? r1 r2
177         addps   %xmm4, %xmm0            # xmm0 = ?? ?? r1+r3 i2+i4
178         movlps  %xmm0, (%eax)           # store low 2x32 bits (complex) to memory
179
180         popl    %ebp
181         ret
182
183 FUNC_TAIL(fcomplex_dotprod_sse)
184         .ident  "Hand coded x86 SSE assembly"
185
186 #if defined(__linux__) && defined(__ELF__)
187 .section .note.GNU-stack,"",%progbits
188 #endif