| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668 |
- //-------------------------------------------------------------------------------------------------------
- // Copyright (C) Microsoft. All rights reserved.
- // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
- //-------------------------------------------------------------------------------------------------------
- #include "Backend.h"
- #define GET_SIMDOPCODE(irOpcode) m_simd128OpCodesMap[(uint32)(irOpcode - Js::OpCode::Simd128_Start)]
- #define SET_SIMDOPCODE(irOpcode, mdOpcode) \
- Assert((uint32)m_simd128OpCodesMap[(uint32)(Js::OpCode::irOpcode - Js::OpCode::Simd128_Start)] == 0); \
- Assert(Js::OpCode::mdOpcode > Js::OpCode::MDStart); \
- m_simd128OpCodesMap[(uint32)(Js::OpCode::irOpcode - Js::OpCode::Simd128_Start)] = Js::OpCode::mdOpcode;
- IR::Instr* LowererMD::Simd128Instruction(IR::Instr *instr)
- {
- // Currently only handles type-specialized/asm.js opcodes
- if (!instr->GetDst())
- {
- // SIMD ops always have DST in asmjs
- Assert(!instr->m_func->GetJnFunction()->GetIsAsmjsMode());
- // unused result. Do nothing.
- IR::Instr * pInstr = instr->m_prev;
- instr->Remove();
- return pInstr;
- }
- if (Simd128TryLowerMappedInstruction(instr))
- {
- return instr->m_prev;
- }
- return Simd128LowerUnMappedInstruction(instr);
- }
- bool LowererMD::Simd128TryLowerMappedInstruction(IR::Instr *instr)
- {
- bool legalize = true;
- Js::OpCode opcode = GET_SIMDOPCODE(instr->m_opcode);
- if ((uint32)opcode == 0)
- return false;
- Assert(instr->GetDst() && instr->GetDst()->IsRegOpnd() && instr->GetDst()->IsSimd128() || instr->GetDst()->GetType() == TyInt32);
- Assert(instr->GetSrc1() && instr->GetSrc1()->IsRegOpnd() && instr->GetSrc1()->IsSimd128());
- Assert(!instr->GetSrc2() || (((instr->GetSrc2()->IsRegOpnd() && instr->GetSrc2()->IsSimd128()) || (instr->GetSrc2()->IsIntConstOpnd() && instr->GetSrc2()->GetType() == TyInt8))));
- switch (instr->m_opcode)
- {
- case Js::OpCode::Simd128_Abs_F4:
- Assert(opcode == Js::OpCode::ANDPS);
- instr->SetSrc2(IR::MemRefOpnd::New((void*)&X86_ABS_MASK_F4, instr->GetSrc1()->GetType(), m_func));
- break;
- case Js::OpCode::Simd128_Abs_D2:
- Assert(opcode == Js::OpCode::ANDPD);
- instr->SetSrc2(IR::MemRefOpnd::New((void*)&X86_ABS_MASK_D2, instr->GetSrc1()->GetType(), m_func));
- break;
- case Js::OpCode::Simd128_Neg_F4:
- Assert(opcode == Js::OpCode::XORPS);
- instr->SetSrc2(IR::MemRefOpnd::New((void*)&X86_NEG_MASK_F4, instr->GetSrc1()->GetType(), m_func));
- break;
- case Js::OpCode::Simd128_Neg_D2:
- Assert(opcode == Js::OpCode::XORPS);
- instr->SetSrc2(IR::MemRefOpnd::New((void*)&X86_NEG_MASK_D2, instr->GetSrc1()->GetType(), m_func));
- break;
- case Js::OpCode::Simd128_Not_F4:
- case Js::OpCode::Simd128_Not_I4:
- Assert(opcode == Js::OpCode::XORPS);
- instr->SetSrc2(IR::MemRefOpnd::New((void*)&X86_ALL_NEG_ONES, instr->GetSrc1()->GetType(), m_func));
- break;
- case Js::OpCode::Simd128_Gt_F4:
- case Js::OpCode::Simd128_Gt_D2:
- case Js::OpCode::Simd128_GtEq_F4:
- case Js::OpCode::Simd128_GtEq_D2:
- case Js::OpCode::Simd128_Lt_I4:
- {
- Assert(opcode == Js::OpCode::CMPLTPS || opcode == Js::OpCode::CMPLTPD || opcode == Js::OpCode::CMPLEPS || opcode == Js::OpCode::CMPLEPD || opcode == Js::OpCode::PCMPGTD);
- // swap operands
- auto *src1 = instr->UnlinkSrc1();
- auto *src2 = instr->UnlinkSrc2();
- instr->SetSrc1(src2);
- instr->SetSrc2(src1);
- break;
- }
- case Js::OpCode::Simd128_LdSignMask_F4:
- case Js::OpCode::Simd128_LdSignMask_I4:
- case Js::OpCode::Simd128_LdSignMask_D2:
- legalize = false;
- break;
- }
- instr->m_opcode = opcode;
- if (legalize)
- {
- //MakeDstEquSrc1(instr);
- Legalize(instr);
- }
- return true;
- }
- IR::Instr* LowererMD::Simd128LowerUnMappedInstruction(IR::Instr *instr)
- {
- switch (instr->m_opcode)
- {
- case Js::OpCode::Simd128_LdC:
- return Simd128LoadConst(instr);
- case Js::OpCode::Simd128_FloatsToF4:
- case Js::OpCode::Simd128_IntsToI4:
- case Js::OpCode::Simd128_DoublesToD2:
- return Simd128LowerConstructor(instr);
- case Js::OpCode::Simd128_ExtractLane_I4:
- case Js::OpCode::Simd128_ExtractLane_F4:
- return Simd128LowerLdLane(instr);
- case Js::OpCode::Simd128_ReplaceLane_I4:
- case Js::OpCode::Simd128_ReplaceLane_F4:
- return SIMD128LowerReplaceLane(instr);
- case Js::OpCode::Simd128_Splat_F4:
- case Js::OpCode::Simd128_Splat_I4:
- case Js::OpCode::Simd128_Splat_D2:
- return Simd128LowerSplat(instr);
- case Js::OpCode::Simd128_Rcp_F4:
- case Js::OpCode::Simd128_Rcp_D2:
- return Simd128LowerRcp(instr);
- case Js::OpCode::Simd128_Sqrt_F4:
- case Js::OpCode::Simd128_Sqrt_D2:
- return Simd128LowerSqrt(instr);
- case Js::OpCode::Simd128_RcpSqrt_F4:
- case Js::OpCode::Simd128_RcpSqrt_D2:
- return Simd128LowerRcpSqrt(instr);
- case Js::OpCode::Simd128_Select_F4:
- case Js::OpCode::Simd128_Select_I4:
- case Js::OpCode::Simd128_Select_D2:
- return Simd128LowerSelect(instr);
- case Js::OpCode::Simd128_Neg_I4:
- return Simd128LowerNegI4(instr);
- case Js::OpCode::Simd128_Mul_I4:
- return Simd128LowerMulI4(instr);
- case Js::OpCode::Simd128_LdArr_I4:
- case Js::OpCode::Simd128_LdArr_F4:
- case Js::OpCode::Simd128_LdArr_D2:
- case Js::OpCode::Simd128_LdArrConst_I4:
- case Js::OpCode::Simd128_LdArrConst_F4:
- case Js::OpCode::Simd128_LdArrConst_D2:
- if (m_func->m_workItem->GetFunctionBody()->GetIsAsmjsMode())
- {
- // with bound checks
- return Simd128AsmJsLowerLoadElem(instr);
- }
- else
- {
- // non-AsmJs, boundChecks are extracted from instr
- return Simd128LowerLoadElem(instr);
- }
-
- case Js::OpCode::Simd128_StArr_I4:
- case Js::OpCode::Simd128_StArr_F4:
- case Js::OpCode::Simd128_StArr_D2:
- case Js::OpCode::Simd128_StArrConst_I4:
- case Js::OpCode::Simd128_StArrConst_F4:
- case Js::OpCode::Simd128_StArrConst_D2:
- if (m_func->m_workItem->GetFunctionBody()->GetIsAsmjsMode())
- {
- return Simd128AsmJsLowerStoreElem(instr);
- }
- else
- {
- return Simd128LowerStoreElem(instr);
- }
- case Js::OpCode::Simd128_Swizzle_I4:
- case Js::OpCode::Simd128_Swizzle_F4:
- case Js::OpCode::Simd128_Swizzle_D2:
- return Simd128LowerSwizzle4(instr);
- case Js::OpCode::Simd128_Shuffle_I4:
- case Js::OpCode::Simd128_Shuffle_F4:
- case Js::OpCode::Simd128_Shuffle_D2:
- return Simd128LowerShuffle4(instr);
- case Js::OpCode::Simd128_FromFloat32x4_I4:
- return Simd128LowerInt32x4FromFloat32x4(instr);
- default:
- AssertMsg(UNREACHED, "Unsupported Simd128 instruction");
- }
- return nullptr;
- }
- IR::Instr* LowererMD::Simd128LoadConst(IR::Instr* instr)
- {
- Assert(instr->GetDst() && instr->m_opcode == Js::OpCode::Simd128_LdC);
- if (instr->GetDst()->IsSimd128())
- {
- Assert(instr->GetSrc1()->IsSimd128());
- Assert(instr->GetSrc1()->IsSimd128ConstOpnd());
- Assert(instr->GetSrc2() == nullptr);
- AsmJsSIMDValue value = instr->GetSrc1()->AsSimd128ConstOpnd()->m_value;
- // MOVUPS dst, [const]
- AsmJsSIMDValue *pValue = NativeCodeDataNew(instr->m_func->GetNativeCodeDataAllocator(), AsmJsSIMDValue);
- pValue->SetValue(value);
- IR::Opnd * opnd = IR::MemRefOpnd::New((void *)pValue, instr->GetDst()->GetType(), instr->m_func);
- instr->ReplaceSrc1(opnd);
- instr->m_opcode = LowererMDArch::GetAssignOp(instr->GetDst()->GetType());
- Legalize(instr);
- return instr->m_prev;
- }
- else
- {
- AssertMsg(UNREACHED, "Non-typespecialized form of Simd128_LdC is unsupported");
- }
- return nullptr;
- }
- IR::Instr* LowererMD::Simd128LowerConstructor(IR::Instr *instr)
- {
- IR::Opnd* dst = nullptr;
- IR::Opnd* src1 = nullptr;
- IR::Opnd* src2 = nullptr;
- IR::Opnd* src3 = nullptr;
- IR::Opnd* src4 = nullptr;
- IR::Instr* newInstr = nullptr;
- if (instr->m_opcode == Js::OpCode::Simd128_FloatsToF4 || instr->m_opcode == Js::OpCode::Simd128_IntsToI4)
- {
- // use MOVSS for both int32x4 and float32x4. MOVD zeroes upper bits.
- Js::OpCode movOpcode = Js::OpCode::MOVSS;
- Js::OpCode shiftOpcode = Js::OpCode::PSLLDQ;
- SList<IR::Opnd*> *args = Simd128GetExtendedArgs(instr);
- // The number of src opnds should be exact. If opnds are missing, they should be filled in by globopt during type-spec.
- Assert(args->Count() == 5);
- dst = args->Pop();
- src1 = args->Pop();
- src2 = args->Pop();
- src3 = args->Pop();
- src4 = args->Pop();
- if (instr->m_opcode == Js::OpCode::Simd128_FloatsToF4)
- {
- // We don't have f32 type-spec, so we type-spec to f64 and convert to f32 before use.
- if (src1->IsFloat64())
- {
- IR::RegOpnd *regOpnd32 = IR::RegOpnd::New(TyFloat32, this->m_func);
- // CVTSD2SS regOpnd32.f32, src.f64 -- Convert regOpnd from f64 to f32
- newInstr = IR::Instr::New(Js::OpCode::CVTSD2SS, regOpnd32, src1, this->m_func);
- instr->InsertBefore(newInstr);
- src1 = regOpnd32;
- }
- if (src2->IsFloat64())
- {
- IR::RegOpnd *regOpnd32 = IR::RegOpnd::New(TyFloat32, this->m_func);
- // CVTSD2SS regOpnd32.f32, src.f64 -- Convert regOpnd from f64 to f32
- newInstr = IR::Instr::New(Js::OpCode::CVTSD2SS, regOpnd32, src2, this->m_func);
- instr->InsertBefore(newInstr);
- src2 = regOpnd32;
- }
- if (src3->IsFloat64())
- {
- IR::RegOpnd *regOpnd32 = IR::RegOpnd::New(TyFloat32, this->m_func);
- // CVTSD2SS regOpnd32.f32, src.f64 -- Convert regOpnd from f64 to f32
- newInstr = IR::Instr::New(Js::OpCode::CVTSD2SS, regOpnd32, src3, this->m_func);
- instr->InsertBefore(newInstr);
- src3 = regOpnd32;
- }
- if (src4->IsFloat64())
- {
- IR::RegOpnd *regOpnd32 = IR::RegOpnd::New(TyFloat32, this->m_func);
- // CVTSD2SS regOpnd32.f32, src.f64 -- Convert regOpnd from f64 to f32
- newInstr = IR::Instr::New(Js::OpCode::CVTSD2SS, regOpnd32, src4, this->m_func);
- instr->InsertBefore(newInstr);
- src4 = regOpnd32;
- }
- Assert(src1->IsRegOpnd() && src1->GetType() == TyFloat32);
- Assert(src2->IsRegOpnd() && src2->GetType() == TyFloat32);
- Assert(src3->IsRegOpnd() && src3->GetType() == TyFloat32);
- Assert(src4->IsRegOpnd() && src4->GetType() == TyFloat32);
- // MOVSS dst, src4
- instr->InsertBefore(IR::Instr::New(movOpcode, dst, src4, m_func));
- // PSLLDQ dst, dst, 4
- instr->InsertBefore(IR::Instr::New(shiftOpcode, dst, dst, IR::IntConstOpnd::New(4, TyInt8, m_func, true), m_func));
- // MOVSS dst, src3
- instr->InsertBefore(IR::Instr::New(movOpcode, dst, src3, m_func));
- // PSLLDQ dst, 4
- instr->InsertBefore(IR::Instr::New(shiftOpcode, dst, dst, IR::IntConstOpnd::New(4, TyInt8, m_func, true), m_func));
- // MOVSS dst, src2
- instr->InsertBefore(IR::Instr::New(movOpcode, dst, src2, m_func));
- // PSLLDQ dst, 4
- instr->InsertBefore(IR::Instr::New(shiftOpcode, dst, dst, IR::IntConstOpnd::New(4, TyInt8, m_func, true), m_func));
- // MOVSS dst, src1
- instr->InsertBefore(IR::Instr::New(movOpcode, dst, src1, m_func));
- }
- else
- {
- //Simd128_IntsToI4
- // b-namost: better way to implement this on SSE2? Using MOVD directly zeroes upper bits.
- IR::RegOpnd *temp = IR::RegOpnd::New(TyFloat32, m_func);
- // src's might have been constant prop'd. Enregister them if so.
- src4 = EnregisterIntConst(instr, src4);
- src3 = EnregisterIntConst(instr, src3);
- src2 = EnregisterIntConst(instr, src2);
- src1 = EnregisterIntConst(instr, src1);
- Assert(src1->GetType() == TyInt32 && src1->IsRegOpnd());
- Assert(src2->GetType() == TyInt32 && src2->IsRegOpnd());
- Assert(src3->GetType() == TyInt32 && src3->IsRegOpnd());
- Assert(src4->GetType() == TyInt32 && src4->IsRegOpnd());
- // MOVD t(TyFloat32), src4(TyInt32)
- instr->InsertBefore(IR::Instr::New(Js::OpCode::MOVD, temp, src4, m_func));
- // MOVSS dst, t
- instr->InsertBefore(IR::Instr::New(movOpcode, dst, temp, m_func));
- // PSLLDQ dst, dst, 4
- instr->InsertBefore(IR::Instr::New(shiftOpcode, dst, dst, IR::IntConstOpnd::New(TySize[TyInt32], TyInt8, m_func, true), m_func));
- // MOVD t(TyFloat32), sr34(TyInt32)
- instr->InsertBefore(IR::Instr::New(Js::OpCode::MOVD, temp, src3, m_func));
- // MOVSS dst, t
- instr->InsertBefore(IR::Instr::New(movOpcode, dst, temp, m_func));
- // PSLLDQ dst, dst, 4
- instr->InsertBefore(IR::Instr::New(shiftOpcode, dst, dst, IR::IntConstOpnd::New(TySize[TyInt32], TyInt8, m_func, true), m_func));
- // MOVD t(TyFloat32), src2(TyInt32)
- instr->InsertBefore(IR::Instr::New(Js::OpCode::MOVD, temp, src2, m_func));
- // MOVSS dst, t
- instr->InsertBefore(IR::Instr::New(movOpcode, dst, temp, m_func));
- // PSLLDQ dst, dst, 4
- instr->InsertBefore(IR::Instr::New(shiftOpcode, dst, dst, IR::IntConstOpnd::New(TySize[TyInt32], TyInt8, m_func, true), m_func));
- // MOVD t(TyFloat32), src1(TyInt32)
- instr->InsertBefore(IR::Instr::New(Js::OpCode::MOVD, temp, src1, m_func));
- // MOVSS dst, t
- instr->InsertBefore(IR::Instr::New(movOpcode, dst, temp, m_func));
- }
- }
- else
- {
- Assert(instr->m_opcode == Js::OpCode::Simd128_DoublesToD2);
- dst = instr->GetDst();
- src1 = instr->GetSrc1();
- src2 = instr->GetSrc2();
- Assert(src1->IsRegOpnd() && src1->GetType() == TyFloat64);
- Assert(src2->IsRegOpnd() && src2->GetType() == TyFloat64);
- // MOVSD dst, src2
- instr->InsertBefore(IR::Instr::New(Js::OpCode::MOVSD, dst, src2, m_func));
- // PSLLDQ dst, dst, 8
- instr->InsertBefore(IR::Instr::New(Js::OpCode::PSLLDQ, dst, dst, IR::IntConstOpnd::New(TySize[TyFloat64], TyInt8, m_func, true), m_func));
- // MOVSD dst, src1
- instr->InsertBefore(IR::Instr::New(Js::OpCode::MOVSD, dst, src1, m_func));
- }
- Assert(dst->IsRegOpnd() && dst->IsSimd128());
- IR::Instr* prevInstr;
- prevInstr = instr->m_prev;
- instr->Remove();
- return prevInstr;
- }
- IR::Instr* LowererMD::Simd128LowerLdLane(IR::Instr *instr)
- {
- IR::Opnd* dst, *src1, *src2;
- Js::OpCode movOpcode = Js::OpCode::MOVSS;
- uint laneSize = 0, laneIndex = 0;
- dst = instr->GetDst();
- src1 = instr->GetSrc1();
- src2 = instr->GetSrc2();
- Assert(dst && dst->IsRegOpnd() && (dst->GetType() == TyFloat32 || dst->GetType() == TyInt32 || dst->GetType() == TyFloat64));
- Assert(src1 && src1->IsRegOpnd() && src1->IsSimd128());
- Assert(src2 && src2->IsIntConstOpnd());
- laneIndex = (uint)src2->AsIntConstOpnd()->AsUint32();
- switch (instr->m_opcode)
- {
- case Js::OpCode::Simd128_ExtractLane_F4:
- laneSize = 4;
- movOpcode = Js::OpCode::MOVSS;
- Assert(laneIndex < 4);
- break;
- case Js::OpCode::Simd128_ExtractLane_I4:
- laneSize = 4;
- movOpcode = Js::OpCode::MOVD;
- Assert(laneIndex < 4);
- break;
- default:
- Assert(UNREACHED);
- }
- IR::Opnd* tmp = src1;
- if (laneIndex != 0)
- {
- // tmp = PSRLDQ src1, shamt
- tmp = IR::RegOpnd::New(src1->GetType(), m_func);
- IR::Instr *shiftInstr = IR::Instr::New(Js::OpCode::PSRLDQ, tmp, src1, IR::IntConstOpnd::New(laneSize * laneIndex, TyInt8, m_func, true), m_func);
- instr->InsertBefore(shiftInstr);
- //MakeDstEquSrc1(shiftInstr);
- Legalize(shiftInstr);
- }
- // MOVSS/MOVSD/MOVD dst, tmp
- instr->InsertBefore(IR::Instr::New(movOpcode, dst, tmp, m_func));
- IR::Instr* prevInstr = instr->m_prev;
- instr->Remove();
- return prevInstr;
- }
- IR::Instr* LowererMD::Simd128LowerSplat(IR::Instr *instr)
- {
- Js::OpCode shufOpCode = Js::OpCode::SHUFPS, movOpCode = Js::OpCode::MOVSS;
- IR::Opnd *dst, *src1;
- dst = instr->GetDst();
- src1 = instr->GetSrc1();
- Assert(dst && dst->IsRegOpnd() && dst->IsSimd128());
- Assert(src1 && src1->IsRegOpnd() && (src1->GetType() == TyFloat32 || src1->GetType() == TyInt32 || src1->GetType() == TyFloat64));
- Assert(!instr->GetSrc2());
- switch (instr->m_opcode)
- {
- case Js::OpCode::Simd128_Splat_F4:
- shufOpCode = Js::OpCode::SHUFPS;
- movOpCode = Js::OpCode::MOVSS;
- break;
- case Js::OpCode::Simd128_Splat_I4:
- shufOpCode = Js::OpCode::PSHUFD;
- movOpCode = Js::OpCode::MOVD;
- break;
- case Js::OpCode::Simd128_Splat_D2:
- shufOpCode = Js::OpCode::SHUFPD;
- movOpCode = Js::OpCode::MOVSD;
- break;
- default:
- Assert(UNREACHED);
- }
- if (instr->m_opcode == Js::OpCode::Simd128_Splat_F4 && instr->GetSrc1()->IsFloat64())
- {
- IR::RegOpnd *regOpnd32 = IR::RegOpnd::New(TyFloat32, this->m_func);
- // CVTSD2SS regOpnd32.f32, src.f64 -- Convert regOpnd from f64 to f32
- instr->InsertBefore(IR::Instr::New(Js::OpCode::CVTSD2SS, regOpnd32, src1, this->m_func));
- src1 = regOpnd32;
- }
- instr->InsertBefore(IR::Instr::New(movOpCode, dst, src1, m_func));
- instr->InsertBefore(IR::Instr::New(shufOpCode, dst, dst, IR::IntConstOpnd::New(0, TyInt8, m_func, true), m_func));
- IR::Instr* prevInstr = instr->m_prev;
- instr->Remove();
- return prevInstr;
- }
- IR::Instr* LowererMD::Simd128LowerRcp(IR::Instr *instr, bool removeInstr)
- {
- Js::OpCode opcode = Js::OpCode::DIVPS;
- void* x86_allones_mask = nullptr;
- IR::Opnd *dst, *src1;
- dst = instr->GetDst();
- src1 = instr->GetSrc1();
- Assert(dst && dst->IsRegOpnd());
- Assert(src1 && src1->IsRegOpnd());
- Assert(instr->GetSrc2() == nullptr);
- if (instr->m_opcode == Js::OpCode::Simd128_Rcp_F4 || instr->m_opcode == Js::OpCode::Simd128_RcpSqrt_F4)
- {
- Assert(src1->IsSimd128F4() || src1->IsSimd128I4());
- opcode = Js::OpCode::DIVPS;
- x86_allones_mask = (void*)(&X86_ALL_ONES_F4);
- }
- else
- {
- Assert(instr->m_opcode == Js::OpCode::Simd128_Rcp_D2 || instr->m_opcode == Js::OpCode::Simd128_RcpSqrt_D2);
- Assert(src1->IsSimd128D2());
- opcode = Js::OpCode::DIVPD;
- x86_allones_mask = (void*)(&X86_ALL_ONES_D2);
- }
- IR::RegOpnd* tmp = IR::RegOpnd::New(src1->GetType(), m_func);
- IR::Instr* movInstr = IR::Instr::New(Js::OpCode::MOVAPS, tmp, IR::MemRefOpnd::New(x86_allones_mask, src1->GetType(), m_func), m_func);
- instr->InsertBefore(movInstr);
- Legalize(movInstr);
- instr->InsertBefore(IR::Instr::New(opcode, tmp, tmp, src1, m_func));
- instr->InsertBefore(IR::Instr::New(Js::OpCode::MOVAPS, dst, tmp, m_func));
- if (removeInstr)
- {
- IR::Instr* prevInstr = instr->m_prev;
- instr->Remove();
- return prevInstr;
- }
- return instr;
- }
- IR::Instr* LowererMD::Simd128LowerSqrt(IR::Instr *instr)
- {
- Js::OpCode opcode = Js::OpCode::SQRTPS;
- IR::Opnd *dst, *src1;
- dst = instr->GetDst();
- src1 = instr->GetSrc1();
- Assert(dst && dst->IsRegOpnd());
- Assert(src1 && src1->IsRegOpnd());
- Assert(instr->GetSrc2() == nullptr);
- if (instr->m_opcode == Js::OpCode::Simd128_Sqrt_F4)
- {
- opcode = Js::OpCode::SQRTPS;
- }
- else
- {
- Assert(instr->m_opcode == Js::OpCode::Simd128_Sqrt_D2);
- opcode = Js::OpCode::SQRTPD;
- }
- instr->InsertBefore(IR::Instr::New(opcode, dst, src1, m_func));
- IR::Instr* prevInstr = instr->m_prev;
- instr->Remove();
- return prevInstr;
- }
- IR::Instr* LowererMD::Simd128LowerRcpSqrt(IR::Instr *instr)
- {
- Js::OpCode opcode = Js::OpCode::SQRTPS;
- Simd128LowerRcp(instr, false);
- if (instr->m_opcode == Js::OpCode::Simd128_RcpSqrt_F4)
- {
- opcode = Js::OpCode::SQRTPS;
- }
- else
- {
- Assert(instr->m_opcode == Js::OpCode::Simd128_RcpSqrt_D2);
- opcode = Js::OpCode::SQRTPD;
- }
- instr->InsertBefore(IR::Instr::New(opcode, instr->GetDst(), instr->GetDst(), m_func));
- IR::Instr* prevInstr = instr->m_prev;
- instr->Remove();
- return prevInstr;
- }
- IR::Instr* LowererMD::Simd128LowerSelect(IR::Instr *instr)
- {
- Assert(instr->m_opcode == Js::OpCode::Simd128_Select_F4 || instr->m_opcode == Js::OpCode::Simd128_Select_I4 || instr->m_opcode == Js::OpCode::Simd128_Select_D2);
- IR::Opnd* dst = nullptr;
- IR::Opnd* src1 = nullptr;
- IR::Opnd* src2 = nullptr;
- IR::Opnd* src3 = nullptr;
- SList<IR::Opnd*> *args = Simd128GetExtendedArgs(instr);
- // The number of src opnds should be exact. Missing opnds means type-error, and we should generate an exception throw instead (or globopt does).
- Assert(args->Count() == 4);
- dst = args->Pop();
- src1 = args->Pop(); // mask
- src2 = args->Pop(); // trueValue
- src3 = args->Pop(); // falseValue
- Assert(dst->IsRegOpnd() && dst->IsSimd128());
- Assert(src1->IsRegOpnd() && src1->IsSimd128());
- Assert(src2->IsRegOpnd() && src2->IsSimd128());
- Assert(src3->IsRegOpnd() && src3->IsSimd128());
- IR::RegOpnd *tmp = IR::RegOpnd::New(src1->GetType(), m_func);
- IR::Instr *pInstr = nullptr;
- // ANDPS tmp1, mask, tvalue
- pInstr = IR::Instr::New(Js::OpCode::ANDPS, tmp, src1, src2, m_func);
- instr->InsertBefore(pInstr);
- //MakeDstEquSrc1(pInstr);
- Legalize(pInstr);
- // ANDPS dst, mask, fvalue
- pInstr = IR::Instr::New(Js::OpCode::ANDNPS, dst, src1, src3, m_func);
- instr->InsertBefore(pInstr);
- //MakeDstEquSrc1(pInstr);
- Legalize(pInstr);
- // ORPS dst, dst, tmp1
- pInstr = IR::Instr::New(Js::OpCode::ORPS, dst, dst, tmp, m_func);
- instr->InsertBefore(pInstr);
- pInstr = instr->m_prev;
- instr->Remove();
- return pInstr;
- }
- IR::Instr* LowererMD::Simd128LowerNegI4(IR::Instr *instr)
- {
- Assert(instr->m_opcode == Js::OpCode::Simd128_Neg_I4);
- IR::Opnd* dst = instr->GetDst();
- IR::Opnd* src1 = instr->GetSrc1();
- Assert(dst->IsRegOpnd() && dst->IsSimd128());
- Assert(src1->IsRegOpnd() && src1->IsSimd128());
- Assert(instr->GetSrc2() == nullptr);
- // MOVAPS dst, src1
- IR::Instr *pInstr = IR::Instr::New(Js::OpCode::MOVAPS, dst, src1, m_func);
- instr->InsertBefore(pInstr);
- // XORPS dst, dst, 0xfff...f
- pInstr = IR::Instr::New(Js::OpCode::XORPS, dst, dst, IR::MemRefOpnd::New((void*)&X86_ALL_NEG_ONES, src1->GetType(), m_func), m_func);
- instr->InsertBefore(pInstr);
- Legalize(pInstr);
- // PADDD dst, dst, {1,1,1,1}
- pInstr = IR::Instr::New(Js::OpCode::PADDD, dst, dst, IR::MemRefOpnd::New((void*)&X86_ALL_ONES_I4, src1->GetType(), m_func), m_func);
- instr->InsertBefore(pInstr);
- Legalize(pInstr);
- pInstr = instr->m_prev;
- instr->Remove();
- return pInstr;
- }
- IR::Instr* LowererMD::Simd128LowerMulI4(IR::Instr *instr)
- {
- Assert(instr->m_opcode == Js::OpCode::Simd128_Mul_I4);
- IR::Instr *pInstr;
- IR::Opnd* dst = instr->GetDst();
- IR::Opnd* src1 = instr->GetSrc1();
- IR::Opnd* src2 = instr->GetSrc2();
- IR::Opnd* temp1, *temp2, *temp3;
- Assert(dst->IsRegOpnd() && dst->IsSimd128());
- Assert(src1->IsRegOpnd() && src1->IsSimd128());
- Assert(src2->IsRegOpnd() && src2->IsSimd128());
- temp1 = IR::RegOpnd::New(src1->GetType(), m_func);
- temp2 = IR::RegOpnd::New(src1->GetType(), m_func);
- temp3 = IR::RegOpnd::New(src1->GetType(), m_func);
- // temp1 = PMULUDQ src1, src2
- pInstr = IR::Instr::New(Js::OpCode::PMULUDQ, temp1, src1, src2, m_func);
- instr->InsertBefore(pInstr);
- //MakeDstEquSrc1(pInstr);
- Legalize(pInstr);
- // temp2 = PSLRD src1, 0x4
- pInstr = IR::Instr::New(Js::OpCode::PSRLDQ, temp2, src1, IR::IntConstOpnd::New(TySize[TyInt32], TyInt8, m_func, true), m_func);
- instr->InsertBefore(pInstr);
- //MakeDstEquSrc1(pInstr);
- Legalize(pInstr);
- // temp3 = PSLRD src2, 0x4
- pInstr = IR::Instr::New(Js::OpCode::PSRLDQ, temp3, src2, IR::IntConstOpnd::New(TySize[TyInt32], TyInt8, m_func, true), m_func);
- instr->InsertBefore(pInstr);
- //MakeDstEquSrc1(pInstr);
- Legalize(pInstr);
- // temp2 = PMULUDQ temp2, temp3
- pInstr = IR::Instr::New(Js::OpCode::PMULUDQ, temp2, temp2, temp3, m_func);
- instr->InsertBefore(pInstr);
- Legalize(pInstr);
- //PSHUFD temp1, temp1, 0x8
- instr->InsertBefore(IR::Instr::New(Js::OpCode::PSHUFD, temp1, temp1, IR::IntConstOpnd::New( 8 /*b00001000*/, TyInt8, m_func, true), m_func));
- //PSHUFD temp2, temp2, 0x8
- instr->InsertBefore(IR::Instr::New(Js::OpCode::PSHUFD, temp2, temp2, IR::IntConstOpnd::New(8 /*b00001000*/, TyInt8, m_func, true), m_func));
- // PUNPCKLDQ dst, temp1, temp2
- pInstr = IR::Instr::New(Js::OpCode::PUNPCKLDQ, dst, temp1, temp2, m_func);
- instr->InsertBefore(pInstr);
- Legalize(pInstr);
- pInstr = instr->m_prev;
- instr->Remove();
- return pInstr;
- }
- IR::Instr* LowererMD::SIMD128LowerReplaceLane(IR::Instr* instr)
- {
- SList<IR::Opnd*> *args = Simd128GetExtendedArgs(instr);
- int lane = 0, byteWidth = 0;
- IR::Opnd *dst = args->Pop();
- IR::Opnd *src1 = args->Pop();
- IR::Opnd *src2 = args->Pop();
- IR::Opnd *src3 = args->Pop();
- Assert(dst->IsSimd128() && src1->IsSimd128());
- IRType type = dst->GetType();
- lane = src2->AsIntConstOpnd()->AsInt32();
- IR::Opnd* laneValue = EnregisterIntConst(instr, src3);
- switch (instr->m_opcode)
- {
- case Js::OpCode::Simd128_ReplaceLane_I4:
- byteWidth = TySize[TyInt32];
- break;
- case Js::OpCode::Simd128_ReplaceLane_F4:
- byteWidth = TySize[TyFloat32];
- break;
- default:
- Assert(UNREACHED);
- }
- // MOVAPS dst, src1
- instr->InsertBefore(IR::Instr::New(Js::OpCode::MOVAPS, dst, src1, m_func));
- if (byteWidth == TySize[TyFloat32])
- {
- if (laneValue->GetType() == TyInt32)
- {
- IR::RegOpnd *tempReg = IR::RegOpnd::New(TyFloat32, m_func); //mov intval to xmm
- //MOVD
- instr->InsertBefore(IR::Instr::New(Js::OpCode::MOVD, tempReg, laneValue, m_func));
- laneValue = tempReg;
- }
- Assert(laneValue->GetType() == TyFloat32);
- if (lane == 0)
- {
- // MOVSS for both TyFloat32 and TyInt32. MOVD zeroes upper bits.
- instr->InsertBefore(IR::Instr::New(Js::OpCode::MOVSS, dst, laneValue, m_func));
- }
- else if (lane == 2)
- {
- IR::RegOpnd *tmp = IR::RegOpnd::New(type, m_func);
- instr->InsertBefore(IR::Instr::New(Js::OpCode::MOVHLPS, tmp, dst, m_func));
- instr->InsertBefore(IR::Instr::New(Js::OpCode::MOVSS, tmp, laneValue, m_func));
- instr->InsertBefore(IR::Instr::New(Js::OpCode::MOVLHPS, dst, tmp, m_func));
- }
- else
- {
- Assert(lane == 1 || lane == 3);
- uint8 shufMask = 0xE4; // 11 10 01 00
- shufMask |= lane; // 11 10 01 id
- shufMask &= ~(0x03 << (lane << 1)); // set 2 bits corresponding to lane index to 00
- // SHUFPS dst, dst, shufMask
- instr->InsertBefore(IR::Instr::New(Js::OpCode::SHUFPS, dst, dst, IR::IntConstOpnd::New(shufMask, TyInt8, m_func, true), m_func));
- // MOVSS dst, value
- instr->InsertBefore(IR::Instr::New(Js::OpCode::MOVSS, dst, laneValue, m_func));
- // SHUFPS dst, dst, shufMask
- instr->InsertBefore(IR::Instr::New(Js::OpCode::SHUFPS, dst, dst, IR::IntConstOpnd::New(shufMask, TyInt8, m_func, true), m_func));
- }
- }
- IR::Instr* prevInstr = instr->m_prev;
- instr->Remove();
- return prevInstr;
- }
- /*
- 4 and 2 lane Swizzle.
- */
- IR::Instr* LowererMD::Simd128LowerSwizzle4(IR::Instr* instr)
- {
- Js::OpCode shufOpcode = Js::OpCode::SHUFPS;
- Js::OpCode irOpcode = instr->m_opcode;
- SList<IR::Opnd*> *args = Simd128GetExtendedArgs(instr);
- IR::Opnd *dst = args->Pop();
- IR::Opnd *srcs[6] = { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr };
- int i = 0;
- while (!args->Empty() && i < 6)
- {
- srcs[i++] = args->Pop();
- }
- int8 shufMask = 0;
- int lane0 = 0, lane1 = 0, lane2 = 0, lane3 = 0;
- IR::Instr *pInstr = instr->m_prev;
- Assert(dst->IsSimd128() && srcs[0] && srcs[0]->IsSimd128());
- // globOpt will type-spec if all lane indices are constants, and within range constraints to match a single SSE instruction
- Assert(irOpcode == Js::OpCode::Simd128_Swizzle_I4 || irOpcode == Js::OpCode::Simd128_Swizzle_F4 || irOpcode == Js::OpCode::Simd128_Swizzle_D2);
- AssertMsg(srcs[1] && srcs[1]->IsIntConstOpnd() &&
- srcs[2] && srcs[2]->IsIntConstOpnd() &&
- (irOpcode == Js::OpCode::Simd128_Swizzle_D2 || (srcs[3] && srcs[3]->IsIntConstOpnd())) &&
- (irOpcode == Js::OpCode::Simd128_Swizzle_D2 || (srcs[4] && srcs[4]->IsIntConstOpnd())), "Type-specialized swizzle is supported only with constant lane indices");
- if (irOpcode == Js::OpCode::Simd128_Swizzle_D2)
- {
- lane0 = srcs[1]->AsIntConstOpnd()->AsInt32();
- lane1 = srcs[2]->AsIntConstOpnd()->AsInt32();
- Assert(lane0 >= 0 && lane0 < 2);
- Assert(lane1 >= 0 && lane1 < 2);
- shufMask = (int8)((lane1 << 1) | lane0);
- shufOpcode = Js::OpCode::SHUFPD;
- }
- else
- {
- if (irOpcode == Js::OpCode::Simd128_Swizzle_I4)
- {
- shufOpcode = Js::OpCode::PSHUFD;
- }
- AnalysisAssert(srcs[3] != nullptr && srcs[4] != nullptr);
- lane0 = srcs[1]->AsIntConstOpnd()->AsInt32();
- lane1 = srcs[2]->AsIntConstOpnd()->AsInt32();
- lane2 = srcs[3]->AsIntConstOpnd()->AsInt32();
- lane3 = srcs[4]->AsIntConstOpnd()->AsInt32();
- Assert(lane1 >= 0 && lane1 < 4);
- Assert(lane2 >= 0 && lane2 < 4);
- Assert(lane2 >= 0 && lane2 < 4);
- Assert(lane3 >= 0 && lane3 < 4);
- shufMask = (int8)((lane3 << 6) | (lane2 << 4) | (lane1 << 2) | lane0);
- }
- instr->m_opcode = shufOpcode;
- instr->SetDst(dst);
- // MOVAPS dst, src1
- instr->InsertBefore(IR::Instr::New(Js::OpCode::MOVAPS, dst, srcs[0], m_func));
- // SHUF dst, dst, imm8
- instr->SetSrc1(dst);
- instr->SetSrc2(IR::IntConstOpnd::New((IntConstType)shufMask, TyInt8, m_func, true));
- return pInstr;
- }
- /*
- 4 lane shuffle. Handles arbitrary lane values.
- */
- IR::Instr* LowererMD::Simd128LowerShuffle4(IR::Instr* instr)
- {
- Js::OpCode irOpcode = instr->m_opcode;
- SList<IR::Opnd*> *args = Simd128GetExtendedArgs(instr);
- IR::Opnd *dst = args->Pop();
- IR::Opnd *srcs[6] = { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr };
- int i = 0;
- while (!args->Empty() && i < 6)
- {
- srcs[i++] = args->Pop();
- }
- uint8 lanes[4], lanesSrc[4];
- uint fromSrc1, fromSrc2;
- IR::Instr *pInstr = instr->m_prev;
-
- Assert(dst->IsSimd128() && srcs[0] && srcs[0]->IsSimd128() && srcs[1] && srcs[1]->IsSimd128());
- Assert(irOpcode == Js::OpCode::Simd128_Shuffle_I4 || irOpcode == Js::OpCode::Simd128_Shuffle_F4);
- // globOpt will type-spec if all lane indices are constants, and within range constraints to match a single SSE instruction
- AssertMsg(srcs[2] && srcs[2]->IsIntConstOpnd() &&
- srcs[3] && srcs[3]->IsIntConstOpnd() &&
- srcs[4] && srcs[4]->IsIntConstOpnd() &&
- srcs[5] && srcs[5]->IsIntConstOpnd(), "Type-specialized shuffle is supported only with constant lane indices");
-
- lanes[0] = (uint8) srcs[2]->AsIntConstOpnd()->AsInt32();
- lanes[1] = (uint8) srcs[3]->AsIntConstOpnd()->AsInt32();
- lanes[2] = (uint8) srcs[4]->AsIntConstOpnd()->AsInt32();
- lanes[3] = (uint8) srcs[5]->AsIntConstOpnd()->AsInt32();
- Assert(lanes[0] >= 0 && lanes[0] < 8);
- Assert(lanes[1] >= 0 && lanes[1] < 8);
- Assert(lanes[2] >= 0 && lanes[2] < 8);
- Assert(lanes[3] >= 0 && lanes[3] < 8);
- CheckShuffleLanes4(lanes, lanesSrc, &fromSrc1, &fromSrc2);
- Assert(fromSrc1 + fromSrc2 == 4);
- if (fromSrc1 == 4 || fromSrc2 == 4)
- {
- // can be done with a swizzle
- IR::Opnd *srcOpnd = fromSrc1 == 4 ? srcs[0] : srcs[1];
- InsertShufps(lanes, dst, srcOpnd, srcOpnd, instr);
- }
- else if (fromSrc1 == 2)
- {
- if (lanes[0] < 4 && lanes[1] < 4)
- {
- // x86 friendly shuffle
- Assert(lanes[2] >= 4 && lanes[3] >= 4);
- InsertShufps(lanes, dst, srcs[0], srcs[1], instr);
- }
- else
- {
- // arbitrary shuffle with 2 lanes from each src
- uint8 ordLanes[4], reArrLanes[4];
- // order lanes based on which src they come from
- // compute re-arrangement mask
- for (uint8 i = 0, j1 = 0, j2 = 2; i < 4; i++)
- {
- if (lanesSrc[i] == 1)
- {
- ordLanes[j1] = lanes[i];
- reArrLanes[i] = j1;
- j1++;
- }
- else
- {
- Assert(lanesSrc[i] == 2);
- ordLanes[j2] = lanes[i];
- reArrLanes[i] = j2;
- j2++;
- }
- }
- IR::RegOpnd *temp = IR::RegOpnd::New(dst->GetType(), m_func);
- InsertShufps(ordLanes, temp, srcs[0], srcs[1], instr);
- InsertShufps(reArrLanes, dst, temp, temp, instr);
- }
- }
- else if (fromSrc1 == 3 || fromSrc2 == 3)
- {
- // shuffle with 3 lanes from one src, one from another
- IR::Instr *newInstr;
- IR::Opnd * majSrc, *minSrc;
- IR::RegOpnd *temp1 = IR::RegOpnd::New(dst->GetType(), m_func);
- IR::RegOpnd *temp2 = IR::RegOpnd::New(dst->GetType(), m_func);
- IR::RegOpnd *temp3 = IR::RegOpnd::New(dst->GetType(), m_func);
- uint8 minorityLane = 0, maxLaneValue;
- majSrc = fromSrc1 == 3 ? srcs[0] : srcs[1];
- minSrc = fromSrc1 == 3 ? srcs[1] : srcs[0];
- Assert(majSrc != minSrc);
- // Algorithm:
- // SHUFPS temp1, majSrc, lanes
- // SHUFPS temp2, minSrc, lanes
- // MOVUPS temp3, [minorityLane mask]
- // ANDPS temp2, temp3 // mask all lanes but minorityLane
- // ANDNPS temp3, temp1 // zero minorityLane
- // ORPS dst, temp2, temp3
- // find minorityLane to mask
- maxLaneValue = minSrc == srcs[0] ? 4 : 8;
- for (uint8 i = 0; i < 4; i++)
- {
- if (lanes[i] >= (maxLaneValue - 4) && lanes[i] < maxLaneValue)
- {
- minorityLane = i;
- break;
- }
- }
- IR::MemRefOpnd * laneMask = IR::MemRefOpnd::New((void*)&X86_4LANES_MASKS[minorityLane], dst->GetType(), m_func);
- InsertShufps(lanes, temp1, majSrc, majSrc, instr);
- InsertShufps(lanes, temp2, minSrc, minSrc, instr);
- newInstr = IR::Instr::New(Js::OpCode::MOVUPS, temp3, laneMask, m_func);
- instr->InsertBefore(newInstr);
- Legalize(newInstr);
- newInstr = IR::Instr::New(Js::OpCode::ANDPS, temp2, temp2, temp3, m_func);
- instr->InsertBefore(newInstr);
- Legalize(newInstr);
- newInstr = IR::Instr::New(Js::OpCode::ANDNPS, temp3, temp3, temp1, m_func);
- instr->InsertBefore(newInstr);
- Legalize(newInstr);
- newInstr = IR::Instr::New(Js::OpCode::ORPS, dst, temp2, temp3, m_func);
- instr->InsertBefore(newInstr);
- Legalize(newInstr);
- }
- instr->Remove();
- return pInstr;
- }
- IR::Instr* LowererMD::Simd128LowerInt32x4FromFloat32x4(IR::Instr *instr)
- {
- IR::Opnd *dst, *src, *tmp, *tmp2, *mask1, *mask2;
- IR::Instr *insertInstr, *pInstr, *newInstr;
- IR::LabelInstr *doneLabel;
- dst = instr->GetDst();
- src = instr->GetSrc1();
- Assert(dst != nullptr && src != nullptr && dst->IsSimd128() && src->IsSimd128());
- // CVTTPS2DQ dst, src
- instr->m_opcode = Js::OpCode::CVTTPS2DQ;
- insertInstr = instr->m_next;
- pInstr = instr->m_prev;
- doneLabel = IR::LabelInstr::New(Js::OpCode::Label, this->m_func);
- mask1 = IR::RegOpnd::New(TyInt32, m_func);
- mask2 = IR::RegOpnd::New(TyInt32, m_func);
- // bound checks
- // check if any value is potentially out of range (0x80000000 in output)
- // PCMPEQD tmp, dst, X86_NEG_MASK (0x80000000)
- // MOVMSKPS mask1, tmp
- // CMP mask1, 0
- // JNE $doneLabel
- tmp = IR::RegOpnd::New(TySimd128I4, m_func);
- tmp2 = IR::RegOpnd::New(TySimd128I4, m_func);
- newInstr = IR::Instr::New(Js::OpCode::MOVAPS, tmp2, IR::MemRefOpnd::New((void*)&X86_NEG_MASK_F4, TySimd128I4, m_func), m_func);
- insertInstr->InsertBefore(newInstr);
- Legalize(newInstr);
- newInstr = IR::Instr::New(Js::OpCode::PCMPEQD, tmp, dst, tmp2, m_func);
- insertInstr->InsertBefore(newInstr);
- Legalize(newInstr);
- insertInstr->InsertBefore(IR::Instr::New(Js::OpCode::MOVMSKPS, mask1, tmp, m_func));
- newInstr = IR::Instr::New(Js::OpCode::CMP, m_func);
- newInstr->SetSrc1(mask1);
- newInstr->SetSrc2(IR::IntConstOpnd::New(0, TyInt32, m_func));
- insertInstr->InsertBefore(newInstr);
- insertInstr->InsertBefore(IR::BranchInstr::New(Js::OpCode::JEQ, doneLabel, m_func));
- // we have potential out of bound. check bounds
- // MOVAPS tmp2, X86_TWO_31_F4 (0x4f000000)
- // CMPLEPS tmp, tmp2, src
- // MOVMSKPS mask1, tmp
- // MOVAPS tmp2, X86_NEG_TWO_31_F4 (0xcf000000)
- // CMPLTPS tmp, src, tmp2
- // MOVMSKPS mask2, tmp
- // OR mask1, mask1, mask2
- // CMP mask1, 0
- // JNE $doneLabel
- newInstr = IR::Instr::New(Js::OpCode::MOVAPS, tmp2, IR::MemRefOpnd::New((void*)&X86_TWO_31_F4, TySimd128I4, m_func), m_func);
- insertInstr->InsertBefore(newInstr);
- Legalize(newInstr);
- newInstr = IR::Instr::New(Js::OpCode::CMPLEPS, tmp, tmp2, src, m_func);
- insertInstr->InsertBefore(newInstr);
- Legalize(newInstr);
- insertInstr->InsertBefore(IR::Instr::New(Js::OpCode::MOVMSKPS, mask1, tmp, m_func));
- newInstr = IR::Instr::New(Js::OpCode::MOVAPS, tmp2, IR::MemRefOpnd::New((void*)&X86_NEG_TWO_31_F4, TySimd128I4, m_func), m_func);
- insertInstr->InsertBefore(newInstr);
- Legalize(newInstr);
- newInstr = IR::Instr::New(Js::OpCode::CMPLTPS, tmp, src, tmp2, m_func);
- insertInstr->InsertBefore(newInstr);
- Legalize(newInstr);
- insertInstr->InsertBefore(IR::Instr::New(Js::OpCode::MOVMSKPS, mask2, tmp, m_func));
- insertInstr->InsertBefore(IR::Instr::New(Js::OpCode::OR, mask1, mask1, mask2, m_func));
- newInstr = IR::Instr::New(Js::OpCode::CMP, m_func);
- newInstr->SetSrc1(mask1);
- newInstr->SetSrc2(IR::IntConstOpnd::New(0, TyInt32, m_func));
- insertInstr->InsertBefore(newInstr);
- insertInstr->InsertBefore(IR::BranchInstr::New(Js::OpCode::JEQ, doneLabel, m_func));
- // throw range error
- m_lowerer->GenerateRuntimeError(insertInstr, JSERR_ArgumentOutOfRange, IR::HelperOp_RuntimeRangeError);
- insertInstr->InsertBefore(doneLabel);
- return pInstr;
- }
- IR::Instr* LowererMD::Simd128AsmJsLowerLoadElem(IR::Instr *instr)
- {
- Assert(instr->m_opcode == Js::OpCode::Simd128_LdArr_I4 ||
- instr->m_opcode == Js::OpCode::Simd128_LdArr_F4 ||
- instr->m_opcode == Js::OpCode::Simd128_LdArr_D2 ||
- instr->m_opcode == Js::OpCode::Simd128_LdArrConst_I4 ||
- instr->m_opcode == Js::OpCode::Simd128_LdArrConst_F4 ||
- instr->m_opcode == Js::OpCode::Simd128_LdArrConst_D2
- );
- IR::Instr * instrPrev = instr->m_prev;
- IR::RegOpnd * indexOpnd = instr->GetSrc1()->AsIndirOpnd()->GetIndexOpnd();
- IR::RegOpnd * baseOpnd = instr->GetSrc1()->AsIndirOpnd()->GetBaseOpnd();
- IR::Opnd * dst = instr->GetDst();
- IR::Opnd * src1 = instr->GetSrc1();
- IR::Opnd * src2 = instr->GetSrc2();
- ValueType arrType = baseOpnd->GetValueType();
- uint8 dataWidth = instr->dataWidth;
- // Type-specialized.
- Assert(dst->IsSimd128() && src1->IsSimd128() && src2->GetType() == TyUint32);
- IR::Instr * done;
- if (indexOpnd || (((uint32)src1->AsIndirOpnd()->GetOffset() + dataWidth) > 0x1000000 /* 16 MB */))
- {
- uint32 bpe = Simd128GetTypedArrBytesPerElem(arrType);
- // bound check and helper
- done = this->lowererMDArch.LowerAsmJsLdElemHelper(instr, true, bpe != dataWidth);
- }
- else
- {
- // Reaching here means:
- // We have a constant index, and either
- // (1) constant heap or (2) variable heap with constant index < 16MB.
- // Case (1) requires static bound check. Case (2) means we are always in bound.
- // this can happen in cases where globopt props a constant access which was not known at bytecodegen time or when heap is non-constant
- if (src2->IsIntConstOpnd() && ((uint32)src1->AsIndirOpnd()->GetOffset() + dataWidth > src2->AsIntConstOpnd()->AsUint32()))
- {
- m_lowerer->GenerateRuntimeError(instr, JSERR_ArgumentOutOfRange, IR::HelperOp_RuntimeRangeError);
- instr->Remove();
- return instrPrev;
- }
- done = instr;
- }
- return Simd128ConvertToLoad(dst, src1, dataWidth, instr);
- }
- IR::Instr* LowererMD::Simd128LowerLoadElem(IR::Instr *instr)
- {
- Assert(!m_func->m_workItem->GetFunctionBody()->GetIsAsmjsMode());
- Assert(instr->m_opcode == Js::OpCode::Simd128_LdArr_I4 || instr->m_opcode == Js::OpCode::Simd128_LdArr_F4);
- IR::Opnd * src = instr->GetSrc1();
- IR::RegOpnd * indexOpnd =src->AsIndirOpnd()->GetIndexOpnd();
- IR::Opnd * dst = instr->GetDst();
- ValueType arrType = src->AsIndirOpnd()->GetBaseOpnd()->GetValueType();
- // If we type-specialized, then array is a definite typed-array.
- Assert(arrType.IsObject() && arrType.IsTypedArray());
- Simd128GenerateUpperBoundCheck(indexOpnd, src->AsIndirOpnd(), arrType, instr);
- Simd128LoadHeadSegment(src->AsIndirOpnd(), arrType, instr);
- return Simd128ConvertToLoad(dst, src, instr->dataWidth, instr, m_lowerer->GetArrayIndirScale(arrType) /* scale factor */);
- }
- IR::Instr *
- LowererMD::Simd128ConvertToLoad(IR::Opnd *dst, IR::Opnd *src, uint8 dataWidth, IR::Instr* instr, byte scaleFactor /* = 0*/)
- {
- IR::Instr *newInstr = nullptr;
- IR::Instr * instrPrev = instr->m_prev;
- // Type-specialized.
- Assert(dst && dst->IsSimd128());
- Assert(src->IsIndirOpnd());
- if (scaleFactor > 0)
- {
- // needed only for non-Asmjs code
- Assert(!m_func->m_workItem->GetFunctionBody()->GetIsAsmjsMode());
- src->AsIndirOpnd()->SetScale(scaleFactor);
- }
- switch (dataWidth)
- {
- case 16:
- // MOVUPS dst, src1([arrayBuffer + indexOpnd])
- newInstr = IR::Instr::New(LowererMDArch::GetAssignOp(src->GetType()), dst, src, instr->m_func);
- instr->InsertBefore(newInstr);
- Legalize(newInstr);
- break;
- case 12:
- {
- IR::RegOpnd *temp = IR::RegOpnd::New(src->GetType(), instr->m_func);
- // MOVSD dst, src1([arrayBuffer + indexOpnd])
- newInstr = IR::Instr::New(Js::OpCode::MOVSD, dst, src, instr->m_func);
- instr->InsertBefore(newInstr);
- Legalize(newInstr);
- // MOVSS temp, src1([arrayBuffer + indexOpnd + 8])
- newInstr = IR::Instr::New(Js::OpCode::MOVSS, temp, src, instr->m_func);
- instr->InsertBefore(newInstr);
- newInstr->GetSrc1()->AsIndirOpnd()->SetOffset(src->AsIndirOpnd()->GetOffset() + 8, true);
- Legalize(newInstr);
- // PSLLDQ temp, 0x08
- instr->InsertBefore(IR::Instr::New(Js::OpCode::PSLLDQ, temp, temp, IR::IntConstOpnd::New(8, TyInt8, instr->m_func, true), instr->m_func));
- // ORPS dst, temp
- newInstr = IR::Instr::New(Js::OpCode::ORPS, dst, dst, temp, instr->m_func);
- instr->InsertBefore(newInstr);
- Legalize(newInstr);
- break;
- }
- case 8:
- // MOVSD dst, src1([arrayBuffer + indexOpnd])
- newInstr = IR::Instr::New(Js::OpCode::MOVSD, dst, src, instr->m_func);
- instr->InsertBefore(newInstr);
- Legalize(newInstr);
- break;
- case 4:
- // MOVSS dst, src1([arrayBuffer + indexOpnd])
- newInstr = IR::Instr::New(Js::OpCode::MOVSS, dst, src, instr->m_func);
- instr->InsertBefore(newInstr);
- Legalize(newInstr);
- break;
- default:
- Assume(UNREACHED);
- }
- instr->Remove();
- return instrPrev;
- }
- IR::Instr* LowererMD::Simd128AsmJsLowerStoreElem(IR::Instr *instr)
- {
- Assert(instr->m_opcode == Js::OpCode::Simd128_StArr_I4 ||
- instr->m_opcode == Js::OpCode::Simd128_StArr_F4 ||
- instr->m_opcode == Js::OpCode::Simd128_StArr_D2 ||
- instr->m_opcode == Js::OpCode::Simd128_StArrConst_I4 ||
- instr->m_opcode == Js::OpCode::Simd128_StArrConst_F4 ||
- instr->m_opcode == Js::OpCode::Simd128_StArrConst_D2
- );
- IR::Instr * instrPrev = instr->m_prev;
- IR::RegOpnd * indexOpnd = instr->GetDst()->AsIndirOpnd()->GetIndexOpnd();
- IR::RegOpnd * baseOpnd = instr->GetDst()->AsIndirOpnd()->GetBaseOpnd();
- IR::Opnd * dst = instr->GetDst();
- IR::Opnd * src1 = instr->GetSrc1();
- IR::Opnd * src2 = instr->GetSrc2();
- ValueType arrType = baseOpnd->GetValueType();
- uint8 dataWidth = instr->dataWidth;
- // Type-specialized.
- Assert(dst->IsSimd128() && src1->IsSimd128() && src2->GetType() == TyUint32);
- IR::Instr * done;
-
- if (indexOpnd || ((uint32)dst->AsIndirOpnd()->GetOffset() + dataWidth > 0x1000000))
- {
- // CMP indexOpnd, src2(arrSize)
- // JA $helper
- // JMP $store
- // $helper:
- // Throw RangeError
- // JMP $done
- // $store:
- // MOV dst([arrayBuffer + indexOpnd]), src1
- // $done:
- uint32 bpe = Simd128GetTypedArrBytesPerElem(arrType);
- done = this->lowererMDArch.LowerAsmJsStElemHelper(instr, true, bpe != dataWidth);
- }
- else
- {
- // we might have a constant index if globopt propped a constant store. we can ahead of time check if it is in-bounds
- if (src2->IsIntConstOpnd() && ((uint32)dst->AsIndirOpnd()->GetOffset() + dataWidth > src2->AsIntConstOpnd()->AsUint32()))
- {
- m_lowerer->GenerateRuntimeError(instr, JSERR_ArgumentOutOfRange, IR::HelperOp_RuntimeRangeError);
- instr->Remove();
- return instrPrev;
- }
- done = instr;
- }
- return Simd128ConvertToStore(dst, src1, dataWidth, instr);
- }
- IR::Instr* LowererMD::Simd128LowerStoreElem(IR::Instr *instr)
- {
- Assert(!m_func->m_workItem->GetFunctionBody()->GetIsAsmjsMode());
- Assert(instr->m_opcode == Js::OpCode::Simd128_StArr_I4 || instr->m_opcode == Js::OpCode::Simd128_StArr_F4);
- IR::Opnd * dst = instr->GetDst();
- IR::RegOpnd * indexOpnd = dst->AsIndirOpnd()->GetIndexOpnd();
- IR::Opnd * src1 = instr->GetSrc1();
- uint8 dataWidth = instr->dataWidth;
- ValueType arrType = dst->AsIndirOpnd()->GetBaseOpnd()->GetValueType();
-
- // If we type-specialized, then array is a definite type-array.
- Assert(arrType.IsObject() && arrType.IsTypedArray());
-
- Simd128GenerateUpperBoundCheck(indexOpnd, dst->AsIndirOpnd(), arrType, instr);
- Simd128LoadHeadSegment(dst->AsIndirOpnd(), arrType, instr);
- return Simd128ConvertToStore(dst, src1, dataWidth, instr, m_lowerer->GetArrayIndirScale(arrType) /*scale factor*/);
- }
- IR::Instr *
- LowererMD::Simd128ConvertToStore(IR::Opnd *dst, IR::Opnd *src1, uint8 dataWidth, IR::Instr* instr, byte scaleFactor /* = 0 */)
- {
- IR::Instr * instrPrev = instr->m_prev;
-
- Assert(src1 && src1->IsSimd128());
- Assert(dst->IsIndirOpnd());
-
- if (scaleFactor > 0)
- {
- // needed only for non-Asmjs code
- Assert(!m_func->m_workItem->GetFunctionBody()->GetIsAsmjsMode());
- dst->AsIndirOpnd()->SetScale(scaleFactor);
- }
-
- switch (dataWidth)
- {
- case 16:
- // MOVUPS dst([arrayBuffer + indexOpnd]), src1
- instr->InsertBefore(IR::Instr::New(LowererMDArch::GetAssignOp(src1->GetType()), dst, src1, instr->m_func));
- break;
- case 12:
- {
- IR::RegOpnd *temp = IR::RegOpnd::New(src1->GetType(), instr->m_func);
- IR::Instr *movss;
- // MOVAPS temp, src
- instr->InsertBefore(IR::Instr::New(Js::OpCode::MOVAPS, temp, src1, instr->m_func));
- // MOVSD dst([arrayBuffer + indexOpnd]), temp
- instr->InsertBefore(IR::Instr::New(Js::OpCode::MOVSD, dst, temp, instr->m_func));
- // PSRLDQ temp, 0x08
- instr->InsertBefore(IR::Instr::New(Js::OpCode::PSRLDQ, temp, temp, IR::IntConstOpnd::New(8, TyInt8, m_func, true), instr->m_func));
- // MOVSS dst([arrayBuffer + indexOpnd + 8]), temp
- movss = IR::Instr::New(Js::OpCode::MOVSS, dst, temp, instr->m_func);
- instr->InsertBefore(movss);
- movss->GetDst()->AsIndirOpnd()->SetOffset(dst->AsIndirOpnd()->GetOffset() + 8, true);
- break;
- }
- case 8:
- // MOVSD dst([arrayBuffer + indexOpnd]), src1
- instr->InsertBefore(IR::Instr::New(Js::OpCode::MOVSD, dst, src1, instr->m_func));
- break;
- case 4:
- // MOVSS dst([arrayBuffer + indexOpnd]), src1
- instr->InsertBefore(IR::Instr::New(Js::OpCode::MOVSS, dst, src1, instr->m_func));
- break;
- default:;
- Assume(UNREACHED);
- }
- instr->Remove();
- return instrPrev;
- }
- void
- LowererMD::Simd128GenerateUpperBoundCheck(IR::RegOpnd *indexOpnd, IR::IndirOpnd *indirOpnd, ValueType arrType, IR::Instr *instr)
- {
- Assert(!m_func->m_workItem->GetFunctionBody()->GetIsAsmjsMode());
- IR::ArrayRegOpnd *arrayRegOpnd = indirOpnd->GetBaseOpnd()->AsArrayRegOpnd();
- IR::Opnd* headSegmentLengthOpnd;
- if (arrayRegOpnd->EliminatedUpperBoundCheck())
- {
- // already eliminated or extracted by globOpt (OptArraySrc). Nothing to do.
- return;
- }
- if (arrayRegOpnd->HeadSegmentLengthSym())
- {
- headSegmentLengthOpnd = IR::RegOpnd::New(arrayRegOpnd->HeadSegmentLengthSym(), TyUint32, m_func);
- }
- else
- {
- // (headSegmentLength = [base + offset(length)])
- int lengthOffset;
- lengthOffset = m_lowerer->GetArrayOffsetOfLength(arrType);
- headSegmentLengthOpnd = IR::IndirOpnd::New(arrayRegOpnd, lengthOffset, TyUint32, m_func);
- }
- IR::LabelInstr * skipLabel = Lowerer::InsertLabel(false, instr);
- int32 elemCount = Lowerer::SimdGetElementCountFromBytes(arrayRegOpnd->GetValueType(), instr->dataWidth);
- if (indexOpnd)
- {
- // MOV tmp, elemCount
- // ADD tmp, index
- // CMP tmp, Length -- upper bound check
- // JBE $storeLabel
- // Throw RuntimeError
- // skipLabel:
- IR::RegOpnd *tmp = IR::RegOpnd::New(indexOpnd->GetType(), m_func);
- IR::IntConstOpnd *elemCountOpnd = IR::IntConstOpnd::New(elemCount, TyInt8, m_func, true);
- m_lowerer->InsertMove(tmp, elemCountOpnd, skipLabel);
- Lowerer::InsertAdd(false, tmp, tmp, indexOpnd, skipLabel);
- m_lowerer->InsertCompareBranch(tmp, headSegmentLengthOpnd, Js::OpCode::BrLe_A, true, skipLabel, skipLabel);
- }
- else
- {
- // CMP Length, (offset + elemCount)
- // JA $storeLabel
- int32 offset = indirOpnd->GetOffset();
- int32 index = offset + elemCount;
- m_lowerer->InsertCompareBranch(headSegmentLengthOpnd, IR::IntConstOpnd::New(index, TyInt32, m_func, true), Js::OpCode::BrLe_A, true, skipLabel, skipLabel);
- }
- m_lowerer->GenerateRuntimeError(skipLabel, JSERR_ArgumentOutOfRange, IR::HelperOp_RuntimeRangeError);
- return;
- }
- void
- LowererMD::Simd128LoadHeadSegment(IR::IndirOpnd *indirOpnd, ValueType arrType, IR::Instr *instr)
- {
- // For non-asm.js we check if headSeg symbol exists, else load it.
- IR::ArrayRegOpnd *arrayRegOpnd = indirOpnd->GetBaseOpnd()->AsArrayRegOpnd();
- IR::RegOpnd *headSegmentOpnd;
-
- if (arrayRegOpnd->HeadSegmentSym())
- {
- headSegmentOpnd = IR::RegOpnd::New(arrayRegOpnd->HeadSegmentSym(), TyMachPtr, m_func);
- }
- else
- {
- // REVIEW: Is this needed ? Shouldn't globOpt make sure headSegSym is set and alive ?
- // MOV headSegment, [base + offset(head)]
- int32 headOffset = m_lowerer->GetArrayOffsetOfHeadSegment(arrType);
- IR::IndirOpnd * indirOpnd = IR::IndirOpnd::New(arrayRegOpnd, headOffset, TyMachPtr, this->m_func);
- headSegmentOpnd = IR::RegOpnd::New(TyMachPtr, this->m_func);
- m_lowerer->InsertMove(headSegmentOpnd, indirOpnd, instr);
- }
- // change base to be the head segment instead of the array object
- indirOpnd->SetBaseOpnd(headSegmentOpnd);
- }
- // Builds args list <dst, src1, src2, src3 ..>
- SList<IR::Opnd*> * LowererMD::Simd128GetExtendedArgs(IR::Instr *instr)
- {
- SList<IR::Opnd*> * args = JitAnew(m_lowerer->m_alloc, SList<IR::Opnd*>, m_lowerer->m_alloc);
- IR::Instr *pInstr = instr;
- IR::Opnd *dst, *src1, *src2;
- dst = src1 = src2 = nullptr;
- if (pInstr->GetDst())
- {
- dst = pInstr->UnlinkDst();
- }
- src1 = pInstr->UnlinkSrc1();
- Assert(src1->GetStackSym()->IsSingleDef());
- pInstr = src1->GetStackSym()->GetInstrDef();
- while (pInstr && pInstr->m_opcode == Js::OpCode::ExtendArg_A)
- {
- Assert(pInstr->GetSrc1());
- src1 = pInstr->GetSrc1()->Copy(this->m_func);
- if (src1->IsRegOpnd())
- {
- this->m_lowerer->addToLiveOnBackEdgeSyms->Set(src1->AsRegOpnd()->m_sym->m_id);
- }
- args->Push(src1);
- if (pInstr->GetSrc2())
- {
- src2 = pInstr->GetSrc2();
- Assert(src2->GetStackSym()->IsSingleDef());
- pInstr = src2->GetStackSym()->GetInstrDef();
- }
- else
- {
- pInstr = nullptr;
- }
- }
- args->Push(dst);
- Assert(args->Count() > 3);
- return args;
- }
- IR::Opnd* LowererMD::EnregisterIntConst(IR::Instr* instr, IR::Opnd *constOpnd)
- {
- if (constOpnd->IsRegOpnd())
- {
- // already a register
- return constOpnd;
- }
- Assert(constOpnd->GetType() == TyInt32);
- IR::RegOpnd *tempReg = IR::RegOpnd::New(TyInt32, m_func);
- // MOV tempReg, constOpnd
- instr->InsertBefore(IR::Instr::New(Js::OpCode::MOV, tempReg, constOpnd, m_func));
- return tempReg;
- }
- void LowererMD::Simd128InitOpcodeMap()
- {
- m_simd128OpCodesMap = JitAnewArrayZ(m_lowerer->m_alloc, Js::OpCode, Js::Simd128OpcodeCount());
- // All simd ops should be contiguous for this mapping to work
- Assert(Js::OpCode::Simd128_End + (Js::OpCode) 1 == Js::OpCode::Simd128_Start_Extend);
- SET_SIMDOPCODE(Simd128_FromFloat64x2_I4 , CVTTPD2DQ);
- SET_SIMDOPCODE(Simd128_FromFloat64x2Bits_I4 , MOVAPS);
- SET_SIMDOPCODE(Simd128_FromFloat32x4Bits_I4 , MOVAPS);
- SET_SIMDOPCODE(Simd128_Add_I4 , PADDD);
- SET_SIMDOPCODE(Simd128_Sub_I4 , PSUBD);
- SET_SIMDOPCODE(Simd128_Lt_I4 , PCMPGTD);
- SET_SIMDOPCODE(Simd128_Gt_I4 , PCMPGTD);
- SET_SIMDOPCODE(Simd128_Eq_I4 , PCMPEQD);
- SET_SIMDOPCODE(Simd128_And_I4 , PAND);
- SET_SIMDOPCODE(Simd128_Or_I4 , POR);
- SET_SIMDOPCODE(Simd128_Xor_I4 , XORPS);
- SET_SIMDOPCODE(Simd128_Not_I4 , XORPS);
- SET_SIMDOPCODE(Simd128_LdSignMask_I4 , MOVMSKPS);
- SET_SIMDOPCODE(Simd128_FromFloat64x2_F4 , CVTPD2PS);
- SET_SIMDOPCODE(Simd128_FromFloat64x2Bits_F4 , MOVAPS);
- SET_SIMDOPCODE(Simd128_FromInt32x4_F4 , CVTDQ2PS);
- SET_SIMDOPCODE(Simd128_FromInt32x4Bits_F4 , MOVAPS);
- SET_SIMDOPCODE(Simd128_Abs_F4 , ANDPS);
- SET_SIMDOPCODE(Simd128_Neg_F4 , XORPS);
- SET_SIMDOPCODE(Simd128_Add_F4 , ADDPS);
- SET_SIMDOPCODE(Simd128_Sub_F4 , SUBPS);
- SET_SIMDOPCODE(Simd128_Mul_F4 , MULPS);
- SET_SIMDOPCODE(Simd128_Div_F4 , DIVPS);
- SET_SIMDOPCODE(Simd128_Min_F4 , MINPS);
- SET_SIMDOPCODE(Simd128_Max_F4 , MAXPS);
- SET_SIMDOPCODE(Simd128_Sqrt_F4 , SQRTPS);
- SET_SIMDOPCODE(Simd128_Lt_F4 , CMPLTPS); // CMPLTPS
- SET_SIMDOPCODE(Simd128_LtEq_F4 , CMPLEPS); // CMPLEPS
- SET_SIMDOPCODE(Simd128_Eq_F4 , CMPEQPS); // CMPEQPS
- SET_SIMDOPCODE(Simd128_Neq_F4 , CMPNEQPS); // CMPNEQPS
- SET_SIMDOPCODE(Simd128_Gt_F4 , CMPLTPS); // CMPLTPS (swap srcs)
- SET_SIMDOPCODE(Simd128_GtEq_F4 , CMPLEPS); // CMPLEPS (swap srcs)
- SET_SIMDOPCODE(Simd128_And_F4 , ANDPS);
- SET_SIMDOPCODE(Simd128_Or_F4 , ORPS);
- SET_SIMDOPCODE(Simd128_Xor_F4 , XORPS );
- SET_SIMDOPCODE(Simd128_Not_F4 , XORPS );
- SET_SIMDOPCODE(Simd128_LdSignMask_F4 , MOVMSKPS );
- SET_SIMDOPCODE(Simd128_FromFloat32x4_D2 , CVTPS2PD);
- SET_SIMDOPCODE(Simd128_FromFloat32x4Bits_D2 , MOVAPS);
- SET_SIMDOPCODE(Simd128_FromInt32x4_D2 , CVTDQ2PD);
- SET_SIMDOPCODE(Simd128_FromInt32x4Bits_D2 , MOVAPS);
- SET_SIMDOPCODE(Simd128_Neg_D2 , XORPS);
- SET_SIMDOPCODE(Simd128_Add_D2 , ADDPD);
- SET_SIMDOPCODE(Simd128_Abs_D2 , ANDPD);
- SET_SIMDOPCODE(Simd128_Sub_D2 , SUBPD);
- SET_SIMDOPCODE(Simd128_Mul_D2 , MULPD);
- SET_SIMDOPCODE(Simd128_Div_D2 , DIVPD);
- SET_SIMDOPCODE(Simd128_Min_D2 , MINPD);
- SET_SIMDOPCODE(Simd128_Max_D2 , MAXPD);
- SET_SIMDOPCODE(Simd128_Sqrt_D2 , SQRTPD);
- SET_SIMDOPCODE(Simd128_Lt_D2 , CMPLTPD); // CMPLTPD
- SET_SIMDOPCODE(Simd128_LtEq_D2 , CMPLEPD); // CMPLEPD
- SET_SIMDOPCODE(Simd128_Eq_D2 , CMPEQPD); // CMPEQPD
- SET_SIMDOPCODE(Simd128_Neq_D2 , CMPNEQPD); // CMPNEQPD
- SET_SIMDOPCODE(Simd128_Gt_D2 , CMPLTPD); // CMPLTPD (swap srcs)
- SET_SIMDOPCODE(Simd128_GtEq_D2 , CMPLEPD); // CMPLEPD (swap srcs)
- SET_SIMDOPCODE(Simd128_LdSignMask_D2 , MOVMSKPD);
- }
- #undef SIMD_SETOPCODE
- #undef SIMD_GETOPCODE
- // FromVar
- void LowererMD::GenerateCheckedSimdLoad(IR::Instr * instr)
- {
- Assert(instr->m_opcode == Js::OpCode::FromVar);
- Assert(instr->GetSrc1()->GetType() == TyVar);
- Assert(IRType_IsSimd128(instr->GetDst()->GetType()));
- bool checkRequired = instr->HasBailOutInfo();
- IR::LabelInstr * labelHelper = nullptr, * labelDone = nullptr;
- IR::Instr * insertInstr = instr, * newInstr;
- IR::RegOpnd * src = instr->GetSrc1()->AsRegOpnd(), * dst = instr->GetDst()->AsRegOpnd();
- Assert(!checkRequired || instr->GetBailOutKind() == IR::BailOutSimd128F4Only || instr->GetBailOutKind() == IR::BailOutSimd128I4Only);
- if (checkRequired)
- {
- labelHelper = IR::LabelInstr::New(Js::OpCode::Label, this->m_func, true);
- labelDone = IR::LabelInstr::New(Js::OpCode::Label, this->m_func);
- instr->InsertBefore(labelHelper);
- instr->InsertAfter(labelDone);
- insertInstr = labelHelper;
- GenerateObjectTest(instr->GetSrc1(), insertInstr, labelHelper);
- newInstr = IR::Instr::New(Js::OpCode::CMP, instr->m_func);
- newInstr->SetSrc1(IR::IndirOpnd::New(instr->GetSrc1()->AsRegOpnd(), 0, TyMachPtr, instr->m_func));
- newInstr->SetSrc2(m_lowerer->LoadVTableValueOpnd(instr, dst->GetType() == TySimd128F4 ? VTableValue::VtableSimd128F4 : VTableValue::VtableSimd128I4));
- insertInstr->InsertBefore(newInstr);
- Legalize(newInstr);
- insertInstr->InsertBefore(IR::BranchInstr::New(Js::OpCode::JNE, labelHelper, this->m_func));
- instr->UnlinkSrc1();
- instr->UnlinkDst();
- this->m_lowerer->GenerateBailOut(instr);
- }
- size_t valueOffset = dst->GetType() == TySimd128F4 ? Js::JavascriptSIMDFloat32x4::GetOffsetOfValue() : Js::JavascriptSIMDInt32x4::GetOffsetOfValue();
- Assert(valueOffset < INT_MAX);
- newInstr = IR::Instr::New(Js::OpCode::MOVUPS, dst, IR::IndirOpnd::New(src, static_cast<int>(valueOffset), dst->GetType(), this->m_func), this->m_func);
- insertInstr->InsertBefore(newInstr);
- insertInstr->InsertBefore(IR::BranchInstr::New(Js::OpCode::JMP, labelDone, this->m_func));
- // FromVar is converted to BailOut call. Don't remove.
- }
- // ToVar
- void LowererMD::GenerateSimdStore(IR::Instr * instr)
- {
- IR::RegOpnd *dst, *src;
- IRType type;
- dst = instr->GetDst()->AsRegOpnd();
- src = instr->GetSrc1()->AsRegOpnd();
- type = src->GetType();
- this->m_lowerer->LoadScriptContext(instr);
- IR::Instr * instrCall = IR::Instr::New(Js::OpCode::CALL, instr->GetDst(),
- IR::HelperCallOpnd::New(type == TySimd128F4 ? IR::HelperAllocUninitializedSimdF4 : IR::HelperAllocUninitializedSimdI4, this->m_func), this->m_func);
- instr->InsertBefore(instrCall);
- this->lowererMDArch.LowerCall(instrCall, 0);
- IR::Opnd * valDst;
- if (type == TySimd128F4)
- {
- valDst = IR::IndirOpnd::New(dst, (int32)Js::JavascriptSIMDFloat32x4::GetOffsetOfValue(), TySimd128F4, this->m_func);
- }
- else
- {
- valDst = IR::IndirOpnd::New(dst, (int32)Js::JavascriptSIMDInt32x4::GetOffsetOfValue(), TySimd128I4, this->m_func);
- }
- instr->InsertBefore(IR::Instr::New(Js::OpCode::MOVUPS, valDst, src, this->m_func));
- instr->Remove();
- }
- void LowererMD::CheckShuffleLanes4(uint8 lanes[], uint8 lanesSrc[], uint *fromSrc1, uint *fromSrc2)
- {
- Assert(lanes);
- Assert(lanesSrc);
- Assert(fromSrc1 && fromSrc2);
- *fromSrc1 = 0;
- *fromSrc2 = 0;
- for (uint i = 0; i < 4; i++)
- {
- if (lanes[i] >= 0 && lanes[i] < 4)
- {
- (*fromSrc1)++;
- lanesSrc[i] = 1;
- }
- else if (lanes[i] >= 4 && lanes[i] < 8)
- {
- (*fromSrc2)++;
- lanesSrc[i] = 2;
- }
- else
- {
- Assert(UNREACHED);
- }
- }
- }
- void LowererMD::InsertShufps(uint8 lanes[], IR::Opnd *dst, IR::Opnd *src1, IR::Opnd *src2, IR::Instr *instr)
- {
- int8 shufMask;
- uint8 normLanes[4];
-
- for (uint i = 0; i < 4; i++)
- {
- normLanes[i] = (lanes[i] >= 4) ? (lanes[i] - 4) : lanes[i];
- }
- shufMask = (int8)((normLanes[3] << 6) | (normLanes[2] << 4) | (normLanes[1] << 2) | normLanes[0]);
- // MOVAPS dst, src1
- instr->InsertBefore(IR::Instr::New(Js::OpCode::MOVAPS, dst, src1, m_func));
- // SHUF dst, src2, imm8
- instr->InsertBefore(IR::Instr::New(Js::OpCode::SHUFPS, dst, src2, IR::IntConstOpnd::New((IntConstType)shufMask, TyInt8, m_func, true), m_func));
- }
- BYTE LowererMD::Simd128GetTypedArrBytesPerElem(ValueType arrType)
- {
- return (1 << Lowerer::GetArrayIndirScale(arrType));
- }
|