// Copyright 2015 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 TestLiveControlOps(t *testing.T) { c := testConfig(t) f := Fun(c, "entry", Bloc("entry", Valu("mem", OpInitMem, TypeMem, 0, nil), Valu("x", OpAMD64MOVLconst, TypeInt8, 1, nil), Valu("y", OpAMD64MOVLconst, TypeInt8, 2, nil), Valu("a", OpAMD64TESTB, TypeFlags, 0, nil, "x", "y"), Valu("b", OpAMD64TESTB, TypeFlags, 0, nil, "y", "x"), Eq("a", "if", "exit"), ), Bloc("if", Eq("b", "plain", "exit"), ), Bloc("plain", Goto("exit"), ), Bloc("exit", Exit("mem"), ), ) flagalloc(f.f) regalloc(f.f) checkFunc(f.f) } func TestSpillMove(t *testing.T) { // Test for issue 20472. We shouldn't move a spill out to exit blocks // if there is an exit block where the spill is dead but the pre-spill // value is live. c := testConfig(t) ptrType := &TypeImpl{Size_: 8, Ptr: true, Name: "testptr"} // dummy for testing arg1Aux := c.fe.Auto(TypeInt64) arg2Aux := c.fe.Auto(ptrType) f := Fun(c, "entry", Bloc("entry", Valu("mem", OpInitMem, TypeMem, 0, nil), Valu("x", OpArg, TypeInt64, 0, arg1Aux), Valu("p", OpArg, ptrType, 0, arg2Aux), Valu("a", OpAMD64TESTQ, TypeFlags, 0, nil, "x", "x"), Goto("loop1"), ), Bloc("loop1", Valu("y", OpAMD64MULQ, TypeInt64, 0, nil, "x", "x"), Eq("a", "loop2", "exit1"), ), Bloc("loop2", Eq("a", "loop1", "exit2"), ), Bloc("exit1", // store before call, y is available in a register Valu("mem2", OpAMD64MOVQstore, TypeMem, 0, nil, "p", "y", "mem"), Valu("mem3", OpAMD64CALLstatic, TypeMem, 0, nil, "mem2"), Exit("mem3"), ), Bloc("exit2", // store after call, y must be loaded from a spill location Valu("mem4", OpAMD64CALLstatic, TypeMem, 0, nil, "mem"), Valu("mem5", OpAMD64MOVQstore, TypeMem, 0, nil, "p", "y", "mem4"), Exit("mem5"), ), ) flagalloc(f.f) regalloc(f.f) checkFunc(f.f) // There should still be a spill in Loop1, and nowhere else. if numSpills(f.blocks["loop1"]) != 1 { t.Errorf("spill missing from loop1") } if numSpills(f.blocks["loop2"]) != 0 { t.Errorf("spill present in loop2") } if numSpills(f.blocks["exit1"]) != 0 { t.Errorf("spill present in exit1") } if numSpills(f.blocks["exit2"]) != 0 { t.Errorf("spill present in exit2") } } func numSpills(b *Block) int { n := 0 for _, v := range b.Values { if v.Op == OpStoreReg { n++ } } return n }