all: use compiler-rt for builtins

Этот коммит содержится в:
Ayke van Laethem 2018-10-07 17:37:27 +02:00
родитель e8f211935e
коммит 22da104530
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: E97FF5335DFDFDED
11 изменённых файлов: 350 добавлений и 13 удалений

4
.gitmodules предоставленный
Просмотреть файл

@ -10,3 +10,7 @@
[submodule "lib/cmsis-svd"]
path = lib/cmsis-svd
url = https://github.com/posborne/cmsis-svd
[submodule "lib/compiler-rt"]
path = lib/compiler-rt
url = https://github.com/llvm-mirror/compiler-rt.git
branch = release_70

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

@ -8,8 +8,8 @@ before_install:
- echo "deb http://apt.llvm.org/trusty/ llvm-toolchain-trusty-7 main" | sudo tee -a /etc/apt/sources.list
- echo "deb http://ppa.launchpad.net/ubuntu-toolchain-r/test/ubuntu trusty main" | sudo tee -a /etc/apt/sources.list
- sudo apt-get update -qq
- sudo apt-get install llvm-7-dev gcc-8 gcc-arm-none-eabi --allow-unauthenticated -y
- sudo ln -s /usr/bin/gcc-8 /usr/local/bin/cc # work around missing -no-pie in old GCC version
- sudo apt-get install llvm-7-dev clang-7 gcc-arm-none-eabi --allow-unauthenticated -y
- sudo ln -s /usr/bin/clang-7 /usr/local/bin/cc # work around missing -no-pie in old GCC version
install:
- go get github.com/aykevl/go-llvm

108
buildcache.go Обычный файл
Просмотреть файл

@ -0,0 +1,108 @@
package main
import (
"io"
"os"
"path/filepath"
"time"
)
// Get the cache directory, usually ~/.cache/tinygo
func cacheDir() string {
home := getHomeDir()
dir := filepath.Join(home, ".cache", "tinygo")
return dir
}
// Return the newest timestamp of all the file paths passed in. Used to check
// for stale caches.
func cacheTimestamp(paths []string) (time.Time, error) {
var timestamp time.Time
for _, path := range paths {
st, err := os.Stat(path)
if err != nil {
return time.Time{}, err
}
if timestamp.IsZero() {
timestamp = st.ModTime()
} else if timestamp.Before(st.ModTime()) {
timestamp = st.ModTime()
}
}
return timestamp, nil
}
// Try to load a given file from the cache. Return "", nil if no cached file can
// be found (or the file is stale), return the absolute path if there is a cache
// and return an error on I/O errors.
//
// TODO: the configKey is currently ignored. It is supposed to be used as extra
// data for the cache key, like the compiler version and arguments.
func cacheLoad(name, configKey string, sourceFiles []string) (string, error) {
dir := cacheDir()
cachepath := filepath.Join(dir, name)
cacheStat, err := os.Stat(cachepath)
if os.IsNotExist(err) {
return "", nil // does not exist
} else if err != nil {
return "", err // cannot stat cache file
}
sourceTimestamp, err := cacheTimestamp(sourceFiles)
if err != nil {
return "", err // cannot stat source files
}
if cacheStat.ModTime().After(sourceTimestamp) {
return cachepath, nil
} else {
os.Remove(cachepath)
// stale cache
return "", nil
}
}
// Store the file located at tmppath in the cache with the given name. The
// tmppath may or may not be gone afterwards.
//
// Note: the configKey is ignored, see cacheLoad.
func cacheStore(tmppath, name, configKey string, sourceFiles []string) (string, error) {
// get the last modified time
if len(sourceFiles) == 0 {
panic("cache: no source files")
}
// TODO: check the config key
dir := cacheDir()
err := os.MkdirAll(dir, 0777)
if err != nil {
return "", err
}
cachepath := filepath.Join(dir, name)
err = os.Rename(tmppath, cachepath)
if err != nil {
inf, err := os.Open(tmppath)
if err != nil {
return "", err
}
defer inf.Close()
outf, err := os.Create(cachepath + ".tmp")
if err != nil {
return "", err
}
_, err = io.Copy(outf, inf)
if err != nil {
return "", err
}
err = os.Rename(cachepath+".tmp", cachepath)
if err != nil {
return "", err
}
return cachepath, outf.Close()
}
return cachepath, nil
}

186
builtins.go Обычный файл
Просмотреть файл

