void StackSym::SetIsConst() { Assert(this->m_isSingleDef); Assert(this->m_instrDef); IR::Opnd * src = this->m_instrDef->GetSrc1(); Assert(src->IsImmediateOpnd() || src->IsFloatConstOpnd() || src->IsSimd128ConstOpnd()); if (src->IsIntConstOpnd()) { Assert(this->m_instrDef->m_opcode == Js::OpCode::Ld_I4 || this->m_instrDef->m_opcode == Js::OpCode::LdC_A_I4 || LowererMD::IsAssign(this->m_instrDef)); this->SetIsIntConst(src->AsIntConstOpnd()->GetValue()); } else if (src->IsFloatConstOpnd()) { Assert(this->m_instrDef->m_opcode == Js::OpCode::LdC_A_R8); this->SetIsFloatConst(); } else if (src->IsSimd128ConstOpnd()){ Assert(this->m_instrDef->m_opcode == Js::OpCode::Simd128_LdC); this->SetIsSimd128Const(); } else { Assert(this->m_instrDef->m_opcode == Js::OpCode::Ld_A || LowererMD::IsAssign(this->m_instrDef)); Assert(src->IsAddrOpnd()); IR::AddrOpnd * addrOpnd = src->AsAddrOpnd(); this->m_isConst = true; if (addrOpnd->IsVar()) { Js::Var var = addrOpnd->m_address; if (Js::TaggedInt::Is(var)) { this->m_isIntConst = true; this->m_isTaggableIntConst = true; } else if (var && Js::JavascriptNumber::Is(var) && Js::JavascriptNumber::IsInt32_NoChecks(var)) { this->m_isIntConst = true; } } } }
bool GlobOpt::Simd128DoTypeSpecLoadStore(IR::Instr *instr, const Value *src1Val, const Value *src2Val, const Value *dstVal, const ThreadContext::SimdFuncSignature *simdFuncSignature) { IR::Opnd *baseOpnd = nullptr, *indexOpnd = nullptr, *valueOpnd = nullptr; IR::Opnd *src, *dst; bool doTypeSpec = true; // value = Ld [arr + index] // [arr + index] = St value src = instr->GetSrc1(); dst = instr->GetDst(); Assert(dst && src && !instr->GetSrc2()); if (Js::IsSimd128Load(instr->m_opcode)) { Assert(src->IsIndirOpnd()); baseOpnd = instr->GetSrc1()->AsIndirOpnd()->GetBaseOpnd(); indexOpnd = instr->GetSrc1()->AsIndirOpnd()->GetIndexOpnd(); valueOpnd = instr->GetDst(); } else if (Js::IsSimd128Store(instr->m_opcode)) { Assert(dst->IsIndirOpnd()); baseOpnd = instr->GetDst()->AsIndirOpnd()->GetBaseOpnd(); indexOpnd = instr->GetDst()->AsIndirOpnd()->GetIndexOpnd(); valueOpnd = instr->GetSrc1(); // St(arr, index, value). Make sure value can be Simd128 type-spec'd doTypeSpec = doTypeSpec && Simd128CanTypeSpecOpnd(FindValue(valueOpnd->AsRegOpnd()->m_sym)->GetValueInfo()->Type(), simdFuncSignature->args[2]); } else { Assert(UNREACHED); } // array and index operands should have been type-specialized in OptArraySrc: ValueTypes should be definite at this point. If not, don't type-spec. // We can be in a loop prepass, where opnd ValueInfo is not set yet. Get the ValueInfo from the Value Table instead. ValueType baseOpndType = FindValue(baseOpnd->AsRegOpnd()->m_sym)->GetValueInfo()->Type(); if (IsLoopPrePass()) { doTypeSpec = doTypeSpec && (baseOpndType.IsObject() && baseOpndType.IsTypedArray()); // indexOpnd might be missing if loading from [0] if (indexOpnd != nullptr) { ValueType indexOpndType = FindValue(indexOpnd->AsRegOpnd()->m_sym)->GetValueInfo()->Type(); doTypeSpec = doTypeSpec && indexOpndType.IsLikelyInt(); } } else { doTypeSpec = doTypeSpec && (baseOpndType.IsObject() && baseOpndType.IsTypedArray()); if (indexOpnd != nullptr) { ValueType indexOpndType = FindValue(indexOpnd->AsRegOpnd()->m_sym)->GetValueInfo()->Type(); doTypeSpec = doTypeSpec && indexOpndType.IsInt(); } } return doTypeSpec; }
bool GlobOpt::Simd128DoTypeSpec(IR::Instr *instr, const Value *src1Val, const Value *src2Val, const Value *dstVal) { bool doTypeSpec = true; // TODO: Some operations require additional opnd constraints (e.g. shuffle/swizzle). if (Js::IsSimd128Opcode(instr->m_opcode)) { ThreadContext::SimdFuncSignature simdFuncSignature; instr->m_func->GetScriptContext()->GetThreadContext()->GetSimdFuncSignatureFromOpcode(instr->m_opcode, simdFuncSignature); if (!simdFuncSignature.valid) { // not implemented yet. return false; } // special handling for Load/Store if (Js::IsSimd128Load(instr->m_opcode) || Js::IsSimd128Store(instr->m_opcode)) { return Simd128DoTypeSpecLoadStore(instr, src1Val, src2Val, dstVal, &simdFuncSignature); } const uint argCount = simdFuncSignature.argCount; switch (argCount) { case 2: Assert(src2Val); doTypeSpec = doTypeSpec && Simd128CanTypeSpecOpnd(src2Val->GetValueInfo()->Type(), simdFuncSignature.args[1]) && Simd128ValidateIfLaneIndex(instr, instr->GetSrc2(), 1); // fall-through case 1: Assert(src1Val); doTypeSpec = doTypeSpec && Simd128CanTypeSpecOpnd(src1Val->GetValueInfo()->Type(), simdFuncSignature.args[0]) && Simd128ValidateIfLaneIndex(instr, instr->GetSrc1(), 0); break; default: { // extended args Assert(argCount > 2); // Check if all args have been type specialized. int arg = argCount - 1; IR::Instr * eaInstr = GetExtendedArg(instr); while (arg>=0) { Assert(eaInstr); Assert(eaInstr->m_opcode == Js::OpCode::ExtendArg_A); ValueType expectedType = simdFuncSignature.args[arg]; IR::Opnd * opnd = eaInstr->GetSrc1(); StackSym * sym = opnd->GetStackSym(); // In Forward Prepass: Check liveness through liveness bits, not IR type, since in prepass no actual type-spec happens. // In the Forward Pass: Check IRType since Sym can be null, because of const prop. if (expectedType.IsSimd128Float32x4()) { if (sym && !IsSimd128F4TypeSpecialized(sym, ¤tBlock->globOptData) || !sym && opnd->GetType() != TySimd128F4) { return false; } } else if (expectedType.IsSimd128Int32x4()) { if (sym && !IsSimd128I4TypeSpecialized(sym, ¤tBlock->globOptData) || !sym && opnd->GetType() != TySimd128I4) { return false; } } else if (expectedType.IsFloat()) { if (sym && !IsFloat64TypeSpecialized(sym, ¤tBlock->globOptData) || !sym&& opnd->GetType() != TyFloat64) { return false; } } else if (expectedType.IsInt()) { if ((sym && !IsInt32TypeSpecialized(sym, ¤tBlock->globOptData) && !currentBlock->globOptData.liveLossyInt32Syms->Test(sym->m_id)) || !sym && opnd->GetType() != TyInt32) { return false; } // Extra check if arg is a lane index if (!Simd128ValidateIfLaneIndex(instr, opnd, arg)) { return false; } } else { Assert(UNREACHED); } eaInstr = GetExtendedArg(eaInstr); arg--; } // all args are type-spec'd doTypeSpec = true; } } } else { Assert(instr->m_opcode == Js::OpCode::ExtendArg_A); // For ExtendArg, the expected type is encoded in the dst(link) operand. doTypeSpec = doTypeSpec && Simd128CanTypeSpecOpnd(src1Val->GetValueInfo()->Type(), instr->GetDst()->GetValueType()); } return doTypeSpec; }
void LegalizeMD::LegalizeDst(IR::Instr * instr, bool fPostRegAlloc) { LegalForms forms = LegalDstForms(instr); IR::Opnd * opnd = instr->GetDst(); if (opnd == NULL) { #ifdef DBG // No legalization possible, just report error. if (forms != 0) { IllegalInstr(instr, L"Expected dst opnd"); } #endif return; } switch (opnd->GetKind()) { case IR::OpndKindReg: #ifdef DBG // No legalization possible, just report error. if (!(forms & L_RegMask)) { IllegalInstr(instr, L"Unexpected reg dst"); } #endif break; case IR::OpndKindMemRef: { // MemRefOpnd is a deference of the memory location. // So extract the location, load it to register, replace the MemRefOpnd with an IndirOpnd taking the // register as base, and fall through to legalize the IndirOpnd. void *memLoc = opnd->AsMemRefOpnd()->GetMemLoc(); IR::RegOpnd *newReg = IR::RegOpnd::New(TyMachPtr, instr->m_func); if (fPostRegAlloc) { newReg->SetReg(SCRATCH_REG); } IR::Instr *newInstr = IR::Instr::New(Js::OpCode::LDIMM, newReg, IR::AddrOpnd::New(memLoc, opnd->AsMemRefOpnd()->GetAddrKind(), instr->m_func, true), instr->m_func); instr->InsertBefore(newInstr); LegalizeMD::LegalizeInstr(newInstr, fPostRegAlloc); IR::IndirOpnd *indirOpnd = IR::IndirOpnd::New(newReg, 0, opnd->GetType(), instr->m_func); opnd = instr->ReplaceDst(indirOpnd); } // FALL THROUGH case IR::OpndKindIndir: if (!(forms & L_IndirMask)) { instr = LegalizeStore(instr, forms, fPostRegAlloc); forms = LegalDstForms(instr); } LegalizeIndirOffset(instr, opnd->AsIndirOpnd(), forms, fPostRegAlloc); break; case IR::OpndKindSym: if (!(forms & L_SymMask)) { instr = LegalizeStore(instr, forms, fPostRegAlloc); forms = LegalDstForms(instr); } if (fPostRegAlloc) { // In order to legalize SymOffset we need to know final argument area, which is only available after lowerer. // So, don't legalize sym offset here, but it will be done as part of register allocator. LegalizeSymOffset(instr, opnd->AsSymOpnd(), forms, fPostRegAlloc); } break; default: AssertMsg(UNREACHED, "Unexpected dst opnd kind"); break; } }
void PeepsMD::PeepAssign(IR::Instr *instr) { IR::Opnd* dst = instr->GetDst(); IR::Opnd* src = instr->GetSrc1(); if(dst->IsRegOpnd() && instr->m_opcode == Js::OpCode::MOV) { if (src->IsImmediateOpnd() && src->GetImmediateValue(instr->m_func) == 0) { Assert(instr->GetSrc2() == NULL); // 32-bit XOR has a smaller encoding if (TySize[dst->GetType()] == MachPtr) { dst->SetType(TyInt32); } instr->m_opcode = Js::OpCode::XOR; instr->ReplaceSrc1(dst); instr->SetSrc2(dst); } else if (!instr->isInlineeEntryInstr) { if(src->IsIntConstOpnd() && src->GetSize() <= TySize[TyUint32]) { dst->SetType(TyUint32); } else if(src->IsAddrOpnd() && (((size_t)src->AsAddrOpnd()->m_address >> 32) == 0 )) { instr->ReplaceSrc1(IR::IntConstOpnd::New(::Math::PointerCastToIntegral<UIntConstType>(src->AsAddrOpnd()->m_address), TyUint32, instr->m_func)); dst->SetType(TyUint32); } } } else if (((instr->m_opcode == Js::OpCode::MOVSD || instr->m_opcode == Js::OpCode::MOVSS)