| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433 |
- //-------------------------------------------------------------------------------------------------------
- // 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"
- #include "ARMEncode.h"
- #include "Language\JavascriptFunctionArgIndex.h"
- const FormTable * InstrEncode[]={
- #define MACRO(name, jnLayout, attrib, byte2, form, opbyte, ...) opbyte,
- #include "MdOpcodes.h"
- #undef ASMDAT
- };
- ///----------------------------------------------------------------------------
- ///
- /// EncoderMD::Init
- ///
- ///----------------------------------------------------------------------------
- void
- EncoderMD::Init(Encoder *encoder)
- {
- m_encoder = encoder;
- m_relocList = nullptr;
- }
- ///----------------------------------------------------------------------------
- ///
- /// EncoderMD::GetRegEncode
- ///
- /// Get the encoding of a given register.
- ///
- ///----------------------------------------------------------------------------
- const BYTE
- EncoderMD::GetRegEncode(IR::RegOpnd *regOpnd)
- {
- return GetRegEncode(regOpnd->GetReg());
- }
- const BYTE
- EncoderMD::GetRegEncode(RegNum reg)
- {
- return RegEncode[reg];
- }
- const BYTE
- EncoderMD::GetFloatRegEncode(IR::RegOpnd *regOpnd)
- {
- //Each double register holds two single precision registers.
- BYTE regEncode = GetRegEncode(regOpnd->GetReg()) * 2;
- AssertMsg(regEncode <= LAST_FLOAT_REG_NUM, "Impossible to allocate higher registers on VFP");
- return regEncode;
- }
- ///----------------------------------------------------------------------------
- ///
- /// EncoderMD::GetOpdope
- ///
- /// Get the dope vector of a particular instr. The dope vector describes
- /// certain properties of an instr.
- ///
- ///----------------------------------------------------------------------------
- uint32
- EncoderMD::GetOpdope(IR::Instr *instr)
- {
- return GetOpdope(instr->m_opcode);
- }
- uint32
- EncoderMD::GetOpdope(Js::OpCode op)
- {
- return Opdope[op - (Js::OpCode::MDStart+1)];
- }
- //
- // EncoderMD::CanonicalizeInstr :
- // Put the instruction in its final form for encoding. This may involve
- // expanding a pseudo-op such as LEA or changing an opcode to indicate the
- // op bits the encoder should use.
- //
- // Return the size of the final instruction's encoding.
- //
- InstructionType EncoderMD::CanonicalizeInstr(IR::Instr* instr)
- {
- if (!instr->IsLowered())
- {
- return InstructionType::None;
- }
- switch (instr->m_opcode)
- {
- CASE_OPCODES_ALWAYS_THUMB2
- return InstructionType::Thumb2;
- CASE_OPCODES_NEVER_THUMB2
- return InstructionType::Thumb;
- case Js::OpCode::MOV:
- return this->CanonicalizeMov(instr);
- case Js::OpCode::B:
- return InstructionType::Thumb2; // For now only T2 branches are encoded
- case Js::OpCode::BL:
- return InstructionType::Thumb2;
- case Js::OpCode::BNE:
- case Js::OpCode::BEQ:
- case Js::OpCode::BLT:
- case Js::OpCode::BLE:
- case Js::OpCode::BGE:
- case Js::OpCode::BGT:
- case Js::OpCode::BCS:
- case Js::OpCode::BCC:
- case Js::OpCode::BHI:
- case Js::OpCode::BLS:
- case Js::OpCode::BMI:
- case Js::OpCode::BPL:
- case Js::OpCode::BVS:
- case Js::OpCode::BVC:
- return InstructionType::Thumb2; // For now only T2 branches are encoded
- case Js::OpCode::CMP:
- return this->CmpEncodeType(instr);
- case Js::OpCode::CMN:
- return this->CmnEncodeType(instr);
- case Js::OpCode::CMP_ASR31:
- return InstructionType::Thumb2;
- case Js::OpCode::POP:
- return this->PushPopEncodeType(instr->GetSrc1()->AsIndirOpnd(), instr->GetDst()->AsRegBVOpnd());
- case Js::OpCode::PUSH:
- return this->PushPopEncodeType(instr->GetDst()->AsIndirOpnd(), instr->GetSrc1()->AsRegBVOpnd());
- case Js::OpCode::LDR:
- return this->CanonicalizeLoad(instr);
- case Js::OpCode::STR:
- return this->CanonicalizeStore(instr);
- case Js::OpCode::LEA:
- return this->CanonicalizeLea(instr);
- case Js::OpCode::ADD:
- case Js::OpCode::ADDS:
- return this->CanonicalizeAdd(instr);
- case Js::OpCode::SUB:
- case Js::OpCode::SUBS:
- return this->CanonicalizeSub(instr);
- case Js::OpCode::AND:
- case Js::OpCode::EOR:
- case Js::OpCode::MUL:
- case Js::OpCode::ORR:
- case Js::OpCode::RSB:
- case Js::OpCode::RSBS:
- case Js::OpCode::BIC:
- return this->Alu3EncodeType(instr);
- case Js::OpCode::EOR_ASR31:
- return InstructionType::Thumb2;
- case Js::OpCode::SMULL:
- case Js::OpCode::SMLAL:
- return InstructionType::Thumb2;
- case Js::OpCode::MVN:
- return this->Alu2EncodeType(instr->GetDst(), instr->GetSrc1());
- case Js::OpCode::TST:
- return this->Alu2EncodeType(instr->GetSrc1(), instr->GetSrc2());
- case Js::OpCode::ASR:
- case Js::OpCode::ASRS:
- case Js::OpCode::LSL:
- case Js::OpCode::LSR:
- return this->ShiftEncodeType(instr);
- case Js::OpCode::VSTR:
- case Js::OpCode::VSTR32:
- case Js::OpCode::VLDR:
- case Js::OpCode::VLDR32:
- case Js::OpCode::VABS:
- case Js::OpCode::VSQRT:
- case Js::OpCode::VMOV:
- case Js::OpCode::VMOVARMVFP:
- case Js::OpCode::VCVTF64F32:
- case Js::OpCode::VCVTF32F64:
- case Js::OpCode::VCVTF64S32:
- case Js::OpCode::VCVTF64U32:
- case Js::OpCode::VCVTS32F64:
- case Js::OpCode::VCVTRS32F64:
- case Js::OpCode::VPUSH:
- case Js::OpCode::VPOP:
- case Js::OpCode::VADDF64:
- case Js::OpCode::VSUBF64:
- case Js::OpCode::VMULF64:
- case Js::OpCode::VDIVF64:
- case Js::OpCode::VNEGF64:
- case Js::OpCode::VCMPF64:
- case Js::OpCode::VMRS:
- case Js::OpCode::VMRSR:
- case Js::OpCode::VMSR:
- return InstructionType::Vfp;
- default:
- AssertMsg(UNREACHED, "Unexpected opcode in IsInstrThumb2");
- return InstructionType::None;
- }
- }
- // CanonicalizeMov: Determine the size of the encoding and change the opcode
- // if necessary to indicate a wide instruction. (We do this for MOV, LDR, and STR
- // to cut down on the time it takes to search all the possible forms.)
- InstructionType EncoderMD::CanonicalizeMov(IR::Instr * instr)
- {
- // 3 possibilities:
- // 1. MOV (T1):
- // - uint8 to low reg
- // - any reg to reg
- // 2. MOVW (T2):
- // - uint16 to reg
- // 3. MOV_W (T2):
- // - mod const imm to reg
- IR::RegOpnd *dstOpnd = instr->GetDst()->AsRegOpnd();
- IR::Opnd *srcOpnd = instr->GetSrc1();
- if (srcOpnd->IsRegOpnd())
- {
- // All reg to reg copies are 2 bytes.
- return InstructionType::Thumb;
- }
- IntConstType immed = srcOpnd->GetImmediateValue(instr->m_func);
- if (IS_LOWREG(dstOpnd->GetReg()) &&
- IS_CONST_UINT8(immed))
- {
- // uint8 -> low reg
- return InstructionType::Thumb;
- }
- // Wide MOV instruction. Choose the opcode based on the constant.
- if (IS_CONST_UINT16(immed))
- {
- instr->m_opcode = Js::OpCode::MOVW;
- }
- else
- {
- Assert(CanEncodeModConst12(immed));
- instr->m_opcode = Js::OpCode::MOV_W;
- }
- return InstructionType::Thumb2;
- }
- // CanonicalizeLoad: Determine the size of the encoding and change the opcode
- // if necessary to indicate a wide instruction. (We do this for MOV, LDR, and STR
- // to cut down on the time it takes to search all the possible forms.)
- InstructionType EncoderMD::CanonicalizeLoad(IR::Instr * instr)
- {
- IR::Opnd *memOpnd = instr->GetSrc1();
- // Note: sign-extension of less-than-4-byte loads requires a wide instruction.
- if (memOpnd->GetSize() == 4 || memOpnd->IsUnsigned())
- {
- if (!this->IsWideMemInstr(instr->GetSrc1(), instr->GetDst()->AsRegOpnd()))
- {
- return InstructionType::Thumb;
- }
- }
- instr->m_opcode = Js::OpCode::LDR_W;
- return InstructionType::Thumb2;
- }
- // CanonicalizeStore: Determine the size of the encoding and change the opcode
- // if necessary to indicate a wide instruction. (We do this for MOV, LDR, and STR
- // to cut down on the time it takes to search all the possible forms.)
- InstructionType EncoderMD::CanonicalizeStore(IR::Instr * instr)
- {
- if (this->IsWideMemInstr(instr->GetDst(), instr->GetSrc1()->AsRegOpnd()))
- {
- instr->m_opcode = Js::OpCode::STR_W;
- return InstructionType::Thumb2;
- }
- return InstructionType::Thumb;
- }
- // IsWideMemInstr: Shared by LDR and STR.
- // Determine the width of the encoding based on the operand properties.
- bool EncoderMD::IsWideMemInstr(IR::Opnd *memOpnd, IR::RegOpnd *regOpnd)
- {
- // LDR/STR rn, [rbase + rindex], or
- // LDR/STR rn, [rbase + offset]
- // If rn is not low reg, instr is wide.
- if (!IS_LOWREG(regOpnd->GetReg()))
- {
- return true;
- }
- // Pull the base and index/offset from the indirection.
- RegNum baseReg;
- IR::RegOpnd *indexOpnd;
- int32 offset;
- if (memOpnd->IsSymOpnd())
- {
- indexOpnd = nullptr;
- this->BaseAndOffsetFromSym(memOpnd->AsSymOpnd(), &baseReg, &offset, this->m_func);
- }
- else
- {
- IR::IndirOpnd *indirOpnd = memOpnd->AsIndirOpnd();
- // Scaled index operands require wide instruction.
- if (indirOpnd->GetScale() > 0)
- {
- return true;
- }
- baseReg = indirOpnd->GetBaseOpnd()->GetReg();
- indexOpnd = indirOpnd->GetIndexOpnd();
- offset = indirOpnd->GetOffset();
- }
- Assert(offset == 0 || indexOpnd == nullptr);
- if (indexOpnd)
- {
- // Both base and index must be low regs.
- return !IS_LOWREG(baseReg) || !IS_LOWREG(indexOpnd->GetReg());
- }
- else
- {
- size_t size = memOpnd->GetSize();
- if (!IS_LOWREG(baseReg) && (baseReg != RegSP || size != 4))
- {
- // Base reg must be low or SP (and we only have 4-byte SP-relative ops).
- return true;
- }
- // Short encodings shift the offset based on the size of the load/store.
- // (E.g., 4-byte load shifts the offset by 2.)
- if (offset & (size - 1))
- {
- // Can't use a short encoding if we lose bits by shifting the offset.
- return true;
- }
- uint32 shiftBits = Math::Log2(size);
- if (baseReg == RegSP)
- {
- // LDR/STR rn, [SP + uint8:00]
- return !IS_CONST_UINT8(offset >> shiftBits);
- }
- else
- {
- // LDR/STR rn, [base + uint5:size]
- return !IS_CONST_UINT5(offset >> shiftBits);
- }
- }
- }
- InstructionType EncoderMD::CanonicalizeAdd(IR::Instr * instr)
- {
- IR::Opnd *src2 = instr->GetSrc2();
- IntConstType immed = 0;
- // Check cases that apply to ADD but not SUB.
- if (src2->IsRegOpnd())
- {
- // Check for rm = ADD rm, rn
- if (instr->m_opcode != Js::OpCode::ADDS &&
- instr->GetDst()->AsRegOpnd()->IsSameReg(instr->GetSrc1()))
- {
- return InstructionType::Thumb;
- }
- }
- else
- {
- immed = src2->GetImmediateValue(instr->m_func);
- // Check for rm = ADD SP, uint8:00
- if (IS_LOWREG(instr->GetDst()->AsRegOpnd()->GetReg()))
- {
- if (instr->GetSrc1()->AsRegOpnd()->GetReg() == RegSP)
- {
- if ((immed & 3) == 0 && IS_CONST_UINT8(immed >> 2))
- {
- return InstructionType::Thumb;
- }
- }
- }
- }
- // Now check the shared ADD/SUB cases.
- if (this->IsWideAddSub(instr))
- {
- // The instr is definitely wide. Let the opcode indicate that if we're using the uint12 form.
- // Note that the uint12 form can't set the status bits.
- if (!src2->IsRegOpnd() && !this->CanEncodeModConst12(immed))
- {
- Assert(instr->m_opcode != Js::OpCode::ADDS);
- Assert(IS_CONST_UINT12(immed));
- instr->m_opcode = Js::OpCode::ADDW;
- }
- return InstructionType::Thumb2;
- }
- return InstructionType::Thumb;
- }
- InstructionType EncoderMD::CanonicalizeSub(IR::Instr * instr)
- {
- if (this->IsWideAddSub(instr))
- {
- IR::Opnd *src2 = instr->GetSrc2();
- // The instr is definitely wide. Let the opcode indicate that if we're using the uint12 form.
- // Note that the uint12 form can't set the status bits.
- if (!src2->IsRegOpnd() && !this->CanEncodeModConst12(src2->GetImmediateValue(instr->m_func)))
- {
- Assert(instr->m_opcode != Js::OpCode::SUBS);
- Assert(IS_CONST_UINT12(src2->GetImmediateValue(instr->m_func)));
- instr->m_opcode = Js::OpCode::SUBW;
- }
- return InstructionType::Thumb2;
- }
- return InstructionType::Thumb;
- }
- bool EncoderMD::IsWideAddSub(IR::Instr * instr)
- {
- IR::RegOpnd *dst = instr->GetDst()->AsRegOpnd();
- IR::RegOpnd *src1 = instr->GetSrc1()->AsRegOpnd();
- IR::Opnd *src2 = instr->GetSrc2();
- IntConstType immed;
- if (dst->GetReg() == RegSP)
- {
- // The one short form is SP = op SP, uint7:00
- if (src1->GetReg() != RegSP)
- {
- return true;
- }
- if (src2->IsRegOpnd())
- {
- return true;
- }
- immed = src2->GetImmediateValue(instr->m_func);
- return ((immed & 3) != 0) || !IS_CONST_UINT7(immed >> 2);
- }
- else
- {
- // low1 = op low2, low3 or
- // low1 = op low2, uint3 or
- // low1 = op low1, uint8
- if (!IS_LOWREG(dst->GetReg()) || !IS_LOWREG(src1->GetReg()))
- {
- return true;
- }
- if (src2->IsRegOpnd())
- {
- return !IS_LOWREG(src2->AsRegOpnd()->GetReg());
- }
- else
- {
- immed = src2->GetImmediateValue(instr->m_func);
- return dst->IsSameReg(src1) ? !IS_CONST_UINT8(immed) : !IS_CONST_UINT3(immed);
- }
- }
- }
- InstructionType EncoderMD::CanonicalizeLea(IR::Instr * instr)
- {
- RegNum baseReg;
- int32 offset;
- IR::Opnd* src1 = instr->UnlinkSrc1();
- if (src1->IsSymOpnd())
- {
- // We may as well turn this LEA into the equivalent ADD instruction and let the common ADD
- // logic handle it.
- IR::SymOpnd *symOpnd = src1->AsSymOpnd();
- this->BaseAndOffsetFromSym(symOpnd, &baseReg, &offset, this->m_func);
- symOpnd->Free(this->m_func);
- instr->SetSrc1(IR::RegOpnd::New(nullptr, baseReg, TyMachReg, this->m_func));
- instr->SetSrc2(IR::IntConstOpnd::New(offset, TyMachReg, this->m_func));
- }
- else
- {
- IR::IndirOpnd *indirOpnd = src1->AsIndirOpnd();
- IR::RegOpnd *baseOpnd = indirOpnd->GetBaseOpnd();
- IR::RegOpnd *indexOpnd = indirOpnd->GetIndexOpnd();
- offset = indirOpnd->GetOffset();
- Assert(offset == 0 || indexOpnd == nullptr);
- instr->SetSrc1(baseOpnd);
- if (indexOpnd)
- {
- AssertMsg(indirOpnd->GetScale() == 0, "NYI Needs shifted register support for ADD");
- instr->SetSrc2(indexOpnd);
- }
- else
- {
- instr->SetSrc2(IR::IntConstOpnd::New(offset, TyMachReg, this->m_func));
- }
- indirOpnd->Free(this->m_func);
- }
- instr->m_opcode = Js::OpCode::ADD;
- return this->CanonicalizeAdd(instr);
- }
- InstructionType EncoderMD::CmpEncodeType(IR::Instr * instr)
- {
- // CMP:
- // - low reg, uint8
- // - any reg, any reg
- IR::Opnd *src2 = instr->GetSrc2();
- if (src2->IsRegOpnd())
- {
- Assert(instr->GetSrc1()->IsRegOpnd());
- return InstructionType::Thumb;
- }
- if (IS_LOWREG(instr->GetSrc1()->AsRegOpnd()->GetReg()) &&
- IS_CONST_UINT8(src2->GetImmediateValue(instr->m_func)))
- {
- return InstructionType::Thumb;
- }
- return InstructionType::Thumb2;
- }
- InstructionType EncoderMD::CmnEncodeType(IR::Instr * instr)
- {
- // CMN:
- // - low reg, low reg
- // - any reg, uint8
- // - any reg, any reg
- IR::Opnd *src2 = instr->GetSrc2();
- if (src2->IsRegOpnd())
- {
- // low reg, low reg
- if (IS_LOWREG(instr->GetSrc1()->AsRegOpnd()->GetReg()) && IS_LOWREG(instr->GetSrc2()->AsRegOpnd()->GetReg()))
- {
- return InstructionType::Thumb;
- }
- }
- // any reg, uint8
- // any reg, any reg
- return InstructionType::Thumb2;
- }
- InstructionType EncoderMD::PushPopEncodeType(IR::IndirOpnd *target, IR::RegBVOpnd * opnd)
- {
- if(target->GetBaseOpnd()->GetReg() != RegSP)
- {
- return InstructionType::Thumb2;
- }
- // NOTE: because T1 encoding permits LR here, we could theoretically check for it specially,
- // but in practice we never push LR without R11, so it would never help. If that changes, we
- // should make this function smarter.
- BYTE lastRegEncode = (BYTE)opnd->m_value.GetPrevBit();
- Assert(lastRegEncode != BVInvalidIndex);
- return lastRegEncode > RegEncode[RegR7] ? InstructionType::Thumb2 : InstructionType::Thumb;
- }
- InstructionType EncoderMD::Alu2EncodeType(IR::Opnd *opnd1, IR::Opnd *opnd2)
- {
- // Shared by TST (checks src1 and src2) and MVN (checks dst and src1), which is why we pass
- // operands rather than the whole instruction.
- // Short encoding requires two low regs as operands.
- if (!opnd1->IsRegOpnd() || !IS_LOWREG(opnd1->AsRegOpnd()->GetReg()))
- {
- return InstructionType::Thumb2;
- }
- if (!opnd2->IsRegOpnd() || !IS_LOWREG(opnd2->AsRegOpnd()->GetReg()))
- {
- return InstructionType::Thumb2;
- }
- return InstructionType::Thumb;
- }
- InstructionType EncoderMD::Alu3EncodeType(IR::Instr * instr)
- {
- // Check for rm = op rm, rn
- IR::RegOpnd *dst = instr->GetDst()->AsRegOpnd();
- if (!IS_LOWREG(dst->GetReg()) ||
- !dst->IsSameReg(instr->GetSrc1()))
- {
- return InstructionType::Thumb2;
- }
- IR::Opnd *src2 = instr->GetSrc2();
- if (!src2->IsRegOpnd() || !IS_LOWREG(src2->AsRegOpnd()->GetReg()))
- {
- return InstructionType::Thumb2;
- }
- return InstructionType::Thumb;
- }
- InstructionType EncoderMD::ShiftEncodeType(IR::Instr * instr)
- {
- // 2 short forms:
- // rm = op rn, uint5
- // rm = op rm, rn
- IR::RegOpnd *dst = instr->GetDst()->AsRegOpnd();
- if (!IS_LOWREG(dst->GetReg()))
- {
- return InstructionType::Thumb2;
- }
- IR::RegOpnd *src1 = instr->GetSrc1()->AsRegOpnd();
- IR::Opnd *src2 = instr->GetSrc2();
- if (src2->IsRegOpnd())
- {
- return (IS_LOWREG(src2->AsRegOpnd()->GetReg()) && dst->IsSameReg(src1)) ? InstructionType::Thumb : InstructionType::Thumb2;
- }
- else
- {
- Assert(IS_CONST_UINT5(src2->GetImmediateValue(instr->m_func)));
- return IS_LOWREG(src1->GetReg()) ? InstructionType::Thumb : InstructionType::Thumb2;
- }
- }
- int
- EncoderMD::IndirForm(int form, int *pOpnnum, RegNum baseReg, IR::Opnd *indexOpnd)
- {
- int opnnum = *pOpnnum;
- form |= FSRC(INDIR, opnnum++);
- switch (baseReg)
- {
- case RegSP:
- form |= FSRC(SP, opnnum++);
- break ;
- case RegPC:
- form |= FSRC(PC, opnnum++);
- break;
- default:
- form |= FSRC(REG, opnnum++);
- break;
- }
- if (indexOpnd == nullptr)
- {
- // UTC does this for OPBASED. Seems to be based on the assumption
- // that we have either an offset or an index, but not both.
- form |= FSRC(CONST, opnnum++); // OFFSET
- }
- else
- {
- form |= FSRC(REG, opnnum++); // INDEX
- }
- *pOpnnum = opnnum;
- return form;
- }
- //---------------------------------------------------------------------------
- //
- // CoGenIForms()
- //
- // parses the instruction tuple and generates the corresponding 'form' constant
- //
- //---------------------------------------------------------------------------
- int
- EncoderMD::GetForm(IR::Instr *instr, int32 size)
- {
- int form;
- int opnnum; //Current looping operand in the instruction
- int operands; //Represents if the current operand is dst or source
- RegNum regNum;
- IR::Opnd* dst;
- IR::Opnd* opn;
- IR::IndirOpnd *indirOpnd;
- bool sameSrcDst = false;
- bool T2instr = false;
- form = 0;
- T2instr = (size == 4);
- // Set THUMB or THUMB2 instruction, this is to figure out if the form is T2 or T1.
- if (T2instr)
- {
- form |= FTHUMB2;
- }
- else
- {
- sameSrcDst = true;
- form |= FTHUMB;
- }
- dst = instr->GetDst();
- if (dst == nullptr || LowererMD::IsCall(instr))
- {
- opn = instr->GetSrc1();
- opnnum = 1;
- operands = 1;
- if (instr->IsBranchInstr() && instr->AsBranchInstr()->GetTarget())
- {
- // Treat the label reference as the first source.
- form |= FSRC(LABEL, opnnum++);
- }
- }
- else
- {
- opn = dst;
- opnnum = 0;
- operands = 0;
- }
- bool done = false;
- while (opn != nullptr)
- {
- switch (opn->GetKind())
- {
- case IR::OpndKindIntConst:
- case IR::OpndKindFloatConst:
- case IR::OpndKindAddr: //UTC - CASE_DATAADDRTUPLE
- {
- form |= FSRC(CONST, opnnum++);
- }
- break;
- case IR::OpndKindReg:
- {
- regNum = opn->AsRegOpnd()->GetReg();
- switch (regNum)
- {
- case RegSP:
- case RegPC:
- if (size != 4 || instr->m_opcode == Js::OpCode::LDRRET)
- {
- if (regNum == RegSP)
- {
- form |= FSRC(SP, opnnum++);
- }
- else
- {
- form |= FSRC(PC, opnnum++);
- }
- break;
- }
- // FALL THROUGH!
- default:
- if (regNum >= RegR0 && regNum <= RegPC)
- {
- if ((regNum > RegR7) && (!T2instr))
- {
- form |= FSET(REG,28);
- }
- if (operands == 0)
- { // dst operands
- form |= FSRC(REG,opnnum++);
- }
- else
- { // src operands
- if (sameSrcDst && dst && opn->AsRegOpnd()->IsSameReg(dst))
- {
- form |= FSRC(REG,0); // same src,dst
- sameSrcDst = false;
- }
- else
- {
- form |= FSRC(REG, opnnum++);
- }
- }
- }
- else if (regNum >= RegR0 && regNum <= LAST_DOUBLE_REG)
- {
- form |= FSRC(DREG, opnnum++);
- }
- break;
- }
- }
- break;
- case IR::OpndKindHelperCall:
- {
- form |= FSRC(CODE, opnnum++);
- }
- break;
- case IR::OpndKindRegBV:
- {
- Assert(instr->m_opcode == Js::OpCode::PUSH || instr->m_opcode == Js::OpCode::POP
- || instr->m_opcode == Js::OpCode::VPUSH || instr->m_opcode == Js::OpCode::VPOP);
- BVIndex count = opn->AsRegBVOpnd()->GetValue().Count();
- Assert(count > 0);
- // Note: only the wide encoding distinguishes between single- and multiple-register push/pop.
- if (count == 1 && T2instr)
- {
- form |= FSRC(REG, opnnum++);
- }
- break;
- }
- case IR::OpndKindIndir:
- indirOpnd = opn->AsIndirOpnd();
- form = this->IndirForm(form, &opnnum, indirOpnd->GetBaseOpnd()->GetReg(), indirOpnd->GetIndexOpnd());
- break;
- case IR::OpndKindSym:
- {
- RegNum baseReg;
- int32 offset;
- AssertMsg(opn->AsSymOpnd()->m_sym->IsStackSym(), "Should only see stackSym syms in encoder.");
- form |= FSRC(INDIR, opnnum++);
- this->BaseAndOffsetFromSym(opn->AsSymOpnd(), &baseReg, &offset, this->m_func);
- if (baseReg == RegSP)
- {
- form |= FSRC(SP, opnnum++);
- }
- else
- {
- form |= FSRC(REG, opnnum++);
- form |= FSRC(CONST, opnnum++);
- }
- break;
- }
- case IR::OpndKindLabel:
- form |= FSRC(LABEL, opnnum++);
- break;
- case IR::OpndKindMemRef:
- // Deref of literal address
- AssertMsg(0, "NYI");
- return 0;
- default:
- AssertMsg(UNREACHED, "Unrecognized kind");
- return 0;
- }
- if (done)
- {
- //If we have traversed all the 3 operands exit.
- break;
- }
- if (LowererMD::IsCall(instr))
- {
- break;
- }
- if (opn == dst)
- {
- opn = instr->GetSrc1();
- if (instr->IsBranchInstr() && instr->AsBranchInstr()->GetTarget())
- {
- // Treat the label reference as the first source.
- form |= FSRC(LABEL, opnnum++);
- }
- }
- else
- {
- opn = instr->GetSrc2();
- done = true;
- }
- operands = 1;
- }
- return (form);
- }
- bool EncoderMD::EncodeImmediate16(long constant, DWORD * result)
- {
- if (constant > 0xFFFF)
- {
- return FALSE;
- }
- DWORD encode = ((constant & 0xFF) << 16) |
- ((constant & 0x0700) << 20) |
- ((constant & 0x0800) >> 1) |
- ((constant & 0xF000) >> 12);
- *result |= encode;
- return TRUE;
- }
- ENCODE_32
- EncoderMD::EncodeT2Immediate12(ENCODE_32 encode, long constant)
- {
- Assert((constant & 0xFFFFF000) == 0);
- ENCODE_32 encoded = (constant & 0x800) >> (11-10);
- encoded |= (constant & 0x700) << (16+12-8);
- encoded |= (constant & 0xFF) << 16;
- encode |= encoded;
- return encode;
- }
- ENCODE_32
- EncoderMD::EncodeT2Offset(ENCODE_32 encode, IR::Instr *instr, int offset, int bitOffset)
- {
- if (EncoderMD::IsShifterUpdate(instr))
- {
- Assert(IS_CONST_INT8(offset));
- encode |= 9 << 24;
- if (!EncoderMD::IsShifterSub(instr))
- {
- encode |= 1 << 25;
- }
- if (!EncoderMD::IsShifterPost(instr))
- {
- encode |= 1 << 26;
- }
- }
- else
- {
- if (offset >=0)
- {
- Assert(IS_CONST_UINT12(offset));
- encode |= 1 << 7;
- }
- else
- {
- offset = -offset;
- Assert(IS_CONST_UINT8(offset));
- encode |= 0x0C000000;
- }
- }
- encode |= offset << bitOffset;
- return encode;
- }
- //---------------------------------------------------------------------------
- //
- // GenerateEncoding()
- //
- // generates the encoding for the specified tuple/form by applying the
- // associated encoding steps
- //
- //---------------------------------------------------------------------------
- ENCODE_32
- EncoderMD::GenerateEncoding(IR::Instr* instr, IFORM iform, BYTE *pc, int32 size, InstructionType instrType)
- {
- ENCODE_32 encode = 0 ;
- DWORD encoded = 0;
- IR::Opnd* opn = 0;
- IR::Opnd* dst = 0;
- IR::Opnd* reg = 0; //tupReg;
- IR::IndirOpnd *indirOpnd;
- Js::OpCode opcode = instr->m_opcode;
- const AssemblyStep *AsmSteps = nullptr;
- const FormTable *ftp = nullptr;
- int bitOffset;
- int offset;
- bool fUpdate;
- bool fSub;
- bool fPost;
- int done = false;
- long constant = 0; //UTC IVALTYPE
- bool constantValid = false;
- RegNum regNum;
- unsigned int iType = 0, SFlag = 0;
- dst = instr->GetDst();
- if(opcode == Js::OpCode::MLS)
- {
- Assert(instr->m_prev->GetDst()->IsRegOpnd() && (instr->m_prev->GetDst()->AsRegOpnd()->GetReg() == RegR12));
- }
- if (dst == nullptr || LowererMD::IsCall(instr))
- {
- opn = instr->GetSrc1();
- reg = opn;
- }
- else if (opcode == Js::OpCode::POP || opcode == Js::OpCode::VPOP)
- {
- opn = instr->GetSrc1();
- reg = dst;
- }
- else
- {
- opn = dst;
- reg = opn;
- }
- for (ftp = InstrEncode[opcode - (Js::OpCode::MDStart + 1)]; !done && ftp->form != FORM_NOMORE; ftp++)
- {
- if (ftp->form != iform)
- {
- if (!((iform & (1<<28)) == 0 && THUMB2_THUMB1_FORM(ftp->form, iform)))
- {
- continue;
- }
- }
- AsmSteps = ftp->steps;
- done = false;
- constantValid=0;
- while (!done)
- {
- switch (*AsmSteps++)
- {
- case STEP_NEXTOPN:
- // Get Next operand
- if (opn == dst)
- {
- opn = instr->GetSrc1();
- }
- else
- {
- Assert(opn == instr->GetSrc1());
- opn = instr->GetSrc2();
- }
- reg = opn;
- continue;
- case STEP_CONSTANT:
- Assert(opn->IsImmediateOpnd());
- constant = opn->GetImmediateValue(instr->m_func);
- constantValid = true;
- continue;
- case STEP_CALL:
- continue;
- case STEP_T2_BRANCH24:
- // Constant encoded with 24bits
- EncodeReloc::New(&m_relocList, RelocTypeBranch24, m_pc, instr->AsBranchInstr()->GetTarget(), m_encoder->m_tempAlloc);
- continue;
- case STEP_T2_BRANCH20:
- // Constant encoded with 20bits.
- EncodeReloc::New(&m_relocList, RelocTypeBranch20, m_pc, instr->AsBranchInstr()->GetTarget(), m_encoder->m_tempAlloc);
- continue;
- case STEP_REG:
- Assert(reg != nullptr);
- Assert(reg->IsRegOpnd());
- bitOffset = *AsmSteps++;
- regNum = (RegNum)this->GetRegEncode(reg->AsRegOpnd());
- encode |= regNum << bitOffset;
- continue;
- case STEP_HREG:
- Assert(reg != nullptr);
- Assert(reg->IsRegOpnd());
- bitOffset = *AsmSteps++;
- regNum = (RegNum)this->GetRegEncode(reg->AsRegOpnd());
- encode |= (regNum & 0x7) << bitOffset;
- continue;
- case STEP_R12:
- bitOffset = *AsmSteps++;
- regNum = (RegNum)this->GetRegEncode(RegR12);
- encode |= regNum << bitOffset;
- continue;
- case STEP_HBIT:
- Assert(reg != nullptr);
- Assert(reg->IsRegOpnd());
- regNum = (RegNum)this->GetRegEncode(reg->AsRegOpnd());
- if (regNum >= MAX_INT_REGISTERS_LOW)
- {
- bitOffset = *AsmSteps;
- encode |= 1 << bitOffset;
- }
- AsmSteps++;
- continue;
- case STEP_OPEQ:
- Assert(instr->GetDst()->AsRegOpnd()->IsSameReg(instr->GetSrc1()));
- continue;
- case STEP_DUMMY_REG:
- Assert(opn->AsRegOpnd()->GetReg() == RegSP ||
- opn->AsRegOpnd()->GetReg() == RegPC);
- continue;
- case STEP_OPCODE:
- //ASSERTTNR(!(instr & ftp->inst), tupInstr);
- encode |= ftp->inst;
- continue;
- case STEP_FIXUP:
- /*
- if (TU_ISINDIR(tupOpn)) {
- if (fApplyFixup)
- CoApplyFixup(tupOpn, dataBuf);
- }*/
- continue;
- case STEP_LDR:
- Assert(!constantValid);
- switch (opn->GetType())
- {
- case TyInt8:
- constant = 0x5600;
- case TyInt16:
- constant = 0x5e00;
- break;
- case TyInt32:
- case TyUint32:
- case TyVar:
- constant = 0x5800;
- break;
- case TyUint8:
- constant = 0x5c00;
- break;
- case TyUint16:
- constant = 0x5a00;
- break;
- }
- encode |= constant;
- continue;
- case STEP_LDRI:
- Assert(!constantValid);
- switch (opn->GetType())
- {
- case TyInt8:
- case TyInt16:
- constant = 0;
- break;
- case TyInt32:
- case TyUint32:
- case TyVar:
- constant = 0x6800;
- break;
- case TyUint8:
- constant = 0x7800;
- break;
- case TyUint16:
- constant = 0x8800;
- break;
- }
- encode |= constant;
- continue;
- case STEP_STRI:
- Assert(!constantValid);
- switch (opn->GetType())
- {
- case TyInt8:
- case TyUint8:
- constant = 0x7000;
- break;
- case TyInt16:
- case TyUint16:
- constant = 0x8000;
- break;
- case TyInt32:
- case TyUint32:
- case TyVar:
- constant = 0x6000;
- break;
- }
- encode |= constant;
- continue;
- case STEP_STR:
- Assert(!constantValid);
- switch (opn->GetType())
- {
- case TyInt8:
- case TyUint8:
- constant = 0x5400;
- break;
- case TyInt16:
- case TyUint16:
- constant = 0x5200;
- break;
- case TyInt32:
- case TyUint32:
- case TyVar:
- constant = 0x5000;
- break;
- }
- encode |= constant;
- continue;
- case STEP_IMM:
- bitOffset = *AsmSteps++;
- if (opn->IsIndirOpnd())
- {
- offset = opn->AsIndirOpnd()->GetOffset();
- }
- else
- {
- this->BaseAndOffsetFromSym(opn->AsSymOpnd(), ®Num, &offset, this->m_func);
- }
- switch (opn->GetSize())
- {
- case 1:
- break;
- case 2:
- Assert(!(offset & 0x1));
- offset = offset >> 1;
- break;
- case 4:
- Assert(!(offset & 0x3)); //check for word-align
- offset = offset >> 2;
- break;
- default:
- Assert(UNREACHED);
- offset = 0;
- }
- Assert(IS_CONST_UINT5(offset));
- encode |= offset << bitOffset;
- continue;
- case STEP_UIMM3:
- bitOffset = *AsmSteps++;
- Assert(constantValid);
- Assert(IS_CONST_UINT3(constant));
- encode |= constant << bitOffset;
- continue;
- case STEP_IMM_W7:
- Assert(constantValid);
- Assert(!(constant & 0x3)); // check for word-alignment
- constant = constant >> 2; // remove rightmost two zero bits
- Assert(IS_CONST_UINT7(constant));
- encode |= constant;
- constantValid = false;
- continue;
- case STEP_IMM_DPW8:
- Assert(constantValid);
- Assert(IS_CONST_UINT8(constant >> 2));
- Assert(constant % 4 == 0);
- encode |= constant >> 2;
- constantValid = false;
- continue;
- case STEP_IMM_W8:
- if (opn->IsSymOpnd())
- {
- this->BaseAndOffsetFromSym(opn->AsSymOpnd(), ®Num, &offset, this->m_func);
- }
- else
- {
- offset = opn->AsIndirOpnd()->GetOffset();
- }
- Assert(offset % 4 == 0);
- Assert(IS_CONST_UINT8(offset >> 2));
- encode |= offset >> 2;
- continue;
- case STEP_T2_IMM_16:
- if (!EncodeImmediate16(constant, &encoded))
- {
- AssertMsg(false,"constant > than 16 bits");
- }
- encode |= encoded;
- continue;
- case STEP_T2_IMM_12:
- encode = this->EncodeT2Immediate12(encode, constant);
- continue;
- case STEP_OFFSET:
- {
- unsigned int R_bit = 0;
- if (ISSTORE(instr->m_opcode))
- {
- if (TESTREGBIT(constant, RegLR))
- {
- R_bit = 1 << 8;
- }
- CLEARREGBIT(constant, RegLR);
- }
- else
- {
- if (TESTREGBIT(constant, RegPC))
- {
- R_bit = 1 << 8;
- }
- CLEARREGBIT(constant, RegPC);
- }
- Assert(IS_CONST_UINT8(constant));
- encode |= (CO_UIMMED8(constant) | R_bit);
- constantValid=false;
- continue;
- }
- case STEP_SCALE_CONST:
- {
- bitOffset = *AsmSteps++;
- byte scale = opn->AsIndirOpnd()->GetScale();
- Assert(IS_CONST_UINT5(scale));
- encode |= scale << bitOffset;
- continue;
- }
- case STEP_SHIFTER_CONST:
- bitOffset = *AsmSteps++;
- // TODO: When we have IR that can send Shifts we will
- // need to translate the following:
- // As of now instructions do not have a mechanism to
- // provide the shift offset.
- //ASSERTNR(IS_CONST_UINT5(TU_SHIFTER_SHIFT(tupOpn)));
- //instr |= TU_SHIFTER_SHIFT(tupOpn) << to;
- continue;
- case STEP_BASEREG:
- bitOffset = *AsmSteps++;
- if (opn->IsIndirOpnd())
- {
- regNum = opn->AsIndirOpnd()->GetBaseOpnd()->GetReg();
- }
- else
- {
- this->BaseAndOffsetFromSym(opn->AsSymOpnd(), ®Num, &offset, this->m_func);
- }
- encode |= RegEncode[regNum] << bitOffset;
- continue;
- case STEP_INDEXED:
- Assert(opn->IsIndirOpnd());
- Assert(opn->AsIndirOpnd()->GetIndexOpnd() != nullptr);
- Assert(opn->AsIndirOpnd()->GetOffset() == 0);
- continue;
- case STEP_INDEXREG:
- bitOffset = *AsmSteps++;
- reg = opn->AsIndirOpnd()->GetIndexOpnd();
- Assert(reg != nullptr);
- Assert(reg->IsRegOpnd());
- regNum = (RegNum)this->GetRegEncode(reg->AsRegOpnd());
- encode |= regNum << bitOffset;
- continue;
- case STEP_INDIR:
- Assert(opn->IsIndirOpnd() ||
- (opn->IsSymOpnd() && opn->AsSymOpnd()->m_sym->IsStackSym()));
- continue;
- case STEP_BASED:
- Assert((opn->IsIndirOpnd() && opn->AsIndirOpnd()->GetIndexOpnd() == nullptr) ||
- (opn->IsSymOpnd() && opn->AsSymOpnd()->m_sym->IsStackSym()));
- continue;
- case STEP_T2_REGLIST:
- //ASSERTTNR(constant_valid, tupOpn);
- encode |= constant << 16;
- constantValid = false;
- if (EncoderMD::IsShifterUpdate(instr))
- {
- encode |= 0x20;
- }
- continue;
- case STEP_UIMM5:
- bitOffset = *AsmSteps++;
- Assert(constantValid);
- Assert(IS_CONST_UINT5(constant));
- encode |= constant << bitOffset;
- constantValid = false;
- continue;
- case STEP_UIMM8:
- Assert(constantValid);
- Assert(IS_CONST_UINT8(constant));
- encode |= constant;
- constantValid = false;
- continue;
- case STEP_REGLIST:
- {
- indirOpnd = opn->AsIndirOpnd();
- Assert(indirOpnd->GetIndexOpnd() == nullptr);
- constant = indirOpnd->GetOffset();
- IR::Opnd *opndRD;
- if (EncoderMD::IsLoad(instr))
- {
- opndRD = instr->GetDst();
- }
- else
- {
- opndRD = instr->GetSrc1();
- }
- if (!constant)
- {
- BVUnit32 registers = opndRD->AsRegBVOpnd()->GetValue();
- unsigned long regenc;
- BVIndex index = registers.GetNextBit();
- // Note: only the wide encoding distinguishes between
- // single- and multiple-register push/pop.
- if (registers.Count() > 1 || size == 2)
- {
- // Add the physical register number
- do
- {
- regenc = 1 << index;
- constant |= regenc;
- }while ((index = registers.GetNextBit(index + 1))!= BVInvalidIndex);
- }
- else
- {
- bitOffset = *AsmSteps++;
- Assert(index < RegEncode[RegSP]);
- encode |= index << bitOffset;
- continue;
- }
- }
- if (size == 4)
- {
- fSub = EncoderMD::IsShifterSub(instr);
- fUpdate = EncoderMD::IsShifterUpdate(instr);
- encode |= fSub << 8;
- encode |= !fSub << 7;
- encode |= fUpdate << 5;
- }
- constantValid=true;
- }
- continue;
- case STEP_T1_SETS_CR0:
- {
- //ASSERTTNR(Tuple::FindReg(TU_DST(tupInstr), RG_SYM(CR0)) != nullptr, tupInstr);
- }
- continue;
- case STEP_SBIT:
- {
- if (this->SetsSBit(instr))
- {
- bitOffset = *AsmSteps;
- encode |= 1 << bitOffset;
- }
- AsmSteps++;
- }
- continue;
- case STEP_NOSBIT:
- // just asserts that we're not supposed to set the condition flags
- //
- Assert(!this->SetsSBit(instr));
- continue;
- case STEP_MODCONST_12:
- if (!EncodeModConst12(constant, &encoded))
- {
- Assert(UNREACHED);
- }
- encode |= encoded;
- continue;
- case STEP_T2_MEMIMM_POS12_NEG8:
- bitOffset = *AsmSteps++;
- Assert(opn != nullptr);
- if (opn->IsIndirOpnd())
- {
- Assert(opn->AsIndirOpnd()->GetIndexOpnd() == nullptr);
- offset = opn->AsIndirOpnd()->GetOffset();
- // TODO: Handle literal pool loads, if necessary
- // <tfs #775202>: LDR_W could have $Label Fixup for literal-pool
- //if (TU_FEFIXUPSYM(tupOpn) && SS_ISLABEL(TU_FEFIXUPSYM(tupOpn))) {
- // offset += (SS_OFFSET(TU_FEFIXUPSYM(tupOpn)) - ((pc & (~3)) + 4));
- //}
- }
- else if (opn->IsSymOpnd())
- {
- Assert(opn->AsSymOpnd()->m_sym->IsStackSym());
- this->BaseAndOffsetFromSym(opn->AsSymOpnd(), ®Num, &offset, this->m_func);
- }
- else
- {
- Assert(opn->IsImmediateOpnd());
- offset = opn->GetImmediateValue(instr->m_func);
- }
- encode = this->EncodeT2Offset(encode, instr, offset, bitOffset);
- continue;
- case STEP_T2_IMMSTACK_POS12_NEG8:
- bitOffset = *AsmSteps++;
- Assert(opn != nullptr);
- Assert(opn->IsSymOpnd() && opn->AsSymOpnd()->m_sym->IsStackSym());
- this->BaseAndOffsetFromSym(opn->AsSymOpnd(), ®Num, &offset, this->m_func);
- encode = this->EncodeT2Offset(encode, instr, offset, bitOffset);
- encode |= RegEncode[regNum];
- continue;
- case STEP_T2_STACKSYM_IMM_12:
- // Used by LEA. Encode base reg at the given bit offset and 12-bit constant
- // as a normal ADDW immediate.
- bitOffset = *AsmSteps++;
- Assert(opn != nullptr);
- Assert(opn->IsSymOpnd() && opn->AsSymOpnd()->m_sym->IsStackSym());
- this->BaseAndOffsetFromSym(opn->AsSymOpnd(), ®Num, &offset, this->m_func);
- encode |= RegEncode[regNum] << bitOffset;
- encode = this->EncodeT2Immediate12(encode, offset);
- continue;
- case STEP_T2_MEM_TYPE:
- {
- Assert((ftp->inst & 0xFF00) == 0xF800);
- switch (opn->GetType())
- {
- case TyInt8:
- SFlag = 1;
- iType = 0;
- break;
- case TyUint8:
- SFlag = 0;
- iType = 0;
- break;
- case TyInt16:
- SFlag = 1;
- iType = 1;
- break;
- case TyUint16:
- iType = 1;
- SFlag = 0;
- break;
- case TyInt32:
- case TyUint32:
- case TyVar:
- SFlag = 0;
- iType = 2;
- break;
- default:
- Assert(UNREACHED);
- }
- if (!EncoderMD::IsLoad(instr))
- {
- SFlag = 0;
- }
- encode |= (SFlag << 8) | (iType << 5);
- continue;
- }
- case STEP_T2_SHIFT_IMM_5:
- #if DBG
- if(instr->m_opcode == Js::OpCode::ASR ||
- instr->m_opcode == Js::OpCode::ASRS ||
- instr->m_opcode == Js::OpCode::LSR)
- {
- // Encoding zero is interpreted as 32
- // for these instructions.
- Assert(constant != 0);
- }
- #endif
- Assert(IS_CONST_UINT5(constant));
- encoded = (constant & 0x03) << (16+6);
- encoded |= (constant & 0x1c) << (16+12-2);
- encode |= encoded;
- continue;
- case STEP_MOVW_reloc:
- Assert(opn && opn->IsLabelOpnd());
- if (opn->AsLabelOpnd()->GetLabel()->m_isDataLabel)
- {
- Assert(!opn->AsLabelOpnd()->GetLabel()->isInlineeEntryInstr);
- EncodeReloc::New(&m_relocList, RelocTypeDataLabelLow, m_pc, opn->AsLabelOpnd()->GetLabel(), m_encoder->m_tempAlloc);
- }
- else
- {
- EncodeReloc::New(&m_relocList, RelocTypeLabelLow, m_pc, opn->AsLabelOpnd()->GetLabel(), m_encoder->m_tempAlloc);
- }
- continue;
- case STEP_MOVT_reloc:
- Assert(opn && opn->IsLabelOpnd());
- EncodeReloc::New(&m_relocList, RelocTypeLabelHigh, m_pc, opn->AsLabelOpnd()->GetLabel(), m_encoder->m_tempAlloc);
- continue;
- case STEP_DREG:
- {
- int bbit = 0;
- DWORD tmp = 0;
- Assert(opn != nullptr && opn->IsRegOpnd());
- bitOffset = *AsmSteps++;
- bbit = *AsmSteps++;
- regNum = (RegNum)GetRegEncode(opn->AsRegOpnd());
- //Check to see if register number is valid
- Assert(regNum >= 0 && regNum <= LAST_DOUBLE_REG_NUM);
- tmp |= (regNum & 0xf) << bitOffset;
- tmp |= ((regNum >> 4) & 0x1) << bbit;
- Assert(0 == (encode & tmp));
- encode |= tmp;
- continue;
- }
- case STEP_SREG:
- {
- int bbit = 0;
- DWORD tmp = 0;
- Assert(opn != nullptr && opn->IsRegOpnd());
- bitOffset = *AsmSteps++;
- bbit = *AsmSteps++;
- regNum = (RegNum)GetFloatRegEncode(opn->AsRegOpnd());
- //Check to see if register number is valid
- Assert(regNum >= 0 && regNum <= LAST_FLOAT_REG_NUM);
- tmp |= (regNum & 0x1) << bbit;
- tmp |= (regNum >> 1) << bitOffset;
- Assert(0 == (encode & tmp));
- encode |= tmp;
- continue;
- }
- case STEP_IMM_S8:
- {
- Assert(opn!=nullptr);
- AssertMsg(instrType == InstructionType::Vfp, "This step is specific to VFP instructions");
- if (opn->IsIndirOpnd())
- {
- Assert(opn->AsIndirOpnd()->GetIndexOpnd() == nullptr);
- offset = opn->AsIndirOpnd()->GetOffset();
- // TODO: Handle literal pool loads, if necessary
- // <tfs #775202>: LDR_W could have $Label Fixup for literal-pool
- //if (TU_FEFIXUPSYM(tupOpn) && SS_ISLABEL(TU_FEFIXUPSYM(tupOpn))) {
- // offset += (SS_OFFSET(TU_FEFIXUPSYM(tupOpn)) - ((pc & (~3)) + 4));
- //}
- }
- else if (opn->IsSymOpnd())
- {
- Assert(opn->AsSymOpnd()->m_sym->IsStackSym());
- this->BaseAndOffsetFromSym(opn->AsSymOpnd(), ®Num, &offset, this->m_func);
- }
- else
- {
- offset = 0;
- AssertMsg(false, "Why are we here");
- }
- if (offset < 0)
- {
- //IsShifterSub(tupOpn) = TRUE; //Doesn't seem necessary for us, why does UTC set this?
- offset = -offset;
- encode &= ~(1 << 7);
- }
- else
- {
- encode |= (1 << 7);
- }
- // Set the W (writeback) bit if IsShifterUpdate is
- // specified.
- if (EncoderMD::IsShifterUpdate(instr))
- {
- encode |= (1 << 5);
- // Set the P (pre-indexed) bit to be the complement
- // of IsShifterPost
- if (EncoderMD::IsShifterPost(instr))
- {
- encode &= ~(1 << 8);
- }
- else
- {
- encode |= (1 << 8);
- }
- }
- else
- {
- // Clear the W bit and set the P bit (offset
- // addressing).
- encode &= ~(1 << 5);
- encode |= (1 << 8);
- }
- Assert(IS_CONST_UINT8(offset >> 2));
- encode |= ((offset >> 2) << 16);
- continue;
- }
- case STEP_DREGLIST:
- {
- IR::Opnd *opndRD;
- if (EncoderMD::IsLoad(instr))
- {
- opndRD = instr->GetDst();
- }
- else
- {
- opndRD = instr->GetSrc1();
- }
- BVUnit32 registers = opndRD->AsRegBVOpnd()->GetValue();
- DWORD first = registers.GetNextBit();
- DWORD last = (DWORD)-1;
- _BitScanReverse((DWORD*)&last, (DWORD)registers.GetWord());
- Assert(last >= first && last <= LAST_DOUBLE_CALLEE_SAVED_REG_NUM);
- encode |= (CO_UIMMED8((last - first + 1) * 2)) << 16;
- encode |= (first << 28);
- }
- continue;
- case STEP_AM5:
- Assert(opn->IsIndirOpnd());
- Assert(opn->AsIndirOpnd()->GetIndexOpnd() == nullptr);
- Assert(opn->AsIndirOpnd()->GetOffset() == 0);
- fPost = EncoderMD::IsShifterPost(instr);
- fSub = EncoderMD::IsShifterSub(instr);
- fUpdate = EncoderMD::IsShifterUpdate(instr);
- // update addressing mode
- encode |= !fPost << 8;
- encode |= !fSub << 7;
- encode |= fUpdate << 5;
- continue;
- case STEP_DONE:
- done = true;
- break;
- default:
- #if DBG
- instr->Dump();
- AssertMsg(UNREACHED, "Unrecognized assembly step");
- #endif
- return 0;
- }
- break;
- }
- }
- #if DBG
- if (!done)
- {
- instr->Dump();
- Output::Flush();
- AssertMsg(UNREACHED, "Unsupported Instruction Form");
- }
- #endif
- return encode;
- }
- #ifdef INSERT_NOPS
- ptrdiff_t insertNops(BYTE *pc, ENCODE_32 outInstr, uint count, uint size)
- {
- //Insert count nops in the beginning
- for(int i = 0; i < count;i++)
- {
- *(ENCODE_32 *)(pc + i * sizeof(ENCODE_32)) = 0x8000F3AF;
- }
- if (size == sizeof(ENCODE_16))
- {
- *(ENCODE_16 *)(pc + count * sizeof(ENCODE_32)) = (ENCODE_16)(outInstr & 0x0000ffff);
- *(ENCODE_16 *)(pc + sizeof(ENCODE_16) + count * sizeof(ENCODE_32)) = (ENCODE_16)(0xBF00);
- }
- else
- {
- Assert(size == sizeof(ENCODE_32));
- *(ENCODE_32 *)(pc + count * sizeof(ENCODE_32)) = outInstr;
- }
- //Insert count nops at the end;
- for(int i = count + 1; i < (2 *count + 1); i++)
- {
- *(ENCODE_32 *)(pc + i * sizeof(ENCODE_32)) = 0x8000F3AF;
- }
- return MachInt*(2*count + 1);
- }
- #endif //INSERT_NOPS
- #ifdef SOFTWARE_FIXFOR_HARDWARE_BUGWIN8_502326
- bool
- EncoderMD::IsBuggyHardware()
- {
- return true;
- // TODO: Enable this for restricting to Qualcomm Krait cores affected: KR28M2A10, KR28M2A11, KR28M2A12
- /*
- AssertMsg(AutoSystemInfo::Data.wProcessorArchitecture == 5, "This has to be ARM architecture");
- if (((AutoSystemInfo::Data.wProcessorLevel & 0xFC0) == 0x40) && ((AutoSystemInfo::Data.wProcessorRevision & 0xF0) == 0))
- {
- #if DBG_DUMP
- if (Js::Configuration::Global.flags.Trace.IsEnabled(Js::EncoderPhase))
- {
- Output::Print(L"TRACE: Running in buggy hardware.\n");
- }
- #endif
- return true;
- }
- return false;
- */
- }
- bool
- EncoderMD::CheckBranchInstrCriteria(IR::Instr* instr)
- {
- if (ISQBUGGYBR(instr->m_opcode))
- {
- return true;
- }
- #if DBG
- switch (instr->m_opcode)
- {
- case Js::OpCode::RET: //This is never Thumb2 hence we are safe in this hardware bug
- return false;
- case Js::OpCode::BL:
- AssertMsg(false, "We don't generate these now. Include in the opcode list above for BL T1 encodings");
- return false;
- case Js::OpCode::BLX:
- AssertMsg(instr->GetSrc1()->IsRegOpnd(),"If we generate label include in the opcode list above");
- //Fallthrough
- default:
- {
- //Assert to make sure none of the other instructions have target as PC register.
- if (instr->GetDst() && instr->GetDst()->IsRegOpnd())
- {
- AssertMsg(instr->GetDst()->AsRegOpnd()->GetReg() != RegPC, "Check for this opcode above");
- }
- }
- }
- #endif
- return false;
- }
- #endif //SOFTWARE_FIXFOR_HARDWARE_BUGWIN8_502326
- ///----------------------------------------------------------------------------
- ///
- /// EncoderMD::Encode
- ///
- /// Emit the ARM encoding for the given instruction in the passed in
- /// buffer ptr.
- ///
- ///----------------------------------------------------------------------------
- ptrdiff_t
- EncoderMD::Encode(IR::Instr *instr, BYTE *pc, BYTE* beginCodeAddress)
- {
- m_pc = pc;
- ENCODE_32 outInstr;
- IFORM iform;
- int size = 0;
- // Instructions must be lowered, we don't handle non-MD opcodes here.
- Assert(instr != nullptr);
- if (instr->IsLowered() == false)
- {
- if (instr->IsLabelInstr())
- {
- if (instr->isInlineeEntryInstr)
- {
- Js::Var inlineeCallInfo = 0;
- const bool encodeResult = Js::InlineeCallInfo::Encode(inlineeCallInfo, instr->AsLabelInstr()->GetOffset(), m_pc - m_encoder->m_encodeBuffer);
- Assert(encodeResult);
- //We are re-using offset to save the inlineeCallInfo which will be patched in ApplyRelocs
- //This is a cleaner way to patch MOVW\MOVT pair with the right inlineeCallInfo
- instr->AsLabelInstr()->ResetOffset((uint32)inlineeCallInfo);
- }
- else
- {
- instr->AsLabelInstr()->SetPC(m_pc);
- if (instr->AsLabelInstr()->m_id == m_func->m_unwindInfo.GetPrologStartLabel())
- {
- m_func->m_unwindInfo.SetPrologOffset(m_pc - m_encoder->m_encodeBuffer);
- }
- else if (instr->AsLabelInstr()->m_id == m_func->m_unwindInfo.GetEpilogEndLabel())
- {
- // This is the last instruction in the epilog. Any instructions that follow
- // are separated code, so the unwind info will have to represent them as a function
- // fragment. (If there's no separated code, then this offset will equal the total
- // code size.)
- m_func->m_unwindInfo.SetEpilogEndOffset(m_pc - m_encoder->m_encodeBuffer - m_func->m_unwindInfo.GetPrologOffset());
- }
- }
- }
- #if DBG_DUMP
- if (instr->IsEntryInstr() && Js::Configuration::Global.flags.DebugBreak.Contains(m_func->GetFunctionNumber()))
- {
- IR::Instr *int3 = IR::Instr::New(Js::OpCode::DEBUGBREAK, m_func);
- return this->Encode(int3, m_pc);
- }
- #endif
- return 0;
- }
- #ifdef SOFTWARE_FIXFOR_HARDWARE_BUGWIN8_502326
- if (IsBuggyHardware())
- {
- // Hardware bug is in Qualcomm 8960. 32 bit thumb branch instructions might not jump to the correct address in following
- // conditions:
- // a.3 T16 thumb instruction followed by T32 branch instruction (conditional\unconditional & RegPc load).
- // b.Branch instruction starts at 0x*****FBE
- // As we don't know the final address, instead of checking for 0x*FBE we just check for offset 0x*E
- // as the final function start address is always aligned at 16 byte boundary (EMIT_BUFFER_ALIGNMENT)
- if (consecutiveThumbInstrCount >= 3 && (((uint)(m_pc - beginCodeAddress) & 0xF) == 0xE) && CheckBranchInstrCriteria(instr))
- {
- Assert(beginCodeAddress);
- IR::Instr *nop = IR::Instr::New(Js::OpCode::VMOV,
- IR::RegOpnd::New(nullptr, RegD15, TyMachDouble, this->m_func),
- IR::RegOpnd::New(nullptr, RegD15, TyMachDouble, this->m_func),
- m_func);
- size = this->Encode(nop, m_pc);
- consecutiveThumbInstrCount = 0;
- size+= this->Encode(instr, m_pc + size);
- #if DBG_DUMP
- if (Js::Configuration::Global.flags.Trace.IsEnabled(Js::EncoderPhase))
- {
- Output::Print(L"TRACE: Avoiding Branch instruction and Dummy nops at 0x*E \n");
- }
- #endif
- Assert(size == 8);
- // We are okay with returning size 8 as the previous 3 thumb instructions any way would have saved 6 bytes
- // and doesn't alter the logic of allocating temp buffer based on MachMaxInstrSize
- return size;
- }
- }
- #endif
- InstructionType instrType = this->CanonicalizeInstr(instr);
- switch(instrType)
- {
- case Thumb:
- size = 2;
- consecutiveThumbInstrCount++;
- break;
- case Thumb2:
- size = 4;
- consecutiveThumbInstrCount = 0;
- break;
- case Vfp:
- size = 4;
- consecutiveThumbInstrCount = 0;
- break;
- default: Assert(false);
- }
- AssertMsg(size != MachChar, "Thumb2 is never single Byte");
- iform = (IFORM)GetForm(instr, size);
- outInstr = GenerateEncoding(instr, iform, m_pc, size, instrType);
- if (outInstr == 0)
- {
- return 0;
- }
- // TODO: Check if VFP/Neon instructions in Thumb-2 mode we need to swap the instruction halfwords
- if (size == sizeof(ENCODE_16))
- {
- #ifdef INSERT_NOPS
- return insertNops(m_pc, outInstr, CountNops, sizeof(ENCODE_16));
- #else
- //2 byte Thumb encoding
- Assert((outInstr & 0xffff0000) == 0);
- *(ENCODE_16 *)m_pc = (ENCODE_16)(outInstr & 0x0000ffff);
- return MachShort;
- #endif
- }
- else if (size == sizeof(ENCODE_32))
- {
- #ifdef INSERT_NOPS
- return insertNops(m_pc, outInstr, CountNops, sizeof(ENCODE_32));
- #else
- //4 byte Thumb2 encoding
- *(ENCODE_32 *)m_pc = outInstr ;
- return MachInt;
- #endif
- }
- AssertMsg(UNREACHED, "Unexpected size");
- return 0;
- }
- bool
- EncoderMD::CanEncodeModConst12(DWORD constant)
- {
- DWORD encode;
- return EncodeModConst12(constant, &encode);
- }
- bool
- EncoderMD::EncodeModConst12(DWORD constant, DWORD * result)
- {
- unsigned int a, b, c, d, rotation, firstbit, lastbit, temp=0;
- if (constant == 0)
- {
- *result = 0;
- return true;
- }
- a = constant & 0xff;
- b = (constant >> 8) & 0xff;
- c = (constant >> 16) & 0xff;
- d = (constant >> 24) & 0xff;
- _BitScanReverse((DWORD*)&firstbit, constant);
- _BitScanForward((DWORD*)&lastbit, constant);
- if (! ((a == 0 && c == 0 && b == d)
- || (b == 0 && d == 0 && a == c)
- || (a == b && b == c && c == d)
- || (firstbit-lastbit < 8) ))
- {
- return false;
- }
- *result = 0;
- if (constant <= 0xFF)
- {
- *result |= constant << 16;
- }
- else if (firstbit-lastbit < 8)
- {
- if (firstbit > 7)
- {
- temp |= 0x7F & (constant >> (firstbit-7));
- rotation = 32-firstbit+7;
- }
- else
- {
- temp |= 0x7F & (constant << (7-firstbit));
- rotation = 7-firstbit;
- }
- *result = (temp & 0xFF) << 16;
- *result |= (0x10 & rotation) << 6;
- *result |= (0xE & rotation) << 27;
- *result |= (0x1 & rotation) << 23;
- }
- else
- {
- if (a==0 && c==0 && b==d)
- {
- *result |= 0x20000000; // HW2[12]
- *result |= (0xFF & b) << 16;
- }
- else if (a==c && b==0 && d==0)
- {
- *result |= 0x10000000;
- *result |= (0xFF & a) << 16;
- }
- else if (a==b && b==c && c==d)
- {
- *result |= 0x30000000;
- *result |= (0xFF & d) << 16;
- }
- else
- {
- Assert(UNREACHED);
- }
- }
- return true;
- }
- ///----------------------------------------------------------------------------
- ///
- /// EncodeReloc::New
- ///
- ///----------------------------------------------------------------------------
- void
- EncodeReloc::New(EncodeReloc **pHead, RelocType relocType, BYTE *offset, IR::Instr *relocInstr, ArenaAllocator *alloc)
- {
- EncodeReloc *newReloc = AnewStruct(alloc, EncodeReloc);
- newReloc->m_relocType = relocType;
- newReloc->m_consumerOffset = offset;
- newReloc->m_next = *pHead;
- newReloc->m_relocInstr = relocInstr;
- *pHead = newReloc;
- }
- ENCODE_32 EncoderMD::CallOffset(int x)
- {
- Assert(IS_CONST_INT24(x >> 1));
- ENCODE_32 ret;
- int Sflag = (x & 0x1000000) >> 24;
- int off23 = (x & 0x800000) >> 23;
- int off22 = (x & 0x400000) >> 22;
- ret = (x & 0xFFE) << 15;
- ret |= (x & 0x3FF000) >> 12;
- ret |= (((~off23) ^ Sflag) & 0x1) << (16+13);
- ret |= (((~off22) ^ Sflag) & 0x1) << (16+11);
- ret |= (Sflag << 10);
- return ret;
- }
- ENCODE_32 EncoderMD::BranchOffset_T2_24(int x)
- {
- x -= 4;
- Assert(IS_CONST_INT24(x >> 1));
- int ret;
- int Sflag = (x & 0x1000000) >> 24;
- int off23 = (x & 0x800000) >> 23;
- int off22 = (x & 0x400000) >> 22;
- ret = (x & 0xFFE) << 15;
- ret |= (x & 0x3FF000) >> 12;
- ret |= (((~off23) ^ Sflag) & 0x1) << (16+13);
- ret |= (((~off22) ^ Sflag) & 0x1) << (16+11);
- ret |= (Sflag << 10);
- return INSTR_TYPE(ret);
- }
- ENCODE_32 EncoderMD::BranchOffset_T2_20(int x)
- {
- x -= 4;
- Assert(IS_CONST_INT21(x));
- uint32 ret;
- uint32 Sflag = (x & 0x100000) >> 20;
- uint32 off19 = (x & 0x80000) >> 19;
- uint32 off18 = (x & 0x40000) >> 18;
- ret = (x & 0xFFE) << 15;
- ret |= (x & 0x3F000) >> 12;
- ret |= off18 << (13+16);
- ret |= off19 << (11+16);
- ret |= (Sflag << 10);
- return ret;
- }
- void
- EncoderMD::BaseAndOffsetFromSym(IR::SymOpnd *symOpnd, RegNum *pBaseReg, int32 *pOffset, Func * func)
- {
- StackSym *stackSym = symOpnd->m_sym->AsStackSym();
- RegNum baseReg = func->GetLocalsPointer();
- int32 offset = stackSym->m_offset + symOpnd->m_offset;
- if (baseReg == RegSP)
- {
- // SP points to the base of the argument area. Non-reg SP points directly to the locals.
- offset += (func->m_argSlotsForFunctionsCalled * MachRegInt);
- if (func->GetMaxInlineeArgOutCount())
- {
- Assert(func->HasInlinee());
- if ((!stackSym->IsArgSlotSym() || stackSym->m_isOrphanedArg) && !stackSym->IsParamSlotSym())
- {
- offset += func->GetInlineeArgumentStackSize();
- }
- }
- }
- if (stackSym->IsParamSlotSym())
- {
- offset += func->m_localStackHeight + func->m_ArgumentsOffset;
- if (!EncoderMD::CanEncodeLoadStoreOffset(offset))
- {
- // Use the frame pointer. No need to hoist an offset for a param.
- baseReg = FRAME_REG;
- offset = stackSym->m_offset + symOpnd->m_offset - (Js::JavascriptFunctionArgIndex_Frame * MachRegInt);
- Assert(EncoderMD::CanEncodeLoadStoreOffset(offset));
- }
- }
- #ifdef DBG
- else
- {
- // Locals are offset by the size of the area allocated for stack args.
- Assert(offset >= 0);
- Assert(baseReg != RegSP || (uint)offset >= (func->m_argSlotsForFunctionsCalled * MachRegInt));
- if (func->GetMaxInlineeArgOutCount())
- {
- Assert(baseReg == RegSP);
- if (stackSym->IsArgSlotSym() && !stackSym->m_isOrphanedArg)
- {
- Assert(stackSym->m_isInlinedArgSlot);
- Assert((uint)offset <= ((func->m_argSlotsForFunctionsCalled + func->GetMaxInlineeArgOutCount()) * MachRegInt));
- }
- else
- {
- AssertMsg(stackSym->IsAllocated(), "StackSym offset should be set");
- Assert((uint)offset > ((func->m_argSlotsForFunctionsCalled + func->GetMaxInlineeArgOutCount()) * MachRegInt));
- }
- }
- // TODO: restore the following assert (very useful) once we have a way to tell whether prolog/epilog
- // gen is complete.
- //Assert(offset < func->m_localStackHeight);
- }
- #endif
- *pBaseReg = baseReg;
- *pOffset = offset;
- }
- ///----------------------------------------------------------------------------
- ///
- /// EncoderMD::ApplyRelocs
- /// We apply relocations to the temporary buffer using the target buffer's address
- /// before we copy the contents of the temporary buffer to the target buffer.
- ///----------------------------------------------------------------------------
- void
- EncoderMD::ApplyRelocs(uint32 codeBufferAddress)
- {
- for (EncodeReloc *reloc = m_relocList; reloc; reloc = reloc->m_next)
- {
- BYTE * relocAddress = reloc->m_consumerOffset;
- int32 pcrel;
- ENCODE_32 encode = *(ENCODE_32*)relocAddress;
- switch (reloc->m_relocType)
- {
- case RelocTypeBranch20:
- {
- IR::LabelInstr * labelInstr = reloc->m_relocInstr->AsLabelInstr();
- Assert(!labelInstr->isInlineeEntryInstr);
- AssertMsg(labelInstr->GetPC() != nullptr, "Branch to unemitted label?");
- pcrel = (uint32)(labelInstr->GetPC() - reloc->m_consumerOffset);
- encode |= BranchOffset_T2_20(pcrel);
- *(uint32 *)relocAddress = encode;
- break;
- }
- case RelocTypeBranch24:
- {
- IR::LabelInstr * labelInstr = reloc->m_relocInstr->AsLabelInstr();
- Assert(!labelInstr->isInlineeEntryInstr);
- AssertMsg(labelInstr->GetPC() != nullptr, "Branch to unemitted label?");
- pcrel = (uint32)(labelInstr->GetPC() - reloc->m_consumerOffset);
- encode |= BranchOffset_T2_24(pcrel);
- *(ENCODE_32 *)relocAddress = encode;
- break;
- }
- case RelocTypeDataLabelLow:
- {
- IR::LabelInstr * labelInstr = reloc->m_relocInstr->AsLabelInstr();
- Assert(!labelInstr->isInlineeEntryInstr && labelInstr->m_isDataLabel);
- AssertMsg(labelInstr->GetPC() != nullptr, "Branch to unemitted label?");
- pcrel = ((labelInstr->GetPC() - m_encoder->m_encodeBuffer + codeBufferAddress) & 0xFFFF);
- if (!EncodeImmediate16(pcrel, (DWORD*) &encode))
- {
- Assert(UNREACHED);
- }
- *(ENCODE_32 *) relocAddress = encode;
- break;
- }
- case RelocTypeLabelLow:
- {
- // Absolute (not relative) label address (lower 16 bits)
- IR::LabelInstr * labelInstr = reloc->m_relocInstr->AsLabelInstr();
- if (!labelInstr->isInlineeEntryInstr)
- {
- AssertMsg(labelInstr->GetPC() != nullptr, "Branch to unemitted label?");
- // Note that the bottom bit must be set, since this is a Thumb code address.
- pcrel = ((labelInstr->GetPC() - m_encoder->m_encodeBuffer + codeBufferAddress) & 0xFFFF) | 1;
- }
- else
- {
- //This is a encoded low 16 bits.
- pcrel = labelInstr->GetOffset() & 0xFFFF;
- }
- if (!EncodeImmediate16(pcrel, (DWORD*) &encode))
- {
- Assert(UNREACHED);
- }
- *(ENCODE_32 *) relocAddress = encode;
- break;
- }
- case RelocTypeLabelHigh:
- {
- // Absolute (not relative) label address (upper 16 bits)
- IR::LabelInstr * labelInstr = reloc->m_relocInstr->AsLabelInstr();
- if (!labelInstr->isInlineeEntryInstr)
- {
- AssertMsg(labelInstr->GetPC() != nullptr, "Branch to unemitted label?");
- pcrel = (labelInstr->GetPC() - m_encoder->m_encodeBuffer + codeBufferAddress) >> 16;
- // We only record the relocation on the low byte of the pair
- }
- else
- {
- //This is a encoded high 16 bits.
- pcrel = labelInstr->GetOffset() >> 16;
- }
- if (!EncodeImmediate16(pcrel, (DWORD*) &encode))
- {
- Assert(UNREACHED);
- }
- *(ENCODE_32 *) relocAddress = encode;
- break;
- }
- case RelocTypeLabel:
- {
- IR::LabelInstr * labelInstr = reloc->m_relocInstr->AsLabelInstr();
- AssertMsg(labelInstr->GetPC() != nullptr, "Branch to unemitted label?");
- /* For Thumb instruction set -> OR 1 with the address*/
- *(uint32 *)relocAddress = (uint32)(labelInstr->GetPC() - m_encoder->m_encodeBuffer + codeBufferAddress) | 1;
- break;
- }
- default:
- AssertMsg(UNREACHED, "Unknown reloc type");
- }
- }
- }
- void
- EncoderMD::EncodeInlineeCallInfo(IR::Instr *instr, uint32 codeOffset)
- {
- IR::LabelInstr* inlineeStart = instr->AsLabelInstr();
- Assert((inlineeStart->GetOffset() & 0x0F) == inlineeStart->GetOffset());
- return;
- }
- bool EncoderMD::TryConstFold(IR::Instr *instr, IR::RegOpnd *regOpnd)
- {
- Assert(regOpnd->m_sym->IsConst());
- if (instr->m_opcode == Js::OpCode::MOV)
- {
- if (instr->GetSrc1() != regOpnd)
- {
- return false;
- }
- if (!instr->GetDst()->IsRegOpnd())
- {
- return false;
- }
- instr->ReplaceSrc(regOpnd, regOpnd->m_sym->GetConstOpnd());
- LegalizeMD::LegalizeInstr(instr, false);
- return true;
- }
- else
- {
- return false;
- }
- }
- bool EncoderMD::TryFold(IR::Instr *instr, IR::RegOpnd *regOpnd)
- {
- if (LowererMD::IsAssign(instr))
- {
- if (!instr->GetDst()->IsRegOpnd() || regOpnd != instr->GetSrc1())
- {
- return false;
- }
- IR::SymOpnd *symOpnd = IR::SymOpnd::New(regOpnd->m_sym, regOpnd->GetType(), instr->m_func);
- instr->ReplaceSrc(regOpnd, symOpnd);
- LegalizeMD::LegalizeInstr(instr, false);
- return true;
- }
- else
- {
- return false;
- }
- }
- void EncoderMD::AddLabelReloc(BYTE* relocAddress)
- {
- Assert(relocAddress != nullptr);
- EncodeReloc::New(&m_relocList, RelocTypeLabel, relocAddress, *(IR::Instr**)relocAddress, m_encoder->m_tempAlloc);
- }
|