From f5bc649ef89498dd1c3e48fa032a8e4808008a00 Mon Sep 17 00:00:00 2001 From: Qihan Cai Date: Mon, 4 Jul 2022 03:35:09 +1000 Subject: [PATCH 1/5] gollvm: add support for crosscompiling Add support for compiling gollvm for other arch by specifying GOLLVM_DRIVER_DIR to a prebuilt gollvm with two targets, and specify target, toolchain and sysroot in GOLLVM_EXTRA_GOCFLAGS. Example usage: RISCV=$HOME/toolchain SOURCE=$HOME/llvm-project/llvm TRIPLE=riscv64-unknown-linux-gnu # host cmake -G Ninja -S $SOURCE -B build-x86 \ -DCMAKE_INSTALL_PREFIX=install-x86 \ -DCMAKE_BUILD_TYPE=Debug \ -DLLVM_USE_LINKER=bfd \ -DGOLLVM_DEFAULT_LINKER=bfd \ -DLLVM_TARGET_ARCH="X86-64,RISCV64" \ -DLLVM_TARGETS_TO_BUILD="X86;RISCV" # crosscompile cmake -G Ninja -S $SOURCE -B build-riscv \ -DCMAKE_INSTALL_PREFIX=$INSTALL \ -DCMAKE_BUILD_TYPE=Debug \ -DLLVM_USE_LINKER=bfd \ -DGOLLVM_DEFAULT_LINKER=bfd \ -DCMAKE_CROSSCOMPILING=True \ -DLLVM_TARGET_ARCH=RISCV64 \ -DLLVM_DEFAULT_TARGET_TRIPLE=$TRIPLE \ -DLLVM_TARGETS_TO_BUILD=RISCV \ -DCMAKE_C_COMPILER=$RISCV/bin/$TRIPLE-gcc \ -DCMAKE_CXX_COMPILER=$RISCV/bin/$TRIPLE-g++ \ -DLLVM_TABLEGEN=$PWD/build-x86/bin/llvm-tblgen \ -DGOLLVM_DRIVER_DIR=$PWD/build-x86/bin \ -DGOLLVM_EXTRA_GOCFLAGS="--target=$TRIPLE \ --gcc-toolchain=$RISCV/ \ --sysroot=$RISCV/sysroot" \ -DGOLLVM_USE_SPLIT_STACK=OFF \ -DCMAKE_C_FLAGS=-latomic \ -DCMAKE_CXX_FLAGS=-latomic # build gollvm crosscompiler ninja -C build-x86 llvm-goc llvm-goc-token llvm-godumpspec # cross compile gollvm, go tools and install ninja -C build-riscv install-gollvm Change-Id: Ie4997771fd21437f65d857b7aaae267b7a394f23 Reviewed-on: https://go-review.googlesource.com/c/gollvm/+/425199 Reviewed-by: David Chase Reviewed-by: Than McIntosh --- CMakeLists.txt | 21 ++++++++++++++++++--- cmake/modules/AutoGenGo.cmake | 6 +++++- cmake/modules/GoPackage.cmake | 7 ++++++- driver/GollvmOptions.td | 3 ++- driver/LinuxToolChain.cpp | 14 +++++++++++--- gotools/CMakeLists.txt | 8 ++++++-- libgo/CMakeLists.txt | 16 ++++++++++++---- 7 files changed, 60 insertions(+), 15 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 40a9618..2561f8b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,13 +39,28 @@ set(EXTCC "CC=${CMAKE_C_COMPILER}" "CXX=${CMAKE_CXX_COMPILER}") set(gollvm_binroot "${CMAKE_CURRENT_BINARY_DIR}") +# Set MPN path according to the target processor +string(REGEX REPLACE "-" " " lht_components ${LLVM_DEFAULT_TARGET_TRIPLE}) +separate_arguments(lht_components) +list(GET lht_components 0 llarch) + +if( ${llarch} STREQUAL "x86_64" ) + set(MPN_PATH "x86_64 generic") +elseif( ${llarch} STREQUAL "aarch64" ) + set(MPN_PATH "arm64 generic") +elseif( ${llarch} STREQUAL "riscv64" ) + set(MPN_PATH "riscv generic") +else() + message(SEND_ERROR "Arch ${llarch} not yet supported") +endif() + externalproject_add(libgmp URL https://gmplib.org/download/gmp/gmp-6.2.0.tar.bz2 https://mirrors.kernel.org/gnu/gmp/gmp-6.2.0.tar.bz2 URL_MD5 c24161e0dd44cae78cd5f67193492a21 DOWNLOAD_DIR ${CMAKE_CURRENT_BINARY_DIR}/external-downloads BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/external/gmp-build SOURCE_DIR ${CMAKE_CURRENT_BINARY_DIR}/external/gmp - CONFIGURE_COMMAND /configure --prefix=${EXTINSTALLDIR} ${EXTCPPFLAGS} ${EXTLDFLAGS} ${EXTCC} + CONFIGURE_COMMAND /configure --prefix=${EXTINSTALLDIR} ${EXTCPPFLAGS} ${EXTLDFLAGS} ${EXTCC} --build=${LLVM_HOST_TRIPLE} --host=${LLVM_DEFAULT_TARGET_TRIPLE} MPN_PATH=${MPN_PATH} BUILD_COMMAND make -j${PROCESSOR_COUNT} install LOG_CONFIGURE 1 LOG_BUILD 1 @@ -59,7 +74,7 @@ externalproject_add(libmpfr DOWNLOAD_DIR ${CMAKE_CURRENT_BINARY_DIR}/external-downloads BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/external/mpfr SOURCE_DIR ${CMAKE_CURRENT_BINARY_DIR}/external/mpfr - CONFIGURE_COMMAND /configure --with-gmp=${CMAKE_CURRENT_BINARY_DIR}/external/gmp --prefix=${EXTINSTALLDIR} ${EXTCPPFLAGS} ${EXTLDFLAGS} ${EXTCC} + CONFIGURE_COMMAND /configure --with-gmp=${CMAKE_CURRENT_BINARY_DIR}/external/gmp --prefix=${EXTINSTALLDIR} ${EXTCPPFLAGS} ${EXTLDFLAGS} ${EXTCC} -build=${LLVM_HOST_TRIPLE} --host=${LLVM_DEFAULT_TARGET_TRIPLE} BUILD_COMMAND make -j${PROCESSOR_COUNT} install LOG_CONFIGURE 1 LOG_BUILD 1 @@ -74,7 +89,7 @@ externalproject_add(libmpc BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/external/mpc SOURCE_DIR ${CMAKE_CURRENT_BINARY_DIR}/external/mpc PREFIX ${EXTINSTALLDIR} - CONFIGURE_COMMAND /configure --with-gmp=${CMAKE_CURRENT_BINARY_DIR}/external/gmp --with-mpfr=${CMAKE_CURRENT_BINARY_DIR}/external/mpfr --prefix=${EXTINSTALLDIR} ${EXTCPPFLAGS} ${EXTLDFLAGS} ${EXTCC} + CONFIGURE_COMMAND /configure --with-gmp=${CMAKE_CURRENT_BINARY_DIR}/external/gmp --with-mpfr=${CMAKE_CURRENT_BINARY_DIR}/external/mpfr --prefix=${EXTINSTALLDIR} ${EXTCPPFLAGS} ${EXTLDFLAGS} ${EXTCC} -build=${LLVM_HOST_TRIPLE} --host=${LLVM_DEFAULT_TARGET_TRIPLE} BUILD_COMMAND make -j${PROCESSOR_COUNT} install LOG_CONFIGURE 1 LOG_BUILD 1 diff --git a/cmake/modules/AutoGenGo.cmake b/cmake/modules/AutoGenGo.cmake index 644075a..a0a3af6 100644 --- a/cmake/modules/AutoGenGo.cmake +++ b/cmake/modules/AutoGenGo.cmake @@ -375,7 +375,11 @@ function(mkzdefaultcc package outfile ccpath cxxpath) CMAKE_PARSE_ARGUMENTS(ARG "EXPORT" "" "" ${ARGN}) # Construct default driver path - set(driverpath "${GOLLVM_INSTALL_DIR}/bin/llvm-goc") + if (GOLLVM_DRIVER_DIR) + set(driverpath "${GOLLVM_DRIVER_DIR}/bin/llvm-goc") + else() + set(driverpath "${GOLLVM_INSTALL_DIR}/bin/llvm-goc") + endif() file(REMOVE ${outfile}) file(WRITE ${outfile} "package ${package}\n\n") diff --git a/cmake/modules/GoPackage.cmake b/cmake/modules/GoPackage.cmake index 7e9e065..0d26a16 100644 --- a/cmake/modules/GoPackage.cmake +++ b/cmake/modules/GoPackage.cmake @@ -80,9 +80,14 @@ function(add_go_package pkgpath dest) endif() # Command to build *.gox.tmp + set(objcopycommand "objcopy") + if (GOLLVM_DRIVER_DIR) + set(objcopycommand "${LLVM_DEFAULT_TARGET_TRIPLE}-objcopy") + endif() + add_custom_command( OUTPUT "${package_goxtmp}" - COMMAND objcopy -j .go_export "${package_ofile}" "${package_goxtmp}" + COMMAND "${objcopycommand}" -j .go_export "${package_ofile}" "${package_goxtmp}" DEPENDS ${package_ofile} ${package_picofile} COMMENT "Building Go exports file for package '${pkgpath}'" VERBATIM) diff --git a/driver/GollvmOptions.td b/driver/GollvmOptions.td index 3c60287..b2b627f 100644 --- a/driver/GollvmOptions.td +++ b/driver/GollvmOptions.td @@ -506,7 +506,8 @@ def disable_llvm_passes : Flag<["-"], "disable-llvm-passes">, "frontend by not running any LLVM passes at all">; def gcc_toolchain_EQ : Joined<["--"], "gcc-toolchain=">, Flags<[DriverOption]>, - HelpText<"Use the gcc toolchain at the given directory">; + HelpText<"Use the gcc toolchain at the given directory, the directory typically contains " + "‘lib{,32,64}/gcc{,-cross}/$triple’ and ‘include’">; def enable_gc_EQ : Joined<["-"], "enable-gc=">, HelpText<"Enable stack map generation">; diff --git a/driver/LinuxToolChain.cpp b/driver/LinuxToolChain.cpp index 2a2fb10..bebad8c 100644 --- a/driver/LinuxToolChain.cpp +++ b/driver/LinuxToolChain.cpp @@ -34,9 +34,10 @@ static void addIfPathExists(pathlist &paths, const llvm::Twine &path) static llvm::StringRef getOSLibDir(const llvm::Triple &triple) { - // multilib is not supported on major aarch64/arm64 linux distributions + // multilib is not supported on major aarch64/arm64 and riscv64 linux distributions // subject to change when more scenarios to be taken into account - if (triple.getArch() == llvm::Triple::aarch64) + if (triple.getArch() == llvm::Triple::aarch64 || + triple.getArch() == llvm::Triple::riscv64) return "lib"; // x86 uses the lib32 variant, unlike other archs. if (triple.getArch() == llvm::Triple::x86) @@ -67,8 +68,11 @@ Linux::Linux(gollvm::driver::Driver &driver, pathlist &fpaths = filePaths(); addIfPathExists(fpaths, gccDetector_.getLibPath()); std::string osLibDir = getOSLibDir(targetTriple).str(); - if (!driver.sysRoot().empty()) + if (!driver.sysRoot().empty()) { + addIfPathExists(fpaths, llvm::Twine(driver.sysRoot() + "/usr/" + + osLibDir).str()); osLibDir = driver.sysRoot() + "/" + osLibDir; + } addIfPathExists(fpaths, llvm::Twine(gccDetector_.getParentLibPath() + "/../" + ftrip).str()); addIfPathExists(fpaths, llvm::Twine(osLibDir).str()); @@ -136,6 +140,10 @@ std::string Linux::getDynamicLinker(const llvm::opt::ArgList &args) break; } } + if (auto *Arg = args.getLastArg(gollvm::options::OPT_sysroot_EQ)) { + std::string Sysroot = Arg->getValue(); + return Sysroot + "/" + LibDir + "/" + Loader; + } return "/" + LibDir + "/" + Loader; } diff --git a/gotools/CMakeLists.txt b/gotools/CMakeLists.txt index cf70562..e8023f4 100644 --- a/gotools/CMakeLists.txt +++ b/gotools/CMakeLists.txt @@ -22,8 +22,12 @@ if(NOT GOLLVM_USE_SPLIT_STACK) endif() # Driver for compiling *.go files. -get_target_property(driverdir llvm-goc RUNTIME_OUTPUT_DIRECTORY) -set(gollvm_driver "${driverdir}/llvm-goc") +if (GOLLVM_DRIVER_DIR) + set(gollvm_driver "${GOLLVM_DRIVER_DIR}/llvm-goc") +else() + get_target_property(driverdir llvm-goc RUNTIME_OUTPUT_DIRECTORY) + set(gollvm_driver "${driverdir}/llvm-goc") +endif() set(gocompiler ${gollvm_driver}) set(cmd_srcroot "${GOLLVM_SOURCE_DIR}/gofrontend/libgo/go/cmd") diff --git a/libgo/CMakeLists.txt b/libgo/CMakeLists.txt index b0cf30d..8625699 100644 --- a/libgo/CMakeLists.txt +++ b/libgo/CMakeLists.txt @@ -72,8 +72,12 @@ add_subdirectory(godumpspec) #...................................................................... # Driver for compiling *.go files. -get_target_property(driverdir llvm-goc RUNTIME_OUTPUT_DIRECTORY) -set(gollvm_driver "${driverdir}/llvm-goc") +if (GOLLVM_DRIVER_DIR) + set(gollvm_driver "${GOLLVM_DRIVER_DIR}/llvm-goc") +else() + get_target_property(driverdir llvm-goc RUNTIME_OUTPUT_DIRECTORY) + set(gollvm_driver "${driverdir}/llvm-goc") +endif() set(gocompiler ${gollvm_driver}) # Pick up any extra Go compiler flags specified via @@ -272,8 +276,12 @@ set(gensysinfodotgo "${libgo_binroot}/gen-sysinfo.go") set(gensysinfotmp "${libgo_binroot}/gen-sysinfo.go.tmp") set(gensysinfomacrotmp "${libgo_binroot}/sysinfo.macros.txt") set(gensysinfoobject "${libgo_binroot}/sysinfo.o") -get_target_property(godumpspecdir llvm-godumpspec RUNTIME_OUTPUT_DIRECTORY) -set(godumpspecexec "${godumpspecdir}/llvm-godumpspec") +if (GOLLVM_DRIVER_DIR) + set(godumpspecexec "${GOLLVM_DRIVER_DIR}/llvm-godumpspec") +else() + get_target_property(godumpspecdir llvm-godumpspec RUNTIME_OUTPUT_DIRECTORY) + set(godumpspecexec "${godumpspecdir}/llvm-godumpspec") +endif() set(sysinfoc "${libgo_srcroot}/sysinfo.c") set(sysinfoflags ${basedefines}) list(APPEND sysinfoflags "-I${libgo_binroot}" "-I${libgo_binroot}/runtime") From 253c122ed62d5e9a32a9806e83c47a389a6435bf Mon Sep 17 00:00:00 2001 From: melonedo Date: Fri, 26 Aug 2022 14:32:47 +0800 Subject: [PATCH 2/5] gollvm: pass arch info to the integrated assembler Currently, architecture information is passed to the compiler but not the integrated assembler, causing discrepancies in the ABI chosen by the two tools, especially on the RISC-V platform. This patch makes sure both share the same architecture information. Change-Id: I29f441e86e06f1f0b46c3ea62576a7d1291c2ce4 Reviewed-on: https://go-review.googlesource.com/c/gollvm/+/425854 Reviewed-by: David Chase Reviewed-by: Than McIntosh --- driver/ArchCpuSetup.cpp | 71 +++++++++++++++++++++++++++++++++++++++ driver/ArchCpuSetup.h | 27 +++++++++++++++ driver/CMakeLists.txt | 1 + driver/CompileGo.cpp | 43 ++---------------------- driver/Driver.cpp | 3 +- driver/IntegAssembler.cpp | 13 ++----- 6 files changed, 106 insertions(+), 52 deletions(-) create mode 100644 driver/ArchCpuSetup.cpp create mode 100644 driver/ArchCpuSetup.h diff --git a/driver/ArchCpuSetup.cpp b/driver/ArchCpuSetup.cpp new file mode 100644 index 0000000..a7eb765 --- /dev/null +++ b/driver/ArchCpuSetup.cpp @@ -0,0 +1,71 @@ +//===-- ArchCpuSetup.cpp --------------------------------------------------===// +// +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. +// +//===----------------------------------------------------------------------===// +// +// Gollvm driver helper function setupArchCpu +// +//===----------------------------------------------------------------------===// + +#include "ArchCpuSetup.h" + +#include "llvm/Option/Arg.h" +#include "llvm/Support/Host.h" +#include "llvm/Support/raw_ostream.h" + +namespace gollvm { namespace arch { +#include "ArchCpusAttrs.h" +} } + +using namespace llvm; + +bool gollvm::driver::setupArchCpu(opt::Arg *cpuarg, std::string &cpu, + std::string &attrs, Triple triple, + const char *progname) { + std::string cpuStr; + if (cpuarg != nullptr) { + std::string val(cpuarg->getValue()); + if (val == "native") + cpuStr = sys::getHostCPUName().str(); + else + cpuStr = cpuarg->getValue(); + } + + // Locate correct entry in architectures table for this triple + const gollvm::arch::CpuAttrs *cpuAttrs = nullptr; + for (unsigned i = 0; gollvm::arch::triples[i].cpuattrs != nullptr; i += 1) { + if (!strcmp(triple.str().c_str(), gollvm::arch::triples[i].triple)) { + cpuAttrs = gollvm::arch::triples[i].cpuattrs; + break; + } + } + if (cpuAttrs == nullptr) { + errs() << progname << ": unable to determine target CPU features for " + << "target " << triple.str() << "\n"; + return false; + } + + // If no CPU specified, use first entry. Otherwise look for CPU name. + if (!cpuStr.empty()) { + bool found = false; + while (strlen(cpuAttrs->cpu) != 0) { + if (!strcmp(cpuAttrs->cpu, cpuStr.c_str())) { + // found + found = true; + break; + } + cpuAttrs++; + } + if (!found) { + errs() << progname << ": invalid setting for -march:" + << " -- unable to identify CPU '" << cpuStr << "'\n"; + return false; + } + } + cpu = cpuAttrs->cpu; + attrs = cpuAttrs->attrs; + return true; +} diff --git a/driver/ArchCpuSetup.h b/driver/ArchCpuSetup.h new file mode 100644 index 0000000..7129c04 --- /dev/null +++ b/driver/ArchCpuSetup.h @@ -0,0 +1,27 @@ +//===-- ArchCpuSetup.cpp --------------------------------------------------===// +// +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. +// +//===----------------------------------------------------------------------===// +// +// Declares gollvm driver helper function setupArchCpu. +// +//===----------------------------------------------------------------------===// + +#ifndef GOLLVM_DRIVER_ARCHCPUSETUP_H +#define GOLLVM_DRIVER_ARCHCPUSETUP_H + +#include "Tool.h" + +namespace gollvm { +namespace driver { + +bool setupArchCpu(llvm::opt::Arg *cpuarg, std::string &cpu, std::string &attrs, + llvm::Triple triple_, const char *progname_); + +} // end namespace driver +} // end namespace gollvm + +#endif diff --git a/driver/CMakeLists.txt b/driver/CMakeLists.txt index c6429df..62b457a 100644 --- a/driver/CMakeLists.txt +++ b/driver/CMakeLists.txt @@ -26,6 +26,7 @@ include_directories(${EXTINSTALLDIR}/include) # A library containing driver utility code. add_llvm_library(LLVMDriverUtils Action.cpp + ArchCpuSetup.cpp Artifact.cpp Command.cpp Compilation.cpp diff --git a/driver/CompileGo.cpp b/driver/CompileGo.cpp index 6affe49..b317c9b 100644 --- a/driver/CompileGo.cpp +++ b/driver/CompileGo.cpp @@ -22,6 +22,7 @@ #include "GollvmPasses.h" #include "Action.h" +#include "ArchCpuSetup.h" #include "Artifact.h" #include "Driver.h" #include "ToolChain.h" @@ -466,49 +467,9 @@ bool CompileGoImpl::setup(const Action &jobAction) Options.AllowFPOpFusion = *dofuse; // Support -march - std::string cpuStr; opt::Arg *cpuarg = args_.getLastArg(gollvm::options::OPT_march_EQ); - if (cpuarg != nullptr) { - std::string val(cpuarg->getValue()); - if (val == "native") - cpuStr = sys::getHostCPUName().str(); - else - cpuStr = cpuarg->getValue(); - } - - // Locate correct entry in architectures table for this triple - const gollvm::arch::CpuAttrs *cpuAttrs = nullptr; - for (unsigned i = 0; gollvm::arch::triples[i].cpuattrs != nullptr; i += 1) { - if (!strcmp(triple_.str().c_str(), gollvm::arch::triples[i].triple)) { - cpuAttrs = gollvm::arch::triples[i].cpuattrs; - break; - } - } - if (cpuAttrs == nullptr) { - errs() << progname_ << ": unable to determine target CPU features for " - << "target " << triple_.str() << "\n"; + if (!setupArchCpu(cpuarg, targetCpuAttr_, targetFeaturesAttr_, triple_, progname_)) return false; - } - - // If no CPU specified, use first entry. Otherwise look for CPU name. - if (!cpuStr.empty()) { - bool found = false; - while (strlen(cpuAttrs->cpu) != 0) { - if (!strcmp(cpuAttrs->cpu, cpuStr.c_str())) { - // found - found = true; - break; - } - cpuAttrs++; - } - if (!found) { - errs() << progname_ << ": invalid setting for -march:" - << " -- unable to identify CPU '" << cpuStr << "'\n"; - return false; - } - } - targetCpuAttr_ = cpuAttrs->cpu; - targetFeaturesAttr_ = cpuAttrs->attrs; // Create target machine Optional CM = None; diff --git a/driver/Driver.cpp b/driver/Driver.cpp index 8debbab..777cc2b 100644 --- a/driver/Driver.cpp +++ b/driver/Driver.cpp @@ -186,7 +186,8 @@ bool Driver::supportedAsmOptions() continue; } if (value.startswith("-compress-debug-sections") || - value.startswith("--compress-debug-sections")) { + value.startswith("--compress-debug-sections") || + value.startswith("-march")) { continue; } // Unrecognized -Wa,... option diff --git a/driver/IntegAssembler.cpp b/driver/IntegAssembler.cpp index 39d080f..a40be9f 100644 --- a/driver/IntegAssembler.cpp +++ b/driver/IntegAssembler.cpp @@ -22,6 +22,7 @@ #include "GollvmPasses.h" #include "Action.h" +#include "ArchCpuSetup.h" #include "Artifact.h" #include "Driver.h" #include "ToolChain.h" @@ -185,16 +186,6 @@ bool IntegAssemblerImpl::invokeAssembler() // Note: -Xassembler and -Wa, options should already have been // examined at this point. - // FIXME: no support yet for -march (bring over from CompileGo.cpp) - opt::Arg *cpuarg = args_.getLastArg(gollvm::options::OPT_march_EQ); - if (cpuarg != nullptr) { - errs() << progname_ << ": internal error: option '" - << cpuarg->getAsString(args_) - << "' not yet implemented in integrated assembler\n"; - assert(false); - return false; - } - // Support for compressed debug. llvm::DebugCompressionType CompressDebugSections = llvm::DebugCompressionType::None; @@ -208,6 +199,8 @@ bool IntegAssemblerImpl::invokeAssembler() // Build up the feature string from the target feature list. std::string FS; std::string CPU; + opt::Arg *cpuarg = args_.getLastArg(gollvm::options::OPT_march_EQ); + setupArchCpu(cpuarg, CPU, FS, triple_, progname_); std::unique_ptr Str; std::unique_ptr MCII(TheTarget->createMCInstrInfo()); std::unique_ptr STI( From a7bb3bcd9bd211c0fbf0ed71885fd756203d6b7c Mon Sep 17 00:00:00 2001 From: melonedo Date: Fri, 2 Sep 2022 21:53:02 +0800 Subject: [PATCH 3/5] gollvm: support building on RISC-V linux This patch adds relevant flags for builoding on RISC-V linux platform, its C-ABI setup is on another patch. Change-Id: Ibfe22aabb7a6718ccf3e55c6cc35f70953d972d4 --- CMakeLists.txt | 7 ++-- README.md | 55 ++++++++++++++++++++++++++- cmake/modules/GoVars.cmake | 8 ++++ cmake/modules/LibbacktraceUtils.cmake | 7 ++++ cmake/modules/LibffiUtils.cmake | 10 ++++- libgo/CMakeLists.txt | 12 +++++- 6 files changed, 93 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2561f8b..b8f20d8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,6 +18,10 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules") set(GOLLVM_USE_SPLIT_STACK ON CACHE BOOL "use split stack by default") set(GOLLVM_DEFAULT_LINKER gold CACHE STRING "default linker for Go links") +string(REGEX REPLACE "-" " " lht_components ${LLVM_DEFAULT_TARGET_TRIPLE}) +separate_arguments(lht_components) +list(GET lht_components 0 llarch) + include(CmakeUtils) include(AddGollvm) @@ -40,9 +44,6 @@ set(EXTCC "CC=${CMAKE_C_COMPILER}" "CXX=${CMAKE_CXX_COMPILER}") set(gollvm_binroot "${CMAKE_CURRENT_BINARY_DIR}") # Set MPN path according to the target processor -string(REGEX REPLACE "-" " " lht_components ${LLVM_DEFAULT_TARGET_TRIPLE}) -separate_arguments(lht_components) -list(GET lht_components 0 llarch) if( ${llarch} STREQUAL "x86_64" ) set(MPN_PATH "x86_64 generic") diff --git a/README.md b/README.md index 0c563c9..5117856 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ source tree, then within the LLVM tree you check out additional git repos. * [Invoking cmake and ninja](#cmakeninja) * [Installing gollvm](#installing) * [Using an installed copy of gollvm](#using) + * [Crosscompiling gollvm](#crosscompiling) * [Information for gollvm developers](#developers) [FAQ](#FAQ) @@ -120,6 +121,58 @@ hi mom! % ``` +## Crosscompiling gollvm +You need a working version of gollvm on host system to cross compile. The following script will build and install gollvm on a cross compile system. + +``` +#!/bin/bash +set -e +mkdir -p build +cd build + +RISCV=$HOME/toolchain +SOURCE=$HOME/llvm-project/llvm +TRIPLE=riscv64-unknown-linux-gnu +INSTALL=/tmp/gollvm-install + +# host +cmake -G Ninja -S $SOURCE -B build-x86 \ + -DCMAKE_INSTALL_PREFIX=install-x86 \ + -DCMAKE_BUILD_TYPE=Debug \ + -DLLVM_USE_LINKER=bfd \ + -DGOLLVM_DEFAULT_LINKER=bfd \ + -DLLVM_TARGET_ARCH="X86-64,RISCV64" \ + -DLLVM_TARGETS_TO_BUILD="X86;RISCV" + +# crosscompile +cmake -G Ninja -S $SOURCE -B build-riscv \ + -DCMAKE_INSTALL_PREFIX=$INSTALL \ + -DCMAKE_BUILD_TYPE=Debug \ + -DLLVM_USE_LINKER=bfd \ + -DGOLLVM_DEFAULT_LINKER=bfd \ + -DCMAKE_CROSSCOMPILING=True \ + -DLLVM_TARGET_ARCH=RISCV64 \ + -DLLVM_DEFAULT_TARGET_TRIPLE=$TRIPLE \ + -DLLVM_TARGETS_TO_BUILD=RISCV \ + -DCMAKE_C_COMPILER=$RISCV/bin/$TRIPLE-gcc \ + -DCMAKE_CXX_COMPILER=$RISCV/bin/$TRIPLE-g++ \ + -DLLVM_TABLEGEN=$PWD/build-x86/bin/llvm-tblgen \ + -DGOLLVM_DRIVER_DIR=$PWD/build-x86/bin \ + -DGOLLVM_EXTRA_GOCFLAGS="--target=$TRIPLE \ + --gcc-toolchain=$RISCV/ \ + --sysroot=$RISCV/sysroot" \ + -DGOLLVM_USE_SPLIT_STACK=OFF \ + -DCMAKE_C_FLAGS=-latomic \ + -DCMAKE_CXX_FLAGS=-latomic + + +# build gollvm crosscompiler +ninja -C build-x86 llvm-goc llvm-goc-token llvm-godumpspec + +# cross compile gollvm, go tools and install +ninja -C build-riscv install-gollvm +``` + # Information for gollvm developers ## Source code structure @@ -269,7 +322,7 @@ inlining, vectorization, register allocation, etc. ## Which architectures and operating systems are supported for gollvm? -Gollvm is currently supported only for x86_64 and aarch64 Linux. +Gollvm is currently supported only for x86_64, aarch64 and riscv64 Linux. ## How does the gollvm runtime differ from the main Go runtime? diff --git a/cmake/modules/GoVars.cmake b/cmake/modules/GoVars.cmake index 5aa2c32..c8d0e98 100644 --- a/cmake/modules/GoVars.cmake +++ b/cmake/modules/GoVars.cmake @@ -11,6 +11,10 @@ if( ${llarch} STREQUAL "x86_64" ) # LLVM's "aarch64" is the same as Go's "arm64". elseif( ${llarch} STREQUAL "aarch64" ) set(goarch "arm64") +elseif( ${llarch} STREQUAL "riscv64" ) + # Driver::installedLibDir honors ./lib64 only + # Future change needed (along with those in AddGollvm.cmake) + set(goarch "riscv64") else() message(SEND_ERROR "Arch ${llarch} not yet supported") endif() @@ -27,6 +31,10 @@ elseif( ${llarch} STREQUAL "aarch64" ) # Driver::installedLibDir honors ./lib64 only # Future change needed (along with those in AddGollvm.cmake) set(library_suffix "64") +elseif( ${llarch} STREQUAL "riscv64" ) + # Driver::installedLibDir honors ./lib64 only + # Future change needed (along with those in AddGollvm.cmake) + set(library_suffix "64") else() message(SEND_ERROR "Arch ${llarch} not yet supported") endif() diff --git a/cmake/modules/LibbacktraceUtils.cmake b/cmake/modules/LibbacktraceUtils.cmake index dc54f18..2c018fd 100644 --- a/cmake/modules/LibbacktraceUtils.cmake +++ b/cmake/modules/LibbacktraceUtils.cmake @@ -11,6 +11,9 @@ function(setup_libbacktrace) elseif( ${goarch} STREQUAL "arm64") set(BACKTRACE_ELF_SIZE 64) set(HAVE_GETIPINFO 1) + elseif( ${goarch} STREQUAL "riscv64") + set(BACKTRACE_ELF_SIZE 64) + set(HAVE_GETIPINFO 1) else() message(SEND_ERROR "Libbacktrace config setup not implemented for ${goarch}") endif() @@ -68,6 +71,10 @@ function(setup_libbacktrace) if(GOLLVM_USE_SPLIT_STACK) string(APPEND libbacktraceflags " -fsplit-stack ${CFPROTECTION_WORKAROUND}") endif() + # Force -funwind-tables to be used for RISC-V so .eh_frame exists for stack unwinding. + if (${goarch} STREQUAL "riscv64") + string(APPEND libbacktraceflags " -funwind-tables") + endif() string(APPEND libbacktraceflags " ${GOLLVM_EXTRA_CFLAGS}") # Object libraries built from libbacktrace sources. diff --git a/cmake/modules/LibffiUtils.cmake b/cmake/modules/LibffiUtils.cmake index 035b647..a05bbe9 100644 --- a/cmake/modules/LibffiUtils.cmake +++ b/cmake/modules/LibffiUtils.cmake @@ -9,6 +9,8 @@ function(setup_libffi libffi_srcroot) set(arch_dir "aarch64") elseif(${llarch} STREQUAL "x86_64") set(arch_dir "x86") + elseif(${llarch} STREQUAL "riscv64") + set(arch_dir "riscv") else() message(SEND_ERROR "Arch ${llarch} not yet supported") endif() @@ -35,7 +37,7 @@ function(setup_libffi libffi_srcroot) set(HAVE_64BIT 0) else() set(HAVE_64BIT 1) - if(NOT ${llarch} STREQUAL "aarch64") + if(${llarch} STREQUAL "x86_64") set(HAVE_AS_X86_64_UNWIND_SECTION_TYPE 1) endif() endif() @@ -62,6 +64,8 @@ function(setup_libffi libffi_srcroot) # Set target based on arch. if(HAVE_64BIT AND ${llarch} STREQUAL "aarch64") set(TARGET AARCH64) + elseif(HAVE_64BIT AND ${llarch} STREQUAL "riscv64") + set(TARGET RISCV64) elseif(HAVE_64BIT) set(TARGET X86_64) else() @@ -86,6 +90,10 @@ function(setup_libffi libffi_srcroot) if(GOLLVM_USE_SPLIT_STACK) string(APPEND libffiflags " -fsplit-stack ${CFPROTECTION_WORKAROUND}") endif() + # Force -funwind-tables to be used for RISC-V so .eh_frame exists for stack unwinding. + if (${goarch} STREQUAL "riscv64") + string(APPEND libffiflags " -funwind-tables") + endif() string(APPEND libffiflags " ${GOLLVM_EXTRA_CFLAGS}") # Copy correct version of ffitarget.h to libgo binary root. diff --git a/libgo/CMakeLists.txt b/libgo/CMakeLists.txt index 8625699..30cc02d 100644 --- a/libgo/CMakeLists.txt +++ b/libgo/CMakeLists.txt @@ -86,6 +86,9 @@ set(tmp_libgo_extra_gocflags ${GOLLVM_EXTRA_GOCFLAGS}) if(GOLLVM_EXTRA_GOCFLAGS) string(REPLACE " " ";" libgo_extra_gocflags ${tmp_libgo_extra_gocflags}) endif() +if (${llarch} STREQUAL "riscv64") + string(APPEND libgo_extra_gocflags ";-latomic") +endif() if(NOT GOLLVM_USE_SPLIT_STACK) list(APPEND libgo_extra_gocflags "-fno-split-stack") endif() @@ -509,7 +512,7 @@ list(APPEND runtimecfiles "go/syscall/signame.c" "go/syscall/wait.c") -if (NOT ${goarch} STREQUAL "arm64") +if (${goarch} STREQUAL "amd64") list(APPEND runtimecfiles "go/golang.org/x/sys/cpu/cpu_gccgo_x86.c") endif() @@ -529,6 +532,7 @@ endforeach() # go-wrapper.c is not in gofrontend/libgo list(APPEND runtimecpaths "${GOLLVM_SOURCE_DIR}/libgo/runtime/go-wrappers.c") + # Compiler flags for C files in the runtime. set(baseopts "-g -Wno-zero-length-array ") if(GOLLVM_USE_SPLIT_STACK) @@ -537,6 +541,10 @@ endif() foreach(def ${basedefines}) string(APPEND baseopts "${def} ") endforeach() +# Force -funwind-tables to be used for RISC-V so .eh_frame exists for stack unwinding. +if (${goarch} STREQUAL "riscv64") + string(APPEND baseopts "-funwind-tables ") +endif() string(APPEND baseopts "${GOLLVM_EXTRA_CFLAGS} ") # Special flags required for aeshash.c (functions in this file are called @@ -544,6 +552,8 @@ string(APPEND baseopts "${GOLLVM_EXTRA_CFLAGS} ") # specific architectural features). if (${goarch} STREQUAL "arm64") set_source_files_properties(${libgo_csrcroot}/runtime/aeshash.c PROPERTIES COMPILE_FLAGS "-march=armv8-a+crypto") +elseif (${goarch} STREQUAL "riscv64") + set_source_files_properties(${libgo_csrcroot}/runtime/aeshash.c PROPERTIES COMPILE_FLAGS "-march=rv64gc") else() set_source_files_properties(${libgo_csrcroot}/runtime/aeshash.c PROPERTIES COMPILE_FLAGS "-maes -mssse3") endif() From 737b721bbb615f33ffda2ebd5bb2e60e511c17d5 Mon Sep 17 00:00:00 2001 From: melonedo Date: Fri, 2 Sep 2022 21:54:55 +0800 Subject: [PATCH 4/5] gollvm: add linux RISC-V support This patch sets up the C-ABI oracle for the RISC-V linux platform. The main changes are: 1. The C calling convention is used to identify this platform. 2. C-ABI oracle and compile options are set for RISC-V linux. 3. The ABI is hardcoded as lp64d on RISC-V linux. Change-Id: I640cd7dbaf7d7efb6abdba93a04e9b9a37244eca --- bridge/go-llvm-cabi-oracle.cpp | 239 +++++++++- bridge/go-llvm-cabi-oracle.h | 14 + bridge/go-llvm.cpp | 5 + driver/ArchCpusAttrs.h | 141 +++--- driver/CompileGo.cpp | 13 +- driver/Driver.cpp | 4 - driver/GccUtils.cpp | 10 + driver/GnuTools.cpp | 3 + driver/IntegAssembler.cpp | 2 + driver/LinuxToolChain.cpp | 8 + tools/capture-fcn-attributes.go | 1 + .../BackendCore/BackendCABIOracleTests.cpp | 431 ++++++++++++++++++ unittests/BackendCore/TestUtils.cpp | 5 +- unittests/BackendCore/TestUtils.h | 3 +- 14 files changed, 816 insertions(+), 63 deletions(-) diff --git a/bridge/go-llvm-cabi-oracle.cpp b/bridge/go-llvm-cabi-oracle.cpp index 45c2406..4ba1b53 100644 --- a/bridge/go-llvm-cabi-oracle.cpp +++ b/bridge/go-llvm-cabi-oracle.cpp @@ -139,6 +139,7 @@ class EightByteInfo { void incorporateScalar(Btype *bt); void determineABITypesForARM_AAPCS(); void determineABITypesForX86_64_SysV(); + void determineABITypesForRISC_V(); TypeManager *tm() const { return typeManager_; } }; @@ -158,6 +159,9 @@ EightByteInfo::EightByteInfo(Btype *bt, TypeManager *tmgr) determineABITypesForARM_AAPCS(); } break; + case llvm::CallingConv::C: + determineABITypesForRISC_V(); + break; default: llvm::errs() << "unsupported llvm::CallingConv::ID " << cconv << "\n"; break; @@ -489,6 +493,80 @@ void EightByteInfo::determineABITypesForX86_64_SysV() ebrs_[0].abiDirectType = tm()->llvmDoubleType(); } +// Select the appropriate abi type for each eight-byte region within +// an EightByteInfo. Pure floating point types are mapped onto float, +// double, or <2 x float> (a vector type), integer types (or something +// that is a mix of integer and non-integer) are mapped onto the +// appropriately sized integer type. +// +// Problems arise in the code below when dealing with structures with +// constructs that inject additional padding. For example, consider +// the following struct passed by value: +// +// struct { +// f1 int8 +// f2 [0]uint64 +// f3 int8 +// } +// +// Without taking into account the over-alignment of field f3, we would +// wind up with two regions, each with type int8. This in itself is not so +// bad, but creating a struct from these two types (via ::computeABIStructType) +// would give us { int8, int8 }, in which the second field doesn't have +// the correct alignment. Work around this by checking for such situations +// and promoting the type of the first EBR to 64 bits. +// +void EightByteInfo::determineABITypesForRISC_V() { + // In the direct case, ebrs_.size() cannot be greater than 2 because parameters + // larger than 16 bytes are passed indirectly. + assert(ebrs_.size() <= 2); + unsigned intRegions = 0; + unsigned floatRegions = 0; + for (auto &ebr : ebrs_) { + if (ebr.abiDirectType != nullptr) + continue; + TypDisp regionDisp = ebr.getRegionTypDisp(); + if (regionDisp == FlavSSE) { + // Case 1: two floats -> two float structs + if (ebr.types.size() == 2) { + assert(ebr.types[0] == tm()->llvmDoubleType() || + ebr.types[0] == tm()->llvmFloatType() || + ebr.types[1] == tm()->llvmDoubleType() || + ebr.types[1] == tm()->llvmFloatType()); + ebr.abiDirectType = tm()->makeLLVMTwoElementStructType(ebr.types[0], ebr.types[1]); + } else if (ebr.types.size() == 1) { + assert(ebr.types[0] == tm()->llvmDoubleType() || + ebr.types[0] == tm()->llvmFloatType()); + ebr.abiDirectType = ebr.types[0]; + } else { + assert(false && "this should never happen"); + } + floatRegions += 1; + } else { + unsigned nel = ebr.offsets.size(); + unsigned bytes = ebr.offsets[nel-1] - ebr.offsets[0] + + tm()->llvmTypeSize(ebr.types[nel-1]); + assert(bytes && bytes <= 8); + // Preserve pointerness for the use of GC. + // TODO: this assumes pointer is 8 byte, so we never pack pointer + // and other stuff together. + if (ebr.types[0]->isPointerTy()) + ebr.abiDirectType = tm()->llvmPtrType(); + else + ebr.abiDirectType = tm()->llvmArbitraryIntegerType(bytes); + intRegions += 1; + } + } + + // See the example above for more on why this is needed. + if (intRegions == 2 && + ebrs_[0].abiDirectType->isIntegerTy()) + ebrs_[0].abiDirectType = tm()->llvmArbitraryIntegerType(8); + else if (floatRegions == 2 && + ebrs_[0].abiDirectType == tm()->llvmFloatType()) + ebrs_[0].abiDirectType = tm()->llvmDoubleType(); +} + //...................................................................... llvm::Type *CABIParamInfo::computeABIStructType(TypeManager *tm) const @@ -554,6 +632,10 @@ class ABIState { availIntRegs_ = 8; availSIMDFPRegs_ = 8; break; + case llvm::CallingConv::C: + availIntRegs_ = 8; + availFloatRegs_ = 8; + break; default: llvm::errs() << "unsupported llvm::CallingConv::ID " << cconv << "\n"; break; @@ -576,6 +658,11 @@ class ABIState { availSIMDFPRegs_ = t; argCount_ += 1; } + void addDirectFloatArg() { + if (availFloatRegs_) + availFloatRegs_ -= 1; + argCount_ += 1; + } void addIndirectArg() { argCount_ += 1; } void addIndirectReturn() { if (availIntRegs_) @@ -589,6 +676,7 @@ class ABIState { unsigned availIntRegs() const { return availIntRegs_; } unsigned availSSERegs() const { return availSSERegs_; } unsigned availSIMDFPRegs() const { return availSIMDFPRegs_; } + unsigned availFloatRegs() const { return availFloatRegs_; } void clearAvailIntRegs() { availIntRegs_ = 0; } void clearAvailSIMDFPRegs() { availSIMDFPRegs_ = 0; } @@ -596,6 +684,7 @@ class ABIState { unsigned availIntRegs_; unsigned availSSERegs_; unsigned availSIMDFPRegs_; + unsigned availFloatRegs_; unsigned argCount_; }; @@ -637,7 +726,8 @@ void CABIOracle::setCC() ccID_ = typeManager_->callingConv(); // Supported architectures at present. assert(ccID_ == llvm::CallingConv::X86_64_SysV || - ccID_ == llvm::CallingConv::ARM_AAPCS); + ccID_ == llvm::CallingConv::ARM_AAPCS || + ccID_ == llvm::CallingConv::C); if (cc_ != nullptr) { return; @@ -649,6 +739,9 @@ void CABIOracle::setCC() case llvm::CallingConv::ARM_AAPCS: cc_ = std::unique_ptr(new CABIOracleARM_AAPCS(typeManager_)); break; + case llvm::CallingConv::C: + cc_ = std::unique_ptr( new CABIOracleRISC_V(typeManager_)); + break; default: llvm::errs() << "unsupported llvm::CallingConv::ID " << ccID_ << "\n"; break; @@ -1155,3 +1248,147 @@ CABIParamInfo CABIOracleARM_AAPCS::analyzeABIReturn(Btype *resultType, } //...................................................................... + +CABIOracleRISC_V::CABIOracleRISC_V(TypeManager *typeManager) + : CABIOracleArgumentAnalyzer(typeManager) {} + +CABIParamDisp CABIOracleRISC_V::classifyArgType(Btype *btype) +{ + int64_t sz = tm_->typeSize(btype); + return (sz == 0 ? ParmIgnore : ((sz <= 16) ? ParmDirect : ParmIndirect)); +} + +// Given the number of registers that we think a param is going to consume, and +// a state object storing the registers used so far, canPassDirectly() makes a +// decision as to whether a given param can be passed directly in registers vs +// in memory. +// +// Note the first clause, "if (regsInt + regsSIMDFP == 1) return true". This may +// seem counter-intuitive (why no check against the state object?), but this way +// of doing things is the convention used by other front ends (e.g. clang). What +// is happening here is that for larger aggregate/array params (things that +// don't fit into a single register), we'll make the pass-through-memory +// semantics explicit in the function signature and generate the explict code to +// copy things into memory. For params that do fit into a single register, +// however, we just leave them all as by-value parameters and then assume that +// the back end will do the right thing (e.g. pass the first few in registers +// and then the remaining ones in memory). +// +// Doing things this way has performance advantages in that the middle-end +// (all of the machine-independent LLVM optimization passes) won't have +// to deal with the additional chunks of stack memory and code to copy +// things onto and off of the stack (not to mention the aliasing concerns +// when a local variable's address is taken and then passed in a function +// call). + +bool CABIOracleRISC_V::canPassDirectly(unsigned regsInt, + unsigned regsFloat, + ABIState &state) +{ + if (regsInt + regsFloat == 1) // see comment above + return true; + if (regsInt <= state.availIntRegs() && regsFloat <= state.availFloatRegs()) + return true; + return false; +} + +CABIParamInfo CABIOracleRISC_V::analyzeABIParam(Btype *paramType, ABIState &state) +{ + llvm::Type *ptyp = paramType->type(); + + // The only situations in which we should be seeing AuxT types here is + // in cases where we're analyzing the signatures of builtin functions, + // meaning that there should be no structures or arrays. + assert(paramType->flavor() != Btype::AuxT || ptyp->isVoidTy() || + !(ptyp->isStructTy() || ptyp->isArrayTy() || ptyp->isVectorTy() || + ptyp->isEmptyTy() || ptyp->isIntegerTy(8) || ptyp->isIntegerTy(16))); + + CABIParamDisp pdisp = classifyArgType(paramType); + + if (pdisp == ParmIgnore) { + // Empty struct or array + llvm::Type *voidType = tm_->llvmVoidType(); + return CABIParamInfo(voidType, ParmIgnore, AttrNone, -1); + } + + int sigOff = state.argCount(); + + if (pdisp == ParmIndirect) { + // Value will be passed in memory on stack. + // Stack is always in address space 0. + llvm::Type *ptrTyp = llvm::PointerType::get(ptyp, 0); + state.addIndirectArg(); + return CABIParamInfo(ptrTyp, ParmIndirect, AttrByVal, sigOff); + } + + // Figure out what to do in the direct case + assert(pdisp == ParmDirect); + EightByteInfo ebi(paramType, tm_); + + // Figure out how many registers it would take to pass this parm directly + unsigned regsInt = 0, regsFloat = 0; + ebi.getRegisterRequirements(®sInt, ®sFloat); + + // Make direct/indirect decision + CABIParamAttr attr = AttrNone; + if (canPassDirectly(regsInt, regsFloat, state)) { + std::vector abiTypes; + for (auto &ebr : ebi.regions()) { + abiTypes.push_back(ebr.abiDirectType); + if (ebr.attr != AttrNone) { + assert(attr == AttrNone || attr == ebr.attr); + attr = ebr.attr; + } + if (ebr.getRegionTypDisp() == FlavSSE) + state.addDirectFloatArg(); + else + state.addDirectIntArg(); + } + return CABIParamInfo(abiTypes, ParmDirect, attr, sigOff); + } else { + state.addIndirectArg(); + llvm::Type *ptrTyp = llvm::PointerType::get(ptyp, 0); + return CABIParamInfo(ptrTyp, ParmIndirect, AttrByVal, sigOff); + } +} + +CABIParamInfo CABIOracleRISC_V::analyzeABIReturn(Btype *resultType, + ABIState &state) { + llvm::Type *rtyp = resultType->type(); + CABIParamDisp rdisp = + (rtyp == tm_->llvmVoidType() ? ParmIgnore + : classifyArgType(resultType)); + + if (rdisp == ParmIgnore) { + // This corresponds to a function with no returns or + // returning an empty composite. + llvm::Type *voidType = tm_->llvmVoidType(); + return CABIParamInfo(voidType, ParmIgnore, AttrNone, -1); + } + + if (rdisp == ParmIndirect) { + // Return value will be passed in memory, via a hidden + // struct return param. + // It is on stack, therefore address space 0. + llvm::Type *ptrTyp = llvm::PointerType::get(rtyp, 0); + state.addIndirectReturn(); + return CABIParamInfo(ptrTyp, ParmIndirect, AttrStructReturn, 0); + } + + // Figure out what to do in the direct case + assert(rdisp == ParmDirect); + EightByteInfo ebi(resultType, tm_); + auto ®ions = ebi.regions(); + if (regions.size() == 1) { + // Single value + return CABIParamInfo(regions[0].abiDirectType, + ParmDirect, regions[0].attr, -1); + } + + // Two-element struct + assert(regions.size() == 2); + llvm::Type *abiTyp = + tm_->makeLLVMTwoElementStructType(regions[0].abiDirectType, + regions[1].abiDirectType); + return CABIParamInfo(abiTyp, ParmDirect, AttrNone, -1); +} \ No newline at end of file diff --git a/bridge/go-llvm-cabi-oracle.h b/bridge/go-llvm-cabi-oracle.h index c186c38..6d39aba 100644 --- a/bridge/go-llvm-cabi-oracle.h +++ b/bridge/go-llvm-cabi-oracle.h @@ -248,4 +248,18 @@ class CABIOracleARM_AAPCS : public CABIOracleArgumentAnalyzer { bool canPassDirectly(unsigned regsInt, unsigned regsSSE, ABIState &state); }; +class CABIOracleRISC_V : public CABIOracleArgumentAnalyzer { +public: + // Given information on the param types and result type for a + // function, create an oracle object that can answer C ABI + // queries about the function. + CABIOracleRISC_V(TypeManager *typeManager); + CABIParamInfo analyzeABIParam(Btype *pType, ABIState &state); + CABIParamInfo analyzeABIReturn(Btype *resultType, ABIState &state); + +private: + CABIParamDisp classifyArgType(Btype *btype); + bool canPassDirectly(unsigned regsInt, unsigned regsSSE, ABIState &state); +}; + #endif // LLVMGOFRONTEND_GO_LLVM_CABI_ORACLE_H diff --git a/bridge/go-llvm.cpp b/bridge/go-llvm.cpp index 312b38b..a76cf32 100644 --- a/bridge/go-llvm.cpp +++ b/bridge/go-llvm.cpp @@ -93,6 +93,11 @@ Llvm_backend::Llvm_backend(llvm::LLVMContext &context, ownModule_->setDataLayout("e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"); triple_ = llvm::Triple("aarch64-unknown-linux-gnu"); break; + case llvm::CallingConv::C: + ownModule_->setTargetTriple("riscv64-unknown-linux-gnu"); + ownModule_->setDataLayout("e-m:e-p:64:64-i64:64-i128:128-n64-S128"); + triple_ = llvm::Triple("riscv64-unknown-linux-gnu"); + break; default: std::cerr <<"Unsupported calling convention\n"; } diff --git a/driver/ArchCpusAttrs.h b/driver/ArchCpusAttrs.h index b083dda..424544a 100644 --- a/driver/ArchCpusAttrs.h +++ b/driver/ArchCpusAttrs.h @@ -4,7 +4,7 @@ // // in combination with clang: // -// clang version 11.0.0 (https://github.com/llvm/llvm-project.git 0160ad802e899c2922bc9b29564080c22eb0908c) +// clang version 15.0.0 (git@github.com:plctlab/llvm-project.git ed6894730b4329183dc2fe2c00b6c5b4aa6ed56b) // typedef struct { @@ -21,54 +21,61 @@ typedef struct { static const CpuAttrs attrs0[] = { // first entry is default cpu { "x86-64", "+cx8,+fxsr,+mmx,+sse,+sse2,+x87"}, + { "alderlake", "+adx,+aes,+avx,+avx2,+avxvnni,+bmi,+bmi2,+cldemote,+clflushopt,+clwb,+crc32,+cx16,+cx8,+f16c,+fma,+fsgsbase,+fxsr,+gfni,+hreset,+invpcid,+kl,+lzcnt,+mmx,+movbe,+movdir64b,+movdiri,+pclmul,+pconfig,+pku,+popcnt,+prfchw,+ptwrite,+rdpid,+rdrnd,+rdseed,+sahf,+serialize,+sgx,+sha,+shstk,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+vaes,+vpclmulqdq,+waitpkg,+widekl,+x87,+xsave,+xsavec,+xsaveopt,+xsaves"}, { "amdfam10", "+3dnow,+3dnowa,+cx16,+cx8,+fxsr,+lzcnt,+mmx,+popcnt,+prfchw,+sahf,+sse,+sse2,+sse3,+sse4a,+x87"}, { "athlon-fx", "+3dnow,+3dnowa,+cx8,+fxsr,+mmx,+sse,+sse2,+x87"}, { "athlon64", "+3dnow,+3dnowa,+cx8,+fxsr,+mmx,+sse,+sse2,+x87"}, { "athlon64-sse3", "+3dnow,+3dnowa,+cx8,+fxsr,+mmx,+sse,+sse2,+sse3,+x87"}, { "atom", "+cx16,+cx8,+fxsr,+mmx,+movbe,+sahf,+sse,+sse2,+sse3,+ssse3,+x87"}, { "barcelona", "+3dnow,+3dnowa,+cx16,+cx8,+fxsr,+lzcnt,+mmx,+popcnt,+prfchw,+sahf,+sse,+sse2,+sse3,+sse4a,+x87"}, - { "bdver1", "+aes,+avx,+cx16,+cx8,+fma4,+fxsr,+lwp,+lzcnt,+mmx,+pclmul,+popcnt,+prfchw,+sahf,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+sse4a,+ssse3,+x87,+xop,+xsave"}, - { "bdver2", "+aes,+avx,+bmi,+cx16,+cx8,+f16c,+fma,+fma4,+fxsr,+lwp,+lzcnt,+mmx,+pclmul,+popcnt,+prfchw,+sahf,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+sse4a,+ssse3,+tbm,+x87,+xop,+xsave"}, - { "bdver3", "+aes,+avx,+bmi,+cx16,+cx8,+f16c,+fma,+fma4,+fsgsbase,+fxsr,+lwp,+lzcnt,+mmx,+pclmul,+popcnt,+prfchw,+sahf,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+sse4a,+ssse3,+tbm,+x87,+xop,+xsave,+xsaveopt"}, - { "bdver4", "+aes,+avx,+avx2,+bmi,+bmi2,+cx16,+cx8,+f16c,+fma,+fma4,+fsgsbase,+fxsr,+lwp,+lzcnt,+mmx,+movbe,+mwaitx,+pclmul,+popcnt,+prfchw,+rdrnd,+sahf,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+sse4a,+ssse3,+tbm,+x87,+xop,+xsave,+xsaveopt"}, + { "bdver1", "+aes,+avx,+crc32,+cx16,+cx8,+fma4,+fxsr,+lwp,+lzcnt,+mmx,+pclmul,+popcnt,+prfchw,+sahf,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+sse4a,+ssse3,+x87,+xop,+xsave"}, + { "bdver2", "+aes,+avx,+bmi,+crc32,+cx16,+cx8,+f16c,+fma,+fma4,+fxsr,+lwp,+lzcnt,+mmx,+pclmul,+popcnt,+prfchw,+sahf,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+sse4a,+ssse3,+tbm,+x87,+xop,+xsave"}, + { "bdver3", "+aes,+avx,+bmi,+crc32,+cx16,+cx8,+f16c,+fma,+fma4,+fsgsbase,+fxsr,+lwp,+lzcnt,+mmx,+pclmul,+popcnt,+prfchw,+sahf,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+sse4a,+ssse3,+tbm,+x87,+xop,+xsave,+xsaveopt"}, + { "bdver4", "+aes,+avx,+avx2,+bmi,+bmi2,+crc32,+cx16,+cx8,+f16c,+fma,+fma4,+fsgsbase,+fxsr,+lwp,+lzcnt,+mmx,+movbe,+mwaitx,+pclmul,+popcnt,+prfchw,+rdrnd,+sahf,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+sse4a,+ssse3,+tbm,+x87,+xop,+xsave,+xsaveopt"}, { "bonnell", "+cx16,+cx8,+fxsr,+mmx,+movbe,+sahf,+sse,+sse2,+sse3,+ssse3,+x87"}, - { "broadwell", "+adx,+avx,+avx2,+bmi,+bmi2,+cx16,+cx8,+f16c,+fma,+fsgsbase,+fxsr,+invpcid,+lzcnt,+mmx,+movbe,+pclmul,+popcnt,+prfchw,+rdrnd,+rdseed,+sahf,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87,+xsave,+xsaveopt"}, + { "broadwell", "+adx,+avx,+avx2,+bmi,+bmi2,+crc32,+cx16,+cx8,+f16c,+fma,+fsgsbase,+fxsr,+invpcid,+lzcnt,+mmx,+movbe,+pclmul,+popcnt,+prfchw,+rdrnd,+rdseed,+sahf,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87,+xsave,+xsaveopt"}, { "btver1", "+cx16,+cx8,+fxsr,+lzcnt,+mmx,+popcnt,+prfchw,+sahf,+sse,+sse2,+sse3,+sse4a,+ssse3,+x87"}, - { "btver2", "+aes,+avx,+bmi,+cx16,+cx8,+f16c,+fxsr,+lzcnt,+mmx,+movbe,+pclmul,+popcnt,+prfchw,+sahf,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+sse4a,+ssse3,+x87,+xsave,+xsaveopt"}, - { "cannonlake", "+adx,+aes,+avx,+avx2,+avx512bw,+avx512cd,+avx512dq,+avx512f,+avx512ifma,+avx512vbmi,+avx512vl,+bmi,+bmi2,+clflushopt,+cx16,+cx8,+f16c,+fma,+fsgsbase,+fxsr,+invpcid,+lzcnt,+mmx,+movbe,+pclmul,+pku,+popcnt,+prfchw,+rdrnd,+rdseed,+sahf,+sgx,+sha,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87,+xsave,+xsavec,+xsaveopt,+xsaves"}, - { "cascadelake", "+adx,+aes,+avx,+avx2,+avx512bw,+avx512cd,+avx512dq,+avx512f,+avx512vl,+avx512vnni,+bmi,+bmi2,+clflushopt,+clwb,+cx16,+cx8,+f16c,+fma,+fsgsbase,+fxsr,+invpcid,+lzcnt,+mmx,+movbe,+pclmul,+pku,+popcnt,+prfchw,+rdrnd,+rdseed,+sahf,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87,+xsave,+xsavec,+xsaveopt,+xsaves"}, - { "cooperlake", "+adx,+aes,+avx,+avx2,+avx512bf16,+avx512bw,+avx512cd,+avx512dq,+avx512f,+avx512vl,+avx512vnni,+bmi,+bmi2,+clflushopt,+clwb,+cx16,+cx8,+f16c,+fma,+fsgsbase,+fxsr,+invpcid,+lzcnt,+mmx,+movbe,+pclmul,+pku,+popcnt,+prfchw,+rdrnd,+rdseed,+sahf,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87,+xsave,+xsavec,+xsaveopt,+xsaves"}, - { "core-avx-i", "+avx,+cx16,+cx8,+f16c,+fsgsbase,+fxsr,+mmx,+pclmul,+popcnt,+rdrnd,+sahf,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87,+xsave,+xsaveopt"}, - { "core-avx2", "+avx,+avx2,+bmi,+bmi2,+cx16,+cx8,+f16c,+fma,+fsgsbase,+fxsr,+invpcid,+lzcnt,+mmx,+movbe,+pclmul,+popcnt,+rdrnd,+sahf,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87,+xsave,+xsaveopt"}, + { "btver2", "+aes,+avx,+bmi,+crc32,+cx16,+cx8,+f16c,+fxsr,+lzcnt,+mmx,+movbe,+pclmul,+popcnt,+prfchw,+sahf,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+sse4a,+ssse3,+x87,+xsave,+xsaveopt"}, + { "cannonlake", "+adx,+aes,+avx,+avx2,+avx512bw,+avx512cd,+avx512dq,+avx512f,+avx512ifma,+avx512vbmi,+avx512vl,+bmi,+bmi2,+clflushopt,+crc32,+cx16,+cx8,+f16c,+fma,+fsgsbase,+fxsr,+invpcid,+lzcnt,+mmx,+movbe,+pclmul,+pku,+popcnt,+prfchw,+rdrnd,+rdseed,+sahf,+sgx,+sha,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87,+xsave,+xsavec,+xsaveopt,+xsaves"}, + { "cascadelake", "+adx,+aes,+avx,+avx2,+avx512bw,+avx512cd,+avx512dq,+avx512f,+avx512vl,+avx512vnni,+bmi,+bmi2,+clflushopt,+clwb,+crc32,+cx16,+cx8,+f16c,+fma,+fsgsbase,+fxsr,+invpcid,+lzcnt,+mmx,+movbe,+pclmul,+pku,+popcnt,+prfchw,+rdrnd,+rdseed,+sahf,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87,+xsave,+xsavec,+xsaveopt,+xsaves"}, + { "cooperlake", "+adx,+aes,+avx,+avx2,+avx512bf16,+avx512bw,+avx512cd,+avx512dq,+avx512f,+avx512vl,+avx512vnni,+bmi,+bmi2,+clflushopt,+clwb,+crc32,+cx16,+cx8,+f16c,+fma,+fsgsbase,+fxsr,+invpcid,+lzcnt,+mmx,+movbe,+pclmul,+pku,+popcnt,+prfchw,+rdrnd,+rdseed,+sahf,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87,+xsave,+xsavec,+xsaveopt,+xsaves"}, + { "core-avx-i", "+avx,+crc32,+cx16,+cx8,+f16c,+fsgsbase,+fxsr,+mmx,+pclmul,+popcnt,+rdrnd,+sahf,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87,+xsave,+xsaveopt"}, + { "core-avx2", "+avx,+avx2,+bmi,+bmi2,+crc32,+cx16,+cx8,+f16c,+fma,+fsgsbase,+fxsr,+invpcid,+lzcnt,+mmx,+movbe,+pclmul,+popcnt,+rdrnd,+sahf,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87,+xsave,+xsaveopt"}, { "core2", "+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+ssse3,+x87"}, - { "corei7", "+cx16,+cx8,+fxsr,+mmx,+popcnt,+sahf,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87"}, - { "corei7-avx", "+avx,+cx16,+cx8,+fxsr,+mmx,+pclmul,+popcnt,+sahf,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87,+xsave,+xsaveopt"}, - { "goldmont", "+aes,+clflushopt,+cx16,+cx8,+fsgsbase,+fxsr,+mmx,+movbe,+pclmul,+popcnt,+prfchw,+rdrnd,+rdseed,+sahf,+sha,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87,+xsave,+xsavec,+xsaveopt,+xsaves"}, - { "goldmont-plus", "+aes,+clflushopt,+cx16,+cx8,+fsgsbase,+fxsr,+mmx,+movbe,+pclmul,+popcnt,+prfchw,+ptwrite,+rdpid,+rdrnd,+rdseed,+sahf,+sgx,+sha,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87,+xsave,+xsavec,+xsaveopt,+xsaves"}, - { "haswell", "+avx,+avx2,+bmi,+bmi2,+cx16,+cx8,+f16c,+fma,+fsgsbase,+fxsr,+invpcid,+lzcnt,+mmx,+movbe,+pclmul,+popcnt,+rdrnd,+sahf,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87,+xsave,+xsaveopt"}, - { "icelake-client", "+adx,+aes,+avx,+avx2,+avx512bitalg,+avx512bw,+avx512cd,+avx512dq,+avx512f,+avx512ifma,+avx512vbmi,+avx512vbmi2,+avx512vl,+avx512vnni,+avx512vpopcntdq,+bmi,+bmi2,+clflushopt,+clwb,+cx16,+cx8,+f16c,+fma,+fsgsbase,+fxsr,+gfni,+invpcid,+lzcnt,+mmx,+movbe,+pclmul,+pku,+popcnt,+prfchw,+rdpid,+rdrnd,+rdseed,+sahf,+sgx,+sha,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+vaes,+vpclmulqdq,+x87,+xsave,+xsavec,+xsaveopt,+xsaves"}, - { "icelake-server", "+adx,+aes,+avx,+avx2,+avx512bitalg,+avx512bw,+avx512cd,+avx512dq,+avx512f,+avx512ifma,+avx512vbmi,+avx512vbmi2,+avx512vl,+avx512vnni,+avx512vpopcntdq,+bmi,+bmi2,+clflushopt,+clwb,+cx16,+cx8,+f16c,+fma,+fsgsbase,+fxsr,+gfni,+invpcid,+lzcnt,+mmx,+movbe,+pclmul,+pconfig,+pku,+popcnt,+prfchw,+rdpid,+rdrnd,+rdseed,+sahf,+sgx,+sha,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+vaes,+vpclmulqdq,+wbnoinvd,+x87,+xsave,+xsavec,+xsaveopt,+xsaves"}, - { "ivybridge", "+avx,+cx16,+cx8,+f16c,+fsgsbase,+fxsr,+mmx,+pclmul,+popcnt,+rdrnd,+sahf,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87,+xsave,+xsaveopt"}, + { "corei7", "+crc32,+cx16,+cx8,+fxsr,+mmx,+popcnt,+sahf,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87"}, + { "corei7-avx", "+avx,+crc32,+cx16,+cx8,+fxsr,+mmx,+pclmul,+popcnt,+sahf,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87,+xsave,+xsaveopt"}, + { "goldmont", "+aes,+clflushopt,+crc32,+cx16,+cx8,+fsgsbase,+fxsr,+mmx,+movbe,+pclmul,+popcnt,+prfchw,+rdrnd,+rdseed,+sahf,+sha,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87,+xsave,+xsavec,+xsaveopt,+xsaves"}, + { "goldmont-plus", "+aes,+clflushopt,+crc32,+cx16,+cx8,+fsgsbase,+fxsr,+mmx,+movbe,+pclmul,+popcnt,+prfchw,+ptwrite,+rdpid,+rdrnd,+rdseed,+sahf,+sgx,+sha,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87,+xsave,+xsavec,+xsaveopt,+xsaves"}, + { "haswell", "+avx,+avx2,+bmi,+bmi2,+crc32,+cx16,+cx8,+f16c,+fma,+fsgsbase,+fxsr,+invpcid,+lzcnt,+mmx,+movbe,+pclmul,+popcnt,+rdrnd,+sahf,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87,+xsave,+xsaveopt"}, + { "icelake-client", "+adx,+aes,+avx,+avx2,+avx512bitalg,+avx512bw,+avx512cd,+avx512dq,+avx512f,+avx512ifma,+avx512vbmi,+avx512vbmi2,+avx512vl,+avx512vnni,+avx512vpopcntdq,+bmi,+bmi2,+clflushopt,+crc32,+cx16,+cx8,+f16c,+fma,+fsgsbase,+fxsr,+gfni,+invpcid,+lzcnt,+mmx,+movbe,+pclmul,+pku,+popcnt,+prfchw,+rdpid,+rdrnd,+rdseed,+sahf,+sgx,+sha,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+vaes,+vpclmulqdq,+x87,+xsave,+xsavec,+xsaveopt,+xsaves"}, + { "icelake-server", "+adx,+aes,+avx,+avx2,+avx512bitalg,+avx512bw,+avx512cd,+avx512dq,+avx512f,+avx512ifma,+avx512vbmi,+avx512vbmi2,+avx512vl,+avx512vnni,+avx512vpopcntdq,+bmi,+bmi2,+clflushopt,+clwb,+crc32,+cx16,+cx8,+f16c,+fma,+fsgsbase,+fxsr,+gfni,+invpcid,+lzcnt,+mmx,+movbe,+pclmul,+pconfig,+pku,+popcnt,+prfchw,+rdpid,+rdrnd,+rdseed,+sahf,+sgx,+sha,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+vaes,+vpclmulqdq,+wbnoinvd,+x87,+xsave,+xsavec,+xsaveopt,+xsaves"}, + { "ivybridge", "+avx,+crc32,+cx16,+cx8,+f16c,+fsgsbase,+fxsr,+mmx,+pclmul,+popcnt,+rdrnd,+sahf,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87,+xsave,+xsaveopt"}, { "k8", "+3dnow,+3dnowa,+cx8,+fxsr,+mmx,+sse,+sse2,+x87"}, { "k8-sse3", "+3dnow,+3dnowa,+cx8,+fxsr,+mmx,+sse,+sse2,+sse3,+x87"}, - { "knl", "+adx,+aes,+avx,+avx2,+avx512cd,+avx512er,+avx512f,+avx512pf,+bmi,+bmi2,+cx16,+cx8,+f16c,+fma,+fsgsbase,+fxsr,+invpcid,+lzcnt,+mmx,+movbe,+pclmul,+popcnt,+prefetchwt1,+prfchw,+rdrnd,+rdseed,+sahf,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87,+xsave,+xsaveopt"}, - { "knm", "+adx,+aes,+avx,+avx2,+avx512cd,+avx512er,+avx512f,+avx512pf,+avx512vpopcntdq,+bmi,+bmi2,+cx16,+cx8,+f16c,+fma,+fsgsbase,+fxsr,+invpcid,+lzcnt,+mmx,+movbe,+pclmul,+popcnt,+prefetchwt1,+prfchw,+rdrnd,+rdseed,+sahf,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87,+xsave,+xsaveopt"}, - { "nehalem", "+cx16,+cx8,+fxsr,+mmx,+popcnt,+sahf,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87"}, + { "knl", "+adx,+aes,+avx,+avx2,+avx512cd,+avx512er,+avx512f,+avx512pf,+bmi,+bmi2,+crc32,+cx16,+cx8,+f16c,+fma,+fsgsbase,+fxsr,+invpcid,+lzcnt,+mmx,+movbe,+pclmul,+popcnt,+prefetchwt1,+prfchw,+rdrnd,+rdseed,+sahf,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87,+xsave,+xsaveopt"}, + { "knm", "+adx,+aes,+avx,+avx2,+avx512cd,+avx512er,+avx512f,+avx512pf,+avx512vpopcntdq,+bmi,+bmi2,+crc32,+cx16,+cx8,+f16c,+fma,+fsgsbase,+fxsr,+invpcid,+lzcnt,+mmx,+movbe,+pclmul,+popcnt,+prefetchwt1,+prfchw,+rdrnd,+rdseed,+sahf,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87,+xsave,+xsaveopt"}, + { "nehalem", "+crc32,+cx16,+cx8,+fxsr,+mmx,+popcnt,+sahf,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87"}, { "nocona", "+cx16,+cx8,+fxsr,+mmx,+sse,+sse2,+sse3,+x87"}, { "opteron", "+3dnow,+3dnowa,+cx8,+fxsr,+mmx,+sse,+sse2,+x87"}, { "opteron-sse3", "+3dnow,+3dnowa,+cx8,+fxsr,+mmx,+sse,+sse2,+sse3,+x87"}, { "penryn", "+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87"}, - { "sandybridge", "+avx,+cx16,+cx8,+fxsr,+mmx,+pclmul,+popcnt,+sahf,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87,+xsave,+xsaveopt"}, - { "silvermont", "+cx16,+cx8,+fxsr,+mmx,+movbe,+pclmul,+popcnt,+prfchw,+rdrnd,+sahf,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87"}, - { "skx", "+adx,+aes,+avx,+avx2,+avx512bw,+avx512cd,+avx512dq,+avx512f,+avx512vl,+bmi,+bmi2,+clflushopt,+clwb,+cx16,+cx8,+f16c,+fma,+fsgsbase,+fxsr,+invpcid,+lzcnt,+mmx,+movbe,+pclmul,+pku,+popcnt,+prfchw,+rdrnd,+rdseed,+sahf,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87,+xsave,+xsavec,+xsaveopt,+xsaves"}, - { "skylake", "+adx,+aes,+avx,+avx2,+bmi,+bmi2,+clflushopt,+cx16,+cx8,+f16c,+fma,+fsgsbase,+fxsr,+invpcid,+lzcnt,+mmx,+movbe,+pclmul,+popcnt,+prfchw,+rdrnd,+rdseed,+sahf,+sgx,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87,+xsave,+xsavec,+xsaveopt,+xsaves"}, - { "skylake-avx512", "+adx,+aes,+avx,+avx2,+avx512bw,+avx512cd,+avx512dq,+avx512f,+avx512vl,+bmi,+bmi2,+clflushopt,+clwb,+cx16,+cx8,+f16c,+fma,+fsgsbase,+fxsr,+invpcid,+lzcnt,+mmx,+movbe,+pclmul,+pku,+popcnt,+prfchw,+rdrnd,+rdseed,+sahf,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87,+xsave,+xsavec,+xsaveopt,+xsaves"}, - { "slm", "+cx16,+cx8,+fxsr,+mmx,+movbe,+pclmul,+popcnt,+prfchw,+rdrnd,+sahf,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87"}, - { "tigerlake", "+adx,+aes,+avx,+avx2,+avx512bitalg,+avx512bw,+avx512cd,+avx512dq,+avx512f,+avx512ifma,+avx512vbmi,+avx512vbmi2,+avx512vl,+avx512vnni,+avx512vp2intersect,+avx512vpopcntdq,+bmi,+bmi2,+clflushopt,+clwb,+cx16,+cx8,+f16c,+fma,+fsgsbase,+fxsr,+gfni,+invpcid,+lzcnt,+mmx,+movbe,+movdir64b,+movdiri,+pclmul,+pku,+popcnt,+prfchw,+rdpid,+rdrnd,+rdseed,+sahf,+sgx,+sha,+shstk,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+vaes,+vpclmulqdq,+x87,+xsave,+xsavec,+xsaveopt,+xsaves"}, - { "tremont", "+aes,+clflushopt,+clwb,+cx16,+cx8,+fsgsbase,+fxsr,+gfni,+mmx,+movbe,+pclmul,+popcnt,+prfchw,+ptwrite,+rdpid,+rdrnd,+rdseed,+sahf,+sgx,+sha,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87,+xsave,+xsavec,+xsaveopt,+xsaves"}, - { "westmere", "+cx16,+cx8,+fxsr,+mmx,+pclmul,+popcnt,+sahf,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87"}, - { "znver1", "+adx,+aes,+avx,+avx2,+bmi,+bmi2,+clflushopt,+clzero,+cx16,+cx8,+f16c,+fma,+fsgsbase,+fxsr,+lzcnt,+mmx,+movbe,+mwaitx,+pclmul,+popcnt,+prfchw,+rdrnd,+rdseed,+sahf,+sha,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+sse4a,+ssse3,+x87,+xsave,+xsavec,+xsaveopt,+xsaves"}, - { "znver2", "+adx,+aes,+avx,+avx2,+bmi,+bmi2,+clflushopt,+clwb,+clzero,+cx16,+cx8,+f16c,+fma,+fsgsbase,+fxsr,+lzcnt,+mmx,+movbe,+mwaitx,+pclmul,+popcnt,+prfchw,+rdpid,+rdrnd,+rdseed,+sahf,+sha,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+sse4a,+ssse3,+wbnoinvd,+x87,+xsave,+xsavec,+xsaveopt,+xsaves"}, + { "rocketlake", "+adx,+aes,+avx,+avx2,+avx512bitalg,+avx512bw,+avx512cd,+avx512dq,+avx512f,+avx512ifma,+avx512vbmi,+avx512vbmi2,+avx512vl,+avx512vnni,+avx512vpopcntdq,+bmi,+bmi2,+clflushopt,+crc32,+cx16,+cx8,+f16c,+fma,+fsgsbase,+fxsr,+gfni,+invpcid,+lzcnt,+mmx,+movbe,+pclmul,+pku,+popcnt,+prfchw,+rdpid,+rdrnd,+rdseed,+sahf,+sha,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+vaes,+vpclmulqdq,+x87,+xsave,+xsavec,+xsaveopt,+xsaves"}, + { "sandybridge", "+avx,+crc32,+cx16,+cx8,+fxsr,+mmx,+pclmul,+popcnt,+sahf,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87,+xsave,+xsaveopt"}, + { "sapphirerapids", "+adx,+aes,+amx-bf16,+amx-int8,+amx-tile,+avx,+avx2,+avx512bf16,+avx512bitalg,+avx512bw,+avx512cd,+avx512dq,+avx512f,+avx512fp16,+avx512ifma,+avx512vbmi,+avx512vbmi2,+avx512vl,+avx512vnni,+avx512vp2intersect,+avx512vpopcntdq,+avxvnni,+bmi,+bmi2,+cldemote,+clflushopt,+clwb,+crc32,+cx16,+cx8,+enqcmd,+f16c,+fma,+fsgsbase,+fxsr,+gfni,+invpcid,+lzcnt,+mmx,+movbe,+movdir64b,+movdiri,+pclmul,+pconfig,+pku,+popcnt,+prfchw,+ptwrite,+rdpid,+rdrnd,+rdseed,+sahf,+serialize,+sgx,+sha,+shstk,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+tsxldtrk,+uintr,+vaes,+vpclmulqdq,+waitpkg,+wbnoinvd,+x87,+xsave,+xsavec,+xsaveopt,+xsaves"}, + { "silvermont", "+crc32,+cx16,+cx8,+fxsr,+mmx,+movbe,+pclmul,+popcnt,+prfchw,+rdrnd,+sahf,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87"}, + { "skx", "+adx,+aes,+avx,+avx2,+avx512bw,+avx512cd,+avx512dq,+avx512f,+avx512vl,+bmi,+bmi2,+clflushopt,+clwb,+crc32,+cx16,+cx8,+f16c,+fma,+fsgsbase,+fxsr,+invpcid,+lzcnt,+mmx,+movbe,+pclmul,+pku,+popcnt,+prfchw,+rdrnd,+rdseed,+sahf,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87,+xsave,+xsavec,+xsaveopt,+xsaves"}, + { "skylake", "+adx,+aes,+avx,+avx2,+bmi,+bmi2,+clflushopt,+crc32,+cx16,+cx8,+f16c,+fma,+fsgsbase,+fxsr,+invpcid,+lzcnt,+mmx,+movbe,+pclmul,+popcnt,+prfchw,+rdrnd,+rdseed,+sahf,+sgx,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87,+xsave,+xsavec,+xsaveopt,+xsaves"}, + { "skylake-avx512", "+adx,+aes,+avx,+avx2,+avx512bw,+avx512cd,+avx512dq,+avx512f,+avx512vl,+bmi,+bmi2,+clflushopt,+clwb,+crc32,+cx16,+cx8,+f16c,+fma,+fsgsbase,+fxsr,+invpcid,+lzcnt,+mmx,+movbe,+pclmul,+pku,+popcnt,+prfchw,+rdrnd,+rdseed,+sahf,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87,+xsave,+xsavec,+xsaveopt,+xsaves"}, + { "slm", "+crc32,+cx16,+cx8,+fxsr,+mmx,+movbe,+pclmul,+popcnt,+prfchw,+rdrnd,+sahf,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87"}, + { "tigerlake", "+adx,+aes,+avx,+avx2,+avx512bitalg,+avx512bw,+avx512cd,+avx512dq,+avx512f,+avx512ifma,+avx512vbmi,+avx512vbmi2,+avx512vl,+avx512vnni,+avx512vp2intersect,+avx512vpopcntdq,+bmi,+bmi2,+clflushopt,+clwb,+crc32,+cx16,+cx8,+f16c,+fma,+fsgsbase,+fxsr,+gfni,+invpcid,+kl,+lzcnt,+mmx,+movbe,+movdir64b,+movdiri,+pclmul,+pku,+popcnt,+prfchw,+rdpid,+rdrnd,+rdseed,+sahf,+sgx,+sha,+shstk,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+vaes,+vpclmulqdq,+widekl,+x87,+xsave,+xsavec,+xsaveopt,+xsaves"}, + { "tremont", "+aes,+clflushopt,+clwb,+crc32,+cx16,+cx8,+fsgsbase,+fxsr,+gfni,+mmx,+movbe,+pclmul,+popcnt,+prfchw,+ptwrite,+rdpid,+rdrnd,+rdseed,+sahf,+sgx,+sha,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87,+xsave,+xsavec,+xsaveopt,+xsaves"}, + { "westmere", "+crc32,+cx16,+cx8,+fxsr,+mmx,+pclmul,+popcnt,+sahf,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87"}, + { "x86-64-v2", "+crc32,+cx16,+cx8,+fxsr,+mmx,+popcnt,+sahf,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87"}, + { "x86-64-v3", "+avx,+avx2,+bmi,+bmi2,+crc32,+cx16,+cx8,+f16c,+fma,+fxsr,+lzcnt,+mmx,+movbe,+popcnt,+sahf,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87,+xsave"}, + { "x86-64-v4", "+avx,+avx2,+avx512bw,+avx512cd,+avx512dq,+avx512f,+avx512vl,+bmi,+bmi2,+crc32,+cx16,+cx8,+f16c,+fma,+fxsr,+lzcnt,+mmx,+movbe,+popcnt,+sahf,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87,+xsave"}, + { "znver1", "+adx,+aes,+avx,+avx2,+bmi,+bmi2,+clflushopt,+clzero,+crc32,+cx16,+cx8,+f16c,+fma,+fsgsbase,+fxsr,+lzcnt,+mmx,+movbe,+mwaitx,+pclmul,+popcnt,+prfchw,+rdrnd,+rdseed,+sahf,+sha,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+sse4a,+ssse3,+x87,+xsave,+xsavec,+xsaveopt,+xsaves"}, + { "znver2", "+adx,+aes,+avx,+avx2,+bmi,+bmi2,+clflushopt,+clwb,+clzero,+crc32,+cx16,+cx8,+f16c,+fma,+fsgsbase,+fxsr,+lzcnt,+mmx,+movbe,+mwaitx,+pclmul,+popcnt,+prfchw,+rdpid,+rdrnd,+rdseed,+sahf,+sha,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+sse4a,+ssse3,+wbnoinvd,+x87,+xsave,+xsavec,+xsaveopt,+xsaves"}, + { "znver3", "+adx,+aes,+avx,+avx2,+bmi,+bmi2,+clflushopt,+clwb,+clzero,+crc32,+cx16,+cx8,+f16c,+fma,+fsgsbase,+fxsr,+invpcid,+lzcnt,+mmx,+movbe,+mwaitx,+pclmul,+pku,+popcnt,+prfchw,+rdpid,+rdrnd,+rdseed,+sahf,+sha,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+sse4a,+ssse3,+vaes,+vpclmulqdq,+wbnoinvd,+x87,+xsave,+xsavec,+xsaveopt,+xsaves"}, { "", "" } // sentinel }; @@ -77,52 +84,80 @@ static const CpuAttrs attrs1[] = { // first entry is default cpu { "generic", "+neon"}, { "a64fx", "+aes,+crc,+crypto,+fp-armv8,+fullfp16,+lse,+neon,+ras,+rdm,+sha2,+sve,+v8.2a"}, - { "apple-a10", "+aes,+crc,+crypto,+fp-armv8,+neon,+rdm,+sha2,+zcm,+zcz"}, - { "apple-a11", "+aes,+crc,+crypto,+fp-armv8,+lse,+neon,+ras,+rdm,+sha2,+v8.2a,+zcm,+zcz"}, + { "apple-a10", "+aes,+crc,+crypto,+fp-armv8,+neon,+rdm,+sha2,+v8a,+zcm,+zcz"}, + { "apple-a11", "+aes,+crc,+crypto,+fp-armv8,+fullfp16,+lse,+neon,+ras,+rdm,+sha2,+v8.2a,+zcm,+zcz"}, { "apple-a12", "+aes,+crc,+crypto,+fp-armv8,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+v8.3a,+zcm,+zcz"}, { "apple-a13", "+aes,+crc,+crypto,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+sm4,+v8.4a,+zcm,+zcz"}, - { "apple-a7", "+aes,+crypto,+fp-armv8,+neon,+sha2,+zcm,+zcz"}, - { "apple-a8", "+aes,+crypto,+fp-armv8,+neon,+sha2,+zcm,+zcz"}, - { "apple-a9", "+aes,+crypto,+fp-armv8,+neon,+sha2,+zcm,+zcz"}, + { "apple-a14", "+aes,+crc,+crypto,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+v8.5a,+zcm,+zcz"}, + { "apple-a7", "+aes,+crypto,+fp-armv8,+neon,+sha2,+v8a,+zcm,+zcz"}, + { "apple-a8", "+aes,+crypto,+fp-armv8,+neon,+sha2,+v8a,+zcm,+zcz"}, + { "apple-a9", "+aes,+crypto,+fp-armv8,+neon,+sha2,+v8a,+zcm,+zcz"}, + { "apple-m1", "+aes,+crc,+crypto,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+v8.5a,+zcm,+zcz"}, { "apple-s4", "+aes,+crc,+crypto,+fp-armv8,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+v8.3a,+zcm,+zcz"}, { "apple-s5", "+aes,+crc,+crypto,+fp-armv8,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+v8.3a,+zcm,+zcz"}, { "carmel", "+aes,+crc,+crypto,+fp-armv8,+fullfp16,+lse,+neon,+ras,+rdm,+sha2,+v8.2a"}, - { "cortex-a34", "+aes,+crc,+crypto,+fp-armv8,+neon,+sha2"}, - { "cortex-a35", "+aes,+crc,+crypto,+fp-armv8,+neon,+sha2"}, - { "cortex-a53", "+aes,+crc,+crypto,+fp-armv8,+neon,+sha2"}, + { "cortex-a34", "+aes,+crc,+crypto,+fp-armv8,+neon,+sha2,+v8a"}, + { "cortex-a35", "+aes,+crc,+crypto,+fp-armv8,+neon,+sha2,+v8a"}, + { "cortex-a510", "+crc,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+pauth,+ras,+rcpc,+rdm,+sve,+sve2,+sve2-bitperm,+v9a"}, + { "cortex-a53", "+aes,+crc,+crypto,+fp-armv8,+neon,+sha2,+v8a"}, { "cortex-a55", "+aes,+crc,+crypto,+dotprod,+fp-armv8,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+v8.2a"}, - { "cortex-a57", "+aes,+crc,+crypto,+fp-armv8,+neon,+sha2"}, + { "cortex-a57", "+aes,+crc,+crypto,+fp-armv8,+neon,+sha2,+v8a"}, { "cortex-a65", "+aes,+crc,+crypto,+dotprod,+fp-armv8,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+v8.2a"}, { "cortex-a65ae", "+aes,+crc,+crypto,+dotprod,+fp-armv8,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+v8.2a"}, - { "cortex-a72", "+aes,+crc,+crypto,+fp-armv8,+neon,+sha2"}, - { "cortex-a73", "+aes,+crc,+crypto,+fp-armv8,+neon,+sha2"}, + { "cortex-a710", "+crc,+dotprod,+flagm,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+pauth,+ras,+rcpc,+rdm,+sve,+sve2,+sve2-bitperm,+v9a"}, + { "cortex-a72", "+aes,+crc,+crypto,+fp-armv8,+neon,+sha2,+v8a"}, + { "cortex-a73", "+aes,+crc,+crypto,+fp-armv8,+neon,+sha2,+v8a"}, { "cortex-a75", "+aes,+crc,+crypto,+dotprod,+fp-armv8,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+v8.2a"}, { "cortex-a76", "+aes,+crc,+crypto,+dotprod,+fp-armv8,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+v8.2a"}, { "cortex-a76ae", "+aes,+crc,+crypto,+dotprod,+fp-armv8,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+v8.2a"}, { "cortex-a77", "+aes,+crc,+crypto,+dotprod,+fp-armv8,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+v8.2a"}, { "cortex-a78", "+aes,+crc,+crypto,+dotprod,+fp-armv8,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+v8.2a"}, + { "cortex-a78c", "+aes,+crc,+crypto,+dotprod,+fp-armv8,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+v8.2a"}, + { "cortex-r82", "+crc,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+v8r"}, { "cortex-x1", "+aes,+crc,+crypto,+dotprod,+fp-armv8,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+v8.2a"}, - { "cyclone", "+aes,+crypto,+fp-armv8,+neon,+sha2,+zcm,+zcz"}, - { "exynos-m3", "+aes,+crc,+crypto,+fp-armv8,+neon,+sha2"}, + { "cortex-x1c", "+aes,+crc,+crypto,+dotprod,+fp-armv8,+fullfp16,+lse,+neon,+pauth,+ras,+rcpc,+rdm,+sha2,+v8.2a"}, + { "cortex-x2", "+crc,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+pauth,+ras,+rcpc,+rdm,+sve,+sve2,+sve2-bitperm,+v9a"}, + { "cyclone", "+aes,+crypto,+fp-armv8,+neon,+sha2,+v8a,+zcm,+zcz"}, + { "exynos-m3", "+aes,+crc,+crypto,+fp-armv8,+neon,+sha2,+v8a"}, { "exynos-m4", "+aes,+crc,+crypto,+dotprod,+fp-armv8,+fullfp16,+lse,+neon,+ras,+rdm,+sha2,+v8.2a"}, { "exynos-m5", "+aes,+crc,+crypto,+dotprod,+fp-armv8,+fullfp16,+lse,+neon,+ras,+rdm,+sha2,+v8.2a"}, - { "falkor", "+aes,+crc,+crypto,+fp-armv8,+neon,+rdm,+sha2"}, - { "kryo", "+aes,+crc,+crypto,+fp-armv8,+neon,+sha2"}, + { "falkor", "+aes,+crc,+crypto,+fp-armv8,+neon,+rdm,+sha2,+v8a"}, + { "kryo", "+aes,+crc,+crypto,+fp-armv8,+neon,+sha2,+v8a"}, + { "neoverse-512tvb", "+aes,+crc,+crypto,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+sm4,+sve,+v8.4a"}, { "neoverse-e1", "+aes,+crc,+crypto,+dotprod,+fp-armv8,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+v8.2a"}, { "neoverse-n1", "+aes,+crc,+crypto,+dotprod,+fp-armv8,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+spe,+v8.2a"}, + { "neoverse-n2", "+aes,+crc,+crypto,+dotprod,+fp-armv8,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sve,+sve2,+sve2-bitperm,+v8.5a"}, + { "neoverse-v1", "+aes,+crc,+crypto,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+sm4,+sve,+v8.4a"}, { "saphira", "+aes,+crc,+crypto,+fp-armv8,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+spe,+v8.3a"}, - { "thunderx", "+aes,+crc,+crypto,+fp-armv8,+neon,+sha2,+spe"}, + { "thunderx", "+aes,+crc,+crypto,+fp-armv8,+neon,+sha2,+spe,+v8a"}, { "thunderx2t99", "+aes,+crc,+crypto,+fp-armv8,+lse,+neon,+rdm,+sha2,+v8.1a"}, { "thunderx3t110", "+aes,+crc,+crypto,+fp-armv8,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+spe,+v8.3a"}, - { "thunderxt81", "+aes,+crc,+crypto,+fp-armv8,+neon,+sha2,+spe"}, - { "thunderxt83", "+aes,+crc,+crypto,+fp-armv8,+neon,+sha2,+spe"}, - { "thunderxt88", "+aes,+crc,+crypto,+fp-armv8,+neon,+sha2,+spe"}, + { "thunderxt81", "+aes,+crc,+crypto,+fp-armv8,+neon,+sha2,+spe,+v8a"}, + { "thunderxt83", "+aes,+crc,+crypto,+fp-armv8,+neon,+sha2,+spe,+v8a"}, + { "thunderxt88", "+aes,+crc,+crypto,+fp-armv8,+neon,+sha2,+spe,+v8a"}, { "tsv110", "+aes,+crc,+crypto,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rdm,+sha2,+spe,+v8.2a"}, { "", "" } // sentinel }; +// triple: riscv64-unknown-linux-gnu +static const CpuAttrs attrs2[] = { + // first entry is default cpu + { "", "+64bit,+a,+c,+d,+f,+m,+relax,-save-restore"}, + { "generic-rv64", "+64bit,+a,+c,+d,+f,+m,+relax,-save-restore"}, + { "rocket-rv64", "+64bit,+a,+c,+d,+f,+m,+relax,-save-restore"}, + { "sifive-7-rv64", "+64bit,+a,+c,+d,+f,+m,+relax,-save-restore"}, + { "sifive-s21", "+64bit,+a,+c,+m,+relax,-save-restore"}, + { "sifive-s51", "+64bit,+a,+c,+m,+relax,-save-restore"}, + { "sifive-s54", "+64bit,+a,+c,+d,+f,+m,+relax,-save-restore"}, + { "sifive-s76", "+64bit,+a,+c,+d,+f,+m,+relax,-save-restore"}, + { "sifive-u54", "+64bit,+a,+c,+d,+f,+m,+relax,-save-restore"}, + { "sifive-u74", "+64bit,+a,+c,+d,+f,+m,+relax,-save-restore"}, + { "", "" } // sentinel +}; + const TripleCpus triples[] = { { "x86_64-unknown-linux-gnu", &attrs0[0] }, { "aarch64-unknown-linux-gnu", &attrs1[0] }, + { "riscv64-unknown-linux-gnu", &attrs2[0] }, { "", nullptr } // sentinel }; diff --git a/driver/CompileGo.cpp b/driver/CompileGo.cpp index b317c9b..9a369e5 100644 --- a/driver/CompileGo.cpp +++ b/driver/CompileGo.cpp @@ -412,6 +412,9 @@ bool CompileGoImpl::setup(const Action &jobAction) TargetOptions Options; + if (triple_.getArch() == llvm::Triple::riscv64) + Options.MCOptions.ABIName = "lp64d"; + auto jat = jobAction.type(); assert(jat == Action::A_CompileAndAssemble || jat == Action::A_Compile); @@ -728,6 +731,9 @@ void CompileGoImpl::setCConv() case Triple::aarch64: cconv_ = CallingConv::ARM_AAPCS; break; + case Triple::riscv64: + cconv_ = CallingConv::C; + break; default: errs() << "currently Gollvm is not supported on architecture " << triple_.getArchName().str()<< "\n"; @@ -856,9 +862,10 @@ bool CompileGoImpl::invokeBackEnd(const Action &jobAction) createTargetTransformInfoWrapperPass(target_->getTargetIRAnalysis())); createPasses(modulePasses, functionPasses); - // Disable inlining getg in some cases on x86_64. - if (triple_.getArch() == llvm::Triple::x86_64) { - modulePasses.add(createGoSafeGetgPass()); + // Disable inlining getg in some cases on x86_64 and RISC-V. + if (triple_.getArch() == llvm::Triple::x86_64 || + triple_.getArch() == llvm::Triple::riscv64) { + modulePasses.add(createGoSafeGetgPass()); } // Add statepoint insertion pass to the end of optimization pipeline, diff --git a/driver/Driver.cpp b/driver/Driver.cpp index 777cc2b..c8a7db5 100644 --- a/driver/Driver.cpp +++ b/driver/Driver.cpp @@ -418,10 +418,6 @@ ToolChain *Driver::setup() triple_ = defaultTargetTriple; if (const opt::Arg *arg = args_.getLastArg(gollvm::options::OPT_target_EQ)) triple_ = Triple(Triple::normalize(arg->getValue())); - if (triple_ != defaultTargetTriple) { - errs() << progname_ << ": error: gollvm doesn't support cross compiling yet\n"; - return nullptr; - } // Honor -dumpmachine if (args_.hasArg(gollvm::options::OPT_dumpmachine)) { diff --git a/driver/GccUtils.cpp b/driver/GccUtils.cpp index f8f8c8e..01fc06c 100644 --- a/driver/GccUtils.cpp +++ b/driver/GccUtils.cpp @@ -190,6 +190,16 @@ bool GCCInstallationDetector::selectLibDirs(state &s) s.triple.setTriple(triple_.str()); s.suffixes = {""}; break; + case llvm::Triple::riscv64: + s.tripleAliases = { + triple_.str(), + "riscv64-linux-gnu", "riscv64-unknown-linux-gnu" + }; + s.libdirs.push_back("/lib"); + s.libdirs.push_back("/lib64"); + s.triple.setTriple(triple_.str()); + s.suffixes = {""}; + break; default: llvm::errs() << "error: unsupported triple " << triple_.str() << " in " << __FUNCTION__ << "\n"; diff --git a/driver/GnuTools.cpp b/driver/GnuTools.cpp index ea148f5..ca80bef 100644 --- a/driver/GnuTools.cpp +++ b/driver/GnuTools.cpp @@ -218,6 +218,9 @@ void Linker::addLDM(llvm::opt::ArgStringList &cmdArgs) // Currently only support linux/arm64 cmdArgs.push_back("aarch64linux"); break; + case llvm::Triple::riscv64: + cmdArgs.push_back("elf64lriscv"); + break; default: // unhandled architecture cmdArgs.push_back("%unknown%"); diff --git a/driver/IntegAssembler.cpp b/driver/IntegAssembler.cpp index a40be9f..77b42f8 100644 --- a/driver/IntegAssembler.cpp +++ b/driver/IntegAssembler.cpp @@ -179,6 +179,8 @@ bool IntegAssemblerImpl::invokeAssembler() assert(MRI && "Unable to create target register info!"); MCTargetOptions MCOptions; + if (triple_.getArch() == llvm::Triple::riscv64) + MCOptions.ABIName = "lp64d"; std::unique_ptr MAI( TheTarget->createMCAsmInfo(*MRI, Trip, MCOptions)); assert(MAI && "Unable to create target asm info!"); diff --git a/driver/LinuxToolChain.cpp b/driver/LinuxToolChain.cpp index bebad8c..afda0ff 100644 --- a/driver/LinuxToolChain.cpp +++ b/driver/LinuxToolChain.cpp @@ -139,6 +139,14 @@ std::string Linux::getDynamicLinker(const llvm::opt::ArgList &args) Loader = "ld-linux-x86-64.so.2"; break; } + case llvm::Triple::riscv64: + LibDir = "lib"; + Loader = "ld-linux-riscv64-lp64d.so.1"; + break; + } + if (auto *Arg = args.getLastArg(gollvm::options::OPT_sysroot_EQ)) { + std::string Sysroot = Arg->getValue(); + return Sysroot + "/" + LibDir + "/" + Loader; } if (auto *Arg = args.getLastArg(gollvm::options::OPT_sysroot_EQ)) { std::string Sysroot = Arg->getValue(); diff --git a/tools/capture-fcn-attributes.go b/tools/capture-fcn-attributes.go index 545d7cd..d50a827 100644 --- a/tools/capture-fcn-attributes.go +++ b/tools/capture-fcn-attributes.go @@ -87,6 +87,7 @@ void Add512(vstuff *v) { var supportedTriples []string = []string{ "x86_64-unknown-linux-gnu", "aarch64-unknown-linux-gnu", + "riscv64-unknown-linux-gnu", } var ( diff --git a/unittests/BackendCore/BackendCABIOracleTests.cpp b/unittests/BackendCore/BackendCABIOracleTests.cpp index c1535ba..4c80bb8 100644 --- a/unittests/BackendCore/BackendCABIOracleTests.cpp +++ b/unittests/BackendCore/BackendCABIOracleTests.cpp @@ -438,6 +438,190 @@ TEST(BackendCABIOracleTests, ExtendedArm64) { } } +TEST(BackendCABIOracleTests, ExtendedRV64) { + LLVMContext C; + std::unique_ptr bep( + new Llvm_backend(C, nullptr, nullptr, 0, llvm::Triple(), llvm::CallingConv::C)); + Llvm_backend *be = bep.get(); + + Btype *bi8t = be->integer_type(false, 8); + Btype *bu8t = be->integer_type(true, 8); + Btype *bu64t = be->integer_type(true, 64); + Btype *bu32t = be->integer_type(true, 32); + Btype *bi16t = be->integer_type(false, 16); + Btype *bf32t = be->float_type(32); + Btype *bf64t = be->float_type(64); + Btype *bpu64t = be->pointer_type(bu64t); + Btype *bpf64t = be->pointer_type(bf64t); + Btype *st0 = mkBackendStruct(be, nullptr); + Btype *st1 = mkBackendStruct(be, bi8t, "a", bu8t, "b", bf32t, "c", nullptr); + Btype *st2 = mkBackendStruct(be, bf64t, "f1", bf64t, "f2", nullptr); + Btype *st3 = mkBackendStruct(be, st2, "f1", bi8t, "f2", nullptr); + Btype *st4 = mkBackendStruct(be, bf32t, "f1", bf32t, "f2", nullptr); + Btype *st5 = mkBackendStruct(be, bf32t, "f1", nullptr); + Btype *st6 = mkBackendStruct(be, bf32t, "f1", bi8t, "a", bu8t, "b", + bu64t, "c", nullptr); + Btype *st7 = mkBackendStruct(be, bf32t, "f1", bu32t, "f2", nullptr); + Btype *st8 = mkBackendStruct(be, bi8t, "f1", bi16t, "f2", st7, "f3", nullptr); + Btype *stii = mkBackendStruct(be, bu64t, "a", bu64t, "b", nullptr); + Btype *stip = mkBackendStruct(be, bu64t, "a", bpu64t, "b", nullptr); + Btype *stpi = mkBackendStruct(be, bpu64t, "a", bu64t, "b", nullptr); + Btype *stpp = mkBackendStruct(be, bpu64t, "a", bpu64t, "b", nullptr); + Btype *at0 = be->array_type(bu32t, mkInt64Const(be, int64_t(0))); + Btype *at1 = be->array_type(bu32t, mkInt64Const(be, int64_t(1))); + Btype *at2 = be->array_type(bu32t, mkInt64Const(be, int64_t(3))); + Btype *at3 = be->array_type(bu8t, mkInt64Const(be, int64_t(16))); + + struct FcnItem { + FcnItem(const std::vector &r, + const std::vector &p, + const char *d, const char *t) + : results(r), parms(p), expDump(d), expTyp(t) { } + std::vector results; + std::vector parms; + const char *expDump; + const char *expTyp; + }; + + Btype *nt = nullptr; + std::vector items = { + + // 1 + FcnItem( { }, { }, + "Return: Ignore { void } sigOffset: -1 " + "Param 1: Direct AttrNest { i8* } sigOffset: 0", + "void (i8*)"), + + // 2 + FcnItem( { bi8t }, { }, + "Return: Direct AttrSext { i8 } sigOffset: -1 " + "Param 1: Direct AttrNest { i8* } sigOffset: 0", + "i8 (i8*)"), + + // 3 + FcnItem( { }, { bi8t }, + "Return: Ignore { void } sigOffset: -1 " + "Param 1: Direct AttrNest { i8* } sigOffset: 0 " + "Param 2: Direct AttrSext { i8 } sigOffset: 1", + "void (i8*, i8)"), + + // 4 + FcnItem( { }, { st5, bpf64t }, + "Return: Ignore { void } sigOffset: -1 " + "Param 1: Direct AttrNest { i8* } sigOffset: 0 " + "Param 2: Direct { float } sigOffset: 1 " + "Param 3: Direct { double* } sigOffset: 2", + "void (i8*, float, double*)"), + + // 5 + FcnItem({ bi8t, bf64t }, { bi8t, bu8t, st0 }, + "Return: Direct { { i8, double } } sigOffset: -1 " + "Param 1: Direct AttrNest { i8* } sigOffset: 0 " + "Param 2: Direct AttrSext { i8 } sigOffset: 1 " + "Param 3: Direct AttrZext { i8 } sigOffset: 2 " + "Param 4: Ignore { void } sigOffset: -1", + "{ i8, double } (i8*, i8, i8)"), + + // 6 + FcnItem({ st2 }, { st2, st0, st4, st1 }, + "Return: Direct { { double, double } } sigOffset: -1 " + "Param 1: Direct AttrNest { i8* } sigOffset: 0 " + "Param 2: Direct { double, double } sigOffset: 1 " + "Param 3: Ignore { void } sigOffset: -1 " + "Param 4: Direct { <2 x float> } sigOffset: 3 " + "Param 5: Direct { i64 } sigOffset: 4 ", + "{ double, double } (i8*, double, double, <2 x float>, i64)"), + + // 7 + FcnItem({ st3 }, { st3, st0, bu8t }, + "Return: Indirect AttrStructReturn { { { double, double }, i8 }* } sigOffset: 0 " + "Param 1: Direct AttrNest { i8* } sigOffset: 1 " + "Param 2: Indirect AttrByVal { { { double, double }, i8 }* } sigOffset: 2 " + "Param 3: Ignore { void } sigOffset: -1 " + "Param 4: Direct AttrZext { i8 } sigOffset: 3 ", + "void ({ { double, double }, i8 }*, i8*, " + "{ { double, double }, i8 }*, i8)"), + + // 8 + FcnItem( { st6 }, { st6, st6 }, + "Return: Direct { { i64, i64 } } sigOffset: -1 " + "Param 1: Direct AttrNest { i8* } sigOffset: 0 " + "Param 2: Direct { i64, i64 } sigOffset: 1 " + "Param 3: Direct { i64, i64 } sigOffset: 3", + "{ i64, i64 } (i8*, i64, i64, i64, i64)"), + + // 9 + FcnItem( { st8 }, { st8 }, + "Return: Direct { { i64, i32 } } sigOffset: -1 " + "Param 1: Direct AttrNest { i8* } sigOffset: 0 " + "Param 2: Direct { i64, i32 } sigOffset: 1", + "{ i64, i32 } (i8*, i64, i32)"), + + // 10 + FcnItem( { at0 }, { at1 }, + "Return: Ignore { void } sigOffset: -1 " + "Param 1: Direct AttrNest { i8* } sigOffset: 0 " + "Param 2: Direct { i32 } sigOffset: 1", + "void (i8*, i32)"), + + // 11 + FcnItem( { at2 }, { at3 }, + "Return: Direct { { i64, i32 } } sigOffset: -1 " + "Param 1: Direct AttrNest { i8* } sigOffset: 0 " + "Param 2: Direct { i64, i64 } sigOffset: 1", + "{ i64, i32 } (i8*, i64, i64)"), + + // 12 + // Make sure pointerness is preserved. + FcnItem( { stip }, { stii, stpp, stpi }, + "Return: Direct { { i64, i8* } } sigOffset: -1 " + "Param 1: Direct AttrNest { i8* } sigOffset: 0 " + "Param 2: Direct { i64, i64 } sigOffset: 1 " + "Param 3: Direct { i8*, i8* } sigOffset: 3 " + "Param 4: Direct { i8*, i64 } sigOffset: 5", + "{ i64, i8* } (i8*, i64, i64, i8*, i8*, i8*, i64)"), + }; + + unsigned count = 1; + for (auto &item : items) { + std::vector results; + std::vector params; + for (auto &r : item.results) + results.push_back(mkid(r)); + for (auto &p : item.parms) + params.push_back(mkid(p)); + Btype *rt = nullptr; + if (results.size() > 1) + rt = be->struct_type(results); + Btype *t = be->function_type(mkid(nt), params, results, rt, Location()); + BFunctionType *bft = t->castToBFunctionType(); + CABIOracle cab(bft, be->typeManager()); + + { + std::string reason; + bool equal = difftokens(item.expDump, cab.toString(), reason); + EXPECT_EQ("pass", equal ? "pass" : reason); + if (!equal) { + std::cerr << "count: " << count << "\n"; + std::cerr << "exp:\n" << item.expDump << "\n"; + std::cerr << "act:\n" << cab.toString() << "\n"; + } + } + { + std::string reason; + std::string result(repr(cab.getFunctionTypeForABI())); + bool equal = difftokens(item.expTyp, result, reason); + EXPECT_EQ("pass", equal ? "pass" : reason); + if (!equal) { + std::cerr << "count: " << count << "\n"; + std::cerr << "exp:\n" << item.expTyp << "\n"; + std::cerr << "act:\n" << result << "\n"; + } + } + count++; + } +} + TEST(BackendCABIOracleTests, RecursiveCall1Amd64) { FcnTestHarness h(llvm::CallingConv::X86_64_SysV); Llvm_backend *be = h.be(); @@ -685,6 +869,131 @@ TEST(BackendCABIOracleTests, RecursiveCall1Arm64) { EXPECT_FALSE(broken && "Module failed to verify."); } +TEST(BackendCABIOracleTests, RecursiveCall1RV64) { + FcnTestHarness h(llvm::CallingConv::C); + Llvm_backend *be = h.be(); + + // type s1 struct { + // f1, f2 float32 + // i1, i2, i3 int16 + // } + // type s2 struct { + // k float64 + // f1, f2 float32 + // } + // type s3 struct { + // f1, s1 + // f2, s2 + // } + // type s4 struct { + // } + // func foo(x s1, y s2, z s4, sm1 uint8, sm2 int8, w s3) s2 { + // if (sm1 == 0) { + // return y + // } + // return foo(x, y, z, sm1-1, sm2, w) + // } + // + + // Create struct types + Btype *bf32t = be->float_type(32); + Btype *bf64t = be->float_type(64); + Btype *bi16t = be->integer_type(false, 16); + Btype *bi8t = be->integer_type(false, 8); + Btype *bu8t = be->integer_type(true, 8); + Btype *s1 = mkBackendStruct(be, bf32t, "f1", bf32t, "f2", + bi16t, "i1", bi16t, "i2", bi16t, "i3", nullptr); + Btype *s2 = mkBackendStruct(be, bf64t, "k", bf32t, "f1", bf32t, "f2", + nullptr); + Btype *s3 = mkBackendStruct(be, s1, "f1", s2, "f2", nullptr); + Btype *s4 = mkBackendStruct(be, nullptr); + + // Create function type + BFunctionType *befty1 = mkFuncTyp(be, + L_PARM, s1, + L_PARM, s2, + L_PARM, s4, + L_PARM, bu8t, + L_PARM, bi8t, + L_PARM, s3, + L_RES, s2, + L_END); + Bfunction *func = h.mkFunction("foo", befty1); + + // sm1 == 0 + Bvariable *p3 = func->getNthParamVar(3); + Location loc; + Bexpression *vex = be->var_expression(p3, loc); + Bexpression *c0 = be->convert_expression(bu8t, mkInt32Const(be, 0), loc); + Bexpression *eq = be->binary_expression(OPERATOR_EQEQ, vex, c0, loc); + + // call + Bexpression *fn = be->function_code_expression(func, loc); + std::vector args; + Bvariable *p0 = func->getNthParamVar(0); + args.push_back(be->var_expression(p0, loc)); + + Bvariable *p1 = func->getNthParamVar(1); + args.push_back(be->var_expression(p1, loc)); + + Bvariable *p2 = func->getNthParamVar(2); + args.push_back(be->var_expression(p2, loc)); + + Bvariable *p3x = func->getNthParamVar(3); + Bexpression *vex3 = be->var_expression(p3x, loc); + Bexpression *c1 = be->convert_expression(bu8t, mkInt32Const(be, 1), loc); + Bexpression *minus = be->binary_expression(OPERATOR_MINUS, vex3, c1, loc); + args.push_back(minus); + + Bvariable *p4 = func->getNthParamVar(4); + args.push_back(be->var_expression(p4, loc)); + + Bvariable *p5 = func->getNthParamVar(5); + args.push_back(be->var_expression(p5, loc)); + Bexpression *call = be->call_expression(func, fn, args, nullptr, h.loc()); + + // return y + std::vector rvals1; + rvals1.push_back(be->var_expression(p1, loc)); + Bstatement *rst1 = h.mkReturn(rvals1, FcnTestHarness::NoAppend); + + // return call + std::vector rvals2; + rvals2.push_back(call); + Bstatement *rst2 = h.mkReturn(rvals2, FcnTestHarness::NoAppend); + + DECLARE_EXPECTED_OUTPUT(exp, R"RAW_RESULT( + %p3.ld.0 = load i8, i8* %p3.addr, align 1 + %sub.0 = sub i8 %p3.ld.0, 1 + %p4.ld.0 = load i8, i8* %p4.addr, align 1 + %cast.1 = bitcast { float, float, i16, i16, i16 }* %p0.addr to { <2 x float>, i48 }* + %field0.0 = getelementptr inbounds { <2 x float>, i48 }, { <2 x float>, i48 }* %cast.1, i32 0, i32 0 + %ld.1 = load <2 x float>, <2 x float>* %field0.0, align 8 + %field1.0 = getelementptr inbounds { <2 x float>, i48 }, { <2 x float>, i48 }* %cast.1, i32 0, i32 1 + %ld.2 = load i48, i48* %field1.0, align 8 + %cast.2 = bitcast { double, float, float }* %p1.addr to { double, <2 x float> }* + %field0.1 = getelementptr inbounds { double, <2 x float> }, { double, <2 x float> }* %cast.2, i32 0, i32 0 + %ld.3 = load double, double* %field0.1, align 8 + %field1.1 = getelementptr inbounds { double, <2 x float> }, { double, <2 x float> }* %cast.2, i32 0, i32 1 + %ld.4 = load <2 x float>, <2 x float>* %field1.1, align 8 + %call.0 = call addrspace(0) { double, <2 x float> } @foo(i8* nest undef, <2 x float> %ld.1, i48 %ld.2, double %ld.3, <2 x float> %ld.4, i8 zeroext %sub.0, i8 signext %p4.ld.0, { { float, float, i16, i16, i16 }, { double, float, float } }* byval({ { float, float, i16, i16, i16 }, { double, float, float } }) %p5) + %cast.3 = bitcast { double, float, float }* %sret.actual.0 to { double, <2 x float> }* + store { double, <2 x float> } %call.0, { double, <2 x float> }* %cast.3, align 8 + %cast.4 = bitcast { double, float, float }* %sret.actual.0 to { double, <2 x float> }* + %ld.5 = load { double, <2 x float> }, { double, <2 x float> }* %cast.4, align 8 + ret { double, <2 x float> } %ld.5 + )RAW_RESULT"); + + bool isOK = h.expectStmt(rst2, exp); + EXPECT_TRUE(isOK && "Statement does not have expected contents"); + + // if statement + h.mkIf(eq, rst1, rst2); + + bool broken = h.finish(PreserveDebugInfo); + EXPECT_FALSE(broken && "Module failed to verify."); +} + TEST(BackendCABIOracleTests, PassAndReturnArraysAmd64) { FcnTestHarness h(llvm::CallingConv::X86_64_SysV); Llvm_backend *be = h.be(); @@ -776,6 +1085,53 @@ TEST(BackendCABIOracleTests, PassAndReturnArraysArm64) { EXPECT_FALSE(broken && "Module failed to verify."); } +TEST(BackendCABIOracleTests, PassAndReturnArraysRV64) { + FcnTestHarness h(llvm::CallingConv::C); + Llvm_backend *be = h.be(); + + Btype *bf32t = be->float_type(32); + Btype *bf64t = be->float_type(64); + Btype *at2f = be->array_type(bf32t, mkInt64Const(be, int64_t(2))); + Btype *at3d = be->array_type(bf64t, mkInt64Const(be, int64_t(3))); + + // func foo(fp [2]float32) [3]float64 + BFunctionType *befty1 = mkFuncTyp(be, + L_PARM, at2f, + L_RES, at3d, + L_END); + Bfunction *func = h.mkFunction("foo", befty1); + + // foo(fp) + Location loc; + Bvariable *p0 = func->getNthParamVar(0); + Bexpression *vex = be->var_expression(p0, loc); + Bexpression *fn = be->function_code_expression(func, loc); + std::vector args; + args.push_back(vex); + Bexpression *call = be->call_expression(func, fn, args, nullptr, h.loc()); + + // return foo(fp) + std::vector rvals; + rvals.push_back(call); + h.mkReturn(rvals); + + DECLARE_EXPECTED_OUTPUT(exp, R"RAW_RESULT( + %cast.0 = bitcast [2 x float]* %p0.addr to <2 x float>* + %ld.0 = load <2 x float>, <2 x float>* %cast.0, align 8 + call addrspace(0) void @foo([3 x double]* sret([3 x double]) "go_sret" %sret.actual.0, i8* nest undef, <2 x float> %ld.0) + %cast.1 = bitcast [3 x double]* %sret.formal.0 to i8* + %cast.2 = bitcast [3 x double]* %sret.actual.0 to i8* + call addrspace(0) void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %cast.1, i8* align 8 %cast.2, i64 24, i1 false) + ret void + )RAW_RESULT"); + + bool isOK = h.expectBlock(exp); + EXPECT_TRUE(isOK && "Block does not have expected contents"); + + bool broken = h.finish(PreserveDebugInfo); + EXPECT_FALSE(broken && "Module failed to verify."); +} + TEST_P(BackendCABIOracleTests, EmptyStructParamsAndReturns) { auto cc = GetParam(); FcnTestHarness h(cc); @@ -992,4 +1348,79 @@ TEST(BackendCABIOracleTests, PassAndReturnComplexArm64) { EXPECT_FALSE(broken && "Module failed to verify."); } +TEST(BackendCABIOracleTests, PassAndReturnComplexRV64) { + FcnTestHarness h(llvm::CallingConv::C); + Llvm_backend *be = h.be(); + + Btype *bc64t = be->complex_type(64); + Btype *bc128t = be->complex_type(128); + + // func foo(x complex64, y complex128) complex64 + BFunctionType *befty1 = mkFuncTyp(be, + L_PARM, bc64t, + L_PARM, bc128t, + L_RES, bc64t, + L_END); + Bfunction *func = h.mkFunction("foo", befty1); + + // z = foo(x, y) + Location loc; + Bvariable *x = func->getNthParamVar(0); + Bvariable *y = func->getNthParamVar(1); + Bexpression *xvex = be->var_expression(x, loc); + Bexpression *yvex = be->var_expression(y, loc); + Bexpression *fn1 = be->function_code_expression(func, loc); + std::vector args1 = {xvex, yvex}; + Bexpression *call1 = be->call_expression(func, fn1, args1, nullptr, h.loc()); + h.mkLocal("z", bc64t, call1); + + // Call with constant args + // foo(1+2i, 3+4i) + mpc_t mpc_val1, mpc_val2; + mpc_init2(mpc_val1, 256); + mpc_set_d_d(mpc_val1, 1.0, 2.0, GMP_RNDN); + mpc_init2(mpc_val2, 256); + mpc_set_d_d(mpc_val2, 3.0, 4.0, GMP_RNDN); + Bexpression *ccon1 = be->complex_constant_expression(bc64t, mpc_val1); + Bexpression *ccon2 = be->complex_constant_expression(bc128t, mpc_val2); + mpc_clear(mpc_val1); + mpc_clear(mpc_val2); + Bexpression *fn2 = be->function_code_expression(func, loc); + std::vector args2 = {ccon1, ccon2}; + Bexpression *call2 = be->call_expression(func, fn2, args2, nullptr, h.loc()); + + // return the call expr above + std::vector rvals = {call2}; + h.mkReturn(rvals); + + DECLARE_EXPECTED_OUTPUT(exp, R"RAW_RESULT( + %cast.0 = bitcast { float, float }* %p0.addr to <2 x float>* + %ld.0 = load <2 x float>, <2 x float>* %cast.0, align 8 + %field0.0 = getelementptr inbounds { double, double }, { double, double }* %p1.addr, i32 0, i32 0 + %ld.1 = load double, double* %field0.0, align 8 + %field1.0 = getelementptr inbounds { double, double }, { double, double }* %p1.addr, i32 0, i32 1 + %ld.2 = load double, double* %field1.0, align 8 + %call.0 = call addrspace(0) <2 x float> @foo(i8* nest undef, <2 x float> %ld.0, double %ld.1, double %ld.2) + %cast.2 = bitcast { float, float }* %sret.actual.0 to <2 x float>* + store <2 x float> %call.0, <2 x float>* %cast.2, align 8 + %cast.3 = bitcast { float, float }* %z to i8* + %cast.4 = bitcast { float, float }* %sret.actual.0 to i8* + call addrspace(0) void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %cast.3, i8* align 4 %cast.4, i64 8, i1 false) + %ld.3 = load <2 x float>, <2 x float>* bitcast ({ float, float }* @const.0 to <2 x float>*), align 8 + %ld.4 = load double, double* getelementptr inbounds ({ double, double }, { double, double }* @const.1, i32 0, i32 0), align 8 + %ld.5 = load double, double* getelementptr inbounds ({ double, double }, { double, double }* @const.1, i32 0, i32 1), align 8 + %call.1 = call addrspace(0) <2 x float> @foo(i8* nest undef, <2 x float> %ld.3, double %ld.4, double %ld.5) + %cast.7 = bitcast { float, float }* %sret.actual.1 to <2 x float>* + store <2 x float> %call.1, <2 x float>* %cast.7, align 8 + %cast.8 = bitcast { float, float }* %sret.actual.1 to <2 x float>* + %ld.6 = load <2 x float>, <2 x float>* %cast.8, align 8 + ret <2 x float> %ld.6 + )RAW_RESULT"); + + bool isOK = h.expectBlock(exp); + EXPECT_TRUE(isOK && "Block does not have expected contents"); + + bool broken = h.finish(PreserveDebugInfo); + EXPECT_FALSE(broken && "Module failed to verify."); +} } // namespace diff --git a/unittests/BackendCore/TestUtils.cpp b/unittests/BackendCore/TestUtils.cpp index bfca6c1..55062b8 100644 --- a/unittests/BackendCore/TestUtils.cpp +++ b/unittests/BackendCore/TestUtils.cpp @@ -14,12 +14,15 @@ namespace goBackendUnitTests { std::string ccName(llvm::CallingConv::ID cc) { assert(cc == llvm::CallingConv::X86_64_SysV || - cc == llvm::CallingConv::ARM_AAPCS); + cc == llvm::CallingConv::ARM_AAPCS || + cc == llvm::CallingConv::C); switch (cc) { case llvm::CallingConv::X86_64_SysV: return "X8664SysV"; case llvm::CallingConv::ARM_AAPCS: return "ARMAAPCS"; + case llvm::CallingConv::C: + return "C"; default: return ""; } diff --git a/unittests/BackendCore/TestUtils.h b/unittests/BackendCore/TestUtils.h index 366fbf7..f62c934 100644 --- a/unittests/BackendCore/TestUtils.h +++ b/unittests/BackendCore/TestUtils.h @@ -33,7 +33,8 @@ namespace goBackendUnitTests { // All supported calling conventions auto CConvs = testing::Values(llvm::CallingConv::X86_64_SysV, - llvm::CallingConv::ARM_AAPCS); + llvm::CallingConv::ARM_AAPCS, + llvm::CallingConv::C); // Convert llvm::CallingConv::ID to its coresponding string name. std::string ccName(llvm::CallingConv::ID); From 452926868c6d239b0deeb1e3af238d6912bda021 Mon Sep 17 00:00:00 2001 From: melonedo Date: Fri, 2 Sep 2022 21:58:34 +0800 Subject: [PATCH 5/5] gollvm: copy go module declarations The check_xxx_tool tests fail immediately because go.mod is not present in the test directory. This patch copies these files to enable them but relies on the existence of go.sum, is there a better way? Change-Id: Ibb67d5bd687da3ca6e3ee63f4d787c1fc468e6ab --- gotools/CMakeLists.txt | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/gotools/CMakeLists.txt b/gotools/CMakeLists.txt index e8023f4..d891283 100644 --- a/gotools/CMakeLists.txt +++ b/gotools/CMakeLists.txt @@ -168,12 +168,13 @@ add_custom_target( "${cmd_srcroot}/go/internal:src/cmd/go" "${cmd_srcroot}/internal:src/cmd" "${cmd_srcroot}/go/testdata:src/cmd/go" - "${libgo_srcroot}/go/golang.org/x/mod:src/cmd/vendor/golang.org/x" - "${libgo_srcroot}/go/golang.org/x/crypto:src/cmd/vendor/golang.org/x" - "${libgo_srcroot}/go/golang.org/x/xerrors:src/cmd/vendor/golang.org/x" + "${libgo_srcroot}/go/golang.org/x:src/cmd/vendor/golang.org" "COPYFILES" "${libgo_binroot}/zdefaultcc.go:src/cmd/go/internal/cfg/" "${libgo_binroot}/objabi.go:src/cmd/internal/objabi" + "${cmd_srcroot}/go.mod:src/cmd" + "${cmd_srcroot}/go.sum:src/cmd" + "${cmd_srcroot}/vendor/modules.txt:src/cmd/vendor" "TIMEOUT" ${cmdgo_check_timeout} "GOC" "${rungoc}" "BINDIR" ${gotools_binroot} @@ -197,7 +198,11 @@ add_custom_target( "${cmd_srcroot}/vet:src/cmd" "${cmd_srcroot}/internal/objabi:src/cmd/internal" "${libgo_srcroot}/go/golang.org/x/tools:src/cmd/vendor/golang.org/x" - "COPYFILES" "${libgo_binroot}/objabi.go:src/cmd/internal/objabi" + "COPYFILES" + "${libgo_binroot}/objabi.go:src/cmd/internal/objabi" + "${cmd_srcroot}/go.mod:src/cmd" + "${cmd_srcroot}/go.sum:src/cmd" + "${cmd_srcroot}/vendor/modules.txt:src/cmd/vendor" "TIMEOUT" ${default_check_timeout} "GOC" "${rungoc}" "BINDIR" ${gotools_binroot} @@ -216,6 +221,7 @@ add_custom_target( "SUBDIR" "misc/cgo/test" "LOGFILE" "${gotools_binroot}/cmd_cgo-testlog" "COPYDIRS" "${libgo_srcroot}/misc/cgo/test:misc/cgo" + "COPYFILES" "${libgo_srcroot}/misc/go.mod:misc/cgo" "TIMEOUT" ${default_check_timeout} "GOC" "${rungoc}" "SETENV" "GOTRACEBACK=2" @@ -235,6 +241,7 @@ add_custom_target( "SUBDIR" "misc/cgo/testcarchive" "LOGFILE" "${gotools_binroot}/cmd_carchive-testlog" "COPYDIRS" "${libgo_srcroot}/misc/cgo/testcarchive:misc/cgo" + "COPYFILES" "${libgo_srcroot}/misc/go.mod:misc/cgo" "TIMEOUT" ${default_check_timeout} "GOC" "${rungoc}" "CC" "${runcc}"