print.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540
  1. void ssa_fprintf(gbFile *f, char *fmt, ...) {
  2. va_list va;
  3. va_start(va, fmt);
  4. gb_fprintf_va(f, fmt, va);
  5. #if 1
  6. gb_printf_va(fmt, va);
  7. #endif
  8. va_end(va);
  9. }
  10. b32 ssa_valid_char(u8 c) {
  11. if (gb_char_is_alphanumeric(c))
  12. return true;
  13. switch (c) {
  14. case '$':
  15. case '-':
  16. case '.':
  17. case '_':
  18. return true;
  19. }
  20. return false;
  21. }
  22. void ssa_print_escape_string(gbFile *f, String name) {
  23. isize extra = 0;
  24. for (isize i = 0; i < name.len; i++) {
  25. u8 c = name.text[i];
  26. if (!ssa_valid_char(c))
  27. extra += 2;
  28. }
  29. if (extra == 0) {
  30. ssa_fprintf(f, "%.*s", LIT(name));
  31. return;
  32. }
  33. char hex_table[] = "0123456789ABCDEF";
  34. isize buf_len = name.len + extra;
  35. u8 *buf = gb_alloc_array(gb_heap_allocator(), u8, buf_len);
  36. defer (gb_free(gb_heap_allocator(), buf));
  37. isize j = 0;
  38. for (isize i = 0; i < name.len; i++) {
  39. u8 c = name.text[i];
  40. if (ssa_valid_char(c)) {
  41. buf[j++] = c;
  42. } else {
  43. buf[j] = '\\';
  44. buf[j+1] = hex_table[c >> 4];
  45. buf[j+2] = hex_table[c & 0x0f];
  46. j += 3;
  47. }
  48. }
  49. gb_file_write(f, buf, buf_len);
  50. }
  51. void ssa_print_encoded_local(gbFile *f, String name) {
  52. ssa_fprintf(f, "%%");
  53. ssa_print_escape_string(f, name);
  54. }
  55. void ssa_print_encoded_global(gbFile *f, String name) {
  56. ssa_fprintf(f, "@");
  57. ssa_print_escape_string(f, name);
  58. }
  59. void ssa_print_type(gbFile *f, BaseTypeSizes s, Type *t) {
  60. i64 word_bits = 8*s.word_size;
  61. GB_ASSERT_NOT_NULL(t);
  62. t = default_type(t);
  63. switch (t->kind) {
  64. case Type_Basic:
  65. switch (t->basic.kind) {
  66. case Basic_bool: ssa_fprintf(f, "i1"); break;
  67. case Basic_i8: ssa_fprintf(f, "i8"); break;
  68. case Basic_i16: ssa_fprintf(f, "i16"); break;
  69. case Basic_i32: ssa_fprintf(f, "i32"); break;
  70. case Basic_i64: ssa_fprintf(f, "i64"); break;
  71. case Basic_u8: ssa_fprintf(f, "i8"); break;
  72. case Basic_u16: ssa_fprintf(f, "i16"); break;
  73. case Basic_u32: ssa_fprintf(f, "i32"); break;
  74. case Basic_u64: ssa_fprintf(f, "i64"); break;
  75. case Basic_f32: ssa_fprintf(f, "float"); break;
  76. case Basic_f64: ssa_fprintf(f, "double"); break;
  77. case Basic_rawptr: ssa_fprintf(f, "void*"); break;
  78. case Basic_string: ssa_fprintf(f, "{i8*, i%lld}", word_bits); break;
  79. case Basic_int: ssa_fprintf(f, "i%lld", word_bits); break;
  80. case Basic_uint: ssa_fprintf(f, "i%lld", word_bits); break;
  81. }
  82. break;
  83. case Type_Array:
  84. ssa_fprintf(f, "[%lld x ", t->array.count);
  85. ssa_print_type(f, s, t->array.element);
  86. ssa_fprintf(f, "]");
  87. break;
  88. case Type_Slice:
  89. ssa_fprintf(f, "{");
  90. ssa_print_type(f, s, t->slice.element);
  91. ssa_fprintf(f, "*, i%lld, i%lld}", word_bits, word_bits);
  92. break;
  93. case Type_Structure:
  94. ssa_fprintf(f, "{");
  95. for (isize i = 0; i < t->structure.field_count; i++) {
  96. if (i > 0) ssa_fprintf(f, ", ");
  97. ssa_print_type(f, s, t->structure.fields[i]->type);
  98. }
  99. ssa_fprintf(f, "}");
  100. break;
  101. case Type_Pointer:
  102. ssa_print_type(f, s, t->pointer.element);
  103. ssa_fprintf(f, "*");
  104. break;
  105. case Type_Named:
  106. ssa_print_encoded_local(f, t->named.name);
  107. break;
  108. case Type_Alias:
  109. ssa_print_type(f, s, t->alias.base);
  110. break;
  111. case Type_Tuple:
  112. if (t->tuple.variable_count == 1) {
  113. ssa_print_type(f, s, t->tuple.variables[0]->type);
  114. } else {
  115. ssa_fprintf(f, "{");
  116. for (isize i = 0; i < t->tuple.variable_count; i++) {
  117. if (i > 0) ssa_fprintf(f, ", ");
  118. ssa_print_type(f, s, t->tuple.variables[i]->type);
  119. }
  120. ssa_fprintf(f, "}");
  121. }
  122. break;
  123. case Type_Procedure:
  124. if (t->procedure.result_count == 0)
  125. ssa_fprintf(f, "void");
  126. else
  127. ssa_print_type(f, s, t->procedure.results);
  128. ssa_fprintf(f, " (");
  129. for (isize i = 0; i < t->procedure.param_count; i++) {
  130. if (i > 0) ssa_fprintf(f, ", ");
  131. ssa_print_type(f, s, &t->procedure.params[i]);
  132. }
  133. ssa_fprintf(f, ")*");
  134. break;
  135. }
  136. }
  137. void ssa_print_exact_value(gbFile *f, ssaModule *m, ExactValue value, Type *type) {
  138. switch (value.kind) {
  139. case ExactValue_Bool:
  140. ssa_fprintf(f, (value.value_bool ? "true" : "false"));
  141. break;
  142. case ExactValue_String: {
  143. ssa_fprintf(f, "c\"");
  144. // TODO(bill): Make unquote string function
  145. String unquoted = value.value_string;
  146. unquoted.text++;
  147. unquoted.len -= 2;
  148. ssa_print_escape_string(f, unquoted);
  149. ssa_fprintf(f, "\"");
  150. } break;
  151. case ExactValue_Integer:
  152. ssa_fprintf(f, "%lld", value.value_integer);
  153. break;
  154. case ExactValue_Float: {
  155. u64 u = 0;
  156. if (is_type_float(type) && type->basic.kind == Basic_f32) {
  157. // IMPORTANT NOTE(bill): LLVM requires all floating point constants to be
  158. // a 64 bit number if bits_of(float type) <= 64.
  159. // To overcome this problem, fill the "bottom" 32 bits with zeros
  160. // https://groups.google.com/forum/#!topic/llvm-dev/IlqV3TbSk6M
  161. f32 fp = cast(f32)value.value_float;
  162. u = *cast(u32 *)&fp;
  163. u <<= 32;
  164. } else {
  165. u = *cast(u64 *)&value.value_float;
  166. }
  167. ssa_fprintf(f, "0x%llx", u);
  168. } break;
  169. case ExactValue_Pointer:
  170. if (value.value_float == NULL) {
  171. ssa_fprintf(f, "null");
  172. } else {
  173. GB_PANIC("TODO(bill): ExactValue_Pointer");
  174. }
  175. break;
  176. default:
  177. GB_PANIC("Invalid ExactValue");
  178. break;
  179. }
  180. }
  181. void ssa_print_block_name(gbFile *f, ssaBlock *b) {
  182. ssa_fprintf(f, "\"");
  183. ssa_print_escape_string(f, b->label);
  184. ssa_fprintf(f, " - %d", b->id);
  185. ssa_fprintf(f, "\"");
  186. }
  187. void ssa_print_value(gbFile *f, ssaModule *m, ssaValue *value, Type *type_hint) {
  188. if (value == NULL) {
  189. ssa_fprintf(f, "!!!NULL_VALUE");
  190. return;
  191. }
  192. switch (value->kind) {
  193. case ssaValue_Constant:
  194. ssa_print_exact_value(f, m, value->constant.value, type_hint);
  195. break;
  196. case ssaValue_TypeName:
  197. ssa_print_encoded_local(f, value->type_name.entity->token.string);
  198. break;
  199. case ssaValue_Global:
  200. ssa_print_encoded_global(f, value->global.entity->token.string);
  201. break;
  202. case ssaValue_Param:
  203. ssa_print_encoded_local(f, value->param.entity->token.string);
  204. break;
  205. case ssaValue_Proc:
  206. ssa_print_encoded_global(f, value->proc.entity->token.string);
  207. break;
  208. case ssaValue_Instr:
  209. ssa_fprintf(f, "%%%d", value->id);
  210. break;
  211. }
  212. }
  213. void ssa_print_instr(gbFile *f, ssaModule *m, ssaValue *value) {
  214. GB_ASSERT(value->kind == ssaValue_Instr);
  215. ssaInstr *instr = &value->instr;
  216. ssa_fprintf(f, "\t");
  217. switch (instr->kind) {
  218. case ssaInstr_Local: {
  219. Type *type = instr->local.entity->type;
  220. ssa_fprintf(f, "%%%d = alloca ", value->id);
  221. ssa_print_type(f, m->sizes, type);
  222. ssa_fprintf(f, ", align %lld ", type_align_of(m->sizes, gb_heap_allocator(), type));
  223. {
  224. String str = instr->local.entity->token.string;
  225. if (str.len > 0)
  226. ssa_fprintf(f, "; %.*s", LIT(instr->local.entity->token.string));
  227. }
  228. ssa_fprintf(f, "\n");
  229. ssa_fprintf(f, "\tstore ");
  230. ssa_print_type(f, m->sizes, type);
  231. ssa_fprintf(f, " zeroinitializer, ");
  232. ssa_print_type(f, m->sizes, type);
  233. ssa_fprintf(f, "* %%%d\n", value->id);
  234. } break;
  235. case ssaInstr_Store: {
  236. Type *type = ssa_value_type(instr->store.address);
  237. ssa_fprintf(f, "store ");
  238. ssa_print_type(f, m->sizes, type);
  239. ssa_fprintf(f, " ");
  240. ssa_print_value(f, m, instr->store.value, type);
  241. ssa_fprintf(f, ", ");
  242. ssa_print_type(f, m->sizes, type);
  243. ssa_fprintf(f, "* ");
  244. ssa_print_value(f, m, instr->store.address, type);
  245. ssa_fprintf(f, "\n");
  246. } break;
  247. case ssaInstr_Load: {
  248. Type *type = instr->load.type;
  249. ssa_fprintf(f, "%%%d = load ", value->id);
  250. ssa_print_type(f, m->sizes, type);
  251. ssa_fprintf(f, ", ");
  252. ssa_print_type(f, m->sizes, type);
  253. ssa_fprintf(f, "* ");
  254. ssa_print_value(f, m, instr->load.address, type);
  255. ssa_fprintf(f, "\n");
  256. } break;
  257. case ssaInstr_GetElementPtr: {
  258. Type *et = instr->get_element_ptr.element_type;
  259. ssa_fprintf(f, "%%%d = getelementptr ", value->id);
  260. if (instr->get_element_ptr.inbounds)
  261. ssa_fprintf(f, "inbounds ");
  262. ssa_print_type(f, m->sizes, et);
  263. ssa_fprintf(f, ", ");
  264. ssa_print_type(f, m->sizes, et);
  265. ssa_fprintf(f, "* ");
  266. ssa_print_value(f, m, instr->get_element_ptr.address, et);
  267. for (isize i = 0; i < instr->get_element_ptr.index_count; i++) {
  268. ssaValue *index = instr->get_element_ptr.indices[i];
  269. Type *t = ssa_value_type(index);
  270. ssa_fprintf(f, ", ");
  271. ssa_print_type(f, m->sizes, t);
  272. ssa_fprintf(f, " ");
  273. ssa_print_value(f, m, index, t);
  274. }
  275. ssa_fprintf(f, "\n");
  276. } break;
  277. case ssaInstr_Br: {
  278. ssa_fprintf(f, "br ");
  279. if (instr->br.cond != NULL) {
  280. ssa_print_type(f, m->sizes, t_bool);
  281. ssa_fprintf(f, " ");
  282. ssa_print_value(f, m, instr->br.cond, t_bool);
  283. ssa_fprintf(f, ", ", instr->br.cond->id);
  284. }
  285. ssa_fprintf(f, "label ");
  286. ssa_fprintf(f, "%%"); ssa_print_block_name(f, instr->br.true_block);
  287. if (instr->br.false_block != NULL) {
  288. ssa_fprintf(f, ", label ");
  289. ssa_fprintf(f, "%%"); ssa_print_block_name(f, instr->br.false_block);
  290. }
  291. ssa_fprintf(f, "\n");
  292. } break;
  293. case ssaInstr_Ret: {
  294. auto *ret = &instr->ret;
  295. ssa_fprintf(f, "ret ");
  296. if (ret->value == NULL) {
  297. ssa_fprintf(f, "void");
  298. } else {
  299. Type *t = ssa_value_type(ret->value);
  300. ssa_print_type(f, m->sizes, t);
  301. ssa_fprintf(f, " ");
  302. ssa_print_value(f, m, ret->value, t);
  303. }
  304. ssa_fprintf(f, "\n");
  305. } break;
  306. case ssaInstr_Unreachable: {
  307. ssa_fprintf(f, "unreachable\n");
  308. } break;
  309. case ssaInstr_BinaryOp: {
  310. auto *bo = &value->instr.binary_op;
  311. Type *type = ssa_value_type(bo->left);
  312. ssa_fprintf(f, "%%%d = ", value->id);
  313. if (gb_is_between(bo->op.kind, Token__ComparisonBegin+1, Token__ComparisonEnd-1)) {
  314. if (is_type_float(type)) {
  315. ssa_fprintf(f, "fcmp ");
  316. switch (bo->op.kind) {
  317. case Token_CmpEq: ssa_fprintf(f, "oeq"); break;
  318. case Token_NotEq: ssa_fprintf(f, "one"); break;
  319. case Token_Lt: ssa_fprintf(f, "olt"); break;
  320. case Token_Gt: ssa_fprintf(f, "ogt"); break;
  321. case Token_LtEq: ssa_fprintf(f, "ole"); break;
  322. case Token_GtEq: ssa_fprintf(f, "oge"); break;
  323. }
  324. } else {
  325. ssa_fprintf(f, "icmp ");
  326. if (bo->op.kind != Token_CmpEq &&
  327. bo->op.kind != Token_NotEq) {
  328. if (is_type_unsigned(type)) {
  329. ssa_fprintf(f, "u");
  330. } else {
  331. ssa_fprintf(f, "s");
  332. }
  333. }
  334. switch (bo->op.kind) {
  335. case Token_CmpEq: ssa_fprintf(f, "eq"); break;
  336. case Token_NotEq: ssa_fprintf(f, "ne"); break;
  337. case Token_Lt: ssa_fprintf(f, "lt"); break;
  338. case Token_Gt: ssa_fprintf(f, "gt"); break;
  339. case Token_LtEq: ssa_fprintf(f, "le"); break;
  340. case Token_GtEq: ssa_fprintf(f, "ge"); break;
  341. }
  342. }
  343. } else {
  344. if (is_type_float(type))
  345. ssa_fprintf(f, "f");
  346. switch (bo->op.kind) {
  347. case Token_Add: ssa_fprintf(f, "add"); break;
  348. case Token_Sub: ssa_fprintf(f, "sub"); break;
  349. case Token_And: ssa_fprintf(f, "and"); break;
  350. case Token_Or: ssa_fprintf(f, "or"); break;
  351. case Token_Xor: ssa_fprintf(f, "xor"); break;
  352. case Token_AndNot: GB_PANIC("Token_AndNot Should never be called");
  353. case Token_Mul: ssa_fprintf(f, "mul"); break;
  354. default: {
  355. if (!is_type_float(type)) {
  356. if (is_type_unsigned(type)) ssa_fprintf(f, "u");
  357. else ssa_fprintf(f, "s");
  358. }
  359. switch (bo->op.kind) {
  360. case Token_Quo: ssa_fprintf(f, "div"); break;
  361. case Token_Mod: ssa_fprintf(f, "rem"); break;
  362. }
  363. } break;
  364. }
  365. }
  366. ssa_fprintf(f, " ");
  367. ssa_print_type(f, m->sizes, type);
  368. ssa_fprintf(f, " ");
  369. ssa_print_value(f, m, bo->left, type);
  370. ssa_fprintf(f, ", ");
  371. ssa_print_value(f, m, bo->right, type);
  372. ssa_fprintf(f, "\n");
  373. } break;
  374. case ssaInstr_Call: {
  375. auto *call = &instr->call;
  376. if (call->type) {
  377. ssa_fprintf(f, "%%%d = ", value->id);
  378. }
  379. ssa_fprintf(f, "call ");
  380. if (call->type) {
  381. ssa_print_type(f, m->sizes, call->type);
  382. } else {
  383. ssa_fprintf(f, "void");
  384. }
  385. ssa_fprintf(f, " ");
  386. ssa_print_value(f, m, call->value, call->type);
  387. ssa_fprintf(f, "(");
  388. for (isize i = 0; i < call->arg_count; i++) {
  389. ssaValue *arg = call->args[i];
  390. Type *t = ssa_value_type(arg);
  391. if (i > 0) {
  392. ssa_fprintf(f, ", ");
  393. }
  394. ssa_print_type(f, m->sizes, t);
  395. ssa_fprintf(f, " ");
  396. ssa_print_value(f, m, arg, t);
  397. }
  398. ssa_fprintf(f, ")\n");
  399. } break;
  400. default:
  401. ssa_fprintf(f, "; <unknown instr> %d\n", instr->kind);
  402. break;
  403. }
  404. }
  405. void ssa_print_llvm_ir(gbFile *f, ssaModule *m) {
  406. if (m->layout.len > 0) {
  407. ssa_fprintf(f, "target datalayout = %.*s\n", LIT(m->layout));
  408. }
  409. gb_for_array(member_index, m->members.entries) {
  410. auto *entry = &m->members.entries[member_index];
  411. ssaValue *v = entry->value;
  412. switch (v->kind) {
  413. case ssaValue_TypeName: {
  414. ssa_print_encoded_local(f, v->type_name.entity->token.string);
  415. ssa_fprintf(f, " = type ");
  416. ssa_print_type(f, m->sizes, get_base_type(v->type_name.type));
  417. ssa_fprintf(f, "\n");
  418. } break;
  419. case ssaValue_Global: {
  420. auto *g = &v->global;
  421. ssa_print_encoded_global(f, g->entity->token.string);
  422. ssa_fprintf(f, " = ");
  423. if (g->is_constant) {
  424. ssa_fprintf(f, "private constant ");
  425. } else {
  426. ssa_fprintf(f, "global ");
  427. }
  428. ssa_print_type(f, m->sizes, get_base_type(g->entity->type));
  429. ssa_fprintf(f, " ");
  430. ssa_print_value(f, m, g->value, g->entity->type);
  431. ssa_fprintf(f, "\n");
  432. } break;
  433. case ssaValue_Proc: {
  434. ssaProcedure *proc = &v->proc;
  435. if (proc->body == NULL) {
  436. ssa_fprintf(f, "declare ");
  437. } else {
  438. ssa_fprintf(f, "define ");
  439. }
  440. auto *proc_type = &proc->entity->type->procedure;
  441. if (proc_type->result_count == 0) {
  442. ssa_fprintf(f, "void");
  443. } else {
  444. ssa_print_type(f, m->sizes, proc_type->results);
  445. }
  446. ssa_fprintf(f, " ");
  447. ssa_print_encoded_global(f, proc->name);
  448. ssa_fprintf(f, "(");
  449. if (proc_type->param_count > 0) {
  450. auto *params = &proc_type->params->tuple;
  451. for (isize i = 0; i < params->variable_count; i++) {
  452. Entity *e = params->variables[i];
  453. if (i > 0)
  454. ssa_fprintf(f, ", ");
  455. ssa_print_type(f, m->sizes, e->type);
  456. ssa_fprintf(f, " %%%.*s", LIT(e->token.string));
  457. }
  458. }
  459. ssa_fprintf(f, ") ");
  460. if (proc->body == NULL) {
  461. ssa_fprintf(f, "\n");
  462. } else {
  463. ssa_fprintf(f, "{\n");
  464. gb_for_array(i, proc->blocks) {
  465. ssaBlock *block = proc->blocks[i];
  466. if (i > 0) ssa_fprintf(f, "\n");
  467. ssa_print_block_name(f, block);
  468. ssa_fprintf(f, ":\n");
  469. gb_for_array(j, block->instrs) {
  470. ssaValue *value = block->instrs[j];
  471. ssa_print_instr(f, m, value);
  472. }
  473. }
  474. ssa_fprintf(f, "}\n\n");
  475. }
  476. } break;
  477. }
  478. }
  479. }