#ifndef IR_H #define IR_H #include "arena.h" #include "dynarr.h" #include "lex.h" /* for error reporting only */ #include "str.h" #include "typ.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 { /* TODO: maybe move type to end for alignment reasons */ Type type; union { int64_t i; uint64_t u; /* TODO: * maybe can use a slice instead of dynamic array, save 8 bytes */ 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); void type_check(struct Node *n, Lexer *l); Str type_desc(Type *t, Arena *arena); void type_err(struct Node *n, Lexer *l); void type_expected(Type *want, 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(UNINIT, "uninitialized value")\ 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 struct { u32 len, cap; union { struct Node *sbo; struct Node **data; }; } NodeList; typedef struct Node { union { struct Node *prev_free; struct { NodeList in; /* note: index 0 used for control flow */ NodeList out; int walked; LexSpan src_pos; union { Type type; Value val; }; }; }; int id; NodeType op; } Node; /* convenience macros (lisp-inspired lol) */ #define Ni(nl, i) (*nodelist_nth(&(nl), i)) #define IN(n, i) Ni(n->in, i) #define OUT(n, i) Ni(n->out, 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) /* node graph */ typedef struct { Arena *arena; Node *free_list; } NodePool; typedef struct { /* pointer so that e.g. there can be one pool per worker thread, * instead of one per procedure graph */ NodePool *pool; Node *start, *stop, *ctrl, *keepalive; } Graph; #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, Graph *p); void node_die(Node *n, Graph *p); void node_del_out(Node *n, Node *p); void node_del_in(Node *n, Node *p); void node_kill(Node *n, Graph *p); void node_add(Graph *p, Node *src, Node *dest); void node_add_out(Graph *p, Node *a, Node *b); void node_add_in(Graph *p, Node *a, Node *b); void node_set_in(Graph *p, Node *n, int idx, Node *to); void node_remove(Graph *p, Node *src, Node *dest); Node *node_new_empty(Graph *p, NodeType t); Node *node_newv(Graph *p, NodeType t, Node *ctrl, ...); Node *node_dedup_lit(Graph *p, Value v); Node *node_new_lit(Graph *p, Value v); Node *node_new_lit_bool(Graph *p, int b); Node *node_new_lit_i64(Graph *p, int64_t i); int node_uninit(Node *n); int node_maybe_uninit(Node *n); #define node_new(...) node_newv(__VA_ARGS__, NULL) static inline Node **nodelist_data(NodeList *l) { return l->cap ? l->data : &l->sbo; } static inline Node **nodelist_nth(NodeList *l, uint32_t i) { return nodelist_data(l) + i; } #endif