LegalizeMD.cpp 21 KB

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