Blob Blame History Raw
From cff70b542db4a8b99e4445c555f70dad32337e5c Mon Sep 17 00:00:00 2001
From: Ayke van Laethem <aykevanlaethem@gmail.com>
Date: Sun, 28 Mar 2021 19:56:03 -0400
Subject: [PATCH 6/9] all: add LLVM 12 support

Originally based on a PR by @QuLogic, but extended a lot to get all
tests to pass.

Signed-off-by: Elliott Sales de Andrade <quantum.analyst@gmail.com>
---
 .circleci/config.yml                 | 18 +++++++++---------
 .github/workflows/windows.yml        |  4 ++--
 Makefile                             | 14 ++++++--------
 cgo/libclang_config.go               |  1 +
 cgo/libclang_config_llvm12.go        | 14 ++++++++++++++
 compileopts/target.go                | 14 ++++++++++++++
 compiler/compiler_test.go            | 27 ++++++++++++++++++++++-----
 compiler/testdata/channel.ll         |  6 +++---
 compiler/testdata/intrinsics-wasm.ll |  6 +++---
 go.mod                               |  4 ++--
 go.sum                               | 10 ++++------
 interp/interp_test.go                |  1 +
 transform/maps_test.go               |  1 +
 transform/testdata/coroutines.out.ll |  6 +++---
 transform/transform_test.go          |  3 ++-
 15 files changed, 87 insertions(+), 42 deletions(-)
 create mode 100644 cgo/libclang_config_llvm12.go

diff --git a/.circleci/config.yml b/.circleci/config.yml
index 61c7e287..50bdd087 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -52,12 +52,12 @@ commands:
     steps:
       - restore_cache:
           keys:
-            - llvm-source-11-v2
+            - llvm-source-12-v1
       - run:
           name: "Fetch LLVM source"
           command: make llvm-source
       - save_cache:
-          key: llvm-source-11-v2
+          key: llvm-source-12-v1
           paths:
             - llvm-project/clang/lib/Headers
             - llvm-project/clang/include
@@ -332,12 +332,12 @@ commands:
             - go-cache-macos-v3-{{ checksum "go.mod" }}
       - restore_cache:
           keys:
-            - llvm-source-11-macos-v3
+            - llvm-source-12-macos-v1
       - run:
           name: "Fetch LLVM source"
           command: make llvm-source
       - save_cache:
-          key: llvm-source-11-macos-v3
+          key: llvm-source-12-macos-v1
           paths:
             - llvm-project/clang/lib/Headers
             - llvm-project/clang/include
@@ -345,7 +345,7 @@ commands:
             - llvm-project/llvm/include
       - restore_cache:
           keys:
-            - llvm-build-11-macos-v5
+            - llvm-build-12-macos-v1
       - run:
           name: "Build LLVM"
           command: |
@@ -359,7 +359,7 @@ commands:
               find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
             fi
       - save_cache:
-          key: llvm-build-11-macos-v5
+          key: llvm-build-12-macos-v1
           paths:
             llvm-build
       - restore_cache:
@@ -418,12 +418,12 @@ jobs:
     steps:
       - test-linux:
           llvm: "11"
-  test-llvm11-go116:
+  test-llvm12-go116:
     docker:
       - image: circleci/golang:1.16-buster
     steps:
       - test-linux:
-          llvm: "11"
+          llvm: "12"
   assert-test-linux:
     docker:
       - image: circleci/golang:1.17-buster
@@ -451,7 +451,7 @@ workflows:
   test-all:
     jobs:
       - test-llvm11-go115
-      - test-llvm11-go116
+      - test-llvm12-go116
       - build-linux
       - test-linux-build:
           requires:
diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml
index 4bc07d59..8649f635 100644
--- a/.github/workflows/windows.yml
+++ b/.github/workflows/windows.yml
@@ -27,7 +27,7 @@ jobs:
         uses: actions/cache@v2
         id: cache-llvm-source
         with:
