github.com/mdempsky/go@v0.0.0-20151201204031-5dd372bd1e70/src/cmd/compile/internal/mips64/gsubr.go (about) 1 // Derived from Inferno utils/6c/txt.c 2 // http://code.google.com/p/inferno-os/source/browse/utils/6c/txt.c 3 // 4 // Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. 5 // Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) 6 // Portions Copyright © 1997-1999 Vita Nuova Limited 7 // Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) 8 // Portions Copyright © 2004,2006 Bruce Ellis 9 // Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) 10 // Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others 11 // Portions Copyright © 2009 The Go Authors. All rights reserved. 12 // 13 // Permission is hereby granted, free of charge, to any person obtaining a copy 14 // of this software and associated documentation files (the "Software"), to deal 15 // in the Software without restriction, including without limitation the rights 16 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 // copies of the Software, and to permit persons to whom the Software is 18 // furnished to do so, subject to the following conditions: 19 // 20 // The above copyright notice and this permission notice shall be included in 21 // all copies or substantial portions of the Software. 22 // 23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 29 // THE SOFTWARE. 30 31 package mips64 32 33 import ( 34 "cmd/compile/internal/big" 35 "cmd/compile/internal/gc" 36 "cmd/internal/obj" 37 "cmd/internal/obj/mips" 38 "fmt" 39 ) 40 41 var resvd = []int{ 42 mips.REGZERO, 43 mips.REGSP, // reserved for SP 44 mips.REGLINK, // reserved for link 45 mips.REGG, 46 mips.REGTMP, 47 mips.REG_R26, // kernel 48 mips.REG_R27, // kernel 49 mips.FREGZERO, 50 mips.FREGHALF, 51 mips.FREGONE, 52 mips.FREGTWO, 53 } 54 55 /* 56 * generate 57 * as $c, n 58 */ 59 func ginscon(as int, c int64, n2 *gc.Node) { 60 var n1 gc.Node 61 62 gc.Nodconst(&n1, gc.Types[gc.TINT64], c) 63 64 if as != mips.AMOVV && (c < -mips.BIG || c > mips.BIG) || n2.Op != gc.OREGISTER || as == mips.AMUL || as == mips.AMULU || as == mips.AMULV || as == mips.AMULVU { 65 // cannot have more than 16-bit of immediate in ADD, etc. 66 // instead, MOV into register first. 67 var ntmp gc.Node 68 gc.Regalloc(&ntmp, gc.Types[gc.TINT64], nil) 69 70 rawgins(mips.AMOVV, &n1, &ntmp) 71 rawgins(as, &ntmp, n2) 72 gc.Regfree(&ntmp) 73 return 74 } 75 76 rawgins(as, &n1, n2) 77 } 78 79 // generate branch 80 // n1, n2 are registers 81 func ginsbranch(as int, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog { 82 p := gc.Gbranch(as, t, likely) 83 gc.Naddr(&p.From, n1) 84 if n2 != nil { 85 p.Reg = n2.Reg 86 } 87 return p 88 } 89 90 func ginscmp(op gc.Op, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog { 91 if !gc.Isfloat[t.Etype] && (op == gc.OLT || op == gc.OGE) { 92 // swap nodes to fit SGT instruction 93 n1, n2 = n2, n1 94 } 95 if gc.Isfloat[t.Etype] && (op == gc.OLT || op == gc.OLE) { 96 // swap nodes to fit CMPGT, CMPGE instructions and reverse relation 97 n1, n2 = n2, n1 98 if op == gc.OLT { 99 op = gc.OGT 100 } else { 101 op = gc.OGE 102 } 103 } 104 105 var r1, r2, g1, g2 gc.Node 106 gc.Regalloc(&r1, t, n1) 107 gc.Regalloc(&g1, n1.Type, &r1) 108 gc.Cgen(n1, &g1) 109 gmove(&g1, &r1) 110 111 gc.Regalloc(&r2, t, n2) 112 gc.Regalloc(&g2, n1.Type, &r2) 113 gc.Cgen(n2, &g2) 114 gmove(&g2, &r2) 115 116 var p *obj.Prog 117 var ntmp gc.Node 118 gc.Nodreg(&ntmp, gc.Types[gc.TINT], mips.REGTMP) 119 120 switch gc.Simtype[t.Etype] { 121 case gc.TINT8, 122 gc.TINT16, 123 gc.TINT32, 124 gc.TINT64: 125 if op == gc.OEQ || op == gc.ONE { 126 p = ginsbranch(optoas(op, t), nil, &r1, &r2, likely) 127 } else { 128 gins3(mips.ASGT, &r1, &r2, &ntmp) 129 130 p = ginsbranch(optoas(op, t), nil, &ntmp, nil, likely) 131 } 132 133 case gc.TBOOL, 134 gc.TUINT8, 135 gc.TUINT16, 136 gc.TUINT32, 137 gc.TUINT64, 138 gc.TPTR32, 139 gc.TPTR64: 140 if op == gc.OEQ || op == gc.ONE { 141 p = ginsbranch(optoas(op, t), nil, &r1, &r2, likely) 142 } else { 143 gins3(mips.ASGTU, &r1, &r2, &ntmp) 144 145 p = ginsbranch(optoas(op, t), nil, &ntmp, nil, likely) 146 } 147 148 case gc.TFLOAT32: 149 switch op { 150 default: 151 gc.Fatalf("ginscmp: no entry for op=%v type=%v", gc.Oconv(int(op), 0), t) 152 153 case gc.OEQ, 154 gc.ONE: 155 gins3(mips.ACMPEQF, &r1, &r2, nil) 156 157 case gc.OGE: 158 gins3(mips.ACMPGEF, &r1, &r2, nil) 159 160 case gc.OGT: 161 gins3(mips.ACMPGTF, &r1, &r2, nil) 162 } 163 p = gc.Gbranch(optoas(op, t), nil, likely) 164 165 case gc.TFLOAT64: 166 switch op { 167 default: 168 gc.Fatalf("ginscmp: no entry for op=%v type=%v", gc.Oconv(int(op), 0), t) 169 170 case gc.OEQ, 171 gc.ONE: 172 gins3(mips.ACMPEQD, &r1, &r2, nil) 173 174 case gc.OGE: 175 gins3(mips.ACMPGED, &r1, &r2, nil) 176 177 case gc.OGT: 178 gins3(mips.ACMPGTD, &r1, &r2, nil) 179 } 180 p = gc.Gbranch(optoas(op, t), nil, likely) 181 } 182 183 gc.Regfree(&g2) 184 gc.Regfree(&r2) 185 gc.Regfree(&g1) 186 gc.Regfree(&r1) 187 188 return p 189 } 190 191 // set up nodes representing 2^63 192 var ( 193 bigi gc.Node 194 bigf gc.Node 195 bignodes_did bool 196 ) 197 198 func bignodes() { 199 if bignodes_did { 200 return 201 } 202 bignodes_did = true 203 204 var i big.Int 205 i.SetInt64(1) 206 i.Lsh(&i, 63) 207 208 gc.Nodconst(&bigi, gc.Types[gc.TUINT64], 0) 209 bigi.SetBigInt(&i) 210 211 bigi.Convconst(&bigf, gc.Types[gc.TFLOAT64]) 212 } 213 214 /* 215 * generate move: 216 * t = f 217 * hard part is conversions. 218 */ 219 func gmove(f *gc.Node, t *gc.Node) { 220 if gc.Debug['M'] != 0 { 221 fmt.Printf("gmove %v -> %v\n", gc.Nconv(f, obj.FmtLong), gc.Nconv(t, obj.FmtLong)) 222 } 223 224 ft := int(gc.Simsimtype(f.Type)) 225 tt := int(gc.Simsimtype(t.Type)) 226 cvt := (*gc.Type)(t.Type) 227 228 if gc.Iscomplex[ft] || gc.Iscomplex[tt] { 229 gc.Complexmove(f, t) 230 return 231 } 232 233 // cannot have two memory operands 234 var r2 gc.Node 235 var r1 gc.Node 236 var a int 237 if gc.Ismem(f) && gc.Ismem(t) { 238 goto hard 239 } 240 241 // convert constant to desired type 242 if f.Op == gc.OLITERAL { 243 var con gc.Node 244 switch tt { 245 default: 246 f.Convconst(&con, t.Type) 247 248 case gc.TINT32, 249 gc.TINT16, 250 gc.TINT8: 251 var con gc.Node 252 f.Convconst(&con, gc.Types[gc.TINT64]) 253 var r1 gc.Node 254 gc.Regalloc(&r1, con.Type, t) 255 gins(mips.AMOVV, &con, &r1) 256 gmove(&r1, t) 257 gc.Regfree(&r1) 258 return 259 260 case gc.TUINT32, 261 gc.TUINT16, 262 gc.TUINT8: 263 var con gc.Node 264 f.Convconst(&con, gc.Types[gc.TUINT64]) 265 var r1 gc.Node 266 gc.Regalloc(&r1, con.Type, t) 267 gins(mips.AMOVV, &con, &r1) 268 gmove(&r1, t) 269 gc.Regfree(&r1) 270 return 271 } 272 273 f = &con 274 ft = tt // so big switch will choose a simple mov 275 276 // constants can't move directly to memory. 277 if gc.Ismem(t) { 278 goto hard 279 } 280 } 281 282 // value -> value copy, first operand in memory. 283 // any floating point operand requires register 284 // src, so goto hard to copy to register first. 285 if gc.Ismem(f) && ft != tt && (gc.Isfloat[ft] || gc.Isfloat[tt]) { 286 cvt = gc.Types[ft] 287 goto hard 288 } 289 290 // value -> value copy, only one memory operand. 291 // figure out the instruction to use. 292 // break out of switch for one-instruction gins. 293 // goto rdst for "destination must be register". 294 // goto hard for "convert to cvt type first". 295 // otherwise handle and return. 296 297 switch uint32(ft)<<16 | uint32(tt) { 298 default: 299 gc.Fatalf("gmove %v -> %v", gc.Tconv(f.Type, obj.FmtLong), gc.Tconv(t.Type, obj.FmtLong)) 300 301 /* 302 * integer copy and truncate 303 */ 304 case gc.TINT8<<16 | gc.TINT8, // same size 305 gc.TUINT8<<16 | gc.TINT8, 306 gc.TINT16<<16 | gc.TINT8, // truncate 307 gc.TUINT16<<16 | gc.TINT8, 308 gc.TINT32<<16 | gc.TINT8, 309 gc.TUINT32<<16 | gc.TINT8, 310 gc.TINT64<<16 | gc.TINT8, 311 gc.TUINT64<<16 | gc.TINT8: 312 a = mips.AMOVB 313 314 case gc.TINT8<<16 | gc.TUINT8, // same size 315 gc.TUINT8<<16 | gc.TUINT8, 316 gc.TINT16<<16 | gc.TUINT8, // truncate 317 gc.TUINT16<<16 | gc.TUINT8, 318 gc.TINT32<<16 | gc.TUINT8, 319 gc.TUINT32<<16 | gc.TUINT8, 320 gc.TINT64<<16 | gc.TUINT8, 321 gc.TUINT64<<16 | gc.TUINT8: 322 a = mips.AMOVBU 323 324 case gc.TINT16<<16 | gc.TINT16, // same size 325 gc.TUINT16<<16 | gc.TINT16, 326 gc.TINT32<<16 | gc.TINT16, // truncate 327 gc.TUINT32<<16 | gc.TINT16, 328 gc.TINT64<<16 | gc.TINT16, 329 gc.TUINT64<<16 | gc.TINT16: 330 a = mips.AMOVH 331 332 case gc.TINT16<<16 | gc.TUINT16, // same size 333 gc.TUINT16<<16 | gc.TUINT16, 334 gc.TINT32<<16 | gc.TUINT16, // truncate 335 gc.TUINT32<<16 | gc.TUINT16, 336 gc.TINT64<<16 | gc.TUINT16, 337 gc.TUINT64<<16 | gc.TUINT16: 338 a = mips.AMOVHU 339 340 case gc.TINT32<<16 | gc.TINT32, // same size 341 gc.TUINT32<<16 | gc.TINT32, 342 gc.TINT64<<16 | gc.TINT32, // truncate 343 gc.TUINT64<<16 | gc.TINT32: 344 a = mips.AMOVW 345 346 case gc.TINT32<<16 | gc.TUINT32, // same size 347 gc.TUINT32<<16 | gc.TUINT32, 348 gc.TINT64<<16 | gc.TUINT32, // truncate 349 gc.TUINT64<<16 | gc.TUINT32: 350 a = mips.AMOVWU 351 352 case gc.TINT64<<16 | gc.TINT64, // same size 353 gc.TINT64<<16 | gc.TUINT64, 354 gc.TUINT64<<16 | gc.TINT64, 355 gc.TUINT64<<16 | gc.TUINT64: 356 a = mips.AMOVV 357 358 /* 359 * integer up-conversions 360 */ 361 case gc.TINT8<<16 | gc.TINT16, // sign extend int8 362 gc.TINT8<<16 | gc.TUINT16, 363 gc.TINT8<<16 | gc.TINT32, 364 gc.TINT8<<16 | gc.TUINT32, 365 gc.TINT8<<16 | gc.TINT64, 366 gc.TINT8<<16 | gc.TUINT64: 367 a = mips.AMOVB 368 369 goto rdst 370 371 case gc.TUINT8<<16 | gc.TINT16, // zero extend uint8 372 gc.TUINT8<<16 | gc.TUINT16, 373 gc.TUINT8<<16 | gc.TINT32, 374 gc.TUINT8<<16 | gc.TUINT32, 375 gc.TUINT8<<16 | gc.TINT64, 376 gc.TUINT8<<16 | gc.TUINT64: 377 a = mips.AMOVBU 378 379 goto rdst 380 381 case gc.TINT16<<16 | gc.TINT32, // sign extend int16 382 gc.TINT16<<16 | gc.TUINT32, 383 gc.TINT16<<16 | gc.TINT64, 384 gc.TINT16<<16 | gc.TUINT64: 385 a = mips.AMOVH 386 387 goto rdst 388 389 case gc.TUINT16<<16 | gc.TINT32, // zero extend uint16 390 gc.TUINT16<<16 | gc.TUINT32, 391 gc.TUINT16<<16 | gc.TINT64, 392 gc.TUINT16<<16 | gc.TUINT64: 393 a = mips.AMOVHU 394 395 goto rdst 396 397 case gc.TINT32<<16 | gc.TINT64, // sign extend int32 398 gc.TINT32<<16 | gc.TUINT64: 399 a = mips.AMOVW 400 401 goto rdst 402 403 case gc.TUINT32<<16 | gc.TINT64, // zero extend uint32 404 gc.TUINT32<<16 | gc.TUINT64: 405 a = mips.AMOVWU 406 407 goto rdst 408 409 //warn("gmove: convert float to int not implemented: %N -> %N\n", f, t); 410 //return; 411 // algorithm is: 412 // if small enough, use native float64 -> int64 conversion. 413 // otherwise, subtract 2^63, convert, and add it back. 414 /* 415 * float to integer 416 */ 417 case gc.TFLOAT32<<16 | gc.TINT32, 418 gc.TFLOAT64<<16 | gc.TINT32, 419 gc.TFLOAT32<<16 | gc.TINT64, 420 gc.TFLOAT64<<16 | gc.TINT64, 421 gc.TFLOAT32<<16 | gc.TINT16, 422 gc.TFLOAT32<<16 | gc.TINT8, 423 gc.TFLOAT32<<16 | gc.TUINT16, 424 gc.TFLOAT32<<16 | gc.TUINT8, 425 gc.TFLOAT64<<16 | gc.TINT16, 426 gc.TFLOAT64<<16 | gc.TINT8, 427 gc.TFLOAT64<<16 | gc.TUINT16, 428 gc.TFLOAT64<<16 | gc.TUINT8, 429 gc.TFLOAT32<<16 | gc.TUINT32, 430 gc.TFLOAT64<<16 | gc.TUINT32, 431 gc.TFLOAT32<<16 | gc.TUINT64, 432 gc.TFLOAT64<<16 | gc.TUINT64: 433 bignodes() 434 435 gc.Regalloc(&r1, gc.Types[gc.TFLOAT64], nil) 436 gmove(f, &r1) 437 if tt == gc.TUINT64 { 438 gc.Regalloc(&r2, gc.Types[gc.TFLOAT64], nil) 439 gmove(&bigf, &r2) 440 gins3(mips.ACMPGED, &r1, &r2, nil) 441 p1 := gc.Gbranch(mips.ABFPF, nil, 0) 442 gins(mips.ASUBD, &r2, &r1) 443 gc.Patch(p1, gc.Pc) 444 gc.Regfree(&r2) 445 } 446 447 gc.Regalloc(&r2, gc.Types[gc.TINT64], t) 448 gins(mips.ATRUNCDV, &r1, &r1) 449 gins(mips.AMOVV, &r1, &r2) 450 gc.Regfree(&r1) 451 452 if tt == gc.TUINT64 { 453 p1 := gc.Gbranch(mips.ABFPF, nil, 0) // use FCR0 here again 454 gc.Nodreg(&r1, gc.Types[gc.TINT64], mips.REGTMP) 455 gmove(&bigi, &r1) 456 gins(mips.AADDVU, &r1, &r2) 457 gc.Patch(p1, gc.Pc) 458 } 459 460 gmove(&r2, t) 461 gc.Regfree(&r2) 462 return 463 464 //warn("gmove: convert int to float not implemented: %N -> %N\n", f, t); 465 //return; 466 // algorithm is: 467 // if small enough, use native int64 -> float64 conversion. 468 // otherwise, halve (rounding to odd?), convert, and double. 469 /* 470 * integer to float 471 */ 472 case gc.TINT32<<16 | gc.TFLOAT32, 473 gc.TINT32<<16 | gc.TFLOAT64, 474 gc.TINT64<<16 | gc.TFLOAT32, 475 gc.TINT64<<16 | gc.TFLOAT64, 476 gc.TINT16<<16 | gc.TFLOAT32, 477 gc.TINT16<<16 | gc.TFLOAT64, 478 gc.TINT8<<16 | gc.TFLOAT32, 479 gc.TINT8<<16 | gc.TFLOAT64, 480 gc.TUINT16<<16 | gc.TFLOAT32, 481 gc.TUINT16<<16 | gc.TFLOAT64, 482 gc.TUINT8<<16 | gc.TFLOAT32, 483 gc.TUINT8<<16 | gc.TFLOAT64, 484 gc.TUINT32<<16 | gc.TFLOAT32, 485 gc.TUINT32<<16 | gc.TFLOAT64, 486 gc.TUINT64<<16 | gc.TFLOAT32, 487 gc.TUINT64<<16 | gc.TFLOAT64: 488 bignodes() 489 490 var rtmp gc.Node 491 gc.Regalloc(&r1, gc.Types[gc.TINT64], nil) 492 gmove(f, &r1) 493 if ft == gc.TUINT64 { 494 gc.Nodreg(&rtmp, gc.Types[gc.TUINT64], mips.REGTMP) 495 gmove(&bigi, &rtmp) 496 gins(mips.AAND, &r1, &rtmp) 497 p1 := ginsbranch(mips.ABEQ, nil, &rtmp, nil, 0) 498 p2 := gins(mips.ASRLV, nil, &r1) 499 p2.From.Type = obj.TYPE_CONST 500 p2.From.Offset = 1 501 gc.Patch(p1, gc.Pc) 502 } 503 504 gc.Regalloc(&r2, gc.Types[gc.TFLOAT64], t) 505 gins(mips.AMOVV, &r1, &r2) 506 gins(mips.AMOVVD, &r2, &r2) 507 gc.Regfree(&r1) 508 509 if ft == gc.TUINT64 { 510 p1 := ginsbranch(mips.ABEQ, nil, &rtmp, nil, 0) 511 gc.Nodreg(&r1, gc.Types[gc.TFLOAT64], mips.FREGTWO) 512 gins(mips.AMULD, &r1, &r2) 513 gc.Patch(p1, gc.Pc) 514 } 515 516 gmove(&r2, t) 517 gc.Regfree(&r2) 518 return 519 520 /* 521 * float to float 522 */ 523 case gc.TFLOAT32<<16 | gc.TFLOAT32: 524 a = mips.AMOVF 525 526 case gc.TFLOAT64<<16 | gc.TFLOAT64: 527 a = mips.AMOVD 528 529 case gc.TFLOAT32<<16 | gc.TFLOAT64: 530 a = mips.AMOVFD 531 goto rdst 532 533 case gc.TFLOAT64<<16 | gc.TFLOAT32: 534 a = mips.AMOVDF 535 goto rdst 536 } 537 538 gins(a, f, t) 539 return 540 541 // requires register destination 542 rdst: 543 { 544 gc.Regalloc(&r1, t.Type, t) 545 546 gins(a, f, &r1) 547 gmove(&r1, t) 548 gc.Regfree(&r1) 549 return 550 } 551 552 // requires register intermediate 553 hard: 554 gc.Regalloc(&r1, cvt, t) 555 556 gmove(f, &r1) 557 gmove(&r1, t) 558 gc.Regfree(&r1) 559 return 560 } 561 562 // gins is called by the front end. 563 // It synthesizes some multiple-instruction sequences 564 // so the front end can stay simpler. 565 func gins(as int, f, t *gc.Node) *obj.Prog { 566 if as >= obj.A_ARCHSPECIFIC { 567 if x, ok := f.IntLiteral(); ok { 568 ginscon(as, x, t) 569 return nil // caller must not use 570 } 571 } 572 return rawgins(as, f, t) 573 } 574 575 /* 576 * generate one instruction: 577 * as f, r, t 578 * r must be register, if not nil 579 */ 580 func gins3(as int, f, r, t *gc.Node) *obj.Prog { 581 p := rawgins(as, f, t) 582 if r != nil { 583 p.Reg = r.Reg 584 } 585 return p 586 } 587 588 /* 589 * generate one instruction: 590 * as f, t 591 */ 592 func rawgins(as int, f *gc.Node, t *gc.Node) *obj.Prog { 593 // TODO(austin): Add self-move test like in 6g (but be careful 594 // of truncation moves) 595 596 p := gc.Prog(as) 597 gc.Naddr(&p.From, f) 598 gc.Naddr(&p.To, t) 599 600 switch as { 601 case obj.ACALL: 602 if p.To.Type == obj.TYPE_REG { 603 // Allow front end to emit CALL REG, and rewrite into CALL (REG). 604 p.From = obj.Addr{} 605 p.To.Type = obj.TYPE_MEM 606 p.To.Offset = 0 607 608 if gc.Debug['g'] != 0 { 609 fmt.Printf("%v\n", p) 610 } 611 612 return p 613 } 614 615 // Bad things the front end has done to us. Crash to find call stack. 616 case mips.AAND: 617 if p.From.Type == obj.TYPE_CONST { 618 gc.Debug['h'] = 1 619 gc.Fatalf("bad inst: %v", p) 620 } 621 case mips.ASGT, mips.ASGTU: 622 if p.From.Type == obj.TYPE_MEM || p.To.Type == obj.TYPE_MEM { 623 gc.Debug['h'] = 1 624 gc.Fatalf("bad inst: %v", p) 625 } 626 627 // Special cases 628 case mips.AMUL, mips.AMULU, mips.AMULV, mips.AMULVU: 629 if p.From.Type == obj.TYPE_CONST { 630 gc.Debug['h'] = 1 631 gc.Fatalf("bad inst: %v", p) 632 } 633 634 pp := gc.Prog(mips.AMOVV) 635 pp.From.Type = obj.TYPE_REG 636 pp.From.Reg = mips.REG_LO 637 pp.To = p.To 638 639 p.Reg = p.To.Reg 640 p.To = obj.Addr{} 641 642 case mips.ASUBVU: 643 // unary 644 if f == nil { 645 p.From = p.To 646 p.Reg = mips.REGZERO 647 } 648 } 649 650 if gc.Debug['g'] != 0 { 651 fmt.Printf("%v\n", p) 652 } 653 654 w := int32(0) 655 switch as { 656 case mips.AMOVB, 657 mips.AMOVBU: 658 w = 1 659 660 case mips.AMOVH, 661 mips.AMOVHU: 662 w = 2 663 664 case mips.AMOVW, 665 mips.AMOVWU: 666 w = 4 667 668 case mips.AMOVV: 669 if p.From.Type == obj.TYPE_CONST || p.From.Type == obj.TYPE_ADDR { 670 break 671 } 672 w = 8 673 } 674 675 if w != 0 && ((f != nil && p.From.Width < int64(w)) || (t != nil && p.To.Type != obj.TYPE_REG && p.To.Width > int64(w))) { 676 gc.Dump("f", f) 677 gc.Dump("t", t) 678 gc.Fatalf("bad width: %v (%d, %d)\n", p, p.From.Width, p.To.Width) 679 } 680 681 return p 682 } 683 684 /* 685 * return Axxx for Oxxx on type t. 686 */ 687 func optoas(op gc.Op, t *gc.Type) int { 688 if t == nil { 689 gc.Fatalf("optoas: t is nil") 690 } 691 692 // avoid constant conversions in switches below 693 const ( 694 OMINUS_ = uint32(gc.OMINUS) << 16 695 OLSH_ = uint32(gc.OLSH) << 16 696 ORSH_ = uint32(gc.ORSH) << 16 697 OADD_ = uint32(gc.OADD) << 16 698 OSUB_ = uint32(gc.OSUB) << 16 699 OMUL_ = uint32(gc.OMUL) << 16 700 ODIV_ = uint32(gc.ODIV) << 16 701 OOR_ = uint32(gc.OOR) << 16 702 OAND_ = uint32(gc.OAND) << 16 703 OXOR_ = uint32(gc.OXOR) << 16 704 OEQ_ = uint32(gc.OEQ) << 16 705 ONE_ = uint32(gc.ONE) << 16 706 OLT_ = uint32(gc.OLT) << 16 707 OLE_ = uint32(gc.OLE) << 16 708 OGE_ = uint32(gc.OGE) << 16 709 OGT_ = uint32(gc.OGT) << 16 710 OCMP_ = uint32(gc.OCMP) << 16 711 OAS_ = uint32(gc.OAS) << 16 712 OHMUL_ = uint32(gc.OHMUL) << 16 713 ) 714 715 a := int(obj.AXXX) 716 switch uint32(op)<<16 | uint32(gc.Simtype[t.Etype]) { 717 default: 718 gc.Fatalf("optoas: no entry for op=%v type=%v", gc.Oconv(int(op), 0), t) 719 720 case OEQ_ | gc.TBOOL, 721 OEQ_ | gc.TINT8, 722 OEQ_ | gc.TUINT8, 723 OEQ_ | gc.TINT16, 724 OEQ_ | gc.TUINT16, 725 OEQ_ | gc.TINT32, 726 OEQ_ | gc.TUINT32, 727 OEQ_ | gc.TINT64, 728 OEQ_ | gc.TUINT64, 729 OEQ_ | gc.TPTR32, 730 OEQ_ | gc.TPTR64: 731 a = mips.ABEQ 732 733 case OEQ_ | gc.TFLOAT32, // ACMPEQF 734 OEQ_ | gc.TFLOAT64: // ACMPEQD 735 a = mips.ABFPT 736 737 case ONE_ | gc.TBOOL, 738 ONE_ | gc.TINT8, 739 ONE_ | gc.TUINT8, 740 ONE_ | gc.TINT16, 741 ONE_ | gc.TUINT16, 742 ONE_ | gc.TINT32, 743 ONE_ | gc.TUINT32, 744 ONE_ | gc.TINT64, 745 ONE_ | gc.TUINT64, 746 ONE_ | gc.TPTR32, 747 ONE_ | gc.TPTR64: 748 a = mips.ABNE 749 750 case ONE_ | gc.TFLOAT32, // ACMPEQF 751 ONE_ | gc.TFLOAT64: // ACMPEQD 752 a = mips.ABFPF 753 754 case OLT_ | gc.TINT8, // ASGT 755 OLT_ | gc.TINT16, 756 OLT_ | gc.TINT32, 757 OLT_ | gc.TINT64, 758 OLT_ | gc.TUINT8, // ASGTU 759 OLT_ | gc.TUINT16, 760 OLT_ | gc.TUINT32, 761 OLT_ | gc.TUINT64: 762 a = mips.ABNE 763 764 case OLT_ | gc.TFLOAT32, // ACMPGEF 765 OLT_ | gc.TFLOAT64: // ACMPGED 766 a = mips.ABFPT 767 768 case OLE_ | gc.TINT8, // ASGT 769 OLE_ | gc.TINT16, 770 OLE_ | gc.TINT32, 771 OLE_ | gc.TINT64, 772 OLE_ | gc.TUINT8, // ASGTU 773 OLE_ | gc.TUINT16, 774 OLE_ | gc.TUINT32, 775 OLE_ | gc.TUINT64: 776 a = mips.ABEQ 777 778 case OLE_ | gc.TFLOAT32, // ACMPGTF 779 OLE_ | gc.TFLOAT64: // ACMPGTD 780 a = mips.ABFPT 781 782 case OGT_ | gc.TINT8, // ASGT 783 OGT_ | gc.TINT16, 784 OGT_ | gc.TINT32, 785 OGT_ | gc.TINT64, 786 OGT_ | gc.TUINT8, // ASGTU 787 OGT_ | gc.TUINT16, 788 OGT_ | gc.TUINT32, 789 OGT_ | gc.TUINT64: 790 a = mips.ABNE 791 792 case OGT_ | gc.TFLOAT32, // ACMPGTF 793 OGT_ | gc.TFLOAT64: // ACMPGTD 794 a = mips.ABFPT 795 796 case OGE_ | gc.TINT8, // ASGT 797 OGE_ | gc.TINT16, 798 OGE_ | gc.TINT32, 799 OGE_ | gc.TINT64, 800 OGE_ | gc.TUINT8, // ASGTU 801 OGE_ | gc.TUINT16, 802 OGE_ | gc.TUINT32, 803 OGE_ | gc.TUINT64: 804 a = mips.ABEQ 805 806 case OGE_ | gc.TFLOAT32, // ACMPGEF 807 OGE_ | gc.TFLOAT64: // ACMPGED 808 a = mips.ABFPT 809 810 case OAS_ | gc.TBOOL, 811 OAS_ | gc.TINT8: 812 a = mips.AMOVB 813 814 case OAS_ | gc.TUINT8: 815 a = mips.AMOVBU 816 817 case OAS_ | gc.TINT16: 818 a = mips.AMOVH 819 820 case OAS_ | gc.TUINT16: 821 a = mips.AMOVHU 822 823 case OAS_ | gc.TINT32: 824 a = mips.AMOVW 825 826 case OAS_ | gc.TUINT32, 827 OAS_ | gc.TPTR32: 828 a = mips.AMOVWU 829 830 case OAS_ | gc.TINT64, 831 OAS_ | gc.TUINT64, 832 OAS_ | gc.TPTR64: 833 a = mips.AMOVV 834 835 case OAS_ | gc.TFLOAT32: 836 a = mips.AMOVF 837 838 case OAS_ | gc.TFLOAT64: 839 a = mips.AMOVD 840 841 case OADD_ | gc.TINT8, 842 OADD_ | gc.TUINT8, 843 OADD_ | gc.TINT16, 844 OADD_ | gc.TUINT16, 845 OADD_ | gc.TINT32, 846 OADD_ | gc.TUINT32, 847 OADD_ | gc.TPTR32: 848 a = mips.AADDU 849 850 case OADD_ | gc.TINT64, 851 OADD_ | gc.TUINT64, 852 OADD_ | gc.TPTR64: 853 a = mips.AADDVU 854 855 case OADD_ | gc.TFLOAT32: 856 a = mips.AADDF 857 858 case OADD_ | gc.TFLOAT64: 859 a = mips.AADDD 860 861 case OSUB_ | gc.TINT8, 862 OSUB_ | gc.TUINT8, 863 OSUB_ | gc.TINT16, 864 OSUB_ | gc.TUINT16, 865 OSUB_ | gc.TINT32, 866 OSUB_ | gc.TUINT32, 867 OSUB_ | gc.TPTR32: 868 a = mips.ASUBU 869 870 case OSUB_ | gc.TINT64, 871 OSUB_ | gc.TUINT64, 872 OSUB_ | gc.TPTR64: 873 a = mips.ASUBVU 874 875 case OSUB_ | gc.TFLOAT32: 876 a = mips.ASUBF 877 878 case OSUB_ | gc.TFLOAT64: 879 a = mips.ASUBD 880 881 case OMINUS_ | gc.TINT8, 882 OMINUS_ | gc.TUINT8, 883 OMINUS_ | gc.TINT16, 884 OMINUS_ | gc.TUINT16, 885 OMINUS_ | gc.TINT32, 886 OMINUS_ | gc.TUINT32, 887 OMINUS_ | gc.TPTR32, 888 OMINUS_ | gc.TINT64, 889 OMINUS_ | gc.TUINT64, 890 OMINUS_ | gc.TPTR64: 891 a = mips.ASUBVU 892 893 case OAND_ | gc.TINT8, 894 OAND_ | gc.TUINT8, 895 OAND_ | gc.TINT16, 896 OAND_ | gc.TUINT16, 897 OAND_ | gc.TINT32, 898 OAND_ | gc.TUINT32, 899 OAND_ | gc.TPTR32, 900 OAND_ | gc.TINT64, 901 OAND_ | gc.TUINT64, 902 OAND_ | gc.TPTR64: 903 a = mips.AAND 904 905 case OOR_ | gc.TINT8, 906 OOR_ | gc.TUINT8, 907 OOR_ | gc.TINT16, 908 OOR_ | gc.TUINT16, 909 OOR_ | gc.TINT32, 910 OOR_ | gc.TUINT32, 911 OOR_ | gc.TPTR32, 912 OOR_ | gc.TINT64, 913 OOR_ | gc.TUINT64, 914 OOR_ | gc.TPTR64: 915 a = mips.AOR 916 917 case OXOR_ | gc.TINT8, 918 OXOR_ | gc.TUINT8, 919 OXOR_ | gc.TINT16, 920 OXOR_ | gc.TUINT16, 921 OXOR_ | gc.TINT32, 922 OXOR_ | gc.TUINT32, 923 OXOR_ | gc.TPTR32, 924 OXOR_ | gc.TINT64, 925 OXOR_ | gc.TUINT64, 926 OXOR_ | gc.TPTR64: 927 a = mips.AXOR 928 929 // TODO(minux): handle rotates 930 //case CASE(OLROT, TINT8): 931 //case CASE(OLROT, TUINT8): 932 //case CASE(OLROT, TINT16): 933 //case CASE(OLROT, TUINT16): 934 //case CASE(OLROT, TINT32): 935 //case CASE(OLROT, TUINT32): 936 //case CASE(OLROT, TPTR32): 937 //case CASE(OLROT, TINT64): 938 //case CASE(OLROT, TUINT64): 939 //case CASE(OLROT, TPTR64): 940 // a = 0//???; RLDC? 941 // break; 942 943 case OLSH_ | gc.TINT8, 944 OLSH_ | gc.TUINT8, 945 OLSH_ | gc.TINT16, 946 OLSH_ | gc.TUINT16, 947 OLSH_ | gc.TINT32, 948 OLSH_ | gc.TUINT32, 949 OLSH_ | gc.TPTR32, 950 OLSH_ | gc.TINT64, 951 OLSH_ | gc.TUINT64, 952 OLSH_ | gc.TPTR64: 953 a = mips.ASLLV 954 955 case ORSH_ | gc.TUINT8, 956 ORSH_ | gc.TUINT16, 957 ORSH_ | gc.TUINT32, 958 ORSH_ | gc.TPTR32, 959 ORSH_ | gc.TUINT64, 960 ORSH_ | gc.TPTR64: 961 a = mips.ASRLV 962 963 case ORSH_ | gc.TINT8, 964 ORSH_ | gc.TINT16, 965 ORSH_ | gc.TINT32, 966 ORSH_ | gc.TINT64: 967 a = mips.ASRAV 968 969 // TODO(minux): handle rotates 970 //case CASE(ORROTC, TINT8): 971 //case CASE(ORROTC, TUINT8): 972 //case CASE(ORROTC, TINT16): 973 //case CASE(ORROTC, TUINT16): 974 //case CASE(ORROTC, TINT32): 975 //case CASE(ORROTC, TUINT32): 976 //case CASE(ORROTC, TINT64): 977 //case CASE(ORROTC, TUINT64): 978 // a = 0//??? RLDC?? 979 // break; 980 981 case OHMUL_ | gc.TINT64: 982 a = mips.AMULV 983 984 case OHMUL_ | gc.TUINT64, 985 OHMUL_ | gc.TPTR64: 986 a = mips.AMULVU 987 988 case OMUL_ | gc.TINT8, 989 OMUL_ | gc.TINT16, 990 OMUL_ | gc.TINT32, 991 OMUL_ | gc.TINT64: 992 a = mips.AMULV 993 994 case OMUL_ | gc.TUINT8, 995 OMUL_ | gc.TUINT16, 996 OMUL_ | gc.TUINT32, 997 OMUL_ | gc.TPTR32, 998 OMUL_ | gc.TUINT64, 999 OMUL_ | gc.TPTR64: 1000 a = mips.AMULVU 1001 1002 case OMUL_ | gc.TFLOAT32: 1003 a = mips.AMULF 1004 1005 case OMUL_ | gc.TFLOAT64: 1006 a = mips.AMULD 1007 1008 case ODIV_ | gc.TINT8, 1009 ODIV_ | gc.TINT16, 1010 ODIV_ | gc.TINT32, 1011 ODIV_ | gc.TINT64: 1012 a = mips.ADIVV 1013 1014 case ODIV_ | gc.TUINT8, 1015 ODIV_ | gc.TUINT16, 1016 ODIV_ | gc.TUINT32, 1017 ODIV_ | gc.TPTR32, 1018 ODIV_ | gc.TUINT64, 1019 ODIV_ | gc.TPTR64: 1020 a = mips.ADIVVU 1021 1022 case ODIV_ | gc.TFLOAT32: 1023 a = mips.ADIVF 1024 1025 case ODIV_ | gc.TFLOAT64: 1026 a = mips.ADIVD 1027 } 1028 1029 return a 1030 } 1031 1032 const ( 1033 ODynam = 1 << 0 1034 OAddable = 1 << 1 1035 ) 1036 1037 func xgen(n *gc.Node, a *gc.Node, o int) bool { 1038 // TODO(minux) 1039 1040 return -1 != 0 /*TypeKind(100016)*/ 1041 } 1042 1043 func sudoclean() { 1044 return 1045 } 1046 1047 /* 1048 * generate code to compute address of n, 1049 * a reference to a (perhaps nested) field inside 1050 * an array or struct. 1051 * return 0 on failure, 1 on success. 1052 * on success, leaves usable address in a. 1053 * 1054 * caller is responsible for calling sudoclean 1055 * after successful sudoaddable, 1056 * to release the register used for a. 1057 */ 1058 func sudoaddable(as int, n *gc.Node, a *obj.Addr) bool { 1059 // TODO(minux) 1060 1061 *a = obj.Addr{} 1062 return false 1063 }