From ef4ad52239f9be8ca68987b8a85f698b806444f3 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 10 Jun 2019 00:36:13 +0900 Subject: [PATCH] Make binary_expr fold constants This is where constant folding should have happened all along. While unary_expr should fold constants too, it seems to already try to do so and it's a bit much of a mess to clean up right now. --- tools/qfcc/source/expr.c | 8 ++++---- tools/qfcc/source/expr_binary.c | 35 ++++++++++++++++++++++++++++----- tools/qfcc/source/qc-parse.y | 33 +++++++++++++------------------ tools/qfcc/source/switch.c | 2 -- 4 files changed, 48 insertions(+), 30 deletions(-) diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index 74a81369f..e2225d2bc 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -1280,7 +1280,7 @@ test_expr (expr_t *e) new = binary_expr (NE, e, new); new->line = e->line; new->file = e->file; - return fold_constants (new); + return new; } void @@ -2130,10 +2130,10 @@ array_expr (expr_t *array, expr_t *index) || ind - array_type->t.array.base >= array_type->t.array.size)) return error (index, "array index out of bounds"); scale = new_integer_expr (type_size (array_type->t.array.type)); - index = fold_constants (binary_expr ('*', index, scale)); + index = binary_expr ('*', index, scale); base = new_integer_expr (array_type->t.array.base); - offset = fold_constants (binary_expr ('*', base, scale)); - index = fold_constants (binary_expr ('-', index, offset)); + offset = binary_expr ('*', base, scale); + index = binary_expr ('-', index, offset); if (is_short_val (index)) ind = expr_short (index); if (is_integer_val (index)) diff --git a/tools/qfcc/source/expr_binary.c b/tools/qfcc/source/expr_binary.c index 8b0c5a485..d53d3677c 100644 --- a/tools/qfcc/source/expr_binary.c +++ b/tools/qfcc/source/expr_binary.c @@ -42,8 +42,11 @@ typedef struct { type_t *type; type_t *a_cast; type_t *b_cast; + expr_t *(*process)(int op, expr_t *e1, expr_t *e2); } expr_type_t; +static expr_t *pointer_arithmetic (int op, expr_t *e1, expr_t *e2); + static expr_type_t string_string[] = { {'+', &type_string}, {EQ, &type_integer}, @@ -157,8 +160,8 @@ static expr_type_t pointer_pointer[] = { }; static expr_type_t pointer_integer[] = { - {'+', &type_pointer}, - {'-', &type_pointer}, + {'+', 0, 0, 0, pointer_arithmetic}, + {'-', 0, 0, 0, pointer_arithmetic}, {0, 0} }; #define pointer_uinteger pointer_integer @@ -218,7 +221,7 @@ static expr_type_t integer_vector[] = { }; static expr_type_t integer_pointer[] = { - {'+', &type_pointer}, + {'+', &type_pointer, 0, &type_integer}, {0, 0} }; @@ -579,6 +582,25 @@ static expr_type_t **binary_expr_types[] = { short_x, }; +static expr_t * +pointer_arithmetic (int op, expr_t *e1, expr_t *e2) +{ + expr_t *e; + type_t *ptype = get_type (e1); + + if (!is_pointer (ptype)) { + ptype = get_type (e2); + } + if (!is_pointer (ptype)) { + internal_error (e1, "pointer arithmetic on non-pointers"); + } + + e1 = cast_expr (&type_integer, e1); + e2 = cast_expr (&type_integer, e2); + e = binary_expr (op, e1, e2); + return cast_expr (ptype, e); +} + static expr_t * invalid_binary_expr (int op, expr_t *e1, expr_t *e2) { @@ -780,9 +802,12 @@ binary_expr (int op, expr_t *e1, expr_t *e2) e1 = cast_expr (expr_type->a_cast, e1); if (expr_type->b_cast) e2 = cast_expr (expr_type->b_cast, e2); + if (expr_type->process) { + return fold_constants (expr_type->process (op, e1, e2)); + } if ((e = reimplement_binary_expr (op, e1, e2))) - return e; + return fold_constants (e); e = new_binary_expr (op, e1, e2); e->e.expr.type = expr_type->type; @@ -790,5 +815,5 @@ binary_expr (int op, expr_t *e1, expr_t *e2) if (options.code.progsversion == PROG_ID_VERSION) e->e.expr.type = &type_float; } - return e; + return fold_constants (e); } diff --git a/tools/qfcc/source/qc-parse.y b/tools/qfcc/source/qc-parse.y index cb1b28ea3..eba38584d 100644 --- a/tools/qfcc/source/qc-parse.y +++ b/tools/qfcc/source/qc-parse.y @@ -180,7 +180,7 @@ int yylex (void); %type methoddef %type opt_initializer var_initializer local_def -%type opt_init opt_expr cexpr fexpr expr element_list element +%type opt_init opt_expr cexpr expr element_list element %type optional_state_expr texpr vector_expr %type statement statements compound_statement %type else label break_label continue_label @@ -577,7 +577,7 @@ enumerator_list enumerator : identifier { add_enum ($0, $1, 0); } - | identifier '=' fexpr { add_enum ($0, $1, $3); } + | identifier '=' expr { add_enum ($0, $1, $3); } ; struct_specifier @@ -846,9 +846,8 @@ abs_decl ; array_decl - : '[' fexpr ']' + : '[' expr ']' { - $2 = fold_constants ($2); if (!is_integer_val ($2) || expr_integer ($2) < 1) { error (0, "invalid array size"); $$ = 0; @@ -971,11 +970,11 @@ overloaded_identifier ; non_code_func - : '=' '#' fexpr + : '=' '#' expr { build_builtin_function ($0, $3, 0); } - | '=' fexpr + | '=' expr { symbol_t *sym = $0; specifier_t spec = $-1; @@ -1023,7 +1022,7 @@ opt_initializer ; var_initializer - : '=' fexpr { $$ = $2; } + : '=' expr { $$ = $2; } | '=' '{' element_list optional_comma '}' { $$ = $3; } ; @@ -1046,7 +1045,7 @@ element_list element : '{' element_list optional_comma '}' { $$ = $2; } - | fexpr { $$ = $1; } + | expr { $$ = $1; } ; optional_comma @@ -1128,7 +1127,7 @@ statement else error (0, "continue outside of loop"); } - | CASE fexpr ':' + | CASE expr ':' { $$ = case_label_expr (switch_block, $2); } @@ -1136,7 +1135,7 @@ statement { $$ = case_label_expr (switch_block, 0); } - | SWITCH break_label '(' fexpr switch_block ')' compound_statement + | SWITCH break_label '(' expr switch_block ')' compound_statement { $$ = switch_expr (switch_block, break_label, $7); switch_block = $5; @@ -1295,7 +1294,7 @@ unary_expr ; vector_expr - : '[' fexpr ',' arg_list ']' + : '[' expr ',' arg_list ']' { expr_t *t = $4; while (t->next) @@ -1338,12 +1337,8 @@ expr | expr '%' expr { $$ = binary_expr ('%', $1, $3); } ; -fexpr - : expr { $$ = fold_constants ($1); } - ; - texpr - : fexpr { $$ = convert_bool ($1, 1); } + : expr { $$ = convert_bool ($1, 1); } ; cexpr @@ -1364,8 +1359,8 @@ opt_arg_list ; arg_list - : fexpr - | arg_list ',' fexpr + : expr + | arg_list ',' expr { $3->next = $1; $$ = $3; @@ -1874,7 +1869,7 @@ obj_messageexpr ; receiver - : fexpr + : expr | CLASS_NAME { $$ = new_symbol_expr ($1); diff --git a/tools/qfcc/source/switch.c b/tools/qfcc/source/switch.c index 0ff624b95..7e76ef6f4 100644 --- a/tools/qfcc/source/switch.c +++ b/tools/qfcc/source/switch.c @@ -338,8 +338,6 @@ build_switch (expr_t *sw, case_node_t *tree, int op, expr_t *sw_val, int i; expr_t *range = binary_expr ('-', tree->high, tree->low); - range = fold_constants (range); - table_init = new_block_expr (); for (i = 0; i <= high - low; i++) { tree->labels[i]->e.label.used++;