#ifndef IR_H #define IR_H #include "arena.h" #include "dynarr.h" #include "lex.h" /* for error reporting only */ #include "str.h" /* types */ typedef enum { T_TOP, /* may or may not be a constant */ T_CONST, /* known compile-time constant */ T_BOT, /* known not a constant */ T_CTRL, /* control flow bottom */ T_XCTRL, /* control flow top (dead) */ } TypeLevel; typedef enum { T_NONE, T_TUPLE, T_BOOL, T_INT } BaseType; typedef struct Type { TypeLevel lvl; BaseType t; struct Type *next; } Type; typedef struct Value { Type type; union { int64_t i; uint64_t u; DYNARR(struct Value) tuple; }; } Value; struct Node; int type_eql(Type *a, Type *b); int type_base_eql(Type *a, Type *b); int value_eql(Value *a, Value *b); int type_check(struct Node *n); Str type_desc(Type *t, Arena *arena); void type_err(struct Node *n, Lexer *l); /* nodes */ typedef enum { N_NONE, N_START, N_IF_ELSE, N_REGION, N_PHI, N_STOP, N_PROJ, N_RETURN, N_KEEPALIVE, N_LIT, N_OP_ADD, N_OP_SUB, N_OP_MUL, N_OP_DIV, N_OP_AND, N_OP_OR, N_OP_XOR, N_OP_SHL, N_OP_SHR, N_OP_NEG, N_OP_NOT, N_CMP_EQL, N_CMP_NEQ, N_CMP_LES, N_CMP_GTR, N_CMP_LTE, N_CMP_GTE, N_VALUE } NodeType; const char *node_type_name(NodeType t); typedef DYNARR(struct Node *) NodeList; typedef NodeList NodeInputs, NodeOutputs; typedef struct Node { int id, refs; union { struct Node *prev_free; struct { int walked; NodeType type; LexSpan src_pos; NodeInputs in; /* note: index 0 used for control flow */ NodeOutputs out; Value val; }; }; } Node; /* procedure graph */ typedef struct NameBinding { struct NameBinding *prev; LexSpan src_pos; Str name; Node *node; } NameBinding; typedef struct ScopeFrame { struct ScopeFrame *prev; NameBinding *latest; } ScopeFrame; typedef struct { ScopeFrame *tail, *free_scope; NameBinding *free_bind; } Scope; typedef struct { Str name; Node *node; } ScopeName; typedef DYNARR(ScopeName) ScopeNameList; typedef struct { Arena arena; Str name; Node *start, *stop, *ctrl, *keepalive; Node *free_list; Scope scope; } Proc; #define NODE_KEEP(p, n, ...)\ do { Node *keep_node = n;\ node_add_out(p, keep_node, p->keepalive); __VA_ARGS__;\ node_del_out(keep_node, p->keepalive); } while(0) void node_kill(Node *n, Proc *p); void node_die(Node *n, Proc *p); void node_del_out(Node *n, Node *p); void node_del_in(Node *n, Node *p); void node_kill(Node *n, Proc *p); void node_add(Proc *p, Node *src, Node *dest); void node_add_out(Proc *p, Node *a, Node *b); void node_add_in(Proc *p, Node *a, Node *b); void node_remove(Proc *p, Node *src, Node *dest); Node *node_new_empty(Proc *p, NodeType t); Node *node_newv(Proc *p, NodeType t, Node *ctrl, ...); Node *node_dedup_lit(Proc *p, Value v); Value node_compute(Node *n, Lexer *l); Node *node_peephole(Node *n, Proc *p, Lexer *l); Node *node_new_lit(Proc *p, Value v); Node *node_new_lit_bool(Proc *p, int b); Node *node_new_lit_i64(Proc *p, int64_t i); #define node_new(...) node_newv(__VA_ARGS__, NULL) void proc_init(Proc *proc, Str name); void proc_free(Proc *proc); ScopeFrame *scope_push(Scope *scope, Proc *proc); ScopeFrame *scope_pop(Scope *scope, Proc *proc); NameBinding *scope_find(Scope *scope, Str name); NameBinding *scope_bind(Scope *scope, Str name, Node *value, LexSpan pos, Proc *proc); NameBinding *scope_update(Scope *scope, Str name, Node *to, Proc *proc); void scope_collect(Scope *scope, Proc *proc, ScopeNameList *nl, Arena *arena); void scope_uncollect(Scope *scope, Proc *proc, ScopeNameList *nl); #endif