mirror of
https://github.com/golang/go
synced 2024-10-06 09:11:21 -06:00
[dev.ssa] cmd/internal/ssa: SSA cleanups
Mostly suggested by Alan. Convert Const* ops to just one Const op. Use more of go/types. Get rid of typers, all types must be specified explicitly. Change-Id: Id4758f2b887d8a6888e88a7e047d97af55e34b62 Reviewed-on: https://go-review.googlesource.com/8110 Reviewed-by: Alan Donovan <adonovan@google.com>
This commit is contained in:
parent
7b96284295
commit
2c9b491e01
@ -54,6 +54,7 @@ const (
|
|||||||
BlockPlain // a single successor
|
BlockPlain // a single successor
|
||||||
BlockIf // 2 successors, if control goto Succs[0] else goto Succs[1]
|
BlockIf // 2 successors, if control goto Succs[0] else goto Succs[1]
|
||||||
BlockCall // 2 successors, normal return and panic
|
BlockCall // 2 successors, normal return and panic
|
||||||
|
// TODO(khr): BlockPanic for the built-in panic call, has 1 edge to the exit block
|
||||||
BlockUnknown
|
BlockUnknown
|
||||||
|
|
||||||
// 386/amd64 variants of BlockIf that take the flags register as an arg
|
// 386/amd64 variants of BlockIf that take the flags register as an arg
|
||||||
|
@ -79,7 +79,7 @@ var passOrder = map[string]string{
|
|||||||
// regalloc requires all the values in a block to be scheduled
|
// regalloc requires all the values in a block to be scheduled
|
||||||
//"schedule": "regalloc",
|
//"schedule": "regalloc",
|
||||||
// code generation requires register allocation
|
// code generation requires register allocation
|
||||||
//"cgen":"regalloc",
|
//"regalloc": "cgen",
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -20,7 +20,7 @@ func deadcode(f *Func) {
|
|||||||
|
|
||||||
// constant-fold conditionals
|
// constant-fold conditionals
|
||||||
// TODO: rewrite rules instead?
|
// TODO: rewrite rules instead?
|
||||||
if b.Kind == BlockIf && b.Control.Op == OpConstBool {
|
if b.Kind == BlockIf && b.Control.Op == OpConst {
|
||||||
cond := b.Control.Aux.(bool)
|
cond := b.Control.Aux.(bool)
|
||||||
var c *Block
|
var c *Block
|
||||||
if cond {
|
if cond {
|
||||||
|
@ -57,5 +57,5 @@ func (b *Block) NewValue(op Op, t Type, aux interface{}) *Value {
|
|||||||
func (f *Func) ConstInt(c int64) *Value {
|
func (f *Func) ConstInt(c int64) *Value {
|
||||||
// TODO: cache?
|
// TODO: cache?
|
||||||
// TODO: different types?
|
// TODO: different types?
|
||||||
return f.Entry.NewValue(OpConstInt, TypeInt, c)
|
return f.Entry.NewValue(OpConst, TypeInt64, c)
|
||||||
}
|
}
|
||||||
|
@ -5,23 +5,23 @@ package ssa
|
|||||||
func genericRules(v *Value) bool {
|
func genericRules(v *Value) bool {
|
||||||
switch v.Op {
|
switch v.Op {
|
||||||
case OpAdd:
|
case OpAdd:
|
||||||
// match: (Add <t> (ConstInt [c]) (ConstInt [d]))
|
// match: (Add <t> (Const [c]) (Const [d]))
|
||||||
// cond: is64BitInt(t)
|
// cond: is64BitInt(t) && isSigned(t)
|
||||||
// result: (ConstInt [{c.(int64)+d.(int64)}])
|
// result: (Const [{c.(int64)+d.(int64)}])
|
||||||
{
|
{
|
||||||
t := v.Type
|
t := v.Type
|
||||||
if v.Args[0].Op != OpConstInt {
|
if v.Args[0].Op != OpConst {
|
||||||
goto end0
|
goto end0
|
||||||
}
|
}
|
||||||
c := v.Args[0].Aux
|
c := v.Args[0].Aux
|
||||||
if v.Args[1].Op != OpConstInt {
|
if v.Args[1].Op != OpConst {
|
||||||
goto end0
|
goto end0
|
||||||
}
|
}
|
||||||
d := v.Args[1].Aux
|
d := v.Args[1].Aux
|
||||||
if !(is64BitInt(t)) {
|
if !(is64BitInt(t) && isSigned(t)) {
|
||||||
goto end0
|
goto end0
|
||||||
}
|
}
|
||||||
v.Op = OpConstInt
|
v.Op = OpConst
|
||||||
v.Aux = nil
|
v.Aux = nil
|
||||||
v.Args = v.argstorage[:0]
|
v.Args = v.argstorage[:0]
|
||||||
v.Aux = c.(int64) + d.(int64)
|
v.Aux = c.(int64) + d.(int64)
|
||||||
@ -29,13 +29,37 @@ func genericRules(v *Value) bool {
|
|||||||
}
|
}
|
||||||
end0:
|
end0:
|
||||||
;
|
;
|
||||||
|
// match: (Add <t> (Const [c]) (Const [d]))
|
||||||
|
// cond: is64BitInt(t) && !isSigned(t)
|
||||||
|
// result: (Const [{c.(uint64)+d.(uint64)}])
|
||||||
|
{
|
||||||
|
t := v.Type
|
||||||
|
if v.Args[0].Op != OpConst {
|
||||||
|
goto end1
|
||||||
|
}
|
||||||
|
c := v.Args[0].Aux
|
||||||
|
if v.Args[1].Op != OpConst {
|
||||||
|
goto end1
|
||||||
|
}
|
||||||
|
d := v.Args[1].Aux
|
||||||
|
if !(is64BitInt(t) && !isSigned(t)) {
|
||||||
|
goto end1
|
||||||
|
}
|
||||||
|
v.Op = OpConst
|
||||||
|
v.Aux = nil
|
||||||
|
v.Args = v.argstorage[:0]
|
||||||
|
v.Aux = c.(uint64) + d.(uint64)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
end1:
|
||||||
|
;
|
||||||
case OpLoad:
|
case OpLoad:
|
||||||
// match: (Load (FPAddr [offset]) mem)
|
// match: (Load (FPAddr [offset]) mem)
|
||||||
// cond:
|
// cond:
|
||||||
// result: (LoadFP [offset] mem)
|
// result: (LoadFP [offset] mem)
|
||||||
{
|
{
|
||||||
if v.Args[0].Op != OpFPAddr {
|
if v.Args[0].Op != OpFPAddr {
|
||||||
goto end1
|
goto end2
|
||||||
}
|
}
|
||||||
offset := v.Args[0].Aux
|
offset := v.Args[0].Aux
|
||||||
mem := v.Args[1]
|
mem := v.Args[1]
|
||||||
@ -46,14 +70,14 @@ func genericRules(v *Value) bool {
|
|||||||
v.AddArg(mem)
|
v.AddArg(mem)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
end1:
|
end2:
|
||||||
;
|
;
|
||||||
// match: (Load (SPAddr [offset]) mem)
|
// match: (Load (SPAddr [offset]) mem)
|
||||||
// cond:
|
// cond:
|
||||||
// result: (LoadSP [offset] mem)
|
// result: (LoadSP [offset] mem)
|
||||||
{
|
{
|
||||||
if v.Args[0].Op != OpSPAddr {
|
if v.Args[0].Op != OpSPAddr {
|
||||||
goto end2
|
goto end3
|
||||||
}
|
}
|
||||||
offset := v.Args[0].Aux
|
offset := v.Args[0].Aux
|
||||||
mem := v.Args[1]
|
mem := v.Args[1]
|
||||||
@ -64,7 +88,7 @@ func genericRules(v *Value) bool {
|
|||||||
v.AddArg(mem)
|
v.AddArg(mem)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
end2:
|
end3:
|
||||||
;
|
;
|
||||||
case OpStore:
|
case OpStore:
|
||||||
// match: (Store (FPAddr [offset]) val mem)
|
// match: (Store (FPAddr [offset]) val mem)
|
||||||
@ -72,7 +96,7 @@ func genericRules(v *Value) bool {
|
|||||||
// result: (StoreFP [offset] val mem)
|
// result: (StoreFP [offset] val mem)
|
||||||
{
|
{
|
||||||
if v.Args[0].Op != OpFPAddr {
|
if v.Args[0].Op != OpFPAddr {
|
||||||
goto end3
|
goto end4
|
||||||
}
|
}
|
||||||
offset := v.Args[0].Aux
|
offset := v.Args[0].Aux
|
||||||
val := v.Args[1]
|
val := v.Args[1]
|
||||||
@ -85,14 +109,14 @@ func genericRules(v *Value) bool {
|
|||||||
v.AddArg(mem)
|
v.AddArg(mem)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
end3:
|
end4:
|
||||||
;
|
;
|
||||||
// match: (Store (SPAddr [offset]) val mem)
|
// match: (Store (SPAddr [offset]) val mem)
|
||||||
// cond:
|
// cond:
|
||||||
// result: (StoreSP [offset] val mem)
|
// result: (StoreSP [offset] val mem)
|
||||||
{
|
{
|
||||||
if v.Args[0].Op != OpSPAddr {
|
if v.Args[0].Op != OpSPAddr {
|
||||||
goto end4
|
goto end5
|
||||||
}
|
}
|
||||||
offset := v.Args[0].Aux
|
offset := v.Args[0].Aux
|
||||||
val := v.Args[1]
|
val := v.Args[1]
|
||||||
@ -105,7 +129,7 @@ func genericRules(v *Value) bool {
|
|||||||
v.AddArg(mem)
|
v.AddArg(mem)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
end4:
|
end5:
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -5,12 +5,12 @@ package ssa
|
|||||||
func lowerAmd64(v *Value) bool {
|
func lowerAmd64(v *Value) bool {
|
||||||
switch v.Op {
|
switch v.Op {
|
||||||
case OpADDQ:
|
case OpADDQ:
|
||||||
// match: (ADDQ x (ConstInt [c]))
|
// match: (ADDQ x (Const [c]))
|
||||||
// cond:
|
// cond:
|
||||||
// result: (ADDCQ [c] x)
|
// result: (ADDCQ [c] x)
|
||||||
{
|
{
|
||||||
x := v.Args[0]
|
x := v.Args[0]
|
||||||
if v.Args[1].Op != OpConstInt {
|
if v.Args[1].Op != OpConst {
|
||||||
goto end0
|
goto end0
|
||||||
}
|
}
|
||||||
c := v.Args[1].Aux
|
c := v.Args[1].Aux
|
||||||
@ -23,11 +23,11 @@ func lowerAmd64(v *Value) bool {
|
|||||||
}
|
}
|
||||||
end0:
|
end0:
|
||||||
;
|
;
|
||||||
// match: (ADDQ (ConstInt [c]) x)
|
// match: (ADDQ (Const [c]) x)
|
||||||
// cond:
|
// cond:
|
||||||
// result: (ADDCQ [c] x)
|
// result: (ADDCQ [c] x)
|
||||||
{
|
{
|
||||||
if v.Args[0].Op != OpConstInt {
|
if v.Args[0].Op != OpConst {
|
||||||
goto end1
|
goto end1
|
||||||
}
|
}
|
||||||
c := v.Args[0].Aux
|
c := v.Args[0].Aux
|
||||||
@ -81,12 +81,12 @@ func lowerAmd64(v *Value) bool {
|
|||||||
end3:
|
end3:
|
||||||
;
|
;
|
||||||
case OpCMPQ:
|
case OpCMPQ:
|
||||||
// match: (CMPQ x (ConstInt [c]))
|
// match: (CMPQ x (Const [c]))
|
||||||
// cond:
|
// cond:
|
||||||
// result: (CMPCQ x [c])
|
// result: (CMPCQ x [c])
|
||||||
{
|
{
|
||||||
x := v.Args[0]
|
x := v.Args[0]
|
||||||
if v.Args[1].Op != OpConstInt {
|
if v.Args[1].Op != OpConst {
|
||||||
goto end4
|
goto end4
|
||||||
}
|
}
|
||||||
c := v.Args[1].Aux
|
c := v.Args[1].Aux
|
||||||
@ -99,11 +99,11 @@ func lowerAmd64(v *Value) bool {
|
|||||||
}
|
}
|
||||||
end4:
|
end4:
|
||||||
;
|
;
|
||||||
// match: (CMPQ (ConstInt [c]) x)
|
// match: (CMPQ (Const [c]) x)
|
||||||
// cond:
|
// cond:
|
||||||
// result: (InvertFlags (CMPCQ x [c]))
|
// result: (InvertFlags (CMPCQ <TypeFlags> x [c]))
|
||||||
{
|
{
|
||||||
if v.Args[0].Op != OpConstInt {
|
if v.Args[0].Op != OpConst {
|
||||||
goto end5
|
goto end5
|
||||||
}
|
}
|
||||||
c := v.Args[0].Aux
|
c := v.Args[0].Aux
|
||||||
@ -112,9 +112,9 @@ func lowerAmd64(v *Value) bool {
|
|||||||
v.Aux = nil
|
v.Aux = nil
|
||||||
v.Args = v.argstorage[:0]
|
v.Args = v.argstorage[:0]
|
||||||
v0 := v.Block.NewValue(OpCMPCQ, TypeInvalid, nil)
|
v0 := v.Block.NewValue(OpCMPCQ, TypeInvalid, nil)
|
||||||
|
v0.Type = TypeFlags
|
||||||
v0.AddArg(x)
|
v0.AddArg(x)
|
||||||
v0.Aux = c
|
v0.Aux = c
|
||||||
v0.SetType()
|
|
||||||
v.AddArg(v0)
|
v.AddArg(v0)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -123,7 +123,7 @@ func lowerAmd64(v *Value) bool {
|
|||||||
case OpLess:
|
case OpLess:
|
||||||
// match: (Less x y)
|
// match: (Less x y)
|
||||||
// cond: is64BitInt(v.Args[0].Type) && isSigned(v.Args[0].Type)
|
// cond: is64BitInt(v.Args[0].Type) && isSigned(v.Args[0].Type)
|
||||||
// result: (SETL (CMPQ x y))
|
// result: (SETL (CMPQ <TypeFlags> x y))
|
||||||
{
|
{
|
||||||
x := v.Args[0]
|
x := v.Args[0]
|
||||||
y := v.Args[1]
|
y := v.Args[1]
|
||||||
@ -134,9 +134,9 @@ func lowerAmd64(v *Value) bool {
|
|||||||
v.Aux = nil
|
v.Aux = nil
|
||||||
v.Args = v.argstorage[:0]
|
v.Args = v.argstorage[:0]
|
||||||
v0 := v.Block.NewValue(OpCMPQ, TypeInvalid, nil)
|
v0 := v.Block.NewValue(OpCMPQ, TypeInvalid, nil)
|
||||||
|
v0.Type = TypeFlags
|
||||||
v0.AddArg(x)
|
v0.AddArg(x)
|
||||||
v0.AddArg(y)
|
v0.AddArg(y)
|
||||||
v0.SetType()
|
|
||||||
v.AddArg(v0)
|
v.AddArg(v0)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -202,12 +202,12 @@ func lowerAmd64(v *Value) bool {
|
|||||||
end9:
|
end9:
|
||||||
;
|
;
|
||||||
case OpSUBQ:
|
case OpSUBQ:
|
||||||
// match: (SUBQ x (ConstInt [c]))
|
// match: (SUBQ x (Const [c]))
|
||||||
// cond:
|
// cond:
|
||||||
// result: (SUBCQ x [c])
|
// result: (SUBCQ x [c])
|
||||||
{
|
{
|
||||||
x := v.Args[0]
|
x := v.Args[0]
|
||||||
if v.Args[1].Op != OpConstInt {
|
if v.Args[1].Op != OpConst {
|
||||||
goto end10
|
goto end10
|
||||||
}
|
}
|
||||||
c := v.Args[1].Aux
|
c := v.Args[1].Aux
|
||||||
@ -220,11 +220,12 @@ func lowerAmd64(v *Value) bool {
|
|||||||
}
|
}
|
||||||
end10:
|
end10:
|
||||||
;
|
;
|
||||||
// match: (SUBQ (ConstInt [c]) x)
|
// match: (SUBQ <t> (Const [c]) x)
|
||||||
// cond:
|
// cond:
|
||||||
// result: (NEGQ (SUBCQ x [c]))
|
// result: (NEGQ (SUBCQ <t> x [c]))
|
||||||
{
|
{
|
||||||
if v.Args[0].Op != OpConstInt {
|
t := v.Type
|
||||||
|
if v.Args[0].Op != OpConst {
|
||||||
goto end11
|
goto end11
|
||||||
}
|
}
|
||||||
c := v.Args[0].Aux
|
c := v.Args[0].Aux
|
||||||
@ -233,9 +234,9 @@ func lowerAmd64(v *Value) bool {
|
|||||||
v.Aux = nil
|
v.Aux = nil
|
||||||
v.Args = v.argstorage[:0]
|
v.Args = v.argstorage[:0]
|
||||||
v0 := v.Block.NewValue(OpSUBCQ, TypeInvalid, nil)
|
v0 := v.Block.NewValue(OpSUBCQ, TypeInvalid, nil)
|
||||||
|
v0.Type = t
|
||||||
v0.AddArg(x)
|
v0.AddArg(x)
|
||||||
v0.Aux = c
|
v0.Aux = c
|
||||||
v0.SetType()
|
|
||||||
v.AddArg(v0)
|
v.AddArg(v0)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -29,14 +29,9 @@ const (
|
|||||||
OpLess
|
OpLess
|
||||||
|
|
||||||
// constants
|
// constants
|
||||||
OpConstNil
|
OpConst
|
||||||
OpConstBool // aux is type bool
|
|
||||||
OpConstString // aux is type string
|
|
||||||
OpConstInt // aux is type int64
|
|
||||||
OpConstFloat // aux is type float64
|
|
||||||
OpConstComplex // aux is type complex128
|
|
||||||
|
|
||||||
OpArg // address of a function parameter/result
|
OpArg // address of a function parameter/result. Memory input is an arg called ".mem".
|
||||||
OpGlobal // address of a global variable
|
OpGlobal // address of a global variable
|
||||||
OpFunc // entry address of a function
|
OpFunc // entry address of a function
|
||||||
OpCopy // output = input
|
OpCopy // output = input
|
||||||
@ -56,7 +51,7 @@ const (
|
|||||||
OpIndexAddr
|
OpIndexAddr
|
||||||
|
|
||||||
OpLoad // args are ptr, memory
|
OpLoad // args are ptr, memory
|
||||||
OpStore // args are ptr, memory, returns memory
|
OpStore // args are ptr, value, memory, returns memory
|
||||||
|
|
||||||
OpCheckNil // arg[0] != nil
|
OpCheckNil // arg[0] != nil
|
||||||
OpCheckBound // 0 <= arg[0] < arg[1]
|
OpCheckBound // 0 <= arg[0] < arg[1]
|
||||||
@ -135,9 +130,6 @@ type OpInfo struct {
|
|||||||
// %A: print aux with fmt.Print
|
// %A: print aux with fmt.Print
|
||||||
asm string
|
asm string
|
||||||
|
|
||||||
// computes type for values with this opcode
|
|
||||||
typer func(v *Value)
|
|
||||||
|
|
||||||
// returns a reg constraint for the instruction. [0] gives a reg constraint
|
// returns a reg constraint for the instruction. [0] gives a reg constraint
|
||||||
// for each input, [1] gives a reg constraint for each output. (Values have
|
// for each input, [1] gives a reg constraint for each output. (Values have
|
||||||
// exactly one output for now)
|
// exactly one output for now)
|
||||||
@ -178,28 +170,6 @@ const (
|
|||||||
ArchArm
|
ArchArm
|
||||||
)
|
)
|
||||||
|
|
||||||
func firstArgTyper(v *Value) {
|
|
||||||
v.Type = v.Args[0].Type
|
|
||||||
}
|
|
||||||
func boolTyper(v *Value) {
|
|
||||||
v.Type = TypeBool
|
|
||||||
}
|
|
||||||
func stringTyper(v *Value) {
|
|
||||||
v.Type = TypeString
|
|
||||||
}
|
|
||||||
func flagsTyper(v *Value) {
|
|
||||||
v.Type = TypeFlags
|
|
||||||
}
|
|
||||||
func uint8Typer(v *Value) {
|
|
||||||
v.Type = TypeUint8
|
|
||||||
}
|
|
||||||
func uint64Typer(v *Value) {
|
|
||||||
v.Type = TypeUint64
|
|
||||||
}
|
|
||||||
func auxTyper(v *Value) {
|
|
||||||
v.Type = v.Aux.(Type)
|
|
||||||
}
|
|
||||||
|
|
||||||
// general purpose registers, 2 input, 1 output
|
// general purpose registers, 2 input, 1 output
|
||||||
var gp21 = [2][]regMask{{gp, gp}, {gp}}
|
var gp21 = [2][]regMask{{gp, gp}, {gp}}
|
||||||
var gp21_overwrite = [2][]regMask{{gp, gp}, {overwrite0}}
|
var gp21_overwrite = [2][]regMask{{gp, gp}, {overwrite0}}
|
||||||
@ -221,16 +191,12 @@ var genericTable = [...]OpInfo{
|
|||||||
// the unknown op is used only during building and should not appear in a
|
// the unknown op is used only during building and should not appear in a
|
||||||
// fully formed ssa representation.
|
// fully formed ssa representation.
|
||||||
|
|
||||||
OpAdd: {flags: OpFlagCommutative, typer: firstArgTyper},
|
OpAdd: {flags: OpFlagCommutative},
|
||||||
OpSub: {typer: firstArgTyper},
|
OpSub: {},
|
||||||
OpMul: {flags: OpFlagCommutative, typer: firstArgTyper},
|
OpMul: {flags: OpFlagCommutative},
|
||||||
OpLess: {typer: boolTyper},
|
OpLess: {},
|
||||||
|
|
||||||
OpConstBool: {typer: boolTyper}, // aux is a bool
|
OpConst: {}, // aux matches the type (e.g. bool, int64 float64)
|
||||||
OpConstString: {typer: stringTyper}, // aux is a string
|
|
||||||
OpConstInt: {}, // aux is an int64
|
|
||||||
OpConstFloat: {}, // aux is a float64
|
|
||||||
OpConstComplex: {},
|
|
||||||
OpArg: {}, // aux is the name of the input variable TODO:?
|
OpArg: {}, // aux is the name of the input variable TODO:?
|
||||||
OpGlobal: {}, // address of a global variable
|
OpGlobal: {}, // address of a global variable
|
||||||
OpFunc: {},
|
OpFunc: {},
|
||||||
@ -281,12 +247,12 @@ var genericTable = [...]OpInfo{
|
|||||||
|
|
||||||
// Opcodes that appear in an output amd64 program
|
// Opcodes that appear in an output amd64 program
|
||||||
var amd64Table = [...]OpInfo{
|
var amd64Table = [...]OpInfo{
|
||||||
OpADDQ: {flags: OpFlagCommutative, asm: "ADDQ\t%I0,%I1,%O0", reg: gp21, typer: firstArgTyper}, // TODO: overwrite
|
OpADDQ: {flags: OpFlagCommutative, asm: "ADDQ\t%I0,%I1,%O0", reg: gp21}, // TODO: overwrite
|
||||||
OpADDCQ: {asm: "ADDQ\t$%A,%I0,%O0", reg: gp11_overwrite, typer: firstArgTyper}, // aux = int64 constant to add
|
OpADDCQ: {asm: "ADDQ\t$%A,%I0,%O0", reg: gp11_overwrite}, // aux = int64 constant to add
|
||||||
OpSUBQ: {asm: "SUBQ\t%I0,%I1,%O0", reg: gp21, typer: firstArgTyper},
|
OpSUBQ: {asm: "SUBQ\t%I0,%I1,%O0", reg: gp21},
|
||||||
OpSUBCQ: {asm: "SUBQ\t$%A,%I0,%O0", reg: gp11_overwrite, typer: firstArgTyper},
|
OpSUBCQ: {asm: "SUBQ\t$%A,%I0,%O0", reg: gp11_overwrite},
|
||||||
|
|
||||||
OpCMPQ: {asm: "CMPQ\t%I0,%I1", reg: gp2_flags, typer: flagsTyper}, // compute arg[0]-arg[1] and produce flags
|
OpCMPQ: {asm: "CMPQ\t%I0,%I1", reg: gp2_flags}, // compute arg[0]-arg[1] and produce flags
|
||||||
OpCMPCQ: {asm: "CMPQ\t$%A,%I0", reg: gp1_flags},
|
OpCMPCQ: {asm: "CMPQ\t$%A,%I0", reg: gp1_flags},
|
||||||
|
|
||||||
OpLEAQ: {flags: OpFlagCommutative, asm: "LEAQ\t%A(%I0)(%I1*1),%O0", reg: gp21}, // aux = int64 constant to add
|
OpLEAQ: {flags: OpFlagCommutative, asm: "LEAQ\t%A(%I0)(%I1*1),%O0", reg: gp21}, // aux = int64 constant to add
|
||||||
@ -302,7 +268,7 @@ var amd64Table = [...]OpInfo{
|
|||||||
OpCopy: {asm: "MOVQ\t%I0,%O0", reg: gp11},
|
OpCopy: {asm: "MOVQ\t%I0,%O0", reg: gp11},
|
||||||
|
|
||||||
// convert from flags back to boolean
|
// convert from flags back to boolean
|
||||||
OpSETL: {typer: boolTyper},
|
OpSETL: {},
|
||||||
|
|
||||||
// ops for load/store to stack
|
// ops for load/store to stack
|
||||||
OpLoadFP8: {asm: "MOVQ\t%A(FP),%O0"},
|
OpLoadFP8: {asm: "MOVQ\t%A(FP),%O0"},
|
||||||
|
@ -4,9 +4,9 @@ package ssa
|
|||||||
|
|
||||||
import "fmt"
|
import "fmt"
|
||||||
|
|
||||||
const _Op_name = "OpUnknownOpNopOpThunkOpAddOpSubOpMulOpLessOpConstNilOpConstBoolOpConstStringOpConstIntOpConstFloatOpConstComplexOpArgOpGlobalOpFuncOpCopyOpPhiOpSliceMakeOpSlicePtrOpSliceLenOpSliceCapOpStringMakeOpStringPtrOpStringLenOpSliceOpIndexOpIndexAddrOpLoadOpStoreOpCheckNilOpCheckBoundOpCallOpStaticCallOpConvertOpConvNopOpFPAddrOpSPAddrOpLoadFPOpLoadSPOpStoreFPOpStoreSPOpStoreReg8OpLoadReg8OpADDQOpSUBQOpADDCQOpSUBCQOpNEGQOpCMPQOpCMPCQOpADDLOpSETLOpSETGEOpInvertFlagsOpLEAQOpLEAQ2OpLEAQ4OpLEAQ8OpLoadFP8OpLoadSP8OpStoreFP8OpStoreSP8OpMax"
|
const _Op_name = "OpUnknownOpNopOpThunkOpAddOpSubOpMulOpLessOpConstOpArgOpGlobalOpFuncOpCopyOpPhiOpSliceMakeOpSlicePtrOpSliceLenOpSliceCapOpStringMakeOpStringPtrOpStringLenOpSliceOpIndexOpIndexAddrOpLoadOpStoreOpCheckNilOpCheckBoundOpCallOpStaticCallOpConvertOpConvNopOpFPAddrOpSPAddrOpLoadFPOpLoadSPOpStoreFPOpStoreSPOpStoreReg8OpLoadReg8OpADDQOpSUBQOpADDCQOpSUBCQOpNEGQOpCMPQOpCMPCQOpADDLOpSETLOpSETGEOpInvertFlagsOpLEAQOpLEAQ2OpLEAQ4OpLEAQ8OpLoadFP8OpLoadSP8OpStoreFP8OpStoreSP8OpMax"
|
||||||
|
|
||||||
var _Op_index = [...]uint16{0, 9, 14, 21, 26, 31, 36, 42, 52, 63, 76, 86, 98, 112, 117, 125, 131, 137, 142, 153, 163, 173, 183, 195, 206, 217, 224, 231, 242, 248, 255, 265, 277, 283, 295, 304, 313, 321, 329, 337, 345, 354, 363, 374, 384, 390, 396, 403, 410, 416, 422, 429, 435, 441, 448, 461, 467, 474, 481, 488, 497, 506, 516, 526, 531}
|
var _Op_index = [...]uint16{0, 9, 14, 21, 26, 31, 36, 42, 49, 54, 62, 68, 74, 79, 90, 100, 110, 120, 132, 143, 154, 161, 168, 179, 185, 192, 202, 214, 220, 232, 241, 250, 258, 266, 274, 282, 291, 300, 311, 321, 327, 333, 340, 347, 353, 359, 366, 372, 378, 385, 398, 404, 411, 418, 425, 434, 443, 453, 463, 468}
|
||||||
|
|
||||||
func (i Op) String() string {
|
func (i Op) String() string {
|
||||||
if i < 0 || i+1 >= Op(len(_Op_index)) {
|
if i < 0 || i+1 >= Op(len(_Op_index)) {
|
||||||
|
@ -28,43 +28,36 @@ func applyRewrite(f *Func, r func(*Value) bool) {
|
|||||||
// Common functions called from rewriting rules
|
// Common functions called from rewriting rules
|
||||||
|
|
||||||
func is64BitInt(t Type) bool {
|
func is64BitInt(t Type) bool {
|
||||||
return typeIdentical(t, TypeInt64) ||
|
if b, ok := t.Underlying().(*types.Basic); ok {
|
||||||
typeIdentical(t, TypeUint64) ||
|
switch b.Kind() {
|
||||||
(typeIdentical(t, TypeInt) && intSize == 8) ||
|
case types.Int64, types.Uint64:
|
||||||
(typeIdentical(t, TypeUint) && intSize == 8) ||
|
return true
|
||||||
(typeIdentical(t, TypeUintptr) && ptrSize == 8)
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func is32BitInt(t Type) bool {
|
func is32BitInt(t Type) bool {
|
||||||
return typeIdentical(t, TypeInt32) ||
|
if b, ok := t.Underlying().(*types.Basic); ok {
|
||||||
typeIdentical(t, TypeUint32) ||
|
switch b.Kind() {
|
||||||
(typeIdentical(t, TypeInt) && intSize == 4) ||
|
case types.Int32, types.Uint32:
|
||||||
(typeIdentical(t, TypeUint) && intSize == 4) ||
|
return true
|
||||||
(typeIdentical(t, TypeUintptr) && ptrSize == 4)
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func isSigned(t Type) bool {
|
func isSigned(t Type) bool {
|
||||||
return typeIdentical(t, TypeInt) ||
|
if b, ok := t.Underlying().(*types.Basic); ok {
|
||||||
typeIdentical(t, TypeInt8) ||
|
switch b.Kind() {
|
||||||
typeIdentical(t, TypeInt16) ||
|
case types.Int8, types.Int16, types.Int32, types.Int64:
|
||||||
typeIdentical(t, TypeInt32) ||
|
return true
|
||||||
typeIdentical(t, TypeInt64)
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func typeSize(t Type) int {
|
var sizer types.Sizes = &types.StdSizes{int64(ptrSize), int64(ptrSize)} // TODO(khr): from config
|
||||||
switch t {
|
func typeSize(t Type) int64 {
|
||||||
case TypeInt32, TypeUint32:
|
return sizer.Sizeof(t)
|
||||||
return 4
|
|
||||||
case TypeInt64, TypeUint64:
|
|
||||||
return 8
|
|
||||||
case TypeUintptr:
|
|
||||||
return ptrSize
|
|
||||||
case TypeInt, TypeUint:
|
|
||||||
return intSize
|
|
||||||
default:
|
|
||||||
if _, ok := t.(*types.Pointer); ok {
|
|
||||||
return ptrSize
|
|
||||||
}
|
|
||||||
panic("TODO: width of " + t.String())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,8 @@
|
|||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
// constant folding
|
// constant folding
|
||||||
(Add <t> (ConstInt [c]) (ConstInt [d])) && is64BitInt(t) -> (ConstInt [{c.(int64)+d.(int64)}])
|
(Add <t> (Const [c]) (Const [d])) && is64BitInt(t) && isSigned(t) -> (Const [{c.(int64)+d.(int64)}])
|
||||||
|
(Add <t> (Const [c]) (Const [d])) && is64BitInt(t) && !isSigned(t) -> (Const [{c.(uint64)+d.(uint64)}])
|
||||||
|
|
||||||
// load/store to stack
|
// load/store to stack
|
||||||
(Load (FPAddr [offset]) mem) -> (LoadFP [offset] mem)
|
(Load (FPAddr [offset]) mem) -> (LoadFP [offset] mem)
|
||||||
|
@ -8,7 +8,8 @@
|
|||||||
// on the matching side
|
// on the matching side
|
||||||
// - the types and aux fields must match if they are specified.
|
// - the types and aux fields must match if they are specified.
|
||||||
// on the generated side
|
// on the generated side
|
||||||
// - types will be computed by opcode typers if not specified explicitly.
|
// - the type of the top-level expression is the same as the one on the left-hand side.
|
||||||
|
// - the type of any subexpressions must be specified explicitly.
|
||||||
// - aux will be nil if not specified.
|
// - aux will be nil if not specified.
|
||||||
|
|
||||||
// x86 register conventions:
|
// x86 register conventions:
|
||||||
@ -24,7 +25,7 @@
|
|||||||
|
|
||||||
(Sub <t> x y) && is64BitInt(t) -> (SUBQ x y)
|
(Sub <t> x y) && is64BitInt(t) -> (SUBQ x y)
|
||||||
|
|
||||||
(Less x y) && is64BitInt(v.Args[0].Type) && isSigned(v.Args[0].Type) -> (SETL (CMPQ x y))
|
(Less x y) && is64BitInt(v.Args[0].Type) && isSigned(v.Args[0].Type) -> (SETL (CMPQ <TypeFlags> x y))
|
||||||
|
|
||||||
// stack loads/stores
|
// stack loads/stores
|
||||||
(LoadFP <t> [offset] mem) && typeSize(t) == 8 -> (LoadFP8 <t> [offset] mem)
|
(LoadFP <t> [offset] mem) && typeSize(t) == 8 -> (LoadFP8 <t> [offset] mem)
|
||||||
@ -35,12 +36,12 @@
|
|||||||
// Rules below here apply some simple optimizations after lowering.
|
// Rules below here apply some simple optimizations after lowering.
|
||||||
// TODO: Should this be a separate pass?
|
// TODO: Should this be a separate pass?
|
||||||
|
|
||||||
(ADDQ x (ConstInt [c])) -> (ADDCQ [c] x) // TODO: restrict c to int32 range?
|
(ADDQ x (Const [c])) -> (ADDCQ [c] x) // TODO: restrict c to int32 range?
|
||||||
(ADDQ (ConstInt [c]) x) -> (ADDCQ [c] x)
|
(ADDQ (Const [c]) x) -> (ADDCQ [c] x)
|
||||||
(SUBQ x (ConstInt [c])) -> (SUBCQ x [c])
|
(SUBQ x (Const [c])) -> (SUBCQ x [c])
|
||||||
(SUBQ (ConstInt [c]) x) -> (NEGQ (SUBCQ x [c]))
|
(SUBQ <t> (Const [c]) x) -> (NEGQ (SUBCQ <t> x [c]))
|
||||||
(CMPQ x (ConstInt [c])) -> (CMPCQ x [c])
|
(CMPQ x (Const [c])) -> (CMPCQ x [c])
|
||||||
(CMPQ (ConstInt [c]) x) -> (InvertFlags (CMPCQ x [c]))
|
(CMPQ (Const [c]) x) -> (InvertFlags (CMPCQ <TypeFlags> x [c]))
|
||||||
|
|
||||||
// reverse ordering of compare instruction
|
// reverse ordering of compare instruction
|
||||||
(SETL (InvertFlags x)) -> (SETGE x)
|
(SETL (InvertFlags x)) -> (SETGE x)
|
||||||
|
@ -17,6 +17,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"go/format"
|
"go/format"
|
||||||
"io"
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"sort"
|
"sort"
|
||||||
@ -148,22 +149,14 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Write to a file if given, otherwise stdout.
|
// Write to a file if given, otherwise stdout.
|
||||||
var out io.WriteCloser
|
|
||||||
if len(os.Args) >= 4 {
|
if len(os.Args) >= 4 {
|
||||||
outfile := os.Args[3]
|
err = ioutil.WriteFile(os.Args[3], b, 0666)
|
||||||
out, err = os.Create(outfile)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("can't open output file %s: %v\n", outfile, err)
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
out = os.Stdout
|
_, err = os.Stdout.Write(b)
|
||||||
}
|
}
|
||||||
if _, err = out.Write(b); err != nil {
|
if err != nil {
|
||||||
log.Fatalf("can't write output: %v\n", err)
|
log.Fatalf("can't write output: %v\n", err)
|
||||||
}
|
}
|
||||||
if err = out.Close(); err != nil {
|
|
||||||
log.Fatalf("can't close output: %v\n", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func genMatch(w io.Writer, match, fail string) {
|
func genMatch(w io.Writer, match, fail string) {
|
||||||
@ -251,17 +244,17 @@ func genResult0(w io.Writer, result string, alloc *int, top bool) string {
|
|||||||
|
|
||||||
s := split(result[1 : len(result)-1])
|
s := split(result[1 : len(result)-1])
|
||||||
var v string
|
var v string
|
||||||
var needsType bool
|
var hasType bool
|
||||||
if top {
|
if top {
|
||||||
v = "v"
|
v = "v"
|
||||||
fmt.Fprintf(w, "v.Op = Op%s\n", s[0])
|
fmt.Fprintf(w, "v.Op = Op%s\n", s[0])
|
||||||
fmt.Fprintf(w, "v.Aux = nil\n")
|
fmt.Fprintf(w, "v.Aux = nil\n")
|
||||||
fmt.Fprintf(w, "v.Args = v.argstorage[:0]\n")
|
fmt.Fprintf(w, "v.Args = v.argstorage[:0]\n")
|
||||||
|
hasType = true
|
||||||
} else {
|
} else {
|
||||||
v = fmt.Sprintf("v%d", *alloc)
|
v = fmt.Sprintf("v%d", *alloc)
|
||||||
*alloc++
|
*alloc++
|
||||||
fmt.Fprintf(w, "%s := v.Block.NewValue(Op%s, TypeInvalid, nil)\n", v, s[0])
|
fmt.Fprintf(w, "%s := v.Block.NewValue(Op%s, TypeInvalid, nil)\n", v, s[0])
|
||||||
needsType = true
|
|
||||||
}
|
}
|
||||||
for _, a := range s[1:] {
|
for _, a := range s[1:] {
|
||||||
if a[0] == '<' {
|
if a[0] == '<' {
|
||||||
@ -271,7 +264,7 @@ func genResult0(w io.Writer, result string, alloc *int, top bool) string {
|
|||||||
t = t[1 : len(t)-1]
|
t = t[1 : len(t)-1]
|
||||||
}
|
}
|
||||||
fmt.Fprintf(w, "%s.Type = %s\n", v, t)
|
fmt.Fprintf(w, "%s.Type = %s\n", v, t)
|
||||||
needsType = false
|
hasType = true
|
||||||
} else if a[0] == '[' {
|
} else if a[0] == '[' {
|
||||||
// aux restriction
|
// aux restriction
|
||||||
x := a[1 : len(a)-1]
|
x := a[1 : len(a)-1]
|
||||||
@ -287,8 +280,8 @@ func genResult0(w io.Writer, result string, alloc *int, top bool) string {
|
|||||||
fmt.Fprintf(w, "%s.AddArg(%s)\n", v, x)
|
fmt.Fprintf(w, "%s.AddArg(%s)\n", v, x)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if needsType {
|
if !hasType {
|
||||||
fmt.Fprintf(w, "%s.SetType()\n", v)
|
log.Fatalf("sub-expression %s must have a type", result)
|
||||||
}
|
}
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
@ -411,7 +411,8 @@ func parseSexprType(e sexpr) ssa.Type {
|
|||||||
if !e.compound {
|
if !e.compound {
|
||||||
switch e.name {
|
switch e.name {
|
||||||
case "int":
|
case "int":
|
||||||
return ssa.TypeInt
|
// TODO: pick correct width
|
||||||
|
return ssa.TypeInt64
|
||||||
default:
|
default:
|
||||||
fmt.Println(e.name)
|
fmt.Println(e.name)
|
||||||
panic("unknown type")
|
panic("unknown type")
|
||||||
|
@ -13,8 +13,8 @@ type Type types.Type
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
// shortcuts for commonly used basic types
|
// shortcuts for commonly used basic types
|
||||||
TypeInt = types.Typ[types.Int]
|
//TypeInt = types.Typ[types.Int]
|
||||||
TypeUint = types.Typ[types.Uint]
|
//TypeUint = types.Typ[types.Uint]
|
||||||
TypeInt8 = types.Typ[types.Int8]
|
TypeInt8 = types.Typ[types.Int8]
|
||||||
TypeInt16 = types.Typ[types.Int16]
|
TypeInt16 = types.Typ[types.Int16]
|
||||||
TypeInt32 = types.Typ[types.Int32]
|
TypeInt32 = types.Typ[types.Int32]
|
||||||
@ -23,7 +23,7 @@ var (
|
|||||||
TypeUint16 = types.Typ[types.Uint16]
|
TypeUint16 = types.Typ[types.Uint16]
|
||||||
TypeUint32 = types.Typ[types.Uint32]
|
TypeUint32 = types.Typ[types.Uint32]
|
||||||
TypeUint64 = types.Typ[types.Uint64]
|
TypeUint64 = types.Typ[types.Uint64]
|
||||||
TypeUintptr = types.Typ[types.Uintptr]
|
//TypeUintptr = types.Typ[types.Uintptr]
|
||||||
TypeBool = types.Typ[types.Bool]
|
TypeBool = types.Typ[types.Bool]
|
||||||
TypeString = types.Typ[types.String]
|
TypeString = types.Typ[types.String]
|
||||||
|
|
||||||
@ -32,6 +32,14 @@ var (
|
|||||||
// Additional compiler-only types go here.
|
// Additional compiler-only types go here.
|
||||||
TypeMem = &Memory{}
|
TypeMem = &Memory{}
|
||||||
TypeFlags = &Flags{}
|
TypeFlags = &Flags{}
|
||||||
|
|
||||||
|
// TODO(khr): we probably shouldn't use int/uint/uintptr as Value types in the compiler.
|
||||||
|
// In OpConst's case, their width is the compiler's width, not the to-be-compiled
|
||||||
|
// program's width. For now, we can translate int/uint/uintptr to their specific
|
||||||
|
// widths variants before SSA.
|
||||||
|
// However, we may need at some point to maintain all possible user types in the
|
||||||
|
// compiler to handle things like interface conversion. At that point, we may
|
||||||
|
// need to revisit this decision.
|
||||||
)
|
)
|
||||||
|
|
||||||
// typeIdentical reports whether its two arguments are the same type.
|
// typeIdentical reports whether its two arguments are the same type.
|
||||||
|
117
src/cmd/internal/ssa/types/sizes.go
Normal file
117
src/cmd/internal/ssa/types/sizes.go
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
// Copyright 2013 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.
|
||||||
|
|
||||||
|
// This file implements Sizes.
|
||||||
|
|
||||||
|
package types
|
||||||
|
|
||||||
|
import "log"
|
||||||
|
|
||||||
|
// Sizes defines the sizing functions for package unsafe.
|
||||||
|
type Sizes interface {
|
||||||
|
// Alignof returns the alignment of a variable of type T.
|
||||||
|
// Alignof must implement the alignment guarantees required by the spec.
|
||||||
|
Alignof(T Type) int64
|
||||||
|
|
||||||
|
// Offsetsof returns the offsets of the given struct fields, in bytes.
|
||||||
|
// Offsetsof must implement the offset guarantees required by the spec.
|
||||||
|
Offsetsof(fields []*Var) []int64
|
||||||
|
|
||||||
|
// Sizeof returns the size of a variable of type T.
|
||||||
|
// Sizeof must implement the size guarantees required by the spec.
|
||||||
|
Sizeof(T Type) int64
|
||||||
|
}
|
||||||
|
|
||||||
|
// StdSizes is a convenience type for creating commonly used Sizes.
|
||||||
|
// It makes the following simplifying assumptions:
|
||||||
|
//
|
||||||
|
// - The size of explicitly sized basic types (int16, etc.) is the
|
||||||
|
// specified size.
|
||||||
|
// - The size of strings and interfaces is 2*WordSize.
|
||||||
|
// - The size of slices is 3*WordSize.
|
||||||
|
// - The size of an array of n elements corresponds to the size of
|
||||||
|
// a struct of n consecutive fields of the array's element type.
|
||||||
|
// - The size of a struct is the offset of the last field plus that
|
||||||
|
// field's size. As with all element types, if the struct is used
|
||||||
|
// in an array its size must first be aligned to a multiple of the
|
||||||
|
// struct's alignment.
|
||||||
|
// - All other types have size WordSize.
|
||||||
|
// - Arrays and structs are aligned per spec definition; all other
|
||||||
|
// types are naturally aligned with a maximum alignment MaxAlign.
|
||||||
|
//
|
||||||
|
// *StdSizes implements Sizes.
|
||||||
|
//
|
||||||
|
type StdSizes struct {
|
||||||
|
WordSize int64 // word size in bytes - must be >= 4 (32bits)
|
||||||
|
MaxAlign int64 // maximum alignment in bytes - must be >= 1
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StdSizes) Alignof(T Type) int64 {
|
||||||
|
a := s.Sizeof(T) // may be 0
|
||||||
|
// spec: "For a variable x of any type: unsafe.Alignof(x) is at least 1."
|
||||||
|
if a < 1 {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
if a > s.MaxAlign {
|
||||||
|
return s.MaxAlign
|
||||||
|
}
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StdSizes) Offsetsof(fields []*Var) []int64 {
|
||||||
|
offsets := make([]int64, len(fields))
|
||||||
|
var o int64
|
||||||
|
for i, f := range fields {
|
||||||
|
a := s.Alignof(f.typ)
|
||||||
|
o = align(o, a)
|
||||||
|
offsets[i] = o
|
||||||
|
o += s.Sizeof(f.typ)
|
||||||
|
}
|
||||||
|
return offsets
|
||||||
|
}
|
||||||
|
|
||||||
|
var basicSizes = [...]byte{
|
||||||
|
Bool: 1,
|
||||||
|
Int8: 1,
|
||||||
|
Int16: 2,
|
||||||
|
Int32: 4,
|
||||||
|
Int64: 8,
|
||||||
|
Uint8: 1,
|
||||||
|
Uint16: 2,
|
||||||
|
Uint32: 4,
|
||||||
|
Uint64: 8,
|
||||||
|
Float32: 4,
|
||||||
|
Float64: 8,
|
||||||
|
Complex64: 8,
|
||||||
|
Complex128: 16,
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StdSizes) Sizeof(T Type) int64 {
|
||||||
|
switch t := T.Underlying().(type) {
|
||||||
|
case *Basic:
|
||||||
|
k := t.kind
|
||||||
|
if int(k) < len(basicSizes) {
|
||||||
|
if s := basicSizes[k]; s > 0 {
|
||||||
|
return int64(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if k == String {
|
||||||
|
return s.WordSize * 2
|
||||||
|
}
|
||||||
|
case *Slice:
|
||||||
|
return s.WordSize * 3
|
||||||
|
default:
|
||||||
|
log.Fatalf("not implemented")
|
||||||
|
}
|
||||||
|
return s.WordSize // catch-all
|
||||||
|
}
|
||||||
|
|
||||||
|
// stdSizes is used if Config.Sizes == nil.
|
||||||
|
var stdSizes = StdSizes{8, 8}
|
||||||
|
|
||||||
|
// align returns the smallest y >= x such that y % a == 0.
|
||||||
|
func align(x, a int64) int64 {
|
||||||
|
y := x + a - 1
|
||||||
|
return y - y%a
|
||||||
|
}
|
@ -40,8 +40,8 @@ type Value struct {
|
|||||||
// Examples:
|
// Examples:
|
||||||
// Opcode aux args
|
// Opcode aux args
|
||||||
// OpAdd nil 2
|
// OpAdd nil 2
|
||||||
// OpConstStr string 0
|
// OpConst string 0 string constant
|
||||||
// OpConstInt int64 0
|
// OpConst int64 0 int64 constant
|
||||||
// OpAddcq int64 1 amd64 op: v = arg[0] + constant
|
// OpAddcq int64 1 amd64 op: v = arg[0] + constant
|
||||||
|
|
||||||
// short form print. Just v#.
|
// short form print. Just v#.
|
||||||
@ -113,12 +113,3 @@ func (v *Value) CopyFrom(w *Value) {
|
|||||||
v.resetArgs()
|
v.resetArgs()
|
||||||
v.AddArgs(w.Args...)
|
v.AddArgs(w.Args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetType sets the type of v. v must not have had its type
|
|
||||||
// set yet (it must be TypeInvalid).
|
|
||||||
func (v *Value) SetType() {
|
|
||||||
if v.Type != TypeInvalid {
|
|
||||||
panic("setting type when it is already set")
|
|
||||||
}
|
|
||||||
opcodeTable[v.Op].typer(v)
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user