github.com/mh-cbon/go@v0.0.0-20160603070303-9e112a3fe4c0/src/cmd/compile/internal/s390x/cgen.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  type direction int
    14  
    15  const (
    16  	_FORWARDS direction = iota
    17  	_BACKWARDS
    18  )
    19  
    20  // blockcopy copies w bytes from &n to &res
    21  func blockcopy(n, res *gc.Node, osrc, odst, w int64) {
    22  	var dst gc.Node
    23  	var src gc.Node
    24  	if n.Ullman >= res.Ullman {
    25  		gc.Agenr(n, &dst, res) // temporarily use dst
    26  		gc.Regalloc(&src, gc.Types[gc.Tptr], nil)
    27  		gins(s390x.AMOVD, &dst, &src)
    28  		if res.Op == gc.ONAME {
    29  			gc.Gvardef(res)
    30  		}
    31  		gc.Agen(res, &dst)
    32  	} else {
    33  		if res.Op == gc.ONAME {
    34  			gc.Gvardef(res)
    35  		}
    36  		gc.Agenr(res, &dst, res)
    37  		gc.Agenr(n, &src, nil)
    38  	}
    39  	defer gc.Regfree(&src)
    40  	defer gc.Regfree(&dst)
    41  
    42  	var tmp gc.Node
    43  	gc.Regalloc(&tmp, gc.Types[gc.Tptr], nil)
    44  	defer gc.Regfree(&tmp)
    45  
    46  	offset := int64(0)
    47  	dir := _FORWARDS
    48  	if osrc < odst && odst < osrc+w {
    49  		// Reverse. Can't use MVC, fall back onto basic moves.
    50  		dir = _BACKWARDS
    51  		const copiesPerIter = 2
    52  		if w >= 8*copiesPerIter {
    53  			cnt := w - (w % (8 * copiesPerIter))
    54  			ginscon(s390x.AADD, w, &src)
    55  			ginscon(s390x.AADD, w, &dst)
    56  
    57  			var end gc.Node
    58  			gc.Regalloc(&end, gc.Types[gc.Tptr], nil)
    59  			p := gins(s390x.ASUB, nil, &end)
    60  			p.From.Type = obj.TYPE_CONST
    61  			p.From.Offset = cnt
    62  			p.Reg = src.Reg
    63  
    64  			var label *obj.Prog
    65  			for i := 0; i < copiesPerIter; i++ {
    66  				offset := int64(-8 * (i + 1))
    67  				p := gins(s390x.AMOVD, &src, &tmp)
    68  				p.From.Type = obj.TYPE_MEM
    69  				p.From.Offset = offset
    70  				if i == 0 {
    71  					label = p
    72  				}
    73  				p = gins(s390x.AMOVD, &tmp, &dst)
    74  				p.To.Type = obj.TYPE_MEM
    75  				p.To.Offset = offset
    76  			}
    77  
    78  			ginscon(s390x.ASUB, 8*copiesPerIter, &src)
    79  			ginscon(s390x.ASUB, 8*copiesPerIter, &dst)
    80  			gins(s390x.ACMP, &src, &end)
    81  			gc.Patch(gc.Gbranch(s390x.ABNE, nil, 0), label)
    82  			gc.Regfree(&end)
    83  
    84  			w -= cnt
    85  		} else {
    86  			offset = w
    87  		}
    88  	}
    89  
    90  	if dir == _FORWARDS && w > 1024 {
    91  		// Loop over MVCs
    92  		cnt := w - (w % 256)
    93  
    94  		var end gc.Node
    95  		gc.Regalloc(&end, gc.Types[gc.Tptr], nil)
    96  		add := gins(s390x.AADD, nil, &end)
    97  		add.From.Type = obj.TYPE_CONST
    98  		add.From.Offset = cnt
    99  		add.Reg = src.Reg
   100  
   101  		mvc := gins(s390x.AMVC, &src, &dst)
   102  		mvc.From.Type = obj.TYPE_MEM
   103  		mvc.From.Offset = 0
   104  		mvc.To.Type = obj.TYPE_MEM
   105  		mvc.To.Offset = 0
   106  		mvc.From3 = new(obj.Addr)
   107  		mvc.From3.Type = obj.TYPE_CONST
   108  		mvc.From3.Offset = 256
   109  
   110  		ginscon(s390x.AADD, 256, &src)
   111  		ginscon(s390x.AADD, 256, &dst)
   112  		gins(s390x.ACMP, &src, &end)
   113  		gc.Patch(gc.Gbranch(s390x.ABNE, nil, 0), mvc)
   114  		gc.Regfree(&end)
   115  
   116  		w -= cnt
   117  	}
   118  
   119  	for w > 0 {
   120  		cnt := w
   121  		// If in reverse we can only do 8, 4, 2 or 1 bytes at a time.
   122  		if dir == _BACKWARDS {
   123  			switch {
   124  			case cnt >= 8:
   125  				cnt = 8
   126  			case cnt >= 4:
   127  				cnt = 4
   128  			case cnt >= 2:
   129  				cnt = 2
   130  			}
   131  		} else if cnt > 256 {
   132  			cnt = 256
   133  		}
   134  
   135  		switch cnt {
   136  		case 8, 4, 2, 1:
   137  			op := s390x.AMOVB
   138  			switch cnt {
   139  			case 8:
   140  				op = s390x.AMOVD
   141  			case 4:
   142  				op = s390x.AMOVW
   143  			case 2:
   144  				op = s390x.AMOVH
   145  			}
   146  			load := gins(op, &src, &tmp)
   147  			load.From.Type = obj.TYPE_MEM
   148  			load.From.Offset = offset
   149  
   150  			store := gins(op, &tmp, &dst)
   151  			store.To.Type = obj.TYPE_MEM
   152  			store.To.Offset = offset
   153  
   154  			if dir == _BACKWARDS {
   155  				load.From.Offset -= cnt
   156  				store.To.Offset -= cnt
   157  			}
   158  
   159  		default:
   160  			p := gins(s390x.AMVC, &src, &dst)
   161  			p.From.Type = obj.TYPE_MEM
   162  			p.From.Offset = offset
   163  			p.To.Type = obj.TYPE_MEM
   164  			p.To.Offset = offset
   165  			p.From3 = new(obj.Addr)
   166  			p.From3.Type = obj.TYPE_CONST
   167  			p.From3.Offset = cnt
   168  		}
   169  
   170  		switch dir {
   171  		case _FORWARDS:
   172  			offset += cnt
   173  		case _BACKWARDS:
   174  			offset -= cnt
   175  		}
   176  		w -= cnt
   177  	}
   178  }