void loadTV(Vout& v, const SSATmp* dst, Vloc dstLoc, Vptr src, bool aux /* = false */) { auto const type = dst->type(); if (dstLoc.isFullSIMD()) { // The whole TV is loaded into a single SIMD reg. assertx(RuntimeOption::EvalHHIRAllocSIMDRegs); v << loadups{src, dstLoc.reg()}; return; } if (type.needsReg()) { assertx(dstLoc.hasReg(1)); if (aux) { v << load{src + TVOFF(m_type), dstLoc.reg(1)}; } else { v << loadb{src + TVOFF(m_type), dstLoc.reg(1)}; } } if (type <= TBool) { v << loadtqb{src + TVOFF(m_data), dstLoc.reg(0)}; } else { v << load{src + TVOFF(m_data), dstLoc.reg(0)}; } }
void storeTV(Vout& v, Vptr dst, Vloc srcLoc, const SSATmp* src) { auto const type = src->type(); if (srcLoc.isFullSIMD()) { // The whole TV is stored in a single SIMD reg. assertx(RuntimeOption::EvalHHIRAllocSIMDRegs); v << storeups{srcLoc.reg(), dst}; return; } if (type.needsReg()) { assertx(srcLoc.hasReg(1)); v << storeb{srcLoc.reg(1), dst + TVOFF(m_type)}; } else { v << storeb{v.cns(type.toDataType()), dst + TVOFF(m_type)}; } // We ignore the values of statically nullish types. if (src->isA(TNull) || src->isA(TNullptr)) return; // Store the value. if (src->hasConstVal()) { // Skip potential zero-extend if we know the value. v << store{v.cns(src->rawVal()), dst + TVOFF(m_data)}; } else { assertx(srcLoc.hasReg(0)); auto const extended = zeroExtendIfBool(v, src->type(), srcLoc.reg(0)); v << store{extended, dst + TVOFF(m_data)}; } }
void copyTV(Vout& v, Vloc src, Vloc dst, Type destType) { auto src_arity = src.numAllocated(); auto dst_arity = dst.numAllocated(); if (dst_arity == 2) { always_assert(src_arity == 2); v << copy2{src.reg(0), src.reg(1), dst.reg(0), dst.reg(1)}; return; } always_assert(dst_arity == 1); if (src_arity == 2 && dst.isFullSIMD()) { pack2(v, src.reg(0), src.reg(1), dst.reg(0)); return; } always_assert(src_arity >= 1); if (src_arity == 2 && destType <= TBool) { v << movtqb{src.reg(0), dst.reg(0)}; } else { v << copy{src.reg(0), dst.reg(0)}; } }
void CodeGenerator::emitLoadTypedValue(Vout& v, Vloc dst, Vreg base, ptrdiff_t offset, Block* label) { if (label) not_implemented(); if (dst.isFullSIMD()) not_implemented(); auto valueDst = dst.reg(0); auto typeDst = dst.reg(1); // Avoid clobbering the base reg if we'll need it later if (base == typeDst && valueDst.isValid()) { auto tmp = v.makeReg(); v << copy{base, tmp}; base = tmp; } if (typeDst.isValid()) { v << loadzbl{base[offset + TVOFF(m_type)], typeDst}; } if (valueDst.isValid()) { v << load{base[offset + TVOFF(m_data)], valueDst}; } }
void copyTV(Vout& v, Vreg data, Vreg type, Vloc srcLoc, const SSATmp* src) { // SIMD register are not supported here. assertx(!srcLoc.isFullSIMD()); if (src->type().needsReg()) { assertx(srcLoc.hasReg(1)); v << copy{srcLoc.reg(1), type}; } else { v << copy{v.cns(src->type().toDataType()), type}; } // Ignore the values for nulls. if (src->isA(TNull)) return; if (src->hasConstVal()) { // Skip potential zero-extend if we know the value. v << copy{v.cns(src->rawVal()), data}; } else { assertx(srcLoc.hasReg(0)); auto const extended = zeroExtendIfBool(v, src->type(), srcLoc.reg(0)); v << copy{extended, data}; } }