2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present 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/irlower-internal.h"
19 #include "hphp/runtime/base/stats.h"
20 #include "hphp/runtime/base/string-data.h"
21 #include "hphp/runtime/vm/bytecode.h"
22 #include "hphp/runtime/vm/resumable.h"
23 #include "hphp/runtime/vm/srckey.h"
25 #include "hphp/runtime/vm/jit/abi.h"
26 #include "hphp/runtime/vm/jit/arg-group.h"
27 #include "hphp/runtime/vm/jit/bc-marker.h"
28 #include "hphp/runtime/vm/jit/call-spec.h"
29 #include "hphp/runtime/vm/jit/code-gen-helpers.h"
30 #include "hphp/runtime/vm/jit/extra-data.h"
31 #include "hphp/runtime/vm/jit/ir-instruction.h"
32 #include "hphp/runtime/vm/jit/ir-opcode.h"
33 #include "hphp/runtime/vm/jit/prof-data.h"
34 #include "hphp/runtime/vm/jit/ssa-tmp.h"
35 #include "hphp/runtime/vm/jit/tc.h"
36 #include "hphp/runtime/vm/jit/translator-inline.h"
37 #include "hphp/runtime/vm/jit/types.h"
38 #include "hphp/runtime/vm/jit/unique-stubs.h"
39 #include "hphp/runtime/vm/jit/vasm-gen.h"
40 #include "hphp/runtime/vm/jit/vasm-instr.h"
41 #include "hphp/runtime/vm/jit/vasm-reg.h"
42 #include "hphp/runtime/vm/jit/write-lease.h"
44 #include "hphp/util/trace.h"
46 namespace HPHP
{ namespace jit
{ namespace irlower
{
48 TRACE_SET_MOD(irlower
);
50 ///////////////////////////////////////////////////////////////////////////////
52 void cgNop(IRLS
&, const IRInstruction
*) {}
53 void cgDefConst(IRLS
&, const IRInstruction
*) {}
54 void cgEndGuards(IRLS
&, const IRInstruction
*) {}
55 void cgExitPlaceholder(IRLS
&, const IRInstruction
*) {}
57 ///////////////////////////////////////////////////////////////////////////////
59 void cgFuncGuard(IRLS
& env
, const IRInstruction
* inst
) {
60 auto const extra
= inst
->extra
<FuncGuard
>();
61 vmain(env
) << funcguard
{extra
->func
, extra
->prologueAddrPtr
};
64 void cgDefFP(IRLS
&, const IRInstruction
*) {}
66 void cgDefSP(IRLS
& env
, const IRInstruction
* inst
) {
67 auto const sp
= dstLoc(env
, inst
, 0).reg();
70 if (inst
->marker().resumeMode() != ResumeMode::None
) {
75 auto const fp
= srcLoc(env
, inst
, 0).reg();
76 v
<< lea
{fp
[-cellsToBytes(inst
->extra
<DefSP
>()->offset
.offset
)], sp
};
79 void cgEagerSyncVMRegs(IRLS
& env
, const IRInstruction
* inst
) {
80 auto const extra
= inst
->extra
<EagerSyncVMRegs
>();
81 auto const fp
= srcLoc(env
, inst
, 0).reg();
82 auto const sp
= srcLoc(env
, inst
, 1).reg();
85 auto const sync_sp
= v
.makeReg();
86 v
<< lea
{sp
[cellsToBytes(extra
->offset
.offset
)], sync_sp
};
87 emitEagerSyncPoint(v
, inst
->marker().fixupSk().pc(), rvmtl(), fp
, sync_sp
);
90 void cgMov(IRLS
& env
, const IRInstruction
* inst
) {
91 auto const dst
= dstLoc(env
, inst
, 0);
92 auto const src
= srcLoc(env
, inst
, 0);
93 always_assert(inst
->src(0)->numWords() == inst
->dst(0)->numWords());
94 copyTV(vmain(env
), src
, dst
, inst
->dst()->type());
97 void cgUnreachable(IRLS
& env
, const IRInstruction
* /*inst*/) {
101 void cgEndBlock(IRLS
& env
, const IRInstruction
* /*inst*/) {
105 ///////////////////////////////////////////////////////////////////////////////
107 void cgInterpOne(IRLS
& env
, const IRInstruction
* inst
) {
108 auto const extra
= inst
->extra
<InterpOne
>();
109 auto const sp
= srcLoc(env
, inst
, 0).reg();
111 // Did you forget to specify ControlFlowInfo?
112 assertx(!instrIsControlFlow(extra
->opcode
));
113 auto const helper
= interpOneEntryPoints
[size_t(extra
->opcode
)];
114 auto const args
= argGroup(env
, inst
)
116 .addr(sp
, cellsToBytes(extra
->spOffset
.offset
))
119 // Call the interpOne##Op() routine, which syncs VM regs manually.
120 cgCallHelper(vmain(env
), env
, CallSpec::direct(helper
),
121 kVoidDest
, SyncOptions::None
, args
);
124 void cgInterpOneCF(IRLS
& env
, const IRInstruction
* inst
) {
125 auto const extra
= inst
->extra
<InterpOneCF
>();
126 auto const sp
= srcLoc(env
, inst
, 0).reg();
127 auto& v
= vmain(env
);
129 auto const sync_sp
= v
.makeReg();
130 v
<< lea
{sp
[cellsToBytes(extra
->spOffset
.offset
)], sync_sp
};
131 v
<< syncvmsp
{sync_sp
};
133 assertx(tc::ustubs().interpOneCFHelpers
.count(extra
->opcode
));
135 // We pass the Offset in the third argument register.
136 v
<< ldimml
{extra
->bcOff
, rarg(2)};
137 v
<< jmpi
{tc::ustubs().interpOneCFHelpers
.at(extra
->opcode
),
138 interp_one_cf_regs()};
141 ///////////////////////////////////////////////////////////////////////////////
143 IMPL_OPCODE_CALL(GetTime
);
144 IMPL_OPCODE_CALL(GetTimeNs
);
146 ///////////////////////////////////////////////////////////////////////////////
148 IMPL_OPCODE_CALL(PrintBool
)
149 IMPL_OPCODE_CALL(PrintInt
)
150 IMPL_OPCODE_CALL(PrintStr
)
152 IMPL_OPCODE_CALL(GetMemoKey
)
154 void cgRBTraceEntry(IRLS
& env
, const IRInstruction
* inst
) {
155 auto const extra
= inst
->extra
<RBTraceEntry
>();
157 auto const args
= argGroup(env
, inst
)
159 .imm(extra
->sk
.toAtomicInt());
161 cgCallHelper(vmain(env
), env
, CallSpec::direct(Trace::ringbufferEntryRip
),
162 kVoidDest
, SyncOptions::None
, args
);
165 void cgRBTraceMsg(IRLS
& env
, const IRInstruction
* inst
) {
166 auto const extra
= inst
->extra
<RBTraceMsg
>();
167 assertx(extra
->msg
->isStatic());
169 auto const args
= argGroup(env
, inst
)
170 .immPtr(extra
->msg
->data())
171 .imm(extra
->msg
->size())
174 cgCallHelper(vmain(env
), env
, CallSpec::direct(Trace::ringbufferMsg
),
175 kVoidDest
, SyncOptions::None
, args
);
178 ///////////////////////////////////////////////////////////////////////////////
180 void cgIncStat(IRLS
& env
, const IRInstruction
*inst
) {
181 auto const stat
= Stats::StatCounter(inst
->src(0)->intVal());
182 auto const n
= inst
->src(1)->intVal();
183 auto const force
= inst
->src(2)->boolVal();
184 emitIncStat(vmain(env
), stat
, n
, force
);
187 IMPL_OPCODE_CALL(IncStatGrouped
)
189 void cgIncProfCounter(IRLS
& env
, const IRInstruction
* inst
) {
190 auto const transID
= inst
->extra
<TransIDData
>()->transId
;
191 auto const counterAddr
= profData()->transCounterAddr(transID
);
192 auto& v
= vmain(env
);
194 v
<< decqmlock
{v
.cns(counterAddr
)[0], v
.makeReg()};
197 void cgCheckCold(IRLS
& env
, const IRInstruction
* inst
) {
198 auto const transID
= inst
->extra
<CheckCold
>()->transId
;
199 auto const counterAddr
= profData()->transCounterAddr(transID
);
200 auto& v
= vmain(env
);
202 auto const sf
= v
.makeReg();
203 v
<< decqmlock
{v
.cns(counterAddr
)[0], sf
};
204 if (RuntimeOption::EvalJitFilterLease
) {
205 auto filter
= v
.makeBlock();
206 v
<< jcc
{CC_LE
, sf
, {label(env
, inst
->next()), filter
}};
208 auto const res
= v
.makeReg();
209 cgCallHelper(v
, env
, CallSpec::direct(couldAcquireOptimizeLease
),
210 callDest(res
), SyncOptions::None
,
211 argGroup(env
, inst
).immPtr(inst
->func()));
212 auto const sf2
= v
.makeReg();
213 v
<< testb
{res
, res
, sf2
};
214 v
<< jcc
{CC_NZ
, sf2
, {label(env
, inst
->next()), label(env
, inst
->taken())}};
216 v
<< jcc
{CC_LE
, sf
, {label(env
, inst
->next()), label(env
, inst
->taken())}};
220 ///////////////////////////////////////////////////////////////////////////////