...

Text file src/runtime/vlop_arm.s

Documentation: runtime

     1// Inferno's libkern/vlop-arm.s
     2// https://bitbucket.org/inferno-os/inferno-os/src/master/libkern/vlop-arm.s
     3//
     4//         Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
     5//         Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).  All rights reserved.
     6//         Portions Copyright 2009 The Go Authors. All rights reserved.
     7//
     8// Permission is hereby granted, free of charge, to any person obtaining a copy
     9// of this software and associated documentation files (the "Software"), to deal
    10// in the Software without restriction, including without limitation the rights
    11// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    12// copies of the Software, and to permit persons to whom the Software is
    13// furnished to do so, subject to the following conditions:
    14//
    15// The above copyright notice and this permission notice shall be included in
    16// all copies or substantial portions of the Software.
    17//
    18// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    19// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    20// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
    21// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    22// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    23// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    24// THE SOFTWARE.
    25
    26#include "go_asm.h"
    27#include "go_tls.h"
    28#include "funcdata.h"
    29#include "textflag.h"
    30
    31// func runtime·udiv(n, d uint32) (q, r uint32)
    32// compiler knowns the register usage of this function
    33// Reference:
    34// Sloss, Andrew et. al; ARM System Developer's Guide: Designing and Optimizing System Software
    35// Morgan Kaufmann; 1 edition (April 8, 2004), ISBN 978-1558608740
    36#define Rq	R0 // input d, output q
    37#define Rr	R1 // input n, output r
    38#define Rs	R2 // three temporary variables
    39#define RM	R3
    40#define Ra	R11
    41
    42// Be careful: Ra == R11 will be used by the linker for synthesized instructions.
    43// Note: this function does not have a frame.
    44TEXT runtime·udiv(SB),NOSPLIT|NOFRAME,$0
    45	MOVBU	internal∕cpu·ARM+const_offsetARMHasIDIVA(SB), Ra
    46	CMP	$0, Ra
    47	BNE	udiv_hardware
    48
    49	CLZ 	Rq, Rs // find normalizing shift
    50	MOVW.S	Rq<<Rs, Ra
    51	MOVW	$fast_udiv_tab<>-64(SB), RM
    52	ADD.NE	Ra>>25, RM, Ra // index by most significant 7 bits of divisor
    53	MOVBU.NE	(Ra), Ra
    54
    55	SUB.S	$7, Rs
    56	RSB 	$0, Rq, RM // M = -q
    57	MOVW.PL	Ra<<Rs, Rq
    58
    59	// 1st Newton iteration
    60	MUL.PL	RM, Rq, Ra // a = -q*d
    61	BMI 	udiv_by_large_d
    62	MULAWT	Ra, Rq, Rq, Rq // q approx q-(q*q*d>>32)
    63	TEQ 	RM->1, RM // check for d=0 or d=1
    64
    65	// 2nd Newton iteration
    66	MUL.NE	RM, Rq, Ra
    67	MOVW.NE	$0, Rs
    68	MULAL.NE Rq, Ra, (Rq,Rs)
    69	BEQ 	udiv_by_0_or_1
    70
    71	// q now accurate enough for a remainder r, 0<=r<3*d
    72	MULLU	Rq, Rr, (Rq,Rs) // q = (r * q) >> 32
    73	ADD 	RM, Rr, Rr // r = n - d
    74	MULA	RM, Rq, Rr, Rr // r = n - (q+1)*d
    75
    76	// since 0 <= n-q*d < 3*d; thus -d <= r < 2*d
    77	CMN 	RM, Rr // t = r-d
    78	SUB.CS	RM, Rr, Rr // if (t<-d || t>=0) r=r+d
    79	ADD.CC	$1, Rq
    80	ADD.PL	RM<<1, Rr
    81	ADD.PL	$2, Rq
    82	RET
    83
    84// use hardware divider
    85udiv_hardware:
    86	DIVUHW	Rq, Rr, Rs
    87	MUL	Rs, Rq, RM
    88	RSB	Rr, RM, Rr
    89	MOVW	Rs, Rq
    90	RET
    91
    92udiv_by_large_d:
    93	// at this point we know d>=2^(31-6)=2^25
    94	SUB 	$4, Ra, Ra
    95	RSB 	$0, Rs, Rs
    96	MOVW	Ra>>Rs, Rq
    97	MULLU	Rq, Rr, (Rq,Rs)
    98	MULA	RM, Rq, Rr, Rr
    99
   100	// q now accurate enough for a remainder r, 0<=r<4*d
   101	CMN 	Rr>>1, RM // if(r/2 >= d)
   102	ADD.CS	RM<<1, Rr
   103	ADD.CS	$2, Rq
   104	CMN 	Rr, RM
   105	ADD.CS	RM, Rr
   106	ADD.CS	$1, Rq
   107	RET
   108
   109udiv_by_0_or_1:
   110	// carry set if d==1, carry clear if d==0
   111	BCC udiv_by_0
   112	MOVW	Rr, Rq
   113	MOVW	$0, Rr
   114	RET
   115
   116udiv_by_0:
   117	MOVW	$runtime·panicdivide(SB), R11
   118	B	(R11)
   119
   120// var tab [64]byte
   121// tab[0] = 255; for i := 1; i <= 63; i++ { tab[i] = (1<<14)/(64+i) }
   122// laid out here as little-endian uint32s
   123DATA fast_udiv_tab<>+0x00(SB)/4, $0xf4f8fcff
   124DATA fast_udiv_tab<>+0x04(SB)/4, $0xe6eaedf0
   125DATA fast_udiv_tab<>+0x08(SB)/4, $0xdadde0e3
   126DATA fast_udiv_tab<>+0x0c(SB)/4, $0xcfd2d4d7
   127DATA fast_udiv_tab<>+0x10(SB)/4, $0xc5c7cacc
   128DATA fast_udiv_tab<>+0x14(SB)/4, $0xbcbec0c3
   129DATA fast_udiv_tab<>+0x18(SB)/4, $0xb4b6b8ba
   130DATA fast_udiv_tab<>+0x1c(SB)/4, $0xacaeb0b2
   131DATA fast_udiv_tab<>+0x20(SB)/4, $0xa5a7a8aa
   132DATA fast_udiv_tab<>+0x24(SB)/4, $0x9fa0a2a3
   133DATA fast_udiv_tab<>+0x28(SB)/4, $0x999a9c9d
   134DATA fast_udiv_tab<>+0x2c(SB)/4, $0x93949697
   135DATA fast_udiv_tab<>+0x30(SB)/4, $0x8e8f9092
   136DATA fast_udiv_tab<>+0x34(SB)/4, $0x898a8c8d
   137DATA fast_udiv_tab<>+0x38(SB)/4, $0x85868788
   138DATA fast_udiv_tab<>+0x3c(SB)/4, $0x81828384
   139GLOBL fast_udiv_tab<>(SB), RODATA, $64
   140
   141// The linker will pass numerator in R8
   142#define Rn R8
   143// The linker expects the result in RTMP
   144#define RTMP R11
   145
   146TEXT runtime·_divu(SB), NOSPLIT, $16-0
   147	// It's not strictly true that there are no local pointers.
   148	// It could be that the saved registers Rq, Rr, Rs, and Rm
   149	// contain pointers. However, the only way this can matter
   150	// is if the stack grows (which it can't, udiv is nosplit)
   151	// or if a fault happens and more frames are added to
   152	// the stack due to deferred functions.
   153	// In the latter case, the stack can grow arbitrarily,
   154	// and garbage collection can happen, and those
   155	// operations care about pointers, but in that case
   156	// the calling frame is dead, and so are the saved
   157	// registers. So we can claim there are no pointers here.
   158	NO_LOCAL_POINTERS
   159	MOVW	Rq, 4(R13)
   160	MOVW	Rr, 8(R13)
   161	MOVW	Rs, 12(R13)
   162	MOVW	RM, 16(R13)
   163
   164	MOVW	Rn, Rr			/* numerator */
   165	MOVW	g_m(g), Rq
   166	MOVW	m_divmod(Rq), Rq	/* denominator */
   167	BL  	runtime·udiv(SB)
   168	MOVW	Rq, RTMP
   169	MOVW	4(R13), Rq
   170	MOVW	8(R13), Rr
   171	MOVW	12(R13), Rs
   172	MOVW	16(R13), RM
   173	RET
   174
   175TEXT runtime·_modu(SB), NOSPLIT, $16-0
   176	NO_LOCAL_POINTERS
   177	MOVW	Rq, 4(R13)
   178	MOVW	Rr, 8(R13)
   179	MOVW	Rs, 12(R13)
   180	MOVW	RM, 16(R13)
   181
   182	MOVW	Rn, Rr			/* numerator */
   183	MOVW	g_m(g), Rq
   184	MOVW	m_divmod(Rq), Rq	/* denominator */
   185	BL  	runtime·udiv(SB)
   186	MOVW	Rr, RTMP
   187	MOVW	4(R13), Rq
   188	MOVW	8(R13), Rr
   189	MOVW	12(R13), Rs
   190	MOVW	16(R13), RM
   191	RET
   192
   193TEXT runtime·_div(SB),NOSPLIT,$16-0
   194	NO_LOCAL_POINTERS
   195	MOVW	Rq, 4(R13)
   196	MOVW	Rr, 8(R13)
   197	MOVW	Rs, 12(R13)
   198	MOVW	RM, 16(R13)
   199	MOVW	Rn, Rr			/* numerator */
   200	MOVW	g_m(g), Rq
   201	MOVW	m_divmod(Rq), Rq	/* denominator */
   202	CMP 	$0, Rr
   203	BGE 	d1
   204	RSB 	$0, Rr, Rr
   205	CMP 	$0, Rq
   206	BGE 	d2
   207	RSB 	$0, Rq, Rq
   208d0:
   209	BL  	runtime·udiv(SB)  	/* none/both neg */
   210	MOVW	Rq, RTMP
   211	B	out1
   212d1:
   213	CMP 	$0, Rq
   214	BGE 	d0
   215	RSB 	$0, Rq, Rq
   216d2:
   217	BL  	runtime·udiv(SB)  	/* one neg */
   218	RSB	$0, Rq, RTMP
   219out1:
   220	MOVW	4(R13), Rq
   221	MOVW	8(R13), Rr
   222	MOVW	12(R13), Rs
   223	MOVW	16(R13), RM
   224	RET
   225
   226TEXT runtime·_mod(SB),NOSPLIT,$16-0
   227	NO_LOCAL_POINTERS
   228	MOVW	Rq, 4(R13)
   229	MOVW	Rr, 8(R13)
   230	MOVW	Rs, 12(R13)
   231	MOVW	RM, 16(R13)
   232	MOVW	Rn, Rr			/* numerator */
   233	MOVW	g_m(g), Rq
   234	MOVW	m_divmod(Rq), Rq	/* denominator */
   235	CMP 	$0, Rq
   236	RSB.LT	$0, Rq, Rq
   237	CMP 	$0, Rr
   238	BGE 	m1
   239	RSB 	$0, Rr, Rr
   240	BL  	runtime·udiv(SB)  	/* neg numerator */
   241	RSB 	$0, Rr, RTMP
   242	B   	out
   243m1:
   244	BL  	runtime·udiv(SB)  	/* pos numerator */
   245	MOVW	Rr, RTMP
   246out:
   247	MOVW	4(R13), Rq
   248	MOVW	8(R13), Rr
   249	MOVW	12(R13), Rs
   250	MOVW	16(R13), RM
   251	RET
   252
   253// _mul64by32 and _div64by32 not implemented on arm
   254TEXT runtime·_mul64by32(SB), NOSPLIT, $0
   255	MOVW	$0, R0
   256	MOVW	(R0), R1 // crash
   257
   258TEXT runtime·_div64by32(SB), NOSPLIT, $0
   259	MOVW	$0, R0
   260	MOVW	(R0), R1 // crash

View as plain text