github.com/q45/go@v0.0.0-20151101211701-a4fb8c13db3f/src/cmd/compile/internal/arm64/cgen.go (about)

     1  // Copyright 2009 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 arm64
     6  
     7  import (
     8  	"cmd/compile/internal/gc"
     9  	"cmd/internal/obj"
    10  	"cmd/internal/obj/arm64"
    11  )
    12  
    13  func blockcopy(n, res *gc.Node, osrc, odst, w int64) {
    14  	// determine alignment.
    15  	// want to avoid unaligned access, so have to use
    16  	// smaller operations for less aligned types.
    17  	// for example moving [4]byte must use 4 MOVB not 1 MOVW.
    18  	align := int(n.Type.Align)
    19  
    20  	var op int
    21  	switch align {
    22  	default:
    23  		gc.Fatalf("sgen: invalid alignment %d for %v", align, n.Type)
    24  
    25  	case 1:
    26  		op = arm64.AMOVB
    27  
    28  	case 2:
    29  		op = arm64.AMOVH
    30  
    31  	case 4:
    32  		op = arm64.AMOVW
    33  
    34  	case 8:
    35  		op = arm64.AMOVD
    36  	}
    37  
    38  	if w%int64(align) != 0 {
    39  		gc.Fatalf("sgen: unaligned size %d (align=%d) for %v", w, align, n.Type)
    40  	}
    41  	c := int32(w / int64(align))
    42  
    43  	if osrc%int64(align) != 0 || odst%int64(align) != 0 {
    44  		gc.Fatalf("sgen: unaligned offset src %d or dst %d (align %d)", osrc, odst, align)
    45  	}
    46  
    47  	// if we are copying forward on the stack and
    48  	// the src and dst overlap, then reverse direction
    49  	dir := align
    50  
    51  	if osrc < odst && int64(odst) < int64(osrc)+w {
    52  		dir = -dir
    53  	}
    54  
    55  	var dst gc.Node
    56  	var src gc.Node
    57  	if n.Ullman >= res.Ullman {
    58  		gc.Agenr(n, &dst, res) // temporarily use dst
    59  		gc.Regalloc(&src, gc.Types[gc.Tptr], nil)
    60  		gins(arm64.AMOVD, &dst, &src)
    61  		if res.Op == gc.ONAME {
    62  			gc.Gvardef(res)
    63  		}
    64  		gc.Agen(res, &dst)
    65  	} else {
    66  		if res.Op == gc.ONAME {
    67  			gc.Gvardef(res)
    68  		}
    69  		gc.Agenr(res, &dst, res)
    70  		gc.Agenr(n, &src, nil)
    71  	}
    72  
    73  	var tmp gc.Node
    74  	gc.Regalloc(&tmp, gc.Types[gc.Tptr], nil)
    75  
    76  	// set up end marker
    77  	var nend gc.Node
    78  
    79  	// move src and dest to the end of block if necessary
    80  	if dir < 0 {
    81  		if c >= 4 {
    82  			gc.Regalloc(&nend, gc.Types[gc.Tptr], nil)
    83  			gins(arm64.AMOVD, &src, &nend)
    84  		}
    85  
    86  		p := gins(arm64.AADD, nil, &src)
    87  		p.From.Type = obj.TYPE_CONST
    88  		p.From.Offset = w
    89  
    90  		p = gins(arm64.AADD, nil, &dst)
    91  		p.From.Type = obj.TYPE_CONST
    92  		p.From.Offset = w
    93  	} else {
    94  		p := gins(arm64.AADD, nil, &src)
    95  		p.From.Type = obj.TYPE_CONST
    96  		p.From.Offset = int64(-dir)
    97  
    98  		p = gins(arm64.AADD, nil, &dst)
    99  		p.From.Type = obj.TYPE_CONST
   100  		p.From.Offset = int64(-dir)
   101  
   102  		if c >= 4 {
   103  			gc.Regalloc(&nend, gc.Types[gc.Tptr], nil)
   104  			p := gins(arm64.AMOVD, &src, &nend)
   105  			p.From.Type = obj.TYPE_ADDR
   106  			p.From.Offset = w
   107  		}
   108  	}
   109  
   110  	// move
   111  	// TODO: enable duffcopy for larger copies.
   112  	if c >= 4 {
   113  		p := gins(op, &src, &tmp)
   114  		p.From.Type = obj.TYPE_MEM
   115  		p.From.Offset = int64(dir)
   116  		p.Scond = arm64.C_XPRE
   117  		ploop := p
   118  
   119  		p = gins(op, &tmp, &dst)
   120  		p.To.Type = obj.TYPE_MEM
   121  		p.To.Offset = int64(dir)
   122  		p.Scond = arm64.C_XPRE
   123  
   124  		p = gcmp(arm64.ACMP, &src, &nend)
   125  
   126  		gc.Patch(gc.Gbranch(arm64.ABNE, nil, 0), ploop)
   127  		gc.Regfree(&nend)
   128  	} else {
   129  		// TODO(austin): Instead of generating ADD $-8,R8; ADD
   130  		// $-8,R7; n*(MOVDU 8(R8),R9; MOVDU R9,8(R7);) just
   131  		// generate the offsets directly and eliminate the
   132  		// ADDs.  That will produce shorter, more
   133  		// pipeline-able code.
   134  		var p *obj.Prog
   135  		for ; c > 0; c-- {
   136  			p = gins(op, &src, &tmp)
   137  			p.From.Type = obj.TYPE_MEM
   138  			p.From.Offset = int64(dir)
   139  			p.Scond = arm64.C_XPRE
   140  
   141  			p = gins(op, &tmp, &dst)
   142  			p.To.Type = obj.TYPE_MEM
   143  			p.To.Offset = int64(dir)
   144  			p.Scond = arm64.C_XPRE
   145  		}
   146  	}
   147  
   148  	gc.Regfree(&dst)
   149  	gc.Regfree(&src)
   150  	gc.Regfree(&tmp)
   151  }