Index: runtime/vm/assembler_mips.h |
=================================================================== |
--- runtime/vm/assembler_mips.h (revision 20399) |
+++ runtime/vm/assembler_mips.h (working copy) |
@@ -147,9 +147,7 @@ |
UNIMPLEMENTED(); |
} |
- void Bind(Label* label) { |
- UNIMPLEMENTED(); |
- } |
+ void Bind(Label* label); |
// Misc. functionality |
int CodeSize() const { return buffer_.Size(); } |
@@ -245,6 +243,101 @@ |
EmitIType(ANDI, rs, rt, imm_value); |
} |
+ // Unconditional branch. |
+ void b(Label* l) { |
+ beq(R0, R0, l); |
+ } |
+ |
+ // Branch if equal. |
+ void beq(Register rs, Register rt, Label* l) { |
+ ASSERT(!in_delay_slot_); |
+ EmitBranch(BEQ, rs, rt, l); |
+ EmitBranchDelayNop(); |
+ } |
+ |
+ // Branch if equal, likely taken. |
+ // Delay slot executed only when branch taken. |
+ void beql(Register rs, Register rt, Label* l) { |
+ ASSERT(!in_delay_slot_); |
+ EmitBranch(BEQL, rs, rt, l); |
+ EmitBranchDelayNop(); |
+ } |
+ |
+ // Branch if rs >= 0. |
+ void bgez(Register rs, Label* l) { |
+ ASSERT(!in_delay_slot_); |
+ EmitRegImmBranch(BGEZ, rs, l); |
+ EmitBranchDelayNop(); |
+ } |
+ |
+ // Branch if rs >= 0, likely taken. |
+ // Delay slot executed only when branch taken. |
+ void bgezl(Register rs, Label* l) { |
+ ASSERT(!in_delay_slot_); |
+ EmitRegImmBranch(BGEZL, rs, l); |
+ EmitBranchDelayNop(); |
+ } |
+ |
+ // Branch if rs > 0. |
+ void bgtz(Register rs, Label* l) { |
+ ASSERT(!in_delay_slot_); |
+ EmitBranch(BGTZ, rs, R0, l); |
+ EmitBranchDelayNop(); |
+ } |
+ |
+ // Branch if rs > 0, likely taken. |
+ // Delay slot executed only when branch taken. |
+ void bgtzl(Register rs, Label* l) { |
+ ASSERT(!in_delay_slot_); |
+ EmitBranch(BGTZL, rs, R0, l); |
+ EmitBranchDelayNop(); |
+ } |
+ |
+ // Branch if rs <= 0. |
+ void blez(Register rs, Label* l) { |
+ ASSERT(!in_delay_slot_); |
+ EmitBranch(BLEZ, rs, R0, l); |
+ EmitBranchDelayNop(); |
+ } |
+ |
+ // Branch if rs <= 0, likely taken. |
+ // Delay slot executed only when branch taken. |
+ void blezl(Register rs, Label* l) { |
+ ASSERT(!in_delay_slot_); |
+ EmitBranch(BLEZL, rs, R0, l); |
+ EmitBranchDelayNop(); |
+ } |
+ |
+ // Branch if rs < 0. |
+ void bltz(Register rs, Label* l) { |
+ ASSERT(!in_delay_slot_); |
+ EmitRegImmBranch(BLTZ, rs, l); |
+ EmitBranchDelayNop(); |
+ } |
+ |
+ // Branch if rs < 0, likely taken. |
+ // Delay slot executed only when branch taken. |
+ void bltzl(Register rs, Label* l) { |
+ ASSERT(!in_delay_slot_); |
+ EmitRegImmBranch(BLTZL, rs, l); |
+ EmitBranchDelayNop(); |
+ } |
+ |
+ // Branch if not equal. |
+ void bne(Register rs, Register rt, Label* l) { |
+ ASSERT(!in_delay_slot_); // Jump within a delay slot is not supported. |
+ EmitBranch(BNE, rs, rt, l); |
+ EmitBranchDelayNop(); |
+ } |
+ |
+ // Branch if not equal, likely taken. |
+ // Delay slot executed only when branch taken. |
+ void bnel(Register rs, Register rt, Label* l) { |
+ ASSERT(!in_delay_slot_); // Jump within a delay slot is not supported. |
+ EmitBranch(BNEL, rs, rt, l); |
+ EmitBranchDelayNop(); |
+ } |
+ |
void break_(int32_t code) { |
ASSERT(Utils::IsUint(20, code)); |
Emit(SPECIAL << kOpcodeShift | |
@@ -315,6 +408,10 @@ |
EmitRType(SPECIAL, R0, R0, rd, 0, MFLO); |
} |
+ void mov(Register rd, Register rs) { |
+ or_(rd, rs, ZR); |
+ } |
+ |
void movn(Register rd, Register rs, Register rt) { |
EmitRType(SPECIAL, rs, rt, rd, 0, MOVN); |
} |
@@ -331,6 +428,10 @@ |
EmitRType(SPECIAL, rs, rt, R0, 0, MULTU); |
} |
+ void nop() { |
+ Emit(Instr::kNopInstruction); |
+ } |
+ |
void nor(Register rd, Register rs, Register rt) { |
EmitRType(SPECIAL, rs, rt, rd, 0, NOR); |
} |
@@ -411,10 +512,6 @@ |
} |
} |
- void Move(Register rd, Register rs) { |
- or_(rd, rs, ZR); |
- } |
- |
private: |
AssemblerBuffer buffer_; |
GrowableObjectArray& object_pool_; // Objects and patchable jump targets. |
@@ -496,6 +593,35 @@ |
func << kFunctionShift); |
} |
+ void EmitBranch(Opcode b, Register rs, Register rt, Label* label) { |
+ if (label->IsBound()) { |
+ // Reletive destination from an instruction after the branch. |
+ int32_t dest = label->Position() - (buffer_.Size() + Instr::kInstrSize); |
+ uint16_t dest_off = EncodeBranchOffset(dest, 0); |
+ EmitIType(b, rs, rt, dest_off); |
+ } else { |
+ int position = buffer_.Size(); |
+ EmitIType(b, rs, rt, label->position_); |
+ label->LinkTo(position); |
+ } |
+ } |
+ |
+ void EmitRegImmBranch(RtRegImm b, Register rs, Label* label) { |
+ if (label->IsBound()) { |
+ // Reletive destination from an instruction after the branch. |
+ int32_t dest = label->Position() - (buffer_.Size() + Instr::kInstrSize); |
+ uint16_t dest_off = EncodeBranchOffset(dest, 0); |
+ EmitRegImmType(REGIMM, rs, b, dest_off); |
+ } else { |
+ int position = buffer_.Size(); |
+ EmitRegImmType(REGIMM, rs, b, label->position_); |
+ label->LinkTo(position); |
+ } |
+ } |
+ |
+ static int32_t EncodeBranchOffset(int32_t offset, int32_t instr); |
+ static int DecodeBranchOffset(int32_t instr); |
+ |
void EmitBranchDelayNop() { |
Emit(Instr::kNopInstruction); // Branch delay NOP. |
delay_slot_available_ = true; |