// StackSym::GetIntConstValue int32 StackSym::GetIntConstValue() const { Assert(this->IsIntConst()); IR::Instr *defInstr = this->m_instrDef; IR::Opnd *src1 = defInstr->GetSrc1(); if (src1->IsIntConstOpnd()) { Assert(defInstr->m_opcode == Js::OpCode::Ld_I4 || defInstr->m_opcode == Js::OpCode::LdC_A_I4 || defInstr->m_opcode == Js::OpCode::ArgOut_A_InlineBuiltIn || LowererMD::IsAssign(defInstr)); return src1->AsIntConstOpnd()->AsInt32(); } if (src1->IsAddrOpnd()) { Assert(defInstr->m_opcode == Js::OpCode::Ld_A || LowererMD::IsAssign(defInstr) || defInstr->m_opcode == Js::OpCode::ArgOut_A_InlineBuiltIn); IR::AddrOpnd *addr = src1->AsAddrOpnd(); Assert(addr->IsVar()); Js::Var var = src1->AsAddrOpnd()->m_address; if (Js::TaggedInt::Is(var)) { return Js::TaggedInt::ToInt32(var); } int32 value; const bool isInt32 = Js::JavascriptNumber::TryGetInt32Value(Js::JavascriptNumber::GetValue(var), &value); Assert(isInt32); return value; } Assert(src1->IsRegOpnd()); return src1->AsRegOpnd()->m_sym->GetIntConstValue(); }
BailoutConstantValue StackSym::GetConstValueForBailout() const { Assert(this->IsConst()); IR::Instr *defInstr = this->m_instrDef; IR::Opnd *src1 = defInstr->GetSrc1(); return src1->GetConstValue(); }
Js::Var StackSym::GetFloatConstValueAsVar_PostGlobOpt() const { Assert(this->IsConst()); IR::Instr *defInstr = this->m_instrDef; IR::Opnd *src1 = defInstr->GetSrc1(); StackSym * stackSym = nullptr; if (src1->IsRegOpnd()) { stackSym = src1->AsRegOpnd()->m_sym; Assert(!stackSym->m_isEncodedConstant); if (stackSym->m_isSingleDef) { //In ARM constant load is always legalized. Try to get the constant from src def defInstr = stackSym->m_instrDef; src1 = defInstr->GetSrc1(); } } Assert(this->IsFloatConst() || (stackSym && stackSym->IsFloatConst())); IR::AddrOpnd *addrOpnd; if (src1->IsAddrOpnd()) { Assert(defInstr->m_opcode == Js::OpCode::Ld_A); addrOpnd = src1->AsAddrOpnd(); } else { Assert(src1->IsFloatConstOpnd()); Assert(defInstr->m_opcode == Js::OpCode::LdC_A_R8); addrOpnd = src1->AsFloatConstOpnd()->GetAddrOpnd(defInstr->m_func); // This is just to prevent creating multiple numbers when the sym is used multiple times. We can only do this // post-GlobOpt, as otherwise it violates some invariants assumed in GlobOpt. defInstr->ReplaceSrc1(addrOpnd); defInstr->m_opcode = Js::OpCode::Ld_A; } const Js::Var address = addrOpnd->m_address; Assert(Js::JavascriptNumber::Is(address)); return address; }
IR::Opnd * StackSym::GetConstOpnd() const { Assert(IsConst()); IR::Instr *defInstr = this->m_instrDef; IR::Opnd *src1 = defInstr->GetSrc1(); if (!src1) { #if defined(_M_IX86) || defined(_M_X64) Assert(defInstr->m_opcode == Js::OpCode::MOVSD_ZERO); #else Assert(UNREACHED); #endif } else if (src1->IsIntConstOpnd()) { Assert(this->IsIntConst()); if (defInstr->m_opcode == Js::OpCode::LdC_A_I4) { src1 = IR::AddrOpnd::NewFromNumber(src1->AsIntConstOpnd()->GetValue(), defInstr->m_func); defInstr->ReplaceSrc1(src1); defInstr->m_opcode = Js::OpCode::Ld_A; } else { Assert(defInstr->m_opcode == Js::OpCode::Ld_I4 || LowererMD::IsAssign(defInstr) || defInstr->m_opcode == Js::OpCode::ArgOut_A_InlineBuiltIn); } } else if (src1->IsFloatConstOpnd()) { Assert(this->IsFloatConst()); Assert(defInstr->m_opcode == Js::OpCode::LdC_A_R8); src1 = src1->AsFloatConstOpnd()->GetAddrOpnd(defInstr->m_func); defInstr->ReplaceSrc1(src1); defInstr->m_opcode = Js::OpCode::Ld_A; } else if (src1->IsAddrOpnd()) { Assert(defInstr->m_opcode == Js::OpCode::Ld_A || LowererMD::IsAssign(defInstr) || defInstr->m_opcode == Js::OpCode::ArgOut_A_InlineBuiltIn); } else if (src1->IsMemRefOpnd()) { Assert(this->IsFloatConst() || this->IsSimd128Const()); } else { AssertMsg(UNREACHED, "Invalid const value"); } return src1; }
void *StackSym::GetConstAddress() const { Assert(this->IsConst()); IR::Instr *defInstr = this->m_instrDef; IR::Opnd *src1 = defInstr->GetSrc1(); StackSym * stackSym = nullptr; if (src1->IsRegOpnd()) { stackSym = src1->AsRegOpnd()->m_sym; Assert(!stackSym->m_isEncodedConstant); if (stackSym->m_isSingleDef) { //In ARM constant load is always legalized. Try to get the constant from src def defInstr = stackSym->m_instrDef; src1 = defInstr->GetSrc1(); } } Assert(src1->IsAddrOpnd()); Assert(defInstr->m_opcode == Js::OpCode::Ld_A || defInstr->m_opcode == Js::OpCode::LdStr || defInstr->m_opcode == Js::OpCode::ArgOut_A_InlineBuiltIn || LowererMD::IsAssign(defInstr)); return src1->AsAddrOpnd()->m_address; }
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; }
intptr_t StackSym::GetLiteralConstValue_PostGlobOpt() const { Assert(this->IsConst()); IR::Instr *defInstr = this->m_instrDef; IR::Opnd *src1 = defInstr->GetSrc1(); StackSym * stackSym = nullptr; if (src1->IsRegOpnd()) { stackSym = src1->AsRegOpnd()->m_sym; if (stackSym->m_isEncodedConstant) { Assert(!stackSym->m_isSingleDef); Assert(LowererMD::IsAssign(defInstr) || defInstr->m_opcode == Js::OpCode::ArgOut_A_InlineBuiltIn); return stackSym->constantValue; } if (stackSym->m_isSingleDef) { //In ARM constant load is always legalized. Try to get the constant from src def defInstr = stackSym->m_instrDef; src1 = defInstr->GetSrc1(); } } if (src1->IsAddrOpnd()) { Assert(defInstr->m_opcode == Js::OpCode::Ld_A || defInstr->m_opcode == Js::OpCode::LdStr || defInstr->m_opcode == Js::OpCode::ArgOut_A_InlineBuiltIn || LowererMD::IsAssign(defInstr)); return reinterpret_cast<intptr_t>(src1->AsAddrOpnd()->m_address); } if (src1->IsIntConstOpnd()) { Assert(this->IsIntConst() || (stackSym && stackSym->IsIntConst())); if (defInstr->m_opcode == Js::OpCode::LdC_A_I4) { IR::AddrOpnd *const addrOpnd = IR::AddrOpnd::NewFromNumber(src1->AsIntConstOpnd()->GetValue(), defInstr->m_func); const Js::Var address = addrOpnd->m_address; // This is just to prevent creating multiple numbers when the sym is used multiple times. We can only do this // post-GlobOpt, as otherwise it violates some invariants assumed in GlobOpt. defInstr->ReplaceSrc1(addrOpnd); defInstr->m_opcode = Js::OpCode::Ld_A; return reinterpret_cast<intptr_t>(address); } Assert(defInstr->m_opcode == Js::OpCode::Ld_I4 || LowererMD::IsAssign(defInstr) || defInstr->m_opcode == Js::OpCode::ArgOut_A_InlineBuiltIn); return src1->AsIntConstOpnd()->GetValue(); } if (src1->IsFloatConstOpnd()) { Assert(this->IsFloatConst() || (stackSym && stackSym->IsFloatConst())); Assert(defInstr->m_opcode == Js::OpCode::LdC_A_R8); IR::AddrOpnd *const addrOpnd = src1->AsFloatConstOpnd()->GetAddrOpnd(defInstr->m_func); const Js::Var address = addrOpnd->m_address; // This is just to prevent creating multiple numbers when the sym is used multiple times. We can only do this // post-GlobOpt, as otherwise it violates some invariants assumed in GlobOpt. defInstr->ReplaceSrc1(addrOpnd); defInstr->m_opcode = Js::OpCode::Ld_A; return reinterpret_cast<intptr_t>(address); } AssertMsg(UNREACHED, "Unknown const value"); return 0; }