Translate bootstrapping main from C to LLVM IR

This avoids needing a C compiler for every platform.
Этот коммит содержится в:
Ayke van Laethem 2018-06-03 17:32:10 +02:00
родитель a9bbed2f6c
коммит 588910792d
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: E97FF5335DFDFDED
4 изменённых файлов: 53 добавлений и 46 удалений

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

@ -9,6 +9,7 @@ tgo: build/tgo
LLVM := $(shell go env GOPATH)/src/llvm.org/llvm/bindings/go/llvm/workdir/llvm_build/bin/
LINK = $(LLVM)llvm-link
LLC = $(LLVM)llc
LLAS = $(LLVM)llvm-as
CFLAGS = -Wall -Werror -Os -g -fno-exceptions -flto -ffunction-sections -fdata-sections $(LLFLAGS)
@ -16,7 +17,14 @@ RUNTIME_PARTS = build/runtime.bc
TARGET ?= unix
ifeq ($(TARGET),pca10040)
ifeq ($(TARGET),unix)
# Regular *nix system.
GCC = gcc
LD = clang
SIZE = size
else ifeq ($(TARGET),pca10040)
# PCA10040: nRF52832 development board
GCC = arm-none-eabi-gcc
LD = arm-none-eabi-ld -T arm.ld --gc-sections
SIZE = arm-none-eabi-size
@ -30,14 +38,12 @@ CFLAGS += -I$(CURDIR)/lib/CMSIS/CMSIS/Include
CFLAGS += -DNRF52832_XXAA
CFLAGS += -Wno-uninitialized
RUNTIME_PARTS += build/runtime_nrf.bc
RUNTIME_PARTS += build/system_nrf52.bc
OBJ += build/startup_nrf51.o # TODO nrf52, see https://bugs.llvm.org/show_bug.cgi?id=31601
RUNTIME_PARTS += build/nrfx_system_nrf52.bc
OBJ += build/nrfx_startup_nrf51.o # TODO nrf52, see https://bugs.llvm.org/show_bug.cgi?id=31601
else
$(error Unknown target)
else ifeq ($(TARGET),unix)
# Regular *nix system.
GCC = gcc
LD = clang
SIZE = size
endif
@ -75,13 +81,17 @@ build/%.bc: src/runtime/%.c src/runtime/*.h
@mkdir -p build
clang $(CFLAGS) -c -o $@ $<
# Compile LLVM bitcode from LLVM source.
build/%.bc: src/runtime/%.ll
$(LLAS) -o $@ $<
# Compile system_* file for the nRF.
build/%.bc: lib/nrfx/mdk/%.c
build/nrfx_%.bc: lib/nrfx/mdk/%.c
@mkdir -p build
clang $(CFLAGS) -c -o $@ $^
# Compile startup_* file for the nRF.
build/%.o: lib/nrfx/mdk/gcc_%.S
build/nrfx_%.o: lib/nrfx/mdk/gcc_%.S
@mkdir -p build
clang $(CFLAGS) -c -o $@ $^

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

@ -1,21 +0,0 @@
#include "runtime.h"
#include <string.h>
void go_init() __asm__("runtime.initAll");
void go_main() __asm__("main.main");
int main() {
go_init();
go_main();
return 0;
}
__attribute__((weak))
void * memset(void *s, int c, size_t n) {
for (size_t i = 0; i < n; i++) {
((uint8_t*)s)[i] = c;
}
return s;
}

10
src/runtime/runtime.ll Обычный файл
Просмотреть файл

@ -0,0 +1,10 @@
source_filename = "runtime/runtime.ll"
declare void @runtime.initAll()
declare void @main.main()
define i32 @main() {
call void @runtime.initAll()
call void @main.main()
ret i32 0
}

34
tgo.go
Просмотреть файл

@ -199,8 +199,12 @@ func (c *Compiler) Parse(mainPath string, buildTags []string) error {
// After all packages are imported, add a synthetic initializer function
// that calls the initializer of each package.
initFn := c.mod.NamedFunction("runtime.initAll")
if initFn.IsNil() {
initType := llvm.FunctionType(llvm.VoidType(), nil, false)
initFn := llvm.AddFunction(c.mod, "runtime.initAll", initType)
initFn = llvm.AddFunction(c.mod, "runtime.initAll", initType)
}
initFn.SetLinkage(llvm.PrivateLinkage)
block := c.ctx.AddBasicBlock(initFn, "entry")
c.builder.SetInsertPointAtEnd(block)
for _, fn := range c.initFuncs {
@ -208,6 +212,11 @@ func (c *Compiler) Parse(mainPath string, buildTags []string) error {
}
c.builder.CreateRetVoid()
// Set functions referenced in runtime.ll to internal linkage, to improve
// optimization (hopefully).
main := c.mod.NamedFunction("main.main")
main.SetLinkage(llvm.PrivateLinkage)
return nil
}
@ -518,6 +527,7 @@ func (c *Compiler) parseFuncDecl(f *ssa.Function) (*Frame, error) {
// Special function parser for generated package initializers (which also
// initializes global variables).
func (c *Compiler) parseInitFunc(frame *Frame, f *ssa.Function) error {
frame.llvmFn.SetLinkage(llvm.PrivateLinkage)
llvmBlock := c.ctx.AddBasicBlock(frame.llvmFn, "entry")
c.builder.SetInsertPointAtEnd(llvmBlock)
@ -605,10 +615,7 @@ func (c *Compiler) parseInitFunc(frame *Frame, f *ssa.Function) error {
}
func (c *Compiler) parseFunc(frame *Frame, f *ssa.Function) error {
if frame.llvmFn.Name() != "main.main" {
// This function is only used from within Go.
frame.llvmFn.SetLinkage(llvm.PrivateLinkage)
}
// Pre-create all basic blocks in the function.
for _, block := range f.DomPreorder() {
@ -1341,15 +1348,7 @@ func Compile(pkgName, runtimePath, outpath, target string, printIR bool) error {
return err
}
parseErr := c.Parse(pkgName, buildTags)
if printIR {
fmt.Println(c.IR())
}
if parseErr != nil {
return parseErr
}
// Add C runtime.
// Add C/LLVM runtime.
runtime, err := llvm.ParseBitcodeFile(runtimePath)
if err != nil {
return err
@ -1359,6 +1358,15 @@ func Compile(pkgName, runtimePath, outpath, target string, printIR bool) error {
return err
}
// Compile Go code to IR.
parseErr := c.Parse(pkgName, buildTags)
if printIR {
fmt.Println(c.IR())
}
if parseErr != nil {
return parseErr
}
c.ApplyFunctionSections() // -ffunction-sections
if err := c.Verify(); err != nil {