From 1fba2b4f2c27a2f4162855056f9765ee79db31e9 Mon Sep 17 00:00:00 2001 From: Patrick Mackinlay Date: Fri, 11 Feb 2022 17:16:46 +0700 Subject: asmjit: sync with upstream --- 3rdparty/asmjit/test/asmjit_test_compiler_a64.cpp | 690 ++++++++++++++++++++++ 1 file changed, 690 insertions(+) create mode 100644 3rdparty/asmjit/test/asmjit_test_compiler_a64.cpp (limited to '3rdparty/asmjit/test/asmjit_test_compiler_a64.cpp') diff --git a/3rdparty/asmjit/test/asmjit_test_compiler_a64.cpp b/3rdparty/asmjit/test/asmjit_test_compiler_a64.cpp new file mode 100644 index 00000000000..4fc362e7230 --- /dev/null +++ b/3rdparty/asmjit/test/asmjit_test_compiler_a64.cpp @@ -0,0 +1,690 @@ +// This file is part of AsmJit project +// +// See asmjit.h or LICENSE.md for license and copyright information +// SPDX-License-Identifier: Zlib + +#include +#if !defined(ASMJIT_NO_AARCH64) && ASMJIT_ARCH_ARM == 64 + +#include +#include +#include +#include + +#include "./asmjit_test_compiler.h" + +using namespace asmjit; + +// a64::Compiler - A64TestCase +// =========================== + +class A64TestCase : public TestCase { +public: + A64TestCase(const char* name = nullptr) + : TestCase(name) {} + + virtual void compile(BaseCompiler& cc) override { + compile(static_cast(cc)); + } + + virtual void compile(a64::Compiler& cc) = 0; +}; + +// a64::Compiler - A64Test_GpArgs +// ============================== + +class A64Test_GpArgs : public A64TestCase { +public: + uint32_t _argCount; + bool _preserveFP; + + A64Test_GpArgs(uint32_t argCount, bool preserveFP) + : _argCount(argCount), + _preserveFP(preserveFP) { + _name.assignFormat("GpArgs {NumArgs=%u PreserveFP=%c}", argCount, preserveFP ? 'Y' : 'N'); + } + + static void add(TestApp& app) { + for (uint32_t i = 0; i <= 16; i++) { + app.add(new A64Test_GpArgs(i, true)); + app.add(new A64Test_GpArgs(i, false)); + } + } + + virtual void compile(a64::Compiler& cc) { + uint32_t i; + uint32_t argCount = _argCount; + + FuncSignatureBuilder signature; + signature.setRetT(); + for (i = 0; i < argCount; i++) + signature.addArgT(); + + FuncNode* funcNode = cc.addFunc(signature); + if (_preserveFP) + funcNode->frame().setPreservedFP(); + + arm::Gp sum; + + if (argCount) { + for (i = 0; i < argCount; i++) { + arm::Gp iReg = cc.newInt32("i%u", i); + funcNode->setArg(i, iReg); + + if (i == 0) + sum = iReg; + else + cc.add(sum, sum, iReg); + } + } + else { + sum = cc.newInt32("i"); + cc.mov(sum, 0); + } + + cc.ret(sum); + cc.endFunc(); + } + + virtual bool run(void* _func, String& result, String& expect) { + typedef unsigned int U; + + typedef U (*Func0)(); + typedef U (*Func1)(U); + typedef U (*Func2)(U, U); + typedef U (*Func3)(U, U, U); + typedef U (*Func4)(U, U, U, U); + typedef U (*Func5)(U, U, U, U, U); + typedef U (*Func6)(U, U, U, U, U, U); + typedef U (*Func7)(U, U, U, U, U, U, U); + typedef U (*Func8)(U, U, U, U, U, U, U, U); + typedef U (*Func9)(U, U, U, U, U, U, U, U, U); + typedef U (*Func10)(U, U, U, U, U, U, U, U, U, U); + typedef U (*Func11)(U, U, U, U, U, U, U, U, U, U, U); + typedef U (*Func12)(U, U, U, U, U, U, U, U, U, U, U, U); + typedef U (*Func13)(U, U, U, U, U, U, U, U, U, U, U, U, U); + typedef U (*Func14)(U, U, U, U, U, U, U, U, U, U, U, U, U, U); + typedef U (*Func15)(U, U, U, U, U, U, U, U, U, U, U, U, U, U, U); + typedef U (*Func16)(U, U, U, U, U, U, U, U, U, U, U, U, U, U, U, U); + + unsigned int resultRet = 0; + unsigned int expectRet = 0; + + switch (_argCount) { + case 0: + resultRet = ptr_as_func(_func)(); + expectRet = 0; + break; + case 1: + resultRet = ptr_as_func(_func)(1); + expectRet = 1; + break; + case 2: + resultRet = ptr_as_func(_func)(1, 2); + expectRet = 1 + 2; + break; + case 3: + resultRet = ptr_as_func(_func)(1, 2, 3); + expectRet = 1 + 2 + 3; + break; + case 4: + resultRet = ptr_as_func(_func)(1, 2, 3, 4); + expectRet = 1 + 2 + 3 + 4; + break; + case 5: + resultRet = ptr_as_func(_func)(1, 2, 3, 4, 5); + expectRet = 1 + 2 + 3 + 4 + 5; + break; + case 6: + resultRet = ptr_as_func(_func)(1, 2, 3, 4, 5, 6); + expectRet = 1 + 2 + 3 + 4 + 5 + 6; + break; + case 7: + resultRet = ptr_as_func(_func)(1, 2, 3, 4, 5, 6, 7); + expectRet = 1 + 2 + 3 + 4 + 5 + 6 + 7; + break; + case 8: + resultRet = ptr_as_func(_func)(1, 2, 3, 4, 5, 6, 7, 8); + expectRet = 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8; + break; + case 9: + resultRet = ptr_as_func(_func)(1, 2, 3, 4, 5, 6, 7, 8, 9); + expectRet = 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9; + break; + case 10: + resultRet = ptr_as_func(_func)(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + expectRet = 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10; + break; + case 11: + resultRet = ptr_as_func(_func)(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11); + expectRet = 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11; + break; + case 12: + resultRet = ptr_as_func(_func)(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12); + expectRet = 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12; + break; + case 13: + resultRet = ptr_as_func(_func)(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13); + expectRet = 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13; + break; + case 14: + resultRet = ptr_as_func(_func)(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14); + expectRet = 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14; + break; + case 15: + resultRet = ptr_as_func(_func)(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + expectRet = 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15; + break; + case 16: + resultRet = ptr_as_func(_func)(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + expectRet = 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16; + break; + } + + result.assignFormat("ret={%u, %u}", resultRet >> 28, resultRet & 0x0FFFFFFFu); + expect.assignFormat("ret={%u, %u}", expectRet >> 28, expectRet & 0x0FFFFFFFu); + + return resultRet == expectRet; + } +}; + +// a64::Compiler - A64Test_Simd1 +// ============================= + +class A64Test_Simd1 : public A64TestCase { +public: + A64Test_Simd1() + : A64TestCase("Simd1") {} + + static void add(TestApp& app) { + app.add(new A64Test_Simd1()); + } + + virtual void compile(a64::Compiler& cc) { + FuncNode* funcNode = cc.addFunc(FuncSignatureT()); + + arm::Gp dst = cc.newUIntPtr("dst"); + arm::Gp src1 = cc.newUIntPtr("src1"); + arm::Gp src2 = cc.newUIntPtr("src2"); + + funcNode->setArg(0, dst); + funcNode->setArg(1, src1); + funcNode->setArg(2, src2); + + arm::Vec v1 = cc.newVecQ("vec1"); + arm::Vec v2 = cc.newVecQ("vec2"); + arm::Vec v3 = cc.newVecQ("vec3"); + + cc.ldr(v2, arm::ptr(src1)); + cc.ldr(v3, arm::ptr(src2)); + cc.add(v1.b16(), v2.b16(), v3.b16()); + cc.str(v1, arm::ptr(dst)); + + cc.endFunc(); + } + + virtual bool run(void* _func, String& result, String& expect) { + typedef void (*Func)(void*, const void*, const void*); + + uint32_t dst[4]; + uint32_t aSrc[4] = { 0 , 1 , 2 , 255 }; + uint32_t bSrc[4] = { 99, 17, 33, 1 }; + + // NOTE: It's a byte-add, so uint8_t(255+1) == 0. + uint32_t ref[4] = { 99, 18, 35, 0 }; + + ptr_as_func(_func)(dst, aSrc, bSrc); + + unsigned int resultRet = 0; + unsigned int expectRet = 0; + + result.assignFormat("ret={%u, %u, %u, %u}", dst[0], dst[1], dst[2], dst[3]); + expect.assignFormat("ret={%u, %u, %u, %u}", ref[0], ref[1], ref[2], ref[3]); + + return resultRet == expectRet; + } +}; + +// a64::Compiler - A64Test_ManyRegs +// ================================ + +class A64Test_ManyRegs : public A64TestCase { +public: + uint32_t _regCount; + + A64Test_ManyRegs(uint32_t n) + : A64TestCase(), + _regCount(n) { + _name.assignFormat("GpRegs {NumRegs=%u}", n); + } + + static void add(TestApp& app) { + for (uint32_t i = 2; i < 64; i++) + app.add(new A64Test_ManyRegs(i)); + } + + virtual void compile(a64::Compiler& cc) { + cc.addFunc(FuncSignatureT()); + + arm::Gp* regs = static_cast(malloc(_regCount * sizeof(arm::Gp))); + + for (uint32_t i = 0; i < _regCount; i++) { + regs[i] = cc.newUInt32("reg%u", i); + cc.mov(regs[i], i + 1); + } + + arm::Gp sum = cc.newUInt32("sum"); + cc.mov(sum, 0); + + for (uint32_t i = 0; i < _regCount; i++) { + cc.add(sum, sum, regs[i]); + } + + cc.ret(sum); + cc.endFunc(); + + free(regs); + } + + virtual bool run(void* _func, String& result, String& expect) { + typedef int (*Func)(void); + Func func = ptr_as_func(_func); + + result.assignFormat("ret={%d}", func()); + expect.assignFormat("ret={%d}", calcSum()); + + return result == expect; + } + + uint32_t calcSum() const { + return (_regCount | 1) * ((_regCount + 1) / 2); + } +}; + +// a64::Compiler - A64Test_Adr +// =========================== + +class A64Test_Adr : public A64TestCase { +public: + A64Test_Adr() + : A64TestCase("Adr") {} + + static void add(TestApp& app) { + app.add(new A64Test_Adr()); + } + + virtual void compile(a64::Compiler& cc) { + cc.addFunc(FuncSignatureT()); + + arm::Gp addr = cc.newIntPtr("addr"); + arm::Gp val = cc.newIntPtr("val"); + + Label L_Table = cc.newLabel(); + + cc.adr(addr, L_Table); + cc.ldrsw(val, arm::ptr(addr, 8)); + cc.ret(val); + cc.endFunc(); + + cc.bind(L_Table); + cc.embedInt32(1); + cc.embedInt32(2); + cc.embedInt32(3); + cc.embedInt32(4); + cc.embedInt32(5); + } + + virtual bool run(void* _func, String& result, String& expect) { + typedef int (*Func)(void); + Func func = ptr_as_func(_func); + + result.assignFormat("ret={%d}", func()); + expect.assignFormat("ret={%d}", 3); + + return result == expect; + } +}; + +// a64::Compiler - A64Test_Branch1 +// =============================== + +class A64Test_Branch1 : public A64TestCase { +public: + A64Test_Branch1() + : A64TestCase("Branch1") {} + + static void add(TestApp& app) { + app.add(new A64Test_Branch1()); + } + + virtual void compile(a64::Compiler& cc) { + FuncNode* funcNode = cc.addFunc(FuncSignatureT()); + + arm::Gp p = cc.newIntPtr("p"); + arm::Gp count = cc.newIntPtr("count"); + arm::Gp i = cc.newIntPtr("i"); + Label L = cc.newLabel(); + + funcNode->setArg(0, p); + funcNode->setArg(1, count); + + cc.mov(i, 0); + + cc.bind(L); + cc.strb(i.w(), a64::ptr(p, i)); + cc.add(i, i, 1); + cc.cmp(i, count); + cc.b_ne(L); + + cc.endFunc(); + } + + virtual bool run(void* _func, String& result, String& expect) { + typedef void (*Func)(void* p, size_t n); + Func func = ptr_as_func(_func); + + uint8_t array[16]; + func(array, 16); + + expect.assign("ret={0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}"); + + result.assign("ret={"); + for (size_t i = 0; i < 16; i++) { + if (i) + result.append(", "); + result.appendFormat("%d", int(array[i])); + } + result.append("}"); + + return result == expect; + } +}; + +// a64::Compiler - A64Test_Invoke1 +// =============================== + +class A64Test_Invoke1 : public A64TestCase { +public: + A64Test_Invoke1() + : A64TestCase("Invoke1") {} + + static void add(TestApp& app) { + app.add(new A64Test_Invoke1()); + } + + virtual void compile(a64::Compiler& cc) { + FuncNode* funcNode = cc.addFunc(FuncSignatureT()); + + arm::Gp x = cc.newUInt32("x"); + arm::Gp y = cc.newUInt32("y"); + arm::Gp r = cc.newUInt32("r"); + arm::Gp fn = cc.newUIntPtr("fn"); + + funcNode->setArg(0, x); + funcNode->setArg(1, y); + + cc.mov(fn, (uint64_t)calledFunc); + + InvokeNode* invokeNode; + cc.invoke(&invokeNode, fn, FuncSignatureT(CallConvId::kHost)); + invokeNode->setArg(0, x); + invokeNode->setArg(1, y); + invokeNode->setRet(0, r); + + cc.ret(r); + cc.endFunc(); + } + + virtual bool run(void* _func, String& result, String& expect) { + typedef uint32_t (*Func)(uint32_t, uint32_t); + Func func = ptr_as_func(_func); + + uint32_t x = 49; + uint32_t y = 7; + + result.assignFormat("ret={%u}", func(x, y)); + expect.assignFormat("ret={%u}", x - y); + + return result == expect; + } + + static uint32_t calledFunc(uint32_t x, uint32_t y) { + return x - y; + } +}; + +// a64::Compiler - A64Test_Invoke2 +// =============================== + +class A64Test_Invoke2 : public A64TestCase { +public: + A64Test_Invoke2() + : A64TestCase("Invoke2") {} + + static void add(TestApp& app) { + app.add(new A64Test_Invoke2()); + } + + virtual void compile(a64::Compiler& cc) { + FuncNode* funcNode = cc.addFunc(FuncSignatureT()); + + arm::Vec x = cc.newVecD("x"); + arm::Vec y = cc.newVecD("y"); + arm::Vec r = cc.newVecD("r"); + arm::Gp fn = cc.newUIntPtr("fn"); + + funcNode->setArg(0, x); + funcNode->setArg(1, y); + cc.mov(fn, (uint64_t)calledFunc); + + InvokeNode* invokeNode; + cc.invoke(&invokeNode, fn, FuncSignatureT(CallConvId::kHost)); + invokeNode->setArg(0, x); + invokeNode->setArg(1, y); + invokeNode->setRet(0, r); + + cc.ret(r); + cc.endFunc(); + } + + virtual bool run(void* _func, String& result, String& expect) { + typedef double (*Func)(double, double); + Func func = ptr_as_func(_func); + + double x = 49; + double y = 7; + + result.assignFormat("ret={%f}", func(x, y)); + expect.assignFormat("ret={%f}", calledFunc(x, y)); + + return result == expect; + } + + static double calledFunc(double x, double y) { + return x - y; + } +}; + +// a64::Compiler - A64Test_Invoke3 +// =============================== + +class A64Test_Invoke3 : public A64TestCase { +public: + A64Test_Invoke3() + : A64TestCase("Invoke3") {} + + static void add(TestApp& app) { + app.add(new A64Test_Invoke3()); + } + + virtual void compile(a64::Compiler& cc) { + FuncNode* funcNode = cc.addFunc(FuncSignatureT()); + + arm::Vec x = cc.newVecD("x"); + arm::Vec y = cc.newVecD("y"); + arm::Vec r = cc.newVecD("r"); + arm::Gp fn = cc.newUIntPtr("fn"); + + funcNode->setArg(0, x); + funcNode->setArg(1, y); + cc.mov(fn, (uint64_t)calledFunc); + + InvokeNode* invokeNode; + cc.invoke(&invokeNode, fn, FuncSignatureT(CallConvId::kHost)); + invokeNode->setArg(0, y); + invokeNode->setArg(1, x); + invokeNode->setRet(0, r); + + cc.ret(r); + cc.endFunc(); + } + + virtual bool run(void* _func, String& result, String& expect) { + typedef double (*Func)(double, double); + Func func = ptr_as_func(_func); + + double x = 49; + double y = 7; + + result.assignFormat("ret={%f}", func(x, y)); + expect.assignFormat("ret={%f}", calledFunc(y, x)); + + return result == expect; + } + + static double calledFunc(double x, double y) { + return x - y; + } +}; + +// a64::Compiler - A64Test_JumpTable +// ================================= + +class A64Test_JumpTable : public A64TestCase { +public: + bool _annotated; + + A64Test_JumpTable(bool annotated) + : A64TestCase("A64Test_JumpTable"), + _annotated(annotated) { + _name.assignFormat("JumpTable {%s}", annotated ? "Annotated" : "Unknown Target"); + } + + enum Operator { + kOperatorAdd = 0, + kOperatorSub = 1, + kOperatorMul = 2, + kOperatorDiv = 3 + }; + + static void add(TestApp& app) { + app.add(new A64Test_JumpTable(false)); + app.add(new A64Test_JumpTable(true)); + } + + virtual void compile(a64::Compiler& cc) { + FuncNode* funcNode = cc.addFunc(FuncSignatureT()); + + arm::Vec a = cc.newVecS("a"); + arm::Vec b = cc.newVecS("b"); + arm::Gp op = cc.newUInt32("op"); + + arm::Gp target = cc.newIntPtr("target"); + arm::Gp offset = cc.newIntPtr("offset"); + + Label L_End = cc.newLabel(); + + Label L_Table = cc.newLabel(); + Label L_Add = cc.newLabel(); + Label L_Sub = cc.newLabel(); + Label L_Mul = cc.newLabel(); + Label L_Div = cc.newLabel(); + + funcNode->setArg(0, a); + funcNode->setArg(1, b); + funcNode->setArg(2, op); + + cc.adr(target, L_Table); + cc.ldrsw(offset, arm::ptr(target, op, arm::sxtw(2))); + cc.add(target, target, offset); + + // JumpAnnotation allows to annotate all possible jump targets of + // instructions where it cannot be deduced from operands. + if (_annotated) { + JumpAnnotation* annotation = cc.newJumpAnnotation(); + annotation->addLabel(L_Add); + annotation->addLabel(L_Sub); + annotation->addLabel(L_Mul); + annotation->addLabel(L_Div); + cc.br(target, annotation); + } + else { + cc.br(target); + } + + cc.bind(L_Add); + cc.fadd(a, a, b); + cc.b(L_End); + + cc.bind(L_Sub); + cc.fsub(a, a, b); + cc.b(L_End); + + cc.bind(L_Mul); + cc.fmul(a, a, b); + cc.b(L_End); + + cc.bind(L_Div); + cc.fdiv(a, a, b); + + cc.bind(L_End); + cc.ret(a); + cc.endFunc(); + + cc.bind(L_Table); + cc.embedLabelDelta(L_Add, L_Table, 4); + cc.embedLabelDelta(L_Sub, L_Table, 4); + cc.embedLabelDelta(L_Mul, L_Table, 4); + cc.embedLabelDelta(L_Div, L_Table, 4); + } + + virtual bool run(void* _func, String& result, String& expect) { + typedef float (*Func)(float, float, uint32_t); + Func func = ptr_as_func(_func); + + float dst[4]; + float ref[4]; + + dst[0] = func(33.0f, 14.0f, kOperatorAdd); + dst[1] = func(33.0f, 14.0f, kOperatorSub); + dst[2] = func(10.0f, 6.0f, kOperatorMul); + dst[3] = func(80.0f, 8.0f, kOperatorDiv); + + ref[0] = 47.0f; + ref[1] = 19.0f; + ref[2] = 60.0f; + ref[3] = 10.0f; + + result.assignFormat("ret={%f, %f, %f, %f}", dst[0], dst[1], dst[2], dst[3]); + expect.assignFormat("ret={%f, %f, %f, %f}", ref[0], ref[1], ref[2], ref[3]); + + return result == expect; + } +}; + +// a64::Compiler - Export +// ====================== + +void compiler_add_a64_tests(TestApp& app) { + app.addT(); + app.addT(); + app.addT(); + app.addT(); + app.addT(); + app.addT(); + app.addT(); + app.addT(); + app.addT(); +} + +#endif // !ASMJIT_NO_AARCH64 && ASMJIT_ARCH_ARM == 64 -- cgit v1.2.3-70-g09d2