Chromium Code Reviews| Index: runtime/vm/assembler_mips.h |
| =================================================================== |
| --- runtime/vm/assembler_mips.h (revision 25483) |
| +++ runtime/vm/assembler_mips.h (working copy) |
| @@ -22,6 +22,8 @@ |
| // The MIPS32® Instruction Set" in short "VolII-A" |
| namespace dart { |
| +DECLARE_FLAG(bool, mips_far_branches); |
| + |
| // Forward declarations. |
| class RuntimeEntry; |
| @@ -854,76 +856,80 @@ |
| } |
| void BranchEqual(Register rd, int32_t value, Label* l) { |
| - ASSERT(rd != CMPRES); |
| - LoadImmediate(CMPRES, value); |
| - beq(rd, CMPRES, l); |
| + ASSERT(rd != CMPRES2); |
| + LoadImmediate(CMPRES2, value); |
| + beq(rd, CMPRES2, l); |
| } |
| void BranchEqual(Register rd, const Object& object, Label* l) { |
| - ASSERT(rd != CMPRES); |
| - LoadObject(CMPRES, object); |
| - beq(rd, CMPRES, l); |
| + ASSERT(rd != CMPRES2); |
| + LoadObject(CMPRES2, object); |
| + beq(rd, CMPRES2, l); |
| } |
| void BranchNotEqual(Register rd, int32_t value, Label* l) { |
| - ASSERT(rd != CMPRES); |
| - LoadImmediate(CMPRES, value); |
| - bne(rd, CMPRES, l); |
| + ASSERT(rd != CMPRES2); |
| + LoadImmediate(CMPRES2, value); |
| + bne(rd, CMPRES2, l); |
| } |
| void BranchNotEqual(Register rd, const Object& object, Label* l) { |
| - ASSERT(rd != CMPRES); |
| - LoadObject(CMPRES, object); |
| - bne(rd, CMPRES, l); |
| + ASSERT(rd != CMPRES2); |
| + LoadObject(CMPRES2, object); |
| + bne(rd, CMPRES2, l); |
| } |
| void BranchSignedGreater(Register rd, Register rs, Label* l) { |
| - slt(CMPRES, rs, rd); // CMPRES = rd > rs ? 1 : 0. |
| - bne(CMPRES, ZR, l); |
| + slt(CMPRES1, rs, rd); // CMPRES1 = rd > rs ? 1 : 0. |
|
regis
2013/07/25 20:07:43
It's awkward that some branch instructions use CMP
zra
2013/07/26 21:26:15
Done.
|
| + bne(CMPRES1, ZR, l); |
| } |
| void BranchSignedGreater(Register rd, int32_t value, Label* l) { |
| - LoadImmediate(CMPRES, value); |
| - BranchSignedGreater(rd, CMPRES, l); |
| + ASSERT(rd != CMPRES2); |
| + LoadImmediate(CMPRES2, value); |
| + BranchSignedGreater(rd, CMPRES2, l); |
| } |
| void BranchUnsignedGreater(Register rd, Register rs, Label* l) { |
| - sltu(CMPRES, rs, rd); |
| - bne(CMPRES, ZR, l); |
| + sltu(CMPRES1, rs, rd); |
| + bne(CMPRES1, ZR, l); |
| } |
| void BranchUnsignedGreater(Register rd, int32_t value, Label* l) { |
| - LoadImmediate(CMPRES, value); |
| - BranchUnsignedGreater(rd, CMPRES, l); |
| + ASSERT(rd != CMPRES2); |
| + LoadImmediate(CMPRES2, value); |
| + BranchUnsignedGreater(rd, CMPRES2, l); |
| } |
| void BranchSignedGreaterEqual(Register rd, Register rs, Label* l) { |
| - slt(CMPRES, rd, rs); // CMPRES = rd < rs ? 1 : 0. |
| - beq(CMPRES, ZR, l); // If CMPRES = 0, then rd >= rs. |
| + slt(CMPRES1, rd, rs); // CMPRES1 = rd < rs ? 1 : 0. |
| + beq(CMPRES1, ZR, l); // If CMPRES1 = 0, then rd >= rs. |
| } |
| void BranchSignedGreaterEqual(Register rd, int32_t value, Label* l) { |
| if (Utils::IsInt(kImmBits, value)) { |
| - slti(CMPRES, rd, Immediate(value)); |
| - beq(CMPRES, ZR, l); |
| + slti(CMPRES1, rd, Immediate(value)); |
| + beq(CMPRES1, ZR, l); |
| } else { |
| - LoadImmediate(CMPRES, value); |
| - BranchSignedGreaterEqual(rd, CMPRES, l); |
| + ASSERT(rd != CMPRES2); |
| + LoadImmediate(CMPRES2, value); |
| + BranchSignedGreaterEqual(rd, CMPRES2, l); |
| } |
| } |
| void BranchUnsignedGreaterEqual(Register rd, Register rs, Label* l) { |
| - sltu(CMPRES, rd, rs); // CMPRES = rd < rs ? 1 : 0. |
| - beq(CMPRES, ZR, l); |
| + sltu(CMPRES1, rd, rs); // CMPRES1 = rd < rs ? 1 : 0. |
| + beq(CMPRES1, ZR, l); |
| } |
| void BranchUnsignedGreaterEqual(Register rd, int32_t value, Label* l) { |
| if (Utils::IsUint(kImmBits, value)) { |
| - sltiu(CMPRES, rd, Immediate(value)); |
| - beq(CMPRES, ZR, l); |
| + sltiu(CMPRES1, rd, Immediate(value)); |
| + beq(CMPRES1, ZR, l); |
| } else { |
| - LoadImmediate(CMPRES, value); |
| - BranchUnsignedGreaterEqual(rd, CMPRES, l); |
| + ASSERT(rd != CMPRES2); |
| + LoadImmediate(CMPRES2, value); |
| + BranchUnsignedGreaterEqual(rd, CMPRES2, l); |
| } |
| } |
| @@ -933,11 +939,12 @@ |
| void BranchSignedLess(Register rd, int32_t value, Label* l) { |
| if (Utils::IsInt(kImmBits, value)) { |
| - slti(CMPRES, rd, Immediate(value)); |
| - bne(CMPRES, ZR, l); |
| + slti(CMPRES1, rd, Immediate(value)); |
| + bne(CMPRES1, ZR, l); |
| } else { |
| - LoadImmediate(CMPRES, value); |
| - BranchSignedGreater(CMPRES, rd, l); |
| + ASSERT(rd != CMPRES2); |
| + LoadImmediate(CMPRES2, value); |
| + BranchSignedGreater(CMPRES2, rd, l); |
| } |
| } |
| @@ -947,11 +954,12 @@ |
| void BranchUnsignedLess(Register rd, int32_t value, Label* l) { |
| if (Utils::IsUint(kImmBits, value)) { |
| - sltiu(CMPRES, rd, Immediate(value)); |
| - bne(CMPRES, ZR, l); |
| + sltiu(CMPRES1, rd, Immediate(value)); |
| + bne(CMPRES1, ZR, l); |
| } else { |
| - LoadImmediate(CMPRES, value); |
| - BranchUnsignedGreater(CMPRES, rd, l); |
| + ASSERT(rd != CMPRES2); |
| + LoadImmediate(CMPRES2, value); |
| + BranchUnsignedGreater(CMPRES2, rd, l); |
| } |
| } |
| @@ -960,8 +968,8 @@ |
| } |
| void BranchSignedLessEqual(Register rd, int32_t value, Label* l) { |
| - LoadImmediate(CMPRES, value); |
| - BranchSignedGreaterEqual(CMPRES, rd, l); |
| + LoadImmediate(CMPRES1, value); |
| + BranchSignedGreaterEqual(CMPRES1, rd, l); |
| } |
| void BranchUnsignedLessEqual(Register rd, Register rs, Label* l) { |
| @@ -969,8 +977,8 @@ |
| } |
| void BranchUnsignedLessEqual(Register rd, int32_t value, Label* l) { |
| - LoadImmediate(CMPRES, value); |
| - BranchUnsignedGreaterEqual(CMPRES, rd, l); |
| + LoadImmediate(CMPRES1, value); |
| + BranchUnsignedGreaterEqual(CMPRES1, rd, l); |
| } |
| void Push(Register rt) { |
| @@ -1029,6 +1037,19 @@ |
| lwc1(hi, Address(base, offset + kWordSize)); |
| } |
| + // dest gets the address of the following instruction. If preserve ra is true |
| + // RA is preserved using CMPRES1 as a temporary. |
| + void GetNextPC(Register dest, bool preserve_ra) { |
| + if (preserve_ra) { |
| + mov(CMPRES1, RA); |
| + } |
| + EmitRegImmType(REGIMM, R0, BGEZAL, 1); |
| + mov(dest, RA); |
| + if (preserve_ra) { |
| + mov(RA, CMPRES1); |
| + } |
| + } |
| + |
| void ReserveAlignedFrameSpace(intptr_t frame_space); |
| // Create a frame for calling into runtime that preserves all volatile |
| @@ -1182,17 +1203,140 @@ |
| func << kCop1FnShift); |
| } |
| + int32_t DecodeLoadImmediate(int32_t low, int32_t high); |
| + int32_t EncodeLoadImmediate(int32_t dest, int32_t instr); |
| + |
| + Opcode OppositeBranchOpcode(Opcode b) { |
| + switch (b) { |
| + case BEQ: return BNE; |
| + case BNE: return BEQ; |
| + case BGTZ: return BLEZ; |
| + case BLEZ: return BGTZ; |
| + case BEQL: return BNEL; |
| + case BNEL: return BEQL; |
| + case BGTZL: return BLEZL; |
| + case BLEZL: return BGTZL; |
| + default: |
| + UNREACHABLE(); |
| + break; |
| + } |
| + return BNE; |
| + } |
| + |
| + void EmitFarBranch(Opcode b, Register rs, Register rt, int32_t offset) { |
| + ASSERT(rs != TMP); |
| + ASSERT(rt != TMP); |
| + |
| + const uint16_t low = Utils::Low16Bits(offset); |
| + const uint16_t high = Utils::High16Bits(offset); |
| + lui(TMP, Immediate(high)); |
| + ori(TMP, TMP, Immediate(low)); |
| + |
| + addiu(SP, SP, Immediate(-1 * kWordSize)); |
| + sw(CMPRES1, Address(SP, -0 * kWordSize)); |
| + |
| + mov(CMPRES1, RA); |
| + EmitRegImmType(REGIMM, R0, BGEZAL, 1); |
|
regis
2013/07/25 20:07:43
You are not using GetNextPC. Still needed?
OK, I s
|
| + addu(TMP, TMP, RA); |
| + mov(RA, CMPRES1); |
| + |
| + lw(CMPRES1, Address(SP, -0 * kWordSize)); |
| + addiu(SP, SP, Immediate(1 * kWordSize)); |
|
regis
2013/07/25 20:07:43
Preserving and restoring CMPRES1 in order to, in t
|
| + |
| + EmitIType(OppositeBranchOpcode(b), rs, rt, 2); |
|
regis
2013/07/25 20:07:43
You should have an unconditional EmitFarBranch(off
zra
2013/07/26 21:26:15
Done.
|
| + nop(); |
| + EmitRType(SPECIAL, TMP, R0, R0, 0, JR); |
| + } |
| + |
| + RtRegImm OppositeBranchNoLink(RtRegImm b) { |
| + switch (b) { |
| + case BLTZ: return BGEZ; |
| + case BGEZ: return BLTZ; |
| + case BLTZAL: return BGEZ; |
| + case BGEZAL: return BLTZ; |
| + default: |
| + UNREACHABLE(); |
| + break; |
| + } |
| + return BLTZ; |
| + } |
| + |
| + void EmitFarRegImmBranch(RtRegImm b, Register rs, int32_t offset) { |
| + ASSERT(rs != TMP); |
| + |
| + const uint16_t low = Utils::Low16Bits(offset); |
| + const uint16_t high = Utils::High16Bits(offset); |
| + lui(TMP, Immediate(high)); |
| + ori(TMP, TMP, Immediate(low)); |
| + |
| + addiu(SP, SP, Immediate(-1 * kWordSize)); |
| + sw(CMPRES1, Address(SP, -0 * kWordSize)); |
| + |
| + mov(CMPRES1, RA); |
| + EmitRegImmType(REGIMM, R0, BGEZAL, 1); |
| + addu(TMP, TMP, RA); |
| + mov(RA, CMPRES1); |
| + |
| + lw(CMPRES1, Address(SP, -0 * kWordSize)); |
| + addiu(SP, SP, Immediate(1 * kWordSize)); |
| + |
| + EmitRegImmType(REGIMM, rs, OppositeBranchNoLink(b), 2); |
| + nop(); |
| + if ((b == BLTZAL) || (b == BGEZAL)) { |
| + EmitRType(SPECIAL, TMP, R0, RA, 0, JALR); |
| + } else { |
| + EmitRType(SPECIAL, TMP, R0, R0, 0, JR); |
| + } |
| + } |
| + |
| + |
| + void EmitFarFpuBranch(bool kind, int32_t offset) { |
| + const uint32_t b16 = kind ? 0 : (1 << 16); |
| + |
| + const uint16_t low = Utils::Low16Bits(offset); |
| + const uint16_t high = Utils::High16Bits(offset); |
| + lui(TMP, Immediate(high)); |
| + ori(TMP, TMP, Immediate(low)); |
| + |
| + addiu(SP, SP, Immediate(-1 * kWordSize)); |
| + sw(CMPRES1, Address(SP, -0 * kWordSize)); |
| + |
| + mov(CMPRES1, RA); |
| + EmitRegImmType(REGIMM, R0, BGEZAL, 1); |
| + addu(TMP, TMP, RA); |
| + mov(RA, CMPRES1); |
| + |
| + lw(CMPRES1, Address(SP, -0 * kWordSize)); |
| + addiu(SP, SP, Immediate(1 * kWordSize)); |
| + |
| + Emit(COP1 << kOpcodeShift | COP1_BC << kCop1SubShift | b16 | 2); |
| + nop(); |
| + EmitRType(SPECIAL, TMP, R0, R0, 0, JR); |
| + } |
| + |
| + |
| void EmitBranch(Opcode b, Register rs, Register rt, Label* label) { |
| if (label->IsBound()) { |
|
regis
2013/07/25 20:07:43
If the label is bound, you know the offset and you
zra
2013/07/26 21:26:15
Done.
|
| // Relative destination from an instruction after the branch. |
| - const int32_t dest = |
| - label->Position() - (buffer_.Size() + Instr::kInstrSize); |
| - const uint16_t dest_off = EncodeBranchOffset(dest, 0); |
| - EmitIType(b, rs, rt, dest_off); |
| + if (FLAG_mips_far_branches) { |
| + const int32_t dest = |
| + label->Position() - (buffer_.Size() + 7 * Instr::kInstrSize); |
| + EmitFarBranch(b, rs, rt, dest); |
| + } else { |
| + const int32_t dest = |
| + label->Position() - (buffer_.Size() + Instr::kInstrSize); |
| + const uint16_t dest_off = EncodeBranchOffset(dest, 0); |
| + EmitIType(b, rs, rt, dest_off); |
| + } |
| } else { |
| const int position = buffer_.Size(); |
| - const uint16_t dest_off = EncodeBranchOffset(label->position_, 0); |
| - EmitIType(b, rs, rt, dest_off); |
| + if (FLAG_mips_far_branches) { |
| + const uint32_t dest_off = label->position_; |
| + EmitFarBranch(b, rs, rt, dest_off); |
| + } else { |
| + const uint16_t dest_off = EncodeBranchOffset(label->position_, 0); |
| + EmitIType(b, rs, rt, dest_off); |
| + } |
| label->LinkTo(position); |
| } |
| } |
| @@ -1200,14 +1344,25 @@ |
| void EmitRegImmBranch(RtRegImm b, Register rs, Label* label) { |
| if (label->IsBound()) { |
|
regis
2013/07/25 20:07:43
ditto
zra
2013/07/26 21:26:15
Done.
|
| // Relative destination from an instruction after the branch. |
| - const int32_t dest = |
| - label->Position() - (buffer_.Size() + Instr::kInstrSize); |
| - const uint16_t dest_off = EncodeBranchOffset(dest, 0); |
| - EmitRegImmType(REGIMM, rs, b, dest_off); |
| + if (FLAG_mips_far_branches) { |
| + const int32_t dest = |
| + label->Position() - (buffer_.Size() + 7 * Instr::kInstrSize); |
| + EmitFarRegImmBranch(b, rs, dest); |
| + } else { |
| + const int32_t dest = |
| + label->Position() - (buffer_.Size() + Instr::kInstrSize); |
| + const uint16_t dest_off = EncodeBranchOffset(dest, 0); |
| + EmitRegImmType(REGIMM, rs, b, dest_off); |
| + } |
| } else { |
| const int position = buffer_.Size(); |
| - const uint16_t dest_off = EncodeBranchOffset(label->position_, 0); |
| - EmitRegImmType(REGIMM, rs, b, dest_off); |
| + if (FLAG_mips_far_branches) { |
| + const uint32_t dest_off = label->position_; |
| + EmitFarRegImmBranch(b, rs, dest_off); |
| + } else { |
| + const uint16_t dest_off = EncodeBranchOffset(label->position_, 0); |
| + EmitRegImmType(REGIMM, rs, b, dest_off); |
| + } |
| label->LinkTo(position); |
| } |
| } |
| @@ -1216,20 +1371,31 @@ |
| const int32_t b16 = kind ? (1 << 16) : 0; // Bit 16 set for branch on true. |
| if (label->IsBound()) { |
|
regis
2013/07/25 20:07:43
ditto
zra
2013/07/26 21:26:15
Done.
|
| // Relative destination from an instruction after the branch. |
| - const int32_t dest = |
| - label->Position() - (buffer_.Size() + Instr::kInstrSize); |
| - const uint16_t dest_off = EncodeBranchOffset(dest, 0); |
| - Emit(COP1 << kOpcodeShift | |
| - COP1_BC << kCop1SubShift | |
| - b16 | |
| - dest_off); |
| + if (FLAG_mips_far_branches) { |
| + const int32_t dest = |
| + label->Position() - (buffer_.Size() + 7 * Instr::kInstrSize); |
| + EmitFarFpuBranch(kind, dest); |
| + } else { |
| + const int32_t dest = |
| + label->Position() - (buffer_.Size() + Instr::kInstrSize); |
| + const uint16_t dest_off = EncodeBranchOffset(dest, 0); |
| + Emit(COP1 << kOpcodeShift | |
| + COP1_BC << kCop1SubShift | |
| + b16 | |
| + dest_off); |
| + } |
| } else { |
| const int position = buffer_.Size(); |
| - const uint16_t dest_off = EncodeBranchOffset(label->position_, 0); |
| - Emit(COP1 << kOpcodeShift | |
| - COP1_BC << kCop1SubShift | |
| - b16 | |
| - dest_off); |
| + if (FLAG_mips_far_branches) { |
| + const uint32_t dest_off = label->position_; |
| + EmitFarFpuBranch(kind, dest_off); |
| + } else { |
| + const uint16_t dest_off = EncodeBranchOffset(label->position_, 0); |
| + Emit(COP1 << kOpcodeShift | |
| + COP1_BC << kCop1SubShift | |
| + b16 | |
| + dest_off); |
| + } |
| label->LinkTo(position); |
| } |
| } |