mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
[dev.ssa] cmd/compile/internal/ssa: add line numbers to Values
Change-Id: I1dfffd75cc1f49307c654f910f7133c03da6c84f Reviewed-on: https://go-review.googlesource.com/10559 Reviewed-by: Keith Randall <khr@golang.org>
This commit is contained in:
parent
43a2676ff0
commit
81ccf508aa
11 changed files with 174 additions and 99 deletions
|
|
@ -18,6 +18,9 @@ func buildssa(fn *Node) *ssa.Func {
|
||||||
|
|
||||||
var s state
|
var s state
|
||||||
|
|
||||||
|
s.pushLine(fn.Lineno)
|
||||||
|
defer s.popLine()
|
||||||
|
|
||||||
// TODO(khr): build config just once at the start of the compiler binary
|
// TODO(khr): build config just once at the start of the compiler binary
|
||||||
s.config = ssa.NewConfig(Thearch.Thestring, ssaExport{})
|
s.config = ssa.NewConfig(Thearch.Thestring, ssaExport{})
|
||||||
s.f = s.config.NewFunc()
|
s.f = s.config.NewFunc()
|
||||||
|
|
@ -35,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.f.Entry.NewValue(ssa.OpArg, ssa.TypeMem, ".mem")
|
s.startmem = s.entryNewValue(ssa.OpArg, ssa.TypeMem, ".mem")
|
||||||
s.fp = s.f.Entry.NewValue(ssa.OpFP, s.config.Uintptr, nil) // TODO: use generic pointer type (unsafe.Pointer?) instead
|
s.fp = s.entryNewValue(ssa.OpFP, s.config.Uintptr, nil) // TODO: use generic pointer type (unsafe.Pointer?) instead
|
||||||
s.sp = s.f.Entry.NewValue(ssa.OpSP, s.config.Uintptr, nil)
|
s.sp = s.entryNewValue(ssa.OpSP, s.config.Uintptr, nil)
|
||||||
|
|
||||||
s.vars = map[string]*ssa.Value{}
|
s.vars = map[string]*ssa.Value{}
|
||||||
s.labels = map[string]*ssa.Block{}
|
s.labels = map[string]*ssa.Block{}
|
||||||
|
|
@ -97,6 +100,9 @@ type state struct {
|
||||||
startmem *ssa.Value
|
startmem *ssa.Value
|
||||||
fp *ssa.Value
|
fp *ssa.Value
|
||||||
sp *ssa.Value
|
sp *ssa.Value
|
||||||
|
|
||||||
|
// line number stack. The current line number is top of stack
|
||||||
|
line []int32
|
||||||
}
|
}
|
||||||
|
|
||||||
// startBlock sets the current block we're generating code in to b.
|
// startBlock sets the current block we're generating code in to b.
|
||||||
|
|
@ -122,9 +128,65 @@ func (s *state) endBlock() *ssa.Block {
|
||||||
s.defvars[b.ID] = s.vars
|
s.defvars[b.ID] = s.vars
|
||||||
s.curBlock = nil
|
s.curBlock = nil
|
||||||
s.vars = nil
|
s.vars = nil
|
||||||
|
b.Line = s.peekLine()
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// pushLine pushes a line number on the line number stack.
|
||||||
|
func (s *state) pushLine(line int32) {
|
||||||
|
s.line = append(s.line, line)
|
||||||
|
}
|
||||||
|
|
||||||
|
// popLine pops the top of the line number stack.
|
||||||
|
func (s *state) popLine() {
|
||||||
|
s.line = s.line[:len(s.line)-1]
|
||||||
|
}
|
||||||
|
|
||||||
|
// peekLine peek the top of the line number stack.
|
||||||
|
func (s *state) peekLine() int32 {
|
||||||
|
return s.line[len(s.line)-1]
|
||||||
|
}
|
||||||
|
|
||||||
|
// newValue adds a new value with no argueents to the current block.
|
||||||
|
func (s *state) newValue(op ssa.Op, t ssa.Type, aux interface{}) *ssa.Value {
|
||||||
|
return s.curBlock.NewValue(s.peekLine(), op, t, aux)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
return s.curBlock.NewValue1(s.peekLine(), op, t, aux, arg)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
return s.curBlock.NewValue2(s.peekLine(), op, t, aux, arg0, arg1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
return s.curBlock.NewValue3(s.peekLine(), op, t, aux, arg0, arg1, arg2)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
return s.f.Entry.NewValue(s.peekLine(), op, t, aux)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
return s.f.Entry.NewValue1(s.peekLine(), op, t, aux, arg)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
return s.f.Entry.NewValue2(s.peekLine(), op, t, aux, arg0, arg1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// constInt adds a new const int value to the entry block.
|
||||||
|
func (s *state) constInt(t ssa.Type, c int64) *ssa.Value {
|
||||||
|
return s.f.ConstInt(s.peekLine(), t, c)
|
||||||
|
}
|
||||||
|
|
||||||
// ssaStmtList converts the statement n to SSA and adds it to s.
|
// ssaStmtList converts the statement n to SSA and adds it to s.
|
||||||
func (s *state) stmtList(l *NodeList) {
|
func (s *state) stmtList(l *NodeList) {
|
||||||
for ; l != nil; l = l.Next {
|
for ; l != nil; l = l.Next {
|
||||||
|
|
@ -134,6 +196,9 @@ func (s *state) stmtList(l *NodeList) {
|
||||||
|
|
||||||
// ssaStmt converts the statement n to SSA and adds it to s.
|
// ssaStmt converts the statement n to SSA and adds it to s.
|
||||||
func (s *state) stmt(n *Node) {
|
func (s *state) stmt(n *Node) {
|
||||||
|
s.pushLine(n.Lineno)
|
||||||
|
defer s.popLine()
|
||||||
|
|
||||||
s.stmtList(n.Ninit)
|
s.stmtList(n.Ninit)
|
||||||
switch n.Op {
|
switch n.Op {
|
||||||
|
|
||||||
|
|
@ -167,11 +232,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.f.Entry.NewValue(ssa.OpConst, n.Left.Type, "")
|
val = s.entryNewValue(ssa.OpConst, n.Left.Type, "")
|
||||||
case t.IsInteger():
|
case t.IsInteger():
|
||||||
val = s.f.Entry.NewValue(ssa.OpConst, n.Left.Type, int64(0))
|
val = s.entryNewValue(ssa.OpConst, n.Left.Type, int64(0))
|
||||||
case t.IsBoolean():
|
case t.IsBoolean():
|
||||||
val = s.f.Entry.NewValue(ssa.OpConst, n.Left.Type, false)
|
val = s.entryNewValue(ssa.OpConst, n.Left.Type, false)
|
||||||
default:
|
default:
|
||||||
log.Fatalf("zero for type %v not implemented", t)
|
log.Fatalf("zero for type %v not implemented", t)
|
||||||
}
|
}
|
||||||
|
|
@ -185,7 +250,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.curBlock.NewValue3(ssa.OpStore, ssa.TypeMem, nil, addr, val, s.mem())
|
s.vars[".mem"] = s.newValue3(ssa.OpStore, ssa.TypeMem, nil, addr, val, s.mem())
|
||||||
// TODO: try to make more variables registerizeable.
|
// TODO: try to make more variables registerizeable.
|
||||||
case OIF:
|
case OIF:
|
||||||
cond := s.expr(n.Ntest)
|
cond := s.expr(n.Ntest)
|
||||||
|
|
@ -268,22 +333,25 @@ func (s *state) stmt(n *Node) {
|
||||||
|
|
||||||
// expr converts the expression n to ssa, adds it to s and returns the ssa result.
|
// expr converts the expression n to ssa, adds it to s and returns the ssa result.
|
||||||
func (s *state) expr(n *Node) *ssa.Value {
|
func (s *state) expr(n *Node) *ssa.Value {
|
||||||
|
s.pushLine(n.Lineno)
|
||||||
|
defer s.popLine()
|
||||||
|
|
||||||
switch n.Op {
|
switch n.Op {
|
||||||
case ONAME:
|
case ONAME:
|
||||||
// TODO: remember offsets for PPARAM names
|
// TODO: remember offsets for PPARAM names
|
||||||
if n.Class == PEXTERN {
|
if n.Class == PEXTERN {
|
||||||
// global variable
|
// global variable
|
||||||
addr := s.f.Entry.NewValue(ssa.OpGlobal, Ptrto(n.Type), n.Sym)
|
addr := s.entryNewValue(ssa.OpGlobal, Ptrto(n.Type), n.Sym)
|
||||||
return s.curBlock.NewValue2(ssa.OpLoad, n.Type, nil, addr, s.mem())
|
return s.newValue2(ssa.OpLoad, n.Type, nil, addr, s.mem())
|
||||||
}
|
}
|
||||||
s.argOffsets[n.Sym.Name] = n.Xoffset
|
s.argOffsets[n.Sym.Name] = n.Xoffset
|
||||||
return s.variable(n.Sym.Name, n.Type)
|
return s.variable(n.Sym.Name, n.Type)
|
||||||
case OLITERAL:
|
case OLITERAL:
|
||||||
switch n.Val.Ctype {
|
switch n.Val.Ctype {
|
||||||
case CTINT:
|
case CTINT:
|
||||||
return s.f.ConstInt(n.Type, Mpgetfix(n.Val.U.(*Mpint)))
|
return s.constInt(n.Type, Mpgetfix(n.Val.U.(*Mpint)))
|
||||||
case CTSTR:
|
case CTSTR:
|
||||||
return s.f.Entry.NewValue(ssa.OpConst, n.Type, n.Val.U)
|
return s.entryNewValue(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
|
||||||
|
|
@ -293,24 +361,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.curBlock.NewValue2(ssa.OpLess, ssa.TypeBool, nil, a, b)
|
return s.newValue2(ssa.OpLess, ssa.TypeBool, nil, 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.curBlock.NewValue2(ssa.OpAdd, a.Type, nil, a, b)
|
return s.newValue2(ssa.OpAdd, a.Type, nil, 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.curBlock.NewValue2(ssa.OpSub, a.Type, nil, a, b)
|
return s.newValue2(ssa.OpSub, a.Type, nil, 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.curBlock.NewValue2(ssa.OpLsh, a.Type, nil, a, b)
|
return s.newValue2(ssa.OpLsh, a.Type, nil, 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.curBlock.NewValue2(ssa.OpRsh, a.Type, nil, a, b)
|
return s.newValue2(ssa.OpRsh, a.Type, nil, a, b)
|
||||||
|
|
||||||
case OADDR:
|
case OADDR:
|
||||||
return s.addr(n.Left)
|
return s.addr(n.Left)
|
||||||
|
|
@ -318,13 +386,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.curBlock.NewValue2(ssa.OpLoad, n.Type, nil, p, s.mem())
|
return s.newValue2(ssa.OpLoad, n.Type, nil, 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.curBlock.NewValue2(ssa.OpAdd, p.Type, nil, p, s.f.ConstInt(s.config.Uintptr, n.Xoffset))
|
p = s.newValue2(ssa.OpAdd, p.Type, nil, p, s.constInt(s.config.Uintptr, n.Xoffset))
|
||||||
return s.curBlock.NewValue2(ssa.OpLoad, n.Type, nil, p, s.mem())
|
return s.newValue2(ssa.OpLoad, n.Type, nil, 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
|
||||||
|
|
@ -333,17 +401,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.curBlock.NewValue1(ssa.OpStringLen, s.config.Uintptr, nil, a)
|
len = s.newValue1(ssa.OpStringLen, s.config.Uintptr, nil, a)
|
||||||
elemtype = Types[TUINT8]
|
elemtype = Types[TUINT8]
|
||||||
} else {
|
} else {
|
||||||
len = s.f.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.curBlock.NewValue2(ssa.OpArrayIndex, elemtype, nil, a, i)
|
return s.newValue2(ssa.OpArrayIndex, elemtype, nil, a, i)
|
||||||
} else { // slice
|
} else { // slice
|
||||||
p := s.addr(n)
|
p := s.addr(n)
|
||||||
return s.curBlock.NewValue2(ssa.OpLoad, n.Left.Type.Type, nil, p, s.mem())
|
return s.newValue2(ssa.OpLoad, n.Left.Type.Type, nil, p, s.mem())
|
||||||
}
|
}
|
||||||
|
|
||||||
case OCALLFUNC:
|
case OCALLFUNC:
|
||||||
|
|
@ -357,7 +425,7 @@ func (s *state) expr(n *Node) *ssa.Value {
|
||||||
log.Fatalf("can't handle CALLFUNC with non-ONAME fn %s", opnames[n.Left.Op])
|
log.Fatalf("can't handle CALLFUNC with non-ONAME fn %s", opnames[n.Left.Op])
|
||||||
}
|
}
|
||||||
bNext := s.f.NewBlock(ssa.BlockPlain)
|
bNext := s.f.NewBlock(ssa.BlockPlain)
|
||||||
call := s.curBlock.NewValue1(ssa.OpStaticCall, ssa.TypeMem, n.Left.Sym, s.mem())
|
call := s.newValue1(ssa.OpStaticCall, ssa.TypeMem, n.Left.Sym, s.mem())
|
||||||
b := s.endBlock()
|
b := s.endBlock()
|
||||||
b.Kind = ssa.BlockCall
|
b.Kind = ssa.BlockCall
|
||||||
b.Control = call
|
b.Control = call
|
||||||
|
|
@ -368,8 +436,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.f.Entry.NewValue1(ssa.OpOffPtr, Ptrto(fp.Type), fp.Width, s.sp)
|
a := s.entryNewValue1(ssa.OpOffPtr, Ptrto(fp.Type), fp.Width, s.sp)
|
||||||
return s.curBlock.NewValue2(ssa.OpLoad, fp.Type, nil, a, call)
|
return s.newValue2(ssa.OpLoad, fp.Type, nil, a, call)
|
||||||
default:
|
default:
|
||||||
log.Fatalf("unhandled expr %s", opnames[n.Op])
|
log.Fatalf("unhandled expr %s", opnames[n.Op])
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -382,11 +450,11 @@ func (s *state) addr(n *Node) *ssa.Value {
|
||||||
case ONAME:
|
case ONAME:
|
||||||
if n.Class == PEXTERN {
|
if n.Class == PEXTERN {
|
||||||
// global variable
|
// global variable
|
||||||
return s.f.Entry.NewValue(ssa.OpGlobal, Ptrto(n.Type), n.Sym)
|
return s.entryNewValue(ssa.OpGlobal, Ptrto(n.Type), n.Sym)
|
||||||
}
|
}
|
||||||
if n.Class == PPARAMOUT {
|
if n.Class == PPARAMOUT {
|
||||||
// store to parameter slot
|
// store to parameter slot
|
||||||
return s.f.Entry.NewValue1(ssa.OpOffPtr, Ptrto(n.Type), n.Xoffset, s.fp)
|
return s.entryNewValue1(ssa.OpOffPtr, Ptrto(n.Type), n.Xoffset, s.fp)
|
||||||
}
|
}
|
||||||
// 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)
|
||||||
|
|
@ -394,21 +462,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.f.Entry.NewValue1(ssa.OpOffPtr, Ptrto(n.Type), n.Xoffset, s.sp)
|
return s.entryNewValue1(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.f.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.curBlock.NewValue2(ssa.OpPtrIndex, Ptrto(n.Left.Type.Type), nil, a, i)
|
return s.newValue2(ssa.OpPtrIndex, Ptrto(n.Left.Type.Type), nil, 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.curBlock.NewValue1(ssa.OpSliceLen, s.config.Uintptr, nil, a)
|
len := s.newValue1(ssa.OpSliceLen, s.config.Uintptr, nil, a)
|
||||||
s.boundsCheck(i, len)
|
s.boundsCheck(i, len)
|
||||||
p := s.curBlock.NewValue1(ssa.OpSlicePtr, Ptrto(n.Left.Type.Type), nil, a)
|
p := s.newValue1(ssa.OpSlicePtr, Ptrto(n.Left.Type.Type), nil, a)
|
||||||
return s.curBlock.NewValue2(ssa.OpPtrIndex, Ptrto(n.Left.Type.Type), nil, p, i)
|
return s.newValue2(ssa.OpPtrIndex, Ptrto(n.Left.Type.Type), nil, 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))
|
||||||
|
|
@ -419,7 +487,7 @@ func (s *state) addr(n *Node) *ssa.Value {
|
||||||
// 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.curBlock.NewValue1(ssa.OpIsNonNil, ssa.TypeBool, nil, ptr)
|
c := s.newValue1(ssa.OpIsNonNil, ssa.TypeBool, nil, ptr)
|
||||||
b := s.endBlock()
|
b := s.endBlock()
|
||||||
b.Kind = ssa.BlockIf
|
b.Kind = ssa.BlockIf
|
||||||
b.Control = c
|
b.Control = c
|
||||||
|
|
@ -438,7 +506,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.curBlock.NewValue2(ssa.OpIsInBounds, ssa.TypeBool, nil, idx, len)
|
cmp := s.newValue2(ssa.OpIsInBounds, ssa.TypeBool, nil, idx, len)
|
||||||
b := s.endBlock()
|
b := s.endBlock()
|
||||||
b.Kind = ssa.BlockIf
|
b.Kind = ssa.BlockIf
|
||||||
b.Control = cmp
|
b.Control = cmp
|
||||||
|
|
@ -457,7 +525,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.curBlock.NewValue(ssa.OpFwdRef, t, name)
|
v = s.newValue(ssa.OpFwdRef, t, name)
|
||||||
s.vars[name] = v
|
s.vars[name] = v
|
||||||
}
|
}
|
||||||
return v
|
return v
|
||||||
|
|
@ -496,8 +564,9 @@ 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.f.Entry.NewValue1(ssa.OpOffPtr, Ptrto(t.(*Type)), s.argOffsets[name], s.fp)
|
addr := s.entryNewValue1(ssa.OpOffPtr, Ptrto(t.(*Type)), s.argOffsets[name], s.fp)
|
||||||
return b.NewValue2(ssa.OpLoad, t, nil, addr, s.startmem)
|
return s.entryNewValue2(ssa.OpLoad, t, nil, addr, s.startmem)
|
||||||
|
|
||||||
}
|
}
|
||||||
var vals []*ssa.Value
|
var vals []*ssa.Value
|
||||||
for _, p := range b.Preds {
|
for _, p := range b.Preds {
|
||||||
|
|
@ -507,7 +576,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(ssa.OpPhi, t, nil)
|
v := b.NewValue(s.peekLine(), ssa.OpPhi, t, nil)
|
||||||
v.AddArgs(vals...)
|
v.AddArgs(vals...)
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
@ -528,7 +597,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(ssa.OpCopy, t, nil)
|
v := b.NewValue(s.peekLine(), ssa.OpCopy, t, nil)
|
||||||
m[name] = v
|
m[name] = v
|
||||||
v.AddArg(s.lookupVarIncoming(b, t, name))
|
v.AddArg(s.lookupVarIncoming(b, t, name))
|
||||||
return v
|
return v
|
||||||
|
|
@ -606,6 +675,7 @@ func genssa(f *ssa.Func, ptxt *obj.Prog, gcargs, gclocals *Sym) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func genValue(v *ssa.Value) {
|
func genValue(v *ssa.Value) {
|
||||||
|
lineno = v.Line
|
||||||
switch v.Op {
|
switch v.Op {
|
||||||
case ssa.OpAMD64ADDQ:
|
case ssa.OpAMD64ADDQ:
|
||||||
// TODO: use addq instead of leaq if target is in the right register.
|
// TODO: use addq instead of leaq if target is in the right register.
|
||||||
|
|
@ -797,6 +867,7 @@ func genValue(v *ssa.Value) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func genBlock(b, next *ssa.Block, branches []branch) []branch {
|
func genBlock(b, next *ssa.Block, branches []branch) []branch {
|
||||||
|
lineno = b.Line
|
||||||
switch b.Kind {
|
switch b.Kind {
|
||||||
case ssa.BlockPlain:
|
case ssa.BlockPlain:
|
||||||
if b.Succs[0] != next {
|
if b.Succs[0] != next {
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,6 @@ Scheduling
|
||||||
variables first.
|
variables first.
|
||||||
|
|
||||||
Values
|
Values
|
||||||
- Add a line number field. Figure out how to populate it and
|
|
||||||
maintain it during rewrites.
|
|
||||||
- Store *Type instead of Type? Keep an array of used Types in Func
|
- Store *Type instead of Type? Keep an array of used Types in Func
|
||||||
and reference by id? Unify with the type ../gc so we just use a
|
and reference by id? Unify with the type ../gc so we just use a
|
||||||
pointer instead of an interface?
|
pointer instead of an interface?
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,9 @@ type Block struct {
|
||||||
|
|
||||||
// The containing function
|
// The containing function
|
||||||
Func *Func
|
Func *Func
|
||||||
|
|
||||||
|
// Line number for block's control operation
|
||||||
|
Line int32
|
||||||
}
|
}
|
||||||
|
|
||||||
// kind control successors
|
// kind control successors
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@ func (f *Func) NewBlock(kind BlockKind) *Block {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewValue returns a new value in the block with no arguments.
|
// NewValue returns a new value in the block with no arguments.
|
||||||
func (b *Block) NewValue(op Op, t Type, aux interface{}) *Value {
|
func (b *Block) NewValue(line int32, op Op, t Type, aux interface{}) *Value {
|
||||||
v := &Value{
|
v := &Value{
|
||||||
ID: b.Func.vid.get(),
|
ID: b.Func.vid.get(),
|
||||||
Op: op,
|
Op: op,
|
||||||
|
|
@ -57,7 +57,7 @@ func (b *Block) NewValue(op Op, t Type, aux interface{}) *Value {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewValue1 returns a new value in the block with one argument.
|
// NewValue1 returns a new value in the block with one argument.
|
||||||
func (b *Block) NewValue1(op Op, t Type, aux interface{}, arg *Value) *Value {
|
func (b *Block) NewValue1(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,
|
||||||
|
|
@ -72,7 +72,7 @@ func (b *Block) NewValue1(op Op, t Type, aux interface{}, arg *Value) *Value {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewValue2 returns a new value in the block with two arguments.
|
// NewValue2 returns a new value in the block with two arguments.
|
||||||
func (b *Block) NewValue2(op Op, t Type, aux interface{}, arg0, arg1 *Value) *Value {
|
func (b *Block) NewValue2(line int32, op Op, t Type, aux interface{}, arg0, arg1 *Value) *Value {
|
||||||
v := &Value{
|
v := &Value{
|
||||||
ID: b.Func.vid.get(),
|
ID: b.Func.vid.get(),
|
||||||
Op: op,
|
Op: op,
|
||||||
|
|
@ -88,7 +88,7 @@ func (b *Block) NewValue2(op Op, t Type, aux interface{}, arg0, arg1 *Value) *Va
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewValue3 returns a new value in the block with three arguments.
|
// NewValue3 returns a new value in the block with three arguments.
|
||||||
func (b *Block) NewValue3(op Op, t Type, aux interface{}, arg0, arg1, arg2 *Value) *Value {
|
func (b *Block) NewValue3(line int32, op Op, t Type, aux interface{}, arg0, arg1, arg2 *Value) *Value {
|
||||||
v := &Value{
|
v := &Value{
|
||||||
ID: b.Func.vid.get(),
|
ID: b.Func.vid.get(),
|
||||||
Op: op,
|
Op: op,
|
||||||
|
|
@ -102,7 +102,7 @@ func (b *Block) NewValue3(op Op, t Type, aux interface{}, arg0, arg1, arg2 *Valu
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConstInt returns an int constant representing its argument.
|
// ConstInt returns an int constant representing its argument.
|
||||||
func (f *Func) ConstInt(t Type, c int64) *Value {
|
func (f *Func) ConstInt(line int32, t Type, c int64) *Value {
|
||||||
// TODO: cache?
|
// TODO: cache?
|
||||||
return f.Entry.NewValue(OpConst, t, c)
|
return f.Entry.NewValue(line, OpConst, t, c)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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(valu.op, valu.t, valu.aux)
|
values[valu.name] = b.NewValue(0, valu.op, valu.t, valu.aux)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Connect the blocks together and specify control values.
|
// Connect the blocks together and specify control values.
|
||||||
|
|
|
||||||
|
|
@ -364,7 +364,7 @@ func genResult0(w io.Writer, arch arch, result string, alloc *int, top bool) str
|
||||||
} else {
|
} else {
|
||||||
v = fmt.Sprintf("v%d", *alloc)
|
v = fmt.Sprintf("v%d", *alloc)
|
||||||
*alloc++
|
*alloc++
|
||||||
fmt.Fprintf(w, "%s := v.Block.NewValue(%s, TypeInvalid, nil)\n", v, opName(s[0], arch))
|
fmt.Fprintf(w, "%s := v.Block.NewValue(v.Line, %s, TypeInvalid, nil)\n", v, opName(s[0], arch))
|
||||||
}
|
}
|
||||||
for _, a := range s[1:] {
|
for _, a := range s[1:] {
|
||||||
if a[0] == '<' {
|
if a[0] == '<' {
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ func genericValueRules(v *Value, config *Config) bool {
|
||||||
v.Op = OpLoad
|
v.Op = OpLoad
|
||||||
v.Aux = nil
|
v.Aux = nil
|
||||||
v.resetArgs()
|
v.resetArgs()
|
||||||
v0 := v.Block.NewValue(OpPtrIndex, TypeInvalid, nil)
|
v0 := v.Block.NewValue(v.Line, OpPtrIndex, TypeInvalid, nil)
|
||||||
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)
|
||||||
|
|
@ -68,15 +68,15 @@ func genericValueRules(v *Value, config *Config) bool {
|
||||||
v.Op = OpStringMake
|
v.Op = OpStringMake
|
||||||
v.Aux = nil
|
v.Aux = nil
|
||||||
v.resetArgs()
|
v.resetArgs()
|
||||||
v0 := v.Block.NewValue(OpOffPtr, TypeInvalid, nil)
|
v0 := v.Block.NewValue(v.Line, OpOffPtr, TypeInvalid, nil)
|
||||||
v0.Type = TypeBytePtr
|
v0.Type = TypeBytePtr
|
||||||
v0.Aux = 2 * config.ptrSize
|
v0.Aux = 2 * config.ptrSize
|
||||||
v1 := v.Block.NewValue(OpGlobal, TypeInvalid, nil)
|
v1 := v.Block.NewValue(v.Line, OpGlobal, TypeInvalid, nil)
|
||||||
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(OpConst, TypeInvalid, nil)
|
v2 := v.Block.NewValue(v.Line, OpConst, TypeInvalid, nil)
|
||||||
v2.Type = config.Uintptr
|
v2.Type = config.Uintptr
|
||||||
v2.Aux = int64(len(s.(string)))
|
v2.Aux = int64(len(s.(string)))
|
||||||
v.AddArg(v2)
|
v.AddArg(v2)
|
||||||
|
|
@ -121,14 +121,14 @@ func genericValueRules(v *Value, config *Config) bool {
|
||||||
v.Op = OpStringMake
|
v.Op = OpStringMake
|
||||||
v.Aux = nil
|
v.Aux = nil
|
||||||
v.resetArgs()
|
v.resetArgs()
|
||||||
v0 := v.Block.NewValue(OpLoad, TypeInvalid, nil)
|
v0 := v.Block.NewValue(v.Line, OpLoad, TypeInvalid, nil)
|
||||||
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(OpLoad, TypeInvalid, nil)
|
v1 := v.Block.NewValue(v.Line, OpLoad, TypeInvalid, nil)
|
||||||
v1.Type = config.Uintptr
|
v1.Type = config.Uintptr
|
||||||
v2 := v.Block.NewValue(OpOffPtr, TypeInvalid, nil)
|
v2 := v.Block.NewValue(v.Line, OpOffPtr, TypeInvalid, nil)
|
||||||
v2.Type = TypeBytePtr
|
v2.Type = TypeBytePtr
|
||||||
v2.Aux = config.ptrSize
|
v2.Aux = config.ptrSize
|
||||||
v2.AddArg(ptr)
|
v2.AddArg(ptr)
|
||||||
|
|
@ -178,10 +178,10 @@ func genericValueRules(v *Value, config *Config) bool {
|
||||||
v.Aux = nil
|
v.Aux = nil
|
||||||
v.resetArgs()
|
v.resetArgs()
|
||||||
v.AddArg(ptr)
|
v.AddArg(ptr)
|
||||||
v0 := v.Block.NewValue(OpMul, TypeInvalid, nil)
|
v0 := v.Block.NewValue(v.Line, OpMul, TypeInvalid, nil)
|
||||||
v0.Type = config.Uintptr
|
v0.Type = config.Uintptr
|
||||||
v0.AddArg(idx)
|
v0.AddArg(idx)
|
||||||
v1 := v.Block.NewValue(OpConst, TypeInvalid, nil)
|
v1 := v.Block.NewValue(v.Line, OpConst, TypeInvalid, nil)
|
||||||
v1.Type = config.Uintptr
|
v1.Type = config.Uintptr
|
||||||
v1.Aux = t.Elem().Size()
|
v1.Aux = t.Elem().Size()
|
||||||
v0.AddArg(v1)
|
v0.AddArg(v1)
|
||||||
|
|
@ -204,10 +204,10 @@ func genericValueRules(v *Value, config *Config) bool {
|
||||||
v.Op = OpLoad
|
v.Op = OpLoad
|
||||||
v.Aux = nil
|
v.Aux = nil
|
||||||
v.resetArgs()
|
v.resetArgs()
|
||||||
v0 := v.Block.NewValue(OpAdd, TypeInvalid, nil)
|
v0 := v.Block.NewValue(v.Line, OpAdd, TypeInvalid, nil)
|
||||||
v0.Type = ptr.Type
|
v0.Type = ptr.Type
|
||||||
v0.AddArg(ptr)
|
v0.AddArg(ptr)
|
||||||
v1 := v.Block.NewValue(OpConst, TypeInvalid, nil)
|
v1 := v.Block.NewValue(v.Line, OpConst, TypeInvalid, nil)
|
||||||
v1.Type = config.Uintptr
|
v1.Type = config.Uintptr
|
||||||
v1.Aux = int64(config.ptrSize * 2)
|
v1.Aux = int64(config.ptrSize * 2)
|
||||||
v0.AddArg(v1)
|
v0.AddArg(v1)
|
||||||
|
|
@ -231,10 +231,10 @@ func genericValueRules(v *Value, config *Config) bool {
|
||||||
v.Op = OpLoad
|
v.Op = OpLoad
|
||||||
v.Aux = nil
|
v.Aux = nil
|
||||||
v.resetArgs()
|
v.resetArgs()
|
||||||
v0 := v.Block.NewValue(OpAdd, TypeInvalid, nil)
|
v0 := v.Block.NewValue(v.Line, OpAdd, TypeInvalid, nil)
|
||||||
v0.Type = ptr.Type
|
v0.Type = ptr.Type
|
||||||
v0.AddArg(ptr)
|
v0.AddArg(ptr)
|
||||||
v1 := v.Block.NewValue(OpConst, TypeInvalid, nil)
|
v1 := v.Block.NewValue(v.Line, OpConst, TypeInvalid, nil)
|
||||||
v1.Type = config.Uintptr
|
v1.Type = config.Uintptr
|
||||||
v1.Aux = int64(config.ptrSize)
|
v1.Aux = int64(config.ptrSize)
|
||||||
v0.AddArg(v1)
|
v0.AddArg(v1)
|
||||||
|
|
@ -308,19 +308,19 @@ func genericValueRules(v *Value, config *Config) bool {
|
||||||
v.Op = OpStore
|
v.Op = OpStore
|
||||||
v.Aux = nil
|
v.Aux = nil
|
||||||
v.resetArgs()
|
v.resetArgs()
|
||||||
v0 := v.Block.NewValue(OpOffPtr, TypeInvalid, nil)
|
v0 := v.Block.NewValue(v.Line, OpOffPtr, TypeInvalid, nil)
|
||||||
v0.Type = TypeBytePtr
|
v0.Type = TypeBytePtr
|
||||||
v0.Aux = config.ptrSize
|
v0.Aux = config.ptrSize
|
||||||
v0.AddArg(dst)
|
v0.AddArg(dst)
|
||||||
v.AddArg(v0)
|
v.AddArg(v0)
|
||||||
v1 := v.Block.NewValue(OpStringLen, TypeInvalid, nil)
|
v1 := v.Block.NewValue(v.Line, OpStringLen, TypeInvalid, nil)
|
||||||
v1.Type = config.Uintptr
|
v1.Type = config.Uintptr
|
||||||
v1.AddArg(str)
|
v1.AddArg(str)
|
||||||
v.AddArg(v1)
|
v.AddArg(v1)
|
||||||
v2 := v.Block.NewValue(OpStore, TypeInvalid, nil)
|
v2 := v.Block.NewValue(v.Line, OpStore, TypeInvalid, nil)
|
||||||
v2.Type = TypeMem
|
v2.Type = TypeMem
|
||||||
v2.AddArg(dst)
|
v2.AddArg(dst)
|
||||||
v3 := v.Block.NewValue(OpStringPtr, TypeInvalid, nil)
|
v3 := v.Block.NewValue(v.Line, OpStringPtr, TypeInvalid, nil)
|
||||||
v3.Type = TypeBytePtr
|
v3.Type = TypeBytePtr
|
||||||
v3.AddArg(str)
|
v3.AddArg(str)
|
||||||
v2.AddArg(v3)
|
v2.AddArg(v3)
|
||||||
|
|
|
||||||
|
|
@ -262,24 +262,24 @@ 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(OpCopy, w.Type, nil, w)
|
c = b.NewValue1(w.Line, OpCopy, w.Type, nil, w)
|
||||||
} else {
|
} else {
|
||||||
c = b.NewValue(w.Op, w.Type, w.Aux)
|
c = b.NewValue(w.Line, w.Op, w.Type, 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.Op, w.Type, w.Aux, w.Args[0])
|
c = b.NewValue1(w.Line, w.Op, w.Type, 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(OpCopy, w.Type, nil)
|
c = b.NewValue(w.Line, OpCopy, w.Type, nil)
|
||||||
c.AddArg(regs[s].c)
|
c.AddArg(regs[s].c)
|
||||||
} else {
|
} else {
|
||||||
// Load from home location
|
// Load from home location
|
||||||
c = b.NewValue(OpLoadReg8, w.Type, nil)
|
c = b.NewValue(w.Line, OpLoadReg8, w.Type, nil)
|
||||||
c.AddArg(w)
|
c.AddArg(w)
|
||||||
}
|
}
|
||||||
home = setloc(home, c, ®isters[r])
|
home = setloc(home, c, ®isters[r])
|
||||||
|
|
@ -337,7 +337,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.Op, v.Type, v.Aux)
|
c := b.NewValue(v.Line, v.Op, v.Type, v.Aux)
|
||||||
c.AddArgs(v.Args...)
|
c.AddArgs(v.Args...)
|
||||||
home = setloc(home, c, ®isters[r])
|
home = setloc(home, c, ®isters[r])
|
||||||
|
|
||||||
|
|
@ -406,7 +406,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(OpCopy, v.Type, nil, w)
|
cpy := c.NewValue1(w.Line, OpCopy, v.Type, nil, w)
|
||||||
v.Args[i] = cpy
|
v.Args[i] = cpy
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -181,7 +181,7 @@ func rewriteValueAMD64(v *Value, config *Config) bool {
|
||||||
v.Op = OpAMD64InvertFlags
|
v.Op = OpAMD64InvertFlags
|
||||||
v.Aux = nil
|
v.Aux = nil
|
||||||
v.resetArgs()
|
v.resetArgs()
|
||||||
v0 := v.Block.NewValue(OpAMD64CMPQconst, TypeInvalid, nil)
|
v0 := v.Block.NewValue(v.Line, OpAMD64CMPQconst, TypeInvalid, nil)
|
||||||
v0.Type = TypeFlags
|
v0.Type = TypeFlags
|
||||||
v0.AddArg(x)
|
v0.AddArg(x)
|
||||||
v0.Aux = c
|
v0.Aux = c
|
||||||
|
|
@ -235,7 +235,7 @@ func rewriteValueAMD64(v *Value, config *Config) bool {
|
||||||
v.Op = OpAMD64SETB
|
v.Op = OpAMD64SETB
|
||||||
v.Aux = nil
|
v.Aux = nil
|
||||||
v.resetArgs()
|
v.resetArgs()
|
||||||
v0 := v.Block.NewValue(OpAMD64CMPQ, TypeInvalid, nil)
|
v0 := v.Block.NewValue(v.Line, OpAMD64CMPQ, TypeInvalid, nil)
|
||||||
v0.Type = TypeFlags
|
v0.Type = TypeFlags
|
||||||
v0.AddArg(idx)
|
v0.AddArg(idx)
|
||||||
v0.AddArg(len)
|
v0.AddArg(len)
|
||||||
|
|
@ -254,7 +254,7 @@ func rewriteValueAMD64(v *Value, config *Config) bool {
|
||||||
v.Op = OpAMD64SETNE
|
v.Op = OpAMD64SETNE
|
||||||
v.Aux = nil
|
v.Aux = nil
|
||||||
v.resetArgs()
|
v.resetArgs()
|
||||||
v0 := v.Block.NewValue(OpAMD64TESTQ, TypeInvalid, nil)
|
v0 := v.Block.NewValue(v.Line, OpAMD64TESTQ, TypeInvalid, nil)
|
||||||
v0.Type = TypeFlags
|
v0.Type = TypeFlags
|
||||||
v0.AddArg(p)
|
v0.AddArg(p)
|
||||||
v0.AddArg(p)
|
v0.AddArg(p)
|
||||||
|
|
@ -277,7 +277,7 @@ func rewriteValueAMD64(v *Value, config *Config) bool {
|
||||||
v.Op = OpAMD64SETL
|
v.Op = OpAMD64SETL
|
||||||
v.Aux = nil
|
v.Aux = nil
|
||||||
v.resetArgs()
|
v.resetArgs()
|
||||||
v0 := v.Block.NewValue(OpAMD64CMPQ, TypeInvalid, nil)
|
v0 := v.Block.NewValue(v.Line, OpAMD64CMPQ, TypeInvalid, nil)
|
||||||
v0.Type = TypeFlags
|
v0.Type = TypeFlags
|
||||||
v0.AddArg(x)
|
v0.AddArg(x)
|
||||||
v0.AddArg(y)
|
v0.AddArg(y)
|
||||||
|
|
@ -596,7 +596,7 @@ func rewriteValueAMD64(v *Value, config *Config) bool {
|
||||||
v.resetArgs()
|
v.resetArgs()
|
||||||
v.AddArg(dst)
|
v.AddArg(dst)
|
||||||
v.AddArg(src)
|
v.AddArg(src)
|
||||||
v0 := v.Block.NewValue(OpConst, TypeInvalid, nil)
|
v0 := v.Block.NewValue(v.Line, OpConst, TypeInvalid, nil)
|
||||||
v0.Type = TypeUInt64
|
v0.Type = TypeUInt64
|
||||||
v0.Aux = size.(int64)
|
v0.Aux = size.(int64)
|
||||||
v.AddArg(v0)
|
v.AddArg(v0)
|
||||||
|
|
@ -733,7 +733,7 @@ func rewriteValueAMD64(v *Value, config *Config) bool {
|
||||||
v.Op = OpAMD64NEGQ
|
v.Op = OpAMD64NEGQ
|
||||||
v.Aux = nil
|
v.Aux = nil
|
||||||
v.resetArgs()
|
v.resetArgs()
|
||||||
v0 := v.Block.NewValue(OpAMD64SUBQconst, TypeInvalid, nil)
|
v0 := v.Block.NewValue(v.Line, OpAMD64SUBQconst, TypeInvalid, nil)
|
||||||
v0.Type = t
|
v0.Type = t
|
||||||
v0.AddArg(x)
|
v0.AddArg(x)
|
||||||
v0.Aux = c
|
v0.Aux = c
|
||||||
|
|
@ -927,7 +927,7 @@ func rewriteBlockAMD64(b *Block) bool {
|
||||||
goto end7e22019fb0effc80f85c05ea30bdb5d9
|
goto end7e22019fb0effc80f85c05ea30bdb5d9
|
||||||
}
|
}
|
||||||
b.Kind = BlockAMD64NE
|
b.Kind = BlockAMD64NE
|
||||||
v0 := v.Block.NewValue(OpAMD64TESTB, TypeInvalid, nil)
|
v0 := v.Block.NewValue(v.Line, OpAMD64TESTB, TypeInvalid, nil)
|
||||||
v0.Type = TypeFlags
|
v0.Type = TypeFlags
|
||||||
v0.AddArg(cond)
|
v0.AddArg(cond)
|
||||||
v0.AddArg(cond)
|
v0.AddArg(cond)
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ func rewriteValuegeneric(v *Value, config *Config) bool {
|
||||||
v.Op = OpLoad
|
v.Op = OpLoad
|
||||||
v.Aux = nil
|
v.Aux = nil
|
||||||
v.resetArgs()
|
v.resetArgs()
|
||||||
v0 := v.Block.NewValue(OpPtrIndex, TypeInvalid, nil)
|
v0 := v.Block.NewValue(v.Line, OpPtrIndex, TypeInvalid, nil)
|
||||||
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)
|
||||||
|
|
@ -68,15 +68,15 @@ func rewriteValuegeneric(v *Value, config *Config) bool {
|
||||||
v.Op = OpStringMake
|
v.Op = OpStringMake
|
||||||
v.Aux = nil
|
v.Aux = nil
|
||||||
v.resetArgs()
|
v.resetArgs()
|
||||||
v0 := v.Block.NewValue(OpOffPtr, TypeInvalid, nil)
|
v0 := v.Block.NewValue(v.Line, OpOffPtr, TypeInvalid, nil)
|
||||||
v0.Type = TypeBytePtr
|
v0.Type = TypeBytePtr
|
||||||
v0.Aux = 2 * config.ptrSize
|
v0.Aux = 2 * config.ptrSize
|
||||||
v1 := v.Block.NewValue(OpGlobal, TypeInvalid, nil)
|
v1 := v.Block.NewValue(v.Line, OpGlobal, TypeInvalid, nil)
|
||||||
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(OpConst, TypeInvalid, nil)
|
v2 := v.Block.NewValue(v.Line, OpConst, TypeInvalid, nil)
|
||||||
v2.Type = config.Uintptr
|
v2.Type = config.Uintptr
|
||||||
v2.Aux = int64(len(s.(string)))
|
v2.Aux = int64(len(s.(string)))
|
||||||
v.AddArg(v2)
|
v.AddArg(v2)
|
||||||
|
|
@ -121,14 +121,14 @@ func rewriteValuegeneric(v *Value, config *Config) bool {
|
||||||
v.Op = OpStringMake
|
v.Op = OpStringMake
|
||||||
v.Aux = nil
|
v.Aux = nil
|
||||||
v.resetArgs()
|
v.resetArgs()
|
||||||
v0 := v.Block.NewValue(OpLoad, TypeInvalid, nil)
|
v0 := v.Block.NewValue(v.Line, OpLoad, TypeInvalid, nil)
|
||||||
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(OpLoad, TypeInvalid, nil)
|
v1 := v.Block.NewValue(v.Line, OpLoad, TypeInvalid, nil)
|
||||||
v1.Type = config.Uintptr
|
v1.Type = config.Uintptr
|
||||||
v2 := v.Block.NewValue(OpOffPtr, TypeInvalid, nil)
|
v2 := v.Block.NewValue(v.Line, OpOffPtr, TypeInvalid, nil)
|
||||||
v2.Type = TypeBytePtr
|
v2.Type = TypeBytePtr
|
||||||
v2.Aux = config.ptrSize
|
v2.Aux = config.ptrSize
|
||||||
v2.AddArg(ptr)
|
v2.AddArg(ptr)
|
||||||
|
|
@ -178,10 +178,10 @@ func rewriteValuegeneric(v *Value, config *Config) bool {
|
||||||
v.Aux = nil
|
v.Aux = nil
|
||||||
v.resetArgs()
|
v.resetArgs()
|
||||||
v.AddArg(ptr)
|
v.AddArg(ptr)
|
||||||
v0 := v.Block.NewValue(OpMul, TypeInvalid, nil)
|
v0 := v.Block.NewValue(v.Line, OpMul, TypeInvalid, nil)
|
||||||
v0.Type = config.Uintptr
|
v0.Type = config.Uintptr
|
||||||
v0.AddArg(idx)
|
v0.AddArg(idx)
|
||||||
v1 := v.Block.NewValue(OpConst, TypeInvalid, nil)
|
v1 := v.Block.NewValue(v.Line, OpConst, TypeInvalid, nil)
|
||||||
v1.Type = config.Uintptr
|
v1.Type = config.Uintptr
|
||||||
v1.Aux = t.Elem().Size()
|
v1.Aux = t.Elem().Size()
|
||||||
v0.AddArg(v1)
|
v0.AddArg(v1)
|
||||||
|
|
@ -204,10 +204,10 @@ func rewriteValuegeneric(v *Value, config *Config) bool {
|
||||||
v.Op = OpLoad
|
v.Op = OpLoad
|
||||||
v.Aux = nil
|
v.Aux = nil
|
||||||
v.resetArgs()
|
v.resetArgs()
|
||||||
v0 := v.Block.NewValue(OpAdd, TypeInvalid, nil)
|
v0 := v.Block.NewValue(v.Line, OpAdd, TypeInvalid, nil)
|
||||||
v0.Type = ptr.Type
|
v0.Type = ptr.Type
|
||||||
v0.AddArg(ptr)
|
v0.AddArg(ptr)
|
||||||
v1 := v.Block.NewValue(OpConst, TypeInvalid, nil)
|
v1 := v.Block.NewValue(v.Line, OpConst, TypeInvalid, nil)
|
||||||
v1.Type = config.Uintptr
|
v1.Type = config.Uintptr
|
||||||
v1.Aux = int64(config.ptrSize * 2)
|
v1.Aux = int64(config.ptrSize * 2)
|
||||||
v0.AddArg(v1)
|
v0.AddArg(v1)
|
||||||
|
|
@ -231,10 +231,10 @@ func rewriteValuegeneric(v *Value, config *Config) bool {
|
||||||
v.Op = OpLoad
|
v.Op = OpLoad
|
||||||
v.Aux = nil
|
v.Aux = nil
|
||||||
v.resetArgs()
|
v.resetArgs()
|
||||||
v0 := v.Block.NewValue(OpAdd, TypeInvalid, nil)
|
v0 := v.Block.NewValue(v.Line, OpAdd, TypeInvalid, nil)
|
||||||
v0.Type = ptr.Type
|
v0.Type = ptr.Type
|
||||||
v0.AddArg(ptr)
|
v0.AddArg(ptr)
|
||||||
v1 := v.Block.NewValue(OpConst, TypeInvalid, nil)
|
v1 := v.Block.NewValue(v.Line, OpConst, TypeInvalid, nil)
|
||||||
v1.Type = config.Uintptr
|
v1.Type = config.Uintptr
|
||||||
v1.Aux = int64(config.ptrSize)
|
v1.Aux = int64(config.ptrSize)
|
||||||
v0.AddArg(v1)
|
v0.AddArg(v1)
|
||||||
|
|
@ -308,19 +308,19 @@ func rewriteValuegeneric(v *Value, config *Config) bool {
|
||||||
v.Op = OpStore
|
v.Op = OpStore
|
||||||
v.Aux = nil
|
v.Aux = nil
|
||||||
v.resetArgs()
|
v.resetArgs()
|
||||||
v0 := v.Block.NewValue(OpOffPtr, TypeInvalid, nil)
|
v0 := v.Block.NewValue(v.Line, OpOffPtr, TypeInvalid, nil)
|
||||||
v0.Type = TypeBytePtr
|
v0.Type = TypeBytePtr
|
||||||
v0.Aux = config.ptrSize
|
v0.Aux = config.ptrSize
|
||||||
v0.AddArg(dst)
|
v0.AddArg(dst)
|
||||||
v.AddArg(v0)
|
v.AddArg(v0)
|
||||||
v1 := v.Block.NewValue(OpStringLen, TypeInvalid, nil)
|
v1 := v.Block.NewValue(v.Line, OpStringLen, TypeInvalid, nil)
|
||||||
v1.Type = config.Uintptr
|
v1.Type = config.Uintptr
|
||||||
v1.AddArg(str)
|
v1.AddArg(str)
|
||||||
v.AddArg(v1)
|
v.AddArg(v1)
|
||||||
v2 := v.Block.NewValue(OpStore, TypeInvalid, nil)
|
v2 := v.Block.NewValue(v.Line, OpStore, TypeInvalid, nil)
|
||||||
v2.Type = TypeMem
|
v2.Type = TypeMem
|
||||||
v2.AddArg(dst)
|
v2.AddArg(dst)
|
||||||
v3 := v.Block.NewValue(OpStringPtr, TypeInvalid, nil)
|
v3 := v.Block.NewValue(v.Line, OpStringPtr, TypeInvalid, nil)
|
||||||
v3.Type = TypeBytePtr
|
v3.Type = TypeBytePtr
|
||||||
v3.AddArg(str)
|
v3.AddArg(str)
|
||||||
v2.AddArg(v3)
|
v2.AddArg(v3)
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,9 @@ type Value struct {
|
||||||
// Containing basic block
|
// Containing basic block
|
||||||
Block *Block
|
Block *Block
|
||||||
|
|
||||||
|
// Source line number
|
||||||
|
Line int32
|
||||||
|
|
||||||
// Storage for the first two args
|
// Storage for the first two args
|
||||||
argstorage [2]*Value
|
argstorage [2]*Value
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue