github.com/slayercat/go@v0.0.0-20170428012452-c51559813f61/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(s *gc.SSAGenState, op obj.As, dest, src int16) *obj.Prog { 136 p := s.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(s *gc.SSAGenState, op obj.As, dest, src int16, off int64) *obj.Prog { 149 p := s.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 switch v.Op { 160 case ssa.OpS390XSLD, ssa.OpS390XSLW, 161 ssa.OpS390XSRD, ssa.OpS390XSRW, 162 ssa.OpS390XSRAD, ssa.OpS390XSRAW: 163 r := v.Reg() 164 r1 := v.Args[0].Reg() 165 r2 := v.Args[1].Reg() 166 if r2 == s390x.REG_R0 { 167 v.Fatalf("cannot use R0 as shift value %s", v.LongString()) 168 } 169 p := opregreg(s, v.Op.Asm(), r, r2) 170 if r != r1 { 171 p.Reg = r1 172 } 173 case ssa.OpS390XADD, ssa.OpS390XADDW, 174 ssa.OpS390XSUB, ssa.OpS390XSUBW, 175 ssa.OpS390XAND, ssa.OpS390XANDW, 176 ssa.OpS390XOR, ssa.OpS390XORW, 177 ssa.OpS390XXOR, ssa.OpS390XXORW: 178 r := v.Reg() 179 r1 := v.Args[0].Reg() 180 r2 := v.Args[1].Reg() 181 p := opregreg(s, v.Op.Asm(), r, r2) 182 if r != r1 { 183 p.Reg = r1 184 } 185 // 2-address opcode arithmetic 186 case ssa.OpS390XMULLD, ssa.OpS390XMULLW, 187 ssa.OpS390XMULHD, ssa.OpS390XMULHDU, 188 ssa.OpS390XFADDS, ssa.OpS390XFADD, ssa.OpS390XFSUBS, ssa.OpS390XFSUB, 189 ssa.OpS390XFMULS, ssa.OpS390XFMUL, ssa.OpS390XFDIVS, ssa.OpS390XFDIV: 190 r := v.Reg() 191 if r != v.Args[0].Reg() { 192 v.Fatalf("input[0] and output not in same register %s", v.LongString()) 193 } 194 opregreg(s, v.Op.Asm(), r, v.Args[1].Reg()) 195 case ssa.OpS390XFMADD, ssa.OpS390XFMADDS, 196 ssa.OpS390XFMSUB, ssa.OpS390XFMSUBS: 197 r := v.Reg() 198 if r != v.Args[0].Reg() { 199 v.Fatalf("input[0] and output not in same register %s", v.LongString()) 200 } 201 r1 := v.Args[1].Reg() 202 r2 := v.Args[2].Reg() 203 p := s.Prog(v.Op.Asm()) 204 p.From.Type = obj.TYPE_REG 205 p.From.Reg = r1 206 p.Reg = r2 207 p.To.Type = obj.TYPE_REG 208 p.To.Reg = r 209 case ssa.OpS390XDIVD, ssa.OpS390XDIVW, 210 ssa.OpS390XDIVDU, ssa.OpS390XDIVWU, 211 ssa.OpS390XMODD, ssa.OpS390XMODW, 212 ssa.OpS390XMODDU, ssa.OpS390XMODWU: 213 214 // TODO(mundaym): use the temp registers every time like x86 does with AX? 215 dividend := v.Args[0].Reg() 216 divisor := v.Args[1].Reg() 217 218 // CPU faults upon signed overflow, which occurs when most 219 // negative int is divided by -1. 220 var j *obj.Prog 221 if v.Op == ssa.OpS390XDIVD || v.Op == ssa.OpS390XDIVW || 222 v.Op == ssa.OpS390XMODD || v.Op == ssa.OpS390XMODW { 223 224 var c *obj.Prog 225 c = s.Prog(s390x.ACMP) 226 j = s.Prog(s390x.ABEQ) 227 228 c.From.Type = obj.TYPE_REG 229 c.From.Reg = divisor 230 c.To.Type = obj.TYPE_CONST 231 c.To.Offset = -1 232 233 j.To.Type = obj.TYPE_BRANCH 234 235 } 236 237 p := s.Prog(v.Op.Asm()) 238 p.From.Type = obj.TYPE_REG 239 p.From.Reg = divisor 240 p.Reg = 0 241 p.To.Type = obj.TYPE_REG 242 p.To.Reg = dividend 243 244 // signed division, rest of the check for -1 case 245 if j != nil { 246 j2 := s.Prog(s390x.ABR) 247 j2.To.Type = obj.TYPE_BRANCH 248 249 var n *obj.Prog 250 if v.Op == ssa.OpS390XDIVD || v.Op == ssa.OpS390XDIVW { 251 // n * -1 = -n 252 n = s.Prog(s390x.ANEG) 253 n.To.Type = obj.TYPE_REG 254 n.To.Reg = dividend 255 } else { 256 // n % -1 == 0 257 n = s.Prog(s390x.AXOR) 258 n.From.Type = obj.TYPE_REG 259 n.From.Reg = dividend 260 n.To.Type = obj.TYPE_REG 261 n.To.Reg = dividend 262 } 263 264 j.To.Val = n 265 j2.To.Val = s.Pc() 266 } 267 case ssa.OpS390XADDconst, ssa.OpS390XADDWconst: 268 opregregimm(s, v.Op.Asm(), v.Reg(), v.Args[0].Reg(), v.AuxInt) 269 case ssa.OpS390XMULLDconst, ssa.OpS390XMULLWconst, 270 ssa.OpS390XSUBconst, ssa.OpS390XSUBWconst, 271 ssa.OpS390XANDconst, ssa.OpS390XANDWconst, 272 ssa.OpS390XORconst, ssa.OpS390XORWconst, 273 ssa.OpS390XXORconst, ssa.OpS390XXORWconst: 274 r := v.Reg() 275 if r != v.Args[0].Reg() { 276 v.Fatalf("input[0] and output not in same register %s", v.LongString()) 277 } 278 p := s.Prog(v.Op.Asm()) 279 p.From.Type = obj.TYPE_CONST 280 p.From.Offset = v.AuxInt 281 p.To.Type = obj.TYPE_REG 282 p.To.Reg = r 283 case ssa.OpS390XSLDconst, ssa.OpS390XSLWconst, 284 ssa.OpS390XSRDconst, ssa.OpS390XSRWconst, 285 ssa.OpS390XSRADconst, ssa.OpS390XSRAWconst, 286 ssa.OpS390XRLLGconst, ssa.OpS390XRLLconst: 287 p := s.Prog(v.Op.Asm()) 288 p.From.Type = obj.TYPE_CONST 289 p.From.Offset = v.AuxInt 290 r := v.Reg() 291 r1 := v.Args[0].Reg() 292 if r != r1 { 293 p.Reg = r1 294 } 295 p.To.Type = obj.TYPE_REG 296 p.To.Reg = r 297 case ssa.OpS390XSUBEcarrymask, ssa.OpS390XSUBEWcarrymask: 298 r := v.Reg() 299 p := s.Prog(v.Op.Asm()) 300 p.From.Type = obj.TYPE_REG 301 p.From.Reg = r 302 p.To.Type = obj.TYPE_REG 303 p.To.Reg = r 304 case ssa.OpS390XMOVDaddridx: 305 r := v.Args[0].Reg() 306 i := v.Args[1].Reg() 307 p := s.Prog(s390x.AMOVD) 308 p.From.Scale = 1 309 if i == s390x.REGSP { 310 r, i = i, r 311 } 312 p.From.Type = obj.TYPE_ADDR 313 p.From.Reg = r 314 p.From.Index = i 315 gc.AddAux(&p.From, v) 316 p.To.Type = obj.TYPE_REG 317 p.To.Reg = v.Reg() 318 case ssa.OpS390XMOVDaddr: 319 p := s.Prog(s390x.AMOVD) 320 p.From.Type = obj.TYPE_ADDR 321 p.From.Reg = v.Args[0].Reg() 322 gc.AddAux(&p.From, v) 323 p.To.Type = obj.TYPE_REG 324 p.To.Reg = v.Reg() 325 case ssa.OpS390XCMP, ssa.OpS390XCMPW, ssa.OpS390XCMPU, ssa.OpS390XCMPWU: 326 opregreg(s, v.Op.Asm(), v.Args[1].Reg(), v.Args[0].Reg()) 327 case ssa.OpS390XFCMPS, ssa.OpS390XFCMP: 328 opregreg(s, v.Op.Asm(), v.Args[1].Reg(), v.Args[0].Reg()) 329 case ssa.OpS390XCMPconst, ssa.OpS390XCMPWconst, ssa.OpS390XCMPUconst, ssa.OpS390XCMPWUconst: 330 p := s.Prog(v.Op.Asm()) 331 p.From.Type = obj.TYPE_REG 332 p.From.Reg = v.Args[0].Reg() 333 p.To.Type = obj.TYPE_CONST 334 p.To.Offset = v.AuxInt 335 case ssa.OpS390XMOVDconst: 336 x := v.Reg() 337 p := s.Prog(v.Op.Asm()) 338 p.From.Type = obj.TYPE_CONST 339 p.From.Offset = v.AuxInt 340 p.To.Type = obj.TYPE_REG 341 p.To.Reg = x 342 case ssa.OpS390XFMOVSconst, ssa.OpS390XFMOVDconst: 343 x := v.Reg() 344 p := s.Prog(v.Op.Asm()) 345 p.From.Type = obj.TYPE_FCONST 346 p.From.Val = math.Float64frombits(uint64(v.AuxInt)) 347 p.To.Type = obj.TYPE_REG 348 p.To.Reg = x 349 case ssa.OpS390XADDWload, ssa.OpS390XADDload, 350 ssa.OpS390XMULLWload, ssa.OpS390XMULLDload, 351 ssa.OpS390XSUBWload, ssa.OpS390XSUBload, 352 ssa.OpS390XANDWload, ssa.OpS390XANDload, 353 ssa.OpS390XORWload, ssa.OpS390XORload, 354 ssa.OpS390XXORWload, ssa.OpS390XXORload: 355 r := v.Reg() 356 if r != v.Args[0].Reg() { 357 v.Fatalf("input[0] and output not in same register %s", v.LongString()) 358 } 359 p := s.Prog(v.Op.Asm()) 360 p.From.Type = obj.TYPE_MEM 361 p.From.Reg = v.Args[1].Reg() 362 gc.AddAux(&p.From, v) 363 p.To.Type = obj.TYPE_REG 364 p.To.Reg = r 365 case ssa.OpS390XMOVDload, 366 ssa.OpS390XMOVWZload, ssa.OpS390XMOVHZload, ssa.OpS390XMOVBZload, 367 ssa.OpS390XMOVDBRload, ssa.OpS390XMOVWBRload, ssa.OpS390XMOVHBRload, 368 ssa.OpS390XMOVBload, ssa.OpS390XMOVHload, ssa.OpS390XMOVWload, 369 ssa.OpS390XFMOVSload, ssa.OpS390XFMOVDload: 370 p := s.Prog(v.Op.Asm()) 371 p.From.Type = obj.TYPE_MEM 372 p.From.Reg = v.Args[0].Reg() 373 gc.AddAux(&p.From, v) 374 p.To.Type = obj.TYPE_REG 375 p.To.Reg = v.Reg() 376 case ssa.OpS390XMOVBZloadidx, ssa.OpS390XMOVHZloadidx, ssa.OpS390XMOVWZloadidx, ssa.OpS390XMOVDloadidx, 377 ssa.OpS390XMOVHBRloadidx, ssa.OpS390XMOVWBRloadidx, ssa.OpS390XMOVDBRloadidx, 378 ssa.OpS390XFMOVSloadidx, ssa.OpS390XFMOVDloadidx: 379 r := v.Args[0].Reg() 380 i := v.Args[1].Reg() 381 if i == s390x.REGSP { 382 r, i = i, r 383 } 384 p := s.Prog(v.Op.Asm()) 385 p.From.Type = obj.TYPE_MEM 386 p.From.Reg = r 387 p.From.Scale = 1 388 p.From.Index = i 389 gc.AddAux(&p.From, v) 390 p.To.Type = obj.TYPE_REG 391 p.To.Reg = v.Reg() 392 case ssa.OpS390XMOVBstore, ssa.OpS390XMOVHstore, ssa.OpS390XMOVWstore, ssa.OpS390XMOVDstore, 393 ssa.OpS390XMOVHBRstore, ssa.OpS390XMOVWBRstore, ssa.OpS390XMOVDBRstore, 394 ssa.OpS390XFMOVSstore, ssa.OpS390XFMOVDstore: 395 p := s.Prog(v.Op.Asm()) 396 p.From.Type = obj.TYPE_REG 397 p.From.Reg = v.Args[1].Reg() 398 p.To.Type = obj.TYPE_MEM 399 p.To.Reg = v.Args[0].Reg() 400 gc.AddAux(&p.To, v) 401 case ssa.OpS390XMOVBstoreidx, ssa.OpS390XMOVHstoreidx, ssa.OpS390XMOVWstoreidx, ssa.OpS390XMOVDstoreidx, 402 ssa.OpS390XMOVHBRstoreidx, ssa.OpS390XMOVWBRstoreidx, ssa.OpS390XMOVDBRstoreidx, 403 ssa.OpS390XFMOVSstoreidx, ssa.OpS390XFMOVDstoreidx: 404 r := v.Args[0].Reg() 405 i := v.Args[1].Reg() 406 if i == s390x.REGSP { 407 r, i = i, r 408 } 409 p := s.Prog(v.Op.Asm()) 410 p.From.Type = obj.TYPE_REG 411 p.From.Reg = v.Args[2].Reg() 412 p.To.Type = obj.TYPE_MEM 413 p.To.Reg = r 414 p.To.Scale = 1 415 p.To.Index = i 416 gc.AddAux(&p.To, v) 417 case ssa.OpS390XMOVDstoreconst, ssa.OpS390XMOVWstoreconst, ssa.OpS390XMOVHstoreconst, ssa.OpS390XMOVBstoreconst: 418 p := s.Prog(v.Op.Asm()) 419 p.From.Type = obj.TYPE_CONST 420 sc := v.AuxValAndOff() 421 p.From.Offset = sc.Val() 422 p.To.Type = obj.TYPE_MEM 423 p.To.Reg = v.Args[0].Reg() 424 gc.AddAux2(&p.To, v, sc.Off()) 425 case ssa.OpS390XMOVBreg, ssa.OpS390XMOVHreg, ssa.OpS390XMOVWreg, 426 ssa.OpS390XMOVBZreg, ssa.OpS390XMOVHZreg, ssa.OpS390XMOVWZreg, 427 ssa.OpS390XCEFBRA, ssa.OpS390XCDFBRA, ssa.OpS390XCEGBRA, ssa.OpS390XCDGBRA, 428 ssa.OpS390XCFEBRA, ssa.OpS390XCFDBRA, ssa.OpS390XCGEBRA, ssa.OpS390XCGDBRA, 429 ssa.OpS390XLDEBR, ssa.OpS390XLEDBR, 430 ssa.OpS390XFNEG, ssa.OpS390XFNEGS: 431 opregreg(s, v.Op.Asm(), v.Reg(), v.Args[0].Reg()) 432 case ssa.OpS390XCLEAR: 433 p := s.Prog(v.Op.Asm()) 434 p.From.Type = obj.TYPE_CONST 435 sc := v.AuxValAndOff() 436 p.From.Offset = sc.Val() 437 p.To.Type = obj.TYPE_MEM 438 p.To.Reg = v.Args[0].Reg() 439 gc.AddAux2(&p.To, v, sc.Off()) 440 case ssa.OpCopy, ssa.OpS390XMOVDconvert, ssa.OpS390XMOVDreg: 441 if v.Type.IsMemory() { 442 return 443 } 444 x := v.Args[0].Reg() 445 y := v.Reg() 446 if x != y { 447 opregreg(s, moveByType(v.Type), y, x) 448 } 449 case ssa.OpS390XMOVDnop: 450 if v.Reg() != v.Args[0].Reg() { 451 v.Fatalf("input[0] and output not in same register %s", v.LongString()) 452 } 453 // nothing to do 454 case ssa.OpLoadReg: 455 if v.Type.IsFlags() { 456 v.Fatalf("load flags not implemented: %v", v.LongString()) 457 return 458 } 459 p := s.Prog(loadByType(v.Type)) 460 gc.AddrAuto(&p.From, v.Args[0]) 461 p.To.Type = obj.TYPE_REG 462 p.To.Reg = v.Reg() 463 case ssa.OpStoreReg: 464 if v.Type.IsFlags() { 465 v.Fatalf("store flags not implemented: %v", v.LongString()) 466 return 467 } 468 p := s.Prog(storeByType(v.Type)) 469 p.From.Type = obj.TYPE_REG 470 p.From.Reg = v.Args[0].Reg() 471 gc.AddrAuto(&p.To, v) 472 case ssa.OpS390XLoweredGetClosurePtr: 473 // Closure pointer is R12 (already) 474 gc.CheckLoweredGetClosurePtr(v) 475 case ssa.OpS390XLoweredRound32F, ssa.OpS390XLoweredRound64F: 476 // input is already rounded 477 case ssa.OpS390XLoweredGetG: 478 r := v.Reg() 479 p := s.Prog(s390x.AMOVD) 480 p.From.Type = obj.TYPE_REG 481 p.From.Reg = s390x.REGG 482 p.To.Type = obj.TYPE_REG 483 p.To.Reg = r 484 case ssa.OpS390XCALLstatic, ssa.OpS390XCALLclosure, ssa.OpS390XCALLinter: 485 s.Call(v) 486 case ssa.OpS390XFLOGR, ssa.OpS390XNEG, ssa.OpS390XNEGW, 487 ssa.OpS390XMOVWBR, ssa.OpS390XMOVDBR: 488 p := s.Prog(v.Op.Asm()) 489 p.From.Type = obj.TYPE_REG 490 p.From.Reg = v.Args[0].Reg() 491 p.To.Type = obj.TYPE_REG 492 p.To.Reg = v.Reg() 493 case ssa.OpS390XNOT, ssa.OpS390XNOTW: 494 v.Fatalf("NOT/NOTW generated %s", v.LongString()) 495 case ssa.OpS390XMOVDEQ, ssa.OpS390XMOVDNE, 496 ssa.OpS390XMOVDLT, ssa.OpS390XMOVDLE, 497 ssa.OpS390XMOVDGT, ssa.OpS390XMOVDGE, 498 ssa.OpS390XMOVDGTnoinv, ssa.OpS390XMOVDGEnoinv: 499 r := v.Reg() 500 if r != v.Args[0].Reg() { 501 v.Fatalf("input[0] and output not in same register %s", v.LongString()) 502 } 503 p := s.Prog(v.Op.Asm()) 504 p.From.Type = obj.TYPE_REG 505 p.From.Reg = v.Args[1].Reg() 506 p.To.Type = obj.TYPE_REG 507 p.To.Reg = r 508 case ssa.OpS390XFSQRT: 509 p := s.Prog(v.Op.Asm()) 510 p.From.Type = obj.TYPE_REG 511 p.From.Reg = v.Args[0].Reg() 512 p.To.Type = obj.TYPE_REG 513 p.To.Reg = v.Reg() 514 case ssa.OpS390XInvertFlags: 515 v.Fatalf("InvertFlags should never make it to codegen %v", v.LongString()) 516 case ssa.OpS390XFlagEQ, ssa.OpS390XFlagLT, ssa.OpS390XFlagGT: 517 v.Fatalf("Flag* ops should never make it to codegen %v", v.LongString()) 518 case ssa.OpS390XAddTupleFirst32, ssa.OpS390XAddTupleFirst64: 519 v.Fatalf("AddTupleFirst* should never make it to codegen %v", v.LongString()) 520 case ssa.OpS390XLoweredNilCheck: 521 // Issue a load which will fault if the input is nil. 522 p := s.Prog(s390x.AMOVBZ) 523 p.From.Type = obj.TYPE_MEM 524 p.From.Reg = v.Args[0].Reg() 525 gc.AddAux(&p.From, v) 526 p.To.Type = obj.TYPE_REG 527 p.To.Reg = s390x.REGTMP 528 if gc.Debug_checknil != 0 && v.Pos.Line() > 1 { // v.Pos.Line()==1 in generated wrappers 529 gc.Warnl(v.Pos, "generated nil check") 530 } 531 case ssa.OpS390XMVC: 532 vo := v.AuxValAndOff() 533 p := s.Prog(s390x.AMVC) 534 p.From.Type = obj.TYPE_CONST 535 p.From.Offset = vo.Val() 536 p.From3 = new(obj.Addr) 537 p.From3.Type = obj.TYPE_MEM 538 p.From3.Reg = v.Args[1].Reg() 539 p.From3.Offset = vo.Off() 540 p.To.Type = obj.TYPE_MEM 541 p.To.Reg = v.Args[0].Reg() 542 p.To.Offset = vo.Off() 543 case ssa.OpS390XSTMG2, ssa.OpS390XSTMG3, ssa.OpS390XSTMG4, 544 ssa.OpS390XSTM2, ssa.OpS390XSTM3, ssa.OpS390XSTM4: 545 for i := 2; i < len(v.Args)-1; i++ { 546 if v.Args[i].Reg() != v.Args[i-1].Reg()+1 { 547 v.Fatalf("invalid store multiple %s", v.LongString()) 548 } 549 } 550 p := s.Prog(v.Op.Asm()) 551 p.From.Type = obj.TYPE_REG 552 p.From.Reg = v.Args[1].Reg() 553 p.Reg = v.Args[len(v.Args)-2].Reg() 554 p.To.Type = obj.TYPE_MEM 555 p.To.Reg = v.Args[0].Reg() 556 gc.AddAux(&p.To, v) 557 case ssa.OpS390XLoweredMove: 558 // Inputs must be valid pointers to memory, 559 // so adjust arg0 and arg1 as part of the expansion. 560 // arg2 should be src+size, 561 // 562 // mvc: MVC $256, 0(R2), 0(R1) 563 // MOVD $256(R1), R1 564 // MOVD $256(R2), R2 565 // CMP R2, Rarg2 566 // BNE mvc 567 // MVC $rem, 0(R2), 0(R1) // if rem > 0 568 // arg2 is the last address to move in the loop + 256 569 mvc := s.Prog(s390x.AMVC) 570 mvc.From.Type = obj.TYPE_CONST 571 mvc.From.Offset = 256 572 mvc.From3 = new(obj.Addr) 573 mvc.From3.Type = obj.TYPE_MEM 574 mvc.From3.Reg = v.Args[1].Reg() 575 mvc.To.Type = obj.TYPE_MEM 576 mvc.To.Reg = v.Args[0].Reg() 577 578 for i := 0; i < 2; i++ { 579 movd := s.Prog(s390x.AMOVD) 580 movd.From.Type = obj.TYPE_ADDR 581 movd.From.Reg = v.Args[i].Reg() 582 movd.From.Offset = 256 583 movd.To.Type = obj.TYPE_REG 584 movd.To.Reg = v.Args[i].Reg() 585 } 586 587 cmpu := s.Prog(s390x.ACMPU) 588 cmpu.From.Reg = v.Args[1].Reg() 589 cmpu.From.Type = obj.TYPE_REG 590 cmpu.To.Reg = v.Args[2].Reg() 591 cmpu.To.Type = obj.TYPE_REG 592 593 bne := s.Prog(s390x.ABLT) 594 bne.To.Type = obj.TYPE_BRANCH 595 gc.Patch(bne, mvc) 596 597 if v.AuxInt > 0 { 598 mvc := s.Prog(s390x.AMVC) 599 mvc.From.Type = obj.TYPE_CONST 600 mvc.From.Offset = v.AuxInt 601 mvc.From3 = new(obj.Addr) 602 mvc.From3.Type = obj.TYPE_MEM 603 mvc.From3.Reg = v.Args[1].Reg() 604 mvc.To.Type = obj.TYPE_MEM 605 mvc.To.Reg = v.Args[0].Reg() 606 } 607 case ssa.OpS390XLoweredZero: 608 // Input must be valid pointers to memory, 609 // so adjust arg0 as part of the expansion. 610 // arg1 should be src+size, 611 // 612 // clear: CLEAR $256, 0(R1) 613 // MOVD $256(R1), R1 614 // CMP R1, Rarg1 615 // BNE clear 616 // CLEAR $rem, 0(R1) // if rem > 0 617 // arg1 is the last address to zero in the loop + 256 618 clear := s.Prog(s390x.ACLEAR) 619 clear.From.Type = obj.TYPE_CONST 620 clear.From.Offset = 256 621 clear.To.Type = obj.TYPE_MEM 622 clear.To.Reg = v.Args[0].Reg() 623 624 movd := s.Prog(s390x.AMOVD) 625 movd.From.Type = obj.TYPE_ADDR 626 movd.From.Reg = v.Args[0].Reg() 627 movd.From.Offset = 256 628 movd.To.Type = obj.TYPE_REG 629 movd.To.Reg = v.Args[0].Reg() 630 631 cmpu := s.Prog(s390x.ACMPU) 632 cmpu.From.Reg = v.Args[0].Reg() 633 cmpu.From.Type = obj.TYPE_REG 634 cmpu.To.Reg = v.Args[1].Reg() 635 cmpu.To.Type = obj.TYPE_REG 636 637 bne := s.Prog(s390x.ABLT) 638 bne.To.Type = obj.TYPE_BRANCH 639 gc.Patch(bne, clear) 640 641 if v.AuxInt > 0 { 642 clear := s.Prog(s390x.ACLEAR) 643 clear.From.Type = obj.TYPE_CONST 644 clear.From.Offset = v.AuxInt 645 clear.To.Type = obj.TYPE_MEM 646 clear.To.Reg = v.Args[0].Reg() 647 } 648 case ssa.OpS390XMOVWZatomicload, ssa.OpS390XMOVDatomicload: 649 p := s.Prog(v.Op.Asm()) 650 p.From.Type = obj.TYPE_MEM 651 p.From.Reg = v.Args[0].Reg() 652 gc.AddAux(&p.From, v) 653 p.To.Type = obj.TYPE_REG 654 p.To.Reg = v.Reg0() 655 case ssa.OpS390XMOVWatomicstore, ssa.OpS390XMOVDatomicstore: 656 p := s.Prog(v.Op.Asm()) 657 p.From.Type = obj.TYPE_REG 658 p.From.Reg = v.Args[1].Reg() 659 p.To.Type = obj.TYPE_MEM 660 p.To.Reg = v.Args[0].Reg() 661 gc.AddAux(&p.To, v) 662 case ssa.OpS390XLAA, ssa.OpS390XLAAG: 663 p := s.Prog(v.Op.Asm()) 664 p.Reg = v.Reg0() 665 p.From.Type = obj.TYPE_REG 666 p.From.Reg = v.Args[1].Reg() 667 p.To.Type = obj.TYPE_MEM 668 p.To.Reg = v.Args[0].Reg() 669 gc.AddAux(&p.To, v) 670 case ssa.OpS390XLoweredAtomicCas32, ssa.OpS390XLoweredAtomicCas64: 671 // Convert the flags output of CS{,G} into a bool. 672 // CS{,G} arg1, arg2, arg0 673 // MOVD $0, ret 674 // BNE 2(PC) 675 // MOVD $1, ret 676 // NOP (so the BNE has somewhere to land) 677 678 // CS{,G} arg1, arg2, arg0 679 cs := s.Prog(v.Op.Asm()) 680 cs.From.Type = obj.TYPE_REG 681 cs.From.Reg = v.Args[1].Reg() // old 682 cs.Reg = v.Args[2].Reg() // new 683 cs.To.Type = obj.TYPE_MEM 684 cs.To.Reg = v.Args[0].Reg() 685 gc.AddAux(&cs.To, v) 686 687 // MOVD $0, ret 688 movd := s.Prog(s390x.AMOVD) 689 movd.From.Type = obj.TYPE_CONST 690 movd.From.Offset = 0 691 movd.To.Type = obj.TYPE_REG 692 movd.To.Reg = v.Reg0() 693 694 // BNE 2(PC) 695 bne := s.Prog(s390x.ABNE) 696 bne.To.Type = obj.TYPE_BRANCH 697 698 // MOVD $1, ret 699 movd = s.Prog(s390x.AMOVD) 700 movd.From.Type = obj.TYPE_CONST 701 movd.From.Offset = 1 702 movd.To.Type = obj.TYPE_REG 703 movd.To.Reg = v.Reg0() 704 705 // NOP (so the BNE has somewhere to land) 706 nop := s.Prog(obj.ANOP) 707 gc.Patch(bne, nop) 708 case ssa.OpS390XLoweredAtomicExchange32, ssa.OpS390XLoweredAtomicExchange64: 709 // Loop until the CS{,G} succeeds. 710 // MOV{WZ,D} arg0, ret 711 // cs: CS{,G} ret, arg1, arg0 712 // BNE cs 713 714 // MOV{WZ,D} arg0, ret 715 load := s.Prog(loadByType(v.Type.FieldType(0))) 716 load.From.Type = obj.TYPE_MEM 717 load.From.Reg = v.Args[0].Reg() 718 load.To.Type = obj.TYPE_REG 719 load.To.Reg = v.Reg0() 720 gc.AddAux(&load.From, v) 721 722 // CS{,G} ret, arg1, arg0 723 cs := s.Prog(v.Op.Asm()) 724 cs.From.Type = obj.TYPE_REG 725 cs.From.Reg = v.Reg0() // old 726 cs.Reg = v.Args[1].Reg() // new 727 cs.To.Type = obj.TYPE_MEM 728 cs.To.Reg = v.Args[0].Reg() 729 gc.AddAux(&cs.To, v) 730 731 // BNE cs 732 bne := s.Prog(s390x.ABNE) 733 bne.To.Type = obj.TYPE_BRANCH 734 gc.Patch(bne, cs) 735 case ssa.OpClobber: 736 // TODO: implement for clobberdead experiment. Nop is ok for now. 737 default: 738 v.Fatalf("genValue not implemented: %s", v.LongString()) 739 } 740 } 741 742 var blockJump = [...]struct { 743 asm, invasm obj.As 744 }{ 745 ssa.BlockS390XEQ: {s390x.ABEQ, s390x.ABNE}, 746 ssa.BlockS390XNE: {s390x.ABNE, s390x.ABEQ}, 747 ssa.BlockS390XLT: {s390x.ABLT, s390x.ABGE}, 748 ssa.BlockS390XGE: {s390x.ABGE, s390x.ABLT}, 749 ssa.BlockS390XLE: {s390x.ABLE, s390x.ABGT}, 750 ssa.BlockS390XGT: {s390x.ABGT, s390x.ABLE}, 751 ssa.BlockS390XGTF: {s390x.ABGT, s390x.ABLEU}, 752 ssa.BlockS390XGEF: {s390x.ABGE, s390x.ABLTU}, 753 } 754 755 func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) { 756 switch b.Kind { 757 case ssa.BlockPlain: 758 if b.Succs[0].Block() != next { 759 p := s.Prog(s390x.ABR) 760 p.To.Type = obj.TYPE_BRANCH 761 s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()}) 762 } 763 case ssa.BlockDefer: 764 // defer returns in R3: 765 // 0 if we should continue executing 766 // 1 if we should jump to deferreturn call 767 p := s.Prog(s390x.ACMPW) 768 p.From.Type = obj.TYPE_REG 769 p.From.Reg = s390x.REG_R3 770 p.To.Type = obj.TYPE_CONST 771 p.To.Offset = 0 772 p = s.Prog(s390x.ABNE) 773 p.To.Type = obj.TYPE_BRANCH 774 s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[1].Block()}) 775 if b.Succs[0].Block() != next { 776 p := s.Prog(s390x.ABR) 777 p.To.Type = obj.TYPE_BRANCH 778 s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()}) 779 } 780 case ssa.BlockExit: 781 s.Prog(obj.AUNDEF) // tell plive.go that we never reach here 782 case ssa.BlockRet: 783 s.Prog(obj.ARET) 784 case ssa.BlockRetJmp: 785 p := s.Prog(s390x.ABR) 786 p.To.Type = obj.TYPE_MEM 787 p.To.Name = obj.NAME_EXTERN 788 p.To.Sym = b.Aux.(*obj.LSym) 789 case ssa.BlockS390XEQ, ssa.BlockS390XNE, 790 ssa.BlockS390XLT, ssa.BlockS390XGE, 791 ssa.BlockS390XLE, ssa.BlockS390XGT, 792 ssa.BlockS390XGEF, ssa.BlockS390XGTF: 793 jmp := blockJump[b.Kind] 794 var p *obj.Prog 795 switch next { 796 case b.Succs[0].Block(): 797 p = s.Prog(jmp.invasm) 798 p.To.Type = obj.TYPE_BRANCH 799 s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[1].Block()}) 800 case b.Succs[1].Block(): 801 p = s.Prog(jmp.asm) 802 p.To.Type = obj.TYPE_BRANCH 803 s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()}) 804 default: 805 p = s.Prog(jmp.asm) 806 p.To.Type = obj.TYPE_BRANCH 807 s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()}) 808 q := s.Prog(s390x.ABR) 809 q.To.Type = obj.TYPE_BRANCH 810 s.Branches = append(s.Branches, gc.Branch{P: q, B: b.Succs[1].Block()}) 811 } 812 default: 813 b.Fatalf("branch not implemented: %s. Control: %s", b.LongString(), b.Control.LongString()) 814 } 815 }