Assembly.h 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956
  1. #pragma once
  2. #include <vector>
  3. #include "Array.h"
  4. #include "Text.h"
  5. #include "Writer.h"
  6. namespace Framework
  7. {
  8. namespace Assembly
  9. {
  10. enum Operation
  11. {
  12. // no real operation, used for labels
  13. NOP,
  14. // Arithmetic Operations
  15. ADD, // Addition
  16. ADDPD, // Add Packed Double-Precision Floating-Point Values
  17. ADDPS, // Add Packed Single-Precision Floating-Point Values
  18. ADDSD, // Add Scalar Double-Precision Floating-Point Values
  19. ADDSS, // Add Scalar Single-Precision Floating-Point Values
  20. SUB, // Subtraction
  21. SUBPD, // Subtract Packed Double-Precision Floating-Point Values
  22. SUBPS, // Subtract Packed Single-Precision Floating-Point Values
  23. SUBSD, // Subtract Scalar Double-Precision Floating-Point Values
  24. SUBSS, // Subtract Scalar Single-Precision Floating-Point Values
  25. MUL, // Multiply unsigned
  26. IMUL, // Multiply signed
  27. MULPD, // Multiply Packed Double Precision Floating-Point Values
  28. MULPS, // Multiply Packed Single Precision Floating-Point Values
  29. MULSD, // Multiply Scalar Double Precision Floating-Point Value
  30. MULSS, // Multiply Scalar Single Precision Floating-Point Values
  31. DIV, // Division unsigned
  32. IDIV, // Division signed
  33. DIVPD, // Divide Packed Double-Precision Floating-Point Values
  34. DIVPS, // Divide Packed Single-Precision Floating-Point Values
  35. DIVSD, // Divide Scalar Double-Precision Floating-Point Values
  36. DIVSS, // Divide Scalar Single-Precision Floating-Point Values
  37. NEG, // Negation
  38. INC, // Increment
  39. // Logical Operations
  40. AND, // Bitwise AND
  41. OR, // Bitwise OR
  42. XOR, // Bitwise XOR
  43. NOT, // Bitwise NOT
  44. // Comparison Operations
  45. // Bitwise AND without storing the result. only
  46. // SpecialRegister.FLAGS (SF, ZF, PF) is affected
  47. TEST,
  48. // Compare
  49. // temporary subtracts op2 from op without storing the result. only
  50. // SpecialRegister.FLAGS is affected
  51. CMP,
  52. // Compare Packed Double Precision Floating-Point Values
  53. // temporary subtracts op2 from op without storing the result. only
  54. // SpecialRegister.FLAGS is affected
  55. CMPPD,
  56. // Compare Packed Single Precision Floating-Point Values
  57. // temporary subtracts op2 from op without storing the result. only
  58. // SpecialRegister.FLAGS is affected
  59. CMPPS,
  60. // Compare Scalar Double Precision Floating-Point Value
  61. // temporary subtracts op2 from op without storing the result. only
  62. // SpecialRegister.FLAGS is affected
  63. CMPSD,
  64. // Compare Scalar Single Precision Floating-Point Value
  65. // temporary subtracts op2 from op without storing the result. only
  66. // SpecialRegister.FLAGS is affected
  67. CMPSS,
  68. // Data Movement
  69. MOV, // Move data from source to destination
  70. // Move Aligned Packed Double-Precision Floating-Point Value
  71. MOVAPD,
  72. // Move Aligned Packed Single-Precision Floating-Point Value
  73. MOVAPS,
  74. MOVSD, // Move Scalar Double-Precision Floating-Point Value
  75. MOVSS, // Move Scalar Single-Precision Floating-Point Value
  76. LEA, // Load Effective Address
  77. // Control Flow
  78. JMP, // Unconditional Jump
  79. JZ, // Jump if Zero: SpecialRegister.FLAGS(ZF) = 1
  80. JNZ, // Jump if Not Zero: SpecialRegister.FLAGS(ZF) = 0
  81. // Jump if Greater: SpecialRegister.FLAGS(SF) =
  82. // SpecialRegister.FLAGS(OF) and SpecialRegister.FLAGS(ZF) = 0
  83. JG,
  84. // Jump if Greater or Equal: SpecialRegister.FLAGS(SF) =
  85. // SpecialRegister.FLAGS(OF)
  86. JGE,
  87. // Jump if Less: SpecialRegister.FLAGS(SF) !=
  88. // SpecialRegister.FLAGS(OF)
  89. JL,
  90. // Jump if Less or Equal: SpecialRegister.FLAGS(SF) !=
  91. // SpecialRegister.FLAGS(OF) or SpecialRegister.FLAGS(ZF) = 1
  92. JLE,
  93. // Jump if above: SpecialRegister.FLAGS(CF) = 0 and
  94. // SpecialRegister.FLAGS(ZF) = 0
  95. JA,
  96. // Jump if carry: SpecialRegister.FLAGS(CF) = 1
  97. JC,
  98. // Jump if not carry: SpecialRegister.FLAGS(CF) = 0
  99. JNC,
  100. // Jump if below or equal: SpecialRegister.FLAGS(CF) = 1 or
  101. // SpecialRegister.FLAGS(ZF) = 1
  102. JBE,
  103. JO, // Jump if overflow: SpecialRegister.FLAGS(OF) = 1
  104. JNO, // Jump if not overflow: SpecialRegister.FLAGS(OF) = 0
  105. JP, // Jump if parity even: SpecialRegister.FLAGS(PF) = 1
  106. JNP, // Jump if not parity odd: SpecialRegister.FLAGS(PF) = 0
  107. JS, // Jump if sign: SpecialRegister.FLAGS(SF) = 1
  108. JNS, // Jump if not sign: SpecialRegister.FLAGS(SF) = 0
  109. CALL, // Call subroutine
  110. ENTER, // Set up stack frame for procedure
  111. LEAVE, // Destroy stack frame for procedure
  112. RET, // Return from subroutine
  113. // Stack Operations
  114. PUSH, // Push onto stack
  115. POP // Pop from stack
  116. };
  117. enum CMP_IMM8
  118. {
  119. EQ_OQ = 0, // Equal (ordered, non-signaling)
  120. LT_OS = 1, // Less than (ordered, signaling)
  121. LE_OS = 2, // Less than or equal (ordered, signaling
  122. UNORD_Q = 3, // Unordered (non-signaling)
  123. NEQ_UQ = 4, // Not-equal (unordered, non-signaling)
  124. NLT_US = 5, // Not less than (unordered, signaling)
  125. NLE_US = 6, // Not-less-than-or-equal (unordered, signaling)
  126. ORD_Q = 7, // Ordered (non-signaling)
  127. EQ_US = 8, // Equal (unordered, signaling)
  128. NGE_US = 9, // Not-greater-than-or-equal (unordered, signaling)
  129. NGT_US = 10, // Not-greater-than (unordered, signaling)
  130. FALSE_OQ = 11, // False (ordered, non-signaling)
  131. NEQ_OQ = 12, // Not-equal (ordered, non-signaling)
  132. GE_OS = 13, // Greater-than-or-equal (ordered, signaling)
  133. GT_OS = 14, // Greater-than (ordered, signaling)
  134. TRUE_UQ = 15, // True (unordered, non-signaling)
  135. EQ_OS = 16, // Equal (ordered, signaling)
  136. LT_OQ = 17, // Less-than (ordered, non-signaling)
  137. LE_OQ = 18, // Less-than-or-equal (ordered, non
  138. UNORD_S = 19, // Unordered (signaling)
  139. NEQ_US = 20, // Not-equal (unordered, signaling)
  140. NLT_UQ = 21, // Not-less-than (unordered, non-sign
  141. NLE_UQ = 22, // Not-less-than-or-equal (unordered, non-signaling)
  142. ORD_S = 23, // Ordered (signaling)
  143. EQ_UQ = 24, // Equal (unordered, non-signaling)
  144. NGE_UQ = 25, // Not-greater-than-or-equal (
  145. NGT_UQ = 26, // Not-greater-than (unordered, non-signaling)
  146. FALSE_OS = 27, // False (ordered, signaling)
  147. NEQ_OS = 28, // Not-equal (ordered, signaling)
  148. GE_OQ = 29, // Greater-than-or-equal (ordered, non
  149. GT_OQ = 30, // Greater-than (ordered, non-signaling)
  150. TRUE_S = 31 // True (signaling)
  151. };
  152. enum FPDataType
  153. {
  154. SINGLE_FLOAT,
  155. SINGLE_DOUBLE,
  156. PACKED_FLOAT,
  157. PACKED_DOUBLE
  158. };
  159. // General Purpose Registers
  160. enum GPRegister
  161. {
  162. // volatile register (can be altered by a function call)
  163. RAX = 0b0000,
  164. // non-volatile register (mus be restored on return)
  165. RBX = 0b0011,
  166. // volatile register (can be altered by a function call)
  167. RCX = 0b0001,
  168. // volatile register (can be altered by a function call)
  169. RDX = 0b0010,
  170. // Stack pointer points to the position of the last item that was
  171. // pushed to the stack. The stack grows downwards so lower means
  172. // more elements in the stack. needs to be aligned to 16 bytes
  173. RSP = 0b0100,
  174. // base pointer points to the base of the current stack frame
  175. // non-volatile register (mus be restored on return)
  176. RBP = 0b0101,
  177. // non-volatile register (mus be restored on return)
  178. RSI = 0b0110,
  179. // non-volatile register (mus be restored on return)
  180. RDI = 0b0111,
  181. // volatile register (can be altered by a function call)
  182. R8 = 0b1000,
  183. // volatile register (can be altered by a function call)
  184. R9 = 0b1001,
  185. // volatile register (can be altered by a function call)
  186. R10 = 0b1010,
  187. // volatile register (can be altered by a function call)
  188. R11 = 0b1011,
  189. // non-volatile register (mus be restored on return)
  190. R12 = 0b1100,
  191. // non-volatile register (mus be restored on return)
  192. R13 = 0b1101,
  193. // non-volatile register (mus be restored on return)
  194. R14 = 0b1110,
  195. // non-volatile register (mus be restored on return)
  196. R15 = 0b1111
  197. };
  198. enum SpecialRegister
  199. {
  200. // Instruction pointer points to the instruction that is executed
  201. // next
  202. RIP,
  203. /**
  204. only lower 16 bits are used:
  205. - CF: Carry Flag
  206. - PF: Parity Flag (1 if an even number of bits was set to 1 in
  207. the result of the last operation)
  208. - AF: Adjust Flag
  209. - ZF: Zero Flag (1 if the result of the last operation was zero)
  210. - SF: Sign Flag (1 if the result of the last operation was a
  211. positive number)
  212. - TF: Trap Flag
  213. - IF: Interrupt Flag
  214. - DF: Direction Flag
  215. - OF: Overflow Flag
  216. */
  217. FLAGS,
  218. };
  219. /**
  220. floating point registers
  221. */
  222. enum FPRegister
  223. {
  224. MM0,
  225. MM1,
  226. MM2,
  227. MM3,
  228. MM4,
  229. MM5,
  230. MM6,
  231. MM7,
  232. MM8,
  233. MM9,
  234. MM10,
  235. MM11,
  236. MM12,
  237. MM13,
  238. MM14,
  239. MM15,
  240. __FP_REGISTER_COUNT
  241. };
  242. /**
  243. describes the bits of the specified register that should be used.
  244. */
  245. enum GPRegisterPart
  246. {
  247. LOWER8,
  248. HIGHER8,
  249. LOWER16,
  250. LOWER32,
  251. FULL64
  252. };
  253. /**
  254. describes the bits of the specified register that should be used.
  255. */
  256. enum FPRegisterPart
  257. {
  258. X,
  259. Y,
  260. // Z
  261. };
  262. class AssemblyBlock;
  263. class GPRegisterArgument;
  264. class FPRegisterArgument;
  265. class MemoryAccessArgument;
  266. class ConstantArgument;
  267. class JumpTargetArgument;
  268. /**
  269. An argument for an Instruction.
  270. */
  271. class OperationArgument
  272. {
  273. private:
  274. public:
  275. /**
  276. * checks if a register is used in this argument.
  277. *
  278. * \param reg the register to check
  279. * \return true if the register is used
  280. */
  281. DLLEXPORT virtual bool usesRegister(GPRegister reg) const;
  282. /**
  283. * checks if a register is used in this argument.
  284. *
  285. * \param reg the register to check
  286. * \return true if the register is used
  287. */
  288. DLLEXPORT virtual bool usesRegister(FPRegister reg) const;
  289. /**
  290. * replaces a register with another register.
  291. *
  292. * \param oldReg the register to replace
  293. * \param newReg the register to use instead
  294. */
  295. DLLEXPORT virtual void replaceRegister(
  296. GPRegister oldReg, GPRegister newReg);
  297. /**
  298. * replaces a register with another register.
  299. *
  300. * \param oldReg the register to replace
  301. * \param newReg the register to use instead
  302. */
  303. DLLEXPORT virtual void replaceRegister(
  304. FPRegister oldReg, FPRegister newReg);
  305. /**
  306. * adds a prefix to all jump labels in this argument to avoid
  307. * conflicts if the assembly block that contains this argument is
  308. * inlined into another block.
  309. *
  310. * \param labelPrefix the label prefix to add
  311. */
  312. DLLEXPORT virtual void addJumpLabelPrefix(Text labelPrefix);
  313. /**
  314. * \return the GPRegisterArgument or 0 if it is not a
  315. * GPRegisterArgument
  316. */
  317. DLLEXPORT const GPRegisterArgument* asGPRegisterArgument() const;
  318. /**
  319. * \return the GPRegisterArgument or 0 if it is not a
  320. * GPRegisterArgument
  321. */
  322. DLLEXPORT const MemoryAccessArgument*
  323. asMemoryAccessArgument() const;
  324. /**
  325. * \return the ConstantArgument or 0 if it is not a
  326. * ConstantArgument
  327. */
  328. DLLEXPORT const ConstantArgument* asConstantArgument() const;
  329. /**
  330. * \return the FPRegisterArgument or 0 if it is not a
  331. * FPRegisterArgument
  332. */
  333. DLLEXPORT const FPRegisterArgument* asFPRegisterArgument() const;
  334. /**
  335. * \return the JumpTargetArgument or 0 if it is not a
  336. * JumpTargetArgument
  337. */
  338. DLLEXPORT const JumpTargetArgument* asJumpTargetArgument() const;
  339. };
  340. /**
  341. Represents the usage of a GPRegister as an Instruction Argument.
  342. */
  343. class GPRegisterArgument : public OperationArgument
  344. {
  345. private:
  346. GPRegister reg;
  347. GPRegisterPart part;
  348. public:
  349. DLLEXPORT GPRegisterArgument(
  350. GPRegister reg, GPRegisterPart part = GPRegisterPart::FULL64);
  351. DLLEXPORT bool usesRegister(GPRegister reg) const override;
  352. DLLEXPORT void replaceRegister(
  353. GPRegister oldReg, GPRegister newReg) override;
  354. DLLEXPORT GPRegister getRegister() const;
  355. DLLEXPORT GPRegisterPart getPart() const;
  356. };
  357. /**
  358. Represents the usage of a FPRegister as an Instruction Argument.
  359. */
  360. class FPRegisterArgument : public OperationArgument
  361. {
  362. private:
  363. FPRegister reg;
  364. FPRegisterPart part;
  365. public:
  366. DLLEXPORT FPRegisterArgument(FPRegister reg, FPRegisterPart = X);
  367. DLLEXPORT bool usesRegister(FPRegister reg) const override;
  368. DLLEXPORT void replaceRegister(
  369. FPRegister oldReg, FPRegister newReg) override;
  370. DLLEXPORT FPRegister getRegister() const;
  371. DLLEXPORT FPRegisterPart getPart() const;
  372. };
  373. enum class MemoryBlockSize
  374. {
  375. // 8 bist
  376. BYTE = 1,
  377. // 16 bits
  378. WORD = 2,
  379. // 32 bits
  380. DWORD = 4,
  381. // 64 bits
  382. QWORD = 8,
  383. // 128 bits
  384. M128 = 16,
  385. // 256 bits
  386. M256 = 32,
  387. // 512 bits
  388. // M512 = 64
  389. };
  390. /**
  391. Represents the usage of a Memory Read Request as an Instruction
  392. Argument.
  393. */
  394. class MemoryAccessArgument : public OperationArgument
  395. {
  396. private:
  397. bool useAddressReg;
  398. GPRegister address;
  399. int offset; // offset from the address in the register
  400. GPRegister offsetReg;
  401. bool useOffsetReg;
  402. MemoryBlockSize blockSize; // size of the block to access (1,2,4,8)
  403. public:
  404. DLLEXPORT MemoryAccessArgument(MemoryBlockSize blockSize,
  405. GPRegister address,
  406. bool useAddressReg = true,
  407. int offset = 0,
  408. bool useOffsetReg = false,
  409. GPRegister offsetReg = RAX);
  410. DLLEXPORT bool usesRegister(GPRegister reg) const override;
  411. DLLEXPORT void replaceRegister(
  412. GPRegister oldReg, GPRegister newReg) override;
  413. DLLEXPORT bool isUsingAddressRegister() const;
  414. DLLEXPORT GPRegister getAddressRegister() const;
  415. DLLEXPORT int getOffset() const;
  416. DLLEXPORT bool isUsingOffsetRegister() const;
  417. DLLEXPORT GPRegister getOffsetRegister() const;
  418. DLLEXPORT MemoryBlockSize getBlockSize() const;
  419. };
  420. /**
  421. Represents the usage of a const value as an Instruction Argument.
  422. */
  423. class ConstantArgument : public OperationArgument
  424. {
  425. private:
  426. __int64 value;
  427. MemoryBlockSize size; // size in byte
  428. public:
  429. DLLEXPORT ConstantArgument(
  430. __int64 value, MemoryBlockSize size = MemoryBlockSize::QWORD);
  431. DLLEXPORT ConstantArgument(
  432. int value, MemoryBlockSize size = MemoryBlockSize::DWORD);
  433. DLLEXPORT ConstantArgument(
  434. short value, MemoryBlockSize size = MemoryBlockSize::WORD);
  435. DLLEXPORT ConstantArgument(
  436. char value, MemoryBlockSize size = MemoryBlockSize::BYTE);
  437. DLLEXPORT __int64 getValue() const;
  438. DLLEXPORT MemoryBlockSize getSize() const;
  439. };
  440. /**
  441. Represents the usage of a jump label as an Instruction Argument.
  442. */
  443. class JumpTargetArgument : public OperationArgument
  444. {
  445. private:
  446. Text name;
  447. public:
  448. DLLEXPORT JumpTargetArgument(Text name);
  449. DLLEXPORT void addJumpLabelPrefix(Text labelPrefix) override;
  450. const Text& getLabel() const;
  451. };
  452. /**
  453. Represents a single assembly instruction with its arguments.
  454. */
  455. class Instruction : public Framework::ReferenceCounter
  456. {
  457. private:
  458. Operation op;
  459. std::vector<OperationArgument*> args;
  460. public:
  461. DLLEXPORT Instruction(
  462. Operation op, std::initializer_list<OperationArgument*> params);
  463. DLLEXPORT ~Instruction();
  464. /**
  465. * checks if this instruction reads from a specified register.
  466. *
  467. * \param reg the register to check
  468. * \return true if the instruction reads from the register
  469. */
  470. DLLEXPORT bool writesToRegister(
  471. GPRegister reg, const AssemblyBlock* block) const;
  472. /**
  473. * checks if this instruction reads from a specified register.
  474. *
  475. * \param reg the register to check
  476. * \return true if the instruction reads from the register
  477. */
  478. DLLEXPORT bool writesToRegister(
  479. FPRegister reg, const AssemblyBlock* block) const;
  480. /**
  481. * checks if this instruction reads from a specified register.
  482. *
  483. * \param reg the register to check
  484. * \return true if the instruction reads from the register
  485. */
  486. DLLEXPORT bool readsFromRegister(
  487. GPRegister reg, const AssemblyBlock* block) const;
  488. /**
  489. * checks if this instruction reads from a specified register.
  490. *
  491. * \param reg the register to check
  492. * \return true if the instruction reads from the register
  493. */
  494. DLLEXPORT bool readsFromRegister(
  495. FPRegister reg, const AssemblyBlock* block) const;
  496. /**
  497. * checks if a register can be replaced by another register.
  498. *
  499. * \param oldReg the register to replace
  500. * \param newReg the register to use instead
  501. * \return true if the replacement is possible
  502. */
  503. DLLEXPORT bool isReplacementPossible(GPRegister oldReg,
  504. GPRegister newReg,
  505. const AssemblyBlock* block) const;
  506. /**
  507. * checks if a register can be replaced by another register.
  508. *
  509. * \param oldReg the register to replace
  510. * \param newReg the register to use instead
  511. * \return true if the replacement is possible
  512. */
  513. DLLEXPORT bool isReplacementPossible(FPRegister oldReg,
  514. FPRegister newReg,
  515. const AssemblyBlock* block) const;
  516. /**
  517. * replaces a register with another register.
  518. *
  519. * \param oldReg the register to replace
  520. * \param newReg the register to use instead
  521. */
  522. DLLEXPORT void replaceRegister(
  523. GPRegister oldReg, GPRegister newReg);
  524. /**
  525. * replaces a register with another register.
  526. *
  527. * \param oldReg the register to replace
  528. * \param newReg the register to use instead
  529. */
  530. DLLEXPORT void replaceRegister(
  531. FPRegister oldReg, FPRegister newReg);
  532. /**
  533. * adds a prefix to all jump labels in this instruction to avoid
  534. * conflicts if the assembly block that contains this instruction is
  535. * inlined into another block.
  536. *
  537. * \param labelPrefix the label prefix to add
  538. */
  539. DLLEXPORT void addJumpLabelPrefix(Text labelPrefix);
  540. /**
  541. * compiles this Instruction to macine code.
  542. *
  543. * \param machineCodeWriter the machine code will be written to this
  544. * writer
  545. * \param block the block that contains this instruction. needed to
  546. * resolve jump labels
  547. */
  548. DLLEXPORT void compile(StreamWriter* machineCodeWriter,
  549. const AssemblyBlock* block) const;
  550. /**
  551. * calculates the bytes needed for this instruction in machine code.
  552. *
  553. * \return the bytes needed
  554. */
  555. DLLEXPORT int compiledSize(const AssemblyBlock* block) const;
  556. /**
  557. * \return the op code of this instruction
  558. */
  559. DLLEXPORT Operation getOperation() const;
  560. /**
  561. * \return true if the given label is defined by this operation
  562. */
  563. DLLEXPORT bool definesLabel(Text label) const;
  564. };
  565. /**
  566. Represents a block of assembly instructions that can be compiled to
  567. machine code or inlined into another AssemblyBlock with addBlock(...).
  568. */
  569. class AssemblyBlock
  570. {
  571. private:
  572. RCArray<Instruction> instructions;
  573. int inlineIndex;
  574. void* compiledCode;
  575. public:
  576. DLLEXPORT AssemblyBlock();
  577. DLLEXPORT ~AssemblyBlock();
  578. /**
  579. * adds an instruction.
  580. *
  581. * \param instr the instruction to add.
  582. */
  583. DLLEXPORT void addInstruction(Instruction* instr);
  584. /**
  585. * defines a new jump target label.
  586. *
  587. * \param name the name of the label.
  588. */
  589. DLLEXPORT void defineJumpTarget(Text name);
  590. /**
  591. * adds a jump instruction that jumps to the next Instaruction after
  592. * the definition of the given label.
  593. *
  594. * \param jumpOp the op code of the jump iperation.
  595. * \param targetName the label to jump to.
  596. */
  597. DLLEXPORT void addJump(Operation jumpOp, Text targetName);
  598. /**
  599. * writes the specified valueAddress pointer into a register.
  600. *
  601. * \param valueAddress the pointer to the value witch address should
  602. * be stored
  603. * \param target the register where the address should be stored
  604. */
  605. DLLEXPORT void addLoadValue(char* valueAddress, GPRegister target);
  606. /**
  607. * writes the specified valueAddress pointer into a register.
  608. *
  609. * \param valueAddress the pointer to the value witch address should
  610. * be stored
  611. * \param target the register where the address should be stored
  612. */
  613. DLLEXPORT void addLoadValue(short* valueAddress, GPRegister target);
  614. /**
  615. * writes the specified valueAddress pointer into a register.
  616. *
  617. * \param valueAddress the pointer to the value witch address should
  618. * be stored
  619. * \param target the register where the address should be stored
  620. */
  621. DLLEXPORT void addLoadValue(int* valueAddress, GPRegister target);
  622. /**
  623. * writes the specified valueAddress pointer into a register.
  624. *
  625. * \param valueAddress the pointer to the value witch address should
  626. * be stored
  627. * \param target the register where the address should be stored
  628. */
  629. DLLEXPORT void addLoadValue(
  630. __int64* valueAddress, GPRegister target);
  631. /**
  632. * writes the specified valueAddress pointer into a register.
  633. *
  634. * \param valueAddress the pointer to the value witch address should
  635. * be stored
  636. * \param target the register where the address should be stored
  637. */
  638. DLLEXPORT void addLoadValue(
  639. float* valueAddress, FPRegister target, GPRegister temp = RAX);
  640. /**
  641. * writes the specified valueAddress pointer into a register.
  642. *
  643. * \param valueAddress the pointer to the value witch address should
  644. * be stored
  645. * \param target the register where the address should be stored
  646. */
  647. DLLEXPORT void addLoadValue(
  648. double* valueAddress, FPRegister target, GPRegister temp = RAX);
  649. /**
  650. * calls a function at a specified memory address.
  651. *
  652. * \param functionAddress pointet to the address of the function to
  653. * call
  654. */
  655. template<typename T>
  656. void addLoadAddress(T* addr, GPRegister temp = RAX)
  657. {
  658. instructions.add(new Instruction(MOV,
  659. {new GPRegisterArgument(temp),
  660. new ConstantArgument(
  661. reinterpret_cast<__int64>(addr))}));
  662. }
  663. /**
  664. * moves the given value to LOWER8 bits of target register.
  665. *
  666. * \param target the register to move the value to
  667. * \param value the value to move
  668. */
  669. DLLEXPORT void addMoveValue(GPRegister target, char value);
  670. /**
  671. * moves the given value to LOWER16 bits of target register.
  672. *
  673. * \param target the register to move the value to
  674. * \param value the value to move
  675. */
  676. DLLEXPORT void addMoveValue(GPRegister target, short value);
  677. /**
  678. * moves the given value to LOWER32 bits of target register.
  679. *
  680. * \param target the register to move the value to
  681. * \param value the value to move
  682. */
  683. DLLEXPORT void addMoveValue(GPRegister target, int value);
  684. /**
  685. * moves the given value to LOWER64 bits of target register.
  686. *
  687. * \param target the register to move the value to
  688. * \param value the value to move
  689. */
  690. DLLEXPORT void addMoveValue(GPRegister target, __int64 value);
  691. /**
  692. * moves the given value to LOWER32 bits of target register.
  693. * The value needs to be temporarily pushed to the stack, so
  694. * addLoadValue should be used if performance is critical.
  695. *
  696. * \param target the register to move the value to
  697. * \param value the value to move
  698. * \param temp temporary register that can be used us store the
  699. * value
  700. */
  701. DLLEXPORT void addMoveValue(
  702. FPRegister target, float value, GPRegister temp = RAX);
  703. /**
  704. * moves the given value to LOWER64 bits of target register.
  705. * The value needs to be temporarily pushed to the stack, so
  706. * addLoadValue should be used if performance is critical.
  707. *
  708. * \param target the register to move the value to
  709. * \param value the value to move
  710. * \param temp temporary register that can be used us store the
  711. * value
  712. */
  713. DLLEXPORT void addMoveValue(
  714. FPRegister target, double value, GPRegister temp = RAX);
  715. /**
  716. * moves the value from source register to target register.
  717. *
  718. * \param target the register to move the value to
  719. * \param source the register to move the value from
  720. * \param part the part of the register to move
  721. */
  722. DLLEXPORT void addMoveValue(GPRegister target,
  723. GPRegister source,
  724. GPRegisterPart part = FULL64);
  725. /**
  726. * moves the value from source register to target register.
  727. *
  728. * \param target the register to move the value to
  729. * \param source the register to move the value from
  730. * \param part the part of the register to move
  731. */
  732. DLLEXPORT void addMoveValue(FPRegister target,
  733. FPRegister source,
  734. FPDataType type,
  735. FPRegisterPart part = Y);
  736. /**
  737. * calls a function at a specified memory address.
  738. *
  739. * \param functionAddress pointet to the address of the function to
  740. * call
  741. */
  742. DLLEXPORT void addCall(
  743. void* functionAddress, GPRegister temp = RAX);
  744. /**
  745. * calls a function at a specified memory address.
  746. *
  747. * \param functionAddress pointet to the address of the function to
  748. * call
  749. */
  750. template<typename T>
  751. void addMemberCall(T&& functionAddress, GPRegister temp = RAX)
  752. {
  753. addCall((void*&)functionAddress, temp);
  754. }
  755. /**
  756. * adds an ENTER instruction to set up a stack frame for a function
  757. *
  758. * \param stackSize the size of the stack frame to create. should be
  759. * a multiple of 16 and >= 32
  760. * \param nestingLevel the nesting level of the function. usually 0
  761. */
  762. DLLEXPORT void addEnter(
  763. short stackSize = 32, char nestingLevel = 0);
  764. /**
  765. * adds a LEAVE instruction to destroy the stack frame of a
  766. * function.
  767. */
  768. DLLEXPORT void addLeave();
  769. /**
  770. * returns from executing the compiled assembly function.
  771. */
  772. DLLEXPORT void addReturn();
  773. /**
  774. * pushes a register into the stack.
  775. *
  776. * \param reg the register to push
  777. * \param part the part of the register to push
  778. */
  779. DLLEXPORT void addPush(
  780. GPRegister reg, GPRegisterPart part = FULL64);
  781. /**
  782. * pops a value from the sack into a specified register.
  783. *
  784. * \param reg the register to store the popped value
  785. * \param part the part of the register to store the popped value
  786. */
  787. DLLEXPORT void addPop(GPRegister reg, GPRegisterPart part = FULL64);
  788. /**
  789. * pushes a register into the stack.
  790. *
  791. * \param reg the register to push
  792. */
  793. DLLEXPORT void addPush(FPRegister reg, FPRegisterPart part = X);
  794. /**
  795. * pops a value from the sack into a specified register.
  796. *
  797. * \param reg the register to store the popped value
  798. */
  799. DLLEXPORT void addPop(FPRegister reg, FPRegisterPart part = X);
  800. /**
  801. * copies the assembly code from a given block of assembly
  802. * instructions.
  803. *
  804. * \param block the block to inline
  805. * \param preservedGPRegisters the GP registers that should be
  806. * preserved during the inlined block. if a preserved register is
  807. * used in the block, it will be replaced by another register or
  808. * pushed to the stack if no free register is available.
  809. * \param preservedFPRegisters same as preservedGPRegisters but for
  810. * FP registers
  811. * \param blockResultGpReg if the register RAX should be preserved
  812. * this pointer will be set to the register that was selected to
  813. * replace RAX during execution of the block.
  814. * \param blockResultFpReg same as blockResultGpReg but for XMM0
  815. */
  816. DLLEXPORT void addBlock(AssemblyBlock* block,
  817. std::initializer_list<GPRegister> preservedGPRegisters,
  818. std::initializer_list<FPRegister> preservedFPRegisters,
  819. GPRegister* blockResultGpReg,
  820. FPRegister* blockResultFpReg);
  821. /**
  822. * checks if this block writes to a specified register.
  823. *
  824. * \param reg the register to check
  825. * \return true if the block writes to the register
  826. */
  827. DLLEXPORT bool writesToRegister(GPRegister reg) const;
  828. /**
  829. * checks if this block writes to a specified register.
  830. *
  831. * \param reg the register to check
  832. * \return true if the block writes to the register
  833. */
  834. DLLEXPORT bool writesToRegister(FPRegister reg) const;
  835. /**
  836. * checks if this block reads from a specified register.
  837. *
  838. * \param reg the register to check
  839. * \return true if the block reads from the register
  840. */
  841. DLLEXPORT bool readsFromRegister(GPRegister reg) const;
  842. /**
  843. * checks if this block reads from a specified register.
  844. *
  845. * \param reg the register to check
  846. * \return true if the block reads from the register
  847. */
  848. DLLEXPORT bool readsFromRegister(FPRegister reg) const;
  849. /**
  850. * checks if a register can be replaced by another register.
  851. *
  852. * \param oldReg the register to replace
  853. * \param newReg the register to use instead
  854. * \return true if the replacement is possible
  855. */
  856. DLLEXPORT bool isReplacementPossible(
  857. GPRegister oldReg, GPRegister newReg) const;
  858. /**
  859. * checks if a register can be replaced by another register.
  860. *
  861. * \param oldReg the register to replace
  862. * \param newReg the register to use instead
  863. * \return true if the replacement is possible
  864. */
  865. DLLEXPORT bool isReplacementPossible(
  866. FPRegister oldReg, FPRegister newReg) const;
  867. /**
  868. * replaces a register with another register.
  869. *
  870. * \param oldReg the register to replace
  871. * \param newReg the register to use instead
  872. */
  873. DLLEXPORT void replaceRegister(
  874. GPRegister oldReg, GPRegister newReg);
  875. /**
  876. * replaces a register with another register.
  877. *
  878. * \param oldReg the register to replace
  879. * \param newReg the register to use instead
  880. */
  881. DLLEXPORT void replaceRegister(
  882. FPRegister oldReg, FPRegister newReg);
  883. /**
  884. * adds a prefix to all jump labels in this block to avoid conflicts
  885. * if this block is inlined into another block.
  886. *
  887. * \param labelPrefix the label prefix to add
  888. */
  889. DLLEXPORT void addJumpLabelPrefix(Text labelPrefix);
  890. /**
  891. * \return the instructions of this block
  892. */
  893. DLLEXPORT const RCArray<Instruction>& getInstructions() const;
  894. /**
  895. * \return a pointer to a function that contains the compiled byte
  896. * code of this assembly block. and can be called directly with
  897. * reinterpret_cast<returnType(*)(parameterTypes...)>(compile())(parameters...)
  898. */
  899. DLLEXPORT void* compile();
  900. /**
  901. * \return a pointer to a function that contains the compiled byte
  902. * code of this assembly block. and can be called directly with
  903. */
  904. template<typename T> T compileToFunction()
  905. {
  906. return reinterpret_cast<T>(compile());
  907. }
  908. };
  909. } // namespace Assembly
  910. } // namespace Framework