hphp/runtime/vm/jit/vasm-info.cpp (398 lines of code) (raw):
/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010-present 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/vasm-info.h"
#include "hphp/runtime/vm/jit/vasm-instr.h"
#include "hphp/runtime/vm/jit/vasm-reg.h"
#include <utility>
namespace HPHP::jit {
///////////////////////////////////////////////////////////////////////////////
namespace {
///////////////////////////////////////////////////////////////////////////////
/*
* Provide a default template that matches every instruction, but which
* is only a near match for a non-const Inst&.
*/
template <typename Inst>
std::pair<ConditionCode*,Vreg> ccUsageHelper(const Inst&) {
return { nullptr, Vreg{} };
}
/*
* Provide a template that only matches instructions with cc and sf
* members, and is an exact match for a non-const Inst&.
*/
template <typename Inst>
auto ccUsageHelper(Inst& i) ->
decltype(std::make_pair(&i.cc, Vreg(size_t(i.sf)))) {
return { &i.cc, Vreg(size_t(i.sf)) };
}
std::pair<ConditionCode*,Vreg> ccUsage(Vinstr& inst) {
#define O(name,...) case Vinstr::name: return ccUsageHelper(inst.name##_);
switch (inst.op) {
VASM_OPCODES
}
#undef O
not_reached();
}
template<typename M>
constexpr bool useMemory() { return false; }
template<>
constexpr bool useMemory<Vptr>() { return true; }
template<>
constexpr bool useMemory<Vptr8>() { return true; }
template<>
constexpr bool useMemory<Vptr16>() { return true; }
template<>
constexpr bool useMemory<Vptr32>() { return true; }
template<>
constexpr bool useMemory<Vptr64>() { return true; }
template<>
constexpr bool useMemory<Vptr128>() { return true; }
///////////////////////////////////////////////////////////////////////////////
}
ConditionCode& getConditionCode(Vinstr& inst) {
auto usage = ccUsage(inst);
assertx(usage.first);
return *usage.first;
}
Vreg getSFUseReg(const Vinstr& inst) {
return ccUsage(const_cast<Vinstr&>(inst)).second;
}
bool touchesMemory(Vinstr::Opcode op) {
if (op == Vinstr::killeffects) return true;
if (op == Vinstr::lea) return false;
if (isCall(op)) return true;
#define O(name, imms, uses, defs) \
case Vinstr::name: { using T = name; return uses false; }
#define U(s) useMemory<decltype(T::s)>() ||
#define UA(s) useMemory<decltype(T::s)>() ||
#define UH(s,h) (assertx(!useMemory<decltype(T::s)>()),false) ||
#define UW(s) (assertx(useMemory<decltype(T::s)>()),true) ||
#define UM(s) (assertx(useMemory<decltype(T::s)>()),true) ||
#define Un false ||
switch (op) {
VASM_OPCODES
}
return false;
#undef Un
#undef UH
#undef UA
#undef UW
#undef UM
#undef U
#undef O
}
bool writesMemory(Vinstr::Opcode op) {
if (op == Vinstr::killeffects) return true;
if (isCall(op)) return true;
#define O(name, imms, uses, defs) \
case Vinstr::name: { using T = name; return uses false; }
#define U(s)
#define UA(s)
#define UH(s,h)
#define UW(s) (assertx(useMemory<decltype(T::s)>()),true) ||
#define UM(s) (assertx(useMemory<decltype(T::s)>()),true) ||
#define Un
switch (op) {
VASM_OPCODES
}
return false;
#undef Un
#undef UH
#undef UA
#undef UW
#undef UM
#undef U
#undef O
}
bool touchesMemory(const Vinstr& inst) {
return touchesMemory(inst.op);
}
bool writesMemory(const Vinstr& inst) {
return writesMemory(inst.op);
}
///////////////////////////////////////////////////////////////////////////////
namespace {
bool effectsImpl(const Vinstr& inst, bool pure) {
switch (inst.op) {
// Pure:
case Vinstr::absdbl:
case Vinstr::addl:
case Vinstr::addli:
case Vinstr::addq:
case Vinstr::addqi:
case Vinstr::addsd:
case Vinstr::andb:
case Vinstr::andbi:
case Vinstr::andw:
case Vinstr::andwi:
case Vinstr::andl:
case Vinstr::andli:
case Vinstr::andq:
case Vinstr::andqi64:
case Vinstr::andqi:
case Vinstr::btrq:
case Vinstr::cmovb:
case Vinstr::cmovl:
case Vinstr::cmovq:
case Vinstr::cmovw:
case Vinstr::cmpb:
case Vinstr::cmpbi:
case Vinstr::cmpl:
case Vinstr::cmpli:
case Vinstr::cmpq:
case Vinstr::cmpqi:
case Vinstr::cmpsd:
case Vinstr::cmpw:
case Vinstr::cmpwi:
case Vinstr::copy2:
case Vinstr::copy:
case Vinstr::copyargs:
case Vinstr::crc32q:
case Vinstr::csincb:
case Vinstr::csincl:
case Vinstr::csincq:
case Vinstr::csincw:
case Vinstr::cvtsi2sd:
case Vinstr::cvttsd2siq:
case Vinstr::decl:
case Vinstr::decq:
case Vinstr::divint:
case Vinstr::divsd:
case Vinstr::fcvtzs:
case Vinstr::imul:
case Vinstr::incl:
case Vinstr::incq:
case Vinstr::incw:
case Vinstr::ldimmb:
case Vinstr::ldimml:
case Vinstr::ldimmq:
case Vinstr::ldimmw:
case Vinstr::ldundefq:
case Vinstr::lea:
case Vinstr::lead:
case Vinstr::movb:
case Vinstr::movl:
case Vinstr::movsbl:
case Vinstr::movsbq:
case Vinstr::movslq:
case Vinstr::movswl:
case Vinstr::movswq:
case Vinstr::movtdb:
case Vinstr::movtdq:
case Vinstr::movtqb:
case Vinstr::movtql:
case Vinstr::movtqw:
case Vinstr::movw:
case Vinstr::movzbl:
case Vinstr::movzbq:
case Vinstr::movzbw:
case Vinstr::movzlq:
case Vinstr::movzwl:
case Vinstr::movzwq:
case Vinstr::mulsd:
case Vinstr::neg:
case Vinstr::nop:
case Vinstr::not:
case Vinstr::notb:
case Vinstr::orbi:
case Vinstr::orwi:
case Vinstr::orli:
case Vinstr::orq:
case Vinstr::orqi:
case Vinstr::reload:
case Vinstr::roundsd:
case Vinstr::sar:
case Vinstr::sarq:
case Vinstr::sarqi:
case Vinstr::setcc:
case Vinstr::shl:
case Vinstr::shr:
case Vinstr::shlli:
case Vinstr::shlq:
case Vinstr::shlqi:
case Vinstr::shrq:
case Vinstr::shrli:
case Vinstr::shrqi:
case Vinstr::spill:
case Vinstr::spillbi:
case Vinstr::spillli:
case Vinstr::spillqi:
case Vinstr::spillundefq:
case Vinstr::sqrtsd:
case Vinstr::srem:
case Vinstr::ssaalias:
case Vinstr::subl:
case Vinstr::subli:
case Vinstr::subq:
case Vinstr::subqi:
case Vinstr::subsd:
case Vinstr::testb:
case Vinstr::testbi:
case Vinstr::testl:
case Vinstr::testli:
case Vinstr::testq:
case Vinstr::testqi:
case Vinstr::testw:
case Vinstr::testwi:
case Vinstr::ubfmli:
case Vinstr::ucomisd:
case Vinstr::unpcklpd:
case Vinstr::xorb:
case Vinstr::xorbi:
case Vinstr::xorw:
case Vinstr::xorwi:
case Vinstr::xorl:
case Vinstr::xorq:
case Vinstr::xorqi:
assertx(!touchesMemory(inst));
return pure;
// Non-effectful but non-pure:
case Vinstr::cloadq:
case Vinstr::cmpbim:
case Vinstr::cmpbm:
case Vinstr::cmplim:
case Vinstr::cmplm:
case Vinstr::cmpqim:
case Vinstr::cmpqm:
case Vinstr::cmpwim:
case Vinstr::cmpwm:
case Vinstr::cvtsi2sdm:
case Vinstr::defvmretdata:
case Vinstr::defvmrettype:
case Vinstr::defvmsp:
case Vinstr::defvmfp:
case Vinstr::leap:
case Vinstr::leav:
case Vinstr::load:
case Vinstr::loadb:
case Vinstr::loadl:
case Vinstr::loadqd:
case Vinstr::loadqp:
case Vinstr::loadsbl:
case Vinstr::loadsbq:
case Vinstr::loadsd:
case Vinstr::loadtqb:
case Vinstr::loadtql:
case Vinstr::loadups:
case Vinstr::loadw:
case Vinstr::loadzbl:
case Vinstr::loadzbq:
case Vinstr::loadzwq:
case Vinstr::loadzlq:
case Vinstr::mrs:
case Vinstr::testbim:
case Vinstr::testbm:
case Vinstr::testlim:
case Vinstr::testlm:
case Vinstr::testqim:
case Vinstr::testqm:
case Vinstr::testwim:
case Vinstr::testwm:
assertx(!writesMemory(inst));
assertx(!isCall(inst));
return false;
// Effectful:
case Vinstr::addlim:
case Vinstr::addlm:
case Vinstr::addqim:
case Vinstr::addqmr:
case Vinstr::addqrm:
case Vinstr::addwm:
case Vinstr::andbim:
case Vinstr::bindaddr:
case Vinstr::ldbindaddr:
case Vinstr::ldbindretaddr:
case Vinstr::bindjcc:
case Vinstr::bindjmp:
case Vinstr::call:
case Vinstr::callfaststub:
case Vinstr::callm:
case Vinstr::callphp:
case Vinstr::callphpr:
case Vinstr::callphps:
case Vinstr::callr:
case Vinstr::calls:
case Vinstr::callstub:
case Vinstr::conjure:
case Vinstr::conjureuse:
case Vinstr::contenter:
case Vinstr::cqo:
case Vinstr::debugtrap:
case Vinstr::declm:
case Vinstr::decqm:
case Vinstr::decqmlock:
case Vinstr::decqmlocknosf:
case Vinstr::fallback:
case Vinstr::fallbackcc:
case Vinstr::fallthru:
case Vinstr::idiv:
case Vinstr::inclm:
case Vinstr::incqm:
case Vinstr::incwm:
case Vinstr::inittc:
case Vinstr::inlineend:
case Vinstr::inlinestart:
case Vinstr::jcc:
case Vinstr::jcci:
case Vinstr::jmp:
case Vinstr::jmps:
case Vinstr::jmpi:
case Vinstr::jmpm:
case Vinstr::jmpr:
case Vinstr::killeffects:
case Vinstr::landingpad:
case Vinstr::leavetc:
case Vinstr::loadstubret:
case Vinstr::mcprep:
case Vinstr::movqs:
case Vinstr::msr:
case Vinstr::nothrow:
case Vinstr::orbim:
case Vinstr::orlim:
case Vinstr::orqim:
case Vinstr::orwim:
case Vinstr::phidef:
case Vinstr::phijmp:
case Vinstr::phplogue:
case Vinstr::phpret:
case Vinstr::pop:
case Vinstr::popf:
case Vinstr::popm:
case Vinstr::popp:
case Vinstr::poppm:
case Vinstr::prefetch:
case Vinstr::push:
case Vinstr::pushf:
case Vinstr::pushframe:
case Vinstr::pushm:
case Vinstr::pushp:
case Vinstr::pushpm:
case Vinstr::pushvmfp:
case Vinstr::recordbasenativesp:
case Vinstr::unrecordbasenativesp:
case Vinstr::recordstack:
case Vinstr::resumetc:
case Vinstr::ret:
case Vinstr::store:
case Vinstr::storeb:
case Vinstr::storebi:
case Vinstr::storel:
case Vinstr::storeli:
case Vinstr::storeqi:
case Vinstr::storesd:
case Vinstr::storeups:
case Vinstr::storew:
case Vinstr::storewi:
case Vinstr::stublogue:
case Vinstr::stubret:
case Vinstr::stubtophp:
case Vinstr::stubunwind:
case Vinstr::subqim:
case Vinstr::syncpoint:
case Vinstr::syncvmret:
case Vinstr::syncvmrettype:
case Vinstr::syncvmsp:
case Vinstr::tailcallstub:
case Vinstr::tailcallstubr:
case Vinstr::trap:
case Vinstr::unstublogue:
case Vinstr::unwind:
case Vinstr::vcall:
case Vinstr::vinvoke:
case Vinstr::vregrestrict:
case Vinstr::vregunrestrict:
return !pure;
}
always_assert(false);
}
}
bool effectful(const Vinstr& inst) {
return effectsImpl(inst, false);
}
bool isPure(const Vinstr& inst) {
return effectsImpl(inst, true);
}
}