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 1ba6551..f2278a7 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/bridge/go-llvm-cabi-oracle.cpp b/bridge/go-llvm-cabi-oracle.cpp
index 7ba851f..7eb9925 100644
--- a/bridge/go-llvm-cabi-oracle.cpp
+++ b/bridge/go-llvm-cabi-oracle.cpp
@@ -141,6 +141,7 @@ class EightByteInfo {
void incorporateScalar(Btype *bt);
void determineABITypesForARM_AAPCS();
void determineABITypesForX86_64_SysV();
+ void determineABITypesForRISC_V();
TypeManager *tm() const { return typeManager_; }
};
@@ -160,6 +161,9 @@ EightByteInfo::EightByteInfo(Btype *bt, TypeManager *tmgr)
determineABITypesForARM_AAPCS();
}
break;
+ case gollvm::driver::CallingConvId::RISCV64_C:
+ determineABITypesForRISC_V();
+ break;
default:
llvm::errs() << "unsupported gollvm::driver::CallingConvId " << static_cast(cconv) << "\n";
break;
@@ -491,6 +495,79 @@ 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
@@ -556,6 +633,10 @@ class ABIState {
availIntRegs_ = 8;
availSIMDFPRegs_ = 8;
break;
+ case gollvm::driver::CallingConvId::RISCV64_C:
+ availIntRegs_ = 8;
+ availFloatRegs_ = 8;
+ break;
default:
llvm::errs() << "unsupported gollvm::driver::CallingConvId " << static_cast(cconv) << "\n";
break;
@@ -578,6 +659,11 @@ class ABIState {
availSIMDFPRegs_ = t;
argCount_ += 1;
}
+ void addDirectFloatArg() {
+ if (availFloatRegs_)
+ availFloatRegs_ -= 1;
+ argCount_ += 1;
+ }
void addIndirectArg() { argCount_ += 1; }
void addIndirectReturn() {
if (availIntRegs_)
@@ -591,6 +677,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; }
@@ -598,6 +685,7 @@ class ABIState {
unsigned availIntRegs_;
unsigned availSSERegs_;
unsigned availSIMDFPRegs_;
+ unsigned availFloatRegs_;
unsigned argCount_;
};
@@ -652,6 +740,10 @@ void CABIOracle::setCC()
case gollvm::driver::CallingConvId::ARM_AAPCS:
cc_ = std::unique_ptr(new CABIOracleARM_AAPCS(typeManager_));
break;
+ case gollvm::driver::CallingConvId::RISCV64_C:
+ cc_ = std::unique_ptr(
+ new CABIOracleRISC_V(typeManager_));
+ break;
default:
llvm::errs() << "unsupported gollvm::driver::CallingConvId " << static_cast(ccID_) << "\n";
break;
@@ -1158,3 +1250,142 @@ 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);
+}
diff --git a/bridge/go-llvm-cabi-oracle.h b/bridge/go-llvm-cabi-oracle.h
index 86b79f5..67097a1 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/cmake/modules/AutoGenGo.cmake b/cmake/modules/AutoGenGo.cmake
index a0a3af6..22f2376 100644
--- a/cmake/modules/AutoGenGo.cmake
+++ b/cmake/modules/AutoGenGo.cmake
@@ -375,11 +375,8 @@ function(mkzdefaultcc package outfile ccpath cxxpath)
CMAKE_PARSE_ARGUMENTS(ARG "EXPORT" "" "" ${ARGN})
# Construct default driver path
- if (GOLLVM_DRIVER_DIR)
- set(driverpath "${GOLLVM_DRIVER_DIR}/bin/llvm-goc")
- else()
- set(driverpath "${GOLLVM_INSTALL_DIR}/bin/llvm-goc")
- endif()
+ set(driverpath "${GOLLVM_INSTALL_DIR}/bin/llvm-goc")
+
file(REMOVE ${outfile})
file(WRITE ${outfile} "package ${package}\n\n")
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 3312a7a..48301da 100644
--- a/driver/CompileGo.cpp
+++ b/driver/CompileGo.cpp
@@ -413,6 +413,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);
@@ -860,9 +863,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 a12b794..2c304ca 100644
--- a/driver/LinuxToolChain.cpp
+++ b/driver/LinuxToolChain.cpp
@@ -145,6 +145,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;
}
if (auto *Arg = args.getLastArg(gollvm::options::OPT_sysroot_EQ)) {
std::string Sysroot = Arg->getValue();
diff --git a/libgo/CMakeLists.txt b/libgo/CMakeLists.txt
index 6fcdff6..8585c90 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()
@@ -510,7 +513,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()
@@ -530,6 +533,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)
@@ -538,6 +542,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
@@ -545,6 +553,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 3f3c902..aaa9589 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 { { float, float } } sigOffset: 3 "
+ "Param 5: Direct { i64 } sigOffset: 4 ",
+ "{ double, double } (i8*, double, double, { float, 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(gollvm::driver::CallingConvId::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 { { float, float }, i48 }*
+ %field0.0 = getelementptr inbounds { { float, float }, i48 }, { { float, float }, i48 }* %cast.1, i32 0, i32 0
+ %ld.1 = load { float, float }, { float, float }* %field0.0, align 4
+ %field1.0 = getelementptr inbounds { { float, float }, i48 }, { { float, 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, { float, float } }*
+ %field0.1 = getelementptr inbounds { double, { float, float } }, { double, { float, float } }* %cast.2, i32 0, i32 0
+ %ld.3 = load double, double* %field0.1, align 8
+ %field1.1 = getelementptr inbounds { double, { float, float } }, { double, { float, float } }* %cast.2, i32 0, i32 1
+ %ld.4 = load { float, float }, { float, float }* %field1.1, align 4
+ %call.0 = call addrspace(0) { double, { float, float } } @foo(i8* nest undef, { float, float } %ld.1, i48 %ld.2, double %ld.3, { float, 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, { float, float } }*
+ store { double, { float, float } } %call.0, { double, { float, float } }* %cast.3, align 8
+ %cast.4 = bitcast { double, float, float }* %sret.actual.0 to { double, { float, float } }*
+ %ld.5 = load { double, { float, float } }, { double, { float, float } }* %cast.4, align 8
+ ret { double, { float, 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(gollvm::driver::CallingConvId::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 { float, float }*
+ %ld.0 = load { float, float }, { float, float }* %cast.0, align 4
+ call addrspace(0) void @foo([3 x double]* sret([3 x double]) "go_sret" %sret.actual.0, i8* nest undef, { float, 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,75 @@ 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(
+ %ld.0 = load { float, float }, { float, float }* %p0.addr, align 4
+ %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) { float, float } @foo(i8* nest undef, { float, float } %ld.0, double %ld.1, double %ld.2)
+ store { float, float } %call.0, { float, float }* %sret.actual.0, align 4
+ %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 { float, float }, { float, float }* @const.0, align 4
+ %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) { float, float } @foo(i8* nest undef, { float, float } %ld.3, double %ld.4, double %ld.5)
+ store { float, float } %call.1, { float, float }* %sret.actual.1, align 4
+ %ld.6 = load { float, float }, { float, float }* %sret.actual.1, align 4
+ ret { float, 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