mirror of
https://github.com/RPCS3/asmjit.git
synced 2026-07-18 18:34:26 -04:00
Added a support for indirect jumps within a function (Compiler) (#286)
This commit is contained in:
@@ -25,9 +25,12 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "./asmjit_test_misc.h"
|
||||
#include "./asmjit_test_opcode.h"
|
||||
|
||||
#ifndef ASMJIT_NO_COMPILER
|
||||
#include "./asmjit_test_misc.h"
|
||||
#endif
|
||||
|
||||
using namespace asmjit;
|
||||
|
||||
// ============================================================================
|
||||
@@ -131,6 +134,7 @@ static void benchX86(uint32_t archId) noexcept {
|
||||
asmtest::generateOpcodes(a.as<x86::Emitter>());
|
||||
});
|
||||
|
||||
#ifndef ASMJIT_NO_BUILDER
|
||||
BenchUtils::bench<x86::Builder>(code, archId, "[raw]", [](x86::Builder& cb) {
|
||||
asmtest::generateOpcodes(cb.as<x86::Emitter>());
|
||||
});
|
||||
@@ -139,7 +143,9 @@ static void benchX86(uint32_t archId) noexcept {
|
||||
asmtest::generateOpcodes(cb.as<x86::Emitter>());
|
||||
cb.finalize();
|
||||
});
|
||||
#endif
|
||||
|
||||
#ifndef ASMJIT_NO_COMPILER
|
||||
BenchUtils::bench<x86::Compiler>(code, archId, "[raw]", [](x86::Compiler& cc) {
|
||||
asmtest::generateAlphaBlend(cc);
|
||||
});
|
||||
@@ -148,17 +154,15 @@ static void benchX86(uint32_t archId) noexcept {
|
||||
asmtest::generateAlphaBlend(cc);
|
||||
cc.finalize();
|
||||
});
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
ASMJIT_UNUSED(argc);
|
||||
ASMJIT_UNUSED(argv);
|
||||
|
||||
#ifdef ASMJIT_BUILD_X86
|
||||
int main() {
|
||||
#ifdef ASMJIT_BUILD_X86
|
||||
benchX86(ArchInfo::kIdX86);
|
||||
benchX86(ArchInfo::kIdX64);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -61,10 +61,7 @@ struct TestErrorHandler : public ErrorHandler {
|
||||
|
||||
typedef void (*VoidFunc)(void);
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
ASMJIT_UNUSED(argc);
|
||||
ASMJIT_UNUSED(argv);
|
||||
|
||||
int main() {
|
||||
TestErrorHandler eh;
|
||||
|
||||
OpcodeDumpInfo infoList[] = {
|
||||
@@ -87,11 +84,11 @@ int main(int argc, char* argv[]) {
|
||||
code.init(CodeInfo(info.archId));
|
||||
code.setErrorHandler(&eh);
|
||||
|
||||
#ifndef ASMJIT_NO_LOGGING
|
||||
#ifndef ASMJIT_NO_LOGGING
|
||||
FileLogger logger(stdout);
|
||||
logger.addFlags(FormatOptions::kFlagMachineCode);
|
||||
code.setLogger(&logger);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
x86::Assembler a(&code);
|
||||
asmtest::generateOpcodes(a.as<x86::Emitter>(), info.useRex1, info.useRex2);
|
||||
|
||||
+18
-18
@@ -71,7 +71,7 @@ static void dumpCpu(void) noexcept {
|
||||
// [X86]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
#if ASMJIT_ARCH_X86
|
||||
#if ASMJIT_ARCH_X86
|
||||
static const DumpCpuFeature x86FeaturesList[] = {
|
||||
{ x86::Features::kNX , "NX" },
|
||||
{ x86::Features::kMT , "MT" },
|
||||
@@ -168,13 +168,13 @@ static void dumpCpu(void) noexcept {
|
||||
INFO("X86 Features:");
|
||||
dumpFeatures(cpu, x86FeaturesList, ASMJIT_ARRAY_SIZE(x86FeaturesList));
|
||||
INFO("");
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// [ARM]
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
#if ASMJIT_ARCH_ARM
|
||||
#if ASMJIT_ARCH_ARM
|
||||
static const DumpCpuFeature armFeaturesList[] = {
|
||||
{ arm::Features::kARMv6 , "ARMv6" },
|
||||
{ arm::Features::kARMv7 , "ARMv7" },
|
||||
@@ -198,17 +198,17 @@ static void dumpCpu(void) noexcept {
|
||||
INFO("ARM Features:");
|
||||
dumpFeatures(cpu, armFeaturesList, ASMJIT_ARRAY_SIZE(armFeaturesList));
|
||||
INFO("");
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// [DumpSizeOf]
|
||||
// ============================================================================
|
||||
|
||||
static void dumpSizeOf(void) noexcept {
|
||||
#define DUMP_TYPE(...) \
|
||||
INFO(" %-26s: %u", #__VA_ARGS__, uint32_t(sizeof(__VA_ARGS__)))
|
||||
#define DUMP_TYPE(...) \
|
||||
INFO(" %-26s: %u", #__VA_ARGS__, uint32_t(sizeof(__VA_ARGS__)))
|
||||
|
||||
static void dumpSizeOf(void) noexcept {
|
||||
INFO("Size of C++ types:");
|
||||
DUMP_TYPE(int8_t);
|
||||
DUMP_TYPE(int16_t);
|
||||
@@ -260,7 +260,7 @@ static void dumpSizeOf(void) noexcept {
|
||||
DUMP_TYPE(FuncArgsAssignment);
|
||||
INFO("");
|
||||
|
||||
#ifndef ASMJIT_NO_BUILDER
|
||||
#ifndef ASMJIT_NO_BUILDER
|
||||
INFO("Size of builder classes:");
|
||||
DUMP_TYPE(BaseBuilder);
|
||||
DUMP_TYPE(BaseNode);
|
||||
@@ -274,18 +274,18 @@ static void dumpSizeOf(void) noexcept {
|
||||
DUMP_TYPE(CommentNode);
|
||||
DUMP_TYPE(SentinelNode);
|
||||
INFO("");
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef ASMJIT_NO_COMPILER
|
||||
#ifndef ASMJIT_NO_COMPILER
|
||||
INFO("Size of compiler classes:");
|
||||
DUMP_TYPE(BaseCompiler);
|
||||
DUMP_TYPE(FuncNode);
|
||||
DUMP_TYPE(FuncRetNode);
|
||||
DUMP_TYPE(FuncCallNode);
|
||||
INFO("");
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef ASMJIT_BUILD_X86
|
||||
#ifdef ASMJIT_BUILD_X86
|
||||
INFO("Size of x86-specific classes:");
|
||||
DUMP_TYPE(x86::Assembler);
|
||||
#ifndef ASMJIT_NO_BUILDER
|
||||
@@ -299,11 +299,11 @@ static void dumpSizeOf(void) noexcept {
|
||||
DUMP_TYPE(x86::InstDB::OpSignature);
|
||||
DUMP_TYPE(x86::InstDB::InstSignature);
|
||||
INFO("");
|
||||
#endif
|
||||
|
||||
#undef DUMP_TYPE
|
||||
#endif
|
||||
}
|
||||
|
||||
#undef DUMP_TYPE
|
||||
|
||||
// ============================================================================
|
||||
// [Main]
|
||||
// ============================================================================
|
||||
@@ -314,11 +314,11 @@ static void onBeforeRun(void) noexcept {
|
||||
}
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
#if defined(ASMJIT_BUILD_DEBUG)
|
||||
#if defined(ASMJIT_BUILD_DEBUG)
|
||||
const char buildType[] = "Debug";
|
||||
#else
|
||||
#else
|
||||
const char buildType[] = "Release";
|
||||
#endif
|
||||
#endif
|
||||
|
||||
INFO("AsmJit Unit-Test v%u.%u.%u [Arch=%s] [Mode=%s]\n\n",
|
||||
unsigned((ASMJIT_LIBRARY_VERSION >> 16) ),
|
||||
|
||||
@@ -75,6 +75,7 @@ static void makeRawFunc(x86::Emitter* emitter) noexcept {
|
||||
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();
|
||||
@@ -95,13 +96,19 @@ static void makeCompiledFunc(x86::Compiler* cc) noexcept {
|
||||
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) {
|
||||
@@ -112,6 +119,7 @@ static uint32_t testFunc(JitRuntime& rt, uint32_t emitterType) noexcept {
|
||||
break;
|
||||
}
|
||||
|
||||
#ifndef ASMJIT_NO_BUILDER
|
||||
case BaseEmitter::kTypeBuilder: {
|
||||
printf("Using x86::Builder:\n");
|
||||
x86::Builder cb(&code);
|
||||
@@ -124,7 +132,9 @@ static uint32_t testFunc(JitRuntime& rt, uint32_t emitterType) noexcept {
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef ASMJIT_NO_COMPILER
|
||||
case BaseEmitter::kTypeCompiler: {
|
||||
printf("Using x86::Compiler:\n");
|
||||
x86::Compiler cc(&code);
|
||||
@@ -137,6 +147,7 @@ static uint32_t testFunc(JitRuntime& rt, uint32_t emitterType) noexcept {
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Add the code generated to the runtime.
|
||||
@@ -161,16 +172,19 @@ static uint32_t testFunc(JitRuntime& rt, uint32_t emitterType) noexcept {
|
||||
return !(out[0] == 5 && out[1] == 8 && out[2] == 4 && out[3] == 9);
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
ASMJIT_UNUSED(argc);
|
||||
ASMJIT_UNUSED(argv);
|
||||
|
||||
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");
|
||||
|
||||
+136
-19
@@ -65,7 +65,7 @@ class SimpleErrorHandler : public ErrorHandler {
|
||||
public:
|
||||
SimpleErrorHandler() : _err(kErrorOk) {}
|
||||
virtual void handleError(Error err, const char* message, BaseEmitter* origin) {
|
||||
ASMJIT_UNUSED(origin);
|
||||
DebugUtils::unused(origin);
|
||||
_err = err;
|
||||
_message.assignString(message);
|
||||
}
|
||||
@@ -154,7 +154,7 @@ void X86TestApp::showInfo() {
|
||||
}
|
||||
|
||||
int X86TestApp::run() {
|
||||
#ifndef ASMJIT_NO_LOGGING
|
||||
#ifndef ASMJIT_NO_LOGGING
|
||||
uint32_t kFormatFlags = FormatOptions::kFlagMachineCode |
|
||||
FormatOptions::kFlagExplainImms |
|
||||
FormatOptions::kFlagRegCasts |
|
||||
@@ -167,7 +167,7 @@ int X86TestApp::run() {
|
||||
|
||||
StringLogger stringLogger;
|
||||
stringLogger.addFlags(kFormatFlags);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
for (X86Test* test : _tests) {
|
||||
JitRuntime runtime;
|
||||
@@ -177,7 +177,7 @@ int X86TestApp::run() {
|
||||
code.init(runtime.codeInfo());
|
||||
code.setErrorHandler(&errorHandler);
|
||||
|
||||
#ifndef ASMJIT_NO_LOGGING
|
||||
#ifndef ASMJIT_NO_LOGGING
|
||||
if (_verbose) {
|
||||
code.setLogger(&fileLogger);
|
||||
}
|
||||
@@ -185,13 +185,13 @@ int X86TestApp::run() {
|
||||
stringLogger.clear();
|
||||
code.setLogger(&stringLogger);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
printf("[Test] %s", test->name());
|
||||
|
||||
#ifndef ASMJIT_NO_LOGGING
|
||||
#ifndef ASMJIT_NO_LOGGING
|
||||
if (_verbose) printf("\n");
|
||||
#endif
|
||||
#endif
|
||||
|
||||
x86::Compiler cc(&code);
|
||||
test->compile(cc);
|
||||
@@ -202,7 +202,7 @@ int X86TestApp::run() {
|
||||
if (!err)
|
||||
err = cc.finalize();
|
||||
|
||||
#ifndef ASMJIT_NO_LOGGING
|
||||
#ifndef ASMJIT_NO_LOGGING
|
||||
if (_dumpAsm) {
|
||||
if (!_verbose) printf("\n");
|
||||
|
||||
@@ -210,7 +210,7 @@ int X86TestApp::run() {
|
||||
cc.dump(sb, kFormatFlags);
|
||||
printf("%s", sb.data());
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (err == kErrorOk)
|
||||
err = runtime.add(&func, &code);
|
||||
@@ -230,9 +230,9 @@ int X86TestApp::run() {
|
||||
else {
|
||||
if (!_verbose) printf(" [FAILED]\n");
|
||||
|
||||
#ifndef ASMJIT_NO_LOGGING
|
||||
#ifndef ASMJIT_NO_LOGGING
|
||||
if (!_verbose) printf("%s", stringLogger.data());
|
||||
#endif
|
||||
#endif
|
||||
|
||||
printf("[Status]\n");
|
||||
printf(" Returned: %s\n", result.data());
|
||||
@@ -249,9 +249,9 @@ int X86TestApp::run() {
|
||||
else {
|
||||
if (!_verbose) printf(" [FAILED]\n");
|
||||
|
||||
#ifndef ASMJIT_NO_LOGGING
|
||||
#ifndef ASMJIT_NO_LOGGING
|
||||
if (!_verbose) printf("%s", stringLogger.data());
|
||||
#endif
|
||||
#endif
|
||||
|
||||
printf("[Status]\n");
|
||||
printf(" ERROR 0x%08X: %s\n", unsigned(err), errorHandler._message.data());
|
||||
@@ -458,8 +458,7 @@ public:
|
||||
}
|
||||
|
||||
virtual bool run(void* _func, String& result, String& expect) {
|
||||
ASMJIT_UNUSED(result);
|
||||
ASMJIT_UNUSED(expect);
|
||||
DebugUtils::unused(result, expect);
|
||||
|
||||
typedef void(*Func)(void);
|
||||
Func func = ptr_as_func<Func>(_func);
|
||||
@@ -489,8 +488,7 @@ public:
|
||||
}
|
||||
|
||||
virtual bool run(void* _func, String& result, String& expect) {
|
||||
ASMJIT_UNUSED(result);
|
||||
ASMJIT_UNUSED(expect);
|
||||
DebugUtils::unused(result, expect);
|
||||
|
||||
typedef void (*Func)(void);
|
||||
Func func = ptr_as_func<Func>(_func);
|
||||
@@ -598,8 +596,7 @@ public:
|
||||
}
|
||||
|
||||
virtual bool run(void* _func, String& result, String& expect) {
|
||||
ASMJIT_UNUSED(result);
|
||||
ASMJIT_UNUSED(expect);
|
||||
DebugUtils::unused(result, expect);
|
||||
|
||||
typedef void (*Func)(void);
|
||||
Func func = ptr_as_func<Func>(_func);
|
||||
@@ -760,6 +757,125 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// [X86Test_JumpTable]
|
||||
// ============================================================================
|
||||
|
||||
class X86Test_JumpTable : public X86Test {
|
||||
public:
|
||||
bool _annotated;
|
||||
|
||||
X86Test_JumpTable(bool annotated)
|
||||
: X86Test("X86Test_JumpTable"),
|
||||
_annotated(annotated) {
|
||||
_name.assignFormat("JumpTable {%s}", annotated ? "Annotated" : "Unknown Reg/Mem");
|
||||
}
|
||||
|
||||
enum Operator {
|
||||
kOperatorAdd = 0,
|
||||
kOperatorSub = 1,
|
||||
kOperatorMul = 2,
|
||||
kOperatorDiv = 3
|
||||
};
|
||||
|
||||
static void add(X86TestApp& app) {
|
||||
app.add(new X86Test_JumpTable(false));
|
||||
app.add(new X86Test_JumpTable(true));
|
||||
}
|
||||
|
||||
virtual void compile(x86::Compiler& cc) {
|
||||
cc.addFunc(FuncSignatureT<float, float, float, uint32_t>(CallConv::kIdHost));
|
||||
|
||||
x86::Xmm a = cc.newXmmSs("a");
|
||||
x86::Xmm b = cc.newXmmSs("b");
|
||||
x86::Gp op = cc.newUInt32("op");
|
||||
x86::Gp target = cc.newIntPtr("target");
|
||||
x86::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();
|
||||
|
||||
cc.setArg(0, a);
|
||||
cc.setArg(1, b);
|
||||
cc.setArg(2, op);
|
||||
|
||||
cc.lea(offset, x86::ptr(L_Table));
|
||||
if (cc.is64Bit())
|
||||
cc.movsxd(target, x86::dword_ptr(offset, op.cloneAs(offset), 2));
|
||||
else
|
||||
cc.mov(target, x86::dword_ptr(offset, op.cloneAs(offset), 2));
|
||||
cc.add(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.jmp(target, annotation);
|
||||
}
|
||||
else {
|
||||
cc.jmp(target);
|
||||
}
|
||||
|
||||
cc.bind(L_Add);
|
||||
cc.addss(a, b);
|
||||
cc.jmp(L_End);
|
||||
|
||||
cc.bind(L_Sub);
|
||||
cc.subss(a, b);
|
||||
cc.jmp(L_End);
|
||||
|
||||
cc.bind(L_Mul);
|
||||
cc.mulss(a, b);
|
||||
cc.jmp(L_End);
|
||||
|
||||
cc.bind(L_Div);
|
||||
cc.divss(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>(_func);
|
||||
|
||||
float results[4];
|
||||
float expected[4];
|
||||
|
||||
results[0] = func(33.0f, 14.0f, kOperatorAdd);
|
||||
results[1] = func(33.0f, 14.0f, kOperatorSub);
|
||||
results[2] = func(10.0f, 6.0f, kOperatorMul);
|
||||
results[3] = func(80.0f, 8.0f, kOperatorDiv);
|
||||
|
||||
expected[0] = 47.0f;
|
||||
expected[1] = 19.0f;
|
||||
expected[2] = 60.0f;
|
||||
expected[3] = 10.0f;
|
||||
|
||||
result.assignFormat("ret={%f, %f, %f, %f}", results[0], results[1], results[2], results[3]);
|
||||
expect.assignFormat("ret={%f, %f, %f, %f}", expected[0], expected[1], expected[2], expected[3]);
|
||||
|
||||
return result == expect;
|
||||
}
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// [X86Test_AllocBase]
|
||||
// ============================================================================
|
||||
@@ -3984,6 +4100,7 @@ int main(int argc, char* argv[]) {
|
||||
app.addT<X86Test_JumpMany>();
|
||||
app.addT<X86Test_JumpUnreachable1>();
|
||||
app.addT<X86Test_JumpUnreachable2>();
|
||||
app.addT<X86Test_JumpTable>();
|
||||
|
||||
// Alloc tests.
|
||||
app.addT<X86Test_AllocBase>();
|
||||
|
||||
@@ -52,19 +52,21 @@ static void fail(const char* message, Error err) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
ASMJIT_UNUSED(argc);
|
||||
ASMJIT_UNUSED(argv);
|
||||
|
||||
int main() {
|
||||
CodeInfo codeInfo(ArchInfo::kIdHost);
|
||||
JitAllocator allocator;
|
||||
|
||||
#ifndef ASMJIT_NO_LOGGING
|
||||
FileLogger logger(stdout);
|
||||
logger.setIndentation(FormatOptions::kIndentationCode, 2);
|
||||
#endif
|
||||
|
||||
CodeHolder code;
|
||||
code.init(codeInfo);
|
||||
|
||||
#ifndef ASMJIT_NO_LOGGING
|
||||
code.setLogger(&logger);
|
||||
#endif
|
||||
|
||||
Section* dataSection;
|
||||
Error err = code.newSection(&dataSection, ".data", SIZE_MAX, 0, 8);
|
||||
|
||||
Reference in New Issue
Block a user