LegalizeMD.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. #include "Backend.h"
  6. #undef MACRO
  7. #define MACRO(name, jnLayout, attrib, byte2, legalforms, opbyte, ...) legalforms,
  8. static const LegalInstrForms _InstrForms[] =
  9. {
  10. #include "MdOpCodes.h"
  11. };
  12. static LegalForms LegalDstForms(IR::Instr * instr)
  13. {
  14. Assert(instr->IsLowered());
  15. return _InstrForms[instr->m_opcode - (Js::OpCode::MDStart+1)].dst;
  16. }
  17. static LegalForms LegalSrcForms(IR::Instr * instr, uint opndNum)
  18. {
  19. Assert(instr->IsLowered());
  20. return _InstrForms[instr->m_opcode - (Js::OpCode::MDStart+1)].src[opndNum-1];
  21. }
  22. void LegalizeMD::LegalizeInstr(IR::Instr * instr, bool fPostRegAlloc)
  23. {
  24. if (!instr->IsLowered())
  25. {
  26. AssertMsg(UNREACHED, "Unlowered instruction in m.d. legalizer");
  27. return;
  28. }
  29. LegalizeDst(instr, fPostRegAlloc);
  30. LegalizeSrc(instr, instr->GetSrc1(), 1, fPostRegAlloc);
  31. LegalizeSrc(instr, instr->GetSrc2(), 2, fPostRegAlloc);
  32. }
  33. void LegalizeMD::LegalizeDst(IR::Instr * instr, bool fPostRegAlloc)
  34. {
  35. LegalForms forms = LegalDstForms(instr);
  36. IR::Opnd * opnd = instr->GetDst();
  37. if (opnd == NULL)
  38. {
  39. #ifdef DBG
  40. // No legalization possible, just report error.
  41. if (forms != 0)
  42. {
  43. IllegalInstr(instr, _u("Expected dst opnd"));
  44. }
  45. #endif
  46. return;
  47. }
  48. switch (opnd->GetKind())
  49. {
  50. case IR::OpndKindReg:
  51. #ifdef DBG
  52. // No legalization possible, just report error.
  53. if (!(forms & L_RegMask))
  54. {
  55. IllegalInstr(instr, _u("Unexpected reg dst"));
  56. }
  57. #endif
  58. break;
  59. case IR::OpndKindMemRef:
  60. {
  61. // MemRefOpnd is a deference of the memory location.
  62. // So extract the location, load it to register, replace the MemRefOpnd with an IndirOpnd taking the
  63. // register as base, and fall through to legalize the IndirOpnd.
  64. intptr_t memLoc = opnd->AsMemRefOpnd()->GetMemLoc();
  65. IR::RegOpnd *newReg = IR::RegOpnd::New(TyMachPtr, instr->m_func);
  66. if (fPostRegAlloc)
  67. {
  68. newReg->SetReg(SCRATCH_REG);
  69. }
  70. IR::Instr *newInstr = IR::Instr::New(Js::OpCode::LDIMM, newReg,
  71. IR::AddrOpnd::New(memLoc, opnd->AsMemRefOpnd()->GetAddrKind(), instr->m_func, true), instr->m_func);
  72. instr->InsertBefore(newInstr);
  73. LegalizeMD::LegalizeInstr(newInstr, fPostRegAlloc);
  74. IR::IndirOpnd *indirOpnd = IR::IndirOpnd::New(newReg, 0, opnd->GetType(), instr->m_func);
  75. opnd = instr->ReplaceDst(indirOpnd);
  76. }
  77. // FALL THROUGH
  78. case IR::OpndKindIndir:
  79. if (!(forms & L_IndirMask))
  80. {
  81. instr = LegalizeStore(instr, forms, fPostRegAlloc);
  82. forms = LegalDstForms(instr);
  83. }
  84. LegalizeIndirOffset(instr, opnd->AsIndirOpnd(), forms, fPostRegAlloc);
  85. break;
  86. case IR::OpndKindSym:
  87. if (!(forms & L_SymMask))
  88. {
  89. instr = LegalizeStore(instr, forms, fPostRegAlloc);
  90. forms = LegalDstForms(instr);
  91. }
  92. if (fPostRegAlloc)
  93. {
  94. // In order to legalize SymOffset we need to know final argument area, which is only available after lowerer.
  95. // So, don't legalize sym offset here, but it will be done as part of register allocator.
  96. LegalizeSymOffset(instr, opnd->AsSymOpnd(), forms, fPostRegAlloc);
  97. }
  98. break;
  99. default:
  100. AssertMsg(UNREACHED, "Unexpected dst opnd kind");
  101. break;
  102. }
  103. }
  104. IR::Instr * LegalizeMD::LegalizeStore(IR::Instr *instr, LegalForms forms, bool fPostRegAlloc)
  105. {
  106. if (LowererMD::IsAssign(instr) && instr->GetSrc1()->IsRegOpnd())
  107. {
  108. // We can just change this to a store in place.
  109. instr->m_opcode = LowererMD::GetStoreOp(instr->GetSrc1()->GetType());
  110. }
  111. else
  112. {
  113. // Sink the mem opnd. The caller will verify the offset.
  114. // We don't expect to hit this point after register allocation, because we
  115. // can't guarantee that the instruction will be legal.
  116. Assert(!fPostRegAlloc);
  117. instr = instr->SinkDst(LowererMD::GetStoreOp(instr->GetDst()->GetType()), RegNOREG);
  118. }
  119. return instr;
  120. }
  121. void LegalizeMD::LegalizeSrc(IR::Instr * instr, IR::Opnd * opnd, uint opndNum, bool fPostRegAlloc)
  122. {
  123. LegalForms forms = LegalSrcForms(instr, opndNum);
  124. if (opnd == NULL)
  125. {
  126. #ifdef DBG
  127. // No legalization possible, just report error.
  128. if (forms != 0)
  129. {
  130. IllegalInstr(instr, _u("Expected src %d opnd"), opndNum);
  131. }
  132. #endif
  133. return;
  134. }
  135. switch (opnd->GetKind())
  136. {
  137. case IR::OpndKindReg:
  138. // No legalization possible, just report error.
  139. #ifdef DBG
  140. if (!(forms & L_RegMask))
  141. {
  142. IllegalInstr(instr, _u("Unexpected reg as src%d opnd"), opndNum);
  143. }
  144. #endif
  145. break;
  146. case IR::OpndKindAddr:
  147. case IR::OpndKindHelperCall:
  148. case IR::OpndKindIntConst:
  149. LegalizeImmed(instr, opnd, opndNum, opnd->GetImmediateValueAsInt32(instr->m_func), forms, fPostRegAlloc);
  150. break;
  151. case IR::OpndKindLabel:
  152. LegalizeLabelOpnd(instr, opnd, opndNum, fPostRegAlloc);
  153. break;
  154. case IR::OpndKindMemRef:
  155. {
  156. // MemRefOpnd is a deference of the memory location.
  157. // So extract the location, load it to register, replace the MemRefOpnd with an IndirOpnd taking the
  158. // register as base, and fall through to legalize the IndirOpnd.
  159. intptr_t memLoc = opnd->AsMemRefOpnd()->GetMemLoc();
  160. IR::RegOpnd *newReg = IR::RegOpnd::New(TyMachPtr, instr->m_func);
  161. if (fPostRegAlloc)
  162. {
  163. newReg->SetReg(SCRATCH_REG);
  164. }
  165. IR::Instr *newInstr = IR::Instr::New(Js::OpCode::LDIMM, newReg, IR::AddrOpnd::New(memLoc, IR::AddrOpndKindDynamicMisc, instr->m_func), instr->m_func);
  166. instr->InsertBefore(newInstr);
  167. LegalizeMD::LegalizeInstr(newInstr, fPostRegAlloc);
  168. IR::IndirOpnd *indirOpnd = IR::IndirOpnd::New(newReg, 0, opnd->GetType(), instr->m_func);
  169. if (opndNum == 1)
  170. {
  171. opnd = instr->ReplaceSrc1(indirOpnd);
  172. }
  173. else
  174. {
  175. opnd = instr->ReplaceSrc2(indirOpnd);
  176. }
  177. }
  178. // FALL THROUGH
  179. case IR::OpndKindIndir:
  180. if (!(forms & L_IndirMask))
  181. {
  182. instr = LegalizeLoad(instr, opndNum, forms, fPostRegAlloc);
  183. forms = LegalSrcForms(instr, 1);
  184. }
  185. LegalizeIndirOffset(instr, opnd->AsIndirOpnd(), forms, fPostRegAlloc);
  186. break;
  187. case IR::OpndKindSym:
  188. if (!(forms & L_SymMask))
  189. {
  190. instr = LegalizeLoad(instr, opndNum, forms, fPostRegAlloc);
  191. forms = LegalSrcForms(instr, 1);
  192. }
  193. if (fPostRegAlloc)
  194. {
  195. // In order to legalize SymOffset we need to know final argument area, which is only available after lowerer.
  196. // So, don't legalize sym offset here, but it will be done as part of register allocator.
  197. LegalizeSymOffset(instr, opnd->AsSymOpnd(), forms, fPostRegAlloc);
  198. }
  199. break;
  200. default:
  201. AssertMsg(UNREACHED, "Unexpected src opnd kind");
  202. break;
  203. }
  204. }
  205. IR::Instr * LegalizeMD::LegalizeLoad(IR::Instr *instr, uint opndNum, LegalForms forms, bool fPostRegAlloc)
  206. {
  207. if (LowererMD::IsAssign(instr) && instr->GetDst()->IsRegOpnd())
  208. {
  209. // We can just change this to a load in place.
  210. instr->m_opcode = LowererMD::GetLoadOp(instr->GetDst()->GetType());
  211. }
  212. else
  213. {
  214. // Hoist the memory opnd. The caller will verify the offset.
  215. if (opndNum == 1)
  216. {
  217. AssertMsg(!fPostRegAlloc || instr->GetSrc1()->GetType() == TyMachReg, "Post RegAlloc other types disallowed");
  218. instr = instr->HoistSrc1(LowererMD::GetLoadOp(instr->GetSrc1()->GetType()), fPostRegAlloc ? SCRATCH_REG : RegNOREG);
  219. }
  220. else
  221. {
  222. AssertMsg(!fPostRegAlloc || instr->GetSrc2()->GetType() == TyMachReg, "Post RegAlloc other types disallowed");
  223. instr = instr->HoistSrc2(LowererMD::GetLoadOp(instr->GetSrc2()->GetType()), fPostRegAlloc ? SCRATCH_REG : RegNOREG);
  224. }
  225. }
  226. return instr;
  227. }
  228. void LegalizeMD::LegalizeIndirOffset(IR::Instr * instr, IR::IndirOpnd * indirOpnd, LegalForms forms, bool fPostRegAlloc)
  229. {
  230. if (forms & (L_VIndirI11))
  231. {
  232. // Vfp doesn't support register indirect operation
  233. LegalizeMD::LegalizeIndirOpndForVFP(instr, indirOpnd, fPostRegAlloc);
  234. return;
  235. }
  236. int32 offset = indirOpnd->GetOffset();
  237. if (indirOpnd->GetIndexOpnd() != NULL && offset != 0)
  238. {
  239. IR::Instr *addInstr = instr->HoistIndirOffset(indirOpnd, fPostRegAlloc ? SCRATCH_REG : RegNOREG);
  240. LegalizeMD::LegalizeInstr(addInstr, fPostRegAlloc);
  241. return;
  242. }
  243. if (forms & (L_IndirI8 | L_IndirU12I8))
  244. {
  245. if (IS_CONST_INT8(offset))
  246. {
  247. return;
  248. }
  249. }
  250. if (forms & (L_IndirU12I8 | L_IndirU12))
  251. {
  252. if (IS_CONST_UINT12(offset))
  253. {
  254. return;
  255. }
  256. }
  257. // Offset is too large, so hoist it and replace it with an index, only valid for Thumb & Thumb2
  258. IR::Instr *addInstr = instr->HoistIndirOffset(indirOpnd, fPostRegAlloc ? SCRATCH_REG : RegNOREG);
  259. LegalizeMD::LegalizeInstr(addInstr, fPostRegAlloc);
  260. }
  261. void LegalizeMD::LegalizeSymOffset(
  262. IR::Instr * instr,
  263. IR::SymOpnd * symOpnd,
  264. LegalForms forms,
  265. bool fPostRegAlloc)
  266. {
  267. AssertMsg(fPostRegAlloc, "LegalizeMD::LegalizeSymOffset can (and will) be called as part of register allocation. Can't call it as part of lowerer, as final argument area is not available yet.");
  268. RegNum baseReg;
  269. int32 offset;
  270. if (!symOpnd->m_sym->IsStackSym())
  271. {
  272. return;
  273. }
  274. EncoderMD::BaseAndOffsetFromSym(symOpnd, &baseReg, &offset, instr->m_func->GetTopFunc());
  275. if (forms & (L_SymU12I8 | L_SymU12))
  276. {
  277. if (IS_CONST_UINT12(offset))
  278. {
  279. return;
  280. }
  281. }
  282. if (forms & L_SymU12I8)
  283. {
  284. if (IS_CONST_INT8(offset))
  285. {
  286. return;
  287. }
  288. }
  289. if (forms & (L_VSymI11))
  290. {
  291. if (IS_CONST_UINT10((offset < 0? -offset: offset)))
  292. {
  293. return;
  294. }
  295. IR::RegOpnd *baseOpnd = IR::RegOpnd::New(NULL, baseReg, TyMachPtr, instr->m_func);
  296. IR::Instr* instrAdd = instr->HoistSymOffsetAsAdd(symOpnd, baseOpnd, offset, fPostRegAlloc ? SCRATCH_REG : RegNOREG);
  297. LegalizeMD::LegalizeInstr(instrAdd, fPostRegAlloc);
  298. return;
  299. }
  300. IR::Instr * newInstr;
  301. if (instr->m_opcode == Js::OpCode::LEA)
  302. {
  303. instr->m_opcode = Js::OpCode::ADD;
  304. instr->ReplaceSrc1(IR::RegOpnd::New(NULL, baseReg, TyMachPtr, instr->m_func));
  305. instr->SetSrc2(IR::IntConstOpnd::New(offset, TyMachReg, instr->m_func));
  306. newInstr = instr->HoistSrc2(Js::OpCode::LDIMM, fPostRegAlloc ? SCRATCH_REG : RegNOREG);
  307. LegalizeMD::LegalizeInstr(newInstr, fPostRegAlloc);
  308. LegalizeMD::LegalizeInstr(instr, fPostRegAlloc);
  309. }
  310. else
  311. {
  312. newInstr = instr->HoistSymOffset(symOpnd, baseReg, offset, fPostRegAlloc ? SCRATCH_REG : RegNOREG);
  313. LegalizeMD::LegalizeInstr(newInstr, fPostRegAlloc);
  314. }
  315. }
  316. void LegalizeMD::LegalizeImmed(
  317. IR::Instr * instr,
  318. IR::Opnd * opnd,
  319. uint opndNum,
  320. IntConstType immed,
  321. LegalForms forms,
  322. bool fPostRegAlloc)
  323. {
  324. if (!(((forms & L_ImmModC12) && EncoderMD::CanEncodeModConst12(immed)) ||
  325. ((forms & L_ImmU5) && IS_CONST_UINT5(immed)) ||
  326. ((forms & L_ImmU12) && IS_CONST_UINT12(immed)) ||
  327. ((forms & L_ImmU16) && IS_CONST_UINT16(immed))))
  328. {
  329. if (instr->m_opcode != Js::OpCode::LDIMM)
  330. {
  331. instr = LegalizeMD::GenerateLDIMM(instr, opndNum, fPostRegAlloc ? SCRATCH_REG : RegNOREG);
  332. }
  333. if (fPostRegAlloc)
  334. {
  335. LegalizeMD::LegalizeLDIMM(instr, immed);
  336. }
  337. }
  338. }
  339. void LegalizeMD::LegalizeLabelOpnd(
  340. IR::Instr * instr,
  341. IR::Opnd * opnd,
  342. uint opndNum,
  343. bool fPostRegAlloc)
  344. {
  345. if (instr->m_opcode != Js::OpCode::LDIMM)
  346. {
  347. instr = LegalizeMD::GenerateLDIMM(instr, opndNum, fPostRegAlloc ? SCRATCH_REG : RegNOREG);
  348. }
  349. if (fPostRegAlloc)
  350. {
  351. LegalizeMD::LegalizeLdLabel(instr, opnd);
  352. }
  353. }
  354. IR::Instr * LegalizeMD::GenerateLDIMM(IR::Instr * instr, uint opndNum, RegNum scratchReg)
  355. {
  356. if (LowererMD::IsAssign(instr) && instr->GetDst()->IsRegOpnd())
  357. {
  358. instr->m_opcode = Js::OpCode::LDIMM;
  359. }
  360. else
  361. {
  362. if (opndNum == 1)
  363. {
  364. instr = instr->HoistSrc1(Js::OpCode::LDIMM, scratchReg);
  365. }
  366. else
  367. {
  368. instr = instr->HoistSrc2(Js::OpCode::LDIMM, scratchReg);
  369. }
  370. }
  371. return instr;
  372. }
  373. void LegalizeMD::LegalizeLDIMM(IR::Instr * instr, IntConstType immed)
  374. {
  375. // In case of inlined entry instruction, we don't know the offset till the encoding phase
  376. if (!instr->isInlineeEntryInstr)
  377. {
  378. if (IS_CONST_UINT16(immed) || EncoderMD::CanEncodeModConst12(immed))
  379. {
  380. instr->m_opcode = Js::OpCode::MOV;
  381. return;
  382. }
  383. bool fDontEncode = Security::DontEncode(instr->GetSrc1());
  384. IR::IntConstOpnd *src1 = IR::IntConstOpnd::New(immed & 0x0000FFFF, TyInt16, instr->m_func);
  385. IR::Instr * instrMov = IR::Instr::New(Js::OpCode::MOV, instr->GetDst(), src1, instr->m_func);
  386. instr->InsertBefore(instrMov);
  387. src1 = IR::IntConstOpnd::New((immed & 0xFFFF0000)>>16, TyInt16, instr->m_func);
  388. instr->ReplaceSrc1(src1);
  389. instr->m_opcode = Js::OpCode::MOVT;
  390. if (!fDontEncode)
  391. {
  392. LegalizeMD::ObfuscateLDIMM(instrMov, instr);
  393. }
  394. }
  395. else
  396. {
  397. Assert(Security::DontEncode(instr->GetSrc1()));
  398. IR::LabelInstr *label = IR::LabelInstr::New(Js::OpCode::Label, instr->m_func, false);
  399. instr->InsertBefore(label);
  400. Assert((immed & 0x0000000F) == immed);
  401. label->SetOffset(immed);
  402. IR::LabelOpnd *target = IR::LabelOpnd::New(label, instr->m_func);
  403. IR::Instr * instrMov = IR::Instr::New(Js::OpCode::MOVW, instr->GetDst(), target, instr->m_func);
  404. instr->InsertBefore(instrMov);
  405. instr->ReplaceSrc1(target);
  406. instr->m_opcode = Js::OpCode::MOVT;
  407. label->isInlineeEntryInstr = true;
  408. instr->isInlineeEntryInstr = false;
  409. }
  410. }
  411. void LegalizeMD::ObfuscateLDIMM(IR::Instr * instrMov, IR::Instr * instrMovt)
  412. {
  413. // Are security measures disabled?
  414. if (CONFIG_ISENABLED(Js::DebugFlag) ||
  415. CONFIG_ISENABLED(Js::BenchmarkFlag) ||
  416. PHASE_OFF(Js::EncodeConstantsPhase, instrMov->m_func->GetTopFunc())
  417. )
  418. {
  419. return;
  420. }
  421. UINT_PTR rand = Math::Rand();
  422. // Use this random value as follows:
  423. // bits 0-3: reg to use in pre-LDIMM instr
  424. // bits 4: do/don't emit pre-LDIMM instr
  425. // bits 5-6: emit and/or/add/mov as pre-LDIMM instr
  426. // Similarly for bits 7-13 (mid-LDIMM) and 14-20 (post-LDIMM)
  427. RegNum targetReg = instrMov->GetDst()->AsRegOpnd()->GetReg();
  428. LegalizeMD::EmitRandomNopBefore(instrMov, rand, targetReg);
  429. LegalizeMD::EmitRandomNopBefore(instrMovt, rand >> 7, targetReg);
  430. LegalizeMD::EmitRandomNopBefore(instrMovt->m_next, rand >> 14, targetReg);
  431. }
  432. void LegalizeMD::EmitRandomNopBefore(IR::Instr *insertInstr, UINT_PTR rand, RegNum targetReg)
  433. {
  434. // bits 0-3: reg to use in pre-LDIMM instr
  435. // bits 4: do/don't emit pre-LDIMM instr
  436. // bits 5-6: emit and/or/add/mov as pre-LDIMM instr
  437. if (!(rand & (1 << 4)) && !PHASE_FORCE(Js::EncodeConstantsPhase, insertInstr->m_func->GetTopFunc()))
  438. {
  439. return;
  440. }
  441. IR::Instr * instr;
  442. IR::RegOpnd * opnd1;
  443. IR::Opnd * opnd2 = NULL;
  444. Js::OpCode op = Js::OpCode::InvalidOpCode;
  445. RegNum regNum = (RegNum)((rand & ((1 << 4) - 1)) + RegR0);
  446. opnd1 = IR::RegOpnd::New(NULL, regNum, TyMachReg, insertInstr->m_func);
  447. if (regNum == RegSP || regNum == RegPC || regNum == targetReg) //skip sp & pc & the target reg
  448. {
  449. // ORR pc,pc,0 has unpredicted behavior.
  450. // AND sp,sp,sp has unpredicted behavior.
  451. // We avoid target reg to avoid pipeline stalls.
  452. // Less likely target reg will be RegR12 as we insert nops only for user defined constants and
  453. // RegR12 is mostly used for temporary data such as legalizer post regalloc.
  454. opnd1->SetReg(RegR12);
  455. }
  456. switch ((rand >> 5) & 3)
  457. {
  458. case 0:
  459. op = Js::OpCode::AND;
  460. opnd2 = opnd1;
  461. break;
  462. case 1:
  463. op = Js::OpCode::ORR;
  464. opnd2 = IR::IntConstOpnd::New(0, TyMachReg, insertInstr->m_func);
  465. break;
  466. case 2:
  467. op = Js::OpCode::ADD;
  468. opnd2 = IR::IntConstOpnd::New(0, TyMachReg, insertInstr->m_func);
  469. break;
  470. case 3:
  471. op = Js::OpCode::MOV;
  472. break;
  473. }
  474. instr = IR::Instr::New(op, opnd1, opnd1, insertInstr->m_func);
  475. if (opnd2)
  476. {
  477. instr->SetSrc2(opnd2);
  478. }
  479. insertInstr->InsertBefore(instr);
  480. }
  481. void LegalizeMD::LegalizeLdLabel(IR::Instr * instr, IR::Opnd * opnd)
  482. {
  483. Assert(instr->m_opcode == Js::OpCode::LDIMM);
  484. Assert(opnd->IsLabelOpnd());
  485. IR::Instr * instrMov = IR::Instr::New(Js::OpCode::MOVW, instr->GetDst(), opnd, instr->m_func);
  486. instr->InsertBefore(instrMov);
  487. instr->m_opcode = Js::OpCode::MOVT;
  488. }
  489. bool LegalizeMD::LegalizeDirectBranch(IR::BranchInstr *branchInstr, uint32 branchOffset)
  490. {
  491. Assert(branchInstr->IsBranchInstr());
  492. uint32 labelOffset = branchInstr->GetTarget()->GetOffset();
  493. Assert(labelOffset); //Label offset must be set.
  494. int32 offset = labelOffset - branchOffset;
  495. //We should never run out of 24 bits which corresponds to +-16MB of code size.
  496. AssertMsg(IS_CONST_INT24(offset >> 1), "Cannot encode more that 16 MB offset");
  497. if (LowererMD::IsUnconditionalBranch(branchInstr))
  498. {
  499. return false;
  500. }
  501. if (IS_CONST_INT21(offset))
  502. {
  503. return false;
  504. }
  505. // Convert a conditional branch which can only be +-1MB to unconditional branch which is +-16MB
  506. // Convert beq Label (where Label is long jump) to something like this
  507. // bne Fallback
  508. // b Label
  509. // Fallback:
  510. IR::LabelInstr *doneLabelInstr = IR::LabelInstr::New(Js::OpCode::Label, branchInstr->m_func, false);
  511. IR::BranchInstr *newBranchInstr = IR::BranchInstr::New(branchInstr->m_opcode, doneLabelInstr, branchInstr->m_func);
  512. LowererMD::InvertBranch(newBranchInstr);
  513. branchInstr->InsertBefore(newBranchInstr);
  514. branchInstr->InsertAfter(doneLabelInstr);
  515. branchInstr->m_opcode = Js::OpCode::B;
  516. return true;
  517. }
  518. void LegalizeMD::LegalizeIndirOpndForVFP(IR::Instr* insertInstr, IR::IndirOpnd *indirOpnd, bool fPostRegAlloc)
  519. {
  520. IR::RegOpnd *baseOpnd = indirOpnd->GetBaseOpnd();
  521. int32 offset = indirOpnd->GetOffset();
  522. IR::RegOpnd *indexOpnd = indirOpnd->UnlinkIndexOpnd(); //Clears index operand
  523. byte scale = indirOpnd->GetScale();
  524. IR::Instr *instr = NULL;
  525. if (indexOpnd)
  526. {
  527. if (scale > 0)
  528. {
  529. // There is no support for ADD instruction with barrel shifter in encoder, hence add an explicit instruction to left shift the index operand
  530. // Reason is this requires 4 operand in IR and there is no support for this yet.
  531. // If we encounter more such scenarios, its better to solve the root cause.
  532. // Also VSTR & VLDR don't take index operand as parameter
  533. IR::RegOpnd* newIndexOpnd = IR::RegOpnd::New(indexOpnd->GetType(), insertInstr->m_func);
  534. instr = IR::Instr::New(Js::OpCode::LSL, newIndexOpnd, indexOpnd,
  535. IR::IntConstOpnd::New(scale, TyMachReg, insertInstr->m_func), insertInstr->m_func);
  536. insertInstr->InsertBefore(instr);
  537. indirOpnd->SetScale(0); //Clears scale
  538. indexOpnd = newIndexOpnd;
  539. }
  540. insertInstr->HoistIndirIndexOpndAsAdd(indirOpnd, baseOpnd, indexOpnd, fPostRegAlloc? SCRATCH_REG : RegNOREG);
  541. }
  542. if (IS_CONST_UINT10((offset < 0? -offset: offset)))
  543. {
  544. return;
  545. }
  546. IR::Instr* instrAdd = insertInstr->HoistIndirOffsetAsAdd(indirOpnd, indirOpnd->GetBaseOpnd(), offset, fPostRegAlloc ? SCRATCH_REG : RegNOREG);
  547. LegalizeMD::LegalizeInstr(instrAdd, fPostRegAlloc);
  548. }
  549. #ifdef DBG
  550. void LegalizeMD::IllegalInstr(IR::Instr * instr, const char16 * msg, ...)
  551. {
  552. va_list argptr;
  553. va_start(argptr, msg);
  554. Output::Print(_u("Illegal instruction: "));
  555. instr->Dump();
  556. Output::Print(msg, argptr);
  557. Assert(UNREACHED);
  558. }
  559. #endif