PeepHoleOpt::Changed PeepHoleOpt::handleInst_Convert_F2I_D2I(Inst* inst) { // // Inline 'int_value = (int)(float_value or double_value)' // Opnd* dst = inst->getOpnd(0); Opnd* src = inst->getOpnd(2); Type* srcType = src->getType(); assert(srcType->isSingle() || srcType->isDouble()); assert(dst->getType()->isInt4()); const bool is_dbl = srcType->isDouble(); // Here, we might have to deal with 3 cases with src (_value): // 1. Unassigned operand - act as if were operating with XMM // 2. Assigned to FPU - convert to FPU operations, to // avoid long FPU->mem->XMM chain // 3. Assigned to XMM - see #1 const bool xmm_way = !(src->hasAssignedPhysicalLocation() && src->isPlacedIn(OpndKind_FPReg)); if (!xmm_way) { //TODO: will add FPU later if measurements show it worths trying return Changed_Nothing; } // // /* movss xmm0, val // presuming the corner cases (NaN, overflow) // normally happen rare, do conversion first, // and check for falls later -- convertNode cvttss2si eax, xmm0 -- ovfTestNode // did overflow happen ? cmp eax, 0x80000000 jne _done // no - go return result -- testAgainstZeroNode // test SRC against zero comiss xmm0, [fp_zero] // isNaN ? jp _nan // yes - go load 0 -- testIfBelowNode // xmm < 0 ? jb _done // yes - go load MIN_INT. EAX already has it - simply return. -- loadMaxIntNode // ok. at this point, XMM is positive and > MAX_INT // must load MAX_INT which is 0x7fffffff. // As EAX has 0x80000000, then simply substract 1 sub eax, 1 jmp _done -- loadZeroNode _nan: xor eax, eax -- nodeNode _done: mov result, eax } */ Opnd* fpZeroOpnd = getZeroConst(srcType); Type* int32type = irManager->getTypeManager().getInt32Type(); Opnd* oneOpnd = irManager->newImmOpnd(int32type, 1); Opnd* intZeroOpnd = getIntZeroConst(); // 0x8..0 here is not the INT_MIN, but comes from the COMISS // opcode description instead. Opnd* minIntOpnd = irManager->newImmOpnd(int32type, 0x80000000); newSubGFG(); Node* entryNode = getSubCfgEntryNode(); Node* convertNode = newBB(); Node* ovfTestNode = newBB(); Node* testAgainstZeroNode = newBB(); Node* testIfBelowNode = newBB(); Node* loadMaxIntNode = newBB(); Node* loadZeroNode = newBB(); Node* doneNode = newBB(); // // presuming the corner cases (NaN, overflow) // normally happen rare, do conversion first, // and check for falls later // connectNodes(entryNode, convertNode); // // convert // setCurrentNode(convertNode) ; Mnemonic mn_cvt = is_dbl ? Mnemonic_CVTTSD2SI : Mnemonic_CVTTSS2SI; /*cvttss2si r32, xmm*/ newInst(mn_cvt, 1, dst, src); connectNodeTo(ovfTestNode); setCurrentNode(NULL); // // check whether overflow happened // setCurrentNode(ovfTestNode); /*cmp r32, MIN_INT*/ newInst(Mnemonic_CMP, dst, minIntOpnd); /*jne _done */ newBranch(Mnemonic_JNE, doneNode, testAgainstZeroNode, 0.9, 0.1); // setCurrentNode(NULL); // test SRC against zero // setCurrentNode(testAgainstZeroNode); Mnemonic mn_cmp = is_dbl ? Mnemonic_UCOMISD : Mnemonic_UCOMISS; /*comiss src, 0. */ newInst(mn_cmp, src, fpZeroOpnd); /*jp _nan:result=0*/ newBranch(Mnemonic_JP, loadZeroNode, testIfBelowNode); setCurrentNode(NULL); // // // setCurrentNode(loadZeroNode); /*mov r32, 0*/ newInst(Mnemonic_MOV, dst, intZeroOpnd); /*jmp _done*/ connectNodeTo(doneNode); setCurrentNode(NULL); // // test if we have a huge negative in SRC // setCurrentNode(testIfBelowNode); /*jb _done:*/ newBranch(Mnemonic_JB, doneNode, loadMaxIntNode); setCurrentNode(NULL); // // // setCurrentNode(loadMaxIntNode); /* sub dst, 1*/ newInst(Mnemonic_SUB, dst, oneOpnd); connectNodeTo(doneNode); setCurrentNode(NULL); // connectNodes(doneNode, getSubCfgReturnNode()); // propagateSubCFG(inst); return Changed_Node; }
//___________________________________________________________________________________________________ void EarlyPropagation::runImpl() { irManager->updateLoopInfo(); U_32 opndCount=irManager->getOpndCount(); MemoryManager mm("early_prop"); OpndInfo * opndInfos = new(mm) OpndInfo[opndCount]; Node * currentLoopHeader = NULL; bool anyInstHandled=false; LoopTree* lt = irManager->getFlowGraph()->getLoopTree(); const Nodes& postOrdered = irManager->getFlowGraph()->getNodesPostOrder(); for (Nodes::const_reverse_iterator it = postOrdered.rbegin(), end = postOrdered.rend(); it!=end; ++it) { Node * node=*it; if (!node->isBlockNode()) { continue; } Node * loopHeader = lt->getLoopHeader(node, false); if (currentLoopHeader != loopHeader){ currentLoopHeader = loopHeader; for (U_32 i = 0; i < opndCount; ++i) if (opndInfos[i].sourceOpndId != EmptyUint32) opndInfos[i].defCount++; } for (Inst * inst = (Inst*)node->getFirstInst(); inst != NULL; inst=inst->getNextInst()){ bool assignedOpndPropagated = false; Inst::Opnds opnds(inst, Inst::OpndRole_All); for (Inst::Opnds::iterator it = opnds.begin(); it != opnds.end(); it = opnds.next(it)){ Opnd * opnd=inst->getOpnd(it); U_32 roles=inst->getOpndRoles(it); U_32 opndId = opnd->getId(); OpndInfo& opndInfo = opndInfos[opndId]; U_32 mask = 0; if (roles & Inst::OpndRole_Def){ ++opndInfo.defCount; }else if (roles & Inst::OpndRole_Use){ if (opndInfo.sourceOpndId != EmptyUint32){ if (opndInfo.sourceOpndDefCountAtCopy < opndInfos[opndInfo.sourceOpndId].defCount) opndInfo.sourceOpndId = EmptyUint32; else{ Opnd * srcOpnd = irManager->getOpnd(opndInfo.sourceOpndId); Constraint co = srcOpnd->getConstraint(Opnd::ConstraintKind_Location); if (co.getKind() == OpndKind_Mem){ mask = (1<<it)-1; if ((roles & Inst::OpndRole_Explicit) == 0 || inst->hasKind(Inst::Kind_PseudoInst) || irManager->isGCSafePoint(inst) || opndInfo.sourceInst != inst->getPrevInst() || assignedOpndPropagated || (inst->getConstraint(it, mask, co.getSize())&co).isNull() ) opndInfo.sourceOpndId = EmptyUint32; assignedOpndPropagated = true; } } } } if (opndInfo.defCount > 1){ opndInfo.sourceOpndId = EmptyUint32; } } /* Here is the previous version to test whether the inst is copy or not. bool isCopy = inst->getMnemonic() == Mnemonic_MOV ||( (inst->getMnemonic() == Mnemonic_ADD || inst->getMnemonic() == Mnemonic_SUB) && inst->getOpnd(3)->isPlacedIn(OpndKind_Imm) && inst->getOpnd(3)->getImmValue()==0 && inst->getOpnd(3)->getRuntimeInfo()==NULL ); It considered special case of 'dst = src +/- 0' as copy. In fact there are more similar cases like 'IMUL src, 1 ; shift src, 0' etc. Such checks are obsolete now, Should as peephole takes care about such copies. Anyway, the code above had a bug: 'inst->getOpnd(3)' crashes in instructions in native form (like ADD def_use, use). */ const bool isCopy = inst->getMnemonic() == Mnemonic_MOV; if (isCopy){ // CopyPseudoInst or mov Opnd * defOpnd = inst->getOpnd(0); Opnd * srcOpnd = inst->getOpnd(1); U_32 defOpndId = defOpnd->getId(); OpndInfo * opndInfo = opndInfos + defOpndId; bool instHandled=false; bool typeConvOk = isTypeConversionAllowed(srcOpnd, defOpnd); if (typeConvOk && opndInfo->defCount == 1 && ! srcOpnd->isPlacedIn(OpndKind_Reg)){ if (!defOpnd->hasAssignedPhysicalLocation()){ opndInfo->sourceInst = inst; opndInfo->sourceOpndId = srcOpnd->getId(); instHandled=true; } } if (instHandled){ if (opndInfos[opndInfo->sourceOpndId].sourceOpndId != EmptyUint32) opndInfo->sourceOpndId = opndInfos[opndInfo->sourceOpndId].sourceOpndId; opndInfo->sourceOpndDefCountAtCopy = opndInfos[opndInfo->sourceOpndId].defCount; anyInstHandled=true; } } } } if (anyInstHandled){ Opnd ** replacements = new(mm) Opnd* [opndCount]; memset(replacements, 0, sizeof(Opnd*) * opndCount); bool hasReplacements = false; for (U_32 i = 0; i < opndCount; ++i){ if (opndInfos[i].sourceOpndId != EmptyUint32){ Inst * inst = opndInfos[i].sourceInst; if (inst !=NULL){ inst->unlink(); } if (opndInfos[i].sourceOpndId != i){ Opnd* origOpnd= irManager->getOpnd(i); Opnd* replacementOpnd = irManager->getOpnd(opndInfos[i].sourceOpndId); assert(isTypeConversionAllowed(replacementOpnd, origOpnd)); if (origOpnd->getType()->isUnmanagedPtr() && replacementOpnd->getType()->isInteger()) { replacementOpnd->setType(origOpnd->getType()); }/* else if (origOpnd->getType()->isObject() && replacementOpnd->getType()->isUnmanagedPtr()) { replacementOpnd->setType(origOpnd->getType()); }*/ replacements[i] = replacementOpnd; hasReplacements = true; } } } if (hasReplacements){ const Nodes& postOrdered = irManager->getFlowGraph()->getNodesPostOrder(); for (Nodes::const_reverse_iterator it = postOrdered.rbegin(), end = postOrdered.rend(); it!=end; ++it) { Node * node=*it; if (!node->isBlockNode()) { continue; } for (Inst * inst = (Inst*)node->getFirstInst(); inst != NULL; inst=inst->getNextInst()){ inst->replaceOpnds(replacements); } } } } }
PeepHoleOpt::Changed PeepHoleOpt::handleInst(Inst* inst) { PeepHoleOpt::Changed temp; // Local propagation Inst::Opnds opnds(inst, Inst::OpndRole_All); for (Inst::Opnds::iterator it=opnds.begin();it != opnds.end();it = opnds.next(it)) { Opnd * opnd=inst->getOpnd(it); U_32 roles=inst->getOpndRoles(it); if (roles & Inst::OpndRole_Use) { if ((roles & Inst::OpndRole_All & Inst::OpndRole_FromEncoder) && (roles & Inst::OpndRole_All & Inst::OpndRole_ForIterator) && (roles & Inst::OpndRole_Changeable) && ((roles & Inst::OpndRole_Def) == 0) && copyMap->has(opnd)) { if (opnd->getType()->isUnmanagedPtr() && (*copyMap)[opnd]->getType()->isInteger()) (*copyMap)[opnd]->setType(opnd->getType()); inst->setOpnd(it, (*copyMap)[opnd]); } } } for (Inst::Opnds::iterator it = opnds.begin();it != opnds.end();it = opnds.next(it)) { Opnd * opnd=inst->getOpnd(it); U_32 roles=inst->getOpndRoles(it); if (roles & Inst::OpndRole_Def) { if (copyMap->has(opnd)) { if (Log::isEnabled()) Log::out()<<"copy relation DELETED: " << opnd->getFirstId() << "<=" << (*copyMap)[opnd]->getFirstId() <<std::endl; copyMap->erase(opnd); } tempSet->clear(); for(StlHashMap<Opnd*, Opnd*>::iterator iter=copyMap->begin(); iter!=copyMap->end();++iter) if (iter->second == opnd) { if (Log::isEnabled()) Log::out()<<"copy relation DELETED: " << iter->first->getFirstId() << "<=" << iter->second->getFirstId() <<std::endl; tempSet->insert(iter->first); } for(StlSet<Opnd*>::iterator iter=tempSet->begin(); iter!=tempSet->end();++iter) copyMap->erase(*iter); } } if (inst->getMnemonic() == Mnemonic_MOV) { Inst::Opnds opnds(inst, Inst::OpndRole_All); Opnd * dst = NULL; Opnd * src = NULL; U_32 counterDef = 0; U_32 counterUse = 0; for (Inst::Opnds::iterator it=opnds.begin();it!=opnds.end();it=opnds.next(it)) { Opnd * opnd = inst->getOpnd(it); U_32 roles = inst->getOpndRoles(it); if (roles & Inst::OpndRole_Def) { counterDef++; dst = opnd; } else if (roles & Inst::OpndRole_Use) { counterUse++; src = opnd; } } if ((counterDef == 1) && (counterUse == 1) && (!dst->hasAssignedPhysicalLocation())) { bool kindsAreOk = true; if(src->canBePlacedIn(OpndKind_FPReg) || dst->canBePlacedIn(OpndKind_FPReg)) { Constraint srcConstr = src->getConstraint(Opnd::ConstraintKind_Calculated); Constraint dstConstr = dst->getConstraint(Opnd::ConstraintKind_Calculated); kindsAreOk = ! (srcConstr&dstConstr).isNull(); } bool typeConvOk = src->getSize() == dst->getSize() && isTypeConversionAllowed(src, dst); if (typeConvOk && kindsAreOk && ! src->isPlacedIn(OpndKind_Reg)) { if (copyMap->has(src)) { (*copyMap)[dst] = (*copyMap)[src]; if (Log::isEnabled()) Log::out()<<"copy relation INSERTED: " << dst->getFirstId() << "<=" << (*copyMap)[src]->getFirstId() <<std::endl; } else { (*copyMap)[dst] = src; if (Log::isEnabled()) Log::out()<<"copy relation INSERTED: " << dst->getFirstId() << "<=" << src->getFirstId() <<std::endl; } } } } if (inst->hasKind(Inst::Kind_PseudoInst) && inst->getKind() != Inst::Kind_CopyPseudoInst) { return Changed_Nothing; } Mnemonic mnemonic = inst->getMnemonic(); switch(mnemonic) { case Mnemonic_MOV: return handleInst_MOV(inst); case Mnemonic_CALL: return handleInst_Call(inst); case Mnemonic_ADD: case Mnemonic_ADC: case Mnemonic_SUB: case Mnemonic_SBB: case Mnemonic_NOT: case Mnemonic_AND: case Mnemonic_OR: case Mnemonic_XOR: case Mnemonic_TEST: return handleInst_ALU(inst); case Mnemonic_CMP: temp = handleInst_CMP(inst); if ( temp == Changed_Nothing ) { return handleInst_ALU(inst); } else { return temp; } case Mnemonic_SETG: case Mnemonic_SETE: case Mnemonic_SETNE: case Mnemonic_SETL: return handleInst_SETcc(inst); case Mnemonic_IMUL: case Mnemonic_MUL: return handleInst_MUL(inst); case Mnemonic_MOVSS: case Mnemonic_MOVSD: //return handleInst_SSEMov(inst); case Mnemonic_XORPS: case Mnemonic_XORPD: //return handleInst_SSEXor(inst); default: break; } return Changed_Nothing; }