1 // Copyright 2015 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.
12 func applyRewrite(f *Func, rb func(*Block) bool, rv func(*Value, *Config) bool) {
13 // repeat rewrites until we find no more rewrites
18 curb.Fatalf("panic during rewrite of block %s\n", curb.LongString())
21 curv.Fatalf("panic during rewrite of value %s\n", curv.LongString())
22 // TODO(khr): print source location also
28 for _, b := range f.Blocks {
29 if b.Kind == BlockDead {
32 if b.Control != nil && b.Control.Op == OpCopy {
33 for b.Control.Op == OpCopy {
34 b.Control = b.Control.Args[0]
42 for _, v := range b.Values {
43 // elide any copies generated during rewriting
44 for i, a := range v.Args {
48 // Rewriting can generate OpCopy loops.
49 // They are harmless (see removePredecessor),
50 // but take care to stop if we find a cycle.
51 slow := a // advances every other iteration
66 // apply rewrite function
80 // Common functions called from rewriting rules
82 func is64BitFloat(t Type) bool {
83 return t.Size() == 8 && t.IsFloat()
86 func is32BitFloat(t Type) bool {
87 return t.Size() == 4 && t.IsFloat()
90 func is64BitInt(t Type) bool {
91 return t.Size() == 8 && t.IsInteger()
94 func is32BitInt(t Type) bool {
95 return t.Size() == 4 && t.IsInteger()
98 func is16BitInt(t Type) bool {
99 return t.Size() == 2 && t.IsInteger()
102 func is8BitInt(t Type) bool {
103 return t.Size() == 1 && t.IsInteger()
106 func isPtr(t Type) bool {
110 func isSigned(t Type) bool {
114 func typeSize(t Type) int64 {
118 // addOff adds two int64 offsets. Fails if wraparound happens.
119 func addOff(x, y int64) int64 {
121 // x and y have same sign and z has a different sign => overflow
122 if x^y >= 0 && x^z < 0 {
123 panic(fmt.Sprintf("offset overflow %d %d", x, y))
128 // mergeSym merges two symbolic offsets. There is no real merging of
129 // offsets, we just pick the non-nil one.
130 func mergeSym(x, y interface{}) interface{} {
137 panic(fmt.Sprintf("mergeSym with two non-nil syms %s %s", x, y))
140 func canMergeSym(x, y interface{}) bool {
141 return x == nil || y == nil
144 func inBounds8(idx, len int64) bool { return int8(idx) >= 0 && int8(idx) < int8(len) }
145 func inBounds16(idx, len int64) bool { return int16(idx) >= 0 && int16(idx) < int16(len) }
146 func inBounds32(idx, len int64) bool { return int32(idx) >= 0 && int32(idx) < int32(len) }
147 func inBounds64(idx, len int64) bool { return idx >= 0 && idx < len }
149 // log2 returns logarithm in base of n.
150 // expects n to be a power of 2.
151 func log2(n int64) (l int64) {
159 // isPowerOfTwo reports whether n is a power of 2.
160 func isPowerOfTwo(n int64) bool {
161 return n > 0 && n&(n-1) == 0
164 // is32Bit reports whether n can be represented as a signed 32 bit integer.
165 func is32Bit(n int64) bool {
166 return n == int64(int32(n))
169 // b2i translates a boolean value to 0 or 1 for assigning to auxInt.
170 func b2i(b bool) int64 {
177 // f2i is used in the rules for storing a float in AuxInt.
178 func f2i(f float64) int64 {
179 return int64(math.Float64bits(f))
182 // DUFFZERO consists of repeated blocks of 4 MOVs + ADD,
183 // with 4 STOSQs at the very end.
184 // The trailing STOSQs prevent the need for a DI preadjustment
185 // for small numbers of words to clear.
186 // See runtime/mkduff.go.
188 dzBlocks = 31 // number of MOV/ADD blocks
189 dzBlockLen = 4 // number of clears per block
190 dzBlockSize = 19 // size of instructions in a single block
191 dzMovSize = 4 // size of single MOV instruction w/ offset
192 dzAddSize = 4 // size of single ADD instruction
193 dzDIStep = 8 // number of bytes cleared by each MOV instruction
195 dzTailLen = 4 // number of final STOSQ instructions
196 dzTailSize = 2 // size of single STOSQ instruction
198 dzSize = dzBlocks*dzBlockSize + dzTailLen*dzTailSize // total size of DUFFZERO routine
201 func duffStart(size int64) int64 {
205 func duffAdj(size int64) int64 {
210 // duff returns the offset (from duffzero, in bytes) and pointer adjust (in bytes)
211 // required to use the duffzero mechanism for a block of the given size.
212 func duff(size int64) (int64, int64) {
213 if size < 32 || size > 1024 || size%8 != 0 {
214 panic("bad duffzero size")
216 // TODO: arch-dependent
218 off -= dzTailLen * dzTailSize
219 size -= dzTailLen * dzDIStep
221 blocks, singles := q/dzBlockLen, q%dzBlockLen
222 off -= dzBlockSize * blocks
225 off -= dzAddSize + dzMovSize*singles
226 adj -= dzDIStep * (dzBlockLen - singles)