Switch-related cleanup
[hiphop-php.git] / hphp / runtime / vm / jit / ir-unit.cpp
blob9c8549b1c42246ce43996118d4c171b1e4df96f1
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
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 ///////////////////////////////////////////////////////////////////////////////
28 TRACE_SET_MOD(hhir);
30 ///////////////////////////////////////////////////////////////////////////////
32 IRUnit::IRUnit(TransContext context)
33 : m_context(context)
34 , m_entry(defBlock())
37 IRInstruction* IRUnit::defLabel(unsigned numDst, BCMarker marker) {
38 IRInstruction inst(DefLabel, marker);
39 auto const label = clone(&inst);
40 if (numDst > 0) {
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);
47 return label;
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()];
54 unsigned i = 0;
55 for (auto dst : label->dsts()) {
56 dstsPtr[i++] = dst;
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);
67 size_t i = 0;
68 for (auto src : jmp->srcs()) {
69 newSrcs[i++] = src;
71 newSrcs[i++] = value;
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++);
78 block->setHint(hint);
79 return block;
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);
89 return tmp;
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();
106 switch (inst.op()) {
107 // These instructions end a unit after executing the bytecode
108 // instruction they correspond to.
109 case InterpOneCF:
110 case JmpSSwitchDest:
111 case JmpSwitchDest:
112 case RaiseError:
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.
118 case RetCtrl:
119 case AsyncRetCtrl:
120 return inst.marker().sk().op() != Op::Await;
122 // A ReqBindJmp ends a unit and it jumps to the next instruction
123 // to execute.
124 case ReqBindJmp: {
125 auto destOffset = inst.extra<ReqBindJmp>()->dest.offset();
126 return sk.succOffsets().count(destOffset);
129 default:
130 return false;
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) {
142 mainExit = block;
143 continue;
146 always_assert_flog(
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 = {}",
157 showShort(lastSk));
159 FTRACE(5, "findMainExitBlock: mainExit = B{}\n", mainExit->id());
161 return mainExit;
164 ///////////////////////////////////////////////////////////////////////////////