Add string vectorized find and detection functions
[glibc.git] / sysdeps / i386 / stpncpy.S
blobb38a94541c33f0ca02f1e63f24ee5685f21ecc63
1 /* copy no more than N bytes from SRC to DEST, returning the address of
2    the terminating '\0' in DEST.
3    For Intel 80x86, x>=3.
4    Copyright (C) 1994-2023 Free Software Foundation, Inc.
5    This file is part of the GNU C Library.
7    The GNU C Library is free software; you can redistribute it and/or
8    modify it under the terms of the GNU Lesser General Public
9    License as published by the Free Software Foundation; either
10    version 2.1 of the License, or (at your option) any later version.
12    The GNU C Library 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 GNU
15    Lesser General Public License for more details.
17    You should have received a copy of the GNU Lesser General Public
18    License along with the GNU C Library; if not, see
19    <https://www.gnu.org/licenses/>.  */
21 #include <sysdep.h>
22 #include "asm-syntax.h"
24 #define PARMS   4+4     /* space for 1 saved reg */
25 #define RTN     PARMS
26 #define DEST    RTN
27 #define SRC     DEST+4
28 #define LEN     SRC+4
30         .text
31 ENTRY (__stpncpy)
33         pushl %esi
34         cfi_adjust_cfa_offset (4)
36         movl DEST(%esp), %eax
37         movl SRC(%esp), %esi
38         cfi_rel_offset (esi, 0)
39         movl LEN(%esp), %ecx
41         subl %eax, %esi         /* magic: reduce number of loop variants
42                                    to one using addressing mode */
43         jmp L(1)                /* jump to loop "head" */
45         ALIGN(4)
47         /* Four times unfolded loop with two loop counters.  We get the
48            third value (the source address) by using the index+base
49            addressing mode.  */
50 L(2):   movb (%eax,%esi), %dl   /* load current char */
51         movb %dl, (%eax)        /* and store it */
52         testb %dl, %dl          /* was it NUL? */
53         jz L(7)                 /* yes, then exit */
55         movb 1(%eax,%esi), %dl  /* load current char */
56         movb %dl, 1(%eax)       /* and store it */
57         testb %dl, %dl          /* was it NUL? */
58         jz L(6)                 /* yes, then exit */
60         movb 2(%eax,%esi), %dl  /* load current char */
61         movb %dl, 2(%eax)       /* and store it */
62         testb %dl, %dl          /* was it NUL? */
63         jz L(5)                 /* yes, then exit */
65         movb 3(%eax,%esi), %dl  /* load current char */
66         movb %dl, 3(%eax)       /* and store it */
67         testb %dl, %dl          /* was it NUL? */
68         jz L(4)                 /* yes, then exit */
70         addl $4, %eax           /* increment loop counter for full round */
72 L(1):   subl $4, %ecx           /* still more than 4 bytes allowed? */
73         jae L(2)                /* yes, then go to start of loop */
75         /* The maximal remaining 15 bytes are not processed in a loop.  */
77         addl $4, %ecx           /* correct above subtraction */
78         jz L(9)                 /* maximal allowed char reached => go to end */
80         movb (%eax,%esi), %dl   /* load current char */
81         movb %dl, (%eax)        /* and store it */
82         testb %dl, %dl          /* was it NUL? */
83         jz L(3)                 /* yes, then exit */
85         incl %eax               /* increment pointer */
86         decl %ecx               /* decrement length counter */
87         jz L(9)                 /* no more allowed => exit */
89         movb (%eax,%esi), %dl   /* load current char */
90         movb %dl, (%eax)        /* and store it */
91         testb %dl, %dl          /* was it NUL? */
92         jz L(3)                 /* yes, then exit */
94         incl %eax               /* increment pointer */
95         decl %ecx               /* decrement length counter */
96         jz L(9)                 /* no more allowed => exit */
98         movb (%eax,%esi), %dl   /* load current char */
99         movb %dl, (%eax)        /* and store it */
100         testb %dl, %dl          /* was it NUL? */
101         jz L(3)                 /* yes, then exit */
103         incl %eax               /* increment pointer */
104         jmp L(9)                /* we don't have to test for counter underflow
105                                    because we know we had a most 3 bytes
106                                    remaining => exit */
108         /* When coming from the main loop we have to adjust the pointer.  */
109 L(4):   decl %ecx               /* decrement counter */
110         incl %eax               /* increment pointer */
112 L(5):   decl %ecx               /* increment pointer */
113         incl %eax               /* increment pointer */
115 L(6):   decl %ecx               /* increment pointer */
116         incl %eax               /* increment pointer */
117 L(7):
119         addl $3, %ecx           /* correct pre-decrementation of counter
120                                    at the beginning of the loop; but why 3
121                                    and not 4?  Very simple, we have to count
122                                    the NUL char we already wrote.  */
123         jz L(9)                 /* counter is also 0 => exit */
125         /* We now have to fill the rest of the buffer with NUL.  This
126            is done in a tricky way.  Please note that the addressing mode
127            used below is not the same we used above.  Here we use the
128            %ecx register.  */
129 L(8):
130         movb $0, (%ecx,%eax)    /* store NUL char */
131 L(3):   decl %ecx               /* all bytes written? */
132         jnz L(8)                /* no, then again */
134 L(9):   popl %esi               /* restore saved register content */
135         cfi_adjust_cfa_offset (-4)
136         cfi_restore (esi)
138         ret
139 END (__stpncpy)
141 libc_hidden_def (__stpncpy)
142 weak_alias (__stpncpy, stpncpy)