| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842 |
- //-------------------------------------------------------------------------------------------------------
- // Copyright (C) Microsoft Corporation and contributors. All rights reserved.
- // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
- //-------------------------------------------------------------------------------------------------------
- #include "Backend.h"
- #include "Core/CRC.h"
- #include "X86Encode.h"
- static const BYTE OpcodeByte2[]={
- #define MACRO(name, jnLayout, attrib, byte2, ...) byte2,
- #include "MdOpCodes.h"
- #undef MACRO
- };
- struct FormTemplate{ BYTE form[6]; };
- #define f(form) TEMPLATE_FORM_ ## form
- static const struct FormTemplate OpcodeFormTemplate[] =
- {
- #define MACRO(name, jnLayout, attrib, byte2, form, ...) form ,
- #include "MdOpCodes.h"
- #undef MACRO
- };
- #undef f
- struct OpbyteTemplate { byte opbyte[6]; };
- static const struct OpbyteTemplate Opbyte[] =
- {
- #define MACRO(name, jnLayout, attrib, byte2, form, opbyte, ...) opbyte,
- #include "MdOpCodes.h"
- #undef MACRO
- };
- static const uint32 Opdope[] =
- {
- #define MACRO(name, jnLayout, attrib, byte2, form, opbyte, dope, ...) dope,
- #include "MdOpCodes.h"
- #undef MACRO
- };
- static const BYTE RegEncode[] =
- {
- #define REGDAT(Name, Listing, Encoding, ...) Encoding,
- #include "RegList.h"
- #undef REGDAT
- };
- static const enum Forms OpcodeForms[] =
- {
- #define MACRO(name, jnLayout, attrib, byte2, form, ...) form,
- #include "MdOpCodes.h"
- #undef MACRO
- };
- static const uint32 OpcodeLeadIn[] =
- {
- #define MACRO(name, jnLayout, attrib, byte2, form, opByte, dope, leadIn, ...) leadIn,
- #include "MdOpCodes.h"
- #undef MACRO
- };
- static const BYTE Nop1[] = { 0x90 }; /* nop */
- static const BYTE Nop2[] = { 0x66, 0x90 }; /* 66 nop */
- static const BYTE Nop3[] = { 0x0F, 0x1F, 0x00 }; /* nop dword ptr [eax] */
- static const BYTE Nop4[] = { 0x0F, 0x1F, 0x40, 0x00 }; /* nop dword ptr [eax + 0] */
- static const BYTE *Nop[4] = { Nop1, Nop2, Nop3, Nop4 };
- enum CMP_IMM8
- {
- EQ,
- LT,
- LE,
- UNORD,
- NEQ,
- NLT,
- NLE,
- ORD
- };
- ///----------------------------------------------------------------------------
- ///
- /// EncoderMD::Init
- ///
- ///----------------------------------------------------------------------------
- void
- EncoderMD::Init(Encoder *encoder)
- {
- m_encoder = encoder;
- m_relocList = nullptr;
- m_lastLoopLabelPosition = -1;
- }
- ///----------------------------------------------------------------------------
- ///
- /// EncoderMD::GetOpcodeByte2
- ///
- /// Get the second byte encoding of the given instr.
- ///
- ///----------------------------------------------------------------------------
- const BYTE
- EncoderMD::GetOpcodeByte2(IR::Instr *instr)
- {
- return OpcodeByte2[instr->m_opcode - (Js::OpCode::MDStart+1)];
- }
- ///----------------------------------------------------------------------------
- ///
- /// EncoderMD::GetInstrForm
- ///
- /// Get the form list of the given instruction. The form list contains
- /// the possible encoding forms of an instruction.
- ///
- ///----------------------------------------------------------------------------
- Forms
- EncoderMD::GetInstrForm(IR::Instr *instr)
- {
- return OpcodeForms[instr->m_opcode - (Js::OpCode::MDStart+1)];
- }
- const BYTE *
- EncoderMD::GetFormTemplate(IR::Instr *instr)
- {
- return OpcodeFormTemplate[instr->m_opcode - (Js::OpCode::MDStart + 1)].form;
- }
- ///----------------------------------------------------------------------------
- ///
- /// EncoderMD::GetOpbyte
- ///
- /// Get the first byte opcode of an instr.
- ///
- ///----------------------------------------------------------------------------
- const BYTE *
- EncoderMD::GetOpbyte(IR::Instr *instr)
- {
- return Opbyte[instr->m_opcode - (Js::OpCode::MDStart+1)].opbyte;
- }
- ///----------------------------------------------------------------------------
- ///
- /// EncoderMD::GetRegEncode
- ///
- /// Get the x86 encoding of a given register.
- ///
- ///----------------------------------------------------------------------------
- const BYTE
- EncoderMD::GetRegEncode(IR::RegOpnd *regOpnd)
- {
- AssertMsg(regOpnd->GetReg() != RegNOREG, "RegOpnd should have valid reg in encoder");
- return RegEncode[regOpnd->GetReg()];
- }
- ///----------------------------------------------------------------------------
- ///
- /// EncoderMD::GetOpdope
- ///
- /// Get the dope vector of a particular instr. The dope vector describes
- /// certain properties of an instr.
- ///
- ///----------------------------------------------------------------------------
- const uint32
- EncoderMD::GetOpdope(IR::Instr *instr)
- {
- return Opdope[instr->m_opcode - (Js::OpCode::MDStart+1)];
- }
- ///----------------------------------------------------------------------------
- ///
- /// EncoderMD::GetLeadIn
- ///
- /// Get the leadin of a particular instr.
- ///
- ///----------------------------------------------------------------------------
- const uint32
- EncoderMD::GetLeadIn(IR::Instr * instr)
- {
- return OpcodeLeadIn[instr->m_opcode - (Js::OpCode::MDStart+1)];
- }
- ///----------------------------------------------------------------------------
- ///
- /// EncoderMD::FitsInByte
- ///
- /// Can we encode this value into a signed extended byte?
- ///
- ///----------------------------------------------------------------------------
- bool
- EncoderMD::FitsInByte(size_t value)
- {
- return ((size_t)(signed char)(value & 0xFF) == value);
- }
- ///----------------------------------------------------------------------------
- ///
- /// EncoderMD::GetMod
- ///
- /// Get the "MOD" part of a MODRM encoding for a given operand.
- ///
- ///----------------------------------------------------------------------------
- BYTE
- EncoderMD::GetMod(IR::IndirOpnd * opr, int* pDispSize)
- {
- return GetMod(opr->AsIndirOpnd()->GetOffset(), (opr->GetBaseOpnd()->GetReg() == RegEBP), pDispSize);
- }
- BYTE
- EncoderMD::GetMod(IR::SymOpnd * symOpnd, int * pDispSize, RegNum& rmReg)
- {
- StackSym * stackSym = symOpnd->m_sym->AsStackSym();
- int32 offset = stackSym->m_offset;
- rmReg = RegEBP;
- if (stackSym->IsArgSlotSym() && !stackSym->m_isOrphanedArg)
- {
- if (stackSym->m_isInlinedArgSlot)
- {
- Assert(offset >= 0);
- offset -= this->m_func->m_localStackHeight;
- stackSym->m_offset = offset;
- stackSym->m_allocated = true;
- }
- else
- {
- rmReg = RegESP;
- }
- }
- else
- {
- Assert(offset != 0);
- }
- return GetMod(offset + symOpnd->m_offset, rmReg == RegEBP, pDispSize);
- }
- BYTE
- EncoderMD::GetMod(size_t offset, bool baseRegIsEBP, int * pDispSize)
- {
- if (offset == 0 && !baseRegIsEBP)
- {
- *(pDispSize) = 0;
- return 0x00;
- }
- else if (this->FitsInByte(offset))
- {
- *(pDispSize) = 1;
- return 0x40;
- }
- else
- {
- *(pDispSize) = 4;
- return 0x80;
- }
- }
- ///----------------------------------------------------------------------------
- ///
- /// EncoderMD::EmitModRM
- ///
- /// Emit an effective address using the MODRM byte.
- ///
- ///----------------------------------------------------------------------------
- void
- EncoderMD::EmitModRM(IR::Instr * instr, IR::Opnd *opnd, BYTE reg1)
- {
- RegNum rmReg;
- int dispSize;
- IR::IndirOpnd *indirOpnd;
- IR::RegOpnd *regOpnd;
- IR::RegOpnd *baseOpnd;
- IR::RegOpnd *indexOpnd;
- BYTE reg;
- BYTE regBase;
- BYTE regIndex;
- #ifdef DBG
- dispSize = -1;
- #endif
- reg1 = (reg1 & 7) << 3; // mask and put in reg field
- switch (opnd->GetKind())
- {
- case IR::OpndKindReg:
- regOpnd = opnd->AsRegOpnd();
- AssertMsg(regOpnd->GetReg() != RegNOREG, "All regOpnd should have a valid reg set during encoder");
- reg = this->GetRegEncode(regOpnd);
- // Special handling for TEST_AH
- if (instr->m_opcode == Js::OpCode::TEST_AH)
- {
- // We can't represent AH in the IR. We should have AL now, add 4 to represent AH.
- Assert(regOpnd->GetReg() == RegEAX && regOpnd->GetType() == TyInt8);
- reg += 4;
- }
- this->EmitConst((0xC0| reg1 | reg), 1);
- return;
- case IR::OpndKindSym:
- AssertMsg(opnd->AsSymOpnd()->m_sym->IsStackSym(), "Should only see stackSym syms in encoder.");
- BYTE mod;
- BYTE byte;
- uint32 baseRegEncode;
- mod = this->GetMod(opnd->AsSymOpnd(), &dispSize, rmReg);
- AssertMsg(rmReg != RegNOREG, "rmReg should have been set");
- baseRegEncode = rmReg - RegEAX;
- byte = (BYTE)(mod | reg1 | baseRegEncode);
- *(m_pc++) = byte;
- if (rmReg == RegESP)
- {
- byte = (BYTE)(((baseRegEncode & 7) << 3) | (baseRegEncode & 7));
- *(m_pc++) = byte;
- }
- else
- {
- AssertMsg(opnd->AsSymOpnd()->m_sym->AsStackSym()->m_offset, "Expected stackSym offset to be set.");
- }
- break;
- case IR::OpndKindIndir:
- indirOpnd = opnd->AsIndirOpnd();
- baseOpnd = indirOpnd->GetBaseOpnd();
- indexOpnd = indirOpnd->GetIndexOpnd();
- AssertMsg(!indexOpnd || indexOpnd->GetReg() != RegESP, "ESP cannot be the index of an indir.");
- if (baseOpnd == nullptr)
- {
- Assert(indexOpnd != nullptr);
- regIndex = this->GetRegEncode(indexOpnd);
- dispSize = 4;
- *(m_pc++) = (0x00 | reg1 | 0x4);
- *(m_pc++) = (((indirOpnd->GetScale() & 3) << 6) | ((regIndex & 7) << 3) | 0x5);
- }
- else
- {
- regBase = this->GetRegEncode(baseOpnd);
- if (indexOpnd != nullptr)
- {
- regIndex = this->GetRegEncode(indexOpnd);
- *(m_pc++) = (this->GetMod(indirOpnd, &dispSize) | reg1 | 0x4);
- *(m_pc++) = (((indirOpnd->GetScale() & 3) << 6) | ((regIndex & 7) << 3) | (regBase & 7));
- }
- else
- {
- *(m_pc++) = (this->GetMod(indirOpnd, &dispSize) | reg1 | regBase);
- if (baseOpnd->GetReg() == RegESP)
- {
- // needs SIB byte
- *(m_pc++) = ((regBase & 7) << 3) | (regBase & 7);
- }
- }
- }
- break;
- case IR::OpndKindMemRef:
- *(m_pc++) = (char)(reg1 | 0x5);
- dispSize = 4;
- break;
- default:
- #if DBG
- AssertMsg(UNREACHED, "Unexpected operand kind");
- dispSize = -1; // Satisfy prefast
- break;
- #else
- __assume(UNREACHED);
- #endif
- }
- AssertMsg(dispSize != -1, "Uninitialized dispSize");
- this->EmitImmed(opnd, dispSize, 0);
- }
- ///----------------------------------------------------------------------------
- ///
- /// EncoderMD::EmitConst
- ///
- /// Emit a constant of the given size.
- ///
- ///----------------------------------------------------------------------------
- void
- EncoderMD::EmitConst(size_t val, int size)
- {
- switch (size) {
- case 0:
- return;
- case 1:
- *(uint8*)m_pc = (char)val;
- break;
- case 2:
- *(uint16*)m_pc = (short)val;
- break;
- case 4:
- *(uint32*)m_pc = (uint32)val;
- break;
- default:
- AssertMsg(UNREACHED, "Unexpected size");
- }
- m_pc += size;
- }
- ///----------------------------------------------------------------------------
- ///
- /// EncoderMD::EmitImmed
- ///
- /// Emit the immediate value of the given operand. It returns 0x2 for a
- /// sbit encoding, 0 otherwise.
- ///
- ///----------------------------------------------------------------------------
- int
- EncoderMD::EmitImmed(IR::Opnd * opnd, int opSize, int sbit)
- {
- int retval = 0;
- StackSym *stackSym;
- size_t value = 0;
- switch (opnd->GetKind()) {
- case IR::OpndKindAddr:
- value = (uint32)opnd->AsAddrOpnd()->m_address;
- goto intConst;
- case IR::OpndKindIntConst:
- value = opnd->AsIntConstOpnd()->GetValue();
- intConst:
- if (sbit && opSize > 1 && this->FitsInByte(value))
- {
- opSize = 1;
- retval = 0x2; /* set S bit */
- }
- break;
- case IR::OpndKindSym:
- AssertMsg(opnd->AsSymOpnd()->m_sym->IsStackSym(), "Should only see stackSym here");
- stackSym = opnd->AsSymOpnd()->m_sym->AsStackSym();
- value = stackSym->m_offset + opnd->AsSymOpnd()->m_offset;
- break;
- case IR::OpndKindIndir:
- value = opnd->AsIndirOpnd()->GetOffset();
- break;
- case IR::OpndKindMemRef:
- value = (size_t)opnd->AsMemRefOpnd()->GetMemLoc();
- break;
- default:
- AssertMsg(UNREACHED, "Unimplemented...");
- }
- this->EmitConst(value, opSize);
- return retval;
- }
- ///----------------------------------------------------------------------------
- ///
- /// EncoderMD::EmitCondBranch
- ///
- /// First pass of branch encoding: create a branch reloc that pairs the
- /// branch with its label and records the branch's byte offset.
- ///
- ///----------------------------------------------------------------------------
- void
- EncoderMD::EmitCondBranch(IR::BranchInstr * branchInstr)
- {
- IR::LabelInstr * labelInstr;
- // TODO: Make this more table-driven by mapping opcodes to condcodes.
- // (Will become more useful when we're emitting short branches as well.)
- switch (branchInstr->m_opcode)
- {
- case Js::OpCode::JA:
- *(m_pc++) = 0x87;
- break;
- case Js::OpCode::JAE:
- *(m_pc++) = 0x83;
- break;
- case Js::OpCode::JEQ:
- *(m_pc++) = 0x84;
- break;
- case Js::OpCode::JNE:
- *(m_pc++) = 0x85;
- break;
- case Js::OpCode::JNP:
- *(m_pc++) = 0x8B;
- break;
- case Js::OpCode::JB:
- *(m_pc++) = 0x82;
- break;
- case Js::OpCode::JBE:
- *(m_pc++) = 0x86;
- break;
- case Js::OpCode::JLT:
- *(m_pc++) = 0x8c;
- break;
- case Js::OpCode::JLE:
- *(m_pc++) = 0x8e;
- break;
- case Js::OpCode::JGT:
- *(m_pc++) = 0x8f;
- break;
- case Js::OpCode::JGE:
- *(m_pc++) = 0x8d;
- break;
- case Js::OpCode::JO:
- *(m_pc++) = 0x80;
- break;
- case Js::OpCode::JP:
- *(m_pc++) = 0x8A;
- break;
- case Js::OpCode::JNO:
- *(m_pc++) = 0x81;
- break;
- case Js::OpCode::JSB:
- *(m_pc++) = 0x88;
- break;
- case Js::OpCode::JNSB:
- *(m_pc++) = 0x89;
- break;
- default:
- AssertMsg(0, "Unsupported branch opcode");
- break;
- }
- labelInstr = branchInstr->GetTarget();
- AppendRelocEntry(RelocTypeBranch, (void*) m_pc, labelInstr);
- this->EmitConst(0, MachInt);
- }
- ///----------------------------------------------------------------------------
- ///
- /// EncoderMD::Encode
- ///
- /// Emit the x86 encoding for the given instruction in the passed in
- /// buffer ptr.
- ///
- ///----------------------------------------------------------------------------
- ptrdiff_t
- EncoderMD::Encode(IR::Instr *instr, BYTE *pc, BYTE* beginCodeAddress)
- {
- BYTE *opcodeByte;
- BYTE *instrStart, *instrRestart;
- m_pc = pc;
- pc = nullptr; // just to avoid using it...
- if (instr->IsLowered() == false)
- {
- if (instr->IsLabelInstr())
- {
- IR::LabelInstr *labelInstr = instr->AsLabelInstr();
- labelInstr->SetPC(m_pc);
- if(!labelInstr->IsUnreferenced())
- {
- int relocEntryPosition = AppendRelocEntry(RelocTypeLabel, (void*) instr);
- if (!PHASE_OFF(Js::LoopAlignPhase, m_func))
- {
- // we record position of last loop-top label (leaf loops) for loop alignment
- if (labelInstr->m_isLoopTop && labelInstr->GetLoop()->isLeaf)
- {
- m_relocList->Item(relocEntryPosition).m_type = RelocType::RelocTypeAlignedLabel;
- }
- }
- }
- }
- #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::INT, m_func);
- int3->SetSrc1(IR::IntConstOpnd::New(3, TyMachReg, m_func));
- return this->Encode(int3, m_pc);
- }
- #endif
- return 0;
- }
- IR::Opnd *dst = instr->GetDst();
- IR::Opnd *src1 = instr->GetSrc1();
- IR::Opnd *src2 = instr->GetSrc2();
- IR::Opnd *opr1;
- IR::Opnd *opr2;
- uint32 opdope = this->GetOpdope(instr);
- // Canonicalize operands.
- if (opdope & DDST)
- {
- opr1 = dst;
- opr2 = src1;
- }
- else
- {
- opr1 = src1;
- opr2 = src2;
- }
- int instrSize = TySize[opr1 != nullptr? opr1->GetType() : 0];
- const BYTE *form = EncoderMD::GetFormTemplate(instr);
- const BYTE *opcodeTemplate = EncoderMD::GetOpbyte(instr);
- const uint32 leadIn = EncoderMD::GetLeadIn(instr);
- instrRestart = instrStart = m_pc;
- // Emit the lock byte first if needed
- if (opdope & DLOCK)
- {
- *instrRestart++ = 0xf0;
- }
- if (instrSize == 2 && (opdope & (DNO16|DFLT)) == 0)
- {
- *instrRestart++ = 0x66;
- }
- if (opdope & D66EX)
- {
- if (opr1->IsFloat64() || opr2->IsFloat64())
- {
- *instrRestart++ = 0x66;
- }
- }
- if (opdope & (DZEROF|DF2|DF3|D66))
- {
- if (opdope & DZEROF)
- {
- }
- else if (opdope & DF2)
- {
- *instrRestart++ = 0xf2;
- }
- else if (opdope & DF3)
- {
- *instrRestart++ = 0xf3;
- }
- else if (opdope & D66)
- {
- *instrRestart++ = 0x66;
- }
- else
- {
- Assert(UNREACHED);
- }
- *instrRestart++ = 0xf;
- switch(leadIn)
- {
- case OLB_NONE:
- break;
- case OLB_0F3A:
- *instrRestart++ = 0x3a;
- break;
- default:
- Assert(UNREACHED);
- __assume(UNREACHED);
- }
- }
- // Try each form 1 by 1, until we find the one appropriate for this instruction
- // and its operands
- for(;; opcodeTemplate++, form++)
- {
- AssertMsg(m_pc - instrStart <= MachMaxInstrSize, "MachMaxInstrSize not set correctly");
- m_pc = instrRestart;
- opcodeByte = m_pc;
- // Set first opcode byte.
- *(m_pc++) = *opcodeTemplate;
- switch ((*form) & FORM_MASK)
- {
- case AX_IM:
- AnalysisAssert(opr1);
- if (!opr1->IsRegOpnd() || opr1->AsRegOpnd()->GetReg() != RegEAX
- || !opr2->IsImmediateOpnd())
- {
- continue;
- }
- size_t value;
- switch (opr2->GetKind())
- {
- case IR::OpndKindIntConst:
- value = opr2->AsIntConstOpnd()->GetValue();
- break;
- case IR::OpndKindAddr:
- value = (size_t)opr2->AsAddrOpnd()->m_address;
- break;
- default:
- Assert(UNREACHED);
- __assume(false);
- }
- if ((*form & SBIT) && FitsInByte(value))
- {
- // If the SBIT is set on this form, then it means
- // that there is a short immediate form of this instruction
- // available, and the short immediate encoding is a bit
- // smaller for DWORD sized instrs
- if (instrSize == 4)
- {
- continue;
- }
- // Stay away from the 16-bit immediate form below. It will
- // cause an LCP stall. Use the 8-bit sign extended immediate
- // form which uses the same number of instruction bytes.
- if (instrSize == 2)
- {
- continue;
- }
- }
- *opcodeByte |= this->EmitImmed(opr2, instrSize, 0);
- break;
- case AX_MEM:
- continue;
- // general case immediate. Special cases have already been checked
- case IMM:
- if (!opr2->IsImmediateOpnd() && !opr2->IsLabelOpnd())
- {
- continue;
- }
- this->EmitModRM(instr, opr1, this->GetOpcodeByte2(instr) >> 3);
- if (opr2->IsLabelOpnd())
- {
- AppendRelocEntry( RelocTypeLabelUse, (void*) m_pc, opr2->AsLabelOpnd()->GetLabel());
- this->EmitConst(0, 4);
- }
- else
- {
- *opcodeByte |= this->EmitImmed(opr2, instrSize, *form & SBIT);
- }
- break;
- case NO:
- {
- BYTE byte2 = this->GetOpcodeByte2(instr);
- if (byte2)
- {
- *(m_pc)++ = byte2;
- }
- }
- break;
- // Short immediate/reg
- case SHIMR:
- if (!opr1->IsRegOpnd())
- {
- continue;
- }
- if (!opr2->IsIntConstOpnd() && !opr2->IsAddrOpnd())
- {
- continue;
- }
- *opcodeByte |= this->GetRegEncode(opr1->AsRegOpnd());
- if (instrSize > 1)
- {
- *opcodeByte |= 0x8; /* set the W bit */
- }
- this->EmitImmed(opr2, instrSize, 0); /* S bit known to be 0 */
- break;
- case AXMODRM:
- AssertMsg(opr1->AsRegOpnd()->GetReg() == RegEAX, "Expected src1 of IMUL/IDIV to be EAX");
- opr1 = opr2;
- opr2 = nullptr;
- // FALLTHROUGH
- case MODRM:
- modrm:
- if ((instr->m_opcode == Js::OpCode::MOVSD || instr->m_opcode == Js::OpCode::MOVSS) &&
- (!opr1->IsRegOpnd() || !REGNUM_ISXMMXREG(opr1->AsRegOpnd()->GetReg())))
- {
- *opcodeByte |= 1;
- }
- if (opr2 == nullptr)
- {
- BYTE byte2 = (this->GetOpcodeByte2(instr) >> 3);
- this->EmitModRM(instr, opr1, byte2);
- break;
- }
- if (opr1->IsRegOpnd())
- {
- this->EmitModRM(instr, opr2, this->GetRegEncode(opr1->AsRegOpnd()));
- if ((*form) & DBIT)
- {
- *opcodeByte |= 0x2; // set D bit
- }
- }
- else
- {
- AssertMsg(opr2->IsRegOpnd(), "Expected opr2 to be a valid reg");
- this->EmitModRM(instr, opr1, this->GetRegEncode(opr2->AsRegOpnd()));
- }
- break;
- /* floating pt with modrm, all are "binary" */
- case FUMODRM:
- /* make the opr1 be the mem operand (if any) */
- if (opr1->IsRegOpnd())
- {
- opr1 = opr2;
- }
- if (!opr1->IsRegOpnd() && (((*form) & FINT) ? instrSize == 2 : instrSize == 8))
- {
- *opcodeByte |= 4; /* memsize bit */
- }
- this->EmitModRM(instr, opr1, this->GetOpcodeByte2(instr)>>3);
- break;
- // reg in opbyte. Only whole register allowed
- case SH_REG:
- if (!opr1->IsRegOpnd())
- {
- continue;
- }
- *opcodeByte |= this->GetRegEncode(opr1->AsRegOpnd());
- break;
- // short form immed. (must be unary)
- case SH_IM:
- if (!opr1->IsIntConstOpnd() && !opr1->IsAddrOpnd())
- {
- if (!opr1->IsLabelOpnd())
- {
- continue;
- }
- AppendRelocEntry(RelocTypeLabelUse, (void*) m_pc, opr1->AsLabelOpnd()->GetLabel());
- this->EmitConst(0, 4);
- }
- else
- {
- *opcodeByte |= this->EmitImmed(opr1, instrSize, 1);
- }
- break;
- case SHFT:
- this->EmitModRM(instr, opr1, this->GetOpcodeByte2(instr) >> 3);
- if (opr2->IsRegOpnd())
- {
- AssertMsg(opr2->AsRegOpnd()->GetReg() == RegECX, "Expected ECX as opr2 of variable shift");
- *opcodeByte |= *(opcodeTemplate + 1);
- }
- else
- {
- AssertMsg(opr2->IsIntConstOpnd(), "Expected register or constant as shift amount opnd");
- uint32 constValue = opr2->AsIntConstOpnd()->GetValue();
- if (constValue == 1)
- {
- *opcodeByte |= 0x10;
- }
- else
- {
- this->EmitConst(constValue, 1);
- }
- }
- break;
- case LABREL1:
- // TODO
- continue;
- // jmp, call with full relative disp
- case LABREL2:
- if (opr1 == nullptr)
- {
- // Unconditional branch
- AssertMsg(instr->IsBranchInstr(), "Invalid LABREL2 form");
- AppendRelocEntry(RelocTypeBranch, (void*)m_pc, instr->AsBranchInstr()->GetTarget());
- this->EmitConst(0, 4);
- }
- else if (opr1->IsIntConstOpnd())
- {
- AppendRelocEntry(RelocTypeCallPcrel, (void*)m_pc, nullptr, (void*)opr1->AsIntConstOpnd()->GetValue());
- this->EmitConst(0, 4);
- AssertMsg(m_func->IsOOPJIT() || ( ((BYTE*)opr1->AsIntConstOpnd()->GetValue()) < m_encoder->m_encodeBuffer || ((BYTE *)opr1->AsIntConstOpnd()->GetValue()) >= m_encoder->m_encodeBuffer + m_encoder->m_encodeBufferSize), "Call Target within buffer.");
- }
- else if (opr1->IsHelperCallOpnd())
- {
- const void* fnAddress = (void *)IR::GetMethodAddress(m_func->GetThreadContextInfo(), opr1->AsHelperCallOpnd());
- AppendRelocEntry(RelocTypeCallPcrel, (void*)m_pc, nullptr, fnAddress);
- AssertMsg(sizeof(uint32) == sizeof(void*), "Sizes of void* assumed to be 32-bits");
- this->EmitConst(0, 4);
- AssertMsg(m_func->IsOOPJIT() || (((BYTE*)fnAddress) < m_encoder->m_encodeBuffer || ((BYTE *)fnAddress) >= m_encoder->m_encodeBuffer + m_encoder->m_encodeBufferSize), "Call Target within buffer.");
- }
- else
- {
- continue;
- }
- break;
- // Special form which doesn't fit any existing patterns.
- case SPECIAL:
- switch (instr->m_opcode)
- {
- case Js::OpCode::RET: {
- AssertMsg(opr1->IsIntConstOpnd(), "RET should have intConst as src");
- uint32 constValue = opr1->AsIntConstOpnd()->GetValue();
- if (constValue == 0)
- {
- *opcodeByte |= 0x1; // no imm16 follows
- }
- else {
- this->EmitConst(constValue, 2);
- }
- break;
- }
- case Js::OpCode::JA:
- case Js::OpCode::JAE:
- case Js::OpCode::JEQ:
- case Js::OpCode::JB:
- case Js::OpCode::JBE:
- case Js::OpCode::JNE:
- case Js::OpCode::JLT:
- case Js::OpCode::JLE:
- case Js::OpCode::JGT:
- case Js::OpCode::JGE:
- case Js::OpCode::JO:
- case Js::OpCode::JNO:
- case Js::OpCode::JP:
- case Js::OpCode::JNP:
- case Js::OpCode::JSB:
- case Js::OpCode::JNSB:
- {
- *opcodeByte = 0xf;
- this->EmitCondBranch(instr->AsBranchInstr());
- break;
- }
- case Js::OpCode::IMUL2:
- AssertMsg(opr1->IsRegOpnd() && instrSize != 1, "Illegal IMUL2");
- if (!opr2->IsImmediateOpnd())
- {
- continue;
- }
- // turn an 'imul2 reg, immed' into an 'imul3 reg, reg, immed'
- *instrStart = *opcodeTemplate; // hammer prefix
- opcodeByte = instrStart; // reset pointers
- m_pc = instrStart + 1;
- this->EmitModRM(instr, opr1, this->GetRegEncode(opr1->AsRegOpnd()));
- *opcodeByte |= this->EmitImmed(opr2, instrSize, 1);
- break;
- case Js::OpCode::INT:
- if (opr1->AsIntConstOpnd()->GetValue() != 3)
- {
- *opcodeByte |= 1;
- *(m_pc)++ = (char)opr1->AsIntConstOpnd()->GetValue();
- }
- break;
- case Js::OpCode::FSTP:
- if (opr1->IsRegOpnd())
- {
- *opcodeByte |= 4;
- this->EmitModRM(instr, opr1, this->GetOpcodeByte2(instr)>>3);
- break;
- }
- if (instrSize != 10)
- {
- continue;
- }
- *opcodeByte |= 2;
- this->EmitModRM(instr, opr1, (this->GetOpcodeByte2(instr) >> 3)|5);
- break;
- case Js::OpCode::MOVD:
- // is second operand a MMX register? if so use "store" form
- if (opr2->IsRegOpnd() && REGNUM_ISXMMXREG(opr2->AsRegOpnd()->GetReg()))
- {
- if (opr1->IsRegOpnd())
- {
- // have 2 choices - we do it this way to match Intel's
- // tools; Have to swap operands to get right behavior from
- // modrm code.
- IR::Opnd *oprTmp = opr1;
- opr1 = opr2;
- opr2 = oprTmp;
- }
- *opcodeByte |= 0x10;
- }
- Assert(opr1->IsRegOpnd() && REGNUM_ISXMMXREG(opr1->AsRegOpnd()->GetReg()));
- goto modrm;
- case Js::OpCode::MOVLHPS:
- case Js::OpCode::MOVHLPS:
- Assert(opr1->IsRegOpnd() && REGNUM_ISXMMXREG(opr1->AsRegOpnd()->GetReg()));
- Assert(opr2->IsRegOpnd() && REGNUM_ISXMMXREG(opr2->AsRegOpnd()->GetReg()));
- goto modrm;
- case Js::OpCode::MOVMSKPD:
- case Js::OpCode::MOVMSKPS:
- case Js::OpCode::PMOVMSKB:
- /* Instruction form is "MOVMSKP[S/D] r32, xmm" */
- Assert(opr1->IsRegOpnd() && opr2->IsRegOpnd() && REGNUM_ISXMMXREG(opr2->AsRegOpnd()->GetReg()));
- goto modrm;
- case Js::OpCode::MOVSS:
- case Js::OpCode::MOVAPS:
- case Js::OpCode::MOVUPS:
- case Js::OpCode::MOVHPD:
- case Js::OpCode::MOVLPD:
- if (!opr1->IsRegOpnd())
- {
- Assert(opr2->IsRegOpnd());
- *opcodeByte |= 0x01;
- }
- goto modrm;
- case Js::OpCode::FISTTP:
- if (opr1->GetSize() != 8)
- continue; /* handle 8bytes here, others the usual way */
- this->EmitModRM(instr, opr1, this->GetOpcodeByte2(instr) >> 3);
- break;
- case Js::OpCode::FLD:
- if (instrSize != 10)
- {
- continue;
- }
- *opcodeByte |= 0x2;
- this->EmitModRM(instr, opr1, (this->GetOpcodeByte2(instr) >> 3)|5);
- break;
- case Js::OpCode::NOP:
- if (AutoSystemInfo::Data.SSE2Available() && instr->GetSrc1())
- {
- // Multibyte NOP. Encode fast NOPs on SSE2 supported x86 system
- Assert(instr->GetSrc1()->IsIntConstOpnd() && instr->GetSrc1()->GetType() == TyInt8);
- unsigned nopSize = instr->GetSrc1()->AsIntConstOpnd()->GetValue();
- Assert(nopSize >= 2 && nopSize <= 4);
- nopSize = max(2u, min(4u, nopSize)); // satisfy oacr
- const BYTE *nopEncoding = Nop[nopSize - 1];
- *opcodeByte = nopEncoding[0];
- for (unsigned i = 1; i < nopSize; i++)
- {
- *(m_pc)++ = nopEncoding[i];
- }
- }
- else
- {
- BYTE byte2 = this->GetOpcodeByte2(instr);
- if (byte2)
- {
- *(m_pc)++ = byte2;
- }
- }
- break;
- case Js::OpCode::XCHG:
- if (instrSize == 1)
- continue;
- if (opr1->IsRegOpnd() && opr1->AsRegOpnd()->GetReg() == RegEAX
- && opr2->IsRegOpnd())
- {
- *opcodeByte |= this->GetRegEncode(opr2->AsRegOpnd());
- }
- else if (opr2->IsRegOpnd() && opr2->AsRegOpnd()->GetReg() == RegEAX
- && opr1->IsRegOpnd())
- {
- *opcodeByte |= this->GetRegEncode(opr1->AsRegOpnd());
- }
- else
- {
- continue;
- }
- break;
- case Js::OpCode::PEXTRD:
- this->EmitModRM(instr, opr1, this->GetRegEncode(opr2->AsRegOpnd()));
- break;
- case Js::OpCode::BT:
- case Js::OpCode::BTR:
- /*
- * 0F A3 /r BT r/m16, r16
- * 0F A3 /r BT r/m32, r32
- * 0F BA /4 ib BT r/m16, imm8
- * 0F BA /4 ib BT r/m32, imm8
- * or
- * 0F B3 /r BTR r/m16, r32
- * 0F B3 /r BTR r/m32, r64
- * 0F BA /6 ib BTR r/m16, imm8
- * 0F BA /6 ib BTR r/m32, imm8
- */
- Assert(instr->m_opcode != Js::OpCode::BT || dst == nullptr);
- AssertMsg(instr->m_opcode == Js::OpCode::BT ||
- dst && (dst->IsRegOpnd() || dst->IsMemRefOpnd() || dst->IsIndirOpnd()), "Invalid dst type on BTR/BTS instruction.");
- if (src2->IsImmediateOpnd())
- {
- this->EmitModRM(instr, src1, this->GetOpcodeByte2(instr) >> 3);
- Assert(src2->IsIntConstOpnd() && src2->GetType() == TyInt8);
- *opcodeByte |= EmitImmed(src2, 1, 0);
- }
- else
- {
- /* this is special dbit modrm in which opr1 can be a reg*/
- Assert(src2->IsRegOpnd());
- form++;
- opcodeTemplate++;
- Assert(((*form) & FORM_MASK) == MODRM);
- *opcodeByte = *opcodeTemplate;
- this->EmitModRM(instr, src1, this->GetRegEncode(src2->AsRegOpnd()));
- }
- break;
- case Js::OpCode::PSLLW:
- case Js::OpCode::PSLLD:
- case Js::OpCode::PSRLW:
- case Js::OpCode::PSRLD:
- case Js::OpCode::PSRAW:
- case Js::OpCode::PSRAD:
- case Js::OpCode::PSLLDQ:
- case Js::OpCode::PSRLDQ:
- Assert(opr1->IsRegOpnd());
- if (src2 &&src2->IsIntConstOpnd())
- {
- // SSE shift with IMM
- this->EmitModRM(instr, opr1, this->GetOpcodeByte2(instr) >> 3);
- break;
- }
- else
- {
- // Variable shift amount
- // fix opcode byte
- switch (instr->m_opcode)
- {
- case Js::OpCode::PSLLW:
- *opcodeByte = 0xF1;
- break;
- case Js::OpCode::PSLLD:
- *opcodeByte = 0xF2;
- break;
- case Js::OpCode::PSRLW:
- *opcodeByte = 0xD1;
- break;
- case Js::OpCode::PSRLD:
- *opcodeByte = 0xD2;
- break;
- case Js::OpCode::PSRAW:
- *opcodeByte = 0xE1;
- break;
- case Js::OpCode::PSRAD:
- *opcodeByte = 0xE2;
- break;
- default:
- Assert(UNREACHED);
- }
- goto modrm;
- }
- default:
- AssertMsg(UNREACHED, "Unhandled opcode in SPECIAL form");
- }
- break;
- case INVALID:
- return m_pc - instrStart;
- default:
- AssertMsg(UNREACHED, "Unhandled encoder form");
- }
- // if instr has W bit, set it appropriately
- if ((*form & WBIT) && !(opdope & DFLT) && instrSize != 1)
- {
- *opcodeByte |= 0x1; // set WBIT
- }
- AssertMsg(m_pc - instrStart <= MachMaxInstrSize, "MachMaxInstrSize not set correctly");
- if (opdope & DSSE)
- {
- // extra imm8 byte for SSE instructions.
- uint valueImm = 0;
- bool writeImm = true;
- if (src2 &&src2->IsIntConstOpnd())
- {
- valueImm = (uint)src2->AsIntConstOpnd()->GetImmediateValue(instr->m_func);
- }
- else
- {
- // Variable src2, we are either encoding a CMP op, or don't need an Imm.
- // src2(comparison byte) is missing in CMP instructions and is part of the opcode instead.
- switch (instr->m_opcode)
- {
- case Js::OpCode::CMPLTPS:
- case Js::OpCode::CMPLTPD:
- valueImm = CMP_IMM8::LT;
- break;
- case Js::OpCode::CMPLEPS:
- case Js::OpCode::CMPLEPD:
- valueImm = CMP_IMM8::LE;
- break;
- case Js::OpCode::CMPEQPS:
- case Js::OpCode::CMPEQPD:
- valueImm = CMP_IMM8::EQ;
- break;
- case Js::OpCode::CMPNEQPS:
- case Js::OpCode::CMPNEQPD:
- valueImm = CMP_IMM8::NEQ;
- break;
- case Js::OpCode::CMPUNORDPS:
- valueImm = CMP_IMM8::UNORD;
- break;
- default:
- // none comparison op, should have non-constant src2 already encoded as MODRM reg.
- Assert(src2 && !src2->IsIntConstOpnd());
- writeImm = false;
- }
- }
-
- if (writeImm)
- {
- *(m_pc++) = (valueImm & 0xff);
- }
- }
- return m_pc - instrStart;
- }
- }
- int
- EncoderMD::AppendRelocEntry(RelocType type, void *ptr, IR::LabelInstr* labelInstr, const void * fnAddress)
- {
- if (m_relocList == nullptr)
- m_relocList = Anew(m_encoder->m_tempAlloc, RelocList, m_encoder->m_tempAlloc);
- EncodeRelocAndLabels reloc;
- reloc.init(type, ptr, labelInstr, fnAddress);
- return m_relocList->Add(reloc);
- }
- int
- EncoderMD::FixRelocListEntry(uint32 index, int32 totalBytesSaved, BYTE *buffStart, BYTE* buffEnd)
- {
- BYTE* currentPc;
- EncodeRelocAndLabels &relocRecord = m_relocList->Item(index);
- int result = totalBytesSaved;
- // LabelInstr ?
- if (relocRecord.isLabel())
- {
- BYTE* newPC;
- currentPc = relocRecord.getLabelCurrPC();
- AssertMsg(currentPc >= buffStart && currentPc < buffEnd, "LabelInstr offset has to be within buffer.");
- newPC = currentPc - totalBytesSaved;
- // find the number of nops needed to align this loop top
- if (relocRecord.isAlignedLabel() && !PHASE_OFF(Js::LoopAlignPhase, m_func))
- {
- uint32 offset = (uint32)newPC - (uint32)buffStart;
- // Since the final code buffer is page aligned, it is enough to align the offset of the label.
- BYTE nopCount = m_encoder->FindNopCountFor16byteAlignment(offset);
- if (nopCount <= Js::Configuration::Global.flags.LoopAlignNopLimit)
- {
- // new label pc
- newPC += nopCount;
- relocRecord.setLabelNopCount(nopCount);
- // adjust bytes saved
- result -= nopCount;
- }
- }
- relocRecord.setLabelCurrPC(newPC);
- }
- else
- {
- currentPc = (BYTE*) relocRecord.m_origPtr;
- // ignore outside buffer offsets (e.g. JumpTable entries)
- if (currentPc >= buffStart && currentPc < buffEnd)
- {
- if (relocRecord.m_type == RelocTypeInlineeEntryOffset)
- {
- // ptr points to imm32 offset of the instruction that needs to be adjusted
- // offset is in top 28-bits, arg count in bottom 4
- uint32 field = *((uint32*) relocRecord.m_origPtr);
- uint32 offset = field >> 4;
- uint32 count = field & 0xf;
- AssertMsg(offset < (uint32)(buffEnd - buffStart), "Inlinee entry offset out of range");
- relocRecord.SetInlineOffset(((offset - totalBytesSaved) << 4) | count);
- }
- // adjust the ptr to the buffer itself
- relocRecord.m_ptr = (BYTE*) relocRecord.m_ptr - totalBytesSaved;
- }
- }
- return result;
- }
- ///----------------------------------------------------------------------------
- ///
- /// EncoderMD::FixMaps
- /// Fixes the inlinee frame records and map based on BR shortening
- ///
- ///----------------------------------------------------------------------------
- void
- EncoderMD::FixMaps(uint32 brOffset, int32 bytesSaved, uint32 *inlineeFrameRecordsIndex, uint32 *inlineeFrameMapIndex, uint32 *pragmaInstToRecordOffsetIndex, uint32 *offsetBuffIndex)
- {
- InlineeFrameRecords *recList = m_encoder->m_inlineeFrameRecords;
- ArenaInlineeFrameMap *mapList = m_encoder->m_inlineeFrameMap;
- PragmaInstrList *pInstrList = m_encoder->m_pragmaInstrToRecordOffset;
- int32 i;
- for (i = *inlineeFrameRecordsIndex; i < recList->Count() && recList->Item(i)->inlineeStartOffset <= brOffset; i++)
- recList->Item(i)->inlineeStartOffset -= bytesSaved;
- *inlineeFrameRecordsIndex = i;
- for (i = *inlineeFrameMapIndex; i < mapList->Count() && mapList->Item(i).offset <= brOffset; i++)
- mapList->Item(i).offset -= bytesSaved;
- *inlineeFrameMapIndex = i;
- for (i = *pragmaInstToRecordOffsetIndex; i < pInstrList->Count() && pInstrList->Item(i)->m_offsetInBuffer <= brOffset; i++)
- pInstrList->Item(i)->m_offsetInBuffer -= bytesSaved;
- *pragmaInstToRecordOffsetIndex = i;
- #if DBG_DUMP
- for (i = *offsetBuffIndex; (uint)i < m_encoder->m_instrNumber && m_encoder->m_offsetBuffer[i] <= brOffset; i++)
- m_encoder->m_offsetBuffer[i] -= bytesSaved;
- *offsetBuffIndex = i;
- #endif
- }
- ///----------------------------------------------------------------------------
- ///
- /// 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 (int32 i = 0; i < m_relocList->Count(); i++)
- {
- EncodeRelocAndLabels *reloc = &m_relocList->Item(i);
- BYTE * relocAddress = (BYTE*)reloc->m_ptr;
- uint32 pcrel;
- switch (reloc->m_type)
- {
- case RelocTypeCallPcrel:
- {
- pcrel = (uint32)(codeBufferAddress + (BYTE*)reloc->m_ptr - m_encoder->m_encodeBuffer + 4);
- uint32 offset = (uint32)reloc->GetFnAddress() - pcrel;
- if (!isFinalBufferValidation)
- {
- Assert(*(uint32 *)relocAddress == 0);
- *(uint32 *)relocAddress = offset;
- }
- *bufferCRC = CalculateCRC(*bufferCRC, offset);
- break;
- }
- case RelocTypeBranch:
- {
- IR::LabelInstr * labelInstr = reloc->getBrTargetLabel();
- AssertMsg(labelInstr->GetPC() != nullptr, "Branch to unemitted label?");
- if (reloc->isShortBr())
- {
- // short branch
- pcrel = (uint32)(labelInstr->GetPC() - ((BYTE*)reloc->m_ptr + 1));
- AssertMsg((int32)pcrel >= -128 && (int32)pcrel <= 127, "Offset doesn't fit in imm8.");
- if (!isFinalBufferValidation)
- {
- Assert(*(BYTE*)relocAddress == 0);
- *(BYTE*)relocAddress = (BYTE)pcrel;
- }
- else
- {
- Encoder::EnsureRelocEntryIntegrity(codeBufferAddress, codeSize, (size_t)m_encoder->m_encodeBuffer, (size_t)relocAddress, sizeof(BYTE), (ptrdiff_t)labelInstr->GetPC() - ((ptrdiff_t)reloc->m_ptr + 1));
- }
- }
- else
- {
- pcrel = (uint32)(labelInstr->GetPC() - ((BYTE*)reloc->m_ptr + 4));
- if (!isFinalBufferValidation)
- {
- Assert(*(uint32 *)relocAddress == 0);
- *(uint32 *)relocAddress = pcrel;
- }
- else
- {
- Encoder::EnsureRelocEntryIntegrity(codeBufferAddress, codeSize, (size_t)m_encoder->m_encodeBuffer, (size_t)relocAddress, sizeof(uint32), (ptrdiff_t)labelInstr->GetPC() - ((ptrdiff_t)reloc->m_ptr + 4));
- }
- }
- *bufferCRC = CalculateCRC(*bufferCRC, pcrel);
- break;
- }
- case RelocTypeLabelUse:
- {
- IR::LabelInstr * labelInstr = reloc->GetLabelInstrForRelocTypeLabelUse();
- AssertMsg(labelInstr->GetPC() != nullptr, "Branch to unemitted label?");
- uint32 offset = uint32(labelInstr->GetPC() - m_encoder->m_encodeBuffer);
- size_t targetAddress = (uint32)(offset + codeBufferAddress);
- if (!isFinalBufferValidation)
- {
- Assert(*(uint32 *)relocAddress == 0);
- *(uint32 *)relocAddress = targetAddress;
- }
- else
- {
- Encoder::EnsureRelocEntryIntegrity(codeBufferAddress, codeSize, (size_t)m_encoder->m_encodeBuffer, (size_t)relocAddress, sizeof(size_t), targetAddress, false);
- }
- *bufferCRC = CalculateCRC(*bufferCRC, offset);
- break;
- }
- case RelocTypeLabel:
- case RelocTypeAlignedLabel:
- case RelocTypeInlineeEntryOffset:
- break;
- default:
- AssertMsg(UNREACHED, "Unknown reloc type");
- }
- }
- }
- uint
- EncoderMD::GetRelocDataSize(EncodeRelocAndLabels *reloc)
- {
- switch (reloc->m_type)
- {
- case RelocTypeCallPcrel:
- case RelocTypeLabelUse:
- {
- return sizeof(uint32);
- }
- case RelocTypeBranch:
- {
- if (reloc->isShortBr())
- {
- return sizeof(BYTE);
- }
- else
- {
- return sizeof(uint32);
- }
- }
- default:
- {
- return 0;
- }
- }
- }
- BYTE *
- EncoderMD::GetRelocBufferAddress(EncodeRelocAndLabels * reloc)
- {
- return (BYTE*)reloc->m_ptr;
- }
- ///----------------------------------------------------------------------------
- ///
- /// EncodeRelocAndLabels::VerifyRelocList
- /// Verify that the list of offsets within the encoder buffer range are in ascending order.
- /// This includes offsets of immediate fields in the code and offsets of LabelInstrs
- ///----------------------------------------------------------------------------
- #ifdef DBG
- void
- EncoderMD::VerifyRelocList(BYTE *buffStart, BYTE *buffEnd)
- {
- BYTE *last_pc = 0, *pc;
- for (int32 i = 0; i < m_relocList->Count(); i ++)
- {
- EncodeRelocAndLabels &p = m_relocList->Item(i);
- // LabelInstr ?
- if (p.isLabel())
- {
- AssertMsg(p.m_ptr < buffStart || p.m_ptr >= buffEnd, "Invalid label instruction pointer.");
- pc = ((IR::LabelInstr*)p.m_ptr)->GetPC();
- AssertMsg(pc >= buffStart && pc < buffEnd, "LabelInstr offset has to be within buffer.");
- }
- else
- pc = (BYTE*)p.m_ptr;
- // The list is partially sorted, out of bound ptrs (JumpTable entries) don't follow.
- if (pc >= buffStart && pc < buffEnd)
- {
- if (last_pc)
- AssertMsg(pc >= last_pc, "Unordered reloc list.");
- last_pc = pc;
- }
- }
- }
- #endif
- void
- EncoderMD::EncodeInlineeCallInfo(IR::Instr *instr, uint32 codeOffset)
- {
- Assert(instr->GetDst() &&
- instr->GetDst()->IsSymOpnd() &&
- instr->GetDst()->AsSymOpnd()->m_sym->IsStackSym() &&
- instr->GetDst()->AsSymOpnd()->m_sym->AsStackSym()->m_isInlinedArgSlot);
- Assert(instr->GetSrc1() &&
- instr->GetSrc1()->IsIntConstOpnd() &&
- (instr->GetSrc1()->AsIntConstOpnd()->GetValue() == (instr->GetSrc1()->AsIntConstOpnd()->GetValue() & 0xF)));
- intptr_t inlineeCallInfo = 0;
- // 28 (x86) bits on the InlineeCallInfo to store the
- // offset of the start of the inlinee. We shouldn't have gotten here with more arguments
- // than can fit in as many bits.
- const bool encodeResult = Js::InlineeCallInfo::Encode(inlineeCallInfo, (uint32)instr->GetSrc1()->AsIntConstOpnd()->GetValue(), codeOffset);
- Assert(encodeResult);
- instr->GetSrc1()->AsIntConstOpnd()->SetValue(inlineeCallInfo);
- }
- bool EncoderMD::TryConstFold(IR::Instr *instr, IR::RegOpnd *regOpnd)
- {
- Assert(regOpnd->m_sym->IsConst());
- switch(GetInstrForm(instr))
- {
- case FORM_MOV:
- if (!instr->GetSrc1()->IsRegOpnd())
- {
- return false;
- }
- break;
- case FORM_PSHPOP:
- if (instr->m_opcode != Js::OpCode::PUSH)
- {
- return false;
- }
- if (!instr->GetSrc1()->IsRegOpnd())
- {
- return false;
- }
- break;
- case FORM_BINOP:
- case FORM_SHIFT:
- if (regOpnd != instr->GetSrc2())
- {
- return false;
- }
- break;
- default:
- return false;
- }
- if(regOpnd != instr->GetSrc1() && regOpnd != instr->GetSrc2())
- {
- if(!regOpnd->m_sym->IsConst() || regOpnd->m_sym->IsFloatConst())
- {
- return false;
- }
- // Check if it's the index opnd inside an indir
- bool foundUse = false;
- bool foldedAllUses = true;
- IR::Opnd *const srcs[] = { instr->GetSrc1(), instr->GetSrc2(), instr->GetDst() };
- for(int i = 0; i < sizeof(srcs) / sizeof(srcs[0]); ++i)
- {
- const auto src = srcs[i];
- if(!src || !src->IsIndirOpnd())
- {
- continue;
- }
- const auto indir = src->AsIndirOpnd();
- if(regOpnd == indir->GetBaseOpnd())
- {
- // Can't const-fold into the base opnd
- foundUse = true;
- foldedAllUses = false;
- continue;
- }
- if(regOpnd != indir->GetIndexOpnd())
- {
- continue;
- }
- foundUse = true;
- if(!regOpnd->m_sym->IsIntConst())
- {
- foldedAllUses = false;
- continue;
- }
- // offset = indir.offset + (index << scale)
- IntConstType offset = regOpnd->m_sym->GetIntConstValue();
- if(indir->GetScale() != 0 && Int32Math::Shl(offset, indir->GetScale(), &offset) ||
- indir->GetOffset() != 0 && Int32Math::Add(indir->GetOffset(), offset, &offset))
- {
- foldedAllUses = false;
- continue;
- }
- indir->SetOffset(offset);
- indir->SetIndexOpnd(nullptr);
- }
- return foundUse && foldedAllUses;
- }
- instr->ReplaceSrc(regOpnd, regOpnd->m_sym->GetConstOpnd());
- return true;
- }
- bool EncoderMD::TryFold(IR::Instr *instr, IR::RegOpnd *regOpnd)
- {
- IR::Opnd *src1 = instr->GetSrc1();
- IR::Opnd *src2 = instr->GetSrc2();
-
- if (IRType_IsSimd128(regOpnd->GetType()))
- {
- // No folding for SIMD values. Alignment is not guaranteed.
- return false;
- }
- switch(GetInstrForm(instr))
- {
- case FORM_MOV:
- if (!instr->GetDst()->IsRegOpnd() || regOpnd != src1)
- {
- return false;
- }
- break;
- case FORM_BINOP:
- if (regOpnd == src1 && instr->m_opcode == Js::OpCode::CMP && (src2->IsRegOpnd() || src1->IsImmediateOpnd()))
- {
- IR::Instr *instrNext = instr->GetNextRealInstrOrLabel();
- if (instrNext->IsBranchInstr() && instrNext->AsBranchInstr()->IsConditional())
- {
- // Swap src and reverse branch
- src2 = instr->UnlinkSrc1();
- src1 = instr->UnlinkSrc2();
- instr->SetSrc1(src1);
- instr->SetSrc2(src2);
- LowererMD::ReverseBranch(instrNext->AsBranchInstr());
- }
- else
- {
- return false;
- }
- }
- if (regOpnd != src2 || !src1->IsRegOpnd())
- {
- return false;
- }
- break;
- case FORM_MODRM:
- if (src2 == nullptr)
- {
- if (!instr->GetDst()->IsRegOpnd() || regOpnd != src1 || EncoderMD::IsOPEQ(instr))
- {
- return false;
- }
- }
- else
- {
- if (regOpnd != src2 || !src1->IsRegOpnd())
- {
- return false;
- }
- }
- break;
- case FORM_PSHPOP:
- if (instr->m_opcode != Js::OpCode::PUSH)
- {
- return false;
- }
- if (!instr->GetSrc1()->IsRegOpnd())
- {
- return false;
- }
- break;
- case FORM_TEST:
- if (regOpnd == src1)
- {
- if (!src2->IsRegOpnd() && !src2->IsIntConstOpnd())
- {
- return false;
- }
- }
- else if (src1->IsRegOpnd())
- {
- instr->SwapOpnds();
- }
- else
- {
- return false;
- }
- break;
- default:
- return false;
- }
- IR::SymOpnd *symOpnd = IR::SymOpnd::New(regOpnd->m_sym, regOpnd->GetType(), instr->m_func);
- instr->ReplaceSrc(regOpnd, symOpnd);
- return true;
- }
- bool EncoderMD::SetsConditionCode(IR::Instr *instr)
- {
- return instr->IsLowered() && (EncoderMD::GetOpdope(instr) & DSETCC);
- }
- bool EncoderMD::UsesConditionCode(IR::Instr *instr)
- {
- return instr->IsLowered() && (EncoderMD::GetOpdope(instr) & DUSECC);
- }
- void EncoderMD::UpdateRelocListWithNewBuffer(RelocList * relocList, BYTE * newBuffer, BYTE * oldBufferStart, BYTE * oldBufferEnd)
- {
- for (int32 i = 0; i < relocList->Count(); i++)
- {
- EncodeRelocAndLabels &reloc = relocList->Item(i);
- if (reloc.isLabel())
- {
- IR::LabelInstr* label = reloc.getLabel();
- AssertMsg((BYTE*)label < oldBufferStart || (BYTE*)label >= oldBufferEnd, "Invalid label pointer.");
- BYTE* labelPC = label->GetPC();
- Assert((BYTE*) reloc.m_origPtr >= oldBufferStart && (BYTE*) reloc.m_origPtr < oldBufferEnd);
- label->SetPC(labelPC - oldBufferStart + newBuffer);
- // nothing more to be done for a label
- continue;
- }
- else if (reloc.m_type >= RelocTypeBranch && reloc.m_type <= RelocTypeLabelUse &&
- (BYTE*) reloc.m_origPtr >= oldBufferStart && (BYTE*) reloc.m_origPtr < oldBufferEnd)
- {
- // we need to relocate all new offset that were originally within buffer
- reloc.m_ptr = (BYTE*) reloc.m_ptr - oldBufferStart + newBuffer;
- }
- }
- }
- bool EncoderMD::IsOPEQ(IR::Instr *instr)
- {
- return instr->IsLowered() && (EncoderMD::GetOpdope(instr) & DOPEQ);
- }
- bool EncoderMD::IsSHIFT(IR::Instr *instr)
- {
- return (instr->IsLowered() && EncoderMD::GetInstrForm(instr) == FORM_SHIFT) ||
- instr->m_opcode == Js::OpCode::PSLLDQ || instr->m_opcode == Js::OpCode::PSRLDQ ||
- instr->m_opcode == Js::OpCode::PSLLW || instr->m_opcode == Js::OpCode::PSRLW ||
- instr->m_opcode == Js::OpCode::PSLLD;
- }
- void EncoderMD::AddLabelReloc(BYTE* relocAddress)
- {
- AppendRelocEntry(RelocTypeLabel, relocAddress);
- }
|