2009-07-10 12:58:34 -07:00
|
|
|
/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
|
|
|
|
/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
|
2009-02-15 18:10:03 -08:00
|
|
|
/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 4 -*- */
|
|
|
|
/* ***** BEGIN LICENSE BLOCK *****
|
|
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
|
|
*
|
|
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
|
|
* the License. You may obtain a copy of the License at
|
|
|
|
* http://www.mozilla.org/MPL/
|
|
|
|
*
|
|
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
|
|
* for the specific language governing rights and limitations under the
|
|
|
|
* License.
|
|
|
|
*
|
|
|
|
* The Original Code is [Open Source Virtual Machine].
|
|
|
|
*
|
|
|
|
* The Initial Developer of the Original Code is
|
|
|
|
* Adobe System Incorporated.
|
|
|
|
* Portions created by the Initial Developer are Copyright (C) 2004-2007
|
|
|
|
* the Initial Developer. All Rights Reserved.
|
|
|
|
*
|
|
|
|
* Contributor(s):
|
|
|
|
* Adobe AS3 Team
|
|
|
|
* leon.sha@sun.com
|
|
|
|
*
|
|
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
|
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
|
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
|
|
* the provisions above, a recipient may use your version of this file under
|
|
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
|
|
*
|
|
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
|
|
|
|
#include <sys/mman.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include "nanojit.h"
|
|
|
|
|
|
|
|
namespace nanojit
|
|
|
|
{
|
|
|
|
#ifdef FEATURE_NANOJIT
|
|
|
|
|
|
|
|
#ifdef NJ_VERBOSE
|
|
|
|
const char *regNames[] = {
|
|
|
|
"%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",
|
|
|
|
"%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"
|
|
|
|
};
|
|
|
|
#endif
|
|
|
|
|
|
|
|
const Register Assembler::argRegs[] = { I0, I1, I2, I3, I4, I5 };
|
|
|
|
const Register Assembler::retRegs[] = { O0 };
|
|
|
|
const Register Assembler::savedRegs[] = { I0, I1, I2, I3, I4, I5 };
|
|
|
|
|
|
|
|
static const int kLinkageAreaSize = 68;
|
|
|
|
static const int kcalleeAreaSize = 80; // The max size.
|
|
|
|
static const int NJ_PAGE_SIZE_SPARC = 8192; // Use sparc page size here.
|
|
|
|
|
|
|
|
#define BIT_ROUND_UP(v,q) ( (((uintptr_t)v)+(q)-1) & ~((q)-1) )
|
|
|
|
|
|
|
|
void Assembler::nInit(AvmCore* core)
|
|
|
|
{
|
|
|
|
has_cmov = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
NIns* Assembler::genPrologue()
|
|
|
|
{
|
|
|
|
/**
|
|
|
|
* Prologue
|
|
|
|
*/
|
2009-07-22 02:06:23 -07:00
|
|
|
underrunProtect(16);
|
2009-02-15 18:10:03 -08:00
|
|
|
uint32_t stackNeeded = STACK_GRANULARITY * _activation.highwatermark;
|
|
|
|
uint32_t frameSize = stackNeeded + kcalleeAreaSize + kLinkageAreaSize;
|
|
|
|
frameSize = BIT_ROUND_UP(frameSize, 8);
|
|
|
|
|
|
|
|
if (frameSize <= 4096)
|
2009-07-22 02:06:23 -07:00
|
|
|
SUBI(FP, frameSize, SP);
|
2009-02-15 18:10:03 -08:00
|
|
|
else {
|
2009-07-22 02:06:23 -07:00
|
|
|
SUB(FP, G1, SP);
|
2009-07-22 02:44:28 -07:00
|
|
|
ORI(G1, frameSize & 0x3FF, G1);
|
|
|
|
SETHI(frameSize, G1);
|
2009-02-15 18:10:03 -08:00
|
|
|
}
|
|
|
|
|
2009-07-22 02:06:23 -07:00
|
|
|
verbose_only( verbose_outputf(" %p:",_nIns); )
|
|
|
|
verbose_only( asm_output(" patch entry:"); )
|
|
|
|
NIns *patchEntry = _nIns;
|
|
|
|
|
|
|
|
// The frame size in SAVE is faked. We will still re-caculate SP later.
|
|
|
|
// We can use 0 here but it is not good for debuggers.
|
|
|
|
SAVEI(SP, -148, SP);
|
|
|
|
|
2009-02-15 18:10:03 -08:00
|
|
|
// align the entry point
|
|
|
|
asm_align_code();
|
|
|
|
|
|
|
|
return patchEntry;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Assembler::asm_align_code() {
|
|
|
|
while(uintptr_t(_nIns) & 15) {
|
|
|
|
NOP();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Assembler::nFragExit(LInsp guard)
|
|
|
|
{
|
|
|
|
SideExit* exit = guard->record()->exit;
|
|
|
|
Fragment *frag = exit->target;
|
|
|
|
GuardRecord *lr;
|
|
|
|
if (frag && frag->fragEntry)
|
|
|
|
{
|
|
|
|
JMP(frag->fragEntry);
|
|
|
|
lr = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// target doesn't exit yet. emit jump to epilog, and set up to patch later.
|
|
|
|
lr = guard->record();
|
|
|
|
JMP_long((intptr_t)_epilogue);
|
|
|
|
lr->jmp = _nIns;
|
|
|
|
}
|
|
|
|
|
|
|
|
// return value is GuardRecord*
|
|
|
|
SET32(int(lr), O0);
|
|
|
|
}
|
|
|
|
|
|
|
|
NIns *Assembler::genEpilogue()
|
|
|
|
{
|
|
|
|
underrunProtect(12);
|
|
|
|
RESTORE(G0, G0, G0); //restore
|
|
|
|
JMPLI(I7, 8, G0); //ret
|
|
|
|
ORI(O0, 0, I0);
|
|
|
|
return _nIns;
|
|
|
|
}
|
2009-07-10 12:58:34 -07:00
|
|
|
|
2009-02-15 18:10:03 -08:00
|
|
|
void Assembler::asm_call(LInsp ins)
|
|
|
|
{
|
|
|
|
const CallInfo* call = ins->callInfo();
|
|
|
|
|
|
|
|
underrunProtect(8);
|
|
|
|
NOP();
|
|
|
|
|
2009-07-29 17:44:34 -07:00
|
|
|
ArgSize sizes[MAXARGS];
|
2009-02-15 18:10:03 -08:00
|
|
|
uint32_t argc = call->get_sizes(sizes);
|
|
|
|
|
2009-06-19 02:20:26 -07:00
|
|
|
NanoAssert(ins->isop(LIR_call) || ins->isop(LIR_fcall));
|
2009-07-13 21:49:29 -07:00
|
|
|
verbose_only(if (_logc->lcbits & LC_Assembly)
|
2009-06-19 02:20:26 -07:00
|
|
|
outputf(" %p:", _nIns);
|
|
|
|
)
|
|
|
|
CALL(call);
|
2009-02-15 18:10:03 -08:00
|
|
|
|
|
|
|
uint32_t GPRIndex = O0;
|
|
|
|
uint32_t offset = kLinkageAreaSize; // start of parameters stack postion.
|
|
|
|
|
|
|
|
for(int i=0; i<argc; i++)
|
|
|
|
{
|
|
|
|
uint32_t j = argc-i-1;
|
|
|
|
ArgSize sz = sizes[j];
|
|
|
|
if (sz == ARGSIZE_F) {
|
|
|
|
Register r = findRegFor(ins->arg(j), FpRegs);
|
|
|
|
GPRIndex += 2;
|
|
|
|
offset += 8;
|
|
|
|
|
|
|
|
underrunProtect(48);
|
|
|
|
// We might be calling a varargs function.
|
|
|
|
// So, make sure the GPR's are also loaded with
|
|
|
|
// the value, or the stack contains it.
|
|
|
|
if (GPRIndex-2 <= O5) {
|
|
|
|
LDSW32(SP, offset-8, (Register)(GPRIndex-2));
|
|
|
|
}
|
|
|
|
if (GPRIndex-1 <= O5) {
|
|
|
|
LDSW32(SP, offset-4, (Register)(GPRIndex-1));
|
|
|
|
}
|
|
|
|
STDF32(r, offset-8, SP);
|
|
|
|
} else {
|
|
|
|
if (GPRIndex > O5) {
|
|
|
|
underrunProtect(12);
|
|
|
|
Register r = findRegFor(ins->arg(j), GpRegs);
|
|
|
|
STW32(r, offset, SP);
|
|
|
|
} else {
|
|
|
|
Register r = findSpecificRegFor(ins->arg(j), (Register)GPRIndex);
|
|
|
|
}
|
|
|
|
GPRIndex++;
|
|
|
|
offset += 4;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Assembler::nMarkExecute(Page* page, int flags)
|
|
|
|
{
|
|
|
|
static const int kProtFlags[4] = {
|
|
|
|
PROT_READ, // 0
|
|
|
|
PROT_READ|PROT_WRITE, // PAGE_WRITE
|
|
|
|
PROT_READ|PROT_EXEC, // PAGE_EXEC
|
|
|
|
PROT_READ|PROT_WRITE|PROT_EXEC // PAGE_EXEC|PAGE_WRITE
|
|
|
|
};
|
|
|
|
int prot = kProtFlags[flags & (PAGE_WRITE|PAGE_EXEC)];
|
|
|
|
intptr_t addr = (intptr_t)page;
|
|
|
|
addr &= ~((uintptr_t)NJ_PAGE_SIZE_SPARC - 1);
|
|
|
|
if (mprotect((char *)addr, NJ_PAGE_SIZE_SPARC, prot) == -1) {
|
|
|
|
// todo: we can't abort or assert here, we have to fail gracefully.
|
|
|
|
NanoAssertMsg(false, "FATAL ERROR: mprotect(PROT_EXEC) failed\n");
|
|
|
|
}
|
|
|
|
}
|
2009-07-10 12:58:34 -07:00
|
|
|
|
2009-02-15 18:10:03 -08:00
|
|
|
Register Assembler::nRegisterAllocFromSet(int set)
|
|
|
|
{
|
|
|
|
// need to implement faster way
|
|
|
|
int i=0;
|
|
|
|
while (!(set & rmask((Register)i)))
|
|
|
|
i ++;
|
|
|
|
_allocator.free &= ~rmask((Register)i);
|
|
|
|
return (Register) i;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Assembler::nRegisterResetAll(RegAlloc& a)
|
|
|
|
{
|
|
|
|
a.clear();
|
|
|
|
a.used = 0;
|
|
|
|
a.free = GpRegs | FpRegs;
|
|
|
|
debug_only( a.managed = a.free; )
|
|
|
|
}
|
|
|
|
|
|
|
|
NIns *Assembler::nPatchBranch(NIns* branch, NIns* location)
|
|
|
|
{
|
|
|
|
NIns *was;
|
|
|
|
|
|
|
|
was = (NIns*)(((*(uint32_t*)&branch[0] & 0x3FFFFF) << 10) | (*(uint32_t*)&branch[1] & 0x3FF ));
|
|
|
|
*(uint32_t*)&branch[0] &= 0xFFC00000;
|
|
|
|
*(uint32_t*)&branch[0] |= ((intptr_t)location >> 10) & 0x3FFFFF;
|
|
|
|
*(uint32_t*)&branch[1] &= 0xFFFFFC00;
|
|
|
|
*(uint32_t*)&branch[1] |= (intptr_t)location & 0x3FF;
|
|
|
|
return was;
|
|
|
|
}
|
|
|
|
|
|
|
|
RegisterMask Assembler::hint(LIns* i, RegisterMask allow)
|
|
|
|
{
|
|
|
|
return allow;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Assembler::asm_qjoin(LIns *ins)
|
|
|
|
{
|
|
|
|
underrunProtect(40);
|
|
|
|
int d = findMemFor(ins);
|
|
|
|
AvmAssert(d);
|
|
|
|
LIns* lo = ins->oprnd1();
|
|
|
|
LIns* hi = ins->oprnd2();
|
|
|
|
|
|
|
|
Reservation *resv = getresv(ins);
|
|
|
|
Register rr = resv->reg;
|
|
|
|
|
|
|
|
if (rr != UnknownReg && (rmask(rr) & FpRegs))
|
|
|
|
evict(rr);
|
|
|
|
|
|
|
|
if (hi->isconst()) {
|
2009-07-06 23:16:35 -07:00
|
|
|
STW32(L2, d+4, FP);
|
|
|
|
SET32(hi->imm32(), L2);
|
2009-02-15 18:10:03 -08:00
|
|
|
} else {
|
|
|
|
Register rh = findRegFor(hi, GpRegs);
|
|
|
|
STW32(rh, d+4, FP);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (lo->isconst()) {
|
2009-07-06 23:16:35 -07:00
|
|
|
STW32(L2, d, FP);
|
|
|
|
SET32(lo->imm32(), L2);
|
2009-02-15 18:10:03 -08:00
|
|
|
} else {
|
|
|
|
// okay if r gets recycled.
|
|
|
|
Register rl = findRegFor(lo, GpRegs);
|
|
|
|
STW32(rl, d, FP);
|
|
|
|
}
|
|
|
|
|
|
|
|
freeRsrcOf(ins, false); // if we had a reg in use, emit a ST to flush it to mem
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Assembler::asm_restore(LInsp i, Reservation *resv, Register r)
|
|
|
|
{
|
|
|
|
underrunProtect(24);
|
2009-07-14 17:00:43 -07:00
|
|
|
if (i->isop(LIR_ialloc)) {
|
2009-07-06 23:16:35 -07:00
|
|
|
ADD(FP, L2, r);
|
|
|
|
SET32(disp(resv), L2);
|
2009-07-13 21:49:29 -07:00
|
|
|
verbose_only(if (_logc->lcbits & LC_RegAlloc) {
|
2009-02-15 18:10:03 -08:00
|
|
|
outputf(" remat %s size %d", _thisfrag->lirbuf->names->formatRef(i), i->size());
|
|
|
|
})
|
|
|
|
}
|
|
|
|
else if (i->isconst()) {
|
|
|
|
if (!resv->arIndex) {
|
2009-06-29 13:23:06 -07:00
|
|
|
i->resv()->clear();
|
2009-02-15 18:10:03 -08:00
|
|
|
}
|
2009-05-11 19:41:25 -07:00
|
|
|
int v = i->imm32();
|
2009-02-15 18:10:03 -08:00
|
|
|
SET32(v, r);
|
|
|
|
} else {
|
|
|
|
int d = findMemFor(i);
|
|
|
|
if (rmask(r) & FpRegs) {
|
|
|
|
LDDF32(FP, d, r);
|
|
|
|
} else {
|
|
|
|
LDSW32(FP, d, r);
|
|
|
|
}
|
2009-07-13 21:49:29 -07:00
|
|
|
verbose_only(if (_logc->lcbits & LC_RegAlloc) {
|
2009-02-15 18:10:03 -08:00
|
|
|
outputf(" restore %s", _thisfrag->lirbuf->names->formatRef(i));
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Assembler::asm_store32(LIns *value, int dr, LIns *base)
|
|
|
|
{
|
|
|
|
underrunProtect(20);
|
|
|
|
if (value->isconst())
|
|
|
|
{
|
|
|
|
Register rb = getBaseReg(base, dr, GpRegs);
|
2009-05-11 19:41:25 -07:00
|
|
|
int c = value->imm32();
|
2009-07-06 23:16:35 -07:00
|
|
|
STW32(L2, dr, rb);
|
|
|
|
SET32(c, L2);
|
2009-02-15 18:10:03 -08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// make sure what is in a register
|
|
|
|
Reservation *rA, *rB;
|
|
|
|
Register ra, rb;
|
2009-07-14 17:00:43 -07:00
|
|
|
if (base->isop(LIR_ialloc)) {
|
2009-02-15 18:10:03 -08:00
|
|
|
rb = FP;
|
|
|
|
dr += findMemFor(base);
|
|
|
|
ra = findRegFor(value, GpRegs);
|
|
|
|
} else if (base->isconst()) {
|
|
|
|
// absolute address
|
2009-05-11 19:41:25 -07:00
|
|
|
dr += base->imm32();
|
2009-02-15 18:10:03 -08:00
|
|
|
ra = findRegFor(value, GpRegs);
|
|
|
|
rb = G0;
|
|
|
|
} else {
|
|
|
|
findRegFor2(GpRegs, value, rA, base, rB);
|
|
|
|
ra = rA->reg;
|
|
|
|
rb = rB->reg;
|
|
|
|
}
|
|
|
|
STW32(ra, dr, rb);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Assembler::asm_spill(Register rr, int d, bool pop, bool quad)
|
|
|
|
{
|
|
|
|
underrunProtect(24);
|
|
|
|
(void)quad;
|
|
|
|
if (d) {
|
|
|
|
if (rmask(rr) & FpRegs) {
|
|
|
|
STDF32(rr, d, FP);
|
|
|
|
} else {
|
|
|
|
STW32(rr, d, FP);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Assembler::asm_load64(LInsp ins)
|
|
|
|
{
|
|
|
|
underrunProtect(72);
|
|
|
|
LIns* base = ins->oprnd1();
|
2009-07-06 16:26:12 -07:00
|
|
|
int db = ins->disp();
|
2009-02-15 18:10:03 -08:00
|
|
|
Reservation *resv = getresv(ins);
|
|
|
|
Register rr = resv->reg;
|
|
|
|
|
|
|
|
int dr = disp(resv);
|
|
|
|
Register rb;
|
2009-07-14 17:00:43 -07:00
|
|
|
if (base->isop(LIR_ialloc)) {
|
2009-02-15 18:10:03 -08:00
|
|
|
rb = FP;
|
|
|
|
db += findMemFor(base);
|
|
|
|
} else {
|
|
|
|
rb = findRegFor(base, GpRegs);
|
|
|
|
}
|
|
|
|
resv->reg = UnknownReg;
|
|
|
|
|
|
|
|
// don't use an fpu reg to simply load & store the value.
|
|
|
|
if (dr)
|
|
|
|
asm_mmq(FP, dr, rb, db);
|
|
|
|
|
|
|
|
freeRsrcOf(ins, false);
|
|
|
|
|
|
|
|
if (rr != UnknownReg)
|
|
|
|
{
|
|
|
|
NanoAssert(rmask(rr)&FpRegs);
|
|
|
|
_allocator.retire(rr);
|
|
|
|
LDDF32(rb, db, rr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Assembler::asm_store64(LInsp value, int dr, LInsp base)
|
|
|
|
{
|
|
|
|
underrunProtect(48);
|
|
|
|
if (value->isconstq())
|
|
|
|
{
|
|
|
|
// if a constant 64-bit value just store it now rather than
|
|
|
|
// generating a pointless store/load/store sequence
|
|
|
|
Register rb = findRegFor(base, GpRegs);
|
2009-07-06 23:16:35 -07:00
|
|
|
STW32(L2, dr+4, rb);
|
|
|
|
SET32(value->imm64_0(), L2);
|
|
|
|
STW32(L2, dr, rb);
|
|
|
|
SET32(value->imm64_1(), L2);
|
2009-02-15 18:10:03 -08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (value->isop(LIR_ldq) || value->isop(LIR_ldqc) || value->isop(LIR_qjoin))
|
|
|
|
{
|
|
|
|
// value is 64bit struct or int64_t, or maybe a double.
|
|
|
|
// it may be live in an FPU reg. Either way, don't
|
|
|
|
// put it in an FPU reg just to load & store it.
|
|
|
|
|
|
|
|
// a) if we know it's not a double, this is right.
|
|
|
|
// b) if we guarded that its a double, this store could be on
|
|
|
|
// the side exit, copying a non-double.
|
|
|
|
// c) maybe its a double just being stored. oh well.
|
|
|
|
|
|
|
|
int da = findMemFor(value);
|
|
|
|
Register rb;
|
2009-07-14 17:00:43 -07:00
|
|
|
if (base->isop(LIR_ialloc)) {
|
2009-02-15 18:10:03 -08:00
|
|
|
rb = FP;
|
|
|
|
dr += findMemFor(base);
|
|
|
|
} else {
|
|
|
|
rb = findRegFor(base, GpRegs);
|
|
|
|
}
|
|
|
|
asm_mmq(rb, dr, FP, da);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Register rb;
|
2009-07-14 17:00:43 -07:00
|
|
|
if (base->isop(LIR_ialloc)) {
|
2009-02-15 18:10:03 -08:00
|
|
|
rb = FP;
|
|
|
|
dr += findMemFor(base);
|
|
|
|
} else {
|
|
|
|
rb = findRegFor(base, GpRegs);
|
|
|
|
}
|
|
|
|
|
|
|
|
// if value already in a reg, use that, otherwise
|
|
|
|
// try to get it into XMM regs before FPU regs.
|
|
|
|
Reservation* rA = getresv(value);
|
|
|
|
Register rv;
|
|
|
|
int pop = !rA || rA->reg==UnknownReg;
|
|
|
|
if (pop) {
|
|
|
|
rv = findRegFor(value, FpRegs);
|
|
|
|
} else {
|
|
|
|
rv = rA->reg;
|
|
|
|
}
|
|
|
|
|
|
|
|
STDF32(rv, dr, rb);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* copy 64 bits: (rd+dd) <- (rs+ds)
|
|
|
|
*/
|
|
|
|
void Assembler::asm_mmq(Register rd, int dd, Register rs, int ds)
|
|
|
|
{
|
|
|
|
// value is either a 64bit struct or maybe a float
|
|
|
|
// that isn't live in an FPU reg. Either way, don't
|
|
|
|
// put it in an FPU reg just to load & store it.
|
|
|
|
Register t = registerAlloc(GpRegs & ~(rmask(rd)|rmask(rs)));
|
|
|
|
_allocator.addFree(t);
|
|
|
|
STW32(t, dd+4, rd);
|
|
|
|
LDSW32(rs, ds+4, t);
|
|
|
|
STW32(t, dd, rd);
|
|
|
|
LDSW32(rs, ds, t);
|
|
|
|
}
|
|
|
|
|
2009-07-23 22:41:32 -07:00
|
|
|
NIns* Assembler::asm_branch(bool branchOnFalse, LInsp cond, NIns* targ)
|
2009-02-15 18:10:03 -08:00
|
|
|
{
|
|
|
|
NIns* at = 0;
|
|
|
|
LOpcode condop = cond->opcode();
|
|
|
|
NanoAssert(cond->isCond());
|
|
|
|
if (condop >= LIR_feq && condop <= LIR_fge)
|
|
|
|
{
|
|
|
|
return asm_jmpcc(branchOnFalse, cond, targ);
|
|
|
|
}
|
|
|
|
|
|
|
|
underrunProtect(32);
|
|
|
|
intptr_t tt = ((intptr_t)targ - (intptr_t)_nIns + 8) >> 2;
|
|
|
|
// !targ means that it needs patch.
|
|
|
|
if( !(isIMM22((int32_t)tt)) || !targ ) {
|
|
|
|
JMP_long_nocheck((intptr_t)targ);
|
|
|
|
at = _nIns;
|
|
|
|
NOP();
|
|
|
|
BA(0, 5);
|
|
|
|
tt = 4;
|
|
|
|
}
|
|
|
|
NOP();
|
|
|
|
|
|
|
|
|
|
|
|
// produce the branch
|
|
|
|
if (branchOnFalse)
|
|
|
|
{
|
|
|
|
if (condop == LIR_eq)
|
|
|
|
BNE(0, tt);
|
|
|
|
else if (condop == LIR_ov)
|
|
|
|
BVC(0, tt);
|
|
|
|
else if (condop == LIR_lt)
|
|
|
|
BGE(0, tt);
|
|
|
|
else if (condop == LIR_le)
|
|
|
|
BG(0, tt);
|
|
|
|
else if (condop == LIR_gt)
|
|
|
|
BLE(0, tt);
|
|
|
|
else if (condop == LIR_ge)
|
|
|
|
BL(0, tt);
|
|
|
|
else if (condop == LIR_ult)
|
|
|
|
BCC(0, tt);
|
|
|
|
else if (condop == LIR_ule)
|
|
|
|
BGU(0, tt);
|
|
|
|
else if (condop == LIR_ugt)
|
|
|
|
BLEU(0, tt);
|
|
|
|
else //if (condop == LIR_uge)
|
|
|
|
BCS(0, tt);
|
|
|
|
}
|
|
|
|
else // op == LIR_xt
|
|
|
|
{
|
|
|
|
if (condop == LIR_eq)
|
|
|
|
BE(0, tt);
|
|
|
|
else if (condop == LIR_ov)
|
|
|
|
BVS(0, tt);
|
|
|
|
else if (condop == LIR_lt)
|
|
|
|
BL(0, tt);
|
|
|
|
else if (condop == LIR_le)
|
|
|
|
BLE(0, tt);
|
|
|
|
else if (condop == LIR_gt)
|
|
|
|
BG(0, tt);
|
|
|
|
else if (condop == LIR_ge)
|
|
|
|
BGE(0, tt);
|
|
|
|
else if (condop == LIR_ult)
|
|
|
|
BCS(0, tt);
|
|
|
|
else if (condop == LIR_ule)
|
|
|
|
BLEU(0, tt);
|
|
|
|
else if (condop == LIR_ugt)
|
|
|
|
BGU(0, tt);
|
|
|
|
else //if (condop == LIR_uge)
|
|
|
|
BCC(0, tt);
|
|
|
|
}
|
|
|
|
asm_cmp(cond);
|
|
|
|
return at;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Assembler::asm_cmp(LIns *cond)
|
|
|
|
{
|
|
|
|
underrunProtect(12);
|
|
|
|
LOpcode condop = cond->opcode();
|
2009-07-10 12:58:34 -07:00
|
|
|
|
2009-07-01 19:21:28 -07:00
|
|
|
// LIR_ov recycles the flags set by arithmetic ops
|
|
|
|
if ((condop == LIR_ov))
|
2009-02-15 18:10:03 -08:00
|
|
|
return;
|
2009-07-10 12:58:34 -07:00
|
|
|
|
2009-02-15 18:10:03 -08:00
|
|
|
LInsp lhs = cond->oprnd1();
|
|
|
|
LInsp rhs = cond->oprnd2();
|
|
|
|
Reservation *rA, *rB;
|
|
|
|
|
|
|
|
NanoAssert((!lhs->isQuad() && !rhs->isQuad()) || (lhs->isQuad() && rhs->isQuad()));
|
|
|
|
|
|
|
|
NanoAssert(!lhs->isQuad() && !rhs->isQuad());
|
|
|
|
|
|
|
|
// ready to issue the compare
|
|
|
|
if (rhs->isconst())
|
|
|
|
{
|
2009-05-11 19:41:25 -07:00
|
|
|
int c = rhs->imm32();
|
2009-02-15 18:10:03 -08:00
|
|
|
if (c == 0 && cond->isop(LIR_eq)) {
|
|
|
|
Register r = findRegFor(lhs, GpRegs);
|
|
|
|
ANDCC(r, r, G0);
|
|
|
|
}
|
|
|
|
else if (!rhs->isQuad()) {
|
|
|
|
Register r = getBaseReg(lhs, c, GpRegs);
|
2009-07-06 23:16:35 -07:00
|
|
|
SUBCC(r, L2, G0);
|
|
|
|
SET32(c, L2);
|
2009-02-15 18:10:03 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
findRegFor2(GpRegs, lhs, rA, rhs, rB);
|
|
|
|
Register ra = rA->reg;
|
|
|
|
Register rb = rB->reg;
|
|
|
|
SUBCC(ra, rb, G0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Assembler::asm_loop(LInsp ins, NInsList& loopJumps)
|
|
|
|
{
|
|
|
|
(void)ins;
|
2009-07-10 12:58:34 -07:00
|
|
|
JMP_long_placeholder(); // jump to SOT
|
|
|
|
|
2009-02-15 18:10:03 -08:00
|
|
|
loopJumps.add(_nIns);
|
|
|
|
|
|
|
|
assignSavedRegs();
|
|
|
|
|
|
|
|
// restore first parameter, the only one we use
|
|
|
|
LInsp state = _thisfrag->lirbuf->state;
|
2009-07-10 12:58:34 -07:00
|
|
|
findSpecificRegFor(state, argRegs[state->paramArg()]);
|
|
|
|
}
|
2009-02-15 18:10:03 -08:00
|
|
|
|
|
|
|
void Assembler::asm_fcond(LInsp ins)
|
|
|
|
{
|
2009-07-10 12:58:34 -07:00
|
|
|
// only want certain regs
|
2009-02-15 18:10:03 -08:00
|
|
|
Register r = prepResultReg(ins, AllowableFlagRegs);
|
|
|
|
asm_setcc(r, ins);
|
|
|
|
}
|
2009-07-10 12:58:34 -07:00
|
|
|
|
2009-02-15 18:10:03 -08:00
|
|
|
void Assembler::asm_cond(LInsp ins)
|
|
|
|
{
|
|
|
|
underrunProtect(8);
|
2009-07-10 12:58:34 -07:00
|
|
|
// only want certain regs
|
|
|
|
LOpcode op = ins->opcode();
|
2009-02-15 18:10:03 -08:00
|
|
|
Register r = prepResultReg(ins, AllowableFlagRegs);
|
|
|
|
|
|
|
|
if (op == LIR_eq)
|
|
|
|
MOVEI(1, 1, 0, 0, r);
|
|
|
|
else if (op == LIR_ov)
|
|
|
|
MOVVSI(1, 1, 0, 0, r);
|
|
|
|
else if (op == LIR_lt)
|
|
|
|
MOVLI(1, 1, 0, 0, r);
|
|
|
|
else if (op == LIR_le)
|
|
|
|
MOVLEI(1, 1, 0, 0, r);
|
|
|
|
else if (op == LIR_gt)
|
|
|
|
MOVGI(1, 1, 0, 0, r);
|
|
|
|
else if (op == LIR_ge)
|
|
|
|
MOVGEI(1, 1, 0, 0, r);
|
|
|
|
else if (op == LIR_ult)
|
|
|
|
MOVEI(1, 1, 0, 0, r);
|
|
|
|
else if (op == LIR_ule)
|
|
|
|
MOVLEUI(1, 1, 0, 0, r);
|
|
|
|
else if (op == LIR_ugt)
|
|
|
|
MOVGUI(1, 1, 0, 0, r);
|
|
|
|
else // if (op == LIR_uge)
|
|
|
|
MOVCCI(1, 1, 0, 0, r);
|
|
|
|
ORI(G0, 0, r);
|
|
|
|
asm_cmp(ins);
|
|
|
|
}
|
2009-07-10 12:58:34 -07:00
|
|
|
|
2009-02-15 18:10:03 -08:00
|
|
|
void Assembler::asm_arith(LInsp ins)
|
|
|
|
{
|
|
|
|
underrunProtect(28);
|
2009-07-10 12:58:34 -07:00
|
|
|
LOpcode op = ins->opcode();
|
2009-02-15 18:10:03 -08:00
|
|
|
LInsp lhs = ins->oprnd1();
|
|
|
|
LInsp rhs = ins->oprnd2();
|
|
|
|
|
|
|
|
Register rb = UnknownReg;
|
|
|
|
RegisterMask allow = GpRegs;
|
|
|
|
bool forceReg = (op == LIR_mul || !rhs->isconst());
|
|
|
|
|
|
|
|
if (lhs != rhs && forceReg)
|
|
|
|
{
|
|
|
|
if ((rb = asm_binop_rhs_reg(ins)) == UnknownReg) {
|
|
|
|
rb = findRegFor(rhs, allow);
|
|
|
|
}
|
|
|
|
allow &= ~rmask(rb);
|
|
|
|
}
|
2009-07-14 17:00:43 -07:00
|
|
|
else if ((op == LIR_add||op == LIR_iaddp) && lhs->isop(LIR_ialloc) && rhs->isconst()) {
|
2009-02-15 18:10:03 -08:00
|
|
|
// add alloc+const, use lea
|
|
|
|
Register rr = prepResultReg(ins, allow);
|
2009-05-11 19:41:25 -07:00
|
|
|
int d = findMemFor(lhs) + rhs->imm32();
|
2009-07-06 23:16:35 -07:00
|
|
|
ADD(FP, L2, rr);
|
|
|
|
SET32(d, L2);
|
2009-02-15 18:10:03 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
Register rr = prepResultReg(ins, allow);
|
|
|
|
Reservation* rA = getresv(lhs);
|
|
|
|
Register ra;
|
|
|
|
// if this is last use of lhs in reg, we can re-use result reg
|
|
|
|
if (rA == 0 || (ra = rA->reg) == UnknownReg)
|
|
|
|
ra = findSpecificRegFor(lhs, rr);
|
|
|
|
// else, rA already has a register assigned.
|
|
|
|
|
|
|
|
if (forceReg)
|
|
|
|
{
|
|
|
|
if (lhs == rhs)
|
|
|
|
rb = ra;
|
|
|
|
|
2009-07-14 17:00:43 -07:00
|
|
|
if (op == LIR_add || op == LIR_iaddp)
|
2009-04-22 01:06:45 -07:00
|
|
|
ADDCC(rr, rb, rr);
|
2009-02-15 18:10:03 -08:00
|
|
|
else if (op == LIR_sub)
|
2009-04-22 01:06:45 -07:00
|
|
|
SUBCC(rr, rb, rr);
|
2009-02-15 18:10:03 -08:00
|
|
|
else if (op == LIR_mul)
|
|
|
|
MULX(rr, rb, rr);
|
|
|
|
else if (op == LIR_and)
|
|
|
|
AND(rr, rb, rr);
|
|
|
|
else if (op == LIR_or)
|
|
|
|
OR(rr, rb, rr);
|
|
|
|
else if (op == LIR_xor)
|
|
|
|
XOR(rr, rb, rr);
|
|
|
|
else if (op == LIR_lsh)
|
|
|
|
SLL(rr, rb, rr);
|
|
|
|
else if (op == LIR_rsh)
|
|
|
|
SRA(rr, rb, rr);
|
|
|
|
else if (op == LIR_ush)
|
|
|
|
SRL(rr, rb, rr);
|
|
|
|
else
|
|
|
|
NanoAssertMsg(0, "Unsupported");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-05-11 19:41:25 -07:00
|
|
|
int c = rhs->imm32();
|
2009-07-14 17:00:43 -07:00
|
|
|
if (op == LIR_add || op == LIR_iaddp) {
|
2009-07-10 12:58:34 -07:00
|
|
|
ADDCC(rr, L2, rr);
|
2009-02-15 18:10:03 -08:00
|
|
|
} else if (op == LIR_sub) {
|
2009-07-10 12:58:34 -07:00
|
|
|
SUBCC(rr, L2, rr);
|
2009-02-15 18:10:03 -08:00
|
|
|
} else if (op == LIR_and)
|
2009-07-06 23:16:35 -07:00
|
|
|
AND(rr, L2, rr);
|
2009-02-15 18:10:03 -08:00
|
|
|
else if (op == LIR_or)
|
2009-07-06 23:16:35 -07:00
|
|
|
OR(rr, L2, rr);
|
2009-02-15 18:10:03 -08:00
|
|
|
else if (op == LIR_xor)
|
2009-07-06 23:16:35 -07:00
|
|
|
XOR(rr, L2, rr);
|
2009-02-15 18:10:03 -08:00
|
|
|
else if (op == LIR_lsh)
|
2009-07-06 23:16:35 -07:00
|
|
|
SLL(rr, L2, rr);
|
2009-02-15 18:10:03 -08:00
|
|
|
else if (op == LIR_rsh)
|
2009-07-06 23:16:35 -07:00
|
|
|
SRA(rr, L2, rr);
|
2009-02-15 18:10:03 -08:00
|
|
|
else if (op == LIR_ush)
|
2009-07-06 23:16:35 -07:00
|
|
|
SRL(rr, L2, rr);
|
2009-02-15 18:10:03 -08:00
|
|
|
else
|
|
|
|
NanoAssertMsg(0, "Unsupported");
|
2009-07-06 23:16:35 -07:00
|
|
|
SET32(c, L2);
|
2009-02-15 18:10:03 -08:00
|
|
|
}
|
|
|
|
|
2009-07-10 12:58:34 -07:00
|
|
|
if ( rr != ra )
|
2009-02-15 18:10:03 -08:00
|
|
|
ORI(ra, 0, rr);
|
|
|
|
}
|
2009-07-10 12:58:34 -07:00
|
|
|
|
2009-02-15 18:10:03 -08:00
|
|
|
void Assembler::asm_neg_not(LInsp ins)
|
|
|
|
{
|
|
|
|
underrunProtect(8);
|
2009-07-10 12:58:34 -07:00
|
|
|
LOpcode op = ins->opcode();
|
2009-02-15 18:10:03 -08:00
|
|
|
Register rr = prepResultReg(ins, GpRegs);
|
|
|
|
|
|
|
|
LIns* lhs = ins->oprnd1();
|
|
|
|
Reservation *rA = getresv(lhs);
|
|
|
|
// if this is last use of lhs in reg, we can re-use result reg
|
|
|
|
Register ra;
|
|
|
|
if (rA == 0 || (ra=rA->reg) == UnknownReg)
|
|
|
|
ra = findSpecificRegFor(lhs, rr);
|
|
|
|
// else, rA already has a register assigned.
|
|
|
|
|
|
|
|
if (op == LIR_not)
|
2009-07-10 12:58:34 -07:00
|
|
|
ORN(G0, rr, rr);
|
2009-02-15 18:10:03 -08:00
|
|
|
else
|
2009-07-10 12:58:34 -07:00
|
|
|
SUB(G0, rr, rr);
|
2009-02-15 18:10:03 -08:00
|
|
|
|
2009-07-10 12:58:34 -07:00
|
|
|
if ( rr != ra )
|
2009-02-15 18:10:03 -08:00
|
|
|
ORI(ra, 0, rr);
|
|
|
|
}
|
2009-07-10 12:58:34 -07:00
|
|
|
|
2009-02-15 18:10:03 -08:00
|
|
|
void Assembler::asm_ld(LInsp ins)
|
|
|
|
{
|
|
|
|
underrunProtect(12);
|
2009-07-10 12:58:34 -07:00
|
|
|
LOpcode op = ins->opcode();
|
2009-02-15 18:10:03 -08:00
|
|
|
LIns* base = ins->oprnd1();
|
2009-07-06 16:26:12 -07:00
|
|
|
int d = ins->disp();
|
2009-02-15 18:10:03 -08:00
|
|
|
Register rr = prepResultReg(ins, GpRegs);
|
|
|
|
Register ra = getBaseReg(base, d, GpRegs);
|
|
|
|
if (op == LIR_ldcb) {
|
2009-02-27 01:17:08 -08:00
|
|
|
LDUB32(ra, d, rr);
|
2009-02-15 18:10:03 -08:00
|
|
|
} else if (op == LIR_ldcs) {
|
2009-02-27 01:17:08 -08:00
|
|
|
LDUH32(ra, d, rr);
|
2009-02-15 18:10:03 -08:00
|
|
|
} else {
|
|
|
|
LDSW32(ra, d, rr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Assembler::asm_cmov(LInsp ins)
|
|
|
|
{
|
|
|
|
underrunProtect(4);
|
2009-07-10 12:58:34 -07:00
|
|
|
LOpcode op = ins->opcode();
|
2009-02-15 18:10:03 -08:00
|
|
|
LIns* condval = ins->oprnd1();
|
2009-07-21 17:28:25 -07:00
|
|
|
LIns* iftrue = ins->oprnd2();
|
|
|
|
LIns* iffalse = ins->oprnd3();
|
2009-07-20 14:18:17 -07:00
|
|
|
|
2009-07-21 17:28:25 -07:00
|
|
|
NanoAssert(condval->isCmp());
|
2009-02-15 18:10:03 -08:00
|
|
|
NanoAssert(op == LIR_qcmov || (!iftrue->isQuad() && !iffalse->isQuad()));
|
2009-07-10 12:58:34 -07:00
|
|
|
|
2009-02-15 18:10:03 -08:00
|
|
|
const Register rr = prepResultReg(ins, GpRegs);
|
|
|
|
|
|
|
|
// this code assumes that neither LD nor MR nor MRcc set any of the condition flags.
|
|
|
|
// (This is true on Intel, is it true on all architectures?)
|
|
|
|
const Register iffalsereg = findRegFor(iffalse, GpRegs & ~rmask(rr));
|
|
|
|
if (op == LIR_cmov) {
|
|
|
|
switch (condval->opcode()) {
|
|
|
|
// note that these are all opposites...
|
|
|
|
case LIR_eq: MOVNE (iffalsereg, 1, 0, 0, rr); break;
|
|
|
|
case LIR_ov: MOVVC (iffalsereg, 1, 0, 0, rr); break;
|
|
|
|
case LIR_lt: MOVGE (iffalsereg, 1, 0, 0, rr); break;
|
|
|
|
case LIR_le: MOVG (iffalsereg, 1, 0, 0, rr); break;
|
|
|
|
case LIR_gt: MOVLE (iffalsereg, 1, 0, 0, rr); break;
|
|
|
|
case LIR_ge: MOVL (iffalsereg, 1, 0, 0, rr); break;
|
|
|
|
case LIR_ult: MOVCC (iffalsereg, 1, 0, 0, rr); break;
|
|
|
|
case LIR_ule: MOVGU (iffalsereg, 1, 0, 0, rr); break;
|
|
|
|
case LIR_ugt: MOVLEU(iffalsereg, 1, 0, 0, rr); break;
|
|
|
|
case LIR_uge: MOVCS (iffalsereg, 1, 0, 0, rr); break;
|
|
|
|
debug_only( default: NanoAssert(0); break; )
|
|
|
|
}
|
|
|
|
} else if (op == LIR_qcmov) {
|
|
|
|
NanoAssert(0);
|
|
|
|
}
|
|
|
|
/*const Register iftruereg =*/ findSpecificRegFor(iftrue, rr);
|
|
|
|
asm_cmp(condval);
|
|
|
|
}
|
2009-07-10 12:58:34 -07:00
|
|
|
|
2009-02-15 18:10:03 -08:00
|
|
|
void Assembler::asm_qhi(LInsp ins)
|
|
|
|
{
|
|
|
|
underrunProtect(12);
|
|
|
|
Register rr = prepResultReg(ins, GpRegs);
|
|
|
|
LIns *q = ins->oprnd1();
|
|
|
|
int d = findMemFor(q);
|
|
|
|
LDSW32(FP, d+4, rr);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Assembler::asm_param(LInsp ins)
|
|
|
|
{
|
2009-06-30 21:18:55 -07:00
|
|
|
uint32_t a = ins->paramArg();
|
|
|
|
uint32_t kind = ins->paramKind();
|
2009-02-15 18:10:03 -08:00
|
|
|
// prepResultReg(ins, rmask(argRegs[a]));
|
|
|
|
if (kind == 0) {
|
|
|
|
prepResultReg(ins, rmask(argRegs[a]));
|
|
|
|
} else {
|
|
|
|
prepResultReg(ins, rmask(savedRegs[a]));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Assembler::asm_int(LInsp ins)
|
|
|
|
{
|
|
|
|
underrunProtect(8);
|
|
|
|
Register rr = prepResultReg(ins, GpRegs);
|
|
|
|
int32_t val = ins->imm32();
|
|
|
|
if (val == 0)
|
|
|
|
XOR(rr, rr, rr);
|
|
|
|
else
|
|
|
|
SET32(val, rr);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Assembler::asm_quad(LInsp ins)
|
|
|
|
{
|
|
|
|
underrunProtect(64);
|
|
|
|
Reservation *rR = getresv(ins);
|
|
|
|
Register rr = rR->reg;
|
|
|
|
if (rr != UnknownReg)
|
|
|
|
{
|
|
|
|
// @todo -- add special-cases for 0 and 1
|
|
|
|
_allocator.retire(rr);
|
|
|
|
rR->reg = UnknownReg;
|
|
|
|
NanoAssert((rmask(rr) & FpRegs) != 0);
|
|
|
|
findMemFor(ins);
|
|
|
|
int d = disp(rR);
|
|
|
|
LDDF32(FP, d, rr);
|
|
|
|
}
|
|
|
|
|
|
|
|
// @todo, if we used xor, ldsd, fldz, etc above, we don't need mem here
|
|
|
|
int d = disp(rR);
|
|
|
|
freeRsrcOf(ins, false);
|
|
|
|
if (d)
|
|
|
|
{
|
2009-07-22 02:28:33 -07:00
|
|
|
STW32(L2, d+4, FP);
|
|
|
|
SET32(ins->imm64_0(), L2);
|
|
|
|
STW32(L2, d, FP);
|
|
|
|
SET32(ins->imm64_1(), L2);
|
2009-02-15 18:10:03 -08:00
|
|
|
}
|
|
|
|
}
|
2009-07-10 12:58:34 -07:00
|
|
|
|
2009-02-15 18:10:03 -08:00
|
|
|
void Assembler::asm_qlo(LInsp ins)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void Assembler::asm_fneg(LInsp ins)
|
|
|
|
{
|
|
|
|
underrunProtect(4);
|
|
|
|
Register rr = prepResultReg(ins, FpRegs);
|
|
|
|
LIns* lhs = ins->oprnd1();
|
|
|
|
|
|
|
|
// lhs into reg, prefer same reg as result
|
|
|
|
Reservation* rA = getresv(lhs);
|
|
|
|
Register ra;
|
|
|
|
// if this is last use of lhs in reg, we can re-use result reg
|
|
|
|
if (rA == 0 || rA->reg == UnknownReg)
|
|
|
|
ra = findSpecificRegFor(lhs, rr);
|
|
|
|
else
|
|
|
|
ra = findRegFor(lhs, FpRegs);
|
|
|
|
// else, rA already has a different reg assigned
|
|
|
|
|
|
|
|
FNEGD(ra, rr);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Assembler::asm_fop(LInsp ins)
|
|
|
|
{
|
|
|
|
underrunProtect(4);
|
|
|
|
LOpcode op = ins->opcode();
|
|
|
|
LIns *lhs = ins->oprnd1();
|
|
|
|
LIns *rhs = ins->oprnd2();
|
|
|
|
|
|
|
|
RegisterMask allow = FpRegs;
|
|
|
|
Register ra = findRegFor(lhs, FpRegs);
|
|
|
|
Register rb = (rhs == lhs) ? ra : findRegFor(rhs, FpRegs);
|
|
|
|
|
|
|
|
Register rr = prepResultReg(ins, allow);
|
|
|
|
|
|
|
|
if (op == LIR_fadd)
|
|
|
|
FADDD(ra, rb, rr);
|
|
|
|
else if (op == LIR_fsub)
|
|
|
|
FSUBD(ra, rb, rr);
|
|
|
|
else if (op == LIR_fmul)
|
|
|
|
FMULD(ra, rb, rr);
|
|
|
|
else //if (op == LIR_fdiv)
|
|
|
|
FDIVD(ra, rb, rr);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void Assembler::asm_i2f(LInsp ins)
|
|
|
|
{
|
|
|
|
underrunProtect(32);
|
|
|
|
// where our result goes
|
|
|
|
Register rr = prepResultReg(ins, FpRegs);
|
|
|
|
int d = findMemFor(ins->oprnd1());
|
|
|
|
FITOD(rr, rr);
|
|
|
|
LDDF32(FP, d, rr);
|
|
|
|
}
|
|
|
|
|
|
|
|
Register Assembler::asm_prep_fcall(Reservation *rR, LInsp ins)
|
|
|
|
{
|
|
|
|
if (rR) {
|
|
|
|
Register rr;
|
|
|
|
if ((rr=rR->reg) != UnknownReg && (rmask(rr) & FpRegs))
|
|
|
|
evict(rr);
|
|
|
|
}
|
|
|
|
return prepResultReg(ins, rmask(F0));
|
|
|
|
}
|
|
|
|
|
|
|
|
void Assembler::asm_u2f(LInsp ins)
|
|
|
|
{
|
|
|
|
underrunProtect(72);
|
|
|
|
// where our result goes
|
|
|
|
Register rr = prepResultReg(ins, FpRegs);
|
|
|
|
Register rt = registerAlloc(FpRegs & ~(rmask(rr)));
|
|
|
|
_allocator.addFree(rt);
|
|
|
|
Register gr = findRegFor(ins->oprnd1(), GpRegs);
|
|
|
|
int disp = -8;
|
|
|
|
|
|
|
|
FABSS(rr, rr);
|
|
|
|
FSUBD(rt, rr, rr);
|
|
|
|
LDDF32(SP, disp, rr);
|
|
|
|
STWI(G0, disp+4, SP);
|
|
|
|
LDDF32(SP, disp, rt);
|
|
|
|
STWI(gr, disp+4, SP);
|
|
|
|
STWI(G1, disp, SP);
|
|
|
|
SETHI(0x43300000, G1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Assembler::asm_nongp_copy(Register r, Register s)
|
|
|
|
{
|
|
|
|
underrunProtect(4);
|
|
|
|
NanoAssert((rmask(r) & FpRegs) && (rmask(s) & FpRegs));
|
|
|
|
FMOVD(s, r);
|
|
|
|
}
|
|
|
|
|
|
|
|
NIns * Assembler::asm_jmpcc(bool branchOnFalse, LIns *cond, NIns *targ)
|
|
|
|
{
|
|
|
|
NIns *at = 0;
|
|
|
|
LOpcode condop = cond->opcode();
|
|
|
|
NanoAssert(condop >= LIR_feq && condop <= LIR_fge);
|
|
|
|
underrunProtect(32);
|
|
|
|
intptr_t tt = ((intptr_t)targ - (intptr_t)_nIns + 8) >> 2;
|
|
|
|
// !targ means that it needs patch.
|
|
|
|
if( !(isIMM22((int32_t)tt)) || !targ ) {
|
|
|
|
JMP_long_nocheck((intptr_t)targ);
|
|
|
|
at = _nIns;
|
|
|
|
NOP();
|
|
|
|
BA(0, 5);
|
|
|
|
tt = 4;
|
|
|
|
}
|
|
|
|
NOP();
|
|
|
|
|
|
|
|
// produce the branch
|
|
|
|
if (branchOnFalse)
|
|
|
|
{
|
|
|
|
if (condop == LIR_feq)
|
|
|
|
FBNE(0, tt);
|
|
|
|
else if (condop == LIR_fle)
|
|
|
|
FBG(0, tt);
|
|
|
|
else if (condop == LIR_flt)
|
|
|
|
FBGE(0, tt);
|
|
|
|
else if (condop == LIR_fge)
|
|
|
|
FBL(0, tt);
|
|
|
|
else //if (condop == LIR_fgt)
|
|
|
|
FBLE(0, tt);
|
|
|
|
}
|
|
|
|
else // op == LIR_xt
|
|
|
|
{
|
|
|
|
if (condop == LIR_feq)
|
|
|
|
FBE(0, tt);
|
|
|
|
else if (condop == LIR_fle)
|
|
|
|
FBLE(0, tt);
|
|
|
|
else if (condop == LIR_flt)
|
|
|
|
FBL(0, tt);
|
|
|
|
else if (condop == LIR_fge)
|
|
|
|
FBGE(0, tt);
|
|
|
|
else //if (condop == LIR_fgt)
|
|
|
|
FBG(0, tt);
|
|
|
|
}
|
|
|
|
asm_fcmp(cond);
|
|
|
|
return at;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Assembler::asm_setcc(Register r, LIns *cond)
|
|
|
|
{
|
|
|
|
underrunProtect(8);
|
|
|
|
LOpcode condop = cond->opcode();
|
|
|
|
NanoAssert(condop >= LIR_feq && condop <= LIR_fge);
|
|
|
|
if (condop == LIR_feq)
|
|
|
|
MOVFEI(1, 0, 0, 0, r);
|
|
|
|
else if (condop == LIR_fle)
|
|
|
|
MOVFLEI(1, 0, 0, 0, r);
|
|
|
|
else if (condop == LIR_flt)
|
|
|
|
MOVFLI(1, 0, 0, 0, r);
|
|
|
|
else if (condop == LIR_fge)
|
|
|
|
MOVFGEI(1, 0, 0, 0, r);
|
|
|
|
else // if (condop == LIR_fgt)
|
|
|
|
MOVFGI(1, 0, 0, 0, r);
|
|
|
|
ORI(G0, 0, r);
|
|
|
|
asm_fcmp(cond);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Assembler::asm_fcmp(LIns *cond)
|
|
|
|
{
|
|
|
|
underrunProtect(4);
|
|
|
|
LIns* lhs = cond->oprnd1();
|
|
|
|
LIns* rhs = cond->oprnd2();
|
|
|
|
|
|
|
|
Register rLhs = findRegFor(lhs, FpRegs);
|
|
|
|
Register rRhs = findRegFor(rhs, FpRegs);
|
|
|
|
|
|
|
|
FCMPD(rLhs, rRhs);
|
|
|
|
}
|
2009-07-10 12:58:34 -07:00
|
|
|
|
2009-02-15 18:10:03 -08:00
|
|
|
/** no longer called by patch/unpatch
|
|
|
|
NIns* Assembler::asm_adjustBranch(NIns* at, NIns* target)
|
|
|
|
{
|
|
|
|
NIns* was;
|
|
|
|
was = (NIns*)(((*(uint32_t*)&at[0] & 0x3FFFFF) << 10) | (*(uint32_t*)&at[1] & 0x3FF ));
|
|
|
|
*(uint32_t*)&at[0] &= 0xFFC00000;
|
|
|
|
*(uint32_t*)&at[0] |= ((intptr_t)target >> 10) & 0x3FFFFF;
|
|
|
|
*(uint32_t*)&at[1] &= 0xFFFFFC00;
|
|
|
|
*(uint32_t*)&at[1] |= (intptr_t)target & 0x3FF;
|
|
|
|
return was;
|
|
|
|
}
|
|
|
|
*/
|
2009-07-10 12:58:34 -07:00
|
|
|
|
2009-02-15 18:10:03 -08:00
|
|
|
void Assembler::nativePageReset()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
Register Assembler::asm_binop_rhs_reg(LInsp ins)
|
|
|
|
{
|
2009-07-10 12:58:34 -07:00
|
|
|
return UnknownReg;
|
2009-02-15 18:10:03 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
void Assembler::nativePageSetup()
|
|
|
|
{
|
|
|
|
if (!_nIns) _nIns = pageAlloc();
|
|
|
|
if (!_nExitIns) _nExitIns = pageAlloc(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Assembler::underrunProtect(int bytes)
|
|
|
|
{
|
|
|
|
intptr_t u = bytes + sizeof(PageHeader)/sizeof(NIns) + 16;
|
|
|
|
if (!samepage((intptr_t)_nIns-u,_nIns)) {
|
|
|
|
NIns* target = _nIns;
|
|
|
|
_nIns = pageAlloc(_inExit);
|
|
|
|
JMP_long_nocheck((intptr_t)target);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
void Assembler::asm_ret(LInsp ins)
|
|
|
|
{
|
|
|
|
if (_nIns != _epilogue) {
|
|
|
|
JMP(_epilogue);
|
|
|
|
}
|
|
|
|
assignSavedRegs();
|
|
|
|
LIns *val = ins->oprnd1();
|
|
|
|
if (ins->isop(LIR_ret)) {
|
|
|
|
findSpecificRegFor(val, retRegs[0]);
|
|
|
|
} else {
|
|
|
|
findSpecificRegFor(val, F0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
|
|
|
#endif /* FEATURE_NANOJIT */
|
|
|
|
}
|