Home | History | Annotate | Download | only in amd64
      1 // Derived from Inferno utils/6c/peep.c
      2 // http://code.google.com/p/inferno-os/source/browse/utils/6c/peep.c
      3 //
      4 //	Copyright  1994-1999 Lucent Technologies Inc.  All rights reserved.
      5 //	Portions Copyright  1995-1997 C H Forsyth (forsyth (a] 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 (a] 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 
     31 package amd64
     32 
     33 import (
     34 	"cmd/compile/internal/gc"
     35 	"cmd/internal/obj"
     36 	"cmd/internal/obj/x86"
     37 	"fmt"
     38 )
     39 
     40 var gactive uint32
     41 
     42 const (
     43 	exregoffset = x86.REG_R15
     44 )
     45 
     46 // do we need the carry bit
     47 func needc(p *obj.Prog) bool {
     48 	for p != nil {
     49 		flags := progcarryflags(p)
     50 		if flags&gc.UseCarry != 0 {
     51 			return true
     52 		}
     53 		if flags&(gc.SetCarry|gc.KillCarry) != 0 {
     54 			return false
     55 		}
     56 		p = p.Link
     57 	}
     58 
     59 	return false
     60 }
     61 
     62 func rnops(r *gc.Flow) *gc.Flow {
     63 	if r != nil {
     64 		var p *obj.Prog
     65 		var r1 *gc.Flow
     66 		for {
     67 			p = r.Prog
     68 			if p.As != obj.ANOP || p.From.Type != obj.TYPE_NONE || p.To.Type != obj.TYPE_NONE {
     69 				break
     70 			}
     71 			r1 = gc.Uniqs(r)
     72 			if r1 == nil {
     73 				break
     74 			}
     75 			r = r1
     76 		}
     77 	}
     78 
     79 	return r
     80 }
     81 
     82 func peep(firstp *obj.Prog) {
     83 	g := (*gc.Graph)(gc.Flowstart(firstp, nil))
     84 	if g == nil {
     85 		return
     86 	}
     87 	gactive = 0
     88 
     89 	// byte, word arithmetic elimination.
     90 	elimshortmov(g)
     91 
     92 	// constant propagation
     93 	// find MOV $con,R followed by
     94 	// another MOV $con,R without
     95 	// setting R in the interim
     96 	var p *obj.Prog
     97 	for r := (*gc.Flow)(g.Start); r != nil; r = r.Link {
     98 		p = r.Prog
     99 		switch p.As {
    100 		case x86.ALEAL,
    101 			x86.ALEAQ:
    102 			if regtyp(&p.To) {
    103 				if p.From.Sym != nil {
    104 					if p.From.Index == x86.REG_NONE {
    105 						conprop(r)
    106 					}
    107 				}
    108 			}
    109 
    110 		case x86.AMOVB,
    111 			x86.AMOVW,
    112 			x86.AMOVL,
    113 			x86.AMOVQ,
    114 			x86.AMOVSS,
    115 			x86.AMOVSD:
    116 			if regtyp(&p.To) {
    117 				if p.From.Type == obj.TYPE_CONST || p.From.Type == obj.TYPE_FCONST {
    118 					conprop(r)
    119 				}
    120 			}
    121 		}
    122 	}
    123 
    124 	var r *gc.Flow
    125 	var r1 *gc.Flow
    126 	var p1 *obj.Prog
    127 	var t int
    128 loop1:
    129 	if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
    130 		gc.Dumpit("loop1", g.Start, 0)
    131 	}
    132 
    133 	t = 0
    134 	for r = g.Start; r != nil; r = r.Link {
    135 		p = r.Prog
    136 		switch p.As {
    137 		case x86.AMOVL,
    138 			x86.AMOVQ,
    139 			x86.AMOVSS,
    140 			x86.AMOVSD:
    141 			if regtyp(&p.To) {
    142 				if regtyp(&p.From) {
    143 					if copyprop(g, r) {
    144 						excise(r)
    145 						t++
    146 					} else if subprop(r) && copyprop(g, r) {
    147 						excise(r)
    148 						t++
    149 					}
    150 				}
    151 			}
    152 
    153 		case x86.AMOVBLZX,
    154 			x86.AMOVWLZX,
    155 			x86.AMOVBLSX,
    156 			x86.AMOVWLSX:
    157 			if regtyp(&p.To) {
    158 				r1 = rnops(gc.Uniqs(r))
    159 				if r1 != nil {
    160 					p1 = r1.Prog
    161 					if p.As == p1.As && p.To.Type == p1.From.Type && p.To.Reg == p1.From.Reg {
    162 						p1.As = x86.AMOVL
    163 						t++
    164 					}
    165 				}
    166 			}
    167 
    168 		case x86.AMOVBQSX,
    169 			x86.AMOVBQZX,
    170 			x86.AMOVWQSX,
    171 			x86.AMOVWQZX,
    172 			x86.AMOVLQSX,
    173 			x86.AMOVLQZX,
    174 			x86.AMOVQL:
    175 			if regtyp(&p.To) {
    176 				r1 = rnops(gc.Uniqs(r))
    177 				if r1 != nil {
    178 					p1 = r1.Prog
    179 					if p.As == p1.As && p.To.Type == p1.From.Type && p.To.Reg == p1.From.Reg {
    180 						p1.As = x86.AMOVQ
    181 						t++
    182 					}
    183 				}
    184 			}
    185 
    186 		case x86.AADDL,
    187 			x86.AADDQ,
    188 			x86.AADDW:
    189 			if p.From.Type != obj.TYPE_CONST || needc(p.Link) {
    190 				break
    191 			}
    192 			if p.From.Offset == -1 {
    193 				if p.As == x86.AADDQ {
    194 					p.As = x86.ADECQ
    195 				} else if p.As == x86.AADDL {
    196 					p.As = x86.ADECL
    197 				} else {
    198 					p.As = x86.ADECW
    199 				}
    200 				p.From = obj.Addr{}
    201 				break
    202 			}
    203 
    204 			if p.From.Offset == 1 {
    205 				if p.As == x86.AADDQ {
    206 					p.As = x86.AINCQ
    207 				} else if p.As == x86.AADDL {
    208 					p.As = x86.AINCL
    209 				} else {
    210 					p.As = x86.AINCW
    211 				}
    212 				p.From = obj.Addr{}
    213 				break
    214 			}
    215 
    216 		case x86.ASUBL,
    217 			x86.ASUBQ,
    218 			x86.ASUBW:
    219 			if p.From.Type != obj.TYPE_CONST || needc(p.Link) {
    220 				break
    221 			}
    222 			if p.From.Offset == -1 {
    223 				if p.As == x86.ASUBQ {
    224 					p.As = x86.AINCQ
    225 				} else if p.As == x86.ASUBL {
    226 					p.As = x86.AINCL
    227 				} else {
    228 					p.As = x86.AINCW
    229 				}
    230 				p.From = obj.Addr{}
    231 				break
    232 			}
    233 
    234 			if p.From.Offset == 1 {
    235 				if p.As == x86.ASUBQ {
    236 					p.As = x86.ADECQ
    237 				} else if p.As == x86.ASUBL {
    238 					p.As = x86.ADECL
    239 				} else {
    240 					p.As = x86.ADECW
    241 				}
    242 				p.From = obj.Addr{}
    243 				break
    244 			}
    245 		}
    246 	}
    247 
    248 	if t != 0 {
    249 		goto loop1
    250 	}
    251 
    252 	// MOVLQZX removal.
    253 	// The MOVLQZX exists to avoid being confused for a
    254 	// MOVL that is just copying 32-bit data around during
    255 	// copyprop.  Now that copyprop is done, remov MOVLQZX R1, R2
    256 	// if it is dominated by an earlier ADDL/MOVL/etc into R1 that
    257 	// will have already cleared the high bits.
    258 	//
    259 	// MOVSD removal.
    260 	// We never use packed registers, so a MOVSD between registers
    261 	// can be replaced by MOVAPD, which moves the pair of float64s
    262 	// instead of just the lower one.  We only use the lower one, but
    263 	// the processor can do better if we do moves using both.
    264 	for r := (*gc.Flow)(g.Start); r != nil; r = r.Link {
    265 		p = r.Prog
    266 		if p.As == x86.AMOVLQZX {
    267 			if regtyp(&p.From) {
    268 				if p.From.Type == p.To.Type && p.From.Reg == p.To.Reg {
    269 					if prevl(r, int(p.From.Reg)) {
    270 						excise(r)
    271 					}
    272 				}
    273 			}
    274 		}
    275 
    276 		if p.As == x86.AMOVSD {
    277 			if regtyp(&p.From) {
    278 				if regtyp(&p.To) {
    279 					p.As = x86.AMOVAPD
    280 				}
    281 			}
    282 		}
    283 	}
    284 
    285 	// load pipelining
    286 	// push any load from memory as early as possible
    287 	// to give it time to complete before use.
    288 	for r := (*gc.Flow)(g.Start); r != nil; r = r.Link {
    289 		p = r.Prog
    290 		switch p.As {
    291 		case x86.AMOVB,
    292 			x86.AMOVW,
    293 			x86.AMOVL,
    294 			x86.AMOVQ,
    295 			x86.AMOVLQZX:
    296 			if regtyp(&p.To) && !regconsttyp(&p.From) {
    297 				pushback(r)
    298 			}
    299 		}
    300 	}
    301 
    302 	gc.Flowend(g)
    303 }
    304 
    305 func pushback(r0 *gc.Flow) {
    306 	var r *gc.Flow
    307 	var p *obj.Prog
    308 
    309 	var b *gc.Flow
    310 	p0 := (*obj.Prog)(r0.Prog)
    311 	for r = gc.Uniqp(r0); r != nil && gc.Uniqs(r) != nil; r = gc.Uniqp(r) {
    312 		p = r.Prog
    313 		if p.As != obj.ANOP {
    314 			if !regconsttyp(&p.From) || !regtyp(&p.To) {
    315 				break
    316 			}
    317 			if copyu(p, &p0.To, nil) != 0 || copyu(p0, &p.To, nil) != 0 {
    318 				break
    319 			}
    320 		}
    321 
    322 		if p.As == obj.ACALL {
    323 			break
    324 		}
    325 		b = r
    326 	}
    327 
    328 	if b == nil {
    329 		if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
    330 			fmt.Printf("no pushback: %v\n", r0.Prog)
    331 			if r != nil {
    332 				fmt.Printf("\t%v [%v]\n", r.Prog, gc.Uniqs(r) != nil)
    333 			}
    334 		}
    335 
    336 		return
    337 	}
    338 
    339 	if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
    340 		fmt.Printf("pushback\n")
    341 		for r := (*gc.Flow)(b); ; r = r.Link {
    342 			fmt.Printf("\t%v\n", r.Prog)
    343 			if r == r0 {
    344 				break
    345 			}
    346 		}
    347 	}
    348 
    349 	t := obj.Prog(*r0.Prog)
    350 	for r = gc.Uniqp(r0); ; r = gc.Uniqp(r) {
    351 		p0 = r.Link.Prog
    352 		p = r.Prog
    353 		p0.As = p.As
    354 		p0.Lineno = p.Lineno
    355 		p0.From = p.From
    356 		p0.To = p.To
    357 
    358 		if r == b {
    359 			break
    360 		}
    361 	}
    362 
    363 	p0 = r.Prog
    364 	p0.As = t.As
    365 	p0.Lineno = t.Lineno
    366 	p0.From = t.From
    367 	p0.To = t.To
    368 
    369 	if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
    370 		fmt.Printf("\tafter\n")
    371 		for r := (*gc.Flow)(b); ; r = r.Link {
    372 			fmt.Printf("\t%v\n", r.Prog)
    373 			if r == r0 {
    374 				break
    375 			}
    376 		}
    377 	}
    378 }
    379 
    380 func excise(r *gc.Flow) {
    381 	p := (*obj.Prog)(r.Prog)
    382 	if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
    383 		fmt.Printf("%v ===delete===\n", p)
    384 	}
    385 
    386 	obj.Nopout(p)
    387 
    388 	gc.Ostats.Ndelmov++
    389 }
    390 
    391 func regtyp(a *obj.Addr) bool {
    392 	return a.Type == obj.TYPE_REG && (x86.REG_AX <= a.Reg && a.Reg <= x86.REG_R15 || x86.REG_X0 <= a.Reg && a.Reg <= x86.REG_X15)
    393 }
    394 
    395 // movb elimination.
    396 // movb is simulated by the linker
    397 // when a register other than ax, bx, cx, dx
    398 // is used, so rewrite to other instructions
    399 // when possible.  a movb into a register
    400 // can smash the entire 32-bit register without
    401 // causing any trouble.
    402 //
    403 // TODO: Using the Q forms here instead of the L forms
    404 // seems unnecessary, and it makes the instructions longer.
    405 func elimshortmov(g *gc.Graph) {
    406 	var p *obj.Prog
    407 
    408 	for r := (*gc.Flow)(g.Start); r != nil; r = r.Link {
    409 		p = r.Prog
    410 		if regtyp(&p.To) {
    411 			switch p.As {
    412 			case x86.AINCB,
    413 				x86.AINCW:
    414 				p.As = x86.AINCQ
    415 
    416 			case x86.ADECB,
    417 				x86.ADECW:
    418 				p.As = x86.ADECQ
    419 
    420 			case x86.ANEGB,
    421 				x86.ANEGW:
    422 				p.As = x86.ANEGQ
    423 
    424 			case x86.ANOTB,
    425 				x86.ANOTW:
    426 				p.As = x86.ANOTQ
    427 			}
    428 
    429 			if regtyp(&p.From) || p.From.Type == obj.TYPE_CONST {
    430 				// move or artihmetic into partial register.
    431 				// from another register or constant can be movl.
    432 				// we don't switch to 64-bit arithmetic if it can
    433 				// change how the carry bit is set (and the carry bit is needed).
    434 				switch p.As {
    435 				case x86.AMOVB,
    436 					x86.AMOVW:
    437 					p.As = x86.AMOVQ
    438 
    439 				case x86.AADDB,
    440 					x86.AADDW:
    441 					if !needc(p.Link) {
    442 						p.As = x86.AADDQ
    443 					}
    444 
    445 				case x86.ASUBB,
    446 					x86.ASUBW:
    447 					if !needc(p.Link) {
    448 						p.As = x86.ASUBQ
    449 					}
    450 
    451 				case x86.AMULB,
    452 					x86.AMULW:
    453 					p.As = x86.AMULQ
    454 
    455 				case x86.AIMULB,
    456 					x86.AIMULW:
    457 					p.As = x86.AIMULQ
    458 
    459 				case x86.AANDB,
    460 					x86.AANDW:
    461 					p.As = x86.AANDQ
    462 
    463 				case x86.AORB,
    464 					x86.AORW:
    465 					p.As = x86.AORQ
    466 
    467 				case x86.AXORB,
    468 					x86.AXORW:
    469 					p.As = x86.AXORQ
    470 
    471 				case x86.ASHLB,
    472 					x86.ASHLW:
    473 					p.As = x86.ASHLQ
    474 				}
    475 			} else if p.From.Type != obj.TYPE_REG {
    476 				// explicit zero extension, but don't
    477 				// do that if source is a byte register
    478 				// (only AH can occur and it's forbidden).
    479 				switch p.As {
    480 				case x86.AMOVB:
    481 					p.As = x86.AMOVBQZX
    482 
    483 				case x86.AMOVW:
    484 					p.As = x86.AMOVWQZX
    485 				}
    486 			}
    487 		}
    488 	}
    489 }
    490 
    491 // is 'a' a register or constant?
    492 func regconsttyp(a *obj.Addr) bool {
    493 	if regtyp(a) {
    494 		return true
    495 	}
    496 	switch a.Type {
    497 	case obj.TYPE_CONST,
    498 		obj.TYPE_FCONST,
    499 		obj.TYPE_SCONST,
    500 		obj.TYPE_ADDR: // TODO(rsc): Not all TYPE_ADDRs are constants.
    501 		return true
    502 	}
    503 
    504 	return false
    505 }
    506 
    507 // is reg guaranteed to be truncated by a previous L instruction?
    508 func prevl(r0 *gc.Flow, reg int) bool {
    509 	for r := (*gc.Flow)(gc.Uniqp(r0)); r != nil; r = gc.Uniqp(r) {
    510 		p := r.Prog
    511 		if p.To.Type == obj.TYPE_REG && int(p.To.Reg) == reg {
    512 			flags := progflags(p)
    513 			if flags&gc.RightWrite != 0 {
    514 				if flags&gc.SizeL != 0 {
    515 					return true
    516 				}
    517 				return false
    518 			}
    519 		}
    520 	}
    521 
    522 	return false
    523 }
    524 
    525 /*
    526  * the idea is to substitute
    527  * one register for another
    528  * from one MOV to another
    529  *	MOV	a, R0
    530  *	ADD	b, R0	/ no use of R1
    531  *	MOV	R0, R1
    532  * would be converted to
    533  *	MOV	a, R1
    534  *	ADD	b, R1
    535  *	MOV	R1, R0
    536  * hopefully, then the former or latter MOV
    537  * will be eliminated by copy propagation.
    538  */
    539 func subprop(r0 *gc.Flow) bool {
    540 	if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
    541 		fmt.Printf("subprop %v\n", r0.Prog)
    542 	}
    543 	p := (*obj.Prog)(r0.Prog)
    544 	v1 := (*obj.Addr)(&p.From)
    545 	if !regtyp(v1) {
    546 		if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
    547 			fmt.Printf("\tnot regtype %v; return 0\n", gc.Ctxt.Dconv(v1))
    548 		}
    549 		return false
    550 	}
    551 
    552 	v2 := (*obj.Addr)(&p.To)
    553 	if !regtyp(v2) {
    554 		if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
    555 			fmt.Printf("\tnot regtype %v; return 0\n", gc.Ctxt.Dconv(v2))
    556 		}
    557 		return false
    558 	}
    559 
    560 	for r := gc.Uniqp(r0); r != nil; r = gc.Uniqp(r) {
    561 		if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
    562 			fmt.Printf("\t? %v\n", r.Prog)
    563 		}
    564 		if gc.Uniqs(r) == nil {
    565 			if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
    566 				fmt.Printf("\tno unique successor\n")
    567 			}
    568 			break
    569 		}
    570 
    571 		p = r.Prog
    572 		if p.As == obj.AVARDEF || p.As == obj.AVARKILL {
    573 			continue
    574 		}
    575 		if p.Info.Flags&gc.Call != 0 {
    576 			if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
    577 				fmt.Printf("\tfound %v; return 0\n", p)
    578 			}
    579 			return false
    580 		}
    581 
    582 		if p.Info.Reguse|p.Info.Regset != 0 {
    583 			if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
    584 				fmt.Printf("\tfound %v; return 0\n", p)
    585 			}
    586 			return false
    587 		}
    588 
    589 		if (p.Info.Flags&gc.Move != 0) && (p.Info.Flags&(gc.SizeL|gc.SizeQ|gc.SizeF|gc.SizeD) != 0) && p.To.Type == v1.Type && p.To.Reg == v1.Reg {
    590 			copysub(&p.To, v1, v2, 1)
    591 			if gc.Debug['P'] != 0 {
    592 				fmt.Printf("gotit: %v->%v\n%v", gc.Ctxt.Dconv(v1), gc.Ctxt.Dconv(v2), r.Prog)
    593 				if p.From.Type == v2.Type && p.From.Reg == v2.Reg {
    594 					fmt.Printf(" excise")
    595 				}
    596 				fmt.Printf("\n")
    597 			}
    598 
    599 			for r = gc.Uniqs(r); r != r0; r = gc.Uniqs(r) {
    600 				p = r.Prog
    601 				copysub(&p.From, v1, v2, 1)
    602 				copysub(&p.To, v1, v2, 1)
    603 				if gc.Debug['P'] != 0 {
    604 					fmt.Printf("%v\n", r.Prog)
    605 				}
    606 			}
    607 
    608 			t := int(int(v1.Reg))
    609 			v1.Reg = v2.Reg
    610 			v2.Reg = int16(t)
    611 			if gc.Debug['P'] != 0 {
    612 				fmt.Printf("%v last\n", r.Prog)
    613 			}
    614 			return true
    615 		}
    616 
    617 		if copyau(&p.From, v2) || copyau(&p.To, v2) {
    618 			if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
    619 				fmt.Printf("\tcopyau %v failed\n", gc.Ctxt.Dconv(v2))
    620 			}
    621 			break
    622 		}
    623 
    624 		if copysub(&p.From, v1, v2, 0) != 0 || copysub(&p.To, v1, v2, 0) != 0 {
    625 			if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
    626 				fmt.Printf("\tcopysub failed\n")
    627 			}
    628 			break
    629 		}
    630 	}
    631 
    632 	if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
    633 		fmt.Printf("\tran off end; return 0\n")
    634 	}
    635 	return false
    636 }
    637 
    638 /*
    639  * The idea is to remove redundant copies.
    640  *	v1->v2	F=0
    641  *	(use v2	s/v2/v1/)*
    642  *	set v1	F=1
    643  *	use v2	return fail
    644  *	-----------------
    645  *	v1->v2	F=0
    646  *	(use v2	s/v2/v1/)*
    647  *	set v1	F=1
    648  *	set v2	return success
    649  */
    650 func copyprop(g *gc.Graph, r0 *gc.Flow) bool {
    651 	if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
    652 		fmt.Printf("copyprop %v\n", r0.Prog)
    653 	}
    654 	p := (*obj.Prog)(r0.Prog)
    655 	v1 := (*obj.Addr)(&p.From)
    656 	v2 := (*obj.Addr)(&p.To)
    657 	if copyas(v1, v2) {
    658 		return true
    659 	}
    660 	gactive++
    661 	return copy1(v1, v2, r0.S1, 0)
    662 }
    663 
    664 func copy1(v1 *obj.Addr, v2 *obj.Addr, r *gc.Flow, f int) bool {
    665 	if uint32(r.Active) == gactive {
    666 		if gc.Debug['P'] != 0 {
    667 			fmt.Printf("act set; return 1\n")
    668 		}
    669 		return true
    670 	}
    671 
    672 	r.Active = int32(gactive)
    673 	if gc.Debug['P'] != 0 {
    674 		fmt.Printf("copy %v->%v f=%d\n", gc.Ctxt.Dconv(v1), gc.Ctxt.Dconv(v2), f)
    675 	}
    676 	var t int
    677 	var p *obj.Prog
    678 	for ; r != nil; r = r.S1 {
    679 		p = r.Prog
    680 		if gc.Debug['P'] != 0 {
    681 			fmt.Printf("%v", p)
    682 		}
    683 		if f == 0 && gc.Uniqp(r) == nil {
    684 			f = 1
    685 			if gc.Debug['P'] != 0 {
    686 				fmt.Printf("; merge; f=%d", f)
    687 			}
    688 		}
    689 
    690 		t = copyu(p, v2, nil)
    691 		switch t {
    692 		case 2: /* rar, can't split */
    693 			if gc.Debug['P'] != 0 {
    694 				fmt.Printf("; %v rar; return 0\n", gc.Ctxt.Dconv(v2))
    695 			}
    696 			return false
    697 
    698 		case 3: /* set */
    699 			if gc.Debug['P'] != 0 {
    700 				fmt.Printf("; %v set; return 1\n", gc.Ctxt.Dconv(v2))
    701 			}
    702 			return true
    703 
    704 		case 1, /* used, substitute */
    705 			4: /* use and set */
    706 			if f != 0 {
    707 				if gc.Debug['P'] == 0 {
    708 					return false
    709 				}
    710 				if t == 4 {
    711 					fmt.Printf("; %v used+set and f=%d; return 0\n", gc.Ctxt.Dconv(v2), f)
    712 				} else {
    713 					fmt.Printf("; %v used and f=%d; return 0\n", gc.Ctxt.Dconv(v2), f)
    714 				}
    715 				return false
    716 			}
    717 
    718 			if copyu(p, v2, v1) != 0 {
    719 				if gc.Debug['P'] != 0 {
    720 					fmt.Printf("; sub fail; return 0\n")
    721 				}
    722 				return false
    723 			}
    724 
    725 			if gc.Debug['P'] != 0 {
    726 				fmt.Printf("; sub %v/%v", gc.Ctxt.Dconv(v2), gc.Ctxt.Dconv(v1))
    727 			}
    728 			if t == 4 {
    729 				if gc.Debug['P'] != 0 {
    730 					fmt.Printf("; %v used+set; return 1\n", gc.Ctxt.Dconv(v2))
    731 				}
    732 				return true
    733 			}
    734 		}
    735 
    736 		if f == 0 {
    737 			t = copyu(p, v1, nil)
    738 			if f == 0 && (t == 2 || t == 3 || t == 4) {
    739 				f = 1
    740 				if gc.Debug['P'] != 0 {
    741 					fmt.Printf("; %v set and !f; f=%d", gc.Ctxt.Dconv(v1), f)
    742 				}
    743 			}
    744 		}
    745 
    746 		if gc.Debug['P'] != 0 {
    747 			fmt.Printf("\n")
    748 		}
    749 		if r.S2 != nil {
    750 			if !copy1(v1, v2, r.S2, f) {
    751 				return false
    752 			}
    753 		}
    754 	}
    755 
    756 	return true
    757 }
    758 
    759 /*
    760  * return
    761  * 1 if v only used (and substitute),
    762  * 2 if read-alter-rewrite
    763  * 3 if set
    764  * 4 if set and used
    765  * 0 otherwise (not touched)
    766  */
    767 func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int {
    768 	switch p.As {
    769 	case obj.AJMP:
    770 		if s != nil {
    771 			if copysub(&p.To, v, s, 1) != 0 {
    772 				return 1
    773 			}
    774 			return 0
    775 		}
    776 
    777 		if copyau(&p.To, v) {
    778 			return 1
    779 		}
    780 		return 0
    781 
    782 	case obj.ARET:
    783 		if s != nil {
    784 			return 1
    785 		}
    786 		return 3
    787 
    788 	case obj.ACALL:
    789 		if x86.REGEXT != 0 /*TypeKind(100016)*/ && v.Type == obj.TYPE_REG && v.Reg <= x86.REGEXT && v.Reg > exregoffset {
    790 			return 2
    791 		}
    792 		if x86.REGARG >= 0 && v.Type == obj.TYPE_REG && v.Reg == x86.REGARG {
    793 			return 2
    794 		}
    795 		if v.Type == p.From.Type && v.Reg == p.From.Reg {
    796 			return 2
    797 		}
    798 
    799 		if s != nil {
    800 			if copysub(&p.To, v, s, 1) != 0 {
    801 				return 1
    802 			}
    803 			return 0
    804 		}
    805 
    806 		if copyau(&p.To, v) {
    807 			return 4
    808 		}
    809 		return 3
    810 
    811 	case obj.ATEXT:
    812 		if x86.REGARG >= 0 && v.Type == obj.TYPE_REG && v.Reg == x86.REGARG {
    813 			return 3
    814 		}
    815 		return 0
    816 	}
    817 
    818 	if p.As == obj.AVARDEF || p.As == obj.AVARKILL {
    819 		return 0
    820 	}
    821 
    822 	if (p.Info.Reguse|p.Info.Regset)&RtoB(int(v.Reg)) != 0 {
    823 		return 2
    824 	}
    825 
    826 	if p.Info.Flags&gc.LeftAddr != 0 {
    827 		if copyas(&p.From, v) {
    828 			return 2
    829 		}
    830 	}
    831 
    832 	if p.Info.Flags&(gc.RightRead|gc.RightWrite) == gc.RightRead|gc.RightWrite {
    833 		if copyas(&p.To, v) {
    834 			return 2
    835 		}
    836 	}
    837 
    838 	if p.Info.Flags&gc.RightWrite != 0 {
    839 		if copyas(&p.To, v) {
    840 			if s != nil {
    841 				return copysub(&p.From, v, s, 1)
    842 			}
    843 			if copyau(&p.From, v) {
    844 				return 4
    845 			}
    846 			return 3
    847 		}
    848 	}
    849 
    850 	if p.Info.Flags&(gc.LeftAddr|gc.LeftRead|gc.LeftWrite|gc.RightAddr|gc.RightRead|gc.RightWrite) != 0 {
    851 		if s != nil {
    852 			if copysub(&p.From, v, s, 1) != 0 {
    853 				return 1
    854 			}
    855 			return copysub(&p.To, v, s, 1)
    856 		}
    857 
    858 		if copyau(&p.From, v) {
    859 			return 1
    860 		}
    861 		if copyau(&p.To, v) {
    862 			return 1
    863 		}
    864 	}
    865 
    866 	return 0
    867 }
    868 
    869 /*
    870  * direct reference,
    871  * could be set/use depending on
    872  * semantics
    873  */
    874 func copyas(a *obj.Addr, v *obj.Addr) bool {
    875 	if x86.REG_AL <= a.Reg && a.Reg <= x86.REG_R15B {
    876 		gc.Fatal("use of byte register")
    877 	}
    878 	if x86.REG_AL <= v.Reg && v.Reg <= x86.REG_R15B {
    879 		gc.Fatal("use of byte register")
    880 	}
    881 
    882 	if a.Type != v.Type || a.Name != v.Name || a.Reg != v.Reg {
    883 		return false
    884 	}
    885 	if regtyp(v) {
    886 		return true
    887 	}
    888 	if v.Type == obj.TYPE_MEM && (v.Name == obj.NAME_AUTO || v.Name == obj.NAME_PARAM) {
    889 		if v.Offset == a.Offset {
    890 			return true
    891 		}
    892 	}
    893 	return false
    894 }
    895 
    896 func sameaddr(a *obj.Addr, v *obj.Addr) bool {
    897 	if a.Type != v.Type || a.Name != v.Name || a.Reg != v.Reg {
    898 		return false
    899 	}
    900 	if regtyp(v) {
    901 		return true
    902 	}
    903 	if v.Type == obj.TYPE_MEM && (v.Name == obj.NAME_AUTO || v.Name == obj.NAME_PARAM) {
    904 		if v.Offset == a.Offset {
    905 			return true
    906 		}
    907 	}
    908 	return false
    909 }
    910 
    911 /*
    912  * either direct or indirect
    913  */
    914 func copyau(a *obj.Addr, v *obj.Addr) bool {
    915 	if copyas(a, v) {
    916 		if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
    917 			fmt.Printf("\tcopyau: copyas returned 1\n")
    918 		}
    919 		return true
    920 	}
    921 
    922 	if regtyp(v) {
    923 		if a.Type == obj.TYPE_MEM && a.Reg == v.Reg {
    924 			if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
    925 				fmt.Printf("\tcopyau: found indir use - return 1\n")
    926 			}
    927 			return true
    928 		}
    929 
    930 		if a.Index == v.Reg {
    931 			if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
    932 				fmt.Printf("\tcopyau: found index use - return 1\n")
    933 			}
    934 			return true
    935 		}
    936 	}
    937 
    938 	return false
    939 }
    940 
    941 /*
    942  * substitute s for v in a
    943  * return failure to substitute
    944  */
    945 func copysub(a *obj.Addr, v *obj.Addr, s *obj.Addr, f int) int {
    946 	if copyas(a, v) {
    947 		reg := int(int(s.Reg))
    948 		if reg >= x86.REG_AX && reg <= x86.REG_R15 || reg >= x86.REG_X0 && reg <= x86.REG_X0+15 {
    949 			if f != 0 {
    950 				a.Reg = int16(reg)
    951 			}
    952 		}
    953 
    954 		return 0
    955 	}
    956 
    957 	if regtyp(v) {
    958 		reg := int(int(v.Reg))
    959 		if a.Type == obj.TYPE_MEM && int(a.Reg) == reg {
    960 			if (s.Reg == x86.REG_BP || s.Reg == x86.REG_R13) && a.Index != x86.REG_NONE {
    961 				return 1 /* can't use BP-base with index */
    962 			}
    963 			if f != 0 {
    964 				a.Reg = s.Reg
    965 			}
    966 		}
    967 
    968 		//			return 0;
    969 		if int(a.Index) == reg {
    970 			if f != 0 {
    971 				a.Index = s.Reg
    972 			}
    973 			return 0
    974 		}
    975 
    976 		return 0
    977 	}
    978 
    979 	return 0
    980 }
    981 
    982 func conprop(r0 *gc.Flow) {
    983 	var p *obj.Prog
    984 	var t int
    985 
    986 	p0 := (*obj.Prog)(r0.Prog)
    987 	v0 := (*obj.Addr)(&p0.To)
    988 	r := (*gc.Flow)(r0)
    989 
    990 loop:
    991 	r = gc.Uniqs(r)
    992 	if r == nil || r == r0 {
    993 		return
    994 	}
    995 	if gc.Uniqp(r) == nil {
    996 		return
    997 	}
    998 
    999 	p = r.Prog
   1000 	t = copyu(p, v0, nil)
   1001 	switch t {
   1002 	case 0, // miss
   1003 		1: // use
   1004 		goto loop
   1005 
   1006 	case 2, // rar
   1007 		4: // use and set
   1008 		break
   1009 
   1010 	case 3: // set
   1011 		if p.As == p0.As {
   1012 			if p.From.Type == p0.From.Type {
   1013 				if p.From.Reg == p0.From.Reg {
   1014 					if p.From.Node == p0.From.Node {
   1015 						if p.From.Offset == p0.From.Offset {
   1016 							if p.From.Scale == p0.From.Scale {
   1017 								if p.From.Type == obj.TYPE_FCONST && p.From.Val.(float64) == p0.From.Val.(float64) {
   1018 									if p.From.Index == p0.From.Index {
   1019 										excise(r)
   1020 										goto loop
   1021 									}
   1022 								}
   1023 							}
   1024 						}
   1025 					}
   1026 				}
   1027 			}
   1028 		}
   1029 	}
   1030 }
   1031 
   1032 func smallindir(a *obj.Addr, reg *obj.Addr) bool {
   1033 	return regtyp(reg) && a.Type == obj.TYPE_MEM && a.Reg == reg.Reg && a.Index == x86.REG_NONE && 0 <= a.Offset && a.Offset < 4096
   1034 }
   1035 
   1036 func stackaddr(a *obj.Addr) bool {
   1037 	return a.Type == obj.TYPE_REG && a.Reg == x86.REG_SP
   1038 }
   1039