mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2024-11-14 21:37:52 -07:00
Merge in latest changes to ArmEmitter from the PPSSPP crew. Should fix the dumb random crashes I had from IOS icache clearing not initializing a value.
This commit is contained in:
parent
2c722bb04f
commit
6d9c0c8863
@ -83,6 +83,40 @@ bool TryMakeOperand2_AllowNegation(s32 imm, Operand2 &op2, bool *negated)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Operand2 AssumeMakeOperand2(u32 imm) {
|
||||||
|
Operand2 op2;
|
||||||
|
bool result = TryMakeOperand2(imm, op2);
|
||||||
|
_dbg_assert_msg_(JIT, result, "Could not make assumed Operand2.");
|
||||||
|
return op2;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ARMXEmitter::TrySetValue_TwoOp(ARMReg reg, u32 val)
|
||||||
|
{
|
||||||
|
int ops = 0;
|
||||||
|
for (int i = 0; i < 16; i++)
|
||||||
|
{
|
||||||
|
if ((val >> (i*2)) & 0x3)
|
||||||
|
{
|
||||||
|
ops++;
|
||||||
|
i+=3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ops > 2)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
bool first = true;
|
||||||
|
for (int i = 0; i < 16; i++, val >>=2) {
|
||||||
|
if (val & 0x3) {
|
||||||
|
first ? MOV(reg, Operand2((u8)val, (u8)((16-i) & 0xF)))
|
||||||
|
: ORR(reg, reg, Operand2((u8)val, (u8)((16-i) & 0xF)));
|
||||||
|
first = false;
|
||||||
|
i+=3;
|
||||||
|
val >>= 6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void ARMXEmitter::MOVI2F(ARMReg dest, float val, ARMReg tempReg)
|
void ARMXEmitter::MOVI2F(ARMReg dest, float val, ARMReg tempReg)
|
||||||
{
|
{
|
||||||
union {float f; u32 u;} conv;
|
union {float f; u32 u;} conv;
|
||||||
@ -93,6 +127,21 @@ void ARMXEmitter::MOVI2F(ARMReg dest, float val, ARMReg tempReg)
|
|||||||
// Otherwise, use a literal pool and VLDR directly (+- 1020)
|
// Otherwise, use a literal pool and VLDR directly (+- 1020)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ARMXEmitter::ADDI2R(ARMReg rd, ARMReg rs, u32 val, ARMReg scratch)
|
||||||
|
{
|
||||||
|
Operand2 op2;
|
||||||
|
bool negated;
|
||||||
|
if (TryMakeOperand2_AllowNegation(val, op2, &negated)) {
|
||||||
|
if (!negated)
|
||||||
|
ADD(rd, rs, op2);
|
||||||
|
else
|
||||||
|
SUB(rd, rs, op2);
|
||||||
|
} else {
|
||||||
|
MOVI2R(scratch, val);
|
||||||
|
ADD(rd, rs, scratch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ARMXEmitter::ANDI2R(ARMReg rd, ARMReg rs, u32 val, ARMReg scratch)
|
void ARMXEmitter::ANDI2R(ARMReg rd, ARMReg rs, u32 val, ARMReg scratch)
|
||||||
{
|
{
|
||||||
Operand2 op2;
|
Operand2 op2;
|
||||||
@ -109,6 +158,21 @@ void ARMXEmitter::ANDI2R(ARMReg rd, ARMReg rs, u32 val, ARMReg scratch)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ARMXEmitter::CMPI2R(ARMReg rs, u32 val, ARMReg scratch)
|
||||||
|
{
|
||||||
|
Operand2 op2;
|
||||||
|
bool negated;
|
||||||
|
if (TryMakeOperand2_AllowNegation(val, op2, &negated)) {
|
||||||
|
if (!negated)
|
||||||
|
CMP(rs, op2);
|
||||||
|
else
|
||||||
|
CMN(rs, op2);
|
||||||
|
} else {
|
||||||
|
MOVI2R(scratch, val);
|
||||||
|
CMP(rs, scratch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ARMXEmitter::ORI2R(ARMReg rd, ARMReg rs, u32 val, ARMReg scratch)
|
void ARMXEmitter::ORI2R(ARMReg rd, ARMReg rs, u32 val, ARMReg scratch)
|
||||||
{
|
{
|
||||||
Operand2 op2;
|
Operand2 op2;
|
||||||
@ -173,7 +237,7 @@ void ARMXEmitter::MOVI2R(ARMReg reg, u32 val, bool optimize)
|
|||||||
MOVW(reg, val & 0xFFFF);
|
MOVW(reg, val & 0xFFFF);
|
||||||
if(val & 0xFFFF0000)
|
if(val & 0xFFFF0000)
|
||||||
MOVT(reg, val, true);
|
MOVT(reg, val, true);
|
||||||
} else {
|
} else if (!TrySetValue_TwoOp(reg,val)) {
|
||||||
// Use literal pool for ARMv6.
|
// Use literal pool for ARMv6.
|
||||||
AddNewLit(val);
|
AddNewLit(val);
|
||||||
LDR(reg, _PC); // To be backpatched later
|
LDR(reg, _PC); // To be backpatched later
|
||||||
@ -190,9 +254,7 @@ void ARMXEmitter::SetCodePtr(u8 *ptr)
|
|||||||
{
|
{
|
||||||
code = ptr;
|
code = ptr;
|
||||||
startcode = code;
|
startcode = code;
|
||||||
#ifdef IOS
|
|
||||||
lastCacheFlushEnd = ptr;
|
lastCacheFlushEnd = ptr;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const u8 *ARMXEmitter::GetCodePtr() const
|
const u8 *ARMXEmitter::GetCodePtr() const
|
||||||
@ -236,12 +298,9 @@ void ARMXEmitter::FlushIcacheSection(u8 *start, u8 *end)
|
|||||||
#elif defined(BLACKBERRY)
|
#elif defined(BLACKBERRY)
|
||||||
msync(start, end - start, MS_SYNC | MS_INVALIDATE_ICACHE);
|
msync(start, end - start, MS_SYNC | MS_INVALIDATE_ICACHE);
|
||||||
#elif defined(IOS)
|
#elif defined(IOS)
|
||||||
if (start != NULL)
|
// Header file says this is equivalent to: sys_icache_invalidate(start, end - start);
|
||||||
sys_cache_control(kCacheFunctionPrepareForExecution, start, end - start);
|
sys_cache_control(kCacheFunctionPrepareForExecution, start, end - start);
|
||||||
#elif !defined(_WIN32)
|
#elif !defined(_WIN32)
|
||||||
#ifndef ANDROID
|
|
||||||
start = startcode; // Should be Linux Only
|
|
||||||
#endif
|
|
||||||
__builtin___clear_cache(start, end);
|
__builtin___clear_cache(start, end);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -628,38 +687,40 @@ void ARMXEmitter::SVC(Operand2 op)
|
|||||||
|
|
||||||
// IMM, REG, IMMSREG, RSR
|
// IMM, REG, IMMSREG, RSR
|
||||||
// -1 for invalid if the instruction doesn't support that
|
// -1 for invalid if the instruction doesn't support that
|
||||||
const s32 LoadStoreOps[][4] = { {0x40, 0x60, 0x60, -1}, // STR
|
const s32 LoadStoreOps[][4] = {
|
||||||
{0x41, 0x61, 0x61, -1}, // LDR
|
{0x40, 0x60, 0x60, -1}, // STR
|
||||||
{0x44, 0x64, 0x64, -1}, // STRB
|
{0x41, 0x61, 0x61, -1}, // LDR
|
||||||
{0x45, 0x65, 0x65, -1}, // LDRB
|
{0x44, 0x64, 0x64, -1}, // STRB
|
||||||
// Special encodings
|
{0x45, 0x65, 0x65, -1}, // LDRB
|
||||||
{ 0x4, 0x0, -1, -1}, // STRH
|
// Special encodings
|
||||||
{ 0x5, 0x1, -1, -1}, // LDRH
|
{ 0x4, 0x0, -1, -1}, // STRH
|
||||||
{ 0x5, 0x1, -1, -1}, // LDRSB
|
{ 0x5, 0x1, -1, -1}, // LDRH
|
||||||
{ 0x5, 0x1, -1, -1}, // LDRSH
|
{ 0x5, 0x1, -1, -1}, // LDRSB
|
||||||
};
|
{ 0x5, 0x1, -1, -1}, // LDRSH
|
||||||
const char *LoadStoreNames[] = { "STR",
|
};
|
||||||
"LDR",
|
const char *LoadStoreNames[] = {
|
||||||
"STRB",
|
"STR",
|
||||||
"LDRB",
|
"LDR",
|
||||||
"STRH",
|
"STRB",
|
||||||
"LDRH",
|
"LDRB",
|
||||||
"LDRSB",
|
"STRH",
|
||||||
"LDRSH",
|
"LDRH",
|
||||||
};
|
"LDRSB",
|
||||||
|
"LDRSH",
|
||||||
|
};
|
||||||
|
|
||||||
void ARMXEmitter::WriteStoreOp(u32 Op, ARMReg Rt, ARMReg Rn, Operand2 Rm, bool RegAdd)
|
void ARMXEmitter::WriteStoreOp(u32 Op, ARMReg Rt, ARMReg Rn, Operand2 Rm, bool RegAdd)
|
||||||
{
|
{
|
||||||
s32 op = LoadStoreOps[Op][Rm.GetType()]; // Type always decided by last operand
|
s32 op = LoadStoreOps[Op][Rm.GetType()]; // Type always decided by last operand
|
||||||
u32 Data;
|
u32 Data;
|
||||||
|
|
||||||
// Qualcomm chipsets get /really/ angry if you don't use index, even if the offset is zero.
|
// Qualcomm chipsets get /really/ angry if you don't use index, even if the offset is zero.
|
||||||
// Some of these encodings require Index at all times anyway. Doesn't really matter.
|
// Some of these encodings require Index at all times anyway. Doesn't really matter.
|
||||||
// bool Index = op2 != 0 ? true : false;
|
// bool Index = op2 != 0 ? true : false;
|
||||||
bool Index = true;
|
bool Index = true;
|
||||||
bool Add = false;
|
bool Add = false;
|
||||||
|
|
||||||
// Special Encoding
|
// Special Encoding (misc addressing mode)
|
||||||
bool SpecialOp = false;
|
bool SpecialOp = false;
|
||||||
bool Half = false;
|
bool Half = false;
|
||||||
bool SignedLoad = false;
|
bool SignedLoad = false;
|
||||||
@ -699,10 +760,13 @@ void ARMXEmitter::WriteStoreOp(u32 Op, ARMReg Rt, ARMReg Rn, Operand2 Rm, bool R
|
|||||||
// The offset is encoded differently on this one.
|
// The offset is encoded differently on this one.
|
||||||
if (SpecialOp)
|
if (SpecialOp)
|
||||||
Data = (Data & 0xF0 << 4) | (Data & 0xF);
|
Data = (Data & 0xF0 << 4) | (Data & 0xF);
|
||||||
if (Temp >= 0) Add = true;
|
if (Temp >= 0) Add = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case TYPE_REG:
|
case TYPE_REG:
|
||||||
|
Data = Rm.GetData();
|
||||||
|
Add = RegAdd;
|
||||||
|
break;
|
||||||
case TYPE_IMMSREG:
|
case TYPE_IMMSREG:
|
||||||
if (!SpecialOp)
|
if (!SpecialOp)
|
||||||
{
|
{
|
||||||
@ -710,17 +774,18 @@ void ARMXEmitter::WriteStoreOp(u32 Op, ARMReg Rt, ARMReg Rn, Operand2 Rm, bool R
|
|||||||
Add = RegAdd;
|
Add = RegAdd;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
// Intentional fallthrough: TYPE_IMMSREG not supported for misc addressing.
|
||||||
default:
|
default:
|
||||||
// RSR not supported for any of these
|
// RSR not supported for any of these
|
||||||
// We already have the warning above
|
// We already have the warning above
|
||||||
BKPT(0x2);
|
BKPT(0x2);
|
||||||
return;
|
return;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (SpecialOp)
|
if (SpecialOp)
|
||||||
{
|
{
|
||||||
// Add SpecialOp things
|
// Add SpecialOp things
|
||||||
Data = (0x5 << 4) | (SignedLoad << 6) | (Half << 5) | Data;
|
Data = (0x9 << 4) | (SignedLoad << 6) | (Half << 5) | Data;
|
||||||
}
|
}
|
||||||
Write32(condition | (op << 20) | (Index << 24) | (Add << 23) | (Rn << 16) | (Rt << 12) | Data);
|
Write32(condition | (op << 20) | (Index << 24) | (Add << 23) | (Rn << 16) | (Rt << 12) | Data);
|
||||||
}
|
}
|
||||||
@ -947,7 +1012,6 @@ void ARMXEmitter::VLDR(ARMReg Dest, ARMReg Base, s16 offset)
|
|||||||
{
|
{
|
||||||
Write32(condition | (0xD << 24) | (Add << 23) | ((Dest & 0x1) << 22) | (1 << 20) | (Base << 16) \
|
Write32(condition | (0xD << 24) | (Add << 23) | ((Dest & 0x1) << 22) | (1 << 20) | (Base << 16) \
|
||||||
| ((Dest & 0x1E) << 11) | (10 << 8) | (imm >> 2));
|
| ((Dest & 0x1E) << 11) | (10 << 8) | (imm >> 2));
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -320,6 +320,9 @@ bool TryMakeOperand2(u32 imm, Operand2 &op2);
|
|||||||
bool TryMakeOperand2_AllowInverse(u32 imm, Operand2 &op2, bool *inverse);
|
bool TryMakeOperand2_AllowInverse(u32 imm, Operand2 &op2, bool *inverse);
|
||||||
bool TryMakeOperand2_AllowNegation(s32 imm, Operand2 &op2, bool *negated);
|
bool TryMakeOperand2_AllowNegation(s32 imm, Operand2 &op2, bool *negated);
|
||||||
|
|
||||||
|
// Use this only when you know imm can be made into an Operand2.
|
||||||
|
Operand2 AssumeMakeOperand2(u32 imm);
|
||||||
|
|
||||||
inline Operand2 R(ARMReg Reg) { return Operand2(Reg, TYPE_REG); }
|
inline Operand2 R(ARMReg Reg) { return Operand2(Reg, TYPE_REG); }
|
||||||
inline Operand2 IMM(u32 Imm) { return Operand2(Imm, TYPE_IMM); }
|
inline Operand2 IMM(u32 Imm) { return Operand2(Imm, TYPE_IMM); }
|
||||||
inline Operand2 Mem(void *ptr) { return Operand2((u32)ptr, TYPE_IMM); }
|
inline Operand2 Mem(void *ptr) { return Operand2((u32)ptr, TYPE_IMM); }
|
||||||
@ -394,6 +397,7 @@ public:
|
|||||||
|
|
||||||
void FlushLitPool();
|
void FlushLitPool();
|
||||||
void AddNewLit(u32 val);
|
void AddNewLit(u32 val);
|
||||||
|
bool TrySetValue_TwoOp(ARMReg reg, u32 val);
|
||||||
|
|
||||||
CCFlags GetCC() { return CCFlags(condition >> 28); }
|
CCFlags GetCC() { return CCFlags(condition >> 28); }
|
||||||
void SetCC(CCFlags cond = CC_AL);
|
void SetCC(CCFlags cond = CC_AL);
|
||||||
@ -562,7 +566,9 @@ public:
|
|||||||
void MOVI2R(ARMReg reg, u32 val, bool optimize = true);
|
void MOVI2R(ARMReg reg, u32 val, bool optimize = true);
|
||||||
void MOVI2F(ARMReg dest, float val, ARMReg tempReg);
|
void MOVI2F(ARMReg dest, float val, ARMReg tempReg);
|
||||||
|
|
||||||
|
void ADDI2R(ARMReg rd, ARMReg rs, u32 val, ARMReg scratch);
|
||||||
void ANDI2R(ARMReg rd, ARMReg rs, u32 val, ARMReg scratch);
|
void ANDI2R(ARMReg rd, ARMReg rs, u32 val, ARMReg scratch);
|
||||||
|
void CMPI2R(ARMReg rs, u32 val, ARMReg scratch);
|
||||||
void ORI2R(ARMReg rd, ARMReg rs, u32 val, ARMReg scratch);
|
void ORI2R(ARMReg rd, ARMReg rs, u32 val, ARMReg scratch);
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user