Move unique stubs to unique-stubs-resumable.cpp
[hiphop-php.git] / hphp / runtime / vm / jit / irlower-intrinsic.cpp
blob2bec1cefcd58f1c78a8ce75d487c02bb1732f2d6
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
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();
68 auto& v = vmain(env);
70 if (inst->marker().resumeMode() != ResumeMode::None) {
71 v << defvmsp{sp};
72 return;
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();
83 auto& v = vmain(env);
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*/) {
98 vmain(env) << ud2{};
101 void cgEndBlock(IRLS& env, const IRInstruction* /*inst*/) {
102 vmain(env) << ud2{};
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)
115 .ssa(1)
116 .addr(sp, cellsToBytes(extra->spOffset.offset))
117 .imm(extra->bcOff);
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)
158 .imm(extra->type)
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())
172 .imm(extra->type);
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}};
207 v = 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())}};
215 } else {
216 v << jcc{CC_LE, sf, {label(env, inst->next()), label(env, inst->taken())}};
220 ///////////////////////////////////////////////////////////////////////////////