blob: 6ae4808e02f25d6427dcdd30b6d64d4a736a5499 [file] [log] [blame]
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef assembler_assembler_MacroAssemblerSparc_h
#define assembler_assembler_MacroAssemblerSparc_h
#include <assembler/wtf/Platform.h>
#if ENABLE_ASSEMBLER && WTF_CPU_SPARC
#include "SparcAssembler.h"
#include "AbstractMacroAssembler.h"
namespace JSC {
class MacroAssemblerSparc : public AbstractMacroAssembler<SparcAssembler> {
public:
enum Condition {
Equal = SparcAssembler::ConditionE,
NotEqual = SparcAssembler::ConditionNE,
Above = SparcAssembler::ConditionGU,
AboveOrEqual = SparcAssembler::ConditionCC,
Below = SparcAssembler::ConditionCS,
BelowOrEqual = SparcAssembler::ConditionLEU,
GreaterThan = SparcAssembler::ConditionG,
GreaterThanOrEqual = SparcAssembler::ConditionGE,
LessThan = SparcAssembler::ConditionL,
LessThanOrEqual = SparcAssembler::ConditionLE,
Overflow = SparcAssembler::ConditionVS,
Signed = SparcAssembler::ConditionNEG,
Zero = SparcAssembler::ConditionE,
NonZero = SparcAssembler::ConditionNE
};
enum DoubleCondition {
// These conditions will only evaluate to true if the comparison is ordered - i.e. neither operand is NaN.
DoubleEqual = SparcAssembler::DoubleConditionE,
DoubleNotEqual = SparcAssembler::DoubleConditionNE,
DoubleGreaterThan = SparcAssembler::DoubleConditionG,
DoubleGreaterThanOrEqual = SparcAssembler::DoubleConditionGE,
DoubleLessThan = SparcAssembler::DoubleConditionL,
DoubleLessThanOrEqual = SparcAssembler::DoubleConditionLE,
// If either operand is NaN, these conditions always evaluate to true.
DoubleEqualOrUnordered = SparcAssembler::DoubleConditionUE,
DoubleNotEqualOrUnordered = SparcAssembler::DoubleConditionNE,
DoubleGreaterThanOrUnordered = SparcAssembler::DoubleConditionUG,
DoubleGreaterThanOrEqualOrUnordered = SparcAssembler::DoubleConditionUGE,
DoubleLessThanOrUnordered = SparcAssembler::DoubleConditionUL,
DoubleLessThanOrEqualOrUnordered = SparcAssembler::DoubleConditionULE
};
static const RegisterID stackPointerRegister = SparcRegisters::sp;
static const Scale ScalePtr = TimesFour;
static const unsigned int TotalRegisters = 24;
void add32(RegisterID src, RegisterID dest)
{
m_assembler.addcc_r(dest, src, dest);
}
void add32(TrustedImm32 imm, Address address)
{
load32(address, SparcRegisters::g2);
add32(imm, SparcRegisters::g2);
store32(SparcRegisters::g2, address);
}
void add32(TrustedImm32 imm, RegisterID dest)
{
if (m_assembler.isimm13(imm.m_value))
m_assembler.addcc_imm(dest, imm.m_value, dest);
else {
m_assembler.move_nocheck(imm.m_value, SparcRegisters::g3);
m_assembler.addcc_r(dest, SparcRegisters::g3, dest);
}
}
void add32(Address src, RegisterID dest)
{
load32(src, SparcRegisters::g2);
m_assembler.addcc_r(dest, SparcRegisters::g2, dest);
}
void and32(Address src, RegisterID dest)
{
load32(src, SparcRegisters::g2);
m_assembler.andcc_r(dest, SparcRegisters::g2, dest);
}
void add32(TrustedImm32 imm, RegisterID src, RegisterID dest)
{
if (m_assembler.isimm13(imm.m_value))
m_assembler.addcc_imm(src, imm.m_value, dest);
else {
m_assembler.move_nocheck(imm.m_value, SparcRegisters::g3);
m_assembler.addcc_r(src, SparcRegisters::g3, dest);
}
}
void and32(RegisterID src, RegisterID dest)
{
m_assembler.andcc_r(dest, src, dest);
}
void and32(Imm32 imm, RegisterID dest)
{
if (m_assembler.isimm13(imm.m_value))
m_assembler.andcc_imm(dest, imm.m_value, dest);
else {
m_assembler.move_nocheck(imm.m_value, SparcRegisters::g3);
m_assembler.andcc_r(dest, SparcRegisters::g3, dest);
}
}
void lshift32(RegisterID shift_amount, RegisterID dest)
{
m_assembler.sll_r(dest, shift_amount, dest);
}
void lshift32(Imm32 imm, RegisterID dest)
{
// No need to check if imm.m_value.
// The last 5 bit of imm.m_value will be used anyway.
m_assembler.sll_imm(dest, imm.m_value, dest);
}
void mul32(RegisterID src, RegisterID dest)
{
m_assembler.smulcc_r(dest, src, dest);
}
void mul32(Imm32 imm, RegisterID src, RegisterID dest)
{
if (m_assembler.isimm13(imm.m_value))
m_assembler.smulcc_imm(dest, imm.m_value, dest);
else {
m_assembler.move_nocheck(imm.m_value, SparcRegisters::g3);
m_assembler.smulcc_r(SparcRegisters::g3, dest, dest);
}
}
void neg32(RegisterID srcDest)
{
m_assembler.subcc_r(SparcRegisters::g0, srcDest, srcDest);
}
void not32(RegisterID dest)
{
m_assembler.xnorcc_r(dest, SparcRegisters::g0, dest);
}
void or32(RegisterID src, RegisterID dest)
{
m_assembler.orcc_r(dest, src, dest);
}
void or32(TrustedImm32 imm, RegisterID dest)
{
if (m_assembler.isimm13(imm.m_value))
m_assembler.orcc_imm(dest, imm.m_value, dest);
else {
m_assembler.move_nocheck(imm.m_value, SparcRegisters::g3);
m_assembler.or_r(SparcRegisters::g3, dest, dest);
}
}
void or32(Address address, RegisterID dest)
{
load32(address, SparcRegisters::g2);
or32(SparcRegisters::g2, dest);
}
void rshift32(RegisterID shift_amount, RegisterID dest)
{
m_assembler.sra_r(dest, shift_amount, dest);
}
void rshift32(Imm32 imm, RegisterID dest)
{
// No need to check if imm.m_value.
// The last 5 bit of imm.m_value will be used anyway.
m_assembler.sra_imm(dest, imm.m_value, dest);
}
void urshift32(RegisterID shift_amount, RegisterID dest)
{
m_assembler.srl_r(dest, shift_amount, dest);
}
void urshift32(Imm32 imm, RegisterID dest)
{
// No need to check if imm.m_value.
// The last 5 bit of imm.m_value will be used anyway.
m_assembler.srl_imm(dest, imm.m_value, dest);
}
void sub32(RegisterID src, RegisterID dest)
{
m_assembler.subcc_r(dest, src, dest);
}
void sub32(TrustedImm32 imm, RegisterID dest)
{
if (m_assembler.isimm13(imm.m_value))
m_assembler.subcc_imm(dest, imm.m_value, dest);
else {
m_assembler.move_nocheck(imm.m_value, SparcRegisters::g3);
m_assembler.subcc_r(dest, SparcRegisters::g3, dest);
}
}
void sub32(TrustedImm32 imm, Address address)
{
load32(address, SparcRegisters::g2);
sub32(imm, SparcRegisters::g2);
store32(SparcRegisters::g2, address);
}
void sub32(Address src, RegisterID dest)
{
load32(src, SparcRegisters::g2);
sub32(SparcRegisters::g2, dest);
}
void xor32(RegisterID src, RegisterID dest)
{
m_assembler.xorcc_r(src, dest, dest);
}
void xor32(TrustedImm32 imm, RegisterID dest)
{
if (m_assembler.isimm13(imm.m_value))
m_assembler.xorcc_imm(dest, imm.m_value, dest);
else {
m_assembler.move_nocheck(imm.m_value, SparcRegisters::g3);
m_assembler.xorcc_r(dest, SparcRegisters::g3, dest);
}
}
void xor32(Address src, RegisterID dest)
{
load32(src, SparcRegisters::g2);
xor32(SparcRegisters::g2, dest);
}
void load8(ImplicitAddress address, RegisterID dest)
{
if (m_assembler.isimm13(address.offset))
m_assembler.ldub_imm(address.base, address.offset, dest);
else {
m_assembler.move_nocheck(address.offset, SparcRegisters::g3);
m_assembler.ldub_r(address.base, SparcRegisters::g3, dest);
}
}
void load32(ImplicitAddress address, RegisterID dest)
{
if (m_assembler.isimm13(address.offset))
m_assembler.lduw_imm(address.base, address.offset, dest);
else {
m_assembler.move_nocheck(address.offset, SparcRegisters::g3);
m_assembler.lduw_r(address.base, SparcRegisters::g3, dest);
}
}
void load32(BaseIndex address, RegisterID dest)
{
m_assembler.sll_imm(address.index, address.scale, SparcRegisters::g2);
add32(Imm32(address.offset), SparcRegisters::g2);
m_assembler.lduw_r(address.base, SparcRegisters::g2, dest);
}
void load32WithUnalignedHalfWords(BaseIndex address, RegisterID dest)
{
m_assembler.sll_imm(address.index, address.scale, SparcRegisters::g2);
add32(Imm32(address.offset+3), SparcRegisters::g2);
m_assembler.ldub_r(address.base, SparcRegisters::g2, dest);
m_assembler.subcc_imm(SparcRegisters::g2, 1, SparcRegisters::g2);
m_assembler.ldub_r(address.base, SparcRegisters::g2, SparcRegisters::g3);
m_assembler.sll_imm(SparcRegisters::g3, 8, SparcRegisters::g3);
m_assembler.or_r(SparcRegisters::g3, dest, dest);
m_assembler.subcc_imm(SparcRegisters::g2, 1, SparcRegisters::g2);
m_assembler.ldub_r(address.base, SparcRegisters::g2, SparcRegisters::g3);
m_assembler.sll_imm(SparcRegisters::g3, 16, SparcRegisters::g3);
m_assembler.or_r(SparcRegisters::g3, dest, dest);
m_assembler.subcc_imm(SparcRegisters::g2, 1, SparcRegisters::g2);
m_assembler.ldub_r(address.base, SparcRegisters::g2, SparcRegisters::g3);
m_assembler.sll_imm(SparcRegisters::g3, 24, SparcRegisters::g3);
m_assembler.or_r(SparcRegisters::g3, dest, dest);
}
DataLabel32 load32WithAddressOffsetPatch(Address address, RegisterID dest)
{
DataLabel32 dataLabel(this);
m_assembler.move_nocheck(0, SparcRegisters::g3);
m_assembler.lduw_r(address.base, SparcRegisters::g3, dest);
return dataLabel;
}
DataLabel32 load64WithAddressOffsetPatch(Address address, RegisterID hi, RegisterID lo)
{
DataLabel32 dataLabel(this);
m_assembler.move_nocheck(0, SparcRegisters::g3);
m_assembler.add_imm(SparcRegisters::g3, 4, SparcRegisters::g2);
m_assembler.lduw_r(address.base, SparcRegisters::g3, hi);
m_assembler.lduw_r(address.base, SparcRegisters::g2, lo);
return dataLabel;
}
Label loadPtrWithPatchToLEA(Address address, RegisterID dest)
{
Label label(this);
load32(address, dest);
return label;
}
void load16(BaseIndex address, RegisterID dest)
{
m_assembler.sll_imm(address.index, address.scale, SparcRegisters::g2);
add32(Imm32(address.offset), SparcRegisters::g2);
m_assembler.lduh_r(address.base, SparcRegisters::g2, dest);
}
void load16(ImplicitAddress address, RegisterID dest)
{
if (m_assembler.isimm13(address.offset))
m_assembler.lduh_imm(address.base, address.offset, dest);
else {
m_assembler.move_nocheck(address.offset, SparcRegisters::g3);
m_assembler.lduh_r(address.base, SparcRegisters::g3, dest);
}
}
void store8(RegisterID src, ImplicitAddress address)
{
if (m_assembler.isimm13(address.offset))
m_assembler.stb_imm(src, address.base, address.offset);
else {
m_assembler.move_nocheck(address.offset, SparcRegisters::g3);
m_assembler.stb_r(src, address.base, SparcRegisters::g3);
}
}
void store8(RegisterID src, BaseIndex address)
{
m_assembler.sll_imm(address.index, address.scale, SparcRegisters::g2);
add32(Imm32(address.offset), SparcRegisters::g2);
m_assembler.stb_r(src, address.base, SparcRegisters::g2);
}
void store8(Imm32 imm, ImplicitAddress address)
{
m_assembler.move_nocheck(imm.m_value, SparcRegisters::g2);
store8(SparcRegisters::g2, address);
}
void store8(Imm32 imm, BaseIndex address)
{
m_assembler.sll_imm(address.index, address.scale, SparcRegisters::g2);
add32(Imm32(address.offset), SparcRegisters::g2);
move(imm, SparcRegisters::g3);
m_assembler.stb_r(SparcRegisters::g3, SparcRegisters::g2, address.base);
}
void store16(RegisterID src, ImplicitAddress address)
{
if (m_assembler.isimm13(address.offset))
m_assembler.sth_imm(src, address.base, address.offset);
else {
m_assembler.move_nocheck(address.offset, SparcRegisters::g3);
m_assembler.sth_r(src, address.base, SparcRegisters::g3);
}
}
void store16(RegisterID src, BaseIndex address)
{
m_assembler.sll_imm(address.index, address.scale, SparcRegisters::g2);
add32(Imm32(address.offset), SparcRegisters::g2);
m_assembler.sth_r(src, address.base, SparcRegisters::g2);
}
void store16(Imm32 imm, ImplicitAddress address)
{
m_assembler.move_nocheck(imm.m_value, SparcRegisters::g2);
store16(SparcRegisters::g2, address);
}
void store16(Imm32 imm, BaseIndex address)
{
m_assembler.sll_imm(address.index, address.scale, SparcRegisters::g2);
add32(Imm32(address.offset), SparcRegisters::g2);
move(imm, SparcRegisters::g3);
m_assembler.sth_r(SparcRegisters::g3, SparcRegisters::g2, address.base);
}
void load8ZeroExtend(BaseIndex address, RegisterID dest)
{
m_assembler.sll_imm(address.index, address.scale, SparcRegisters::g2);
add32(Imm32(address.offset), SparcRegisters::g2);
m_assembler.ldub_r(address.base, SparcRegisters::g2, dest);
}
void load8ZeroExtend(Address address, RegisterID dest)
{
if (m_assembler.isimm13(address.offset))
m_assembler.ldub_imm(address.base, address.offset, dest);
else {
m_assembler.move_nocheck(address.offset, SparcRegisters::g3);
m_assembler.ldub_r(address.base, SparcRegisters::g3, dest);
}
}
void load8SignExtend(BaseIndex address, RegisterID dest)
{
m_assembler.sll_imm(address.index, address.scale, SparcRegisters::g2);
add32(Imm32(address.offset), SparcRegisters::g2);
m_assembler.ldsb_r(address.base, SparcRegisters::g2, dest);
}
void load8SignExtend(Address address, RegisterID dest)
{
if (m_assembler.isimm13(address.offset))
m_assembler.ldsb_imm(address.base, address.offset, dest);
else {
m_assembler.move_nocheck(address.offset, SparcRegisters::g3);
m_assembler.ldsb_r(address.base, SparcRegisters::g3, dest);
}
}
void load16SignExtend(BaseIndex address, RegisterID dest)
{
m_assembler.sll_imm(address.index, address.scale, SparcRegisters::g2);
add32(Imm32(address.offset), SparcRegisters::g2);
m_assembler.ldsh_r(address.base, SparcRegisters::g2, dest);
}
void load16SignExtend(Address address, RegisterID dest)
{
if (m_assembler.isimm13(address.offset))
m_assembler.ldsh_imm(address.base, address.offset, dest);
else {
m_assembler.move_nocheck(address.offset, SparcRegisters::g3);
m_assembler.ldsh_r(address.base, SparcRegisters::g3, dest);
}
}
DataLabel32 store32WithAddressOffsetPatch(RegisterID src, Address address)
{
DataLabel32 dataLabel(this);
// Since this is for patch, we don't check is offset is imm13.
m_assembler.move_nocheck(0, SparcRegisters::g3);
m_assembler.stw_r(src, address.base, SparcRegisters::g3);
return dataLabel;
}
DataLabel32 store64WithAddressOffsetPatch(RegisterID hi, RegisterID lo, Address address)
{
DataLabel32 dataLabel(this);
m_assembler.move_nocheck(address.offset, SparcRegisters::g3);
m_assembler.add_r(SparcRegisters::g3, address.base, SparcRegisters::g3);
m_assembler.stw_imm(lo, SparcRegisters::g3, 4);
m_assembler.stw_imm(hi, SparcRegisters::g3, 0);
return dataLabel;
}
DataLabel32 store64WithAddressOffsetPatch(Imm32 hi, RegisterID lo, Address address)
{
DataLabel32 dataLabel(this);
m_assembler.move_nocheck(address.offset, SparcRegisters::g3);
m_assembler.add_r(SparcRegisters::g3, address.base, SparcRegisters::g3);
m_assembler.stw_imm(lo, SparcRegisters::g3, 4);
move(hi, SparcRegisters::g2);
m_assembler.stw_imm(SparcRegisters::g2, SparcRegisters::g3, 0);
return dataLabel;
}
DataLabel32 store64WithAddressOffsetPatch(Imm32 hi, Imm32 lo, Address address)
{
DataLabel32 dataLabel(this);
m_assembler.move_nocheck(address.offset, SparcRegisters::g3);
m_assembler.add_r(SparcRegisters::g3, address.base, SparcRegisters::g3);
move(lo, SparcRegisters::g2);
m_assembler.stw_imm(SparcRegisters::g2, SparcRegisters::g3, 4);
move(hi, SparcRegisters::g2);
m_assembler.stw_imm(SparcRegisters::g2, SparcRegisters::g3, 0);
return dataLabel;
}
void store32(RegisterID src, ImplicitAddress address)
{
if (m_assembler.isimm13(address.offset))
m_assembler.stw_imm(src, address.base, address.offset);
else {
m_assembler.move_nocheck(address.offset, SparcRegisters::g3);
m_assembler.stw_r(src, address.base, SparcRegisters::g3);
}
}
void store32(RegisterID src, BaseIndex address)
{
m_assembler.sll_imm(address.index, address.scale, SparcRegisters::g2);
add32(Imm32(address.offset), SparcRegisters::g2);
m_assembler.stw_r(src, address.base, SparcRegisters::g2);
}
void store32(TrustedImm32 imm, BaseIndex address)
{
m_assembler.sll_imm(address.index, address.scale, SparcRegisters::g2);
add32(Imm32(address.offset), SparcRegisters::g2);
move(imm, SparcRegisters::g3);
m_assembler.stw_r(SparcRegisters::g3, SparcRegisters::g2, address.base);
}
void store32(TrustedImm32 imm, ImplicitAddress address)
{
m_assembler.move_nocheck(imm.m_value, SparcRegisters::g2);
store32(SparcRegisters::g2, address);
}
void store32(RegisterID src, void* address)
{
m_assembler.move_nocheck((int)address, SparcRegisters::g3);
m_assembler.stw_r(src, SparcRegisters::g0, SparcRegisters::g3);
}
void store32(TrustedImm32 imm, void* address)
{
move(imm, SparcRegisters::g2);
store32(SparcRegisters::g2, address);
}
void pop(RegisterID dest)
{
m_assembler.lduw_imm(SparcRegisters::sp, 0x68, dest);
m_assembler.addcc_imm(SparcRegisters::sp, 4, SparcRegisters::sp);
}
void push(RegisterID src)
{
m_assembler.subcc_imm(SparcRegisters::sp, 4, SparcRegisters::sp);
m_assembler.stw_imm(src, SparcRegisters::sp, 0x68);
}
void push(Address address)
{
load32(address, SparcRegisters::g2);
push(SparcRegisters::g2);
}
void push(Imm32 imm)
{
move(imm, SparcRegisters::g2);
push(SparcRegisters::g2);
}
void move(TrustedImm32 imm, RegisterID dest)
{
if (m_assembler.isimm13(imm.m_value))
m_assembler.or_imm(SparcRegisters::g0, imm.m_value, dest);
else
m_assembler.move_nocheck(imm.m_value, dest);
}
void move(RegisterID src, RegisterID dest)
{
m_assembler.or_r(src, SparcRegisters::g0, dest);
}
void move(TrustedImmPtr imm, RegisterID dest)
{
move(Imm32(imm), dest);
}
void swap(RegisterID reg1, RegisterID reg2)
{
m_assembler.or_r(reg1, SparcRegisters::g0, SparcRegisters::g3);
m_assembler.or_r(reg2, SparcRegisters::g0, reg1);
m_assembler.or_r(SparcRegisters::g3, SparcRegisters::g0, reg2);
}
void signExtend32ToPtr(RegisterID src, RegisterID dest)
{
if (src != dest)
move(src, dest);
}
void zeroExtend32ToPtr(RegisterID src, RegisterID dest)
{
if (src != dest)
move(src, dest);
}
Jump branch8(Condition cond, Address left, Imm32 right)
{
load8(left, SparcRegisters::g2);
return branch32(cond, SparcRegisters::g2, right);
}
Jump branch32_force32(Condition cond, RegisterID left, TrustedImm32 right)
{
m_assembler.move_nocheck(right.m_value, SparcRegisters::g3);
m_assembler.subcc_r(left, SparcRegisters::g3, SparcRegisters::g0);
return Jump(m_assembler.branch(SparcCondition(cond)));
}
Jump branch32FixedLength(Condition cond, RegisterID left, TrustedImm32 right)
{
m_assembler.move_nocheck(right.m_value, SparcRegisters::g2);
return branch32(cond, left, SparcRegisters::g2);
}
Jump branch32WithPatch(Condition cond, RegisterID left, TrustedImm32 right, DataLabel32 &dataLabel)
{
// Always use move_nocheck, since the value is to be patched.
dataLabel = DataLabel32(this);
m_assembler.move_nocheck(right.m_value, SparcRegisters::g3);
m_assembler.subcc_r(left, SparcRegisters::g3, SparcRegisters::g0);
return Jump(m_assembler.branch(SparcCondition(cond)));
}
Jump branch32(Condition cond, RegisterID left, RegisterID right)
{
m_assembler.subcc_r(left, right, SparcRegisters::g0);
return Jump(m_assembler.branch(SparcCondition(cond)));
}
Jump branch32(Condition cond, RegisterID left, TrustedImm32 right)
{
if (m_assembler.isimm13(right.m_value))
m_assembler.subcc_imm(left, right.m_value, SparcRegisters::g0);
else {
m_assembler.move_nocheck(right.m_value, SparcRegisters::g3);
m_assembler.subcc_r(left, SparcRegisters::g3, SparcRegisters::g0);
}
return Jump(m_assembler.branch(SparcCondition(cond)));
}
Jump branch32(Condition cond, RegisterID left, Address right)
{
load32(right, SparcRegisters::g2);
return branch32(cond, left, SparcRegisters::g2);
}
Jump branch32(Condition cond, Address left, RegisterID right)
{
load32(left, SparcRegisters::g2);
return branch32(cond, SparcRegisters::g2, right);
}
Jump branch32(Condition cond, Address left, TrustedImm32 right)
{
load32(left, SparcRegisters::g2);
return branch32(cond, SparcRegisters::g2, right);
}
Jump branch32(Condition cond, BaseIndex left, TrustedImm32 right)
{
load32(left, SparcRegisters::g2);
return branch32(cond, SparcRegisters::g2, right);
}
Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, TrustedImm32 right)
{
load32WithUnalignedHalfWords(left, SparcRegisters::g4);
return branch32(cond, SparcRegisters::g4, right);
}
Jump branch16(Condition cond, BaseIndex left, RegisterID right)
{
(void)(cond);
(void)(left);
(void)(right);
ASSERT_NOT_REACHED();
return jump();
}
Jump branch16(Condition cond, BaseIndex left, Imm32 right)
{
load16(left, SparcRegisters::g3);
move(right, SparcRegisters::g2);
m_assembler.subcc_r(SparcRegisters::g3, SparcRegisters::g2, SparcRegisters::g0);
return Jump(m_assembler.branch(SparcCondition(cond)));
}
Jump branchTest8(Condition cond, Address address, Imm32 mask = Imm32(-1))
{
load8(address, SparcRegisters::g2);
return branchTest32(cond, SparcRegisters::g2, mask);
}
Jump branchTest32(Condition cond, RegisterID reg, RegisterID mask)
{
m_assembler.andcc_r(reg, mask, SparcRegisters::g0);
return Jump(m_assembler.branch(SparcCondition(cond)));
}
Jump branchTest32(Condition cond, RegisterID reg, Imm32 mask = Imm32(-1))
{
if (m_assembler.isimm13(mask.m_value))
m_assembler.andcc_imm(reg, mask.m_value, SparcRegisters::g0);
else {
m_assembler.move_nocheck(mask.m_value, SparcRegisters::g3);
m_assembler.andcc_r(reg, SparcRegisters::g3, SparcRegisters::g0);
}
return Jump(m_assembler.branch(SparcCondition(cond)));
}
Jump branchTest32(Condition cond, Address address, Imm32 mask = Imm32(-1))
{
load32(address, SparcRegisters::g2);
return branchTest32(cond, SparcRegisters::g2, mask);
}
Jump branchTest32(Condition cond, BaseIndex address, Imm32 mask = Imm32(-1))
{
// FIXME. branchTest32 only used by PolyIC.
// PolyIC is not enabled for sparc now.
ASSERT(0);
return jump();
}
Jump jump()
{
return Jump(m_assembler.jmp());
}
void jump(RegisterID target)
{
m_assembler.jmpl_r(SparcRegisters::g0, target, SparcRegisters::g0);
m_assembler.nop();
}
void jump(Address address)
{
load32(address, SparcRegisters::g2);
m_assembler.jmpl_r(SparcRegisters::g2, SparcRegisters::g0, SparcRegisters::g0);
m_assembler.nop();
}
void jump(BaseIndex address)
{
load32(address, SparcRegisters::g2);
m_assembler.jmpl_r(SparcRegisters::g2, SparcRegisters::g0, SparcRegisters::g0);
m_assembler.nop();
}
Jump branchAdd32(Condition cond, RegisterID src, RegisterID dest)
{
ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
m_assembler.addcc_r(src, dest, dest);
return Jump(m_assembler.branch(SparcCondition(cond)));
}
Jump branchAdd32(Condition cond, Imm32 imm, RegisterID dest)
{
ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
if (m_assembler.isimm13(imm.m_value))
m_assembler.addcc_imm(dest, imm.m_value, dest);
else {
m_assembler.move_nocheck(imm.m_value, SparcRegisters::g3);
m_assembler.addcc_r(dest, SparcRegisters::g3, dest);
}
return Jump(m_assembler.branch(SparcCondition(cond)));
}
Jump branchAdd32(Condition cond, Address src, RegisterID dest)
{
ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
load32(src, SparcRegisters::g2);
return branchAdd32(cond, SparcRegisters::g2, dest);
}
void mull32(RegisterID src1, RegisterID src2, RegisterID dest)
{
m_assembler.smulcc_r(src1, src2, dest);
}
Jump branchMul32(Condition cond, RegisterID src, RegisterID dest)
{
ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
m_assembler.smulcc_r(src, dest, dest);
if (cond == Overflow) {
m_assembler.rdy(SparcRegisters::g2);
m_assembler.sra_imm(dest, 31, SparcRegisters::g3);
m_assembler.subcc_r(SparcRegisters::g2, SparcRegisters::g3, SparcRegisters::g2);
cond = NotEqual;
}
return Jump(m_assembler.branch(SparcCondition(cond)));
}
Jump branchMul32(Condition cond, Imm32 imm, RegisterID src, RegisterID dest)
{
ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
if (m_assembler.isimm13(imm.m_value))
m_assembler.smulcc_imm(src, imm.m_value, dest);
else {
m_assembler.move_nocheck(imm.m_value, SparcRegisters::g3);
m_assembler.smulcc_r(src, SparcRegisters::g3, dest);
}
if (cond == Overflow) {
m_assembler.rdy(SparcRegisters::g2);
m_assembler.sra_imm(dest, 31, SparcRegisters::g3);
m_assembler.subcc_r(SparcRegisters::g2, SparcRegisters::g3, SparcRegisters::g2);
cond = NotEqual;
}
return Jump(m_assembler.branch(SparcCondition(cond)));
}
Jump branchMul32(Condition cond, Address src, RegisterID dest)
{
ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
load32(src, SparcRegisters::g2);
return branchMul32(cond, SparcRegisters::g2, dest);
}
Jump branchSub32(Condition cond, RegisterID src, RegisterID dest)
{
ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
m_assembler.subcc_r(dest, src, dest);
return Jump(m_assembler.branch(SparcCondition(cond)));
}
Jump branchSub32(Condition cond, Imm32 imm, RegisterID dest)
{
ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
sub32(imm, dest);
return Jump(m_assembler.branch(SparcCondition(cond)));
}
Jump branchSub32(Condition cond, Address src, RegisterID dest)
{
ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
load32(src, SparcRegisters::g2);
return branchSub32(cond, SparcRegisters::g2, dest);
}
Jump branchSub32(Condition cond, Imm32 imm, Address dest)
{
ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
sub32(imm, dest);
return Jump(m_assembler.branch(SparcCondition(cond)));
}
Jump branchNeg32(Condition cond, RegisterID srcDest)
{
ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
neg32(srcDest);
return Jump(m_assembler.branch(SparcCondition(cond)));
}
Jump branchOr32(Condition cond, RegisterID src, RegisterID dest)
{
ASSERT((cond == Signed) || (cond == Zero) || (cond == NonZero));
m_assembler.orcc_r(src, dest, dest);
return Jump(m_assembler.branch(SparcCondition(cond)));
}
void breakpoint()
{
m_assembler.ta_imm(8);
}
Call nearCall()
{
return Call(m_assembler.call(), Call::LinkableNear);
}
Call call(RegisterID target)
{
m_assembler.jmpl_r(target, SparcRegisters::g0, SparcRegisters::o7);
m_assembler.nop();
JmpSrc jmpSrc;
return Call(jmpSrc, Call::None);
}
void call(Address address)
{
if (m_assembler.isimm13(address.offset)) {
m_assembler.jmpl_imm(address.base, address.offset, SparcRegisters::o7);
m_assembler.nop();
} else {
m_assembler.move_nocheck(address.offset, SparcRegisters::g3);
m_assembler.jmpl_r(address.base, SparcRegisters::g3, SparcRegisters::o7);
m_assembler.nop();
}
}
void ret()
{
m_assembler.jmpl_imm(SparcRegisters::i7, 8, SparcRegisters::g0);
m_assembler.nop();
}
void ret_and_restore()
{
m_assembler.jmpl_imm(SparcRegisters::i7, 8, SparcRegisters::g0);
m_assembler.restore_r(SparcRegisters::g0, SparcRegisters::g0, SparcRegisters::g0);
}
void save(Imm32 size)
{
if (m_assembler.isimm13(size.m_value)) {
m_assembler.save_imm(SparcRegisters::sp, size.m_value, SparcRegisters::sp);
} else {
m_assembler.move_nocheck(size.m_value, SparcRegisters::g3);
m_assembler.save_r(SparcRegisters::sp, SparcRegisters::g3, SparcRegisters::sp);
}
}
void set32(Condition cond, Address left, RegisterID right, RegisterID dest)
{
load32(left, SparcRegisters::g2);
set32(cond, SparcRegisters::g2, right, dest);
}
void set32(Condition cond, RegisterID left, Address right, RegisterID dest)
{
load32(right, SparcRegisters::g2);
set32(cond, left, SparcRegisters::g2, dest);
}
void set32(Condition cond, RegisterID left, RegisterID right, RegisterID dest)
{
m_assembler.subcc_r(left, right, SparcRegisters::g0);
m_assembler.or_imm(SparcRegisters::g0, 0, dest);
m_assembler.movcc_imm(1, dest, SparcCondition(cond));
}
void set32(Condition cond, RegisterID left, Imm32 right, RegisterID dest)
{
if (m_assembler.isimm13(right.m_value))
m_assembler.subcc_imm(left, right.m_value, SparcRegisters::g0);
else {
m_assembler.move_nocheck(right.m_value, SparcRegisters::g3);
m_assembler.subcc_r(left, SparcRegisters::g3, SparcRegisters::g0);
}
m_assembler.or_imm(SparcRegisters::g0, 0, dest);
m_assembler.movcc_imm(1, dest, SparcCondition(cond));
}
void set32(Condition cond, Address left, Imm32 right, RegisterID dest)
{
load32(left, SparcRegisters::g2);
set32(cond, SparcRegisters::g2, right, dest);
}
void set8(Condition cond, RegisterID left, RegisterID right, RegisterID dest)
{
// Sparc does not have byte register.
set32(cond, left, right, dest);
}
void set8(Condition cond, Address left, RegisterID right, RegisterID dest)
{
// Sparc doesn't have byte registers
load32(left, SparcRegisters::g2);
set32(cond, SparcRegisters::g2, right, dest);
}
void set8(Condition cond, RegisterID left, Imm32 right, RegisterID dest)
{
// Sparc does not have byte register.
set32(cond, left, right, dest);
}
void setTest32(Condition cond, Address address, Imm32 mask, RegisterID dest)
{
load32(address, SparcRegisters::g2);
if (m_assembler.isimm13(mask.m_value))
m_assembler.andcc_imm(SparcRegisters::g2, mask.m_value, SparcRegisters::g0);
else {
m_assembler.move_nocheck(mask.m_value, SparcRegisters::g3);
m_assembler.andcc_r(SparcRegisters::g3, SparcRegisters::g2, SparcRegisters::g0);
}
m_assembler.or_imm(SparcRegisters::g0, 0, dest);
m_assembler.movcc_imm(1, dest, SparcCondition(cond));
}
void setTest8(Condition cond, Address address, Imm32 mask, RegisterID dest)
{
// Sparc does not have byte register.
setTest32(cond, address, mask, dest);
}
void lea(Address address, RegisterID dest)
{
if (m_assembler.isimm13(address.offset))
m_assembler.add_imm(address.base, address.offset, dest);
else {
m_assembler.move_nocheck(address.offset, SparcRegisters::g3);
m_assembler.add_r(address.base, SparcRegisters::g3, dest);
}
}
void lea(BaseIndex address, RegisterID dest)
{
// lea only used by PolyIC.
// PolyIC is not enabled for sparc now.
ASSERT(0);
}
void add32(Imm32 imm, AbsoluteAddress address)
{
load32(address.m_ptr, SparcRegisters::g2);
add32(imm, SparcRegisters::g2);
store32(SparcRegisters::g2, address.m_ptr);
}
void sub32(TrustedImm32 imm, AbsoluteAddress address)
{
load32(address.m_ptr, SparcRegisters::g2);
sub32(imm, SparcRegisters::g2);
store32(SparcRegisters::g2, address.m_ptr);
}
void load32(const void* address, RegisterID dest)
{
m_assembler.move_nocheck((int)address, SparcRegisters::g3);
m_assembler.lduw_r(SparcRegisters::g3, SparcRegisters::g0, dest);
}
Jump branch32(Condition cond, AbsoluteAddress left, RegisterID right)
{
load32(left.m_ptr, SparcRegisters::g2);
return branch32(cond, SparcRegisters::g2, right);
}
Jump branch32(Condition cond, AbsoluteAddress left, TrustedImm32 right)
{
load32(left.m_ptr, SparcRegisters::g2);
return branch32(cond, SparcRegisters::g2, right);
}
Call call()
{
m_assembler.rdpc(SparcRegisters::g2);
m_assembler.add_imm(SparcRegisters::g2, 32, SparcRegisters::g2);
m_assembler.stw_imm(SparcRegisters::g2, SparcRegisters::fp, -8);
Call cl = Call(m_assembler.call(), Call::Linkable);
m_assembler.lduw_imm(SparcRegisters::fp, -8, SparcRegisters::g2);
m_assembler.jmpl_imm(SparcRegisters::g2, 0, SparcRegisters::g0);
m_assembler.nop();
return cl;
}
Call tailRecursiveCall()
{
return Call::fromTailJump(jump());
}
Call makeTailRecursiveCall(Jump oldJump)
{
return Call::fromTailJump(oldJump);
}
DataLabelPtr moveWithPatch(TrustedImmPtr initialValue, RegisterID dest)
{
DataLabelPtr dataLabel(this);
Imm32 imm = Imm32(initialValue);
m_assembler.move_nocheck(imm.m_value, dest);
return dataLabel;
}
DataLabel32 moveWithPatch(TrustedImm32 initialValue, RegisterID dest)
{
DataLabel32 dataLabel(this);
m_assembler.move_nocheck(initialValue.m_value, dest);
return dataLabel;
}
Jump branchPtrWithPatch(Condition cond, RegisterID left, DataLabelPtr& dataLabel, ImmPtr initialRightValue = ImmPtr(0))
{
dataLabel = moveWithPatch(initialRightValue, SparcRegisters::g2);
Jump jump = branch32(cond, left, SparcRegisters::g2);
return jump;
}
Jump branchPtrWithPatch(Condition cond, Address left, DataLabelPtr& dataLabel, ImmPtr initialRightValue = ImmPtr(0))
{
load32(left, SparcRegisters::g2);
dataLabel = moveWithPatch(initialRightValue, SparcRegisters::g3);
Jump jump = branch32(cond, SparcRegisters::g3, SparcRegisters::g2);
return jump;
}
DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address)
{
DataLabelPtr dataLabel = moveWithPatch(initialValue, SparcRegisters::g2);
store32(SparcRegisters::g2, address);
return dataLabel;
}
DataLabelPtr storePtrWithPatch(ImplicitAddress address)
{
return storePtrWithPatch(ImmPtr(0), address);
}
// Floating point operators
bool supportsFloatingPoint() const
{
return true;
}
bool supportsFloatingPointTruncate() const
{
return true;
}
bool supportsFloatingPointSqrt() const
{
return true;
}
void moveDouble(FPRegisterID src, FPRegisterID dest)
{
m_assembler.fmovd_r(src, dest);
}
void loadFloat(BaseIndex address, FPRegisterID dest)
{
m_assembler.sll_imm(address.index, address.scale, SparcRegisters::g2);
add32(Imm32(address.offset), SparcRegisters::g2);
m_assembler.ldf_r(address.base, SparcRegisters::g2, dest);
m_assembler.fstod_r(dest, dest);
}
void loadFloat(ImplicitAddress address, FPRegisterID dest)
{
if (m_assembler.isimm13(address.offset))
m_assembler.ldf_imm(address.base, address.offset, dest);
else {
m_assembler.move_nocheck(address.offset, SparcRegisters::g3);
m_assembler.ldf_r(address.base, SparcRegisters::g3, dest);
}
m_assembler.fstod_r(dest, dest);
}
void loadFloat(const void* address, FPRegisterID dest)
{
m_assembler.move_nocheck((int)address, SparcRegisters::g3);
m_assembler.ldf_r(SparcRegisters::g3, SparcRegisters::g0, dest);
m_assembler.fstod_r(dest, dest);
}
void loadDouble(BaseIndex address, FPRegisterID dest)
{
m_assembler.sll_imm(address.index, address.scale, SparcRegisters::g2);
add32(Imm32(address.offset), SparcRegisters::g2);
m_assembler.ldf_r(address.base, SparcRegisters::g2, dest);
m_assembler.add_imm(SparcRegisters::g2, 4, SparcRegisters::g2);
m_assembler.ldf_r(address.base, SparcRegisters::g2, dest + 1);
}
void loadDouble(ImplicitAddress address, FPRegisterID dest)
{
m_assembler.move_nocheck(address.offset, SparcRegisters::g3);
m_assembler.ldf_r(address.base, SparcRegisters::g3, dest);
m_assembler.add_imm(SparcRegisters::g3, 4, SparcRegisters::g3);
m_assembler.ldf_r(address.base, SparcRegisters::g3, dest + 1);
}
DataLabelPtr loadDouble(const void* address, FPRegisterID dest)
{
DataLabelPtr dataLabel(this);
m_assembler.move_nocheck((int)address, SparcRegisters::g3);
m_assembler.ldf_imm(SparcRegisters::g3, 0, dest);
m_assembler.ldf_imm(SparcRegisters::g3, 4, dest + 1);
return dataLabel;
}
void storeFloat(FPRegisterID src, BaseIndex address)
{
m_assembler.sll_imm(address.index, address.scale, SparcRegisters::g2);
add32(Imm32(address.offset), SparcRegisters::g2);
m_assembler.stf_r(src, address.base, SparcRegisters::g2);
}
void storeFloat(FPRegisterID src, ImplicitAddress address)
{
if (m_assembler.isimm13(address.offset))
m_assembler.stf_imm(src, address.base, address.offset);
else {
m_assembler.move_nocheck(address.offset, SparcRegisters::g3);
m_assembler.stf_r(src, address.base, SparcRegisters::g3);
}
}
void storeFloat(ImmDouble imm, Address address)
{
union {
float f;
uint32_t u32;
} u;
u.f = imm.u.d;
store32(Imm32(u.u32), address);
}
void storeFloat(ImmDouble imm, BaseIndex address)
{
union {
float f;
uint32_t u32;
} u;
u.f = imm.u.d;
store32(Imm32(u.u32), address);
}
void storeDouble(FPRegisterID src, BaseIndex address)
{
m_assembler.sll_imm(address.index, address.scale, SparcRegisters::g2);
add32(Imm32(address.offset), SparcRegisters::g2);
m_assembler.stf_r(src, address.base, SparcRegisters::g2);
m_assembler.add_imm(SparcRegisters::g2, 4, SparcRegisters::g2);
m_assembler.stf_r(src + 1, address.base, SparcRegisters::g2);
}
void storeDouble(FPRegisterID src, ImplicitAddress address)
{
if (m_assembler.isimm13(address.offset + 4)) {
m_assembler.stf_imm(src, address.base, address.offset);
m_assembler.stf_imm(src + 1, address.base, address.offset + 4);
} else {
m_assembler.move_nocheck(address.offset, SparcRegisters::g3);
m_assembler.stf_r(src, address.base, SparcRegisters::g3);
m_assembler.add_imm(SparcRegisters::g3, 4, SparcRegisters::g3);
m_assembler.stf_r(src + 1, address.base, SparcRegisters::g3);
}
}
void storeDouble(ImmDouble imm, Address address)
{
store32(Imm32(imm.u.s.msb), address);
store32(Imm32(imm.u.s.lsb), Address(address.base, address.offset + 4));
}
void storeDouble(ImmDouble imm, BaseIndex address)
{
store32(Imm32(imm.u.s.msb), address);
store32(Imm32(imm.u.s.lsb),
BaseIndex(address.base, address.index, address.scale, address.offset + 4));
}
void addDouble(FPRegisterID src, FPRegisterID dest)
{
m_assembler.faddd_r(src, dest, dest);
}
void addDouble(Address src, FPRegisterID dest)
{
loadDouble(src, SparcRegisters::f30);
m_assembler.faddd_r(SparcRegisters::f30, dest, dest);
}
void divDouble(FPRegisterID src, FPRegisterID dest)
{
m_assembler.fdivd_r(dest, src, dest);
}
void divDouble(Address src, FPRegisterID dest)
{
loadDouble(src, SparcRegisters::f30);
m_assembler.fdivd_r(dest, SparcRegisters::f30, dest);
}
void subDouble(FPRegisterID src, FPRegisterID dest)
{
m_assembler.fsubd_r(dest, src, dest);
}
void subDouble(Address src, FPRegisterID dest)
{
loadDouble(src, SparcRegisters::f30);
m_assembler.fsubd_r(dest, SparcRegisters::f30, dest);
}
void mulDouble(FPRegisterID src, FPRegisterID dest)
{
m_assembler.fmuld_r(src, dest, dest);
}
void mulDouble(Address src, FPRegisterID dest)
{
loadDouble(src, SparcRegisters::f30);
m_assembler.fmuld_r(SparcRegisters::f30, dest, dest);
}
void absDouble(FPRegisterID src, FPRegisterID dest)
{
m_assembler.fabsd_r(src, dest);
}
void sqrtDouble(FPRegisterID src, FPRegisterID dest)
{
m_assembler.fsqrtd_r(src, dest);
}
void negDouble(FPRegisterID src, FPRegisterID dest)
{
m_assembler.fnegd_r(src, dest);
}
void convertUInt32ToDouble(RegisterID src, FPRegisterID dest)
{
m_assembler.move_nocheck(0x43300000, SparcRegisters::g1);
m_assembler.stw_imm(SparcRegisters::g1, SparcRegisters::sp, 0x60);
m_assembler.stw_imm(src, SparcRegisters::sp, 0x64);
m_assembler.ldf_imm(SparcRegisters::sp, 0x60, SparcRegisters::f30);
m_assembler.ldf_imm(SparcRegisters::sp, 0x64, SparcRegisters::f31);
m_assembler.stw_imm(SparcRegisters::g0, SparcRegisters::sp, 0x64);
m_assembler.ldf_imm(SparcRegisters::sp, 0x60, dest);
m_assembler.ldf_imm(SparcRegisters::sp, 0x64, dest + 1);
m_assembler.fsubd_r(SparcRegisters::f30, dest, dest);
m_assembler.fabss_r(dest, dest);
}
void convertInt32ToDouble(RegisterID src, FPRegisterID dest)
{
m_assembler.stw_imm(src, SparcRegisters::sp, 0x60);
m_assembler.ldf_imm(SparcRegisters::sp, 0x60, dest);
m_assembler.fitod_r(dest, dest);
}
void convertInt32ToDouble(Address address, FPRegisterID dest)
{
if (m_assembler.isimm13(address.offset))
m_assembler.ldf_imm(address.base, address.offset, dest);
else {
m_assembler.move_nocheck(address.offset, SparcRegisters::g3);
m_assembler.ldf_r(address.base, SparcRegisters::g3, dest);
}
m_assembler.fitod_r(dest, dest);
}
void convertInt32ToDouble(AbsoluteAddress src, FPRegisterID dest)
{
m_assembler.move_nocheck((int)src.m_ptr, SparcRegisters::g3);
m_assembler.ldf_r(SparcRegisters::g3, SparcRegisters::g0, dest);
m_assembler.fitod_r(dest, dest);
}
void fastLoadDouble(RegisterID lo, RegisterID hi, FPRegisterID fpReg)
{
m_assembler.stw_imm(lo, SparcRegisters::sp, 0x64);
m_assembler.stw_imm(hi, SparcRegisters::sp, 0x60);
m_assembler.ldf_imm(SparcRegisters::sp, 0x60, fpReg);
m_assembler.ldf_imm(SparcRegisters::sp, 0x64, fpReg + 1);
}
void convertDoubleToFloat(FPRegisterID src, FPRegisterID dest)
{
m_assembler.fdtos_r(src, dest);
}
void breakDoubleTo32(FPRegisterID srcDest, RegisterID typeReg, RegisterID dataReg) {
// We don't assume stack is aligned to 8.
// Always using stf, ldf instead of stdf, lddf.
m_assembler.stf_imm(srcDest, SparcRegisters::sp, 0x60);
m_assembler.stf_imm(srcDest + 1, SparcRegisters::sp, 0x64);
m_assembler.lduw_imm(SparcRegisters::sp, 0x60, typeReg);
m_assembler.lduw_imm(SparcRegisters::sp, 0x64, dataReg);
}
Jump branchDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right)
{
m_assembler.fcmpd_r(left, right);
return Jump(m_assembler.fbranch(SparcDoubleCondition(cond)));
}
// Truncates 'src' to an integer, and places the resulting 'dest'.
// If the result is not representable as a 32 bit value, branch.
// May also branch for some values that are representable in 32 bits
// (specifically, in this case, INT_MIN).
Jump branchTruncateDoubleToInt32(FPRegisterID src, RegisterID dest)
{
m_assembler.fdtoi_r(src, SparcRegisters::f30);
m_assembler.stf_imm(SparcRegisters::f30, SparcRegisters::sp, 0x60);
m_assembler.lduw_imm(SparcRegisters::sp, 0x60, dest);
m_assembler.or_r(SparcRegisters::g0, SparcRegisters::g0, SparcRegisters::g2);
m_assembler.move_nocheck(0x80000000, SparcRegisters::g3);
m_assembler.subcc_r(SparcRegisters::g3, dest, SparcRegisters::g0);
m_assembler.movcc_imm(1, SparcRegisters::g2, SparcCondition(Equal));
m_assembler.move_nocheck(0x7fffffff, SparcRegisters::g3);
m_assembler.subcc_r(SparcRegisters::g3, dest, SparcRegisters::g0);
m_assembler.movcc_imm(1, SparcRegisters::g2, SparcCondition(Equal));
return branch32(Equal, SparcRegisters::g2, Imm32(1));
}
// Convert 'src' to an integer, and places the resulting 'dest'.
// If the result is not representable as a 32 bit value, branch.
// May also branch for some values that are representable in 32 bits
// (specifically, in this case, 0).
void branchConvertDoubleToInt32(FPRegisterID src, RegisterID dest, JumpList& failureCases, FPRegisterID fpTemp)
{
m_assembler.fdtoi_r(src, SparcRegisters::f30);
m_assembler.stf_imm(SparcRegisters::f30, SparcRegisters::sp, 0x60);
m_assembler.lduw_imm(SparcRegisters::sp, 0x60, dest);
// Convert the integer result back to float & compare to the original value - if not equal or unordered (NaN) then jump.
m_assembler.fitod_r(SparcRegisters::f30, SparcRegisters::f30);
failureCases.append(branchDouble(DoubleNotEqualOrUnordered, src, SparcRegisters::f30));
// If the result is zero, it might have been -0.0, and 0.0 equals to -0.0
failureCases.append(branchTest32(Zero, dest));
}
void zeroDouble(FPRegisterID srcDest)
{
fastLoadDouble(SparcRegisters::g0, SparcRegisters::g0, srcDest);
}
protected:
SparcAssembler::Condition SparcCondition(Condition cond)
{
return static_cast<SparcAssembler::Condition>(cond);
}
SparcAssembler::DoubleCondition SparcDoubleCondition(DoubleCondition cond)
{
return static_cast<SparcAssembler::DoubleCondition>(cond);
}
private:
friend class LinkBuffer;
friend class RepatchBuffer;
static void linkCall(void* code, Call call, FunctionPtr function)
{
SparcAssembler::linkCall(code, call.m_jmp, function.value());
}
static void repatchCall(CodeLocationCall call, CodeLocationLabel destination)
{
SparcAssembler::relinkCall(call.dataLocation(), destination.executableAddress());
}
static void repatchCall(CodeLocationCall call, FunctionPtr destination)
{
SparcAssembler::relinkCall(call.dataLocation(), destination.executableAddress());
}
};
}
#endif // ENABLE(ASSEMBLER) && CPU(SPARC)
#endif /* assembler_assembler_MacroAssemblerSparc_h */