Implement //go:linkname pragma

Этот коммит содержится в:
Ayke van Laethem 2018-08-30 22:27:19 +02:00
родитель 906e061e37
коммит 771f23e320
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: E97FF5335DFDFDED
3 изменённых файлов: 46 добавлений и 1 удалений

Просмотреть файл

@ -13,6 +13,7 @@ import (
"strings"
"github.com/aykevl/llvm/bindings/go/llvm"
"go/parser"
"golang.org/x/tools/go/loader"
"golang.org/x/tools/go/ssa"
"golang.org/x/tools/go/ssa/ssautil"
@ -139,6 +140,7 @@ func (c *Compiler) Parse(mainPath string, buildTags []string) error {
Compiler: "gc", // must be one of the recognized compilers
BuildTags: append([]string{"tgo"}, buildTags...),
},
ParserMode: parser.ParseComments,
AllowErrors: true,
}
config.Import("runtime")
@ -155,7 +157,7 @@ func (c *Compiler) Parse(mainPath string, buildTags []string) error {
}
}
program := ssautil.CreateProgram(lprogram, ssa.SanityCheckFunctions|ssa.BareInits)
program := ssautil.CreateProgram(lprogram, ssa.SanityCheckFunctions|ssa.BareInits|ssa.GlobalDebug)
program.Build()
c.ir = NewProgram(program, mainPath)
@ -1067,6 +1069,8 @@ func (c *Compiler) parseInstr(frame *Frame, instr ssa.Instruction) error {
}
frame.locals[instr] = value
return err
case *ssa.DebugRef:
return nil // ignore
case *ssa.Go:
if instr.Common().Method != nil {
return errors.New("todo: go on method receiver")

Просмотреть файл

@ -128,6 +128,8 @@ func (p *Program) interpret(instrs []ssa.Instruction, paramKeys []*ssa.Parameter
default:
return i, errors.New("todo: init: unknown convert: " + instr.String())
}
case *ssa.DebugRef:
// ignore
case *ssa.FieldAddr:
x, err := p.getValue(instr.X, locals)
if err != nil {
@ -273,6 +275,7 @@ func canInterpret(callee *ssa.Function) bool {
// above.
case *ssa.Alloc:
case *ssa.Convert:
case *ssa.DebugRef:
case *ssa.FieldAddr:
case *ssa.IndexAddr:
case *ssa.MakeInterface:

38
ir.go
Просмотреть файл

@ -1,6 +1,7 @@
package main
import (
"go/ast"
"go/types"
"sort"
"strings"
@ -33,6 +34,7 @@ type Program struct {
type Function struct {
fn *ssa.Function
llvmFn llvm.Value
linkName string
blocking bool
flag bool // used by dead code elimination
parents []*Function // calculated by AnalyseCallgraph
@ -117,6 +119,39 @@ func (p *Program) addFunction(ssaFn *ssa.Function) {
f := &Function{fn: ssaFn}
p.Functions = append(p.Functions, f)
p.functionMap[ssaFn] = f
// Parse compiler directives in the preceding comments.
if f.fn.Syntax() != nil && f.fn.Syntax().(*ast.FuncDecl).Doc != nil {
for _, comment := range f.fn.Syntax().(*ast.FuncDecl).Doc.List {
if !strings.HasPrefix(comment.Text, "//go:") {
continue
}
parts := strings.Fields(comment.Text)
switch parts[0] {
case "//go:linkname":
if len(parts) != 3 || parts[1] != ssaFn.Name() {
continue
}
// Only enable go:linkname when the package imports "unsafe".
// This is a slightly looser requirement than what gc uses: gc
// requires the file to import "unsafe", not the package as a
// whole.
if hasUnsafeImport(ssaFn.Pkg.Pkg) {
f.linkName = parts[2]
}
}
}
}
}
// Return true if this package imports "unsafe", false otherwise.
func hasUnsafeImport(pkg *types.Package) bool {
for _, imp := range pkg.Imports() {
if imp == types.Unsafe {
return true
}
}
return false
}
func (p *Program) GetFunction(ssaFn *ssa.Function) *Function {
@ -129,6 +164,9 @@ func (p *Program) GetGlobal(ssaGlobal *ssa.Global) *Global {
// Return the link name for this function.
func (f *Function) LinkName() string {
if f.linkName != "" {
return f.linkName
}
if f.fn.Signature.Recv() != nil {
// Method on a defined type (which may be a pointer).
return f.fn.RelString(nil)