func findu1(r *gc.Flow, v *obj.Addr) bool { for ; r != nil; r = r.S1 { if r.Active != 0 { return false } r.Active = 1 switch copyu(r.Prog, v, nil) { case 1, /* used */ 2, /* read-alter-rewrite */ 4: /* set and used */ return true case 3: /* set */ return false } if r.S2 != nil { if findu1(r.S2, v) { return true } } } return false }
// copy1 replaces uses of v2 with v1 starting at r and returns true if // all uses were rewritten. func copy1(v1 *obj.Addr, v2 *obj.Addr, r *gc.Flow, f int) bool { if uint32(r.Active) == gactive { return true } r.Active = int32(gactive) for ; r != nil; r = r.S1 { p := r.Prog if f == 0 && gc.Uniqp(r) == nil { // Multiple predecessors; conservatively // assume v1 was set on other path f = 1 } t := copyu(p, v2, nil) switch t { case _ReadWriteSame: return false case _Write: return true case _Read, _ReadWriteDiff: if f != 0 { return false } if copyu(p, v2, v1) != 0 { return false } if t == _ReadWriteDiff { return true } } if f == 0 { switch copyu(p, v1, nil) { case _ReadWriteSame, _ReadWriteDiff, _Write: f = 1 } } if r.S2 != nil { if !copy1(v1, v2, r.S2, f) { return false } } } return true }
// copy1 replaces uses of v2 with v1 starting at r and returns true if // all uses were rewritten. func copy1(v1 *obj.Addr, v2 *obj.Addr, r *gc.Flow, f bool) bool { if uint32(r.Active) == gactive { if gc.Debug['P'] != 0 { fmt.Printf("act set; return 1\n") } return true } r.Active = int32(gactive) if gc.Debug['P'] != 0 { fmt.Printf("copy1 replace %v with %v f=%v\n", gc.Ctxt.Dconv(v2), gc.Ctxt.Dconv(v1), f) } for ; r != nil; r = r.S1 { p := r.Prog if gc.Debug['P'] != 0 { fmt.Printf("%v", p) } if !f && gc.Uniqp(r) == nil { // Multiple predecessors; conservatively // assume v1 was set on other path f = true if gc.Debug['P'] != 0 { fmt.Printf("; merge; f=%v", f) } } switch t := copyu(p, v2, nil); t { case 2: /* rar, can't split */ if gc.Debug['P'] != 0 { fmt.Printf("; %v rar; return 0\n", gc.Ctxt.Dconv(v2)) } return false case 3: /* set */ if gc.Debug['P'] != 0 { fmt.Printf("; %v set; return 1\n", gc.Ctxt.Dconv(v2)) } return true case 1, /* used, substitute */ 4: /* use and set */ if f { if gc.Debug['P'] == 0 { return false } if t == 4 { fmt.Printf("; %v used+set and f=%v; return 0\n", gc.Ctxt.Dconv(v2), f) } else { fmt.Printf("; %v used and f=%v; return 0\n", gc.Ctxt.Dconv(v2), f) } return false } if copyu(p, v2, v1) != 0 { if gc.Debug['P'] != 0 { fmt.Printf("; sub fail; return 0\n") } return false } if gc.Debug['P'] != 0 { fmt.Printf("; sub %v->%v\n => %v", gc.Ctxt.Dconv(v2), gc.Ctxt.Dconv(v1), p) } if t == 4 { if gc.Debug['P'] != 0 { fmt.Printf("; %v used+set; return 1\n", gc.Ctxt.Dconv(v2)) } return true } } if !f { t := copyu(p, v1, nil) if t == 2 || t == 3 || t == 4 { f = true if gc.Debug['P'] != 0 { fmt.Printf("; %v set and !f; f=%v", gc.Ctxt.Dconv(v1), f) } } } if gc.Debug['P'] != 0 { fmt.Printf("\n") } if r.S2 != nil { if !copy1(v1, v2, r.S2, f) { return false } } } return true }