Assembler.cs 37 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160
  1. using ARMeilleure.IntermediateRepresentation;
  2. using System;
  3. using System.Diagnostics;
  4. using System.IO;
  5. using static ARMeilleure.IntermediateRepresentation.Operand;
  6. namespace ARMeilleure.CodeGen.Arm64
  7. {
  8. class Assembler
  9. {
  10. public const uint SfFlag = 1u << 31;
  11. private const int SpRegister = 31;
  12. private const int ZrRegister = 31;
  13. private readonly Stream _stream;
  14. public Assembler(Stream stream)
  15. {
  16. _stream = stream;
  17. }
  18. public void Add(Operand rd, Operand rn, Operand rm, ArmExtensionType extensionType, int shiftAmount = 0)
  19. {
  20. WriteInstructionAuto(0x0b200000u, rd, rn, rm, extensionType, shiftAmount);
  21. }
  22. public void Add(Operand rd, Operand rn, Operand rm, ArmShiftType shiftType = ArmShiftType.Lsl, int shiftAmount = 0, bool immForm = false)
  23. {
  24. WriteInstructionAuto(0x11000000u, 0x0b000000u, rd, rn, rm, shiftType, shiftAmount, immForm);
  25. }
  26. public void And(Operand rd, Operand rn, Operand rm, ArmShiftType shiftType = ArmShiftType.Lsl, int shiftAmount = 0)
  27. {
  28. WriteInstructionBitwiseAuto(0x12000000u, 0x0a000000u, rd, rn, rm, shiftType, shiftAmount);
  29. }
  30. public void Ands(Operand rd, Operand rn, Operand rm, ArmShiftType shiftType = ArmShiftType.Lsl, int shiftAmount = 0)
  31. {
  32. WriteInstructionBitwiseAuto(0x72000000u, 0x6a000000u, rd, rn, rm, shiftType, shiftAmount);
  33. }
  34. public void Asr(Operand rd, Operand rn, Operand rm)
  35. {
  36. if (rm.Kind == OperandKind.Constant)
  37. {
  38. int shift = rm.AsInt32();
  39. int mask = rd.Type == OperandType.I64 ? 63 : 31;
  40. shift &= mask;
  41. Sbfm(rd, rn, shift, mask);
  42. }
  43. else
  44. {
  45. Asrv(rd, rn, rm);
  46. }
  47. }
  48. public void Asrv(Operand rd, Operand rn, Operand rm)
  49. {
  50. WriteInstructionBitwiseAuto(0x1ac02800u, rd, rn, rm);
  51. }
  52. public void B(int imm)
  53. {
  54. WriteUInt32(0x14000000u | EncodeSImm26_2(imm));
  55. }
  56. public void B(ArmCondition condition, int imm)
  57. {
  58. WriteUInt32(0x54000000u | (uint)condition | (EncodeSImm19_2(imm) << 5));
  59. }
  60. public void Blr(Operand rn)
  61. {
  62. WriteUInt32(0xd63f0000u | (EncodeReg(rn) << 5));
  63. }
  64. public void Br(Operand rn)
  65. {
  66. WriteUInt32(0xd61f0000u | (EncodeReg(rn) << 5));
  67. }
  68. public void Brk()
  69. {
  70. WriteUInt32(0xd4200000u);
  71. }
  72. public void Cbz(Operand rt, int imm)
  73. {
  74. WriteInstructionAuto(0x34000000u | (EncodeSImm19_2(imm) << 5), rt);
  75. }
  76. public void Cbnz(Operand rt, int imm)
  77. {
  78. WriteInstructionAuto(0x35000000u | (EncodeSImm19_2(imm) << 5), rt);
  79. }
  80. public void Clrex(int crm = 15)
  81. {
  82. WriteUInt32(0xd503305fu | (EncodeUImm4(crm) << 8));
  83. }
  84. public void Clz(Operand rd, Operand rn)
  85. {
  86. WriteInstructionAuto(0x5ac01000u, rd, rn);
  87. }
  88. public void CmeqVector(Operand rd, Operand rn, Operand rm, int size, bool q = true)
  89. {
  90. Debug.Assert((uint)size < 4);
  91. WriteSimdInstruction(0x2e208c00u | ((uint)size << 22), rd, rn, rm, q);
  92. }
  93. public void Cmp(Operand rn, Operand rm, ArmShiftType shiftType = ArmShiftType.Lsl, int shiftAmount = 0)
  94. {
  95. Subs(Factory.Register(ZrRegister, RegisterType.Integer, rn.Type), rn, rm, shiftType, shiftAmount);
  96. }
  97. public void Csel(Operand rd, Operand rn, Operand rm, ArmCondition condition)
  98. {
  99. WriteInstructionBitwiseAuto(0x1a800000u | ((uint)condition << 12), rd, rn, rm);
  100. }
  101. public void Cset(Operand rd, ArmCondition condition)
  102. {
  103. var zr = Factory.Register(ZrRegister, RegisterType.Integer, rd.Type);
  104. Csinc(rd, zr, zr, (ArmCondition)((int)condition ^ 1));
  105. }
  106. public void Csinc(Operand rd, Operand rn, Operand rm, ArmCondition condition)
  107. {
  108. WriteInstructionBitwiseAuto(0x1a800400u | ((uint)condition << 12), rd, rn, rm);
  109. }
  110. public void Dmb(uint option)
  111. {
  112. WriteUInt32(0xd50330bfu | (option << 8));
  113. }
  114. public void DupScalar(Operand rd, Operand rn, int index, int size)
  115. {
  116. WriteInstruction(0x5e000400u | (EncodeIndexSizeImm5(index, size) << 16), rd, rn);
  117. }
  118. public void Eor(Operand rd, Operand rn, Operand rm, ArmShiftType shiftType = ArmShiftType.Lsl, int shiftAmount = 0)
  119. {
  120. WriteInstructionBitwiseAuto(0x52000000u, 0x4a000000u, rd, rn, rm, shiftType, shiftAmount);
  121. }
  122. public void EorVector(Operand rd, Operand rn, Operand rm, bool q = true)
  123. {
  124. WriteSimdInstruction(0x2e201c00u, rd, rn, rm, q);
  125. }
  126. public void Extr(Operand rd, Operand rn, Operand rm, int imms)
  127. {
  128. uint n = rd.Type == OperandType.I64 ? 1u << 22 : 0u;
  129. WriteInstructionBitwiseAuto(0x13800000u | n | (EncodeUImm6(imms) << 10), rd, rn, rm);
  130. }
  131. public void FaddScalar(Operand rd, Operand rn, Operand rm)
  132. {
  133. WriteFPInstructionAuto(0x1e202800u, rd, rn, rm);
  134. }
  135. public void FcvtScalar(Operand rd, Operand rn)
  136. {
  137. uint instruction = 0x1e224000u | (rd.Type == OperandType.FP64 ? 1u << 15 : 1u << 22);
  138. WriteUInt32(instruction | EncodeReg(rd) | (EncodeReg(rn) << 5));
  139. }
  140. public void FdivScalar(Operand rd, Operand rn, Operand rm)
  141. {
  142. WriteFPInstructionAuto(0x1e201800u, rd, rn, rm);
  143. }
  144. public void Fmov(Operand rd, Operand rn)
  145. {
  146. WriteFPInstructionAuto(0x1e204000u, rd, rn);
  147. }
  148. public void Fmov(Operand rd, Operand rn, bool topHalf)
  149. {
  150. Debug.Assert(rd.Type.IsInteger() != rn.Type.IsInteger());
  151. Debug.Assert(rd.Type == OperandType.I64 || rn.Type == OperandType.I64 || !topHalf);
  152. uint opcode = rd.Type.IsInteger() ? 0b110u : 0b111u;
  153. uint rmode = topHalf ? 1u << 19 : 0u;
  154. uint ftype = rd.Type == OperandType.FP64 || rn.Type == OperandType.FP64 ? 1u << 22 : 0u;
  155. uint sf = rd.Type == OperandType.I64 || rn.Type == OperandType.I64 ? SfFlag : 0u;
  156. WriteUInt32(0x1e260000u | (opcode << 16) | rmode | ftype | sf | EncodeReg(rd) | (EncodeReg(rn) << 5));
  157. }
  158. public void FmulScalar(Operand rd, Operand rn, Operand rm)
  159. {
  160. WriteFPInstructionAuto(0x1e200800u, rd, rn, rm);
  161. }
  162. public void FnegScalar(Operand rd, Operand rn)
  163. {
  164. WriteFPInstructionAuto(0x1e214000u, rd, rn);
  165. }
  166. public void FsubScalar(Operand rd, Operand rn, Operand rm)
  167. {
  168. WriteFPInstructionAuto(0x1e203800u, rd, rn, rm);
  169. }
  170. public void Ins(Operand rd, Operand rn, int index, int size)
  171. {
  172. WriteInstruction(0x4e001c00u | (EncodeIndexSizeImm5(index, size) << 16), rd, rn);
  173. }
  174. public void Ins(Operand rd, Operand rn, int srcIndex, int dstIndex, int size)
  175. {
  176. uint imm4 = (uint)srcIndex << size;
  177. Debug.Assert((uint)srcIndex < (16u >> size));
  178. WriteInstruction(0x6e000400u | (imm4 << 11) | (EncodeIndexSizeImm5(dstIndex, size) << 16), rd, rn);
  179. }
  180. public void Ldaxp(Operand rt, Operand rt2, Operand rn)
  181. {
  182. WriteInstruction(0x887f8000u | ((rt.Type == OperandType.I64 ? 3u : 2u) << 30), rt, rn, rt2);
  183. }
  184. public void Ldaxr(Operand rt, Operand rn)
  185. {
  186. WriteInstruction(0x085ffc00u | ((rt.Type == OperandType.I64 ? 3u : 2u) << 30), rt, rn);
  187. }
  188. public void Ldaxrb(Operand rt, Operand rn)
  189. {
  190. WriteInstruction(0x085ffc00u, rt, rn);
  191. }
  192. public void Ldaxrh(Operand rt, Operand rn)
  193. {
  194. WriteInstruction(0x085ffc00u | (1u << 30), rt, rn);
  195. }
  196. public void LdpRiPost(Operand rt, Operand rt2, Operand rn, int imm)
  197. {
  198. uint instruction = GetLdpStpInstruction(0x28c00000u, 0x2cc00000u, imm, rt.Type);
  199. WriteInstruction(instruction, rt, rn, rt2);
  200. }
  201. public void LdpRiPre(Operand rt, Operand rt2, Operand rn, int imm)
  202. {
  203. uint instruction = GetLdpStpInstruction(0x29c00000u, 0x2dc00000u, imm, rt.Type);
  204. WriteInstruction(instruction, rt, rn, rt2);
  205. }
  206. public void LdpRiUn(Operand rt, Operand rt2, Operand rn, int imm)
  207. {
  208. uint instruction = GetLdpStpInstruction(0x29400000u, 0x2d400000u, imm, rt.Type);
  209. WriteInstruction(instruction, rt, rn, rt2);
  210. }
  211. public void Ldr(Operand rt, Operand rn)
  212. {
  213. if (rn.Kind == OperandKind.Memory)
  214. {
  215. MemoryOperand memOp = rn.GetMemory();
  216. if (memOp.Index != default)
  217. {
  218. Debug.Assert(memOp.Displacement == 0);
  219. Debug.Assert(memOp.Scale == Multiplier.x1 || (int)memOp.Scale == GetScaleForType(rt.Type));
  220. LdrRr(rt, memOp.BaseAddress, memOp.Index, ArmExtensionType.Uxtx, memOp.Scale != Multiplier.x1);
  221. }
  222. else
  223. {
  224. LdrRiUn(rt, memOp.BaseAddress, memOp.Displacement);
  225. }
  226. }
  227. else
  228. {
  229. LdrRiUn(rt, rn, 0);
  230. }
  231. }
  232. public void LdrLit(Operand rt, int offset)
  233. {
  234. uint instruction = 0x18000000u | (EncodeSImm19_2(offset) << 5);
  235. if (rt.Type == OperandType.I64)
  236. {
  237. instruction |= 1u << 30;
  238. }
  239. WriteInstruction(instruction, rt);
  240. }
  241. public void LdrRiPost(Operand rt, Operand rn, int imm)
  242. {
  243. uint instruction = GetLdrStrInstruction(0xb8400400u, 0x3c400400u, rt.Type) | (EncodeSImm9(imm) << 12);
  244. WriteInstruction(instruction, rt, rn);
  245. }
  246. public void LdrRiPre(Operand rt, Operand rn, int imm)
  247. {
  248. uint instruction = GetLdrStrInstruction(0xb8400c00u, 0x3c400c00u, rt.Type) | (EncodeSImm9(imm) << 12);
  249. WriteInstruction(instruction, rt, rn);
  250. }
  251. public void LdrRiUn(Operand rt, Operand rn, int imm)
  252. {
  253. uint instruction = GetLdrStrInstruction(0xb9400000u, 0x3d400000u, rt.Type) | (EncodeUImm12(imm, rt.Type) << 10);
  254. WriteInstruction(instruction, rt, rn);
  255. }
  256. public void LdrRr(Operand rt, Operand rn, Operand rm, ArmExtensionType extensionType, bool shift)
  257. {
  258. uint instruction = GetLdrStrInstruction(0xb8600800u, 0x3ce00800u, rt.Type);
  259. WriteInstructionLdrStrAuto(instruction, rt, rn, rm, extensionType, shift);
  260. }
  261. public void LdrbRiPost(Operand rt, Operand rn, int imm)
  262. {
  263. uint instruction = 0x38400400u | (EncodeSImm9(imm) << 12);
  264. WriteInstruction(instruction, rt, rn);
  265. }
  266. public void LdrbRiPre(Operand rt, Operand rn, int imm)
  267. {
  268. uint instruction = 0x38400c00u | (EncodeSImm9(imm) << 12);
  269. WriteInstruction(instruction, rt, rn);
  270. }
  271. public void LdrbRiUn(Operand rt, Operand rn, int imm)
  272. {
  273. uint instruction = 0x39400000u | (EncodeUImm12(imm, 0) << 10);
  274. WriteInstruction(instruction, rt, rn);
  275. }
  276. public void LdrhRiPost(Operand rt, Operand rn, int imm)
  277. {
  278. uint instruction = 0x78400400u | (EncodeSImm9(imm) << 12);
  279. WriteInstruction(instruction, rt, rn);
  280. }
  281. public void LdrhRiPre(Operand rt, Operand rn, int imm)
  282. {
  283. uint instruction = 0x78400c00u | (EncodeSImm9(imm) << 12);
  284. WriteInstruction(instruction, rt, rn);
  285. }
  286. public void LdrhRiUn(Operand rt, Operand rn, int imm)
  287. {
  288. uint instruction = 0x79400000u | (EncodeUImm12(imm, 1) << 10);
  289. WriteInstruction(instruction, rt, rn);
  290. }
  291. public void Ldur(Operand rt, Operand rn, int imm)
  292. {
  293. uint instruction = GetLdrStrInstruction(0xb8400000u, 0x3c400000u, rt.Type) | (EncodeSImm9(imm) << 12);
  294. WriteInstruction(instruction, rt, rn);
  295. }
  296. public void Lsl(Operand rd, Operand rn, Operand rm)
  297. {
  298. if (rm.Kind == OperandKind.Constant)
  299. {
  300. int shift = rm.AsInt32();
  301. int mask = rd.Type == OperandType.I64 ? 63 : 31;
  302. shift &= mask;
  303. Ubfm(rd, rn, -shift & mask, mask - shift);
  304. }
  305. else
  306. {
  307. Lslv(rd, rn, rm);
  308. }
  309. }
  310. public void Lslv(Operand rd, Operand rn, Operand rm)
  311. {
  312. WriteInstructionBitwiseAuto(0x1ac02000u, rd, rn, rm);
  313. }
  314. public void Lsr(Operand rd, Operand rn, Operand rm)
  315. {
  316. if (rm.Kind == OperandKind.Constant)
  317. {
  318. int shift = rm.AsInt32();
  319. int mask = rd.Type == OperandType.I64 ? 63 : 31;
  320. shift &= mask;
  321. Ubfm(rd, rn, shift, mask);
  322. }
  323. else
  324. {
  325. Lsrv(rd, rn, rm);
  326. }
  327. }
  328. public void Lsrv(Operand rd, Operand rn, Operand rm)
  329. {
  330. WriteInstructionBitwiseAuto(0x1ac02400u, rd, rn, rm);
  331. }
  332. public void Madd(Operand rd, Operand rn, Operand rm, Operand ra)
  333. {
  334. WriteInstructionAuto(0x1b000000u, rd, rn, rm, ra);
  335. }
  336. public void Mul(Operand rd, Operand rn, Operand rm)
  337. {
  338. Madd(rd, rn, rm, Factory.Register(ZrRegister, RegisterType.Integer, rd.Type));
  339. }
  340. public void Mov(Operand rd, Operand rn)
  341. {
  342. if (rd.Type.IsInteger())
  343. {
  344. Orr(rd, Factory.Register(ZrRegister, RegisterType.Integer, rd.Type), rn);
  345. }
  346. else
  347. {
  348. OrrVector(rd, rn, rn);
  349. }
  350. }
  351. public void MovSp(Operand rd, Operand rn)
  352. {
  353. if (rd.GetRegister().Index == SpRegister ||
  354. rn.GetRegister().Index == SpRegister)
  355. {
  356. Add(rd, rn, Factory.Const(rd.Type, 0), immForm: true);
  357. }
  358. else
  359. {
  360. Mov(rd, rn);
  361. }
  362. }
  363. public void Mov(Operand rd, int imm)
  364. {
  365. Movz(rd, imm, 0);
  366. }
  367. public void Movz(Operand rd, int imm, int hw)
  368. {
  369. Debug.Assert((hw & (rd.Type == OperandType.I64 ? 3 : 1)) == hw);
  370. WriteInstructionAuto(0x52800000u | (EncodeUImm16(imm) << 5) | ((uint)hw << 21), rd);
  371. }
  372. public void Movk(Operand rd, int imm, int hw)
  373. {
  374. Debug.Assert((hw & (rd.Type == OperandType.I64 ? 3 : 1)) == hw);
  375. WriteInstructionAuto(0x72800000u | (EncodeUImm16(imm) << 5) | ((uint)hw << 21), rd);
  376. }
  377. public void Mrs(Operand rt, uint o0, uint op1, uint crn, uint crm, uint op2)
  378. {
  379. uint instruction = 0xd5300000u;
  380. instruction |= (op2 & 7) << 5;
  381. instruction |= (crm & 15) << 8;
  382. instruction |= (crn & 15) << 12;
  383. instruction |= (op1 & 7) << 16;
  384. instruction |= (o0 & 1) << 19;
  385. WriteInstruction(instruction, rt);
  386. }
  387. public void Mvn(Operand rd, Operand rn, ArmShiftType shiftType = ArmShiftType.Lsl, int shiftAmount = 0)
  388. {
  389. Orn(rd, Factory.Register(ZrRegister, RegisterType.Integer, rd.Type), rn, shiftType, shiftAmount);
  390. }
  391. public void Neg(Operand rd, Operand rn, ArmShiftType shiftType = ArmShiftType.Lsl, int shiftAmount = 0)
  392. {
  393. Sub(rd, Factory.Register(ZrRegister, RegisterType.Integer, rd.Type), rn, shiftType, shiftAmount);
  394. }
  395. public void Orn(Operand rd, Operand rn, Operand rm, ArmShiftType shiftType = ArmShiftType.Lsl, int shiftAmount = 0)
  396. {
  397. WriteInstructionBitwiseAuto(0x2a200000u, rd, rn, rm, shiftType, shiftAmount);
  398. }
  399. public void Orr(Operand rd, Operand rn, Operand rm, ArmShiftType shiftType = ArmShiftType.Lsl, int shiftAmount = 0)
  400. {
  401. WriteInstructionBitwiseAuto(0x32000000u, 0x2a000000u, rd, rn, rm, shiftType, shiftAmount);
  402. }
  403. public void OrrVector(Operand rd, Operand rn, Operand rm, bool q = true)
  404. {
  405. WriteSimdInstruction(0x0ea01c00u, rd, rn, rm, q);
  406. }
  407. public void Ret(Operand rn)
  408. {
  409. WriteUInt32(0xd65f0000u | (EncodeReg(rn) << 5));
  410. }
  411. public void Rev(Operand rd, Operand rn)
  412. {
  413. uint opc0 = rd.Type == OperandType.I64 ? 1u << 10 : 0u;
  414. WriteInstructionAuto(0x5ac00800u | opc0, rd, rn);
  415. }
  416. public void Ror(Operand rd, Operand rn, Operand rm)
  417. {
  418. if (rm.Kind == OperandKind.Constant)
  419. {
  420. int shift = rm.AsInt32();
  421. int mask = rd.Type == OperandType.I64 ? 63 : 31;
  422. shift &= mask;
  423. Extr(rd, rn, rn, shift);
  424. }
  425. else
  426. {
  427. Rorv(rd, rn, rm);
  428. }
  429. }
  430. public void Rorv(Operand rd, Operand rn, Operand rm)
  431. {
  432. WriteInstructionBitwiseAuto(0x1ac02c00u, rd, rn, rm);
  433. }
  434. public void Sbfm(Operand rd, Operand rn, int immr, int imms)
  435. {
  436. uint n = rd.Type == OperandType.I64 ? 1u << 22 : 0u;
  437. WriteInstructionAuto(0x13000000u | n | (EncodeUImm6(imms) << 10) | (EncodeUImm6(immr) << 16), rd, rn);
  438. }
  439. public void ScvtfScalar(Operand rd, Operand rn)
  440. {
  441. uint instruction = 0x1e220000u;
  442. if (rn.Type == OperandType.I64)
  443. {
  444. instruction |= SfFlag;
  445. }
  446. WriteFPInstructionAuto(instruction, rd, rn);
  447. }
  448. public void Sdiv(Operand rd, Operand rn, Operand rm)
  449. {
  450. WriteInstructionRm16Auto(0x1ac00c00u, rd, rn, rm);
  451. }
  452. public void Smulh(Operand rd, Operand rn, Operand rm)
  453. {
  454. WriteInstructionRm16(0x9b407c00u, rd, rn, rm);
  455. }
  456. public void Stlxp(Operand rt, Operand rt2, Operand rn, Operand rs)
  457. {
  458. WriteInstruction(0x88208000u | ((rt.Type == OperandType.I64 ? 3u : 2u) << 30), rt, rn, rs, rt2);
  459. }
  460. public void Stlxr(Operand rt, Operand rn, Operand rs)
  461. {
  462. WriteInstructionRm16(0x0800fc00u | ((rt.Type == OperandType.I64 ? 3u : 2u) << 30), rt, rn, rs);
  463. }
  464. public void Stlxrb(Operand rt, Operand rn, Operand rs)
  465. {
  466. WriteInstructionRm16(0x0800fc00u, rt, rn, rs);
  467. }
  468. public void Stlxrh(Operand rt, Operand rn, Operand rs)
  469. {
  470. WriteInstructionRm16(0x0800fc00u | (1u << 30), rt, rn, rs);
  471. }
  472. public void StpRiPost(Operand rt, Operand rt2, Operand rn, int imm)
  473. {
  474. uint instruction = GetLdpStpInstruction(0x28800000u, 0x2c800000u, imm, rt.Type);
  475. WriteInstruction(instruction, rt, rn, rt2);
  476. }
  477. public void StpRiPre(Operand rt, Operand rt2, Operand rn, int imm)
  478. {
  479. uint instruction = GetLdpStpInstruction(0x29800000u, 0x2d800000u, imm, rt.Type);
  480. WriteInstruction(instruction, rt, rn, rt2);
  481. }
  482. public void StpRiUn(Operand rt, Operand rt2, Operand rn, int imm)
  483. {
  484. uint instruction = GetLdpStpInstruction(0x29000000u, 0x2d000000u, imm, rt.Type);
  485. WriteInstruction(instruction, rt, rn, rt2);
  486. }
  487. public void Str(Operand rt, Operand rn)
  488. {
  489. if (rn.Kind == OperandKind.Memory)
  490. {
  491. MemoryOperand memOp = rn.GetMemory();
  492. if (memOp.Index != default)
  493. {
  494. Debug.Assert(memOp.Displacement == 0);
  495. Debug.Assert(memOp.Scale == Multiplier.x1 || (int)memOp.Scale == GetScaleForType(rt.Type));
  496. StrRr(rt, memOp.BaseAddress, memOp.Index, ArmExtensionType.Uxtx, memOp.Scale != Multiplier.x1);
  497. }
  498. else
  499. {
  500. StrRiUn(rt, memOp.BaseAddress, memOp.Displacement);
  501. }
  502. }
  503. else
  504. {
  505. StrRiUn(rt, rn, 0);
  506. }
  507. }
  508. public void StrRiPost(Operand rt, Operand rn, int imm)
  509. {
  510. uint instruction = GetLdrStrInstruction(0xb8000400u, 0x3c000400u, rt.Type) | (EncodeSImm9(imm) << 12);
  511. WriteInstruction(instruction, rt, rn);
  512. }
  513. public void StrRiPre(Operand rt, Operand rn, int imm)
  514. {
  515. uint instruction = GetLdrStrInstruction(0xb8000c00u, 0x3c000c00u, rt.Type) | (EncodeSImm9(imm) << 12);
  516. WriteInstruction(instruction, rt, rn);
  517. }
  518. public void StrRiUn(Operand rt, Operand rn, int imm)
  519. {
  520. uint instruction = GetLdrStrInstruction(0xb9000000u, 0x3d000000u, rt.Type) | (EncodeUImm12(imm, rt.Type) << 10);
  521. WriteInstruction(instruction, rt, rn);
  522. }
  523. public void StrRr(Operand rt, Operand rn, Operand rm, ArmExtensionType extensionType, bool shift)
  524. {
  525. uint instruction = GetLdrStrInstruction(0xb8200800u, 0x3ca00800u, rt.Type);
  526. WriteInstructionLdrStrAuto(instruction, rt, rn, rm, extensionType, shift);
  527. }
  528. public void StrbRiPost(Operand rt, Operand rn, int imm)
  529. {
  530. uint instruction = 0x38000400u | (EncodeSImm9(imm) << 12);
  531. WriteInstruction(instruction, rt, rn);
  532. }
  533. public void StrbRiPre(Operand rt, Operand rn, int imm)
  534. {
  535. uint instruction = 0x38000c00u | (EncodeSImm9(imm) << 12);
  536. WriteInstruction(instruction, rt, rn);
  537. }
  538. public void StrbRiUn(Operand rt, Operand rn, int imm)
  539. {
  540. uint instruction = 0x39000000u | (EncodeUImm12(imm, 0) << 10);
  541. WriteInstruction(instruction, rt, rn);
  542. }
  543. public void StrhRiPost(Operand rt, Operand rn, int imm)
  544. {
  545. uint instruction = 0x78000400u | (EncodeSImm9(imm) << 12);
  546. WriteInstruction(instruction, rt, rn);
  547. }
  548. public void StrhRiPre(Operand rt, Operand rn, int imm)
  549. {
  550. uint instruction = 0x78000c00u | (EncodeSImm9(imm) << 12);
  551. WriteInstruction(instruction, rt, rn);
  552. }
  553. public void StrhRiUn(Operand rt, Operand rn, int imm)
  554. {
  555. uint instruction = 0x79000000u | (EncodeUImm12(imm, 1) << 10);
  556. WriteInstruction(instruction, rt, rn);
  557. }
  558. public void Stur(Operand rt, Operand rn, int imm)
  559. {
  560. uint instruction = GetLdrStrInstruction(0xb8000000u, 0x3c000000u, rt.Type) | (EncodeSImm9(imm) << 12);
  561. WriteInstruction(instruction, rt, rn);
  562. }
  563. public void Sub(Operand rd, Operand rn, Operand rm, ArmExtensionType extensionType, int shiftAmount = 0)
  564. {
  565. WriteInstructionAuto(0x4b200000u, rd, rn, rm, extensionType, shiftAmount);
  566. }
  567. public void Sub(Operand rd, Operand rn, Operand rm, ArmShiftType shiftType = ArmShiftType.Lsl, int shiftAmount = 0)
  568. {
  569. WriteInstructionAuto(0x51000000u, 0x4b000000u, rd, rn, rm, shiftType, shiftAmount);
  570. }
  571. public void Subs(Operand rd, Operand rn, Operand rm, ArmShiftType shiftType = ArmShiftType.Lsl, int shiftAmount = 0)
  572. {
  573. WriteInstructionAuto(0x71000000u, 0x6b000000u, rd, rn, rm, shiftType, shiftAmount);
  574. }
  575. public void Sxtb(Operand rd, Operand rn)
  576. {
  577. Sbfm(rd, rn, 0, 7);
  578. }
  579. public void Sxth(Operand rd, Operand rn)
  580. {
  581. Sbfm(rd, rn, 0, 15);
  582. }
  583. public void Sxtw(Operand rd, Operand rn)
  584. {
  585. Sbfm(rd, rn, 0, 31);
  586. }
  587. public void Tst(Operand rn, Operand rm, ArmShiftType shiftType = ArmShiftType.Lsl, int shiftAmount = 0)
  588. {
  589. Ands(Factory.Register(ZrRegister, RegisterType.Integer, rn.Type), rn, rm, shiftType, shiftAmount);
  590. }
  591. public void Ubfm(Operand rd, Operand rn, int immr, int imms)
  592. {
  593. uint n = rd.Type == OperandType.I64 ? 1u << 22 : 0u;
  594. WriteInstructionAuto(0x53000000u | n | (EncodeUImm6(imms) << 10) | (EncodeUImm6(immr) << 16), rd, rn);
  595. }
  596. public void UcvtfScalar(Operand rd, Operand rn)
  597. {
  598. uint instruction = 0x1e230000u;
  599. if (rn.Type == OperandType.I64)
  600. {
  601. instruction |= SfFlag;
  602. }
  603. WriteFPInstructionAuto(instruction, rd, rn);
  604. }
  605. public void Udiv(Operand rd, Operand rn, Operand rm)
  606. {
  607. WriteInstructionRm16Auto(0x1ac00800u, rd, rn, rm);
  608. }
  609. public void Umov(Operand rd, Operand rn, int index, int size)
  610. {
  611. uint q = size == 3 ? 1u << 30 : 0u;
  612. WriteInstruction(0x0e003c00u | (EncodeIndexSizeImm5(index, size) << 16) | q, rd, rn);
  613. }
  614. public void Umulh(Operand rd, Operand rn, Operand rm)
  615. {
  616. WriteInstructionRm16(0x9bc07c00u, rd, rn, rm);
  617. }
  618. public void Uxtb(Operand rd, Operand rn)
  619. {
  620. Ubfm(rd, rn, 0, 7);
  621. }
  622. public void Uxth(Operand rd, Operand rn)
  623. {
  624. Ubfm(rd, rn, 0, 15);
  625. }
  626. private void WriteInstructionAuto(
  627. uint instI,
  628. uint instR,
  629. Operand rd,
  630. Operand rn,
  631. Operand rm,
  632. ArmShiftType shiftType = ArmShiftType.Lsl,
  633. int shiftAmount = 0,
  634. bool immForm = false)
  635. {
  636. if (rm.Kind == OperandKind.Constant && (rm.Value != 0 || immForm))
  637. {
  638. Debug.Assert(shiftAmount == 0);
  639. int imm = rm.AsInt32();
  640. Debug.Assert((uint)imm == rm.Value);
  641. if (imm != 0 && (imm & 0xfff) == 0)
  642. {
  643. instI |= 1 << 22; // sh flag
  644. imm >>= 12;
  645. }
  646. WriteInstructionAuto(instI | (EncodeUImm12(imm, 0) << 10), rd, rn);
  647. }
  648. else
  649. {
  650. instR |= EncodeUImm6(shiftAmount) << 10;
  651. instR |= (uint)shiftType << 22;
  652. WriteInstructionRm16Auto(instR, rd, rn, rm);
  653. }
  654. }
  655. private void WriteInstructionAuto(
  656. uint instruction,
  657. Operand rd,
  658. Operand rn,
  659. Operand rm,
  660. ArmExtensionType extensionType,
  661. int shiftAmount = 0)
  662. {
  663. Debug.Assert((uint)shiftAmount <= 4);
  664. instruction |= (uint)shiftAmount << 10;
  665. instruction |= (uint)extensionType << 13;
  666. WriteInstructionRm16Auto(instruction, rd, rn, rm);
  667. }
  668. private void WriteInstructionBitwiseAuto(
  669. uint instI,
  670. uint instR,
  671. Operand rd,
  672. Operand rn,
  673. Operand rm,
  674. ArmShiftType shiftType = ArmShiftType.Lsl,
  675. int shiftAmount = 0)
  676. {
  677. if (rm.Kind == OperandKind.Constant && rm.Value != 0)
  678. {
  679. Debug.Assert(shiftAmount == 0);
  680. bool canEncode = CodeGenCommon.TryEncodeBitMask(rm, out int immN, out int immS, out int immR);
  681. Debug.Assert(canEncode);
  682. uint instruction = instI | ((uint)immS << 10) | ((uint)immR << 16) | ((uint)immN << 22);
  683. WriteInstructionAuto(instruction, rd, rn);
  684. }
  685. else
  686. {
  687. WriteInstructionBitwiseAuto(instR, rd, rn, rm, shiftType, shiftAmount);
  688. }
  689. }
  690. private void WriteInstructionBitwiseAuto(
  691. uint instruction,
  692. Operand rd,
  693. Operand rn,
  694. Operand rm,
  695. ArmShiftType shiftType = ArmShiftType.Lsl,
  696. int shiftAmount = 0)
  697. {
  698. if (rd.Type == OperandType.I64)
  699. {
  700. instruction |= SfFlag;
  701. }
  702. instruction |= EncodeUImm6(shiftAmount) << 10;
  703. instruction |= (uint)shiftType << 22;
  704. WriteInstructionRm16(instruction, rd, rn, rm);
  705. }
  706. private void WriteInstructionLdrStrAuto(
  707. uint instruction,
  708. Operand rd,
  709. Operand rn,
  710. Operand rm,
  711. ArmExtensionType extensionType,
  712. bool shift)
  713. {
  714. if (shift)
  715. {
  716. instruction |= 1u << 12;
  717. }
  718. instruction |= (uint)extensionType << 13;
  719. if (rd.Type == OperandType.I64)
  720. {
  721. instruction |= 1u << 30;
  722. }
  723. WriteInstructionRm16(instruction, rd, rn, rm);
  724. }
  725. private void WriteInstructionAuto(uint instruction, Operand rd)
  726. {
  727. if (rd.Type == OperandType.I64)
  728. {
  729. instruction |= SfFlag;
  730. }
  731. WriteInstruction(instruction, rd);
  732. }
  733. public void WriteInstructionAuto(uint instruction, Operand rd, Operand rn)
  734. {
  735. if (rd.Type == OperandType.I64)
  736. {
  737. instruction |= SfFlag;
  738. }
  739. WriteInstruction(instruction, rd, rn);
  740. }
  741. private void WriteInstructionAuto(uint instruction, Operand rd, Operand rn, Operand rm, Operand ra)
  742. {
  743. if (rd.Type == OperandType.I64)
  744. {
  745. instruction |= SfFlag;
  746. }
  747. WriteInstruction(instruction, rd, rn, rm, ra);
  748. }
  749. public void WriteInstruction(uint instruction, Operand rd)
  750. {
  751. WriteUInt32(instruction | EncodeReg(rd));
  752. }
  753. public void WriteInstruction(uint instruction, Operand rd, Operand rn)
  754. {
  755. WriteUInt32(instruction | EncodeReg(rd) | (EncodeReg(rn) << 5));
  756. }
  757. public void WriteInstruction(uint instruction, Operand rd, Operand rn, Operand rm)
  758. {
  759. WriteUInt32(instruction | EncodeReg(rd) | (EncodeReg(rn) << 5) | (EncodeReg(rm) << 10));
  760. }
  761. public void WriteInstruction(uint instruction, Operand rd, Operand rn, Operand rm, Operand ra)
  762. {
  763. WriteUInt32(instruction | EncodeReg(rd) | (EncodeReg(rn) << 5) | (EncodeReg(ra) << 10) | (EncodeReg(rm) << 16));
  764. }
  765. private void WriteFPInstructionAuto(uint instruction, Operand rd, Operand rn)
  766. {
  767. if (rd.Type == OperandType.FP64)
  768. {
  769. instruction |= 1u << 22;
  770. }
  771. WriteUInt32(instruction | EncodeReg(rd) | (EncodeReg(rn) << 5));
  772. }
  773. private void WriteFPInstructionAuto(uint instruction, Operand rd, Operand rn, Operand rm)
  774. {
  775. if (rd.Type == OperandType.FP64)
  776. {
  777. instruction |= 1u << 22;
  778. }
  779. WriteInstructionRm16(instruction, rd, rn, rm);
  780. }
  781. private void WriteSimdInstruction(uint instruction, Operand rd, Operand rn, Operand rm, bool q = true)
  782. {
  783. if (q)
  784. {
  785. instruction |= 1u << 30;
  786. }
  787. WriteInstructionRm16(instruction, rd, rn, rm);
  788. }
  789. private void WriteInstructionRm16Auto(uint instruction, Operand rd, Operand rn, Operand rm)
  790. {
  791. if (rd.Type == OperandType.I64)
  792. {
  793. instruction |= SfFlag;
  794. }
  795. WriteInstructionRm16(instruction, rd, rn, rm);
  796. }
  797. public void WriteInstructionRm16(uint instruction, Operand rd, Operand rn, Operand rm)
  798. {
  799. WriteUInt32(instruction | EncodeReg(rd) | (EncodeReg(rn) << 5) | (EncodeReg(rm) << 16));
  800. }
  801. public void WriteInstructionRm16NoRet(uint instruction, Operand rn, Operand rm)
  802. {
  803. WriteUInt32(instruction | (EncodeReg(rn) << 5) | (EncodeReg(rm) << 16));
  804. }
  805. private static uint GetLdpStpInstruction(uint intInst, uint vecInst, int imm, OperandType type)
  806. {
  807. uint instruction;
  808. int scale;
  809. if (type.IsInteger())
  810. {
  811. instruction = intInst;
  812. if (type == OperandType.I64)
  813. {
  814. instruction |= SfFlag;
  815. scale = 3;
  816. }
  817. else
  818. {
  819. scale = 2;
  820. }
  821. }
  822. else
  823. {
  824. int opc = type switch
  825. {
  826. OperandType.FP32 => 0,
  827. OperandType.FP64 => 1,
  828. _ => 2
  829. };
  830. instruction = vecInst | ((uint)opc << 30);
  831. scale = 2 + opc;
  832. }
  833. instruction |= (EncodeSImm7(imm, scale) << 15);
  834. return instruction;
  835. }
  836. private static uint GetLdrStrInstruction(uint intInst, uint vecInst, OperandType type)
  837. {
  838. uint instruction;
  839. if (type.IsInteger())
  840. {
  841. instruction = intInst;
  842. if (type == OperandType.I64)
  843. {
  844. instruction |= 1 << 30;
  845. }
  846. }
  847. else
  848. {
  849. instruction = vecInst;
  850. if (type == OperandType.V128)
  851. {
  852. instruction |= 1u << 23;
  853. }
  854. else
  855. {
  856. instruction |= type == OperandType.FP32 ? 2u << 30 : 3u << 30;
  857. }
  858. }
  859. return instruction;
  860. }
  861. private static uint EncodeIndexSizeImm5(int index, int size)
  862. {
  863. Debug.Assert((uint)size < 4);
  864. Debug.Assert((uint)index < (16u >> size), $"Invalid index {index} and size {size} combination.");
  865. return ((uint)index << (size + 1)) | (1u << size);
  866. }
  867. private static uint EncodeSImm7(int value, int scale)
  868. {
  869. uint imm = (uint)(value >> scale) & 0x7f;
  870. Debug.Assert(((int)imm << 25) >> (25 - scale) == value, $"Failed to encode constant 0x{value:X} with scale {scale}.");
  871. return imm;
  872. }
  873. private static uint EncodeSImm9(int value)
  874. {
  875. uint imm = (uint)value & 0x1ff;
  876. Debug.Assert(((int)imm << 23) >> 23 == value, $"Failed to encode constant 0x{value:X}.");
  877. return imm;
  878. }
  879. private static uint EncodeSImm19_2(int value)
  880. {
  881. uint imm = (uint)(value >> 2) & 0x7ffff;
  882. Debug.Assert(((int)imm << 13) >> 11 == value, $"Failed to encode constant 0x{value:X}.");
  883. return imm;
  884. }
  885. private static uint EncodeSImm26_2(int value)
  886. {
  887. uint imm = (uint)(value >> 2) & 0x3ffffff;
  888. Debug.Assert(((int)imm << 6) >> 4 == value, $"Failed to encode constant 0x{value:X}.");
  889. return imm;
  890. }
  891. private static uint EncodeUImm4(int value)
  892. {
  893. uint imm = (uint)value & 0xf;
  894. Debug.Assert((int)imm == value, $"Failed to encode constant 0x{value:X}.");
  895. return imm;
  896. }
  897. private static uint EncodeUImm6(int value)
  898. {
  899. uint imm = (uint)value & 0x3f;
  900. Debug.Assert((int)imm == value, $"Failed to encode constant 0x{value:X}.");
  901. return imm;
  902. }
  903. private static uint EncodeUImm12(int value, OperandType type)
  904. {
  905. return EncodeUImm12(value, GetScaleForType(type));
  906. }
  907. private static uint EncodeUImm12(int value, int scale)
  908. {
  909. uint imm = (uint)(value >> scale) & 0xfff;
  910. Debug.Assert((int)imm << scale == value, $"Failed to encode constant 0x{value:X} with scale {scale}.");
  911. return imm;
  912. }
  913. private static uint EncodeUImm16(int value)
  914. {
  915. uint imm = (uint)value & 0xffff;
  916. Debug.Assert((int)imm == value, $"Failed to encode constant 0x{value:X}.");
  917. return imm;
  918. }
  919. private static uint EncodeReg(Operand reg)
  920. {
  921. if (reg.Kind == OperandKind.Constant && reg.Value == 0)
  922. {
  923. return ZrRegister;
  924. }
  925. uint regIndex = (uint)reg.GetRegister().Index;
  926. Debug.Assert(reg.Kind == OperandKind.Register);
  927. Debug.Assert(regIndex < 32);
  928. return regIndex;
  929. }
  930. public static int GetScaleForType(OperandType type)
  931. {
  932. return type switch
  933. {
  934. OperandType.I32 => 2,
  935. OperandType.I64 => 3,
  936. OperandType.FP32 => 2,
  937. OperandType.FP64 => 3,
  938. OperandType.V128 => 4,
  939. _ => throw new ArgumentException($"Invalid type {type}.")
  940. };
  941. }
  942. private void WriteInt16(short value)
  943. {
  944. WriteUInt16((ushort)value);
  945. }
  946. private void WriteInt32(int value)
  947. {
  948. WriteUInt32((uint)value);
  949. }
  950. private void WriteByte(byte value)
  951. {
  952. _stream.WriteByte(value);
  953. }
  954. private void WriteUInt16(ushort value)
  955. {
  956. _stream.WriteByte((byte)(value >> 0));
  957. _stream.WriteByte((byte)(value >> 8));
  958. }
  959. private void WriteUInt32(uint value)
  960. {
  961. _stream.WriteByte((byte)(value >> 0));
  962. _stream.WriteByte((byte)(value >> 8));
  963. _stream.WriteByte((byte)(value >> 16));
  964. _stream.WriteByte((byte)(value >> 24));
  965. }
  966. }
  967. }