diff --git a/CMakeLists.txt b/CMakeLists.txt index a009a11a5a..3bbf15a606 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -72,6 +72,27 @@ set(CMAKE_C_VISIBILITY_PRESET hidden) set(CMAKE_CXX_VISIBILITY_PRESET hidden) set(CMAKE_VISIBILITY_INLINES_HIDDEN YES) +if(CMAKE_SYSTEM_PROCESSOR STREQUAL x86_64) + # Setup options for x86_64 micro-architecture levels. + # https://clang.llvm.org/docs/UsersManual.html#x86 + + set(EVMONE_X86_64_ARCH_LEVEL_INIT 2) + if(APPLE) + # On macos with Apple Silicon CPU (arm64) the x86 is emulated and SSE4.2 is not available. + set(EVMONE_X86_64_ARCH_LEVEL_INIT 1) + endif() + + set(EVMONE_X86_64_ARCH_LEVEL ${EVMONE_X86_64_ARCH_LEVEL_INIT} CACHE STRING "The x86_64 micro-architecture level") + if(EVMONE_X86_64_ARCH_LEVEL GREATER_EQUAL 1 AND EVMONE_X86_64_ARCH_LEVEL LESS_EQUAL 4) + message(STATUS "x86_64 micro-architecture level: ${EVMONE_X86_64_ARCH_LEVEL}") + if(EVMONE_X86_64_ARCH_LEVEL GREATER_EQUAL 2) + add_compile_options(-march=x86-64-v${EVMONE_X86_64_ARCH_LEVEL}) + endif() + else() + message(FATAL_ERROR "Invalid EVMONE_X86_64_ARCH_LEVEL: ${EVMONE_X86_64_ARCH_LEVEL}") + endif() +endif() + include(GNUInstallDirs) if(EVMONE_FUZZING) @@ -89,7 +110,6 @@ if(EVMONE_FUZZING) # The coverage builds should be without fuzzing instrumentation to allow # running fuzzing corpus once and getting code coverage. set(fuzzing_flags -fsanitize=fuzzer-no-link,address,undefined,shift-exponent,implicit-conversion,nullability) -# set(fuzzing_flags -fsanitize=fuzzer-no-link) add_compile_options(${fuzzing_flags}) set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${fuzzing_flags}") endif() diff --git a/circle.yml b/circle.yml index 8d7f7ee3b6..30b92be9de 100644 --- a/circle.yml +++ b/circle.yml @@ -586,14 +586,21 @@ jobs: executor: linux-gcc-latest environment: BUILD_TYPE: Release - CMAKE_OPTIONS: -DCMAKE_CROSSCOMPILING_EMULATOR=qemu-x86_64-static QEMU_CPU: core2duo # The lowest 64-bit CPU I could find, but qemu64 should be good too. steps: - run: name: "Install qemu" command: sudo apt update -y && sudo apt install -y qemu-user-static - build - - test + - run: + name: "Check evmone.so" + working_directory: ~/build + command: (! qemu-x86_64-static bin/evmc run --vm ./lib/libevmone.so,trace 6000 2>&1) | grep "CPU does not support" + - run: + name: "Check unittests" + working_directory: ~/build + command: (! qemu-x86_64-static bin/evmone-unittests 2>&1) | grep "CPU does not support" + workflows: diff --git a/lib/evmone/CMakeLists.txt b/lib/evmone/CMakeLists.txt index bffddd35b9..28c403f220 100644 --- a/lib/evmone/CMakeLists.txt +++ b/lib/evmone/CMakeLists.txt @@ -19,7 +19,7 @@ add_library(evmone baseline_instruction_table.cpp baseline_instruction_table.hpp eof.cpp - eof.hpp + eof.hpp instructions.hpp instructions_calls.cpp instructions_opcodes.hpp @@ -37,6 +37,13 @@ target_link_libraries(evmone PUBLIC evmc::evmc intx::intx PRIVATE ethash::keccak target_include_directories(evmone PUBLIC $$ ) + +if(EVMONE_X86_64_ARCH_LEVEL GREATER_EQUAL 2) + # Add CPU architecture runtime check. The EVMONE_X86_64_ARCH_LEVEL has a valid value. + target_sources(evmone PRIVATE cpu_check.cpp) + set_source_files_properties(cpu_check.cpp PROPERTIES COMPILE_DEFINITIONS EVMONE_X86_64_ARCH_LEVEL=${EVMONE_X86_64_ARCH_LEVEL}) +endif() + if(CABLE_COMPILER_GNULIKE) target_compile_options( evmone PRIVATE diff --git a/lib/evmone/cpu_check.cpp b/lib/evmone/cpu_check.cpp new file mode 100644 index 0000000000..8e60630f69 --- /dev/null +++ b/lib/evmone/cpu_check.cpp @@ -0,0 +1,29 @@ + +#define STRINGIFY_HELPER(X) #X +#define STRINGIFY(X) STRINGIFY_HELPER(X) + +#if defined(__GNUC__) && __GNUC__ >= 12 +#define CPU_FEATURE "x86-64-v" STRINGIFY(EVMONE_X86_64_ARCH_LEVEL) +#else +// Clang 16 and GCC 11 does not support architecture levels in __builtin_cpu_supports(). +// Use approximations. +#if EVMONE_X86_64_ARCH_LEVEL == 2 +#define CPU_FEATURE "sse4.2" +#endif +#endif + +#ifndef CPU_FEATURE +#error "EVMONE_X86_64_ARCH_LEVEL: Unsupported x86-64 architecture level" +#endif + +#include +#include + +static bool cpu_check = []() noexcept { + if (!__builtin_cpu_supports(CPU_FEATURE)) + { + (void)std::fputs("CPU does not support " CPU_FEATURE "\n", stderr); + std::abort(); + } + return false; +}();