| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441 |
- //-------------------------------------------------------------------------------------------------------
- // 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.
- ///
- ///----------------------------------------------------------------------------
- BYTE
- EncoderMD::GetRegEncode(IR::RegOpnd *regOpnd)
- {
- return GetRegEncode(regOpnd->GetReg());
- }
- BYTE
- EncoderMD::GetRegEncode(RegNum reg)
- {
- return RegEncode[reg];
- }
- 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::VMOVF64R32L:
- case Js::OpCode::VMOVF64R32U:
- 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;
- }
- int32 immed = srcOpnd->GetImmediateValueAsInt32(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();
- int32 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->GetImmediateValueAsInt32(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.
- Assert(!IRType_IsInt64(src2->GetType()));
- if (!src2->IsRegOpnd() && !this->CanEncodeModConst12(src2->GetImmediateValueAsInt32(instr->m_func)))
- {
- Assert(instr->m_opcode != Js::OpCode::SUBS);
- Assert(IS_CONST_UINT12(src2->GetImmediateValueAsInt32(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();
- int32 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->GetImmediateValueAsInt32(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->GetImmediateValueAsInt32(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->GetImmediateValueAsInt32(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->GetImmediateValueAsInt32(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(int32 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, int32 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;
- int32 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->GetImmediateValueAsInt32(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();
- uint32 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->GetImmediateValueAsInt32(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(_u("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)
- {
- intptr_t 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 ENABLE_DEBUG_CONFIG_OPTIONS
- if (instr->IsEntryInstr() && (
- Js::Configuration::Global.flags.DebugBreak.Contains(m_func->GetFunctionNumber()) ||
- PHASE_ON(Js::DebugBreakPhase, m_func)
- ))
- {
- 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(_u("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->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->GetMaxInlineeArgOutSize() != 0)
- {
- Assert(func->HasInlinee());
- Assert(baseReg == (func->HasTry() ? RegR7 : RegSP));
- if (stackSym->IsArgSlotSym() && !stackSym->m_isOrphanedArg)
- {
- Assert(stackSym->m_isInlinedArgSlot);
- Assert((uint)offset <= func->m_argSlotsForFunctionsCalled * MachRegInt + func->GetMaxInlineeArgOutSize());
- }
- else
- {
- AssertMsg(stackSym->IsAllocated(), "StackSym offset should be set");
- Assert(offset > (func->HasTry() ? (int32)func->GetMaxInlineeArgOutSize() : (int32)(func->m_argSlotsForFunctionsCalled * MachRegInt + func->GetMaxInlineeArgOutSize())));
- }
- }
- // 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, size_t codeSize, uint* bufferCRC, BOOL isBrShorteningSucceeded, bool isFinalBufferValidation)
- {
- 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);
- 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);
- 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);
- }
|