Index: vm/jitrino/src/codegenerator/ia32/Ia32IRManager.cpp =================================================================== --- vm/jitrino/src/codegenerator/ia32/Ia32IRManager.cpp (revision 538118) +++ vm/jitrino/src/codegenerator/ia32/Ia32IRManager.cpp (working copy) @@ -670,7 +670,10 @@ AliasPseudoInst * IRManager::newAliasPseudoInst(Opnd * targetOpnd, Opnd * sourceOpnd, uint32 offset) { assert(sourceOpnd->isPlacedIn(OpndKind_Memory)); - assert(!targetOpnd->hasAssignedPhysicalLocation()); + assert(!targetOpnd->hasAssignedPhysicalLocation() || + (targetOpnd->isPlacedIn(OpndKind_Memory) && + targetOpnd->getMemOpndKind() == sourceOpnd->getMemOpndKind()) + ); assert(targetOpnd->canBePlacedIn(OpndKind_Memory)); Type * sourceType=sourceOpnd->getType(); Index: vm/jitrino/src/codegenerator/ia32/Ia32I8Lowerer.cpp =================================================================== --- vm/jitrino/src/codegenerator/ia32/Ia32I8Lowerer.cpp (revision 538118) +++ vm/jitrino/src/codegenerator/ia32/Ia32I8Lowerer.cpp (working copy) @@ -150,6 +150,17 @@ return true; } /** + * performs original mnemonic action on the new operands + */ + void applyMnemonic(Inst* inst, Opnd* dst, Opnd* dst_1, Opnd* dst_2, + Opnd* src1, Opnd* src1_1, Opnd* src1_2, + Opnd* src2, Opnd* src2_1, Opnd* src2_2); + /** + * check if the opnd is a volatile field of long type + */ + bool I8Lowerer::isLongVolatileMemoryOpnd(Opnd* opnd); + + /** * Points to the list of instructions to process. * * The pointer points to the local variable in runImpl(); @@ -354,145 +365,214 @@ Opnd * src1 = useCount> 0 ? inst->getOpnd(defCount): NULL; Opnd * src2 = useCount> 1 ? inst->getOpnd(defCount+1): NULL; + Opnd* dstVolatile = NULL; + if (mn!=Mnemonic_IDIV && mn!=Mnemonic_IMUL) { - if (dst) - prepareNewOpnds(dst, dst_1,dst_2); - if (src1) - prepareNewOpnds(src1, src1_1,src1_2); - if (src2) - prepareNewOpnds(src2, src2_1,src2_2); - } - - switch(mn) { - case Mnemonic_ADD : - assert(dst_1 && src1_1 && src2_1); - assert(dst_2 && src1_2 && src2_2); - irManager->newInstEx(Mnemonic_ADD, 1, dst_1, src1_1, src2_1)->insertBefore(inst); - irManager->newInstEx(Mnemonic_ADC, 1, dst_2, src1_2, src2_2)->insertBefore(inst); - inst->unlink(); - break; - case Mnemonic_SUB : - assert(dst_1 && src1_1 && src2_1); - assert(dst_2 && src1_2 && src2_2); - irManager->newInstEx(Mnemonic_SUB, 1, dst_1, src1_1, src2_1)->insertBefore(inst); - irManager->newInstEx(Mnemonic_SBB, 1, dst_2, src1_2, src2_2)->insertBefore(inst); - inst->unlink(); - break; - case Mnemonic_AND : - case Mnemonic_OR : - case Mnemonic_XOR : - assert(dst_1 && src1_1 && src2_1); - assert(dst_2 && src1_2 && src2_2); - case Mnemonic_NOT : - assert(dst_1 && src1_1); - assert(dst_2 && src1_2); - irManager->newInstEx(mn, 1, dst_1, src1_1, src2_1)->insertBefore(inst); - irManager->newInstEx(mn, 1, dst_2, src1_2, src2_2)->insertBefore(inst); - inst->unlink(); - break; - case Mnemonic_MOV : - assert(dst_1 && src1_1); - irManager->newCopyPseudoInst(Mnemonic_MOV, dst_1, src1_1)->insertBefore(inst); - if (dst_2 && src1_2) { - irManager->newCopyPseudoInst(Mnemonic_MOV, dst_2, src1_2)->insertBefore(inst); + if (dst) { + if(isLongVolatileMemoryOpnd(dst)) { + // temporary dst placed on stack will be used in the original instruction + dstVolatile = dst; + dst = irManager->newMemOpnd(dst->getType(), MemOpndKind_StackAutoLayout, irManager->getRegOpnd(STACK_REG), 0); } - inst->unlink(); - break; - case Mnemonic_MOVSX : - case Mnemonic_MOVZX : - assert(dst_1 && dst_2 && src1_1); - assert(!src1_2); - if (src1_1->getSize()newInstEx(mn, 1, dst_1, src1_1)->insertBefore(inst); - }else{ - assert(src1_1->getSize()==OpndSize_32); - irManager->newInstEx(Mnemonic_MOV, 1, dst_1, src1_1)->insertBefore(inst); + prepareNewOpnds(dst,dst_1,dst_2); + if(isLongVolatileMemoryOpnd(dst)) { } - if (mn==Mnemonic_MOVSX){ - // It's possible to substitute complex CDQ with a tight - // constraints to the set of simpler instructions - // with a wider constraints to let more freedom - // to regalloc and constraint resolver. - // However, this seems does not change anything currently, - // so leaving as-is. - //test low, low - //setns hi ; if lo is positive, then load 1 into hi - //sub hi, 1 ; if lo is positive, then hi is now '0'. otherwise, it's -1 - irManager->newInstEx(Mnemonic_CDQ, 1, dst_2, dst_1)->insertBefore(inst); - } else { - //fill upper word with 0 - assert(mn == Mnemonic_MOVZX); - Opnd* imm0=irManager->newImmOpnd(irManager->getTypeManager().getInt32Type(), 0); - irManager->newInstEx(Mnemonic_MOV, 1, dst_2, imm0)->insertBefore(inst); - } - inst->unlink(); - break; - case Mnemonic_PUSH : - assert(src1_1); - assert(src1_2); - irManager->newInstEx(Mnemonic_PUSH, 0, src1_2)->insertBefore(inst); - irManager->newInstEx(Mnemonic_PUSH, 0, src1_1)->insertBefore(inst); - inst->unlink(); - break; - case Mnemonic_POP : - assert(dst_1); - assert(dst_2); - irManager->newInstEx(Mnemonic_POP, 1, dst_1)->insertBefore(inst); - irManager->newInstEx(Mnemonic_POP, 1, dst_2)->insertBefore(inst); - inst->unlink(); - break; - case Mnemonic_SHL : - { - assert(dst && src1 && src2); - buildShiftSubGraph(inst, src1_2, src1_1, src2, dst_2, dst_1, mn, Mnemonic_SHR); - inst->unlink(); - break; } - case Mnemonic_SHR : - case Mnemonic_SAR : - { - assert(dst && src1 && src2); - buildShiftSubGraph(inst, src1_1, src1_2, src2, dst_1, dst_2, mn, Mnemonic_SHL); - inst->unlink(); - break; - } - case Mnemonic_CMP : - { - assert(src1 && src2); - Inst * condInst = inst->getNextInst(); - while (condInst && condInst->getMnemonic() == Mnemonic_MOV) { - condInst = condInst->getNextInst(); + if (src1) { + Opnd* src1Volatile = NULL; + if(isLongVolatileMemoryOpnd(src1)) { + // read src1 -> XMM reg + // store XMM reg -> src1Volatile placed on stack + // substitue src1 with src1Volatile + Opnd* regXMM = irManager->newOpnd(src1->getType(),OpndKind_XMMReg); + src1Volatile = src1; + src1 = irManager->newMemOpnd(src1->getType(), MemOpndKind_StackAutoLayout, irManager->getRegOpnd(STACK_REG), 0); + irManager->newCopyPseudoInst(Mnemonic_MOV, regXMM, src1Volatile)->insertBefore(inst); + irManager->newCopyPseudoInst(Mnemonic_MOV, src1, regXMM)->insertBefore(inst); } - Mnemonic mnem = condInst ? getBaseConditionMnemonic(condInst->getMnemonic()) : Mnemonic_NULL; - if (mnem != Mnemonic_NULL) { - if(condInst->hasKind(Inst::Kind_BranchInst)) { - buildJumpSubGraph(inst,src1_1,src1_2,src2_1,src2_2,condInst); - } else { - buildSetSubGraph(inst,src1_1,src1_2,src2_1,src2_2,condInst); - } - } else { - buildComplexSubGraph(inst,src1_1,src1_2,src2_1,src2_2); + prepareNewOpnds(src1,src1_1,src1_2); + if(src1Volatile) { + irManager->newAliasPseudoInst(src1_1, src1, 0)->insertBefore(inst); + irManager->newAliasPseudoInst(src1_2, src1, 4)->insertBefore(inst); } - inst->unlink(); - break; } - case Mnemonic_IMUL: - lowerMul64(inst); - break; - case Mnemonic_IDIV: - if (isI8RemInst(inst)) { - lowerRem64(inst); + if (src2) { + Opnd* src2Volatile = NULL; + if(isLongVolatileMemoryOpnd(src2)) { + // read src2 -> XMM reg + // store XMM reg -> src2Volatile placed on stack + // substitue src2 with src2Volatile + Opnd* regXMM = irManager->newOpnd(src2->getType(),OpndKind_XMMReg); + src2Volatile = src2; + src2 = irManager->newMemOpnd(src2->getType(), MemOpndKind_StackAutoLayout, irManager->getRegOpnd(STACK_REG), 0); + irManager->newCopyPseudoInst(Mnemonic_MOV, regXMM, src2Volatile)->insertBefore(inst); + irManager->newCopyPseudoInst(Mnemonic_MOV, src2, regXMM)->insertBefore(inst); } - else { - lowerDiv64(inst); + prepareNewOpnds(src2,src2_1,src2_2); + if(src2Volatile) { + irManager->newAliasPseudoInst(src2_1, src2, 0)->insertBefore(inst); + irManager->newAliasPseudoInst(src2_2, src2, 4)->insertBefore(inst); } - break; - default : - assert(0); - }//end switch by mnemonics + } + } + + applyMnemonic(inst,dst,dst_1,dst_2,src1,src1_1,src1_2,src2,src2_1,src2_2); + + if(dstVolatile) { + // link dst sub opnds to the outer to protect them from DCE + Opnd * dst_sub_opnds[2]={ dst_1, dst_2 }; + irManager->newAliasPseudoInst(dst, 2, dst_sub_opnds)->insertBefore(inst); + // read dst -> XMM reg + // store XMM -> original dst (dstVolatile) + Opnd* regXMM = irManager->newOpnd(dst->getType(),OpndKind_XMMReg); + irManager->newCopyPseudoInst(Mnemonic_MOV, regXMM, dst)->insertBefore(inst); + irManager->newCopyPseudoInst(Mnemonic_MOV, dstVolatile, regXMM)->insertBefore(inst); + } + + inst->unlink(); + } } +bool I8Lowerer::isLongVolatileMemoryOpnd(Opnd* opnd) { + + if ( isI8Type(opnd->getType()) ) { + Opnd* disp = opnd->isPlacedIn(OpndKind_Memory) ? opnd->getMemOpndSubOpnd(MemOpndSubOpndKind_Displacement) : NULL; + Opnd::RuntimeInfo* ri = (disp == NULL) ? NULL : disp->getRuntimeInfo(); + Opnd::RuntimeInfo::Kind riKind = (ri == NULL) ? Opnd::RuntimeInfo::Kind_Null : ri->getKind(); + return (riKind == Opnd::RuntimeInfo::Kind_FieldOffset || + riKind == Opnd::RuntimeInfo::Kind_StaticFieldAddress) && + ((FieldDesc*)disp->getRuntimeInfo()->getValue(0))->isVolatile(); + } else { + return false; + } +} + + +void I8Lowerer::applyMnemonic(Inst* inst, Opnd* dst, Opnd* dst_1, Opnd* dst_2, + Opnd* src1, Opnd* src1_1, Opnd* src1_2, + Opnd* src2, Opnd* src2_1, Opnd* src2_2) +{ + Mnemonic mn = inst->getMnemonic(); + switch(mn) { + case Mnemonic_ADD : + assert(dst_1 && src1_1 && src2_1); + assert(dst_2 && src1_2 && src2_2); + irManager->newInstEx(Mnemonic_ADD, 1, dst_1, src1_1, src2_1)->insertBefore(inst); + irManager->newInstEx(Mnemonic_ADC, 1, dst_2, src1_2, src2_2)->insertBefore(inst); + break; + case Mnemonic_SUB : + assert(dst_1 && src1_1 && src2_1); + assert(dst_2 && src1_2 && src2_2); + irManager->newInstEx(Mnemonic_SUB, 1, dst_1, src1_1, src2_1)->insertBefore(inst); + irManager->newInstEx(Mnemonic_SBB, 1, dst_2, src1_2, src2_2)->insertBefore(inst); + break; + case Mnemonic_AND : + case Mnemonic_OR : + case Mnemonic_XOR : + assert(dst_1 && src1_1 && src2_1); + assert(dst_2 && src1_2 && src2_2); + case Mnemonic_NOT : + assert(dst_1 && src1_1); + assert(dst_2 && src1_2); + irManager->newInstEx(mn, 1, dst_1, src1_1, src2_1)->insertBefore(inst); + irManager->newInstEx(mn, 1, dst_2, src1_2, src2_2)->insertBefore(inst); + break; + case Mnemonic_MOV : + assert(dst_1 && src1_1); + irManager->newCopyPseudoInst(Mnemonic_MOV, dst_1, src1_1)->insertBefore(inst); + if (dst_2 && src1_2) { + irManager->newCopyPseudoInst(Mnemonic_MOV, dst_2, src1_2)->insertBefore(inst); + } + break; + case Mnemonic_MOVSX : + case Mnemonic_MOVZX : + assert(dst_1 && dst_2 && src1_1); + assert(!src1_2); + if (src1_1->getSize()newInstEx(mn, 1, dst_1, src1_1)->insertBefore(inst); + }else{ + assert(src1_1->getSize()==OpndSize_32); + irManager->newInstEx(Mnemonic_MOV, 1, dst_1, src1_1)->insertBefore(inst); + } + if (mn==Mnemonic_MOVSX){ + // It's possible to substitute complex CDQ with a tight + // constraints to the set of simpler instructions + // with a wider constraints to let more freedom + // to regalloc and constraint resolver. + // However, this seems does not change anything currently, + // so leaving as-is. + //test low, low + //setns hi ; if lo is positive, then load 1 into hi + //sub hi, 1 ; if lo is positive, then hi is now '0'. otherwise, it's -1 + irManager->newInstEx(Mnemonic_CDQ, 1, dst_2, dst_1)->insertBefore(inst); + } else { + //fill upper word with 0 + assert(mn == Mnemonic_MOVZX); + Opnd* imm0=irManager->newImmOpnd(irManager->getTypeManager().getInt32Type(), 0); + irManager->newInstEx(Mnemonic_MOV, 1, dst_2, imm0)->insertBefore(inst); + } + break; + case Mnemonic_PUSH : + assert(src1_1); + assert(src1_2); + irManager->newInstEx(Mnemonic_PUSH, 0, src1_2)->insertBefore(inst); + irManager->newInstEx(Mnemonic_PUSH, 0, src1_1)->insertBefore(inst); + break; + case Mnemonic_POP : + assert(dst_1); + assert(dst_2); + irManager->newInstEx(Mnemonic_POP, 1, dst_1)->insertBefore(inst); + irManager->newInstEx(Mnemonic_POP, 1, dst_2)->insertBefore(inst); + break; + case Mnemonic_SHL : + { + assert(dst && src1 && src2); + buildShiftSubGraph(inst, src1_2, src1_1, src2, dst_2, dst_1, mn, Mnemonic_SHR); + break; + } + case Mnemonic_SHR : + case Mnemonic_SAR : + { + assert(dst && src1 && src2); + buildShiftSubGraph(inst, src1_1, src1_2, src2, dst_1, dst_2, mn, Mnemonic_SHL); + break; + } + case Mnemonic_CMP : + { + assert(src1 && src2); + Inst * condInst = inst->getNextInst(); + while (condInst && condInst->getMnemonic() == Mnemonic_MOV) { + condInst = condInst->getNextInst(); + } + Mnemonic mnem = condInst ? getBaseConditionMnemonic(condInst->getMnemonic()) : Mnemonic_NULL; + if (mnem != Mnemonic_NULL) { + if(condInst->hasKind(Inst::Kind_BranchInst)) { + buildJumpSubGraph(inst,src1_1,src1_2,src2_1,src2_2,condInst); + } else { + buildSetSubGraph(inst,src1_1,src1_2,src2_1,src2_2,condInst); + } + } else { + buildComplexSubGraph(inst,src1_1,src1_2,src2_1,src2_2); + } + break; + } + case Mnemonic_IMUL: + lowerMul64(inst); + break; + case Mnemonic_IDIV: + if (isI8RemInst(inst)) { + lowerRem64(inst); + } + else { + lowerDiv64(inst); + } + break; + default : + assert(0); + } +} // applyMnemonic + void I8Lowerer::buildShiftSubGraph(Inst * inst, Opnd * src1_1, Opnd * src1_2, Opnd * src2, Opnd * dst_1, Opnd * dst_2, Mnemonic mnem, Mnemonic opMnem) { Opnd * dst1_1 = irManager->newOpnd(dst_2->getType()), * dst1_2 = irManager->newOpnd(dst_2->getType()),