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