Commit 65677cab authored by Keith Randall's avatar Keith Randall

[dev.ssa] cmd/compile/internal/ssa: allow ops to have a default type

Specifying types in rewrites for all subexpressions gets verbose
quickly.  Allow opcodes to specify a default type which is used when
none is supplied explicitly.

Provide default types for a few easy opcodes.  There are probably more
we can do, but this is a good start.

Change-Id: Iedc2a1a423cc3e2d4472640433982f9aa76a9f18
Reviewed-on: https://go-review.googlesource.com/14128Reviewed-by: 's avatarJosh Bleecher Snyder <josharian@gmail.com>
parent a0022d9b
......@@ -241,26 +241,26 @@ func init() {
{name: "XORWconst", reg: gp11, asm: "XORW"}, // arg0 ^ auxint
{name: "XORBconst", reg: gp11, asm: "XORB"}, // arg0 ^ auxint
{name: "CMPQ", reg: gp2flags, asm: "CMPQ"}, // arg0 compare to arg1
{name: "CMPL", reg: gp2flags, asm: "CMPL"}, // arg0 compare to arg1
{name: "CMPW", reg: gp2flags, asm: "CMPW"}, // arg0 compare to arg1
{name: "CMPB", reg: gp2flags, asm: "CMPB"}, // arg0 compare to arg1
{name: "CMPQconst", reg: gp1flags, asm: "CMPQ"}, // arg0 compare to auxint
{name: "CMPLconst", reg: gp1flags, asm: "CMPL"}, // arg0 compare to auxint
{name: "CMPWconst", reg: gp1flags, asm: "CMPW"}, // arg0 compare to auxint
{name: "CMPBconst", reg: gp1flags, asm: "CMPB"}, // arg0 compare to auxint
{name: "UCOMISS", reg: fp2flags, asm: "UCOMISS"}, // arg0 compare to arg1, f32
{name: "UCOMISD", reg: fp2flags, asm: "UCOMISD"}, // arg0 compare to arg1, f64
{name: "TESTQ", reg: gp2flags, asm: "TESTQ"}, // (arg0 & arg1) compare to 0
{name: "TESTL", reg: gp2flags, asm: "TESTL"}, // (arg0 & arg1) compare to 0
{name: "TESTW", reg: gp2flags, asm: "TESTW"}, // (arg0 & arg1) compare to 0
{name: "TESTB", reg: gp2flags, asm: "TESTB"}, // (arg0 & arg1) compare to 0
{name: "TESTQconst", reg: gp1flags, asm: "TESTQ"}, // (arg0 & auxint) compare to 0
{name: "TESTLconst", reg: gp1flags, asm: "TESTL"}, // (arg0 & auxint) compare to 0
{name: "TESTWconst", reg: gp1flags, asm: "TESTW"}, // (arg0 & auxint) compare to 0
{name: "TESTBconst", reg: gp1flags, asm: "TESTB"}, // (arg0 & auxint) compare to 0
{name: "CMPQ", reg: gp2flags, asm: "CMPQ", typ: "Flags"}, // arg0 compare to arg1
{name: "CMPL", reg: gp2flags, asm: "CMPL", typ: "Flags"}, // arg0 compare to arg1
{name: "CMPW", reg: gp2flags, asm: "CMPW", typ: "Flags"}, // arg0 compare to arg1
{name: "CMPB", reg: gp2flags, asm: "CMPB", typ: "Flags"}, // arg0 compare to arg1
{name: "CMPQconst", reg: gp1flags, asm: "CMPQ", typ: "Flags"}, // arg0 compare to auxint
{name: "CMPLconst", reg: gp1flags, asm: "CMPL", typ: "Flags"}, // arg0 compare to auxint
{name: "CMPWconst", reg: gp1flags, asm: "CMPW", typ: "Flags"}, // arg0 compare to auxint
{name: "CMPBconst", reg: gp1flags, asm: "CMPB", typ: "Flags"}, // arg0 compare to auxint
{name: "UCOMISS", reg: fp2flags, asm: "UCOMISS", typ: "Flags"}, // arg0 compare to arg1, f32
{name: "UCOMISD", reg: fp2flags, asm: "UCOMISD", typ: "Flags"}, // arg0 compare to arg1, f64
{name: "TESTQ", reg: gp2flags, asm: "TESTQ", typ: "Flags"}, // (arg0 & arg1) compare to 0
{name: "TESTL", reg: gp2flags, asm: "TESTL", typ: "Flags"}, // (arg0 & arg1) compare to 0
{name: "TESTW", reg: gp2flags, asm: "TESTW", typ: "Flags"}, // (arg0 & arg1) compare to 0
{name: "TESTB", reg: gp2flags, asm: "TESTB", typ: "Flags"}, // (arg0 & arg1) compare to 0
{name: "TESTQconst", reg: gp1flags, asm: "TESTQ", typ: "Flags"}, // (arg0 & auxint) compare to 0
{name: "TESTLconst", reg: gp1flags, asm: "TESTL", typ: "Flags"}, // (arg0 & auxint) compare to 0
{name: "TESTWconst", reg: gp1flags, asm: "TESTW", typ: "Flags"}, // (arg0 & auxint) compare to 0
{name: "TESTBconst", reg: gp1flags, asm: "TESTB", typ: "Flags"}, // (arg0 & auxint) compare to 0
{name: "SHLQ", reg: gp21shift, asm: "SHLQ"}, // arg0 << arg1, shift amount is mod 64
{name: "SHLL", reg: gp21shift, asm: "SHLL"}, // arg0 << arg1, shift amount is mod 32
......
......@@ -65,13 +65,13 @@
(EqFat x y) && x.Op == OpConstNil && y.Op != OpConstNil -> (EqFat y x)
(NeqFat x y) && x.Op == OpConstNil && y.Op != OpConstNil -> (NeqFat y x)
// it suffices to check the first word (backing array for slices, dynamic type for interfaces)
(EqFat (Load ptr mem) (ConstNil)) -> (EqPtr (Load <config.fe.TypeUintptr()> ptr mem) (ConstPtr <config.fe.TypeUintptr()> [0]))
(NeqFat (Load ptr mem) (ConstNil)) -> (NeqPtr (Load <config.fe.TypeUintptr()> ptr mem) (ConstPtr <config.fe.TypeUintptr()> [0]))
(EqFat (Load ptr mem) (ConstNil)) -> (EqPtr (Load <config.fe.TypeUintptr()> ptr mem) (ConstPtr [0]))
(NeqFat (Load ptr mem) (ConstNil)) -> (NeqPtr (Load <config.fe.TypeUintptr()> ptr mem) (ConstPtr [0]))
// indexing operations
// Note: bounds check has already been done
(ArrayIndex (Load ptr mem) idx) -> (Load (PtrIndex <v.Type.PtrTo()> ptr idx) mem)
(PtrIndex <t> ptr idx) -> (AddPtr ptr (MulPtr <config.fe.TypeUintptr()> idx (ConstPtr <config.fe.TypeUintptr()> [t.Elem().Size()])))
(PtrIndex <t> ptr idx) -> (AddPtr ptr (MulPtr idx (ConstPtr [t.Elem().Size()])))
(StructSelect [idx] (Load ptr mem)) -> (Load (OffPtr <v.Type.PtrTo()> [idx] ptr) mem)
// complex ops
......@@ -89,7 +89,7 @@
(Store [4]
(OffPtr <config.fe.TypeFloat32().PtrTo()> [4] dst)
imag
(Store <TypeMem> [4] dst real mem))
(Store [4] dst real mem))
(Load <t> ptr mem) && t.IsComplex() && t.Size() == 16 ->
(ComplexMake
......@@ -102,7 +102,7 @@
(Store [8]
(OffPtr <config.fe.TypeFloat64().PtrTo()> [8] dst)
imag
(Store <TypeMem> [8] dst real mem))
(Store [8] dst real mem))
// string ops
(StringPtr (StringMake ptr _)) -> ptr
......@@ -110,8 +110,8 @@
(ConstString {s}) ->
(StringMake
(Addr <config.fe.TypeBytePtr()> {config.fe.StringData(s.(string))}
(SB <config.fe.TypeUintptr()>))
(ConstPtr <config.fe.TypeUintptr()> [int64(len(s.(string)))]))
(SB))
(ConstPtr [int64(len(s.(string)))]))
(Load <t> ptr mem) && t.IsString() ->
(StringMake
(Load <config.fe.TypeBytePtr()> ptr mem)
......@@ -122,7 +122,7 @@
(Store [config.PtrSize]
(OffPtr <config.fe.TypeUintptr().PtrTo()> [config.PtrSize] dst)
len
(Store <TypeMem> [config.PtrSize] dst ptr mem))
(Store [config.PtrSize] dst ptr mem))
// slice ops
(SlicePtr (SliceMake ptr _ _ )) -> ptr
......@@ -131,8 +131,8 @@
(ConstSlice) ->
(SliceMake
(ConstNil <config.fe.TypeBytePtr()>)
(ConstPtr <config.fe.TypeUintptr()>)
(ConstPtr <config.fe.TypeUintptr()>))
(ConstPtr [0])
(ConstPtr [0]))
(Load <t> ptr mem) && t.IsSlice() ->
(SliceMake
......@@ -147,10 +147,10 @@
(Store [config.PtrSize]
(OffPtr <config.fe.TypeUintptr().PtrTo()> [2*config.PtrSize] dst)
cap
(Store <TypeMem> [config.PtrSize]
(Store [config.PtrSize]
(OffPtr <config.fe.TypeUintptr().PtrTo()> [config.PtrSize] dst)
len
(Store <TypeMem> [config.PtrSize] dst ptr mem)))
(Store [config.PtrSize] dst ptr mem)))
// interface ops
(ITab (IMake itab _)) -> itab
......@@ -169,7 +169,7 @@
(Store [config.PtrSize]
(OffPtr <config.fe.TypeBytePtr().PtrTo()> [config.PtrSize] dst)
data
(Store <TypeMem> [config.PtrSize] dst itab mem))
(Store [config.PtrSize] dst itab mem))
// big-object moves (TODO: remove?)
(Store [size] dst (Load src mem) mem) && size > config.IntSize -> (Move [size] dst src mem)
......
......@@ -30,7 +30,7 @@ var genericOps = []opData{
{name: "Mul16"},
{name: "Mul32"},
{name: "Mul64"},
{name: "MulPtr"}, // MulPtr is used for address calculations
{name: "MulPtr", typ: "Uintptr"}, // MulPtr is used for address calculations
{name: "Mul32F"},
{name: "Mul64F"},
......@@ -250,9 +250,9 @@ var genericOps = []opData{
{name: "Const64"},
{name: "Const32F"},
{name: "Const64F"},
{name: "ConstPtr"}, // pointer-sized integer constant
{name: "ConstInterface"}, // nil interface
{name: "ConstSlice"}, // nil slice
{name: "ConstPtr", typ: "Uintptr"}, // pointer-sized integer constant
{name: "ConstInterface"}, // nil interface
{name: "ConstSlice"}, // nil slice
// TODO: Const32F, ...
// Constant-like things
......@@ -264,15 +264,15 @@ var genericOps = []opData{
// or *AutoSymbol (arg0=SP).
{name: "Addr"}, // Address of a variable. Arg0=SP or SB. Aux identifies the variable.
{name: "SP"}, // stack pointer
{name: "SB"}, // static base pointer (a.k.a. globals pointer)
{name: "Func"}, // entry address of a function
{name: "SP"}, // stack pointer
{name: "SB", typ: "Uintptr"}, // static base pointer (a.k.a. globals pointer)
{name: "Func"}, // entry address of a function
// Memory operations
{name: "Load"}, // Load from arg0. arg1=memory
{name: "Store"}, // 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"}, // 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.
// 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
......@@ -281,13 +281,13 @@ var genericOps = []opData{
{name: "StaticCall"}, // call function aux.(*gc.Sym), arg0=memory. Returns memory.
// Conversions: signed extensions, zero (unsigned) extensions, truncations
{name: "SignExt8to16"},
{name: "SignExt8to16", typ: "Int16"},
{name: "SignExt8to32"},
{name: "SignExt8to64"},
{name: "SignExt16to32"},
{name: "SignExt16to64"},
{name: "SignExt32to64"},
{name: "ZeroExt8to16"},
{name: "ZeroExt8to16", typ: "UInt16"},
{name: "ZeroExt8to32"},
{name: "ZeroExt8to64"},
{name: "ZeroExt16to32"},
......
......@@ -29,6 +29,7 @@ type opData struct {
name string
reg regInfo
asm string
typ string // default result type
}
type blockData struct {
......
......@@ -459,7 +459,24 @@ func genResult0(w io.Writer, arch arch, result string, alloc *int, top bool) str
}
}
if !hasType {
log.Fatalf("sub-expression %s must have a type", result)
// find default type, if any
for _, op := range arch.ops {
if op.name != s[0] || op.typ == "" || hasType {
continue
}
fmt.Fprintf(w, "%s.Type = %s\n", v, typeName(op.typ))
hasType = true
}
for _, op := range genericOps {
if op.name != s[0] || op.typ == "" || hasType {
continue
}
fmt.Fprintf(w, "%s.Type = %s\n", v, typeName(op.typ))
hasType = true
}
}
if !hasType {
log.Fatalf("sub-expression %s (op=%s) must have a type", result, s[0])
}
return v
}
......@@ -547,6 +564,16 @@ func blockName(name string, arch arch) string {
return "Block" + arch.name + name
}
// typeName returns the string to use to generate a type.
func typeName(typ string) string {
switch typ {
case "Flags", "Mem":
return "Type" + typ
default:
return "config.fe.Type" + typ + "()"
}
}
// unbalanced returns true if there aren't the same number of ( and ) in the string.
func unbalanced(s string) bool {
var left, right int
......
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