From 090bc82fa2099734b3061fe10efd1e904f04bf1f Mon Sep 17 00:00:00 2001 From: hermanv Date: Sat, 30 Mar 2013 19:11:49 -0700 Subject: [PATCH] Specialized code generation for more of the ConvXxxToDbl instructions. Rather than using just two general purpose helpers, there are now some specialized helpers and more inline code. Also, the flags in ir.h are now more accurate. --- hphp/runtime/vm/translator/hopt/codegen.cpp | 70 ++++++++++++++++--- .../vm/translator/hopt/hhbctranslator.cpp | 1 + hphp/runtime/vm/translator/hopt/ir.cpp | 3 + hphp/runtime/vm/translator/hopt/ir.h | 19 +++-- 4 files changed, 76 insertions(+), 17 deletions(-) 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) \