Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
hrydgard
GitHub Repository: hrydgard/ppsspp
Path: blob/master/Core/MIPS/ARM64/Arm64RegCacheFPU.h
5811 views
1
// Copyright (c) 2012- PPSSPP Project.
2
3
// This program is free software: you can redistribute it and/or modify
4
// it under the terms of the GNU General Public License as published by
5
// the Free Software Foundation, version 2.0 or later versions.
6
7
// This program is distributed in the hope that it will be useful,
8
// but WITHOUT ANY WARRANTY; without even the implied warranty of
9
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
// GNU General Public License 2.0 for more details.
11
12
// A copy of the GPL 2.0 should have been included with the program.
13
// If not, see http://www.gnu.org/licenses/
14
15
// Official git repository and contact information can be found at
16
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
17
18
#pragma once
19
20
#include "Core/MIPS/MIPS.h"
21
#include "Core/MIPS/ARM64/Arm64RegCache.h"
22
#include "Core/MIPS/MIPSVFPUUtils.h"
23
#include "Common/Arm64Emitter.h"
24
25
namespace Arm64JitConstants {
26
27
enum {
28
NUM_TEMPS = 16,
29
TEMP0 = 32 + 128,
30
TOTAL_MAPPABLE_MIPSFPUREGS = 32 + 128 + NUM_TEMPS,
31
};
32
33
enum {
34
MAP_READ = 0,
35
MAP_MTX_TRANSPOSED = 16,
36
MAP_PREFER_LOW = 16,
37
MAP_PREFER_HIGH = 32,
38
39
// Force is not yet correctly implemented, if the reg is already mapped it will not move
40
MAP_FORCE_LOW = 64, // Only map Q0-Q7 (and probably not Q0-Q3 as they are S registers so that leaves Q8-Q15)
41
MAP_FORCE_HIGH = 128, // Only map Q8-Q15
42
};
43
44
}
45
46
struct FPURegARM64 {
47
int mipsReg; // if -1, no mipsreg attached.
48
bool isDirty; // Should the register be written back?
49
};
50
51
struct FPURegQuad64 {
52
int mipsVec;
53
VectorSize sz;
54
u8 vregs[4];
55
bool isDirty;
56
bool spillLock;
57
bool isTemp;
58
};
59
60
struct FPURegMIPS {
61
// Where is this MIPS register?
62
Arm64JitConstants::RegMIPSLoc loc;
63
// Data (only one of these is used, depending on loc. Could make a union).
64
u32 reg;
65
int lane;
66
67
bool spillLock; // if true, this register cannot be spilled.
68
bool tempLock;
69
// If loc == ML_MEM, it's back in its location in the CPU context struct.
70
};
71
72
namespace MIPSComp {
73
struct JitOptions;
74
struct JitState;
75
}
76
77
class Arm64RegCacheFPU {
78
public:
79
Arm64RegCacheFPU(MIPSState *mipsState, MIPSComp::JitState *js, MIPSComp::JitOptions *jo);
80
~Arm64RegCacheFPU() {}
81
82
void Init(Arm64Gen::ARM64XEmitter *emitter, Arm64Gen::ARM64FloatEmitter *fp);
83
84
void Start();
85
86
// Protect the arm register containing a MIPS register from spilling, to ensure that
87
// it's being kept allocated.
88
void SpillLock(MIPSReg reg, MIPSReg reg2 = -1, MIPSReg reg3 = -1, MIPSReg reg4 = -1);
89
void SpillLockV(MIPSReg r) { SpillLock(r + 32); }
90
91
void ReleaseSpillLocksAndDiscardTemps();
92
void ReleaseSpillLock(int mipsreg) {
93
mr[mipsreg].spillLock = false;
94
}
95
void ReleaseSpillLockV(int mipsreg) {
96
ReleaseSpillLock(mipsreg + 32);
97
}
98
99
void SetImm(MIPSReg reg, u32 immVal);
100
bool IsImm(MIPSReg reg) const;
101
u32 GetImm(MIPSReg reg) const;
102
103
// Returns an ARM register containing the requested MIPS register.
104
Arm64Gen::ARM64Reg MapReg(MIPSReg reg, int mapFlags = 0);
105
void MapInIn(MIPSReg rd, MIPSReg rs);
106
void MapDirty(MIPSReg rd);
107
void MapDirtyIn(MIPSReg rd, MIPSReg rs, bool avoidLoad = true);
108
void MapDirtyInIn(MIPSReg rd, MIPSReg rs, MIPSReg rt, bool avoidLoad = true);
109
bool IsMapped(MIPSReg r);
110
bool IsMappedV(MIPSReg r) { return IsMapped((MIPSReg)(r + 32)); }
111
bool IsInRAM(MIPSReg r);
112
bool IsInRAMV(MIPSReg r) { return IsInRAM((MIPSReg)(r + 32)); }
113
void FlushArmReg(Arm64Gen::ARM64Reg r);
114
void FlushR(MIPSReg r);
115
void DiscardR(MIPSReg r);
116
Arm64Gen::ARM64Reg R(int preg); // Returns a cached register
117
118
void MapRegV(int vreg, int flags = 0);
119
void LoadToRegV(Arm64Gen::ARM64Reg armReg, int vreg);
120
void MapInInV(int rt, int rs);
121
void MapDirtyInV(int rd, int rs, bool avoidLoad = true);
122
void MapDirtyInInV(int rd, int rs, int rt, bool avoidLoad = true);
123
124
bool IsTempX(Arm64Gen::ARM64Reg r) const;
125
MIPSReg GetTempV() { return GetTempR() - 32; }
126
// VFPU registers as single VFP registers.
127
Arm64Gen::ARM64Reg V(int vreg) { return R(vreg + 32); }
128
129
void FlushAll();
130
131
// This one is allowed at any point.
132
void FlushV(MIPSReg r);
133
134
// NOTE: These require you to release spill locks manually!
135
void MapRegsAndSpillLockV(int vec, VectorSize vsz, int flags);
136
void MapRegsAndSpillLockV(const u8 *v, VectorSize vsz, int flags);
137
138
void SpillLockV(const u8 *v, VectorSize vsz);
139
void SpillLockV(int vec, VectorSize vsz);
140
141
void SetEmitter(Arm64Gen::ARM64XEmitter *emitter, Arm64Gen::ARM64FloatEmitter *fp) { emit_ = emitter; fp_ = fp; }
142
143
int GetMipsRegOffset(MIPSReg r);
144
int GetMipsRegOffsetV(MIPSReg r) {
145
return GetMipsRegOffset(r + 32);
146
}
147
148
private:
149
Arm64Gen::ARM64Reg ARM64RegForFlush(int r);
150
MIPSReg GetTempR();
151
const Arm64Gen::ARM64Reg *GetMIPSAllocationOrder(int &count);
152
153
void SetupInitialRegs();
154
155
MIPSState *mips_;
156
Arm64Gen::ARM64XEmitter *emit_;
157
Arm64Gen::ARM64FloatEmitter *fp_;
158
MIPSComp::JitState *js_;
159
MIPSComp::JitOptions *jo_;
160
161
int numARMFpuReg_;
162
163
enum {
164
// On ARM64, each of the 32 registers are full 128-bit. No sharing of components!
165
MAX_ARMFPUREG = 32,
166
NUM_MIPSFPUREG = Arm64JitConstants::TOTAL_MAPPABLE_MIPSFPUREGS,
167
};
168
169
FPURegARM64 ar[MAX_ARMFPUREG];
170
FPURegMIPS mr[NUM_MIPSFPUREG];
171
FPURegMIPS *vr;
172
173
bool pendingFlush;
174
bool initialReady = false;
175
FPURegARM64 arInitial[MAX_ARMFPUREG];
176
FPURegMIPS mrInitial[NUM_MIPSFPUREG];
177
};
178
179