-          key: llvm-source-11-windows-v1
+          key: llvm-source-12-windows-v1
           path: |
             llvm-project/clang/lib/Headers
             llvm-project/clang/include
@@ -40,7 +40,7 @@ jobs:
         uses: actions/cache@v2
         id: cache-llvm-build
         with:
-          key: llvm-build-11-windows-v2
+          key: llvm-build-12-windows-v1
           path: llvm-build
       - name: Build LLVM
         if: steps.cache-llvm-build.outputs.cache-hit != 'true'
diff --git a/Makefile b/Makefile
index 5de97014..0ebfcd82 100644
--- a/Makefile
+++ b/Makefile
@@ -59,18 +59,13 @@ ifeq ($(OS),Windows_NT)
 
     BINARYEN_OPTION += -DCMAKE_EXE_LINKER_FLAGS='-static-libgcc -static-libstdc++'
 
-    LIBCLANG_NAME = libclang
-
 else ifeq ($(shell uname -s),Darwin)
     MD5SUM = md5
-    LIBCLANG_NAME = clang
 else ifeq ($(shell uname -s),FreeBSD)
     MD5SUM = md5
-    LIBCLANG_NAME = clang
     START_GROUP = -Wl,--start-group
     END_GROUP = -Wl,--end-group
 else
-    LIBCLANG_NAME = clang
     START_GROUP = -Wl,--start-group
     END_GROUP = -Wl,--end-group
 endif
@@ -86,19 +81,22 @@ LLD_LIBS = $(START_GROUP) $(addprefix -l,$(LLD_LIB_NAMES)) $(END_GROUP)
 # Other libraries that are needed to link TinyGo.
 EXTRA_LIB_NAMES = LLVMInterpreter
 
+# All libraries to be built and linked with the tinygo binary (lib/lib*.a).
+LIB_NAMES = clang $(CLANG_LIB_NAMES) $(LLD_LIB_NAMES) $(EXTRA_LIB_NAMES)
+
 # These build targets appear to be the only ones necessary to build all TinyGo
 # dependencies. Only building a subset significantly speeds up rebuilding LLVM.
 # The Makefile rules convert a name like lldELF to lib/liblldELF.a to match the
 # library path (for ninja).
 # This list also includes a few tools that are necessary as part of the full
 # TinyGo build.
-NINJA_BUILD_TARGETS = clang llvm-config llvm-ar llvm-nm $(addprefix lib/lib,$(addsuffix .a,$(LIBCLANG_NAME) $(CLANG_LIB_NAMES) $(LLD_LIB_NAMES) $(EXTRA_LIB_NAMES)))
+NINJA_BUILD_TARGETS = clang llvm-config llvm-ar llvm-nm $(addprefix lib/lib,$(addsuffix .a,$(LIB_NAMES)))
 
 # For static linking.
 ifneq ("$(wildcard $(LLVM_BUILDDIR)/bin/llvm-config*)","")
     CGO_CPPFLAGS+=$(shell $(LLVM_BUILDDIR)/bin/llvm-config --cppflags) -I$(abspath $(LLVM_BUILDDIR))/tools/clang/include -I$(abspath $(CLANG_SRC))/include -I$(abspath $(LLD_SRC))/include
     CGO_CXXFLAGS=-std=c++14
-    CGO_LDFLAGS+=$(abspath $(LLVM_BUILDDIR))/lib/lib$(LIBCLANG_NAME).a -L$(abspath $(LLVM_BUILDDIR)/lib) $(CLANG_LIBS) $(LLD_LIBS) $(shell $(LLVM_BUILDDIR)/bin/llvm-config --ldflags --libs --system-libs $(LLVM_COMPONENTS)) -lstdc++ $(CGO_LDFLAGS_EXTRA)
+    CGO_LDFLAGS+=-L$(abspath $(LLVM_BUILDDIR)/lib) -lclang $(CLANG_LIBS) $(LLD_LIBS) $(shell $(LLVM_BUILDDIR)/bin/llvm-config --ldflags --libs --system-libs $(LLVM_COMPONENTS)) -lstdc++ $(CGO_LDFLAGS_EXTRA)
 endif
 
 
@@ -162,7 +160,7 @@ gen-device-rp: build/gen-device-svd
 
 # Get LLVM sources.
 $(LLVM_PROJECTDIR)/llvm:
-	git clone -b xtensa_release_11.0.0 --depth=1 https://github.com/tinygo-org/llvm-project $(LLVM_PROJECTDIR)
+	git clone -b xtensa_release_12.0.1 --depth=1 https://github.com/tinygo-org/llvm-project $(LLVM_PROJECTDIR)
 llvm-source: $(LLVM_PROJECTDIR)/llvm
 
 # Configure LLVM.
diff --git a/cgo/libclang_config.go b/cgo/libclang_config.go
index 4b4ce2db..9f7cdc1c 100644
--- a/cgo/libclang_config.go
+++ b/cgo/libclang_config.go
@@ -1,4 +1,5 @@
 // +build !byollvm
+// +build !llvm12
 
 package cgo
 
diff --git a/cgo/libclang_config_llvm12.go b/cgo/libclang_config_llvm12.go
new file mode 100644
index 00000000..1837cc15
--- /dev/null
+++ b/cgo/libclang_config_llvm12.go
@@ -0,0 +1,14 @@
+// +build !byollvm
+// +build llvm12
+
+package cgo
+
+/*
+#cgo linux   CFLAGS:  -I/usr/lib/llvm-12/include
+#cgo darwin  CFLAGS:  -I/usr/local/opt/llvm@12/include
+#cgo freebsd CFLAGS:  -I/usr/local/llvm12/include
+#cgo linux   LDFLAGS: -L/usr/lib/llvm-12/lib -lclang
+#cgo darwin  LDFLAGS: -L/usr/local/opt/llvm@12/lib -lclang -lffi
+#cgo freebsd LDFLAGS: -L/usr/local/llvm12/lib -lclang
+*/
+import "C"
diff --git a/compileopts/target.go b/compileopts/target.go
index bdd77613..57b5bd84 100644
--- a/compileopts/target.go
+++ b/compileopts/target.go
@@ -12,9 +12,11 @@ import (
 	"path/filepath"
 	"reflect"
 	"runtime"
+	"strconv"
 	"strings"
 
 	"github.com/tinygo-org/tinygo/goenv"
+	"tinygo.org/x/go-llvm"
 )
 
 // Target specification for a given target. Used for bare metal targets.
@@ -280,6 +282,12 @@ func defaultTarget(goos, goarch, triple string) (*TargetSpec, error) {
 	} else if goos == "windows" {
 		spec.Linker = "ld.lld"
 		spec.Libc = "mingw-w64"
+		// Note: using a medium code model, low image base and no ASLR
+		// because Go doesn't really need those features. ASLR patches
+		// around issues for unsafe languages like C/C++ that are not
+		// normally present in Go (without explicitly opting in).
+		// For more discussion:
+		// https://groups.google.com/g/Golang-nuts/c/Jd9tlNc6jUE/m/Zo-7zIP_m3MJ?pli=1
 		spec.LDFlags = append(spec.LDFlags,
 			"-m", "i386pep",
 			"-Bdynamic",
@@ -287,6 +295,12 @@ func defaultTarget(goos, goarch, triple string) (*TargetSpec, error) {
 			"--gc-sections",
 			"--no-insert-timestamp",
 		)
+		llvmMajor, _ := strconv.Atoi(strings.Split(llvm.Version, ".")[0])
+		if llvmMajor >= 12 {
+			// This flag was added in LLVM 12. At the same time, LLVM 12
+			// switched the default from --dynamicbase to --no-dynamicbase.
+			spec.LDFlags = append(spec.LDFlags, "--no-dynamicbase")
+		}
 	} else {
 		spec.LDFlags = append(spec.LDFlags, "-no-pie", "-Wl,--gc-sections") // WARNING: clang < 5.0 requires -nopie
 	}
diff --git a/compiler/compiler_test.go b/compiler/compiler_test.go
index cbf89fe2..3c978274 100644
--- a/compiler/compiler_test.go
+++ b/compiler/compiler_test.go
@@ -41,6 +41,13 @@ func TestCompiler(t *testing.T) {
 		t.Skip("compiler tests require LLVM 11 or above, got LLVM ", llvm.Version)
 	}
 
+	// Determine Go minor version (e.g. 16 in go1.16.3).
+	_, goMinor, err := goenv.GetGorootVersion(goenv.Get("GOROOT"))
+	if err != nil {
+		t.Fatal("could not read Go version:", err)
+	}
+
+	// Determine which tests to run, depending on the Go and LLVM versions.
 	tests := []testCase{
 		{"basic.go", "", ""},
 		{"pointer.go", "", ""},
@@ -58,12 +65,11 @@ func TestCompiler(t *testing.T) {
 		{"intrinsics.go", "wasm", ""},
 		{"gc.go", "", ""},
 	}
-
-	_, minor, err := goenv.GetGorootVersion(goenv.Get("GOROOT"))
-	if err != nil {
-		t.Fatal("could not read Go version:", err)
+	if llvmMajor >= 12 {
+		tests = append(tests, testCase{"intrinsics.go", "cortex-m-qemu", ""})
+		tests = append(tests, testCase{"intrinsics.go", "wasm", ""})
 	}
-	if minor >= 17 {
+	if goMinor >= 17 {
 		tests = append(tests, testCase{"go1.17.go", "", ""})
 	}
 
@@ -201,6 +207,12 @@ func fuzzyEqualIR(s1, s2 string) bool {
 // stripped out.
 func filterIrrelevantIRLines(lines []string) []string {
 	var out []string
+	llvmVersion, err := strconv.Atoi(strings.Split(llvm.Version, ".")[0])
+	if err != nil {
+		// Note: this should never happen and if it does, it will always happen
+		// for a particular build because llvm.Version is a constant.
+		panic(err)
+	}
 	for _, line := range lines {
 		line = strings.Split(line, ";")[0]    // strip out comments/info
 		line = strings.TrimRight(line, "\r ") // drop '\r' on Windows and remove trailing spaces from comments
@@ -210,6 +222,11 @@ func filterIrrelevantIRLines(lines []string) []string {
 		if strings.HasPrefix(line, "source_filename = ") {
 			continue
 		}
+		if llvmVersion < 12 && strings.HasPrefix(line, "attributes ") {
+			// Ignore attribute groups. These may change between LLVM versions.
+			// Right now test outputs are for LLVM 12.
+			continue
+		}
 		out = append(out, line)
 	}
 	return out
diff --git a/compiler/testdata/channel.ll b/compiler/testdata/channel.ll
index 04bfa4af..36d7fd96 100644
--- a/compiler/testdata/channel.ll
+++ b/compiler/testdata/channel.ll
@@ -34,12 +34,12 @@ entry:
   ret void
 }
 
-; Function Attrs: argmemonly nounwind willreturn
+; Function Attrs: argmemonly nofree nosync nounwind willreturn
 declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) #1
 
 declare void @runtime.chanSend(%runtime.channel* dereferenceable_or_null(32), i8*, %runtime.channelBlockedList* dereferenceable_or_null(24), i8*, i8*)
 
-; Function Attrs: argmemonly nounwind willreturn
+; Function Attrs: argmemonly nofree nosync nounwind willreturn
 declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture) #1
 
 ; Function Attrs: nounwind
@@ -119,4 +119,4 @@ select.body:                                      ; preds = %select.next
 declare { i32, i1 } @runtime.tryChanSelect(i8*, %runtime.chanSelectState*, i32, i32, i8*, i8*)
 
 attributes #0 = { nounwind }
-attributes #1 = { argmemonly nounwind willreturn }
+attributes #1 = { argmemonly nofree nosync nounwind willreturn }
diff --git a/compiler/testdata/intrinsics-wasm.ll b/compiler/testdata/intrinsics-wasm.ll
index bebadb08..9e6687d5 100644
--- a/compiler/testdata/intrinsics-wasm.ll
+++ b/compiler/testdata/intrinsics-wasm.ll
@@ -18,7 +18,7 @@ entry:
   ret double %0
 }
 
-; Function Attrs: nounwind readnone speculatable willreturn
+; Function Attrs: nofree nosync nounwind readnone speculatable willreturn
 declare double @llvm.sqrt.f64(double) #1
 
 ; Function Attrs: nounwind
@@ -28,8 +28,8 @@ entry:
   ret double %0
 }
 
-; Function Attrs: nounwind readnone speculatable willreturn
+; Function Attrs: nofree nosync nounwind readnone speculatable willreturn
 declare double @llvm.trunc.f64(double) #1
 
 attributes #0 = { nounwind }
-attributes #1 = { nounwind readnone speculatable willreturn }
+attributes #1 = { nofree nosync nounwind readnone speculatable willreturn }
diff --git a/go.mod b/go.mod
index 26a4b027..52dd71c3 100644
--- a/go.mod
+++ b/go.mod
@@ -3,7 +3,7 @@ module github.com/tinygo-org/tinygo
 go 1.15
 
 require (
-	github.com/aykevl/go-wasm v0.0.2-0.20211030161413-11881cb9032d // indirect
+	github.com/aykevl/go-wasm v0.0.2-0.20211119014117-0761b1ddcd1a // indirect
 	github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2
 	github.com/chromedp/cdproto v0.0.0-20210113043257-dabd2f2e7693
 	github.com/chromedp/chromedp v0.6.4
@@ -13,5 +13,5 @@ require (
 	go.bug.st/serial v1.1.3
 	golang.org/x/sys v0.0.0-20210510120138-977fb7262007
 	golang.org/x/tools v0.1.6-0.20210813165731-45389f592fe9
-	tinygo.org/x/go-llvm v0.0.0-20210325115028-e7b85195e81c
+	tinygo.org/x/go-llvm v0.0.0-20210907125547-fd2d62ea06be
 )
diff --git a/go.sum b/go.sum
index 1daa9388..73697653 100644
--- a/go.sum
+++ b/go.sum
@@ -1,5 +1,5 @@
-github.com/aykevl/go-wasm v0.0.2-0.20211030161413-11881cb9032d h1:JeuI5/546naK5hpOIX+Lq5xE8rvt7uwiTp6iL+pLQgk=
-github.com/aykevl/go-wasm v0.0.2-0.20211030161413-11881cb9032d/go.mod h1:7sXyiaA0WtSogCu67R2252fQpVmJMh9JWJ9ddtGkpWw=
+github.com/aykevl/go-wasm v0.0.2-0.20211119014117-0761b1ddcd1a h1:QPU7APo6y/6VkCDq6HU3WWIUzER8iywSac23+1UQv60=
+github.com/aykevl/go-wasm v0.0.2-0.20211119014117-0761b1ddcd1a/go.mod h1:7sXyiaA0WtSogCu67R2252fQpVmJMh9JWJ9ddtGkpWw=
 github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2 h1:oMCHnXa6CCCafdPDbMh/lWRhRByN0VFLvv+g+ayx1SI=
 github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI=
 github.com/chromedp/cdproto v0.0.0-20210113043257-dabd2f2e7693 h1:11eq/RkpaotwdF6b1TRMcdgQUPNmyFEJOB7zLvh0O/Y=
@@ -68,7 +68,5 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T
 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-tinygo.org/x/go-llvm v0.0.0-20210308112806-9ef958b6bed4 h1:CMUHxVTb+UuUePuMf8vkWjZ3gTp9BBK91KrgOCwoNHs=
-tinygo.org/x/go-llvm v0.0.0-20210308112806-9ef958b6bed4/go.mod h1:fv1F0BSNpxMfCL0zF3M4OPFbgYHnhtB6ST0HvUtu/LE=
-tinygo.org/x/go-llvm v0.0.0-20210325115028-e7b85195e81c h1:vn9IPshzYmzZis10UEVrsIBRv9FpykADw6M3/tHHROg=
-tinygo.org/x/go-llvm v0.0.0-20210325115028-e7b85195e81c/go.mod h1:fv1F0BSNpxMfCL0zF3M4OPFbgYHnhtB6ST0HvUtu/LE=
+tinygo.org/x/go-llvm v0.0.0-20210907125547-fd2d62ea06be h1:syIpWbi/yESuoyijF2nhRdgX4422sNfmij+o73B3+vU=
+tinygo.org/x/go-llvm v0.0.0-20210907125547-fd2d62ea06be/go.mod h1:fv1F0BSNpxMfCL0zF3M4OPFbgYHnhtB6ST0HvUtu/LE=
diff --git a/interp/interp_test.go b/interp/interp_test.go
index 516fdd11..ae2635af 100644
--- a/interp/interp_test.go
+++ b/interp/interp_test.go
@@ -71,6 +71,7 @@ func runTest(t *testing.T, pathPrefix string) {
 	defer pm.Dispose()
 	pm.AddGlobalOptimizerPass()
 	pm.AddDeadStoreEliminationPass()
+	pm.AddAggressiveDCEPass()
 	pm.Run(mod)
 
 	// Read the expected output IR.
diff --git a/transform/maps_test.go b/transform/maps_test.go
index 1f821d4b..e8b11133 100644
--- a/transform/maps_test.go
+++ b/transform/maps_test.go
@@ -18,6 +18,7 @@ func TestOptimizeMaps(t *testing.T) {
 		pm := llvm.NewPassManager()
 		defer pm.Dispose()
 		pm.AddDeadStoreEliminationPass()
+		pm.AddAggressiveDCEPass()
 		pm.Run(mod)
 	})
 }
diff --git a/transform/testdata/coroutines.out.ll b/transform/testdata/coroutines.out.ll
index d4a49a5e..de902884 100644
--- a/transform/testdata/coroutines.out.ll
+++ b/transform/testdata/coroutines.out.ll
@@ -301,13 +301,13 @@ declare i8* @llvm.coro.free(token, i8* nocapture readonly) #0
 ; Function Attrs: nounwind
 declare token @llvm.coro.save(i8*) #2
 
-; Function Attrs: argmemonly nounwind willreturn
+; Function Attrs: argmemonly nofree nosync nounwind willreturn
 declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) #3
 
-; Function Attrs: argmemonly nounwind willreturn
+; Function Attrs: argmemonly nofree nosync nounwind willreturn
 declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture) #3
 
 attributes #0 = { argmemonly nounwind readonly }
 attributes #1 = { nounwind readnone }
 attributes #2 = { nounwind }
-attributes #3 = { argmemonly nounwind willreturn }
+attributes #3 = { argmemonly nofree nosync nounwind willreturn }
diff --git a/transform/transform_test.go b/transform/transform_test.go
index ae531eeb..935d660b 100644
--- a/transform/transform_test.go
+++ b/transform/transform_test.go
@@ -116,8 +116,9 @@ func filterIrrelevantIRLines(lines []string) []string {
 		if strings.HasPrefix(line, "source_filename = ") {
 			continue
 		}
-		if llvmVersion < 11 && strings.HasPrefix(line, "attributes ") {
+		if llvmVersion < 12 && strings.HasPrefix(line, "attributes ") {
 			// Ignore attribute groups. These may change between LLVM versions.
+			// Right now test outputs are for LLVM 12.
 			continue
 		}
 		out = append(out, line)
-- 
2.31.1