From 6fb0a28bc8ad8a9d2f064aa090102a4d8545a64b Mon Sep 17 00:00:00 2001 From: Qihan Cai Date: Mon, 4 Jul 2022 03:35:09 +1000 Subject: [PATCH 1/2] 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 folders of crosscompiler by -L, -I in GOLLVM_EXTRA_GOCFLAGS. Example usage: cmake -Wno-dev -G Ninja -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CROSSCOMPILING=True -DLLVM_DEFAULT_TARGET_TRIPLE=riscv64-unknown-linux-gnu -DGOLLVM_USE_SPLIT_STACK=OFF -DLLVM_TARGET_ARCH=RISCV64 -DLLVM_TARGETS_TO_BUILD=RISCV -DCMAKE_C_COMPILER=/opt/riscv/bin/riscv64-unknown-linux-gnu-gcc -DCMAKE_CXX_COMPILER=/opt/riscv/bin/riscv64-unknown-linux-gnu-g++ -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_FLAGS=-latomic -DCMAKE_CXX_FLAGS=-latomic -DCMAKE_INSTALL_PREFIX=/tmp/gollvm-install -DLLVM_USE_LINKER=bfd -DGOLLVM_DEFAULT_LINKER=bfd -DLLVM_TABLEGEN=../build-x86/bin/llvm-tblgen -DCLANG_TABLEGEN=../build-x86/clang-tblgen -DGOLLVM_DRIVER_DIR=../build-x86/bin -DGOLLVM_EXTRA_GOCFLAGS="--target=riscv64-unknown-linux-gnu --gcc-toolchain=/opt/riscv/bin --sysroot=/opt/riscv/sysroot -I /opt/riscv/sysroot/usr/lib64/lp64d -I /opt/riscv/riscv64-unknown-linux-gnu/bin -I /opt/riscv/lib/gcc/riscv64-unknown-linux-gnu/11.1.0 -L/opt/riscv/bin" -G Ninja Change-Id: I557df1ea8e69d4dadaa6c64b7ebc076393d4c530 --- CMakeLists.txt | 21 ++++++++++++++++++--- cmake/modules/AutoGenGo.cmake | 6 +++++- cmake/modules/GoPackage.cmake | 21 +++++++++++++++------ driver/LinuxToolChain.cpp | 6 ++++++ gotools/CMakeLists.txt | 8 ++++++-- libgo/CMakeLists.txt | 16 ++++++++++++---- 6 files changed, 62 insertions(+), 16 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..2d29c64 100644 --- a/cmake/modules/GoPackage.cmake +++ b/cmake/modules/GoPackage.cmake @@ -80,12 +80,21 @@ function(add_go_package pkgpath dest) endif() # Command to build *.gox.tmp - add_custom_command( - OUTPUT "${package_goxtmp}" - COMMAND objcopy -j .go_export "${package_ofile}" "${package_goxtmp}" - DEPENDS ${package_ofile} ${package_picofile} - COMMENT "Building Go exports file for package '${pkgpath}'" - VERBATIM) + if (GOLLVM_DRIVER_DIR) + add_custom_command( + OUTPUT "${package_goxtmp}" + COMMAND ${LLVM_DEFAULT_TARGET_TRIPLE}-objcopy -j .go_export "${package_ofile}" "${package_goxtmp}" + DEPENDS ${package_ofile} ${package_picofile} + COMMENT "Building Go exports file for package '${pkgpath}'" + VERBATIM) + else() + add_custom_command( + OUTPUT "${package_goxtmp}" + COMMAND objcopy -j .go_export "${package_ofile}" "${package_goxtmp}" + DEPENDS ${package_ofile} ${package_picofile} + COMMENT "Building Go exports file for package '${pkgpath}'" + VERBATIM) + endif() # Command to update *.gox if different from *.gox.tmp add_custom_command( diff --git a/driver/LinuxToolChain.cpp b/driver/LinuxToolChain.cpp index 2a2fb10..243ac0f 100644 --- a/driver/LinuxToolChain.cpp +++ b/driver/LinuxToolChain.cpp @@ -59,12 +59,18 @@ Linux::Linux(gollvm::driver::Driver &driver, // Program paths pathlist &ppaths = programPaths(); auto ftrip = gccDetector_.foundTriple().str(); + for (const auto &path : driver.args().getAllArgValues(gollvm::options::OPT_L)) { + ppaths.push_back(path); + } addIfPathExists(ppaths, llvm::Twine(gccDetector_.getParentLibPath() + "/../../" + ftrip + "/bin").str()); // File paths pathlist &fpaths = filePaths(); + for (const auto &path : driver.args().getAllArgValues(gollvm::options::OPT_I)) { + fpaths.push_back(path); + } addIfPathExists(fpaths, gccDetector_.getLibPath()); std::string osLibDir = getOSLibDir(targetTriple).str(); if (!driver.sysRoot().empty()) 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 6209ac8c52147b212ed84343c81ae22563980b05 Mon Sep 17 00:00:00 2001 From: Qihan Cai Date: Mon, 22 Aug 2022 01:43:19 +1000 Subject: [PATCH 2/2] gollvm: Add support for riscv64 platform co-authored with Funan Zeng, Xufan Lu This CL adds linux riscv64 support for Gollvm, with this patch we can build and run Go programs with Gollvm on linux riscv64. The main changes include: 1, RISC-V C ABI implementation. 2, port existing unit test cases on amd64 to risc-v. It should be emphasized that since ld.gold does not support risc-v, we must specify force cmake to use ld.bfd, and add cmake parameter -DGOLLVM_USE_SPLIT_STACK=OFF when building. Change-Id: Iad7779cdd0c3c62611d992d3e2fc8b50a536cc95 --- bridge/go-llvm-cabi-oracle.cpp | 239 +++++++++- bridge/go-llvm-cabi-oracle.h | 14 + bridge/go-llvm.cpp | 5 + cmake/modules/AddGollvm.cmake | 2 +- cmake/modules/GoPackage.cmake | 23 +- cmake/modules/GoVars.cmake | 8 + cmake/modules/LibbacktraceUtils.cmake | 7 + cmake/modules/LibffiUtils.cmake | 10 +- driver/ArchCpusAttrs.h | 141 +++--- driver/CompileGo.cpp | 46 +- driver/CompileGo.h | 3 + driver/Driver.cpp | 7 +- driver/GccUtils.cpp | 10 + driver/GnuTools.cpp | 3 + driver/IntegAssembler.cpp | 15 +- driver/LinuxToolChain.cpp | 4 + gotools/CMakeLists.txt | 15 +- libgo/CMakeLists.txt | 12 +- tools/capture-fcn-attributes.go | 1 + .../BackendCore/BackendCABIOracleTests.cpp | 431 ++++++++++++++++++ unittests/BackendCore/TestUtils.cpp | 5 +- unittests/BackendCore/TestUtils.h | 3 +- 22 files changed, 898 insertions(+), 106 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/cmake/modules/AddGollvm.cmake b/cmake/modules/AddGollvm.cmake index d8ca938..5540faf 100644 --- a/cmake/modules/AddGollvm.cmake +++ b/cmake/modules/AddGollvm.cmake @@ -65,7 +65,7 @@ if(GOLLVM_USE_SPLIT_STACK) set(C_SUPPORTS_SPLIT_STACK 1) endif() if(NOT C_SUPPORTS_SPLIT_STACK) - message(SEND_ERROR "C compiler does not support -fsplit-stack") +# message(SEND_ERROR "C compiler does not support -fsplit-stack") else() set(USING_SPLIT_STACK 1) endif() diff --git a/cmake/modules/GoPackage.cmake b/cmake/modules/GoPackage.cmake index 2d29c64..018b809 100644 --- a/cmake/modules/GoPackage.cmake +++ b/cmake/modules/GoPackage.cmake @@ -81,19 +81,18 @@ function(add_go_package pkgpath dest) # Command to build *.gox.tmp if (GOLLVM_DRIVER_DIR) - add_custom_command( - OUTPUT "${package_goxtmp}" - COMMAND ${LLVM_DEFAULT_TARGET_TRIPLE}-objcopy -j .go_export "${package_ofile}" "${package_goxtmp}" - DEPENDS ${package_ofile} ${package_picofile} - COMMENT "Building Go exports file for package '${pkgpath}'" - VERBATIM) + get_filename_component(c_compiler_dir ${CMAKE_C_COMPILER} DIRECTORY) + set(gollvm_objcopy ${c_compiler_dir}/${LLVM_DEFAULT_TARGET_TRIPLE}-objcopy) else() - add_custom_command( - OUTPUT "${package_goxtmp}" - COMMAND objcopy -j .go_export "${package_ofile}" "${package_goxtmp}" - DEPENDS ${package_ofile} ${package_picofile} - COMMENT "Building Go exports file for package '${pkgpath}'" - VERBATIM) + set(gollvm_objcopy objcopy) + endif() + add_custom_command( + OUTPUT "${package_goxtmp}" + COMMAND objcopy -j .go_export "${package_ofile}" "${package_goxtmp}" + COMMAND ${gollvm_objcopy} -j .go_export "${package_ofile}" "${package_goxtmp}" + DEPENDS ${package_ofile} ${package_picofile} + COMMENT "Building Go exports file for package '${pkgpath}'" + VERBATIM) endif() # Command to update *.gox if different from *.gox.tmp 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/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 6affe49..88e1612 100644 --- a/driver/CompileGo.cpp +++ b/driver/CompileGo.cpp @@ -411,6 +411,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); @@ -466,8 +469,25 @@ 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 (!setupArch(cpuarg, targetCpuAttr_, targetFeaturesAttr_, triple_, progname_)) + return false; + + // Create target machine + Optional CM = None; + target_.reset( + TheTarget->createTargetMachine(triple_.getTriple(), + targetCpuAttr_, targetFeaturesAttr_, + Options, driver_.reconcileRelocModel(), + CM, cgolvl_)); + assert(target_.get() && "Could not allocate target machine!"); + + return true; +} + +bool setupArch(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") @@ -507,18 +527,8 @@ bool CompileGoImpl::setup(const Action &jobAction) return false; } } - targetCpuAttr_ = cpuAttrs->cpu; - targetFeaturesAttr_ = cpuAttrs->attrs; - - // Create target machine - Optional CM = None; - target_.reset( - TheTarget->createTargetMachine(triple_.getTriple(), - targetCpuAttr_, targetFeaturesAttr_, - Options, driver_.reconcileRelocModel(), - CM, cgolvl_)); - assert(target_.get() && "Could not allocate target machine!"); - + cpu = cpuAttrs->cpu; + attrs = cpuAttrs->attrs; return true; } @@ -767,6 +777,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"; @@ -895,9 +908,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/CompileGo.h b/driver/CompileGo.h index c33b8df..62551b1 100644 --- a/driver/CompileGo.h +++ b/driver/CompileGo.h @@ -43,6 +43,9 @@ class CompileGo : public InternalTool { std::unique_ptr impl_; }; +bool setupArch(llvm::opt::Arg *cpuarg, std::string &cpu, std::string &attrs, + llvm::Triple triple_, const char *progname_); + } // end namespace driver } // end namespace gollvm diff --git a/driver/Driver.cpp b/driver/Driver.cpp index 8debbab..c8a7db5 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 @@ -417,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 39d080f..ee6bf65 100644 --- a/driver/IntegAssembler.cpp +++ b/driver/IntegAssembler.cpp @@ -20,6 +20,7 @@ #include "GollvmOptions.h" #include "GollvmConfig.h" #include "GollvmPasses.h" +#include "CompileGo.h" #include "Action.h" #include "Artifact.h" @@ -178,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!"); @@ -185,16 +188,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 +201,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); + setupArch(cpuarg, CPU, FS, triple_, progname_); std::unique_ptr Str; std::unique_ptr MCII(TheTarget->createMCInstrInfo()); std::unique_ptr STI( diff --git a/driver/LinuxToolChain.cpp b/driver/LinuxToolChain.cpp index 243ac0f..6df7864 100644 --- a/driver/LinuxToolChain.cpp +++ b/driver/LinuxToolChain.cpp @@ -141,6 +141,10 @@ 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; } return "/" + LibDir + "/" + Loader; } 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}" 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() 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);