mariadb/strings/my_strtoll10-x86.s
unknown 38b4ccf5d3 Fix for BUG #11642: [Patch]es x86 Assembler and text relocations
Changed assembler functions to not access global variables or variables in text segement
Added wrapper function in C to longlong2str() to pass _dig_vec_upper as an argument


mysql-test/r/bigint.result:
  More tests for parsing of bigint's
  More tests for different values to conv()
mysql-test/t/bigint.test:
  More tests for parsing of bigint's
  More tests for different values to conv()
strings/Makefile.am:
  Added longlong2str_asm.c
strings/longlong2str-x86.s:
  Changed functions to not access variables in text segment
  Fixed this by adding global variable '_dig_vec_upper' as an argument to longlong2str_with_dig_vector()
strings/my_strtoll10-x86.s:
  Removd array lfactor by calculating the value in code
  (this is to to make the code position independent)
strings/longlong2str_asm.c:
  New BitKeeper file ``strings/longlong2str_asm.c''
2005-08-08 13:18:18 +03:00

418 lines
9.3 KiB
ArmAsm

# 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.
# For documentation, check my_strtoll.c
.file "my_strtoll10-x86.s"
.version "01.02"
.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
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
movb (%esi), %al # al= next byte
incl %esi
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:
movb (%esi), %al # al= next byte
incl %esi
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
movb (%esi), %al # al= next byte after sign
incl %esi
# 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
decl %esi
.p2align 4,,7
# Skip pre zeros
.L481:
incl %esi # Skip processed byte
cmpl %ebx,%esi
je .Lms_return_zero
cmpb (%esi),%al # Test if next byte is also zero
je .L481
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:
movb (%esi), %al # al= next byte
incl %esi
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:
movb (%esi), %al # al= next byte
incl %esi
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
.L499:
movl $1000000000,%eax
jmp .Lgot_factor # 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 .L499 # 18 digit string
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 # Neg 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
# Calculate %eax= 10 ** %cl, where %cl <= 8
# With an array one could do this with:
# movl 10_factor_table(,%ecx,4),%eax
# We calculate the table here to avoid problems in
# position independent code (gcc -pic)
cmpb $3,%cl
ja .L4_to_8
movl $1000, %eax
je .Lgot_factor # %cl=3, eax= 1000
movl $10, %eax
cmpb $1,%cl # %cl is here 0 - 2
je .Lgot_factor # %cl=1, eax= 10
movl $100, %eax
ja .Lgot_factor # %cl=2, eax=100
movl $1, %eax
jmp .Lgot_factor # %cl=0, eax=1
.L4_to_8: # %cl is here 4-8
cmpb $5,%cl
movl $100000, %eax
je .Lgot_factor # %cl=5, eax=100000
movl $10000, %eax
jbe .Lgot_factor # %cl=4, eax=10000
movl $10000000, %eax
cmpb $7,%cl
je .Lgot_factor # %cl=7, eax=10000000
movl $100000000, %eax
ja .Lgot_factor # %cl=8, eax=100000000
movl $1000000, %eax # %cl=6, eax=1000000
# Return -8(%ebp) * %eax + edi
.p2align 4,,7
.Lgot_factor:
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"