Assembly.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. #include "pch.h"
  2. #include "Assembly.h"
  3. #include "CppUnitTest.h"
  4. using namespace Microsoft::VisualStudio::CppUnitTestFramework;
  5. int globalFunc(int a, int b)
  6. {
  7. return a * b;
  8. }
  9. class A
  10. {
  11. public:
  12. virtual int getValue()
  13. {
  14. return 0;
  15. }
  16. };
  17. class B : public A
  18. {
  19. public:
  20. virtual int getValue() override
  21. {
  22. return 10;
  23. }
  24. };
  25. namespace FrameworkTests
  26. {
  27. TEST_CLASS (AssemblyTests)
  28. {
  29. public:
  30. TEST_METHOD (Add8Test)
  31. {
  32. Framework::Assembly::AssemblyBlock codeBlock;
  33. codeBlock.addMoveValue(Framework::Assembly::RAX, (__int64)0);
  34. codeBlock.addMoveValue(Framework::Assembly::RAX,
  35. Framework::Assembly::RDX,
  36. Framework::Assembly::LOWER8);
  37. codeBlock.addAddition(Framework::Assembly::RAX,
  38. Framework::Assembly::RCX,
  39. Framework::Assembly::LOWER8);
  40. int (*add)(int a, int b) = (int (*)(int, int))codeBlock.compile();
  41. int result = add(22, 15);
  42. int result2 = add(0x0FFFFF43, 0x0FFFFF05);
  43. Assert::AreEqual(37, result);
  44. Assert::AreEqual(0x48, result2);
  45. }
  46. TEST_METHOD (Add16Test)
  47. {
  48. Framework::Assembly::AssemblyBlock codeBlock;
  49. codeBlock.addMoveValue(Framework::Assembly::RAX, (__int64)0);
  50. codeBlock.addMoveValue(Framework::Assembly::RAX,
  51. Framework::Assembly::RDX,
  52. Framework::Assembly::LOWER16);
  53. codeBlock.addAddition(Framework::Assembly::RAX,
  54. Framework::Assembly::RCX,
  55. Framework::Assembly::LOWER16);
  56. int (*add)(int a, int b) = (int (*)(int, int))codeBlock.compile();
  57. int result = add(22, 15);
  58. int result2 = add(0x11111111, 0x22222222);
  59. Assert::AreEqual(37, result);
  60. Assert::AreEqual(0x3333, result2);
  61. }
  62. TEST_METHOD (Add32Test)
  63. {
  64. Framework::Assembly::AssemblyBlock codeBlock;
  65. codeBlock.addMoveValue(Framework::Assembly::RAX,
  66. Framework::Assembly::RDX,
  67. Framework::Assembly::LOWER32);
  68. codeBlock.addAddition(Framework::Assembly::RAX,
  69. Framework::Assembly::RCX,
  70. Framework::Assembly::LOWER32);
  71. __int64 (*add)(__int64 a, __int64 b)
  72. = (__int64 (*)(__int64, __int64))codeBlock.compile();
  73. __int64 result = add(22, 15);
  74. __int64 result2 = add(0x1111111111111111, 0x1111111111111111);
  75. Assert::AreEqual((__int64)37, result);
  76. Assert::AreEqual((__int64)0x22222222, result2);
  77. }
  78. TEST_METHOD (Add64Test)
  79. {
  80. Framework::Assembly::AssemblyBlock codeBlock;
  81. codeBlock.addMoveValue(
  82. Framework::Assembly::RAX, Framework::Assembly::RDX);
  83. codeBlock.addAddition(
  84. Framework::Assembly::RAX, Framework::Assembly::RCX);
  85. __int64 (*add)(__int64 a, __int64 b)
  86. = (__int64 (*)(__int64, __int64))codeBlock.compile();
  87. __int64 result = add(22, 15);
  88. __int64 result2 = add(0x1111111111111111, 0x1111111111111111);
  89. Assert::AreEqual((__int64)37, result);
  90. Assert::AreEqual((__int64)0x2222222222222222, result2);
  91. }
  92. TEST_METHOD (AddFloatTest)
  93. {
  94. Framework::Assembly::AssemblyBlock codeBlock;
  95. codeBlock.addAddition(Framework::Assembly::MM0,
  96. Framework::Assembly::MM1,
  97. Framework::Assembly::SINGLE_FLOAT,
  98. Framework::Assembly::X);
  99. float (*add)(float a, float b)
  100. = (float (*)(float, float))codeBlock.compile();
  101. float result = add(4.24f, 8.54f);
  102. float result2 = add(0.3f, 7.6f);
  103. Assert::AreEqual((float)(4.24f + 8.54f), result);
  104. Assert::AreEqual((float)(0.3f + 7.6f), result2);
  105. }
  106. TEST_METHOD (AddDoubleTest)
  107. {
  108. Framework::Assembly::AssemblyBlock codeBlock;
  109. codeBlock.addAddition(Framework::Assembly::MM0,
  110. Framework::Assembly::MM1,
  111. Framework::Assembly::SINGLE_DOUBLE,
  112. Framework::Assembly::X);
  113. double (*add)(double a, double b)
  114. = (double (*)(double, double))codeBlock.compile();
  115. double result = add(4.24, 8.54);
  116. double result2 = add(0.3, 7.6);
  117. Assert::AreEqual(4.24 + 8.54, result);
  118. Assert::AreEqual(0.3 + 7.6, result2);
  119. }
  120. TEST_METHOD (returnRefTest)
  121. {
  122. char cRef = 1;
  123. short sRef = 2;
  124. int iRef = 3;
  125. __int64 lRef = 4;
  126. float fRef = 5.0f;
  127. double dRef = 6.0;
  128. Framework::Assembly::AssemblyBlock ccodeBlock;
  129. ccodeBlock.addLoadValue(&cRef, Framework::Assembly::RAX);
  130. char (*getc)() = (char (*)())ccodeBlock.compile();
  131. char cresult = getc();
  132. Assert::AreEqual((char)1, cresult);
  133. cRef = 11;
  134. cresult = getc();
  135. Assert::AreEqual((char)11, cresult);
  136. Framework::Assembly::AssemblyBlock scodeBlock;
  137. scodeBlock.addLoadValue(&sRef, Framework::Assembly::RAX);
  138. short (*gets)() = (short (*)())scodeBlock.compile();
  139. short sresult = gets();
  140. Assert::AreEqual((short)2, sresult);
  141. sRef = 22;
  142. sresult = gets();
  143. Assert::AreEqual((short)22, sresult);
  144. Framework::Assembly::AssemblyBlock icodeBlock;
  145. icodeBlock.addLoadValue(&iRef, Framework::Assembly::RAX);
  146. int (*geti)() = (int (*)())icodeBlock.compile();
  147. int iresult = geti();
  148. Assert::AreEqual((int)3, iresult);
  149. iRef = 33;
  150. iresult = geti();
  151. Assert::AreEqual((int)33, iresult);
  152. Framework::Assembly::AssemblyBlock lcodeBlock;
  153. lcodeBlock.addLoadValue(&lRef, Framework::Assembly::RAX);
  154. __int64 (*getl)() = (__int64 (*)())lcodeBlock.compile();
  155. __int64 lresult = getl();
  156. Assert::AreEqual((__int64)4, lresult);
  157. lRef = 44;
  158. lresult = getl();
  159. Assert::AreEqual((__int64)44, lresult);
  160. Framework::Assembly::AssemblyBlock fcodeBlock;
  161. fcodeBlock.addLoadValue(&fRef, Framework::Assembly::MM0);
  162. float (*getf)() = (float (*)())fcodeBlock.compile();
  163. float fresult = getf();
  164. Assert::AreEqual((float)5.0f, fresult);
  165. fRef = 55.0f;
  166. fresult = getf();
  167. Assert::AreEqual((float)55.0f, fresult);
  168. Framework::Assembly::AssemblyBlock dcodeBlock;
  169. dcodeBlock.addLoadValue(&dRef, Framework::Assembly::MM0);
  170. double (*getd)() = (double (*)())dcodeBlock.compile();
  171. double dresult = getd();
  172. Assert::AreEqual((double)6.0, dresult);
  173. dRef = 66.0;
  174. dresult = getd();
  175. Assert::AreEqual((double)66.0, dresult);
  176. }
  177. int c;
  178. int testMethod(int a, int b)
  179. {
  180. return a + b + c;
  181. }
  182. TEST_METHOD (testCall)
  183. {
  184. Framework::Assembly::AssemblyBlock gfcodeBlock;
  185. gfcodeBlock.addMoveValue(Framework::Assembly::RCX, 20);
  186. gfcodeBlock.addMoveValue(Framework::Assembly::RDX, 50);
  187. gfcodeBlock.addCall(globalFunc,
  188. Framework::Assembly::INT_VALUE,
  189. {Framework::Assembly::RCX, Framework::Assembly::RDX});
  190. int (*f)() = gfcodeBlock.compileToFunction<int (*)()>();
  191. int result = f();
  192. Assert::AreEqual(globalFunc(20, 50), result);
  193. Framework::Assembly::AssemblyBlock lfcodeBlock;
  194. lfcodeBlock.addLoadAddress(this, Framework::Assembly::RCX);
  195. lfcodeBlock.addMoveValue(Framework::Assembly::RDX, 20);
  196. lfcodeBlock.addMoveValue(Framework::Assembly::R8, 50);
  197. lfcodeBlock.addMemberCall(&AssemblyTests::testMethod,
  198. Framework::Assembly::INT_VALUE,
  199. {Framework::Assembly::RCX,
  200. Framework::Assembly::RDX,
  201. Framework::Assembly::R8});
  202. c = 1;
  203. f = lfcodeBlock.compileToFunction<int (*)()>();
  204. result = f();
  205. A* a = new B();
  206. Assert::AreEqual(testMethod(20, 50), result);
  207. Framework::Assembly::AssemblyBlock vfcodeBlock;
  208. vfcodeBlock.addLoadAddress(a, Framework::Assembly::RCX);
  209. vfcodeBlock.addMemberCall(
  210. &A::getValue, Framework::Assembly::INT_VALUE);
  211. c = 1;
  212. f = vfcodeBlock.compileToFunction<int (*)()>();
  213. result = f();
  214. Assert::AreEqual(a->getValue(), result);
  215. delete a;
  216. }
  217. TEST_METHOD (mulTest)
  218. {
  219. float fa = 3.0f;
  220. float fb = 4.0f;
  221. double da = 5.0;
  222. double db = 6.0;
  223. Framework::Assembly::AssemblyBlock fcodeBlock;
  224. fcodeBlock.addLoadValue(&fa, Framework::Assembly::MM0);
  225. fcodeBlock.addLoadValue(&fb, Framework::Assembly::MM1);
  226. fcodeBlock.addMultiplication(Framework::Assembly::MM0,
  227. Framework::Assembly::MM1,
  228. Framework::Assembly::SINGLE_FLOAT,
  229. Framework::Assembly::X);
  230. float (*fmul)() = fcodeBlock.compileToFunction<float (*)()>();
  231. float fresult = fmul();
  232. Assert::AreEqual(fa * fb, fresult);
  233. Framework::Assembly::AssemblyBlock dcodeBlock;
  234. dcodeBlock.addLoadValue(&da, Framework::Assembly::MM0);
  235. dcodeBlock.addLoadValue(&db, Framework::Assembly::MM1);
  236. dcodeBlock.addMultiplication(Framework::Assembly::MM0,
  237. Framework::Assembly::MM1,
  238. Framework::Assembly::SINGLE_DOUBLE,
  239. Framework::Assembly::X);
  240. double (*dmul)() = dcodeBlock.compileToFunction<double (*)()>();
  241. double dresult = dmul();
  242. Assert::AreEqual(da * db, dresult);
  243. }
  244. TEST_METHOD (jumpTest)
  245. {
  246. Framework::Assembly::AssemblyBlock codeBlock;
  247. codeBlock.addMoveValue(Framework::Assembly::RAX, 0);
  248. codeBlock.addJump(Framework::Assembly::JMP, "end");
  249. codeBlock.addMoveValue(Framework::Assembly::RAX, 1);
  250. codeBlock.defineJumpTarget("start");
  251. codeBlock.addMoveValue(Framework::Assembly::RAX, 2);
  252. codeBlock.defineJumpTarget("end");
  253. codeBlock.addTest(
  254. Framework::Assembly::RAX, Framework::Assembly::RAX);
  255. codeBlock.addJump(Framework::Assembly::JZ, "start");
  256. int (*test)() = codeBlock.compileToFunction<int (*)()>();
  257. int result = test();
  258. Assert::AreEqual(2, result);
  259. }
  260. TEST_METHOD (stackTest)
  261. {
  262. Framework::Assembly::AssemblyBlock codeBlock;
  263. codeBlock.addMoveValue(Framework::Assembly::RAX, (char)10);
  264. codeBlock.addMoveValue(Framework::Assembly::RBX, (short)20);
  265. codeBlock.addMoveValue(Framework::Assembly::RCX, (int)30);
  266. codeBlock.addMoveValue(Framework::Assembly::RDX, (__int64)40);
  267. codeBlock.addMoveValue(
  268. Framework::Assembly::MM0, 5.f, Framework::Assembly::R8);
  269. codeBlock.addMoveValue(
  270. Framework::Assembly::MM1, 6.0, Framework::Assembly::R8);
  271. codeBlock.addPush(
  272. Framework::Assembly::RAX, Framework::Assembly::LOWER8);
  273. codeBlock.addPush(
  274. Framework::Assembly::RBX, Framework::Assembly::LOWER16);
  275. codeBlock.addPush(
  276. Framework::Assembly::RCX, Framework::Assembly::LOWER32);
  277. codeBlock.addPush(
  278. Framework::Assembly::RDX, Framework::Assembly::FULL64);
  279. codeBlock.addPush(Framework::Assembly::MM0,
  280. Framework::Assembly::SINGLE_FLOAT,
  281. Framework::Assembly::X);
  282. codeBlock.addPush(Framework::Assembly::MM1,
  283. Framework::Assembly::SINGLE_DOUBLE,
  284. Framework::Assembly::X);
  285. codeBlock.addPop(Framework::Assembly::MM1,
  286. Framework::Assembly::SINGLE_DOUBLE,
  287. Framework::Assembly::X);
  288. codeBlock.addMoveValue(Framework::Assembly::MM2, 6.0);
  289. codeBlock.addCompare(Framework::Assembly::MM1,
  290. Framework::Assembly::MM2,
  291. Framework::Assembly::SINGLE_DOUBLE);
  292. codeBlock.addJump(Framework::Assembly::JNE, "error");
  293. codeBlock.addPop(Framework::Assembly::MM0,
  294. Framework::Assembly::SINGLE_FLOAT,
  295. Framework::Assembly::X);
  296. codeBlock.addMoveValue(Framework::Assembly::MM2, 5.f);
  297. codeBlock.addCompare(Framework::Assembly::MM0,
  298. Framework::Assembly::MM2,
  299. Framework::Assembly::SINGLE_FLOAT);
  300. codeBlock.addJump(Framework::Assembly::JNE, "error");
  301. codeBlock.addPop(
  302. Framework::Assembly::RDX, Framework::Assembly::FULL64);
  303. codeBlock.addCompare(Framework::Assembly::RDX, 40);
  304. codeBlock.addJump(Framework::Assembly::JNE, "error");
  305. codeBlock.addPop(
  306. Framework::Assembly::RCX, Framework::Assembly::LOWER32);
  307. codeBlock.addCompare(Framework::Assembly::RCX, 30);
  308. codeBlock.addJump(Framework::Assembly::JNE, "error");
  309. codeBlock.addPop(
  310. Framework::Assembly::RBX, Framework::Assembly::LOWER16);
  311. codeBlock.addCompare(Framework::Assembly::RBX, (short)20);
  312. codeBlock.addJump(Framework::Assembly::JNE, "error");
  313. codeBlock.addPop(
  314. Framework::Assembly::RAX, Framework::Assembly::LOWER8);
  315. codeBlock.addCompare(Framework::Assembly::RAX, (char)10);
  316. codeBlock.addJump(Framework::Assembly::JNE, "error");
  317. codeBlock.addMoveValue(Framework::Assembly::RAX, 1);
  318. codeBlock.addJump(Framework::Assembly::JMP, "end");
  319. codeBlock.defineJumpTarget("error");
  320. codeBlock.addMoveValue(Framework::Assembly::RAX, 0);
  321. codeBlock.defineJumpTarget("end");
  322. int (*test)() = codeBlock.compileToFunction<int (*)()>();
  323. int result = test();
  324. Assert::AreEqual(1, result);
  325. }
  326. };
  327. } // namespace FrameworkTests