ARM: Merging constants in simulator and assembler header files and other cleanup.
First stab at a general ARM cleanup patch. It merges ARM constants so that they can be used across simulator, assembler and disassembler, and tidies up some syntax and ambiguities. BUG=none TEST=none Review URL: http://codereview.chromium.org/6274009 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@6483 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
591eb3f406
commit
0e183035a2
src
arm
assembler-arm.ccassembler-arm.hbuiltins-arm.cccode-stubs-arm.cccodegen-arm-inl.hcodegen-arm.ccconstants-arm.ccconstants-arm.hcpu-arm.ccdisasm-arm.ccfull-codegen-arm.ccic-arm.ccjump-target-arm.cclithium-codegen-arm.ccmacro-assembler-arm.ccmacro-assembler-arm.hsimulator-arm.ccsimulator-arm.h
top.cctop.hv8.cc@ -213,74 +213,29 @@ MemOperand::MemOperand(Register rn, Register rm,
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Implementation of Assembler.
|
||||
|
||||
// Instruction encoding bits.
|
||||
enum {
|
||||
H = 1 << 5, // halfword (or byte)
|
||||
S6 = 1 << 6, // signed (or unsigned)
|
||||
L = 1 << 20, // load (or store)
|
||||
S = 1 << 20, // set condition code (or leave unchanged)
|
||||
W = 1 << 21, // writeback base register (or leave unchanged)
|
||||
A = 1 << 21, // accumulate in multiply instruction (or not)
|
||||
B = 1 << 22, // unsigned byte (or word)
|
||||
N = 1 << 22, // long (or short)
|
||||
U = 1 << 23, // positive (or negative) offset/index
|
||||
P = 1 << 24, // offset/pre-indexed addressing (or post-indexed addressing)
|
||||
I = 1 << 25, // immediate shifter operand (or not)
|
||||
|
||||
B4 = 1 << 4,
|
||||
B5 = 1 << 5,
|
||||
B6 = 1 << 6,
|
||||
B7 = 1 << 7,
|
||||
B8 = 1 << 8,
|
||||
B9 = 1 << 9,
|
||||
B12 = 1 << 12,
|
||||
B16 = 1 << 16,
|
||||
B18 = 1 << 18,
|
||||
B19 = 1 << 19,
|
||||
B20 = 1 << 20,
|
||||
B21 = 1 << 21,
|
||||
B22 = 1 << 22,
|
||||
B23 = 1 << 23,
|
||||
B24 = 1 << 24,
|
||||
B25 = 1 << 25,
|
||||
B26 = 1 << 26,
|
||||
B27 = 1 << 27,
|
||||
|
||||
// Instruction bit masks.
|
||||
RdMask = 15 << 12, // in str instruction
|
||||
CondMask = 15 << 28,
|
||||
CoprocessorMask = 15 << 8,
|
||||
OpCodeMask = 15 << 21, // in data-processing instructions
|
||||
Imm24Mask = (1 << 24) - 1,
|
||||
Off12Mask = (1 << 12) - 1,
|
||||
// Reserved condition.
|
||||
nv = 15 << 28
|
||||
};
|
||||
|
||||
// Specific instructions, constants, and masks.
|
||||
|
||||
// add(sp, sp, 4) instruction (aka Pop())
|
||||
static const Instr kPopInstruction =
|
||||
al | 4 * B21 | 4 | LeaveCC | I | sp.code() * B16 | sp.code() * B12;
|
||||
const Instr kPopInstruction =
|
||||
al | PostIndex | 4 | LeaveCC | I | sp.code() * B16 | sp.code() * B12;
|
||||
// str(r, MemOperand(sp, 4, NegPreIndex), al) instruction (aka push(r))
|
||||
// register r is not encoded.
|
||||
static const Instr kPushRegPattern =
|
||||
const Instr kPushRegPattern =
|
||||
al | B26 | 4 | NegPreIndex | sp.code() * B16;
|
||||
// ldr(r, MemOperand(sp, 4, PostIndex), al) instruction (aka pop(r))
|
||||
// register r is not encoded.
|
||||
static const Instr kPopRegPattern =
|
||||
const Instr kPopRegPattern =
|
||||
al | B26 | L | 4 | PostIndex | sp.code() * B16;
|
||||
// mov lr, pc
|
||||
const Instr kMovLrPc = al | 13*B21 | pc.code() | lr.code() * B12;
|
||||
const Instr kMovLrPc = al | MOV | pc.code() | lr.code() * B12;
|
||||
// ldr rd, [pc, #offset]
|
||||
const Instr kLdrPCMask = CondMask | 15 * B24 | 7 * B20 | 15 * B16;
|
||||
const Instr kLdrPCMask = kCondMask | 15 * B24 | 7 * B20 | 15 * B16;
|
||||
const Instr kLdrPCPattern = al | 5 * B24 | L | pc.code() * B16;
|
||||
// blxcc rm
|
||||
const Instr kBlxRegMask =
|
||||
15 * B24 | 15 * B20 | 15 * B16 | 15 * B12 | 15 * B8 | 15 * B4;
|
||||
const Instr kBlxRegPattern =
|
||||
B24 | B21 | 15 * B16 | 15 * B12 | 15 * B8 | 3 * B4;
|
||||
B24 | B21 | 15 * B16 | 15 * B12 | 15 * B8 | BLX;
|
||||
const Instr kMovMvnMask = 0x6d * B21 | 0xf * B16;
|
||||
const Instr kMovMvnPattern = 0xd * B21;
|
||||
const Instr kMovMvnFlip = B22;
|
||||
@ -292,33 +247,28 @@ const Instr kMovwLeaveCCFlip = 0x5 * B21;
|
||||
const Instr kCmpCmnMask = 0xdd * B20 | 0xf * B12;
|
||||
const Instr kCmpCmnPattern = 0x15 * B20;
|
||||
const Instr kCmpCmnFlip = B21;
|
||||
const Instr kALUMask = 0x6f * B21;
|
||||
const Instr kAddPattern = 0x4 * B21;
|
||||
const Instr kSubPattern = 0x2 * B21;
|
||||
const Instr kBicPattern = 0xe * B21;
|
||||
const Instr kAndPattern = 0x0 * B21;
|
||||
const Instr kAddSubFlip = 0x6 * B21;
|
||||
const Instr kAndBicFlip = 0xe * B21;
|
||||
|
||||
// A mask for the Rd register for push, pop, ldr, str instructions.
|
||||
const Instr kRdMask = 0x0000f000;
|
||||
static const int kRdShift = 12;
|
||||
static const Instr kLdrRegFpOffsetPattern =
|
||||
const Instr kLdrRegFpOffsetPattern =
|
||||
al | B26 | L | Offset | fp.code() * B16;
|
||||
static const Instr kStrRegFpOffsetPattern =
|
||||
const Instr kStrRegFpOffsetPattern =
|
||||
al | B26 | Offset | fp.code() * B16;
|
||||
static const Instr kLdrRegFpNegOffsetPattern =
|
||||
const Instr kLdrRegFpNegOffsetPattern =
|
||||
al | B26 | L | NegOffset | fp.code() * B16;
|
||||
static const Instr kStrRegFpNegOffsetPattern =
|
||||
const Instr kStrRegFpNegOffsetPattern =
|
||||
al | B26 | NegOffset | fp.code() * B16;
|
||||
static const Instr kLdrStrInstrTypeMask = 0xffff0000;
|
||||
static const Instr kLdrStrInstrArgumentMask = 0x0000ffff;
|
||||
static const Instr kLdrStrOffsetMask = 0x00000fff;
|
||||
const Instr kLdrStrInstrTypeMask = 0xffff0000;
|
||||
const Instr kLdrStrInstrArgumentMask = 0x0000ffff;
|
||||
const Instr kLdrStrOffsetMask = 0x00000fff;
|
||||
|
||||
|
||||
// Spare buffer.
|
||||
static const int kMinimalBufferSize = 4*KB;
|
||||
static byte* spare_buffer_ = NULL;
|
||||
|
||||
|
||||
Assembler::Assembler(void* buffer, int buffer_size)
|
||||
: positions_recorder_(this),
|
||||
allow_peephole_optimization_(false) {
|
||||
@ -411,7 +361,7 @@ int Assembler::GetBranchOffset(Instr instr) {
|
||||
ASSERT(IsBranch(instr));
|
||||
// Take the jump offset in the lower 24 bits, sign extend it and multiply it
|
||||
// with 4 to get the offset in bytes.
|
||||
return ((instr & Imm24Mask) << 8) >> 6;
|
||||
return ((instr & kImm24Mask) << 8) >> 6;
|
||||
}
|
||||
|
||||
|
||||
@ -423,7 +373,7 @@ bool Assembler::IsLdrRegisterImmediate(Instr instr) {
|
||||
int Assembler::GetLdrRegisterImmediateOffset(Instr instr) {
|
||||
ASSERT(IsLdrRegisterImmediate(instr));
|
||||
bool positive = (instr & B23) == B23;
|
||||
int offset = instr & Off12Mask; // Zero extended offset.
|
||||
int offset = instr & kOff12Mask; // Zero extended offset.
|
||||
return positive ? offset : -offset;
|
||||
}
|
||||
|
||||
@ -436,7 +386,7 @@ Instr Assembler::SetLdrRegisterImmediateOffset(Instr instr, int offset) {
|
||||
// Set bit indicating whether the offset should be added.
|
||||
instr = (instr & ~B23) | (positive ? B23 : 0);
|
||||
// Set the actual offset.
|
||||
return (instr & ~Off12Mask) | offset;
|
||||
return (instr & ~kOff12Mask) | offset;
|
||||
}
|
||||
|
||||
|
||||
@ -453,7 +403,7 @@ Instr Assembler::SetStrRegisterImmediateOffset(Instr instr, int offset) {
|
||||
// Set bit indicating whether the offset should be added.
|
||||
instr = (instr & ~B23) | (positive ? B23 : 0);
|
||||
// Set the actual offset.
|
||||
return (instr & ~Off12Mask) | offset;
|
||||
return (instr & ~kOff12Mask) | offset;
|
||||
}
|
||||
|
||||
|
||||
@ -467,13 +417,13 @@ Instr Assembler::SetAddRegisterImmediateOffset(Instr instr, int offset) {
|
||||
ASSERT(offset >= 0);
|
||||
ASSERT(is_uint12(offset));
|
||||
// Set the offset.
|
||||
return (instr & ~Off12Mask) | offset;
|
||||
return (instr & ~kOff12Mask) | offset;
|
||||
}
|
||||
|
||||
|
||||
Register Assembler::GetRd(Instr instr) {
|
||||
Register reg;
|
||||
reg.code_ = ((instr & kRdMask) >> kRdShift);
|
||||
reg.code_ = Instruction::RdValue(instr);
|
||||
return reg;
|
||||
}
|
||||
|
||||
@ -511,7 +461,7 @@ bool Assembler::IsLdrRegFpNegOffset(Instr instr) {
|
||||
bool Assembler::IsLdrPcImmediateOffset(Instr instr) {
|
||||
// Check the instruction is indeed a
|
||||
// ldr<cond> <Rd>, [pc +/- offset_12].
|
||||
return (instr & 0x0f7f0000) == 0x051f0000;
|
||||
return (instr & (kLdrPCMask & ~kCondMask)) == 0x051f0000;
|
||||
}
|
||||
|
||||
|
||||
@ -532,13 +482,14 @@ const int kEndOfChain = -4;
|
||||
|
||||
int Assembler::target_at(int pos) {
|
||||
Instr instr = instr_at(pos);
|
||||
if ((instr & ~Imm24Mask) == 0) {
|
||||
if ((instr & ~kImm24Mask) == 0) {
|
||||
// Emitted label constant, not part of a branch.
|
||||
return instr - (Code::kHeaderSize - kHeapObjectTag);
|
||||
}
|
||||
ASSERT((instr & 7*B25) == 5*B25); // b, bl, or blx imm24
|
||||
int imm26 = ((instr & Imm24Mask) << 8) >> 6;
|
||||
if ((instr & CondMask) == nv && (instr & B24) != 0) {
|
||||
int imm26 = ((instr & kImm24Mask) << 8) >> 6;
|
||||
if ((Instruction::ConditionField(instr) == kSpecialCondition) &&
|
||||
((instr & B24) != 0)) {
|
||||
// blx uses bit 24 to encode bit 2 of imm26
|
||||
imm26 += 2;
|
||||
}
|
||||
@ -548,7 +499,7 @@ int Assembler::target_at(int pos) {
|
||||
|
||||
void Assembler::target_at_put(int pos, int target_pos) {
|
||||
Instr instr = instr_at(pos);
|
||||
if ((instr & ~Imm24Mask) == 0) {
|
||||
if ((instr & ~kImm24Mask) == 0) {
|
||||
ASSERT(target_pos == kEndOfChain || target_pos >= 0);
|
||||
// Emitted label constant, not part of a branch.
|
||||
// Make label relative to Code* of generated Code object.
|
||||
@ -557,17 +508,17 @@ void Assembler::target_at_put(int pos, int target_pos) {
|
||||
}
|
||||
int imm26 = target_pos - (pos + kPcLoadDelta);
|
||||
ASSERT((instr & 7*B25) == 5*B25); // b, bl, or blx imm24
|
||||
if ((instr & CondMask) == nv) {
|
||||
if (Instruction::ConditionField(instr) == kSpecialCondition) {
|
||||
// blx uses bit 24 to encode bit 2 of imm26
|
||||
ASSERT((imm26 & 1) == 0);
|
||||
instr = (instr & ~(B24 | Imm24Mask)) | ((imm26 & 2) >> 1)*B24;
|
||||
instr = (instr & ~(B24 | kImm24Mask)) | ((imm26 & 2) >> 1)*B24;
|
||||
} else {
|
||||
ASSERT((imm26 & 3) == 0);
|
||||
instr &= ~Imm24Mask;
|
||||
instr &= ~kImm24Mask;
|
||||
}
|
||||
int imm24 = imm26 >> 2;
|
||||
ASSERT(is_int24(imm24));
|
||||
instr_at_put(pos, instr | (imm24 & Imm24Mask));
|
||||
instr_at_put(pos, instr | (imm24 & kImm24Mask));
|
||||
}
|
||||
|
||||
|
||||
@ -582,14 +533,14 @@ void Assembler::print(Label* L) {
|
||||
while (l.is_linked()) {
|
||||
PrintF("@ %d ", l.pos());
|
||||
Instr instr = instr_at(l.pos());
|
||||
if ((instr & ~Imm24Mask) == 0) {
|
||||
if ((instr & ~kImm24Mask) == 0) {
|
||||
PrintF("value\n");
|
||||
} else {
|
||||
ASSERT((instr & 7*B25) == 5*B25); // b, bl, or blx
|
||||
int cond = instr & CondMask;
|
||||
Condition cond = Instruction::ConditionField(instr);
|
||||
const char* b;
|
||||
const char* c;
|
||||
if (cond == nv) {
|
||||
if (cond == kSpecialCondition) {
|
||||
b = "blx";
|
||||
c = "";
|
||||
} else {
|
||||
@ -731,14 +682,14 @@ static bool fits_shifter(uint32_t imm32,
|
||||
}
|
||||
} else {
|
||||
Instr alu_insn = (*instr & kALUMask);
|
||||
if (alu_insn == kAddPattern ||
|
||||
alu_insn == kSubPattern) {
|
||||
if (alu_insn == ADD ||
|
||||
alu_insn == SUB) {
|
||||
if (fits_shifter(-imm32, rotate_imm, immed_8, NULL)) {
|
||||
*instr ^= kAddSubFlip;
|
||||
return true;
|
||||
}
|
||||
} else if (alu_insn == kAndPattern ||
|
||||
alu_insn == kBicPattern) {
|
||||
} else if (alu_insn == AND ||
|
||||
alu_insn == BIC) {
|
||||
if (fits_shifter(~imm32, rotate_imm, immed_8, NULL)) {
|
||||
*instr ^= kAndBicFlip;
|
||||
return true;
|
||||
@ -782,7 +733,7 @@ void Assembler::addrmod1(Instr instr,
|
||||
Register rd,
|
||||
const Operand& x) {
|
||||
CheckBuffer();
|
||||
ASSERT((instr & ~(CondMask | OpCodeMask | S)) == 0);
|
||||
ASSERT((instr & ~(kCondMask | kOpCodeMask | S)) == 0);
|
||||
if (!x.rm_.is_valid()) {
|
||||
// Immediate.
|
||||
uint32_t rotate_imm;
|
||||
@ -794,8 +745,8 @@ void Assembler::addrmod1(Instr instr,
|
||||
// However, if the original instruction is a 'mov rd, x' (not setting the
|
||||
// condition code), then replace it with a 'ldr rd, [pc]'.
|
||||
CHECK(!rn.is(ip)); // rn should never be ip, or will be trashed
|
||||
Condition cond = static_cast<Condition>(instr & CondMask);
|
||||
if ((instr & ~CondMask) == 13*B21) { // mov, S not set
|
||||
Condition cond = Instruction::ConditionField(instr);
|
||||
if ((instr & ~kCondMask) == 13*B21) { // mov, S not set
|
||||
if (x.must_use_constant_pool() || !CpuFeatures::IsSupported(ARMv7)) {
|
||||
RecordRelocInfo(x.rmode_, x.imm32_);
|
||||
ldr(rd, MemOperand(pc, 0), cond);
|
||||
@ -836,7 +787,7 @@ void Assembler::addrmod1(Instr instr,
|
||||
|
||||
|
||||
void Assembler::addrmod2(Instr instr, Register rd, const MemOperand& x) {
|
||||
ASSERT((instr & ~(CondMask | B | L)) == B26);
|
||||
ASSERT((instr & ~(kCondMask | B | L)) == B26);
|
||||
int am = x.am_;
|
||||
if (!x.rm_.is_valid()) {
|
||||
// Immediate offset.
|
||||
@ -849,8 +800,7 @@ void Assembler::addrmod2(Instr instr, Register rd, const MemOperand& x) {
|
||||
// Immediate offset cannot be encoded, load it first to register ip
|
||||
// rn (and rd in a load) should never be ip, or will be trashed.
|
||||
ASSERT(!x.rn_.is(ip) && ((instr & L) == L || !rd.is(ip)));
|
||||
mov(ip, Operand(x.offset_), LeaveCC,
|
||||
static_cast<Condition>(instr & CondMask));
|
||||
mov(ip, Operand(x.offset_), LeaveCC, Instruction::ConditionField(instr));
|
||||
addrmod2(instr, rd, MemOperand(x.rn_, ip, x.am_));
|
||||
return;
|
||||
}
|
||||
@ -869,7 +819,7 @@ void Assembler::addrmod2(Instr instr, Register rd, const MemOperand& x) {
|
||||
|
||||
|
||||
void Assembler::addrmod3(Instr instr, Register rd, const MemOperand& x) {
|
||||
ASSERT((instr & ~(CondMask | L | S6 | H)) == (B4 | B7));
|
||||
ASSERT((instr & ~(kCondMask | L | S6 | H)) == (B4 | B7));
|
||||
ASSERT(x.rn_.is_valid());
|
||||
int am = x.am_;
|
||||
if (!x.rm_.is_valid()) {
|
||||
@ -883,8 +833,7 @@ void Assembler::addrmod3(Instr instr, Register rd, const MemOperand& x) {
|
||||
// Immediate offset cannot be encoded, load it first to register ip
|
||||
// rn (and rd in a load) should never be ip, or will be trashed.
|
||||
ASSERT(!x.rn_.is(ip) && ((instr & L) == L || !rd.is(ip)));
|
||||
mov(ip, Operand(x.offset_), LeaveCC,
|
||||
static_cast<Condition>(instr & CondMask));
|
||||
mov(ip, Operand(x.offset_), LeaveCC, Instruction::ConditionField(instr));
|
||||
addrmod3(instr, rd, MemOperand(x.rn_, ip, x.am_));
|
||||
return;
|
||||
}
|
||||
@ -895,7 +844,7 @@ void Assembler::addrmod3(Instr instr, Register rd, const MemOperand& x) {
|
||||
// rn (and rd in a load) should never be ip, or will be trashed.
|
||||
ASSERT(!x.rn_.is(ip) && ((instr & L) == L || !rd.is(ip)));
|
||||
mov(ip, Operand(x.rm_, x.shift_op_, x.shift_imm_), LeaveCC,
|
||||
static_cast<Condition>(instr & CondMask));
|
||||
Instruction::ConditionField(instr));
|
||||
addrmod3(instr, rd, MemOperand(x.rn_, ip, x.am_));
|
||||
return;
|
||||
} else {
|
||||
@ -909,7 +858,7 @@ void Assembler::addrmod3(Instr instr, Register rd, const MemOperand& x) {
|
||||
|
||||
|
||||
void Assembler::addrmod4(Instr instr, Register rn, RegList rl) {
|
||||
ASSERT((instr & ~(CondMask | P | U | W | L)) == B27);
|
||||
ASSERT((instr & ~(kCondMask | P | U | W | L)) == B27);
|
||||
ASSERT(rl != 0);
|
||||
ASSERT(!rn.is(pc));
|
||||
emit(instr | rn.code()*B16 | rl);
|
||||
@ -919,7 +868,7 @@ void Assembler::addrmod4(Instr instr, Register rn, RegList rl) {
|
||||
void Assembler::addrmod5(Instr instr, CRegister crd, const MemOperand& x) {
|
||||
// Unindexed addressing is not encoded by this function.
|
||||
ASSERT_EQ((B27 | B26),
|
||||
(instr & ~(CondMask | CoprocessorMask | P | U | N | W | L)));
|
||||
(instr & ~(kCondMask | kCoprocessorMask | P | U | N | W | L)));
|
||||
ASSERT(x.rn_.is_valid() && !x.rm_.is_valid());
|
||||
int am = x.am_;
|
||||
int offset_8 = x.offset_;
|
||||
@ -982,7 +931,7 @@ void Assembler::b(int branch_offset, Condition cond) {
|
||||
ASSERT((branch_offset & 3) == 0);
|
||||
int imm24 = branch_offset >> 2;
|
||||
ASSERT(is_int24(imm24));
|
||||
emit(cond | B27 | B25 | (imm24 & Imm24Mask));
|
||||
emit(cond | B27 | B25 | (imm24 & kImm24Mask));
|
||||
|
||||
if (cond == al) {
|
||||
// Dead code is a good location to emit the constant pool.
|
||||
@ -996,7 +945,7 @@ void Assembler::bl(int branch_offset, Condition cond) {
|
||||
ASSERT((branch_offset & 3) == 0);
|
||||
int imm24 = branch_offset >> 2;
|
||||
ASSERT(is_int24(imm24));
|
||||
emit(cond | B27 | B25 | B24 | (imm24 & Imm24Mask));
|
||||
emit(cond | B27 | B25 | B24 | (imm24 & kImm24Mask));
|
||||
}
|
||||
|
||||
|
||||
@ -1006,21 +955,21 @@ void Assembler::blx(int branch_offset) { // v5 and above
|
||||
int h = ((branch_offset & 2) >> 1)*B24;
|
||||
int imm24 = branch_offset >> 2;
|
||||
ASSERT(is_int24(imm24));
|
||||
emit(nv | B27 | B25 | h | (imm24 & Imm24Mask));
|
||||
emit(kSpecialCondition | B27 | B25 | h | (imm24 & kImm24Mask));
|
||||
}
|
||||
|
||||
|
||||
void Assembler::blx(Register target, Condition cond) { // v5 and above
|
||||
positions_recorder()->WriteRecordedPositions();
|
||||
ASSERT(!target.is(pc));
|
||||
emit(cond | B24 | B21 | 15*B16 | 15*B12 | 15*B8 | 3*B4 | target.code());
|
||||
emit(cond | B24 | B21 | 15*B16 | 15*B12 | 15*B8 | BLX | target.code());
|
||||
}
|
||||
|
||||
|
||||
void Assembler::bx(Register target, Condition cond) { // v5 and above, plus v4t
|
||||
positions_recorder()->WriteRecordedPositions();
|
||||
ASSERT(!target.is(pc)); // use of pc is actually allowed, but discouraged
|
||||
emit(cond | B24 | B21 | 15*B16 | 15*B12 | 15*B8 | B4 | target.code());
|
||||
emit(cond | B24 | B21 | 15*B16 | 15*B12 | 15*B8 | BX | target.code());
|
||||
}
|
||||
|
||||
|
||||
@ -1028,31 +977,31 @@ void Assembler::bx(Register target, Condition cond) { // v5 and above, plus v4t
|
||||
|
||||
void Assembler::and_(Register dst, Register src1, const Operand& src2,
|
||||
SBit s, Condition cond) {
|
||||
addrmod1(cond | 0*B21 | s, src1, dst, src2);
|
||||
addrmod1(cond | AND | s, src1, dst, src2);
|
||||
}
|
||||
|
||||
|
||||
void Assembler::eor(Register dst, Register src1, const Operand& src2,
|
||||
SBit s, Condition cond) {
|
||||
addrmod1(cond | 1*B21 | s, src1, dst, src2);
|
||||
addrmod1(cond | EOR | s, src1, dst, src2);
|
||||
}
|
||||
|
||||
|
||||
void Assembler::sub(Register dst, Register src1, const Operand& src2,
|
||||
SBit s, Condition cond) {
|
||||
addrmod1(cond | 2*B21 | s, src1, dst, src2);
|
||||
addrmod1(cond | SUB | s, src1, dst, src2);
|
||||
}
|
||||
|
||||
|
||||
void Assembler::rsb(Register dst, Register src1, const Operand& src2,
|
||||
SBit s, Condition cond) {
|
||||
addrmod1(cond | 3*B21 | s, src1, dst, src2);
|
||||
addrmod1(cond | RSB | s, src1, dst, src2);
|
||||
}
|
||||
|
||||
|
||||
void Assembler::add(Register dst, Register src1, const Operand& src2,
|
||||
SBit s, Condition cond) {
|
||||
addrmod1(cond | 4*B21 | s, src1, dst, src2);
|
||||
addrmod1(cond | ADD | s, src1, dst, src2);
|
||||
|
||||
// Eliminate pattern: push(r), pop()
|
||||
// str(src, MemOperand(sp, 4, NegPreIndex), al);
|
||||
@ -1061,7 +1010,7 @@ void Assembler::add(Register dst, Register src1, const Operand& src2,
|
||||
if (can_peephole_optimize(2) &&
|
||||
// Pattern.
|
||||
instr_at(pc_ - 1 * kInstrSize) == kPopInstruction &&
|
||||
(instr_at(pc_ - 2 * kInstrSize) & ~RdMask) == kPushRegPattern) {
|
||||
(instr_at(pc_ - 2 * kInstrSize) & ~kRdMask) == kPushRegPattern) {
|
||||
pc_ -= 2 * kInstrSize;
|
||||
if (FLAG_print_peephole_optimization) {
|
||||
PrintF("%x push(reg)/pop() eliminated\n", pc_offset());
|
||||
@ -1072,45 +1021,45 @@ void Assembler::add(Register dst, Register src1, const Operand& src2,
|
||||
|
||||
void Assembler::adc(Register dst, Register src1, const Operand& src2,
|
||||
SBit s, Condition cond) {
|
||||
addrmod1(cond | 5*B21 | s, src1, dst, src2);
|
||||
addrmod1(cond | ADC | s, src1, dst, src2);
|
||||
}
|
||||
|
||||
|
||||
void Assembler::sbc(Register dst, Register src1, const Operand& src2,
|
||||
SBit s, Condition cond) {
|
||||
addrmod1(cond | 6*B21 | s, src1, dst, src2);
|
||||
addrmod1(cond | SBC | s, src1, dst, src2);
|
||||
}
|
||||
|
||||
|
||||
void Assembler::rsc(Register dst, Register src1, const Operand& src2,
|
||||
SBit s, Condition cond) {
|
||||
addrmod1(cond | 7*B21 | s, src1, dst, src2);
|
||||
addrmod1(cond | RSC | s, src1, dst, src2);
|
||||
}
|
||||
|
||||
|
||||
void Assembler::tst(Register src1, const Operand& src2, Condition cond) {
|
||||
addrmod1(cond | 8*B21 | S, src1, r0, src2);
|
||||
addrmod1(cond | TST | S, src1, r0, src2);
|
||||
}
|
||||
|
||||
|
||||
void Assembler::teq(Register src1, const Operand& src2, Condition cond) {
|
||||
addrmod1(cond | 9*B21 | S, src1, r0, src2);
|
||||
addrmod1(cond | TEQ | S, src1, r0, src2);
|
||||
}
|
||||
|
||||
|
||||
void Assembler::cmp(Register src1, const Operand& src2, Condition cond) {
|
||||
addrmod1(cond | 10*B21 | S, src1, r0, src2);
|
||||
addrmod1(cond | CMP | S, src1, r0, src2);
|
||||
}
|
||||
|
||||
|
||||
void Assembler::cmn(Register src1, const Operand& src2, Condition cond) {
|
||||
addrmod1(cond | 11*B21 | S, src1, r0, src2);
|
||||
addrmod1(cond | CMN | S, src1, r0, src2);
|
||||
}
|
||||
|
||||
|
||||
void Assembler::orr(Register dst, Register src1, const Operand& src2,
|
||||
SBit s, Condition cond) {
|
||||
addrmod1(cond | 12*B21 | s, src1, dst, src2);
|
||||
addrmod1(cond | ORR | s, src1, dst, src2);
|
||||
}
|
||||
|
||||
|
||||
@ -1122,7 +1071,7 @@ void Assembler::mov(Register dst, const Operand& src, SBit s, Condition cond) {
|
||||
// the mov instruction. They must be generated using nop(int/NopMarkerTypes)
|
||||
// or MarkCode(int/NopMarkerTypes) pseudo instructions.
|
||||
ASSERT(!(src.is_reg() && src.rm().is(dst) && s == LeaveCC && cond == al));
|
||||
addrmod1(cond | 13*B21 | s, r0, dst, src);
|
||||
addrmod1(cond | MOV | s, r0, dst, src);
|
||||
}
|
||||
|
||||
|
||||
@ -1139,12 +1088,12 @@ void Assembler::movt(Register reg, uint32_t immediate, Condition cond) {
|
||||
|
||||
void Assembler::bic(Register dst, Register src1, const Operand& src2,
|
||||
SBit s, Condition cond) {
|
||||
addrmod1(cond | 14*B21 | s, src1, dst, src2);
|
||||
addrmod1(cond | BIC | s, src1, dst, src2);
|
||||
}
|
||||
|
||||
|
||||
void Assembler::mvn(Register dst, const Operand& src, SBit s, Condition cond) {
|
||||
addrmod1(cond | 15*B21 | s, r0, dst, src);
|
||||
addrmod1(cond | MVN | s, r0, dst, src);
|
||||
}
|
||||
|
||||
|
||||
@ -1222,7 +1171,7 @@ void Assembler::clz(Register dst, Register src, Condition cond) {
|
||||
// v5 and above.
|
||||
ASSERT(!dst.is(pc) && !src.is(pc));
|
||||
emit(cond | B24 | B22 | B21 | 15*B16 | dst.code()*B12 |
|
||||
15*B8 | B4 | src.code());
|
||||
15*B8 | CLZ | src.code());
|
||||
}
|
||||
|
||||
|
||||
@ -1376,7 +1325,7 @@ void Assembler::ldr(Register dst, const MemOperand& src, Condition cond) {
|
||||
Instr pop_instr = instr_at(pc_ - 1 * kInstrSize);
|
||||
|
||||
if (IsPush(push_instr) && IsPop(pop_instr)) {
|
||||
if ((pop_instr & kRdMask) != (push_instr & kRdMask)) {
|
||||
if (Instruction::RdValue(pop_instr) != Instruction::RdValue(push_instr)) {
|
||||
// For consecutive push and pop on different registers,
|
||||
// we delete both the push & pop and insert a register move.
|
||||
// push ry, pop rx --> mov rx, ry
|
||||
@ -1457,8 +1406,8 @@ void Assembler::ldr(Register dst, const MemOperand& src, Condition cond) {
|
||||
IsPop(mem_read_instr)) {
|
||||
if ((IsLdrRegFpOffset(ldr_instr) ||
|
||||
IsLdrRegFpNegOffset(ldr_instr))) {
|
||||
if ((mem_write_instr & kRdMask) ==
|
||||
(mem_read_instr & kRdMask)) {
|
||||
if (Instruction::RdValue(mem_write_instr) ==
|
||||
Instruction::RdValue(mem_read_instr)) {
|
||||
// Pattern: push & pop from/to same register,
|
||||
// with a fp+offset ldr in between
|
||||
//
|
||||
@ -1473,7 +1422,8 @@ void Assembler::ldr(Register dst, const MemOperand& src, Condition cond) {
|
||||
// else
|
||||
// ldr rz, [fp, #-24]
|
||||
|
||||
if ((mem_write_instr & kRdMask) == (ldr_instr & kRdMask)) {
|
||||
if (Instruction::RdValue(mem_write_instr) ==
|
||||
Instruction::RdValue(ldr_instr)) {
|
||||
pc_ -= 3 * kInstrSize;
|
||||
} else {
|
||||
pc_ -= 3 * kInstrSize;
|
||||
@ -1503,22 +1453,23 @@ void Assembler::ldr(Register dst, const MemOperand& src, Condition cond) {
|
||||
// ldr rz, [fp, #-24]
|
||||
|
||||
Register reg_pushed, reg_popped;
|
||||
if ((mem_read_instr & kRdMask) == (ldr_instr & kRdMask)) {
|
||||
if (Instruction::RdValue(mem_read_instr) ==
|
||||
Instruction::RdValue(ldr_instr)) {
|
||||
reg_pushed = GetRd(mem_write_instr);
|
||||
reg_popped = GetRd(mem_read_instr);
|
||||
pc_ -= 3 * kInstrSize;
|
||||
mov(reg_popped, reg_pushed);
|
||||
} else if ((mem_write_instr & kRdMask)
|
||||
!= (ldr_instr & kRdMask)) {
|
||||
} else if (Instruction::RdValue(mem_write_instr) !=
|
||||
Instruction::RdValue(ldr_instr)) {
|
||||
reg_pushed = GetRd(mem_write_instr);
|
||||
reg_popped = GetRd(mem_read_instr);
|
||||
pc_ -= 3 * kInstrSize;
|
||||
emit(ldr_instr);
|
||||
mov(reg_popped, reg_pushed);
|
||||
} else if (((mem_read_instr & kRdMask)
|
||||
!= (ldr_instr & kRdMask)) ||
|
||||
((mem_write_instr & kRdMask)
|
||||
== (ldr_instr & kRdMask)) ) {
|
||||
} else if ((Instruction::RdValue(mem_read_instr) !=
|
||||
Instruction::RdValue(ldr_instr)) ||
|
||||
(Instruction::RdValue(mem_write_instr) ==
|
||||
Instruction::RdValue(ldr_instr))) {
|
||||
reg_pushed = GetRd(mem_write_instr);
|
||||
reg_popped = GetRd(mem_read_instr);
|
||||
pc_ -= 3 * kInstrSize;
|
||||
@ -1640,18 +1591,14 @@ void Assembler::stm(BlockAddrMode am,
|
||||
// enabling/disabling and a counter feature. See simulator-arm.h .
|
||||
void Assembler::stop(const char* msg, Condition cond, int32_t code) {
|
||||
#ifndef __arm__
|
||||
// See constants-arm.h SoftwareInterruptCodes. Unluckily the Assembler and
|
||||
// Simulator do not share constants declaration.
|
||||
ASSERT(code >= kDefaultStopCode);
|
||||
static const uint32_t kStopInterruptCode = 1 << 23;
|
||||
static const uint32_t kMaxStopCode = kStopInterruptCode - 1;
|
||||
// The Simulator will handle the stop instruction and get the message address.
|
||||
// It expects to find the address just after the svc instruction.
|
||||
BlockConstPoolFor(2);
|
||||
if (code >= 0) {
|
||||
svc(kStopInterruptCode + code, cond);
|
||||
svc(kStopCode + code, cond);
|
||||
} else {
|
||||
svc(kStopInterruptCode + kMaxStopCode, cond);
|
||||
svc(kStopCode + kMaxStopCode, cond);
|
||||
}
|
||||
emit(reinterpret_cast<Instr>(msg));
|
||||
#else // def __arm__
|
||||
@ -1673,7 +1620,7 @@ void Assembler::stop(const char* msg, Condition cond, int32_t code) {
|
||||
|
||||
void Assembler::bkpt(uint32_t imm16) { // v5 and above
|
||||
ASSERT(is_uint16(imm16));
|
||||
emit(al | B24 | B21 | (imm16 >> 4)*B8 | 7*B4 | (imm16 & 0xf));
|
||||
emit(al | B24 | B21 | (imm16 >> 4)*B8 | BKPT | (imm16 & 0xf));
|
||||
}
|
||||
|
||||
|
||||
@ -1703,7 +1650,7 @@ void Assembler::cdp2(Coprocessor coproc,
|
||||
CRegister crn,
|
||||
CRegister crm,
|
||||
int opcode_2) { // v5 and above
|
||||
cdp(coproc, opcode_1, crd, crn, crm, opcode_2, static_cast<Condition>(nv));
|
||||
cdp(coproc, opcode_1, crd, crn, crm, opcode_2, kSpecialCondition);
|
||||
}
|
||||
|
||||
|
||||
@ -1726,7 +1673,7 @@ void Assembler::mcr2(Coprocessor coproc,
|
||||
CRegister crn,
|
||||
CRegister crm,
|
||||
int opcode_2) { // v5 and above
|
||||
mcr(coproc, opcode_1, rd, crn, crm, opcode_2, static_cast<Condition>(nv));
|
||||
mcr(coproc, opcode_1, rd, crn, crm, opcode_2, kSpecialCondition);
|
||||
}
|
||||
|
||||
|
||||
@ -1749,7 +1696,7 @@ void Assembler::mrc2(Coprocessor coproc,
|
||||
CRegister crn,
|
||||
CRegister crm,
|
||||
int opcode_2) { // v5 and above
|
||||
mrc(coproc, opcode_1, rd, crn, crm, opcode_2, static_cast<Condition>(nv));
|
||||
mrc(coproc, opcode_1, rd, crn, crm, opcode_2, kSpecialCondition);
|
||||
}
|
||||
|
||||
|
||||
@ -1779,7 +1726,7 @@ void Assembler::ldc2(Coprocessor coproc,
|
||||
CRegister crd,
|
||||
const MemOperand& src,
|
||||
LFlag l) { // v5 and above
|
||||
ldc(coproc, crd, src, l, static_cast<Condition>(nv));
|
||||
ldc(coproc, crd, src, l, kSpecialCondition);
|
||||
}
|
||||
|
||||
|
||||
@ -1788,7 +1735,7 @@ void Assembler::ldc2(Coprocessor coproc,
|
||||
Register rn,
|
||||
int option,
|
||||
LFlag l) { // v5 and above
|
||||
ldc(coproc, crd, rn, option, l, static_cast<Condition>(nv));
|
||||
ldc(coproc, crd, rn, option, l, kSpecialCondition);
|
||||
}
|
||||
|
||||
|
||||
@ -1818,7 +1765,7 @@ void Assembler::stc2(Coprocessor
|
||||
coproc, CRegister crd,
|
||||
const MemOperand& dst,
|
||||
LFlag l) { // v5 and above
|
||||
stc(coproc, crd, dst, l, static_cast<Condition>(nv));
|
||||
stc(coproc, crd, dst, l, kSpecialCondition);
|
||||
}
|
||||
|
||||
|
||||
@ -1827,7 +1774,7 @@ void Assembler::stc2(Coprocessor coproc,
|
||||
Register rn,
|
||||
int option,
|
||||
LFlag l) { // v5 and above
|
||||
stc(coproc, crd, rn, option, l, static_cast<Condition>(nv));
|
||||
stc(coproc, crd, rn, option, l, kSpecialCondition);
|
||||
}
|
||||
|
||||
|
||||
@ -2637,7 +2584,7 @@ void Assembler::CheckConstPool(bool force_emit, bool require_jump) {
|
||||
|
||||
// Instruction to patch must be a ldr/str [pc, #offset].
|
||||
// P and U set, B and W clear, Rn == pc, offset12 still 0.
|
||||
ASSERT((instr & (7*B25 | P | U | B | W | 15*B16 | Off12Mask)) ==
|
||||
ASSERT((instr & (7*B25 | P | U | B | W | 15*B16 | kOff12Mask)) ==
|
||||
(2*B25 | P | U | pc.code()*B16));
|
||||
int delta = pc_ - rinfo.pc() - 8;
|
||||
ASSERT(delta >= -4); // instr could be ldr pc, [pc, #-4] followed by targ32
|
||||
|
@ -41,6 +41,7 @@
|
||||
#define V8_ARM_ASSEMBLER_ARM_H_
|
||||
#include <stdio.h>
|
||||
#include "assembler.h"
|
||||
#include "constants-arm.h"
|
||||
#include "serialize.h"
|
||||
|
||||
namespace v8 {
|
||||
@ -300,18 +301,6 @@ const DwVfpRegister d13 = { 13 };
|
||||
const DwVfpRegister d14 = { 14 };
|
||||
const DwVfpRegister d15 = { 15 };
|
||||
|
||||
// VFP FPSCR constants.
|
||||
static const uint32_t kVFPNConditionFlagBit = 1 << 31;
|
||||
static const uint32_t kVFPZConditionFlagBit = 1 << 30;
|
||||
static const uint32_t kVFPCConditionFlagBit = 1 << 29;
|
||||
static const uint32_t kVFPVConditionFlagBit = 1 << 28;
|
||||
|
||||
static const uint32_t kVFPFlushToZeroMask = 1 << 24;
|
||||
|
||||
static const uint32_t kVFPRoundingModeMask = 3 << 22;
|
||||
static const uint32_t kVFPRoundToMinusInfinityBits = 2 << 22;
|
||||
|
||||
static const uint32_t kVFPExceptionMask = 0xf;
|
||||
|
||||
// Coprocessor register
|
||||
struct CRegister {
|
||||
@ -372,149 +361,6 @@ enum Coprocessor {
|
||||
};
|
||||
|
||||
|
||||
// Condition field in instructions.
|
||||
enum Condition {
|
||||
// any value < 0 is considered no_condition
|
||||
no_condition = -1,
|
||||
|
||||
eq = 0 << 28, // Z set equal.
|
||||
ne = 1 << 28, // Z clear not equal.
|
||||
nz = 1 << 28, // Z clear not zero.
|
||||
cs = 2 << 28, // C set carry set.
|
||||
hs = 2 << 28, // C set unsigned higher or same.
|
||||
cc = 3 << 28, // C clear carry clear.
|
||||
lo = 3 << 28, // C clear unsigned lower.
|
||||
mi = 4 << 28, // N set negative.
|
||||
pl = 5 << 28, // N clear positive or zero.
|
||||
vs = 6 << 28, // V set overflow.
|
||||
vc = 7 << 28, // V clear no overflow.
|
||||
hi = 8 << 28, // C set, Z clear unsigned higher.
|
||||
ls = 9 << 28, // C clear or Z set unsigned lower or same.
|
||||
ge = 10 << 28, // N == V greater or equal.
|
||||
lt = 11 << 28, // N != V less than.
|
||||
gt = 12 << 28, // Z clear, N == V greater than.
|
||||
le = 13 << 28, // Z set or N != V less then or equal
|
||||
al = 14 << 28 // always.
|
||||
};
|
||||
|
||||
|
||||
// Returns the equivalent of !cc.
|
||||
inline Condition NegateCondition(Condition cc) {
|
||||
ASSERT(cc != al);
|
||||
return static_cast<Condition>(cc ^ ne);
|
||||
}
|
||||
|
||||
|
||||
// Corresponds to transposing the operands of a comparison.
|
||||
inline Condition ReverseCondition(Condition cc) {
|
||||
switch (cc) {
|
||||
case lo:
|
||||
return hi;
|
||||
case hi:
|
||||
return lo;
|
||||
case hs:
|
||||
return ls;
|
||||
case ls:
|
||||
return hs;
|
||||
case lt:
|
||||
return gt;
|
||||
case gt:
|
||||
return lt;
|
||||
case ge:
|
||||
return le;
|
||||
case le:
|
||||
return ge;
|
||||
default:
|
||||
return cc;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
// Branch hints are not used on the ARM. They are defined so that they can
|
||||
// appear in shared function signatures, but will be ignored in ARM
|
||||
// implementations.
|
||||
enum Hint { no_hint };
|
||||
|
||||
// Hints are not used on the arm. Negating is trivial.
|
||||
inline Hint NegateHint(Hint ignored) { return no_hint; }
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Addressing modes and instruction variants
|
||||
|
||||
// Shifter operand shift operation
|
||||
enum ShiftOp {
|
||||
LSL = 0 << 5,
|
||||
LSR = 1 << 5,
|
||||
ASR = 2 << 5,
|
||||
ROR = 3 << 5,
|
||||
RRX = -1
|
||||
};
|
||||
|
||||
|
||||
// Condition code updating mode
|
||||
enum SBit {
|
||||
SetCC = 1 << 20, // set condition code
|
||||
LeaveCC = 0 << 20 // leave condition code unchanged
|
||||
};
|
||||
|
||||
|
||||
// Status register selection
|
||||
enum SRegister {
|
||||
CPSR = 0 << 22,
|
||||
SPSR = 1 << 22
|
||||
};
|
||||
|
||||
|
||||
// Status register fields
|
||||
enum SRegisterField {
|
||||
CPSR_c = CPSR | 1 << 16,
|
||||
CPSR_x = CPSR | 1 << 17,
|
||||
CPSR_s = CPSR | 1 << 18,
|
||||
CPSR_f = CPSR | 1 << 19,
|
||||
SPSR_c = SPSR | 1 << 16,
|
||||
SPSR_x = SPSR | 1 << 17,
|
||||
SPSR_s = SPSR | 1 << 18,
|
||||
SPSR_f = SPSR | 1 << 19
|
||||
};
|
||||
|
||||
// Status register field mask (or'ed SRegisterField enum values)
|
||||
typedef uint32_t SRegisterFieldMask;
|
||||
|
||||
|
||||
// Memory operand addressing mode
|
||||
enum AddrMode {
|
||||
// bit encoding P U W
|
||||
Offset = (8|4|0) << 21, // offset (without writeback to base)
|
||||
PreIndex = (8|4|1) << 21, // pre-indexed addressing with writeback
|
||||
PostIndex = (0|4|0) << 21, // post-indexed addressing with writeback
|
||||
NegOffset = (8|0|0) << 21, // negative offset (without writeback to base)
|
||||
NegPreIndex = (8|0|1) << 21, // negative pre-indexed with writeback
|
||||
NegPostIndex = (0|0|0) << 21 // negative post-indexed with writeback
|
||||
};
|
||||
|
||||
|
||||
// Load/store multiple addressing mode
|
||||
enum BlockAddrMode {
|
||||
// bit encoding P U W
|
||||
da = (0|0|0) << 21, // decrement after
|
||||
ia = (0|4|0) << 21, // increment after
|
||||
db = (8|0|0) << 21, // decrement before
|
||||
ib = (8|4|0) << 21, // increment before
|
||||
da_w = (0|0|1) << 21, // decrement after with writeback to base
|
||||
ia_w = (0|4|1) << 21, // increment after with writeback to base
|
||||
db_w = (8|0|1) << 21, // decrement before with writeback to base
|
||||
ib_w = (8|4|1) << 21 // increment before with writeback to base
|
||||
};
|
||||
|
||||
|
||||
// Coprocessor load/store operand size
|
||||
enum LFlag {
|
||||
Long = 1 << 22, // long load/store coprocessor
|
||||
Short = 0 << 22 // short load/store coprocessor
|
||||
};
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Machine instruction Operands
|
||||
|
||||
@ -658,9 +504,6 @@ class CpuFeatures : public AllStatic {
|
||||
};
|
||||
|
||||
|
||||
typedef int32_t Instr;
|
||||
|
||||
|
||||
extern const Instr kMovLrPc;
|
||||
extern const Instr kLdrPCMask;
|
||||
extern const Instr kLdrPCPattern;
|
||||
@ -680,15 +523,11 @@ extern const Instr kMovwLeaveCCFlip;
|
||||
extern const Instr kCmpCmnMask;
|
||||
extern const Instr kCmpCmnPattern;
|
||||
extern const Instr kCmpCmnFlip;
|
||||
|
||||
extern const Instr kALUMask;
|
||||
extern const Instr kAddPattern;
|
||||
extern const Instr kSubPattern;
|
||||
extern const Instr kAndPattern;
|
||||
extern const Instr kBicPattern;
|
||||
extern const Instr kAddSubFlip;
|
||||
extern const Instr kAndBicFlip;
|
||||
|
||||
|
||||
|
||||
class Assembler : public Malloced {
|
||||
public:
|
||||
// Create an assembler. Instructions and relocation information are emitted
|
||||
@ -1001,7 +840,6 @@ class Assembler : public Malloced {
|
||||
void stm(BlockAddrMode am, Register base, RegList src, Condition cond = al);
|
||||
|
||||
// Exception-generating instructions and debugging support
|
||||
static const int kDefaultStopCode = -1;
|
||||
void stop(const char* msg,
|
||||
Condition cond = al,
|
||||
int32_t code = kDefaultStopCode);
|
||||
|
@ -190,7 +190,7 @@ static void AllocateJSArray(MacroAssembler* masm,
|
||||
|
||||
// Check whether an empty sized array is requested.
|
||||
__ tst(array_size, array_size);
|
||||
__ b(nz, ¬_empty);
|
||||
__ b(ne, ¬_empty);
|
||||
|
||||
// If an empty array is requested allocate a small elements array anyway. This
|
||||
// keeps the code below free of special casing for the empty array.
|
||||
@ -666,7 +666,7 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
|
||||
__ mov(r2, Operand(debug_step_in_fp));
|
||||
__ ldr(r2, MemOperand(r2));
|
||||
__ tst(r2, r2);
|
||||
__ b(nz, &rt_call);
|
||||
__ b(ne, &rt_call);
|
||||
#endif
|
||||
|
||||
// Load the initial map and verify that it is in fact a map.
|
||||
|
@ -41,7 +41,7 @@ namespace internal {
|
||||
|
||||
static void EmitIdenticalObjectComparison(MacroAssembler* masm,
|
||||
Label* slow,
|
||||
Condition cc,
|
||||
Condition cond,
|
||||
bool never_nan_nan);
|
||||
static void EmitSmiNonsmiComparison(MacroAssembler* masm,
|
||||
Register lhs,
|
||||
@ -49,7 +49,7 @@ static void EmitSmiNonsmiComparison(MacroAssembler* masm,
|
||||
Label* lhs_not_nan,
|
||||
Label* slow,
|
||||
bool strict);
|
||||
static void EmitTwoNonNanDoubleComparison(MacroAssembler* masm, Condition cc);
|
||||
static void EmitTwoNonNanDoubleComparison(MacroAssembler* masm, Condition cond);
|
||||
static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm,
|
||||
Register lhs,
|
||||
Register rhs);
|
||||
@ -544,7 +544,7 @@ void WriteInt32ToHeapNumberStub::Generate(MacroAssembler* masm) {
|
||||
// for "identity and not NaN".
|
||||
static void EmitIdenticalObjectComparison(MacroAssembler* masm,
|
||||
Label* slow,
|
||||
Condition cc,
|
||||
Condition cond,
|
||||
bool never_nan_nan) {
|
||||
Label not_identical;
|
||||
Label heap_number, return_equal;
|
||||
@ -553,31 +553,31 @@ static void EmitIdenticalObjectComparison(MacroAssembler* masm,
|
||||
|
||||
// The two objects are identical. If we know that one of them isn't NaN then
|
||||
// we now know they test equal.
|
||||
if (cc != eq || !never_nan_nan) {
|
||||
if (cond != eq || !never_nan_nan) {
|
||||
// Test for NaN. Sadly, we can't just compare to Factory::nan_value(),
|
||||
// so we do the second best thing - test it ourselves.
|
||||
// They are both equal and they are not both Smis so both of them are not
|
||||
// Smis. If it's not a heap number, then return equal.
|
||||
if (cc == lt || cc == gt) {
|
||||
if (cond == lt || cond == gt) {
|
||||
__ CompareObjectType(r0, r4, r4, FIRST_JS_OBJECT_TYPE);
|
||||
__ b(ge, slow);
|
||||
} else {
|
||||
__ CompareObjectType(r0, r4, r4, HEAP_NUMBER_TYPE);
|
||||
__ b(eq, &heap_number);
|
||||
// Comparing JS objects with <=, >= is complicated.
|
||||
if (cc != eq) {
|
||||
if (cond != eq) {
|
||||
__ cmp(r4, Operand(FIRST_JS_OBJECT_TYPE));
|
||||
__ b(ge, slow);
|
||||
// Normally here we fall through to return_equal, but undefined is
|
||||
// special: (undefined == undefined) == true, but
|
||||
// (undefined <= undefined) == false! See ECMAScript 11.8.5.
|
||||
if (cc == le || cc == ge) {
|
||||
if (cond == le || cond == ge) {
|
||||
__ cmp(r4, Operand(ODDBALL_TYPE));
|
||||
__ b(ne, &return_equal);
|
||||
__ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
|
||||
__ cmp(r0, r2);
|
||||
__ b(ne, &return_equal);
|
||||
if (cc == le) {
|
||||
if (cond == le) {
|
||||
// undefined <= undefined should fail.
|
||||
__ mov(r0, Operand(GREATER));
|
||||
} else {
|
||||
@ -591,20 +591,20 @@ static void EmitIdenticalObjectComparison(MacroAssembler* masm,
|
||||
}
|
||||
|
||||
__ bind(&return_equal);
|
||||
if (cc == lt) {
|
||||
if (cond == lt) {
|
||||
__ mov(r0, Operand(GREATER)); // Things aren't less than themselves.
|
||||
} else if (cc == gt) {
|
||||
} else if (cond == gt) {
|
||||
__ mov(r0, Operand(LESS)); // Things aren't greater than themselves.
|
||||
} else {
|
||||
__ mov(r0, Operand(EQUAL)); // Things are <=, >=, ==, === themselves.
|
||||
}
|
||||
__ Ret();
|
||||
|
||||
if (cc != eq || !never_nan_nan) {
|
||||
if (cond != eq || !never_nan_nan) {
|
||||
// For less and greater we don't have to check for NaN since the result of
|
||||
// x < x is false regardless. For the others here is some code to check
|
||||
// for NaN.
|
||||
if (cc != lt && cc != gt) {
|
||||
if (cond != lt && cond != gt) {
|
||||
__ bind(&heap_number);
|
||||
// It is a heap number, so return non-equal if it's NaN and equal if it's
|
||||
// not NaN.
|
||||
@ -628,10 +628,10 @@ static void EmitIdenticalObjectComparison(MacroAssembler* masm,
|
||||
// if all bits in mantissa are zero (it's an Infinity) and non-zero if
|
||||
// not (it's a NaN). For <= and >= we need to load r0 with the failing
|
||||
// value if it's a NaN.
|
||||
if (cc != eq) {
|
||||
if (cond != eq) {
|
||||
// All-zero means Infinity means equal.
|
||||
__ Ret(eq);
|
||||
if (cc == le) {
|
||||
if (cond == le) {
|
||||
__ mov(r0, Operand(GREATER)); // NaN <= NaN should fail.
|
||||
} else {
|
||||
__ mov(r0, Operand(LESS)); // NaN >= NaN should fail.
|
||||
@ -738,7 +738,7 @@ static void EmitSmiNonsmiComparison(MacroAssembler* masm,
|
||||
}
|
||||
|
||||
|
||||
void EmitNanCheck(MacroAssembler* masm, Label* lhs_not_nan, Condition cc) {
|
||||
void EmitNanCheck(MacroAssembler* masm, Label* lhs_not_nan, Condition cond) {
|
||||
bool exp_first = (HeapNumber::kExponentOffset == HeapNumber::kValueOffset);
|
||||
Register rhs_exponent = exp_first ? r0 : r1;
|
||||
Register lhs_exponent = exp_first ? r2 : r3;
|
||||
@ -778,7 +778,7 @@ void EmitNanCheck(MacroAssembler* masm, Label* lhs_not_nan, Condition cc) {
|
||||
__ bind(&one_is_nan);
|
||||
// NaN comparisons always fail.
|
||||
// Load whatever we need in r0 to make the comparison fail.
|
||||
if (cc == lt || cc == le) {
|
||||
if (cond == lt || cond == le) {
|
||||
__ mov(r0, Operand(GREATER));
|
||||
} else {
|
||||
__ mov(r0, Operand(LESS));
|
||||
@ -790,7 +790,8 @@ void EmitNanCheck(MacroAssembler* masm, Label* lhs_not_nan, Condition cc) {
|
||||
|
||||
|
||||
// See comment at call site.
|
||||
static void EmitTwoNonNanDoubleComparison(MacroAssembler* masm, Condition cc) {
|
||||
static void EmitTwoNonNanDoubleComparison(MacroAssembler* masm,
|
||||
Condition cond) {
|
||||
bool exp_first = (HeapNumber::kExponentOffset == HeapNumber::kValueOffset);
|
||||
Register rhs_exponent = exp_first ? r0 : r1;
|
||||
Register lhs_exponent = exp_first ? r2 : r3;
|
||||
@ -798,7 +799,7 @@ static void EmitTwoNonNanDoubleComparison(MacroAssembler* masm, Condition cc) {
|
||||
Register lhs_mantissa = exp_first ? r3 : r2;
|
||||
|
||||
// r0, r1, r2, r3 have the two doubles. Neither is a NaN.
|
||||
if (cc == eq) {
|
||||
if (cond == eq) {
|
||||
// Doubles are not equal unless they have the same bit pattern.
|
||||
// Exception: 0 and -0.
|
||||
__ cmp(rhs_mantissa, Operand(lhs_mantissa));
|
||||
@ -1087,7 +1088,7 @@ void CompareStub::Generate(MacroAssembler* masm) {
|
||||
} else if (FLAG_debug_code) {
|
||||
__ orr(r2, r1, r0);
|
||||
__ tst(r2, Operand(kSmiTagMask));
|
||||
__ Assert(nz, "CompareStub: unexpected smi operands.");
|
||||
__ Assert(ne, "CompareStub: unexpected smi operands.");
|
||||
}
|
||||
|
||||
// NOTICE! This code is only reached after a smi-fast-case check, so
|
||||
@ -3834,7 +3835,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
|
||||
__ ldr(regexp_data, FieldMemOperand(r0, JSRegExp::kDataOffset));
|
||||
if (FLAG_debug_code) {
|
||||
__ tst(regexp_data, Operand(kSmiTagMask));
|
||||
__ Check(nz, "Unexpected type for RegExp data, FixedArray expected");
|
||||
__ Check(ne, "Unexpected type for RegExp data, FixedArray expected");
|
||||
__ CompareObjectType(regexp_data, r0, r0, FIXED_ARRAY_TYPE);
|
||||
__ Check(eq, "Unexpected type for RegExp data, FixedArray expected");
|
||||
}
|
||||
@ -3937,7 +3938,7 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
|
||||
// Is first part a flat string?
|
||||
STATIC_ASSERT(kSeqStringTag == 0);
|
||||
__ tst(r0, Operand(kStringRepresentationMask));
|
||||
__ b(nz, &runtime);
|
||||
__ b(ne, &runtime);
|
||||
|
||||
__ bind(&seq_string);
|
||||
// subject: Subject string
|
||||
@ -4385,13 +4386,13 @@ void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) {
|
||||
// If the first cons component is also non-flat, then go to runtime.
|
||||
STATIC_ASSERT(kSeqStringTag == 0);
|
||||
__ tst(result_, Operand(kStringRepresentationMask));
|
||||
__ b(nz, &call_runtime_);
|
||||
__ b(ne, &call_runtime_);
|
||||
|
||||
// Check for 1-byte or 2-byte string.
|
||||
__ bind(&flat_string);
|
||||
STATIC_ASSERT(kAsciiStringTag != 0);
|
||||
__ tst(result_, Operand(kStringEncodingMask));
|
||||
__ b(nz, &ascii_string);
|
||||
__ b(ne, &ascii_string);
|
||||
|
||||
// 2-byte string.
|
||||
// Load the 2-byte character code into the result register. We can
|
||||
@ -4476,7 +4477,7 @@ void StringCharFromCodeGenerator::GenerateFast(MacroAssembler* masm) {
|
||||
__ tst(code_,
|
||||
Operand(kSmiTagMask |
|
||||
((~String::kMaxAsciiCharCode) << kSmiTagSize)));
|
||||
__ b(nz, &slow_case_);
|
||||
__ b(ne, &slow_case_);
|
||||
|
||||
__ LoadRoot(result_, Heap::kSingleCharacterStringCacheRootIndex);
|
||||
// At this point code register contains smi tagged ascii char code.
|
||||
@ -4923,7 +4924,7 @@ void StringHelper::GenerateHashGetHash(MacroAssembler* masm,
|
||||
__ add(hash, hash, Operand(hash, LSL, 15), SetCC);
|
||||
|
||||
// if (hash == 0) hash = 27;
|
||||
__ mov(hash, Operand(27), LeaveCC, nz);
|
||||
__ mov(hash, Operand(27), LeaveCC, ne);
|
||||
}
|
||||
|
||||
|
||||
|
@ -39,7 +39,7 @@ namespace internal {
|
||||
// Platform-specific inline functions.
|
||||
|
||||
void DeferredCode::Jump() { __ jmp(&entry_label_); }
|
||||
void DeferredCode::Branch(Condition cc) { __ b(cc, &entry_label_); }
|
||||
void DeferredCode::Branch(Condition cond) { __ b(cond, &entry_label_); }
|
||||
|
||||
#undef __
|
||||
|
||||
|
@ -1589,7 +1589,7 @@ void CodeGenerator::SmiOperation(Token::Value op,
|
||||
}
|
||||
|
||||
|
||||
void CodeGenerator::Comparison(Condition cc,
|
||||
void CodeGenerator::Comparison(Condition cond,
|
||||
Expression* left,
|
||||
Expression* right,
|
||||
bool strict) {
|
||||
@ -1603,7 +1603,7 @@ void CodeGenerator::Comparison(Condition cc,
|
||||
// result : cc register
|
||||
|
||||
// Strict only makes sense for equality comparisons.
|
||||
ASSERT(!strict || cc == eq);
|
||||
ASSERT(!strict || cond == eq);
|
||||
|
||||
Register lhs;
|
||||
Register rhs;
|
||||
@ -1614,8 +1614,8 @@ void CodeGenerator::Comparison(Condition cc,
|
||||
// We load the top two stack positions into registers chosen by the virtual
|
||||
// frame. This should keep the register shuffling to a minimum.
|
||||
// Implement '>' and '<=' by reversal to obtain ECMA-262 conversion order.
|
||||
if (cc == gt || cc == le) {
|
||||
cc = ReverseCondition(cc);
|
||||
if (cond == gt || cond == le) {
|
||||
cond = ReverseCondition(cond);
|
||||
lhs_is_smi = frame_->KnownSmiAt(0);
|
||||
rhs_is_smi = frame_->KnownSmiAt(1);
|
||||
lhs = frame_->PopToRegister();
|
||||
@ -1655,7 +1655,7 @@ void CodeGenerator::Comparison(Condition cc,
|
||||
// Perform non-smi comparison by stub.
|
||||
// CompareStub takes arguments in r0 and r1, returns <0, >0 or 0 in r0.
|
||||
// We call with 0 args because there are 0 on the stack.
|
||||
CompareStub stub(cc, strict, NO_SMI_COMPARE_IN_STUB, lhs, rhs);
|
||||
CompareStub stub(cond, strict, NO_SMI_COMPARE_IN_STUB, lhs, rhs);
|
||||
frame_->CallStub(&stub, 0);
|
||||
__ cmp(r0, Operand(0, RelocInfo::NONE));
|
||||
exit.Jump();
|
||||
@ -1667,7 +1667,7 @@ void CodeGenerator::Comparison(Condition cc,
|
||||
__ cmp(lhs, Operand(rhs));
|
||||
|
||||
exit.Bind();
|
||||
cc_reg_ = cc;
|
||||
cc_reg_ = cond;
|
||||
}
|
||||
|
||||
|
||||
@ -1885,8 +1885,8 @@ void CodeGenerator::CallApplyLazy(Expression* applicand,
|
||||
|
||||
void CodeGenerator::Branch(bool if_true, JumpTarget* target) {
|
||||
ASSERT(has_cc());
|
||||
Condition cc = if_true ? cc_reg_ : NegateCondition(cc_reg_);
|
||||
target->Branch(cc);
|
||||
Condition cond = if_true ? cc_reg_ : NegateCondition(cc_reg_);
|
||||
target->Branch(cond);
|
||||
cc_reg_ = al;
|
||||
}
|
||||
|
||||
@ -5572,7 +5572,7 @@ void CodeGenerator::GenerateSwapElements(ZoneList<Expression*>* args) {
|
||||
deferred->Branch(lt);
|
||||
__ ldrb(tmp2, FieldMemOperand(tmp1, Map::kBitFieldOffset));
|
||||
__ tst(tmp2, Operand(KeyedLoadIC::kSlowCaseBitFieldMask));
|
||||
deferred->Branch(nz);
|
||||
deferred->Branch(ne);
|
||||
|
||||
// Check the object's elements are in fast case and writable.
|
||||
__ ldr(tmp1, FieldMemOperand(object, JSObject::kElementsOffset));
|
||||
@ -5589,7 +5589,7 @@ void CodeGenerator::GenerateSwapElements(ZoneList<Expression*>* args) {
|
||||
__ mov(tmp2, index1);
|
||||
__ orr(tmp2, tmp2, index2);
|
||||
__ tst(tmp2, Operand(kSmiTagMask));
|
||||
deferred->Branch(nz);
|
||||
deferred->Branch(ne);
|
||||
|
||||
// Check that both indices are valid.
|
||||
__ ldr(tmp2, FieldMemOperand(object, JSArray::kLengthOffset));
|
||||
|
@ -32,12 +32,10 @@
|
||||
#include "constants-arm.h"
|
||||
|
||||
|
||||
namespace assembler {
|
||||
namespace arm {
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
namespace v8i = v8::internal;
|
||||
|
||||
double Instr::DoubleImmedVmov() const {
|
||||
double Instruction::DoubleImmedVmov() const {
|
||||
// Reconstruct a double from the immediate encoded in the vmov instruction.
|
||||
//
|
||||
// instruction: [xxxxxxxx,xxxxabcd,xxxxxxxx,xxxxefgh]
|
||||
@ -149,6 +147,6 @@ int Registers::Number(const char* name) {
|
||||
}
|
||||
|
||||
|
||||
} } // namespace assembler::arm
|
||||
} } // namespace v8::internal
|
||||
|
||||
#endif // V8_TARGET_ARCH_ARM
|
||||
|
@ -86,8 +86,8 @@
|
||||
#define USE_BLX 1
|
||||
#endif
|
||||
|
||||
namespace assembler {
|
||||
namespace arm {
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// Number of registers in normal ARM mode.
|
||||
static const int kNumRegisters = 16;
|
||||
@ -102,6 +102,9 @@ static const int kNumVFPRegisters =
|
||||
static const int kPCRegister = 15;
|
||||
static const int kNoRegister = -1;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Conditions.
|
||||
|
||||
// Defines constants and accessor classes to assemble, disassemble and
|
||||
// simulate ARM instructions.
|
||||
//
|
||||
@ -111,93 +114,262 @@ static const int kNoRegister = -1;
|
||||
// Constants for specific fields are defined in their respective named enums.
|
||||
// General constants are in an anonymous enum in class Instr.
|
||||
|
||||
typedef unsigned char byte;
|
||||
|
||||
// Values for the condition field as defined in section A3.2
|
||||
enum Condition {
|
||||
no_condition = -1,
|
||||
EQ = 0, // equal
|
||||
NE = 1, // not equal
|
||||
CS = 2, // carry set/unsigned higher or same
|
||||
CC = 3, // carry clear/unsigned lower
|
||||
MI = 4, // minus/negative
|
||||
PL = 5, // plus/positive or zero
|
||||
VS = 6, // overflow
|
||||
VC = 7, // no overflow
|
||||
HI = 8, // unsigned higher
|
||||
LS = 9, // unsigned lower or same
|
||||
GE = 10, // signed greater than or equal
|
||||
LT = 11, // signed less than
|
||||
GT = 12, // signed greater than
|
||||
LE = 13, // signed less than or equal
|
||||
AL = 14, // always (unconditional)
|
||||
special_condition = 15, // special condition (refer to section A3.2.1)
|
||||
max_condition = 16
|
||||
kNoCondition = -1,
|
||||
|
||||
eq = 0 << 28, // Z set Equal.
|
||||
ne = 1 << 28, // Z clear Not equal.
|
||||
cs = 2 << 28, // C set Unsigned higher or same.
|
||||
cc = 3 << 28, // C clear Unsigned lower.
|
||||
mi = 4 << 28, // N set Negative.
|
||||
pl = 5 << 28, // N clear Positive or zero.
|
||||
vs = 6 << 28, // V set Overflow.
|
||||
vc = 7 << 28, // V clear No overflow.
|
||||
hi = 8 << 28, // C set, Z clear Unsigned higher.
|
||||
ls = 9 << 28, // C clear or Z set Unsigned lower or same.
|
||||
ge = 10 << 28, // N == V Greater or equal.
|
||||
lt = 11 << 28, // N != V Less than.
|
||||
gt = 12 << 28, // Z clear, N == V Greater than.
|
||||
le = 13 << 28, // Z set or N != V Less then or equal
|
||||
al = 14 << 28, // Always.
|
||||
|
||||
kSpecialCondition = 15 << 28, // Special condition (refer to section A3.2.1).
|
||||
kNumberOfConditions = 16,
|
||||
|
||||
// Aliases.
|
||||
hs = cs, // C set Unsigned higher or same.
|
||||
lo = cc // C clear Unsigned lower.
|
||||
};
|
||||
|
||||
|
||||
inline Condition NegateCondition(Condition cond) {
|
||||
ASSERT(cond != al);
|
||||
return static_cast<Condition>(cond ^ ne);
|
||||
}
|
||||
|
||||
|
||||
// Corresponds to transposing the operands of a comparison.
|
||||
inline Condition ReverseCondition(Condition cond) {
|
||||
switch (cond) {
|
||||
case lo:
|
||||
return hi;
|
||||
case hi:
|
||||
return lo;
|
||||
case hs:
|
||||
return ls;
|
||||
case ls:
|
||||
return hs;
|
||||
case lt:
|
||||
return gt;
|
||||
case gt:
|
||||
return lt;
|
||||
case ge:
|
||||
return le;
|
||||
case le:
|
||||
return ge;
|
||||
default:
|
||||
return cond;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Instructions encoding.
|
||||
|
||||
// Instr is merely used by the Assembler to distinguish 32bit integers
|
||||
// representing instructions from usual 32 bit values.
|
||||
// Instruction objects are pointers to 32bit values, and provide methods to
|
||||
// access the various ISA fields.
|
||||
typedef int32_t Instr;
|
||||
|
||||
|
||||
// Opcodes for Data-processing instructions (instructions with a type 0 and 1)
|
||||
// as defined in section A3.4
|
||||
enum Opcode {
|
||||
no_operand = -1,
|
||||
AND = 0, // Logical AND
|
||||
EOR = 1, // Logical Exclusive OR
|
||||
SUB = 2, // Subtract
|
||||
RSB = 3, // Reverse Subtract
|
||||
ADD = 4, // Add
|
||||
ADC = 5, // Add with Carry
|
||||
SBC = 6, // Subtract with Carry
|
||||
RSC = 7, // Reverse Subtract with Carry
|
||||
TST = 8, // Test
|
||||
TEQ = 9, // Test Equivalence
|
||||
CMP = 10, // Compare
|
||||
CMN = 11, // Compare Negated
|
||||
ORR = 12, // Logical (inclusive) OR
|
||||
MOV = 13, // Move
|
||||
BIC = 14, // Bit Clear
|
||||
MVN = 15, // Move Not
|
||||
max_operand = 16
|
||||
AND = 0 << 21, // Logical AND.
|
||||
EOR = 1 << 21, // Logical Exclusive OR.
|
||||
SUB = 2 << 21, // Subtract.
|
||||
RSB = 3 << 21, // Reverse Subtract.
|
||||
ADD = 4 << 21, // Add.
|
||||
ADC = 5 << 21, // Add with Carry.
|
||||
SBC = 6 << 21, // Subtract with Carry.
|
||||
RSC = 7 << 21, // Reverse Subtract with Carry.
|
||||
TST = 8 << 21, // Test.
|
||||
TEQ = 9 << 21, // Test Equivalence.
|
||||
CMP = 10 << 21, // Compare.
|
||||
CMN = 11 << 21, // Compare Negated.
|
||||
ORR = 12 << 21, // Logical (inclusive) OR.
|
||||
MOV = 13 << 21, // Move.
|
||||
BIC = 14 << 21, // Bit Clear.
|
||||
MVN = 15 << 21 // Move Not.
|
||||
};
|
||||
|
||||
|
||||
// The bits for bit 7-4 for some type 0 miscellaneous instructions.
|
||||
enum MiscInstructionsBits74 {
|
||||
// With bits 22-21 01.
|
||||
BX = 1,
|
||||
BXJ = 2,
|
||||
BLX = 3,
|
||||
BKPT = 7,
|
||||
BX = 1 << 4,
|
||||
BXJ = 2 << 4,
|
||||
BLX = 3 << 4,
|
||||
BKPT = 7 << 4,
|
||||
|
||||
// With bits 22-21 11.
|
||||
CLZ = 1
|
||||
CLZ = 1 << 4
|
||||
};
|
||||
|
||||
|
||||
// Instruction encoding bits and masks.
|
||||
enum {
|
||||
H = 1 << 5, // Halfword (or byte).
|
||||
S6 = 1 << 6, // Signed (or unsigned).
|
||||
L = 1 << 20, // Load (or store).
|
||||
S = 1 << 20, // Set condition code (or leave unchanged).
|
||||
W = 1 << 21, // Writeback base register (or leave unchanged).
|
||||
A = 1 << 21, // Accumulate in multiply instruction (or not).
|
||||
B = 1 << 22, // Unsigned byte (or word).
|
||||
N = 1 << 22, // Long (or short).
|
||||
U = 1 << 23, // Positive (or negative) offset/index.
|
||||
P = 1 << 24, // Offset/pre-indexed addressing (or post-indexed addressing).
|
||||
I = 1 << 25, // Immediate shifter operand (or not).
|
||||
|
||||
B4 = 1 << 4,
|
||||
B5 = 1 << 5,
|
||||
B6 = 1 << 6,
|
||||
B7 = 1 << 7,
|
||||
B8 = 1 << 8,
|
||||
B9 = 1 << 9,
|
||||
B12 = 1 << 12,
|
||||
B16 = 1 << 16,
|
||||
B18 = 1 << 18,
|
||||
B19 = 1 << 19,
|
||||
B20 = 1 << 20,
|
||||
B21 = 1 << 21,
|
||||
B22 = 1 << 22,
|
||||
B23 = 1 << 23,
|
||||
B24 = 1 << 24,
|
||||
B25 = 1 << 25,
|
||||
B26 = 1 << 26,
|
||||
B27 = 1 << 27,
|
||||
B28 = 1 << 28,
|
||||
|
||||
// Instruction bit masks.
|
||||
kCondMask = 15 << 28,
|
||||
kALUMask = 0x6f << 21,
|
||||
kRdMask = 15 << 12, // In str instruction.
|
||||
kCoprocessorMask = 15 << 8,
|
||||
kOpCodeMask = 15 << 21, // In data-processing instructions.
|
||||
kImm24Mask = (1 << 24) - 1,
|
||||
kOff12Mask = (1 << 12) - 1
|
||||
};
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Addressing modes and instruction variants.
|
||||
|
||||
// Condition code updating mode.
|
||||
enum SBit {
|
||||
SetCC = 1 << 20, // Set condition code.
|
||||
LeaveCC = 0 << 20 // Leave condition code unchanged.
|
||||
};
|
||||
|
||||
|
||||
// Status register selection.
|
||||
enum SRegister {
|
||||
CPSR = 0 << 22,
|
||||
SPSR = 1 << 22
|
||||
};
|
||||
|
||||
|
||||
// Shifter types for Data-processing operands as defined in section A5.1.2.
|
||||
enum Shift {
|
||||
no_shift = -1,
|
||||
LSL = 0, // Logical shift left
|
||||
LSR = 1, // Logical shift right
|
||||
ASR = 2, // Arithmetic shift right
|
||||
ROR = 3, // Rotate right
|
||||
max_shift = 4
|
||||
enum ShiftOp {
|
||||
LSL = 0 << 5, // Logical shift left.
|
||||
LSR = 1 << 5, // Logical shift right.
|
||||
ASR = 2 << 5, // Arithmetic shift right.
|
||||
ROR = 3 << 5, // Rotate right.
|
||||
|
||||
// RRX is encoded as ROR with shift_imm == 0.
|
||||
// Use a special code to make the distinction. The RRX ShiftOp is only used
|
||||
// as an argument, and will never actually be encoded. The Assembler will
|
||||
// detect it and emit the correct ROR shift operand with shift_imm == 0.
|
||||
RRX = -1,
|
||||
kNumberOfShifts = 4
|
||||
};
|
||||
|
||||
|
||||
// Status register fields.
|
||||
enum SRegisterField {
|
||||
CPSR_c = CPSR | 1 << 16,
|
||||
CPSR_x = CPSR | 1 << 17,
|
||||
CPSR_s = CPSR | 1 << 18,
|
||||
CPSR_f = CPSR | 1 << 19,
|
||||
SPSR_c = SPSR | 1 << 16,
|
||||
SPSR_x = SPSR | 1 << 17,
|
||||
SPSR_s = SPSR | 1 << 18,
|
||||
SPSR_f = SPSR | 1 << 19
|
||||
};
|
||||
|
||||
// Status register field mask (or'ed SRegisterField enum values).
|
||||
typedef uint32_t SRegisterFieldMask;
|
||||
|
||||
|
||||
// Memory operand addressing mode.
|
||||
enum AddrMode {
|
||||
// Bit encoding P U W.
|
||||
Offset = (8|4|0) << 21, // Offset (without writeback to base).
|
||||
PreIndex = (8|4|1) << 21, // Pre-indexed addressing with writeback.
|
||||
PostIndex = (0|4|0) << 21, // Post-indexed addressing with writeback.
|
||||
NegOffset = (8|0|0) << 21, // Negative offset (without writeback to base).
|
||||
NegPreIndex = (8|0|1) << 21, // Negative pre-indexed with writeback.
|
||||
NegPostIndex = (0|0|0) << 21 // Negative post-indexed with writeback.
|
||||
};
|
||||
|
||||
|
||||
// Load/store multiple addressing mode.
|
||||
enum BlockAddrMode {
|
||||
// Bit encoding P U W .
|
||||
da = (0|0|0) << 21, // Decrement after.
|
||||
ia = (0|4|0) << 21, // Increment after.
|
||||
db = (8|0|0) << 21, // Decrement before.
|
||||
ib = (8|4|0) << 21, // Increment before.
|
||||
da_w = (0|0|1) << 21, // Decrement after with writeback to base.
|
||||
ia_w = (0|4|1) << 21, // Increment after with writeback to base.
|
||||
db_w = (8|0|1) << 21, // Decrement before with writeback to base.
|
||||
ib_w = (8|4|1) << 21, // Increment before with writeback to base.
|
||||
|
||||
// Alias modes for comparison when writeback does not matter.
|
||||
da_x = (0|0|0) << 21, // Decrement after.
|
||||
ia_x = (0|4|0) << 21, // Increment after.
|
||||
db_x = (8|0|0) << 21, // Decrement before.
|
||||
ib_x = (8|4|0) << 21 // Increment before.
|
||||
};
|
||||
|
||||
|
||||
// Coprocessor load/store operand size.
|
||||
enum LFlag {
|
||||
Long = 1 << 22, // Long load/store coprocessor.
|
||||
Short = 0 << 22 // Short load/store coprocessor.
|
||||
};
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Supervisor Call (svc) specific support.
|
||||
|
||||
// Special Software Interrupt codes when used in the presence of the ARM
|
||||
// simulator.
|
||||
// svc (formerly swi) provides a 24bit immediate value. Use bits 22:0 for
|
||||
// standard SoftwareInterrupCode. Bit 23 is reserved for the stop feature.
|
||||
enum SoftwareInterruptCodes {
|
||||
// transition to C code
|
||||
call_rt_redirected = 0x10,
|
||||
kCallRtRedirected= 0x10,
|
||||
// break point
|
||||
break_point = 0x20,
|
||||
kBreakpoint= 0x20,
|
||||
// stop
|
||||
stop = 1 << 23
|
||||
kStopCode = 1 << 23
|
||||
};
|
||||
static const int32_t kStopCodeMask = stop - 1;
|
||||
static const uint32_t kMaxStopCode = stop - 1;
|
||||
static const uint32_t kStopCodeMask = kStopCode - 1;
|
||||
static const uint32_t kMaxStopCode = kStopCode - 1;
|
||||
static const int32_t kDefaultStopCode = -1;
|
||||
|
||||
|
||||
// Type of VFP register. Determines register encoding.
|
||||
@ -206,6 +378,20 @@ enum VFPRegPrecision {
|
||||
kDoublePrecision = 1
|
||||
};
|
||||
|
||||
|
||||
// VFP FPSCR constants.
|
||||
static const uint32_t kVFPExceptionMask = 0xf;
|
||||
static const uint32_t kVFPRoundingModeMask = 3 << 22;
|
||||
static const uint32_t kVFPFlushToZeroMask = 1 << 24;
|
||||
static const uint32_t kVFPRoundToMinusInfinityBits = 2 << 22;
|
||||
static const uint32_t kVFPInvalidExceptionBit = 1;
|
||||
|
||||
static const uint32_t kVFPNConditionFlagBit = 1 << 31;
|
||||
static const uint32_t kVFPZConditionFlagBit = 1 << 30;
|
||||
static const uint32_t kVFPCConditionFlagBit = 1 << 29;
|
||||
static const uint32_t kVFPVConditionFlagBit = 1 << 28;
|
||||
|
||||
|
||||
// VFP rounding modes. See ARM DDI 0406B Page A2-29.
|
||||
enum FPSCRRoundingModes {
|
||||
RN, // Round to Nearest.
|
||||
@ -214,22 +400,91 @@ enum FPSCRRoundingModes {
|
||||
RZ // Round towards zero.
|
||||
};
|
||||
|
||||
typedef int32_t instr_t;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Hints.
|
||||
|
||||
// Branch hints are not used on the ARM. They are defined so that they can
|
||||
// appear in shared function signatures, but will be ignored in ARM
|
||||
// implementations.
|
||||
enum Hint { no_hint };
|
||||
|
||||
// Hints are not used on the arm. Negating is trivial.
|
||||
inline Hint NegateHint(Hint ignored) { return no_hint; }
|
||||
|
||||
|
||||
// The class Instr enables access to individual fields defined in the ARM
|
||||
// -----------------------------------------------------------------------------
|
||||
// Specific instructions, constants, and masks.
|
||||
// These constants are declared in assembler-arm.cc, as they use named registers
|
||||
// and other constants.
|
||||
|
||||
|
||||
// add(sp, sp, 4) instruction (aka Pop())
|
||||
extern const Instr kPopInstruction;
|
||||
|
||||
// str(r, MemOperand(sp, 4, NegPreIndex), al) instruction (aka push(r))
|
||||
// register r is not encoded.
|
||||
extern const Instr kPushRegPattern;
|
||||
|
||||
// ldr(r, MemOperand(sp, 4, PostIndex), al) instruction (aka pop(r))
|
||||
// register r is not encoded.
|
||||
extern const Instr kPopRegPattern;
|
||||
|
||||
// mov lr, pc
|
||||
extern const Instr kMovLrPc;
|
||||
// ldr rd, [pc, #offset]
|
||||
extern const Instr kLdrPCMask;
|
||||
extern const Instr kLdrPCPattern;
|
||||
// blxcc rm
|
||||
extern const Instr kBlxRegMask;
|
||||
|
||||
extern const Instr kBlxRegPattern;
|
||||
|
||||
extern const Instr kMovMvnMask;
|
||||
extern const Instr kMovMvnPattern;
|
||||
extern const Instr kMovMvnFlip;
|
||||
extern const Instr kMovLeaveCCMask;
|
||||
extern const Instr kMovLeaveCCPattern;
|
||||
extern const Instr kMovwMask;
|
||||
extern const Instr kMovwPattern;
|
||||
extern const Instr kMovwLeaveCCFlip;
|
||||
extern const Instr kCmpCmnMask;
|
||||
extern const Instr kCmpCmnPattern;
|
||||
extern const Instr kCmpCmnFlip;
|
||||
extern const Instr kAddSubFlip;
|
||||
extern const Instr kAndBicFlip;
|
||||
|
||||
// A mask for the Rd register for push, pop, ldr, str instructions.
|
||||
extern const Instr kLdrRegFpOffsetPattern;
|
||||
|
||||
extern const Instr kStrRegFpOffsetPattern;
|
||||
|
||||
extern const Instr kLdrRegFpNegOffsetPattern;
|
||||
|
||||
extern const Instr kStrRegFpNegOffsetPattern;
|
||||
|
||||
extern const Instr kLdrStrInstrTypeMask;
|
||||
extern const Instr kLdrStrInstrArgumentMask;
|
||||
extern const Instr kLdrStrOffsetMask;
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Instruction abstraction.
|
||||
|
||||
// The class Instruction enables access to individual fields defined in the ARM
|
||||
// architecture instruction set encoding as described in figure A3-1.
|
||||
// Note that the Assembler uses typedef int32_t Instr.
|
||||
//
|
||||
// Example: Test whether the instruction at ptr does set the condition code
|
||||
// bits.
|
||||
//
|
||||
// bool InstructionSetsConditionCodes(byte* ptr) {
|
||||
// Instr* instr = Instr::At(ptr);
|
||||
// int type = instr->TypeField();
|
||||
// Instruction* instr = Instruction::At(ptr);
|
||||
// int type = instr->TypeValue();
|
||||
// return ((type == 0) || (type == 1)) && instr->HasS();
|
||||
// }
|
||||
//
|
||||
class Instr {
|
||||
class Instruction {
|
||||
public:
|
||||
enum {
|
||||
kInstrSize = 4,
|
||||
@ -237,14 +492,24 @@ class Instr {
|
||||
kPCReadOffset = 8
|
||||
};
|
||||
|
||||
// Helper macro to define static accessors.
|
||||
// We use the cast to char* trick to bypass the strict anti-aliasing rules.
|
||||
#define DECLARE_STATIC_TYPED_ACCESSOR(return_type, Name) \
|
||||
static inline return_type Name(Instr instr) { \
|
||||
char* temp = reinterpret_cast<char*>(&instr); \
|
||||
return reinterpret_cast<Instruction*>(temp)->Name(); \
|
||||
}
|
||||
|
||||
#define DECLARE_STATIC_ACCESSOR(Name) DECLARE_STATIC_TYPED_ACCESSOR(int, Name)
|
||||
|
||||
// Get the raw instruction bits.
|
||||
inline instr_t InstructionBits() const {
|
||||
return *reinterpret_cast<const instr_t*>(this);
|
||||
inline Instr InstructionBits() const {
|
||||
return *reinterpret_cast<const Instr*>(this);
|
||||
}
|
||||
|
||||
// Set the raw instruction bits to value.
|
||||
inline void SetInstructionBits(instr_t value) {
|
||||
*reinterpret_cast<instr_t*>(this) = value;
|
||||
inline void SetInstructionBits(Instr value) {
|
||||
*reinterpret_cast<Instr*>(this) = value;
|
||||
}
|
||||
|
||||
// Read one particular bit out of the instruction bits.
|
||||
@ -252,93 +517,141 @@ class Instr {
|
||||
return (InstructionBits() >> nr) & 1;
|
||||
}
|
||||
|
||||
// Read a bit field out of the instruction bits.
|
||||
// Read a bit field's value out of the instruction bits.
|
||||
inline int Bits(int hi, int lo) const {
|
||||
return (InstructionBits() >> lo) & ((2 << (hi - lo)) - 1);
|
||||
}
|
||||
|
||||
// Read a bit field out of the instruction bits.
|
||||
inline int BitField(int hi, int lo) const {
|
||||
return InstructionBits() & (((2 << (hi - lo)) - 1) << lo);
|
||||
}
|
||||
|
||||
// Static support.
|
||||
|
||||
// Read one particular bit out of the instruction bits.
|
||||
static inline int Bit(Instr instr, int nr) {
|
||||
return (instr >> nr) & 1;
|
||||
}
|
||||
|
||||
// Read the value of a bit field out of the instruction bits.
|
||||
static inline int Bits(Instr instr, int hi, int lo) {
|
||||
return (instr >> lo) & ((2 << (hi - lo)) - 1);
|
||||
}
|
||||
|
||||
|
||||
// Read a bit field out of the instruction bits.
|
||||
static inline int BitField(Instr instr, int hi, int lo) {
|
||||
return instr & (((2 << (hi - lo)) - 1) << lo);
|
||||
}
|
||||
|
||||
|
||||
// Accessors for the different named fields used in the ARM encoding.
|
||||
// The naming of these accessor corresponds to figure A3-1.
|
||||
//
|
||||
// Two kind of accessors are declared:
|
||||
// - <Name>Field() will return the raw field, ie the field's bits at their
|
||||
// original place in the instruction encoding.
|
||||
// eg. if instr is the 'addgt r0, r1, r2' instruction, encoded as 0xC0810002
|
||||
// ConditionField(instr) will return 0xC0000000.
|
||||
// - <Name>Value() will return the field value, shifted back to bit 0.
|
||||
// eg. if instr is the 'addgt r0, r1, r2' instruction, encoded as 0xC0810002
|
||||
// ConditionField(instr) will return 0xC.
|
||||
|
||||
|
||||
// Generally applicable fields
|
||||
inline Condition ConditionField() const {
|
||||
inline Condition ConditionValue() const {
|
||||
return static_cast<Condition>(Bits(31, 28));
|
||||
}
|
||||
inline int TypeField() const { return Bits(27, 25); }
|
||||
inline Condition ConditionField() const {
|
||||
return static_cast<Condition>(BitField(31, 28));
|
||||
}
|
||||
DECLARE_STATIC_TYPED_ACCESSOR(Condition, ConditionValue);
|
||||
DECLARE_STATIC_TYPED_ACCESSOR(Condition, ConditionField);
|
||||
|
||||
inline int RnField() const { return Bits(19, 16); }
|
||||
inline int RdField() const { return Bits(15, 12); }
|
||||
inline int TypeValue() const { return Bits(27, 25); }
|
||||
|
||||
inline int CoprocessorField() const { return Bits(11, 8); }
|
||||
inline int RnValue() const { return Bits(19, 16); }
|
||||
inline int RdValue() const { return Bits(15, 12); }
|
||||
DECLARE_STATIC_ACCESSOR(RdValue);
|
||||
|
||||
inline int CoprocessorValue() const { return Bits(11, 8); }
|
||||
// Support for VFP.
|
||||
// Vn(19-16) | Vd(15-12) | Vm(3-0)
|
||||
inline int VnField() const { return Bits(19, 16); }
|
||||
inline int VmField() const { return Bits(3, 0); }
|
||||
inline int VdField() const { return Bits(15, 12); }
|
||||
inline int NField() const { return Bit(7); }
|
||||
inline int MField() const { return Bit(5); }
|
||||
inline int DField() const { return Bit(22); }
|
||||
inline int RtField() const { return Bits(15, 12); }
|
||||
inline int PField() const { return Bit(24); }
|
||||
inline int UField() const { return Bit(23); }
|
||||
inline int Opc1Field() const { return (Bit(23) << 2) | Bits(21, 20); }
|
||||
inline int Opc2Field() const { return Bits(19, 16); }
|
||||
inline int Opc3Field() const { return Bits(7, 6); }
|
||||
inline int SzField() const { return Bit(8); }
|
||||
inline int VLField() const { return Bit(20); }
|
||||
inline int VCField() const { return Bit(8); }
|
||||
inline int VAField() const { return Bits(23, 21); }
|
||||
inline int VBField() const { return Bits(6, 5); }
|
||||
inline int VFPNRegCode(VFPRegPrecision pre) {
|
||||
return VFPGlueRegCode(pre, 16, 7);
|
||||
inline int VnValue() const { return Bits(19, 16); }
|
||||
inline int VmValue() const { return Bits(3, 0); }
|
||||
inline int VdValue() const { return Bits(15, 12); }
|
||||
inline int NValue() const { return Bit(7); }
|
||||
inline int MValue() const { return Bit(5); }
|
||||
inline int DValue() const { return Bit(22); }
|
||||
inline int RtValue() const { return Bits(15, 12); }
|
||||
inline int PValue() const { return Bit(24); }
|
||||
inline int UValue() const { return Bit(23); }
|
||||
inline int Opc1Value() const { return (Bit(23) << 2) | Bits(21, 20); }
|
||||
inline int Opc2Value() const { return Bits(19, 16); }
|
||||
inline int Opc3Value() const { return Bits(7, 6); }
|
||||
inline int SzValue() const { return Bit(8); }
|
||||
inline int VLValue() const { return Bit(20); }
|
||||
inline int VCValue() const { return Bit(8); }
|
||||
inline int VAValue() const { return Bits(23, 21); }
|
||||
inline int VBValue() const { return Bits(6, 5); }
|
||||
inline int VFPNRegValue(VFPRegPrecision pre) {
|
||||
return VFPGlueRegValue(pre, 16, 7);
|
||||
}
|
||||
inline int VFPMRegCode(VFPRegPrecision pre) {
|
||||
return VFPGlueRegCode(pre, 0, 5);
|
||||
inline int VFPMRegValue(VFPRegPrecision pre) {
|
||||
return VFPGlueRegValue(pre, 0, 5);
|
||||
}
|
||||
inline int VFPDRegCode(VFPRegPrecision pre) {
|
||||
return VFPGlueRegCode(pre, 12, 22);
|
||||
inline int VFPDRegValue(VFPRegPrecision pre) {
|
||||
return VFPGlueRegValue(pre, 12, 22);
|
||||
}
|
||||
|
||||
// Fields used in Data processing instructions
|
||||
inline Opcode OpcodeField() const {
|
||||
inline int OpcodeValue() const {
|
||||
return static_cast<Opcode>(Bits(24, 21));
|
||||
}
|
||||
inline int SField() const { return Bit(20); }
|
||||
inline Opcode OpcodeField() const {
|
||||
return static_cast<Opcode>(BitField(24, 21));
|
||||
}
|
||||
inline int SValue() const { return Bit(20); }
|
||||
// with register
|
||||
inline int RmField() const { return Bits(3, 0); }
|
||||
inline Shift ShiftField() const { return static_cast<Shift>(Bits(6, 5)); }
|
||||
inline int RegShiftField() const { return Bit(4); }
|
||||
inline int RsField() const { return Bits(11, 8); }
|
||||
inline int ShiftAmountField() const { return Bits(11, 7); }
|
||||
inline int RmValue() const { return Bits(3, 0); }
|
||||
inline int ShiftValue() const { return static_cast<ShiftOp>(Bits(6, 5)); }
|
||||
inline ShiftOp ShiftField() const {
|
||||
return static_cast<ShiftOp>(BitField(6, 5));
|
||||
}
|
||||
inline int RegShiftValue() const { return Bit(4); }
|
||||
inline int RsValue() const { return Bits(11, 8); }
|
||||
inline int ShiftAmountValue() const { return Bits(11, 7); }
|
||||
// with immediate
|
||||
inline int RotateField() const { return Bits(11, 8); }
|
||||
inline int Immed8Field() const { return Bits(7, 0); }
|
||||
inline int Immed4Field() const { return Bits(19, 16); }
|
||||
inline int ImmedMovwMovtField() const {
|
||||
return Immed4Field() << 12 | Offset12Field(); }
|
||||
inline int RotateValue() const { return Bits(11, 8); }
|
||||
inline int Immed8Value() const { return Bits(7, 0); }
|
||||
inline int Immed4Value() const { return Bits(19, 16); }
|
||||
inline int ImmedMovwMovtValue() const {
|
||||
return Immed4Value() << 12 | Offset12Value(); }
|
||||
|
||||
// Fields used in Load/Store instructions
|
||||
inline int PUField() const { return Bits(24, 23); }
|
||||
inline int BField() const { return Bit(22); }
|
||||
inline int WField() const { return Bit(21); }
|
||||
inline int LField() const { return Bit(20); }
|
||||
inline int PUValue() const { return Bits(24, 23); }
|
||||
inline int PUField() const { return BitField(24, 23); }
|
||||
inline int BValue() const { return Bit(22); }
|
||||
inline int WValue() const { return Bit(21); }
|
||||
inline int LValue() const { return Bit(20); }
|
||||
// with register uses same fields as Data processing instructions above
|
||||
// with immediate
|
||||
inline int Offset12Field() const { return Bits(11, 0); }
|
||||
inline int Offset12Value() const { return Bits(11, 0); }
|
||||
// multiple
|
||||
inline int RlistField() const { return Bits(15, 0); }
|
||||
inline int RlistValue() const { return Bits(15, 0); }
|
||||
// extra loads and stores
|
||||
inline int SignField() const { return Bit(6); }
|
||||
inline int HField() const { return Bit(5); }
|
||||
inline int ImmedHField() const { return Bits(11, 8); }
|
||||
inline int ImmedLField() const { return Bits(3, 0); }
|
||||
inline int SignValue() const { return Bit(6); }
|
||||
inline int HValue() const { return Bit(5); }
|
||||
inline int ImmedHValue() const { return Bits(11, 8); }
|
||||
inline int ImmedLValue() const { return Bits(3, 0); }
|
||||
|
||||
// Fields used in Branch instructions
|
||||
inline int LinkField() const { return Bit(24); }
|
||||
inline int SImmed24Field() const { return ((InstructionBits() << 8) >> 8); }
|
||||
inline int LinkValue() const { return Bit(24); }
|
||||
inline int SImmed24Value() const { return ((InstructionBits() << 8) >> 8); }
|
||||
|
||||
// Fields used in Software interrupt instructions
|
||||
inline SoftwareInterruptCodes SvcField() const {
|
||||
inline SoftwareInterruptCodes SvcValue() const {
|
||||
return static_cast<SoftwareInterruptCodes>(Bits(23, 0));
|
||||
}
|
||||
|
||||
@ -354,42 +667,45 @@ class Instr {
|
||||
|
||||
// Test for a stop instruction.
|
||||
inline bool IsStop() const {
|
||||
return (TypeField() == 7) && (Bit(24) == 1) && (SvcField() >= stop);
|
||||
return (TypeValue() == 7) && (Bit(24) == 1) && (SvcValue() >= kStopCode);
|
||||
}
|
||||
|
||||
// Special accessors that test for existence of a value.
|
||||
inline bool HasS() const { return SField() == 1; }
|
||||
inline bool HasB() const { return BField() == 1; }
|
||||
inline bool HasW() const { return WField() == 1; }
|
||||
inline bool HasL() const { return LField() == 1; }
|
||||
inline bool HasU() const { return UField() == 1; }
|
||||
inline bool HasSign() const { return SignField() == 1; }
|
||||
inline bool HasH() const { return HField() == 1; }
|
||||
inline bool HasLink() const { return LinkField() == 1; }
|
||||
inline bool HasS() const { return SValue() == 1; }
|
||||
inline bool HasB() const { return BValue() == 1; }
|
||||
inline bool HasW() const { return WValue() == 1; }
|
||||
inline bool HasL() const { return LValue() == 1; }
|
||||
inline bool HasU() const { return UValue() == 1; }
|
||||
inline bool HasSign() const { return SignValue() == 1; }
|
||||
inline bool HasH() const { return HValue() == 1; }
|
||||
inline bool HasLink() const { return LinkValue() == 1; }
|
||||
|
||||
// Decoding the double immediate in the vmov instruction.
|
||||
double DoubleImmedVmov() const;
|
||||
|
||||
// Instructions are read of out a code stream. The only way to get a
|
||||
// reference to an instruction is to convert a pointer. There is no way
|
||||
// to allocate or create instances of class Instr.
|
||||
// Use the At(pc) function to create references to Instr.
|
||||
static Instr* At(byte* pc) { return reinterpret_cast<Instr*>(pc); }
|
||||
// to allocate or create instances of class Instruction.
|
||||
// Use the At(pc) function to create references to Instruction.
|
||||
static Instruction* At(byte* pc) {
|
||||
return reinterpret_cast<Instruction*>(pc);
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
// Join split register codes, depending on single or double precision.
|
||||
// four_bit is the position of the least-significant bit of the four
|
||||
// bit specifier. one_bit is the position of the additional single bit
|
||||
// specifier.
|
||||
inline int VFPGlueRegCode(VFPRegPrecision pre, int four_bit, int one_bit) {
|
||||
inline int VFPGlueRegValue(VFPRegPrecision pre, int four_bit, int one_bit) {
|
||||
if (pre == kSinglePrecision) {
|
||||
return (Bits(four_bit + 3, four_bit) << 1) | Bit(one_bit);
|
||||
}
|
||||
return (Bit(one_bit) << 4) | Bits(four_bit + 3, four_bit);
|
||||
}
|
||||
|
||||
// We need to prevent the creation of instances of class Instr.
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(Instr);
|
||||
// We need to prevent the creation of instances of class Instruction.
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(Instruction);
|
||||
};
|
||||
|
||||
|
||||
@ -428,6 +744,6 @@ class VFPRegisters {
|
||||
};
|
||||
|
||||
|
||||
} } // namespace assembler::arm
|
||||
} } // namespace v8::internal
|
||||
|
||||
#endif // V8_ARM_CONSTANTS_ARM_H_
|
||||
|
@ -56,7 +56,7 @@ void CPU::FlushICache(void* start, size_t size) {
|
||||
// that the Icache was flushed.
|
||||
// None of this code ends up in the snapshot so there are no issues
|
||||
// around whether or not to generate the code when building snapshots.
|
||||
assembler::arm::Simulator::FlushICache(start, size);
|
||||
Simulator::FlushICache(start, size);
|
||||
#else
|
||||
// Ideally, we would call
|
||||
// syscall(__ARM_NR_cacheflush, start,
|
||||
|
@ -64,10 +64,8 @@
|
||||
#include "platform.h"
|
||||
|
||||
|
||||
namespace assembler {
|
||||
namespace arm {
|
||||
|
||||
namespace v8i = v8::internal;
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@ -78,7 +76,7 @@ namespace v8i = v8::internal;
|
||||
class Decoder {
|
||||
public:
|
||||
Decoder(const disasm::NameConverter& converter,
|
||||
v8::internal::Vector<char> out_buffer)
|
||||
Vector<char> out_buffer)
|
||||
: converter_(converter),
|
||||
out_buffer_(out_buffer),
|
||||
out_buffer_pos_(0) {
|
||||
@ -100,45 +98,45 @@ class Decoder {
|
||||
void PrintRegister(int reg);
|
||||
void PrintSRegister(int reg);
|
||||
void PrintDRegister(int reg);
|
||||
int FormatVFPRegister(Instr* instr, const char* format);
|
||||
void PrintMovwMovt(Instr* instr);
|
||||
int FormatVFPinstruction(Instr* instr, const char* format);
|
||||
void PrintCondition(Instr* instr);
|
||||
void PrintShiftRm(Instr* instr);
|
||||
void PrintShiftImm(Instr* instr);
|
||||
void PrintShiftSat(Instr* instr);
|
||||
void PrintPU(Instr* instr);
|
||||
int FormatVFPRegister(Instruction* instr, const char* format);
|
||||
void PrintMovwMovt(Instruction* instr);
|
||||
int FormatVFPinstruction(Instruction* instr, const char* format);
|
||||
void PrintCondition(Instruction* instr);
|
||||
void PrintShiftRm(Instruction* instr);
|
||||
void PrintShiftImm(Instruction* instr);
|
||||
void PrintShiftSat(Instruction* instr);
|
||||
void PrintPU(Instruction* instr);
|
||||
void PrintSoftwareInterrupt(SoftwareInterruptCodes svc);
|
||||
|
||||
// Handle formatting of instructions and their options.
|
||||
int FormatRegister(Instr* instr, const char* option);
|
||||
int FormatOption(Instr* instr, const char* option);
|
||||
void Format(Instr* instr, const char* format);
|
||||
void Unknown(Instr* instr);
|
||||
int FormatRegister(Instruction* instr, const char* option);
|
||||
int FormatOption(Instruction* instr, const char* option);
|
||||
void Format(Instruction* instr, const char* format);
|
||||
void Unknown(Instruction* instr);
|
||||
|
||||
// Each of these functions decodes one particular instruction type, a 3-bit
|
||||
// field in the instruction encoding.
|
||||
// Types 0 and 1 are combined as they are largely the same except for the way
|
||||
// they interpret the shifter operand.
|
||||
void DecodeType01(Instr* instr);
|
||||
void DecodeType2(Instr* instr);
|
||||
void DecodeType3(Instr* instr);
|
||||
void DecodeType4(Instr* instr);
|
||||
void DecodeType5(Instr* instr);
|
||||
void DecodeType6(Instr* instr);
|
||||
void DecodeType01(Instruction* instr);
|
||||
void DecodeType2(Instruction* instr);
|
||||
void DecodeType3(Instruction* instr);
|
||||
void DecodeType4(Instruction* instr);
|
||||
void DecodeType5(Instruction* instr);
|
||||
void DecodeType6(Instruction* instr);
|
||||
// Type 7 includes special Debugger instructions.
|
||||
int DecodeType7(Instr* instr);
|
||||
int DecodeType7(Instruction* instr);
|
||||
// For VFP support.
|
||||
void DecodeTypeVFP(Instr* instr);
|
||||
void DecodeType6CoprocessorIns(Instr* instr);
|
||||
void DecodeTypeVFP(Instruction* instr);
|
||||
void DecodeType6CoprocessorIns(Instruction* instr);
|
||||
|
||||
void DecodeVMOVBetweenCoreAndSinglePrecisionRegisters(Instr* instr);
|
||||
void DecodeVCMP(Instr* instr);
|
||||
void DecodeVCVTBetweenDoubleAndSingle(Instr* instr);
|
||||
void DecodeVCVTBetweenFloatingPointAndInteger(Instr* instr);
|
||||
void DecodeVMOVBetweenCoreAndSinglePrecisionRegisters(Instruction* instr);
|
||||
void DecodeVCMP(Instruction* instr);
|
||||
void DecodeVCVTBetweenDoubleAndSingle(Instruction* instr);
|
||||
void DecodeVCVTBetweenFloatingPointAndInteger(Instruction* instr);
|
||||
|
||||
const disasm::NameConverter& converter_;
|
||||
v8::internal::Vector<char> out_buffer_;
|
||||
Vector<char> out_buffer_;
|
||||
int out_buffer_pos_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Decoder);
|
||||
@ -169,15 +167,15 @@ void Decoder::Print(const char* str) {
|
||||
|
||||
// These condition names are defined in a way to match the native disassembler
|
||||
// formatting. See for example the command "objdump -d <binary file>".
|
||||
static const char* cond_names[max_condition] = {
|
||||
static const char* cond_names[kNumberOfConditions] = {
|
||||
"eq", "ne", "cs" , "cc" , "mi" , "pl" , "vs" , "vc" ,
|
||||
"hi", "ls", "ge", "lt", "gt", "le", "", "invalid",
|
||||
};
|
||||
|
||||
|
||||
// Print the condition guarding the instruction.
|
||||
void Decoder::PrintCondition(Instr* instr) {
|
||||
Print(cond_names[instr->ConditionField()]);
|
||||
void Decoder::PrintCondition(Instruction* instr) {
|
||||
Print(cond_names[instr->ConditionValue()]);
|
||||
}
|
||||
|
||||
|
||||
@ -188,36 +186,37 @@ void Decoder::PrintRegister(int reg) {
|
||||
|
||||
// Print the VFP S register name according to the active name converter.
|
||||
void Decoder::PrintSRegister(int reg) {
|
||||
Print(assembler::arm::VFPRegisters::Name(reg, false));
|
||||
Print(VFPRegisters::Name(reg, false));
|
||||
}
|
||||
|
||||
// Print the VFP D register name according to the active name converter.
|
||||
void Decoder::PrintDRegister(int reg) {
|
||||
Print(assembler::arm::VFPRegisters::Name(reg, true));
|
||||
Print(VFPRegisters::Name(reg, true));
|
||||
}
|
||||
|
||||
|
||||
// These shift names are defined in a way to match the native disassembler
|
||||
// formatting. See for example the command "objdump -d <binary file>".
|
||||
static const char* shift_names[max_shift] = {
|
||||
static const char* shift_names[kNumberOfShifts] = {
|
||||
"lsl", "lsr", "asr", "ror"
|
||||
};
|
||||
|
||||
|
||||
// Print the register shift operands for the instruction. Generally used for
|
||||
// data processing instructions.
|
||||
void Decoder::PrintShiftRm(Instr* instr) {
|
||||
Shift shift = instr->ShiftField();
|
||||
int shift_amount = instr->ShiftAmountField();
|
||||
int rm = instr->RmField();
|
||||
void Decoder::PrintShiftRm(Instruction* instr) {
|
||||
ShiftOp shift = instr->ShiftField();
|
||||
int shift_index = instr->ShiftValue();
|
||||
int shift_amount = instr->ShiftAmountValue();
|
||||
int rm = instr->RmValue();
|
||||
|
||||
PrintRegister(rm);
|
||||
|
||||
if ((instr->RegShiftField() == 0) && (shift == LSL) && (shift_amount == 0)) {
|
||||
if ((instr->RegShiftValue() == 0) && (shift == LSL) && (shift_amount == 0)) {
|
||||
// Special case for using rm only.
|
||||
return;
|
||||
}
|
||||
if (instr->RegShiftField() == 0) {
|
||||
if (instr->RegShiftValue() == 0) {
|
||||
// by immediate
|
||||
if ((shift == ROR) && (shift_amount == 0)) {
|
||||
Print(", RRX");
|
||||
@ -225,14 +224,15 @@ void Decoder::PrintShiftRm(Instr* instr) {
|
||||
} else if (((shift == LSR) || (shift == ASR)) && (shift_amount == 0)) {
|
||||
shift_amount = 32;
|
||||
}
|
||||
out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_,
|
||||
", %s #%d",
|
||||
shift_names[shift], shift_amount);
|
||||
out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_,
|
||||
", %s #%d",
|
||||
shift_names[shift_index],
|
||||
shift_amount);
|
||||
} else {
|
||||
// by register
|
||||
int rs = instr->RsField();
|
||||
out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_,
|
||||
", %s ", shift_names[shift]);
|
||||
int rs = instr->RsValue();
|
||||
out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_,
|
||||
", %s ", shift_names[shift_index]);
|
||||
PrintRegister(rs);
|
||||
}
|
||||
}
|
||||
@ -240,43 +240,43 @@ void Decoder::PrintShiftRm(Instr* instr) {
|
||||
|
||||
// Print the immediate operand for the instruction. Generally used for data
|
||||
// processing instructions.
|
||||
void Decoder::PrintShiftImm(Instr* instr) {
|
||||
int rotate = instr->RotateField() * 2;
|
||||
int immed8 = instr->Immed8Field();
|
||||
void Decoder::PrintShiftImm(Instruction* instr) {
|
||||
int rotate = instr->RotateValue() * 2;
|
||||
int immed8 = instr->Immed8Value();
|
||||
int imm = (immed8 >> rotate) | (immed8 << (32 - rotate));
|
||||
out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_,
|
||||
"#%d", imm);
|
||||
out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_,
|
||||
"#%d", imm);
|
||||
}
|
||||
|
||||
|
||||
// Print the optional shift and immediate used by saturating instructions.
|
||||
void Decoder::PrintShiftSat(Instr* instr) {
|
||||
void Decoder::PrintShiftSat(Instruction* instr) {
|
||||
int shift = instr->Bits(11, 7);
|
||||
if (shift > 0) {
|
||||
out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_,
|
||||
", %s #%d",
|
||||
shift_names[instr->Bit(6) * 2],
|
||||
instr->Bits(11, 7));
|
||||
out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_,
|
||||
", %s #%d",
|
||||
shift_names[instr->Bit(6) * 2],
|
||||
instr->Bits(11, 7));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Print PU formatting to reduce complexity of FormatOption.
|
||||
void Decoder::PrintPU(Instr* instr) {
|
||||
void Decoder::PrintPU(Instruction* instr) {
|
||||
switch (instr->PUField()) {
|
||||
case 0: {
|
||||
case da_x: {
|
||||
Print("da");
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
case ia_x: {
|
||||
Print("ia");
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
case db_x: {
|
||||
Print("db");
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
case ib_x: {
|
||||
Print("ib");
|
||||
break;
|
||||
}
|
||||
@ -292,22 +292,22 @@ void Decoder::PrintPU(Instr* instr) {
|
||||
// the FormatOption method.
|
||||
void Decoder::PrintSoftwareInterrupt(SoftwareInterruptCodes svc) {
|
||||
switch (svc) {
|
||||
case call_rt_redirected:
|
||||
Print("call_rt_redirected");
|
||||
case kCallRtRedirected:
|
||||
Print("call rt redirected");
|
||||
return;
|
||||
case break_point:
|
||||
Print("break_point");
|
||||
case kBreakpoint:
|
||||
Print("breakpoint");
|
||||
return;
|
||||
default:
|
||||
if (svc >= stop) {
|
||||
out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_,
|
||||
"%d - 0x%x",
|
||||
svc & kStopCodeMask,
|
||||
svc & kStopCodeMask);
|
||||
if (svc >= kStopCode) {
|
||||
out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_,
|
||||
"%d - 0x%x",
|
||||
svc & kStopCodeMask,
|
||||
svc & kStopCodeMask);
|
||||
} else {
|
||||
out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_,
|
||||
"%d",
|
||||
svc);
|
||||
out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_,
|
||||
"%d",
|
||||
svc);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -316,32 +316,32 @@ void Decoder::PrintSoftwareInterrupt(SoftwareInterruptCodes svc) {
|
||||
|
||||
// Handle all register based formatting in this function to reduce the
|
||||
// complexity of FormatOption.
|
||||
int Decoder::FormatRegister(Instr* instr, const char* format) {
|
||||
int Decoder::FormatRegister(Instruction* instr, const char* format) {
|
||||
ASSERT(format[0] == 'r');
|
||||
if (format[1] == 'n') { // 'rn: Rn register
|
||||
int reg = instr->RnField();
|
||||
int reg = instr->RnValue();
|
||||
PrintRegister(reg);
|
||||
return 2;
|
||||
} else if (format[1] == 'd') { // 'rd: Rd register
|
||||
int reg = instr->RdField();
|
||||
int reg = instr->RdValue();
|
||||
PrintRegister(reg);
|
||||
return 2;
|
||||
} else if (format[1] == 's') { // 'rs: Rs register
|
||||
int reg = instr->RsField();
|
||||
int reg = instr->RsValue();
|
||||
PrintRegister(reg);
|
||||
return 2;
|
||||
} else if (format[1] == 'm') { // 'rm: Rm register
|
||||
int reg = instr->RmField();
|
||||
int reg = instr->RmValue();
|
||||
PrintRegister(reg);
|
||||
return 2;
|
||||
} else if (format[1] == 't') { // 'rt: Rt register
|
||||
int reg = instr->RtField();
|
||||
int reg = instr->RtValue();
|
||||
PrintRegister(reg);
|
||||
return 2;
|
||||
} else if (format[1] == 'l') {
|
||||
// 'rlist: register list for load and store multiple instructions
|
||||
ASSERT(STRING_STARTS_WITH(format, "rlist"));
|
||||
int rlist = instr->RlistField();
|
||||
int rlist = instr->RlistValue();
|
||||
int reg = 0;
|
||||
Print("{");
|
||||
// Print register list in ascending order, by scanning the bit mask.
|
||||
@ -365,22 +365,22 @@ int Decoder::FormatRegister(Instr* instr, const char* format) {
|
||||
|
||||
// Handle all VFP register based formatting in this function to reduce the
|
||||
// complexity of FormatOption.
|
||||
int Decoder::FormatVFPRegister(Instr* instr, const char* format) {
|
||||
int Decoder::FormatVFPRegister(Instruction* instr, const char* format) {
|
||||
ASSERT((format[0] == 'S') || (format[0] == 'D'));
|
||||
|
||||
if (format[1] == 'n') {
|
||||
int reg = instr->VnField();
|
||||
if (format[0] == 'S') PrintSRegister(((reg << 1) | instr->NField()));
|
||||
int reg = instr->VnValue();
|
||||
if (format[0] == 'S') PrintSRegister(((reg << 1) | instr->NValue()));
|
||||
if (format[0] == 'D') PrintDRegister(reg);
|
||||
return 2;
|
||||
} else if (format[1] == 'm') {
|
||||
int reg = instr->VmField();
|
||||
if (format[0] == 'S') PrintSRegister(((reg << 1) | instr->MField()));
|
||||
int reg = instr->VmValue();
|
||||
if (format[0] == 'S') PrintSRegister(((reg << 1) | instr->MValue()));
|
||||
if (format[0] == 'D') PrintDRegister(reg);
|
||||
return 2;
|
||||
} else if (format[1] == 'd') {
|
||||
int reg = instr->VdField();
|
||||
if (format[0] == 'S') PrintSRegister(((reg << 1) | instr->DField()));
|
||||
int reg = instr->VdValue();
|
||||
if (format[0] == 'S') PrintSRegister(((reg << 1) | instr->DValue()));
|
||||
if (format[0] == 'D') PrintDRegister(reg);
|
||||
return 2;
|
||||
}
|
||||
@ -390,19 +390,19 @@ int Decoder::FormatVFPRegister(Instr* instr, const char* format) {
|
||||
}
|
||||
|
||||
|
||||
int Decoder::FormatVFPinstruction(Instr* instr, const char* format) {
|
||||
int Decoder::FormatVFPinstruction(Instruction* instr, const char* format) {
|
||||
Print(format);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// Print the movw or movt instruction.
|
||||
void Decoder::PrintMovwMovt(Instr* instr) {
|
||||
int imm = instr->ImmedMovwMovtField();
|
||||
int rd = instr->RdField();
|
||||
void Decoder::PrintMovwMovt(Instruction* instr) {
|
||||
int imm = instr->ImmedMovwMovtValue();
|
||||
int rd = instr->RdValue();
|
||||
PrintRegister(rd);
|
||||
out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_,
|
||||
", #%d", imm);
|
||||
out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_,
|
||||
", #%d", imm);
|
||||
}
|
||||
|
||||
|
||||
@ -411,7 +411,7 @@ void Decoder::PrintMovwMovt(Instr* instr) {
|
||||
// character of the option string (the option escape has already been
|
||||
// consumed by the caller.) FormatOption returns the number of
|
||||
// characters that were consumed from the formatting string.
|
||||
int Decoder::FormatOption(Instr* instr, const char* format) {
|
||||
int Decoder::FormatOption(Instruction* instr, const char* format) {
|
||||
switch (format[0]) {
|
||||
case 'a': { // 'a: accumulate multiplies
|
||||
if (instr->Bit(21) == 0) {
|
||||
@ -434,8 +434,8 @@ int Decoder::FormatOption(Instr* instr, const char* format) {
|
||||
}
|
||||
case 'd': { // 'd: vmov double immediate.
|
||||
double d = instr->DoubleImmedVmov();
|
||||
out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_,
|
||||
"#%g", d);
|
||||
out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_,
|
||||
"#%g", d);
|
||||
return 1;
|
||||
}
|
||||
case 'f': { // 'f: bitfield instructions - v7 and above.
|
||||
@ -448,8 +448,8 @@ int Decoder::FormatOption(Instr* instr, const char* format) {
|
||||
ASSERT(width > 0);
|
||||
}
|
||||
ASSERT((width + lsbit) <= 32);
|
||||
out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_,
|
||||
"#%d, #%d", lsbit, width);
|
||||
out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_,
|
||||
"#%d, #%d", lsbit, width);
|
||||
return 1;
|
||||
}
|
||||
case 'h': { // 'h: halfword operation for extra loads and stores
|
||||
@ -469,9 +469,9 @@ int Decoder::FormatOption(Instr* instr, const char* format) {
|
||||
ASSERT((lsb >= 0) && (lsb <= 31));
|
||||
ASSERT((width + lsb) <= 32);
|
||||
|
||||
out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_,
|
||||
"%d",
|
||||
instr->Bits(width + lsb - 1, lsb));
|
||||
out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_,
|
||||
"%d",
|
||||
instr->Bits(width + lsb - 1, lsb));
|
||||
return 8;
|
||||
}
|
||||
case 'l': { // 'l: branch and link
|
||||
@ -505,31 +505,31 @@ int Decoder::FormatOption(Instr* instr, const char* format) {
|
||||
ASSERT(STRING_STARTS_WITH(format, "msg"));
|
||||
byte* str =
|
||||
reinterpret_cast<byte*>(instr->InstructionBits() & 0x0fffffff);
|
||||
out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_,
|
||||
"%s", converter_.NameInCode(str));
|
||||
out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_,
|
||||
"%s", converter_.NameInCode(str));
|
||||
return 3;
|
||||
}
|
||||
case 'o': {
|
||||
if ((format[3] == '1') && (format[4] == '2')) {
|
||||
// 'off12: 12-bit offset for load and store instructions
|
||||
ASSERT(STRING_STARTS_WITH(format, "off12"));
|
||||
out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_,
|
||||
"%d", instr->Offset12Field());
|
||||
out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_,
|
||||
"%d", instr->Offset12Value());
|
||||
return 5;
|
||||
} else if (format[3] == '0') {
|
||||
// 'off0to3and8to19 16-bit immediate encoded in bits 19-8 and 3-0.
|
||||
ASSERT(STRING_STARTS_WITH(format, "off0to3and8to19"));
|
||||
out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_,
|
||||
"%d",
|
||||
(instr->Bits(19, 8) << 4) +
|
||||
instr->Bits(3, 0));
|
||||
out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_,
|
||||
"%d",
|
||||
(instr->Bits(19, 8) << 4) +
|
||||
instr->Bits(3, 0));
|
||||
return 15;
|
||||
}
|
||||
// 'off8: 8-bit offset for extra load and store instructions
|
||||
ASSERT(STRING_STARTS_WITH(format, "off8"));
|
||||
int offs8 = (instr->ImmedHField() << 4) | instr->ImmedLField();
|
||||
out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_,
|
||||
"%d", offs8);
|
||||
int offs8 = (instr->ImmedHValue() << 4) | instr->ImmedLValue();
|
||||
out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_,
|
||||
"%d", offs8);
|
||||
return 4;
|
||||
}
|
||||
case 'p': { // 'pu: P and U bits for load and store instructions
|
||||
@ -544,10 +544,10 @@ int Decoder::FormatOption(Instr* instr, const char* format) {
|
||||
if (format[1] == 'h') { // 'shift_op or 'shift_rm or 'shift_sat.
|
||||
if (format[6] == 'o') { // 'shift_op
|
||||
ASSERT(STRING_STARTS_WITH(format, "shift_op"));
|
||||
if (instr->TypeField() == 0) {
|
||||
if (instr->TypeValue() == 0) {
|
||||
PrintShiftRm(instr);
|
||||
} else {
|
||||
ASSERT(instr->TypeField() == 1);
|
||||
ASSERT(instr->TypeValue() == 1);
|
||||
PrintShiftImm(instr);
|
||||
}
|
||||
return 8;
|
||||
@ -562,7 +562,7 @@ int Decoder::FormatOption(Instr* instr, const char* format) {
|
||||
}
|
||||
} else if (format[1] == 'v') { // 'svc
|
||||
ASSERT(STRING_STARTS_WITH(format, "svc"));
|
||||
PrintSoftwareInterrupt(instr->SvcField());
|
||||
PrintSoftwareInterrupt(instr->SvcValue());
|
||||
return 3;
|
||||
} else if (format[1] == 'i') { // 'sign: signed extra loads and stores
|
||||
ASSERT(STRING_STARTS_WITH(format, "sign"));
|
||||
@ -579,12 +579,12 @@ int Decoder::FormatOption(Instr* instr, const char* format) {
|
||||
}
|
||||
case 't': { // 'target: target of branch instructions
|
||||
ASSERT(STRING_STARTS_WITH(format, "target"));
|
||||
int off = (instr->SImmed24Field() << 2) + 8;
|
||||
out_buffer_pos_ += v8i::OS::SNPrintF(
|
||||
out_buffer_ + out_buffer_pos_,
|
||||
"%+d -> %s",
|
||||
off,
|
||||
converter_.NameOfAddress(reinterpret_cast<byte*>(instr) + off));
|
||||
int off = (instr->SImmed24Value() << 2) + 8;
|
||||
out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_,
|
||||
"%+d -> %s",
|
||||
off,
|
||||
converter_.NameOfAddress(
|
||||
reinterpret_cast<byte*>(instr) + off));
|
||||
return 6;
|
||||
}
|
||||
case 'u': { // 'u: signed or unsigned multiplies
|
||||
@ -633,7 +633,7 @@ int Decoder::FormatOption(Instr* instr, const char* format) {
|
||||
// Format takes a formatting string for a whole instruction and prints it into
|
||||
// the output buffer. All escaped options are handed to FormatOption to be
|
||||
// parsed further.
|
||||
void Decoder::Format(Instr* instr, const char* format) {
|
||||
void Decoder::Format(Instruction* instr, const char* format) {
|
||||
char cur = *format++;
|
||||
while ((cur != 0) && (out_buffer_pos_ < (out_buffer_.length() - 1))) {
|
||||
if (cur == '\'') { // Single quote is used as the formatting escape.
|
||||
@ -649,13 +649,13 @@ void Decoder::Format(Instr* instr, const char* format) {
|
||||
|
||||
// For currently unimplemented decodings the disassembler calls Unknown(instr)
|
||||
// which will just print "unknown" of the instruction bits.
|
||||
void Decoder::Unknown(Instr* instr) {
|
||||
void Decoder::Unknown(Instruction* instr) {
|
||||
Format(instr, "unknown");
|
||||
}
|
||||
|
||||
|
||||
void Decoder::DecodeType01(Instr* instr) {
|
||||
int type = instr->TypeField();
|
||||
void Decoder::DecodeType01(Instruction* instr) {
|
||||
int type = instr->TypeValue();
|
||||
if ((type == 0) && instr->IsSpecialType0()) {
|
||||
// multiply instruction or extra loads and stores
|
||||
if (instr->Bits(7, 4) == 9) {
|
||||
@ -689,7 +689,7 @@ void Decoder::DecodeType01(Instr* instr) {
|
||||
} else if ((instr->Bit(20) == 0) && ((instr->Bits(7, 4) & 0xd) == 0xd)) {
|
||||
// ldrd, strd
|
||||
switch (instr->PUField()) {
|
||||
case 0: {
|
||||
case da_x: {
|
||||
if (instr->Bit(22) == 0) {
|
||||
Format(instr, "'memop'cond's 'rd, ['rn], -'rm");
|
||||
} else {
|
||||
@ -697,7 +697,7 @@ void Decoder::DecodeType01(Instr* instr) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
case ia_x: {
|
||||
if (instr->Bit(22) == 0) {
|
||||
Format(instr, "'memop'cond's 'rd, ['rn], +'rm");
|
||||
} else {
|
||||
@ -705,7 +705,7 @@ void Decoder::DecodeType01(Instr* instr) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
case db_x: {
|
||||
if (instr->Bit(22) == 0) {
|
||||
Format(instr, "'memop'cond's 'rd, ['rn, -'rm]'w");
|
||||
} else {
|
||||
@ -713,7 +713,7 @@ void Decoder::DecodeType01(Instr* instr) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
case ib_x: {
|
||||
if (instr->Bit(22) == 0) {
|
||||
Format(instr, "'memop'cond's 'rd, ['rn, +'rm]'w");
|
||||
} else {
|
||||
@ -730,7 +730,7 @@ void Decoder::DecodeType01(Instr* instr) {
|
||||
} else {
|
||||
// extra load/store instructions
|
||||
switch (instr->PUField()) {
|
||||
case 0: {
|
||||
case da_x: {
|
||||
if (instr->Bit(22) == 0) {
|
||||
Format(instr, "'memop'cond'sign'h 'rd, ['rn], -'rm");
|
||||
} else {
|
||||
@ -738,7 +738,7 @@ void Decoder::DecodeType01(Instr* instr) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
case ia_x: {
|
||||
if (instr->Bit(22) == 0) {
|
||||
Format(instr, "'memop'cond'sign'h 'rd, ['rn], +'rm");
|
||||
} else {
|
||||
@ -746,7 +746,7 @@ void Decoder::DecodeType01(Instr* instr) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
case db_x: {
|
||||
if (instr->Bit(22) == 0) {
|
||||
Format(instr, "'memop'cond'sign'h 'rd, ['rn, -'rm]'w");
|
||||
} else {
|
||||
@ -754,7 +754,7 @@ void Decoder::DecodeType01(Instr* instr) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
case ib_x: {
|
||||
if (instr->Bit(22) == 0) {
|
||||
Format(instr, "'memop'cond'sign'h 'rd, ['rn, +'rm]'w");
|
||||
} else {
|
||||
@ -772,7 +772,7 @@ void Decoder::DecodeType01(Instr* instr) {
|
||||
}
|
||||
} else if ((type == 0) && instr->IsMiscType0()) {
|
||||
if (instr->Bits(22, 21) == 1) {
|
||||
switch (instr->Bits(7, 4)) {
|
||||
switch (instr->BitField(7, 4)) {
|
||||
case BX:
|
||||
Format(instr, "bx'cond 'rm");
|
||||
break;
|
||||
@ -787,7 +787,7 @@ void Decoder::DecodeType01(Instr* instr) {
|
||||
break;
|
||||
}
|
||||
} else if (instr->Bits(22, 21) == 3) {
|
||||
switch (instr->Bits(7, 4)) {
|
||||
switch (instr->BitField(7, 4)) {
|
||||
case CLZ:
|
||||
Format(instr, "clz'cond 'rd, 'rm");
|
||||
break;
|
||||
@ -894,27 +894,27 @@ void Decoder::DecodeType01(Instr* instr) {
|
||||
}
|
||||
|
||||
|
||||
void Decoder::DecodeType2(Instr* instr) {
|
||||
void Decoder::DecodeType2(Instruction* instr) {
|
||||
switch (instr->PUField()) {
|
||||
case 0: {
|
||||
case da_x: {
|
||||
if (instr->HasW()) {
|
||||
Unknown(instr); // not used in V8
|
||||
}
|
||||
Format(instr, "'memop'cond'b 'rd, ['rn], #-'off12");
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
case ia_x: {
|
||||
if (instr->HasW()) {
|
||||
Unknown(instr); // not used in V8
|
||||
}
|
||||
Format(instr, "'memop'cond'b 'rd, ['rn], #+'off12");
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
case db_x: {
|
||||
Format(instr, "'memop'cond'b 'rd, ['rn, #-'off12]'w");
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
case ib_x: {
|
||||
Format(instr, "'memop'cond'b 'rd, ['rn, #+'off12]'w");
|
||||
break;
|
||||
}
|
||||
@ -927,14 +927,14 @@ void Decoder::DecodeType2(Instr* instr) {
|
||||
}
|
||||
|
||||
|
||||
void Decoder::DecodeType3(Instr* instr) {
|
||||
void Decoder::DecodeType3(Instruction* instr) {
|
||||
switch (instr->PUField()) {
|
||||
case 0: {
|
||||
case da_x: {
|
||||
ASSERT(!instr->HasW());
|
||||
Format(instr, "'memop'cond'b 'rd, ['rn], -'shift_rm");
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
case ia_x: {
|
||||
if (instr->HasW()) {
|
||||
ASSERT(instr->Bits(5, 4) == 0x1);
|
||||
if (instr->Bit(22) == 0x1) {
|
||||
@ -947,11 +947,11 @@ void Decoder::DecodeType3(Instr* instr) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
case db_x: {
|
||||
Format(instr, "'memop'cond'b 'rd, ['rn, -'shift_rm]'w");
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
case ib_x: {
|
||||
if (instr->HasW() && (instr->Bits(6, 4) == 0x5)) {
|
||||
uint32_t widthminus1 = static_cast<uint32_t>(instr->Bits(20, 16));
|
||||
uint32_t lsbit = static_cast<uint32_t>(instr->Bits(11, 7));
|
||||
@ -969,7 +969,7 @@ void Decoder::DecodeType3(Instr* instr) {
|
||||
uint32_t lsbit = static_cast<uint32_t>(instr->Bits(11, 7));
|
||||
uint32_t msbit = static_cast<uint32_t>(instr->Bits(20, 16));
|
||||
if (msbit >= lsbit) {
|
||||
if (instr->RmField() == 15) {
|
||||
if (instr->RmValue() == 15) {
|
||||
Format(instr, "bfc'cond 'rd, 'f");
|
||||
} else {
|
||||
Format(instr, "bfi'cond 'rd, 'rm, 'f");
|
||||
@ -991,7 +991,7 @@ void Decoder::DecodeType3(Instr* instr) {
|
||||
}
|
||||
|
||||
|
||||
void Decoder::DecodeType4(Instr* instr) {
|
||||
void Decoder::DecodeType4(Instruction* instr) {
|
||||
ASSERT(instr->Bit(22) == 0); // Privileged mode currently not supported.
|
||||
if (instr->HasL()) {
|
||||
Format(instr, "ldm'cond'pu 'rn'w, 'rlist");
|
||||
@ -1001,41 +1001,43 @@ void Decoder::DecodeType4(Instr* instr) {
|
||||
}
|
||||
|
||||
|
||||
void Decoder::DecodeType5(Instr* instr) {
|
||||
void Decoder::DecodeType5(Instruction* instr) {
|
||||
Format(instr, "b'l'cond 'target");
|
||||
}
|
||||
|
||||
|
||||
void Decoder::DecodeType6(Instr* instr) {
|
||||
void Decoder::DecodeType6(Instruction* instr) {
|
||||
DecodeType6CoprocessorIns(instr);
|
||||
}
|
||||
|
||||
|
||||
int Decoder::DecodeType7(Instr* instr) {
|
||||
int Decoder::DecodeType7(Instruction* instr) {
|
||||
if (instr->Bit(24) == 1) {
|
||||
if (instr->SvcField() >= stop) {
|
||||
if (instr->SvcValue() >= kStopCode) {
|
||||
Format(instr, "stop'cond 'svc");
|
||||
// Also print the stop message. Its address is encoded
|
||||
// in the following 4 bytes.
|
||||
out_buffer_pos_ +=
|
||||
v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_,
|
||||
"\n %p %08x stop message: %s",
|
||||
reinterpret_cast<int32_t*>(instr + Instr::kInstrSize),
|
||||
*reinterpret_cast<char**>(instr + Instr::kInstrSize),
|
||||
*reinterpret_cast<char**>(instr + Instr::kInstrSize));
|
||||
// We have decoded 2 * Instr::kInstrSize bytes.
|
||||
return 2 * Instr::kInstrSize;
|
||||
out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_,
|
||||
"\n %p %08x stop message: %s",
|
||||
reinterpret_cast<int32_t*>(instr
|
||||
+ Instruction::kInstrSize),
|
||||
*reinterpret_cast<char**>(instr
|
||||
+ Instruction::kInstrSize),
|
||||
*reinterpret_cast<char**>(instr
|
||||
+ Instruction::kInstrSize));
|
||||
// We have decoded 2 * Instruction::kInstrSize bytes.
|
||||
return 2 * Instruction::kInstrSize;
|
||||
} else {
|
||||
Format(instr, "svc'cond 'svc");
|
||||
}
|
||||
} else {
|
||||
DecodeTypeVFP(instr);
|
||||
}
|
||||
return Instr::kInstrSize;
|
||||
return Instruction::kInstrSize;
|
||||
}
|
||||
|
||||
|
||||
// void Decoder::DecodeTypeVFP(Instr* instr)
|
||||
// void Decoder::DecodeTypeVFP(Instruction* instr)
|
||||
// vmov: Sn = Rt
|
||||
// vmov: Rt = Sn
|
||||
// vcvt: Dd = Sm
|
||||
@ -1048,34 +1050,34 @@ int Decoder::DecodeType7(Instr* instr) {
|
||||
// vmrs
|
||||
// vmsr
|
||||
// Dd = vsqrt(Dm)
|
||||
void Decoder::DecodeTypeVFP(Instr* instr) {
|
||||
ASSERT((instr->TypeField() == 7) && (instr->Bit(24) == 0x0) );
|
||||
void Decoder::DecodeTypeVFP(Instruction* instr) {
|
||||
ASSERT((instr->TypeValue() == 7) && (instr->Bit(24) == 0x0) );
|
||||
ASSERT(instr->Bits(11, 9) == 0x5);
|
||||
|
||||
if (instr->Bit(4) == 0) {
|
||||
if (instr->Opc1Field() == 0x7) {
|
||||
if (instr->Opc1Value() == 0x7) {
|
||||
// Other data processing instructions
|
||||
if ((instr->Opc2Field() == 0x0) && (instr->Opc3Field() == 0x1)) {
|
||||
if ((instr->Opc2Value() == 0x0) && (instr->Opc3Value() == 0x1)) {
|
||||
// vmov register to register.
|
||||
if (instr->SzField() == 0x1) {
|
||||
if (instr->SzValue() == 0x1) {
|
||||
Format(instr, "vmov.f64'cond 'Dd, 'Dm");
|
||||
} else {
|
||||
Format(instr, "vmov.f32'cond 'Sd, 'Sm");
|
||||
}
|
||||
} else if ((instr->Opc2Field() == 0x7) && (instr->Opc3Field() == 0x3)) {
|
||||
} else if ((instr->Opc2Value() == 0x7) && (instr->Opc3Value() == 0x3)) {
|
||||
DecodeVCVTBetweenDoubleAndSingle(instr);
|
||||
} else if ((instr->Opc2Field() == 0x8) && (instr->Opc3Field() & 0x1)) {
|
||||
} else if ((instr->Opc2Value() == 0x8) && (instr->Opc3Value() & 0x1)) {
|
||||
DecodeVCVTBetweenFloatingPointAndInteger(instr);
|
||||
} else if (((instr->Opc2Field() >> 1) == 0x6) &&
|
||||
(instr->Opc3Field() & 0x1)) {
|
||||
} else if (((instr->Opc2Value() >> 1) == 0x6) &&
|
||||
(instr->Opc3Value() & 0x1)) {
|
||||
DecodeVCVTBetweenFloatingPointAndInteger(instr);
|
||||
} else if (((instr->Opc2Field() == 0x4) || (instr->Opc2Field() == 0x5)) &&
|
||||
(instr->Opc3Field() & 0x1)) {
|
||||
} else if (((instr->Opc2Value() == 0x4) || (instr->Opc2Value() == 0x5)) &&
|
||||
(instr->Opc3Value() & 0x1)) {
|
||||
DecodeVCMP(instr);
|
||||
} else if (((instr->Opc2Field() == 0x1)) && (instr->Opc3Field() == 0x3)) {
|
||||
} else if (((instr->Opc2Value() == 0x1)) && (instr->Opc3Value() == 0x3)) {
|
||||
Format(instr, "vsqrt.f64'cond 'Dd, 'Dm");
|
||||
} else if (instr->Opc3Field() == 0x0) {
|
||||
if (instr->SzField() == 0x1) {
|
||||
} else if (instr->Opc3Value() == 0x0) {
|
||||
if (instr->SzValue() == 0x1) {
|
||||
Format(instr, "vmov.f64'cond 'Dd, 'd");
|
||||
} else {
|
||||
Unknown(instr); // Not used by V8.
|
||||
@ -1083,9 +1085,9 @@ void Decoder::DecodeTypeVFP(Instr* instr) {
|
||||
} else {
|
||||
Unknown(instr); // Not used by V8.
|
||||
}
|
||||
} else if (instr->Opc1Field() == 0x3) {
|
||||
if (instr->SzField() == 0x1) {
|
||||
if (instr->Opc3Field() & 0x1) {
|
||||
} else if (instr->Opc1Value() == 0x3) {
|
||||
if (instr->SzValue() == 0x1) {
|
||||
if (instr->Opc3Value() & 0x1) {
|
||||
Format(instr, "vsub.f64'cond 'Dd, 'Dn, 'Dm");
|
||||
} else {
|
||||
Format(instr, "vadd.f64'cond 'Dd, 'Dn, 'Dm");
|
||||
@ -1093,14 +1095,14 @@ void Decoder::DecodeTypeVFP(Instr* instr) {
|
||||
} else {
|
||||
Unknown(instr); // Not used by V8.
|
||||
}
|
||||
} else if ((instr->Opc1Field() == 0x2) && !(instr->Opc3Field() & 0x1)) {
|
||||
if (instr->SzField() == 0x1) {
|
||||
} else if ((instr->Opc1Value() == 0x2) && !(instr->Opc3Value() & 0x1)) {
|
||||
if (instr->SzValue() == 0x1) {
|
||||
Format(instr, "vmul.f64'cond 'Dd, 'Dn, 'Dm");
|
||||
} else {
|
||||
Unknown(instr); // Not used by V8.
|
||||
}
|
||||
} else if ((instr->Opc1Field() == 0x4) && !(instr->Opc3Field() & 0x1)) {
|
||||
if (instr->SzField() == 0x1) {
|
||||
} else if ((instr->Opc1Value() == 0x4) && !(instr->Opc3Value() & 0x1)) {
|
||||
if (instr->SzValue() == 0x1) {
|
||||
Format(instr, "vdiv.f64'cond 'Dd, 'Dn, 'Dm");
|
||||
} else {
|
||||
Unknown(instr); // Not used by V8.
|
||||
@ -1109,13 +1111,13 @@ void Decoder::DecodeTypeVFP(Instr* instr) {
|
||||
Unknown(instr); // Not used by V8.
|
||||
}
|
||||
} else {
|
||||
if ((instr->VCField() == 0x0) &&
|
||||
(instr->VAField() == 0x0)) {
|
||||
if ((instr->VCValue() == 0x0) &&
|
||||
(instr->VAValue() == 0x0)) {
|
||||
DecodeVMOVBetweenCoreAndSinglePrecisionRegisters(instr);
|
||||
} else if ((instr->VCField() == 0x0) &&
|
||||
(instr->VAField() == 0x7) &&
|
||||
} else if ((instr->VCValue() == 0x0) &&
|
||||
(instr->VAValue() == 0x7) &&
|
||||
(instr->Bits(19, 16) == 0x1)) {
|
||||
if (instr->VLField() == 0) {
|
||||
if (instr->VLValue() == 0) {
|
||||
if (instr->Bits(15, 12) == 0xF) {
|
||||
Format(instr, "vmsr'cond FPSCR, APSR");
|
||||
} else {
|
||||
@ -1133,11 +1135,12 @@ void Decoder::DecodeTypeVFP(Instr* instr) {
|
||||
}
|
||||
|
||||
|
||||
void Decoder::DecodeVMOVBetweenCoreAndSinglePrecisionRegisters(Instr* instr) {
|
||||
ASSERT((instr->Bit(4) == 1) && (instr->VCField() == 0x0) &&
|
||||
(instr->VAField() == 0x0));
|
||||
void Decoder::DecodeVMOVBetweenCoreAndSinglePrecisionRegisters(
|
||||
Instruction* instr) {
|
||||
ASSERT((instr->Bit(4) == 1) && (instr->VCValue() == 0x0) &&
|
||||
(instr->VAValue() == 0x0));
|
||||
|
||||
bool to_arm_register = (instr->VLField() == 0x1);
|
||||
bool to_arm_register = (instr->VLValue() == 0x1);
|
||||
|
||||
if (to_arm_register) {
|
||||
Format(instr, "vmov'cond 'rt, 'Sn");
|
||||
@ -1147,19 +1150,19 @@ void Decoder::DecodeVMOVBetweenCoreAndSinglePrecisionRegisters(Instr* instr) {
|
||||
}
|
||||
|
||||
|
||||
void Decoder::DecodeVCMP(Instr* instr) {
|
||||
ASSERT((instr->Bit(4) == 0) && (instr->Opc1Field() == 0x7));
|
||||
ASSERT(((instr->Opc2Field() == 0x4) || (instr->Opc2Field() == 0x5)) &&
|
||||
(instr->Opc3Field() & 0x1));
|
||||
void Decoder::DecodeVCMP(Instruction* instr) {
|
||||
ASSERT((instr->Bit(4) == 0) && (instr->Opc1Value() == 0x7));
|
||||
ASSERT(((instr->Opc2Value() == 0x4) || (instr->Opc2Value() == 0x5)) &&
|
||||
(instr->Opc3Value() & 0x1));
|
||||
|
||||
// Comparison.
|
||||
bool dp_operation = (instr->SzField() == 1);
|
||||
bool dp_operation = (instr->SzValue() == 1);
|
||||
bool raise_exception_for_qnan = (instr->Bit(7) == 0x1);
|
||||
|
||||
if (dp_operation && !raise_exception_for_qnan) {
|
||||
if (instr->Opc2Field() == 0x4) {
|
||||
if (instr->Opc2Value() == 0x4) {
|
||||
Format(instr, "vcmp.f64'cond 'Dd, 'Dm");
|
||||
} else if (instr->Opc2Field() == 0x5) {
|
||||
} else if (instr->Opc2Value() == 0x5) {
|
||||
Format(instr, "vcmp.f64'cond 'Dd, #0.0");
|
||||
} else {
|
||||
Unknown(instr); // invalid
|
||||
@ -1170,11 +1173,11 @@ void Decoder::DecodeVCMP(Instr* instr) {
|
||||
}
|
||||
|
||||
|
||||
void Decoder::DecodeVCVTBetweenDoubleAndSingle(Instr* instr) {
|
||||
ASSERT((instr->Bit(4) == 0) && (instr->Opc1Field() == 0x7));
|
||||
ASSERT((instr->Opc2Field() == 0x7) && (instr->Opc3Field() == 0x3));
|
||||
void Decoder::DecodeVCVTBetweenDoubleAndSingle(Instruction* instr) {
|
||||
ASSERT((instr->Bit(4) == 0) && (instr->Opc1Value() == 0x7));
|
||||
ASSERT((instr->Opc2Value() == 0x7) && (instr->Opc3Value() == 0x3));
|
||||
|
||||
bool double_to_single = (instr->SzField() == 1);
|
||||
bool double_to_single = (instr->SzValue() == 1);
|
||||
|
||||
if (double_to_single) {
|
||||
Format(instr, "vcvt.f32.f64'cond 'Sd, 'Dm");
|
||||
@ -1184,13 +1187,13 @@ void Decoder::DecodeVCVTBetweenDoubleAndSingle(Instr* instr) {
|
||||
}
|
||||
|
||||
|
||||
void Decoder::DecodeVCVTBetweenFloatingPointAndInteger(Instr* instr) {
|
||||
ASSERT((instr->Bit(4) == 0) && (instr->Opc1Field() == 0x7));
|
||||
ASSERT(((instr->Opc2Field() == 0x8) && (instr->Opc3Field() & 0x1)) ||
|
||||
(((instr->Opc2Field() >> 1) == 0x6) && (instr->Opc3Field() & 0x1)));
|
||||
void Decoder::DecodeVCVTBetweenFloatingPointAndInteger(Instruction* instr) {
|
||||
ASSERT((instr->Bit(4) == 0) && (instr->Opc1Value() == 0x7));
|
||||
ASSERT(((instr->Opc2Value() == 0x8) && (instr->Opc3Value() & 0x1)) ||
|
||||
(((instr->Opc2Value() >> 1) == 0x6) && (instr->Opc3Value() & 0x1)));
|
||||
|
||||
bool to_integer = (instr->Bit(18) == 1);
|
||||
bool dp_operation = (instr->SzField() == 1);
|
||||
bool dp_operation = (instr->SzValue() == 1);
|
||||
if (to_integer) {
|
||||
bool unsigned_integer = (instr->Bit(16) == 0);
|
||||
|
||||
@ -1232,11 +1235,11 @@ void Decoder::DecodeVCVTBetweenFloatingPointAndInteger(Instr* instr) {
|
||||
// <Rt, Rt2> = vmov(Dm)
|
||||
// Ddst = MEM(Rbase + 4*offset).
|
||||
// MEM(Rbase + 4*offset) = Dsrc.
|
||||
void Decoder::DecodeType6CoprocessorIns(Instr* instr) {
|
||||
ASSERT((instr->TypeField() == 6));
|
||||
void Decoder::DecodeType6CoprocessorIns(Instruction* instr) {
|
||||
ASSERT(instr->TypeValue() == 6);
|
||||
|
||||
if (instr->CoprocessorField() == 0xA) {
|
||||
switch (instr->OpcodeField()) {
|
||||
if (instr->CoprocessorValue() == 0xA) {
|
||||
switch (instr->OpcodeValue()) {
|
||||
case 0x8:
|
||||
case 0xA:
|
||||
if (instr->HasL()) {
|
||||
@ -1257,8 +1260,8 @@ void Decoder::DecodeType6CoprocessorIns(Instr* instr) {
|
||||
Unknown(instr); // Not used by V8.
|
||||
break;
|
||||
}
|
||||
} else if (instr->CoprocessorField() == 0xB) {
|
||||
switch (instr->OpcodeField()) {
|
||||
} else if (instr->CoprocessorValue() == 0xB) {
|
||||
switch (instr->OpcodeValue()) {
|
||||
case 0x2:
|
||||
// Load and store double to two GP registers
|
||||
if (instr->Bits(7, 4) != 0x1) {
|
||||
@ -1295,16 +1298,16 @@ void Decoder::DecodeType6CoprocessorIns(Instr* instr) {
|
||||
|
||||
// Disassemble the instruction at *instr_ptr into the output buffer.
|
||||
int Decoder::InstructionDecode(byte* instr_ptr) {
|
||||
Instr* instr = Instr::At(instr_ptr);
|
||||
Instruction* instr = Instruction::At(instr_ptr);
|
||||
// Print raw instruction bytes.
|
||||
out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_,
|
||||
"%08x ",
|
||||
instr->InstructionBits());
|
||||
if (instr->ConditionField() == special_condition) {
|
||||
out_buffer_pos_ += OS::SNPrintF(out_buffer_ + out_buffer_pos_,
|
||||
"%08x ",
|
||||
instr->InstructionBits());
|
||||
if (instr->ConditionField() == kSpecialCondition) {
|
||||
UNIMPLEMENTED();
|
||||
return Instr::kInstrSize;
|
||||
return Instruction::kInstrSize;
|
||||
}
|
||||
switch (instr->TypeField()) {
|
||||
switch (instr->TypeValue()) {
|
||||
case 0:
|
||||
case 1: {
|
||||
DecodeType01(instr);
|
||||
@ -1339,11 +1342,11 @@ int Decoder::InstructionDecode(byte* instr_ptr) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return Instr::kInstrSize;
|
||||
return Instruction::kInstrSize;
|
||||
}
|
||||
|
||||
|
||||
} } // namespace assembler::arm
|
||||
} } // namespace v8::internal
|
||||
|
||||
|
||||
|
||||
@ -1351,8 +1354,6 @@ int Decoder::InstructionDecode(byte* instr_ptr) {
|
||||
|
||||
namespace disasm {
|
||||
|
||||
namespace v8i = v8::internal;
|
||||
|
||||
|
||||
const char* NameConverter::NameOfAddress(byte* addr) const {
|
||||
static v8::internal::EmbeddedVector<char, 32> tmp_buffer;
|
||||
@ -1367,7 +1368,7 @@ const char* NameConverter::NameOfConstant(byte* addr) const {
|
||||
|
||||
|
||||
const char* NameConverter::NameOfCPURegister(int reg) const {
|
||||
return assembler::arm::Registers::Name(reg);
|
||||
return v8::internal::Registers::Name(reg);
|
||||
}
|
||||
|
||||
|
||||
@ -1401,7 +1402,7 @@ Disassembler::~Disassembler() {}
|
||||
|
||||
int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
|
||||
byte* instruction) {
|
||||
assembler::arm::Decoder d(converter_, buffer);
|
||||
v8::internal::Decoder d(converter_, buffer);
|
||||
return d.InstructionDecode(instruction);
|
||||
}
|
||||
|
||||
|
@ -517,16 +517,16 @@ void FullCodeGenerator::DoTest(Label* if_true,
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::Split(Condition cc,
|
||||
void FullCodeGenerator::Split(Condition cond,
|
||||
Label* if_true,
|
||||
Label* if_false,
|
||||
Label* fall_through) {
|
||||
if (if_false == fall_through) {
|
||||
__ b(cc, if_true);
|
||||
__ b(cond, if_true);
|
||||
} else if (if_true == fall_through) {
|
||||
__ b(NegateCondition(cc), if_false);
|
||||
__ b(NegateCondition(cond), if_false);
|
||||
} else {
|
||||
__ b(cc, if_true);
|
||||
__ b(cond, if_true);
|
||||
__ b(if_false);
|
||||
}
|
||||
}
|
||||
@ -3461,34 +3461,34 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
|
||||
|
||||
default: {
|
||||
VisitForAccumulatorValue(expr->right());
|
||||
Condition cc = eq;
|
||||
Condition cond = eq;
|
||||
bool strict = false;
|
||||
switch (op) {
|
||||
case Token::EQ_STRICT:
|
||||
strict = true;
|
||||
// Fall through
|
||||
case Token::EQ:
|
||||
cc = eq;
|
||||
cond = eq;
|
||||
__ pop(r1);
|
||||
break;
|
||||
case Token::LT:
|
||||
cc = lt;
|
||||
cond = lt;
|
||||
__ pop(r1);
|
||||
break;
|
||||
case Token::GT:
|
||||
// Reverse left and right sides to obtain ECMA-262 conversion order.
|
||||
cc = lt;
|
||||
cond = lt;
|
||||
__ mov(r1, result_register());
|
||||
__ pop(r0);
|
||||
break;
|
||||
case Token::LTE:
|
||||
// Reverse left and right sides to obtain ECMA-262 conversion order.
|
||||
cc = ge;
|
||||
cond = ge;
|
||||
__ mov(r1, result_register());
|
||||
__ pop(r0);
|
||||
break;
|
||||
case Token::GTE:
|
||||
cc = ge;
|
||||
cond = ge;
|
||||
__ pop(r1);
|
||||
break;
|
||||
case Token::IN:
|
||||
@ -3503,17 +3503,17 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
|
||||
__ orr(r2, r0, Operand(r1));
|
||||
__ JumpIfNotSmi(r2, &slow_case);
|
||||
__ cmp(r1, r0);
|
||||
Split(cc, if_true, if_false, NULL);
|
||||
Split(cond, if_true, if_false, NULL);
|
||||
__ bind(&slow_case);
|
||||
}
|
||||
CompareFlags flags = inline_smi_code
|
||||
? NO_SMI_COMPARE_IN_STUB
|
||||
: NO_COMPARE_FLAGS;
|
||||
CompareStub stub(cc, strict, flags, r1, r0);
|
||||
CompareStub stub(cond, strict, flags, r1, r0);
|
||||
__ CallStub(&stub);
|
||||
PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
|
||||
__ cmp(r0, Operand(0, RelocInfo::NONE));
|
||||
Split(cc, if_true, if_false, fall_through);
|
||||
Split(cond, if_true, if_false, fall_through);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -95,13 +95,13 @@ static void GenerateStringDictionaryReceiverCheck(MacroAssembler* masm,
|
||||
__ ldrb(t1, FieldMemOperand(t0, Map::kBitFieldOffset));
|
||||
__ tst(t1, Operand((1 << Map::kIsAccessCheckNeeded) |
|
||||
(1 << Map::kHasNamedInterceptor)));
|
||||
__ b(nz, miss);
|
||||
__ b(ne, miss);
|
||||
|
||||
__ ldr(elements, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
|
||||
__ ldr(t1, FieldMemOperand(elements, HeapObject::kMapOffset));
|
||||
__ LoadRoot(ip, Heap::kHashTableMapRootIndex);
|
||||
__ cmp(t1, ip);
|
||||
__ b(nz, miss);
|
||||
__ b(ne, miss);
|
||||
}
|
||||
|
||||
|
||||
@ -427,7 +427,7 @@ static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm,
|
||||
__ ldrb(scratch, FieldMemOperand(map, Map::kBitFieldOffset));
|
||||
__ tst(scratch,
|
||||
Operand((1 << Map::kIsAccessCheckNeeded) | (1 << interceptor_bit)));
|
||||
__ b(nz, slow);
|
||||
__ b(ne, slow);
|
||||
// Check that the object is some kind of JS object EXCEPT JS Value type.
|
||||
// In the case that the object is a value-wrapper object,
|
||||
// we enter the runtime system to make sure that indexing into string
|
||||
@ -1674,7 +1674,7 @@ Condition CompareIC::ComputeCondition(Token::Value op) {
|
||||
return ge;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return no_condition;
|
||||
return kNoCondition;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -76,7 +76,7 @@ void JumpTarget::DoJump() {
|
||||
}
|
||||
|
||||
|
||||
void JumpTarget::DoBranch(Condition cc, Hint ignored) {
|
||||
void JumpTarget::DoBranch(Condition cond, Hint ignored) {
|
||||
ASSERT(cgen()->has_valid_frame());
|
||||
|
||||
if (entry_frame_set_) {
|
||||
@ -86,7 +86,7 @@ void JumpTarget::DoBranch(Condition cc, Hint ignored) {
|
||||
ASSERT(entry_frame_.IsCompatibleWith(cgen()->frame()));
|
||||
}
|
||||
// We have an expected frame to merge to on the backward edge.
|
||||
cgen()->frame()->MergeTo(&entry_frame_, cc);
|
||||
cgen()->frame()->MergeTo(&entry_frame_, cond);
|
||||
} else {
|
||||
// Clone the current frame to use as the expected one at the target.
|
||||
set_entry_frame(cgen()->frame());
|
||||
@ -98,8 +98,8 @@ void JumpTarget::DoBranch(Condition cc, Hint ignored) {
|
||||
// frame with less precise type info branches to them.
|
||||
ASSERT(direction_ != FORWARD_ONLY);
|
||||
}
|
||||
__ b(cc, &entry_label_);
|
||||
if (cc == al) {
|
||||
__ b(cond, &entry_label_);
|
||||
if (cond == al) {
|
||||
cgen()->DeleteFrame();
|
||||
}
|
||||
}
|
||||
|
@ -661,7 +661,7 @@ void LCodeGen::DeoptimizeIf(Condition cc, LEnvironment* environment) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (cc == no_condition) {
|
||||
if (cc == kNoCondition) {
|
||||
if (FLAG_trap_on_deopt) __ stop("trap_on_deopt");
|
||||
__ Jump(entry, RelocInfo::RUNTIME_ENTRY);
|
||||
} else {
|
||||
@ -1216,7 +1216,7 @@ void LCodeGen::DoMulI(LMulI* instr) {
|
||||
__ b(ne, &done);
|
||||
if (instr->InputAt(1)->IsConstantOperand()) {
|
||||
if (ToInteger32(LConstantOperand::cast(instr->InputAt(1))) < 0) {
|
||||
DeoptimizeIf(no_condition, instr->environment());
|
||||
DeoptimizeIf(kNoCondition, instr->environment());
|
||||
}
|
||||
} else {
|
||||
// Test the non-zero operand for negative sign.
|
||||
@ -1483,7 +1483,7 @@ void LCodeGen::DoBranch(LBranch* instr) {
|
||||
if (r.IsInteger32()) {
|
||||
Register reg = ToRegister(instr->InputAt(0));
|
||||
__ cmp(reg, Operand(0));
|
||||
EmitBranch(true_block, false_block, nz);
|
||||
EmitBranch(true_block, false_block, ne);
|
||||
} else if (r.IsDouble()) {
|
||||
DoubleRegister reg = ToDoubleRegister(instr->InputAt(0));
|
||||
Register scratch = scratch0();
|
||||
@ -1541,7 +1541,7 @@ void LCodeGen::DoBranch(LBranch* instr) {
|
||||
__ CallStub(&stub);
|
||||
__ cmp(reg, Operand(0));
|
||||
__ ldm(ia_w, sp, saved_regs);
|
||||
EmitBranch(true_block, false_block, nz);
|
||||
EmitBranch(true_block, false_block, ne);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1593,7 +1593,7 @@ void LCodeGen::DoGoto(LGoto* instr) {
|
||||
|
||||
|
||||
Condition LCodeGen::TokenToCondition(Token::Value op, bool is_unsigned) {
|
||||
Condition cond = no_condition;
|
||||
Condition cond = kNoCondition;
|
||||
switch (op) {
|
||||
case Token::EQ:
|
||||
case Token::EQ_STRICT:
|
||||
@ -2136,7 +2136,7 @@ static Condition ComputeCompareCondition(Token::Value op) {
|
||||
return ge;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return no_condition;
|
||||
return kNoCondition;
|
||||
}
|
||||
}
|
||||
|
||||
@ -3556,7 +3556,7 @@ Condition LCodeGen::EmitTypeofIs(Label* true_label,
|
||||
Label* false_label,
|
||||
Register input,
|
||||
Handle<String> type_name) {
|
||||
Condition final_branch_condition = no_condition;
|
||||
Condition final_branch_condition = kNoCondition;
|
||||
Register scratch = scratch0();
|
||||
if (type_name->Equals(Heap::number_symbol())) {
|
||||
__ tst(input, Operand(kSmiTagMask));
|
||||
@ -3641,7 +3641,7 @@ void LCodeGen::DoLazyBailout(LLazyBailout* instr) {
|
||||
|
||||
|
||||
void LCodeGen::DoDeoptimize(LDeoptimize* instr) {
|
||||
DeoptimizeIf(no_condition, instr->environment());
|
||||
DeoptimizeIf(kNoCondition, instr->environment());
|
||||
}
|
||||
|
||||
|
||||
|
@ -318,7 +318,7 @@ void MacroAssembler::SmiJumpTable(Register index, Vector<Label*> targets) {
|
||||
CheckConstPool(true, true);
|
||||
add(pc, pc, Operand(index,
|
||||
LSL,
|
||||
assembler::arm::Instr::kInstrSizeLog2 - kSmiTagSize));
|
||||
Instruction::kInstrSizeLog2 - kSmiTagSize));
|
||||
BlockConstPoolBefore(pc_offset() + (targets.length() + 1) * kInstrSize);
|
||||
nop(); // Jump table alignment.
|
||||
for (int i = 0; i < targets.length(); i++) {
|
||||
@ -369,12 +369,12 @@ void MacroAssembler::RecordWriteHelper(Register object,
|
||||
|
||||
void MacroAssembler::InNewSpace(Register object,
|
||||
Register scratch,
|
||||
Condition cc,
|
||||
Condition cond,
|
||||
Label* branch) {
|
||||
ASSERT(cc == eq || cc == ne);
|
||||
ASSERT(cond == eq || cond == ne);
|
||||
and_(scratch, object, Operand(ExternalReference::new_space_mask()));
|
||||
cmp(scratch, Operand(ExternalReference::new_space_start()));
|
||||
b(cc, branch);
|
||||
b(cond, branch);
|
||||
}
|
||||
|
||||
|
||||
@ -926,7 +926,7 @@ void MacroAssembler::IsObjectJSStringType(Register object,
|
||||
ldr(scratch, FieldMemOperand(object, HeapObject::kMapOffset));
|
||||
ldrb(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset));
|
||||
tst(scratch, Operand(kIsNotStringMask));
|
||||
b(nz, fail);
|
||||
b(ne, fail);
|
||||
}
|
||||
|
||||
|
||||
@ -1806,9 +1806,9 @@ void MacroAssembler::DecrementCounter(StatsCounter* counter, int value,
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::Assert(Condition cc, const char* msg) {
|
||||
void MacroAssembler::Assert(Condition cond, const char* msg) {
|
||||
if (FLAG_debug_code)
|
||||
Check(cc, msg);
|
||||
Check(cond, msg);
|
||||
}
|
||||
|
||||
|
||||
@ -1841,9 +1841,9 @@ void MacroAssembler::AssertFastElements(Register elements) {
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::Check(Condition cc, const char* msg) {
|
||||
void MacroAssembler::Check(Condition cond, const char* msg) {
|
||||
Label L;
|
||||
b(cc, &L);
|
||||
b(cond, &L);
|
||||
Abort(msg);
|
||||
// will not return here
|
||||
bind(&L);
|
||||
|
@ -139,7 +139,7 @@ class MacroAssembler: public Assembler {
|
||||
// scratch can be object itself, but it will be clobbered.
|
||||
void InNewSpace(Register object,
|
||||
Register scratch,
|
||||
Condition cc, // eq for new space, ne otherwise
|
||||
Condition cond, // eq for new space, ne otherwise
|
||||
Label* branch);
|
||||
|
||||
|
||||
@ -685,14 +685,14 @@ class MacroAssembler: public Assembler {
|
||||
// ---------------------------------------------------------------------------
|
||||
// Debugging
|
||||
|
||||
// Calls Abort(msg) if the condition cc is not satisfied.
|
||||
// Calls Abort(msg) if the condition cond is not satisfied.
|
||||
// Use --debug_code to enable.
|
||||
void Assert(Condition cc, const char* msg);
|
||||
void Assert(Condition cond, const char* msg);
|
||||
void AssertRegisterIsRoot(Register reg, Heap::RootListIndex index);
|
||||
void AssertFastElements(Register elements);
|
||||
|
||||
// Like Assert(), but always enabled.
|
||||
void Check(Condition cc, const char* msg);
|
||||
void Check(Condition cond, const char* msg);
|
||||
|
||||
// Print a message to stdout and abort execution.
|
||||
void Abort(const char* msg);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -80,8 +80,8 @@ class SimulatorStack : public v8::internal::AllStatic {
|
||||
#include "constants-arm.h"
|
||||
#include "hashmap.h"
|
||||
|
||||
namespace assembler {
|
||||
namespace arm {
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
class CachePage {
|
||||
public:
|
||||
@ -203,11 +203,11 @@ class Simulator {
|
||||
};
|
||||
|
||||
// Unsupported instructions use Format to print an error and stop execution.
|
||||
void Format(Instr* instr, const char* format);
|
||||
void Format(Instruction* instr, const char* format);
|
||||
|
||||
// Checks if the current instruction should be executed based on its
|
||||
// condition bits.
|
||||
bool ConditionallyExecute(Instr* instr);
|
||||
bool ConditionallyExecute(Instruction* instr);
|
||||
|
||||
// Helper functions to set the conditional flags in the architecture state.
|
||||
void SetNZFlags(int32_t val);
|
||||
@ -225,13 +225,13 @@ class Simulator {
|
||||
void Copy_FPSCR_to_APSR();
|
||||
|
||||
// Helper functions to decode common "addressing" modes
|
||||
int32_t GetShiftRm(Instr* instr, bool* carry_out);
|
||||
int32_t GetImm(Instr* instr, bool* carry_out);
|
||||
void HandleRList(Instr* instr, bool load);
|
||||
void SoftwareInterrupt(Instr* instr);
|
||||
int32_t GetShiftRm(Instruction* instr, bool* carry_out);
|
||||
int32_t GetImm(Instruction* instr, bool* carry_out);
|
||||
void HandleRList(Instruction* instr, bool load);
|
||||
void SoftwareInterrupt(Instruction* instr);
|
||||
|
||||
// Stop helper functions.
|
||||
inline bool isStopInstruction(Instr* instr);
|
||||
inline bool isStopInstruction(Instruction* instr);
|
||||
inline bool isWatchedStop(uint32_t bkpt_code);
|
||||
inline bool isEnabledStop(uint32_t bkpt_code);
|
||||
inline void EnableStop(uint32_t bkpt_code);
|
||||
@ -245,41 +245,42 @@ class Simulator {
|
||||
inline void WriteB(int32_t addr, uint8_t value);
|
||||
inline void WriteB(int32_t addr, int8_t value);
|
||||
|
||||
inline uint16_t ReadHU(int32_t addr, Instr* instr);
|
||||
inline int16_t ReadH(int32_t addr, Instr* instr);
|
||||
inline uint16_t ReadHU(int32_t addr, Instruction* instr);
|
||||
inline int16_t ReadH(int32_t addr, Instruction* instr);
|
||||
// Note: Overloaded on the sign of the value.
|
||||
inline void WriteH(int32_t addr, uint16_t value, Instr* instr);
|
||||
inline void WriteH(int32_t addr, int16_t value, Instr* instr);
|
||||
inline void WriteH(int32_t addr, uint16_t value, Instruction* instr);
|
||||
inline void WriteH(int32_t addr, int16_t value, Instruction* instr);
|
||||
|
||||
inline int ReadW(int32_t addr, Instr* instr);
|
||||
inline void WriteW(int32_t addr, int value, Instr* instr);
|
||||
inline int ReadW(int32_t addr, Instruction* instr);
|
||||
inline void WriteW(int32_t addr, int value, Instruction* instr);
|
||||
|
||||
int32_t* ReadDW(int32_t addr);
|
||||
void WriteDW(int32_t addr, int32_t value1, int32_t value2);
|
||||
|
||||
// Executing is handled based on the instruction type.
|
||||
void DecodeType01(Instr* instr); // both type 0 and type 1 rolled into one
|
||||
void DecodeType2(Instr* instr);
|
||||
void DecodeType3(Instr* instr);
|
||||
void DecodeType4(Instr* instr);
|
||||
void DecodeType5(Instr* instr);
|
||||
void DecodeType6(Instr* instr);
|
||||
void DecodeType7(Instr* instr);
|
||||
// Both type 0 and type 1 rolled into one.
|
||||
void DecodeType01(Instruction* instr);
|
||||
void DecodeType2(Instruction* instr);
|
||||
void DecodeType3(Instruction* instr);
|
||||
void DecodeType4(Instruction* instr);
|
||||
void DecodeType5(Instruction* instr);
|
||||
void DecodeType6(Instruction* instr);
|
||||
void DecodeType7(Instruction* instr);
|
||||
|
||||
// Support for VFP.
|
||||
void DecodeTypeVFP(Instr* instr);
|
||||
void DecodeType6CoprocessorIns(Instr* instr);
|
||||
void DecodeTypeVFP(Instruction* instr);
|
||||
void DecodeType6CoprocessorIns(Instruction* instr);
|
||||
|
||||
void DecodeVMOVBetweenCoreAndSinglePrecisionRegisters(Instr* instr);
|
||||
void DecodeVCMP(Instr* instr);
|
||||
void DecodeVCVTBetweenDoubleAndSingle(Instr* instr);
|
||||
void DecodeVCVTBetweenFloatingPointAndInteger(Instr* instr);
|
||||
void DecodeVMOVBetweenCoreAndSinglePrecisionRegisters(Instruction* instr);
|
||||
void DecodeVCMP(Instruction* instr);
|
||||
void DecodeVCVTBetweenDoubleAndSingle(Instruction* instr);
|
||||
void DecodeVCVTBetweenFloatingPointAndInteger(Instruction* instr);
|
||||
|
||||
// Executes one instruction.
|
||||
void InstructionDecode(Instr* instr);
|
||||
void InstructionDecode(Instruction* instr);
|
||||
|
||||
// ICache.
|
||||
static void CheckICache(Instr* instr);
|
||||
static void CheckICache(Instruction* instr);
|
||||
static void FlushOnePage(intptr_t start, int size);
|
||||
static CachePage* GetCachePage(void* page);
|
||||
|
||||
@ -330,8 +331,8 @@ class Simulator {
|
||||
static v8::internal::HashMap* i_cache_;
|
||||
|
||||
// Registered breakpoints.
|
||||
Instr* break_pc_;
|
||||
instr_t break_instr_;
|
||||
Instruction* break_pc_;
|
||||
Instr break_instr_;
|
||||
|
||||
// A stop is watched if its code is less than kNumOfWatchedStops.
|
||||
// Only watched stops support enabling/disabling and the counter feature.
|
||||
@ -344,27 +345,22 @@ class Simulator {
|
||||
// instruction, if bit 31 of watched_stops[code].count is unset.
|
||||
// The value watched_stops[code].count & ~(1 << 31) indicates how many times
|
||||
// the breakpoint was hit or gone through.
|
||||
struct StopCoundAndDesc {
|
||||
struct StopCountAndDesc {
|
||||
uint32_t count;
|
||||
char* desc;
|
||||
};
|
||||
StopCoundAndDesc watched_stops[kNumOfWatchedStops];
|
||||
StopCountAndDesc watched_stops[kNumOfWatchedStops];
|
||||
};
|
||||
|
||||
} } // namespace assembler::arm
|
||||
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// When running with the simulator transition into simulated execution at this
|
||||
// point.
|
||||
#define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4) \
|
||||
reinterpret_cast<Object*>(assembler::arm::Simulator::current()->Call( \
|
||||
reinterpret_cast<Object*>(Simulator::current()->Call( \
|
||||
FUNCTION_ADDR(entry), 5, p0, p1, p2, p3, p4))
|
||||
|
||||
#define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6) \
|
||||
assembler::arm::Simulator::current()->Call( \
|
||||
Simulator::current()->Call( \
|
||||
FUNCTION_ADDR(entry), 7, p0, p1, p2, p3, p4, p5, p6)
|
||||
|
||||
#define TRY_CATCH_FROM_ADDRESS(try_catch_address) \
|
||||
@ -380,16 +376,16 @@ namespace internal {
|
||||
class SimulatorStack : public v8::internal::AllStatic {
|
||||
public:
|
||||
static inline uintptr_t JsLimitFromCLimit(uintptr_t c_limit) {
|
||||
return assembler::arm::Simulator::current()->StackLimit();
|
||||
return Simulator::current()->StackLimit();
|
||||
}
|
||||
|
||||
static inline uintptr_t RegisterCTryCatch(uintptr_t try_catch_address) {
|
||||
assembler::arm::Simulator* sim = assembler::arm::Simulator::current();
|
||||
Simulator* sim = Simulator::current();
|
||||
return sim->PushAddress(try_catch_address);
|
||||
}
|
||||
|
||||
static inline void UnregisterCTryCatch() {
|
||||
assembler::arm::Simulator::current()->PopAddress();
|
||||
Simulator::current()->PopAddress();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -72,7 +72,7 @@ void ThreadLocalTop::Initialize() {
|
||||
handler_ = 0;
|
||||
#ifdef USE_SIMULATOR
|
||||
#ifdef V8_TARGET_ARCH_ARM
|
||||
simulator_ = assembler::arm::Simulator::current();
|
||||
simulator_ = Simulator::current();
|
||||
#elif V8_TARGET_ARCH_MIPS
|
||||
simulator_ = assembler::mips::Simulator::current();
|
||||
#endif
|
||||
@ -1095,7 +1095,7 @@ char* Top::RestoreThread(char* from) {
|
||||
// thread_local_ is restored on a separate OS thread.
|
||||
#ifdef USE_SIMULATOR
|
||||
#ifdef V8_TARGET_ARCH_ARM
|
||||
thread_local_.simulator_ = assembler::arm::Simulator::current();
|
||||
thread_local_.simulator_ = Simulator::current();
|
||||
#elif V8_TARGET_ARCH_MIPS
|
||||
thread_local_.simulator_ = assembler::mips::Simulator::current();
|
||||
#endif
|
||||
|
@ -109,7 +109,7 @@ class ThreadLocalTop BASE_EMBEDDED {
|
||||
|
||||
#ifdef USE_SIMULATOR
|
||||
#ifdef V8_TARGET_ARCH_ARM
|
||||
assembler::arm::Simulator* simulator_;
|
||||
Simulator* simulator_;
|
||||
#elif V8_TARGET_ARCH_MIPS
|
||||
assembler::mips::Simulator* simulator_;
|
||||
#endif
|
||||
|
@ -79,7 +79,7 @@ bool V8::Initialize(Deserializer* des) {
|
||||
// Initialize other runtime facilities
|
||||
#if defined(USE_SIMULATOR)
|
||||
#if defined(V8_TARGET_ARCH_ARM)
|
||||
::assembler::arm::Simulator::Initialize();
|
||||
Simulator::Initialize();
|
||||
#elif defined(V8_TARGET_ARCH_MIPS)
|
||||
::assembler::mips::Simulator::Initialize();
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user