#pragma once #include #include // IR uses an unlimited number of registers. This will later be fixed by a regalloc. enum instype { INS_ADD, // r0 = r1 + r2 INS_SUB, // r0 = r1 - r2 INS_MUL, // r0 = r1 * r2 INS_DIV, // r0 = r1 / r2 INS_MOD, // r0 = r1 % r2 INS_NEG, // r0 = -r1 INS_NOT, // r0 = ~r1 INS_TEST, // r1 & r2 (flags) INS_PUSH, // push r1 INS_POP, // r0 = pop INS_CMP, // r1 - r2 (flags) INS_LBL, // label name INS_JMP, // jmp name INS_JCC, // if condcode, jmp name INS_CALL, // call name INS_CALLV, // r0 = call name INS_RET, // return INS_RETV, // return r1 INS_MOV, // r0 = r1 INS_BRK, // halt INS_HWI, // hwi r1 }; enum condcode { CCZ, CCNZ, CCL, CCG, CCLE, CCGE }; enum reftype { REF_REG, // reg REF_MEM, // [reg + offset + {0, .data, heap base}[rel]] REF_IMM, // imm // This can only appear in user-entered asm literals and will be eliminated in the compiler. // It should refer to a symbol that is in scope, otherwise an error will be reported. REF_VARNAME, // name }; enum refrel { REFREL_ZERO, REFREL_DATA, REFREL_HEAP, }; #define REG_UNUSED (-1) #define REG_A (-10) #define REG_B (-11) #define REG_C (-12) #define REG_D (-13) #define REG_X (-14) #define REG_Y (-15) #define REG_SP (-16) #define REG_BP (-17) struct ref { enum reftype type; int reg; // >=0 for temporary or one of the REG_ constants int offset; enum refrel rel; int imm; const char *name; // should be a return value from ir_str() }; struct irins { enum instype type; union { struct ref three_refs[3]; struct {struct ref r0, r1, r2;}; }; const char *name; // should be a return value from ir_str() enum condcode condcode; }; struct ir { int cap, len; struct irins **inss; int globspace; }; struct ir* ir_make(void); void ir_delete(struct ir *ir); void ir_print(struct ir *ir, FILE *f); void irins_print(struct irins *ins, FILE *f); const char* condcode_show(enum condcode condcode); const char* ref_show(struct ref ref); // returns pointer to static buffer const char* ir_str(const char *str); // returns interned string // returns offset in .data segment struct ref ir_reserve_global(struct ir *ir, int size); void ir_insert_before(struct ir *ir, int pos, struct irins *ins); void ir_append(struct ir *ir, struct irins *ins); struct irins* irins_make(enum instype type); struct irins* irins_make_name(enum instype type, const char *name); struct irins* irins_make_0(enum instype type, struct ref r0); struct irins* irins_make_01(enum instype type, struct ref r0, struct ref r1); struct irins* irins_make_012(enum instype type, struct ref r0, struct ref r1, struct ref r2); struct irins* irins_make_1(enum instype type, struct ref r1); struct irins* irins_make_12(enum instype type, struct ref r1, struct ref r2); struct irins* irins_make_jcc(const char *name, enum condcode condcode); void irins_delete(struct irins *ins); void irins_which_refs(const struct irins *ins, bool haveref[3]); const char* gen_label_name(void); struct ref ref_reg(int reg); struct ref ref_mem(int reg, int offset, enum refrel rel); struct ref ref_imm(int imm); struct ref ref_varname(const char *name); struct ref ref_next_register(void); bool ref_equal(struct ref r1, struct ref r2);