From bb6e881c9a2f7b25b7881561de138afa6e44b59a Mon Sep 17 00:00:00 2001 From: Per Bothner Date: Tue, 2 Feb 1999 04:20:36 -0800 Subject: [PATCH] Optimize: `return (a ? b : c)' as: `if (a) return b; else return c;'. a Optimize: `return (a ? b : c)' as: `if (a) return b; else return c;'. * jcf-write.c (generate_bytecode_return): New function. (generate_bytecode_insns): Use it, for RETURN_EXPR. * jcf-write.c (generate_bytecode_insns): For REAL_CST that is 0 or 1, generate special [fd]const_[01] instructions. * jcf-parse.c (yyparse): Don't emit_register_classes if -fsyntax-only. * verify.c (verify_jvm_instructions): Do INVALIDATE_PC after handling OPCODE_lookupswitch or OPCODE_tableswitch. From-SVN: r24971 --- gcc/java/jcf-write.c | 139 +++++++++++++++++++++++++++++-------------- 1 file changed, 93 insertions(+), 46 deletions(-) diff --git a/gcc/java/jcf-write.c b/gcc/java/jcf-write.c index 4e43b75d45b..b8aad7ebca8 100644 --- a/gcc/java/jcf-write.c +++ b/gcc/java/jcf-write.c @@ -1268,6 +1268,72 @@ call_cleanups (limit, state) } } +void +generate_bytecode_return (exp, state) + tree exp; + struct jcf_partial *state; +{ + tree return_type = TREE_TYPE (TREE_TYPE (state->current_method)); + int returns_void = TREE_CODE (return_type) == VOID_TYPE; + int op; + again: + if (exp != NULL) + { + switch (TREE_CODE (exp)) + { + case COMPOUND_EXPR: + generate_bytecode_insns (TREE_OPERAND (exp, 0), IGNORE_TARGET, + state); + exp = TREE_OPERAND (exp, 1); + goto again; + case COND_EXPR: + { + struct jcf_block *then_label = gen_jcf_label (state); + struct jcf_block *else_label = gen_jcf_label (state); + generate_bytecode_conditional (TREE_OPERAND (exp, 0), + then_label, else_label, 1, state); + define_jcf_label (then_label, state); + generate_bytecode_return (TREE_OPERAND (exp, 1), state); + define_jcf_label (else_label, state); + generate_bytecode_return (TREE_OPERAND (exp, 2), state); + } + return; + default: + generate_bytecode_insns (exp, + returns_void ? IGNORE_TARGET + : STACK_TARGET, state); + } + } + if (returns_void) + { + op = OPCODE_return; + call_cleanups (NULL_TREE, state); + } + else + { + op = OPCODE_ireturn + adjust_typed_op (return_type, 4); + if (state->num_finalizers > 0) + { + if (state->return_value_decl == NULL_TREE) + { + state->return_value_decl + = build_decl (VAR_DECL, NULL_TREE, TREE_TYPE (exp)); + localvar_alloc (state->return_value_decl, state); + } + emit_store (state->return_value_decl, state); + call_cleanups (NULL_TREE, state); + emit_load (state->return_value_decl, state); + /* If we call localvar_free (state->return_value_decl, state), + then we risk the save decl erroneously re-used in the + finalizer. Instead, we keep the state->return_value_decl + allocated through the rest of the method. This is not + the greatest solution, but it is at least simple and safe. */ + } + } + RESERVE (1); + OP1 (op); +} + /* Generate bytecode for sub-expression EXP of METHOD. TARGET is one of STACK_TARGET or IGNORE_TARGET. */ @@ -1362,20 +1428,26 @@ generate_bytecode_insns (exp, target, state) } break; case REAL_CST: - offset = find_constant_index (exp, state); - switch (TYPE_PRECISION (type)) - { - case 32: - push_constant1 (offset, state); - NOTE_PUSH (1); - break; - case 64: - push_constant2 (offset, state); - NOTE_PUSH (2); - break; - default: - abort (); - } + { + int prec = TYPE_PRECISION (type) >> 5; + RESERVE(1); + if (real_zerop (exp)) + OP1 (prec == 1 ? OPCODE_fconst_0 : OPCODE_dconst_0); + else if (real_onep (exp)) + OP1 (prec == 1 ? OPCODE_fconst_1 : OPCODE_dconst_1); + /* FIXME Should also use fconst_2 for 2.0f. + Also, should use iconst_2/ldc followed by i2f/i2d + for other float/double when the value is a small integer. */ + else + { + offset = find_constant_index (exp, state); + if (prec == 1) + push_constant1 (offset, state); + else + push_constant2 (offset, state); + } + NOTE_PUSH (prec); + } break; case STRING_CST: push_constant1 (find_string_constant (&state->cpool, exp), state); @@ -1651,39 +1723,14 @@ generate_bytecode_insns (exp, target, state) } case RETURN_EXPR: - if (!TREE_OPERAND (exp, 0)) - { - op = OPCODE_return; - call_cleanups (NULL_TREE, state); - } + exp = TREE_OPERAND (exp, 0); + if (exp == NULL_TREE) + exp = empty_stmt_node; + else if (TREE_CODE (exp) != MODIFY_EXPR) + abort (); else - { - exp = TREE_OPERAND (exp, 0); - if (TREE_CODE (exp) != MODIFY_EXPR) - abort (); - exp = TREE_OPERAND (exp, 1); - op = OPCODE_ireturn + adjust_typed_op (TREE_TYPE (exp), 4); - generate_bytecode_insns (exp, STACK_TARGET, state); - if (state->num_finalizers > 0) - { - if (state->return_value_decl == NULL_TREE) - { - state->return_value_decl - = build_decl (VAR_DECL, NULL_TREE, TREE_TYPE (exp)); - localvar_alloc (state->return_value_decl, state); - } - emit_store (state->return_value_decl, state); - call_cleanups (NULL_TREE, state); - emit_load (state->return_value_decl, state); - /* If we call localvar_free (state->return_value_decl, state), - then we risk the save decl erroneously re-used in the - finalizer. Instead, we keep the state->return_value_decl - allocated through the rest of the method. This is not - the greatest solution, but it is at least simple and safe. */ - } - } - RESERVE (1); - OP1 (op); + exp = TREE_OPERAND (exp, 1); + generate_bytecode_return (exp, state); break; case LABELED_BLOCK_EXPR: { -- 2.30.2