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