my_strtoll10-x86.s 8.52 KB
Newer Older
unknown's avatar
unknown committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396
# Copyright (C) 2003 MySQL AB
# This program is free software; you can resistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307	USA

# Implemention of my_strtoll():  Converting a string to a 64 bit integer.

	.file	"my_strtoll10-x86.s"
	.version "01.01"
.data
	.align 32
	.type	 lfactor,@object
	.size	 lfactor,36
lfactor:
	.long 1
	.long 10
	.long 100
	.long 1000
	.long 10000
	.long 100000
	.long 1000000
	.long 10000000
	.long 100000000
.text
	.align 4
	
.globl my_strtoll10
	.type	 my_strtoll10,@function


	# Used stack variables
	# ebp-4		dummy for storing endptr if endptr = 0
	# ebp-8		First 9 digits of return values
	# ebp-12	Pointer to first digit of second part
	# ebp-16	Store lowest 2 digits
	# ebp-20	!= 0 if value was negative
	# ebp-24	High max value
	# ebp-28	Middle max value
	# ebp-32	Low max value
	# ebp-36	Temp value

	# esi		Pointer to input string
	# ebx		End of string
	
my_strtoll10:
	pushl %ebp
	movl %esp,%ebp
	subl $48,%esp
	pushl %esi
	pushl %edi
	pushl %ebx
	movl 8(%ebp),%esi	# esi= nptr
	movl 16(%ebp),%ecx	# ecx= error (Will be overwritten later)
	movl 12(%ebp),%eax	# eax= endptr
	cld			# Move forward in esi
	cmpl $0,%eax		# if (endptr)
	je .L110

# Fixed length string
	movl (%eax),%ebx	# bx= end-of-string
	.p2align 4,,7
.L100:
	cmpl %ebx,%esi
	je .Lno_conv
	lodsb			# al= next byte
	cmpb $32,%al		# Skip space
	je .L100
	cmpb $9,%al		# Skip tab
	je .L100
	jmp .L130

# String that ends with \0

.L110:
	leal -4(%ebp),%edi
	movl %edi,12(%ebp)	# endptr= &dummy, for easier end check
	.p2align 4,,7
.L120:
	lodsb			# al= next byte
	cmpb $32,%al
	je .L120
	cmpb $9,%al
	je .L120
	testb %al,%al		# Test if we found end \0
	je .Lno_conv
	leal 65535(%esi),%ebx	# ebx = end-of-string

.L130:
	cmpb $45,%al		# Test if '-'
	jne .Lpositive

	# negative number
	movl $-1,(%ecx)		# error = -1 (mark that number is negative)
	movl $1,-20(%ebp)	# negative= 1
	movl $92233720,-24(%ebp)
	movl $368547758,-28(%ebp)
	movl $8,-32(%ebp)
	jmp .L460

	.p2align 4,,7
.Lpositive:
	movl $0,(%ecx)		# error=0
	movl $0,-20(%ebp)	# negative= 0
	movl $184467440,-24(%ebp)
	movl $737095516,-28(%ebp)
	movl $15,-32(%ebp)
	cmpb $43,%al		# Check if '+'
	jne .L462

.L460:
	cmpl %ebx,%esi		# Check if overflow
	je .Lno_conv
	lodsb			# al= next byte after sign

	# Remove pre zero to be able to handle a lot of pre-zero
.L462:
	cmpb $48,%al
	jne .L475		# Number doesn't start with 0
	movl %esi, %edi
	.p2align 4,,7
.L481:				# Skip pre zeros
	cmpl %ebx,%esi
	je .Lms_return_zero
	scasb
	je .L481
	movl %edi, %esi
	decl %esi		# Point to last non '0' digit
	leal 9(%esi),%ecx	# ecx = end-of-current-part
	xorl %edi,%edi		# Store first 9 digits in edi
	jmp .L482
	.p2align 4,,7

	# Check if first char is a valid number
.L475:
	addb $-48,%al
	cmpb $9,%al
	ja .Lno_conv
