Cthulhu  0.2.10
Cthulhu compiler collection
ssa.c
Go to the documentation of this file.
1 #include "cthulhu/ssa/ssa.h"
2 #include "base/panic.h"
3 #include "base/util.h"
4 #include "debug/target.h"
5 
6 #include "common.h"
7 
9 
10 #include "fs/fs.h"
11 #include "io/io.h"
12 #include "notify/notify.h"
13 
14 #include "core/macros.h"
15 
16 #include "std/map.h"
17 #include "std/set.h"
18 #include "std/str.h"
19 #include "std/typed/vector.h"
20 #include "std/vector.h"
21 
22 typedef struct ssa_emit_t
23 {
25 
26  fs_t *fs;
28 } ssa_emit_t;
29 
30 static char *fn_params_to_string(typevec_t *params, arena_t *arena)
31 {
32  size_t len = typevec_len(params);
33  vector_t *vec = vector_of(len, arena);
34  for (size_t i = 0; i < len; i++)
35  {
36  const ssa_param_t *param = typevec_offset(params, i);
37  const char *ty = type_to_string(param->type, arena);
38  vector_set(vec, i, str_format(arena, "%s: %s", param->name, ty));
39  }
40 
41  return str_join(", ", vec, arena);
42 }
43 
44 static vector_t *join_attribs(const ssa_symbol_t *symbol, arena_t *arena)
45 {
46  vector_t *attribs = vector_new(2, arena);
47 
48  if (symbol->linkage_string != NULL)
49  {
50  vector_push(&attribs, str_format(arena, "extern = `%s`", symbol->linkage_string));
51  }
52 
53  vector_push(&attribs, str_format(arena, "linkage = %s", linkage_string(symbol->linkage)));
54  vector_push(&attribs, str_format(arena, "visibility = %s", visibility_string(symbol->visibility)));
55 
56  return attribs;
57 }
58 
59 static void emit_ssa_attribs(io_t *io, const ssa_symbol_t *symbol, arena_t *arena)
60 {
61  io_printf(io, "\t[%s]\n", str_join(", ", join_attribs(symbol, arena), arena));
62 }
63 
64 static const char *value_to_string(const ssa_value_t *value, arena_t *arena);
65 
66 static const char *pointer_value_to_string(const ssa_value_t *value, arena_t *arena)
67 {
69  size_t len = vector_len(literal.data);
70  vector_t *parts = vector_new(16, arena);
71  for (size_t i = 0; i < CT_MIN(len, 16); i++)
72  {
73  const ssa_value_t *elem = vector_get(literal.data, i);
74  const char *it = value_to_string(elem, arena);
75  vector_push(&parts, (char*)it);
76  }
77 
78  if (len > 16) { vector_push(&parts, "..."); }
79 
80  char *joined = str_join(", ", parts, arena);
81  return str_format(arena, "[%s]", joined);
82 }
83 
84 static const char *value_to_string(const ssa_value_t *value, arena_t *arena)
85 {
86  if (!value->init) { return "noinit"; }
87 
88  const ssa_type_t *type = value->type;
89  switch (type->kind)
90  {
91  case eTypeDigit: return mpz_get_str(NULL, 10, ssa_value_get_literal(value).digit);
92  case eTypeBool: return ssa_value_get_bool(value) ? "true" : "false";
93  case eTypeUnit: return "unit";
94  case eTypeEmpty: return "empty";
95  case eTypePointer: return pointer_value_to_string(value, arena);
96 
97  default: CT_NEVER("unknown type kind %d", type->kind);
98  }
99 }
100 
101 static const char *operand_to_string(ssa_emit_t *emit, ssa_operand_t operand)
102 {
103  emit_t *base = &emit->emit;
104  arena_t *arena = base->arena;
105  switch (operand.kind)
106  {
107  case eOperandEmpty: return "empty";
108  case eOperandBlock:
109  return str_format(arena, ".%s", get_block_name(&emit->emit, operand.bb));
110  case eOperandImm:
111  return str_format(arena, "$%s", value_to_string(operand.value, arena));
112  case eOperandReg:
113  return str_format(arena, "%%%s", get_step_from_block(&emit->emit, operand.vreg_context, operand.vreg_index));
114  case eOperandGlobal: {
115  const ssa_symbol_t *symbol = operand.global;
116  return str_format(arena, "@%s", symbol->name);
117  }
118  case eOperandFunction: {
119  const ssa_symbol_t *symbol = operand.function;
120  return str_format(arena, "::%s", symbol->name);
121  }
122  case eOperandLocal: {
123  size_t index = operand.local;
124  return str_format(arena, "local(%zu)", index);
125  }
126  case eOperandParam: {
127  size_t index = operand.param;
128  return str_format(arena, "param(%zu)", index);
129  }
130  default: CT_NEVER("unknown operand kind %d", operand.kind);
131  }
132 }
133 
134 static void emit_ssa_block(ssa_emit_t *emit, io_t *io, const ssa_block_t *bb)
135 {
136  emit_t *base = &emit->emit;
137  size_t len = typevec_len(bb->steps);
138  io_printf(io, ".%s: [len=%zu]\n", get_block_name(&emit->emit, bb), len);
139  for (size_t i = 0; i < len; i++)
140  {
141  const ssa_step_t *step = typevec_offset(bb->steps, i);
142  switch (step->opcode)
143  {
144  case eOpValue:
145  io_printf(io, "\t%%%s = const %s\n",
146  get_step_name(&emit->emit, step),
147  value_to_string(step->value, base->arena)
148  );
149  break;
150  case eOpNop:
151  io_printf(io, "\tnop\n");
152  break;
153  case eOpUnary: {
154  ssa_unary_t unary = step->unary;
155  io_printf(io, "\t%%%s = unary %s %s\n",
156  get_step_name(&emit->emit, step),
157  unary_name(unary.unary),
158  operand_to_string(emit, unary.operand)
159  );
160  break;
161  }
162  case eOpBinary: {
163  ssa_binary_t binary = step->binary;
164  io_printf(io, "\t%%%s = binary %s %s %s\n",
165  get_step_name(&emit->emit, step),
166  binary_name(binary.binary),
167  operand_to_string(emit, binary.lhs),
168  operand_to_string(emit, binary.rhs)
169  );
170  break;
171  }
172  case eOpCast: {
173  ssa_cast_t cast = step->cast;
174  io_printf(io, "\t%%%s = cast %s %s\n",
175  get_step_name(&emit->emit, step),
176  type_to_string(cast.type, base->arena),
177  operand_to_string(emit, cast.operand)
178  );
179  break;
180  }
181  case eOpLoad: {
182  ssa_load_t load = step->load;
183  io_printf(io, "\t%%%s = load %s\n",
184  get_step_name(&emit->emit, step),
185  operand_to_string(emit, load.src)
186  );
187  break;
188  }
189  case eOpOffset: {
190  ssa_offset_t offset = step->offset;
191  io_printf(io, "\t%%%s = offset %s %s\n",
192  get_step_name(&emit->emit, step),
193  operand_to_string(emit, offset.array),
194  operand_to_string(emit, offset.offset)
195  );
196  break;
197  }
198  case eOpMember: {
199  ssa_member_t member = step->member;
200  io_printf(io, "\t%%%s = member %s.%zu\n",
201  get_step_name(&emit->emit, step),
202  operand_to_string(emit, member.object),
203  member.index
204  );
205  break;
206  }
207  case eOpAddress: {
208  ssa_addr_t addr = step->addr;
209  io_printf(io, "\t%%%s = addr %s\n",
210  get_step_name(&emit->emit, step),
211  operand_to_string(emit, addr.symbol)
212  );
213  break;
214  }
215  case eOpReturn: {
216  ssa_return_t ret = step->ret;
217  io_printf(io, "\tret %s\n", operand_to_string(emit, ret.value));
218  break;
219  }
220  case eOpJump: {
221  ssa_jump_t jmp = step->jump;
222  io_printf(io, "\tjump %s\n", operand_to_string(emit, jmp.target));
223  break;
224  }
225  case eOpStore: {
226  ssa_store_t store = step->store;
227  io_printf(io, "\tstore %s %s\n",
228  operand_to_string(emit, store.dst),
229  operand_to_string(emit, store.src)
230  );
231  break;
232  }
233  case eOpCall: {
234  ssa_call_t call = step->call;
235  size_t args_len = typevec_len(call.args);
236  vector_t *args = vector_of(args_len, base->arena);
237  for (size_t arg_idx = 0; arg_idx < args_len; arg_idx++)
238  {
239  const ssa_operand_t *arg = typevec_offset(call.args, arg_idx);
240  vector_set(args, arg_idx, (char*)operand_to_string(emit, *arg));
241  }
242  io_printf(io, "\t%%%s = call %s (%s)\n",
243  get_step_name(&emit->emit, step),
244  operand_to_string(emit, call.function),
245  str_join(", ", args, base->arena)
246  );
247  break;
248  }
249  case eOpBranch: {
250  ssa_branch_t branch = step->branch;
251  io_printf(io, "\tbranch %s %s %s\n",
252  operand_to_string(emit, branch.cond),
253  operand_to_string(emit, branch.then),
254  operand_to_string(emit, branch.other)
255  );
256  break;
257  }
258  case eOpCompare: {
259  ssa_compare_t compare = step->compare;
260  io_printf(io, "\t%%%s = compare %s %s %s\n",
261  get_step_name(&emit->emit, step),
262  compare_name(compare.compare),
263  operand_to_string(emit, compare.lhs),
264  operand_to_string(emit, compare.rhs)
265  );
266  break;
267  }
268  case eOpSizeOf: {
269  ssa_sizeof_t size_of = step->size_of;
270  io_printf(io, "\t%%%s = sizeof %s\n",
271  get_step_name(&emit->emit, step),
272  type_to_string(size_of.type, base->arena)
273  );
274  break;
275  }
276  case eOpAlignOf: {
277  ssa_alignof_t align_of = step->align_of;
278  io_printf(io, "\t%%%s = alignof %s\n",
279  get_step_name(&emit->emit, step),
280  type_to_string(align_of.type, base->arena)
281  );
282  break;
283  }
284  case eOpOffsetOf: {
285  ssa_offsetof_t offset_of = step->offset_of;
286  io_printf(io, "\t%%%s = offsetof %s %zu\n",
287  get_step_name(&emit->emit, step),
288  type_to_string(offset_of.type, base->arena),
289  offset_of.index
290  );
291  break;
292  }
293 
294  default:
295  CT_NEVER("unknown opcode %d", step->opcode);
296  }
297  }
298 }
299 
300 static void emit_ssa_blocks(ssa_emit_t *emit, io_t *io, vector_t *bbs)
301 {
302  size_t len = vector_len(bbs);
303  for (size_t i = 0; i < len; i++)
304  {
305  const ssa_block_t *bb = vector_get(bbs, i);
306  emit_ssa_block(emit, io, bb);
307  }
308 }
309 
310 static const char *storage_to_string(ssa_storage_t storage, arena_t *arena)
311 {
312  const char *ty = type_to_string(storage.type, arena);
313  const char *quals = quals_string(storage.quals);
314 
315  return str_format(arena, "{type = %s, quals = %s, size = %zu}", ty, quals, storage.size);
316 }
317 
318 static void emit_ssa_locals(ssa_emit_t *emit, io_t *io, typevec_t *locals)
319 {
320  emit_t *base = &emit->emit;
321  size_t len = typevec_len(locals);
322  for (size_t i = 0; i < len; i++)
323  {
324  const ssa_local_t *local = typevec_offset(locals, i);
325  io_printf(io, "\tlocal[%zu] %s %s\n", i, type_to_string(local->type, base->arena), storage_to_string(local->storage, base->arena));
326  }
327 }
328 
329 static void emit_symbol_deps(io_t *io, const ssa_symbol_t *symbol, map_t *deps)
330 {
331  set_t *all = map_get(deps, symbol);
332  if (all != NULL)
333  {
334  io_printf(io, "deps: (");
335  set_iter_t iter = set_iter(all);
336  while (set_has_next(&iter))
337  {
338  const ssa_symbol_t *dep = set_next(&iter);
339  io_printf(io, "%s", dep->name);
340 
341  if (set_has_next(&iter)) { io_printf(io, ", "); }
342  }
343  io_printf(io, ")\n");
344  }
345 }
346 
347 static void debug_emit_module(ssa_emit_t *emit, const ssa_module_t *mod)
348 {
349  fs_t *fs = emit->fs;
350  emit_t *base = &emit->emit;
351  char *path = begin_module(&emit->emit, fs, mod);
352 
353  char *file = str_format(base->arena, "%s/%s.ssa", path, mod->name);
354  fs_file_create(fs, file);
355  vector_push(&base->files, file);
356 
357  io_t *io = fs_open(fs, file, eOsAccessWrite | eOsAccessTruncate);
358  io_printf(io, "module {name=%s", mod->name);
359  if (ctu_strlen(path) > 0) { io_printf(io, ", path=%s", path); }
360  io_printf(io, "}\n");
361 
362  io_printf(io, "\n");
363 
364  size_t len = vector_len(mod->globals);
365  for (size_t i = 0; i < len; i++)
366  {
367  const ssa_symbol_t *global = vector_get(mod->globals, i);
368  emit_symbol_deps(io, global, emit->deps);
369 
370  io_printf(io, "global %s: %s\n", global->name, type_to_string(global->type, base->arena));
371  emit_ssa_attribs(io, global, base->arena);
372 
373  emit_ssa_blocks(emit, io, global->blocks);
374 
375  if (len >= i) { io_printf(io, "\n"); }
376  }
377 
378  size_t fns = vector_len(mod->functions);
379  for (size_t i = 0; i < fns; i++)
380  {
381  const ssa_symbol_t *fn = vector_get(mod->functions, i);
382  emit_symbol_deps(io, fn, emit->deps);
383 
384  const ssa_type_t *type = fn->type;
385  CTASSERTF(type->kind == eTypeClosure, "fn %s is not a closure", fn->name);
386  ssa_type_closure_t closure = type->closure;
387 
388  io_printf(io, "fn %s(%s) -> %s [variadic: %s]\n",
389  fn->name,
390  fn_params_to_string(closure.params, base->arena), type_to_string(closure.result, base->arena),
391  closure.variadic ? "true" : "false"
392  );
393  emit_ssa_attribs(io, fn, base->arena);
394 
395  if (fn->linkage != eLinkImport)
396  {
397  emit_ssa_locals(emit, io, fn->locals);
398  emit_ssa_blocks(emit, io, fn->blocks);
399  }
400 
401  if (len >= i) { io_printf(io, "\n"); }
402  }
403 }
404 
406 {
407  arena_t *arena = runtime->arena;
408  ssa_emit_t emit = {
409  .emit = {
410  .arena = arena,
411  .reports = runtime->logger,
412  .block_names = names_new(64, arena),
413  .vreg_names = names_new(64, arena),
414  .files = vector_new(16, arena),
415  },
416  .fs = target->fs,
417  .deps = ssa->deps,
418  };
419 
420  size_t len = vector_len(ssa->modules);
421  for (size_t i = 0; i < len; i++)
422  {
423  const ssa_module_t *mod = vector_get(ssa->modules, i);
424  debug_emit_module(&emit, mod);
425  }
426 
427  emit_result_t result = {
428  .files = emit.emit.files
429  };
430 
431  return result;
432 }
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_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_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_has_next(set_iter_t *iter)
check if a set iterator has more items
Definition: set.c:301
CT_IO_API size_t io_printf(io_t *io, STA_FORMAT_STRING const char *fmt,...)
printf to an io object
#define CT_MIN(L, R)
Definition: macros.h:38
#define CT_NEVER(...)
assert that a code path is never reached
Definition: panic.h:136
#define CTASSERTF(expr,...)
assert a condition with a message and optional format arguments
Definition: panic.h:116
CT_SSA_API bool ssa_value_get_bool(const ssa_value_t *value)
Definition: value.c:136
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_name(binary_t op)
get the pretty name of a binary operator
Definition: ops.c:42
CT_TREE_API const char * linkage_string(tree_linkage_t link)
get the name of a linkage
Definition: ops.c:141
CT_TREE_API const char * quals_string(tree_quals_t quals)
get the name of a set of qualifiers
Definition: ops.c:109
CT_TREE_API const char * visibility_string(tree_visibility_t vis)
get the name of visibility
Definition: ops.c:153
CT_TREE_API const char * compare_name(compare_t op)
get the pretty name of a comparison operator
Definition: ops.c:66
CT_TREE_API const char * unary_name(unary_t op)
get the pretty name of a unary operator
Definition: ops.c:18
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
STA_DECL char * str_format(arena_t *arena, const char *fmt,...)
Definition: str.c:97
an allocator object
Definition: arena.h:86
vector_t * files
Definition: broker.h:224
target code emitter options
Definition: common.h:16
arena_t * arena
arena to use
Definition: common.h:17
vector_t * files
Definition: common.h:23
Definition: common.h:72
io object implementation
Definition: impl.h:122
an unordered hash map
Definition: map.h:38
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
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
Definition: ssa.c:23
emit_t emit
Definition: ssa.c:24
fs_t * fs
Definition: ssa.c:26
map_t * deps
Definition: ssa.c:27
ssa_operand_t target
Definition: ssa.h:282
ssa_operand_t src
Definition: ssa.h:227
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 * 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
size_t size
the number of elements in the storage
Definition: ssa.h:83
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
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
tree_visibility_t visibility
Definition: ssa.h:336
const char * linkage_string
external name
Definition: ssa.h:338
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
ssa_kind_t kind
Definition: ssa.h:146
ssa_type_closure_t closure
Definition: ssa.h:152
unary_t unary
Definition: ssa.h:236
ssa_operand_t operand
Definition: ssa.h:235
bool init
whether this value has been initialized
Definition: ssa.h:180
const ssa_type_t * type
Definition: ssa.h:178
fs_t * fs
Definition: broker.h:311
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
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_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
emit_result_t debug_ssa(target_runtime_t *runtime, const ssa_result_t *ssa, target_emit_t *target)
Definition: ssa.c:405
vector_t * data
Definition: ssa.h:167