m := s.mem()
b := s.endBlock()
b.Kind = ssa.BlockExit
- b.Control = m
+ b.SetControl(m)
// TODO: never rewrite OPANIC to OCALLFUNC in the
// first place. Need to wait until all backends
// go through SSA.
m := s.mem()
b := s.endBlock()
b.Kind = ssa.BlockRet
- b.Control = m
+ b.SetControl(m)
return b
}
b := s.endBlock()
b.Kind = ssa.BlockIf
- b.Control = el
+ b.SetControl(el)
// In theory, we should set b.Likely here based on context.
// However, gc only gives us likeliness hints
// in a single place, for plain OIF statements,
b := s.endBlock()
b.Kind = ssa.BlockIf
b.Likely = ssa.BranchUnlikely
- b.Control = cmp
+ b.SetControl(cmp)
b.AddEdgeTo(grow)
b.AddEdgeTo(assign)
c := s.expr(cond)
b := s.endBlock()
b.Kind = ssa.BlockIf
- b.Control = c
+ b.SetControl(c)
b.Likely = ssa.BranchPrediction(likely) // gc and ssa both use -1/0/+1 for likeliness
b.AddEdgeTo(yes)
b.AddEdgeTo(no)
s.vars[&memVar] = call
b := s.endBlock()
b.Kind = ssa.BlockCall
- b.Control = call
+ b.SetControl(call)
b.AddEdgeTo(bNext)
if k == callDefer {
// Add recover edge to exit code.
chk := s.newValue2(ssa.OpNilCheck, ssa.TypeVoid, ptr, s.mem())
b := s.endBlock()
b.Kind = ssa.BlockCheck
- b.Control = chk
+ b.SetControl(chk)
bNext := s.f.NewBlock(ssa.BlockPlain)
b.AddEdgeTo(bNext)
s.startBlock(bNext)
func (s *state) check(cmp *ssa.Value, fn *Node) {
b := s.endBlock()
b.Kind = ssa.BlockIf
- b.Control = cmp
+ b.SetControl(cmp)
b.Likely = ssa.BranchLikely
bNext := s.f.NewBlock(ssa.BlockPlain)
line := s.peekLine()
b := s.endBlock()
if !returns {
b.Kind = ssa.BlockExit
- b.Control = call
+ b.SetControl(call)
call.AuxInt = off
if len(results) > 0 {
Fatalf("panic call can't have results")
return nil
}
b.Kind = ssa.BlockCall
- b.Control = call
+ b.SetControl(call)
bNext := s.f.NewBlock(ssa.BlockPlain)
b.AddEdgeTo(bNext)
s.startBlock(bNext)
b := s.endBlock()
b.Kind = ssa.BlockIf
b.Likely = ssa.BranchUnlikely
- b.Control = flag
+ b.SetControl(flag)
b.AddEdgeTo(bThen)
b.AddEdgeTo(bElse)
b := s.endBlock()
b.Kind = ssa.BlockIf
b.Likely = ssa.BranchUnlikely
- b.Control = flag
+ b.SetControl(flag)
b.AddEdgeTo(bThen)
b.AddEdgeTo(bElse)
b := s.endBlock()
b.Kind = ssa.BlockIf
b.Likely = ssa.BranchLikely
- b.Control = cmp
+ b.SetControl(cmp)
// Generate code for non-zero length slice case.
nz := s.f.NewBlock(ssa.BlockPlain)
cmp := s.newValue2(cvttab.geq, Types[TBOOL], x, s.zeroVal(ft))
b := s.endBlock()
b.Kind = ssa.BlockIf
- b.Control = cmp
+ b.SetControl(cmp)
b.Likely = ssa.BranchLikely
bThen := s.f.NewBlock(ssa.BlockPlain)
cmp := s.newValue2(ssa.OpEqPtr, Types[TBOOL], x, nilValue)
b := s.endBlock()
b.Kind = ssa.BlockIf
- b.Control = cmp
+ b.SetControl(cmp)
b.Likely = ssa.BranchUnlikely
bThen := s.f.NewBlock(ssa.BlockPlain)
cmp := s.newValue2(cvttab.ltf, Types[TBOOL], x, twoToThe63)
b := s.endBlock()
b.Kind = ssa.BlockIf
- b.Control = cmp
+ b.SetControl(cmp)
b.Likely = ssa.BranchLikely
bThen := s.f.NewBlock(ssa.BlockPlain)
isnonnil := s.newValue2(ssa.OpNeqPtr, Types[TBOOL], tab, s.constNil(byteptr))
b := s.endBlock()
b.Kind = ssa.BlockIf
- b.Control = isnonnil
+ b.SetControl(isnonnil)
b.Likely = ssa.BranchLikely
bLoad := s.f.NewBlock(ssa.BlockPlain)
cond := s.newValue2(ssa.OpEqPtr, Types[TBOOL], typ, target)
b := s.endBlock()
b.Kind = ssa.BlockIf
- b.Control = cond
+ b.SetControl(cond)
b.Likely = ssa.BranchLikely
byteptr := Ptrto(Types[TUINT8])
return s
}
+func (b *Block) SetControl(v *Value) {
+ if w := b.Control; w != nil {
+ w.Uses--
+ }
+ b.Control = v
+ if v != nil {
+ v.Uses++
+ }
+}
+
// AddEdgeTo adds an edge from block b to block c. Used during building of the
// SSA graph; do not use on an already-completed SSA graph.
func (b *Block) AddEdgeTo(c *Block) {
}
}
}
+
+ // Check use counts
+ uses := make([]int32, f.NumValues())
+ for _, b := range f.Blocks {
+ for _, v := range b.Values {
+ for _, a := range v.Args {
+ uses[a.ID]++
+ }
+ }
+ if b.Control != nil {
+ uses[b.Control.ID]++
+ }
+ }
+ for _, b := range f.Blocks {
+ for _, v := range b.Values {
+ if v.Uses != uses[v.ID] {
+ f.Fatalf("%s has %d uses, but has Uses=%d", v, uses[v.ID], v.Uses)
+ }
+ }
+ }
}
// domCheck reports whether x dominates y (including x==y).
copyelimValue(v)
}
v := b.Control
- if v != nil {
+ if v != nil && v.Op == OpCopy {
for v.Op == OpCopy {
v = v.Args[0]
}
- b.Control = v
+ b.SetControl(v)
}
}
}
}
-func copyelimValue(v *Value) {
+func copyelimValue(v *Value) bool {
// elide any copies generated during rewriting
+ changed := false
for i, a := range v.Args {
if a.Op != OpCopy {
continue
}
advance = !advance
}
- v.Args[i] = a
+ v.SetArg(i, a)
+ changed = true
}
+ return changed
}
// them appropriately, so don't mess with them here.
continue
}
- b.Control = x
+ b.SetControl(x)
}
}
}
}
f.Names = f.Names[:i]
+ // Unlink values.
+ for _, b := range f.Blocks {
+ if !reachable[b.ID] {
+ b.SetControl(nil)
+ }
+ for _, v := range b.Values {
+ if !live[v.ID] {
+ v.resetArgs()
+ }
+ }
+ }
+
// Remove dead values from blocks' value list. Return dead
// values to the allocator.
for _, b := range f.Blocks {
if v.Op != OpPhi {
continue
}
+ v.Args[i].Uses--
v.Args[i] = v.Args[n]
v.Args[n] = nil // aid GC
v.Args = v.Args[:n]
if v := b.Control; v != nil && v != flag && v.Type.IsFlags() {
// Recalculate control value.
c := v.copyInto(b)
- b.Control = c
+ b.SetControl(c)
flag = v
}
if v := end[b.ID]; v != nil && v != flag {
if v.Block == nil {
f.Fatalf("trying to free an already freed value")
}
+ if v.Uses != 0 {
+ f.Fatalf("value %s still has %d uses", v, v.Uses)
+ }
// Clear everything but ID (which we reuse).
id := v.ID
v.AuxInt = 0
v.Args = v.argstorage[:1]
v.argstorage[0] = arg
+ arg.Uses++
return v
}
v.AuxInt = auxint
v.Args = v.argstorage[:1]
v.argstorage[0] = arg
+ arg.Uses++
return v
}
v.Aux = aux
v.Args = v.argstorage[:1]
v.argstorage[0] = arg
+ arg.Uses++
return v
}
v.Aux = aux
v.Args = v.argstorage[:1]
v.argstorage[0] = arg
+ arg.Uses++
return v
}
v.Args = v.argstorage[:2]
v.argstorage[0] = arg0
v.argstorage[1] = arg1
+ arg0.Uses++
+ arg1.Uses++
return v
}
v.Args = v.argstorage[:2]
v.argstorage[0] = arg0
v.argstorage[1] = arg1
+ arg0.Uses++
+ arg1.Uses++
return v
}
v := b.Func.newValue(op, t, b, line)
v.AuxInt = 0
v.Args = []*Value{arg0, arg1, arg2}
+ arg0.Uses++
+ arg1.Uses++
+ arg2.Uses++
return v
}
v := b.Func.newValue(op, t, b, line)
v.AuxInt = auxint
v.Args = []*Value{arg0, arg1, arg2}
+ arg0.Uses++
+ arg1.Uses++
+ arg2.Uses++
return v
}
if !ok {
f.Fatalf("control value for block %s missing", bloc.name)
}
- b.Control = cval
+ b.SetControl(cval)
}
// Fill in args.
for _, valu := range bloc.valus {
ss.removePred(s1)
}
b.Kind = BlockPlain
- b.Control = nil
+ b.SetControl(nil)
b.Succs = append(b.Succs[:0], ss)
// Trash the empty blocks s0 & s1.
// as the original load. If not, we end up making a value with
// memory type live in two different blocks, which can lead to
// multiple memory values alive simultaneously.
-(MOVBQSX (MOVBload [off] {sym} ptr mem)) -> @v.Args[0].Block (MOVBQSXload <v.Type> [off] {sym} ptr mem)
-(MOVBQZX (MOVBload [off] {sym} ptr mem)) -> @v.Args[0].Block (MOVBQZXload <v.Type> [off] {sym} ptr mem)
-(MOVWQSX (MOVWload [off] {sym} ptr mem)) -> @v.Args[0].Block (MOVWQSXload <v.Type> [off] {sym} ptr mem)
-(MOVWQZX (MOVWload [off] {sym} ptr mem)) -> @v.Args[0].Block (MOVWQZXload <v.Type> [off] {sym} ptr mem)
-(MOVLQSX (MOVLload [off] {sym} ptr mem)) -> @v.Args[0].Block (MOVLQSXload <v.Type> [off] {sym} ptr mem)
-(MOVLQZX (MOVLload [off] {sym} ptr mem)) -> @v.Args[0].Block (MOVLQZXload <v.Type> [off] {sym} ptr mem)
+// Make sure we don't combine these ops if the load has another use.
+// This prevents a single load from being split into multiple loads
+// which then might return different values. See test/atomicload.go.
+(MOVBQSX (MOVBload [off] {sym} ptr mem)) && v.Args[0].Uses == 1 -> @v.Args[0].Block (MOVBQSXload <v.Type> [off] {sym} ptr mem)
+(MOVBQZX (MOVBload [off] {sym} ptr mem)) && v.Args[0].Uses == 1 -> @v.Args[0].Block (MOVBQZXload <v.Type> [off] {sym} ptr mem)
+(MOVWQSX (MOVWload [off] {sym} ptr mem)) && v.Args[0].Uses == 1 -> @v.Args[0].Block (MOVWQSXload <v.Type> [off] {sym} ptr mem)
+(MOVWQZX (MOVWload [off] {sym} ptr mem)) && v.Args[0].Uses == 1 -> @v.Args[0].Block (MOVWQZXload <v.Type> [off] {sym} ptr mem)
+(MOVLQSX (MOVLload [off] {sym} ptr mem)) && v.Args[0].Uses == 1 -> @v.Args[0].Block (MOVLQSXload <v.Type> [off] {sym} ptr mem)
+(MOVLQZX (MOVLload [off] {sym} ptr mem)) && v.Args[0].Uses == 1 -> @v.Args[0].Block (MOVLQZXload <v.Type> [off] {sym} ptr mem)
// replace load from same location as preceding store with copy
(MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
fmt.Fprintf(w, "b.Kind = %s\n", blockName(t[0], arch))
if t[1] == "nil" {
- fmt.Fprintf(w, "b.Control = nil\n")
+ fmt.Fprintf(w, "b.SetControl(nil)\n")
} else {
- fmt.Fprintf(w, "b.Control = %s\n", genResult0(w, arch, t[1], new(int), false, false))
+ fmt.Fprintf(w, "b.SetControl(%s)\n", genResult0(w, arch, t[1], new(int), false, false))
}
if len(newsuccs) < len(succs) {
fmt.Fprintf(w, "b.Succs = b.Succs[:%d]\n", len(newsuccs))
v = fmt.Sprintf("v%d", *alloc)
*alloc++
fmt.Fprintf(w, "%s := b.NewValue0(v.Line, %s, %s)\n", v, opName(s[0], arch), opType)
- if move {
+ if move && top {
// Rewrite original into a copy
fmt.Fprintf(w, "v.reset(OpCopy)\n")
fmt.Fprintf(w, "v.AddArg(%s)\n", v)
switch node.block.Kind {
case BlockIf:
node.block.Kind = BlockFirst
- node.block.Control = nil
+ node.block.SetControl(nil)
case BlockCheck:
node.block.Kind = BlockPlain
- node.block.Control = nil
+ node.block.SetControl(nil)
default:
f.Fatalf("bad block kind in nilcheck %s", node.block.Kind)
}
if succ != unknown {
b := node.block
b.Kind = BlockFirst
- b.Control = nil
+ b.SetControl(nil)
if succ == negative {
b.Succs[0], b.Succs[1] = b.Succs[1], b.Succs[0]
}
// Value is rematerializeable, don't issue it here.
// It will get issued just before each use (see
// allocValueToReg).
+ for _, a := range v.Args {
+ a.Uses--
+ }
s.advanceUses(v)
continue
}
// Issue the Value itself.
for i, a := range args {
- v.Args[i] = a // use register version of arguments
+ v.SetArg(i, a) // use register version of arguments
}
b.Values = append(b.Values, v)
// Constants, SP, SB, ...
continue
}
+ spill.Args[0].Uses--
f.freeValue(spill)
}
for _, b := range f.Blocks {
// Value is already in the correct place.
e.contents[loc] = contentRecord{vid, occupant.c, true}
if splice != nil {
+ (*splice).Uses--
*splice = occupant.c
+ occupant.c.Uses++
}
// Note: if splice==nil then c will appear dead. This is
// non-SSA formed code, so be careful after this pass not to run
}
e.set(loc, vid, x, true)
if splice != nil {
+ (*splice).Uses--
*splice = x
+ x.Uses++
}
return true
}
}
if b.Control != nil && b.Control.Op == OpCopy {
for b.Control.Op == OpCopy {
- b.Control = b.Control.Args[0]
+ b.SetControl(b.Control.Args[0])
}
}
curb = b
}
curb = nil
for _, v := range b.Values {
- copyelimValue(v)
+ change = copyelimValue(v) || change
change = phielimValue(v) || change
// apply rewrite function
b := v.Block
_ = b
// match: (MOVBQSX (MOVBload [off] {sym} ptr mem))
- // cond:
+ // cond: v.Args[0].Uses == 1
// result: @v.Args[0].Block (MOVBQSXload <v.Type> [off] {sym} ptr mem)
for {
if v.Args[0].Op != OpAMD64MOVBload {
sym := v.Args[0].Aux
ptr := v.Args[0].Args[0]
mem := v.Args[0].Args[1]
+ if !(v.Args[0].Uses == 1) {
+ break
+ }
b = v.Args[0].Block
v0 := b.NewValue0(v.Line, OpAMD64MOVBQSXload, v.Type)
v.reset(OpCopy)
b := v.Block
_ = b
// match: (MOVBQZX (MOVBload [off] {sym} ptr mem))
- // cond:
+ // cond: v.Args[0].Uses == 1
// result: @v.Args[0].Block (MOVBQZXload <v.Type> [off] {sym} ptr mem)
for {
if v.Args[0].Op != OpAMD64MOVBload {
sym := v.Args[0].Aux
ptr := v.Args[0].Args[0]
mem := v.Args[0].Args[1]
+ if !(v.Args[0].Uses == 1) {
+ break
+ }
b = v.Args[0].Block
v0 := b.NewValue0(v.Line, OpAMD64MOVBQZXload, v.Type)
v.reset(OpCopy)
b := v.Block
_ = b
// match: (MOVLQSX (MOVLload [off] {sym} ptr mem))
- // cond:
+ // cond: v.Args[0].Uses == 1
// result: @v.Args[0].Block (MOVLQSXload <v.Type> [off] {sym} ptr mem)
for {
if v.Args[0].Op != OpAMD64MOVLload {
sym := v.Args[0].Aux
ptr := v.Args[0].Args[0]
mem := v.Args[0].Args[1]
+ if !(v.Args[0].Uses == 1) {
+ break
+ }
b = v.Args[0].Block
v0 := b.NewValue0(v.Line, OpAMD64MOVLQSXload, v.Type)
v.reset(OpCopy)
b := v.Block
_ = b
// match: (MOVLQZX (MOVLload [off] {sym} ptr mem))
- // cond:
+ // cond: v.Args[0].Uses == 1
// result: @v.Args[0].Block (MOVLQZXload <v.Type> [off] {sym} ptr mem)
for {
if v.Args[0].Op != OpAMD64MOVLload {
sym := v.Args[0].Aux
ptr := v.Args[0].Args[0]
mem := v.Args[0].Args[1]
+ if !(v.Args[0].Uses == 1) {
+ break
+ }
b = v.Args[0].Block
v0 := b.NewValue0(v.Line, OpAMD64MOVLQZXload, v.Type)
v.reset(OpCopy)
b := v.Block
_ = b
// match: (MOVWQSX (MOVWload [off] {sym} ptr mem))
- // cond:
+ // cond: v.Args[0].Uses == 1
// result: @v.Args[0].Block (MOVWQSXload <v.Type> [off] {sym} ptr mem)
for {
if v.Args[0].Op != OpAMD64MOVWload {
sym := v.Args[0].Aux
ptr := v.Args[0].Args[0]
mem := v.Args[0].Args[1]
+ if !(v.Args[0].Uses == 1) {
+ break
+ }
b = v.Args[0].Block
v0 := b.NewValue0(v.Line, OpAMD64MOVWQSXload, v.Type)
v.reset(OpCopy)
b := v.Block
_ = b
// match: (MOVWQZX (MOVWload [off] {sym} ptr mem))
- // cond:
+ // cond: v.Args[0].Uses == 1
// result: @v.Args[0].Block (MOVWQZXload <v.Type> [off] {sym} ptr mem)
for {
if v.Args[0].Op != OpAMD64MOVWload {
sym := v.Args[0].Aux
ptr := v.Args[0].Args[0]
mem := v.Args[0].Args[1]
+ if !(v.Args[0].Uses == 1) {
+ break
+ }
b = v.Args[0].Block
v0 := b.NewValue0(v.Line, OpAMD64MOVWQZXload, v.Type)
v.reset(OpCopy)
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockAMD64EQ
- b.Control = cmp
+ b.SetControl(cmp)
b.Succs[0] = yes
b.Succs[1] = no
return true
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockFirst
- b.Control = nil
+ b.SetControl(nil)
b.Succs[0] = yes
b.Succs[1] = no
return true
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockFirst
- b.Control = nil
+ b.SetControl(nil)
b.Succs[0] = no
b.Succs[1] = yes
b.Likely *= -1
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockFirst
- b.Control = nil
+ b.SetControl(nil)
b.Succs[0] = no
b.Succs[1] = yes
b.Likely *= -1
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockFirst
- b.Control = nil
+ b.SetControl(nil)
b.Succs[0] = no
b.Succs[1] = yes
b.Likely *= -1
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockFirst
- b.Control = nil
+ b.SetControl(nil)
b.Succs[0] = no
b.Succs[1] = yes
b.Likely *= -1
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockAMD64LE
- b.Control = cmp
+ b.SetControl(cmp)
b.Succs[0] = yes
b.Succs[1] = no
return true
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockFirst
- b.Control = nil
+ b.SetControl(nil)
b.Succs[0] = yes
b.Succs[1] = no
return true
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockFirst
- b.Control = nil
+ b.SetControl(nil)
b.Succs[0] = no
b.Succs[1] = yes
b.Likely *= -1
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockFirst
- b.Control = nil
+ b.SetControl(nil)
b.Succs[0] = no
b.Succs[1] = yes
b.Likely *= -1
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockFirst
- b.Control = nil
+ b.SetControl(nil)
b.Succs[0] = yes
b.Succs[1] = no
return true
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockFirst
- b.Control = nil
+ b.SetControl(nil)
b.Succs[0] = yes
b.Succs[1] = no
return true
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockAMD64LT
- b.Control = cmp
+ b.SetControl(cmp)
b.Succs[0] = yes
b.Succs[1] = no
return true
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockFirst
- b.Control = nil
+ b.SetControl(nil)
b.Succs[0] = no
b.Succs[1] = yes
b.Likely *= -1
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockFirst
- b.Control = nil
+ b.SetControl(nil)
b.Succs[0] = no
b.Succs[1] = yes
b.Likely *= -1
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockFirst
- b.Control = nil
+ b.SetControl(nil)
b.Succs[0] = no
b.Succs[1] = yes
b.Likely *= -1
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockFirst
- b.Control = nil
+ b.SetControl(nil)
b.Succs[0] = yes
b.Succs[1] = no
return true
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockFirst
- b.Control = nil
+ b.SetControl(nil)
b.Succs[0] = yes
b.Succs[1] = no
return true
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockAMD64LT
- b.Control = cmp
+ b.SetControl(cmp)
b.Succs[0] = yes
b.Succs[1] = no
return true
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockAMD64LE
- b.Control = cmp
+ b.SetControl(cmp)
b.Succs[0] = yes
b.Succs[1] = no
return true
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockAMD64GT
- b.Control = cmp
+ b.SetControl(cmp)
b.Succs[0] = yes
b.Succs[1] = no
return true
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockAMD64GE
- b.Control = cmp
+ b.SetControl(cmp)
b.Succs[0] = yes
b.Succs[1] = no
return true
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockAMD64EQ
- b.Control = cmp
+ b.SetControl(cmp)
b.Succs[0] = yes
b.Succs[1] = no
return true
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockAMD64NE
- b.Control = cmp
+ b.SetControl(cmp)
b.Succs[0] = yes
b.Succs[1] = no
return true
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockAMD64ULT
- b.Control = cmp
+ b.SetControl(cmp)
b.Succs[0] = yes
b.Succs[1] = no
return true
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockAMD64ULE
- b.Control = cmp
+ b.SetControl(cmp)
b.Succs[0] = yes
b.Succs[1] = no
return true
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockAMD64UGT
- b.Control = cmp
+ b.SetControl(cmp)
b.Succs[0] = yes
b.Succs[1] = no
return true
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockAMD64UGE
- b.Control = cmp
+ b.SetControl(cmp)
b.Succs[0] = yes
b.Succs[1] = no
return true
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockAMD64UGT
- b.Control = cmp
+ b.SetControl(cmp)
b.Succs[0] = yes
b.Succs[1] = no
return true
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockAMD64UGE
- b.Control = cmp
+ b.SetControl(cmp)
b.Succs[0] = yes
b.Succs[1] = no
return true
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockAMD64EQF
- b.Control = cmp
+ b.SetControl(cmp)
b.Succs[0] = yes
b.Succs[1] = no
return true
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockAMD64NEF
- b.Control = cmp
+ b.SetControl(cmp)
b.Succs[0] = yes
b.Succs[1] = no
return true
v0 := b.NewValue0(v.Line, OpAMD64TESTB, TypeFlags)
v0.AddArg(cond)
v0.AddArg(cond)
- b.Control = v0
+ b.SetControl(v0)
b.Succs[0] = yes
b.Succs[1] = no
return true
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockAMD64GE
- b.Control = cmp
+ b.SetControl(cmp)
b.Succs[0] = yes
b.Succs[1] = no
return true
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockFirst
- b.Control = nil
+ b.SetControl(nil)
b.Succs[0] = yes
b.Succs[1] = no
return true
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockFirst
- b.Control = nil
+ b.SetControl(nil)
b.Succs[0] = yes
b.Succs[1] = no
return true
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockFirst
- b.Control = nil
+ b.SetControl(nil)
b.Succs[0] = yes
b.Succs[1] = no
return true
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockFirst
- b.Control = nil
+ b.SetControl(nil)
b.Succs[0] = no
b.Succs[1] = yes
b.Likely *= -1
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockFirst
- b.Control = nil
+ b.SetControl(nil)
b.Succs[0] = no
b.Succs[1] = yes
b.Likely *= -1
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockAMD64GT
- b.Control = cmp
+ b.SetControl(cmp)
b.Succs[0] = yes
b.Succs[1] = no
return true
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockFirst
- b.Control = nil
+ b.SetControl(nil)
b.Succs[0] = no
b.Succs[1] = yes
b.Likely *= -1
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockFirst
- b.Control = nil
+ b.SetControl(nil)
b.Succs[0] = yes
b.Succs[1] = no
return true
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockFirst
- b.Control = nil
+ b.SetControl(nil)
b.Succs[0] = yes
b.Succs[1] = no
return true
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockFirst
- b.Control = nil
+ b.SetControl(nil)
b.Succs[0] = no
b.Succs[1] = yes
b.Likely *= -1
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockFirst
- b.Control = nil
+ b.SetControl(nil)
b.Succs[0] = no
b.Succs[1] = yes
b.Likely *= -1
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockAMD64LT
- b.Control = cmp
+ b.SetControl(cmp)
b.Succs[0] = yes
b.Succs[1] = no
return true
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockAMD64LE
- b.Control = cmp
+ b.SetControl(cmp)
b.Succs[0] = yes
b.Succs[1] = no
return true
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockAMD64GT
- b.Control = cmp
+ b.SetControl(cmp)
b.Succs[0] = yes
b.Succs[1] = no
return true
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockAMD64GE
- b.Control = cmp
+ b.SetControl(cmp)
b.Succs[0] = yes
b.Succs[1] = no
return true
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockAMD64EQ
- b.Control = cmp
+ b.SetControl(cmp)
b.Succs[0] = yes
b.Succs[1] = no
return true
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockAMD64NE
- b.Control = cmp
+ b.SetControl(cmp)
b.Succs[0] = yes
b.Succs[1] = no
return true
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockAMD64ULT
- b.Control = cmp
+ b.SetControl(cmp)
b.Succs[0] = yes
b.Succs[1] = no
return true
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockAMD64ULE
- b.Control = cmp
+ b.SetControl(cmp)
b.Succs[0] = yes
b.Succs[1] = no
return true
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockAMD64UGT
- b.Control = cmp
+ b.SetControl(cmp)
b.Succs[0] = yes
b.Succs[1] = no
return true
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockAMD64UGE
- b.Control = cmp
+ b.SetControl(cmp)
b.Succs[0] = yes
b.Succs[1] = no
return true
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockAMD64UGT
- b.Control = cmp
+ b.SetControl(cmp)
b.Succs[0] = yes
b.Succs[1] = no
return true
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockAMD64UGE
- b.Control = cmp
+ b.SetControl(cmp)
b.Succs[0] = yes
b.Succs[1] = no
return true
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockAMD64EQF
- b.Control = cmp
+ b.SetControl(cmp)
b.Succs[0] = yes
b.Succs[1] = no
return true
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockAMD64NEF
- b.Control = cmp
+ b.SetControl(cmp)
b.Succs[0] = yes
b.Succs[1] = no
return true
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockAMD64NE
- b.Control = cmp
+ b.SetControl(cmp)
b.Succs[0] = yes
b.Succs[1] = no
return true
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockFirst
- b.Control = nil
+ b.SetControl(nil)
b.Succs[0] = no
b.Succs[1] = yes
b.Likely *= -1
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockFirst
- b.Control = nil
+ b.SetControl(nil)
b.Succs[0] = yes
b.Succs[1] = no
return true
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockFirst
- b.Control = nil
+ b.SetControl(nil)
b.Succs[0] = yes
b.Succs[1] = no
return true
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockFirst
- b.Control = nil
+ b.SetControl(nil)
b.Succs[0] = yes
b.Succs[1] = no
return true
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockFirst
- b.Control = nil
+ b.SetControl(nil)
b.Succs[0] = yes
b.Succs[1] = no
return true
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockAMD64ULE
- b.Control = cmp
+ b.SetControl(cmp)
b.Succs[0] = yes
b.Succs[1] = no
return true
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockFirst
- b.Control = nil
+ b.SetControl(nil)
b.Succs[0] = yes
b.Succs[1] = no
return true
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockFirst
- b.Control = nil
+ b.SetControl(nil)
b.Succs[0] = no
b.Succs[1] = yes
b.Likely *= -1
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockFirst
- b.Control = nil
+ b.SetControl(nil)
b.Succs[0] = yes
b.Succs[1] = no
return true
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockFirst
- b.Control = nil
+ b.SetControl(nil)
b.Succs[0] = no
b.Succs[1] = yes
b.Likely *= -1
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockFirst
- b.Control = nil
+ b.SetControl(nil)
b.Succs[0] = yes
b.Succs[1] = no
return true
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockAMD64ULT
- b.Control = cmp
+ b.SetControl(cmp)
b.Succs[0] = yes
b.Succs[1] = no
return true
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockFirst
- b.Control = nil
+ b.SetControl(nil)
b.Succs[0] = no
b.Succs[1] = yes
b.Likely *= -1
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockFirst
- b.Control = nil
+ b.SetControl(nil)
b.Succs[0] = no
b.Succs[1] = yes
b.Likely *= -1
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockFirst
- b.Control = nil
+ b.SetControl(nil)
b.Succs[0] = yes
b.Succs[1] = no
return true
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockFirst
- b.Control = nil
+ b.SetControl(nil)
b.Succs[0] = no
b.Succs[1] = yes
b.Likely *= -1
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockFirst
- b.Control = nil
+ b.SetControl(nil)
b.Succs[0] = yes
b.Succs[1] = no
return true
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockAMD64UGE
- b.Control = cmp
+ b.SetControl(cmp)
b.Succs[0] = yes
b.Succs[1] = no
return true
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockFirst
- b.Control = nil
+ b.SetControl(nil)
b.Succs[0] = yes
b.Succs[1] = no
return true
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockFirst
- b.Control = nil
+ b.SetControl(nil)
b.Succs[0] = yes
b.Succs[1] = no
return true
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockFirst
- b.Control = nil
+ b.SetControl(nil)
b.Succs[0] = no
b.Succs[1] = yes
b.Likely *= -1
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockFirst
- b.Control = nil
+ b.SetControl(nil)
b.Succs[0] = yes
b.Succs[1] = no
return true
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockFirst
- b.Control = nil
+ b.SetControl(nil)
b.Succs[0] = no
b.Succs[1] = yes
b.Likely *= -1
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockAMD64UGT
- b.Control = cmp
+ b.SetControl(cmp)
b.Succs[0] = yes
b.Succs[1] = no
return true
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockFirst
- b.Control = nil
+ b.SetControl(nil)
b.Succs[0] = no
b.Succs[1] = yes
b.Likely *= -1
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockFirst
- b.Control = nil
+ b.SetControl(nil)
b.Succs[0] = yes
b.Succs[1] = no
return true
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockFirst
- b.Control = nil
+ b.SetControl(nil)
b.Succs[0] = no
b.Succs[1] = yes
b.Likely *= -1
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockFirst
- b.Control = nil
+ b.SetControl(nil)
b.Succs[0] = yes
b.Succs[1] = no
return true
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockFirst
- b.Control = nil
+ b.SetControl(nil)
b.Succs[0] = no
b.Succs[1] = yes
b.Likely *= -1
v.reset(OpCopy)
v.AddArg(v0)
v1 := b.NewValue0(v.Line, OpOffPtr, v.Type.PtrTo())
- v.reset(OpCopy)
- v.AddArg(v1)
v1.AuxInt = t.FieldOff(int(i))
v1.AddArg(ptr)
v0.AddArg(v1)
}
next := b.Succs[0]
b.Kind = BlockPlain
- b.Control = nil
+ b.SetControl(nil)
b.Succs[0] = next
b.Likely = BranchUnknown
return true
yes := b.Succs[0]
no := b.Succs[1]
b.Kind = BlockIf
- b.Control = cond
+ b.SetControl(cond)
b.Succs[0] = no
b.Succs[1] = yes
b.Likely *= -1
break
}
b.Kind = BlockFirst
- b.Control = nil
+ b.SetControl(nil)
b.Succs[0] = yes
b.Succs[1] = no
return true
break
}
b.Kind = BlockFirst
- b.Control = nil
+ b.SetControl(nil)
b.Succs[0] = no
b.Succs[1] = yes
b.Likely *= -1
continue
}
if p.Succs[0] == b {
- v.Args[i] = ct
+ v.SetArg(i, ct)
} else {
- v.Args[i] = cf
+ v.SetArg(i, cf)
}
}
}
if w.Op != OpPhi {
continue
}
- w.Args = append(w.Args, w.Args[j])
+ w.AddArg(w.Args[j])
}
// Fix up b to have one less predecessor.
b.Preds[i] = b.Preds[n]
b.Preds[n] = nil
b.Preds = b.Preds[:n]
+ v.Args[i].Uses--
v.Args[i] = v.Args[n]
v.Args[n] = nil
v.Args = v.Args[:n]
_32bit uintptr // size on 32bit platforms
_64bit uintptr // size on 64bit platforms
}{
- {Value{}, 64, 112},
+ {Value{}, 68, 112},
{Block{}, 124, 232},
}
// Source line number
Line int32
+ // Use count. Each appearance in Value.Args and Block.Control counts once.
+ Uses int32
+
// Storage for the first three args
argstorage [3]*Value
}
v.resetArgs() // use argstorage
}
v.Args = append(v.Args, w)
+ w.Uses++
}
func (v *Value) AddArgs(a ...*Value) {
if v.Args == nil {
v.resetArgs() // use argstorage
}
v.Args = append(v.Args, a...)
+ for _, x := range a {
+ x.Uses++
+ }
}
func (v *Value) SetArg(i int, w *Value) {
+ v.Args[i].Uses--
v.Args[i] = w
+ w.Uses++
}
func (v *Value) RemoveArg(i int) {
+ v.Args[i].Uses--
copy(v.Args[i:], v.Args[i+1:])
v.Args[len(v.Args)-1] = nil // aid GC
v.Args = v.Args[:len(v.Args)-1]
}
func (v *Value) resetArgs() {
+ for _, a := range v.Args {
+ a.Uses--
+ }
v.argstorage[0] = nil
v.argstorage[1] = nil
v.Args = v.argstorage[:0]
if opcodeTable[a.Op].argLen == 0 {
key := vkey{a.Op, keyFor(a), a.Aux, typeStr(a)}
if rv, ok := vals[key]; ok {
- v.Args[i] = rv
+ v.SetArg(i, rv)
}
}
}
--- /dev/null
+// run
+
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Check that we do loads exactly once. The SSA backend
+// once tried to do the load in f twice, once sign extended
+// and once zero extended. This can cause problems in
+// racy code, particularly sync/mutex.
+
+package main
+
+func f(p *byte) bool {
+ x := *p
+ a := int64(int8(x))
+ b := int64(uint8(x))
+ return a == b
+}
+
+func main() {
+ var x byte
+ const N = 1000000
+ c := make(chan struct{})
+ go func() {
+ for i := 0; i < N; i++ {
+ x = 1
+ }
+ c <- struct{}{}
+ }()
+ go func() {
+ for i := 0; i < N; i++ {
+ x = 2
+ }
+ c <- struct{}{}
+ }()
+
+ for i := 0; i < N; i++ {
+ if !f(&x) {
+ panic("non-atomic load!")
+ }
+ }
+ <-c
+ <-c
+}