}
}
-func (p *Parser) pos() src.Pos {
- return src.MakePos(p.lex.Base(), uint(p.lineNum), 0)
+func (p *Parser) pos() src.XPos {
+ return p.ctxt.PosTable.XPos(src.MakePos(p.lex.Base(), uint(p.lineNum), 0))
}
func (p *Parser) Parse() (*obj.Prog, bool) {
package gc
-import (
- "cmd/internal/src"
- "fmt"
-)
+import "fmt"
// AlgKind describes the kind of algorithms used for comparing and
// hashing a Type.
fmt.Printf("genhash %v %v\n", sym, t)
}
- lineno = src.MakePos(nil, 1, 0) // less confusing than end of input
+ lineno = MakePos(nil, 1, 0) // less confusing than end of input
dclcontext = PEXTERN
markdcl()
fmt.Printf("geneq %v %v\n", sym, t)
}
- lineno = src.MakePos(nil, 1, 0) // less confusing than end of input
+ lineno = MakePos(nil, 1, 0) // less confusing than end of input
dclcontext = PEXTERN
markdcl()
func fileLine(n *Node) (file string, line int) {
if n != nil {
- file = n.Pos.AbsFilename()
- line = int(n.Pos.Line())
+ pos := Ctxt.PosTable.Pos(n.Pos)
+ file = pos.AbsFilename()
+ line = int(pos.Line())
}
return
}
nr := n.Right
var rv Val
- var lno src.Pos
+ var lno src.XPos
var wr EType
var v Val
var norig *Node
// declare constants from grammar
// new_name_list [[type] = expr_list]
func constiter(vl []*Node, t *Node, cl []*Node) []*Node {
- var lno src.Pos // default is to leave line number alone in listtreecopy
+ var lno src.XPos // default is to leave line number alone in listtreecopy
if len(cl) == 0 {
if t != nil {
yyerror("const declaration cannot have type without expression")
type nowritebarrierrecCall struct {
target *Node
depth int
- lineno src.Pos
+ lineno src.XPos
}
func checknowritebarrierrec() {
// saved and restored by dcopy
Pkg *Pkg
- Name string // object name
- Def *Node // definition: ONAME OTYPE OPACK or OLITERAL
- Block int32 // blocknumber to catch redeclaration
- Lastlineno src.Pos // last declaration for diagnostic
+ Name string // object name
+ Def *Node // definition: ONAME OTYPE OPACK or OLITERAL
+ Block int32 // blocknumber to catch redeclaration
+ Lastlineno src.XPos // last declaration for diagnostic
Label *Node // corresponding label (ephemeral)
Origpkg *Pkg // original package for . import
}
// Plaster over linenumbers
-func setlnolist(ll Nodes, lno src.Pos) {
+func setlnolist(ll Nodes, lno src.XPos) {
for _, n := range ll.Slice() {
setlno(n, lno)
}
}
-func setlno(n *Node, lno src.Pos) {
+func setlno(n *Node, lno src.XPos) {
if n == nil {
return
}
// lineno is the source position at the start of the most recently lexed token.
// TODO(gri) rename and eventually remove
-var lineno src.Pos
+var lineno src.XPos
+
+func MakePos(base *src.PosBase, line, col uint) src.XPos {
+ return Ctxt.PosTable.XPos(src.MakePos(base, line, col))
+}
func isSpace(c rune) bool {
return c == ' ' || c == '\t' || c == '\n' || c == '\r'
}
}
-func pkgnotused(lineno src.Pos, path string, name string) {
+func pkgnotused(lineno src.XPos, path string, name string) {
// If the package was imported with a name other than the final
// import path element, show it explicitly in the error message.
// Note that this handles both renamed imports and imports of
// for fninit and set lineno to NoPos here.
// TODO(gri) fix this once we switched permanently to the new
// position information.
- lineno = src.MakePos(file.Pos().Base(), uint(file.Lines), 0)
+ lineno = MakePos(file.Pos().Base(), uint(file.Lines), 0)
}
func (p *noder) decls(decls []syntax.Decl) (l []*Node) {
yyerror("can only use //go:noescape with external func implementations")
}
f.Func.Pragma = pragma
- lineno = src.MakePos(fun.Pos().Base(), fun.EndLine, 0)
+ lineno = MakePos(fun.Pos().Base(), fun.EndLine, 0)
f.Func.Endlineno = lineno
funcbody(f)
l[i] = p.wrapname(expr.ElemList[i], e)
}
n.List.Set(l)
- lineno = src.MakePos(expr.Pos().Base(), expr.EndLine, 0)
+ lineno = MakePos(expr.Pos().Base(), expr.EndLine, 0)
return n
case *syntax.KeyValueExpr:
return p.nod(expr, OKEY, p.expr(expr.Key), p.wrapname(expr.Value, p.expr(expr.Value)))
case *syntax.FuncLit:
closurehdr(p.typeExpr(expr.Type))
body := p.stmts(expr.Body)
- lineno = src.MakePos(expr.Pos().Base(), expr.EndLine, 0)
+ lineno = MakePos(expr.Pos().Base(), expr.EndLine, 0)
return p.setlineno(expr, closurebody(body))
case *syntax.ParenExpr:
return p.nod(expr, OPAREN, p.expr(expr.X), nil)
// TODO(mdempsky): Shouldn't happen. Fix package syntax.
return dst
}
- dst.Pos = pos
+ dst.Pos = Ctxt.PosTable.XPos(pos)
return dst
}
// TODO(mdempsky): Shouldn't happen. Fix package syntax.
return
}
- lineno = pos
+ lineno = Ctxt.PosTable.XPos(pos)
}
func (p *noder) error(err error) {
e := err.(syntax.Error)
- yyerrorl(e.Pos, "%s", e.Msg)
+ yyerrorl(Ctxt.PosTable.XPos(e.Pos), "%s", e.Msg)
}
func (p *noder) pragma(pos src.Pos, text string) syntax.Pragma {
n.Left = orderexpr(n.Left, order, nil)
n.Left = ordersafeexpr(n.Left, order)
- tmp1 := treecopy(n.Left, src.NoPos)
+ tmp1 := treecopy(n.Left, src.NoXPos)
if tmp1.Op == OINDEXMAP {
tmp1.Etype = 0 // now an rvalue not an lvalue
}
assertI2I2 = Sysfunc("assertI2I2")
}
- defer func(lno src.Pos) {
+ defer func(lno src.XPos) {
lineno = lno
}(setlineno(fn))
}
// lookupVarOutgoing finds the variable's value at the end of block b.
-func (s *simplePhiState) lookupVarOutgoing(b *ssa.Block, t ssa.Type, var_ *Node, line src.Pos) *ssa.Value {
+func (s *simplePhiState) lookupVarOutgoing(b *ssa.Block, t ssa.Type, var_ *Node, line src.XPos) *ssa.Value {
for {
if v := s.defvars[b.ID][var_]; v != nil {
return v
*np = n
}
- n = treecopy(n, src.NoPos)
+ n = treecopy(n, src.NoXPos)
makeaddable(n)
var f *Node
if flag_msan {
_32bit uintptr // size on 32bit platforms
_64bit uintptr // size on 64bit platforms
}{
- {Func{}, 100, 184},
+ {Func{}, 100, 168},
{Name{}, 44, 72},
{Param{}, 24, 48},
- {Node{}, 96, 160},
- {Sym{}, 64, 128},
- {Type{}, 64, 112},
+ {Node{}, 96, 152},
+ {Sym{}, 64, 120},
+ {Type{}, 64, 104},
{MapType{}, 20, 40},
- {ForwardType{}, 20, 40},
+ {ForwardType{}, 20, 32},
{FuncType{}, 28, 48},
{StructType{}, 12, 24},
{InterType{}, 4, 8},
sb *ssa.Value
// line number stack. The current line number is top of stack
- line []src.Pos
+ line []src.XPos
// list of panic calls by function name and line number.
// Used to deduplicate panic calls.
cgoUnsafeArgs bool
noWB bool
- WBPos src.Pos // line number of first write barrier. 0=no write barriers
+ WBPos src.XPos // line number of first write barrier. 0=no write barriers
}
type funcLine struct {
f *Node
- line src.Pos
+ line src.XPos
}
type ssaLabel struct {
func (s *state) Logf(msg string, args ...interface{}) { s.config.Logf(msg, args...) }
func (s *state) Log() bool { return s.config.Log() }
func (s *state) Fatalf(msg string, args ...interface{}) { s.config.Fatalf(s.peekPos(), msg, args...) }
-func (s *state) Warnl(pos src.Pos, msg string, args ...interface{}) {
+func (s *state) Warnl(pos src.XPos, msg string, args ...interface{}) {
s.config.Warnl(pos, msg, args...)
}
func (s *state) Debug_checknil() bool { return s.config.Debug_checknil() }
}
// pushLine pushes a line number on the line number stack.
-func (s *state) pushLine(line src.Pos) {
+func (s *state) pushLine(line src.XPos) {
if !line.IsKnown() {
// the frontend may emit node with line number missing,
// use the parent line number in this case.
}
// peekPos peeks the top of the line number stack.
-func (s *state) peekPos() src.Pos {
+func (s *state) peekPos() src.XPos {
return s.line[len(s.line)-1]
}
// If deref is true, rightIsVolatile reports whether right points to volatile (clobbered by a call) storage.
// Include a write barrier if wb is true.
// skip indicates assignments (at the top level) that can be avoided.
-func (s *state) assign(left *Node, right *ssa.Value, wb, deref bool, line src.Pos, skip skipMask, rightIsVolatile bool) {
+func (s *state) assign(left *Node, right *ssa.Value, wb, deref bool, line src.XPos, skip skipMask, rightIsVolatile bool) {
if left.Op == ONAME && isblank(left) {
return
}
}
// exprPtr evaluates n to a pointer and nil-checks it.
-func (s *state) exprPtr(n *Node, bounded bool, lineno src.Pos) *ssa.Value {
+func (s *state) exprPtr(n *Node, bounded bool, lineno src.XPos) *ssa.Value {
p := s.expr(n)
if bounded || n.NonNil {
if s.f.Config.Debug_checknil() && lineno.Line() > 1 {
// insertWBmove inserts the assignment *left = *right including a write barrier.
// t is the type being assigned.
// If right == nil, then we're zeroing *left.
-func (s *state) insertWBmove(t *Type, left, right *ssa.Value, line src.Pos, rightIsVolatile bool) {
+func (s *state) insertWBmove(t *Type, left, right *ssa.Value, line src.XPos, rightIsVolatile bool) {
// if writeBarrier.enabled {
// typedmemmove(&t, left, right)
// } else {
// insertWBstore inserts the assignment *left = right including a write barrier.
// t is the type being assigned.
-func (s *state) insertWBstore(t *Type, left, right *ssa.Value, line src.Pos, skip skipMask) {
+func (s *state) insertWBstore(t *Type, left, right *ssa.Value, line src.XPos, skip skipMask) {
// store scalar fields
// if writeBarrier.enabled {
// writebarrierptr for pointer fields
}
// SetPos sets the current source position.
-func (s *SSAGenState) SetPos(pos src.Pos) {
+func (s *SSAGenState) SetPos(pos src.XPos) {
lineno = pos
}
return canSSAType(t.(*Type))
}
-func (e *ssaExport) Line(pos src.Pos) string {
+func (e *ssaExport) Line(pos src.XPos) string {
return linestr(pos)
}
}
// Fatal reports a compiler error and exits.
-func (e *ssaExport) Fatalf(pos src.Pos, msg string, args ...interface{}) {
+func (e *ssaExport) Fatalf(pos src.XPos, msg string, args ...interface{}) {
lineno = pos
Fatalf(msg, args...)
}
// Warnl reports a "warning", which is usually flag-triggered
// logging output for the benefit of tests.
-func (e *ssaExport) Warnl(pos src.Pos, fmt_ string, args ...interface{}) {
+func (e *ssaExport) Warnl(pos src.XPos, fmt_ string, args ...interface{}) {
Warnl(pos, fmt_, args...)
}
)
type Error struct {
- pos src.Pos
+ pos src.XPos
msg string
}
}
}
-func adderr(pos src.Pos, format string, args ...interface{}) {
+func adderr(pos src.XPos, format string, args ...interface{}) {
errors = append(errors, Error{
pos: pos,
msg: fmt.Sprintf("%v: %s\n", linestr(pos), fmt.Sprintf(format, args...)),
}
}
-func linestr(pos src.Pos) string {
- return pos.String()
+func linestr(pos src.XPos) string {
+ return Ctxt.PosTable.Pos(pos).String()
}
// lasterror keeps track of the most recently issued error.
// It is used to avoid multiple error messages on the same
// line.
var lasterror struct {
- syntax src.Pos // source position of last syntax error
- other src.Pos // source position of last non-syntax error
- msg string // error message of last non-syntax error
+ syntax src.XPos // source position of last syntax error
+ other src.XPos // source position of last non-syntax error
+ msg string // error message of last non-syntax error
}
// sameline reports whether two positions a, b are on the same line.
-func sameline(a, b src.Pos) bool {
- return a.Filename() == b.Filename() && a.Line() == b.Line()
+func sameline(a, b src.XPos) bool {
+ p := Ctxt.PosTable.Pos(a)
+ q := Ctxt.PosTable.Pos(b)
+ return p.Base() == q.Base() && p.Line() == q.Line()
}
-func yyerrorl(pos src.Pos, format string, args ...interface{}) {
+func yyerrorl(pos src.XPos, format string, args ...interface{}) {
msg := fmt.Sprintf(format, args...)
if strings.HasPrefix(msg, "syntax error") {
hcrash()
}
-func Warnl(line src.Pos, fmt_ string, args ...interface{}) {
+func Warnl(line src.XPos, fmt_ string, args ...interface{}) {
adderr(line, fmt_, args...)
if Debug['m'] != 0 {
flusherrors()
Ctxt.AddImport(file)
}
-func setlineno(n *Node) src.Pos {
+func setlineno(n *Node) src.XPos {
lno := lineno
if n != nil {
switch n.Op {
// Copies of iota ONONAME nodes are assigned the current
// value of iota_. If pos.IsKnown(), it sets the source
// position of newly allocated nodes to pos.
-func treecopy(n *Node, pos src.Pos) *Node {
+func treecopy(n *Node, pos src.XPos) *Node {
if n == nil {
return nil
}
fmt.Printf("genwrapper rcvrtype=%v method=%v newnam=%v\n", rcvr, method, newnam)
}
- lineno = src.MakePos(src.NewFileBase("<autogenerated>", "<autogenerated>"), 1, 0)
+ lineno = MakePos(src.NewFileBase("<autogenerated>", "<autogenerated>"), 1, 0)
dclcontext = PEXTERN
markdcl()
return et
}
-func listtreecopy(l []*Node, pos src.Pos) []*Node {
+func listtreecopy(l []*Node, pos src.XPos) []*Node {
var out []*Node
for _, n := range l {
out = append(out, treecopy(n, pos))
// Possibly still more uses. If you find any, document them.
Xoffset int64
- Pos src.Pos
+ Pos src.XPos
Esc uint16 // EscXXX
Label int32 // largest auto-generated label in this function
- Endlineno src.Pos
- WBPos src.Pos // position of first write barrier
+ Endlineno src.XPos
+ WBPos src.XPos // position of first write barrier
Pragma Pragma // go:xxx function annotations
Dupok bool // duplicate definitions ok
sliceOf *Type
ptrTo *Type
- Sym *Sym // symbol containing name, for named types
- Vargen int32 // unique name for OTYPE/ONAME
- Pos src.Pos // position at which this type was declared, implicitly or explicitly
+ Sym *Sym // symbol containing name, for named types
+ Vargen int32 // unique name for OTYPE/ONAME
+ Pos src.XPos // position at which this type was declared, implicitly or explicitly
Etype EType // kind of type
Noalg bool // suppress hash and eq algorithm generation
// ForwardType contains Type fields specific to forward types.
type ForwardType struct {
- Copyto []*Node // where to copy the eventual value to
- Embedlineno src.Pos // first use of this type as an embedded type
+ Copyto []*Node // where to copy the eventual value to
+ Embedlineno src.XPos // first use of this type as an embedded type
}
// ForwardType returns t's extra forward-type-specific fields.
type mapqueueval struct {
n *Node
- lno src.Pos
+ lno src.XPos
}
// tracks the line numbers at which forward types are first used as map keys
ID ID
// Source position for block's control operation
- Pos src.Pos
+ Pos src.XPos
// The kind of block this is.
Kind BlockKind
fi, err := os.Create(fname)
if err != nil {
- f.Config.Warnl(src.NoPos, "Unable to create after-phase dump file %s", fname)
+ f.Config.Warnl(src.NoXPos, "Unable to create after-phase dump file %s", fname)
return
}
Log() bool
// Fatal reports a compiler error and exits.
- Fatalf(pos src.Pos, msg string, args ...interface{})
+ Fatalf(pos src.XPos, msg string, args ...interface{})
// Warnl writes compiler messages in the form expected by "errorcheck" tests
- Warnl(pos src.Pos, fmt_ string, args ...interface{})
+ Warnl(pos src.XPos, fmt_ string, args ...interface{})
// Fowards the Debug flags from gc
Debug_checknil() bool
SplitInt64(LocalSlot) (LocalSlot, LocalSlot) // returns (hi, lo)
// Line returns a string describing the given position.
- Line(src.Pos) string
+ Line(src.XPos) string
// AllocFrame assigns frame offsets to all live auto variables.
AllocFrame(f *Func)
c.hasGReg = true
c.noDuffDevice = true
default:
- fe.Fatalf(src.NoPos, "arch %s not implemented", arch)
+ fe.Fatalf(src.NoXPos, "arch %s not implemented", arch)
}
c.ctxt = ctxt
c.optimize = optimize
if ev != "" {
v, err := strconv.ParseInt(ev, 10, 64)
if err != nil {
- fe.Fatalf(src.NoPos, "Environment variable GO_SSA_PHI_LOC_CUTOFF (value '%s') did not parse as a number", ev)
+ fe.Fatalf(src.NoXPos, "Environment variable GO_SSA_PHI_LOC_CUTOFF (value '%s') did not parse as a number", ev)
}
c.sparsePhiCutoff = uint64(v) // convert -1 to maxint, for never use sparse
}
func (c *Config) NewFunc() *Func {
// TODO(khr): should this function take name, type, etc. as arguments?
if c.curFunc != nil {
- c.Fatalf(src.NoPos, "NewFunc called without previous Free")
+ c.Fatalf(src.NoXPos, "NewFunc called without previous Free")
}
f := &Func{Config: c, NamedValues: map[LocalSlot][]*Value{}}
c.curFunc = f
return f
}
-func (c *Config) Logf(msg string, args ...interface{}) { c.fe.Logf(msg, args...) }
-func (c *Config) Log() bool { return c.fe.Log() }
-func (c *Config) Fatalf(pos src.Pos, msg string, args ...interface{}) { c.fe.Fatalf(pos, msg, args...) }
-func (c *Config) Warnl(pos src.Pos, msg string, args ...interface{}) { c.fe.Warnl(pos, msg, args...) }
-func (c *Config) Debug_checknil() bool { return c.fe.Debug_checknil() }
-func (c *Config) Debug_wb() bool { return c.fe.Debug_wb() }
+func (c *Config) Logf(msg string, args ...interface{}) { c.fe.Logf(msg, args...) }
+func (c *Config) Log() bool { return c.fe.Log() }
+func (c *Config) Fatalf(pos src.XPos, msg string, args ...interface{}) { c.fe.Fatalf(pos, msg, args...) }
+func (c *Config) Warnl(pos src.XPos, msg string, args ...interface{}) { c.fe.Warnl(pos, msg, args...) }
+func (c *Config) Debug_checknil() bool { return c.fe.Debug_checknil() }
+func (c *Config) Debug_wb() bool { return c.fe.Debug_wb() }
func (c *Config) logDebugHashMatch(evname, name string) {
file := c.logfiles[evname]
var ok error
file, ok = os.Create(tmpfile)
if ok != nil {
- c.Fatalf(src.NoPos, "Could not open hash-testing logfile %s", tmpfile)
+ c.Fatalf(src.NoXPos, "Could not open hash-testing logfile %s", tmpfile)
}
}
c.logfiles[evname] = file
if sz > 0x7fffffff { // work around sparseMap's int32 value type
sz = 0x7fffffff
}
- shadowed.set(v.Args[0].ID, int32(sz), src.NoPos)
+ shadowed.set(v.Args[0].ID, int32(sz), src.NoXPos)
}
}
// walk to previous store
func (d DummyFrontend) SplitArray(s LocalSlot) LocalSlot {
return LocalSlot{s.N, s.Type.ElemType(), s.Off}
}
-func (DummyFrontend) Line(_ src.Pos) string {
+func (DummyFrontend) Line(_ src.XPos) string {
return "unknown.go:0"
}
func (DummyFrontend) AllocFrame(f *Func) {
func (d DummyFrontend) Logf(msg string, args ...interface{}) { d.t.Logf(msg, args...) }
func (d DummyFrontend) Log() bool { return true }
-func (d DummyFrontend) Fatalf(_ src.Pos, msg string, args ...interface{}) { d.t.Fatalf(msg, args...) }
-func (d DummyFrontend) Warnl(_ src.Pos, msg string, args ...interface{}) { d.t.Logf(msg, args...) }
-func (d DummyFrontend) Debug_checknil() bool { return false }
-func (d DummyFrontend) Debug_wb() bool { return false }
+func (d DummyFrontend) Fatalf(_ src.XPos, msg string, args ...interface{}) { d.t.Fatalf(msg, args...) }
+func (d DummyFrontend) Warnl(_ src.XPos, msg string, args ...interface{}) { d.t.Logf(msg, args...) }
+func (d DummyFrontend) Debug_checknil() bool { return false }
+func (d DummyFrontend) Debug_wb() bool { return false }
func (d DummyFrontend) TypeBool() Type { return TypeBool }
func (d DummyFrontend) TypeInt8() Type { return TypeInt8 }
}
// newValue allocates a new Value with the given fields and places it at the end of b.Values.
-func (f *Func) newValue(op Op, t Type, b *Block, pos src.Pos) *Value {
+func (f *Func) newValue(op Op, t Type, b *Block, pos src.XPos) *Value {
var v *Value
if f.freeValues != nil {
v = f.freeValues
}
// NewValue0 returns a new value in the block with no arguments and zero aux values.
-func (b *Block) NewValue0(pos src.Pos, op Op, t Type) *Value {
+func (b *Block) NewValue0(pos src.XPos, op Op, t Type) *Value {
v := b.Func.newValue(op, t, b, pos)
v.AuxInt = 0
v.Args = v.argstorage[:0]
}
// NewValue returns a new value in the block with no arguments and an auxint value.
-func (b *Block) NewValue0I(pos src.Pos, op Op, t Type, auxint int64) *Value {
+func (b *Block) NewValue0I(pos src.XPos, op Op, t Type, auxint int64) *Value {
v := b.Func.newValue(op, t, b, pos)
v.AuxInt = auxint
v.Args = v.argstorage[:0]
}
// NewValue returns a new value in the block with no arguments and an aux value.
-func (b *Block) NewValue0A(pos src.Pos, op Op, t Type, aux interface{}) *Value {
+func (b *Block) NewValue0A(pos src.XPos, 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
}
// NewValue returns a new value in the block with no arguments and both an auxint and aux values.
-func (b *Block) NewValue0IA(pos src.Pos, op Op, t Type, auxint int64, aux interface{}) *Value {
+func (b *Block) NewValue0IA(pos src.XPos, op Op, t Type, auxint int64, aux interface{}) *Value {
v := b.Func.newValue(op, t, b, pos)
v.AuxInt = auxint
v.Aux = aux
}
// NewValue1 returns a new value in the block with one argument and zero aux values.
-func (b *Block) NewValue1(pos src.Pos, op Op, t Type, arg *Value) *Value {
+func (b *Block) NewValue1(pos src.XPos, op Op, t Type, arg *Value) *Value {
v := b.Func.newValue(op, t, b, pos)
v.AuxInt = 0
v.Args = v.argstorage[:1]
}
// NewValue1I returns a new value in the block with one argument and an auxint value.
-func (b *Block) NewValue1I(pos src.Pos, op Op, t Type, auxint int64, arg *Value) *Value {
+func (b *Block) NewValue1I(pos src.XPos, op Op, t Type, auxint int64, arg *Value) *Value {
v := b.Func.newValue(op, t, b, pos)
v.AuxInt = auxint
v.Args = v.argstorage[:1]
}
// NewValue1A returns a new value in the block with one argument and an aux value.
-func (b *Block) NewValue1A(pos src.Pos, op Op, t Type, aux interface{}, arg *Value) *Value {
+func (b *Block) NewValue1A(pos src.XPos, op Op, t Type, aux interface{}, arg *Value) *Value {
v := b.Func.newValue(op, t, b, pos)
v.AuxInt = 0
v.Aux = aux
}
// NewValue1IA returns a new value in the block with one argument and both an auxint and aux values.
-func (b *Block) NewValue1IA(pos src.Pos, op Op, t Type, auxint int64, aux interface{}, arg *Value) *Value {
+func (b *Block) NewValue1IA(pos src.XPos, op Op, t Type, auxint int64, aux interface{}, arg *Value) *Value {
v := b.Func.newValue(op, t, b, pos)
v.AuxInt = auxint
v.Aux = aux
}
// NewValue2 returns a new value in the block with two arguments and zero aux values.
-func (b *Block) NewValue2(pos src.Pos, op Op, t Type, arg0, arg1 *Value) *Value {
+func (b *Block) NewValue2(pos src.XPos, op Op, t Type, arg0, arg1 *Value) *Value {
v := b.Func.newValue(op, t, b, pos)
v.AuxInt = 0
v.Args = v.argstorage[:2]
}
// NewValue2I returns a new value in the block with two arguments and an auxint value.
-func (b *Block) NewValue2I(pos src.Pos, op Op, t Type, auxint int64, arg0, arg1 *Value) *Value {
+func (b *Block) NewValue2I(pos src.XPos, op Op, t Type, auxint int64, arg0, arg1 *Value) *Value {
v := b.Func.newValue(op, t, b, pos)
v.AuxInt = auxint
v.Args = v.argstorage[:2]
}
// NewValue3 returns a new value in the block with three arguments and zero aux values.
-func (b *Block) NewValue3(pos src.Pos, op Op, t Type, arg0, arg1, arg2 *Value) *Value {
+func (b *Block) NewValue3(pos src.XPos, op Op, t Type, arg0, arg1, arg2 *Value) *Value {
v := b.Func.newValue(op, t, b, pos)
v.AuxInt = 0
v.Args = v.argstorage[:3]
}
// NewValue3I returns a new value in the block with three arguments and an auxint value.
-func (b *Block) NewValue3I(pos src.Pos, op Op, t Type, auxint int64, arg0, arg1, arg2 *Value) *Value {
+func (b *Block) NewValue3I(pos src.XPos, op Op, t Type, auxint int64, arg0, arg1, arg2 *Value) *Value {
v := b.Func.newValue(op, t, b, pos)
v.AuxInt = auxint
v.Args = v.argstorage[:3]
}
// NewValue4 returns a new value in the block with four arguments and zero aux values.
-func (b *Block) NewValue4(pos src.Pos, op Op, t Type, arg0, arg1, arg2, arg3 *Value) *Value {
+func (b *Block) NewValue4(pos src.XPos, op Op, t Type, arg0, arg1, arg2, arg3 *Value) *Value {
v := b.Func.newValue(op, t, b, pos)
v.AuxInt = 0
v.Args = []*Value{arg0, arg1, arg2, arg3}
}
// constVal returns a constant value for c.
-func (f *Func) constVal(pos src.Pos, op Op, t Type, c int64, setAux bool) *Value {
+func (f *Func) constVal(pos src.XPos, op Op, t Type, c int64, setAux bool) *Value {
if f.constants == nil {
f.constants = make(map[int64][]*Value)
}
)
// ConstInt returns an int constant representing its argument.
-func (f *Func) ConstBool(pos src.Pos, t Type, c bool) *Value {
+func (f *Func) ConstBool(pos src.XPos, t Type, c bool) *Value {
i := int64(0)
if c {
i = 1
}
return f.constVal(pos, OpConstBool, t, i, true)
}
-func (f *Func) ConstInt8(pos src.Pos, t Type, c int8) *Value {
+func (f *Func) ConstInt8(pos src.XPos, t Type, c int8) *Value {
return f.constVal(pos, OpConst8, t, int64(c), true)
}
-func (f *Func) ConstInt16(pos src.Pos, t Type, c int16) *Value {
+func (f *Func) ConstInt16(pos src.XPos, t Type, c int16) *Value {
return f.constVal(pos, OpConst16, t, int64(c), true)
}
-func (f *Func) ConstInt32(pos src.Pos, t Type, c int32) *Value {
+func (f *Func) ConstInt32(pos src.XPos, t Type, c int32) *Value {
return f.constVal(pos, OpConst32, t, int64(c), true)
}
-func (f *Func) ConstInt64(pos src.Pos, t Type, c int64) *Value {
+func (f *Func) ConstInt64(pos src.XPos, t Type, c int64) *Value {
return f.constVal(pos, OpConst64, t, c, true)
}
-func (f *Func) ConstFloat32(pos src.Pos, t Type, c float64) *Value {
+func (f *Func) ConstFloat32(pos src.XPos, t Type, c float64) *Value {
return f.constVal(pos, OpConst32F, t, int64(math.Float64bits(float64(float32(c)))), true)
}
-func (f *Func) ConstFloat64(pos src.Pos, t Type, c float64) *Value {
+func (f *Func) ConstFloat64(pos src.XPos, t Type, c float64) *Value {
return f.constVal(pos, OpConst64F, t, int64(math.Float64bits(c)), true)
}
-func (f *Func) ConstSlice(pos src.Pos, t Type) *Value {
+func (f *Func) ConstSlice(pos src.XPos, t Type) *Value {
return f.constVal(pos, OpConstSlice, t, constSliceMagic, false)
}
-func (f *Func) ConstInterface(pos src.Pos, t Type) *Value {
+func (f *Func) ConstInterface(pos src.XPos, t Type) *Value {
return f.constVal(pos, OpConstInterface, t, constInterfaceMagic, false)
}
-func (f *Func) ConstNil(pos src.Pos, t Type) *Value {
+func (f *Func) ConstNil(pos src.XPos, t Type) *Value {
return f.constVal(pos, OpConstNil, t, constNilMagic, false)
}
-func (f *Func) ConstEmptyString(pos src.Pos, t Type) *Value {
+func (f *Func) ConstEmptyString(pos src.XPos, t Type) *Value {
v := f.constVal(pos, OpConstString, t, constEmptyStringMagic, false)
v.Aux = ""
return v
blocks[bloc.name] = b
for _, valu := range bloc.valus {
// args are filled in the second pass.
- values[valu.name] = b.NewValue0IA(src.NoPos, valu.op, valu.t, valu.auxint, valu.aux)
+ values[valu.name] = b.NewValue0IA(src.NoXPos, valu.op, valu.t, valu.auxint, valu.aux)
}
}
// Connect the blocks together and specify control values.
Bloc("entry",
Valu("mem", OpInitMem, TypeMem, 0, nil),
Exit("mem")))
- v1 := f.f.ConstBool(src.NoPos, TypeBool, false)
- v2 := f.f.ConstBool(src.NoPos, TypeBool, true)
+ v1 := f.f.ConstBool(src.NoXPos, TypeBool, false)
+ v2 := f.f.ConstBool(src.NoXPos, TypeBool, true)
f.f.freeValue(v1)
f.f.freeValue(v2)
- v3 := f.f.ConstBool(src.NoPos, TypeBool, false)
- v4 := f.f.ConstBool(src.NoPos, TypeBool, true)
+ v3 := f.f.ConstBool(src.NoXPos, TypeBool, false)
+ v4 := f.f.ConstBool(src.NoXPos, TypeBool, true)
if v3.AuxInt != 0 {
t.Errorf("expected %s to have auxint of 0\n", v3.LongString())
}
func NewHTMLWriter(path string, logger Logger, funcname string) *HTMLWriter {
out, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
if err != nil {
- logger.Fatalf(src.NoPos, "%v", err)
+ logger.Fatalf(src.NoXPos, "%v", err)
}
html := HTMLWriter{File: out, Logger: logger}
html.start(funcname)
func (w *HTMLWriter) Printf(msg string, v ...interface{}) {
if _, err := fmt.Fprintf(w.File, msg, v...); err != nil {
- w.Fatalf(src.NoPos, "%v", err)
+ w.Fatalf(src.NoXPos, "%v", err)
}
}
func (w *HTMLWriter) WriteString(s string) {
if _, err := w.File.WriteString(s); err != nil {
- w.Fatalf(src.NoPos, "%v", err)
+ w.Fatalf(src.NoXPos, "%v", err)
}
}
}
type use struct {
- dist int32 // distance from start of the block to a use of a value
- pos src.Pos // source position of the use
- next *use // linked list of uses of a value in nondecreasing dist order
+ dist int32 // distance from start of the block to a use of a value
+ pos src.XPos // source position of the use
+ next *use // linked list of uses of a value in nondecreasing dist order
}
type valState struct {
type startReg struct {
r register
- vid ID // pre-regalloc value needed in this register
- pos src.Pos // source position of use of this register
+ vid ID // pre-regalloc value needed in this register
+ pos src.XPos // source position of use of this register
}
// freeReg frees up register r. Any current user of r is kicked out.
// allocated register is marked nospill so the assignment cannot be
// undone until the caller allows it by clearing nospill. Returns a
// *Value which is either v or a copy of v allocated to the chosen register.
-func (s *regAllocState) allocValToReg(v *Value, mask regMask, nospill bool, pos src.Pos) *Value {
+func (s *regAllocState) allocValToReg(v *Value, mask regMask, nospill bool, pos src.XPos) *Value {
vi := &s.values[v.ID]
// Check if v is already in a requested register.
case "s390x":
// nothing to do, R10 & R11 already reserved
default:
- s.f.Config.fe.Fatalf(src.NoPos, "arch %s not implemented", s.f.Config.arch)
+ s.f.Config.fe.Fatalf(src.NoXPos, "arch %s not implemented", s.f.Config.arch)
}
}
if s.f.Config.nacl {
// Adds a use record for id at distance dist from the start of the block.
// All calls to addUse must happen with nonincreasing dist.
-func (s *regAllocState) addUse(id ID, dist int32, pos src.Pos) {
+func (s *regAllocState) addUse(id ID, dist int32, pos src.XPos) {
r := s.freeUseRecords
if r != nil {
s.freeUseRecords = r.next
}
type contentRecord struct {
- vid ID // pre-regalloc value
- c *Value // cached value
- final bool // this is a satisfied destination
- pos src.Pos // source position of use of the value
+ vid ID // pre-regalloc value
+ c *Value // cached value
+ final bool // this is a satisfied destination
+ pos src.XPos // source position of use of the value
}
type dstRecord struct {
loc Location // register or stack slot
vid ID // pre-regalloc value it should contain
splice **Value // place to store reference to the generating instruction
- pos src.Pos // source position of use of this location
+ pos src.XPos // source position of use of this location
}
// setup initializes the edge state for shuffling.
// Live registers can be sources.
for _, x := range srcReg {
- e.set(&e.s.registers[x.r], x.v.ID, x.c, false, src.NoPos) // don't care the position of the source
+ e.set(&e.s.registers[x.r], x.v.ID, x.c, false, src.NoXPos) // don't care the position of the source
}
// So can all of the spill locations.
for _, spillID := range stacklive {
v := e.s.orig[spillID]
spill := e.s.values[v.ID].spill
- e.set(e.s.f.getHome(spillID), v.ID, spill, false, src.NoPos) // don't care the position of the source
+ e.set(e.s.f.getHome(spillID), v.ID, spill, false, src.NoXPos) // don't care the position of the source
}
// Figure out all the destinations we need.
// processDest generates code to put value vid into location loc. Returns true
// if progress was made.
-func (e *edgeState) processDest(loc Location, vid ID, splice **Value, pos src.Pos) bool {
+func (e *edgeState) processDest(loc Location, vid ID, splice **Value, pos src.XPos) bool {
occupant := e.contents[loc]
if occupant.vid == vid {
// Value is already in the correct place.
}
// set changes the contents of location loc to hold the given value and its cached representative.
-func (e *edgeState) set(loc Location, vid ID, c *Value, final bool, pos src.Pos) {
+func (e *edgeState) set(loc Location, vid ID, c *Value, final bool, pos src.XPos) {
e.s.f.setHome(c, loc)
e.erase(loc)
e.contents[loc] = contentRecord{vid, c, final, pos}
}
type liveInfo struct {
- ID ID // ID of value
- dist int32 // # of instructions before next use
- pos src.Pos // source position of next use
+ ID ID // ID of value
+ dist int32 // # of instructions before next use
+ pos src.XPos // source position of next use
}
// dblock contains information about desired & avoid registers at the end of a block.
_32bit uintptr // size on 32bit platforms
_64bit uintptr // size on 64bit platforms
}{
- {Value{}, 72, 128},
- {Block{}, 152, 304},
+ {Value{}, 72, 120},
+ {Block{}, 152, 288},
}
for _, tt := range tests {
type sparseEntry struct {
key ID
val int32
- aux src.Pos
+ aux src.XPos
}
type sparseMap struct {
return -1
}
-func (s *sparseMap) set(k ID, v int32, a src.Pos) {
+func (s *sparseMap) set(k ID, v int32, a src.XPos) {
i := s.sparse[k]
if i < int32(len(s.dense)) && s.dense[i].key == k {
s.dense[i].val = v
s.dense[i].val |= 1 << v
return
}
- s.dense = append(s.dense, sparseEntry{k, 1 << v, src.NoPos})
+ s.dense = append(s.dense, sparseEntry{k, 1 << v, src.NoXPos})
s.sparse[k] = int32(len(s.dense)) - 1
}
return new(stackAllocState)
}
if s.f != nil {
- f.Config.Fatalf(src.NoPos, "newStackAllocState called without previous free")
+ f.Config.Fatalf(src.NoXPos, "newStackAllocState called without previous free")
}
return s
}
Block *Block
// Source position
- Pos src.Pos
+ Pos src.XPos
// Use count. Each appearance in Value.Args and Block.Control counts once.
Uses int32
// wbcall emits write barrier runtime call in b, returns memory.
// if valIsVolatile, it moves val into temp space before making the call.
-func wbcall(pos src.Pos, b *Block, fn interface{}, typ interface{}, ptr, val, mem, sp, sb *Value, valIsVolatile bool) *Value {
+func wbcall(pos src.XPos, b *Block, fn interface{}, typ interface{}, ptr, val, mem, sp, sb *Value, valIsVolatile bool) *Value {
config := b.Func.Config
var tmp GCNode
}
// This is modified copy of linkgetline to work from src.Pos.
-func linkgetlineFromPos(ctxt *Link, pos src.Pos) (f *LSym, l int32) {
+func linkgetlineFromPos(ctxt *Link, xpos src.XPos) (f *LSym, l int32) {
+ pos := ctxt.PosTable.Pos(xpos)
filename := pos.AbsFilename()
if !pos.IsKnown() || filename == "" {
return Linklookup(ctxt, "??", HistVersion), 0
}
for _, test := range tests {
- f, l := linkgetlineFromPos(ctxt, test.pos)
+ f, l := linkgetlineFromPos(ctxt, ctxt.PosTable.XPos(test.pos))
got := fmt.Sprintf("%s:%d", f.Name, l)
if got != test.want {
t.Errorf("linkgetline(%v) = %q, want %q", test.pos, got, test.want)
Forwd *Prog // for x86 back end
Rel *Prog // for x86, arm back ends
Pc int64 // for back ends or assembler: virtual or actual program counter, depending on phase
- Pos src.Pos // source position of this instruction
+ Pos src.XPos // source position of this instruction
Spadj int32 // effect of instruction on stack pointer (increment or decrement amount)
As As // assembler opcode
Reg int16 // 2nd source operand
Bso *bufio.Writer
Pathname string
Hash map[SymVer]*LSym
+ PosTable src.PosTable
Imports []string
Plists []*Plist
Sym_div *LSym
}{
{Addr{}, 40, 64},
{LSym{}, 76, 128},
- {Prog{}, 148, 240},
+ {Prog{}, 148, 232},
}
for _, tt := range tests {
}
func (p *Prog) Line() string {
- return p.Pos.String()
+ return p.Ctxt.PosTable.Pos(p.Pos).String()
}
var armCondCode = []string{
}
// IsKnown reports whether the position p is known.
+// A position is known if it either has a non-nil
+// position base, or a non-zero line number.
func (p Pos) IsKnown() bool {
return p.base != nil || p.Line() != 0
}
--- /dev/null
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements the compressed encoding of source
+// positions using a lookup table.
+
+package src
+
+// XPos is a more compact representation of Pos.
+type XPos struct {
+ index int32
+ lico
+}
+
+// NoXPos is a valid unknown position.
+var NoXPos XPos
+
+// IsKnown reports whether the position p is known.
+// XPos.IsKnown() matches Pos.IsKnown() for corresponding
+// positions.
+func (p XPos) IsKnown() bool {
+ return p.index != 0 || p.Line() != 0
+}
+
+// Before reports whether the position p comes before q in the source.
+// For positions with different bases, ordering is by base index.
+func (p XPos) Before(q XPos) bool {
+ n, m := p.index, q.index
+ return n < m || n == m && p.lico < q.lico
+}
+
+// After reports whether the position p comes after q in the source.
+// For positions with different bases, ordering is by base index.
+func (p XPos) After(q XPos) bool {
+ n, m := p.index, q.index
+ return n > m || n == m && p.lico > q.lico
+}
+
+// A PosTable tracks Pos -> XPos conversions and vice versa.
+// Its zero value is a ready-to-use PosTable.
+type PosTable struct {
+ baseList []*PosBase
+ indexMap map[*PosBase]int
+}
+
+// XPos returns the corresponding XPos for the given pos,
+// adding pos to t if necessary.
+func (t *PosTable) XPos(pos Pos) XPos {
+ m := t.indexMap
+ if m == nil {
+ // Create new list and map and populate with nil
+ // base so that NoPos always gets index 0.
+ t.baseList = append(t.baseList, nil)
+ m = map[*PosBase]int{nil: 0}
+ t.indexMap = m
+ }
+ i, ok := m[pos.base]
+ if !ok {
+ i = len(t.baseList)
+ t.baseList = append(t.baseList, pos.base)
+ t.indexMap[pos.base] = i
+ }
+ return XPos{int32(i), pos.lico}
+}
+
+// Pos returns the corresponding Pos for the given p.
+// If p cannot be translated via t, the function panics.
+func (t *PosTable) Pos(p XPos) Pos {
+ var base *PosBase
+ if p.index != 0 {
+ base = t.baseList[p.index]
+ }
+ return Pos{base, p.lico}
+}
--- /dev/null
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package src
+
+import (
+ "testing"
+ "unsafe"
+)
+
+func TestNoXPos(t *testing.T) {
+ var tab PosTable
+ if tab.Pos(NoXPos) != NoPos {
+ t.Errorf("failed to translate NoXPos to Pos using zero PosTable")
+ }
+}
+
+func TestConversion(t *testing.T) {
+ b1 := NewFileBase("b1", "b1")
+ b2 := NewFileBase("b2", "b2")
+ b3 := NewLinePragmaBase(MakePos(b1, 10, 0), "b3", 123)
+
+ var tab PosTable
+ for _, want := range []Pos{
+ NoPos,
+ MakePos(nil, 0, 0), // same table entry as NoPos
+ MakePos(b1, 0, 0),
+ MakePos(nil, 10, 20), // same table entry as NoPos
+ MakePos(b2, 10, 20),
+ MakePos(b3, 10, 20),
+ MakePos(b3, 123, 0), // same table entry as MakePos(b3, 10, 20)
+ } {
+ xpos := tab.XPos(want)
+ got := tab.Pos(xpos)
+ if got != want {
+ t.Errorf("got %v; want %v", got, want)
+ }
+ }
+
+ if len(tab.baseList) != len(tab.indexMap) {
+ t.Errorf("table length discrepancy: %d != %d", len(tab.baseList), len(tab.indexMap))
+ }
+
+ const wantLen = 4
+ if len(tab.baseList) != wantLen {
+ t.Errorf("got table length %d; want %d", len(tab.baseList), wantLen)
+ }
+
+ if got := tab.XPos(NoPos); got != NoXPos {
+ t.Errorf("XPos(NoPos): got %v; want %v", got, NoXPos)
+ }
+
+ if tab.baseList[0] != nil || tab.indexMap[nil] != 0 {
+ t.Errorf("nil base not at index 0")
+ }
+}
+
+func TestSize(t *testing.T) {
+ var p XPos
+ if unsafe.Alignof(p) != 4 {
+ t.Errorf("alignment = %s; want 4", unsafe.Alignof(p))
+ }
+ if unsafe.Sizeof(p) != 8 {
+ t.Errorf("size = %s; want 8", unsafe.Sizeof(p))
+ }
+}