.L477:	
	movzbl %al,%edi		# edi = first digit
	leal 8(%esi),%ecx	# ecx = end-of-current-part

	# Handle first 8/9 digits and store them in edi
.L482:
	cmpl %ebx,%ecx
	jbe .L522
	movl %ebx,%ecx		# ecx = min(end-of-current-part, end-of-string)
	jmp .L522

	.p2align 4,,7
.L488:
	lodsb			# al= next byte
	addb $-48,%al
	cmpb $9,%al
	ja .Lend_i_dec_esi

	# Calculate edi= edi*10 + al
	leal (%edi,%edi,4),%edx
	movzbl %al,%eax
	leal (%eax,%edx,2),%edi
.L522:
	cmpl %ecx,%esi		# If more digits at this level
	jne .L488
	cmpl %ebx,%esi		# If end of string
	je .Lend_i

	movl %edi,-8(%ebp)	# Store first 9 digits
	movl %esi,-12(%ebp)	# store pos to first digit of second part

	# Calculate next 9 digits and store them in edi

	xorl %edi,%edi
	leal 9(%esi),%ecx	# ecx= end-of-current-part
	movl %ecx,-36(%ebp)	# Store max length
	cmpl %ebx,%ecx
	jbe .L498
	movl %ebx,%ecx		# ecx = min(end-of-current-part, end-of-string)

	.p2align 4,,7
.L498:
	lodsb			# al= next byte	
	addb $-48,%al
	cmpb $9,%al
	ja .Lend_i_and_j_decl_esi

	# Calculate edi= edi*10 + al
	leal (%edi,%edi,4),%edx
	movzbl %al,%eax
	leal (%eax,%edx,2),%edi

	cmpl %ecx,%esi		# If end of current part
	jne .L498
	cmpl %ebx,%esi		# If end of string
	jne .L500
	cmpl -36(%ebp),%esi	# Test if string is less than 18 digits
	jne .Lend_i_and_j
	jmp .Lend3		# 18 digit string

	# Handle the possible next to last digit and store in ecx
.L500:
	movb (%esi),%al
	addb $-48,%al
	cmpb $9,%al
	ja .Lend3

	incl %esi
	movzbl %al,%ecx
	cmpl %ebx,%esi		# If end of string
	je .Lend4

	movb (%esi),%al		# Read last digit
	addb $-48,%al
	cmpb $9,%al
	ja .Lend4

	# ecx= ecx*10 + al
	leal (%ecx,%ecx,4),%edx
	movzbl %al,%eax
	leal (%eax,%edx,2),%ecx

	movl 12(%ebp),%eax	# eax = endptr
	incl %esi
	movl %esi,(%eax)	# *endptr = end-of-string
	cmpl %ebx,%esi
	je .L505		# At end of string

	movb (%esi),%al		# check if extra digits
	addb $-48,%al
	cmpb $9,%al
	jbe .Loverflow

	# At this point we have:
	# -8(%ebp)	First 9 digits
	# edi		Next 9 digits
	# ecx		Last 2 digits
	# *endpos	end-of-string
	
.L505:	# Check that we are not going to get overflow for unsigned long long
	movl -8(%ebp),%eax	# First 9 digits
	cmpl -24(%ebp),%eax
	ja .Loverflow
	jne .L507
	cmpl -28(%ebp),%edi
	ja .Loverflow
	jne .L507
	cmpl -32(%ebp),%ecx
	ja .Loverflow

.L507:
	movl %edi,-4(%ebp)	# Save middle bytes
	movl %ecx,%esi		# esi = 2 last digits
	movl $1215752192,%ecx	# %ecx= lower_32_bits(100000000000)
	mull %ecx
	imull $23,-8(%ebp),%ecx
	movl $0,-36(%ebp)
	movl %eax,%ebx
	imull $1215752192,-36(%ebp),%eax
	movl %edx,%edi
	addl %ecx,%edi
	addl %eax,%edi		# Temp in edi:ebx

	movl $100,%eax		# j= j*100
	mull -4(%ebp)
	addl %ebx,%eax		# edx:eax+= edi:ebx
	adcl %edi,%edx
	addl %esi,%eax
	adcl $0,%edx
	jmp .Lms_return

