Chromium Code Reviews| Index: src/mips/macro-assembler-mips.cc |
| diff --git a/src/mips/macro-assembler-mips.cc b/src/mips/macro-assembler-mips.cc |
| index a040ab5b0eae05fede61b7c95f3b1a89c4319ce7..246b2eb039d58957211cbe1a238a7c3b61392126 100644 |
| --- a/src/mips/macro-assembler-mips.cc |
| +++ b/src/mips/macro-assembler-mips.cc |
| @@ -1938,14 +1938,13 @@ void MacroAssembler::GetLeastBitsFromInt32(Register dst, |
| (cond != cc_always && (!rs.is(zero_reg) || !rt.rm().is(zero_reg)))) |
| -void MacroAssembler::Branch(int16_t offset, BranchDelaySlot bdslot) { |
| +void MacroAssembler::Branch(int32_t offset, BranchDelaySlot bdslot) { |
| BranchShort(offset, bdslot); |
| } |
| -void MacroAssembler::Branch(int16_t offset, Condition cond, Register rs, |
| - const Operand& rt, |
| - BranchDelaySlot bdslot) { |
| +void MacroAssembler::Branch(int32_t offset, Condition cond, Register rs, |
| + const Operand& rt, BranchDelaySlot bdslot) { |
| BranchShort(offset, cond, rs, rt, bdslot); |
| } |
| @@ -2012,7 +2011,9 @@ void MacroAssembler::Branch(Label* L, |
| } |
| -void MacroAssembler::BranchShort(int16_t offset, BranchDelaySlot bdslot) { |
| +void MacroAssembler::BranchShortHelper(int16_t offset, Label* L, |
| + BranchDelaySlot bdslot) { |
| + offset = GetOffset(offset, L, 16); |
| b(offset); |
| // Emit a nop in the branch delay slot if required. |
| @@ -2021,240 +2022,380 @@ void MacroAssembler::BranchShort(int16_t offset, BranchDelaySlot bdslot) { |
| } |
| -void MacroAssembler::BranchShort(int16_t offset, Condition cond, Register rs, |
| - const Operand& rt, |
| - BranchDelaySlot bdslot) { |
| - BRANCH_ARGS_CHECK(cond, rs, rt); |
| - DCHECK(!rs.is(zero_reg)); |
| - Register r2 = no_reg; |
| - Register scratch = at; |
| +void MacroAssembler::BranchShortHelperR6(int32_t offset, Label* L) { |
| + offset = GetOffset(offset, L, 26); |
| + bc(offset); |
| +} |
| - if (rt.is_reg()) { |
| - // NOTE: 'at' can be clobbered by Branch but it is legal to use it as rs or |
| - // rt. |
| - BlockTrampolinePoolScope block_trampoline_pool(this); |
| - r2 = rt.rm_; |
| - switch (cond) { |
| - case cc_always: |
| - b(offset); |
| - break; |
| - case eq: |
| - beq(rs, r2, offset); |
| - break; |
| - case ne: |
| - bne(rs, r2, offset); |
| - break; |
| - // Signed comparison. |
| - case greater: |
| - if (r2.is(zero_reg)) { |
| - bgtz(rs, offset); |
| - } else { |
| - slt(scratch, r2, rs); |
| - bne(scratch, zero_reg, offset); |
| - } |
| - break; |
| - case greater_equal: |
| - if (r2.is(zero_reg)) { |
| - bgez(rs, offset); |
| - } else { |
| - slt(scratch, rs, r2); |
| - beq(scratch, zero_reg, offset); |
| - } |
| - break; |
| - case less: |
| - if (r2.is(zero_reg)) { |
| - bltz(rs, offset); |
| - } else { |
| - slt(scratch, rs, r2); |
| - bne(scratch, zero_reg, offset); |
| - } |
| - break; |
| - case less_equal: |
| - if (r2.is(zero_reg)) { |
| - blez(rs, offset); |
| - } else { |
| - slt(scratch, r2, rs); |
| - beq(scratch, zero_reg, offset); |
| - } |
| - break; |
| - // Unsigned comparison. |
| - case Ugreater: |
| - if (r2.is(zero_reg)) { |
| - bne(rs, zero_reg, offset); |
| - } else { |
| - sltu(scratch, r2, rs); |
| - bne(scratch, zero_reg, offset); |
| - } |
| - break; |
| - case Ugreater_equal: |
| - if (r2.is(zero_reg)) { |
| - b(offset); |
| - } else { |
| - sltu(scratch, rs, r2); |
| - beq(scratch, zero_reg, offset); |
| - } |
| - break; |
| - case Uless: |
| - if (r2.is(zero_reg)) { |
| - // No code needs to be emitted. |
| - return; |
| - } else { |
| - sltu(scratch, rs, r2); |
| - bne(scratch, zero_reg, offset); |
| - } |
| - break; |
| - case Uless_equal: |
| - if (r2.is(zero_reg)) { |
| - beq(rs, zero_reg, offset); |
| - } else { |
| - sltu(scratch, r2, rs); |
| - beq(scratch, zero_reg, offset); |
| - } |
| - break; |
| - default: |
| - UNREACHABLE(); |
| - } |
| + |
| +void MacroAssembler::BranchShort(int32_t offset, BranchDelaySlot bdslot) { |
| + if (IsMipsArchVariant(kMips32r6) && bdslot == PROTECT) { |
| + DCHECK(is_int26(offset)); |
| + BranchShortHelperR6(offset, nullptr); |
| } else { |
| - // Be careful to always use shifted_branch_offset only just before the |
| - // branch instruction, as the location will be remember for patching the |
| - // target. |
| - BlockTrampolinePoolScope block_trampoline_pool(this); |
| - switch (cond) { |
| - case cc_always: |
| - b(offset); |
| - break; |
| - case eq: |
| - if (rt.imm32_ == 0) { |
| - beq(rs, zero_reg, offset); |
| - } else { |
| - // We don't want any other register but scratch clobbered. |
| - DCHECK(!scratch.is(rs)); |
| - r2 = scratch; |
| - li(r2, rt); |
| - beq(rs, r2, offset); |
| - } |
| - break; |
| - case ne: |
| - if (rt.imm32_ == 0) { |
| - bne(rs, zero_reg, offset); |
| - } else { |
| - // We don't want any other register but scratch clobbered. |
| - DCHECK(!scratch.is(rs)); |
| - r2 = scratch; |
| - li(r2, rt); |
| - bne(rs, r2, offset); |
| - } |
| - break; |
| - // Signed comparison. |
| - case greater: |
| - if (rt.imm32_ == 0) { |
| - bgtz(rs, offset); |
| - } else { |
| - r2 = scratch; |
| - li(r2, rt); |
| - slt(scratch, r2, rs); |
| - bne(scratch, zero_reg, offset); |
| - } |
| - break; |
| - case greater_equal: |
| - if (rt.imm32_ == 0) { |
| - bgez(rs, offset); |
| - } else if (is_int16(rt.imm32_)) { |
| - slti(scratch, rs, rt.imm32_); |
| - beq(scratch, zero_reg, offset); |
| - } else { |
| - r2 = scratch; |
| - li(r2, rt); |
| - slt(scratch, rs, r2); |
| - beq(scratch, zero_reg, offset); |
| - } |
| - break; |
| - case less: |
| - if (rt.imm32_ == 0) { |
| - bltz(rs, offset); |
| - } else if (is_int16(rt.imm32_)) { |
| - slti(scratch, rs, rt.imm32_); |
| - bne(scratch, zero_reg, offset); |
| - } else { |
| - r2 = scratch; |
| - li(r2, rt); |
| - slt(scratch, rs, r2); |
| - bne(scratch, zero_reg, offset); |
| - } |
| - break; |
| - case less_equal: |
| - if (rt.imm32_ == 0) { |
| - blez(rs, offset); |
| - } else { |
| - r2 = scratch; |
| - li(r2, rt); |
| - slt(scratch, r2, rs); |
| - beq(scratch, zero_reg, offset); |
| - } |
| - break; |
| - // Unsigned comparison. |
| - case Ugreater: |
| - if (rt.imm32_ == 0) { |
| - bne(rs, zero_reg, offset); |
| - } else { |
| - r2 = scratch; |
| - li(r2, rt); |
| - sltu(scratch, r2, rs); |
| - bne(scratch, zero_reg, offset); |
| - } |
| - break; |
| - case Ugreater_equal: |
| - if (rt.imm32_ == 0) { |
| - b(offset); |
| - } else if (is_int16(rt.imm32_)) { |
| - sltiu(scratch, rs, rt.imm32_); |
| - beq(scratch, zero_reg, offset); |
| - } else { |
| - r2 = scratch; |
| - li(r2, rt); |
| - sltu(scratch, rs, r2); |
| - beq(scratch, zero_reg, offset); |
| - } |
| - break; |
| - case Uless: |
| - if (rt.imm32_ == 0) { |
| - // No code needs to be emitted. |
| - return; |
| - } else if (is_int16(rt.imm32_)) { |
| - sltiu(scratch, rs, rt.imm32_); |
| - bne(scratch, zero_reg, offset); |
| - } else { |
| - r2 = scratch; |
| - li(r2, rt); |
| - sltu(scratch, rs, r2); |
| - bne(scratch, zero_reg, offset); |
| - } |
| - break; |
| - case Uless_equal: |
| - if (rt.imm32_ == 0) { |
| - beq(rs, zero_reg, offset); |
| - } else { |
| - r2 = scratch; |
| - li(r2, rt); |
| - sltu(scratch, r2, rs); |
| - beq(scratch, zero_reg, offset); |
| - } |
| - break; |
| - default: |
| - UNREACHABLE(); |
| - } |
| + DCHECK(is_int16(offset)); |
| + BranchShortHelper(offset, nullptr, bdslot); |
| } |
| - // Emit a nop in the branch delay slot if required. |
| - if (bdslot == PROTECT) |
| - nop(); |
| } |
| void MacroAssembler::BranchShort(Label* L, BranchDelaySlot bdslot) { |
| - // We use branch_offset as an argument for the branch instructions to be sure |
| - // it is called just before generating the branch instruction, as needed. |
| + if (IsMipsArchVariant(kMips32r6) && bdslot == PROTECT) { |
| + BranchShortHelperR6(0, L); |
| + } else { |
| + BranchShortHelper(0, L, bdslot); |
| + } |
| +} |
| + |
| + |
| +static inline bool IsZero(const Operand& rt) { |
| + if (rt.is_reg()) { |
| + return rt.rm().is(zero_reg); |
| + } else { |
| + return rt.immediate() == 0; |
| + } |
| +} |
| + |
| + |
| +int32_t MacroAssembler::GetOffset(int32_t offset, Label* L, int bits) { |
| + if (L) { |
| + return branch_offset_helper(L, false, bits) >> 2; |
| + } else { |
| + DCHECK(is_intn(offset, bits)); |
| + } |
| + return offset; |
| +} |
| + |
| - b(shifted_branch_offset(L, false)); |
| +void MacroAssembler::BranchShortHelperR6(int32_t offset, Label* L, |
| + Condition cond, Register rs, |
| + const Operand& rt) { |
| + Register scratch = rs.is(at) ? t8 : at; |
| + |
| + // Be careful to always use shifted_branch_offset only just before the |
| + // branch instruction, as the location will be remember for patching the |
| + // target. |
| + BlockTrampolinePoolScope block_trampoline_pool(this); |
| + switch (cond) { |
| + case cc_always: |
| + offset = GetOffset(offset, L, 26); |
| + bc(offset); |
| + break; |
| + case eq: |
| + if (rs.code() == rt.rm_.reg_code) { |
| + // Pre R6 beq is used here to make the code patchable. Otherwise bc |
| + // should be used which has no condition field so is not patchable. |
| + scratch = GetRtAsRegisterHelper(rt, scratch); |
| + offset = GetOffset(offset, L, 26); |
| + beq(rs, scratch, offset); |
| + nop(); |
| + } else if (IsZero(rt)) { |
| + offset = GetOffset(offset, L, 21); |
| + beqzc(rs, offset); |
| + } else { |
| + // We don't want any other register but scratch clobbered. |
| + scratch = GetRtAsRegisterHelper(rt, scratch); |
| + offset = GetOffset(offset, L, 16); |
| + beqc(rs, scratch, offset); |
| + } |
| + break; |
| + case ne: |
| + if (rs.code() == rt.rm_.reg_code) { |
| + // Pre R6 bne is used here to make the code patchable. Otherwise we |
| + // should not generate any instruction. |
| + scratch = GetRtAsRegisterHelper(rt, scratch); |
| + offset = GetOffset(offset, L, 26); |
| + bne(rs, scratch, offset); |
| + nop(); |
| + } else if (IsZero(rt)) { |
| + offset = GetOffset(offset, L, 21); |
| + bnezc(rs, offset); |
| + } else { |
| + // We don't want any other register but scratch clobbered. |
| + scratch = GetRtAsRegisterHelper(rt, scratch); |
| + offset = GetOffset(offset, L, 16); |
| + bnec(rs, scratch, offset); |
| + } |
| + break; |
| + |
| + // Signed comparison. |
| + case greater: |
| + // rs > rt |
| + if (rs.code() == rt.rm_.reg_code) { |
| + break; // No code needs to be emitted. |
| + } else if (rs.is(zero_reg)) { |
| + scratch = GetRtAsRegisterHelper(rt, scratch); |
| + offset = GetOffset(offset, L, 16); |
| + bltzc(scratch, offset); |
| + } else if (IsZero(rt)) { |
| + offset = GetOffset(offset, L, 16); |
| + bgtzc(rs, offset); |
| + } else { |
| + scratch = GetRtAsRegisterHelper(rt, scratch); |
| + DCHECK(!rs.is(scratch)); |
| + offset = GetOffset(offset, L, 16); |
| + bltc(scratch, rs, offset); |
| + } |
| + break; |
| + case greater_equal: |
| + // rs >= rt |
| + if (rs.code() == rt.rm_.reg_code) { |
| + offset = GetOffset(offset, L, 26); |
| + bc(offset); |
| + } else if (rs.is(zero_reg)) { |
| + scratch = GetRtAsRegisterHelper(rt, scratch); |
| + offset = GetOffset(offset, L, 16); |
| + blezc(scratch, offset); |
| + } else if (IsZero(rt)) { |
| + offset = GetOffset(offset, L, 16); |
| + bgezc(rs, offset); |
| + } else { |
| + scratch = GetRtAsRegisterHelper(rt, scratch); |
| + DCHECK(!rs.is(scratch)); |
| + offset = GetOffset(offset, L, 16); |
| + bgec(rs, scratch, offset); |
| + } |
| + break; |
| + case less: |
| + // rs < rt |
| + if (rs.code() == rt.rm_.reg_code) { |
| + break; // No code needs to be emitted. |
| + } else if (rs.is(zero_reg)) { |
| + scratch = GetRtAsRegisterHelper(rt, scratch); |
| + offset = GetOffset(offset, L, 16); |
| + bgtzc(scratch, offset); |
| + } else if (IsZero(rt)) { |
| + offset = GetOffset(offset, L, 16); |
| + bltzc(rs, offset); |
| + } else { |
| + scratch = GetRtAsRegisterHelper(rt, scratch); |
| + DCHECK(!rs.is(scratch)); |
| + offset = GetOffset(offset, L, 16); |
| + bltc(rs, scratch, offset); |
| + } |
| + break; |
| + case less_equal: |
| + // rs <= rt |
| + if (rs.code() == rt.rm_.reg_code) { |
| + offset = GetOffset(offset, L, 26); |
| + bc(offset); |
| + } else if (rs.is(zero_reg)) { |
| + scratch = GetRtAsRegisterHelper(rt, scratch); |
| + offset = GetOffset(offset, L, 16); |
| + bgezc(scratch, offset); |
| + } else if (IsZero(rt)) { |
| + offset = GetOffset(offset, L, 16); |
| + blezc(rs, offset); |
| + } else { |
| + scratch = GetRtAsRegisterHelper(rt, scratch); |
| + DCHECK(!rs.is(scratch)); |
| + offset = GetOffset(offset, L, 21); |
| + bgec(scratch, rs, offset); |
| + } |
| + break; |
| + |
| + // Unsigned comparison. |
| + case Ugreater: |
| + // rs > rt |
| + if (rs.code() == rt.rm_.reg_code) { |
| + break; // No code needs to be emitted. |
| + } else if (rs.is(zero_reg)) { |
| + scratch = GetRtAsRegisterHelper(rt, scratch); |
| + offset = GetOffset(offset, L, 16); |
| + bnezc(scratch, offset); |
| + } else if (IsZero(rt)) { |
| + offset = GetOffset(offset, L, 21); |
| + bnezc(rs, offset); |
| + } else { |
| + scratch = GetRtAsRegisterHelper(rt, scratch); |
| + DCHECK(!rs.is(scratch)); |
| + offset = GetOffset(offset, L, 16); |
| + bltuc(scratch, rs, offset); |
| + } |
| + break; |
| + case Ugreater_equal: |
| + // rs >= rt |
| + if (rs.code() == rt.rm_.reg_code) { |
| + offset = GetOffset(offset, L, 26); |
| + bc(offset); |
| + } else if (rs.is(zero_reg)) { |
| + scratch = GetRtAsRegisterHelper(rt, scratch); |
| + offset = GetOffset(offset, L, 21); |
| + beqzc(scratch, offset); |
| + } else if (IsZero(rt)) { |
| + offset = GetOffset(offset, L, 26); |
| + bc(offset); |
| + } else { |
| + scratch = GetRtAsRegisterHelper(rt, scratch); |
| + DCHECK(!rs.is(scratch)); |
| + offset = GetOffset(offset, L, 16); |
| + bgeuc(rs, scratch, offset); |
| + } |
| + break; |
| + case Uless: |
| + // rs < rt |
| + if (rs.code() == rt.rm_.reg_code) { |
| + break; // No code needs to be emitted. |
| + } else if (rs.is(zero_reg)) { |
| + scratch = GetRtAsRegisterHelper(rt, scratch); |
| + offset = GetOffset(offset, L, 21); |
| + bnezc(scratch, offset); |
| + } else if (IsZero(rt)) { |
| + break; // No code needs to be emitted. |
| + } else { |
| + scratch = GetRtAsRegisterHelper(rt, scratch); |
| + DCHECK(!rs.is(scratch)); |
| + offset = GetOffset(offset, L, 16); |
| + bltuc(rs, scratch, offset); |
| + } |
| + break; |
| + case Uless_equal: |
| + // rs <= rt |
| + if (rs.code() == rt.rm_.reg_code) { |
| + offset = GetOffset(offset, L, 26); |
| + bc(offset); |
| + } else if (rs.is(zero_reg)) { |
| + scratch = GetRtAsRegisterHelper(rt, scratch); |
| + offset = GetOffset(offset, L, 26); |
| + bc(offset); |
| + } else if (IsZero(rt)) { |
| + offset = GetOffset(offset, L, 21); |
| + beqzc(rs, offset); |
| + } else { |
| + scratch = GetRtAsRegisterHelper(rt, scratch); |
| + DCHECK(!rs.is(scratch)); |
| + offset = GetOffset(offset, L, 16); |
| + bgeuc(scratch, rs, offset); |
| + } |
| + break; |
| + default: |
| + UNREACHABLE(); |
| + } |
| +} |
| + |
| + |
| +void MacroAssembler::BranchShortHelper(int16_t offset, Label* L, Condition cond, |
| + Register rs, const Operand& rt, |
| + BranchDelaySlot bdslot) { |
| + Register scratch = at; |
| + |
| + // Be careful to always use shifted_branch_offset only just before the |
| + // branch instruction, as the location will be remember for patching the |
| + // target. |
| + BlockTrampolinePoolScope block_trampoline_pool(this); |
| + switch (cond) { |
| + case cc_always: |
| + offset = GetOffset(offset, L, 16); |
| + b(offset); |
| + break; |
| + case eq: |
| + if (IsZero(rt)) { |
| + offset = GetOffset(offset, L, 16); |
| + beq(rs, zero_reg, offset); |
| + } else { |
| + // We don't want any other register but scratch clobbered. |
| + scratch = GetRtAsRegisterHelper(rt, scratch); |
| + offset = GetOffset(offset, L, 16); |
| + beq(rs, scratch, offset); |
| + } |
| + break; |
| + case ne: |
| + if (IsZero(rt)) { |
| + offset = GetOffset(offset, L, 16); |
| + bne(rs, zero_reg, offset); |
| + } else { |
| + // We don't want any other register but scratch clobbered. |
| + scratch = GetRtAsRegisterHelper(rt, scratch); |
| + offset = GetOffset(offset, L, 16); |
| + bne(rs, scratch, offset); |
| + } |
| + break; |
| + |
| + // Signed comparison. |
| + case greater: |
| + if (IsZero(rt)) { |
| + offset = GetOffset(offset, L, 16); |
| + bgtz(rs, offset); |
| + } else { |
| + Slt(scratch, GetRtAsRegisterHelper(rt, scratch), rs); |
| + offset = GetOffset(offset, L, 16); |
| + bne(scratch, zero_reg, offset); |
| + } |
| + break; |
| + case greater_equal: |
| + if (IsZero(rt)) { |
| + offset = GetOffset(offset, L, 16); |
| + bgez(rs, offset); |
| + } else { |
| + Slt(scratch, rs, rt); |
| + offset = GetOffset(offset, L, 16); |
| + beq(scratch, zero_reg, offset); |
| + } |
| + break; |
| + case less: |
| + if (IsZero(rt)) { |
| + offset = GetOffset(offset, L, 16); |
| + bltz(rs, offset); |
| + } else { |
| + Slt(scratch, rs, rt); |
| + offset = GetOffset(offset, L, 16); |
| + bne(scratch, zero_reg, offset); |
| + } |
| + break; |
| + case less_equal: |
| + if (IsZero(rt)) { |
| + offset = GetOffset(offset, L, 16); |
| + blez(rs, offset); |
| + } else { |
| + Slt(scratch, GetRtAsRegisterHelper(rt, scratch), rs); |
| + offset = GetOffset(offset, L, 16); |
| + beq(scratch, zero_reg, offset); |
| + } |
| + break; |
| + |
| + // Unsigned comparison. |
| + case Ugreater: |
| + if (IsZero(rt)) { |
| + offset = GetOffset(offset, L, 16); |
| + bne(rs, zero_reg, offset); |
| + } else { |
| + Sltu(scratch, GetRtAsRegisterHelper(rt, scratch), rs); |
| + offset = GetOffset(offset, L, 16); |
| + bne(scratch, zero_reg, offset); |
| + } |
| + break; |
| + case Ugreater_equal: |
| + if (IsZero(rt)) { |
| + offset = GetOffset(offset, L, 16); |
| + b(offset); |
| + } else { |
| + Sltu(scratch, rs, rt); |
| + offset = GetOffset(offset, L, 16); |
| + beq(scratch, zero_reg, offset); |
| + } |
| + break; |
| + case Uless: |
| + if (IsZero(rt)) { |
| + return; // No code needs to be emitted. |
| + } else { |
| + Sltu(scratch, rs, rt); |
| + offset = GetOffset(offset, L, 16); |
| + bne(scratch, zero_reg, offset); |
| + } |
| + break; |
| + case Uless_equal: |
| + if (IsZero(rt)) { |
| + offset = GetOffset(offset, L, 16); |
| + beq(rs, zero_reg, offset); |
| + } else { |
| + Sltu(scratch, GetRtAsRegisterHelper(rt, scratch), rs); |
| + offset = GetOffset(offset, L, 16); |
| + beq(scratch, zero_reg, offset); |
| + } |
| + break; |
| + default: |
| + UNREACHABLE(); |
| + } |
| // Emit a nop in the branch delay slot if required. |
| if (bdslot == PROTECT) |
| @@ -2262,294 +2403,40 @@ void MacroAssembler::BranchShort(Label* L, BranchDelaySlot bdslot) { |
| } |
| +void MacroAssembler::BranchShort(int32_t offset, Condition cond, Register rs, |
| + const Operand& rt, BranchDelaySlot bdslot) { |
| + BRANCH_ARGS_CHECK(cond, rs, rt); |
| + |
| + if (IsMipsArchVariant(kMips32r6) && bdslot == PROTECT) { |
| + DCHECK(is_int26(offset)); |
| + BranchShortHelperR6(offset, nullptr, cond, rs, rt); |
| + } else { |
| + DCHECK(is_int16(offset)); |
| + BranchShortHelper(offset, nullptr, cond, rs, rt, bdslot); |
| + } |
| +} |
| + |
| + |
| void MacroAssembler::BranchShort(Label* L, Condition cond, Register rs, |
| const Operand& rt, |
| BranchDelaySlot bdslot) { |
| BRANCH_ARGS_CHECK(cond, rs, rt); |
| - int32_t offset = 0; |
| - Register r2 = no_reg; |
| - Register scratch = at; |
| - if (rt.is_reg()) { |
| - BlockTrampolinePoolScope block_trampoline_pool(this); |
| - r2 = rt.rm_; |
| - // Be careful to always use shifted_branch_offset only just before the |
| - // branch instruction, as the location will be remember for patching the |
| - // target. |
| - switch (cond) { |
| - case cc_always: |
| - offset = shifted_branch_offset(L, false); |
| - b(offset); |
| - break; |
| - case eq: |
| - offset = shifted_branch_offset(L, false); |
| - beq(rs, r2, offset); |
| - break; |
| - case ne: |
| - offset = shifted_branch_offset(L, false); |
| - bne(rs, r2, offset); |
| - break; |
| - // Signed comparison. |
| - case greater: |
| - if (r2.is(zero_reg)) { |
| - offset = shifted_branch_offset(L, false); |
| - bgtz(rs, offset); |
| - } else { |
| - slt(scratch, r2, rs); |
| - offset = shifted_branch_offset(L, false); |
| - bne(scratch, zero_reg, offset); |
| - } |
| - break; |
| - case greater_equal: |
| - if (r2.is(zero_reg)) { |
| - offset = shifted_branch_offset(L, false); |
| - bgez(rs, offset); |
| - } else { |
| - slt(scratch, rs, r2); |
| - offset = shifted_branch_offset(L, false); |
| - beq(scratch, zero_reg, offset); |
| - } |
| - break; |
| - case less: |
| - if (r2.is(zero_reg)) { |
| - offset = shifted_branch_offset(L, false); |
| - bltz(rs, offset); |
| - } else { |
| - slt(scratch, rs, r2); |
| - offset = shifted_branch_offset(L, false); |
| - bne(scratch, zero_reg, offset); |
| - } |
| - break; |
| - case less_equal: |
| - if (r2.is(zero_reg)) { |
| - offset = shifted_branch_offset(L, false); |
| - blez(rs, offset); |
| - } else { |
| - slt(scratch, r2, rs); |
| - offset = shifted_branch_offset(L, false); |
| - beq(scratch, zero_reg, offset); |
| - } |
| - break; |
| - // Unsigned comparison. |
| - case Ugreater: |
| - if (r2.is(zero_reg)) { |
| - offset = shifted_branch_offset(L, false); |
| - bne(rs, zero_reg, offset); |
| - } else { |
| - sltu(scratch, r2, rs); |
| - offset = shifted_branch_offset(L, false); |
| - bne(scratch, zero_reg, offset); |
| - } |
| - break; |
| - case Ugreater_equal: |
| - if (r2.is(zero_reg)) { |
| - offset = shifted_branch_offset(L, false); |
| - b(offset); |
| - } else { |
| - sltu(scratch, rs, r2); |
| - offset = shifted_branch_offset(L, false); |
| - beq(scratch, zero_reg, offset); |
| - } |
| - break; |
| - case Uless: |
| - if (r2.is(zero_reg)) { |
| - // No code needs to be emitted. |
| - return; |
| - } else { |
| - sltu(scratch, rs, r2); |
| - offset = shifted_branch_offset(L, false); |
| - bne(scratch, zero_reg, offset); |
| - } |
| - break; |
| - case Uless_equal: |
| - if (r2.is(zero_reg)) { |
| - offset = shifted_branch_offset(L, false); |
| - beq(rs, zero_reg, offset); |
| - } else { |
| - sltu(scratch, r2, rs); |
| - offset = shifted_branch_offset(L, false); |
| - beq(scratch, zero_reg, offset); |
| - } |
| - break; |
| - default: |
| - UNREACHABLE(); |
| - } |
| + if (IsMipsArchVariant(kMips32r6) && bdslot == PROTECT) { |
| + BranchShortHelperR6(0, L, cond, rs, rt); |
| } else { |
| - // Be careful to always use shifted_branch_offset only just before the |
| - // branch instruction, as the location will be remember for patching the |
| - // target. |
| - BlockTrampolinePoolScope block_trampoline_pool(this); |
| - switch (cond) { |
| - case cc_always: |
| - offset = shifted_branch_offset(L, false); |
| - b(offset); |
| - break; |
| - case eq: |
| - if (rt.imm32_ == 0) { |
| - offset = shifted_branch_offset(L, false); |
| - beq(rs, zero_reg, offset); |
| - } else { |
| - DCHECK(!scratch.is(rs)); |
| - r2 = scratch; |
| - li(r2, rt); |
| - offset = shifted_branch_offset(L, false); |
| - beq(rs, r2, offset); |
| - } |
| - break; |
| - case ne: |
| - if (rt.imm32_ == 0) { |
| - offset = shifted_branch_offset(L, false); |
| - bne(rs, zero_reg, offset); |
| - } else { |
| - DCHECK(!scratch.is(rs)); |
| - r2 = scratch; |
| - li(r2, rt); |
| - offset = shifted_branch_offset(L, false); |
| - bne(rs, r2, offset); |
| - } |
| - break; |
| - // Signed comparison. |
| - case greater: |
| - if (rt.imm32_ == 0) { |
| - offset = shifted_branch_offset(L, false); |
| - bgtz(rs, offset); |
| - } else { |
| - DCHECK(!scratch.is(rs)); |
| - r2 = scratch; |
| - li(r2, rt); |
| - slt(scratch, r2, rs); |
| - offset = shifted_branch_offset(L, false); |
| - bne(scratch, zero_reg, offset); |
| - } |
| - break; |
| - case greater_equal: |
| - if (rt.imm32_ == 0) { |
| - offset = shifted_branch_offset(L, false); |
| - bgez(rs, offset); |
| - } else if (is_int16(rt.imm32_)) { |
| - slti(scratch, rs, rt.imm32_); |
| - offset = shifted_branch_offset(L, false); |
| - beq(scratch, zero_reg, offset); |
| - } else { |
| - DCHECK(!scratch.is(rs)); |
| - r2 = scratch; |
| - li(r2, rt); |
| - slt(scratch, rs, r2); |
| - offset = shifted_branch_offset(L, false); |
| - beq(scratch, zero_reg, offset); |
| - } |
| - break; |
| - case less: |
| - if (rt.imm32_ == 0) { |
| - offset = shifted_branch_offset(L, false); |
| - bltz(rs, offset); |
| - } else if (is_int16(rt.imm32_)) { |
| - slti(scratch, rs, rt.imm32_); |
| - offset = shifted_branch_offset(L, false); |
| - bne(scratch, zero_reg, offset); |
| - } else { |
| - DCHECK(!scratch.is(rs)); |
| - r2 = scratch; |
| - li(r2, rt); |
| - slt(scratch, rs, r2); |
| - offset = shifted_branch_offset(L, false); |
| - bne(scratch, zero_reg, offset); |
| - } |
| - break; |
| - case less_equal: |
| - if (rt.imm32_ == 0) { |
| - offset = shifted_branch_offset(L, false); |
| - blez(rs, offset); |
| - } else { |
| - DCHECK(!scratch.is(rs)); |
| - r2 = scratch; |
| - li(r2, rt); |
| - slt(scratch, r2, rs); |
| - offset = shifted_branch_offset(L, false); |
| - beq(scratch, zero_reg, offset); |
| - } |
| - break; |
| - // Unsigned comparison. |
| - case Ugreater: |
| - if (rt.imm32_ == 0) { |
| - offset = shifted_branch_offset(L, false); |
| - bne(rs, zero_reg, offset); |
| - } else { |
| - DCHECK(!scratch.is(rs)); |
| - r2 = scratch; |
| - li(r2, rt); |
| - sltu(scratch, r2, rs); |
| - offset = shifted_branch_offset(L, false); |
| - bne(scratch, zero_reg, offset); |
| - } |
| - break; |
| - case Ugreater_equal: |
| - if (rt.imm32_ == 0) { |
| - offset = shifted_branch_offset(L, false); |
| - b(offset); |
| - } else if (is_int16(rt.imm32_)) { |
| - sltiu(scratch, rs, rt.imm32_); |
| - offset = shifted_branch_offset(L, false); |
| - beq(scratch, zero_reg, offset); |
| - } else { |
| - DCHECK(!scratch.is(rs)); |
| - r2 = scratch; |
| - li(r2, rt); |
| - sltu(scratch, rs, r2); |
| - offset = shifted_branch_offset(L, false); |
| - beq(scratch, zero_reg, offset); |
| - } |
| - break; |
| - case Uless: |
| - if (rt.imm32_ == 0) { |
| - // No code needs to be emitted. |
| - return; |
| - } else if (is_int16(rt.imm32_)) { |
| - sltiu(scratch, rs, rt.imm32_); |
| - offset = shifted_branch_offset(L, false); |
| - bne(scratch, zero_reg, offset); |
| - } else { |
| - DCHECK(!scratch.is(rs)); |
| - r2 = scratch; |
| - li(r2, rt); |
| - sltu(scratch, rs, r2); |
| - offset = shifted_branch_offset(L, false); |
| - bne(scratch, zero_reg, offset); |
| - } |
| - break; |
| - case Uless_equal: |
| - if (rt.imm32_ == 0) { |
| - offset = shifted_branch_offset(L, false); |
| - beq(rs, zero_reg, offset); |
| - } else { |
| - DCHECK(!scratch.is(rs)); |
| - r2 = scratch; |
| - li(r2, rt); |
| - sltu(scratch, r2, rs); |
| - offset = shifted_branch_offset(L, false); |
| - beq(scratch, zero_reg, offset); |
| - } |
| - break; |
| - default: |
| - UNREACHABLE(); |
| - } |
| + BranchShortHelper(0, L, cond, rs, rt, bdslot); |
| } |
| - // Check that offset could actually hold on an int16_t. |
| - DCHECK(is_int16(offset)); |
| - // Emit a nop in the branch delay slot if required. |
| - if (bdslot == PROTECT) |
| - nop(); |
| } |
| -void MacroAssembler::BranchAndLink(int16_t offset, BranchDelaySlot bdslot) { |
| +void MacroAssembler::BranchAndLink(int32_t offset, BranchDelaySlot bdslot) { |
| BranchAndLinkShort(offset, bdslot); |
| } |
| -void MacroAssembler::BranchAndLink(int16_t offset, Condition cond, Register rs, |
| - const Operand& rt, |
| - BranchDelaySlot bdslot) { |
| +void MacroAssembler::BranchAndLink(int32_t offset, Condition cond, Register rs, |
| + const Operand& rt, BranchDelaySlot bdslot) { |
| BranchAndLinkShort(offset, cond, rs, rt, bdslot); |
| } |
| @@ -2598,11 +2485,23 @@ void MacroAssembler::BranchAndLink(Label* L, Condition cond, Register rs, |
| } |
| -// We need to use a bgezal or bltzal, but they can't be used directly with the |
| -// slt instructions. We could use sub or add instead but we would miss overflow |
| -// cases, so we keep slt and add an intermediate third instruction. |
| -void MacroAssembler::BranchAndLinkShort(int16_t offset, |
| - BranchDelaySlot bdslot) { |
| +Register MacroAssembler::GetRtAsRegisterHelper(const Operand& rt, |
| + Register scratch) { |
| + Register r2 = no_reg; |
| + if (rt.is_reg()) { |
| + r2 = rt.rm_; |
| + } else { |
| + r2 = scratch; |
| + li(r2, rt); |
| + } |
| + |
| + return r2; |
| +} |
| + |
| + |
| +void MacroAssembler::BranchAndLinkShortHelper(int16_t offset, Label* L, |
| + BranchDelaySlot bdslot) { |
| + offset = GetOffset(offset, L, 16); |
|
ivica.bogosavljevic
2015/10/15 11:49:08
16 -> constant. it applies elsewhere as well
balazs.kilvady
2015/10/30 21:11:14
Done.
|
| bal(offset); |
| // Emit a nop in the branch delay slot if required. |
| @@ -2611,174 +2510,242 @@ void MacroAssembler::BranchAndLinkShort(int16_t offset, |
| } |
| -void MacroAssembler::BranchAndLinkShort(int16_t offset, Condition cond, |
| - Register rs, const Operand& rt, |
| - BranchDelaySlot bdslot) { |
| - BRANCH_ARGS_CHECK(cond, rs, rt); |
| - Register r2 = no_reg; |
| - Register scratch = at; |
| +void MacroAssembler::BranchAndLinkShortHelperR6(int32_t offset, Label* L) { |
| + offset = GetOffset(offset, L, 26); |
| + balc(offset); |
| +} |
| - if (rt.is_reg()) { |
| - r2 = rt.rm_; |
| - } else if (cond != cc_always) { |
| - r2 = scratch; |
| - li(r2, rt); |
| - } |
| - if (!IsMipsArchVariant(kMips32r6)) { |
| - BlockTrampolinePoolScope block_trampoline_pool(this); |
| - switch (cond) { |
| - case cc_always: |
| - bal(offset); |
| - break; |
| - case eq: |
| - bne(rs, r2, 2); |
| - nop(); |
| - bal(offset); |
| - break; |
| - case ne: |
| - beq(rs, r2, 2); |
| - nop(); |
| - bal(offset); |
| - break; |
| - |
| - // Signed comparison. |
| - case greater: |
| - slt(scratch, r2, rs); |
| - addiu(scratch, scratch, -1); |
| - bgezal(scratch, offset); |
| - break; |
| - case greater_equal: |
| - slt(scratch, rs, r2); |
| - addiu(scratch, scratch, -1); |
| - bltzal(scratch, offset); |
| - break; |
| - case less: |
| - slt(scratch, rs, r2); |
| - addiu(scratch, scratch, -1); |
| - bgezal(scratch, offset); |
| - break; |
| - case less_equal: |
| - slt(scratch, r2, rs); |
| - addiu(scratch, scratch, -1); |
| - bltzal(scratch, offset); |
| - break; |
| - |
| - // Unsigned comparison. |
| - case Ugreater: |
| - sltu(scratch, r2, rs); |
| - addiu(scratch, scratch, -1); |
| - bgezal(scratch, offset); |
| - break; |
| - case Ugreater_equal: |
| - sltu(scratch, rs, r2); |
| - addiu(scratch, scratch, -1); |
| - bltzal(scratch, offset); |
| - break; |
| - case Uless: |
| - sltu(scratch, rs, r2); |
| - addiu(scratch, scratch, -1); |
| - bgezal(scratch, offset); |
| - break; |
| - case Uless_equal: |
| - sltu(scratch, r2, rs); |
| - addiu(scratch, scratch, -1); |
| - bltzal(scratch, offset); |
| - break; |
| - |
| - default: |
| - UNREACHABLE(); |
| - } |
| +void MacroAssembler::BranchAndLinkShort(int32_t offset, |
| + BranchDelaySlot bdslot) { |
| + if (IsMipsArchVariant(kMips32r6) && bdslot == PROTECT) { |
| + DCHECK(is_int26(offset)); |
| + BranchAndLinkShortHelperR6(offset, nullptr); |
| } else { |
| - BlockTrampolinePoolScope block_trampoline_pool(this); |
| - switch (cond) { |
| - case cc_always: |
| - bal(offset); |
| - break; |
| - case eq: |
| - bne(rs, r2, 2); |
| - nop(); |
| - bal(offset); |
| - break; |
| - case ne: |
| - beq(rs, r2, 2); |
| - nop(); |
| - bal(offset); |
| - break; |
| - |
| - // Signed comparison. |
| - case greater: |
| - // rs > rt |
| - slt(scratch, r2, rs); |
| - beq(scratch, zero_reg, 2); |
| - nop(); |
| - bal(offset); |
| - break; |
| - case greater_equal: |
| - // rs >= rt |
| - slt(scratch, rs, r2); |
| - bne(scratch, zero_reg, 2); |
| - nop(); |
| - bal(offset); |
| - break; |
| - case less: |
| - // rs < r2 |
| - slt(scratch, rs, r2); |
| - bne(scratch, zero_reg, 2); |
| - nop(); |
| - bal(offset); |
| - break; |
| - case less_equal: |
| - // rs <= r2 |
| - slt(scratch, r2, rs); |
| - bne(scratch, zero_reg, 2); |
| - nop(); |
| - bal(offset); |
| - break; |
| + DCHECK(is_int16(offset)); |
| + BranchAndLinkShortHelper(offset, nullptr, bdslot); |
| + } |
| +} |
| - // Unsigned comparison. |
| - case Ugreater: |
| - // rs > rt |
| - sltu(scratch, r2, rs); |
| - beq(scratch, zero_reg, 2); |
| - nop(); |
| - bal(offset); |
| - break; |
| - case Ugreater_equal: |
| - // rs >= rt |
| - sltu(scratch, rs, r2); |
| - bne(scratch, zero_reg, 2); |
| - nop(); |
| - bal(offset); |
| - break; |
| - case Uless: |
| - // rs < r2 |
| - sltu(scratch, rs, r2); |
| - bne(scratch, zero_reg, 2); |
| - nop(); |
| - bal(offset); |
| - break; |
| - case Uless_equal: |
| - // rs <= r2 |
| - sltu(scratch, r2, rs); |
| - bne(scratch, zero_reg, 2); |
| - nop(); |
| - bal(offset); |
| - break; |
| - default: |
| - UNREACHABLE(); |
| - } |
| +void MacroAssembler::BranchAndLinkShort(Label* L, BranchDelaySlot bdslot) { |
| + if (IsMipsArchVariant(kMips32r6) && bdslot == PROTECT) { |
| + BranchAndLinkShortHelperR6(0, L); |
| + } else { |
| + BranchAndLinkShortHelper(0, L, bdslot); |
| } |
| +} |
| - // Emit a nop in the branch delay slot if required. |
| - if (bdslot == PROTECT) |
| - nop(); |
| + |
| +void MacroAssembler::BranchAndLinkShortHelperR6(int32_t offset, Label* L, |
| + Condition cond, Register rs, |
| + const Operand& rt) { |
| + Register scratch = rs.is(at) ? t8 : at; |
| + |
| + BlockTrampolinePoolScope block_trampoline_pool(this); |
| + DCHECK((cond == cc_always && is_int26(offset)) || is_int16(offset)); |
| + switch (cond) { |
| + case cc_always: |
| + offset = GetOffset(offset, L, 26); |
| + balc(offset); |
| + break; |
| + case eq: |
| + Subu(scratch, rs, rt); |
| + offset = GetOffset(offset, L, 16); |
| + beqzalc(scratch, offset); |
| + break; |
| + case ne: |
| + Subu(scratch, rs, rt); |
| + offset = GetOffset(offset, L, 16); |
| + bnezalc(scratch, offset); |
| + break; |
| + |
| + // Signed comparison. |
| + case greater: |
| + // rs > rt |
| + if (rs.code() == rt.rm_.reg_code) { |
| + break; // No code needs to be emitted. |
| + } else if (rs.is(zero_reg)) { |
| + scratch = GetRtAsRegisterHelper(rt, scratch); |
| + offset = GetOffset(offset, L, 16); |
| + bltzalc(scratch, offset); |
| + } else if (IsZero(rt)) { |
| + offset = GetOffset(offset, L, 16); |
| + bgtzalc(rs, offset); |
| + } else { |
| + Slt(scratch, GetRtAsRegisterHelper(rt, scratch), rs); |
| + offset = GetOffset(offset, L, 16); |
| + bnezalc(scratch, offset); |
| + } |
| + break; |
| + case greater_equal: |
| + // rs >= rt |
| + if (rs.code() == rt.rm_.reg_code) { |
| + offset = GetOffset(offset, L, 26); |
| + balc(offset); |
| + } else if (rs.is(zero_reg)) { |
| + scratch = GetRtAsRegisterHelper(rt, scratch); |
| + offset = GetOffset(offset, L, 16); |
| + blezalc(scratch, offset); |
| + } else if (IsZero(rt)) { |
| + offset = GetOffset(offset, L, 16); |
| + bgezalc(rs, offset); |
| + } else { |
| + Slt(scratch, rs, rt); |
| + offset = GetOffset(offset, L, 16); |
| + beqzalc(scratch, offset); |
| + } |
| + break; |
| + case less: |
| + // rs < rt |
| + if (rs.code() == rt.rm_.reg_code) { |
| + break; // No code needs to be emitted. |
| + } else if (rs.is(zero_reg)) { |
| + scratch = GetRtAsRegisterHelper(rt, scratch); |
| + offset = GetOffset(offset, L, 16); |
| + bgtzalc(scratch, offset); |
| + } else if (IsZero(rt)) { |
| + offset = GetOffset(offset, L, 16); |
| + bltzalc(rs, offset); |
| + } else { |
| + Slt(scratch, rs, rt); |
| + offset = GetOffset(offset, L, 16); |
| + bnezalc(scratch, offset); |
| + } |
| + break; |
| + case less_equal: |
| + // rs <= r2 |
| + if (rs.code() == rt.rm_.reg_code) { |
| + offset = GetOffset(offset, L, 26); |
| + balc(offset); |
| + } else if (rs.is(zero_reg)) { |
| + scratch = GetRtAsRegisterHelper(rt, scratch); |
| + offset = GetOffset(offset, L, 16); |
| + bgezalc(scratch, offset); |
| + } else if (IsZero(rt)) { |
| + offset = GetOffset(offset, L, 16); |
| + blezalc(rs, offset); |
| + } else { |
| + Slt(scratch, GetRtAsRegisterHelper(rt, scratch), rs); |
| + offset = GetOffset(offset, L, 16); |
| + beqzalc(scratch, offset); |
| + } |
| + break; |
| + |
| + |
| + // Unsigned comparison. |
| + case Ugreater: |
| + // rs > r2 |
| + Sltu(scratch, GetRtAsRegisterHelper(rt, scratch), rs); |
| + offset = GetOffset(offset, L, 16); |
| + bnezalc(scratch, offset); |
| + break; |
| + case Ugreater_equal: |
| + // rs >= r2 |
| + Sltu(scratch, rs, rt); |
| + offset = GetOffset(offset, L, 16); |
| + beqzalc(scratch, offset); |
| + break; |
| + case Uless: |
| + // rs < r2 |
| + Sltu(scratch, rs, rt); |
| + offset = GetOffset(offset, L, 16); |
| + bnezalc(scratch, offset); |
| + break; |
| + case Uless_equal: |
| + // rs <= r2 |
| + Sltu(scratch, GetRtAsRegisterHelper(rt, scratch), rs); |
| + offset = GetOffset(offset, L, 16); |
| + beqzalc(scratch, offset); |
| + break; |
| + default: |
| + UNREACHABLE(); |
| + } |
| } |
| -void MacroAssembler::BranchAndLinkShort(Label* L, BranchDelaySlot bdslot) { |
| - bal(shifted_branch_offset(L, false)); |
| +// Pre r6 we need to use a bgezal or bltzal, but they can't be used directly |
| +// with the slt instructions. We could use sub or add instead but we would miss |
| +// overflow cases, so we keep slt and add an intermediate third instruction. |
| +void MacroAssembler::BranchAndLinkShortHelper(int16_t offset, Label* L, |
| + Condition cond, Register rs, |
| + const Operand& rt, |
| + BranchDelaySlot bdslot) { |
| + Register scratch = t8; |
| + BlockTrampolinePoolScope block_trampoline_pool(this); |
| + switch (cond) { |
| + case cc_always: |
| + offset = GetOffset(offset, L, 16); |
| + bal(offset); |
| + break; |
| + case eq: |
| + bne(rs, GetRtAsRegisterHelper(rt, scratch), 2); |
| + nop(); |
| + offset = GetOffset(offset, L, 16); |
| + bal(offset); |
| + break; |
| + case ne: |
| + beq(rs, GetRtAsRegisterHelper(rt, scratch), 2); |
| + nop(); |
| + offset = GetOffset(offset, L, 16); |
| + bal(offset); |
| + break; |
| + |
| + // Signed comparison. |
| + case greater: |
| + Slt(scratch, GetRtAsRegisterHelper(rt, scratch), rs); |
| + addiu(scratch, scratch, -1); |
| + offset = GetOffset(offset, L, 16); |
| + bgezal(scratch, offset); |
| + break; |
| + case greater_equal: |
| + Slt(scratch, rs, rt); |
| + addiu(scratch, scratch, -1); |
| + offset = GetOffset(offset, L, 16); |
| + bltzal(scratch, offset); |
| + break; |
| + case less: |
| + Slt(scratch, rs, rt); |
| + addiu(scratch, scratch, -1); |
| + offset = GetOffset(offset, L, 16); |
| + bgezal(scratch, offset); |
| + break; |
| + case less_equal: |
| + Slt(scratch, GetRtAsRegisterHelper(rt, scratch), rs); |
| + addiu(scratch, scratch, -1); |
| + offset = GetOffset(offset, L, 16); |
| + bltzal(scratch, offset); |
| + break; |
| + |
| + // Unsigned comparison. |
| + case Ugreater: |
| + Sltu(scratch, GetRtAsRegisterHelper(rt, scratch), rs); |
| + addiu(scratch, scratch, -1); |
| + offset = GetOffset(offset, L, 16); |
| + bgezal(scratch, offset); |
| + break; |
| + case Ugreater_equal: |
| + Sltu(scratch, rs, rt); |
| + addiu(scratch, scratch, -1); |
| + offset = GetOffset(offset, L, 16); |
| + bltzal(scratch, offset); |
| + break; |
| + case Uless: |
| + Sltu(scratch, rs, rt); |
| + addiu(scratch, scratch, -1); |
| + offset = GetOffset(offset, L, 16); |
| + bgezal(scratch, offset); |
| + break; |
| + case Uless_equal: |
| + Sltu(scratch, GetRtAsRegisterHelper(rt, scratch), rs); |
| + addiu(scratch, scratch, -1); |
| + offset = GetOffset(offset, L, 16); |
| + bltzal(scratch, offset); |
| + break; |
| + |
| + default: |
| + UNREACHABLE(); |
| + } |
| // Emit a nop in the branch delay slot if required. |
| if (bdslot == PROTECT) |
| @@ -2786,196 +2753,31 @@ void MacroAssembler::BranchAndLinkShort(Label* L, BranchDelaySlot bdslot) { |
| } |
| -void MacroAssembler::BranchAndLinkShort(Label* L, Condition cond, Register rs, |
| - const Operand& rt, |
| +void MacroAssembler::BranchAndLinkShort(int32_t offset, Condition cond, |
| + Register rs, const Operand& rt, |
| BranchDelaySlot bdslot) { |
| BRANCH_ARGS_CHECK(cond, rs, rt); |
| - int32_t offset = 0; |
| - Register r2 = no_reg; |
| - Register scratch = at; |
| - if (rt.is_reg()) { |
| - r2 = rt.rm_; |
| - } else if (cond != cc_always) { |
| - r2 = scratch; |
| - li(r2, rt); |
| - } |
| - |
| - if (!IsMipsArchVariant(kMips32r6)) { |
| - BlockTrampolinePoolScope block_trampoline_pool(this); |
| - switch (cond) { |
| - case cc_always: |
| - offset = shifted_branch_offset(L, false); |
| - bal(offset); |
| - break; |
| - case eq: |
| - bne(rs, r2, 2); |
| - nop(); |
| - offset = shifted_branch_offset(L, false); |
| - bal(offset); |
| - break; |
| - case ne: |
| - beq(rs, r2, 2); |
| - nop(); |
| - offset = shifted_branch_offset(L, false); |
| - bal(offset); |
| - break; |
| - |
| - // Signed comparison. |
| - case greater: |
| - slt(scratch, r2, rs); |
| - addiu(scratch, scratch, -1); |
| - offset = shifted_branch_offset(L, false); |
| - bgezal(scratch, offset); |
| - break; |
| - case greater_equal: |
| - slt(scratch, rs, r2); |
| - addiu(scratch, scratch, -1); |
| - offset = shifted_branch_offset(L, false); |
| - bltzal(scratch, offset); |
| - break; |
| - case less: |
| - slt(scratch, rs, r2); |
| - addiu(scratch, scratch, -1); |
| - offset = shifted_branch_offset(L, false); |
| - bgezal(scratch, offset); |
| - break; |
| - case less_equal: |
| - slt(scratch, r2, rs); |
| - addiu(scratch, scratch, -1); |
| - offset = shifted_branch_offset(L, false); |
| - bltzal(scratch, offset); |
| - break; |
| - |
| - // Unsigned comparison. |
| - case Ugreater: |
| - sltu(scratch, r2, rs); |
| - addiu(scratch, scratch, -1); |
| - offset = shifted_branch_offset(L, false); |
| - bgezal(scratch, offset); |
| - break; |
| - case Ugreater_equal: |
| - sltu(scratch, rs, r2); |
| - addiu(scratch, scratch, -1); |
| - offset = shifted_branch_offset(L, false); |
| - bltzal(scratch, offset); |
| - break; |
| - case Uless: |
| - sltu(scratch, rs, r2); |
| - addiu(scratch, scratch, -1); |
| - offset = shifted_branch_offset(L, false); |
| - bgezal(scratch, offset); |
| - break; |
| - case Uless_equal: |
| - sltu(scratch, r2, rs); |
| - addiu(scratch, scratch, -1); |
| - offset = shifted_branch_offset(L, false); |
| - bltzal(scratch, offset); |
| - break; |
| - |
| - default: |
| - UNREACHABLE(); |
| - } |
| + if (IsMipsArchVariant(kMips32r6) && bdslot == PROTECT) { |
| + DCHECK(is_int26(offset)); |
| + BranchAndLinkShortHelperR6(offset, nullptr, cond, rs, rt); |
| } else { |
| - BlockTrampolinePoolScope block_trampoline_pool(this); |
| - switch (cond) { |
| - case cc_always: |
| - offset = shifted_branch_offset(L, false); |
| - bal(offset); |
| - break; |
| - case eq: |
| - bne(rs, r2, 2); |
| - nop(); |
| - offset = shifted_branch_offset(L, false); |
| - bal(offset); |
| - break; |
| - case ne: |
| - beq(rs, r2, 2); |
| - nop(); |
| - offset = shifted_branch_offset(L, false); |
| - bal(offset); |
| - break; |
| - |
| - // Signed comparison. |
| - case greater: |
| - // rs > rt |
| - slt(scratch, r2, rs); |
| - beq(scratch, zero_reg, 2); |
| - nop(); |
| - offset = shifted_branch_offset(L, false); |
| - bal(offset); |
| - break; |
| - case greater_equal: |
| - // rs >= rt |
| - slt(scratch, rs, r2); |
| - bne(scratch, zero_reg, 2); |
| - nop(); |
| - offset = shifted_branch_offset(L, false); |
| - bal(offset); |
| - break; |
| - case less: |
| - // rs < r2 |
| - slt(scratch, rs, r2); |
| - bne(scratch, zero_reg, 2); |
| - nop(); |
| - offset = shifted_branch_offset(L, false); |
| - bal(offset); |
| - break; |
| - case less_equal: |
| - // rs <= r2 |
| - slt(scratch, r2, rs); |
| - bne(scratch, zero_reg, 2); |
| - nop(); |
| - offset = shifted_branch_offset(L, false); |
| - bal(offset); |
| - break; |
| + DCHECK(is_int16(offset)); |
| + BranchAndLinkShortHelper(offset, nullptr, cond, rs, rt, bdslot); |
| + } |
| +} |
| - // Unsigned comparison. |
| - case Ugreater: |
| - // rs > rt |
| - sltu(scratch, r2, rs); |
| - beq(scratch, zero_reg, 2); |
| - nop(); |
| - offset = shifted_branch_offset(L, false); |
| - bal(offset); |
| - break; |
| - case Ugreater_equal: |
| - // rs >= rt |
| - sltu(scratch, rs, r2); |
| - bne(scratch, zero_reg, 2); |
| - nop(); |
| - offset = shifted_branch_offset(L, false); |
| - bal(offset); |
| - break; |
| - case Uless: |
| - // rs < r2 |
| - sltu(scratch, rs, r2); |
| - bne(scratch, zero_reg, 2); |
| - nop(); |
| - offset = shifted_branch_offset(L, false); |
| - bal(offset); |
| - break; |
| - case Uless_equal: |
| - // rs <= r2 |
| - sltu(scratch, r2, rs); |
| - bne(scratch, zero_reg, 2); |
| - nop(); |
| - offset = shifted_branch_offset(L, false); |
| - bal(offset); |
| - break; |
| +void MacroAssembler::BranchAndLinkShort(Label* L, Condition cond, Register rs, |
| + const Operand& rt, |
| + BranchDelaySlot bdslot) { |
| + BRANCH_ARGS_CHECK(cond, rs, rt); |
| - default: |
| - UNREACHABLE(); |
| - } |
| + if (IsMipsArchVariant(kMips32r6) && bdslot == PROTECT) { |
| + BranchAndLinkShortHelperR6(0, L, cond, rs, rt); |
| + } else { |
| + BranchAndLinkShortHelper(0, L, cond, rs, rt, bdslot); |
| } |
| - |
| - // Check that offset could actually hold on an int16_t. |
| - DCHECK(is_int16(offset)); |
| - |
| - // Emit a nop in the branch delay slot if required. |
| - if (bdslot == PROTECT) |
| - nop(); |
| } |
| @@ -3065,6 +2867,10 @@ void MacroAssembler::Call(Register target, |
| Register rs, |
| const Operand& rt, |
| BranchDelaySlot bd) { |
| +#ifdef DEBUG |
| + int size = IsPrevInstrCompactBranch() ? kInstrSize : 0; |
| +#endif |
| + |
| BlockTrampolinePoolScope block_trampoline_pool(this); |
| Label start; |
| bind(&start); |
| @@ -3079,8 +2885,10 @@ void MacroAssembler::Call(Register target, |
| if (bd == PROTECT) |
| nop(); |
| - DCHECK_EQ(CallSize(target, cond, rs, rt, bd), |
| - SizeOfCodeGeneratedSince(&start)); |
| +#ifdef DEBUG |
| + CHECK_EQ(size + CallSize(target, cond, rs, rt, bd), |
| + SizeOfCodeGeneratedSince(&start)); |
| +#endif |
| } |
| @@ -5887,7 +5695,7 @@ void CodePatcher::Emit(Address addr) { |
| } |
| -void CodePatcher::ChangeBranchCondition(Condition cond) { |
| +void CodePatcher::ChangeBranchCondition() { |
| Instr instr = Assembler::instr_at(masm_.pc_); |
| DCHECK(Assembler::IsBranch(instr)); |
| uint32_t opcode = Assembler::GetOpcodeField(instr); |
| @@ -5895,15 +5703,34 @@ void CodePatcher::ChangeBranchCondition(Condition cond) { |
| // branch instructions (with opcode being the branch type). |
| // There are some special cases (see Assembler::IsBranch()) so extending this |
| // would be tricky. |
|
paul.l...
2015/10/15 01:51:24
This comment block is a little out of date. Same b
balazs.kilvady
2015/10/30 21:11:14
Done.
|
| - DCHECK(opcode == BEQ || |
| - opcode == BNE || |
| - opcode == BLEZ || |
| - opcode == BGTZ || |
| - opcode == BEQL || |
| - opcode == BNEL || |
| - opcode == BLEZL || |
| - opcode == BGTZL); |
| - opcode = (cond == eq) ? BEQ : BNE; |
| + DCHECK(opcode == BEQ || opcode == BNE || opcode == BLEZ || opcode == BGTZ || |
| + opcode == BEQL || opcode == BNEL || opcode == BLEZL || |
| + opcode == BGTZL || opcode == POP10 || // BEQC |
| + opcode == POP30 || // BNEC |
| + opcode == POP66 || // BEQZC |
| + opcode == POP76); // BNEZC; |
| + switch (opcode) { |
| + case BEQ: |
| + opcode = BNE; |
| + break; |
| + case POP10: |
| + opcode = POP30; |
|
paul.l...
2015/10/15 01:51:24
Even with the comments above, I really don't like
balazs.kilvady
2015/10/30 21:11:14
Done.
|
| + break; |
| + case POP66: |
| + opcode = POP76; |
| + break; |
| + case BNE: |
| + opcode = BEQ; |
| + break; |
| + case POP30: |
| + opcode = POP10; |
| + break; |
| + case POP76: |
| + opcode = POP66; |
| + break; |
| + default: |
| + UNIMPLEMENTED(); |
| + } |
| instr = (instr & ~kOpcodeMask) | opcode; |
| masm_.emit(instr); |
| } |