Bug 488775 - TM: widen LIR instructions. r=graydon,edwsmith
[mozilla-central.git] / js / src / nanojit / LIR.cpp
blob20072cb967ce3c893fa5a14af5bb590c84e0d975
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
13 * License.
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.
22 * Contributor(s):
23 * Adobe AS3 Team
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 ***** */
39 #include "nanojit.h"
40 #include <stdio.h>
41 #include <ctype.h>
43 #ifdef PERFM
44 #include "../vprof/vprof.h"
45 #endif /* PERFM */
47 namespace nanojit
49 using namespace avmplus;
50 #ifdef FEATURE_NANOJIT
52 const uint8_t operandCount[] = {
53 #define OPDEF(op, number, operands) \
54 operands,
55 #define OPDEF64(op, number, operands) \
56 operands,
57 #include "LIRopcode.tbl"
58 #undef OPDEF
59 #undef OPDEF64
63 // LIR verbose specific
64 #ifdef NJ_VERBOSE
66 const char* lirNames[] = {
67 #define OPDEF(op, number, operands) \
68 #op,
69 #define OPDEF64(op, number, operands) \
70 #op,
71 #include "LIRopcode.tbl"
72 #undef OPDEF
73 #undef OPDEF64
74 NULL
77 #endif /* NANOJIT_VEBROSE */
79 // implementation
81 #ifdef NJ_PROFILE
82 // @todo fixup move to nanojit.h
83 #undef counter_value
84 #define counter_value(x) x
85 #endif /* NJ_PROFILE */
87 //static int32_t buffer_count = 0;
89 // LCompressedBuffer
90 LirBuffer::LirBuffer(Fragmento* frago, const CallInfo* functions)
91 : _frago(frago),
92 #ifdef NJ_VERBOSE
93 names(NULL),
94 #endif
95 _functions(functions), abi(ABI_FASTCALL),
96 state(NULL), param1(NULL), sp(NULL), rp(NULL),
97 _pages(frago->core()->GetGC())
99 rewind();
102 LirBuffer::~LirBuffer()
104 clear();
105 verbose_only(if (names) NJ_DELETE(names);)
106 _frago = 0;
109 void LirBuffer::clear()
111 // free all the memory and clear the stats
112 _frago->pagesRelease(_pages);
113 NanoAssert(!_pages.size());
114 _unused = 0;
115 _stats.lir = 0;
116 _noMem = 0;
117 _nextPage = 0;
118 for (int i = 0; i < NumSavedRegs; ++i)
119 savedRegs[i] = NULL;
120 explicitSavedRegs = false;
123 void LirBuffer::rewind()
125 clear();
126 // pre-allocate the current and the next page we will be using
127 Page* start = pageAlloc();
128 _unused = start ? &start->lir[0] : NULL;
129 _nextPage = pageAlloc();
130 NanoAssert((_unused && _nextPage) || _noMem);
133 int32_t LirBuffer::insCount()
135 // Doesn't include LIR_skip payload or LIR_call arg slots.
136 return _stats.lir;
139 int32_t LirBuffer::byteCount()
141 return ((_pages.size() ? _pages.size()-1 : 0) * sizeof(Page)) +
142 ((int32_t)_unused - (int32_t)pageTop(_unused));
145 Page* LirBuffer::pageAlloc()
147 Page* page = _frago->pageAlloc();
148 if (page)
149 _pages.add(page);
150 else
151 _noMem = 1;
152 return page;
155 LInsp LirBuffer::next()
157 return _unused;
160 void LirBufWriter::ensureRoom(uint32_t count)
162 NanoAssert(count <= NJ_PAGE_SIZE - sizeof(LIns));
163 LInsp before = _buf->next();
164 LInsp after = before+count+1;
165 // transition to the next page?
166 if (!samepage(before,after))
168 // we don't want this to fail, so we always have a page in reserve
169 NanoAssert(_buf->_nextPage);
170 _buf->_unused = &_buf->_nextPage->lir[0];
171 // link LIR stream back to prior instruction (careful,
172 // insSkipWithoutBuffer relies on _unused...)
173 insSkipWithoutBuffer(before-1);
174 _buf->_nextPage = _buf->pageAlloc();
175 NanoAssert(_buf->_nextPage || _buf->_noMem);
179 LInsp LirBufWriter::insSkipWithoutBuffer(LInsp to)
181 LInsp l = _buf->next();
182 NanoAssert(samepage(l,l+1)); // make sure we have room
183 l->initOpcodeAndClearResv(LIR_skip);
184 l->setOprnd1(to);
185 _buf->commit(1);
186 _buf->_stats.lir++;
187 return l;
190 LInsp LirBuffer::commit(uint32_t count)
192 NanoAssertMsg( samepage(_unused, _unused+count), "You need to call ensureRoom first!" );
193 return _unused += count;
196 LInsp LirBufWriter::insStorei(LInsp val, LInsp base, int32_t d)
198 ensureRoom(1);
199 LOpcode op = val->isQuad() ? LIR_stqi : LIR_sti;
200 LInsp l = _buf->next();
201 l->initOpcodeAndClearResv(op);
202 l->setOprnd1(val);
203 l->setOprnd2(base);
204 l->setDisp(d);
205 _buf->commit(1);
206 _buf->_stats.lir++;
207 return l;
210 LInsp LirBufWriter::ins0(LOpcode op)
212 ensureRoom(1);
213 LirBuffer *b = this->_buf;
214 LInsp l = b->next();
215 l->initOpcodeAndClearResv(op);
216 b->commit(1);
217 b->_stats.lir++;
218 return l;
221 LInsp LirBufWriter::ins1(LOpcode op, LInsp o1)
223 ensureRoom(1);
224 LInsp l = _buf->next();
225 l->initOpcodeAndClearResv(op);
226 l->setOprnd1(o1);
227 _buf->commit(1);
228 _buf->_stats.lir++;
229 return l;
232 LInsp LirBufWriter::ins2(LOpcode op, LInsp o1, LInsp o2)
234 ensureRoom(1);
235 LInsp l = _buf->next();
236 l->initOpcodeAndClearResv(op);
237 l->setOprnd1(o1);
238 l->setOprnd2(o2);
239 _buf->commit(1);
240 _buf->_stats.lir++;
241 return l;
244 LInsp LirBufWriter::insLoad(LOpcode op, LInsp base, LInsp d)
246 return ins2(op,base,d);
249 LInsp LirBufWriter::insGuard(LOpcode op, LInsp c, LInsp data)
251 return ins2(op, c, data);
254 LInsp LirBufWriter::insBranch(LOpcode op, LInsp condition, LInsp toLabel)
256 NanoAssert(condition);
257 return ins2(op, condition, toLabel);
260 LInsp LirBufWriter::insAlloc(int32_t size)
262 size = (size+3)>>2; // # of required 32bit words
263 NanoAssert(isU16(size));
264 ensureRoom(1);
265 LInsp l = _buf->next();
266 l->initOpcodeAndClearResv(LIR_alloc);
267 l->i.imm32 = size;
268 _buf->commit(1);
269 _buf->_stats.lir++;
270 return l;
273 LInsp LirBufWriter::insParam(int32_t arg, int32_t kind)
275 ensureRoom(1);
276 LirBuffer *b = this->_buf;
277 LInsp l = b->next();
278 l->initOpcodeAndClearResv(LIR_param);
279 NanoAssert(isU8(arg) && isU8(kind));
280 l->c.imm8a = arg;
281 l->c.imm8b = kind;
282 l->c.ci = NULL;
283 if (kind) {
284 NanoAssert(arg < NumSavedRegs);
285 b->savedRegs[arg] = l;
286 b->explicitSavedRegs = true;
288 b->commit(1);
289 b->_stats.lir++;
290 return l;
293 LInsp LirBufWriter::insImm(int32_t imm)
295 ensureRoom(1);
296 LInsp l = _buf->next();
297 l->initOpcodeAndClearResv(LIR_int);
298 l->setimm32(imm);
299 _buf->commit(1);
300 _buf->_stats.lir++;
301 return l;
304 LInsp LirBufWriter::insImmq(uint64_t imm)
306 ensureRoom(1);
307 LInsp l = _buf->next();
308 l->initOpcodeAndClearResv(LIR_quad);
309 l->i64.imm64_0 = int32_t(imm);
310 l->i64.imm64_1 = int32_t(imm>>32);
311 _buf->commit(1);
312 _buf->_stats.lir++;
313 return l;
316 LInsp LirBufWriter::insSkip(size_t size)
318 const uint32_t nSlots = (size+sizeof(LIns)-1)/sizeof(LIns);
319 ensureRoom(nSlots); // make room for it
320 LInsp last = _buf->next()-1; // safe, next()-1+nSlots guaranteed to be on same page
321 _buf->commit(nSlots);
322 NanoAssert(samepage(last,_buf->next()));
323 ensureRoom(1);
324 return insSkipWithoutBuffer(last);
327 LInsp LirReader::read()
329 LInsp cur = _i;
330 if (!cur)
331 return 0;
332 LIns* i = cur;
333 LOpcode iop = i->opcode();
336 switch (iop)
338 default:
339 i--;
340 break;
342 #if defined NANOJIT_64BIT
343 case LIR_callh:
344 #endif
345 case LIR_call:
346 case LIR_fcall:
347 case LIR_calli:
348 case LIR_fcalli:
349 NanoAssert( samepage(i, i + 1 - i->callInsSlots()) );
350 i -= i->callInsSlots();
351 break;
353 case LIR_skip:
354 NanoAssert(i->oprnd1() != i);
355 i = i->oprnd1();
356 break;
358 case LIR_start:
359 _i = 0; // start of trace
360 return cur;
362 iop = i->opcode();
364 while (iop==LIR_skip || iop==LIR_2);
365 _i = i;
366 return cur;
369 bool FASTCALL isCmp(LOpcode c) {
370 return (c >= LIR_eq && c <= LIR_uge) || (c >= LIR_feq && c <= LIR_fge);
373 bool FASTCALL isCond(LOpcode c) {
374 return (c == LIR_ov) || (c == LIR_cs) || isCmp(c);
377 bool FASTCALL isFloat(LOpcode c) {
378 switch (c) {
379 default:
380 return false;
381 case LIR_fadd:
382 case LIR_fsub:
383 case LIR_fmul:
384 case LIR_fdiv:
385 case LIR_fneg:
386 case LIR_fcall:
387 case LIR_fcalli:
388 case LIR_i2f:
389 case LIR_u2f:
390 return true;
394 bool LIns::isCmp() const {
395 return nanojit::isCmp(u.code);
398 bool LIns::isCond() const {
399 return nanojit::isCond(u.code);
402 bool LIns::isQuad() const {
403 #ifdef AVMPLUS_64BIT
404 // callh in 64bit cpu's means a call that returns an int64 in a single register
405 return (u.code & LIR64) != 0 || u.code == LIR_callh;
406 #else
407 // callh in 32bit cpu's means the 32bit MSW of an int64 result in 2 registers
408 return (u.code & LIR64) != 0;
409 #endif
412 bool LIns::isconstval(int32_t val) const
414 return isconst() && imm32()==val;
417 bool LIns::isconstq() const
419 return isop(LIR_quad);
422 bool LIns::isconstp() const
424 #ifdef AVMPLUS_64BIT
425 return isconstq();
426 #else
427 return isconst();
428 #endif
431 bool FASTCALL isCse(LOpcode op) {
432 op = LOpcode(op & ~LIR64);
433 return op >= LIR_ldcs && op <= LIR_uge;
436 bool LIns::isCse(const CallInfo *functions) const
438 return nanojit::isCse(u.code) || (isCall() && callInfo()->_cse);
441 void LIns::initOpcodeAndClearResv(LOpcode op)
443 NanoAssert(4*sizeof(void*) == sizeof(LIns));
444 u.code = op;
445 u.resv = 0; // have to zero this; the Assembler relies on it
448 void LIns::setTarget(LInsp label)
450 NanoAssert(label && label->isop(LIR_label));
451 NanoAssert(isBranch());
452 setOprnd2(label);
455 LInsp LIns::getTarget()
457 NanoAssert(isBranch());
458 return oprnd2();
461 void *LIns::payload() const
463 NanoAssert(isop(LIR_skip));
464 return (void*) (oprnd1()+1);
467 uint64_t LIns::imm64() const
469 #ifdef AVMPLUS_UNALIGNED_ACCESS
470 return *(const uint64_t*)i64.imm32;
471 #else
472 union { uint64_t tmp; int32_t dst[2]; } u;
473 #ifdef AVMPLUS_BIG_ENDIAN
474 u.dst[0] = i64.imm64_1;
475 u.dst[1] = i64.imm64_0;
476 #else
477 u.dst[0] = i64.imm64_0;
478 u.dst[1] = i64.imm64_1;
479 #endif
480 return u.tmp;
481 #endif
484 double LIns::imm64f() const
486 NanoAssert(isconstq());
487 #ifdef AVMPLUS_UNALIGNED_ACCESS
488 return *(const double*)i64.imm32;
489 #else
490 union { uint32_t dst[2]; double tmpf; } u;
491 #ifdef AVMPLUS_BIG_ENDIAN
492 u.dst[0] = i64.imm64_1;
493 u.dst[1] = i64.imm64_0;
494 #else
495 u.dst[0] = i64.imm64_0;
496 u.dst[1] = i64.imm64_1;
497 #endif
498 return u.tmpf;
499 #endif
502 inline uint32_t argSlots(uint32_t argc) {
503 NanoAssert(4*sizeof(void*) == sizeof(LIns));
504 return (argc + 3) / 4; // we can fit four args per slot
507 size_t LIns::callInsSlots() const
509 return argSlots(argc()) + 1;
512 const CallInfo* LIns::callInfo() const
514 return c.ci;
517 // Index args in r-l order. arg(0) is rightmost arg.
518 // Nb: this must be kept in sync with insCall().
519 LInsp LIns::arg(uint32_t i)
521 NanoAssert(i < argc());
522 LInsp* offs = (LInsp*)this - (i+1);
523 return *offs;
526 LIns* LirWriter::ins2i(LOpcode v, LIns* oprnd1, int32_t imm)
528 return ins2(v, oprnd1, insImm(imm));
531 bool insIsS16(LInsp i)
533 if (i->isconst()) {
534 int c = i->imm32();
535 return isS16(c);
537 if (i->isop(LIR_cmov) || i->isop(LIR_qcmov)) {
538 LInsp vals = i->oprnd2();
539 return insIsS16(vals->oprnd1()) && insIsS16(vals->oprnd2());
541 if (i->isCmp())
542 return true;
543 // many other possibilities too.
544 return false;
547 LIns* ExprFilter::ins1(LOpcode v, LIns* i)
549 if (v == LIR_qlo) {
550 if (i->isconstq())
551 return insImm(int32_t(i->imm64()));
552 if (i->isop(LIR_qjoin))
553 return i->oprnd1();
555 else if (v == LIR_qhi) {
556 if (i->isconstq())
557 return insImm(int32_t(i->imm64()>>32));
558 if (i->isop(LIR_qjoin))
559 return i->oprnd2();
561 else if (i->isconst()) {
562 int32_t c = i->imm32();
563 if (v == LIR_neg)
564 return insImm(-c);
565 if (v == LIR_not)
566 return insImm(~c);
568 else if (v == i->opcode() && (v == LIR_not || v == LIR_neg || v == LIR_fneg)) {
569 // not(not(x)) = x; neg(neg(x)) = x; fneg(fneg(x)) = x;
570 return i->oprnd1();
572 /* [ed 8.27.08] this causes a big slowdown in gameoflife.as. why?
573 else if (i->isconst()) {
574 if (v == LIR_i2f) {
575 return insImmf(i->imm32());
577 else if (v == LIR_u2f) {
578 return insImmf((uint32_t)i->imm32());
582 // todo
583 // -(a-b) = b-a
585 return out->ins1(v, i);
588 LIns* ExprFilter::ins2(LOpcode v, LIns* oprnd1, LIns* oprnd2)
590 NanoAssert(oprnd1 && oprnd2);
591 if (v == LIR_cmov || v == LIR_qcmov) {
592 if (oprnd2->oprnd1() == oprnd2->oprnd2()) {
593 // c ? a : a => a
594 return oprnd2->oprnd1();
596 if (oprnd1->isconst()) {
597 // const ? x : y => return x or y depending on const
598 return oprnd1->imm32() ? oprnd2->oprnd1() : oprnd2->oprnd2();
601 if (oprnd1 == oprnd2)
603 if (v == LIR_xor || v == LIR_sub ||
604 v == LIR_ult || v == LIR_ugt || v == LIR_gt || v == LIR_lt)
605 return insImm(0);
606 if (v == LIR_or || v == LIR_and)
607 return oprnd1;
608 if (v == LIR_le || v == LIR_ule || v == LIR_ge || v == LIR_uge) {
609 // x <= x == 1; x >= x == 1
610 return insImm(1);
613 if (oprnd1->isconst() && oprnd2->isconst())
615 int32_t c1 = oprnd1->imm32();
616 int32_t c2 = oprnd2->imm32();
617 double d;
618 int32_t r;
619 if (v == LIR_qjoin) {
620 uint64_t q = c1 | uint64_t(c2)<<32;
621 return insImmq(q);
623 switch (v) {
624 case LIR_eq:
625 return insImm(c1 == c2);
626 case LIR_ov:
627 return insImm((c2 != 0) && ((c1 + c2) <= c1));
628 case LIR_cs:
629 return insImm((c2 != 0) && ((uint32_t(c1) + uint32_t(c2)) <= uint32_t(c1)));
630 case LIR_lt:
631 return insImm(c1 < c2);
632 case LIR_gt:
633 return insImm(c1 > c2);
634 case LIR_le:
635 return insImm(c1 <= c2);
636 case LIR_ge:
637 return insImm(c1 >= c2);
638 case LIR_ult:
639 return insImm(uint32_t(c1) < uint32_t(c2));
640 case LIR_ugt:
641 return insImm(uint32_t(c1) > uint32_t(c2));
642 case LIR_ule:
643 return insImm(uint32_t(c1) <= uint32_t(c2));
644 case LIR_uge:
645 return insImm(uint32_t(c1) >= uint32_t(c2));
646 case LIR_rsh:
647 return insImm(int32_t(c1) >> int32_t(c2));
648 case LIR_lsh:
649 return insImm(int32_t(c1) << int32_t(c2));
650 case LIR_ush:
651 return insImm(uint32_t(c1) >> int32_t(c2));
652 case LIR_or:
653 return insImm(uint32_t(c1) | int32_t(c2));
654 case LIR_and:
655 return insImm(uint32_t(c1) & int32_t(c2));
656 case LIR_xor:
657 return insImm(uint32_t(c1) ^ int32_t(c2));
658 case LIR_add:
659 d = double(c1) + double(c2);
660 fold:
661 r = int32_t(d);
662 if (r == d)
663 return insImm(r);
664 break;
665 case LIR_sub:
666 d = double(c1) - double(c2);
667 goto fold;
668 case LIR_mul:
669 d = double(c1) * double(c2);
670 goto fold;
671 default:
675 else if (oprnd1->isconstq() && oprnd2->isconstq())
677 double c1 = oprnd1->imm64f();
678 double c2 = oprnd2->imm64f();
679 switch (v) {
680 case LIR_feq:
681 return insImm(c1 == c2);
682 case LIR_flt:
683 return insImm(c1 < c2);
684 case LIR_fgt:
685 return insImm(c1 > c2);
686 case LIR_fle:
687 return insImm(c1 <= c2);
688 case LIR_fge:
689 return insImm(c1 >= c2);
690 case LIR_fadd:
691 return insImmf(c1 + c2);
692 case LIR_fsub:
693 return insImmf(c1 - c2);
694 case LIR_fmul:
695 return insImmf(c1 * c2);
696 case LIR_fdiv:
697 return insImmf(c1 / c2);
698 default:
702 else if (oprnd1->isconst() && !oprnd2->isconst())
704 if (v == LIR_add || v == LIR_addp || v == LIR_mul ||
705 v == LIR_fadd || v == LIR_fmul ||
706 v == LIR_xor || v == LIR_or || v == LIR_and ||
707 v == LIR_eq) {
708 // move const to rhs
709 LIns* t = oprnd2;
710 oprnd2 = oprnd1;
711 oprnd1 = t;
713 else if (v >= LIR_lt && v <= LIR_uge) {
714 NanoStaticAssert((LIR_lt ^ 1) == LIR_gt);
715 NanoStaticAssert((LIR_le ^ 1) == LIR_ge);
716 NanoStaticAssert((LIR_ult ^ 1) == LIR_ugt);
717 NanoStaticAssert((LIR_ule ^ 1) == LIR_uge);
719 // move const to rhs, swap the operator
720 LIns *t = oprnd2;
721 oprnd2 = oprnd1;
722 oprnd1 = t;
723 v = LOpcode(v^1);
727 if (oprnd2->isconst())
729 int c = oprnd2->imm32();
730 if (v == LIR_add && oprnd1->isop(LIR_add) && oprnd1->oprnd2()->isconst()) {
731 // add(add(x,c1),c2) => add(x,c1+c2)
732 c += oprnd1->oprnd2()->imm32();
733 oprnd2 = insImm(c);
734 oprnd1 = oprnd1->oprnd1();
736 else if (v == LIR_sub && oprnd1->isop(LIR_add) && oprnd1->oprnd2()->isconst()) {
737 // sub(add(x,c1),c2) => add(x,c1-c2)
738 c = oprnd1->oprnd2()->imm32() - c;
739 oprnd2 = insImm(c);
740 oprnd1 = oprnd1->oprnd1();
741 v = LIR_add;
743 else if (v == LIR_rsh && c == 16 && oprnd1->isop(LIR_lsh) &&
744 oprnd1->oprnd2()->isconstval(16)) {
745 if (insIsS16(oprnd1->oprnd1())) {
746 // rsh(lhs(x,16),16) == x, if x is S16
747 return oprnd1->oprnd1();
750 else if (v == LIR_ult) {
751 if (oprnd1->isop(LIR_cmov) || oprnd1->isop(LIR_qcmov)) {
752 LInsp a = oprnd1->oprnd2()->oprnd1();
753 LInsp b = oprnd1->oprnd2()->oprnd2();
754 if (a->isconst() && b->isconst()) {
755 bool a_lt = uint32_t(a->imm32()) < uint32_t(oprnd2->imm32());
756 bool b_lt = uint32_t(b->imm32()) < uint32_t(oprnd2->imm32());
757 if (a_lt == b_lt)
758 return insImm(a_lt);
763 if (c == 0)
765 if (v == LIR_add || v == LIR_addp || v == LIR_or || v == LIR_xor ||
766 v == LIR_sub || v == LIR_lsh || v == LIR_rsh || v == LIR_ush)
767 return oprnd1;
768 else if (v == LIR_and || v == LIR_mul)
769 return oprnd2;
770 else if (v == LIR_eq && oprnd1->isop(LIR_or) &&
771 oprnd1->oprnd2()->isconst() &&
772 oprnd1->oprnd2()->imm32() != 0) {
773 // (x or c) != 0 if c != 0
774 return insImm(0);
777 else if (c == -1 || (c == 1 && oprnd1->isCmp())) {
778 if (v == LIR_or) {
779 // x | -1 = -1, cmp | 1 = 1
780 return oprnd2;
782 else if (v == LIR_and) {
783 // x & -1 = x, cmp & 1 = cmp
784 return oprnd1;
789 LInsp i;
790 if (v == LIR_qjoin && oprnd1->isop(LIR_qlo) && oprnd2->isop(LIR_qhi)
791 && (i = oprnd1->oprnd1()) == oprnd2->oprnd1()) {
792 // qjoin(qlo(x),qhi(x)) == x
793 return i;
796 return out->ins2(v, oprnd1, oprnd2);
799 LIns* ExprFilter::insGuard(LOpcode v, LInsp c, LInsp x)
801 if (v == LIR_xt || v == LIR_xf) {
802 if (c->isconst()) {
803 if ((v == LIR_xt && !c->imm32()) || (v == LIR_xf && c->imm32())) {
804 return 0; // no guard needed
806 else {
807 #ifdef JS_TRACER
808 // We're emitting a guard that will always fail. Any code
809 // emitted after this guard is dead code. We could
810 // silently optimize out the rest of the emitted code, but
811 // this could indicate a performance problem or other bug,
812 // so assert in debug builds.
813 NanoAssertMsg(0, "Constantly false guard detected");
814 #endif
815 return out->insGuard(LIR_x, out->insImm(1), x);
818 else {
819 NanoStaticAssert((LIR_xt ^ 1) == LIR_xf);
820 while (c->isop(LIR_eq) && c->oprnd1()->isCmp() &&
821 c->oprnd2()->isconstval(0)) {
822 // xt(eq(cmp,0)) => xf(cmp) or xf(eq(cmp,0)) => xt(cmp)
823 v = LOpcode(v^1);
824 c = c->oprnd1();
828 return out->insGuard(v, c, x);
831 LIns* ExprFilter::insBranch(LOpcode v, LIns *c, LIns *t)
833 if (v == LIR_jt || v == LIR_jf) {
834 while (c->isop(LIR_eq) && c->oprnd1()->isCmp() && c->oprnd2()->isconstval(0)) {
835 // jt(eq(cmp,0)) => jf(cmp) or jf(eq(cmp,0)) => jt(cmp)
836 v = LOpcode(v ^ 1);
837 c = c->oprnd1();
840 return out->insBranch(v, c, t);
843 LIns* LirWriter::insLoadi(LIns *base, int disp)
845 return insLoad(LIR_ld,base,disp);
848 LIns* LirWriter::insLoad(LOpcode op, LIns *base, int disp)
850 return insLoad(op, base, insImm(disp));
853 LIns* LirWriter::ins_eq0(LIns* oprnd1)
855 return ins2i(LIR_eq, oprnd1, 0);
858 LIns* LirWriter::insImmf(double f)
860 union {
861 double f;
862 uint64_t q;
863 } u;
864 u.f = f;
865 return insImmq(u.q);
868 LIns* LirWriter::qjoin(LInsp lo, LInsp hi)
870 return ins2(LIR_qjoin, lo, hi);
873 LIns* LirWriter::insImmPtr(const void *ptr)
875 return sizeof(ptr) == 8 ? insImmq((uintptr_t)ptr) : insImm((intptr_t)ptr);
878 LIns* LirWriter::ins_choose(LIns* cond, LIns* iftrue, LIns* iffalse)
880 // if not a conditional, make it implicitly an ==0 test (then flop results)
881 if (!cond->isCmp())
883 cond = ins_eq0(cond);
884 LInsp tmp = iftrue;
885 iftrue = iffalse;
886 iffalse = tmp;
889 if (true/*avmplus::AvmCore::use_cmov()*/)
891 return ins2((iftrue->isQuad() || iffalse->isQuad()) ? LIR_qcmov : LIR_cmov, cond, ins2(LIR_2, iftrue, iffalse));
894 // @todo -- it might be better to use a short conditional branch rather than
895 // the bit-twiddling on systems that don't provide a conditional move instruction.
896 LInsp ncond = ins1(LIR_neg, cond); // cond ? -1 : 0
897 return ins2(LIR_or,
898 ins2(LIR_and, iftrue, ncond),
899 ins2(LIR_and, iffalse, ins1(LIR_not, ncond)));
902 LIns* LirBufWriter::insCall(const CallInfo *ci, LInsp args[])
904 static const LOpcode k_callmap[] = { LIR_call, LIR_fcall, LIR_call, LIR_callh };
905 static const LOpcode k_callimap[] = { LIR_calli, LIR_fcalli, LIR_calli, LIR_skip };
907 uint32_t argt = ci->_argtypes;
908 LOpcode op = (ci->isIndirect() ? k_callimap : k_callmap)[argt & 3];
909 NanoAssert(op != LIR_skip); // LIR_skip here is just an error condition
911 ArgSize sizes[MAXARGS];
912 int32_t argc = ci->get_sizes(sizes);
914 if (AvmCore::config.soft_float) {
915 if (op == LIR_fcall)
916 op = LIR_callh;
919 // An example of what we're trying to serialize (for a 32-bit machine):
921 // byte slot
922 // ---- ----
923 // N [ arg operand #3 ---------------------- K
924 // N+4 arg operand #2 ----------------------
925 // N+8 arg operand #1 ----------------------
926 // N+12 arg operand #0 ---------------------- ]
927 // N+16 [ code=LIR_call | resv | (pad16) ------ K+1
928 // imm8a | (pad24) ---------------------
929 // imm8b | (pad24) ---------------------
930 // ci ---------------------------------- ]
932 // In this example:
933 // 'argc' = 4
934 // argSlots(argc) = 1
936 NanoAssert(argc <= (int)MAXARGS);
937 int32_t nSlots = argSlots(argc) + 1;
938 ensureRoom(nSlots);
940 // Skip slots needed for call parameters.
941 LInsp l = _buf->next() + argSlots(argc);
943 // Call parameters laid in reverse order.
944 // Nb: this must be kept in sync with arg().
945 LInsp* offs = (LInsp*)l;
946 for (int32_t i=0; i < argc; i++)
947 *--offs = args[i];
948 NanoAssert((LInsp)offs >= _buf->next());
950 #ifndef NANOJIT_64BIT
951 l->initOpcodeAndClearResv(op==LIR_callh ? LIR_call : op);
952 #else
953 l->initOpcodeAndClearResv(op);
954 #endif
955 l->c.imm8a = 0;
956 l->c.imm8b = argc;
957 l->c.ci = ci;
958 _buf->commit(nSlots);
959 _buf->_stats.lir++;
960 return l;
963 using namespace avmplus;
965 StackFilter::StackFilter(LirFilter *in, GC *gc, LirBuffer *lirbuf, LInsp sp)
966 : LirFilter(in), gc(gc), lirbuf(lirbuf), sp(sp), top(0)
969 LInsp StackFilter::read()
971 for (;;)
973 LInsp i = in->read();
974 if (!i)
975 return i;
976 if (i->isStore())
978 LInsp base = i->oprnd2();
979 if (base == sp)
981 LInsp v = i->oprnd1();
982 int d = i->immdisp() >> 2;
983 if (d >= top) {
984 continue;
985 } else {
986 d = top - d;
987 if (v->isQuad()) {
988 // storing 8 bytes
989 if (stk.get(d) && stk.get(d-1)) {
990 continue;
991 } else {
992 stk.set(gc, d);
993 stk.set(gc, d-1);
996 else {
997 // storing 4 bytes
998 if (stk.get(d))
999 continue;
1000 else
1001 stk.set(gc, d);
1007 * NB: If there is a backward branch other than the loop-restart branch, this is
1008 * going to be wrong. Unfortunately there doesn't seem to be an easy way to detect
1009 * such branches. Just do not create any.
1011 else if (i->isGuard())
1013 stk.reset();
1014 top = getTop(i) >> 2;
1016 return i;
1021 // inlined/separated version of SuperFastHash
1022 // This content is copyrighted by Paul Hsieh, For reference see : http://www.azillionmonkeys.com/qed/hash.html
1024 inline uint32_t _hash8(uint32_t hash, const uint8_t data)
1026 hash += data;
1027 hash ^= hash << 10;
1028 hash += hash >> 1;
1029 return hash;
1032 inline uint32_t _hash32(uint32_t hash, const uint32_t data)
1034 const uint32_t dlo = data & 0xffff;
1035 const uint32_t dhi = data >> 16;
1036 hash += dlo;
1037 const uint32_t tmp = (dhi << 11) ^ hash;
1038 hash = (hash << 16) ^ tmp;
1039 hash += hash >> 11;
1040 return hash;
1043 inline uint32_t _hashptr(uint32_t hash, const void* data)
1045 #ifdef NANOJIT_64BIT
1046 hash = _hash32(hash, uint32_t(uintptr_t(data) >> 32));
1047 hash = _hash32(hash, uint32_t(uintptr_t(data)));
1048 return hash;
1049 #else
1050 return _hash32(hash, uint32_t(data));
1051 #endif
1054 inline uint32_t _hashfinish(uint32_t hash)
1056 /* Force "avalanching" of final 127 bits */
1057 hash ^= hash << 3;
1058 hash += hash >> 5;
1059 hash ^= hash << 4;
1060 hash += hash >> 17;
1061 hash ^= hash << 25;
1062 hash += hash >> 6;
1063 return hash;
1066 LInsHashSet::LInsHashSet(GC* gc) :
1067 m_used(0), m_cap(kInitialCap), m_gc(gc)
1069 #ifdef MEMORY_INFO
1070 // m_list.set_meminfo_name("LInsHashSet.list");
1071 #endif
1072 LInsp *list = (LInsp*) gc->Alloc(sizeof(LInsp)*m_cap, GC::kZero);
1073 WB(gc, this, &m_list, list);
1076 LInsHashSet::~LInsHashSet()
1078 m_gc->Free(m_list);
1081 void LInsHashSet::clear() {
1082 memset(m_list, 0, sizeof(LInsp)*m_cap);
1083 m_used = 0;
1086 /*static*/ uint32_t FASTCALL LInsHashSet::hashcode(LInsp i)
1088 const LOpcode op = i->opcode();
1089 switch (op)
1091 case LIR_int:
1092 return hashimm(i->imm32());
1093 case LIR_quad:
1094 return hashimmq(i->imm64());
1095 case LIR_call:
1096 case LIR_fcall:
1097 #if defined NANOJIT_64BIT
1098 case LIR_callh:
1099 #endif
1101 LInsp args[10];
1102 int32_t argc = i->argc();
1103 NanoAssert(argc < 10);
1104 for (int32_t j=0; j < argc; j++)
1105 args[j] = i->arg(j);
1106 return hashcall(i->callInfo(), argc, args);
1108 default:
1109 if (operandCount[op] == 2)
1110 return hash2(op, i->oprnd1(), i->oprnd2());
1111 else
1112 return hash1(op, i->oprnd1());
1116 /*static*/ bool FASTCALL LInsHashSet::equals(LInsp a, LInsp b)
1118 if (a==b)
1119 return true;
1120 if (a->opcode() != b->opcode())
1121 return false;
1122 AvmAssert(a->opcode() == b->opcode());
1123 const LOpcode op = a->opcode();
1124 switch (op)
1126 case LIR_int:
1128 return a->imm32() == b->imm32();
1130 case LIR_quad:
1132 return a->imm64() == b->imm64();
1134 case LIR_call:
1135 case LIR_fcall:
1136 #if defined NANOJIT_64BIT
1137 case LIR_callh:
1138 #endif
1140 if (a->callInfo() != b->callInfo()) return false;
1141 uint32_t argc=a->argc();
1142 NanoAssert(argc == b->argc());
1143 for (uint32_t i=0; i < argc; i++)
1144 if (a->arg(i) != b->arg(i))
1145 return false;
1146 return true;
1148 default:
1150 const uint32_t count = operandCount[op];
1151 if ((count >= 1 && a->oprnd1() != b->oprnd1()) ||
1152 (count >= 2 && a->oprnd2() != b->oprnd2()))
1153 return false;
1154 return true;
1159 void FASTCALL LInsHashSet::grow()
1161 const uint32_t newcap = m_cap << 1;
1162 LInsp *newlist = (LInsp*) m_gc->Alloc(newcap * sizeof(LInsp), GC::kZero);
1163 LInsp *list = m_list;
1164 #ifdef MEMORY_INFO
1165 // newlist.set_meminfo_name("LInsHashSet.list");
1166 #endif
1167 for (uint32_t i=0, n=m_cap; i < n; i++) {
1168 LInsp name = list[i];
1169 if (!name) continue;
1170 uint32_t j = find(name, hashcode(name), newlist, newcap);
1171 newlist[j] = name;
1173 m_cap = newcap;
1174 m_gc->Free(list);
1175 WB(m_gc, this, &m_list, newlist);
1178 uint32_t FASTCALL LInsHashSet::find(LInsp name, uint32_t hash, const LInsp *list, uint32_t cap)
1180 const uint32_t bitmask = (cap - 1) & ~0x1;
1182 uint32_t n = 7 << 1;
1183 hash &= bitmask;
1184 LInsp k;
1185 while ((k = list[hash]) != NULL && !equals(k, name))
1187 hash = (hash + (n += 2)) & bitmask; // quadratic probe
1189 return hash;
1192 LInsp LInsHashSet::add(LInsp name, uint32_t k)
1194 // this is relatively short-lived so let's try a more aggressive load factor
1195 // in the interest of improving performance
1196 if (((m_used+1)<<1) >= m_cap) // 0.50
1198 grow();
1199 k = find(name, hashcode(name), m_list, m_cap);
1201 NanoAssert(!m_list[k]);
1202 m_used++;
1203 return m_list[k] = name;
1206 void LInsHashSet::replace(LInsp i)
1208 LInsp *list = m_list;
1209 uint32_t k = find(i, hashcode(i), list, m_cap);
1210 if (list[k]) {
1211 // already there, so replace it
1212 list[k] = i;
1213 } else {
1214 add(i, k);
1218 uint32_t LInsHashSet::hashimm(int32_t a) {
1219 return _hashfinish(_hash32(0,a));
1222 uint32_t LInsHashSet::hashimmq(uint64_t a) {
1223 uint32_t hash = _hash32(0, uint32_t(a >> 32));
1224 return _hashfinish(_hash32(hash, uint32_t(a)));
1227 uint32_t LInsHashSet::hash1(LOpcode op, LInsp a) {
1228 uint32_t hash = _hash8(0,uint8_t(op));
1229 return _hashfinish(_hashptr(hash, a));
1232 uint32_t LInsHashSet::hash2(LOpcode op, LInsp a, LInsp b) {
1233 uint32_t hash = _hash8(0,uint8_t(op));
1234 hash = _hashptr(hash, a);
1235 return _hashfinish(_hashptr(hash, b));
1238 uint32_t LInsHashSet::hashcall(const CallInfo *ci, uint32_t argc, LInsp args[]) {
1239 uint32_t hash = _hashptr(0, ci);
1240 for (int32_t j=argc-1; j >= 0; j--)
1241 hash = _hashptr(hash,args[j]);
1242 return _hashfinish(hash);
1245 LInsp LInsHashSet::find32(int32_t a, uint32_t &i)
1247 uint32_t cap = m_cap;
1248 const LInsp *list = m_list;
1249 const uint32_t bitmask = (cap - 1) & ~0x1;
1250 uint32_t hash = hashimm(a) & bitmask;
1251 uint32_t n = 7 << 1;
1252 LInsp k;
1253 while ((k = list[hash]) != NULL &&
1254 (!k->isconst() || k->imm32() != a))
1256 hash = (hash + (n += 2)) & bitmask; // quadratic probe
1258 i = hash;
1259 return k;
1262 LInsp LInsHashSet::find64(uint64_t a, uint32_t &i)
1264 uint32_t cap = m_cap;
1265 const LInsp *list = m_list;
1266 const uint32_t bitmask = (cap - 1) & ~0x1;
1267 uint32_t hash = hashimmq(a) & bitmask;
1268 uint32_t n = 7 << 1;
1269 LInsp k;
1270 while ((k = list[hash]) != NULL &&
1271 (!k->isconstq() || k->imm64() != a))
1273 hash = (hash + (n += 2)) & bitmask; // quadratic probe
1275 i = hash;
1276 return k;
1279 LInsp LInsHashSet::find1(LOpcode op, LInsp a, uint32_t &i)
1281 uint32_t cap = m_cap;
1282 const LInsp *list = m_list;
1283 const uint32_t bitmask = (cap - 1) & ~0x1;
1284 uint32_t hash = hash1(op,a) & bitmask;
1285 uint32_t n = 7 << 1;
1286 LInsp k;
1287 while ((k = list[hash]) != NULL &&
1288 (k->opcode() != op || k->oprnd1() != a))
1290 hash = (hash + (n += 2)) & bitmask; // quadratic probe
1292 i = hash;
1293 return k;
1296 LInsp LInsHashSet::find2(LOpcode op, LInsp a, LInsp b, uint32_t &i)
1298 uint32_t cap = m_cap;
1299 const LInsp *list = m_list;
1300 const uint32_t bitmask = (cap - 1) & ~0x1;
1301 uint32_t hash = hash2(op,a,b) & bitmask;
1302 uint32_t n = 7 << 1;
1303 LInsp k;
1304 while ((k = list[hash]) != NULL &&
1305 (k->opcode() != op || k->oprnd1() != a || k->oprnd2() != b))
1307 hash = (hash + (n += 2)) & bitmask; // quadratic probe
1309 i = hash;
1310 return k;
1313 bool argsmatch(LInsp i, uint32_t argc, LInsp args[])
1315 for (uint32_t j=0; j < argc; j++)
1316 if (i->arg(j) != args[j])
1317 return false;
1318 return true;
1321 LInsp LInsHashSet::findcall(const CallInfo *ci, uint32_t argc, LInsp args[], uint32_t &i)
1323 uint32_t cap = m_cap;
1324 const LInsp *list = m_list;
1325 const uint32_t bitmask = (cap - 1) & ~0x1;
1326 uint32_t hash = hashcall(ci, argc, args) & bitmask;
1327 uint32_t n = 7 << 1;
1328 LInsp k;
1329 while ((k = list[hash]) != NULL &&
1330 (!k->isCall() || k->callInfo() != ci || !argsmatch(k, argc, args)))
1332 hash = (hash + (n += 2)) & bitmask; // quadratic probe
1334 i = hash;
1335 return k;
1338 GuardRecord *LIns::record()
1340 NanoAssert(isGuard());
1341 return (GuardRecord*)oprnd2()->payload();
1344 #ifdef NJ_VERBOSE
1345 class RetiredEntry: public GCObject
1347 public:
1348 List<LInsp, LIST_NonGCObjects> live;
1349 LInsp i;
1350 RetiredEntry(GC *gc): live(gc) {}
1352 class LiveTable
1354 public:
1355 SortedMap<LInsp,LInsp,LIST_NonGCObjects> live;
1356 List<RetiredEntry*, LIST_GCObjects> retired;
1357 int maxlive;
1358 LiveTable(GC *gc) : live(gc), retired(gc), maxlive(0) {}
1359 ~LiveTable()
1361 for (size_t i = 0; i < retired.size(); i++) {
1362 NJ_DELETE(retired.get(i));
1366 void add(LInsp i, LInsp use) {
1367 if (!i->isconst() && !i->isconstq() && !live.containsKey(i)) {
1368 NanoAssert(size_t(i->opcode()) < sizeof(lirNames) / sizeof(lirNames[0]));
1369 live.put(i,use);
1372 void retire(LInsp i, GC *gc) {
1373 RetiredEntry *e = NJ_NEW(gc, RetiredEntry)(gc);
1374 e->i = i;
1375 for (int j=0, n=live.size(); j < n; j++) {
1376 LInsp l = live.keyAt(j);
1377 if (!l->isStore() && !l->isGuard())
1378 e->live.add(l);
1380 int size=0;
1381 if ((size = e->live.size()) > maxlive)
1382 maxlive = size;
1384 live.remove(i);
1385 retired.add(e);
1387 bool contains(LInsp i) {
1388 return live.containsKey(i);
1392 void live(GC *gc, LirBuffer *lirbuf)
1394 // traverse backwards to find live exprs and a few other stats.
1396 LiveTable live(gc);
1397 uint32_t exits = 0;
1398 LirReader br(lirbuf);
1399 StackFilter sf(&br, gc, lirbuf, lirbuf->sp);
1400 StackFilter r(&sf, gc, lirbuf, lirbuf->rp);
1401 int total = 0;
1402 if (lirbuf->state)
1403 live.add(lirbuf->state, r.pos());
1404 for (LInsp i = r.read(); i != 0; i = r.read())
1406 total++;
1408 // first handle side-effect instructions
1409 if (!i->isCse(lirbuf->_functions))
1411 live.add(i,0);
1412 if (i->isGuard())
1413 exits++;
1416 // now propagate liveness
1417 if (live.contains(i))
1419 live.retire(i,gc);
1420 NanoAssert(size_t(i->opcode()) < sizeof(operandCount) / sizeof(operandCount[0]));
1421 if (i->isStore()) {
1422 live.add(i->oprnd2(),i); // base
1423 live.add(i->oprnd1(),i); // val
1425 else if (i->isop(LIR_cmov) || i->isop(LIR_qcmov)) {
1426 live.add(i->oprnd1(),i);
1427 live.add(i->oprnd2()->oprnd1(),i);
1428 live.add(i->oprnd2()->oprnd2(),i);
1430 else if (operandCount[i->opcode()] == 1) {
1431 live.add(i->oprnd1(),i);
1433 else if (operandCount[i->opcode()] == 2) {
1434 live.add(i->oprnd1(),i);
1435 live.add(i->oprnd2(),i);
1437 else if (i->isCall()) {
1438 for (int j=0, c=i->argc(); j < c; j++)
1439 live.add(i->arg(j),i);
1444 printf("live instruction count %d, total %u, max pressure %d\n",
1445 live.retired.size(), total, live.maxlive);
1446 printf("side exits %u\n", exits);
1448 // print live exprs, going forwards
1449 LirNameMap *names = lirbuf->names;
1450 bool newblock = true;
1451 for (int j=live.retired.size()-1; j >= 0; j--)
1453 RetiredEntry *e = live.retired[j];
1454 char livebuf[4000], *s=livebuf;
1455 *s = 0;
1456 if (!newblock && e->i->isop(LIR_label)) {
1457 printf("\n");
1459 newblock = false;
1460 for (int k=0,n=e->live.size(); k < n; k++) {
1461 strcpy(s, names->formatRef(e->live[k]));
1462 s += strlen(s);
1463 *s++ = ' '; *s = 0;
1464 NanoAssert(s < livebuf+sizeof(livebuf));
1466 printf("%-60s %s\n", livebuf, names->formatIns(e->i));
1467 if (e->i->isGuard() || e->i->isBranch() || isRet(e->i->opcode())) {
1468 printf("\n");
1469 newblock = true;
1474 LabelMap::Entry::~Entry()
1478 LirNameMap::Entry::~Entry()
1482 LirNameMap::~LirNameMap()
1484 Entry *e;
1486 while ((e = names.removeLast()) != NULL) {
1487 labels->core->freeString(e->name);
1488 NJ_DELETE(e);
1492 bool LirNameMap::addName(LInsp i, Stringp name) {
1493 if (!names.containsKey(i)) {
1494 Entry *e = NJ_NEW(labels->core->gc, Entry)(name);
1495 names.put(i, e);
1496 return true;
1498 return false;
1500 void LirNameMap::addName(LInsp i, const char *name) {
1501 Stringp new_name = labels->core->newString(name);
1502 if (!addName(i, new_name)) {
1503 labels->core->freeString(new_name);
1507 void LirNameMap::copyName(LInsp i, const char *s, int suffix) {
1508 char s2[200];
1509 if (isdigit(s[strlen(s)-1])) {
1510 // if s ends with a digit, add '_' to clarify the suffix
1511 sprintf(s2,"%s_%d", s, suffix);
1512 } else {
1513 sprintf(s2,"%s%d", s, suffix);
1515 addName(i, labels->core->newString(s2));
1518 void LirNameMap::formatImm(int32_t c, char *buf) {
1519 if (c >= 10000 || c <= -10000)
1520 sprintf(buf,"#%s",labels->format((void*)c));
1521 else
1522 sprintf(buf,"%d", c);
1525 const char* LirNameMap::formatRef(LIns *ref)
1527 char buffer[200], *buf=buffer;
1528 buf[0]=0;
1529 GC *gc = labels->core->gc;
1530 if (names.containsKey(ref)) {
1531 StringNullTerminatedUTF8 cname(gc, names.get(ref)->name);
1532 strcat(buf, cname.c_str());
1534 else if (ref->isconstq()) {
1535 #if defined NANOJIT_64BIT
1536 sprintf(buf, "#0x%lx", (nj_printf_ld)ref->imm64());
1537 #else
1538 formatImm(uint32_t(ref->imm64()>>32), buf);
1539 buf += strlen(buf);
1540 *buf++ = ':';
1541 formatImm(uint32_t(ref->imm64()), buf);
1542 #endif
1544 else if (ref->isconst()) {
1545 formatImm(ref->imm32(), buf);
1547 else {
1548 if (ref->isCall()) {
1549 #if !defined NANOJIT_64BIT
1550 if (ref->isop(LIR_callh)) {
1551 // we've presumably seen the other half already
1552 ref = ref->oprnd1();
1553 } else {
1554 #endif
1555 copyName(ref, ref->callInfo()->_name, funccounts.add(ref->callInfo()));
1556 #if !defined NANOJIT_64BIT
1558 #endif
1559 } else {
1560 NanoAssert(size_t(ref->opcode()) < sizeof(lirNames) / sizeof(lirNames[0]));
1561 copyName(ref, lirNames[ref->opcode()], lircounts.add(ref->opcode()));
1563 StringNullTerminatedUTF8 cname(gc, names.get(ref)->name);
1564 strcat(buf, cname.c_str());
1566 return labels->dup(buffer);
1569 const char* LirNameMap::formatIns(LIns* i)
1571 char sbuf[200];
1572 char *s = sbuf;
1573 LOpcode op = i->opcode();
1574 switch(op)
1576 case LIR_int:
1578 sprintf(s, "%s", formatRef(i));
1579 break;
1582 case LIR_alloc: {
1583 sprintf(s, "%s = %s %d", formatRef(i), lirNames[op], i->size());
1584 break;
1587 case LIR_quad:
1589 sprintf(s, "#%X:%X /* %g */", i->imm64_1(), i->imm64_0(), i->imm64f());
1590 break;
1593 case LIR_loop:
1594 case LIR_start:
1595 sprintf(s, "%s", lirNames[op]);
1596 break;
1598 #if defined NANOJIT_64BIT
1599 case LIR_callh:
1600 #endif
1601 case LIR_fcall:
1602 case LIR_call: {
1603 sprintf(s, "%s = %s ( ", formatRef(i), i->callInfo()->_name);
1604 for (int32_t j=i->argc()-1; j >= 0; j--) {
1605 s += strlen(s);
1606 sprintf(s, "%s ",formatRef(i->arg(j)));
1608 s += strlen(s);
1609 sprintf(s, ")");
1610 break;
1612 case LIR_fcalli:
1613 case LIR_calli: {
1614 int32_t argc = i->argc();
1615 sprintf(s, "%s = [%s] ( ", formatRef(i), formatRef(i->arg(argc-1)));
1616 s += strlen(s);
1617 argc--;
1618 for (int32_t j=argc-1; j >= 0; j--) {
1619 s += strlen(s);
1620 sprintf(s, "%s ",formatRef(i->arg(j)));
1622 s += strlen(s);
1623 sprintf(s, ")");
1624 break;
1627 case LIR_param: {
1628 uint32_t arg = i->imm8();
1629 if (!i->imm8b()) {
1630 if (arg < sizeof(Assembler::argRegs)/sizeof(Assembler::argRegs[0])) {
1631 sprintf(s, "%s = %s %d %s", formatRef(i), lirNames[op],
1632 arg, gpn(Assembler::argRegs[arg]));
1633 } else {
1634 sprintf(s, "%s = %s %d", formatRef(i), lirNames[op], arg);
1636 } else {
1637 sprintf(s, "%s = %s %d %s", formatRef(i), lirNames[op],
1638 arg, gpn(Assembler::savedRegs[arg]));
1640 break;
1643 case LIR_label:
1644 sprintf(s, "%s:", formatRef(i));
1645 break;
1647 case LIR_jt:
1648 case LIR_jf:
1649 sprintf(s, "%s %s -> %s", lirNames[op], formatRef(i->oprnd1()),
1650 i->oprnd2() ? formatRef(i->oprnd2()) : "unpatched");
1651 break;
1653 case LIR_j:
1654 sprintf(s, "%s -> %s", lirNames[op],
1655 i->oprnd2() ? formatRef(i->oprnd2()) : "unpatched");
1656 break;
1658 case LIR_live:
1659 case LIR_ret:
1660 case LIR_fret:
1661 sprintf(s, "%s %s", lirNames[op], formatRef(i->oprnd1()));
1662 break;
1664 case LIR_callh:
1665 case LIR_neg:
1666 case LIR_fneg:
1667 case LIR_i2f:
1668 case LIR_u2f:
1669 case LIR_qlo:
1670 case LIR_qhi:
1671 case LIR_ov:
1672 case LIR_cs:
1673 case LIR_not:
1674 sprintf(s, "%s = %s %s", formatRef(i), lirNames[op], formatRef(i->oprnd1()));
1675 break;
1677 case LIR_x:
1678 case LIR_xt:
1679 case LIR_xf:
1680 case LIR_xbarrier:
1681 case LIR_xtbl:
1682 formatGuard(i, s);
1683 break;
1685 case LIR_add:
1686 case LIR_addp:
1687 case LIR_sub:
1688 case LIR_mul:
1689 case LIR_fadd:
1690 case LIR_fsub:
1691 case LIR_fmul:
1692 case LIR_fdiv:
1693 case LIR_and:
1694 case LIR_or:
1695 case LIR_xor:
1696 case LIR_lsh:
1697 case LIR_rsh:
1698 case LIR_ush:
1699 case LIR_eq:
1700 case LIR_lt:
1701 case LIR_le:
1702 case LIR_gt:
1703 case LIR_ge:
1704 case LIR_ult:
1705 case LIR_ule:
1706 case LIR_ugt:
1707 case LIR_uge:
1708 case LIR_feq:
1709 case LIR_flt:
1710 case LIR_fle:
1711 case LIR_fgt:
1712 case LIR_fge:
1713 case LIR_qiadd:
1714 case LIR_qiand:
1715 case LIR_qilsh:
1716 case LIR_qior:
1717 sprintf(s, "%s = %s %s, %s", formatRef(i), lirNames[op],
1718 formatRef(i->oprnd1()),
1719 formatRef(i->oprnd2()));
1720 break;
1722 case LIR_qjoin:
1723 sprintf(s, "%s (%s), %s", lirNames[op],
1724 formatIns(i->oprnd1()),
1725 formatRef(i->oprnd2()));
1726 break;
1728 case LIR_qcmov:
1729 case LIR_cmov:
1730 sprintf(s, "%s = %s %s ? %s : %s", formatRef(i), lirNames[op],
1731 formatRef(i->oprnd1()),
1732 formatRef(i->oprnd2()->oprnd1()),
1733 formatRef(i->oprnd2()->oprnd2()));
1734 break;
1736 case LIR_ld:
1737 case LIR_ldc:
1738 case LIR_ldq:
1739 case LIR_ldqc:
1740 case LIR_ldcb:
1741 case LIR_ldcs:
1742 sprintf(s, "%s = %s %s[%s]", formatRef(i), lirNames[op],
1743 formatRef(i->oprnd1()),
1744 formatRef(i->oprnd2()));
1745 break;
1747 case LIR_sti:
1748 case LIR_stqi:
1749 sprintf(s, "%s %s[%d] = %s", lirNames[op],
1750 formatRef(i->oprnd2()),
1751 i->immdisp(),
1752 formatRef(i->oprnd1()));
1753 break;
1755 default:
1756 sprintf(s, "?");
1757 break;
1759 return labels->dup(sbuf);
1763 #endif
1764 CseFilter::CseFilter(LirWriter *out, GC *gc)
1765 : LirWriter(out), exprs(gc) {}
1767 LIns* CseFilter::insImm(int32_t imm)
1769 uint32_t k;
1770 LInsp found = exprs.find32(imm, k);
1771 if (found)
1772 return found;
1773 return exprs.add(out->insImm(imm), k);
1776 LIns* CseFilter::insImmq(uint64_t q)
1778 uint32_t k;
1779 LInsp found = exprs.find64(q, k);
1780 if (found)
1781 return found;
1782 return exprs.add(out->insImmq(q), k);
1785 LIns* CseFilter::ins0(LOpcode v)
1787 if (v == LIR_label)
1788 exprs.clear();
1789 return out->ins0(v);
1792 LIns* CseFilter::ins1(LOpcode v, LInsp a)
1794 if (isCse(v)) {
1795 NanoAssert(operandCount[v]==1);
1796 uint32_t k;
1797 LInsp found = exprs.find1(v, a, k);
1798 if (found)
1799 return found;
1800 return exprs.add(out->ins1(v,a), k);
1802 return out->ins1(v,a);
1805 LIns* CseFilter::ins2(LOpcode v, LInsp a, LInsp b)
1807 if (isCse(v)) {
1808 NanoAssert(operandCount[v]==2);
1809 uint32_t k;
1810 LInsp found = exprs.find2(v, a, b, k);
1811 if (found)
1812 return found;
1813 return exprs.add(out->ins2(v,a,b), k);
1815 return out->ins2(v,a,b);
1818 LIns* CseFilter::insLoad(LOpcode v, LInsp base, LInsp disp)
1820 if (isCse(v)) {
1821 NanoAssert(operandCount[v]==2);
1822 uint32_t k;
1823 LInsp found = exprs.find2(v, base, disp, k);
1824 if (found)
1825 return found;
1826 return exprs.add(out->insLoad(v,base,disp), k);
1828 return out->insLoad(v,base,disp);
1831 LInsp CseFilter::insGuard(LOpcode v, LInsp c, LInsp x)
1833 if (isCse(v)) {
1834 // conditional guard
1835 NanoAssert(operandCount[v]==1);
1836 uint32_t k;
1837 LInsp found = exprs.find1(v, c, k);
1838 if (found)
1839 return 0;
1840 return exprs.add(out->insGuard(v,c,x), k);
1842 return out->insGuard(v, c, x);
1845 LInsp CseFilter::insCall(const CallInfo *ci, LInsp args[])
1847 if (ci->_cse) {
1848 uint32_t k;
1849 uint32_t argc = ci->count_args();
1850 LInsp found = exprs.findcall(ci, argc, args, k);
1851 if (found)
1852 return found;
1853 return exprs.add(out->insCall(ci, args), k);
1855 return out->insCall(ci, args);
1858 CseReader::CseReader(LirFilter *in, LInsHashSet *exprs, const CallInfo *functions)
1859 : LirFilter(in), exprs(exprs), functions(functions)
1862 LInsp CseReader::read()
1864 LInsp i = in->read();
1865 if (i) {
1866 if (i->isCse(functions))
1867 exprs->replace(i);
1869 return i;
1872 LIns* FASTCALL callArgN(LIns* i, uint32_t n)
1874 return i->arg(i->argc()-n-1);
1877 void compile(Assembler* assm, Fragment* triggerFrag)
1879 Fragmento *frago = triggerFrag->lirbuf->_frago;
1880 AvmCore *core = frago->core();
1881 GC *gc = core->gc;
1883 verbose_only( StringList asmOutput(gc); )
1884 verbose_only( assm->_outputCache = &asmOutput; )
1886 verbose_only(if (assm->_verbose && core->config.verbose_live)
1887 live(gc, triggerFrag->lirbuf);)
1889 bool treeCompile = core->config.tree_opt && (triggerFrag->kind == BranchTrace);
1890 RegAllocMap regMap(gc);
1891 NInsList loopJumps(gc);
1892 #ifdef MEMORY_INFO
1893 // loopJumps.set_meminfo_name("LIR loopjumps");
1894 #endif
1895 assm->beginAssembly(triggerFrag, &regMap);
1896 if (assm->error())
1897 return;
1899 //fprintf(stderr, "recompile trigger %X kind %d\n", (int)triggerFrag, triggerFrag->kind);
1900 Fragment* root = triggerFrag;
1901 if (treeCompile)
1903 // recompile the entire tree
1904 root = triggerFrag->root;
1905 root->fragEntry = 0;
1906 root->loopEntry = 0;
1907 root->releaseCode(frago);
1909 // do the tree branches
1910 Fragment* frag = root->treeBranches;
1911 while(frag)
1913 // compile til no more frags
1914 if (frag->lastIns)
1916 assm->assemble(frag, loopJumps);
1917 verbose_only(if (assm->_verbose)
1918 assm->outputf("compiling branch %s ip %s",
1919 frago->labels->format(frag),
1920 frago->labels->format(frag->ip)); )
1922 NanoAssert(frag->kind == BranchTrace);
1923 RegAlloc* regs = NJ_NEW(gc, RegAlloc)();
1924 assm->copyRegisters(regs);
1925 assm->releaseRegisters();
1926 SideExit* exit = frag->spawnedFrom;
1927 regMap.put(exit, regs);
1929 frag = frag->treeBranches;
1933 // now the the main trunk
1934 assm->assemble(root, loopJumps);
1935 verbose_only(if (assm->_verbose)
1936 assm->outputf("compiling trunk %s",
1937 frago->labels->format(root));)
1938 NanoAssert(!frago->core()->config.tree_opt || root == root->anchor || root->kind == MergeTrace);
1939 assm->endAssembly(root, loopJumps);
1941 // reverse output so that assembly is displayed low-to-high
1942 verbose_only( assm->_outputCache = 0; )
1943 verbose_only(for(int i=asmOutput.size()-1; i>=0; --i) { assm->outputf("%s",asmOutput.get(i)); } );
1945 if (assm->error()) {
1946 root->fragEntry = 0;
1947 root->loopEntry = 0;
1951 LInsp LoadFilter::insLoad(LOpcode v, LInsp base, LInsp disp)
1953 if (base != sp && base != rp && (v == LIR_ld || v == LIR_ldq)) {
1954 uint32_t k;
1955 LInsp found = exprs.find2(v, base, disp, k);
1956 if (found)
1957 return found;
1958 return exprs.add(out->insLoad(v,base,disp), k);
1960 return out->insLoad(v, base, disp);
1963 void LoadFilter::clear(LInsp p)
1965 if (p != sp && p != rp)
1966 exprs.clear();
1969 LInsp LoadFilter::insStorei(LInsp v, LInsp b, int32_t d)
1971 clear(b);
1972 return out->insStorei(v, b, d);
1975 LInsp LoadFilter::insCall(const CallInfo *ci, LInsp args[])
1977 if (!ci->_cse)
1978 exprs.clear();
1979 return out->insCall(ci, args);
1982 LInsp LoadFilter::ins0(LOpcode op)
1984 if (op == LIR_label)
1985 exprs.clear();
1986 return out->ins0(op);
1989 #endif /* FEATURE_NANOJIT */
1991 #if defined(NJ_VERBOSE)
1992 LabelMap::LabelMap(AvmCore *core, LabelMap* parent)
1993 : parent(parent), names(core->gc), addrs(core->config.verbose_addrs), end(buf), core(core)
1996 LabelMap::~LabelMap()
1998 clear();
2001 void LabelMap::clear()
2003 Entry *e;
2004 while ((e = names.removeLast()) != NULL) {
2005 core->freeString(e->name);
2006 NJ_DELETE(e);
2010 void LabelMap::add(const void *p, size_t size, size_t align, const char *name)
2012 if (!this || names.containsKey(p))
2013 return;
2014 add(p, size, align, core->newString(name));
2017 void LabelMap::add(const void *p, size_t size, size_t align, Stringp name)
2019 if (!this || names.containsKey(p))
2020 return;
2021 Entry *e = NJ_NEW(core->gc, Entry)(name, size<<align, align);
2022 names.put(p, e);
2025 const char *LabelMap::format(const void *p)
2027 char b[200];
2028 int i = names.findNear(p);
2029 if (i >= 0) {
2030 const void *start = names.keyAt(i);
2031 Entry *e = names.at(i);
2032 const void *end = (const char*)start + e->size;
2033 avmplus::StringNullTerminatedUTF8 cname(core->gc, e->name);
2034 const char *name = cname.c_str();
2035 if (p == start) {
2036 if (addrs)
2037 sprintf(b,"%p %s",p,name);
2038 else
2039 strcpy(b, name);
2040 return dup(b);
2042 else if (p > start && p < end) {
2043 int32_t d = int32_t(intptr_t(p)-intptr_t(start)) >> e->align;
2044 if (addrs)
2045 sprintf(b, "%p %s+%d", p, name, d);
2046 else
2047 sprintf(b,"%s+%d", name, d);
2048 return dup(b);
2050 else {
2051 if (parent)
2052 return parent->format(p);
2054 sprintf(b, "%p", p);
2055 return dup(b);
2058 if (parent)
2059 return parent->format(p);
2061 sprintf(b, "%p", p);
2062 return dup(b);
2065 const char *LabelMap::dup(const char *b)
2067 size_t need = strlen(b)+1;
2068 char *s = end;
2069 end += need;
2070 if (end > buf+sizeof(buf)) {
2071 s = buf;
2072 end = s+need;
2074 strcpy(s, b);
2075 return s;
2078 // copy all labels to parent, adding newbase to label addresses
2079 void LabelMap::promoteAll(const void *newbase)
2081 for (int i=0, n=names.size(); i < n; i++) {
2082 void *base = (char*)newbase + (intptr_t)names.keyAt(i);
2083 parent->names.put(base, names.at(i));
2086 #endif // NJ_VERBOSE