diff --git a/src/implementation.h b/src/implementation.h index 9c482d3..50f865b 100644 --- a/src/implementation.h +++ b/src/implementation.h @@ -381,9 +381,6 @@ DECLARE_PTR_LIST(proc_list, struct proc); enum opcode { op_nop, op_ret, - op_loadk, - op_loadnil, - op_loadbool, op_add, op_addff, op_addfi, @@ -457,6 +454,10 @@ enum opcode { op_cbr, op_br, op_mov, + op_movi, + op_movif, /* int to float if compatible else error */ + op_movf, + op_movfi, /* float to int if compatible else error */ op_call, op_get, op_get_ikey, diff --git a/src/linearizer.c b/src/linearizer.c index 4b9953b..86a8c12 100644 --- a/src/linearizer.c +++ b/src/linearizer.c @@ -42,8 +42,8 @@ static void instruct_br(struct proc *proc, struct pseudo *pseudo); static bool is_block_terminated(struct basic_block *block); static struct pseudo *instruct_move(struct proc *proc, enum opcode op, struct pseudo *target, struct pseudo *src); static void linearize_function(struct linearizer_state *linearizer); -static struct instruction* allocate_instruction(struct proc* proc, enum opcode op); -static void free_temp_pseudo(struct proc* proc, struct pseudo* pseudo); +static struct instruction *allocate_instruction(struct proc *proc, enum opcode op); +static void free_temp_pseudo(struct proc *proc, struct pseudo *pseudo); /** * Allocates a register by reusing a free'd register if possible otherwise @@ -122,14 +122,14 @@ void raviX_destroy_linearizer(struct linearizer_state *linearizer) /** * We assume strings are all interned and can be compared by - * address + * address. Return true if values match else false. */ static int compare_constants(const void *a, const void *b) { const struct constant *c1 = (const struct constant *)a; const struct constant *c2 = (const struct constant *)b; if (c1->type != c2->type) - return 1; + return 0; if (c1->type == RAVI_TNUMINT) return c1->i == c2->i; else if (c1->type == RAVI_TNUMFLT) @@ -166,7 +166,7 @@ static const struct constant *add_constant(struct proc *proc, const struct const memcpy(c1, c, sizeof(struct constant)); c1->index = reg; set_add(proc->constants, c1); - // printf("Created new constant and assigned reg %d\n", reg); + // printf("Created new constant of type %d and assigned reg %d\n", c->type, reg); return c1; } else { const struct constant *c1 = entry->key; @@ -198,48 +198,48 @@ static const struct constant *allocate_integer_constant(struct proc *proc, int i return add_constant(proc, &c); } -static inline void add_instruction_operand(struct proc* proc, struct instruction* insn, struct pseudo* pseudo) +static inline void add_instruction_operand(struct proc *proc, struct instruction *insn, struct pseudo *pseudo) { - ptrlist_add((struct ptr_list**) & insn->operands, pseudo, &proc->linearizer->ptrlist_allocator); + ptrlist_add((struct ptr_list **)&insn->operands, pseudo, &proc->linearizer->ptrlist_allocator); } -static inline void add_instruction_target(struct proc* proc, struct instruction* insn, struct pseudo* pseudo) +static inline void add_instruction_target(struct proc *proc, struct instruction *insn, struct pseudo *pseudo) { - ptrlist_add((struct ptr_list**) & insn->targets, pseudo, &proc->linearizer->ptrlist_allocator); + ptrlist_add((struct ptr_list **)&insn->targets, pseudo, &proc->linearizer->ptrlist_allocator); } -static struct instruction* allocate_instruction(struct proc* proc, enum opcode op) +static struct instruction *allocate_instruction(struct proc *proc, enum opcode op) { - struct instruction* insn = raviX_allocator_allocate(&proc->linearizer->instruction_allocator, 0); + struct instruction *insn = raviX_allocator_allocate(&proc->linearizer->instruction_allocator, 0); insn->opcode = op; return insn; } -static void free_instruction_operand_pseudos(struct proc* proc, struct instruction* insn) +static void free_instruction_operand_pseudos(struct proc *proc, struct instruction *insn) { - struct pseudo* operand; + struct pseudo *operand; FOR_EACH_PTR_REVERSE(insn->operands, operand) { free_temp_pseudo(proc, operand); } END_FOR_EACH_PTR_REVERSE(operand) } -static inline void add_instruction(struct proc* proc, struct instruction* insn) +static inline void add_instruction(struct proc *proc, struct instruction *insn) { assert(insn->block == NULL || insn->block == proc->current_bb); - ptrlist_add((struct ptr_list**) & proc->current_bb->insns, insn, &proc->linearizer->ptrlist_allocator); + ptrlist_add((struct ptr_list **)&proc->current_bb->insns, insn, &proc->linearizer->ptrlist_allocator); insn->block = proc->current_bb; } -static inline void remove_instruction(struct basic_block* block, struct instruction* insn) +static inline void remove_instruction(struct basic_block *block, struct instruction *insn) { - ptrlist_remove((struct ptr_list**) & block->insns, insn, 1); + ptrlist_remove((struct ptr_list **)&block->insns, insn, 1); insn->block = NULL; } -static inline struct instruction* last_instruction(struct basic_block* block) +static inline struct instruction *last_instruction(struct basic_block *block) { - if (ptrlist_size((struct ptr_list*)block->insns) == 0) + if (ptrlist_size((struct ptr_list *)block->insns) == 0) return NULL; - return (struct instruction*)ptrlist_last((struct ptr_list*)block->insns); + return (struct instruction *)ptrlist_last((struct ptr_list *)block->insns); } static const struct constant *allocate_string_constant(struct proc *proc, const struct string_object *s) @@ -419,27 +419,42 @@ static inline void set_current_proc(struct linearizer_state *linearizer, struct linearizer->current_proc = proc; } -static void instruct_totype(struct proc* proc, struct pseudo* target, const struct var_type* vtype) +static void instruct_totype(struct proc *proc, struct pseudo *target, const struct var_type *vtype) { enum opcode targetop = op_nop; switch (vtype->type_code) { - case RAVI_TNUMFLT: targetop = op_toflt; break; - case RAVI_TNUMINT: targetop = op_toint; break; - case RAVI_TSTRING: targetop = op_tostring; break; - case RAVI_TFUNCTION: targetop = op_toclosure; break; - case RAVI_TTABLE: targetop = op_totable; break; - case RAVI_TARRAYFLT: targetop = op_tofarray; break; - case RAVI_TARRAYINT: targetop = op_toiarray; break; - case RAVI_TUSERDATA: targetop = op_totype; + case RAVI_TNUMFLT: + targetop = op_toflt; + break; + case RAVI_TNUMINT: + targetop = op_toint; + break; + case RAVI_TSTRING: + targetop = op_tostring; + break; + case RAVI_TFUNCTION: + targetop = op_toclosure; + break; + case RAVI_TTABLE: + targetop = op_totable; + break; + case RAVI_TARRAYFLT: + targetop = op_tofarray; + break; + case RAVI_TARRAYINT: + targetop = op_toiarray; + break; + case RAVI_TUSERDATA: + targetop = op_totype; break; default: return; } - struct instruction* insn = allocate_instruction(proc, targetop); + struct instruction *insn = allocate_instruction(proc, targetop); if (targetop == op_totype) { assert(vtype->type_name); - const struct constant* tname_constant = allocate_string_constant(proc, vtype->type_name); - struct pseudo* tname_pseudo = allocate_constant_pseudo(proc, tname_constant); + const struct constant *tname_constant = allocate_string_constant(proc, vtype->type_name); + struct pseudo *tname_pseudo = allocate_constant_pseudo(proc, tname_constant); add_instruction_operand(proc, insn, tname_pseudo); } add_instruction_target(proc, insn, target); @@ -467,7 +482,6 @@ static void linearize_statement_list(struct proc *proc, struct ast_node_list *li END_FOR_EACH_PTR(node) } - static inline struct pseudo *convert_range_to_temp(struct pseudo *pseudo) { assert(pseudo->type == PSEUDO_RANGE); @@ -1149,18 +1163,50 @@ static struct pseudo *linearize_table_constructor(struct proc *proc, struct ast_ return target; } -static void linearize_store_var(struct proc *proc, const struct var_type *var_type, struct pseudo *var_pseudo, - const struct var_type *val_type, struct pseudo *val_pseudo) +/** Is the type NIL-able */ +static bool is_nillable(const struct var_type *var_type) { - // ravitype_t var_type = var_node->common_expr.type.type_code; - // ravitype_t val_type = var_node->common_expr.type.type_code; + return var_type->type_code != RAVI_TARRAYFLT && var_type->type_code != RAVI_TARRAYINT && + var_type->type_code != RAVI_TNUMFLT && var_type->type_code != RAVI_TNUMINT; +} + +/* Check if we can assign value to variable */ +static bool is_compatible(const struct var_type *var_type, const struct var_type *val_type) +{ + if (var_type->type_code == RAVI_TANY) + return true; + if (is_nillable(var_type) && val_type->type_code == RAVI_TNIL) + return true; + if (val_type->type_code == var_type->type_code && val_type->type_name == var_type->type_name) + return true; + if ((var_type->type_code == RAVI_TNUMFLT && val_type->type_code == RAVI_TNUMINT) || + (var_type->type_code == RAVI_TNUMINT && val_type->type_code == RAVI_TNUMFLT)) + /* Maybe conversion is possible so allow */ + return true; + return false; +} +static void linearize_store_var(struct proc *proc, const struct var_type *var_type, struct pseudo *var_pseudo, + const struct var_type *val_type, struct pseudo *val_pseudo) +{ if (var_pseudo->insn && var_pseudo->insn->opcode >= op_get && var_pseudo->insn->opcode <= op_faget_ikey) { convert_indexed_load_to_store(proc, var_pseudo->insn, val_pseudo, val_type->type_code); } else if (var_pseudo->insn && var_pseudo->insn->opcode == op_loadglobal) { convert_loadglobal_to_store(proc, var_pseudo->insn, val_pseudo, val_type->type_code); } else { - instruct_move(proc, op_mov, var_pseudo, val_pseudo); // TODO add type specialization + assert(!var_pseudo->insn); + assert(var_type->type_code != RAVI_TVARARGS && var_type->type_code != RAVI_TNIL); + if (!is_compatible(var_type, val_type)) { + instruct_totype(proc, val_pseudo, var_type); + val_type = var_type; // Because of the type assertion! + } + enum opcode op = op_mov; + if (var_type->type_code == RAVI_TNUMINT) { + op = val_type->type_code == RAVI_TNUMINT ? op_movi : op_movfi; + } else if (var_type->type_code == RAVI_TNUMFLT) { + op = val_type->type_code == RAVI_TNUMFLT ? op_movf : op_movif; + } + instruct_move(proc, op, var_pseudo, val_pseudo); } } @@ -1825,8 +1871,8 @@ static void linearize_function_statement(struct proc *proc, struct ast_node *nod } struct pseudo *function_pseudo = linearize_function_expr(proc, node->function_stmt.function_expr); /* Following will potentially convert load to store */ - linearize_store_var(proc, &prev_node->common_expr.type, prev_pseudo, - &node->function_stmt.function_expr->common_expr.type, function_pseudo); + linearize_store_var(proc, &prev_node->common_expr.type, prev_pseudo, + &node->function_stmt.function_expr->common_expr.type, function_pseudo); } static void linearize_statement(struct proc *proc, struct ast_node *node) @@ -2068,16 +2114,17 @@ static void output_pseudo(struct pseudo *pseudo, membuff_t *mb) } static const char *op_codenames[] = { - "NOOP", "RET", "LOADK", "LOADNIL", "LOADBOOL", "ADD", "ADDff", "ADDfi", "ADDii", - "SUB", "SUBff", "SUBfi", "SUBif", "SUBii", "MUL", "MULff", "MULfi", "MULii", - "DIV", "DIVff", "DIVfi", "DIVif", "DIVii", "IDIV", "BAND", "BANDii", "BOR", - "BORii", "BXOR", "BXORii", "SHL", "SHLii", "SHR", "SHRii", "EQ", "EQii", - "EQff", "LT", "LIii", "LTff", "LE", "LEii", "LEff", "MOD", "POW", - "CLOSURE", "UNM", "UNMi", "UNMf", "LEN", "LENi", "TOINT", "TOFLT", "TOCLOSURE", - "TOSTRING", "TOIARRAY", "TOFARRAY", "TOTABLE", "TOTYPE", "NOT", "BNOT", "LOADGLOBAL", "NEWTABLE", - "NEWIARRAY", "NEWFARRAY", "PUT", "PUTik", "PUTsk", "TPUT", "TPUTik", "TPUTsk", "IAPUT", - "IAPUTiv", "FAPUT", "FAPUTfv", "CBR", "BR", "MOV", "CALL", "GET", "GETik", - "GETsk", "TGET", "TGETik", "TGETsk", "IAGET", "IAGETik", "FAGET", "FAGETik", "STOREGLOBAL"}; + "NOOP", "RET", "ADD", "ADDff", "ADDfi", "ADDii", "SUB", "SUBff", "SUBfi", + "SUBif", "SUBii", "MUL", "MULff", "MULfi", "MULii", "DIV", "DIVff", "DIVfi", + "DIVif", "DIVii", "IDIV", "BAND", "BANDii", "BOR", "BORii", "BXOR", "BXORii", + "SHL", "SHLii", "SHR", "SHRii", "EQ", "EQii", "EQff", "LT", "LIii", + "LTff", "LE", "LEii", "LEff", "MOD", "POW", "CLOSURE", "UNM", "UNMi", + "UNMf", "LEN", "LENi", "TOINT", "TOFLT", "TOCLOSURE", "TOSTRING", "TOIARRAY", "TOFARRAY", + "TOTABLE", "TOTYPE", "NOT", "BNOT", "LOADGLOBAL", "NEWTABLE", "NEWIARRAY", "NEWFARRAY", "PUT", + "PUTik", "PUTsk", "TPUT", "TPUTik", "TPUTsk", "IAPUT", "IAPUTiv", "FAPUT", "FAPUTfv", + "CBR", "BR", "MOV", "MOVi", "MOVif", "MOVf", "MOVfi", "CALL", "GET", + "GETik", "GETsk", "TGET", "TGETik", "TGETsk", "IAGET", "IAGETik", "FAGET", "FAGETik", + "STOREGLOBAL"}; static void output_pseudo_list(struct pseudo_list *list, membuff_t *mb) { diff --git a/tests/expected/results.expected b/tests/expected/results.expected index 72a027c..765a0b0 100644 --- a/tests/expected/results.expected +++ b/tests/expected/results.expected @@ -492,7 +492,7 @@ L0 (entry) POW {3 Kint(0), 0 Kint(1)} {Tflt(0)} UNMf {Tflt(0)} {Tflt(1)} ADDfi {Tflt(1), 5 Kint(2)} {Tflt(2)} - IDIV {Tflt(2), 3 Kint(0)} {T(0)} + IDIV {Tflt(2), 3.000000000000 Kflt(3)} {T(0)} RET {T(0)} {L1} L1 (exit) return 0xF0.0 | 0xCC.0 ~ 0xAA & 0xFD @@ -909,19 +909,19 @@ function() end define Proc%0 L0 (entry) - UNMi {2.000000000000 Kflt(0)} {Tint(0)} + UNMi {2 Kint(1)} {Tint(0)} POW {2.000000000000 Kflt(0), Tint(0)} {Tflt(0)} - DIVii {1 Kint(1), 4 Kint(2)} {Tflt(1)} + DIVii {1 Kint(2), 4 Kint(3)} {Tflt(1)} EQff {Tflt(0), Tflt(1)} {T(1)} MOV {T(1)} {T(0)} CBR {T(0)} {L2, L3} L1 (exit) L2 - UNMi {2.000000000000 Kflt(0)} {Tint(0)} + UNMi {2 Kint(1)} {Tint(0)} UNMi {Tint(0)} {Tint(1)} - POW {2.000000000000 Kflt(0), Tint(1)} {Tflt(1)} + POW {2 Kint(1), Tint(1)} {Tflt(1)} UNMf {Tflt(1)} {Tflt(0)} - UNMi {4 Kint(2)} {Tint(1)} + UNMi {4 Kint(3)} {Tint(1)} UNMi {Tint(1)} {Tint(2)} UNMi {Tint(2)} {Tint(3)} EQ {Tflt(0), Tint(3)} {T(1)} @@ -2104,16 +2104,16 @@ L6 MOV {2 Kint(1)} {T(3)} BR {L7} L7 - UNMf {1 Kint(0)} {Tflt(0)} + UNMf {1.250000000000 Kflt(2)} {Tflt(0)} MOV {Tflt(0)} {T(2)} CBR {T(2)} {L9, L8} L8 - UNMi {4 Kint(2)} {Tint(0)} + UNMi {4 Kint(3)} {Tint(0)} MOV {Tint(0)} {T(2)} BR {L9} L9 ADD {T(3), T(2)} {T(4)} - EQ {T(4), 0.750000000000 Kflt(3)} {T(2)} + EQ {T(4), 0.750000000000 Kflt(4)} {T(2)} MOV {T(2)} {T(0)} BR {L3} return (b or a)+1 == 2 and (10 or a)+1 == 11 @@ -5678,7 +5678,8 @@ end define Proc%0 L0 (entry) LEN {local(t, 0)} {T(0)} - MOV {T(0)} {local(len, 1)} + TOINT {T(0)} + MOVi {T(0)} {local(len, 1)} RET {local(len, 1)} {L1} L1 (exit) return function(t: table, i: integer) i = #t end @@ -5750,7 +5751,8 @@ L0 (entry) TOTABLE {local(t, 0)} TOINT {local(i, 1)} LEN {local(t, 0)} {T(0)} - MOV {T(0)} {local(i, 1)} + TOINT {T(0)} + MOVi {T(0)} {local(i, 1)} BR {L1} L1 (exit) ::L1:: a = 1; goto L1; return @@ -6862,9 +6864,9 @@ L4 CBR {Tint(4)} {L6, L5} L5 MOV {Tint(0)} {local(j, 1)} - MOV {0 Kint(2)} {local(sum, 0)} + MOV {0.000000000000 Kflt(3)} {local(sum, 0)} MOV {1 Kint(0)} {Tint(5)} - MOV {10000 Kint(3)} {Tint(6)} + MOV {10000 Kint(4)} {Tint(6)} MOV {1 Kint(0)} {Tint(7)} LIii {0 Kint(2), Tint(7)} {Tint(8)} SUBii {Tint(5), Tint(7)} {Tint(5)} @@ -6883,7 +6885,7 @@ L9 L10 MOV {Tint(5)} {local(k, 2)} MULii {local(k, 2), local(k, 2)} {Tint(10)} - DIVfi {1 Kint(0), Tint(10)} {Tflt(0)} + DIVfi {1.000000000000 Kflt(5), Tint(10)} {Tflt(0)} ADD {local(sum, 0), Tflt(0)} {T(0)} MOV {T(0)} {local(sum, 0)} BR {L7} @@ -7681,12 +7683,16 @@ L0 (entry) LEN {T(5)} {T(6)} NEWTABLE {T(7)} MOV {T(7)} {local(x, 5)} - MOV {T(6)} {local(p, 4)} - MOV {T(2)} {local(n, 3)} - MOV {T(4)} {local(m, 2)} + TOINT {T(6)} + MOVi {T(6)} {local(p, 4)} + TOINT {T(2)} + MOVi {T(2)} {local(n, 3)} + TOINT {T(4)} + MOVi {T(4)} {local(m, 2)} LOADGLOBAL {matrix} {T(4)} GETsk {T(4), 'T' Ks(1)} {T(2)} CALL {T(2), local(b, 1)} {T(2..)} + TOTABLE {T(2[2..])} MOV {T(2[2..])} {local(c, 6)} MOV {1 Kint(0)} {Tint(0)} MOV {local(m, 2)} {Tint(1)} @@ -7708,7 +7714,8 @@ L5 MOV {Tint(0)} {local(i, 7)} LOADGLOBAL {table} {T(6)} GETsk {T(6), 'numarray' Ks(3)} {T(7)} - CALL {T(7), local(p, 4), 0 Kint(2)} {T(7..)} + CALL {T(7), local(p, 4), 0.000000000000 Kflt(4)} {T(7..)} + TOFARRAY {T(7[7..])} MOV {T(7[7..])} {local(xi, 8)} TPUTik {local(x, 5), local(i, 7), local(xi, 8)} MOV {1 Kint(0)} {Tint(5)} @@ -7736,7 +7743,7 @@ L10 TOFARRAY {T(9)} MOV {T(9)} {local(cj, 12)} MOV {T(8)} {local(ai, 11)} - MOV {0 Kint(2)} {local(sum, 10)} + MOVf {0.000000000000 Kflt(4)} {local(sum, 10)} MOV {1 Kint(0)} {Tint(10)} MOV {local(n, 3)} {Tint(11)} MOV {1 Kint(0)} {Tint(12)} @@ -7760,7 +7767,7 @@ L15 FAGETik {local(cj, 12), local(k, 13)} {Tflt(1)} MULff {Tflt(0), Tflt(1)} {Tflt(2)} ADDff {local(sum, 10), Tflt(2)} {Tflt(1)} - MOV {Tflt(1)} {local(sum, 10)} + MOVf {Tflt(1)} {local(sum, 10)} BR {L12} L16 FAPUTfv {local(xi, 8), local(j, 9), local(sum, 10)} @@ -8213,9 +8220,9 @@ L0 (entry) ADDfi {Tflt(0), Tint(1)} {Tflt(1)} MOD {Tflt(1), 8 Kint(1)} {Tflt(0)} UNMf {Tflt(0)} {Tflt(1)} - DIVfi {Tflt(1), 2.000000000000 Kflt(0)} {Tflt(2)} - MULfi {Tflt(2), 4 Kint(3)} {Tflt(1)} - SUBfi {Tflt(1), 3 Kint(4)} {Tflt(2)} + DIVfi {Tflt(1), 2 Kint(3)} {Tflt(2)} + MULfi {Tflt(2), 4 Kint(4)} {Tflt(1)} + SUBfi {Tflt(1), 3 Kint(5)} {Tflt(2)} RET {Tflt(2)} {L1} L1 (exit) return -((2^8 + -(-1)) % 8)//2 * 4 - 3