Arquivos
hhvm/hphp/runtime/vm/jit/opt.cpp
T
bsimmers cf197fee81 Collapse runtime/vm/translator's contents into runtime/vm/jit
Facebook: ~bsimmers/bin/move-vm-files.sh
2013-06-03 10:54:43 -07:00

152 linhas
5.2 KiB
C++

/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
*/
#include "hphp/runtime/vm/jit/opt.h"
#include "hphp/runtime/vm/jit/tracebuilder.h"
#include "hphp/util/trace.h"
#include "hphp/runtime/vm/jit/irfactory.h"
#include "hphp/runtime/vm/jit/print.h"
#include "hphp/runtime/vm/jit/check.h"
namespace HPHP {
namespace JIT {
// insert inst after the point dst is defined
static void insertAfter(IRInstruction* definer, IRInstruction* inst) {
assert(!definer->isBlockEnd());
Block* block = definer->block();
auto pos = block->iteratorTo(definer);
if (pos->op() == DefLabel) {
++pos;
assert(pos != block->end() && pos->op() == Marker);
}
++pos;
block->insert(pos, inst);
}
/*
* Insert a DbgAssertRefCount instruction after each place we produce
* a refcounted value. The value must be something we can safely dereference
* to check the _count field.
*/
static void insertRefCountAsserts(IRInstruction& inst, IRFactory* factory) {
for (SSATmp& dst : inst.dsts()) {
Type t = dst.type();
if (t.subtypeOf(Type::Counted | Type::StaticStr | Type::StaticArr)) {
insertAfter(&inst, factory->gen(DbgAssertRefCount, &dst));
}
}
}
/*
* Insert a DbgAssertTv instruction for each stack location stored to by
* a SpillStack instruction.
*/
static void insertSpillStackAsserts(IRInstruction& inst, IRFactory* factory) {
SSATmp* sp = inst.dst();
auto const vals = inst.srcs().subpiece(2);
auto* block = inst.block();
auto pos = block->iteratorTo(&inst); ++pos;
for (unsigned i = 0, n = vals.size(); i < n; ++i) {
Type t = vals[i]->type();
if (t.subtypeOf(Type::Gen)) {
IRInstruction* addr = factory->gen(LdStackAddr,
Type::PtrToGen,
StackOffset(i),
sp);
block->insert(pos, addr);
IRInstruction* check = factory->gen(DbgAssertPtr, addr->dst());
block->insert(pos, check);
}
}
}
/*
* Insert asserts at various points in the IR.
* TODO: t2137231 Insert DbgAssertPtr at points that use or produces a GenPtr
*/
static void insertAsserts(Trace* trace, IRFactory* factory) {
forEachTraceBlock(trace, [=](Block* block) {
for (auto it = block->begin(), end = block->end(); it != end; ) {
IRInstruction& inst = *it;
++it;
if (inst.op() == SpillStack) {
insertSpillStackAsserts(inst, factory);
continue;
}
if (inst.op() == Call) {
SSATmp* sp = inst.dst();
IRInstruction* addr = factory->gen(LdStackAddr,
Type::PtrToGen,
StackOffset(0),
sp);
insertAfter(&inst, addr);
insertAfter(addr, factory->gen(DbgAssertPtr, addr->dst()));
continue;
}
if (!inst.isBlockEnd()) insertRefCountAsserts(inst, factory);
}
});
}
void optimizeTrace(Trace* trace, TraceBuilder* traceBuilder) {
IRFactory* irFactory = traceBuilder->getIrFactory();
auto finishPass = [&](const char* msg) {
dumpTrace(6, trace, folly::format("after {}", msg).str().c_str());
assert(checkCfg(trace, *irFactory));
assert(checkTmpsSpanningCalls(trace, *irFactory));
if (debug) forEachTraceInst(trace, assertOperandTypes);
};
auto doPass = [&](void (*fn)(Trace*, IRFactory*),
const char* msg) {
fn(trace, irFactory);
finishPass(msg);
};
auto dce = [&](const char* which) {
if (!RuntimeOption::EvalHHIRDeadCodeElim) return;
eliminateDeadCode(trace, irFactory);
finishPass(folly::format("{} DCE", which).str().c_str());
};
dce("initial");
if (RuntimeOption::EvalHHIRPredictionOpts) {
doPass(optimizePredictions, "prediction opts");
}
if (RuntimeOption::EvalHHIRExtraOptPass
&& (RuntimeOption::EvalHHIRCse
|| RuntimeOption::EvalHHIRSimplification)) {
traceBuilder->reoptimize();
finishPass("reoptimize");
// Cleanup any dead code left around by CSE/Simplification
// Ideally, this would be controlled by a flag returned
// by optimzeTrace indicating whether DCE is necessary
dce("reoptimize");
}
if (RuntimeOption::EvalHHIRJumpOpts) {
doPass(optimizeJumps, "jumpopts");
dce("jump opts");
}
if (RuntimeOption::EvalHHIRGenerateAsserts) {
doPass(insertAsserts, "RefCnt asserts");
}
}
} }