Index: vm/port/src/encoder/ia32_em64t/enc_defs.h =================================================================== --- vm/port/src/encoder/ia32_em64t/enc_defs.h (revision 671441) +++ vm/port/src/encoder/ia32_em64t/enc_defs.h (working copy) @@ -604,12 +604,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: vm/jitrino/src/codegenerator/ia32/Ia32InstCodeSelector.cpp =================================================================== --- vm/jitrino/src/codegenerator/ia32/Ia32InstCodeSelector.cpp (revision 671441) +++ vm/jitrino/src/codegenerator/ia32/Ia32InstCodeSelector.cpp (working copy) @@ -788,6 +788,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 @@ -796,8 +820,79 @@ CG_OpndHandle* src1, CG_OpndHandle* src2) { - Type * dstType; + Type * dstType = NULL; Opnd * dst, * srcOpnd1, * srcOpnd2; + + // 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; + } + + IntegerOp::Types shiftOpType; + + // check whether one of operands is constant AND is the power of 2 + // + bool doNegate = false; + if(multiplier < 0) { + doNegate = true; + multiplier = -multiplier; + } + + 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; +#if 0 +//Problem exists with I8PseudoInst + case ArithmeticOp::I8: + dstType = irManager.getTypeFromTag(Type::Int64); + shiftOpType = IntegerOp::I8; + break; +#endif + 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 * shiftResult = NULL; + switch(isConst) { + case 1: + srcOpnd1->assignImmValue(shiftBits); + shiftResult = shiftOp(shiftOpType, Mnemonic_SHL, srcOpnd2, srcOpnd1); + break; + case 2: + srcOpnd2->assignImmValue(shiftBits); + shiftResult = shiftOp(shiftOpType, Mnemonic_SHL, srcOpnd1, srcOpnd2); + break; + } // switch + + if(doNegate) { + dst = irManager.newOpnd(dstType); + appendInsts(irManager.newInstEx(Mnemonic_NEG, 1, dst, (Opnd*)convert(shiftResult, dstType))); + return dst; + } else { + return shiftResult; + } + + } // type check + } + switch(opType){ case ArithmeticOp::I4: case ArithmeticOp::I: @@ -849,9 +944,95 @@ //_______________________________________________________________________________________________________________ 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 == 16 && 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; +#if 0 +//Problem exists with I8PseudoInst + case DivOp::I8: + dstType = irManager.getTypeFromTag(Type::Int64); + shiftAndOpType = IntegerOp::I8; + addSubOpType = ArithmeticOp::I8; + maskShiftBits = 63; // 64 - 1 + break; +#endif + 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) { + dst = irManager.newOpnd(dstType); + appendInsts(irManager.newInstEx(Mnemonic_NEG, 1, dst, (Opnd*)convert(shiftResult, dstType))); + } else + dst = shiftResult; + + if(!rem) + return dst; + else { + // remainder requested + // do more for remainder + + Opnd * shiftResult2 = (Opnd *)shl(shiftAndOpType, dst, convert(src2, dstType)); + return (Opnd *)sub(addSubOpType, srcOpnd1, shiftResult2); + } + } // type check + } // divisor != 0 + switch(opType){ case DivOp::I: case DivOp::I4: