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