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:
Ryan Houdek 2013-04-12 11:59:19 -05:00
parent 2c722bb04f
commit 6d9c0c8863
2 changed files with 104 additions and 34 deletions

View File

@ -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
{ {

View File

@ -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);