Added MSVC support for Argon2.

This commit is contained in:
XMRig 2019-08-17 04:01:53 +07:00
parent 3022f19eda
commit fe832f510e
13 changed files with 132 additions and 87 deletions

View file

@ -40,7 +40,23 @@ set_property(TARGET argon2 APPEND PROPERTY
)
if (CMAKE_C_COMPILER_ID MATCHES MSVC)
function(add_feature_impl FEATURE MSVC_FLAG DEF)
add_library(argon2-${FEATURE} STATIC arch/x86_64/lib/argon2-${FEATURE}.c)
target_link_libraries(argon2-${FEATURE} PRIVATE argon2-internal)
set_target_properties(argon2-${FEATURE} PROPERTIES POSITION_INDEPENDENT_CODE True)
target_compile_options(argon2-${FEATURE} PRIVATE ${MSVC_FLAG})
target_compile_definitions(argon2-${FEATURE} PRIVATE ${DEF})
target_link_libraries(argon2 PUBLIC argon2-${FEATURE})
endfunction()
add_feature_impl(sse2 "" HAVE_SSE2)
add_feature_impl(ssse3 ""/arch:SSSE3"" HAVE_SSSE3)
add_feature_impl(xop "" HAVE_XOP)
add_feature_impl(avx2 "/arch:AVX2" HAVE_AVX2)
add_feature_impl(avx512f "/arch:AVX512F" HAVE_AVX512F)
target_sources(argon2 PRIVATE arch/x86_64/lib/argon2-arch.c arch/x86_64/lib/cpu-flags.c)
elseif (NOT XMRIG_ARM AND CMAKE_SIZEOF_VOID_P EQUAL 8)
function(add_feature_impl FEATURE GCC_FLAG DEF)
add_library(argon2-${FEATURE} STATIC arch/x86_64/lib/argon2-${FEATURE}.c)
@ -81,12 +97,7 @@ elseif (NOT XMRIG_ARM AND CMAKE_SIZEOF_VOID_P EQUAL 8)
add_feature_impl(avx2 -mavx2 HAVE_AVX2)
add_feature_impl(avx512f -mavx512f HAVE_AVX512F)
target_sources(argon2 PRIVATE
arch/x86_64/lib/argon2-arch.c
arch/x86_64/lib/cpu-flags.c
)
target_sources(argon2 PRIVATE arch/x86_64/lib/argon2-arch.c arch/x86_64/lib/cpu-flags.c)
else()
target_sources(argon2 PRIVATE
arch/generic/lib/argon2-arch.c
)
target_sources(argon2 PRIVATE arch/generic/lib/argon2-arch.c)
endif()

View file

@ -3,7 +3,11 @@
#ifdef HAVE_AVX2
#include <string.h>
#include <x86intrin.h>
#ifdef __GNUC__
# include <x86intrin.h>
#else
# include <intrin.h>
#endif
#include "cpu-flags.h"

View file

@ -4,7 +4,11 @@
#include <stdint.h>
#include <string.h>
#include <x86intrin.h>
#ifdef __GNUC__
# include <x86intrin.h>
#else
# include <intrin.h>
#endif
#include "cpu-flags.h"

View file

@ -1,7 +1,11 @@
#include "argon2-sse2.h"
#ifdef HAVE_SSE2
#include <x86intrin.h>
#ifdef __GNUC__
# include <x86intrin.h>
#else
# include <intrin.h>
#endif
#include "cpu-flags.h"

View file

@ -3,7 +3,11 @@
#ifdef HAVE_SSSE3
#include <string.h>
#include <x86intrin.h>
#ifdef __GNUC__
# include <x86intrin.h>
#else
# include <intrin.h>
#endif
#include "cpu-flags.h"

View file

@ -1,6 +1,10 @@
#include <string.h>
#include <x86intrin.h>
#ifdef __GNUC__
# include <x86intrin.h>
#else
# include <intrin.h>
#endif
#include "core.h"

View file

@ -3,7 +3,11 @@
#ifdef HAVE_XOP
#include <string.h>
#include <x86intrin.h>
#ifdef __GNUC__
# include <x86intrin.h>
#else
# include <intrin.h>
#endif
#include "cpu-flags.h"

View file

