SSATmp* Simplifier::simplifyNot(SSATmp* src) { IRInstruction* inst = src->getInstruction(); Opcode op = inst->getOpcode(); // TODO: Add more algebraic simplification rules for NOT switch (op) { case ConvToBool: return simplifyNot(inst->getSrc(0)); case OpXor: { // !!X --> bool(X) if (isNotInst(inst->getSrc(0))) { return m_tb->genConvToBool(inst->getSrc(0)); } break; } // !(X cmp Y) --> X opposite_cmp Y case OpLt: case OpLte: case OpGt: case OpGte: case OpEq: case OpNeq: case OpSame: case OpNSame: // XXX: this could technically be losing a ConvToBool, except // that we kinda know "not" instructions (Xor with 1) are always // going to be followed by ConvToBool. // // TODO(#2058865): This would make more sense with a real Not // instruction and allowing boolean output types for query ops. return m_tb->genCmp(negateQueryOp(op), inst->getSrc(0), inst->getSrc(1)); case InstanceOf: case NInstanceOf: case InstanceOfBitmask: case NInstanceOfBitmask: // TODO: combine this with the above check and use isQueryOp or // add an isNegatable. return m_tb->gen(negateQueryOp(op), inst->getNumSrcs(), inst->getSrcs().begin()); // TODO !(X | non_zero) --> 0 default: (void)op; } return nullptr; }
/* * Insert a DbgAssertTv instruction for each stack location stored to by * a SpillStack instruction */ static void insertSpillStackAsserts(IRInstruction& inst, IRFactory* factory) { SSATmp* sp = inst.getDst(); auto const vals = inst.getSrcs().subpiece(2); auto* block = inst.getBlock(); auto pos = block->iteratorTo(&inst); ++pos; for (unsigned i = 0, offset = 0, n = vals.size(); i < n; ++i) { Type t = vals[i]->getType(); if (t == Type::ActRec) { offset += kNumActRecCells; i += kSpillStackActRecExtraArgs; } else { if (t.subtypeOf(Type::Gen)) { IRInstruction* addr = factory->gen(LdStackAddr, sp, factory->defConst(offset)); block->insert(pos, addr); IRInstruction* check = factory->gen(DbgAssertPtr, addr->getDst()); block->insert(pos, check); } ++offset; } } }