2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-2013 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/simplifier.h"
20 #include <type_traits>
22 #include "hphp/runtime/base/memory/smart_containers.h"
23 #include "hphp/runtime/base/type_conversions.h"
24 #include "hphp/runtime/vm/jit/tracebuilder.h"
25 #include "hphp/runtime/vm/runtime.h"
32 //////////////////////////////////////////////////////////////////////
34 StackValueInfo
getStackValue(SSATmp
* sp
, uint32_t index
) {
35 assert(sp
->isA(Type::StkPtr
));
36 IRInstruction
* inst
= sp
->inst();
42 case ReDefGeneratorSP
:
43 case StashGeneratorSP
:
44 return getStackValue(inst
->src(0), index
);
47 return getStackValue(inst
->src(1), index
);
49 case ExceptionBarrier
:
50 return getStackValue(inst
->src(0), index
);
52 case SideExitGuardStk
:
53 always_assert(0 && "simplifier is not tested for running after jumpopts");
62 // We don't have a value, but we may know the type due to guarding
64 if (inst
->extra
<StackOffset
>()->offset
== index
) {
65 return StackValueInfo
{ inst
->typeParam() };
67 return getStackValue(inst
->src(0), index
);
71 // return value from call
72 return StackValueInfo
{ nullptr };
75 getStackValue(inst
->src(0),
76 // Pushes a return value, pops an ActRec and args Array
78 (1 /* pushed */ - kNumActRecCells
+ 1 /* popped */));
79 info
.spansCall
= true;
85 // return value from call
86 return StackValueInfo
{ nullptr };
89 getStackValue(inst
->src(0),
91 (1 /* pushed */ - kNumActRecCells
/* popped */));
92 info
.spansCall
= true;
97 int64_t numPushed
= 0;
98 int32_t numSpillSrcs
= inst
->numSrcs() - 2;
100 for (int i
= 0; i
< numSpillSrcs
; ++i
) {
101 SSATmp
* tmp
= inst
->src(i
+ 2);
102 if (index
== numPushed
) {
103 if (tmp
->inst()->op() == IncRef
) {
104 tmp
= tmp
->inst()->src(0);
106 if (!tmp
->type().equals(Type::None
)) {
107 return StackValueInfo
{ tmp
};
113 // This is not one of the values pushed onto the stack by this
114 // spillstack instruction, so continue searching.
115 SSATmp
* prevSp
= inst
->src(0);
116 int64_t numPopped
= inst
->src(1)->getValInt();
117 return getStackValue(prevSp
,
118 // pop values pushed by spillstack
119 index
- (numPushed
- numPopped
));
123 SSATmp
* prevSp
= inst
->src(1);
124 int64_t spAdjustment
= inst
->src(3)->getValInt(); // # popped - # pushed
125 Type resultType
= inst
->typeParam();
126 if (index
== 0 && !resultType
.equals(Type::None
)) {
127 return StackValueInfo
{ resultType
};
129 return getStackValue(prevSp
, index
+ spAdjustment
);
133 case CufIterSpillFrame
:
134 return getStackValue(inst
->src(0),
136 index
- kNumActRecCells
);
140 // Assume it's a vector instruction. This will assert in
141 // vectorBaseIdx if not.
142 auto const base
= inst
->src(vectorBaseIdx(inst
));
143 assert(base
->inst()->op() == LdStackAddr
);
144 if (base
->inst()->extra
<LdStackAddr
>()->offset
== index
) {
145 VectorEffects
ve(inst
);
146 assert(ve
.baseTypeChanged
|| ve
.baseValChanged
);
147 return StackValueInfo
{ ve
.baseType
.derefIfPtr() };
149 return getStackValue(base
->inst()->src(0), index
);
153 // Should not get here!
157 smart::vector
<SSATmp
*> collectStackValues(SSATmp
* sp
, uint32_t stackDepth
) {
158 smart::vector
<SSATmp
*> ret
;
159 ret
.reserve(stackDepth
);
160 for (uint32_t i
= 0; i
< stackDepth
; ++i
) {
161 auto const value
= getStackValue(sp
, i
).value
;
163 ret
.push_back(value
);
169 //////////////////////////////////////////////////////////////////////
171 static void copyPropSrc(IRInstruction
* inst
, int index
) {
172 auto tmp
= inst
->src(index
);
173 auto srcInst
= tmp
->inst();
175 switch (srcInst
->op()) {
177 inst
->setSrc(index
, srcInst
->src(0));
181 if (!isRefCounted(srcInst
->src(0))) {
182 srcInst
->setOpcode(Mov
);
183 inst
->setSrc(index
, srcInst
->src(0));
192 void copyProp(IRInstruction
* inst
) {
193 for (uint32_t i
= 0; i
< inst
->numSrcs(); i
++) {
194 copyPropSrc(inst
, i
);
199 * Checks if property propName of class clsTmp, called from context class ctx,
200 * can be accessed via the static property cache.
201 * Right now, this returns true for two cases:
202 * (a) the property is accessed from within the class containing it
203 * (b) the property belongs to a persistent class and it's accessible from ctx
205 bool canUseSPropCache(SSATmp
* clsTmp
,
206 const StringData
* propName
,
208 if (propName
== nullptr) return false;
210 const StringData
* clsName
= findClassName(clsTmp
);
212 const StringData
* ctxName
= ctx
->preClass()->name();;
213 if (clsName
&& ctxName
&& clsName
->isame(ctxName
)) return true;
216 if (!clsTmp
->isConst()) return false;
218 const Class
* cls
= clsTmp
->getValClass();
220 if (!Transl::TargetCache::classIsPersistent(cls
)) return false;
222 // If the class requires initialization, it might not have been
223 // initialized yet. getSProp() below will trigger initialization,
224 // but that's only valid to do earlier if it doesn't require any
225 // property initializer ([sp]init methods).
226 if (cls
->hasInitMethods()) return false;
228 bool visible
, accessible
;
229 cls
->getSProp(const_cast<Class
*>(ctx
), propName
, visible
, accessible
);
231 return visible
&& accessible
;
234 //////////////////////////////////////////////////////////////////////
236 template<class... Args
> SSATmp
* Simplifier::cns(Args
&&... cns
) {
237 return m_tb
->cns(std::forward
<Args
>(cns
)...);
240 template<class... Args
> SSATmp
* Simplifier::gen(Args
&&... args
) {
241 return m_tb
->gen(std::forward
<Args
>(args
)...);
244 //////////////////////////////////////////////////////////////////////
246 SSATmp
* Simplifier::simplify(IRInstruction
* inst
) {
247 SSATmp
* src1
= inst
->src(0);
248 SSATmp
* src2
= inst
->src(1);
250 Opcode opc
= inst
->op();
252 case OpAdd
: return simplifyAdd(src1
, src2
);
253 case OpSub
: return simplifySub(src1
, src2
);
254 case OpMul
: return simplifyMul(src1
, src2
);
255 case OpBitAnd
: return simplifyBitAnd(src1
, src2
);
256 case OpBitOr
: return simplifyBitOr(src1
, src2
);
257 case OpBitXor
: return simplifyBitXor(src1
, src2
);
258 case OpLogicXor
: return simplifyLogicXor(src1
, src2
);
268 return simplifyCmp(opc
, inst
, src1
, src2
);
270 case Concat
: return simplifyConcat(src1
, src2
);
271 case Mov
: return simplifyMov(src1
);
272 case OpNot
: return simplifyNot(src1
);
273 case LdClsPropAddr
: return simplifyLdClsPropAddr(inst
);
274 case ConvBoolToArr
: return simplifyConvToArr(inst
);
275 case ConvDblToArr
: return simplifyConvToArr(inst
);
276 case ConvIntToArr
: return simplifyConvToArr(inst
);
277 case ConvStrToArr
: return simplifyConvToArr(inst
);
278 case ConvArrToBool
: return simplifyConvArrToBool(inst
);
279 case ConvDblToBool
: return simplifyConvDblToBool(inst
);
280 case ConvIntToBool
: return simplifyConvIntToBool(inst
);
281 case ConvStrToBool
: return simplifyConvStrToBool(inst
);
282 case ConvArrToDbl
: return simplifyConvArrToDbl(inst
);
283 case ConvBoolToDbl
: return simplifyConvBoolToDbl(inst
);
284 case ConvIntToDbl
: return simplifyConvIntToDbl(inst
);
285 case ConvStrToDbl
: return simplifyConvStrToDbl(inst
);
286 case ConvArrToInt
: return simplifyConvArrToInt(inst
);
287 case ConvBoolToInt
: return simplifyConvBoolToInt(inst
);
288 case ConvDblToInt
: return simplifyConvDblToInt(inst
);
289 case ConvStrToInt
: return simplifyConvStrToInt(inst
);
290 case ConvBoolToStr
: return simplifyConvBoolToStr(inst
);
291 case ConvDblToStr
: return simplifyConvDblToStr(inst
);
292 case ConvIntToStr
: return simplifyConvIntToStr(inst
);
293 case ConvCellToBool
:return simplifyConvCellToBool(inst
);
294 case Unbox
: return simplifyUnbox(inst
);
295 case UnboxPtr
: return simplifyUnboxPtr(inst
);
297 case IsNType
: return simplifyIsType(inst
);
299 case CheckInitMem
: return simplifyCheckInit(inst
);
303 return simplifyCondJmp(inst
);
313 return simplifyQueryJmp(inst
);
317 return simplifyJmpIsType(inst
);
321 case PrintBool
: return simplifyPrint(inst
);
323 case DecRefNZOrBranch
:
324 case DecRefNZ
: return simplifyDecRef(inst
);
325 case IncRef
: return simplifyIncRef(inst
);
326 case CheckType
: return simplifyCheckType(inst
);
327 case AssertNonNull
:return simplifyAssertNonNull(inst
);
329 case LdCls
: return simplifyLdCls(inst
);
330 case LdThis
: return simplifyLdThis(inst
);
331 case LdCtx
: return simplifyLdCtx(inst
);
332 case LdClsCtx
: return simplifyLdClsCtx(inst
);
333 case GetCtxFwdCall
:return simplifyGetCtxFwdCall(inst
);
335 case SpillStack
: return simplifySpillStack(inst
);
336 case Call
: return simplifyCall(inst
);
337 case CastStk
: return simplifyCastStk(inst
);
338 case AssertStk
: return simplifyAssertStk(inst
);
339 case LdStack
: return simplifyLdStack(inst
);
340 case LdStackAddr
: return simplifyLdStackAddr(inst
);
341 case DecRefStack
: return simplifyDecRefStack(inst
);
342 case DecRefLoc
: return simplifyDecRefLoc(inst
);
343 case LdLoc
: return simplifyLdLoc(inst
);
344 case StRef
: return simplifyStRef(inst
);
346 case ExitOnVarEnv
: return simplifyExitOnVarEnv(inst
);
353 SSATmp
* Simplifier::simplifySpillStack(IRInstruction
* inst
) {
354 auto const sp
= inst
->src(0);
355 auto const spDeficit
= inst
->src(1)->getValInt();
356 auto spillVals
= inst
->srcs().subpiece(2);
357 auto const numSpillSrcs
= spillVals
.size();
358 auto const spillCells
= spillValueCells(inst
);
359 int64_t adjustment
= spDeficit
- spillCells
;
361 // If there's nothing to spill, and no stack adjustment, we don't
362 // need the instruction; the old stack is still accurate.
363 if (!numSpillSrcs
&& spDeficit
== 0) return sp
;
365 // If our value came from a LdStack on the same sp and offset,
366 // we don't need to spill it.
367 for (uint32_t i
= 0, cellOff
= 0; i
< numSpillSrcs
; i
++) {
368 const int64_t offset
= cellOff
+ adjustment
;
369 auto* srcInst
= spillVals
[i
]->inst();
370 if (srcInst
->op() == LdStack
&& srcInst
->src(0) == sp
&&
371 srcInst
->extra
<LdStack
>()->offset
== offset
) {
372 spillVals
[i
] = m_tb
->genDefNone();
377 // Note: although the instruction might have been modified above, we still
378 // need to return nullptr so that it gets cloned later if it's stack-allocated
382 SSATmp
* Simplifier::simplifyCall(IRInstruction
* inst
) {
383 auto spillVals
= inst
->srcs().subpiece(3);
384 auto const spillStack
= inst
->src(0)->inst();
385 if (spillStack
->op() != SpillStack
) {
389 SSATmp
* sp
= spillStack
->src(0);
390 int baseOffset
= spillStack
->src(1)->getValInt() -
391 spillValueCells(spillStack
);
392 auto const numSpillSrcs
= spillVals
.size();
393 for (int32_t i
= 0; i
< numSpillSrcs
; i
++) {
394 const int64_t offset
= -(i
+ 1) + baseOffset
;
395 assert(spillVals
[i
]->type() != Type::ActRec
);
396 IRInstruction
* srcInst
= spillVals
[i
]->inst();
397 // If our value came from a LdStack on the same sp and offset,
398 // we don't need to spill it.
399 if (srcInst
->op() == LdStack
&& srcInst
->src(0) == sp
&&
400 srcInst
->extra
<LdStack
>()->offset
== offset
) {
401 spillVals
[i
] = m_tb
->genDefNone();
405 // Note: although the instruction might have been modified above, we still
406 // need to return nullptr so that it gets cloned later if it's stack-allocated
410 // We never inline functions that could have a VarEnv, so an
411 // ExitOnVarEnv that has a frame based on DefInlineFP can be removed.
412 SSATmp
* Simplifier::simplifyExitOnVarEnv(IRInstruction
* inst
) {
413 auto const frameInst
= inst
->src(0)->inst();
414 if (frameInst
->op() == DefInlineFP
) {
415 inst
->convertToNop();
420 SSATmp
* Simplifier::simplifyLdCtx(IRInstruction
* inst
) {
421 const Func
* func
= inst
->src(1)->getValFunc();
422 if (func
->isStatic()) {
423 // ActRec->m_cls of a static function is always a valid class pointer with
424 // the bottom bit set
425 return gen(LdCctx
, inst
->src(0));
430 SSATmp
* Simplifier::simplifyLdClsCtx(IRInstruction
* inst
) {
431 SSATmp
* ctx
= inst
->src(0);
432 Type ctxType
= ctx
->type();
433 if (ctxType
.equals(Type::Obj
)) {
434 // this pointer... load its class ptr
435 return gen(LdObjClass
, ctx
);
437 if (ctxType
.equals(Type::Cctx
)) {
438 return gen(LdClsCctx
, ctx
);
443 SSATmp
* Simplifier::simplifyGetCtxFwdCall(IRInstruction
* inst
) {
444 SSATmp
* srcCtx
= inst
->src(0);
445 if (srcCtx
->isA(Type::Cctx
)) {
451 SSATmp
* Simplifier::simplifyLdCls(IRInstruction
* inst
) {
452 SSATmp
* clsName
= inst
->src(0);
453 if (clsName
->isConst()) {
454 const Class
* cls
= Unit::lookupClass(clsName
->getValStr());
456 if (Transl::TargetCache::isPersistentHandle(cls
->m_cachedOffset
)) {
457 // the class is always defined
460 const Class
* ctx
= inst
->src(1)->getValClass();
461 if (ctx
&& ctx
->classof(cls
)) {
462 // the class of the current function being compiled is the
463 // same as or derived from cls, so cls must be defined and
464 // cannot change the next time we execute this same code
468 return gen(LdClsCached
, clsName
);
473 SSATmp
* Simplifier::simplifyCheckType(IRInstruction
* inst
) {
474 Type type
= inst
->typeParam();
475 SSATmp
* src
= inst
->src(0);
476 Type srcType
= src
->type();
478 if (srcType
.subtypeOf(type
)) {
480 * The type of the src is the same or more refined than type, so the
481 * guard is unnecessary.
485 if (type
.strictSubtypeOf(srcType
)) {
489 if (type
.equals(Type::Str
) && srcType
.maybe(Type::Str
)) {
491 * If we're guarding against Str and srcType has StaticStr or CountedStr
492 * in it, refine the output type. This can happen when we have a
493 * KindOfString guard from Translator but internally we know a more
494 * specific subtype of Str.
496 FTRACE(1, "CheckType: refining {} to {}\n", srcType
.toString(),
498 inst
->setTypeParam(type
& srcType
);
503 * We got a predicted type that is wrong -- it's incompatible with
504 * the tracked type. So throw the prediction away, since it would
507 FTRACE(1, "WARNING: CheckType: removed incorrect prediction that {} is {}\n",
508 srcType
.toString(), type
.toString());
512 SSATmp
* Simplifier::simplifyQueryJmp(IRInstruction
* inst
) {
513 SSATmp
* src1
= inst
->src(0);
514 SSATmp
* src2
= inst
->src(1);
515 Opcode opc
= inst
->op();
516 // reuse the logic in simplifyCmp.
517 SSATmp
* newCmp
= simplifyCmp(queryJmpToQueryOp(opc
), nullptr, src1
, src2
);
518 if (!newCmp
) return nullptr;
520 SSATmp
* newQueryJmp
= makeInstruction(
521 [=] (IRInstruction
* condJmp
) -> SSATmp
* {
522 SSATmp
* newCondJmp
= simplifyCondJmp(condJmp
);
523 if (newCondJmp
) return newCondJmp
;
524 if (condJmp
->op() == Nop
) {
525 // simplifyCondJmp folded the branch into a nop
526 inst
->convertToNop();
528 // Couldn't fold condJmp or combine it with newCmp
534 if (!newQueryJmp
) return nullptr;
538 SSATmp
* Simplifier::simplifyMov(SSATmp
* src
) {
542 SSATmp
* Simplifier::simplifyNot(SSATmp
* src
) {
543 if (src
->isConst()) {
544 return cns(!src
->getValBool());
547 IRInstruction
* inst
= src
->inst();
548 Opcode op
= inst
->op();
555 // !(X cmp Y) --> X opposite_cmp Y
564 // Not for Dbl: (x < NaN) != !(x >= NaN)
565 if (!inst
->src(0)->isA(Type::Dbl
) &&
566 !inst
->src(1)->isA(Type::Dbl
)) {
567 return gen(negateQueryOp(op
), inst
->src(0), inst
->src(1));
571 case InstanceOfBitmask
:
572 case NInstanceOfBitmask
:
573 // TODO: combine this with the above check and use isQueryOp or
574 // add an isNegatable.
577 std::make_pair(inst
->numSrcs(), inst
->srcs().begin())
580 // TODO !(X | non_zero) --> 0
586 #define SIMPLIFY_CONST(OP) do { \
587 /* don't canonicalize to the right, OP might not be commutative */ \
588 if (src1->isConst() && src2->isConst()) { \
589 if (src1->type().isNull()) { \
591 if (src2->type().isNull()) { \
592 return cns(int64_t(0 OP 0)); \
594 /* Null op ConstInt */ \
595 if (src2->type() == Type::Int) { \
596 return cns(int64_t(0 OP src2->getValInt())); \
598 /* Null op ConstBool */ \
599 if (src2->type() == Type::Bool) { \
600 return cns(int64_t(0 OP src2->getValBool())); \
602 /* Null op StaticStr */ \
603 if (src2->type() == Type::StaticStr) { \
604 const StringData* str = src2->getValStr(); \
605 if (str->isInteger()) { \
606 return cns(int64_t(0 OP str->toInt64())); \
608 return cns(int64_t(0 OP 0)); \
611 if (src1->type() == Type::Int) { \
612 /* ConstInt op Null */ \
613 if (src2->type().isNull()) { \
614 return cns(int64_t(src1->getValInt()) OP 0); \
616 /* ConstInt op ConstInt */ \
617 if (src2->type() == Type::Int) { \
618 return cns(int64_t(src1->getValInt() OP \
619 src2->getValInt())); \
621 /* ConstInt op ConstBool */ \
622 if (src2->type() == Type::Bool) { \
623 return cns(int64_t(src1->getValInt() OP \
624 int(src2->getValBool()))); \
626 /* ConstInt op StaticStr */ \
627 if (src2->type() == Type::StaticStr) { \
628 const StringData* str = src2->getValStr(); \
629 if (str->isInteger()) { \
630 return cns(int64_t(src1->getValInt() OP str->toInt64())); \
632 return cns(int64_t(src1->getValInt() OP 0)); \
635 if (src1->type() == Type::Bool) { \
636 /* ConstBool op Null */ \
637 if (src2->type().isNull()) { \
638 return cns(int64_t(src1->getValBool() OP 0)); \
640 /* ConstBool op ConstInt */ \
641 if (src2->type() == Type::Int) { \
642 return cns(int64_t(int(src1->getValBool()) OP \
643 src2->getValInt())); \
645 /* ConstBool op ConstBool */ \
646 if (src2->type() == Type::Bool) { \
647 return cns(int64_t(src1->getValBool() OP \
648 src2->getValBool())); \
650 /* ConstBool op StaticStr */ \
651 if (src2->type() == Type::StaticStr) { \
652 const StringData* str = src2->getValStr(); \
653 if (str->isInteger()) { \
654 return cns(int64_t(int(src1->getValBool()) OP str->toInt64())); \
656 return cns(int64_t(int(src1->getValBool()) OP 0)); \
659 if (src1->type() == Type::StaticStr) { \
660 const StringData* str = src1->getValStr(); \
661 int64_t strInt = 0; \
662 if (str->isInteger()) { \
663 strInt = str->toInt64(); \
665 /* StaticStr op Null */ \
666 if (src2->type().isNull()) { \
667 return cns(int64_t(strInt OP 0)); \
669 /* StaticStr op ConstInt */ \
670 if (src2->type() == Type::Int) { \
671 return cns(int64_t(strInt OP src2->getValInt())); \
673 /* StaticStr op ConstBool */ \
674 if (src2->type() == Type::Bool) { \
675 return cns(int64_t(strInt OP int(src2->getValBool()))); \
677 /* StaticStr op StaticStr */ \
678 if (src2->type() == Type::StaticStr) { \
679 const StringData* str2 = src2->getValStr(); \
680 if (str2->isInteger()) { \
681 return cns(int64_t(strInt OP str2->toInt64())); \
683 return cns(int64_t(strInt OP 0)); \
689 #define SIMPLIFY_COMMUTATIVE(OP, NAME) do { \
690 SIMPLIFY_CONST(OP); \
691 if (src1->isConst() && !src2->isConst()) { \
692 return gen(Op##NAME, src2, src1); \
694 if (src1->isA(Type::Int) && src2->isA(Type::Int)) { \
695 IRInstruction* inst1 = src1->inst(); \
696 IRInstruction* inst2 = src2->inst(); \
697 if (inst1->op() == Op##NAME && inst1->src(1)->isConst()) { \
698 /* (X + C1) + C2 --> X + C3 */ \
699 if (src2->isConst()) { \
700 int64_t right = inst1->src(1)->getValInt(); \
701 right OP##= src2->getValInt(); \
702 return gen(Op##NAME, inst1->src(0), cns(right)); \
704 /* (X + C1) + (Y + C2) --> X + Y + C3 */ \
705 if (inst2->op() == Op##NAME && inst2->src(1)->isConst()) { \
706 int64_t right = inst1->src(1)->getValInt(); \
707 right OP##= inst2->src(1)->getValInt(); \
708 SSATmp* left = gen(Op##NAME, inst1->src(0), inst2->src(0)); \
709 return gen(Op##NAME, left, cns(right)); \
715 #define SIMPLIFY_DISTRIBUTIVE(OUTOP, INOP, OUTNAME, INNAME) do { \
716 /* assumes that OUTOP is commutative, don't use with subtract! */ \
717 SIMPLIFY_COMMUTATIVE(OUTOP, OUTNAME); \
718 IRInstruction* inst1 = src1->inst(); \
719 IRInstruction* inst2 = src2->inst(); \
720 Opcode op1 = inst1->op(); \
721 Opcode op2 = inst2->op(); \
722 /* all combinations of X * Y + X * Z --> X * (Y + Z) */ \
723 if (op1 == Op##INNAME && op2 == Op##INNAME) { \
724 if (inst1->src(0) == inst2->src(0)) { \
725 SSATmp* fold = gen(Op##OUTNAME, inst1->src(1), inst2->src(1)); \
726 return gen(Op##INNAME, inst1->src(0), fold); \
728 if (inst1->src(0) == inst2->src(1)) { \
729 SSATmp* fold = gen(Op##OUTNAME, inst1->src(1), inst2->src(0)); \
730 return gen(Op##INNAME, inst1->src(0), fold); \
732 if (inst1->src(1) == inst2->src(0)) { \
733 SSATmp* fold = gen(Op##OUTNAME, inst1->src(0), inst2->src(1)); \
734 return gen(Op##INNAME, inst1->src(1), fold); \
736 if (inst1->src(1) == inst2->src(1)) { \
737 SSATmp* fold = gen(Op##OUTNAME, inst1->src(0), inst2->src(0)); \
738 return gen(Op##INNAME, inst1->src(1), fold); \
743 SSATmp
* Simplifier::simplifyAdd(SSATmp
* src1
, SSATmp
* src2
) {
744 SIMPLIFY_DISTRIBUTIVE(+, *, Add
, Mul
);
745 if (src2
->isConst() && src2
->type() == Type::Int
) {
746 int64_t src2Val
= src2
->getValInt();
749 if (src1
->type() == Type::Bool
) {
750 return gen(ConvBoolToInt
, src1
);
756 return gen(OpSub
, src1
, cns(-src2Val
));
759 // X + (0 - Y) --> X - Y
760 IRInstruction
* inst2
= src2
->inst();
761 Opcode op2
= inst2
->op();
763 SSATmp
* src
= inst2
->src(0);
764 if (src
->isConst() && src
->type() == Type::Int
) {
765 if (src
->getValInt() == 0) {
766 return gen(OpSub
, src1
, inst2
->src(1));
773 SSATmp
* Simplifier::simplifySub(SSATmp
* src1
, SSATmp
* src2
) {
779 if (src2
->isConst() && src2
->type() == Type::Int
) {
780 int64_t src2Val
= src2
->getValInt();
783 if (src1
->type() == Type::Bool
) {
784 return gen(ConvBoolToInt
, src1
);
789 if (src2Val
< 0 && src2Val
> std::numeric_limits
<int64_t>::min()) {
790 return gen(OpAdd
, src1
, cns(-src2Val
));
793 // X - (0 - Y) --> X + Y
794 IRInstruction
* inst2
= src2
->inst();
795 Opcode op2
= inst2
->op();
797 SSATmp
* src
= inst2
->src(0);
798 if (src
->isConst() && src
->type() == Type::Int
) {
799 if (src
->getValInt() == 0) {
800 return gen(OpAdd
, src1
, inst2
->src(1));
804 // TODO patterns in the form of:
805 // (X - C1) + (X - C2)
807 // (X - C1) + (X + C2)
811 SSATmp
* Simplifier::simplifyMul(SSATmp
* src1
, SSATmp
* src2
) {
812 SIMPLIFY_COMMUTATIVE(*, Mul
);
813 if (src2
->isConst() && src2
->type() == Type::Int
) {
815 if (src2
->getValInt() == -1) {
816 return gen(OpSub
, cns(0), src1
);
819 if (src2
->getValInt() == 0) {
823 if (src2
->getValInt() == 1) {
824 if (src1
->type() == Type::Bool
) {
825 return gen(ConvBoolToInt
, src1
);
830 if (src2
->getValInt() == 2) {
831 return gen(OpAdd
, src1
, src1
);
833 // TODO once IR has shifts
834 // X * 2^C --> X << C
835 // X * (2^C + 1) --> ((X << C) + X)
836 // X * (2^C - 1) --> ((X << C) - X)
841 SSATmp
* Simplifier::simplifyBitAnd(SSATmp
* src1
, SSATmp
* src2
) {
842 SIMPLIFY_DISTRIBUTIVE(&, |, BitAnd
, BitOr
);
847 if (src2
->isConst()) {
849 if (src2
->getValInt() == 0) {
853 if (src2
->getValInt() == ~0L) {
860 SSATmp
* Simplifier::simplifyBitOr(SSATmp
* src1
, SSATmp
* src2
) {
861 SIMPLIFY_DISTRIBUTIVE(|, &, BitOr
, BitAnd
);
866 if (src2
->isConst()) {
868 if (src2
->getValInt() == 0) {
872 if (src2
->getValInt() == ~uint64_t(0)) {
873 return cns(~uint64_t(0));
879 SSATmp
* Simplifier::simplifyBitXor(SSATmp
* src1
, SSATmp
* src2
) {
880 SIMPLIFY_COMMUTATIVE(^, BitXor
);
884 // X ^ 0 --> X; X ^ -1 --> ~X
885 if (src2
->isConst()) {
886 if (src2
->getValInt() == 0) {
889 if (src2
->getValInt() == -1) {
890 return gen(OpBitNot
, src1
);
896 SSATmp
* Simplifier::simplifyLogicXor(SSATmp
* src1
, SSATmp
* src2
) {
897 SIMPLIFY_COMMUTATIVE(^, LogicXor
);
902 // SIMPLIFY_COMMUTATIVE takes care of the both-sides-const case, and
903 // canonicalizes a single const to the right
904 if (src2
->isConst()) {
905 if (src2
->getValBool()) {
906 return gen(OpNot
, src1
);
914 static SSATmp
* chaseIncRefs(SSATmp
* tmp
) {
915 while (tmp
->inst()->op() == IncRef
) {
916 tmp
= tmp
->inst()->src(0);
921 template<class T
, class U
>
922 static typename
std::common_type
<T
,U
>::type
cmpOp(Opcode opName
, T a
, U b
) {
924 case OpGt
: return a
> b
;
925 case OpGte
: return a
>= b
;
926 case OpLt
: return a
< b
;
927 case OpLte
: return a
<= b
;
929 case OpEq
: return a
== b
;
931 case OpNeq
: return a
!= b
;
937 SSATmp
* Simplifier::simplifyCmp(Opcode opName
, IRInstruction
* inst
,
938 SSATmp
* src1
, SSATmp
* src2
) {
939 auto newInst
= [inst
, this](Opcode op
, SSATmp
* src1
, SSATmp
* src2
) {
940 return gen(op
, inst
? inst
->taken() : (Block
*)nullptr, src1
, src2
);
942 // ---------------------------------------------------------------------
943 // Perform some execution optimizations immediately
944 // ---------------------------------------------------------------------
946 // Identity optimization
947 if ((src1
== src2
|| chaseIncRefs(src1
) == chaseIncRefs(src2
)) &&
948 src1
->type() != Type::Dbl
) {
949 // (val1 == val1) does not simplify to true when val1 is a NaN
950 return cns(bool(cmpOp(opName
, 0, 0)));
953 // need both types to be unboxed and known to simplify
954 if (!src1
->type().notBoxed() || src1
->type() == Type::Cell
||
955 !src2
->type().notBoxed() || src2
->type() == Type::Cell
) {
959 // ---------------------------------------------------------------------
960 // OpSame and OpNSame have some special rules
961 // ---------------------------------------------------------------------
963 if (opName
== OpSame
|| opName
== OpNSame
) {
964 // OpSame and OpNSame do not perform type juggling
965 if (src1
->type() != src2
->type()) {
966 if (!(src1
->type().isString() && src2
->type().isString())) {
967 return cns(opName
== OpNSame
);
971 // src1 and src2 are same type, treating Str and StaticStr as the same
973 // OpSame and OpNSame have special rules for string and object
974 // Other types may simplify to OpEq and OpNeq, respectively
975 if (src1
->type().isString() && src2
->type().isString()) {
976 if (src1
->isConst() && src2
->isConst()) {
977 auto str1
= src1
->getValStr();
978 auto str2
= src2
->getValStr();
979 bool same
= str1
->same(str2
);
980 return cns(bool(cmpOp(opName
, same
, 1)));
985 if (src1
->type() == Type::Obj
&& src2
->type() == Type::Obj
) {
988 // for arrays, don't simplify Same to Eq
989 if (src1
->type() == Type::Arr
&& src2
->type() == Type::Arr
) {
992 // Type is neither a string nor an object - simplify to OpEq/OpNeq
993 if (opName
== OpSame
) {
994 return newInst(OpEq
, src1
, src2
);
996 return newInst(OpNeq
, src1
, src2
);
999 // ---------------------------------------------------------------------
1000 // We may now perform constant-constant optimizations
1001 // ---------------------------------------------------------------------
1004 if (src1
->type().isNull() && src2
->type().isNull()) {
1005 return cns(bool(cmpOp(opName
, 0, 0)));
1008 // TODO this list is incomplete - feel free to add more
1009 // TODO: can simplify const arrays when sizes are different or both 0
1010 if (src1
->isConst() && src2
->isConst()) {
1011 // StaticStr cmp StaticStr
1012 if (src1
->type() == Type::StaticStr
&&
1013 src2
->type() == Type::StaticStr
) {
1014 int cmp
= src1
->getValStr()->compare(src2
->getValStr());
1015 return cns(bool(cmpOp(opName
, cmp
, 0)));
1017 // ConstInt cmp ConstInt
1018 if (src1
->type() == Type::Int
&& src2
->type() == Type::Int
) {
1020 cmpOp(opName
, src1
->getValInt(), src2
->getValInt())));
1022 // ConstBool cmp ConstBool
1023 if (src1
->type() == Type::Bool
&& src2
->type() == Type::Bool
) {
1025 cmpOp(opName
, src1
->getValBool(), src2
->getValBool())));
1029 // ---------------------------------------------------------------------
1030 // Constant bool comparisons can be strength-reduced
1031 // NOTE: Comparisons with bools get juggled to bool.
1032 // ---------------------------------------------------------------------
1034 // Perform constant-bool optimizations
1035 if (src2
->type() == Type::Bool
&& src2
->isConst()) {
1036 bool b
= src2
->getValBool();
1038 // The result of the comparison might be independent of the truth
1039 // value of the LHS. If so, then simplify.
1040 // E.g. `some-int > true`. some-int may juggle to false or true
1041 // (0 or 1), but `0 > true` and `1 > true` are both false, so we can
1042 // simplify to false immediately.
1043 if (cmpOp(opName
, false, b
) == cmpOp(opName
, true, b
)) {
1044 return cns(bool(cmpOp(opName
, false, b
)));
1047 // There are only two distinct booleans - false and true (0 and 1).
1048 // From above, we know that (0 OP b) != (1 OP b).
1049 // Hence exactly one of (0 OP b) and (1 OP b) is true.
1050 // Hence there is exactly one boolean value of src1 that results in the
1051 // overall expression being true (after type-juggling).
1052 // Hence we may check for equality with that boolean.
1053 // E.g. `some-int > false` is equivalent to `some-int == true`
1054 if (opName
!= OpEq
) {
1055 if (cmpOp(opName
, false, b
)) {
1056 return newInst(OpEq
, src1
, cns(false));
1058 return newInst(OpEq
, src1
, cns(true));
1063 // ---------------------------------------------------------------------
1064 // For same-type cmps, canonicalize any constants to the right
1065 // Then stop - there are no more simplifications left
1066 // ---------------------------------------------------------------------
1068 if (src1
->type() == src2
->type() ||
1069 (src1
->type().isString() && src2
->type().isString())) {
1070 if (src1
->isConst() && !src2
->isConst()) {
1071 return newInst(commuteQueryOp(opName
), src2
, src1
);
1076 // ---------------------------------------------------------------------
1077 // Perform type juggling and type canonicalization for different types
1078 // see http://www.php.net/manual/en/language.operators.comparison.php
1079 // ---------------------------------------------------------------------
1081 // nulls get canonicalized to the right
1082 if (src1
->type().isNull()) {
1083 return newInst(commuteQueryOp(opName
), src2
, src1
);
1086 // case 1: null cmp string. Convert null to ""
1087 if (src1
->type().isString() && src2
->type().isNull()) {
1088 return newInst(opName
, src1
, cns(StringData::GetStaticString("")));
1091 // case 2a: null cmp anything. Convert null to false
1092 if (src2
->type().isNull()) {
1093 return newInst(opName
, src1
, cns(false));
1096 // bools get canonicalized to the right
1097 if (src1
->type() == Type::Bool
) {
1098 return newInst(commuteQueryOp(opName
), src2
, src1
);
1101 // case 2b: bool cmp anything. Convert anything to bool
1102 if (src2
->type() == Type::Bool
) {
1103 if (src1
->isConst()) {
1104 if (src1
->type() == Type::Int
) {
1105 return newInst(opName
, cns(bool(src1
->getValInt())), src2
);
1106 } else if (src1
->type().isString()) {
1107 auto str
= src1
->getValStr();
1108 return newInst(opName
, cns(str
->toBoolean()), src2
);
1112 // Optimize comparison between int and const bool
1113 if (src1
->type() == Type::Int
&& src2
->isConst()) {
1114 // Based on the const bool optimization (above) opName should be OpEq
1115 always_assert(opName
== OpEq
);
1117 if (src2
->getValBool()) {
1118 return newInst(OpNeq
, src1
, cns(0));
1120 return newInst(OpEq
, src1
, cns(0));
1124 // Nothing fancy to do - perform juggling as normal.
1125 return newInst(opName
, gen(ConvCellToBool
, src1
), src2
);
1128 // From here on, we must be careful of how Type::Obj gets dealt with,
1129 // since Type::Obj can refer to an object or to a resource.
1131 // case 3: object cmp object. No juggling to do
1132 // same-type simplification is performed above
1134 // strings get canonicalized to the left
1135 if (src2
->type().isString()) {
1136 return newInst(commuteQueryOp(opName
), src2
, src1
);
1139 // ints get canonicalized to the right
1140 if (src1
->type() == Type::Int
) {
1141 return newInst(commuteQueryOp(opName
), src2
, src1
);
1144 // case 4: number/string/resource cmp. Convert to number (int OR double)
1145 // NOTE: The following if-test only checks for some of the SRON-SRON
1146 // cases (specifically, string-int). Other cases (like string-string)
1147 // are dealt with earlier, while other cases (like number-resource)
1148 // are not caught at all (and end up exiting this macro at the bottom).
1149 if (src1
->type().isString() && src1
->isConst() &&
1150 src2
->type() == Type::Int
) {
1151 auto str
= src1
->getValStr();
1152 int64_t si
; double sd
;
1153 auto st
= str
->isNumericWithVal(si
, sd
, true /* allow errors */);
1154 if (st
== KindOfDouble
) {
1155 return newInst(opName
, cns(sd
), src2
);
1157 if (st
== KindOfNull
) {
1160 return newInst(opName
, cns(si
), src2
);
1163 // case 5: array cmp array. No juggling to do
1164 // same-type simplification is performed above
1166 // case 6: array cmp anything. Array is greater
1167 if (src1
->isArray()) {
1168 return cns(bool(cmpOp(opName
, 1, 0)));
1170 if (src2
->isArray()) {
1171 return cns(bool(cmpOp(opName
, 0, 1)));
1174 // case 7: object cmp anything. Object is greater
1175 // ---------------------------------------------------------------------
1176 // Unfortunately, we are unsure of whether Type::Obj is an object or a
1177 // resource, so this code cannot be applied.
1178 // ---------------------------------------------------------------------
1182 SSATmp
* Simplifier::simplifyJmpIsType(IRInstruction
* inst
) {
1183 SSATmp
* res
= simplifyIsType(inst
);
1184 if (res
== nullptr) return nullptr;
1185 assert(res
->isConst());
1186 if (res
->getValBool()) {
1188 return gen(Jmp_
, inst
->taken());
1190 // Not taken jump; turn jump into a nop
1191 inst
->convertToNop();
1196 SSATmp
* Simplifier::simplifyIsType(IRInstruction
* inst
) {
1198 inst
->op() == IsType
|| inst
->op() == JmpIsType
;
1199 auto type
= inst
->typeParam();
1200 auto src
= inst
->src(0);
1201 auto srcType
= src
->type();
1203 // The comparisons below won't work for these cases covered by this
1204 // assert, and we currently don't generate these types.
1205 assert(type
.isKnownUnboxedDataType() && type
!= Type::StaticStr
);
1207 // CountedStr and StaticStr are disjoint, but compatible for this purpose.
1208 if (type
.isString() && srcType
.isString()) {
1209 return cns(trueSense
);
1212 // The types are disjoint; the result must be false.
1213 if ((srcType
& type
).equals(Type::Bottom
)) {
1214 return cns(!trueSense
);
1217 // The src type is a subtype of the tested type. You'd think the result would
1218 // always be true, but it's not for is_object.
1219 if (!type
.subtypeOf(Type::Obj
) && srcType
.subtypeOf(type
)) {
1220 return cns(trueSense
);
1223 // At this point, either the tested type is a subtype of the src type, or they
1224 // are non-disjoint but neither is a subtype of the other. (Or it's the weird
1225 // Obj case.) We can't simplify this away.
1229 SSATmp
* Simplifier::simplifyConcat(SSATmp
* src1
, SSATmp
* src2
) {
1230 if (src1
->isConst() && src1
->type() == Type::StaticStr
&&
1231 src2
->isConst() && src2
->type() == Type::StaticStr
) {
1232 StringData
* str1
= const_cast<StringData
*>(src1
->getValStr());
1233 StringData
* str2
= const_cast<StringData
*>(src2
->getValStr());
1234 StringData
* merge
= StringData::GetStaticString(concat_ss(str1
, str2
));
1240 SSATmp
* Simplifier::simplifyConvToArr(IRInstruction
* inst
) {
1241 SSATmp
* src
= inst
->src(0);
1242 if (src
->isConst()) {
1243 Array arr
= Array::Create(src
->getValVariant());
1244 return cns(ArrayData::GetScalarArray(arr
.get()));
1249 SSATmp
* Simplifier::simplifyConvArrToBool(IRInstruction
* inst
) {
1250 SSATmp
* src
= inst
->src(0);
1251 if (src
->isConst()) {
1252 if (src
->getValArr()->empty()) {
1260 SSATmp
* Simplifier::simplifyConvDblToBool(IRInstruction
* inst
) {
1261 SSATmp
* src
= inst
->src(0);
1262 if (src
->isConst()) {
1263 return cns(bool(src
->getValDbl()));
1268 SSATmp
* Simplifier::simplifyConvIntToBool(IRInstruction
* inst
) {
1269 SSATmp
* src
= inst
->src(0);
1270 if (src
->isConst()) {
1271 return cns(bool(src
->getValInt()));
1276 SSATmp
* Simplifier::simplifyConvStrToBool(IRInstruction
* inst
) {
1277 SSATmp
* src
= inst
->src(0);
1278 if (src
->isConst()) {
1279 // only the strings "", and "0" convert to false, all other strings
1280 // are converted to true
1281 const StringData
* str
= src
->getValStr();
1282 return cns(!str
->empty() && !str
->isZero());
1287 SSATmp
* Simplifier::simplifyConvArrToDbl(IRInstruction
* inst
) {
1288 SSATmp
* src
= inst
->src(0);
1289 if (src
->isConst()) {
1290 if (src
->getValArr()->empty()) {
1297 SSATmp
* Simplifier::simplifyConvBoolToDbl(IRInstruction
* inst
) {
1298 SSATmp
* src
= inst
->src(0);
1299 if (src
->isConst()) {
1300 return cns(double(src
->getValBool()));
1305 SSATmp
* Simplifier::simplifyConvIntToDbl(IRInstruction
* inst
) {
1306 SSATmp
* src
= inst
->src(0);
1307 if (src
->isConst()) {
1308 return cns(double(src
->getValInt()));
1313 SSATmp
* Simplifier::simplifyConvStrToDbl(IRInstruction
* inst
) {
1314 SSATmp
* src
= inst
->src(0);
1315 if (src
->isConst()) {
1316 const StringData
*str
= src
->getValStr();
1319 DataType ret
= str
->isNumericWithVal(lval
, dval
, 1);
1320 if (ret
== KindOfInt64
) {
1321 dval
= (double)lval
;
1322 } else if (ret
!= KindOfDouble
) {
1330 SSATmp
* Simplifier::simplifyConvArrToInt(IRInstruction
* inst
) {
1331 SSATmp
* src
= inst
->src(0);
1332 if (src
->isConst()) {
1333 if (src
->getValArr()->empty()) {
1341 SSATmp
* Simplifier::simplifyConvBoolToInt(IRInstruction
* inst
) {
1342 SSATmp
* src
= inst
->src(0);
1343 if (src
->isConst()) {
1344 return cns(int(src
->getValBool()));
1349 SSATmp
* Simplifier::simplifyConvDblToInt(IRInstruction
* inst
) {
1350 SSATmp
* src
= inst
->src(0);
1351 if (src
->isConst()) {
1352 return cns(toInt64(src
->getValDbl()));
1357 SSATmp
* Simplifier::simplifyConvStrToInt(IRInstruction
* inst
) {
1358 SSATmp
* src
= inst
->src(0);
1359 if (src
->isConst()) {
1360 const StringData
*str
= src
->getValStr();
1363 DataType ret
= str
->isNumericWithVal(lval
, dval
, 1);
1364 if (ret
== KindOfDouble
) {
1365 lval
= (int64_t)dval
;
1366 } else if (ret
!= KindOfInt64
) {
1374 SSATmp
* Simplifier::simplifyConvBoolToStr(IRInstruction
* inst
) {
1375 SSATmp
* src
= inst
->src(0);
1376 if (src
->isConst()) {
1377 if (src
->getValBool()) {
1378 return cns(StringData::GetStaticString("1"));
1380 return cns(StringData::GetStaticString(""));
1385 SSATmp
* Simplifier::simplifyConvDblToStr(IRInstruction
* inst
) {
1386 SSATmp
* src
= inst
->src(0);
1387 if (src
->isConst()) {
1389 StringData::convert_double_helper(src
->getValDbl()));
1394 SSATmp
* Simplifier::simplifyConvIntToStr(IRInstruction
* inst
) {
1395 SSATmp
* src
= inst
->src(0);
1396 if (src
->isConst()) {
1398 StringData::convert_integer_helper(src
->getValInt()));
1403 SSATmp
* Simplifier::simplifyConvCellToBool(IRInstruction
* inst
) {
1404 auto const src
= inst
->src(0);
1405 auto const srcType
= src
->type();
1407 if (srcType
.isBool()) return src
;
1408 if (srcType
.isNull()) return cns(false);
1409 if (srcType
.isArray()) return gen(ConvArrToBool
, src
);
1410 if (srcType
.isDbl()) return gen(ConvDblToBool
, src
);
1411 if (srcType
.isInt()) return gen(ConvIntToBool
, src
);
1412 if (srcType
.isString()) return gen(ConvStrToBool
, src
);
1413 if (srcType
.isObj()) return cns(true);
1418 SSATmp
* Simplifier::simplifyLdClsPropAddr(IRInstruction
* inst
) {
1419 SSATmp
* propName
= inst
->src(1);
1420 if (!propName
->isConst()) return nullptr;
1422 SSATmp
* cls
= inst
->src(0);
1423 auto ctxCls
= inst
->src(2)->getValClass();
1425 if (canUseSPropCache(cls
, propName
->getValStr(), ctxCls
)) {
1427 const StringData
* clsNameStr
= findClassName(cls
);
1429 return gen(LdClsPropAddrCached
,
1441 * If we're in an inlined frame, use the this that we put in the
1442 * inlined ActRec. (This could chase more intervening SpillStack
1443 * instructions to find the SpillFrame, but for now we don't inline
1444 * calls that will have that.)
1446 SSATmp
* Simplifier::simplifyLdThis(IRInstruction
* inst
) {
1447 auto fpInst
= inst
->src(0)->inst();
1448 if (fpInst
->op() == DefInlineFP
) {
1449 auto spInst
= fpInst
->src(0)->inst();
1450 if (spInst
->op() == SpillFrame
&&
1451 spInst
->src(3)->isA(Type::Obj
)) {
1452 return spInst
->src(3);
1460 SSATmp
* Simplifier::simplifyUnbox(IRInstruction
* inst
) {
1461 auto* src
= inst
->src(0);
1462 auto type
= outputType(inst
);
1464 Type srcType
= src
->type();
1465 if (srcType
.notBoxed()) {
1466 assert(type
.equals(srcType
));
1469 if (srcType
.isBoxed()) {
1470 srcType
= srcType
.innerType();
1471 assert(type
.equals(srcType
));
1472 return gen(LdRef
, type
, inst
->taken()->trace(), src
);
1477 SSATmp
* Simplifier::simplifyUnboxPtr(IRInstruction
* inst
) {
1478 if (inst
->src(0)->isA(Type::PtrToCell
)) {
1480 return inst
->src(0);
1485 SSATmp
* Simplifier::simplifyCheckInit(IRInstruction
* inst
) {
1486 Type srcType
= inst
->src(0)->type();
1487 srcType
= inst
->op() == CheckInitMem
? srcType
.deref() : srcType
;
1488 assert(srcType
.notPtr());
1489 assert(inst
->taken());
1490 if (srcType
.isInit()) {
1491 inst
->convertToNop();
1496 SSATmp
* Simplifier::simplifyPrint(IRInstruction
* inst
) {
1497 if (inst
->src(0)->type().isNull()) {
1498 inst
->convertToNop();
1503 SSATmp
* Simplifier::simplifyDecRef(IRInstruction
* inst
) {
1504 if (!isRefCounted(inst
->src(0))) {
1505 inst
->convertToNop();
1510 SSATmp
* Simplifier::simplifyIncRef(IRInstruction
* inst
) {
1511 SSATmp
* src
= inst
->src(0);
1512 if (!isRefCounted(src
)) {
1518 SSATmp
* Simplifier::simplifyCondJmp(IRInstruction
* inst
) {
1519 SSATmp
* const src
= inst
->src(0);
1520 IRInstruction
* const srcInst
= src
->inst();
1521 const Opcode srcOpcode
= srcInst
->op();
1523 // After other simplifications below (isConvIntOrPtrToBool), we can
1524 // end up with a non-Bool input. Nothing more to do in this case.
1525 if (src
->type() != Type::Bool
) {
1529 // Constant propagate.
1530 if (src
->isConst()) {
1531 bool val
= src
->getValBool();
1532 if (inst
->op() == JmpZero
) {
1536 return gen(Jmp_
, inst
->taken());
1538 inst
->convertToNop();
1542 // Pull negations into the jump.
1543 if (src
->inst()->op() == OpNot
) {
1544 return gen(inst
->op() == JmpZero
? JmpNZero
: JmpZero
,
1550 * Try to combine the src inst with the Jmp. We can't do any
1551 * combinations of the src instruction with the jump if the src's
1552 * are refcounted, since we may have dec refs between the src
1553 * instruction and the jump.
1555 for (auto& src
: srcInst
->srcs()) {
1556 if (isRefCounted(src
)) return nullptr;
1559 // If the source is conversion of an int or pointer to boolean, we
1560 // can test the int/ptr value directly.
1561 if (isConvIntOrPtrToBool(srcInst
)) {
1562 return gen(inst
->op(), inst
->taken(), srcInst
->src(0));
1565 // Fuse jumps with query operators.
1566 if (isQueryOp(srcOpcode
)) {
1567 SrcRange ssas
= srcInst
->srcs();
1570 inst
->op() == JmpZero
1571 ? negateQueryOp(srcOpcode
)
1573 srcInst
->typeParam(), // if it had a type param
1575 std::make_pair(ssas
.size(), ssas
.begin())
1582 SSATmp
* Simplifier::simplifyCastStk(IRInstruction
* inst
) {
1583 auto const info
= getStackValue(inst
->src(0),
1584 inst
->extra
<CastStk
>()->offset
);
1585 if (info
.knownType
.subtypeOf(inst
->typeParam())) {
1586 // No need to cast---the type was as good or better.
1587 inst
->convertToNop();
1592 SSATmp
* Simplifier::simplifyAssertStk(IRInstruction
* inst
) {
1593 auto const info
= getStackValue(inst
->src(0),
1594 inst
->extra
<AssertStk
>()->offset
);
1596 // AssertStk indicated that we knew the type from static analysis,
1597 // so this assert just double checks.
1598 if (info
.value
) assert(info
.value
->isA(inst
->typeParam()));
1600 if (info
.knownType
.subtypeOf(inst
->typeParam())) {
1601 inst
->convertToNop();
1606 SSATmp
* Simplifier::simplifyLdStack(IRInstruction
* inst
) {
1607 auto const info
= getStackValue(inst
->src(0),
1608 inst
->extra
<LdStack
>()->offset
);
1610 // We don't want to extend live ranges of tmps across calls, so we
1611 // don't get the value if spansCall is true; however, we can use
1612 // any type information known.
1613 if (info
.value
&& (!info
.spansCall
||
1614 info
.value
->inst()->op() == DefConst
)) {
1617 if (!info
.knownType
.equals(Type::None
)) {
1619 Type::mostRefined(inst
->typeParam(), info
.knownType
)
1625 SSATmp
* Simplifier::simplifyDecRefLoc(IRInstruction
* inst
) {
1626 if (inst
->typeParam().notCounted()) {
1627 inst
->convertToNop();
1632 SSATmp
* Simplifier::simplifyLdLoc(IRInstruction
* inst
) {
1633 if (inst
->typeParam().isNull()) {
1634 return cns(inst
->typeParam());
1639 // Replace StRef with StRefNT when we know we aren't going to change
1640 // its m_type field.
1641 SSATmp
* Simplifier::simplifyStRef(IRInstruction
* inst
) {
1642 auto const oldUnbox
= inst
->src(0)->type().unbox();
1643 auto const newType
= inst
->src(1)->type();
1644 if (oldUnbox
.isKnownDataType() &&
1645 oldUnbox
.equals(newType
) && !oldUnbox
.isString()) {
1646 inst
->setOpcode(StRefNT
);
1651 SSATmp
* Simplifier::simplifyLdStackAddr(IRInstruction
* inst
) {
1652 auto const info
= getStackValue(inst
->src(0),
1653 inst
->extra
<StackOffset
>()->offset
);
1654 if (!info
.knownType
.equals(Type::None
)) {
1656 Type::mostRefined(inst
->typeParam(), info
.knownType
.ptr())
1662 SSATmp
* Simplifier::simplifyDecRefStack(IRInstruction
* inst
) {
1663 if (inst
->typeParam().notCounted()) {
1664 inst
->convertToNop();
1667 auto const info
= getStackValue(inst
->src(0),
1668 inst
->extra
<StackOffset
>()->offset
);
1669 if (info
.value
&& !info
.spansCall
) {
1670 inst
->convertToNop();
1671 return gen(DecRef
, info
.knownType
, info
.value
);
1673 if (!info
.knownType
.equals(Type::None
)) {
1675 Type::mostRefined(inst
->typeParam(), info
.knownType
)
1681 SSATmp
* Simplifier::simplifyAssertNonNull(IRInstruction
* inst
) {
1682 auto t
= inst
->typeParam();
1683 assert(t
.maybe(Type::Nullptr
));
1684 if (t
.subtypeOf(Type::Nullptr
)) {
1685 return inst
->src(0);
1690 //////////////////////////////////////////////////////////////////////