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