| Index: src/mips/assembler-mips.cc
|
| diff --git a/src/mips/assembler-mips.cc b/src/mips/assembler-mips.cc
|
| index e50a239a4a9c6c0533995a2ed8a337743797d915..39448d3812b609ed0cc625d1d250e83a636b4a14 100644
|
| --- a/src/mips/assembler-mips.cc
|
| +++ b/src/mips/assembler-mips.cc
|
| @@ -534,6 +534,11 @@ bool Assembler::IsBnec(Instr instr) {
|
| return opcode == POP30 && rs != 0 && rs < rt; // && rt != 0
|
| }
|
|
|
| +bool Assembler::IsJicOrJialc(Instr instr) {
|
| + uint32_t opcode = GetOpcodeField(instr);
|
| + uint32_t rs = GetRsField(instr);
|
| + return (opcode == POP66 || opcode == POP76) && rs == 0;
|
| +}
|
|
|
| bool Assembler::IsJump(Instr instr) {
|
| uint32_t opcode = GetOpcodeField(instr);
|
| @@ -546,7 +551,6 @@ bool Assembler::IsJump(Instr instr) {
|
| ((function_field == JALR) || (rd_field == 0 && (function_field == JR))));
|
| }
|
|
|
| -
|
| bool Assembler::IsJ(Instr instr) {
|
| uint32_t opcode = GetOpcodeField(instr);
|
| // Checks if the instruction is a jump.
|
| @@ -697,6 +701,47 @@ static inline int32_t AddBranchOffset(int pos, Instr instr) {
|
| }
|
| }
|
|
|
| +uint32_t Assembler::CreateTargetAddress(Instr instr_lui, Instr instr_jic) {
|
| + DCHECK(IsLui(instr_lui) && IsJicOrJialc(instr_jic));
|
| + int16_t jic_offset = GetImmediate16(instr_jic);
|
| + int16_t lui_offset = GetImmediate16(instr_lui);
|
| +
|
| + if (jic_offset < 0) {
|
| + lui_offset += kImm16Mask;
|
| + }
|
| + uint32_t lui_offset_u = (static_cast<uint32_t>(lui_offset)) << kLuiShift;
|
| + uint32_t jic_offset_u = static_cast<uint32_t>(jic_offset) & kImm16Mask;
|
| +
|
| + return lui_offset_u | jic_offset_u;
|
| +}
|
| +
|
| +// Use just lui and jic instructions. Insert lower part of the target address in
|
| +// jic offset part. Since jic sign-extends offset and then add it with register,
|
| +// before that addition, difference between upper part of the target address and
|
| +// upper part of the sign-extended offset (0xffff or 0x0000), will be inserted
|
| +// in jic register with lui instruction.
|
| +void Assembler::UnpackTargetAddress(uint32_t address, int16_t& lui_offset,
|
| + int16_t& jic_offset) {
|
| + lui_offset = (address & kHiMask) >> kLuiShift;
|
| + jic_offset = address & kLoMask;
|
| +
|
| + if (jic_offset < 0) {
|
| + lui_offset -= kImm16Mask;
|
| + }
|
| +}
|
| +
|
| +void Assembler::UnpackTargetAddressUnsigned(uint32_t address,
|
| + uint32_t& lui_offset,
|
| + uint32_t& jic_offset) {
|
| + int16_t lui_offset16 = (address & kHiMask) >> kLuiShift;
|
| + int16_t jic_offset16 = address & kLoMask;
|
| +
|
| + if (jic_offset16 < 0) {
|
| + lui_offset16 -= kImm16Mask;
|
| + }
|
| + lui_offset = static_cast<uint32_t>(lui_offset16) & kImm16Mask;
|
| + jic_offset = static_cast<uint32_t>(jic_offset16) & kImm16Mask;
|
| +}
|
|
|
| int Assembler::target_at(int pos, bool is_internal) {
|
| Instr instr = instr_at(pos);
|
| @@ -724,11 +769,16 @@ int Assembler::target_at(int pos, bool is_internal) {
|
| if (IsBranch(instr)) {
|
| return AddBranchOffset(pos, instr);
|
| } else {
|
| - Instr instr_lui = instr_at(pos + 0 * Assembler::kInstrSize);
|
| - Instr instr_ori = instr_at(pos + 1 * Assembler::kInstrSize);
|
| - DCHECK(IsOri(instr_ori));
|
| - int32_t imm = (instr_lui & static_cast<int32_t>(kImm16Mask)) << kLuiShift;
|
| - imm |= (instr_ori & static_cast<int32_t>(kImm16Mask));
|
| + Instr instr1 = instr_at(pos + 0 * Assembler::kInstrSize);
|
| + Instr instr2 = instr_at(pos + 1 * Assembler::kInstrSize);
|
| + DCHECK(IsOri(instr2) || IsJicOrJialc(instr2));
|
| + int32_t imm;
|
| + if (IsJicOrJialc(instr2)) {
|
| + imm = CreateTargetAddress(instr1, instr2);
|
| + } else {
|
| + imm = (instr1 & static_cast<int32_t>(kImm16Mask)) << kLuiShift;
|
| + imm |= (instr2 & static_cast<int32_t>(kImm16Mask));
|
| + }
|
|
|
| if (imm == kEndOfJumpChain) {
|
| // EndOfChain sentinel is returned directly, not relative to pc or pos.
|
| @@ -781,19 +831,26 @@ void Assembler::target_at_put(int32_t pos, int32_t target_pos,
|
| instr = SetBranchOffset(pos, target_pos, instr);
|
| instr_at_put(pos, instr);
|
| } else {
|
| - Instr instr_lui = instr_at(pos + 0 * Assembler::kInstrSize);
|
| - Instr instr_ori = instr_at(pos + 1 * Assembler::kInstrSize);
|
| - DCHECK(IsOri(instr_ori));
|
| + Instr instr1 = instr_at(pos + 0 * Assembler::kInstrSize);
|
| + Instr instr2 = instr_at(pos + 1 * Assembler::kInstrSize);
|
| + DCHECK(IsOri(instr2) || IsJicOrJialc(instr2));
|
| uint32_t imm = reinterpret_cast<uint32_t>(buffer_) + target_pos;
|
| DCHECK((imm & 3) == 0);
|
| -
|
| - instr_lui &= ~kImm16Mask;
|
| - instr_ori &= ~kImm16Mask;
|
| -
|
| - instr_at_put(pos + 0 * Assembler::kInstrSize,
|
| - instr_lui | ((imm & kHiMask) >> kLuiShift));
|
| - instr_at_put(pos + 1 * Assembler::kInstrSize,
|
| - instr_ori | (imm & kImm16Mask));
|
| + DCHECK(IsLui(instr1) && (IsJicOrJialc(instr2) || IsOri(instr2)));
|
| + instr1 &= ~kImm16Mask;
|
| + instr2 &= ~kImm16Mask;
|
| +
|
| + if (IsJicOrJialc(instr2)) {
|
| + uint32_t lui_offset_u, jic_offset_u;
|
| + UnpackTargetAddressUnsigned(imm, lui_offset_u, jic_offset_u);
|
| + instr_at_put(pos + 0 * Assembler::kInstrSize, instr1 | lui_offset_u);
|
| + instr_at_put(pos + 1 * Assembler::kInstrSize, instr2 | jic_offset_u);
|
| + } else {
|
| + instr_at_put(pos + 0 * Assembler::kInstrSize,
|
| + instr1 | ((imm & kHiMask) >> kLuiShift));
|
| + instr_at_put(pos + 1 * Assembler::kInstrSize,
|
| + instr2 | (imm & kImm16Mask));
|
| + }
|
| }
|
| }
|
|
|
| @@ -2790,24 +2847,36 @@ int Assembler::RelocateInternalReference(RelocInfo::Mode rmode, byte* pc,
|
| } else {
|
| DCHECK(RelocInfo::IsInternalReferenceEncoded(rmode));
|
| if (IsLui(instr)) {
|
| - Instr instr_lui = instr_at(pc + 0 * Assembler::kInstrSize);
|
| - Instr instr_ori = instr_at(pc + 1 * Assembler::kInstrSize);
|
| - DCHECK(IsOri(instr_ori));
|
| - int32_t imm = (instr_lui & static_cast<int32_t>(kImm16Mask)) << kLuiShift;
|
| - imm |= (instr_ori & static_cast<int32_t>(kImm16Mask));
|
| + Instr instr1 = instr_at(pc + 0 * Assembler::kInstrSize);
|
| + Instr instr2 = instr_at(pc + 1 * Assembler::kInstrSize);
|
| + DCHECK(IsOri(instr2) || IsJicOrJialc(instr2));
|
| + int32_t imm;
|
| + if (IsJicOrJialc(instr2)) {
|
| + imm = CreateTargetAddress(instr1, instr2);
|
| + } else {
|
| + imm = (instr1 & static_cast<int32_t>(kImm16Mask)) << kLuiShift;
|
| + imm |= (instr2 & static_cast<int32_t>(kImm16Mask));
|
| + }
|
| +
|
| if (imm == kEndOfJumpChain) {
|
| return 0; // Number of instructions patched.
|
| }
|
| imm += pc_delta;
|
| DCHECK((imm & 3) == 0);
|
| -
|
| - instr_lui &= ~kImm16Mask;
|
| - instr_ori &= ~kImm16Mask;
|
| -
|
| - instr_at_put(pc + 0 * Assembler::kInstrSize,
|
| - instr_lui | ((imm >> kLuiShift) & kImm16Mask));
|
| - instr_at_put(pc + 1 * Assembler::kInstrSize,
|
| - instr_ori | (imm & kImm16Mask));
|
| + instr1 &= ~kImm16Mask;
|
| + instr2 &= ~kImm16Mask;
|
| +
|
| + if (IsJicOrJialc(instr2)) {
|
| + uint32_t lui_offset_u, jic_offset_u;
|
| + Assembler::UnpackTargetAddressUnsigned(imm, lui_offset_u, jic_offset_u);
|
| + instr_at_put(pc + 0 * Assembler::kInstrSize, instr1 | lui_offset_u);
|
| + instr_at_put(pc + 1 * Assembler::kInstrSize, instr2 | jic_offset_u);
|
| + } else {
|
| + instr_at_put(pc + 0 * Assembler::kInstrSize,
|
| + instr1 | ((imm >> kLuiShift) & kImm16Mask));
|
| + instr_at_put(pc + 1 * Assembler::kInstrSize,
|
| + instr2 | (imm & kImm16Mask));
|
| + }
|
| return 2; // Number of instructions patched.
|
| } else {
|
| UNREACHABLE();
|
| @@ -2964,19 +3033,40 @@ void Assembler::CheckTrampolinePool() {
|
| }
|
|
|
| int pool_start = pc_offset();
|
| - for (int i = 0; i < unbound_labels_count_; i++) {
|
| - uint32_t imm32;
|
| - imm32 = jump_address(&after_pool);
|
| - { BlockGrowBufferScope block_buf_growth(this);
|
| - // Buffer growth (and relocation) must be blocked for internal
|
| - // references until associated instructions are emitted and available
|
| - // to be patched.
|
| - RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE_ENCODED);
|
| - lui(at, (imm32 & kHiMask) >> kLuiShift);
|
| - ori(at, at, (imm32 & kImm16Mask));
|
| + if (IsMipsArchVariant(kMips32r6)) {
|
| + for (int i = 0; i < unbound_labels_count_; i++) {
|
| + uint32_t imm32;
|
| + imm32 = jump_address(&after_pool);
|
| + uint32_t lui_offset, jic_offset;
|
| + UnpackTargetAddressUnsigned(imm32, lui_offset, jic_offset);
|
| + {
|
| + BlockGrowBufferScope block_buf_growth(this);
|
| + // Buffer growth (and relocation) must be blocked for internal
|
| + // references until associated instructions are emitted and
|
| + // available to be patched.
|
| + RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE_ENCODED);
|
| + lui(at, lui_offset);
|
| + jic(at, jic_offset);
|
| + }
|
| + CheckBuffer();
|
| + }
|
| + } else {
|
| + for (int i = 0; i < unbound_labels_count_; i++) {
|
| + uint32_t imm32;
|
| + imm32 = jump_address(&after_pool);
|
| + {
|
| + BlockGrowBufferScope block_buf_growth(this);
|
| + // Buffer growth (and relocation) must be blocked for internal
|
| + // references until associated instructions are emitted and
|
| + // available to be patched.
|
| + RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE_ENCODED);
|
| + lui(at, (imm32 & kHiMask) >> kLuiShift);
|
| + ori(at, at, (imm32 & kImm16Mask));
|
| + }
|
| + CheckBuffer();
|
| + jr(at);
|
| + nop();
|
| }
|
| - jr(at);
|
| - nop();
|
| }
|
| bind(&after_pool);
|
| trampoline_ = Trampoline(pool_start, unbound_labels_count_);
|
| @@ -3000,10 +3090,10 @@ Address Assembler::target_address_at(Address pc) {
|
| Instr instr1 = instr_at(pc);
|
| Instr instr2 = instr_at(pc + kInstrSize);
|
| // Interpret 2 instructions generated by li: lui/ori
|
| - if ((GetOpcodeField(instr1) == LUI) && (GetOpcodeField(instr2) == ORI)) {
|
| + if (IsLui(instr1) && IsOri(instr2)) {
|
| // Assemble the 32 bit value.
|
| - return reinterpret_cast<Address>(
|
| - (GetImmediate16(instr1) << 16) | GetImmediate16(instr2));
|
| + return reinterpret_cast<Address>((GetImmediate16(instr1) << kLuiShift) |
|
| + GetImmediate16(instr2));
|
| }
|
|
|
| // We should never get here, force a bad address if we do.
|
| @@ -3024,6 +3114,8 @@ void Assembler::QuietNaN(HeapObject* object) {
|
| // On Mips, a target address is stored in a lui/ori instruction pair, each
|
| // of which load 16 bits of the 32-bit address to a register.
|
| // Patching the address must replace both instr, and flush the i-cache.
|
| +// On r6, target address is stored in a lui/jic pair, and both instr have to be
|
| +// patched.
|
| //
|
| // There is an optimization below, which emits a nop when the address
|
| // fits in just 16 bits. This is unlikely to help, and should be benchmarked,
|
| @@ -3039,15 +3131,27 @@ void Assembler::set_target_address_at(Isolate* isolate, Address pc,
|
| #ifdef DEBUG
|
| // Check we have the result from a li macro-instruction, using instr pair.
|
| Instr instr1 = instr_at(pc);
|
| - CHECK((GetOpcodeField(instr1) == LUI && GetOpcodeField(instr2) == ORI));
|
| + CHECK(IsLui(instr1) && (IsOri(instr2) || IsJicOrJialc(instr2)));
|
| #endif
|
|
|
| - // Must use 2 instructions to insure patchable code => just use lui and ori.
|
| - // lui rt, upper-16.
|
| - // ori rt rt, lower-16.
|
| - *p = LUI | rt_code | ((itarget & kHiMask) >> kLuiShift);
|
| - *(p + 1) = ORI | rt_code | (rt_code << 5) | (itarget & kImm16Mask);
|
| + if (IsJicOrJialc(instr2)) {
|
| + // Must use 2 instructions to insure patchable code => use lui and jic
|
| + uint32_t lui_offset, jic_offset;
|
| + Assembler::UnpackTargetAddressUnsigned(itarget, lui_offset, jic_offset);
|
|
|
| + *p &= ~kImm16Mask;
|
| + *(p + 1) &= ~kImm16Mask;
|
| +
|
| + *p |= lui_offset;
|
| + *(p + 1) |= jic_offset;
|
| +
|
| + } else {
|
| + // Must use 2 instructions to insure patchable code => just use lui and ori.
|
| + // lui rt, upper-16.
|
| + // ori rt rt, lower-16.
|
| + *p = LUI | rt_code | ((itarget & kHiMask) >> kLuiShift);
|
| + *(p + 1) = ORI | rt_code | (rt_code << 5) | (itarget & kImm16Mask);
|
| + }
|
|
|
| if (icache_flush_mode != SKIP_ICACHE_FLUSH) {
|
| Assembler::FlushICache(isolate, pc, 2 * sizeof(int32_t));
|
|
|