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