1 /* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 4 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * The Original Code is [Open Source Virtual Machine].
17 * The Initial Developer of the Original Code is
18 * Adobe System Incorporated.
19 * Portions created by the Initial Developer are Copyright (C) 2004-2007
20 * the Initial Developer. All Rights Reserved.
24 * Mozilla TraceMonkey Team
25 * Asko Tontti <atontti@cc.hut.fi>
27 * Alternatively, the contents of this file may be used under the terms of
28 * either the GNU General Public License Version 2 or later (the "GPL"), or
29 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 * in which case the provisions of the GPL or the LGPL are applicable instead
31 * of those above. If you wish to allow use of your version of this file only
32 * under the terms of either the GPL or the LGPL, and not to allow others to
33 * use your version of this file under the terms of the MPL, indicate your
34 * decision by deleting the provisions above and replace them with the notice
35 * and other provisions required by the GPL or the LGPL. If you do not delete
36 * the provisions above, a recipient may use your version of this file under
37 * the terms of any one of the MPL, the GPL or the LGPL.
39 * ***** END LICENSE BLOCK ***** */
42 // for MakeDataExecutable
43 #include <CoreServices/CoreServices.h>
46 #if defined AVMPLUS_UNIX || defined AVMPLUS_MAC
55 #ifdef FEATURE_NANOJIT
58 const char *regNames
[] = {
59 #if defined NANOJIT_IA32
60 "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi",
61 "xmm0","xmm1","xmm2","xmm3","xmm4","xmm5","xmm6","xmm7",
62 "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7"
63 #elif defined NANOJIT_AMD64
64 "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
65 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
66 "xmm0","xmm1","xmm2","xmm3","xmm4","xmm5","xmm6","xmm7",
67 "xmm8","xmm9","xmm10","xmm11","xmm12","xmm13","xmm14","xmm15"
72 #if defined NANOJIT_IA32
73 const Register
Assembler::argRegs
[] = { ECX
, EDX
};
74 const Register
Assembler::retRegs
[] = { EAX
, EDX
};
75 const Register
Assembler::savedRegs
[] = { EBX
, ESI
, EDI
};
76 #elif defined NANOJIT_AMD64
78 const Register
Assembler::argRegs
[] = { R8
, R9
, RCX
, RDX
};
80 const Register
Assembler::argRegs
[] = { RDI
, RSI
, RDX
, RCX
, R8
, R9
};
82 const Register
Assembler::retRegs
[] = { RAX
, RDX
};
83 const Register
Assembler::savedRegs
[] = { R13
, R14
, R15
};
86 const static uint8_t max_abi_regs
[] = {
94 void Assembler::nInit(AvmCore
* core
)
100 NIns
* Assembler::genPrologue()
105 uint32_t stackNeeded
= STACK_GRANULARITY
* _activation
.highwatermark
;
107 uint32_t stackPushed
=
108 STACK_GRANULARITY
+ // returnaddr
109 STACK_GRANULARITY
; // ebp
111 if (!_thisfrag
->lirbuf
->explicitSavedRegs
)
112 stackPushed
+= NumSavedRegs
* STACK_GRANULARITY
;
114 uint32_t aligned
= alignUp(stackNeeded
+ stackPushed
, NJ_ALIGN_STACK
);
115 uint32_t amt
= aligned
- stackPushed
;
117 // Reserve stackNeeded bytes, padded
118 // to preserve NJ_ALIGN_STACK-byte alignment.
121 #if defined NANOJIT_IA32
123 #elif defined NANOJIT_AMD64
128 verbose_only( outputAddr
=true; asm_output("[frag entry]"); )
129 NIns
*fragEntry
= _nIns
;
130 MR(FP
, SP
); // Establish our own FP.
131 PUSHr(FP
); // Save caller's FP.
133 if (!_thisfrag
->lirbuf
->explicitSavedRegs
)
134 for (int i
= 0; i
< NumSavedRegs
; ++i
)
137 // align the entry point
143 void Assembler::asm_align_code() {
144 static uint8_t nop
[][9] = {
148 {0x0f,0x1f,0x40,0x00},
149 {0x0f,0x1f,0x44,0x00,0x00},
150 {0x66,0x0f,0x1f,0x44,0x00,0x00},
151 {0x0f,0x1f,0x80,0x00,0x00,0x00,0x00},
152 {0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00},
153 {0x66,0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00},
156 while((n
= uintptr_t(_nIns
) & 15) != 0) {
161 memcpy(_nIns
, nop
[n
-1], n
);
162 asm_output("nop%d", n
);
166 void Assembler::nFragExit(LInsp guard
)
168 SideExit
*exit
= guard
->record()->exit
;
169 bool trees
= _frago
->core()->config
.tree_opt
;
170 Fragment
*frag
= exit
->target
;
172 bool destKnown
= (frag
&& frag
->fragEntry
);
173 if (destKnown
&& !trees
)
175 // already exists, emit jump now. no patching required.
176 JMP(frag
->fragEntry
);
181 // target doesn't exit yet. emit jump to epilog, and set up to patch later.
182 lr
= guard
->record();
183 #if defined NANOJIT_AMD64
184 /* 8 bytes for address, 4 for imm32, 2 for jmp */
187 *(intptr_t *)_nIns
= intptr_t(_epilogue
);
195 // first restore ESP from EBP, undoing SUBi(SP,amt) from genPrologue
198 // return value is GuardRecord*
199 #if defined NANOJIT_IA32
201 #elif defined NANOJIT_AMD64
202 LDQi(RAX
, intptr_t(lr
));
206 NIns
*Assembler::genEpilogue()
210 if (!_thisfrag
->lirbuf
->explicitSavedRegs
)
211 for (int i
= NumSavedRegs
- 1; i
>= 0; --i
)
214 POPr(FP
); // Restore caller's FP.
215 MR(SP
,FP
); // pop the stack frame
219 #if defined NANOJIT_IA32
220 void Assembler::asm_call(LInsp ins
)
222 const CallInfo
* call
= ins
->callInfo();
223 // must be signed, not unsigned
224 uint32_t iargs
= call
->count_iargs();
225 int32_t fargs
= call
->count_args() - iargs
- call
->isIndirect();
227 bool imt
= call
->isInterface();
231 uint32_t max_regs
= max_abi_regs
[call
->_abi
];
232 if (max_regs
> iargs
)
235 int32_t istack
= iargs
-max_regs
; // first 2 4B args are in registers
237 const int32_t pushsize
= 4*istack
+ 8*fargs
; // actual stack space used
240 // msc is slack, and MIR doesn't do anything extra, so lets use this
241 // call-site alignment to at least have code size parity with MIR.
242 uint32_t align
= 4;//NJ_ALIGN_STACK;
244 uint32_t align
= NJ_ALIGN_STACK
;
248 // stack re-alignment
249 // only pop our adjustment amount since callee pops args in FASTCALL mode
250 extra
= alignUp(pushsize
, align
) - pushsize
;
251 if (call
->_abi
== ABI_CDECL
) {
252 // with CDECL only, caller pops args
253 ADDi(SP
, extra
+pushsize
);
254 } else if (extra
> 0) {
259 bool indirect
= false;
260 if (ins
->isop(LIR_call
) || ins
->isop(LIR_fcall
)) {
264 // indirect call. x86 Calling conventions don't use EAX as an
265 // argument, and do use EAX as a return value. We need a register
266 // for the address to call, so we use EAX since it will always be
268 NanoAssert(ins
->isop(LIR_calli
) || ins
->isop(LIR_fcalli
));
273 // make sure fpu stack is empty before call (restoreCallerSaved)
274 NanoAssert(_allocator
.isFree(FST0
));
275 // note: this code requires that ref arguments (ARGSIZE_Q)
276 // be one of the first two arguments
277 // pre-assign registers to the first N 4B args based on the calling convention
280 ArgSize sizes
[2*MAXARGS
];
281 uint32_t argc
= call
->get_sizes(sizes
);
284 asm_arg(ARGSIZE_LO
, ins
->arg(argc
), EAX
);
288 // interface thunk calling convention: put iid in EDX
289 NanoAssert(call
->_abi
== ABI_CDECL
);
291 asm_arg(ARGSIZE_LO
, ins
->arg(argc
), EDX
);
294 for(uint32_t i
=0; i
< argc
; i
++)
296 uint32_t j
= argc
-i
-1;
297 ArgSize sz
= sizes
[j
];
298 Register r
= UnknownReg
;
299 if (n
< max_regs
&& sz
!= ARGSIZE_F
) {
300 r
= argRegs
[n
++]; // tell asm_arg what reg to use
302 asm_arg(sz
, ins
->arg(j
), r
);
309 #elif defined NANOJIT_AMD64
311 void Assembler::asm_call(LInsp ins
)
313 Register fpu_reg
= XMM0
;
314 const CallInfo
* call
= ins
->callInfo();
320 uint32_t argc
= call
->get_sizes(sizes
);
322 for(uint32_t i
=0; i
< argc
; i
++)
324 uint32_t j
= argc
-i
-1;
325 ArgSize sz
= sizes
[j
];
326 Register r
= UnknownReg
;
327 if (sz
!= ARGSIZE_F
) {
328 r
= argRegs
[n
++]; // tell asm_arg what reg to use
331 fpu_reg
= nextreg(fpu_reg
);
333 findSpecificRegFor(ins
->arg(j
), r
);
338 void Assembler::nMarkExecute(Page
* page
, int flags
)
340 NanoAssert(sizeof(Page
) == NJ_PAGE_SIZE
);
341 #if defined WIN32 || defined WIN64
343 static const DWORD kProtFlags
[4] =
346 PAGE_READWRITE
, // PAGE_WRITE
347 PAGE_EXECUTE_READ
, // PAGE_EXEC
348 PAGE_EXECUTE_READWRITE
// PAGE_EXEC|PAGE_WRITE
350 DWORD prot
= kProtFlags
[flags
& (PAGE_WRITE
|PAGE_EXEC
)];
351 BOOL res
= VirtualProtect(page
, NJ_PAGE_SIZE
, prot
, &dwIgnore
);
354 // todo: we can't abort or assert here, we have to fail gracefully.
355 NanoAssertMsg(false, "FATAL ERROR: VirtualProtect() failed\n");
357 #elif defined AVMPLUS_UNIX || defined AVMPLUS_MAC
358 static const int kProtFlags
[4] =
361 PROT_READ
|PROT_WRITE
, // PAGE_WRITE
362 PROT_READ
|PROT_EXEC
, // PAGE_EXEC
363 PROT_READ
|PROT_WRITE
|PROT_EXEC
// PAGE_EXEC|PAGE_WRITE
365 int prot
= kProtFlags
[flags
& (PAGE_WRITE
|PAGE_EXEC
)];
366 intptr_t addr
= (intptr_t)page
;
367 addr
&= ~((uintptr_t)NJ_PAGE_SIZE
- 1);
368 NanoAssert(addr
== (intptr_t)page
);
370 if (mprotect((char *)addr
, NJ_PAGE_SIZE
, prot
) == -1)
372 if (mprotect((void *)addr
, NJ_PAGE_SIZE
, prot
) == -1)
375 // todo: we can't abort or assert here, we have to fail gracefully.
376 NanoAssertMsg(false, "FATAL ERROR: mprotect(PROT_EXEC) failed\n");
384 Register
Assembler::nRegisterAllocFromSet(int set
)
387 RegAlloc
®s
= _allocator
;
392 bsf eax
, set
// i = first bit set
393 btr
RegAlloc::free
[ecx
], eax
// free &= ~rmask(i)
397 unsigned long tr
, fr
;
398 _BitScanForward(&tr
, set
);
399 _bittestandreset(&fr
, tr
);
407 : "=m"(r
) : "m"(set
), "m"(regs
.free
) : "%eax", "memory" );
412 void Assembler::nRegisterResetAll(RegAlloc
& a
)
414 // add scratch registers to our free list for the allocator
417 a
.free
= SavedRegs
| ScratchRegs
;
418 #if defined NANOJIT_IA32
422 debug_only( a
.managed
= a
.free
; )
425 NIns
* Assembler::nPatchBranch(NIns
* branch
, NIns
* targ
)
427 #if defined NANOJIT_IA32
429 intptr_t offset
= intptr_t(targ
) - intptr_t(branch
);
430 if (branch
[0] == JMP32
) {
431 was
= branch
+ *(int32_t*)&branch
[1] + 5;
432 *(int32_t*)&branch
[1] = offset
- 5;
433 } else if (branch
[0] == JCC32
) {
434 was
= branch
+ *(int32_t*)&branch
[2] + 6;
435 *(int32_t*)&branch
[2] = offset
- 6;
437 NanoAssertMsg(0, "Unknown branch type in nPatchBranch");
439 if (branch
[0] == 0xFF && branch
[1] == 0x25) {
441 mem
= &branch
[6] + *(int32_t *)&branch
[2];
442 was
= *(intptr_t*)mem
;
443 *(intptr_t *)mem
= intptr_t(targ
);
445 NanoAssertMsg(0, "Unknown branch type in nPatchBranch");
451 RegisterMask
Assembler::hint(LIns
* i
, RegisterMask allow
)
453 uint32_t op
= i
->opcode();
455 if (op
== LIR_call
|| op
== LIR_calli
) {
456 prefer
&= rmask(retRegs
[0]);
458 else if (op
== LIR_fcall
|| op
== LIR_fcalli
) {
459 prefer
&= rmask(FST0
);
461 else if (op
== LIR_param
) {
462 uint32_t max_regs
= max_abi_regs
[_thisfrag
->lirbuf
->abi
];
463 if (i
->imm8() < max_regs
)
464 prefer
&= rmask(Register(i
->imm8()));
466 else if (op
== LIR_callh
|| op
== LIR_rsh
&& i
->oprnd1()->opcode()==LIR_callh
) {
467 prefer
&= rmask(retRegs
[1]);
469 else if (i
->isCmp()) {
470 prefer
&= AllowableFlagRegs
;
472 else if (i
->isconst()) {
473 prefer
&= ScratchRegs
;
475 return (_allocator
.free
& prefer
) ? prefer
: allow
;
478 void Assembler::asm_qjoin(LIns
*ins
)
480 int d
= findMemFor(ins
);
482 LIns
* lo
= ins
->oprnd1();
483 LIns
* hi
= ins
->oprnd2();
485 Reservation
*resv
= getresv(ins
);
486 Register rr
= resv
->reg
;
488 if (rr
!= UnknownReg
&& (rmask(rr
) & FpRegs
))
493 STi(FP
, d
+4, hi
->constval());
497 Register r
= findRegFor(hi
, GpRegs
);
503 STi(FP
, d
, lo
->constval());
507 // okay if r gets recycled.
508 Register r
= findRegFor(lo
, GpRegs
);
512 freeRsrcOf(ins
, false); // if we had a reg in use, emit a ST to flush it to mem
515 void Assembler::asm_load(int d
, Register r
)
517 if (rmask(r
) & FpRegs
)
519 #if defined NANOJIT_IA32
520 if (rmask(r
) & XmmRegs
) {
523 #if defined NANOJIT_IA32
529 #if defined NANOJIT_AMD64
530 else if (i
->opcode() == LIR_param
)
541 void Assembler::asm_restore(LInsp i
, Reservation
*resv
, Register r
)
543 if (i
->isop(LIR_alloc
)) {
544 verbose_only( if (_verbose
) { outputForEOL(" <= remat %s size %d", _thisfrag
->lirbuf
->names
->formatRef(i
), i
->size()); } )
545 LEA(r
, disp(resv
), FP
);
547 else if (i
->isconst()) {
548 if (!resv
->arIndex
) {
551 LDi(r
, i
->constval());
554 int d
= findMemFor(i
);
555 verbose_only( if (_verbose
) { outputForEOL(" <= restore %s", _thisfrag
->lirbuf
->names
->formatRef(i
)); } )
560 void Assembler::asm_store32(LIns
*value
, int dr
, LIns
*base
)
562 if (value
->isconst())
564 Register rb
= getBaseReg(base
, dr
, GpRegs
);
565 int c
= value
->constval();
570 // make sure what is in a register
571 Reservation
*rA
, *rB
;
573 if (base
->isop(LIR_alloc
)) {
575 dr
+= findMemFor(base
);
576 ra
= findRegFor(value
, GpRegs
);
577 } else if (base
->isconst()) {
579 dr
+= base
->constval();
580 ra
= findRegFor(value
, GpRegs
);
583 findRegFor2(GpRegs
, value
, rA
, base
, rB
);
591 void Assembler::asm_spill(Register rr
, int d
, bool pop
, bool quad
)
596 // save to spill location
597 if (rmask(rr
) & FpRegs
)
599 #if defined NANOJIT_IA32
600 if (rmask(rr
) & XmmRegs
) {
603 #if defined NANOJIT_IA32
605 FSTQ((pop
?1:0), d
, FP
);
609 #if defined NANOJIT_AMD64
620 #if defined NANOJIT_IA32
621 else if (pop
&& (rmask(rr
) & x87Regs
))
623 // pop the fpu result since it isn't used
629 void Assembler::asm_load64(LInsp ins
)
631 LIns
* base
= ins
->oprnd1();
632 int db
= ins
->oprnd2()->constval();
633 Reservation
*resv
= getresv(ins
);
634 Register rr
= resv
->reg
;
636 if (rr
!= UnknownReg
&& rmask(rr
) & XmmRegs
)
638 freeRsrcOf(ins
, false);
639 Register rb
= getBaseReg(base
, db
, GpRegs
);
642 #if defined NANOJIT_AMD64
643 else if (rr
!= UnknownReg
&& rmask(rr
) & GpRegs
)
645 freeRsrcOf(ins
, false);
646 Register rb
= findRegFor(base
, GpRegs
);
652 Register rb
= findRegFor(base
, GpRegs
);
654 /* We need a temporary register we can move the desination into */
655 rr
= registerAlloc(GpRegs
);
661 _allocator
.addFree(rr
);
663 freeRsrcOf(ins
, false);
665 #elif defined NANOJIT_IA32
670 if (base
->isop(LIR_alloc
)) {
672 db
+= findMemFor(base
);
674 rb
= findRegFor(base
, GpRegs
);
676 resv
->reg
= UnknownReg
;
678 // don't use an fpu reg to simply load & store the value.
680 asm_mmq(FP
, dr
, rb
, db
);
682 freeRsrcOf(ins
, false);
684 if (rr
!= UnknownReg
)
686 NanoAssert(rmask(rr
)&FpRegs
);
687 _allocator
.retire(rr
);
694 void Assembler::asm_store64(LInsp value
, int dr
, LInsp base
)
696 if (value
->isconstq())
698 // if a constant 64-bit value just store it now rather than
699 // generating a pointless store/load/store sequence
701 if (base
->isop(LIR_alloc
)) {
703 dr
+= findMemFor(base
);
705 rb
= findRegFor(base
, GpRegs
);
707 const int32_t* p
= (const int32_t*) (value
-2);
713 #if defined NANOJIT_IA32
714 if (value
->isop(LIR_ldq
) || value
->isop(LIR_ldqc
) || value
->isop(LIR_qjoin
))
716 // value is 64bit struct or int64_t, or maybe a double.
717 // it may be live in an FPU reg. Either way, don't
718 // put it in an FPU reg just to load & store it.
720 // a) if we know it's not a double, this is right.
721 // b) if we guarded that its a double, this store could be on
722 // the side exit, copying a non-double.
723 // c) maybe its a double just being stored. oh well.
726 Register rv
= findRegFor(value
, XmmRegs
);
728 if (base
->isop(LIR_alloc
)) {
730 dr
+= findMemFor(base
);
732 rb
= findRegFor(base
, GpRegs
);
738 int da
= findMemFor(value
);
740 if (base
->isop(LIR_alloc
)) {
742 dr
+= findMemFor(base
);
744 rb
= findRegFor(base
, GpRegs
);
746 asm_mmq(rb
, dr
, FP
, da
);
751 if (base
->isop(LIR_alloc
)) {
753 dr
+= findMemFor(base
);
755 rb
= findRegFor(base
, GpRegs
);
758 // if value already in a reg, use that, otherwise
759 // try to get it into XMM regs before FPU regs.
760 Reservation
* rA
= getresv(value
);
762 int pop
= !rA
|| rA
->reg
==UnknownReg
;
764 rv
= findRegFor(value
, config
.sse2
? XmmRegs
: FpRegs
);
769 if (rmask(rv
) & XmmRegs
) {
774 #elif defined NANOJIT_AMD64
775 /* If this is not a float operation, we can use GpRegs instead.
776 * We can do this in a few other cases but for now I'll keep it simple.
778 Register rb
= findRegFor(base
, GpRegs
);
779 Reservation
*rV
= getresv(value
);
781 if (rV
!= NULL
&& rV
->reg
!= UnknownReg
) {
782 if (rmask(rV
->reg
) & GpRegs
) {
783 STQ(rb
, dr
, rV
->reg
);
785 SSE_STQ(dr
, rb
, rV
->reg
);
790 /* Try to catch some common patterns.
791 * Note: this is a necessity, since in between things like
792 * asm_fop() could see the reservation and try to use a non-SSE
793 * register for adding. Same for asm_qbinop in theory.
794 * There should probably be asserts to catch more cases.
796 if (value
->isop(LIR_u2f
)
797 || value
->isop(LIR_i2f
)
798 || (value
->opcode() >= LIR_fneg
&& value
->opcode() <= LIR_fmul
)
799 || value
->opcode() == LIR_fdiv
800 || value
->opcode() == LIR_fcall
) {
801 rv
= findRegFor(value
, XmmRegs
);
804 rv
= findRegFor(value
, GpRegs
);
812 * copy 64 bits: (rd+dd) <- (rs+ds)
814 void Assembler::asm_mmq(Register rd
, int dd
, Register rs
, int ds
)
816 // value is either a 64bit struct or maybe a float
817 // that isn't live in an FPU reg. Either way, don't
818 // put it in an FPU reg just to load & store it.
819 #if defined NANOJIT_IA32
823 // use SSE to load+store 64bits
824 Register t
= registerAlloc(XmmRegs
);
825 _allocator
.addFree(t
);
828 #if defined NANOJIT_IA32
833 Register t
= registerAlloc(GpRegs
& ~(rmask(rd
)|rmask(rs
)));
834 _allocator
.addFree(t
);
843 NIns
* Assembler::asm_branch(bool branchOnFalse
, LInsp cond
, NIns
* targ
, bool isfar
)
846 LOpcode condop
= cond
->opcode();
847 NanoAssert(cond
->isCond());
849 if (condop
>= LIR_feq
&& condop
<= LIR_fge
)
851 return asm_jmpcc(branchOnFalse
, cond
, targ
);
854 // produce the branch
857 if (condop
== LIR_eq
)
859 else if (condop
== LIR_ov
)
861 else if (condop
== LIR_cs
)
863 else if (condop
== LIR_lt
)
865 else if (condop
== LIR_le
)
867 else if (condop
== LIR_gt
)
869 else if (condop
== LIR_ge
)
871 else if (condop
== LIR_ult
)
873 else if (condop
== LIR_ule
)
875 else if (condop
== LIR_ugt
)
877 else //if (condop == LIR_uge)
882 if (condop
== LIR_eq
)
884 else if (condop
== LIR_ov
)
886 else if (condop
== LIR_cs
)
888 else if (condop
== LIR_lt
)
890 else if (condop
== LIR_le
)
892 else if (condop
== LIR_gt
)
894 else if (condop
== LIR_ge
)
896 else if (condop
== LIR_ult
)
898 else if (condop
== LIR_ule
)
900 else if (condop
== LIR_ugt
)
902 else //if (condop == LIR_uge)
910 void Assembler::asm_cmp(LIns
*cond
)
912 LOpcode condop
= cond
->opcode();
914 // LIR_ov and LIR_cs recycle the flags set by arithmetic ops
915 if ((condop
== LIR_ov
) || (condop
== LIR_cs
))
918 LInsp lhs
= cond
->oprnd1();
919 LInsp rhs
= cond
->oprnd2();
920 Reservation
*rA
, *rB
;
922 NanoAssert((!lhs
->isQuad() && !rhs
->isQuad()) || (lhs
->isQuad() && rhs
->isQuad()));
924 // Not supported yet.
925 #if !defined NANOJIT_64BIT
926 NanoAssert(!lhs
->isQuad() && !rhs
->isQuad());
929 // ready to issue the compare
932 int c
= rhs
->constval();
933 if (c
== 0 && cond
->isop(LIR_eq
)) {
934 Register r
= findRegFor(lhs
, GpRegs
);
936 #if defined NANOJIT_64BIT
942 // No 64-bit immediates so fall-back to below
944 else if (!rhs
->isQuad()) {
945 Register r
= getBaseReg(lhs
, c
, GpRegs
);
951 findRegFor2(GpRegs
, lhs
, rA
, rhs
, rB
);
952 Register ra
= rA
->reg
;
953 Register rb
= rB
->reg
;
955 #if defined NANOJIT_64BIT
964 void Assembler::asm_loop(LInsp ins
, NInsList
& loopJumps
)
967 loopJumps
.add(_nIns
);
969 // If the target we are looping to is in a different fragment, we have to restore
970 // SP since we will target fragEntry and not loopEntry.
971 if (ins
->record()->exit
->target
!= _thisfrag
)
975 void Assembler::asm_fcond(LInsp ins
)
977 // only want certain regs
978 Register r
= prepResultReg(ins
, AllowableFlagRegs
);
983 // SETcc only sets low 8 bits, so extend
990 void Assembler::asm_cond(LInsp ins
)
992 // only want certain regs
993 LOpcode op
= ins
->opcode();
994 Register r
= prepResultReg(ins
, AllowableFlagRegs
);
995 // SETcc only sets low 8 bits, so extend
999 else if (op
== LIR_ov
)
1001 else if (op
== LIR_cs
)
1003 else if (op
== LIR_lt
)
1005 else if (op
== LIR_le
)
1007 else if (op
== LIR_gt
)
1009 else if (op
== LIR_ge
)
1011 else if (op
== LIR_ult
)
1013 else if (op
== LIR_ule
)
1015 else if (op
== LIR_ugt
)
1017 else // if (op == LIR_uge)
1022 void Assembler::asm_arith(LInsp ins
)
1024 LOpcode op
= ins
->opcode();
1025 LInsp lhs
= ins
->oprnd1();
1026 LInsp rhs
= ins
->oprnd2();
1028 Register rb
= UnknownReg
;
1029 RegisterMask allow
= GpRegs
;
1030 bool forceReg
= (op
== LIR_mul
|| !rhs
->isconst());
1032 /* Even if lhs == rhs && forceReg, shift instructions require ECX on the rhs. */
1033 if ((lhs
!= rhs
|| (op
== LIR_lsh
|| op
== LIR_rsh
|| op
== LIR_ush
)) && forceReg
)
1035 if ((rb
= asm_binop_rhs_reg(ins
)) == UnknownReg
) {
1036 rb
= findRegFor(rhs
, allow
);
1038 allow
&= ~rmask(rb
);
1040 else if ((op
== LIR_add
||op
== LIR_addp
) && lhs
->isop(LIR_alloc
) && rhs
->isconst()) {
1041 // add alloc+const, use lea
1042 Register rr
= prepResultReg(ins
, allow
);
1043 int d
= findMemFor(lhs
) + rhs
->constval();
1047 Register rr
= prepResultReg(ins
, allow
);
1048 Reservation
* rA
= getresv(lhs
);
1050 // if this is last use of lhs in reg, we can re-use result reg
1051 if (rA
== 0 || (ra
= rA
->reg
) == UnknownReg
)
1052 ra
= findSpecificRegFor(lhs
, rr
);
1053 // else, rA already has a register assigned.
1060 if (op
== LIR_add
|| op
== LIR_addp
)
1062 else if (op
== LIR_sub
)
1064 else if (op
== LIR_mul
)
1066 else if (op
== LIR_and
)
1068 else if (op
== LIR_or
)
1070 else if (op
== LIR_xor
)
1072 else if (op
== LIR_lsh
)
1074 else if (op
== LIR_rsh
)
1076 else if (op
== LIR_ush
)
1079 NanoAssertMsg(0, "Unsupported");
1083 int c
= rhs
->constval();
1084 if (op
== LIR_add
|| op
== LIR_addp
) {
1085 #ifdef NANOJIT_IA32_TODO
1087 // this doesn't set cc's, only use it when cc's not required.
1089 ra
= rr
; // suppress mov
1095 } else if (op
== LIR_sub
) {
1105 } else if (op
== LIR_and
)
1107 else if (op
== LIR_or
)
1109 else if (op
== LIR_xor
)
1111 else if (op
== LIR_lsh
)
1113 else if (op
== LIR_rsh
)
1115 else if (op
== LIR_ush
)
1118 NanoAssertMsg(0, "Unsupported");
1125 void Assembler::asm_neg_not(LInsp ins
)
1127 LOpcode op
= ins
->opcode();
1128 Register rr
= prepResultReg(ins
, GpRegs
);
1130 LIns
* lhs
= ins
->oprnd1();
1131 Reservation
*rA
= getresv(lhs
);
1132 // if this is last use of lhs in reg, we can re-use result reg
1134 if (rA
== 0 || (ra
=rA
->reg
) == UnknownReg
)
1135 ra
= findSpecificRegFor(lhs
, rr
);
1136 // else, rA already has a register assigned.
1147 void Assembler::asm_ld(LInsp ins
)
1149 LOpcode op
= ins
->opcode();
1150 LIns
* base
= ins
->oprnd1();
1151 LIns
* disp
= ins
->oprnd2();
1152 Register rr
= prepResultReg(ins
, GpRegs
);
1153 int d
= disp
->constval();
1156 /* Can't use this on AMD64, no 64-bit immediate addresses. */
1157 if (base
->isconst()) {
1158 intptr_t addr
= base
->constval();
1162 else if (op
== LIR_ldcs
)
1169 /* :TODO: Use this on AMD64 as well. */
1170 /* Search for add(X,Y) */
1171 if (base
->opcode() == LIR_piadd
) {
1173 LIns
*lhs
= base
->oprnd1();
1174 LIns
*rhs
= base
->oprnd2();
1176 /* See if we can bypass any SHLs, by searching for
1177 * add(X, shl(Y,Z)) -> mov r, [X+Y*Z]
1179 if (rhs
->opcode() == LIR_pilsh
&& rhs
->oprnd2()->isconst()) {
1180 scale
= rhs
->oprnd2()->constval();
1181 if (scale
>= 1 && scale
<= 3)
1182 rhs
= rhs
->oprnd1();
1188 Reservation
*rL
= getresv(lhs
);
1190 /* Does LHS have a register yet? If not, re-use the result reg.
1191 * :TODO: If LHS is const, we could eliminate a register use.
1193 if (rL
== NULL
|| rL
->reg
== UnknownReg
)
1194 rleft
= findSpecificRegFor(lhs
, rr
);
1198 Register rright
= UnknownReg
;
1199 Reservation
*rR
= getresv(rhs
);
1201 /* Does RHS have a register yet? If not, try to re-use the result reg. */
1202 if (rr
!= rleft
&& (rR
== NULL
|| rR
->reg
== UnknownReg
))
1203 rright
= findSpecificRegFor(rhs
, rr
);
1204 if (rright
== UnknownReg
)
1205 rright
= findRegFor(rhs
, GpRegs
& ~(rmask(rleft
)));
1208 LD8Zsib(rr
, d
, rleft
, rright
, scale
);
1209 else if (op
== LIR_ldcs
)
1210 LD16Zsib(rr
, d
, rleft
, rright
, scale
);
1212 LDsib(rr
, d
, rleft
, rright
, scale
);
1218 Register ra
= getBaseReg(base
, d
, GpRegs
);
1221 else if (op
== LIR_ldcs
)
1227 void Assembler::asm_cmov(LInsp ins
)
1229 LOpcode op
= ins
->opcode();
1230 LIns
* condval
= ins
->oprnd1();
1231 NanoAssert(condval
->isCmp());
1233 LIns
* values
= ins
->oprnd2();
1235 NanoAssert(values
->opcode() == LIR_2
);
1236 LIns
* iftrue
= values
->oprnd1();
1237 LIns
* iffalse
= values
->oprnd2();
1239 NanoAssert(op
== LIR_qcmov
|| (!iftrue
->isQuad() && !iffalse
->isQuad()));
1241 const Register rr
= prepResultReg(ins
, GpRegs
);
1243 // this code assumes that neither LD nor MR nor MRcc set any of the condition flags.
1244 // (This is true on Intel, is it true on all architectures?)
1245 const Register iffalsereg
= findRegFor(iffalse
, GpRegs
& ~rmask(rr
));
1246 if (op
== LIR_cmov
) {
1247 switch (condval
->opcode())
1249 // note that these are all opposites...
1250 case LIR_eq
: MRNE(rr
, iffalsereg
); break;
1251 case LIR_ov
: MRNO(rr
, iffalsereg
); break;
1252 case LIR_cs
: MRNC(rr
, iffalsereg
); break;
1253 case LIR_lt
: MRGE(rr
, iffalsereg
); break;
1254 case LIR_le
: MRG(rr
, iffalsereg
); break;
1255 case LIR_gt
: MRLE(rr
, iffalsereg
); break;
1256 case LIR_ge
: MRL(rr
, iffalsereg
); break;
1257 case LIR_ult
: MRAE(rr
, iffalsereg
); break;
1258 case LIR_ule
: MRA(rr
, iffalsereg
); break;
1259 case LIR_ugt
: MRBE(rr
, iffalsereg
); break;
1260 case LIR_uge
: MRB(rr
, iffalsereg
); break;
1261 debug_only( default: NanoAssert(0); break; )
1263 } else if (op
== LIR_qcmov
) {
1264 #if !defined NANOJIT_64BIT
1267 switch (condval
->opcode())
1269 // note that these are all opposites...
1270 case LIR_eq
: MRQNE(rr
, iffalsereg
); break;
1271 case LIR_ov
: MRQNO(rr
, iffalsereg
); break;
1272 case LIR_cs
: MRQNC(rr
, iffalsereg
); break;
1273 case LIR_lt
: MRQGE(rr
, iffalsereg
); break;
1274 case LIR_le
: MRQG(rr
, iffalsereg
); break;
1275 case LIR_gt
: MRQLE(rr
, iffalsereg
); break;
1276 case LIR_ge
: MRQL(rr
, iffalsereg
); break;
1277 case LIR_ult
: MRQAE(rr
, iffalsereg
); break;
1278 case LIR_ule
: MRQA(rr
, iffalsereg
); break;
1279 case LIR_ugt
: MRQBE(rr
, iffalsereg
); break;
1280 case LIR_uge
: MRQB(rr
, iffalsereg
); break;
1281 debug_only( default: NanoAssert(0); break; )
1285 /*const Register iftruereg =*/ findSpecificRegFor(iftrue
, rr
);
1289 void Assembler::asm_qhi(LInsp ins
)
1291 Register rr
= prepResultReg(ins
, GpRegs
);
1292 LIns
*q
= ins
->oprnd1();
1293 int d
= findMemFor(q
);
1297 void Assembler::asm_param(LInsp ins
)
1299 uint32_t a
= ins
->imm8();
1300 uint32_t kind
= ins
->imm8b();
1303 AbiKind abi
= _thisfrag
->lirbuf
->abi
;
1304 uint32_t abi_regcount
= max_abi_regs
[abi
];
1305 if (a
< abi_regcount
) {
1306 // incoming arg in register
1307 prepResultReg(ins
, rmask(argRegs
[a
]));
1309 // incoming arg is on stack, and EBP points nearby (see genPrologue)
1310 Register r
= prepResultReg(ins
, GpRegs
);
1311 int d
= (a
- abi_regcount
) * sizeof(intptr_t) + 8;
1317 prepResultReg(ins
, rmask(savedRegs
[a
]));
1321 void Assembler::asm_short(LInsp ins
)
1323 Register rr
= prepResultReg(ins
, GpRegs
);
1324 int32_t val
= ins
->imm16();
1331 void Assembler::asm_int(LInsp ins
)
1333 Register rr
= prepResultReg(ins
, GpRegs
);
1334 int32_t val
= ins
->imm32();
1341 void Assembler::asm_quad(LInsp ins
)
1343 #if defined NANOJIT_IA32
1344 Reservation
*rR
= getresv(ins
);
1345 Register rr
= rR
->reg
;
1346 if (rr
!= UnknownReg
)
1348 // @todo -- add special-cases for 0 and 1
1349 _allocator
.retire(rr
);
1350 rR
->reg
= UnknownReg
;
1351 NanoAssert((rmask(rr
) & FpRegs
) != 0);
1353 const double d
= ins
->constvalf();
1354 const uint64_t q
= ins
->constvalq();
1355 if (rmask(rr
) & XmmRegs
) {
1357 // test (int64)0 since -0.0 == 0.0
1359 } else if (d
== 1.0) {
1360 // 1.0 is extremely frequent and worth special-casing!
1361 static const double k_ONE
= 1.0;
1365 const int d
= disp(rR
);
1370 // test (int64)0 since -0.0 == 0.0
1372 } else if (d
== 1.0) {
1382 // @todo, if we used xor, ldsd, fldz, etc above, we don't need mem here
1384 freeRsrcOf(ins
, false);
1387 const int32_t* p
= (const int32_t*) (ins
-2);
1391 #elif defined NANOJIT_AMD64
1392 Reservation
*rR
= getresv(ins
);
1393 int64_t val
= *(int64_t *)(ins
- 2);
1395 if (rR
->reg
!= UnknownReg
)
1397 if (rmask(rR
->reg
) & GpRegs
)
1401 else if (rmask(rR
->reg
) & XmmRegs
)
1403 if (ins
->constvalf() == 0.0)
1405 SSE_XORPDr(rR
->reg
, rR
->reg
);
1409 /* Get a short-lived register, not associated with instruction */
1410 Register rd
= rR
->reg
;
1411 Register rs
= registerAlloc(GpRegs
);
1416 _allocator
.addFree(rs
);
1422 const int32_t* p
= (const int32_t*) (ins
-2);
1424 STi(FP
, dr
+4, p
[1]);
1428 freeRsrcOf(ins
, false);
1432 void Assembler::asm_qlo(LInsp ins
)
1434 LIns
*q
= ins
->oprnd1();
1436 #if defined NANOJIT_IA32
1439 Register rr
= prepResultReg(ins
, GpRegs
);
1440 int d
= findMemFor(q
);
1446 Reservation
*resv
= getresv(ins
);
1447 Register rr
= resv
->reg
;
1448 if (rr
== UnknownReg
) {
1449 // store quad in spill loc
1451 freeRsrcOf(ins
, false);
1452 Register qr
= findRegFor(q
, XmmRegs
);
1453 SSE_MOVDm(d
, FP
, qr
);
1455 freeRsrcOf(ins
, false);
1456 Register qr
= findRegFor(q
, XmmRegs
);
1462 void Assembler::asm_fneg(LInsp ins
)
1464 #if defined NANOJIT_IA32
1468 LIns
*lhs
= ins
->oprnd1();
1470 Register rr
= prepResultReg(ins
, XmmRegs
);
1471 Reservation
*rA
= getresv(lhs
);
1474 // if this is last use of lhs in reg, we can re-use result reg
1475 if (rA
== 0 || (ra
= rA
->reg
) == UnknownReg
) {
1476 ra
= findSpecificRegFor(lhs
, rr
);
1477 } else if ((rmask(ra
) & XmmRegs
) == 0) {
1478 /* We need this case on AMD64, because it's possible that
1479 * an earlier instruction has done a quadword load and reserved a
1480 * GPR. If so, ask for a new register.
1482 ra
= findRegFor(lhs
, XmmRegs
);
1484 // else, rA already has a register assigned.
1486 #if defined __SUNPRO_CC
1487 // from Sun Studio C++ Readme: #pragma align inside namespace requires mangled names
1488 static uint32_t temp
[] = {0, 0, 0, 0, 0, 0, 0};
1489 static uint32_t *negateMask
= (uint32_t *)alignUp(temp
, 16);
1490 negateMask
[1] = 0x80000000;
1492 static const AVMPLUS_ALIGN16(uint32_t) negateMask
[] = {0,0x80000000,0,0};
1494 SSE_XORPD(rr
, negateMask
);
1498 #if defined NANOJIT_IA32
1502 Register rr
= prepResultReg(ins
, FpRegs
);
1504 LIns
* lhs
= ins
->oprnd1();
1506 // lhs into reg, prefer same reg as result
1507 Reservation
* rA
= getresv(lhs
);
1508 // if this is last use of lhs in reg, we can re-use result reg
1509 if (rA
== 0 || rA
->reg
== UnknownReg
)
1510 findSpecificRegFor(lhs
, rr
);
1511 // else, rA already has a different reg assigned
1513 NanoAssert(getresv(lhs
)!=0 && getresv(lhs
)->reg
==FST0
);
1514 // assume that the lhs is in ST(0) and rhs is on stack
1517 // if we had more than one fpu reg, this is where
1518 // we would move ra into rr if rr != ra.
1523 void Assembler::asm_arg(ArgSize sz
, LInsp p
, Register r
)
1525 if (sz
== ARGSIZE_Q
)
1527 // ref arg - use lea
1528 if (r
!= UnknownReg
)
1530 // arg in specific reg
1531 int da
= findMemFor(p
);
1536 NanoAssert(0); // not supported
1539 else if (sz
== ARGSIZE_LO
)
1541 if (r
!= UnknownReg
) {
1542 // arg goes in specific register
1544 LDi(r
, p
->constval());
1546 Reservation
* rA
= getresv(p
);
1548 if (rA
->reg
== UnknownReg
) {
1549 // load it into the arg reg
1550 int d
= findMemFor(p
);
1551 if (p
->isop(LIR_alloc
)) {
1557 // it must be in a saved reg
1562 // this is the last use, so fine to assign it
1563 // to the scratch reg, it's dead after this point.
1564 findSpecificRegFor(p
, r
);
1574 NanoAssert(sz
== ARGSIZE_F
);
1579 void Assembler::asm_pusharg(LInsp p
)
1581 // arg goes on stack
1582 Reservation
* rA
= getresv(p
);
1583 if (rA
== 0 && p
->isconst())
1585 // small const we push directly
1586 PUSHi(p
->constval());
1588 else if (rA
== 0 || p
->isop(LIR_alloc
))
1590 Register ra
= findRegFor(p
, GpRegs
);
1593 else if (rA
->reg
== UnknownReg
)
1595 PUSHm(disp(rA
), FP
);
1603 void Assembler::asm_farg(LInsp p
)
1605 #if defined NANOJIT_IA32
1606 NanoAssert(p
->isQuad());
1607 Register r
= findRegFor(p
, FpRegs
);
1608 if (rmask(r
) & XmmRegs
) {
1612 /* It's possible that the same LIns* with r=FST0 will appear in the argument list more
1613 * than once. In this case FST0 will not have been evicted and the multiple pop
1614 * actions will unbalance the FPU stack. A quick fix is to always evict FST0 manually.
1619 //PUSHr(ECX); // 2*pushr is smaller than sub
1624 void Assembler::asm_fop(LInsp ins
)
1626 LOpcode op
= ins
->opcode();
1627 #if defined NANOJIT_IA32
1631 LIns
*lhs
= ins
->oprnd1();
1632 LIns
*rhs
= ins
->oprnd2();
1634 RegisterMask allow
= XmmRegs
;
1635 Register rb
= UnknownReg
;
1637 rb
= findRegFor(rhs
,allow
);
1638 allow
&= ~rmask(rb
);
1641 Register rr
= prepResultReg(ins
, allow
);
1642 Reservation
*rA
= getresv(lhs
);
1645 // if this is last use of lhs in reg, we can re-use result reg
1646 if (rA
== 0 || (ra
= rA
->reg
) == UnknownReg
) {
1647 ra
= findSpecificRegFor(lhs
, rr
);
1648 } else if ((rmask(ra
) & XmmRegs
) == 0) {
1649 /* We need this case on AMD64, because it's possible that
1650 * an earlier instruction has done a quadword load and reserved a
1651 * GPR. If so, ask for a new register.
1653 ra
= findRegFor(lhs
, XmmRegs
);
1656 // rA already has a register assigned but maybe not from the allow set
1657 ra
= findRegFor(lhs
, allow
);
1665 else if (op
== LIR_fsub
)
1667 else if (op
== LIR_fmul
)
1669 else //if (op == LIR_fdiv)
1674 #if defined NANOJIT_IA32
1678 // we swap lhs/rhs on purpose here, works out better
1679 // if you only have one fpu reg. use divr/subr.
1680 LIns
* rhs
= ins
->oprnd1();
1681 LIns
* lhs
= ins
->oprnd2();
1682 Register rr
= prepResultReg(ins
, rmask(FST0
));
1684 // make sure rhs is in memory
1685 int db
= findMemFor(rhs
);
1687 // lhs into reg, prefer same reg as result
1688 Reservation
* rA
= getresv(lhs
);
1689 // last use of lhs in reg, can reuse rr
1690 if (rA
== 0 || rA
->reg
== UnknownReg
)
1691 findSpecificRegFor(lhs
, rr
);
1692 // else, rA already has a different reg assigned
1694 NanoAssert(getresv(lhs
)!=0 && getresv(lhs
)->reg
==FST0
);
1695 // assume that the lhs is in ST(0) and rhs is on stack
1698 else if (op
== LIR_fsub
)
1700 else if (op
== LIR_fmul
)
1702 else if (op
== LIR_fdiv
)
1708 void Assembler::asm_i2f(LInsp ins
)
1710 // where our result goes
1711 Register rr
= prepResultReg(ins
, FpRegs
);
1712 #if defined NANOJIT_IA32
1713 if (rmask(rr
) & XmmRegs
)
1716 // todo support int value in memory
1717 Register gr
= findRegFor(ins
->oprnd1(), GpRegs
);
1718 SSE_CVTSI2SD(rr
, gr
);
1719 #if defined NANOJIT_IA32
1723 int d
= findMemFor(ins
->oprnd1());
1729 Register
Assembler::asm_prep_fcall(Reservation
*rR
, LInsp ins
)
1731 #if defined NANOJIT_IA32
1734 if ((rr
=rR
->reg
) != UnknownReg
&& (rmask(rr
) & XmmRegs
))
1737 return prepResultReg(ins
, rmask(FST0
));
1738 #elif defined NANOJIT_AMD64
1740 return prepResultReg(ins
, rmask(XMM0
));
1744 void Assembler::asm_u2f(LInsp ins
)
1746 // where our result goes
1747 Register rr
= prepResultReg(ins
, FpRegs
);
1748 #if defined NANOJIT_IA32
1749 if (rmask(rr
) & XmmRegs
)
1752 // don't call findRegFor, we want a reg we can stomp on for a very short time,
1753 // not a reg that will continue to be associated with the LIns
1754 Register gr
= registerAlloc(GpRegs
);
1756 // technique inspired by gcc disassembly
1757 // Edwin explains it:
1761 // sub gr,0x80000000
1763 // now gr is -2^31..2^31-1, i.e. the range of int, but not the same value
1768 // rr is now a double with the int value range
1770 // addsd rr, 2147483648.0
1772 // adding back double(0x80000000) makes the range 0..2^32-1.
1774 static const double k_NEGONE
= 2147483648.0;
1775 #if defined NANOJIT_IA32
1776 SSE_ADDSDm(rr
, &k_NEGONE
);
1777 #elif defined NANOJIT_AMD64
1778 /* Squirrel the constant at the bottom of the page. */
1779 if (_dblNegPtr
!= NULL
)
1781 underrunProtect(10);
1783 if (_dblNegPtr
== NULL
)
1785 underrunProtect(30);
1786 uint8_t *base
, *begin
;
1787 base
= (uint8_t *)((intptr_t)_nIns
& ~((intptr_t)NJ_PAGE_SIZE
-1));
1788 base
+= sizeof(PageHeader
) + _pageData
;
1790 /* Make sure we align */
1791 if ((uintptr_t)base
& 0xF) {
1792 base
= (NIns
*)((uintptr_t)base
& ~(0xF));
1795 _pageData
+= (int32_t)(base
- begin
) + sizeof(double);
1796 _negOnePtr
= (NIns
*)base
;
1797 *(double *)_negOnePtr
= k_NEGONE
;
1799 SSE_ADDSDm(rr
, _negOnePtr
);
1802 SSE_CVTSI2SD(rr
, gr
);
1804 Reservation
* resv
= getresv(ins
->oprnd1());
1806 if (resv
&& (xr
= resv
->reg
) != UnknownReg
&& (rmask(xr
) & GpRegs
))
1808 LEA(gr
, 0x80000000, xr
);
1812 const int d
= findMemFor(ins
->oprnd1());
1813 SUBi(gr
, 0x80000000);
1817 // ok, we're done with it
1818 _allocator
.addFree(gr
);
1819 #if defined NANOJIT_IA32
1823 const int disp
= -8;
1824 const Register base
= SP
;
1825 Register gr
= findRegFor(ins
->oprnd1(), GpRegs
);
1826 NanoAssert(rr
== FST0
);
1828 STi(base
, disp
+4, 0); // high 32 bits = 0
1829 ST(base
, disp
, gr
); // low 32 bits = unsigned value
1834 void Assembler::asm_nongp_copy(Register r
, Register s
)
1836 if ((rmask(r
) & XmmRegs
) && (rmask(s
) & XmmRegs
)) {
1838 } else if ((rmask(r
) & GpRegs
) && (rmask(s
) & XmmRegs
)) {
1841 if (rmask(r
) & XmmRegs
) {
1843 NanoAssertMsg(false, "Should not move data from GPR to XMM");
1846 NanoAssertMsg(false, "Should not move data from GPR/XMM to x87 FPU");
1851 NIns
* Assembler::asm_jmpcc(bool branchOnFalse
, LIns
*cond
, NIns
*targ
)
1853 LOpcode c
= cond
->opcode();
1854 if (config
.sse2
&& c
!= LIR_feq
) {
1855 LIns
*lhs
= cond
->oprnd1();
1856 LIns
*rhs
= cond
->oprnd2();
1858 LIns
*t
= lhs
; lhs
= rhs
; rhs
= t
;
1861 else if (c
== LIR_fle
) {
1862 LIns
*t
= lhs
; lhs
= rhs
; rhs
= t
;
1867 if (branchOnFalse
) { JNA(targ
, false); } else { JA(targ
, false); }
1869 else { // if (c == LIR_fge)
1870 if (branchOnFalse
) { JNAE(targ
, false); } else { JAE(targ
, false); }
1873 Reservation
*rA
, *rB
;
1874 findRegFor2(XmmRegs
, lhs
, rA
, rhs
, rB
);
1875 SSE_UCOMISD(rA
->reg
, rB
->reg
);
1888 void Assembler::asm_setcc(Register r
, LIns
*cond
)
1890 LOpcode c
= cond
->opcode();
1891 if (config
.sse2
&& c
!= LIR_feq
) {
1893 LIns
*lhs
= cond
->oprnd1();
1894 LIns
*rhs
= cond
->oprnd2();
1896 LIns
*t
= lhs
; lhs
= rhs
; rhs
= t
;
1899 else if (c
== LIR_fle
) {
1900 LIns
*t
= lhs
; lhs
= rhs
; rhs
= t
;
1903 else if (c
== LIR_fgt
) {
1906 else { // if (c == LIR_fge)
1909 Reservation
*rA
, *rB
;
1910 findRegFor2(XmmRegs
, lhs
, rA
, rhs
, rB
);
1911 SSE_UCOMISD(rA
->reg
, rB
->reg
);
1914 // SETcc only sets low 8 bits, so extend
1920 void Assembler::asm_fcmp(LIns
*cond
)
1922 LOpcode condop
= cond
->opcode();
1923 NanoAssert(condop
>= LIR_feq
&& condop
<= LIR_fge
);
1924 LIns
* lhs
= cond
->oprnd1();
1925 LIns
* rhs
= cond
->oprnd2();
1928 if (condop
== LIR_feq
)
1930 else if (condop
== LIR_fle
)
1932 else if (condop
== LIR_flt
)
1934 else if (condop
== LIR_fge
) {
1937 LIns
* t
= lhs
; lhs
= rhs
; rhs
= t
;
1939 } else { // if (condop == LIR_fgt)
1942 LIns
* t
= lhs
; lhs
= rhs
; rhs
= t
;
1946 #if defined NANOJIT_IA32
1950 // UNORDERED: ZF,PF,CF <- 111;
1951 // GREATER_THAN: ZF,PF,CF <- 000;
1952 // LESS_THAN: ZF,PF,CF <- 001;
1953 // EQUAL: ZF,PF,CF <- 100;
1955 if (condop
== LIR_feq
&& lhs
== rhs
) {
1957 Register r
= findRegFor(lhs
, XmmRegs
);
1961 #if defined NANOJIT_IA32
1965 #elif defined NANOJIT_AMD64
1971 Reservation
*rA
, *rB
;
1972 findRegFor2(XmmRegs
, lhs
, rA
, rhs
, rB
);
1973 SSE_UCOMISD(rA
->reg
, rB
->reg
);
1975 #if defined NANOJIT_IA32
1982 NanoAssert(lhs
->isQuad() && rhs
->isQuad());
1986 // compare two different numbers
1987 int d
= findMemFor(rhs
);
1989 int pop
= !rA
|| rA
->reg
== UnknownReg
;
1990 findSpecificRegFor(lhs
, FST0
);
1991 // lhs is in ST(0) and rhs is on stack
1996 // compare n to itself, this is a NaN test.
1998 int pop
= !rA
|| rA
->reg
== UnknownReg
;
1999 findSpecificRegFor(lhs
, FST0
);
2011 void Assembler::nativePageReset()
2013 #if defined NANOJIT_AMD64
2014 /* We store some stuff at the bottom of the page.
2015 * We reserve 8-bytes for long jumps just in case we need them.
2023 Register
Assembler::asm_binop_rhs_reg(LInsp ins
)
2025 LOpcode op
= ins
->opcode();
2026 LIns
*rhs
= ins
->oprnd2();
2028 if (op
== LIR_lsh
|| op
== LIR_rsh
|| op
== LIR_ush
) {
2029 #if defined NANOJIT_IA32
2030 return findSpecificRegFor(rhs
, ECX
);
2031 #elif defined NANOJIT_AMD64
2032 return findSpecificRegFor(rhs
, RCX
);
2039 #if defined NANOJIT_AMD64
2040 void Assembler::asm_qbinop(LIns
*ins
)
2042 LInsp lhs
= ins
->oprnd1();
2043 LInsp rhs
= ins
->oprnd2();
2044 LOpcode op
= ins
->opcode();
2046 Register rr
= prepResultReg(ins
, GpRegs
);
2047 Reservation
*rA
= getresv(lhs
);
2050 if (rA
== NULL
|| (ra
= rA
->reg
) == UnknownReg
) {
2051 ra
= findSpecificRegFor(lhs
, rr
);
2056 int c
= rhs
->constval();
2058 if (op
== LIR_qiadd
)
2061 } else if (op
== LIR_qiand
) {
2063 } else if (op
== LIR_qilsh
) {
2065 } else if (op
== LIR_qior
) {
2074 rv
= findRegFor(rhs
, GpRegs
& ~(rmask(rr
)));
2077 if (op
== LIR_qiadd
) {
2079 } else if (op
== LIR_qiand
) {
2081 } else if (op
== LIR_qior
) {
2084 NanoAssert(rhs
->isconst());
2094 void Assembler::nativePageSetup()
2096 if (!_nIns
) _nIns
= pageAlloc();
2097 if (!_nExitIns
) _nExitIns
= pageAlloc(true);
2100 // enough room for n bytes
2101 void Assembler::underrunProtect(int n
)
2103 NanoAssertMsg(n
<=LARGEST_UNDERRUN_PROT
, "constant LARGEST_UNDERRUN_PROT is too small");
2104 NIns
*eip
= this->_nIns
;
2105 Page
*p
= (Page
*)pageTop(eip
-1);
2106 NIns
*top
= (NIns
*) &p
->code
[0];
2107 if (eip
- n
< top
) {
2108 _nIns
= pageAlloc(_inExit
);
2113 #endif /* FEATURE_NANOJIT */