forked from FEX-Emu/FEX
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathSyscallOptimization.cpp
89 lines (71 loc) · 2.79 KB
/
SyscallOptimization.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
/*
$info$
tags: ir|opts
desc: Removes unused arguments if known syscall number
$end_info$
*/
#include "Interface/IR/PassManager.h"
#include <FEXCore/IR/IR.h>
#include <FEXCore/IR/IREmitter.h>
#include <FEXCore/IR/IntrusiveIRList.h>
#include <FEXCore/HLE/SyscallHandler.h>
#include <FEXCore/Utils/Profiler.h>
#include <memory>
#include <stdint.h>
namespace FEXCore::IR {
class SyscallOptimization final : public FEXCore::IR::Pass {
public:
bool Run(IREmitter *IREmit) override;
};
bool SyscallOptimization::Run(IREmitter *IREmit) {
FEXCORE_PROFILE_SCOPED("PassManager::SyscallOpt");
bool Changed = false;
auto CurrentIR = IREmit->ViewIR();
for (auto [CodeNode, IROp] : CurrentIR.GetAllCode()) {
if (IROp->Op == FEXCore::IR::OP_SYSCALL) {
auto Op = IROp->CW<IR::IROp_Syscall>();
// Is the first argument a constant?
uint64_t Constant;
if (IREmit->IsValueConstant(Op->SyscallID, &Constant)) {
auto SyscallDef = Manager->SyscallHandler->GetSyscallABI(Constant);
auto SyscallFlags = Manager->SyscallHandler->GetSyscallFlags(Constant);
// Update the syscall flags
Op->Flags = SyscallFlags;
// XXX: Once we have the ability to do real function calls then we can call directly in to the syscall handler
if (SyscallDef.NumArgs < FEXCore::HLE::SyscallArguments::MAX_ARGS) {
// If the number of args are less than what the IR op supports then we can remove arg usage
// We need +1 since we are still passing in syscall number here
for (uint8_t Arg = (SyscallDef.NumArgs + 1); Arg < FEXCore::HLE::SyscallArguments::MAX_ARGS; ++Arg) {
IREmit->ReplaceNodeArgument(CodeNode, Arg, IREmit->Invalid());
}
#ifdef _M_ARM_64
// Replace syscall with inline passthrough syscall if we can
if (SyscallDef.HostSyscallNumber != -1) {
IREmit->SetWriteCursor(CodeNode);
// Skip Args[0] since that is the syscallid
auto InlineSyscall = IREmit->_InlineSyscall(
CurrentIR.GetNode(IROp->Args[1]),
CurrentIR.GetNode(IROp->Args[2]),
CurrentIR.GetNode(IROp->Args[3]),
CurrentIR.GetNode(IROp->Args[4]),
CurrentIR.GetNode(IROp->Args[5]),
CurrentIR.GetNode(IROp->Args[6]),
SyscallDef.HostSyscallNumber,
Op->Flags);
// Replace all syscall uses with this inline one
IREmit->ReplaceAllUsesWith(CodeNode, InlineSyscall);
// We must remove here since DCE can't remove a IROp with sideeffects
IREmit->Remove(CodeNode);
}
#endif
}
Changed = true;
}
}
}
return Changed;
}
fextl::unique_ptr<FEXCore::IR::Pass> CreateSyscallOptimization() {
return fextl::make_unique<SyscallOptimization>();
}
}