#ifndef BDL_IR_H #define BDL_IR_H typedef enum Operator { // Arithmetic ops. OP_ADD, OP_SUB, OP_MUL, OP_DIV, OP_MOD, // Load/store/copy operations. OP_LD8, OP_LD16, OP_LD32, OP_LD64, OP_ST8, OP_ST16, OP_ST32, OP_ST64, OP_CP8, OP_CP16, OP_CP32, OP_CP64, // Bit fiddling operations. OP_NOT, OP_AND, OP_OR, OP_XOR, OP_LSHIFT, OP_RSHIFT, OP_LROT, OP_RROT, // (Un)conditional jump operations. OP_LABEL, OP_JMP, OP_JMP_EQ, OP_JMP_NEQ, OP_JMP_GT, OP_JMP_LT, OP_JMP_GE, OP_JMP_LE, } Operator; typedef enum OperandType { OP_TYPE_REG, OP_TYPE_CONST, OP_TYPE_LABEL, } OperandType; #define NEW_REG() (Operand){ .type = OP_TYPE_REG, .id = reg_gen_id++ } #define NEW_LAB() (Operand){ .type = OP_TYPE_LABEL, .id = lab_gen_id++ } #define NEW_S64(C) (Operand){ .type = OP_TYPE_CONST, .constant.sval = (C) } #define EMIT_0(PROGRAM, LINE, OP, DST) do { \ Instruction inst = (Instruction){ \ .op = (OP), \ .dst = (DST), \ }; \ array_push((PROGRAM)->inst, inst); \ array_push((PROGRAM)->lines, (LINE)); \ } while(false); #define EMIT_1(PROGRAM, LINE, OP, DST, A) do { \ Instruction inst = (Instruction){ \ .op = (OP), \ .dst = (DST), \ .src_a = (A), \ }; \ array_push((PROGRAM)->inst, inst); \ array_push((PROGRAM)->lines, (LINE)); \ } while(false); #define EMIT_2(PROGRAM, LINE, OP, DST, A, B) do { \ Instruction inst = (Instruction){ \ .op = (OP), \ .dst = (DST), \ .src_a = (A), \ .src_b = (B), \ }; \ array_push((PROGRAM)->inst, inst); \ array_push((PROGRAM)->lines, (LINE)); \ } while(false); typedef struct Operand { OperandType type; union { // REG/LABEL size_t id; // s64 constant; struct { union { u64 uval; s64 sval; }; } constant; }; } Operand; typedef struct Instruction { Operator op; Operand dst; Operand src_a; Operand src_b; } Instruction; typedef struct LineInfo { size_t line; size_t col; } LineInfo; typedef struct ProgramBASM { Instruction *inst; LineInfo *lines; } ProgramBASM; Operand emit_basm(ProgramBASM *program, Node *node); #endif // BDL_IR_H