https://gcc.gnu.org/g:7781ff63bf3c43e5620810048bc9c5cfe3f447e1
commit r17-4943-g7781ff63bf3c43e5620810048bc9c5cfe3f447e1 Author: Robert Dubner <[email protected]> Date: Tue Oct 6 19:41:12 2026 -0400 cobol: Increase speed of COMPUTE C = A <op> B statement. COMPUTE C = A + B is inherently more complex than ADD A + B GIVING D, even though the operation is inherently the same These changes detect when the COMPUTE operation can be done using the simpler ADD logic for two operands The result is that such COMPUTEs run two to three times faster than before. gcc/cobol/ChangeLog: * genapi.h (parser_add): Formatting. (parser_divide): Remove unused declaration. (parser_intrinsic_convert): Remove whitespace. (parser_trim): Likewise. * genmath.cc (fast_add): Support faster COMPUTE. (fast_subtract): Support faster COMPUTE. (add_case_1): Whitespace. (parser_as_two): New function detects when faster is possible. (parser_compute): Use parser_as_two(). Diff: --- gcc/cobol/genapi.h | 16 ++---- gcc/cobol/genmath.cc | 147 ++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 146 insertions(+), 17 deletions(-) diff --git a/gcc/cobol/genapi.h b/gcc/cobol/genapi.h index 6cd8eed07e1b..301075de2059 100644 --- a/gcc/cobol/genapi.h +++ b/gcc/cobol/genapi.h @@ -114,7 +114,8 @@ parser_add( size_t nC, cbl_num_result_t *C, size_t nA, cbl_refer_t *A, cbl_arith_format_t format, cbl_label_t *error, - cbl_label_t *not_error, void *compute_error = NULL); // This has to be cast to a tree pointer to int + cbl_label_t *not_error, + void *compute_error = NULL); // This has to be cast to a tree pointer to int void parser_arith_error( cbl_label_t *name ); void parser_arith_error_end( cbl_label_t *name ); @@ -166,13 +167,6 @@ parser_divide( const cbl_refer_t& quotient, const cbl_refer_t& dividend, enum cbl_round_t = truncation_e, const cbl_refer_t& remainder = cbl_refer_t()); - -// void -// parser_exponentiation( cbl_refer_t cref, -// cbl_refer_t aref, -// cbl_refer_t bref, -// cbl_round_t rounded = truncation_e ); - void parser_relop( struct cbl_field_t *tgt, struct cbl_refer_t a, enum relop_t, struct cbl_refer_t b ); @@ -490,8 +484,8 @@ parser_exception_file( cbl_field_t *tgt, cbl_file_t* file = NULL ); void parser_intrinsic_convert(cbl_field_t *tgt, - const cbl_refer_t& input, - convert_type_t src_fmt, + const cbl_refer_t& input, + convert_type_t src_fmt, unsigned int dst_fmt ); void @@ -642,7 +636,7 @@ tree parser_compile_dcls( const std::vector<uint64_t>& dcls ); void parser_trim( cbl_field_t *tgt, const cbl_refer_t& input, size_t how, const std::vector<cbl_refer_t>& args ); -void +void move_helper(tree size_error, // INT cbl_refer_t destref, cbl_refer_t sourceref, diff --git a/gcc/cobol/genmath.cc b/gcc/cobol/genmath.cc index a6766c95e8c2..f15aeb6192ea 100644 --- a/gcc/cobol/genmath.cc +++ b/gcc/cobol/genmath.cc @@ -479,7 +479,8 @@ fast_add( size_t nC, cbl_num_result_t *C, if( all_results_integer(nC, C) && all_refers_integer(nA, A) && !error - && !not_error ) + && !not_error + && !process_this_exception(ec_size_truncation_e) ) { Analyze(); // All targets are non-PICTURE binaries: @@ -602,7 +603,7 @@ fast_subtract(size_t nC, cbl_num_result_t *C, && all_results_integer(nC, C) && !error && !not_error - ) + && !process_this_exception(ec_size_truncation_e) ) { Analyze(); // All targets are non-PICTURE binaries: @@ -1294,7 +1295,6 @@ add_case_1( tree pointer, { // We have rippled through every digit, meaning we just added // 1 to 9999, yielding 0000. - set_exception_code(ec_size_truncation_e); gg_append_statement(break_goto); @@ -2559,6 +2559,116 @@ parser_divide( const cbl_refer_t& cref, NULL ); } +static +bool parser_as_two(cbl_refer_t *tgt, + const std::deque<rpn_t>& operations, + cbl_round_t rounded, + cbl_label_t *on_error, + cbl_label_t *not_error, + cbl_label_t *compute_error_label) + { + bool retval = false; + if( operations.size() == 3 + && strchr("+-*/", operations[2].op) + && ( (operations[0].term.field->type == FldLiteralN) + || !(operations[0].term.field->attr & intermediate_e)) + && ( (operations[0].term.field->type == FldLiteralN) + || !(operations[1].term.field->attr & intermediate_e)) ) + { + set_up_compute_error_label(compute_error_label); + gg_assign(var_decl_default_compute_error, integer_zero_node); + tree compute_error = compute_error_label + ? gg_get_address_of( compute_error_label-> + structs.compute_error-> + compute_error_code) + : gg_get_address_of(var_decl_default_compute_error) ; + cbl_num_result_t result; + result.refer = *tgt; + result.rounded = rounded; + switch(operations[2].op) + { + case '+': + { + cbl_refer_t A[2]; + A[0] = operations[0].term; + A[1] = operations[1].term; + parser_add( 1, &result, + 2, A, + giving_e, + on_error, + not_error, + compute_error ); + retval = true; + break; + } + + case '-': + { + cbl_refer_t A[1]; + cbl_refer_t B[1]; + A[0] = operations[1].term; + B[0] = operations[0].term; + // Yes, the A-ness and B-ness are not really consistent + parser_subtract(1, &result, + 1, A, + 1, B, + giving_e, + on_error, + not_error, + compute_error ); + retval = true; + break; + } + + case '*': + { + cbl_refer_t A[1]; + cbl_refer_t B[1]; + A[0] = operations[1].term; + B[0] = operations[0].term; + parser_multiply(1, &result, + 1, A, + 1, B, + on_error, + not_error, + compute_error ); + retval = true; + break; + } + case '/': + { + cbl_refer_t A[1]; + cbl_refer_t B[1]; + A[0] = operations[0].term; + B[0] = operations[1].term; + parser_divide(1, &result, + 1, A, + 1, B, + NULL, + on_error, + not_error, + compute_error ); + retval = true; + break; + } + } + + if( retval && process_this_exception(ec_size_truncation_e) ) + { + IF( gg_indirect(compute_error), ne_op, integer_zero_node ) + { + set_exception_code(ec_size_truncation_e); + } + ELSE + { + } + ENDIF + } + } + + return retval; + } + void parser_compute( cbl_refer_t *tgt, const std::deque<rpn_t>& operations, @@ -2568,6 +2678,17 @@ parser_compute( cbl_refer_t *tgt, CHECK_FIELD(tgt->field); gcc_assert(operations.size()); + if( parser_as_two(tgt, + operations, + truncation_e, + NULL, + NULL, + compute_error_label) ) + { + // We were able to handle it as an operation on two variables. + return; + } + set_up_compute_error_label(compute_error_label); gg_assign(var_decl_default_compute_error, integer_zero_node); @@ -2646,8 +2767,22 @@ parser_compute( std::vector<cbl_num_result_t>& results, const std::deque<rpn_t>& operations, cbl_label_t *on_error, cbl_label_t *not_error, - cbl_label_t *compute_error) + cbl_label_t *compute_error_label) { + if( results.size() == 1 ) + { + if( parser_as_two(&results[0].refer, + operations, + results[0].rounded, + on_error, + not_error, + compute_error_label) ) + { + // We were able to handle it as an operation on two variables. + return; + } + } + bool compute_float = false; for(auto op : operations) { @@ -2676,7 +2811,7 @@ parser_compute( std::vector<cbl_num_result_t>& results, cbl_refer_t temp_refer; temp_refer.field = temp_field; - parser_compute( &temp_refer, operations, compute_error ); + parser_compute( &temp_refer, operations, compute_error_label ); if( !results.empty() ) { @@ -2685,7 +2820,7 @@ parser_compute( std::vector<cbl_num_result_t>& results, temp_refer, on_error, not_error, - compute_error); + compute_error_label); } }
