diff options
Diffstat (limited to '3rdparty/asmjit/test/asmjit_test_x86_asm.cpp')
-rw-r--r-- | 3rdparty/asmjit/test/asmjit_test_x86_asm.cpp | 195 |
1 files changed, 195 insertions, 0 deletions
diff --git a/3rdparty/asmjit/test/asmjit_test_x86_asm.cpp b/3rdparty/asmjit/test/asmjit_test_x86_asm.cpp new file mode 100644 index 00000000000..a01185d80f9 --- /dev/null +++ b/3rdparty/asmjit/test/asmjit_test_x86_asm.cpp @@ -0,0 +1,195 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#include <asmjit/x86.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +using namespace asmjit; + +// Signature of the generated function. +typedef void (*SumIntsFunc)(int* dst, const int* a, const int* b); + +// This function works with both x86::Assembler and x86::Builder. It shows how +// `x86::Emitter` can be used to make your code more generic. +static void makeRawFunc(x86::Emitter* emitter) noexcept { + // Decide which registers will be mapped to function arguments. Try changing + // registers of `dst`, `src_a`, and `src_b` and see what happens in function's + // prolog and epilog. + x86::Gp dst = emitter->zax(); + x86::Gp src_a = emitter->zcx(); + x86::Gp src_b = emitter->zdx(); + + // Decide which vector registers to use. We use these to keep the code generic, + // you can switch to any other registers when needed. + x86::Xmm vec0 = x86::xmm0; + x86::Xmm vec1 = x86::xmm1; + + // Create and initialize `FuncDetail` and `FuncFrame`. + FuncDetail func; + func.init(FuncSignatureT<void, int*, const int*, const int*>(CallConv::kIdHost)); + + FuncFrame frame; + frame.init(func); + + // Make XMM0 and XMM1 dirty. VEC group includes XMM|YMM|ZMM registers. + frame.addDirtyRegs(x86::xmm0, x86::xmm1); + + FuncArgsAssignment args(&func); // Create arguments assignment context. + args.assignAll(dst, src_a, src_b); // Assign our registers to arguments. + args.updateFuncFrame(frame); // Reflect our args in FuncFrame. + frame.finalize(); + + // Emit prolog and allocate arguments to registers. + emitter->emitProlog(frame); + emitter->emitArgsAssignment(frame, args); + + emitter->movdqu(vec0, x86::ptr(src_a)); // Load 4 ints from [src_a] to XMM0. + emitter->movdqu(vec1, x86::ptr(src_b)); // Load 4 ints from [src_b] to XMM1. + + emitter->paddd(vec0, vec1); // Add 4 ints in XMM1 to XMM0. + emitter->movdqu(x86::ptr(dst), vec0); // Store the result to [dst]. + + // Emit epilog and return. + emitter->emitEpilog(frame); +} + +#ifndef ASMJIT_NO_COMPILER +// This function works with x86::Compiler, provided for comparison. +static void makeCompiledFunc(x86::Compiler* cc) noexcept { + x86::Gp dst = cc->newIntPtr(); + x86::Gp src_a = cc->newIntPtr(); + x86::Gp src_b = cc->newIntPtr(); + + x86::Xmm vec0 = cc->newXmm(); + x86::Xmm vec1 = cc->newXmm(); + + cc->addFunc(FuncSignatureT<void, int*, const int*, const int*>(CallConv::kIdHost)); + cc->setArg(0, dst); + cc->setArg(1, src_a); + cc->setArg(2, src_b); + + cc->movdqu(vec0, x86::ptr(src_a)); + cc->movdqu(vec1, x86::ptr(src_b)); + cc->paddd(vec0, vec1); + cc->movdqu(x86::ptr(dst), vec0); + cc->endFunc(); +} +#endif + +static uint32_t testFunc(JitRuntime& rt, uint32_t emitterType) noexcept { +#ifndef ASMJIT_NO_LOGGING + FileLogger logger(stdout); +#endif + + CodeHolder code; + code.init(rt.codeInfo()); + +#ifndef ASMJIT_NO_LOGGING + code.setLogger(&logger); +#endif + + Error err = kErrorOk; + switch (emitterType) { + case BaseEmitter::kTypeAssembler: { + printf("Using x86::Assembler:\n"); + x86::Assembler a(&code); + makeRawFunc(a.as<x86::Emitter>()); + break; + } + +#ifndef ASMJIT_NO_BUILDER + case BaseEmitter::kTypeBuilder: { + printf("Using x86::Builder:\n"); + x86::Builder cb(&code); + makeRawFunc(cb.as<x86::Emitter>()); + + err = cb.finalize(); + if (err) { + printf("x86::Builder::finalize() failed: %s\n", DebugUtils::errorAsString(err)); + return 1; + } + break; + } +#endif + +#ifndef ASMJIT_NO_COMPILER + case BaseEmitter::kTypeCompiler: { + printf("Using x86::Compiler:\n"); + x86::Compiler cc(&code); + makeCompiledFunc(&cc); + + err = cc.finalize(); + if (err) { + printf("x86::Compiler::finalize() failed: %s\n", DebugUtils::errorAsString(err)); + return 1; + } + break; + } +#endif + } + + // Add the code generated to the runtime. + SumIntsFunc fn; + err = rt.add(&fn, &code); + + if (err) { + printf("JitRuntime::add() failed: %s\n", DebugUtils::errorAsString(err)); + return 1; + } + + // Execute the generated function. + int inA[4] = { 4, 3, 2, 1 }; + int inB[4] = { 1, 5, 2, 8 }; + int out[4]; + fn(out, inA, inB); + + // Should print {5 8 4 9}. + printf("Result = { %d %d %d %d }\n\n", out[0], out[1], out[2], out[3]); + + rt.release(fn); + return !(out[0] == 5 && out[1] == 8 && out[2] == 4 && out[3] == 9); +} + +int main() { + unsigned nFailed = 0; + JitRuntime rt; + + nFailed += testFunc(rt, BaseEmitter::kTypeAssembler); + +#ifndef ASMJIT_NO_BUILDER + nFailed += testFunc(rt, BaseEmitter::kTypeBuilder); +#endif + +#ifndef ASMJIT_NO_COMPILER + nFailed += testFunc(rt, BaseEmitter::kTypeCompiler); +#endif + + if (!nFailed) + printf("[PASSED] All tests passed\n"); + else + printf("[FAILED] %u %s failed\n", nFailed, nFailed == 1 ? "test" : "tests"); + + return nFailed ? 1 : 0; +} |