mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
[dev.ssa] cmd/compiler/internal/ssa: Add auxint field
Add an additional int64 auxiliary field to Value. There are two main reasons for doing this: 1) Ints in interfaces require allocation, and we store ints in Aux a lot. 2) I'd like to have both *gc.Sym and int offsets included in lots of operations (e.g. MOVQloadidx8). It will be more efficient to store them as separate fields instead of a pointer to a sym/int pair. It also simplifies a bunch of code. This is just the refactoring. I'll start using this some more in a subsequent changelist. Change-Id: I1ca797ff572553986cf90cab3ac0a0c1d01ad241 Reviewed-on: https://go-review.googlesource.com/10929 Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
This commit is contained in:
parent
0ad9c8c720
commit
8f22b5292f
20 changed files with 756 additions and 1003 deletions
|
|
@ -38,9 +38,9 @@ func buildssa(fn *Node) *ssa.Func {
|
||||||
s.exit = s.f.NewBlock(ssa.BlockExit)
|
s.exit = s.f.NewBlock(ssa.BlockExit)
|
||||||
|
|
||||||
// Allocate starting values
|
// Allocate starting values
|
||||||
s.startmem = s.entryNewValue(ssa.OpArg, ssa.TypeMem, ".mem")
|
s.startmem = s.entryNewValue0(ssa.OpArg, ssa.TypeMem)
|
||||||
s.fp = s.entryNewValue(ssa.OpFP, s.config.Uintptr, nil) // TODO: use generic pointer type (unsafe.Pointer?) instead
|
s.fp = s.entryNewValue0(ssa.OpFP, s.config.Uintptr) // TODO: use generic pointer type (unsafe.Pointer?) instead
|
||||||
s.sp = s.entryNewValue(ssa.OpSP, s.config.Uintptr, nil)
|
s.sp = s.entryNewValue0(ssa.OpSP, s.config.Uintptr)
|
||||||
|
|
||||||
s.vars = map[string]*ssa.Value{}
|
s.vars = map[string]*ssa.Value{}
|
||||||
s.labels = map[string]*ssa.Block{}
|
s.labels = map[string]*ssa.Block{}
|
||||||
|
|
@ -147,39 +147,59 @@ func (s *state) peekLine() int32 {
|
||||||
return s.line[len(s.line)-1]
|
return s.line[len(s.line)-1]
|
||||||
}
|
}
|
||||||
|
|
||||||
// newValue adds a new value with no argueents to the current block.
|
// newValue0 adds a new value with no arguments to the current block.
|
||||||
func (s *state) newValue(op ssa.Op, t ssa.Type, aux interface{}) *ssa.Value {
|
func (s *state) newValue0(op ssa.Op, t ssa.Type) *ssa.Value {
|
||||||
return s.curBlock.NewValue(s.peekLine(), op, t, aux)
|
return s.curBlock.NewValue0(s.peekLine(), op, t)
|
||||||
|
}
|
||||||
|
|
||||||
|
// newValue0A adds a new value with no arguments and an aux value to the current block.
|
||||||
|
func (s *state) newValue0A(op ssa.Op, t ssa.Type, aux interface{}) *ssa.Value {
|
||||||
|
return s.curBlock.NewValue0A(s.peekLine(), op, t, aux)
|
||||||
}
|
}
|
||||||
|
|
||||||
// newValue1 adds a new value with one argument to the current block.
|
// newValue1 adds a new value with one argument to the current block.
|
||||||
func (s *state) newValue1(op ssa.Op, t ssa.Type, aux interface{}, arg *ssa.Value) *ssa.Value {
|
func (s *state) newValue1(op ssa.Op, t ssa.Type, arg *ssa.Value) *ssa.Value {
|
||||||
return s.curBlock.NewValue1(s.peekLine(), op, t, aux, arg)
|
return s.curBlock.NewValue1(s.peekLine(), op, t, arg)
|
||||||
|
}
|
||||||
|
|
||||||
|
// newValue1A adds a new value with one argument and an aux value to the current block.
|
||||||
|
func (s *state) newValue1A(op ssa.Op, t ssa.Type, aux interface{}, arg *ssa.Value) *ssa.Value {
|
||||||
|
return s.curBlock.NewValue1A(s.peekLine(), op, t, aux, arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
// newValue2 adds a new value with two arguments to the current block.
|
// newValue2 adds a new value with two arguments to the current block.
|
||||||
func (s *state) newValue2(op ssa.Op, t ssa.Type, aux interface{}, arg0, arg1 *ssa.Value) *ssa.Value {
|
func (s *state) newValue2(op ssa.Op, t ssa.Type, arg0, arg1 *ssa.Value) *ssa.Value {
|
||||||
return s.curBlock.NewValue2(s.peekLine(), op, t, aux, arg0, arg1)
|
return s.curBlock.NewValue2(s.peekLine(), op, t, arg0, arg1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// newValue3 adds a new value with three arguments to the current block.
|
// newValue3 adds a new value with three arguments to the current block.
|
||||||
func (s *state) newValue3(op ssa.Op, t ssa.Type, aux interface{}, arg0, arg1, arg2 *ssa.Value) *ssa.Value {
|
func (s *state) newValue3(op ssa.Op, t ssa.Type, arg0, arg1, arg2 *ssa.Value) *ssa.Value {
|
||||||
return s.curBlock.NewValue3(s.peekLine(), op, t, aux, arg0, arg1, arg2)
|
return s.curBlock.NewValue3(s.peekLine(), op, t, arg0, arg1, arg2)
|
||||||
}
|
}
|
||||||
|
|
||||||
// entryNewValue adds a new value with no arguments to the entry block.
|
// entryNewValue adds a new value with no arguments to the entry block.
|
||||||
func (s *state) entryNewValue(op ssa.Op, t ssa.Type, aux interface{}) *ssa.Value {
|
func (s *state) entryNewValue0(op ssa.Op, t ssa.Type) *ssa.Value {
|
||||||
return s.f.Entry.NewValue(s.peekLine(), op, t, aux)
|
return s.f.Entry.NewValue0(s.peekLine(), op, t)
|
||||||
|
}
|
||||||
|
|
||||||
|
// entryNewValue adds a new value with no arguments and an aux value to the entry block.
|
||||||
|
func (s *state) entryNewValue0A(op ssa.Op, t ssa.Type, aux interface{}) *ssa.Value {
|
||||||
|
return s.f.Entry.NewValue0A(s.peekLine(), op, t, aux)
|
||||||
}
|
}
|
||||||
|
|
||||||
// entryNewValue1 adds a new value with one argument to the entry block.
|
// entryNewValue1 adds a new value with one argument to the entry block.
|
||||||
func (s *state) entryNewValue1(op ssa.Op, t ssa.Type, aux interface{}, arg *ssa.Value) *ssa.Value {
|
func (s *state) entryNewValue1(op ssa.Op, t ssa.Type, arg *ssa.Value) *ssa.Value {
|
||||||
return s.f.Entry.NewValue1(s.peekLine(), op, t, aux, arg)
|
return s.f.Entry.NewValue1(s.peekLine(), op, t, arg)
|
||||||
|
}
|
||||||
|
|
||||||
|
// entryNewValue1 adds a new value with one argument and an auxint value to the entry block.
|
||||||
|
func (s *state) entryNewValue1I(op ssa.Op, t ssa.Type, auxint int64, arg *ssa.Value) *ssa.Value {
|
||||||
|
return s.f.Entry.NewValue1I(s.peekLine(), op, t, auxint, arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
// entryNewValue2 adds a new value with two arguments to the entry block.
|
// entryNewValue2 adds a new value with two arguments to the entry block.
|
||||||
func (s *state) entryNewValue2(op ssa.Op, t ssa.Type, aux interface{}, arg0, arg1 *ssa.Value) *ssa.Value {
|
func (s *state) entryNewValue2(op ssa.Op, t ssa.Type, arg0, arg1 *ssa.Value) *ssa.Value {
|
||||||
return s.f.Entry.NewValue2(s.peekLine(), op, t, aux, arg0, arg1)
|
return s.f.Entry.NewValue2(s.peekLine(), op, t, arg0, arg1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// constInt adds a new const int value to the entry block.
|
// constInt adds a new const int value to the entry block.
|
||||||
|
|
@ -234,11 +254,11 @@ func (s *state) stmt(n *Node) {
|
||||||
t := n.Left.Type
|
t := n.Left.Type
|
||||||
switch {
|
switch {
|
||||||
case t.IsString():
|
case t.IsString():
|
||||||
val = s.entryNewValue(ssa.OpConst, n.Left.Type, "")
|
val = s.entryNewValue0(ssa.OpConst, n.Left.Type)
|
||||||
case t.IsInteger():
|
case t.IsInteger():
|
||||||
val = s.entryNewValue(ssa.OpConst, n.Left.Type, int64(0))
|
val = s.entryNewValue0(ssa.OpConst, n.Left.Type)
|
||||||
case t.IsBoolean():
|
case t.IsBoolean():
|
||||||
val = s.entryNewValue(ssa.OpConst, n.Left.Type, false)
|
val = s.entryNewValue0A(ssa.OpConst, n.Left.Type, false) // TODO: store bools as 0/1 in AuxInt?
|
||||||
default:
|
default:
|
||||||
log.Fatalf("zero for type %v not implemented", t)
|
log.Fatalf("zero for type %v not implemented", t)
|
||||||
}
|
}
|
||||||
|
|
@ -252,7 +272,7 @@ func (s *state) stmt(n *Node) {
|
||||||
}
|
}
|
||||||
// not ssa-able. Treat as a store.
|
// not ssa-able. Treat as a store.
|
||||||
addr := s.addr(n.Left)
|
addr := s.addr(n.Left)
|
||||||
s.vars[".mem"] = s.newValue3(ssa.OpStore, ssa.TypeMem, nil, addr, val, s.mem())
|
s.vars[".mem"] = s.newValue3(ssa.OpStore, ssa.TypeMem, addr, val, s.mem())
|
||||||
case OIF:
|
case OIF:
|
||||||
cond := s.expr(n.Left)
|
cond := s.expr(n.Left)
|
||||||
b := s.endBlock()
|
b := s.endBlock()
|
||||||
|
|
@ -341,20 +361,20 @@ func (s *state) expr(n *Node) *ssa.Value {
|
||||||
case ONAME:
|
case ONAME:
|
||||||
if n.Class == PFUNC {
|
if n.Class == PFUNC {
|
||||||
// "value" of a function is the address of the function's closure
|
// "value" of a function is the address of the function's closure
|
||||||
return s.entryNewValue(ssa.OpGlobal, Ptrto(n.Type), funcsym(n.Sym))
|
return s.entryNewValue0A(ssa.OpGlobal, Ptrto(n.Type), funcsym(n.Sym))
|
||||||
}
|
}
|
||||||
s.argOffsets[n.Sym.Name] = n.Xoffset // TODO: remember this another way?
|
s.argOffsets[n.Sym.Name] = n.Xoffset // TODO: remember this another way?
|
||||||
if canSSA(n) {
|
if canSSA(n) {
|
||||||
return s.variable(n.Sym.Name, n.Type)
|
return s.variable(n.Sym.Name, n.Type)
|
||||||
}
|
}
|
||||||
addr := s.addr(n)
|
addr := s.addr(n)
|
||||||
return s.newValue2(ssa.OpLoad, n.Type, nil, addr, s.mem())
|
return s.newValue2(ssa.OpLoad, n.Type, addr, s.mem())
|
||||||
case OLITERAL:
|
case OLITERAL:
|
||||||
switch n.Val().Ctype() {
|
switch n.Val().Ctype() {
|
||||||
case CTINT:
|
case CTINT:
|
||||||
return s.constInt(n.Type, Mpgetfix(n.Val().U.(*Mpint)))
|
return s.constInt(n.Type, Mpgetfix(n.Val().U.(*Mpint)))
|
||||||
case CTSTR:
|
case CTSTR:
|
||||||
return s.entryNewValue(ssa.OpConst, n.Type, n.Val().U)
|
return s.entryNewValue0A(ssa.OpConst, n.Type, n.Val().U)
|
||||||
default:
|
default:
|
||||||
log.Fatalf("unhandled OLITERAL %v", n.Val().Ctype())
|
log.Fatalf("unhandled OLITERAL %v", n.Val().Ctype())
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -367,24 +387,24 @@ func (s *state) expr(n *Node) *ssa.Value {
|
||||||
case OLT:
|
case OLT:
|
||||||
a := s.expr(n.Left)
|
a := s.expr(n.Left)
|
||||||
b := s.expr(n.Right)
|
b := s.expr(n.Right)
|
||||||
return s.newValue2(ssa.OpLess, ssa.TypeBool, nil, a, b)
|
return s.newValue2(ssa.OpLess, ssa.TypeBool, a, b)
|
||||||
case OADD:
|
case OADD:
|
||||||
a := s.expr(n.Left)
|
a := s.expr(n.Left)
|
||||||
b := s.expr(n.Right)
|
b := s.expr(n.Right)
|
||||||
return s.newValue2(ssa.OpAdd, a.Type, nil, a, b)
|
return s.newValue2(ssa.OpAdd, a.Type, a, b)
|
||||||
case OSUB:
|
case OSUB:
|
||||||
// TODO:(khr) fold code for all binary ops together somehow
|
// TODO:(khr) fold code for all binary ops together somehow
|
||||||
a := s.expr(n.Left)
|
a := s.expr(n.Left)
|
||||||
b := s.expr(n.Right)
|
b := s.expr(n.Right)
|
||||||
return s.newValue2(ssa.OpSub, a.Type, nil, a, b)
|
return s.newValue2(ssa.OpSub, a.Type, a, b)
|
||||||
case OLSH:
|
case OLSH:
|
||||||
a := s.expr(n.Left)
|
a := s.expr(n.Left)
|
||||||
b := s.expr(n.Right)
|
b := s.expr(n.Right)
|
||||||
return s.newValue2(ssa.OpLsh, a.Type, nil, a, b)
|
return s.newValue2(ssa.OpLsh, a.Type, a, b)
|
||||||
case ORSH:
|
case ORSH:
|
||||||
a := s.expr(n.Left)
|
a := s.expr(n.Left)
|
||||||
b := s.expr(n.Right)
|
b := s.expr(n.Right)
|
||||||
return s.newValue2(ssa.OpRsh, a.Type, nil, a, b)
|
return s.newValue2(ssa.OpRsh, a.Type, a, b)
|
||||||
|
|
||||||
case OADDR:
|
case OADDR:
|
||||||
return s.addr(n.Left)
|
return s.addr(n.Left)
|
||||||
|
|
@ -392,13 +412,13 @@ func (s *state) expr(n *Node) *ssa.Value {
|
||||||
case OIND:
|
case OIND:
|
||||||
p := s.expr(n.Left)
|
p := s.expr(n.Left)
|
||||||
s.nilCheck(p)
|
s.nilCheck(p)
|
||||||
return s.newValue2(ssa.OpLoad, n.Type, nil, p, s.mem())
|
return s.newValue2(ssa.OpLoad, n.Type, p, s.mem())
|
||||||
|
|
||||||
case ODOTPTR:
|
case ODOTPTR:
|
||||||
p := s.expr(n.Left)
|
p := s.expr(n.Left)
|
||||||
s.nilCheck(p)
|
s.nilCheck(p)
|
||||||
p = s.newValue2(ssa.OpAdd, p.Type, nil, p, s.constInt(s.config.Uintptr, n.Xoffset))
|
p = s.newValue2(ssa.OpAdd, p.Type, p, s.constInt(s.config.Uintptr, n.Xoffset))
|
||||||
return s.newValue2(ssa.OpLoad, n.Type, nil, p, s.mem())
|
return s.newValue2(ssa.OpLoad, n.Type, p, s.mem())
|
||||||
|
|
||||||
case OINDEX:
|
case OINDEX:
|
||||||
if n.Left.Type.Bound >= 0 { // array or string
|
if n.Left.Type.Bound >= 0 { // array or string
|
||||||
|
|
@ -407,17 +427,17 @@ func (s *state) expr(n *Node) *ssa.Value {
|
||||||
var elemtype *Type
|
var elemtype *Type
|
||||||
var len *ssa.Value
|
var len *ssa.Value
|
||||||
if n.Left.Type.IsString() {
|
if n.Left.Type.IsString() {
|
||||||
len = s.newValue1(ssa.OpStringLen, s.config.Uintptr, nil, a)
|
len = s.newValue1(ssa.OpStringLen, s.config.Uintptr, a)
|
||||||
elemtype = Types[TUINT8]
|
elemtype = Types[TUINT8]
|
||||||
} else {
|
} else {
|
||||||
len = s.constInt(s.config.Uintptr, n.Left.Type.Bound)
|
len = s.constInt(s.config.Uintptr, n.Left.Type.Bound)
|
||||||
elemtype = n.Left.Type.Type
|
elemtype = n.Left.Type.Type
|
||||||
}
|
}
|
||||||
s.boundsCheck(i, len)
|
s.boundsCheck(i, len)
|
||||||
return s.newValue2(ssa.OpArrayIndex, elemtype, nil, a, i)
|
return s.newValue2(ssa.OpArrayIndex, elemtype, a, i)
|
||||||
} else { // slice
|
} else { // slice
|
||||||
p := s.addr(n)
|
p := s.addr(n)
|
||||||
return s.newValue2(ssa.OpLoad, n.Left.Type.Type, nil, p, s.mem())
|
return s.newValue2(ssa.OpLoad, n.Left.Type.Type, p, s.mem())
|
||||||
}
|
}
|
||||||
|
|
||||||
case OCALLFUNC:
|
case OCALLFUNC:
|
||||||
|
|
@ -435,10 +455,10 @@ func (s *state) expr(n *Node) *ssa.Value {
|
||||||
bNext := s.f.NewBlock(ssa.BlockPlain)
|
bNext := s.f.NewBlock(ssa.BlockPlain)
|
||||||
var call *ssa.Value
|
var call *ssa.Value
|
||||||
if static {
|
if static {
|
||||||
call = s.newValue1(ssa.OpStaticCall, ssa.TypeMem, n.Left.Sym, s.mem())
|
call = s.newValue1A(ssa.OpStaticCall, ssa.TypeMem, n.Left.Sym, s.mem())
|
||||||
} else {
|
} else {
|
||||||
entry := s.newValue2(ssa.OpLoad, s.config.Uintptr, nil, closure, s.mem())
|
entry := s.newValue2(ssa.OpLoad, s.config.Uintptr, closure, s.mem())
|
||||||
call = s.newValue3(ssa.OpClosureCall, ssa.TypeMem, nil, entry, closure, s.mem())
|
call = s.newValue3(ssa.OpClosureCall, ssa.TypeMem, entry, closure, s.mem())
|
||||||
}
|
}
|
||||||
b := s.endBlock()
|
b := s.endBlock()
|
||||||
b.Kind = ssa.BlockCall
|
b.Kind = ssa.BlockCall
|
||||||
|
|
@ -450,8 +470,8 @@ func (s *state) expr(n *Node) *ssa.Value {
|
||||||
s.startBlock(bNext)
|
s.startBlock(bNext)
|
||||||
var titer Iter
|
var titer Iter
|
||||||
fp := Structfirst(&titer, Getoutarg(n.Left.Type))
|
fp := Structfirst(&titer, Getoutarg(n.Left.Type))
|
||||||
a := s.entryNewValue1(ssa.OpOffPtr, Ptrto(fp.Type), fp.Width, s.sp)
|
a := s.entryNewValue1I(ssa.OpOffPtr, Ptrto(fp.Type), fp.Width, s.sp)
|
||||||
return s.newValue2(ssa.OpLoad, fp.Type, nil, a, call)
|
return s.newValue2(ssa.OpLoad, fp.Type, a, call)
|
||||||
default:
|
default:
|
||||||
log.Fatalf("unhandled expr %s", opnames[n.Op])
|
log.Fatalf("unhandled expr %s", opnames[n.Op])
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -465,10 +485,10 @@ func (s *state) addr(n *Node) *ssa.Value {
|
||||||
switch n.Class {
|
switch n.Class {
|
||||||
case PEXTERN:
|
case PEXTERN:
|
||||||
// global variable
|
// global variable
|
||||||
return s.entryNewValue(ssa.OpGlobal, Ptrto(n.Type), n.Sym)
|
return s.entryNewValue0A(ssa.OpGlobal, Ptrto(n.Type), n.Sym)
|
||||||
case PPARAMOUT:
|
case PPARAMOUT:
|
||||||
// store to parameter slot
|
// store to parameter slot
|
||||||
return s.entryNewValue1(ssa.OpOffPtr, Ptrto(n.Type), n.Xoffset, s.fp)
|
return s.entryNewValue1I(ssa.OpOffPtr, Ptrto(n.Type), n.Xoffset, s.fp)
|
||||||
default:
|
default:
|
||||||
// TODO: address of locals
|
// TODO: address of locals
|
||||||
log.Fatalf("variable address of %v not implemented", n)
|
log.Fatalf("variable address of %v not implemented", n)
|
||||||
|
|
@ -477,21 +497,21 @@ func (s *state) addr(n *Node) *ssa.Value {
|
||||||
case OINDREG:
|
case OINDREG:
|
||||||
// indirect off a register (TODO: always SP?)
|
// indirect off a register (TODO: always SP?)
|
||||||
// used for storing/loading arguments/returns to/from callees
|
// used for storing/loading arguments/returns to/from callees
|
||||||
return s.entryNewValue1(ssa.OpOffPtr, Ptrto(n.Type), n.Xoffset, s.sp)
|
return s.entryNewValue1I(ssa.OpOffPtr, Ptrto(n.Type), n.Xoffset, s.sp)
|
||||||
case OINDEX:
|
case OINDEX:
|
||||||
if n.Left.Type.Bound >= 0 { // array
|
if n.Left.Type.Bound >= 0 { // array
|
||||||
a := s.addr(n.Left)
|
a := s.addr(n.Left)
|
||||||
i := s.expr(n.Right)
|
i := s.expr(n.Right)
|
||||||
len := s.constInt(s.config.Uintptr, n.Left.Type.Bound)
|
len := s.constInt(s.config.Uintptr, n.Left.Type.Bound)
|
||||||
s.boundsCheck(i, len)
|
s.boundsCheck(i, len)
|
||||||
return s.newValue2(ssa.OpPtrIndex, Ptrto(n.Left.Type.Type), nil, a, i)
|
return s.newValue2(ssa.OpPtrIndex, Ptrto(n.Left.Type.Type), a, i)
|
||||||
} else { // slice
|
} else { // slice
|
||||||
a := s.expr(n.Left)
|
a := s.expr(n.Left)
|
||||||
i := s.expr(n.Right)
|
i := s.expr(n.Right)
|
||||||
len := s.newValue1(ssa.OpSliceLen, s.config.Uintptr, nil, a)
|
len := s.newValue1(ssa.OpSliceLen, s.config.Uintptr, a)
|
||||||
s.boundsCheck(i, len)
|
s.boundsCheck(i, len)
|
||||||
p := s.newValue1(ssa.OpSlicePtr, Ptrto(n.Left.Type.Type), nil, a)
|
p := s.newValue1(ssa.OpSlicePtr, Ptrto(n.Left.Type.Type), a)
|
||||||
return s.newValue2(ssa.OpPtrIndex, Ptrto(n.Left.Type.Type), nil, p, i)
|
return s.newValue2(ssa.OpPtrIndex, Ptrto(n.Left.Type.Type), p, i)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
log.Fatalf("addr: bad op %v", Oconv(int(n.Op), 0))
|
log.Fatalf("addr: bad op %v", Oconv(int(n.Op), 0))
|
||||||
|
|
@ -524,7 +544,7 @@ func canSSA(n *Node) bool {
|
||||||
// nilCheck generates nil pointer checking code.
|
// nilCheck generates nil pointer checking code.
|
||||||
// Starts a new block on return.
|
// Starts a new block on return.
|
||||||
func (s *state) nilCheck(ptr *ssa.Value) {
|
func (s *state) nilCheck(ptr *ssa.Value) {
|
||||||
c := s.newValue1(ssa.OpIsNonNil, ssa.TypeBool, nil, ptr)
|
c := s.newValue1(ssa.OpIsNonNil, ssa.TypeBool, ptr)
|
||||||
b := s.endBlock()
|
b := s.endBlock()
|
||||||
b.Kind = ssa.BlockIf
|
b.Kind = ssa.BlockIf
|
||||||
b.Control = c
|
b.Control = c
|
||||||
|
|
@ -543,7 +563,7 @@ func (s *state) boundsCheck(idx, len *ssa.Value) {
|
||||||
// TODO: if index is 64-bit and we're compiling to 32-bit, check that high 32 bits are zero.
|
// TODO: if index is 64-bit and we're compiling to 32-bit, check that high 32 bits are zero.
|
||||||
|
|
||||||
// bounds check
|
// bounds check
|
||||||
cmp := s.newValue2(ssa.OpIsInBounds, ssa.TypeBool, nil, idx, len)
|
cmp := s.newValue2(ssa.OpIsInBounds, ssa.TypeBool, idx, len)
|
||||||
b := s.endBlock()
|
b := s.endBlock()
|
||||||
b.Kind = ssa.BlockIf
|
b.Kind = ssa.BlockIf
|
||||||
b.Control = cmp
|
b.Control = cmp
|
||||||
|
|
@ -562,7 +582,7 @@ func (s *state) variable(name string, t ssa.Type) *ssa.Value {
|
||||||
v := s.vars[name]
|
v := s.vars[name]
|
||||||
if v == nil {
|
if v == nil {
|
||||||
// TODO: get type? Take Sym as arg?
|
// TODO: get type? Take Sym as arg?
|
||||||
v = s.newValue(ssa.OpFwdRef, t, name)
|
v = s.newValue0A(ssa.OpFwdRef, t, name)
|
||||||
s.vars[name] = v
|
s.vars[name] = v
|
||||||
}
|
}
|
||||||
return v
|
return v
|
||||||
|
|
@ -601,8 +621,8 @@ func (s *state) lookupVarIncoming(b *ssa.Block, t ssa.Type, name string) *ssa.Va
|
||||||
return s.startmem
|
return s.startmem
|
||||||
}
|
}
|
||||||
// variable is live at the entry block. Load it.
|
// variable is live at the entry block. Load it.
|
||||||
addr := s.entryNewValue1(ssa.OpOffPtr, Ptrto(t.(*Type)), s.argOffsets[name], s.fp)
|
addr := s.entryNewValue1I(ssa.OpOffPtr, Ptrto(t.(*Type)), s.argOffsets[name], s.fp)
|
||||||
return s.entryNewValue2(ssa.OpLoad, t, nil, addr, s.startmem)
|
return s.entryNewValue2(ssa.OpLoad, t, addr, s.startmem)
|
||||||
|
|
||||||
}
|
}
|
||||||
var vals []*ssa.Value
|
var vals []*ssa.Value
|
||||||
|
|
@ -613,7 +633,7 @@ func (s *state) lookupVarIncoming(b *ssa.Block, t ssa.Type, name string) *ssa.Va
|
||||||
for i := 1; i < len(vals); i++ {
|
for i := 1; i < len(vals); i++ {
|
||||||
if vals[i] != v0 {
|
if vals[i] != v0 {
|
||||||
// need a phi value
|
// need a phi value
|
||||||
v := b.NewValue(s.peekLine(), ssa.OpPhi, t, nil)
|
v := b.NewValue0(s.peekLine(), ssa.OpPhi, t)
|
||||||
v.AddArgs(vals...)
|
v.AddArgs(vals...)
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
@ -634,7 +654,7 @@ func (s *state) lookupVarOutgoing(b *ssa.Block, t ssa.Type, name string) *ssa.Va
|
||||||
// Make v = copy(w). We need the extra copy to
|
// Make v = copy(w). We need the extra copy to
|
||||||
// prevent infinite recursion when looking up the
|
// prevent infinite recursion when looking up the
|
||||||
// incoming value of the variable.
|
// incoming value of the variable.
|
||||||
v := b.NewValue(s.peekLine(), ssa.OpCopy, t, nil)
|
v := b.NewValue0(s.peekLine(), ssa.OpCopy, t)
|
||||||
m[name] = v
|
m[name] = v
|
||||||
v.AddArg(s.lookupVarIncoming(b, t, name))
|
v.AddArg(s.lookupVarIncoming(b, t, name))
|
||||||
return v
|
return v
|
||||||
|
|
@ -728,7 +748,7 @@ func genValue(v *ssa.Value) {
|
||||||
p := Prog(x86.ALEAQ)
|
p := Prog(x86.ALEAQ)
|
||||||
p.From.Type = obj.TYPE_MEM
|
p.From.Type = obj.TYPE_MEM
|
||||||
p.From.Reg = regnum(v.Args[0])
|
p.From.Reg = regnum(v.Args[0])
|
||||||
p.From.Offset = v.Aux.(int64)
|
p.From.Offset = v.AuxInt
|
||||||
p.To.Type = obj.TYPE_REG
|
p.To.Type = obj.TYPE_REG
|
||||||
p.To.Reg = regnum(v)
|
p.To.Reg = regnum(v)
|
||||||
case ssa.OpAMD64MULQconst:
|
case ssa.OpAMD64MULQconst:
|
||||||
|
|
@ -736,7 +756,7 @@ func genValue(v *ssa.Value) {
|
||||||
// has ever been taught to compile imul $c, r1, r2.
|
// has ever been taught to compile imul $c, r1, r2.
|
||||||
p := Prog(x86.AIMULQ)
|
p := Prog(x86.AIMULQ)
|
||||||
p.From.Type = obj.TYPE_CONST
|
p.From.Type = obj.TYPE_CONST
|
||||||
p.From.Offset = v.Aux.(int64)
|
p.From.Offset = v.AuxInt
|
||||||
p.From3.Type = obj.TYPE_REG
|
p.From3.Type = obj.TYPE_REG
|
||||||
p.From3.Reg = regnum(v.Args[0])
|
p.From3.Reg = regnum(v.Args[0])
|
||||||
p.To.Type = obj.TYPE_REG
|
p.To.Type = obj.TYPE_REG
|
||||||
|
|
@ -756,7 +776,7 @@ func genValue(v *ssa.Value) {
|
||||||
}
|
}
|
||||||
p := Prog(x86.ASUBQ)
|
p := Prog(x86.ASUBQ)
|
||||||
p.From.Type = obj.TYPE_CONST
|
p.From.Type = obj.TYPE_CONST
|
||||||
p.From.Offset = v.Aux.(int64)
|
p.From.Offset = v.AuxInt
|
||||||
p.To.Type = obj.TYPE_REG
|
p.To.Type = obj.TYPE_REG
|
||||||
p.To.Reg = r
|
p.To.Reg = r
|
||||||
case ssa.OpAMD64SHLQ:
|
case ssa.OpAMD64SHLQ:
|
||||||
|
|
@ -829,7 +849,7 @@ func genValue(v *ssa.Value) {
|
||||||
}
|
}
|
||||||
p := Prog(x86.ASHLQ)
|
p := Prog(x86.ASHLQ)
|
||||||
p.From.Type = obj.TYPE_CONST
|
p.From.Type = obj.TYPE_CONST
|
||||||
p.From.Offset = v.Aux.(int64)
|
p.From.Offset = v.AuxInt
|
||||||
p.To.Type = obj.TYPE_REG
|
p.To.Type = obj.TYPE_REG
|
||||||
p.To.Reg = r
|
p.To.Reg = r
|
||||||
case ssa.OpAMD64SHRQconst:
|
case ssa.OpAMD64SHRQconst:
|
||||||
|
|
@ -845,7 +865,7 @@ func genValue(v *ssa.Value) {
|
||||||
}
|
}
|
||||||
p := Prog(x86.ASHRQ)
|
p := Prog(x86.ASHRQ)
|
||||||
p.From.Type = obj.TYPE_CONST
|
p.From.Type = obj.TYPE_CONST
|
||||||
p.From.Offset = v.Aux.(int64)
|
p.From.Offset = v.AuxInt
|
||||||
p.To.Type = obj.TYPE_REG
|
p.To.Type = obj.TYPE_REG
|
||||||
p.To.Reg = r
|
p.To.Reg = r
|
||||||
case ssa.OpAMD64SARQconst:
|
case ssa.OpAMD64SARQconst:
|
||||||
|
|
@ -861,7 +881,7 @@ func genValue(v *ssa.Value) {
|
||||||
}
|
}
|
||||||
p := Prog(x86.ASARQ)
|
p := Prog(x86.ASARQ)
|
||||||
p.From.Type = obj.TYPE_CONST
|
p.From.Type = obj.TYPE_CONST
|
||||||
p.From.Offset = v.Aux.(int64)
|
p.From.Offset = v.AuxInt
|
||||||
p.To.Type = obj.TYPE_REG
|
p.To.Type = obj.TYPE_REG
|
||||||
p.To.Reg = r
|
p.To.Reg = r
|
||||||
case ssa.OpAMD64SBBQcarrymask:
|
case ssa.OpAMD64SBBQcarrymask:
|
||||||
|
|
@ -921,7 +941,7 @@ func genValue(v *ssa.Value) {
|
||||||
p.From.Reg = regnum(v.Args[0])
|
p.From.Reg = regnum(v.Args[0])
|
||||||
p.From.Scale = 1
|
p.From.Scale = 1
|
||||||
p.From.Index = regnum(v.Args[1])
|
p.From.Index = regnum(v.Args[1])
|
||||||
p.From.Offset = v.Aux.(int64)
|
p.From.Offset = v.AuxInt
|
||||||
p.To.Type = obj.TYPE_REG
|
p.To.Type = obj.TYPE_REG
|
||||||
p.To.Reg = regnum(v)
|
p.To.Reg = regnum(v)
|
||||||
case ssa.OpAMD64CMPQ:
|
case ssa.OpAMD64CMPQ:
|
||||||
|
|
@ -935,7 +955,7 @@ func genValue(v *ssa.Value) {
|
||||||
p.From.Type = obj.TYPE_REG
|
p.From.Type = obj.TYPE_REG
|
||||||
p.From.Reg = regnum(v.Args[0])
|
p.From.Reg = regnum(v.Args[0])
|
||||||
p.To.Type = obj.TYPE_CONST
|
p.To.Type = obj.TYPE_CONST
|
||||||
p.To.Offset = v.Aux.(int64)
|
p.To.Offset = v.AuxInt
|
||||||
case ssa.OpAMD64TESTB:
|
case ssa.OpAMD64TESTB:
|
||||||
p := Prog(x86.ATESTB)
|
p := Prog(x86.ATESTB)
|
||||||
p.From.Type = obj.TYPE_REG
|
p.From.Type = obj.TYPE_REG
|
||||||
|
|
@ -946,28 +966,28 @@ func genValue(v *ssa.Value) {
|
||||||
x := regnum(v)
|
x := regnum(v)
|
||||||
p := Prog(x86.AMOVQ)
|
p := Prog(x86.AMOVQ)
|
||||||
p.From.Type = obj.TYPE_CONST
|
p.From.Type = obj.TYPE_CONST
|
||||||
p.From.Offset = v.Aux.(int64)
|
p.From.Offset = v.AuxInt
|
||||||
p.To.Type = obj.TYPE_REG
|
p.To.Type = obj.TYPE_REG
|
||||||
p.To.Reg = x
|
p.To.Reg = x
|
||||||
case ssa.OpAMD64MOVQload:
|
case ssa.OpAMD64MOVQload:
|
||||||
p := Prog(x86.AMOVQ)
|
p := Prog(x86.AMOVQ)
|
||||||
p.From.Type = obj.TYPE_MEM
|
p.From.Type = obj.TYPE_MEM
|
||||||
p.From.Reg = regnum(v.Args[0])
|
p.From.Reg = regnum(v.Args[0])
|
||||||
p.From.Offset = v.Aux.(int64)
|
p.From.Offset = v.AuxInt
|
||||||
p.To.Type = obj.TYPE_REG
|
p.To.Type = obj.TYPE_REG
|
||||||
p.To.Reg = regnum(v)
|
p.To.Reg = regnum(v)
|
||||||
case ssa.OpAMD64MOVBload:
|
case ssa.OpAMD64MOVBload:
|
||||||
p := Prog(x86.AMOVB)
|
p := Prog(x86.AMOVB)
|
||||||
p.From.Type = obj.TYPE_MEM
|
p.From.Type = obj.TYPE_MEM
|
||||||
p.From.Reg = regnum(v.Args[0])
|
p.From.Reg = regnum(v.Args[0])
|
||||||
p.From.Offset = v.Aux.(int64)
|
p.From.Offset = v.AuxInt
|
||||||
p.To.Type = obj.TYPE_REG
|
p.To.Type = obj.TYPE_REG
|
||||||
p.To.Reg = regnum(v)
|
p.To.Reg = regnum(v)
|
||||||
case ssa.OpAMD64MOVQloadidx8:
|
case ssa.OpAMD64MOVQloadidx8:
|
||||||
p := Prog(x86.AMOVQ)
|
p := Prog(x86.AMOVQ)
|
||||||
p.From.Type = obj.TYPE_MEM
|
p.From.Type = obj.TYPE_MEM
|
||||||
p.From.Reg = regnum(v.Args[0])
|
p.From.Reg = regnum(v.Args[0])
|
||||||
p.From.Offset = v.Aux.(int64)
|
p.From.Offset = v.AuxInt
|
||||||
p.From.Scale = 8
|
p.From.Scale = 8
|
||||||
p.From.Index = regnum(v.Args[1])
|
p.From.Index = regnum(v.Args[1])
|
||||||
p.To.Type = obj.TYPE_REG
|
p.To.Type = obj.TYPE_REG
|
||||||
|
|
@ -978,7 +998,7 @@ func genValue(v *ssa.Value) {
|
||||||
p.From.Reg = regnum(v.Args[1])
|
p.From.Reg = regnum(v.Args[1])
|
||||||
p.To.Type = obj.TYPE_MEM
|
p.To.Type = obj.TYPE_MEM
|
||||||
p.To.Reg = regnum(v.Args[0])
|
p.To.Reg = regnum(v.Args[0])
|
||||||
p.To.Offset = v.Aux.(int64)
|
p.To.Offset = v.AuxInt
|
||||||
case ssa.OpCopy: // TODO: lower to MOVQ earlier?
|
case ssa.OpCopy: // TODO: lower to MOVQ earlier?
|
||||||
if v.Type.IsMemory() {
|
if v.Type.IsMemory() {
|
||||||
return
|
return
|
||||||
|
|
@ -1021,14 +1041,13 @@ func genValue(v *ssa.Value) {
|
||||||
}
|
}
|
||||||
case ssa.OpArg:
|
case ssa.OpArg:
|
||||||
// memory arg needs no code
|
// memory arg needs no code
|
||||||
// TODO: only mem arg goes here.
|
// TODO: check that only mem arg goes here.
|
||||||
case ssa.OpAMD64LEAQglobal:
|
case ssa.OpAMD64LEAQglobal:
|
||||||
g := v.Aux.(ssa.GlobalOffset)
|
|
||||||
p := Prog(x86.ALEAQ)
|
p := Prog(x86.ALEAQ)
|
||||||
p.From.Type = obj.TYPE_MEM
|
p.From.Type = obj.TYPE_MEM
|
||||||
p.From.Name = obj.NAME_EXTERN
|
p.From.Name = obj.NAME_EXTERN
|
||||||
p.From.Sym = Linksym(g.Global.(*Sym))
|
p.From.Sym = Linksym(v.Aux.(*Sym))
|
||||||
p.From.Offset = g.Offset
|
p.From.Offset = v.AuxInt
|
||||||
p.To.Type = obj.TYPE_REG
|
p.To.Type = obj.TYPE_REG
|
||||||
p.To.Reg = regnum(v)
|
p.To.Reg = regnum(v)
|
||||||
case ssa.OpAMD64CALLstatic:
|
case ssa.OpAMD64CALLstatic:
|
||||||
|
|
|
||||||
|
|
@ -10,14 +10,14 @@ func TestDeadLoop(t *testing.T) {
|
||||||
c := NewConfig("amd64", DummyFrontend{})
|
c := NewConfig("amd64", DummyFrontend{})
|
||||||
fun := Fun(c, "entry",
|
fun := Fun(c, "entry",
|
||||||
Bloc("entry",
|
Bloc("entry",
|
||||||
Valu("mem", OpArg, TypeMem, ".mem"),
|
Valu("mem", OpArg, TypeMem, 0, ".mem"),
|
||||||
Goto("exit")),
|
Goto("exit")),
|
||||||
Bloc("exit",
|
Bloc("exit",
|
||||||
Exit("mem")),
|
Exit("mem")),
|
||||||
// dead loop
|
// dead loop
|
||||||
Bloc("deadblock",
|
Bloc("deadblock",
|
||||||
// dead value in dead block
|
// dead value in dead block
|
||||||
Valu("deadval", OpConst, TypeBool, true),
|
Valu("deadval", OpConst, TypeBool, 0, true),
|
||||||
If("deadval", "deadblock", "exit")))
|
If("deadval", "deadblock", "exit")))
|
||||||
|
|
||||||
CheckFunc(fun.f)
|
CheckFunc(fun.f)
|
||||||
|
|
@ -40,8 +40,8 @@ func TestDeadValue(t *testing.T) {
|
||||||
c := NewConfig("amd64", DummyFrontend{})
|
c := NewConfig("amd64", DummyFrontend{})
|
||||||
fun := Fun(c, "entry",
|
fun := Fun(c, "entry",
|
||||||
Bloc("entry",
|
Bloc("entry",
|
||||||
Valu("mem", OpArg, TypeMem, ".mem"),
|
Valu("mem", OpArg, TypeMem, 0, ".mem"),
|
||||||
Valu("deadval", OpConst, TypeInt64, int64(37)),
|
Valu("deadval", OpConst, TypeInt64, 37, nil),
|
||||||
Goto("exit")),
|
Goto("exit")),
|
||||||
Bloc("exit",
|
Bloc("exit",
|
||||||
Exit("mem")))
|
Exit("mem")))
|
||||||
|
|
@ -63,8 +63,8 @@ func TestNeverTaken(t *testing.T) {
|
||||||
c := NewConfig("amd64", DummyFrontend{})
|
c := NewConfig("amd64", DummyFrontend{})
|
||||||
fun := Fun(c, "entry",
|
fun := Fun(c, "entry",
|
||||||
Bloc("entry",
|
Bloc("entry",
|
||||||
Valu("cond", OpConst, TypeBool, false),
|
Valu("cond", OpConst, TypeBool, 0, false),
|
||||||
Valu("mem", OpArg, TypeMem, ".mem"),
|
Valu("mem", OpArg, TypeMem, 0, ".mem"),
|
||||||
If("cond", "then", "else")),
|
If("cond", "then", "else")),
|
||||||
Bloc("then",
|
Bloc("then",
|
||||||
Goto("exit")),
|
Goto("exit")),
|
||||||
|
|
|
||||||
|
|
@ -13,13 +13,13 @@ func TestDeadStore(t *testing.T) {
|
||||||
ptrType := &TypeImpl{Size_: 8, Ptr: true, Name: "testptr"} // dummy for testing
|
ptrType := &TypeImpl{Size_: 8, Ptr: true, Name: "testptr"} // dummy for testing
|
||||||
fun := Fun(c, "entry",
|
fun := Fun(c, "entry",
|
||||||
Bloc("entry",
|
Bloc("entry",
|
||||||
Valu("start", OpArg, TypeMem, ".mem"),
|
Valu("start", OpArg, TypeMem, 0, ".mem"),
|
||||||
Valu("v", OpConst, TypeBool, true),
|
Valu("v", OpConst, TypeBool, 0, true),
|
||||||
Valu("addr1", OpGlobal, ptrType, nil),
|
Valu("addr1", OpGlobal, ptrType, 0, nil),
|
||||||
Valu("addr2", OpGlobal, ptrType, nil),
|
Valu("addr2", OpGlobal, ptrType, 0, nil),
|
||||||
Valu("store1", OpStore, TypeMem, nil, "addr1", "v", "start"),
|
Valu("store1", OpStore, TypeMem, 0, nil, "addr1", "v", "start"),
|
||||||
Valu("store2", OpStore, TypeMem, nil, "addr2", "v", "store1"),
|
Valu("store2", OpStore, TypeMem, 0, nil, "addr2", "v", "store1"),
|
||||||
Valu("store3", OpStore, TypeMem, nil, "addr1", "v", "store2"),
|
Valu("store3", OpStore, TypeMem, 0, nil, "addr1", "v", "store2"),
|
||||||
Goto("exit")),
|
Goto("exit")),
|
||||||
Bloc("exit",
|
Bloc("exit",
|
||||||
Exit("store3")))
|
Exit("store3")))
|
||||||
|
|
@ -39,13 +39,13 @@ func TestDeadStorePhi(t *testing.T) {
|
||||||
ptrType := &TypeImpl{Size_: 8, Ptr: true, Name: "testptr"} // dummy for testing
|
ptrType := &TypeImpl{Size_: 8, Ptr: true, Name: "testptr"} // dummy for testing
|
||||||
fun := Fun(c, "entry",
|
fun := Fun(c, "entry",
|
||||||
Bloc("entry",
|
Bloc("entry",
|
||||||
Valu("start", OpArg, TypeMem, ".mem"),
|
Valu("start", OpArg, TypeMem, 0, ".mem"),
|
||||||
Valu("v", OpConst, TypeBool, true),
|
Valu("v", OpConst, TypeBool, 0, true),
|
||||||
Valu("addr", OpGlobal, ptrType, nil),
|
Valu("addr", OpGlobal, ptrType, 0, nil),
|
||||||
Goto("loop")),
|
Goto("loop")),
|
||||||
Bloc("loop",
|
Bloc("loop",
|
||||||
Valu("phi", OpPhi, TypeMem, nil, "start", "store"),
|
Valu("phi", OpPhi, TypeMem, 0, nil, "start", "store"),
|
||||||
Valu("store", OpStore, TypeMem, nil, "addr", "v", "phi"),
|
Valu("store", OpStore, TypeMem, 0, nil, "addr", "v", "phi"),
|
||||||
If("v", "loop", "exit")),
|
If("v", "loop", "exit")),
|
||||||
Bloc("exit",
|
Bloc("exit",
|
||||||
Exit("store")))
|
Exit("store")))
|
||||||
|
|
@ -65,12 +65,12 @@ func TestDeadStoreTypes(t *testing.T) {
|
||||||
t2 := &TypeImpl{Size_: 4, Ptr: true, Name: "t2"}
|
t2 := &TypeImpl{Size_: 4, Ptr: true, Name: "t2"}
|
||||||
fun := Fun(c, "entry",
|
fun := Fun(c, "entry",
|
||||||
Bloc("entry",
|
Bloc("entry",
|
||||||
Valu("start", OpArg, TypeMem, ".mem"),
|
Valu("start", OpArg, TypeMem, 0, ".mem"),
|
||||||
Valu("v", OpConst, TypeBool, true),
|
Valu("v", OpConst, TypeBool, 0, true),
|
||||||
Valu("addr1", OpGlobal, t1, nil),
|
Valu("addr1", OpGlobal, t1, 0, nil),
|
||||||
Valu("addr2", OpGlobal, t2, nil),
|
Valu("addr2", OpGlobal, t2, 0, nil),
|
||||||
Valu("store1", OpStore, TypeMem, nil, "addr1", "v", "start"),
|
Valu("store1", OpStore, TypeMem, 0, nil, "addr1", "v", "start"),
|
||||||
Valu("store2", OpStore, TypeMem, nil, "addr2", "v", "store1"),
|
Valu("store2", OpStore, TypeMem, 0, nil, "addr2", "v", "store1"),
|
||||||
Goto("exit")),
|
Goto("exit")),
|
||||||
Bloc("exit",
|
Bloc("exit",
|
||||||
Exit("store2")))
|
Exit("store2")))
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@
|
||||||
|
|
||||||
package ssa
|
package ssa
|
||||||
|
|
||||||
|
import "log"
|
||||||
|
|
||||||
// A Func represents a Go func declaration (or function literal) and
|
// A Func represents a Go func declaration (or function literal) and
|
||||||
// its body. This package compiles each Func independently.
|
// its body. This package compiles each Func independently.
|
||||||
type Func struct {
|
type Func struct {
|
||||||
|
|
@ -42,8 +44,41 @@ func (f *Func) NewBlock(kind BlockKind) *Block {
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewValue returns a new value in the block with no arguments.
|
// NewValue0 returns a new value in the block with no arguments and zero aux values.
|
||||||
func (b *Block) NewValue(line int32, op Op, t Type, aux interface{}) *Value {
|
func (b *Block) NewValue0(line int32, op Op, t Type) *Value {
|
||||||
|
v := &Value{
|
||||||
|
ID: b.Func.vid.get(),
|
||||||
|
Op: op,
|
||||||
|
Type: t,
|
||||||
|
Block: b,
|
||||||
|
}
|
||||||
|
v.Args = v.argstorage[:0]
|
||||||
|
b.Values = append(b.Values, v)
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewValue returns a new value in the block with no arguments and an auxint value.
|
||||||
|
func (b *Block) NewValue0I(line int32, op Op, t Type, auxint int64) *Value {
|
||||||
|
v := &Value{
|
||||||
|
ID: b.Func.vid.get(),
|
||||||
|
Op: op,
|
||||||
|
Type: t,
|
||||||
|
AuxInt: auxint,
|
||||||
|
Block: b,
|
||||||
|
}
|
||||||
|
v.Args = v.argstorage[:0]
|
||||||
|
b.Values = append(b.Values, v)
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewValue returns a new value in the block with no arguments and an aux value.
|
||||||
|
func (b *Block) NewValue0A(line int32, op Op, t Type, aux interface{}) *Value {
|
||||||
|
if _, ok := aux.(int64); ok {
|
||||||
|
// Disallow int64 aux values. They should be in the auxint field instead.
|
||||||
|
// Maybe we want to allow this at some point, but for now we disallow it
|
||||||
|
// to prevent errors like using NewValue1A instead of NewValue1I.
|
||||||
|
log.Fatalf("aux field has int64 type op=%s type=%s aux=%v", op, t, aux)
|
||||||
|
}
|
||||||
v := &Value{
|
v := &Value{
|
||||||
ID: b.Func.vid.get(),
|
ID: b.Func.vid.get(),
|
||||||
Op: op,
|
Op: op,
|
||||||
|
|
@ -56,8 +91,52 @@ func (b *Block) NewValue(line int32, op Op, t Type, aux interface{}) *Value {
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewValue1 returns a new value in the block with one argument.
|
// NewValue returns a new value in the block with no arguments and both an auxint and aux values.
|
||||||
func (b *Block) NewValue1(line int32, op Op, t Type, aux interface{}, arg *Value) *Value {
|
func (b *Block) NewValue0IA(line int32, op Op, t Type, auxint int64, aux interface{}) *Value {
|
||||||
|
v := &Value{
|
||||||
|
ID: b.Func.vid.get(),
|
||||||
|
Op: op,
|
||||||
|
Type: t,
|
||||||
|
AuxInt: auxint,
|
||||||
|
Aux: aux,
|
||||||
|
Block: b,
|
||||||
|
}
|
||||||
|
v.Args = v.argstorage[:0]
|
||||||
|
b.Values = append(b.Values, v)
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewValue1 returns a new value in the block with one argument and zero aux values.
|
||||||
|
func (b *Block) NewValue1(line int32, op Op, t Type, arg *Value) *Value {
|
||||||
|
v := &Value{
|
||||||
|
ID: b.Func.vid.get(),
|
||||||
|
Op: op,
|
||||||
|
Type: t,
|
||||||
|
Block: b,
|
||||||
|
}
|
||||||
|
v.Args = v.argstorage[:1]
|
||||||
|
v.Args[0] = arg
|
||||||
|
b.Values = append(b.Values, v)
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewValue1I returns a new value in the block with one argument and an auxint value.
|
||||||
|
func (b *Block) NewValue1I(line int32, op Op, t Type, auxint int64, arg *Value) *Value {
|
||||||
|
v := &Value{
|
||||||
|
ID: b.Func.vid.get(),
|
||||||
|
Op: op,
|
||||||
|
Type: t,
|
||||||
|
AuxInt: auxint,
|
||||||
|
Block: b,
|
||||||
|
}
|
||||||
|
v.Args = v.argstorage[:1]
|
||||||
|
v.Args[0] = arg
|
||||||
|
b.Values = append(b.Values, v)
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewValue1A returns a new value in the block with one argument and an aux value.
|
||||||
|
func (b *Block) NewValue1A(line int32, op Op, t Type, aux interface{}, arg *Value) *Value {
|
||||||
v := &Value{
|
v := &Value{
|
||||||
ID: b.Func.vid.get(),
|
ID: b.Func.vid.get(),
|
||||||
Op: op,
|
Op: op,
|
||||||
|
|
@ -71,13 +150,28 @@ func (b *Block) NewValue1(line int32, op Op, t Type, aux interface{}, arg *Value
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewValue2 returns a new value in the block with two arguments.
|
// NewValue1IA returns a new value in the block with one argument and both an auxint and aux values.
|
||||||
func (b *Block) NewValue2(line int32, op Op, t Type, aux interface{}, arg0, arg1 *Value) *Value {
|
func (b *Block) NewValue1IA(line int32, op Op, t Type, auxint int64, aux interface{}, arg *Value) *Value {
|
||||||
|
v := &Value{
|
||||||
|
ID: b.Func.vid.get(),
|
||||||
|
Op: op,
|
||||||
|
Type: t,
|
||||||
|
AuxInt: auxint,
|
||||||
|
Aux: aux,
|
||||||
|
Block: b,
|
||||||
|
}
|
||||||
|
v.Args = v.argstorage[:1]
|
||||||
|
v.Args[0] = arg
|
||||||
|
b.Values = append(b.Values, v)
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewValue2 returns a new value in the block with two arguments and zero aux values.
|
||||||
|
func (b *Block) NewValue2(line int32, op Op, t Type, arg0, arg1 *Value) *Value {
|
||||||
v := &Value{
|
v := &Value{
|
||||||
ID: b.Func.vid.get(),
|
ID: b.Func.vid.get(),
|
||||||
Op: op,
|
Op: op,
|
||||||
Type: t,
|
Type: t,
|
||||||
Aux: aux,
|
|
||||||
Block: b,
|
Block: b,
|
||||||
}
|
}
|
||||||
v.Args = v.argstorage[:2]
|
v.Args = v.argstorage[:2]
|
||||||
|
|
@ -87,13 +181,12 @@ func (b *Block) NewValue2(line int32, op Op, t Type, aux interface{}, arg0, arg1
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewValue3 returns a new value in the block with three arguments.
|
// NewValue3 returns a new value in the block with three arguments and zero aux values.
|
||||||
func (b *Block) NewValue3(line int32, op Op, t Type, aux interface{}, arg0, arg1, arg2 *Value) *Value {
|
func (b *Block) NewValue3(line int32, op Op, t Type, arg0, arg1, arg2 *Value) *Value {
|
||||||
v := &Value{
|
v := &Value{
|
||||||
ID: b.Func.vid.get(),
|
ID: b.Func.vid.get(),
|
||||||
Op: op,
|
Op: op,
|
||||||
Type: t,
|
Type: t,
|
||||||
Aux: aux,
|
|
||||||
Block: b,
|
Block: b,
|
||||||
}
|
}
|
||||||
v.Args = []*Value{arg0, arg1, arg2}
|
v.Args = []*Value{arg0, arg1, arg2}
|
||||||
|
|
@ -104,5 +197,5 @@ func (b *Block) NewValue3(line int32, op Op, t Type, aux interface{}, arg0, arg1
|
||||||
// ConstInt returns an int constant representing its argument.
|
// ConstInt returns an int constant representing its argument.
|
||||||
func (f *Func) ConstInt(line int32, t Type, c int64) *Value {
|
func (f *Func) ConstInt(line int32, t Type, c int64) *Value {
|
||||||
// TODO: cache?
|
// TODO: cache?
|
||||||
return f.Entry.NewValue(line, OpConst, t, c)
|
return f.Entry.NewValue0I(line, OpConst, t, c)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,12 +18,12 @@
|
||||||
//
|
//
|
||||||
// fun := Fun("entry",
|
// fun := Fun("entry",
|
||||||
// Bloc("entry",
|
// Bloc("entry",
|
||||||
// Valu("mem", OpArg, TypeMem, ".mem"),
|
// Valu("mem", OpArg, TypeMem, 0, ".mem"),
|
||||||
// Goto("exit")),
|
// Goto("exit")),
|
||||||
// Bloc("exit",
|
// Bloc("exit",
|
||||||
// Exit("mem")),
|
// Exit("mem")),
|
||||||
// Bloc("deadblock",
|
// Bloc("deadblock",
|
||||||
// Valu("deadval", OpConst, TypeBool, true),
|
// Valu("deadval", OpConst, TypeBool, 0, true),
|
||||||
// If("deadval", "deadblock", "exit")))
|
// If("deadval", "deadblock", "exit")))
|
||||||
//
|
//
|
||||||
// and the Blocks or Values used in the Func can be accessed
|
// and the Blocks or Values used in the Func can be accessed
|
||||||
|
|
@ -61,7 +61,7 @@ func Equiv(f, g *Func) bool {
|
||||||
// Ignore ids. Ops and Types are compared for equality.
|
// Ignore ids. Ops and Types are compared for equality.
|
||||||
// TODO(matloob): Make sure types are canonical and can
|
// TODO(matloob): Make sure types are canonical and can
|
||||||
// be compared for equality.
|
// be compared for equality.
|
||||||
if fv.Op != gv.Op || fv.Type != gv.Type {
|
if fv.Op != gv.Op || fv.Type != gv.Type || fv.AuxInt != gv.AuxInt {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(fv.Aux, gv.Aux) {
|
if !reflect.DeepEqual(fv.Aux, gv.Aux) {
|
||||||
|
|
@ -149,7 +149,7 @@ func Fun(c *Config, entry string, blocs ...bloc) fun {
|
||||||
blocks[bloc.name] = b
|
blocks[bloc.name] = b
|
||||||
for _, valu := range bloc.valus {
|
for _, valu := range bloc.valus {
|
||||||
// args are filled in the second pass.
|
// args are filled in the second pass.
|
||||||
values[valu.name] = b.NewValue(0, valu.op, valu.t, valu.aux)
|
values[valu.name] = b.NewValue0IA(0, valu.op, valu.t, valu.auxint, valu.aux)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Connect the blocks together and specify control values.
|
// Connect the blocks together and specify control values.
|
||||||
|
|
@ -212,8 +212,8 @@ func Bloc(name string, entries ...interface{}) bloc {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Valu defines a value in a block.
|
// Valu defines a value in a block.
|
||||||
func Valu(name string, op Op, t Type, aux interface{}, args ...string) valu {
|
func Valu(name string, op Op, t Type, auxint int64, aux interface{}, args ...string) valu {
|
||||||
return valu{name, op, t, aux, args}
|
return valu{name, op, t, auxint, aux, args}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Goto specifies that this is a BlockPlain and names the single successor.
|
// Goto specifies that this is a BlockPlain and names the single successor.
|
||||||
|
|
@ -248,11 +248,12 @@ type ctrl struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type valu struct {
|
type valu struct {
|
||||||
name string
|
name string
|
||||||
op Op
|
op Op
|
||||||
t Type
|
t Type
|
||||||
aux interface{}
|
auxint int64
|
||||||
args []string
|
aux interface{}
|
||||||
|
args []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func addEdge(b, c *Block) {
|
func addEdge(b, c *Block) {
|
||||||
|
|
@ -264,10 +265,10 @@ func TestArgs(t *testing.T) {
|
||||||
c := NewConfig("amd64", DummyFrontend{})
|
c := NewConfig("amd64", DummyFrontend{})
|
||||||
fun := Fun(c, "entry",
|
fun := Fun(c, "entry",
|
||||||
Bloc("entry",
|
Bloc("entry",
|
||||||
Valu("a", OpConst, TypeInt64, 14),
|
Valu("a", OpConst, TypeInt64, 14, nil),
|
||||||
Valu("b", OpConst, TypeInt64, 26),
|
Valu("b", OpConst, TypeInt64, 26, nil),
|
||||||
Valu("sum", OpAdd, TypeInt64, nil, "a", "b"),
|
Valu("sum", OpAdd, TypeInt64, 0, nil, "a", "b"),
|
||||||
Valu("mem", OpArg, TypeMem, ".mem"),
|
Valu("mem", OpArg, TypeMem, 0, ".mem"),
|
||||||
Goto("exit")),
|
Goto("exit")),
|
||||||
Bloc("exit",
|
Bloc("exit",
|
||||||
Exit("mem")))
|
Exit("mem")))
|
||||||
|
|
@ -287,19 +288,19 @@ func TestEquiv(t *testing.T) {
|
||||||
{
|
{
|
||||||
Fun(c, "entry",
|
Fun(c, "entry",
|
||||||
Bloc("entry",
|
Bloc("entry",
|
||||||
Valu("a", OpConst, TypeInt64, 14),
|
Valu("a", OpConst, TypeInt64, 14, nil),
|
||||||
Valu("b", OpConst, TypeInt64, 26),
|
Valu("b", OpConst, TypeInt64, 26, nil),
|
||||||
Valu("sum", OpAdd, TypeInt64, nil, "a", "b"),
|
Valu("sum", OpAdd, TypeInt64, 0, nil, "a", "b"),
|
||||||
Valu("mem", OpArg, TypeMem, ".mem"),
|
Valu("mem", OpArg, TypeMem, 0, ".mem"),
|
||||||
Goto("exit")),
|
Goto("exit")),
|
||||||
Bloc("exit",
|
Bloc("exit",
|
||||||
Exit("mem"))),
|
Exit("mem"))),
|
||||||
Fun(c, "entry",
|
Fun(c, "entry",
|
||||||
Bloc("entry",
|
Bloc("entry",
|
||||||
Valu("a", OpConst, TypeInt64, 14),
|
Valu("a", OpConst, TypeInt64, 14, nil),
|
||||||
Valu("b", OpConst, TypeInt64, 26),
|
Valu("b", OpConst, TypeInt64, 26, nil),
|
||||||
Valu("sum", OpAdd, TypeInt64, nil, "a", "b"),
|
Valu("sum", OpAdd, TypeInt64, 0, nil, "a", "b"),
|
||||||
Valu("mem", OpArg, TypeMem, ".mem"),
|
Valu("mem", OpArg, TypeMem, 0, ".mem"),
|
||||||
Goto("exit")),
|
Goto("exit")),
|
||||||
Bloc("exit",
|
Bloc("exit",
|
||||||
Exit("mem"))),
|
Exit("mem"))),
|
||||||
|
|
@ -308,10 +309,10 @@ func TestEquiv(t *testing.T) {
|
||||||
{
|
{
|
||||||
Fun(c, "entry",
|
Fun(c, "entry",
|
||||||
Bloc("entry",
|
Bloc("entry",
|
||||||
Valu("a", OpConst, TypeInt64, 14),
|
Valu("a", OpConst, TypeInt64, 14, nil),
|
||||||
Valu("b", OpConst, TypeInt64, 26),
|
Valu("b", OpConst, TypeInt64, 26, nil),
|
||||||
Valu("sum", OpAdd, TypeInt64, nil, "a", "b"),
|
Valu("sum", OpAdd, TypeInt64, 0, nil, "a", "b"),
|
||||||
Valu("mem", OpArg, TypeMem, ".mem"),
|
Valu("mem", OpArg, TypeMem, 0, ".mem"),
|
||||||
Goto("exit")),
|
Goto("exit")),
|
||||||
Bloc("exit",
|
Bloc("exit",
|
||||||
Exit("mem"))),
|
Exit("mem"))),
|
||||||
|
|
@ -319,10 +320,10 @@ func TestEquiv(t *testing.T) {
|
||||||
Bloc("exit",
|
Bloc("exit",
|
||||||
Exit("mem")),
|
Exit("mem")),
|
||||||
Bloc("entry",
|
Bloc("entry",
|
||||||
Valu("a", OpConst, TypeInt64, 14),
|
Valu("a", OpConst, TypeInt64, 14, nil),
|
||||||
Valu("b", OpConst, TypeInt64, 26),
|
Valu("b", OpConst, TypeInt64, 26, nil),
|
||||||
Valu("sum", OpAdd, TypeInt64, nil, "a", "b"),
|
Valu("sum", OpAdd, TypeInt64, 0, nil, "a", "b"),
|
||||||
Valu("mem", OpArg, TypeMem, ".mem"),
|
Valu("mem", OpArg, TypeMem, 0, ".mem"),
|
||||||
Goto("exit"))),
|
Goto("exit"))),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
@ -339,58 +340,71 @@ func TestEquiv(t *testing.T) {
|
||||||
{
|
{
|
||||||
Fun(c, "entry",
|
Fun(c, "entry",
|
||||||
Bloc("entry",
|
Bloc("entry",
|
||||||
Valu("mem", OpArg, TypeMem, ".mem"),
|
Valu("mem", OpArg, TypeMem, 0, ".mem"),
|
||||||
Goto("exit")),
|
Goto("exit")),
|
||||||
Bloc("exit",
|
Bloc("exit",
|
||||||
Exit("mem"))),
|
Exit("mem"))),
|
||||||
Fun(c, "entry",
|
Fun(c, "entry",
|
||||||
Bloc("entry",
|
Bloc("entry",
|
||||||
Valu("mem", OpArg, TypeMem, ".mem"),
|
Valu("mem", OpArg, TypeMem, 0, ".mem"),
|
||||||
Exit("mem"))),
|
Exit("mem"))),
|
||||||
},
|
},
|
||||||
// value order changed
|
// value order changed
|
||||||
{
|
{
|
||||||
Fun(c, "entry",
|
Fun(c, "entry",
|
||||||
Bloc("entry",
|
Bloc("entry",
|
||||||
Valu("mem", OpArg, TypeMem, ".mem"),
|
Valu("mem", OpArg, TypeMem, 0, ".mem"),
|
||||||
Valu("b", OpConst, TypeInt64, 26),
|
Valu("b", OpConst, TypeInt64, 26, nil),
|
||||||
Valu("a", OpConst, TypeInt64, 14),
|
Valu("a", OpConst, TypeInt64, 14, nil),
|
||||||
Exit("mem"))),
|
Exit("mem"))),
|
||||||
Fun(c, "entry",
|
Fun(c, "entry",
|
||||||
Bloc("entry",
|
Bloc("entry",
|
||||||
Valu("mem", OpArg, TypeMem, ".mem"),
|
Valu("mem", OpArg, TypeMem, 0, ".mem"),
|
||||||
Valu("a", OpConst, TypeInt64, 14),
|
Valu("a", OpConst, TypeInt64, 14, nil),
|
||||||
Valu("b", OpConst, TypeInt64, 26),
|
Valu("b", OpConst, TypeInt64, 26, nil),
|
||||||
|
Exit("mem"))),
|
||||||
|
},
|
||||||
|
// value auxint different
|
||||||
|
{
|
||||||
|
Fun(c, "entry",
|
||||||
|
Bloc("entry",
|
||||||
|
Valu("mem", OpArg, TypeMem, 0, ".mem"),
|
||||||
|
Valu("a", OpConst, TypeInt64, 14, nil),
|
||||||
|
Exit("mem"))),
|
||||||
|
Fun(c, "entry",
|
||||||
|
Bloc("entry",
|
||||||
|
Valu("mem", OpArg, TypeMem, 0, ".mem"),
|
||||||
|
Valu("a", OpConst, TypeInt64, 26, nil),
|
||||||
Exit("mem"))),
|
Exit("mem"))),
|
||||||
},
|
},
|
||||||
// value aux different
|
// value aux different
|
||||||
{
|
{
|
||||||
Fun(c, "entry",
|
Fun(c, "entry",
|
||||||
Bloc("entry",
|
Bloc("entry",
|
||||||
Valu("mem", OpArg, TypeMem, ".mem"),
|
Valu("mem", OpArg, TypeMem, 0, ".mem"),
|
||||||
Valu("a", OpConst, TypeInt64, 14),
|
Valu("a", OpConst, TypeInt64, 0, 14),
|
||||||
Exit("mem"))),
|
Exit("mem"))),
|
||||||
Fun(c, "entry",
|
Fun(c, "entry",
|
||||||
Bloc("entry",
|
Bloc("entry",
|
||||||
Valu("mem", OpArg, TypeMem, ".mem"),
|
Valu("mem", OpArg, TypeMem, 0, ".mem"),
|
||||||
Valu("a", OpConst, TypeInt64, 26),
|
Valu("a", OpConst, TypeInt64, 0, 26),
|
||||||
Exit("mem"))),
|
Exit("mem"))),
|
||||||
},
|
},
|
||||||
// value args different
|
// value args different
|
||||||
{
|
{
|
||||||
Fun(c, "entry",
|
Fun(c, "entry",
|
||||||
Bloc("entry",
|
Bloc("entry",
|
||||||
Valu("mem", OpArg, TypeMem, ".mem"),
|
Valu("mem", OpArg, TypeMem, 0, ".mem"),
|
||||||
Valu("a", OpConst, TypeInt64, 14),
|
Valu("a", OpConst, TypeInt64, 14, nil),
|
||||||
Valu("b", OpConst, TypeInt64, 26),
|
Valu("b", OpConst, TypeInt64, 26, nil),
|
||||||
Valu("sum", OpAdd, TypeInt64, nil, "a", "b"),
|
Valu("sum", OpAdd, TypeInt64, 0, nil, "a", "b"),
|
||||||
Exit("mem"))),
|
Exit("mem"))),
|
||||||
Fun(c, "entry",
|
Fun(c, "entry",
|
||||||
Bloc("entry",
|
Bloc("entry",
|
||||||
Valu("mem", OpArg, TypeMem, ".mem"),
|
Valu("mem", OpArg, TypeMem, 0, ".mem"),
|
||||||
Valu("a", OpConst, TypeInt64, 0),
|
Valu("a", OpConst, TypeInt64, 0, nil),
|
||||||
Valu("b", OpConst, TypeInt64, 14),
|
Valu("b", OpConst, TypeInt64, 14, nil),
|
||||||
Valu("sum", OpAdd, TypeInt64, nil, "b", "a"),
|
Valu("sum", OpAdd, TypeInt64, 0, nil, "b", "a"),
|
||||||
Exit("mem"))),
|
Exit("mem"))),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,30 +23,30 @@
|
||||||
// mask = shift >= 64 ? 0 : 0xffffffffffffffff
|
// mask = shift >= 64 ? 0 : 0xffffffffffffffff
|
||||||
// result = mask & arg << shift
|
// result = mask & arg << shift
|
||||||
(Lsh <t> x y) && is64BitInt(t) ->
|
(Lsh <t> x y) && is64BitInt(t) ->
|
||||||
(ANDQ (SHLQ <t> x y) (SBBQcarrymask <t> (CMPQconst <TypeFlags> [int64(64)] y)))
|
(ANDQ (SHLQ <t> x y) (SBBQcarrymask <t> (CMPQconst <TypeFlags> [64] y)))
|
||||||
(Rsh <t> x y) && is64BitInt(t) && !t.IsSigned() ->
|
(Rsh <t> x y) && is64BitInt(t) && !t.IsSigned() ->
|
||||||
(ANDQ (SHRQ <t> x y) (SBBQcarrymask <t> (CMPQconst <TypeFlags> [int64(64)] y)))
|
(ANDQ (SHRQ <t> x y) (SBBQcarrymask <t> (CMPQconst <TypeFlags> [64] y)))
|
||||||
|
|
||||||
// Note: signed right shift needs to return 0/-1 if shift amount is >= 64.
|
// Note: signed right shift needs to return 0/-1 if shift amount is >= 64.
|
||||||
// if shift > 63 { shift = 63 }
|
// if shift > 63 { shift = 63 }
|
||||||
// result = arg >> shift
|
// result = arg >> shift
|
||||||
(Rsh <t> x y) && is64BitInt(t) && t.IsSigned() ->
|
(Rsh <t> x y) && is64BitInt(t) && t.IsSigned() ->
|
||||||
(SARQ <t> x (CMOVQCC <t>
|
(SARQ <t> x (CMOVQCC <t>
|
||||||
(CMPQconst <TypeFlags> [int64(64)] y)
|
(CMPQconst <TypeFlags> [64] y)
|
||||||
(Const <t> [int64(63)])
|
(Const <t> [63])
|
||||||
y))
|
y))
|
||||||
|
|
||||||
(Less x y) && is64BitInt(v.Args[0].Type) && isSigned(v.Args[0].Type) -> (SETL (CMPQ <TypeFlags> x y))
|
(Less x y) && is64BitInt(v.Args[0].Type) && isSigned(v.Args[0].Type) -> (SETL (CMPQ <TypeFlags> x y))
|
||||||
|
|
||||||
(Load <t> ptr mem) && t.IsBoolean() -> (MOVBload [int64(0)] ptr mem)
|
(Load <t> ptr mem) && t.IsBoolean() -> (MOVBload ptr mem)
|
||||||
(Load <t> ptr mem) && (is64BitInt(t) || isPtr(t)) -> (MOVQload [int64(0)] ptr mem)
|
(Load <t> ptr mem) && (is64BitInt(t) || isPtr(t)) -> (MOVQload ptr mem)
|
||||||
(Store ptr val mem) && (is64BitInt(val.Type) || isPtr(val.Type)) -> (MOVQstore [int64(0)] ptr val mem)
|
(Store ptr val mem) && (is64BitInt(val.Type) || isPtr(val.Type)) -> (MOVQstore ptr val mem)
|
||||||
|
|
||||||
// checks
|
// checks
|
||||||
(IsNonNil p) -> (SETNE (TESTQ <TypeFlags> p p))
|
(IsNonNil p) -> (SETNE (TESTQ <TypeFlags> p p))
|
||||||
(IsInBounds idx len) -> (SETB (CMPQ <TypeFlags> idx len))
|
(IsInBounds idx len) -> (SETB (CMPQ <TypeFlags> idx len))
|
||||||
|
|
||||||
(Move [size] dst src mem) -> (REPMOVSB dst src (Const <TypeUInt64> [size.(int64)]) mem)
|
(Move [size] dst src mem) -> (REPMOVSB dst src (Const <TypeUInt64> [size]) mem)
|
||||||
|
|
||||||
(OffPtr [off] ptr) -> (ADDQconst [off] ptr)
|
(OffPtr [off] ptr) -> (ADDQconst [off] ptr)
|
||||||
|
|
||||||
|
|
@ -65,14 +65,14 @@
|
||||||
// TODO: Should this be a separate pass?
|
// TODO: Should this be a separate pass?
|
||||||
|
|
||||||
// global loads/stores
|
// global loads/stores
|
||||||
(Global [sym]) -> (LEAQglobal [GlobalOffset{sym,0}])
|
(Global {sym}) -> (LEAQglobal {sym})
|
||||||
|
|
||||||
// fold constants into instructions
|
// fold constants into instructions
|
||||||
(ADDQ x (MOVQconst [c])) -> (ADDQconst [c] x) // TODO: restrict c to int32 range?
|
(ADDQ x (MOVQconst [c])) -> (ADDQconst [c] x) // TODO: restrict c to int32 range?
|
||||||
(ADDQ (MOVQconst [c]) x) -> (ADDQconst [c] x)
|
(ADDQ (MOVQconst [c]) x) -> (ADDQconst [c] x)
|
||||||
(SUBQ x (MOVQconst [c])) -> (SUBQconst x [c])
|
(SUBQ x (MOVQconst [c])) -> (SUBQconst x [c])
|
||||||
(SUBQ <t> (MOVQconst [c]) x) -> (NEGQ (SUBQconst <t> x [c]))
|
(SUBQ <t> (MOVQconst [c]) x) -> (NEGQ (SUBQconst <t> x [c]))
|
||||||
(MULQ x (MOVQconst [c])) && c.(int64) == int64(int32(c.(int64))) -> (MULQconst [c] x)
|
(MULQ x (MOVQconst [c])) && c == int64(int32(c)) -> (MULQconst [c] x)
|
||||||
(MULQ (MOVQconst [c]) x) -> (MULQconst [c] x)
|
(MULQ (MOVQconst [c]) x) -> (MULQconst [c] x)
|
||||||
(ANDQ x (MOVQconst [c])) -> (ANDQconst [c] x)
|
(ANDQ x (MOVQconst [c])) -> (ANDQconst [c] x)
|
||||||
(ANDQ (MOVQconst [c]) x) -> (ANDQconst [c] x)
|
(ANDQ (MOVQconst [c]) x) -> (ANDQconst [c] x)
|
||||||
|
|
@ -84,11 +84,11 @@
|
||||||
|
|
||||||
// strength reduction
|
// strength reduction
|
||||||
// TODO: do this a lot more generically
|
// TODO: do this a lot more generically
|
||||||
(MULQconst [c] x) && c.(int64) == 8 -> (SHLQconst [int64(3)] x)
|
(MULQconst [8] x) -> (SHLQconst [3] x)
|
||||||
(MULQconst [c] x) && c.(int64) == 64 -> (SHLQconst [int64(5)] x)
|
(MULQconst [64] x) -> (SHLQconst [5] x)
|
||||||
|
|
||||||
// fold add/shift into leaq
|
// fold add/shift into leaq
|
||||||
(ADDQ x (SHLQconst [shift] y)) && shift.(int64) == 3 -> (LEAQ8 [int64(0)] x y)
|
(ADDQ x (SHLQconst [3] y)) -> (LEAQ8 x y)
|
||||||
(ADDQconst [c] (LEAQ8 [d] x y)) -> (LEAQ8 [addOff(c, d)] x y)
|
(ADDQconst [c] (LEAQ8 [d] x y)) -> (LEAQ8 [addOff(c, d)] x y)
|
||||||
|
|
||||||
// reverse ordering of compare instruction
|
// reverse ordering of compare instruction
|
||||||
|
|
@ -110,7 +110,7 @@
|
||||||
(MOVQloadidx8 [off1] (ADDQconst [off2] ptr) idx mem) -> (MOVQloadidx8 [addOff(off1, off2)] ptr idx mem)
|
(MOVQloadidx8 [off1] (ADDQconst [off2] ptr) idx mem) -> (MOVQloadidx8 [addOff(off1, off2)] ptr idx mem)
|
||||||
(MOVQstoreidx8 [off1] (ADDQconst [off2] ptr) idx val mem) -> (MOVQstoreidx8 [addOff(off1, off2)] ptr idx val mem)
|
(MOVQstoreidx8 [off1] (ADDQconst [off2] ptr) idx val mem) -> (MOVQstoreidx8 [addOff(off1, off2)] ptr idx val mem)
|
||||||
|
|
||||||
(ADDQconst [off] x) && off.(int64) == 0 -> (Copy x)
|
(ADDQconst [0] x) -> (Copy x)
|
||||||
|
|
||||||
// Absorb InvertFlags into branches.
|
// Absorb InvertFlags into branches.
|
||||||
(LT (InvertFlags cmp) yes no) -> (GT cmp yes no)
|
(LT (InvertFlags cmp) yes no) -> (GT cmp yes no)
|
||||||
|
|
@ -125,9 +125,9 @@
|
||||||
(NE (InvertFlags cmp) yes no) -> (NE cmp yes no)
|
(NE (InvertFlags cmp) yes no) -> (NE cmp yes no)
|
||||||
|
|
||||||
// get rid of >=64 code for constant shifts
|
// get rid of >=64 code for constant shifts
|
||||||
(SBBQcarrymask (CMPQconst [c] (MOVQconst [d]))) && inBounds(d.(int64), c.(int64)) -> (Const [int64(-1)])
|
(SBBQcarrymask (CMPQconst [c] (MOVQconst [d]))) && inBounds(d, c) -> (Const [-1])
|
||||||
(SBBQcarrymask (CMPQconst [c] (MOVQconst [d]))) && !inBounds(d.(int64), c.(int64)) -> (Const [int64(0)])
|
(SBBQcarrymask (CMPQconst [c] (MOVQconst [d]))) && !inBounds(d, c) -> (Const [0])
|
||||||
(ANDQconst [c] _) && c.(int64) == 0 -> (MOVQconst [int64(0)])
|
(ANDQconst [0] _) -> (MOVQconst [0])
|
||||||
(ANDQconst [c] x) && c.(int64) == -1 -> (Copy x)
|
(ANDQconst [-1] x) -> (Copy x)
|
||||||
(CMOVQCC (CMPQconst [c] (MOVQconst [d])) _ x) && inBounds(d.(int64), c.(int64)) -> (Copy x)
|
(CMOVQCC (CMPQconst [c] (MOVQconst [d])) _ x) && inBounds(d, c) -> (Copy x)
|
||||||
(CMOVQCC (CMPQconst [c] (MOVQconst [d])) x _) && !inBounds(d.(int64), c.(int64)) -> (Copy x)
|
(CMOVQCC (CMPQconst [c] (MOVQconst [d])) x _) && !inBounds(d, c) -> (Copy x)
|
||||||
|
|
|
||||||
|
|
@ -93,24 +93,24 @@ func init() {
|
||||||
// TODO: 2-address instructions. Mark ops as needing matching input/output regs.
|
// TODO: 2-address instructions. Mark ops as needing matching input/output regs.
|
||||||
var AMD64ops = []opData{
|
var AMD64ops = []opData{
|
||||||
{name: "ADDQ", reg: gp21}, // arg0 + arg1
|
{name: "ADDQ", reg: gp21}, // arg0 + arg1
|
||||||
{name: "ADDQconst", reg: gp11}, // arg0 + aux.(int64)
|
{name: "ADDQconst", reg: gp11}, // arg0 + auxint
|
||||||
{name: "SUBQ", reg: gp21}, // arg0 - arg1
|
{name: "SUBQ", reg: gp21}, // arg0 - arg1
|
||||||
{name: "SUBQconst", reg: gp11}, // arg0 - aux.(int64)
|
{name: "SUBQconst", reg: gp11}, // arg0 - auxint
|
||||||
{name: "MULQ", reg: gp21}, // arg0 * arg1
|
{name: "MULQ", reg: gp21}, // arg0 * arg1
|
||||||
{name: "MULQconst", reg: gp11}, // arg0 * aux.(int64)
|
{name: "MULQconst", reg: gp11}, // arg0 * auxint
|
||||||
{name: "ANDQ", reg: gp21}, // arg0 & arg1
|
{name: "ANDQ", reg: gp21}, // arg0 & arg1
|
||||||
{name: "ANDQconst", reg: gp11}, // arg0 & aux.(int64)
|
{name: "ANDQconst", reg: gp11}, // arg0 & auxint
|
||||||
{name: "SHLQ", reg: gp21shift}, // arg0 << arg1, shift amount is mod 64
|
{name: "SHLQ", reg: gp21shift}, // arg0 << arg1, shift amount is mod 64
|
||||||
{name: "SHLQconst", reg: gp11}, // arg0 << aux.(int64), shift amount 0-63
|
{name: "SHLQconst", reg: gp11}, // arg0 << auxint, shift amount 0-63
|
||||||
{name: "SHRQ", reg: gp21shift}, // unsigned arg0 >> arg1, shift amount is mod 64
|
{name: "SHRQ", reg: gp21shift}, // unsigned arg0 >> arg1, shift amount is mod 64
|
||||||
{name: "SHRQconst", reg: gp11}, // unsigned arg0 >> aux.(int64), shift amount 0-63
|
{name: "SHRQconst", reg: gp11}, // unsigned arg0 >> auxint, shift amount 0-63
|
||||||
{name: "SARQ", reg: gp21shift}, // signed arg0 >> arg1, shift amount is mod 64
|
{name: "SARQ", reg: gp21shift}, // signed arg0 >> arg1, shift amount is mod 64
|
||||||
{name: "SARQconst", reg: gp11}, // signed arg0 >> aux.(int64), shift amount 0-63
|
{name: "SARQconst", reg: gp11}, // signed arg0 >> auxint, shift amount 0-63
|
||||||
|
|
||||||
{name: "NEGQ", reg: gp11}, // -arg0
|
{name: "NEGQ", reg: gp11}, // -arg0
|
||||||
|
|
||||||
{name: "CMPQ", reg: gp2flags}, // arg0 compare to arg1
|
{name: "CMPQ", reg: gp2flags}, // arg0 compare to arg1
|
||||||
{name: "CMPQconst", reg: gp1flags}, // arg0 compare to aux.(int64)
|
{name: "CMPQconst", reg: gp1flags}, // arg0 compare to auxint
|
||||||
{name: "TESTQ", reg: gp2flags}, // (arg0 & arg1) compare to 0
|
{name: "TESTQ", reg: gp2flags}, // (arg0 & arg1) compare to 0
|
||||||
{name: "TESTB", reg: gp2flags}, // (arg0 & arg1) compare to 0
|
{name: "TESTB", reg: gp2flags}, // (arg0 & arg1) compare to 0
|
||||||
|
|
||||||
|
|
@ -125,21 +125,21 @@ func init() {
|
||||||
|
|
||||||
{name: "CMOVQCC", reg: cmov}, // carry clear
|
{name: "CMOVQCC", reg: cmov}, // carry clear
|
||||||
|
|
||||||
{name: "MOVQconst", reg: gp01}, // aux.(int64)
|
{name: "MOVQconst", reg: gp01}, // auxint
|
||||||
{name: "LEAQ", reg: gp21}, // arg0 + arg1 + aux.(int64)
|
{name: "LEAQ", reg: gp21}, // arg0 + arg1 + auxint
|
||||||
{name: "LEAQ2", reg: gp21}, // arg0 + 2*arg1 + aux.(int64)
|
{name: "LEAQ2", reg: gp21}, // arg0 + 2*arg1 + auxint
|
||||||
{name: "LEAQ4", reg: gp21}, // arg0 + 4*arg1 + aux.(int64)
|
{name: "LEAQ4", reg: gp21}, // arg0 + 4*arg1 + auxint
|
||||||
{name: "LEAQ8", reg: gp21}, // arg0 + 8*arg1 + aux.(int64)
|
{name: "LEAQ8", reg: gp21}, // arg0 + 8*arg1 + auxint
|
||||||
{name: "LEAQglobal", reg: gp01}, // no args. address of aux.(GlobalOffset)
|
{name: "LEAQglobal", reg: gp01}, // no args. address of aux.(*gc.Sym)
|
||||||
|
|
||||||
{name: "MOVBload", reg: gpload}, // load byte from arg0+aux.(int64). arg1=mem
|
{name: "MOVBload", reg: gpload}, // load byte from arg0+auxint. arg1=mem
|
||||||
{name: "MOVBQZXload", reg: gpload}, // ditto, extend to uint64
|
{name: "MOVBQZXload", reg: gpload}, // ditto, extend to uint64
|
||||||
{name: "MOVBQSXload", reg: gpload}, // ditto, extend to int64
|
{name: "MOVBQSXload", reg: gpload}, // ditto, extend to int64
|
||||||
{name: "MOVQload", reg: gpload}, // load 8 bytes from arg0+aux.(int64). arg1=mem
|
{name: "MOVQload", reg: gpload}, // load 8 bytes from arg0+auxint. arg1=mem
|
||||||
{name: "MOVQloadidx8", reg: gploadidx}, // load 8 bytes from arg0+8*arg1+aux.(int64). arg2=mem
|
{name: "MOVQloadidx8", reg: gploadidx}, // load 8 bytes from arg0+8*arg1+auxint. arg2=mem
|
||||||
{name: "MOVBstore", reg: gpstore}, // store byte in arg1 to arg0+aux.(int64). arg2=mem
|
{name: "MOVBstore", reg: gpstore}, // store byte in arg1 to arg0+auxint. arg2=mem
|
||||||
{name: "MOVQstore", reg: gpstore}, // store 8 bytes in arg1 to arg0+aux.(int64). arg2=mem
|
{name: "MOVQstore", reg: gpstore}, // store 8 bytes in arg1 to arg0+auxint. arg2=mem
|
||||||
{name: "MOVQstoreidx8", reg: gpstoreidx}, // store 8 bytes in arg2 to arg0+8*arg1+aux.(int64). arg3=mem
|
{name: "MOVQstoreidx8", reg: gpstoreidx}, // store 8 bytes in arg2 to arg0+8*arg1+auxint. arg3=mem
|
||||||
|
|
||||||
// Load/store from global. Same as the above loads, but arg0 is missing and
|
// Load/store from global. Same as the above loads, but arg0 is missing and
|
||||||
// aux is a GlobalOffset instead of an int64.
|
// aux is a GlobalOffset instead of an int64.
|
||||||
|
|
@ -147,7 +147,7 @@ func init() {
|
||||||
{name: "MOVQstoreglobal"}, // store arg0 to aux.(GlobalOffset). arg1=memory, returns memory.
|
{name: "MOVQstoreglobal"}, // store arg0 to aux.(GlobalOffset). arg1=memory, returns memory.
|
||||||
|
|
||||||
//TODO: set register clobber to everything?
|
//TODO: set register clobber to everything?
|
||||||
{name: "CALLstatic"}, // call static function. arg0=mem, returns mem
|
{name: "CALLstatic"}, // call static function aux.(*gc.Sym). arg0=mem, returns mem
|
||||||
{name: "CALLclosure", reg: regInfo{[]regMask{gpsp, buildReg("DX"), 0}, 0, nil}}, // call function via closure. arg0=codeptr, arg1=closure, arg2=mem returns mem
|
{name: "CALLclosure", reg: regInfo{[]regMask{gpsp, buildReg("DX"), 0}, 0, nil}}, // call function via closure. arg0=codeptr, arg1=closure, arg2=mem returns mem
|
||||||
|
|
||||||
{name: "REPMOVSB", reg: regInfo{[]regMask{buildReg("DI"), buildReg("SI"), buildReg("CX")}, buildReg("DI SI CX"), nil}}, // move arg2 bytes from arg1 to arg0. arg3=mem, returns memory
|
{name: "REPMOVSB", reg: regInfo{[]regMask{buildReg("DI"), buildReg("SI"), buildReg("CX")}, buildReg("DI SI CX"), nil}}, // move arg2 bytes from arg1 to arg0. arg3=mem, returns memory
|
||||||
|
|
|
||||||
|
|
@ -3,13 +3,14 @@
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
// values are specified using the following format:
|
// values are specified using the following format:
|
||||||
// (op <type> [aux] arg0 arg1 ...)
|
// (op <type> [auxint] {aux} arg0 arg1 ...)
|
||||||
// the type and aux fields are optional
|
// the type and aux fields are optional
|
||||||
// on the matching side
|
// on the matching side
|
||||||
// - the types and aux fields must match if they are specified.
|
// - the type, aux, and auxint fields must match if they are specified.
|
||||||
// on the generated side
|
// on the generated side
|
||||||
// - the type of the top-level expression is the same as the one on the left-hand side.
|
// - 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.
|
// - the type of any subexpressions must be specified explicitly.
|
||||||
|
// - auxint will be 0 if not specified.
|
||||||
// - aux will be nil if not specified.
|
// - aux will be nil if not specified.
|
||||||
|
|
||||||
// blocks are specified using the following format:
|
// blocks are specified using the following format:
|
||||||
|
|
@ -19,15 +20,15 @@
|
||||||
// For now, the generated successors must be a permutation of the matched successors.
|
// For now, the generated successors must be a permutation of the matched successors.
|
||||||
|
|
||||||
// constant folding
|
// constant folding
|
||||||
(Add <t> (Const [c]) (Const [d])) && is64BitInt(t) -> (Const [{c.(int64)+d.(int64)}])
|
(Add <t> (Const [c]) (Const [d])) && is64BitInt(t) -> (Const [c+d])
|
||||||
(Mul <t> (Const [c]) (Const [d])) && is64BitInt(t) -> (Const [{c.(int64)*d.(int64)}])
|
(Mul <t> (Const [c]) (Const [d])) && is64BitInt(t) -> (Const [c*d])
|
||||||
(IsInBounds (Const [c]) (Const [d])) -> (Const [inBounds(c.(int64),d.(int64))])
|
(IsInBounds (Const [c]) (Const [d])) -> (Const {inBounds(c,d)})
|
||||||
|
|
||||||
// tear apart slices
|
// tear apart slices
|
||||||
// TODO: anything that generates a slice needs to go in here.
|
// TODO: anything that generates a slice needs to go in here.
|
||||||
(SlicePtr (Load ptr mem)) -> (Load ptr mem)
|
(SlicePtr (Load ptr mem)) -> (Load ptr mem)
|
||||||
(SliceLen (Load ptr mem)) -> (Load (Add <ptr.Type> ptr (Const <config.Uintptr> [int64(config.ptrSize)])) mem)
|
(SliceLen (Load ptr mem)) -> (Load (Add <ptr.Type> ptr (Const <config.Uintptr> [config.ptrSize])) mem)
|
||||||
(SliceCap (Load ptr mem)) -> (Load (Add <ptr.Type> ptr (Const <config.Uintptr> [int64(config.ptrSize*2)])) mem)
|
(SliceCap (Load ptr mem)) -> (Load (Add <ptr.Type> ptr (Const <config.Uintptr> [config.ptrSize*2])) mem)
|
||||||
|
|
||||||
// indexing operations
|
// indexing operations
|
||||||
// Note: bounds check has already been done
|
// Note: bounds check has already been done
|
||||||
|
|
@ -39,11 +40,11 @@
|
||||||
(Store dst (Load <t> src mem) mem) && t.Size() > 8 -> (Move [t.Size()] dst src mem)
|
(Store dst (Load <t> src mem) mem) && t.Size() > 8 -> (Move [t.Size()] dst src mem)
|
||||||
|
|
||||||
// string ops
|
// string ops
|
||||||
(Const <t> [s]) && t.IsString() -> (StringMake (OffPtr <TypeBytePtr> [2*config.ptrSize] (Global <TypeBytePtr> [config.fe.StringSym(s.(string))])) (Const <config.Uintptr> [int64(len(s.(string)))])) // TODO: ptr
|
(Const <t> {s}) && t.IsString() -> (StringMake (OffPtr <TypeBytePtr> [2*config.ptrSize] (Global <TypeBytePtr> {config.fe.StringSym(s.(string))})) (Const <config.Uintptr> [int64(len(s.(string)))])) // TODO: ptr
|
||||||
(Load <t> ptr mem) && t.IsString() -> (StringMake (Load <TypeBytePtr> ptr mem) (Load <config.Uintptr> (OffPtr <TypeBytePtr> [config.ptrSize] ptr) mem))
|
(Load <t> ptr mem) && t.IsString() -> (StringMake (Load <TypeBytePtr> ptr mem) (Load <config.Uintptr> (OffPtr <TypeBytePtr> [config.ptrSize] ptr) mem))
|
||||||
(StringPtr (StringMake ptr _)) -> ptr
|
(StringPtr (StringMake ptr _)) -> ptr
|
||||||
(StringLen (StringMake _ len)) -> len
|
(StringLen (StringMake _ len)) -> len
|
||||||
(Store dst str mem) && str.Type.IsString() -> (Store (OffPtr <TypeBytePtr> [config.ptrSize] dst) (StringLen <config.Uintptr> str) (Store <TypeMem> dst (StringPtr <TypeBytePtr> str) mem))
|
(Store dst str mem) && str.Type.IsString() -> (Store (OffPtr <TypeBytePtr> [config.ptrSize] dst) (StringLen <config.Uintptr> str) (Store <TypeMem> dst (StringPtr <TypeBytePtr> str) mem))
|
||||||
|
|
||||||
(If (Const [c]) yes no) && c.(bool) -> (Plain nil yes)
|
(If (Const {c}) yes no) && c.(bool) -> (Plain nil yes)
|
||||||
(If (Const [c]) yes no) && !c.(bool) -> (Plain nil no)
|
(If (Const {c}) yes no) && !c.(bool) -> (Plain nil no)
|
||||||
|
|
|
||||||
|
|
@ -37,9 +37,9 @@ var genericOps = []opData{
|
||||||
{name: "Func"}, // entry address of a function
|
{name: "Func"}, // entry address of a function
|
||||||
|
|
||||||
// Memory operations
|
// Memory operations
|
||||||
{name: "Load"}, // Load from arg0+aux.(int64). arg1=memory
|
{name: "Load"}, // Load from arg0. arg1=memory
|
||||||
{name: "Store"}, // Store arg1 to arg0+aux.(int64). arg2=memory. Returns memory.
|
{name: "Store"}, // Store arg1 to arg0. arg2=memory. Returns memory.
|
||||||
{name: "Move"}, // arg0=destptr, arg1=srcptr, arg2=mem, aux.(int64)=size. Returns memory.
|
{name: "Move"}, // arg0=destptr, arg1=srcptr, arg2=mem, auxint=size. Returns memory.
|
||||||
|
|
||||||
// Function calls. Arguments to the call have already been written to the stack.
|
// 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
|
// Return values appear on the stack. The method receiver, if any, is treated
|
||||||
|
|
@ -58,7 +58,7 @@ var genericOps = []opData{
|
||||||
// Indexing operations
|
// Indexing operations
|
||||||
{name: "ArrayIndex"}, // arg0=array, arg1=index. Returns a[i]
|
{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: "PtrIndex"}, // arg0=ptr, arg1=index. Computes ptr+sizeof(*v.type)*index, where index is extended to ptrwidth type
|
||||||
{name: "OffPtr"}, // arg0 + aux.(int64) (arg0 and result are pointers)
|
{name: "OffPtr"}, // arg0 + auxint (arg0 and result are pointers)
|
||||||
|
|
||||||
// Slices
|
// Slices
|
||||||
{name: "SliceMake"}, // arg0=ptr, arg1=len, arg2=cap
|
{name: "SliceMake"}, // arg0=ptr, arg1=len, arg2=cap
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
"regexp"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
@ -29,9 +30,9 @@ import (
|
||||||
// sexpr are s-expressions (lisp-like parenthesized groupings)
|
// sexpr are s-expressions (lisp-like parenthesized groupings)
|
||||||
// sexpr ::= (opcode sexpr*)
|
// sexpr ::= (opcode sexpr*)
|
||||||
// | variable
|
// | variable
|
||||||
// | [aux]
|
|
||||||
// | <type>
|
// | <type>
|
||||||
// | {code}
|
// | [auxint]
|
||||||
|
// | {aux}
|
||||||
//
|
//
|
||||||
// aux ::= variable | {code}
|
// aux ::= variable | {code}
|
||||||
// type ::= variable | {code}
|
// type ::= variable | {code}
|
||||||
|
|
@ -310,9 +311,9 @@ func genMatch0(w io.Writer, arch arch, match, v, fail string, m map[string]strin
|
||||||
if a[0] == '<' {
|
if a[0] == '<' {
|
||||||
// type restriction
|
// type restriction
|
||||||
t := a[1 : len(a)-1] // remove <>
|
t := a[1 : len(a)-1] // remove <>
|
||||||
if t[0] == '{' {
|
if !isVariable(t) {
|
||||||
// code. We must match the results of this code.
|
// code. We must match the results of this code.
|
||||||
fmt.Fprintf(w, "if %s.Type != %s %s", v, t[1:len(t)-1], fail)
|
fmt.Fprintf(w, "if %s.Type != %s %s", v, t, fail)
|
||||||
} else {
|
} else {
|
||||||
// variable
|
// variable
|
||||||
if u, ok := m[t]; ok {
|
if u, ok := m[t]; ok {
|
||||||
|
|
@ -324,11 +325,26 @@ func genMatch0(w io.Writer, arch arch, match, v, fail string, m map[string]strin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if a[0] == '[' {
|
} else if a[0] == '[' {
|
||||||
// aux restriction
|
// auxint restriction
|
||||||
x := a[1 : len(a)-1] // remove []
|
x := a[1 : len(a)-1] // remove []
|
||||||
if x[0] == '{' {
|
if !isVariable(x) {
|
||||||
// code
|
// code
|
||||||
fmt.Fprintf(w, "if %s.Aux != %s %s", v, x[1:len(x)-1], fail)
|
fmt.Fprintf(w, "if %s.AuxInt != %s %s", v, x, fail)
|
||||||
|
} else {
|
||||||
|
// variable
|
||||||
|
if y, ok := m[x]; ok {
|
||||||
|
fmt.Fprintf(w, "if %s.AuxInt != %s %s", v, y, fail)
|
||||||
|
} else {
|
||||||
|
m[x] = v + ".AuxInt"
|
||||||
|
fmt.Fprintf(w, "%s := %s.AuxInt\n", x, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if a[0] == '{' {
|
||||||
|
// auxint restriction
|
||||||
|
x := a[1 : len(a)-1] // remove {}
|
||||||
|
if !isVariable(x) {
|
||||||
|
// code
|
||||||
|
fmt.Fprintf(w, "if %s.Aux != %s %s", v, x, fail)
|
||||||
} else {
|
} else {
|
||||||
// variable
|
// variable
|
||||||
if y, ok := m[x]; ok {
|
if y, ok := m[x]; ok {
|
||||||
|
|
@ -338,9 +354,6 @@ func genMatch0(w io.Writer, arch arch, match, v, fail string, m map[string]strin
|
||||||
fmt.Fprintf(w, "%s := %s.Aux\n", x, v)
|
fmt.Fprintf(w, "%s := %s.Aux\n", x, v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if a[0] == '{' {
|
|
||||||
fmt.Fprintf(w, "if %s.Args[%d] != %s %s", v, argnum, a[1:len(a)-1], fail)
|
|
||||||
argnum++
|
|
||||||
} else {
|
} else {
|
||||||
// variable or sexpr
|
// variable or sexpr
|
||||||
genMatch0(w, arch, a, fmt.Sprintf("%s.Args[%d]", v, argnum), fail, m, false)
|
genMatch0(w, arch, a, fmt.Sprintf("%s.Args[%d]", v, argnum), fail, m, false)
|
||||||
|
|
@ -357,6 +370,7 @@ func genResult0(w io.Writer, arch arch, result string, alloc *int, top bool) str
|
||||||
// variable
|
// variable
|
||||||
if top {
|
if top {
|
||||||
fmt.Fprintf(w, "v.Op = %s.Op\n", result)
|
fmt.Fprintf(w, "v.Op = %s.Op\n", result)
|
||||||
|
fmt.Fprintf(w, "v.AuxInt = %s.AuxInt\n", result)
|
||||||
fmt.Fprintf(w, "v.Aux = %s.Aux\n", result)
|
fmt.Fprintf(w, "v.Aux = %s.Aux\n", result)
|
||||||
fmt.Fprintf(w, "v.resetArgs()\n")
|
fmt.Fprintf(w, "v.resetArgs()\n")
|
||||||
fmt.Fprintf(w, "v.AddArgs(%s.Args...)\n", result)
|
fmt.Fprintf(w, "v.AddArgs(%s.Args...)\n", result)
|
||||||
|
|
@ -370,32 +384,29 @@ func genResult0(w io.Writer, arch arch, result string, alloc *int, top bool) str
|
||||||
if top {
|
if top {
|
||||||
v = "v"
|
v = "v"
|
||||||
fmt.Fprintf(w, "v.Op = %s\n", opName(s[0], arch))
|
fmt.Fprintf(w, "v.Op = %s\n", opName(s[0], arch))
|
||||||
|
fmt.Fprintf(w, "v.AuxInt = 0\n")
|
||||||
fmt.Fprintf(w, "v.Aux = nil\n")
|
fmt.Fprintf(w, "v.Aux = nil\n")
|
||||||
fmt.Fprintf(w, "v.resetArgs()\n")
|
fmt.Fprintf(w, "v.resetArgs()\n")
|
||||||
hasType = true
|
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(v.Line, %s, TypeInvalid, nil)\n", v, opName(s[0], arch))
|
fmt.Fprintf(w, "%s := v.Block.NewValue0(v.Line, %s, TypeInvalid)\n", v, opName(s[0], arch))
|
||||||
}
|
}
|
||||||
for _, a := range s[1:] {
|
for _, a := range s[1:] {
|
||||||
if a[0] == '<' {
|
if a[0] == '<' {
|
||||||
// type restriction
|
// type restriction
|
||||||
t := a[1 : len(a)-1] // remove <>
|
t := a[1 : len(a)-1] // remove <>
|
||||||
if t[0] == '{' {
|
|
||||||
t = t[1 : len(t)-1] // remove {}
|
|
||||||
}
|
|
||||||
fmt.Fprintf(w, "%s.Type = %s\n", v, t)
|
fmt.Fprintf(w, "%s.Type = %s\n", v, t)
|
||||||
hasType = true
|
hasType = true
|
||||||
} else if a[0] == '[' {
|
} else if a[0] == '[' {
|
||||||
// aux restriction
|
// auxint restriction
|
||||||
x := a[1 : len(a)-1] // remove []
|
x := a[1 : len(a)-1] // remove []
|
||||||
if x[0] == '{' {
|
fmt.Fprintf(w, "%s.AuxInt = %s\n", v, x)
|
||||||
x = x[1 : len(x)-1] // remove {}
|
|
||||||
}
|
|
||||||
fmt.Fprintf(w, "%s.Aux = %s\n", v, x)
|
|
||||||
} else if a[0] == '{' {
|
} else if a[0] == '{' {
|
||||||
fmt.Fprintf(w, "%s.AddArg(%s)\n", v, a[1:len(a)-1])
|
// aux restriction
|
||||||
|
x := a[1 : len(a)-1] // remove {}
|
||||||
|
fmt.Fprintf(w, "%s.Aux = %s\n", v, x)
|
||||||
} else {
|
} else {
|
||||||
// regular argument (sexpr or variable)
|
// regular argument (sexpr or variable)
|
||||||
x := genResult0(w, arch, a, alloc, false)
|
x := genResult0(w, arch, a, alloc, false)
|
||||||
|
|
@ -504,3 +515,12 @@ func unbalanced(s string) bool {
|
||||||
}
|
}
|
||||||
return left != right
|
return left != right
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// isVariable reports whether s is a single Go alphanumeric identifier.
|
||||||
|
func isVariable(s string) bool {
|
||||||
|
b, err := regexp.MatchString("[A-Za-z_][A-Za-z_0-9]*", s)
|
||||||
|
if err != nil {
|
||||||
|
panic("bad variable regexp")
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,424 +0,0 @@
|
||||||
// autogenerated from rulegen/generic.rules: do not edit!
|
|
||||||
// generated with: go run rulegen/rulegen.go rulegen/generic.rules genericBlockRules genericValueRules generic.go
|
|
||||||
package ssa
|
|
||||||
|
|
||||||
func genericValueRules(v *Value, config *Config) bool {
|
|
||||||
switch v.Op {
|
|
||||||
case OpAdd:
|
|
||||||
// match: (Add <t> (Const [c]) (Const [d]))
|
|
||||||
// cond: is64BitInt(t)
|
|
||||||
// result: (Const [{c.(int64)+d.(int64)}])
|
|
||||||
{
|
|
||||||
t := v.Type
|
|
||||||
if v.Args[0].Op != OpConst {
|
|
||||||
goto end8d047ed0ae9537b840adc79ea82c6e05
|
|
||||||
}
|
|
||||||
c := v.Args[0].Aux
|
|
||||||
if v.Args[1].Op != OpConst {
|
|
||||||
goto end8d047ed0ae9537b840adc79ea82c6e05
|
|
||||||
}
|
|
||||||
d := v.Args[1].Aux
|
|
||||||
if !(is64BitInt(t)) {
|
|
||||||
goto end8d047ed0ae9537b840adc79ea82c6e05
|
|
||||||
}
|
|
||||||
v.Op = OpConst
|
|
||||||
v.Aux = nil
|
|
||||||
v.resetArgs()
|
|
||||||
v.Aux = c.(int64) + d.(int64)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
goto end8d047ed0ae9537b840adc79ea82c6e05
|
|
||||||
end8d047ed0ae9537b840adc79ea82c6e05:
|
|
||||||
;
|
|
||||||
case OpArrayIndex:
|
|
||||||
// match: (ArrayIndex (Load ptr mem) idx)
|
|
||||||
// cond:
|
|
||||||
// result: (Load (PtrIndex <ptr.Type.Elem().Elem().PtrTo()> ptr idx) mem)
|
|
||||||
{
|
|
||||||
if v.Args[0].Op != OpLoad {
|
|
||||||
goto end3809f4c52270a76313e4ea26e6f0b753
|
|
||||||
}
|
|
||||||
ptr := v.Args[0].Args[0]
|
|
||||||
mem := v.Args[0].Args[1]
|
|
||||||
idx := v.Args[1]
|
|
||||||
v.Op = OpLoad
|
|
||||||
v.Aux = nil
|
|
||||||
v.resetArgs()
|
|
||||||
v0 := v.Block.NewValue(v.Line, OpPtrIndex, TypeInvalid, nil)
|
|
||||||
v0.Type = ptr.Type.Elem().Elem().PtrTo()
|
|
||||||
v0.AddArg(ptr)
|
|
||||||
v0.AddArg(idx)
|
|
||||||
v.AddArg(v0)
|
|
||||||
v.AddArg(mem)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
goto end3809f4c52270a76313e4ea26e6f0b753
|
|
||||||
end3809f4c52270a76313e4ea26e6f0b753:
|
|
||||||
;
|
|
||||||
case OpConst:
|
|
||||||
// match: (Const <t> [s])
|
|
||||||
// cond: t.IsString()
|
|
||||||
// result: (StringMake (OffPtr <TypeBytePtr> [2*config.ptrSize] (Global <TypeBytePtr> [config.fe.StringSym(s.(string))])) (Const <config.Uintptr> [int64(len(s.(string)))]))
|
|
||||||
{
|
|
||||||
t := v.Type
|
|
||||||
s := v.Aux
|
|
||||||
if !(t.IsString()) {
|
|
||||||
goto end8442aa5b3f4e5b840055475883110372
|
|
||||||
}
|
|
||||||
v.Op = OpStringMake
|
|
||||||
v.Aux = nil
|
|
||||||
v.resetArgs()
|
|
||||||
v0 := v.Block.NewValue(v.Line, OpOffPtr, TypeInvalid, nil)
|
|
||||||
v0.Type = TypeBytePtr
|
|
||||||
v0.Aux = 2 * config.ptrSize
|
|
||||||
v1 := v.Block.NewValue(v.Line, OpGlobal, TypeInvalid, nil)
|
|
||||||
v1.Type = TypeBytePtr
|
|
||||||
v1.Aux = config.fe.StringSym(s.(string))
|
|
||||||
v0.AddArg(v1)
|
|
||||||
v.AddArg(v0)
|
|
||||||
v2 := v.Block.NewValue(v.Line, OpConst, TypeInvalid, nil)
|
|
||||||
v2.Type = config.Uintptr
|
|
||||||
v2.Aux = int64(len(s.(string)))
|
|
||||||
v.AddArg(v2)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
goto end8442aa5b3f4e5b840055475883110372
|
|
||||||
end8442aa5b3f4e5b840055475883110372:
|
|
||||||
;
|
|
||||||
case OpIsInBounds:
|
|
||||||
// match: (IsInBounds (Const [c]) (Const [d]))
|
|
||||||
// cond:
|
|
||||||
// result: (Const [inBounds(c.(int64),d.(int64))])
|
|
||||||
{
|
|
||||||
if v.Args[0].Op != OpConst {
|
|
||||||
goto enddbd1a394d9b71ee64335361b8384865c
|
|
||||||
}
|
|
||||||
c := v.Args[0].Aux
|
|
||||||
if v.Args[1].Op != OpConst {
|
|
||||||
goto enddbd1a394d9b71ee64335361b8384865c
|
|
||||||
}
|
|
||||||
d := v.Args[1].Aux
|
|
||||||
v.Op = OpConst
|
|
||||||
v.Aux = nil
|
|
||||||
v.resetArgs()
|
|
||||||
v.Aux = inBounds(c.(int64), d.(int64))
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
goto enddbd1a394d9b71ee64335361b8384865c
|
|
||||||
enddbd1a394d9b71ee64335361b8384865c:
|
|
||||||
;
|
|
||||||
case OpLoad:
|
|
||||||
// match: (Load <t> ptr mem)
|
|
||||||
// cond: t.IsString()
|
|
||||||
// result: (StringMake (Load <TypeBytePtr> ptr mem) (Load <config.Uintptr> (OffPtr <TypeBytePtr> [config.ptrSize] ptr) mem))
|
|
||||||
{
|
|
||||||
t := v.Type
|
|
||||||
ptr := v.Args[0]
|
|
||||||
mem := v.Args[1]
|
|
||||||
if !(t.IsString()) {
|
|
||||||
goto endd0afd003b70d726a1c5bbaf51fe06182
|
|
||||||
}
|
|
||||||
v.Op = OpStringMake
|
|
||||||
v.Aux = nil
|
|
||||||
v.resetArgs()
|
|
||||||
v0 := v.Block.NewValue(v.Line, OpLoad, TypeInvalid, nil)
|
|
||||||
v0.Type = TypeBytePtr
|
|
||||||
v0.AddArg(ptr)
|
|
||||||
v0.AddArg(mem)
|
|
||||||
v.AddArg(v0)
|
|
||||||
v1 := v.Block.NewValue(v.Line, OpLoad, TypeInvalid, nil)
|
|
||||||
v1.Type = config.Uintptr
|
|
||||||
v2 := v.Block.NewValue(v.Line, OpOffPtr, TypeInvalid, nil)
|
|
||||||
v2.Type = TypeBytePtr
|
|
||||||
v2.Aux = config.ptrSize
|
|
||||||
v2.AddArg(ptr)
|
|
||||||
v1.AddArg(v2)
|
|
||||||
v1.AddArg(mem)
|
|
||||||
v.AddArg(v1)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
goto endd0afd003b70d726a1c5bbaf51fe06182
|
|
||||||
endd0afd003b70d726a1c5bbaf51fe06182:
|
|
||||||
;
|
|
||||||
case OpMul:
|
|
||||||
// match: (Mul <t> (Const [c]) (Const [d]))
|
|
||||||
// cond: is64BitInt(t)
|
|
||||||
// result: (Const [{c.(int64)*d.(int64)}])
|
|
||||||
{
|
|
||||||
t := v.Type
|
|
||||||
if v.Args[0].Op != OpConst {
|
|
||||||
goto end776610f88cf04f438242d76ed2b14f1c
|
|
||||||
}
|
|
||||||
c := v.Args[0].Aux
|
|
||||||
if v.Args[1].Op != OpConst {
|
|
||||||
goto end776610f88cf04f438242d76ed2b14f1c
|
|
||||||
}
|
|
||||||
d := v.Args[1].Aux
|
|
||||||
if !(is64BitInt(t)) {
|
|
||||||
goto end776610f88cf04f438242d76ed2b14f1c
|
|
||||||
}
|
|
||||||
v.Op = OpConst
|
|
||||||
v.Aux = nil
|
|
||||||
v.resetArgs()
|
|
||||||
v.Aux = c.(int64) * d.(int64)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
goto end776610f88cf04f438242d76ed2b14f1c
|
|
||||||
end776610f88cf04f438242d76ed2b14f1c:
|
|
||||||
;
|
|
||||||
case OpPtrIndex:
|
|
||||||
// match: (PtrIndex <t> ptr idx)
|
|
||||||
// cond:
|
|
||||||
// result: (Add ptr (Mul <config.Uintptr> idx (Const <config.Uintptr> [t.Elem().Size()])))
|
|
||||||
{
|
|
||||||
t := v.Type
|
|
||||||
ptr := v.Args[0]
|
|
||||||
idx := v.Args[1]
|
|
||||||
v.Op = OpAdd
|
|
||||||
v.Aux = nil
|
|
||||||
v.resetArgs()
|
|
||||||
v.AddArg(ptr)
|
|
||||||
v0 := v.Block.NewValue(v.Line, OpMul, TypeInvalid, nil)
|
|
||||||
v0.Type = config.Uintptr
|
|
||||||
v0.AddArg(idx)
|
|
||||||
v1 := v.Block.NewValue(v.Line, OpConst, TypeInvalid, nil)
|
|
||||||
v1.Type = config.Uintptr
|
|
||||||
v1.Aux = t.Elem().Size()
|
|
||||||
v0.AddArg(v1)
|
|
||||||
v.AddArg(v0)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
goto end88c7c383675420d1581daeb899039fa8
|
|
||||||
end88c7c383675420d1581daeb899039fa8:
|
|
||||||
;
|
|
||||||
case OpSliceCap:
|
|
||||||
// match: (SliceCap (Load ptr mem))
|
|
||||||
// cond:
|
|
||||||
// result: (Load (Add <ptr.Type> ptr (Const <config.Uintptr> [int64(config.ptrSize*2)])) mem)
|
|
||||||
{
|
|
||||||
if v.Args[0].Op != OpLoad {
|
|
||||||
goto endc871dcd9a720b4290c9cae78fe147c8a
|
|
||||||
}
|
|
||||||
ptr := v.Args[0].Args[0]
|
|
||||||
mem := v.Args[0].Args[1]
|
|
||||||
v.Op = OpLoad
|
|
||||||
v.Aux = nil
|
|
||||||
v.resetArgs()
|
|
||||||
v0 := v.Block.NewValue(v.Line, OpAdd, TypeInvalid, nil)
|
|
||||||
v0.Type = ptr.Type
|
|
||||||
v0.AddArg(ptr)
|
|
||||||
v1 := v.Block.NewValue(v.Line, OpConst, TypeInvalid, nil)
|
|
||||||
v1.Type = config.Uintptr
|
|
||||||
v1.Aux = int64(config.ptrSize * 2)
|
|
||||||
v0.AddArg(v1)
|
|
||||||
v.AddArg(v0)
|
|
||||||
v.AddArg(mem)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
goto endc871dcd9a720b4290c9cae78fe147c8a
|
|
||||||
endc871dcd9a720b4290c9cae78fe147c8a:
|
|
||||||
;
|
|
||||||
case OpSliceLen:
|
|
||||||
// match: (SliceLen (Load ptr mem))
|
|
||||||
// cond:
|
|
||||||
// result: (Load (Add <ptr.Type> ptr (Const <config.Uintptr> [int64(config.ptrSize)])) mem)
|
|
||||||
{
|
|
||||||
if v.Args[0].Op != OpLoad {
|
|
||||||
goto end1eec05e44f5fc8944e7c176f98a74d92
|
|
||||||
}
|
|
||||||
ptr := v.Args[0].Args[0]
|
|
||||||
mem := v.Args[0].Args[1]
|
|
||||||
v.Op = OpLoad
|
|
||||||
v.Aux = nil
|
|
||||||
v.resetArgs()
|
|
||||||
v0 := v.Block.NewValue(v.Line, OpAdd, TypeInvalid, nil)
|
|
||||||
v0.Type = ptr.Type
|
|
||||||
v0.AddArg(ptr)
|
|
||||||
v1 := v.Block.NewValue(v.Line, OpConst, TypeInvalid, nil)
|
|
||||||
v1.Type = config.Uintptr
|
|
||||||
v1.Aux = int64(config.ptrSize)
|
|
||||||
v0.AddArg(v1)
|
|
||||||
v.AddArg(v0)
|
|
||||||
v.AddArg(mem)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
goto end1eec05e44f5fc8944e7c176f98a74d92
|
|
||||||
end1eec05e44f5fc8944e7c176f98a74d92:
|
|
||||||
;
|
|
||||||
case OpSlicePtr:
|
|
||||||
// match: (SlicePtr (Load ptr mem))
|
|
||||||
// cond:
|
|
||||||
// result: (Load ptr mem)
|
|
||||||
{
|
|
||||||
if v.Args[0].Op != OpLoad {
|
|
||||||
goto end459613b83f95b65729d45c2ed663a153
|
|
||||||
}
|
|
||||||
ptr := v.Args[0].Args[0]
|
|
||||||
mem := v.Args[0].Args[1]
|
|
||||||
v.Op = OpLoad
|
|
||||||
v.Aux = nil
|
|
||||||
v.resetArgs()
|
|
||||||
v.AddArg(ptr)
|
|
||||||
v.AddArg(mem)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
goto end459613b83f95b65729d45c2ed663a153
|
|
||||||
end459613b83f95b65729d45c2ed663a153:
|
|
||||||
;
|
|
||||||
case OpStore:
|
|
||||||
// match: (Store dst (Load <t> src mem) mem)
|
|
||||||
// cond: t.Size() > 8
|
|
||||||
// result: (Move [t.Size()] dst src mem)
|
|
||||||
{
|
|
||||||
dst := v.Args[0]
|
|
||||||
if v.Args[1].Op != OpLoad {
|
|
||||||
goto end324ffb6d2771808da4267f62c854e9c8
|
|
||||||
}
|
|
||||||
t := v.Args[1].Type
|
|
||||||
src := v.Args[1].Args[0]
|
|
||||||
mem := v.Args[1].Args[1]
|
|
||||||
if v.Args[2] != v.Args[1].Args[1] {
|
|
||||||
goto end324ffb6d2771808da4267f62c854e9c8
|
|
||||||
}
|
|
||||||
if !(t.Size() > 8) {
|
|
||||||
goto end324ffb6d2771808da4267f62c854e9c8
|
|
||||||
}
|
|
||||||
v.Op = OpMove
|
|
||||||
v.Aux = nil
|
|
||||||
v.resetArgs()
|
|
||||||
v.Aux = t.Size()
|
|
||||||
v.AddArg(dst)
|
|
||||||
v.AddArg(src)
|
|
||||||
v.AddArg(mem)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
goto end324ffb6d2771808da4267f62c854e9c8
|
|
||||||
end324ffb6d2771808da4267f62c854e9c8:
|
|
||||||
;
|
|
||||||
// match: (Store dst str mem)
|
|
||||||
// cond: str.Type.IsString()
|
|
||||||
// result: (Store (OffPtr <TypeBytePtr> [config.ptrSize] dst) (StringLen <config.Uintptr> str) (Store <TypeMem> dst (StringPtr <TypeBytePtr> str) mem))
|
|
||||||
{
|
|
||||||
dst := v.Args[0]
|
|
||||||
str := v.Args[1]
|
|
||||||
mem := v.Args[2]
|
|
||||||
if !(str.Type.IsString()) {
|
|
||||||
goto end410559d97aed8018f820cd88723de442
|
|
||||||
}
|
|
||||||
v.Op = OpStore
|
|
||||||
v.Aux = nil
|
|
||||||
v.resetArgs()
|
|
||||||
v0 := v.Block.NewValue(v.Line, OpOffPtr, TypeInvalid, nil)
|
|
||||||
v0.Type = TypeBytePtr
|
|
||||||
v0.Aux = config.ptrSize
|
|
||||||
v0.AddArg(dst)
|
|
||||||
v.AddArg(v0)
|
|
||||||
v1 := v.Block.NewValue(v.Line, OpStringLen, TypeInvalid, nil)
|
|
||||||
v1.Type = config.Uintptr
|
|
||||||
v1.AddArg(str)
|
|
||||||
v.AddArg(v1)
|
|
||||||
v2 := v.Block.NewValue(v.Line, OpStore, TypeInvalid, nil)
|
|
||||||
v2.Type = TypeMem
|
|
||||||
v2.AddArg(dst)
|
|
||||||
v3 := v.Block.NewValue(v.Line, OpStringPtr, TypeInvalid, nil)
|
|
||||||
v3.Type = TypeBytePtr
|
|
||||||
v3.AddArg(str)
|
|
||||||
v2.AddArg(v3)
|
|
||||||
v2.AddArg(mem)
|
|
||||||
v.AddArg(v2)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
goto end410559d97aed8018f820cd88723de442
|
|
||||||
end410559d97aed8018f820cd88723de442:
|
|
||||||
;
|
|
||||||
case OpStringLen:
|
|
||||||
// match: (StringLen (StringMake _ len))
|
|
||||||
// cond:
|
|
||||||
// result: len
|
|
||||||
{
|
|
||||||
if v.Args[0].Op != OpStringMake {
|
|
||||||
goto end0d922460b7e5ca88324034f4bd6c027c
|
|
||||||
}
|
|
||||||
len := v.Args[0].Args[1]
|
|
||||||
v.Op = len.Op
|
|
||||||
v.Aux = len.Aux
|
|
||||||
v.resetArgs()
|
|
||||||
v.AddArgs(len.Args...)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
goto end0d922460b7e5ca88324034f4bd6c027c
|
|
||||||
end0d922460b7e5ca88324034f4bd6c027c:
|
|
||||||
;
|
|
||||||
case OpStringPtr:
|
|
||||||
// match: (StringPtr (StringMake ptr _))
|
|
||||||
// cond:
|
|
||||||
// result: ptr
|
|
||||||
{
|
|
||||||
if v.Args[0].Op != OpStringMake {
|
|
||||||
goto end061edc5d85c73ad909089af2556d9380
|
|
||||||
}
|
|
||||||
ptr := v.Args[0].Args[0]
|
|
||||||
v.Op = ptr.Op
|
|
||||||
v.Aux = ptr.Aux
|
|
||||||
v.resetArgs()
|
|
||||||
v.AddArgs(ptr.Args...)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
goto end061edc5d85c73ad909089af2556d9380
|
|
||||||
end061edc5d85c73ad909089af2556d9380:
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
func genericBlockRules(b *Block) bool {
|
|
||||||
switch b.Kind {
|
|
||||||
case BlockIf:
|
|
||||||
// match: (BlockIf (Const [c]) yes no)
|
|
||||||
// cond: c.(bool)
|
|
||||||
// result: (BlockPlain nil yes)
|
|
||||||
{
|
|
||||||
v := b.Control
|
|
||||||
if v.Op != OpConst {
|
|
||||||
goto endbe39807508a6192b4022c7293eb6e114
|
|
||||||
}
|
|
||||||
c := v.Aux
|
|
||||||
yes := b.Succs[0]
|
|
||||||
no := b.Succs[1]
|
|
||||||
if !(c.(bool)) {
|
|
||||||
goto endbe39807508a6192b4022c7293eb6e114
|
|
||||||
}
|
|
||||||
removePredecessor(b, no)
|
|
||||||
b.Kind = BlockPlain
|
|
||||||
b.Control = nil
|
|
||||||
b.Succs = b.Succs[:1]
|
|
||||||
b.Succs[0] = yes
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
goto endbe39807508a6192b4022c7293eb6e114
|
|
||||||
endbe39807508a6192b4022c7293eb6e114:
|
|
||||||
;
|
|
||||||
// match: (BlockIf (Const [c]) yes no)
|
|
||||||
// cond: !c.(bool)
|
|
||||||
// result: (BlockPlain nil no)
|
|
||||||
{
|
|
||||||
v := b.Control
|
|
||||||
if v.Op != OpConst {
|
|
||||||
goto end69ac35957ebe0a77a5ef5103c1f79fbf
|
|
||||||
}
|
|
||||||
c := v.Aux
|
|
||||||
yes := b.Succs[0]
|
|
||||||
no := b.Succs[1]
|
|
||||||
if !(!c.(bool)) {
|
|
||||||
goto end69ac35957ebe0a77a5ef5103c1f79fbf
|
|
||||||
}
|
|
||||||
removePredecessor(b, yes)
|
|
||||||
b.Kind = BlockPlain
|
|
||||||
b.Control = nil
|
|
||||||
b.Succs = b.Succs[:1]
|
|
||||||
b.Succs[0] = no
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
goto end69ac35957ebe0a77a5ef5103c1f79fbf
|
|
||||||
end69ac35957ebe0a77a5ef5103c1f79fbf:
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
@ -4,11 +4,6 @@
|
||||||
|
|
||||||
package ssa
|
package ssa
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
)
|
|
||||||
|
|
||||||
// An Op encodes the specific operation that a Value performs.
|
// An Op encodes the specific operation that a Value performs.
|
||||||
// Opcodes' semantics can be modified by the type and aux fields of the Value.
|
// Opcodes' semantics can be modified by the type and aux fields of the Value.
|
||||||
// For instance, OpAdd can be 32 or 64 bit, signed or unsigned, float or complex, depending on Value.Type.
|
// For instance, OpAdd can be 32 or 64 bit, signed or unsigned, float or complex, depending on Value.Type.
|
||||||
|
|
@ -17,26 +12,6 @@ import (
|
||||||
// for each architecture.
|
// for each architecture.
|
||||||
type Op int32
|
type Op int32
|
||||||
|
|
||||||
// GlobalOffset represents a fixed offset within a global variable
|
|
||||||
type GlobalOffset struct {
|
|
||||||
Global interface{} // holds a *gc.Sym
|
|
||||||
Offset int64
|
|
||||||
}
|
|
||||||
|
|
||||||
// offset adds x to the location specified by g and returns it.
|
|
||||||
func (g GlobalOffset) offset(x int64) GlobalOffset {
|
|
||||||
y := g.Offset
|
|
||||||
z := x + y
|
|
||||||
if x^y >= 0 && x^z < 0 {
|
|
||||||
log.Panicf("offset overflow %d %d\n", x, y)
|
|
||||||
}
|
|
||||||
return GlobalOffset{g.Global, z}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (g GlobalOffset) String() string {
|
|
||||||
return fmt.Sprintf("%v+%d", g.Global, g.Offset)
|
|
||||||
}
|
|
||||||
|
|
||||||
type opInfo struct {
|
type opInfo struct {
|
||||||
name string
|
name string
|
||||||
reg regInfo
|
reg regInfo
|
||||||
|
|
|
||||||
|
|
@ -262,25 +262,23 @@ func regalloc(f *Func) {
|
||||||
if len(w.Args) == 0 {
|
if len(w.Args) == 0 {
|
||||||
// Materialize w
|
// Materialize w
|
||||||
if w.Op == OpFP || w.Op == OpSP || w.Op == OpGlobal {
|
if w.Op == OpFP || w.Op == OpSP || w.Op == OpGlobal {
|
||||||
c = b.NewValue1(w.Line, OpCopy, w.Type, nil, w)
|
c = b.NewValue1(w.Line, OpCopy, w.Type, w)
|
||||||
} else {
|
} else {
|
||||||
c = b.NewValue(w.Line, w.Op, w.Type, w.Aux)
|
c = b.NewValue0IA(w.Line, w.Op, w.Type, w.AuxInt, w.Aux)
|
||||||
}
|
}
|
||||||
} else if len(w.Args) == 1 && (w.Args[0].Op == OpFP || w.Args[0].Op == OpSP || w.Args[0].Op == OpGlobal) {
|
} else if len(w.Args) == 1 && (w.Args[0].Op == OpFP || w.Args[0].Op == OpSP || w.Args[0].Op == OpGlobal) {
|
||||||
// Materialize offsets from SP/FP/Global
|
// Materialize offsets from SP/FP/Global
|
||||||
c = b.NewValue1(w.Line, w.Op, w.Type, w.Aux, w.Args[0])
|
c = b.NewValue1IA(w.Line, w.Op, w.Type, w.AuxInt, w.Aux, w.Args[0])
|
||||||
} else if wreg != 0 {
|
} else if wreg != 0 {
|
||||||
// Copy from another register.
|
// Copy from another register.
|
||||||
// Typically just an optimization, but this is
|
// Typically just an optimization, but this is
|
||||||
// required if w is dirty.
|
// required if w is dirty.
|
||||||
s := pickReg(wreg)
|
s := pickReg(wreg)
|
||||||
// inv: s != r
|
// inv: s != r
|
||||||
c = b.NewValue(w.Line, OpCopy, w.Type, nil)
|
c = b.NewValue1(w.Line, OpCopy, w.Type, regs[s].c)
|
||||||
c.AddArg(regs[s].c)
|
|
||||||
} else {
|
} else {
|
||||||
// Load from home location
|
// Load from home location
|
||||||
c = b.NewValue(w.Line, OpLoadReg8, w.Type, nil)
|
c = b.NewValue1(w.Line, OpLoadReg8, w.Type, w)
|
||||||
c.AddArg(w)
|
|
||||||
}
|
}
|
||||||
home = setloc(home, c, ®isters[r])
|
home = setloc(home, c, ®isters[r])
|
||||||
// Remember what we did
|
// Remember what we did
|
||||||
|
|
@ -337,7 +335,7 @@ func regalloc(f *Func) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reissue v with new op, with r as its home.
|
// Reissue v with new op, with r as its home.
|
||||||
c := b.NewValue(v.Line, v.Op, v.Type, v.Aux)
|
c := b.NewValue0IA(v.Line, v.Op, v.Type, v.AuxInt, v.Aux)
|
||||||
c.AddArgs(v.Args...)
|
c.AddArgs(v.Args...)
|
||||||
home = setloc(home, c, ®isters[r])
|
home = setloc(home, c, ®isters[r])
|
||||||
|
|
||||||
|
|
@ -406,7 +404,7 @@ func addPhiCopies(f *Func) {
|
||||||
}
|
}
|
||||||
for i, w := range v.Args {
|
for i, w := range v.Args {
|
||||||
c := b.Preds[i]
|
c := b.Preds[i]
|
||||||
cpy := c.NewValue1(w.Line, OpCopy, v.Type, nil, w)
|
cpy := c.NewValue1(w.Line, OpCopy, v.Type, w)
|
||||||
v.Args[i] = cpy
|
v.Args[i] = cpy
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -82,11 +82,8 @@ func typeSize(t Type) int64 {
|
||||||
return t.Size()
|
return t.Size()
|
||||||
}
|
}
|
||||||
|
|
||||||
// addOff adds two offset aux values. Each should be an int64. Fails if wraparound happens.
|
// addOff adds two int64 offsets. Fails if wraparound happens.
|
||||||
func addOff(a, b interface{}) interface{} {
|
func addOff(x, y int64) int64 {
|
||||||
return addOffset(a.(int64), b.(int64))
|
|
||||||
}
|
|
||||||
func addOffset(x, y int64) int64 {
|
|
||||||
z := x + y
|
z := x + y
|
||||||
// x and y have same sign and z has a different sign => overflow
|
// x and y have same sign and z has a different sign => overflow
|
||||||
if x^y >= 0 && x^z < 0 {
|
if x^y >= 0 && x^z < 0 {
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -7,28 +7,29 @@ func rewriteValuegeneric(v *Value, config *Config) bool {
|
||||||
case OpAdd:
|
case OpAdd:
|
||||||
// match: (Add <t> (Const [c]) (Const [d]))
|
// match: (Add <t> (Const [c]) (Const [d]))
|
||||||
// cond: is64BitInt(t)
|
// cond: is64BitInt(t)
|
||||||
// result: (Const [{c.(int64)+d.(int64)}])
|
// result: (Const [c+d])
|
||||||
{
|
{
|
||||||
t := v.Type
|
t := v.Type
|
||||||
if v.Args[0].Op != OpConst {
|
if v.Args[0].Op != OpConst {
|
||||||
goto end8d047ed0ae9537b840adc79ea82c6e05
|
goto end279f4ea85ed10e5ffc5b53f9e060529b
|
||||||
}
|
}
|
||||||
c := v.Args[0].Aux
|
c := v.Args[0].AuxInt
|
||||||
if v.Args[1].Op != OpConst {
|
if v.Args[1].Op != OpConst {
|
||||||
goto end8d047ed0ae9537b840adc79ea82c6e05
|
goto end279f4ea85ed10e5ffc5b53f9e060529b
|
||||||
}
|
}
|
||||||
d := v.Args[1].Aux
|
d := v.Args[1].AuxInt
|
||||||
if !(is64BitInt(t)) {
|
if !(is64BitInt(t)) {
|
||||||
goto end8d047ed0ae9537b840adc79ea82c6e05
|
goto end279f4ea85ed10e5ffc5b53f9e060529b
|
||||||
}
|
}
|
||||||
v.Op = OpConst
|
v.Op = OpConst
|
||||||
|
v.AuxInt = 0
|
||||||
v.Aux = nil
|
v.Aux = nil
|
||||||
v.resetArgs()
|
v.resetArgs()
|
||||||
v.Aux = c.(int64) + d.(int64)
|
v.AuxInt = c + d
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
goto end8d047ed0ae9537b840adc79ea82c6e05
|
goto end279f4ea85ed10e5ffc5b53f9e060529b
|
||||||
end8d047ed0ae9537b840adc79ea82c6e05:
|
end279f4ea85ed10e5ffc5b53f9e060529b:
|
||||||
;
|
;
|
||||||
case OpArrayIndex:
|
case OpArrayIndex:
|
||||||
// match: (ArrayIndex (Load ptr mem) idx)
|
// match: (ArrayIndex (Load ptr mem) idx)
|
||||||
|
|
@ -42,9 +43,10 @@ func rewriteValuegeneric(v *Value, config *Config) bool {
|
||||||
mem := v.Args[0].Args[1]
|
mem := v.Args[0].Args[1]
|
||||||
idx := v.Args[1]
|
idx := v.Args[1]
|
||||||
v.Op = OpLoad
|
v.Op = OpLoad
|
||||||
|
v.AuxInt = 0
|
||||||
v.Aux = nil
|
v.Aux = nil
|
||||||
v.resetArgs()
|
v.resetArgs()
|
||||||
v0 := v.Block.NewValue(v.Line, OpPtrIndex, TypeInvalid, nil)
|
v0 := v.Block.NewValue0(v.Line, OpPtrIndex, TypeInvalid)
|
||||||
v0.Type = ptr.Type.Elem().Elem().PtrTo()
|
v0.Type = ptr.Type.Elem().Elem().PtrTo()
|
||||||
v0.AddArg(ptr)
|
v0.AddArg(ptr)
|
||||||
v0.AddArg(idx)
|
v0.AddArg(idx)
|
||||||
|
|
@ -56,56 +58,58 @@ func rewriteValuegeneric(v *Value, config *Config) bool {
|
||||||
end3809f4c52270a76313e4ea26e6f0b753:
|
end3809f4c52270a76313e4ea26e6f0b753:
|
||||||
;
|
;
|
||||||
case OpConst:
|
case OpConst:
|
||||||
// match: (Const <t> [s])
|
// match: (Const <t> {s})
|
||||||
// cond: t.IsString()
|
// cond: t.IsString()
|
||||||
// result: (StringMake (OffPtr <TypeBytePtr> [2*config.ptrSize] (Global <TypeBytePtr> [config.fe.StringSym(s.(string))])) (Const <config.Uintptr> [int64(len(s.(string)))]))
|
// result: (StringMake (OffPtr <TypeBytePtr> [2*config.ptrSize] (Global <TypeBytePtr> {config.fe.StringSym(s.(string))})) (Const <config.Uintptr> [int64(len(s.(string)))]))
|
||||||
{
|
{
|
||||||
t := v.Type
|
t := v.Type
|
||||||
s := v.Aux
|
s := v.Aux
|
||||||
if !(t.IsString()) {
|
if !(t.IsString()) {
|
||||||
goto end8442aa5b3f4e5b840055475883110372
|
goto end6d6321106a054a5984b2ed0acec52a5b
|
||||||
}
|
}
|
||||||
v.Op = OpStringMake
|
v.Op = OpStringMake
|
||||||
|
v.AuxInt = 0
|
||||||
v.Aux = nil
|
v.Aux = nil
|
||||||
v.resetArgs()
|
v.resetArgs()
|
||||||
v0 := v.Block.NewValue(v.Line, OpOffPtr, TypeInvalid, nil)
|
v0 := v.Block.NewValue0(v.Line, OpOffPtr, TypeInvalid)
|
||||||
v0.Type = TypeBytePtr
|
v0.Type = TypeBytePtr
|
||||||
v0.Aux = 2 * config.ptrSize
|
v0.AuxInt = 2 * config.ptrSize
|
||||||
v1 := v.Block.NewValue(v.Line, OpGlobal, TypeInvalid, nil)
|
v1 := v.Block.NewValue0(v.Line, OpGlobal, TypeInvalid)
|
||||||
v1.Type = TypeBytePtr
|
v1.Type = TypeBytePtr
|
||||||
v1.Aux = config.fe.StringSym(s.(string))
|
v1.Aux = config.fe.StringSym(s.(string))
|
||||||
v0.AddArg(v1)
|
v0.AddArg(v1)
|
||||||
v.AddArg(v0)
|
v.AddArg(v0)
|
||||||
v2 := v.Block.NewValue(v.Line, OpConst, TypeInvalid, nil)
|
v2 := v.Block.NewValue0(v.Line, OpConst, TypeInvalid)
|
||||||
v2.Type = config.Uintptr
|
v2.Type = config.Uintptr
|
||||||
v2.Aux = int64(len(s.(string)))
|
v2.AuxInt = int64(len(s.(string)))
|
||||||
v.AddArg(v2)
|
v.AddArg(v2)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
goto end8442aa5b3f4e5b840055475883110372
|
goto end6d6321106a054a5984b2ed0acec52a5b
|
||||||
end8442aa5b3f4e5b840055475883110372:
|
end6d6321106a054a5984b2ed0acec52a5b:
|
||||||
;
|
;
|
||||||
case OpIsInBounds:
|
case OpIsInBounds:
|
||||||
// match: (IsInBounds (Const [c]) (Const [d]))
|
// match: (IsInBounds (Const [c]) (Const [d]))
|
||||||
// cond:
|
// cond:
|
||||||
// result: (Const [inBounds(c.(int64),d.(int64))])
|
// result: (Const {inBounds(c,d)})
|
||||||
{
|
{
|
||||||
if v.Args[0].Op != OpConst {
|
if v.Args[0].Op != OpConst {
|
||||||
goto enddbd1a394d9b71ee64335361b8384865c
|
goto enda96ccac78df2d17ae96c8baf2af2e189
|
||||||
}
|
}
|
||||||
c := v.Args[0].Aux
|
c := v.Args[0].AuxInt
|
||||||
if v.Args[1].Op != OpConst {
|
if v.Args[1].Op != OpConst {
|
||||||
goto enddbd1a394d9b71ee64335361b8384865c
|
goto enda96ccac78df2d17ae96c8baf2af2e189
|
||||||
}
|
}
|
||||||
d := v.Args[1].Aux
|
d := v.Args[1].AuxInt
|
||||||
v.Op = OpConst
|
v.Op = OpConst
|
||||||
|
v.AuxInt = 0
|
||||||
v.Aux = nil
|
v.Aux = nil
|
||||||
v.resetArgs()
|
v.resetArgs()
|
||||||
v.Aux = inBounds(c.(int64), d.(int64))
|
v.Aux = inBounds(c, d)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
goto enddbd1a394d9b71ee64335361b8384865c
|
goto enda96ccac78df2d17ae96c8baf2af2e189
|
||||||
enddbd1a394d9b71ee64335361b8384865c:
|
enda96ccac78df2d17ae96c8baf2af2e189:
|
||||||
;
|
;
|
||||||
case OpLoad:
|
case OpLoad:
|
||||||
// match: (Load <t> ptr mem)
|
// match: (Load <t> ptr mem)
|
||||||
|
|
@ -119,18 +123,19 @@ func rewriteValuegeneric(v *Value, config *Config) bool {
|
||||||
goto endd0afd003b70d726a1c5bbaf51fe06182
|
goto endd0afd003b70d726a1c5bbaf51fe06182
|
||||||
}
|
}
|
||||||
v.Op = OpStringMake
|
v.Op = OpStringMake
|
||||||
|
v.AuxInt = 0
|
||||||
v.Aux = nil
|
v.Aux = nil
|
||||||
v.resetArgs()
|
v.resetArgs()
|
||||||
v0 := v.Block.NewValue(v.Line, OpLoad, TypeInvalid, nil)
|
v0 := v.Block.NewValue0(v.Line, OpLoad, TypeInvalid)
|
||||||
v0.Type = TypeBytePtr
|
v0.Type = TypeBytePtr
|
||||||
v0.AddArg(ptr)
|
v0.AddArg(ptr)
|
||||||
v0.AddArg(mem)
|
v0.AddArg(mem)
|
||||||
v.AddArg(v0)
|
v.AddArg(v0)
|
||||||
v1 := v.Block.NewValue(v.Line, OpLoad, TypeInvalid, nil)
|
v1 := v.Block.NewValue0(v.Line, OpLoad, TypeInvalid)
|
||||||
v1.Type = config.Uintptr
|
v1.Type = config.Uintptr
|
||||||
v2 := v.Block.NewValue(v.Line, OpOffPtr, TypeInvalid, nil)
|
v2 := v.Block.NewValue0(v.Line, OpOffPtr, TypeInvalid)
|
||||||
v2.Type = TypeBytePtr
|
v2.Type = TypeBytePtr
|
||||||
v2.Aux = config.ptrSize
|
v2.AuxInt = config.ptrSize
|
||||||
v2.AddArg(ptr)
|
v2.AddArg(ptr)
|
||||||
v1.AddArg(v2)
|
v1.AddArg(v2)
|
||||||
v1.AddArg(mem)
|
v1.AddArg(mem)
|
||||||
|
|
@ -143,28 +148,29 @@ func rewriteValuegeneric(v *Value, config *Config) bool {
|
||||||
case OpMul:
|
case OpMul:
|
||||||
// match: (Mul <t> (Const [c]) (Const [d]))
|
// match: (Mul <t> (Const [c]) (Const [d]))
|
||||||
// cond: is64BitInt(t)
|
// cond: is64BitInt(t)
|
||||||
// result: (Const [{c.(int64)*d.(int64)}])
|
// result: (Const [c*d])
|
||||||
{
|
{
|
||||||
t := v.Type
|
t := v.Type
|
||||||
if v.Args[0].Op != OpConst {
|
if v.Args[0].Op != OpConst {
|
||||||
goto end776610f88cf04f438242d76ed2b14f1c
|
goto endd82095c6a872974522d33aaff1ee07be
|
||||||
}
|
}
|
||||||
c := v.Args[0].Aux
|
c := v.Args[0].AuxInt
|
||||||
if v.Args[1].Op != OpConst {
|
if v.Args[1].Op != OpConst {
|
||||||
goto end776610f88cf04f438242d76ed2b14f1c
|
goto endd82095c6a872974522d33aaff1ee07be
|
||||||
}
|
}
|
||||||
d := v.Args[1].Aux
|
d := v.Args[1].AuxInt
|
||||||
if !(is64BitInt(t)) {
|
if !(is64BitInt(t)) {
|
||||||
goto end776610f88cf04f438242d76ed2b14f1c
|
goto endd82095c6a872974522d33aaff1ee07be
|
||||||
}
|
}
|
||||||
v.Op = OpConst
|
v.Op = OpConst
|
||||||
|
v.AuxInt = 0
|
||||||
v.Aux = nil
|
v.Aux = nil
|
||||||
v.resetArgs()
|
v.resetArgs()
|
||||||
v.Aux = c.(int64) * d.(int64)
|
v.AuxInt = c * d
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
goto end776610f88cf04f438242d76ed2b14f1c
|
goto endd82095c6a872974522d33aaff1ee07be
|
||||||
end776610f88cf04f438242d76ed2b14f1c:
|
endd82095c6a872974522d33aaff1ee07be:
|
||||||
;
|
;
|
||||||
case OpPtrIndex:
|
case OpPtrIndex:
|
||||||
// match: (PtrIndex <t> ptr idx)
|
// match: (PtrIndex <t> ptr idx)
|
||||||
|
|
@ -175,15 +181,16 @@ func rewriteValuegeneric(v *Value, config *Config) bool {
|
||||||
ptr := v.Args[0]
|
ptr := v.Args[0]
|
||||||
idx := v.Args[1]
|
idx := v.Args[1]
|
||||||
v.Op = OpAdd
|
v.Op = OpAdd
|
||||||
|
v.AuxInt = 0
|
||||||
v.Aux = nil
|
v.Aux = nil
|
||||||
v.resetArgs()
|
v.resetArgs()
|
||||||
v.AddArg(ptr)
|
v.AddArg(ptr)
|
||||||
v0 := v.Block.NewValue(v.Line, OpMul, TypeInvalid, nil)
|
v0 := v.Block.NewValue0(v.Line, OpMul, TypeInvalid)
|
||||||
v0.Type = config.Uintptr
|
v0.Type = config.Uintptr
|
||||||
v0.AddArg(idx)
|
v0.AddArg(idx)
|
||||||
v1 := v.Block.NewValue(v.Line, OpConst, TypeInvalid, nil)
|
v1 := v.Block.NewValue0(v.Line, OpConst, TypeInvalid)
|
||||||
v1.Type = config.Uintptr
|
v1.Type = config.Uintptr
|
||||||
v1.Aux = t.Elem().Size()
|
v1.AuxInt = t.Elem().Size()
|
||||||
v0.AddArg(v1)
|
v0.AddArg(v1)
|
||||||
v.AddArg(v0)
|
v.AddArg(v0)
|
||||||
return true
|
return true
|
||||||
|
|
@ -194,56 +201,58 @@ func rewriteValuegeneric(v *Value, config *Config) bool {
|
||||||
case OpSliceCap:
|
case OpSliceCap:
|
||||||
// match: (SliceCap (Load ptr mem))
|
// match: (SliceCap (Load ptr mem))
|
||||||
// cond:
|
// cond:
|
||||||
// result: (Load (Add <ptr.Type> ptr (Const <config.Uintptr> [int64(config.ptrSize*2)])) mem)
|
// result: (Load (Add <ptr.Type> ptr (Const <config.Uintptr> [config.ptrSize*2])) mem)
|
||||||
{
|
{
|
||||||
if v.Args[0].Op != OpLoad {
|
if v.Args[0].Op != OpLoad {
|
||||||
goto endc871dcd9a720b4290c9cae78fe147c8a
|
goto end919cfa3d3539eb2e06a435d5f89654b9
|
||||||
}
|
}
|
||||||
ptr := v.Args[0].Args[0]
|
ptr := v.Args[0].Args[0]
|
||||||
mem := v.Args[0].Args[1]
|
mem := v.Args[0].Args[1]
|
||||||
v.Op = OpLoad
|
v.Op = OpLoad
|
||||||
|
v.AuxInt = 0
|
||||||
v.Aux = nil
|
v.Aux = nil
|
||||||
v.resetArgs()
|
v.resetArgs()
|
||||||
v0 := v.Block.NewValue(v.Line, OpAdd, TypeInvalid, nil)
|
v0 := v.Block.NewValue0(v.Line, OpAdd, TypeInvalid)
|
||||||
v0.Type = ptr.Type
|
v0.Type = ptr.Type
|
||||||
v0.AddArg(ptr)
|
v0.AddArg(ptr)
|
||||||
v1 := v.Block.NewValue(v.Line, OpConst, TypeInvalid, nil)
|
v1 := v.Block.NewValue0(v.Line, OpConst, TypeInvalid)
|
||||||
v1.Type = config.Uintptr
|
v1.Type = config.Uintptr
|
||||||
v1.Aux = int64(config.ptrSize * 2)
|
v1.AuxInt = config.ptrSize * 2
|
||||||
v0.AddArg(v1)
|
v0.AddArg(v1)
|
||||||
v.AddArg(v0)
|
v.AddArg(v0)
|
||||||
v.AddArg(mem)
|
v.AddArg(mem)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
goto endc871dcd9a720b4290c9cae78fe147c8a
|
goto end919cfa3d3539eb2e06a435d5f89654b9
|
||||||
endc871dcd9a720b4290c9cae78fe147c8a:
|
end919cfa3d3539eb2e06a435d5f89654b9:
|
||||||
;
|
;
|
||||||
case OpSliceLen:
|
case OpSliceLen:
|
||||||
// match: (SliceLen (Load ptr mem))
|
// match: (SliceLen (Load ptr mem))
|
||||||
// cond:
|
// cond:
|
||||||
// result: (Load (Add <ptr.Type> ptr (Const <config.Uintptr> [int64(config.ptrSize)])) mem)
|
// result: (Load (Add <ptr.Type> ptr (Const <config.Uintptr> [config.ptrSize])) mem)
|
||||||
{
|
{
|
||||||
if v.Args[0].Op != OpLoad {
|
if v.Args[0].Op != OpLoad {
|
||||||
goto end1eec05e44f5fc8944e7c176f98a74d92
|
goto end3d74a5ef07180a709a91052da88bcd01
|
||||||
}
|
}
|
||||||
ptr := v.Args[0].Args[0]
|
ptr := v.Args[0].Args[0]
|
||||||
mem := v.Args[0].Args[1]
|
mem := v.Args[0].Args[1]
|
||||||
v.Op = OpLoad
|
v.Op = OpLoad
|
||||||
|
v.AuxInt = 0
|
||||||
v.Aux = nil
|
v.Aux = nil
|
||||||
v.resetArgs()
|
v.resetArgs()
|
||||||
v0 := v.Block.NewValue(v.Line, OpAdd, TypeInvalid, nil)
|
v0 := v.Block.NewValue0(v.Line, OpAdd, TypeInvalid)
|
||||||
v0.Type = ptr.Type
|
v0.Type = ptr.Type
|
||||||
v0.AddArg(ptr)
|
v0.AddArg(ptr)
|
||||||
v1 := v.Block.NewValue(v.Line, OpConst, TypeInvalid, nil)
|
v1 := v.Block.NewValue0(v.Line, OpConst, TypeInvalid)
|
||||||
v1.Type = config.Uintptr
|
v1.Type = config.Uintptr
|
||||||
v1.Aux = int64(config.ptrSize)
|
v1.AuxInt = config.ptrSize
|
||||||
v0.AddArg(v1)
|
v0.AddArg(v1)
|
||||||
v.AddArg(v0)
|
v.AddArg(v0)
|
||||||
v.AddArg(mem)
|
v.AddArg(mem)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
goto end1eec05e44f5fc8944e7c176f98a74d92
|
goto end3d74a5ef07180a709a91052da88bcd01
|
||||||
end1eec05e44f5fc8944e7c176f98a74d92:
|
end3d74a5ef07180a709a91052da88bcd01:
|
||||||
;
|
;
|
||||||
case OpSlicePtr:
|
case OpSlicePtr:
|
||||||
// match: (SlicePtr (Load ptr mem))
|
// match: (SlicePtr (Load ptr mem))
|
||||||
|
|
@ -256,6 +265,7 @@ func rewriteValuegeneric(v *Value, config *Config) bool {
|
||||||
ptr := v.Args[0].Args[0]
|
ptr := v.Args[0].Args[0]
|
||||||
mem := v.Args[0].Args[1]
|
mem := v.Args[0].Args[1]
|
||||||
v.Op = OpLoad
|
v.Op = OpLoad
|
||||||
|
v.AuxInt = 0
|
||||||
v.Aux = nil
|
v.Aux = nil
|
||||||
v.resetArgs()
|
v.resetArgs()
|
||||||
v.AddArg(ptr)
|
v.AddArg(ptr)
|
||||||
|
|
@ -284,9 +294,10 @@ func rewriteValuegeneric(v *Value, config *Config) bool {
|
||||||
goto end324ffb6d2771808da4267f62c854e9c8
|
goto end324ffb6d2771808da4267f62c854e9c8
|
||||||
}
|
}
|
||||||
v.Op = OpMove
|
v.Op = OpMove
|
||||||
|
v.AuxInt = 0
|
||||||
v.Aux = nil
|
v.Aux = nil
|
||||||
v.resetArgs()
|
v.resetArgs()
|
||||||
v.Aux = t.Size()
|
v.AuxInt = t.Size()
|
||||||
v.AddArg(dst)
|
v.AddArg(dst)
|
||||||
v.AddArg(src)
|
v.AddArg(src)
|
||||||
v.AddArg(mem)
|
v.AddArg(mem)
|
||||||
|
|
@ -306,21 +317,22 @@ func rewriteValuegeneric(v *Value, config *Config) bool {
|
||||||
goto end410559d97aed8018f820cd88723de442
|
goto end410559d97aed8018f820cd88723de442
|
||||||
}
|
}
|
||||||
v.Op = OpStore
|
v.Op = OpStore
|
||||||
|
v.AuxInt = 0
|
||||||
v.Aux = nil
|
v.Aux = nil
|
||||||
v.resetArgs()
|
v.resetArgs()
|
||||||
v0 := v.Block.NewValue(v.Line, OpOffPtr, TypeInvalid, nil)
|
v0 := v.Block.NewValue0(v.Line, OpOffPtr, TypeInvalid)
|
||||||
v0.Type = TypeBytePtr
|
v0.Type = TypeBytePtr
|
||||||
v0.Aux = config.ptrSize
|
v0.AuxInt = config.ptrSize
|
||||||
v0.AddArg(dst)
|
v0.AddArg(dst)
|
||||||
v.AddArg(v0)
|
v.AddArg(v0)
|
||||||
v1 := v.Block.NewValue(v.Line, OpStringLen, TypeInvalid, nil)
|
v1 := v.Block.NewValue0(v.Line, OpStringLen, TypeInvalid)
|
||||||
v1.Type = config.Uintptr
|
v1.Type = config.Uintptr
|
||||||
v1.AddArg(str)
|
v1.AddArg(str)
|
||||||
v.AddArg(v1)
|
v.AddArg(v1)
|
||||||
v2 := v.Block.NewValue(v.Line, OpStore, TypeInvalid, nil)
|
v2 := v.Block.NewValue0(v.Line, OpStore, TypeInvalid)
|
||||||
v2.Type = TypeMem
|
v2.Type = TypeMem
|
||||||
v2.AddArg(dst)
|
v2.AddArg(dst)
|
||||||
v3 := v.Block.NewValue(v.Line, OpStringPtr, TypeInvalid, nil)
|
v3 := v.Block.NewValue0(v.Line, OpStringPtr, TypeInvalid)
|
||||||
v3.Type = TypeBytePtr
|
v3.Type = TypeBytePtr
|
||||||
v3.AddArg(str)
|
v3.AddArg(str)
|
||||||
v2.AddArg(v3)
|
v2.AddArg(v3)
|
||||||
|
|
@ -341,6 +353,7 @@ func rewriteValuegeneric(v *Value, config *Config) bool {
|
||||||
}
|
}
|
||||||
len := v.Args[0].Args[1]
|
len := v.Args[0].Args[1]
|
||||||
v.Op = len.Op
|
v.Op = len.Op
|
||||||
|
v.AuxInt = len.AuxInt
|
||||||
v.Aux = len.Aux
|
v.Aux = len.Aux
|
||||||
v.resetArgs()
|
v.resetArgs()
|
||||||
v.AddArgs(len.Args...)
|
v.AddArgs(len.Args...)
|
||||||
|
|
@ -359,6 +372,7 @@ func rewriteValuegeneric(v *Value, config *Config) bool {
|
||||||
}
|
}
|
||||||
ptr := v.Args[0].Args[0]
|
ptr := v.Args[0].Args[0]
|
||||||
v.Op = ptr.Op
|
v.Op = ptr.Op
|
||||||
|
v.AuxInt = ptr.AuxInt
|
||||||
v.Aux = ptr.Aux
|
v.Aux = ptr.Aux
|
||||||
v.resetArgs()
|
v.resetArgs()
|
||||||
v.AddArgs(ptr.Args...)
|
v.AddArgs(ptr.Args...)
|
||||||
|
|
@ -372,19 +386,19 @@ func rewriteValuegeneric(v *Value, config *Config) bool {
|
||||||
func rewriteBlockgeneric(b *Block) bool {
|
func rewriteBlockgeneric(b *Block) bool {
|
||||||
switch b.Kind {
|
switch b.Kind {
|
||||||
case BlockIf:
|
case BlockIf:
|
||||||
// match: (If (Const [c]) yes no)
|
// match: (If (Const {c}) yes no)
|
||||||
// cond: c.(bool)
|
// cond: c.(bool)
|
||||||
// result: (Plain nil yes)
|
// result: (Plain nil yes)
|
||||||
{
|
{
|
||||||
v := b.Control
|
v := b.Control
|
||||||
if v.Op != OpConst {
|
if v.Op != OpConst {
|
||||||
goto end60cde11c1be8092f493d9cda982445ca
|
goto end915e334b6388fed7d63e09aa69ecb05c
|
||||||
}
|
}
|
||||||
c := v.Aux
|
c := v.Aux
|
||||||
yes := b.Succs[0]
|
yes := b.Succs[0]
|
||||||
no := b.Succs[1]
|
no := b.Succs[1]
|
||||||
if !(c.(bool)) {
|
if !(c.(bool)) {
|
||||||
goto end60cde11c1be8092f493d9cda982445ca
|
goto end915e334b6388fed7d63e09aa69ecb05c
|
||||||
}
|
}
|
||||||
removePredecessor(b, no)
|
removePredecessor(b, no)
|
||||||
b.Kind = BlockPlain
|
b.Kind = BlockPlain
|
||||||
|
|
@ -393,22 +407,22 @@ func rewriteBlockgeneric(b *Block) bool {
|
||||||
b.Succs[0] = yes
|
b.Succs[0] = yes
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
goto end60cde11c1be8092f493d9cda982445ca
|
goto end915e334b6388fed7d63e09aa69ecb05c
|
||||||
end60cde11c1be8092f493d9cda982445ca:
|
end915e334b6388fed7d63e09aa69ecb05c:
|
||||||
;
|
;
|
||||||
// match: (If (Const [c]) yes no)
|
// match: (If (Const {c}) yes no)
|
||||||
// cond: !c.(bool)
|
// cond: !c.(bool)
|
||||||
// result: (Plain nil no)
|
// result: (Plain nil no)
|
||||||
{
|
{
|
||||||
v := b.Control
|
v := b.Control
|
||||||
if v.Op != OpConst {
|
if v.Op != OpConst {
|
||||||
goto endf2a5efbfd2d40dead087c33685c8f30b
|
goto end6452ee3a5bb02c708bddc3181c3ea3cb
|
||||||
}
|
}
|
||||||
c := v.Aux
|
c := v.Aux
|
||||||
yes := b.Succs[0]
|
yes := b.Succs[0]
|
||||||
no := b.Succs[1]
|
no := b.Succs[1]
|
||||||
if !(!c.(bool)) {
|
if !(!c.(bool)) {
|
||||||
goto endf2a5efbfd2d40dead087c33685c8f30b
|
goto end6452ee3a5bb02c708bddc3181c3ea3cb
|
||||||
}
|
}
|
||||||
removePredecessor(b, yes)
|
removePredecessor(b, yes)
|
||||||
b.Kind = BlockPlain
|
b.Kind = BlockPlain
|
||||||
|
|
@ -417,8 +431,8 @@ func rewriteBlockgeneric(b *Block) bool {
|
||||||
b.Succs[0] = no
|
b.Succs[0] = no
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
goto endf2a5efbfd2d40dead087c33685c8f30b
|
goto end6452ee3a5bb02c708bddc3181c3ea3cb
|
||||||
endf2a5efbfd2d40dead087c33685c8f30b:
|
end6452ee3a5bb02c708bddc3181c3ea3cb:
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,15 +11,15 @@ func TestSchedule(t *testing.T) {
|
||||||
cases := []fun{
|
cases := []fun{
|
||||||
Fun(c, "entry",
|
Fun(c, "entry",
|
||||||
Bloc("entry",
|
Bloc("entry",
|
||||||
Valu("mem0", OpArg, TypeMem, ".mem"),
|
Valu("mem0", OpArg, TypeMem, 0, ".mem"),
|
||||||
Valu("ptr", OpConst, TypeInt64, 0xABCD),
|
Valu("ptr", OpConst, TypeInt64, 0xABCD, nil),
|
||||||
Valu("v", OpConst, TypeInt64, 12),
|
Valu("v", OpConst, TypeInt64, 12, nil),
|
||||||
Valu("mem1", OpStore, TypeMem, 32, "ptr", "v", "mem0"),
|
Valu("mem1", OpStore, TypeMem, 0, nil, "ptr", "v", "mem0"),
|
||||||
Valu("mem2", OpStore, TypeMem, 32, "ptr", "v", "mem1"),
|
Valu("mem2", OpStore, TypeMem, 0, nil, "ptr", "v", "mem1"),
|
||||||
Valu("mem3", OpStore, TypeInt64, "ptr", "sum", "mem2"),
|
Valu("mem3", OpStore, TypeInt64, 0, nil, "ptr", "sum", "mem2"),
|
||||||
Valu("l1", OpLoad, TypeInt64, 16, "ptr", "mem1"),
|
Valu("l1", OpLoad, TypeInt64, 0, nil, "ptr", "mem1"),
|
||||||
Valu("l2", OpLoad, TypeInt64, 8, "ptr", "mem2"),
|
Valu("l2", OpLoad, TypeInt64, 0, nil, "ptr", "mem2"),
|
||||||
Valu("sum", OpAdd, TypeInt64, "l1", "l2"),
|
Valu("sum", OpAdd, TypeInt64, 0, nil, "l1", "l2"),
|
||||||
Goto("exit")),
|
Goto("exit")),
|
||||||
Bloc("exit",
|
Bloc("exit",
|
||||||
Exit("mem3"))),
|
Exit("mem3"))),
|
||||||
|
|
|
||||||
|
|
@ -28,14 +28,14 @@ func makeConstShiftFunc(c *Config, amount int64, op Op, typ Type) fun {
|
||||||
ptyp := &TypeImpl{Size_: 8, Ptr: true, Name: "ptr"}
|
ptyp := &TypeImpl{Size_: 8, Ptr: true, Name: "ptr"}
|
||||||
fun := Fun(c, "entry",
|
fun := Fun(c, "entry",
|
||||||
Bloc("entry",
|
Bloc("entry",
|
||||||
Valu("mem", OpArg, TypeMem, ".mem"),
|
Valu("mem", OpArg, TypeMem, 0, ".mem"),
|
||||||
Valu("FP", OpFP, TypeUInt64, nil),
|
Valu("FP", OpFP, TypeUInt64, 0, nil),
|
||||||
Valu("argptr", OpOffPtr, ptyp, int64(8), "FP"),
|
Valu("argptr", OpOffPtr, ptyp, 8, nil, "FP"),
|
||||||
Valu("resptr", OpOffPtr, ptyp, int64(16), "FP"),
|
Valu("resptr", OpOffPtr, ptyp, 16, nil, "FP"),
|
||||||
Valu("load", OpLoad, typ, nil, "argptr", "mem"),
|
Valu("load", OpLoad, typ, 0, nil, "argptr", "mem"),
|
||||||
Valu("c", OpConst, TypeUInt64, amount),
|
Valu("c", OpConst, TypeUInt64, amount, nil),
|
||||||
Valu("shift", op, typ, nil, "load", "c"),
|
Valu("shift", op, typ, 0, nil, "load", "c"),
|
||||||
Valu("store", OpStore, TypeMem, nil, "resptr", "shift", "mem"),
|
Valu("store", OpStore, TypeMem, 0, nil, "resptr", "shift", "mem"),
|
||||||
Exit("store")))
|
Exit("store")))
|
||||||
Compile(fun.f)
|
Compile(fun.f)
|
||||||
return fun
|
return fun
|
||||||
|
|
|
||||||
|
|
@ -92,14 +92,14 @@ func stackalloc(f *Func) {
|
||||||
case OpAMD64ADDQ:
|
case OpAMD64ADDQ:
|
||||||
// (ADDQ (FP) x) -> (LEAQ [n] (SP) x)
|
// (ADDQ (FP) x) -> (LEAQ [n] (SP) x)
|
||||||
v.Op = OpAMD64LEAQ
|
v.Op = OpAMD64LEAQ
|
||||||
v.Aux = n
|
v.AuxInt = n
|
||||||
case OpAMD64LEAQ, OpAMD64MOVQload, OpAMD64MOVQstore, OpAMD64MOVBload, OpAMD64MOVQloadidx8:
|
case OpAMD64LEAQ, OpAMD64MOVQload, OpAMD64MOVQstore, OpAMD64MOVBload, OpAMD64MOVQloadidx8:
|
||||||
if v.Op == OpAMD64MOVQloadidx8 && i == 1 {
|
if v.Op == OpAMD64MOVQloadidx8 && i == 1 {
|
||||||
// Note: we could do it, but it is probably an error
|
// Note: we could do it, but it is probably an error
|
||||||
log.Panicf("can't do FP->SP adjust on index slot of load %s", v.Op)
|
log.Panicf("can't do FP->SP adjust on index slot of load %s", v.Op)
|
||||||
}
|
}
|
||||||
// eg: (MOVQload [c] (FP) mem) -> (MOVQload [c+n] (SP) mem)
|
// eg: (MOVQload [c] (FP) mem) -> (MOVQload [c+n] (SP) mem)
|
||||||
v.Aux = addOffset(v.Aux.(int64), n)
|
v.AuxInt = addOff(v.AuxInt, n)
|
||||||
default:
|
default:
|
||||||
log.Panicf("can't do FP->SP adjust on %s", v.Op)
|
log.Panicf("can't do FP->SP adjust on %s", v.Op)
|
||||||
// TODO: OpCopy -> ADDQ
|
// TODO: OpCopy -> ADDQ
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,9 @@ type Value struct {
|
||||||
Type Type
|
Type Type
|
||||||
|
|
||||||
// Auxiliary info for this value. The type of this information depends on the opcode and type.
|
// Auxiliary info for this value. The type of this information depends on the opcode and type.
|
||||||
Aux interface{}
|
// AuxInt is used for integer values, Aux is used for other values.
|
||||||
|
AuxInt int64
|
||||||
|
Aux interface{}
|
||||||
|
|
||||||
// Arguments of this value
|
// Arguments of this value
|
||||||
Args []*Value
|
Args []*Value
|
||||||
|
|
@ -53,8 +55,11 @@ func (v *Value) String() string {
|
||||||
func (v *Value) LongString() string {
|
func (v *Value) LongString() string {
|
||||||
s := fmt.Sprintf("v%d = %s", v.ID, v.Op.String())
|
s := fmt.Sprintf("v%d = %s", v.ID, v.Op.String())
|
||||||
s += " <" + v.Type.String() + ">"
|
s += " <" + v.Type.String() + ">"
|
||||||
|
if v.AuxInt != 0 {
|
||||||
|
s += fmt.Sprintf(" [%d]", v.AuxInt)
|
||||||
|
}
|
||||||
if v.Aux != nil {
|
if v.Aux != nil {
|
||||||
s += fmt.Sprintf(" [%v]", v.Aux)
|
s += fmt.Sprintf(" {%v}", v.Aux)
|
||||||
}
|
}
|
||||||
for _, a := range v.Args {
|
for _, a := range v.Args {
|
||||||
s += fmt.Sprintf(" %v", a)
|
s += fmt.Sprintf(" %v", a)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue