...
Run Format

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/default/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	// trampoline for _sfloat2. passes LR as arg0 and
    32	// saves registers R0-R13 and CPSR on the stack. R0-R12 and CPSR flags can
    33	// be changed by _sfloat2.
    34	TEXT runtime·_sfloat(SB), NOSPLIT, $68-0 // 4 arg + 14*4 saved regs + cpsr + return value
    35		MOVW	R14, 4(R13)
    36		MOVW	R0, 8(R13)
    37		MOVW	$12(R13), R0
    38		MOVM.IA.W	[R1-R12], (R0)
    39		MOVW	$72(R13), R1 // correct for frame size
    40		MOVW	R1, 60(R13)
    41		WORD	$0xe10f1000 // mrs r1, cpsr
    42		MOVW	R1, 64(R13)
    43		// Disable preemption of this goroutine during _sfloat2 by
    44		// m->locks++ and m->locks-- around the call.
    45		// Rescheduling this goroutine may cause the loss of the
    46		// contents of the software floating point registers in 
    47		// m->freghi, m->freglo, m->fflag, if the goroutine is moved
    48		// to a different m or another goroutine runs on this m.
    49		// Rescheduling at ordinary function calls is okay because
    50		// all registers are caller save, but _sfloat2 and the things
    51		// that it runs are simulating the execution of individual
    52		// program instructions, and those instructions do not expect
    53		// the floating point registers to be lost.
    54		// An alternative would be to move the software floating point
    55		// registers into G, but they do not need to be kept at the 
    56		// usual places a goroutine reschedules (at function calls),
    57		// so it would be a waste of 132 bytes per G.
    58		MOVW	g_m(g), R8
    59		MOVW	m_locks(R8), R1
    60		ADD	$1, R1
    61		MOVW	R1, m_locks(R8)
    62		MOVW	$1, R1
    63		MOVW	R1, m_softfloat(R8)
    64		BL	runtime·_sfloat2(SB)
    65		MOVW	68(R13), R0
    66		MOVW	g_m(g), R8
    67		MOVW	m_locks(R8), R1
    68		SUB	$1, R1
    69		MOVW	R1, m_locks(R8)
    70		MOVW	$0, R1
    71		MOVW	R1, m_softfloat(R8)
    72		MOVW	R0, 0(R13)
    73		MOVW	64(R13), R1
    74		WORD	$0xe128f001	// msr cpsr_f, r1
    75		MOVW	$12(R13), R0
    76		// Restore R1-R12, R0.
    77		MOVM.IA.W	(R0), [R1-R12]
    78		MOVW	8(R13), R0
    79		RET
    80	
    81	// trampoline for _sfloat2 panic.
    82	// _sfloat2 instructs _sfloat to return here.
    83	// We need to push a fake saved LR onto the stack,
    84	// load the signal fault address into LR, and jump
    85	// to the real sigpanic.
    86	// This simulates what sighandler does for a memory fault.
    87	TEXT runtime·_sfloatpanic(SB),NOSPLIT,$-4
    88		MOVW	$0, R0
    89		MOVW.W	R0, -4(R13)
    90		MOVW	g_sigpc(g), LR
    91		B	runtime·sigpanic(SB)
    92	
    93	// func runtime·udiv(n, d uint32) (q, r uint32)
    94	// compiler knowns the register usage of this function
    95	// Reference: 
    96	// Sloss, Andrew et. al; ARM System Developer's Guide: Designing and Optimizing System Software
    97	// Morgan Kaufmann; 1 edition (April 8, 2004), ISBN 978-1558608740
    98	#define Rq	R0 // input d, output q
    99	#define Rr	R1 // input n, output r
   100	#define Rs	R2 // three temporary variables
   101	#define RM	R3
   102	#define Ra	R11
   103	
   104	// Be careful: Ra == R11 will be used by the linker for synthesized instructions.
   105	TEXT runtime·udiv(SB),NOSPLIT,$-4
   106		MOVBU	runtime·hardDiv(SB), Ra
   107		CMP	$0, Ra
   108		BNE	udiv_hardware
   109	
   110		CLZ 	Rq, Rs // find normalizing shift
   111		MOVW.S	Rq<<Rs, Ra
   112		MOVW	$fast_udiv_tab<>-64(SB), RM
   113		ADD.NE	Ra>>25, RM, Ra // index by most significant 7 bits of divisor
   114		MOVBU.NE	(Ra), Ra
   115	
   116		SUB.S	$7, Rs
   117		RSB 	$0, Rq, RM // M = -q
   118		MOVW.PL	Ra<<Rs, Rq
   119	
   120		// 1st Newton iteration
   121		MUL.PL	RM, Rq, Ra // a = -q*d
   122		BMI 	udiv_by_large_d
   123		MULAWT	Ra, Rq, Rq, Rq // q approx q-(q*q*d>>32)
   124		TEQ 	RM->1, RM // check for d=0 or d=1
   125	
   126		// 2nd Newton iteration
   127		MUL.NE	RM, Rq, Ra
   128		MOVW.NE	$0, Rs
   129		MULAL.NE Rq, Ra, (Rq,Rs)
   130		BEQ 	udiv_by_0_or_1
   131	
   132		// q now accurate enough for a remainder r, 0<=r<3*d
   133		MULLU	Rq, Rr, (Rq,Rs) // q = (r * q) >> 32
   134		ADD 	RM, Rr, Rr // r = n - d
   135		MULA	RM, Rq, Rr, Rr // r = n - (q+1)*d
   136	
   137		// since 0 <= n-q*d < 3*d; thus -d <= r < 2*d
   138		CMN 	RM, Rr // t = r-d
   139		SUB.CS	RM, Rr, Rr // if (t<-d || t>=0) r=r+d
   140		ADD.CC	$1, Rq
   141		ADD.PL	RM<<1, Rr
   142		ADD.PL	$2, Rq
   143		RET
   144	
   145	// use hardware divider
   146	udiv_hardware:
   147		DIVUHW	Rq, Rr, Rs
   148		MUL	Rs, Rq, RM
   149		RSB	Rr, RM, Rr
   150		MOVW	Rs, Rq
   151		RET
   152	
   153	udiv_by_large_d:
   154		// at this point we know d>=2^(31-6)=2^25
   155		SUB 	$4, Ra, Ra
   156		RSB 	$0, Rs, Rs
   157		MOVW	Ra>>Rs, Rq
   158		MULLU	Rq, Rr, (Rq,Rs)
   159		MULA	RM, Rq, Rr, Rr
   160	
   161		// q now accurate enough for a remainder r, 0<=r<4*d
   162		CMN 	Rr>>1, RM // if(r/2 >= d)
   163		ADD.CS	RM<<1, Rr
   164		ADD.CS	$2, Rq
   165		CMN 	Rr, RM
   166		ADD.CS	RM, Rr
   167		ADD.CS	$1, Rq
   168		RET
   169	
   170	udiv_by_0_or_1:
   171		// carry set if d==1, carry clear if d==0
   172		BCC udiv_by_0
   173		MOVW	Rr, Rq
   174		MOVW	$0, Rr
   175		RET
   176	
   177	udiv_by_0:
   178		MOVW	$runtime·panicdivide(SB), R11
   179		B	(R11)
   180	
   181	// var tab [64]byte
   182	// tab[0] = 255; for i := 1; i <= 63; i++ { tab[i] = (1<<14)/(64+i) }
   183	// laid out here as little-endian uint32s
   184	DATA fast_udiv_tab<>+0x00(SB)/4, $0xf4f8fcff
   185	DATA fast_udiv_tab<>+0x04(SB)/4, $0xe6eaedf0
   186	DATA fast_udiv_tab<>+0x08(SB)/4, $0xdadde0e3
   187	DATA fast_udiv_tab<>+0x0c(SB)/4, $0xcfd2d4d7
   188	DATA fast_udiv_tab<>+0x10(SB)/4, $0xc5c7cacc
   189	DATA fast_udiv_tab<>+0x14(SB)/4, $0xbcbec0c3
   190	DATA fast_udiv_tab<>+0x18(SB)/4, $0xb4b6b8ba
   191	DATA fast_udiv_tab<>+0x1c(SB)/4, $0xacaeb0b2
   192	DATA fast_udiv_tab<>+0x20(SB)/4, $0xa5a7a8aa
   193	DATA fast_udiv_tab<>+0x24(SB)/4, $0x9fa0a2a3
   194	DATA fast_udiv_tab<>+0x28(SB)/4, $0x999a9c9d
   195	DATA fast_udiv_tab<>+0x2c(SB)/4, $0x93949697
   196	DATA fast_udiv_tab<>+0x30(SB)/4, $0x8e8f9092
   197	DATA fast_udiv_tab<>+0x34(SB)/4, $0x898a8c8d
   198	DATA fast_udiv_tab<>+0x38(SB)/4, $0x85868788
   199	DATA fast_udiv_tab<>+0x3c(SB)/4, $0x81828384
   200	GLOBL fast_udiv_tab<>(SB), RODATA, $64
   201	
   202	// The linker will pass numerator in R8
   203	#define Rn R8
   204	// The linker expects the result in RTMP
   205	#define RTMP R11
   206	
   207	TEXT runtime·_divu(SB), NOSPLIT, $16-0
   208		// It's not strictly true that there are no local pointers.
   209		// It could be that the saved registers Rq, Rr, Rs, and Rm
   210		// contain pointers. However, the only way this can matter
   211		// is if the stack grows (which it can't, udiv is nosplit)
   212		// or if a fault happens and more frames are added to
   213		// the stack due to deferred functions.
   214		// In the latter case, the stack can grow arbitrarily,
   215		// and garbage collection can happen, and those
   216		// operations care about pointers, but in that case
   217		// the calling frame is dead, and so are the saved
   218		// registers. So we can claim there are no pointers here.
   219		NO_LOCAL_POINTERS
   220		MOVW	Rq, 4(R13)
   221		MOVW	Rr, 8(R13)
   222		MOVW	Rs, 12(R13)
   223		MOVW	RM, 16(R13)
   224	
   225		MOVW	Rn, Rr			/* numerator */
   226		MOVW	g_m(g), Rq
   227		MOVW	m_divmod(Rq), Rq	/* denominator */
   228		BL  	runtime·udiv(SB)
   229		MOVW	Rq, RTMP
   230		MOVW	4(R13), Rq
   231		MOVW	8(R13), Rr
   232		MOVW	12(R13), Rs
   233		MOVW	16(R13), RM
   234		RET
   235	
   236	TEXT runtime·_modu(SB), NOSPLIT, $16-0
   237		NO_LOCAL_POINTERS
   238		MOVW	Rq, 4(R13)
   239		MOVW	Rr, 8(R13)
   240		MOVW	Rs, 12(R13)
   241		MOVW	RM, 16(R13)
   242	
   243		MOVW	Rn, Rr			/* numerator */
   244		MOVW	g_m(g), Rq
   245		MOVW	m_divmod(Rq), Rq	/* denominator */
   246		BL  	runtime·udiv(SB)
   247		MOVW	Rr, RTMP
   248		MOVW	4(R13), Rq
   249		MOVW	8(R13), Rr
   250		MOVW	12(R13), Rs
   251		MOVW	16(R13), RM
   252		RET
   253	
   254	TEXT runtime·_div(SB),NOSPLIT,$16-0
   255		NO_LOCAL_POINTERS
   256		MOVW	Rq, 4(R13)
   257		MOVW	Rr, 8(R13)
   258		MOVW	Rs, 12(R13)
   259		MOVW	RM, 16(R13)
   260		MOVW	Rn, Rr			/* numerator */
   261		MOVW	g_m(g), Rq
   262		MOVW	m_divmod(Rq), Rq	/* denominator */
   263		CMP 	$0, Rr
   264		BGE 	d1
   265		RSB 	$0, Rr, Rr
   266		CMP 	$0, Rq
   267		BGE 	d2
   268		RSB 	$0, Rq, Rq
   269	d0:
   270		BL  	runtime·udiv(SB)  	/* none/both neg */
   271		MOVW	Rq, RTMP
   272		B	out1
   273	d1:
   274		CMP 	$0, Rq
   275		BGE 	d0
   276		RSB 	$0, Rq, Rq
   277	d2:
   278		BL  	runtime·udiv(SB)  	/* one neg */
   279		RSB	$0, Rq, RTMP
   280	out1:
   281		MOVW	4(R13), Rq
   282		MOVW	8(R13), Rr
   283		MOVW	12(R13), Rs
   284		MOVW	16(R13), RM
   285		RET
   286	
   287	TEXT runtime·_mod(SB),NOSPLIT,$16-0
   288		NO_LOCAL_POINTERS
   289		MOVW	Rq, 4(R13)
   290		MOVW	Rr, 8(R13)
   291		MOVW	Rs, 12(R13)
   292		MOVW	RM, 16(R13)
   293		MOVW	Rn, Rr			/* numerator */
   294		MOVW	g_m(g), Rq
   295		MOVW	m_divmod(Rq), Rq	/* denominator */
   296		CMP 	$0, Rq
   297		RSB.LT	$0, Rq, Rq
   298		CMP 	$0, Rr
   299		BGE 	m1
   300		RSB 	$0, Rr, Rr
   301		BL  	runtime·udiv(SB)  	/* neg numerator */
   302		RSB 	$0, Rr, RTMP
   303		B   	out
   304	m1:
   305		BL  	runtime·udiv(SB)  	/* pos numerator */
   306		MOVW	Rr, RTMP
   307	out:
   308		MOVW	4(R13), Rq
   309		MOVW	8(R13), Rr
   310		MOVW	12(R13), Rs
   311		MOVW	16(R13), RM
   312		RET
   313	
   314	// _mul64by32 and _div64by32 not implemented on arm
   315	TEXT runtime·_mul64by32(SB), NOSPLIT, $0
   316		MOVW	$0, R0
   317		MOVW	(R0), R1 // crash
   318	
   319	TEXT runtime·_div64by32(SB), NOSPLIT, $0
   320		MOVW	$0, R0
   321		MOVW	(R0), R1 // crash

View as plain text