You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

361 lines
12 KiB

  1. #include "molasses/parser_primitives.h"
  2. #include "molasses/generator_primitives.h"
  3. namespace molasses {
  4. std::string marshal(const std::string& target) {
  5. std::stringstream builder;
  6. bool is_first = true;
  7. for(char character : target) {
  8. if(isalpha(character)) {
  9. builder << character;
  10. } else if(isdigit(character) and is_first) {
  11. builder << "___" << (int)character << "___";
  12. } else {
  13. builder << "__" << (int)character << "__";
  14. }
  15. is_first = false;
  16. }
  17. return builder.str();
  18. }
  19. std::string escape(const std::string& target) {
  20. std::stringstream builder;
  21. for(char character : target) {
  22. switch(character) {
  23. case 0:
  24. builder << "\\0";
  25. break;
  26. case '\n':
  27. builder << "\\n";
  28. break;
  29. case '"':
  30. builder << "\\\"";
  31. break;
  32. case '\t':
  33. builder << "\\t";
  34. break;
  35. case '\'':
  36. builder << "\\'";
  37. break;
  38. default:
  39. builder << character;
  40. }
  41. }
  42. return builder.str();
  43. }
  44. parser_context register_integers(parser_context ctx) requires(architecture == architecture_t::x86_64_linux)
  45. {
  46. ctx.types.push_back(std::make_shared<primitive_type>("i8", 1));
  47. ctx.types.push_back(std::make_shared<primitive_type>("i16", 2));
  48. ctx.types.push_back(std::make_shared<primitive_type>("i32", 4));
  49. ctx.types.push_back(std::make_shared<primitive_type>("i64", 8));
  50. ctx.types.push_back(std::make_shared<primitive_type>("u8", 1));
  51. ctx.types.push_back(std::make_shared<primitive_type>("u16", 2));
  52. ctx.types.push_back(std::make_shared<primitive_type>("u32", 4));
  53. ctx.types.push_back(std::make_shared<primitive_type>("u64", 8));
  54. return ctx;
  55. }
  56. parser_context register_i32_operations(parser_context ctx)
  57. requires (architecture == architecture_t::x86_64_linux) {
  58. ctx.operations.emplace_back(
  59. std::make_shared<molasses::primitive_operation>(
  60. std::string{"+"},
  61. std::vector<std::string>({"i32", "i32"}),
  62. std::vector<std::string>({"i32"}),
  63. std::vector<std::string>({
  64. " popq %rax\n",
  65. " popq %rbx\n",
  66. " addl %ebx, %eax\n",
  67. " andl $0xFFFFFFFF, %eax\n",
  68. " pushq %rax\n"
  69. })
  70. )
  71. );
  72. ctx.operations.emplace_back(
  73. std::make_shared<molasses::primitive_operation>(
  74. std::string{"+_i64"},
  75. std::vector<std::string>({"i64", "i64"}),
  76. std::vector<std::string>({"i64"}),
  77. std::vector<std::string>({
  78. " popq %rax\n",
  79. " popq %rbx\n",
  80. " addq %rbx, %rax\n",
  81. " pushq %rax\n"
  82. })
  83. )
  84. );
  85. ctx.operations.emplace_back(
  86. std::make_shared<molasses::primitive_operation>(
  87. std::string{"/%_i64"},
  88. std::vector<std::string>({"i64", "i64"}),
  89. std::vector<std::string>({"i64", "i64"}),
  90. std::vector<std::string>({
  91. " popq %rax\n",
  92. " popq %rbx\n",
  93. " divq %rbx, %rax\n",
  94. " pushq %rax\n",
  95. " pushq %rdx\n"
  96. // TODO: this is actually unsigned division, so it needs improvements on negative numbers
  97. })
  98. )
  99. );
  100. ctx.operations.emplace_back(
  101. std::make_shared<molasses::primitive_operation>(
  102. std::string{"u8-ptr_to_i64"},
  103. std::vector<std::string>({"u8 ptr"}),
  104. std::vector<std::string>({"i64"}),
  105. std::vector<std::string>({
  106. })
  107. )
  108. );
  109. ctx.operations.emplace_back(
  110. std::make_shared<molasses::primitive_operation>(
  111. std::string{"*"},
  112. std::vector<std::string>({"i32", "i32"}),
  113. std::vector<std::string>({"i32"}),
  114. std::vector<std::string>({
  115. " popq %rax\n",
  116. " popq %rbx\n",
  117. " imull %ebx, %eax\n",
  118. " andl $0xFFFFFFFF, %eax\n",
  119. " pushq %rax\n"
  120. })
  121. )
  122. );
  123. ctx.operations.emplace_back(
  124. std::make_shared<molasses::primitive_operation>(
  125. std::string{"-"},
  126. std::vector<std::string>({"i32", "i32"}),
  127. std::vector<std::string>({"i32"}),
  128. std::vector<std::string>({
  129. " popq %rax\n",
  130. " popq %rbx\n",
  131. " subl %ebx, %eax\n",
  132. " andl $0xFFFFFFFF, %eax\n",
  133. " pushq %rax\n"
  134. })
  135. )
  136. );
  137. ctx.operations.emplace_back(
  138. std::make_shared<molasses::primitive_operation>(
  139. std::string{"i32-to-i64"},
  140. std::vector<std::string>({"i32"}),
  141. std::vector<std::string>({"i64"}),
  142. std::vector<std::string>({
  143. " popq %rax\n",
  144. " movslq %eax, %rax\n",
  145. " pushq %rax\n"
  146. })
  147. )
  148. );
  149. ctx.operations.emplace_back(
  150. std::make_shared<molasses::primitive_operation>(
  151. std::string{"drop_i64"},
  152. std::vector<std::string>({"i64"}),
  153. std::vector<std::string>({}),
  154. std::vector<std::string>({
  155. " popq %rax\n"
  156. })
  157. )
  158. );
  159. ctx.operations.emplace_back(
  160. std::make_shared<molasses::primitive_operation>(
  161. std::string{"syscall1"},
  162. std::vector<std::string>({"i64", "i64"}),
  163. std::vector<std::string>({"i64"}),
  164. std::vector<std::string>({
  165. " popq %rax\n",
  166. " popq %rdi\n",
  167. " syscall\n",
  168. " pushq %rax\n"
  169. })
  170. )
  171. );
  172. ctx.operations.emplace_back(
  173. std::make_shared<molasses::primitive_operation>(
  174. std::string{"syscall2"},
  175. std::vector<std::string>({"i64", "i64", "i64"}),
  176. std::vector<std::string>({"i64"}),
  177. std::vector<std::string>({
  178. " popq %rax\n",
  179. " popq %rdi\n",
  180. " popq %rsi\n",
  181. " syscall\n",
  182. " pushq %rax\n"
  183. })
  184. )
  185. );
  186. ctx.operations.emplace_back(
  187. std::make_shared<molasses::primitive_operation>(
  188. std::string{"syscall3"},
  189. std::vector<std::string>({"i64", "i64", "i64", "i64"}),
  190. std::vector<std::string>({"i64"}),
  191. std::vector<std::string>({
  192. " popq %rax\n",
  193. " popq %rdi\n",
  194. " popq %rsi\n",
  195. " popq %rdx\n",
  196. " syscall\n",
  197. " pushq %rax\n"
  198. })
  199. )
  200. );
  201. ctx.operations.emplace_back(
  202. std::make_shared<molasses::primitive_operation>(
  203. std::string{"syscall4"},
  204. std::vector<std::string>({"i64", "i64", "i64", "i64", "i64"}),
  205. std::vector<std::string>({"i64"}),
  206. std::vector<std::string>({
  207. " popq %rax\n",
  208. " popq %rdi\n",
  209. " popq %rsi\n",
  210. " popq %rdx\n",
  211. " popq %r10\n",
  212. " syscall\n",
  213. " pushq %rax\n"
  214. })
  215. )
  216. );
  217. ctx.operations.emplace_back(
  218. std::make_shared<molasses::primitive_operation>(
  219. std::string{"syscall5"},
  220. std::vector<std::string>({"i64", "i64", "i64", "i64", "i64", "i64"}),
  221. std::vector<std::string>({"i64"}),
  222. std::vector<std::string>({
  223. " popq %rax\n",
  224. " popq %rdi\n",
  225. " popq %rsi\n",
  226. " popq %rdx\n",
  227. " popq %r10\n",
  228. " popq %r8\n",
  229. " syscall\n",
  230. " pushq %rax\n"
  231. })
  232. )
  233. );
  234. ctx.operations.emplace_back(
  235. std::make_shared<molasses::primitive_operation>(
  236. std::string{"syscall6"},
  237. std::vector<std::string>({"i64", "i64", "i64", "i64", "i64", "i64", "i64"}),
  238. std::vector<std::string>({"i64"}),
  239. std::vector<std::string>({
  240. " popq %rax\n",
  241. " popq %rdi\n",
  242. " popq %rsi\n",
  243. " popq %rdx\n",
  244. " popq %r10\n",
  245. " popq %r8\n",
  246. " popq %r9\n",
  247. " syscall\n",
  248. " pushq %rax\n"
  249. })
  250. )
  251. );
  252. return ctx;
  253. }
  254. std::vector<std::string> generate_call(const std::string& target)
  255. requires (architecture == architecture_t::x86_64_linux) {
  256. return {
  257. " call "+marshal(target)+"\n",
  258. };
  259. }
  260. std::vector<std::string> generate_string(const symbol& representation, const std::string& string_value)
  261. requires (architecture == architecture_t::x86_64_linux) {
  262. return {
  263. "__EMITED_STRING_____"+std::to_string(representation.id)+"___:\n",
  264. " .asciz \""+escape(string_value)+"\"\n",
  265. };
  266. }
  267. std::vector<std::string> generate_push_string_ptr(const symbol& representation) {
  268. return {
  269. " pushq $__EMITED_STRING_____"+std::to_string(representation.id)+"___\n"
  270. };
  271. }
  272. std::vector<std::string> generate_push_int32(int32_t target)
  273. requires (architecture == architecture_t::x86_64_linux) {
  274. return {
  275. " pushq $" +std::to_string(target)+ "\n"
  276. };
  277. }
  278. std::vector<std::string> generate_push_int64(int64_t target)
  279. requires (architecture == architecture_t::x86_64_linux) {
  280. return {
  281. " pushq $" +std::to_string(target)+ "\n"
  282. };
  283. }
  284. std::vector<std::string> generate_label(const std::string& target)
  285. requires (architecture == architecture_t::x86_64_linux) {
  286. return {
  287. marshal(target)+":\n"
  288. };
  289. }
  290. std::vector<std::string> generate_return()
  291. requires (architecture == architecture_t::x86_64_linux) {
  292. return {
  293. " // Return to caller\n",
  294. " addq $-8, %r10\n",
  295. " pushq (%r10)\n",
  296. " retq\n"
  297. };
  298. }
  299. std::vector<std::string> generate_enter()
  300. requires (architecture == architecture_t::x86_64_linux) {
  301. return {
  302. " // Prepare the function stack\n",
  303. " popq (%r10)\n"
  304. " addq $8, %r10\n",
  305. };
  306. }
  307. std::vector<std::string> initialize_stack()
  308. requires (architecture == architecture_t::x86_64_linux) {
  309. std::vector<std::string> operations = {
  310. "code:\n",
  311. " .skip 1000000\n",
  312. ".text\n",
  313. " .globl _start\n",
  314. "initialize_callstack:\n",
  315. " movq $9, %rax\n",
  316. " movq $0, %rdi\n",
  317. " movq $8192, %rsi\n",
  318. " movq $3, %rdx\n",
  319. " movq $34, %r10\n",
  320. " movq $-1, %r8\n",
  321. " movq $0, %r9\n",
  322. " syscall\n",
  323. " movq %rax, %r10\n",
  324. " retq\n",
  325. "_start:\n",
  326. " call initialize_callstack\n"
  327. };
  328. for(const auto& op : generate_call("main")) {
  329. operations.push_back(op);
  330. }
  331. for(const auto& op : std::vector<std::string>{
  332. " movq $0, %rdi\n",
  333. " movq $60, %rax\n",
  334. " syscall\n"
  335. }
  336. ) {
  337. operations.push_back(op);
  338. }
  339. return operations;
  340. }
  341. }