diff --git a/Makefile b/Makefile index 5b4575a..f1a02be 100644 --- a/Makefile +++ b/Makefile @@ -41,7 +41,8 @@ endif OBJS_COMMON = $(BUILD_DIR)/ir.o $(BUILD_DIR)/ir_strtab.o $(BUILD_DIR)/ir_cfg.o \ $(BUILD_DIR)/ir_sccp.o $(BUILD_DIR)/ir_gcm.o $(BUILD_DIR)/ir_ra.o $(BUILD_DIR)/ir_emit.o \ $(BUILD_DIR)/ir_load.o $(BUILD_DIR)/ir_save.o $(BUILD_DIR)/ir_emit_c.o $(BUILD_DIR)/ir_dump.o \ - $(BUILD_DIR)/ir_disasm.o $(BUILD_DIR)/ir_gdb.o $(BUILD_DIR)/ir_perf.o $(BUILD_DIR)/ir_check.o + $(BUILD_DIR)/ir_disasm.o $(BUILD_DIR)/ir_gdb.o $(BUILD_DIR)/ir_perf.o $(BUILD_DIR)/ir_check.o \ + $(BUILD_DIR)/ir_cpuinfo.o OBJS_IR = $(BUILD_DIR)/ir_main.o OBJS_IR_TEST = $(BUILD_DIR)/ir_test.o diff --git a/ir.h b/ir.h index 8c5d735..c9eff7e 100644 --- a/ir.h +++ b/ir.h @@ -768,6 +768,8 @@ int ir_mem_protect(void *ptr, size_t size); int ir_mem_unprotect(void *ptr, size_t size); int ir_mem_flush(void *ptr, size_t size); +uint32_t ir_cpuinfo(void); + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/ir_cpuinfo.c b/ir_cpuinfo.c new file mode 100644 index 0000000..64a9bc6 --- /dev/null +++ b/ir_cpuinfo.c @@ -0,0 +1,61 @@ +/* + * IR - Lightweight JIT Compilation Framework + * (CPU framework for x86) + * Copyright (C) 2023 by IR project. + * Authors: Anatol Belski + */ + +#include "ir.h" + +#if defined(IR_TARGET_X86) || defined(IR_TARGET_X64) + +#include "ir_x86.h" + +#ifndef _WIN32 +IR_ALWAYS_INLINE void ir_cpuid_ex(uint32_t info[4], uint32_t function, uint32_t index) +{ + asm volatile("cpuid" + : "=a" (info[0]), + "=b" (info[1]), + "=c" (info[2]), + "=d" (info[3]) + : "0" (function), "2" (index) + : "memory"); +} +IR_ALWAYS_INLINE void ir_cpuid(uint32_t info[4], uint32_t function) +{ + ir_cpuid_ex(info, function, 0); +} +#else +#define ir_cpuid_ex __cpuidex +#define ir_cpuid __cpuid +#endif + +/* Intel SDM Vol. 2A */ +uint32_t ir_cpuinfo(void) +{ + uint32_t ret = 0; + uint32_t info_0x1[4] = {0}, info_0x7_0[4] = {0}; +#define bit(mask, pos) (((mask) >> (pos)) & 1U) + + ir_cpuid(info_0x1, 0x1); + if (bit(info_0x1[3], 26U)) ret |= IR_X86_SSE2; + if (bit(info_0x1[2], 0U)) ret |= IR_X86_SSE3; + if (bit(info_0x1[2], 9U)) ret |= IR_X86_SSSE3; + if (bit(info_0x1[2], 19U)) ret |= IR_X86_SSE41; + if (bit(info_0x1[2], 20U)) ret |= IR_X86_SSE42; + if (bit(info_0x1[2], 28U)) ret |= IR_X86_AVX; + + ir_cpuid_ex(info_0x7_0, 0x7, 0); + if (bit(info_0x7_0[1], 5U)) ret |= IR_X86_AVX2; + +#undef bit + + return ret; +} +#else +uint32_t ir_cpuinfo(void) +{ + return 0; +} +#endif /* IR_TARGET_X86 || IR_TARGET_X64 */ diff --git a/ir_test.c b/ir_test.c index b0a1f1e..ae88476 100644 --- a/ir_test.c +++ b/ir_test.c @@ -7,6 +7,9 @@ #include "ir.h" #include "ir_builder.h" +#if defined(IR_TARGET_X86) || defined(IR_TARGET_X64) +# include "ir_x86.h" +#endif #include #include #ifndef _WIN32 @@ -94,6 +97,9 @@ int main(int argc, char **argv) int opt_level = 2; uint32_t mflags = 0; uint64_t debug_regset = 0xffffffffffffffff; +#if defined(IR_TARGET_X86) || defined(IR_TARGET_X64) + uint32_t cpuinfo = ir_cpuinfo(); +#endif ir_consistency_check(); @@ -109,6 +115,12 @@ int main(int argc, char **argv) /* pass */ } } else if (strcmp(argv[i], "-mavx") == 0) { +#if defined(IR_TARGET_X86) || defined(IR_TARGET_X64) + if (!(cpuinfo & IR_X86_AVX)) { + fprintf(stderr, "ERROR: CPU doesn't support AVX instruction set)\n"); + return 1; + } +#endif mflags |= IR_AVX; } else if (strcmp(argv[i], "-muse-fp") == 0) { mflags |= IR_USE_FRAME_POINTER; diff --git a/ir_x86.h b/ir_x86.h index e88d311..42bb78a 100644 --- a/ir_x86.h +++ b/ir_x86.h @@ -221,4 +221,12 @@ struct _ir_target_constraints { int8_t hints[IR_MAX_REG_ARGS + 3]; }; +#define IR_X86_SSE2 (1<<0) +#define IR_X86_SSE3 (1<<1) +#define IR_X86_SSSE3 (1<<2) +#define IR_X86_SSE41 (1<<3) +#define IR_X86_SSE42 (1<<4) +#define IR_X86_AVX (1<<5) +#define IR_X86_AVX2 (1<<6) + #endif /* IR_X86_H */ diff --git a/win32/Makefile b/win32/Makefile index 74394c0..37fef36 100644 --- a/win32/Makefile +++ b/win32/Makefile @@ -65,7 +65,7 @@ LIBS=psapi.lib capstone.lib OBJS_COMMON=$(BUILD_DIR)\ir.obj $(BUILD_DIR)\ir_strtab.obj $(BUILD_DIR)\ir_cfg.obj \ $(BUILD_DIR)\ir_sccp.obj $(BUILD_DIR)\ir_gcm.obj $(BUILD_DIR)\ir_ra.obj $(BUILD_DIR)\ir_emit.obj \ $(BUILD_DIR)\ir_load.obj $(BUILD_DIR)\ir_save.obj $(BUILD_DIR)\ir_emit_c.obj $(BUILD_DIR)\ir_dump.obj \ - $(BUILD_DIR)\ir_disasm.obj $(BUILD_DIR)\ir_check.obj + $(BUILD_DIR)\ir_disasm.obj $(BUILD_DIR)\ir_check.obj $(BUILD_DIR)\ir_cpuinfo.obj OBJS_IR = $(BUILD_DIR)\ir_main.obj OBJS_IR_TEST = $(BUILD_DIR)\ir_test.obj