2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-2014 Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
17 #include "hphp/runtime/vm/jit/ir-unit.h"
19 #include "hphp/runtime/vm/jit/block.h"
20 #include "hphp/runtime/vm/jit/cfg.h"
21 #include "hphp/runtime/vm/jit/frame-state.h"
22 #include "hphp/runtime/vm/jit/mc-generator.h"
23 #include "hphp/runtime/vm/jit/timer.h"
25 namespace HPHP
{ namespace jit
{
26 ///////////////////////////////////////////////////////////////////////////////
30 ///////////////////////////////////////////////////////////////////////////////
32 IRUnit::IRUnit(TransContext context
)
37 IRInstruction
* IRUnit::defLabel(unsigned numDst
, BCMarker marker
) {
38 IRInstruction
inst(DefLabel
, marker
);
39 auto const label
= clone(&inst
);
41 auto const dstsPtr
= new (m_arena
) SSATmp
*[numDst
];
42 for (unsigned i
= 0; i
< numDst
; ++i
) {
43 dstsPtr
[i
] = newSSATmp(label
);
45 label
->setDsts(numDst
, dstsPtr
);
50 void IRUnit::expandLabel(IRInstruction
* label
, unsigned extraDst
) {
51 assertx(label
->is(DefLabel
));
52 assertx(extraDst
> 0);
53 auto const dstsPtr
= new (m_arena
) SSATmp
*[extraDst
+ label
->numDsts()];
55 for (auto dst
: label
->dsts()) {
58 for (unsigned j
= 0; j
< extraDst
; j
++) {
59 dstsPtr
[i
++] = newSSATmp(label
);
61 label
->setDsts(i
, dstsPtr
);
64 void IRUnit::expandJmp(IRInstruction
* jmp
, SSATmp
* value
) {
65 assertx(jmp
->is(Jmp
));
66 std::vector
<SSATmp
*> newSrcs(jmp
->numSrcs() + 1);
68 for (auto src
: jmp
->srcs()) {
72 replace(jmp
, Jmp
, jmp
->taken(), std::make_pair(i
, &newSrcs
[0]));
75 Block
* IRUnit::defBlock(Block::Hint hint
) {
76 FTRACE(2, "IRUnit defining B{}\n", m_nextBlockId
);
77 auto const block
= new (m_arena
) Block(m_nextBlockId
++);
82 SSATmp
* IRUnit::cns(Type type
) {
83 assertx(type
.hasConstVal() ||
84 type
.subtypeOfAny(TUninit
, TInitNull
, TNullptr
));
85 IRInstruction
inst(DefConst
, BCMarker
{});
86 inst
.setTypeParam(type
);
87 if (SSATmp
* tmp
= m_constTable
.lookup(&inst
)) {
88 assertx(tmp
->type() == type
);
91 return m_constTable
.insert(clone(&inst
)->dst());
94 ///////////////////////////////////////////////////////////////////////////////
97 * Returns true iff `block' ends the IR unit after finishing execution
98 * of the bytecode instruction at `sk'.
100 static bool endsUnitAtSrcKey(const Block
* block
, SrcKey sk
) {
101 if (!block
->isExitNoThrow()) return false;
103 const auto& inst
= block
->back();
104 const auto instSk
= inst
.marker().sk();
107 // These instructions end a unit after executing the bytecode
108 // instruction they correspond to.
113 return instSk
== sk
;;
115 // The RetCtrl is generally ending a bytecode instruction, with the
116 // exception being in an Await bytecode instruction, where we consider the
117 // end of the bytecode instruction to be the non-suspending path.
120 return inst
.marker().sk().op() != Op::Await
;
122 // A ReqBindJmp ends a unit and it jumps to the next instruction
125 auto destOffset
= inst
.extra
<ReqBindJmp
>()->dest
.offset();
126 return sk
.succOffsets().count(destOffset
);
134 Block
* findMainExitBlock(const IRUnit
& unit
, SrcKey lastSk
) {
135 Block
* mainExit
= nullptr;
137 FTRACE(5, "findMainExitBlock: starting on unit:\n{}\n", show(unit
));
139 for (auto block
: rpoSortCfg(unit
)) {
140 if (endsUnitAtSrcKey(block
, lastSk
)) {
141 if (mainExit
== nullptr) {
147 mainExit
->hint() == Block::Hint::Unlikely
||
148 block
->hint() == Block::Hint::Unlikely
,
149 "findMainExit: 2 likely exits found: B{} and B{}\nlastSk = {}",
150 mainExit
->id(), block
->id(), showShort(lastSk
));
152 if (mainExit
->hint() == Block::Hint::Unlikely
) mainExit
= block
;
156 always_assert_flog(mainExit
, "findMainExit: no exit found for lastSk = {}",
159 FTRACE(5, "findMainExitBlock: mainExit = B{}\n", mainExit
->id());
164 ///////////////////////////////////////////////////////////////////////////////