Commit 16b1fce9 authored by Keith Randall's avatar Keith Randall

[dev.ssa] cmd/compile: add aux typing, flags to ops

Add the aux type to opcodes.
Add rematerializeable as a flag.

Change-Id: I906e19281498f3ee51bb136299bf26e13a54b2ec
Reviewed-on: https://go-review.googlesource.com/19088
Run-TryBot: Keith Randall <khr@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: 's avatarTodd Neal <todd@tneal.org>
parent c87a62f3
......@@ -4022,11 +4022,11 @@ func (s *genState) genValue(v *ssa.Value) {
var i int64
switch v.Op {
case ssa.OpAMD64MOVBconst:
i = int64(int8(v.AuxInt))
i = int64(v.AuxInt8())
case ssa.OpAMD64MOVWconst:
i = int64(int16(v.AuxInt))
i = int64(v.AuxInt16())
case ssa.OpAMD64MOVLconst:
i = int64(int32(v.AuxInt))
i = int64(v.AuxInt32())
case ssa.OpAMD64MOVQconst:
i = v.AuxInt
}
......@@ -4116,7 +4116,7 @@ func (s *genState) genValue(v *ssa.Value) {
case ssa.OpAMD64MOVQstoreconst, ssa.OpAMD64MOVLstoreconst, ssa.OpAMD64MOVWstoreconst, ssa.OpAMD64MOVBstoreconst:
p := Prog(v.Op.Asm())
p.From.Type = obj.TYPE_CONST
sc := ssa.ValAndOff(v.AuxInt)
sc := v.AuxValAndOff()
i := sc.Val()
switch v.Op {
case ssa.OpAMD64MOVBstoreconst:
......
......@@ -148,9 +148,27 @@ func checkFunc(f *Func) {
}
for _, v := range b.Values {
switch v.Aux.(type) {
case bool, float32, float64:
f.Fatalf("value %v has an Aux value of type %T, should be AuxInt", v.LongString(), v.Aux)
// Check to make sure aux values make sense.
canHaveAux := false
canHaveAuxInt := false
switch opcodeTable[v.Op].auxType {
case auxNone:
case auxBool, auxInt8, auxInt16, auxInt32, auxInt64, auxFloat:
canHaveAuxInt = true
case auxString, auxSym:
canHaveAux = true
case auxSymOff, auxSymValAndOff:
canHaveAuxInt = true
canHaveAux = true
default:
f.Fatalf("unknown aux type for %s", v.Op)
}
if !canHaveAux && v.Aux != nil {
f.Fatalf("value %v has an Aux value %v but shouldn't", v.LongString(), v.Aux)
}
if !canHaveAuxInt && v.AuxInt != 0 {
f.Fatalf("value %v has an AuxInt value %d but shouldn't", v.LongString(), v.AuxInt)
}
for _, arg := range v.Args {
......
......@@ -10,7 +10,7 @@ func TestDeadLoop(t *testing.T) {
c := testConfig(t)
fun := Fun(c, "entry",
Bloc("entry",
Valu("mem", OpInitMem, TypeMem, 0, ".mem"),
Valu("mem", OpInitMem, TypeMem, 0, nil),
Goto("exit")),
Bloc("exit",
Exit("mem")),
......@@ -40,7 +40,7 @@ func TestDeadValue(t *testing.T) {
c := testConfig(t)
fun := Fun(c, "entry",
Bloc("entry",
Valu("mem", OpInitMem, TypeMem, 0, ".mem"),
Valu("mem", OpInitMem, TypeMem, 0, nil),
Valu("deadval", OpConst64, TypeInt64, 37, nil),
Goto("exit")),
Bloc("exit",
......@@ -64,7 +64,7 @@ func TestNeverTaken(t *testing.T) {
fun := Fun(c, "entry",
Bloc("entry",
Valu("cond", OpConstBool, TypeBool, 0, nil),
Valu("mem", OpInitMem, TypeMem, 0, ".mem"),
Valu("mem", OpInitMem, TypeMem, 0, nil),
If("cond", "then", "else")),
Bloc("then",
Goto("exit")),
......@@ -98,7 +98,7 @@ func TestNestedDeadBlocks(t *testing.T) {
c := testConfig(t)
fun := Fun(c, "entry",
Bloc("entry",
Valu("mem", OpInitMem, TypeMem, 0, ".mem"),
Valu("mem", OpInitMem, TypeMem, 0, nil),
Valu("cond", OpConstBool, TypeBool, 0, nil),
If("cond", "b2", "b4")),
Bloc("b2",
......
......@@ -12,7 +12,7 @@ func TestDeadStore(t *testing.T) {
ptrType := &TypeImpl{Size_: 8, Ptr: true, Name: "testptr", Elem_: elemType} // dummy for testing
fun := Fun(c, "entry",
Bloc("entry",
Valu("start", OpInitMem, TypeMem, 0, ".mem"),
Valu("start", OpInitMem, TypeMem, 0, nil),
Valu("sb", OpSB, TypeInvalid, 0, nil),
Valu("v", OpConstBool, TypeBool, 1, nil),
Valu("addr1", OpAddr, ptrType, 0, nil, "sb"),
......@@ -47,7 +47,7 @@ func TestDeadStorePhi(t *testing.T) {
ptrType := &TypeImpl{Size_: 8, Ptr: true, Name: "testptr"} // dummy for testing
fun := Fun(c, "entry",
Bloc("entry",
Valu("start", OpInitMem, TypeMem, 0, ".mem"),
Valu("start", OpInitMem, TypeMem, 0, nil),
Valu("sb", OpSB, TypeInvalid, 0, nil),
Valu("v", OpConstBool, TypeBool, 1, nil),
Valu("addr", OpAddr, ptrType, 0, nil, "sb"),
......@@ -74,7 +74,7 @@ func TestDeadStoreTypes(t *testing.T) {
t2 := &TypeImpl{Size_: 4, Ptr: true, Name: "t2"}
fun := Fun(c, "entry",
Bloc("entry",
Valu("start", OpInitMem, TypeMem, 0, ".mem"),
Valu("start", OpInitMem, TypeMem, 0, nil),
Valu("sb", OpSB, TypeInvalid, 0, nil),
Valu("v", OpConstBool, TypeBool, 1, nil),
Valu("addr1", OpAddr, t1, 0, nil, "sb"),
......
......@@ -20,7 +20,7 @@ func genLinear(size int) []bloc {
var blocs []bloc
blocs = append(blocs,
Bloc("entry",
Valu("mem", OpInitMem, TypeMem, 0, ".mem"),
Valu("mem", OpInitMem, TypeMem, 0, nil),
Goto(blockn(0)),
),
)
......@@ -43,7 +43,7 @@ func genFwdBack(size int) []bloc {
var blocs []bloc
blocs = append(blocs,
Bloc("entry",
Valu("mem", OpInitMem, TypeMem, 0, ".mem"),
Valu("mem", OpInitMem, TypeMem, 0, nil),
Valu("p", OpConstBool, TypeBool, 1, nil),
Goto(blockn(0)),
),
......@@ -73,7 +73,7 @@ func genManyPred(size int) []bloc {
var blocs []bloc
blocs = append(blocs,
Bloc("entry",
Valu("mem", OpInitMem, TypeMem, 0, ".mem"),
Valu("mem", OpInitMem, TypeMem, 0, nil),
Valu("p", OpConstBool, TypeBool, 1, nil),
Goto(blockn(0)),
),
......@@ -111,7 +111,7 @@ func genMaxPred(size int) []bloc {
var blocs []bloc
blocs = append(blocs,
Bloc("entry",
Valu("mem", OpInitMem, TypeMem, 0, ".mem"),
Valu("mem", OpInitMem, TypeMem, 0, nil),
Valu("p", OpConstBool, TypeBool, 1, nil),
Goto(blockn(0)),
),
......@@ -136,7 +136,7 @@ func genMaxPredValue(size int) []bloc {
var blocs []bloc
blocs = append(blocs,
Bloc("entry",
Valu("mem", OpInitMem, TypeMem, 0, ".mem"),
Valu("mem", OpInitMem, TypeMem, 0, nil),
Valu("p", OpConstBool, TypeBool, 1, nil),
Goto(blockn(0)),
),
......@@ -223,7 +223,7 @@ func TestDominatorsSingleBlock(t *testing.T) {
c := testConfig(t)
fun := Fun(c, "entry",
Bloc("entry",
Valu("mem", OpInitMem, TypeMem, 0, ".mem"),
Valu("mem", OpInitMem, TypeMem, 0, nil),
Exit("mem")))
doms := map[string]string{}
......@@ -238,7 +238,7 @@ func TestDominatorsSimple(t *testing.T) {
c := testConfig(t)
fun := Fun(c, "entry",
Bloc("entry",
Valu("mem", OpInitMem, TypeMem, 0, ".mem"),
Valu("mem", OpInitMem, TypeMem, 0, nil),
Goto("a")),
Bloc("a",
Goto("b")),
......@@ -266,7 +266,7 @@ func TestDominatorsMultPredFwd(t *testing.T) {
c := testConfig(t)
fun := Fun(c, "entry",
Bloc("entry",
Valu("mem", OpInitMem, TypeMem, 0, ".mem"),
Valu("mem", OpInitMem, TypeMem, 0, nil),
Valu("p", OpConstBool, TypeBool, 1, nil),
If("p", "a", "c")),
Bloc("a",
......@@ -294,7 +294,7 @@ func TestDominatorsDeadCode(t *testing.T) {
c := testConfig(t)
fun := Fun(c, "entry",
Bloc("entry",
Valu("mem", OpInitMem, TypeMem, 0, ".mem"),
Valu("mem", OpInitMem, TypeMem, 0, nil),
Valu("p", OpConstBool, TypeBool, 0, nil),
If("p", "b3", "b5")),
Bloc("b2", Exit("mem")),
......@@ -319,7 +319,7 @@ func TestDominatorsMultPredRev(t *testing.T) {
Bloc("entry",
Goto("first")),
Bloc("first",
Valu("mem", OpInitMem, TypeMem, 0, ".mem"),
Valu("mem", OpInitMem, TypeMem, 0, nil),
Valu("p", OpConstBool, TypeBool, 1, nil),
Goto("a")),
Bloc("a",
......@@ -348,7 +348,7 @@ func TestDominatorsMultPred(t *testing.T) {
c := testConfig(t)
fun := Fun(c, "entry",
Bloc("entry",
Valu("mem", OpInitMem, TypeMem, 0, ".mem"),
Valu("mem", OpInitMem, TypeMem, 0, nil),
Valu("p", OpConstBool, TypeBool, 1, nil),
If("p", "a", "c")),
Bloc("a",
......@@ -376,7 +376,7 @@ func TestPostDominators(t *testing.T) {
c := testConfig(t)
fun := Fun(c, "entry",
Bloc("entry",
Valu("mem", OpInitMem, TypeMem, 0, ".mem"),
Valu("mem", OpInitMem, TypeMem, 0, nil),
Valu("p", OpConstBool, TypeBool, 1, nil),
If("p", "a", "c")),
Bloc("a",
......@@ -403,7 +403,7 @@ func TestInfiniteLoop(t *testing.T) {
// note lack of an exit block
fun := Fun(c, "entry",
Bloc("entry",
Valu("mem", OpInitMem, TypeMem, 0, ".mem"),
Valu("mem", OpInitMem, TypeMem, 0, nil),
Valu("p", OpConstBool, TypeBool, 1, nil),
Goto("a")),
Bloc("a",
......
......@@ -6,7 +6,7 @@
// As an example, the following func
//
// b1:
// v1 = Arg <mem> [.mem]
// v1 = InitMem <mem>
// Plain -> b2
// b2:
// Exit v1
......@@ -18,7 +18,7 @@
//
// fun := Fun("entry",
// Bloc("entry",
// Valu("mem", OpInitMem, TypeMem, 0, ".mem"),
// Valu("mem", OpInitMem, TypeMem, 0, nil),
// Goto("exit")),
// Bloc("exit",
// Exit("mem")),
......@@ -267,7 +267,7 @@ func TestArgs(t *testing.T) {
Valu("a", OpConst64, TypeInt64, 14, nil),
Valu("b", OpConst64, TypeInt64, 26, nil),
Valu("sum", OpAdd64, TypeInt64, 0, nil, "a", "b"),
Valu("mem", OpInitMem, TypeMem, 0, ".mem"),
Valu("mem", OpInitMem, TypeMem, 0, nil),
Goto("exit")),
Bloc("exit",
Exit("mem")))
......@@ -289,7 +289,7 @@ func TestEquiv(t *testing.T) {
Valu("a", OpConst64, TypeInt64, 14, nil),
Valu("b", OpConst64, TypeInt64, 26, nil),
Valu("sum", OpAdd64, TypeInt64, 0, nil, "a", "b"),
Valu("mem", OpInitMem, TypeMem, 0, ".mem"),
Valu("mem", OpInitMem, TypeMem, 0, nil),
Goto("exit")),
Bloc("exit",
Exit("mem"))),
......@@ -298,7 +298,7 @@ func TestEquiv(t *testing.T) {
Valu("a", OpConst64, TypeInt64, 14, nil),
Valu("b", OpConst64, TypeInt64, 26, nil),
Valu("sum", OpAdd64, TypeInt64, 0, nil, "a", "b"),
Valu("mem", OpInitMem, TypeMem, 0, ".mem"),
Valu("mem", OpInitMem, TypeMem, 0, nil),
Goto("exit")),
Bloc("exit",
Exit("mem"))),
......@@ -310,7 +310,7 @@ func TestEquiv(t *testing.T) {
Valu("a", OpConst64, TypeInt64, 14, nil),
Valu("b", OpConst64, TypeInt64, 26, nil),
Valu("sum", OpAdd64, TypeInt64, 0, nil, "a", "b"),
Valu("mem", OpInitMem, TypeMem, 0, ".mem"),
Valu("mem", OpInitMem, TypeMem, 0, nil),
Goto("exit")),
Bloc("exit",
Exit("mem"))),
......@@ -321,7 +321,7 @@ func TestEquiv(t *testing.T) {
Valu("a", OpConst64, TypeInt64, 14, nil),
Valu("b", OpConst64, TypeInt64, 26, nil),
Valu("sum", OpAdd64, TypeInt64, 0, nil, "a", "b"),
Valu("mem", OpInitMem, TypeMem, 0, ".mem"),
Valu("mem", OpInitMem, TypeMem, 0, nil),
Goto("exit"))),
},
}
......@@ -338,26 +338,26 @@ func TestEquiv(t *testing.T) {
{
Fun(testConfig(t), "entry",
Bloc("entry",
Valu("mem", OpInitMem, TypeMem, 0, ".mem"),
Valu("mem", OpInitMem, TypeMem, 0, nil),
Goto("exit")),
Bloc("exit",
Exit("mem"))),
Fun(testConfig(t), "entry",
Bloc("entry",
Valu("mem", OpInitMem, TypeMem, 0, ".mem"),
Valu("mem", OpInitMem, TypeMem, 0, nil),
Exit("mem"))),
},
// value order changed
{
Fun(testConfig(t), "entry",
Bloc("entry",
Valu("mem", OpInitMem, TypeMem, 0, ".mem"),
Valu("mem", OpInitMem, TypeMem, 0, nil),
Valu("b", OpConst64, TypeInt64, 26, nil),
Valu("a", OpConst64, TypeInt64, 14, nil),
Exit("mem"))),
Fun(testConfig(t), "entry",
Bloc("entry",
Valu("mem", OpInitMem, TypeMem, 0, ".mem"),
Valu("mem", OpInitMem, TypeMem, 0, nil),
Valu("a", OpConst64, TypeInt64, 14, nil),
Valu("b", OpConst64, TypeInt64, 26, nil),
Exit("mem"))),
......@@ -366,12 +366,12 @@ func TestEquiv(t *testing.T) {
{
Fun(testConfig(t), "entry",
Bloc("entry",
Valu("mem", OpInitMem, TypeMem, 0, ".mem"),
Valu("mem", OpInitMem, TypeMem, 0, nil),
Valu("a", OpConst64, TypeInt64, 14, nil),
Exit("mem"))),
Fun(testConfig(t), "entry",
Bloc("entry",
Valu("mem", OpInitMem, TypeMem, 0, ".mem"),
Valu("mem", OpInitMem, TypeMem, 0, nil),
Valu("a", OpConst64, TypeInt64, 26, nil),
Exit("mem"))),
},
......@@ -379,12 +379,12 @@ func TestEquiv(t *testing.T) {
{
Fun(testConfig(t), "entry",
Bloc("entry",
Valu("mem", OpInitMem, TypeMem, 0, ".mem"),
Valu("mem", OpInitMem, TypeMem, 0, nil),
Valu("a", OpConst64, TypeInt64, 0, 14),
Exit("mem"))),
Fun(testConfig(t), "entry",
Bloc("entry",
Valu("mem", OpInitMem, TypeMem, 0, ".mem"),
Valu("mem", OpInitMem, TypeMem, 0, nil),
Valu("a", OpConst64, TypeInt64, 0, 26),
Exit("mem"))),
},
......@@ -392,14 +392,14 @@ func TestEquiv(t *testing.T) {
{
Fun(testConfig(t), "entry",
Bloc("entry",
Valu("mem", OpInitMem, TypeMem, 0, ".mem"),
Valu("mem", OpInitMem, TypeMem, 0, nil),
Valu("a", OpConst64, TypeInt64, 14, nil),
Valu("b", OpConst64, TypeInt64, 26, nil),
Valu("sum", OpAdd64, TypeInt64, 0, nil, "a", "b"),
Exit("mem"))),
Fun(testConfig(t), "entry",
Bloc("entry",
Valu("mem", OpInitMem, TypeMem, 0, ".mem"),
Valu("mem", OpInitMem, TypeMem, 0, nil),
Valu("a", OpConst64, TypeInt64, 0, nil),
Valu("b", OpConst64, TypeInt64, 14, nil),
Valu("sum", OpAdd64, TypeInt64, 0, nil, "b", "a"),
......
......@@ -148,10 +148,10 @@ var genericOps = []opData{
// for rotates is hashing and crypto code with constant
// distance, rotate instructions are only substituted
// when arg1 is a constant between 1 and A-1, inclusive.
{name: "Lrot8"},
{name: "Lrot16"},
{name: "Lrot32"},
{name: "Lrot64"},
{name: "Lrot8", aux: "Int64"},
{name: "Lrot16", aux: "Int64"},
{name: "Lrot32", aux: "Int64"},
{name: "Lrot64", aux: "Int64"},
// 2-input comparisons
{name: "Eq8"}, // arg0 == arg1
......@@ -247,46 +247,46 @@ var genericOps = []opData{
// constants. Constant values are stored in the aux or
// auxint fields.
{name: "ConstBool"}, // auxint is 0 for false and 1 for true
{name: "ConstString"}, // value is aux.(string)
{name: "ConstNil", typ: "BytePtr"}, // nil pointer
{name: "Const8"}, // value is low 8 bits of auxint
{name: "Const16"}, // value is low 16 bits of auxint
{name: "Const32"}, // value is low 32 bits of auxint
{name: "Const64"}, // value is auxint
{name: "Const32F"}, // value is math.Float64frombits(uint64(auxint))
{name: "Const64F"}, // value is math.Float64frombits(uint64(auxint))
{name: "ConstInterface"}, // nil interface
{name: "ConstSlice"}, // nil slice
{name: "ConstBool", aux: "Bool"}, // auxint is 0 for false and 1 for true
{name: "ConstString", aux: "String"}, // value is aux.(string)
{name: "ConstNil", typ: "BytePtr"}, // nil pointer
{name: "Const8", aux: "Int8"}, // value is low 8 bits of auxint
{name: "Const16", aux: "Int16"}, // value is low 16 bits of auxint
{name: "Const32", aux: "Int32"}, // value is low 32 bits of auxint
{name: "Const64", aux: "Int64"}, // value is auxint
{name: "Const32F", aux: "Float"}, // value is math.Float64frombits(uint64(auxint))
{name: "Const64F", aux: "Float"}, // value is math.Float64frombits(uint64(auxint))
{name: "ConstInterface"}, // nil interface
{name: "ConstSlice"}, // nil slice
// Constant-like things
{name: "InitMem"}, // memory input to the function.
{name: "Arg"}, // argument to the function. aux=GCNode of arg, off = offset in that arg.
{name: "InitMem"}, // memory input to the function.
{name: "Arg", aux: "SymOff"}, // argument to the function. aux=GCNode of arg, off = offset in that arg.
// The address of a variable. arg0 is the base pointer (SB or SP, depending
// on whether it is a global or stack variable). The Aux field identifies the
// variable. It will be either an *ExternSymbol (with arg0=SB), *ArgSymbol (arg0=SP),
// or *AutoSymbol (arg0=SP).
{name: "Addr"}, // Address of a variable. Arg0=SP or SB. Aux identifies the variable.
{name: "Addr", aux: "Sym"}, // Address of a variable. Arg0=SP or SB. Aux identifies the variable.
{name: "SP"}, // stack pointer
{name: "SB", typ: "Uintptr"}, // static base pointer (a.k.a. globals pointer)
{name: "Func"}, // entry address of a function
{name: "Func", aux: "Sym"}, // entry address of a function
// Memory operations
{name: "Load"}, // Load from arg0. arg1=memory
{name: "Store", typ: "Mem"}, // Store arg1 to arg0. arg2=memory, auxint=size. Returns memory.
{name: "Move"}, // arg0=destptr, arg1=srcptr, arg2=mem, auxint=size. Returns memory.
{name: "Zero"}, // arg0=destptr, arg1=mem, auxint=size. Returns memory.
{name: "Load"}, // Load from arg0. arg1=memory
{name: "Store", typ: "Mem", aux: "Int64"}, // Store arg1 to arg0. arg2=memory, auxint=size. Returns memory.
{name: "Move", aux: "Int64"}, // arg0=destptr, arg1=srcptr, arg2=mem, auxint=size. Returns memory.
{name: "Zero", aux: "Int64"}, // arg0=destptr, arg1=mem, auxint=size. Returns memory.
// Function calls. Arguments to the call have already been written to the stack.
// Return values appear on the stack. The method receiver, if any, is treated
// as a phantom first argument.
{name: "ClosureCall"}, // arg0=code pointer, arg1=context ptr, arg2=memory. auxint=arg size. Returns memory.
{name: "StaticCall"}, // call function aux.(*gc.Sym), arg0=memory. auxint=arg size. Returns memory.
{name: "DeferCall"}, // defer call. arg0=memory, auxint=arg size. Returns memory.
{name: "GoCall"}, // go call. arg0=memory, auxint=arg size. Returns memory.
{name: "InterCall"}, // interface call. arg0=code pointer, arg1=memory, auxint=arg size. Returns memory.
{name: "ClosureCall", aux: "Int64"}, // arg0=code pointer, arg1=context ptr, arg2=memory. auxint=arg size. Returns memory.
{name: "StaticCall", aux: "SymOff"}, // call function aux.(*gc.Sym), arg0=memory. auxint=arg size. Returns memory.
{name: "DeferCall", aux: "Int64"}, // defer call. arg0=memory, auxint=arg size. Returns memory.
{name: "GoCall", aux: "Int64"}, // go call. arg0=memory, auxint=arg size. Returns memory.
{name: "InterCall", aux: "Int64"}, // interface call. arg0=code pointer, arg1=memory, auxint=arg size. Returns memory.
// Conversions: signed extensions, zero (unsigned) extensions, truncations
{name: "SignExt8to16", typ: "Int16"},
......@@ -330,9 +330,9 @@ var genericOps = []opData{
{name: "GetClosurePtr"}, // get closure pointer from dedicated register
// Indexing operations
{name: "ArrayIndex"}, // arg0=array, arg1=index. Returns a[i]
{name: "PtrIndex"}, // arg0=ptr, arg1=index. Computes ptr+sizeof(*v.type)*index, where index is extended to ptrwidth type
{name: "OffPtr"}, // arg0 + auxint (arg0 and result are pointers)
{name: "ArrayIndex"}, // arg0=array, arg1=index. Returns a[i]
{name: "PtrIndex"}, // arg0=ptr, arg1=index. Computes ptr+sizeof(*v.type)*index, where index is extended to ptrwidth type
{name: "OffPtr", aux: "Int64"}, // arg0 + auxint (arg0 and result are pointers)
// Slices
{name: "SliceMake"}, // arg0=ptr, arg1=len, arg2=cap
......@@ -356,12 +356,12 @@ var genericOps = []opData{
{name: "IData"}, // arg0=interface, returns data field
// Structs
{name: "StructMake0"}, // Returns struct with 0 fields.
{name: "StructMake1"}, // arg0=field0. Returns struct.
{name: "StructMake2"}, // arg0,arg1=field0,field1. Returns struct.
{name: "StructMake3"}, // arg0..2=field0..2. Returns struct.
{name: "StructMake4"}, // arg0..3=field0..3. Returns struct.
{name: "StructSelect"}, // arg0=struct, auxint=field index. Returns the auxint'th field.
{name: "StructMake0"}, // Returns struct with 0 fields.
{name: "StructMake1"}, // arg0=field0. Returns struct.
{name: "StructMake2"}, // arg0,arg1=field0,field1. Returns struct.
{name: "StructMake3"}, // arg0..2=field0..2. Returns struct.
{name: "StructMake4"}, // arg0..3=field0..3. Returns struct.
{name: "StructSelect", aux: "Int64"}, // arg0=struct, auxint=field index. Returns the auxint'th field.
// Spill&restore ops for the register allocator. These are
// semantically identical to OpCopy; they do not take/return
......@@ -376,9 +376,9 @@ var genericOps = []opData{
// Unknown value. Used for Values whose values don't matter because they are dead code.
{name: "Unknown"},
{name: "VarDef", typ: "Mem"}, // aux is a *gc.Node of a variable that is about to be initialized. arg0=mem, returns mem
{name: "VarKill"}, // aux is a *gc.Node of a variable that is known to be dead. arg0=mem, returns mem
{name: "VarLive"}, // aux is a *gc.Node of a variable that must be kept live. arg0=mem, returns mem
{name: "VarDef", aux: "Sym", typ: "Mem"}, // aux is a *gc.Node of a variable that is about to be initialized. arg0=mem, returns mem
{name: "VarKill", aux: "Sym"}, // aux is a *gc.Node of a variable that is known to be dead. arg0=mem, returns mem
{name: "VarLive", aux: "Sym"}, // aux is a *gc.Node of a variable that must be kept live. arg0=mem, returns mem
}
// kind control successors implicit exit
......
......@@ -26,10 +26,12 @@ type arch struct {
}
type opData struct {
name string
reg regInfo
asm string
typ string // default result type
name string
reg regInfo
asm string
typ string // default result type
aux string
rematerializeable bool
}
type blockData struct {
......@@ -117,6 +119,17 @@ func genOp() {
for _, v := range a.ops {
fmt.Fprintln(w, "{")
fmt.Fprintf(w, "name:\"%s\",\n", v.name)
// flags
if v.aux != "" {
fmt.Fprintf(w, "auxType: aux%s,\n", v.aux)
}
if v.rematerializeable {
if v.reg.clobbers != 0 {
log.Fatalf("%s is rematerializeable and clobbers registers", v.name)
}
fmt.Fprintln(w, "rematerializeable: true,")
}
if a.name == "generic" {
fmt.Fprintln(w, "generic:true,")
fmt.Fprintln(w, "},") // close op
......
......@@ -21,7 +21,7 @@ func benchmarkNilCheckDeep(b *testing.B, depth int) {
var blocs []bloc
blocs = append(blocs,
Bloc("entry",
Valu("mem", OpInitMem, TypeMem, 0, ".mem"),
Valu("mem", OpInitMem, TypeMem, 0, nil),
Valu("sb", OpSB, TypeInvalid, 0, nil),
Goto(blockn(0)),
),
......@@ -67,7 +67,7 @@ func TestNilcheckSimple(t *testing.T) {
c := NewConfig("amd64", DummyFrontend{t}, nil, true)
fun := Fun(c, "entry",
Bloc("entry",
Valu("mem", OpInitMem, TypeMem, 0, ".mem"),
Valu("mem", OpInitMem, TypeMem, 0, nil),
Valu("sb", OpSB, TypeInvalid, 0, nil),
Goto("checkPtr")),
Bloc("checkPtr",
......@@ -104,7 +104,7 @@ func TestNilcheckDomOrder(t *testing.T) {
c := NewConfig("amd64", DummyFrontend{t}, nil, true)
fun := Fun(c, "entry",
Bloc("entry",
Valu("mem", OpInitMem, TypeMem, 0, ".mem"),
Valu("mem", OpInitMem, TypeMem, 0, nil),
Valu("sb", OpSB, TypeInvalid, 0, nil),
Goto("checkPtr")),
Bloc("checkPtr",
......@@ -140,7 +140,7 @@ func TestNilcheckAddr(t *testing.T) {
c := NewConfig("amd64", DummyFrontend{t}, nil, true)
fun := Fun(c, "entry",
Bloc("entry",
Valu("mem", OpInitMem, TypeMem, 0, ".mem"),
Valu("mem", OpInitMem, TypeMem, 0, nil),
Valu("sb", OpSB, TypeInvalid, 0, nil),
Goto("checkPtr")),
Bloc("checkPtr",
......@@ -173,7 +173,7 @@ func TestNilcheckAddPtr(t *testing.T) {
c := NewConfig("amd64", DummyFrontend{t}, nil, true)
fun := Fun(c, "entry",
Bloc("entry",
Valu("mem", OpInitMem, TypeMem, 0, ".mem"),
Valu("mem", OpInitMem, TypeMem, 0, nil),
Valu("sb", OpSB, TypeInvalid, 0, nil),
Goto("checkPtr")),
Bloc("checkPtr",
......@@ -207,7 +207,7 @@ func TestNilcheckPhi(t *testing.T) {
c := NewConfig("amd64", DummyFrontend{t}, nil, true)
fun := Fun(c, "entry",
Bloc("entry",
Valu("mem", OpInitMem, TypeMem, 0, ".mem"),
Valu("mem", OpInitMem, TypeMem, 0, nil),
Valu("sb", OpSB, TypeInvalid, 0, nil),
Valu("sp", OpSP, TypeInvalid, 0, nil),
Valu("baddr", OpAddr, TypeBool, 0, "b", "sp"),
......@@ -251,7 +251,7 @@ func TestNilcheckKeepRemove(t *testing.T) {
c := NewConfig("amd64", DummyFrontend{t}, nil, true)
fun := Fun(c, "entry",
Bloc("entry",
Valu("mem", OpInitMem, TypeMem, 0, ".mem"),
Valu("mem", OpInitMem, TypeMem, 0, nil),
Valu("sb", OpSB, TypeInvalid, 0, nil),
Goto("checkPtr")),
Bloc("checkPtr",
......@@ -299,7 +299,7 @@ func TestNilcheckInFalseBranch(t *testing.T) {
c := NewConfig("amd64", DummyFrontend{t}, nil, true)
fun := Fun(c, "entry",
Bloc("entry",
Valu("mem", OpInitMem, TypeMem, 0, ".mem"),
Valu("mem", OpInitMem, TypeMem, 0, nil),
Valu("sb", OpSB, TypeInvalid, 0, nil),
Goto("checkPtr")),
Bloc("checkPtr",
......@@ -350,7 +350,7 @@ func TestNilcheckUser(t *testing.T) {
c := NewConfig("amd64", DummyFrontend{t}, nil, true)
fun := Fun(c, "entry",
Bloc("entry",
Valu("mem", OpInitMem, TypeMem, 0, ".mem"),
Valu("mem", OpInitMem, TypeMem, 0, nil),
Valu("sb", OpSB, TypeInvalid, 0, nil),
Goto("checkPtr")),
Bloc("checkPtr",
......@@ -389,7 +389,7 @@ func TestNilcheckBug(t *testing.T) {
c := NewConfig("amd64", DummyFrontend{t}, nil, true)
fun := Fun(c, "entry",
Bloc("entry",
Valu("mem", OpInitMem, TypeMem, 0, ".mem"),
Valu("mem", OpInitMem, TypeMem, 0, nil),
Valu("sb", OpSB, TypeInvalid, 0, nil),
Goto("checkPtr")),
Bloc("checkPtr",
......
......@@ -15,10 +15,12 @@ import "fmt"
type Op int32
type opInfo struct {
name string
asm int
reg regInfo
generic bool // this is a generic (arch-independent) opcode
name string
asm int
reg regInfo
auxType auxType
generic bool // this is a generic (arch-independent) opcode
rematerializeable bool // this op is rematerializeable
}
type inputInfo struct {
......@@ -32,6 +34,22 @@ type regInfo struct {
outputs []regMask // NOTE: values can only have 1 output for now.
}
type auxType int8
const (
auxNone auxType = iota
auxBool // auxInt is 0/1 for false/true
auxInt8 // auxInt is an 8-bit integer
auxInt16 // auxInt is a 16-bit integer
auxInt32 // auxInt is a 32-bit integer
auxInt64 // auxInt is a 64-bit integer
auxFloat // auxInt is a float64 (encoded with math.Float64bits)
auxString // auxInt is a string
auxSym // aux is a symbol
auxSymOff // aux is a symbol, auxInt is an offset
auxSymValAndOff // aux is a symbol, auxInt is a ValAndOff
)
// A ValAndOff is used by the several opcodes. It holds
// both a value and a pointer offset.
// A ValAndOff is intended to be encoded into an AuxInt field.
......
This diff is collapsed.
......@@ -68,7 +68,7 @@ func genFunction(size int) []bloc {
valn := func(s string, m, n int) string { return fmt.Sprintf("%s%d-%d", s, m, n) }
blocs = append(blocs,
Bloc("entry",
Valu(valn("store", 0, 4), OpArg, TypeMem, 0, ".mem"),
Valu(valn("store", 0, 4), OpInitMem, TypeMem, 0, nil),
Valu("sb", OpSB, TypeInvalid, 0, nil),
Goto(blockn(1)),
),
......
......@@ -1481,31 +1481,16 @@ func (e *edgeState) findRegFor(typ Type) Location {
}
func (v *Value) rematerializeable() bool {
// TODO: add a flags field to opInfo for this test?
regspec := opcodeTable[v.Op].reg
// rematerializeable ops must be able to fill any register.
outputs := regspec.outputs
if len(outputs) == 0 || countRegs(outputs[0]) <= 1 {
// Note: this case handles OpAMD64LoweredGetClosurePtr
// which can't be moved.
if !opcodeTable[v.Op].rematerializeable {
return false
}
// We can't rematerialize instructions which
// clobber the flags register.
if regspec.clobbers&flagRegMask != 0 {
return false
}
if len(v.Args) == 0 {
return true
}
if len(v.Args) == 1 && (v.Args[0].Op == OpSP || v.Args[0].Op == OpSB) {
for _, a := range v.Args {
// SP and SB (generated by OpSP and OpSB) are always available.
return true
if a.Op != OpSP && a.Op != OpSB {
return false
}
}
return false
return true
}
type liveInfo struct {
......
......@@ -10,9 +10,9 @@ func TestLiveControlOps(t *testing.T) {
c := testConfig(t)
f := Fun(c, "entry",
Bloc("entry",
Valu("mem", OpInitMem, TypeMem, 0, ".mem"),
Valu("x", OpAMD64MOVBconst, TypeInt8, 0, 1),
Valu("y", OpAMD64MOVBconst, TypeInt8, 0, 2),
Valu("mem", OpInitMem, TypeMem, 0, nil),
Valu("x", OpAMD64MOVBconst, TypeInt8, 1, nil),
Valu("y", OpAMD64MOVBconst, TypeInt8, 2, nil),
Valu("a", OpAMD64TESTB, TypeFlags, 0, nil, "x", "y"),
Valu("b", OpAMD64TESTB, TypeFlags, 0, nil, "y", "x"),
Eq("a", "if", "exit"),
......
......@@ -11,7 +11,7 @@ func TestSchedule(t *testing.T) {
cases := []fun{
Fun(c, "entry",
Bloc("entry",
Valu("mem0", OpInitMem, TypeMem, 0, ".mem"),
Valu("mem0", OpInitMem, TypeMem, 0, nil),
Valu("ptr", OpConst64, TypeInt64, 0xABCD, nil),
Valu("v", OpConst64, TypeInt64, 12, nil),
Valu("mem1", OpStore, TypeMem, 8, nil, "ptr", "v", "mem0"),
......
......@@ -34,7 +34,7 @@ func makeConstShiftFunc(c *Config, amount int64, op Op, typ Type) fun {
ptyp := &TypeImpl{Size_: 8, Ptr: true, Name: "ptr"}
fun := Fun(c, "entry",
Bloc("entry",
Valu("mem", OpInitMem, TypeMem, 0, ".mem"),
Valu("mem", OpInitMem, TypeMem, 0, nil),
Valu("SP", OpSP, TypeUInt64, 0, nil),
Valu("argptr", OpOffPtr, ptyp, 8, nil, "SP"),
Valu("resptr", OpOffPtr, ptyp, 16, nil, "SP"),
......
......@@ -11,7 +11,7 @@ func TestShortCircuit(t *testing.T) {
fun := Fun(c, "entry",
Bloc("entry",
Valu("mem", OpInitMem, TypeMem, 0, ".mem"),
Valu("mem", OpInitMem, TypeMem, 0, nil),
Valu("arg1", OpArg, TypeInt64, 0, nil),
Valu("arg2", OpArg, TypeInt64, 0, nil),
Valu("arg3", OpArg, TypeInt64, 0, nil),
......
......@@ -57,34 +57,72 @@ func (v *Value) String() string {
return fmt.Sprintf("v%d", v.ID)
}
func (v *Value) AuxInt8() int8 {
if opcodeTable[v.Op].auxType != auxInt8 {
v.Fatalf("op %s doesn't have an int8 aux field", v.Op)
}
return int8(v.AuxInt)
}
func (v *Value) AuxInt16() int16 {
if opcodeTable[v.Op].auxType != auxInt16 {
v.Fatalf("op %s doesn't have an int16 aux field", v.Op)
}
return int16(v.AuxInt)
}
func (v *Value) AuxInt32() int32 {
if opcodeTable[v.Op].auxType != auxInt32 {
v.Fatalf("op %s doesn't have an int32 aux field", v.Op)
}
return int32(v.AuxInt)
}
func (v *Value) AuxFloat() float64 {
if opcodeTable[v.Op].auxType != auxFloat {
v.Fatalf("op %s doesn't have a float aux field", v.Op)
}
return math.Float64frombits(uint64(v.AuxInt))
}
func (v *Value) AuxValAndOff() ValAndOff {
if opcodeTable[v.Op].auxType != auxSymValAndOff {
v.Fatalf("op %s doesn't have a ValAndOff aux field", v.Op)
}
return ValAndOff(v.AuxInt)
}
// long form print. v# = opcode <type> [aux] args [: reg]
func (v *Value) LongString() string {
s := fmt.Sprintf("v%d = %s", v.ID, v.Op.String())
s += " <" + v.Type.String() + ">"
// TODO: use some operator property flags to decide
// what is encoded in the AuxInt field.
switch v.Op {
case OpConst32F, OpConst64F:
s += fmt.Sprintf(" [%g]", math.Float64frombits(uint64(v.AuxInt)))
case OpConstBool:
switch opcodeTable[v.Op].auxType {
case auxBool:
if v.AuxInt == 0 {
s += " [false]"
} else {
s += " [true]"
}
case OpAMD64MOVBstoreconst, OpAMD64MOVWstoreconst, OpAMD64MOVLstoreconst, OpAMD64MOVQstoreconst:
s += fmt.Sprintf(" [%s]", ValAndOff(v.AuxInt))
default:
if v.AuxInt != 0 {
s += fmt.Sprintf(" [%d]", v.AuxInt)
case auxInt8:
s += fmt.Sprintf(" [%d]", v.AuxInt8())
case auxInt16:
s += fmt.Sprintf(" [%d]", v.AuxInt16())
case auxInt32:
s += fmt.Sprintf(" [%d]", v.AuxInt32())
case auxInt64:
s += fmt.Sprintf(" [%d]", v.AuxInt)
case auxFloat:
s += fmt.Sprintf(" [%g]", v.AuxFloat())
case auxString:
s += fmt.Sprintf(" {%s}", v.Aux)
case auxSymOff:
if v.Aux != nil {
s += fmt.Sprintf(" {%s}", v.Aux)
}
}
if v.Aux != nil {
if _, ok := v.Aux.(string); ok {
s += fmt.Sprintf(" {%q}", v.Aux)
} else {
s += fmt.Sprintf(" {%v}", v.Aux)
s += fmt.Sprintf(" [%s]", v.AuxInt)
case auxSymValAndOff:
if v.Aux != nil {
s += fmt.Sprintf(" {%s}", v.Aux)
}
s += fmt.Sprintf(" [%s]", v.AuxValAndOff())
}
for _, a := range v.Args {
s += fmt.Sprintf(" %v", a)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment