github.com/slayercat/go@v0.0.0-20170428012452-c51559813f61/src/cmd/compile/internal/ppc64/ssa.go (about) 1 // Copyright 2016 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 ppc64 6 7 import ( 8 "cmd/compile/internal/gc" 9 "cmd/compile/internal/ssa" 10 "cmd/internal/obj" 11 "cmd/internal/obj/ppc64" 12 "math" 13 ) 14 15 // iselOp encodes mapping of comparison operations onto ISEL operands 16 type iselOp struct { 17 cond int64 18 valueIfCond int // if cond is true, the value to return (0 or 1) 19 } 20 21 // Input registers to ISEL used for comparison. Index 0 is zero, 1 is (will be) 1 22 var iselRegs = [2]int16{ppc64.REG_R0, ppc64.REGTMP} 23 24 var iselOps = map[ssa.Op]iselOp{ 25 ssa.OpPPC64Equal: iselOp{cond: ppc64.C_COND_EQ, valueIfCond: 1}, 26 ssa.OpPPC64NotEqual: iselOp{cond: ppc64.C_COND_EQ, valueIfCond: 0}, 27 ssa.OpPPC64LessThan: iselOp{cond: ppc64.C_COND_LT, valueIfCond: 1}, 28 ssa.OpPPC64GreaterEqual: iselOp{cond: ppc64.C_COND_LT, valueIfCond: 0}, 29 ssa.OpPPC64GreaterThan: iselOp{cond: ppc64.C_COND_GT, valueIfCond: 1}, 30 ssa.OpPPC64LessEqual: iselOp{cond: ppc64.C_COND_GT, valueIfCond: 0}, 31 ssa.OpPPC64FLessThan: iselOp{cond: ppc64.C_COND_LT, valueIfCond: 1}, 32 ssa.OpPPC64FGreaterThan: iselOp{cond: ppc64.C_COND_GT, valueIfCond: 1}, 33 ssa.OpPPC64FLessEqual: iselOp{cond: ppc64.C_COND_LT, valueIfCond: 1}, // 2 comparisons, 2nd is EQ 34 ssa.OpPPC64FGreaterEqual: iselOp{cond: ppc64.C_COND_GT, valueIfCond: 1}, // 2 comparisons, 2nd is EQ 35 } 36 37 // markMoves marks any MOVXconst ops that need to avoid clobbering flags. 38 func ssaMarkMoves(s *gc.SSAGenState, b *ssa.Block) { 39 // flive := b.FlagsLiveAtEnd 40 // if b.Control != nil && b.Control.Type.IsFlags() { 41 // flive = true 42 // } 43 // for i := len(b.Values) - 1; i >= 0; i-- { 44 // v := b.Values[i] 45 // if flive && (v.Op == v.Op == ssa.OpPPC64MOVDconst) { 46 // // The "mark" is any non-nil Aux value. 47 // v.Aux = v 48 // } 49 // if v.Type.IsFlags() { 50 // flive = false 51 // } 52 // for _, a := range v.Args { 53 // if a.Type.IsFlags() { 54 // flive = true 55 // } 56 // } 57 // } 58 } 59 60 // loadByType returns the load instruction of the given type. 61 func loadByType(t ssa.Type) obj.As { 62 if t.IsFloat() { 63 switch t.Size() { 64 case 4: 65 return ppc64.AFMOVS 66 case 8: 67 return ppc64.AFMOVD 68 } 69 } else { 70 switch t.Size() { 71 case 1: 72 if t.IsSigned() { 73 return ppc64.AMOVB 74 } else { 75 return ppc64.AMOVBZ 76 } 77 case 2: 78 if t.IsSigned() { 79 return ppc64.AMOVH 80 } else { 81 return ppc64.AMOVHZ 82 } 83 case 4: 84 if t.IsSigned() { 85 return ppc64.AMOVW 86 } else { 87 return ppc64.AMOVWZ 88 } 89 case 8: 90 return ppc64.AMOVD 91 } 92 } 93 panic("bad load type") 94 } 95 96 // storeByType returns the store instruction of the given type. 97 func storeByType(t ssa.Type) obj.As { 98 if t.IsFloat() { 99 switch t.Size() { 100 case 4: 101 return ppc64.AFMOVS 102 case 8: 103 return ppc64.AFMOVD 104 } 105 } else { 106 switch t.Size() { 107 case 1: 108 return ppc64.AMOVB 109 case 2: 110 return ppc64.AMOVH 111 case 4: 112 return ppc64.AMOVW 113 case 8: 114 return ppc64.AMOVD 115 } 116 } 117 panic("bad store type") 118 } 119 120 func ssaGenISEL(s *gc.SSAGenState, v *ssa.Value, cr int64, r1, r2 int16) { 121 r := v.Reg() 122 p := s.Prog(ppc64.AISEL) 123 p.To.Type = obj.TYPE_REG 124 p.To.Reg = r 125 p.Reg = r1 126 p.From3 = &obj.Addr{Type: obj.TYPE_REG, Reg: r2} 127 p.From.Type = obj.TYPE_CONST 128 p.From.Offset = cr 129 } 130 131 func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) { 132 switch v.Op { 133 case ssa.OpCopy, ssa.OpPPC64MOVDconvert: 134 t := v.Type 135 if t.IsMemory() { 136 return 137 } 138 x := v.Args[0].Reg() 139 y := v.Reg() 140 if x != y { 141 rt := obj.TYPE_REG 142 op := ppc64.AMOVD 143 144 if t.IsFloat() { 145 op = ppc64.AFMOVD 146 } 147 p := s.Prog(op) 148 p.From.Type = rt 149 p.From.Reg = x 150 p.To.Type = rt 151 p.To.Reg = y 152 } 153 154 case ssa.OpPPC64Xf2i64: 155 { 156 x := v.Args[0].Reg() 157 y := v.Reg() 158 159 p := s.Prog(ppc64.AMFVSRD) 160 p.From.Type = obj.TYPE_REG 161 p.From.Reg = x 162 p.To.Type = obj.TYPE_REG 163 p.To.Reg = y 164 } 165 case ssa.OpPPC64Xi2f64: 166 { 167 x := v.Args[0].Reg() 168 y := v.Reg() 169 170 p := s.Prog(ppc64.AMTVSRD) 171 p.From.Type = obj.TYPE_REG 172 p.From.Reg = x 173 p.To.Type = obj.TYPE_REG 174 p.To.Reg = y 175 } 176 177 case ssa.OpPPC64LoweredAtomicAnd8, 178 ssa.OpPPC64LoweredAtomicOr8: 179 // SYNC 180 // LBAR (Rarg0), Rtmp 181 // AND/OR Rarg1, Rtmp 182 // STBCCC Rtmp, (Rarg0) 183 // BNE -3(PC) 184 // ISYNC 185 r0 := v.Args[0].Reg() 186 r1 := v.Args[1].Reg() 187 psync := s.Prog(ppc64.ASYNC) 188 psync.To.Type = obj.TYPE_NONE 189 p := s.Prog(ppc64.ALBAR) 190 p.From.Type = obj.TYPE_MEM 191 p.From.Reg = r0 192 p.To.Type = obj.TYPE_REG 193 p.To.Reg = ppc64.REGTMP 194 p1 := s.Prog(v.Op.Asm()) 195 p1.From.Type = obj.TYPE_REG 196 p1.From.Reg = r1 197 p1.To.Type = obj.TYPE_REG 198 p1.To.Reg = ppc64.REGTMP 199 p2 := s.Prog(ppc64.ASTBCCC) 200 p2.From.Type = obj.TYPE_REG 201 p2.From.Reg = ppc64.REGTMP 202 p2.To.Type = obj.TYPE_MEM 203 p2.To.Reg = r0 204 p2.RegTo2 = ppc64.REGTMP 205 p3 := s.Prog(ppc64.ABNE) 206 p3.To.Type = obj.TYPE_BRANCH 207 gc.Patch(p3, p) 208 pisync := s.Prog(ppc64.AISYNC) 209 pisync.To.Type = obj.TYPE_NONE 210 211 case ssa.OpPPC64LoweredAtomicAdd32, 212 ssa.OpPPC64LoweredAtomicAdd64: 213 // SYNC 214 // LDAR/LWAR (Rarg0), Rout 215 // ADD Rarg1, Rout 216 // STDCCC/STWCCC Rout, (Rarg0) 217 // BNE -3(PC) 218 // ISYNC 219 // MOVW Rout,Rout (if Add32) 220 ld := ppc64.ALDAR 221 st := ppc64.ASTDCCC 222 if v.Op == ssa.OpPPC64LoweredAtomicAdd32 { 223 ld = ppc64.ALWAR 224 st = ppc64.ASTWCCC 225 } 226 r0 := v.Args[0].Reg() 227 r1 := v.Args[1].Reg() 228 out := v.Reg0() 229 // SYNC 230 psync := s.Prog(ppc64.ASYNC) 231 psync.To.Type = obj.TYPE_NONE 232 // LDAR or LWAR 233 p := s.Prog(ld) 234 p.From.Type = obj.TYPE_MEM 235 p.From.Reg = r0 236 p.To.Type = obj.TYPE_REG 237 p.To.Reg = out 238 // ADD reg1,out 239 p1 := s.Prog(ppc64.AADD) 240 p1.From.Type = obj.TYPE_REG 241 p1.From.Reg = r1 242 p1.To.Reg = out 243 p1.To.Type = obj.TYPE_REG 244 // STDCCC or STWCCC 245 p3 := s.Prog(st) 246 p3.From.Type = obj.TYPE_REG 247 p3.From.Reg = out 248 p3.To.Type = obj.TYPE_MEM 249 p3.To.Reg = r0 250 // BNE retry 251 p4 := s.Prog(ppc64.ABNE) 252 p4.To.Type = obj.TYPE_BRANCH 253 gc.Patch(p4, p) 254 // ISYNC 255 pisync := s.Prog(ppc64.AISYNC) 256 pisync.To.Type = obj.TYPE_NONE 257 258 // Ensure a 32 bit result 259 if v.Op == ssa.OpPPC64LoweredAtomicAdd32 { 260 p5 := s.Prog(ppc64.AMOVWZ) 261 p5.To.Type = obj.TYPE_REG 262 p5.To.Reg = out 263 p5.From.Type = obj.TYPE_REG 264 p5.From.Reg = out 265 } 266 267 case ssa.OpPPC64LoweredAtomicExchange32, 268 ssa.OpPPC64LoweredAtomicExchange64: 269 // SYNC 270 // LDAR/LWAR (Rarg0), Rout 271 // STDCCC/STWCCC Rout, (Rarg0) 272 // BNE -2(PC) 273 // ISYNC 274 ld := ppc64.ALDAR 275 st := ppc64.ASTDCCC 276 if v.Op == ssa.OpPPC64LoweredAtomicExchange32 { 277 ld = ppc64.ALWAR 278 st = ppc64.ASTWCCC 279 } 280 r0 := v.Args[0].Reg() 281 r1 := v.Args[1].Reg() 282 out := v.Reg0() 283 // SYNC 284 psync := s.Prog(ppc64.ASYNC) 285 psync.To.Type = obj.TYPE_NONE 286 // LDAR or LWAR 287 p := s.Prog(ld) 288 p.From.Type = obj.TYPE_MEM 289 p.From.Reg = r0 290 p.To.Type = obj.TYPE_REG 291 p.To.Reg = out 292 // STDCCC or STWCCC 293 p1 := s.Prog(st) 294 p1.From.Type = obj.TYPE_REG 295 p1.From.Reg = r1 296 p1.To.Type = obj.TYPE_MEM 297 p1.To.Reg = r0 298 // BNE retry 299 p2 := s.Prog(ppc64.ABNE) 300 p2.To.Type = obj.TYPE_BRANCH 301 gc.Patch(p2, p) 302 // ISYNC 303 pisync := s.Prog(ppc64.AISYNC) 304 pisync.To.Type = obj.TYPE_NONE 305 306 case ssa.OpPPC64LoweredAtomicLoad32, 307 ssa.OpPPC64LoweredAtomicLoad64, 308 ssa.OpPPC64LoweredAtomicLoadPtr: 309 // SYNC 310 // MOVD/MOVW (Rarg0), Rout 311 // CMP Rout,Rout 312 // BNE 1(PC) 313 // ISYNC 314 ld := ppc64.AMOVD 315 cmp := ppc64.ACMP 316 if v.Op == ssa.OpPPC64LoweredAtomicLoad32 { 317 ld = ppc64.AMOVW 318 cmp = ppc64.ACMPW 319 } 320 arg0 := v.Args[0].Reg() 321 out := v.Reg0() 322 // SYNC 323 psync := s.Prog(ppc64.ASYNC) 324 psync.To.Type = obj.TYPE_NONE 325 // Load 326 p := s.Prog(ld) 327 p.From.Type = obj.TYPE_MEM 328 p.From.Reg = arg0 329 p.To.Type = obj.TYPE_REG 330 p.To.Reg = out 331 // CMP 332 p1 := s.Prog(cmp) 333 p1.From.Type = obj.TYPE_REG 334 p1.From.Reg = out 335 p1.To.Type = obj.TYPE_REG 336 p1.To.Reg = out 337 // BNE 338 p2 := s.Prog(ppc64.ABNE) 339 p2.To.Type = obj.TYPE_BRANCH 340 // ISYNC 341 pisync := s.Prog(ppc64.AISYNC) 342 pisync.To.Type = obj.TYPE_NONE 343 gc.Patch(p2, pisync) 344 345 case ssa.OpPPC64LoweredAtomicStore32, 346 ssa.OpPPC64LoweredAtomicStore64: 347 // SYNC 348 // MOVD/MOVW arg1,(arg0) 349 st := ppc64.AMOVD 350 if v.Op == ssa.OpPPC64LoweredAtomicStore32 { 351 st = ppc64.AMOVW 352 } 353 arg0 := v.Args[0].Reg() 354 arg1 := v.Args[1].Reg() 355 // SYNC 356 psync := s.Prog(ppc64.ASYNC) 357 psync.To.Type = obj.TYPE_NONE 358 // Store 359 p := s.Prog(st) 360 p.To.Type = obj.TYPE_MEM 361 p.To.Reg = arg0 362 p.From.Type = obj.TYPE_REG 363 p.From.Reg = arg1 364 365 case ssa.OpPPC64LoweredAtomicCas64, 366 ssa.OpPPC64LoweredAtomicCas32: 367 // SYNC 368 // loop: 369 // LDAR (Rarg0), Rtmp 370 // CMP Rarg1, Rtmp 371 // BNE fail 372 // STDCCC Rarg2, (Rarg0) 373 // BNE loop 374 // ISYNC 375 // MOVD $1, Rout 376 // BR end 377 // fail: 378 // MOVD $0, Rout 379 // end: 380 ld := ppc64.ALDAR 381 st := ppc64.ASTDCCC 382 cmp := ppc64.ACMP 383 if v.Op == ssa.OpPPC64LoweredAtomicCas32 { 384 ld = ppc64.ALWAR 385 st = ppc64.ASTWCCC 386 cmp = ppc64.ACMPW 387 } 388 r0 := v.Args[0].Reg() 389 r1 := v.Args[1].Reg() 390 r2 := v.Args[2].Reg() 391 out := v.Reg0() 392 // SYNC 393 psync := s.Prog(ppc64.ASYNC) 394 psync.To.Type = obj.TYPE_NONE 395 // LDAR or LWAR 396 p := s.Prog(ld) 397 p.From.Type = obj.TYPE_MEM 398 p.From.Reg = r0 399 p.To.Type = obj.TYPE_REG 400 p.To.Reg = ppc64.REGTMP 401 // CMP reg1,reg2 402 p1 := s.Prog(cmp) 403 p1.From.Type = obj.TYPE_REG 404 p1.From.Reg = r1 405 p1.To.Reg = ppc64.REGTMP 406 p1.To.Type = obj.TYPE_REG 407 // BNE cas_fail 408 p2 := s.Prog(ppc64.ABNE) 409 p2.To.Type = obj.TYPE_BRANCH 410 // STDCCC or STWCCC 411 p3 := s.Prog(st) 412 p3.From.Type = obj.TYPE_REG 413 p3.From.Reg = r2 414 p3.To.Type = obj.TYPE_MEM 415 p3.To.Reg = r0 416 // BNE retry 417 p4 := s.Prog(ppc64.ABNE) 418 p4.To.Type = obj.TYPE_BRANCH 419 gc.Patch(p4, p) 420 // ISYNC 421 pisync := s.Prog(ppc64.AISYNC) 422 pisync.To.Type = obj.TYPE_NONE 423 // return true 424 p5 := s.Prog(ppc64.AMOVD) 425 p5.From.Type = obj.TYPE_CONST 426 p5.From.Offset = 1 427 p5.To.Type = obj.TYPE_REG 428 p5.To.Reg = out 429 // BR done 430 p6 := s.Prog(obj.AJMP) 431 p6.To.Type = obj.TYPE_BRANCH 432 // return false 433 p7 := s.Prog(ppc64.AMOVD) 434 p7.From.Type = obj.TYPE_CONST 435 p7.From.Offset = 0 436 p7.To.Type = obj.TYPE_REG 437 p7.To.Reg = out 438 gc.Patch(p2, p7) 439 // done (label) 440 p8 := s.Prog(obj.ANOP) 441 gc.Patch(p6, p8) 442 443 case ssa.OpPPC64LoweredGetClosurePtr: 444 // Closure pointer is R11 (already) 445 gc.CheckLoweredGetClosurePtr(v) 446 447 case ssa.OpPPC64LoweredRound32F, ssa.OpPPC64LoweredRound64F: 448 // input is already rounded 449 450 case ssa.OpLoadReg: 451 loadOp := loadByType(v.Type) 452 p := s.Prog(loadOp) 453 gc.AddrAuto(&p.From, v.Args[0]) 454 p.To.Type = obj.TYPE_REG 455 p.To.Reg = v.Reg() 456 457 case ssa.OpStoreReg: 458 storeOp := storeByType(v.Type) 459 p := s.Prog(storeOp) 460 p.From.Type = obj.TYPE_REG 461 p.From.Reg = v.Args[0].Reg() 462 gc.AddrAuto(&p.To, v) 463 464 case ssa.OpPPC64DIVD: 465 // For now, 466 // 467 // cmp arg1, -1 468 // be ahead 469 // v = arg0 / arg1 470 // b over 471 // ahead: v = - arg0 472 // over: nop 473 r := v.Reg() 474 r0 := v.Args[0].Reg() 475 r1 := v.Args[1].Reg() 476 477 p := s.Prog(ppc64.ACMP) 478 p.From.Type = obj.TYPE_REG 479 p.From.Reg = r1 480 p.To.Type = obj.TYPE_CONST 481 p.To.Offset = -1 482 483 pbahead := s.Prog(ppc64.ABEQ) 484 pbahead.To.Type = obj.TYPE_BRANCH 485 486 p = s.Prog(v.Op.Asm()) 487 p.From.Type = obj.TYPE_REG 488 p.From.Reg = r1 489 p.Reg = r0 490 p.To.Type = obj.TYPE_REG 491 p.To.Reg = r 492 493 pbover := s.Prog(obj.AJMP) 494 pbover.To.Type = obj.TYPE_BRANCH 495 496 p = s.Prog(ppc64.ANEG) 497 p.To.Type = obj.TYPE_REG 498 p.To.Reg = r 499 p.From.Type = obj.TYPE_REG 500 p.From.Reg = r0 501 gc.Patch(pbahead, p) 502 503 p = s.Prog(obj.ANOP) 504 gc.Patch(pbover, p) 505 506 case ssa.OpPPC64DIVW: 507 // word-width version of above 508 r := v.Reg() 509 r0 := v.Args[0].Reg() 510 r1 := v.Args[1].Reg() 511 512 p := s.Prog(ppc64.ACMPW) 513 p.From.Type = obj.TYPE_REG 514 p.From.Reg = r1 515 p.To.Type = obj.TYPE_CONST 516 p.To.Offset = -1 517 518 pbahead := s.Prog(ppc64.ABEQ) 519 pbahead.To.Type = obj.TYPE_BRANCH 520 521 p = s.Prog(v.Op.Asm()) 522 p.From.Type = obj.TYPE_REG 523 p.From.Reg = r1 524 p.Reg = r0 525 p.To.Type = obj.TYPE_REG 526 p.To.Reg = r 527 528 pbover := s.Prog(obj.AJMP) 529 pbover.To.Type = obj.TYPE_BRANCH 530 531 p = s.Prog(ppc64.ANEG) 532 p.To.Type = obj.TYPE_REG 533 p.To.Reg = r 534 p.From.Type = obj.TYPE_REG 535 p.From.Reg = r0 536 gc.Patch(pbahead, p) 537 538 p = s.Prog(obj.ANOP) 539 gc.Patch(pbover, p) 540 541 case ssa.OpPPC64ADD, ssa.OpPPC64FADD, ssa.OpPPC64FADDS, ssa.OpPPC64SUB, ssa.OpPPC64FSUB, ssa.OpPPC64FSUBS, 542 ssa.OpPPC64MULLD, ssa.OpPPC64MULLW, ssa.OpPPC64DIVDU, ssa.OpPPC64DIVWU, 543 ssa.OpPPC64SRAD, ssa.OpPPC64SRAW, ssa.OpPPC64SRD, ssa.OpPPC64SRW, ssa.OpPPC64SLD, ssa.OpPPC64SLW, 544 ssa.OpPPC64MULHD, ssa.OpPPC64MULHW, ssa.OpPPC64MULHDU, ssa.OpPPC64MULHWU, 545 ssa.OpPPC64FMUL, ssa.OpPPC64FMULS, ssa.OpPPC64FDIV, ssa.OpPPC64FDIVS, 546 ssa.OpPPC64AND, ssa.OpPPC64OR, ssa.OpPPC64ANDN, ssa.OpPPC64ORN, ssa.OpPPC64NOR, ssa.OpPPC64XOR, ssa.OpPPC64EQV: 547 r := v.Reg() 548 r1 := v.Args[0].Reg() 549 r2 := v.Args[1].Reg() 550 p := s.Prog(v.Op.Asm()) 551 p.From.Type = obj.TYPE_REG 552 p.From.Reg = r2 553 p.Reg = r1 554 p.To.Type = obj.TYPE_REG 555 p.To.Reg = r 556 557 case ssa.OpPPC64ROTLconst, ssa.OpPPC64ROTLWconst: 558 p := s.Prog(v.Op.Asm()) 559 p.From.Type = obj.TYPE_CONST 560 p.From.Offset = v.AuxInt 561 p.Reg = v.Args[0].Reg() 562 p.To.Type = obj.TYPE_REG 563 p.To.Reg = v.Reg() 564 565 case ssa.OpPPC64FMADD, ssa.OpPPC64FMADDS, ssa.OpPPC64FMSUB, ssa.OpPPC64FMSUBS: 566 r := v.Reg() 567 r1 := v.Args[0].Reg() 568 r2 := v.Args[1].Reg() 569 r3 := v.Args[2].Reg() 570 // r = r1*r2 ± r3 571 p := s.Prog(v.Op.Asm()) 572 p.From.Type = obj.TYPE_REG 573 p.From.Reg = r1 574 p.Reg = r3 575 p.From3 = new(obj.Addr) 576 p.From3.Type = obj.TYPE_REG 577 p.From3.Reg = r2 578 p.To.Type = obj.TYPE_REG 579 p.To.Reg = r 580 581 case ssa.OpPPC64MaskIfNotCarry: 582 r := v.Reg() 583 p := s.Prog(v.Op.Asm()) 584 p.From.Type = obj.TYPE_REG 585 p.From.Reg = ppc64.REGZERO 586 p.To.Type = obj.TYPE_REG 587 p.To.Reg = r 588 589 case ssa.OpPPC64ADDconstForCarry: 590 r1 := v.Args[0].Reg() 591 p := s.Prog(v.Op.Asm()) 592 p.Reg = r1 593 p.From.Type = obj.TYPE_CONST 594 p.From.Offset = v.AuxInt 595 p.To.Type = obj.TYPE_REG 596 p.To.Reg = ppc64.REGTMP // Ignored; this is for the carry effect. 597 598 case ssa.OpPPC64NEG, ssa.OpPPC64FNEG, ssa.OpPPC64FSQRT, ssa.OpPPC64FSQRTS, ssa.OpPPC64FCTIDZ, ssa.OpPPC64FCTIWZ, ssa.OpPPC64FCFID, ssa.OpPPC64FRSP: 599 r := v.Reg() 600 p := s.Prog(v.Op.Asm()) 601 p.To.Type = obj.TYPE_REG 602 p.To.Reg = r 603 p.From.Type = obj.TYPE_REG 604 p.From.Reg = v.Args[0].Reg() 605 606 case ssa.OpPPC64ADDconst, ssa.OpPPC64ANDconst, ssa.OpPPC64ORconst, ssa.OpPPC64XORconst, 607 ssa.OpPPC64SRADconst, ssa.OpPPC64SRAWconst, ssa.OpPPC64SRDconst, ssa.OpPPC64SRWconst, ssa.OpPPC64SLDconst, ssa.OpPPC64SLWconst: 608 p := s.Prog(v.Op.Asm()) 609 p.Reg = v.Args[0].Reg() 610 611 if v.Aux != nil { 612 p.From.Type = obj.TYPE_CONST 613 p.From.Offset = gc.AuxOffset(v) 614 } else { 615 p.From.Type = obj.TYPE_CONST 616 p.From.Offset = v.AuxInt 617 } 618 619 p.To.Type = obj.TYPE_REG 620 p.To.Reg = v.Reg() 621 622 case ssa.OpPPC64ANDCCconst: 623 p := s.Prog(v.Op.Asm()) 624 p.Reg = v.Args[0].Reg() 625 626 if v.Aux != nil { 627 p.From.Type = obj.TYPE_CONST 628 p.From.Offset = gc.AuxOffset(v) 629 } else { 630 p.From.Type = obj.TYPE_CONST 631 p.From.Offset = v.AuxInt 632 } 633 634 p.To.Type = obj.TYPE_REG 635 p.To.Reg = ppc64.REGTMP // discard result 636 637 case ssa.OpPPC64MOVDaddr: 638 p := s.Prog(ppc64.AMOVD) 639 p.From.Type = obj.TYPE_ADDR 640 p.To.Type = obj.TYPE_REG 641 p.To.Reg = v.Reg() 642 643 var wantreg string 644 // Suspect comment, copied from ARM code 645 // MOVD $sym+off(base), R 646 // the assembler expands it as the following: 647 // - base is SP: add constant offset to SP 648 // when constant is large, tmp register (R11) may be used 649 // - base is SB: load external address from constant pool (use relocation) 650 switch v.Aux.(type) { 651 default: 652 v.Fatalf("aux is of unknown type %T", v.Aux) 653 case *ssa.ExternSymbol: 654 wantreg = "SB" 655 gc.AddAux(&p.From, v) 656 case *ssa.ArgSymbol, *ssa.AutoSymbol: 657 wantreg = "SP" 658 gc.AddAux(&p.From, v) 659 case nil: 660 // No sym, just MOVD $off(SP), R 661 wantreg = "SP" 662 p.From.Reg = ppc64.REGSP 663 p.From.Offset = v.AuxInt 664 } 665 if reg := v.Args[0].RegName(); reg != wantreg { 666 v.Fatalf("bad reg %s for symbol type %T, want %s", reg, v.Aux, wantreg) 667 } 668 669 case ssa.OpPPC64MOVDconst: 670 p := s.Prog(v.Op.Asm()) 671 p.From.Type = obj.TYPE_CONST 672 p.From.Offset = v.AuxInt 673 p.To.Type = obj.TYPE_REG 674 p.To.Reg = v.Reg() 675 676 case ssa.OpPPC64FMOVDconst, ssa.OpPPC64FMOVSconst: 677 p := s.Prog(v.Op.Asm()) 678 p.From.Type = obj.TYPE_FCONST 679 p.From.Val = math.Float64frombits(uint64(v.AuxInt)) 680 p.To.Type = obj.TYPE_REG 681 p.To.Reg = v.Reg() 682 683 case ssa.OpPPC64FCMPU, ssa.OpPPC64CMP, ssa.OpPPC64CMPW, ssa.OpPPC64CMPU, ssa.OpPPC64CMPWU: 684 p := s.Prog(v.Op.Asm()) 685 p.From.Type = obj.TYPE_REG 686 p.From.Reg = v.Args[0].Reg() 687 p.To.Type = obj.TYPE_REG 688 p.To.Reg = v.Args[1].Reg() 689 690 case ssa.OpPPC64CMPconst, ssa.OpPPC64CMPUconst, ssa.OpPPC64CMPWconst, ssa.OpPPC64CMPWUconst: 691 p := s.Prog(v.Op.Asm()) 692 p.From.Type = obj.TYPE_REG 693 p.From.Reg = v.Args[0].Reg() 694 p.To.Type = obj.TYPE_CONST 695 p.To.Offset = v.AuxInt 696 697 case ssa.OpPPC64MOVBreg, ssa.OpPPC64MOVBZreg, ssa.OpPPC64MOVHreg, ssa.OpPPC64MOVHZreg, ssa.OpPPC64MOVWreg, ssa.OpPPC64MOVWZreg: 698 // Shift in register to required size 699 p := s.Prog(v.Op.Asm()) 700 p.From.Type = obj.TYPE_REG 701 p.From.Reg = v.Args[0].Reg() 702 p.To.Reg = v.Reg() 703 p.To.Type = obj.TYPE_REG 704 705 case ssa.OpPPC64MOVDload, ssa.OpPPC64MOVWload, ssa.OpPPC64MOVHload, ssa.OpPPC64MOVWZload, ssa.OpPPC64MOVBZload, ssa.OpPPC64MOVHZload: 706 p := s.Prog(v.Op.Asm()) 707 p.From.Type = obj.TYPE_MEM 708 p.From.Reg = v.Args[0].Reg() 709 gc.AddAux(&p.From, v) 710 p.To.Type = obj.TYPE_REG 711 p.To.Reg = v.Reg() 712 713 case ssa.OpPPC64FMOVDload, ssa.OpPPC64FMOVSload: 714 p := s.Prog(v.Op.Asm()) 715 p.From.Type = obj.TYPE_MEM 716 p.From.Reg = v.Args[0].Reg() 717 gc.AddAux(&p.From, v) 718 p.To.Type = obj.TYPE_REG 719 p.To.Reg = v.Reg() 720 721 case ssa.OpPPC64MOVDstorezero, ssa.OpPPC64MOVWstorezero, ssa.OpPPC64MOVHstorezero, ssa.OpPPC64MOVBstorezero: 722 p := s.Prog(v.Op.Asm()) 723 p.From.Type = obj.TYPE_REG 724 p.From.Reg = ppc64.REGZERO 725 p.To.Type = obj.TYPE_MEM 726 p.To.Reg = v.Args[0].Reg() 727 gc.AddAux(&p.To, v) 728 729 case ssa.OpPPC64MOVDstore, ssa.OpPPC64MOVWstore, ssa.OpPPC64MOVHstore, ssa.OpPPC64MOVBstore: 730 p := s.Prog(v.Op.Asm()) 731 p.From.Type = obj.TYPE_REG 732 p.From.Reg = v.Args[1].Reg() 733 p.To.Type = obj.TYPE_MEM 734 p.To.Reg = v.Args[0].Reg() 735 gc.AddAux(&p.To, v) 736 case ssa.OpPPC64FMOVDstore, ssa.OpPPC64FMOVSstore: 737 p := s.Prog(v.Op.Asm()) 738 p.From.Type = obj.TYPE_REG 739 p.From.Reg = v.Args[1].Reg() 740 p.To.Type = obj.TYPE_MEM 741 p.To.Reg = v.Args[0].Reg() 742 gc.AddAux(&p.To, v) 743 744 case ssa.OpPPC64Equal, 745 ssa.OpPPC64NotEqual, 746 ssa.OpPPC64LessThan, 747 ssa.OpPPC64FLessThan, 748 ssa.OpPPC64LessEqual, 749 ssa.OpPPC64GreaterThan, 750 ssa.OpPPC64FGreaterThan, 751 ssa.OpPPC64GreaterEqual: 752 753 // On Power7 or later, can use isel instruction: 754 // for a < b, a > b, a = b: 755 // rtmp := 1 756 // isel rt,rtmp,r0,cond // rt is target in ppc asm 757 758 // for a >= b, a <= b, a != b: 759 // rtmp := 1 760 // isel rt,0,rtmp,!cond // rt is target in ppc asm 761 762 p := s.Prog(ppc64.AMOVD) 763 p.From.Type = obj.TYPE_CONST 764 p.From.Offset = 1 765 p.To.Type = obj.TYPE_REG 766 p.To.Reg = iselRegs[1] 767 iop := iselOps[v.Op] 768 ssaGenISEL(s, v, iop.cond, iselRegs[iop.valueIfCond], iselRegs[1-iop.valueIfCond]) 769 770 case ssa.OpPPC64FLessEqual, // These include a second branch for EQ -- dealing with NaN prevents REL= to !REL conversion 771 ssa.OpPPC64FGreaterEqual: 772 773 p := s.Prog(ppc64.AMOVD) 774 p.From.Type = obj.TYPE_CONST 775 p.From.Offset = 1 776 p.To.Type = obj.TYPE_REG 777 p.To.Reg = iselRegs[1] 778 iop := iselOps[v.Op] 779 ssaGenISEL(s, v, iop.cond, iselRegs[iop.valueIfCond], iselRegs[1-iop.valueIfCond]) 780 ssaGenISEL(s, v, ppc64.C_COND_EQ, iselRegs[1], v.Reg()) 781 782 case ssa.OpPPC64LoweredZero: 783 784 // unaligned data doesn't hurt performance 785 // for these instructions on power8 or later 786 787 // for sizes >= 64 generate a loop as follows: 788 789 // set up loop counter in CTR, used by BC 790 // MOVD len/32,REG_TMP 791 // MOVD REG_TMP,CTR 792 // loop: 793 // MOVD R0,(R3) 794 // MOVD R0,8(R3) 795 // MOVD R0,16(R3) 796 // MOVD R0,24(R3) 797 // ADD $32,R3 798 // BC 16, 0, loop 799 // 800 // any remainder is done as described below 801 802 // for sizes < 64 bytes, first clear as many doublewords as possible, 803 // then handle the remainder 804 // MOVD R0,(R3) 805 // MOVD R0,8(R3) 806 // .... etc. 807 // 808 // the remainder bytes are cleared using one or more 809 // of the following instructions with the appropriate 810 // offsets depending which instructions are needed 811 // 812 // MOVW R0,n1(R3) 4 bytes 813 // MOVH R0,n2(R3) 2 bytes 814 // MOVB R0,n3(R3) 1 byte 815 // 816 // 7 bytes: MOVW, MOVH, MOVB 817 // 6 bytes: MOVW, MOVH 818 // 5 bytes: MOVW, MOVB 819 // 3 bytes: MOVH, MOVB 820 821 // each loop iteration does 32 bytes 822 ctr := v.AuxInt / 32 823 824 // remainder bytes 825 rem := v.AuxInt % 32 826 827 // only generate a loop if there is more 828 // than 1 iteration. 829 if ctr > 1 { 830 // Set up CTR loop counter 831 p := s.Prog(ppc64.AMOVD) 832 p.From.Type = obj.TYPE_CONST 833 p.From.Offset = ctr 834 p.To.Type = obj.TYPE_REG 835 p.To.Reg = ppc64.REGTMP 836 837 p = s.Prog(ppc64.AMOVD) 838 p.From.Type = obj.TYPE_REG 839 p.From.Reg = ppc64.REGTMP 840 p.To.Type = obj.TYPE_REG 841 p.To.Reg = ppc64.REG_CTR 842 843 // generate 4 MOVDs 844 // when this is a loop then the top must be saved 845 var top *obj.Prog 846 for offset := int64(0); offset < 32; offset += 8 { 847 // This is the top of loop 848 p := s.Prog(ppc64.AMOVD) 849 p.From.Type = obj.TYPE_REG 850 p.From.Reg = ppc64.REG_R0 851 p.To.Type = obj.TYPE_MEM 852 p.To.Reg = v.Args[0].Reg() 853 p.To.Offset = offset 854 // Save the top of loop 855 if top == nil { 856 top = p 857 } 858 } 859 860 // Increment address for the 861 // 4 doublewords just zeroed. 862 p = s.Prog(ppc64.AADD) 863 p.Reg = v.Args[0].Reg() 864 p.From.Type = obj.TYPE_CONST 865 p.From.Offset = 32 866 p.To.Type = obj.TYPE_REG 867 p.To.Reg = v.Args[0].Reg() 868 869 // Branch back to top of loop 870 // based on CTR 871 // BC with BO_BCTR generates bdnz 872 p = s.Prog(ppc64.ABC) 873 p.From.Type = obj.TYPE_CONST 874 p.From.Offset = ppc64.BO_BCTR 875 p.Reg = ppc64.REG_R0 876 p.To.Type = obj.TYPE_BRANCH 877 gc.Patch(p, top) 878 } 879 880 // when ctr == 1 the loop was not generated but 881 // there are at least 32 bytes to clear, so add 882 // that to the remainder to generate the code 883 // to clear those doublewords 884 if ctr == 1 { 885 rem += 32 886 } 887 888 // clear the remainder starting at offset zero 889 offset := int64(0) 890 891 // first clear as many doublewords as possible 892 // then clear remaining sizes as available 893 for rem > 0 { 894 op, size := ppc64.AMOVB, int64(1) 895 switch { 896 case rem >= 8: 897 op, size = ppc64.AMOVD, 8 898 case rem >= 4: 899 op, size = ppc64.AMOVW, 4 900 case rem >= 2: 901 op, size = ppc64.AMOVH, 2 902 } 903 p := s.Prog(op) 904 p.From.Type = obj.TYPE_REG 905 p.From.Reg = ppc64.REG_R0 906 p.To.Type = obj.TYPE_MEM 907 p.To.Reg = v.Args[0].Reg() 908 p.To.Offset = offset 909 rem -= size 910 offset += size 911 } 912 913 case ssa.OpPPC64LoweredMove: 914 915 // This will be used when moving more 916 // than 8 bytes. Moves start with as 917 // as many 8 byte moves as possible, then 918 // 4, 2, or 1 byte(s) as remaining. This will 919 // work and be efficient for power8 or later. 920 // If there are 64 or more bytes, then a 921 // loop is generated to move 32 bytes and 922 // update the src and dst addresses on each 923 // iteration. When < 64 bytes, the appropriate 924 // number of moves are generated based on the 925 // size. 926 // When moving >= 64 bytes a loop is used 927 // MOVD len/32,REG_TMP 928 // MOVD REG_TMP,CTR 929 // top: 930 // MOVD (R4),R7 931 // MOVD 8(R4),R8 932 // MOVD 16(R4),R9 933 // MOVD 24(R4),R10 934 // ADD R4,$32 935 // MOVD R7,(R3) 936 // MOVD R8,8(R3) 937 // MOVD R9,16(R3) 938 // MOVD R10,24(R3) 939 // ADD R3,$32 940 // BC 16,0,top 941 // Bytes not moved by this loop are moved 942 // with a combination of the following instructions, 943 // starting with the largest sizes and generating as 944 // many as needed, using the appropriate offset value. 945 // MOVD n(R4),R7 946 // MOVD R7,n(R3) 947 // MOVW n1(R4),R7 948 // MOVW R7,n1(R3) 949 // MOVH n2(R4),R7 950 // MOVH R7,n2(R3) 951 // MOVB n3(R4),R7 952 // MOVB R7,n3(R3) 953 954 // Each loop iteration moves 32 bytes 955 ctr := v.AuxInt / 32 956 957 // Remainder after the loop 958 rem := v.AuxInt % 32 959 960 dst_reg := v.Args[0].Reg() 961 src_reg := v.Args[1].Reg() 962 963 // The set of registers used here, must match the clobbered reg list 964 // in PPC64Ops.go. 965 useregs := []int16{ppc64.REG_R7, ppc64.REG_R8, ppc64.REG_R9, ppc64.REG_R10} 966 offset := int64(0) 967 968 // top of the loop 969 var top *obj.Prog 970 // Only generate looping code when loop counter is > 1 for >= 64 bytes 971 if ctr > 1 { 972 // Set up the CTR 973 p := s.Prog(ppc64.AMOVD) 974 p.From.Type = obj.TYPE_CONST 975 p.From.Offset = ctr 976 p.To.Type = obj.TYPE_REG 977 p.To.Reg = ppc64.REGTMP 978 979 p = s.Prog(ppc64.AMOVD) 980 p.From.Type = obj.TYPE_REG 981 p.From.Reg = ppc64.REGTMP 982 p.To.Type = obj.TYPE_REG 983 p.To.Reg = ppc64.REG_CTR 984 985 // Generate all the MOVDs for loads 986 // based off the same register, increasing 987 // the offset by 8 for each instruction 988 for _, rg := range useregs { 989 p := s.Prog(ppc64.AMOVD) 990 p.From.Type = obj.TYPE_MEM 991 p.From.Reg = src_reg 992 p.From.Offset = offset 993 p.To.Type = obj.TYPE_REG 994 p.To.Reg = rg 995 if top == nil { 996 top = p 997 } 998 offset += 8 999 } 1000 // increment the src_reg for next iteration 1001 p = s.Prog(ppc64.AADD) 1002 p.Reg = src_reg 1003 p.From.Type = obj.TYPE_CONST 1004 p.From.Offset = 32 1005 p.To.Type = obj.TYPE_REG 1006 p.To.Reg = src_reg 1007 1008 // generate the MOVDs for stores, based 1009 // off the same register, using the same 1010 // offsets as in the loads. 1011 offset = int64(0) 1012 for _, rg := range useregs { 1013 p := s.Prog(ppc64.AMOVD) 1014 p.From.Type = obj.TYPE_REG 1015 p.From.Reg = rg 1016 p.To.Type = obj.TYPE_MEM 1017 p.To.Reg = dst_reg 1018 p.To.Offset = offset 1019 offset += 8 1020 } 1021 // increment the dst_reg for next iteration 1022 p = s.Prog(ppc64.AADD) 1023 p.Reg = dst_reg 1024 p.From.Type = obj.TYPE_CONST 1025 p.From.Offset = 32 1026 p.To.Type = obj.TYPE_REG 1027 p.To.Reg = dst_reg 1028 1029 // BC with BO_BCTR generates bdnz to branch on nonzero CTR 1030 // to loop top. 1031 p = s.Prog(ppc64.ABC) 1032 p.From.Type = obj.TYPE_CONST 1033 p.From.Offset = ppc64.BO_BCTR 1034 p.Reg = ppc64.REG_R0 1035 p.To.Type = obj.TYPE_BRANCH 1036 gc.Patch(p, top) 1037 1038 // src_reg and dst_reg were incremented in the loop, so 1039 // later instructions start with offset 0. 1040 offset = int64(0) 1041 } 1042 1043 // No loop was generated for one iteration, so 1044 // add 32 bytes to the remainder to move those bytes. 1045 if ctr == 1 { 1046 rem += 32 1047 } 1048 1049 // Generate all the remaining load and store pairs, starting with 1050 // as many 8 byte moves as possible, then 4, 2, 1. 1051 for rem > 0 { 1052 op, size := ppc64.AMOVB, int64(1) 1053 switch { 1054 case rem >= 8: 1055 op, size = ppc64.AMOVD, 8 1056 case rem >= 4: 1057 op, size = ppc64.AMOVW, 4 1058 case rem >= 2: 1059 op, size = ppc64.AMOVH, 2 1060 } 1061 // Load 1062 p := s.Prog(op) 1063 p.To.Type = obj.TYPE_REG 1064 p.To.Reg = ppc64.REG_R7 1065 p.From.Type = obj.TYPE_MEM 1066 p.From.Reg = src_reg 1067 p.From.Offset = offset 1068 1069 // Store 1070 p = s.Prog(op) 1071 p.From.Type = obj.TYPE_REG 1072 p.From.Reg = ppc64.REG_R7 1073 p.To.Type = obj.TYPE_MEM 1074 p.To.Reg = dst_reg 1075 p.To.Offset = offset 1076 rem -= size 1077 offset += size 1078 } 1079 1080 case ssa.OpPPC64CALLstatic: 1081 s.Call(v) 1082 1083 case ssa.OpPPC64CALLclosure, ssa.OpPPC64CALLinter: 1084 p := s.Prog(ppc64.AMOVD) 1085 p.From.Type = obj.TYPE_REG 1086 p.From.Reg = v.Args[0].Reg() 1087 p.To.Type = obj.TYPE_REG 1088 p.To.Reg = ppc64.REG_CTR 1089 1090 if gc.Ctxt.Flag_shared && p.From.Reg != ppc64.REG_R12 { 1091 // Make sure function pointer is in R12 as well when 1092 // compiling Go into PIC. 1093 // TODO(mwhudson): it would obviously be better to 1094 // change the register allocation to put the value in 1095 // R12 already, but I don't know how to do that. 1096 // TODO: We have the technology now to implement TODO above. 1097 q := s.Prog(ppc64.AMOVD) 1098 q.From = p.From 1099 q.To.Type = obj.TYPE_REG 1100 q.To.Reg = ppc64.REG_R12 1101 } 1102 1103 pp := s.Call(v) 1104 pp.To.Reg = ppc64.REG_CTR 1105 1106 if gc.Ctxt.Flag_shared { 1107 // When compiling Go into PIC, the function we just 1108 // called via pointer might have been implemented in 1109 // a separate module and so overwritten the TOC 1110 // pointer in R2; reload it. 1111 q := s.Prog(ppc64.AMOVD) 1112 q.From.Type = obj.TYPE_MEM 1113 q.From.Offset = 24 1114 q.From.Reg = ppc64.REGSP 1115 q.To.Type = obj.TYPE_REG 1116 q.To.Reg = ppc64.REG_R2 1117 } 1118 1119 case ssa.OpPPC64LoweredNilCheck: 1120 // Issue a load which will fault if arg is nil. 1121 p := s.Prog(ppc64.AMOVBZ) 1122 p.From.Type = obj.TYPE_MEM 1123 p.From.Reg = v.Args[0].Reg() 1124 gc.AddAux(&p.From, v) 1125 p.To.Type = obj.TYPE_REG 1126 p.To.Reg = ppc64.REGTMP 1127 if gc.Debug_checknil != 0 && v.Pos.Line() > 1 { // v.Pos.Line()==1 in generated wrappers 1128 gc.Warnl(v.Pos, "generated nil check") 1129 } 1130 1131 case ssa.OpPPC64InvertFlags: 1132 v.Fatalf("InvertFlags should never make it to codegen %v", v.LongString()) 1133 case ssa.OpPPC64FlagEQ, ssa.OpPPC64FlagLT, ssa.OpPPC64FlagGT: 1134 v.Fatalf("Flag* ops should never make it to codegen %v", v.LongString()) 1135 case ssa.OpClobber: 1136 // TODO: implement for clobberdead experiment. Nop is ok for now. 1137 default: 1138 v.Fatalf("genValue not implemented: %s", v.LongString()) 1139 } 1140 } 1141 1142 var blockJump = [...]struct { 1143 asm, invasm obj.As 1144 asmeq, invasmun bool 1145 }{ 1146 ssa.BlockPPC64EQ: {ppc64.ABEQ, ppc64.ABNE, false, false}, 1147 ssa.BlockPPC64NE: {ppc64.ABNE, ppc64.ABEQ, false, false}, 1148 1149 ssa.BlockPPC64LT: {ppc64.ABLT, ppc64.ABGE, false, false}, 1150 ssa.BlockPPC64GE: {ppc64.ABGE, ppc64.ABLT, false, false}, 1151 ssa.BlockPPC64LE: {ppc64.ABLE, ppc64.ABGT, false, false}, 1152 ssa.BlockPPC64GT: {ppc64.ABGT, ppc64.ABLE, false, false}, 1153 1154 // TODO: need to work FP comparisons into block jumps 1155 ssa.BlockPPC64FLT: {ppc64.ABLT, ppc64.ABGE, false, false}, 1156 ssa.BlockPPC64FGE: {ppc64.ABGT, ppc64.ABLT, true, true}, // GE = GT or EQ; !GE = LT or UN 1157 ssa.BlockPPC64FLE: {ppc64.ABLT, ppc64.ABGT, true, true}, // LE = LT or EQ; !LE = GT or UN 1158 ssa.BlockPPC64FGT: {ppc64.ABGT, ppc64.ABLE, false, false}, 1159 } 1160 1161 func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) { 1162 switch b.Kind { 1163 case ssa.BlockDefer: 1164 // defer returns in R3: 1165 // 0 if we should continue executing 1166 // 1 if we should jump to deferreturn call 1167 p := s.Prog(ppc64.ACMP) 1168 p.From.Type = obj.TYPE_REG 1169 p.From.Reg = ppc64.REG_R3 1170 p.To.Type = obj.TYPE_REG 1171 p.To.Reg = ppc64.REG_R0 1172 1173 p = s.Prog(ppc64.ABNE) 1174 p.To.Type = obj.TYPE_BRANCH 1175 s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[1].Block()}) 1176 if b.Succs[0].Block() != next { 1177 p := s.Prog(obj.AJMP) 1178 p.To.Type = obj.TYPE_BRANCH 1179 s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()}) 1180 } 1181 1182 case ssa.BlockPlain: 1183 if b.Succs[0].Block() != next { 1184 p := s.Prog(obj.AJMP) 1185 p.To.Type = obj.TYPE_BRANCH 1186 s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()}) 1187 } 1188 case ssa.BlockExit: 1189 s.Prog(obj.AUNDEF) // tell plive.go that we never reach here 1190 case ssa.BlockRet: 1191 s.Prog(obj.ARET) 1192 case ssa.BlockRetJmp: 1193 p := s.Prog(obj.AJMP) 1194 p.To.Type = obj.TYPE_MEM 1195 p.To.Name = obj.NAME_EXTERN 1196 p.To.Sym = b.Aux.(*obj.LSym) 1197 1198 case ssa.BlockPPC64EQ, ssa.BlockPPC64NE, 1199 ssa.BlockPPC64LT, ssa.BlockPPC64GE, 1200 ssa.BlockPPC64LE, ssa.BlockPPC64GT, 1201 ssa.BlockPPC64FLT, ssa.BlockPPC64FGE, 1202 ssa.BlockPPC64FLE, ssa.BlockPPC64FGT: 1203 jmp := blockJump[b.Kind] 1204 var p *obj.Prog 1205 switch next { 1206 case b.Succs[0].Block(): 1207 p = s.Prog(jmp.invasm) 1208 p.To.Type = obj.TYPE_BRANCH 1209 s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[1].Block()}) 1210 if jmp.invasmun { 1211 // TODO: The second branch is probably predict-not-taken since it is for FP unordered 1212 q := s.Prog(ppc64.ABVS) 1213 q.To.Type = obj.TYPE_BRANCH 1214 s.Branches = append(s.Branches, gc.Branch{P: q, B: b.Succs[1].Block()}) 1215 } 1216 case b.Succs[1].Block(): 1217 p = s.Prog(jmp.asm) 1218 p.To.Type = obj.TYPE_BRANCH 1219 s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()}) 1220 if jmp.asmeq { 1221 q := s.Prog(ppc64.ABEQ) 1222 q.To.Type = obj.TYPE_BRANCH 1223 s.Branches = append(s.Branches, gc.Branch{P: q, B: b.Succs[0].Block()}) 1224 } 1225 default: 1226 p = s.Prog(jmp.asm) 1227 p.To.Type = obj.TYPE_BRANCH 1228 s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()}) 1229 if jmp.asmeq { 1230 q := s.Prog(ppc64.ABEQ) 1231 q.To.Type = obj.TYPE_BRANCH 1232 s.Branches = append(s.Branches, gc.Branch{P: q, B: b.Succs[0].Block()}) 1233 } 1234 q := s.Prog(obj.AJMP) 1235 q.To.Type = obj.TYPE_BRANCH 1236 s.Branches = append(s.Branches, gc.Branch{P: q, B: b.Succs[1].Block()}) 1237 } 1238 1239 default: 1240 b.Fatalf("branch not implemented: %s. Control: %s", b.LongString(), b.Control.LongString()) 1241 } 1242 }