Implement //go:linkname pragma
Этот коммит содержится в:
родитель
906e061e37
коммит
771f23e320
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
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)
|
||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче