commit | 284107a8e85e442e0cd13e37682769642c598755 | [log] [tgz] |
---|---|---|
author | Than McIntosh <thanm@google.com> | Tue Jun 12 16:09:51 2018 -0400 |
committer | Than McIntosh <thanm@google.com> | Wed Jun 20 12:37:57 2018 +0000 |
tree | 4fbf5dc82e6450eceb2ee62111e6897210090d2d | |
parent | e593d34d99a0c95e0ef3eb0a4d837c1646223dd7 [diff] |
gollvm: support target CPU/features (-march=XXX, etc) This patch adds real support for the "-march=" command line option, to allow users to have the back end target a specific CPU (ex: 'nehalem') within a given architecture (ex: x86-64). Each specific cpu/arch selection gets translated into a set of "target feature" attributes that are then attached to each LLVM function; specifying the correct attributes is key to insuring that vectorization works properly. Notes: - creates a new Go helper program, "capture-fcn-attributes.go", that developers can build and run to generate a header containing the correct set of fcn attributes to use for specific CPUs/archs. The expectation is that building and running this Go program is something done by gollvm developers offline (as opposed to having it be part of the cmake/ninja build process each time gollvm is built). The helper program works by capturing the behavior of clang: running clang on an input file for specific -march=... values and then looking at the generated IR. - unlike clang, gollvm won't support (at least initially) flags for turning on/off individual features/instructions, since this would add a great deal of complexity. Change-Id: I99abf703608e0d1f5d00f6becc3f43cbdb60b394 Reviewed-on: https://go-review.googlesource.com/118322 Reviewed-by: Cherry Zhang <cherryyz@google.com> Reviewed-by: Ian Lance Taylor <iant@golang.org>
Gollvm is an LLVM-based Go compiler. It incorporates “gofrontend” (a Go language front end written in C++ and shared with GCCGO), a bridge component (which translates from gofrontend IR to LLVM IR), and a driver that sends the resulting IR through the LLVM back end.
Gollvm (name still not finalized) is set up to be a subproject within the LLVM tools directory, similar to how things work for “clang” or “compiler-rt”: you check out a copy of the LLVM source tree, then within the LLVM tree you check out additional git repos.
You'll need to have an up-to-date copy of cmake on your system (3.6 vintage).
// Here 'workarea' will contain a copy of the LLVM source tree and one or more build areas % mkdir workarea % cd workarea // Sources % git clone http://llvm.org/git/llvm.git ... % cd llvm/tools % git clone https://go.googlesource.com/gollvm ... % cd gollvm % git clone https://go.googlesource.com/gofrontend ... % cd libgo % git clone https://github.com/libffi/libffi.git ... % git clone https://github.com/ianlancetaylor/libbacktrace.git ... % // Create a build directory, and run cmake % mkdir build.opt % cd build.opt % cmake -DCMAKE_BUILD_TYPE=Debug -DLLVM_USE_LINKER=gold -G Ninja ../llvm // Build ninja <gollvm target(s)>
A gollvm installation will contain ‘llvm-goc’, the Gollvm compiler, the libgo standard Go libraries, and the standard Go tools (“go”, “vet”, “cgo”, etc).
The installation directory for gollvm needs to be specified when invoking cmake prior to the build:
% mkdir build.rel % cd build.rel % cmake -DCMAKE_INSTALL_PREFIX=/my/install/dir -DCMAKE_BUILD_TYPE=Release -DLLVM_USE_LINKER=gold -G Ninja ../llvm // Build all of gollvm % ninja gollvm ... // Install gollvm % ninja install-gollvm
Programs build with the Gollvm Go compiler default to shared linkage, meaning that they need to pick up the Go runtime library via LD_LIBRARY_PATH:
// Root of Gollvm install is /tmp/gollvm-install % export LD_LIBRARY_PATH=/tmp/gollvm-install/lib64 % export PATH=/tmp/gollvm-install/bin:$PATH % go run himom.go hi mom! %
Within /llvm/tools/gollvm, the following directories are of interest:
.../llvm/tools/gollvm:
.../llvm/tools/gollvm/driver, .../llvm/tools/gollvm/driver-main:
.../llvm/tools/gollvm/gofrontend:
.../llvm/tools/gollvm/bridge:
.../llvm/tools/gollvm/unittests:
The executable llvm-goc is the main compiler driver for gollvm; it functions as a compiler (consuming source for a Go package and producing an object file), an assembler, and/or a linker. While it is possible to build and run llvm-goc directly from the command line, in practice there is little point in doing this (better to build using “go build”, which will invoke llvm-goc on your behalf.
// From within <workarea>/build.opt: % ninja llvm-goc ... % cat micro.go package foo func Bar() int { return 1 } % ./bin/llvm-goc -fgo-pkgpath=foo -O3 -o micro.s micro.go %
Here are instructions on building and running the unit tests for the middle layer:
// From within <workarea>/build.opt: // Build unit test % ninja GoBackendCoreTests // Run unit test % ./tools/gollvm/unittests/BackendCore/GoBackendCoreTests [==========] Running 10 tests from 2 test cases. [----------] Global test environment set-up. [----------] 9 tests from BackendCoreTests [ RUN ] BackendCoreTests.MakeBackend [ OK ] BackendCoreTests.MakeBackend (1 ms) [ RUN ] BackendCoreTests.ScalarTypes [ OK ] BackendCoreTests.ScalarTypes (0 ms) [ RUN ] BackendCoreTests.StructTypes [ OK ] BackendCoreTests.StructTypes (1 ms) [ RUN ] BackendCoreTests.ComplexTypes [ OK ] BackendCoreTests.ComplexTypes (0 ms) [ RUN ] BackendCoreTests.FunctionTypes [ OK ] BackendCoreTests.FunctionTypes (0 ms) [ RUN ] BackendCoreTests.PlaceholderTypes [ OK ] BackendCoreTests.PlaceholderTypes (0 ms) [ RUN ] BackendCoreTests.ArrayTypes [ OK ] BackendCoreTests.ArrayTypes (0 ms) [ RUN ] BackendCoreTests.NamedTypes [ OK ] BackendCoreTests.NamedTypes (0 ms) [ RUN ] BackendCoreTests.TypeUtils ... [ PASSED ] 10 tests.
The unit tests currently work by instantiating an LLVM Backend instance and making backend method calls (to mimic what the frontend would do), then inspects the results to make sure they are as expected. Here is an example:
TEST(BackendCoreTests, ComplexTypes) { LLVMContext C; Type *ft = Type::getFloatTy(C); Type *dt = Type::getDoubleTy(C); std::unique_ptr<Backend> be(go_get_backend(C)); Btype *c32 = be->complex_type(64); ASSERT_TRUE(c32 != NULL); ASSERT_EQ(c32->type(), mkTwoFieldLLvmStruct(C, ft, ft)); Btype *c64 = be->complex_type(128); ASSERT_TRUE(c64 != NULL); ASSERT_EQ(c64->type(), mkTwoFieldLLvmStruct(C, dt, dt)); }
The test above makes sure that the LLVM type we get as a result of calling Backend::complex_type() is kosher and matches up to expectations.
To build the Go runtime and standard libraries, use the following:
// From within <workarea>/build.opt: // Build Go runtime and standard libraries % ninja libgo_all
This will compile static (.a) and dynamic (.so) versions of the library.