diff --git a/Makefile b/Makefile index 796144f9..5da38bbc 100644 --- a/Makefile +++ b/Makefile @@ -12,11 +12,14 @@ LLC = $(LLVM)llc 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) GCC = arm-none-eabi-gcc LD = arm-none-eabi-ld -T arm.ld +SIZE = arm-none-eabi-size OBJCOPY = arm-none-eabi-objcopy LLFLAGS += -target armv7m-none-eabi TGOFLAGS += -target $(TARGET) @@ -26,17 +29,21 @@ CFLAGS += -I$(CURDIR)/lib/nrfx/mdk CFLAGS += -I$(CURDIR)/lib/CMSIS/CMSIS/Include CFLAGS += -DNRF52832_XXAA CFLAGS += -Wno-uninitialized -RUNTIME += build/runtime_nrf.bc -RUNTIME += build/system_nrf52.bc +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 -else +else ifeq ($(TARGET),unix) # Regular *nix system. GCC = gcc LD = clang +SIZE = size endif +# Make debugging easier by keeping these intermediary files. +SECONDARY: build/hello.ll build/blinky.ll build/blinky.elf + run-hello: build/hello ./build/hello @@ -58,8 +65,8 @@ build/tgo: *.go go build -o build/tgo -i . # Build textual IR with the Go compiler. -build/%.ll: src/examples/% src/examples/%/*.go build/tgo src/runtime/*.go - ./build/tgo $(TGOFLAGS) -printir -o $@ $(subst src/,,$<) +build/%.o: src/examples/% src/examples/%/*.go build/tgo src/runtime/*.go build/runtime-$(TARGET)-combined.bc + ./build/tgo $(TGOFLAGS) -printir -runtime build/runtime-$(TARGET)-combined.bc -o $@ $(subst src/,,$<) # Compile C sources for the runtime. build/%.bc: src/runtime/%.c src/runtime/*.h @@ -76,14 +83,10 @@ build/%.o: lib/nrfx/mdk/gcc_%.S @mkdir -p build clang $(CFLAGS) -c -o $@ $^ -# Merge all LLVM files together in a single bitcode file. -build/%.bc: $(RUNTIME) build/%.ll +# Merge all runtime LLVM files together in a single bitcode file. +build/runtime-$(TARGET)-combined.bc: $(RUNTIME_PARTS) $(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. build/%: build/%.o $(OBJ) $(LD) -o $@ $^ @@ -91,6 +94,7 @@ build/%: build/%.o $(OBJ) # Generate output ELF for use in objcopy (on a microcontroller). build/%.elf: build/%.o $(OBJ) $(LD) -o $@ $^ + $(SIZE) $@ # Convert executable to Intel hex file (for flashing). build/%.hex: build/%.elf diff --git a/src/runtime/runtime.c b/src/runtime/runtime.c index ecad8e0f..4e72f5a0 100644 --- a/src/runtime/runtime.c +++ b/src/runtime/runtime.c @@ -1,15 +1,19 @@ #include "runtime.h" +#include void go_main() __asm__("main.main"); -void __go_runtime_main() { - go_main(); -} - -__attribute__((weak)) int main() { - __go_runtime_main(); + 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; +} diff --git a/src/runtime/runtime_nrf.c b/src/runtime/runtime_nrf.c index 7668a0a4..ea314034 100644 --- a/src/runtime/runtime_nrf.c +++ b/src/runtime/runtime_nrf.c @@ -2,6 +2,7 @@ #include "hal/nrf_uart.h" #include "nrf.h" #include "runtime.h" +#include void uart_init(uint32_t pin_tx) { NRF_UART0->ENABLE = UART_ENABLE_ENABLE_Enabled; @@ -30,9 +31,7 @@ __attribute__((weak)) void __aeabi_memclr(uint8_t *dest, size_t n) { // TODO: link with compiler-rt for a better implementation. // For now, use a simple memory zeroer. - for (size_t i = 0; i < n; i++) { - dest[i] = 0; - } + memset(dest, 0, n); } __attribute__((weak)) diff --git a/tgo.go b/tgo.go index d9ed7663..030f3ecb 100644 --- a/tgo.go +++ b/tgo.go @@ -1033,6 +1033,10 @@ func (c *Compiler) Verify() error { 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) { builder := llvm.NewPassManagerBuilder() defer builder.Dispose() @@ -1079,7 +1083,7 @@ func (c *Compiler) EmitObject(path string) error { } // 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 // TODO: put this somewhere else if target == "pca10040" { @@ -1100,6 +1104,16 @@ func Compile(pkgName, outpath, target string, printIR bool) error { 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 { return err } @@ -1119,20 +1133,21 @@ func Compile(pkgName, outpath, target string, printIR bool) error { func main() { outpath := flag.String("o", "", "output filename") - target := flag.String("target", llvm.DefaultTargetTriple(), "LLVM target") 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() if *outpath == "" || flag.NArg() != 1 { - fmt.Fprintf(os.Stderr, "usage: %s [-printir] [-target=] -o ", os.Args[0]) + fmt.Fprintf(os.Stderr, "usage: %s [-printir] -runtime= [-target=] -o ", os.Args[0]) flag.PrintDefaults() return } 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 { fmt.Fprintln(os.Stderr, "error:", err) os.Exit(1)