Translate bootstrapping main from C to LLVM IR
This avoids needing a C compiler for every platform.
Этот коммит содержится в:
родитель
a9bbed2f6c
коммит
588910792d
4 изменённых файлов: 53 добавлений и 46 удалений
30
Makefile
30
Makefile
|
@ -9,6 +9,7 @@ tgo: build/tgo
|
||||||
LLVM := $(shell go env GOPATH)/src/llvm.org/llvm/bindings/go/llvm/workdir/llvm_build/bin/
|
LLVM := $(shell go env GOPATH)/src/llvm.org/llvm/bindings/go/llvm/workdir/llvm_build/bin/
|
||||||
LINK = $(LLVM)llvm-link
|
LINK = $(LLVM)llvm-link
|
||||||
LLC = $(LLVM)llc
|
LLC = $(LLVM)llc
|
||||||
|
LLAS = $(LLVM)llvm-as
|
||||||
|
|
||||||
CFLAGS = -Wall -Werror -Os -g -fno-exceptions -flto -ffunction-sections -fdata-sections $(LLFLAGS)
|
CFLAGS = -Wall -Werror -Os -g -fno-exceptions -flto -ffunction-sections -fdata-sections $(LLFLAGS)
|
||||||
|
|
||||||
|
@ -16,7 +17,14 @@ RUNTIME_PARTS = build/runtime.bc
|
||||||
|
|
||||||
TARGET ?= unix
|
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
|
GCC = arm-none-eabi-gcc
|
||||||
LD = arm-none-eabi-ld -T arm.ld --gc-sections
|
LD = arm-none-eabi-ld -T arm.ld --gc-sections
|
||||||
SIZE = arm-none-eabi-size
|
SIZE = arm-none-eabi-size
|
||||||
|
@ -30,14 +38,12 @@ CFLAGS += -I$(CURDIR)/lib/CMSIS/CMSIS/Include
|
||||||
CFLAGS += -DNRF52832_XXAA
|
CFLAGS += -DNRF52832_XXAA
|
||||||
CFLAGS += -Wno-uninitialized
|
CFLAGS += -Wno-uninitialized
|
||||||
RUNTIME_PARTS += build/runtime_nrf.bc
|
RUNTIME_PARTS += build/runtime_nrf.bc
|
||||||
RUNTIME_PARTS += build/system_nrf52.bc
|
RUNTIME_PARTS += build/nrfx_system_nrf52.bc
|
||||||
OBJ += build/startup_nrf51.o # TODO nrf52, see https://bugs.llvm.org/show_bug.cgi?id=31601
|
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
|
endif
|
||||||
|
|
||||||
|
|
||||||
|
@ -75,13 +81,17 @@ build/%.bc: src/runtime/%.c src/runtime/*.h
|
||||||
@mkdir -p build
|
@mkdir -p build
|
||||||
clang $(CFLAGS) -c -o $@ $<
|
clang $(CFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
|
# Compile LLVM bitcode from LLVM source.
|
||||||
|
build/%.bc: src/runtime/%.ll
|
||||||
|
$(LLAS) -o $@ $<
|
||||||
|
|
||||||
# Compile system_* file for the nRF.
|
# Compile system_* file for the nRF.
|
||||||
build/%.bc: lib/nrfx/mdk/%.c
|
build/nrfx_%.bc: lib/nrfx/mdk/%.c
|
||||||
@mkdir -p build
|
@mkdir -p build
|
||||||
clang $(CFLAGS) -c -o $@ $^
|
clang $(CFLAGS) -c -o $@ $^
|
||||||
|
|
||||||
# Compile startup_* file for the nRF.
|
# Compile startup_* file for the nRF.
|
||||||
build/%.o: lib/nrfx/mdk/gcc_%.S
|
build/nrfx_%.o: lib/nrfx/mdk/gcc_%.S
|
||||||
@mkdir -p build
|
@mkdir -p build
|
||||||
clang $(CFLAGS) -c -o $@ $^
|
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
Обычный файл
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
|
||||||
|
}
|
38
tgo.go
38
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
|
// After all packages are imported, add a synthetic initializer function
|
||||||
// that calls the initializer of each package.
|
// that calls the initializer of each package.
|
||||||
initType := llvm.FunctionType(llvm.VoidType(), nil, false)
|
initFn := c.mod.NamedFunction("runtime.initAll")
|
||||||
initFn := llvm.AddFunction(c.mod, "runtime.initAll", initType)
|
if initFn.IsNil() {
|
||||||
|
initType := llvm.FunctionType(llvm.VoidType(), nil, false)
|
||||||
|
initFn = llvm.AddFunction(c.mod, "runtime.initAll", initType)
|
||||||
|
}
|
||||||
|
initFn.SetLinkage(llvm.PrivateLinkage)
|
||||||
block := c.ctx.AddBasicBlock(initFn, "entry")
|
block := c.ctx.AddBasicBlock(initFn, "entry")
|
||||||
c.builder.SetInsertPointAtEnd(block)
|
c.builder.SetInsertPointAtEnd(block)
|
||||||
for _, fn := range c.initFuncs {
|
for _, fn := range c.initFuncs {
|
||||||
|
@ -208,6 +212,11 @@ func (c *Compiler) Parse(mainPath string, buildTags []string) error {
|
||||||
}
|
}
|
||||||
c.builder.CreateRetVoid()
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -518,6 +527,7 @@ func (c *Compiler) parseFuncDecl(f *ssa.Function) (*Frame, error) {
|
||||||
// Special function parser for generated package initializers (which also
|
// Special function parser for generated package initializers (which also
|
||||||
// initializes global variables).
|
// initializes global variables).
|
||||||
func (c *Compiler) parseInitFunc(frame *Frame, f *ssa.Function) error {
|
func (c *Compiler) parseInitFunc(frame *Frame, f *ssa.Function) error {
|
||||||
|
frame.llvmFn.SetLinkage(llvm.PrivateLinkage)
|
||||||
llvmBlock := c.ctx.AddBasicBlock(frame.llvmFn, "entry")
|
llvmBlock := c.ctx.AddBasicBlock(frame.llvmFn, "entry")
|
||||||
c.builder.SetInsertPointAtEnd(llvmBlock)
|
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 {
|
func (c *Compiler) parseFunc(frame *Frame, f *ssa.Function) error {
|
||||||
if frame.llvmFn.Name() != "main.main" {
|
frame.llvmFn.SetLinkage(llvm.PrivateLinkage)
|
||||||
// This function is only used from within Go.
|
|
||||||
frame.llvmFn.SetLinkage(llvm.PrivateLinkage)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pre-create all basic blocks in the function.
|
// Pre-create all basic blocks in the function.
|
||||||
for _, block := range f.DomPreorder() {
|
for _, block := range f.DomPreorder() {
|
||||||
|
@ -1341,15 +1348,7 @@ func Compile(pkgName, runtimePath, outpath, target string, printIR bool) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
parseErr := c.Parse(pkgName, buildTags)
|
// Add C/LLVM runtime.
|
||||||
if printIR {
|
|
||||||
fmt.Println(c.IR())
|
|
||||||
}
|
|
||||||
if parseErr != nil {
|
|
||||||
return parseErr
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add C runtime.
|
|
||||||
runtime, err := llvm.ParseBitcodeFile(runtimePath)
|
runtime, err := llvm.ParseBitcodeFile(runtimePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -1359,6 +1358,15 @@ func Compile(pkgName, runtimePath, outpath, target string, printIR bool) error {
|
||||||
return err
|
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
|
c.ApplyFunctionSections() // -ffunction-sections
|
||||||
|
|
||||||
if err := c.Verify(); err != nil {
|
if err := c.Verify(); err != nil {
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче