ArgDesc::ArgDesc(SSATmp* tmp, Vloc loc, bool val) { if (tmp->hasConstVal()) { // tmp is a constant if (val) { m_imm64 = tmp->rawVal(); } else { static_assert(offsetof(TypedValue, m_type) % 8 == 0, ""); m_imm64 = uint64_t(tmp->type().toDataType()); } m_kind = Kind::Imm; return; } if (val) { assertx(loc.reg(0) != InvalidReg); m_srcReg = loc.reg(0); m_kind = Kind::Reg; // zero extend any boolean value that we pass to the helper in case // the helper expects it (e.g., as TypedValue) if (tmp->isA(TBool)) m_zeroExtend = true; return; } if (tmp->numWords() > 1) { assertx(loc.reg(1) != InvalidReg); m_srcReg = loc.reg(1); // Since val is false then we're passing tmp's type. TypeReg lets // CodeGenerator know that the value might require some massaging // to be in the right format for the call. m_kind = Kind::TypeReg; return; } // arg is the (constant) type of a known-typed value. static_assert(offsetof(TypedValue, m_type) % 8 == 0, ""); m_imm64 = uint64_t(tmp->type().toDataType()); m_kind = Kind::Imm; }
void CodeGenerator::emitStoreTypedValue(Vout& v, Vreg base, ptrdiff_t offset, Vloc src) { assert(src.numWords() == 2); auto reg0 = src.reg(0); auto reg1 = src.reg(1); v << store{reg0, base[offset + TVOFF(m_data)]}; v << storeb{reg1, base[offset + TVOFF(m_type)]}; }
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 CodeGenerator::emitLoad(Vout& v, Type type, Vloc dst, Vreg base, ptrdiff_t offset, Block* label /* = nullptr */) { if (type.needsReg()) { return emitLoadTypedValue(v, dst, base, offset, label); } if (label) { not_implemented(); } auto data = dst.reg(); v << load{base[offset + TVOFF(m_data)], data}; }
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 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}; } }
ArgDesc::ArgDesc(SSATmp* tmp, Vloc loc, bool val) { if (tmp->hasConstVal()) { // tmp is a constant if (val) { m_imm64 = tmp->rawVal(); m_kind = Kind::Imm; } else { static_assert(offsetof(TypedValue, m_type) % 8 == 0, ""); m_typeImm = tmp->type().toDataType(); m_kind = Kind::TypeImm; } return; } if (val) { assertx(loc.reg(0) != InvalidReg); m_srcReg = loc.reg(0); m_kind = Kind::Reg; // zero extend any boolean value that we pass to the helper in case // the helper expects it (e.g., as TypedValue) if (tmp->isA(TBool)) m_zeroExtend = true; return; } if (tmp->numWords() > 1) { assertx(loc.reg(1) != InvalidReg); // val is false so we're passing tmp's type. m_srcReg = loc.reg(1); m_kind = Kind::Reg; return; } // arg is the (constant) type of a known-typed value. static_assert(offsetof(TypedValue, m_type) % 8 == 0, ""); m_typeImm = tmp->type().toDataType(); m_kind = Kind::TypeImm; }
void CodeGenerator::emitStore(Vout& v, Vreg base, ptrdiff_t offset, SSATmp* src, Vloc srcLoc, bool genStoreType /* = true */) { auto type = src->type(); if (type.needsReg()) { return emitStoreTypedValue(v, base, offset, srcLoc); } if (genStoreType) { auto dt = type.toDataType(); v << storeb{v.cns(dt), base[offset + TVOFF(m_type)]}; } if (type <= Type::Null) { return; } auto data = srcLoc.reg(); if (src->isA(Type::Bool)) { auto extended = v.makeReg(); v << movzbl{data, extended}; data = extended; } v << store{data, base[offset + 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)}; } }