bool IRInstruction::canCSE() const { auto canCSE = opcodeHasFlags(op(), CanCSE); // Make sure that instructions that are CSE'able can't consume reference // counts. assert(!canCSE || !consumesReferences()); return canCSE; }
bool IRInstruction::canCSE() const { auto canCSE = opcodeHasFlags(op(), CanCSE); // Make sure that instructions that are CSE'able can't produce a reference // count or consume reference counts. CheckType/AssertType are special // because they can refine a maybeCounted type to a notCounted type, so they // logically consume and produce a reference without doing any work. assert(!canCSE || !consumesReferences() || m_op == CheckType || m_op == AssertType); return canCSE && !mayReenterHelper(); }
bool IRInstruction::isEssential() const { Opcode opc = op(); if (opc == DecRefNZ) { // If the source of a DecRefNZ is not an IncRef, mark it as essential // because we won't remove its source as well as itself. // If the ref count optimization is turned off, mark all DecRefNZ as // essential. if (!RuntimeOption::EvalHHIREnableRefCountOpt || src(0)->inst()->op() != IncRef) { return true; } } return isControlFlow() || opcodeHasFlags(opc, Essential) || mayReenterHelper(); }
bool IRInstruction::mayModifyRefs() const { Opcode opc = op(); // DecRefNZ does not have side effects other than decrementing the ref // count. Therefore, its MayModifyRefs should be false. if (opc == DecRef) { auto type = src(0)->type(); if (isControlFlow()) { // If the decref has a target label, then it exits if the destructor // has to be called, so it does not have any side effects on the main // trace. return false; } if (!type.canRunDtor()) { return false; } } return opcodeHasFlags(opc, MayModifyRefs) || mayReenterHelper(); }
bool IRInstruction::isPassthrough() const { return opcodeHasFlags(op(), Passthrough); }
bool IRInstruction::isTerminal() const { return opcodeHasFlags(op(), Terminal); }
bool IRInstruction::isEssential() const { return isControlFlow() || opcodeHasFlags(op(), Essential); }
bool MInstrEffects::supported(Opcode op) { return opcodeHasFlags(op, MInstrProp | MInstrElem); }
bool IRInstruction::producesReference(int dstNo) const { return opcodeHasFlags(op(), ProducesRC); }
bool IRInstruction::naryDst() const { return opcodeHasFlags(op(), NaryDest | ModifiesStack); }
bool IRInstruction::hasMainDst() const { return opcodeHasFlags(op(), HasDest); }
bool IRInstruction::hasMemEffects() const { return opcodeHasFlags(op(), MemEffects) || mayReenterHelper(); }
bool IRInstruction::mayRaiseError() const { return opcodeHasFlags(op(), MayRaiseError) || mayReenterHelper(); }
// minstrBaseIdx returns the src index for inst's base operand. int minstrBaseIdx(Opcode opc) { return opcodeHasFlags(opc, MInstrProp) ? 0 : opcodeHasFlags(opc, MInstrElem) ? 0 : bad_value<int>(); }
bool IRInstruction::killsSources() const { return opcodeHasFlags(op(), KillsSources); }
bool IRInstruction::modifiesStack() const { return opcodeHasFlags(op(), ModifiesStack); }
bool IRInstruction::mayRaiseError() const { return opcodeHasFlags(op(), MayRaiseError); }
bool IRInstruction::hasDst() const { return opcodeHasFlags(op(), HasDest) && !opcodeHasFlags(op(), ModifiesStack); }
bool hasEdges(Opcode opcode) { return opcodeHasFlags(opcode, Branch | MayRaiseError); }
bool IRInstruction::isNative() const { return opcodeHasFlags(op(), CallsNative); }
bool opHasExtraData(Opcode op) { return opcodeHasFlags(op, HasExtra); }
bool IRInstruction::consumesReferences() const { return opcodeHasFlags(op(), ConsumesRC); }
Opcode getStackModifyingOpcode(Opcode opc) { assert(opcodeHasFlags(opc, HasStackVersion)); opc = Opcode(uint64_t(opc) + 1); assert(opcodeHasFlags(opc, ModifiesStack)); return opc; }