.Loverflow:
	# When we come here, *endptr is already updated

	movl 16(%ebp),%edx	# edx= error
	movl $34,(%edx)		# *error = 34
	movl $-1,%eax
	movl %eax,%edx
	cmpl $0,-20(%ebp)	# If negative
	je .Lms_return
	xor %eax,%eax		# edx:eax = LONGLONG_LMIN
	movl $-2147483648,%edx
	jmp .Lms_return

	# Return value that is in %edi as long long
	.p2align 4,,7
.Lend_i_dec_esi:
	decl %esi		# Fix so that it points at last digit
.Lend_i:
	xorl %edx,%edx
	movl %edi,%eax
	cmpl $0,-20(%ebp)
	je .Lreturn_save_endptr	# Positive number
	negl %eax
	cltd			# Negetive result in edx:eax
	jmp .Lreturn_save_endptr

	# Return value (%ebp-8) * lfactor[(uint) (edx-start)] + edi
	.p2align 4,,7
.Lend_i_and_j_decl_esi:
	decl %esi		# Fix so that it points at last digit
.Lend_i_and_j:
	movl %esi,%ecx
	subl -12(%ebp),%ecx	# ecx= number of digits in second part
	movl lfactor(,%ecx,4),%eax
	jmp .L523

	# Return -8(%ebp) * $1000000000 + edi
	.p2align 4,,7
.Lend3:
	movl $1000000000,%eax
.L523:
	mull -8(%ebp)
	addl %edi,%eax
	adcl $0,%edx
	cmpl $0,-20(%ebp)	# if negative
	je .Lreturn_save_endptr
	negl %eax		# Neg edx:%eax
	adcl $0,%edx
	negl %edx
	jmp .Lreturn_save_endptr

	# Return -8(%ebp) * $10000000000 + edi*10 + ecx
	.p2align 4,,7
.Lend4:
	movl %ecx,-16(%ebp)	# store lowest digits
	movl 12(%ebp),%ebx
	movl %esi,(%ebx)	# *endpos = end-of-string
	movl -8(%ebp),%eax	# First 9 digits
	movl $1410065408,%ecx	# ecx= lower_32_bits(10000000000)
	mull %ecx
	movl $0,-36(%ebp)
	movl %eax,%ebx		# Store lowest 32 byte from multiplication
	imull $1410065408,-36(%ebp),%eax
	movl -8(%ebp),%ecx	# First 9 digits
	movl %edx,%esi
	addl %ecx,%ecx
	addl %ecx,%esi
	addl %eax,%esi		# %esi:%ebx now has -8(%ebp) * $10000000000

	movl $10,%eax		# Calc edi*10
	mull %edi
	addl %ebx,%eax		# And add to result
	adcl %esi,%edx
	addl -16(%ebp),%eax	# Add lowest digit
	adcl $0,%edx
	cmpl $0,-20(%ebp)	# if negative
	je .Lms_return

	cmpl $-2147483648,%edx	# Test if too big signed integer
	ja .Loverflow
	jne .L516
	testl %eax,%eax
	ja .Loverflow

.L516:	
	negl %eax
	adcl $0,%edx
	negl %edx
	jmp .Lms_return

	.p2align 4,,7
.Lno_conv:			# Not a legal number
	movl 16(%ebp),%eax
	movl $33,(%eax)		# error= edom

.Lms_return_zero:
	xorl %eax,%eax		# Return zero
	xorl %edx,%edx

	.p2align 4,,7
.Lreturn_save_endptr:
	movl 12(%ebp),%ecx	# endptr= end-of-string
	movl %esi,(%ecx)	# *endptr= end-of-string

.Lms_return:
	popl %ebx
	popl %edi
	popl %esi
	movl %ebp,%esp
	popl %ebp
	ret

my_strtoll10_end:
	.size	my_strtoll10,.my_strtoll10_end-my_strtoll10
        .comm   res,240,32
        .comm   end_ptr,120,32
        .comm   error,120,32
	.ident	"Monty"