Add `recordbasenativesp` instr and support it in vasm-xls
[hiphop-php.git] / hphp / runtime / vm / jit / irlower.cpp
blob5a6d1576d0269f582c3b87e2ee2e1f113a728ceb
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.h"
18 #include "hphp/runtime/vm/jit/irlower-internal.h"
20 #include "hphp/runtime/base/perf-warning.h"
21 #include "hphp/runtime/base/runtime-option.h"
22 #include "hphp/runtime/base/tracing.h"
24 #include "hphp/runtime/vm/jit/types.h"
25 #include "hphp/runtime/vm/jit/abi.h"
26 #include "hphp/runtime/vm/jit/cfg.h"
27 #include "hphp/runtime/vm/jit/containers.h"
28 #include "hphp/runtime/vm/jit/ir-instruction.h"
29 #include "hphp/runtime/vm/jit/ir-unit.h"
30 #include "hphp/runtime/vm/jit/print.h"
31 #include "hphp/runtime/vm/jit/punt.h"
32 #include "hphp/runtime/vm/jit/timer.h"
33 #include "hphp/runtime/vm/jit/vasm-emit.h"
34 #include "hphp/runtime/vm/jit/vasm-gen.h"
35 #include "hphp/runtime/vm/jit/vasm-print.h"
36 #include "hphp/runtime/vm/jit/vasm-unit.h"
38 #include "hphp/util/arch.h"
39 #include "hphp/util/assertions.h"
40 #include "hphp/util/trace.h"
42 #include <folly/Format.h>
43 #include <folly/Range.h>
45 #include <sstream>
47 namespace HPHP { namespace jit { namespace irlower {
49 ///////////////////////////////////////////////////////////////////////////////
51 TRACE_SET_MOD(hhir);
53 namespace {
55 ///////////////////////////////////////////////////////////////////////////////
57 void cgInst(IRLS& env, const IRInstruction* inst){
58 SCOPE_ASSERT_DETAIL("cgInst") { return inst->toString(); };
60 switch (inst->op()) {
61 #define O(name, dsts, srcs, flags) \
62 case name: \
63 FTRACE(7, "cg" #name "\n"); \
64 try { \
65 cg##name(env, inst); \
66 } catch (const Exception& e) { \
67 always_assert_flog(0, "Exception escaped from cg" #name ": {}", \
68 e.getMessage()); \
69 } catch (const std::exception& e) { \
70 always_assert_flog(0, "std::exception escaped from cg" #name ": {}", \
71 e.what()); \
72 } catch (...) { \
73 always_assert_flog(0, "unknown exception escaped from cg" #name); \
74 } \
75 break;
76 IR_OPCODES
77 #undef O
78 default:
79 always_assert(false);
82 auto& v = vmain(env);
83 if (inst->isBlockEnd() && !v.closed()) {
84 if (auto const next = inst->next()) {
85 v << jmp{label(env, next)};
86 } else {
87 v << trap{TRAP_REASON}; // or end?
93 * Lower `block' from HHIR to vasm.
95 void genBlock(IRLS& env, Vout& v, Vout& vc, Block& block) {
96 FTRACE(6, "genBlock: {}\n", block.id());
98 env.vmain = &v;
99 env.vcold = &vc;
101 for (auto& inst : block) {
102 v.unit().cur_voff = 0;
103 v.setOrigin(&inst);
104 vc.setOrigin(&inst);
105 cgInst(env, &inst);
109 void optimize(Vunit& unit, CodeKind kind, bool regAlloc) {
110 auto const abi = jit::abi(kind);
111 switch (arch()) {
112 case Arch::X64:
113 optimizeX64(unit, abi, regAlloc);
114 break;
115 case Arch::ARM:
116 optimizeARM(unit, abi, regAlloc);
117 break;
118 case Arch::PPC64:
119 optimizePPC64(unit, abi, regAlloc);
120 break;
126 ///////////////////////////////////////////////////////////////////////////////
128 std::unique_ptr<Vunit> lowerUnit(const IRUnit& unit,
129 CodeKind kind,
130 bool regAlloc /* = true */) noexcept {
131 Timer timer(Timer::hhir_lower, unit.logEntry().get_pointer());
133 tracing::Block _{
134 "vasm-gen",
135 [&] {
136 return traceProps(unit)
137 .add("code_kind", codeKindAsString(kind))
138 .add("reg_alloc", regAlloc);
142 rqtrace::EventGuard trace{"VLOWER"};
143 SCOPE_ASSERT_DETAIL("hhir unit") { return show(unit); };
145 auto vunit = std::make_unique<Vunit>();
146 vunit->context = unit.context();
147 vunit->log_entry = unit.logEntry().get_pointer();
148 vunit->profiling = true;
149 Vasm vasm{*vunit};
150 SCOPE_ASSERT_DETAIL("vasm unit") { return show(*vunit); };
152 IRLS env{unit};
153 auto const blocks = rpoSortCfg(unit);
155 // Create the initial set of vasm blocks, numbered the same as the
156 // corresponding HHIR blocks.
157 // We initially create the blocks with 0 weight, and then set them below.
158 for (uint32_t i = 0, n = unit.numBlocks(); i < n; ++i) {
159 env.labels[i] = vunit->makeBlock(AreaIndex::Main, 0);
161 vunit->entry = env.labels[unit.entry()];
163 // Create Vregs for all relevant SSATmps.
164 assignRegs(unit, *vunit, env, blocks);
166 for (auto block : blocks) {
167 auto& v = block->hint() == Block::Hint::Unlikely ? vasm.cold() :
168 block->hint() == Block::Hint::Unused ? vasm.frozen() :
169 vasm.main();
170 FTRACE(6, "genBlock {} on {}\n", block->id(),
171 area_names[(unsigned)v.area()]);
173 auto b = env.labels[block];
174 vunit->blocks[b].area_idx = v.area();
175 vunit->blocks[b].weight = block->profCount() * areaWeightFactor(v.area());
176 v.use(b);
178 auto& vcold =
179 block->hint() == Block::Hint::Unused ? vasm.frozen() : vasm.cold();
181 if (block == unit.entry() && kind == CodeKind::Trace) {
182 v << recordbasenativesp{};
184 genBlock(env, v, vcold, *block);
186 assertx(v.closed());
187 assertx(vasm.main().empty() || vasm.main().closed());
188 assertx(vasm.cold().empty() || vasm.cold().closed());
189 assertx(vasm.frozen().empty() || vasm.frozen().closed());
192 fixBlockWeights(*vunit);
194 // This pass requires on some invariants about rvmfp() from HHIR, so we do it
195 // here rather than in optimize() as those optimizations may be called for non
196 // HHIR Vunits.
197 fixupVmfpUses(*vunit);
199 printUnit(kInitialVasmLevel, "after initial vasm generation", *vunit);
200 assertx(check(*vunit));
201 timer.stop();
202 trace.finish();
204 try {
205 optimize(*vunit, kind, regAlloc);
206 } catch (const FailedTraceGen& e) {
207 // vasm-xls can fail if it tries to allocate too many spill slots.
208 tracing::addPoint("vasm-optimize punt");
209 logLowPriPerfWarning(
210 "vasm-optimize punt",
211 1000,
212 [&](StructuredLogEntry& cols) {
213 cols.setStr("punt_type", e.what());
214 cols.setStr("vasm_unit", show(*vunit));
217 FTRACE(1, "vasm-optimize failed with {}\n", e.what());
218 return nullptr;
221 return vunit;
224 Vcost computeIRUnitCost(const IRUnit& unit) {
225 auto vunit = lowerUnit(unit, CodeKind::Trace, false /* regAlloc */);
226 if (RuntimeOption::EvalHHIRInliningUseLayoutBlocks) {
227 layoutBlocks(*vunit);
229 return computeVunitCost(*vunit);
233 ///////////////////////////////////////////////////////////////////////////////