Merge commit '2201a0227297b9251717e44adc32554a51ca0ed6' as 'external/xbyak'
This commit is contained in:
Vendored
+143
@@ -0,0 +1,143 @@
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
project(XbyakSamples)
|
||||
|
||||
# Set C++ standard
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
# Include directories
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/..)
|
||||
|
||||
# Read warning flags if available (only for GCC/Clang)
|
||||
if(NOT MSVC AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/../test/CFLAGS_WARN.cfg")
|
||||
file(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/../test/CFLAGS_WARN.cfg" CFLAGS_WARN_STR)
|
||||
separate_arguments(CFLAGS_WARN UNIX_COMMAND "${CFLAGS_WARN_STR}")
|
||||
endif()
|
||||
|
||||
# Platform-specific compiler flags
|
||||
if(WIN32)
|
||||
if(MSVC)
|
||||
set(COMMON_COMPILE_FLAGS /W3)
|
||||
else()
|
||||
set(COMMON_COMPILE_FLAGS -Wall -fomit-frame-pointer ${CFLAGS_WARN})
|
||||
endif()
|
||||
else()
|
||||
set(COMMON_COMPILE_FLAGS -Wall -fomit-frame-pointer ${CFLAGS_WARN})
|
||||
endif()
|
||||
|
||||
# Check for Boost (optional for calc samples)
|
||||
find_package(Boost QUIET COMPONENTS system)
|
||||
|
||||
# Helper function to add sample executable
|
||||
function(add_sample_target target_name source_file)
|
||||
add_executable(${target_name} ${source_file})
|
||||
target_compile_options(${target_name} PRIVATE ${COMMON_COMPILE_FLAGS})
|
||||
|
||||
# Set output directory
|
||||
set_target_properties(${target_name} PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin
|
||||
)
|
||||
|
||||
# Platform-specific settings
|
||||
if(NOT WIN32)
|
||||
find_package(Threads)
|
||||
if(Threads_FOUND)
|
||||
target_link_libraries(${target_name} ${CMAKE_THREAD_LIBS_INIT})
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# 64-bit targets (always available on 64-bit platforms)
|
||||
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
add_sample_target(test64 test0.cpp)
|
||||
add_sample_target(bf64 bf.cpp)
|
||||
add_sample_target(memfunc64 memfunc.cpp)
|
||||
add_sample_target(test_util64 test_util.cpp)
|
||||
add_sample_target(cputopology cputopology.cpp)
|
||||
add_sample_target(jmp_table64 jmp_table.cpp)
|
||||
add_sample_target(zero_upper zero_upper.cpp)
|
||||
add_sample_target(ccmp ccmp.cpp)
|
||||
add_sample_target(no_flags no_flags.cpp)
|
||||
|
||||
# Boost-dependent targets
|
||||
if(Boost_FOUND)
|
||||
add_sample_target(calc64 calc.cpp)
|
||||
target_link_libraries(calc64 Boost::boost)
|
||||
endif()
|
||||
|
||||
# Non-macOS targets
|
||||
if(NOT APPLE)
|
||||
if(UNIX)
|
||||
# static_buf uses Linux-specific mmap feature
|
||||
add_sample_target(static_buf64 static_buf.cpp)
|
||||
add_sample_target(memfd memfd.cpp)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Additional useful targets
|
||||
add_sample_target(quantize quantize.cpp)
|
||||
endif()
|
||||
|
||||
# Optional 32-bit targets (skip on macOS which is 64-bit only)
|
||||
# Note: Building 32-bit on 64-bit requires multilib on Linux (gcc-multilib g++-multilib)
|
||||
# Enable with: cmake -DBUILD_32BIT_TARGETS=ON ..
|
||||
option(BUILD_32BIT_TARGETS "Build 32-bit targets on 64-bit systems (requires multilib)" OFF)
|
||||
|
||||
if(BUILD_32BIT_TARGETS AND NOT APPLE AND CMAKE_SIZEOF_VOID_P EQUAL 8 AND UNIX AND NOT WIN32)
|
||||
message(STATUS "Building 32-bit targets (requires multilib)")
|
||||
|
||||
add_sample_target(test test0.cpp)
|
||||
target_compile_options(test PRIVATE -m32)
|
||||
target_link_options(test PRIVATE -m32)
|
||||
|
||||
add_sample_target(bf bf.cpp)
|
||||
target_compile_options(bf PRIVATE -m32)
|
||||
target_link_options(bf PRIVATE -m32)
|
||||
|
||||
add_sample_target(toyvm toyvm.cpp)
|
||||
target_compile_options(toyvm PRIVATE -m32)
|
||||
target_link_options(toyvm PRIVATE -m32)
|
||||
|
||||
add_sample_target(test_util test_util.cpp)
|
||||
target_compile_options(test_util PRIVATE -m32)
|
||||
target_link_options(test_util PRIVATE -m32)
|
||||
|
||||
add_sample_target(memfunc memfunc.cpp)
|
||||
target_compile_options(memfunc PRIVATE -m32)
|
||||
target_link_options(memfunc PRIVATE -m32)
|
||||
|
||||
add_sample_target(static_buf static_buf.cpp)
|
||||
target_compile_options(static_buf PRIVATE -m32)
|
||||
target_link_options(static_buf PRIVATE -m32)
|
||||
|
||||
add_sample_target(jmp_table jmp_table.cpp)
|
||||
target_compile_options(jmp_table PRIVATE -m32)
|
||||
target_link_options(jmp_table PRIVATE -m32)
|
||||
|
||||
if(Boost_FOUND)
|
||||
add_sample_target(calc calc.cpp)
|
||||
target_compile_options(calc PRIVATE -m32)
|
||||
target_link_options(calc PRIVATE -m32)
|
||||
target_link_libraries(calc Boost::boost)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Additional utilities
|
||||
add_sample_target(profiler profiler.cpp)
|
||||
|
||||
# Optional VTune profiler build
|
||||
option(BUILD_PROFILER_VTUNE "Build profiler with VTune support" OFF)
|
||||
if(BUILD_PROFILER_VTUNE AND UNIX)
|
||||
add_sample_target(profiler-vtune profiler.cpp)
|
||||
target_compile_definitions(profiler-vtune PRIVATE XBYAK_USE_VTUNE)
|
||||
target_include_directories(profiler-vtune PRIVATE /opt/intel/vtune_amplifier/include/)
|
||||
target_link_directories(profiler-vtune PRIVATE /opt/intel/vtune_amplifier/lib64)
|
||||
target_link_libraries(profiler-vtune jitprofiling dl)
|
||||
endif()
|
||||
|
||||
# Print configuration summary
|
||||
message(STATUS "Xbyak Samples Configuration:")
|
||||
message(STATUS " Build type: ${CMAKE_BUILD_TYPE}")
|
||||
message(STATUS " Architecture: ${CMAKE_SIZEOF_VOID_P} bytes (${CMAKE_SIZEOF_VOID_P} * 8 = ${CMAKE_SYSTEM_PROCESSOR})")
|
||||
message(STATUS " Boost found: ${Boost_FOUND}")
|
||||
message(STATUS " Output directory: ${CMAKE_BINARY_DIR}/bin")
|
||||
Vendored
+144
@@ -0,0 +1,144 @@
|
||||
XBYAK_INC=../xbyak/xbyak.h
|
||||
CXX?=g++
|
||||
CXX_32=$(CXX) -m32
|
||||
CXX_64=$(CXX) -m64
|
||||
|
||||
BOOST_EXIST=$(shell echo "#include <boost/spirit/core.hpp>" | $(CXX) -x c++ -c - 2>/dev/null && echo 1)
|
||||
UNAME_M=$(shell uname -m)
|
||||
|
||||
ONLY_64BIT=0
|
||||
ifeq ($(shell uname -s),Darwin)
|
||||
ONLY_64BIT=1
|
||||
OS=mac
|
||||
ifeq ($(UNAME_M),x86_64)
|
||||
BIT=64
|
||||
endif
|
||||
ifeq ($(UNAME_M),i386)
|
||||
BIT=32
|
||||
endif
|
||||
ifeq ($(shell sw_vers -productVersion | cut -c1-4 | sed 's/\.//'),105)
|
||||
ifeq ($(shell sysctl -n hw.cpu64bit_capable),1)
|
||||
BIT=64
|
||||
endif
|
||||
endif
|
||||
else
|
||||
BIT=32
|
||||
ifeq ($(UNAME_M),x86_64)
|
||||
BIT=64
|
||||
endif
|
||||
ifeq ($(UNAME_M),amd64)
|
||||
BIT=64
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(BIT),64)
|
||||
TARGET += test64 bf64 memfunc64 test_util64 jmp_table64 zero_upper ccmp no_flags
|
||||
ifeq ($(BOOST_EXIST),1)
|
||||
TARGET += calc64 #calc2_64
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq ($(OS),mac)
|
||||
TARGET += static_buf64
|
||||
TARGET += memfd
|
||||
endif
|
||||
|
||||
|
||||
ifneq ($(ONLY_64BIT),1)
|
||||
TARGET += test quantize bf toyvm test_util memfunc static_buf jmp_table
|
||||
ifeq ($(BOOST_EXIST),1)
|
||||
TARGET += calc #calc2
|
||||
endif
|
||||
endif
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
CFLAGS_WARN=$(shell cat ../test/CFLAGS_WARN.cfg)
|
||||
|
||||
CFLAGS=-g -O2 -fomit-frame-pointer -Wall -I../ $(CFLAGS_WARN) $(CXXFLAGS) $(CPPFLAGS) $(LDFLAGS)
|
||||
|
||||
test:
|
||||
$(CXX_32) $(CFLAGS) test0.cpp -o $@
|
||||
|
||||
quantize:
|
||||
$(CXX_32) $(CFLAGS) quantize.cpp -o $@
|
||||
|
||||
calc:
|
||||
$(CXX_32) $(CFLAGS) calc.cpp -o $@
|
||||
calc64:
|
||||
$(CXX_64) $(CFLAGS) calc.cpp -o $@
|
||||
calc2:
|
||||
$(CXX_32) $(CFLAGS) calc2.cpp -o $@
|
||||
calc2_64:
|
||||
$(CXX_64) $(CFLAGS) calc2.cpp -o $@
|
||||
|
||||
bf:
|
||||
$(CXX_32) $(CFLAGS) bf.cpp -o $@
|
||||
bf64:
|
||||
$(CXX_64) $(CFLAGS) bf.cpp -o $@
|
||||
|
||||
memfunc:
|
||||
$(CXX_32) $(CFLAGS) memfunc.cpp -o $@
|
||||
memfunc64:
|
||||
$(CXX_64) $(CFLAGS) memfunc.cpp -o $@
|
||||
|
||||
toyvm:
|
||||
$(CXX_32) $(CFLAGS) toyvm.cpp -o $@
|
||||
|
||||
test64:
|
||||
$(CXX_64) $(CFLAGS) test0.cpp -o $@
|
||||
test_util:
|
||||
$(CXX_32) $(CFLAGS) test_util.cpp -o $@
|
||||
test_util64:
|
||||
$(CXX_64) $(CFLAGS) test_util.cpp -o $@
|
||||
static_buf:
|
||||
$(CXX_32) $(CFLAGS) static_buf.cpp -o $@
|
||||
static_buf64:
|
||||
$(CXX_64) $(CFLAGS) static_buf.cpp -o $@
|
||||
cputopology:
|
||||
$(CXX_64) $(CFLAGS) cputopology.cpp -o $@
|
||||
jmp_table:
|
||||
$(CXX_32) $(CFLAGS) jmp_table.cpp -o $@
|
||||
jmp_table64:
|
||||
$(CXX_64) $(CFLAGS) jmp_table.cpp -o $@
|
||||
memfd:
|
||||
$(CXX_64) $(CFLAGS) memfd.cpp -o $@
|
||||
profiler: profiler.cpp ../xbyak/xbyak_util.h
|
||||
$(CXX) $(CFLAGS) profiler.cpp -o $@
|
||||
profiler-vtune: profiler.cpp ../xbyak/xbyak_util.h
|
||||
$(CXX) $(CFLAGS) profiler.cpp -o $@ -DXBYAK_USE_VTUNE -I /opt/intel/vtune_amplifier/include/ -L /opt/intel/vtune_amplifier/lib64 -ljitprofiling -ldl
|
||||
zero_upper: zero_upper.cpp $(XBYAK_INC)
|
||||
$(CXX) $(CFLAGS) zero_upper.cpp -o $@
|
||||
test_zero_upper: zero_upper
|
||||
sde -future -- ./zero_upper
|
||||
ccmp: ccmp.cpp $(XBYAK_INC)
|
||||
$(CXX) $(CFLAGS) ccmp.cpp -o $@
|
||||
test_ccmp: ccmp
|
||||
sde -future -- ./ccmp
|
||||
no_flags: no_flags.cpp $(XBYAK_INC)
|
||||
$(CXX) $(CFLAGS) no_flags.cpp -o $@
|
||||
test_no_flags: no_flags
|
||||
sde -future -- ./no_flags
|
||||
|
||||
clean:
|
||||
rm -rf $(TARGET) profiler profiler-vtune
|
||||
|
||||
test : test0.cpp $(XBYAK_INC)
|
||||
test64: test0.cpp $(XBYAK_INC)
|
||||
quantize : quantize.cpp $(XBYAK_INC)
|
||||
calc : calc.cpp $(XBYAK_INC)
|
||||
calc64 : calc.cpp $(XBYAK_INC)
|
||||
calc2 : calc2.cpp $(XBYAK_INC)
|
||||
calc2_64 : calc2.cpp $(XBYAK_INC)
|
||||
bf : bf.cpp $(XBYAK_INC)
|
||||
bf64 : bf.cpp $(XBYAK_INC)
|
||||
memfunc : memfunc.cpp $(XBYAK_INC)
|
||||
memfunc64 : memfunc.cpp $(XBYAK_INC)
|
||||
toyvm : toyvm.cpp $(XBYAK_INC)
|
||||
static_buf: static_buf.cpp $(XBYAK_INC)
|
||||
static_buf64: static_buf.cpp $(XBYAK_INC)
|
||||
test_util : test_util.cpp $(XBYAK_INC) ../xbyak/xbyak_util.h
|
||||
test_util64 : test_util.cpp $(XBYAK_INC) ../xbyak/xbyak_util.h
|
||||
jmp_table: jmp_table.cpp $(XBYAK_INC)
|
||||
jmp_table64: jmp_table.cpp $(XBYAK_INC)
|
||||
memfd: memfd.cpp $(XBYAK_INC)
|
||||
Vendored
+222
@@ -0,0 +1,222 @@
|
||||
#include "xbyak/xbyak.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stack>
|
||||
#include <fstream>
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable : 4996) // scanf
|
||||
#define snprintf _snprintf_s
|
||||
#endif
|
||||
|
||||
class Brainfuck : public Xbyak::CodeGenerator {
|
||||
public:
|
||||
int getContinuousChar(std::istream& is, char c)
|
||||
{
|
||||
int count = 1;
|
||||
char p;
|
||||
while (is >> p) {
|
||||
if (p != c) break;
|
||||
count++;
|
||||
}
|
||||
is.unget();
|
||||
return count;
|
||||
}
|
||||
Brainfuck(std::istream& is) : CodeGenerator(100000)
|
||||
{
|
||||
// void (*)(void* putchar, void* getchar, int *stack)
|
||||
using namespace Xbyak;
|
||||
#ifdef XBYAK32
|
||||
const Reg32& pPutchar(esi);
|
||||
const Reg32& pGetchar(edi);
|
||||
const Reg32& stack(ebp);
|
||||
const Address cur = byte [stack];
|
||||
push(ebp); // stack
|
||||
push(esi);
|
||||
push(edi);
|
||||
const int P_ = 4 * 3;
|
||||
mov(pPutchar, ptr[esp + P_ + 4]); // putchar
|
||||
mov(pGetchar, ptr[esp + P_ + 8]); // getchar
|
||||
mov(stack, ptr[esp + P_ + 12]); // stack
|
||||
#elif defined(XBYAK64_WIN)
|
||||
const Reg64& pPutchar(rsi);
|
||||
const Reg64& pGetchar(rdi);
|
||||
const Reg64& stack(rbp); // stack
|
||||
const Address cur = byte [stack];
|
||||
push(rsi);
|
||||
push(rdi);
|
||||
push(rbp);
|
||||
mov(pPutchar, rcx); // putchar
|
||||
mov(pGetchar, rdx); // getchar
|
||||
mov(stack, r8); // stack
|
||||
#else
|
||||
const Reg64& pPutchar(rbx);
|
||||
const Reg64& pGetchar(rbp);
|
||||
const Reg64& stack(r12); // stack
|
||||
const Address cur = byte [stack];
|
||||
push(rbx);
|
||||
push(rbp);
|
||||
push(r12);
|
||||
mov(pPutchar, rdi); // putchar
|
||||
mov(pGetchar, rsi); // getchar
|
||||
mov(stack, rdx); // stack
|
||||
#endif
|
||||
std::stack<Label> labelF, labelB;
|
||||
char c;
|
||||
while (is >> c) {
|
||||
switch (c) {
|
||||
case '+':
|
||||
case '-':
|
||||
{
|
||||
int count = getContinuousChar(is, c);
|
||||
if (count == 1) {
|
||||
c == '+' ? inc(cur) : dec(cur);
|
||||
} else {
|
||||
add(cur, (c == '+' ? count : -count));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case '>':
|
||||
case '<':
|
||||
{
|
||||
int count = getContinuousChar(is, c);
|
||||
add(stack, (c == '>' ? count : -count));
|
||||
}
|
||||
break;
|
||||
case '.':
|
||||
#ifdef XBYAK32
|
||||
push(cur);
|
||||
call(pPutchar);
|
||||
pop(eax);
|
||||
#elif defined(XBYAK64_WIN)
|
||||
movzx(ecx, cur);
|
||||
sub(rsp, 32);
|
||||
call(pPutchar);
|
||||
add(rsp, 32);
|
||||
#else
|
||||
movzx(edi, cur);
|
||||
call(pPutchar);
|
||||
#endif
|
||||
break;
|
||||
case ',':
|
||||
#if defined(XBYAK32) || defined(XBYAK64_GCC)
|
||||
call(pGetchar);
|
||||
#elif defined(XBYAK64_WIN)
|
||||
sub(rsp, 32);
|
||||
call(pGetchar);
|
||||
add(rsp, 32);
|
||||
#endif
|
||||
mov(cur, al);
|
||||
break;
|
||||
case '[':
|
||||
{
|
||||
Label B = L();
|
||||
labelB.push(B);
|
||||
movzx(eax, cur);
|
||||
test(eax, eax);
|
||||
Label F;
|
||||
jz(F, T_NEAR);
|
||||
labelF.push(F);
|
||||
}
|
||||
break;
|
||||
case ']':
|
||||
{
|
||||
Label B = labelB.top(); labelB.pop();
|
||||
jmp(B);
|
||||
Label F = labelF.top(); labelF.pop();
|
||||
L(F);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
#ifdef XBYAK32
|
||||
pop(edi);
|
||||
pop(esi);
|
||||
pop(ebp);
|
||||
#elif defined(XBYAK64_WIN)
|
||||
pop(rbp);
|
||||
pop(rdi);
|
||||
pop(rsi);
|
||||
#else
|
||||
pop(r12);
|
||||
pop(rbp);
|
||||
pop(rbx);
|
||||
#endif
|
||||
ret();
|
||||
}
|
||||
};
|
||||
|
||||
void dump(const uint8_t *code, size_t size)
|
||||
{
|
||||
puts("#include <stdio.h>\nstatic int stack[128 * 1024];");
|
||||
#ifdef _MSC_VER
|
||||
printf("static __declspec(align(4096)) ");
|
||||
#else
|
||||
printf("static __attribute__((aligned(4096)))");
|
||||
#endif
|
||||
puts("const unsigned char code[] = {");
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
printf("0x%02x,", code[i]); if ((i % 16) == 15) putchar('\n');
|
||||
}
|
||||
puts("\n};");
|
||||
#ifdef _MSC_VER
|
||||
puts("#include <windows.h>");
|
||||
#else
|
||||
puts("#include <unistd.h>");
|
||||
puts("#include <sys/mman.h>");
|
||||
#endif
|
||||
puts("int main()\n{");
|
||||
#ifdef _MSC_VER
|
||||
puts("\tDWORD oldProtect;");
|
||||
puts("\tVirtualProtect((void*)code, sizeof(code), PAGE_EXECUTE_READWRITE, &oldProtect);");
|
||||
#else
|
||||
puts("\tlong pageSize = sysconf(_SC_PAGESIZE) - 1;");
|
||||
puts("\tmprotect((void*)code, (sizeof(code) + pageSize) & ~pageSize, PROT_READ | PROT_EXEC);");
|
||||
#endif
|
||||
puts(
|
||||
"\t((void (*)(void*, void*, int *))code)((void*)putchar, (void*)getchar, stack);\n"
|
||||
"}"
|
||||
);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
#ifdef XBYAK32
|
||||
fprintf(stderr, "32bit mode\n");
|
||||
#else
|
||||
fprintf(stderr, "64bit mode\n");
|
||||
#endif
|
||||
if (argc == 1) {
|
||||
fprintf(stderr, "bf filename.bf [0|1|2]\n");
|
||||
return 1;
|
||||
}
|
||||
std::ifstream ifs(argv[1]);
|
||||
int mode = argc == 3 ? atoi(argv[2]) : 0;
|
||||
try {
|
||||
Brainfuck bf(ifs);
|
||||
switch (mode) {
|
||||
case 0: {
|
||||
static int stack[128 * 1024];
|
||||
bf.getCode<void (*)(const void*, const void*, int *)>()(reinterpret_cast<const void*>(putchar), reinterpret_cast<const void*>(getchar), stack);
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
dump(bf.getCode(), bf.getSize());
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
const char *dumpName = "bf.dump";
|
||||
printf("dump to %s\n", dumpName);
|
||||
std::ofstream ofs(dumpName, std::ios::binary);
|
||||
ofs.write((const char*)bf.getCode(), bf.getSize());
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (std::exception& e) {
|
||||
printf("ERR:%s\n", e.what());
|
||||
} catch (...) {
|
||||
printf("unknown error\n");
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+228
@@ -0,0 +1,228 @@
|
||||
/*
|
||||
@author herumi
|
||||
|
||||
tiny calculator
|
||||
This program generates a function to calc the value of
|
||||
polynomial given by user in run-time.
|
||||
use boost::spirit::classic
|
||||
see calc2.cpp for new version of boost::spirit
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <sstream>
|
||||
#include <map>
|
||||
#include "xbyak/xbyak.h"
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable : 4127) // for boost(constant condition)
|
||||
#pragma warning(disable : 4512) // for boost
|
||||
#endif
|
||||
#include <boost/spirit/include/classic_file_iterator.hpp>
|
||||
#include <boost/spirit/include/classic_core.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
|
||||
enum Error {
|
||||
UNDEFINED_VARIABLE = 1
|
||||
};
|
||||
|
||||
/*
|
||||
JIT assemble of given polynomial for VC or gcc
|
||||
*/
|
||||
class FuncGen : public Xbyak::CodeGenerator {
|
||||
public:
|
||||
typedef std::map<std::string, int> Map;
|
||||
private:
|
||||
enum {
|
||||
MAX_CONST_NUM = 32
|
||||
};
|
||||
double constTbl_[MAX_CONST_NUM];
|
||||
size_t constTblPos_;
|
||||
int regIdx_;
|
||||
Map varMap_; // map var name to index
|
||||
#ifdef XBYAK32
|
||||
const Xbyak::Reg32& valTbl_;
|
||||
const Xbyak::Reg32& tbl_;
|
||||
#else
|
||||
const Xbyak::Reg64& valTbl_;
|
||||
const Xbyak::Reg64& tbl_;
|
||||
#endif
|
||||
public:
|
||||
/*
|
||||
@param y [out] the value of f(var)
|
||||
@param var [in] table of input variables
|
||||
func(double *y, const double var[]);
|
||||
@note func does not return double to avoid difference of compiler
|
||||
*/
|
||||
FuncGen(const std::vector<std::string>& varTbl)
|
||||
: constTblPos_(0)
|
||||
, regIdx_(-1)
|
||||
#ifdef XBYAK32
|
||||
, valTbl_(eax)
|
||||
, tbl_(edx)
|
||||
#elif defined(XBYAK64_WIN)
|
||||
, valTbl_(rcx)
|
||||
, tbl_(rdx)
|
||||
#else
|
||||
, valTbl_(rdi)
|
||||
, tbl_(rsi)
|
||||
#endif
|
||||
{
|
||||
#ifdef XBYAK32
|
||||
mov(valTbl_, ptr[esp+8]); // eax == varTbl
|
||||
mov(tbl_, (size_t)constTbl_);
|
||||
#else
|
||||
#ifdef XBYAK64_WIN
|
||||
movaps(ptr [rsp + 8], xm6); // save xm6, xm7
|
||||
movaps(ptr [rsp + 8 + 16], xm7);
|
||||
#endif
|
||||
mov(tbl_, (size_t)constTbl_);
|
||||
#endif
|
||||
for (int i = 0, n = static_cast<int>(varTbl.size()); i < n; i++) {
|
||||
varMap_[varTbl[i]] = i;
|
||||
}
|
||||
}
|
||||
// use edx
|
||||
void genPush(double n)
|
||||
{
|
||||
if (constTblPos_ >= MAX_CONST_NUM) throw;
|
||||
constTbl_[constTblPos_] = n;
|
||||
if (regIdx_ == 7) throw;
|
||||
movsd(Xbyak::Xmm(++regIdx_), ptr[tbl_ + (int)(constTblPos_ * sizeof(double))]);
|
||||
constTblPos_++;
|
||||
}
|
||||
// use eax
|
||||
void genVal(const char *begin, const char *end)
|
||||
{
|
||||
std::string var(begin, end);
|
||||
if (varMap_.find(var) == varMap_.end()) throw UNDEFINED_VARIABLE;
|
||||
if (regIdx_ == 7) throw;
|
||||
movsd(Xbyak::Xmm(++regIdx_), ptr[valTbl_ + varMap_[var] * sizeof(double)]);
|
||||
}
|
||||
void genAdd(const char*, const char*)
|
||||
{
|
||||
addsd(Xbyak::Xmm(regIdx_ - 1), Xbyak::Xmm(regIdx_)); regIdx_--;
|
||||
}
|
||||
void genSub(const char*, const char*)
|
||||
{
|
||||
subsd(Xbyak::Xmm(regIdx_ - 1), Xbyak::Xmm(regIdx_)); regIdx_--;
|
||||
}
|
||||
void genMul(const char*, const char*)
|
||||
{
|
||||
mulsd(Xbyak::Xmm(regIdx_ - 1), Xbyak::Xmm(regIdx_)); regIdx_--;
|
||||
}
|
||||
void genDiv(const char*, const char*)
|
||||
{
|
||||
divsd(Xbyak::Xmm(regIdx_ - 1), Xbyak::Xmm(regIdx_)); regIdx_--;
|
||||
}
|
||||
void complete()
|
||||
{
|
||||
#ifdef XBYAK32
|
||||
mov(eax, ptr [esp + 4]); // eax = valTbl
|
||||
movsd(ptr [eax], xm0);
|
||||
#else
|
||||
#ifdef XBYAK64_WIN
|
||||
movaps(xm6, ptr [rsp + 8]);
|
||||
movaps(xm7, ptr [rsp + 8 + 16]);
|
||||
#endif
|
||||
#endif
|
||||
ret();
|
||||
}
|
||||
};
|
||||
|
||||
struct Grammar : public boost::spirit::classic::grammar<Grammar> {
|
||||
FuncGen& f_;
|
||||
Grammar(FuncGen& f) : f_(f) { }
|
||||
template<typename ScannerT>
|
||||
struct definition {
|
||||
boost::spirit::classic::rule<ScannerT> poly0, poly1, poly2, var;
|
||||
|
||||
definition(const Grammar& self)
|
||||
{
|
||||
using namespace boost;
|
||||
using namespace boost::spirit::classic;
|
||||
|
||||
poly0 = poly1 >> *(('+' >> poly1)[bind(&FuncGen::genAdd, ref(self.f_), _1, _2)]
|
||||
| ('-' >> poly1)[bind(&FuncGen::genSub, ref(self.f_), _1, _2)]);
|
||||
poly1 = poly2 >> *(('*' >> poly2)[bind(&FuncGen::genMul, ref(self.f_), _1, _2)]
|
||||
| ('/' >> poly2)[bind(&FuncGen::genDiv, ref(self.f_), _1, _2)]);
|
||||
var = (+alpha_p)[bind(&FuncGen::genVal, ref(self.f_), _1, _2)];
|
||||
poly2 = real_p[bind(&FuncGen::genPush, ref(self.f_), _1)]
|
||||
| var
|
||||
| '(' >> poly0 >> ')';
|
||||
}
|
||||
const boost::spirit::classic::rule<ScannerT>& start() const { return poly0; }
|
||||
};
|
||||
};
|
||||
|
||||
void put(const std::vector<double>& x)
|
||||
{
|
||||
for (size_t i = 0, n = x.size(); i < n; i++) {
|
||||
if (i > 0) printf(", ");
|
||||
printf("%f", x[i]);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc <= 2) {
|
||||
fprintf(stderr, "calc \"var1 var2 ...\" \"function of var\"\n");
|
||||
fprintf(stderr, "eg. calc x \"x*x\"\n");
|
||||
fprintf(stderr, "eg. calc \"x y z\" \"x*x + y - z\"\n");
|
||||
return 1;
|
||||
}
|
||||
const char *poly = argv[2];
|
||||
try {
|
||||
std::vector<std::string> varTbl;
|
||||
|
||||
// get varTbl from argv[1]
|
||||
{
|
||||
std::istringstream is(argv[1]);
|
||||
int i = 0;
|
||||
printf("varTbl = { ");
|
||||
while (is) {
|
||||
std::string var;
|
||||
is >> var;
|
||||
if (var.empty()) break;
|
||||
printf("%s:%d, ", var.c_str(), i);
|
||||
varTbl.push_back(var);
|
||||
i++;
|
||||
}
|
||||
printf("}\n");
|
||||
}
|
||||
FuncGen funcGen(varTbl);
|
||||
Grammar calc(funcGen);
|
||||
boost::spirit::classic::parse_info<> r = parse(poly, calc, boost::spirit::classic::space_p);
|
||||
if (!r.full) {
|
||||
printf("err poly=%s\n", poly);
|
||||
return 1;
|
||||
}
|
||||
funcGen.complete();
|
||||
std::vector<double> valTbl;
|
||||
valTbl.resize(varTbl.size());
|
||||
#ifdef XBYAK32
|
||||
puts("32bit mode");
|
||||
void (*func)(double *ret, const double *valTbl) = funcGen.getCode<void (*)(double *, const double*)>();
|
||||
#else
|
||||
puts("64bit mode");
|
||||
double (*func)(const double *valTbl) = funcGen.getCode<double (*)(const double*)>();
|
||||
#endif
|
||||
for (int i = 0; i < 10; i++) {
|
||||
for (size_t j = 0, n = valTbl.size(); j < n; j++) {
|
||||
valTbl[j] = rand() % 7;
|
||||
}
|
||||
double y;
|
||||
#ifdef XBYAK32
|
||||
func(&y, &valTbl[0]);
|
||||
#else
|
||||
y = func(&valTbl[0]);
|
||||
#endif
|
||||
printf("f("); put(valTbl); printf(")=%f\n", y);
|
||||
}
|
||||
} catch (std::exception& e) {
|
||||
printf("ERR:%s\n", e.what());
|
||||
} catch (Error err) {
|
||||
printf("ERR:%d\n", err);
|
||||
} catch (...) {
|
||||
printf("unknown error\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Vendored
+301
@@ -0,0 +1,301 @@
|
||||
/*
|
||||
@author herumi
|
||||
|
||||
tiny calculator 2
|
||||
This program generates a function to calc the value of
|
||||
polynomial given by user in run-time.
|
||||
use boost::spirit::qi
|
||||
*/
|
||||
#ifdef _WIN32
|
||||
#pragma warning(disable : 4127) // for boost(constant condition)
|
||||
#pragma warning(disable : 4512) // for boost
|
||||
#pragma warning(disable : 4819)
|
||||
#endif
|
||||
#include <boost/config/warning_disable.hpp>
|
||||
#include <boost/spirit/include/qi.hpp>
|
||||
#include <boost/spirit/include/phoenix_core.hpp>
|
||||
#include <boost/spirit/include/phoenix_container.hpp>
|
||||
#include <boost/spirit/include/phoenix_bind.hpp>
|
||||
#include <boost/timer.hpp>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "xbyak/xbyak.h"
|
||||
|
||||
enum Operand {
|
||||
OpAdd,
|
||||
OpSub,
|
||||
OpMul,
|
||||
OpDiv,
|
||||
OpNeg,
|
||||
OpImm,
|
||||
OpVarX
|
||||
};
|
||||
|
||||
struct Code {
|
||||
Operand op_;
|
||||
double val_;
|
||||
Code(Operand op)
|
||||
: op_(op)
|
||||
, val_(0)
|
||||
{
|
||||
}
|
||||
Code(double val)
|
||||
: op_(OpImm)
|
||||
, val_(val)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::vector<Code> CodeSet;
|
||||
|
||||
struct Vm {
|
||||
CodeSet code_;
|
||||
double operator()(double x) const
|
||||
{
|
||||
const size_t maxStack = 16;
|
||||
double stack[maxStack];
|
||||
double *p = stack;
|
||||
CodeSet::const_iterator pc = code_.begin();
|
||||
|
||||
while (pc != code_.end()) {
|
||||
switch (pc->op_) {
|
||||
case OpVarX:
|
||||
*p++ = x;
|
||||
break;
|
||||
case OpImm:
|
||||
*p++ = pc->val_;
|
||||
break;
|
||||
case OpNeg:
|
||||
p[-1] = -p[-1];
|
||||
break;
|
||||
case OpAdd:
|
||||
--p;
|
||||
p[-1] += p[0];
|
||||
break;
|
||||
case OpSub:
|
||||
--p;
|
||||
p[-1] -= p[0];
|
||||
break;
|
||||
case OpMul:
|
||||
--p;
|
||||
p[-1] *= p[0];
|
||||
break;
|
||||
case OpDiv:
|
||||
--p;
|
||||
p[-1] /= p[0];
|
||||
break;
|
||||
}
|
||||
++pc;
|
||||
assert(p < stack + maxStack);
|
||||
}
|
||||
return p[-1];
|
||||
}
|
||||
};
|
||||
|
||||
class Jit : public Xbyak::CodeGenerator {
|
||||
private:
|
||||
enum {
|
||||
MAX_CONST_NUM = 32
|
||||
};
|
||||
MIE_ALIGN(16) double constTbl_[MAX_CONST_NUM];
|
||||
Xbyak::uint64_t negConst_;
|
||||
size_t constTblPos_;
|
||||
#ifdef XBYAK32
|
||||
const Xbyak::Reg32& varTbl_;
|
||||
const Xbyak::Reg32& tbl_;
|
||||
#else
|
||||
const Xbyak::Reg64& tbl_;
|
||||
#endif
|
||||
int regIdx_;
|
||||
public:
|
||||
/*
|
||||
double jit(double x);
|
||||
@note 32bit: x : [esp+4], return fp0
|
||||
64bit: x [rcx](win), xmm0(gcc), return xmm0
|
||||
*/
|
||||
Jit()
|
||||
: negConst_(Xbyak::uint64_t(1) << 63)
|
||||
, constTblPos_(0)
|
||||
#ifdef XBYAK32
|
||||
, varTbl_(eax)
|
||||
, tbl_(edx)
|
||||
#elif defined(XBYAK64_WIN)
|
||||
, tbl_(rcx)
|
||||
#else
|
||||
, tbl_(rdi)
|
||||
#endif
|
||||
, regIdx_(-1)
|
||||
{
|
||||
#ifdef XBYAK32
|
||||
lea(varTbl_, ptr [esp+4]);
|
||||
#else
|
||||
#ifdef XBYAK64_WIN
|
||||
movaps(ptr [rsp + 8], xm6); // save xm6, xm7
|
||||
movaps(ptr [rsp + 8 + 16], xm7);
|
||||
#endif
|
||||
movaps(xm7, xm0); // save xm0
|
||||
#endif
|
||||
mov(tbl_, (size_t)constTbl_);
|
||||
}
|
||||
void genPush(double n)
|
||||
{
|
||||
if (constTblPos_ >= MAX_CONST_NUM) throw;
|
||||
constTbl_[constTblPos_] = n;
|
||||
if (regIdx_ == 7) throw;
|
||||
movsd(Xbyak::Xmm(++regIdx_), ptr[tbl_ + constTblPos_ * sizeof(double)]);
|
||||
constTblPos_++;
|
||||
}
|
||||
void genVarX()
|
||||
{
|
||||
#ifdef XBYAK32
|
||||
if (regIdx_ == 7) throw;
|
||||
movsd(Xbyak::Xmm(++regIdx_), ptr[varTbl_]);
|
||||
#else
|
||||
if (regIdx_ == 6) throw;
|
||||
movsd(Xbyak::Xmm(++regIdx_), xm7);
|
||||
#endif
|
||||
}
|
||||
void genAdd()
|
||||
{
|
||||
addsd(Xbyak::Xmm(regIdx_ - 1), Xbyak::Xmm(regIdx_)); regIdx_--;
|
||||
}
|
||||
void genSub()
|
||||
{
|
||||
subsd(Xbyak::Xmm(regIdx_ - 1), Xbyak::Xmm(regIdx_)); regIdx_--;
|
||||
}
|
||||
void genMul()
|
||||
{
|
||||
mulsd(Xbyak::Xmm(regIdx_ - 1), Xbyak::Xmm(regIdx_)); regIdx_--;
|
||||
}
|
||||
void genDiv()
|
||||
{
|
||||
divsd(Xbyak::Xmm(regIdx_ - 1), Xbyak::Xmm(regIdx_)); regIdx_--;
|
||||
}
|
||||
void genNeg()
|
||||
{
|
||||
xorpd(Xbyak::Xmm(regIdx_), ptr [tbl_ + MAX_CONST_NUM * sizeof(double)]);
|
||||
}
|
||||
void complete()
|
||||
{
|
||||
#ifdef XBYAK32
|
||||
sub(esp, 8);
|
||||
movsd(ptr [esp], xm0);
|
||||
fld(qword [esp]);
|
||||
add(esp, 8);
|
||||
#else
|
||||
#ifdef XBYAK64_WIN
|
||||
movaps(xm6, ptr [rsp + 8]);
|
||||
movaps(xm7, ptr [rsp + 8 + 16]);
|
||||
#endif
|
||||
#endif
|
||||
ret();
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Iterator>
|
||||
struct Parser : boost::spirit::qi::grammar<Iterator, boost::spirit::ascii::space_type> {
|
||||
boost::spirit::qi::rule<Iterator, boost::spirit::ascii::space_type> expression, term, factor;
|
||||
CodeSet& code_;
|
||||
Parser(CodeSet& code)
|
||||
: Parser::base_type(expression)
|
||||
, code_(code)
|
||||
{
|
||||
namespace qi = boost::spirit::qi;
|
||||
using namespace qi::labels;
|
||||
|
||||
using boost::phoenix::ref;
|
||||
using boost::phoenix::push_back;
|
||||
|
||||
expression = term >> *(('+' > term[push_back(ref(code_), OpAdd)])
|
||||
| ('-' > term[push_back(ref(code_), OpSub)]));
|
||||
|
||||
term = factor >> *(('*' > factor[push_back(ref(code_), OpMul)])
|
||||
| ('/' > factor[push_back(ref(code_), OpDiv)]));
|
||||
|
||||
factor = qi::double_[push_back(ref(code_), _1)]
|
||||
| qi::lit('x')[push_back(ref(code_), OpVarX)]
|
||||
| ('(' > expression > ')')
|
||||
| ('-' > factor[push_back(ref(code_), OpNeg)])
|
||||
| ('+' > factor);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Iterator>
|
||||
struct ParserJit : boost::spirit::qi::grammar<Iterator, boost::spirit::ascii::space_type> {
|
||||
boost::spirit::qi::rule<Iterator, boost::spirit::ascii::space_type> expression, term, factor;
|
||||
Jit code_;
|
||||
ParserJit()
|
||||
: ParserJit::base_type(expression)
|
||||
{
|
||||
namespace qi = boost::spirit::qi;
|
||||
using namespace qi::labels;
|
||||
|
||||
using boost::phoenix::ref;
|
||||
using boost::phoenix::push_back;
|
||||
using boost::phoenix::bind;
|
||||
|
||||
expression = term >> *(('+' > term[bind(&Jit::genAdd, ref(code_))])
|
||||
| ('-' > term[bind(&Jit::genSub, ref(code_))]));
|
||||
|
||||
term = factor >> *(('*' > factor[bind(&Jit::genMul, ref(code_))])
|
||||
| ('/' > factor[bind(&Jit::genDiv, ref(code_))]));
|
||||
|
||||
factor = qi::double_[bind(&Jit::genPush, ref(code_), _1)]
|
||||
| qi::lit('x')[bind(&Jit::genVarX, ref(code_))]
|
||||
| ('(' > expression > ')')
|
||||
| ('-' > factor[bind(&Jit::genNeg, ref(code_))])
|
||||
| ('+' > factor);
|
||||
}
|
||||
};
|
||||
|
||||
template<class Func>
|
||||
void Test(const char *msg, const Func& f)
|
||||
{
|
||||
printf("%s:", msg);
|
||||
boost::timer t;
|
||||
double sum = 0;
|
||||
for (double x = 0; x < 1000; x += 0.0001) {
|
||||
sum += f(x);
|
||||
}
|
||||
printf("sum=%f, %fsec\n", sum, t.elapsed());
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "input formula\n");
|
||||
return 1;
|
||||
}
|
||||
const std::string str(argv[1]);
|
||||
|
||||
try {
|
||||
Vm vm;
|
||||
Parser<std::string::const_iterator> parser(vm.code_);
|
||||
ParserJit<std::string::const_iterator> parserJit;
|
||||
|
||||
const std::string::const_iterator end = str.end();
|
||||
|
||||
std::string::const_iterator i = str.begin();
|
||||
if (!phrase_parse(i, end, parser, boost::spirit::ascii::space) || i != end) {
|
||||
puts("err 1");
|
||||
return 1;
|
||||
}
|
||||
printf("ret=%f\n", vm(2.3));
|
||||
|
||||
i = str.begin();
|
||||
if (!phrase_parse(i, end, parserJit, boost::spirit::ascii::space) || i != end) {
|
||||
puts("err 2");
|
||||
return 1;
|
||||
}
|
||||
parserJit.code_.complete();
|
||||
double (*jit)(double) = parserJit.code_.getCode<double (*)(double)>();
|
||||
|
||||
Test("VM ", vm);
|
||||
Test("JIT", jit);
|
||||
} catch (...) {
|
||||
fprintf(stderr, "err\n");
|
||||
}
|
||||
}
|
||||
Vendored
+68
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
An example of ccmp
|
||||
> g++ ccmp.cpp -I ../xbyak
|
||||
> sde -future -- ./a.out
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <xbyak/xbyak.h>
|
||||
#include <xbyak/xbyak_util.h>
|
||||
|
||||
using namespace Xbyak;
|
||||
|
||||
struct Code1 : Xbyak::CodeGenerator {
|
||||
Code1()
|
||||
{
|
||||
Xbyak::util::StackFrame sf(this, 2);
|
||||
const auto& p1 = sf.p[0];
|
||||
const auto& p2 = sf.p[1];
|
||||
int dfv = 0;
|
||||
cmp(p1, 3);
|
||||
ctesta(p2, 1, dfv); // eflags = (p1 > 3) ? ((p2 & 1) == 0) : dfv;
|
||||
setz(al|T_zu);
|
||||
}
|
||||
};
|
||||
|
||||
struct Code2 : Xbyak::CodeGenerator {
|
||||
Code2()
|
||||
{
|
||||
Xbyak::util::StackFrame sf(this, 3);
|
||||
const auto& p1 = sf.p[0];
|
||||
const auto& p2 = sf.p[1];
|
||||
const auto& p3 = sf.p[2];
|
||||
int dfv = 0;
|
||||
cmp(p1, 1);
|
||||
ccmpe(p2, 2, dfv); // eflags = p1==1 ? p2==2 : dfv;
|
||||
ccmpe(p3, 3, dfv); // eflags = (p1==1 && p2==2) ? p3==3 : dfv;
|
||||
setz(al|T_zu); // p1==1 && p2==2 && p3==3
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
int main()
|
||||
try
|
||||
{
|
||||
{
|
||||
puts("(p1 > 3) && ((p2 & 1) == 0)");
|
||||
Code1 c;
|
||||
auto f = c.getCode<int (*)(int, int)>();
|
||||
for (int p1 = 2; p1 < 5; p1++) {
|
||||
for (int p2 = 0; p2 < 3; p2++) {
|
||||
printf("p1=%d p2=%d ret=%d (%d)\n", p1, p2, f(p1, p2), p1 > 3 && ((p2&1) == 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
puts("p1 == 1 && p2 == 2 && p3 == 3");
|
||||
Code2 c;
|
||||
auto f = c.getCode<int (*)(int, int, int)>();
|
||||
for (int p1 = 0; p1 < 3; p1++) {
|
||||
for (int p2 = 1; p2 < 4; p2++) {
|
||||
for (int p3 = 2; p3 < 5; p3++) {
|
||||
printf("p1=%d p2=%d p3=%d ret=%d (%d)\n", p1, p2, p3, f(p1, p2, p3), p1==1 && p2==2 && p3==3);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (std::exception& e) {
|
||||
printf("ERR %s\n", e.what());
|
||||
}
|
||||
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
vendor intel
|
||||
mmx mmx2 cmov sse sse2 sse3 ssse3 sse41 sse42 popcnt aesni rdtscp xsave(xgetvb) osxsave pclmulqdq avx fma avx2 bmi1 bmi2 lzcnt prefetchw enh_rep rdrand adx rdseed smap sha f16c movbe gfni vaes vpclmulqdq avx_vnni waitpkg clflushopt clwb movdiri movdir64b serialize aeskle wide_kl keylocker keylocker_wide hybrid
|
||||
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
vendor intel
|
||||
mmx mmx2 cmov sse sse2 sse3 ssse3 sse41 sse42 popcnt aesni rdtscp xsave(xgetvb) osxsave pclmulqdq avx fma avx2 bmi1 bmi2 lzcnt prefetchw enh_rep rdrand adx rdseed smap sha f16c movbe gfni vaes vpclmulqdq avx_vnni waitpkg clflushopt clwb movdiri movdir64b uintr serialize avx_vnni_int8 avx_ne_convert avx_ifma cmpccxadd sha512 sm3 sm4 avx_vnni_int16 aeskle wide_kl keylocker keylocker_wide hybrid
|
||||
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
vendor intel
|
||||
mmx mmx2 cmov sse sse2 sse3 ssse3 sse41 sse42 popcnt aesni rdtscp xsave(xgetvb) osxsave pclmulqdq avx fma avx2 bmi1 bmi2 lzcnt prefetchw enh_rep rdrand adx rdseed smap f16c movbe
|
||||
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
vendor intel
|
||||
mmx mmx2 cmov sse sse2 sse3 ssse3 sse41 sse42 popcnt aesni rdtscp xsave(xgetvb) osxsave pclmulqdq avx fma avx2 bmi1 bmi2 lzcnt prefetchw enh_rep rdrand adx rdseed smap f16c movbe avx512f avx512dq avx512cd avx512bw avx512vl avx512_vnni clflushopt clwb
|
||||
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
vendor intel
|
||||
mmx mmx2 cmov sse sse2 sse3 ssse3 sse41 sse42 popcnt aesni rdtscp xsave(xgetvb) osxsave pclmulqdq avx fma avx2 bmi1 bmi2 lzcnt prefetchw enh_rep rdrand adx rdseed smap sha f16c movbe avx512f avx512dq avx512_ifma avx512cd avx512bw avx512vl avx512_vbmi clflushopt
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
#!/bin/bash
|
||||
|
||||
UPDATE=0
|
||||
if [ $# -eq 1 ]; then
|
||||
UPDATE=1
|
||||
fi
|
||||
|
||||
if [ $UPDATE == 1 ]; then
|
||||
echo "UPDATE"
|
||||
fi
|
||||
|
||||
make -C ../ test_util64
|
||||
|
||||
cpus=(p4p mrm pnr nhm wsm snb ivb hsw bdw slt slm glm glp tnt skl cnl icl skx clx cpx icx tgl adl mtl rpl spr emr gnr dmr srf arl lnl ptl nvl cwf)
|
||||
|
||||
for cpu in ${cpus[@]} ; do
|
||||
echo $cpu
|
||||
if [ $UPDATE == 1 ]; then
|
||||
~/bin/sde -$cpu -- ../test_util64 -cpuid > $cpu.txt
|
||||
else
|
||||
~/bin/sde -$cpu -- ../test_util64 -cpuid > tmp.txt
|
||||
diff $cpu.txt tmp.txt
|
||||
fi
|
||||
done
|
||||
|
||||
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
vendor intel
|
||||
mmx mmx2 cmov sse sse2 sse3 ssse3 sse41 sse42 popcnt aesni rdtscp xsave(xgetvb) osxsave pclmulqdq avx fma avx2 bmi1 bmi2 lzcnt prefetchw enh_rep rdrand adx rdseed smap f16c movbe avx512f avx512dq avx512cd avx512bw avx512vl avx512_vnni avx512_bf16 clflushopt clwb amx_fp8 amx_transpose amx_tf32 amx_avx512
|
||||
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
vendor intel
|
||||
mmx mmx2 cmov sse sse2 sse3 ssse3 sse41 sse42 popcnt aesni rdtscp xsave(xgetvb) osxsave pclmulqdq avx fma avx2 bmi1 bmi2 lzcnt enh_rep rdrand adx rdseed smap sha f16c movbe gfni vaes vpclmulqdq avx_vnni waitpkg clflushopt cldemote clwb movdiri movdir64b uintr serialize avx_vnni_int8 avx_ne_convert avx_ifma cmpccxadd prefetchiti sha512 sm3 sm4 avx_vnni_int16 aeskle wide_kl keylocker keylocker_wide
|
||||
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
vendor intel
|
||||
mmx mmx2 cmov sse sse2 sse3 ssse3 sse41 sse42 popcnt aesni rdtscp xsave(xgetvb) osxsave pclmulqdq avx fma avx2 bmi1 bmi2 lzcnt prefetchw enh_rep rdrand adx rdseed smap sha f16c movbe avx512f avx512dq avx512_ifma avx512cd avx512bw avx512vl avx512_vbmi avx512_vbmi2 gfni vaes vpclmulqdq avx512_vnni avx512_bitalg avx512_vpopcntdq avx512_bf16 amx(tile) amx(int8) amx(bf16) avx_vnni avx512_fp16 waitpkg clflushopt cldemote clwb movdiri movdir64b uintr serialize amx_fp16 avx_vnni_int8 avx_ne_convert avx_ifma cmpccxadd prefetchiti sha512 sm3 sm4 avx_vnni_int16 apx_f avx10 amx_fp8 amx_transpose amx_tf32 amx_avx512 amx_movrs movrs
|
||||
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
vendor intel
|
||||
mmx mmx2 cmov sse sse2 sse3 ssse3 sse41 sse42 popcnt aesni rdtscp xsave(xgetvb) osxsave pclmulqdq avx fma avx2 bmi1 bmi2 lzcnt prefetchw enh_rep rdrand adx rdseed smap sha f16c movbe avx512f avx512dq avx512_ifma avx512cd avx512bw avx512vl avx512_vbmi avx512_vbmi2 gfni vaes vpclmulqdq avx512_vnni avx512_bitalg avx512_vpopcntdq avx512_bf16 amx(tile) amx(int8) amx(bf16) avx_vnni avx512_fp16 waitpkg clflushopt cldemote clwb movdiri movdir64b uintr serialize
|
||||
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
vendor intel
|
||||
mmx mmx2 cmov sse sse2 sse3 ssse3 sse41 sse42 popcnt aesni rdtscp xsave(xgetvb) osxsave pclmulqdq enh_rep rdrand rdseed smap sha movbe clflushopt
|
||||
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
vendor intel
|
||||
mmx mmx2 cmov sse sse2 sse3 ssse3 sse41 sse42 popcnt aesni rdtscp xsave(xgetvb) osxsave pclmulqdq enh_rep rdrand rdseed smap sha movbe clflushopt
|
||||
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
vendor intel
|
||||
mmx mmx2 cmov sse sse2 sse3 ssse3 sse41 sse42 popcnt aesni rdtscp xsave(xgetvb) osxsave pclmulqdq avx fma avx2 bmi1 bmi2 lzcnt prefetchw enh_rep rdrand adx rdseed smap sha f16c movbe avx512f avx512dq avx512_ifma avx512cd avx512bw avx512vl avx512_vbmi avx512_vbmi2 gfni vaes vpclmulqdq avx512_vnni avx512_bitalg avx512_vpopcntdq avx512_bf16 amx(tile) amx(int8) amx(bf16) avx_vnni avx512_fp16 waitpkg clflushopt cldemote clwb movdiri movdir64b uintr serialize amx_fp16 prefetchiti avx10
|
||||
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
vendor intel
|
||||
mmx mmx2 cmov sse sse2 sse3 ssse3 sse41 sse42 popcnt aesni rdtscp xsave(xgetvb) osxsave pclmulqdq avx fma avx2 bmi1 bmi2 lzcnt enh_rep rdrand f16c movbe
|
||||
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
vendor intel
|
||||
mmx mmx2 cmov sse sse2 sse3 ssse3 sse41 sse42 popcnt aesni rdtscp xsave(xgetvb) osxsave pclmulqdq avx fma avx2 bmi1 bmi2 lzcnt prefetchw enh_rep rdrand adx rdseed smap sha f16c movbe avx512f avx512dq avx512_ifma avx512cd avx512bw avx512vl avx512_vbmi avx512_vbmi2 gfni vaes vpclmulqdq avx512_vnni avx512_bitalg avx512_vpopcntdq clflushopt clwb
|
||||
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
vendor intel
|
||||
mmx mmx2 cmov sse sse2 sse3 ssse3 sse41 sse42 popcnt aesni rdtscp xsave(xgetvb) osxsave pclmulqdq avx fma avx2 bmi1 bmi2 lzcnt prefetchw enh_rep rdrand adx rdseed smap sha f16c movbe avx512f avx512dq avx512_ifma avx512cd avx512bw avx512vl avx512_vbmi avx512_vbmi2 gfni vaes vpclmulqdq avx512_vnni avx512_bitalg avx512_vpopcntdq clflushopt clwb
|
||||
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
vendor intel
|
||||
mmx mmx2 cmov sse sse2 sse3 ssse3 sse41 sse42 popcnt aesni rdtscp xsave(xgetvb) osxsave pclmulqdq avx enh_rep rdrand f16c
|
||||
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
vendor intel
|
||||
mmx mmx2 cmov sse sse2 sse3 ssse3 sse41 sse42 popcnt aesni rdtscp xsave(xgetvb) osxsave pclmulqdq avx fma avx2 bmi1 bmi2 lzcnt prefetchw enh_rep rdrand adx rdseed smap sha f16c movbe gfni vaes vpclmulqdq avx_vnni waitpkg clflushopt clwb movdiri movdir64b uintr serialize avx_vnni_int8 avx_ne_convert avx_ifma cmpccxadd sha512 sm3 sm4 avx_vnni_int16 aeskle wide_kl keylocker keylocker_wide hybrid
|
||||
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
vendor intel
|
||||
mmx mmx2 cmov sse sse2 sse3 ssse3
|
||||
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
vendor intel
|
||||
mmx mmx2 cmov sse sse2 sse3 ssse3 sse41 sse42 popcnt aesni rdtscp xsave(xgetvb) osxsave pclmulqdq avx fma avx2 bmi1 bmi2 lzcnt prefetchw enh_rep rdrand adx rdseed smap sha f16c movbe gfni vaes vpclmulqdq avx_vnni waitpkg clflushopt clwb movdiri movdir64b serialize aeskle wide_kl keylocker keylocker_wide hybrid
|
||||
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
vendor intel
|
||||
mmx mmx2 cmov sse sse2 sse3 ssse3 sse41 sse42 popcnt rdtscp
|
||||
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
vendor intel
|
||||
mmx mmx2 cmov sse sse2 sse3
|
||||
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
vendor intel
|
||||
mmx mmx2 cmov sse sse2 sse3 ssse3 sse41
|
||||
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
vendor intel
|
||||
mmx mmx2 cmov sse sse2 sse3 ssse3 sse41 sse42 popcnt aesni rdtscp xsave(xgetvb) osxsave pclmulqdq avx fma avx2 bmi1 bmi2 lzcnt prefetchw enh_rep rdrand adx rdseed smap sha f16c movbe gfni vaes vpclmulqdq avx_vnni waitpkg clflushopt clwb movdiri movdir64b uintr serialize avx_vnni_int8 avx_ne_convert avx_ifma cmpccxadd sha512 sm3 sm4 avx_vnni_int16 aeskle wide_kl keylocker keylocker_wide hybrid
|
||||
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
vendor intel
|
||||
mmx mmx2 cmov sse sse2 sse3 ssse3 sse41 sse42 popcnt aesni rdtscp xsave(xgetvb) osxsave pclmulqdq avx fma avx2 bmi1 bmi2 lzcnt prefetchw enh_rep rdrand adx rdseed smap sha f16c movbe gfni vaes vpclmulqdq avx_vnni waitpkg clflushopt clwb movdiri movdir64b serialize aeskle wide_kl keylocker keylocker_wide hybrid
|
||||
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
vendor intel
|
||||
mmx mmx2 cmov sse sse2 sse3 ssse3 sse41 sse42 popcnt aesni rdtscp xsave(xgetvb) osxsave pclmulqdq avx fma avx2 bmi1 bmi2 lzcnt prefetchw enh_rep rdrand adx rdseed smap f16c movbe clflushopt
|
||||
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
vendor intel
|
||||
mmx mmx2 cmov sse sse2 sse3 ssse3 sse41 sse42 popcnt aesni rdtscp xsave(xgetvb) osxsave pclmulqdq avx fma avx2 bmi1 bmi2 lzcnt prefetchw enh_rep rdrand adx rdseed smap f16c movbe avx512f avx512dq avx512cd avx512bw avx512vl clflushopt clwb
|
||||
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
vendor intel
|
||||
mmx mmx2 cmov sse sse2 sse3 ssse3 sse41 sse42 popcnt aesni rdtscp pclmulqdq prefetchw enh_rep rdrand movbe
|
||||
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
vendor intel
|
||||
mmx mmx2 cmov sse sse2 sse3 ssse3 movbe
|
||||
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
vendor intel
|
||||
mmx mmx2 cmov sse sse2 sse3 ssse3 sse41 sse42 popcnt aesni rdtscp xsave(xgetvb) osxsave pclmulqdq avx
|
||||
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
vendor intel
|
||||
mmx mmx2 cmov sse sse2 sse3 ssse3 sse41 sse42 popcnt aesni rdtscp xsave(xgetvb) osxsave pclmulqdq avx fma avx2 bmi1 bmi2 lzcnt prefetchw enh_rep rdrand adx rdseed smap sha f16c movbe avx512f avx512dq avx512_ifma avx512cd avx512bw avx512vl avx512_vbmi avx512_vbmi2 gfni vaes vpclmulqdq avx512_vnni avx512_bitalg avx512_vpopcntdq avx512_bf16 amx(tile) amx(int8) amx(bf16) avx_vnni avx512_fp16 waitpkg clflushopt cldemote clwb movdiri movdir64b uintr serialize
|
||||
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
vendor intel
|
||||
mmx mmx2 cmov sse sse2 sse3 ssse3 sse41 sse42 popcnt aesni rdtscp xsave(xgetvb) osxsave pclmulqdq avx fma avx2 bmi1 bmi2 lzcnt enh_rep rdrand adx rdseed smap sha f16c movbe gfni vaes vpclmulqdq avx_vnni waitpkg clflushopt cldemote clwb movdiri movdir64b uintr serialize avx_vnni_int8 avx_ne_convert avx_ifma cmpccxadd aeskle wide_kl keylocker keylocker_wide
|
||||
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
vendor intel
|
||||
mmx mmx2 cmov sse sse2 sse3 ssse3 sse41 sse42 popcnt aesni rdtscp xsave(xgetvb) osxsave pclmulqdq avx fma avx2 bmi1 bmi2 lzcnt prefetchw enh_rep rdrand adx rdseed smap sha f16c movbe avx512f avx512dq avx512_ifma avx512cd avx512bw avx512vl avx512_vbmi avx512_vbmi2 gfni vaes vpclmulqdq avx512_vnni avx512_bitalg avx512_vpopcntdq avx512_vp2intersect clflushopt clwb movdiri movdir64b aeskle wide_kl keylocker keylocker_wide
|
||||
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
vendor intel
|
||||
mmx mmx2 cmov sse sse2 sse3 ssse3 sse41 sse42 popcnt aesni rdtscp xsave(xgetvb) osxsave pclmulqdq enh_rep rdrand rdseed smap sha movbe gfni clflushopt cldemote clwb
|
||||
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
vendor intel
|
||||
mmx mmx2 cmov sse sse2 sse3 ssse3 sse41 sse42 popcnt aesni rdtscp pclmulqdq
|
||||
+236
@@ -0,0 +1,236 @@
|
||||
/*
|
||||
* Test program for Xbyak CPU Cache Topology API
|
||||
* Demonstrates the CpuTopology, CpuCache, LogicalCpu, and CpuMask classes
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include "xbyak/xbyak_util.h"
|
||||
|
||||
using namespace Xbyak::util;
|
||||
|
||||
void printSeparator()
|
||||
{
|
||||
printf("========================================\n");
|
||||
}
|
||||
|
||||
void printSystemTopology(const CpuTopology& cpuTopo)
|
||||
{
|
||||
printSeparator();
|
||||
printf("CpuTopology Class - System CPU topology\n");
|
||||
printSeparator();
|
||||
|
||||
printf("System Configuration:\n");
|
||||
printf(" Logical CPUs: %zu\n", cpuTopo.getLogicalCpuNum());
|
||||
printf(" Physical Cores: %zu\n", cpuTopo.getPhysicalCoreNum());
|
||||
printf(" Cache Line Size:%u bytes\n", cpuTopo.getLineSize());
|
||||
printf(" Hybrid System: %s\n", cpuTopo.isHybrid() ? "Yes (P-cores + E-cores)" : "No");
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void printLogicalCpuDetails(const CpuTopology& cpuTopo)
|
||||
{
|
||||
printSeparator();
|
||||
printf("LogicalCpu Class - Per-CPU topology information\n");
|
||||
printSeparator();
|
||||
|
||||
printf("Detailed CPU Topology (showing upto 32 Logical CPUs):\n");
|
||||
size_t maxCpusToPrint = 32;
|
||||
size_t numCpus = cpuTopo.getLogicalCpuNum();
|
||||
|
||||
for (size_t i = 0; i < numCpus && i < maxCpusToPrint; i++) {
|
||||
const LogicalCpu& logCpu = cpuTopo.getLogicalCpu(i);
|
||||
printf(" CPU %3zu: Core=%u Type=%s Siblings=", i, logCpu.coreId, getCoreTypeStr(logCpu.coreType));
|
||||
logCpu.getSiblings().put();
|
||||
}
|
||||
|
||||
if (numCpus > maxCpusToPrint) {
|
||||
printf(" ... (%zu more CPUs not shown)\n", numCpus - maxCpusToPrint);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
// Print cache size in appropriate unit (MB, KB, or B)
|
||||
void printCacheSize(uint32_t size)
|
||||
{
|
||||
if (size >= 1024 * 1024) {
|
||||
printf("%.2f MB", size / (1024.0 * 1024.0));
|
||||
} else if (size >= 1024) {
|
||||
printf("%.2f KB", size / 1024.0);
|
||||
} else {
|
||||
printf("%u B", size);
|
||||
}
|
||||
}
|
||||
|
||||
// Comparator to group CPUs by their cache topology
|
||||
struct CacheTopologyComparator {
|
||||
const CpuTopology& cpuTopo;
|
||||
|
||||
CacheTopologyComparator(const CpuTopology& topo) : cpuTopo(topo) {}
|
||||
|
||||
bool operator()(size_t cpu1, size_t cpu2) const {
|
||||
const LogicalCpu& logi1 = cpuTopo.getLogicalCpu(cpu1);
|
||||
const LogicalCpu& logi2 = cpuTopo.getLogicalCpu(cpu2);
|
||||
|
||||
// Sort by core type (E-core before P-core)
|
||||
if (logi1.coreType != logi2.coreType) return logi1.coreType > logi2.coreType;
|
||||
|
||||
// Compare cache properties
|
||||
for (int cType = L1i; cType < CACHE_TYPE_NUM; cType++) {
|
||||
const CpuCache& cache1 = cpuTopo.getCache(cpu1, (CacheType)cType);
|
||||
const CpuCache& cache2 = cpuTopo.getCache(cpu2, (CacheType)cType);
|
||||
|
||||
if (cache1.size != cache2.size) return cache1.size < cache2.size;
|
||||
if (cache1.associativity != cache2.associativity) return cache1.associativity < cache2.associativity;
|
||||
size_t num1 = cache1.getSharedCpuNum();
|
||||
size_t num2 = cache2.getSharedCpuNum();
|
||||
if (num1 != num2) return num1 < num2;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::map<size_t, CpuMask, CacheTopologyComparator> TopologyGroupMap;
|
||||
|
||||
// Group CPUs by their cache topology
|
||||
TopologyGroupMap groupCpusByTopology(const CpuTopology& cpuTopo)
|
||||
{
|
||||
TopologyGroupMap group((CacheTopologyComparator(cpuTopo)));
|
||||
|
||||
for (uint32_t cpuIdx = 0; cpuIdx < cpuTopo.getLogicalCpuNum(); cpuIdx++) {
|
||||
group[cpuIdx].append(cpuIdx);
|
||||
}
|
||||
return group;
|
||||
}
|
||||
|
||||
void printCacheHierarchy(const CpuTopology& cpuTopo, const TopologyGroupMap& group)
|
||||
{
|
||||
printSeparator();
|
||||
printf("CpuCache Class - Cache hierarchy and sharing\n");
|
||||
printSeparator();
|
||||
|
||||
// Print each unique cache topology group
|
||||
printf("Cache Hierarchy by Topology:\n");
|
||||
|
||||
for (TopologyGroupMap::const_iterator it = group.begin(); it != group.end(); ++it) {
|
||||
|
||||
const CpuMask& cpus = it->second;
|
||||
if (cpus.empty()) continue;
|
||||
|
||||
size_t firstCpu = cpus.get(0);
|
||||
const LogicalCpu& logCpu = cpuTopo.getLogicalCpu(firstCpu);
|
||||
|
||||
// Print core type and CPU list
|
||||
printf("\n%s CPUs ", getCoreTypeStr(logCpu.coreType));
|
||||
cpus.put();
|
||||
|
||||
// Print cache details for this topology
|
||||
for (int cType = 0; cType < CACHE_TYPE_NUM; cType++) {
|
||||
const CpuCache& cache = logCpu.cache[cType];
|
||||
if (cache.size > 0) {
|
||||
printf(" %s: ", getCacheTypeStr(cType));
|
||||
printCacheSize(cache.size);
|
||||
printf(" | %2u-way", cache.associativity);
|
||||
if (cache.isShared()) {
|
||||
printf(" | Shared by %zu CPUs", cache.getSharedCpuNum());
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void printCacheSharingDetails(const CpuTopology& cpuTopo, const TopologyGroupMap& group)
|
||||
{
|
||||
printSeparator();
|
||||
printf("Cache Sharing Analysis\n");
|
||||
printSeparator();
|
||||
|
||||
// Print cache sharing analysis for each unique topology
|
||||
for (TopologyGroupMap::const_iterator it = group.begin(); it != group.end(); ++it) {
|
||||
|
||||
const CpuMask& cpus = it->second;
|
||||
if (cpus.empty()) continue;
|
||||
|
||||
size_t firstCpu = cpus.get(0);
|
||||
const LogicalCpu& logCpu = cpuTopo.getLogicalCpu(firstCpu);
|
||||
|
||||
printf("%s Topology (representative CPU %zu):\n", getCoreTypeStr(logCpu.coreType), firstCpu);
|
||||
|
||||
// Analyze each cache level
|
||||
for (int cType = 0; cType < CACHE_TYPE_NUM; cType++) {
|
||||
const CpuCache& cache = logCpu.cache[cType];
|
||||
if (cache.size > 0) {
|
||||
printf(" %s Cache:\n", getCacheTypeStr(cType));
|
||||
printf(" Size: ");
|
||||
printCacheSize(cache.size);
|
||||
printf("\n");
|
||||
|
||||
if (cache.isShared()) {
|
||||
printf(" Shared by %zu CPUs: ", cache.getSharedCpuNum());
|
||||
cache.sharedCpuIndices.put();
|
||||
} else {
|
||||
printf(" Private (not shared)\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
void printSmallSample(const CpuTopology& cpuTopo)
|
||||
{
|
||||
printf("logical CPU num %zu %s\n", cpuTopo.getLogicalCpuNum(), cpuTopo.isHybrid() ? "hybrid" : "");
|
||||
if (!cpuTopo.isHybrid()) {
|
||||
cpuTopo.getLogicalCpu(0).put();
|
||||
return;
|
||||
}
|
||||
bool foundEcore = false;
|
||||
bool foundPcore = false;
|
||||
for (size_t i = 0; i < cpuTopo.getLogicalCpuNum(); i++) {
|
||||
const LogicalCpu& logi = cpuTopo.getLogicalCpu(i);
|
||||
if (!foundEcore && logi.coreType == Efficient) {
|
||||
logi.put();
|
||||
foundEcore = true;
|
||||
continue;
|
||||
}
|
||||
if (!foundPcore && logi.coreType == Performance) {
|
||||
logi.put();
|
||||
foundPcore = true;
|
||||
continue;
|
||||
}
|
||||
if (foundEcore && foundPcore) return;
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
try
|
||||
{
|
||||
printf("\n");
|
||||
printf("Xbyak CPU Cache Topology API Test\n");
|
||||
printf("==================================\n");
|
||||
printf("\n");
|
||||
|
||||
Cpu cpu;
|
||||
CpuTopology cpuTopo(cpu);
|
||||
|
||||
const TopologyGroupMap group = groupCpusByTopology(cpuTopo);
|
||||
|
||||
printSystemTopology(cpuTopo);
|
||||
printLogicalCpuDetails(cpuTopo);
|
||||
printCacheHierarchy(cpuTopo, group);
|
||||
printCacheSharingDetails(cpuTopo, group);
|
||||
|
||||
printSeparator();
|
||||
printf("All tests completed successfully!\n");
|
||||
printSeparator();
|
||||
printf("\n");
|
||||
printSeparator();
|
||||
printSmallSample(cpuTopo);
|
||||
} catch (std::exception& e) {
|
||||
printf("Error: %s\n", e.what());
|
||||
return 1;
|
||||
}
|
||||
Vendored
+5
@@ -0,0 +1,5 @@
|
||||
>>++++++++[->++++++++<]>>>>+++++++++[->++++++++++<]>[<<,[->+<<+<<+>>>]<<<[
|
||||
->>>+<<<]>>>>>[->+>>+<<<]>[<<[->+>>+<<<]>>>[-<<<+>>>]<<[[-]<->]>-]>>[-<<<+
|
||||
>>>]<<<<<<<[-<+<<+>>>]<[>>[-<+<<+>>>]<<<[->>>+<<<]>>[[-]>-<]<-]<<[->>>+<<<
|
||||
]>>>>><[[-]>++++++++++++++++++++++++++++++++>[[-]<------------------------
|
||||
-------->]<<]>>[-]<.>>]
|
||||
Vendored
+19
@@ -0,0 +1,19 @@
|
||||
++++++[->++++>>+>+>-<<<<<]>
|
||||
[<++++>>+++>++++>>+++>+++++>+++++>>>>>>++>>++<<<<<<<<<<<<<<-]
|
||||
<++++>+++>-->+++>->>--->++>>>+++++[->++>++<<]<<<<<<<<<<
|
||||
|
||||
[->
|
||||
-[>>>>>>>]>[<+++>.>.>>>>..>>>+<]<<<<<
|
||||
-[>>>>]>[<+++++>.>.>..>>>+<]>>>>
|
||||
|
||||
+<-[<<<]<[
|
||||
[-<<+>>]>>>+>+<<<<<<[->>+>+>-<<<<]<
|
||||
]>>
|
||||
|
||||
[[-]<]>[
|
||||
>>>[>.<<.<<<]<[.<<<<]>
|
||||
]
|
||||
|
||||
>.<<<<<<<<<<<
|
||||
]
|
||||
|
||||
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
>+++++++++[<++++++++>-]<.>+++++++[<++++>-]<+.+++++++..+++.[-]>++++++++[<++
|
||||
++>-]<.>+++++++++++[<+++++>-]<.>++++++++[<+++>-]<.+++.------.--------.[-]>
|
||||
++++++++[<++++>-]<+.[-]++++++++++.
|
||||
Vendored
+127
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
sample of move(reg, LABEL);, L(LABEL), putL(LABEL);
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <xbyak/xbyak.h>
|
||||
|
||||
const int expectTbl[] = {
|
||||
5, 9, 12
|
||||
};
|
||||
|
||||
struct Code : Xbyak::CodeGenerator {
|
||||
explicit Code(int mode, size_t size, void *p)
|
||||
: Xbyak::CodeGenerator(size, p)
|
||||
{
|
||||
inLocalLabel();
|
||||
#ifdef XBYAK64
|
||||
const Xbyak::Reg64& a = rax;
|
||||
const Xbyak::Reg64& c = rcx;
|
||||
#ifdef XBYAK64_WIN
|
||||
mov(rax, rcx);
|
||||
#else
|
||||
mov(rax, rdi);
|
||||
#endif
|
||||
#else
|
||||
const Xbyak::Reg32& a = eax;
|
||||
const Xbyak::Reg32& c = ecx;
|
||||
mov(a, ptr [esp + 4]);
|
||||
#endif
|
||||
|
||||
switch (mode) {
|
||||
case 0:
|
||||
mov(c, ".jmp_table");
|
||||
lea(c, ptr [c + a * 8]);
|
||||
jmp(c);
|
||||
align(8);
|
||||
L(".jmp_table");
|
||||
mov(a, expectTbl[0]);
|
||||
ret();
|
||||
align(8);
|
||||
mov(a, expectTbl[1]);
|
||||
ret();
|
||||
align(8);
|
||||
mov(a, expectTbl[2]);
|
||||
ret();
|
||||
break;
|
||||
|
||||
case 1:
|
||||
/*
|
||||
the label for putL is defined when called
|
||||
*/
|
||||
mov(c, ".jmp_table");
|
||||
jmp(ptr [c + a * (int)sizeof(size_t)]);
|
||||
L(".label1");
|
||||
mov(a, expectTbl[0]);
|
||||
jmp(".end");
|
||||
L(".label2");
|
||||
mov(a, expectTbl[1]);
|
||||
jmp(".end");
|
||||
L(".label3");
|
||||
mov(a, expectTbl[2]);
|
||||
jmp(".end");
|
||||
L(".end");
|
||||
ret();
|
||||
ud2();
|
||||
|
||||
align(8);
|
||||
L(".jmp_table");
|
||||
putL(".label1");
|
||||
putL(".label2");
|
||||
putL(".label3");
|
||||
break;
|
||||
|
||||
case 2:
|
||||
/*
|
||||
the label for putL is not defined when called
|
||||
*/
|
||||
jmp(".in");
|
||||
ud2();
|
||||
align(8);
|
||||
L(".jmp_table");
|
||||
putL(".label1");
|
||||
putL(".label2");
|
||||
putL(".label3");
|
||||
L(".in");
|
||||
mov(c, ".jmp_table");
|
||||
jmp(ptr [c + a * (int)sizeof(size_t)]);
|
||||
L(".label1");
|
||||
mov(a, expectTbl[0]);
|
||||
jmp(".end");
|
||||
L(".label2");
|
||||
mov(a, expectTbl[1]);
|
||||
jmp(".end");
|
||||
L(".label3");
|
||||
mov(a, expectTbl[2]);
|
||||
jmp(".end");
|
||||
L(".end");
|
||||
ret();
|
||||
break;
|
||||
}
|
||||
outLocalLabel();
|
||||
}
|
||||
};
|
||||
|
||||
int main()
|
||||
try
|
||||
{
|
||||
for (int mode = 0; mode < 3; mode++) {
|
||||
printf("mode=%d\n", mode);
|
||||
for (int grow = 0; grow < 2; grow++) {
|
||||
printf("auto grow=%s\n", grow ? "on" : "off");
|
||||
Code c(mode, grow ? 30 : 4096, grow ? Xbyak::AutoGrow : 0);
|
||||
int (*f)(int) = c.getCode<int (*)(int)>();
|
||||
c.ready();
|
||||
for (int i = 0; i < 3; i++) {
|
||||
const int a = expectTbl[i];
|
||||
const int b = f(i);
|
||||
if (a != b) {
|
||||
printf("ERR i=%d, a=%d, b=%d\n", i, a, b);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
puts("ok");
|
||||
} catch (std::exception& e) {
|
||||
printf("ERR %s\n", e.what());
|
||||
}
|
||||
Vendored
+41
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
a sample to use MmapAllocator with an user-defined name
|
||||
cat /proc/`pidof ./memfd`/maps
|
||||
|
||||
7fca70b44000-7fca70b4a000 rw-p 00000000 00:00 0
|
||||
7fca70b67000-7fca70b68000 rwxs 00000000 00:05 19960170 /memfd:xyz (deleted)
|
||||
7fca70b68000-7fca70b69000 rwxs 00000000 00:05 19960169 /memfd:abc (deleted)
|
||||
7fca70b69000-7fca70b6a000 r--p 00029000 103:03 19136541 /lib/x86_64-linux-gnu/ld-2.27.so
|
||||
7fca70b6a000-7fca70b6b000 rw-p 0002a000 103:03 19136541 /lib/x86_64-linux-gnu/ld-2.27.so
|
||||
*/
|
||||
#define XBYAK_USE_MEMFD
|
||||
#include <xbyak/xbyak.h>
|
||||
#include <fstream>
|
||||
|
||||
class Code : Xbyak::MmapAllocator, public Xbyak::CodeGenerator {
|
||||
public:
|
||||
Code(const char *name, int v)
|
||||
: Xbyak::MmapAllocator(name)
|
||||
, Xbyak::CodeGenerator(4096, nullptr, this /* specify external MmapAllocator */)
|
||||
{
|
||||
mov(eax, v);
|
||||
ret();
|
||||
}
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
printf("pid=%d\n", getpid());
|
||||
Code c1("Xbyak::abc", 123);
|
||||
Code c2("Xbyak::xyz", 456);
|
||||
printf("c1 %d\n", c1.getCode<int (*)()>()());
|
||||
printf("c2 %d\n", c2.getCode<int (*)()>()());
|
||||
std::ifstream ifs("/proc/self/maps", std::ios::binary);
|
||||
if (ifs) {
|
||||
std::string line;
|
||||
while (std::getline(ifs, line)) {
|
||||
printf("%s\n", line.c_str());
|
||||
}
|
||||
}
|
||||
getchar();
|
||||
}
|
||||
Vendored
+110
@@ -0,0 +1,110 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <memory.h>
|
||||
#include <xbyak/xbyak.h>
|
||||
|
||||
struct A {
|
||||
int x_;
|
||||
int y_;
|
||||
A() : x_(3), y_(5) {}
|
||||
int func(int a, int b, int c, int d, int e) const { return x_ + y_ + a + b + c + d + e; }
|
||||
};
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable : 4510 4512 4610)
|
||||
#endif
|
||||
|
||||
struct Code : public Xbyak::CodeGenerator {
|
||||
Code()
|
||||
{
|
||||
using namespace Xbyak;
|
||||
|
||||
int RET_ADJ = 0;
|
||||
#ifdef XBYAK32
|
||||
#ifdef _WIN32
|
||||
const int PARA_ADJ = 0;
|
||||
RET_ADJ = 5 * 4;
|
||||
#else
|
||||
const int PARA_ADJ = 4;
|
||||
mov(ecx, ptr [esp + 4]);
|
||||
#endif
|
||||
#endif
|
||||
const struct {
|
||||
#ifdef XBYAK32
|
||||
const Reg32& self;
|
||||
#else
|
||||
const Reg64& self;
|
||||
#endif
|
||||
const Operand& a;
|
||||
const Operand& b;
|
||||
const Operand& c;
|
||||
const Operand& d;
|
||||
const Operand& e;
|
||||
} para = {
|
||||
#if defined(XBYAK64_WIN)
|
||||
rcx,
|
||||
edx,
|
||||
r8d,
|
||||
r9d,
|
||||
ptr [rsp + 8 * 5],
|
||||
ptr [rsp + 8 * 6],
|
||||
#elif defined(XBYAK64_GCC)
|
||||
rdi,
|
||||
esi,
|
||||
edx,
|
||||
ecx,
|
||||
r8d,
|
||||
r9d,
|
||||
#else
|
||||
ecx,
|
||||
ptr [esp + 4 + PARA_ADJ],
|
||||
ptr [esp + 8 + PARA_ADJ],
|
||||
ptr [esp + 12 + PARA_ADJ],
|
||||
ptr [esp + 16 + PARA_ADJ],
|
||||
ptr [esp + 20 + PARA_ADJ],
|
||||
#endif
|
||||
};
|
||||
mov(eax, ptr [para.self]);
|
||||
add(eax, ptr [para.self + 4]);
|
||||
add(eax, para.a);
|
||||
add(eax, para.b);
|
||||
add(eax, para.c);
|
||||
add(eax, para.d);
|
||||
add(eax, para.e);
|
||||
ret(RET_ADJ);
|
||||
}
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
#ifdef XBYAK64
|
||||
printf("64bit");
|
||||
#else
|
||||
printf("32bit");
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
puts(" win");
|
||||
#else
|
||||
puts(" linux");
|
||||
#endif
|
||||
try {
|
||||
Code code;
|
||||
int (A::*p)(int, int, int, int, int) const = 0;
|
||||
const void *addr = code.getCode<void*>();
|
||||
memcpy(&p, &addr, sizeof(void*));
|
||||
for (int i = 0; i < 10; i++) {
|
||||
A a;
|
||||
int t1, t2, t3, t4, t5, x, y;
|
||||
a.x_ = rand(); a.y_ = rand();
|
||||
t1 = rand(); t2 = rand(); t3 = rand();
|
||||
t4 = rand(); t5 = rand();
|
||||
x = a.func(t1, t2, t3, t4, t5);
|
||||
y = (a.*p)(t1, t2, t3, t4, t5);
|
||||
printf("%c %d, %d\n", x == y ? 'o' : 'x', x, y);
|
||||
}
|
||||
} catch (std::exception& e) {
|
||||
printf("err=%s\n", e.what());
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+25
@@ -0,0 +1,25 @@
|
||||
#include <stdio.h>
|
||||
#include <xbyak/xbyak.h>
|
||||
|
||||
struct Code : Xbyak::CodeGenerator {
|
||||
Code(bool nf) {
|
||||
xor_(eax, eax); // CF = 0
|
||||
mov(eax, -1);
|
||||
if (nf) {
|
||||
puts("no flags (with T_nf)");
|
||||
add(eax|T_nf, eax, 1); // does not change CF
|
||||
} else {
|
||||
puts("change flags (without T_nf)");
|
||||
add(eax, eax, 1); // CF = 1
|
||||
}
|
||||
adc(eax, 0); // eax = CF ? 1 : 0
|
||||
ret();
|
||||
}
|
||||
};
|
||||
|
||||
int main() {
|
||||
for (int i = 0; i < 2; i++) {
|
||||
Code c(i);
|
||||
printf("i=%d ret=%d\n", i, c.getCode<int(*)()>()());
|
||||
}
|
||||
}
|
||||
Vendored
+90
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
How to profile JIT-code with perf or VTune
|
||||
sudo perf record ./profiler 1
|
||||
amplxe-cl -collect hotspots -result-dir r001hs -quiet ./profiler-vtune 2
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <xbyak/xbyak_util.h>
|
||||
|
||||
const int N = 3000000;
|
||||
struct Code : public Xbyak::CodeGenerator {
|
||||
Code()
|
||||
{
|
||||
mov(eax, N);
|
||||
Xbyak::Label lp = L();
|
||||
for (int i = 0; i < 10; i++) {
|
||||
sub(eax, 1);
|
||||
}
|
||||
jg(lp);
|
||||
mov(eax, 1);
|
||||
ret();
|
||||
}
|
||||
};
|
||||
|
||||
struct Code2 : public Xbyak::CodeGenerator {
|
||||
Code2()
|
||||
{
|
||||
mov(eax, N);
|
||||
Xbyak::Label lp = L();
|
||||
for (int i = 0; i < 10; i++) {
|
||||
xorps(xm0, xm0);
|
||||
}
|
||||
sub(eax, 1);
|
||||
jg(lp);
|
||||
mov(eax, 1);
|
||||
ret();
|
||||
}
|
||||
};
|
||||
|
||||
double s1(int n)
|
||||
{
|
||||
double r = 0;
|
||||
for (int i = 0; i < n; i++) {
|
||||
r += 1.0 / (i + 1);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
double s2(int n)
|
||||
{
|
||||
double r = 0;
|
||||
for (int i = 0; i < n; i++) {
|
||||
r += 1.0 / (i * i + 1) + 2.0 / (i + 3);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int mode = argc == 1 ? 0 : atoi(argv[1]);
|
||||
Code c;
|
||||
Code2 c2;
|
||||
int (*f)() = (int (*)())c.getCode();
|
||||
int (*g)() = (int (*)())c2.getCode();
|
||||
|
||||
printf("f:%p, %d\n", (const void*)f, (int)c.getSize());
|
||||
printf("g:%p, %d\n", (const void*)g, (int)c2.getSize());
|
||||
Xbyak::util::Profiler prof;
|
||||
printf("mode=%d\n", mode);
|
||||
prof.init(mode);
|
||||
prof.set("f", (const void*)f, c.getSize());
|
||||
prof.set("g", (const void*)g, c2.getSize());
|
||||
|
||||
double sum = 0;
|
||||
for (int i = 0; i < 20000; i++) {
|
||||
sum += s1(i);
|
||||
sum += s2(i);
|
||||
}
|
||||
printf("sum=%f\n", sum);
|
||||
for (int i = 0; i < 2000; i++) {
|
||||
sum += f();
|
||||
}
|
||||
printf("f=%f\n", sum);
|
||||
for (int i = 0; i < 2000; i++) {
|
||||
sum += g();
|
||||
}
|
||||
printf("g=%f\n", sum);
|
||||
puts("end");
|
||||
}
|
||||
Vendored
+69
@@ -0,0 +1,69 @@
|
||||
#include <xbyak/xbyak.h>
|
||||
|
||||
struct Code1 : Xbyak::CodeGenerator {
|
||||
Code1()
|
||||
: Xbyak::CodeGenerator(4096, Xbyak::DontSetProtectRWE)
|
||||
{
|
||||
mov(eax, 123);
|
||||
ret();
|
||||
}
|
||||
void update()
|
||||
{
|
||||
db(0);
|
||||
}
|
||||
};
|
||||
|
||||
void test1(bool updateCode)
|
||||
{
|
||||
Code1 c;
|
||||
c.setProtectModeRE();
|
||||
if (updateCode) c.update(); // segmentation fault
|
||||
int (*f)() = c.getCode<int (*)()>();
|
||||
printf("f=%d\n", f());
|
||||
|
||||
c.setProtectModeRW();
|
||||
c.update();
|
||||
puts("ok");
|
||||
}
|
||||
|
||||
struct Code2 : Xbyak::CodeGenerator {
|
||||
Code2()
|
||||
: Xbyak::CodeGenerator(4096, Xbyak::AutoGrow)
|
||||
{
|
||||
mov(eax, 123);
|
||||
ret();
|
||||
}
|
||||
void update()
|
||||
{
|
||||
db(0);
|
||||
}
|
||||
};
|
||||
|
||||
void test2(bool updateCode)
|
||||
{
|
||||
Code2 c;
|
||||
c.readyRE();
|
||||
if (updateCode) c.update(); // segmentation fault
|
||||
int (*f)() = c.getCode<int (*)()>();
|
||||
printf("f=%d\n", f());
|
||||
|
||||
c.setProtectModeRW();
|
||||
c.update();
|
||||
puts("ok");
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "%s <testNum> [update]\n", argv[0]);
|
||||
return 0;
|
||||
}
|
||||
bool update = argc == 3;
|
||||
int n = atoi(argv[1]);
|
||||
printf("n=%d update=%d\n", n, update);
|
||||
switch (n) {
|
||||
case 1: test1(update); break;
|
||||
case 2: test2(update); break;
|
||||
default: fprintf(stderr, "no test %d\n", n); break;
|
||||
}
|
||||
}
|
||||
Vendored
+225
@@ -0,0 +1,225 @@
|
||||
/*
|
||||
@author herumi
|
||||
|
||||
JPEG quantize sample
|
||||
This program generates a quantization routine by using fast division algorithm in run-time.
|
||||
|
||||
time(sec)
|
||||
quality 1(high) 10 50 100(low)
|
||||
VC2005 8.0 8.0 8.0 8.0
|
||||
Xbyak 1.6 0.8 0.5 0.5
|
||||
|
||||
|
||||
; generated code at q = 1
|
||||
push esi
|
||||
push edi
|
||||
mov edi,dword ptr [esp+0Ch]
|
||||
mov esi,dword ptr [esp+10h]
|
||||
mov eax,dword ptr [esi]
|
||||
shr eax,4
|
||||
mov dword ptr [edi],eax
|
||||
mov eax,dword ptr [esi+4]
|
||||
mov edx,0BA2E8BA3h
|
||||
mul eax,edx
|
||||
shr edx,3
|
||||
...
|
||||
|
||||
; generated code at q = 100
|
||||
push esi
|
||||
push edi
|
||||
mov edi,dword ptr [esp+0Ch]
|
||||
mov esi,dword ptr [esp+10h]
|
||||
mov eax,dword ptr [esi]
|
||||
mov dword ptr [edi],eax
|
||||
mov eax,dword ptr [esi+4]
|
||||
mov dword ptr [edi+4],eax
|
||||
mov eax,dword ptr [esi+8]
|
||||
mov dword ptr [edi+8],eax
|
||||
mov eax,dword ptr [esi+0Ch]
|
||||
...
|
||||
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include "xbyak/xbyak.h"
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable : 4996) // scanf
|
||||
#endif
|
||||
|
||||
const int N = 64;
|
||||
|
||||
class Quantize : public Xbyak::CodeGenerator {
|
||||
static int ilog2(int x)
|
||||
{
|
||||
int shift = 0;
|
||||
while ((1 << shift) <= x) shift++;
|
||||
return shift - 1;
|
||||
}
|
||||
public:
|
||||
/*
|
||||
input : esi
|
||||
output : eax = [esi+offset] / dividend
|
||||
destroy : edx
|
||||
*/
|
||||
void udiv(uint32_t dividend, int offset)
|
||||
{
|
||||
mov(eax, ptr[esi + offset]);
|
||||
|
||||
/* dividend = odd x 2^exponent */
|
||||
int exponent = 0, odd = dividend;
|
||||
while ((odd & 1) == 0) {
|
||||
odd >>= 1; exponent++;
|
||||
}
|
||||
|
||||
if (odd == 1) { // trivial case
|
||||
if (exponent) {
|
||||
shr(eax, exponent);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t mLow, mHigh;
|
||||
int len = ilog2(odd) + 1;
|
||||
{
|
||||
uint64_t roundUp = uint64_t(1) << (32 + len);
|
||||
uint64_t k = roundUp / (0xFFFFFFFFL - (0xFFFFFFFFL % odd));
|
||||
mLow = roundUp / odd;
|
||||
mHigh = (roundUp + k) / odd;
|
||||
}
|
||||
|
||||
while (((mLow >> 1) < (mHigh >> 1)) && (len > 0)) {
|
||||
mLow >>= 1; mHigh >>= 1; len--;
|
||||
}
|
||||
|
||||
uint64_t m; int a;
|
||||
if ((mHigh >> 32) == 0) {
|
||||
m = mHigh; a = 0;
|
||||
} else {
|
||||
len = ilog2(odd);
|
||||
uint64_t roundDown = uint64_t(1) << (32 + len);
|
||||
mLow = roundDown / odd;
|
||||
int r = (int)(roundDown % odd);
|
||||
m = (r <= (odd >> 1)) ? mLow : mLow + 1;
|
||||
a = 1;
|
||||
}
|
||||
while ((m & 1) == 0) {
|
||||
m >>= 1; len--;
|
||||
}
|
||||
len += exponent;
|
||||
|
||||
mov(edx, int(m));
|
||||
mul(edx);
|
||||
if (a) {
|
||||
add(eax, int(m));
|
||||
adc(edx, 0);
|
||||
}
|
||||
if (len) {
|
||||
shr(edx, len);
|
||||
}
|
||||
mov(eax, edx);
|
||||
}
|
||||
/*
|
||||
quantize(uint32_t dest[64], const uint32_t src[64]);
|
||||
*/
|
||||
Quantize(const uint32_t qTbl[64])
|
||||
{
|
||||
push(esi);
|
||||
push(edi);
|
||||
const int P_ = 4 * 2;
|
||||
mov(edi, ptr [esp+P_+4]); // dest
|
||||
mov(esi, ptr [esp+P_+8]); // src
|
||||
for (int i = 0; i < N; i++) {
|
||||
udiv(qTbl[i], i * 4);
|
||||
mov(ptr[edi+i*4], eax);
|
||||
}
|
||||
pop(edi);
|
||||
pop(esi);
|
||||
ret();
|
||||
}
|
||||
};
|
||||
|
||||
void quantize(uint32_t dest[64], const uint32_t src[64], const uint32_t qTbl[64])
|
||||
{
|
||||
for (int i = 0; i < N; i++) {
|
||||
dest[i] = src[i] / qTbl[i];
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef XBYAK64
|
||||
int main()
|
||||
{
|
||||
puts("not implemented for 64bit");
|
||||
return 1;
|
||||
}
|
||||
#else
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int q;
|
||||
if (argc > 1) {
|
||||
q = atoi(argv[1]);
|
||||
} else {
|
||||
printf("input quantize=");
|
||||
if (scanf("%d", &q) != 1) {
|
||||
fprintf(stderr, "bad number\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
printf("q=%d\n", q);
|
||||
uint32_t qTbl[] = {
|
||||
16, 11, 10, 16, 24, 40, 51, 61,
|
||||
12, 12, 14, 19, 26, 58, 60, 55,
|
||||
14, 13, 16, 24, 40, 57, 69, 56,
|
||||
14, 17, 22, 29, 51, 87, 80, 62,
|
||||
18, 22, 37, 56, 68, 109, 103, 77,
|
||||
24, 35, 55, 64, 81, 104, 113, 92,
|
||||
49, 64, 78, 87, 103, 121, 120, 101,
|
||||
72, 92, 95, 98, 112, 100, 103, 99
|
||||
};
|
||||
|
||||
for (int i = 0; i < N; i++) {
|
||||
qTbl[i] /= q;
|
||||
if (qTbl[i] == 0) qTbl[i] = 1;
|
||||
}
|
||||
|
||||
try {
|
||||
uint32_t src[N];
|
||||
uint32_t dest[N];
|
||||
uint32_t dest2[N];
|
||||
for (int i = 0; i < N; i++) {
|
||||
src[i] = rand() % 2048;
|
||||
}
|
||||
|
||||
Quantize jit(qTbl);
|
||||
//printf("jit size=%d, ptr=%p\n", jit.getSize(), jit.getCode());
|
||||
void (*quantize2)(uint32_t*, const uint32_t*, const uint32_t *) = jit.getCode<void (*)(uint32_t*, const uint32_t*, const uint32_t *)>();
|
||||
|
||||
quantize(dest, src, qTbl);
|
||||
quantize2(dest2, src, qTbl);
|
||||
for (int i = 0; i < N; i++) {
|
||||
if (dest[i] != dest2[i]) {
|
||||
printf("err[%d] %u %u\n", i, dest[i], dest2[i]);
|
||||
}
|
||||
}
|
||||
|
||||
const int count = 10000000;
|
||||
int begin;
|
||||
|
||||
begin = clock();
|
||||
for (int i = 0; i < count; i++) {
|
||||
quantize(dest, src, qTbl);
|
||||
}
|
||||
printf("time=%.1fsec\n", (clock() - begin) / double(CLOCKS_PER_SEC));
|
||||
|
||||
begin = clock();
|
||||
for (int i = 0; i < count; i++) {
|
||||
quantize2(dest, src, qTbl);
|
||||
}
|
||||
printf("time=%.1fsec\n", (clock() - begin) / double(CLOCKS_PER_SEC));
|
||||
} catch (std::exception& e) {
|
||||
printf("ERR:%s\n", e.what());
|
||||
} catch (...) {
|
||||
printf("unknown error\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
Vendored
+214
@@ -0,0 +1,214 @@
|
||||
# Xbyak Sample Programs
|
||||
|
||||
This directory contains sample programs demonstrating various features of the Xbyak JIT assembler library.
|
||||
|
||||
## Sample Programs
|
||||
|
||||
- **test0.cpp** (test/test64) - Basic Xbyak functionality tests
|
||||
- **bf.cpp** (bf/bf64) - Brainf*ck interpreter using JIT compilation
|
||||
- **calc.cpp** (calc/calc64) - Calculator using Boost.Spirit parser (requires Boost)
|
||||
- **memfunc.cpp** (memfunc/memfunc64) - Member function JIT compilation example
|
||||
- **test_util.cpp** (test_util/test_util64) - CPU feature detection and cache topology
|
||||
- **cputopology.cpp** (cputopology) - CPU cache topology API demonstration (CpuTopology, CpuCache, LogicalCpu, CpuMask)
|
||||
- **jmp_table.cpp** (jmp_table/jmp_table64) - Jump table demonstration
|
||||
- **zero_upper.cpp** (zero_upper) - AVX zero upper demonstration
|
||||
- **ccmp.cpp** (ccmp) - Conditional compare instructions
|
||||
- **no_flags.cpp** (no_flags) - Instructions without flag modifications
|
||||
- **quantize.cpp** (quantize) - Quantization example
|
||||
- **toyvm.cpp** (toyvm) - Simple toy virtual machine with JIT
|
||||
- **profiler.cpp** (profiler) - Performance profiling example
|
||||
- **static_buf.cpp** (static_buf/static_buf64) - Static buffer example (Linux only)
|
||||
- **memfd.cpp** (memfd) - Memory file descriptor example (Linux only)
|
||||
|
||||
## Building with CMake (Recommended)
|
||||
|
||||
CMake provides cross-platform build support for Windows, Linux, and macOS.
|
||||
|
||||
### Basic Build (64-bit targets)
|
||||
|
||||
```bash
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
cmake --build . --config Release
|
||||
```
|
||||
|
||||
### Clean build
|
||||
```bash
|
||||
#clean build
|
||||
cmake --build . --target clean
|
||||
#clean then build (Recommended)
|
||||
cmake --build . --clean-first --config Release
|
||||
```
|
||||
|
||||
### Clean Fresh start (most thorough)
|
||||
```bash
|
||||
# Delete build directory and reconfigure
|
||||
rm -rf build
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
cmake --build . --config Release
|
||||
```
|
||||
|
||||
### Running Examples
|
||||
|
||||
**On Windows:**
|
||||
```bash
|
||||
.\bin\Release\test_util64.exe
|
||||
.\bin\Release\test64.exe
|
||||
.\bin\Release\bf64.exe
|
||||
```
|
||||
|
||||
**On Linux/macOS:**
|
||||
```bash
|
||||
./bin/test_util64
|
||||
./bin/test64
|
||||
./bin/bf64
|
||||
```
|
||||
|
||||
### Building Specific Targets
|
||||
|
||||
```bash
|
||||
# Build only test_util64
|
||||
cmake --build . --config Release --target test_util64
|
||||
|
||||
# Build only profiler
|
||||
cmake --build . --config Release --target profiler
|
||||
```
|
||||
|
||||
### Optional 32-bit Targets (Linux only)
|
||||
|
||||
To build 32-bit targets on a 64-bit Linux system, you need multilib support:
|
||||
|
||||
```bash
|
||||
# Install multilib (Ubuntu/Debian)
|
||||
sudo apt-get install gcc-multilib g++-multilib
|
||||
|
||||
# Configure with 32-bit targets enabled
|
||||
cmake -DBUILD_32BIT_TARGETS=ON ..
|
||||
cmake --build . --config Release
|
||||
```
|
||||
|
||||
This will build additional 32-bit versions: `test`, `bf`, `toyvm`, `test_util`, `memfunc`, `static_buf`, `jmp_table`, and `calc` (if Boost is available).
|
||||
|
||||
### Boost Support
|
||||
|
||||
The `calc` and `calc64` targets require Boost libraries. CMake will automatically detect Boost and build these targets if available.
|
||||
|
||||
**Installing Boost:**
|
||||
- **Windows**: Download from https://www.boost.org/ or use vcpkg
|
||||
- **Linux**: `sudo apt-get install libboost-all-dev`
|
||||
- **macOS**: `brew install boost`
|
||||
|
||||
### CMake Options
|
||||
|
||||
- `BUILD_32BIT_TARGETS=ON/OFF` - Enable 32-bit target builds (default: OFF, Linux 64-bit only)
|
||||
- `BUILD_PROFILER_VTUNE=ON/OFF` - Build profiler with VTune support (default: OFF, requires Intel VTune)
|
||||
|
||||
```bash
|
||||
# Example with options
|
||||
cmake -DBUILD_32BIT_TARGETS=ON -DBUILD_PROFILER_VTUNE=ON ..
|
||||
```
|
||||
|
||||
## Building with Make (Linux/macOS)
|
||||
|
||||
```bash
|
||||
# Build all targets
|
||||
make
|
||||
|
||||
# Build specific target
|
||||
make test64
|
||||
make bf64
|
||||
make test_util64
|
||||
|
||||
# Clean
|
||||
make clean
|
||||
```
|
||||
|
||||
The Makefile automatically detects:
|
||||
- System architecture (32-bit vs 64-bit)
|
||||
- Boost availability
|
||||
- Platform (Linux vs macOS)
|
||||
|
||||
## Building with Visual Studio (Windows)
|
||||
|
||||
Individual Visual Studio project files are provided for quick builds on Windows.
|
||||
|
||||
### Using Visual Studio IDE
|
||||
|
||||
1. Open the desired `.vcxproj` file in Visual Studio
|
||||
2. Select configuration (Debug/Release) and platform (x86/x64)
|
||||
3. Build → Build Solution (or press F7)
|
||||
4. Run the executable from the output directory
|
||||
|
||||
**Available project files:**
|
||||
- `bf.vcxproj` - Brainf*ck interpreter
|
||||
- `calc.vcxproj` - Calculator (requires Boost)
|
||||
- `calc2.vcxproj` - Alternative calculator (requires Boost)
|
||||
- `quantize.vcxproj` - Quantization example
|
||||
- `test0.vcxproj` - Basic tests
|
||||
- `test_util.vcxproj` - CPU utility
|
||||
- `toyvm.vcxproj` - Toy VM
|
||||
|
||||
### Using MSBuild (Command Line)
|
||||
|
||||
```powershell
|
||||
# Build with MSBuild
|
||||
msbuild test0.vcxproj /p:Configuration=Release /p:Platform=x64
|
||||
|
||||
# Or use the solution file if available
|
||||
msbuild xbyak_samples.sln /p:Configuration=Release
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### CMake: "Cannot find Boost"
|
||||
If Boost is installed but not detected:
|
||||
```bash
|
||||
cmake -DBOOST_ROOT=/path/to/boost ..
|
||||
```
|
||||
|
||||
### Linux: "cannot find -lstdc++"
|
||||
Install the C++ standard library:
|
||||
```bash
|
||||
sudo apt-get install libstdc++-dev
|
||||
```
|
||||
|
||||
### Linux: "undefined reference to pthread"
|
||||
This should be handled automatically by CMake. If issues persist, ensure pthreads is available:
|
||||
```bash
|
||||
sudo apt-get install libpthread-stubs0-dev
|
||||
```
|
||||
|
||||
### Windows: Static buffer and memfd targets fail
|
||||
These targets are Linux-specific and use Linux memory mapping APIs. They are automatically excluded on Windows.
|
||||
|
||||
## Notes
|
||||
|
||||
- **64-bit vs 32-bit**: On 64-bit systems, the `*64` suffix indicates 64-bit builds. 32-bit builds have no suffix.
|
||||
- **Platform-specific**: Some samples (like `static_buf` and `memfd`) only work on Linux
|
||||
- **Boost dependency**: The `calc` samples require Boost.Spirit and are only built if Boost is detected
|
||||
- **Warning flags**: The build reads compiler warnings from `../test/CFLAGS_WARN.cfg` (GCC/Clang only)
|
||||
|
||||
## Running Brainf*ck Examples
|
||||
|
||||
Several Brainf*ck programs are included:
|
||||
|
||||
```bash
|
||||
# On Windows
|
||||
.\build\bin\Release\bf64.exe echo.bf
|
||||
.build\bin\Release\bf64.exe hello.bf
|
||||
.build\bin\Release\bf64.exe fizzbuzz.bf
|
||||
|
||||
# On Linux
|
||||
./build/bin/bf64 echo.bf
|
||||
./build/bin/bf64 hello.bf
|
||||
./build/bin/bf64 fizzbuzz.bf
|
||||
```
|
||||
|
||||
## Additional Resources
|
||||
|
||||
- [Xbyak Documentation](https://github.com/herumi/xbyak)
|
||||
- [Main README](../readme.md)
|
||||
- [Usage Guide](../doc/usage.md)
|
||||
Vendored
+28
@@ -0,0 +1,28 @@
|
||||
#include <xbyak/xbyak_util.h>
|
||||
|
||||
#ifdef XBYAK32
|
||||
#error "this sample is for only 64-bit mode"
|
||||
#endif
|
||||
|
||||
struct Code : public Xbyak::CodeGenerator {
|
||||
Code()
|
||||
{
|
||||
// see xbyak/sample/sf_test.cpp for how to use other parameter
|
||||
Xbyak::util::StackFrame sf(this, 3);
|
||||
mov(rax, sf.p[0]);
|
||||
add(rax, sf.p[1]);
|
||||
add(rax, sf.p[2]);
|
||||
}
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
Code c;
|
||||
int (*f)(int, int, int) = c.getCode<int(*) (int, int, int)>();
|
||||
int ret = f(3, 5, 2);
|
||||
if (ret == 3 + 5 + 2) {
|
||||
puts("ok");
|
||||
} else {
|
||||
puts("ng");
|
||||
}
|
||||
}
|
||||
Vendored
+44
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
sample to use static memory
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include "xbyak/xbyak.h"
|
||||
|
||||
MIE_ALIGN(4096) char buf[4096];
|
||||
|
||||
struct Code : Xbyak::CodeGenerator {
|
||||
Code()
|
||||
: Xbyak::CodeGenerator(sizeof(buf), buf)
|
||||
{
|
||||
puts("generate");
|
||||
printf("ptr=%p, %p\n", getCode(), buf);
|
||||
#ifdef XBYAK32
|
||||
mov(eax, ptr [esp + 4]);
|
||||
add(eax, ptr [esp + 8]);
|
||||
#elif defined(XBYAK64_WIN)
|
||||
lea(rax, ptr [rcx + rdx]);
|
||||
#else
|
||||
lea(rax, ptr [rdi + rsi]);
|
||||
#endif
|
||||
ret();
|
||||
Xbyak::CodeArray::protect(buf, sizeof(buf), Xbyak::CodeArray::PROTECT_RE);
|
||||
}
|
||||
~Code()
|
||||
{
|
||||
Xbyak::CodeArray::protect(buf, sizeof(buf), Xbyak::CodeArray::PROTECT_RW);
|
||||
}
|
||||
} s_code;
|
||||
|
||||
inline int add(int a, int b)
|
||||
{
|
||||
return reinterpret_cast<int (*)(int, int)>(buf)(a, b);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int sum = 0;
|
||||
for (int i = 0; i < 10; i++) {
|
||||
sum += add(i, 5);
|
||||
}
|
||||
printf("sum=%d\n", sum);
|
||||
}
|
||||
Vendored
+189
@@ -0,0 +1,189 @@
|
||||
#if defined(_MSC_VER) && (_MSC_VER <= 1200)
|
||||
#pragma warning(disable:4514)
|
||||
#pragma warning(disable:4786)
|
||||
#endif
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1900)
|
||||
#pragma warning(disable:4456)
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "xbyak/xbyak.h"
|
||||
|
||||
class Sample : public Xbyak::CodeGenerator {
|
||||
void operator=(const Sample&);
|
||||
public:
|
||||
Sample(void *userPtr = 0, size_t size = Xbyak::DEFAULT_MAX_CODE_SIZE) : Xbyak::CodeGenerator(size, userPtr)
|
||||
{
|
||||
inLocalLabel(); // use local label for multiple instance
|
||||
#ifdef XBYAK32
|
||||
mov(ecx, ptr [esp + 4]); // n
|
||||
#elif defined(XBYAK64_GCC)
|
||||
mov(ecx, edi); // n
|
||||
#else
|
||||
// n = ecx
|
||||
#endif
|
||||
xor_(eax, eax); // sum
|
||||
test(ecx, ecx);
|
||||
jz(".exit");
|
||||
xor_(edx, edx); // i
|
||||
L(".lp");
|
||||
add(eax, edx);
|
||||
inc(edx);
|
||||
|
||||
cmp(edx, ecx);
|
||||
jbe(".lp"); // jmp to previous @@
|
||||
L(".exit"); // <B>
|
||||
ret();
|
||||
outLocalLabel(); // end of local label
|
||||
}
|
||||
};
|
||||
|
||||
class AddFunc : public Xbyak::CodeGenerator {
|
||||
void operator=(const AddFunc&);
|
||||
public:
|
||||
AddFunc(int y)
|
||||
{
|
||||
#ifdef XBYAK32
|
||||
mov(eax, ptr [esp + 4]);
|
||||
add(eax, y);
|
||||
#elif defined(XBYAK64_WIN)
|
||||
lea(rax, ptr [rcx + y]);
|
||||
#else
|
||||
lea(eax, ptr [edi + y]);
|
||||
#endif
|
||||
ret();
|
||||
}
|
||||
int (*get() const)(int) { return getCode<int(*)(int)>(); }
|
||||
};
|
||||
|
||||
class CallAtoi : public Xbyak::CodeGenerator {
|
||||
void operator=(const CallAtoi&);
|
||||
public:
|
||||
CallAtoi()
|
||||
{
|
||||
#ifdef XBYAK64
|
||||
#ifdef XBYAK64_WIN
|
||||
sub(rsp, 32); // return-address is destroied if 64bit debug mode
|
||||
#endif
|
||||
mov(rax, (size_t)atoi);
|
||||
call(rax);
|
||||
#ifdef XBYAK64_WIN
|
||||
add(rsp, 32);
|
||||
#endif
|
||||
#else
|
||||
mov(eax, ptr [esp + 4]);
|
||||
push(eax);
|
||||
#ifdef XBYAK_VARIADIC_TEMPLATE
|
||||
call(atoi);
|
||||
#else
|
||||
call(reinterpret_cast<const void*>(atoi));
|
||||
#endif
|
||||
add(esp, 4);
|
||||
#endif
|
||||
ret();
|
||||
}
|
||||
int (*get() const)(const char *) { return getCode<int (*)(const char *)>(); }
|
||||
};
|
||||
|
||||
class JmpAtoi : public Xbyak::CodeGenerator {
|
||||
void operator=(const JmpAtoi&);
|
||||
public:
|
||||
JmpAtoi()
|
||||
{
|
||||
/* already pushed "456" */
|
||||
#ifdef XBYAK64
|
||||
mov(rax, (size_t)atoi);
|
||||
jmp(rax);
|
||||
#else
|
||||
jmp(reinterpret_cast<const void*>(atoi));
|
||||
#endif
|
||||
}
|
||||
int (*get() const)(const char *) { return getCode<int (*)(const char *)>(); }
|
||||
};
|
||||
|
||||
struct Reset : public Xbyak::CodeGenerator {
|
||||
void init(int n)
|
||||
{
|
||||
xor_(eax, eax);
|
||||
mov(ecx, n);
|
||||
test(ecx, ecx);
|
||||
jnz("@f");
|
||||
ret();
|
||||
L("@@");
|
||||
for (int i = 0; i < 10 - n; i++) {
|
||||
add(eax, ecx);
|
||||
}
|
||||
sub(ecx, 1);
|
||||
jnz("@b");
|
||||
ret();
|
||||
}
|
||||
};
|
||||
|
||||
void testReset()
|
||||
{
|
||||
puts("testReset");
|
||||
Reset code;
|
||||
int (*f)(int) = code.getCode<int(*)(int)>();
|
||||
for (int i = 0; i < 10; i++) {
|
||||
code.init(i);
|
||||
int v = f(i);
|
||||
printf("%d %d\n", i, v);
|
||||
code.reset();
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
try {
|
||||
Sample s;
|
||||
printf("Xbyak version=%s\n", s.getVersionString());
|
||||
#ifdef XBYAK64_GCC
|
||||
puts("64bit mode(gcc)");
|
||||
#elif defined(XBYAK64_WIN)
|
||||
puts("64bit mode(win)");
|
||||
#else
|
||||
puts("32bit");
|
||||
#endif
|
||||
int (*func)(int) = s.getCode<int (*)(int)>();
|
||||
for (int i = 0; i <= 10; i++) {
|
||||
printf("0 + ... + %d = %d\n", i, func(i));
|
||||
}
|
||||
for (int i = 0; i < 10; i++) {
|
||||
AddFunc a(i);
|
||||
int (*add)(int) = a.get();
|
||||
int y = add(i);
|
||||
printf("%d + %d = %d\n", i, i, y);
|
||||
}
|
||||
CallAtoi c;
|
||||
printf("call atoi(\"123\") = %d\n", c.get()("123"));
|
||||
JmpAtoi j;
|
||||
printf("jmp atoi(\"456\") = %d\n", j.get()("456"));
|
||||
{
|
||||
// use memory allocated by user
|
||||
using namespace Xbyak;
|
||||
const size_t codeSize = 4096;
|
||||
uint8_t buf[codeSize + 16];
|
||||
uint8_t *p = CodeArray::getAlignedAddress(buf);
|
||||
Sample s(p, codeSize);
|
||||
if (!CodeArray::protect(p, codeSize, CodeArray::PROTECT_RWE)) {
|
||||
fprintf(stderr, "can't protect\n");
|
||||
return 1;
|
||||
}
|
||||
int (*func)(int) = s.getCode<int (*)(int)>();
|
||||
const uint8_t *funcp = reinterpret_cast<const uint8_t*>(func);
|
||||
if (funcp != p) {
|
||||
fprintf(stderr, "internal error %p %p\n", p, funcp);
|
||||
return 1;
|
||||
}
|
||||
printf("0 + ... + %d = %d\n", 100, func(100));
|
||||
CodeArray::protect(p, codeSize, CodeArray::PROTECT_RW);
|
||||
}
|
||||
puts("OK");
|
||||
testReset();
|
||||
} catch (std::exception& e) {
|
||||
printf("ERR:%s\n", e.what());
|
||||
} catch (...) {
|
||||
printf("unknown error\n");
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+170
@@ -0,0 +1,170 @@
|
||||
#include <stdio.h>
|
||||
#include "xbyak/xbyak_util.h"
|
||||
|
||||
#define NUM_OF_ARRAY(x) (sizeof(x) / sizeof(x[0]))
|
||||
|
||||
struct PopCountTest : public Xbyak::CodeGenerator {
|
||||
PopCountTest(int n)
|
||||
: Xbyak::CodeGenerator(4096, Xbyak::DontSetProtectRWE)
|
||||
{
|
||||
mov(eax, n);
|
||||
popcnt(eax, eax);
|
||||
ret();
|
||||
}
|
||||
};
|
||||
|
||||
void putCPUinfo(bool onlyCpuidFeature)
|
||||
{
|
||||
using namespace Xbyak::util;
|
||||
Cpu cpu;
|
||||
printf("vendor %s\n", cpu.has(Cpu::tINTEL) ? "intel" : "amd");
|
||||
static const struct {
|
||||
Cpu::Type type;
|
||||
const char *str;
|
||||
} tbl[] = {
|
||||
{ Cpu::tMMX, "mmx" },
|
||||
{ Cpu::tMMX2, "mmx2" },
|
||||
{ Cpu::tCMOV, "cmov" },
|
||||
{ Cpu::tSSE, "sse" },
|
||||
{ Cpu::tSSE2, "sse2" },
|
||||
{ Cpu::tSSE3, "sse3" },
|
||||
{ Cpu::tSSSE3, "ssse3" },
|
||||
{ Cpu::tSSE41, "sse41" },
|
||||
{ Cpu::tSSE42, "sse42" },
|
||||
{ Cpu::tSSE4a, "sse4a" },
|
||||
{ Cpu::tPOPCNT, "popcnt" },
|
||||
{ Cpu::t3DN, "3dn" },
|
||||
{ Cpu::tE3DN, "e3dn" },
|
||||
{ Cpu::tAESNI, "aesni" },
|
||||
{ Cpu::tRDTSCP, "rdtscp" },
|
||||
{ Cpu::tXSAVE, "xsave(xgetvb)" },
|
||||
{ Cpu::tOSXSAVE, "osxsave" },
|
||||
{ Cpu::tPCLMULQDQ, "pclmulqdq" },
|
||||
{ Cpu::tAVX, "avx" },
|
||||
{ Cpu::tFMA, "fma" },
|
||||
{ Cpu::tAVX2, "avx2" },
|
||||
{ Cpu::tBMI1, "bmi1" },
|
||||
{ Cpu::tBMI2, "bmi2" },
|
||||
{ Cpu::tLZCNT, "lzcnt" },
|
||||
{ Cpu::tPREFETCHW, "prefetchw" },
|
||||
{ Cpu::tENHANCED_REP, "enh_rep" },
|
||||
{ Cpu::tRDRAND, "rdrand" },
|
||||
{ Cpu::tADX, "adx" },
|
||||
{ Cpu::tRDSEED, "rdseed" },
|
||||
{ Cpu::tSMAP, "smap" },
|
||||
{ Cpu::tHLE, "hle" },
|
||||
{ Cpu::tRTM, "rtm" },
|
||||
{ Cpu::tMPX, "mpx" },
|
||||
{ Cpu::tSHA, "sha" },
|
||||
{ Cpu::tF16C, "f16c" },
|
||||
{ Cpu::tMOVBE, "movbe" },
|
||||
{ Cpu::tAVX512F, "avx512f" },
|
||||
{ Cpu::tAVX512DQ, "avx512dq" },
|
||||
{ Cpu::tAVX512IFMA, "avx512_ifma" },
|
||||
{ Cpu::tAVX512CD, "avx512cd" },
|
||||
{ Cpu::tAVX512BW, "avx512bw" },
|
||||
{ Cpu::tAVX512VL, "avx512vl" },
|
||||
{ Cpu::tAVX512VBMI, "avx512_vbmi" },
|
||||
|
||||
{ Cpu::tAVX512_VBMI2, "avx512_vbmi2" },
|
||||
{ Cpu::tGFNI, "gfni" },
|
||||
{ Cpu::tVAES, "vaes" },
|
||||
{ Cpu::tVPCLMULQDQ, "vpclmulqdq" },
|
||||
{ Cpu::tAVX512_VNNI, "avx512_vnni" },
|
||||
{ Cpu::tAVX512_BITALG, "avx512_bitalg" },
|
||||
{ Cpu::tAVX512_VPOPCNTDQ, "avx512_vpopcntdq" },
|
||||
{ Cpu::tAVX512_BF16, "avx512_bf16" },
|
||||
{ Cpu::tAVX512_VP2INTERSECT, "avx512_vp2intersect" },
|
||||
{ Cpu::tAMX_TILE, "amx(tile)" },
|
||||
{ Cpu::tAMX_INT8, "amx(int8)" },
|
||||
{ Cpu::tAMX_BF16, "amx(bf16)" },
|
||||
{ Cpu::tAVX_VNNI, "avx_vnni" },
|
||||
{ Cpu::tAVX512_FP16, "avx512_fp16" },
|
||||
{ Cpu::tWAITPKG, "waitpkg" },
|
||||
{ Cpu::tCLFLUSHOPT, "clflushopt" },
|
||||
{ Cpu::tCLDEMOTE, "cldemote" },
|
||||
{ Cpu::tCLWB, "clwb" },
|
||||
{ Cpu::tMOVDIRI, "movdiri" },
|
||||
{ Cpu::tMOVDIR64B, "movdir64b" },
|
||||
{ Cpu::tUINTR, "uintr" },
|
||||
{ Cpu::tSERIALIZE, "serialize" },
|
||||
{ Cpu::tCLZERO, "clzero" },
|
||||
{ Cpu::tAMX_FP16, "amx_fp16" },
|
||||
{ Cpu::tAVX_VNNI_INT8, "avx_vnni_int8" },
|
||||
{ Cpu::tAVX_NE_CONVERT, "avx_ne_convert" },
|
||||
{ Cpu::tAVX_IFMA, "avx_ifma" },
|
||||
{ Cpu::tRAO_INT, "rao-int" },
|
||||
{ Cpu::tCMPCCXADD, "cmpccxadd" },
|
||||
{ Cpu::tPREFETCHITI, "prefetchiti" },
|
||||
{ Cpu::tSHA512, "sha512" },
|
||||
{ Cpu::tSM3, "sm3" },
|
||||
{ Cpu::tSM4, "sm4" },
|
||||
{ Cpu::tAVX_VNNI_INT16, "avx_vnni_int16" },
|
||||
{ Cpu::tAPX_F, "apx_f" },
|
||||
{ Cpu::tAVX10, "avx10" },
|
||||
{ Cpu::tAESKLE, "aeskle" },
|
||||
{ Cpu::tWIDE_KL, "wide_kl" },
|
||||
{ Cpu::tKEYLOCKER, "keylocker" },
|
||||
{ Cpu::tKEYLOCKER_WIDE, "keylocker_wide" },
|
||||
{ Cpu::tTSXLDTRK, "tsxldtrk" },
|
||||
{ Cpu::tAMX_FP8, "amx_fp8" },
|
||||
{ Cpu::tAMX_TRANSPOSE, "amx_transpose" },
|
||||
{ Cpu::tAMX_TF32, "amx_tf32" },
|
||||
{ Cpu::tAMX_AVX512, "amx_avx512" },
|
||||
{ Cpu::tAMX_MOVRS, "amx_movrs" },
|
||||
{ Cpu::tMOVRS, "movrs" },
|
||||
{ Cpu::tHYBRID, "hybrid" },
|
||||
{ Cpu::tAMX_COMPLEX, "amx_complex" },
|
||||
};
|
||||
for (size_t i = 0; i < NUM_OF_ARRAY(tbl); i++) {
|
||||
if (cpu.has(tbl[i].type)) printf(" %s", tbl[i].str);
|
||||
}
|
||||
printf("\n");
|
||||
if (onlyCpuidFeature) return;
|
||||
if (cpu.has(Cpu::tAVX10)) {
|
||||
printf("AVX10 version %d\n", cpu.getAVX10version());
|
||||
}
|
||||
if (cpu.has(Cpu::tPOPCNT)) {
|
||||
const int n = 0x12345678; // bitcount = 13
|
||||
const int ok = 13;
|
||||
PopCountTest code(n);
|
||||
code.setProtectModeRE();
|
||||
int (*f)() = code.getCode<int (*)()>();
|
||||
int r = f();
|
||||
if (r == ok) {
|
||||
puts("popcnt ok");
|
||||
} else {
|
||||
printf("popcnt ng %d %d\n", r, ok);
|
||||
}
|
||||
code.setProtectModeRW();
|
||||
}
|
||||
/*
|
||||
displayFamily displayModel
|
||||
Opteron 2376 10 4
|
||||
Core2 Duo T7100 6 F
|
||||
Core i3-2120T 6 2A
|
||||
Core i7-2600 6 2A
|
||||
Xeon X5650 6 2C
|
||||
Core i7-3517 6 3A
|
||||
Core i7-3930K 6 2D
|
||||
*/
|
||||
cpu.putFamily();
|
||||
for (unsigned int i = 0; i < cpu.getDataCacheLevels(); i++) {
|
||||
printf("cache level=%u data cache size=%u cores sharing data cache=%u\n", i, cpu.getDataCacheSize(i), cpu.getCoresSharingDataCache(i));
|
||||
}
|
||||
printf("SmtLevel =%u\n", cpu.getNumCores(Xbyak::util::SmtLevel));
|
||||
printf("CoreLevel=%u\n", cpu.getNumCores(Xbyak::util::CoreLevel));
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
bool onlyCpuidFeature = argc == 2 && strcmp(argv[1], "-cpuid") == 0;
|
||||
if (!onlyCpuidFeature) {
|
||||
#ifdef XBYAK32
|
||||
puts("32bit");
|
||||
#else
|
||||
puts("64bit");
|
||||
#endif
|
||||
}
|
||||
putCPUinfo(onlyCpuidFeature);
|
||||
}
|
||||
Vendored
+383
@@ -0,0 +1,383 @@
|
||||
/*
|
||||
toy vm
|
||||
register A, B : 32bit
|
||||
PC : program counter
|
||||
|
||||
mem_ 4byte x 65536
|
||||
|
||||
all instructions are fixed at 4 bytes.
|
||||
all immediate values are 16-bit.
|
||||
|
||||
R = A or B
|
||||
vldiR, imm ; R = imm
|
||||
vldR, idx ; R = mem_[idx]
|
||||
vstR, idx ; mem_[idx] = R
|
||||
vaddiR, imm ; R += imm
|
||||
vsubiR, imm ; R -= imm
|
||||
vaddR, idx ; R += mem_[idx]
|
||||
vsubR, idx ; R -= mem_[idx]
|
||||
vputR ; print R
|
||||
vjnzR, offset; if (R != 0) then jmp(PC += offset(signed))
|
||||
*/
|
||||
#if defined(_MSC_VER) && (_MSC_VER <= 1200)
|
||||
#pragma warning(disable:4514)
|
||||
#pragma warning(disable:4786)
|
||||
#endif
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" // wrong detection in recompile()
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <memory.h>
|
||||
#include <vector>
|
||||
#include "xbyak/xbyak.h"
|
||||
#include "xbyak/xbyak_util.h"
|
||||
#define NUM_OF_ARRAY(x) (sizeof(x) / sizeof(x[0]))
|
||||
|
||||
#ifdef XBYAK64
|
||||
#error "only 32bit"
|
||||
#endif
|
||||
|
||||
using namespace Xbyak;
|
||||
|
||||
class ToyVm : public Xbyak::CodeGenerator {
|
||||
typedef std::vector<uint32_t> Buffer;
|
||||
public:
|
||||
enum Reg {
|
||||
A, B
|
||||
};
|
||||
enum Code {
|
||||
LD, LDI, ST, ADD, ADDI, SUB, SUBI, PUT, JNZ,
|
||||
END_OF_CODE
|
||||
};
|
||||
ToyVm()
|
||||
: mark_(0)
|
||||
{
|
||||
::memset(mem_, 0, sizeof(mem_));
|
||||
}
|
||||
void vldi(Reg r, uint16_t imm) { encode(LDI, r, imm); }
|
||||
void vld(Reg r, uint16_t idx) { encode(LD, r, idx); }
|
||||
void vst(Reg r, uint16_t idx) { encode(ST, r, idx); }
|
||||
void vadd(Reg r, uint16_t idx) { encode(ADD, r, idx); }
|
||||
void vaddi(Reg r, uint16_t imm) { encode(ADDI, r, imm); }
|
||||
void vsub(Reg r, uint16_t idx) { encode(SUB, r, idx); }
|
||||
void vsubi(Reg r, uint16_t imm) { encode(SUBI, r, imm); }
|
||||
void vjnz(Reg r, int offset) { encode(JNZ, r, static_cast<uint16_t>(offset)); }
|
||||
void vput(Reg r) { encode(PUT, r); }
|
||||
void setMark()
|
||||
{
|
||||
mark_ = (int)code_.size();
|
||||
}
|
||||
int getMarkOffset()
|
||||
{
|
||||
return mark_ - (int)code_.size() - 1;
|
||||
}
|
||||
void run()
|
||||
{
|
||||
bool debug = false;//true;
|
||||
uint32_t reg[2] = { 0, 0 };
|
||||
const size_t end = code_.size();
|
||||
uint32_t pc = 0;
|
||||
for (;;) {
|
||||
uint32_t x = code_[pc];
|
||||
uint32_t code, r, imm;
|
||||
decode(code, r, imm, x);
|
||||
if (debug) {
|
||||
printf("---\n");
|
||||
printf("A %08x B %08x\n", reg[0], reg[1]);
|
||||
printf("mem_[] = %08x %08x %08x\n", mem_[0], mem_[1], mem_[2]);
|
||||
printf("pc=%4d, code=%02x, r=%d, imm=%04x\n", pc, code, r, imm);
|
||||
}
|
||||
switch (code) {
|
||||
case LDI:
|
||||
reg[r] = imm;
|
||||
break;
|
||||
case LD:
|
||||
reg[r] = mem_[imm];
|
||||
break;
|
||||
case ST:
|
||||
mem_[imm] = reg[r];
|
||||
break;
|
||||
case ADD:
|
||||
reg[r] += mem_[imm];
|
||||
break;
|
||||
case ADDI:
|
||||
reg[r] += imm;
|
||||
break;
|
||||
case SUB:
|
||||
reg[r] -= mem_[imm];
|
||||
break;
|
||||
case SUBI:
|
||||
reg[r] -= imm;
|
||||
break;
|
||||
case PUT:
|
||||
printf("%c %8u(0x%08x)\n", 'A' + r, reg[r], reg[r]);
|
||||
break;
|
||||
case JNZ:
|
||||
if (reg[r] != 0) pc += static_cast<signed short>(imm);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
pc++;
|
||||
if (pc >= end) break;
|
||||
} // for (;;)
|
||||
}
|
||||
void recompile()
|
||||
{
|
||||
using namespace Xbyak;
|
||||
/*
|
||||
esi : A
|
||||
edi : B
|
||||
ebx : mem_
|
||||
for speed up
|
||||
mem_[0] : eax
|
||||
mem_[1] : ecx
|
||||
mem_[2] : edx
|
||||
*/
|
||||
push(ebx);
|
||||
push(esi);
|
||||
push(edi);
|
||||
|
||||
const Reg32 reg[2] = { esi, edi };
|
||||
const Reg32 mem(ebx);
|
||||
|
||||
const Reg32 memTbl[] = { eax, ecx, edx };
|
||||
const size_t memTblNum = NUM_OF_ARRAY(memTbl);
|
||||
for (size_t i = 0; i < memTblNum; i++) xor_(memTbl[i], memTbl[i]);
|
||||
|
||||
xor_(esi, esi);
|
||||
xor_(edi, edi);
|
||||
mov(mem, (size_t)mem_);
|
||||
const size_t end = code_.size();
|
||||
uint32_t pc = 0;
|
||||
uint32_t labelNum = 0;
|
||||
for (;;) {
|
||||
uint32_t x = code_[pc];
|
||||
uint32_t code, r, imm;
|
||||
decode(code, r, imm, x);
|
||||
L(Label::toStr(labelNum++));
|
||||
switch (code) {
|
||||
case LDI:
|
||||
mov(reg[r], imm);
|
||||
break;
|
||||
case LD:
|
||||
if (imm < memTblNum) {
|
||||
mov(reg[r], memTbl[imm]);
|
||||
} else {
|
||||
mov(reg[r], ptr[mem + imm * 4]);
|
||||
}
|
||||
break;
|
||||
case ST:
|
||||
if (imm < memTblNum) {
|
||||
mov(memTbl[imm], reg[r]);
|
||||
} else {
|
||||
mov(ptr [mem + imm * 4], reg[r]);
|
||||
}
|
||||
break;
|
||||
case ADD:
|
||||
if (imm < memTblNum) {
|
||||
add(reg[r], memTbl[imm]);
|
||||
} else {
|
||||
add(reg[r], ptr [mem + imm * 4]);
|
||||
}
|
||||
break;
|
||||
case ADDI:
|
||||
add(reg[r], imm);
|
||||
break;
|
||||
case SUB:
|
||||
if (imm < memTblNum) {
|
||||
sub(reg[r], memTbl[imm]);
|
||||
} else {
|
||||
sub(reg[r], ptr [mem + imm * 4]);
|
||||
}
|
||||
break;
|
||||
case SUBI:
|
||||
sub(reg[r], imm);
|
||||
break;
|
||||
case PUT:
|
||||
{
|
||||
static const char *str = "%c %8d(0x%08x)\n";
|
||||
push(eax);
|
||||
push(edx);
|
||||
push(ecx);
|
||||
push(reg[r]);
|
||||
push(reg[r]);
|
||||
push('A' + r);
|
||||
push((int)str);
|
||||
call(reinterpret_cast<const void*>(printf));
|
||||
add(esp, 4 * 4);
|
||||
pop(ecx);
|
||||
pop(edx);
|
||||
pop(eax);
|
||||
}
|
||||
break;
|
||||
case JNZ:
|
||||
test(reg[r], reg[r]);
|
||||
jnz(Label::toStr(labelNum + static_cast<signed short>(imm)));
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
pc++;
|
||||
if (pc >= end) break;
|
||||
} // for (;;)
|
||||
|
||||
pop(edi);
|
||||
pop(esi);
|
||||
pop(ebx);
|
||||
ret();
|
||||
}
|
||||
private:
|
||||
uint32_t mem_[65536];
|
||||
Buffer code_;
|
||||
int mark_;
|
||||
void decode(uint32_t& code, uint32_t& r, uint32_t& imm, uint32_t x)
|
||||
{
|
||||
code = x >> 24;
|
||||
r = (x >> 16) & 0xff;
|
||||
imm = x & 0xffff;
|
||||
}
|
||||
void encode(Code code, Reg r, uint16_t imm = 0)
|
||||
{
|
||||
uint32_t x = (code << 24) | (r << 16) | imm;
|
||||
code_.push_back(x);
|
||||
}
|
||||
};
|
||||
|
||||
class Fib : public ToyVm {
|
||||
public:
|
||||
Fib(int n)
|
||||
{
|
||||
if (n >= 65536) {
|
||||
fprintf(stderr, "current version support only imm16\n");
|
||||
return;
|
||||
}
|
||||
/*
|
||||
A : c
|
||||
B : temporary
|
||||
mem_[0] : p
|
||||
mem_[1] : t
|
||||
mem_[2] : n
|
||||
*/
|
||||
vldi(A, 1); // c
|
||||
vst(A, 0); // p(1)
|
||||
vldi(B, static_cast<uint16_t>(n));
|
||||
vst(B, 2); // n
|
||||
// lp
|
||||
setMark();
|
||||
vst(A, 1); // t = c
|
||||
vadd(A, 0); // c += p
|
||||
vld(B, 1);
|
||||
vst(B, 0); // p = t
|
||||
// vput(A);
|
||||
vld(B, 2);
|
||||
vsubi(B, 1);
|
||||
vst(B, 2); // n--
|
||||
vjnz(B, getMarkOffset());
|
||||
vput(A);
|
||||
}
|
||||
void runByJIT()
|
||||
{
|
||||
getCode<void (*)()>();
|
||||
}
|
||||
};
|
||||
|
||||
void fibC(uint32_t n)
|
||||
{
|
||||
uint32_t p, c, t;
|
||||
p = 1;
|
||||
c = 1;
|
||||
lp:
|
||||
t = c;
|
||||
c += p;
|
||||
p = t;
|
||||
n--;
|
||||
if (n != 0) goto lp;
|
||||
printf("c=%u(0x%08x)\n", c, c);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
try {
|
||||
const int n = 10000;
|
||||
Fib fib(n);
|
||||
|
||||
fib.recompile();
|
||||
|
||||
{
|
||||
Xbyak::util::Clock clk;
|
||||
clk.begin();
|
||||
fib.run();
|
||||
clk.end();
|
||||
printf("vm %.2fKclk\n", clk.getClock() * 1e-3);
|
||||
}
|
||||
|
||||
{
|
||||
Xbyak::util::Clock clk;
|
||||
clk.begin();
|
||||
fib.runByJIT();
|
||||
clk.end();
|
||||
printf("jit %.2fKclk\n", clk.getClock() * 1e-3);
|
||||
}
|
||||
|
||||
{
|
||||
Xbyak::util::Clock clk;
|
||||
clk.begin();
|
||||
fibC(n);
|
||||
clk.end();
|
||||
printf("native C %.2fKclk\n", clk.getClock() * 1e-3);
|
||||
}
|
||||
} catch (std::exception& e) {
|
||||
printf("ERR:%s\n", e.what());
|
||||
} catch (...) {
|
||||
printf("unknown error\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
the code generated by Xbyak
|
||||
push ebx
|
||||
push esi
|
||||
push edi
|
||||
xor eax,eax
|
||||
xor ecx,ecx
|
||||
xor edx,edx
|
||||
xor esi,esi
|
||||
xor edi,edi
|
||||
mov ebx,0EFF58h
|
||||
mov esi,1
|
||||
mov eax,esi
|
||||
mov edi,2710h
|
||||
mov edx,edi
|
||||
.lp:
|
||||
mov ecx,esi
|
||||
add esi,eax
|
||||
mov edi,ecx
|
||||
mov eax,edi
|
||||
mov edi,edx
|
||||
sub edi,1
|
||||
mov edx,edi
|
||||
test edi,edi
|
||||
jne .lp
|
||||
push eax
|
||||
push edx
|
||||
push ecx
|
||||
push esi
|
||||
push esi
|
||||
push 41h
|
||||
push 42C434h
|
||||
call printf (409342h)
|
||||
add esp,10h
|
||||
pop ecx
|
||||
pop edx
|
||||
pop eax
|
||||
pop edi
|
||||
pop esi
|
||||
pop ebx
|
||||
ret
|
||||
*/
|
||||
Vendored
+48
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
An example of T_zu (zero upper) flag
|
||||
> g++ zero_upper.cpp -I ../xbyak
|
||||
> sde -future -- ./a.out
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <xbyak/xbyak.h>
|
||||
|
||||
using namespace Xbyak;
|
||||
|
||||
struct Code : Xbyak::CodeGenerator {
|
||||
Code(int mode)
|
||||
{
|
||||
mov(eax, 0x12345678);
|
||||
cmp(eax, eax); // ZF=1
|
||||
switch (mode) {
|
||||
case 0: // imul
|
||||
puts("imul");
|
||||
imul(ax,ax, 0x1234);
|
||||
break;
|
||||
case 1: // imul+zu
|
||||
puts("imul+zu");
|
||||
imul(ax|T_zu, ax, 0x1234);
|
||||
break;
|
||||
case 2: // setz
|
||||
puts("setz");
|
||||
setz(al);
|
||||
break;
|
||||
case 3: // setz+zu
|
||||
puts("setz+zu");
|
||||
setz(al|T_zu);
|
||||
break;
|
||||
}
|
||||
ret();
|
||||
}
|
||||
};
|
||||
|
||||
int main()
|
||||
try
|
||||
{
|
||||
for (int mode = 0; mode < 4; mode++) {
|
||||
Code c(mode);
|
||||
auto f = c.getCode<int (*)()>();
|
||||
printf("ret=%08x\n", f());
|
||||
}
|
||||
} catch (std::exception& e) {
|
||||
printf("ERR %s\n", e.what());
|
||||
}
|
||||
Reference in New Issue
Block a user