Move string printing to runtime
Этот коммит содержится в:
родитель
7ffb73b407
коммит
d08ff64d1d
4 изменённых файлов: 105 добавлений и 33 удалений
15
Makefile
15
Makefile
|
@ -3,19 +3,24 @@ all: tgo
|
||||||
tgo: build/tgo
|
tgo: build/tgo
|
||||||
test: build/hello.o
|
test: build/hello.o
|
||||||
|
|
||||||
.PHONY: all tgo test test-run clean
|
CFLAGS = -Wall -Werror -O2 -g -flto
|
||||||
|
|
||||||
|
.PHONY: all tgo test run-test clean
|
||||||
|
|
||||||
build/tgo: *.go
|
build/tgo: *.go
|
||||||
@mkdir -p build
|
@mkdir -p build
|
||||||
@go build -o build/tgo -i .
|
@go build -o build/tgo -i .
|
||||||
|
|
||||||
build/hello.o: build/tgo hello/hello.go
|
build/hello.o: build/tgo hello/hello.go
|
||||||
@./build/tgo -printir -target x86_64-pc-linux-gnu -o build/hello.o hello/hello.go
|
@./build/tgo -printir -o build/hello.o hello/hello.go
|
||||||
|
|
||||||
build/hello: build/hello.o
|
build/runtime.o: runtime/*.c runtime/*.h
|
||||||
@clang -o build/hello build/hello.o
|
clang $(CFLAGS) -c -o $@ runtime/*.c
|
||||||
|
|
||||||
test-run: build/hello
|
build/hello: build/hello.o build/runtime.o
|
||||||
|
@clang $(CFLAGS) -o $@ $^
|
||||||
|
|
||||||
|
run-test: build/hello
|
||||||
@./build/hello
|
@./build/hello
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
|
|
30
runtime/runtime.c
Обычный файл
30
runtime/runtime.c
Обычный файл
|
@ -0,0 +1,30 @@
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "runtime.h"
|
||||||
|
|
||||||
|
void __go_printstring(char *str) {
|
||||||
|
write(STDOUT_FILENO, str, strlen(str));
|
||||||
|
}
|
||||||
|
|
||||||
|
void __go_printspace() {
|
||||||
|
write(STDOUT_FILENO, " ", 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void __go_printnl() {
|
||||||
|
write(STDOUT_FILENO, "\n", 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void go_main() __asm__("main.main");
|
||||||
|
|
||||||
|
void __go_runtime_main() {
|
||||||
|
go_main();
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((weak))
|
||||||
|
int main() {
|
||||||
|
__go_runtime_main();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
12
runtime/runtime.h
Обычный файл
12
runtime/runtime.h
Обычный файл
|
@ -0,0 +1,12 @@
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t length; // TODO: size_t
|
||||||
|
uint8_t *data;
|
||||||
|
} string_t;
|
||||||
|
|
||||||
|
void __go_printstring(char *str);
|
||||||
|
void __go_printnl();
|
73
tgo.go
73
tgo.go
|
@ -27,7 +27,9 @@ type Compiler struct {
|
||||||
ctx llvm.Context
|
ctx llvm.Context
|
||||||
builder llvm.Builder
|
builder llvm.Builder
|
||||||
machine llvm.TargetMachine
|
machine llvm.TargetMachine
|
||||||
putsFunc llvm.Value
|
printstringFunc llvm.Value
|
||||||
|
printspaceFunc llvm.Value
|
||||||
|
printnlFunc llvm.Value
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCompiler(path, triplet string) (*Compiler, error) {
|
func NewCompiler(path, triplet string) (*Compiler, error) {
|
||||||
|
@ -43,8 +45,12 @@ func NewCompiler(path, triplet string) (*Compiler, error) {
|
||||||
c.ctx = c.mod.Context()
|
c.ctx = c.mod.Context()
|
||||||
c.builder = c.ctx.NewBuilder()
|
c.builder = c.ctx.NewBuilder()
|
||||||
|
|
||||||
putsType := llvm.FunctionType(llvm.Int32Type(), []llvm.Type{llvm.PointerType(llvm.Int8Type(), 0)}, false)
|
printstringType := llvm.FunctionType(llvm.VoidType(), []llvm.Type{llvm.PointerType(llvm.Int8Type(), 0)}, false)
|
||||||
c.putsFunc = llvm.AddFunction(c.mod, "puts", putsType)
|
c.printstringFunc = llvm.AddFunction(c.mod, "__go_printstring", printstringType)
|
||||||
|
printspaceType := llvm.FunctionType(llvm.VoidType(), nil, false)
|
||||||
|
c.printspaceFunc = llvm.AddFunction(c.mod, "__go_printspace", printspaceType)
|
||||||
|
printnlType := llvm.FunctionType(llvm.VoidType(), nil, false)
|
||||||
|
c.printnlFunc = llvm.AddFunction(c.mod, "__go_printnl", printnlType)
|
||||||
|
|
||||||
return c, nil
|
return c, nil
|
||||||
}
|
}
|
||||||
|
@ -66,7 +72,7 @@ func (c *Compiler) Parse(path string) error {
|
||||||
}
|
}
|
||||||
fmt.Println("package:", pkgInfo.Pkg.Name())
|
fmt.Println("package:", pkgInfo.Pkg.Name())
|
||||||
for _, file := range pkgInfo.Files {
|
for _, file := range pkgInfo.Files {
|
||||||
err := c.parseFile(file)
|
err := c.parseFile(pkgInfo.Pkg.Name(), file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -75,16 +81,11 @@ func (c *Compiler) Parse(path string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Compiler) IR() string {
|
func (c *Compiler) parseFile(pkgName string, file *ast.File) error {
|
||||||
return c.mod.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
func (c *Compiler) parseFile(file *ast.File) error {
|
|
||||||
for _, decl := range file.Decls {
|
for _, decl := range file.Decls {
|
||||||
switch v := decl.(type) {
|
switch v := decl.(type) {
|
||||||
case *ast.FuncDecl:
|
case *ast.FuncDecl:
|
||||||
err := c.parseFunc(v)
|
err := c.parseFunc(pkgName, v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -96,11 +97,17 @@ func (c *Compiler) parseFile(file *ast.File) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Compiler) parseFunc(f *ast.FuncDecl) error {
|
func (c *Compiler) parseFunc(pkgName string, f *ast.FuncDecl) error {
|
||||||
fmt.Println("func:", f.Name)
|
fmt.Println("func:", f.Name)
|
||||||
|
|
||||||
fnType := llvm.FunctionType(llvm.Int32Type(), nil, false)
|
var fnType llvm.Type
|
||||||
fn := llvm.AddFunction(c.mod, f.Name.Name, fnType)
|
if f.Type.Results == nil {
|
||||||
|
fnType = llvm.FunctionType(llvm.VoidType(), nil, false)
|
||||||
|
} else {
|
||||||
|
return errors.New("todo: return values")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn := llvm.AddFunction(c.mod, pkgName + "." + f.Name.Name, fnType)
|
||||||
start := c.ctx.AddBasicBlock(fn, "start")
|
start := c.ctx.AddBasicBlock(fn, "start")
|
||||||
c.builder.SetInsertPointAtEnd(start)
|
c.builder.SetInsertPointAtEnd(start)
|
||||||
|
|
||||||
|
@ -112,7 +119,11 @@ func (c *Compiler) parseFunc(f *ast.FuncDecl) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
c.builder.CreateRet(llvm.ConstInt(llvm.Int32Type(), 0, false))
|
if f.Type.Results == nil {
|
||||||
|
c.builder.CreateRetVoid()
|
||||||
|
//} else if len(f.Type.Results.List) == 1 {
|
||||||
|
// c.builder.CreateRet(llvm.ConstInt(llvm.Int32Type(), 0, false))
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,26 +143,32 @@ func (c *Compiler) parseStmt(stmt ast.Node) error {
|
||||||
func (c *Compiler) parseExpr(expr ast.Expr) error {
|
func (c *Compiler) parseExpr(expr ast.Expr) error {
|
||||||
switch v := expr.(type) {
|
switch v := expr.(type) {
|
||||||
case *ast.CallExpr:
|
case *ast.CallExpr:
|
||||||
values := []llvm.Value{}
|
|
||||||
|
|
||||||
zero := llvm.ConstInt(llvm.Int32Type(), 0, false)
|
zero := llvm.ConstInt(llvm.Int32Type(), 0, false)
|
||||||
name := v.Fun.(*ast.Ident).Name
|
name := v.Fun.(*ast.Ident).Name
|
||||||
fmt.Printf(" call: %s\n", name)
|
fmt.Printf(" call: %s\n", name)
|
||||||
|
|
||||||
if name != "println" {
|
printnl := false
|
||||||
return errors.New("implement anything other than println()")
|
if name == "println" {
|
||||||
|
printnl = true
|
||||||
|
} else if name == "print" {
|
||||||
|
} else {
|
||||||
|
return errors.New("todo: call anything other than println()")
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, arg := range v.Args {
|
for i, arg := range v.Args {
|
||||||
|
if i >= 1 {
|
||||||
|
c.builder.CreateCall(c.printspaceFunc, nil, "")
|
||||||
|
}
|
||||||
switch arg := arg.(type) {
|
switch arg := arg.(type) {
|
||||||
case *ast.BasicLit:
|
case *ast.BasicLit:
|
||||||
fmt.Printf(" arg: %s\n", arg.Value)
|
fmt.Printf(" arg: %s\n", arg.Value)
|
||||||
val := constant.MakeFromLiteral(arg.Value, arg.Kind, 0)
|
val := constant.MakeFromLiteral(arg.Value, arg.Kind, 0)
|
||||||
switch arg.Kind {
|
switch arg.Kind {
|
||||||
case token.STRING:
|
case token.STRING:
|
||||||
msg := c.builder.CreateGlobalString(constant.StringVal(val) + "\x00", "")
|
str := constant.StringVal(val)
|
||||||
msgCast := c.builder.CreateGEP(msg, []llvm.Value{zero, zero}, "")
|
strObj := c.builder.CreateGlobalString(str + "\x00", "")
|
||||||
values = append(values, msgCast)
|
msgCast := c.builder.CreateGEP(strObj, []llvm.Value{zero, zero}, "")
|
||||||
|
c.builder.CreateCall(c.printstringFunc, []llvm.Value{msgCast}, "")
|
||||||
default:
|
default:
|
||||||
return errors.New("todo: print anything other than strings")
|
return errors.New("todo: print anything other than strings")
|
||||||
}
|
}
|
||||||
|
@ -159,13 +176,20 @@ func (c *Compiler) parseExpr(expr ast.Expr) error {
|
||||||
return errors.New("unknown arg type")
|
return errors.New("unknown arg type")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
c.builder.CreateCall(c.putsFunc, values, "")
|
if printnl {
|
||||||
|
c.builder.CreateCall(c.printnlFunc, nil, "")
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
return errors.New("unknown expr")
|
return errors.New("unknown expr")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IR returns the whole IR as a human-readable string.
|
||||||
|
func (c *Compiler) IR() string {
|
||||||
|
return c.mod.String()
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Compiler) Verify() error {
|
func (c *Compiler) Verify() error {
|
||||||
return llvm.VerifyModule(c.mod, llvm.PrintMessageAction)
|
return llvm.VerifyModule(c.mod, llvm.PrintMessageAction)
|
||||||
}
|
}
|
||||||
|
@ -201,6 +225,7 @@ func (c *Compiler) EmitObject(path string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Helper function for Compiler object.
|
||||||
func Compile(inpath, outpath, target string, printIR bool) error {
|
func Compile(inpath, outpath, target string, printIR bool) error {
|
||||||
c, err := NewCompiler(inpath, target)
|
c, err := NewCompiler(inpath, target)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче