Home | History | Annotate | Download | only in x86
      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 }
    160