blob: e0cb7f517ba3f5e1e7c31ba0212c897fe6804787 [file] [log] [blame]
Keith Randall7b962842015-03-23 17:02:11 -07001// 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.
4
5package ssa
6
Todd Neal19447a62015-09-04 06:33:56 -05007import (
8 "fmt"
9 "math"
10)
Keith Randall7b962842015-03-23 17:02:11 -070011
Keith Randallf7f604e2015-05-27 14:52:22 -070012func applyRewrite(f *Func, rb func(*Block) bool, rv func(*Value, *Config) bool) {
Keith Randall7b962842015-03-23 17:02:11 -070013 // repeat rewrites until we find no more rewrites
Keith Randalla9cec302015-05-28 16:45:33 -070014 var curb *Block
Keith Randalld2fd43a2015-04-15 15:51:25 -070015 var curv *Value
16 defer func() {
Keith Randalla9cec302015-05-28 16:45:33 -070017 if curb != nil {
Josh Bleecher Snyder37ddc272015-06-24 14:03:39 -070018 curb.Fatalf("panic during rewrite of block %s\n", curb.LongString())
Keith Randalla9cec302015-05-28 16:45:33 -070019 }
Keith Randalld2fd43a2015-04-15 15:51:25 -070020 if curv != nil {
Josh Bleecher Snyder37ddc272015-06-24 14:03:39 -070021 curv.Fatalf("panic during rewrite of value %s\n", curv.LongString())
Keith Randalld2fd43a2015-04-15 15:51:25 -070022 // TODO(khr): print source location also
23 }
24 }()
Keith Randallf7f604e2015-05-27 14:52:22 -070025 config := f.Config
Keith Randall7b962842015-03-23 17:02:11 -070026 for {
27 change := false
28 for _, b := range f.Blocks {
Josh Bleecher Snyder9b048522015-07-09 21:24:12 -060029 if b.Kind == BlockDead {
30 continue
31 }
Keith Randalla9cec302015-05-28 16:45:33 -070032 if b.Control != nil && b.Control.Op == OpCopy {
33 for b.Control.Op == OpCopy {
Keith Randall56e0ecc2016-03-15 20:45:50 -070034 b.SetControl(b.Control.Args[0])
Keith Randalla9cec302015-05-28 16:45:33 -070035 }
36 }
37 curb = b
38 if rb(b) {
39 change = true
40 }
41 curb = nil
Keith Randall7b962842015-03-23 17:02:11 -070042 for _, v := range b.Values {
Keith Randall56e0ecc2016-03-15 20:45:50 -070043 change = copyelimValue(v) || change
Alexandru Moșoi65855cf2016-02-11 20:46:43 +010044 change = phielimValue(v) || change
Keith Randallcfc2aa52015-05-18 16:44:20 -070045
46 // apply rewrite function
Keith Randalld2fd43a2015-04-15 15:51:25 -070047 curv = v
Keith Randallf7f604e2015-05-27 14:52:22 -070048 if rv(v, config) {
Keith Randall7b962842015-03-23 17:02:11 -070049 change = true
50 }
Keith Randalla9cec302015-05-28 16:45:33 -070051 curv = nil
Keith Randall7b962842015-03-23 17:02:11 -070052 }
53 }
54 if !change {
55 return
56 }
57 }
58}
59
60// Common functions called from rewriting rules
61
David Chase997a9f32015-08-12 16:38:11 -040062func is64BitFloat(t Type) bool {
63 return t.Size() == 8 && t.IsFloat()
64}
65
66func is32BitFloat(t Type) bool {
67 return t.Size() == 4 && t.IsFloat()
68}
69
Keith Randall7b962842015-03-23 17:02:11 -070070func is64BitInt(t Type) bool {
Keith Randalld2fd43a2015-04-15 15:51:25 -070071 return t.Size() == 8 && t.IsInteger()
Keith Randall7b962842015-03-23 17:02:11 -070072}
73
74func is32BitInt(t Type) bool {
Keith Randalld2fd43a2015-04-15 15:51:25 -070075 return t.Size() == 4 && t.IsInteger()
76}
77
Michael Matloob73054f52015-06-14 11:38:46 -070078func is16BitInt(t Type) bool {
79 return t.Size() == 2 && t.IsInteger()
80}
81
82func is8BitInt(t Type) bool {
83 return t.Size() == 1 && t.IsInteger()
84}
85
Keith Randalld2fd43a2015-04-15 15:51:25 -070086func isPtr(t Type) bool {
Matthew Dempsky788f1122016-03-28 10:55:44 -070087 return t.IsPtrShaped()
Keith Randall7b962842015-03-23 17:02:11 -070088}
89
90func isSigned(t Type) bool {
Keith Randalld2fd43a2015-04-15 15:51:25 -070091 return t.IsSigned()
Keith Randall7b962842015-03-23 17:02:11 -070092}
93
Keith Randall2c9b4912015-03-26 10:49:03 -070094func typeSize(t Type) int64 {
Keith Randalld2fd43a2015-04-15 15:51:25 -070095 return t.Size()
Keith Randall7b962842015-03-23 17:02:11 -070096}
Keith Randallcfc2aa52015-05-18 16:44:20 -070097
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +000098// mergeSym merges two symbolic offsets. There is no real merging of
Keith Randall01490eb2015-08-23 21:14:25 -070099// offsets, we just pick the non-nil one.
Keith Randall8c46aa52015-06-19 21:02:28 -0700100func mergeSym(x, y interface{}) interface{} {
101 if x == nil {
102 return y
103 }
104 if y == nil {
105 return x
106 }
107 panic(fmt.Sprintf("mergeSym with two non-nil syms %s %s", x, y))
108 return nil
109}
Keith Randall01490eb2015-08-23 21:14:25 -0700110func canMergeSym(x, y interface{}) bool {
111 return x == nil || y == nil
112}
Keith Randall8c46aa52015-06-19 21:02:28 -0700113
Todd Nealadc8d492016-02-11 20:43:15 -0600114// nlz returns the number of leading zeros.
115func nlz(x int64) int64 {
116 // log2(0) == 1, so nlz(0) == 64
117 return 63 - log2(x)
118}
119
120// ntz returns the number of trailing zeros.
121func ntz(x int64) int64 {
122 return 64 - nlz(^x&(x-1))
123}
124
125// nlo returns the number of leading ones.
126func nlo(x int64) int64 {
127 return nlz(^x)
128}
129
130// nto returns the number of trailing ones.
131func nto(x int64) int64 {
132 return ntz(^x)
133}
134
135// log2 returns logarithm in base of uint64(n), with log2(0) = -1.
Alexandru Moșoi3e7e5192015-07-17 12:26:35 +0200136func log2(n int64) (l int64) {
Todd Nealadc8d492016-02-11 20:43:15 -0600137 l = -1
138 x := uint64(n)
139 for ; x >= 0x8000; x >>= 16 {
140 l += 16
Alexandru Moșoi3e7e5192015-07-17 12:26:35 +0200141 }
Todd Nealadc8d492016-02-11 20:43:15 -0600142 if x >= 0x80 {
143 x >>= 8
144 l += 8
145 }
146 if x >= 0x8 {
147 x >>= 4
148 l += 4
149 }
150 if x >= 0x2 {
151 x >>= 2
152 l += 2
153 }
154 if x >= 0x1 {
155 l++
156 }
157 return
Alexandru Moșoi3e7e5192015-07-17 12:26:35 +0200158}
159
Todd Nealdb523262015-07-25 12:53:58 -0500160// isPowerOfTwo reports whether n is a power of 2.
Alexandru Moșoi3e7e5192015-07-17 12:26:35 +0200161func isPowerOfTwo(n int64) bool {
162 return n > 0 && n&(n-1) == 0
163}
Todd Nealdb523262015-07-25 12:53:58 -0500164
165// is32Bit reports whether n can be represented as a signed 32 bit integer.
166func is32Bit(n int64) bool {
167 return n == int64(int32(n))
168}
Todd Neal991036a2015-09-03 18:24:22 -0500169
170// b2i translates a boolean value to 0 or 1 for assigning to auxInt.
171func b2i(b bool) int64 {
172 if b {
173 return 1
174 }
175 return 0
176}
Todd Neal19447a62015-09-04 06:33:56 -0500177
Todd Nealf6ceed22016-03-11 19:36:54 -0600178// i2f is used in rules for converting from an AuxInt to a float.
179func i2f(i int64) float64 {
180 return math.Float64frombits(uint64(i))
181}
182
183// i2f32 is used in rules for converting from an AuxInt to a float32.
184func i2f32(i int64) float32 {
185 return float32(math.Float64frombits(uint64(i)))
186}
187
Todd Neal19447a62015-09-04 06:33:56 -0500188// f2i is used in the rules for storing a float in AuxInt.
189func f2i(f float64) int64 {
190 return int64(math.Float64bits(f))
191}
Keith Randall04d6edc2015-09-18 18:23:34 -0700192
Todd Neal93a0b0f2016-02-03 06:21:24 -0500193// uaddOvf returns true if unsigned a+b would overflow.
194func uaddOvf(a, b int64) bool {
195 return uint64(a)+uint64(b) < uint64(a)
196}
197
Todd Neal9dc13342016-02-13 17:37:19 -0600198// isSamePtr reports whether p1 and p2 point to the same address.
199func isSamePtr(p1, p2 *Value) bool {
Keith Randalla5325762016-02-24 12:58:47 -0800200 if p1 == p2 {
201 return true
202 }
Josh Bleecher Snyder6ed10382016-03-04 18:55:09 -0800203 if p1.Op != p2.Op {
204 return false
205 }
206 switch p1.Op {
207 case OpOffPtr:
208 return p1.AuxInt == p2.AuxInt && isSamePtr(p1.Args[0], p2.Args[0])
209 case OpAddr:
210 // OpAddr's 0th arg is either OpSP or OpSB, which means that it is uniquely identified by its Op.
211 // Checking for value equality only works after [z]cse has run.
212 return p1.Aux == p2.Aux && p1.Args[0].Op == p2.Args[0].Op
213 case OpAddPtr:
214 return p1.Args[1] == p2.Args[1] && isSamePtr(p1.Args[0], p2.Args[0])
215 }
216 return false
Todd Neal9dc13342016-02-13 17:37:19 -0600217}
218
Keith Randall7c4fbb62015-10-19 13:56:55 -0700219// DUFFZERO consists of repeated blocks of 4 MOVUPSs + ADD,
Keith Randall04d6edc2015-09-18 18:23:34 -0700220// See runtime/mkduff.go.
221const (
Keith Randall7c4fbb62015-10-19 13:56:55 -0700222 dzBlocks = 16 // number of MOV/ADD blocks
Keith Randall04d6edc2015-09-18 18:23:34 -0700223 dzBlockLen = 4 // number of clears per block
224 dzBlockSize = 19 // size of instructions in a single block
225 dzMovSize = 4 // size of single MOV instruction w/ offset
226 dzAddSize = 4 // size of single ADD instruction
Keith Randall7c4fbb62015-10-19 13:56:55 -0700227 dzClearStep = 16 // number of bytes cleared by each MOV instruction
Keith Randall04d6edc2015-09-18 18:23:34 -0700228
229 dzTailLen = 4 // number of final STOSQ instructions
230 dzTailSize = 2 // size of single STOSQ instruction
231
Keith Randall7c4fbb62015-10-19 13:56:55 -0700232 dzClearLen = dzClearStep * dzBlockLen // bytes cleared by one block
233 dzSize = dzBlocks * dzBlockSize
Keith Randall04d6edc2015-09-18 18:23:34 -0700234)
235
236func duffStart(size int64) int64 {
237 x, _ := duff(size)
238 return x
239}
240func duffAdj(size int64) int64 {
241 _, x := duff(size)
242 return x
243}
244
245// duff returns the offset (from duffzero, in bytes) and pointer adjust (in bytes)
246// required to use the duffzero mechanism for a block of the given size.
247func duff(size int64) (int64, int64) {
Keith Randall7c4fbb62015-10-19 13:56:55 -0700248 if size < 32 || size > 1024 || size%dzClearStep != 0 {
Keith Randall04d6edc2015-09-18 18:23:34 -0700249 panic("bad duffzero size")
250 }
251 // TODO: arch-dependent
Keith Randall7c4fbb62015-10-19 13:56:55 -0700252 steps := size / dzClearStep
253 blocks := steps / dzBlockLen
254 steps %= dzBlockLen
255 off := dzBlockSize * (dzBlocks - blocks)
Keith Randall04d6edc2015-09-18 18:23:34 -0700256 var adj int64
Keith Randall7c4fbb62015-10-19 13:56:55 -0700257 if steps != 0 {
258 off -= dzAddSize
259 off -= dzMovSize * steps
260 adj -= dzClearStep * (dzBlockLen - steps)
Keith Randall04d6edc2015-09-18 18:23:34 -0700261 }
262 return off, adj
263}
Keith Randallb81f2f12016-03-28 21:45:33 -0700264
265// mergePoint finds a block among a's blocks which dominates b and is itself
266// dominated by all of a's blocks. Returns nil if it can't find one.
267// Might return nil even if one does exist.
268func mergePoint(b *Block, a ...*Value) *Block {
269 // Walk backward from b looking for one of the a's blocks.
270
271 // Max distance
272 d := 100
273
274 for d > 0 {
275 for _, x := range a {
276 if b == x.Block {
277 goto found
278 }
279 }
280 if len(b.Preds) > 1 {
281 // Don't know which way to go back. Abort.
282 return nil
283 }
284 b = b.Preds[0]
285 d--
286 }
287 return nil // too far away
288found:
289 // At this point, r is the first value in a that we find by walking backwards.
290 // if we return anything, r will be it.
291 r := b
292
293 // Keep going, counting the other a's that we find. They must all dominate r.
294 na := 0
295 for d > 0 {
296 for _, x := range a {
297 if b == x.Block {
298 na++
299 }
300 }
301 if na == len(a) {
302 // Found all of a in a backwards walk. We can return r.
303 return r
304 }
305 if len(b.Preds) > 1 {
306 return nil
307 }
308 b = b.Preds[0]
309 d--
310
311 }
312 return nil // too far away
313}