github.com/gagliardetto/golang-go@v0.0.0-20201020153340-53909ea70814/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 "github.com/gagliardetto/golang-go/cmd/compile/internal/gc" 11 "github.com/gagliardetto/golang-go/cmd/compile/internal/logopt" 12 "github.com/gagliardetto/golang-go/cmd/compile/internal/ssa" 13 "github.com/gagliardetto/golang-go/cmd/compile/internal/types" 14 "github.com/gagliardetto/golang-go/cmd/internal/obj" 15 "github.com/gagliardetto/golang-go/cmd/internal/obj/s390x" 16 ) 17 18 // markMoves marks any MOVXconst ops that need to avoid clobbering flags. 19 func ssaMarkMoves(s *gc.SSAGenState, b *ssa.Block) { 20 flive := b.FlagsLiveAtEnd 21 for _, c := range b.ControlValues() { 22 flive = c.Type.IsFlags() || flive 23 } 24 for i := len(b.Values) - 1; i >= 0; i-- { 25 v := b.Values[i] 26 if flive && v.Op == ssa.OpS390XMOVDconst { 27 // The "mark" is any non-nil Aux value. 28 v.Aux = v 29 } 30 if v.Type.IsFlags() { 31 flive = false 32 } 33 for _, a := range v.Args { 34 if a.Type.IsFlags() { 35 flive = true 36 } 37 } 38 } 39 } 40 41 // loadByType returns the load instruction of the given type. 42 func loadByType(t *types.Type) obj.As { 43 if t.IsFloat() { 44 switch t.Size() { 45 case 4: 46 return s390x.AFMOVS 47 case 8: 48 return s390x.AFMOVD 49 } 50 } else { 51 switch t.Size() { 52 case 1: 53 if t.IsSigned() { 54 return s390x.AMOVB 55 } else { 56 return s390x.AMOVBZ 57 } 58 case 2: 59 if t.IsSigned() { 60 return s390x.AMOVH 61 } else { 62 return s390x.AMOVHZ 63 } 64 case 4: 65 if t.IsSigned() { 66 return s390x.AMOVW 67 } else { 68 return s390x.AMOVWZ 69 } 70 case 8: 71 return s390x.AMOVD 72 } 73 } 74 panic("bad load type") 75 } 76 77 // storeByType returns the store instruction of the given type. 78 func storeByType(t *types.Type) obj.As { 79 width := t.Size() 80 if t.IsFloat() { 81 switch width { 82 case 4: 83 return s390x.AFMOVS 84 case 8: 85 return s390x.AFMOVD 86 } 87 } else { 88 switch width { 89 case 1: 90 return s390x.AMOVB 91 case 2: 92 return s390x.AMOVH 93 case 4: 94 return s390x.AMOVW 95 case 8: 96 return s390x.AMOVD 97 } 98 } 99 panic("bad store type") 100 } 101 102 // moveByType returns the reg->reg move instruction of the given type. 103 func moveByType(t *types.Type) obj.As { 104 if t.IsFloat() { 105 return s390x.AFMOVD 106 } else { 107 switch t.Size() { 108 case 1: 109 if t.IsSigned() { 110 return s390x.AMOVB 111 } else { 112 return s390x.AMOVBZ 113 } 114 case 2: 115 if t.IsSigned() { 116 return s390x.AMOVH 117 } else { 118 return s390x.AMOVHZ 119 } 120 case 4: 121 if t.IsSigned() { 122 return s390x.AMOVW 123 } else { 124 return s390x.AMOVWZ 125 } 126 case 8: 127 return s390x.AMOVD 128 } 129 } 130 panic("bad load type") 131 } 132 133 // opregreg emits instructions for 134 // dest := dest(To) op src(From) 135 // and also returns the created obj.Prog so it 136 // may be further adjusted (offset, scale, etc). 137 func opregreg(s *gc.SSAGenState, op obj.As, dest, src int16) *obj.Prog { 138 p := s.Prog(op) 139 p.From.Type = obj.TYPE_REG 140 p.To.Type = obj.TYPE_REG 141 p.To.Reg = dest 142 p.From.Reg = src 143 return p 144 } 145 146 // opregregimm emits instructions for 147 // dest := src(From) op off 148 // and also returns the created obj.Prog so it 149 // may be further adjusted (offset, scale, etc). 150 func opregregimm(s *gc.SSAGenState, op obj.As, dest, src int16, off int64) *obj.Prog { 151 p := s.Prog(op) 152 p.From.Type = obj.TYPE_CONST 153 p.From.Offset = off 154 p.Reg = src 155 p.To.Reg = dest 156 p.To.Type = obj.TYPE_REG 157 return p 158 } 159 160 func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) { 161 switch v.Op { 162 case ssa.OpS390XSLD, ssa.OpS390XSLW, 163 ssa.OpS390XSRD, ssa.OpS390XSRW, 164 ssa.OpS390XSRAD, ssa.OpS390XSRAW, 165 ssa.OpS390XRLLG, ssa.OpS390XRLL: 166 r := v.Reg() 167 r1 := v.Args[0].Reg() 168 r2 := v.Args[1].Reg() 169 if r2 == s390x.REG_R0 { 170 v.Fatalf("cannot use R0 as shift value %s", v.LongString()) 171 } 172 p := opregreg(s, v.Op.Asm(), r, r2) 173 if r != r1 { 174 p.Reg = r1 175 } 176 case ssa.OpS390XRXSBG: 177 r1 := v.Reg() 178 if r1 != v.Args[0].Reg() { 179 v.Fatalf("input[0] and output not in same register %s", v.LongString()) 180 } 181 r2 := v.Args[1].Reg() 182 i := v.Aux.(s390x.RotateParams) 183 p := s.Prog(v.Op.Asm()) 184 p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: int64(i.Start)} 185 p.RestArgs = []obj.Addr{ 186 {Type: obj.TYPE_CONST, Offset: int64(i.End)}, 187 {Type: obj.TYPE_CONST, Offset: int64(i.Amount)}, 188 {Type: obj.TYPE_REG, Reg: r2}, 189 } 190 p.To = obj.Addr{Type: obj.TYPE_REG, Reg: r1} 191 case ssa.OpS390XADD, ssa.OpS390XADDW, 192 ssa.OpS390XSUB, ssa.OpS390XSUBW, 193 ssa.OpS390XAND, ssa.OpS390XANDW, 194 ssa.OpS390XOR, ssa.OpS390XORW, 195 ssa.OpS390XXOR, ssa.OpS390XXORW: 196 r := v.Reg() 197 r1 := v.Args[0].Reg() 198 r2 := v.Args[1].Reg() 199 p := opregreg(s, v.Op.Asm(), r, r2) 200 if r != r1 { 201 p.Reg = r1 202 } 203 case ssa.OpS390XADDC: 204 r1 := v.Reg0() 205 r2 := v.Args[0].Reg() 206 r3 := v.Args[1].Reg() 207 if r1 == r2 { 208 r2, r3 = r3, r2 209 } 210 p := opregreg(s, v.Op.Asm(), r1, r2) 211 if r3 != r1 { 212 p.Reg = r3 213 } 214 case ssa.OpS390XSUBC: 215 r1 := v.Reg0() 216 r2 := v.Args[0].Reg() 217 r3 := v.Args[1].Reg() 218 p := opregreg(s, v.Op.Asm(), r1, r3) 219 if r1 != r2 { 220 p.Reg = r2 221 } 222 case ssa.OpS390XADDE, ssa.OpS390XSUBE: 223 r1 := v.Reg0() 224 if r1 != v.Args[0].Reg() { 225 v.Fatalf("input[0] and output not in same register %s", v.LongString()) 226 } 227 r2 := v.Args[1].Reg() 228 opregreg(s, v.Op.Asm(), r1, r2) 229 case ssa.OpS390XADDCconst: 230 r1 := v.Reg0() 231 r3 := v.Args[0].Reg() 232 i2 := int64(int16(v.AuxInt)) 233 opregregimm(s, v.Op.Asm(), r1, r3, i2) 234 // 2-address opcode arithmetic 235 case ssa.OpS390XMULLD, ssa.OpS390XMULLW, 236 ssa.OpS390XMULHD, ssa.OpS390XMULHDU, 237 ssa.OpS390XFADDS, ssa.OpS390XFADD, ssa.OpS390XFSUBS, ssa.OpS390XFSUB, 238 ssa.OpS390XFMULS, ssa.OpS390XFMUL, ssa.OpS390XFDIVS, ssa.OpS390XFDIV: 239 r := v.Reg() 240 if r != v.Args[0].Reg() { 241 v.Fatalf("input[0] and output not in same register %s", v.LongString()) 242 } 243 opregreg(s, v.Op.Asm(), r, v.Args[1].Reg()) 244 case ssa.OpS390XMLGR: 245 // MLGR Rx R3 -> R2:R3 246 r0 := v.Args[0].Reg() 247 r1 := v.Args[1].Reg() 248 if r1 != s390x.REG_R3 { 249 v.Fatalf("We require the multiplcand to be stored in R3 for MLGR %s", v.LongString()) 250 } 251 p := s.Prog(s390x.AMLGR) 252 p.From.Type = obj.TYPE_REG 253 p.From.Reg = r0 254 p.To.Reg = s390x.REG_R2 255 p.To.Type = obj.TYPE_REG 256 case ssa.OpS390XFMADD, ssa.OpS390XFMADDS, 257 ssa.OpS390XFMSUB, ssa.OpS390XFMSUBS: 258 r := v.Reg() 259 if r != v.Args[0].Reg() { 260 v.Fatalf("input[0] and output not in same register %s", v.LongString()) 261 } 262 r1 := v.Args[1].Reg() 263 r2 := v.Args[2].Reg() 264 p := s.Prog(v.Op.Asm()) 265 p.From.Type = obj.TYPE_REG 266 p.From.Reg = r1 267 p.Reg = r2 268 p.To.Type = obj.TYPE_REG 269 p.To.Reg = r 270 case ssa.OpS390XFIDBR: 271 switch v.AuxInt { 272 case 0, 1, 3, 4, 5, 6, 7: 273 opregregimm(s, v.Op.Asm(), v.Reg(), v.Args[0].Reg(), v.AuxInt) 274 default: 275 v.Fatalf("invalid FIDBR mask: %v", v.AuxInt) 276 } 277 case ssa.OpS390XCPSDR: 278 p := opregreg(s, v.Op.Asm(), v.Reg(), v.Args[1].Reg()) 279 p.Reg = v.Args[0].Reg() 280 case ssa.OpS390XDIVD, ssa.OpS390XDIVW, 281 ssa.OpS390XDIVDU, ssa.OpS390XDIVWU, 282 ssa.OpS390XMODD, ssa.OpS390XMODW, 283 ssa.OpS390XMODDU, ssa.OpS390XMODWU: 284 285 // TODO(mundaym): use the temp registers every time like x86 does with AX? 286 dividend := v.Args[0].Reg() 287 divisor := v.Args[1].Reg() 288 289 // CPU faults upon signed overflow, which occurs when most 290 // negative int is divided by -1. 291 var j *obj.Prog 292 if v.Op == ssa.OpS390XDIVD || v.Op == ssa.OpS390XDIVW || 293 v.Op == ssa.OpS390XMODD || v.Op == ssa.OpS390XMODW { 294 295 var c *obj.Prog 296 c = s.Prog(s390x.ACMP) 297 j = s.Prog(s390x.ABEQ) 298 299 c.From.Type = obj.TYPE_REG 300 c.From.Reg = divisor 301 c.To.Type = obj.TYPE_CONST 302 c.To.Offset = -1 303 304 j.To.Type = obj.TYPE_BRANCH 305 306 } 307 308 p := s.Prog(v.Op.Asm()) 309 p.From.Type = obj.TYPE_REG 310 p.From.Reg = divisor 311 p.Reg = 0 312 p.To.Type = obj.TYPE_REG 313 p.To.Reg = dividend 314 315 // signed division, rest of the check for -1 case 316 if j != nil { 317 j2 := s.Prog(s390x.ABR) 318 j2.To.Type = obj.TYPE_BRANCH 319 320 var n *obj.Prog 321 if v.Op == ssa.OpS390XDIVD || v.Op == ssa.OpS390XDIVW { 322 // n * -1 = -n 323 n = s.Prog(s390x.ANEG) 324 n.To.Type = obj.TYPE_REG 325 n.To.Reg = dividend 326 } else { 327 // n % -1 == 0 328 n = s.Prog(s390x.AXOR) 329 n.From.Type = obj.TYPE_REG 330 n.From.Reg = dividend 331 n.To.Type = obj.TYPE_REG 332 n.To.Reg = dividend 333 } 334 335 j.To.Val = n 336 j2.To.Val = s.Pc() 337 } 338 case ssa.OpS390XADDconst, ssa.OpS390XADDWconst: 339 opregregimm(s, v.Op.Asm(), v.Reg(), v.Args[0].Reg(), v.AuxInt) 340 case ssa.OpS390XMULLDconst, ssa.OpS390XMULLWconst, 341 ssa.OpS390XSUBconst, ssa.OpS390XSUBWconst, 342 ssa.OpS390XANDconst, ssa.OpS390XANDWconst, 343 ssa.OpS390XORconst, ssa.OpS390XORWconst, 344 ssa.OpS390XXORconst, ssa.OpS390XXORWconst: 345 r := v.Reg() 346 if r != v.Args[0].Reg() { 347 v.Fatalf("input[0] and output not in same register %s", v.LongString()) 348 } 349 p := s.Prog(v.Op.Asm()) 350 p.From.Type = obj.TYPE_CONST 351 p.From.Offset = v.AuxInt 352 p.To.Type = obj.TYPE_REG 353 p.To.Reg = r 354 case ssa.OpS390XSLDconst, ssa.OpS390XSLWconst, 355 ssa.OpS390XSRDconst, ssa.OpS390XSRWconst, 356 ssa.OpS390XSRADconst, ssa.OpS390XSRAWconst, 357 ssa.OpS390XRLLGconst, ssa.OpS390XRLLconst: 358 p := s.Prog(v.Op.Asm()) 359 p.From.Type = obj.TYPE_CONST 360 p.From.Offset = v.AuxInt 361 r := v.Reg() 362 r1 := v.Args[0].Reg() 363 if r != r1 { 364 p.Reg = r1 365 } 366 p.To.Type = obj.TYPE_REG 367 p.To.Reg = r 368 case ssa.OpS390XMOVDaddridx: 369 r := v.Args[0].Reg() 370 i := v.Args[1].Reg() 371 p := s.Prog(s390x.AMOVD) 372 p.From.Scale = 1 373 if i == s390x.REGSP { 374 r, i = i, r 375 } 376 p.From.Type = obj.TYPE_ADDR 377 p.From.Reg = r 378 p.From.Index = i 379 gc.AddAux(&p.From, v) 380 p.To.Type = obj.TYPE_REG 381 p.To.Reg = v.Reg() 382 case ssa.OpS390XMOVDaddr: 383 p := s.Prog(s390x.AMOVD) 384 p.From.Type = obj.TYPE_ADDR 385 p.From.Reg = v.Args[0].Reg() 386 gc.AddAux(&p.From, v) 387 p.To.Type = obj.TYPE_REG 388 p.To.Reg = v.Reg() 389 case ssa.OpS390XCMP, ssa.OpS390XCMPW, ssa.OpS390XCMPU, ssa.OpS390XCMPWU: 390 opregreg(s, v.Op.Asm(), v.Args[1].Reg(), v.Args[0].Reg()) 391 case ssa.OpS390XFCMPS, ssa.OpS390XFCMP: 392 opregreg(s, v.Op.Asm(), v.Args[1].Reg(), v.Args[0].Reg()) 393 case ssa.OpS390XCMPconst, ssa.OpS390XCMPWconst: 394 p := s.Prog(v.Op.Asm()) 395 p.From.Type = obj.TYPE_REG 396 p.From.Reg = v.Args[0].Reg() 397 p.To.Type = obj.TYPE_CONST 398 p.To.Offset = v.AuxInt 399 case ssa.OpS390XCMPUconst, ssa.OpS390XCMPWUconst: 400 p := s.Prog(v.Op.Asm()) 401 p.From.Type = obj.TYPE_REG 402 p.From.Reg = v.Args[0].Reg() 403 p.To.Type = obj.TYPE_CONST 404 p.To.Offset = int64(uint32(v.AuxInt)) 405 case ssa.OpS390XMOVDconst: 406 x := v.Reg() 407 p := s.Prog(v.Op.Asm()) 408 p.From.Type = obj.TYPE_CONST 409 p.From.Offset = v.AuxInt 410 p.To.Type = obj.TYPE_REG 411 p.To.Reg = x 412 case ssa.OpS390XFMOVSconst, ssa.OpS390XFMOVDconst: 413 x := v.Reg() 414 p := s.Prog(v.Op.Asm()) 415 p.From.Type = obj.TYPE_FCONST 416 p.From.Val = math.Float64frombits(uint64(v.AuxInt)) 417 p.To.Type = obj.TYPE_REG 418 p.To.Reg = x 419 case ssa.OpS390XADDWload, ssa.OpS390XADDload, 420 ssa.OpS390XMULLWload, ssa.OpS390XMULLDload, 421 ssa.OpS390XSUBWload, ssa.OpS390XSUBload, 422 ssa.OpS390XANDWload, ssa.OpS390XANDload, 423 ssa.OpS390XORWload, ssa.OpS390XORload, 424 ssa.OpS390XXORWload, ssa.OpS390XXORload: 425 r := v.Reg() 426 if r != v.Args[0].Reg() { 427 v.Fatalf("input[0] and output not in same register %s", v.LongString()) 428 } 429 p := s.Prog(v.Op.Asm()) 430 p.From.Type = obj.TYPE_MEM 431 p.From.Reg = v.Args[1].Reg() 432 gc.AddAux(&p.From, v) 433 p.To.Type = obj.TYPE_REG 434 p.To.Reg = r 435 case ssa.OpS390XMOVDload, 436 ssa.OpS390XMOVWZload, ssa.OpS390XMOVHZload, ssa.OpS390XMOVBZload, 437 ssa.OpS390XMOVDBRload, ssa.OpS390XMOVWBRload, ssa.OpS390XMOVHBRload, 438 ssa.OpS390XMOVBload, ssa.OpS390XMOVHload, ssa.OpS390XMOVWload, 439 ssa.OpS390XFMOVSload, ssa.OpS390XFMOVDload: 440 p := s.Prog(v.Op.Asm()) 441 p.From.Type = obj.TYPE_MEM 442 p.From.Reg = v.Args[0].Reg() 443 gc.AddAux(&p.From, v) 444 p.To.Type = obj.TYPE_REG 445 p.To.Reg = v.Reg() 446 case ssa.OpS390XMOVBZloadidx, ssa.OpS390XMOVHZloadidx, ssa.OpS390XMOVWZloadidx, 447 ssa.OpS390XMOVBloadidx, ssa.OpS390XMOVHloadidx, ssa.OpS390XMOVWloadidx, ssa.OpS390XMOVDloadidx, 448 ssa.OpS390XMOVHBRloadidx, ssa.OpS390XMOVWBRloadidx, ssa.OpS390XMOVDBRloadidx, 449 ssa.OpS390XFMOVSloadidx, ssa.OpS390XFMOVDloadidx: 450 r := v.Args[0].Reg() 451 i := v.Args[1].Reg() 452 if i == s390x.REGSP { 453 r, i = i, r 454 } 455 p := s.Prog(v.Op.Asm()) 456 p.From.Type = obj.TYPE_MEM 457 p.From.Reg = r 458 p.From.Scale = 1 459 p.From.Index = i 460 gc.AddAux(&p.From, v) 461 p.To.Type = obj.TYPE_REG 462 p.To.Reg = v.Reg() 463 case ssa.OpS390XMOVBstore, ssa.OpS390XMOVHstore, ssa.OpS390XMOVWstore, ssa.OpS390XMOVDstore, 464 ssa.OpS390XMOVHBRstore, ssa.OpS390XMOVWBRstore, ssa.OpS390XMOVDBRstore, 465 ssa.OpS390XFMOVSstore, ssa.OpS390XFMOVDstore: 466 p := s.Prog(v.Op.Asm()) 467 p.From.Type = obj.TYPE_REG 468 p.From.Reg = v.Args[1].Reg() 469 p.To.Type = obj.TYPE_MEM 470 p.To.Reg = v.Args[0].Reg() 471 gc.AddAux(&p.To, v) 472 case ssa.OpS390XMOVBstoreidx, ssa.OpS390XMOVHstoreidx, ssa.OpS390XMOVWstoreidx, ssa.OpS390XMOVDstoreidx, 473 ssa.OpS390XMOVHBRstoreidx, ssa.OpS390XMOVWBRstoreidx, ssa.OpS390XMOVDBRstoreidx, 474 ssa.OpS390XFMOVSstoreidx, ssa.OpS390XFMOVDstoreidx: 475 r := v.Args[0].Reg() 476 i := v.Args[1].Reg() 477 if i == s390x.REGSP { 478 r, i = i, r 479 } 480 p := s.Prog(v.Op.Asm()) 481 p.From.Type = obj.TYPE_REG 482 p.From.Reg = v.Args[2].Reg() 483 p.To.Type = obj.TYPE_MEM 484 p.To.Reg = r 485 p.To.Scale = 1 486 p.To.Index = i 487 gc.AddAux(&p.To, v) 488 case ssa.OpS390XMOVDstoreconst, ssa.OpS390XMOVWstoreconst, ssa.OpS390XMOVHstoreconst, ssa.OpS390XMOVBstoreconst: 489 p := s.Prog(v.Op.Asm()) 490 p.From.Type = obj.TYPE_CONST 491 sc := v.AuxValAndOff() 492 p.From.Offset = sc.Val() 493 p.To.Type = obj.TYPE_MEM 494 p.To.Reg = v.Args[0].Reg() 495 gc.AddAux2(&p.To, v, sc.Off()) 496 case ssa.OpS390XMOVBreg, ssa.OpS390XMOVHreg, ssa.OpS390XMOVWreg, 497 ssa.OpS390XMOVBZreg, ssa.OpS390XMOVHZreg, ssa.OpS390XMOVWZreg, 498 ssa.OpS390XLDGR, ssa.OpS390XLGDR, 499 ssa.OpS390XCEFBRA, ssa.OpS390XCDFBRA, ssa.OpS390XCEGBRA, ssa.OpS390XCDGBRA, 500 ssa.OpS390XCFEBRA, ssa.OpS390XCFDBRA, ssa.OpS390XCGEBRA, ssa.OpS390XCGDBRA, 501 ssa.OpS390XLDEBR, ssa.OpS390XLEDBR, 502 ssa.OpS390XFNEG, ssa.OpS390XFNEGS, 503 ssa.OpS390XLPDFR, ssa.OpS390XLNDFR: 504 opregreg(s, v.Op.Asm(), v.Reg(), v.Args[0].Reg()) 505 case ssa.OpS390XCLEAR: 506 p := s.Prog(v.Op.Asm()) 507 p.From.Type = obj.TYPE_CONST 508 sc := v.AuxValAndOff() 509 p.From.Offset = sc.Val() 510 p.To.Type = obj.TYPE_MEM 511 p.To.Reg = v.Args[0].Reg() 512 gc.AddAux2(&p.To, v, sc.Off()) 513 case ssa.OpCopy: 514 if v.Type.IsMemory() { 515 return 516 } 517 x := v.Args[0].Reg() 518 y := v.Reg() 519 if x != y { 520 opregreg(s, moveByType(v.Type), y, x) 521 } 522 case ssa.OpLoadReg: 523 if v.Type.IsFlags() { 524 v.Fatalf("load flags not implemented: %v", v.LongString()) 525 return 526 } 527 p := s.Prog(loadByType(v.Type)) 528 gc.AddrAuto(&p.From, v.Args[0]) 529 p.To.Type = obj.TYPE_REG 530 p.To.Reg = v.Reg() 531 case ssa.OpStoreReg: 532 if v.Type.IsFlags() { 533 v.Fatalf("store flags not implemented: %v", v.LongString()) 534 return 535 } 536 p := s.Prog(storeByType(v.Type)) 537 p.From.Type = obj.TYPE_REG 538 p.From.Reg = v.Args[0].Reg() 539 gc.AddrAuto(&p.To, v) 540 case ssa.OpS390XLoweredGetClosurePtr: 541 // Closure pointer is R12 (already) 542 gc.CheckLoweredGetClosurePtr(v) 543 case ssa.OpS390XLoweredRound32F, ssa.OpS390XLoweredRound64F: 544 // input is already rounded 545 case ssa.OpS390XLoweredGetG: 546 r := v.Reg() 547 p := s.Prog(s390x.AMOVD) 548 p.From.Type = obj.TYPE_REG 549 p.From.Reg = s390x.REGG 550 p.To.Type = obj.TYPE_REG 551 p.To.Reg = r 552 case ssa.OpS390XLoweredGetCallerSP: 553 // caller's SP is FixedFrameSize below the address of the first arg 554 p := s.Prog(s390x.AMOVD) 555 p.From.Type = obj.TYPE_ADDR 556 p.From.Offset = -gc.Ctxt.FixedFrameSize() 557 p.From.Name = obj.NAME_PARAM 558 p.To.Type = obj.TYPE_REG 559 p.To.Reg = v.Reg() 560 case ssa.OpS390XLoweredGetCallerPC: 561 p := s.Prog(obj.AGETCALLERPC) 562 p.To.Type = obj.TYPE_REG 563 p.To.Reg = v.Reg() 564 case ssa.OpS390XCALLstatic, ssa.OpS390XCALLclosure, ssa.OpS390XCALLinter: 565 s.Call(v) 566 case ssa.OpS390XLoweredWB: 567 p := s.Prog(obj.ACALL) 568 p.To.Type = obj.TYPE_MEM 569 p.To.Name = obj.NAME_EXTERN 570 p.To.Sym = v.Aux.(*obj.LSym) 571 case ssa.OpS390XLoweredPanicBoundsA, ssa.OpS390XLoweredPanicBoundsB, ssa.OpS390XLoweredPanicBoundsC: 572 p := s.Prog(obj.ACALL) 573 p.To.Type = obj.TYPE_MEM 574 p.To.Name = obj.NAME_EXTERN 575 p.To.Sym = gc.BoundsCheckFunc[v.AuxInt] 576 s.UseArgs(16) // space used in callee args area by assembly stubs 577 case ssa.OpS390XFLOGR, ssa.OpS390XPOPCNT, 578 ssa.OpS390XNEG, ssa.OpS390XNEGW, 579 ssa.OpS390XMOVWBR, ssa.OpS390XMOVDBR: 580 p := s.Prog(v.Op.Asm()) 581 p.From.Type = obj.TYPE_REG 582 p.From.Reg = v.Args[0].Reg() 583 p.To.Type = obj.TYPE_REG 584 p.To.Reg = v.Reg() 585 case ssa.OpS390XNOT, ssa.OpS390XNOTW: 586 v.Fatalf("NOT/NOTW generated %s", v.LongString()) 587 case ssa.OpS390XSumBytes2, ssa.OpS390XSumBytes4, ssa.OpS390XSumBytes8: 588 v.Fatalf("SumBytes generated %s", v.LongString()) 589 case ssa.OpS390XLOCGR: 590 r := v.Reg() 591 if r != v.Args[0].Reg() { 592 v.Fatalf("input[0] and output not in same register %s", v.LongString()) 593 } 594 p := s.Prog(v.Op.Asm()) 595 p.From.Type = obj.TYPE_CONST 596 p.From.Offset = int64(v.Aux.(s390x.CCMask)) 597 p.Reg = v.Args[1].Reg() 598 p.To.Type = obj.TYPE_REG 599 p.To.Reg = r 600 case ssa.OpS390XFSQRT: 601 p := s.Prog(v.Op.Asm()) 602 p.From.Type = obj.TYPE_REG 603 p.From.Reg = v.Args[0].Reg() 604 p.To.Type = obj.TYPE_REG 605 p.To.Reg = v.Reg() 606 case ssa.OpS390XInvertFlags: 607 v.Fatalf("InvertFlags should never make it to codegen %v", v.LongString()) 608 case ssa.OpS390XFlagEQ, ssa.OpS390XFlagLT, ssa.OpS390XFlagGT, ssa.OpS390XFlagOV: 609 v.Fatalf("Flag* ops should never make it to codegen %v", v.LongString()) 610 case ssa.OpS390XAddTupleFirst32, ssa.OpS390XAddTupleFirst64: 611 v.Fatalf("AddTupleFirst* should never make it to codegen %v", v.LongString()) 612 case ssa.OpS390XLoweredNilCheck: 613 // Issue a load which will fault if the input is nil. 614 p := s.Prog(s390x.AMOVBZ) 615 p.From.Type = obj.TYPE_MEM 616 p.From.Reg = v.Args[0].Reg() 617 gc.AddAux(&p.From, v) 618 p.To.Type = obj.TYPE_REG 619 p.To.Reg = s390x.REGTMP 620 if logopt.Enabled() { 621 logopt.LogOpt(v.Pos, "nilcheck", "genssa", v.Block.Func.Name) 622 } 623 if gc.Debug_checknil != 0 && v.Pos.Line() > 1 { // v.Pos.Line()==1 in generated wrappers 624 gc.Warnl(v.Pos, "generated nil check") 625 } 626 case ssa.OpS390XMVC: 627 vo := v.AuxValAndOff() 628 p := s.Prog(s390x.AMVC) 629 p.From.Type = obj.TYPE_CONST 630 p.From.Offset = vo.Val() 631 p.SetFrom3(obj.Addr{ 632 Type: obj.TYPE_MEM, 633 Reg: v.Args[1].Reg(), 634 Offset: vo.Off(), 635 }) 636 p.To.Type = obj.TYPE_MEM 637 p.To.Reg = v.Args[0].Reg() 638 p.To.Offset = vo.Off() 639 case ssa.OpS390XSTMG2, ssa.OpS390XSTMG3, ssa.OpS390XSTMG4, 640 ssa.OpS390XSTM2, ssa.OpS390XSTM3, ssa.OpS390XSTM4: 641 for i := 2; i < len(v.Args)-1; i++ { 642 if v.Args[i].Reg() != v.Args[i-1].Reg()+1 { 643 v.Fatalf("invalid store multiple %s", v.LongString()) 644 } 645 } 646 p := s.Prog(v.Op.Asm()) 647 p.From.Type = obj.TYPE_REG 648 p.From.Reg = v.Args[1].Reg() 649 p.Reg = v.Args[len(v.Args)-2].Reg() 650 p.To.Type = obj.TYPE_MEM 651 p.To.Reg = v.Args[0].Reg() 652 gc.AddAux(&p.To, v) 653 case ssa.OpS390XLoweredMove: 654 // Inputs must be valid pointers to memory, 655 // so adjust arg0 and arg1 as part of the expansion. 656 // arg2 should be src+size, 657 // 658 // mvc: MVC $256, 0(R2), 0(R1) 659 // MOVD $256(R1), R1 660 // MOVD $256(R2), R2 661 // CMP R2, Rarg2 662 // BNE mvc 663 // MVC $rem, 0(R2), 0(R1) // if rem > 0 664 // arg2 is the last address to move in the loop + 256 665 mvc := s.Prog(s390x.AMVC) 666 mvc.From.Type = obj.TYPE_CONST 667 mvc.From.Offset = 256 668 mvc.SetFrom3(obj.Addr{Type: obj.TYPE_MEM, Reg: v.Args[1].Reg()}) 669 mvc.To.Type = obj.TYPE_MEM 670 mvc.To.Reg = v.Args[0].Reg() 671 672 for i := 0; i < 2; i++ { 673 movd := s.Prog(s390x.AMOVD) 674 movd.From.Type = obj.TYPE_ADDR 675 movd.From.Reg = v.Args[i].Reg() 676 movd.From.Offset = 256 677 movd.To.Type = obj.TYPE_REG 678 movd.To.Reg = v.Args[i].Reg() 679 } 680 681 cmpu := s.Prog(s390x.ACMPU) 682 cmpu.From.Reg = v.Args[1].Reg() 683 cmpu.From.Type = obj.TYPE_REG 684 cmpu.To.Reg = v.Args[2].Reg() 685 cmpu.To.Type = obj.TYPE_REG 686 687 bne := s.Prog(s390x.ABLT) 688 bne.To.Type = obj.TYPE_BRANCH 689 gc.Patch(bne, mvc) 690 691 if v.AuxInt > 0 { 692 mvc := s.Prog(s390x.AMVC) 693 mvc.From.Type = obj.TYPE_CONST 694 mvc.From.Offset = v.AuxInt 695 mvc.SetFrom3(obj.Addr{Type: obj.TYPE_MEM, Reg: v.Args[1].Reg()}) 696 mvc.To.Type = obj.TYPE_MEM 697 mvc.To.Reg = v.Args[0].Reg() 698 } 699 case ssa.OpS390XLoweredZero: 700 // Input must be valid pointers to memory, 701 // so adjust arg0 as part of the expansion. 702 // arg1 should be src+size, 703 // 704 // clear: CLEAR $256, 0(R1) 705 // MOVD $256(R1), R1 706 // CMP R1, Rarg1 707 // BNE clear 708 // CLEAR $rem, 0(R1) // if rem > 0 709 // arg1 is the last address to zero in the loop + 256 710 clear := s.Prog(s390x.ACLEAR) 711 clear.From.Type = obj.TYPE_CONST 712 clear.From.Offset = 256 713 clear.To.Type = obj.TYPE_MEM 714 clear.To.Reg = v.Args[0].Reg() 715 716 movd := s.Prog(s390x.AMOVD) 717 movd.From.Type = obj.TYPE_ADDR 718 movd.From.Reg = v.Args[0].Reg() 719 movd.From.Offset = 256 720 movd.To.Type = obj.TYPE_REG 721 movd.To.Reg = v.Args[0].Reg() 722 723 cmpu := s.Prog(s390x.ACMPU) 724 cmpu.From.Reg = v.Args[0].Reg() 725 cmpu.From.Type = obj.TYPE_REG 726 cmpu.To.Reg = v.Args[1].Reg() 727 cmpu.To.Type = obj.TYPE_REG 728 729 bne := s.Prog(s390x.ABLT) 730 bne.To.Type = obj.TYPE_BRANCH 731 gc.Patch(bne, clear) 732 733 if v.AuxInt > 0 { 734 clear := s.Prog(s390x.ACLEAR) 735 clear.From.Type = obj.TYPE_CONST 736 clear.From.Offset = v.AuxInt 737 clear.To.Type = obj.TYPE_MEM 738 clear.To.Reg = v.Args[0].Reg() 739 } 740 case ssa.OpS390XMOVBZatomicload, ssa.OpS390XMOVWZatomicload, ssa.OpS390XMOVDatomicload: 741 p := s.Prog(v.Op.Asm()) 742 p.From.Type = obj.TYPE_MEM 743 p.From.Reg = v.Args[0].Reg() 744 gc.AddAux(&p.From, v) 745 p.To.Type = obj.TYPE_REG 746 p.To.Reg = v.Reg0() 747 case ssa.OpS390XMOVBatomicstore, ssa.OpS390XMOVWatomicstore, ssa.OpS390XMOVDatomicstore: 748 p := s.Prog(v.Op.Asm()) 749 p.From.Type = obj.TYPE_REG 750 p.From.Reg = v.Args[1].Reg() 751 p.To.Type = obj.TYPE_MEM 752 p.To.Reg = v.Args[0].Reg() 753 gc.AddAux(&p.To, v) 754 case ssa.OpS390XLANfloor, ssa.OpS390XLAOfloor: 755 r := v.Args[0].Reg() // clobbered, assumed R1 in comments 756 757 // Round ptr down to nearest multiple of 4. 758 // ANDW $~3, R1 759 ptr := s.Prog(s390x.AANDW) 760 ptr.From.Type = obj.TYPE_CONST 761 ptr.From.Offset = 0xfffffffc 762 ptr.To.Type = obj.TYPE_REG 763 ptr.To.Reg = r 764 765 // Redirect output of LA(N|O) into R1 since it is clobbered anyway. 766 // LA(N|O) Rx, R1, 0(R1) 767 op := s.Prog(v.Op.Asm()) 768 op.From.Type = obj.TYPE_REG 769 op.From.Reg = v.Args[1].Reg() 770 op.Reg = r 771 op.To.Type = obj.TYPE_MEM 772 op.To.Reg = r 773 case ssa.OpS390XLAA, ssa.OpS390XLAAG: 774 p := s.Prog(v.Op.Asm()) 775 p.Reg = v.Reg0() 776 p.From.Type = obj.TYPE_REG 777 p.From.Reg = v.Args[1].Reg() 778 p.To.Type = obj.TYPE_MEM 779 p.To.Reg = v.Args[0].Reg() 780 gc.AddAux(&p.To, v) 781 case ssa.OpS390XLoweredAtomicCas32, ssa.OpS390XLoweredAtomicCas64: 782 // Convert the flags output of CS{,G} into a bool. 783 // CS{,G} arg1, arg2, arg0 784 // MOVD $0, ret 785 // BNE 2(PC) 786 // MOVD $1, ret 787 // NOP (so the BNE has somewhere to land) 788 789 // CS{,G} arg1, arg2, arg0 790 cs := s.Prog(v.Op.Asm()) 791 cs.From.Type = obj.TYPE_REG 792 cs.From.Reg = v.Args[1].Reg() // old 793 cs.Reg = v.Args[2].Reg() // new 794 cs.To.Type = obj.TYPE_MEM 795 cs.To.Reg = v.Args[0].Reg() 796 gc.AddAux(&cs.To, v) 797 798 // MOVD $0, ret 799 movd := s.Prog(s390x.AMOVD) 800 movd.From.Type = obj.TYPE_CONST 801 movd.From.Offset = 0 802 movd.To.Type = obj.TYPE_REG 803 movd.To.Reg = v.Reg0() 804 805 // BNE 2(PC) 806 bne := s.Prog(s390x.ABNE) 807 bne.To.Type = obj.TYPE_BRANCH 808 809 // MOVD $1, ret 810 movd = s.Prog(s390x.AMOVD) 811 movd.From.Type = obj.TYPE_CONST 812 movd.From.Offset = 1 813 movd.To.Type = obj.TYPE_REG 814 movd.To.Reg = v.Reg0() 815 816 // NOP (so the BNE has somewhere to land) 817 nop := s.Prog(obj.ANOP) 818 gc.Patch(bne, nop) 819 case ssa.OpS390XLoweredAtomicExchange32, ssa.OpS390XLoweredAtomicExchange64: 820 // Loop until the CS{,G} succeeds. 821 // MOV{WZ,D} arg0, ret 822 // cs: CS{,G} ret, arg1, arg0 823 // BNE cs 824 825 // MOV{WZ,D} arg0, ret 826 load := s.Prog(loadByType(v.Type.FieldType(0))) 827 load.From.Type = obj.TYPE_MEM 828 load.From.Reg = v.Args[0].Reg() 829 load.To.Type = obj.TYPE_REG 830 load.To.Reg = v.Reg0() 831 gc.AddAux(&load.From, v) 832 833 // CS{,G} ret, arg1, arg0 834 cs := s.Prog(v.Op.Asm()) 835 cs.From.Type = obj.TYPE_REG 836 cs.From.Reg = v.Reg0() // old 837 cs.Reg = v.Args[1].Reg() // new 838 cs.To.Type = obj.TYPE_MEM 839 cs.To.Reg = v.Args[0].Reg() 840 gc.AddAux(&cs.To, v) 841 842 // BNE cs 843 bne := s.Prog(s390x.ABNE) 844 bne.To.Type = obj.TYPE_BRANCH 845 gc.Patch(bne, cs) 846 case ssa.OpS390XSYNC: 847 s.Prog(s390x.ASYNC) 848 case ssa.OpClobber: 849 // TODO: implement for clobberdead experiment. Nop is ok for now. 850 default: 851 v.Fatalf("genValue not implemented: %s", v.LongString()) 852 } 853 } 854 855 func blockAsm(b *ssa.Block) obj.As { 856 switch b.Kind { 857 case ssa.BlockS390XBRC: 858 return s390x.ABRC 859 case ssa.BlockS390XCRJ: 860 return s390x.ACRJ 861 case ssa.BlockS390XCGRJ: 862 return s390x.ACGRJ 863 case ssa.BlockS390XCLRJ: 864 return s390x.ACLRJ 865 case ssa.BlockS390XCLGRJ: 866 return s390x.ACLGRJ 867 case ssa.BlockS390XCIJ: 868 return s390x.ACIJ 869 case ssa.BlockS390XCGIJ: 870 return s390x.ACGIJ 871 case ssa.BlockS390XCLIJ: 872 return s390x.ACLIJ 873 case ssa.BlockS390XCLGIJ: 874 return s390x.ACLGIJ 875 } 876 b.Fatalf("blockAsm not implemented: %s", b.LongString()) 877 panic("unreachable") 878 } 879 880 func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) { 881 // Handle generic blocks first. 882 switch b.Kind { 883 case ssa.BlockPlain: 884 if b.Succs[0].Block() != next { 885 p := s.Prog(s390x.ABR) 886 p.To.Type = obj.TYPE_BRANCH 887 s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()}) 888 } 889 return 890 case ssa.BlockDefer: 891 // defer returns in R3: 892 // 0 if we should continue executing 893 // 1 if we should jump to deferreturn call 894 p := s.Br(s390x.ACIJ, b.Succs[1].Block()) 895 p.From.Type = obj.TYPE_CONST 896 p.From.Offset = int64(s390x.NotEqual & s390x.NotUnordered) // unordered is not possible 897 p.Reg = s390x.REG_R3 898 p.RestArgs = []obj.Addr{{Type: obj.TYPE_CONST, Offset: 0}} 899 if b.Succs[0].Block() != next { 900 s.Br(s390x.ABR, b.Succs[0].Block()) 901 } 902 return 903 case ssa.BlockExit: 904 return 905 case ssa.BlockRet: 906 s.Prog(obj.ARET) 907 return 908 case ssa.BlockRetJmp: 909 p := s.Prog(s390x.ABR) 910 p.To.Type = obj.TYPE_MEM 911 p.To.Name = obj.NAME_EXTERN 912 p.To.Sym = b.Aux.(*obj.LSym) 913 return 914 } 915 916 // Handle s390x-specific blocks. These blocks all have a 917 // condition code mask in the Aux value and 2 successors. 918 succs := [...]*ssa.Block{b.Succs[0].Block(), b.Succs[1].Block()} 919 mask := b.Aux.(s390x.CCMask) 920 921 // TODO: take into account Likely property for forward/backward 922 // branches. We currently can't do this because we don't know 923 // whether a block has already been emitted. In general forward 924 // branches are assumed 'not taken' and backward branches are 925 // assumed 'taken'. 926 if next == succs[0] { 927 succs[0], succs[1] = succs[1], succs[0] 928 mask = mask.Inverse() 929 } 930 931 p := s.Br(blockAsm(b), succs[0]) 932 switch b.Kind { 933 case ssa.BlockS390XBRC: 934 p.From.Type = obj.TYPE_CONST 935 p.From.Offset = int64(mask) 936 case ssa.BlockS390XCGRJ, ssa.BlockS390XCRJ, 937 ssa.BlockS390XCLGRJ, ssa.BlockS390XCLRJ: 938 p.From.Type = obj.TYPE_CONST 939 p.From.Offset = int64(mask & s390x.NotUnordered) // unordered is not possible 940 p.Reg = b.Controls[0].Reg() 941 p.RestArgs = []obj.Addr{{Type: obj.TYPE_REG, Reg: b.Controls[1].Reg()}} 942 case ssa.BlockS390XCGIJ, ssa.BlockS390XCIJ: 943 p.From.Type = obj.TYPE_CONST 944 p.From.Offset = int64(mask & s390x.NotUnordered) // unordered is not possible 945 p.Reg = b.Controls[0].Reg() 946 p.RestArgs = []obj.Addr{{Type: obj.TYPE_CONST, Offset: int64(int8(b.AuxInt))}} 947 case ssa.BlockS390XCLGIJ, ssa.BlockS390XCLIJ: 948 p.From.Type = obj.TYPE_CONST 949 p.From.Offset = int64(mask & s390x.NotUnordered) // unordered is not possible 950 p.Reg = b.Controls[0].Reg() 951 p.RestArgs = []obj.Addr{{Type: obj.TYPE_CONST, Offset: int64(uint8(b.AuxInt))}} 952 default: 953 b.Fatalf("branch not implemented: %s", b.LongString()) 954 } 955 if next != succs[1] { 956 s.Br(s390x.ABR, succs[1]) 957 } 958 }