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