1 // XXX: we chose to factor *NOT* the numbered argument decoding with the auto-incremented argument
3 #define LL(l) L(numbered_argument_mode__finish_directives__##l)
4 jmp LL(load_directive_state)
5 ASM_ALIGN_ZERO(CACHE_LINE_BYTES_N_LOG2)
9 sub ST_CONV_DIRECTIVE,QWORD_BYTES_N*CD_QWORDS_N // point on the next conversion direction
10 LL(load_directive_state):
11 mov CONV_DIRECTIVE_STATE,qword ptr [ST_CONV_DIRECTIVE+CD_STATE]
12 test CONV_DIRECTIVE_STATE,CD_STATE__PERCENT_DIRECTIVE // we skip percent directives
13 jnz LL(next_directive)
14 // value argument number specification -- START ----------------------------------------------------
15 #define LLL(l) LL(arg_idx__##l)
16 #define VALUE_ARGUMENT_NUMBER rcx
17 // We are in numbered argument mode, all non immediat values are to be given an explicit
18 // argument number like the value to be actually converted. We prefer to scan for the
19 // terminal '$' of the value argument number instead of logically computing the end of this
20 // field (we do that for the following width and precision fields).
21 mov rdi,qword ptr [ST_CONV_DIRECTIVE+CD_START]
22 inc rdi // skip the '%' of the format
23 movzx rax,byte ptr [rdi]
24 movzx rax,byte ptr [rdi+1]
25 mov rsi,rdi // make a copy for later
26 mov rcx,qword ptr [ST_CONV_DIRECTIVE+CD_SPECIFIER] // our "end" for scanning the '$' char
27 sub rcx,rdi // max chars to scan
28 jz L(put_string) // no room for even '$', bail out
30 repne scasb // we did ensure we have at least 1 char to scan
31 jne L(put_string) // failed to find the mandatory '$', bail out
32 // Here, rdi points past the found '$'
33 mov PREVIOUS_SPECIFICATION_END,rdi // keep that for the following flags decoder
34 dec rdi // make '$' the end pointer for the following decimal string conversion
35 xchg rsi,rdi // register dance to fix our registers for the string_decimal_conversion_nocheck inputs
36 lea LINK_REGISTER,[rel LLL(store)]
37 jmp L(string_decimal_conversion_nocheck) // clobber:rax,rdx,rcx(return value),rsi
39 mov qword ptr [ST_CONV_DIRECTIVE+CD_VALUE_ARGUMENT_NUMBER],VALUE_ARGUMENT_NUMBER
40 // track the highest argument number
41 cmp VALUE_ARGUMENT_NUMBER,HIGHEST_ARGUMENT_NUMBER
42 cmova HIGHEST_ARGUMENT_NUMBER,VALUE_ARGUMENT_NUMBER // bigger one, do update
43 #undef VALUE_ARGUMENT_NUMBER
45 // value argument number specification -- END ------------------------------------------------------
46 // flags specification -- START --------------------------------------------------------------------
47 #define LLL(l) LL(flags__##l)
48 #define FLAGS_CHARS_BITMAP rdx
51 // In this mode, flags would always start at the end of the _value_ argument number.
52 mov FLAG,PREVIOUS_SPECIFICATION_END
53 mov FLAGS_CHARS_BITMAP,FLAGS_CHARS_BITMAP_VALUE
54 jmp LLL(load_next_format_char)
56 LLL(next_format_char):
58 LLL(load_next_format_char):
59 mov FLAG_CHAR,byte ptr [FLAG]
60 test FLAG_CHAR,FLAG_CHAR
61 jz L(put_string) // ERROR:unfinished conversion directive
64 test cl,-64 // warp around and mod 64
65 jnz LLL(epilog) // finished
66 bt FLAGS_CHARS_BITMAP,rcx
67 jnc LLL(epilog) // finished
68 //------------------------------------------------------------------------------------------
69 // we have a flag to decode
70 //------------------------------------------------------------------------------------------
72 cmp FLAG_CHAR,0x20 // ' '
73 jne LLL(alternative_form)
74 or CONV_DIRECTIVE_STATE,CD_STATE__FLAGS__SPACE_PREFIX
75 jmp LLL(next_format_char)
76 //------------------------------------------------------------------------------------------
77 LLL(alternative_form):
78 cmp FLAG_CHAR,0x23 // '#'
79 jne LLL(thousands_grouping)
80 or CONV_DIRECTIVE_STATE,CD_STATE__FLAGS__ALTERNATIVE_FORM
81 jmp LLL(next_format_char)
82 //------------------------------------------------------------------------------------------
83 LLL(thousands_grouping):
84 cmp FLAG_CHAR,0x27 // '''
86 or CONV_DIRECTIVE_STATE,CD_STATE__FLAGS__THOUSANDS_GROUPING
87 jmp LLL(next_format_char)
88 //------------------------------------------------------------------------------------------
90 cmp FLAG_CHAR,0x2b // '+'
92 or CONV_DIRECTIVE_STATE,CD_STATE__FLAGS__ALWAYS_SIGN
93 jmp LLL(next_format_char)
94 //------------------------------------------------------------------------------------------
96 cmp FLAG_CHAR,0x2d // '-'
98 or CONV_DIRECTIVE_STATE,CD_STATE__FLAGS__LEFT_JUSTIFY
99 jmp LLL(next_format_char)
100 //------------------------------------------------------------------------------------------
102 cmp FLAG_CHAR,0x30 // '0'
104 or CONV_DIRECTIVE_STATE,CD_STATE__FLAGS__ZERO_PADDING
105 jmp LLL(next_format_char)
106 //------------------------------------------------------------------------------------------
107 ASM_ALIGN_ZERO(CACHE_LINE_BYTES_N_LOG2)
109 test CONV_DIRECTIVE_STATE,CD_STATE__FLAGS_MSK
111 mov PREVIOUS_SPECIFICATION_END,FLAG
112 mov qword ptr [ST_CONV_DIRECTIVE+CD_STATE],CONV_DIRECTIVE_STATE // do a state update here
113 ASM_ALIGN_NOPS(CODE_FETCH_BYTES_N_LOG2)
115 #undef FLAGS_CHARS_BITMAP
119 // width specification -- START --------------------------------------------------------------------
120 #define LLL(l) LL(width__##l)
121 #define WIDTH_START rdi
122 #define WIDTH_END rsi
124 // Width specification, start and last format pointers:
125 // * Width specification start format pointer: if we have a flags specification, then it
126 // will be the end pointer of this flags specification, if we don't have a flags
127 // specification it will be the first char past the _value_ argument number specification,
128 // namely past its '$' marker. Here this is the end of the previous specification.
129 // * Width specification end format pointer: if we have a precision specification, then it
130 // will be the precision marker pointer, if no precision specification are here but we
131 // have a length modifier, then it will be the the start of this length modifier (which
132 // can be 2 chars), and the last case, if we don't even have a length modifier, it will be
133 // the conversion specifier pointer itself.
134 // Of course, if start == end, there is no width specification.
135 //------------------------------------------------------------------------------------------
136 mov WIDTH_START,PREVIOUS_SPECIFICATION_END // we won't need the previous specification end for the precision decoder since we have the '.' marker
137 //------------------------------------------------------------------------------------------
138 mov WIDTH_END,qword ptr [ST_CONV_DIRECTIVE+CD_SPECIFIER]
139 test CONV_DIRECTIVE_STATE,CD_STATE__LENGTH_MODIFIER_MSK
140 cmovnz WIDTH_END,qword ptr [ST_CONV_DIRECTIVE+CD_LENGTH_MODIFIER_START]
141 test CONV_DIRECTIVE_STATE,CD_STATE__PRECISION_FOUND
142 cmovnz WIDTH_END,qword ptr [ST_CONV_DIRECTIVE+CD_PRECISION_MARKER]
143 cmp WIDTH_END,WIDTH_START // check the width is at least 1 char
145 //------------------------------------------------------------------------------------------
146 // The width value may not be an immediat but stored into a function argument. It is
147 // decided with the '*' char.
148 cmp byte ptr [WIDTH_START],0x2a // '*'
150 //------------------------------------------------------------------------------------------
151 // Since we are in numbered argument mode, we have to convert the string of the argument
152 // number. In other words, the width is not an immediat value but an argument number.
153 // The width should have a '$' as the last char (but we don't check for it, we just skip
155 inc WIDTH_START // skip the '*'
156 dec WIDTH_END // skip the '$' but we do not check for it
158 // update the conversion directive state in the stack
159 or CONV_DIRECTIVE_STATE,CD_STATE__WIDTH_IS_ARGUMENT_NUMBER
160 mov qword ptr [ST_CONV_DIRECTIVE+CD_STATE],CONV_DIRECTIVE_STATE
162 // We did check only for a width of 1 char which is not enough
163 cmp WIDTH_END,WIDTH_START
164 jbe L(put_string) // invalid width argument number, bail out
165 //------------------------------------------------------------------------------------------
167 // nocheck decimal string conversion, inputs are properly setup
168 lea LINK_REGISTER,[rel LLL(store)] // using the link register for the return address
169 jmp L(string_decimal_conversion_nocheck) // clobber:rax,rdx,rcx(return value),rsi
171 mov qword ptr [ST_CONV_DIRECTIVE+CD_WIDTH],WIDTH // output of the string decimal conversion code path
172 test CONV_DIRECTIVE_STATE,CD_STATE__WIDTH_IS_ARGUMENT_NUMBER
173 jz LLL(epilog) // width is a immediat value, no highest argument number to update
174 cmp WIDTH,HIGHEST_ARGUMENT_NUMBER // here, width does actually contain the argument number
175 cmova HIGHEST_ARGUMENT_NUMBER,WIDTH
176 ASM_ALIGN_NOPS(CACHE_LINE_BYTES_N_LOG2)
182 // width specification -- END ----------------------------------------------------------------------
183 // precision specification -- START ----------------------------------------------------------------
184 #define LLL(l) LL(precision__##l)
185 #define PRECISION_START rdi
186 #define PRECISION_END rsi
187 #define PRECISION rcx
188 test CONV_DIRECTIVE_STATE,CD_STATE__PRECISION_FOUND
189 jz LL(next_directive) // the precision was inited at 0 once a '.' marker was found
190 // Precision specification, start and last format pointers:
191 // * Precision specification start format pointer: the char following the precision marker.
192 // * Precision specification end format pointer: if we have length modifier it will be its
193 // first char, but if we don't have a length modifier, it will be the pointer on the
195 // Of course, if start == end, there is a precision of 0.
196 //------------------------------------------------------------------------------------------
197 mov PRECISION_START,qword ptr [ST_CONV_DIRECTIVE+CD_PRECISION_MARKER]
198 inc PRECISION_START // skip '.'
199 mov PRECISION_END,qword ptr [ST_CONV_DIRECTIVE+CD_SPECIFIER]
200 test CONV_DIRECTIVE_STATE,CD_STATE__LENGTH_MODIFIER_MSK
201 cmovnz PRECISION_END,qword ptr [ST_CONV_DIRECTIVE+CD_LENGTH_MODIFIER_START]
202 cmp PRECISION_END,PRECISION_START // at least 1 char?
203 je LL(next_directive) // precision was initide to 0 once the '.' marker was found
204 //------------------------------------------------------------------------------------------
205 // The precision value may not be an immediat but stored into a function argument. It is
206 // decided with the '*' char. Since we are in the numbered argument mode, do convert
207 // the string decimal value to an argument number.
208 cmp byte ptr [PRECISION_START],0x2a // '*'
210 //------------------------------------------------------------------------------------------
211 // Since we are in numbered argument mode, we have to convert the string of the argument
212 // number. In other words, the precision is not an immediat value but an argument number.
213 // The precision should have a '$' as the last char (but we don't check for it, we just skip
215 inc PRECISION_START // skip the '*'
216 dec PRECISION_END // skip the '$' which we are not checking for
218 or CONV_DIRECTIVE_STATE,CD_STATE__PRECISION_IS_ARGUMENT_NUMBER
219 mov qword ptr [ST_CONV_DIRECTIVE+CD_STATE],CONV_DIRECTIVE_STATE
221 // We did check only for a width of 1 char which is not enough
222 cmp PRECISION_END,PRECISION_START
223 jbe L(put_string) // invalid precision argument number (this is _not_ the same as being empty), bail out
224 //------------------------------------------------------------------------------------------
226 // nocheck decimal string conversion, inputs are properly setup
227 lea LINK_REGISTER,[rel LLL(store)] // using the link register for the return address
228 jmp L(string_decimal_conversion_nocheck) // clobber:rax,rdx,rcx(return value),rsi
230 mov qword ptr [ST_CONV_DIRECTIVE+CD_PRECISION],PRECISION
231 test CONV_DIRECTIVE_STATE,CD_STATE__PRECISION_IS_ARGUMENT_NUMBER
232 jz LL(next_directive) // precision is a immediat value, no highest argument number to update
233 cmp PRECISION,HIGHEST_ARGUMENT_NUMBER // here, precision does actually contain the argument number
234 cmova HIGHEST_ARGUMENT_NUMBER,PRECISION
235 jmp LL(next_directive)
236 #undef LLL // precision
237 // precision specification -- END-------------------------------------------------------------------
238 #undef LL // numbered_argument_mode__finish_directives