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 }