ILEmitterCtx.cs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781
  1. using ChocolArm64.Decoders;
  2. using ChocolArm64.Instructions;
  3. using ChocolArm64.Memory;
  4. using ChocolArm64.State;
  5. using System;
  6. using System.Collections.Generic;
  7. using System.Reflection;
  8. using System.Reflection.Emit;
  9. namespace ChocolArm64.Translation
  10. {
  11. class ILEmitterCtx
  12. {
  13. public MemoryManager Memory { get; }
  14. private TranslatorCache _cache;
  15. private TranslatorQueue _queue;
  16. private Dictionary<long, ILLabel> _labels;
  17. private long _subPosition;
  18. private int _opcIndex;
  19. private Block _currBlock;
  20. public Block CurrBlock => _currBlock;
  21. public OpCode64 CurrOp => _currBlock?.OpCodes[_opcIndex];
  22. public TranslationTier Tier { get; }
  23. public Aarch32Mode Mode { get; } = Aarch32Mode.User; //TODO
  24. public bool HasIndirectJump { get; set; }
  25. public bool HasSlowCall { get; set; }
  26. private Dictionary<Block, ILBlock> _visitedBlocks;
  27. private Queue<Block> _branchTargets;
  28. private List<ILBlock> _ilBlocks;
  29. private ILBlock _ilBlock;
  30. private OpCode64 _optOpLastCompare;
  31. private OpCode64 _optOpLastFlagSet;
  32. //This is the index of the temporary register, used to store temporary
  33. //values needed by some functions, since IL doesn't have a swap instruction.
  34. //You can use any value here as long it doesn't conflict with the indices
  35. //for the other registers. Any value >= 64 or < 0 will do.
  36. private const int ReservedLocalsCount = 64;
  37. private const int RorTmpIndex = ReservedLocalsCount + 0;
  38. private const int CmpOptTmp1Index = ReservedLocalsCount + 1;
  39. private const int CmpOptTmp2Index = ReservedLocalsCount + 2;
  40. private const int IntGpTmp1Index = ReservedLocalsCount + 3;
  41. private const int IntGpTmp2Index = ReservedLocalsCount + 4;
  42. private const int UserIntTempStart = ReservedLocalsCount + 5;
  43. //Vectors are part of another "set" of locals.
  44. private const int VecGpTmp1Index = ReservedLocalsCount + 0;
  45. private const int VecGpTmp2Index = ReservedLocalsCount + 1;
  46. private const int UserVecTempStart = ReservedLocalsCount + 2;
  47. private static int _userIntTempCount;
  48. private static int _userVecTempCount;
  49. public ILEmitterCtx(
  50. MemoryManager memory,
  51. TranslatorCache cache,
  52. TranslatorQueue queue,
  53. TranslationTier tier,
  54. Block graph)
  55. {
  56. Memory = memory ?? throw new ArgumentNullException(nameof(memory));
  57. _cache = cache ?? throw new ArgumentNullException(nameof(cache));
  58. _queue = queue ?? throw new ArgumentNullException(nameof(queue));
  59. _currBlock = graph ?? throw new ArgumentNullException(nameof(graph));
  60. Tier = tier;
  61. _labels = new Dictionary<long, ILLabel>();
  62. _visitedBlocks = new Dictionary<Block, ILBlock>();
  63. _visitedBlocks.Add(graph, new ILBlock());
  64. _branchTargets = new Queue<Block>();
  65. _ilBlocks = new List<ILBlock>();
  66. _subPosition = graph.Position;
  67. ResetBlockState();
  68. if (AdvanceOpCode())
  69. {
  70. EmitSynchronization();
  71. _ilBlock.Add(new ILOpCodeLoadState(_ilBlock, isSubEntry: true));
  72. }
  73. }
  74. public static int GetIntTempIndex()
  75. {
  76. return UserIntTempStart + _userIntTempCount++;
  77. }
  78. public static int GetVecTempIndex()
  79. {
  80. return UserVecTempStart + _userVecTempCount++;
  81. }
  82. public ILBlock[] GetILBlocks()
  83. {
  84. EmitAllOpCodes();
  85. return _ilBlocks.ToArray();
  86. }
  87. private void EmitAllOpCodes()
  88. {
  89. do
  90. {
  91. EmitOpCode();
  92. }
  93. while (AdvanceOpCode());
  94. }
  95. private void EmitOpCode()
  96. {
  97. if (_currBlock == null)
  98. {
  99. return;
  100. }
  101. int opcIndex = _opcIndex;
  102. if (opcIndex == 0)
  103. {
  104. MarkLabel(GetLabel(_currBlock.Position));
  105. }
  106. bool isLastOp = opcIndex == CurrBlock.OpCodes.Count - 1;
  107. if (isLastOp && CurrBlock.Branch != null &&
  108. (ulong)CurrBlock.Branch.Position <= (ulong)CurrBlock.Position)
  109. {
  110. EmitSynchronization();
  111. }
  112. //On AARCH32 mode, (almost) all instruction can be conditionally
  113. //executed, and the required condition is encoded on the opcode.
  114. //We handle that here, skipping the instruction if the condition
  115. //is not met. We can just ignore it when the condition is "Always",
  116. //because in this case the instruction is always going to be executed.
  117. //Condition "Never" is also ignored because this is a special encoding
  118. //used by some unconditional instructions.
  119. ILLabel lblSkip = null;
  120. if (CurrOp is OpCode32 op && op.Cond < Condition.Al)
  121. {
  122. lblSkip = new ILLabel();
  123. EmitCondBranch(lblSkip, GetInverseCond(op.Cond));
  124. }
  125. CurrOp.Emitter(this);
  126. if (lblSkip != null)
  127. {
  128. MarkLabel(lblSkip);
  129. //If this is the last op on the block, and there's no "next" block
  130. //after this one, then we have to return right now, with the address
  131. //of the next instruction to be executed (in the case that the condition
  132. //is false, and the branch was not taken, as all basic blocks should end with
  133. //some kind of branch).
  134. if (isLastOp && CurrBlock.Next == null)
  135. {
  136. EmitStoreState();
  137. EmitLdc_I8(CurrOp.Position + CurrOp.OpCodeSizeInBytes);
  138. Emit(OpCodes.Ret);
  139. }
  140. }
  141. _ilBlock.Add(new ILBarrier());
  142. }
  143. private static Condition GetInverseCond(Condition cond)
  144. {
  145. //Bit 0 of all conditions is basically a negation bit, so
  146. //inverting this bit has the effect of inverting the condition.
  147. return (Condition)((int)cond ^ 1);
  148. }
  149. private void EmitSynchronization()
  150. {
  151. EmitLdarg(TranslatedSub.StateArgIdx);
  152. EmitLdc_I4(_currBlock.OpCodes.Count);
  153. EmitPrivateCall(typeof(CpuThreadState), nameof(CpuThreadState.Synchronize));
  154. EmitLdc_I4(0);
  155. ILLabel lblContinue = new ILLabel();
  156. Emit(OpCodes.Bne_Un_S, lblContinue);
  157. EmitLdc_I8(0);
  158. Emit(OpCodes.Ret);
  159. MarkLabel(lblContinue);
  160. }
  161. private bool AdvanceOpCode()
  162. {
  163. if (_currBlock == null)
  164. {
  165. return false;
  166. }
  167. while (++_opcIndex >= _currBlock.OpCodes.Count)
  168. {
  169. if (!AdvanceBlock())
  170. {
  171. return false;
  172. }
  173. ResetBlockState();
  174. }
  175. return true;
  176. }
  177. private bool AdvanceBlock()
  178. {
  179. if (_currBlock.Branch != null)
  180. {
  181. if (_visitedBlocks.TryAdd(_currBlock.Branch, _ilBlock.Branch))
  182. {
  183. _branchTargets.Enqueue(_currBlock.Branch);
  184. }
  185. }
  186. if (_currBlock.Next != null)
  187. {
  188. if (_visitedBlocks.TryAdd(_currBlock.Next, _ilBlock.Next))
  189. {
  190. _currBlock = _currBlock.Next;
  191. return true;
  192. }
  193. else
  194. {
  195. Emit(OpCodes.Br, GetLabel(_currBlock.Next.Position));
  196. }
  197. }
  198. return _branchTargets.TryDequeue(out _currBlock);
  199. }
  200. private void ResetBlockState()
  201. {
  202. _ilBlock = _visitedBlocks[_currBlock];
  203. _ilBlocks.Add(_ilBlock);
  204. _ilBlock.Next = GetOrCreateILBlock(_currBlock.Next);
  205. _ilBlock.Branch = GetOrCreateILBlock(_currBlock.Branch);
  206. _opcIndex = -1;
  207. _optOpLastFlagSet = null;
  208. _optOpLastCompare = null;
  209. }
  210. private ILBlock GetOrCreateILBlock(Block block)
  211. {
  212. if (block == null)
  213. {
  214. return null;
  215. }
  216. if (_visitedBlocks.TryGetValue(block, out ILBlock ilBlock))
  217. {
  218. return ilBlock;
  219. }
  220. return new ILBlock();
  221. }
  222. public void TranslateAhead(long position, ExecutionMode mode = ExecutionMode.Aarch64)
  223. {
  224. if (_cache.TryGetSubroutine(position, out TranslatedSub sub) && sub.Tier != TranslationTier.Tier0)
  225. {
  226. return;
  227. }
  228. _queue.Enqueue(position, mode, TranslationTier.Tier1, isComplete: true);
  229. }
  230. public bool TryOptEmitSubroutineCall()
  231. {
  232. //Calls should always have a next block, unless
  233. //we're translating a single basic block.
  234. if (_currBlock.Next == null)
  235. {
  236. return false;
  237. }
  238. if (!(CurrOp is IOpCodeBImm op))
  239. {
  240. return false;
  241. }
  242. if (!_cache.TryGetSubroutine(op.Imm, out TranslatedSub sub))
  243. {
  244. return false;
  245. }
  246. //It's not worth to call a Tier0 method, because
  247. //it contains slow code, rather than the entire function.
  248. if (sub.Tier == TranslationTier.Tier0)
  249. {
  250. return false;
  251. }
  252. EmitStoreState(sub);
  253. for (int index = 0; index < TranslatedSub.FixedArgTypes.Length; index++)
  254. {
  255. EmitLdarg(index);
  256. }
  257. EmitCall(sub.Method);
  258. return true;
  259. }
  260. public void TryOptMarkCondWithoutCmp()
  261. {
  262. _optOpLastCompare = CurrOp;
  263. InstEmitAluHelper.EmitAluLoadOpers(this);
  264. Stloc(CmpOptTmp2Index, VarType.Int);
  265. Stloc(CmpOptTmp1Index, VarType.Int);
  266. }
  267. private Dictionary<Condition, OpCode> _branchOps = new Dictionary<Condition, OpCode>()
  268. {
  269. { Condition.Eq, OpCodes.Beq },
  270. { Condition.Ne, OpCodes.Bne_Un },
  271. { Condition.GeUn, OpCodes.Bge_Un },
  272. { Condition.LtUn, OpCodes.Blt_Un },
  273. { Condition.GtUn, OpCodes.Bgt_Un },
  274. { Condition.LeUn, OpCodes.Ble_Un },
  275. { Condition.Ge, OpCodes.Bge },
  276. { Condition.Lt, OpCodes.Blt },
  277. { Condition.Gt, OpCodes.Bgt },
  278. { Condition.Le, OpCodes.Ble }
  279. };
  280. public void EmitCondBranch(ILLabel target, Condition cond)
  281. {
  282. if (_optOpLastCompare != null &&
  283. _optOpLastCompare == _optOpLastFlagSet && _branchOps.ContainsKey(cond))
  284. {
  285. if (_optOpLastCompare.Emitter == InstEmit.Subs)
  286. {
  287. Ldloc(CmpOptTmp1Index, VarType.Int, _optOpLastCompare.RegisterSize);
  288. Ldloc(CmpOptTmp2Index, VarType.Int, _optOpLastCompare.RegisterSize);
  289. Emit(_branchOps[cond], target);
  290. return;
  291. }
  292. else if (_optOpLastCompare.Emitter == InstEmit.Adds && cond != Condition.GeUn
  293. && cond != Condition.LtUn
  294. && cond != Condition.GtUn
  295. && cond != Condition.LeUn)
  296. {
  297. //There are several limitations that needs to be taken into account for CMN comparisons:
  298. //* The unsigned comparisons are not valid, as they depend on the
  299. //carry flag value, and they will have different values for addition and
  300. //subtraction. For addition, it's carry, and for subtraction, it's borrow.
  301. //So, we need to make sure we're not doing a unsigned compare for the CMN case.
  302. //* We can only do the optimization for the immediate variants,
  303. //because when the second operand value is exactly INT_MIN, we can't
  304. //negate the value as theres no positive counterpart.
  305. //Such invalid values can't be encoded on the immediate encodings.
  306. if (_optOpLastCompare is IOpCodeAluImm64 op)
  307. {
  308. Ldloc(CmpOptTmp1Index, VarType.Int, _optOpLastCompare.RegisterSize);
  309. if (_optOpLastCompare.RegisterSize == RegisterSize.Int32)
  310. {
  311. EmitLdc_I4((int)-op.Imm);
  312. }
  313. else
  314. {
  315. EmitLdc_I8(-op.Imm);
  316. }
  317. Emit(_branchOps[cond], target);
  318. return;
  319. }
  320. }
  321. }
  322. OpCode ilOp;
  323. int intCond = (int)cond;
  324. if (intCond < 14)
  325. {
  326. int condTrue = intCond >> 1;
  327. switch (condTrue)
  328. {
  329. case 0: EmitLdflg((int)PState.ZBit); break;
  330. case 1: EmitLdflg((int)PState.CBit); break;
  331. case 2: EmitLdflg((int)PState.NBit); break;
  332. case 3: EmitLdflg((int)PState.VBit); break;
  333. case 4:
  334. EmitLdflg((int)PState.CBit);
  335. EmitLdflg((int)PState.ZBit);
  336. Emit(OpCodes.Not);
  337. Emit(OpCodes.And);
  338. break;
  339. case 5:
  340. case 6:
  341. EmitLdflg((int)PState.NBit);
  342. EmitLdflg((int)PState.VBit);
  343. Emit(OpCodes.Ceq);
  344. if (condTrue == 6)
  345. {
  346. EmitLdflg((int)PState.ZBit);
  347. Emit(OpCodes.Not);
  348. Emit(OpCodes.And);
  349. }
  350. break;
  351. }
  352. ilOp = (intCond & 1) != 0
  353. ? OpCodes.Brfalse
  354. : OpCodes.Brtrue;
  355. }
  356. else
  357. {
  358. ilOp = OpCodes.Br;
  359. }
  360. Emit(ilOp, target);
  361. }
  362. public void EmitCast(IntType intType)
  363. {
  364. switch (intType)
  365. {
  366. case IntType.UInt8: Emit(OpCodes.Conv_U1); break;
  367. case IntType.UInt16: Emit(OpCodes.Conv_U2); break;
  368. case IntType.UInt32: Emit(OpCodes.Conv_U4); break;
  369. case IntType.UInt64: Emit(OpCodes.Conv_U8); break;
  370. case IntType.Int8: Emit(OpCodes.Conv_I1); break;
  371. case IntType.Int16: Emit(OpCodes.Conv_I2); break;
  372. case IntType.Int32: Emit(OpCodes.Conv_I4); break;
  373. case IntType.Int64: Emit(OpCodes.Conv_I8); break;
  374. }
  375. bool sz64 = CurrOp.RegisterSize != RegisterSize.Int32;
  376. if (sz64 == (intType == IntType.UInt64 ||
  377. intType == IntType.Int64))
  378. {
  379. return;
  380. }
  381. if (sz64)
  382. {
  383. Emit(intType >= IntType.Int8
  384. ? OpCodes.Conv_I8
  385. : OpCodes.Conv_U8);
  386. }
  387. else
  388. {
  389. Emit(OpCodes.Conv_U4);
  390. }
  391. }
  392. public void EmitLsl(int amount) => EmitILShift(amount, OpCodes.Shl);
  393. public void EmitLsr(int amount) => EmitILShift(amount, OpCodes.Shr_Un);
  394. public void EmitAsr(int amount) => EmitILShift(amount, OpCodes.Shr);
  395. private void EmitILShift(int amount, OpCode ilOp)
  396. {
  397. if (amount > 0)
  398. {
  399. EmitLdc_I4(amount);
  400. Emit(ilOp);
  401. }
  402. }
  403. public void EmitRor(int amount)
  404. {
  405. if (amount > 0)
  406. {
  407. Stloc(RorTmpIndex, VarType.Int);
  408. Ldloc(RorTmpIndex, VarType.Int);
  409. EmitLdc_I4(amount);
  410. Emit(OpCodes.Shr_Un);
  411. Ldloc(RorTmpIndex, VarType.Int);
  412. EmitLdc_I4(CurrOp.GetBitsCount() - amount);
  413. Emit(OpCodes.Shl);
  414. Emit(OpCodes.Or);
  415. }
  416. }
  417. public ILLabel GetLabel(long position)
  418. {
  419. if (!_labels.TryGetValue(position, out ILLabel output))
  420. {
  421. output = new ILLabel();
  422. _labels.Add(position, output);
  423. }
  424. return output;
  425. }
  426. public void MarkLabel(ILLabel label)
  427. {
  428. _ilBlock.Add(label);
  429. }
  430. public void Emit(OpCode ilOp)
  431. {
  432. _ilBlock.Add(new ILOpCode(ilOp));
  433. }
  434. public void Emit(OpCode ilOp, ILLabel label)
  435. {
  436. _ilBlock.Add(new ILOpCodeBranch(ilOp, label));
  437. }
  438. public void EmitFieldLoad(FieldInfo info)
  439. {
  440. _ilBlock.Add(new ILOpCodeLoadField(info));
  441. }
  442. public void EmitPrint(string text)
  443. {
  444. _ilBlock.Add(new ILOpCodeLog(text));
  445. }
  446. public void EmitLdarg(int index)
  447. {
  448. _ilBlock.Add(new ILOpCodeLoad(index, VarType.Arg));
  449. }
  450. public void EmitLdintzr(int index)
  451. {
  452. if (index != RegisterAlias.Zr)
  453. {
  454. EmitLdint(index);
  455. }
  456. else
  457. {
  458. EmitLdc_I(0);
  459. }
  460. }
  461. public void EmitStintzr(int index)
  462. {
  463. if (index != RegisterAlias.Zr)
  464. {
  465. EmitStint(index);
  466. }
  467. else
  468. {
  469. Emit(OpCodes.Pop);
  470. }
  471. }
  472. public void EmitLoadState()
  473. {
  474. if (_ilBlock.Next == null)
  475. {
  476. throw new InvalidOperationException("Can't load state for next block, because there's no next block.");
  477. }
  478. _ilBlock.Add(new ILOpCodeLoadState(_ilBlock.Next));
  479. }
  480. public void EmitStoreState()
  481. {
  482. _ilBlock.Add(new ILOpCodeStoreState(_ilBlock));
  483. }
  484. private void EmitStoreState(TranslatedSub callSub)
  485. {
  486. _ilBlock.Add(new ILOpCodeStoreState(_ilBlock, callSub));
  487. }
  488. public void EmitLdtmp() => EmitLdint(IntGpTmp1Index);
  489. public void EmitSttmp() => EmitStint(IntGpTmp1Index);
  490. public void EmitLdtmp2() => EmitLdint(IntGpTmp2Index);
  491. public void EmitSttmp2() => EmitStint(IntGpTmp2Index);
  492. public void EmitLdvectmp() => EmitLdvec(VecGpTmp1Index);
  493. public void EmitStvectmp() => EmitStvec(VecGpTmp1Index);
  494. public void EmitLdvectmp2() => EmitLdvec(VecGpTmp2Index);
  495. public void EmitStvectmp2() => EmitStvec(VecGpTmp2Index);
  496. public void EmitLdint(int index) => Ldloc(index, VarType.Int);
  497. public void EmitStint(int index) => Stloc(index, VarType.Int);
  498. public void EmitLdvec(int index) => Ldloc(index, VarType.Vector);
  499. public void EmitStvec(int index) => Stloc(index, VarType.Vector);
  500. public void EmitLdflg(int index) => Ldloc(index, VarType.Flag);
  501. public void EmitStflg(int index)
  502. {
  503. //Set this only if any of the NZCV flag bits were modified.
  504. //This is used to ensure that, when emiting a direct IL branch
  505. //instruction for compare + branch sequences, we're not expecting
  506. //to use comparison values from an old instruction, when in fact
  507. //the flags were already overwritten by another instruction further along.
  508. if (index >= (int)PState.VBit)
  509. {
  510. _optOpLastFlagSet = CurrOp;
  511. }
  512. Stloc(index, VarType.Flag);
  513. }
  514. private void Ldloc(int index, VarType varType)
  515. {
  516. _ilBlock.Add(new ILOpCodeLoad(index, varType, CurrOp.RegisterSize));
  517. }
  518. private void Ldloc(int index, VarType varType, RegisterSize registerSize)
  519. {
  520. _ilBlock.Add(new ILOpCodeLoad(index, varType, registerSize));
  521. }
  522. private void Stloc(int index, VarType varType)
  523. {
  524. _ilBlock.Add(new ILOpCodeStore(index, varType, CurrOp.RegisterSize));
  525. }
  526. public void EmitCallPropGet(Type objType, string propName)
  527. {
  528. EmitCall(objType, $"get_{propName}");
  529. }
  530. public void EmitCallPropSet(Type objType, string propName)
  531. {
  532. EmitCall(objType, $"set_{propName}");
  533. }
  534. public void EmitCall(Type objType, string mthdName)
  535. {
  536. if (objType == null)
  537. {
  538. throw new ArgumentNullException(nameof(objType));
  539. }
  540. if (mthdName == null)
  541. {
  542. throw new ArgumentNullException(nameof(mthdName));
  543. }
  544. EmitCall(objType.GetMethod(mthdName));
  545. }
  546. public void EmitCallPrivatePropGet(Type objType, string propName)
  547. {
  548. EmitPrivateCall(objType, $"get_{propName}");
  549. }
  550. public void EmitCallPrivatePropSet(Type objType, string propName)
  551. {
  552. EmitPrivateCall(objType, $"set_{propName}");
  553. }
  554. public void EmitPrivateCall(Type objType, string mthdName)
  555. {
  556. if (objType == null)
  557. {
  558. throw new ArgumentNullException(nameof(objType));
  559. }
  560. if (mthdName == null)
  561. {
  562. throw new ArgumentNullException(nameof(mthdName));
  563. }
  564. EmitCall(objType.GetMethod(mthdName, BindingFlags.Instance | BindingFlags.NonPublic));
  565. }
  566. public void EmitCall(MethodInfo mthdInfo, bool isVirtual = false)
  567. {
  568. _ilBlock.Add(new ILOpCodeCall(mthdInfo ?? throw new ArgumentNullException(nameof(mthdInfo)), isVirtual));
  569. }
  570. public void EmitLdc_I(long value)
  571. {
  572. if (CurrOp.RegisterSize == RegisterSize.Int32)
  573. {
  574. EmitLdc_I4((int)value);
  575. }
  576. else
  577. {
  578. EmitLdc_I8(value);
  579. }
  580. }
  581. public void EmitLdc_I4(int value)
  582. {
  583. _ilBlock.Add(new ILOpCodeConst(value));
  584. }
  585. public void EmitLdc_I8(long value)
  586. {
  587. _ilBlock.Add(new ILOpCodeConst(value));
  588. }
  589. public void EmitLdc_R4(float value)
  590. {
  591. _ilBlock.Add(new ILOpCodeConst(value));
  592. }
  593. public void EmitLdc_R8(double value)
  594. {
  595. _ilBlock.Add(new ILOpCodeConst(value));
  596. }
  597. public void EmitZnFlagCheck()
  598. {
  599. EmitZnCheck(OpCodes.Ceq, (int)PState.ZBit);
  600. EmitZnCheck(OpCodes.Clt, (int)PState.NBit);
  601. }
  602. private void EmitZnCheck(OpCode ilCmpOp, int flag)
  603. {
  604. Emit(OpCodes.Dup);
  605. Emit(OpCodes.Ldc_I4_0);
  606. if (CurrOp.RegisterSize != RegisterSize.Int32)
  607. {
  608. Emit(OpCodes.Conv_I8);
  609. }
  610. Emit(ilCmpOp);
  611. EmitStflg(flag);
  612. }
  613. }
  614. }