@ -0,0 +1,186 @@
package main
import (
"io/ioutil"
"os"
"os/exec"
"path/filepath"
)
// These are the GENERIC_SOURCES according to CMakeList.txt.
var genericBuiltins = []string{
"absvdi2",
"absvsi2",
"absvti2",
"adddf3",
"addsf3",
"addtf3",
"addvdi3",
"addvsi3",
"addvti3",
"apple_versioning",
"ashldi3",
"ashlti3",
"ashrdi3",
"ashrti3",
"bswapdi2",
"bswapsi2",
"clzdi2",
"clzsi2",
"clzti2",
"cmpdi2",
"cmpti2",
"comparedf2",
"comparesf2",
"ctzdi2",
"ctzsi2",
"ctzti2",
"divdc3",
"divdf3",
"divdi3",
"divmoddi4",
"divmodsi4",
"divsc3",
"divsf3",
"divsi3",
"divtc3",
"divti3",
"divtf3",
"extendsfdf2",
"extendhfsf2",
"ffsdi2",
"ffssi2",
"ffsti2",
"fixdfdi",
"fixdfsi",
"fixdfti",
"fixsfdi",
"fixsfsi",
"fixsfti",
"fixunsdfdi",
"fixunsdfsi",
"fixunsdfti",
"fixunssfdi",
"fixunssfsi",
"fixunssfti",
"floatdidf",
"floatdisf",
"floatsidf",
"floatsisf",
"floattidf",
"floattisf",
"floatundidf",
"floatundisf",
"floatunsidf",
"floatunsisf",
"floatuntidf",
"floatuntisf",
//"int_util",
"lshrdi3",
"lshrti3",
"moddi3",
"modsi3",
"modti3",
"muldc3",
"muldf3",
"muldi3",
"mulodi4",
"mulosi4",
"muloti4",
"mulsc3",
"mulsf3",
"multi3",
"multf3",
"mulvdi3",
"mulvsi3",
"mulvti3",
"negdf2",
"negdi2",
"negsf2",
"negti2",
"negvdi2",
"negvsi2",
"negvti2",
"os_version_check",
"paritydi2",
"paritysi2",
"parityti2",
"popcountdi2",
"popcountsi2",
"popcountti2",
"powidf2",
"powisf2",
"powitf2",
"subdf3",
"subsf3",
"subvdi3",
"subvsi3",
"subvti3",
"subtf3",
"trampoline_setup",
"truncdfhf2",
"truncdfsf2",
"truncsfhf2",
"ucmpdi2",
"ucmpti2",
"udivdi3",
"udivmoddi4",
"udivmodsi4",
"udivmodti4",
"udivsi3",
"udivti3",
"umoddi3",
"umodsi3",
"umodti3",
}
// Get the builtins archive, possibly generating it as needed.
func loadBuiltins(target string) (path string, err error) {
outfile := "librt-" + target + ".a"
builtinsDir := filepath.Join(sourceDir(), "lib", "compiler-rt", "lib", "builtins")
srcs := make([]string, len(genericBuiltins))
for i, name := range genericBuiltins {
srcs[i] = filepath.Join(builtinsDir, name+".c")
}
if path, err := cacheLoad(outfile, commands["clang"], srcs); path != "" || err != nil {
return path, err
}
dir, err := ioutil.TempDir("", "tinygo-builtins")
if err != nil {
return "", err
}
defer os.RemoveAll(dir)
// Compile all builtins.
// TODO: use builtins optimized for a given target if available.
objs := make([]string, 0, len(genericBuiltins))
for _, name := range genericBuiltins {
objpath := filepath.Join(dir, name+".o")
objs = append(objs, objpath)
srcpath := filepath.Join(builtinsDir, name+".c")
cmd := exec.Command(commands["clang"], "-c", "-Oz", "-g", "-Werror", "-Wall", "-std=c11", "--target="+target, "-o", objpath, srcpath)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Dir = dir
err = cmd.Run()
if err != nil {
return "", err
}
}
// Put all builtins in an archive to link as a static library.
arpath := filepath.Join(dir, "librt.a")
cmd := exec.Command(commands["ar"], append([]string{"cr", arpath}, objs...)...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Dir = dir
err = cmd.Run()
if err != nil {
return "", err
}
return cacheStore(arpath, outfile, commands["clang"], srcs)
}

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

@ -27,6 +27,8 @@ final binary and flashing it needs some extra tools.
* binutils (``arm-none-eabi-objcopy``) for producing .hex files for
flashing.
* GCC (``arm-none-eabi-gcc``) for linking object files.
* Clang 7 (``clang-7``) for building the `compiler runtime library
<https://compiler-rt.llvm.org/>`_.
* The flashing tool for the particular chip, like ``openocd`` or
``nrfjprog``.

1
lib/compiler-rt Подмодуль

@ -0,0 +1 @@
Subproject commit a4cbb02bca3b952117e9ccfbad8a485857f25935

27
main.go
Просмотреть файл

@ -17,6 +17,11 @@ import (
"github.com/aykevl/tinygo/compiler"
)
var commands = map[string]string{
"ar": "ar",
"clang": "clang-7",
}
// Helper function for Compiler object.
func Compile(pkgName, outpath string, spec *TargetSpec, printIR, dumpSSA, debug bool, printSizes string, action func(string) error) error {
config := compiler.Config{
@ -95,10 +100,24 @@ func Compile(pkgName, outpath string, spec *TargetSpec, printIR, dumpSSA, debug
return err
}
// Load builtins library from the cache, possibly compiling it on the
// fly.
var cachePath string
if spec.CompilerRT {
librt, err := loadBuiltins(spec.Triple)
if err != nil {
return err
}
cachePath, _ = filepath.Split(librt)
}
// Link the object file with the system compiler.
executable := filepath.Join(dir, "main")
tmppath := executable // final file
args := append(spec.PreLinkArgs, "-o", executable, objfile)
if spec.CompilerRT {
args = append(args, "-L", cachePath, "-lrt-"+spec.Triple)
}
cmd := exec.Command(spec.Linker, args...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
@ -371,6 +390,14 @@ func main() {
fmt.Fprintln(os.Stderr, "error:", err)
os.Exit(1)
}
case "clean":
// remove cache directory
dir := cacheDir()
err := os.RemoveAll(dir)
if err != nil {
fmt.Fprintln(os.Stderr, "cannot clean cache:", err)
os.Exit(1)
}
case "help":
usage()
case "run":

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

@ -3,6 +3,7 @@ package main
import (
"encoding/json"
"os"
"os/user"
"path/filepath"
"runtime"
"strings"
@ -17,6 +18,7 @@ type TargetSpec struct {
Triple string `json:"llvm-target"`
BuildTags []string `json:"build-tags"`
Linker string `json:"linker"`
CompilerRT bool `json:"compiler-rt"`
PreLinkArgs []string `json:"pre-link-args"`
Objcopy string `json:"objcopy"`
Flasher string `json:"flash"`
@ -72,16 +74,19 @@ func getGopath() string {
}
// fallback
var home string
if runtime.GOOS == "windows" {
home = os.Getenv("USERPROFILE")
} else {
home = os.Getenv("HOME")
}
if home == "" {
// This is very unlikely, so panic here.
// Not the nicest solution, however.
panic("no $HOME or %USERPROFILE% found")
}
home := getHomeDir()
return filepath.Join(home, "go")
}
func getHomeDir() string {
u, err := user.Current()
if err != nil {
panic("cannot get current user: " + err.Error())
}
if u.HomeDir == "" {
// This is very unlikely, so panic here.
// Not the nicest solution, however.
panic("could not find home directory")
}
return u.HomeDir
}

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

@ -2,6 +2,7 @@
"llvm-target": "armv7m-none-eabi",
"build-tags": ["bluepill", "stm32f103xx", "stm32", "arm", "js", "wasm"],
"linker": "arm-none-eabi-gcc",
"compiler-rt": true,
"pre-link-args": ["-nostdlib", "-nostartfiles", "-mcpu=cortex-m3", "-mthumb", "-T", "targets/stm32.ld", "-Wl,--gc-sections", "-fno-exceptions", "-fno-unwind-tables", "-ffunction-sections", "-fdata-sections", "-Os", "src/device/stm32/stm32f103xx.s"],
"objcopy": "arm-none-eabi-objcopy",
"flash": "openocd -f interface/stlink-v2.cfg -f target/stm32f1x.cfg -c 'program {hex} reset exit'"

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

@ -2,6 +2,7 @@
"llvm-target": "armv6m-none-eabi",
"build-tags": ["microbit", "nrf51822", "nrf51", "nrf", "arm", "js", "wasm"],
"linker": "arm-none-eabi-gcc",
"compiler-rt": true,
"pre-link-args": [
"-nostdlib",
"-nostartfiles",
@ -11,6 +12,7 @@
"-Wl,--gc-sections",
"-fno-exceptions", "-fno-unwind-tables",
"-ffunction-sections", "-fdata-sections",
"-fno-short-enums",
"-Os",
"-DNRF51",
"-Ilib/CMSIS/CMSIS/Include",

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

@ -2,6 +2,7 @@
"llvm-target": "armv7em-none-eabi",
"build-tags": ["pca10040", "nrf52832", "nrf52", "nrf", "arm", "js", "wasm"],
"linker": "arm-none-eabi-gcc",
"compiler-rt": true,
"pre-link-args": [
"-nostdlib",
"-nostartfiles",