all: use compiler-rt for builtins
Этот коммит содержится в:
родитель
e8f211935e
коммит
22da104530
11 изменённых файлов: 350 добавлений и 13 удалений
4
.gitmodules
предоставленный
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
Обычный файл
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
Обычный файл
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
Подмодуль
1
lib/compiler-rt
Подмодуль
|
@ -0,0 +1 @@
|
|||
Subproject commit a4cbb02bca3b952117e9ccfbad8a485857f25935
|
27
main.go
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":
|
||||
|
|
27
target.go
27
target.go
|
@ -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",
|
||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче