| Index: src/mips/macro-assembler-mips.cc
|
| ===================================================================
|
| --- src/mips/macro-assembler-mips.cc (revision 0)
|
| +++ src/mips/macro-assembler-mips.cc (revision 0)
|
| @@ -0,0 +1,895 @@
|
| +// Copyright 2010 the V8 project authors. All rights reserved.
|
| +// Redistribution and use in source and binary forms, with or without
|
| +// modification, are permitted provided that the following conditions are
|
| +// met:
|
| +//
|
| +// * Redistributions of source code must retain the above copyright
|
| +// notice, this list of conditions and the following disclaimer.
|
| +// * Redistributions in binary form must reproduce the above
|
| +// copyright notice, this list of conditions and the following
|
| +// disclaimer in the documentation and/or other materials provided
|
| +// with the distribution.
|
| +// * Neither the name of Google Inc. nor the names of its
|
| +// contributors may be used to endorse or promote products derived
|
| +// from this software without specific prior written permission.
|
| +//
|
| +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
| +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
| +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
| +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
| +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
| +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
| +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
| +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
| +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
| +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| +
|
| +
|
| +
|
| +#include "v8.h"
|
| +
|
| +#include "bootstrapper.h"
|
| +#include "codegen-inl.h"
|
| +#include "debug.h"
|
| +#include "runtime.h"
|
| +
|
| +namespace v8 {
|
| +namespace internal {
|
| +
|
| +MacroAssembler::MacroAssembler(void* buffer, int size)
|
| + : Assembler(buffer, size),
|
| + unresolved_(0),
|
| + generating_stub_(false),
|
| + allow_stub_calls_(true),
|
| + code_object_(Heap::undefined_value()) {
|
| +}
|
| +
|
| +
|
| +
|
| +void MacroAssembler::Jump(Register target, Condition cond,
|
| + Register r1, const Operand& r2) {
|
| + Jump(Operand(target), cond, r1, r2);
|
| +}
|
| +
|
| +
|
| +void MacroAssembler::Jump(intptr_t target, RelocInfo::Mode rmode,
|
| + Condition cond, Register r1, const Operand& r2) {
|
| + Jump(Operand(target), cond, r1, r2);
|
| +}
|
| +
|
| +
|
| +void MacroAssembler::Jump(byte* target, RelocInfo::Mode rmode,
|
| + Condition cond, Register r1, const Operand& r2) {
|
| + ASSERT(!RelocInfo::IsCodeTarget(rmode));
|
| + Jump(reinterpret_cast<intptr_t>(target), rmode, cond, r1, r2);
|
| +}
|
| +
|
| +
|
| +void MacroAssembler::Jump(Handle<Code> code, RelocInfo::Mode rmode,
|
| + Condition cond, Register r1, const Operand& r2) {
|
| + ASSERT(RelocInfo::IsCodeTarget(rmode));
|
| + Jump(reinterpret_cast<intptr_t>(code.location()), rmode, cond);
|
| +}
|
| +
|
| +
|
| +void MacroAssembler::Call(Register target,
|
| + Condition cond, Register r1, const Operand& r2) {
|
| + Call(Operand(target), cond, r1, r2);
|
| +}
|
| +
|
| +
|
| +void MacroAssembler::Call(intptr_t target, RelocInfo::Mode rmode,
|
| + Condition cond, Register r1, const Operand& r2) {
|
| + Call(Operand(target), cond, r1, r2);
|
| +}
|
| +
|
| +
|
| +void MacroAssembler::Call(byte* target, RelocInfo::Mode rmode,
|
| + Condition cond, Register r1, const Operand& r2) {
|
| + ASSERT(!RelocInfo::IsCodeTarget(rmode));
|
| + Call(reinterpret_cast<intptr_t>(target), rmode, cond, r1, r2);
|
| +}
|
| +
|
| +
|
| +void MacroAssembler::Call(Handle<Code> code, RelocInfo::Mode rmode,
|
| + Condition cond, Register r1, const Operand& r2) {
|
| + ASSERT(RelocInfo::IsCodeTarget(rmode));
|
| + Call(reinterpret_cast<intptr_t>(code.location()), rmode, cond, r1, r2);
|
| +}
|
| +
|
| +
|
| +void MacroAssembler::Ret(Condition cond, Register r1, const Operand& r2) {
|
| + Jump(Operand(ra), cond, r1, r2);
|
| +}
|
| +
|
| +
|
| +void MacroAssembler::LoadRoot(Register destination,
|
| + Heap::RootListIndex index) {
|
| + lw(destination, MemOperand(s4, index << kPointerSizeLog2));
|
| +}
|
| +
|
| +void MacroAssembler::LoadRoot(Register destination,
|
| + Heap::RootListIndex index,
|
| + Condition cond,
|
| + Register src1, const Operand& src2) {
|
| + Branch(NegateCondition(cond), 2, src1, src2);
|
| + nop();
|
| + lw(destination, MemOperand(s4, index << kPointerSizeLog2));
|
| +}
|
| +
|
| +
|
| +void MacroAssembler::RecordWrite(Register object, Register offset,
|
| + Register scratch) {
|
| + UNIMPLEMENTED_MIPS();
|
| +}
|
| +
|
| +
|
| +// ---------------------------------------------------------------------------
|
| +// Instruction macros
|
| +
|
| +void MacroAssembler::Add(Register rd, Register rs, const Operand& rt) {
|
| + if (rt.is_reg()) {
|
| + add(rd, rs, rt.rm());
|
| + } else {
|
| + if (is_int16(rt.imm32_) && !MustUseAt(rt.rmode_)) {
|
| + addi(rd, rs, rt.imm32_);
|
| + } else {
|
| + // li handles the relocation.
|
| + ASSERT(!rs.is(at));
|
| + li(at, rt);
|
| + add(rd, rs, at);
|
| + }
|
| + }
|
| +}
|
| +
|
| +
|
| +void MacroAssembler::Addu(Register rd, Register rs, const Operand& rt) {
|
| + if (rt.is_reg()) {
|
| + addu(rd, rs, rt.rm());
|
| + } else {
|
| + if (is_int16(rt.imm32_) && !MustUseAt(rt.rmode_)) {
|
| + addiu(rd, rs, rt.imm32_);
|
| + } else {
|
| + // li handles the relocation.
|
| + ASSERT(!rs.is(at));
|
| + li(at, rt);
|
| + addu(rd, rs, at);
|
| + }
|
| + }
|
| +}
|
| +
|
| +
|
| +void MacroAssembler::Mul(Register rd, Register rs, const Operand& rt) {
|
| + if (rt.is_reg()) {
|
| + mul(rd, rs, rt.rm());
|
| + } else {
|
| + // li handles the relocation.
|
| + ASSERT(!rs.is(at));
|
| + li(at, rt);
|
| + mul(rd, rs, at);
|
| + }
|
| +}
|
| +
|
| +
|
| +void MacroAssembler::Mult(Register rs, const Operand& rt) {
|
| + if (rt.is_reg()) {
|
| + mult(rs, rt.rm());
|
| + } else {
|
| + // li handles the relocation.
|
| + ASSERT(!rs.is(at));
|
| + li(at, rt);
|
| + mult(rs, at);
|
| + }
|
| +}
|
| +
|
| +
|
| +void MacroAssembler::Multu(Register rs, const Operand& rt) {
|
| + if (rt.is_reg()) {
|
| + multu(rs, rt.rm());
|
| + } else {
|
| + // li handles the relocation.
|
| + ASSERT(!rs.is(at));
|
| + li(at, rt);
|
| + multu(rs, at);
|
| + }
|
| +}
|
| +
|
| +
|
| +void MacroAssembler::Div(Register rs, const Operand& rt) {
|
| + if (rt.is_reg()) {
|
| + div(rs, rt.rm());
|
| + } else {
|
| + // li handles the relocation.
|
| + ASSERT(!rs.is(at));
|
| + li(at, rt);
|
| + div(rs, at);
|
| + }
|
| +}
|
| +
|
| +
|
| +void MacroAssembler::Divu(Register rs, const Operand& rt) {
|
| + if (rt.is_reg()) {
|
| + divu(rs, rt.rm());
|
| + } else {
|
| + // li handles the relocation.
|
| + ASSERT(!rs.is(at));
|
| + li(at, rt);
|
| + divu(rs, at);
|
| + }
|
| +}
|
| +
|
| +
|
| +void MacroAssembler::And(Register rd, Register rs, const Operand& rt) {
|
| + if (rt.is_reg()) {
|
| + and_(rd, rs, rt.rm());
|
| + } else {
|
| + if (is_int16(rt.imm32_) && !MustUseAt(rt.rmode_)) {
|
| + andi(rd, rs, rt.imm32_);
|
| + } else {
|
| + // li handles the relocation.
|
| + ASSERT(!rs.is(at));
|
| + li(at, rt);
|
| + and_(rd, rs, at);
|
| + }
|
| + }
|
| +}
|
| +
|
| +
|
| +void MacroAssembler::Or(Register rd, Register rs, const Operand& rt) {
|
| + if (rt.is_reg()) {
|
| + or_(rd, rs, rt.rm());
|
| + } else {
|
| + if (is_int16(rt.imm32_) && !MustUseAt(rt.rmode_)) {
|
| + ori(rd, rs, rt.imm32_);
|
| + } else {
|
| + // li handles the relocation.
|
| + ASSERT(!rs.is(at));
|
| + li(at, rt);
|
| + or_(rd, rs, at);
|
| + }
|
| + }
|
| +}
|
| +
|
| +
|
| +void MacroAssembler::Xor(Register rd, Register rs, const Operand& rt) {
|
| + if (rt.is_reg()) {
|
| + xor_(rd, rs, rt.rm());
|
| + } else {
|
| + if (is_int16(rt.imm32_) && !MustUseAt(rt.rmode_)) {
|
| + xori(rd, rs, rt.imm32_);
|
| + } else {
|
| + // li handles the relocation.
|
| + ASSERT(!rs.is(at));
|
| + li(at, rt);
|
| + xor_(rd, rs, at);
|
| + }
|
| + }
|
| +}
|
| +
|
| +
|
| +void MacroAssembler::Nor(Register rd, Register rs, const Operand& rt) {
|
| + if (rt.is_reg()) {
|
| + nor(rd, rs, rt.rm());
|
| + } else {
|
| + // li handles the relocation.
|
| + ASSERT(!rs.is(at));
|
| + li(at, rt);
|
| + nor(rd, rs, at);
|
| + }
|
| +}
|
| +
|
| +
|
| +void MacroAssembler::Slt(Register rd, Register rs, const Operand& rt) {
|
| + if (rt.is_reg()) {
|
| + slt(rd, rs, rt.rm());
|
| + } else {
|
| + if (is_int16(rt.imm32_) && !MustUseAt(rt.rmode_)) {
|
| + slti(rd, rs, rt.imm32_);
|
| + } else {
|
| + // li handles the relocation.
|
| + ASSERT(!rs.is(at));
|
| + li(at, rt);
|
| + slt(rd, rs, at);
|
| + }
|
| + }
|
| +}
|
| +
|
| +
|
| +void MacroAssembler::Sltu(Register rd, Register rs, const Operand& rt) {
|
| + if (rt.is_reg()) {
|
| + sltu(rd, rs, rt.rm());
|
| + } else {
|
| + if (is_int16(rt.imm32_) && !MustUseAt(rt.rmode_)) {
|
| + sltiu(rd, rs, rt.imm32_);
|
| + } else {
|
| + // li handles the relocation.
|
| + ASSERT(!rs.is(at));
|
| + li(at, rt);
|
| + sltu(rd, rs, at);
|
| + }
|
| + }
|
| +}
|
| +
|
| +
|
| +//------------Pseudo-instructions-------------
|
| +
|
| +void MacroAssembler::movn(Register rd, Register rt) {
|
| + addiu(at, zero_reg, -1); // Fill at with ones.
|
| + xor_(rd, rt, at);
|
| +}
|
| +
|
| +
|
| +// load wartd in a register
|
| +void MacroAssembler::li(Register rd, Operand j, bool gen2instr) {
|
| + ASSERT(!j.is_reg());
|
| +
|
| + if (!MustUseAt(j.rmode_) && !gen2instr) {
|
| + // Normal load of an immediate value which does not need Relocation Info.
|
| + if (is_int16(j.imm32_)) {
|
| + addiu(rd, zero_reg, j.imm32_);
|
| + } else if (!(j.imm32_ & HIMask)) {
|
| + ori(rd, zero_reg, j.imm32_);
|
| + } else if (!(j.imm32_ & LOMask)) {
|
| + lui(rd, (HIMask & j.imm32_) >> 16);
|
| + } else {
|
| + lui(rd, (HIMask & j.imm32_) >> 16);
|
| + ori(rd, rd, (LOMask & j.imm32_));
|
| + }
|
| + } else if (MustUseAt(j.rmode_) || gen2instr) {
|
| + if (MustUseAt(j.rmode_)) {
|
| + RecordRelocInfo(j.rmode_, j.imm32_);
|
| + }
|
| + // We need always the same number of instructions as we may need to patch
|
| + // this code to load another value which may need 2 instructions to load.
|
| + if (is_int16(j.imm32_)) {
|
| + nop();
|
| + addiu(rd, zero_reg, j.imm32_);
|
| + } else if (!(j.imm32_ & HIMask)) {
|
| + nop();
|
| + ori(rd, zero_reg, j.imm32_);
|
| + } else if (!(j.imm32_ & LOMask)) {
|
| + nop();
|
| + lui(rd, (HIMask & j.imm32_) >> 16);
|
| + } else {
|
| + lui(rd, (HIMask & j.imm32_) >> 16);
|
| + ori(rd, rd, (LOMask & j.imm32_));
|
| + }
|
| + }
|
| +}
|
| +
|
| +
|
| +// Exception-generating instructions and debugging support
|
| +void MacroAssembler::stop(const char* msg) {
|
| + // TO_UPGRADE: Just a break for now. Maybe we could upgrade it.
|
| + // We use the 0x54321 value to be able to find it easily when reading memory.
|
| + break_(0x54321);
|
| +}
|
| +
|
| +
|
| +void MacroAssembler::MultiPush(RegList regs) {
|
| + int16_t NumSaved = 0;
|
| + int16_t NumToPush = NumberOfBitsSet(regs);
|
| +
|
| + addiu(sp, sp, -4 * NumToPush);
|
| + for (int16_t i = 0; i < kNumRegisters; i++) {
|
| + if ((regs & (1 << i)) != 0) {
|
| + sw(ToRegister(i), MemOperand(sp, 4 * (NumToPush - ++NumSaved)));
|
| + }
|
| + }
|
| +}
|
| +
|
| +
|
| +void MacroAssembler::MultiPushReversed(RegList regs) {
|
| + int16_t NumSaved = 0;
|
| + int16_t NumToPush = NumberOfBitsSet(regs);
|
| +
|
| + addiu(sp, sp, -4 * NumToPush);
|
| + for (int16_t i = kNumRegisters; i > 0; i--) {
|
| + if ((regs & (1 << i)) != 0) {
|
| + sw(ToRegister(i), MemOperand(sp, 4 * (NumToPush - ++NumSaved)));
|
| + }
|
| + }
|
| +}
|
| +
|
| +
|
| +void MacroAssembler::MultiPop(RegList regs) {
|
| + int16_t NumSaved = 0;
|
| +
|
| + for (int16_t i = kNumRegisters; i > 0; i--) {
|
| + if ((regs & (1 << i)) != 0) {
|
| + lw(ToRegister(i), MemOperand(sp, 4 * (NumSaved++)));
|
| + }
|
| + }
|
| + addiu(sp, sp, 4 * NumSaved);
|
| +}
|
| +
|
| +
|
| +void MacroAssembler::MultiPopReversed(RegList regs) {
|
| + int16_t NumSaved = 0;
|
| +
|
| + for (int16_t i = 0; i < kNumRegisters; i++) {
|
| + if ((regs & (1 << i)) != 0) {
|
| + lw(ToRegister(i), MemOperand(sp, 4 * (NumSaved++)));
|
| + }
|
| + }
|
| + addiu(sp, sp, 4 * NumSaved);
|
| +}
|
| +
|
| +
|
| +// Emulated condtional branches do not emit a nop in the branch delay slot.
|
| +
|
| +// Trashes the at register if no scratch register is provided.
|
| +void MacroAssembler::Branch(Condition cond, int16_t offset, Register rs,
|
| + const Operand& rt, Register scratch) {
|
| + Register r2;
|
| + if (rt.is_reg()) {
|
| + // We don't want any other register but scratch clobbered.
|
| + ASSERT(!scratch.is(rs) && !scratch.is(rt.rm_));
|
| + r2 = rt.rm_;
|
| + } else if (cond != cc_always) {
|
| + // We don't want any other register but scratch clobbered.
|
| + ASSERT(!scratch.is(rs));
|
| + r2 = scratch;
|
| + li(r2, rt);
|
| + }
|
| +
|
| + 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:
|
| + slt(scratch, r2, rs);
|
| + bne(scratch, zero_reg, offset);
|
| + break;
|
| + case greater_equal:
|
| + slt(scratch, rs, r2);
|
| + beq(scratch, zero_reg, offset);
|
| + break;
|
| + case less:
|
| + slt(scratch, rs, r2);
|
| + bne(scratch, zero_reg, offset);
|
| + break;
|
| + case less_equal:
|
| + slt(scratch, r2, rs);
|
| + beq(scratch, zero_reg, offset);
|
| + break;
|
| +
|
| + // Unsigned comparison.
|
| + case Ugreater:
|
| + sltu(scratch, r2, rs);
|
| + bne(scratch, zero_reg, offset);
|
| + break;
|
| + case Ugreater_equal:
|
| + sltu(scratch, rs, r2);
|
| + beq(scratch, zero_reg, offset);
|
| + break;
|
| + case Uless:
|
| + sltu(scratch, rs, r2);
|
| + bne(scratch, zero_reg, offset);
|
| + break;
|
| + case Uless_equal:
|
| + sltu(scratch, r2, rs);
|
| + beq(scratch, zero_reg, offset);
|
| + break;
|
| +
|
| + default:
|
| + UNREACHABLE();
|
| + }
|
| +}
|
| +
|
| +
|
| +void MacroAssembler::Branch(Condition cond, Label* L, Register rs,
|
| + const Operand& rt, Register scratch) {
|
| + Register r2;
|
| + if (rt.is_reg()) {
|
| + r2 = rt.rm_;
|
| + } else if (cond != cc_always) {
|
| + r2 = scratch;
|
| + li(r2, rt);
|
| + }
|
| +
|
| + // 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.
|
| +
|
| + switch (cond) {
|
| + case cc_always:
|
| + b(shifted_branch_offset(L, false));
|
| + break;
|
| + case eq:
|
| + beq(rs, r2, shifted_branch_offset(L, false));
|
| + break;
|
| + case ne:
|
| + bne(rs, r2, shifted_branch_offset(L, false));
|
| + break;
|
| +
|
| + // Signed comparison
|
| + case greater:
|
| + slt(scratch, r2, rs);
|
| + bne(scratch, zero_reg, shifted_branch_offset(L, false));
|
| + break;
|
| + case greater_equal:
|
| + slt(scratch, rs, r2);
|
| + beq(scratch, zero_reg, shifted_branch_offset(L, false));
|
| + break;
|
| + case less:
|
| + slt(scratch, rs, r2);
|
| + bne(scratch, zero_reg, shifted_branch_offset(L, false));
|
| + break;
|
| + case less_equal:
|
| + slt(scratch, r2, rs);
|
| + beq(scratch, zero_reg, shifted_branch_offset(L, false));
|
| + break;
|
| +
|
| + // Unsigned comparison.
|
| + case Ugreater:
|
| + sltu(scratch, r2, rs);
|
| + bne(scratch, zero_reg, shifted_branch_offset(L, false));
|
| + break;
|
| + case Ugreater_equal:
|
| + sltu(scratch, rs, r2);
|
| + beq(scratch, zero_reg, shifted_branch_offset(L, false));
|
| + break;
|
| + case Uless:
|
| + sltu(scratch, rs, r2);
|
| + bne(scratch, zero_reg, shifted_branch_offset(L, false));
|
| + break;
|
| + case Uless_equal:
|
| + sltu(scratch, r2, rs);
|
| + beq(scratch, zero_reg, shifted_branch_offset(L, false));
|
| + break;
|
| +
|
| + default:
|
| + UNREACHABLE();
|
| + }
|
| +}
|
| +
|
| +
|
| +// Trashes the at register if no scratch register is provided.
|
| +// 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::BranchAndLink(Condition cond, int16_t offset, Register rs,
|
| + const Operand& rt, Register scratch) {
|
| + Register r2;
|
| + if (rt.is_reg()) {
|
| + r2 = rt.rm_;
|
| + } else if (cond != cc_always) {
|
| + r2 = scratch;
|
| + li(r2, rt);
|
| + }
|
| +
|
| + 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::BranchAndLink(Condition cond, Label* L, Register rs,
|
| + const Operand& rt, Register scratch) {
|
| + Register r2;
|
| + if (rt.is_reg()) {
|
| + r2 = rt.rm_;
|
| + } else if (cond != cc_always) {
|
| + r2 = scratch;
|
| + li(r2, rt);
|
| + }
|
| +
|
| + switch (cond) {
|
| + case cc_always:
|
| + bal(shifted_branch_offset(L, false));
|
| + break;
|
| + case eq:
|
| + bne(rs, r2, 2);
|
| + nop();
|
| + bal(shifted_branch_offset(L, false));
|
| + break;
|
| + case ne:
|
| + beq(rs, r2, 2);
|
| + nop();
|
| + bal(shifted_branch_offset(L, false));
|
| + break;
|
| +
|
| + // Signed comparison
|
| + case greater:
|
| + slt(scratch, r2, rs);
|
| + addiu(scratch, scratch, -1);
|
| + bgezal(scratch, shifted_branch_offset(L, false));
|
| + break;
|
| + case greater_equal:
|
| + slt(scratch, rs, r2);
|
| + addiu(scratch, scratch, -1);
|
| + bltzal(scratch, shifted_branch_offset(L, false));
|
| + break;
|
| + case less:
|
| + slt(scratch, rs, r2);
|
| + addiu(scratch, scratch, -1);
|
| + bgezal(scratch, shifted_branch_offset(L, false));
|
| + break;
|
| + case less_equal:
|
| + slt(scratch, r2, rs);
|
| + addiu(scratch, scratch, -1);
|
| + bltzal(scratch, shifted_branch_offset(L, false));
|
| + break;
|
| +
|
| + // Unsigned comparison.
|
| + case Ugreater:
|
| + sltu(scratch, r2, rs);
|
| + addiu(scratch, scratch, -1);
|
| + bgezal(scratch, shifted_branch_offset(L, false));
|
| + break;
|
| + case Ugreater_equal:
|
| + sltu(scratch, rs, r2);
|
| + addiu(scratch, scratch, -1);
|
| + bltzal(scratch, shifted_branch_offset(L, false));
|
| + break;
|
| + case Uless:
|
| + sltu(scratch, rs, r2);
|
| + addiu(scratch, scratch, -1);
|
| + bgezal(scratch, shifted_branch_offset(L, false));
|
| + break;
|
| + case Uless_equal:
|
| + sltu(scratch, r2, rs);
|
| + addiu(scratch, scratch, -1);
|
| + bltzal(scratch, shifted_branch_offset(L, false));
|
| + break;
|
| +
|
| + default:
|
| + UNREACHABLE();
|
| + }
|
| +}
|
| +
|
| +
|
| +void MacroAssembler::Jump(const Operand& target,
|
| + Condition cond, Register rs, const Operand& rt) {
|
| + if (target.is_reg()) {
|
| + if (cond == cc_always) {
|
| + jr(target.rm());
|
| + } else {
|
| + Branch(NegateCondition(cond), 2, rs, rt);
|
| + nop();
|
| + jr(target.rm());
|
| + }
|
| + } else { // !target.is_reg()
|
| + if (!MustUseAt(target.rmode_)) {
|
| + if (cond == cc_always) {
|
| + j(target.imm32_);
|
| + } else {
|
| + Branch(NegateCondition(cond), 2, rs, rt);
|
| + nop();
|
| + j(target.imm32_); // will generate only one instruction.
|
| + }
|
| + } else { // MustUseAt(target)
|
| + li(at, rt);
|
| + if (cond == cc_always) {
|
| + jr(at);
|
| + } else {
|
| + Branch(NegateCondition(cond), 2, rs, rt);
|
| + nop();
|
| + jr(at); // will generate only one instruction.
|
| + }
|
| + }
|
| + }
|
| +}
|
| +
|
| +
|
| +void MacroAssembler::Call(const Operand& target,
|
| + Condition cond, Register rs, const Operand& rt) {
|
| + if (target.is_reg()) {
|
| + if (cond == cc_always) {
|
| + jalr(target.rm());
|
| + } else {
|
| + Branch(NegateCondition(cond), 2, rs, rt);
|
| + nop();
|
| + jalr(target.rm());
|
| + }
|
| + } else { // !target.is_reg()
|
| + if (!MustUseAt(target.rmode_)) {
|
| + if (cond == cc_always) {
|
| + jal(target.imm32_);
|
| + } else {
|
| + Branch(NegateCondition(cond), 2, rs, rt);
|
| + nop();
|
| + jal(target.imm32_); // will generate only one instruction.
|
| + }
|
| + } else { // MustUseAt(target)
|
| + li(at, rt);
|
| + if (cond == cc_always) {
|
| + jalr(at);
|
| + } else {
|
| + Branch(NegateCondition(cond), 2, rs, rt);
|
| + nop();
|
| + jalr(at); // will generate only one instruction.
|
| + }
|
| + }
|
| + }
|
| +}
|
| +
|
| +void MacroAssembler::StackLimitCheck(Label* on_stack_overflow) {
|
| + UNIMPLEMENTED_MIPS();
|
| +}
|
| +
|
| +
|
| +void MacroAssembler::Drop(int count, Condition cond) {
|
| + UNIMPLEMENTED_MIPS();
|
| +}
|
| +
|
| +
|
| +void MacroAssembler::Call(Label* target) {
|
| + UNIMPLEMENTED_MIPS();
|
| +}
|
| +
|
| +
|
| +// ---------------------------------------------------------------------------
|
| +// Exception handling
|
| +
|
| +void MacroAssembler::PushTryHandler(CodeLocation try_location,
|
| + HandlerType type) {
|
| + UNIMPLEMENTED_MIPS();
|
| +}
|
| +
|
| +
|
| +void MacroAssembler::PopTryHandler() {
|
| + UNIMPLEMENTED_MIPS();
|
| +}
|
| +
|
| +
|
| +
|
| +// ---------------------------------------------------------------------------
|
| +// Activation frames
|
| +
|
| +void MacroAssembler::CallStub(CodeStub* stub, Condition cond,
|
| + Register r1, const Operand& r2) {
|
| + UNIMPLEMENTED_MIPS();
|
| +}
|
| +
|
| +
|
| +void MacroAssembler::StubReturn(int argc) {
|
| + UNIMPLEMENTED_MIPS();
|
| +}
|
| +
|
| +
|
| +void MacroAssembler::CallRuntime(Runtime::Function* f, int num_arguments) {
|
| + UNIMPLEMENTED_MIPS();
|
| +}
|
| +
|
| +
|
| +void MacroAssembler::CallRuntime(Runtime::FunctionId fid, int num_arguments) {
|
| + UNIMPLEMENTED_MIPS();
|
| +}
|
| +
|
| +
|
| +void MacroAssembler::TailCallRuntime(const ExternalReference& ext,
|
| + int num_arguments,
|
| + int result_size) {
|
| + UNIMPLEMENTED_MIPS();
|
| +}
|
| +
|
| +
|
| +void MacroAssembler::JumpToRuntime(const ExternalReference& builtin) {
|
| + UNIMPLEMENTED_MIPS();
|
| +}
|
| +
|
| +
|
| +Handle<Code> MacroAssembler::ResolveBuiltin(Builtins::JavaScript id,
|
| + bool* resolved) {
|
| + UNIMPLEMENTED_MIPS();
|
| + return Handle<Code>(reinterpret_cast<Code*>(NULL)); // UNIMPLEMENTED RETURN
|
| +}
|
| +
|
| +
|
| +void MacroAssembler::InvokeBuiltin(Builtins::JavaScript id,
|
| + InvokeJSFlags flags) {
|
| + UNIMPLEMENTED_MIPS();
|
| +}
|
| +
|
| +
|
| +void MacroAssembler::GetBuiltinEntry(Register target, Builtins::JavaScript id) {
|
| + UNIMPLEMENTED_MIPS();
|
| +}
|
| +
|
| +
|
| +void MacroAssembler::SetCounter(StatsCounter* counter, int value,
|
| + Register scratch1, Register scratch2) {
|
| + UNIMPLEMENTED_MIPS();
|
| +}
|
| +
|
| +
|
| +void MacroAssembler::IncrementCounter(StatsCounter* counter, int value,
|
| + Register scratch1, Register scratch2) {
|
| + UNIMPLEMENTED_MIPS();
|
| +}
|
| +
|
| +
|
| +void MacroAssembler::DecrementCounter(StatsCounter* counter, int value,
|
| + Register scratch1, Register scratch2) {
|
| + UNIMPLEMENTED_MIPS();
|
| +}
|
| +
|
| +
|
| +
|
| +void MacroAssembler::Assert(Condition cc, const char* msg,
|
| + Register rs, Operand rt) {
|
| + UNIMPLEMENTED_MIPS();
|
| +}
|
| +
|
| +
|
| +void MacroAssembler::Check(Condition cc, const char* msg,
|
| + Register rs, Operand rt) {
|
| + UNIMPLEMENTED_MIPS();
|
| +}
|
| +
|
| +
|
| +void MacroAssembler::Abort(const char* msg) {
|
| + UNIMPLEMENTED_MIPS();
|
| +}
|
| +
|
| +} } // namespace v8::internal
|
| +
|
|
|