1 // Copyright 2009 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 #include "gg.h"
6
7 /*
8 * attempt to generate 64-bit
9 * res = n
10 * return 1 on success, 0 if op not handled.
11 */
12 void
13 cgen64(Node *n, Node *res)
14 {
15 Node t1, t2, ax, dx, cx, ex, fx, *l, *r;
16 Node lo1, lo2, hi1, hi2;
17 Prog *p1, *p2;
18 uint64 v;
19 uint32 lv, hv;
20
21 if(res->op != OINDREG && res->op != ONAME) {
22 dump("n", n);
23 dump("res", res);
24 fatal("cgen64 %O of %O", n->op, res->op);
25 }
26 switch(n->op) {
27 default:
28 fatal("cgen64 %O", n->op);
29
30 case OMINUS:
31 cgen(n->left, res);
32 split64(res, &lo1, &hi1);
33 gins(ANEGL, N, &lo1);
34 gins(AADCL, ncon(0), &hi1);
35 gins(ANEGL, N, &hi1);
36 splitclean();
37 return;
38
39 case OCOM:
40 cgen(n->left, res);
41 split64(res, &lo1, &hi1);
42 gins(ANOTL, N, &lo1);
43 gins(ANOTL, N, &hi1);
44 splitclean();
45 return;
46
47 case OADD:
48 case OSUB:
49 case OMUL:
50 case OLSH:
51 case ORSH:
52 case OAND:
53 case OOR:
54 case OXOR:
55 // binary operators.
56 // common setup below.
57 break;
58 }
59
60 l = n->left;
61 r = n->right;
62 if(!l->addable) {
63 tempname(&t1, l->type);
64 cgen(l, &t1);
65 l = &t1;
66 }
67 if(r != N && !r->addable) {
68 tempname(&t2, r->type);
69 cgen(r, &t2);
70 r = &t2;
71 }
72
73 nodreg(&ax, types[TINT32], D_AX);
74 nodreg(&cx, types[TINT32], D_CX);
75 nodreg(&dx, types[TINT32], D_DX);
76
77 // Setup for binary operation.
78 split64(l, &lo1, &hi1);
79 if(is64(r->type))
80 split64(r, &lo2, &hi2);
81
82 // Do op. Leave result in DX:AX.
83 switch(n->op) {
84 case OADD:
85 // TODO: Constants
86 gins(AMOVL, &lo1, &ax);
87 gins(AMOVL, &hi1, &dx);
88 gins(AADDL, &lo2, &ax);
89 gins(AADCL, &hi2, &dx);
90 break;
91
92 case OSUB:
93 // TODO: Constants.
94 gins(AMOVL, &lo1, &ax);
95 gins(AMOVL, &hi1, &dx);
96 gins(ASUBL, &lo2, &ax);
97 gins(ASBBL, &hi2, &dx);
98 break;
99
100 case OMUL:
101 // let's call the next two EX and FX.
102 regalloc(&ex, types[TPTR32], N);
103 regalloc(&fx, types[TPTR32], N);
104
105 // load args into DX:AX and EX:CX.
106 gins(AMOVL, &lo1, &ax);
107 gins(AMOVL, &hi1, &dx);
108 gins(AMOVL, &lo2, &cx);
109 gins(AMOVL, &hi2, &ex);
110
111 // if DX and EX are zero, use 32 x 32 -> 64 unsigned multiply.
112 gins(AMOVL, &dx, &fx);
113 gins(AORL, &ex, &fx);
114 p1 = gbranch(AJNE, T);
115 gins(AMULL, &cx, N); // implicit &ax
116 p2 = gbranch(AJMP, T);
117 patch(p1, pc);
118
119 // full 64x64 -> 64, from 32x32 -> 64.
120 gins(AIMULL, &cx, &dx);
121 gins(AMOVL, &ax, &fx);
122 gins(AIMULL, &ex, &fx);
123 gins(AADDL, &dx, &fx);
124 gins(AMOVL, &cx, &dx);
125 gins(AMULL, &dx, N); // implicit &ax
126 gins(AADDL, &fx, &dx);
127 patch(p2, pc);
128
129 regfree(&ex);
130 regfree(&fx);
131 break;
132
133 case OLSH:
134 if(r->op == OLITERAL) {
135 v = mpgetfix(r->val.u.xval);
136 if(v >= 64) {
137 if(is64(r->type))
138 splitclean();
139 splitclean();
140 split64(res, &lo2, &hi2);
141 gins(AMOVL, ncon(0), &lo2);
142 gins(AMOVL, ncon(0), &hi2);
143 splitclean();
144 goto out;
145 }
146 if(v >= 32) {
147 if(is64(r->type))
148 splitclean();
149 split64(res, &lo2, &hi2);
150 gmove(&lo1, &hi2);
151 if(v > 32) {
152 gins(ASHLL, ncon(v - 32), &hi2);
153 }
154 gins(AMOVL, ncon(0), &lo2);
155 splitclean();
156 splitclean();
157 goto out;
158 }
159
160 // general shift
161 gins(AMOVL, &lo1, &ax);
162 gins(AMOVL, &hi1, &dx);
163 p1 = gins(ASHLL, ncon(v), &dx);
164 p1->from.index = D_AX; // double-width shift
165 p1->from.scale = 0;
166 gins(ASHLL, ncon(v), &ax);
167 break;
168 }
169
170 // load value into DX:AX.
171 gins(AMOVL, &lo1, &ax);
172 gins(AMOVL, &hi1, &dx);
173
174 // load shift value into register.
175 // if high bits are set, zero value.
176 p1 = P;
177 if(is64(r->type)) {
178 gins(ACMPL, &hi2, ncon(0));
179 p1 = gbranch(AJNE, T);
180 gins(AMOVL, &lo2, &cx);
181 } else {
182 cx.type = types[TUINT32];
183 gmove(r, &cx);
184 }
185
186 // if shift count is >=64, zero value
187 gins(ACMPL, &cx, ncon(64));
188 p2 = gbranch(optoas(OLT, types[TUINT32]), T);
189 if(p1 != P)
190 patch(p1, pc);
191 gins(AXORL, &dx, &dx);
192 gins(AXORL, &ax, &ax);
193 patch(p2, pc);
194
195 // if shift count is >= 32, zero low.
196 gins(ACMPL, &cx, ncon(32));
197 p1 = gbranch(optoas(OLT, types[TUINT32]), T);
198 gins(AMOVL, &ax, &dx);
199 gins(ASHLL, &cx, &dx); // SHLL only uses bottom 5 bits of count
200 gins(AXORL, &ax, &ax);
201 p2 = gbranch(AJMP, T);
202 patch(p1, pc);
203
204 // general shift
205 p1 = gins(ASHLL, &cx, &dx);
206 p1->from.index = D_AX; // double-width shift
207 p1->from.scale = 0;
208 gins(ASHLL, &cx, &ax);
209 patch(p2, pc);
210 break;
211
212 case ORSH:
213 if(r->op == OLITERAL) {
214 v = mpgetfix(r->val.u.xval);
215 if(v >= 64) {
216 if(is64(r->type))
217 splitclean();
218 splitclean();
219 split64(res, &lo2, &hi2);
220 if(hi1.type->etype == TINT32) {
221 gmove(&hi1, &lo2);
222 gins(ASARL, ncon(31), &lo2);
223 gmove(&hi1, &hi2);
224 gins(ASARL, ncon(31), &hi2);
225 } else {
226 gins(AMOVL, ncon(0), &lo2);
227 gins(AMOVL, ncon(0), &hi2);
228 }
229 splitclean();
230 goto out;
231 }
232 if(v >= 32) {
233 if(is64(r->type))
234 splitclean();
235 split64(res, &lo2, &hi2);
236 gmove(&hi1, &lo2);
237 if(v > 32)
238 gins(optoas(ORSH, hi1.type), ncon(v-32), &lo2);
239 if(hi1.type->etype == TINT32) {
240 gmove(&hi1, &hi2);
241 gins(ASARL, ncon(31), &hi2);
242 } else
243 gins(AMOVL, ncon(0), &hi2);
244 splitclean();
245 splitclean();
246 goto out;
247 }
248
249 // general shift
250 gins(AMOVL, &lo1, &ax);
251 gins(AMOVL, &hi1, &dx);
252 p1 = gins(ASHRL, ncon(v), &ax);
253 p1->from.index = D_DX; // double-width shift
254 p1->from.scale = 0;
255 gins(optoas(ORSH, hi1.type), ncon(v), &dx);
256 break;
257 }
258
259 // load value into DX:AX.
260 gins(AMOVL, &lo1, &ax);
261 gins(AMOVL, &hi1, &dx);
262
263 // load shift value into register.
264 // if high bits are set, zero value.
265 p1 = P;
266 if(is64(r->type)) {
267 gins(ACMPL, &hi2, ncon(0));
268 p1 = gbranch(AJNE, T);
269 gins(AMOVL, &lo2, &cx);
270 } else {
271 cx.type = types[TUINT32];
272 gmove(r, &cx);
273 }
274
275 // if shift count is >=64, zero or sign-extend value
276 gins(ACMPL, &cx, ncon(64));
277 p2 = gbranch(optoas(OLT, types[TUINT32]), T);
278 if(p1 != P)
279 patch(p1, pc);
280 if(hi1.type->etype == TINT32) {
281 gins(ASARL, ncon(31), &dx);
282 gins(AMOVL, &dx, &ax);
283 } else {
284 gins(AXORL, &dx, &dx);
285 gins(AXORL, &ax, &ax);
286 }
287 patch(p2, pc);
288
289 // if shift count is >= 32, sign-extend hi.
290 gins(ACMPL, &cx, ncon(32));
291 p1 = gbranch(optoas(OLT, types[TUINT32]), T);
292 gins(AMOVL, &dx, &ax);
293 if(hi1.type->etype == TINT32) {
294 gins(ASARL, &cx, &ax); // SARL only uses bottom 5 bits of count
295 gins(ASARL, ncon(31), &dx);
296 } else {
297 gins(ASHRL, &cx, &ax);
298 gins(AXORL, &dx, &dx);
299 }
300 p2 = gbranch(AJMP, T);
301 patch(p1, pc);
302
303 // general shift
304 p1 = gins(ASHRL, &cx, &ax);
305 p1->from.index = D_DX; // double-width shift
306 p1->from.scale = 0;
307 gins(optoas(ORSH, hi1.type), &cx, &dx);
308 patch(p2, pc);
309 break;
310
311 case OXOR:
312 case OAND:
313 case OOR:
314 // make constant the right side (it usually is anyway).
315 if(lo1.op == OLITERAL) {
316 nswap(&lo1, &lo2);
317 nswap(&hi1, &hi2);
318 }
319 if(lo2.op == OLITERAL) {
320 // special cases for constants.
321 lv = mpgetfix(lo2.val.u.xval);
322 hv = mpgetfix(hi2.val.u.xval);
323 splitclean(); // right side
324 split64(res, &lo2, &hi2);
325 switch(n->op) {
326 case OXOR:
327 gmove(&lo1, &lo2);
328 gmove(&hi1, &hi2);
329 switch(lv) {
330 case 0:
331 break;
332 case 0xffffffffu:
333 gins(ANOTL, N, &lo2);
334 break;
335 default:
336 gins(AXORL, ncon(lv), &lo2);
337 break;
338 }
339 switch(hv) {
340 case 0:
341 break;
342 case 0xffffffffu:
343 gins(ANOTL, N, &hi2);
344 break;
345 default:
346 gins(AXORL, ncon(hv), &hi2);
347 break;
348 }
349 break;
350
351 case OAND:
352 switch(lv) {
353 case 0:
354 gins(AMOVL, ncon(0), &lo2);
355 break;
356 default:
357 gmove(&lo1, &lo2);
358 if(lv != 0xffffffffu)
359 gins(AANDL, ncon(lv), &lo2);
360 break;
361 }
362 switch(hv) {
363 case 0:
364 gins(AMOVL, ncon(0), &hi2);
365 break;
366 default:
367 gmove(&hi1, &hi2);
368 if(hv != 0xffffffffu)
369 gins(AANDL, ncon(hv), &hi2);
370 break;
371 }
372 break;
373
374 case OOR:
375 switch(lv) {
376 case 0:
377 gmove(&lo1, &lo2);
378 break;
379 case 0xffffffffu:
380 gins(AMOVL, ncon(0xffffffffu), &lo2);
381 break;
382 default:
383 gmove(&lo1, &lo2);
384 gins(AORL, ncon(lv), &lo2);
385 break;
386 }
387 switch(hv) {
388 case 0:
389 gmove(&hi1, &hi2);
390 break;
391 case 0xffffffffu:
392 gins(AMOVL, ncon(0xffffffffu), &hi2);
393 break;
394 default:
395 gmove(&hi1, &hi2);
396 gins(AORL, ncon(hv), &hi2);
397 break;
398 }
399 break;
400 }
401 splitclean();
402 splitclean();
403 goto out;
404 }
405 gins(AMOVL, &lo1, &ax);
406 gins(AMOVL, &hi1, &dx);
407 gins(optoas(n->op, lo1.type), &lo2, &ax);
408 gins(optoas(n->op, lo1.type), &hi2, &dx);
409 break;
410 }
411 if(is64(r->type))
412 splitclean();
413 splitclean();
414
415 split64(res, &lo1, &hi1);
416 gins(AMOVL, &ax, &lo1);
417 gins(AMOVL, &dx, &hi1);
418 splitclean();
419
420 out:;
421 }
422
423 /*
424 * generate comparison of nl, nr, both 64-bit.
425 * nl is memory; nr is constant or memory.
426 */
427 void
428 cmp64(Node *nl, Node *nr, int op, Prog *to)
429 {
430 Node lo1, hi1, lo2, hi2, rr;
431 Prog *br;
432 Type *t;
433
434 split64(nl, &lo1, &hi1);
435 split64(nr, &lo2, &hi2);
436
437 // compare most significant word;
438 // if they differ, we're done.
439 t = hi1.type;
440 if(nl->op == OLITERAL || nr->op == OLITERAL)
441 gins(ACMPL, &hi1, &hi2);
442 else {
443 regalloc(&rr, types[TINT32], N);
444 gins(AMOVL, &hi1, &rr);
445 gins(ACMPL, &rr, &hi2);
446 regfree(&rr);
447 }
448 br = P;
449 switch(op) {
450 default:
451 fatal("cmp64 %O %T", op, t);
452 case OEQ:
453 // cmp hi
454 // jne L
455 // cmp lo
456 // jeq to
457 // L:
458 br = gbranch(AJNE, T);
459 break;
460 case ONE:
461 // cmp hi
462 // jne to
463 // cmp lo
464 // jne to
465 patch(gbranch(AJNE, T), to);
466 break;
467 case OGE:
468 case OGT:
469 // cmp hi
470 // jgt to
471 // jlt L
472 // cmp lo
473 // jge to (or jgt to)
474 // L:
475 patch(gbranch(optoas(OGT, t), T), to);
476 br = gbranch(optoas(OLT, t), T);
477 break;
478 case OLE:
479 case OLT:
480 // cmp hi
481 // jlt to
482 // jgt L
483 // cmp lo
484 // jle to (or jlt to)
485 // L:
486 patch(gbranch(optoas(OLT, t), T), to);
487 br = gbranch(optoas(OGT, t), T);
488 break;
489 }
490
491 // compare least significant word
492 t = lo1.type;
493 if(nl->op == OLITERAL || nr->op == OLITERAL)
494 gins(ACMPL, &lo1, &lo2);
495 else {
496 regalloc(&rr, types[TINT32], N);
497 gins(AMOVL, &lo1, &rr);
498 gins(ACMPL, &rr, &lo2);
499 regfree(&rr);
500 }
501
502 // jump again
503 patch(gbranch(optoas(op, t), T), to);
504
505 // point first branch down here if appropriate
506 if(br != P)
507 patch(br, pc);
508
509 splitclean();
510 splitclean();
511 }
512