diff --git a/hphp/runtime/vm/translator/hopt/codegen.cpp b/hphp/runtime/vm/translator/hopt/codegen.cpp index 78143493f..9637aac6e 100644 --- a/hphp/runtime/vm/translator/hopt/codegen.cpp +++ b/hphp/runtime/vm/translator/hopt/codegen.cpp @@ -1708,16 +1708,72 @@ void CodeGenerator::cgConvToBool(IRInstruction* inst) { } } +static int64_t arrayToDoubleHelper(ArrayData* value) { + union { + int64_t intval; + double dblval; + } u; + u.dblval = value->empty() ? 0 : 1; + return u.intval; +} + void CodeGenerator::cgConvArrToDbl(IRInstruction* inst) { - cgConvGenToDbl(inst); + SSATmp* dst = inst->getDst(); + SSATmp* src = inst->getSrc(0); + ArgGroup args; + args.ssa(src); + int64_t (*fPtr)(ArrayData*) = arrayToDoubleHelper; + cgCallHelper(m_as, (TCA)fPtr, dst, kNoSyncPoint, args); } void CodeGenerator::cgConvBoolToDbl(IRInstruction* inst) { - cgConvPrimitiveToDbl(inst); + // cvtsi2sd doesn't modify the high bits of its target, which can + // cause false dependencies to prevent register renaming from kicking + // in. Break the dependency chain by zeroing out xmm0. + m_as.pxor_xmm_xmm(xmm0, xmm0); + SSATmp* dst = inst->getDst(); + auto dstReg = dst->getReg(); + assert(dstReg != InvalidReg); + SSATmp* src = inst->getSrc(0); + auto srcReg = src->getReg(); + if (srcReg == InvalidReg) { + assert(src->isConst()); + int64_t constVal = src->getValRawInt(); + if (constVal == 0) { + m_as.xor_reg64_reg64(dstReg, dstReg); + } else { + m_as.mov_imm64_reg(1, dstReg); + } + } else { + m_as.movzbl(rbyte(srcReg), r32(dstReg)); + } + m_as.cvtsi2sd_reg64_xmm(dstReg, xmm0); + m_as.mov_xmm_reg64(xmm0, dstReg); } void CodeGenerator::cgConvIntToDbl(IRInstruction* inst) { - cgConvPrimitiveToDbl(inst); + // cvtsi2sd doesn't modify the high bits of its target, which can + // cause false dependencies to prevent register renaming from kicking + // in. Break the dependency chain by zeroing out xmm0. + m_as.pxor_xmm_xmm(xmm0, xmm0); + SSATmp* dst = inst->getDst(); + auto dstReg = dst->getReg(); + assert(dstReg != InvalidReg); + SSATmp* src = inst->getSrc(0); + auto srcReg = src->getReg(); + if (srcReg == InvalidReg) { + assert(src->isConst()); + int64_t constVal = src->getValRawInt(); + if (constVal == 0) { + m_as.xor_reg64_reg64(dstReg, dstReg); + } else { + m_as.mov_imm64_reg(constVal, dstReg); + } + m_as.cvtsi2sd_reg64_xmm(dstReg, xmm0); + } else { + m_as.cvtsi2sd_reg64_xmm(srcReg, xmm0); + } + m_as.mov_xmm_reg64(xmm0, dstReg); } void CodeGenerator::cgConvObjToDbl(IRInstruction* inst) { @@ -1743,14 +1799,6 @@ void CodeGenerator::cgConvGenToDbl(IRInstruction* inst) { cgCallHelper(m_as, (TCA)fPtr, dst, kSyncPoint, args); } -void CodeGenerator::cgConvPrimitiveToDbl(IRInstruction* inst) { - SSATmp* dst = inst->getDst(); - SSATmp* src = inst->getSrc(0); - prepUnaryXmmOp(m_as, src, xmm0); - m_as.mov_xmm_reg64(xmm0, dst->getReg()); - return; -} - void CodeGenerator::cgConvToInt(IRInstruction* inst) { Type fromType = inst->getSrc(0)->getType(); SSATmp* dst = inst->getDst(); diff --git a/hphp/runtime/vm/translator/hopt/hhbctranslator.cpp b/hphp/runtime/vm/translator/hopt/hhbctranslator.cpp index 72c593b09..a992f7a75 100644 --- a/hphp/runtime/vm/translator/hopt/hhbctranslator.cpp +++ b/hphp/runtime/vm/translator/hopt/hhbctranslator.cpp @@ -2046,6 +2046,7 @@ void HhbcTranslator::emitCastDouble() { push(m_tb->genDefConst(0.0)); } else if (fromType.isArray()) { push(m_tb->gen(ConvArrToDbl, src)); + m_tb->genDecRef(src); } else if (fromType.isBool()) { push(m_tb->gen(ConvBoolToDbl, src)); } else if (fromType.isInt()) { diff --git a/hphp/runtime/vm/translator/hopt/ir.cpp b/hphp/runtime/vm/translator/hopt/ir.cpp index d22e51a94..fb67121cc 100644 --- a/hphp/runtime/vm/translator/hopt/ir.cpp +++ b/hphp/runtime/vm/translator/hopt/ir.cpp @@ -454,6 +454,9 @@ bool IRInstruction::killsSource(int idx) const { case DecRef: case ConvObjToArr: case ConvGenToArr: + case ConvObjToDbl: + case ConvStrToDbl: + case ConvGenToDbl: assert(idx == 0); return true; case ArraySet: diff --git a/hphp/runtime/vm/translator/hopt/ir.h b/hphp/runtime/vm/translator/hopt/ir.h index 671914ed5..5ffcc1945 100644 --- a/hphp/runtime/vm/translator/hopt/ir.h +++ b/hphp/runtime/vm/translator/hopt/ir.h @@ -167,22 +167,29 @@ O(OpAnd, D(Int), SNumInt SNumInt, C) \ O(OpOr, D(Int), SNum SNum, C) \ O(OpXor, D(Int), SNumInt SNumInt, C) \ O(OpMul, DParam, SNum SNum, C) \ + \ O(ConvBoolToArr, D(Arr), S(Bool), C|N) \ O(ConvDblToArr, D(Arr), S(Dbl), C|N) \ O(ConvIntToArr, D(Arr), S(Int), C|N) \ O(ConvObjToArr, D(Arr), S(Obj), N|CRc|K) \ O(ConvStrToArr, D(Arr), S(Str), N|CRc) \ O(ConvGenToArr, D(Arr), S(Gen), N|CRc|K) \ + \ O(ConvToBool, D(Bool), S(Gen), C|N) \ -O(ConvArrToDbl, D(Dbl), S(Arr), N|CRc) \ -O(ConvBoolToDbl, D(Dbl), S(Bool), C|N) \ -O(ConvIntToDbl, D(Dbl), S(Int), C|N) \ -O(ConvObjToDbl, D(Dbl), S(Obj), N|Er|CRc) \ -O(ConvStrToDbl, D(Dbl), S(Str), N|CRc) \ -O(ConvGenToDbl, D(Dbl), S(Gen), N|Er|CRc) \ + \ +O(ConvArrToDbl, D(Dbl), S(Arr), N) \ +O(ConvBoolToDbl, D(Dbl), S(Bool), C|Rm) \ +O(ConvIntToDbl, D(Dbl), S(Int), C|Rm) \ +O(ConvObjToDbl, D(Dbl), S(Obj), N|Er|CRc|K) \ +O(ConvStrToDbl, D(Dbl), S(Str), N|CRc|K) \ +O(ConvGenToDbl, D(Dbl), S(Gen), N|Er|CRc|K) \ + \ O(ConvToInt, D(Int), S(Gen), C|N) \ + \ O(ConvToObj, D(Obj), S(Gen), C|N) \ + \ O(ConvToStr, D(Str), S(Gen), C|N) \ + \ O(ExtendsClass, D(Bool), S(Cls) C(Cls), C) \ O(IsTypeMem, D(Bool), S(PtrToGen), NA) \ O(IsNTypeMem, D(Bool), S(PtrToGen), NA) \