#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, T_PTR } TypeKind; typedef struct Type { TypeLevel lvl; TypeKind 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 */ #define NODE_TYPE_LIST\ X(NONE, "invalid node")\ X(DEAD, "dead node")\ X(START, "start")\ X(IF_ELSE, "if-else")\ X(REGION, "region")\ X(PHI, "phi")\ X(STOP, "stop")\ X(PROJ, "projection")\ X(RETURN, "return")\ X(KEEPALIVE, "keepalive")\ X(LIT, "literal")\ X(OP_ADD, "add")\ X(OP_SUB, "sub")\ X(OP_MUL, "mul")\ X(OP_DIV, "div")\ X(OP_AND, "and")\ X(OP_OR, "or")\ X(OP_XOR, "xor")\ X(OP_SHL, "shl")\ X(OP_SHR, "shr")\ X(OP_NEG, "neg")\ X(OP_NOT, "not")\ X(CMP_EQL, "equal")\ X(CMP_NEQ, "not-equal")\ X(CMP_LES, "less-than")\ X(CMP_GTR, "greater-than")\ X(CMP_LTE, "less-or-equal")\ X(CMP_GTE, "greater-or-equal") typedef enum { #define X(n, name) N_##n, NODE_TYPE_LIST #undef X N_MAX } NodeType; #define NMASK(n) (1L << n) typedef enum { #define X(n, name) NM_##n = NMASK(N_##n), NODE_TYPE_LIST #undef X } NodeMask; 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 op; LexSpan src_pos; NodeInputs in; /* note: index 0 used for control flow */ NodeOutputs out; union { Type type; Value val; }; }; }; } Node; /* convenience macros (lisp-inspired lol) */ #define IN(n, i) ((n)->in.data[i]) #define OUT(n, i) ((n)->out.data[i]) #define CTRL(n) IN(n, 0) #define CAR(n) IN(n, 1) #define CDR(n) IN(n, 2) #define CAAR(n) CAR(CAR(n)) #define CADR(n) CDR(CAR(n)) #define CDAR(n) CAR(CDR(n)) #define CDDR(n) CDR(CDR(n)) #define CAAAR(n) CAR(CAAR(n)) #define CAADR(n) CDR(CAAR(n)) #define CADAR(n) CAR(CADR(n)) #define CADDR(n) CDR(CADR(n)) #define CDAAR(n) CAR(CDAR(n)) #define CDADR(n) CDR(CDAR(n)) #define CDDAR(n) CAR(CDDR(n)) #define CDDDR(n) CDR(CDDR(n)) #define T(a,b) ((a)->op == b) #define T2(a,b,t) ((a)->op == t && (b)->op == t) /* 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; Type ret_type; 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_set_in(Proc *p, Node *n, int idx, Node *to); 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(NameBinding *b, 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