void OperandStack::d2i(){ Operand opL = pop(); Operand opH = pop(); if((opL.type != TYPE_DOUBLE) || (opH.type != TYPE_DOUBLE)) { printf("Error type not double: :op_stack.d2i\n"); exit(0); } double d = to_double(opH.bytes, opL.bytes); int32_t i = (int32_t) d; Operand op; op.set_value(TYPE_INT, &i); push(op); }
void InstSelect::dump(const Cfg *Func) const { Ostream &Str = Func->getContext()->getStrDump(); dumpDest(Func); Operand *Condition = getCondition(); Operand *TrueOp = getTrueOperand(); Operand *FalseOp = getFalseOperand(); Str << " = select " << Condition->getType() << " "; Condition->dump(Func); Str << ", " << TrueOp->getType() << " "; TrueOp->dump(Func); Str << ", " << FalseOp->getType() << " "; FalseOp->dump(Func); }
void OperandStack::l2d(){ Operand opL = pop(); Operand opH = pop(); if((opL.type != TYPE_LONG) || (opH.type != TYPE_LONG)) { printf("Error type not long: :op_stack.l2d\n"); exit(0); } int64_t l = to_long(opH.bytes, opL.bytes); double d = (double) l; opH.set_high(TYPE_DOUBLE, &d); opL.set_low(TYPE_DOUBLE, &d); push(opH); push(opL); }
Instruction* In::CreateInstruction(Memory::MemoryOffset& memLoc, Processor* proc) { Memory::MemoryOffset opLoc = memLoc; char buf[65]; std::string inst; Prefix* pre = Prefix::GetPrefix(memLoc); unsigned int preSize = 0; Instruction* newIn = 0; if(pre) { opLoc += preSize = pre->GetLength(); } switch(*opLoc) { case IN_AL_IMM8: case IN_AX_IMM8: { eRegisters reg = *opLoc == IN_AL_IMM8 ? REG_AL : REG_AX; Operand* src = new ImmediateOperand(*(opLoc + 1), 1, (opLoc + 1).getOffset()); Operand* dst = new RegisterOperand(reg, proc); GETINST(preSize + 2); snprintf(buf, 65, "IN %s, %s",reg == REG_AX ? "AX" : "AL", src->GetDisasm().c_str()); newIn = new In(pre, buf, inst, (int)*opLoc); newIn->SetOperand(Operand::SRC, src); newIn->SetOperand(Operand::DST, dst); break; } case IN_AL_DX: case IN_AX_DX: { eRegisters reg = *opLoc == IN_AL_DX ? REG_AL : REG_AX; Operand* src = new RegisterOperand(REG_DX, proc); Operand* dst = new RegisterOperand(reg, proc); GETINST(preSize + 1); snprintf(buf, 65, "IN %s, DX", reg == REG_AX ? "AX" : "AL"); newIn = new In(pre, buf, inst, (int)*opLoc); newIn->SetOperand(Operand::SRC, src); newIn->SetOperand(Operand::DST, dst); break; } } return newIn; }
Instruction* Out::CreateInstruction(unsigned char* memLoc, Processor* proc) { unsigned char* opLoc = memLoc; char buf[65]; std::string inst; Prefix* pre = Prefix::GetPrefix(memLoc); unsigned int preSize = 0; Instruction* newOut = 0; if(pre) { opLoc += preSize = pre->GetLength(); } switch(*opLoc) { case OUT_IMM8_AL: case OUT_IMM8_AX: { eRegisters reg = *opLoc == OUT_IMM8_AL ? REG_AL : REG_AX; Operand* dst = new ImmediateOperand(*(opLoc + 1), 1); Operand* src = new RegisterOperand(reg, proc); GETINST(preSize + 2); snprintf(buf, 65, "OUT %s, %s", dst->GetDisasm().c_str(), reg == REG_AX ? "AX" : "AL"); newOut = new Out(pre, buf, inst, (int)*opLoc); newOut->SetOperand(Operand::SRC, src); newOut->SetOperand(Operand::DST, dst); break; } case OUT_DX_AL: case OUT_DX_AX: { eRegisters reg = *opLoc == OUT_DX_AL ? REG_AL : REG_AX; Operand* dst = new RegisterOperand(REG_DX, proc); Operand* src = new RegisterOperand(reg, proc); GETINST(preSize + 1); snprintf(buf, 65, "OUT DX, %s", reg == REG_AX ? "AX" : "AL"); newOut = new Out(pre, buf, inst, (int)*opLoc); newOut->SetOperand(Operand::SRC, src); newOut->SetOperand(Operand::DST, dst); break; } } return newOut; }
/// This should be called in top-down order of each def that needs its uses /// rewrited. The order that we visit uses for a given def is irrelevant. void SILSSAUpdater::RewriteUse(Operand &Op) { // Replicate function_refs to their uses. SILGen can't build phi nodes for // them and it would not make much sense anyways. if (auto *FR = dyn_cast<FunctionRefInst>(Op.get())) { assert(areIdentical(getAvailVals(AV)) && "The function_refs need to have the same value"); SILInstruction *User = Op.getUser(); auto *NewFR = FR->clone(User); Op.set(NewFR); return; } else if (auto *IL = dyn_cast<IntegerLiteralInst>(Op.get())) if (areIdentical(getAvailVals(AV))) { // Some llvm intrinsics don't like phi nodes as their constant inputs (e.g // ctlz). SILInstruction *User = Op.getUser(); auto *NewIL = IL->clone(User); Op.set(NewIL); return; } // Again we need to be careful here, because ssa construction (with the // existing representation) can change the operand from under us. UseWrapper UW(&Op); SILInstruction *User = Op.getUser(); SILValue NewVal = GetValueInMiddleOfBlock(User->getParent()); assert(NewVal && "Need a valid value"); ((Operand *)UW)->set((SILValue)NewVal); }
void OperandStack::d2l(){ Operand opL = pop(); Operand opH = pop(); if((opL.type != TYPE_DOUBLE) || (opH.type != TYPE_DOUBLE)) { printf("Error type not double: :op_stack.d2l\n"); exit(0); } double d = to_double(opH.bytes, opL.bytes); int64_t l = (int64_t) d; opH.set_high(TYPE_LONG, &l); opL.set_low(TYPE_LONG, &l); push(opH); push(opL); }
int IndirectControlFlowAnalyzer::GetMemoryReadSize(Assignment::Ptr memLoc) { if (!memLoc) { parsing_printf("\tmemLoc is null\n"); return 0; } Instruction i = memLoc->insn(); std::vector<Operand> ops; i.getOperands(ops); parsing_printf("\t there are %d operands\n", ops.size()); for (auto oit = ops.begin(); oit != ops.end(); ++oit) { Operand o = *oit; if (o.readsMemory()) { Expression::Ptr exp = o.getValue(); return exp->size(); } } return 0; }
bool CodeGeneratorX64::visitLoadElementT(LLoadElementT *load) { Operand source = createArrayElementOperand(ToRegister(load->elements()), load->index()); if (load->mir()->loadDoubles()) { FloatRegister fpreg = ToFloatRegister(load->output()); if (source.kind() == Operand::REG_DISP) masm.loadDouble(source.toAddress(), fpreg); else masm.loadDouble(source.toBaseIndex(), fpreg); } else { loadUnboxedValue(source, load->mir()->type(), load->output()); } JS_ASSERT(!load->mir()->needsHoleCheck()); return true; }
bool CodeGeneratorX86Shared::visitMulNegativeZeroCheck(MulNegativeZeroCheck *ool) { LMulI *ins = ool->ins(); Register result = ToRegister(ins->output()); Operand lhsCopy = ToOperand(ins->lhsCopy()); Operand rhs = ToOperand(ins->rhs()); JS_ASSERT_IF(lhsCopy.kind() == Operand::REG, lhsCopy.reg() != result.code()); // Result is -0 if lhs or rhs is negative. masm.movl(lhsCopy, result); masm.orl(rhs, result); if (!bailoutIf(Assembler::Signed, ins->snapshot())) return false; masm.mov(ImmWord(0), result); masm.jmp(ool->rejoin()); return true; }
/* * Currently only SBs are frpizable */ bool El_is_frpizable(Hyperblock *hb) { Op *op; Operand pred; /* See if there are any ops guarded by a predicate */ /* Also, no table jumps allowed */ for (Region_ops_C0_order op_i(hb); op_i!=0; op_i++) { op = *op_i; if (op->predicated()) { pred = op->src(PRED1); if (! pred.is_predicate_true()) return (false); } if (op->flag(EL_OPER_TABLE_JUMP)) return (false); } return (true); }
int Or::Execute(Processor* proc) { Operand* dst = mOperands[Operand::DST]; Operand* src = mOperands[Operand::SRC]; if(!dst || !src) { return INVALID_ARGS; } unsigned int dstVal = dst->GetValue(); unsigned int srcVal = src->GetValue(); unsigned int newVal = dstVal | srcVal; unsigned int sign = (dst->GetBitmask() == 0xFF) ? 0x80 : 0x8000; proc->SetFlag(FLAGS_OF, 0); proc->SetFlag(FLAGS_CF, 0); proc->SetFlag(FLAGS_SF, newVal >= sign); proc->SetFlag(FLAGS_ZF, newVal == 0x00); proc->SetFlag(FLAGS_PF, Parity(newVal)); dst->SetValue(newVal); return 0; }
bool GradeSelector::Select( void ) { if( !operand ) return false; Expander expander; expander.expansionTarget = Expander::SUM_OF_BLADES; expander.ManipulateTree( &operand ); Addition* addition = dynamic_cast< Addition* >( operand ); if( !addition ) return false; Addition::OperandList::Node* node = addition->operandList.Head(); while( node ) { Addition::OperandList::Node* nextNode = node->Next(); Operand* nestedOperand = node->data; int count = -1; OuterProduct* outerProduct = dynamic_cast< OuterProduct* >( nestedOperand ); Vector* vector = dynamic_cast< Vector* >( nestedOperand ); if( outerProduct && outerProduct->IsHomogeneousOfVectors() ) count = outerProduct->operandList.Count(); else if( vector ) count = 1; else if( nestedOperand->IsScalar() ) count = 0; if( ( count == grade && type == TYPE_EXCLUSIVE ) || ( count != grade && type == TYPE_INCLUSIVE ) ) addition->operandList.Remove( node ); node = nextNode; } return true; }
void util::NodeMap::doDepthFirstSearch(Node* aNode){ if(m_ops.size() == 0) return; if(aNode->isLeafNode()){ Operand op = m_ops.front(); m_ops.pop_front(); while(op.getType() == Operand::bracketOpen){ if(m_ops.size() == 0) return ; op = m_ops.front(); m_ops.pop_front(); } if(op.getType() == Operand::bracketClose){ dfsFlag = 1; return; } BNode* b = aNode->container; setOpAttrributes(op,b); } std::vector<Node*> vec = aNode->getChildren(); for(std::vector<Node*>::iterator iter = vec.begin(); iter != vec.end(); iter++){ if((*iter) != NULL && strcmp((*iter)->getName().c_str(), "___")){ doDepthFirstSearch(*iter); if(dfsFlag == 1 && !(aNode->getName() == "match_operator" || aNode->getName() == "unspec" || aNode->getName() == "parallel" || aNode->getName() == "unspec_volatile" || aNode->getName() == "match_op_dup" || aNode->getName() == "match_operator" || aNode->getName() == "parallel" || aNode->getName() == "match_op_dup" || aNode->getName() == "sequence")){ return; } else{ dfsFlag = 0; } } } }
void SetAction(string word, Operand *&currod, queue<Operand*> &ods, stack<string> &bucket, int *currop, int *opcount, register int &bracket_ct, register int &currop_ind) { if (currod->GetAction() == DefaultAction) { currod->SetAction(word); } else { Operand *od = new Operand(*currod); if (od->GetAction() != DefaultAction) { ods.push(od); //Look into this opcount[currop_ind] += 1; if (opcount[currop_ind] == currop[currop_ind]) { FixMissingEntriesAndFillTheBucket(ods, bucket); bucket.push(OpenBracket);currop_ind--;opcount[currop_ind] += 1;bracket_ct--; } } ResetCurrentOperand(currod, DefaultComponent, word, DefaultWhen, DefaultLocation, NULL, NULL); } }
int Push::Execute(Processor* proc) { if(mOpcode == PUSHA) { unsigned int sp = proc->GetRegister(REG_SP); proc->PushRegister(REG_AX); proc->PushRegister(REG_CX); proc->PushRegister(REG_DX); proc->PushRegister(REG_BX); proc->PushValue(sp); proc->PushRegister(REG_BP); proc->PushRegister(REG_SI); proc->PushRegister(REG_DI); } else { Operand* dst = mOperands[Operand::DST]; if(!dst) { return INVALID_ARGS; } proc->PushValue(dst->GetValue()); } return 0; }
/// Replace an instruction with a simplified result, including any debug uses, /// and erase the instruction. If the instruction initiates a scope, do not /// replace the end of its scope; it will be deleted along with its parent. void swift::replaceAllSimplifiedUsesAndErase( SILInstruction *I, SILValue result, std::function<void(SILInstruction *)> eraseNotify) { auto *SVI = cast<SingleValueInstruction>(I); assert(SVI != result && "Cannot RAUW a value with itself"); // Only SingleValueInstructions are currently simplified. while (!SVI->use_empty()) { Operand *use = *SVI->use_begin(); SILInstruction *user = use->getUser(); // Erase the end of scope marker. if (isEndOfScopeMarker(user)) { if (eraseNotify) eraseNotify(user); user->eraseFromParent(); continue; } use->set(result); } I->eraseFromParent(); if (eraseNotify) eraseNotify(I); }
void Basic_block::renomme(int num_reg, Instruction* instDeb, Instruction *instFin, int reg_libre) { // iteration Instruction* inst = instDeb; cout << "Renommage de $" << num_reg << " par $" << reg_libre << " de i" << instDeb->get_index() << " a i" << instFin->get_index() << endl; // boucle vrai while(true) { // nbr d'operand int nbOp = inst->get_nbOp(); // pour chaque operand, on verifie si c'est un registre // si oui, si il a le meme num que celui de ref // on le remplace par le reg libre if(inst != instDeb) // on ne remplace pas le registre de sv du dernier juste les operandes if(nbOp > 0) { Operand* tmp = inst->get_op1(); if(tmp->get_op_type() == Reg) { OPRegister* reg_tmp = (dynamic_cast< OPRegister * > (tmp)); if(reg_tmp->get_reg() == num_reg) reg_tmp->set_reg(reg_libre); } } if(inst != instFin) { // on ne remplace pas les operandes dans le premier mais juste l'endroit de sauvegarde if(nbOp > 1) { Operand* tmp = inst->get_op2(); if(tmp->get_op_type() == Reg) { OPRegister* reg_tmp = (dynamic_cast< OPRegister * > (tmp)); if(reg_tmp->get_reg() == num_reg) reg_tmp->set_reg(reg_libre); } } if(nbOp > 2) { Operand* tmp = inst->get_op3(); if(tmp->get_op_type() == Reg) { OPRegister* reg_tmp = (dynamic_cast< OPRegister * > (tmp)); if(reg_tmp->get_reg() == num_reg) reg_tmp->set_reg(reg_libre); } } } // on a fini, on sort if(inst == instFin) break; inst = inst->get_prev(); } }
Operand (const Operand &cp) { action = cp.GetAction(); variable = cp.GetVariable(); time = cp.GetTime(); location = cp.GetLocation(); if (cp.GetTimeRange() != NULL) { time_range = new string[2]; time_range[0] = cp.GetTimeRange()[0]; time_range[1] = cp.GetTimeRange()[1]; } else time_range = NULL; if (cp.GetNodeRange() != NULL) { node_range = new string[2]; node_range[0] = cp.GetNodeRange()[0]; node_range[1] = cp.GetNodeRange()[1]; } else node_range = NULL; }
int IDiv::Execute(Processor* proc) { Operand* dst = mOperands[Operand::DST]; if(dst == 0) return INVALID_ARGS; if(dst->GetValue() == 0) { return IDIV_BY_ZERO; } unsigned int dividend = proc->GetRegister(REG_AX) + (mOpcode == IDIV_MOD8 ? 0 : proc->GetRegister(REG_DX) << 0x10); unsigned int divisor = dst->GetValue(); unsigned int divisorNeg = dst->GetBitmask() == 0xFF ? 0x80 : 0x8000; unsigned int dividendNeg = dst->GetBitmask() == 0xFF ? 0x8000 : 0x80000000; unsigned int dividendBm = dst->GetBitmask() == 0xFF ? 0xFFFF : 0xFFFFFFFF; int rem, val; bool neg = (((dividend & dividendNeg) >> 8) ^ (divisor & divisorNeg)) != 0; //positivize everything if(dividend & dividendNeg) { //if dividend is negative dividend = (~dividend + 1) & dividendBm; // +ve it and ensure within bitmask } if(divisor & divisorNeg) { divisor = (~divisor + 1) & dst->GetBitmask(); //all operands are positive rem = -(int)(dividend % divisor); //remainder is negative } else { rem = (dividend % divisor); //remainder is positive } //calc result val = dividend / divisor; // if((unsigned int)val >= divisorNeg) { //operands are positive, so anything this big is overflow return IDIV_DIV_ERR; } //invert if necessary if(neg) val = -val; val &= dst->GetBitmask(); proc->SetRegister(mOpcode == IDIV_MOD8 ? REG_AL : REG_AX, val); proc->SetRegister(mOpcode == IDIV_MOD8 ? REG_AH : REG_DX, rem); return 0; }
void El_insert_initializer_for_collapsed_predicate(Hyperblock *hb, Operand &br_pred, Operand &ft_pred, Operand &incoming_pred, Op *first_cmpp) { Op *new_op; Pred_lit *new_pred_lit; new_pred_lit = new Pred_lit(true); Operand pred_true(new_pred_lit); if (incoming_pred.is_predicate_true()) { new_op = new Op(PRED_SET); new_op->set_dest(DEST1, br_pred); new_op->set_src(PRED1, pred_true); El_insert_op_after_merge(hb, new_op); new_op = new Op(PRED_SET); new_op->set_dest(DEST1, ft_pred); new_op->set_src(PRED1, pred_true); El_insert_op_after_merge(hb, new_op); } else { // Temporarily we will insert both a PRED_SET, and the CMPP, the PRED_SET // is because the initialization does not fit impact stylization, argh!! new_op = new Op(PRED_SET); new_op->set_dest(DEST1, br_pred); new_op->set_src(PRED1, pred_true); El_insert_op_after_merge(hb, new_op); new_op = new Op(PRED_SET); new_op->set_dest(DEST1, ft_pred); new_op->set_src(PRED1, pred_true); El_insert_op_after_merge(hb, new_op); new_op = new Op((Opcode)CMPP_W_EQ_UN_UN); new_op->set_dest(DEST1, br_pred); new_op->set_dest(DEST2, ft_pred); new_op->set_src(PRED1, incoming_pred); Int_lit* new_int_lit = new Int_lit(0); Operand new_src(new_int_lit); new_op->set_src(SRC1, new_src); new_op->set_src(SRC2, new_src); El_insert_op_before(new_op, first_cmpp); } }
RetType dispatchByItemKind_gen(Operand item,Visitor& vis) { switch(item.kind()) { case BRIG_KIND_OPERAND_ADDRESS: return vis(OperandAddress(item)); case BRIG_KIND_OPERAND_ALIGN: return vis(OperandAlign(item)); case BRIG_KIND_OPERAND_CODE_LIST: return vis(OperandCodeList(item)); case BRIG_KIND_OPERAND_CODE_REF: return vis(OperandCodeRef(item)); case BRIG_KIND_OPERAND_CONSTANT_BYTES: return vis(OperandConstantBytes(item)); case BRIG_KIND_OPERAND_CONSTANT_IMAGE: return vis(OperandConstantImage(item)); case BRIG_KIND_OPERAND_CONSTANT_OPERAND_LIST: return vis(OperandConstantOperandList(item)); case BRIG_KIND_OPERAND_CONSTANT_SAMPLER: return vis(OperandConstantSampler(item)); case BRIG_KIND_OPERAND_OPERAND_LIST: return vis(OperandOperandList(item)); case BRIG_KIND_OPERAND_REGISTER: return vis(OperandRegister(item)); case BRIG_KIND_OPERAND_STRING: return vis(OperandString(item)); case BRIG_KIND_OPERAND_WAVESIZE: return vis(OperandWavesize(item)); default: assert(false); break; } return RetType(); }
RetType dispatchByItemKind_gen(Operand item,Visitor& vis) { using namespace Brig; switch(item.brig()->kind) { case BRIG_OPERAND_ADDRESS: return vis(OperandAddress(item)); case BRIG_OPERAND_SIGNATURE_REF: return vis(OperandSignatureRef(item)); case BRIG_OPERAND_FBARRIER_REF: return vis(OperandFbarrierRef(item)); case BRIG_OPERAND_LABEL_REF: return vis(OperandLabelRef(item)); case BRIG_OPERAND_IMMED: return vis(OperandImmed(item)); case BRIG_OPERAND_ARGUMENT_LIST: return vis(OperandArgumentList(item)); case BRIG_OPERAND_ARGUMENT_REF: return vis(OperandArgumentRef(item)); case BRIG_OPERAND_REG: return vis(OperandReg(item)); case BRIG_OPERAND_FUNCTION_LIST: return vis(OperandFunctionList(item)); case BRIG_OPERAND_FUNCTION_REF: return vis(OperandFunctionRef(item)); case BRIG_OPERAND_REG_VECTOR: return vis(OperandRegVector(item)); case BRIG_OPERAND_WAVESIZE: return vis(OperandWavesize(item)); default: assert(false); break; } return RetType(); }
void El_reassociate_input_operand(Hyperblock *hb, Operand &orig, Operand &replace) { Op *op; Operand operand; Port_num port; if (orig.is_undefined()) return; for (Region_ops_C0_order op_i(hb); op_i!=0; op_i++) { op = *op_i; for (Op_explicit_inputs operand_i(op); operand_i!=0; operand_i++) { operand = *operand_i; if (operand != orig) continue; port = operand_i.get_port_num(); op->set_src(port, replace); } } }
int Out::Execute(Processor* proc) { Operand* dst = mOperands[Operand::DST]; Operand* src = mOperands[Operand::SRC]; if(!dst || !src) { return -1; } if(mOpcode == OUT_IMM8_AL || mOpcode == OUT_DX_AL) { proc->Outb(dst->GetValue(), src->GetValue()); return 0; } else if(mOpcode == OUT_IMM8_AX || mOpcode == OUT_DX_AX) { proc->Outw(dst->GetValue(), src->GetValue()); return 0; } return -1; }
int In::Execute(Processor* proc) { Operand* dst = mOperands[Operand::DST]; Operand* src = mOperands[Operand::SRC]; if(!dst || !src) { return INVALID_ARGS; } if(mOpcode == IN_AL_IMM8 || mOpcode == IN_AL_DX) { dst->SetValue(proc->Inb(src->GetValue())); return 0; } else if(mOpcode == IN_AX_IMM8 || mOpcode == IN_AX_DX) { dst->SetValue(proc->Inw(src->GetValue())); return 0; } return INVALID_ARGS; }
void OperandStack::f2l(){ Operand op = pop(); if(op.type != TYPE_FLOAT) { printf("Error type not float: :op_stack.f2l\n"); exit(0); } float f = op.to_float(); int64_t l = (int64_t) f; Operand opH; Operand opL; opH.set_high(TYPE_LONG, &l); opL.set_low(TYPE_LONG, &l); push(opH); push(opL); }
void OperandStack::f2d(){ Operand op = pop(); if(op.type != TYPE_FLOAT) { printf("Error type not float: :op_stack.f2d\n"); exit(0); } float f = op.to_float(); double d = (double) f; Operand opL; Operand opH; opH.set_high(TYPE_DOUBLE, &d); opL.set_low(TYPE_DOUBLE, &d); push(opH); push(opL); }
int Xor::Execute(Processor* proc) { Operand* dst = mOperands[Operand::DST]; Operand* src = mOperands[Operand::SRC]; if(dst == 0 || src == 0) return -1; unsigned int val = dst->GetValue() ^ src->GetValue(); proc->SetFlag(FLAGS_OF, 0); proc->SetFlag(FLAGS_CF, 0); proc->SetFlag(FLAGS_ZF, val == 0); proc->SetFlag(FLAGS_PF, Parity(val)); proc->SetFlag(FLAGS_SF, val >= (dst->GetBitmask() == 0xFF ? 0x80 : 0x8000)); dst->SetValue(val); return 0; }
int Neg::Execute(Processor* proc) { Operand* dst = mOperands[Operand::DST]; if(!dst) { return INVALID_ARGS; } unsigned int dstVal = dst->GetValue(); unsigned int sign = dst->GetBitmask() == 0xFF ? 0x80 : 0x8000; proc->SetFlag(FLAGS_CF, dstVal != 0); proc->SetFlag(FLAGS_OF, dstVal == 0x80); //only overflow is -128 -> -128 dst->SetValue((~dstVal + 1) & dst->GetBitmask()); dstVal = dst->GetValue(); proc->SetFlag(FLAGS_SF, dstVal >= sign); proc->SetFlag(FLAGS_ZF, dstVal == 0x00); proc->SetFlag(FLAGS_PF, Parity(dstVal)); proc->SetFlag(FLAGS_AF, AdjustSub(dstVal, dstVal*2)); return 0; }