blob: 28977e268a9852b583dc796bd9362ceef987efab [file] [log] [blame]
Russ Cox8c195bd2015-02-13 14:40:36 -05001// Inferno utils/5c/peep.c
2// http://code.google.com/p/inferno-os/source/browse/utils/5c/peep.c
3//
4// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
5// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
6// Portions Copyright © 1997-1999 Vita Nuova Limited
7// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
8// Portions Copyright © 2004,2006 Bruce Ellis
9// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
10// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
11// Portions Copyright © 2009 The Go Authors. All rights reserved.
12//
13// Permission is hereby granted, free of charge, to any person obtaining a copy
14// of this software and associated documentation files (the "Software"), to deal
15// in the Software without restriction, including without limitation the rights
16// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17// copies of the Software, and to permit persons to whom the Software is
18// furnished to do so, subject to the following conditions:
19//
20// The above copyright notice and this permission notice shall be included in
21// all copies or substantial portions of the Software.
22//
23// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29// THE SOFTWARE.
30
31package main
32
33import (
34 "cmd/internal/obj"
35 "cmd/internal/obj/arm"
36 "fmt"
37)
38import "cmd/internal/gc"
39
40var gactive uint32
41
42// UNUSED
43func peep(firstp *obj.Prog) {
Russ Cox382b44e2015-02-23 16:07:24 -050044 g := (*gc.Graph)(gc.Flowstart(firstp, nil))
Russ Cox8c195bd2015-02-13 14:40:36 -050045 if g == nil {
46 return
47 }
48 gactive = 0
49
Russ Cox382b44e2015-02-23 16:07:24 -050050 var r *gc.Flow
51 var p *obj.Prog
52 var t int
Russ Cox8c195bd2015-02-13 14:40:36 -050053loop1:
54 if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
55 gc.Dumpit("loop1", g.Start, 0)
56 }
57
58 t = 0
59 for r = g.Start; r != nil; r = r.Link {
60 p = r.Prog
61 switch p.As {
62 /*
63 * elide shift into TYPE_SHIFT operand of subsequent instruction
64 */
65 // if(shiftprop(r)) {
66 // excise(r);
67 // t++;
68 // break;
69 // }
70 case arm.ASLL,
71 arm.ASRL,
72 arm.ASRA:
73 break
74
75 case arm.AMOVB,
76 arm.AMOVH,
77 arm.AMOVW,
78 arm.AMOVF,
79 arm.AMOVD:
Russ Coxdc7b54b2015-02-17 22:13:49 -050080 if regtyp(&p.From) {
Russ Cox8c195bd2015-02-13 14:40:36 -050081 if p.From.Type == p.To.Type && isfloatreg(&p.From) == isfloatreg(&p.To) {
82 if p.Scond == arm.C_SCOND_NONE {
Russ Coxdc7b54b2015-02-17 22:13:49 -050083 if copyprop(g, r) {
Russ Cox8c195bd2015-02-13 14:40:36 -050084 excise(r)
85 t++
86 break
87 }
88
Russ Coxdc7b54b2015-02-17 22:13:49 -050089 if subprop(r) && copyprop(g, r) {
Russ Cox8c195bd2015-02-13 14:40:36 -050090 excise(r)
91 t++
92 break
93 }
94 }
95 }
96 }
97
98 case arm.AMOVHS,
99 arm.AMOVHU,
100 arm.AMOVBS,
101 arm.AMOVBU:
102 if p.From.Type == obj.TYPE_REG {
Russ Coxdc7b54b2015-02-17 22:13:49 -0500103 if shortprop(r) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500104 t++
105 }
106 }
107 }
108 }
109
110 /*
111 if(p->scond == C_SCOND_NONE)
112 if(regtyp(&p->to))
113 if(isdconst(&p->from)) {
114 constprop(&p->from, &p->to, r->s1);
115 }
116 break;
117 */
118 if t != 0 {
119 goto loop1
120 }
121
Russ Cox382b44e2015-02-23 16:07:24 -0500122 for r := (*gc.Flow)(g.Start); r != nil; r = r.Link {
Russ Cox8c195bd2015-02-13 14:40:36 -0500123 p = r.Prog
124 switch p.As {
125 /*
126 * EOR -1,x,y => MVN x,y
127 */
128 case arm.AEOR:
Russ Coxdc7b54b2015-02-17 22:13:49 -0500129 if isdconst(&p.From) && p.From.Offset == -1 {
Russ Cox8c195bd2015-02-13 14:40:36 -0500130 p.As = arm.AMVN
131 p.From.Type = obj.TYPE_REG
132 if p.Reg != 0 {
133 p.From.Reg = p.Reg
134 } else {
135 p.From.Reg = p.To.Reg
136 }
137 p.Reg = 0
138 }
139 }
140 }
141
Russ Cox382b44e2015-02-23 16:07:24 -0500142 for r := (*gc.Flow)(g.Start); r != nil; r = r.Link {
Russ Cox8c195bd2015-02-13 14:40:36 -0500143 p = r.Prog
144 switch p.As {
145 case arm.AMOVW,
146 arm.AMOVB,
147 arm.AMOVBS,
148 arm.AMOVBU:
149 if p.From.Type == obj.TYPE_MEM && p.From.Offset == 0 {
150 xtramodes(g, r, &p.From)
151 } else if p.To.Type == obj.TYPE_MEM && p.To.Offset == 0 {
152 xtramodes(g, r, &p.To)
153 } else {
154 continue
155 }
156 }
157 }
158
159 // case ACMP:
160 // /*
161 // * elide CMP $0,x if calculation of x can set condition codes
162 // */
163 // if(isdconst(&p->from) || p->from.offset != 0)
164 // continue;
165 // r2 = r->s1;
166 // if(r2 == nil)
167 // continue;
168 // t = r2->prog->as;
169 // switch(t) {
170 // default:
171 // continue;
172 // case ABEQ:
173 // case ABNE:
174 // case ABMI:
175 // case ABPL:
176 // break;
177 // case ABGE:
178 // t = ABPL;
179 // break;
180 // case ABLT:
181 // t = ABMI;
182 // break;
183 // case ABHI:
184 // t = ABNE;
185 // break;
186 // case ABLS:
187 // t = ABEQ;
188 // break;
189 // }
190 // r1 = r;
191 // do
192 // r1 = uniqp(r1);
193 // while (r1 != nil && r1->prog->as == ANOP);
194 // if(r1 == nil)
195 // continue;
196 // p1 = r1->prog;
197 // if(p1->to.type != TYPE_REG)
198 // continue;
199 // if(p1->to.reg != p->reg)
200 // if(!(p1->as == AMOVW && p1->from.type == TYPE_REG && p1->from.reg == p->reg))
201 // continue;
202 //
203 // switch(p1->as) {
204 // default:
205 // continue;
206 // case AMOVW:
207 // if(p1->from.type != TYPE_REG)
208 // continue;
209 // case AAND:
210 // case AEOR:
211 // case AORR:
212 // case ABIC:
213 // case AMVN:
214 // case ASUB:
215 // case ARSB:
216 // case AADD:
217 // case AADC:
218 // case ASBC:
219 // case ARSC:
220 // break;
221 // }
222 // p1->scond |= C_SBIT;
223 // r2->prog->as = t;
224 // excise(r);
225 // continue;
226
227 // predicate(g);
228
229 gc.Flowend(g)
230}
231
Russ Coxdc7b54b2015-02-17 22:13:49 -0500232func regtyp(a *obj.Addr) bool {
233 return a.Type == obj.TYPE_REG && (arm.REG_R0 <= a.Reg && a.Reg <= arm.REG_R15 || arm.REG_F0 <= a.Reg && a.Reg <= arm.REG_F15)
Russ Cox8c195bd2015-02-13 14:40:36 -0500234}
235
236/*
237 * the idea is to substitute
238 * one register for another
239 * from one MOV to another
240 * MOV a, R0
241 * ADD b, R0 / no use of R1
242 * MOV R0, R1
243 * would be converted to
244 * MOV a, R1
245 * ADD b, R1
246 * MOV R1, R0
247 * hopefully, then the former or latter MOV
248 * will be eliminated by copy propagation.
249 */
Russ Coxdc7b54b2015-02-17 22:13:49 -0500250func subprop(r0 *gc.Flow) bool {
Russ Cox382b44e2015-02-23 16:07:24 -0500251 p := (*obj.Prog)(r0.Prog)
252 v1 := (*obj.Addr)(&p.From)
Russ Coxdc7b54b2015-02-17 22:13:49 -0500253 if !regtyp(v1) {
254 return false
Russ Cox8c195bd2015-02-13 14:40:36 -0500255 }
Russ Cox382b44e2015-02-23 16:07:24 -0500256 v2 := (*obj.Addr)(&p.To)
Russ Coxdc7b54b2015-02-17 22:13:49 -0500257 if !regtyp(v2) {
258 return false
Russ Cox8c195bd2015-02-13 14:40:36 -0500259 }
Russ Cox382b44e2015-02-23 16:07:24 -0500260 var info gc.ProgInfo
Russ Cox79f727a2015-03-02 12:35:15 -0500261 for r := gc.Uniqp(r0); r != nil; r = gc.Uniqp(r) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500262 if gc.Uniqs(r) == nil {
263 break
264 }
265 p = r.Prog
266 if p.As == obj.AVARDEF || p.As == obj.AVARKILL {
267 continue
268 }
269 proginfo(&info, p)
270 if info.Flags&gc.Call != 0 {
Russ Coxdc7b54b2015-02-17 22:13:49 -0500271 return false
Russ Cox8c195bd2015-02-13 14:40:36 -0500272 }
273
274 if (info.Flags&gc.CanRegRead != 0) && p.To.Type == obj.TYPE_REG {
275 info.Flags |= gc.RegRead
276 info.Flags &^= (gc.CanRegRead | gc.RightRead)
277 p.Reg = p.To.Reg
278 }
279
280 switch p.As {
281 case arm.AMULLU,
282 arm.AMULA,
283 arm.AMVN:
Russ Coxdc7b54b2015-02-17 22:13:49 -0500284 return false
Russ Cox8c195bd2015-02-13 14:40:36 -0500285 }
286
287 if info.Flags&(gc.RightRead|gc.RightWrite) == gc.RightWrite {
288 if p.To.Type == v1.Type {
289 if p.To.Reg == v1.Reg {
290 if p.Scond == arm.C_SCOND_NONE {
Russ Cox79f727a2015-03-02 12:35:15 -0500291 copysub(&p.To, v1, v2, 1)
292 if gc.Debug['P'] != 0 {
293 fmt.Printf("gotit: %v->%v\n%v", gc.Ctxt.Dconv(v1), gc.Ctxt.Dconv(v2), r.Prog)
294 if p.From.Type == v2.Type {
295 fmt.Printf(" excise")
296 }
297 fmt.Printf("\n")
298 }
299
300 for r = gc.Uniqs(r); r != r0; r = gc.Uniqs(r) {
301 p = r.Prog
302 copysub(&p.From, v1, v2, 1)
303 copysub1(p, v1, v2, 1)
304 copysub(&p.To, v1, v2, 1)
305 if gc.Debug['P'] != 0 {
306 fmt.Printf("%v\n", r.Prog)
307 }
308 }
309
310 t := int(int(v1.Reg))
311 v1.Reg = v2.Reg
312 v2.Reg = int16(t)
313 if gc.Debug['P'] != 0 {
314 fmt.Printf("%v last\n", r.Prog)
315 }
316 return true
Russ Cox8c195bd2015-02-13 14:40:36 -0500317 }
318 }
319 }
320 }
321
Russ Coxdc7b54b2015-02-17 22:13:49 -0500322 if copyau(&p.From, v2) || copyau1(p, v2) || copyau(&p.To, v2) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500323 break
324 }
325 if copysub(&p.From, v1, v2, 0) != 0 || copysub1(p, v1, v2, 0) != 0 || copysub(&p.To, v1, v2, 0) != 0 {
326 break
327 }
328 }
329
Russ Coxdc7b54b2015-02-17 22:13:49 -0500330 return false
Russ Cox8c195bd2015-02-13 14:40:36 -0500331}
332
333/*
334 * The idea is to remove redundant copies.
335 * v1->v2 F=0
336 * (use v2 s/v2/v1/)*
337 * set v1 F=1
338 * use v2 return fail
339 * -----------------
340 * v1->v2 F=0
341 * (use v2 s/v2/v1/)*
342 * set v1 F=1
343 * set v2 return success
344 */
Russ Coxdc7b54b2015-02-17 22:13:49 -0500345func copyprop(g *gc.Graph, r0 *gc.Flow) bool {
Russ Cox382b44e2015-02-23 16:07:24 -0500346 p := (*obj.Prog)(r0.Prog)
347 v1 := (*obj.Addr)(&p.From)
348 v2 := (*obj.Addr)(&p.To)
Russ Coxdc7b54b2015-02-17 22:13:49 -0500349 if copyas(v1, v2) {
350 return true
Russ Cox8c195bd2015-02-13 14:40:36 -0500351 }
352 gactive++
353 return copy1(v1, v2, r0.S1, 0)
354}
355
Russ Coxdc7b54b2015-02-17 22:13:49 -0500356func copy1(v1 *obj.Addr, v2 *obj.Addr, r *gc.Flow, f int) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -0500357 if uint32(r.Active) == gactive {
358 if gc.Debug['P'] != 0 {
359 fmt.Printf("act set; return 1\n")
360 }
Russ Coxdc7b54b2015-02-17 22:13:49 -0500361 return true
Russ Cox8c195bd2015-02-13 14:40:36 -0500362 }
363
364 r.Active = int32(gactive)
365 if gc.Debug['P'] != 0 {
366 fmt.Printf("copy %v->%v f=%d\n", gc.Ctxt.Dconv(v1), gc.Ctxt.Dconv(v2), f)
367 }
Russ Cox382b44e2015-02-23 16:07:24 -0500368 var t int
369 var p *obj.Prog
Russ Cox8c195bd2015-02-13 14:40:36 -0500370 for ; r != nil; r = r.S1 {
371 p = r.Prog
372 if gc.Debug['P'] != 0 {
373 fmt.Printf("%v", p)
374 }
Russ Coxdc7b54b2015-02-17 22:13:49 -0500375 if f == 0 && gc.Uniqp(r) == nil {
Russ Cox8c195bd2015-02-13 14:40:36 -0500376 f = 1
377 if gc.Debug['P'] != 0 {
378 fmt.Printf("; merge; f=%d", f)
379 }
380 }
381
382 t = copyu(p, v2, nil)
383 switch t {
384 case 2: /* rar, can't split */
385 if gc.Debug['P'] != 0 {
386 fmt.Printf("; %vrar; return 0\n", gc.Ctxt.Dconv(v2))
387 }
Russ Coxdc7b54b2015-02-17 22:13:49 -0500388 return false
Russ Cox8c195bd2015-02-13 14:40:36 -0500389
390 case 3: /* set */
391 if gc.Debug['P'] != 0 {
392 fmt.Printf("; %vset; return 1\n", gc.Ctxt.Dconv(v2))
393 }
Russ Coxdc7b54b2015-02-17 22:13:49 -0500394 return true
Russ Cox8c195bd2015-02-13 14:40:36 -0500395
396 case 1, /* used, substitute */
397 4: /* use and set */
398 if f != 0 {
Russ Coxdc7b54b2015-02-17 22:13:49 -0500399 if gc.Debug['P'] == 0 {
400 return false
Russ Cox8c195bd2015-02-13 14:40:36 -0500401 }
402 if t == 4 {
403 fmt.Printf("; %vused+set and f=%d; return 0\n", gc.Ctxt.Dconv(v2), f)
404 } else {
405 fmt.Printf("; %vused and f=%d; return 0\n", gc.Ctxt.Dconv(v2), f)
406 }
Russ Coxdc7b54b2015-02-17 22:13:49 -0500407 return false
Russ Cox8c195bd2015-02-13 14:40:36 -0500408 }
409
410 if copyu(p, v2, v1) != 0 {
411 if gc.Debug['P'] != 0 {
412 fmt.Printf("; sub fail; return 0\n")
413 }
Russ Coxdc7b54b2015-02-17 22:13:49 -0500414 return false
Russ Cox8c195bd2015-02-13 14:40:36 -0500415 }
416
417 if gc.Debug['P'] != 0 {
418 fmt.Printf("; sub%v/%v", gc.Ctxt.Dconv(v2), gc.Ctxt.Dconv(v1))
419 }
420 if t == 4 {
421 if gc.Debug['P'] != 0 {
422 fmt.Printf("; %vused+set; return 1\n", gc.Ctxt.Dconv(v2))
423 }
Russ Coxdc7b54b2015-02-17 22:13:49 -0500424 return true
Russ Cox8c195bd2015-02-13 14:40:36 -0500425 }
426 }
427
Russ Coxdc7b54b2015-02-17 22:13:49 -0500428 if f == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -0500429 t = copyu(p, v1, nil)
Russ Coxdc7b54b2015-02-17 22:13:49 -0500430 if f == 0 && (t == 2 || t == 3 || t == 4) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500431 f = 1
432 if gc.Debug['P'] != 0 {
433 fmt.Printf("; %vset and !f; f=%d", gc.Ctxt.Dconv(v1), f)
434 }
435 }
436 }
437
438 if gc.Debug['P'] != 0 {
439 fmt.Printf("\n")
440 }
441 if r.S2 != nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -0500442 if !copy1(v1, v2, r.S2, f) {
443 return false
Russ Cox8c195bd2015-02-13 14:40:36 -0500444 }
445 }
446 }
447
Russ Coxdc7b54b2015-02-17 22:13:49 -0500448 return true
Russ Cox8c195bd2015-02-13 14:40:36 -0500449}
450
451// UNUSED
452/*
453 * The idea is to remove redundant constants.
454 * $c1->v1
455 * ($c1->v2 s/$c1/v1)*
456 * set v1 return
457 * The v1->v2 should be eliminated by copy propagation.
458 */
459func constprop(c1 *obj.Addr, v1 *obj.Addr, r *gc.Flow) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500460 if gc.Debug['P'] != 0 {
461 fmt.Printf("constprop %v->%v\n", gc.Ctxt.Dconv(c1), gc.Ctxt.Dconv(v1))
462 }
Russ Cox382b44e2015-02-23 16:07:24 -0500463 var p *obj.Prog
Russ Cox8c195bd2015-02-13 14:40:36 -0500464 for ; r != nil; r = r.S1 {
465 p = r.Prog
466 if gc.Debug['P'] != 0 {
467 fmt.Printf("%v", p)
468 }
469 if gc.Uniqp(r) == nil {
470 if gc.Debug['P'] != 0 {
471 fmt.Printf("; merge; return\n")
472 }
473 return
474 }
475
Russ Coxdc7b54b2015-02-17 22:13:49 -0500476 if p.As == arm.AMOVW && copyas(&p.From, c1) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500477 if gc.Debug['P'] != 0 {
478 fmt.Printf("; sub%v/%v", gc.Ctxt.Dconv(&p.From), gc.Ctxt.Dconv(v1))
479 }
480 p.From = *v1
481 } else if copyu(p, v1, nil) > 1 {
482 if gc.Debug['P'] != 0 {
483 fmt.Printf("; %vset; return\n", gc.Ctxt.Dconv(v1))
484 }
485 return
486 }
487
488 if gc.Debug['P'] != 0 {
489 fmt.Printf("\n")
490 }
491 if r.S2 != nil {
492 constprop(c1, v1, r.S2)
493 }
494 }
495}
496
497/*
498 * shortprop eliminates redundant zero/sign extensions.
499 *
500 * MOVBS x, R
501 * <no use R>
502 * MOVBS R, R'
503 *
504 * changed to
505 *
506 * MOVBS x, R
507 * ...
508 * MOVB R, R' (compiled to mov)
509 *
510 * MOVBS above can be a MOVBS, MOVBU, MOVHS or MOVHU.
511 */
Russ Coxdc7b54b2015-02-17 22:13:49 -0500512func shortprop(r *gc.Flow) bool {
Russ Cox382b44e2015-02-23 16:07:24 -0500513 p := (*obj.Prog)(r.Prog)
514 r1 := (*gc.Flow)(findpre(r, &p.From))
Russ Cox8c195bd2015-02-13 14:40:36 -0500515 if r1 == nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -0500516 return false
Russ Cox8c195bd2015-02-13 14:40:36 -0500517 }
518
Russ Cox382b44e2015-02-23 16:07:24 -0500519 p1 := (*obj.Prog)(r1.Prog)
Russ Cox8c195bd2015-02-13 14:40:36 -0500520 if p1.As == p.As {
521 // Two consecutive extensions.
522 goto gotit
523 }
524
Russ Coxdc7b54b2015-02-17 22:13:49 -0500525 if p1.As == arm.AMOVW && isdconst(&p1.From) && p1.From.Offset >= 0 && p1.From.Offset < 128 {
Russ Cox8c195bd2015-02-13 14:40:36 -0500526 // Loaded an immediate.
527 goto gotit
528 }
529
Russ Coxdc7b54b2015-02-17 22:13:49 -0500530 return false
Russ Cox8c195bd2015-02-13 14:40:36 -0500531
532gotit:
533 if gc.Debug['P'] != 0 {
534 fmt.Printf("shortprop\n%v\n%v", p1, p)
535 }
536 switch p.As {
537 case arm.AMOVBS,
538 arm.AMOVBU:
539 p.As = arm.AMOVB
540
541 case arm.AMOVHS,
542 arm.AMOVHU:
543 p.As = arm.AMOVH
544 }
545
546 if gc.Debug['P'] != 0 {
Rob Pike74e88df2015-03-02 20:17:20 -0800547 fmt.Printf(" => %v\n", obj.Aconv(int(p.As)))
Russ Cox8c195bd2015-02-13 14:40:36 -0500548 }
Russ Coxdc7b54b2015-02-17 22:13:49 -0500549 return true
Russ Cox8c195bd2015-02-13 14:40:36 -0500550}
551
552// UNUSED
553/*
554 * ASLL x,y,w
555 * .. (not use w, not set x y w)
556 * AXXX w,a,b (a != w)
557 * .. (not use w)
558 * (set w)
559 * ----------- changed to
560 * ..
561 * AXXX (x<<y),a,b
562 * ..
563 */
Russ Coxdc7b54b2015-02-17 22:13:49 -0500564func shiftprop(r *gc.Flow) bool {
Russ Cox382b44e2015-02-23 16:07:24 -0500565 p := (*obj.Prog)(r.Prog)
Russ Cox8c195bd2015-02-13 14:40:36 -0500566 if p.To.Type != obj.TYPE_REG {
567 if gc.Debug['P'] != 0 {
568 fmt.Printf("\tBOTCH: result not reg; FAILURE\n")
569 }
Russ Coxdc7b54b2015-02-17 22:13:49 -0500570 return false
Russ Cox8c195bd2015-02-13 14:40:36 -0500571 }
572
Russ Cox382b44e2015-02-23 16:07:24 -0500573 n := int(int(p.To.Reg))
574 a := obj.Addr(obj.Addr{})
Russ Cox8c195bd2015-02-13 14:40:36 -0500575 if p.Reg != 0 && p.Reg != p.To.Reg {
576 a.Type = obj.TYPE_REG
577 a.Reg = p.Reg
578 }
579
580 if gc.Debug['P'] != 0 {
581 fmt.Printf("shiftprop\n%v", p)
582 }
Russ Cox382b44e2015-02-23 16:07:24 -0500583 r1 := (*gc.Flow)(r)
584 var p1 *obj.Prog
Russ Cox8c195bd2015-02-13 14:40:36 -0500585 for {
586 /* find first use of shift result; abort if shift operands or result are changed */
587 r1 = gc.Uniqs(r1)
588
589 if r1 == nil {
590 if gc.Debug['P'] != 0 {
591 fmt.Printf("\tbranch; FAILURE\n")
592 }
Russ Coxdc7b54b2015-02-17 22:13:49 -0500593 return false
Russ Cox8c195bd2015-02-13 14:40:36 -0500594 }
595
596 if gc.Uniqp(r1) == nil {
597 if gc.Debug['P'] != 0 {
598 fmt.Printf("\tmerge; FAILURE\n")
599 }
Russ Coxdc7b54b2015-02-17 22:13:49 -0500600 return false
Russ Cox8c195bd2015-02-13 14:40:36 -0500601 }
602
603 p1 = r1.Prog
604 if gc.Debug['P'] != 0 {
605 fmt.Printf("\n%v", p1)
606 }
607 switch copyu(p1, &p.To, nil) {
608 case 0: /* not used or set */
609 if (p.From.Type == obj.TYPE_REG && copyu(p1, &p.From, nil) > 1) || (a.Type == obj.TYPE_REG && copyu(p1, &a, nil) > 1) {
610 if gc.Debug['P'] != 0 {
611 fmt.Printf("\targs modified; FAILURE\n")
612 }
Russ Coxdc7b54b2015-02-17 22:13:49 -0500613 return false
Russ Cox8c195bd2015-02-13 14:40:36 -0500614 }
615
616 continue
617 case 3: /* set, not used */
618 {
619 if gc.Debug['P'] != 0 {
620 fmt.Printf("\tBOTCH: noref; FAILURE\n")
621 }
Russ Coxdc7b54b2015-02-17 22:13:49 -0500622 return false
Russ Cox8c195bd2015-02-13 14:40:36 -0500623 }
624 }
625
626 break
627 }
628
629 /* check whether substitution can be done */
630 switch p1.As {
631 default:
632 if gc.Debug['P'] != 0 {
633 fmt.Printf("\tnon-dpi; FAILURE\n")
634 }
Russ Coxdc7b54b2015-02-17 22:13:49 -0500635 return false
Russ Cox8c195bd2015-02-13 14:40:36 -0500636
637 case arm.AAND,
638 arm.AEOR,
639 arm.AADD,
640 arm.AADC,
641 arm.AORR,
642 arm.ASUB,
643 arm.ASBC,
644 arm.ARSB,
645 arm.ARSC:
646 if int(p1.Reg) == n || (p1.Reg == 0 && p1.To.Type == obj.TYPE_REG && int(p1.To.Reg) == n) {
647 if p1.From.Type != obj.TYPE_REG {
648 if gc.Debug['P'] != 0 {
649 fmt.Printf("\tcan't swap; FAILURE\n")
650 }
Russ Coxdc7b54b2015-02-17 22:13:49 -0500651 return false
Russ Cox8c195bd2015-02-13 14:40:36 -0500652 }
653
654 p1.Reg = p1.From.Reg
655 p1.From.Reg = int16(n)
656 switch p1.As {
657 case arm.ASUB:
658 p1.As = arm.ARSB
659
660 case arm.ARSB:
661 p1.As = arm.ASUB
662
663 case arm.ASBC:
664 p1.As = arm.ARSC
665
666 case arm.ARSC:
667 p1.As = arm.ASBC
668 }
669
670 if gc.Debug['P'] != 0 {
671 fmt.Printf("\t=>%v", p1)
672 }
673 }
674 fallthrough
675
676 case arm.ABIC,
677 arm.ATST,
678 arm.ACMP,
679 arm.ACMN:
680 if int(p1.Reg) == n {
681 if gc.Debug['P'] != 0 {
682 fmt.Printf("\tcan't swap; FAILURE\n")
683 }
Russ Coxdc7b54b2015-02-17 22:13:49 -0500684 return false
Russ Cox8c195bd2015-02-13 14:40:36 -0500685 }
686
687 if p1.Reg == 0 && int(p1.To.Reg) == n {
688 if gc.Debug['P'] != 0 {
689 fmt.Printf("\tshift result used twice; FAILURE\n")
690 }
Russ Coxdc7b54b2015-02-17 22:13:49 -0500691 return false
Russ Cox8c195bd2015-02-13 14:40:36 -0500692 }
693
694 // case AMVN:
695 if p1.From.Type == obj.TYPE_SHIFT {
696 if gc.Debug['P'] != 0 {
697 fmt.Printf("\tshift result used in shift; FAILURE\n")
698 }
Russ Coxdc7b54b2015-02-17 22:13:49 -0500699 return false
Russ Cox8c195bd2015-02-13 14:40:36 -0500700 }
701
702 if p1.From.Type != obj.TYPE_REG || int(p1.From.Reg) != n {
703 if gc.Debug['P'] != 0 {
704 fmt.Printf("\tBOTCH: where is it used?; FAILURE\n")
705 }
Russ Coxdc7b54b2015-02-17 22:13:49 -0500706 return false
Russ Cox8c195bd2015-02-13 14:40:36 -0500707 }
708 }
709
710 /* check whether shift result is used subsequently */
Russ Cox382b44e2015-02-23 16:07:24 -0500711 p2 := (*obj.Prog)(p1)
Russ Cox8c195bd2015-02-13 14:40:36 -0500712
713 if int(p1.To.Reg) != n {
Russ Cox382b44e2015-02-23 16:07:24 -0500714 var p1 *obj.Prog
Russ Cox8c195bd2015-02-13 14:40:36 -0500715 for {
716 r1 = gc.Uniqs(r1)
717 if r1 == nil {
718 if gc.Debug['P'] != 0 {
719 fmt.Printf("\tinconclusive; FAILURE\n")
720 }
Russ Coxdc7b54b2015-02-17 22:13:49 -0500721 return false
Russ Cox8c195bd2015-02-13 14:40:36 -0500722 }
723
724 p1 = r1.Prog
725 if gc.Debug['P'] != 0 {
726 fmt.Printf("\n%v", p1)
727 }
728 switch copyu(p1, &p.To, nil) {
729 case 0: /* not used or set */
730 continue
731
732 case 3: /* set, not used */
733 break
734
735 default: /* used */
736 if gc.Debug['P'] != 0 {
737 fmt.Printf("\treused; FAILURE\n")
738 }
Russ Coxdc7b54b2015-02-17 22:13:49 -0500739 return false
Russ Cox8c195bd2015-02-13 14:40:36 -0500740 }
741
742 break
743 }
744 }
745
746 /* make the substitution */
747 p2.From.Reg = 0
748
Russ Cox382b44e2015-02-23 16:07:24 -0500749 o := int(int(p.Reg))
Russ Cox8c195bd2015-02-13 14:40:36 -0500750 if o == 0 {
751 o = int(p.To.Reg)
752 }
753 o &= 15
754
755 switch p.From.Type {
756 case obj.TYPE_CONST:
757 o |= int((p.From.Offset & 0x1f) << 7)
758
759 case obj.TYPE_REG:
760 o |= 1<<4 | (int(p.From.Reg)&15)<<8
761 }
762
763 switch p.As {
764 case arm.ASLL:
765 o |= 0 << 5
766
767 case arm.ASRL:
768 o |= 1 << 5
769
770 case arm.ASRA:
771 o |= 2 << 5
772 }
773
Russ Coxdc7b54b2015-02-17 22:13:49 -0500774 p2.From = obj.Addr{}
Russ Cox8c195bd2015-02-13 14:40:36 -0500775 p2.From.Type = obj.TYPE_SHIFT
776 p2.From.Offset = int64(o)
777 if gc.Debug['P'] != 0 {
778 fmt.Printf("\t=>%v\tSUCCEED\n", p2)
779 }
Russ Coxdc7b54b2015-02-17 22:13:49 -0500780 return true
Russ Cox8c195bd2015-02-13 14:40:36 -0500781}
782
783/*
784 * findpre returns the last instruction mentioning v
785 * before r. It must be a set, and there must be
786 * a unique path from that instruction to r.
787 */
788func findpre(r *gc.Flow, v *obj.Addr) *gc.Flow {
789 var r1 *gc.Flow
790
791 for r1 = gc.Uniqp(r); r1 != nil; (func() { r = r1; r1 = gc.Uniqp(r) })() {
792 if gc.Uniqs(r1) != r {
793 return nil
794 }
795 switch copyu(r1.Prog, v, nil) {
796 case 1, /* used */
797 2: /* read-alter-rewrite */
798 return nil
799
800 case 3, /* set */
801 4: /* set and used */
802 return r1
803 }
804 }
805
806 return nil
807}
808
809/*
810 * findinc finds ADD instructions with a constant
811 * argument which falls within the immed_12 range.
812 */
813func findinc(r *gc.Flow, r2 *gc.Flow, v *obj.Addr) *gc.Flow {
814 var r1 *gc.Flow
815 var p *obj.Prog
816
817 for r1 = gc.Uniqs(r); r1 != nil && r1 != r2; (func() { r = r1; r1 = gc.Uniqs(r) })() {
818 if gc.Uniqp(r1) != r {
819 return nil
820 }
821 switch copyu(r1.Prog, v, nil) {
822 case 0: /* not touched */
823 continue
824
825 case 4: /* set and used */
826 p = r1.Prog
827
828 if p.As == arm.AADD {
Russ Coxdc7b54b2015-02-17 22:13:49 -0500829 if isdconst(&p.From) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500830 if p.From.Offset > -4096 && p.From.Offset < 4096 {
831 return r1
832 }
833 }
834 }
835 fallthrough
836
837 default:
838 return nil
839 }
840 }
841
842 return nil
843}
844
Russ Coxdc7b54b2015-02-17 22:13:49 -0500845func nochange(r *gc.Flow, r2 *gc.Flow, p *obj.Prog) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -0500846 if r == r2 {
Russ Coxdc7b54b2015-02-17 22:13:49 -0500847 return true
Russ Cox8c195bd2015-02-13 14:40:36 -0500848 }
Russ Cox382b44e2015-02-23 16:07:24 -0500849 n := int(0)
850 var a [3]obj.Addr
Russ Cox8c195bd2015-02-13 14:40:36 -0500851 if p.Reg != 0 && p.Reg != p.To.Reg {
852 a[n].Type = obj.TYPE_REG
853 a[n].Reg = p.Reg
854 n++
855 }
856
857 switch p.From.Type {
858 case obj.TYPE_SHIFT:
859 a[n].Type = obj.TYPE_REG
860 a[n].Reg = int16(arm.REG_R0 + (p.From.Offset & 0xf))
861 n++
862 fallthrough
863
864 case obj.TYPE_REG:
865 a[n].Type = obj.TYPE_REG
866 a[n].Reg = p.From.Reg
867 n++
868 }
869
870 if n == 0 {
Russ Coxdc7b54b2015-02-17 22:13:49 -0500871 return true
Russ Cox8c195bd2015-02-13 14:40:36 -0500872 }
Russ Cox382b44e2015-02-23 16:07:24 -0500873 var i int
Russ Cox8c195bd2015-02-13 14:40:36 -0500874 for ; r != nil && r != r2; r = gc.Uniqs(r) {
875 p = r.Prog
876 for i = 0; i < n; i++ {
877 if copyu(p, &a[i], nil) > 1 {
Russ Coxdc7b54b2015-02-17 22:13:49 -0500878 return false
Russ Cox8c195bd2015-02-13 14:40:36 -0500879 }
880 }
881 }
882
Russ Coxdc7b54b2015-02-17 22:13:49 -0500883 return true
Russ Cox8c195bd2015-02-13 14:40:36 -0500884}
885
Russ Coxdc7b54b2015-02-17 22:13:49 -0500886func findu1(r *gc.Flow, v *obj.Addr) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -0500887 for ; r != nil; r = r.S1 {
888 if r.Active != 0 {
Russ Coxdc7b54b2015-02-17 22:13:49 -0500889 return false
Russ Cox8c195bd2015-02-13 14:40:36 -0500890 }
891 r.Active = 1
892 switch copyu(r.Prog, v, nil) {
893 case 1, /* used */
894 2, /* read-alter-rewrite */
895 4: /* set and used */
Russ Coxdc7b54b2015-02-17 22:13:49 -0500896 return true
Russ Cox8c195bd2015-02-13 14:40:36 -0500897
898 case 3: /* set */
Russ Coxdc7b54b2015-02-17 22:13:49 -0500899 return false
Russ Cox8c195bd2015-02-13 14:40:36 -0500900 }
901
902 if r.S2 != nil {
Russ Coxdc7b54b2015-02-17 22:13:49 -0500903 if findu1(r.S2, v) {
904 return true
Russ Cox8c195bd2015-02-13 14:40:36 -0500905 }
906 }
907 }
908
Russ Coxdc7b54b2015-02-17 22:13:49 -0500909 return false
Russ Cox8c195bd2015-02-13 14:40:36 -0500910}
911
Russ Coxdc7b54b2015-02-17 22:13:49 -0500912func finduse(g *gc.Graph, r *gc.Flow, v *obj.Addr) bool {
Russ Cox382b44e2015-02-23 16:07:24 -0500913 for r1 := (*gc.Flow)(g.Start); r1 != nil; r1 = r1.Link {
Russ Cox8c195bd2015-02-13 14:40:36 -0500914 r1.Active = 0
915 }
916 return findu1(r, v)
917}
918
919/*
920 * xtramodes enables the ARM post increment and
921 * shift offset addressing modes to transform
922 * MOVW 0(R3),R1
923 * ADD $4,R3,R3
924 * into
925 * MOVW.P 4(R3),R1
926 * and
927 * ADD R0,R1
928 * MOVBU 0(R1),R0
929 * into
930 * MOVBU R0<<0(R1),R0
931 */
Russ Coxdc7b54b2015-02-17 22:13:49 -0500932func xtramodes(g *gc.Graph, r *gc.Flow, a *obj.Addr) bool {
Russ Cox382b44e2015-02-23 16:07:24 -0500933 p := (*obj.Prog)(r.Prog)
934 v := obj.Addr(*a)
Russ Cox8c195bd2015-02-13 14:40:36 -0500935 v.Type = obj.TYPE_REG
Russ Cox382b44e2015-02-23 16:07:24 -0500936 r1 := (*gc.Flow)(findpre(r, &v))
Russ Cox8c195bd2015-02-13 14:40:36 -0500937 if r1 != nil {
Russ Cox382b44e2015-02-23 16:07:24 -0500938 p1 := r1.Prog
Russ Cox8c195bd2015-02-13 14:40:36 -0500939 if p1.To.Type == obj.TYPE_REG && p1.To.Reg == v.Reg {
940 switch p1.As {
941 case arm.AADD:
942 if p1.Scond&arm.C_SBIT != 0 {
943 // avoid altering ADD.S/ADC sequences.
944 break
945 }
946
947 if p1.From.Type == obj.TYPE_REG || (p1.From.Type == obj.TYPE_SHIFT && p1.From.Offset&(1<<4) == 0 && ((p.As != arm.AMOVB && p.As != arm.AMOVBS) || (a == &p.From && p1.From.Offset&^0xf == 0))) || ((p1.From.Type == obj.TYPE_ADDR || p1.From.Type == obj.TYPE_CONST) && p1.From.Offset > -4096 && p1.From.Offset < 4096) {
Russ Coxdc7b54b2015-02-17 22:13:49 -0500948 if nochange(gc.Uniqs(r1), r, p1) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500949 if a != &p.From || v.Reg != p.To.Reg {
Russ Coxdc7b54b2015-02-17 22:13:49 -0500950 if finduse(g, r.S1, &v) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500951 if p1.Reg == 0 || p1.Reg == v.Reg {
952 /* pre-indexing */
953 p.Scond |= arm.C_WBIT
954 } else {
Russ Coxdc7b54b2015-02-17 22:13:49 -0500955 return false
Russ Cox8c195bd2015-02-13 14:40:36 -0500956 }
957 }
958 }
959
960 switch p1.From.Type {
961 /* register offset */
962 case obj.TYPE_REG:
963 if gc.Nacl {
Russ Coxdc7b54b2015-02-17 22:13:49 -0500964 return false
Russ Cox8c195bd2015-02-13 14:40:36 -0500965 }
Russ Coxdc7b54b2015-02-17 22:13:49 -0500966 *a = obj.Addr{}
Russ Cox8c195bd2015-02-13 14:40:36 -0500967 a.Type = obj.TYPE_SHIFT
968 a.Offset = int64(p1.From.Reg) & 15
969
970 /* scaled register offset */
971 case obj.TYPE_SHIFT:
972 if gc.Nacl {
Russ Coxdc7b54b2015-02-17 22:13:49 -0500973 return false
Russ Cox8c195bd2015-02-13 14:40:36 -0500974 }
Russ Coxdc7b54b2015-02-17 22:13:49 -0500975 *a = obj.Addr{}
Russ Cox8c195bd2015-02-13 14:40:36 -0500976 a.Type = obj.TYPE_SHIFT
977 fallthrough
978
979 /* immediate offset */
980 case obj.TYPE_CONST,
981 obj.TYPE_ADDR:
982 a.Offset = p1.From.Offset
983 }
984
985 if p1.Reg != 0 {
986 a.Reg = p1.Reg
987 }
988 excise(r1)
Russ Coxdc7b54b2015-02-17 22:13:49 -0500989 return true
Russ Cox8c195bd2015-02-13 14:40:36 -0500990 }
991 }
992
993 case arm.AMOVW:
994 if p1.From.Type == obj.TYPE_REG {
Russ Cox382b44e2015-02-23 16:07:24 -0500995 r2 := (*gc.Flow)(findinc(r1, r, &p1.From))
Russ Cox8c195bd2015-02-13 14:40:36 -0500996 if r2 != nil {
Russ Cox382b44e2015-02-23 16:07:24 -0500997 var r3 *gc.Flow
Russ Cox8c195bd2015-02-13 14:40:36 -0500998 for r3 = gc.Uniqs(r2); r3.Prog.As == obj.ANOP; r3 = gc.Uniqs(r3) {
999 }
1000 if r3 == r {
1001 /* post-indexing */
Russ Cox382b44e2015-02-23 16:07:24 -05001002 p1 := r2.Prog
Russ Cox8c195bd2015-02-13 14:40:36 -05001003
1004 a.Reg = p1.To.Reg
1005 a.Offset = p1.From.Offset
1006 p.Scond |= arm.C_PBIT
Russ Coxdc7b54b2015-02-17 22:13:49 -05001007 if !finduse(g, r, &r1.Prog.To) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001008 excise(r1)
1009 }
1010 excise(r2)
Russ Coxdc7b54b2015-02-17 22:13:49 -05001011 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05001012 }
1013 }
1014 }
1015 }
1016 }
1017 }
1018
1019 if a != &p.From || a.Reg != p.To.Reg {
Russ Cox382b44e2015-02-23 16:07:24 -05001020 r1 := (*gc.Flow)(findinc(r, nil, &v))
Russ Cox8c195bd2015-02-13 14:40:36 -05001021 if r1 != nil {
1022 /* post-indexing */
Russ Cox382b44e2015-02-23 16:07:24 -05001023 p1 := r1.Prog
Russ Cox8c195bd2015-02-13 14:40:36 -05001024
1025 a.Offset = p1.From.Offset
1026 p.Scond |= arm.C_PBIT
1027 excise(r1)
Russ Coxdc7b54b2015-02-17 22:13:49 -05001028 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05001029 }
1030 }
1031
Russ Coxdc7b54b2015-02-17 22:13:49 -05001032 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05001033}
1034
1035/*
1036 * return
1037 * 1 if v only used (and substitute),
1038 * 2 if read-alter-rewrite
1039 * 3 if set
1040 * 4 if set and used
1041 * 0 otherwise (not touched)
1042 */
1043func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int {
1044 switch p.As {
1045 default:
Rob Pike74e88df2015-03-02 20:17:20 -08001046 fmt.Printf("copyu: can't find %v\n", obj.Aconv(int(p.As)))
Russ Cox8c195bd2015-02-13 14:40:36 -05001047 return 2
1048
1049 case arm.AMOVM:
1050 if v.Type != obj.TYPE_REG {
1051 return 0
1052 }
1053 if p.From.Type == obj.TYPE_CONST { /* read reglist, read/rar */
1054 if s != nil {
1055 if p.From.Offset&(1<<uint(v.Reg)) != 0 {
1056 return 1
1057 }
1058 if copysub(&p.To, v, s, 1) != 0 {
1059 return 1
1060 }
1061 return 0
1062 }
1063
Russ Coxdc7b54b2015-02-17 22:13:49 -05001064 if copyau(&p.To, v) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001065 if p.Scond&arm.C_WBIT != 0 {
1066 return 2
1067 }
1068 return 1
1069 }
1070
1071 if p.From.Offset&(1<<uint(v.Reg)) != 0 {
1072 return 1 /* read/rar, write reglist */
1073 }
1074 } else {
1075 if s != nil {
1076 if p.To.Offset&(1<<uint(v.Reg)) != 0 {
1077 return 1
1078 }
1079 if copysub(&p.From, v, s, 1) != 0 {
1080 return 1
1081 }
1082 return 0
1083 }
1084
Russ Coxdc7b54b2015-02-17 22:13:49 -05001085 if copyau(&p.From, v) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001086 if p.Scond&arm.C_WBIT != 0 {
1087 return 2
1088 }
1089 if p.To.Offset&(1<<uint(v.Reg)) != 0 {
1090 return 4
1091 }
1092 return 1
1093 }
1094
1095 if p.To.Offset&(1<<uint(v.Reg)) != 0 {
1096 return 3
1097 }
1098 }
1099
1100 return 0
1101
1102 case obj.ANOP, /* read,, write */
1103 arm.AMOVW,
1104 arm.AMOVF,
1105 arm.AMOVD,
1106 arm.AMOVH,
1107 arm.AMOVHS,
1108 arm.AMOVHU,
1109 arm.AMOVB,
1110 arm.AMOVBS,
1111 arm.AMOVBU,
1112 arm.AMOVFW,
1113 arm.AMOVWF,
1114 arm.AMOVDW,
1115 arm.AMOVWD,
1116 arm.AMOVFD,
1117 arm.AMOVDF:
1118 if p.Scond&(arm.C_WBIT|arm.C_PBIT) != 0 {
1119 if v.Type == obj.TYPE_REG {
1120 if p.From.Type == obj.TYPE_MEM || p.From.Type == obj.TYPE_SHIFT {
1121 if p.From.Reg == v.Reg {
1122 return 2
1123 }
1124 } else {
1125 if p.To.Reg == v.Reg {
1126 return 2
1127 }
1128 }
1129 }
1130 }
1131
1132 if s != nil {
1133 if copysub(&p.From, v, s, 1) != 0 {
1134 return 1
1135 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05001136 if !copyas(&p.To, v) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001137 if copysub(&p.To, v, s, 1) != 0 {
1138 return 1
1139 }
1140 }
1141 return 0
1142 }
1143
Russ Coxdc7b54b2015-02-17 22:13:49 -05001144 if copyas(&p.To, v) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001145 if p.Scond != arm.C_SCOND_NONE {
1146 return 2
1147 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05001148 if copyau(&p.From, v) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001149 return 4
1150 }
1151 return 3
1152 }
1153
Russ Coxdc7b54b2015-02-17 22:13:49 -05001154 if copyau(&p.From, v) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001155 return 1
1156 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05001157 if copyau(&p.To, v) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001158 return 1
1159 }
1160 return 0
1161
1162 case arm.AMULLU, /* read, read, write, write */
1163 arm.AMULL,
1164 arm.AMULA,
1165 arm.AMVN:
1166 return 2
1167
1168 case arm.AADD, /* read, read, write */
1169 arm.AADC,
1170 arm.ASUB,
1171 arm.ASBC,
1172 arm.ARSB,
1173 arm.ASLL,
1174 arm.ASRL,
1175 arm.ASRA,
1176 arm.AORR,
1177 arm.AAND,
1178 arm.AEOR,
1179 arm.AMUL,
1180 arm.AMULU,
1181 arm.ADIV,
1182 arm.ADIVU,
1183 arm.AMOD,
1184 arm.AMODU,
1185 arm.AADDF,
1186 arm.AADDD,
1187 arm.ASUBF,
1188 arm.ASUBD,
1189 arm.AMULF,
1190 arm.AMULD,
1191 arm.ADIVF,
1192 arm.ADIVD,
1193 obj.ACHECKNIL,
1194 /* read */
1195 arm.ACMPF, /* read, read, */
1196 arm.ACMPD,
1197 arm.ACMP,
1198 arm.ACMN,
1199 arm.ACASE,
1200 arm.ATST:
1201 /* read,, */
1202 if s != nil {
1203 if copysub(&p.From, v, s, 1) != 0 {
1204 return 1
1205 }
1206 if copysub1(p, v, s, 1) != 0 {
1207 return 1
1208 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05001209 if !copyas(&p.To, v) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001210 if copysub(&p.To, v, s, 1) != 0 {
1211 return 1
1212 }
1213 }
1214 return 0
1215 }
1216
Russ Coxdc7b54b2015-02-17 22:13:49 -05001217 if copyas(&p.To, v) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001218 if p.Scond != arm.C_SCOND_NONE {
1219 return 2
1220 }
1221 if p.Reg == 0 {
1222 p.Reg = p.To.Reg
1223 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05001224 if copyau(&p.From, v) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001225 return 4
1226 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05001227 if copyau1(p, v) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001228 return 4
1229 }
1230 return 3
1231 }
1232
Russ Coxdc7b54b2015-02-17 22:13:49 -05001233 if copyau(&p.From, v) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001234 return 1
1235 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05001236 if copyau1(p, v) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001237 return 1
1238 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05001239 if copyau(&p.To, v) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001240 return 1
1241 }
1242 return 0
1243
1244 case arm.ABEQ, /* read, read */
1245 arm.ABNE,
1246 arm.ABCS,
1247 arm.ABHS,
1248 arm.ABCC,
1249 arm.ABLO,
1250 arm.ABMI,
1251 arm.ABPL,
1252 arm.ABVS,
1253 arm.ABVC,
1254 arm.ABHI,
1255 arm.ABLS,
1256 arm.ABGE,
1257 arm.ABLT,
1258 arm.ABGT,
1259 arm.ABLE:
1260 if s != nil {
1261 if copysub(&p.From, v, s, 1) != 0 {
1262 return 1
1263 }
1264 return copysub1(p, v, s, 1)
1265 }
1266
Russ Coxdc7b54b2015-02-17 22:13:49 -05001267 if copyau(&p.From, v) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001268 return 1
1269 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05001270 if copyau1(p, v) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001271 return 1
1272 }
1273 return 0
1274
1275 case arm.AB: /* funny */
1276 if s != nil {
1277 if copysub(&p.To, v, s, 1) != 0 {
1278 return 1
1279 }
1280 return 0
1281 }
1282
Russ Coxdc7b54b2015-02-17 22:13:49 -05001283 if copyau(&p.To, v) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001284 return 1
1285 }
1286 return 0
1287
1288 case obj.ARET: /* funny */
1289 if s != nil {
1290 return 1
1291 }
1292 return 3
1293
1294 case arm.ABL: /* funny */
1295 if v.Type == obj.TYPE_REG {
1296 // TODO(rsc): REG_R0 and REG_F0 used to be
1297 // (when register numbers started at 0) exregoffset and exfregoffset,
1298 // which are unset entirely.
1299 // It's strange that this handles R0 and F0 differently from the other
1300 // registers. Possible failure to optimize?
1301 if arm.REG_R0 < v.Reg && v.Reg <= arm.REGEXT {
1302 return 2
1303 }
1304 if v.Reg == arm.REGARG {
1305 return 2
1306 }
1307 if arm.REG_F0 < v.Reg && v.Reg <= arm.FREGEXT {
1308 return 2
1309 }
1310 }
1311
1312 if p.From.Type == obj.TYPE_REG && v.Type == obj.TYPE_REG && p.From.Reg == v.Reg {
1313 return 2
1314 }
1315
1316 if s != nil {
1317 if copysub(&p.To, v, s, 1) != 0 {
1318 return 1
1319 }
1320 return 0
1321 }
1322
Russ Coxdc7b54b2015-02-17 22:13:49 -05001323 if copyau(&p.To, v) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001324 return 4
1325 }
1326 return 3
1327
1328 // R0 is zero, used by DUFFZERO, cannot be substituted.
1329 // R1 is ptr to memory, used and set, cannot be substituted.
1330 case obj.ADUFFZERO:
1331 if v.Type == obj.TYPE_REG {
1332 if v.Reg == REGALLOC_R0 {
1333 return 1
1334 }
1335 if v.Reg == REGALLOC_R0+1 {
1336 return 2
1337 }
1338 }
1339
1340 return 0
1341
1342 // R0 is scratch, set by DUFFCOPY, cannot be substituted.
1343 // R1, R2 areptr to src, dst, used and set, cannot be substituted.
1344 case obj.ADUFFCOPY:
1345 if v.Type == obj.TYPE_REG {
1346 if v.Reg == REGALLOC_R0 {
1347 return 3
1348 }
1349 if v.Reg == REGALLOC_R0+1 || v.Reg == REGALLOC_R0+2 {
1350 return 2
1351 }
1352 }
1353
1354 return 0
1355
1356 case obj.ATEXT: /* funny */
1357 if v.Type == obj.TYPE_REG {
1358 if v.Reg == arm.REGARG {
1359 return 3
1360 }
1361 }
1362 return 0
1363
1364 case obj.APCDATA,
1365 obj.AFUNCDATA,
1366 obj.AVARDEF,
1367 obj.AVARKILL:
1368 return 0
1369 }
1370}
1371
1372/*
1373 * direct reference,
1374 * could be set/use depending on
1375 * semantics
1376 */
Russ Coxdc7b54b2015-02-17 22:13:49 -05001377func copyas(a *obj.Addr, v *obj.Addr) bool {
1378 if regtyp(v) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001379 if a.Type == v.Type {
1380 if a.Reg == v.Reg {
Russ Coxdc7b54b2015-02-17 22:13:49 -05001381 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05001382 }
1383 }
1384 } else if v.Type == obj.TYPE_CONST { /* for constprop */
1385 if a.Type == v.Type {
1386 if a.Name == v.Name {
1387 if a.Sym == v.Sym {
1388 if a.Reg == v.Reg {
1389 if a.Offset == v.Offset {
Russ Coxdc7b54b2015-02-17 22:13:49 -05001390 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05001391 }
1392 }
1393 }
1394 }
1395 }
1396 }
1397
Russ Coxdc7b54b2015-02-17 22:13:49 -05001398 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05001399}
1400
Russ Coxdc7b54b2015-02-17 22:13:49 -05001401func sameaddr(a *obj.Addr, v *obj.Addr) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05001402 if a.Type != v.Type {
Russ Coxdc7b54b2015-02-17 22:13:49 -05001403 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05001404 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05001405 if regtyp(v) && a.Reg == v.Reg {
1406 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05001407 }
1408
1409 // TODO(rsc): Change v->type to v->name and enable.
1410 //if(v->type == NAME_AUTO || v->type == NAME_PARAM) {
1411 // if(v->offset == a->offset)
1412 // return 1;
1413 //}
Russ Coxdc7b54b2015-02-17 22:13:49 -05001414 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05001415}
1416
1417/*
1418 * either direct or indirect
1419 */
Russ Coxdc7b54b2015-02-17 22:13:49 -05001420func copyau(a *obj.Addr, v *obj.Addr) bool {
1421 if copyas(a, v) {
1422 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05001423 }
1424 if v.Type == obj.TYPE_REG {
1425 if a.Type == obj.TYPE_ADDR && a.Reg != 0 {
1426 if a.Reg == v.Reg {
Russ Coxdc7b54b2015-02-17 22:13:49 -05001427 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05001428 }
1429 } else if a.Type == obj.TYPE_MEM {
1430 if a.Reg == v.Reg {
Russ Coxdc7b54b2015-02-17 22:13:49 -05001431 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05001432 }
1433 } else if a.Type == obj.TYPE_REGREG || a.Type == obj.TYPE_REGREG2 {
1434 if a.Reg == v.Reg {
Russ Coxdc7b54b2015-02-17 22:13:49 -05001435 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05001436 }
1437 if a.Offset == int64(v.Reg) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05001438 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05001439 }
1440 } else if a.Type == obj.TYPE_SHIFT {
1441 if a.Offset&0xf == int64(v.Reg-arm.REG_R0) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05001442 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05001443 }
1444 if (a.Offset&(1<<4) != 0) && (a.Offset>>8)&0xf == int64(v.Reg-arm.REG_R0) {
Russ Coxdc7b54b2015-02-17 22:13:49 -05001445 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05001446 }
1447 }
1448 }
1449
Russ Coxdc7b54b2015-02-17 22:13:49 -05001450 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05001451}
1452
1453/*
1454 * compare v to the center
1455 * register in p (p->reg)
1456 */
Russ Coxdc7b54b2015-02-17 22:13:49 -05001457func copyau1(p *obj.Prog, v *obj.Addr) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05001458 if v.Type == obj.TYPE_REG && v.Reg == 0 {
Russ Coxdc7b54b2015-02-17 22:13:49 -05001459 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05001460 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05001461 return p.Reg == v.Reg
Russ Cox8c195bd2015-02-13 14:40:36 -05001462}
1463
1464/*
1465 * substitute s for v in a
1466 * return failure to substitute
1467 */
1468func copysub(a *obj.Addr, v *obj.Addr, s *obj.Addr, f int) int {
1469 if f != 0 {
Russ Coxdc7b54b2015-02-17 22:13:49 -05001470 if copyau(a, v) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001471 if a.Type == obj.TYPE_SHIFT {
1472 if a.Offset&0xf == int64(v.Reg-arm.REG_R0) {
1473 a.Offset = a.Offset&^0xf | int64(s.Reg)&0xf
1474 }
1475 if (a.Offset&(1<<4) != 0) && (a.Offset>>8)&0xf == int64(v.Reg-arm.REG_R0) {
1476 a.Offset = a.Offset&^(0xf<<8) | (int64(s.Reg)&0xf)<<8
1477 }
1478 } else if a.Type == obj.TYPE_REGREG || a.Type == obj.TYPE_REGREG2 {
1479 if a.Offset == int64(v.Reg) {
1480 a.Offset = int64(s.Reg)
1481 }
1482 if a.Reg == v.Reg {
1483 a.Reg = s.Reg
1484 }
1485 } else {
1486 a.Reg = s.Reg
1487 }
1488 }
1489 }
1490
1491 return 0
1492}
1493
1494func copysub1(p1 *obj.Prog, v *obj.Addr, s *obj.Addr, f int) int {
1495 if f != 0 {
Russ Coxdc7b54b2015-02-17 22:13:49 -05001496 if copyau1(p1, v) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001497 p1.Reg = s.Reg
1498 }
1499 }
1500 return 0
1501}
1502
1503var predinfo = []struct {
1504 opcode int
1505 notopcode int
1506 scond int
1507 notscond int
1508}{
1509 struct {
1510 opcode int
1511 notopcode int
1512 scond int
1513 notscond int
1514 }{arm.ABEQ, arm.ABNE, 0x0, 0x1},
1515 struct {
1516 opcode int
1517 notopcode int
1518 scond int
1519 notscond int
1520 }{arm.ABNE, arm.ABEQ, 0x1, 0x0},
1521 struct {
1522 opcode int
1523 notopcode int
1524 scond int
1525 notscond int
1526 }{arm.ABCS, arm.ABCC, 0x2, 0x3},
1527 struct {
1528 opcode int
1529 notopcode int
1530 scond int
1531 notscond int
1532 }{arm.ABHS, arm.ABLO, 0x2, 0x3},
1533 struct {
1534 opcode int
1535 notopcode int
1536 scond int
1537 notscond int
1538 }{arm.ABCC, arm.ABCS, 0x3, 0x2},
1539 struct {
1540 opcode int
1541 notopcode int
1542 scond int
1543 notscond int
1544 }{arm.ABLO, arm.ABHS, 0x3, 0x2},
1545 struct {
1546 opcode int
1547 notopcode int
1548 scond int
1549 notscond int
1550 }{arm.ABMI, arm.ABPL, 0x4, 0x5},
1551 struct {
1552 opcode int
1553 notopcode int
1554 scond int
1555 notscond int
1556 }{arm.ABPL, arm.ABMI, 0x5, 0x4},
1557 struct {
1558 opcode int
1559 notopcode int
1560 scond int
1561 notscond int
1562 }{arm.ABVS, arm.ABVC, 0x6, 0x7},
1563 struct {
1564 opcode int
1565 notopcode int
1566 scond int
1567 notscond int
1568 }{arm.ABVC, arm.ABVS, 0x7, 0x6},
1569 struct {
1570 opcode int
1571 notopcode int
1572 scond int
1573 notscond int
1574 }{arm.ABHI, arm.ABLS, 0x8, 0x9},
1575 struct {
1576 opcode int
1577 notopcode int
1578 scond int
1579 notscond int
1580 }{arm.ABLS, arm.ABHI, 0x9, 0x8},
1581 struct {
1582 opcode int
1583 notopcode int
1584 scond int
1585 notscond int
1586 }{arm.ABGE, arm.ABLT, 0xA, 0xB},
1587 struct {
1588 opcode int
1589 notopcode int
1590 scond int
1591 notscond int
1592 }{arm.ABLT, arm.ABGE, 0xB, 0xA},
1593 struct {
1594 opcode int
1595 notopcode int
1596 scond int
1597 notscond int
1598 }{arm.ABGT, arm.ABLE, 0xC, 0xD},
1599 struct {
1600 opcode int
1601 notopcode int
1602 scond int
1603 notscond int
1604 }{arm.ABLE, arm.ABGT, 0xD, 0xC},
1605}
1606
1607type Joininfo struct {
1608 start *gc.Flow
1609 last *gc.Flow
1610 end *gc.Flow
1611 len int
1612}
1613
1614const (
1615 Join = iota
1616 Split
1617 End
1618 Branch
1619 Setcond
1620 Toolong
1621)
1622
1623const (
1624 Falsecond = iota
1625 Truecond
1626 Delbranch
1627 Keepbranch
1628)
1629
Russ Coxdc7b54b2015-02-17 22:13:49 -05001630func isbranch(p *obj.Prog) bool {
1631 return (arm.ABEQ <= p.As) && (p.As <= arm.ABLE)
Russ Cox8c195bd2015-02-13 14:40:36 -05001632}
1633
Russ Coxdc7b54b2015-02-17 22:13:49 -05001634func predicable(p *obj.Prog) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05001635 switch p.As {
1636 case obj.ANOP,
1637 obj.AXXX,
1638 obj.ADATA,
1639 obj.AGLOBL,
1640 obj.ATEXT,
1641 arm.AWORD,
1642 arm.ABCASE,
1643 arm.ACASE:
Russ Coxdc7b54b2015-02-17 22:13:49 -05001644 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05001645 }
1646
Russ Coxdc7b54b2015-02-17 22:13:49 -05001647 if isbranch(p) {
1648 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05001649 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05001650 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05001651}
1652
1653/*
1654 * Depends on an analysis of the encodings performed by 5l.
1655 * These seem to be all of the opcodes that lead to the "S" bit
1656 * being set in the instruction encodings.
1657 *
1658 * C_SBIT may also have been set explicitly in p->scond.
1659 */
Russ Coxdc7b54b2015-02-17 22:13:49 -05001660func modifiescpsr(p *obj.Prog) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -05001661 switch p.As {
1662 case arm.AMULLU,
1663 arm.AMULA,
1664 arm.AMULU,
1665 arm.ADIVU,
1666 arm.ATEQ,
1667 arm.ACMN,
1668 arm.ATST,
1669 arm.ACMP,
1670 arm.AMUL,
1671 arm.ADIV,
1672 arm.AMOD,
1673 arm.AMODU,
1674 arm.ABL:
Russ Coxdc7b54b2015-02-17 22:13:49 -05001675 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05001676 }
1677
1678 if p.Scond&arm.C_SBIT != 0 {
Russ Coxdc7b54b2015-02-17 22:13:49 -05001679 return true
Russ Cox8c195bd2015-02-13 14:40:36 -05001680 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05001681 return false
Russ Cox8c195bd2015-02-13 14:40:36 -05001682}
1683
1684/*
1685 * Find the maximal chain of instructions starting with r which could
1686 * be executed conditionally
1687 */
1688func joinsplit(r *gc.Flow, j *Joininfo) int {
1689 j.start = r
1690 j.last = r
1691 j.len = 0
1692 for {
1693 if r.P2 != nil && (r.P1 != nil || r.P2.P2link != nil) {
1694 j.end = r
1695 return Join
1696 }
1697
1698 if r.S1 != nil && r.S2 != nil {
1699 j.end = r
1700 return Split
1701 }
1702
1703 j.last = r
1704 if r.Prog.As != obj.ANOP {
1705 j.len++
1706 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05001707 if r.S1 == nil && r.S2 == nil {
Russ Cox8c195bd2015-02-13 14:40:36 -05001708 j.end = r.Link
1709 return End
1710 }
1711
1712 if r.S2 != nil {
1713 j.end = r.S2
1714 return Branch
1715 }
1716
Russ Coxdc7b54b2015-02-17 22:13:49 -05001717 if modifiescpsr(r.Prog) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001718 j.end = r.S1
1719 return Setcond
1720 }
1721
1722 r = r.S1
Russ Coxdc7b54b2015-02-17 22:13:49 -05001723 if j.len >= 4 {
Russ Cox8c195bd2015-02-13 14:40:36 -05001724 break
1725 }
1726 }
1727
1728 j.end = r
1729 return Toolong
1730}
1731
1732func successor(r *gc.Flow) *gc.Flow {
1733 if r.S1 != nil {
1734 return r.S1
1735 } else {
1736 return r.S2
1737 }
1738}
1739
1740func applypred(rstart *gc.Flow, j *Joininfo, cond int, branch int) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001741 if j.len == 0 {
1742 return
1743 }
Russ Cox382b44e2015-02-23 16:07:24 -05001744 var pred int
Russ Cox8c195bd2015-02-13 14:40:36 -05001745 if cond == Truecond {
1746 pred = predinfo[rstart.Prog.As-arm.ABEQ].scond
1747 } else {
1748 pred = predinfo[rstart.Prog.As-arm.ABEQ].notscond
1749 }
1750
Russ Cox382b44e2015-02-23 16:07:24 -05001751 for r := (*gc.Flow)(j.start); ; r = successor(r) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001752 if r.Prog.As == arm.AB {
1753 if r != j.last || branch == Delbranch {
1754 excise(r)
1755 } else {
1756 if cond == Truecond {
1757 r.Prog.As = int16(predinfo[rstart.Prog.As-arm.ABEQ].opcode)
1758 } else {
1759 r.Prog.As = int16(predinfo[rstart.Prog.As-arm.ABEQ].notopcode)
1760 }
1761 }
Russ Coxdc7b54b2015-02-17 22:13:49 -05001762 } else if predicable(r.Prog) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001763 r.Prog.Scond = uint8(int(r.Prog.Scond&^arm.C_SCOND) | pred)
1764 }
1765 if r.S1 != r.Link {
1766 r.S1 = r.Link
1767 r.Link.P1 = r
1768 }
1769
1770 if r == j.last {
1771 break
1772 }
1773 }
1774}
1775
1776func predicate(g *gc.Graph) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001777 var t1 int
1778 var t2 int
1779 var j1 Joininfo
1780 var j2 Joininfo
1781
Russ Cox382b44e2015-02-23 16:07:24 -05001782 for r := (*gc.Flow)(g.Start); r != nil; r = r.Link {
Russ Coxdc7b54b2015-02-17 22:13:49 -05001783 if isbranch(r.Prog) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001784 t1 = joinsplit(r.S1, &j1)
1785 t2 = joinsplit(r.S2, &j2)
1786 if j1.last.Link != j2.start {
1787 continue
1788 }
1789 if j1.end == j2.end {
1790 if (t1 == Branch && (t2 == Join || t2 == Setcond)) || (t2 == Join && (t1 == Join || t1 == Setcond)) {
1791 applypred(r, &j1, Falsecond, Delbranch)
1792 applypred(r, &j2, Truecond, Delbranch)
1793 excise(r)
1794 continue
1795 }
1796 }
1797
1798 if t1 == End || t1 == Branch {
1799 applypred(r, &j1, Falsecond, Keepbranch)
1800 excise(r)
1801 continue
1802 }
1803 }
1804 }
1805}
1806
Russ Coxdc7b54b2015-02-17 22:13:49 -05001807func isdconst(a *obj.Addr) bool {
1808 return a.Type == obj.TYPE_CONST
Russ Cox8c195bd2015-02-13 14:40:36 -05001809}
1810
Russ Coxdc7b54b2015-02-17 22:13:49 -05001811func isfloatreg(a *obj.Addr) bool {
1812 return arm.REG_F0 <= a.Reg && a.Reg <= arm.REG_F15
Russ Cox8c195bd2015-02-13 14:40:36 -05001813}
1814
Russ Coxdc7b54b2015-02-17 22:13:49 -05001815func stackaddr(a *obj.Addr) bool {
1816 return regtyp(a) && a.Reg == arm.REGSP
Russ Cox8c195bd2015-02-13 14:40:36 -05001817}
1818
Russ Coxdc7b54b2015-02-17 22:13:49 -05001819func smallindir(a *obj.Addr, reg *obj.Addr) bool {
1820 return reg.Type == obj.TYPE_REG && a.Type == obj.TYPE_MEM && a.Reg == reg.Reg && 0 <= a.Offset && a.Offset < 4096
Russ Cox8c195bd2015-02-13 14:40:36 -05001821}
1822
1823func excise(r *gc.Flow) {
Russ Cox382b44e2015-02-23 16:07:24 -05001824 p := (*obj.Prog)(r.Prog)
Russ Cox8c195bd2015-02-13 14:40:36 -05001825 obj.Nopout(p)
1826}