Index: working_vm/vm/port/src/encoder/ia32_em64t/enc_defs.h =================================================================== --- working_vm/vm/port/src/encoder/ia32_em64t/enc_defs.h £¨ÐÞ¶©°æ 681003£© +++ working_vm/vm/port/src/encoder/ia32_em64t/enc_defs.h £¨¹¤×÷¿½±´£© @@ -617,12 +617,12 @@ CCM(SET,NLE), CCM(SET,G), Mnemonic_SAL, Mnemonic_SHL=Mnemonic_SAL,// Shift left -Mnemonic_SAR, // Unsigned shift right +Mnemonic_SAR, // Signed shift right Mnemonic_ROR, // Rotate right Mnemonic_RCR, // Rotate right through CARRY flag Mnemonic_ROL, // Rotate left Mnemonic_RCL, // Rotate left through CARRY flag -Mnemonic_SHR, // Signed shift right +Mnemonic_SHR, // Unsigned shift right Mnemonic_SHRD, // Double Precision Shift Right Mnemonic_SHLD, // Double Precision Shift Left Index: working_vm/vm/jitrino/src/codegenerator/ia32/Ia32InstCodeSelector.cpp =================================================================== --- working_vm/vm/jitrino/src/codegenerator/ia32/Ia32InstCodeSelector.cpp £¨ÐÞ¶©°æ 681003£© +++ working_vm/vm/jitrino/src/codegenerator/ia32/Ia32InstCodeSelector.cpp £¨¹¤×÷¿½±´£© @@ -804,7 +804,30 @@ return sub(ArithmeticOp::I4, ref1, ref2); } - +static long long getShiftBits(long long divisor) +{ + bool isPower = false; + int shiftBits = -1; + if((divisor & 1) == 1) { + isPower = true; + shiftBits = 0; + } + for(int i = 1; i < 64; i++) { + divisor >>= 1; + if((divisor & 1) == 1) { + if(isPower) { + isPower = false; + shiftBits = -1; + return -1; + } else { + isPower = true; + shiftBits = i; + } + } + } + return shiftBits; +} + //_______________________________________________________________________________________________________________ // Multiply numeric values @@ -812,8 +835,93 @@ CG_OpndHandle* src1, CG_OpndHandle* src2) { - Type * dstType; - Opnd * dst, * srcOpnd1, * srcOpnd2; + Type * dstType = NULL; + Opnd * dst = NULL; + Opnd * srcOpnd1 = NULL; + Opnd * srcOpnd2 = NULL; + + // for integer mul op, replace it with left shift if one of the two multipliers is a constant and a power of 2 + // isConst: 0 = no constants; 1 = first operand is constant; 2 = second operand is constant + int isConst = 0; + long long multiplier = ((Opnd*)src1)->getImmValue(); + if(multiplier != 0) { + isConst = 1; + } else { + multiplier = ((Opnd*)src2)->getImmValue(); + if(multiplier != 0) + isConst = 2; + } + + // check whether one of operands is constant AND is the power of 2 + bool doNegate = false; + if(multiplier < 0) { + doNegate = true; + multiplier = -multiplier; + } + + IntegerOp::Types shiftOpType; + long long shiftBits; + if(isConst != 0 && (-1 != (shiftBits = getShiftBits(multiplier))) && true ) { + switch(opType) { + case ArithmeticOp::I: + case ArithmeticOp::I4: + dstType = irManager.getTypeFromTag(Type::Int32); + shiftOpType = IntegerOp::I4; + break; + case ArithmeticOp::I8: + dstType = irManager.getTypeFromTag(Type::Int64); + shiftOpType = IntegerOp::I8; + break; + default: + // dummy ops to trick compiler warnings + shiftOpType = IntegerOp::I; + break; + } + + if (dstType != NULL) { + Opnd * srcOpnd1 = (Opnd*)convert(src1, dstType); + Opnd * srcOpnd2 = (Opnd*)convert(src2, dstType); + Opnd * newSrc; + + Opnd * shiftResult = NULL; + switch(isConst) { + case 1: + newSrc = irManager.newOpnd(dstType); + newSrc->assignImmValue(shiftBits); + shiftResult = shiftOp(shiftOpType, Mnemonic_SHL, srcOpnd2, newSrc); + break; + case 2: + newSrc = irManager.newOpnd(dstType); + newSrc->assignImmValue(shiftBits); + shiftResult = shiftOp(shiftOpType, Mnemonic_SHL, srcOpnd1, newSrc); + break; + } // switch + + if(doNegate) { + switch(opType) { + case ArithmeticOp::I: + case ArithmeticOp::I4: + dst = irManager.newOpnd(dstType); + appendInsts(irManager.newInstEx(Mnemonic_NEG, 1, dst, (Opnd*)convert(shiftResult, dstType))); + return dst; + default: //case ArithmeticOp::I8: + Opnd * dstMOV = irManager.newOpnd(dstType); + Opnd * src_null = irManager.newImmOpnd(dstType, 0); +#ifndef _EM64T_ + appendInsts(irManager.newI8PseudoInst(Mnemonic_MOV,1,dstMOV,src_null)); +#else + appendInsts(irManager.newInstEx(Mnemonic_MOV,1,dstMOV,src_null)); +#endif + dst = (Opnd *)sub(ArithmeticOp::I8, dstMOV, shiftResult); + return dst; + } + } else { + return shiftResult; + } + + } // type check + } + switch(opType){ case ArithmeticOp::I4: case ArithmeticOp::I: @@ -865,9 +973,108 @@ //_______________________________________________________________________________________________________________ Opnd * InstCodeSelector::divOp(DivOp::Types opType, bool rem, Opnd * src1, Opnd * src2) { - Opnd * dst=NULL; - Type * dstType; - Opnd * srcOpnd1, * srcOpnd2; + Opnd * dst = NULL; + Type * dstType = NULL; + Opnd * srcOpnd1 = NULL; + Opnd * srcOpnd2 = NULL; + + // for integer div op, replace it with right shift if the divisor is a constant and a power of 2 + // div: q = a / (1 << d); + // shift: q = (a + [(1 << d) - 1] & (a >> 31)) >> d; + IntegerOp::Types shiftAndOpType; + ArithmeticOp::Types addSubOpType; + + int maskShiftBits = 0; + long long divisor = src2->getImmValue(); + long long shiftBits; + + bool doNegate=false; + if(divisor < 0) { + doNegate = true; + divisor = -divisor; + } + + if(divisor != 0 && (-1 != (shiftBits = getShiftBits(divisor))) && true) { + switch(opType) { + case DivOp::I: + case DivOp::I4: + dstType = irManager.getTypeFromTag(Type::Int32); + shiftAndOpType = IntegerOp::I4; + addSubOpType = ArithmeticOp::I4; + maskShiftBits = 31; // 32 - 1 + break; + case DivOp::I8: + dstType = irManager.getTypeFromTag(Type::Int64); + shiftAndOpType = IntegerOp::I8; + addSubOpType = ArithmeticOp::I8; + maskShiftBits = 63; // 64 - 1 + break; + default: + // dummy ops to trick compiler warnings + shiftAndOpType = IntegerOp::I; + addSubOpType = ArithmeticOp::I; + break; + } + + if (dstType != NULL) { + Opnd * srcOpnd1 = (Opnd*)convert(src1, dstType); + + // quotinent requested + + Opnd * constMask = irManager.newOpnd(dstType); + constMask->assignImmValue(maskShiftBits); + Opnd * mask = (Opnd *)shr(shiftAndOpType, srcOpnd1, constMask); + + Opnd * const1 = irManager.newOpnd(dstType); + Opnd * shfBits = irManager.newOpnd(dstType); + const1->assignImmValue(1); + shfBits->assignImmValue(shiftBits); + Opnd * power = (Opnd *)shl(shiftAndOpType, const1, shfBits); + Opnd * span = (Opnd *)sub(addSubOpType, power, const1); + + Opnd * offset = (Opnd *)and_(shiftAndOpType, span, mask); + + Opnd * toBeShifted = (Opnd *)add(addSubOpType, srcOpnd1, offset); + + src2->assignImmValue(shiftBits); + Opnd * shiftResult = (Opnd *)shr(shiftAndOpType, toBeShifted, convert(src2, dstType)); + + if(doNegate) { + switch(opType) { + case DivOp::I: + case DivOp::I4: + dst = irManager.newOpnd(dstType); + appendInsts(irManager.newInstEx(Mnemonic_NEG, 1, dst, (Opnd*)convert(shiftResult, dstType))); + break; + default: //case DivOp::I8: + Opnd * dstMOV = irManager.newOpnd(dstType); + Opnd * src_null = irManager.newImmOpnd(dstType, 0); +#ifndef _EM64T_ + appendInsts(irManager.newI8PseudoInst(Mnemonic_MOV,1,dstMOV,src_null)); +#else + appendInsts(irManager.newInstEx(Mnemonic_MOV,1,dstMOV,src_null)); +#endif + dst = (Opnd *)sub(ArithmeticOp::I8, dstMOV, shiftResult); + break; + } + } else + dst = shiftResult; + + if(!rem) + return dst; + else { + // remainder requested + // do more for remainder + + Opnd * shiftResult2 = shiftOp(shiftAndOpType, Mnemonic_SHL, dst, convert(src2, dstType)); + if(!doNegate) + return (Opnd *)sub(addSubOpType, srcOpnd1, shiftResult2); + else + return (Opnd *)add(addSubOpType, srcOpnd1, shiftResult2); + } + } // type check + } // divisor != 0 + switch(opType){ case DivOp::I: case DivOp::I4: