import (
"cmd/internal/obj"
+ "cmd/internal/obj/x86"
"testing"
)
var Copyelim = copyelim
func testConfig(t testing.TB) *Config {
- testCtxt := &obj.Link{}
+ testCtxt := &obj.Link{Arch: &x86.Linkamd64}
return NewConfig("amd64", DummyFrontend{t}, testCtxt, true)
}
func (DummyFrontend) AllocFrame(f *Func) {
}
func (DummyFrontend) Syslook(s string) interface{} {
- return nil
+ return DummySym(s)
}
func (d DummyFrontend) Logf(msg string, args ...interface{}) { d.t.Logf(msg, args...) }
// There are no un-SSAable types in dummy land.
return true
}
+
+type DummySym string
+
+func (s DummySym) String() string { return string(s) }
func (t *TypeImpl) String() string { return t.Name }
func (t *TypeImpl) SimpleString() string { return t.Name }
func (t *TypeImpl) ElemType() Type { return t.Elem_ }
-func (t *TypeImpl) PtrTo() Type { panic("not implemented") }
+func (t *TypeImpl) PtrTo() Type { return TypeBytePtr }
func (t *TypeImpl) NumFields() int { panic("not implemented") }
func (t *TypeImpl) FieldType(i int) Type { panic("not implemented") }
func (t *TypeImpl) FieldOff(i int) int64 { panic("not implemented") }
defer f.retSparseSet(wbs)
}
- mem := v.Args[2]
line := v.Line
// there may be a sequence of WB stores in the current block. find them.
}
}
+ // find the memory before the WB stores
+ // this memory is not a WB store but it is used in a WB store.
+ var mem *Value
+ for _, w := range storeWBs {
+ a := w.Args[len(w.Args)-1]
+ if wbs.contains(a.ID) {
+ continue
+ }
+ if mem != nil {
+ b.Fatalf("two stores live simultaneously: %s, %s", mem, a)
+ }
+ mem = a
+ }
+
b.Values = append(b.Values[:i], others...) // move WB ops out of this block
bThen := f.NewBlock(BlockPlain)
// which may be used in subsequent blocks. Other memories in the
// sequence must be dead after this block since there can be only
// one memory live.
- v = storeWBs[len(storeWBs)-1]
- bEnd.Values = append(bEnd.Values, v)
- v.Block = bEnd
- v.reset(OpPhi)
- v.Type = TypeMem
- v.AddArg(memThen)
- v.AddArg(memElse)
- for _, w := range storeWBs[:len(storeWBs)-1] {
- for _, a := range w.Args {
- a.Uses--
+ last := storeWBs[0]
+ if len(storeWBs) > 1 {
+ // find the last store
+ last = nil
+ wbs.clear() // we reuse wbs to record WB stores that is used in another WB store
+ for _, w := range storeWBs {
+ wbs.add(w.Args[len(w.Args)-1].ID)
+ }
+ for _, w := range storeWBs {
+ if wbs.contains(w.ID) {
+ continue
+ }
+ if last != nil {
+ b.Fatalf("two stores live simultaneously: %s, %s", last, w)
+ }
+ last = w
}
}
- for _, w := range storeWBs[:len(storeWBs)-1] {
- f.freeValue(w)
+ bEnd.Values = append(bEnd.Values, last)
+ last.Block = bEnd
+ last.reset(OpPhi)
+ last.Type = TypeMem
+ last.AddArg(memThen)
+ last.AddArg(memElse)
+ for _, w := range storeWBs {
+ if w != last {
+ w.resetArgs()
+ }
+ }
+ for _, w := range storeWBs {
+ if w != last {
+ f.freeValue(w)
+ }
}
if f.Config.fe.Debug_wb() {
--- /dev/null
+// 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.
+
+package ssa
+
+import "testing"
+
+func TestWriteBarrierStoreOrder(t *testing.T) {
+ // Make sure writebarrier phase works even StoreWB ops are not in dependency order
+ c := testConfig(t)
+ ptrType := &TypeImpl{Size_: 8, Ptr: true, Name: "testptr"} // dummy for testing
+ fun := Fun(c, "entry",
+ Bloc("entry",
+ Valu("start", OpInitMem, TypeMem, 0, nil),
+ Valu("sb", OpSB, TypeInvalid, 0, nil),
+ Valu("sp", OpSP, TypeInvalid, 0, nil),
+ Valu("v", OpConstNil, ptrType, 0, nil),
+ Valu("addr1", OpAddr, ptrType, 0, nil, "sb"),
+ Valu("wb2", OpStoreWB, TypeMem, 8, nil, "addr1", "v", "wb1"),
+ Valu("wb1", OpStoreWB, TypeMem, 8, nil, "addr1", "v", "start"), // wb1 and wb2 are out of order
+ Goto("exit")),
+ Bloc("exit",
+ Exit("wb2")))
+
+ CheckFunc(fun.f)
+ writebarrier(fun.f)
+ CheckFunc(fun.f)
+}