github.com/mh-cbon/go@v0.0.0-20160603070303-9e112a3fe4c0/src/cmd/compile/internal/s390x/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 s390x 32 33 import ( 34 "cmd/compile/internal/gc" 35 "cmd/internal/obj" 36 "cmd/internal/obj/s390x" 37 "fmt" 38 ) 39 40 var resvd = []int{ 41 s390x.REGZERO, // R0 42 s390x.REGTMP, // R10 43 s390x.REGTMP2, // R11 44 s390x.REGCTXT, // R12 45 s390x.REGG, // R13 46 s390x.REG_LR, // R14 47 s390x.REGSP, // R15 48 } 49 50 // generate 51 // as $c, n 52 func ginscon(as obj.As, c int64, n2 *gc.Node) { 53 var n1 gc.Node 54 55 gc.Nodconst(&n1, gc.Types[gc.TINT64], c) 56 57 if as != s390x.AMOVD && (c < -s390x.BIG || c > s390x.BIG) || n2.Op != gc.OREGISTER { 58 // cannot have more than 16-bit of immediate in ADD, etc. 59 // instead, MOV into register first. 60 var ntmp gc.Node 61 gc.Regalloc(&ntmp, gc.Types[gc.TINT64], nil) 62 63 rawgins(s390x.AMOVD, &n1, &ntmp) 64 rawgins(as, &ntmp, n2) 65 gc.Regfree(&ntmp) 66 return 67 } 68 69 rawgins(as, &n1, n2) 70 } 71 72 // generate 73 // as n, $c (CMP/CMPU) 74 func ginscon2(as obj.As, n2 *gc.Node, c int64) { 75 var n1 gc.Node 76 77 gc.Nodconst(&n1, gc.Types[gc.TINT64], c) 78 79 switch as { 80 default: 81 gc.Fatalf("ginscon2") 82 83 case s390x.ACMP: 84 if -s390x.BIG <= c && c <= s390x.BIG { 85 rawgins(as, n2, &n1) 86 return 87 } 88 89 case s390x.ACMPU: 90 if 0 <= c && c <= 2*s390x.BIG { 91 rawgins(as, n2, &n1) 92 return 93 } 94 } 95 96 // MOV n1 into register first 97 var ntmp gc.Node 98 gc.Regalloc(&ntmp, gc.Types[gc.TINT64], nil) 99 100 rawgins(s390x.AMOVD, &n1, &ntmp) 101 rawgins(as, n2, &ntmp) 102 gc.Regfree(&ntmp) 103 } 104 105 func ginscmp(op gc.Op, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog { 106 if t.IsInteger() && n1.Op == gc.OLITERAL && n2.Op != gc.OLITERAL { 107 // Reverse comparison to place constant last. 108 op = gc.Brrev(op) 109 n1, n2 = n2, n1 110 } 111 112 var r1, r2, g1, g2 gc.Node 113 gc.Regalloc(&r1, t, n1) 114 gc.Regalloc(&g1, n1.Type, &r1) 115 gc.Cgen(n1, &g1) 116 gmove(&g1, &r1) 117 if t.IsInteger() && gc.Isconst(n2, gc.CTINT) { 118 ginscon2(optoas(gc.OCMP, t), &r1, n2.Int64()) 119 } else { 120 gc.Regalloc(&r2, t, n2) 121 gc.Regalloc(&g2, n1.Type, &r2) 122 gc.Cgen(n2, &g2) 123 gmove(&g2, &r2) 124 rawgins(optoas(gc.OCMP, t), &r1, &r2) 125 gc.Regfree(&g2) 126 gc.Regfree(&r2) 127 } 128 gc.Regfree(&g1) 129 gc.Regfree(&r1) 130 return gc.Gbranch(optoas(op, t), nil, likely) 131 } 132 133 // gmvc tries to move f to t using a mvc instruction. 134 // If successful it returns true, otherwise it returns false. 135 func gmvc(f, t *gc.Node) bool { 136 ft := int(gc.Simsimtype(f.Type)) 137 tt := int(gc.Simsimtype(t.Type)) 138 139 if ft != tt { 140 return false 141 } 142 143 if f.Op != gc.OINDREG || t.Op != gc.OINDREG { 144 return false 145 } 146 147 if f.Xoffset < 0 || f.Xoffset >= 4096-8 { 148 return false 149 } 150 151 if t.Xoffset < 0 || t.Xoffset >= 4096-8 { 152 return false 153 } 154 155 var len int64 156 switch ft { 157 case gc.TUINT8, gc.TINT8, gc.TBOOL: 158 len = 1 159 case gc.TUINT16, gc.TINT16: 160 len = 2 161 case gc.TUINT32, gc.TINT32, gc.TFLOAT32: 162 len = 4 163 case gc.TUINT64, gc.TINT64, gc.TFLOAT64, gc.TPTR64: 164 len = 8 165 case gc.TUNSAFEPTR: 166 len = int64(gc.Widthptr) 167 default: 168 return false 169 } 170 171 p := gc.Prog(s390x.AMVC) 172 gc.Naddr(&p.From, f) 173 gc.Naddr(&p.To, t) 174 p.From3 = new(obj.Addr) 175 p.From3.Offset = len 176 p.From3.Type = obj.TYPE_CONST 177 return true 178 } 179 180 // generate move: 181 // t = f 182 // hard part is conversions. 183 func gmove(f *gc.Node, t *gc.Node) { 184 if gc.Debug['M'] != 0 { 185 fmt.Printf("gmove %v -> %v\n", gc.Nconv(f, gc.FmtLong), gc.Nconv(t, gc.FmtLong)) 186 } 187 188 ft := int(gc.Simsimtype(f.Type)) 189 tt := int(gc.Simsimtype(t.Type)) 190 cvt := t.Type 191 192 if gc.Iscomplex[ft] || gc.Iscomplex[tt] { 193 gc.Complexmove(f, t) 194 return 195 } 196 197 var a obj.As 198 199 // cannot have two memory operands 200 if gc.Ismem(f) && gc.Ismem(t) { 201 if gmvc(f, t) { 202 return 203 } 204 goto hard 205 } 206 207 // convert constant to desired type 208 if f.Op == gc.OLITERAL { 209 var con gc.Node 210 f.Convconst(&con, t.Type) 211 f = &con 212 ft = tt // so big switch will choose a simple mov 213 214 // some constants can't move directly to memory. 215 if gc.Ismem(t) { 216 // float constants come from memory. 217 if t.Type.IsFloat() { 218 goto hard 219 } 220 221 // all immediates are 16-bit sign-extended 222 // unless moving into a register. 223 if t.Type.IsInteger() { 224 if i := con.Int64(); int64(int16(i)) != i { 225 goto hard 226 } 227 } 228 229 // immediate moves to memory have a 12-bit unsigned displacement 230 if t.Xoffset < 0 || t.Xoffset >= 4096-8 { 231 goto hard 232 } 233 } 234 } 235 236 // a float-to-int or int-to-float conversion requires the source operand in a register 237 if gc.Ismem(f) && ((f.Type.IsFloat() && t.Type.IsInteger()) || (f.Type.IsInteger() && t.Type.IsFloat())) { 238 cvt = f.Type 239 goto hard 240 } 241 242 // a float32-to-float64 or float64-to-float32 conversion requires the source operand in a register 243 if gc.Ismem(f) && f.Type.IsFloat() && t.Type.IsFloat() && (ft != tt) { 244 cvt = f.Type 245 goto hard 246 } 247 248 // value -> value copy, only one memory operand. 249 // figure out the instruction to use. 250 // break out of switch for one-instruction gins. 251 // goto rdst for "destination must be register". 252 // goto hard for "convert to cvt type first". 253 // otherwise handle and return. 254 switch uint32(ft)<<16 | uint32(tt) { 255 default: 256 gc.Fatalf("gmove %v -> %v", gc.Tconv(f.Type, gc.FmtLong), gc.Tconv(t.Type, gc.FmtLong)) 257 258 // integer copy and truncate 259 case gc.TINT8<<16 | gc.TINT8, 260 gc.TUINT8<<16 | gc.TINT8, 261 gc.TINT16<<16 | gc.TINT8, 262 gc.TUINT16<<16 | gc.TINT8, 263 gc.TINT32<<16 | gc.TINT8, 264 gc.TUINT32<<16 | gc.TINT8, 265 gc.TINT64<<16 | gc.TINT8, 266 gc.TUINT64<<16 | gc.TINT8: 267 a = s390x.AMOVB 268 269 case gc.TINT8<<16 | gc.TUINT8, 270 gc.TUINT8<<16 | gc.TUINT8, 271 gc.TINT16<<16 | gc.TUINT8, 272 gc.TUINT16<<16 | gc.TUINT8, 273 gc.TINT32<<16 | gc.TUINT8, 274 gc.TUINT32<<16 | gc.TUINT8, 275 gc.TINT64<<16 | gc.TUINT8, 276 gc.TUINT64<<16 | gc.TUINT8: 277 a = s390x.AMOVBZ 278 279 case gc.TINT16<<16 | gc.TINT16, 280 gc.TUINT16<<16 | gc.TINT16, 281 gc.TINT32<<16 | gc.TINT16, 282 gc.TUINT32<<16 | gc.TINT16, 283 gc.TINT64<<16 | gc.TINT16, 284 gc.TUINT64<<16 | gc.TINT16: 285 a = s390x.AMOVH 286 287 case gc.TINT16<<16 | gc.TUINT16, 288 gc.TUINT16<<16 | gc.TUINT16, 289 gc.TINT32<<16 | gc.TUINT16, 290 gc.TUINT32<<16 | gc.TUINT16, 291 gc.TINT64<<16 | gc.TUINT16, 292 gc.TUINT64<<16 | gc.TUINT16: 293 a = s390x.AMOVHZ 294 295 case gc.TINT32<<16 | gc.TINT32, 296 gc.TUINT32<<16 | gc.TINT32, 297 gc.TINT64<<16 | gc.TINT32, 298 gc.TUINT64<<16 | gc.TINT32: 299 a = s390x.AMOVW 300 301 case gc.TINT32<<16 | gc.TUINT32, 302 gc.TUINT32<<16 | gc.TUINT32, 303 gc.TINT64<<16 | gc.TUINT32, 304 gc.TUINT64<<16 | gc.TUINT32: 305 a = s390x.AMOVWZ 306 307 case gc.TINT64<<16 | gc.TINT64, 308 gc.TINT64<<16 | gc.TUINT64, 309 gc.TUINT64<<16 | gc.TINT64, 310 gc.TUINT64<<16 | gc.TUINT64: 311 a = s390x.AMOVD 312 313 // sign extend int8 314 case gc.TINT8<<16 | gc.TINT16, 315 gc.TINT8<<16 | gc.TUINT16, 316 gc.TINT8<<16 | gc.TINT32, 317 gc.TINT8<<16 | gc.TUINT32, 318 gc.TINT8<<16 | gc.TINT64, 319 gc.TINT8<<16 | gc.TUINT64: 320 a = s390x.AMOVB 321 goto rdst 322 323 // sign extend uint8 324 case gc.TUINT8<<16 | gc.TINT16, 325 gc.TUINT8<<16 | gc.TUINT16, 326 gc.TUINT8<<16 | gc.TINT32, 327 gc.TUINT8<<16 | gc.TUINT32, 328 gc.TUINT8<<16 | gc.TINT64, 329 gc.TUINT8<<16 | gc.TUINT64: 330 a = s390x.AMOVBZ 331 goto rdst 332 333 // sign extend int16 334 case gc.TINT16<<16 | gc.TINT32, 335 gc.TINT16<<16 | gc.TUINT32, 336 gc.TINT16<<16 | gc.TINT64, 337 gc.TINT16<<16 | gc.TUINT64: 338 a = s390x.AMOVH 339 goto rdst 340 341 // zero extend uint16 342 case gc.TUINT16<<16 | gc.TINT32, 343 gc.TUINT16<<16 | gc.TUINT32, 344 gc.TUINT16<<16 | gc.TINT64, 345 gc.TUINT16<<16 | gc.TUINT64: 346 a = s390x.AMOVHZ 347 goto rdst 348 349 // sign extend int32 350 case gc.TINT32<<16 | gc.TINT64, 351 gc.TINT32<<16 | gc.TUINT64: 352 a = s390x.AMOVW 353 goto rdst 354 355 // zero extend uint32 356 case gc.TUINT32<<16 | gc.TINT64, 357 gc.TUINT32<<16 | gc.TUINT64: 358 a = s390x.AMOVWZ 359 goto rdst 360 361 // float to integer 362 case gc.TFLOAT32<<16 | gc.TUINT8, 363 gc.TFLOAT32<<16 | gc.TUINT16: 364 cvt = gc.Types[gc.TUINT32] 365 goto hard 366 367 case gc.TFLOAT32<<16 | gc.TUINT32: 368 a = s390x.ACLFEBR 369 goto rdst 370 371 case gc.TFLOAT32<<16 | gc.TUINT64: 372 a = s390x.ACLGEBR 373 goto rdst 374 375 case gc.TFLOAT64<<16 | gc.TUINT8, 376 gc.TFLOAT64<<16 | gc.TUINT16: 377 cvt = gc.Types[gc.TUINT32] 378 goto hard 379 380 case gc.TFLOAT64<<16 | gc.TUINT32: 381 a = s390x.ACLFDBR 382 goto rdst 383 384 case gc.TFLOAT64<<16 | gc.TUINT64: 385 a = s390x.ACLGDBR 386 goto rdst 387 388 case gc.TFLOAT32<<16 | gc.TINT8, 389 gc.TFLOAT32<<16 | gc.TINT16: 390 cvt = gc.Types[gc.TINT32] 391 goto hard 392 393 case gc.TFLOAT32<<16 | gc.TINT32: 394 a = s390x.ACFEBRA 395 goto rdst 396 397 case gc.TFLOAT32<<16 | gc.TINT64: 398 a = s390x.ACGEBRA 399 goto rdst 400 401 case gc.TFLOAT64<<16 | gc.TINT8, 402 gc.TFLOAT64<<16 | gc.TINT16: 403 cvt = gc.Types[gc.TINT32] 404 goto hard 405 406 case gc.TFLOAT64<<16 | gc.TINT32: 407 a = s390x.ACFDBRA 408 goto rdst 409 410 case gc.TFLOAT64<<16 | gc.TINT64: 411 a = s390x.ACGDBRA 412 goto rdst 413 414 // integer to float 415 case gc.TUINT8<<16 | gc.TFLOAT32, 416 gc.TUINT16<<16 | gc.TFLOAT32: 417 cvt = gc.Types[gc.TUINT32] 418 goto hard 419 420 case gc.TUINT32<<16 | gc.TFLOAT32: 421 a = s390x.ACELFBR 422 goto rdst 423 424 case gc.TUINT64<<16 | gc.TFLOAT32: 425 a = s390x.ACELGBR 426 goto rdst 427 428 case gc.TUINT8<<16 | gc.TFLOAT64, 429 gc.TUINT16<<16 | gc.TFLOAT64: 430 cvt = gc.Types[gc.TUINT32] 431 goto hard 432 433 case gc.TUINT32<<16 | gc.TFLOAT64: 434 a = s390x.ACDLFBR 435 goto rdst 436 437 case gc.TUINT64<<16 | gc.TFLOAT64: 438 a = s390x.ACDLGBR 439 goto rdst 440 441 case gc.TINT8<<16 | gc.TFLOAT32, 442 gc.TINT16<<16 | gc.TFLOAT32: 443 cvt = gc.Types[gc.TINT32] 444 goto hard 445 446 case gc.TINT32<<16 | gc.TFLOAT32: 447 a = s390x.ACEFBRA 448 goto rdst 449 450 case gc.TINT64<<16 | gc.TFLOAT32: 451 a = s390x.ACEGBRA 452 goto rdst 453 454 case gc.TINT8<<16 | gc.TFLOAT64, 455 gc.TINT16<<16 | gc.TFLOAT64: 456 cvt = gc.Types[gc.TINT32] 457 goto hard 458 459 case gc.TINT32<<16 | gc.TFLOAT64: 460 a = s390x.ACDFBRA 461 goto rdst 462 463 case gc.TINT64<<16 | gc.TFLOAT64: 464 a = s390x.ACDGBRA 465 goto rdst 466 467 // float to float 468 case gc.TFLOAT32<<16 | gc.TFLOAT32: 469 a = s390x.AFMOVS 470 471 case gc.TFLOAT64<<16 | gc.TFLOAT64: 472 a = s390x.AFMOVD 473 474 case gc.TFLOAT32<<16 | gc.TFLOAT64: 475 a = s390x.ALDEBR 476 goto rdst 477 478 case gc.TFLOAT64<<16 | gc.TFLOAT32: 479 a = s390x.ALEDBR 480 goto rdst 481 } 482 483 gins(a, f, t) 484 return 485 486 // requires register destination 487 rdst: 488 if t != nil && t.Op == gc.OREGISTER { 489 gins(a, f, t) 490 return 491 } else { 492 var r1 gc.Node 493 gc.Regalloc(&r1, t.Type, t) 494 495 gins(a, f, &r1) 496 gmove(&r1, t) 497 gc.Regfree(&r1) 498 return 499 } 500 501 // requires register intermediate 502 hard: 503 var r1 gc.Node 504 gc.Regalloc(&r1, cvt, t) 505 506 gmove(f, &r1) 507 gmove(&r1, t) 508 gc.Regfree(&r1) 509 return 510 } 511 512 func intLiteral(n *gc.Node) (x int64, ok bool) { 513 switch { 514 case n == nil: 515 return 516 case gc.Isconst(n, gc.CTINT): 517 return n.Int64(), true 518 case gc.Isconst(n, gc.CTBOOL): 519 return int64(obj.Bool2int(n.Bool())), true 520 } 521 return 522 } 523 524 // gins is called by the front end. 525 // It synthesizes some multiple-instruction sequences 526 // so the front end can stay simpler. 527 func gins(as obj.As, f, t *gc.Node) *obj.Prog { 528 if t != nil { 529 if as >= obj.A_ARCHSPECIFIC { 530 if x, ok := intLiteral(f); ok { 531 ginscon(as, x, t) 532 return nil // caller must not use 533 } 534 } 535 if as == s390x.ACMP || as == s390x.ACMPU { 536 if x, ok := intLiteral(t); ok { 537 ginscon2(as, f, x) 538 return nil // caller must not use 539 } 540 } 541 } 542 return rawgins(as, f, t) 543 } 544 545 // generate one instruction: 546 // as f, t 547 func rawgins(as obj.As, f *gc.Node, t *gc.Node) *obj.Prog { 548 // self move check 549 // TODO(mundaym): use sized math and extend to MOVB, MOVWZ etc. 550 switch as { 551 case s390x.AMOVD, s390x.AFMOVS, s390x.AFMOVD: 552 if f != nil && t != nil && 553 f.Op == gc.OREGISTER && t.Op == gc.OREGISTER && 554 f.Reg == t.Reg { 555 return nil 556 } 557 } 558 559 p := gc.Prog(as) 560 gc.Naddr(&p.From, f) 561 gc.Naddr(&p.To, t) 562 563 switch as { 564 // Bad things the front end has done to us. Crash to find call stack. 565 case s390x.ACMP, s390x.ACMPU: 566 if p.From.Type == obj.TYPE_MEM || p.To.Type == obj.TYPE_MEM { 567 gc.Debug['h'] = 1 568 gc.Fatalf("bad inst: %v", p) 569 } 570 } 571 572 if gc.Debug['g'] != 0 { 573 fmt.Printf("%v\n", p) 574 } 575 576 w := int32(0) 577 switch as { 578 case s390x.AMOVB, s390x.AMOVBZ: 579 w = 1 580 581 case s390x.AMOVH, s390x.AMOVHZ: 582 w = 2 583 584 case s390x.AMOVW, s390x.AMOVWZ: 585 w = 4 586 587 case s390x.AMOVD: 588 if p.From.Type == obj.TYPE_CONST || p.From.Type == obj.TYPE_ADDR { 589 break 590 } 591 w = 8 592 } 593 594 if w != 0 && ((f != nil && p.From.Width < int64(w)) || (t != nil && p.To.Type != obj.TYPE_REG && p.To.Width > int64(w))) { 595 gc.Dump("f", f) 596 gc.Dump("t", t) 597 gc.Fatalf("bad width: %v (%d, %d)\n", p, p.From.Width, p.To.Width) 598 } 599 600 return p 601 } 602 603 // optoas returns the Axxx equivalent of Oxxx for type t 604 func optoas(op gc.Op, t *gc.Type) obj.As { 605 if t == nil { 606 gc.Fatalf("optoas: t is nil") 607 } 608 609 // avoid constant conversions in switches below 610 const ( 611 OMINUS_ = uint32(gc.OMINUS) << 16 612 OLSH_ = uint32(gc.OLSH) << 16 613 ORSH_ = uint32(gc.ORSH) << 16 614 OADD_ = uint32(gc.OADD) << 16 615 OSUB_ = uint32(gc.OSUB) << 16 616 OMUL_ = uint32(gc.OMUL) << 16 617 ODIV_ = uint32(gc.ODIV) << 16 618 OOR_ = uint32(gc.OOR) << 16 619 OAND_ = uint32(gc.OAND) << 16 620 OXOR_ = uint32(gc.OXOR) << 16 621 OEQ_ = uint32(gc.OEQ) << 16 622 ONE_ = uint32(gc.ONE) << 16 623 OLT_ = uint32(gc.OLT) << 16 624 OLE_ = uint32(gc.OLE) << 16 625 OGE_ = uint32(gc.OGE) << 16 626 OGT_ = uint32(gc.OGT) << 16 627 OCMP_ = uint32(gc.OCMP) << 16 628 OAS_ = uint32(gc.OAS) << 16 629 OHMUL_ = uint32(gc.OHMUL) << 16 630 OSQRT_ = uint32(gc.OSQRT) << 16 631 OLROT_ = uint32(gc.OLROT) << 16 632 ) 633 634 a := obj.AXXX 635 switch uint32(op)<<16 | uint32(gc.Simtype[t.Etype]) { 636 default: 637 gc.Fatalf("optoas: no entry for op=%v type=%v", op, t) 638 639 case OEQ_ | gc.TBOOL, 640 OEQ_ | gc.TINT8, 641 OEQ_ | gc.TUINT8, 642 OEQ_ | gc.TINT16, 643 OEQ_ | gc.TUINT16, 644 OEQ_ | gc.TINT32, 645 OEQ_ | gc.TUINT32, 646 OEQ_ | gc.TINT64, 647 OEQ_ | gc.TUINT64, 648 OEQ_ | gc.TPTR32, 649 OEQ_ | gc.TPTR64, 650 OEQ_ | gc.TFLOAT32, 651 OEQ_ | gc.TFLOAT64: 652 a = s390x.ABEQ 653 654 case ONE_ | gc.TBOOL, 655 ONE_ | gc.TINT8, 656 ONE_ | gc.TUINT8, 657 ONE_ | gc.TINT16, 658 ONE_ | gc.TUINT16, 659 ONE_ | gc.TINT32, 660 ONE_ | gc.TUINT32, 661 ONE_ | gc.TINT64, 662 ONE_ | gc.TUINT64, 663 ONE_ | gc.TPTR32, 664 ONE_ | gc.TPTR64, 665 ONE_ | gc.TFLOAT32, 666 ONE_ | gc.TFLOAT64: 667 a = s390x.ABNE 668 669 case OLT_ | gc.TINT8, // ACMP 670 OLT_ | gc.TINT16, 671 OLT_ | gc.TINT32, 672 OLT_ | gc.TINT64, 673 OLT_ | gc.TUINT8, 674 // ACMPU 675 OLT_ | gc.TUINT16, 676 OLT_ | gc.TUINT32, 677 OLT_ | gc.TUINT64, 678 OLT_ | gc.TFLOAT32, 679 // AFCMPU 680 OLT_ | gc.TFLOAT64: 681 a = s390x.ABLT 682 683 case OLE_ | gc.TINT8, // ACMP 684 OLE_ | gc.TINT16, 685 OLE_ | gc.TINT32, 686 OLE_ | gc.TINT64, 687 OLE_ | gc.TUINT8, 688 // ACMPU 689 OLE_ | gc.TUINT16, 690 OLE_ | gc.TUINT32, 691 OLE_ | gc.TUINT64, 692 OLE_ | gc.TFLOAT32, 693 OLE_ | gc.TFLOAT64: 694 a = s390x.ABLE 695 696 case OGT_ | gc.TINT8, 697 OGT_ | gc.TINT16, 698 OGT_ | gc.TINT32, 699 OGT_ | gc.TINT64, 700 OGT_ | gc.TUINT8, 701 OGT_ | gc.TUINT16, 702 OGT_ | gc.TUINT32, 703 OGT_ | gc.TUINT64, 704 OGT_ | gc.TFLOAT32, 705 OGT_ | gc.TFLOAT64: 706 a = s390x.ABGT 707 708 case OGE_ | gc.TINT8, 709 OGE_ | gc.TINT16, 710 OGE_ | gc.TINT32, 711 OGE_ | gc.TINT64, 712 OGE_ | gc.TUINT8, 713 OGE_ | gc.TUINT16, 714 OGE_ | gc.TUINT32, 715 OGE_ | gc.TUINT64, 716 OGE_ | gc.TFLOAT32, 717 OGE_ | gc.TFLOAT64: 718 a = s390x.ABGE 719 720 case OCMP_ | gc.TBOOL, 721 OCMP_ | gc.TINT8, 722 OCMP_ | gc.TINT16, 723 OCMP_ | gc.TINT32, 724 OCMP_ | gc.TPTR32, 725 OCMP_ | gc.TINT64: 726 a = s390x.ACMP 727 728 case OCMP_ | gc.TUINT8, 729 OCMP_ | gc.TUINT16, 730 OCMP_ | gc.TUINT32, 731 OCMP_ | gc.TUINT64, 732 OCMP_ | gc.TPTR64: 733 a = s390x.ACMPU 734 735 case OCMP_ | gc.TFLOAT32: 736 a = s390x.ACEBR 737 738 case OCMP_ | gc.TFLOAT64: 739 a = s390x.AFCMPU 740 741 case OAS_ | gc.TBOOL, 742 OAS_ | gc.TINT8: 743 a = s390x.AMOVB 744 745 case OAS_ | gc.TUINT8: 746 a = s390x.AMOVBZ 747 748 case OAS_ | gc.TINT16: 749 a = s390x.AMOVH 750 751 case OAS_ | gc.TUINT16: 752 a = s390x.AMOVHZ 753 754 case OAS_ | gc.TINT32: 755 a = s390x.AMOVW 756 757 case OAS_ | gc.TUINT32, 758 OAS_ | gc.TPTR32: 759 a = s390x.AMOVWZ 760 761 case OAS_ | gc.TINT64, 762 OAS_ | gc.TUINT64, 763 OAS_ | gc.TPTR64: 764 a = s390x.AMOVD 765 766 case OAS_ | gc.TFLOAT32: 767 a = s390x.AFMOVS 768 769 case OAS_ | gc.TFLOAT64: 770 a = s390x.AFMOVD 771 772 case OADD_ | gc.TINT8, 773 OADD_ | gc.TUINT8, 774 OADD_ | gc.TINT16, 775 OADD_ | gc.TUINT16, 776 OADD_ | gc.TINT32, 777 OADD_ | gc.TUINT32, 778 OADD_ | gc.TPTR32, 779 OADD_ | gc.TINT64, 780 OADD_ | gc.TUINT64, 781 OADD_ | gc.TPTR64: 782 a = s390x.AADD 783 784 case OADD_ | gc.TFLOAT32: 785 a = s390x.AFADDS 786 787 case OADD_ | gc.TFLOAT64: 788 a = s390x.AFADD 789 790 case OSUB_ | gc.TINT8, 791 OSUB_ | gc.TUINT8, 792 OSUB_ | gc.TINT16, 793 OSUB_ | gc.TUINT16, 794 OSUB_ | gc.TINT32, 795 OSUB_ | gc.TUINT32, 796 OSUB_ | gc.TPTR32, 797 OSUB_ | gc.TINT64, 798 OSUB_ | gc.TUINT64, 799 OSUB_ | gc.TPTR64: 800 a = s390x.ASUB 801 802 case OSUB_ | gc.TFLOAT32: 803 a = s390x.AFSUBS 804 805 case OSUB_ | gc.TFLOAT64: 806 a = s390x.AFSUB 807 808 case OMINUS_ | gc.TINT8, 809 OMINUS_ | gc.TUINT8, 810 OMINUS_ | gc.TINT16, 811 OMINUS_ | gc.TUINT16, 812 OMINUS_ | gc.TINT32, 813 OMINUS_ | gc.TUINT32, 814 OMINUS_ | gc.TPTR32, 815 OMINUS_ | gc.TINT64, 816 OMINUS_ | gc.TUINT64, 817 OMINUS_ | gc.TPTR64: 818 a = s390x.ANEG 819 820 case OAND_ | gc.TINT8, 821 OAND_ | gc.TUINT8, 822 OAND_ | gc.TINT16, 823 OAND_ | gc.TUINT16, 824 OAND_ | gc.TINT32, 825 OAND_ | gc.TUINT32, 826 OAND_ | gc.TPTR32, 827 OAND_ | gc.TINT64, 828 OAND_ | gc.TUINT64, 829 OAND_ | gc.TPTR64: 830 a = s390x.AAND 831 832 case OOR_ | gc.TINT8, 833 OOR_ | gc.TUINT8, 834 OOR_ | gc.TINT16, 835 OOR_ | gc.TUINT16, 836 OOR_ | gc.TINT32, 837 OOR_ | gc.TUINT32, 838 OOR_ | gc.TPTR32, 839 OOR_ | gc.TINT64, 840 OOR_ | gc.TUINT64, 841 OOR_ | gc.TPTR64: 842 a = s390x.AOR 843 844 case OXOR_ | gc.TINT8, 845 OXOR_ | gc.TUINT8, 846 OXOR_ | gc.TINT16, 847 OXOR_ | gc.TUINT16, 848 OXOR_ | gc.TINT32, 849 OXOR_ | gc.TUINT32, 850 OXOR_ | gc.TPTR32, 851 OXOR_ | gc.TINT64, 852 OXOR_ | gc.TUINT64, 853 OXOR_ | gc.TPTR64: 854 a = s390x.AXOR 855 856 case OLSH_ | gc.TINT8, 857 OLSH_ | gc.TUINT8, 858 OLSH_ | gc.TINT16, 859 OLSH_ | gc.TUINT16, 860 OLSH_ | gc.TINT32, 861 OLSH_ | gc.TUINT32, 862 OLSH_ | gc.TPTR32, 863 OLSH_ | gc.TINT64, 864 OLSH_ | gc.TUINT64, 865 OLSH_ | gc.TPTR64: 866 a = s390x.ASLD 867 868 case ORSH_ | gc.TUINT8, 869 ORSH_ | gc.TUINT16, 870 ORSH_ | gc.TUINT32, 871 ORSH_ | gc.TPTR32, 872 ORSH_ | gc.TUINT64, 873 ORSH_ | gc.TPTR64: 874 a = s390x.ASRD 875 876 case ORSH_ | gc.TINT8, 877 ORSH_ | gc.TINT16, 878 ORSH_ | gc.TINT32, 879 ORSH_ | gc.TINT64: 880 a = s390x.ASRAD 881 882 case OHMUL_ | gc.TINT64: 883 a = s390x.AMULHD 884 885 case OHMUL_ | gc.TUINT64, 886 OHMUL_ | gc.TPTR64: 887 a = s390x.AMULHDU 888 889 case OMUL_ | gc.TINT8, 890 OMUL_ | gc.TINT16, 891 OMUL_ | gc.TINT32, 892 OMUL_ | gc.TINT64: 893 a = s390x.AMULLD 894 895 case OMUL_ | gc.TUINT8, 896 OMUL_ | gc.TUINT16, 897 OMUL_ | gc.TUINT32, 898 OMUL_ | gc.TPTR32, 899 // don't use word multiply, the high 32-bit are undefined. 900 OMUL_ | gc.TUINT64, 901 OMUL_ | gc.TPTR64: 902 // for 64-bit multiplies, signedness doesn't matter. 903 a = s390x.AMULLD 904 905 case OMUL_ | gc.TFLOAT32: 906 a = s390x.AFMULS 907 908 case OMUL_ | gc.TFLOAT64: 909 a = s390x.AFMUL 910 911 case ODIV_ | gc.TINT8, 912 ODIV_ | gc.TINT16, 913 ODIV_ | gc.TINT32, 914 ODIV_ | gc.TINT64: 915 a = s390x.ADIVD 916 917 case ODIV_ | gc.TUINT8, 918 ODIV_ | gc.TUINT16, 919 ODIV_ | gc.TUINT32, 920 ODIV_ | gc.TPTR32, 921 ODIV_ | gc.TUINT64, 922 ODIV_ | gc.TPTR64: 923 a = s390x.ADIVDU 924 925 case ODIV_ | gc.TFLOAT32: 926 a = s390x.AFDIVS 927 928 case ODIV_ | gc.TFLOAT64: 929 a = s390x.AFDIV 930 931 case OSQRT_ | gc.TFLOAT64: 932 a = s390x.AFSQRT 933 934 case OLROT_ | gc.TUINT32, 935 OLROT_ | gc.TPTR32, 936 OLROT_ | gc.TINT32: 937 a = s390x.ARLL 938 939 case OLROT_ | gc.TUINT64, 940 OLROT_ | gc.TPTR64, 941 OLROT_ | gc.TINT64: 942 a = s390x.ARLLG 943 } 944 945 return a 946 } 947 948 const ( 949 ODynam = 1 << 0 950 OAddable = 1 << 1 951 ) 952 953 var clean [20]gc.Node 954 955 var cleani int = 0 956 957 func sudoclean() { 958 if clean[cleani-1].Op != gc.OEMPTY { 959 gc.Regfree(&clean[cleani-1]) 960 } 961 if clean[cleani-2].Op != gc.OEMPTY { 962 gc.Regfree(&clean[cleani-2]) 963 } 964 cleani -= 2 965 } 966 967 /* 968 * generate code to compute address of n, 969 * a reference to a (perhaps nested) field inside 970 * an array or struct. 971 * return 0 on failure, 1 on success. 972 * on success, leaves usable address in a. 973 * 974 * caller is responsible for calling sudoclean 975 * after successful sudoaddable, 976 * to release the register used for a. 977 */ 978 func sudoaddable(as obj.As, n *gc.Node, a *obj.Addr) bool { 979 if n.Type == nil { 980 return false 981 } 982 983 *a = obj.Addr{} 984 985 switch n.Op { 986 case gc.OLITERAL: 987 if !gc.Isconst(n, gc.CTINT) { 988 return false 989 } 990 v := n.Int64() 991 switch as { 992 default: 993 return false 994 995 // operations that can cope with a 32-bit immediate 996 // TODO(mundaym): logical operations can work on high bits 997 case s390x.AADD, 998 s390x.AADDC, 999 s390x.ASUB, 1000 s390x.AMULLW, 1001 s390x.AAND, 1002 s390x.AOR, 1003 s390x.AXOR, 1004 s390x.ASLD, 1005 s390x.ASLW, 1006 s390x.ASRAW, 1007 s390x.ASRAD, 1008 s390x.ASRW, 1009 s390x.ASRD, 1010 s390x.AMOVB, 1011 s390x.AMOVBZ, 1012 s390x.AMOVH, 1013 s390x.AMOVHZ, 1014 s390x.AMOVW, 1015 s390x.AMOVWZ, 1016 s390x.AMOVD: 1017 if int64(int32(v)) != v { 1018 return false 1019 } 1020 1021 // for comparisons avoid immediates unless they can 1022 // fit into a int8/uint8 1023 // this favours combined compare and branch instructions 1024 case s390x.ACMP: 1025 if int64(int8(v)) != v { 1026 return false 1027 } 1028 case s390x.ACMPU: 1029 if int64(uint8(v)) != v { 1030 return false 1031 } 1032 } 1033 1034 cleani += 2 1035 reg := &clean[cleani-1] 1036 reg1 := &clean[cleani-2] 1037 reg.Op = gc.OEMPTY 1038 reg1.Op = gc.OEMPTY 1039 gc.Naddr(a, n) 1040 return true 1041 1042 case gc.ODOT, 1043 gc.ODOTPTR: 1044 cleani += 2 1045 reg := &clean[cleani-1] 1046 reg1 := &clean[cleani-2] 1047 reg.Op = gc.OEMPTY 1048 reg1.Op = gc.OEMPTY 1049 var nn *gc.Node 1050 var oary [10]int64 1051 o := gc.Dotoffset(n, oary[:], &nn) 1052 if nn == nil { 1053 sudoclean() 1054 return false 1055 } 1056 1057 if nn.Addable && o == 1 && oary[0] >= 0 { 1058 // directly addressable set of DOTs 1059 n1 := *nn 1060 1061 n1.Type = n.Type 1062 n1.Xoffset += oary[0] 1063 // check that the offset fits into a 12-bit displacement 1064 if n1.Xoffset < 0 || n1.Xoffset >= (1<<12)-8 { 1065 sudoclean() 1066 return false 1067 } 1068 gc.Naddr(a, &n1) 1069 return true 1070 } 1071 1072 gc.Regalloc(reg, gc.Types[gc.Tptr], nil) 1073 n1 := *reg 1074 n1.Op = gc.OINDREG 1075 if oary[0] >= 0 { 1076 gc.Agen(nn, reg) 1077 n1.Xoffset = oary[0] 1078 } else { 1079 gc.Cgen(nn, reg) 1080 gc.Cgen_checknil(reg) 1081 n1.Xoffset = -(oary[0] + 1) 1082 } 1083 1084 for i := 1; i < o; i++ { 1085 if oary[i] >= 0 { 1086 gc.Fatalf("can't happen") 1087 } 1088 gins(s390x.AMOVD, &n1, reg) 1089 gc.Cgen_checknil(reg) 1090 n1.Xoffset = -(oary[i] + 1) 1091 } 1092 1093 a.Type = obj.TYPE_NONE 1094 a.Index = 0 1095 // check that the offset fits into a 12-bit displacement 1096 if n1.Xoffset < 0 || n1.Xoffset >= (1<<12)-8 { 1097 tmp := n1 1098 tmp.Op = gc.OREGISTER 1099 tmp.Type = gc.Types[gc.Tptr] 1100 tmp.Xoffset = 0 1101 gc.Cgen_checknil(&tmp) 1102 ginscon(s390x.AADD, n1.Xoffset, &tmp) 1103 n1.Xoffset = 0 1104 } 1105 gc.Naddr(a, &n1) 1106 return true 1107 } 1108 1109 return false 1110 }