Imported Upstream version 3.2.2
[debian/gnuradio] / gcell / lib / general / spu / memset.S
1 /* -*- asm -*- */
2 /*
3  * Copyright 2008 Free Software Foundation, Inc.
4  * 
5  * This file is part of GNU Radio
6  * 
7  * GNU Radio is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3, or (at your option)
10  * any later version.
11  * 
12  * GNU Radio is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  */
21
22 #include <gcell/spu/gc_spu_macs.h>
23
24         .file "memset.S"
25
26         /*
27          * Computes this, only a lot faster...
28          *
29          *      void *
30          *      memset(void *pv, int c, size_t n)
31          *      {
32          *        unsigned char *p = (unsigned char *) pv;
33          *        size_t i;
34          *        for (i = 0; i < n; i++)
35          *          p[i] = c;
36          *      
37          *        return pv;
38          *      }
39          */
40         
41 #define p_arg   arg1    // we're going to clobber arg1 w/ the return value
42 #define c       arg2    // the constant we're writing
43 #define n       arg3    // how many bytes to write
44
45 #define p       r13     // where we're writing
46 #define t0      r14
47 #define t1      r15
48 #define mask    r16
49 #define old     r17
50 #define an      r18     // aligned n (n rounded down to mod 16 boundary)
51 #define next_p  r19
52 #define cond1   r20
53 #define cond2   r21                             
54 #define m       r22
55 #define r       r23
56         
57         PROC_ENTRY(memset)
58         
59         // Hint the return from do_head, in case we go that way.
60         // There's pretty much nothing to can do to hint the branch to it.
61         hbrr    do_head_br, head_complete
62         
63         MR(p, p_arg)    // leaves p, the return value, in the correct reg (r3)
64         BRZ_RETURN(n)
65
66         MODULO(t0, p, 16)       // is p%16 == 0?
67         VSPLTB(c, c, 3)         // splat byte in preferred slot of c into all slots
68         brnz    t0, do_head     // no, handle it
69 head_complete:
70
71         /*
72          * preconditions:       
73          *   p%16 == 0, n > 0
74          */
75         hbrr    middle_loop_br, middle_loop
76         
77         ROUND_DOWN(an, n, 16)   // an is "aligned n"
78         MODULO(n, n, 16)        // what's left over in the last quad
79         brz     an, do_tail     // no whole quad words; skip to tail
80         clgti   t0, an, 127     // an >= 128?
81         brz     t0, middle2     // nope, go handle the cases between 0 and 112
82
83         /*
84          * 128 bytes / iteration
85          */
86         .p2align 4
87 middle_loop:
88         ai      an, an, -128
89           stqd  c,  0*16(p)
90         ai      next_p, p, 128
91           stqd  c,  1*16(p)
92         cgti    cond1, an, 127
93           stqd  c,  2*16(p)
94
95           stqd  c,  3*16(p)
96           stqd  c,  4*16(p)
97           stqd  c,  5*16(p)
98           stqd  c,  6*16(p)
99         
100         MR(p, next_p)
101           stqd  c,  7*16-128(next_p)
102         or      cond2, n, an
103 middle_loop_br:
104           brnz  cond1, middle_loop
105         
106         /*
107          * if an and n are both zero, return now 
108          */
109         BRZ_RETURN(cond2)
110
111         /*
112          * otherwise handle last of full quad words 
113          *
114          *   0 <= an < 128, p%16 == 0
115          */
116 middle2:
117         /*
118          * if an == 0, go handle the final non-full quadword
119          */
120         brz     an, do_tail
121         hbrr    middle2_loop_br, middle2_loop
122         
123         .p2align 3
124 middle2_loop:   
125         ai      next_p, p, 16
126           stqd  c, 0(p)
127         ai      an, an, -16
128           LMR(p, next_p)
129 middle2_loop_br:
130           brnz  an, middle2_loop
131         
132         /* We're done with the full quadwords. */
133         
134         /*
135          * Handle the final partial quadword.
136          * We'll be modifying only the left hand portion of the quad.
137          *
138          * preconditions:
139          *   an == 0, 0 <= n < 16, p%16 == 0
140          */
141 do_tail:
142         HINT_RETURN(do_tail_ret)
143         il      mask, -1
144         sfi     t1, n, 16               // t1 = 16 - n
145         lqd     old, 0(p)
146         shlqby  mask, mask, t1
147         selb    t0, old, c, mask
148         stqd    t0, 0(p)
149 do_tail_ret:    
150         RETURN()
151
152         /*
153          * ----------------------------------------------------------------
154          * Handle the first partial quadword
155          *
156          * preconditions:
157          *   p%16 != 0
158          *
159          * postconditions:
160          *   p%16 == 0 or n == 0
161          *
162          *        |-- m --|
163          *     +----------------+----------------+
164          *     |  ////////      |                |
165          *     +----------------+----------------+
166          *        |----- r -----|
167          *        p
168          * ----------------------------------------------------------------
169          */
170 do_head:
171         lqd     old, 0(p)
172         MODULO_NEG(r, p, 16)
173         il      mask, -1
174         UMIN(m, r, n)
175         shlqby  mask, mask, m   // 1's in the top, m*8 0's in the bottom
176         MR(t1, p)
177         sf      t0, m, r        // t0 = r - m
178         a       p, p, m         // p += m
179         rotqby  mask, mask, t0  // rotate 0's to the right place        
180         sf      n, m, n         // n -= m
181         selb    t0, c, old, mask // merge
182         stqd    t0, 0(t1)
183         BRZ_RETURN(n)
184 do_head_br:
185         br      head_complete