blob: 196f4d2b1e39225b49fb825feee47923312075ca [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_SparcAssembler_h
#define assembler_assembler_SparcAssembler_h
#include <assembler/wtf/Platform.h>
// Some debug code uses s(n)printf for instruction logging.
#include <stdio.h>
#if ENABLE_ASSEMBLER && WTF_CPU_SPARC
#include "AssemblerBufferWithConstantPool.h"
#include <assembler/wtf/Assertions.h>
#include "methodjit/Logging.h"
#define IPFX " %s"
#define ISPFX " "
#ifdef JS_METHODJIT_SPEW
# define MAYBE_PAD (isOOLPath ? "> " : "")
#else
# define MAYBE_PAD ""
#endif
namespace JSC {
typedef uint32_t SparcWord;
namespace SparcRegisters {
typedef enum {
g0 = 0, // g0 is always 0
g1 = 1, // g1 is a scratch register for v8
g2 = 2,
g3 = 3,
g4 = 4,
g5 = 5, // Reserved for system
g6 = 6, // Reserved for system
g7 = 7, // Reserved for system
o0 = 8,
o1 = 9,
o2 = 10,
o3 = 11,
o4 = 12,
o5 = 13,
o6 = 14, // SP
o7 = 15,
l0 = 16,
l1 = 17,
l2 = 18,
l3 = 19,
l4 = 20,
l5 = 21,
l6 = 22,
l7 = 23,
i0 = 24,
i1 = 25,
i2 = 26,
i3 = 27,
i4 = 28,
i5 = 29,
i6 = 30, // FP
i7 = 31,
sp = o6,
fp = i6
} RegisterID;
typedef enum {
f0 = 0,
f1 = 1,
f2 = 2,
f3 = 3,
f4 = 4,
f5 = 5,
f6 = 6,
f7 = 7,
f8 = 8,
f9 = 9,
f10 = 10,
f11 = 11,
f12 = 12,
f13 = 13,
f14 = 14,
f15 = 15,
f16 = 16,
f17 = 17,
f18 = 18,
f19 = 19,
f20 = 20,
f21 = 21,
f22 = 22,
f23 = 23,
f24 = 24,
f25 = 25,
f26 = 26,
f27 = 27,
f28 = 28,
f29 = 29,
f30 = 30,
f31 = 31
} FPRegisterID;
} // namespace SparcRegisters
class SparcAssembler : public GenericAssembler {
public:
typedef SparcRegisters::RegisterID RegisterID;
typedef SparcRegisters::FPRegisterID FPRegisterID;
AssemblerBuffer m_buffer;
bool oom() const { return m_buffer.oom(); }
// Sparc conditional constants
typedef enum {
ConditionE = 0x1, // Zero
ConditionLE = 0x2,
ConditionL = 0x3,
ConditionLEU = 0x4,
ConditionCS = 0x5,
ConditionNEG = 0x6,
ConditionVS = 0x7,
ConditionA = 0x8, // branch_always
ConditionNE = 0x9, // Non-zero
ConditionG = 0xa,
ConditionGE = 0xb,
ConditionGU = 0xc,
ConditionCC = 0xd,
ConditionVC = 0xf
} Condition;
typedef enum {
DoubleConditionNE = 0x1,
DoubleConditionUL = 0x3,
DoubleConditionL = 0x4,
DoubleConditionUG = 0x5,
DoubleConditionG = 0x6,
DoubleConditionE = 0x9,
DoubleConditionUE = 0xa,
DoubleConditionGE = 0xb,
DoubleConditionUGE = 0xc,
DoubleConditionLE = 0xd,
DoubleConditionULE = 0xe
} DoubleCondition;
typedef enum {
BranchOnCondition,
BranchOnDoubleCondition
} BranchType;
class JmpSrc {
friend class SparcAssembler;
public:
JmpSrc()
: m_offset(-1)
{
}
private:
JmpSrc(int offset)
: m_offset(offset)
{
}
int m_offset;
};
class JmpDst {
friend class SparcAssembler;
public:
JmpDst()
: m_offset(-1)
, m_used(false)
{
}
bool isUsed() const { return m_used; }
void used() { m_used = true; }
bool isValid() const { return m_offset != -1; }
private:
JmpDst(int offset)
: m_offset(offset)
, m_used(false)
{
ASSERT(m_offset == offset);
}
int m_used : 1;
signed int m_offset : 31;
};
// Instruction formating
void format_2_1(int rd, int op2, int imm22)
{
m_buffer.putInt(rd << 25 | op2 << 22 | (imm22 & 0x3FFFFF));
}
void format_2_2(int a, int cond, int op2, int disp22)
{
format_2_1((a & 0x1) << 4 | (cond & 0xF), op2, disp22);
}
void format_2_3(int a, int cond, int op2, int cc1, int cc0, int p, int disp19)
{
format_2_2(a, cond, op2, (cc1 & 0x1) << 21 | (cc0 & 0x1) << 20 | (p & 0x1) << 19 | (disp19 & 0x7FFFF));
}
void format_2_4(int a, int rcond, int op2, int d16hi, int p, int rs1, int d16lo)
{
format_2_2(a, (rcond & 0x7), op2, (d16hi & 0x3) << 20 | (p & 0x1) << 19 | rs1 << 14 | (d16lo & 0x3FFF));
}
void format_3(int op1, int rd, int op3, int bits19)
{
m_buffer.putInt(op1 << 30 | rd << 25 | op3 << 19 | (bits19 & 0x7FFFF));
}
void format_3_1(int op1, int rd, int op3, int rs1, int bit8, int rs2)
{
format_3(op1, rd, op3, rs1 << 14 | (bit8 & 0xFF) << 5 | rs2);
}
void format_3_1_imm(int op1, int rd, int op3, int rs1, int simm13)
{
format_3(op1, rd, op3, rs1 << 14 | 1 << 13 | (simm13 & 0x1FFF));
}
void format_3_2(int op1, int rd, int op3, int rs1, int rcond, int rs2)
{
format_3(op1, rd, op3, rs1 << 14 | (rcond & 0x3) << 10 | rs2);
}
void format_3_2_imm(int op1, int rd, int op3, int rs1, int rcond, int simm10)
{
format_3(op1, rd, op3, rs1 << 14 | 1 << 13 | (rcond & 0x3) << 10 | (simm10 & 0x1FFF));
}
void format_3_3(int op1, int rd, int op3, int rs1, int cmask, int mmask)
{
format_3(op1, rd, op3, rs1 << 14 | 1 << 13 | (cmask & 0x7) << 5 | (mmask & 0xF));
}
void format_3_4(int op1, int rd, int op3, int bits19)
{
format_3(op1, rd, op3, bits19);
}
void format_3_5(int op1, int rd, int op3, int rs1, int x, int rs2)
{
format_3(op1, rd, op3, rs1 << 14 | (x & 0x1) << 12 | rs2);
}
void format_3_6(int op1, int rd, int op3, int rs1, int shcnt32)
{
format_3(op1, rd, op3, rs1 << 14 | 1 << 13 | (shcnt32 & 0x1F));
}
void format_3_7(int op1, int rd, int op3, int rs1, int shcnt64)
{
format_3(op1, rd, op3, rs1 << 14 | 1 << 13 | 1 << 12 | (shcnt64 & 0x3F));
}
void format_3_8(int op1, int rd, int op3, int rs1, int bits9, int rs2)
{
format_3(op1, rd, op3, rs1 << 14 | (bits9 & 0x1FF) << 5 | rs2);
}
void format_3_9(int op1, int cc1, int cc0, int op3, int rs1, int bits9, int rs2)
{
format_3(op1, (cc1 & 0x1) << 1 | (cc0 & 0x1), op3, rs1 << 14 | (bits9 & 0x1FF) << 5 | rs2);
}
void format_4_1(int rd, int op3, int rs1, int cc1, int cc0, int rs2)
{
format_3(2, rd, op3, rs1 << 14 | (cc1 & 0x1) << 12 | (cc0 & 0x1) << 11 | rs2);
}
void format_4_1_imm(int rd, int op3, int rs1, int cc1, int cc0, int simm11)
{
format_3(2, rd, op3, rs1 << 14 | (cc1 & 0x1) << 12 | 1 << 13 |(cc0 & 0x1) << 11 | (simm11 & 0x7FF));
}
void format_4_2(int rd, int op3, int cc2, int cond, int cc1, int cc0, int rs2)
{
format_3(2, rd, op3, (cc2 & 0x1) << 18 | (cond & 0xF) << 14 | (cc1 & 0x1) << 12 | (cc0 & 0x1) << 11 | rs2);
}
void format_4_2_imm(int rd, int op3, int cc2, int cond, int cc1, int cc0, int simm11)
{
format_3(2, rd, op3, (cc2 & 0x1) << 18 | (cond & 0xF) << 14 | 1 << 13 | (cc1 & 0x1) << 12 | (cc0 & 0x1) << 11 | (simm11 & 0x7FF));
}
void format_4_3(int rd, int op3, int rs1, int cc1, int cc0, int swap_trap)
{
format_3(2, rd, op3, rs1 << 14 | 1 << 13 | (cc1 & 0x1) << 12 | (cc0 & 0x1) << 11 | (swap_trap & 0x7F));
}
void format_4_4(int rd, int op3, int rs1, int rcond, int opf_low, int rs2)
{
format_3(2, rd, op3, rs1 << 14 | (rcond & 0x7) << 10 | (opf_low & 0x1F) << 5 | rs2);
}
void format_4_5(int rd, int op3, int cond, int opf_cc, int opf_low, int rs2)
{
format_3(2, rd, op3, (cond & 0xF) << 14 | (opf_cc & 0x7) << 11 | (opf_low & 0x3F) << 5 | rs2);
}
void addcc_r(int rs1, int rs2, int rd)
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "addcc %s, %s, %s\n", MAYBE_PAD,
nameGpReg(rs1), nameGpReg(rs2), nameGpReg(rd));
format_3_1(2, rd, 0x10, rs1, 0, rs2);
}
void addcc_imm(int rs1, int simm13, int rd)
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "addcc %s, %d, %s\n", MAYBE_PAD,
nameGpReg(rs1), simm13, nameGpReg(rd));
format_3_1_imm(2, rd, 0x10, rs1, simm13);
}
void add_r(int rs1, int rs2, int rd)
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "add %s, %s, %s\n", MAYBE_PAD,
nameGpReg(rs1), nameGpReg(rs2), nameGpReg(rd));
format_3_1(2, rd, 0, rs1, 0, rs2);
}
void add_imm(int rs1, int simm13, int rd)
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "add %s, %d, %s\n", MAYBE_PAD,
nameGpReg(rs1), simm13, nameGpReg(rd));
format_3_1_imm(2, rd, 0, rs1, simm13);
}
void andcc_r(int rs1, int rs2, int rd)
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "andcc %s, %s, %s\n", MAYBE_PAD,
nameGpReg(rs1), nameGpReg(rs2), nameGpReg(rd));
format_3_1(2, rd, 0x11, rs1, 0, rs2);
}
void andcc_imm(int rs1, int simm13, int rd)
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "andcc %s, %d, %s\n", MAYBE_PAD,
nameGpReg(rs1), simm13, nameGpReg(rd));
format_3_1_imm(2, rd, 0x11, rs1, simm13);
}
void or_r(int rs1, int rs2, int rd)
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "or %s, %s, %s\n", MAYBE_PAD,
nameGpReg(rs1), nameGpReg(rs2), nameGpReg(rd));
format_3_1(2, rd, 0x2, rs1, 0, rs2);
}
void or_imm(int rs1, int simm13, int rd)
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "or %s, %d, %s\n", MAYBE_PAD,
nameGpReg(rs1), simm13, nameGpReg(rd));
format_3_1_imm(2, rd, 0x2, rs1, simm13);
}
// sethi %hi(imm22) rd
void sethi(int imm22, int rd)
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "sethi %%hi(0x%x), %s\n", MAYBE_PAD,
imm22, nameGpReg(rd));
format_2_1(rd, 0x4, (imm22 >> 10));
}
void sll_r(int rs1, int rs2, int rd)
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "sll %s, %s, %s\n", MAYBE_PAD,
nameGpReg(rs1), nameGpReg(rs2), nameGpReg(rd));
format_3_5(2, rd, 0x25, rs1, 0, rs2);
}
void sll_imm(int rs1, int shcnt32, int rd)
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "sll %s, %d, %s\n", MAYBE_PAD,
nameGpReg(rs1), shcnt32, nameGpReg(rd));
format_3_6(2, rd, 0x25, rs1, shcnt32);
}
void sra_r(int rs1, int rs2, int rd)
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "sra %s, %s, %s\n", MAYBE_PAD,
nameGpReg(rs1), nameGpReg(rs2), nameGpReg(rd));
format_3_5(2, rd, 0x27, rs1, 0, rs2);
}
void sra_imm(int rs1, int shcnt32, int rd)
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "sra %s, %d, %s\n", MAYBE_PAD,
nameGpReg(rs1), shcnt32, nameGpReg(rd));
format_3_6(2, rd, 0x27, rs1, shcnt32);
}
void srl_r(int rs1, int rs2, int rd)
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "srl %s, %s, %s\n", MAYBE_PAD,
nameGpReg(rs1), nameGpReg(rs2), nameGpReg(rd));
format_3_5(2, rd, 0x26, rs1, 0, rs2);
}
void srl_imm(int rs1, int shcnt32, int rd)
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "srl %s, %d, %s\n", MAYBE_PAD,
nameGpReg(rs1), shcnt32, nameGpReg(rd));
format_3_6(2, rd, 0x26, rs1, shcnt32);
}
void subcc_r(int rs1, int rs2, int rd)
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "subcc %s, %s, %s\n", MAYBE_PAD,
nameGpReg(rs1), nameGpReg(rs2), nameGpReg(rd));
format_3_1(2, rd, 0x14, rs1, 0, rs2);
}
void subcc_imm(int rs1, int simm13, int rd)
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "subcc %s, %d, %s\n", MAYBE_PAD,
nameGpReg(rs1), simm13, nameGpReg(rd));
format_3_1_imm(2, rd, 0x14, rs1, simm13);
}
void orcc_r(int rs1, int rs2, int rd)
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "orcc %s, %s, %s\n", MAYBE_PAD,
nameGpReg(rs1), nameGpReg(rs2), nameGpReg(rd));
format_3_1(2, rd, 0x12, rs1, 0, rs2);
}
void orcc_imm(int rs1, int simm13, int rd)
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "orcc %s, %d, %s\n", MAYBE_PAD,
nameGpReg(rs1), simm13, nameGpReg(rd));
format_3_1_imm(2, rd, 0x12, rs1, simm13);
}
void xorcc_r(int rs1, int rs2, int rd)
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "xorcc %s, %s, %s\n", MAYBE_PAD,
nameGpReg(rs1), nameGpReg(rs2), nameGpReg(rd));
format_3_1(2, rd, 0x13, rs1, 0, rs2);
}
void xorcc_imm(int rs1, int simm13, int rd)
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "xorcc %s, %d, %s\n", MAYBE_PAD,
nameGpReg(rs1), simm13, nameGpReg(rd));
format_3_1_imm(2, rd, 0x13, rs1, simm13);
}
void xnorcc_r(int rs1, int rs2, int rd)
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "xnorcc %s, %s, %s\n", MAYBE_PAD,
nameGpReg(rs1), nameGpReg(rs2), nameGpReg(rd));
format_3_1(2, rd, 0x17, rs1, 0, rs2);
}
void xnorcc_imm(int rs1, int simm13, int rd)
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "xnorcc %s, %d, %s\n", MAYBE_PAD,
nameGpReg(rs1), simm13, nameGpReg(rd));
format_3_1_imm(2, rd, 0x17, rs1, simm13);
}
void smulcc_r(int rs1, int rs2, int rd)
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "smulcc %s, %s, %s\n", MAYBE_PAD,
nameGpReg(rs1), nameGpReg(rs2), nameGpReg(rd));
format_3_1(2, rd, 0x1b, rs1, 0, rs2);
}
void smulcc_imm(int rs1, int simm13, int rd)
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "smulcc %s, %d, %s\n", MAYBE_PAD,
nameGpReg(rs1), simm13, nameGpReg(rd));
format_3_1_imm(2, rd, 0x1b, rs1, simm13);
}
void ldsb_r(int rs1, int rs2, int rd)
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "ldsb [%s + %s], %s\n", MAYBE_PAD,
nameGpReg(rs1), nameGpReg(rs2), nameGpReg(rd));
format_3_1(3, rd, 0x9, rs1, 0, rs2);
}
void ldsb_imm(int rs1, int simm13, int rd)
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "ldsb [%s + %d], %s\n", MAYBE_PAD,
nameGpReg(rs1), simm13, nameGpReg(rd));
format_3_1_imm(3, rd, 0x9, rs1, simm13);
}
void ldub_r(int rs1, int rs2, int rd)
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "ldub [%s + %s], %s\n", MAYBE_PAD,
nameGpReg(rs1), nameGpReg(rs2), nameGpReg(rd));
format_3_1(3, rd, 0x1, rs1, 0, rs2);
}
void ldub_imm(int rs1, int simm13, int rd)
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "ldub [%s + %d], %s\n", MAYBE_PAD,
nameGpReg(rs1), simm13, nameGpReg(rd));
format_3_1_imm(3, rd, 0x1, rs1, simm13);
}
void lduw_r(int rs1, int rs2, int rd)
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "lduw [%s + %s], %s\n", MAYBE_PAD,
nameGpReg(rs1), nameGpReg(rs2), nameGpReg(rd));
format_3_1(3, rd, 0x0, rs1, 0, rs2);
}
void lduwa_r(int rs1, int rs2, int rd)
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "lduwa [%s + %s], %s\n", MAYBE_PAD,
nameGpReg(rs1), nameGpReg(rs2), nameGpReg(rd));
format_3_1(3, rd, 0x10, rs1, 0x82, rs2);
}
void lduw_imm(int rs1, int simm13, int rd)
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "lduw [%s + %d], %s\n", MAYBE_PAD,
nameGpReg(rs1), simm13, nameGpReg(rd));
format_3_1_imm(3, rd, 0x0, rs1, simm13);
}
void ldsh_r(int rs1, int rs2, int rd)
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "ldsh [%s + %s], %s\n", MAYBE_PAD,
nameGpReg(rs1), nameGpReg(rs2), nameGpReg(rd));
format_3_1(3, rd, 0xa, rs1, 0, rs2);
}
void ldsh_imm(int rs1, int simm13, int rd)
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "ldsh [%s + %d], %s\n", MAYBE_PAD,
nameGpReg(rs1), simm13, nameGpReg(rd));
format_3_1_imm(3, rd, 0xa, rs1, simm13);
}
void lduh_r(int rs1, int rs2, int rd)
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "lduh [%s + %s], %s\n", MAYBE_PAD,
nameGpReg(rs1), nameGpReg(rs2), nameGpReg(rd));
format_3_1(3, rd, 0x2, rs1, 0, rs2);
}
void lduh_imm(int rs1, int simm13, int rd)
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "lduh [%s + %d], %s\n", MAYBE_PAD,
nameGpReg(rs1), simm13, nameGpReg(rd));
format_3_1_imm(3, rd, 0x2, rs1, simm13);
}
void stb_r(int rd, int rs2, int rs1)
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "stb %s, [%s + %s]\n", MAYBE_PAD,
nameGpReg(rd), nameGpReg(rs1), nameGpReg(rs2));
format_3_1(3, rd, 0x5, rs1, 0, rs2);
}
void stb_imm(int rd, int rs1, int simm13)
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "stb %s, [%s + %d]\n", MAYBE_PAD,
nameGpReg(rd), nameGpReg(rs1), simm13);
format_3_1_imm(3, rd, 0x5, rs1, simm13);
}
void sth_r(int rd, int rs2, int rs1)
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "sth %s, [%s + %s]\n", MAYBE_PAD,
nameGpReg(rd), nameGpReg(rs1), nameGpReg(rs2));
format_3_1(3, rd, 0x6, rs1, 0, rs2);
}
void sth_imm(int rd, int rs1, int simm13)
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "sth %s, [%s + %d]\n", MAYBE_PAD,
nameGpReg(rd), nameGpReg(rs1), simm13);
format_3_1_imm(3, rd, 0x6, rs1, simm13);
}
void stw_r(int rd, int rs2, int rs1)
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "stw %s, [%s + %s]\n", MAYBE_PAD,
nameGpReg(rd), nameGpReg(rs1), nameGpReg(rs2));
format_3_1(3, rd, 0x4, rs1, 0, rs2);
}
void stw_imm(int rd, int rs1, int simm13)
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "stw %s, [%s + %d]\n", MAYBE_PAD,
nameGpReg(rd), nameGpReg(rs1), simm13);
format_3_1_imm(3, rd, 0x4, rs1, simm13);
}
void ldf_r(int rs1, int rs2, int rd)
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "ld [%s + %s], %s\n", MAYBE_PAD,
nameGpReg(rs1), nameGpReg(rs2), nameFpReg(rd));
format_3_1(3, rd, 0x20, rs1, 0, rs2);
}
void ldf_imm(int rs1, int simm13, int rd)
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "ld [%s + %d], %s\n", MAYBE_PAD,
nameGpReg(rs1), simm13, nameFpReg(rd));
format_3_1_imm(3, rd, 0x20, rs1, simm13);
}
void stf_r(int rd, int rs2, int rs1)
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "st %s, [%s + %s]\n", MAYBE_PAD,
nameFpReg(rd), nameGpReg(rs1), nameGpReg(rs2));
format_3_1(3, rd, 0x24, rs1, 0, rs2);
}
void stf_imm(int rd, int rs1, int simm13)
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "st %s, [%s + %d]\n", MAYBE_PAD,
nameFpReg(rd), nameGpReg(rs1), simm13);
format_3_1_imm(3, rd, 0x24, rs1, simm13);
}
void fmovd_r(int rs2, int rd)
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "fmovd %s, %s\n", MAYBE_PAD,
nameFpReg(rs2), nameFpReg(rd));
format_3_8(2, rd, 0x34, 0, 0x2, rs2);
}
void fcmpd_r(int rs1, int rs2)
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "fcmpd %s, %s\n", MAYBE_PAD,
nameFpReg(rs1), nameFpReg(rs2));
format_3_9(2, 0, 0, 0x35, rs1, 0x52, rs2);
}
void nop()
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "nop\n", MAYBE_PAD);
format_2_1(0, 0x4, 0);
}
void branch_con(Condition cond, int target)
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "b%s 0x%x\n", MAYBE_PAD,
nameICC(cond), target);
format_2_2(0, cond, 0x2, target);
}
void fbranch_con(DoubleCondition cond, int target)
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "fb%s 0x%x\n", MAYBE_PAD,
nameFCC(cond), target);
format_2_2(0, cond, 0x6, target);
}
void rdy(int rd)
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "rdy %s\n", MAYBE_PAD,
nameFpReg(rd));
format_3_1(2, rd, 0x28, 0, 0, 0);
}
void rdpc(int rd)
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "rdpc %s\n", MAYBE_PAD,
nameGpReg(rd));
format_3_1(2, rd, 0x28, 5, 0, 0);
}
void jmpl_r(int rs1, int rs2, int rd)
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "jmpl %s + %s, %s\n", MAYBE_PAD,
nameGpReg(rs1), nameGpReg(rs2), nameGpReg(rd));
format_3_1(2, rd, 0x38, rs1, 0, rs2);
}
void jmpl_imm(int rs1, int simm13, int rd)
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "jmpl %s + %d, %s\n", MAYBE_PAD,
nameGpReg(rs1), simm13, nameGpReg(rd));
format_3_1_imm(2, rd, 0x38, rs1, simm13);
}
void save_r(int rs1, int rs2, int rd)
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "save %s, %s, %s\n", MAYBE_PAD,
nameGpReg(rs1), nameGpReg(rs2), nameGpReg(rd));
format_3_1(2, rd, 0x3c, rs1, 0, rs2);
}
void save_imm(int rs1, int simm13, int rd)
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "save %s, %d, %s\n", MAYBE_PAD,
nameGpReg(rs1), simm13, nameGpReg(rd));
format_3_1_imm(2, rd, 0x3c, rs1, simm13);
}
void restore_r(int rs1, int rs2, int rd)
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "restore %s, %s, %s\n", MAYBE_PAD,
nameGpReg(rs1), nameGpReg(rs2), nameGpReg(rd));
format_3_1(2, rd, 0x3d, rs1, 0, rs2);
}
void ta_imm(int swap_trap)
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "ta %d\n", MAYBE_PAD,
swap_trap);
format_4_3(0x8, 0xa, 0, 0, 0, swap_trap);
}
void movcc_imm(int simm11, int rd, Condition cond)
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "mov%s %d, %s\n", MAYBE_PAD,
nameICC(cond), simm11, nameGpReg(rd));
format_4_2_imm(rd, 0x2c, 1, cond, 0, 0, simm11);
}
void fabss_r(int rs2, int rd)
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "fabss %s, %s\n", MAYBE_PAD,
nameFpReg(rs2), nameFpReg(rd));
format_3_8(2, rd, 0x34, 0, 0x9, rs2);
}
void faddd_r(int rs1, int rs2, int rd)
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "faddd %s, %s, %s\n", MAYBE_PAD,
nameFpReg(rs1), nameFpReg(rs2), nameFpReg(rd));
format_3_8(2, rd, 0x34, rs1, 0x42, rs2);
}
void fsubd_r(int rs1, int rs2, int rd)
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "fsubd %s, %s, %s\n", MAYBE_PAD,
nameFpReg(rs1), nameFpReg(rs2), nameFpReg(rd));
format_3_8(2, rd, 0x34, rs1, 0x46, rs2);
}
void fmuld_r(int rs1, int rs2, int rd)
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "fmuld %s, %s, %s\n", MAYBE_PAD,
nameFpReg(rs1), nameFpReg(rs2), nameFpReg(rd));
format_3_8(2, rd, 0x34, rs1, 0x4a, rs2);
}
void fdivd_r(int rs1, int rs2, int rd)
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "fdivd %s, %s, %s\n", MAYBE_PAD,
nameFpReg(rs1), nameFpReg(rs2), nameFpReg(rd));
format_3_8(2, rd, 0x34, rs1, 0x4e, rs2);
}
void fsqrtd_r(int rs2, int rd)
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "fsqartd %s, %s\n", MAYBE_PAD,
nameFpReg(rs2), nameFpReg(rd));
format_3_8(2, rd, 0x34, 0, 0x2a, rs2);
}
void fabsd_r(int rs2, int rd)
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "fabsd %s, %s\n", MAYBE_PAD,
nameFpReg(rs2), nameFpReg(rd));
format_3_8(2, rd, 0x34, 0, 0x0a, rs2);
}
void fnegd_r(int rs2, int rd)
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "fnegd %s, %s\n", MAYBE_PAD,
nameFpReg(rs2), nameFpReg(rd));
format_3_8(2, rd, 0x34, 0, 0x06, rs2);
}
void fitod_r(int rs2, int rd)
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "fitod %s, %s\n", MAYBE_PAD,
nameFpReg(rs2), nameFpReg(rd));
format_3_8(2, rd, 0x34, 0, 0xc8, rs2);
}
void fdtoi_r(int rs2, int rd)
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "fdtoi %s, %s\n", MAYBE_PAD,
nameFpReg(rs2), nameFpReg(rd));
format_3_8(2, rd, 0x34, 0, 0xd2, rs2);
}
void fdtos_r(int rs2, int rd)
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "fdtos %s, %s\n", MAYBE_PAD,
nameFpReg(rs2), nameFpReg(rd));
format_3_8(2, rd, 0x34, 0, 0xc6, rs2);
}
void fstod_r(int rs2, int rd)
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "fstod %s, %s\n", MAYBE_PAD,
nameFpReg(rs2), nameFpReg(rd));
format_3_8(2, rd, 0x34, 0, 0xc9, rs2);
}
static bool isimm13(int imm)
{
return (imm) <= 0xfff && (imm) >= -0x1000;
}
static bool isimm22(int imm)
{
return (imm) <= 0x1fffff && (imm) >= -0x200000;
}
void move_nocheck(int imm_v, RegisterID dest)
{
sethi(imm_v, dest);
or_imm(dest, imm_v & 0x3FF, dest);
}
JmpSrc call()
{
JmpSrc r = JmpSrc(m_buffer.size());
js::JaegerSpew(js::JSpew_Insns,
IPFX "call %d\n", MAYBE_PAD,
r.m_offset);
m_buffer.putInt(0x40000000);
nop();
return r;
}
JmpSrc jump_common(BranchType branchtype, int cond)
{
if (branchtype == BranchOnCondition)
branch_con(Condition(cond), 0);
else
fbranch_con(DoubleCondition(cond), 0);
nop();
branch_con(ConditionA, 7);
nop();
move_nocheck(0, SparcRegisters::g2);
rdpc(SparcRegisters::g3);
jmpl_r(SparcRegisters::g2, SparcRegisters::g3, SparcRegisters::g0);
nop();
return JmpSrc(m_buffer.size());
}
JmpSrc branch(Condition cond)
{
return jump_common(BranchOnCondition, cond);
}
JmpSrc fbranch(DoubleCondition cond)
{
return jump_common(BranchOnDoubleCondition, cond);
}
JmpSrc jmp()
{
return jump_common(BranchOnCondition, ConditionA);
}
// Assembler admin methods:
JmpDst label()
{
JmpDst r = JmpDst(m_buffer.size());
js::JaegerSpew(js::JSpew_Insns,
IPFX "#label ((%d))\n", MAYBE_PAD, r.m_offset);
return r;
}
// General helpers
size_t size() const { return m_buffer.size(); }
unsigned char *buffer() const { return m_buffer.buffer(); }
static int getDifferenceBetweenLabels(JmpDst src, JmpDst dst)
{
return dst.m_offset - src.m_offset;
}
static int getDifferenceBetweenLabels(JmpDst src, JmpSrc dst)
{
return dst.m_offset - src.m_offset;
}
static int getDifferenceBetweenLabels(JmpSrc src, JmpDst dst)
{
return dst.m_offset - src.m_offset;
}
static unsigned getCallReturnOffset(JmpSrc call)
{
return call.m_offset + 20;
}
static void* getRelocatedAddress(void* code, JmpSrc jump)
{
ASSERT(jump.m_offset != -1);
return reinterpret_cast<void*>(reinterpret_cast<ptrdiff_t>(code) + jump.m_offset);
}
static void* getRelocatedAddress(void* code, JmpDst destination)
{
ASSERT(destination.m_offset != -1);
return reinterpret_cast<void*>(reinterpret_cast<ptrdiff_t>(code) + destination.m_offset);
}
void* executableAllocAndCopy(ExecutableAllocator* allocator, ExecutablePool **poolp, CodeKind kind)
{
return m_buffer.executableAllocAndCopy(allocator, poolp, kind);
}
void* executableCopy(void* buffer)
{
return memcpy(buffer, m_buffer.buffer(), size());
}
static void patchPointerInternal(void* where, int value)
{
// Patch move_nocheck.
uint32_t *branch = (uint32_t*) where;
branch[0] &= 0xFFC00000;
branch[0] |= (value >> 10) & 0x3FFFFF;
branch[1] &= 0xFFFFFC00;
branch[1] |= value & 0x3FF;
ExecutableAllocator::cacheFlush(where, 8);
}
static void patchbranch(void* where, int value)
{
uint32_t *branch = (uint32_t*) where;
branch[0] &= 0xFFC00000;
branch[0] |= value & 0x3FFFFF;
ExecutableAllocator::cacheFlush(where, 4);
}
static bool canRelinkJump(void* from, void* to)
{
return true;
}
static void relinkJump(void* from, void* to)
{
from = (void *)((int)from - 36);
js::JaegerSpew(js::JSpew_Insns,
ISPFX "##link ((%p)) jumps to ((%p))\n",
from, to);
int value = ((int)to - (int)from) / 4;
if (isimm22(value))
patchbranch(from, value);
else {
patchbranch(from, 4);
from = (void *)((intptr_t)from + 16);
patchPointerInternal(from, (int)(value * 4 - 24));
}
}
void linkJump(JmpSrc from, JmpDst to)
{
ASSERT(from.m_offset != -1);
ASSERT(to.m_offset != -1);
intptr_t code = (intptr_t)(m_buffer.data());
void *where = (void *)((intptr_t)code + from.m_offset);
void *target = (void *)((intptr_t)code + to.m_offset);
relinkJump(where, target);
}
static void linkJump(void* code, JmpSrc from, void* to)
{
ASSERT(from.m_offset != -1);
void *where = (void *)((intptr_t)code + from.m_offset);
relinkJump(where, to);
}
static void relinkCall(void* from, void* to)
{
js::JaegerSpew(js::JSpew_Insns,
ISPFX "##relinkCall ((from=%p)) ((to=%p))\n",
from, to);
void * where= (void *)((intptr_t)from - 20);
patchPointerInternal(where, (int)to);
ExecutableAllocator::cacheFlush(where, 8);
}
static void linkCall(void* code, JmpSrc where, void* to)
{
void *from = (void *)((intptr_t)code + where.m_offset);
js::JaegerSpew(js::JSpew_Insns,
ISPFX "##linkCall ((from=%p)) ((to=%p))\n",
from, to);
int disp = ((int)to - (int)from)/4;
*(uint32_t *)((int)from) &= 0x40000000;
*(uint32_t *)((int)from) |= disp & 0x3fffffff;
ExecutableAllocator::cacheFlush(from, 4);
}
static void linkPointer(void* code, JmpDst where, void* value)
{
js::JaegerSpew(js::JSpew_Insns,
ISPFX "##linkPointer ((%p + %#x)) points to ((%p))\n",
code, where.m_offset, value);
void *from = (void *)((intptr_t)code + where.m_offset);
patchPointerInternal(from, (int)value);
}
static void repatchInt32(void* where, int value)
{
js::JaegerSpew(js::JSpew_Insns,
ISPFX "##repatchInt32 ((where=%p)) holds ((value=%d))\n",
where, value);
patchPointerInternal(where, value);
}
static void repatchPointer(void* where, void* value)
{
js::JaegerSpew(js::JSpew_Insns,
ISPFX "##repatchPointer ((where = %p)) points to ((%p))\n",
where, value);
patchPointerInternal(where, (int)value);
}
static void repatchLoadPtrToLEA(void* where)
{
// sethi is used. The offset is in a register
if (*(uint32_t *)((int)where) & 0x01000000)
where = (void *)((intptr_t)where + 8);
*(uint32_t *)((int)where) &= 0x3fffffff;
*(uint32_t *)((int)where) |= 0x80000000;
ExecutableAllocator::cacheFlush(where, 4);
}
static void repatchLEAToLoadPtr(void* where)
{
// sethi is used. The offset is in a register
if (*(uint32_t *)((int)where) & 0x01000000)
where = (void *)((intptr_t)where + 8);
*(uint32_t *)((int)where) &= 0x3fffffff;
*(uint32_t *)((int)where) |= 0xc0000000;
ExecutableAllocator::cacheFlush(where, 4);
}
private:
static char const * nameGpReg(int reg)
{
ASSERT(reg <= 31);
ASSERT(reg >= 0);
static char const * const names[] = {
"%g0", "%g1", "%g2", "%g3",
"%g4", "%g5", "%g6", "%g7",
"%o0", "%o1", "%o2", "%o3",
"%o4", "%o5", "%sp", "%o7",
"%l0", "%l1", "%l2", "%l3",
"%l4", "%l5", "%l6", "%l7",
"%i0", "%i1", "%i2", "%i3",
"%i4", "%i5", "%fp", "%i7"
};
return names[reg];
}
static char const * nameFpReg(int reg)
{
ASSERT(reg <= 31);
ASSERT(reg >= 0);
static char const * const names[] = {
"%f0", "%f1", "%f2", "%f3",
"%f4", "%f5", "%f6", "%f7",
"%f8", "%f9", "%f10", "%f11",
"%f12", "%f13", "%f14", "%f15",
"%f16", "%f17", "%f18", "%f19",
"%f20", "%f21", "%f22", "%f23",
"%f24", "%f25", "%f26", "%f27",
"%f28", "%f29", "%f30", "%f31"
};
return names[reg];
}
static char const * nameICC(Condition cc)
{
ASSERT(cc <= ConditionVC);
ASSERT(cc >= 0);
uint32_t ccIndex = cc;
static char const * const inames[] = {
" ", "e ",
"le ", "l ",
"leu", "cs ",
"neg", "vs ",
"a ", "ne ",
"g ", "ge ",
"gu ", "cc ",
" ", "vc "
};
return inames[ccIndex];
}
static char const * nameFCC(DoubleCondition cc)
{
ASSERT(cc <= DoubleConditionULE);
ASSERT(cc >= 0);
uint32_t ccIndex = cc;
static char const * const fnames[] = {
" ", "ne ",
" ", "ul ",
"l ", "ug ",
"g ", " ",
" ", "e ",
"ue ", "ge ",
"ugu", "le ",
"ule", " "
};
return fnames[ccIndex];
}
};
} // namespace JSC
#endif // ENABLE(ASSEMBLER) && CPU(SPARC)
#endif /* assembler_assembler_SparcAssembler_h */