Cthulhu  0.2.10
Cthulhu compiler collection
emit.c
Go to the documentation of this file.
1 // SPDX-License-Identifier: LGPL-3.0-only
2 
4 
5 #include "base/util.h"
6 #include "c89.h"
7 
8 #include "cthulhu/ssa/ssa.h"
9 #include "cthulhu/tree/ops.h"
10 #include "io/io.h"
11 #include "notify/notify.h"
12 #include "std/str.h"
13 #include "std/map.h"
14 #include "std/set.h"
15 #include "std/vector.h"
16 #include "std/typed/vector.h"
17 
18 #include "os/os.h"
19 
20 #include "fs/fs.h"
21 
22 #include "arena/arena.h"
23 
24 #include "base/panic.h"
25 #include "core/macros.h"
26 
27 #include <limits.h>
28 
29 static int integer_fits_longlong(const mpz_t value)
30 {
31  // mini gmp doesnt have functions that take longlong so this is a bit of a hack
32  mpz_t max;
33  mpz_init_set_si(max, 2);
34  mpz_pow_ui(max, max, sizeof(long long) * CHAR_BIT - 1);
35  mpz_sub_ui(max, max, 1);
36 
37  mpz_t min;
38  mpz_init_set_si(min, 2);
39  mpz_pow_ui(min, min, sizeof(long long) * CHAR_BIT - 1);
40 
41  mpz_neg(min, min);
42 
43  return mpz_cmp(value, max) <= 0 && mpz_cmp(value, min) >= 0;
44 }
45 
46 static int integer_is_unsigned(const mpz_t value)
47 {
48  return mpz_sgn(value) >= 0;
49 }
50 
51 static c89_source_t *source_new(io_t *io, const char *path, arena_t *arena)
52 {
53  c89_source_t *source = ARENA_MALLOC(sizeof(c89_source_t), path, io, arena);
54  source->io = io;
55  source->path = path;
56  return source;
57 }
58 
59 static c89_source_t *header_for(c89_emit_t *emit, const ssa_module_t *mod, const char *path)
60 {
61  char *it = str_format(emit->arena, "include/%s.h", path);
62  fs_file_create(emit->fs, it);
63 
64  io_t *io = fs_open(emit->fs, it, eOsAccessWrite | eOsAccessTruncate);
65  c89_source_t *source = source_new(io, str_format(emit->arena, "%s.h", path), emit->arena);
66  map_set(emit->hdrmap, mod, source);
67  return source;
68 }
69 
70 static c89_source_t *source_for(c89_emit_t *emit, const ssa_module_t *mod, const char *path)
71 {
72  char *it = str_format(emit->arena, "src/%s.c", path);
73  fs_file_create(emit->fs, it);
74 
75  io_t *io = fs_open(emit->fs, it, eOsAccessWrite | eOsAccessTruncate);
76  c89_source_t *source = source_new(io, it, emit->arena);
77  map_set(emit->srcmap, mod, source);
78  return source;
79 }
80 
82 {
83  if (emit->layout == eFileLayoutPair)
84  return emit->source;
85 
86  c89_source_t *src = map_get(emit->srcmap, mod);
87  CTASSERTF(src != NULL, "no source for %s", mod->name);
88 
89  return src;
90 }
91 
93 {
94  if (emit->layout == eFileLayoutPair)
95  return emit->header;
96 
97  c89_source_t *src = map_get(emit->hdrmap, mod);
98  CTASSERTF(src != NULL, "no header for %s", mod->name);
99 
100  return src;
101 }
102 
104 {
105  c89_source_t *src = c89_get_header(emit, mod);
106  return src->io;
107 }
108 
110 {
111  c89_source_t *src = c89_get_source(emit, mod);
112  return src->io;
113 }
114 
115 // begin api
116 
117 static const char *format_path(const char *base, const char *name, arena_t *arena)
118 {
119  if (ctu_strlen(base) == 0) { return name; }
120  return str_format(arena, "%s/%s", base, name);
121 }
122 
123 static void collect_deps(c89_emit_t *emit, const ssa_module_t *mod, vector_t *symbols)
124 {
125  size_t len = vector_len(symbols);
126  for (size_t i = 0; i < len; i++)
127  {
128  const ssa_symbol_t *global = vector_get(symbols, i);
129  map_set(emit->modmap, global, (ssa_module_t*)mod);
130  }
131 }
132 
133 static void cplusplus_prelude(io_t *io)
134 {
135  io_printf(io,
136  "#ifdef __cplusplus\n"
137  "extern \"C\" {\n"
138  "#endif\n"
139  );
140 }
141 
142 static void cplusplus_epilogue(io_t *io)
143 {
144  io_printf(io,
145  "#ifdef __cplusplus\n"
146  "}\n"
147  "#endif\n"
148  );
149 }
150 
151 static void c89_begin_all(c89_emit_t *emit)
152 {
153  // TODO: use a user provided name
154  fs_file_create(emit->fs, "module.c");
155  fs_file_create(emit->fs, "module.h");
156 
157  io_t *src = fs_open(emit->fs, "module.c", eOsAccessWrite | eOsAccessTruncate);
158  io_t *hdr = fs_open(emit->fs, "module.h", eOsAccessWrite | eOsAccessTruncate);
159 
160  CTASSERTF(io_error(src) == eOsSuccess, "failed to open module.c (%s)", os_error_string(io_error(src), emit->arena));
161  CTASSERTF(io_error(hdr) == eOsSuccess, "failed to open module.h (%s)", os_error_string(io_error(hdr), emit->arena));
162 
163  vector_push(&emit->sources, (char*)"module.c");
164 
165  io_printf(src, "#include \"module.h\"\n");
166 
167  io_printf(hdr, "#pragma once\n");
168  io_printf(hdr, "#include <stdbool.h>\n");
169  io_printf(hdr, "#include <stdint.h>\n");
170  io_printf(hdr, "#include <stddef.h>\n");
171 
172  cplusplus_prelude(hdr);
173 
174  c89_source_t *src_file = source_new(src, "module.c", emit->arena);
175  c89_source_t *hdr_file = source_new(hdr, "module.h", emit->arena);
176 
177  emit->source = src_file;
178  emit->header = hdr_file;
179 }
180 
181 static void c89_end_all(c89_emit_t *emit)
182 {
183  c89_source_t *src = emit->source;
184  c89_source_t *hdr = emit->header;
185  cplusplus_epilogue(hdr->io);
186 
187  io_close(src->io);
188  io_close(hdr->io);
189 }
190 
191 static void c89_begin_module(c89_emit_t *emit, const ssa_module_t *mod)
192 {
193  // collect all symbols defined in this module
194  collect_deps(emit, mod, mod->globals);
195  collect_deps(emit, mod, mod->functions);
196 
197  // create source and header files
198  char *path = begin_module(&emit->emit, emit->fs, mod);
199 
200  const char *src_file = format_path(path, mod->name, emit->arena);
201  const char *hdr_file = format_path(path, mod->name, emit->arena);
202 
203  vector_push(&emit->sources, str_format(emit->arena, "src/%s.c", src_file));
204 
205  c89_source_t *src = source_for(emit, mod, src_file);
206  c89_source_t *hdr = header_for(emit, mod, hdr_file);
207 
208  io_printf(hdr->io, "#pragma once\n");
209  io_printf(hdr->io, "#include <stdbool.h>\n");
210  io_printf(hdr->io, "#include <stdint.h>\n");
211  io_printf(hdr->io, "#include <stddef.h>\n");
212 
213  cplusplus_prelude(hdr->io);
214 
215  io_printf(src->io, "#include \"%s.h\"\n", hdr_file);
216 }
217 
218 // emit api
219 
220 static const char *format_c89_link(tree_linkage_t linkage)
221 {
222  switch (linkage)
223  {
224  case eLinkImport: return "extern ";
225  case eLinkModule: return "static ";
226 
227  case eLinkExport:
228  case eLinkEntryCli:
229  case eLinkEntryGui:
230  return "";
231 
232  default: CT_NEVER("unknown linkage %d", linkage);
233  }
234 }
235 
236 static void get_required_headers(c89_emit_t *emit, set_t *requires, const ssa_module_t *root, vector_t *symbols)
237 {
238  size_t len = vector_len(symbols);
239  for (size_t i = 0; i < len; i++)
240  {
241  const ssa_symbol_t *global = vector_get(symbols, i);
242  set_t *deps = map_get(emit->deps, global);
243  if (deps == NULL) { continue; }
244 
245  set_iter_t iter = set_iter(deps);
246  while (set_has_next(&iter))
247  {
248  const ssa_symbol_t *dep = set_next(&iter);
249  const ssa_module_t *dep_mod = map_get(emit->modmap, dep);
250  if (dep_mod != root)
251  {
252  set_add(requires, dep_mod);
253  }
254  }
255  }
256 }
257 
258 static void emit_required_headers(c89_emit_t *emit, const ssa_module_t *mod)
259 {
260  // TODO: this is very coarse, we should only add deps to the headers
261  // for symbols that are externally visible
262 
263  size_t len = vector_len(mod->globals);
264  set_t *requires = set_new(CT_MAX(len, 1), kTypeInfoPtr, emit->arena); // set of modules required by this module
265 
266  get_required_headers(emit, requires, mod, mod->globals);
267  get_required_headers(emit, requires, mod, mod->functions);
268 
269  io_t *hdr = c89_get_header_io(emit, mod);
270  set_iter_t iter = set_iter(requires);
271  while (set_has_next(&iter))
272  {
273  const ssa_module_t *item = set_next(&iter);
274  c89_source_t *dep = c89_get_header(emit, item);
275  io_printf(hdr, "#include \"%s\"\n", dep->path);
276  }
277 }
278 
279 static const char *mangle_symbol_name(c89_emit_t *emit, const ssa_symbol_t *symbol)
280 {
281  switch (symbol->linkage)
282  {
283  case eLinkEntryCli: return "main";
284  case eLinkEntryGui: return "WinMain";
285  default: break;
286  }
287 
288  if (symbol->linkage_string != NULL) { return symbol->linkage_string; }
289 
290  if (symbol->name == NULL)
291  {
292  // this is an anonymous symbol, we need to generate a unique name
293  return get_anon_symbol_name(&emit->emit, symbol, "anon");
294  }
295 
296  return symbol->name;
297 }
298 
299 static bool is_entry_point(tree_linkage_t link)
300 {
301  return link == eLinkEntryCli || link == eLinkEntryGui;
302 }
303 
304 static const char *format_symbol(c89_emit_t *emit, const ssa_type_t *type, const char *name)
305 {
306  return c89_format_type(emit, type, name, eFormatEmitConst);
307 }
308 
309 char *c89_format_integer_literal(arena_t *arena, const mpz_t value)
310 {
311  if (mpz_fits_sint_p(value))
312  return mpz_get_str(NULL, 10, value);
313 
314  if (integer_fits_longlong(value))
315  return str_format(arena, "%sll", mpz_get_str(NULL, 10, value));
316 
317  // integer must be unsigned if we get this far
318  if (integer_is_unsigned(value))
319  return str_format(arena, "%sull", mpz_get_str(NULL, 10, value));
320 
321  CT_NEVER("integer literal %s is too large, this should be caught earlier", mpz_get_str(NULL, 10, value));
322 }
323 
324 static char *format_integer_value(arena_t *arena, const ssa_value_t *value)
325 {
326  mpz_t digit;
327  ssa_value_get_digit(value, digit);
328  return c89_format_integer_literal(arena, digit);
329 }
330 
331 static void define_enum(io_t *io, const ssa_type_t *type, c89_emit_t *emit)
332 {
333  // update c89_format_type eTypeEnum when this is changed
334  const ssa_type_enum_t it = type->sum;
335  size_t len = typevec_len(it.cases);
336  const ssa_type_t *underlying = it.underlying;
337  char *under = str_format(emit->arena, "%s_underlying_t", type->name);
338  const char *tydef = c89_format_type(emit, underlying, under, false);
339  io_printf(io, "typedef %s;\n", tydef);
340 
341  io_printf(io, "enum %s_cases_t { /* %zu cases */\n", type->name, len);
342  if (len == 0)
343  {
344  io_printf(io, "\te%s_empty = 0,\n", type->name);
345  }
346  else for (size_t i = 0; i < len; i++)
347  {
348  const ssa_case_t *field = typevec_offset(it.cases, i);
349 
350  // TODO: formalize the name mangling for enum fields
351  io_printf(io, "\te%s%s = %s,\n", type->name, field->name, c89_format_integer_literal(emit->arena, field->value));
352  }
353  io_printf(io, "};\n");
354 }
355 
356 static void c89_proto_aggregate(io_t *io, const char *ty, const char *name)
357 {
358  io_printf(io, "%s %s;\n", ty, name);
359 }
360 
361 void c89_proto_type(c89_emit_t *emit, io_t *io, const ssa_type_t *type)
362 {
363  switch (type->kind)
364  {
365  case eTypeStruct:
366  c89_proto_aggregate(io, "struct", type->name);
367  break;
368  case eTypeUnion:
369  c89_proto_aggregate(io, "union", type->name);
370  break;
371 
372  case eTypeEnum:
373  define_enum(io, type, emit);
374  break;
375 
376  default:
377  break; // TODO: how should we honor visiblity and aliases?
378  }
379 }
380 
381 static void write_global(c89_emit_t *emit, io_t *io, const ssa_symbol_t *global)
382 {
383  ssa_storage_t storage = global->storage;
384  const char *it = c89_format_storage(emit, global->storage, mangle_symbol_name(emit, global), (storage.quals & eQualConst) ? eFormatIsConst : eFormatEmitNone);
385  const char *link = format_c89_link(global->linkage);
386 
387  io_printf(io, "%s%s", link, it);
388 }
389 
390 void c89_proto_global(c89_emit_t *emit, const ssa_module_t *mod, const ssa_symbol_t *global)
391 {
392  if (global->visibility == eVisiblePublic)
393  {
394  CTASSERT(global->linkage != eLinkModule); // TODO: move this check into the checker
395 
396  io_t *io = c89_get_header_io(emit, mod);
397  write_global(emit, io, global);
398  io_printf(io, ";\n");
399  }
400  else
401  {
402  io_t *io = c89_get_source_io(emit, mod);
403  write_global(emit, io, global);
404  io_printf(io, ";\n");
405  }
406 }
407 
408 void c89_proto_function(c89_emit_t *emit, const ssa_module_t *mod, const ssa_symbol_t *symbol)
409 {
410  // dont generate prototypes for entry points
411  if (is_entry_point(symbol->linkage)) { return; }
412 
413  io_t *src = c89_get_source_io(emit, mod);
414  io_t *hdr = c89_get_header_io(emit, mod);
415 
416  const ssa_type_t *type = symbol->type;
417  CTASSERTF(type->kind == eTypeClosure, "expected closure type on %s, got %d", symbol->name, type->kind);
418 
419  ssa_type_closure_t closure = type->closure;
420  const char *params = c89_format_params(emit, closure.params, closure.variadic);
421  const char *result = format_symbol(emit, closure.result, mangle_symbol_name(emit, symbol));
422 
423  const char *link = format_c89_link(symbol->linkage);
424 
425  io_t *dst = symbol->visibility == eVisiblePublic ? hdr : src;
426  io_printf(dst, "%s%s(%s);\n", link, result, params);
427 }
428 
429 static void proto_symbols(c89_emit_t *emit, const ssa_module_t *mod, vector_t *vec, void (*fn)(c89_emit_t*, const ssa_module_t*, const ssa_symbol_t*))
430 {
431  size_t len = vector_len(vec);
432  for (size_t i = 0; i < len; i++)
433  {
434  const ssa_symbol_t *symbol = vector_get(vec, i);
435  fn(emit, mod, symbol);
436  }
437 }
438 
439 static void proto_module_types(c89_emit_t *emit, io_t *io, const vector_t *types)
440 {
441  size_t len = vector_len(types);
442  for (size_t i = 0; i < len; i++)
443  {
444  const ssa_type_t *type = vector_get(types, i);
445  c89_proto_type(emit, io, type);
446  }
447 }
448 
449 static void c89_proto_all_types(c89_emit_t *emit, const vector_t *modules)
450 {
451  // forward declare all types
452  c89_source_t *header = emit->header;
453  for (size_t i = 0; i < vector_len(modules); i++)
454  {
455  const ssa_module_t *mod = vector_get(modules, i);
456  proto_module_types(emit, header->io, mod->types);
457  }
458 }
459 
460 static void c89_proto_all_globals(c89_emit_t *emit, const vector_t *modules)
461 {
462  size_t len = vector_len(modules);
463  for (size_t i = 0; i < len; i++)
464  {
465  const ssa_module_t *mod = vector_get(modules, i);
466  proto_symbols(emit, mod, mod->globals, c89_proto_global);
467  }
468 }
469 
470 static void c89_proto_all_functions(c89_emit_t *emit, const vector_t *modules)
471 {
472  size_t len = vector_len(modules);
473  for (size_t i = 0; i < len; i++)
474  {
475  const ssa_module_t *mod = vector_get(modules, i);
476  proto_symbols(emit, mod, mod->functions, c89_proto_function);
477  }
478 }
479 
480 static void c89_proto_module(c89_emit_t *emit, const ssa_module_t *mod)
481 {
482  emit_required_headers(emit, mod);
483 
484  io_t *hdr = c89_get_header_io(emit, mod);
485  proto_module_types(emit, hdr, mod->types);
486 
487  proto_symbols(emit, mod, mod->globals, c89_proto_global);
488  proto_symbols(emit, mod, mod->functions, c89_proto_function);
489 }
490 
492 
493 static const ssa_type_t *get_operand_type(c89_emit_t *emit, ssa_operand_t operand)
494 {
495  switch (operand.kind)
496  {
497  case eOperandImm: {
498  const ssa_value_t *value = operand.value;
499  return value->type;
500  }
501  case eOperandLocal: {
502  const ssa_local_t *local = typevec_offset(emit->current->locals, operand.local);
503  return local->type;
504  }
505  case eOperandParam: {
506  const ssa_param_t *param = typevec_offset(emit->current->params, operand.param);
507  return param->type;
508  }
509  case eOperandGlobal: {
510  const ssa_symbol_t *global = operand.global;
511  return global->type;
512  }
513  case eOperandFunction: {
514  const ssa_symbol_t *func = operand.function;
515  return func->type;
516  }
517  case eOperandReg: {
518  const ssa_block_t *bb = operand.vreg_context;
519  const ssa_step_t *step = typevec_offset(bb->steps, operand.vreg_index);
520  const ssa_type_t *type = map_get(emit->stepmap, step);
521  return type;
522  }
523 
524  default: CT_NEVER("unknown operand kind %d", operand.kind);
525  }
526 }
527 
528 static void set_step_type(c89_emit_t *emit, const ssa_step_t *step, const ssa_type_t *type)
529 {
530  map_set(emit->stepmap, step, (ssa_type_t*)type);
531 }
532 
533 static const char *c89_name_vreg(c89_emit_t *emit, const ssa_step_t *step, const ssa_type_t *type)
534 {
535  set_step_type(emit, step, (ssa_type_t*)type);
536 
537  const char *id = str_format(emit->arena, "vreg%s", get_step_name(&emit->emit, step));
538  return format_symbol(emit, type, id);
539 }
540 
541 static const char *c89_name_vreg_by_operand(c89_emit_t *emit, const ssa_step_t *step, ssa_operand_t operand)
542 {
543  const ssa_type_t *type = get_operand_type(emit, operand);
544  return c89_name_vreg(emit, step, type);
545 }
546 
547 static const ssa_type_t *get_reg_type(const ssa_type_t *type)
548 {
549  switch (type->kind)
550  {
551  case eTypePointer: {
552  ssa_type_pointer_t pointer = type->pointer;
553  return pointer.pointer;
554  }
555 
556  default: CT_NEVER("expected storage or pointer type, got %s (on %s)", ssa_type_name(type->kind), type->name);
557  }
558 }
559 
560 static const char *c89_name_load_vreg_by_operand(c89_emit_t *emit, const ssa_step_t *step, ssa_operand_t operand)
561 {
562  const ssa_type_t *type = get_operand_type(emit, operand);
563  return c89_name_vreg(emit, step, get_reg_type(type));
564 }
565 
566 static const char *operand_type_string(c89_emit_t *emit, ssa_operand_t operand)
567 {
568  const ssa_type_t *type = get_operand_type(emit, operand);
569  return type_to_string(type, emit->arena);
570 }
571 
572 static const char *c89_format_value(c89_emit_t *emit, const ssa_value_t* value);
573 
574 static const char *c89_format_pointer(c89_emit_t *emit, const ssa_value_t *value)
575 {
576  if (value->value == eValueRelative)
577  {
578  ssa_relative_value_t relative = value->relative;
579  return str_format(emit->arena, "(%s)", relative.symbol->name);
580  }
581 
583  arena_t *arena = emit->arena;
584  size_t len = vector_len(literal.data);
585  vector_t *result = vector_of(len, arena);
586  for (size_t i = 0; i < len; i++)
587  {
588  const ssa_value_t *element = vector_get(literal.data, i);
589  const char *it = c89_format_value(emit, element);
590  vector_set(result, i, (char*)it);
591  }
592 
593  char *joined = str_join(", ", result, arena);
594  return str_format(arena, "{ %s }", joined);
595 }
596 
597 static const char *c89_format_opaque(c89_emit_t *emit, const ssa_value_t *value)
598 {
599  if (value->value == eValueLiteral)
600  {
601  ssa_literal_value_t literal = value->literal;
602  return str_format(emit->arena, "((void*)%s)", c89_format_integer_literal(emit->arena, literal.pointer));
603  }
604 
605  if (value->value == eValueRelative)
606  {
607  const ssa_relative_value_t *relative = &value->relative;
608  return str_format(emit->arena, "((void*)%s)", relative->symbol->name);
609  }
610 
611  CT_NEVER("unknown opaque value kind %d", value->value);
612 }
613 
614 static const char *c89_format_value(c89_emit_t *emit, const ssa_value_t* value)
615 {
616  const ssa_type_t *type = value->type;
617  switch (type->kind)
618  {
619  case eTypeBool:
620  return ssa_value_get_bool(value) ? "true" : "false";
621  case eTypeDigit:
622  return format_integer_value(emit->arena, value);
623  case eTypePointer: return c89_format_pointer(emit, value);
624  case eTypeOpaque: return c89_format_opaque(emit, value);
625  default: CT_NEVER("unknown type kind %d", type->kind);
626  }
627 }
628 
629 static const char *get_local_name(c89_emit_t *emit, const ssa_local_t *local)
630 {
631  if (local->name != NULL)
632  return str_format(emit->arena, "local_%s", local->name);
633 
634  return get_anon_local_name(&emit->emit, local, "local_");
635 }
636 
637 static const char *c89_format_local(c89_emit_t *emit, size_t local)
638 {
639  typevec_t *locals = emit->current->locals;
640  CTASSERTF(local < typevec_len(locals), "local(%zu) > locals(%zu)", local, typevec_len(locals));
641 
642  const ssa_local_t *it = typevec_offset(locals, local);
643  return get_local_name(emit, it);
644 }
645 
646 static const char *c89_format_param(c89_emit_t *emit, size_t param)
647 {
648  typevec_t *params = emit->current->params;
649  CTASSERTF(param < typevec_len(params), "param(%zu) > params(%zu)", param, typevec_len(params));
650 
651  const ssa_param_t *it = typevec_offset(params, param);
652  return it->name;
653 }
654 
655 static const char *c89_format_operand(c89_emit_t *emit, ssa_operand_t operand)
656 {
657  switch (operand.kind)
658  {
659  case eOperandEmpty: return "/* empty */";
660  case eOperandImm:
661  return c89_format_value(emit, operand.value);
662 
663  case eOperandBlock:
664  return str_format(emit->arena, "bb%s", get_block_name(&emit->emit, operand.bb));
665 
666  case eOperandReg:
667  return str_format(emit->arena, "vreg%s", get_step_from_block(&emit->emit, operand.vreg_context, operand.vreg_index));
668 
669  case eOperandGlobal:
670  return mangle_symbol_name(emit, operand.global);
671 
672  case eOperandFunction:
673  return mangle_symbol_name(emit, operand.function);
674 
675  case eOperandLocal:
676  return c89_format_local(emit, operand.local);
677 
678  case eOperandParam:
679  return c89_format_param(emit, operand.param);
680 
681  default: CT_NEVER("unknown operand kind %d", operand.kind);
682  }
683 }
684 
685 static bool operand_is_empty(ssa_operand_t operand)
686 {
687  return operand.kind == eOperandEmpty;
688 }
689 
690 static bool operand_cant_return(ssa_operand_t operand)
691 {
692  if (operand.kind == eOperandImm)
693  {
694  const ssa_value_t *value = operand.value;
695  const ssa_type_t *type = value->type;
696  return type->kind == eTypeUnit || type->kind == eTypeEmpty;
697  }
698 
699  return operand.kind == eOperandEmpty;
700 }
701 
702 static void c89_write_address(c89_emit_t *emit, io_t *io, const ssa_step_t *step)
703 {
704  ssa_addr_t addr = step->addr;
705  ssa_operand_t symbol = addr.symbol;
706  const ssa_type_t *type = get_operand_type(emit, symbol);
707 
708  const ssa_type_t *ptr = ssa_type_pointer(type->name, eQualNone, (ssa_type_t*)type, 0);
709  const char *step_name = c89_name_vreg(emit, step, ptr);
710 
711  io_printf(io, "\t%s = &(%s); /* %s */\n",
712  step_name,
713  c89_format_operand(emit, addr.symbol),
714  type_to_string(ptr, emit->arena)
715  );
716 }
717 
718 static void c89_write_offset(c89_emit_t *emit, io_t *io, const ssa_step_t *step)
719 {
720  ssa_offset_t offset = step->offset;
721  io_printf(io, "\t%s = &%s[%s]; /* (array = %s, offset = %s) */\n",
722  c89_name_vreg_by_operand(emit, step, offset.array),
723  c89_format_operand(emit, offset.array),
724  c89_format_operand(emit, offset.offset),
725  operand_type_string(emit, offset.array),
726  operand_type_string(emit, offset.offset)
727  );
728 }
729 
730 static const ssa_field_t *get_aggregate_field(c89_emit_t *emit, const ssa_type_t *type, size_t index)
731 {
732  CTASSERTF(type->kind == eTypeStruct, "expected record type, got %s", type_to_string(type, emit->arena));
733 
734  const ssa_type_record_t record = type->record;
735  return typevec_offset(record.fields, index);
736 }
737 
738 static void c89_write_member(c89_emit_t *emit, io_t *io, const ssa_step_t *step)
739 {
740  CTASSERTF(step->opcode == eOpMember, "expected member, got %s", ssa_opcode_name(step->opcode));
741 
742  ssa_member_t member = step->member;
743  const ssa_type_t *record_ptr = get_operand_type(emit, member.object);
744  CTASSERTF(record_ptr->kind == eTypePointer, "expected record type, got %s", type_to_string(record_ptr, emit->arena));
745 
746  ssa_type_pointer_t ptr = record_ptr->pointer;
747  const ssa_type_t *record = ptr.pointer;
748  CTASSERTF(record->kind == eTypeStruct, "expected record type, got %s", type_to_string(record, emit->arena));
749 
750  const ssa_field_t *field = get_aggregate_field(emit, record, member.index);
751 
752  io_printf(io, "\t%s = &%s->%s;\n",
753  c89_name_vreg(emit, step, ssa_type_pointer(field->name, eQualNone, (ssa_type_t*)field->type, 1)),
754  c89_format_operand(emit, member.object),
755  field->name
756  );
757 }
758 
759 static void c89_write_block(c89_emit_t *emit, io_t *io, const ssa_block_t *bb)
760 {
761  size_t len = typevec_len(bb->steps);
762  io_printf(io, "bb%s: { /* len = %zu */\n", get_block_name(&emit->emit, bb), len);
763  for (size_t i = 0; i < len; i++)
764  {
765  const ssa_step_t *step = typevec_offset(bb->steps, i);
766  switch (step->opcode)
767  {
768  case eOpNop:
769  io_printf(io, "\t/* nop */\n");
770  break;
771  case eOpValue: {
772  const ssa_value_t *value = step->value;
773  const char *name = c89_name_vreg(emit, step, value->type);
774  io_printf(io, "\t%s = %s;\n", name, c89_format_value(emit, value));
775  break;
776  }
777  case eOpStore: {
778  ssa_store_t store = step->store;
779  io_printf(io, "\t*(%s) = %s;\n",
780  c89_format_operand(emit, store.dst),
781  c89_format_operand(emit, store.src)
782  );
783  break;
784  }
785  case eOpCast: {
786  ssa_cast_t cast = step->cast;
787  io_printf(io, "\t%s = (%s)(%s);\n",
788  c89_name_vreg(emit, step, cast.type),
789  format_symbol(emit, cast.type, NULL),
790  c89_format_operand(emit, cast.operand)
791  );
792  break;
793  }
794  case eOpLoad: {
795  ssa_load_t load = step->load;
796  io_printf(io, "\t%s = *(%s);\n",
797  c89_name_load_vreg_by_operand(emit, step, load.src),
798  c89_format_operand(emit, load.src)
799  );
800  break;
801  }
802 
803  case eOpAddress:
804  c89_write_address(emit, io, step);
805  break;
806  case eOpOffset:
807  c89_write_offset(emit, io, step);
808  break;
809  case eOpMember:
810  c89_write_member(emit, io, step);
811  break;
812 
813  case eOpUnary: {
814  ssa_unary_t unary = step->unary;
815  io_printf(io, "\t%s = (%s %s);\n",
816  c89_name_vreg_by_operand(emit, step, unary.operand),
817  unary_symbol(unary.unary),
818  c89_format_operand(emit, unary.operand)
819  );
820  break;
821  }
822  case eOpBinary: {
823  ssa_binary_t bin = step->binary;
824  io_printf(io, "\t%s = (%s %s %s);\n",
825  c89_name_vreg_by_operand(emit, step, bin.lhs),
826  c89_format_operand(emit, bin.lhs),
827  binary_symbol(bin.binary),
828  c89_format_operand(emit, bin.rhs)
829  );
830  break;
831  }
832  case eOpCompare: {
833  ssa_compare_t cmp = step->compare;
834  io_printf(io, "\t%s = (%s %s %s);\n",
835  c89_name_vreg(emit, step, ssa_type_bool("bool", eQualConst)),
836  c89_format_operand(emit, cmp.lhs),
837  compare_symbol(cmp.compare),
838  c89_format_operand(emit, cmp.rhs)
839  );
840  break;
841  }
842 
843  case eOpCall: {
844  ssa_call_t call = step->call;
845  size_t args_len = typevec_len(call.args);
846 
847  const ssa_type_t *ty = get_operand_type(emit, call.function);
848  ssa_type_closure_t closure = ty->closure;
849  const ssa_type_t *result = closure.result;
850 
851  vector_t *args = vector_of(args_len, emit->arena);
852  for (size_t arg_idx = 0; arg_idx < args_len; arg_idx++)
853  {
854  const ssa_operand_t *operand = typevec_offset(call.args, arg_idx);
855  vector_set(args, arg_idx, (char*)c89_format_operand(emit, *operand));
856  }
857 
858  io_printf(io, "\t");
859 
860  if (result->kind != eTypeEmpty && result->kind != eTypeUnit)
861  {
862  io_printf(io, "%s = ", c89_name_vreg(emit, step, result));
863  }
864 
865  io_printf(io, "%s(%s);\n",
866  c89_format_operand(emit, call.function),
867  str_join(", ", args, emit->arena)
868  );
869  break;
870  }
871 
872  case eOpJump: {
873  ssa_jump_t jmp = step->jump;
874  io_printf(io, "\tgoto %s;\n", c89_format_operand(emit, jmp.target));
875  break;
876  }
877  case eOpBranch: {
878  ssa_branch_t br = step->branch;
879  io_printf(io, "\tif (%s) { goto %s; }", c89_format_operand(emit, br.cond), c89_format_operand(emit, br.then));
880  if (!operand_is_empty(br.other))
881  {
882  io_printf(io, " else { goto %s; }", c89_format_operand(emit, br.other));
883  }
884  io_printf(io, "\n");
885  break;
886  }
887  case eOpReturn: {
888  ssa_return_t ret = step->ret;
889  if (!operand_cant_return(ret.value))
890  {
891  io_printf(io, "\treturn %s;\n", c89_format_operand(emit, ret.value));
892  }
893  else
894  {
895  io_printf(io, "\treturn;\n");
896  }
897  break;
898  }
899 
900  case eOpSizeOf:
901  io_printf(io, "\t%s = sizeof(%s);\n",
902  c89_name_vreg(emit, step, ssa_type_digit("size_t", eQualConst, eSignUnsigned, eDigitSize)),
903  c89_format_type(emit, step->size_of.type, NULL, eFormatEmitNone)
904  );
905  break;
906 
907  case eOpAlignOf:
908  io_printf(io, "\t%s = alignof(%s);\n",
909  c89_name_vreg(emit, step, ssa_type_digit("size_t", eQualConst, eSignUnsigned, eDigitSize)),
910  c89_format_type(emit, step->align_of.type, NULL, eFormatEmitNone)
911  );
912  break;
913 
914  case eOpOffsetOf: {
915  ssa_offsetof_t offset = step->offset_of;
916  const ssa_field_t *field = get_aggregate_field(emit, offset.type, offset.index);
917  io_printf(io, "\t%s = offsetof(%s, %s);\n",
918  c89_name_vreg(emit, step, ssa_type_digit("size_t", eQualConst, eSignUnsigned, eDigitSize)),
919  c89_format_type(emit, step->offset_of.type, NULL, eFormatEmitNone),
920  field->name
921  );
922  break;
923  }
924 
925  default: CT_NEVER("unknown opcode %d", step->opcode);
926  }
927  }
928  io_printf(io, "} /* end %s */\n", get_block_name(&emit->emit, bb));
929 }
930 
932 
933 static void define_record(c89_emit_t *emit, const char *aggregate, io_t *io, const ssa_type_t *type)
934 {
935  const ssa_type_record_t record = type->record;
936  io_printf(io, "%s %s {\n", aggregate, type->name);
937  size_t len = typevec_len(record.fields);
938  for (size_t i = 0; i < len; i++)
939  {
940  const ssa_field_t *field = typevec_offset(record.fields, i);
941  io_printf(io, "\t%s;\n", format_symbol(emit, field->type, field->name));
942  }
943  io_printf(io, "};\n");
944 }
945 
946 void c89_define_type(c89_emit_t *emit, io_t *io, const ssa_type_t *type)
947 {
948  switch (type->kind)
949  {
950  case eTypeStruct:
951  define_record(emit, "struct", io, type);
952  break;
953  case eTypeUnion:
954  define_record(emit, "union", io, type);
955  break;
956 
957  default:
958  break;
959  }
960 }
961 
962 static void write_init(c89_emit_t *emit, io_t *io, const ssa_value_t *value)
963 {
964  const ssa_type_t *type = value->type;
965  const char *init = c89_format_value(emit, value);
966 
967  if (type->kind == eTypePointer)
968  {
969  io_printf(io, " = %s", init);
970  }
971  else
972  {
973  io_printf(io, " = { %s }", init);
974  }
975 }
976 
977 void c89_define_global(c89_emit_t *emit, const ssa_module_t *mod, const ssa_symbol_t *symbol)
978 {
979  io_t *src = c89_get_source_io(emit, mod);
980 
981  if (symbol->linkage != eLinkImport)
982  {
983  const ssa_value_t *value = symbol->value;
984  write_global(emit, src, symbol);
985  if (value->init)
986  {
987  write_init(emit, src, value);
988  }
989 
990  io_printf(src, ";\n");
991  }
992 }
993 
994 static bool is_type_pointer(const ssa_type_t *type)
995 {
996  return type->kind == eTypePointer || type->kind == eTypeOpaque || type->kind == eTypeClosure;
997 }
998 
999 static void write_locals(c89_emit_t *emit, io_t *io, typevec_t *locals)
1000 {
1001  size_t len = typevec_len(locals);
1002  for (size_t i = 0; i < len; i++)
1003  {
1004  const ssa_local_t *local = typevec_offset(locals, i);
1005  const char *name = get_local_name(emit, local);
1006 
1007  // TODO: this is a little bit of a hack, works around const locals
1008  // being assigned to at initialization
1010  ssa_storage_t storage = local->storage;
1011  if (!is_type_pointer(storage.type))
1012  flags = eFormatEmitNone;
1013 
1014  io_printf(io, "\t%s;\n",
1015  c89_format_storage(emit, local->storage, name, flags)
1016  );
1017  }
1018 }
1019 
1020 void c89_define_function(c89_emit_t *emit, const ssa_module_t *mod, const ssa_symbol_t *symbol)
1021 {
1022  io_t *src = c89_get_source_io(emit, mod);
1023 
1024  const ssa_type_t *type = symbol->type;
1025  CTASSERTF(type->kind == eTypeClosure, "expected closure type on %s, got %d", symbol->name, type->kind);
1026 
1027  ssa_type_closure_t closure = type->closure;
1028  const char *params = c89_format_params(emit, closure.params, closure.variadic);
1029 
1030  // TODO: handle -Werror=main when the entry point doesnt return int
1031  const char *result = format_symbol(emit, closure.result, mangle_symbol_name(emit, symbol));
1032 
1033  const char *link = format_c89_link(symbol->linkage);
1034 
1035  if (symbol->linkage != eLinkImport)
1036  {
1037  io_printf(src, "%s%s(%s) {\n", link, result, params);
1038  write_locals(emit, src, symbol->locals);
1039  io_printf(src, "\tgoto bb%s;\n", get_block_name(&emit->emit, symbol->entry));
1040  size_t len = vector_len(symbol->blocks);
1041  for (size_t i = 0; i < len; i++)
1042  {
1043  const ssa_block_t *bb = vector_get(symbol->blocks, i);
1044  c89_write_block(emit, src, bb);
1045  }
1046  io_printf(src, "}\n");
1047 
1048  map_reset(emit->stepmap);
1049  counter_reset(&emit->emit);
1050  }
1051 }
1052 
1053 static void define_symbols(
1054  c89_emit_t *emit,
1055  const ssa_module_t *mod,
1056  vector_t *vec,
1057  void (*fn)(c89_emit_t*, const ssa_module_t*, const ssa_symbol_t*)
1058 )
1059 {
1060  size_t len = vector_len(vec);
1061  for (size_t i = 0; i < len; i++)
1062  {
1063  const ssa_symbol_t *symbol = vector_get(vec, i);
1064  emit->current = symbol;
1065  fn(emit, mod, symbol);
1066  }
1067 }
1068 
1069 static void define_type_ordererd(c89_emit_t *emit, io_t *io, const ssa_type_t *type)
1070 {
1071  if (set_contains(emit->defined, type)) { return; }
1072  set_add(emit->defined, type);
1073 
1074  // TODO: this is probably a touch broken, types may be put into the wrong translation unit
1075  if (type->kind == eTypeStruct || type->kind == eTypeUnion)
1076  {
1077  // only match struct and union as they can have dependencies
1078  ssa_type_record_t record = type->record;
1079  size_t len = typevec_len(record.fields);
1080  for (size_t i = 0; i < len; i++)
1081  {
1082  const ssa_field_t *field = typevec_offset(record.fields, i);
1083  define_type_ordererd(emit, io, field->type);
1084  }
1085  }
1086 
1087  c89_define_type(emit, io, type);
1088 }
1089 
1090 static void c89_define_types(c89_emit_t *emit, io_t *io, vector_t *types)
1091 {
1092  size_t len = vector_len(types);
1093  for (size_t i = 0; i < len; i++)
1094  {
1095  const ssa_type_t *type = vector_get(types, i);
1096  define_type_ordererd(emit, io, type);
1097  }
1098 }
1099 
1100 static void c89_define_module(c89_emit_t *emit, const ssa_module_t *mod)
1101 {
1102  io_t *hdr = c89_get_header_io(emit, mod);
1103  c89_define_types(emit, hdr, mod->types);
1104  define_symbols(emit, mod, mod->globals, c89_define_global);
1105  define_symbols(emit, mod, mod->functions, c89_define_function);
1106 
1107  cplusplus_epilogue(hdr);
1108 }
1109 
1110 static void c89_define_all_types(c89_emit_t *emit, const vector_t *modules)
1111 {
1112  size_t len = vector_len(modules);
1113  for (size_t i = 0; i < len; i++)
1114  {
1115  const ssa_module_t *mod = vector_get(modules, i);
1116  c89_define_types(emit, emit->header->io, mod->types);
1117  }
1118 }
1119 
1120 static void c89_define_all_globals(c89_emit_t *emit, const vector_t *modules)
1121 {
1122  size_t len = vector_len(modules);
1123  for (size_t i = 0; i < len; i++)
1124  {
1125  const ssa_module_t *mod = vector_get(modules, i);
1126  define_symbols(emit, mod, mod->globals, c89_define_global);
1127  }
1128 }
1129 
1130 static void c89_define_all_functions(c89_emit_t *emit, const vector_t *modules)
1131 {
1132  size_t len = vector_len(modules);
1133  for (size_t i = 0; i < len; i++)
1134  {
1135  const ssa_module_t *mod = vector_get(modules, i);
1136  define_symbols(emit, mod, mod->functions, c89_define_function);
1137  }
1138 }
1139 
1141 {
1142  size_t len = vector_len(ssa->modules);
1143 
1144  arena_t *arena = runtime->arena;
1145  vector_t *modules = ssa->modules;
1146 
1147  c89_emit_t ctx = {
1148  .arena = arena,
1149  .emit = {
1150  .arena = arena,
1151  .reports = runtime->logger,
1152  .block_names = names_new(64, arena),
1153  .vreg_names = names_new(64, arena),
1154  .anon_names = names_new(64, arena),
1155  },
1156  .modmap = map_optimal(len * 2, kTypeInfoPtr, arena),
1157  .srcmap = map_optimal(len, kTypeInfoPtr, arena),
1158  .hdrmap = map_optimal(len, kTypeInfoPtr, arena),
1159 
1160  .stepmap = map_optimal(64, kTypeInfoPtr, arena),
1161  .defined = set_new(64, kTypeInfoPtr, arena),
1162 
1163  .fs = emit->fs,
1164  .deps = ssa->deps,
1165  .sources = vector_new(32, arena),
1166  .layout = emit->layout,
1167  };
1168 
1169  if (emit->layout == eFileLayoutPair)
1170  {
1171  c89_begin_all(&ctx);
1172 
1173  c89_proto_all_types(&ctx, modules);
1174  c89_proto_all_globals(&ctx, modules);
1175  c89_proto_all_functions(&ctx, modules);
1176 
1177  c89_define_all_types(&ctx, modules);
1178  c89_define_all_globals(&ctx, modules);
1179  c89_define_all_functions(&ctx, modules);
1180 
1181  c89_end_all(&ctx);
1182  }
1183  else
1184  {
1185  for (size_t i = 0; i < len; i++)
1186  {
1187  const ssa_module_t *mod = vector_get(modules, i);
1188  c89_begin_module(&ctx, mod);
1189  }
1190 
1191  for (size_t i = 0; i < len; i++)
1192  {
1193  const ssa_module_t *mod = vector_get(modules, i);
1194  c89_proto_module(&ctx, mod);
1195  }
1196 
1197  for (size_t i = 0; i < len; i++)
1198  {
1199  const ssa_module_t *mod = vector_get(modules, i);
1200  c89_define_module(&ctx, mod);
1201  }
1202  }
1203 
1204  emit_result_t result = {
1205  .files = ctx.sources,
1206  };
1207 
1208  return result;
1209 }
const char * c89_format_type(c89_emit_t *emit, const ssa_type_t *type, const char *name, type_format_t flags)
Definition: type.c:97
type_format_t
Definition: c89.h:47
@ eFormatEmitConst
Definition: c89.h:49
@ eFormatIsConst
Definition: c89.h:54
@ eFormatEmitNone
Definition: c89.h:48
const char * c89_format_storage(c89_emit_t *emit, ssa_storage_t storage, const char *name, type_format_t flags)
Definition: type.c:136
const char * c89_format_params(c89_emit_t *emit, typevec_t *params, bool variadic)
Definition: type.c:142
CT_NODISCARD STA_RET_STRING CT_OS_API char * os_error_string(os_error_t error, arena_t *arena)
convert an os error code to a string
Definition: os.c:56
io_t * c89_get_source_io(c89_emit_t *emit, const ssa_module_t *mod)
Definition: emit.c:109
c89_source_t * c89_get_source(c89_emit_t *emit, const ssa_module_t *mod)
Definition: emit.c:81
emit_result_t cfamily_ssa(target_runtime_t *runtime, const ssa_result_t *ssa, target_emit_t *emit)
Definition: emit.c:1140
c89_source_t * c89_get_header(c89_emit_t *emit, const ssa_module_t *mod)
Definition: emit.c:92
io_t * c89_get_header_io(c89_emit_t *emit, const ssa_module_t *mod)
Definition: emit.c:103
void c89_define_type(c89_emit_t *emit, io_t *io, const ssa_type_t *type)
Definition: emit.c:946
void c89_proto_global(c89_emit_t *emit, const ssa_module_t *mod, const ssa_symbol_t *global)
Definition: emit.c:390
void c89_proto_type(c89_emit_t *emit, io_t *io, const ssa_type_t *type)
Definition: emit.c:361
void c89_proto_function(c89_emit_t *emit, const ssa_module_t *mod, const ssa_symbol_t *symbol)
Definition: emit.c:408
void c89_define_function(c89_emit_t *emit, const ssa_module_t *mod, const ssa_symbol_t *symbol)
Definition: emit.c:1020
void c89_define_global(c89_emit_t *emit, const ssa_module_t *mod, const ssa_symbol_t *symbol)
Definition: emit.c:977
char * c89_format_integer_literal(arena_t *arena, const mpz_t value)
Definition: emit.c:309
CT_NODISCARD CT_PUREFN CT_BASE_API size_t ctu_strlen(const char *str)
get the length of a string not including the null terminator equivalent to strlen but with safety che...
Definition: util.c:87
CT_NODISCARD CT_FS_API io_t * fs_open(fs_t *fs, const char *path, os_access_t flags)
open a file at a given location in the filesystem
Definition: fs.c:254
CT_FS_API void fs_file_create(fs_t *fs, const char *path)
create a file
Definition: fs.c:176
CT_NODISCARD CT_STD_API map_t * map_optimal(size_t size, hash_info_t info, arena_t *arena)
create a new map with an optimal size
Definition: optimal.c:85
CT_STD_API void map_reset(map_t *map)
clear all key-value pairs from a map
Definition: map.c:386
CT_STD_API void map_set(map_t *map, const void *key, void *value)
set a key-value pair in a map
Definition: map.c:294
CT_NODISCARD CT_PUREFN CT_STD_API void * map_get(const map_t *map, const void *key)
get a value from a map
Definition: map.c:324
CT_NODISCARD CT_STD_API set_t * set_new(size_t size, hash_info_t info, arena_t *arena)
create a new set
Definition: set.c:51
CT_STD_API const void * set_add(set_t *set, const void *key)
add a key to a set
Definition: set.c:85
CT_NODISCARD CT_PUREFN CT_STD_API set_iter_t set_iter(set_t *set)
acquire a set iterator for a set
Definition: set.c:268
CT_NODISCARD CT_STD_API const void * set_next(set_iter_t *iter)
get the next item from a set iterator
Definition: set.c:288
CT_NODISCARD CT_PUREFN CT_STD_API bool set_contains(const set_t *set, const void *key)
check if a set contains a key
Definition: set.c:118
CT_NODISCARD CT_PUREFN CT_STD_API bool set_has_next(set_iter_t *iter)
check if a set iterator has more items
Definition: set.c:301
CT_NODISCARD CT_IO_API os_error_t io_error(const io_t *io)
get the last error from the io object
Definition: io.c:144
CT_IO_API os_error_t io_close(INOUT_NOTNULL io_t *io)
destroy an IO object
CT_IO_API size_t io_printf(io_t *io, STA_FORMAT_STRING const char *fmt,...)
printf to an io object
#define CT_MAX(L, R)
Definition: macros.h:34
#define ARENA_MALLOC(size, name, parent, arena)
allocate memory from a custom allocator
Definition: arena.h:392
#define CT_NEVER(...)
assert that a code path is never reached
Definition: panic.h:136
#define CTASSERT(expr)
assert a condition, prints the condition as a message
Definition: panic.h:130
#define CTASSERTF(expr,...)
assert a condition with a message and optional format arguments
Definition: panic.h:116
CT_CONSTFN CT_NODISCARD CT_SSA_API const char * ssa_type_name(STA_IN_RANGE(0, eTypeCount - 1) ssa_kind_t kind)
CT_CONSTFN CT_NODISCARD CT_SSA_API const char * ssa_opcode_name(STA_IN_RANGE(0, eOpCount - 1) ssa_opcode_t opcode)
CT_SSA_API bool ssa_value_get_bool(const ssa_value_t *value)
Definition: value.c:136
CT_SSA_API ssa_type_t * ssa_type_bool(const char *name, tree_quals_t quals)
Definition: type.c:37
CT_SSA_API ssa_type_t * ssa_type_pointer(const char *name, tree_quals_t quals, ssa_type_t *pointer, size_t length)
Definition: type.c:63
CT_SSA_API void ssa_value_get_digit(const ssa_value_t *value, OUT_NOTNULL mpz_t result)
CT_SSA_API ssa_type_t * ssa_type_digit(const char *name, tree_quals_t quals, sign_t sign, digit_t digit)
Definition: type.c:42
CT_SSA_API ssa_literal_value_t ssa_value_get_literal(const ssa_value_t *value)
Definition: value.c:128
CT_NODISCARD CT_STD_API char * str_join(const char *sep, const vector_t *parts, arena_t *arena)
join strings
Definition: str.c:274
CT_TREE_API const char * binary_symbol(binary_t op)
get the C symbol of a binary operator
Definition: ops.c:54
CT_TREE_API const char * unary_symbol(unary_t op)
get the C symbol of a unary operator
Definition: ops.c:30
CT_TREE_API const char * compare_symbol(compare_t op)
get the C symbol of a comparison operator
Definition: ops.c:78
tree_linkage_t
the linkage of a declaration
Definition: ops.h:72
CT_STD_API const hash_info_t kTypeInfoPtr
type information for a generic pointer this operates on the pointer itself and not the data it points...
Definition: typeinfo.c:41
CT_NODISCARD CT_PUREFN CT_STD_API size_t typevec_len(const typevec_t *vec)
get the length of a vector
Definition: vector.c:120
CT_NODISCARD CT_PUREFN CT_STD_API void * typevec_offset(const typevec_t *vec, size_t index)
get a pointer to the value at the given index
Definition: vector.c:191
CT_NODISCARD CT_PUREFN CT_STD_API void * vector_get(const vector_t *vector, size_t index)
get a value from a vector
Definition: vector.c:134
CT_NODISCARD CT_STD_API vector_t * vector_new(size_t size, arena_t *arena)
create a new vector with an initial capacity
Definition: vector.c:63
CT_NODISCARD CT_STD_API vector_t * vector_of(size_t len, arena_t *arena)
create a new vector with a specified length
Definition: vector.c:71
CT_STD_API void vector_push(vector_t **vector, void *value)
push a value onto the end of a vector
Definition: vector.c:108
CT_STD_API void vector_set(vector_t *vector, size_t index, void *value)
set a value in a vector
Definition: vector.c:125
CT_NODISCARD CT_PUREFN CT_STD_API size_t vector_len(const vector_t *vector)
get the length of a vector
Definition: vector.c:152
@ eOsSuccess
Definition: posix.h:24
STA_DECL char * str_format(arena_t *arena, const char *fmt,...)
Definition: str.c:97
an allocator object
Definition: arena.h:86
Definition: c89.h:17
map_t * modmap
Definition: c89.h:22
map_t * deps
Definition: c89.h:38
set_t * defined
Definition: c89.h:35
map_t * srcmap
Definition: c89.h:24
vector_t * sources
Definition: c89.h:39
const ssa_symbol_t * current
Definition: c89.h:31
emit_t emit
Definition: c89.h:20
arena_t * arena
Definition: c89.h:18
map_t * stepmap
Definition: c89.h:33
c89_source_t * header
Definition: c89.h:29
map_t * hdrmap
Definition: c89.h:25
fs_t * fs
Definition: c89.h:37
file_layout_t layout
Definition: c89.h:40
c89_source_t * source
Definition: c89.h:28
io_t * io
Definition: c89.h:12
const char * path
Definition: c89.h:13
io object implementation
Definition: impl.h:122
a set iterator handle
Definition: set.h:78
an unordered hash set
Definition: set.c:19
ssa_operand_t symbol
Definition: ssa.h:231
const ssa_type_t * type
Definition: ssa.h:290
binary_t binary
Definition: ssa.h:242
ssa_operand_t rhs
Definition: ssa.h:241
ssa_operand_t lhs
Definition: ssa.h:240
typevec_t * steps
Definition: ssa.h:330
ssa_operand_t then
Definition: ssa.h:277
ssa_operand_t other
Definition: ssa.h:278
ssa_operand_t cond
Definition: ssa.h:276
ssa_operand_t function
Definition: ssa.h:257
typevec_t * args
Definition: ssa.h:258
mpz_t value
Definition: ssa.h:122
const char * name
Definition: ssa.h:121
const ssa_type_t * type
Definition: ssa.h:253
ssa_operand_t operand
Definition: ssa.h:252
ssa_operand_t rhs
Definition: ssa.h:247
ssa_operand_t lhs
Definition: ssa.h:246
compare_t compare
Definition: ssa.h:248
const ssa_type_t * type
Definition: ssa.h:108
const char * name
Definition: ssa.h:107
ssa_operand_t target
Definition: ssa.h:282
ssa_operand_t src
Definition: ssa.h:227
const char * name
Definition: ssa.h:97
const ssa_type_t * type
Definition: ssa.h:98
ssa_storage_t storage
Definition: ssa.h:95
size_t index
Definition: ssa.h:268
ssa_operand_t object
Definition: ssa.h:267
vector_t * types
vector<ssa_type_t> all types used by this module
Definition: ssa.h:357
vector_t * functions
vector<ssa_symbol_t> all functions declared/imported/exported by this module
Definition: ssa.h:359
vector_t * globals
vector<ssa_symbol_t> all globals declared/imported/exported by this module
Definition: ssa.h:358
const char * name
Definition: ssa.h:355
ssa_operand_t offset
Definition: ssa.h:263
ssa_operand_t array
Definition: ssa.h:262
size_t index
Definition: ssa.h:295
const ssa_type_t * type
Definition: ssa.h:294
size_t param
Definition: ssa.h:208
const ssa_value_t * value
Definition: ssa.h:217
size_t local
Definition: ssa.h:205
const ssa_block_t * vreg_context
Definition: ssa.h:200
ssa_opkind_t kind
Definition: ssa.h:192
const ssa_symbol_t * function
Definition: ssa.h:214
const ssa_symbol_t * global
Definition: ssa.h:211
const ssa_block_t * bb
Definition: ssa.h:196
size_t vreg_index
Definition: ssa.h:201
const char * name
Definition: ssa.h:90
const ssa_type_t * type
Definition: ssa.h:91
vector_t * modules
Definition: ssa.h:363
map_t * deps
Definition: ssa.h:364
ssa_operand_t value
Definition: ssa.h:272
const ssa_type_t * type
Definition: ssa.h:286
ssa_offset_t offset
Definition: ssa.h:314
ssa_store_t store
Definition: ssa.h:303
ssa_call_t call
Definition: ssa.h:312
ssa_unary_t unary
Definition: ssa.h:307
ssa_alignof_t align_of
Definition: ssa.h:322
ssa_binary_t binary
Definition: ssa.h:308
ssa_load_t load
Definition: ssa.h:304
const ssa_value_t * value
Definition: ssa.h:302
ssa_branch_t branch
Definition: ssa.h:318
ssa_opcode_t opcode
Definition: ssa.h:299
ssa_addr_t addr
Definition: ssa.h:305
ssa_return_t ret
Definition: ssa.h:317
ssa_offsetof_t offset_of
Definition: ssa.h:323
ssa_jump_t jump
Definition: ssa.h:319
ssa_member_t member
Definition: ssa.h:315
ssa_compare_t compare
Definition: ssa.h:309
ssa_cast_t cast
Definition: ssa.h:311
ssa_sizeof_t size_of
Definition: ssa.h:321
ssa underlying storage type
Definition: ssa.h:78
tree_quals_t quals
the qualifiers of the storage
Definition: ssa.h:86
const ssa_type_t * type
the internal storage type
Definition: ssa.h:80
ssa_operand_t src
Definition: ssa.h:223
ssa_operand_t dst
Definition: ssa.h:222
ssa_block_t * entry
entry block
Definition: ssa.h:349
const ssa_type_t * type
the public facing type of this symbol
Definition: ssa.h:341
vector_t * blocks
vector_t<ssa_block_t *>
Definition: ssa.h:351
ssa_storage_t storage
the backing storage for this symbol
Definition: ssa.h:342
tree_visibility_t visibility
Definition: ssa.h:336
typevec_t * params
typevec_t<ssa_type_t>
Definition: ssa.h:347
const char * linkage_string
external name
Definition: ssa.h:338
const ssa_value_t * value
the value of this symbol, must always be set for globals
Definition: ssa.h:344
typevec_t * locals
typevec_t<ssa_type_t>
Definition: ssa.h:346
tree_linkage_t linkage
Definition: ssa.h:335
const char * name
internal name
Definition: ssa.h:340
const ssa_type_t * result
Definition: ssa.h:131
bool variadic
Definition: ssa.h:133
typevec_t * params
Definition: ssa.h:132
typevec_t * cases
Definition: ssa.h:127
ssa_type_t * underlying
Definition: ssa.h:126
const ssa_type_t * pointer
Definition: ssa.h:137
typevec_t * fields
Definition: ssa.h:142
ssa_kind_t kind
Definition: ssa.h:146
ssa_type_record_t record
Definition: ssa.h:154
ssa_type_closure_t closure
Definition: ssa.h:152
ssa_type_enum_t sum
Definition: ssa.h:155
const char * name
Definition: ssa.h:148
ssa_type_pointer_t pointer
Definition: ssa.h:153
unary_t unary
Definition: ssa.h:236
ssa_operand_t operand
Definition: ssa.h:235
ssa_literal_value_t literal
Definition: ssa.h:184
bool init
whether this value has been initialized
Definition: ssa.h:180
ssa_value_state_t value
Definition: ssa.h:179
const ssa_type_t * type
Definition: ssa.h:178
ssa_relative_value_t relative
Definition: ssa.h:187
fs_t * fs
Definition: broker.h:311
file_layout_t layout
Definition: broker.h:309
arena_t * arena
Definition: broker.h:302
logger_t * logger
Definition: broker.h:304
A vector with a fixed type size.
Definition: vector.h:24
a generic vector of pointers
Definition: vector.c:16
char * get_anon_symbol_name(emit_t *emit, const ssa_symbol_t *symbol, const char *prefix)
Definition: common.c:93
void counter_reset(emit_t *emit)
Definition: common.c:49
names_t names_new(size_t size, arena_t *arena)
Definition: common.c:39
char * begin_module(emit_t *emit, fs_t *fs, const ssa_module_t *mod)
Definition: common.c:17
char * get_step_name(emit_t *emit, const ssa_step_t *step)
Definition: common.c:72
char * get_anon_local_name(emit_t *emit, const ssa_local_t *local, const char *prefix)
Definition: common.c:98
char * get_block_name(emit_t *emit, const ssa_block_t *block)
Definition: common.c:77
char * get_step_from_block(emit_t *emit, const ssa_block_t *block, size_t index)
Definition: common.c:103
const char * type_to_string(const ssa_type_t *type, arena_t *arena)
Definition: common.c:176
vector_t * data
Definition: ssa.h:167
mpz_t pointer
Definition: ssa.h:170
const ssa_symbol_t * symbol
Definition: ssa.h:174