github.com/q45/go@v0.0.0-20151101211701-a4fb8c13db3f/src/cmd/compile/internal/x86/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 x86
     6  
     7  import (
     8  	"cmd/compile/internal/gc"
     9  	"cmd/internal/obj"
    10  	"cmd/internal/obj/x86"
    11  )
    12  
    13  /*
    14   * generate an addressable node in res, containing the value of n.
    15   * n is an array index, and might be any size; res width is <= 32-bit.
    16   * returns Prog* to patch to panic call.
    17   */
    18  func igenindex(n *gc.Node, res *gc.Node, bounded bool) *obj.Prog {
    19  	if !gc.Is64(n.Type) {
    20  		if n.Addable && (gc.Simtype[n.Etype] == gc.TUINT32 || gc.Simtype[n.Etype] == gc.TINT32) {
    21  			// nothing to do.
    22  			*res = *n
    23  		} else {
    24  			gc.Tempname(res, gc.Types[gc.TUINT32])
    25  			gc.Cgen(n, res)
    26  		}
    27  
    28  		return nil
    29  	}
    30  
    31  	var tmp gc.Node
    32  	gc.Tempname(&tmp, gc.Types[gc.TINT64])
    33  	gc.Cgen(n, &tmp)
    34  	var lo gc.Node
    35  	var hi gc.Node
    36  	split64(&tmp, &lo, &hi)
    37  	gc.Tempname(res, gc.Types[gc.TUINT32])
    38  	gmove(&lo, res)
    39  	if bounded {
    40  		splitclean()
    41  		return nil
    42  	}
    43  
    44  	var zero gc.Node
    45  	gc.Nodconst(&zero, gc.Types[gc.TINT32], 0)
    46  	gins(x86.ACMPL, &hi, &zero)
    47  	splitclean()
    48  	return gc.Gbranch(x86.AJNE, nil, +1)
    49  }
    50  
    51  func blockcopy(n, res *gc.Node, osrc, odst, w int64) {
    52  	var dst gc.Node
    53  	gc.Nodreg(&dst, gc.Types[gc.Tptr], x86.REG_DI)
    54  	var src gc.Node
    55  	gc.Nodreg(&src, gc.Types[gc.Tptr], x86.REG_SI)
    56  
    57  	var tsrc gc.Node
    58  	gc.Tempname(&tsrc, gc.Types[gc.Tptr])
    59  	var tdst gc.Node
    60  	gc.Tempname(&tdst, gc.Types[gc.Tptr])
    61  	if !n.Addable {
    62  		gc.Agen(n, &tsrc)
    63  	}
    64  	if !res.Addable {
    65  		gc.Agen(res, &tdst)
    66  	}
    67  	if n.Addable {
    68  		gc.Agen(n, &src)
    69  	} else {
    70  		gmove(&tsrc, &src)
    71  	}
    72  
    73  	if res.Op == gc.ONAME {
    74  		gc.Gvardef(res)
    75  	}
    76  
    77  	if res.Addable {
    78  		gc.Agen(res, &dst)
    79  	} else {
    80  		gmove(&tdst, &dst)
    81  	}
    82  
    83  	c := int32(w % 4) // bytes
    84  	q := int32(w / 4) // doublewords
    85  
    86  	// if we are copying forward on the stack and
    87  	// the src and dst overlap, then reverse direction
    88  	if osrc < odst && int64(odst) < int64(osrc)+w {
    89  		// reverse direction
    90  		gins(x86.ASTD, nil, nil) // set direction flag
    91  		if c > 0 {
    92  			gconreg(x86.AADDL, w-1, x86.REG_SI)
    93  			gconreg(x86.AADDL, w-1, x86.REG_DI)
    94  
    95  			gconreg(x86.AMOVL, int64(c), x86.REG_CX)
    96  			gins(x86.AREP, nil, nil)   // repeat
    97  			gins(x86.AMOVSB, nil, nil) // MOVB *(SI)-,*(DI)-
    98  		}
    99  
   100  		if q > 0 {
   101  			if c > 0 {
   102  				gconreg(x86.AADDL, -3, x86.REG_SI)
   103  				gconreg(x86.AADDL, -3, x86.REG_DI)
   104  			} else {
   105  				gconreg(x86.AADDL, w-4, x86.REG_SI)
   106  				gconreg(x86.AADDL, w-4, x86.REG_DI)
   107  			}
   108  
   109  			gconreg(x86.AMOVL, int64(q), x86.REG_CX)
   110  			gins(x86.AREP, nil, nil)   // repeat
   111  			gins(x86.AMOVSL, nil, nil) // MOVL *(SI)-,*(DI)-
   112  		}
   113  
   114  		// we leave with the flag clear
   115  		gins(x86.ACLD, nil, nil)
   116  	} else {
   117  		gins(x86.ACLD, nil, nil) // paranoia.  TODO(rsc): remove?
   118  
   119  		// normal direction
   120  		if q > 128 || (q >= 4 && gc.Nacl) {
   121  			gconreg(x86.AMOVL, int64(q), x86.REG_CX)
   122  			gins(x86.AREP, nil, nil)   // repeat
   123  			gins(x86.AMOVSL, nil, nil) // MOVL *(SI)+,*(DI)+
   124  		} else if q >= 4 {
   125  			p := gins(obj.ADUFFCOPY, nil, nil)
   126  			p.To.Type = obj.TYPE_ADDR
   127  			p.To.Sym = gc.Linksym(gc.Pkglookup("duffcopy", gc.Runtimepkg))
   128  
   129  			// 10 and 128 = magic constants: see ../../runtime/asm_386.s
   130  			p.To.Offset = 10 * (128 - int64(q))
   131  		} else if !gc.Nacl && c == 0 {
   132  			var cx gc.Node
   133  			gc.Nodreg(&cx, gc.Types[gc.TINT32], x86.REG_CX)
   134  
   135  			// We don't need the MOVSL side-effect of updating SI and DI,
   136  			// and issuing a sequence of MOVLs directly is faster.
   137  			src.Op = gc.OINDREG
   138  
   139  			dst.Op = gc.OINDREG
   140  			for q > 0 {
   141  				gmove(&src, &cx) // MOVL x+(SI),CX
   142  				gmove(&cx, &dst) // MOVL CX,x+(DI)
   143  				src.Xoffset += 4
   144  				dst.Xoffset += 4
   145  				q--
   146  			}
   147  		} else {
   148  			for q > 0 {
   149  				gins(x86.AMOVSL, nil, nil) // MOVL *(SI)+,*(DI)+
   150  				q--
   151  			}
   152  		}
   153  
   154  		for c > 0 {
   155  			gins(x86.AMOVSB, nil, nil) // MOVB *(SI)+,*(DI)+
   156  			c--
   157  		}
   158  	}
   159  }