@ -1,6 +1,49 @@
#include <stdbool.h>
#include <stdint.h>
#include "cpu-flags.h"
#include <cpuid.h>
#include <stdio.h>
#ifdef _MSC_VER
# include <intrin.h>
#else
# include <cpuid.h>
#endif
#ifndef bit_OSXSAVE
# define bit_OSXSAVE (1 << 27)
#endif
#ifndef bit_SSE2
# define bit_SSE2 (1 << 26)
#endif
#ifndef bit_SSSE3
# define bit_SSSE3 (1 << 9)
#endif
#ifndef bit_AVX2
# define bit_AVX2 (1 << 5)
#endif
#ifndef bit_AVX512F
# define bit_AVX512F (1 << 16)
#endif
#ifndef bit_XOP
# define bit_XOP (1 << 11)
#endif
#define PROCESSOR_INFO (1)
#define EXTENDED_FEATURES (7)
#define EAX_Reg (0)
#define EBX_Reg (1)
#define ECX_Reg (2)
#define EDX_Reg (3)
enum {
X86_64_FEATURE_SSE2 = (1 << 0),
@ -12,56 +55,51 @@ enum {
static unsigned int cpu_flags;
static unsigned int get_cpuid(int ext, unsigned int level, unsigned int *ebx,
unsigned int *ecx, unsigned int *edx)
static inline void cpuid(uint32_t level, int32_t output[4])
{
unsigned int eax;
__cpuid(ext ? (0x80000000 | level) : level,
eax, *ebx, *ecx, *edx);
return eax;
# ifdef _MSC_VER
__cpuid(output, (int) level);
# else
__cpuid_count(level, 0, output[0], output[1], output[2], output[3]);
# endif
}
static unsigned int get_cpuid_count(int ext, unsigned int level,
unsigned int count, unsigned int *ebx,
unsigned int *ecx, unsigned int *edx)
static bool has_feature(uint32_t level, uint32_t reg, int32_t bit)
{
unsigned int eax;
__cpuid_count(ext ? (0x80000000 | level) : level,
count, eax, *ebx, *ecx, *edx);
return 1;
int32_t cpu_info[4] = { 0 };
cpuid(level, cpu_info);
return (cpu_info[reg] & bit) != 0;
}
void cpu_flags_get(void)
{
unsigned int ebx, ecx, edx;
unsigned int level, level_ext;
if (has_feature(PROCESSOR_INFO, EDX_Reg, bit_SSE2)) {
cpu_flags |= X86_64_FEATURE_SSE2;
}
cpu_flags = 0;
level = get_cpuid(0, 0, &ebx, &ecx, &edx);
level_ext = get_cpuid(1, 0, &ebx, &ecx, &edx);
if (has_feature(PROCESSOR_INFO, ECX_Reg, bit_SSSE3)) {
cpu_flags |= X86_64_FEATURE_SSSE3;
}
if (level >= 1 && get_cpuid(0, 1, &ebx, &ecx, &edx)) {
if (edx & (1 << 26)) {
cpu_flags |= X86_64_FEATURE_SSE2;
}
if (ecx & (1 << 9)) {
cpu_flags |= X86_64_FEATURE_SSSE3;
}
if (!has_feature(PROCESSOR_INFO, ECX_Reg, bit_OSXSAVE)) {
return;
}
if (level >= 7 && get_cpuid_count(0, 7, 0, &ebx, &ecx, &edx)) {
if (ebx & (1 << 5)) {
cpu_flags |= X86_64_FEATURE_AVX2;
}
if (ebx & (1 << 16)) {
cpu_flags |= X86_64_FEATURE_AVX512F;
}
if (has_feature(EXTENDED_FEATURES, EBX_Reg, bit_AVX2)) {
cpu_flags |= X86_64_FEATURE_AVX2;
}
if (level_ext >= 1 && get_cpuid(1, 1, &ebx, &ecx, &edx)) {
if (ecx & (1 << 11)) {
cpu_flags |= X86_64_FEATURE_XOP;
}
if (has_feature(EXTENDED_FEATURES, EBX_Reg, bit_AVX512F)) {
cpu_flags |= X86_64_FEATURE_AVX512F;
}
if (has_feature(0x80000001, ECX_Reg, bit_XOP)) {
cpu_flags |= X86_64_FEATURE_XOP;
}
/* FIXME: check also OS support! */
}
int cpu_flags_have_sse2(void)

View file

@ -430,7 +430,7 @@ ARGON2_PUBLIC size_t argon2_encodedlen(uint32_t t_cost, uint32_t m_cost,
* @param prefix What to print before each line; NULL is equivalent to empty
* string
*/
ARGON2_PUBLIC void argon2_select_impl(FILE *out, const char *prefix);
ARGON2_PUBLIC void argon2_select_impl();
ARGON2_PUBLIC const char *argon2_get_impl_name();
ARGON2_PUBLIC int argon2_select_impl_by_name(const char *name);

View file

@ -5,14 +5,7 @@
#include "argon2.h"
#define log_maybe(file, ...) \
do { \
if (file) { \
fprintf(file, __VA_ARGS__); \
} \
} while((void)0, 0)
#define BENCH_SAMPLES 512
#define BENCH_SAMPLES 1024
#define BENCH_MEM_BLOCKS 512
static argon2_impl selected_argon_impl = {
@ -60,32 +53,24 @@ static uint64_t benchmark_impl(const argon2_impl *impl) {
return bench;
}
static void select_impl(FILE *out, const char *prefix)
void argon2_select_impl()
{
argon2_impl_list impls;
unsigned int i;
const argon2_impl *best_impl = NULL;
uint64_t best_bench = UINT_MAX;
log_maybe(out, "%sSelecting best fill_segment implementation...\n", prefix);
argon2_get_impl_list(&impls);
for (i = 0; i < impls.count; i++) {
const argon2_impl *impl = &impls.entries[i];
uint64_t bench;
log_maybe(out, "%s%s: Checking availability... ", prefix, impl->name);
if (impl->check != NULL && !impl->check()) {
log_maybe(out, "FAILED!\n");
continue;
}
log_maybe(out, "OK!\n");
log_maybe(out, "%s%s: Benchmarking...\n", prefix, impl->name);
bench = benchmark_impl(impl);
log_maybe(out, "%s%s: Benchmark result: %llu\n", prefix, impl->name,
(unsigned long long)bench);
if (bench < best_bench) {
best_bench = bench;
@ -94,15 +79,7 @@ static void select_impl(FILE *out, const char *prefix)
}
if (best_impl != NULL) {
log_maybe(out,
"%sBest implementation: '%s' (bench %llu)\n", prefix,
best_impl->name, (unsigned long long)best_bench);
selected_argon_impl = *best_impl;
} else {
log_maybe(out,
"%sNo optimized implementation available, using default!\n",
prefix);
}
}
@ -111,14 +88,6 @@ void fill_segment(const argon2_instance_t *instance, argon2_position_t position)
selected_argon_impl.fill_segment(instance, position);
}
void argon2_select_impl(FILE *out, const char *prefix)
{
if (prefix == NULL) {
prefix = "";
}
select_impl(out, prefix);
}
const char *argon2_get_impl_name()
{
return selected_argon_impl.name;

View file

@ -333,6 +333,10 @@ rapidjson::Value xmrig::CpuBackend::toJSON(rapidjson::Document &doc) const
out.AddMember("asm", false, allocator);
# endif
# ifdef XMRIG_ALGO_ARGON2
out.AddMember("argon2-impl", argon2::Impl::name().toJSON(), allocator);
# endif
const auto pages = hugePages();
rapidjson::Value hugepages(rapidjson::kArrayType);

View file

@ -52,7 +52,6 @@
#define VENDOR_ID (0)
#define PROCESSOR_INFO (1)
#define CACHE_TLB_DESCRIPTOR (2)
#define EXTENDED_FEATURES (7)
#define PROCESSOR_BRAND_STRING_1 (0x80000002)
#define PROCESSOR_BRAND_STRING_2 (0x80000003)

View file

@ -43,7 +43,7 @@ bool xmrig::argon2::Impl::select(const String &nameHint)
{
if (!selected) {
if (nameHint.isEmpty() || argon2_select_impl_by_name(nameHint) == 0) {
argon2_select_impl(nullptr, nullptr);
argon2_select_impl();
}
selected = true;