bool GlobOpt::Simd128CanTypeSpecOpnd(const ValueType opndType, ValueType expectedType) { if (!opndType.IsSimd128() && !expectedType.IsSimd128()) { // Non-Simd types can be coerced or we bailout by a FromVar. return true; } // Simd type if (opndType.HasBeenNull() || opndType.HasBeenUndefined()) { return false; } if ( (opndType.IsLikelyObject() && opndType.ToDefiniteObject() == expectedType) || (opndType.IsLikelyObject() && opndType.GetObjectType() == ObjectType::Object) ) { return true; } return false; }
/* Handles all Simd128 type-spec of an instr, if possible. */ bool GlobOpt::TypeSpecializeSimd128( IR::Instr *instr, Value **pSrc1Val, Value **pSrc2Val, Value **pDstVal ) { if (this->GetIsAsmJSFunc() || SIMD128_TYPE_SPEC_FLAG == false) { // no type-spec for ASMJS code or flag is off. return false; } switch (instr->m_opcode) { case Js::OpCode::ArgOut_A_InlineBuiltIn: if (instr->GetSrc1()->IsRegOpnd()) { StackSym *sym = instr->GetSrc1()->AsRegOpnd()->m_sym; if (IsSimd128TypeSpecialized(sym, this->currentBlock)) { ValueType valueType = (*pSrc1Val)->GetValueInfo()->Type(); Assert(valueType.IsSimd128()); ToTypeSpecUse(instr, instr->GetSrc1(), this->currentBlock, *pSrc1Val, nullptr, GetIRTypeFromValueType(valueType), GetBailOutKindFromValueType(valueType)); return true; } } return false; case Js::OpCode::Ld_A: if (instr->GetSrc1()->IsRegOpnd()) { StackSym *sym = instr->GetSrc1()->AsRegOpnd()->m_sym; IRType type = TyIllegal; if (IsSimd128F4TypeSpecialized(sym, this->currentBlock)) { type = TySimd128F4; } else if (IsSimd128I4TypeSpecialized(sym, this->currentBlock)) { type = TySimd128I4; } else { return false; } ToTypeSpecUse(instr, instr->GetSrc1(), this->currentBlock, *pSrc1Val, nullptr, type, IR::BailOutSimd128F4Only /*not used for Ld_A*/); TypeSpecializeSimd128Dst(type, instr, *pSrc1Val, *pSrc1Val, pDstVal); return true; } return false; case Js::OpCode::ExtendArg_A: if (Simd128DoTypeSpec(instr, *pSrc1Val, *pSrc2Val, *pDstVal)) { Assert(instr->m_opcode == Js::OpCode::ExtendArg_A); Assert(instr->GetDst()->GetType() == TyVar); ValueType valueType = instr->GetDst()->GetValueType(); // Type-spec src1 only based on dst type. Dst type is set by the inliner based on func signature. ToTypeSpecUse(instr, instr->GetSrc1(), this->currentBlock, *pSrc1Val, nullptr, GetIRTypeFromValueType(valueType), GetBailOutKindFromValueType(valueType), true /*lossy*/); ToVarRegOpnd(instr->GetDst()->AsRegOpnd(), this->currentBlock); return true; } return false; } if (!Js::IsSimd128Opcode(instr->m_opcode)) { return false; } // Simd instr if (Simd128DoTypeSpec(instr, *pSrc1Val, *pSrc2Val, *pDstVal)) { ThreadContext::SimdFuncSignature simdFuncSignature; instr->m_func->GetScriptContext()->GetThreadContext()->GetSimdFuncSignatureFromOpcode(instr->m_opcode, simdFuncSignature); // type-spec logic // special handling for load/store // OptArraySrc will type-spec the array and the index. We type-spec the value here. if (Js::IsSimd128Load(instr->m_opcode)) { TypeSpecializeSimd128Dst(GetIRTypeFromValueType(simdFuncSignature.returnType), instr, nullptr, *pSrc1Val, pDstVal); Simd128SetIndirOpndType(instr->GetSrc1()->AsIndirOpnd(), instr->m_opcode); return true; } if (Js::IsSimd128Store(instr->m_opcode)) { ToTypeSpecUse(instr, instr->GetSrc1(), this->currentBlock, *pSrc1Val, nullptr, GetIRTypeFromValueType(simdFuncSignature.args[2]), GetBailOutKindFromValueType(simdFuncSignature.args[2])); Simd128SetIndirOpndType(instr->GetDst()->AsIndirOpnd(), instr->m_opcode); return true; } // For op with ExtendArg. All sources are already type-specialized, just type-specialize dst if (simdFuncSignature.argCount <= 2) { Assert(instr->GetSrc1()); ToTypeSpecUse(instr, instr->GetSrc1(), this->currentBlock, *pSrc1Val, nullptr, GetIRTypeFromValueType(simdFuncSignature.args[0]), GetBailOutKindFromValueType(simdFuncSignature.args[0])); if (instr->GetSrc2()) { ToTypeSpecUse(instr, instr->GetSrc2(), this->currentBlock, *pSrc2Val, nullptr, GetIRTypeFromValueType(simdFuncSignature.args[1]), GetBailOutKindFromValueType(simdFuncSignature.args[1])); } } if (instr->GetDst()) { TypeSpecializeSimd128Dst(GetIRTypeFromValueType(simdFuncSignature.returnType), instr, nullptr, *pSrc1Val, pDstVal); } return true; } else { // We didn't type-spec if (!IsLoopPrePass()) { // Emit bailout if not loop prepass. // The inliner inserts bytecodeUses of original args after the instruction. Bailout is safe. IR::Instr * bailoutInstr = IR::BailOutInstr::New(Js::OpCode::BailOnNoSimdTypeSpec, IR::BailOutNoSimdTypeSpec, instr, instr->m_func); bailoutInstr->SetByteCodeOffset(instr); instr->InsertAfter(bailoutInstr); instr->m_opcode = Js::OpCode::Nop; if (instr->GetSrc1()) { instr->FreeSrc1(); if (instr->GetSrc2()) { instr->FreeSrc2(); } } if (instr->GetDst()) { instr->FreeDst(); } if (this->byteCodeUses) { // All inlined SIMD ops have jitOptimizedReg srcs Assert(this->byteCodeUses->IsEmpty()); JitAdelete(this->alloc, this->byteCodeUses); this->byteCodeUses = nullptr; } RemoveCodeAfterNoFallthroughInstr(bailoutInstr); return true; } } return false; }