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/edge.h"
21 namespace HPHP
{ namespace jit
{
22 ///////////////////////////////////////////////////////////////////////////////
24 inline IRInstruction::IRInstruction(Opcode op
,
30 , m_iroff(bcctx
.iroff
)
33 , m_hasTypeParam
{false}
34 , m_marker(bcctx
.marker
)
40 // DefConst is the only opcode that's allowed to not have a marker, since
41 // it's not part of the instruction stream.
42 assertx(m_marker
.valid());
46 ///////////////////////////////////////////////////////////////////////////////
48 inline bool IRInstruction::hasDst() const {
49 return opcodeHasFlags(op(), HasDest
);
52 inline bool IRInstruction::naryDst() const {
53 return opcodeHasFlags(op(), NaryDest
);
56 inline bool IRInstruction::consumesReferences() const {
57 return opcodeHasFlags(op(), ConsumesRC
);
60 inline bool IRInstruction::mayRaiseError() const {
61 return opcodeMayRaise(op());
64 inline bool IRInstruction::isTerminal() const {
65 return opcodeHasFlags(op(), Terminal
);
68 inline bool IRInstruction::hasEdges() const {
69 return jit::hasEdges(op());
72 inline bool IRInstruction::isPassthrough() const {
73 return opcodeHasFlags(op(), Passthrough
);
76 inline bool IRInstruction::producesReference() const {
77 return opcodeHasFlags(op(), ProducesRC
);
80 inline SSATmp
* IRInstruction::getPassthroughValue() const {
81 assertx(isPassthrough());
82 assertx(is(CheckType
, CheckVArray
, CheckDArray
,
83 AssertType
, AssertNonNull
, Mov
,
88 ///////////////////////////////////////////////////////////////////////////////
90 inline uint32_t IRInstruction::id() const {
91 assertx(m_id
!= kTransient
);
95 inline bool IRInstruction::isTransient() const {
96 return m_id
== kTransient
;
99 inline uint16_t IRInstruction::iroff() const {
103 template<typename
... Args
>
104 bool IRInstruction::is(Opcode op
, Args
&&... args
) const {
105 return m_op
== op
|| is(std::forward
<Args
>(args
)...);
108 inline bool IRInstruction::is() const {
112 inline Opcode
IRInstruction::op() const {
116 inline const BCMarker
& IRInstruction::marker() const {
120 inline BCMarker
& IRInstruction::marker() {
124 inline BCContext
IRInstruction::bcctx() const {
125 return BCContext
{ m_marker
, m_iroff
};
128 inline const Func
* IRInstruction::func() const {
129 return m_marker
.hasFunc() ? m_marker
.func() : nullptr;
132 inline const Class
* IRInstruction::ctx() const {
133 return m_marker
.hasFunc() ? m_marker
.func()->cls() : nullptr;
136 inline bool IRInstruction::hasTypeParam() const { return m_hasTypeParam
; }
138 inline Type
IRInstruction::typeParam() const {
139 assertx(m_hasTypeParam
);
143 inline void IRInstruction::setTypeParam(Type t
) {
144 m_hasTypeParam
= true;
148 ///////////////////////////////////////////////////////////////////////////////
150 inline void IRInstruction::initializeSrcs(uint32_t numSrcs
, SSATmp
** srcs
) {
151 assertx(!m_srcs
&& !m_numSrcs
);
156 inline uint32_t IRInstruction::numSrcs() const {
160 inline uint32_t IRInstruction::numDsts() const {
164 inline SSATmp
* IRInstruction::src(uint32_t i
) const {
165 always_assert_flog(i
< numSrcs(), "src {} out of range in {}", i
, toString());
169 inline SSATmp
* IRInstruction::dst() const {
174 inline folly::Range
<SSATmp
**> IRInstruction::srcs() const {
175 return folly::Range
<SSATmp
**>(m_srcs
, m_numSrcs
);
178 inline folly::Range
<SSATmp
**> IRInstruction::dsts() {
179 assertx(naryDst() || m_numDsts
<= 1);
180 if (hasDst()) return folly::Range
<SSATmp
**>(&m_dest
, m_numDsts
);
181 return folly::Range
<SSATmp
**>(m_dsts
, m_numDsts
);
184 inline void IRInstruction::setSrc(uint32_t i
, SSATmp
* newSrc
) {
185 always_assert(i
< numSrcs());
189 inline void IRInstruction::setSrcs(uint32_t numSrcs
, SSATmp
** newSrcs
) {
194 inline void IRInstruction::deleteSrc(uint32_t i
) {
195 always_assert(i
< numSrcs());
196 std::copy(m_srcs
+ i
+ 1, m_srcs
+ m_numSrcs
, m_srcs
+ i
);
200 inline void IRInstruction::setDst(SSATmp
* newDst
) {
203 m_numDsts
= newDst
? 1 : 0;
206 inline void IRInstruction::setDsts(uint32_t numDsts
, SSATmp
** newDsts
) {
212 inline void IRInstruction::deleteDst(uint32_t i
) {
213 always_assert(i
< numDsts());
215 std::copy(m_dsts
+ i
+ 1, m_dsts
+ m_numDsts
, m_dsts
+ i
);
219 ///////////////////////////////////////////////////////////////////////////////
221 inline bool IRInstruction::hasExtra() const {
226 const typename IRExtraDataType
<opc
>::type
* IRInstruction::extra() const {
227 assertx(opc
== op() && "ExtraData type error");
228 assertx(m_extra
!= nullptr);
229 return static_cast<typename IRExtraDataType
<opc
>::type
*>(m_extra
);
233 typename IRExtraDataType
<opc
>::type
* IRInstruction::extra() {
234 assertx(opc
== op() && "ExtraData type error");
235 return static_cast<typename IRExtraDataType
<opc
>::type
*>(m_extra
);
239 const T
* IRInstruction::extra() const {
240 if (debug
) assert_opcode_extra
<T
>(op());
241 return static_cast<const T
*>(m_extra
);
245 T
* IRInstruction::extra() {
246 if (debug
) assert_opcode_extra
<T
>(op());
247 return static_cast<T
*>(m_extra
);
250 inline const IRExtraData
* IRInstruction::rawExtra() const {
254 inline void IRInstruction::setExtra(IRExtraData
* data
) {
259 inline void IRInstruction::clearExtra() {
263 ///////////////////////////////////////////////////////////////////////////////
265 inline Block
* IRInstruction::block() const {
269 inline void IRInstruction::setBlock(Block
* b
) {
273 inline Block
* IRInstruction::next() const {
277 inline Edge
* IRInstruction::nextEdge() {
281 inline void IRInstruction::setNext(Block
* b
) {
282 return setSucc(0, b
);
285 inline Block
* IRInstruction::taken() const {
289 inline Edge
* IRInstruction::takenEdge() {
293 inline void IRInstruction::setTaken(Block
* b
) {
294 return setSucc(1, b
);
297 inline bool IRInstruction::isControlFlow() const {
298 return bool(taken());
301 inline bool IRInstruction::isBlockEnd() const {
302 return taken() || isTerminal();
305 inline Block
* IRInstruction::succ(int i
) const {
306 assertx(!m_edges
|| hasEdges());
307 return m_edges
? m_edges
[i
].to() : nullptr;
310 inline Edge
* IRInstruction::succEdge(int i
) {
311 assertx(!m_edges
|| hasEdges());
312 return m_edges
&& m_edges
[i
].to() ? &m_edges
[i
] : nullptr;
315 inline void IRInstruction::setSucc(int i
, Block
* b
) {
317 if (isTransient()) m_edges
[i
].setTransientTo(b
);
318 else m_edges
[i
].setTo(b
);
320 assertx(!b
&& !m_edges
);
324 inline void IRInstruction::clearEdges() {
330 ///////////////////////////////////////////////////////////////////////////////