diff --git a/tools/qfcc/include/expr.h b/tools/qfcc/include/expr.h index 977a018ff..641b04246 100644 --- a/tools/qfcc/include/expr.h +++ b/tools/qfcc/include/expr.h @@ -767,7 +767,8 @@ expr_t *conditional_expr (expr_t *cond, expr_t *e1, expr_t *e2); expr_t *incop_expr (int op, expr_t *e, int postop); expr_t *array_expr (expr_t *array, expr_t *index); expr_t *deref_pointer_expr (expr_t *pointer); -expr_t *address_expr (expr_t *e1, expr_t *e2, struct type_s *t); +expr_t *offset_pointer_expr (expr_t *pointer, expr_t *offset); +expr_t *address_expr (expr_t *e1, struct type_s *t); expr_t *build_if_statement (int not, expr_t *test, expr_t *s1, expr_t *els, expr_t *s2); expr_t *build_while_statement (int not, expr_t *test, expr_t *statement, diff --git a/tools/qfcc/source/class.c b/tools/qfcc/source/class.c index 3f141ede9..ce4499fdc 100644 --- a/tools/qfcc/source/class.c +++ b/tools/qfcc/source/class.c @@ -1555,7 +1555,7 @@ class_finish_module (void) init_sym = new_symbol_type (".ctor", &type_func); init_sym = function_symbol (init_sym, 0, 1); - module_expr = address_expr (new_symbol_expr (module_sym), 0, 0); + module_expr = address_expr (new_symbol_expr (module_sym), 0); init_expr = new_block_expr (); append_expr (init_expr, diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index de12be36d..497de95c6 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -1304,7 +1304,10 @@ expr_t * new_alias_expr (type_t *type, expr_t *expr) { if (expr->type == ex_alias) { - return new_offset_alias_expr (type, expr, 0); + if (expr->e.alias.offset) { + return new_offset_alias_expr (type, expr, 0); + } + expr = expr->e.alias.expr; } expr_t *alias = new_expr (); @@ -1527,10 +1530,10 @@ field_expr (expr_t *e1, expr_t *e2) ivar = class_find_ivar (class, protected, sym->name); if (!ivar) return new_error_expr (); - e2->type = ex_value; - e2->e.value = new_short_val (ivar->s.offset); - e = new_address_expr (ivar->type, e1, e2); - return unary_expr ('.', e); + expr_t *offset = new_short_expr (ivar->s.offset); + e1 = offset_pointer_expr (e1, offset); + e1 = cast_expr (pointer_type (ivar->type), e1); + return unary_expr ('.', e1); } } else if (is_vector (t1) || is_quaternion (t1) || is_struct (t1)) { symbol_t *field; @@ -1564,10 +1567,10 @@ field_expr (expr_t *e1, expr_t *e2) return field_expr (e1, e2); } else { if (e1->type == ex_uexpr && e1->e.expr.op == '.') { - e2->type = ex_value; - e2->e.value = new_short_val (field->s.offset); - e = address_expr (e1, e2, field->type); - return unary_expr ('.', e); + expr_t *offset = new_short_expr (field->s.offset); + e1 = offset_pointer_expr (e1->e.expr.e1, offset); + e1 = cast_expr (pointer_type (field->type), e1); + return unary_expr ('.', e1); } else { return new_offset_alias_expr (field->type, e1, field->s.offset); } @@ -2470,7 +2473,7 @@ incop_expr (int op, expr_t *e, int postop) append_expr (block, assign_expr (t2, binary_expr (op, t1, one))); res = copy_expr (e); if (res->type == ex_uexpr && res->e.expr.op == '.') - res = deref_pointer_expr (address_expr (res, 0, 0)); + res = deref_pointer_expr (address_expr (res, 0)); append_expr (block, assign_expr (res, t2)); block->e.block.result = t1; return block; @@ -2487,6 +2490,7 @@ array_expr (expr_t *array, expr_t *index) expr_t *scale; expr_t *offset; expr_t *base; + expr_t *ptr; expr_t *e; int ind = 0; @@ -2495,7 +2499,7 @@ array_expr (expr_t *array, expr_t *index) if (index->type == ex_error) return index; - if (array_type->type != ev_ptr && !is_array (array_type)) + if (!is_ptr (array_type) && !is_array (array_type)) return error (array, "not an array"); if (!is_integral (index_type)) return error (index, "invalid array index type"); @@ -2503,7 +2507,8 @@ array_expr (expr_t *array, expr_t *index) ind = expr_short (index); if (is_int_val (index)) ind = expr_int (index); - if (array_type->t.func.num_params + if (is_array (array_type) + && array_type->t.array.size && is_constant (index) && (ind < array_type->t.array.base || ind - array_type->t.array.base >= array_type->t.array.size)) @@ -2517,18 +2522,21 @@ array_expr (expr_t *array, expr_t *index) ind = expr_short (index); if (is_int_val (index)) ind = expr_int (index); - if ((is_constant (index) && ind < 32768 && ind >= -32768)) - index = new_short_expr (ind); if (is_array (array_type)) { - e = address_expr (array, index, array_type->t.array.type); - } else { - if (!is_short_val (index) || expr_short (index)) { - e = new_address_expr (array_type->t.array.type, array, index); + type_t *element_type = array_type->t.array.type; + if (array->type == ex_uexpr && array->e.expr.op == '.') { + ptr = array->e.expr.e1; } else { - e = array; + expr_t *alias = new_offset_alias_expr (element_type, array, 0); + ptr = new_address_expr (element_type, alias, 0); } + } else { + ptr = array; } - e = unary_expr ('.', e); + ptr = offset_pointer_expr (ptr, index); + ptr = cast_expr (pointer_type (array_type->t.array.type), ptr); + + e = unary_expr ('.', ptr); return e; } @@ -2545,7 +2553,28 @@ deref_pointer_expr (expr_t *pointer) } expr_t * -address_expr (expr_t *e1, expr_t *e2, type_t *t) +offset_pointer_expr (expr_t *pointer, expr_t *offset) +{ + type_t *ptr_type = get_type (pointer); + if (!is_ptr (ptr_type)) { + internal_error (pointer, "not a pointer"); + } + if (!is_integral (get_type (offset))) { + internal_error (offset, "pointer offset is not an integer type"); + } + expr_t *ptr; + if (pointer->type == ex_alias && !pointer->e.alias.offset + && is_integral (get_type (pointer->e.alias.expr))) { + ptr = pointer->e.alias.expr; + } else { + ptr = cast_expr (&type_int, pointer); + } + ptr = binary_expr ('+', ptr, offset); + return cast_expr (ptr_type, ptr); +} + +expr_t * +address_expr (expr_t *e1, type_t *t) { expr_t *e; @@ -2561,6 +2590,12 @@ address_expr (expr_t *e1, expr_t *e2, type_t *t) def_t *def = e1->e.def; type_t *type = def->type; + //FIXME this test should be in statements.c + if (options.code.progsversion == PROG_VERSION + && (def->local || def->param)) { + e = new_address_expr (t, e1, 0); + return e; + } if (is_array (type)) { e = e1; e->type = ex_value; @@ -2577,6 +2612,13 @@ address_expr (expr_t *e1, expr_t *e2, type_t *t) def_t *def = e1->e.symbol->s.def; type_t *type = def->type; + //FIXME this test should be in statements.c + if (options.code.progsversion == PROG_VERSION + && (def->local || def->param)) { + e = new_address_expr (t, e1, 0); + return e; + } + if (is_array (type)) { e = e1; e->type = ex_value; @@ -2614,39 +2656,10 @@ address_expr (expr_t *e1, expr_t *e2, type_t *t) if (!t) { t = e1->e.alias.type; } - if (e1->e.alias.offset) { - if (e2) { - e2 = binary_expr ('+', e1->e.alias.offset, e2); - } else { - e2 = e1->e.alias.offset; - } - } - return address_expr (e1->e.alias.expr, e2, t); + return new_address_expr (t, e1, 0); default: return error (e1, "invalid type for unary &"); } - if (e2) { - if (e2->type == ex_error) - return e2; - if (is_pointer_val (e) && is_integral_val (e2)) { - int base = e->e.value->v.pointer.val; - int offset = expr_integral (e2); - def_t *def = e->e.value->v.pointer.def; - e->e.value = new_pointer_val (base + offset, t, def, 0); - } else { - expr_t *offset = 0; - if (e->type == ex_address) { - offset = e->e.address.offset; - e1 = e->e.address.lvalue; - } else { - e1 = e; - } - if (offset) { - e2 = binary_expr ('+', offset, e2); - } - e = new_address_expr (t, e1, e2); - } - } return e; } @@ -2928,7 +2941,7 @@ cast_expr (type_t *dstType, expr_t *e) return cast_error (e, srcType, dstType); } if (is_array (srcType)) { - return address_expr (e, 0, dstType->t.fldptr.type); + return address_expr (e, dstType->t.fldptr.type); } if (is_constant (e) && is_scalar (dstType) && is_scalar (srcType)) { ex_value_t *val = 0; diff --git a/tools/qfcc/source/expr_assign.c b/tools/qfcc/source/expr_assign.c index 9aa1f2784..f9a66b1be 100644 --- a/tools/qfcc/source/expr_assign.c +++ b/tools/qfcc/source/expr_assign.c @@ -335,7 +335,7 @@ assign_expr (expr_t *dst, expr_t *src) if (is_ptr (dst_type) && is_array (src_type)) { // assigning an array to a pointer is the same as taking the address of // the array but using the type of the array elements - src = address_expr (src, 0, src_type->t.fldptr.type); + src = address_expr (src, src_type->t.fldptr.type); src_type = get_type (src); } if (src->type == ex_bool) { diff --git a/tools/qfcc/source/expr_binary.c b/tools/qfcc/source/expr_binary.c index 27e7f1ff8..22d4b8a5a 100644 --- a/tools/qfcc/source/expr_binary.c +++ b/tools/qfcc/source/expr_binary.c @@ -638,7 +638,6 @@ static expr_type_t **binary_expr_types[ev_type_count] = { static expr_t * pointer_arithmetic (int op, expr_t *e1, expr_t *e2) { - expr_t *e; type_t *t1 = get_type (e1); type_t *t2 = get_type (e2); expr_t *ptr; @@ -663,16 +662,17 @@ pointer_arithmetic (int op, expr_t *e1, expr_t *e2) return binary_expr ('/', binary_expr ('-', e1, e2), psize); } else if (is_ptr (t1)) { offset = cast_expr (&type_int, e2); - ptr = cast_expr (&type_int, e1); + ptr = e1; ptype = t1; } else if (is_ptr (t2)) { offset = cast_expr (&type_int, e1); - ptr = cast_expr (&type_int, e2); + ptr = e2; ptype = t2; } + // op is known to be + or - psize = new_int_expr (type_size (ptype->t.fldptr.type)); - e = binary_expr (op, ptr, binary_expr ('*', offset, psize)); - return cast_expr (ptype, e); + offset = unary_expr (op, binary_expr ('*', offset, psize)); + return offset_pointer_expr (ptr, offset); } static expr_t * diff --git a/tools/qfcc/source/expr_obj.c b/tools/qfcc/source/expr_obj.c index 6a8bedebf..41405c1e4 100644 --- a/tools/qfcc/source/expr_obj.c +++ b/tools/qfcc/source/expr_obj.c @@ -172,7 +172,7 @@ super_expr (class_type_t *class_type) field_expr (e, new_name_expr ("super_class"))); append_expr (super_block, e); - e = address_expr (super, 0, 0); + e = address_expr (super, 0); super_block->e.block.result = e; return super_block; } diff --git a/tools/qfcc/source/flow.c b/tools/qfcc/source/flow.c index 753b15928..4b501c027 100644 --- a/tools/qfcc/source/flow.c +++ b/tools/qfcc/source/flow.c @@ -1183,7 +1183,13 @@ flow_analyze_statement (statement_t *s, set_t *use, set_t *def, set_t *kill, internal_error (s->expr, "not a statement"); case st_expr: flow_add_op_var (def, s->opc, 0); - flow_add_op_var (use, s->opa, 1); + if (strcmp (s->opcode, "lea") == 0) { + if (s->opb) { + flow_add_op_var (use, s->opa, 1); + } + } else { + flow_add_op_var (use, s->opa, 1); + } if (s->opb) flow_add_op_var (use, s->opb, 1); if (operands) { diff --git a/tools/qfcc/source/qc-parse.y b/tools/qfcc/source/qc-parse.y index 399f91b1e..282f501ae 100644 --- a/tools/qfcc/source/qc-parse.y +++ b/tools/qfcc/source/qc-parse.y @@ -1559,7 +1559,7 @@ unary_expr | '-' cast_expr %prec UNARY { $$ = unary_expr ('-', $2); } | '!' cast_expr %prec UNARY { $$ = unary_expr ('!', $2); } | '~' cast_expr %prec UNARY { $$ = unary_expr ('~', $2); } - | '&' cast_expr %prec UNARY { $$ = address_expr ($2, 0, 0); } + | '&' cast_expr %prec UNARY { $$ = address_expr ($2, 0); } | '*' cast_expr %prec UNARY { $$ = deref_pointer_expr ($2); } | SIZEOF unary_expr %prec UNARY { $$ = sizeof_expr ($2, 0); } | SIZEOF '(' abstract_decl ')' %prec HYPERUNARY diff --git a/tools/qfcc/source/statements.c b/tools/qfcc/source/statements.c index 028ec9e96..3ff6df7bd 100644 --- a/tools/qfcc/source/statements.c +++ b/tools/qfcc/source/statements.c @@ -727,10 +727,20 @@ static sblock_t * expr_address (sblock_t *sblock, expr_t *e, operand_t **op) { statement_t *s; + expr_t *lvalue = e->e.address.lvalue; + expr_t *offset = e->e.address.offset; + + if (lvalue->type == ex_alias && offset && is_constant (offset)) { + lvalue = new_offset_alias_expr (lvalue->e.alias.type, + lvalue->e.alias.expr, + expr_int (offset)); + offset = 0; + } + s = new_statement (st_expr, "lea", e); - sblock = statement_subexpr (sblock, e->e.address.lvalue, &s->opa); - if (e->e.address.offset) { - sblock = statement_subexpr (sblock, e->e.address.offset, &s->opb); + sblock = statement_subexpr (sblock, lvalue, &s->opa); + if (offset) { + sblock = statement_subexpr (sblock, offset, &s->opb); } s->opc = temp_operand (e->e.address.type, e); sblock_add_statement (sblock, s); @@ -836,7 +846,7 @@ expr_assign_copy (sblock_t *sblock, expr_t *e, operand_t **op, operand_t *src) } } else { if (is_indirect (src_expr)) { - src_expr = expr_file_line (address_expr (src_expr, 0, 0), e); + src_expr = expr_file_line (address_expr (src_expr, 0), e); need_ptr = 1; } if (!src) { @@ -860,7 +870,7 @@ expr_assign_copy (sblock_t *sblock, expr_t *e, operand_t **op, operand_t *src) // dst_expr and/or src_expr are dereferenced pointers, so need to // un-dereference dst_expr to get the pointer and switch to movep // or memsetp instructions. - dst_expr = expr_file_line (address_expr (dst_expr, 0, 0), e); + dst_expr = expr_file_line (address_expr (dst_expr, 0), e); need_ptr = 1; } sblock = statement_subexpr (sblock, dst_expr, &dst); @@ -945,7 +955,7 @@ expr_assign (sblock_t *sblock, expr_t *e, operand_t **op) dereference_dst: // dst_expr is a dereferenced pointer, so need to un-dereference it // to get the pointer and switch to storep instructions. - dst_expr = expr_file_line (address_expr (dst_expr, 0, 0), e); + dst_expr = expr_file_line (address_expr (dst_expr, 0), e); opcode = "store"; if (dst_expr->type == ex_address && dst_expr->e.address.offset && !is_const_ptr (dst_expr->e.address.lvalue)) { @@ -1167,7 +1177,7 @@ expr_call (sblock_t *sblock, expr_t *call, operand_t **op) sblock = statement_slist (sblock, assign); if (args_params) { - list = address_expr (args_params, 0, &type_param); + list = address_expr (args_params, &type_param); } else { list = new_nil_expr (); } @@ -1258,8 +1268,10 @@ statement_return (sblock_t *sblock, expr_t *e) s = new_statement (st_func, opcode, e); if (options.code.progsversion < PROG_VERSION) { if (e->e.retrn.ret_val) { - s->opa = return_operand (get_type (e->e.retrn.ret_val), e); - sblock = statement_subexpr (sblock, e->e.retrn.ret_val, &s->opa); + expr_t *ret_val = e->e.retrn.ret_val; + type_t *ret_type = get_type (ret_val); + s->opa = return_operand (ret_type, e); + sblock = statement_subexpr (sblock, ret_val, &s->opa); } } else { if (e->e.retrn.ret_val) { @@ -1316,6 +1328,28 @@ lea_statement (operand_t *pointer, operand_t *offset, expr_t *e) return s; } +static statement_t * +movep_statement (operand_t *dst, operand_t *src, type_t *type, expr_t *e) +{ + operand_t *dst_addr = operand_address (dst, e); + statement_t *s = new_statement (st_ptrmove, "movep", e); + s->opa = src; + //FIXME large types + s->opb = short_operand (type_size (type), e); + s->opc = dst_addr; + return s; +} + +static statement_t * +load_statement (operand_t *ptr, operand_t *offs, operand_t *op, expr_t *e) +{ + statement_t *s = new_statement (st_expr, "load", e); + s->opa = ptr; + s->opb = offs; + s->opc = op; + return s; +} + static sblock_t * expr_deref (sblock_t *sblock, expr_t *deref, operand_t **op) { @@ -1337,26 +1371,13 @@ expr_deref (sblock_t *sblock, expr_t *deref, operand_t **op) if (!*op) *op = temp_operand (type, e); if (low_level_type (type) == ev_void) { - operand_t *src_addr; - operand_t *dst_addr; - s = lea_statement (ptr, offs, e); - src_addr = s->opc; sblock_add_statement (sblock, s); - dst_addr = operand_address (*op, e); - - s = new_statement (st_ptrmove, "movep", deref); - s->opa = src_addr; - //FIXME large types - s->opb = short_operand (type_size (type), e); - s->opc = dst_addr; + s = movep_statement (*op, s->opc, type, deref); sblock_add_statement (sblock, s); } else { - s = new_statement (st_expr, "load", deref); - s->opa = ptr; - s->opb = offs; - s->opc = *op; + s = load_statement (ptr, offs, *op, deref); sblock_add_statement (sblock, s); } } else if (e->type == ex_value && e->e.value->lltype == ev_ptr) { @@ -1370,11 +1391,13 @@ expr_deref (sblock_t *sblock, expr_t *deref, operand_t **op) sblock = statement_subexpr (sblock, e, &ptr); if (!*op) *op = temp_operand (type, e); - s = new_statement (st_expr, "load", deref); - s->opa = ptr; - s->opb = short_operand (0, e); - s->opc = *op; - sblock_add_statement (sblock, s); + if (low_level_type (type) == ev_void) { + s = movep_statement (*op, ptr, type, deref); + sblock_add_statement (sblock, s); + } else { + s = load_statement (ptr, short_operand (0, e), *op, deref); + sblock_add_statement (sblock, s); + } } return sblock; } diff --git a/tools/qfcc/source/switch.c b/tools/qfcc/source/switch.c index 10b8dc342..f275af673 100644 --- a/tools/qfcc/source/switch.c +++ b/tools/qfcc/source/switch.c @@ -343,7 +343,7 @@ build_switch (expr_t *sw, case_node_t *tree, int op, expr_t *sw_val, table_init = new_compound_init (); for (i = 0; i <= high - low; i++) { tree->labels[i]->e.label.used++; - label = address_expr (tree->labels[i], 0, 0); + label = address_expr (tree->labels[i], 0); append_element (table_init, new_element (label, 0)); } table_sym = new_symbol_type (table_name,