Home | History | Annotate | Download | only in s390x
      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 	"cmd/compile/internal/gc"
      9 	"cmd/internal/obj"
     10 	"cmd/internal/obj/s390x"
     11 )
     12 
     13 // clearLoopCutOff is the (somewhat arbitrary) value above which it is better
     14 // to have a loop of clear instructions (e.g. XCs) rather than just generating
     15 // multiple instructions (i.e. loop unrolling).
     16 // Must be between 256 and 4096.
     17 const clearLoopCutoff = 1024
     18 
     19 func defframe(ptxt *obj.Prog) {
     20 	// fill in argument size, stack size
     21 	ptxt.To.Type = obj.TYPE_TEXTSIZE
     22 
     23 	ptxt.To.Val = int32(gc.Rnd(gc.Curfn.Type.ArgWidth(), int64(gc.Widthptr)))
     24 	frame := uint32(gc.Rnd(gc.Stksize+gc.Maxarg, int64(gc.Widthreg)))
     25 	ptxt.To.Offset = int64(frame)
     26 
     27 	// insert code to zero ambiguously live variables
     28 	// so that the garbage collector only sees initialized values
     29 	// when it looks for pointers.
     30 	p := ptxt
     31 
     32 	hi := int64(0)
     33 	lo := hi
     34 
     35 	// iterate through declarations - they are sorted in decreasing xoffset order.
     36 	for _, n := range gc.Curfn.Func.Dcl {
     37 		if !n.Name.Needzero {
     38 			continue
     39 		}
     40 		if n.Class != gc.PAUTO {
     41 			gc.Fatalf("needzero class %d", n.Class)
     42 		}
     43 		if n.Type.Width%int64(gc.Widthptr) != 0 || n.Xoffset%int64(gc.Widthptr) != 0 || n.Type.Width == 0 {
     44 			gc.Fatalf("var %L has size %d offset %d", n, int(n.Type.Width), int(n.Xoffset))
     45 		}
     46 
     47 		if lo != hi && n.Xoffset+n.Type.Width >= lo-int64(2*gc.Widthreg) {
     48 			// merge with range we already have
     49 			lo = n.Xoffset
     50 
     51 			continue
     52 		}
     53 
     54 		// zero old range
     55 		p = zerorange(p, int64(frame), lo, hi)
     56 
     57 		// set new range
     58 		hi = n.Xoffset + n.Type.Width
     59 
     60 		lo = n.Xoffset
     61 	}
     62 
     63 	// zero final range
     64 	zerorange(p, int64(frame), lo, hi)
     65 }
     66 
     67 // zerorange clears the stack in the given range.
     68 func zerorange(p *obj.Prog, frame int64, lo int64, hi int64) *obj.Prog {
     69 	cnt := hi - lo
     70 	if cnt == 0 {
     71 		return p
     72 	}
     73 
     74 	// Adjust the frame to account for LR.
     75 	frame += gc.Ctxt.FixedFrameSize()
     76 	offset := frame + lo
     77 	reg := int16(s390x.REGSP)
     78 
     79 	// If the offset cannot fit in a 12-bit unsigned displacement then we
     80 	// need to create a copy of the stack pointer that we can adjust.
     81 	// We also need to do this if we are going to loop.
     82 	if offset < 0 || offset > 4096-clearLoopCutoff || cnt > clearLoopCutoff {
     83 		p = gc.Appendpp(p, s390x.AADD, obj.TYPE_CONST, 0, offset, obj.TYPE_REG, s390x.REGRT1, 0)
     84 		p.Reg = int16(s390x.REGSP)
     85 		reg = s390x.REGRT1
     86 		offset = 0
     87 	}
     88 
     89 	// Generate a loop of large clears.
     90 	if cnt > clearLoopCutoff {
     91 		n := cnt - (cnt % 256)
     92 		end := int16(s390x.REGRT2)
     93 		p = gc.Appendpp(p, s390x.AADD, obj.TYPE_CONST, 0, offset+n, obj.TYPE_REG, end, 0)
     94 		p.Reg = reg
     95 		p = gc.Appendpp(p, s390x.AXC, obj.TYPE_MEM, reg, offset, obj.TYPE_MEM, reg, offset)
     96 		p.From3 = new(obj.Addr)
     97 		p.From3.Type = obj.TYPE_CONST
     98 		p.From3.Offset = 256
     99 		pl := p
    100 		p = gc.Appendpp(p, s390x.AADD, obj.TYPE_CONST, 0, 256, obj.TYPE_REG, reg, 0)
    101 		p = gc.Appendpp(p, s390x.ACMP, obj.TYPE_REG, reg, 0, obj.TYPE_REG, end, 0)
    102 		p = gc.Appendpp(p, s390x.ABNE, obj.TYPE_NONE, 0, 0, obj.TYPE_BRANCH, 0, 0)
    103 		gc.Patch(p, pl)
    104 
    105 		cnt -= n
    106 	}
    107 
    108 	// Generate remaining clear instructions without a loop.
    109 	for cnt > 0 {
    110 		n := cnt
    111 
    112 		// Can clear at most 256 bytes per instruction.
    113 		if n > 256 {
    114 			n = 256
    115 		}
    116 
    117 		switch n {
    118 		// Handle very small clears with move instructions.
    119 		case 8, 4, 2, 1:
    120 			ins := s390x.AMOVB
    121 			switch n {
    122 			case 8:
    123 				ins = s390x.AMOVD
    124 			case 4:
    125 				ins = s390x.AMOVW
    126 			case 2:
    127 				ins = s390x.AMOVH
    128 			}
    129 			p = gc.Appendpp(p, ins, obj.TYPE_CONST, 0, 0, obj.TYPE_MEM, reg, offset)
    130 
    131 		// Handle clears that would require multiple move instructions with XC.
    132 		default:
    133 			p = gc.Appendpp(p, s390x.AXC, obj.TYPE_MEM, reg, offset, obj.TYPE_MEM, reg, offset)
    134 			p.From3 = new(obj.Addr)
    135 			p.From3.Type = obj.TYPE_CONST
    136 			p.From3.Offset = n
    137 		}
    138 
    139 		cnt -= n
    140 		offset += n
    141 	}
    142 
    143 	return p
    144 }
    145 
    146 func ginsnop() {
    147 	p := gc.Prog(s390x.AOR)
    148 	p.From.Type = obj.TYPE_REG
    149 	p.From.Reg = int16(s390x.REG_R0)
    150 	p.To.Type = obj.TYPE_REG
    151 	p.To.Reg = int16(s390x.REG_R0)
    152 }
    153