all: merge dev.inline into master

Change-Id: I7715581a04e513dcda9918e853fa6b1ddc703770
This commit is contained in:
Russ Cox 2017-02-01 09:35:27 -05:00
commit 47ce87877b
124 changed files with 6096 additions and 5655 deletions

View file

@ -61,7 +61,7 @@ func (p *Parser) append(prog *obj.Prog, cond string, doLabel bool) {
} }
prog.Pc = p.pc prog.Pc = p.pc
if *flags.Debug { if *flags.Debug {
fmt.Println(p.histLineNum, prog) fmt.Println(p.lineNum, prog)
} }
if testOut != nil { if testOut != nil {
fmt.Fprintln(testOut, prog) fmt.Fprintln(testOut, prog)
@ -161,10 +161,10 @@ func (p *Parser) asmText(word string, operands [][]lex.Token) {
argSize = p.positiveAtoi(op[1].String()) argSize = p.positiveAtoi(op[1].String())
} }
prog := &obj.Prog{ prog := &obj.Prog{
Ctxt: p.ctxt, Ctxt: p.ctxt,
As: obj.ATEXT, As: obj.ATEXT,
Lineno: p.histLineNum, Pos: p.pos(),
From: nameAddr, From: nameAddr,
From3: &obj.Addr{ From3: &obj.Addr{
Type: obj.TYPE_CONST, Type: obj.TYPE_CONST,
Offset: flag, Offset: flag,
@ -294,11 +294,11 @@ func (p *Parser) asmPCData(word string, operands [][]lex.Token) {
// log.Printf("PCDATA $%d, $%d", key.Offset, value.Offset) // log.Printf("PCDATA $%d, $%d", key.Offset, value.Offset)
prog := &obj.Prog{ prog := &obj.Prog{
Ctxt: p.ctxt, Ctxt: p.ctxt,
As: obj.APCDATA, As: obj.APCDATA,
Lineno: p.histLineNum, Pos: p.pos(),
From: key, From: key,
To: value, To: value,
} }
p.append(prog, "", true) p.append(prog, "", true)
} }
@ -324,11 +324,11 @@ func (p *Parser) asmFuncData(word string, operands [][]lex.Token) {
} }
prog := &obj.Prog{ prog := &obj.Prog{
Ctxt: p.ctxt, Ctxt: p.ctxt,
As: obj.AFUNCDATA, As: obj.AFUNCDATA,
Lineno: p.histLineNum, Pos: p.pos(),
From: valueAddr, From: valueAddr,
To: nameAddr, To: nameAddr,
} }
p.append(prog, "", true) p.append(prog, "", true)
} }
@ -340,9 +340,9 @@ func (p *Parser) asmFuncData(word string, operands [][]lex.Token) {
func (p *Parser) asmJump(op obj.As, cond string, a []obj.Addr) { func (p *Parser) asmJump(op obj.As, cond string, a []obj.Addr) {
var target *obj.Addr var target *obj.Addr
prog := &obj.Prog{ prog := &obj.Prog{
Ctxt: p.ctxt, Ctxt: p.ctxt,
Lineno: p.histLineNum, Pos: p.pos(),
As: op, As: op,
} }
switch len(a) { switch len(a) {
case 1: case 1:
@ -468,9 +468,9 @@ func (p *Parser) branch(jmp, target *obj.Prog) {
func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) { func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
// fmt.Printf("%s %+v\n", op, a) // fmt.Printf("%s %+v\n", op, a)
prog := &obj.Prog{ prog := &obj.Prog{
Ctxt: p.ctxt, Ctxt: p.ctxt,
Lineno: p.histLineNum, Pos: p.pos(),
As: op, As: op,
} }
switch len(a) { switch len(a) {
case 0: case 0:

View file

@ -26,10 +26,9 @@ import (
// result against a golden file. // result against a golden file.
func testEndToEnd(t *testing.T, goarch, file string) { func testEndToEnd(t *testing.T, goarch, file string) {
lex.InitHist()
input := filepath.Join("testdata", file+".s") input := filepath.Join("testdata", file+".s")
architecture, ctxt := setArch(goarch) architecture, ctxt := setArch(goarch)
lexer := lex.NewLexer(input, ctxt) lexer := lex.NewLexer(input)
parser := NewParser(ctxt, architecture, lexer) parser := NewParser(ctxt, architecture, lexer)
pList := obj.Linknewplist(ctxt) pList := obj.Linknewplist(ctxt)
var ok bool var ok bool
@ -264,10 +263,9 @@ var (
) )
func testErrors(t *testing.T, goarch, file string) { func testErrors(t *testing.T, goarch, file string) {
lex.InitHist()
input := filepath.Join("testdata", file+".s") input := filepath.Join("testdata", file+".s")
architecture, ctxt := setArch(goarch) architecture, ctxt := setArch(goarch)
lexer := lex.NewLexer(input, ctxt) lexer := lex.NewLexer(input)
parser := NewParser(ctxt, architecture, lexer) parser := NewParser(ctxt, architecture, lexer)
pList := obj.Linknewplist(ctxt) pList := obj.Linknewplist(ctxt)
var ok bool var ok bool

View file

@ -19,14 +19,14 @@ import (
"cmd/asm/internal/flags" "cmd/asm/internal/flags"
"cmd/asm/internal/lex" "cmd/asm/internal/lex"
"cmd/internal/obj" "cmd/internal/obj"
"cmd/internal/src"
"cmd/internal/sys" "cmd/internal/sys"
) )
type Parser struct { type Parser struct {
lex lex.TokenReader lex lex.TokenReader
lineNum int // Line number in source file. lineNum int // Line number in source file.
histLineNum int32 // Cumulative line number across source files. errorLine int // Line number of last error.
errorLine int32 // (Cumulative) line number of last error.
errorCount int // Number of errors. errorCount int // Number of errors.
pc int64 // virtual PC; count of Progs; doesn't advance for GLOBL or DATA. pc int64 // virtual PC; count of Progs; doesn't advance for GLOBL or DATA.
input []lex.Token input []lex.Token
@ -60,7 +60,7 @@ func NewParser(ctxt *obj.Link, ar *arch.Arch, lexer lex.TokenReader) *Parser {
} }
} }
// panicOnError is enable when testing to abort execution on the first error // panicOnError is enabled when testing to abort execution on the first error
// and turn it into a recoverable panic. // and turn it into a recoverable panic.
var panicOnError bool var panicOnError bool
@ -68,11 +68,11 @@ func (p *Parser) errorf(format string, args ...interface{}) {
if panicOnError { if panicOnError {
panic(fmt.Errorf(format, args...)) panic(fmt.Errorf(format, args...))
} }
if p.histLineNum == p.errorLine { if p.lineNum == p.errorLine {
// Only one error per line. // Only one error per line.
return return
} }
p.errorLine = p.histLineNum p.errorLine = p.lineNum
if p.lex != nil { if p.lex != nil {
// Put file and line information on head of message. // Put file and line information on head of message.
format = "%s:%d: " + format + "\n" format = "%s:%d: " + format + "\n"
@ -85,6 +85,10 @@ func (p *Parser) errorf(format string, args ...interface{}) {
} }
} }
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) { func (p *Parser) Parse() (*obj.Prog, bool) {
for p.line() { for p.line() {
} }
@ -105,7 +109,6 @@ func (p *Parser) line() bool {
// are labeled with this line. Otherwise we complain after we've absorbed // are labeled with this line. Otherwise we complain after we've absorbed
// the terminating newline and the line numbers are off by one in errors. // the terminating newline and the line numbers are off by one in errors.
p.lineNum = p.lex.Line() p.lineNum = p.lex.Line()
p.histLineNum = lex.HistLine()
switch tok { switch tok {
case '\n', ';': case '\n', ';':
continue continue

View file

@ -56,7 +56,6 @@ func TestErroneous(t *testing.T) {
for _, test := range tests { for _, test := range tests {
parser.errorCount = 0 parser.errorCount = 0
parser.lineNum++ parser.lineNum++
parser.histLineNum++
if !parser.pseudo(test.pseudo, tokenize(test.operands)) { if !parser.pseudo(test.pseudo, tokenize(test.operands)) {
t.Fatalf("Wrong pseudo-instruction: %s", test.pseudo) t.Fatalf("Wrong pseudo-instruction: %s", test.pseudo)
} }

View file

@ -13,6 +13,7 @@ import (
"text/scanner" "text/scanner"
"cmd/asm/internal/flags" "cmd/asm/internal/flags"
"cmd/internal/src"
) )
// Input is the main input: a stack of readers and some macro definitions. // Input is the main input: a stack of readers and some macro definitions.
@ -290,7 +291,7 @@ func lookup(args []string, arg string) int {
func (in *Input) invokeMacro(macro *Macro) { func (in *Input) invokeMacro(macro *Macro) {
// If the macro has no arguments, just substitute the text. // If the macro has no arguments, just substitute the text.
if macro.args == nil { if macro.args == nil {
in.Push(NewSlice(in.File(), in.Line(), macro.tokens)) in.Push(NewSlice(in.Base(), in.Line(), macro.tokens))
return return
} }
tok := in.Stack.Next() tok := in.Stack.Next()
@ -300,7 +301,7 @@ func (in *Input) invokeMacro(macro *Macro) {
in.peekToken = tok in.peekToken = tok
in.peekText = in.text in.peekText = in.text
in.peek = true in.peek = true
in.Push(NewSlice(in.File(), in.Line(), []Token{Make(macroName, macro.name)})) in.Push(NewSlice(in.Base(), in.Line(), []Token{Make(macroName, macro.name)}))
return return
} }
actuals := in.argsFor(macro) actuals := in.argsFor(macro)
@ -317,7 +318,7 @@ func (in *Input) invokeMacro(macro *Macro) {
} }
tokens = append(tokens, substitution...) tokens = append(tokens, substitution...)
} }
in.Push(NewSlice(in.File(), in.Line(), tokens)) in.Push(NewSlice(in.Base(), in.Line(), tokens))
} }
// argsFor returns a map from formal name to actual value for this argumented macro invocation. // argsFor returns a map from formal name to actual value for this argumented macro invocation.
@ -452,8 +453,8 @@ func (in *Input) line() {
if tok != '\n' { if tok != '\n' {
in.Error("unexpected token at end of #line: ", tok) in.Error("unexpected token at end of #line: ", tok)
} }
linkCtxt.LineHist.Update(histLine, file, line) pos := src.MakePos(in.Base(), uint(in.Line()), uint(in.Col()))
in.Stack.SetPos(line, file) in.Stack.SetBase(src.NewLinePragmaBase(pos, file, uint(line)))
} }
// #undef processing // #undef processing

View file

@ -12,7 +12,7 @@ import (
"strings" "strings"
"text/scanner" "text/scanner"
"cmd/internal/obj" "cmd/internal/src"
) )
// A ScanToken represents an input item. It is a simple wrapping of rune, as // A ScanToken represents an input item. It is a simple wrapping of rune, as
@ -57,23 +57,8 @@ func (t ScanToken) String() string {
} }
} }
var (
// It might be nice if these weren't global.
linkCtxt *obj.Link // The link context for all instructions.
histLine int = 1 // The cumulative count of lines processed.
)
// HistLine reports the cumulative source line number of the token,
// for use in the Prog structure for the linker. (It's always handling the
// instruction from the current lex line.)
// It returns int32 because that's what type ../asm prefers.
func HistLine() int32 {
return int32(histLine)
}
// NewLexer returns a lexer for the named file and the given link context. // NewLexer returns a lexer for the named file and the given link context.
func NewLexer(name string, ctxt *obj.Link) TokenReader { func NewLexer(name string) TokenReader {
linkCtxt = ctxt
input := NewInput(name) input := NewInput(name)
fd, err := os.Open(name) fd, err := os.Open(name)
if err != nil { if err != nil {
@ -83,16 +68,11 @@ func NewLexer(name string, ctxt *obj.Link) TokenReader {
return input return input
} }
// InitHist sets the line count to 1, for reproducible testing.
func InitHist() {
histLine = 1
}
// The other files in this directory each contain an implementation of TokenReader. // The other files in this directory each contain an implementation of TokenReader.
// A TokenReader is like a reader, but returns lex tokens of type Token. It also can tell you what // A TokenReader is like a reader, but returns lex tokens of type Token. It also can tell you what
// the text of the most recently returned token is, and where it was found. // the text of the most recently returned token is, and where it was found.
// The underlying scanner elides all spaces except newline, so the input looks like a stream of // The underlying scanner elides all spaces except newline, so the input looks like a stream of
// Tokens; original spacing is lost but we don't need it. // Tokens; original spacing is lost but we don't need it.
type TokenReader interface { type TokenReader interface {
// Next returns the next token. // Next returns the next token.
@ -102,12 +82,14 @@ type TokenReader interface {
Text() string Text() string
// File reports the source file name of the token. // File reports the source file name of the token.
File() string File() string
// Base reports the position base of the token.
Base() *src.PosBase
// SetBase sets the position base.
SetBase(*src.PosBase)
// Line reports the source line number of the token. // Line reports the source line number of the token.
Line() int Line() int
// Col reports the source column number of the token. // Col reports the source column number of the token.
Col() int Col() int
// SetPos sets the file and line number.
SetPos(line int, file string)
// Close does any teardown required. // Close does any teardown required.
Close() Close()
} }

View file

@ -4,22 +4,26 @@
package lex package lex
import "text/scanner" import (
"text/scanner"
"cmd/internal/src"
)
// A Slice reads from a slice of Tokens. // A Slice reads from a slice of Tokens.
type Slice struct { type Slice struct {
tokens []Token tokens []Token
fileName string base *src.PosBase
line int line int
pos int pos int
} }
func NewSlice(fileName string, line int, tokens []Token) *Slice { func NewSlice(base *src.PosBase, line int, tokens []Token) *Slice {
return &Slice{ return &Slice{
tokens: tokens, tokens: tokens,
fileName: fileName, base: base,
line: line, line: line,
pos: -1, // Next will advance to zero. pos: -1, // Next will advance to zero.
} }
} }
@ -36,7 +40,17 @@ func (s *Slice) Text() string {
} }
func (s *Slice) File() string { func (s *Slice) File() string {
return s.fileName return s.base.Filename()
}
func (s *Slice) Base() *src.PosBase {
return s.base
}
func (s *Slice) SetBase(base *src.PosBase) {
// Cannot happen because we only have slices of already-scanned text,
// but be prepared.
s.base = base
} }
func (s *Slice) Line() int { func (s *Slice) Line() int {
@ -56,12 +70,5 @@ func (s *Slice) Col() int {
return s.pos return s.pos
} }
func (s *Slice) SetPos(line int, file string) {
// Cannot happen because we only have slices of already-scanned
// text, but be prepared.
s.line = line
s.fileName = file
}
func (s *Slice) Close() { func (s *Slice) Close() {
} }

View file

@ -4,7 +4,11 @@
package lex package lex
import "text/scanner" import (
"text/scanner"
"cmd/internal/src"
)
// A Stack is a stack of TokenReaders. As the top TokenReader hits EOF, // A Stack is a stack of TokenReaders. As the top TokenReader hits EOF,
// it resumes reading the next one down. // it resumes reading the next one down.
@ -34,7 +38,15 @@ func (s *Stack) Text() string {
} }
func (s *Stack) File() string { func (s *Stack) File() string {
return s.tr[len(s.tr)-1].File() return s.Base().Filename()
}
func (s *Stack) Base() *src.PosBase {
return s.tr[len(s.tr)-1].Base()
}
func (s *Stack) SetBase(base *src.PosBase) {
s.tr[len(s.tr)-1].SetBase(base)
} }
func (s *Stack) Line() int { func (s *Stack) Line() int {
@ -45,9 +57,5 @@ func (s *Stack) Col() int {
return s.tr[len(s.tr)-1].Col() return s.tr[len(s.tr)-1].Col()
} }
func (s *Stack) SetPos(line int, file string) {
s.tr[len(s.tr)-1].SetPos(line, file)
}
func (s *Stack) Close() { // Unused. func (s *Stack) Close() { // Unused.
} }

View file

@ -10,17 +10,21 @@ import (
"strings" "strings"
"text/scanner" "text/scanner"
"unicode" "unicode"
"cmd/asm/internal/flags"
"cmd/internal/obj"
"cmd/internal/src"
) )
// A Tokenizer is a simple wrapping of text/scanner.Scanner, configured // A Tokenizer is a simple wrapping of text/scanner.Scanner, configured
// for our purposes and made a TokenReader. It forms the lowest level, // for our purposes and made a TokenReader. It forms the lowest level,
// turning text from readers into tokens. // turning text from readers into tokens.
type Tokenizer struct { type Tokenizer struct {
tok ScanToken tok ScanToken
s *scanner.Scanner s *scanner.Scanner
line int base *src.PosBase
fileName string line int
file *os.File // If non-nil, file descriptor to close. file *os.File // If non-nil, file descriptor to close.
} }
func NewTokenizer(name string, r io.Reader, file *os.File) *Tokenizer { func NewTokenizer(name string, r io.Reader, file *os.File) *Tokenizer {
@ -37,14 +41,11 @@ func NewTokenizer(name string, r io.Reader, file *os.File) *Tokenizer {
scanner.ScanComments scanner.ScanComments
s.Position.Filename = name s.Position.Filename = name
s.IsIdentRune = isIdentRune s.IsIdentRune = isIdentRune
if file != nil {
linkCtxt.LineHist.Push(histLine, name)
}
return &Tokenizer{ return &Tokenizer{
s: &s, s: &s,
line: 1, base: src.NewFileBase(name, obj.AbsFile(obj.WorkingDir(), name, *flags.TrimPath)),
fileName: name, line: 1,
file: file, file: file,
} }
} }
@ -80,7 +81,15 @@ func (t *Tokenizer) Text() string {
} }
func (t *Tokenizer) File() string { func (t *Tokenizer) File() string {
return t.fileName return t.base.Filename()
}
func (t *Tokenizer) Base() *src.PosBase {
return t.base
}
func (t *Tokenizer) SetBase(base *src.PosBase) {
t.base = base
} }
func (t *Tokenizer) Line() int { func (t *Tokenizer) Line() int {
@ -91,11 +100,6 @@ func (t *Tokenizer) Col() int {
return t.s.Pos().Column return t.s.Pos().Column
} }
func (t *Tokenizer) SetPos(line int, file string) {
t.line = line
t.fileName = file
}
func (t *Tokenizer) Next() ScanToken { func (t *Tokenizer) Next() ScanToken {
s := t.s s := t.s
for { for {
@ -105,15 +109,11 @@ func (t *Tokenizer) Next() ScanToken {
} }
length := strings.Count(s.TokenText(), "\n") length := strings.Count(s.TokenText(), "\n")
t.line += length t.line += length
histLine += length
// TODO: If we ever have //go: comments in assembly, will need to keep them here. // TODO: If we ever have //go: comments in assembly, will need to keep them here.
// For now, just discard all comments. // For now, just discard all comments.
} }
switch t.tok { switch t.tok {
case '\n': case '\n':
if t.file != nil {
histLine++
}
t.line++ t.line++
case '-': case '-':
if s.Peek() == '>' { if s.Peek() == '>' {
@ -146,7 +146,5 @@ func (t *Tokenizer) Next() ScanToken {
func (t *Tokenizer) Close() { func (t *Tokenizer) Close() {
if t.file != nil { if t.file != nil {
t.file.Close() t.file.Close()
// It's an open file, so pop the line history.
linkCtxt.LineHist.Pop(histLine)
} }
} }

View file

@ -37,7 +37,6 @@ func main() {
if *flags.PrintOut { if *flags.PrintOut {
ctxt.Debugasm = 1 ctxt.Debugasm = 1
} }
ctxt.LineHist.TrimPathPrefix = *flags.TrimPath
ctxt.Flag_dynlink = *flags.Dynlink ctxt.Flag_dynlink = *flags.Dynlink
ctxt.Flag_shared = *flags.Shared || *flags.Dynlink ctxt.Flag_shared = *flags.Shared || *flags.Dynlink
ctxt.Bso = bufio.NewWriter(os.Stdout) ctxt.Bso = bufio.NewWriter(os.Stdout)
@ -57,7 +56,7 @@ func main() {
var ok, diag bool var ok, diag bool
var failedFile string var failedFile string
for _, f := range flag.Args() { for _, f := range flag.Args() {
lexer := lex.NewLexer(f, ctxt) lexer := lex.NewLexer(f)
parser := asm.NewParser(ctxt, architecture, lexer) parser := asm.NewParser(ctxt, architecture, lexer)
ctxt.DiagFunc = func(format string, args ...interface{}) { ctxt.DiagFunc = func(format string, args ...interface{}) {
diag = true diag = true

View file

@ -654,6 +654,7 @@ var knownFormats = map[string]string{
"cmd/compile/internal/syntax.token %q": "", "cmd/compile/internal/syntax.token %q": "",
"cmd/compile/internal/syntax.token %s": "", "cmd/compile/internal/syntax.token %s": "",
"cmd/internal/obj.As %v": "", "cmd/internal/obj.As %v": "",
"cmd/internal/src.Pos %s": "",
"error %v": "", "error %v": "",
"float64 %.2f": "", "float64 %.2f": "",
"float64 %.3f": "", "float64 %.3f": "",
@ -663,7 +664,6 @@ var knownFormats = map[string]string{
"int %-12d": "", "int %-12d": "",
"int %-6d": "", "int %-6d": "",
"int %-8o": "", "int %-8o": "",
"int %5d": "",
"int %6d": "", "int %6d": "",
"int %c": "", "int %c": "",
"int %d": "", "int %d": "",
@ -699,6 +699,7 @@ var knownFormats = map[string]string{
"time.Duration %d": "", "time.Duration %d": "",
"time.Duration %v": "", "time.Duration %v": "",
"uint %04x": "", "uint %04x": "",
"uint %5d": "",
"uint %d": "", "uint %d": "",
"uint16 %d": "", "uint16 %d": "",
"uint16 %v": "", "uint16 %v": "",

View file

@ -147,7 +147,7 @@ func duff(size int64) (int64, int64) {
} }
func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) { func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
s.SetLineno(v.Line) s.SetPos(v.Pos)
switch v.Op { switch v.Op {
case ssa.OpAMD64ADDQ, ssa.OpAMD64ADDL: case ssa.OpAMD64ADDQ, ssa.OpAMD64ADDL:
r := v.Reg() r := v.Reg()
@ -875,8 +875,8 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p.To.Type = obj.TYPE_MEM p.To.Type = obj.TYPE_MEM
p.To.Reg = v.Args[0].Reg() p.To.Reg = v.Args[0].Reg()
gc.AddAux(&p.To, v) gc.AddAux(&p.To, v)
if gc.Debug_checknil != 0 && v.Line > 1 { // v.Line==1 in generated wrappers if gc.Debug_checknil != 0 && v.Pos.Line() > 1 { // v.Pos.Line()==1 in generated wrappers
gc.Warnl(v.Line, "generated nil check") gc.Warnl(v.Pos, "generated nil check")
} }
case ssa.OpAMD64MOVLatomicload, ssa.OpAMD64MOVQatomicload: case ssa.OpAMD64MOVLatomicload, ssa.OpAMD64MOVQatomicload:
p := gc.Prog(v.Op.Asm()) p := gc.Prog(v.Op.Asm())
@ -962,7 +962,7 @@ var nefJumps = [2][2]gc.FloatingEQNEJump{
} }
func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) { func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
s.SetLineno(b.Line) s.SetPos(b.Pos)
switch b.Kind { switch b.Kind {
case ssa.BlockPlain: case ssa.BlockPlain:

View file

@ -118,7 +118,7 @@ func genregshift(as obj.As, r0, r1, r2, r int16, typ int64) *obj.Prog {
} }
func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) { func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
s.SetLineno(v.Line) s.SetPos(v.Pos)
switch v.Op { switch v.Op {
case ssa.OpInitMem: case ssa.OpInitMem:
// memory arg needs no code // memory arg needs no code
@ -705,8 +705,8 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
gc.AddAux(&p.From, v) gc.AddAux(&p.From, v)
p.To.Type = obj.TYPE_REG p.To.Type = obj.TYPE_REG
p.To.Reg = arm.REGTMP p.To.Reg = arm.REGTMP
if gc.Debug_checknil != 0 && v.Line > 1 { // v.Line==1 in generated wrappers if gc.Debug_checknil != 0 && v.Pos.Line() > 1 { // v.Pos.Line()==1 in generated wrappers
gc.Warnl(v.Line, "generated nil check") gc.Warnl(v.Pos, "generated nil check")
} }
case ssa.OpARMLoweredZero: case ssa.OpARMLoweredZero:
// MOVW.P Rarg2, 4(R1) // MOVW.P Rarg2, 4(R1)
@ -861,7 +861,7 @@ var blockJump = map[ssa.BlockKind]struct {
} }
func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) { func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
s.SetLineno(b.Line) s.SetPos(b.Pos)
switch b.Kind { switch b.Kind {
case ssa.BlockPlain: case ssa.BlockPlain:

View file

@ -92,7 +92,7 @@ func genshift(as obj.As, r0, r1, r int16, typ int64, s int64) *obj.Prog {
} }
func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) { func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
s.SetLineno(v.Line) s.SetPos(v.Pos)
switch v.Op { switch v.Op {
case ssa.OpInitMem: case ssa.OpInitMem:
// memory arg needs no code // memory arg needs no code
@ -690,8 +690,8 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
gc.AddAux(&p.From, v) gc.AddAux(&p.From, v)
p.To.Type = obj.TYPE_REG p.To.Type = obj.TYPE_REG
p.To.Reg = arm64.REGTMP p.To.Reg = arm64.REGTMP
if gc.Debug_checknil != 0 && v.Line > 1 { // v.Line==1 in generated wrappers if gc.Debug_checknil != 0 && v.Pos.Line() > 1 { // v.Line==1 in generated wrappers
gc.Warnl(v.Line, "generated nil check") gc.Warnl(v.Pos, "generated nil check")
} }
case ssa.OpVarDef: case ssa.OpVarDef:
gc.Gvardef(v.Aux.(*gc.Node)) gc.Gvardef(v.Aux.(*gc.Node))
@ -768,7 +768,7 @@ var blockJump = map[ssa.BlockKind]struct {
} }
func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) { func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
s.SetLineno(b.Line) s.SetPos(b.Pos)
switch b.Kind { switch b.Kind {
case ssa.BlockPlain: case ssa.BlockPlain:

View file

@ -186,7 +186,7 @@ func genhash(sym *Sym, t *Type) {
fmt.Printf("genhash %v %v\n", sym, t) fmt.Printf("genhash %v %v\n", sym, t)
} }
lineno = 1 // less confusing than end of input lineno = MakePos(nil, 1, 0) // less confusing than end of input
dclcontext = PEXTERN dclcontext = PEXTERN
markdcl() markdcl()
@ -364,7 +364,7 @@ func geneq(sym *Sym, t *Type) {
fmt.Printf("geneq %v %v\n", sym, t) fmt.Printf("geneq %v %v\n", sym, t)
} }
lineno = 1 // less confusing than end of input lineno = MakePos(nil, 1, 0) // less confusing than end of input
dclcontext = PEXTERN dclcontext = PEXTERN
markdcl() markdcl()

View file

@ -126,7 +126,7 @@ func dowidth(t *Type) {
if t.Width == -2 { if t.Width == -2 {
if !t.Broke { if !t.Broke {
t.Broke = true t.Broke = true
yyerrorl(t.Lineno, "invalid recursive type %v", t) yyerrorl(t.Pos, "invalid recursive type %v", t)
} }
t.Width = 0 t.Width = 0
@ -143,7 +143,7 @@ func dowidth(t *Type) {
defercalc++ defercalc++
lno := lineno lno := lineno
lineno = t.Lineno lineno = t.Pos
t.Width = -2 t.Width = -2
t.Align = 0 t.Align = 0

View file

@ -286,6 +286,6 @@ var issue16214src = `
package main package main
func Mod32(x uint32) uint32 { func Mod32(x uint32) uint32 {
return x % 3 // frontend rewrites it as HMUL with 2863311531, the LITERAL node has Lineno 0 return x % 3 // frontend rewrites it as HMUL with 2863311531, the LITERAL node has unknown Pos
} }
` `

View file

@ -574,7 +574,9 @@ func (p *exporter) pos(n *Node) {
func fileLine(n *Node) (file string, line int) { func fileLine(n *Node) (file string, line int) {
if n != nil { if n != nil {
file, line = Ctxt.LineHist.AbsFileLine(int(n.Lineno)) pos := Ctxt.PosTable.Pos(n.Pos)
file = pos.AbsFilename()
line = int(pos.Line())
} }
return return
} }
@ -784,7 +786,7 @@ func (p *exporter) typ(t *Type) {
// for the issue. // for the issue.
if p.nesting > 100 { if p.nesting > 100 {
p.int(0) // 0 methods to indicate empty interface p.int(0) // 0 methods to indicate empty interface
yyerrorl(t.Lineno, "cannot export unnamed recursive interface") yyerrorl(t.Pos, "cannot export unnamed recursive interface")
break break
} }

View file

@ -247,7 +247,7 @@ func makeclosure(func_ *Node) *Node {
// after capturing (effectively constant). // after capturing (effectively constant).
func capturevars(xfunc *Node) { func capturevars(xfunc *Node) {
lno := lineno lno := lineno
lineno = xfunc.Lineno lineno = xfunc.Pos
func_ := xfunc.Func.Closure func_ := xfunc.Func.Closure
func_.Func.Enter.Set(nil) func_.Func.Enter.Set(nil)
@ -288,7 +288,7 @@ func capturevars(xfunc *Node) {
if v.Name.Byval { if v.Name.Byval {
how = "value" how = "value"
} }
Warnl(v.Lineno, "%v capturing by %s: %v (addr=%v assign=%v width=%d)", name, how, v.Sym, outermost.Addrtaken, outermost.Assigned, int32(v.Type.Width)) Warnl(v.Pos, "%v capturing by %s: %v (addr=%v assign=%v width=%d)", name, how, v.Sym, outermost.Addrtaken, outermost.Assigned, int32(v.Type.Width))
} }
outer = typecheck(outer, Erv) outer = typecheck(outer, Erv)
@ -302,7 +302,7 @@ func capturevars(xfunc *Node) {
// It transform closure bodies to properly reference captured variables. // It transform closure bodies to properly reference captured variables.
func transformclosure(xfunc *Node) { func transformclosure(xfunc *Node) {
lno := lineno lno := lineno
lineno = xfunc.Lineno lineno = xfunc.Pos
func_ := xfunc.Func.Closure func_ := xfunc.Func.Closure
if func_.Func.Top&Ecall != 0 { if func_.Func.Top&Ecall != 0 {
@ -441,13 +441,13 @@ func hasemptycvars(func_ *Node) bool {
func closuredebugruntimecheck(r *Node) { func closuredebugruntimecheck(r *Node) {
if Debug_closure > 0 { if Debug_closure > 0 {
if r.Esc == EscHeap { if r.Esc == EscHeap {
Warnl(r.Lineno, "heap closure, captured vars = %v", r.Func.Cvars) Warnl(r.Pos, "heap closure, captured vars = %v", r.Func.Cvars)
} else { } else {
Warnl(r.Lineno, "stack closure, captured vars = %v", r.Func.Cvars) Warnl(r.Pos, "stack closure, captured vars = %v", r.Func.Cvars)
} }
} }
if compiling_runtime && r.Esc == EscHeap { if compiling_runtime && r.Esc == EscHeap {
yyerrorl(r.Lineno, "heap-allocated closure, not allowed in runtime.") yyerrorl(r.Pos, "heap-allocated closure, not allowed in runtime.")
} }
} }
@ -455,7 +455,7 @@ func walkclosure(func_ *Node, init *Nodes) *Node {
// If no closure vars, don't bother wrapping. // If no closure vars, don't bother wrapping.
if hasemptycvars(func_) { if hasemptycvars(func_) {
if Debug_closure > 0 { if Debug_closure > 0 {
Warnl(func_.Lineno, "closure converted to global") Warnl(func_.Pos, "closure converted to global")
} }
return func_.Func.Closure.Func.Nname return func_.Func.Closure.Func.Nname
} else { } else {

View file

@ -4,7 +4,10 @@
package gc package gc
import "strings" import (
"cmd/internal/src"
"strings"
)
// Ctype describes the constant kind of an "ideal" (untyped) constant. // Ctype describes the constant kind of an "ideal" (untyped) constant.
type Ctype int8 type Ctype int8
@ -676,7 +679,7 @@ func evconst(n *Node) {
nr := n.Right nr := n.Right
var rv Val var rv Val
var lno int32 var lno src.XPos
var wr EType var wr EType
var v Val var v Val
var norig *Node var norig *Node

View file

@ -5,7 +5,9 @@
package gc package gc
import ( import (
"cmd/compile/internal/syntax"
"cmd/internal/obj" "cmd/internal/obj"
"cmd/internal/src"
"fmt" "fmt"
"sort" "sort"
"strings" "strings"
@ -113,7 +115,7 @@ func testdclstack() {
// redeclare emits a diagnostic about symbol s being redeclared somewhere. // redeclare emits a diagnostic about symbol s being redeclared somewhere.
func redeclare(s *Sym, where string) { func redeclare(s *Sym, where string) {
if s.Lastlineno == 0 { if !s.Lastlineno.IsKnown() {
var tmp string var tmp string
if s.Origpkg != nil { if s.Origpkg != nil {
tmp = s.Origpkg.Path tmp = s.Origpkg.Path
@ -162,7 +164,7 @@ func declare(n *Node, ctxt Class) {
// named OLITERAL needs Name; most OLITERALs don't. // named OLITERAL needs Name; most OLITERALs don't.
n.Name = new(Name) n.Name = new(Name)
} }
n.Lineno = lineno n.Pos = lineno
s := n.Sym s := n.Sym
// kludgy: typecheckok means we're past parsing. Eg genwrapper may declare out of package names later. // kludgy: typecheckok means we're past parsing. Eg genwrapper may declare out of package names later.
@ -287,14 +289,14 @@ func variter(vl []*Node, t *Node, el []*Node) []*Node {
// declare constants from grammar // declare constants from grammar
// new_name_list [[type] = expr_list] // new_name_list [[type] = expr_list]
func constiter(vl []*Node, t *Node, cl []*Node) []*Node { func constiter(vl []*Node, t *Node, cl []*Node) []*Node {
lno := int32(0) // 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 len(cl) == 0 {
if t != nil { if t != nil {
yyerror("const declaration cannot have type without expression") yyerror("const declaration cannot have type without expression")
} }
cl = lastconst cl = lastconst
t = lasttype t = lasttype
lno = vl[0].Lineno lno = vl[0].Pos
} else { } else {
lastconst = cl lastconst = cl
lasttype = t lasttype = t
@ -467,13 +469,13 @@ func colasdefn(left []*Node, defn *Node) {
continue continue
} }
if !colasname(n) { if !colasname(n) {
yyerrorl(defn.Lineno, "non-name %v on left side of :=", n) yyerrorl(defn.Pos, "non-name %v on left side of :=", n)
nerr++ nerr++
continue continue
} }
if n.Sym.Flags&SymUniq == 0 { if n.Sym.Flags&SymUniq == 0 {
yyerrorl(defn.Lineno, "%v repeated on left side of :=", n.Sym) yyerrorl(defn.Pos, "%v repeated on left side of :=", n.Sym)
n.Diag = true n.Diag = true
nerr++ nerr++
continue continue
@ -493,7 +495,7 @@ func colasdefn(left []*Node, defn *Node) {
} }
if nnew == 0 && nerr == 0 { if nnew == 0 && nerr == 0 {
yyerrorl(defn.Lineno, "no new variables on left side of :=") yyerrorl(defn.Pos, "no new variables on left side of :=")
} }
} }
@ -692,7 +694,7 @@ func typedcl0(s *Sym) *Node {
// node n, which was returned by typedcl0 // node n, which was returned by typedcl0
// is being declared to have uncompiled type t. // is being declared to have uncompiled type t.
// returns the ODCLTYPE node to use. // returns the ODCLTYPE node to use.
func typedcl1(n *Node, t *Node, pragma Pragma, alias bool) *Node { func typedcl1(n *Node, t *Node, pragma syntax.Pragma, alias bool) *Node {
if pragma != 0 && alias { if pragma != 0 && alias {
yyerror("cannot specify directive with type alias") yyerror("cannot specify directive with type alias")
pragma = 0 pragma = 0
@ -724,14 +726,14 @@ func checkembeddedtype(t *Type) {
if t.IsPtr() || t.IsUnsafePtr() { if t.IsPtr() || t.IsUnsafePtr() {
yyerror("embedded type cannot be a pointer") yyerror("embedded type cannot be a pointer")
} else if t.Etype == TFORW && t.ForwardType().Embedlineno == 0 { } else if t.Etype == TFORW && !t.ForwardType().Embedlineno.IsKnown() {
t.ForwardType().Embedlineno = lineno t.ForwardType().Embedlineno = lineno
} }
} }
func structfield(n *Node) *Field { func structfield(n *Node) *Field {
lno := lineno lno := lineno
lineno = n.Lineno lineno = n.Pos
if n.Op != ODCLFIELD { if n.Op != ODCLFIELD {
Fatalf("structfield: oops %v\n", n) Fatalf("structfield: oops %v\n", n)
@ -789,7 +791,7 @@ func checkdupfields(what string, ts ...*Type) {
continue continue
} }
if seen[f.Sym] { if seen[f.Sym] {
lineno = f.Nname.Lineno lineno = f.Nname.Pos
yyerror("duplicate %s %s", what, f.Sym.Name) yyerror("duplicate %s %s", what, f.Sym.Name)
continue continue
} }
@ -870,7 +872,7 @@ func tofunargsfield(fields []*Field, funarg Funarg) *Type {
func interfacefield(n *Node) *Field { func interfacefield(n *Node) *Field {
lno := lineno lno := lineno
lineno = n.Lineno lineno = n.Pos
if n.Op != ODCLFIELD { if n.Op != ODCLFIELD {
Fatalf("interfacefield: oops %v\n", n) Fatalf("interfacefield: oops %v\n", n)
@ -1352,7 +1354,7 @@ type nowritebarrierrecChecker struct {
type nowritebarrierrecCall struct { type nowritebarrierrecCall struct {
target *Node target *Node
depth int depth int
lineno int32 lineno src.XPos
} }
func checknowritebarrierrec() { func checknowritebarrierrec() {
@ -1362,8 +1364,8 @@ func checknowritebarrierrec() {
visitBottomUp(xtop, func(list []*Node, recursive bool) { visitBottomUp(xtop, func(list []*Node, recursive bool) {
// Functions with write barriers have depth 0. // Functions with write barriers have depth 0.
for _, n := range list { for _, n := range list {
if n.Func.WBLineno != 0 && n.Func.Pragma&Yeswritebarrierrec == 0 { if n.Func.WBPos.IsKnown() && n.Func.Pragma&Yeswritebarrierrec == 0 {
c.best[n] = nowritebarrierrecCall{target: nil, depth: 0, lineno: n.Func.WBLineno} c.best[n] = nowritebarrierrecCall{target: nil, depth: 0, lineno: n.Func.WBPos}
} }
} }
@ -1380,7 +1382,7 @@ func checknowritebarrierrec() {
// yeswritebarrierrec function. // yeswritebarrierrec function.
continue continue
} }
if n.Func.WBLineno == 0 { if !n.Func.WBPos.IsKnown() {
c.curfn = n c.curfn = n
c.visitcodelist(n.Nbody) c.visitcodelist(n.Nbody)
} }
@ -1408,7 +1410,7 @@ func checknowritebarrierrec() {
call = c.best[n] call = c.best[n]
} }
err = fmt.Sprintf("write barrier prohibited by caller; %v%s", n.Func.Nname, err) err = fmt.Sprintf("write barrier prohibited by caller; %v%s", n.Func.Nname, err)
yyerrorl(n.Func.WBLineno, err) yyerrorl(n.Func.WBPos, err)
} }
}) })
} }
@ -1454,6 +1456,6 @@ func (c *nowritebarrierrecChecker) visitcall(n *Node) {
if ok && fnbest.depth+1 >= best.depth { if ok && fnbest.depth+1 >= best.depth {
return return
} }
c.best[c.curfn] = nowritebarrierrecCall{target: defn, depth: fnbest.depth + 1, lineno: n.Lineno} c.best[c.curfn] = nowritebarrierrecCall{target: defn, depth: fnbest.depth + 1, lineno: n.Pos}
c.stable = false c.stable = false
} }

View file

@ -504,7 +504,7 @@ func escAnalyze(all []*Node, recursive bool) {
if n.Esc != escapes[i] { if n.Esc != escapes[i] {
done = false done = false
if Debug['m'] > 2 { if Debug['m'] > 2 {
Warnl(n.Lineno, "Reflooding %v %S", e.curfnSym(n), n) Warnl(n.Pos, "Reflooding %v %S", e.curfnSym(n), n)
} }
escapes[i] = n.Esc escapes[i] = n.Esc
e.escflood(n) e.escflood(n)
@ -525,7 +525,7 @@ func escAnalyze(all []*Node, recursive bool) {
if Debug['m'] != 0 { if Debug['m'] != 0 {
for _, n := range e.noesc { for _, n := range e.noesc {
if n.Esc == EscNone { if n.Esc == EscNone {
Warnl(n.Lineno, "%v %S does not escape", e.curfnSym(n), n) Warnl(n.Pos, "%v %S does not escape", e.curfnSym(n), n)
} }
} }
} }
@ -678,7 +678,7 @@ func (e *EscState) esc(n *Node, parent *Node) {
(n.Op == ONEW || n.Op == OPTRLIT) && n.Type.Elem().Width >= 1<<16 || (n.Op == ONEW || n.Op == OPTRLIT) && n.Type.Elem().Width >= 1<<16 ||
n.Op == OMAKESLICE && !isSmallMakeSlice(n)) { n.Op == OMAKESLICE && !isSmallMakeSlice(n)) {
if Debug['m'] > 2 { if Debug['m'] > 2 {
Warnl(n.Lineno, "%v is too large for stack", n) Warnl(n.Pos, "%v is too large for stack", n)
} }
n.Esc = EscHeap n.Esc = EscHeap
addrescapes(n) addrescapes(n)
@ -778,7 +778,7 @@ func (e *EscState) esc(n *Node, parent *Node) {
// b escapes as well. If we ignore such OSLICEARR, we will conclude // b escapes as well. If we ignore such OSLICEARR, we will conclude
// that b does not escape when b contents do. // that b does not escape when b contents do.
if Debug['m'] != 0 { if Debug['m'] != 0 {
Warnl(n.Lineno, "%v ignoring self-assignment to %S", e.curfnSym(n), n.Left) Warnl(n.Pos, "%v ignoring self-assignment to %S", e.curfnSym(n), n.Left)
} }
break break
@ -882,7 +882,7 @@ func (e *EscState) esc(n *Node, parent *Node) {
slice2 := n.List.Second() slice2 := n.List.Second()
e.escassignDereference(&e.theSink, slice2, e.stepAssignWhere(n, slice2, "appended slice...", n)) // lose track of assign of dereference e.escassignDereference(&e.theSink, slice2, e.stepAssignWhere(n, slice2, "appended slice...", n)) // lose track of assign of dereference
if Debug['m'] > 3 { if Debug['m'] > 3 {
Warnl(n.Lineno, "%v special treatment of append(slice1, slice2...) %S", e.curfnSym(n), n) Warnl(n.Pos, "%v special treatment of append(slice1, slice2...) %S", e.curfnSym(n), n)
} }
} }
e.escassignDereference(&e.theSink, n.List.First(), e.stepAssignWhere(n, n.List.First(), "appendee slice", n)) // The original elements are now leaked, too e.escassignDereference(&e.theSink, n.List.First(), e.stepAssignWhere(n, n.List.First(), "appendee slice", n)) // The original elements are now leaked, too
@ -952,7 +952,7 @@ func (e *EscState) esc(n *Node, parent *Node) {
a := v.Name.Defn a := v.Name.Defn
if !v.Name.Byval { if !v.Name.Byval {
a = nod(OADDR, a, nil) a = nod(OADDR, a, nil)
a.Lineno = v.Lineno a.Pos = v.Pos
e.nodeEscState(a).Loopdepth = e.loopdepth e.nodeEscState(a).Loopdepth = e.loopdepth
a = typecheck(a, Erv) a = typecheck(a, Erv)
} }
@ -1145,7 +1145,7 @@ func (e *EscState) escassign(dst, src *Node, step *EscStep) {
// OCLOSURE is lowered to OPTRLIT, // OCLOSURE is lowered to OPTRLIT,
// insert OADDR to account for the additional indirection. // insert OADDR to account for the additional indirection.
a := nod(OADDR, src, nil) a := nod(OADDR, src, nil)
a.Lineno = src.Lineno a.Pos = src.Pos
e.nodeEscState(a).Loopdepth = e.nodeEscState(src).Loopdepth e.nodeEscState(a).Loopdepth = e.nodeEscState(src).Loopdepth
a.Type = ptrto(src.Type) a.Type = ptrto(src.Type)
e.escflows(dst, a, e.stepAssign(nil, originalDst, src, dstwhy)) e.escflows(dst, a, e.stepAssign(nil, originalDst, src, dstwhy))
@ -1383,7 +1383,7 @@ func (e *EscState) escassignDereference(dst *Node, src *Node, step *EscStep) {
func (e *EscState) addDereference(n *Node) *Node { func (e *EscState) addDereference(n *Node) *Node {
ind := nod(OIND, n, nil) ind := nod(OIND, n, nil)
e.nodeEscState(ind).Loopdepth = e.nodeEscState(n).Loopdepth e.nodeEscState(ind).Loopdepth = e.nodeEscState(n).Loopdepth
ind.Lineno = n.Lineno ind.Pos = n.Pos
t := n.Type t := n.Type
if t.IsKind(Tptr) { if t.IsKind(Tptr) {
// This should model our own sloppy use of OIND to encode // This should model our own sloppy use of OIND to encode
@ -1441,7 +1441,7 @@ func (e *EscState) initEscRetval(call *Node, fntype *Type) {
ret.Name.Curfn = Curfn ret.Name.Curfn = Curfn
e.nodeEscState(ret).Loopdepth = e.loopdepth e.nodeEscState(ret).Loopdepth = e.loopdepth
ret.Used = true ret.Used = true
ret.Lineno = call.Lineno ret.Pos = call.Pos
cE.Retval.Append(ret) cE.Retval.Append(ret)
} }
} }
@ -1546,7 +1546,7 @@ func (e *EscState) esccall(call *Node, parent *Node) {
arg = nod(ODDDARG, nil, nil) arg = nod(ODDDARG, nil, nil)
arr := typArray(n.Type.Elem(), int64(len(args))) arr := typArray(n.Type.Elem(), int64(len(args)))
arg.Type = ptrto(arr) // make pointer so it will be tracked arg.Type = ptrto(arr) // make pointer so it will be tracked
arg.Lineno = call.Lineno arg.Pos = call.Pos
e.track(arg) e.track(arg)
call.Right = arg call.Right = arg
} }
@ -1607,7 +1607,7 @@ func (e *EscState) esccall(call *Node, parent *Node) {
if param.Isddd && !call.Isddd { if param.Isddd && !call.Isddd {
// Introduce ODDDARG node to represent ... allocation. // Introduce ODDDARG node to represent ... allocation.
arg = nod(ODDDARG, nil, nil) arg = nod(ODDDARG, nil, nil)
arg.Lineno = call.Lineno arg.Pos = call.Pos
arr := typArray(param.Type.Elem(), int64(len(args)-i)) arr := typArray(param.Type.Elem(), int64(len(args)-i))
arg.Type = ptrto(arr) // make pointer so it will be tracked arg.Type = ptrto(arr) // make pointer so it will be tracked
e.track(arg) e.track(arg)
@ -1757,7 +1757,7 @@ func (es *EscStep) describe(src *Node) {
if where == nil { if where == nil {
where = dst where = dst
} }
Warnl(src.Lineno, "\tfrom %v (%s) at %s", dst, step.why, where.Line()) Warnl(src.Pos, "\tfrom %v (%s) at %s", dst, step.why, where.Line())
} }
for step := step0; step != nil && step.busy; step = step.parent { for step := step0; step != nil && step.busy; step = step.parent {
step.busy = false step.busy = false
@ -1821,10 +1821,10 @@ func (e *EscState) escwalkBody(level Level, dst *Node, src *Node, step *EscStep,
// 4. return *in // 4. return *in
if Debug['m'] != 0 { if Debug['m'] != 0 {
if Debug['m'] <= 2 { if Debug['m'] <= 2 {
Warnl(src.Lineno, "leaking param: %S to result %v level=%v", src, dst.Sym, level.int()) Warnl(src.Pos, "leaking param: %S to result %v level=%v", src, dst.Sym, level.int())
step.describe(src) step.describe(src)
} else { } else {
Warnl(src.Lineno, "leaking param: %S to result %v level=%v", src, dst.Sym, level) Warnl(src.Pos, "leaking param: %S to result %v level=%v", src, dst.Sym, level)
} }
} }
if src.Esc&EscMask != EscReturn { if src.Esc&EscMask != EscReturn {
@ -1841,7 +1841,7 @@ func (e *EscState) escwalkBody(level Level, dst *Node, src *Node, step *EscStep,
level.int() > 0 { level.int() > 0 {
src.Esc = escMax(EscContentEscapes|src.Esc, EscNone) src.Esc = escMax(EscContentEscapes|src.Esc, EscNone)
if Debug['m'] != 0 { if Debug['m'] != 0 {
Warnl(src.Lineno, "mark escaped content: %S", src) Warnl(src.Pos, "mark escaped content: %S", src)
step.describe(src) step.describe(src)
} }
} }
@ -1858,11 +1858,11 @@ func (e *EscState) escwalkBody(level Level, dst *Node, src *Node, step *EscStep,
if Debug['m'] != 0 { if Debug['m'] != 0 {
if Debug['m'] <= 2 { if Debug['m'] <= 2 {
if osrcesc != src.Esc { if osrcesc != src.Esc {
Warnl(src.Lineno, "leaking param content: %S", src) Warnl(src.Pos, "leaking param content: %S", src)
step.describe(src) step.describe(src)
} }
} else { } else {
Warnl(src.Lineno, "leaking param content: %S level=%v dst.eld=%v src.eld=%v dst=%S", Warnl(src.Pos, "leaking param content: %S level=%v dst.eld=%v src.eld=%v dst=%S",
src, level, dstE.Loopdepth, modSrcLoopdepth, dst) src, level, dstE.Loopdepth, modSrcLoopdepth, dst)
} }
} }
@ -1870,10 +1870,10 @@ func (e *EscState) escwalkBody(level Level, dst *Node, src *Node, step *EscStep,
src.Esc = EscHeap src.Esc = EscHeap
if Debug['m'] != 0 { if Debug['m'] != 0 {
if Debug['m'] <= 2 { if Debug['m'] <= 2 {
Warnl(src.Lineno, "leaking param: %S", src) Warnl(src.Pos, "leaking param: %S", src)
step.describe(src) step.describe(src)
} else { } else {
Warnl(src.Lineno, "leaking param: %S level=%v dst.eld=%v src.eld=%v dst=%S", Warnl(src.Pos, "leaking param: %S level=%v dst.eld=%v src.eld=%v dst=%S",
src, level, dstE.Loopdepth, modSrcLoopdepth, dst) src, level, dstE.Loopdepth, modSrcLoopdepth, dst)
} }
} }
@ -1884,7 +1884,7 @@ func (e *EscState) escwalkBody(level Level, dst *Node, src *Node, step *EscStep,
// original variable. // original variable.
if src.isClosureVar() { if src.isClosureVar() {
if leaks && Debug['m'] != 0 { if leaks && Debug['m'] != 0 {
Warnl(src.Lineno, "leaking closure reference %S", src) Warnl(src.Pos, "leaking closure reference %S", src)
step.describe(src) step.describe(src)
} }
e.escwalk(level, dst, src.Name.Defn, e.stepWalk(dst, src.Name.Defn, "closure-var", step)) e.escwalk(level, dst, src.Name.Defn, e.stepWalk(dst, src.Name.Defn, "closure-var", step))
@ -1903,10 +1903,10 @@ func (e *EscState) escwalkBody(level Level, dst *Node, src *Node, step *EscStep,
p = p.Left // merely to satisfy error messages in tests p = p.Left // merely to satisfy error messages in tests
} }
if Debug['m'] > 2 { if Debug['m'] > 2 {
Warnl(src.Lineno, "%S escapes to heap, level=%v, dst=%v dst.eld=%v, src.eld=%v", Warnl(src.Pos, "%S escapes to heap, level=%v, dst=%v dst.eld=%v, src.eld=%v",
p, level, dst, dstE.Loopdepth, modSrcLoopdepth) p, level, dst, dstE.Loopdepth, modSrcLoopdepth)
} else { } else {
Warnl(src.Lineno, "%S escapes to heap", p) Warnl(src.Pos, "%S escapes to heap", p)
step.describe(src) step.describe(src)
} }
} }
@ -1924,7 +1924,7 @@ func (e *EscState) escwalkBody(level Level, dst *Node, src *Node, step *EscStep,
if leaks { if leaks {
src.Esc = EscHeap src.Esc = EscHeap
if Debug['m'] != 0 && osrcesc != src.Esc { if Debug['m'] != 0 && osrcesc != src.Esc {
Warnl(src.Lineno, "%S escapes to heap", src) Warnl(src.Pos, "%S escapes to heap", src)
step.describe(src) step.describe(src)
} }
extraloopdepth = modSrcLoopdepth extraloopdepth = modSrcLoopdepth
@ -1959,7 +1959,7 @@ func (e *EscState) escwalkBody(level Level, dst *Node, src *Node, step *EscStep,
if leaks { if leaks {
src.Esc = EscHeap src.Esc = EscHeap
if Debug['m'] != 0 && osrcesc != src.Esc { if Debug['m'] != 0 && osrcesc != src.Esc {
Warnl(src.Lineno, "%S escapes to heap", src) Warnl(src.Pos, "%S escapes to heap", src)
step.describe(src) step.describe(src)
} }
extraloopdepth = modSrcLoopdepth extraloopdepth = modSrcLoopdepth
@ -2064,7 +2064,7 @@ func (e *EscState) esctag(fn *Node) {
narg++ narg++
if f.Type.Etype == TUINTPTR { if f.Type.Etype == TUINTPTR {
if Debug['m'] != 0 { if Debug['m'] != 0 {
Warnl(fn.Lineno, "%v assuming %v is unsafe uintptr", funcSym(fn), name(f.Sym, narg)) Warnl(fn.Pos, "%v assuming %v is unsafe uintptr", funcSym(fn), name(f.Sym, narg))
} }
f.Note = unsafeUintptrTag f.Note = unsafeUintptrTag
} }
@ -2079,7 +2079,7 @@ func (e *EscState) esctag(fn *Node) {
narg++ narg++
if f.Type.Etype == TUINTPTR { if f.Type.Etype == TUINTPTR {
if Debug['m'] != 0 { if Debug['m'] != 0 {
Warnl(fn.Lineno, "%v marking %v as escaping uintptr", funcSym(fn), name(f.Sym, narg)) Warnl(fn.Pos, "%v marking %v as escaping uintptr", funcSym(fn), name(f.Sym, narg))
} }
f.Note = uintptrEscapesTag f.Note = uintptrEscapesTag
} }
@ -2087,7 +2087,7 @@ func (e *EscState) esctag(fn *Node) {
if f.Isddd && f.Type.Elem().Etype == TUINTPTR { if f.Isddd && f.Type.Elem().Etype == TUINTPTR {
// final argument is ...uintptr. // final argument is ...uintptr.
if Debug['m'] != 0 { if Debug['m'] != 0 {
Warnl(fn.Lineno, "%v marking %v as escaping ...uintptr", funcSym(fn), name(f.Sym, narg)) Warnl(fn.Pos, "%v marking %v as escaping ...uintptr", funcSym(fn), name(f.Sym, narg))
} }
f.Note = uintptrEscapesTag f.Note = uintptrEscapesTag
} }

View file

@ -283,8 +283,8 @@ func (n *Node) jconv(s fmt.State, flag FmtFlag) {
fmt.Fprintf(s, " g(%d)", n.Name.Vargen) fmt.Fprintf(s, " g(%d)", n.Name.Vargen)
} }
if n.Lineno != 0 { if n.Pos.IsKnown() {
fmt.Fprintf(s, " l(%d)", n.Lineno) fmt.Fprintf(s, " l(%d)", n.Pos.Line())
} }
if c == 0 && n.Xoffset != BADWIDTH { if c == 0 && n.Xoffset != BADWIDTH {

View file

@ -64,7 +64,7 @@ func addrescapes(n *Node) {
Curfn = Curfn.Func.Closure Curfn = Curfn.Func.Closure
} }
ln := lineno ln := lineno
lineno = Curfn.Lineno lineno = Curfn.Pos
moveToHeap(n) moveToHeap(n)
Curfn = oldfn Curfn = oldfn
lineno = ln lineno = ln

View file

@ -8,6 +8,7 @@ import (
"cmd/compile/internal/ssa" "cmd/compile/internal/ssa"
"cmd/internal/bio" "cmd/internal/bio"
"cmd/internal/obj" "cmd/internal/obj"
"cmd/internal/src"
) )
const ( const (
@ -42,10 +43,10 @@ type Sym struct {
// saved and restored by dcopy // saved and restored by dcopy
Pkg *Pkg Pkg *Pkg
Name string // object name Name string // object name
Def *Node // definition: ONAME OTYPE OPACK or OLITERAL Def *Node // definition: ONAME OTYPE OPACK or OLITERAL
Block int32 // blocknumber to catch redeclaration Block int32 // blocknumber to catch redeclaration
Lastlineno int32 // last declaration for diagnostic Lastlineno src.XPos // last declaration for diagnostic
Label *Node // corresponding label (ephemeral) Label *Node // corresponding label (ephemeral)
Origpkg *Pkg // original package for . import Origpkg *Pkg // original package for . import
@ -115,8 +116,6 @@ var sizeof_String int // runtime sizeof(String)
var pragcgobuf string var pragcgobuf string
var infile string
var outfile string var outfile string
var linkobj string var linkobj string

View file

@ -40,12 +40,12 @@ func Prog(as obj.As) *obj.Prog {
Clearp(pc) Clearp(pc)
p.Link = pc p.Link = pc
if lineno == 0 && Debug['K'] != 0 { if !lineno.IsKnown() && Debug['K'] != 0 {
Warn("prog: line 0") Warn("prog: unknown position (line 0)")
} }
p.As = as p.As = as
p.Lineno = lineno p.Pos = lineno
return p return p
} }
@ -60,7 +60,7 @@ func Appendpp(p *obj.Prog, as obj.As, ftype obj.AddrType, freg int16, foffset in
q := Ctxt.NewProg() q := Ctxt.NewProg()
Clearp(q) Clearp(q)
q.As = as q.As = as
q.Lineno = p.Lineno q.Pos = p.Pos
q.From.Type = ftype q.From.Type = ftype
q.From.Reg = freg q.From.Reg = freg
q.From.Offset = foffset q.From.Offset = foffset

View file

@ -75,6 +75,9 @@ func anyinit(n []*Node) bool {
} }
func fninit(n []*Node) { func fninit(n []*Node) {
// This code is using the last value of lineno for position information
// (see comment in noder.go, noder.file method, for details).
nf := initfix(n) nf := initfix(n)
if !anyinit(nf) { if !anyinit(nf) {
return return

View file

@ -27,7 +27,10 @@
package gc package gc
import "fmt" import (
"cmd/internal/src"
"fmt"
)
// Get the function's package. For ordinary functions it's on the ->sym, but for imported methods // Get the function's package. For ordinary functions it's on the ->sym, but for imported methods
// the ->sym can be re-used in the local package, so peel it off the receiver's type. // the ->sym can be re-used in the local package, so peel it off the receiver's type.
@ -837,7 +840,7 @@ func mkinlcall1(n *Node, fn *Node, isddd bool) *Node {
args := as.Rlist args := as.Rlist
as.Rlist.Set(nil) as.Rlist.Set(nil)
setlno(call, n.Lineno) setlno(call, n.Pos)
as.Rlist.Set(args.Slice()) as.Rlist.Set(args.Slice())
@ -1014,20 +1017,20 @@ func (subst *inlsubst) node(n *Node) *Node {
} }
// Plaster over linenumbers // Plaster over linenumbers
func setlnolist(ll Nodes, lno int32) { func setlnolist(ll Nodes, lno src.XPos) {
for _, n := range ll.Slice() { for _, n := range ll.Slice() {
setlno(n, lno) setlno(n, lno)
} }
} }
func setlno(n *Node, lno int32) { func setlno(n *Node, lno src.XPos) {
if n == nil { if n == nil {
return return
} }
// don't clobber names, unless they're freshly synthesized // don't clobber names, unless they're freshly synthesized
if n.Op != ONAME || n.Lineno == 0 { if n.Op != ONAME || !n.Pos.IsKnown() {
n.Lineno = lno n.Pos = lno
} }
setlno(n.Left, lno) setlno(n.Left, lno)

View file

@ -7,16 +7,18 @@ package gc
import ( import (
"cmd/compile/internal/syntax" "cmd/compile/internal/syntax"
"cmd/internal/obj" "cmd/internal/obj"
"cmd/internal/src"
"fmt" "fmt"
"strings" "strings"
) )
// lexlineno is the line number _after_ the most recently read rune. // lineno is the source position at the start of the most recently lexed token.
// In particular, it's advanced (or rewound) as newlines are read (or unread). // TODO(gri) rename and eventually remove
var lexlineno int32 var lineno src.XPos
// lineno is the line number at the start of the most recently lexed token. func MakePos(base *src.PosBase, line, col uint) src.XPos {
var lineno int32 return Ctxt.PosTable.XPos(src.MakePos(base, line, col))
}
func isSpace(c rune) bool { func isSpace(c rune) bool {
return c == ' ' || c == '\t' || c == '\n' || c == '\r' return c == ' ' || c == '\t' || c == '\n' || c == '\r'
@ -38,17 +40,15 @@ func plan9quote(s string) string {
return s return s
} }
type Pragma syntax.Pragma
const ( const (
// Func pragmas. // Func pragmas.
Nointerface Pragma = 1 << iota Nointerface syntax.Pragma = 1 << iota
Noescape // func parameters don't escape Noescape // func parameters don't escape
Norace // func must not have race detector annotations Norace // func must not have race detector annotations
Nosplit // func should not execute on separate stack Nosplit // func should not execute on separate stack
Noinline // func should not be inlined Noinline // func should not be inlined
CgoUnsafeArgs // treat a pointer to one arg as a pointer to them all CgoUnsafeArgs // treat a pointer to one arg as a pointer to them all
UintptrEscapes // pointers converted to uintptr escape UintptrEscapes // pointers converted to uintptr escape
// Runtime-only func pragmas. // Runtime-only func pragmas.
// See ../../../../runtime/README.md for detailed descriptions. // See ../../../../runtime/README.md for detailed descriptions.
@ -61,7 +61,7 @@ const (
NotInHeap // values of this type must not be heap allocated NotInHeap // values of this type must not be heap allocated
) )
func pragmaValue(verb string) Pragma { func pragmaValue(verb string) syntax.Pragma {
switch verb { switch verb {
case "go:nointerface": case "go:nointerface":
if obj.Fieldtrack_enabled != 0 { if obj.Fieldtrack_enabled != 0 {
@ -76,24 +76,12 @@ func pragmaValue(verb string) Pragma {
case "go:noinline": case "go:noinline":
return Noinline return Noinline
case "go:systemstack": case "go:systemstack":
if !compiling_runtime {
yyerror("//go:systemstack only allowed in runtime")
}
return Systemstack return Systemstack
case "go:nowritebarrier": case "go:nowritebarrier":
if !compiling_runtime {
yyerror("//go:nowritebarrier only allowed in runtime")
}
return Nowritebarrier return Nowritebarrier
case "go:nowritebarrierrec": case "go:nowritebarrierrec":
if !compiling_runtime {
yyerror("//go:nowritebarrierrec only allowed in runtime")
}
return Nowritebarrierrec | Nowritebarrier // implies Nowritebarrier return Nowritebarrierrec | Nowritebarrier // implies Nowritebarrier
case "go:yeswritebarrierrec": case "go:yeswritebarrierrec":
if !compiling_runtime {
yyerror("//go:yeswritebarrierrec only allowed in runtime")
}
return Yeswritebarrierrec return Yeswritebarrierrec
case "go:cgo_unsafe_args": case "go:cgo_unsafe_args":
return CgoUnsafeArgs return CgoUnsafeArgs

View file

@ -11,6 +11,7 @@ import (
"bytes" "bytes"
"cmd/compile/internal/ssa" "cmd/compile/internal/ssa"
"cmd/internal/obj" "cmd/internal/obj"
"cmd/internal/src"
"cmd/internal/sys" "cmd/internal/sys"
"flag" "flag"
"fmt" "fmt"
@ -187,7 +188,7 @@ func Main() {
obj.Flagcount("r", "debug generated wrappers", &Debug['r']) obj.Flagcount("r", "debug generated wrappers", &Debug['r'])
flag.BoolVar(&flag_race, "race", false, "enable race detector") flag.BoolVar(&flag_race, "race", false, "enable race detector")
obj.Flagcount("s", "warn about composite literals that can be simplified", &Debug['s']) obj.Flagcount("s", "warn about composite literals that can be simplified", &Debug['s'])
flag.StringVar(&Ctxt.LineHist.TrimPathPrefix, "trimpath", "", "remove `prefix` from recorded source file paths") flag.StringVar(&pathPrefix, "trimpath", "", "remove `prefix` from recorded source file paths")
flag.BoolVar(&safemode, "u", false, "reject unsafe code") flag.BoolVar(&safemode, "u", false, "reject unsafe code")
obj.Flagcount("v", "increase debug verbosity", &Debug['v']) obj.Flagcount("v", "increase debug verbosity", &Debug['v'])
obj.Flagcount("w", "debug type checking", &Debug['w']) obj.Flagcount("w", "debug type checking", &Debug['w'])
@ -219,6 +220,26 @@ func Main() {
usage() usage()
} }
if outfile == "" {
p := flag.Arg(0)
if i := strings.LastIndex(p, "/"); i >= 0 {
p = p[i+1:]
}
if runtime.GOOS == "windows" {
if i := strings.LastIndex(p, `\`); i >= 0 {
p = p[i+1:]
}
}
if i := strings.LastIndex(p, "."); i >= 0 {
p = p[:i]
}
suffix := ".o"
if writearchive {
suffix = ".a"
}
outfile = p + suffix
}
startProfile() startProfile()
if flag_race { if flag_race {
@ -301,33 +322,15 @@ func Main() {
blockgen = 1 blockgen = 1
dclcontext = PEXTERN dclcontext = PEXTERN
nerrors = 0 nerrors = 0
lexlineno = 1
timings.Start("fe", "loadsys") timings.Start("fe", "loadsys")
loadsys() loadsys()
timings.Start("fe", "parse") timings.Start("fe", "parse")
lexlineno0 := lexlineno lines := parseFiles(flag.Args())
for _, infile = range flag.Args() {
linehistpush(infile)
block = 1
iota_ = -1000000
imported_unsafe = false
parseFile(infile)
if nsyntaxerrors != 0 {
errorexit()
}
// Instead of converting EOF into '\n' in getc and count it as an extra line
// for the line history to work, and which then has to be corrected elsewhere,
// just add a line here.
lexlineno++
linehistpop()
}
timings.Stop() timings.Stop()
timings.AddEvent(int64(lexlineno-lexlineno0), "lines") timings.AddEvent(int64(lines), "lines")
mkpackage(localpkg.Name) // final import not used checks
finishUniverse() finishUniverse()
typecheckok = true typecheckok = true
@ -792,7 +795,8 @@ func importfile(f *Val, indent []byte) {
defer impf.Close() defer impf.Close()
imp := bufio.NewReader(impf) imp := bufio.NewReader(impf)
if strings.HasSuffix(file, ".a") { const pkgSuffix = ".a"
if strings.HasSuffix(file, pkgSuffix) {
if !skiptopkgdef(imp) { if !skiptopkgdef(imp) {
yyerror("import %s: not a package file", file) yyerror("import %s: not a package file", file)
errorexit() errorexit()
@ -840,9 +844,9 @@ func importfile(f *Val, indent []byte) {
yyerror("cannot import unsafe package %q", importpkg.Path) yyerror("cannot import unsafe package %q", importpkg.Path)
} }
// assume files move (get installed) // assume files move (get installed) so don't record the full path
// so don't record the full path. // (e.g., for file "/Users/foo/go/pkg/darwin_amd64/math.a" record "math.a")
linehistpragma(file[len(file)-len(path_)-2:]) // acts as #pragma lib Ctxt.AddImport(file[len(file)-len(path_)-len(pkgSuffix):])
// In the importfile, if we find: // In the importfile, if we find:
// $$\n (textual format): not supported anymore // $$\n (textual format): not supported anymore
@ -885,7 +889,7 @@ func importfile(f *Val, indent []byte) {
} }
} }
func pkgnotused(lineno int32, 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 // If the package was imported with a name other than the final
// import path element, show it explicitly in the error message. // import path element, show it explicitly in the error message.
// Note that this handles both renamed imports and imports of // Note that this handles both renamed imports and imports of
@ -913,54 +917,37 @@ func mkpackage(pkgname string) {
if pkgname != localpkg.Name { if pkgname != localpkg.Name {
yyerror("package %s; expected %s", pkgname, localpkg.Name) yyerror("package %s; expected %s", pkgname, localpkg.Name)
} }
for _, s := range localpkg.Syms { }
if s.Def == nil { }
continue
} func clearImports() {
if s.Def.Op == OPACK { for _, s := range localpkg.Syms {
// throw away top-level package name leftover if s.Def == nil {
// from previous file. continue
// leave s->block set to cause redeclaration }
// errors if a conflicting top-level name is if s.Def.Op == OPACK {
// introduced by a different file. // throw away top-level package name leftover
if !s.Def.Used && nsyntaxerrors == 0 { // from previous file.
pkgnotused(s.Def.Lineno, s.Def.Name.Pkg.Path, s.Name) // leave s->block set to cause redeclaration
} // errors if a conflicting top-level name is
s.Def = nil // introduced by a different file.
continue if !s.Def.Used && nsyntaxerrors == 0 {
} pkgnotused(s.Def.Pos, s.Def.Name.Pkg.Path, s.Name)
}
if s.isAlias() { s.Def = nil
// throw away top-level name left over continue
// from previous import . "x" }
if s.Def.Name != nil && s.Def.Name.Pack != nil && !s.Def.Name.Pack.Used && nsyntaxerrors == 0 {
pkgnotused(s.Def.Name.Pack.Lineno, s.Def.Name.Pack.Name.Pkg.Path, "") if s.isAlias() {
s.Def.Name.Pack.Used = true // throw away top-level name left over
} // from previous import . "x"
if s.Def.Name != nil && s.Def.Name.Pack != nil && !s.Def.Name.Pack.Used && nsyntaxerrors == 0 {
s.Def = nil pkgnotused(s.Def.Name.Pack.Pos, s.Def.Name.Pack.Name.Pkg.Path, "")
continue s.Def.Name.Pack.Used = true
} }
}
} s.Def = nil
continue
if outfile == "" { }
p := infile
if i := strings.LastIndex(p, "/"); i >= 0 {
p = p[i+1:]
}
if runtime.GOOS == "windows" {
if i := strings.LastIndex(p, `\`); i >= 0 {
p = p[i+1:]
}
}
if i := strings.LastIndex(p, "."); i >= 0 {
p = p[:i]
}
suffix := ".o"
if writearchive {
suffix = ".a"
}
outfile = p + suffix
} }
} }

View file

@ -12,47 +12,109 @@ import (
"unicode/utf8" "unicode/utf8"
"cmd/compile/internal/syntax" "cmd/compile/internal/syntax"
"cmd/internal/obj"
"cmd/internal/src"
) )
func parseFile(filename string) { func parseFiles(filenames []string) uint {
src, err := os.Open(filename) var lines uint
if err != nil { var noders []*noder
fmt.Println(err)
errorexit() for _, filename := range filenames {
p := &noder{err: make(chan syntax.Error)}
noders = append(noders, p)
go func(filename string) {
defer close(p.err)
base := src.NewFileBase(filename, absFilename(filename))
f, err := os.Open(filename)
if err != nil {
p.error(syntax.Error{Pos: src.MakePos(base, 0, 0), Msg: err.Error()})
return
}
defer f.Close()
p.file, _ = syntax.Parse(base, f, p.error, p.pragma, 0) // errors are tracked via p.error
}(filename)
} }
defer src.Close()
p := noder{baseline: lexlineno} for _, p := range noders {
file, _ := syntax.Parse(src, p.error, p.pragma, 0) // errors are tracked via p.error for e := range p.err {
yyerrorpos(e.Pos, "%s", e.Msg)
p.file(file)
if !imported_unsafe {
for _, x := range p.linknames {
p.error(syntax.Error{Line: x, Msg: "//go:linkname only allowed in Go files that import \"unsafe\""})
} }
}
if nsyntaxerrors == 0 { p.node()
lines += p.file.Lines
p.file = nil // release memory
if nsyntaxerrors != 0 {
errorexit()
}
// Always run testdclstack here, even when debug_dclstack is not set, as a sanity measure. // Always run testdclstack here, even when debug_dclstack is not set, as a sanity measure.
testdclstack() testdclstack()
} }
return lines
} }
// noder transforms package syntax's AST into a Nod tree. func yyerrorpos(pos src.Pos, format string, args ...interface{}) {
yyerrorl(Ctxt.PosTable.XPos(pos), format, args...)
}
var pathPrefix string
func absFilename(name string) string {
return obj.AbsFile(Ctxt.Pathname, name, pathPrefix)
}
// noder transforms package syntax's AST into a Node tree.
type noder struct { type noder struct {
baseline int32 file *syntax.File
linknames []int // tracks //go:linkname lines linknames []linkname
pragcgobuf string
err chan syntax.Error
} }
func (p *noder) file(file *syntax.File) { // linkname records a //go:linkname directive.
p.lineno(file.PkgName) type linkname struct {
mkpackage(file.PkgName.Value) pos src.Pos
local string
remote string
}
xtop = append(xtop, p.decls(file.DeclList)...) func (p *noder) node() {
block = 1
iota_ = -1000000
imported_unsafe = false
lexlineno = p.baseline + int32(file.Lines) - 1 p.lineno(p.file.PkgName)
lineno = lexlineno mkpackage(p.file.PkgName.Value)
xtop = append(xtop, p.decls(p.file.DeclList)...)
for _, n := range p.linknames {
if imported_unsafe {
lookup(n.local).Linkname = n.remote
} else {
yyerrorpos(n.pos, "//go:linkname only allowed in Go files that import \"unsafe\"")
}
}
pragcgobuf += p.pragcgobuf
// For compatibility with old code only (comparisons w/ toolstash):
// The old line number tracking simply continued incrementing the
// virtual line number (lexlineno) and using it also for lineno.
// After processing the last function, the lineno was used for the
// line number information of the initialization code (fninit).
// It would be better to use an explicit "<autogenerated>" filename
// for fninit and set lineno to NoPos here.
// TODO(gri) fix this once we switched permanently to the new
// position information.
lineno = MakePos(p.file.Pos().Base(), uint(p.file.Lines), 0)
clearImports()
} }
func (p *noder) decls(decls []syntax.Decl) (l []*Node) { func (p *noder) decls(decls []syntax.Decl) (l []*Node) {
@ -137,18 +199,18 @@ func (p *noder) importDecl(imp *syntax.ImportDecl) {
return return
} }
if my.Name == "init" { if my.Name == "init" {
yyerrorl(pack.Lineno, "cannot import package as init - init must be a func") yyerrorl(pack.Pos, "cannot import package as init - init must be a func")
return return
} }
if my.Name == "_" { if my.Name == "_" {
return return
} }
if my.Def != nil { if my.Def != nil {
lineno = pack.Lineno lineno = pack.Pos
redeclare(my, "as imported package name") redeclare(my, "as imported package name")
} }
my.Def = pack my.Def = pack
my.Lastlineno = pack.Lineno my.Lastlineno = pack.Pos
my.Block = 1 // at top level my.Block = 1 // at top level
} }
@ -183,7 +245,7 @@ func (p *noder) typeDecl(decl *syntax.TypeDecl) *Node {
// decl.Type may be nil but in that case we got a syntax error during parsing // decl.Type may be nil but in that case we got a syntax error during parsing
typ := p.typeExprOrNil(decl.Type) typ := p.typeExprOrNil(decl.Type)
return typedcl1(name, typ, Pragma(decl.Pragma), decl.Alias) return typedcl1(name, typ, syntax.Pragma(decl.Pragma), decl.Alias)
} }
func (p *noder) declNames(names []*syntax.Name) []*Node { func (p *noder) declNames(names []*syntax.Name) []*Node {
@ -213,7 +275,7 @@ func (p *noder) funcDecl(fun *syntax.FuncDecl) *Node {
} }
} }
pragma := Pragma(fun.Pragma) pragma := fun.Pragma
f.Nbody.Set(body) f.Nbody.Set(body)
f.Noescape = pragma&Noescape != 0 f.Noescape = pragma&Noescape != 0
@ -221,7 +283,7 @@ func (p *noder) funcDecl(fun *syntax.FuncDecl) *Node {
yyerror("can only use //go:noescape with external func implementations") yyerror("can only use //go:noescape with external func implementations")
} }
f.Func.Pragma = pragma f.Func.Pragma = pragma
lineno = p.baseline + int32(fun.EndLine) - 1 lineno = MakePos(fun.Pos().Base(), fun.EndLine, 0)
f.Func.Endlineno = lineno f.Func.Endlineno = lineno
funcbody(f) funcbody(f)
@ -347,14 +409,14 @@ func (p *noder) expr(expr syntax.Expr) *Node {
l[i] = p.wrapname(expr.ElemList[i], e) l[i] = p.wrapname(expr.ElemList[i], e)
} }
n.List.Set(l) n.List.Set(l)
lineno = p.baseline + int32(expr.EndLine) - 1 lineno = MakePos(expr.Pos().Base(), expr.EndLine, 0)
return n return n
case *syntax.KeyValueExpr: case *syntax.KeyValueExpr:
return p.nod(expr, OKEY, p.expr(expr.Key), p.wrapname(expr.Value, p.expr(expr.Value))) return p.nod(expr, OKEY, p.expr(expr.Key), p.wrapname(expr.Value, p.expr(expr.Value)))
case *syntax.FuncLit: case *syntax.FuncLit:
closurehdr(p.typeExpr(expr.Type)) closurehdr(p.typeExpr(expr.Type))
body := p.stmts(expr.Body) body := p.stmts(expr.Body)
lineno = p.baseline + int32(expr.EndLine) - 1 lineno = MakePos(expr.Pos().Base(), expr.EndLine, 0)
return p.setlineno(expr, closurebody(body)) return p.setlineno(expr, closurebody(body))
case *syntax.ParenExpr: case *syntax.ParenExpr:
return p.nod(expr, OPAREN, p.expr(expr.X), nil) return p.nod(expr, OPAREN, p.expr(expr.X), nil)
@ -982,13 +1044,13 @@ func (p *noder) nod(orig syntax.Node, op Op, left, right *Node) *Node {
return p.setlineno(orig, nod(op, left, right)) return p.setlineno(orig, nod(op, left, right))
} }
func (p *noder) setlineno(src syntax.Node, dst *Node) *Node { func (p *noder) setlineno(src_ syntax.Node, dst *Node) *Node {
l := int32(src.Line()) pos := src_.Pos()
if l == 0 { if !pos.IsKnown() {
// TODO(mdempsky): Shouldn't happen. Fix package syntax. // TODO(mdempsky): Shouldn't happen. Fix package syntax.
return dst return dst
} }
dst.Lineno = p.baseline + l - 1 dst.Pos = Ctxt.PosTable.XPos(pos)
return dst return dst
} }
@ -996,72 +1058,47 @@ func (p *noder) lineno(n syntax.Node) {
if n == nil { if n == nil {
return return
} }
l := int32(n.Line()) pos := n.Pos()
if l == 0 { if !pos.IsKnown() {
// TODO(mdempsky): Shouldn't happen. Fix package syntax. // TODO(mdempsky): Shouldn't happen. Fix package syntax.
return return
} }
lineno = p.baseline + l - 1 lineno = Ctxt.PosTable.XPos(pos)
} }
func (p *noder) error(err error) { func (p *noder) error(err error) {
line := p.baseline p.err <- err.(syntax.Error)
var msg string
if err, ok := err.(syntax.Error); ok {
line += int32(err.Line) - 1
msg = err.Msg
} else {
msg = err.Error()
}
yyerrorl(line, "%s", msg)
} }
func (p *noder) pragma(pos, line int, text string) syntax.Pragma { func (p *noder) pragma(pos src.Pos, text string) syntax.Pragma {
switch { switch {
case strings.HasPrefix(text, "line "): case strings.HasPrefix(text, "line "):
// Want to use LastIndexByte below but it's not defined in Go1.4 and bootstrap fails. // line directives are handled by syntax package
i := strings.LastIndex(text, ":") // look from right (Windows filenames may contain ':') panic("unreachable")
if i < 0 {
break
}
n, err := strconv.Atoi(text[i+1:])
if err != nil {
// TODO: make this an error instead? it is almost certainly a bug.
break
}
if n > 1e8 {
p.error(syntax.Error{Pos: pos, Line: line, Msg: "line number out of range"})
errorexit()
}
if n <= 0 {
break
}
lexlineno = p.baseline + int32(line)
linehistupdate(text[5:i], n)
case strings.HasPrefix(text, "go:linkname "): case strings.HasPrefix(text, "go:linkname "):
// Record line number so we can emit an error later if
// the file doesn't import package unsafe.
p.linknames = append(p.linknames, line)
f := strings.Fields(text) f := strings.Fields(text)
if len(f) != 3 { if len(f) != 3 {
p.error(syntax.Error{Pos: pos, Line: line, Msg: "usage: //go:linkname localname linkname"}) p.error(syntax.Error{Pos: pos, Msg: "usage: //go:linkname localname linkname"})
break break
} }
lookup(f[1]).Linkname = f[2] p.linknames = append(p.linknames, linkname{pos, f[1], f[2]})
case strings.HasPrefix(text, "go:cgo_"): case strings.HasPrefix(text, "go:cgo_"):
lineno = p.baseline + int32(line) - 1 // pragcgo may call yyerror // TODO(gri): lineno = p.baseline + int32(line) - 1 // pragcgo may call yyerror
pragcgobuf += pragcgo(text) p.pragcgobuf += pragcgo(text)
fallthrough // because of //go:cgo_unsafe_args fallthrough // because of //go:cgo_unsafe_args
default: default:
verb := text verb := text
if i := strings.Index(text, " "); i >= 0 { if i := strings.Index(text, " "); i >= 0 {
verb = verb[:i] verb = verb[:i]
} }
lineno = p.baseline + int32(line) - 1 // pragmaValue may call yyerror prag := pragmaValue(verb)
return syntax.Pragma(pragmaValue(verb)) const runtimePragmas = Systemstack | Nowritebarrier | Nowritebarrierrec | Yeswritebarrierrec
if !compiling_runtime && prag&runtimePragmas != 0 {
p.error(syntax.Error{Pos: pos, Msg: fmt.Sprintf("//go:%s only allowed in runtime", verb)})
}
return prag
} }
return 0 return 0

View file

@ -5,6 +5,7 @@
package gc package gc
import ( import (
"cmd/internal/src"
"fmt" "fmt"
) )
@ -510,7 +511,7 @@ func orderstmt(n *Node, order *Order) {
n.Left = orderexpr(n.Left, order, nil) n.Left = orderexpr(n.Left, order, nil)
n.Left = ordersafeexpr(n.Left, order) n.Left = ordersafeexpr(n.Left, order)
tmp1 := treecopy(n.Left, 0) tmp1 := treecopy(n.Left, src.NoXPos)
if tmp1.Op == OINDEXMAP { if tmp1.Op == OINDEXMAP {
tmp1.Etype = 0 // now an rvalue not an lvalue tmp1.Etype = 0 // now an rvalue not an lvalue
} }

View file

@ -7,6 +7,7 @@ package gc
import ( import (
"cmd/compile/internal/ssa" "cmd/compile/internal/ssa"
"cmd/internal/obj" "cmd/internal/obj"
"cmd/internal/src"
"cmd/internal/sys" "cmd/internal/sys"
"fmt" "fmt"
"sort" "sort"
@ -311,7 +312,7 @@ func compile(fn *Node) {
assertI2I2 = Sysfunc("assertI2I2") assertI2I2 = Sysfunc("assertI2I2")
} }
defer func(lno int32) { defer func(lno src.XPos) {
lineno = lno lineno = lno
}(setlineno(fn)) }(setlineno(fn))

View file

@ -6,6 +6,7 @@ package gc
import ( import (
"cmd/compile/internal/ssa" "cmd/compile/internal/ssa"
"cmd/internal/src"
"container/heap" "container/heap"
"fmt" "fmt"
) )
@ -233,7 +234,7 @@ func (s *phiState) insertVarPhis(n int, var_ *Node, defs []*ssa.Block, typ ssa.T
if !hasPhi.contains(c.ID) { if !hasPhi.contains(c.ID) {
// Add a phi to block c for variable n. // Add a phi to block c for variable n.
hasPhi.add(c.ID) hasPhi.add(c.ID)
v := c.NewValue0I(currentRoot.Line, ssa.OpPhi, typ, int64(n)) // TODO: line number right? v := c.NewValue0I(currentRoot.Pos, ssa.OpPhi, typ, int64(n)) // TODO: line number right?
// Note: we store the variable number in the phi's AuxInt field. Used temporarily by phi building. // Note: we store the variable number in the phi's AuxInt field. Used temporarily by phi building.
s.s.addNamedValue(var_, v) s.s.addNamedValue(var_, v)
for i := 0; i < len(c.Preds); i++ { for i := 0; i < len(c.Preds); i++ {
@ -466,7 +467,7 @@ loop:
// Find variable value on each predecessor. // Find variable value on each predecessor.
args = args[:0] args = args[:0]
for _, e := range b.Preds { for _, e := range b.Preds {
args = append(args, s.lookupVarOutgoing(e.Block(), v.Type, var_, v.Line)) args = append(args, s.lookupVarOutgoing(e.Block(), v.Type, var_, v.Pos))
} }
// Decide if we need a phi or not. We need a phi if there // Decide if we need a phi or not. We need a phi if there
@ -499,7 +500,7 @@ loop:
} }
// lookupVarOutgoing finds the variable's value at the end of block b. // 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 int32) *ssa.Value { func (s *simplePhiState) lookupVarOutgoing(b *ssa.Block, t ssa.Type, var_ *Node, line src.XPos) *ssa.Value {
for { for {
if v := s.defvars[b.ID][var_]; v != nil { if v := s.defvars[b.ID][var_]; v != nil {
return v return v

View file

@ -1014,7 +1014,7 @@ func unlinkedprog(as obj.As) *obj.Prog {
// covering an existing instruction. // covering an existing instruction.
func newpcdataprog(prog *obj.Prog, index int32) *obj.Prog { func newpcdataprog(prog *obj.Prog, index int32) *obj.Prog {
pcdata := unlinkedprog(obj.APCDATA) pcdata := unlinkedprog(obj.APCDATA)
pcdata.Lineno = prog.Lineno pcdata.Pos = prog.Pos
pcdata.From.Type = obj.TYPE_CONST pcdata.From.Type = obj.TYPE_CONST
pcdata.From.Offset = obj.PCDATA_StackMapIndex pcdata.From.Offset = obj.PCDATA_StackMapIndex
pcdata.To.Type = obj.TYPE_CONST pcdata.To.Type = obj.TYPE_CONST
@ -1253,7 +1253,7 @@ func livenessepilogue(lv *Liveness) {
if !n.Name.Needzero { if !n.Name.Needzero {
n.Name.Needzero = true n.Name.Needzero = true
if debuglive >= 1 { if debuglive >= 1 {
Warnl(p.Lineno, "%v: %L is ambiguously live", Curfn.Func.Nname, n) Warnl(p.Pos, "%v: %L is ambiguously live", Curfn.Func.Nname, n)
} }
} }
} }
@ -1344,7 +1344,7 @@ func livenessepilogue(lv *Liveness) {
} }
n := lv.vars[j] n := lv.vars[j]
if n.Class != PPARAM { if n.Class != PPARAM {
yyerrorl(p.Lineno, "internal error: %v %L recorded as live on entry, p.Pc=%v", Curfn.Func.Nname, n, p.Pc) yyerrorl(p.Pos, "internal error: %v %L recorded as live on entry, p.Pc=%v", Curfn.Func.Nname, n, p.Pc)
} }
} }
} }

View file

@ -5,6 +5,7 @@
package gc package gc
import ( import (
"cmd/internal/src"
"fmt" "fmt"
"strings" "strings"
) )
@ -495,7 +496,7 @@ func callinstr(np **Node, init *Nodes, wr int, skip int) bool {
*np = n *np = n
} }
n = treecopy(n, 0) n = treecopy(n, src.NoXPos)
makeaddable(n) makeaddable(n)
var f *Node var f *Node
if flag_msan { if flag_msan {

View file

@ -258,7 +258,7 @@ func staticinit(n *Node, out *[]*Node) bool {
Fatalf("staticinit") Fatalf("staticinit")
} }
lineno = n.Lineno lineno = n.Pos
l := n.Name.Defn.Left l := n.Name.Defn.Left
r := n.Name.Defn.Right r := n.Name.Defn.Right
return staticassign(l, r, out) return staticassign(l, r, out)
@ -469,7 +469,7 @@ func staticassign(l *Node, r *Node, out *[]*Node) bool {
case OCLOSURE: case OCLOSURE:
if hasemptycvars(r) { if hasemptycvars(r) {
if Debug_closure > 0 { if Debug_closure > 0 {
Warnl(r.Lineno, "closure converted to global") Warnl(r.Pos, "closure converted to global")
} }
// Closures with no captured variables are globals, // Closures with no captured variables are globals,
// so the assignment can be done at link time. // so the assignment can be done at link time.

View file

@ -22,14 +22,14 @@ func TestSizeof(t *testing.T) {
_32bit uintptr // size on 32bit platforms _32bit uintptr // size on 32bit platforms
_64bit uintptr // size on 64bit platforms _64bit uintptr // size on 64bit platforms
}{ }{
{Func{}, 92, 160}, {Func{}, 100, 168},
{Name{}, 44, 72}, {Name{}, 44, 72},
{Param{}, 24, 48}, {Param{}, 24, 48},
{Node{}, 92, 144}, {Node{}, 96, 152},
{Sym{}, 60, 112}, {Sym{}, 64, 120},
{Type{}, 60, 96}, {Type{}, 64, 104},
{MapType{}, 20, 40}, {MapType{}, 20, 40},
{ForwardType{}, 16, 32}, {ForwardType{}, 20, 32},
{FuncType{}, 28, 48}, {FuncType{}, 28, 48},
{StructType{}, 12, 24}, {StructType{}, 12, 24},
{InterType{}, 4, 8}, {InterType{}, 4, 8},

View file

@ -14,6 +14,7 @@ import (
"cmd/compile/internal/ssa" "cmd/compile/internal/ssa"
"cmd/internal/obj" "cmd/internal/obj"
"cmd/internal/src"
"cmd/internal/sys" "cmd/internal/sys"
) )
@ -43,7 +44,7 @@ func buildssa(fn *Node) *ssa.Func {
} }
var s state var s state
s.pushLine(fn.Lineno) s.pushLine(fn.Pos)
defer s.popLine() defer s.popLine()
if fn.Func.Pragma&CgoUnsafeArgs != 0 { if fn.Func.Pragma&CgoUnsafeArgs != 0 {
@ -53,8 +54,8 @@ func buildssa(fn *Node) *ssa.Func {
s.noWB = true s.noWB = true
} }
defer func() { defer func() {
if s.WBLineno != 0 { if s.WBPos.IsKnown() {
fn.Func.WBLineno = s.WBLineno fn.Func.WBPos = s.WBPos
} }
}() }()
// 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
@ -148,11 +149,11 @@ func buildssa(fn *Node) *ssa.Func {
// Check that we used all labels // Check that we used all labels
for name, lab := range s.labels { for name, lab := range s.labels {
if !lab.used() && !lab.reported && !lab.defNode.Used { if !lab.used() && !lab.reported && !lab.defNode.Used {
yyerrorl(lab.defNode.Lineno, "label %v defined and not used", name) yyerrorl(lab.defNode.Pos, "label %v defined and not used", name)
lab.reported = true lab.reported = true
} }
if lab.used() && !lab.defined() && !lab.reported { if lab.used() && !lab.defined() && !lab.reported {
yyerrorl(lab.useNode.Lineno, "label %v not defined", name) yyerrorl(lab.useNode.Pos, "label %v not defined", name)
lab.reported = true lab.reported = true
} }
} }
@ -231,7 +232,7 @@ type state struct {
sb *ssa.Value sb *ssa.Value
// line number stack. The current line number is top of stack // line number stack. The current line number is top of stack
line []int32 line []src.XPos
// list of panic calls by function name and line number. // list of panic calls by function name and line number.
// Used to deduplicate panic calls. // Used to deduplicate panic calls.
@ -245,12 +246,12 @@ type state struct {
cgoUnsafeArgs bool cgoUnsafeArgs bool
noWB bool noWB bool
WBLineno int32 // 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 { type funcLine struct {
f *Node f *Node
line int32 line src.XPos
} }
type ssaLabel struct { type ssaLabel struct {
@ -281,11 +282,13 @@ func (s *state) label(sym *Sym) *ssaLabel {
return lab return lab
} }
func (s *state) Logf(msg string, args ...interface{}) { s.config.Logf(msg, args...) } 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) Log() bool { return s.config.Log() }
func (s *state) Fatalf(msg string, args ...interface{}) { s.config.Fatalf(s.peekLine(), msg, args...) } func (s *state) Fatalf(msg string, args ...interface{}) { s.config.Fatalf(s.peekPos(), msg, args...) }
func (s *state) Warnl(line int32, msg string, args ...interface{}) { s.config.Warnl(line, msg, args...) } func (s *state) Warnl(pos src.XPos, msg string, args ...interface{}) {
func (s *state) Debug_checknil() bool { return s.config.Debug_checknil() } s.config.Warnl(pos, msg, args...)
}
func (s *state) Debug_checknil() bool { return s.config.Debug_checknil() }
var ( var (
// dummy node for the memory variable // dummy node for the memory variable
@ -326,18 +329,18 @@ 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() b.Pos = s.peekPos()
return b return b
} }
// pushLine pushes a line number on the line number stack. // pushLine pushes a line number on the line number stack.
func (s *state) pushLine(line int32) { func (s *state) pushLine(line src.XPos) {
if line == 0 { if !line.IsKnown() {
// the frontend may emit node with line number missing, // the frontend may emit node with line number missing,
// use the parent line number in this case. // use the parent line number in this case.
line = s.peekLine() line = s.peekPos()
if Debug['K'] != 0 { if Debug['K'] != 0 {
Warn("buildssa: line 0") Warn("buildssa: unknown position (line 0)")
} }
} }
s.line = append(s.line, line) s.line = append(s.line, line)
@ -348,130 +351,130 @@ func (s *state) popLine() {
s.line = s.line[:len(s.line)-1] s.line = s.line[:len(s.line)-1]
} }
// peekLine peek the top of the line number stack. // peekPos peeks the top of the line number stack.
func (s *state) peekLine() int32 { func (s *state) peekPos() src.XPos {
return s.line[len(s.line)-1] return s.line[len(s.line)-1]
} }
func (s *state) Error(msg string, args ...interface{}) { func (s *state) Error(msg string, args ...interface{}) {
yyerrorl(s.peekLine(), msg, args...) yyerrorl(s.peekPos(), msg, args...)
} }
// newValue0 adds a new value with no arguments to the current block. // newValue0 adds a new value with no arguments to the current block.
func (s *state) newValue0(op ssa.Op, t ssa.Type) *ssa.Value { func (s *state) newValue0(op ssa.Op, t ssa.Type) *ssa.Value {
return s.curBlock.NewValue0(s.peekLine(), op, t) return s.curBlock.NewValue0(s.peekPos(), op, t)
} }
// newValue0A adds a new value with no arguments and an aux value to the current block. // 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 { func (s *state) newValue0A(op ssa.Op, t ssa.Type, aux interface{}) *ssa.Value {
return s.curBlock.NewValue0A(s.peekLine(), op, t, aux) return s.curBlock.NewValue0A(s.peekPos(), op, t, aux)
} }
// newValue0I adds a new value with no arguments and an auxint value to the current block. // newValue0I adds a new value with no arguments and an auxint value to the current block.
func (s *state) newValue0I(op ssa.Op, t ssa.Type, auxint int64) *ssa.Value { func (s *state) newValue0I(op ssa.Op, t ssa.Type, auxint int64) *ssa.Value {
return s.curBlock.NewValue0I(s.peekLine(), op, t, auxint) return s.curBlock.NewValue0I(s.peekPos(), op, t, auxint)
} }
// 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, 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, arg) return s.curBlock.NewValue1(s.peekPos(), op, t, arg)
} }
// newValue1A adds a new value with one argument and an aux value to the current block. // 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 { 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) return s.curBlock.NewValue1A(s.peekPos(), op, t, aux, arg)
} }
// newValue1I adds a new value with one argument and an auxint value to the current block. // newValue1I adds a new value with one argument and an auxint value to the current block.
func (s *state) newValue1I(op ssa.Op, t ssa.Type, aux int64, arg *ssa.Value) *ssa.Value { func (s *state) newValue1I(op ssa.Op, t ssa.Type, aux int64, arg *ssa.Value) *ssa.Value {
return s.curBlock.NewValue1I(s.peekLine(), op, t, aux, arg) return s.curBlock.NewValue1I(s.peekPos(), 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, 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, arg0, arg1) return s.curBlock.NewValue2(s.peekPos(), op, t, arg0, arg1)
} }
// newValue2I adds a new value with two arguments and an auxint value to the current block. // newValue2I adds a new value with two arguments and an auxint value to the current block.
func (s *state) newValue2I(op ssa.Op, t ssa.Type, aux int64, arg0, arg1 *ssa.Value) *ssa.Value { func (s *state) newValue2I(op ssa.Op, t ssa.Type, aux int64, arg0, arg1 *ssa.Value) *ssa.Value {
return s.curBlock.NewValue2I(s.peekLine(), op, t, aux, arg0, arg1) return s.curBlock.NewValue2I(s.peekPos(), op, t, aux, 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, 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, arg0, arg1, arg2) return s.curBlock.NewValue3(s.peekPos(), op, t, arg0, arg1, arg2)
} }
// newValue3I adds a new value with three arguments and an auxint value to the current block. // newValue3I adds a new value with three arguments and an auxint value to the current block.
func (s *state) newValue3I(op ssa.Op, t ssa.Type, aux int64, arg0, arg1, arg2 *ssa.Value) *ssa.Value { func (s *state) newValue3I(op ssa.Op, t ssa.Type, aux int64, arg0, arg1, arg2 *ssa.Value) *ssa.Value {
return s.curBlock.NewValue3I(s.peekLine(), op, t, aux, arg0, arg1, arg2) return s.curBlock.NewValue3I(s.peekPos(), op, t, aux, arg0, arg1, arg2)
} }
// newValue4 adds a new value with four arguments to the current block. // newValue4 adds a new value with four arguments to the current block.
func (s *state) newValue4(op ssa.Op, t ssa.Type, arg0, arg1, arg2, arg3 *ssa.Value) *ssa.Value { func (s *state) newValue4(op ssa.Op, t ssa.Type, arg0, arg1, arg2, arg3 *ssa.Value) *ssa.Value {
return s.curBlock.NewValue4(s.peekLine(), op, t, arg0, arg1, arg2, arg3) return s.curBlock.NewValue4(s.peekPos(), op, t, arg0, arg1, arg2, arg3)
} }
// entryNewValue0 adds a new value with no arguments to the entry block. // entryNewValue0 adds a new value with no arguments to the entry block.
func (s *state) entryNewValue0(op ssa.Op, t ssa.Type) *ssa.Value { func (s *state) entryNewValue0(op ssa.Op, t ssa.Type) *ssa.Value {
return s.f.Entry.NewValue0(s.peekLine(), op, t) return s.f.Entry.NewValue0(s.peekPos(), op, t)
} }
// entryNewValue0A adds a new value with no arguments and an aux value to the entry block. // entryNewValue0A 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 { func (s *state) entryNewValue0A(op ssa.Op, t ssa.Type, aux interface{}) *ssa.Value {
return s.f.Entry.NewValue0A(s.peekLine(), op, t, aux) return s.f.Entry.NewValue0A(s.peekPos(), op, t, aux)
} }
// entryNewValue0I adds a new value with no arguments and an auxint value to the entry block. // entryNewValue0I adds a new value with no arguments and an auxint value to the entry block.
func (s *state) entryNewValue0I(op ssa.Op, t ssa.Type, auxint int64) *ssa.Value { func (s *state) entryNewValue0I(op ssa.Op, t ssa.Type, auxint int64) *ssa.Value {
return s.f.Entry.NewValue0I(s.peekLine(), op, t, auxint) return s.f.Entry.NewValue0I(s.peekPos(), op, t, auxint)
} }
// 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, 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, arg) return s.f.Entry.NewValue1(s.peekPos(), op, t, arg)
} }
// entryNewValue1 adds a new value with one argument and an auxint value to the entry block. // 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 { 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) return s.f.Entry.NewValue1I(s.peekPos(), op, t, auxint, arg)
} }
// entryNewValue1A adds a new value with one argument and an aux value to the entry block. // entryNewValue1A adds a new value with one argument and an aux value to the entry block.
func (s *state) entryNewValue1A(op ssa.Op, t ssa.Type, aux interface{}, arg *ssa.Value) *ssa.Value { func (s *state) entryNewValue1A(op ssa.Op, t ssa.Type, aux interface{}, arg *ssa.Value) *ssa.Value {
return s.f.Entry.NewValue1A(s.peekLine(), op, t, aux, arg) return s.f.Entry.NewValue1A(s.peekPos(), op, t, aux, 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, 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, arg0, arg1) return s.f.Entry.NewValue2(s.peekPos(), op, t, arg0, arg1)
} }
// const* routines add a new const value to the entry block. // const* routines add a new const value to the entry block.
func (s *state) constSlice(t ssa.Type) *ssa.Value { return s.f.ConstSlice(s.peekLine(), t) } func (s *state) constSlice(t ssa.Type) *ssa.Value { return s.f.ConstSlice(s.peekPos(), t) }
func (s *state) constInterface(t ssa.Type) *ssa.Value { return s.f.ConstInterface(s.peekLine(), t) } func (s *state) constInterface(t ssa.Type) *ssa.Value { return s.f.ConstInterface(s.peekPos(), t) }
func (s *state) constNil(t ssa.Type) *ssa.Value { return s.f.ConstNil(s.peekLine(), t) } func (s *state) constNil(t ssa.Type) *ssa.Value { return s.f.ConstNil(s.peekPos(), t) }
func (s *state) constEmptyString(t ssa.Type) *ssa.Value { return s.f.ConstEmptyString(s.peekLine(), t) } func (s *state) constEmptyString(t ssa.Type) *ssa.Value { return s.f.ConstEmptyString(s.peekPos(), t) }
func (s *state) constBool(c bool) *ssa.Value { func (s *state) constBool(c bool) *ssa.Value {
return s.f.ConstBool(s.peekLine(), Types[TBOOL], c) return s.f.ConstBool(s.peekPos(), Types[TBOOL], c)
} }
func (s *state) constInt8(t ssa.Type, c int8) *ssa.Value { func (s *state) constInt8(t ssa.Type, c int8) *ssa.Value {
return s.f.ConstInt8(s.peekLine(), t, c) return s.f.ConstInt8(s.peekPos(), t, c)
} }
func (s *state) constInt16(t ssa.Type, c int16) *ssa.Value { func (s *state) constInt16(t ssa.Type, c int16) *ssa.Value {
return s.f.ConstInt16(s.peekLine(), t, c) return s.f.ConstInt16(s.peekPos(), t, c)
} }
func (s *state) constInt32(t ssa.Type, c int32) *ssa.Value { func (s *state) constInt32(t ssa.Type, c int32) *ssa.Value {
return s.f.ConstInt32(s.peekLine(), t, c) return s.f.ConstInt32(s.peekPos(), t, c)
} }
func (s *state) constInt64(t ssa.Type, c int64) *ssa.Value { func (s *state) constInt64(t ssa.Type, c int64) *ssa.Value {
return s.f.ConstInt64(s.peekLine(), t, c) return s.f.ConstInt64(s.peekPos(), t, c)
} }
func (s *state) constFloat32(t ssa.Type, c float64) *ssa.Value { func (s *state) constFloat32(t ssa.Type, c float64) *ssa.Value {
return s.f.ConstFloat32(s.peekLine(), t, c) return s.f.ConstFloat32(s.peekPos(), t, c)
} }
func (s *state) constFloat64(t ssa.Type, c float64) *ssa.Value { func (s *state) constFloat64(t ssa.Type, c float64) *ssa.Value {
return s.f.ConstFloat64(s.peekLine(), t, c) return s.f.ConstFloat64(s.peekPos(), t, c)
} }
func (s *state) constInt(t ssa.Type, c int64) *ssa.Value { func (s *state) constInt(t ssa.Type, c int64) *ssa.Value {
if s.config.IntSize == 8 { if s.config.IntSize == 8 {
@ -492,7 +495,7 @@ func (s *state) stmtList(l Nodes) {
// stmt converts the statement n to SSA and adds it to s. // stmt 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) s.pushLine(n.Pos)
defer s.popLine() defer s.popLine()
// If s.curBlock is nil, then we're about to generate dead code. // If s.curBlock is nil, then we're about to generate dead code.
@ -558,8 +561,8 @@ func (s *state) stmt(n *Node) {
deref = true deref = true
res = res.Args[0] res = res.Args[0]
} }
s.assign(n.List.First(), res, needwritebarrier(n.List.First(), n.Rlist.First()), deref, n.Lineno, 0, false) s.assign(n.List.First(), res, needwritebarrier(n.List.First(), n.Rlist.First()), deref, n.Pos, 0, false)
s.assign(n.List.Second(), resok, false, false, n.Lineno, 0, false) s.assign(n.List.Second(), resok, false, false, n.Pos, 0, false)
return return
case OAS2FUNC: case OAS2FUNC:
@ -574,8 +577,8 @@ func (s *state) stmt(n *Node) {
// This is future-proofing against non-scalar 2-result intrinsics. // This is future-proofing against non-scalar 2-result intrinsics.
// Currently we only have scalar ones, which result in no write barrier. // Currently we only have scalar ones, which result in no write barrier.
fakeret := &Node{Op: OINDREGSP} fakeret := &Node{Op: OINDREGSP}
s.assign(n.List.First(), v1, needwritebarrier(n.List.First(), fakeret), false, n.Lineno, 0, false) s.assign(n.List.First(), v1, needwritebarrier(n.List.First(), fakeret), false, n.Pos, 0, false)
s.assign(n.List.Second(), v2, needwritebarrier(n.List.Second(), fakeret), false, n.Lineno, 0, false) s.assign(n.List.Second(), v2, needwritebarrier(n.List.Second(), fakeret), false, n.Pos, 0, false)
return return
case ODCL: case ODCL:
@ -605,7 +608,7 @@ func (s *state) stmt(n *Node) {
if !lab.defined() { if !lab.defined() {
lab.defNode = n lab.defNode = n
} else { } else {
s.Error("label %v already defined at %v", sym, linestr(lab.defNode.Lineno)) s.Error("label %v already defined at %v", sym, linestr(lab.defNode.Pos))
lab.reported = true lab.reported = true
} }
// The label might already have a target block via a goto. // The label might already have a target block via a goto.
@ -690,13 +693,13 @@ func (s *state) stmt(n *Node) {
if samesafeexpr(n.Left, rhs.List.First()) { if samesafeexpr(n.Left, rhs.List.First()) {
if !s.canSSA(n.Left) { if !s.canSSA(n.Left) {
if Debug_append > 0 { if Debug_append > 0 {
Warnl(n.Lineno, "append: len-only update") Warnl(n.Pos, "append: len-only update")
} }
s.append(rhs, true) s.append(rhs, true)
return return
} else { } else {
if Debug_append > 0 { // replicating old diagnostic message if Debug_append > 0 { // replicating old diagnostic message
Warnl(n.Lineno, "append: len-only update (in local slice)") Warnl(n.Pos, "append: len-only update (in local slice)")
} }
} }
} }
@ -759,7 +762,7 @@ func (s *state) stmt(n *Node) {
} }
} }
s.assign(n.Left, r, needwb, deref, n.Lineno, skip, isVolatile) s.assign(n.Left, r, needwb, deref, n.Pos, skip, isVolatile)
case OIF: case OIF:
bThen := s.f.NewBlock(ssa.BlockPlain) bThen := s.f.NewBlock(ssa.BlockPlain)
@ -1435,7 +1438,7 @@ func (s *state) expr(n *Node) *ssa.Value {
if !(n.Op == ONAME || n.Op == OLITERAL && n.Sym != nil) { if !(n.Op == ONAME || n.Op == OLITERAL && n.Sym != nil) {
// ONAMEs and named OLITERALs have the line number // ONAMEs and named OLITERALs have the line number
// of the decl, not the use. See issue 14742. // of the decl, not the use. See issue 14742.
s.pushLine(n.Lineno) s.pushLine(n.Pos)
defer s.popLine() defer s.popLine()
} }
@ -1969,7 +1972,7 @@ func (s *state) expr(n *Node) *ssa.Value {
return s.newValue2(ssa.OpLoad, n.Type, addr, s.mem()) return s.newValue2(ssa.OpLoad, n.Type, addr, s.mem())
case OIND: case OIND:
p := s.exprPtr(n.Left, false, n.Lineno) p := s.exprPtr(n.Left, false, n.Pos)
return s.newValue2(ssa.OpLoad, n.Type, p, s.mem()) return s.newValue2(ssa.OpLoad, n.Type, p, s.mem())
case ODOT: case ODOT:
@ -1982,7 +1985,7 @@ func (s *state) expr(n *Node) *ssa.Value {
return s.newValue2(ssa.OpLoad, n.Type, p, s.mem()) return s.newValue2(ssa.OpLoad, n.Type, p, s.mem())
case ODOTPTR: case ODOTPTR:
p := s.exprPtr(n.Left, false, n.Lineno) p := s.exprPtr(n.Left, false, n.Pos)
p = s.newValue1I(ssa.OpOffPtr, p.Type, n.Xoffset, p) p = s.newValue1I(ssa.OpOffPtr, p.Type, n.Xoffset, p)
return s.newValue2(ssa.OpLoad, n.Type, p, s.mem()) return s.newValue2(ssa.OpLoad, n.Type, p, s.mem())
@ -2223,7 +2226,7 @@ func (s *state) append(n *Node, inplace bool) *ssa.Value {
if ssa.IsStackAddr(addr) { if ssa.IsStackAddr(addr) {
s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, pt.Size(), addr, r[0], s.mem()) s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, pt.Size(), addr, r[0], s.mem())
} else { } else {
s.insertWBstore(pt, addr, r[0], n.Lineno, 0) s.insertWBstore(pt, addr, r[0], n.Pos, 0)
} }
// load the value we just stored to avoid having to spill it // load the value we just stored to avoid having to spill it
s.vars[&ptrVar] = s.newValue2(ssa.OpLoad, pt, addr, s.mem()) s.vars[&ptrVar] = s.newValue2(ssa.OpLoad, pt, addr, s.mem())
@ -2278,13 +2281,13 @@ func (s *state) append(n *Node, inplace bool) *ssa.Value {
addr := s.newValue2(ssa.OpPtrIndex, pt, p2, s.constInt(Types[TINT], int64(i))) addr := s.newValue2(ssa.OpPtrIndex, pt, p2, s.constInt(Types[TINT], int64(i)))
if arg.store { if arg.store {
if haspointers(et) { if haspointers(et) {
s.insertWBstore(et, addr, arg.v, n.Lineno, 0) s.insertWBstore(et, addr, arg.v, n.Pos, 0)
} else { } else {
s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, et.Size(), addr, arg.v, s.mem()) s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, et.Size(), addr, arg.v, s.mem())
} }
} else { } else {
if haspointers(et) { if haspointers(et) {
s.insertWBmove(et, addr, arg.v, n.Lineno, arg.isVolatile) s.insertWBmove(et, addr, arg.v, n.Pos, arg.isVolatile)
} else { } else {
s.vars[&memVar] = s.newValue3I(ssa.OpMove, ssa.TypeMem, sizeAlignAuxInt(et), addr, arg.v, s.mem()) s.vars[&memVar] = s.newValue3I(ssa.OpMove, ssa.TypeMem, sizeAlignAuxInt(et), addr, arg.v, s.mem())
} }
@ -2361,7 +2364,7 @@ const (
// If deref is true, rightIsVolatile reports whether right points to volatile (clobbered by a call) storage. // If deref is true, rightIsVolatile reports whether right points to volatile (clobbered by a call) storage.
// Include a write barrier if wb is true. // Include a write barrier if wb is true.
// skip indicates assignments (at the top level) that can be avoided. // skip indicates assignments (at the top level) that can be avoided.
func (s *state) assign(left *Node, right *ssa.Value, wb, deref bool, line int32, 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) { if left.Op == ONAME && isblank(left) {
return return
} }
@ -2855,7 +2858,7 @@ func (s *state) intrinsicCall(n *Node) *ssa.Value {
if x.Op == ssa.OpSelect0 || x.Op == ssa.OpSelect1 { if x.Op == ssa.OpSelect0 || x.Op == ssa.OpSelect1 {
x = x.Args[0] x = x.Args[0]
} }
Warnl(n.Lineno, "intrinsic substitution for %v with %s", n.Left.Sym.Name, x.LongString()) Warnl(n.Pos, "intrinsic substitution for %v with %s", n.Left.Sym.Name, x.LongString())
} }
return v return v
} }
@ -2945,7 +2948,7 @@ func (s *state) call(n *Node, k callKind) *ssa.Value {
// We can then pass that to defer or go. // We can then pass that to defer or go.
n2 := newname(fn.Sym) n2 := newname(fn.Sym)
n2.Class = PFUNC n2.Class = PFUNC
n2.Lineno = fn.Lineno n2.Pos = fn.Pos
n2.Type = Types[TUINT8] // dummy type for a static closure. Could use runtime.funcval if we had it. n2.Type = Types[TUINT8] // dummy type for a static closure. Could use runtime.funcval if we had it.
closure = s.expr(n2) closure = s.expr(n2)
// Note: receiver is already assigned in n.List, so we don't // Note: receiver is already assigned in n.List, so we don't
@ -3146,12 +3149,12 @@ func (s *state) addr(n *Node, bounded bool) (*ssa.Value, bool) {
return s.newValue2(ssa.OpPtrIndex, ptrto(n.Left.Type.Elem()), a, i), isVolatile return s.newValue2(ssa.OpPtrIndex, ptrto(n.Left.Type.Elem()), a, i), isVolatile
} }
case OIND: case OIND:
return s.exprPtr(n.Left, bounded, n.Lineno), false return s.exprPtr(n.Left, bounded, n.Pos), false
case ODOT: case ODOT:
p, isVolatile := s.addr(n.Left, bounded) p, isVolatile := s.addr(n.Left, bounded)
return s.newValue1I(ssa.OpOffPtr, t, n.Xoffset, p), isVolatile return s.newValue1I(ssa.OpOffPtr, t, n.Xoffset, p), isVolatile
case ODOTPTR: case ODOTPTR:
p := s.exprPtr(n.Left, bounded, n.Lineno) p := s.exprPtr(n.Left, bounded, n.Pos)
return s.newValue1I(ssa.OpOffPtr, t, n.Xoffset, p), false return s.newValue1I(ssa.OpOffPtr, t, n.Xoffset, p), false
case OCLOSUREVAR: case OCLOSUREVAR:
return s.newValue1I(ssa.OpOffPtr, t, n.Xoffset, return s.newValue1I(ssa.OpOffPtr, t, n.Xoffset,
@ -3260,10 +3263,10 @@ func canSSAType(t *Type) bool {
} }
// exprPtr evaluates n to a pointer and nil-checks it. // exprPtr evaluates n to a pointer and nil-checks it.
func (s *state) exprPtr(n *Node, bounded bool, lineno int32) *ssa.Value { func (s *state) exprPtr(n *Node, bounded bool, lineno src.XPos) *ssa.Value {
p := s.expr(n) p := s.expr(n)
if bounded || n.NonNil { if bounded || n.NonNil {
if s.f.Config.Debug_checknil() && lineno > 1 { if s.f.Config.Debug_checknil() && lineno.Line() > 1 {
s.f.Config.Warnl(lineno, "removed nil check") s.f.Config.Warnl(lineno, "removed nil check")
} }
return p return p
@ -3315,7 +3318,7 @@ func (s *state) check(cmp *ssa.Value, fn *Node) {
b.SetControl(cmp) b.SetControl(cmp)
b.Likely = ssa.BranchLikely b.Likely = ssa.BranchLikely
bNext := s.f.NewBlock(ssa.BlockPlain) bNext := s.f.NewBlock(ssa.BlockPlain)
line := s.peekLine() line := s.peekPos()
bPanic := s.panics[funcLine{fn, line}] bPanic := s.panics[funcLine{fn, line}]
if bPanic == nil { if bPanic == nil {
bPanic = s.f.NewBlock(ssa.BlockPlain) bPanic = s.f.NewBlock(ssa.BlockPlain)
@ -3408,7 +3411,7 @@ func (s *state) rtcall(fn *Node, returns bool, results []*Type, args ...*ssa.Val
// insertWBmove inserts the assignment *left = *right including a write barrier. // insertWBmove inserts the assignment *left = *right including a write barrier.
// t is the type being assigned. // t is the type being assigned.
// If right == nil, then we're zeroing *left. // If right == nil, then we're zeroing *left.
func (s *state) insertWBmove(t *Type, left, right *ssa.Value, line int32, rightIsVolatile bool) { func (s *state) insertWBmove(t *Type, left, right *ssa.Value, line src.XPos, rightIsVolatile bool) {
// if writeBarrier.enabled { // if writeBarrier.enabled {
// typedmemmove(&t, left, right) // typedmemmove(&t, left, right)
// } else { // } else {
@ -3426,8 +3429,8 @@ func (s *state) insertWBmove(t *Type, left, right *ssa.Value, line int32, rightI
if s.noWB { if s.noWB {
s.Error("write barrier prohibited") s.Error("write barrier prohibited")
} }
if s.WBLineno == 0 { if !s.WBPos.IsKnown() {
s.WBLineno = left.Line s.WBPos = left.Pos
} }
var val *ssa.Value var val *ssa.Value
@ -3456,7 +3459,7 @@ func (s *state) insertWBmove(t *Type, left, right *ssa.Value, line int32, rightI
// insertWBstore inserts the assignment *left = right including a write barrier. // insertWBstore inserts the assignment *left = right including a write barrier.
// t is the type being assigned. // t is the type being assigned.
func (s *state) insertWBstore(t *Type, left, right *ssa.Value, line int32, skip skipMask) { func (s *state) insertWBstore(t *Type, left, right *ssa.Value, line src.XPos, skip skipMask) {
// store scalar fields // store scalar fields
// if writeBarrier.enabled { // if writeBarrier.enabled {
// writebarrierptr for pointer fields // writebarrierptr for pointer fields
@ -3467,8 +3470,8 @@ func (s *state) insertWBstore(t *Type, left, right *ssa.Value, line int32, skip
if s.noWB { if s.noWB {
s.Error("write barrier prohibited") s.Error("write barrier prohibited")
} }
if s.WBLineno == 0 { if !s.WBPos.IsKnown() {
s.WBLineno = left.Line s.WBPos = left.Pos
} }
s.storeTypeScalars(t, left, right, skip) s.storeTypeScalars(t, left, right, skip)
s.storeTypePtrsWB(t, left, right) s.storeTypePtrsWB(t, left, right)
@ -4062,7 +4065,7 @@ func (s *state) dottype(n *Node, commaok bool) (res, resok *ssa.Value) {
// Converting to an empty interface. // Converting to an empty interface.
// Input could be an empty or nonempty interface. // Input could be an empty or nonempty interface.
if Debug_typeassert > 0 { if Debug_typeassert > 0 {
Warnl(n.Lineno, "type assertion inlined") Warnl(n.Pos, "type assertion inlined")
} }
// Get itab/type field from input. // Get itab/type field from input.
@ -4129,7 +4132,7 @@ func (s *state) dottype(n *Node, commaok bool) (res, resok *ssa.Value) {
} }
// converting to a nonempty interface needs a runtime call. // converting to a nonempty interface needs a runtime call.
if Debug_typeassert > 0 { if Debug_typeassert > 0 {
Warnl(n.Lineno, "type assertion not inlined") Warnl(n.Pos, "type assertion not inlined")
} }
if n.Left.Type.IsEmptyInterface() { if n.Left.Type.IsEmptyInterface() {
if commaok { if commaok {
@ -4146,7 +4149,7 @@ func (s *state) dottype(n *Node, commaok bool) (res, resok *ssa.Value) {
} }
if Debug_typeassert > 0 { if Debug_typeassert > 0 {
Warnl(n.Lineno, "type assertion inlined") Warnl(n.Pos, "type assertion inlined")
} }
// Converting to a concrete type. // Converting to a concrete type.
@ -4154,7 +4157,7 @@ func (s *state) dottype(n *Node, commaok bool) (res, resok *ssa.Value) {
typ := s.ifaceType(n.Left.Type, iface) // actual concrete type of input interface typ := s.ifaceType(n.Left.Type, iface) // actual concrete type of input interface
if Debug_typeassert > 0 { if Debug_typeassert > 0 {
Warnl(n.Lineno, "type assertion inlined") Warnl(n.Pos, "type assertion inlined")
} }
var tmp *Node // temporary for use with large types var tmp *Node // temporary for use with large types
@ -4293,7 +4296,7 @@ func (s *state) checkgoto(from *Node, to *Node) {
fs = fs.Link fs = fs.Link
} }
lno := from.Left.Lineno lno := from.Left.Pos
if block != nil { if block != nil {
yyerrorl(lno, "goto %v jumps into block starting at %v", from.Left.Sym, linestr(block.Lastlineno)) yyerrorl(lno, "goto %v jumps into block starting at %v", from.Left.Sym, linestr(block.Lastlineno))
} else { } else {
@ -4380,9 +4383,9 @@ func (s *SSAGenState) Pc() *obj.Prog {
return pc return pc
} }
// SetLineno sets the current source line number. // SetPos sets the current source position.
func (s *SSAGenState) SetLineno(l int32) { func (s *SSAGenState) SetPos(pos src.XPos) {
lineno = l lineno = pos
} }
// genssa appends entries to ptxt for each instruction in f. // genssa appends entries to ptxt for each instruction in f.
@ -4462,8 +4465,11 @@ func genssa(f *ssa.Func, ptxt *obj.Prog, gcargs, gclocals *Sym) {
f.Logf("%s\t%s\n", s, p) f.Logf("%s\t%s\n", s, p)
} }
if f.Config.HTML != nil { if f.Config.HTML != nil {
saved := ptxt.Ctxt.LineHist.PrintFilenameOnly // LineHist is defunct now - this code won't do
ptxt.Ctxt.LineHist.PrintFilenameOnly = true // anything.
// TODO: fix this (ideally without a global variable)
// saved := ptxt.Ctxt.LineHist.PrintFilenameOnly
// ptxt.Ctxt.LineHist.PrintFilenameOnly = true
var buf bytes.Buffer var buf bytes.Buffer
buf.WriteString("<code>") buf.WriteString("<code>")
buf.WriteString("<dl class=\"ssa-gen\">") buf.WriteString("<dl class=\"ssa-gen\">")
@ -4483,7 +4489,7 @@ func genssa(f *ssa.Func, ptxt *obj.Prog, gcargs, gclocals *Sym) {
buf.WriteString("</dl>") buf.WriteString("</dl>")
buf.WriteString("</code>") buf.WriteString("</code>")
f.Config.HTML.WriteColumn("genssa", buf.String()) f.Config.HTML.WriteColumn("genssa", buf.String())
ptxt.Ctxt.LineHist.PrintFilenameOnly = saved // ptxt.Ctxt.LineHist.PrintFilenameOnly = saved
} }
} }
@ -4958,8 +4964,8 @@ func (e *ssaExport) CanSSA(t ssa.Type) bool {
return canSSAType(t.(*Type)) return canSSAType(t.(*Type))
} }
func (e *ssaExport) Line(line int32) string { func (e *ssaExport) Line(pos src.XPos) string {
return linestr(line) return linestr(pos)
} }
// Log logs a message from the compiler. // Log logs a message from the compiler.
@ -4974,15 +4980,15 @@ func (e *ssaExport) Log() bool {
} }
// Fatal reports a compiler error and exits. // Fatal reports a compiler error and exits.
func (e *ssaExport) Fatalf(line int32, msg string, args ...interface{}) { func (e *ssaExport) Fatalf(pos src.XPos, msg string, args ...interface{}) {
lineno = line lineno = pos
Fatalf(msg, args...) Fatalf(msg, args...)
} }
// Warnl reports a "warning", which is usually flag-triggered // Warnl reports a "warning", which is usually flag-triggered
// logging output for the benefit of tests. // logging output for the benefit of tests.
func (e *ssaExport) Warnl(line int32, fmt_ string, args ...interface{}) { func (e *ssaExport) Warnl(pos src.XPos, fmt_ string, args ...interface{}) {
Warnl(line, fmt_, args...) Warnl(pos, fmt_, args...)
} }
func (e *ssaExport) Debug_checknil() bool { func (e *ssaExport) Debug_checknil() bool {

View file

@ -7,6 +7,7 @@ package gc
import ( import (
"bytes" "bytes"
"cmd/internal/obj" "cmd/internal/obj"
"cmd/internal/src"
"crypto/md5" "crypto/md5"
"encoding/binary" "encoding/binary"
"fmt" "fmt"
@ -20,8 +21,8 @@ import (
) )
type Error struct { type Error struct {
lineno int32 pos src.XPos
msg string msg string
} }
var errors []Error var errors []Error
@ -39,24 +40,24 @@ func adderrorname(n *Node) {
return return
} }
old := fmt.Sprintf("%v: undefined: %v\n", n.Line(), n.Left) old := fmt.Sprintf("%v: undefined: %v\n", n.Line(), n.Left)
if len(errors) > 0 && errors[len(errors)-1].lineno == n.Lineno && errors[len(errors)-1].msg == old { if len(errors) > 0 && errors[len(errors)-1].pos.Line() == n.Pos.Line() && errors[len(errors)-1].msg == old {
errors[len(errors)-1].msg = fmt.Sprintf("%v: undefined: %v in %v\n", n.Line(), n.Left, n) errors[len(errors)-1].msg = fmt.Sprintf("%v: undefined: %v in %v\n", n.Line(), n.Left, n)
} }
} }
func adderr(line int32, format string, args ...interface{}) { func adderr(pos src.XPos, format string, args ...interface{}) {
errors = append(errors, Error{ errors = append(errors, Error{
lineno: line, pos: pos,
msg: fmt.Sprintf("%v: %s\n", linestr(line), fmt.Sprintf(format, args...)), msg: fmt.Sprintf("%v: %s\n", linestr(pos), fmt.Sprintf(format, args...)),
}) })
} }
// byLineno sorts errors by lineno. // byPos sorts errors by source position.
type byLineno []Error type byPos []Error
func (x byLineno) Len() int { return len(x) } func (x byPos) Len() int { return len(x) }
func (x byLineno) Less(i, j int) bool { return x[i].lineno < x[j].lineno } func (x byPos) Less(i, j int) bool { return x[i].pos.Before(x[j].pos) }
func (x byLineno) Swap(i, j int) { x[i], x[j] = x[j], x[i] } func (x byPos) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
// flusherrors sorts errors seen so far by line number, prints them to stdout, // flusherrors sorts errors seen so far by line number, prints them to stdout,
// and empties the errors array. // and empties the errors array.
@ -65,7 +66,7 @@ func flusherrors() {
if len(errors) == 0 { if len(errors) == 0 {
return return
} }
sort.Stable(byLineno(errors)) sort.Stable(byPos(errors))
for i := 0; i < len(errors); i++ { for i := 0; i < len(errors); i++ {
if i == 0 || errors[i].msg != errors[i-1].msg { if i == 0 || errors[i].msg != errors[i-1].msg {
fmt.Printf("%s", errors[i].msg) fmt.Printf("%s", errors[i].msg)
@ -85,49 +86,56 @@ func hcrash() {
} }
} }
func linestr(line int32) string { func linestr(pos src.XPos) string {
return Ctxt.Line(int(line)) return Ctxt.PosTable.Pos(pos).String()
} }
// lasterror keeps track of the most recently issued error. // lasterror keeps track of the most recently issued error.
// It is used to avoid multiple error messages on the same // It is used to avoid multiple error messages on the same
// line. // line.
var lasterror struct { var lasterror struct {
syntax int32 // line of last syntax error syntax src.XPos // source position of last syntax error
other int32 // line of last non-syntax error other src.XPos // source position of last non-syntax error
msg string // error message of last non-syntax error msg string // error message of last non-syntax error
} }
func yyerrorl(line int32, format string, args ...interface{}) { // sameline reports whether two positions a, b are on the same 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.XPos, format string, args ...interface{}) {
msg := fmt.Sprintf(format, args...) msg := fmt.Sprintf(format, args...)
if strings.HasPrefix(msg, "syntax error") { if strings.HasPrefix(msg, "syntax error") {
nsyntaxerrors++ nsyntaxerrors++
// only one syntax error per line, no matter what error // only one syntax error per line, no matter what error
if lasterror.syntax == line { if sameline(lasterror.syntax, pos) {
return return
} }
lasterror.syntax = line lasterror.syntax = pos
} else { } else {
// only one of multiple equal non-syntax errors per line // only one of multiple equal non-syntax errors per line
// (flusherrors shows only one of them, so we filter them // (flusherrors shows only one of them, so we filter them
// here as best as we can (they may not appear in order) // here as best as we can (they may not appear in order)
// so that we don't count them here and exit early, and // so that we don't count them here and exit early, and
// then have nothing to show for.) // then have nothing to show for.)
if lasterror.other == line && lasterror.msg == msg { if sameline(lasterror.other, pos) && lasterror.msg == msg {
return return
} }
lasterror.other = line lasterror.other = pos
lasterror.msg = msg lasterror.msg = msg
} }
adderr(line, "%s", msg) adderr(pos, "%s", msg)
hcrash() hcrash()
nerrors++ nerrors++
if nsavederrors+nerrors >= 10 && Debug['e'] == 0 { if nsavederrors+nerrors >= 10 && Debug['e'] == 0 {
flusherrors() flusherrors()
fmt.Printf("%v: too many errors\n", linestr(line)) fmt.Printf("%v: too many errors\n", linestr(pos))
errorexit() errorexit()
} }
} }
@ -142,7 +150,7 @@ func Warn(fmt_ string, args ...interface{}) {
hcrash() hcrash()
} }
func Warnl(line int32, fmt_ string, args ...interface{}) { func Warnl(line src.XPos, fmt_ string, args ...interface{}) {
adderr(line, fmt_, args...) adderr(line, fmt_, args...)
if Debug['m'] != 0 { if Debug['m'] != 0 {
flusherrors() flusherrors()
@ -172,35 +180,7 @@ func Fatalf(fmt_ string, args ...interface{}) {
errorexit() errorexit()
} }
func linehistpragma(file string) { func setlineno(n *Node) src.XPos {
if Debug['i'] != 0 {
fmt.Printf("pragma %s at line %v\n", file, linestr(lexlineno))
}
Ctxt.AddImport(file)
}
func linehistpush(file string) {
if Debug['i'] != 0 {
fmt.Printf("import %s at line %v\n", file, linestr(lexlineno))
}
Ctxt.LineHist.Push(int(lexlineno), file)
}
func linehistpop() {
if Debug['i'] != 0 {
fmt.Printf("end of import at line %v\n", linestr(lexlineno))
}
Ctxt.LineHist.Pop(int(lexlineno))
}
func linehistupdate(file string, off int) {
if Debug['i'] != 0 {
fmt.Printf("line %s at line %v\n", file, linestr(lexlineno))
}
Ctxt.LineHist.Update(int(lexlineno), file, off)
}
func setlineno(n *Node) int32 {
lno := lineno lno := lineno
if n != nil { if n != nil {
switch n.Op { switch n.Op {
@ -214,10 +194,10 @@ func setlineno(n *Node) int32 {
fallthrough fallthrough
default: default:
lineno = n.Lineno lineno = n.Pos
if lineno == 0 { if !lineno.IsKnown() {
if Debug['K'] != 0 { if Debug['K'] != 0 {
Warn("setlineno: line 0") Warn("setlineno: unknown position (line 0)")
} }
lineno = lno lineno = lno
} }
@ -348,7 +328,7 @@ func importdot(opkg *Pkg, pack *Node) {
if n == 0 { if n == 0 {
// can't possibly be used - there were no symbols // can't possibly be used - there were no symbols
yyerrorl(pack.Lineno, "imported and not used: %q", opkg.Path) yyerrorl(pack.Pos, "imported and not used: %q", opkg.Path)
} }
} }
@ -357,7 +337,7 @@ func nod(op Op, nleft *Node, nright *Node) *Node {
n.Op = op n.Op = op
n.Left = nleft n.Left = nleft
n.Right = nright n.Right = nright
n.Lineno = lineno n.Pos = lineno
n.Xoffset = BADWIDTH n.Xoffset = BADWIDTH
n.Orig = n n.Orig = n
switch op { switch op {
@ -473,9 +453,9 @@ func nodbool(b bool) *Node {
// treecopy recursively copies n, with the exception of // treecopy recursively copies n, with the exception of
// ONAME, OLITERAL, OTYPE, and non-iota ONONAME leaves. // ONAME, OLITERAL, OTYPE, and non-iota ONONAME leaves.
// Copies of iota ONONAME nodes are assigned the current // Copies of iota ONONAME nodes are assigned the current
// value of iota_. If lineno != 0, it sets the line number // value of iota_. If pos.IsKnown(), it sets the source
// of newly allocated nodes to lineno. // position of newly allocated nodes to pos.
func treecopy(n *Node, lineno int32) *Node { func treecopy(n *Node, pos src.XPos) *Node {
if n == nil { if n == nil {
return nil return nil
} }
@ -484,11 +464,11 @@ func treecopy(n *Node, lineno int32) *Node {
default: default:
m := *n m := *n
m.Orig = &m m.Orig = &m
m.Left = treecopy(n.Left, lineno) m.Left = treecopy(n.Left, pos)
m.Right = treecopy(n.Right, lineno) m.Right = treecopy(n.Right, pos)
m.List.Set(listtreecopy(n.List.Slice(), lineno)) m.List.Set(listtreecopy(n.List.Slice(), pos))
if lineno != 0 { if pos.IsKnown() {
m.Lineno = lineno m.Pos = pos
} }
if m.Name != nil && n.Op != ODCLFIELD { if m.Name != nil && n.Op != ODCLFIELD {
Dump("treecopy", n) Dump("treecopy", n)
@ -503,8 +483,8 @@ func treecopy(n *Node, lineno int32) *Node {
// so that all the copies of this const definition // so that all the copies of this const definition
// don't have the same iota value. // don't have the same iota value.
m := *n m := *n
if lineno != 0 { if pos.IsKnown() {
m.Lineno = lineno m.Pos = pos
} }
m.SetIota(iota_) m.SetIota(iota_)
return &m return &m
@ -1706,21 +1686,12 @@ func structargs(tl *Type, mustname bool) []*Node {
// method - M func (t T)(), a TFIELD type struct // method - M func (t T)(), a TFIELD type struct
// newnam - the eventual mangled name of this function // newnam - the eventual mangled name of this function
var genwrapper_linehistdone int = 0
func genwrapper(rcvr *Type, method *Field, newnam *Sym, iface int) { func genwrapper(rcvr *Type, method *Field, newnam *Sym, iface int) {
if false && Debug['r'] != 0 { if false && Debug['r'] != 0 {
fmt.Printf("genwrapper rcvrtype=%v method=%v newnam=%v\n", rcvr, method, newnam) fmt.Printf("genwrapper rcvrtype=%v method=%v newnam=%v\n", rcvr, method, newnam)
} }
lexlineno++ lineno = MakePos(src.NewFileBase("<autogenerated>", "<autogenerated>"), 1, 0)
lineno = lexlineno
if genwrapper_linehistdone == 0 {
// All the wrappers can share the same linehist entry.
linehistpush("<autogenerated>")
genwrapper_linehistdone = 1
}
dclcontext = PEXTERN dclcontext = PEXTERN
markdcl() markdcl()
@ -1993,10 +1964,10 @@ func Simsimtype(t *Type) EType {
return et return et
} }
func listtreecopy(l []*Node, lineno int32) []*Node { func listtreecopy(l []*Node, pos src.XPos) []*Node {
var out []*Node var out []*Node
for _, n := range l { for _, n := range l {
out = append(out, treecopy(n, lineno)) out = append(out, treecopy(n, pos))
} }
return out return out
} }
@ -2005,7 +1976,7 @@ func liststmt(l []*Node) *Node {
n := nod(OBLOCK, nil, nil) n := nod(OBLOCK, nil, nil)
n.List.Set(l) n.List.Set(l)
if len(l) != 0 { if len(l) != 0 {
n.Lineno = l[0].Lineno n.Pos = l[0].Pos
} }
return n return n
} }

View file

@ -578,7 +578,7 @@ Outer:
} }
for _, n := range prev { for _, n := range prev {
if eqtype(n.Left.Type, c.node.Left.Type) { if eqtype(n.Left.Type, c.node.Left.Type) {
yyerrorl(c.node.Lineno, "duplicate case %v in type switch\n\tprevious case at %v", c.node.Left.Type, n.Line()) yyerrorl(c.node.Pos, "duplicate case %v in type switch\n\tprevious case at %v", c.node.Left.Type, n.Line())
// avoid double-reporting errors // avoid double-reporting errors
continue Outer continue Outer
} }

View file

@ -6,6 +6,11 @@
package gc package gc
import (
"cmd/compile/internal/syntax"
"cmd/internal/src"
)
// A Node is a single node in the syntax tree. // A Node is a single node in the syntax tree.
// Actually the syntax tree is a syntax DAG, because there is only one // Actually the syntax tree is a syntax DAG, because there is only one
// node with Op=ONAME for a given instance of a variable x. // node with Op=ONAME for a given instance of a variable x.
@ -42,7 +47,7 @@ type Node struct {
// Possibly still more uses. If you find any, document them. // Possibly still more uses. If you find any, document them.
Xoffset int64 Xoffset int64
Lineno int32 Pos src.XPos
Esc uint16 // EscXXX Esc uint16 // EscXXX
@ -283,7 +288,7 @@ type Param struct {
// OTYPE // OTYPE
// //
// TODO: Should Func pragmas also be stored on the Name? // TODO: Should Func pragmas also be stored on the Name?
Pragma Pragma Pragma syntax.Pragma
Alias bool // node is alias for Ntype (only used when type-checking ODCLTYPE) Alias bool // node is alias for Ntype (only used when type-checking ODCLTYPE)
} }
@ -309,14 +314,14 @@ type Func struct {
Label int32 // largest auto-generated label in this function Label int32 // largest auto-generated label in this function
Endlineno int32 Endlineno src.XPos
WBLineno int32 // line number of first write barrier WBPos src.XPos // position of first write barrier
Pragma Pragma // go:xxx function annotations Pragma syntax.Pragma // go:xxx function annotations
Dupok bool // duplicate definitions ok Dupok bool // duplicate definitions ok
Wrapper bool // is method wrapper Wrapper bool // is method wrapper
Needctxt bool // function uses context register (has closure variables) Needctxt bool // function uses context register (has closure variables)
ReflectMethod bool // function calls reflect.Type.Method or MethodByName ReflectMethod bool // function calls reflect.Type.Method or MethodByName
IsHiddenClosure bool IsHiddenClosure bool
NoFramePointer bool // Must not use a frame pointer for this function NoFramePointer bool // Must not use a frame pointer for this function
} }

View file

@ -11,6 +11,7 @@ package gc
import ( import (
"cmd/compile/internal/ssa" "cmd/compile/internal/ssa"
"cmd/internal/src"
"fmt" "fmt"
) )
@ -149,9 +150,9 @@ type Type struct {
sliceOf *Type sliceOf *Type
ptrTo *Type ptrTo *Type
Sym *Sym // symbol containing name, for named types Sym *Sym // symbol containing name, for named types
Vargen int32 // unique name for OTYPE/ONAME Vargen int32 // unique name for OTYPE/ONAME
Lineno int32 // line at which this type was declared, implicitly or explicitly Pos src.XPos // position at which this type was declared, implicitly or explicitly
Etype EType // kind of type Etype EType // kind of type
Noalg bool // suppress hash and eq algorithm generation Noalg bool // suppress hash and eq algorithm generation
@ -181,8 +182,8 @@ func (t *Type) MapType() *MapType {
// ForwardType contains Type fields specific to forward types. // ForwardType contains Type fields specific to forward types.
type ForwardType struct { type ForwardType struct {
Copyto []*Node // where to copy the eventual value to Copyto []*Node // where to copy the eventual value to
Embedlineno int32 // first use of this type as an embedded type Embedlineno src.XPos // first use of this type as an embedded type
} }
// ForwardType returns t's extra forward-type-specific fields. // ForwardType returns t's extra forward-type-specific fields.
@ -375,9 +376,9 @@ func (f *Fields) Append(s ...*Field) {
// typ returns a new Type of the specified kind. // typ returns a new Type of the specified kind.
func typ(et EType) *Type { func typ(et EType) *Type {
t := &Type{ t := &Type{
Etype: et, Etype: et,
Width: BADWIDTH, Width: BADWIDTH,
Lineno: lineno, Pos: lineno,
} }
t.Orig = t t.Orig = t
// TODO(josharian): lazily initialize some of these? // TODO(josharian): lazily initialize some of these?

View file

@ -6,6 +6,7 @@ package gc
import ( import (
"cmd/internal/obj" "cmd/internal/obj"
"cmd/internal/src"
"fmt" "fmt"
"math" "math"
"strings" "strings"
@ -163,7 +164,7 @@ func typecheck(n *Node, top int) *Node {
if top&Etype == Etype { if top&Etype == Etype {
var trace string var trace string
sprint_depchain(&trace, typecheck_tcstack, n, n) sprint_depchain(&trace, typecheck_tcstack, n, n)
yyerrorl(n.Lineno, "invalid recursive type alias %v%s", n, trace) yyerrorl(n.Pos, "invalid recursive type alias %v%s", n, trace)
} }
case OLITERAL: case OLITERAL:
@ -173,7 +174,7 @@ func typecheck(n *Node, top int) *Node {
} }
var trace string var trace string
sprint_depchain(&trace, typecheck_tcstack, n, n) sprint_depchain(&trace, typecheck_tcstack, n, n)
yyerrorl(n.Lineno, "constant definition loop%s", trace) yyerrorl(n.Pos, "constant definition loop%s", trace)
} }
if nsavederrors+nerrors == 0 { if nsavederrors+nerrors == 0 {
@ -421,7 +422,7 @@ OpSwitch:
if alg == ANOEQ { if alg == ANOEQ {
if bad.Etype == TFORW { if bad.Etype == TFORW {
// queue check for map until all the types are done settling. // queue check for map until all the types are done settling.
mapqueue = append(mapqueue, mapqueueval{l, n.Lineno}) mapqueue = append(mapqueue, mapqueueval{l, n.Pos})
} else if bad.Etype != TANY { } else if bad.Etype != TANY {
// no need to queue, key is already bad // no need to queue, key is already bad
yyerror("invalid map key type %v", l.Type) yyerror("invalid map key type %v", l.Type)
@ -3513,7 +3514,7 @@ func domethod(n *Node) {
type mapqueueval struct { type mapqueueval struct {
n *Node n *Node
lno int32 lno src.XPos
} }
// tracks the line numbers at which forward types are first used as map keys // tracks the line numbers at which forward types are first used as map keys
@ -3561,7 +3562,7 @@ func copytype(n *Node, t *Type) {
// Double-check use of type as embedded type. // Double-check use of type as embedded type.
lno := lineno lno := lineno
if embedlineno != 0 { if embedlineno.IsKnown() {
lineno = embedlineno lineno = embedlineno
if t.IsPtr() || t.IsUnsafePtr() { if t.IsPtr() || t.IsUnsafePtr() {
yyerror("embedded type cannot be a pointer") yyerror("embedded type cannot be a pointer")
@ -3640,8 +3641,8 @@ func typecheckdef(n *Node) *Node {
if n.Op == ONONAME { if n.Op == ONONAME {
if !n.Diag { if !n.Diag {
n.Diag = true n.Diag = true
if n.Lineno != 0 { if n.Pos.IsKnown() {
lineno = n.Lineno lineno = n.Pos
} }
// Note: adderrorname looks for this string and // Note: adderrorname looks for this string and
@ -3695,7 +3696,7 @@ func typecheckdef(n *Node) *Node {
e := n.Name.Defn e := n.Name.Defn
n.Name.Defn = nil n.Name.Defn = nil
if e == nil { if e == nil {
lineno = n.Lineno lineno = n.Pos
Dump("typecheckdef nil defn", n) Dump("typecheckdef nil defn", n)
yyerror("xxx") yyerror("xxx")
} }

View file

@ -11,7 +11,7 @@ import (
) )
func (n *Node) Line() string { func (n *Node) Line() string {
return Ctxt.LineHist.LineString(int(n.Lineno)) return linestr(n.Pos)
} }
var atExitFuncs []func() var atExitFuncs []func()

View file

@ -49,11 +49,11 @@ func walk(fn *Node) {
if defn.Left.Used { if defn.Left.Used {
continue continue
} }
lineno = defn.Left.Lineno lineno = defn.Left.Pos
yyerror("%v declared and not used", ln.Sym) yyerror("%v declared and not used", ln.Sym)
defn.Left.Used = true // suppress repeats defn.Left.Used = true // suppress repeats
} else { } else {
lineno = ln.Lineno lineno = ln.Pos
yyerror("%v declared and not used", ln.Sym) yyerror("%v declared and not used", ln.Sym)
} }
} }
@ -2137,7 +2137,7 @@ func needwritebarrier(l *Node, r *Node) bool {
func applywritebarrier(n *Node) *Node { func applywritebarrier(n *Node) *Node {
if n.Left != nil && n.Right != nil && needwritebarrier(n.Left, n.Right) { if n.Left != nil && n.Right != nil && needwritebarrier(n.Left, n.Right) {
if Debug_wb > 1 { if Debug_wb > 1 {
Warnl(n.Lineno, "marking %v for barrier", n.Left) Warnl(n.Pos, "marking %v for barrier", n.Left)
} }
n.Op = OASWB n.Op = OASWB
return n return n
@ -2592,7 +2592,7 @@ func returnsfromheap(params *Type) []*Node {
// Enter and Exit lists. // Enter and Exit lists.
func heapmoves() { func heapmoves() {
lno := lineno lno := lineno
lineno = Curfn.Lineno lineno = Curfn.Pos
nn := paramstoheap(Curfn.Type.Recvs()) nn := paramstoheap(Curfn.Type.Recvs())
nn = append(nn, paramstoheap(Curfn.Type.Params())...) nn = append(nn, paramstoheap(Curfn.Type.Params())...)
nn = append(nn, paramstoheap(Curfn.Type.Results())...) nn = append(nn, paramstoheap(Curfn.Type.Results())...)
@ -3418,7 +3418,7 @@ func walkinrange(n *Node, init *Nodes) *Node {
opr = brcom(opr) opr = brcom(opr)
} }
cmp := nod(opr, lhs, rhs) cmp := nod(opr, lhs, rhs)
cmp.Lineno = n.Lineno cmp.Pos = n.Pos
cmp = addinit(cmp, l.Ninit.Slice()) cmp = addinit(cmp, l.Ninit.Slice())
cmp = addinit(cmp, r.Ninit.Slice()) cmp = addinit(cmp, r.Ninit.Slice())
// Typecheck the AST rooted at cmp... // Typecheck the AST rooted at cmp...

View file

@ -74,7 +74,7 @@ func storeByType(t ssa.Type, r int16) obj.As {
} }
func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) { func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
s.SetLineno(v.Line) s.SetPos(v.Pos)
switch v.Op { switch v.Op {
case ssa.OpInitMem: case ssa.OpInitMem:
// memory arg needs no code // memory arg needs no code
@ -796,8 +796,8 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
gc.AddAux(&p.From, v) gc.AddAux(&p.From, v)
p.To.Type = obj.TYPE_REG p.To.Type = obj.TYPE_REG
p.To.Reg = mips.REGTMP p.To.Reg = mips.REGTMP
if gc.Debug_checknil != 0 && v.Line > 1 { // v.Line==1 in generated wrappers if gc.Debug_checknil != 0 && v.Pos.Line() > 1 { // v.Pos.Line()==1 in generated wrappers
gc.Warnl(v.Line, "generated nil check") gc.Warnl(v.Pos, "generated nil check")
} }
case ssa.OpMIPSFPFlagTrue, case ssa.OpMIPSFPFlagTrue,
ssa.OpMIPSFPFlagFalse: ssa.OpMIPSFPFlagFalse:
@ -841,7 +841,7 @@ var blockJump = map[ssa.BlockKind]struct {
} }
func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) { func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
s.SetLineno(b.Line) s.SetPos(b.Pos)
switch b.Kind { switch b.Kind {
case ssa.BlockPlain: case ssa.BlockPlain:

View file

@ -82,7 +82,7 @@ func storeByType(t ssa.Type, r int16) obj.As {
} }
func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) { func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
s.SetLineno(v.Line) s.SetPos(v.Pos)
switch v.Op { switch v.Op {
case ssa.OpInitMem: case ssa.OpInitMem:
// memory arg needs no code // memory arg needs no code
@ -548,8 +548,8 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
gc.AddAux(&p.From, v) gc.AddAux(&p.From, v)
p.To.Type = obj.TYPE_REG p.To.Type = obj.TYPE_REG
p.To.Reg = mips.REGTMP p.To.Reg = mips.REGTMP
if gc.Debug_checknil != 0 && v.Line > 1 { // v.Line==1 in generated wrappers if gc.Debug_checknil != 0 && v.Pos.Line() > 1 { // v.Pos.Line()==1 in generated wrappers
gc.Warnl(v.Line, "generated nil check") gc.Warnl(v.Pos, "generated nil check")
} }
case ssa.OpVarDef: case ssa.OpVarDef:
gc.Gvardef(v.Aux.(*gc.Node)) gc.Gvardef(v.Aux.(*gc.Node))
@ -606,7 +606,7 @@ var blockJump = map[ssa.BlockKind]struct {
} }
func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) { func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
s.SetLineno(b.Line) s.SetPos(b.Pos)
switch b.Kind { switch b.Kind {
case ssa.BlockPlain: case ssa.BlockPlain:

View file

@ -143,7 +143,7 @@ func ssaGenISEL(v *ssa.Value, cr int64, r1, r2 int16) {
} }
func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) { func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
s.SetLineno(v.Line) s.SetPos(v.Pos)
switch v.Op { switch v.Op {
case ssa.OpInitMem: case ssa.OpInitMem:
// memory arg needs no code // memory arg needs no code
@ -803,8 +803,8 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
gc.AddAux(&p.From, v) gc.AddAux(&p.From, v)
p.To.Type = obj.TYPE_REG p.To.Type = obj.TYPE_REG
p.To.Reg = ppc64.REGTMP p.To.Reg = ppc64.REGTMP
if gc.Debug_checknil != 0 && v.Line > 1 { // v.Line==1 in generated wrappers if gc.Debug_checknil != 0 && v.Pos.Line() > 1 { // v.Pos.Line()==1 in generated wrappers
gc.Warnl(v.Line, "generated nil check") gc.Warnl(v.Pos, "generated nil check")
} }
case ssa.OpPPC64InvertFlags: case ssa.OpPPC64InvertFlags:
@ -837,7 +837,7 @@ var blockJump = [...]struct {
} }
func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) { func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
s.SetLineno(b.Line) s.SetPos(b.Pos)
switch b.Kind { switch b.Kind {

View file

@ -156,7 +156,7 @@ func opregregimm(op obj.As, dest, src int16, off int64) *obj.Prog {
} }
func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) { func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
s.SetLineno(v.Line) s.SetPos(v.Pos)
switch v.Op { switch v.Op {
case ssa.OpS390XSLD, ssa.OpS390XSLW, case ssa.OpS390XSLD, ssa.OpS390XSLW,
ssa.OpS390XSRD, ssa.OpS390XSRW, ssa.OpS390XSRD, ssa.OpS390XSRW,
@ -570,8 +570,8 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
gc.AddAux(&p.From, v) gc.AddAux(&p.From, v)
p.To.Type = obj.TYPE_REG p.To.Type = obj.TYPE_REG
p.To.Reg = s390x.REGTMP p.To.Reg = s390x.REGTMP
if gc.Debug_checknil != 0 && v.Line > 1 { // v.Line==1 in generated wrappers if gc.Debug_checknil != 0 && v.Pos.Line() > 1 { // v.Pos.Line()==1 in generated wrappers
gc.Warnl(v.Line, "generated nil check") gc.Warnl(v.Pos, "generated nil check")
} }
case ssa.OpS390XMVC: case ssa.OpS390XMVC:
vo := v.AuxValAndOff() vo := v.AuxValAndOff()
@ -796,7 +796,7 @@ var blockJump = [...]struct {
} }
func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) { func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
s.SetLineno(b.Line) s.SetPos(b.Pos)
switch b.Kind { switch b.Kind {
case ssa.BlockPlain: case ssa.BlockPlain:

View file

@ -4,7 +4,10 @@
package ssa package ssa
import "fmt" import (
"cmd/internal/src"
"fmt"
)
// Block represents a basic block in the control flow graph of a function. // Block represents a basic block in the control flow graph of a function.
type Block struct { type Block struct {
@ -12,8 +15,8 @@ type Block struct {
// these IDs densely, but no guarantees. // these IDs densely, but no guarantees.
ID ID ID ID
// Line number for block's control operation // Source position for block's control operation
Line int32 Pos src.XPos
// The kind of block this is. // The kind of block this is.
Kind BlockKind Kind BlockKind

View file

@ -16,7 +16,7 @@ func checkbce(f *Func) {
for _, b := range f.Blocks { for _, b := range f.Blocks {
for _, v := range b.Values { for _, v := range b.Values {
if v.Op == OpIsInBounds || v.Op == OpIsSliceInBounds { if v.Op == OpIsInBounds || v.Op == OpIsSliceInBounds {
f.Config.Warnl(v.Line, "Found %v", v.Op) f.Config.Warnl(v.Pos, "Found %v", v.Op)
} }
} }
} }

View file

@ -6,6 +6,7 @@ package ssa
import ( import (
"cmd/internal/obj" "cmd/internal/obj"
"cmd/internal/src"
"fmt" "fmt"
"log" "log"
"os" "os"
@ -129,7 +130,7 @@ func (f *Func) dumpFile(phaseName string) {
fi, err := os.Create(fname) fi, err := os.Create(fname)
if err != nil { if err != nil {
f.Config.Warnl(0, "Unable to create after-phase dump file %s", fname) f.Config.Warnl(src.NoXPos, "Unable to create after-phase dump file %s", fname)
return return
} }

View file

@ -6,6 +6,7 @@ package ssa
import ( import (
"cmd/internal/obj" "cmd/internal/obj"
"cmd/internal/src"
"crypto/sha1" "crypto/sha1"
"fmt" "fmt"
"os" "os"
@ -88,10 +89,10 @@ type Logger interface {
Log() bool Log() bool
// Fatal reports a compiler error and exits. // Fatal reports a compiler error and exits.
Fatalf(line int32, msg string, args ...interface{}) Fatalf(pos src.XPos, msg string, args ...interface{})
// Warnl writes compiler messages in the form expected by "errorcheck" tests // Warnl writes compiler messages in the form expected by "errorcheck" tests
Warnl(line int32, fmt_ string, args ...interface{}) Warnl(pos src.XPos, fmt_ string, args ...interface{})
// Forwards the Debug flags from gc // Forwards the Debug flags from gc
Debug_checknil() bool Debug_checknil() bool
@ -119,8 +120,8 @@ type Frontend interface {
SplitArray(LocalSlot) LocalSlot // array must be length 1 SplitArray(LocalSlot) LocalSlot // array must be length 1
SplitInt64(LocalSlot) (LocalSlot, LocalSlot) // returns (hi, lo) SplitInt64(LocalSlot) (LocalSlot, LocalSlot) // returns (hi, lo)
// Line returns a string describing the given line number. // Line returns a string describing the given position.
Line(int32) string Line(src.XPos) string
// AllocFrame assigns frame offsets to all live auto variables. // AllocFrame assigns frame offsets to all live auto variables.
AllocFrame(f *Func) AllocFrame(f *Func)
@ -269,7 +270,7 @@ func NewConfig(arch string, fe Frontend, ctxt *obj.Link, optimize bool) *Config
c.hasGReg = true c.hasGReg = true
c.noDuffDevice = true c.noDuffDevice = true
default: default:
fe.Fatalf(0, "arch %s not implemented", arch) fe.Fatalf(src.NoXPos, "arch %s not implemented", arch)
} }
c.ctxt = ctxt c.ctxt = ctxt
c.optimize = optimize c.optimize = optimize
@ -309,7 +310,7 @@ func NewConfig(arch string, fe Frontend, ctxt *obj.Link, optimize bool) *Config
if ev != "" { if ev != "" {
v, err := strconv.ParseInt(ev, 10, 64) v, err := strconv.ParseInt(ev, 10, 64)
if err != nil { if err != nil {
fe.Fatalf(0, "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 c.sparsePhiCutoff = uint64(v) // convert -1 to maxint, for never use sparse
} }
@ -331,19 +332,19 @@ func (c *Config) Ctxt() *obj.Link { return c.ctxt }
func (c *Config) NewFunc() *Func { func (c *Config) NewFunc() *Func {
// TODO(khr): should this function take name, type, etc. as arguments? // TODO(khr): should this function take name, type, etc. as arguments?
if c.curFunc != nil { if c.curFunc != nil {
c.Fatalf(0, "NewFunc called without previous Free") c.Fatalf(src.NoXPos, "NewFunc called without previous Free")
} }
f := &Func{Config: c, NamedValues: map[LocalSlot][]*Value{}} f := &Func{Config: c, NamedValues: map[LocalSlot][]*Value{}}
c.curFunc = f c.curFunc = f
return f return f
} }
func (c *Config) Logf(msg string, args ...interface{}) { c.fe.Logf(msg, args...) } 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) Log() bool { return c.fe.Log() }
func (c *Config) Fatalf(line int32, msg string, args ...interface{}) { c.fe.Fatalf(line, msg, args...) } func (c *Config) Fatalf(pos src.XPos, msg string, args ...interface{}) { c.fe.Fatalf(pos, msg, args...) }
func (c *Config) Warnl(line int32, msg string, args ...interface{}) { c.fe.Warnl(line, 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_checknil() bool { return c.fe.Debug_checknil() }
func (c *Config) Debug_wb() bool { return c.fe.Debug_wb() } func (c *Config) Debug_wb() bool { return c.fe.Debug_wb() }
func (c *Config) logDebugHashMatch(evname, name string) { func (c *Config) logDebugHashMatch(evname, name string) {
file := c.logfiles[evname] file := c.logfiles[evname]
@ -354,7 +355,7 @@ func (c *Config) logDebugHashMatch(evname, name string) {
var ok error var ok error
file, ok = os.Create(tmpfile) file, ok = os.Create(tmpfile)
if ok != nil { if ok != nil {
c.Fatalf(0, "Could not open hash-testing logfile %s", tmpfile) c.Fatalf(src.NoXPos, "Could not open hash-testing logfile %s", tmpfile)
} }
} }
c.logfiles[evname] = file c.logfiles[evname] = file

View file

@ -60,10 +60,10 @@ func critical(f *Func) {
// since we're iterating over len(f.Blocks) above, this forces // since we're iterating over len(f.Blocks) above, this forces
// the new blocks to be re-examined. // the new blocks to be re-examined.
d = f.NewBlock(BlockPlain) d = f.NewBlock(BlockPlain)
d.Line = p.Line d.Pos = p.Pos
blocks[argID] = d blocks[argID] = d
if f.pass.debug > 0 { if f.pass.debug > 0 {
f.Config.Warnl(p.Line, "split critical edge") f.Config.Warnl(p.Pos, "split critical edge")
} }
} else { } else {
reusedBlock = true reusedBlock = true
@ -72,9 +72,9 @@ func critical(f *Func) {
// no existing block, so allocate a new block // no existing block, so allocate a new block
// to place on the edge // to place on the edge
d = f.NewBlock(BlockPlain) d = f.NewBlock(BlockPlain)
d.Line = p.Line d.Pos = p.Pos
if f.pass.debug > 0 { if f.pass.debug > 0 {
f.Config.Warnl(p.Line, "split critical edge") f.Config.Warnl(p.Pos, "split critical edge")
} }
} }

View file

@ -4,6 +4,8 @@
package ssa package ssa
import "cmd/internal/src"
// dse does dead-store elimination on the Function. // dse does dead-store elimination on the Function.
// Dead stores are those which are unconditionally followed by // Dead stores are those which are unconditionally followed by
// another store to the same location, with no intervening load. // another store to the same location, with no intervening load.
@ -111,7 +113,7 @@ func dse(f *Func) {
if sz > 0x7fffffff { // work around sparseMap's int32 value type if sz > 0x7fffffff { // work around sparseMap's int32 value type
sz = 0x7fffffff sz = 0x7fffffff
} }
shadowed.set(v.Args[0].ID, int32(sz), 0) shadowed.set(v.Args[0].ID, int32(sz), src.NoXPos)
} }
} }
// walk to previous store // walk to previous store

View file

@ -35,8 +35,8 @@ func decomposeBuiltIn(f *Func) {
hiName, loName := f.Config.fe.SplitInt64(name) hiName, loName := f.Config.fe.SplitInt64(name)
newNames = append(newNames, hiName, loName) newNames = append(newNames, hiName, loName)
for _, v := range f.NamedValues[name] { for _, v := range f.NamedValues[name] {
hi := v.Block.NewValue1(v.Line, OpInt64Hi, elemType, v) hi := v.Block.NewValue1(v.Pos, OpInt64Hi, elemType, v)
lo := v.Block.NewValue1(v.Line, OpInt64Lo, f.Config.fe.TypeUInt32(), v) lo := v.Block.NewValue1(v.Pos, OpInt64Lo, f.Config.fe.TypeUInt32(), v)
f.NamedValues[hiName] = append(f.NamedValues[hiName], hi) f.NamedValues[hiName] = append(f.NamedValues[hiName], hi)
f.NamedValues[loName] = append(f.NamedValues[loName], lo) f.NamedValues[loName] = append(f.NamedValues[loName], lo)
} }
@ -51,8 +51,8 @@ func decomposeBuiltIn(f *Func) {
rName, iName := f.Config.fe.SplitComplex(name) rName, iName := f.Config.fe.SplitComplex(name)
newNames = append(newNames, rName, iName) newNames = append(newNames, rName, iName)
for _, v := range f.NamedValues[name] { for _, v := range f.NamedValues[name] {
r := v.Block.NewValue1(v.Line, OpComplexReal, elemType, v) r := v.Block.NewValue1(v.Pos, OpComplexReal, elemType, v)
i := v.Block.NewValue1(v.Line, OpComplexImag, elemType, v) i := v.Block.NewValue1(v.Pos, OpComplexImag, elemType, v)
f.NamedValues[rName] = append(f.NamedValues[rName], r) f.NamedValues[rName] = append(f.NamedValues[rName], r)
f.NamedValues[iName] = append(f.NamedValues[iName], i) f.NamedValues[iName] = append(f.NamedValues[iName], i)
} }
@ -63,8 +63,8 @@ func decomposeBuiltIn(f *Func) {
ptrName, lenName := f.Config.fe.SplitString(name) ptrName, lenName := f.Config.fe.SplitString(name)
newNames = append(newNames, ptrName, lenName) newNames = append(newNames, ptrName, lenName)
for _, v := range f.NamedValues[name] { for _, v := range f.NamedValues[name] {
ptr := v.Block.NewValue1(v.Line, OpStringPtr, ptrType, v) ptr := v.Block.NewValue1(v.Pos, OpStringPtr, ptrType, v)
len := v.Block.NewValue1(v.Line, OpStringLen, lenType, v) len := v.Block.NewValue1(v.Pos, OpStringLen, lenType, v)
f.NamedValues[ptrName] = append(f.NamedValues[ptrName], ptr) f.NamedValues[ptrName] = append(f.NamedValues[ptrName], ptr)
f.NamedValues[lenName] = append(f.NamedValues[lenName], len) f.NamedValues[lenName] = append(f.NamedValues[lenName], len)
} }
@ -75,9 +75,9 @@ func decomposeBuiltIn(f *Func) {
ptrName, lenName, capName := f.Config.fe.SplitSlice(name) ptrName, lenName, capName := f.Config.fe.SplitSlice(name)
newNames = append(newNames, ptrName, lenName, capName) newNames = append(newNames, ptrName, lenName, capName)
for _, v := range f.NamedValues[name] { for _, v := range f.NamedValues[name] {
ptr := v.Block.NewValue1(v.Line, OpSlicePtr, ptrType, v) ptr := v.Block.NewValue1(v.Pos, OpSlicePtr, ptrType, v)
len := v.Block.NewValue1(v.Line, OpSliceLen, lenType, v) len := v.Block.NewValue1(v.Pos, OpSliceLen, lenType, v)
cap := v.Block.NewValue1(v.Line, OpSliceCap, lenType, v) cap := v.Block.NewValue1(v.Pos, OpSliceCap, lenType, v)
f.NamedValues[ptrName] = append(f.NamedValues[ptrName], ptr) f.NamedValues[ptrName] = append(f.NamedValues[ptrName], ptr)
f.NamedValues[lenName] = append(f.NamedValues[lenName], len) f.NamedValues[lenName] = append(f.NamedValues[lenName], len)
f.NamedValues[capName] = append(f.NamedValues[capName], cap) f.NamedValues[capName] = append(f.NamedValues[capName], cap)
@ -88,8 +88,8 @@ func decomposeBuiltIn(f *Func) {
typeName, dataName := f.Config.fe.SplitInterface(name) typeName, dataName := f.Config.fe.SplitInterface(name)
newNames = append(newNames, typeName, dataName) newNames = append(newNames, typeName, dataName)
for _, v := range f.NamedValues[name] { for _, v := range f.NamedValues[name] {
typ := v.Block.NewValue1(v.Line, OpITab, ptrType, v) typ := v.Block.NewValue1(v.Pos, OpITab, ptrType, v)
data := v.Block.NewValue1(v.Line, OpIData, ptrType, v) data := v.Block.NewValue1(v.Pos, OpIData, ptrType, v)
f.NamedValues[typeName] = append(f.NamedValues[typeName], typ) f.NamedValues[typeName] = append(f.NamedValues[typeName], typ)
f.NamedValues[dataName] = append(f.NamedValues[dataName], data) f.NamedValues[dataName] = append(f.NamedValues[dataName], data)
} }
@ -133,11 +133,11 @@ func decomposeStringPhi(v *Value) {
ptrType := fe.TypeBytePtr() ptrType := fe.TypeBytePtr()
lenType := fe.TypeInt() lenType := fe.TypeInt()
ptr := v.Block.NewValue0(v.Line, OpPhi, ptrType) ptr := v.Block.NewValue0(v.Pos, OpPhi, ptrType)
len := v.Block.NewValue0(v.Line, OpPhi, lenType) len := v.Block.NewValue0(v.Pos, OpPhi, lenType)
for _, a := range v.Args { for _, a := range v.Args {
ptr.AddArg(a.Block.NewValue1(v.Line, OpStringPtr, ptrType, a)) ptr.AddArg(a.Block.NewValue1(v.Pos, OpStringPtr, ptrType, a))
len.AddArg(a.Block.NewValue1(v.Line, OpStringLen, lenType, a)) len.AddArg(a.Block.NewValue1(v.Pos, OpStringLen, lenType, a))
} }
v.reset(OpStringMake) v.reset(OpStringMake)
v.AddArg(ptr) v.AddArg(ptr)
@ -149,13 +149,13 @@ func decomposeSlicePhi(v *Value) {
ptrType := fe.TypeBytePtr() ptrType := fe.TypeBytePtr()
lenType := fe.TypeInt() lenType := fe.TypeInt()
ptr := v.Block.NewValue0(v.Line, OpPhi, ptrType) ptr := v.Block.NewValue0(v.Pos, OpPhi, ptrType)
len := v.Block.NewValue0(v.Line, OpPhi, lenType) len := v.Block.NewValue0(v.Pos, OpPhi, lenType)
cap := v.Block.NewValue0(v.Line, OpPhi, lenType) cap := v.Block.NewValue0(v.Pos, OpPhi, lenType)
for _, a := range v.Args { for _, a := range v.Args {
ptr.AddArg(a.Block.NewValue1(v.Line, OpSlicePtr, ptrType, a)) ptr.AddArg(a.Block.NewValue1(v.Pos, OpSlicePtr, ptrType, a))
len.AddArg(a.Block.NewValue1(v.Line, OpSliceLen, lenType, a)) len.AddArg(a.Block.NewValue1(v.Pos, OpSliceLen, lenType, a))
cap.AddArg(a.Block.NewValue1(v.Line, OpSliceCap, lenType, a)) cap.AddArg(a.Block.NewValue1(v.Pos, OpSliceCap, lenType, a))
} }
v.reset(OpSliceMake) v.reset(OpSliceMake)
v.AddArg(ptr) v.AddArg(ptr)
@ -172,11 +172,11 @@ func decomposeInt64Phi(v *Value) {
partType = fe.TypeUInt32() partType = fe.TypeUInt32()
} }
hi := v.Block.NewValue0(v.Line, OpPhi, partType) hi := v.Block.NewValue0(v.Pos, OpPhi, partType)
lo := v.Block.NewValue0(v.Line, OpPhi, fe.TypeUInt32()) lo := v.Block.NewValue0(v.Pos, OpPhi, fe.TypeUInt32())
for _, a := range v.Args { for _, a := range v.Args {
hi.AddArg(a.Block.NewValue1(v.Line, OpInt64Hi, partType, a)) hi.AddArg(a.Block.NewValue1(v.Pos, OpInt64Hi, partType, a))
lo.AddArg(a.Block.NewValue1(v.Line, OpInt64Lo, fe.TypeUInt32(), a)) lo.AddArg(a.Block.NewValue1(v.Pos, OpInt64Lo, fe.TypeUInt32(), a))
} }
v.reset(OpInt64Make) v.reset(OpInt64Make)
v.AddArg(hi) v.AddArg(hi)
@ -195,11 +195,11 @@ func decomposeComplexPhi(v *Value) {
v.Fatalf("decomposeComplexPhi: bad complex size %d", z) v.Fatalf("decomposeComplexPhi: bad complex size %d", z)
} }
real := v.Block.NewValue0(v.Line, OpPhi, partType) real := v.Block.NewValue0(v.Pos, OpPhi, partType)
imag := v.Block.NewValue0(v.Line, OpPhi, partType) imag := v.Block.NewValue0(v.Pos, OpPhi, partType)
for _, a := range v.Args { for _, a := range v.Args {
real.AddArg(a.Block.NewValue1(v.Line, OpComplexReal, partType, a)) real.AddArg(a.Block.NewValue1(v.Pos, OpComplexReal, partType, a))
imag.AddArg(a.Block.NewValue1(v.Line, OpComplexImag, partType, a)) imag.AddArg(a.Block.NewValue1(v.Pos, OpComplexImag, partType, a))
} }
v.reset(OpComplexMake) v.reset(OpComplexMake)
v.AddArg(real) v.AddArg(real)
@ -209,11 +209,11 @@ func decomposeComplexPhi(v *Value) {
func decomposeInterfacePhi(v *Value) { func decomposeInterfacePhi(v *Value) {
ptrType := v.Block.Func.Config.fe.TypeBytePtr() ptrType := v.Block.Func.Config.fe.TypeBytePtr()
itab := v.Block.NewValue0(v.Line, OpPhi, ptrType) itab := v.Block.NewValue0(v.Pos, OpPhi, ptrType)
data := v.Block.NewValue0(v.Line, OpPhi, ptrType) data := v.Block.NewValue0(v.Pos, OpPhi, ptrType)
for _, a := range v.Args { for _, a := range v.Args {
itab.AddArg(a.Block.NewValue1(v.Line, OpITab, ptrType, a)) itab.AddArg(a.Block.NewValue1(v.Pos, OpITab, ptrType, a))
data.AddArg(a.Block.NewValue1(v.Line, OpIData, ptrType, a)) data.AddArg(a.Block.NewValue1(v.Pos, OpIData, ptrType, a))
} }
v.reset(OpIMake) v.reset(OpIMake)
v.AddArg(itab) v.AddArg(itab)
@ -247,7 +247,7 @@ func decomposeUser(f *Func) {
} }
for _, v := range f.NamedValues[name] { for _, v := range f.NamedValues[name] {
for i := 0; i < n; i++ { for i := 0; i < n; i++ {
x := v.Block.NewValue1I(v.Line, OpStructSelect, t.FieldType(i), int64(i), v) x := v.Block.NewValue1I(v.Pos, OpStructSelect, t.FieldType(i), int64(i), v)
f.NamedValues[fnames[i]] = append(f.NamedValues[fnames[i]], x) f.NamedValues[fnames[i]] = append(f.NamedValues[fnames[i]], x)
} }
} }
@ -264,7 +264,7 @@ func decomposeUser(f *Func) {
} }
elemName := f.Config.fe.SplitArray(name) elemName := f.Config.fe.SplitArray(name)
for _, v := range f.NamedValues[name] { for _, v := range f.NamedValues[name] {
e := v.Block.NewValue1I(v.Line, OpArraySelect, t.ElemType(), 0, v) e := v.Block.NewValue1I(v.Pos, OpArraySelect, t.ElemType(), 0, v)
f.NamedValues[elemName] = append(f.NamedValues[elemName], e) f.NamedValues[elemName] = append(f.NamedValues[elemName], e)
} }
@ -293,11 +293,11 @@ func decomposeStructPhi(v *Value) {
n := t.NumFields() n := t.NumFields()
var fields [MaxStruct]*Value var fields [MaxStruct]*Value
for i := 0; i < n; i++ { for i := 0; i < n; i++ {
fields[i] = v.Block.NewValue0(v.Line, OpPhi, t.FieldType(i)) fields[i] = v.Block.NewValue0(v.Pos, OpPhi, t.FieldType(i))
} }
for _, a := range v.Args { for _, a := range v.Args {
for i := 0; i < n; i++ { for i := 0; i < n; i++ {
fields[i].AddArg(a.Block.NewValue1I(v.Line, OpStructSelect, t.FieldType(i), int64(i), a)) fields[i].AddArg(a.Block.NewValue1I(v.Pos, OpStructSelect, t.FieldType(i), int64(i), a))
} }
} }
v.reset(StructMakeOp(n)) v.reset(StructMakeOp(n))
@ -320,9 +320,9 @@ func decomposeArrayPhi(v *Value) {
if t.NumElem() != 1 { if t.NumElem() != 1 {
v.Fatalf("SSAable array must have no more than 1 element") v.Fatalf("SSAable array must have no more than 1 element")
} }
elem := v.Block.NewValue0(v.Line, OpPhi, t.ElemType()) elem := v.Block.NewValue0(v.Pos, OpPhi, t.ElemType())
for _, a := range v.Args { for _, a := range v.Args {
elem.AddArg(a.Block.NewValue1I(v.Line, OpArraySelect, t.ElemType(), 0, a)) elem.AddArg(a.Block.NewValue1I(v.Pos, OpArraySelect, t.ElemType(), 0, a))
} }
v.reset(OpArrayMake1) v.reset(OpArrayMake1)
v.AddArg(elem) v.AddArg(elem)

View file

@ -7,6 +7,7 @@ package ssa
import ( import (
"cmd/internal/obj" "cmd/internal/obj"
"cmd/internal/obj/x86" "cmd/internal/obj/x86"
"cmd/internal/src"
"testing" "testing"
) )
@ -62,7 +63,7 @@ func (d DummyFrontend) SplitStruct(s LocalSlot, i int) LocalSlot {
func (d DummyFrontend) SplitArray(s LocalSlot) LocalSlot { func (d DummyFrontend) SplitArray(s LocalSlot) LocalSlot {
return LocalSlot{s.N, s.Type.ElemType(), s.Off} return LocalSlot{s.N, s.Type.ElemType(), s.Off}
} }
func (DummyFrontend) Line(line int32) string { func (DummyFrontend) Line(_ src.XPos) string {
return "unknown.go:0" return "unknown.go:0"
} }
func (DummyFrontend) AllocFrame(f *Func) { func (DummyFrontend) AllocFrame(f *Func) {
@ -74,8 +75,8 @@ func (DummyFrontend) Syslook(s string) interface{} {
func (d DummyFrontend) Logf(msg string, args ...interface{}) { d.t.Logf(msg, args...) } func (d DummyFrontend) Logf(msg string, args ...interface{}) { d.t.Logf(msg, args...) }
func (d DummyFrontend) Log() bool { return true } func (d DummyFrontend) Log() bool { return true }
func (d DummyFrontend) Fatalf(line int32, msg string, args ...interface{}) { d.t.Fatalf(msg, args...) } func (d DummyFrontend) Fatalf(_ src.XPos, msg string, args ...interface{}) { d.t.Fatalf(msg, args...) }
func (d DummyFrontend) Warnl(line int32, msg string, args ...interface{}) { d.t.Logf(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_checknil() bool { return false }
func (d DummyFrontend) Debug_wb() bool { return false } func (d DummyFrontend) Debug_wb() bool { return false }

View file

@ -5,6 +5,7 @@
package ssa package ssa
import ( import (
"cmd/internal/src"
"fmt" "fmt"
"math" "math"
"strings" "strings"
@ -80,7 +81,7 @@ func (f *Func) retSparseSet(ss *sparseSet) {
} }
// newValue allocates a new Value with the given fields and places it at the end of b.Values. // 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, line int32) *Value { func (f *Func) newValue(op Op, t Type, b *Block, pos src.XPos) *Value {
var v *Value var v *Value
if f.freeValues != nil { if f.freeValues != nil {
v = f.freeValues v = f.freeValues
@ -97,7 +98,7 @@ func (f *Func) newValue(op Op, t Type, b *Block, line int32) *Value {
v.Op = op v.Op = op
v.Type = t v.Type = t
v.Block = b v.Block = b
v.Line = line v.Pos = pos
b.Values = append(b.Values, v) b.Values = append(b.Values, v)
return v return v
} }
@ -117,7 +118,7 @@ func (f *Func) LogStat(key string, args ...interface{}) {
if f.pass != nil { if f.pass != nil {
n = strings.Replace(f.pass.name, " ", "_", -1) n = strings.Replace(f.pass.name, " ", "_", -1)
} }
f.Config.Warnl(f.Entry.Line, "\t%s\t%s%s\t%s", n, key, value, f.Name) f.Config.Warnl(f.Entry.Pos, "\t%s\t%s%s\t%s", n, key, value, f.Name)
} }
// freeValue frees a value. It must no longer be referenced. // freeValue frees a value. It must no longer be referenced.
@ -187,30 +188,30 @@ func (f *Func) freeBlock(b *Block) {
} }
// NewValue0 returns a new value in the block with no arguments and zero aux values. // NewValue0 returns a new value in the block with no arguments and zero aux values.
func (b *Block) NewValue0(line int32, op Op, t Type) *Value { func (b *Block) NewValue0(pos src.XPos, op Op, t Type) *Value {
v := b.Func.newValue(op, t, b, line) v := b.Func.newValue(op, t, b, pos)
v.AuxInt = 0 v.AuxInt = 0
v.Args = v.argstorage[:0] v.Args = v.argstorage[:0]
return v return v
} }
// NewValue returns a new value in the block with no arguments and an auxint value. // 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 { func (b *Block) NewValue0I(pos src.XPos, op Op, t Type, auxint int64) *Value {
v := b.Func.newValue(op, t, b, line) v := b.Func.newValue(op, t, b, pos)
v.AuxInt = auxint v.AuxInt = auxint
v.Args = v.argstorage[:0] v.Args = v.argstorage[:0]
return v return v
} }
// NewValue returns a new value in the block with no arguments and an aux value. // 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 { func (b *Block) NewValue0A(pos src.XPos, op Op, t Type, aux interface{}) *Value {
if _, ok := aux.(int64); ok { if _, ok := aux.(int64); ok {
// Disallow int64 aux values. They should be in the auxint field instead. // 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 // Maybe we want to allow this at some point, but for now we disallow it
// to prevent errors like using NewValue1A instead of NewValue1I. // to prevent errors like using NewValue1A instead of NewValue1I.
b.Fatalf("aux field has int64 type op=%s type=%s aux=%v", op, t, aux) b.Fatalf("aux field has int64 type op=%s type=%s aux=%v", op, t, aux)
} }
v := b.Func.newValue(op, t, b, line) v := b.Func.newValue(op, t, b, pos)
v.AuxInt = 0 v.AuxInt = 0
v.Aux = aux v.Aux = aux
v.Args = v.argstorage[:0] v.Args = v.argstorage[:0]
@ -218,8 +219,8 @@ func (b *Block) NewValue0A(line int32, op Op, t Type, aux interface{}) *Value {
} }
// NewValue returns a new value in the block with no arguments and both an auxint and aux values. // NewValue returns a new value in the block with no arguments and both an auxint and aux values.
func (b *Block) NewValue0IA(line int32, 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, line) v := b.Func.newValue(op, t, b, pos)
v.AuxInt = auxint v.AuxInt = auxint
v.Aux = aux v.Aux = aux
v.Args = v.argstorage[:0] v.Args = v.argstorage[:0]
@ -227,8 +228,8 @@ func (b *Block) NewValue0IA(line int32, op Op, t Type, auxint int64, aux interfa
} }
// NewValue1 returns a new value in the block with one argument and zero aux values. // 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 { func (b *Block) NewValue1(pos src.XPos, op Op, t Type, arg *Value) *Value {
v := b.Func.newValue(op, t, b, line) v := b.Func.newValue(op, t, b, pos)
v.AuxInt = 0 v.AuxInt = 0
v.Args = v.argstorage[:1] v.Args = v.argstorage[:1]
v.argstorage[0] = arg v.argstorage[0] = arg
@ -237,8 +238,8 @@ func (b *Block) NewValue1(line int32, op Op, t Type, arg *Value) *Value {
} }
// NewValue1I returns a new value in the block with one argument and an auxint value. // 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 { func (b *Block) NewValue1I(pos src.XPos, op Op, t Type, auxint int64, arg *Value) *Value {
v := b.Func.newValue(op, t, b, line) v := b.Func.newValue(op, t, b, pos)
v.AuxInt = auxint v.AuxInt = auxint
v.Args = v.argstorage[:1] v.Args = v.argstorage[:1]
v.argstorage[0] = arg v.argstorage[0] = arg
@ -247,8 +248,8 @@ func (b *Block) NewValue1I(line int32, op Op, t Type, auxint int64, arg *Value)
} }
// NewValue1A returns a new value in the block with one argument and an aux value. // 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 { func (b *Block) NewValue1A(pos src.XPos, op Op, t Type, aux interface{}, arg *Value) *Value {
v := b.Func.newValue(op, t, b, line) v := b.Func.newValue(op, t, b, pos)
v.AuxInt = 0 v.AuxInt = 0
v.Aux = aux v.Aux = aux
v.Args = v.argstorage[:1] v.Args = v.argstorage[:1]
@ -258,8 +259,8 @@ func (b *Block) NewValue1A(line int32, op Op, t Type, aux interface{}, arg *Valu
} }
// NewValue1IA returns a new value in the block with one argument and both an auxint and aux values. // NewValue1IA returns a new value in the block with one argument and both an auxint and aux values.
func (b *Block) NewValue1IA(line int32, 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, line) v := b.Func.newValue(op, t, b, pos)
v.AuxInt = auxint v.AuxInt = auxint
v.Aux = aux v.Aux = aux
v.Args = v.argstorage[:1] v.Args = v.argstorage[:1]
@ -269,8 +270,8 @@ func (b *Block) NewValue1IA(line int32, op Op, t Type, auxint int64, aux interfa
} }
// NewValue2 returns a new value in the block with two arguments and zero aux values. // 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 { func (b *Block) NewValue2(pos src.XPos, op Op, t Type, arg0, arg1 *Value) *Value {
v := b.Func.newValue(op, t, b, line) v := b.Func.newValue(op, t, b, pos)
v.AuxInt = 0 v.AuxInt = 0
v.Args = v.argstorage[:2] v.Args = v.argstorage[:2]
v.argstorage[0] = arg0 v.argstorage[0] = arg0
@ -281,8 +282,8 @@ func (b *Block) NewValue2(line int32, op Op, t Type, arg0, arg1 *Value) *Value {
} }
// NewValue2I returns a new value in the block with two arguments and an auxint value. // NewValue2I returns a new value in the block with two arguments and an auxint value.
func (b *Block) NewValue2I(line int32, 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, line) v := b.Func.newValue(op, t, b, pos)
v.AuxInt = auxint v.AuxInt = auxint
v.Args = v.argstorage[:2] v.Args = v.argstorage[:2]
v.argstorage[0] = arg0 v.argstorage[0] = arg0
@ -293,8 +294,8 @@ func (b *Block) NewValue2I(line int32, op Op, t Type, auxint int64, arg0, arg1 *
} }
// NewValue3 returns a new value in the block with three arguments and zero aux values. // 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, 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, line) v := b.Func.newValue(op, t, b, pos)
v.AuxInt = 0 v.AuxInt = 0
v.Args = v.argstorage[:3] v.Args = v.argstorage[:3]
v.argstorage[0] = arg0 v.argstorage[0] = arg0
@ -307,8 +308,8 @@ func (b *Block) NewValue3(line int32, op Op, t Type, arg0, arg1, arg2 *Value) *V
} }
// NewValue3I returns a new value in the block with three arguments and an auxint value. // NewValue3I returns a new value in the block with three arguments and an auxint value.
func (b *Block) NewValue3I(line int32, 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, line) v := b.Func.newValue(op, t, b, pos)
v.AuxInt = auxint v.AuxInt = auxint
v.Args = v.argstorage[:3] v.Args = v.argstorage[:3]
v.argstorage[0] = arg0 v.argstorage[0] = arg0
@ -321,8 +322,8 @@ func (b *Block) NewValue3I(line int32, op Op, t Type, auxint int64, arg0, arg1,
} }
// NewValue4 returns a new value in the block with four arguments and zero aux values. // NewValue4 returns a new value in the block with four arguments and zero aux values.
func (b *Block) NewValue4(line int32, 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, line) v := b.Func.newValue(op, t, b, pos)
v.AuxInt = 0 v.AuxInt = 0
v.Args = []*Value{arg0, arg1, arg2, arg3} v.Args = []*Value{arg0, arg1, arg2, arg3}
arg0.Uses++ arg0.Uses++
@ -333,7 +334,7 @@ func (b *Block) NewValue4(line int32, op Op, t Type, arg0, arg1, arg2, arg3 *Val
} }
// constVal returns a constant value for c. // constVal returns a constant value for c.
func (f *Func) constVal(line int32, 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 { if f.constants == nil {
f.constants = make(map[int64][]*Value) f.constants = make(map[int64][]*Value)
} }
@ -348,9 +349,9 @@ func (f *Func) constVal(line int32, op Op, t Type, c int64, setAux bool) *Value
} }
var v *Value var v *Value
if setAux { if setAux {
v = f.Entry.NewValue0I(line, op, t, c) v = f.Entry.NewValue0I(pos, op, t, c)
} else { } else {
v = f.Entry.NewValue0(line, op, t) v = f.Entry.NewValue0(pos, op, t)
} }
f.constants[c] = append(vv, v) f.constants[c] = append(vv, v)
return v return v
@ -368,50 +369,50 @@ const (
) )
// ConstInt returns an int constant representing its argument. // ConstInt returns an int constant representing its argument.
func (f *Func) ConstBool(line int32, t Type, c bool) *Value { func (f *Func) ConstBool(pos src.XPos, t Type, c bool) *Value {
i := int64(0) i := int64(0)
if c { if c {
i = 1 i = 1
} }
return f.constVal(line, OpConstBool, t, i, true) return f.constVal(pos, OpConstBool, t, i, true)
} }
func (f *Func) ConstInt8(line int32, t Type, c int8) *Value { func (f *Func) ConstInt8(pos src.XPos, t Type, c int8) *Value {
return f.constVal(line, OpConst8, t, int64(c), true) return f.constVal(pos, OpConst8, t, int64(c), true)
} }
func (f *Func) ConstInt16(line int32, t Type, c int16) *Value { func (f *Func) ConstInt16(pos src.XPos, t Type, c int16) *Value {
return f.constVal(line, OpConst16, t, int64(c), true) return f.constVal(pos, OpConst16, t, int64(c), true)
} }
func (f *Func) ConstInt32(line int32, t Type, c int32) *Value { func (f *Func) ConstInt32(pos src.XPos, t Type, c int32) *Value {
return f.constVal(line, OpConst32, t, int64(c), true) return f.constVal(pos, OpConst32, t, int64(c), true)
} }
func (f *Func) ConstInt64(line int32, t Type, c int64) *Value { func (f *Func) ConstInt64(pos src.XPos, t Type, c int64) *Value {
return f.constVal(line, OpConst64, t, c, true) return f.constVal(pos, OpConst64, t, c, true)
} }
func (f *Func) ConstFloat32(line int32, t Type, c float64) *Value { func (f *Func) ConstFloat32(pos src.XPos, t Type, c float64) *Value {
return f.constVal(line, OpConst32F, t, int64(math.Float64bits(float64(float32(c)))), true) return f.constVal(pos, OpConst32F, t, int64(math.Float64bits(float64(float32(c)))), true)
} }
func (f *Func) ConstFloat64(line int32, t Type, c float64) *Value { func (f *Func) ConstFloat64(pos src.XPos, t Type, c float64) *Value {
return f.constVal(line, OpConst64F, t, int64(math.Float64bits(c)), true) return f.constVal(pos, OpConst64F, t, int64(math.Float64bits(c)), true)
} }
func (f *Func) ConstSlice(line int32, t Type) *Value { func (f *Func) ConstSlice(pos src.XPos, t Type) *Value {
return f.constVal(line, OpConstSlice, t, constSliceMagic, false) return f.constVal(pos, OpConstSlice, t, constSliceMagic, false)
} }
func (f *Func) ConstInterface(line int32, t Type) *Value { func (f *Func) ConstInterface(pos src.XPos, t Type) *Value {
return f.constVal(line, OpConstInterface, t, constInterfaceMagic, false) return f.constVal(pos, OpConstInterface, t, constInterfaceMagic, false)
} }
func (f *Func) ConstNil(line int32, t Type) *Value { func (f *Func) ConstNil(pos src.XPos, t Type) *Value {
return f.constVal(line, OpConstNil, t, constNilMagic, false) return f.constVal(pos, OpConstNil, t, constNilMagic, false)
} }
func (f *Func) ConstEmptyString(line int32, t Type) *Value { func (f *Func) ConstEmptyString(pos src.XPos, t Type) *Value {
v := f.constVal(line, OpConstString, t, constEmptyStringMagic, false) v := f.constVal(pos, OpConstString, t, constEmptyStringMagic, false)
v.Aux = "" v.Aux = ""
return v return v
} }
func (f *Func) Logf(msg string, args ...interface{}) { f.Config.Logf(msg, args...) } func (f *Func) Logf(msg string, args ...interface{}) { f.Config.Logf(msg, args...) }
func (f *Func) Log() bool { return f.Config.Log() } func (f *Func) Log() bool { return f.Config.Log() }
func (f *Func) Fatalf(msg string, args ...interface{}) { f.Config.Fatalf(f.Entry.Line, msg, args...) } func (f *Func) Fatalf(msg string, args ...interface{}) { f.Config.Fatalf(f.Entry.Pos, msg, args...) }
func (f *Func) Free() { func (f *Func) Free() {
// Clear cached CFG info. // Clear cached CFG info.

View file

@ -37,6 +37,7 @@ package ssa
// the parser can be used instead of Fun. // the parser can be used instead of Fun.
import ( import (
"cmd/internal/src"
"fmt" "fmt"
"reflect" "reflect"
"testing" "testing"
@ -154,7 +155,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.NewValue0IA(0, 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. // Connect the blocks together and specify control values.
@ -428,12 +429,12 @@ func TestConstCache(t *testing.T) {
Bloc("entry", Bloc("entry",
Valu("mem", OpInitMem, TypeMem, 0, nil), Valu("mem", OpInitMem, TypeMem, 0, nil),
Exit("mem"))) Exit("mem")))
v1 := f.f.ConstBool(0, TypeBool, false) v1 := f.f.ConstBool(src.NoXPos, TypeBool, false)
v2 := f.f.ConstBool(0, TypeBool, true) v2 := f.f.ConstBool(src.NoXPos, TypeBool, true)
f.f.freeValue(v1) f.f.freeValue(v1)
f.f.freeValue(v2) f.f.freeValue(v2)
v3 := f.f.ConstBool(0, TypeBool, false) v3 := f.f.ConstBool(src.NoXPos, TypeBool, false)
v4 := f.f.ConstBool(0, TypeBool, true) v4 := f.f.ConstBool(src.NoXPos, TypeBool, true)
if v3.AuxInt != 0 { if v3.AuxInt != 0 {
t.Errorf("expected %s to have auxint of 0\n", v3.LongString()) t.Errorf("expected %s to have auxint of 0\n", v3.LongString())
} }

View file

@ -1009,11 +1009,11 @@
&& mem.Op == OpStaticCall && mem.Op == OpStaticCall
&& isSameSym(mem.Aux, "runtime.newobject") && isSameSym(mem.Aux, "runtime.newobject")
&& c == config.ctxt.FixedFrameSize() + config.RegSize // offset of return value && c == config.ctxt.FixedFrameSize() + config.RegSize // offset of return value
&& warnRule(config.Debug_checknil() && int(v.Line) > 1, v, "removed nil check") && warnRule(config.Debug_checknil() && int(v.Pos) > 1, v, "removed nil check")
-> (Invalid) -> (Invalid)
(NilCheck (OffPtr (Load (OffPtr [c] (SP)) mem)) mem) (NilCheck (OffPtr (Load (OffPtr [c] (SP)) mem)) mem)
&& mem.Op == OpStaticCall && mem.Op == OpStaticCall
&& isSameSym(mem.Aux, "runtime.newobject") && isSameSym(mem.Aux, "runtime.newobject")
&& c == config.ctxt.FixedFrameSize() + config.RegSize // offset of return value && c == config.ctxt.FixedFrameSize() + config.RegSize // offset of return value
&& warnRule(config.Debug_checknil() && int(v.Line) > 1, v, "removed nil check") && warnRule(config.Debug_checknil() && int(v.Pos) > 1, v, "removed nil check")
-> (Invalid) -> (Invalid)

View file

@ -491,7 +491,7 @@ func genResult0(w io.Writer, arch arch, result string, alloc *int, top, move boo
} }
v = fmt.Sprintf("v%d", *alloc) v = fmt.Sprintf("v%d", *alloc)
*alloc++ *alloc++
fmt.Fprintf(w, "%s := b.NewValue0(v.Line, Op%s%s, %s)\n", v, oparch, op.name, typ) fmt.Fprintf(w, "%s := b.NewValue0(v.Pos, Op%s%s, %s)\n", v, oparch, op.name, typ)
if move && top { if move && top {
// Rewrite original into a copy // Rewrite original into a copy
fmt.Fprintf(w, "v.reset(OpCopy)\n") fmt.Fprintf(w, "v.reset(OpCopy)\n")

View file

@ -6,6 +6,7 @@ package ssa
import ( import (
"bytes" "bytes"
"cmd/internal/src"
"fmt" "fmt"
"html" "html"
"io" "io"
@ -20,7 +21,7 @@ type HTMLWriter struct {
func NewHTMLWriter(path string, logger Logger, funcname string) *HTMLWriter { func NewHTMLWriter(path string, logger Logger, funcname string) *HTMLWriter {
out, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644) out, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
if err != nil { if err != nil {
logger.Fatalf(0, "%v", err) logger.Fatalf(src.NoXPos, "%v", err)
} }
html := HTMLWriter{File: out, Logger: logger} html := HTMLWriter{File: out, Logger: logger}
html.start(funcname) html.start(funcname)
@ -328,13 +329,13 @@ func (w *HTMLWriter) WriteColumn(title string, html string) {
func (w *HTMLWriter) Printf(msg string, v ...interface{}) { func (w *HTMLWriter) Printf(msg string, v ...interface{}) {
if _, err := fmt.Fprintf(w.File, msg, v...); err != nil { if _, err := fmt.Fprintf(w.File, msg, v...); err != nil {
w.Fatalf(0, "%v", err) w.Fatalf(src.NoXPos, "%v", err)
} }
} }
func (w *HTMLWriter) WriteString(s string) { func (w *HTMLWriter) WriteString(s string) {
if _, err := w.File.WriteString(s); err != nil { if _, err := w.File.WriteString(s); err != nil {
w.Fatalf(0, "%v", err) w.Fatalf(src.NoXPos, "%v", err)
} }
} }

View file

@ -108,7 +108,7 @@ func describePredictionAgrees(b *Block, prediction BranchPrediction) string {
} }
func describeBranchPrediction(f *Func, b *Block, likely, not int8, prediction BranchPrediction) { func describeBranchPrediction(f *Func, b *Block, likely, not int8, prediction BranchPrediction) {
f.Config.Warnl(b.Line, "Branch prediction rule %s < %s%s", f.Config.Warnl(b.Pos, "Branch prediction rule %s < %s%s",
bllikelies[likely-blMin], bllikelies[not-blMin], describePredictionAgrees(b, prediction)) bllikelies[likely-blMin], bllikelies[not-blMin], describePredictionAgrees(b, prediction))
} }
@ -183,7 +183,7 @@ func likelyadjust(f *Func) {
noprediction = true noprediction = true
} }
if f.pass.debug > 0 && !noprediction { if f.pass.debug > 0 && !noprediction {
f.Config.Warnl(b.Line, "Branch prediction rule stay in loop%s", f.Config.Warnl(b.Pos, "Branch prediction rule stay in loop%s",
describePredictionAgrees(b, prediction)) describePredictionAgrees(b, prediction))
} }
@ -226,7 +226,7 @@ func likelyadjust(f *Func) {
} }
} }
if f.pass.debug > 2 { if f.pass.debug > 2 {
f.Config.Warnl(b.Line, "BP: Block %s, local=%s, certain=%s", b, bllikelies[local[b.ID]-blMin], bllikelies[certain[b.ID]-blMin]) f.Config.Warnl(b.Pos, "BP: Block %s, local=%s, certain=%s", b, bllikelies[local[b.ID]-blMin], bllikelies[certain[b.ID]-blMin])
} }
} }

View file

@ -139,9 +139,9 @@ nextb:
if f.pass.debug > 1 { if f.pass.debug > 1 {
if min.Op == OpConst64 { if min.Op == OpConst64 {
b.Func.Config.Warnl(b.Line, "Induction variable with minimum %d and increment %d", min.AuxInt, inc.AuxInt) b.Func.Config.Warnl(b.Pos, "Induction variable with minimum %d and increment %d", min.AuxInt, inc.AuxInt)
} else { } else {
b.Func.Config.Warnl(b.Line, "Induction variable with non-const minimum and increment %d", inc.AuxInt) b.Func.Config.Warnl(b.Pos, "Induction variable with non-const minimum and increment %d", inc.AuxInt)
} }
} }
@ -205,7 +205,7 @@ func removeBoundsChecks(f *Func, m map[*Value]indVar) {
if iv, has := m[ind]; has && sdom.isAncestorEq(iv.entry, b) && isNonNegative(iv.min) { if iv, has := m[ind]; has && sdom.isAncestorEq(iv.entry, b) && isNonNegative(iv.min) {
if v.Args[1] == iv.max { if v.Args[1] == iv.max {
if f.pass.debug > 0 { if f.pass.debug > 0 {
f.Config.Warnl(b.Line, "Found redundant %s", v.Op) f.Config.Warnl(b.Pos, "Found redundant %s", v.Op)
} }
goto simplify goto simplify
} }
@ -232,7 +232,7 @@ func removeBoundsChecks(f *Func, m map[*Value]indVar) {
if iv, has := m[ind]; has && sdom.isAncestorEq(iv.entry, b) && isNonNegative(iv.min) { if iv, has := m[ind]; has && sdom.isAncestorEq(iv.entry, b) && isNonNegative(iv.min) {
if v.Args[1].Op == OpSliceCap && iv.max.Op == OpSliceLen && v.Args[1].Args[0] == iv.max.Args[0] { if v.Args[1].Op == OpSliceCap && iv.max.Op == OpSliceLen && v.Args[1].Args[0] == iv.max.Args[0] {
if f.pass.debug > 0 { if f.pass.debug > 0 {
f.Config.Warnl(b.Line, "Found redundant %s (len promoted to cap)", v.Op) f.Config.Warnl(b.Pos, "Found redundant %s (len promoted to cap)", v.Op)
} }
goto simplify goto simplify
} }
@ -263,7 +263,7 @@ func removeBoundsChecks(f *Func, m map[*Value]indVar) {
if max := iv.max.AuxInt + add; 0 <= max && max <= limit { // handle overflow if max := iv.max.AuxInt + add; 0 <= max && max <= limit { // handle overflow
if f.pass.debug > 0 { if f.pass.debug > 0 {
f.Config.Warnl(b.Line, "Found redundant (%s ind %d), ind < %d", v.Op, v.Args[1].AuxInt, iv.max.AuxInt+add) f.Config.Warnl(b.Pos, "Found redundant (%s ind %d), ind < %d", v.Op, v.Args[1].AuxInt, iv.max.AuxInt+add)
} }
goto simplify goto simplify
} }

View file

@ -91,7 +91,7 @@ func insertLoopReschedChecks(f *Func) {
// It's possible that there is no memory state (no global/pointer loads/stores or calls) // It's possible that there is no memory state (no global/pointer loads/stores or calls)
if lastMems[f.Entry.ID] == nil { if lastMems[f.Entry.ID] == nil {
lastMems[f.Entry.ID] = f.Entry.NewValue0(f.Entry.Line, OpInitMem, TypeMem) lastMems[f.Entry.ID] = f.Entry.NewValue0(f.Entry.Pos, OpInitMem, TypeMem)
} }
memDefsAtBlockEnds := make([]*Value, f.NumBlocks()) // For each block, the mem def seen at its bottom. Could be from earlier block. memDefsAtBlockEnds := make([]*Value, f.NumBlocks()) // For each block, the mem def seen at its bottom. Could be from earlier block.
@ -109,7 +109,7 @@ func insertLoopReschedChecks(f *Func) {
} }
// Set up counter. There are no phis etc pre-existing for it. // Set up counter. There are no phis etc pre-existing for it.
counter0 := f.Entry.NewValue0I(f.Entry.Line, OpConst32, f.Config.fe.TypeInt32(), initialRescheduleCounterValue) counter0 := f.Entry.NewValue0I(f.Entry.Pos, OpConst32, f.Config.fe.TypeInt32(), initialRescheduleCounterValue)
ctrDefsAtBlockEnds := make([]*Value, f.NumBlocks()) // For each block, def visible at its end, if that def will be used. ctrDefsAtBlockEnds := make([]*Value, f.NumBlocks()) // For each block, def visible at its end, if that def will be used.
// There's a minor difference between memDefsAtBlockEnds and ctrDefsAtBlockEnds; // There's a minor difference between memDefsAtBlockEnds and ctrDefsAtBlockEnds;
@ -205,8 +205,8 @@ func insertLoopReschedChecks(f *Func) {
} }
} }
zero := f.Entry.NewValue0I(f.Entry.Line, OpConst32, f.Config.fe.TypeInt32(), 0) zero := f.Entry.NewValue0I(f.Entry.Pos, OpConst32, f.Config.fe.TypeInt32(), 0)
one := f.Entry.NewValue0I(f.Entry.Line, OpConst32, f.Config.fe.TypeInt32(), 1) one := f.Entry.NewValue0I(f.Entry.Pos, OpConst32, f.Config.fe.TypeInt32(), 1)
// Rewrite backedges to include reschedule checks. // Rewrite backedges to include reschedule checks.
for _, emc := range tofixBackedges { for _, emc := range tofixBackedges {
@ -258,14 +258,14 @@ func insertLoopReschedChecks(f *Func) {
test := f.NewBlock(BlockIf) test := f.NewBlock(BlockIf)
sched := f.NewBlock(BlockPlain) sched := f.NewBlock(BlockPlain)
test.Line = bb.Line test.Pos = bb.Pos
sched.Line = bb.Line sched.Pos = bb.Pos
// ctr1 := ctr0 - 1 // ctr1 := ctr0 - 1
// if ctr1 <= 0 { goto sched } // if ctr1 <= 0 { goto sched }
// goto header // goto header
ctr1 := test.NewValue2(bb.Line, OpSub32, f.Config.fe.TypeInt32(), ctr0, one) ctr1 := test.NewValue2(bb.Pos, OpSub32, f.Config.fe.TypeInt32(), ctr0, one)
cmp := test.NewValue2(bb.Line, OpLeq32, f.Config.fe.TypeBool(), ctr1, zero) cmp := test.NewValue2(bb.Pos, OpLeq32, f.Config.fe.TypeBool(), ctr1, zero)
test.SetControl(cmp) test.SetControl(cmp)
test.AddEdgeTo(sched) // if true test.AddEdgeTo(sched) // if true
// if false -- rewrite edge to header. // if false -- rewrite edge to header.
@ -282,7 +282,7 @@ func insertLoopReschedChecks(f *Func) {
// mem1 := call resched (mem0) // mem1 := call resched (mem0)
// goto header // goto header
resched := f.Config.fe.Syslook("goschedguarded") resched := f.Config.fe.Syslook("goschedguarded")
mem1 := sched.NewValue1A(bb.Line, OpStaticCall, TypeMem, resched, mem0) mem1 := sched.NewValue1A(bb.Pos, OpStaticCall, TypeMem, resched, mem0)
sched.AddEdgeTo(h) sched.AddEdgeTo(h)
headerMemPhi.AddArg(mem1) headerMemPhi.AddArg(mem1)
headerCtrPhi.AddArg(counter0) headerCtrPhi.AddArg(counter0)
@ -313,7 +313,7 @@ func insertLoopReschedChecks(f *Func) {
// newPhiFor inserts a new Phi function into b, // newPhiFor inserts a new Phi function into b,
// with all inputs set to v. // with all inputs set to v.
func newPhiFor(b *Block, v *Value) *Value { func newPhiFor(b *Block, v *Value) *Value {
phiV := b.NewValue0(b.Line, OpPhi, v.Type) phiV := b.NewValue0(b.Pos, OpPhi, v.Type)
for range b.Preds { for range b.Preds {
phiV.AddArg(v) phiV.AddArg(v)

View file

@ -101,8 +101,8 @@ func nilcheckelim(f *Func) {
// This is a redundant implicit nil check. // This is a redundant implicit nil check.
// Logging in the style of the former compiler -- and omit line 1, // Logging in the style of the former compiler -- and omit line 1,
// which is usually in generated code. // which is usually in generated code.
if f.Config.Debug_checknil() && v.Line > 1 { if f.Config.Debug_checknil() && v.Pos.Line() > 1 {
f.Config.Warnl(v.Line, "removed nil check") f.Config.Warnl(v.Pos, "removed nil check")
} }
v.reset(OpUnknown) v.reset(OpUnknown)
// TODO: f.freeValue(v) // TODO: f.freeValue(v)
@ -161,8 +161,8 @@ func nilcheckelim2(f *Func) {
for i := len(b.Values) - 1; i >= 0; i-- { for i := len(b.Values) - 1; i >= 0; i-- {
v := b.Values[i] v := b.Values[i]
if opcodeTable[v.Op].nilCheck && unnecessary.contains(v.Args[0].ID) { if opcodeTable[v.Op].nilCheck && unnecessary.contains(v.Args[0].ID) {
if f.Config.Debug_checknil() && int(v.Line) > 1 { if f.Config.Debug_checknil() && v.Pos.Line() > 1 {
f.Config.Warnl(v.Line, "removed nil check") f.Config.Warnl(v.Pos, "removed nil check")
} }
v.reset(OpUnknown) v.reset(OpUnknown)
continue continue

View file

@ -63,7 +63,7 @@ func phielimValue(v *Value) bool {
v.SetArgs1(w) v.SetArgs1(w)
f := v.Block.Func f := v.Block.Func
if f.pass.debug > 0 { if f.pass.debug > 0 {
f.Config.Warnl(v.Line, "eliminated phi") f.Config.Warnl(v.Pos, "eliminated phi")
} }
return true return true
} }

View file

@ -81,7 +81,7 @@ func phiopt(f *Func) {
v.reset(ops[v.Args[reverse].AuxInt]) v.reset(ops[v.Args[reverse].AuxInt])
v.AddArg(b0.Control) v.AddArg(b0.Control)
if f.pass.debug > 0 { if f.pass.debug > 0 {
f.Config.Warnl(b.Line, "converted OpPhi to %v", v.Op) f.Config.Warnl(b.Pos, "converted OpPhi to %v", v.Op)
} }
continue continue
} }
@ -97,7 +97,7 @@ func phiopt(f *Func) {
v.reset(OpOrB) v.reset(OpOrB)
v.SetArgs2(b0.Control, tmp) v.SetArgs2(b0.Control, tmp)
if f.pass.debug > 0 { if f.pass.debug > 0 {
f.Config.Warnl(b.Line, "converted OpPhi to %v", v.Op) f.Config.Warnl(b.Pos, "converted OpPhi to %v", v.Op)
} }
continue continue
} }
@ -113,7 +113,7 @@ func phiopt(f *Func) {
v.reset(OpAndB) v.reset(OpAndB)
v.SetArgs2(b0.Control, tmp) v.SetArgs2(b0.Control, tmp)
if f.pass.debug > 0 { if f.pass.debug > 0 {
f.Config.Warnl(b.Line, "converted OpPhi to %v", v.Op) f.Config.Warnl(b.Pos, "converted OpPhi to %v", v.Op)
} }
continue continue
} }
@ -163,12 +163,12 @@ func phioptint(v *Value, b0 *Block, reverse int) {
a := b0.Control a := b0.Control
if negate { if negate {
a = v.Block.NewValue1(v.Line, OpNot, a.Type, a) a = v.Block.NewValue1(v.Pos, OpNot, a.Type, a)
} }
v.AddArg(a) v.AddArg(a)
f := b0.Func f := b0.Func
if f.pass.debug > 0 { if f.pass.debug > 0 {
f.Config.Warnl(v.Block.Line, "converted OpPhi bool -> int%d", v.Type.Size()*8) f.Config.Warnl(v.Block.Pos, "converted OpPhi bool -> int%d", v.Type.Size()*8)
} }
} }

View file

@ -62,7 +62,7 @@ func (p stringFuncPrinter) endBlock(b *Block) {
func (p stringFuncPrinter) value(v *Value, live bool) { func (p stringFuncPrinter) value(v *Value, live bool) {
fmt.Fprint(p.w, " ") fmt.Fprint(p.w, " ")
//fmt.Fprint(p.w, v.Block.Func.Config.fe.Line(v.Line)) //fmt.Fprint(p.w, v.Block.Func.Config.fe.Pos(v.Pos))
//fmt.Fprint(p.w, ": ") //fmt.Fprint(p.w, ": ")
fmt.Fprint(p.w, v.LongString()) fmt.Fprint(p.w, v.LongString())
if !live { if !live {

View file

@ -301,7 +301,7 @@ func (ft *factsTable) update(parent *Block, v, w *Value, d domain, r relation) {
ft.limitStack = append(ft.limitStack, limitFact{v.ID, old}) ft.limitStack = append(ft.limitStack, limitFact{v.ID, old})
ft.limits[v.ID] = lim ft.limits[v.ID] = lim
if v.Block.Func.pass.debug > 2 { if v.Block.Func.pass.debug > 2 {
v.Block.Func.Config.Warnl(parent.Line, "parent=%s, new limits %s %s %s", parent, v, w, lim.String()) v.Block.Func.Config.Warnl(parent.Pos, "parent=%s, new limits %s %s %s", parent, v, w, lim.String())
} }
} }
} }
@ -600,7 +600,7 @@ func simplifyBlock(ft *factsTable, b *Block) branch {
v.reset(OpConst32) v.reset(OpConst32)
} }
if b.Func.pass.debug > 0 { if b.Func.pass.debug > 0 {
b.Func.Config.Warnl(v.Line, "Proved slicemask not needed") b.Func.Config.Warnl(v.Pos, "Proved slicemask not needed")
} }
v.AuxInt = -1 v.AuxInt = -1
} }
@ -615,9 +615,9 @@ func simplifyBlock(ft *factsTable, b *Block) branch {
if m == lt|gt { if m == lt|gt {
if b.Func.pass.debug > 0 { if b.Func.pass.debug > 0 {
if b.Func.pass.debug > 1 { if b.Func.pass.debug > 1 {
b.Func.Config.Warnl(b.Line, "Proved boolean %s (%s)", b.Control.Op, b.Control) b.Func.Config.Warnl(b.Pos, "Proved boolean %s (%s)", b.Control.Op, b.Control)
} else { } else {
b.Func.Config.Warnl(b.Line, "Proved boolean %s", b.Control.Op) b.Func.Config.Warnl(b.Pos, "Proved boolean %s", b.Control.Op)
} }
} }
return positive return positive
@ -625,9 +625,9 @@ func simplifyBlock(ft *factsTable, b *Block) branch {
if m == eq { if m == eq {
if b.Func.pass.debug > 0 { if b.Func.pass.debug > 0 {
if b.Func.pass.debug > 1 { if b.Func.pass.debug > 1 {
b.Func.Config.Warnl(b.Line, "Disproved boolean %s (%s)", b.Control.Op, b.Control) b.Func.Config.Warnl(b.Pos, "Disproved boolean %s (%s)", b.Control.Op, b.Control)
} else { } else {
b.Func.Config.Warnl(b.Line, "Disproved boolean %s", b.Control.Op) b.Func.Config.Warnl(b.Pos, "Disproved boolean %s", b.Control.Op)
} }
} }
return negative return negative
@ -656,9 +656,9 @@ func simplifyBlock(ft *factsTable, b *Block) branch {
if m != 0 && tr.r&m == m { if m != 0 && tr.r&m == m {
if b.Func.pass.debug > 0 { if b.Func.pass.debug > 0 {
if b.Func.pass.debug > 1 { if b.Func.pass.debug > 1 {
b.Func.Config.Warnl(b.Line, "Proved %s (%s)", c.Op, c) b.Func.Config.Warnl(b.Pos, "Proved %s (%s)", c.Op, c)
} else { } else {
b.Func.Config.Warnl(b.Line, "Proved %s", c.Op) b.Func.Config.Warnl(b.Pos, "Proved %s", c.Op)
} }
} }
return positive return positive
@ -666,9 +666,9 @@ func simplifyBlock(ft *factsTable, b *Block) branch {
if m != 0 && ((lt|eq|gt)^tr.r)&m == m { if m != 0 && ((lt|eq|gt)^tr.r)&m == m {
if b.Func.pass.debug > 0 { if b.Func.pass.debug > 0 {
if b.Func.pass.debug > 1 { if b.Func.pass.debug > 1 {
b.Func.Config.Warnl(b.Line, "Disproved %s (%s)", c.Op, c) b.Func.Config.Warnl(b.Pos, "Disproved %s (%s)", c.Op, c)
} else { } else {
b.Func.Config.Warnl(b.Line, "Disproved %s", c.Op) b.Func.Config.Warnl(b.Pos, "Disproved %s", c.Op)
} }
} }
return negative return negative
@ -685,9 +685,9 @@ func simplifyBlock(ft *factsTable, b *Block) branch {
if m != 0 && tr.r&m == m { if m != 0 && tr.r&m == m {
if b.Func.pass.debug > 0 { if b.Func.pass.debug > 0 {
if b.Func.pass.debug > 1 { if b.Func.pass.debug > 1 {
b.Func.Config.Warnl(b.Line, "Proved non-negative bounds %s (%s)", c.Op, c) b.Func.Config.Warnl(b.Pos, "Proved non-negative bounds %s (%s)", c.Op, c)
} else { } else {
b.Func.Config.Warnl(b.Line, "Proved non-negative bounds %s", c.Op) b.Func.Config.Warnl(b.Pos, "Proved non-negative bounds %s", c.Op)
} }
} }
return positive return positive

View file

@ -107,6 +107,7 @@ package ssa
import ( import (
"cmd/internal/obj" "cmd/internal/obj"
"cmd/internal/src"
"fmt" "fmt"
"unsafe" "unsafe"
) )
@ -180,9 +181,9 @@ func pickReg(r regMask) register {
} }
type use struct { type use struct {
dist int32 // distance from start of the block to a use of a value dist int32 // distance from start of the block to a use of a value
line int32 // line number of the use pos src.XPos // source position of the use
next *use // linked list of uses of a value in nondecreasing dist order next *use // linked list of uses of a value in nondecreasing dist order
} }
type valState struct { type valState struct {
@ -286,9 +287,9 @@ type endReg struct {
} }
type startReg struct { type startReg struct {
r register r register
vid ID // pre-regalloc value needed in this register vid ID // pre-regalloc value needed in this register
line int32 // line number of use of 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. // freeReg frees up register r. Any current user of r is kicked out.
@ -392,7 +393,7 @@ func (s *regAllocState) allocReg(mask regMask, v *Value) register {
m := s.compatRegs(v2.Type) &^ s.used &^ s.tmpused &^ (regMask(1) << r) m := s.compatRegs(v2.Type) &^ s.used &^ s.tmpused &^ (regMask(1) << r)
if m != 0 && !s.values[v2.ID].rematerializeable && countRegs(s.values[v2.ID].regs) == 1 { if m != 0 && !s.values[v2.ID].rematerializeable && countRegs(s.values[v2.ID].regs) == 1 {
r2 := pickReg(m) r2 := pickReg(m)
c := s.curBlock.NewValue1(v2.Line, OpCopy, v2.Type, s.regs[r].c) c := s.curBlock.NewValue1(v2.Pos, OpCopy, v2.Type, s.regs[r].c)
s.copies[c] = false s.copies[c] = false
if s.f.pass.debug > regDebug { if s.f.pass.debug > regDebug {
fmt.Printf("copy %s to %s : %s\n", v2, c, s.registers[r2].Name()) fmt.Printf("copy %s to %s : %s\n", v2, c, s.registers[r2].Name())
@ -410,7 +411,7 @@ func (s *regAllocState) allocReg(mask regMask, v *Value) register {
// allocated register is marked nospill so the assignment cannot be // allocated register is marked nospill so the assignment cannot be
// undone until the caller allows it by clearing nospill. Returns a // 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. // *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, line int32) *Value { func (s *regAllocState) allocValToReg(v *Value, mask regMask, nospill bool, pos src.XPos) *Value {
vi := &s.values[v.ID] vi := &s.values[v.ID]
// Check if v is already in a requested register. // Check if v is already in a requested register.
@ -436,7 +437,7 @@ func (s *regAllocState) allocValToReg(v *Value, mask regMask, nospill bool, line
if s.regs[r2].v != v { if s.regs[r2].v != v {
panic("bad register state") panic("bad register state")
} }
c = s.curBlock.NewValue1(line, OpCopy, v.Type, s.regs[r2].c) c = s.curBlock.NewValue1(pos, OpCopy, v.Type, s.regs[r2].c)
} else if v.rematerializeable() { } else if v.rematerializeable() {
// Rematerialize instead of loading from the spill location. // Rematerialize instead of loading from the spill location.
c = v.copyInto(s.curBlock) c = v.copyInto(s.curBlock)
@ -445,9 +446,9 @@ func (s *regAllocState) allocValToReg(v *Value, mask regMask, nospill bool, line
// Load v from its spill location. // Load v from its spill location.
case vi.spill != nil: case vi.spill != nil:
if s.f.pass.debug > logSpills { if s.f.pass.debug > logSpills {
s.f.Config.Warnl(vi.spill.Line, "load spill for %v from %v", v, vi.spill) s.f.Config.Warnl(vi.spill.Pos, "load spill for %v from %v", v, vi.spill)
} }
c = s.curBlock.NewValue1(line, OpLoadReg, v.Type, vi.spill) c = s.curBlock.NewValue1(pos, OpLoadReg, v.Type, vi.spill)
vi.spillUsed = true vi.spillUsed = true
default: default:
s.f.Fatalf("attempt to load unspilled value %v", v.LongString()) s.f.Fatalf("attempt to load unspilled value %v", v.LongString())
@ -554,7 +555,7 @@ func (s *regAllocState) init(f *Func) {
case "s390x": case "s390x":
// nothing to do, R10 & R11 already reserved // nothing to do, R10 & R11 already reserved
default: default:
s.f.Config.fe.Fatalf(0, "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 { if s.f.Config.nacl {
@ -617,7 +618,7 @@ func (s *regAllocState) init(f *Func) {
// Adds a use record for id at distance dist from the start of the block. // Adds a use record for id at distance dist from the start of the block.
// All calls to addUse must happen with nonincreasing dist. // All calls to addUse must happen with nonincreasing dist.
func (s *regAllocState) addUse(id ID, dist int32, line int32) { func (s *regAllocState) addUse(id ID, dist int32, pos src.XPos) {
r := s.freeUseRecords r := s.freeUseRecords
if r != nil { if r != nil {
s.freeUseRecords = r.next s.freeUseRecords = r.next
@ -625,7 +626,7 @@ func (s *regAllocState) addUse(id ID, dist int32, line int32) {
r = &use{} r = &use{}
} }
r.dist = dist r.dist = dist
r.line = line r.pos = pos
r.next = s.values[id].uses r.next = s.values[id].uses
s.values[id].uses = r s.values[id].uses = r
if r.next != nil && dist > r.next.dist { if r.next != nil && dist > r.next.dist {
@ -755,11 +756,11 @@ func (s *regAllocState) regalloc(f *Func) {
// Walk backwards through the block doing liveness analysis. // Walk backwards through the block doing liveness analysis.
liveSet.clear() liveSet.clear()
for _, e := range s.live[b.ID] { for _, e := range s.live[b.ID] {
s.addUse(e.ID, int32(len(b.Values))+e.dist, e.line) // pseudo-uses from beyond end of block s.addUse(e.ID, int32(len(b.Values))+e.dist, e.pos) // pseudo-uses from beyond end of block
liveSet.add(e.ID) liveSet.add(e.ID)
} }
if v := b.Control; v != nil && s.values[v.ID].needReg { if v := b.Control; v != nil && s.values[v.ID].needReg {
s.addUse(v.ID, int32(len(b.Values)), b.Line) // pseudo-use by control value s.addUse(v.ID, int32(len(b.Values)), b.Pos) // pseudo-use by control value
liveSet.add(v.ID) liveSet.add(v.ID)
} }
for i := len(b.Values) - 1; i >= 0; i-- { for i := len(b.Values) - 1; i >= 0; i-- {
@ -775,7 +776,7 @@ func (s *regAllocState) regalloc(f *Func) {
if !s.values[a.ID].needReg { if !s.values[a.ID].needReg {
continue continue
} }
s.addUse(a.ID, int32(i), v.Line) s.addUse(a.ID, int32(i), v.Pos)
liveSet.add(a.ID) liveSet.add(a.ID)
} }
} }
@ -901,7 +902,7 @@ func (s *regAllocState) regalloc(f *Func) {
m := s.compatRegs(a.Type) &^ s.used &^ phiUsed m := s.compatRegs(a.Type) &^ s.used &^ phiUsed
if m != 0 && !s.values[a.ID].rematerializeable && countRegs(s.values[a.ID].regs) == 1 { if m != 0 && !s.values[a.ID].rematerializeable && countRegs(s.values[a.ID].regs) == 1 {
r2 := pickReg(m) r2 := pickReg(m)
c := p.NewValue1(a.Line, OpCopy, a.Type, s.regs[r].c) c := p.NewValue1(a.Pos, OpCopy, a.Type, s.regs[r].c)
s.copies[c] = false s.copies[c] = false
if s.f.pass.debug > regDebug { if s.f.pass.debug > regDebug {
fmt.Printf("copy %s to %s : %s\n", a, c, s.registers[r2].Name()) fmt.Printf("copy %s to %s : %s\n", a, c, s.registers[r2].Name())
@ -950,7 +951,7 @@ func (s *regAllocState) regalloc(f *Func) {
// register-based phi // register-based phi
s.assignReg(r, v, v) s.assignReg(r, v, v)
// Spill the phi in case we need to restore it later. // Spill the phi in case we need to restore it later.
spill := b.NewValue1(v.Line, OpStoreReg, v.Type, v) spill := b.NewValue1(v.Pos, OpStoreReg, v.Type, v)
s.setOrig(spill, v) s.setOrig(spill, v)
s.values[v.ID].spill = spill s.values[v.ID].spill = spill
s.values[v.ID].spillUsed = false s.values[v.ID].spillUsed = false
@ -973,7 +974,7 @@ func (s *regAllocState) regalloc(f *Func) {
// specially during merge edge processing. // specially during merge edge processing.
continue continue
} }
regList = append(regList, startReg{r, v.ID, s.values[v.ID].uses.line}) regList = append(regList, startReg{r, v.ID, s.values[v.ID].uses.pos})
} }
s.startRegs[b.ID] = regList s.startRegs[b.ID] = regList
@ -1183,7 +1184,7 @@ func (s *regAllocState) regalloc(f *Func) {
mask &^= desired.avoid mask &^= desired.avoid
} }
} }
args[i.idx] = s.allocValToReg(args[i.idx], mask, true, v.Line) args[i.idx] = s.allocValToReg(args[i.idx], mask, true, v.Pos)
} }
// If the output clobbers the input register, make sure we have // If the output clobbers the input register, make sure we have
@ -1235,7 +1236,7 @@ func (s *regAllocState) regalloc(f *Func) {
for _, r := range dinfo[idx].out { for _, r := range dinfo[idx].out {
if r != noRegister && m>>r&1 != 0 { if r != noRegister && m>>r&1 != 0 {
m = regMask(1) << r m = regMask(1) << r
args[0] = s.allocValToReg(v.Args[0], m, true, v.Line) args[0] = s.allocValToReg(v.Args[0], m, true, v.Pos)
// Note: we update args[0] so the instruction will // Note: we update args[0] so the instruction will
// use the register copy we just made. // use the register copy we just made.
goto ok goto ok
@ -1246,7 +1247,7 @@ func (s *regAllocState) regalloc(f *Func) {
for _, r := range dinfo[idx].in[0] { for _, r := range dinfo[idx].in[0] {
if r != noRegister && m>>r&1 != 0 { if r != noRegister && m>>r&1 != 0 {
m = regMask(1) << r m = regMask(1) << r
c := s.allocValToReg(v.Args[0], m, true, v.Line) c := s.allocValToReg(v.Args[0], m, true, v.Pos)
s.copies[c] = false s.copies[c] = false
// Note: no update to args[0] so the instruction will // Note: no update to args[0] so the instruction will
// use the original copy. // use the original copy.
@ -1257,7 +1258,7 @@ func (s *regAllocState) regalloc(f *Func) {
for _, r := range dinfo[idx].in[1] { for _, r := range dinfo[idx].in[1] {
if r != noRegister && m>>r&1 != 0 { if r != noRegister && m>>r&1 != 0 {
m = regMask(1) << r m = regMask(1) << r
c := s.allocValToReg(v.Args[1], m, true, v.Line) c := s.allocValToReg(v.Args[1], m, true, v.Pos)
s.copies[c] = false s.copies[c] = false
args[0], args[1] = args[1], args[0] args[0], args[1] = args[1], args[0]
goto ok goto ok
@ -1269,7 +1270,7 @@ func (s *regAllocState) regalloc(f *Func) {
m &^= desired.avoid m &^= desired.avoid
} }
// Save input 0 to a new register so we can clobber it. // Save input 0 to a new register so we can clobber it.
c := s.allocValToReg(v.Args[0], m, true, v.Line) c := s.allocValToReg(v.Args[0], m, true, v.Pos)
s.copies[c] = false s.copies[c] = false
} }
@ -1383,7 +1384,7 @@ func (s *regAllocState) regalloc(f *Func) {
// It would be good to have both spill and restore inside the IF. // It would be good to have both spill and restore inside the IF.
issueSpill: issueSpill:
if s.values[v.ID].needReg { if s.values[v.ID].needReg {
spill := b.NewValue1(v.Line, OpStoreReg, v.Type, v) spill := b.NewValue1(v.Pos, OpStoreReg, v.Type, v)
s.setOrig(spill, v) s.setOrig(spill, v)
s.values[v.ID].spill = spill s.values[v.ID].spill = spill
s.values[v.ID].spillUsed = false s.values[v.ID].spillUsed = false
@ -1403,7 +1404,7 @@ func (s *regAllocState) regalloc(f *Func) {
// We assume that a control input can be passed in any // We assume that a control input can be passed in any
// type-compatible register. If this turns out not to be true, // type-compatible register. If this turns out not to be true,
// we'll need to introduce a regspec for a block's control value. // we'll need to introduce a regspec for a block's control value.
b.Control = s.allocValToReg(v, s.compatRegs(v.Type), false, b.Line) b.Control = s.allocValToReg(v, s.compatRegs(v.Type), false, b.Pos)
if b.Control != v { if b.Control != v {
v.Uses-- v.Uses--
b.Control.Uses++ b.Control.Uses++
@ -1458,7 +1459,7 @@ func (s *regAllocState) regalloc(f *Func) {
m &^= desired.avoid m &^= desired.avoid
} }
if m != 0 { if m != 0 {
s.allocValToReg(v, m, false, b.Line) s.allocValToReg(v, m, false, b.Pos)
} }
} }
} }
@ -1609,7 +1610,7 @@ func (s *regAllocState) regalloc(f *Func) {
vi := s.values[i] vi := s.values[i]
if vi.spillUsed { if vi.spillUsed {
if s.f.pass.debug > logSpills && vi.spill.Op != OpArg { if s.f.pass.debug > logSpills && vi.spill.Op != OpArg {
s.f.Config.Warnl(vi.spill.Line, "spilled value at %v remains", vi.spill) s.f.Config.Warnl(vi.spill.Pos, "spilled value at %v remains", vi.spill)
} }
continue continue
} }
@ -1707,7 +1708,7 @@ sinking:
} }
// If here, the register assignment was lost down at least one exit and it can't be sunk // If here, the register assignment was lost down at least one exit and it can't be sunk
if s.f.pass.debug > moveSpills { if s.f.pass.debug > moveSpills {
s.f.Config.Warnl(e.Line, "lost register assignment for spill %v in %v at exit %v to %v", s.f.Config.Warnl(e.Pos, "lost register assignment for spill %v in %v at exit %v to %v",
vsp, b, p, d) vsp, b, p, d)
} }
nSpillsChanged++ nSpillsChanged++
@ -1743,10 +1744,10 @@ sinking:
d := loop.exits[i] d := loop.exits[i]
vspnew := vsp // reuse original for first sunk spill, saves tracking down and renaming uses vspnew := vsp // reuse original for first sunk spill, saves tracking down and renaming uses
if !first { // any sunk spills after first must make a copy if !first { // any sunk spills after first must make a copy
vspnew = d.NewValue1(e.Line, OpStoreReg, e.Type, e) vspnew = d.NewValue1(e.Pos, OpStoreReg, e.Type, e)
f.setHome(vspnew, f.getHome(vsp.ID)) // copy stack home f.setHome(vspnew, f.getHome(vsp.ID)) // copy stack home
if s.f.pass.debug > moveSpills { if s.f.pass.debug > moveSpills {
s.f.Config.Warnl(e.Line, "copied spill %v in %v for %v to %v in %v", s.f.Config.Warnl(e.Pos, "copied spill %v in %v for %v to %v in %v",
vsp, b, e, vspnew, d) vsp, b, e, vspnew, d)
} }
} else { } else {
@ -1754,7 +1755,7 @@ sinking:
vspnew.Block = d vspnew.Block = d
d.Values = append(d.Values, vspnew) d.Values = append(d.Values, vspnew)
if s.f.pass.debug > moveSpills { if s.f.pass.debug > moveSpills {
s.f.Config.Warnl(e.Line, "moved spill %v in %v for %v to %v in %v", s.f.Config.Warnl(e.Pos, "moved spill %v in %v for %v to %v in %v",
vsp, b, e, vspnew, d) vsp, b, e, vspnew, d)
} }
} }
@ -1878,17 +1879,17 @@ type edgeState struct {
} }
type contentRecord struct { type contentRecord struct {
vid ID // pre-regalloc value vid ID // pre-regalloc value
c *Value // cached value c *Value // cached value
final bool // this is a satisfied destination final bool // this is a satisfied destination
line int32 // line number of use of the value pos src.XPos // source position of use of the value
} }
type dstRecord struct { type dstRecord struct {
loc Location // register or stack slot loc Location // register or stack slot
vid ID // pre-regalloc value it should contain vid ID // pre-regalloc value it should contain
splice **Value // place to store reference to the generating instruction splice **Value // place to store reference to the generating instruction
line int32 // line number of use of this location pos src.XPos // source position of use of this location
} }
// setup initializes the edge state for shuffling. // setup initializes the edge state for shuffling.
@ -1911,19 +1912,19 @@ func (e *edgeState) setup(idx int, srcReg []endReg, dstReg []startReg, stacklive
// Live registers can be sources. // Live registers can be sources.
for _, x := range srcReg { for _, x := range srcReg {
e.set(&e.s.registers[x.r], x.v.ID, x.c, false, 0) // don't care the line number 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. // So can all of the spill locations.
for _, spillID := range stacklive { for _, spillID := range stacklive {
v := e.s.orig[spillID] v := e.s.orig[spillID]
spill := e.s.values[v.ID].spill spill := e.s.values[v.ID].spill
e.set(e.s.f.getHome(spillID), v.ID, spill, false, 0) // don't care the line number 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. // Figure out all the destinations we need.
dsts := e.destinations[:0] dsts := e.destinations[:0]
for _, x := range dstReg { for _, x := range dstReg {
dsts = append(dsts, dstRecord{&e.s.registers[x.r], x.vid, nil, x.line}) dsts = append(dsts, dstRecord{&e.s.registers[x.r], x.vid, nil, x.pos})
} }
// Phis need their args to end up in a specific location. // Phis need their args to end up in a specific location.
for _, v := range e.b.Values { for _, v := range e.b.Values {
@ -1934,7 +1935,7 @@ func (e *edgeState) setup(idx int, srcReg []endReg, dstReg []startReg, stacklive
if loc == nil { if loc == nil {
continue continue
} }
dsts = append(dsts, dstRecord{loc, v.Args[idx].ID, &v.Args[idx], v.Line}) dsts = append(dsts, dstRecord{loc, v.Args[idx].ID, &v.Args[idx], v.Pos})
} }
e.destinations = dsts e.destinations = dsts
@ -1959,7 +1960,7 @@ func (e *edgeState) process() {
for len(dsts) > 0 { for len(dsts) > 0 {
i := 0 i := 0
for _, d := range dsts { for _, d := range dsts {
if !e.processDest(d.loc, d.vid, d.splice, d.line) { if !e.processDest(d.loc, d.vid, d.splice, d.pos) {
// Failed - save for next iteration. // Failed - save for next iteration.
dsts[i] = d dsts[i] = d
i++ i++
@ -2006,22 +2007,22 @@ func (e *edgeState) process() {
fmt.Printf("breaking cycle with v%d in %s:%s\n", vid, loc.Name(), c) fmt.Printf("breaking cycle with v%d in %s:%s\n", vid, loc.Name(), c)
} }
if _, isReg := loc.(*Register); isReg { if _, isReg := loc.(*Register); isReg {
c = e.p.NewValue1(d.line, OpCopy, c.Type, c) c = e.p.NewValue1(d.pos, OpCopy, c.Type, c)
} else { } else {
e.s.lateSpillUse(vid) e.s.lateSpillUse(vid)
c = e.p.NewValue1(d.line, OpLoadReg, c.Type, c) c = e.p.NewValue1(d.pos, OpLoadReg, c.Type, c)
} }
e.set(r, vid, c, false, d.line) e.set(r, vid, c, false, d.pos)
} }
} }
// processDest generates code to put value vid into location loc. Returns true // processDest generates code to put value vid into location loc. Returns true
// if progress was made. // if progress was made.
func (e *edgeState) processDest(loc Location, vid ID, splice **Value, line int32) bool { func (e *edgeState) processDest(loc Location, vid ID, splice **Value, pos src.XPos) bool {
occupant := e.contents[loc] occupant := e.contents[loc]
if occupant.vid == vid { if occupant.vid == vid {
// Value is already in the correct place. // Value is already in the correct place.
e.contents[loc] = contentRecord{vid, occupant.c, true, line} e.contents[loc] = contentRecord{vid, occupant.c, true, pos}
if splice != nil { if splice != nil {
(*splice).Uses-- (*splice).Uses--
*splice = occupant.c *splice = occupant.c
@ -2087,25 +2088,25 @@ func (e *edgeState) processDest(loc Location, vid ID, splice **Value, line int32
e.erase(loc) // see pre-clobber comment below e.erase(loc) // see pre-clobber comment below
r := e.findRegFor(v.Type) r := e.findRegFor(v.Type)
x = v.copyInto(e.p) x = v.copyInto(e.p)
e.set(r, vid, x, false, line) e.set(r, vid, x, false, pos)
// Make sure we spill with the size of the slot, not the // Make sure we spill with the size of the slot, not the
// size of x (which might be wider due to our dropping // size of x (which might be wider due to our dropping
// of narrowing conversions). // of narrowing conversions).
x = e.p.NewValue1(line, OpStoreReg, loc.(LocalSlot).Type, x) x = e.p.NewValue1(pos, OpStoreReg, loc.(LocalSlot).Type, x)
} }
} else { } else {
// Emit move from src to dst. // Emit move from src to dst.
_, srcReg := src.(*Register) _, srcReg := src.(*Register)
if srcReg { if srcReg {
if dstReg { if dstReg {
x = e.p.NewValue1(line, OpCopy, c.Type, c) x = e.p.NewValue1(pos, OpCopy, c.Type, c)
} else { } else {
x = e.p.NewValue1(line, OpStoreReg, loc.(LocalSlot).Type, c) x = e.p.NewValue1(pos, OpStoreReg, loc.(LocalSlot).Type, c)
} }
} else { } else {
if dstReg { if dstReg {
e.s.lateSpillUse(vid) e.s.lateSpillUse(vid)
x = e.p.NewValue1(line, OpLoadReg, c.Type, c) x = e.p.NewValue1(pos, OpLoadReg, c.Type, c)
} else { } else {
// mem->mem. Use temp register. // mem->mem. Use temp register.
@ -2123,13 +2124,13 @@ func (e *edgeState) processDest(loc Location, vid ID, splice **Value, line int32
r := e.findRegFor(c.Type) r := e.findRegFor(c.Type)
e.s.lateSpillUse(vid) e.s.lateSpillUse(vid)
t := e.p.NewValue1(line, OpLoadReg, c.Type, c) t := e.p.NewValue1(pos, OpLoadReg, c.Type, c)
e.set(r, vid, t, false, line) e.set(r, vid, t, false, pos)
x = e.p.NewValue1(line, OpStoreReg, loc.(LocalSlot).Type, t) x = e.p.NewValue1(pos, OpStoreReg, loc.(LocalSlot).Type, t)
} }
} }
} }
e.set(loc, vid, x, true, line) e.set(loc, vid, x, true, pos)
if splice != nil { if splice != nil {
(*splice).Uses-- (*splice).Uses--
*splice = x *splice = x
@ -2139,10 +2140,10 @@ func (e *edgeState) processDest(loc Location, vid ID, splice **Value, line int32
} }
// set changes the contents of location loc to hold the given value and its cached representative. // 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, line int32) { func (e *edgeState) set(loc Location, vid ID, c *Value, final bool, pos src.XPos) {
e.s.f.setHome(c, loc) e.s.f.setHome(c, loc)
e.erase(loc) e.erase(loc)
e.contents[loc] = contentRecord{vid, c, final, line} e.contents[loc] = contentRecord{vid, c, final, pos}
a := e.cache[vid] a := e.cache[vid]
if len(a) == 0 { if len(a) == 0 {
e.cachedVals = append(e.cachedVals, vid) e.cachedVals = append(e.cachedVals, vid)
@ -2181,7 +2182,7 @@ func (e *edgeState) erase(loc Location) {
// Add a destination to move this value back into place. // Add a destination to move this value back into place.
// Make sure it gets added to the tail of the destination queue // Make sure it gets added to the tail of the destination queue
// so we make progress on other moves first. // so we make progress on other moves first.
e.extra = append(e.extra, dstRecord{loc, cr.vid, nil, cr.line}) e.extra = append(e.extra, dstRecord{loc, cr.vid, nil, cr.pos})
} }
// Remove c from the list of cached values. // Remove c from the list of cached values.
@ -2250,8 +2251,8 @@ func (e *edgeState) findRegFor(typ Type) Location {
a := e.cache[vid] a := e.cache[vid]
for _, c := range a { for _, c := range a {
if r, ok := e.s.f.getHome(c.ID).(*Register); ok && m>>uint(r.num)&1 != 0 { if r, ok := e.s.f.getHome(c.ID).(*Register); ok && m>>uint(r.num)&1 != 0 {
x := e.p.NewValue1(c.Line, OpStoreReg, c.Type, c) x := e.p.NewValue1(c.Pos, OpStoreReg, c.Type, c)
e.set(t, vid, x, false, c.Line) e.set(t, vid, x, false, c.Pos)
if e.s.f.pass.debug > regDebug { if e.s.f.pass.debug > regDebug {
fmt.Printf(" SPILL %s->%s %s\n", r.Name(), t.Name(), x.LongString()) fmt.Printf(" SPILL %s->%s %s\n", r.Name(), t.Name(), x.LongString())
} }
@ -2290,9 +2291,9 @@ func (v *Value) rematerializeable() bool {
} }
type liveInfo struct { type liveInfo struct {
ID ID // ID of value ID ID // ID of value
dist int32 // # of instructions before next use dist int32 // # of instructions before next use
line int32 // line number of next use pos src.XPos // source position of next use
} }
// dblock contains information about desired & avoid registers at the end of a block. // dblock contains information about desired & avoid registers at the end of a block.
@ -2341,12 +2342,12 @@ func (s *regAllocState) computeLive() {
// to beginning-of-block distance. // to beginning-of-block distance.
live.clear() live.clear()
for _, e := range s.live[b.ID] { for _, e := range s.live[b.ID] {
live.set(e.ID, e.dist+int32(len(b.Values)), e.line) live.set(e.ID, e.dist+int32(len(b.Values)), e.pos)
} }
// Mark control value as live // Mark control value as live
if b.Control != nil && s.values[b.Control.ID].needReg { if b.Control != nil && s.values[b.Control.ID].needReg {
live.set(b.Control.ID, int32(len(b.Values)), b.Line) live.set(b.Control.ID, int32(len(b.Values)), b.Pos)
} }
// Propagate backwards to the start of the block // Propagate backwards to the start of the block
@ -2368,7 +2369,7 @@ func (s *regAllocState) computeLive() {
} }
for _, a := range v.Args { for _, a := range v.Args {
if s.values[a.ID].needReg { if s.values[a.ID].needReg {
live.set(a.ID, int32(i), v.Line) live.set(a.ID, int32(i), v.Pos)
} }
} }
} }
@ -2427,7 +2428,7 @@ func (s *regAllocState) computeLive() {
// Start t off with the previously known live values at the end of p. // Start t off with the previously known live values at the end of p.
t.clear() t.clear()
for _, e := range s.live[p.ID] { for _, e := range s.live[p.ID] {
t.set(e.ID, e.dist, e.line) t.set(e.ID, e.dist, e.pos)
} }
update := false update := false
@ -2446,7 +2447,7 @@ func (s *regAllocState) computeLive() {
id := v.Args[i].ID id := v.Args[i].ID
if s.values[id].needReg && (!t.contains(id) || delta < t.get(id)) { if s.values[id].needReg && (!t.contains(id) || delta < t.get(id)) {
update = true update = true
t.set(id, delta, v.Line) t.set(id, delta, v.Pos)
} }
} }

View file

@ -489,7 +489,7 @@ func noteRule(s string) bool {
// cond is true and the rule is fired. // cond is true and the rule is fired.
func warnRule(cond bool, v *Value, s string) bool { func warnRule(cond bool, v *Value, s string) bool {
if cond { if cond {
v.Block.Func.Config.Warnl(v.Line, s) v.Block.Func.Config.Warnl(v.Pos, s)
} }
return true return true
} }

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -123,12 +123,12 @@ func rewriteValuedec_OpLoad(v *Value, config *Config) bool {
break break
} }
v.reset(OpComplexMake) v.reset(OpComplexMake)
v0 := b.NewValue0(v.Line, OpLoad, config.fe.TypeFloat32()) v0 := b.NewValue0(v.Pos, OpLoad, config.fe.TypeFloat32())
v0.AddArg(ptr) v0.AddArg(ptr)
v0.AddArg(mem) v0.AddArg(mem)
v.AddArg(v0) v.AddArg(v0)
v1 := b.NewValue0(v.Line, OpLoad, config.fe.TypeFloat32()) v1 := b.NewValue0(v.Pos, OpLoad, config.fe.TypeFloat32())
v2 := b.NewValue0(v.Line, OpOffPtr, config.fe.TypeFloat32().PtrTo()) v2 := b.NewValue0(v.Pos, OpOffPtr, config.fe.TypeFloat32().PtrTo())
v2.AuxInt = 4 v2.AuxInt = 4
v2.AddArg(ptr) v2.AddArg(ptr)
v1.AddArg(v2) v1.AddArg(v2)
@ -147,12 +147,12 @@ func rewriteValuedec_OpLoad(v *Value, config *Config) bool {
break break
} }
v.reset(OpComplexMake) v.reset(OpComplexMake)
v0 := b.NewValue0(v.Line, OpLoad, config.fe.TypeFloat64()) v0 := b.NewValue0(v.Pos, OpLoad, config.fe.TypeFloat64())
v0.AddArg(ptr) v0.AddArg(ptr)
v0.AddArg(mem) v0.AddArg(mem)
v.AddArg(v0) v.AddArg(v0)
v1 := b.NewValue0(v.Line, OpLoad, config.fe.TypeFloat64()) v1 := b.NewValue0(v.Pos, OpLoad, config.fe.TypeFloat64())
v2 := b.NewValue0(v.Line, OpOffPtr, config.fe.TypeFloat64().PtrTo()) v2 := b.NewValue0(v.Pos, OpOffPtr, config.fe.TypeFloat64().PtrTo())
v2.AuxInt = 8 v2.AuxInt = 8
v2.AddArg(ptr) v2.AddArg(ptr)
v1.AddArg(v2) v1.AddArg(v2)
@ -171,12 +171,12 @@ func rewriteValuedec_OpLoad(v *Value, config *Config) bool {
break break
} }
v.reset(OpStringMake) v.reset(OpStringMake)
v0 := b.NewValue0(v.Line, OpLoad, config.fe.TypeBytePtr()) v0 := b.NewValue0(v.Pos, OpLoad, config.fe.TypeBytePtr())
v0.AddArg(ptr) v0.AddArg(ptr)
v0.AddArg(mem) v0.AddArg(mem)
v.AddArg(v0) v.AddArg(v0)
v1 := b.NewValue0(v.Line, OpLoad, config.fe.TypeInt()) v1 := b.NewValue0(v.Pos, OpLoad, config.fe.TypeInt())
v2 := b.NewValue0(v.Line, OpOffPtr, config.fe.TypeInt().PtrTo()) v2 := b.NewValue0(v.Pos, OpOffPtr, config.fe.TypeInt().PtrTo())
v2.AuxInt = config.PtrSize v2.AuxInt = config.PtrSize
v2.AddArg(ptr) v2.AddArg(ptr)
v1.AddArg(v2) v1.AddArg(v2)
@ -195,19 +195,19 @@ func rewriteValuedec_OpLoad(v *Value, config *Config) bool {
break break
} }
v.reset(OpSliceMake) v.reset(OpSliceMake)
v0 := b.NewValue0(v.Line, OpLoad, t.ElemType().PtrTo()) v0 := b.NewValue0(v.Pos, OpLoad, t.ElemType().PtrTo())
v0.AddArg(ptr) v0.AddArg(ptr)
v0.AddArg(mem) v0.AddArg(mem)
v.AddArg(v0) v.AddArg(v0)
v1 := b.NewValue0(v.Line, OpLoad, config.fe.TypeInt()) v1 := b.NewValue0(v.Pos, OpLoad, config.fe.TypeInt())
v2 := b.NewValue0(v.Line, OpOffPtr, config.fe.TypeInt().PtrTo()) v2 := b.NewValue0(v.Pos, OpOffPtr, config.fe.TypeInt().PtrTo())
v2.AuxInt = config.PtrSize v2.AuxInt = config.PtrSize
v2.AddArg(ptr) v2.AddArg(ptr)
v1.AddArg(v2) v1.AddArg(v2)
v1.AddArg(mem) v1.AddArg(mem)
v.AddArg(v1) v.AddArg(v1)
v3 := b.NewValue0(v.Line, OpLoad, config.fe.TypeInt()) v3 := b.NewValue0(v.Pos, OpLoad, config.fe.TypeInt())
v4 := b.NewValue0(v.Line, OpOffPtr, config.fe.TypeInt().PtrTo()) v4 := b.NewValue0(v.Pos, OpOffPtr, config.fe.TypeInt().PtrTo())
v4.AuxInt = 2 * config.PtrSize v4.AuxInt = 2 * config.PtrSize
v4.AddArg(ptr) v4.AddArg(ptr)
v3.AddArg(v4) v3.AddArg(v4)
@ -226,12 +226,12 @@ func rewriteValuedec_OpLoad(v *Value, config *Config) bool {
break break
} }
v.reset(OpIMake) v.reset(OpIMake)
v0 := b.NewValue0(v.Line, OpLoad, config.fe.TypeBytePtr()) v0 := b.NewValue0(v.Pos, OpLoad, config.fe.TypeBytePtr())
v0.AddArg(ptr) v0.AddArg(ptr)
v0.AddArg(mem) v0.AddArg(mem)
v.AddArg(v0) v.AddArg(v0)
v1 := b.NewValue0(v.Line, OpLoad, config.fe.TypeBytePtr()) v1 := b.NewValue0(v.Pos, OpLoad, config.fe.TypeBytePtr())
v2 := b.NewValue0(v.Line, OpOffPtr, config.fe.TypeBytePtr().PtrTo()) v2 := b.NewValue0(v.Pos, OpOffPtr, config.fe.TypeBytePtr().PtrTo())
v2.AuxInt = config.PtrSize v2.AuxInt = config.PtrSize
v2.AddArg(ptr) v2.AddArg(ptr)
v1.AddArg(v2) v1.AddArg(v2)
@ -318,12 +318,12 @@ func rewriteValuedec_OpStore(v *Value, config *Config) bool {
mem := v.Args[2] mem := v.Args[2]
v.reset(OpStore) v.reset(OpStore)
v.AuxInt = 4 v.AuxInt = 4
v0 := b.NewValue0(v.Line, OpOffPtr, config.fe.TypeFloat32().PtrTo()) v0 := b.NewValue0(v.Pos, OpOffPtr, config.fe.TypeFloat32().PtrTo())
v0.AuxInt = 4 v0.AuxInt = 4
v0.AddArg(dst) v0.AddArg(dst)
v.AddArg(v0) v.AddArg(v0)
v.AddArg(imag) v.AddArg(imag)
v1 := b.NewValue0(v.Line, OpStore, TypeMem) v1 := b.NewValue0(v.Pos, OpStore, TypeMem)
v1.AuxInt = 4 v1.AuxInt = 4
v1.AddArg(dst) v1.AddArg(dst)
v1.AddArg(real) v1.AddArg(real)
@ -348,12 +348,12 @@ func rewriteValuedec_OpStore(v *Value, config *Config) bool {
mem := v.Args[2] mem := v.Args[2]
v.reset(OpStore) v.reset(OpStore)
v.AuxInt = 8 v.AuxInt = 8
v0 := b.NewValue0(v.Line, OpOffPtr, config.fe.TypeFloat64().PtrTo()) v0 := b.NewValue0(v.Pos, OpOffPtr, config.fe.TypeFloat64().PtrTo())
v0.AuxInt = 8 v0.AuxInt = 8
v0.AddArg(dst) v0.AddArg(dst)
v.AddArg(v0) v.AddArg(v0)
v.AddArg(imag) v.AddArg(imag)
v1 := b.NewValue0(v.Line, OpStore, TypeMem) v1 := b.NewValue0(v.Pos, OpStore, TypeMem)
v1.AuxInt = 8 v1.AuxInt = 8
v1.AddArg(dst) v1.AddArg(dst)
v1.AddArg(real) v1.AddArg(real)
@ -378,12 +378,12 @@ func rewriteValuedec_OpStore(v *Value, config *Config) bool {
mem := v.Args[2] mem := v.Args[2]
v.reset(OpStore) v.reset(OpStore)
v.AuxInt = config.PtrSize v.AuxInt = config.PtrSize
v0 := b.NewValue0(v.Line, OpOffPtr, config.fe.TypeInt().PtrTo()) v0 := b.NewValue0(v.Pos, OpOffPtr, config.fe.TypeInt().PtrTo())
v0.AuxInt = config.PtrSize v0.AuxInt = config.PtrSize
v0.AddArg(dst) v0.AddArg(dst)
v.AddArg(v0) v.AddArg(v0)
v.AddArg(len) v.AddArg(len)
v1 := b.NewValue0(v.Line, OpStore, TypeMem) v1 := b.NewValue0(v.Pos, OpStore, TypeMem)
v1.AuxInt = config.PtrSize v1.AuxInt = config.PtrSize
v1.AddArg(dst) v1.AddArg(dst)
v1.AddArg(ptr) v1.AddArg(ptr)
@ -409,19 +409,19 @@ func rewriteValuedec_OpStore(v *Value, config *Config) bool {
mem := v.Args[2] mem := v.Args[2]
v.reset(OpStore) v.reset(OpStore)
v.AuxInt = config.PtrSize v.AuxInt = config.PtrSize
v0 := b.NewValue0(v.Line, OpOffPtr, config.fe.TypeInt().PtrTo()) v0 := b.NewValue0(v.Pos, OpOffPtr, config.fe.TypeInt().PtrTo())
v0.AuxInt = 2 * config.PtrSize v0.AuxInt = 2 * config.PtrSize
v0.AddArg(dst) v0.AddArg(dst)
v.AddArg(v0) v.AddArg(v0)
v.AddArg(cap) v.AddArg(cap)
v1 := b.NewValue0(v.Line, OpStore, TypeMem) v1 := b.NewValue0(v.Pos, OpStore, TypeMem)
v1.AuxInt = config.PtrSize v1.AuxInt = config.PtrSize
v2 := b.NewValue0(v.Line, OpOffPtr, config.fe.TypeInt().PtrTo()) v2 := b.NewValue0(v.Pos, OpOffPtr, config.fe.TypeInt().PtrTo())
v2.AuxInt = config.PtrSize v2.AuxInt = config.PtrSize
v2.AddArg(dst) v2.AddArg(dst)
v1.AddArg(v2) v1.AddArg(v2)
v1.AddArg(len) v1.AddArg(len)
v3 := b.NewValue0(v.Line, OpStore, TypeMem) v3 := b.NewValue0(v.Pos, OpStore, TypeMem)
v3.AuxInt = config.PtrSize v3.AuxInt = config.PtrSize
v3.AddArg(dst) v3.AddArg(dst)
v3.AddArg(ptr) v3.AddArg(ptr)
@ -447,12 +447,12 @@ func rewriteValuedec_OpStore(v *Value, config *Config) bool {
mem := v.Args[2] mem := v.Args[2]
v.reset(OpStore) v.reset(OpStore)
v.AuxInt = config.PtrSize v.AuxInt = config.PtrSize
v0 := b.NewValue0(v.Line, OpOffPtr, config.fe.TypeBytePtr().PtrTo()) v0 := b.NewValue0(v.Pos, OpOffPtr, config.fe.TypeBytePtr().PtrTo())
v0.AuxInt = config.PtrSize v0.AuxInt = config.PtrSize
v0.AddArg(dst) v0.AddArg(dst)
v.AddArg(v0) v.AddArg(v0)
v.AddArg(data) v.AddArg(data)
v1 := b.NewValue0(v.Line, OpStore, TypeMem) v1 := b.NewValue0(v.Pos, OpStore, TypeMem)
v1.AuxInt = config.PtrSize v1.AuxInt = config.PtrSize
v1.AddArg(dst) v1.AddArg(dst)
v1.AddArg(itab) v1.AddArg(itab)

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -46,8 +46,8 @@ func (h ValHeap) Less(i, j int) bool {
if c := sx - sy; c != 0 { if c := sx - sy; c != 0 {
return c > 0 // higher score comes later. return c > 0 // higher score comes later.
} }
if x.Line != y.Line { // Favor in-order line stepping if x.Pos != y.Pos { // Favor in-order line stepping
return x.Line > y.Line return x.Pos.After(y.Pos)
} }
if x.Op != OpPhi { if x.Op != OpPhi {
if c := len(x.Args) - len(y.Args); c != 0 { if c := len(x.Args) - len(y.Args); c != 0 {

View file

@ -17,8 +17,8 @@ func shortcircuit(f *Func) {
// x = phi(a, ...) // x = phi(a, ...)
// //
// We can replace the "a" in the phi with the constant true. // We can replace the "a" in the phi with the constant true.
ct := f.ConstBool(f.Entry.Line, f.Config.fe.TypeBool(), true) ct := f.ConstBool(f.Entry.Pos, f.Config.fe.TypeBool(), true)
cf := f.ConstBool(f.Entry.Line, f.Config.fe.TypeBool(), false) cf := f.ConstBool(f.Entry.Pos, f.Config.fe.TypeBool(), false)
for _, b := range f.Blocks { for _, b := range f.Blocks {
for _, v := range b.Values { for _, v := range b.Values {
if v.Op != OpPhi { if v.Op != OpPhi {

View file

@ -22,8 +22,8 @@ func TestSizeof(t *testing.T) {
_32bit uintptr // size on 32bit platforms _32bit uintptr // size on 32bit platforms
_64bit uintptr // size on 64bit platforms _64bit uintptr // size on 64bit platforms
}{ }{
{Value{}, 68, 112}, {Value{}, 72, 120},
{Block{}, 148, 288}, {Block{}, 152, 288},
} }
for _, tt := range tests { for _, tt := range tests {

View file

@ -4,13 +4,15 @@
package ssa package ssa
import "cmd/internal/src"
// from http://research.swtch.com/sparse // from http://research.swtch.com/sparse
// in turn, from Briggs and Torczon // in turn, from Briggs and Torczon
type sparseEntry struct { type sparseEntry struct {
key ID key ID
val int32 val int32
aux int32 aux src.XPos
} }
type sparseMap struct { type sparseMap struct {
@ -43,7 +45,7 @@ func (s *sparseMap) get(k ID) int32 {
return -1 return -1
} }
func (s *sparseMap) set(k ID, v, a int32) { func (s *sparseMap) set(k ID, v int32, a src.XPos) {
i := s.sparse[k] i := s.sparse[k]
if i < int32(len(s.dense)) && s.dense[i].key == k { if i < int32(len(s.dense)) && s.dense[i].key == k {
s.dense[i].val = v s.dense[i].val = v
@ -64,7 +66,7 @@ func (s *sparseMap) setBit(k ID, v uint) {
s.dense[i].val |= 1 << v s.dense[i].val |= 1 << v
return return
} }
s.dense = append(s.dense, sparseEntry{k, 1 << v, 0}) s.dense = append(s.dense, sparseEntry{k, 1 << v, src.NoXPos})
s.sparse[k] = int32(len(s.dense)) - 1 s.sparse[k] = int32(len(s.dense)) - 1
} }

View file

@ -6,7 +6,10 @@
package ssa package ssa
import "fmt" import (
"cmd/internal/src"
"fmt"
)
type stackAllocState struct { type stackAllocState struct {
f *Func f *Func
@ -37,7 +40,7 @@ func newStackAllocState(f *Func) *stackAllocState {
return new(stackAllocState) return new(stackAllocState)
} }
if s.f != nil { if s.f != nil {
f.Config.Fatalf(0, "newStackAllocState called without previous free") f.Config.Fatalf(src.NoXPos, "newStackAllocState called without previous free")
} }
return s return s
} }

View file

@ -5,6 +5,7 @@
package ssa package ssa
import ( import (
"cmd/internal/src"
"fmt" "fmt"
"math" "math"
) )
@ -36,8 +37,8 @@ type Value struct {
// Containing basic block // Containing basic block
Block *Block Block *Block
// Source line number // Source position
Line int32 Pos src.XPos
// Use count. Each appearance in Value.Args and Block.Control counts once. // Use count. Each appearance in Value.Args and Block.Control counts once.
Uses int32 Uses int32
@ -217,7 +218,7 @@ func (v *Value) reset(op Op) {
// copyInto makes a new value identical to v and adds it to the end of b. // copyInto makes a new value identical to v and adds it to the end of b.
func (v *Value) copyInto(b *Block) *Value { func (v *Value) copyInto(b *Block) *Value {
c := b.NewValue0(v.Line, v.Op, v.Type) c := b.NewValue0(v.Pos, v.Op, v.Type)
c.Aux = v.Aux c.Aux = v.Aux
c.AuxInt = v.AuxInt c.AuxInt = v.AuxInt
c.AddArgs(v.Args...) c.AddArgs(v.Args...)
@ -232,7 +233,7 @@ func (v *Value) copyInto(b *Block) *Value {
func (v *Value) Logf(msg string, args ...interface{}) { v.Block.Logf(msg, args...) } func (v *Value) Logf(msg string, args ...interface{}) { v.Block.Logf(msg, args...) }
func (v *Value) Log() bool { return v.Block.Log() } func (v *Value) Log() bool { return v.Block.Log() }
func (v *Value) Fatalf(msg string, args ...interface{}) { func (v *Value) Fatalf(msg string, args ...interface{}) {
v.Block.Func.Config.Fatalf(v.Line, msg, args...) v.Block.Func.Config.Fatalf(v.Pos, msg, args...)
} }
// isGenericIntConst returns whether v is a generic integer constant. // isGenericIntConst returns whether v is a generic integer constant.

View file

@ -4,7 +4,10 @@
package ssa package ssa
import "fmt" import (
"cmd/internal/src"
"fmt"
)
// writebarrier expands write barrier ops (StoreWB, MoveWB, etc.) into // writebarrier expands write barrier ops (StoreWB, MoveWB, etc.) into
// branches and runtime calls, like // branches and runtime calls, like
@ -53,7 +56,7 @@ func writebarrier(f *Func) {
if wbaddr == nil { if wbaddr == nil {
// initalize global values for write barrier test and calls // initalize global values for write barrier test and calls
// find SB and SP values in entry block // find SB and SP values in entry block
initln := f.Entry.Line initln := f.Entry.Pos
for _, v := range f.Entry.Values { for _, v := range f.Entry.Values {
if v.Op == OpSB { if v.Op == OpSB {
sb = v sb = v
@ -78,7 +81,7 @@ func writebarrier(f *Func) {
defer f.retSparseSet(wbs) defer f.retSparseSet(wbs)
} }
line := v.Line pos := v.Pos
// there may be a sequence of WB stores in the current block. find them. // there may be a sequence of WB stores in the current block. find them.
storeWBs = storeWBs[:0] storeWBs = storeWBs[:0]
@ -124,9 +127,9 @@ func writebarrier(f *Func) {
bThen := f.NewBlock(BlockPlain) bThen := f.NewBlock(BlockPlain)
bElse := f.NewBlock(BlockPlain) bElse := f.NewBlock(BlockPlain)
bEnd := f.NewBlock(b.Kind) bEnd := f.NewBlock(b.Kind)
bThen.Line = line bThen.Pos = pos
bElse.Line = line bElse.Pos = pos
bEnd.Line = line bEnd.Pos = pos
// set up control flow for end block // set up control flow for end block
bEnd.SetControl(b.Control) bEnd.SetControl(b.Control)
@ -138,9 +141,9 @@ func writebarrier(f *Func) {
// set up control flow for write barrier test // set up control flow for write barrier test
// load word, test word, avoiding partial register write from load byte. // load word, test word, avoiding partial register write from load byte.
flag := b.NewValue2(line, OpLoad, f.Config.fe.TypeUInt32(), wbaddr, mem) flag := b.NewValue2(pos, OpLoad, f.Config.fe.TypeUInt32(), wbaddr, mem)
const0 := f.ConstInt32(line, f.Config.fe.TypeUInt32(), 0) const0 := f.ConstInt32(pos, f.Config.fe.TypeUInt32(), 0)
flag = b.NewValue2(line, OpNeq32, f.Config.fe.TypeBool(), flag, const0) flag = b.NewValue2(pos, OpNeq32, f.Config.fe.TypeBool(), flag, const0)
b.Kind = BlockIf b.Kind = BlockIf
b.SetControl(flag) b.SetControl(flag)
b.Likely = BranchUnlikely b.Likely = BranchUnlikely
@ -175,13 +178,13 @@ func writebarrier(f *Func) {
} }
// then block: emit write barrier call // then block: emit write barrier call
memThen = wbcall(line, bThen, fn, typ, ptr, val, memThen, sp, sb, w.Op == OpMoveWBVolatile) memThen = wbcall(pos, bThen, fn, typ, ptr, val, memThen, sp, sb, w.Op == OpMoveWBVolatile)
// else block: normal store // else block: normal store
if op == OpZero { if op == OpZero {
memElse = bElse.NewValue2I(line, op, TypeMem, siz, ptr, memElse) memElse = bElse.NewValue2I(pos, op, TypeMem, siz, ptr, memElse)
} else { } else {
memElse = bElse.NewValue3I(line, op, TypeMem, siz, ptr, val, memElse) memElse = bElse.NewValue3I(pos, op, TypeMem, siz, ptr, val, memElse)
} }
} }
@ -226,7 +229,7 @@ func writebarrier(f *Func) {
} }
if f.Config.fe.Debug_wb() { if f.Config.fe.Debug_wb() {
f.Config.Warnl(line, "write barrier") f.Config.Warnl(pos, "write barrier")
} }
break valueLoop break valueLoop
@ -237,7 +240,7 @@ func writebarrier(f *Func) {
// wbcall emits write barrier runtime call in b, returns memory. // wbcall emits write barrier runtime call in b, returns memory.
// if valIsVolatile, it moves val into temp space before making the call. // if valIsVolatile, it moves val into temp space before making the call.
func wbcall(line int32, 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 config := b.Func.Config
var tmp GCNode var tmp GCNode
@ -248,10 +251,10 @@ func wbcall(line int32, b *Block, fn interface{}, typ interface{}, ptr, val, mem
t := val.Type.ElemType() t := val.Type.ElemType()
tmp = config.fe.Auto(t) tmp = config.fe.Auto(t)
aux := &AutoSymbol{Typ: t, Node: tmp} aux := &AutoSymbol{Typ: t, Node: tmp}
mem = b.NewValue1A(line, OpVarDef, TypeMem, tmp, mem) mem = b.NewValue1A(pos, OpVarDef, TypeMem, tmp, mem)
tmpaddr := b.NewValue1A(line, OpAddr, t.PtrTo(), aux, sp) tmpaddr := b.NewValue1A(pos, OpAddr, t.PtrTo(), aux, sp)
siz := MakeSizeAndAlign(t.Size(), t.Alignment()).Int64() siz := MakeSizeAndAlign(t.Size(), t.Alignment()).Int64()
mem = b.NewValue3I(line, OpMove, TypeMem, siz, tmpaddr, val, mem) mem = b.NewValue3I(pos, OpMove, TypeMem, siz, tmpaddr, val, mem)
val = tmpaddr val = tmpaddr
} }
@ -259,32 +262,32 @@ func wbcall(line int32, b *Block, fn interface{}, typ interface{}, ptr, val, mem
off := config.ctxt.FixedFrameSize() off := config.ctxt.FixedFrameSize()
if typ != nil { // for typedmemmove if typ != nil { // for typedmemmove
taddr := b.NewValue1A(line, OpAddr, config.fe.TypeUintptr(), typ, sb) taddr := b.NewValue1A(pos, OpAddr, config.fe.TypeUintptr(), typ, sb)
off = round(off, taddr.Type.Alignment()) off = round(off, taddr.Type.Alignment())
arg := b.NewValue1I(line, OpOffPtr, taddr.Type.PtrTo(), off, sp) arg := b.NewValue1I(pos, OpOffPtr, taddr.Type.PtrTo(), off, sp)
mem = b.NewValue3I(line, OpStore, TypeMem, ptr.Type.Size(), arg, taddr, mem) mem = b.NewValue3I(pos, OpStore, TypeMem, ptr.Type.Size(), arg, taddr, mem)
off += taddr.Type.Size() off += taddr.Type.Size()
} }
off = round(off, ptr.Type.Alignment()) off = round(off, ptr.Type.Alignment())
arg := b.NewValue1I(line, OpOffPtr, ptr.Type.PtrTo(), off, sp) arg := b.NewValue1I(pos, OpOffPtr, ptr.Type.PtrTo(), off, sp)
mem = b.NewValue3I(line, OpStore, TypeMem, ptr.Type.Size(), arg, ptr, mem) mem = b.NewValue3I(pos, OpStore, TypeMem, ptr.Type.Size(), arg, ptr, mem)
off += ptr.Type.Size() off += ptr.Type.Size()
if val != nil { if val != nil {
off = round(off, val.Type.Alignment()) off = round(off, val.Type.Alignment())
arg = b.NewValue1I(line, OpOffPtr, val.Type.PtrTo(), off, sp) arg = b.NewValue1I(pos, OpOffPtr, val.Type.PtrTo(), off, sp)
mem = b.NewValue3I(line, OpStore, TypeMem, val.Type.Size(), arg, val, mem) mem = b.NewValue3I(pos, OpStore, TypeMem, val.Type.Size(), arg, val, mem)
off += val.Type.Size() off += val.Type.Size()
} }
off = round(off, config.PtrSize) off = round(off, config.PtrSize)
// issue call // issue call
mem = b.NewValue1A(line, OpStaticCall, TypeMem, fn, mem) mem = b.NewValue1A(pos, OpStaticCall, TypeMem, fn, mem)
mem.AuxInt = off - config.ctxt.FixedFrameSize() mem.AuxInt = off - config.ctxt.FixedFrameSize()
if valIsVolatile { if valIsVolatile {
mem = b.NewValue1A(line, OpVarKill, TypeMem, tmp, mem) // mark temp dead mem = b.NewValue1A(pos, OpVarKill, TypeMem, tmp, mem) // mark temp dead
} }
return mem return mem

View file

@ -14,7 +14,7 @@ func TestDump(t *testing.T) {
t.Skip("skipping test in short mode") t.Skip("skipping test in short mode")
} }
ast, err := ParseFile(*src, nil, nil, 0) ast, err := ParseFile(*src_, nil, nil, 0)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }

View file

@ -4,11 +4,13 @@
package syntax package syntax
import "cmd/internal/src"
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Nodes // Nodes
type Node interface { type Node interface {
Line() uint32 Pos() src.Pos
aNode() aNode()
init(p *parser) init(p *parser)
} }
@ -16,19 +18,18 @@ type Node interface {
type node struct { type node struct {
// commented out for now since not yet used // commented out for now since not yet used
// doc *Comment // nil means no comment(s) attached // doc *Comment // nil means no comment(s) attached
pos uint32 pos src.Pos
line uint32 }
func (n *node) Pos() src.Pos {
return n.pos
} }
func (*node) aNode() {} func (*node) aNode() {}
func (n *node) Line() uint32 { // TODO(gri) we may be able to get rid of init here and in Node
return n.line
}
func (n *node) init(p *parser) { func (n *node) init(p *parser) {
n.pos = uint32(p.pos) n.pos = p.pos()
n.line = uint32(p.line)
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@ -38,7 +39,7 @@ func (n *node) init(p *parser) {
type File struct { type File struct {
PkgName *Name PkgName *Name
DeclList []Decl DeclList []Decl
Lines int Lines uint
node node
} }
@ -103,7 +104,7 @@ type (
Type *FuncType Type *FuncType
Body []Stmt // nil means no body (forward declaration) Body []Stmt // nil means no body (forward declaration)
Pragma Pragma // TODO(mdempsky): Cleaner solution. Pragma Pragma // TODO(mdempsky): Cleaner solution.
EndLine uint32 // TODO(mdempsky): Cleaner solution. EndLine uint // TODO(mdempsky): Cleaner solution.
decl decl
} }
) )
@ -143,8 +144,8 @@ type (
CompositeLit struct { CompositeLit struct {
Type Expr // nil means no literal type Type Expr // nil means no literal type
ElemList []Expr ElemList []Expr
NKeys int // number of elements with keys NKeys int // number of elements with keys
EndLine uint32 // TODO(mdempsky): Cleaner solution. EndLine uint // TODO(mdempsky): Cleaner solution.
expr expr
} }
@ -158,7 +159,7 @@ type (
FuncLit struct { FuncLit struct {
Type *FuncType Type *FuncType
Body []Stmt Body []Stmt
EndLine uint32 // TODO(mdempsky): Cleaner solution. EndLine uint // TODO(mdempsky): Cleaner solution.
expr expr
} }

View file

@ -5,8 +5,10 @@
package syntax package syntax
import ( import (
"cmd/internal/src"
"fmt" "fmt"
"io" "io"
"strconv"
"strings" "strings"
) )
@ -19,21 +21,67 @@ const trace = false
const gcCompat = true const gcCompat = true
type parser struct { type parser struct {
base *src.PosBase
errh ErrorHandler
scanner scanner
first error // first error encountered
pragma Pragma // pragma flags
fnest int // function nesting level (for error handling) fnest int // function nesting level (for error handling)
xnest int // expression nesting level (for complit ambiguity resolution) xnest int // expression nesting level (for complit ambiguity resolution)
indent []byte // tracing support indent []byte // tracing support
} }
func (p *parser) init(src io.Reader, errh ErrorHandler, pragh PragmaHandler) { func (p *parser) init(base *src.PosBase, r io.Reader, errh ErrorHandler, pragh PragmaHandler) {
p.scanner.init(src, errh, pragh) p.base = base
p.errh = errh
p.scanner.init(
r,
// Error and pragma handlers for scanner.
// Because the (line, col) positions passed to these
// handlers are always at or after the current reading
// position, it is save to use the most recent position
// base to compute the corresponding Pos value.
func(line, col uint, msg string) {
p.error_at(p.pos_at(line, col), msg)
},
func(line, col uint, text string) {
if strings.HasPrefix(text, "line ") {
p.updateBase(line, col+5, text[5:])
return
}
if pragh != nil {
p.pragma |= pragh(p.pos_at(line, col), text)
}
},
)
p.first = nil
p.pragma = 0
p.fnest = 0 p.fnest = 0
p.xnest = 0 p.xnest = 0
p.indent = nil p.indent = nil
} }
const lineMax = 1<<24 - 1 // TODO(gri) this limit is defined for src.Pos - fix
func (p *parser) updateBase(line, col uint, text string) {
// Want to use LastIndexByte below but it's not defined in Go1.4 and bootstrap fails.
i := strings.LastIndex(text, ":") // look from right (Windows filenames may contain ':')
if i < 0 {
return // ignore (not a line directive)
}
nstr := text[i+1:]
n, err := strconv.Atoi(nstr)
if err != nil || n <= 0 || n > lineMax {
p.error_at(p.pos_at(line, col+uint(i+1)), "invalid line number: "+nstr)
return
}
p.base = src.NewLinePragmaBase(src.MakePos(p.base.Pos().Base(), line, col), text[:i], uint(n))
}
func (p *parser) got(tok token) bool { func (p *parser) got(tok token) bool {
if p.tok == tok { if p.tok == tok {
p.next() p.next()
@ -52,13 +100,25 @@ func (p *parser) want(tok token) {
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Error handling // Error handling
// syntax_error reports a syntax error at the current line. // pos_at returns the Pos value for (line, col) and the current position base.
func (p *parser) syntax_error(msg string) { func (p *parser) pos_at(line, col uint) src.Pos {
p.syntax_error_at(p.pos, p.line, msg) return src.MakePos(p.base, line, col)
} }
// Like syntax_error, but reports error at given line rather than current lexer line. // error reports an error at the given position.
func (p *parser) syntax_error_at(pos, line int, msg string) { func (p *parser) error_at(pos src.Pos, msg string) {
err := Error{pos, msg}
if p.first == nil {
p.first = err
}
if p.errh == nil {
panic(p.first)
}
p.errh(err)
}
// syntax_error_at reports a syntax error at the given position.
func (p *parser) syntax_error_at(pos src.Pos, msg string) {
if trace { if trace {
defer p.trace("syntax_error (" + msg + ")")() defer p.trace("syntax_error (" + msg + ")")()
} }
@ -77,7 +137,7 @@ func (p *parser) syntax_error_at(pos, line int, msg string) {
msg = ", " + msg msg = ", " + msg
default: default:
// plain error - we don't care about current token // plain error - we don't care about current token
p.error_at(pos, line, "syntax error: "+msg) p.error_at(pos, "syntax error: "+msg)
return return
} }
@ -99,9 +159,14 @@ func (p *parser) syntax_error_at(pos, line int, msg string) {
tok = tokstring(p.tok) tok = tokstring(p.tok)
} }
p.error_at(pos, line, "syntax error: unexpected "+tok+msg) p.error_at(pos, "syntax error: unexpected "+tok+msg)
} }
// Convenience methods using the current token position.
func (p *parser) pos() src.Pos { return p.pos_at(p.line, p.col) }
func (p *parser) error(msg string) { p.error_at(p.pos(), msg) }
func (p *parser) syntax_error(msg string) { p.syntax_error_at(p.pos(), msg) }
// The stopset contains keywords that start a statement. // The stopset contains keywords that start a statement.
// They are good synchronization points in case of syntax // They are good synchronization points in case of syntax
// errors and (usually) shouldn't be skipped over. // errors and (usually) shouldn't be skipped over.
@ -429,7 +494,7 @@ func (p *parser) funcDecl() *FuncDecl {
f.Body = p.funcBody() f.Body = p.funcBody()
f.Pragma = p.pragma f.Pragma = p.pragma
f.EndLine = uint32(p.line) f.EndLine = p.line
// TODO(gri) deal with function properties // TODO(gri) deal with function properties
// if noescape && body != nil { // if noescape && body != nil {
@ -652,7 +717,7 @@ func (p *parser) operand(keep_parens bool) Expr {
f.init(p) f.init(p)
f.Type = t f.Type = t
f.Body = p.funcBody() f.Body = p.funcBody()
f.EndLine = uint32(p.line) f.EndLine = p.line
p.xnest-- p.xnest--
p.fnest-- p.fnest--
return f return f
@ -873,7 +938,7 @@ func (p *parser) complitexpr() *CompositeLit {
} }
} }
x.EndLine = uint32(p.line) x.EndLine = p.line
p.xnest-- p.xnest--
p.want(_Rbrace) p.want(_Rbrace)
@ -1198,7 +1263,7 @@ func (p *parser) fieldDecl(styp *StructType) {
p.want(_Rparen) p.want(_Rparen)
tag := p.oliteral() tag := p.oliteral()
p.addField(styp, nil, typ, tag) p.addField(styp, nil, typ, tag)
p.error("cannot parenthesize embedded type") p.syntax_error("cannot parenthesize embedded type")
} else { } else {
// '(' embed ')' oliteral // '(' embed ')' oliteral
@ -1206,7 +1271,7 @@ func (p *parser) fieldDecl(styp *StructType) {
p.want(_Rparen) p.want(_Rparen)
tag := p.oliteral() tag := p.oliteral()
p.addField(styp, nil, typ, tag) p.addField(styp, nil, typ, tag)
p.error("cannot parenthesize embedded type") p.syntax_error("cannot parenthesize embedded type")
} }
case _Star: case _Star:
@ -1217,7 +1282,7 @@ func (p *parser) fieldDecl(styp *StructType) {
p.want(_Rparen) p.want(_Rparen)
tag := p.oliteral() tag := p.oliteral()
p.addField(styp, nil, typ, tag) p.addField(styp, nil, typ, tag)
p.error("cannot parenthesize embedded type") p.syntax_error("cannot parenthesize embedded type")
} else { } else {
// '*' embed oliteral // '*' embed oliteral
@ -1285,7 +1350,7 @@ func (p *parser) methodDecl() *Field {
f.init(p) f.init(p)
f.Type = p.qualifiedName(nil) f.Type = p.qualifiedName(nil)
p.want(_Rparen) p.want(_Rparen)
p.error("cannot parenthesize embedded type") p.syntax_error("cannot parenthesize embedded type")
return f return f
default: default:
@ -1352,7 +1417,7 @@ func (p *parser) dotsType() *DotsType {
p.want(_DotDotDot) p.want(_DotDotDot)
t.Elem = p.tryType() t.Elem = p.tryType()
if t.Elem == nil { if t.Elem == nil {
p.error("final argument in variadic function missing type") p.syntax_error("final argument in variadic function missing type")
} }
return t return t
@ -1563,7 +1628,7 @@ func (p *parser) labeledStmt(label *Name) Stmt {
s.Stmt = p.stmt() s.Stmt = p.stmt()
if s.Stmt == missing_stmt { if s.Stmt == missing_stmt {
// report error at line of ':' token // report error at line of ':' token
p.syntax_error_at(int(label.pos), int(label.line), "missing statement after label") p.syntax_error_at(label.Pos(), "missing statement after label")
// we are already at the end of the labeled statement - no need to advance // we are already at the end of the labeled statement - no need to advance
return missing_stmt return missing_stmt
} }
@ -1646,7 +1711,7 @@ func (p *parser) header(forStmt bool) (init SimpleStmt, cond Expr, post SimpleSt
if p.tok != _Semi { if p.tok != _Semi {
// accept potential varDecl but complain // accept potential varDecl but complain
if forStmt && p.got(_Var) { if forStmt && p.got(_Var) {
p.error("var declaration not allowed in for initializer") p.syntax_error("var declaration not allowed in for initializer")
} }
init = p.simpleStmt(nil, forStmt) init = p.simpleStmt(nil, forStmt)
// If we have a range clause, we are done. // If we have a range clause, we are done.
@ -1699,7 +1764,7 @@ func (p *parser) ifStmt() *IfStmt {
p.want(_If) p.want(_If)
s.Init, s.Cond, _ = p.header(false) s.Init, s.Cond, _ = p.header(false)
if s.Cond == nil { if s.Cond == nil {
p.error("missing condition in if statement") p.syntax_error("missing condition in if statement")
} }
if gcCompat { if gcCompat {
@ -1715,7 +1780,7 @@ func (p *parser) ifStmt() *IfStmt {
case _Lbrace: case _Lbrace:
s.Else = p.blockStmt() s.Else = p.blockStmt()
default: default:
p.error("else must be followed by if or statement block") p.syntax_error("else must be followed by if or statement block")
p.advance(_Name, _Rbrace) p.advance(_Name, _Rbrace)
} }
} }
@ -2088,7 +2153,7 @@ func (p *parser) exprList() Expr {
list = append(list, p.expr()) list = append(list, p.expr())
} }
t := new(ListExpr) t := new(ListExpr)
t.init(p) // TODO(gri) what is the correct thing here? t.pos = x.Pos()
t.ElemList = list t.ElemList = list
x = t x = t
} }

View file

@ -6,6 +6,7 @@ package syntax
import ( import (
"bytes" "bytes"
"cmd/internal/src"
"flag" "flag"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
@ -18,11 +19,11 @@ import (
) )
var fast = flag.Bool("fast", false, "parse package files in parallel") var fast = flag.Bool("fast", false, "parse package files in parallel")
var src = flag.String("src", "parser.go", "source file to parse") var src_ = flag.String("src", "parser.go", "source file to parse")
var verify = flag.Bool("verify", false, "verify idempotent printing") var verify = flag.Bool("verify", false, "verify idempotent printing")
func TestParse(t *testing.T) { func TestParse(t *testing.T) {
_, err := ParseFile(*src, nil, nil, 0) _, err := ParseFile(*src_, nil, nil, 0)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -39,7 +40,7 @@ func TestStdLib(t *testing.T) {
type parseResult struct { type parseResult struct {
filename string filename string
lines int lines uint
} }
results := make(chan parseResult) results := make(chan parseResult)
@ -65,7 +66,7 @@ func TestStdLib(t *testing.T) {
} }
}() }()
var count, lines int var count, lines uint
for res := range results { for res := range results {
count++ count++
lines += res.lines lines += res.lines
@ -133,7 +134,7 @@ func verifyPrint(filename string, ast1 *File) {
panic(err) panic(err)
} }
ast2, err := ParseBytes(buf1.Bytes(), nil, nil, 0) ast2, err := ParseBytes(src.NewFileBase(filename, filename), buf1.Bytes(), nil, nil, 0)
if err != nil { if err != nil {
panic(err) panic(err)
} }
@ -157,7 +158,7 @@ func verifyPrint(filename string, ast1 *File) {
} }
func TestIssue17697(t *testing.T) { func TestIssue17697(t *testing.T) {
_, err := ParseBytes(nil, nil, nil, 0) // return with parser error, don't panic _, err := ParseBytes(nil, nil, nil, nil, 0) // return with parser error, don't panic
if err == nil { if err == nil {
t.Errorf("no error reported") t.Errorf("no error reported")
} }
@ -182,3 +183,47 @@ func TestParseFile(t *testing.T) {
t.Errorf("got %v; want first error %v", err, first) t.Errorf("got %v; want first error %v", err, first)
} }
} }
func TestLineDirectives(t *testing.T) {
for _, test := range []struct {
src, msg string
filename string
line, col uint
}{
// test validity of //line directive
{`//line :`, "invalid line number: ", "", 1, 8},
{`//line :x`, "invalid line number: x", "", 1, 8},
{`//line foo :`, "invalid line number: ", "", 1, 12},
{`//line foo:123abc`, "invalid line number: 123abc", "", 1, 11},
{`/**///line foo:x`, "invalid line number: x", "", 1, 15},
{`//line foo:0`, "invalid line number: 0", "", 1, 11},
{fmt.Sprintf(`//line foo:%d`, lineMax+1), fmt.Sprintf("invalid line number: %d", lineMax+1), "", 1, 11},
// test effect of //line directive on (relative) position information
{"//line foo:123\n foo", "syntax error: package statement must be first", "foo", 123, 3},
{"//line foo:123\n//line bar:345\nfoo", "syntax error: package statement must be first", "bar", 345, 0},
} {
_, err := ParseBytes(nil, []byte(test.src), nil, nil, 0)
if err == nil {
t.Errorf("%s: no error reported", test.src)
continue
}
perr, ok := err.(Error)
if !ok {
t.Errorf("%s: got %v; want parser error", test.src, err)
continue
}
if msg := perr.Msg; msg != test.msg {
t.Errorf("%s: got msg = %q; want %q", test.src, msg, test.msg)
}
if filename := perr.Pos.RelFilename(); filename != test.filename {
t.Errorf("%s: got filename = %q; want %q", test.src, filename, test.filename)
}
if line := perr.Pos.RelLine(); line != test.line {
t.Errorf("%s: got line = %d; want %d", test.src, line, test.line)
}
if col := perr.Pos.Col(); col != test.col {
t.Errorf("%s: got col = %d; want %d", test.src, col, test.col)
}
}
}

View file

@ -15,7 +15,7 @@ func TestPrint(t *testing.T) {
t.Skip("skipping test in short mode") t.Skip("skipping test in short mode")
} }
ast, err := ParseFile(*src, nil, nil, 0) ast, err := ParseFile(*src_, nil, nil, 0)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -29,7 +29,7 @@ func TestPrintString(t *testing.T) {
"package p; type _ = int; type T1 = struct{}; type ( _ = *struct{}; T2 = float32 )", "package p; type _ = int; type T1 = struct{}; type ( _ = *struct{}; T2 = float32 )",
// TODO(gri) expand // TODO(gri) expand
} { } {
ast, err := ParseBytes([]byte(want), nil, nil, 0) ast, err := ParseBytes(nil, []byte(want), nil, nil, 0)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
continue continue

View file

@ -2,38 +2,55 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// This file implements scanner, a lexical tokenizer for
// Go source. After initialization, consecutive calls of
// next advance the scanner one token at a time.
//
// This file, source.go, and tokens.go are self-contained
// (go tool compile scanner.go source.go tokens.go compiles)
// and thus could be made into its own package.
package syntax package syntax
import ( import (
"fmt" "fmt"
"io" "io"
"strings"
"unicode" "unicode"
"unicode/utf8" "unicode/utf8"
) )
type scanner struct { type scanner struct {
source source
pragh func(line, col uint, msg string)
nlsemi bool // if set '\n' and EOF translate to ';' nlsemi bool // if set '\n' and EOF translate to ';'
pragma Pragma
// current token, valid after calling next() // current token, valid after calling next()
pos, line int line, col uint
tok token tok token
lit string // valid if tok is _Name or _Literal lit string // valid if tok is _Name or _Literal
kind LitKind // valid if tok is _Literal kind LitKind // valid if tok is _Literal
op Operator // valid if tok is _Operator, _AssignOp, or _IncOp op Operator // valid if tok is _Operator, _AssignOp, or _IncOp
prec int // valid if tok is _Operator, _AssignOp, or _IncOp prec int // valid if tok is _Operator, _AssignOp, or _IncOp
pragh PragmaHandler
} }
func (s *scanner) init(src io.Reader, errh ErrorHandler, pragh PragmaHandler) { func (s *scanner) init(src io.Reader, errh, pragh func(line, col uint, msg string)) {
s.source.init(src, errh) s.source.init(src, errh)
s.nlsemi = false
s.pragh = pragh s.pragh = pragh
s.nlsemi = false
} }
// next advances the scanner by reading the next token.
//
// If a read, source encoding, or lexical error occurs, next
// calls the error handler installed with init. The handler
// must exist.
//
// If a //line or //go: directive is encountered, next
// calls the pragma handler installed with init, if not nil.
//
// The (line, col) position passed to the error and pragma
// handler is always at or after the current source reading
// position.
func (s *scanner) next() { func (s *scanner) next() {
nlsemi := s.nlsemi nlsemi := s.nlsemi
s.nlsemi = false s.nlsemi = false
@ -46,9 +63,9 @@ redo:
} }
// token start // token start
s.pos, s.line = s.source.pos0(), s.source.line0 s.line, s.col = s.source.line0, s.source.col0
if isLetter(c) || c >= utf8.RuneSelf && (unicode.IsLetter(c) || s.isCompatRune(c, true)) { if isLetter(c) || c >= utf8.RuneSelf && s.isIdentRune(c, true) {
s.ident() s.ident()
return return
} }
@ -114,8 +131,7 @@ redo:
case '.': case '.':
c = s.getr() c = s.getr()
if isDigit(c) { if isDigit(c) {
s.ungetr() s.ungetr2()
s.source.r0-- // make sure '.' is part of literal (line cannot have changed)
s.number('.') s.number('.')
break break
} }
@ -125,8 +141,7 @@ redo:
s.tok = _DotDotDot s.tok = _DotDotDot
break break
} }
s.ungetr() s.ungetr2()
s.source.r0-- // make next ungetr work (line cannot have changed)
} }
s.ungetr() s.ungetr()
s.tok = _Dot s.tok = _Dot
@ -273,7 +288,7 @@ redo:
default: default:
s.tok = 0 s.tok = 0
s.error(fmt.Sprintf("illegal character %#U", c)) s.error(fmt.Sprintf("invalid character %#U", c))
goto redo goto redo
} }
@ -307,7 +322,7 @@ func (s *scanner) ident() {
// general case // general case
if c >= utf8.RuneSelf { if c >= utf8.RuneSelf {
for unicode.IsLetter(c) || c == '_' || unicode.IsDigit(c) || s.isCompatRune(c, false) { for s.isIdentRune(c, false) {
c = s.getr() c = s.getr()
} }
} }
@ -329,14 +344,18 @@ func (s *scanner) ident() {
s.tok = _Name s.tok = _Name
} }
func (s *scanner) isCompatRune(c rune, start bool) bool { func (s *scanner) isIdentRune(c rune, first bool) bool {
if !gcCompat || c < utf8.RuneSelf { switch {
return false case unicode.IsLetter(c) || c == '_':
} // ok
if start && unicode.IsNumber(c) { case unicode.IsDigit(c):
s.error(fmt.Sprintf("identifier cannot begin with digit %#U", c)) if first {
} else { s.error(fmt.Sprintf("identifier cannot begin with digit %#U", c))
}
case c >= utf8.RuneSelf:
s.error(fmt.Sprintf("invalid identifier character %#U", c)) s.error(fmt.Sprintf("invalid identifier character %#U", c))
default:
return false
} }
return true return true
} }
@ -460,7 +479,7 @@ func (s *scanner) stdString() {
break break
} }
if r < 0 { if r < 0 {
s.error_at(s.pos, s.line, "string not terminated") s.errh(s.line, s.col, "string not terminated")
break break
} }
} }
@ -480,7 +499,7 @@ func (s *scanner) rawString() {
break break
} }
if r < 0 { if r < 0 {
s.error_at(s.pos, s.line, "string not terminated") s.errh(s.line, s.col, "string not terminated")
break break
} }
} }
@ -526,48 +545,46 @@ func (s *scanner) rune() {
s.tok = _Literal s.tok = _Literal
} }
func (s *scanner) lineComment() { func (s *scanner) skipLine(r rune) {
// recognize pragmas
var prefix string
r := s.getr()
if s.pragh == nil {
goto skip
}
switch r {
case 'g':
prefix = "go:"
case 'l':
prefix = "line "
default:
goto skip
}
s.startLit()
for _, m := range prefix {
if r != m {
s.stopLit()
goto skip
}
r = s.getr()
}
for r >= 0 { for r >= 0 {
if r == '\n' { if r == '\n' {
s.ungetr() s.ungetr() // don't consume '\n' - needed for nlsemi logic
break break
} }
r = s.getr() r = s.getr()
} }
s.pragma |= s.pragh(0, s.line, strings.TrimSuffix(string(s.stopLit()), "\r")) }
return
skip: func (s *scanner) lineComment() {
// consume line r := s.getr()
for r != '\n' && r >= 0 { if s.pragh == nil || (r != 'g' && r != 'l') {
s.skipLine(r)
return
}
// s.pragh != nil && (r == 'g' || r == 'l')
// recognize pragmas
prefix := "go:"
if r == 'l' {
prefix = "line "
}
for _, m := range prefix {
if r != m {
s.skipLine(r)
return
}
r = s.getr() r = s.getr()
} }
s.ungetr() // don't consume '\n' - needed for nlsemi logic
// pragma text without line ending (which may be "\r\n" if Windows),
s.startLit()
s.skipLine(r)
text := s.stopLit()
if i := len(text) - 1; i >= 0 && text[i] == '\r' {
text = text[:i]
}
s.pragh(s.line, s.col+2, prefix+string(text)) // +2 since pragma text starts after //
} }
func (s *scanner) fullComment() { func (s *scanner) fullComment() {
@ -580,7 +597,7 @@ func (s *scanner) fullComment() {
} }
} }
if r < 0 { if r < 0 {
s.error_at(s.pos, s.line, "comment not terminated") s.errh(s.line, s.col, "comment not terminated")
return return
} }
} }
@ -628,19 +645,11 @@ func (s *scanner) escape(quote rune) bool {
if c < 0 { if c < 0 {
return true // complain in caller about EOF return true // complain in caller about EOF
} }
if gcCompat { kind := "hex"
name := "hex" if base == 8 {
if base == 8 { kind = "octal"
name = "octal"
}
s.error(fmt.Sprintf("non-%s character in escape sequence: %c", name, c))
} else {
if c != quote {
s.error(fmt.Sprintf("illegal character %#U in escape sequence", c))
} else {
s.error("escape sequence incomplete")
}
} }
s.error(fmt.Sprintf("non-%s character in escape sequence: %c", kind, c))
s.ungetr() s.ungetr()
return false return false
} }

View file

@ -56,7 +56,7 @@ func TestTokens(t *testing.T) {
for i, want := range sampleTokens { for i, want := range sampleTokens {
nlsemi := false nlsemi := false
if got.line != i+1 { if got.line != uint(i+1) {
t.Errorf("got line %d; want %d", got.line, i+1) t.Errorf("got line %d; want %d", got.line, i+1)
} }
@ -256,88 +256,93 @@ var sampleTokens = [...]struct {
func TestScanErrors(t *testing.T) { func TestScanErrors(t *testing.T) {
for _, test := range []struct { for _, test := range []struct {
src, msg string src, msg string
pos, line int line, col uint
}{ }{
// Note: Positions for lexical errors are the earliest position // Note: Positions for lexical errors are the earliest position
// where the error is apparent, not the beginning of the respective // where the error is apparent, not the beginning of the respective
// token. // token.
// rune-level errors // rune-level errors
{"fo\x00o", "invalid NUL character", 2, 1}, {"fo\x00o", "invalid NUL character", 1, 2},
{"foo\n\ufeff bar", "invalid BOM in the middle of the file", 4, 2}, {"foo\n\ufeff bar", "invalid BOM in the middle of the file", 2, 0},
{"foo\n\n\xff ", "invalid UTF-8 encoding", 5, 3}, {"foo\n\n\xff ", "invalid UTF-8 encoding", 3, 0},
// token-level errors // token-level errors
{"x + ~y", "bitwise complement operator is ^", 4, 1}, {"\u00BD" /* ½ */, "invalid identifier character U+00BD '½'", 1, 0},
{"foo$bar = 0", "illegal character U+0024 '$'", 3, 1}, {"\U0001d736\U0001d737\U0001d738_½" /* 𝜶𝜷𝜸_½ */, "invalid identifier character U+00BD '½'", 1, 13 /* byte offset */},
{"const x = 0xyz", "malformed hex constant", 12, 1}, {"\U0001d7d8" /* 𝟘 */, "identifier cannot begin with digit U+1D7D8 '𝟘'", 1, 0},
{"0123456789", "malformed octal constant", 10, 1}, {"foo\U0001d7d8_½" /* foo𝟘_½ */, "invalid identifier character U+00BD '½'", 1, 8 /* byte offset */},
{"0123456789. /* foobar", "comment not terminated", 12, 1}, // valid float constant
{"0123456789e0 /*\nfoobar", "comment not terminated", 13, 1}, // valid float constant {"x + ~y", "bitwise complement operator is ^", 1, 4},
{"var a, b = 08, 07\n", "malformed octal constant", 13, 1}, {"foo$bar = 0", "invalid character U+0024 '$'", 1, 3},
{"(x + 1.0e+x)", "malformed floating-point constant exponent", 10, 1}, {"const x = 0xyz", "malformed hex constant", 1, 12},
{"0123456789", "malformed octal constant", 1, 10},
{"0123456789. /* foobar", "comment not terminated", 1, 12}, // valid float constant
{"0123456789e0 /*\nfoobar", "comment not terminated", 1, 13}, // valid float constant
{"var a, b = 08, 07\n", "malformed octal constant", 1, 13},
{"(x + 1.0e+x)", "malformed floating-point constant exponent", 1, 10},
{`''`, "empty character literal or unescaped ' in character literal", 1, 1}, {`''`, "empty character literal or unescaped ' in character literal", 1, 1},
{"'\n", "newline in character literal", 1, 1}, {"'\n", "newline in character literal", 1, 1},
{`'\`, "missing '", 2, 1}, {`'\`, "missing '", 1, 2},
{`'\'`, "missing '", 3, 1}, {`'\'`, "missing '", 1, 3},
{`'\x`, "missing '", 3, 1}, {`'\x`, "missing '", 1, 3},
{`'\x'`, "non-hex character in escape sequence: '", 3, 1}, {`'\x'`, "non-hex character in escape sequence: '", 1, 3},
{`'\y'`, "unknown escape sequence", 2, 1}, {`'\y'`, "unknown escape sequence", 1, 2},
{`'\x0'`, "non-hex character in escape sequence: '", 4, 1}, {`'\x0'`, "non-hex character in escape sequence: '", 1, 4},
{`'\00'`, "non-octal character in escape sequence: '", 4, 1}, {`'\00'`, "non-octal character in escape sequence: '", 1, 4},
{`'\377' /*`, "comment not terminated", 7, 1}, // valid octal escape {`'\377' /*`, "comment not terminated", 1, 7}, // valid octal escape
{`'\378`, "non-octal character in escape sequence: 8", 4, 1}, {`'\378`, "non-octal character in escape sequence: 8", 1, 4},
{`'\400'`, "octal escape value > 255: 256", 5, 1}, {`'\400'`, "octal escape value > 255: 256", 1, 5},
{`'xx`, "missing '", 2, 1}, {`'xx`, "missing '", 1, 2},
{"\"\n", "newline in string", 1, 1}, {"\"\n", "newline in string", 1, 1},
{`"`, "string not terminated", 0, 1}, {`"`, "string not terminated", 1, 0},
{`"foo`, "string not terminated", 0, 1}, {`"foo`, "string not terminated", 1, 0},
{"`", "string not terminated", 0, 1}, {"`", "string not terminated", 1, 0},
{"`foo", "string not terminated", 0, 1}, {"`foo", "string not terminated", 1, 0},
{"/*/", "comment not terminated", 0, 1}, {"/*/", "comment not terminated", 1, 0},
{"/*\n\nfoo", "comment not terminated", 0, 1}, {"/*\n\nfoo", "comment not terminated", 1, 0},
{"/*\n\nfoo", "comment not terminated", 0, 1}, {"/*\n\nfoo", "comment not terminated", 1, 0},
{`"\`, "string not terminated", 0, 1}, {`"\`, "string not terminated", 1, 0},
{`"\"`, "string not terminated", 0, 1}, {`"\"`, "string not terminated", 1, 0},
{`"\x`, "string not terminated", 0, 1}, {`"\x`, "string not terminated", 1, 0},
{`"\x"`, "non-hex character in escape sequence: \"", 3, 1}, {`"\x"`, "non-hex character in escape sequence: \"", 1, 3},
{`"\y"`, "unknown escape sequence", 2, 1}, {`"\y"`, "unknown escape sequence", 1, 2},
{`"\x0"`, "non-hex character in escape sequence: \"", 4, 1}, {`"\x0"`, "non-hex character in escape sequence: \"", 1, 4},
{`"\00"`, "non-octal character in escape sequence: \"", 4, 1}, {`"\00"`, "non-octal character in escape sequence: \"", 1, 4},
{`"\377" /*`, "comment not terminated", 7, 1}, // valid octal escape {`"\377" /*`, "comment not terminated", 1, 7}, // valid octal escape
{`"\378"`, "non-octal character in escape sequence: 8", 4, 1}, {`"\378"`, "non-octal character in escape sequence: 8", 1, 4},
{`"\400"`, "octal escape value > 255: 256", 5, 1}, {`"\400"`, "octal escape value > 255: 256", 1, 5},
{`s := "foo\z"`, "unknown escape sequence", 10, 1}, {`s := "foo\z"`, "unknown escape sequence", 1, 10},
{`s := "foo\z00\nbar"`, "unknown escape sequence", 10, 1}, {`s := "foo\z00\nbar"`, "unknown escape sequence", 1, 10},
{`"\x`, "string not terminated", 0, 1}, {`"\x`, "string not terminated", 1, 0},
{`"\x"`, "non-hex character in escape sequence: \"", 3, 1}, {`"\x"`, "non-hex character in escape sequence: \"", 1, 3},
{`var s string = "\x"`, "non-hex character in escape sequence: \"", 18, 1}, {`var s string = "\x"`, "non-hex character in escape sequence: \"", 1, 18},
{`return "\Uffffffff"`, "escape sequence is invalid Unicode code point", 18, 1}, {`return "\Uffffffff"`, "escape sequence is invalid Unicode code point", 1, 18},
// former problem cases // former problem cases
{"package p\n\n\xef", "invalid UTF-8 encoding", 11, 3}, {"package p\n\n\xef", "invalid UTF-8 encoding", 3, 0},
} { } {
var s scanner var s scanner
nerrors := 0 nerrors := 0
s.init(&bytesReader{[]byte(test.src)}, func(err error) { s.init(&bytesReader{[]byte(test.src)}, func(line, col uint, msg string) {
nerrors++ nerrors++
// only check the first error // only check the first error
e := err.(Error) // we know it's an Error
if nerrors == 1 { if nerrors == 1 {
if e.Msg != test.msg { if msg != test.msg {
t.Errorf("%q: got msg = %q; want %q", test.src, e.Msg, test.msg) t.Errorf("%q: got msg = %q; want %q", test.src, msg, test.msg)
} }
if e.Pos != test.pos { if line != test.line {
t.Errorf("%q: got pos = %d; want %d", test.src, e.Pos, test.pos) t.Errorf("%q: got line = %d; want %d", test.src, line, test.line)
} }
if e.Line != test.line { if col != test.col {
t.Errorf("%q: got line = %d; want %d", test.src, e.Line, test.line) t.Errorf("%q: got col = %d; want %d", test.src, col, test.col)
} }
} else if nerrors > 1 { } else if nerrors > 1 {
t.Errorf("%q: got unexpected %q at pos = %d, line = %d", test.src, e.Msg, e.Pos, e.Line) // TODO(gri) make this use position info
t.Errorf("%q: got unexpected %q at line = %d", test.src, msg, line)
} }
}, nil) }, nil)

View file

@ -2,6 +2,15 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// This file implements source, a buffered rune reader
// which is specialized for the needs of the Go scanner:
// Contiguous sequences of runes (literals) are extracted
// directly as []byte without the need to re-encode the
// runes in UTF-8 (as would be necessary with bufio.Reader).
//
// This file is self-contained (go tool compile source.go
// compiles) and thus could be made into its own package.
package syntax package syntax
import ( import (
@ -15,64 +24,69 @@ import (
// suf r0 r w // suf r0 r w
type source struct { type source struct {
src io.Reader src io.Reader
errh ErrorHandler errh func(line, pos uint, msg string)
first error // first error encountered
// source buffer // source buffer
buf [4 << 10]byte buf [4 << 10]byte
offs int // source offset of buf offs int // source offset of buf
r0, r, w int // previous/current read and write buf positions, excluding sentinel r0, r, w int // previous/current read and write buf positions, excluding sentinel
line0, line int // previous/current line line0, line uint // previous/current line
err error // pending io error col0, col uint // previous/current column (byte offsets from line start)
ioerr error // pending io error
// literal buffer // literal buffer
lit []byte // literal prefix lit []byte // literal prefix
suf int // literal suffix; suf >= 0 means we are scanning a literal suf int // literal suffix; suf >= 0 means we are scanning a literal
} }
func (s *source) init(src io.Reader, errh ErrorHandler) { // init initializes source to read from src and to report errors via errh.
// errh must not be nil.
func (s *source) init(src io.Reader, errh func(line, pos uint, msg string)) {
s.src = src s.src = src
s.errh = errh s.errh = errh
s.first = nil
s.buf[0] = utf8.RuneSelf // terminate with sentinel s.buf[0] = utf8.RuneSelf // terminate with sentinel
s.offs = 0 s.offs = 0
s.r0, s.r, s.w = 0, 0, 0 s.r0, s.r, s.w = 0, 0, 0
s.line0, s.line = 1, 1 s.line0, s.line = 1, 1
s.err = nil s.col0, s.col = 0, 0
s.ioerr = nil
s.lit = s.lit[:0] s.lit = s.lit[:0]
s.suf = -1 s.suf = -1
} }
func (s *source) error(msg string) { // ungetr ungets the most recently read rune.
s.error_at(s.pos0(), s.line0, msg)
}
func (s *source) error_at(pos, line int, msg string) {
err := Error{pos, line, msg}
if s.first == nil {
s.first = err
}
if s.errh == nil {
panic(s.first)
}
s.errh(err)
}
// pos0 returns the byte position of the last character read.
func (s *source) pos0() int {
return s.offs + s.r0
}
func (s *source) ungetr() { func (s *source) ungetr() {
s.r, s.line = s.r0, s.line0 s.r, s.line, s.col = s.r0, s.line0, s.col0
} }
// ungetr2 is like ungetr but enables a 2nd ungetr.
// It must not be called if one of the runes seen
// was a newline.
func (s *source) ungetr2() {
s.ungetr()
// line must not have changed
s.r0--
s.col0--
}
func (s *source) error(msg string) {
s.errh(s.line0, s.col0, msg)
}
// getr reads and returns the next rune.
//
// If a read or source encoding error occurs, getr
// calls the error handler installed with init.
// The handler must exist.
//
// The (line, col) position passed to the error handler
// is always at the current source reading position.
func (s *source) getr() rune { func (s *source) getr() rune {
redo: redo:
s.r0, s.line0 = s.r, s.line s.r0, s.line0, s.col0 = s.r, s.line, s.col
// We could avoid at least one test that is always taken in the // We could avoid at least one test that is always taken in the
// for loop below by duplicating the common case code (ASCII) // for loop below by duplicating the common case code (ASCII)
@ -80,7 +94,7 @@ redo:
// in the buffer. Measure and optimize if necessary. // in the buffer. Measure and optimize if necessary.
// make sure we have at least one rune in buffer, or we are at EOF // make sure we have at least one rune in buffer, or we are at EOF
for s.r+utf8.UTFMax > s.w && !utf8.FullRune(s.buf[s.r:s.w]) && s.err == nil && s.w-s.r < len(s.buf) { for s.r+utf8.UTFMax > s.w && !utf8.FullRune(s.buf[s.r:s.w]) && s.ioerr == nil && s.w-s.r < len(s.buf) {
s.fill() // s.w-s.r < len(s.buf) => buffer is not full s.fill() // s.w-s.r < len(s.buf) => buffer is not full
} }
@ -88,20 +102,25 @@ redo:
// (invariant: s.buf[s.w] == utf8.RuneSelf) // (invariant: s.buf[s.w] == utf8.RuneSelf)
if b := s.buf[s.r]; b < utf8.RuneSelf { if b := s.buf[s.r]; b < utf8.RuneSelf {
s.r++ s.r++
// TODO(gri) Optimization: Instead of adjusting s.col for each character,
// remember the line offset instead and then compute the offset as needed
// (which is less often).
s.col++
if b == 0 { if b == 0 {
s.error("invalid NUL character") s.error("invalid NUL character")
goto redo goto redo
} }
if b == '\n' { if b == '\n' {
s.line++ s.line++
s.col = 0
} }
return rune(b) return rune(b)
} }
// EOF // EOF
if s.r == s.w { if s.r == s.w {
if s.err != io.EOF { if s.ioerr != io.EOF {
s.error(s.err.Error()) s.error(s.ioerr.Error())
} }
return -1 return -1
} }
@ -109,6 +128,7 @@ redo:
// uncommon case: not ASCII // uncommon case: not ASCII
r, w := utf8.DecodeRune(s.buf[s.r:s.w]) r, w := utf8.DecodeRune(s.buf[s.r:s.w])
s.r += w s.r += w
s.col += uint(w)
if r == utf8.RuneError && w == 1 { if r == utf8.RuneError && w == 1 {
s.error("invalid UTF-8 encoding") s.error("invalid UTF-8 encoding")
@ -157,13 +177,13 @@ func (s *source) fill() {
if n > 0 || err != nil { if n > 0 || err != nil {
s.buf[s.w] = utf8.RuneSelf // sentinel s.buf[s.w] = utf8.RuneSelf // sentinel
if err != nil { if err != nil {
s.err = err s.ioerr = err
} }
return return
} }
} }
s.err = io.ErrNoProgress s.ioerr = io.ErrNoProgress
} }
func (s *source) startLit() { func (s *source) startLit() {

View file

@ -5,6 +5,7 @@
package syntax package syntax
import ( import (
"cmd/internal/src"
"fmt" "fmt"
"io" "io"
"os" "os"
@ -15,14 +16,12 @@ type Mode uint
// Error describes a syntax error. Error implements the error interface. // Error describes a syntax error. Error implements the error interface.
type Error struct { type Error struct {
// TODO(gri) decide what we really need here Pos src.Pos
Pos int // byte offset from file start Msg string
Line int // line (starting with 1)
Msg string
} }
func (err Error) Error() string { func (err Error) Error() string {
return fmt.Sprintf("%d: %s", err.Line, err.Msg) return fmt.Sprintf("%s: %s", err.Pos, err.Msg)
} }
var _ error = Error{} // verify that Error implements error var _ error = Error{} // verify that Error implements error
@ -38,11 +37,11 @@ type Pragma uint16
// A PragmaHandler is used to process //line and //go: directives as // A PragmaHandler is used to process //line and //go: directives as
// they're scanned. The returned Pragma value will be unioned into the // they're scanned. The returned Pragma value will be unioned into the
// next FuncDecl node. // next FuncDecl node.
type PragmaHandler func(pos, line int, text string) Pragma type PragmaHandler func(pos src.Pos, text string) Pragma
// Parse parses a single Go source file from src and returns the corresponding // Parse parses a single Go source file from src and returns the corresponding
// syntax tree. If there are syntax errors, Parse will return the first error // syntax tree. If there are errors, Parse will return the first error found.
// encountered. // The base argument is only used for position information.
// //
// If errh != nil, it is called with each error encountered, and Parse will // If errh != nil, it is called with each error encountered, and Parse will
// process as much source as possible. If errh is nil, Parse will terminate // process as much source as possible. If errh is nil, Parse will terminate
@ -51,11 +50,11 @@ type PragmaHandler func(pos, line int, text string) Pragma
// If a PragmaHandler is provided, it is called with each pragma encountered. // If a PragmaHandler is provided, it is called with each pragma encountered.
// //
// The Mode argument is currently ignored. // The Mode argument is currently ignored.
func Parse(src io.Reader, errh ErrorHandler, pragh PragmaHandler, mode Mode) (_ *File, err error) { func Parse(base *src.PosBase, src io.Reader, errh ErrorHandler, pragh PragmaHandler, mode Mode) (_ *File, first error) {
defer func() { defer func() {
if p := recover(); p != nil { if p := recover(); p != nil {
var ok bool if err, ok := p.(Error); ok {
if err, ok = p.(Error); ok { first = err
return return
} }
panic(p) panic(p)
@ -63,14 +62,14 @@ func Parse(src io.Reader, errh ErrorHandler, pragh PragmaHandler, mode Mode) (_
}() }()
var p parser var p parser
p.init(src, errh, pragh) p.init(base, src, errh, pragh)
p.next() p.next()
return p.file(), p.first return p.file(), p.first
} }
// ParseBytes behaves like Parse but it reads the source from the []byte slice provided. // ParseBytes behaves like Parse but it reads the source from the []byte slice provided.
func ParseBytes(src []byte, errh ErrorHandler, pragh PragmaHandler, mode Mode) (*File, error) { func ParseBytes(base *src.PosBase, src []byte, errh ErrorHandler, pragh PragmaHandler, mode Mode) (*File, error) {
return Parse(&bytesReader{src}, errh, pragh, mode) return Parse(base, &bytesReader{src}, errh, pragh, mode)
} }
type bytesReader struct { type bytesReader struct {
@ -88,13 +87,13 @@ func (r *bytesReader) Read(p []byte) (int, error) {
// ParseFile behaves like Parse but it reads the source from the named file. // ParseFile behaves like Parse but it reads the source from the named file.
func ParseFile(filename string, errh ErrorHandler, pragh PragmaHandler, mode Mode) (*File, error) { func ParseFile(filename string, errh ErrorHandler, pragh PragmaHandler, mode Mode) (*File, error) {
src, err := os.Open(filename) f, err := os.Open(filename)
if err != nil { if err != nil {
if errh != nil { if errh != nil {
errh(err) errh(err)
} }
return nil, err return nil, err
} }
defer src.Close() defer f.Close()
return Parse(src, errh, pragh, mode) return Parse(src.NewFileBase(filename, filename), f, errh, pragh, mode)
} }

Some files were not shown because too many files have changed in this diff Show more