summaryrefslogtreecommitdiff
path: root/sys/src/libc/alpha/divq.s
blob: 98a58e4a8135c27e5dbd927f840f5a400f36d1b7 (plain)
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
/*
 *	uvlong
 *	_udiv(uvlong num, uvlong den)
 *	{
 *		int i;
 *		uvlong quo;
 *
 *		if(den == 0)
 *			*(ulong*)-1 = 0;
 *		quo = num;
 *		if(quo > 1<<(64-1))
 *			quo = 1<<(64-1);
 *		for(i=0; den<quo; i++)
 *			den <<= 1;
 *		quo = 0;
 *		for(; i>=0; i--) {
 *			quo <<= 1;
 *			if(num >= den) {
 *				num -= den;
 *				quo |= 1;
 *			}
 *			den >>= 1;
 *		}
 *		return quo::num;
 *	}
 */

#define	NOPROF	1

/*
 * calling sequence:
 *	num: 8(R30)
 *	den: 16(R30)
 * returns
 *	quo: 8(R30)
 *	rem: 16(R30)
 */
TEXT	_udivmodq(SB), NOPROF, $-8

	MOVQ	$1, R11
	SLLQ	$63, R11
	MOVQ	8(R30), R23	/* numerator */
	MOVQ	16(R30), R10	/* denominator */
	BNE	R10, udm20
	MOVQ	R31, -1(R31)	/* fault -- divide by zero; todo: use gentrap? */
udm20:
	MOVQ	R23, R12
	BGE	R12, udm34
	MOVQ	R11, R12
udm34:
	MOVQ	R31, R11
udm38:
	CMPUGE	R10, R12, R24
	BNE	R24, udm54
	SLLQ	$1, R10
	ADDQ	$1, R11
	JMP	udm38
udm54:
	MOVQ	R31, R12
udm58:
	BLT	R11, udm8c
	SLLQ	$1, R12
	CMPUGE	R23, R10, R24
	BEQ	R24, udm7c
	SUBQ	R10, R23
	OR	$1, R12
udm7c:
	SRLQ	$1, R10
	SUBQ	$1, R11
	JMP	udm58
udm8c:
	MOVQ	R12, 8(R30)	/* quotient */
	MOVQ	R23, 16(R30)	/* remainder */
	RET

/*
 * save working registers
 * and bring in num/den parameters
 */
TEXT	_unsargq(SB), NOPROF, $-8
	MOVQ	R10, 24(R30)
	MOVQ	R11, 32(R30)
	MOVQ	R12, 40(R30)
	MOVQ	R23, 48(R30)
	MOVQ	R24, 56(R30)

	MOVQ	R27, 8(R30)
	MOVQ	72(R30), R27
	MOVQ	R27, 16(R30)

MOVQ	(R30), R10	/* debug */
	RET

/*
 * save working registers
 * and bring in absolute value
 * of num/den parameters
 */
TEXT	_absargq(SB), NOPROF, $-8
	MOVQ	R10, 24(R30)
	MOVQ	R11, 32(R30)
	MOVQ	R12, 40(R30)
	MOVQ	R23, 48(R30)
	MOVQ	R24, 56(R30)

	MOVQ	R27, 64(R30)
	BGE	R27, ab1
	SUBQ	R27, R31, R27
ab1:
	MOVQ	R27, 8(R30)	/* numerator */

	MOVQ	72(R30), R27
	BGE	R27, ab2
	SUBQ	R27, R31, R27
ab2:
	MOVQ	R27, 16(R30)	/* denominator */
MOVQ	(R30), R10	/* debug */
	RET

/*
 * restore registers and
 * return to original caller
 * answer is in R27
 */
TEXT	_retargq(SB), NOPROF, $-8
	MOVQ	24(R30), R10
	MOVQ	32(R30), R11
	MOVQ	40(R30), R12
	MOVQ	48(R30), R23
	MOVQ	56(R30), R24
	MOVL	0(R30), R26

	ADDQ	$64, R30
	RET			/* back to main sequence */

TEXT	_divq(SB), NOPROF, $-8
	SUBQ	$64, R30	/* 5 reg save, 2 parameters, link */
	MOVQ	R26, 0(R30)

	JSR	_absargq(SB)
	JSR	_udivmodq(SB)
	MOVQ	8(R30), R27

	MOVQ	64(R30), R10	/* clean up the sign */
	MOVQ	72(R30), R11
	XOR	R11, R10
	BGE	R10, div1
	SUBQ	R27, R31, R27
div1:

	JSR	_retargq(SB)
	RET			/* not executed */

TEXT	_divqu(SB), NOPROF, $-8
	SUBQ	$64, R30	/* 5 reg save, 2 parameters, link */
	MOVQ	R26, 0(R30)

	JSR	_unsargq(SB)
	JSR	_udivmodq(SB)
	MOVQ	8(R30), R27

	JSR	_retargq(SB)
	RET			/* not executed */

TEXT	_modq(SB), NOPROF, $-8
	SUBQ	$64, R30	/* 5 reg save, 2 parameters, link */
	MOVQ	R26, 0(R30)

	JSR	_absargq(SB)
	JSR	_udivmodq(SB)
	MOVQ	16(R30), R27

	MOVQ	64(R30), R10	/* clean up the sign */
	BGE	R10, div2
	SUBQ	R27, R31, R27
div2:

	JSR	_retargq(SB)
	RET			/* not executed */

TEXT	_modqu(SB), NOPROF, $-8
	SUBQ	$64, R30	/* 5 reg save, 2 parameters, link */
	MOVQ	R26, 0(R30)

	JSR	_unsargq(SB)
	JSR	_udivmodq(SB)
	MOVQ	16(R30), R27

	JSR	_retargq(SB)
	RET			/* not executed */