compiler: Merge the runtime into the Go code, for better code size
Этот коммит содержится в:
родитель
775445cceb
коммит
2d19bb11ba
4 изменённых файлов: 47 добавлений и 25 удалений
28
Makefile
28
Makefile
|
@ -12,11 +12,14 @@ LLC = $(LLVM)llc
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
RUNTIME = build/runtime.bc
|
RUNTIME_PARTS = build/runtime.bc
|
||||||
|
|
||||||
|
TARGET ?= unix
|
||||||
|
|
||||||
ifeq ($(TARGET),pca10040)
|
ifeq ($(TARGET),pca10040)
|
||||||
GCC = arm-none-eabi-gcc
|
GCC = arm-none-eabi-gcc
|
||||||
LD = arm-none-eabi-ld -T arm.ld
|
LD = arm-none-eabi-ld -T arm.ld
|
||||||
|
SIZE = arm-none-eabi-size
|
||||||
OBJCOPY = arm-none-eabi-objcopy
|
OBJCOPY = arm-none-eabi-objcopy
|
||||||
LLFLAGS += -target armv7m-none-eabi
|
LLFLAGS += -target armv7m-none-eabi
|
||||||
TGOFLAGS += -target $(TARGET)
|
TGOFLAGS += -target $(TARGET)
|
||||||
|
@ -26,17 +29,21 @@ CFLAGS += -I$(CURDIR)/lib/nrfx/mdk
|
||||||
CFLAGS += -I$(CURDIR)/lib/CMSIS/CMSIS/Include
|
CFLAGS += -I$(CURDIR)/lib/CMSIS/CMSIS/Include
|
||||||
CFLAGS += -DNRF52832_XXAA
|
CFLAGS += -DNRF52832_XXAA
|
||||||
CFLAGS += -Wno-uninitialized
|
CFLAGS += -Wno-uninitialized
|
||||||
RUNTIME += build/runtime_nrf.bc
|
RUNTIME_PARTS += build/runtime_nrf.bc
|
||||||
RUNTIME += build/system_nrf52.bc
|
RUNTIME_PARTS += build/system_nrf52.bc
|
||||||
OBJ += build/startup_nrf51.o # TODO nrf52, see https://bugs.llvm.org/show_bug.cgi?id=31601
|
OBJ += build/startup_nrf51.o # TODO nrf52, see https://bugs.llvm.org/show_bug.cgi?id=31601
|
||||||
|
|
||||||
else
|
else ifeq ($(TARGET),unix)
|
||||||
# Regular *nix system.
|
# Regular *nix system.
|
||||||
GCC = gcc
|
GCC = gcc
|
||||||
LD = clang
|
LD = clang
|
||||||
|
SIZE = size
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
||||||
|
# Make debugging easier by keeping these intermediary files.
|
||||||
|
SECONDARY: build/hello.ll build/blinky.ll build/blinky.elf
|
||||||
|
|
||||||
|
|
||||||
run-hello: build/hello
|
run-hello: build/hello
|
||||||
./build/hello
|
./build/hello
|
||||||
|
@ -58,8 +65,8 @@ build/tgo: *.go
|
||||||
go build -o build/tgo -i .
|
go build -o build/tgo -i .
|
||||||
|
|
||||||
# Build textual IR with the Go compiler.
|
# Build textual IR with the Go compiler.
|
||||||
build/%.ll: src/examples/% src/examples/%/*.go build/tgo src/runtime/*.go
|
build/%.o: src/examples/% src/examples/%/*.go build/tgo src/runtime/*.go build/runtime-$(TARGET)-combined.bc
|
||||||
./build/tgo $(TGOFLAGS) -printir -o $@ $(subst src/,,$<)
|
./build/tgo $(TGOFLAGS) -printir -runtime build/runtime-$(TARGET)-combined.bc -o $@ $(subst src/,,$<)
|
||||||
|
|
||||||
# Compile C sources for the runtime.
|
# Compile C sources for the runtime.
|
||||||
build/%.bc: src/runtime/%.c src/runtime/*.h
|
build/%.bc: src/runtime/%.c src/runtime/*.h
|
||||||
|
@ -76,14 +83,10 @@ build/%.o: lib/nrfx/mdk/gcc_%.S
|
||||||
@mkdir -p build
|
@mkdir -p build
|
||||||
clang $(CFLAGS) -c -o $@ $^
|
clang $(CFLAGS) -c -o $@ $^
|
||||||
|
|
||||||
# Merge all LLVM files together in a single bitcode file.
|
# Merge all runtime LLVM files together in a single bitcode file.
|
||||||
build/%.bc: $(RUNTIME) build/%.ll
|
build/runtime-$(TARGET)-combined.bc: $(RUNTIME_PARTS)
|
||||||
$(LINK) -o $@ $^
|
$(LINK) -o $@ $^
|
||||||
|
|
||||||
# Generate an ELF object file from a LLVM bitcode file.
|
|
||||||
build/%.o: build/%.bc
|
|
||||||
$(LLC) -filetype=obj -O2 -o $@ $^
|
|
||||||
|
|
||||||
# Generate output ELF executable.
|
# Generate output ELF executable.
|
||||||
build/%: build/%.o $(OBJ)
|
build/%: build/%.o $(OBJ)
|
||||||
$(LD) -o $@ $^
|
$(LD) -o $@ $^
|
||||||
|
@ -91,6 +94,7 @@ build/%: build/%.o $(OBJ)
|
||||||
# Generate output ELF for use in objcopy (on a microcontroller).
|
# Generate output ELF for use in objcopy (on a microcontroller).
|
||||||
build/%.elf: build/%.o $(OBJ)
|
build/%.elf: build/%.o $(OBJ)
|
||||||
$(LD) -o $@ $^
|
$(LD) -o $@ $^
|
||||||
|
$(SIZE) $@
|
||||||
|
|
||||||
# Convert executable to Intel hex file (for flashing).
|
# Convert executable to Intel hex file (for flashing).
|
||||||
build/%.hex: build/%.elf
|
build/%.hex: build/%.elf
|
||||||
|
|
|
@ -1,15 +1,19 @@
|
||||||
|
|
||||||
#include "runtime.h"
|
#include "runtime.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
void go_main() __asm__("main.main");
|
void go_main() __asm__("main.main");
|
||||||
|
|
||||||
void __go_runtime_main() {
|
|
||||||
go_main();
|
|
||||||
}
|
|
||||||
|
|
||||||
__attribute__((weak))
|
|
||||||
int main() {
|
int main() {
|
||||||
__go_runtime_main();
|
go_main();
|
||||||
|
|
||||||
return 0;
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include "hal/nrf_uart.h"
|
#include "hal/nrf_uart.h"
|
||||||
#include "nrf.h"
|
#include "nrf.h"
|
||||||
#include "runtime.h"
|
#include "runtime.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
void uart_init(uint32_t pin_tx) {
|
void uart_init(uint32_t pin_tx) {
|
||||||
NRF_UART0->ENABLE = UART_ENABLE_ENABLE_Enabled;
|
NRF_UART0->ENABLE = UART_ENABLE_ENABLE_Enabled;
|
||||||
|
@ -30,9 +31,7 @@ __attribute__((weak))
|
||||||
void __aeabi_memclr(uint8_t *dest, size_t n) {
|
void __aeabi_memclr(uint8_t *dest, size_t n) {
|
||||||
// TODO: link with compiler-rt for a better implementation.
|
// TODO: link with compiler-rt for a better implementation.
|
||||||
// For now, use a simple memory zeroer.
|
// For now, use a simple memory zeroer.
|
||||||
for (size_t i = 0; i < n; i++) {
|
memset(dest, 0, n);
|
||||||
dest[i] = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
__attribute__((weak))
|
__attribute__((weak))
|
||||||
|
|
23
tgo.go
23
tgo.go
|
@ -1033,6 +1033,10 @@ func (c *Compiler) Verify() error {
|
||||||
return llvm.VerifyModule(c.mod, 0)
|
return llvm.VerifyModule(c.mod, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Compiler) LinkModule(mod llvm.Module) error {
|
||||||
|
return llvm.LinkModules(c.mod, mod)
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Compiler) Optimize(optLevel, sizeLevel int) {
|
func (c *Compiler) Optimize(optLevel, sizeLevel int) {
|
||||||
builder := llvm.NewPassManagerBuilder()
|
builder := llvm.NewPassManagerBuilder()
|
||||||
defer builder.Dispose()
|
defer builder.Dispose()
|
||||||
|
@ -1079,7 +1083,7 @@ func (c *Compiler) EmitObject(path string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper function for Compiler object.
|
// Helper function for Compiler object.
|
||||||
func Compile(pkgName, outpath, target string, printIR bool) error {
|
func Compile(pkgName, runtimePath, outpath, target string, printIR bool) error {
|
||||||
var buildTags []string
|
var buildTags []string
|
||||||
// TODO: put this somewhere else
|
// TODO: put this somewhere else
|
||||||
if target == "pca10040" {
|
if target == "pca10040" {
|
||||||
|
@ -1100,6 +1104,16 @@ func Compile(pkgName, outpath, target string, printIR bool) error {
|
||||||
return parseErr
|
return parseErr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add C runtime.
|
||||||
|
runtime, err := llvm.ParseBitcodeFile(runtimePath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = c.LinkModule(runtime)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
if err := c.Verify(); err != nil {
|
if err := c.Verify(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -1119,20 +1133,21 @@ func Compile(pkgName, outpath, target string, printIR bool) error {
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
outpath := flag.String("o", "", "output filename")
|
outpath := flag.String("o", "", "output filename")
|
||||||
target := flag.String("target", llvm.DefaultTargetTriple(), "LLVM target")
|
|
||||||
printIR := flag.Bool("printir", false, "print LLVM IR after optimizing")
|
printIR := flag.Bool("printir", false, "print LLVM IR after optimizing")
|
||||||
|
runtime := flag.String("runtime", "", "runtime LLVM bitcode files (from C sources)")
|
||||||
|
target := flag.String("target", llvm.DefaultTargetTriple(), "LLVM target")
|
||||||
|
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
if *outpath == "" || flag.NArg() != 1 {
|
if *outpath == "" || flag.NArg() != 1 {
|
||||||
fmt.Fprintf(os.Stderr, "usage: %s [-printir] [-target=<target>] -o <output> <input>", os.Args[0])
|
fmt.Fprintf(os.Stderr, "usage: %s [-printir] -runtime=<runtime.bc> [-target=<target>] -o <output> <input>", os.Args[0])
|
||||||
flag.PrintDefaults()
|
flag.PrintDefaults()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
os.Setenv("CC", "clang -target=" + *target)
|
os.Setenv("CC", "clang -target=" + *target)
|
||||||
|
|
||||||
err := Compile(flag.Args()[0], *outpath, *target, *printIR)
|
err := Compile(flag.Args()[0], *runtime, *outpath, *target, *printIR)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintln(os.Stderr, "error:", err)
|
fmt.Fprintln(os.Stderr, "error:", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче