github.com/FenixAra/go@v0.0.0-20170127160404-96ea0918e670/src/cmd/compile/internal/s390x/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 s390x 6 7 import ( 8 "math" 9 10 "cmd/compile/internal/gc" 11 "cmd/compile/internal/ssa" 12 "cmd/internal/obj" 13 "cmd/internal/obj/s390x" 14 ) 15 16 // markMoves marks any MOVXconst ops that need to avoid clobbering flags. 17 func ssaMarkMoves(s *gc.SSAGenState, b *ssa.Block) { 18 flive := b.FlagsLiveAtEnd 19 if b.Control != nil && b.Control.Type.IsFlags() { 20 flive = true 21 } 22 for i := len(b.Values) - 1; i >= 0; i-- { 23 v := b.Values[i] 24 if flive && v.Op == ssa.OpS390XMOVDconst { 25 // The "mark" is any non-nil Aux value. 26 v.Aux = v 27 } 28 if v.Type.IsFlags() { 29 flive = false 30 } 31 for _, a := range v.Args { 32 if a.Type.IsFlags() { 33 flive = true 34 } 35 } 36 } 37 } 38 39 // loadByType returns the load instruction of the given type. 40 func loadByType(t ssa.Type) obj.As { 41 if t.IsFloat() { 42 switch t.Size() { 43 case 4: 44 return s390x.AFMOVS 45 case 8: 46 return s390x.AFMOVD 47 } 48 } else { 49 switch t.Size() { 50 case 1: 51 if t.IsSigned() { 52 return s390x.AMOVB 53 } else { 54 return s390x.AMOVBZ 55 } 56 case 2: 57 if t.IsSigned() { 58 return s390x.AMOVH 59 } else { 60 return s390x.AMOVHZ 61 } 62 case 4: 63 if t.IsSigned() { 64 return s390x.AMOVW 65 } else { 66 return s390x.AMOVWZ 67 } 68 case 8: 69 return s390x.AMOVD 70 } 71 } 72 panic("bad load type") 73 } 74 75 // storeByType returns the store instruction of the given type. 76 func storeByType(t ssa.Type) obj.As { 77 width := t.Size() 78 if t.IsFloat() { 79 switch width { 80 case 4: 81 return s390x.AFMOVS 82 case 8: 83 return s390x.AFMOVD 84 } 85 } else { 86 switch width { 87 case 1: 88 return s390x.AMOVB 89 case 2: 90 return s390x.AMOVH 91 case 4: 92 return s390x.AMOVW 93 case 8: 94 return s390x.AMOVD 95 } 96 } 97 panic("bad store type") 98 } 99 100 // moveByType returns the reg->reg move instruction of the given type. 101 func moveByType(t ssa.Type) obj.As { 102 if t.IsFloat() { 103 return s390x.AFMOVD 104 } else { 105 switch t.Size() { 106 case 1: 107 if t.IsSigned() { 108 return s390x.AMOVB 109 } else { 110 return s390x.AMOVBZ 111 } 112 case 2: 113 if t.IsSigned() { 114 return s390x.AMOVH 115 } else { 116 return s390x.AMOVHZ 117 } 118 case 4: 119 if t.IsSigned() { 120 return s390x.AMOVW 121 } else { 122 return s390x.AMOVWZ 123 } 124 case 8: 125 return s390x.AMOVD 126 } 127 } 128 panic("bad load type") 129 } 130 131 // opregreg emits instructions for 132 // dest := dest(To) op src(From) 133 // and also returns the created obj.Prog so it 134 // may be further adjusted (offset, scale, etc). 135 func opregreg(op obj.As, dest, src int16) *obj.Prog { 136 p := gc.Prog(op) 137 p.From.Type = obj.TYPE_REG 138 p.To.Type = obj.TYPE_REG 139 p.To.Reg = dest 140 p.From.Reg = src 141 return p 142 } 143 144 // opregregimm emits instructions for 145 // dest := src(From) op off 146 // and also returns the created obj.Prog so it 147 // may be further adjusted (offset, scale, etc). 148 func opregregimm(op obj.As, dest, src int16, off int64) *obj.Prog { 149 p := gc.Prog(op) 150 p.From.Type = obj.TYPE_CONST 151 p.From.Offset = off 152 p.Reg = src 153 p.To.Reg = dest 154 p.To.Type = obj.TYPE_REG 155 return p 156 } 157 158 func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) { 159 s.SetLineno(v.Line) 160 switch v.Op { 161 case ssa.OpS390XSLD, ssa.OpS390XSLW, 162 ssa.OpS390XSRD, ssa.OpS390XSRW, 163 ssa.OpS390XSRAD, ssa.OpS390XSRAW: 164 r := v.Reg() 165 r1 := v.Args[0].Reg() 166 r2 := v.Args[1].Reg() 167 if r2 == s390x.REG_R0 { 168 v.Fatalf("cannot use R0 as shift value %s", v.LongString()) 169 } 170 p := opregreg(v.Op.Asm(), r, r2) 171 if r != r1 { 172 p.Reg = r1 173 } 174 case ssa.OpS390XADD, ssa.OpS390XADDW, 175 ssa.OpS390XSUB, ssa.OpS390XSUBW, 176 ssa.OpS390XAND, ssa.OpS390XANDW, 177 ssa.OpS390XOR, ssa.OpS390XORW, 178 ssa.OpS390XXOR, ssa.OpS390XXORW: 179 r := v.Reg() 180 r1 := v.Args[0].Reg() 181 r2 := v.Args[1].Reg() 182 p := opregreg(v.Op.Asm(), r, r2) 183 if r != r1 { 184 p.Reg = r1 185 } 186 // 2-address opcode arithmetic 187 case ssa.OpS390XMULLD, ssa.OpS390XMULLW, 188 ssa.OpS390XMULHD, ssa.OpS390XMULHDU, 189 ssa.OpS390XFADDS, ssa.OpS390XFADD, ssa.OpS390XFSUBS, ssa.OpS390XFSUB, 190 ssa.OpS390XFMULS, ssa.OpS390XFMUL, ssa.OpS390XFDIVS, ssa.OpS390XFDIV: 191 r := v.Reg() 192 if r != v.Args[0].Reg() { 193 v.Fatalf("input[0] and output not in same register %s", v.LongString()) 194 } 195 opregreg(v.Op.Asm(), r, v.Args[1].Reg()) 196 case ssa.OpS390XDIVD, ssa.OpS390XDIVW, 197 ssa.OpS390XDIVDU, ssa.OpS390XDIVWU, 198 ssa.OpS390XMODD, ssa.OpS390XMODW, 199 ssa.OpS390XMODDU, ssa.OpS390XMODWU: 200 201 // TODO(mundaym): use the temp registers every time like x86 does with AX? 202 dividend := v.Args[0].Reg() 203 divisor := v.Args[1].Reg() 204 205 // CPU faults upon signed overflow, which occurs when most 206 // negative int is divided by -1. 207 var j *obj.Prog 208 if v.Op == ssa.OpS390XDIVD || v.Op == ssa.OpS390XDIVW || 209 v.Op == ssa.OpS390XMODD || v.Op == ssa.OpS390XMODW { 210 211 var c *obj.Prog 212 c = gc.Prog(s390x.ACMP) 213 j = gc.Prog(s390x.ABEQ) 214 215 c.From.Type = obj.TYPE_REG 216 c.From.Reg = divisor 217 c.To.Type = obj.TYPE_CONST 218 c.To.Offset = -1 219 220 j.To.Type = obj.TYPE_BRANCH 221 222 } 223 224 p := gc.Prog(v.Op.Asm()) 225 p.From.Type = obj.TYPE_REG 226 p.From.Reg = divisor 227 p.Reg = 0 228 p.To.Type = obj.TYPE_REG 229 p.To.Reg = dividend 230 231 // signed division, rest of the check for -1 case 232 if j != nil { 233 j2 := gc.Prog(s390x.ABR) 234 j2.To.Type = obj.TYPE_BRANCH 235 236 var n *obj.Prog 237 if v.Op == ssa.OpS390XDIVD || v.Op == ssa.OpS390XDIVW { 238 // n * -1 = -n 239 n = gc.Prog(s390x.ANEG) 240 n.To.Type = obj.TYPE_REG 241 n.To.Reg = dividend 242 } else { 243 // n % -1 == 0 244 n = gc.Prog(s390x.AXOR) 245 n.From.Type = obj.TYPE_REG 246 n.From.Reg = dividend 247 n.To.Type = obj.TYPE_REG 248 n.To.Reg = dividend 249 } 250 251 j.To.Val = n 252 j2.To.Val = s.Pc() 253 } 254 case ssa.OpS390XADDconst, ssa.OpS390XADDWconst: 255 opregregimm(v.Op.Asm(), v.Reg(), v.Args[0].Reg(), v.AuxInt) 256 case ssa.OpS390XMULLDconst, ssa.OpS390XMULLWconst, 257 ssa.OpS390XSUBconst, ssa.OpS390XSUBWconst, 258 ssa.OpS390XANDconst, ssa.OpS390XANDWconst, 259 ssa.OpS390XORconst, ssa.OpS390XORWconst, 260 ssa.OpS390XXORconst, ssa.OpS390XXORWconst: 261 r := v.Reg() 262 if r != v.Args[0].Reg() { 263 v.Fatalf("input[0] and output not in same register %s", v.LongString()) 264 } 265 p := gc.Prog(v.Op.Asm()) 266 p.From.Type = obj.TYPE_CONST 267 p.From.Offset = v.AuxInt 268 p.To.Type = obj.TYPE_REG 269 p.To.Reg = r 270 case ssa.OpS390XSLDconst, ssa.OpS390XSLWconst, 271 ssa.OpS390XSRDconst, ssa.OpS390XSRWconst, 272 ssa.OpS390XSRADconst, ssa.OpS390XSRAWconst, 273 ssa.OpS390XRLLGconst, ssa.OpS390XRLLconst: 274 p := gc.Prog(v.Op.Asm()) 275 p.From.Type = obj.TYPE_CONST 276 p.From.Offset = v.AuxInt 277 r := v.Reg() 278 r1 := v.Args[0].Reg() 279 if r != r1 { 280 p.Reg = r1 281 } 282 p.To.Type = obj.TYPE_REG 283 p.To.Reg = r 284 case ssa.OpS390XSUBEcarrymask, ssa.OpS390XSUBEWcarrymask: 285 r := v.Reg() 286 p := gc.Prog(v.Op.Asm()) 287 p.From.Type = obj.TYPE_REG 288 p.From.Reg = r 289 p.To.Type = obj.TYPE_REG 290 p.To.Reg = r 291 case ssa.OpS390XMOVDaddridx: 292 r := v.Args[0].Reg() 293 i := v.Args[1].Reg() 294 p := gc.Prog(s390x.AMOVD) 295 p.From.Scale = 1 296 if i == s390x.REGSP { 297 r, i = i, r 298 } 299 p.From.Type = obj.TYPE_ADDR 300 p.From.Reg = r 301 p.From.Index = i 302 gc.AddAux(&p.From, v) 303 p.To.Type = obj.TYPE_REG 304 p.To.Reg = v.Reg() 305 case ssa.OpS390XMOVDaddr: 306 p := gc.Prog(s390x.AMOVD) 307 p.From.Type = obj.TYPE_ADDR 308 p.From.Reg = v.Args[0].Reg() 309 gc.AddAux(&p.From, v) 310 p.To.Type = obj.TYPE_REG 311 p.To.Reg = v.Reg() 312 case ssa.OpS390XCMP, ssa.OpS390XCMPW, ssa.OpS390XCMPU, ssa.OpS390XCMPWU: 313 opregreg(v.Op.Asm(), v.Args[1].Reg(), v.Args[0].Reg()) 314 case ssa.OpS390XFCMPS, ssa.OpS390XFCMP: 315 opregreg(v.Op.Asm(), v.Args[1].Reg(), v.Args[0].Reg()) 316 case ssa.OpS390XCMPconst, ssa.OpS390XCMPWconst, ssa.OpS390XCMPUconst, ssa.OpS390XCMPWUconst: 317 p := gc.Prog(v.Op.Asm()) 318 p.From.Type = obj.TYPE_REG 319 p.From.Reg = v.Args[0].Reg() 320 p.To.Type = obj.TYPE_CONST 321 p.To.Offset = v.AuxInt 322 case ssa.OpS390XMOVDconst: 323 x := v.Reg() 324 p := gc.Prog(v.Op.Asm()) 325 p.From.Type = obj.TYPE_CONST 326 p.From.Offset = v.AuxInt 327 p.To.Type = obj.TYPE_REG 328 p.To.Reg = x 329 case ssa.OpS390XFMOVSconst, ssa.OpS390XFMOVDconst: 330 x := v.Reg() 331 p := gc.Prog(v.Op.Asm()) 332 p.From.Type = obj.TYPE_FCONST 333 p.From.Val = math.Float64frombits(uint64(v.AuxInt)) 334 p.To.Type = obj.TYPE_REG 335 p.To.Reg = x 336 case ssa.OpS390XADDWload, ssa.OpS390XADDload, 337 ssa.OpS390XMULLWload, ssa.OpS390XMULLDload, 338 ssa.OpS390XSUBWload, ssa.OpS390XSUBload, 339 ssa.OpS390XANDWload, ssa.OpS390XANDload, 340 ssa.OpS390XORWload, ssa.OpS390XORload, 341 ssa.OpS390XXORWload, ssa.OpS390XXORload: 342 r := v.Reg() 343 if r != v.Args[0].Reg() { 344 v.Fatalf("input[0] and output not in same register %s", v.LongString()) 345 } 346 p := gc.Prog(v.Op.Asm()) 347 p.From.Type = obj.TYPE_MEM 348 p.From.Reg = v.Args[1].Reg() 349 gc.AddAux(&p.From, v) 350 p.To.Type = obj.TYPE_REG 351 p.To.Reg = r 352 case ssa.OpS390XMOVDload, 353 ssa.OpS390XMOVWZload, ssa.OpS390XMOVHZload, ssa.OpS390XMOVBZload, 354 ssa.OpS390XMOVDBRload, ssa.OpS390XMOVWBRload, ssa.OpS390XMOVHBRload, 355 ssa.OpS390XMOVBload, ssa.OpS390XMOVHload, ssa.OpS390XMOVWload, 356 ssa.OpS390XFMOVSload, ssa.OpS390XFMOVDload: 357 p := gc.Prog(v.Op.Asm()) 358 p.From.Type = obj.TYPE_MEM 359 p.From.Reg = v.Args[0].Reg() 360 gc.AddAux(&p.From, v) 361 p.To.Type = obj.TYPE_REG 362 p.To.Reg = v.Reg() 363 case ssa.OpS390XMOVBZloadidx, ssa.OpS390XMOVHZloadidx, ssa.OpS390XMOVWZloadidx, ssa.OpS390XMOVDloadidx, 364 ssa.OpS390XMOVHBRloadidx, ssa.OpS390XMOVWBRloadidx, ssa.OpS390XMOVDBRloadidx, 365 ssa.OpS390XFMOVSloadidx, ssa.OpS390XFMOVDloadidx: 366 r := v.Args[0].Reg() 367 i := v.Args[1].Reg() 368 if i == s390x.REGSP { 369 r, i = i, r 370 } 371 p := gc.Prog(v.Op.Asm()) 372 p.From.Type = obj.TYPE_MEM 373 p.From.Reg = r 374 p.From.Scale = 1 375 p.From.Index = i 376 gc.AddAux(&p.From, v) 377 p.To.Type = obj.TYPE_REG 378 p.To.Reg = v.Reg() 379 case ssa.OpS390XMOVBstore, ssa.OpS390XMOVHstore, ssa.OpS390XMOVWstore, ssa.OpS390XMOVDstore, 380 ssa.OpS390XMOVHBRstore, ssa.OpS390XMOVWBRstore, ssa.OpS390XMOVDBRstore, 381 ssa.OpS390XFMOVSstore, ssa.OpS390XFMOVDstore: 382 p := gc.Prog(v.Op.Asm()) 383 p.From.Type = obj.TYPE_REG 384 p.From.Reg = v.Args[1].Reg() 385 p.To.Type = obj.TYPE_MEM 386 p.To.Reg = v.Args[0].Reg() 387 gc.AddAux(&p.To, v) 388 case ssa.OpS390XMOVBstoreidx, ssa.OpS390XMOVHstoreidx, ssa.OpS390XMOVWstoreidx, ssa.OpS390XMOVDstoreidx, 389 ssa.OpS390XMOVHBRstoreidx, ssa.OpS390XMOVWBRstoreidx, ssa.OpS390XMOVDBRstoreidx, 390 ssa.OpS390XFMOVSstoreidx, ssa.OpS390XFMOVDstoreidx: 391 r := v.Args[0].Reg() 392 i := v.Args[1].Reg() 393 if i == s390x.REGSP { 394 r, i = i, r 395 } 396 p := gc.Prog(v.Op.Asm()) 397 p.From.Type = obj.TYPE_REG 398 p.From.Reg = v.Args[2].Reg() 399 p.To.Type = obj.TYPE_MEM 400 p.To.Reg = r 401 p.To.Scale = 1 402 p.To.Index = i 403 gc.AddAux(&p.To, v) 404 case ssa.OpS390XMOVDstoreconst, ssa.OpS390XMOVWstoreconst, ssa.OpS390XMOVHstoreconst, ssa.OpS390XMOVBstoreconst: 405 p := gc.Prog(v.Op.Asm()) 406 p.From.Type = obj.TYPE_CONST 407 sc := v.AuxValAndOff() 408 p.From.Offset = sc.Val() 409 p.To.Type = obj.TYPE_MEM 410 p.To.Reg = v.Args[0].Reg() 411 gc.AddAux2(&p.To, v, sc.Off()) 412 case ssa.OpS390XMOVBreg, ssa.OpS390XMOVHreg, ssa.OpS390XMOVWreg, 413 ssa.OpS390XMOVBZreg, ssa.OpS390XMOVHZreg, ssa.OpS390XMOVWZreg, 414 ssa.OpS390XCEFBRA, ssa.OpS390XCDFBRA, ssa.OpS390XCEGBRA, ssa.OpS390XCDGBRA, 415 ssa.OpS390XCFEBRA, ssa.OpS390XCFDBRA, ssa.OpS390XCGEBRA, ssa.OpS390XCGDBRA, 416 ssa.OpS390XLDEBR, ssa.OpS390XLEDBR, 417 ssa.OpS390XFNEG, ssa.OpS390XFNEGS: 418 opregreg(v.Op.Asm(), v.Reg(), v.Args[0].Reg()) 419 case ssa.OpS390XCLEAR: 420 p := gc.Prog(v.Op.Asm()) 421 p.From.Type = obj.TYPE_CONST 422 sc := v.AuxValAndOff() 423 p.From.Offset = sc.Val() 424 p.To.Type = obj.TYPE_MEM 425 p.To.Reg = v.Args[0].Reg() 426 gc.AddAux2(&p.To, v, sc.Off()) 427 case ssa.OpCopy, ssa.OpS390XMOVDconvert: 428 if v.Type.IsMemory() { 429 return 430 } 431 x := v.Args[0].Reg() 432 y := v.Reg() 433 if x != y { 434 opregreg(moveByType(v.Type), y, x) 435 } 436 case ssa.OpLoadReg: 437 if v.Type.IsFlags() { 438 v.Fatalf("load flags not implemented: %v", v.LongString()) 439 return 440 } 441 p := gc.Prog(loadByType(v.Type)) 442 gc.AddrAuto(&p.From, v.Args[0]) 443 p.To.Type = obj.TYPE_REG 444 p.To.Reg = v.Reg() 445 case ssa.OpStoreReg: 446 if v.Type.IsFlags() { 447 v.Fatalf("store flags not implemented: %v", v.LongString()) 448 return 449 } 450 p := gc.Prog(storeByType(v.Type)) 451 p.From.Type = obj.TYPE_REG 452 p.From.Reg = v.Args[0].Reg() 453 gc.AddrAuto(&p.To, v) 454 case ssa.OpPhi: 455 gc.CheckLoweredPhi(v) 456 case ssa.OpInitMem: 457 // memory arg needs no code 458 case ssa.OpArg: 459 // input args need no code 460 case ssa.OpS390XLoweredGetClosurePtr: 461 // Closure pointer is R12 (already) 462 gc.CheckLoweredGetClosurePtr(v) 463 case ssa.OpS390XLoweredGetG: 464 r := v.Reg() 465 p := gc.Prog(s390x.AMOVD) 466 p.From.Type = obj.TYPE_REG 467 p.From.Reg = s390x.REGG 468 p.To.Type = obj.TYPE_REG 469 p.To.Reg = r 470 case ssa.OpS390XCALLstatic: 471 if v.Aux.(*gc.Sym) == gc.Deferreturn.Sym { 472 // Deferred calls will appear to be returning to 473 // the CALL deferreturn(SB) that we are about to emit. 474 // However, the stack trace code will show the line 475 // of the instruction byte before the return PC. 476 // To avoid that being an unrelated instruction, 477 // insert an actual hardware NOP that will have the right line number. 478 // This is different from obj.ANOP, which is a virtual no-op 479 // that doesn't make it into the instruction stream. 480 ginsnop() 481 } 482 p := gc.Prog(obj.ACALL) 483 p.To.Type = obj.TYPE_MEM 484 p.To.Name = obj.NAME_EXTERN 485 p.To.Sym = gc.Linksym(v.Aux.(*gc.Sym)) 486 if gc.Maxarg < v.AuxInt { 487 gc.Maxarg = v.AuxInt 488 } 489 case ssa.OpS390XCALLclosure: 490 p := gc.Prog(obj.ACALL) 491 p.To.Type = obj.TYPE_REG 492 p.To.Reg = v.Args[0].Reg() 493 if gc.Maxarg < v.AuxInt { 494 gc.Maxarg = v.AuxInt 495 } 496 case ssa.OpS390XCALLdefer: 497 p := gc.Prog(obj.ACALL) 498 p.To.Type = obj.TYPE_MEM 499 p.To.Name = obj.NAME_EXTERN 500 p.To.Sym = gc.Linksym(gc.Deferproc.Sym) 501 if gc.Maxarg < v.AuxInt { 502 gc.Maxarg = v.AuxInt 503 } 504 case ssa.OpS390XCALLgo: 505 p := gc.Prog(obj.ACALL) 506 p.To.Type = obj.TYPE_MEM 507 p.To.Name = obj.NAME_EXTERN 508 p.To.Sym = gc.Linksym(gc.Newproc.Sym) 509 if gc.Maxarg < v.AuxInt { 510 gc.Maxarg = v.AuxInt 511 } 512 case ssa.OpS390XCALLinter: 513 p := gc.Prog(obj.ACALL) 514 p.To.Type = obj.TYPE_REG 515 p.To.Reg = v.Args[0].Reg() 516 if gc.Maxarg < v.AuxInt { 517 gc.Maxarg = v.AuxInt 518 } 519 case ssa.OpS390XFLOGR, ssa.OpS390XNEG, ssa.OpS390XNEGW, 520 ssa.OpS390XMOVWBR, ssa.OpS390XMOVDBR: 521 p := gc.Prog(v.Op.Asm()) 522 p.From.Type = obj.TYPE_REG 523 p.From.Reg = v.Args[0].Reg() 524 p.To.Type = obj.TYPE_REG 525 p.To.Reg = v.Reg() 526 case ssa.OpS390XNOT, ssa.OpS390XNOTW: 527 v.Fatalf("NOT/NOTW generated %s", v.LongString()) 528 case ssa.OpS390XMOVDEQ, ssa.OpS390XMOVDNE, 529 ssa.OpS390XMOVDLT, ssa.OpS390XMOVDLE, 530 ssa.OpS390XMOVDGT, ssa.OpS390XMOVDGE, 531 ssa.OpS390XMOVDGTnoinv, ssa.OpS390XMOVDGEnoinv: 532 r := v.Reg() 533 if r != v.Args[0].Reg() { 534 v.Fatalf("input[0] and output not in same register %s", v.LongString()) 535 } 536 p := gc.Prog(v.Op.Asm()) 537 p.From.Type = obj.TYPE_REG 538 p.From.Reg = v.Args[1].Reg() 539 p.To.Type = obj.TYPE_REG 540 p.To.Reg = r 541 case ssa.OpS390XFSQRT: 542 p := gc.Prog(v.Op.Asm()) 543 p.From.Type = obj.TYPE_REG 544 p.From.Reg = v.Args[0].Reg() 545 p.To.Type = obj.TYPE_REG 546 p.To.Reg = v.Reg() 547 case ssa.OpSP, ssa.OpSB: 548 // nothing to do 549 case ssa.OpSelect0, ssa.OpSelect1: 550 // nothing to do 551 case ssa.OpVarDef: 552 gc.Gvardef(v.Aux.(*gc.Node)) 553 case ssa.OpVarKill: 554 gc.Gvarkill(v.Aux.(*gc.Node)) 555 case ssa.OpVarLive: 556 gc.Gvarlive(v.Aux.(*gc.Node)) 557 case ssa.OpKeepAlive: 558 gc.KeepAlive(v) 559 case ssa.OpS390XInvertFlags: 560 v.Fatalf("InvertFlags should never make it to codegen %v", v.LongString()) 561 case ssa.OpS390XFlagEQ, ssa.OpS390XFlagLT, ssa.OpS390XFlagGT: 562 v.Fatalf("Flag* ops should never make it to codegen %v", v.LongString()) 563 case ssa.OpS390XAddTupleFirst32, ssa.OpS390XAddTupleFirst64: 564 v.Fatalf("AddTupleFirst* should never make it to codegen %v", v.LongString()) 565 case ssa.OpS390XLoweredNilCheck: 566 // Issue a load which will fault if the input is nil. 567 p := gc.Prog(s390x.AMOVBZ) 568 p.From.Type = obj.TYPE_MEM 569 p.From.Reg = v.Args[0].Reg() 570 gc.AddAux(&p.From, v) 571 p.To.Type = obj.TYPE_REG 572 p.To.Reg = s390x.REGTMP 573 if gc.Debug_checknil != 0 && v.Line > 1 { // v.Line==1 in generated wrappers 574 gc.Warnl(v.Line, "generated nil check") 575 } 576 case ssa.OpS390XMVC: 577 vo := v.AuxValAndOff() 578 p := gc.Prog(s390x.AMVC) 579 p.From.Type = obj.TYPE_MEM 580 p.From.Reg = v.Args[1].Reg() 581 p.From.Offset = vo.Off() 582 p.To.Type = obj.TYPE_MEM 583 p.To.Reg = v.Args[0].Reg() 584 p.To.Offset = vo.Off() 585 p.From3 = new(obj.Addr) 586 p.From3.Type = obj.TYPE_CONST 587 p.From3.Offset = vo.Val() 588 case ssa.OpS390XSTMG2, ssa.OpS390XSTMG3, ssa.OpS390XSTMG4, 589 ssa.OpS390XSTM2, ssa.OpS390XSTM3, ssa.OpS390XSTM4: 590 for i := 2; i < len(v.Args)-1; i++ { 591 if v.Args[i].Reg() != v.Args[i-1].Reg()+1 { 592 v.Fatalf("invalid store multiple %s", v.LongString()) 593 } 594 } 595 p := gc.Prog(v.Op.Asm()) 596 p.From.Type = obj.TYPE_REG 597 p.From.Reg = v.Args[1].Reg() 598 p.Reg = v.Args[len(v.Args)-2].Reg() 599 p.To.Type = obj.TYPE_MEM 600 p.To.Reg = v.Args[0].Reg() 601 gc.AddAux(&p.To, v) 602 case ssa.OpS390XLoweredMove: 603 // Inputs must be valid pointers to memory, 604 // so adjust arg0 and arg1 as part of the expansion. 605 // arg2 should be src+size, 606 // 607 // mvc: MVC $256, 0(R2), 0(R1) 608 // MOVD $256(R1), R1 609 // MOVD $256(R2), R2 610 // CMP R2, Rarg2 611 // BNE mvc 612 // MVC $rem, 0(R2), 0(R1) // if rem > 0 613 // arg2 is the last address to move in the loop + 256 614 mvc := gc.Prog(s390x.AMVC) 615 mvc.From.Type = obj.TYPE_MEM 616 mvc.From.Reg = v.Args[1].Reg() 617 mvc.To.Type = obj.TYPE_MEM 618 mvc.To.Reg = v.Args[0].Reg() 619 mvc.From3 = new(obj.Addr) 620 mvc.From3.Type = obj.TYPE_CONST 621 mvc.From3.Offset = 256 622 623 for i := 0; i < 2; i++ { 624 movd := gc.Prog(s390x.AMOVD) 625 movd.From.Type = obj.TYPE_ADDR 626 movd.From.Reg = v.Args[i].Reg() 627 movd.From.Offset = 256 628 movd.To.Type = obj.TYPE_REG 629 movd.To.Reg = v.Args[i].Reg() 630 } 631 632 cmpu := gc.Prog(s390x.ACMPU) 633 cmpu.From.Reg = v.Args[1].Reg() 634 cmpu.From.Type = obj.TYPE_REG 635 cmpu.To.Reg = v.Args[2].Reg() 636 cmpu.To.Type = obj.TYPE_REG 637 638 bne := gc.Prog(s390x.ABLT) 639 bne.To.Type = obj.TYPE_BRANCH 640 gc.Patch(bne, mvc) 641 642 if v.AuxInt > 0 { 643 mvc := gc.Prog(s390x.AMVC) 644 mvc.From.Type = obj.TYPE_MEM 645 mvc.From.Reg = v.Args[1].Reg() 646 mvc.To.Type = obj.TYPE_MEM 647 mvc.To.Reg = v.Args[0].Reg() 648 mvc.From3 = new(obj.Addr) 649 mvc.From3.Type = obj.TYPE_CONST 650 mvc.From3.Offset = v.AuxInt 651 } 652 case ssa.OpS390XLoweredZero: 653 // Input must be valid pointers to memory, 654 // so adjust arg0 as part of the expansion. 655 // arg1 should be src+size, 656 // 657 // clear: CLEAR $256, 0(R1) 658 // MOVD $256(R1), R1 659 // CMP R1, Rarg1 660 // BNE clear 661 // CLEAR $rem, 0(R1) // if rem > 0 662 // arg1 is the last address to zero in the loop + 256 663 clear := gc.Prog(s390x.ACLEAR) 664 clear.From.Type = obj.TYPE_CONST 665 clear.From.Offset = 256 666 clear.To.Type = obj.TYPE_MEM 667 clear.To.Reg = v.Args[0].Reg() 668 669 movd := gc.Prog(s390x.AMOVD) 670 movd.From.Type = obj.TYPE_ADDR 671 movd.From.Reg = v.Args[0].Reg() 672 movd.From.Offset = 256 673 movd.To.Type = obj.TYPE_REG 674 movd.To.Reg = v.Args[0].Reg() 675 676 cmpu := gc.Prog(s390x.ACMPU) 677 cmpu.From.Reg = v.Args[0].Reg() 678 cmpu.From.Type = obj.TYPE_REG 679 cmpu.To.Reg = v.Args[1].Reg() 680 cmpu.To.Type = obj.TYPE_REG 681 682 bne := gc.Prog(s390x.ABLT) 683 bne.To.Type = obj.TYPE_BRANCH 684 gc.Patch(bne, clear) 685 686 if v.AuxInt > 0 { 687 clear := gc.Prog(s390x.ACLEAR) 688 clear.From.Type = obj.TYPE_CONST 689 clear.From.Offset = v.AuxInt 690 clear.To.Type = obj.TYPE_MEM 691 clear.To.Reg = v.Args[0].Reg() 692 } 693 case ssa.OpS390XMOVWZatomicload, ssa.OpS390XMOVDatomicload: 694 p := gc.Prog(v.Op.Asm()) 695 p.From.Type = obj.TYPE_MEM 696 p.From.Reg = v.Args[0].Reg() 697 gc.AddAux(&p.From, v) 698 p.To.Type = obj.TYPE_REG 699 p.To.Reg = v.Reg0() 700 case ssa.OpS390XMOVWatomicstore, ssa.OpS390XMOVDatomicstore: 701 p := gc.Prog(v.Op.Asm()) 702 p.From.Type = obj.TYPE_REG 703 p.From.Reg = v.Args[1].Reg() 704 p.To.Type = obj.TYPE_MEM 705 p.To.Reg = v.Args[0].Reg() 706 gc.AddAux(&p.To, v) 707 case ssa.OpS390XLAA, ssa.OpS390XLAAG: 708 p := gc.Prog(v.Op.Asm()) 709 p.Reg = v.Reg0() 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.OpS390XLoweredAtomicCas32, ssa.OpS390XLoweredAtomicCas64: 716 // Convert the flags output of CS{,G} into a bool. 717 // CS{,G} arg1, arg2, arg0 718 // MOVD $0, ret 719 // BNE 2(PC) 720 // MOVD $1, ret 721 // NOP (so the BNE has somewhere to land) 722 723 // CS{,G} arg1, arg2, arg0 724 cs := gc.Prog(v.Op.Asm()) 725 cs.From.Type = obj.TYPE_REG 726 cs.From.Reg = v.Args[1].Reg() // old 727 cs.Reg = v.Args[2].Reg() // new 728 cs.To.Type = obj.TYPE_MEM 729 cs.To.Reg = v.Args[0].Reg() 730 gc.AddAux(&cs.To, v) 731 732 // MOVD $0, ret 733 movd := gc.Prog(s390x.AMOVD) 734 movd.From.Type = obj.TYPE_CONST 735 movd.From.Offset = 0 736 movd.To.Type = obj.TYPE_REG 737 movd.To.Reg = v.Reg0() 738 739 // BNE 2(PC) 740 bne := gc.Prog(s390x.ABNE) 741 bne.To.Type = obj.TYPE_BRANCH 742 743 // MOVD $1, ret 744 movd = gc.Prog(s390x.AMOVD) 745 movd.From.Type = obj.TYPE_CONST 746 movd.From.Offset = 1 747 movd.To.Type = obj.TYPE_REG 748 movd.To.Reg = v.Reg0() 749 750 // NOP (so the BNE has somewhere to land) 751 nop := gc.Prog(obj.ANOP) 752 gc.Patch(bne, nop) 753 case ssa.OpS390XLoweredAtomicExchange32, ssa.OpS390XLoweredAtomicExchange64: 754 // Loop until the CS{,G} succeeds. 755 // MOV{WZ,D} arg0, ret 756 // cs: CS{,G} ret, arg1, arg0 757 // BNE cs 758 759 // MOV{WZ,D} arg0, ret 760 load := gc.Prog(loadByType(v.Type.FieldType(0))) 761 load.From.Type = obj.TYPE_MEM 762 load.From.Reg = v.Args[0].Reg() 763 load.To.Type = obj.TYPE_REG 764 load.To.Reg = v.Reg0() 765 gc.AddAux(&load.From, v) 766 767 // CS{,G} ret, arg1, arg0 768 cs := gc.Prog(v.Op.Asm()) 769 cs.From.Type = obj.TYPE_REG 770 cs.From.Reg = v.Reg0() // old 771 cs.Reg = v.Args[1].Reg() // new 772 cs.To.Type = obj.TYPE_MEM 773 cs.To.Reg = v.Args[0].Reg() 774 gc.AddAux(&cs.To, v) 775 776 // BNE cs 777 bne := gc.Prog(s390x.ABNE) 778 bne.To.Type = obj.TYPE_BRANCH 779 gc.Patch(bne, cs) 780 default: 781 v.Fatalf("genValue not implemented: %s", v.LongString()) 782 } 783 } 784 785 var blockJump = [...]struct { 786 asm, invasm obj.As 787 }{ 788 ssa.BlockS390XEQ: {s390x.ABEQ, s390x.ABNE}, 789 ssa.BlockS390XNE: {s390x.ABNE, s390x.ABEQ}, 790 ssa.BlockS390XLT: {s390x.ABLT, s390x.ABGE}, 791 ssa.BlockS390XGE: {s390x.ABGE, s390x.ABLT}, 792 ssa.BlockS390XLE: {s390x.ABLE, s390x.ABGT}, 793 ssa.BlockS390XGT: {s390x.ABGT, s390x.ABLE}, 794 ssa.BlockS390XGTF: {s390x.ABGT, s390x.ABLEU}, 795 ssa.BlockS390XGEF: {s390x.ABGE, s390x.ABLTU}, 796 } 797 798 func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) { 799 s.SetLineno(b.Line) 800 801 switch b.Kind { 802 case ssa.BlockPlain: 803 if b.Succs[0].Block() != next { 804 p := gc.Prog(s390x.ABR) 805 p.To.Type = obj.TYPE_BRANCH 806 s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()}) 807 } 808 case ssa.BlockDefer: 809 // defer returns in R3: 810 // 0 if we should continue executing 811 // 1 if we should jump to deferreturn call 812 p := gc.Prog(s390x.ACMPW) 813 p.From.Type = obj.TYPE_REG 814 p.From.Reg = s390x.REG_R3 815 p.To.Type = obj.TYPE_CONST 816 p.To.Offset = 0 817 p = gc.Prog(s390x.ABNE) 818 p.To.Type = obj.TYPE_BRANCH 819 s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[1].Block()}) 820 if b.Succs[0].Block() != next { 821 p := gc.Prog(s390x.ABR) 822 p.To.Type = obj.TYPE_BRANCH 823 s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()}) 824 } 825 case ssa.BlockExit: 826 gc.Prog(obj.AUNDEF) // tell plive.go that we never reach here 827 case ssa.BlockRet: 828 gc.Prog(obj.ARET) 829 case ssa.BlockRetJmp: 830 p := gc.Prog(s390x.ABR) 831 p.To.Type = obj.TYPE_MEM 832 p.To.Name = obj.NAME_EXTERN 833 p.To.Sym = gc.Linksym(b.Aux.(*gc.Sym)) 834 case ssa.BlockS390XEQ, ssa.BlockS390XNE, 835 ssa.BlockS390XLT, ssa.BlockS390XGE, 836 ssa.BlockS390XLE, ssa.BlockS390XGT, 837 ssa.BlockS390XGEF, ssa.BlockS390XGTF: 838 jmp := blockJump[b.Kind] 839 likely := b.Likely 840 var p *obj.Prog 841 switch next { 842 case b.Succs[0].Block(): 843 p = gc.Prog(jmp.invasm) 844 likely *= -1 845 p.To.Type = obj.TYPE_BRANCH 846 s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[1].Block()}) 847 case b.Succs[1].Block(): 848 p = gc.Prog(jmp.asm) 849 p.To.Type = obj.TYPE_BRANCH 850 s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()}) 851 default: 852 p = gc.Prog(jmp.asm) 853 p.To.Type = obj.TYPE_BRANCH 854 s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()}) 855 q := gc.Prog(s390x.ABR) 856 q.To.Type = obj.TYPE_BRANCH 857 s.Branches = append(s.Branches, gc.Branch{P: q, B: b.Succs[1].Block()}) 858 } 859 default: 860 b.Fatalf("branch not implemented: %s. Control: %s", b.LongString(), b.Control.LongString()) 861 } 862 }