Opnd* OpndUtils::getZeroConst(Type* type) { if (type->isDouble()) { return getDoubleZeroConst(); } if (type->isSingle()) { return getFloatZeroConst(); } if (type->isInt4()) { return getIntZeroConst(); } return m_irManager->newImmOpnd(type, 0); }
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; }