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