mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
all: merge dev.inline into master
Change-Id: I7715581a04e513dcda9918e853fa6b1ddc703770
This commit is contained in:
commit
47ce87877b
124 changed files with 6096 additions and 5655 deletions
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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() {
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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": "",
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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},
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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?
|
||||||
|
|
|
||||||
|
|
@ -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")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -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...
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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 }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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")
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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])
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
@ -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
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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() {
|
||||||
|
|
|
||||||
|
|
@ -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
Loading…
Add table
Add a link
Reference in a new issue