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.
25 * Alternatively, the contents of this file may be used under the terms of
26 * either the GNU General Public License Version 2 or later (the "GPL"), or
27 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
37 * ***** END LICENSE BLOCK ***** */
44 #include "../vprof/vprof.h"
49 using namespace avmplus
;
50 #ifdef FEATURE_NANOJIT
52 const uint8_t operandCount
[] = {
53 #define OPDEF(op, number, operands) \
55 #define OPDEF64(op, number, operands) \
57 #include "LIRopcode.tbl"
63 // LIR verbose specific
66 const char* lirNames
[] = {
67 #define OPDEF(op, number, operands) \
69 #define OPDEF64(op, number, operands) \
71 #include "LIRopcode.tbl"
77 #endif /* NANOJIT_VEBROSE */
82 // @todo fixup move to nanojit.h
84 #define counter_value(x) x
85 #endif /* NJ_PROFILE */
87 //static int32_t buffer_count = 0;
90 LirBuffer::LirBuffer(Fragmento
* frago
, const CallInfo
* functions
)
91 : _frago(frago
), _pages(frago
->core()->GetGC()), _functions(functions
), abi(ABI_FASTCALL
)
94 Page
* start
= pageAlloc();
96 _unused
= &start
->lir
[0];
98 //fprintf(stderr, "LirBuffer %x unused %x\n", (int)this, (int)_unused);
101 LirBuffer::~LirBuffer()
104 //fprintf(stderr, "~LirBuffer %x start %x\n", (int)this, (int)_start);
106 verbose_only(if (names
) NJ_DELETE(names
);)
110 void LirBuffer::clear()
112 // free all the memory and clear the stats
113 _frago
->pagesRelease(_pages
);
114 NanoAssert(!_pages
.size());
119 for (int i
= 0; i
< NumSavedRegs
; ++i
)
121 explicitSavedRegs
= false;
124 int32_t LirBuffer::insCount()
126 // doesn't include embedded constants nor LIR_skip payload
130 int32_t LirBuffer::byteCount()
132 return ((_pages
.size() ? _pages
.size()-1 : 0) * sizeof(Page
)) +
133 ((int32_t)_unused
- (int32_t)pageTop(_unused
));
136 Page
* LirBuffer::pageAlloc()
138 Page
* page
= _frago
->pageAlloc();
146 LInsp
LirBuffer::next()
151 void LirBufWriter::ensureRoom(uint32_t count
)
153 LInsp before
= _buf
->next();
154 LInsp after
= before
+count
+LIR_FAR_SLOTS
;
155 if (!samepage(before
,after
+LirBuffer::LIR_BUF_THRESHOLD
))
157 // transition to the next page?
158 if (!samepage(before
,after
))
160 NanoAssert(_buf
->_thresholdPage
);
161 _buf
->_unused
= &_buf
->_thresholdPage
->lir
[0];
162 _buf
->_thresholdPage
= 0; // pageAlloc() stored it in _pages already
164 // link LIR stream back to prior instruction (careful insLink relies on _unused...)
165 insLinkTo(LIR_skip
, before
-1);
167 else if (!_buf
->_thresholdPage
)
169 // LIR_BUF_THRESHOLD away from a new page but pre-alloc it, setting noMem for early OOM detection
170 _buf
->_thresholdPage
= _buf
->pageAlloc();
171 NanoAssert(_buf
->_thresholdPage
|| _buf
->_noMem
);
176 LInsp
LirBufWriter::insLinkTo(LOpcode op
, LInsp to
)
178 LInsp l
= _buf
->next();
179 NanoAssert(samepage(l
,l
+LIR_FAR_SLOTS
)); // must have called ensureRoom()
180 if (can24bReach(l
,to
))
182 l
->initOpcode(LOpcode(op
-1)); // nearskip or neartramp
189 l
= insLinkToFar(op
,to
);
194 LInsp
LirBufWriter::insLinkToFar(LOpcode op
, LInsp to
)
196 LirFarIns
* ov
= (LirFarIns
*) _buf
->next();
198 ov
->i
.initOpcode(op
);
199 _buf
->commit(LIR_FAR_SLOTS
);
202 NanoAssert( (LInsp
)(ov
+1) == _buf
->next() );
206 void LirBufWriter::makeReachable(LInsp
& o
, LInsp from
)
208 if (o
&& !can8bReach(from
,o
))
210 if (o
== _buf
->sp
&& spref
&& can8bReach(from
, spref
)) {
214 if (o
== _buf
->rp
&& rpref
&& can8bReach(from
, rpref
)) {
219 // need a trampoline to get to from
220 LInsp tramp
= insLinkTo(LIR_tramp
, o
); // will produce neartramp if possible
221 NanoAssert( tramp
->ref() == o
&& samepage(from
,tramp
) );
224 else if (o
== _buf
->rp
)
230 void LirBufWriter::prepFor(LInsp
& i1
, LInsp
& i2
, LInsp
& i3
)
232 uint32_t i
= 0; // count of operands
237 uint32_t count
= (LIR_FAR_SLOTS
*i
)+1; // count of LIns if all operands require tramp
239 NanoAssert( samepage(_buf
->next()+count
,_buf
->next()) );
241 // guaranteed space for far tramps if necc.
242 LInsp from
= _buf
->next()+count
;
243 makeReachable(i1
, from
);
244 makeReachable(i2
, from
);
245 makeReachable(i3
, from
);
246 NanoAssert(from
>i1
&& from
>i2
&& from
>i3
);
249 LInsp
LirBuffer::commit(uint32_t count
)
251 NanoAssertMsg( samepage(_unused
, _unused
+count
), "You need to call ensureRoom first!" );
252 return _unused
+= count
;
255 uint32_t LIns::reference(LIns
*r
) const
257 int delta
= this-r
-1;
258 NanoAssert(isU8(delta
));
262 LIns
* LIns::deref(int32_t off
) const
264 LInsp i
= (LInsp
) this-1 - off
;
265 while (i
&& i
->isTramp()) {
271 LInsp
LirBufWriter::insStore(LInsp val
, LInsp base
, LInsp off
)
273 LOpcode op
= val
->isQuad() ? LIR_stq
: LIR_st
;
274 NanoAssert(val
&& base
&& off
);
275 prepFor(val
, base
, off
);
276 LInsp l
= _buf
->next();
286 LInsp
LirBufWriter::insStorei(LInsp val
, LInsp base
, int32_t d
)
288 LOpcode op
= val
->isQuad() ? LIR_stqi
: LIR_sti
;
289 NanoAssert(val
&& base
&& isS8(d
));
291 prepFor(val
, base
, u3
);
292 LInsp l
= _buf
->next();
296 l
->setDisp(int8_t(d
));
302 LInsp
LirBufWriter::ins0(LOpcode op
)
305 LirBuffer
*b
= this->_buf
;
313 LInsp
LirBufWriter::ins1(LOpcode op
, LInsp o1
)
317 LInsp l
= _buf
->next();
325 LInsp
LirBufWriter::ins2(LOpcode op
, LInsp o1
, LInsp o2
)
329 LInsp l
= _buf
->next();
338 LInsp
LirBufWriter::insLoad(LOpcode op
, LInsp base
, LInsp d
)
340 return ins2(op
,base
,d
);
343 LInsp
LirBufWriter::insGuard(LOpcode op
, LInsp c
, LInsp data
)
345 return ins2(op
, c
, data
);
348 LInsp
LirBufWriter::insBranch(LOpcode op
, LInsp condition
, LInsp toLabel
)
351 toLabel
= insFar(LIR_tramp
,0); //empty tramp
353 // unconditional, just point to something
356 return ins2(op
,condition
,toLabel
);
359 LInsp
LirBufWriter::insAlloc(int32_t size
)
361 size
= (size
+3)>>2; // # of required 32bit words
362 NanoAssert(isU16(size
));
364 LInsp l
= _buf
->next();
365 l
->initOpcode(LIR_alloc
);
366 l
->i
.imm16
= uint16_t(size
);
372 LInsp
LirBufWriter::insParam(int32_t arg
, int32_t kind
)
375 LirBuffer
*b
= this->_buf
;
377 l
->initOpcode(LIR_param
);
378 NanoAssert(isU8(arg
) && isU8(kind
));
382 NanoAssert(arg
< NumSavedRegs
);
383 b
->savedRegs
[arg
] = l
;
384 b
->explicitSavedRegs
= true;
391 LInsp
LirBufWriter::insFar(LOpcode op
, LInsp target
)
393 ensureRoom(LIR_FAR_SLOTS
); // make room for it
394 LInsp l
= insLinkToFar(op
, target
);
399 LInsp
LirBufWriter::insImm(int32_t imm
)
403 LInsp l
= _buf
->next();
404 l
->initOpcode(LIR_short
);
410 ensureRoom(LIR_IMM32_SLOTS
);
411 LirImm32Ins
* l
= (LirImm32Ins
*)_buf
->next();
413 l
->i
.initOpcode(LIR_int
);
414 _buf
->commit(LIR_IMM32_SLOTS
);
416 NanoAssert((LInsp
)(l
+1)==_buf
->next());
421 LInsp
LirBufWriter::insImmq(uint64_t imm
)
423 ensureRoom(LIR_IMM64_SLOTS
);
424 LirImm64Ins
* l
= (LirImm64Ins
*)_buf
->next();
425 l
->v
[0] = int32_t(imm
);
426 l
->v
[1] = int32_t(imm
>>32);
427 l
->i
.initOpcode(LIR_quad
);
428 _buf
->commit(LIR_IMM64_SLOTS
);
430 NanoAssert((LInsp
)(l
+1)==_buf
->next());
434 LInsp
LirBufWriter::skip(size_t size
)
436 const uint32_t n
= (size
+sizeof(LIns
)-1)/sizeof(LIns
);
437 ensureRoom(n
); // make room for it
438 LInsp last
= _buf
->next()-1; // safe, next()-1+n guaranteed to be on same page
440 NanoAssert(samepage(last
,_buf
->next()));
441 ensureRoom(LIR_FAR_SLOTS
);
442 return insLinkTo(LIR_skip
, last
);
445 LInsp
LirReader::read()
451 LOpcode iop
= i
->opcode();
460 #if defined NANOJIT_64BIT
467 NanoAssert( samepage(i
,i
+1-i
->callInsWords()) );
468 i
-= i
->callInsWords();
473 NanoAssert(i
->ref() != i
);
478 NanoAssert(samepage(i
,i
+1-LIR_FAR_SLOTS
));
483 NanoAssert(samepage(i
,i
+1-LIR_IMM32_SLOTS
));
484 i
-= LIR_IMM32_SLOTS
;
488 NanoAssert(samepage(i
,i
+1-LIR_IMM64_SLOTS
));
489 i
-= LIR_IMM64_SLOTS
;
493 _i
= 0; // start of trace
498 while (is_trace_skip_tramp(iop
)||iop
==LIR_2
);
503 bool FASTCALL
isCmp(LOpcode c
) {
504 return c
>= LIR_eq
&& c
<= LIR_uge
|| c
>= LIR_feq
&& c
<= LIR_fge
;
507 bool FASTCALL
isCond(LOpcode c
) {
508 return (c
== LIR_ov
) || (c
== LIR_cs
) || isCmp(c
);
511 bool FASTCALL
isFloat(LOpcode c
) {
528 bool LIns::isCmp() const {
529 return nanojit::isCmp(u
.code
);
532 bool LIns::isCond() const {
533 return nanojit::isCond(u
.code
);
536 bool LIns::isQuad() const {
538 // callh in 64bit cpu's means a call that returns an int64 in a single register
539 return (u
.code
& LIR64
) != 0 || u
.code
== LIR_callh
;
541 // callh in 32bit cpu's means the 32bit MSW of an int64 result in 2 registers
542 return (u
.code
& LIR64
) != 0;
546 bool LIns::isconstval(int32_t val
) const
548 return isconst() && constval()==val
;
551 bool LIns::isconstq() const
553 return isop(LIR_quad
);
556 bool LIns::isconstp() const
565 bool FASTCALL
isCse(LOpcode op
) {
566 op
= LOpcode(op
& ~LIR64
);
567 return op
>= LIR_ldcs
&& op
<= LIR_uge
;
570 bool LIns::isCse(const CallInfo
*functions
) const
572 return nanojit::isCse(u
.code
) || isCall() && callInfo()->_cse
;
575 void LIns::setimm16(int32_t x
)
577 NanoAssert(isS16(x
));
578 i
.imm16
= int16_t(x
);
581 void LIns::setimm24(int32_t x
)
583 NanoAssert(isS24(x
));
587 void LIns::setresv(uint32_t resv
)
589 NanoAssert(isU8(resv
));
593 void LIns::initOpcode(LOpcode op
)
600 void LIns::setOprnd1(LInsp r
)
602 u
.oprnd_1
= reference(r
);
605 void LIns::setOprnd2(LInsp r
)
607 u
.oprnd_2
= reference(r
);
610 void LIns::setOprnd3(LInsp r
)
612 u
.oprnd_3
= reference(r
);
615 void LIns::setDisp(int8_t d
)
620 LIns
**LIns::targetAddr() {
621 NanoAssert(isBranch());
622 LInsp i
= (LInsp
) this-1 - u
.oprnd_2
;
623 NanoAssert(i
->isTramp());
625 while ((ref
=i
->ref()) != 0 && ref
->isTramp())
627 NanoAssert(i
->isop(LIR_tramp
));
628 LirFarIns
* ov
= (LirFarIns
*)(i
-LIR_FAR_SLOTS
+1);
632 void LIns::target(LInsp label
) {
633 NanoAssert(label
&& label
->isop(LIR_label
));
634 *(targetAddr()) = label
;
637 LInsp
LIns::getTarget()
639 NanoAssert(isBranch());
643 LInsp
LIns::oprnd1() const
645 return deref(u
.oprnd_1
);
648 LInsp
LIns::oprnd2() const
650 return deref(u
.oprnd_2
);
653 LInsp
LIns::oprnd3() const
655 return deref(u
.oprnd_3
);
658 void *LIns::payload() const
660 NanoAssert(opcode()==LIR_skip
|| opcode()==LIR_nearskip
);
661 return (void*) (ref()+1);
664 LIns
* LIns::ref() const
671 LirFarIns
* l
= (LirFarIns
*)(this-LIR_FAR_SLOTS
+1);
674 return (const LInsp
)r
;
677 int32_t LIns::imm32() const
679 LirImm32Ins
* l
= (LirImm32Ins
*)(this-LIR_IMM32_SLOTS
+1);
683 uint64_t LIns::constvalq() const
685 LirImm64Ins
* l
= (LirImm64Ins
*)(this-LIR_IMM64_SLOTS
+1);
686 #ifdef AVMPLUS_UNALIGNED_ACCESS
687 int* ptr
= (int*)l
->v
;
688 return *(const uint64_t*)ptr
;
690 union { uint64_t tmp
; int32_t dst
[2]; } u
;
697 double LIns::constvalf() const
699 LirImm64Ins
* l
= (LirImm64Ins
*)(this-LIR_IMM64_SLOTS
+1);
700 NanoAssert(isconstq());
701 #ifdef AVMPLUS_UNALIGNED_ACCESS
702 int* ptr
= (int*)l
->v
;
703 return *(const double*)ptr
;
705 union { uint32_t dst
[2]; double tmpf
; } u
;
712 size_t LIns::callInsWords() const
714 return LIR_CALL_SLOTS
+ argwords(argc());
717 const CallInfo
* LIns::callInfo() const
719 LirCallIns
* l
= (LirCallIns
*)(this-LIR_CALL_SLOTS
+1);
723 // index args in r-l order. arg(0) is rightmost arg
724 LIns
* LIns::arg(uint32_t i
)
726 NanoAssert(i
< argc());
727 LirCallIns
* l
= (LirCallIns
*)(this-LIR_CALL_SLOTS
+1);
728 uint8_t* offs
= (uint8_t*)l
- (i
+1);
732 LIns
* LirWriter::ins2i(LOpcode v
, LIns
* oprnd1
, int32_t imm
)
734 return ins2(v
, oprnd1
, insImm(imm
));
737 bool insIsS16(LInsp i
)
740 int c
= i
->constval();
743 if (i
->isop(LIR_cmov
) || i
->isop(LIR_qcmov
)) {
744 LInsp vals
= i
->oprnd2();
745 return insIsS16(vals
->oprnd1()) && insIsS16(vals
->oprnd2());
749 // many other possibilities too.
753 LIns
* ExprFilter::ins1(LOpcode v
, LIns
* i
)
757 return insImm(int32_t(i
->constvalq()));
758 if (i
->isop(LIR_qjoin
))
761 else if (v
== LIR_qhi
) {
763 return insImm(int32_t(i
->constvalq()>>32));
764 if (i
->isop(LIR_qjoin
))
767 else if (i
->isconst()) {
768 int32_t c
= i
->constval();
774 else if (v
== i
->opcode() && (v
== LIR_not
|| v
== LIR_neg
|| v
== LIR_fneg
)) {
775 // not(not(x)) = x; neg(neg(x)) = x; fneg(fneg(x)) = x;
778 /* [ed 8.27.08] this causes a big slowdown in gameoflife.as. why?
779 else if (i->isconst()) {
781 return insImmf(i->constval());
783 else if (v == LIR_u2f) {
784 return insImmf((uint32_t)i->constval());
791 return out
->ins1(v
, i
);
794 LIns
* ExprFilter::ins2(LOpcode v
, LIns
* oprnd1
, LIns
* oprnd2
)
796 NanoAssert(oprnd1
&& oprnd2
);
797 if (v
== LIR_cmov
|| v
== LIR_qcmov
) {
798 if (oprnd2
->oprnd1() == oprnd2
->oprnd2()) {
800 return oprnd2
->oprnd1();
802 if (oprnd1
->isconst()) {
803 // const ? x : y => return x or y depending on const
804 return oprnd1
->constval() ? oprnd2
->oprnd1() : oprnd2
->oprnd2();
807 if (oprnd1
== oprnd2
)
809 if (v
== LIR_xor
|| v
== LIR_sub
||
810 v
== LIR_ult
|| v
== LIR_ugt
|| v
== LIR_gt
|| v
== LIR_lt
)
812 if (v
== LIR_or
|| v
== LIR_and
)
814 if (v
== LIR_le
|| v
== LIR_ule
|| v
== LIR_ge
|| v
== LIR_uge
) {
815 // x <= x == 1; x >= x == 1
819 if (oprnd1
->isconst() && oprnd2
->isconst())
821 int c1
= oprnd1
->constval();
822 int c2
= oprnd2
->constval();
823 if (v
== LIR_qjoin
) {
824 uint64_t q
= c1
| uint64_t(c2
)<<32;
828 return insImm(c1
== c2
);
830 return insImm((c2
!= 0) && ((c1
+ c2
) <= c1
));
832 return insImm((c2
!= 0) && ((uint32_t(c1
) + uint32_t(c2
)) <= uint32_t(c1
)));
834 return insImm(c1
< c2
);
836 return insImm(c1
> c2
);
838 return insImm(c1
<= c2
);
840 return insImm(c1
>= c2
);
842 return insImm(uint32_t(c1
) < uint32_t(c2
));
844 return insImm(uint32_t(c1
) > uint32_t(c2
));
846 return insImm(uint32_t(c1
) <= uint32_t(c2
));
848 return insImm(uint32_t(c1
) >= uint32_t(c2
));
850 return insImm(int32_t(c1
) >> int32_t(c2
));
852 return insImm(int32_t(c1
) << int32_t(c2
));
854 return insImm(uint32_t(c1
) >> int32_t(c2
));
856 return insImm(uint32_t(c1
) | int32_t(c2
));
858 return insImm(uint32_t(c1
) & int32_t(c2
));
860 return insImm(uint32_t(c1
) ^ int32_t(c2
));
862 else if (oprnd1
->isconstq() && oprnd2
->isconstq())
864 double c1
= oprnd1
->constvalf();
865 double c2
= oprnd2
->constvalf();
867 return insImm(c1
== c2
);
869 return insImm(c1
< c2
);
871 return insImm(c1
> c2
);
873 return insImm(c1
<= c2
);
875 return insImm(c1
>= c2
);
877 else if (oprnd1
->isconst() && !oprnd2
->isconst())
879 if (v
== LIR_add
|| v
== LIR_addp
|| v
== LIR_mul
||
880 v
== LIR_fadd
|| v
== LIR_fmul
||
881 v
== LIR_xor
|| v
== LIR_or
|| v
== LIR_and
||
888 else if (v
>= LIR_lt
&& v
<= LIR_uge
) {
889 NanoStaticAssert((LIR_lt
^ 1) == LIR_gt
);
890 NanoStaticAssert((LIR_le
^ 1) == LIR_ge
);
891 NanoStaticAssert((LIR_ult
^ 1) == LIR_ugt
);
892 NanoStaticAssert((LIR_ule
^ 1) == LIR_uge
);
894 // move const to rhs, swap the operator
902 if (oprnd2
->isconst())
904 int c
= oprnd2
->constval();
905 if (v
== LIR_add
&& oprnd1
->isop(LIR_add
) && oprnd1
->oprnd2()->isconst()) {
906 // add(add(x,c1),c2) => add(x,c1+c2)
907 c
+= oprnd1
->oprnd2()->constval();
909 oprnd1
= oprnd1
->oprnd1();
911 else if (v
== LIR_sub
&& oprnd1
->isop(LIR_add
) && oprnd1
->oprnd2()->isconst()) {
912 // sub(add(x,c1),c2) => add(x,c1-c2)
913 c
= oprnd1
->oprnd2()->constval() - c
;
915 oprnd1
= oprnd1
->oprnd1();
918 else if (v
== LIR_rsh
&& c
== 16 && oprnd1
->isop(LIR_lsh
) &&
919 oprnd1
->oprnd2()->isconstval(16)) {
920 if (insIsS16(oprnd1
->oprnd1())) {
921 // rsh(lhs(x,16),16) == x, if x is S16
922 return oprnd1
->oprnd1();
925 else if (v
== LIR_ult
) {
926 if (oprnd1
->isop(LIR_cmov
) || oprnd1
->isop(LIR_qcmov
)) {
927 LInsp a
= oprnd1
->oprnd2()->oprnd1();
928 LInsp b
= oprnd1
->oprnd2()->oprnd2();
929 if (a
->isconst() && b
->isconst()) {
930 bool a_lt
= uint32_t(a
->constval()) < uint32_t(oprnd2
->constval());
931 bool b_lt
= uint32_t(b
->constval()) < uint32_t(oprnd2
->constval());
940 if (v
== LIR_add
|| v
== LIR_addp
|| v
== LIR_or
|| v
== LIR_xor
||
941 v
== LIR_sub
|| v
== LIR_lsh
|| v
== LIR_rsh
|| v
== LIR_ush
)
943 else if (v
== LIR_and
|| v
== LIR_mul
)
945 else if (v
== LIR_eq
&& oprnd1
->isop(LIR_or
) &&
946 oprnd1
->oprnd2()->isconst() &&
947 oprnd1
->oprnd2()->constval() != 0) {
948 // (x or c) != 0 if c != 0
952 else if (c
== -1 || c
== 1 && oprnd1
->isCmp()) {
954 // x | -1 = -1, cmp | 1 = 1
957 else if (v
== LIR_and
) {
958 // x & -1 = x, cmp & 1 = cmp
965 if (v
== LIR_qjoin
&& oprnd1
->isop(LIR_qlo
) && oprnd2
->isop(LIR_qhi
)
966 && (i
= oprnd1
->oprnd1()) == oprnd2
->oprnd1()) {
967 // qjoin(qlo(x),qhi(x)) == x
971 return out
->ins2(v
, oprnd1
, oprnd2
);
974 LIns
* ExprFilter::insGuard(LOpcode v
, LInsp c
, LInsp x
)
976 if (v
== LIR_xt
|| v
== LIR_xf
) {
978 if (v
== LIR_xt
&& !c
->constval() || v
== LIR_xf
&& c
->constval()) {
979 return 0; // no guard needed
982 // need a way to EOT now, since this is trace end.
984 NanoAssertMsg(0, "need a way to EOT now, since this is trace end");
986 return out
->insGuard(LIR_x
, out
->insImm(1), x
);
990 while (c
->isop(LIR_eq
) && c
->oprnd1()->isCmp() &&
991 c
->oprnd2()->isconstval(0)) {
992 // xt(eq(cmp,0)) => xf(cmp) or xf(eq(cmp,0)) => xt(cmp)
998 return out
->insGuard(v
, c
, x
);
1001 LIns
* ExprFilter::insBranch(LOpcode v
, LIns
*c
, LIns
*t
)
1003 if (v
== LIR_jt
|| v
== LIR_jf
) {
1004 while (c
->isop(LIR_eq
) && c
->oprnd1()->isCmp() && c
->oprnd2()->isconstval(0)) {
1005 // jt(eq(cmp,0)) => jf(cmp) or jf(eq(cmp,0)) => jt(cmp)
1010 return out
->insBranch(v
, c
, t
);
1013 LIns
* LirWriter::insLoadi(LIns
*base
, int disp
)
1015 return insLoad(LIR_ld
,base
,disp
);
1018 LIns
* LirWriter::insLoad(LOpcode op
, LIns
*base
, int disp
)
1020 return insLoad(op
, base
, insImm(disp
));
1023 LIns
* LirWriter::store(LInsp value
, LInsp base
, int32_t d
)
1025 return isS8(d
) ? insStorei(value
, base
, d
)
1026 : insStore(value
, base
, insImm(d
));
1029 LIns
* LirWriter::ins_eq0(LIns
* oprnd1
)
1031 return ins2i(LIR_eq
, oprnd1
, 0);
1034 LIns
* LirWriter::insImmf(double f
)
1041 return insImmq(u
.q
);
1044 LIns
* LirWriter::qjoin(LInsp lo
, LInsp hi
)
1046 return ins2(LIR_qjoin
, lo
, hi
);
1049 LIns
* LirWriter::insImmPtr(const void *ptr
)
1051 return sizeof(ptr
) == 8 ? insImmq((uintptr_t)ptr
) : insImm((intptr_t)ptr
);
1054 LIns
* LirWriter::ins_choose(LIns
* cond
, LIns
* iftrue
, LIns
* iffalse
)
1056 // if not a conditional, make it implicitly an ==0 test (then flop results)
1059 cond
= ins_eq0(cond
);
1065 if (true/*avmplus::AvmCore::use_cmov()*/)
1067 return ins2((iftrue
->isQuad() || iffalse
->isQuad()) ? LIR_qcmov
: LIR_cmov
, cond
, ins2(LIR_2
, iftrue
, iffalse
));
1070 // @todo -- it might be better to use a short conditional branch rather than
1071 // the bit-twiddling on systems that don't provide a conditional move instruction.
1072 LInsp ncond
= ins1(LIR_neg
, cond
); // cond ? -1 : 0
1074 ins2(LIR_and
, iftrue
, ncond
),
1075 ins2(LIR_and
, iffalse
, ins1(LIR_not
, ncond
)));
1078 LIns
* LirBufWriter::insCall(const CallInfo
*ci
, LInsp args
[])
1080 static const LOpcode k_callmap
[] = { LIR_call
, LIR_fcall
, LIR_call
, LIR_callh
};
1081 static const LOpcode k_callimap
[] = { LIR_calli
, LIR_fcalli
, LIR_calli
, LIR_skip
};
1083 uint32_t argt
= ci
->_argtypes
;
1084 LOpcode op
= (ci
->isIndirect() ? k_callimap
: k_callmap
)[argt
& 3];
1085 NanoAssert(op
!= LIR_skip
); // LIR_skip here is just an error condition
1087 ArgSize sizes
[2*MAXARGS
];
1088 int32_t argc
= ci
->get_sizes(sizes
);
1091 if (op
== LIR_fcall
)
1093 LInsp args2
[MAXARGS
*2]; // arm could require 2 args per double
1098 ArgSize a
= ArgSize(argt
&3);
1099 if (a
== ARGSIZE_F
) {
1100 LInsp q
= args
[i
++];
1101 args2
[j
++] = ins1(LIR_qhi
, q
);
1102 args2
[j
++] = ins1(LIR_qlo
, q
);
1104 args2
[j
++] = args
[i
++];
1108 NanoAssert(j
== argc
);
1111 NanoAssert(argc
<= (int)MAXARGS
);
1112 uint32_t words
= argwords(argc
);
1113 int32_t insSz
= words
+ LIR_CALL_SLOTS
; // words need for offsets + size of instruction
1114 ensureRoom(argc
+insSz
); // argc=# possible tramps for args
1115 LInsp from
= _buf
->next()+argc
+words
; // assuming all args need a tramp, offsets are written here
1116 for (int32_t i
=0; i
< argc
; i
++)
1117 makeReachable(args
[i
], from
);
1119 // skip 'words' needed for call parameters
1120 LirCallIns
*l
= (LirCallIns
*) (_buf
->next()+words
);
1123 // call parameters laid in reverse order
1124 uint8_t* offs
= (uint8_t*)l
;
1125 for (int32_t i
=0; i
< argc
; i
++)
1126 *--offs
= (uint8_t) l
->i
.reference(args
[i
]);
1127 NanoAssert((LInsp
)offs
>=_buf
->next());
1129 #ifndef NANOJIT_64BIT
1130 l
->i
.initOpcode(op
==LIR_callh
? LIR_call
: op
);
1132 l
->i
.initOpcode(op
);
1135 l
->i
.c
.imm8b
= argc
;
1136 _buf
->commit(insSz
);
1138 NanoAssert((LInsp
)(l
+1)==_buf
->next());
1142 using namespace avmplus
;
1144 StackFilter::StackFilter(LirFilter
*in
, GC
*gc
, LirBuffer
*lirbuf
, LInsp sp
)
1145 : LirFilter(in
), gc(gc
), lirbuf(lirbuf
), sp(sp
), top(0)
1148 LInsp
StackFilter::read()
1152 LInsp i
= in
->read();
1157 LInsp base
= i
->oprnd2();
1160 LInsp v
= i
->oprnd1();
1161 int d
= i
->immdisp() >> 2;
1168 if (stk
.get(d
) && stk
.get(d
-1)) {
1186 * NB: If there is a backward branch other than the loop-restart branch, this is
1187 * going to be wrong. Unfortunately there doesn't seem to be an easy way to detect
1188 * such branches. Just do not create any.
1190 else if (i
->isGuard())
1193 top
= getTop(i
) >> 2;
1200 // inlined/separated version of SuperFastHash
1201 // This content is copyrighted by Paul Hsieh, For reference see : http://www.azillionmonkeys.com/qed/hash.html
1203 inline uint32_t _hash8(uint32_t hash
, const uint8_t data
)
1211 inline uint32_t _hash32(uint32_t hash
, const uint32_t data
)
1213 const uint32_t dlo
= data
& 0xffff;
1214 const uint32_t dhi
= data
>> 16;
1216 const uint32_t tmp
= (dhi
<< 11) ^ hash
;
1217 hash
= (hash
<< 16) ^ tmp
;
1222 inline uint32_t _hashptr(uint32_t hash
, const void* data
)
1224 #ifdef NANOJIT_64BIT
1225 hash
= _hash32(hash
, uint32_t(uintptr_t(data
) >> 32));
1226 hash
= _hash32(hash
, uint32_t(uintptr_t(data
)));
1229 return _hash32(hash
, uint32_t(data
));
1233 inline uint32_t _hashfinish(uint32_t hash
)
1235 /* Force "avalanching" of final 127 bits */
1245 LInsHashSet::LInsHashSet(GC
* gc
) :
1246 m_used(0), m_cap(kInitialCap
), m_gc(gc
)
1249 // m_list.set_meminfo_name("LInsHashSet.list");
1251 LInsp
*list
= (LInsp
*) gc
->Alloc(sizeof(LInsp
)*m_cap
, GC::kZero
);
1252 WB(gc
, this, &m_list
, list
);
1255 LInsHashSet::~LInsHashSet()
1260 void LInsHashSet::clear() {
1261 memset(m_list
, 0, sizeof(LInsp
)*m_cap
);
1265 /*static*/ uint32_t FASTCALL
LInsHashSet::hashcode(LInsp i
)
1267 const LOpcode op
= i
->opcode();
1271 return hashimm(i
->imm16());
1273 return hashimm(i
->imm32());
1275 return hashimmq(i
->constvalq());
1278 #if defined NANOJIT_64BIT
1283 int32_t argc
= i
->argc();
1284 NanoAssert(argc
< 10);
1285 for (int32_t j
=0; j
< argc
; j
++)
1286 args
[j
] = i
->arg(j
);
1287 return hashcall(i
->callInfo(), argc
, args
);
1290 if (operandCount
[op
] == 2)
1291 return hash2(op
, i
->oprnd1(), i
->oprnd2());
1293 return hash1(op
, i
->oprnd1());
1297 /*static*/ bool FASTCALL
LInsHashSet::equals(LInsp a
, LInsp b
)
1301 AvmAssert(a
->opcode() == b
->opcode());
1302 const LOpcode op
= a
->opcode();
1307 return a
->imm16() == b
->imm16();
1311 return a
->imm32() == b
->imm32();
1315 return a
->constvalq() == b
->constvalq();
1319 #if defined NANOJIT_64BIT
1323 if (a
->callInfo() != b
->callInfo()) return false;
1324 uint32_t argc
=a
->argc();
1325 NanoAssert(argc
== b
->argc());
1326 for (uint32_t i
=0; i
< argc
; i
++)
1327 if (a
->arg(i
) != b
->arg(i
))
1333 const uint32_t count
= operandCount
[op
];
1334 if ((count
>= 1 && a
->oprnd1() != b
->oprnd1()) ||
1335 (count
>= 2 && a
->oprnd2() != b
->oprnd2()))
1342 void FASTCALL
LInsHashSet::grow()
1344 const uint32_t newcap
= m_cap
<< 1;
1345 LInsp
*newlist
= (LInsp
*) m_gc
->Alloc(newcap
* sizeof(LInsp
), GC::kZero
);
1346 LInsp
*list
= m_list
;
1348 // newlist.set_meminfo_name("LInsHashSet.list");
1350 for (uint32_t i
=0, n
=m_cap
; i
< n
; i
++) {
1351 LInsp name
= list
[i
];
1352 if (!name
) continue;
1353 uint32_t j
= find(name
, hashcode(name
), newlist
, newcap
);
1358 WB(m_gc
, this, &m_list
, newlist
);
1361 uint32_t FASTCALL
LInsHashSet::find(LInsp name
, uint32_t hash
, const LInsp
*list
, uint32_t cap
)
1363 const uint32_t bitmask
= (cap
- 1) & ~0x1;
1365 uint32_t n
= 7 << 1;
1368 while ((k
= list
[hash
]) != NULL
&&
1369 (!LIns::sameop(k
,name
) || !equals(k
, name
)))
1371 hash
= (hash
+ (n
+= 2)) & bitmask
; // quadratic probe
1376 LInsp
LInsHashSet::add(LInsp name
, uint32_t k
)
1378 // this is relatively short-lived so let's try a more aggressive load factor
1379 // in the interest of improving performance
1380 if (((m_used
+1)<<1) >= m_cap
) // 0.50
1383 k
= find(name
, hashcode(name
), m_list
, m_cap
);
1385 NanoAssert(!m_list
[k
]);
1387 return m_list
[k
] = name
;
1390 void LInsHashSet::replace(LInsp i
)
1392 LInsp
*list
= m_list
;
1393 uint32_t k
= find(i
, hashcode(i
), list
, m_cap
);
1395 // already there, so replace it
1402 uint32_t LInsHashSet::hashimm(int32_t a
) {
1403 return _hashfinish(_hash32(0,a
));
1406 uint32_t LInsHashSet::hashimmq(uint64_t a
) {
1407 uint32_t hash
= _hash32(0, uint32_t(a
>> 32));
1408 return _hashfinish(_hash32(hash
, uint32_t(a
)));
1411 uint32_t LInsHashSet::hash1(LOpcode op
, LInsp a
) {
1412 uint32_t hash
= _hash8(0,uint8_t(op
));
1413 return _hashfinish(_hashptr(hash
, a
));
1416 uint32_t LInsHashSet::hash2(LOpcode op
, LInsp a
, LInsp b
) {
1417 uint32_t hash
= _hash8(0,uint8_t(op
));
1418 hash
= _hashptr(hash
, a
);
1419 return _hashfinish(_hashptr(hash
, b
));
1422 uint32_t LInsHashSet::hashcall(const CallInfo
*ci
, uint32_t argc
, LInsp args
[]) {
1423 uint32_t hash
= _hashptr(0, ci
);
1424 for (int32_t j
=argc
-1; j
>= 0; j
--)
1425 hash
= _hashptr(hash
,args
[j
]);
1426 return _hashfinish(hash
);
1429 LInsp
LInsHashSet::find32(int32_t a
, uint32_t &i
)
1431 uint32_t cap
= m_cap
;
1432 const LInsp
*list
= m_list
;
1433 const uint32_t bitmask
= (cap
- 1) & ~0x1;
1434 uint32_t hash
= hashimm(a
) & bitmask
;
1435 uint32_t n
= 7 << 1;
1437 while ((k
= list
[hash
]) != NULL
&&
1438 (!k
->isconst() || k
->constval() != a
))
1440 hash
= (hash
+ (n
+= 2)) & bitmask
; // quadratic probe
1446 LInsp
LInsHashSet::find64(uint64_t a
, uint32_t &i
)
1448 uint32_t cap
= m_cap
;
1449 const LInsp
*list
= m_list
;
1450 const uint32_t bitmask
= (cap
- 1) & ~0x1;
1451 uint32_t hash
= hashimmq(a
) & bitmask
;
1452 uint32_t n
= 7 << 1;
1454 while ((k
= list
[hash
]) != NULL
&&
1455 (!k
->isconstq() || k
->constvalq() != a
))
1457 hash
= (hash
+ (n
+= 2)) & bitmask
; // quadratic probe
1463 LInsp
LInsHashSet::find1(LOpcode op
, LInsp a
, uint32_t &i
)
1465 uint32_t cap
= m_cap
;
1466 const LInsp
*list
= m_list
;
1467 const uint32_t bitmask
= (cap
- 1) & ~0x1;
1468 uint32_t hash
= hash1(op
,a
) & bitmask
;
1469 uint32_t n
= 7 << 1;
1471 while ((k
= list
[hash
]) != NULL
&&
1472 (k
->opcode() != op
|| k
->oprnd1() != a
))
1474 hash
= (hash
+ (n
+= 2)) & bitmask
; // quadratic probe
1480 LInsp
LInsHashSet::find2(LOpcode op
, LInsp a
, LInsp b
, uint32_t &i
)
1482 uint32_t cap
= m_cap
;
1483 const LInsp
*list
= m_list
;
1484 const uint32_t bitmask
= (cap
- 1) & ~0x1;
1485 uint32_t hash
= hash2(op
,a
,b
) & bitmask
;
1486 uint32_t n
= 7 << 1;
1488 while ((k
= list
[hash
]) != NULL
&&
1489 (k
->opcode() != op
|| k
->oprnd1() != a
|| k
->oprnd2() != b
))
1491 hash
= (hash
+ (n
+= 2)) & bitmask
; // quadratic probe
1497 bool argsmatch(LInsp i
, uint32_t argc
, LInsp args
[])
1499 for (uint32_t j
=0; j
< argc
; j
++)
1500 if (i
->arg(j
) != args
[j
])
1505 LInsp
LInsHashSet::findcall(const CallInfo
*ci
, uint32_t argc
, LInsp args
[], uint32_t &i
)
1507 uint32_t cap
= m_cap
;
1508 const LInsp
*list
= m_list
;
1509 const uint32_t bitmask
= (cap
- 1) & ~0x1;
1510 uint32_t hash
= hashcall(ci
, argc
, args
) & bitmask
;
1511 uint32_t n
= 7 << 1;
1513 while ((k
= list
[hash
]) != NULL
&&
1514 (!k
->isCall() || k
->callInfo() != ci
|| !argsmatch(k
, argc
, args
)))
1516 hash
= (hash
+ (n
+= 2)) & bitmask
; // quadratic probe
1522 GuardRecord
*LIns::record()
1524 NanoAssert(isGuard());
1525 return (GuardRecord
*)oprnd2()->payload();
1529 class RetiredEntry
: public GCObject
1532 List
<LInsp
, LIST_NonGCObjects
> live
;
1534 RetiredEntry(GC
*gc
): live(gc
) {}
1539 SortedMap
<LInsp
,LInsp
,LIST_NonGCObjects
> live
;
1540 List
<RetiredEntry
*, LIST_GCObjects
> retired
;
1542 LiveTable(GC
*gc
) : live(gc
), retired(gc
), maxlive(0) {}
1545 for (size_t i
= 0; i
< retired
.size(); i
++) {
1546 NJ_DELETE(retired
.get(i
));
1550 void add(LInsp i
, LInsp use
) {
1551 if (!i
->isconst() && !i
->isconstq() && !live
.containsKey(i
)) {
1552 NanoAssert(size_t(i
->opcode()) < sizeof(lirNames
) / sizeof(lirNames
[0]));
1556 void retire(LInsp i
, GC
*gc
) {
1557 RetiredEntry
*e
= NJ_NEW(gc
, RetiredEntry
)(gc
);
1559 for (int j
=0, n
=live
.size(); j
< n
; j
++) {
1560 LInsp l
= live
.keyAt(j
);
1561 if (!l
->isStore() && !l
->isGuard())
1565 if ((size
= e
->live
.size()) > maxlive
)
1571 bool contains(LInsp i
) {
1572 return live
.containsKey(i
);
1576 void live(GC
*gc
, LirBuffer
*lirbuf
)
1578 // traverse backwards to find live exprs and a few other stats.
1582 LirReader
br(lirbuf
);
1583 StackFilter
sf(&br
, gc
, lirbuf
, lirbuf
->sp
);
1584 StackFilter
r(&sf
, gc
, lirbuf
, lirbuf
->rp
);
1587 live
.add(lirbuf
->state
, r
.pos());
1588 for (LInsp i
= r
.read(); i
!= 0; i
= r
.read())
1592 // first handle side-effect instructions
1593 if (!i
->isCse(lirbuf
->_functions
))
1600 // now propagate liveness
1601 if (live
.contains(i
))
1604 NanoAssert(size_t(i
->opcode()) < sizeof(operandCount
) / sizeof(operandCount
[0]));
1606 live
.add(i
->oprnd2(),i
); // base
1607 live
.add(i
->oprnd1(),i
); // val
1609 else if (i
->isop(LIR_cmov
) || i
->isop(LIR_qcmov
)) {
1610 live
.add(i
->oprnd1(),i
);
1611 live
.add(i
->oprnd2()->oprnd1(),i
);
1612 live
.add(i
->oprnd2()->oprnd2(),i
);
1614 else if (operandCount
[i
->opcode()] == 1) {
1615 live
.add(i
->oprnd1(),i
);
1617 else if (operandCount
[i
->opcode()] == 2) {
1618 live
.add(i
->oprnd1(),i
);
1619 live
.add(i
->oprnd2(),i
);
1621 else if (i
->isCall()) {
1622 for (int j
=0, c
=i
->argc(); j
< c
; j
++)
1623 live
.add(i
->arg(j
),i
);
1628 printf("live instruction count %d, total %u, max pressure %d\n",
1629 live
.retired
.size(), total
, live
.maxlive
);
1630 printf("side exits %u\n", exits
);
1632 // print live exprs, going forwards
1633 LirNameMap
*names
= lirbuf
->names
;
1634 bool newblock
= true;
1635 for (int j
=live
.retired
.size()-1; j
>= 0; j
--)
1637 RetiredEntry
*e
= live
.retired
[j
];
1638 char livebuf
[4000], *s
=livebuf
;
1640 if (!newblock
&& e
->i
->isop(LIR_label
)) {
1644 for (int k
=0,n
=e
->live
.size(); k
< n
; k
++) {
1645 strcpy(s
, names
->formatRef(e
->live
[k
]));
1648 NanoAssert(s
< livebuf
+sizeof(livebuf
));
1650 printf("%-60s %s\n", livebuf
, names
->formatIns(e
->i
));
1651 if (e
->i
->isGuard() || e
->i
->isBranch() || isRet(e
->i
->opcode())) {
1658 LabelMap::Entry::~Entry()
1662 LirNameMap::Entry::~Entry()
1666 LirNameMap::~LirNameMap()
1670 while ((e
= names
.removeLast()) != NULL
) {
1671 labels
->core
->freeString(e
->name
);
1676 bool LirNameMap::addName(LInsp i
, Stringp name
) {
1677 if (!names
.containsKey(i
)) {
1678 Entry
*e
= NJ_NEW(labels
->core
->gc
, Entry
)(name
);
1684 void LirNameMap::addName(LInsp i
, const char *name
) {
1685 Stringp new_name
= labels
->core
->newString(name
);
1686 if (!addName(i
, new_name
)) {
1687 labels
->core
->freeString(new_name
);
1691 void LirNameMap::copyName(LInsp i
, const char *s
, int suffix
) {
1693 if (isdigit(s
[strlen(s
)-1])) {
1694 // if s ends with a digit, add '_' to clarify the suffix
1695 sprintf(s2
,"%s_%d", s
, suffix
);
1697 sprintf(s2
,"%s%d", s
, suffix
);
1699 addName(i
, labels
->core
->newString(s2
));
1702 void LirNameMap::formatImm(int32_t c
, char *buf
) {
1703 if (c
>= 10000 || c
<= -10000)
1704 sprintf(buf
,"#%s",labels
->format((void*)c
));
1706 sprintf(buf
,"%d", c
);
1709 const char* LirNameMap::formatRef(LIns
*ref
)
1711 char buffer
[200], *buf
=buffer
;
1713 GC
*gc
= labels
->core
->gc
;
1714 if (names
.containsKey(ref
)) {
1715 StringNullTerminatedUTF8
cname(gc
, names
.get(ref
)->name
);
1716 strcat(buf
, cname
.c_str());
1718 else if (ref
->isconstq()) {
1719 #if defined NANOJIT_64BIT
1720 sprintf(buf
, "#0x%lx", (nj_printf_ld
)ref
->constvalq());
1722 formatImm(uint32_t(ref
->constvalq()>>32), buf
);
1725 formatImm(uint32_t(ref
->constvalq()), buf
);
1728 else if (ref
->isconst()) {
1729 formatImm(ref
->constval(), buf
);
1732 if (ref
->isCall()) {
1733 #if !defined NANOJIT_64BIT
1734 if (ref
->isop(LIR_callh
)) {
1735 // we've presumably seen the other half already
1736 ref
= ref
->oprnd1();
1739 copyName(ref
, ref
->callInfo()->_name
, funccounts
.add(ref
->callInfo()));
1740 #if !defined NANOJIT_64BIT
1744 NanoAssert(size_t(ref
->opcode()) < sizeof(lirNames
) / sizeof(lirNames
[0]));
1745 copyName(ref
, lirNames
[ref
->opcode()], lircounts
.add(ref
->opcode()));
1747 StringNullTerminatedUTF8
cname(gc
, names
.get(ref
)->name
);
1748 strcat(buf
, cname
.c_str());
1750 return labels
->dup(buffer
);
1753 const char* LirNameMap::formatIns(LIns
* i
)
1757 LOpcode op
= i
->opcode();
1763 sprintf(s
, "%s", formatRef(i
));
1768 sprintf(s
, "%s = %s %d", formatRef(i
), lirNames
[op
], i
->size());
1774 int32_t *p
= (int32_t*) (i
-2);
1775 sprintf(s
, "#%X:%X /* %g */", p
[1], p
[0], i
->constvalf());
1781 sprintf(s
, "%s", lirNames
[op
]);
1784 #if defined NANOJIT_64BIT
1789 sprintf(s
, "%s = %s ( ", formatRef(i
), i
->callInfo()->_name
);
1790 for (int32_t j
=i
->argc()-1; j
>= 0; j
--) {
1792 sprintf(s
, "%s ",formatRef(i
->arg(j
)));
1800 int32_t argc
= i
->argc();
1801 sprintf(s
, "%s = [%s] ( ", formatRef(i
), formatRef(i
->arg(argc
-1)));
1804 for (int32_t j
=argc
-1; j
>= 0; j
--) {
1806 sprintf(s
, "%s ",formatRef(i
->arg(j
)));
1814 uint32_t arg
= i
->imm8();
1816 if (arg
< sizeof(Assembler::argRegs
)/sizeof(Assembler::argRegs
[0])) {
1817 sprintf(s
, "%s = %s %d %s", formatRef(i
), lirNames
[op
],
1818 arg
, gpn(Assembler::argRegs
[arg
]));
1820 sprintf(s
, "%s = %s %d", formatRef(i
), lirNames
[op
], arg
);
1823 sprintf(s
, "%s = %s %d %s", formatRef(i
), lirNames
[op
],
1824 arg
, gpn(Assembler::savedRegs
[arg
]));
1830 sprintf(s
, "%s:", formatRef(i
));
1835 sprintf(s
, "%s %s -> %s", lirNames
[op
], formatRef(i
->oprnd1()),
1836 i
->oprnd2() ? formatRef(i
->oprnd2()) : "unpatched");
1840 sprintf(s
, "%s -> %s", lirNames
[op
],
1841 i
->oprnd2() ? formatRef(i
->oprnd2()) : "unpatched");
1847 sprintf(s
, "%s %s", lirNames
[op
], formatRef(i
->oprnd1()));
1860 sprintf(s
, "%s = %s %s", formatRef(i
), lirNames
[op
], formatRef(i
->oprnd1()));
1901 sprintf(s
, "%s = %s %s, %s", formatRef(i
), lirNames
[op
],
1902 formatRef(i
->oprnd1()),
1903 formatRef(i
->oprnd2()));
1907 sprintf(s
, "%s (%s), %s", lirNames
[op
],
1908 formatIns(i
->oprnd1()),
1909 formatRef(i
->oprnd2()));
1914 sprintf(s
, "%s = %s %s ? %s : %s", formatRef(i
), lirNames
[op
],
1915 formatRef(i
->oprnd1()),
1916 formatRef(i
->oprnd2()->oprnd1()),
1917 formatRef(i
->oprnd2()->oprnd2()));
1926 sprintf(s
, "%s = %s %s[%s]", formatRef(i
), lirNames
[op
],
1927 formatRef(i
->oprnd1()),
1928 formatRef(i
->oprnd2()));
1935 sprintf(s
, "%s %s[%d] = %s", lirNames
[op
],
1936 formatRef(i
->oprnd2()),
1938 formatRef(i
->oprnd1()));
1945 return labels
->dup(sbuf
);
1950 CseFilter::CseFilter(LirWriter
*out
, GC
*gc
)
1951 : LirWriter(out
), exprs(gc
) {}
1953 LIns
* CseFilter::insImm(int32_t imm
)
1956 LInsp found
= exprs
.find32(imm
, k
);
1959 return exprs
.add(out
->insImm(imm
), k
);
1962 LIns
* CseFilter::insImmq(uint64_t q
)
1965 LInsp found
= exprs
.find64(q
, k
);
1968 return exprs
.add(out
->insImmq(q
), k
);
1971 LIns
* CseFilter::ins0(LOpcode v
)
1975 return out
->ins0(v
);
1978 LIns
* CseFilter::ins1(LOpcode v
, LInsp a
)
1981 NanoAssert(operandCount
[v
]==1);
1983 LInsp found
= exprs
.find1(v
, a
, k
);
1986 return exprs
.add(out
->ins1(v
,a
), k
);
1988 return out
->ins1(v
,a
);
1991 LIns
* CseFilter::ins2(LOpcode v
, LInsp a
, LInsp b
)
1994 NanoAssert(operandCount
[v
]==2);
1996 LInsp found
= exprs
.find2(v
, a
, b
, k
);
1999 return exprs
.add(out
->ins2(v
,a
,b
), k
);
2001 return out
->ins2(v
,a
,b
);
2004 LIns
* CseFilter::insLoad(LOpcode v
, LInsp base
, LInsp disp
)
2007 NanoAssert(operandCount
[v
]==2);
2009 LInsp found
= exprs
.find2(v
, base
, disp
, k
);
2012 return exprs
.add(out
->insLoad(v
,base
,disp
), k
);
2014 return out
->insLoad(v
,base
,disp
);
2017 LInsp
CseFilter::insGuard(LOpcode v
, LInsp c
, LInsp x
)
2020 // conditional guard
2021 NanoAssert(operandCount
[v
]==1);
2023 LInsp found
= exprs
.find1(v
, c
, k
);
2026 return exprs
.add(out
->insGuard(v
,c
,x
), k
);
2028 return out
->insGuard(v
, c
, x
);
2031 LInsp
CseFilter::insCall(const CallInfo
*ci
, LInsp args
[])
2035 uint32_t argc
= ci
->count_args();
2036 LInsp found
= exprs
.findcall(ci
, argc
, args
, k
);
2039 return exprs
.add(out
->insCall(ci
, args
), k
);
2041 return out
->insCall(ci
, args
);
2044 CseReader::CseReader(LirFilter
*in
, LInsHashSet
*exprs
, const CallInfo
*functions
)
2045 : LirFilter(in
), exprs(exprs
), functions(functions
)
2048 LInsp
CseReader::read()
2050 LInsp i
= in
->read();
2052 if (i
->isCse(functions
))
2058 LIns
* FASTCALL
callArgN(LIns
* i
, uint32_t n
)
2060 return i
->arg(i
->argc()-n
-1);
2063 void compile(Assembler
* assm
, Fragment
* triggerFrag
)
2065 Fragmento
*frago
= triggerFrag
->lirbuf
->_frago
;
2066 AvmCore
*core
= frago
->core();
2069 verbose_only( StringList
asmOutput(gc
); )
2070 verbose_only( assm
->_outputCache
= &asmOutput
; )
2072 verbose_only(if (assm
->_verbose
&& core
->config
.verbose_live
)
2073 live(gc
, triggerFrag
->lirbuf
);)
2075 bool treeCompile
= core
->config
.tree_opt
&& (triggerFrag
->kind
== BranchTrace
);
2076 RegAllocMap
regMap(gc
);
2077 NInsList
loopJumps(gc
);
2079 // loopJumps.set_meminfo_name("LIR loopjumps");
2081 assm
->beginAssembly(triggerFrag
, ®Map
);
2085 //fprintf(stderr, "recompile trigger %X kind %d\n", (int)triggerFrag, triggerFrag->kind);
2086 Fragment
* root
= triggerFrag
;
2089 // recompile the entire tree
2090 root
= triggerFrag
->root
;
2091 root
->fragEntry
= 0;
2092 root
->loopEntry
= 0;
2093 root
->releaseCode(frago
);
2095 // do the tree branches
2096 Fragment
* frag
= root
->treeBranches
;
2099 // compile til no more frags
2102 assm
->assemble(frag
, loopJumps
);
2103 verbose_only(if (assm
->_verbose
)
2104 assm
->outputf("compiling branch %s ip %s",
2105 frago
->labels
->format(frag
),
2106 frago
->labels
->format(frag
->ip
)); )
2108 NanoAssert(frag
->kind
== BranchTrace
);
2109 RegAlloc
* regs
= NJ_NEW(gc
, RegAlloc
)();
2110 assm
->copyRegisters(regs
);
2111 assm
->releaseRegisters();
2112 SideExit
* exit
= frag
->spawnedFrom
;
2113 regMap
.put(exit
, regs
);
2115 frag
= frag
->treeBranches
;
2119 // now the the main trunk
2120 assm
->assemble(root
, loopJumps
);
2121 verbose_only(if (assm
->_verbose
)
2122 assm
->outputf("compiling trunk %s",
2123 frago
->labels
->format(root
));)
2124 NanoAssert(!frago
->core()->config
.tree_opt
|| root
== root
->anchor
|| root
->kind
== MergeTrace
);
2125 assm
->endAssembly(root
, loopJumps
);
2127 // reverse output so that assembly is displayed low-to-high
2128 verbose_only( assm
->_outputCache
= 0; )
2129 verbose_only(for(int i
=asmOutput
.size()-1; i
>=0; --i
) { assm
->outputf("%s",asmOutput
.get(i
)); } );
2131 if (assm
->error()) {
2132 root
->fragEntry
= 0;
2133 root
->loopEntry
= 0;
2137 LInsp
LoadFilter::insLoad(LOpcode v
, LInsp base
, LInsp disp
)
2139 if (base
!= sp
&& base
!= rp
&& (v
== LIR_ld
|| v
== LIR_ldq
)) {
2141 LInsp found
= exprs
.find2(v
, base
, disp
, k
);
2144 return exprs
.add(out
->insLoad(v
,base
,disp
), k
);
2146 return out
->insLoad(v
, base
, disp
);
2149 void LoadFilter::clear(LInsp p
)
2151 if (p
!= sp
&& p
!= rp
)
2155 LInsp
LoadFilter::insStore(LInsp v
, LInsp b
, LInsp d
)
2158 return out
->insStore(v
, b
, d
);
2161 LInsp
LoadFilter::insStorei(LInsp v
, LInsp b
, int32_t d
)
2164 return out
->insStorei(v
, b
, d
);
2167 LInsp
LoadFilter::insCall(const CallInfo
*ci
, LInsp args
[])
2171 return out
->insCall(ci
, args
);
2174 LInsp
LoadFilter::ins0(LOpcode op
)
2176 if (op
== LIR_label
)
2178 return out
->ins0(op
);
2181 #endif /* FEATURE_NANOJIT */
2183 #if defined(NJ_VERBOSE)
2184 LabelMap::LabelMap(AvmCore
*core
, LabelMap
* parent
)
2185 : parent(parent
), names(core
->gc
), addrs(core
->config
.verbose_addrs
), end(buf
), core(core
)
2188 LabelMap::~LabelMap()
2192 while ((e
= names
.removeLast()) != NULL
) {
2193 core
->freeString(e
->name
);
2198 void LabelMap::add(const void *p
, size_t size
, size_t align
, const char *name
)
2200 if (!this || names
.containsKey(p
))
2202 add(p
, size
, align
, core
->newString(name
));
2205 void LabelMap::add(const void *p
, size_t size
, size_t align
, Stringp name
)
2207 if (!this || names
.containsKey(p
))
2209 Entry
*e
= NJ_NEW(core
->gc
, Entry
)(name
, size
<<align
, align
);
2213 const char *LabelMap::format(const void *p
)
2216 int i
= names
.findNear(p
);
2218 const void *start
= names
.keyAt(i
);
2219 Entry
*e
= names
.at(i
);
2220 const void *end
= (const char*)start
+ e
->size
;
2221 avmplus::StringNullTerminatedUTF8
cname(core
->gc
, e
->name
);
2222 const char *name
= cname
.c_str();
2225 sprintf(b
,"%p %s",p
,name
);
2230 else if (p
> start
&& p
< end
) {
2231 int32_t d
= int32_t(intptr_t(p
)-intptr_t(start
)) >> e
->align
;
2233 sprintf(b
, "%p %s+%d", p
, name
, d
);
2235 sprintf(b
,"%s+%d", name
, d
);
2240 return parent
->format(p
);
2242 sprintf(b
, "%p", p
);
2247 return parent
->format(p
);
2249 sprintf(b
, "%p", p
);
2253 const char *LabelMap::dup(const char *b
)
2255 size_t need
= strlen(b
)+1;
2258 if (end
> buf
+sizeof(buf
)) {
2266 // copy all labels to parent, adding newbase to label addresses
2267 void LabelMap::promoteAll(const void *newbase
)
2269 for (int i
=0, n
=names
.size(); i
< n
; i
++) {
2270 void *base
= (char*)newbase
+ (intptr_t)names
.keyAt(i
);
2271 parent
->names
.put(base
, names
.at(i
));
2274 #endif // NJ_VERBOSE