github.com/rakyll/go@v0.0.0-20170216000551-64c02460d703/src/cmd/compile/internal/s390x/ggen.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  	"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  }