[Arm] Various cleanups to the Arm assembler backend.
A couple of cleanups to the Arm backend to enable support of extended OOL constant pools in a following CL. - Remove instruction pattern extern const's and replace their use with IsXXX() functions. - Do calculation of the target address of a load from constant pool in one place. - A couple of other small cleanups. R=ulan@chromium.org Review URL: https://codereview.chromium.org/317653003 git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@21932 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
b0d3b668dd
commit
1b080a76c1
@ -119,21 +119,14 @@ Address RelocInfo::target_address_address() {
|
||||
return reinterpret_cast<Address>(pc_);
|
||||
} else {
|
||||
ASSERT(Assembler::IsLdrPcImmediateOffset(Memory::int32_at(pc_)));
|
||||
return Assembler::target_pointer_address_at(pc_);
|
||||
return constant_pool_entry_address();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Address RelocInfo::constant_pool_entry_address() {
|
||||
ASSERT(IsInConstantPool());
|
||||
if (FLAG_enable_ool_constant_pool) {
|
||||
ASSERT(Assembler::IsLdrPpImmediateOffset(Memory::int32_at(pc_)));
|
||||
return Assembler::target_constant_pool_address_at(pc_,
|
||||
host_->constant_pool());
|
||||
} else {
|
||||
ASSERT(Assembler::IsLdrPcImmediateOffset(Memory::int32_at(pc_)));
|
||||
return Assembler::target_pointer_address_at(pc_);
|
||||
}
|
||||
return Assembler::constant_pool_entry_address(pc_, host_->constant_pool());
|
||||
}
|
||||
|
||||
|
||||
@ -314,8 +307,8 @@ bool RelocInfo::IsPatchedReturnSequence() {
|
||||
// A patched return sequence is:
|
||||
// ldr ip, [pc, #0]
|
||||
// blx ip
|
||||
return ((current_instr & kLdrPCMask) == kLdrPCPattern)
|
||||
&& ((next_instr & kBlxRegMask) == kBlxRegPattern);
|
||||
return Assembler::IsLdrPcImmediateOffset(current_instr) &&
|
||||
Assembler::IsBlxReg(next_instr);
|
||||
}
|
||||
|
||||
|
||||
@ -428,42 +421,6 @@ void Assembler::emit(Instr x) {
|
||||
}
|
||||
|
||||
|
||||
Address Assembler::target_pointer_address_at(Address pc) {
|
||||
Instr instr = Memory::int32_at(pc);
|
||||
return pc + GetLdrRegisterImmediateOffset(instr) + kPcLoadDelta;
|
||||
}
|
||||
|
||||
|
||||
Address Assembler::target_constant_pool_address_at(
|
||||
Address pc, ConstantPoolArray* constant_pool) {
|
||||
ASSERT(constant_pool != NULL);
|
||||
ASSERT(IsLdrPpImmediateOffset(Memory::int32_at(pc)));
|
||||
Instr instr = Memory::int32_at(pc);
|
||||
return reinterpret_cast<Address>(constant_pool) +
|
||||
GetLdrRegisterImmediateOffset(instr);
|
||||
}
|
||||
|
||||
|
||||
Address Assembler::target_address_at(Address pc,
|
||||
ConstantPoolArray* constant_pool) {
|
||||
if (IsMovW(Memory::int32_at(pc))) {
|
||||
ASSERT(IsMovT(Memory::int32_at(pc + kInstrSize)));
|
||||
Instruction* instr = Instruction::At(pc);
|
||||
Instruction* next_instr = Instruction::At(pc + kInstrSize);
|
||||
return reinterpret_cast<Address>(
|
||||
(next_instr->ImmedMovwMovtValue() << 16) |
|
||||
instr->ImmedMovwMovtValue());
|
||||
} else if (FLAG_enable_ool_constant_pool) {
|
||||
ASSERT(IsLdrPpImmediateOffset(Memory::int32_at(pc)));
|
||||
return Memory::Address_at(
|
||||
target_constant_pool_address_at(pc, constant_pool));
|
||||
} else {
|
||||
ASSERT(IsLdrPcImmediateOffset(Memory::int32_at(pc)));
|
||||
return Memory::Address_at(target_pointer_address_at(pc));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Address Assembler::target_address_from_return_address(Address pc) {
|
||||
// Returns the address of the call target from the return address that will
|
||||
// be returned to after a call.
|
||||
@ -523,11 +480,63 @@ static Instr PatchMovwImmediate(Instr instruction, uint32_t immediate) {
|
||||
}
|
||||
|
||||
|
||||
static bool IsConstantPoolLoad(Address pc) {
|
||||
return !Assembler::IsMovW(Memory::int32_at(pc));
|
||||
}
|
||||
|
||||
|
||||
Address Assembler::constant_pool_entry_address(
|
||||
Address pc, ConstantPoolArray* constant_pool) {
|
||||
if (FLAG_enable_ool_constant_pool) {
|
||||
ASSERT(constant_pool != NULL);
|
||||
ASSERT(Assembler::IsLdrPpImmediateOffset(Memory::int32_at(pc)));
|
||||
return reinterpret_cast<Address>(constant_pool) +
|
||||
GetLdrRegisterImmediateOffset(Memory::int32_at(pc));
|
||||
} else {
|
||||
ASSERT(Assembler::IsLdrPcImmediateOffset(Memory::int32_at(pc)));
|
||||
Instr instr = Memory::int32_at(pc);
|
||||
return pc + GetLdrRegisterImmediateOffset(instr) + kPcLoadDelta;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Address Assembler::target_address_at(Address pc,
|
||||
ConstantPoolArray* constant_pool) {
|
||||
if (IsConstantPoolLoad(pc)) {
|
||||
// This is a constant pool lookup. Return the value in the constant pool.
|
||||
return Memory::Address_at(constant_pool_entry_address(pc, constant_pool));
|
||||
} else {
|
||||
// This is an movw_movt immediate load. Return the immediate.
|
||||
ASSERT(IsMovW(Memory::int32_at(pc)) &&
|
||||
IsMovT(Memory::int32_at(pc + kInstrSize)));
|
||||
Instruction* movw_instr = Instruction::At(pc);
|
||||
Instruction* movt_instr = Instruction::At(pc + kInstrSize);
|
||||
return reinterpret_cast<Address>(
|
||||
(movt_instr->ImmedMovwMovtValue() << 16) |
|
||||
movw_instr->ImmedMovwMovtValue());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Assembler::set_target_address_at(Address pc,
|
||||
ConstantPoolArray* constant_pool,
|
||||
Address target,
|
||||
ICacheFlushMode icache_flush_mode) {
|
||||
if (IsMovW(Memory::int32_at(pc))) {
|
||||
if (IsConstantPoolLoad(pc)) {
|
||||
// This is a constant pool lookup. Update the entry in the constant pool.
|
||||
Memory::Address_at(constant_pool_entry_address(pc, constant_pool)) = target;
|
||||
// Intuitively, we would think it is necessary to always flush the
|
||||
// instruction cache after patching a target address in the code as follows:
|
||||
// CPU::FlushICache(pc, sizeof(target));
|
||||
// However, on ARM, no instruction is actually patched in the case
|
||||
// of embedded constants of the form:
|
||||
// ldr ip, [pp, #...]
|
||||
// since the instruction accessing this address in the constant pool remains
|
||||
// unchanged.
|
||||
} else {
|
||||
// This is an movw_movt immediate load. Patch the immediate embedded in the
|
||||
// instructions.
|
||||
ASSERT(IsMovW(Memory::int32_at(pc)));
|
||||
ASSERT(IsMovT(Memory::int32_at(pc + kInstrSize)));
|
||||
uint32_t* instr_ptr = reinterpret_cast<uint32_t*>(pc);
|
||||
uint32_t immediate = reinterpret_cast<uint32_t>(target);
|
||||
@ -538,21 +547,6 @@ void Assembler::set_target_address_at(Address pc,
|
||||
if (icache_flush_mode != SKIP_ICACHE_FLUSH) {
|
||||
CPU::FlushICache(pc, 2 * kInstrSize);
|
||||
}
|
||||
} else if (FLAG_enable_ool_constant_pool) {
|
||||
ASSERT(IsLdrPpImmediateOffset(Memory::int32_at(pc)));
|
||||
Memory::Address_at(
|
||||
target_constant_pool_address_at(pc, constant_pool)) = target;
|
||||
} else {
|
||||
ASSERT(IsLdrPcImmediateOffset(Memory::int32_at(pc)));
|
||||
Memory::Address_at(target_pointer_address_at(pc)) = target;
|
||||
// Intuitively, we would think it is necessary to always flush the
|
||||
// instruction cache after patching a target address in the code as follows:
|
||||
// CPU::FlushICache(pc, sizeof(target));
|
||||
// However, on ARM, no instruction is actually patched in the case
|
||||
// of embedded constants of the form:
|
||||
// ldr ip, [pc, #...]
|
||||
// since the instruction accessing this address in the constant pool remains
|
||||
// unchanged.
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -418,11 +418,11 @@ const Instr kPopRegPattern =
|
||||
// mov lr, pc
|
||||
const Instr kMovLrPc = al | MOV | kRegister_pc_Code | kRegister_lr_Code * B12;
|
||||
// ldr rd, [pc, #offset]
|
||||
const Instr kLdrPCMask = 15 * B24 | 7 * B20 | 15 * B16;
|
||||
const Instr kLdrPCPattern = 5 * B24 | L | kRegister_pc_Code * B16;
|
||||
const Instr kLdrPCImmedMask = 15 * B24 | 7 * B20 | 15 * B16;
|
||||
const Instr kLdrPCImmedPattern = 5 * B24 | L | kRegister_pc_Code * B16;
|
||||
// ldr rd, [pp, #offset]
|
||||
const Instr kLdrPpMask = 15 * B24 | 7 * B20 | 15 * B16;
|
||||
const Instr kLdrPpPattern = 5 * B24 | L | kRegister_r8_Code * B16;
|
||||
const Instr kLdrPpImmedMask = 15 * B24 | 7 * B20 | 15 * B16;
|
||||
const Instr kLdrPpImmedPattern = 5 * B24 | L | kRegister_r8_Code * B16;
|
||||
// vldr dd, [pc, #offset]
|
||||
const Instr kVldrDPCMask = 15 * B24 | 3 * B20 | 15 * B16 | 15 * B8;
|
||||
const Instr kVldrDPCPattern = 13 * B24 | L | kRegister_pc_Code * B16 | 11 * B8;
|
||||
@ -640,6 +640,15 @@ Register Assembler::GetRm(Instr instr) {
|
||||
}
|
||||
|
||||
|
||||
Instr Assembler::GetConsantPoolLoadPattern() {
|
||||
if (FLAG_enable_ool_constant_pool) {
|
||||
return kLdrPpImmedPattern;
|
||||
} else {
|
||||
return kLdrPCImmedPattern;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool Assembler::IsPush(Instr instr) {
|
||||
return ((instr & ~kRdMask) == kPushRegPattern);
|
||||
}
|
||||
@ -673,14 +682,14 @@ bool Assembler::IsLdrRegFpNegOffset(Instr instr) {
|
||||
bool Assembler::IsLdrPcImmediateOffset(Instr instr) {
|
||||
// Check the instruction is indeed a
|
||||
// ldr<cond> <Rd>, [pc +/- offset_12].
|
||||
return (instr & kLdrPCMask) == kLdrPCPattern;
|
||||
return (instr & kLdrPCImmedMask) == kLdrPCImmedPattern;
|
||||
}
|
||||
|
||||
|
||||
bool Assembler::IsLdrPpImmediateOffset(Instr instr) {
|
||||
// Check the instruction is indeed a
|
||||
// ldr<cond> <Rd>, [pp +/- offset_12].
|
||||
return (instr & kLdrPpMask) == kLdrPpPattern;
|
||||
return (instr & kLdrPpImmedMask) == kLdrPpImmedPattern;
|
||||
}
|
||||
|
||||
|
||||
@ -698,6 +707,20 @@ bool Assembler::IsVldrDPpImmediateOffset(Instr instr) {
|
||||
}
|
||||
|
||||
|
||||
bool Assembler::IsBlxReg(Instr instr) {
|
||||
// Check the instruction is indeed a
|
||||
// blxcc <Rm>
|
||||
return (instr & kBlxRegMask) == kBlxRegPattern;
|
||||
}
|
||||
|
||||
|
||||
bool Assembler::IsBlxIp(Instr instr) {
|
||||
// Check the instruction is indeed a
|
||||
// blx ip
|
||||
return instr == kBlxIp;
|
||||
}
|
||||
|
||||
|
||||
bool Assembler::IsTstImmediate(Instr instr) {
|
||||
return (instr & (B27 | B26 | I | kOpCodeMask | S | kRdMask)) ==
|
||||
(I | TST | S);
|
||||
|
@ -672,32 +672,6 @@ class ConstantPoolBuilder BASE_EMBEDDED {
|
||||
int count_of_32bit_;
|
||||
};
|
||||
|
||||
|
||||
extern const Instr kMovLrPc;
|
||||
extern const Instr kLdrPCMask;
|
||||
extern const Instr kLdrPCPattern;
|
||||
extern const Instr kLdrPpMask;
|
||||
extern const Instr kLdrPpPattern;
|
||||
extern const Instr kBlxRegMask;
|
||||
extern const Instr kBlxRegPattern;
|
||||
extern const Instr kBlxIp;
|
||||
|
||||
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;
|
||||
|
||||
struct VmovIndex {
|
||||
unsigned char index;
|
||||
};
|
||||
@ -751,11 +725,7 @@ class Assembler : public AssemblerBase {
|
||||
|
||||
// Return the address in the constant pool of the code target address used by
|
||||
// the branch/call instruction at pc, or the object in a mov.
|
||||
INLINE(static Address target_pointer_address_at(Address pc));
|
||||
|
||||
// Return the address in the constant pool of the code target address used by
|
||||
// the branch/call instruction at pc, or the object in a mov.
|
||||
INLINE(static Address target_constant_pool_address_at(
|
||||
INLINE(static Address constant_pool_entry_address(
|
||||
Address pc, ConstantPoolArray* constant_pool));
|
||||
|
||||
// Read/Modify the code target address in the branch/call instruction at pc.
|
||||
@ -1390,6 +1360,7 @@ class Assembler : public AssemblerBase {
|
||||
static int GetBranchOffset(Instr instr);
|
||||
static bool IsLdrRegisterImmediate(Instr instr);
|
||||
static bool IsVldrDRegisterImmediate(Instr instr);
|
||||
static Instr GetConsantPoolLoadPattern();
|
||||
static bool IsLdrPpImmediateOffset(Instr instr);
|
||||
static bool IsVldrDPpImmediateOffset(Instr instr);
|
||||
static int GetLdrRegisterImmediateOffset(Instr instr);
|
||||
@ -1411,6 +1382,8 @@ class Assembler : public AssemblerBase {
|
||||
static bool IsLdrRegFpNegOffset(Instr instr);
|
||||
static bool IsLdrPcImmediateOffset(Instr instr);
|
||||
static bool IsVldrDPcImmediateOffset(Instr instr);
|
||||
static bool IsBlxReg(Instr instr);
|
||||
static bool IsBlxIp(Instr instr);
|
||||
static bool IsTstImmediate(Instr instr);
|
||||
static bool IsCmpRegister(Instr instr);
|
||||
static bool IsCmpImmediate(Instr instr);
|
||||
|
@ -405,64 +405,6 @@ enum Hint { no_hint };
|
||||
inline Hint NegateHint(Hint ignored) { return no_hint; }
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// 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;
|
||||
// vldr dd, [pc, #offset]
|
||||
extern const Instr kVldrDPCMask;
|
||||
extern const Instr kVldrDPCPattern;
|
||||
// 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.
|
||||
|
||||
|
@ -4753,9 +4753,8 @@ void BackEdgeTable::PatchAt(Code* unoptimized_code,
|
||||
Address pc,
|
||||
BackEdgeState target_state,
|
||||
Code* replacement_code) {
|
||||
static const int kInstrSize = Assembler::kInstrSize;
|
||||
Address pc_immediate_load_address = GetInterruptImmediateLoadAddress(pc);
|
||||
Address branch_address = pc_immediate_load_address - kInstrSize;
|
||||
Address branch_address = pc_immediate_load_address - Assembler::kInstrSize;
|
||||
CodePatcher patcher(branch_address, 1);
|
||||
switch (target_state) {
|
||||
case INTERRUPT:
|
||||
@ -4770,7 +4769,7 @@ void BackEdgeTable::PatchAt(Code* unoptimized_code,
|
||||
|
||||
// Calculate branch offet to the ok-label - this is the difference between
|
||||
// the branch address and |pc| (which points at <blx ip>) plus one instr.
|
||||
int branch_offset = pc + kInstrSize - branch_address;
|
||||
int branch_offset = pc + Assembler::kInstrSize - branch_address;
|
||||
patcher.masm()->b(branch_offset, pl);
|
||||
break;
|
||||
}
|
||||
@ -4800,11 +4799,10 @@ BackEdgeTable::BackEdgeState BackEdgeTable::GetBackEdgeState(
|
||||
Isolate* isolate,
|
||||
Code* unoptimized_code,
|
||||
Address pc) {
|
||||
static const int kInstrSize = Assembler::kInstrSize;
|
||||
ASSERT(Memory::int32_at(pc - kInstrSize) == kBlxIp);
|
||||
ASSERT(Assembler::IsBlxIp(Memory::int32_at(pc - Assembler::kInstrSize)));
|
||||
|
||||
Address pc_immediate_load_address = GetInterruptImmediateLoadAddress(pc);
|
||||
Address branch_address = pc_immediate_load_address - kInstrSize;
|
||||
Address branch_address = pc_immediate_load_address - Assembler::kInstrSize;
|
||||
Address interrupt_address = Assembler::target_address_at(
|
||||
pc_immediate_load_address, unoptimized_code);
|
||||
|
||||
|
@ -3630,15 +3630,9 @@ void MacroAssembler::GetRelocatedValueLocation(Register ldr_location,
|
||||
ldr(result, MemOperand(ldr_location));
|
||||
if (emit_debug_code()) {
|
||||
// Check that the instruction is a ldr reg, [<pc or pp> + offset] .
|
||||
if (FLAG_enable_ool_constant_pool) {
|
||||
and_(result, result, Operand(kLdrPpPattern));
|
||||
cmp(result, Operand(kLdrPpPattern));
|
||||
Check(eq, kTheInstructionToPatchShouldBeALoadFromPp);
|
||||
} else {
|
||||
and_(result, result, Operand(kLdrPCPattern));
|
||||
cmp(result, Operand(kLdrPCPattern));
|
||||
Check(eq, kTheInstructionToPatchShouldBeALoadFromPc);
|
||||
}
|
||||
and_(result, result, Operand(GetConsantPoolLoadPattern()));
|
||||
cmp(result, Operand(GetConsantPoolLoadPattern()));
|
||||
Check(eq, kTheInstructionToPatchShouldBeALoadFromConstantPool);
|
||||
// Result was clobbered. Restore it.
|
||||
ldr(result, MemOperand(ldr_location));
|
||||
}
|
||||
|
@ -1236,10 +1236,8 @@ template <class C> inline bool Is(Object* obj);
|
||||
"The current stack pointer is below csp") \
|
||||
V(kTheInstructionShouldBeALui, "The instruction should be a lui") \
|
||||
V(kTheInstructionShouldBeAnOri, "The instruction should be an ori") \
|
||||
V(kTheInstructionToPatchShouldBeALoadFromPc, \
|
||||
"The instruction to patch should be a load from pc") \
|
||||
V(kTheInstructionToPatchShouldBeALoadFromPp, \
|
||||
"The instruction to patch should be a load from pp") \
|
||||
V(kTheInstructionToPatchShouldBeALoadFromConstantPool, \
|
||||
"The instruction to patch should be a load from the constant pool") \
|
||||
V(kTheInstructionToPatchShouldBeAnLdrLiteral, \
|
||||
"The instruction to patch should be a ldr literal") \
|
||||
V(kTheInstructionToPatchShouldBeALui, \
|
||||
|
Loading…
Reference in New Issue
Block a user