https://gcc.gnu.org/g:5d9ea620152f7f7d2ee290ff35b665f95a4f6bf7
commit r17-4048-g5d9ea620152f7f7d2ee290ff35b665f95a4f6bf7 Author: Robert Dubner <[email protected]> Date: Wed Sep 9 21:22:42 2026 -0400 cobol: Faster execution of floating-point ADD/SUBTRACT. Do GENERIC arithmetic instead of calling library routines. gcc/cobol/ChangeLog: * compare.cc (digiter): Spelling in comment. * genmath.cc (fast_add): Fix aliasing problem. (get_fbinary_value): New function for converting fixed-format to floating point, with rdigit scaling. (add_floats): Stop using library routines in favor of GENERIC. (add_format_3): Likewise. (subtract_floats): Likewise. (subtract_format_3): Likewise. libgcobol/ChangeLog: * gmath.cc (__gg__conditional_stash_float): New routine supporting faster GENERIC arithmetic. (__gg__add_fixed_phase1): Remove obsolete function. (__gg__addf1_fixed_phase2): Likewise. (__gg__fixed_phase2_assign_to_c): Likewise. (__gg__add_float_phase1): Likewise. (__gg__addf1_float_phase2): Likewise. (__gg__float_phase2_assign_to_c): Likewise. (__gg__addf3): Likewise. (__gg__subtractf1_fixed_phase2): Likewise. (__gg__subtractf2_fixed_phase1): Likewise. (__gg__subtractf1_float_phase2): Likewise. (__gg__subtractf2_float_phase1): Likewise. (__gg__subtractf3): Likewise. Diff: --- gcc/cobol/compare.cc | 2 +- gcc/cobol/genmath.cc | 319 ++++++++++++++++---------- libgcobol/gmath.cc | 629 ++------------------------------------------------- 3 files changed, 211 insertions(+), 739 deletions(-) diff --git a/gcc/cobol/compare.cc b/gcc/cobol/compare.cc index f74053825ef3..eabfe650082a 100644 --- a/gcc/cobol/compare.cc +++ b/gcc/cobol/compare.cc @@ -172,7 +172,7 @@ digiter(int &digits, int &rdigits, const cbl_refer_t &refer) if( rdigits < 0 ) { // This is like 999PPPP with rdigits = -4 - // So, digits evntually becomes 7, and rdigits becomes 0 + // So, digits eventually becomes 7, and rdigits becomes 0 // Our caller will have to multiply by 10^4 to get the 999 digits into // the right place. rdigits = 0; diff --git a/gcc/cobol/genmath.cc b/gcc/cobol/genmath.cc index cbc17dc4a578..a6766c95e8c2 100644 --- a/gcc/cobol/genmath.cc +++ b/gcc/cobol/genmath.cc @@ -502,21 +502,10 @@ fast_add( size_t nC, cbl_num_result_t *C, if( refer_is_clean(C[0].refer) ) { - // We are accumulating into memory - - if(is_working_storage(C[0].refer) - && C[0].refer.field->offset == 0 ) - { - gg_assign( C[0].refer.field->data_decl_node, - gg_cast(TREE_TYPE(C[0].refer.field->data_decl_node), - gg_add( C[0].refer.field->data_decl_node, A_value))); - } - else - { - tree dest_addr = member(C[0].refer.field->var_decl_node, "data"); - tree dest_value = safe_load(dest_addr, dest_type); - safe_store(dest_addr, dest_type, gg_add(dest_value, A_value)); - } + // We are accumulating into memory with no offset + tree dest_addr = member(C[0].refer.field->var_decl_node, "data"); + tree dest_value = safe_load(dest_addr, dest_type); + safe_store(dest_addr, dest_type, gg_add(dest_value, A_value)); } else { @@ -918,6 +907,40 @@ fast_divide(size_t nC, cbl_num_result_t *C, return retval; } +tree get_fbinary_value(const cbl_refer_t &refer) + { + tree retval = get_binary_value(refer, FLOAT128); + int scale = refer.field->data.rdigits; + if( scale ) + { + if( refer.field->attr & scaled_e ) + { + if( refer.field->data.rdigits < 0 ) + { + // This is like 999PPPP with rdigits = -4 + // We multiply by 10^4 to get the 999 digits into place + scale = -refer.field->data.rdigits; + FIXED_WIDE_INT(128) power_of_ten = get_power_of_ten(scale); + tree pot = wide_int_to_tree(INT128, power_of_ten); + retval = gg_multiply(retval, gg_cast(FLOAT128, pot)); + scale = 0; + } + else + { + // This is like PPP9999. Digits stays 3, and rdigits becomes 7 + scale += refer.field->data.digits; + } + } + if( scale ) + { + FIXED_WIDE_INT(128) power_of_ten = get_power_of_ten(scale); + tree pot = wide_int_to_tree(INT128, power_of_ten); + retval = gg_real_divide(retval, gg_cast(FLOAT128, pot)); + } + } + return retval; + } + static bool add_floats( size_t nC, cbl_num_result_t *C, size_t nA, cbl_refer_t *A, @@ -926,6 +949,8 @@ add_floats( size_t nC, cbl_num_result_t *C, cbl_label_t *not_error, tree compute_error ) { + gcc_assert(nC > 0); + gcc_assert(nA > 0); bool handled = false; bool computation_is_float = is_somebody_float(nA, A) @@ -941,28 +966,29 @@ add_floats( size_t nC, cbl_num_result_t *C, set_up_arithmetic_error_handler(error, not_error); - // Do phase 1, which calculates the subtotal and puts it into a - // temporary location - arithmetic_operation( 0, NULL, - nA, A, - 0, NULL, - format, - error, - not_error, - compute_error, - "__gg__add_float_phase1"); + tree initial = gg_define_variable(FLOAT128); + gg_assign(initial, get_fbinary_value(A[0])); + tree next = gg_define_variable(FLOAT128); + for(size_t i=1; i<nA; i++ ) + { + gg_assign(next, get_fbinary_value(A[i])); + gg_assign(initial, gg_add(initial, next)); + } - // Do phase 2, which accumulates the subtotal into each target location in turn for(size_t i=0; i<nC; i++) { - arithmetic_operation(1, &C[i], - 0, NULL, - 0, NULL, - format, - error, - not_error, - compute_error, - "__gg__addf1_float_phase2"); + gg_assign(next, gg_add(initial, get_fbinary_value(C[i].refer))); + gg_assign(gg_indirect(compute_error), + gg_bitwise_or(gg_indirect(compute_error), + gg_call_expr( + INT, + "__gg__conditional_stash_float", + gg_get_address_of(C[i].refer.field->var_decl_node), + refer_offset(C[i].refer), + size_t_zero_node, + next, + build_int_cst_type(INT, C[i].rounded), + NULL_TREE))); } arithmetic_error_handler( error, not_error, @@ -977,28 +1003,28 @@ add_floats( size_t nC, cbl_num_result_t *C, // Float format 2 set_up_arithmetic_error_handler(error, not_error); - // Do phase 1, which calculates the subtotal and puts it into a - // temporary location - arithmetic_operation( 0, NULL, - nA, A, - 0, NULL, - format, - error, - not_error, - compute_error, - "__gg__add_float_phase1"); + tree initial = gg_define_variable(FLOAT128); + gg_assign(initial, get_fbinary_value(A[0])); + for(size_t i=1; i<nA; i++ ) + { + tree next = gg_define_variable(FLOAT128); + gg_assign(next, get_fbinary_value(A[i])); + gg_assign(initial, gg_add(initial, next)); + } - // Do phase 2, which puts the subtotal into each target location in turn for(size_t i=0; i<nC; i++) { - arithmetic_operation(1, &C[i], - 0, NULL, - 0, NULL, - format, - error, - not_error, - compute_error, - "__gg__float_phase2_assign_to_c"); + gg_assign(gg_indirect(compute_error), + gg_bitwise_or(gg_indirect(compute_error), + gg_call_expr( + INT, + "__gg__conditional_stash_float", + gg_get_address_of(C[i].refer.field->var_decl_node), + refer_offset(C[i].refer), + size_t_zero_node, + initial, + build_int_cst_type(INT, C[i].rounded), + NULL_TREE))); } arithmetic_error_handler( error, not_error, @@ -1015,14 +1041,21 @@ add_floats( size_t nC, cbl_num_result_t *C, set_up_arithmetic_error_handler(error, not_error); - arithmetic_operation(nC, C, - nA, A, - 0, NULL, - format, - error, - not_error, - compute_error, - "__gg__addf3"); + for(size_t i=0; i<nC; i++) + { + gg_assign(gg_indirect(compute_error), + gg_bitwise_or(gg_indirect(compute_error), + gg_call_expr( + INT, + "__gg__conditional_stash_float", + gg_get_address_of(C[i].refer.field->var_decl_node), + refer_offset(C[i].refer), + size_t_zero_node, + gg_add(get_fbinary_value(C[i].refer), + get_fbinary_value(A[i])), + build_int_cst_type(INT, C[i].rounded), + NULL_TREE))); + } arithmetic_error_handler( error, not_error, compute_error); @@ -2129,14 +2162,28 @@ add_format_3( size_t nC, cbl_num_result_t *C, set_up_arithmetic_error_handler(error, not_error); - arithmetic_operation(nC, C, - nA, A, - 0, NULL, - format, - error, - not_error, - compute_error, - "__gg__addf3"); + for(size_t i=0; i<nC; i++) + { + int digits = 0; + int rdigits = 0; + determine_excess_rdigits(1, &C[i].refer, digits, rdigits); + determine_excess_rdigits(1, &A[i], digits, rdigits); + tree cval = add_phase_1(1, &C[i].refer, rdigits); + tree aval = add_phase_1(1, &A[i], rdigits); + gg_assign(gg_indirect(compute_error), + gg_bitwise_or(gg_indirect(compute_error), gg_call_expr( + INT, + "__gg__conditional_stash", + gg_get_address_of(C[i].refer.field->var_decl_node), + refer_offset(C[i].refer), + error || not_error + ? build_int_cst_type(INT, ON_SIZE_ERROR) + : integer_zero_node, + gg_add(cval, aval), + build_int_cst_type(INT, rdigits), + build_int_cst_type(INT, C[i].rounded), + NULL_TREE))); + } arithmetic_error_handler( error, not_error, compute_error); @@ -2803,32 +2850,33 @@ subtract_floats( size_t nC, cbl_num_result_t *C, { case no_giving_e: { - // Float format 1 + // Float SUBTRACT format 1 set_up_arithmetic_error_handler(error, not_error); - // Do phase 1, which calculates the subtotal and puts it into a - // temporary location - arithmetic_operation( 0, NULL, - nA, A, - 0, NULL, - format, - error, - not_error, - compute_error, - "__gg__add_float_phase1"); + tree initial = gg_define_variable(FLOAT128); + gg_assign(initial, get_fbinary_value(A[0])); + tree next = gg_define_variable(FLOAT128); + for(size_t i=1; i<nA; i++ ) + { + gg_assign(next, get_fbinary_value(A[i])); + gg_assign(initial, gg_add(initial, next)); + } - // Do phase 2, which subtracts the subtotal from each target in turn for(size_t i=0; i<nC; i++) { - arithmetic_operation(1, &C[i], - 0, NULL, - 0, NULL, - format, - error, - not_error, - compute_error, - "__gg__subtractf1_float_phase2"); + gg_assign(next, gg_subtract(get_fbinary_value(C[i].refer), initial)); + gg_assign(gg_indirect(compute_error), + gg_bitwise_or(gg_indirect(compute_error), + gg_call_expr( + INT, + "__gg__conditional_stash_float", + gg_get_address_of(C[i].refer.field->var_decl_node), + refer_offset(C[i].refer), + size_t_zero_node, + next, + build_int_cst_type(INT, C[i].rounded), + NULL_TREE))); } arithmetic_error_handler( error, not_error, @@ -2846,33 +2894,33 @@ subtract_floats( size_t nC, cbl_num_result_t *C, gcc_assert(nB == 1); set_up_arithmetic_error_handler(error, not_error); - // Do phase 1, which calculates the subtotal and puts it into a - // temporary location - arithmetic_operation( 0, NULL, - nA, A, - nB, B, - format, - error, - not_error, - compute_error, - "__gg__subtractf2_float_phase1"); + tree initial = gg_define_variable(FLOAT128); + gg_assign(initial, get_fbinary_value(A[0])); + tree next = gg_define_variable(FLOAT128); + for(size_t i=1; i<nA; i++ ) + { + gg_assign(next, get_fbinary_value(A[i])); + gg_assign(initial, gg_add(initial, next)); + } + gg_assign(next, gg_subtract(get_fbinary_value(B[0]), initial)); - // Do phase 2, which puts the subtotal into each target location in turn for(size_t i=0; i<nC; i++) { - arithmetic_operation(1, &C[i], - 0, NULL, - 0, NULL, - format, - error, - not_error, - compute_error, - "__gg__float_phase2_assign_to_c"); + gg_assign(gg_indirect(compute_error), + gg_bitwise_or(gg_indirect(compute_error), + gg_call_expr( + INT, + "__gg__conditional_stash_float", + gg_get_address_of(C[i].refer.field->var_decl_node), + refer_offset(C[i].refer), + size_t_zero_node, + next, + build_int_cst_type(INT, C[i].rounded), + NULL_TREE))); } arithmetic_error_handler( error, not_error, compute_error); - handled = true; break; } @@ -2884,14 +2932,21 @@ subtract_floats( size_t nC, cbl_num_result_t *C, set_up_arithmetic_error_handler(error, not_error); - arithmetic_operation(nC, C, - nA, A, - 0, NULL, - format, - error, - not_error, - compute_error, - "__gg__subtractf3"); + for(size_t i=0; i<nC; i++) + { + gg_assign(gg_indirect(compute_error), + gg_bitwise_or(gg_indirect(compute_error), + gg_call_expr( + INT, + "__gg__conditional_stash_float", + gg_get_address_of(C[i].refer.field->var_decl_node), + refer_offset(C[i].refer), + size_t_zero_node, + gg_subtract(get_fbinary_value(C[i].refer), + get_fbinary_value(A[i])), + build_int_cst_type(INT, C[i].rounded), + NULL_TREE))); + } arithmetic_error_handler( error, not_error, compute_error); @@ -3012,14 +3067,28 @@ subtract_format_3(size_t nC, cbl_num_result_t *C, set_up_arithmetic_error_handler(error, not_error); - arithmetic_operation(nC, C, - nA, A, - 0, NULL, - format, - error, - not_error, - compute_error, - "__gg__subtractf3"); + for(size_t i=0; i<nC; i++) + { + int digits = 0; + int rdigits = 0; + determine_excess_rdigits(1, &C[i].refer, digits, rdigits); + determine_excess_rdigits(1, &A[i], digits, rdigits); + tree cval = add_phase_1(1, &C[i].refer, rdigits); + tree aval = add_phase_1(1, &A[i], rdigits); + gg_assign(gg_indirect(compute_error), + gg_bitwise_or(gg_indirect(compute_error), gg_call_expr( + INT, + "__gg__conditional_stash", + gg_get_address_of(C[i].refer.field->var_decl_node), + refer_offset(C[i].refer), + error || not_error + ? build_int_cst_type(INT, ON_SIZE_ERROR) + : integer_zero_node, + gg_subtract(cval, aval), + build_int_cst_type(INT, rdigits), + build_int_cst_type(INT, C[i].rounded), + NULL_TREE))); + } arithmetic_error_handler( error, not_error, compute_error); diff --git a/libgcobol/gmath.cc b/libgcobol/gmath.cc index 70096ccea93d..baa1214bb842 100644 --- a/libgcobol/gmath.cc +++ b/libgcobol/gmath.cc @@ -173,6 +173,22 @@ conditional_stash( cblc_field_t *destination, return retval; } +extern "C" +int +__gg__conditional_stash_float( cblc_field_t *destination, + size_t destination_o, + bool on_error_flag, + GCOB_FP128 value, + cbl_round_t rounded) + { + return conditional_stash(destination, + destination_o, + destination->capacity, + on_error_flag, + value, + rounded); + } + static GCOB_FP128 divide_helper_float(GCOB_FP128 a_value, @@ -649,619 +665,6 @@ get_int256_from_qualified_field(int256 &var, } } -static int256 phase1_result; - -static GCOB_FP128 phase1_result_float; - -extern "C" -void -__gg__add_fixed_phase1( cbl_arith_format_t , - size_t nA, - const cblc_referlet_t *AA, - size_t , - cblc_referlet_t *, - size_t , - cblc_referlet_t *, - const cbl_round_t *, - int , - int *compute_error - ) - { - // Our job is to add together the nA fixed-point values in the A[] array - - // The result goes into the temporary phase1_result. - - // Let us prime the pump with the first value of A[] - get_int256_from_qualified_field(phase1_result, - AA[0].field, - AA[0].offset, - AA[0].size); - - // We now go into a loop adding each of the A[] values to phase1_result: - - for( size_t i=1; i<nA; i++ ) - { - int256 temp = {}; - get_int256_from_qualified_field(temp, - AA[i].field, - AA[i].offset, - AA[i].size); - - add_int256_to_int256(phase1_result, temp); - } - - // phase1_result/phase1_result.rdigits now reflect the sum of all A[] - - int overflow = squeeze_int256(phase1_result); - if( overflow ) - { - *compute_error |= compute_error_overflow; - } - } - -extern "C" -void -__gg__addf1_fixed_phase2( cbl_arith_format_t , - size_t , - cblc_referlet_t *, - size_t , - cblc_referlet_t *, - size_t , - const cblc_referlet_t *C, - const cbl_round_t *rounded, - int on_error_flag, - int *compute_error - ) - { - // This is the assignment phase of an ADD Format 1 - - // We take phase1_result and accumulate it into C - bool on_size_error = !!(on_error_flag & ON_SIZE_ERROR); - - if( C[0].field->type == FldFloat) - { - // The target we need to accumulate into is a floating-point number, so we - // need to convert our fixed-point intermediate into floating point and - // proceed accordingly. - - // Convert the intermediate - GCOB_FP128 value_a = (GCOB_FP128)int256_get_u128(phase1_result, 0); - value_a /= __gg__power_of_ten(phase1_result.rdigits); - - // Pick up the target - GCOB_FP128 value_b = __gg__float128_from_qualified_field(C[0].field, - C[0].offset, - C[0].size); - - value_a += value_b; - - // At this point, we assign running_sum to *C. - *compute_error |= conditional_stash(C[0].field, - C[0].offset, - C[0].size, - on_size_error, - value_a, - *rounded++); - } - else - { - // We have a fixed-point intermediate, and we are accumulating into a - // fixed point target. - int256 value_a = phase1_result; - int256 value_b = {}; - - value_a.rdigits = phase1_result.rdigits; - - get_int256_from_qualified_field(value_b, - C[0].field, - C[0].offset, - C[0].size); - add_int256_to_int256(value_a, value_b); - - int overflow = squeeze_int256(value_a); - if( overflow ) - { - *compute_error |= compute_error_overflow; - } - - // At this point, we assign running_sum to *C. - *compute_error |= conditional_stash(C[0].field, - C[0].offset, - C[0].size, - on_size_error, - int256_get_u128(value_a, 0), - value_a.rdigits, - *rounded++); - } - } - -extern "C" -void -__gg__fixed_phase2_assign_to_c( cbl_arith_format_t , - size_t , - cblc_referlet_t *, - size_t , - cblc_referlet_t *, - size_t , - const cblc_referlet_t *CC, - const cbl_round_t *rounded, - int on_error_flag, - int *compute_error - ) - { - // This is the assignment phase of an ADD or SUBTRACT Format 2 - - // We take phase1_result and put it into C - bool on_size_error = !!(on_error_flag & ON_SIZE_ERROR); - - if( CC[0].field->type == FldFloat) - { - // The target we need to accumulate into is a floating-point number, so we - // need to convert our fixed-point intermediate into floating point and - // proceed accordingly. - - // Convert the intermediate - GCOB_FP128 value_a = (GCOB_FP128)int256_get_u128(phase1_result, 0); - value_a /= __gg__power_of_ten(phase1_result.rdigits); - - *compute_error |= conditional_stash(CC[0].field, CC[0].offset, CC[0].size, - on_size_error, - value_a, - *rounded++); - } - else - { - // We have a fixed-point intermediate, and we are accumulating intoi a - // fixed point target. - int256 value_a = phase1_result; - value_a.rdigits = phase1_result.rdigits; - - int overflow = squeeze_int256(value_a); - if( overflow ) - { - *compute_error |= compute_error_overflow; - } - - if( CC[0].field->type == FldPointer ) - { - // In case somebody does pointer arithmetic that goes negative, we need - // to make the top 64 bits positive. Otherwise, the conditional stash - // will see that FldPointer is not signable, and force the value - // positive with a two's complement. - int256_set_u128(value_a, - 0, - int256_get_u128(value_a, 0) & 0xFFFFFFFFFFFFFFFFULL); - } - - // At this point, we assign that value to *C. - *compute_error |= conditional_stash(CC[0].field, CC[0].offset, CC[0].size, - on_size_error, - int256_get_u128(value_a, 0), - value_a.rdigits, - *rounded++); - } - } - -extern "C" -void -__gg__add_float_phase1( cbl_arith_format_t , - size_t nA, - const cblc_referlet_t *A, - size_t , - cblc_referlet_t *, - size_t , - cblc_referlet_t *, - const cbl_round_t *, - int , - int *compute_error - ) - { - // Our job is to add together the nA floating-point values in the A[] array - - // The result goes into the temporary phase1_result_ffloat. - - // Let us prime the pump with the first value of A[] - phase1_result_float = __gg__float128_from_qualified_field(A[0].field, - A[0].offset, - A[0].size); - - // We now go into a loop adding each of the A[] values to phase1_result_flt: - - for( size_t i=1; i<nA; i++ ) - { - GCOB_FP128 temp = __gg__float128_from_qualified_field(A[i].field, - A[i].offset, - A[i].size); - phase1_result_float = addition_helper_float(phase1_result_float, - temp, - compute_error); - } - } - -extern "C" -void -__gg__addf1_float_phase2( cbl_arith_format_t , - size_t , - cblc_referlet_t *, - size_t , - cblc_referlet_t *, - size_t , - const cblc_referlet_t *C, - const cbl_round_t *rounded, - int on_error_flag, - int *compute_error - ) - { - bool on_size_error = !!(on_error_flag & ON_SIZE_ERROR); - // This is the assignment phase of an ADD Format 2 - // We take phase1_result and accumulate it into C - - GCOB_FP128 temp = __gg__float128_from_qualified_field(C[0].field, - C[0].offset, - C[0].size); - temp = addition_helper_float(temp, phase1_result_float, compute_error); - *compute_error |= conditional_stash(C[0].field, C[0].offset, C[0].size, - on_size_error, - temp, - *rounded++); - } - -extern "C" -void -__gg__float_phase2_assign_to_c( cbl_arith_format_t , - size_t , - cblc_referlet_t *, - size_t , - cblc_referlet_t *, - size_t , - const cblc_referlet_t *C, - const cbl_round_t *rounded, - int on_error_flag, - int *compute_error - ) - { - bool on_size_error = !!(on_error_flag & ON_SIZE_ERROR); - // This is the assignment phase of an ADD Format 2 - // We take phase1_result and put it into C - - *compute_error |= conditional_stash(C[0].field, C[0].offset, C[0].size, - on_size_error, - phase1_result_float, - *rounded++); - } - -extern "C" -void -__gg__addf3(cbl_arith_format_t , - size_t nA, - const cblc_referlet_t *A, - size_t , - cblc_referlet_t *, - size_t , - const cblc_referlet_t *C, - const cbl_round_t *rounded, - int on_error_flag, - int *compute_error - ) - { - // This is an ADD Format 3. Each A[i] gets accumulated into each C[i]. When - // both are fixed, we do fixed arithmetic. When either is a FldFloat, we - // do floating-point arithmetic. - bool on_size_error = !!(on_error_flag & ON_SIZE_ERROR); - - for(size_t i=0; i<nA; i++) - { - if( A[i].field->type == FldFloat || C[i].field->type == FldFloat ) - { - GCOB_FP128 value_a = __gg__float128_from_qualified_field(A[i].field, - A[i].offset, - A[i].size); - GCOB_FP128 value_b = __gg__float128_from_qualified_field(C[i].field, - C[i].offset, - C[i].size); - - value_a = addition_helper_float(value_a, value_b, compute_error); - - // At this point, we assign the sum to *C. - *compute_error |= conditional_stash(C[i].field, C[i].offset, C[i].size, - on_size_error, - value_a, - *rounded++); - } - else - { - // We have are doing fixed-point arithmetic. - int256 value_a; - int256 value_b; - - get_int256_from_qualified_field(value_a, - A[i].field, - A[i].offset, - A[i].size); - get_int256_from_qualified_field(value_b, - C[i].field, - C[i].offset, - C[i].size); - add_int256_to_int256(value_a, value_b); - - int overflow = squeeze_int256(value_a); - if( overflow ) - { - *compute_error |= compute_error_overflow; - } - - // At this point, we assign the sum to *C. - *compute_error |= conditional_stash(C[i].field, C[i].offset, C[i].size, - on_size_error, - int256_get_u128(value_a, 0), - value_a.rdigits, - *rounded++); - } - } - } - -extern "C" -void -__gg__subtractf1_fixed_phase2(cbl_arith_format_t , - size_t , - cblc_referlet_t *, - size_t , - cblc_referlet_t *, - size_t , - const cblc_referlet_t *C, - const cbl_round_t *rounded, - int on_error_flag, - int *compute_error - ) - { - // This is the assignment phase of an ADD Format 1 - - // We take phase1_result and subtrace it from C - bool on_size_error = !!(on_error_flag & ON_SIZE_ERROR); - - if( C[0].field->type == FldFloat) - { - // The target we need to accumulate into is a floating-point number, so we - // need to convert our fixed-point intermediate into floating point and - // proceed accordingly. - - // Convert the intermediate - GCOB_FP128 value_a = (GCOB_FP128)int256_get_u128(phase1_result, 0); - value_a /= __gg__power_of_ten(phase1_result.rdigits); - - // Pick up the target - GCOB_FP128 value_b = __gg__float128_from_qualified_field(C[0].field, - C[0].offset, - C[0].size); - - value_b -= value_a; - - // At this point, we assign the difference to *C. - *compute_error |= conditional_stash(C[0].field, C[0].offset, C[0].size, - on_size_error, - value_b, - *rounded++); - } - else - { - // We have a fixed-point intermediate, and we are accumulating intoi a - // fixed point target. - int256 value_a = phase1_result; - value_a.rdigits = phase1_result.rdigits; - - int256 value_b = {}; - - get_int256_from_qualified_field(value_b, - C[0].field, - C[0].offset, - C[0].size); - - subtract_int256_from_int256(value_b, value_a); - - int overflow = squeeze_int256(value_b); - if( overflow ) - { - *compute_error |= compute_error_overflow; - } - - // At this point, we assign running_sum to *C. - *compute_error |= conditional_stash(C[0].field, C[0].offset, C[0].size, - on_size_error, - int256_get_u128(value_b, 0), - value_b.rdigits, - *rounded++); - } - } - -extern "C" -void -__gg__subtractf2_fixed_phase1(cbl_arith_format_t , - size_t nA, - const cblc_referlet_t *AA, - size_t , - const cblc_referlet_t *BB, - size_t , - cblc_referlet_t *, - const cbl_round_t *rounded, - int on_error_flag, - int *compute_error - ) - { - // This is the calculation phase of a fixed-point SUBTRACT Format 2 - - // Add up all the A values - __gg__add_fixed_phase1( not_expected_e , - nA, - AA, - 0, - NULL, - 0, - NULL, - rounded, - on_error_flag, - compute_error); - - // Subtract the phase1_result from the B value: - - int256 value_a = phase1_result; - value_a.rdigits = phase1_result.rdigits; - - int256 value_b = {}; - - get_int256_from_qualified_field(value_b, - BB[0].field, - BB[0].offset, - BB[0].size); - - subtract_int256_from_int256(value_b, value_a); - - int overflow = squeeze_int256(value_b); - if( overflow ) - { - *compute_error |= compute_error_overflow; - } - phase1_result = value_b; - phase1_result.rdigits = value_b.rdigits; - } - -extern "C" -void -__gg__subtractf1_float_phase2(cbl_arith_format_t , - size_t , - cblc_referlet_t *, - size_t , - cblc_referlet_t *, - size_t , - const cblc_referlet_t *C, - const cbl_round_t *rounded, - int on_error_flag, - int *compute_error - ) - { - bool on_size_error = !!(on_error_flag & ON_SIZE_ERROR); - // This is the assignment phase of an SUBTRACT Format 2 - // We take phase1_result and subtract it from C - - GCOB_FP128 temp = __gg__float128_from_qualified_field(C[0].field, - C[0].offset, - C[0].size); - temp = subtraction_helper_float(temp, phase1_result_float, compute_error); - *compute_error |= conditional_stash(C[0].field, C[0].offset, C[0].size, - on_size_error, - temp, - *rounded++); - } - -extern "C" -void -__gg__subtractf2_float_phase1(cbl_arith_format_t , - size_t nA, - const cblc_referlet_t *A, - size_t , - const cblc_referlet_t *B, - size_t , - cblc_referlet_t *, - const cbl_round_t *rounded, - int on_error_flag, - int *compute_error - ) - { - // This is the calculation phase of a fixed-point SUBTRACT Format 2 - - // Add up all the A values - __gg__add_float_phase1( not_expected_e , - nA, - A, - 0, - NULL, - 0, - NULL, - rounded, - on_error_flag, - compute_error - ); - - // Subtract that subtotal from the B value: - GCOB_FP128 value_b = __gg__float128_from_qualified_field(B[0].field, - B[0].offset, - B[0].size); - phase1_result_float = subtraction_helper_float(value_b, - phase1_result_float, - compute_error); - } - -extern "C" -void -__gg__subtractf3( cbl_arith_format_t , - size_t nA, - const cblc_referlet_t *A, - size_t , - cblc_referlet_t *, - size_t , - const cblc_referlet_t *C, - const cbl_round_t *rounded, - int on_error_flag, - int *compute_error - ) - { - // This is an ADD Format 3. Each A[i] gets accumulated into each C[i]. Each - // SUBTRACTION is treated separately. - - bool on_size_error = !!(on_error_flag & ON_SIZE_ERROR); - - for(size_t i=0; i<nA; i++) - { - if( A[i].field->type == FldFloat || C[i].field->type == FldFloat) - { - GCOB_FP128 value_a = __gg__float128_from_qualified_field(A[i].field, - A[i].offset, - A[i].size); - GCOB_FP128 value_b = __gg__float128_from_qualified_field(C[i].field, - C[i].offset, - C[i].size); - - value_b = subtraction_helper_float(value_b, value_a, compute_error); - - // At this point, we assign the sum to *C. - *compute_error |= conditional_stash(C[i].field, C[i].offset, C[i].size, - on_size_error, - value_b, - *rounded++); - } - else - { - // We are doing fixed-point subtraction. - int256 value_a; - int256 value_b; - - get_int256_from_qualified_field(value_a, - A[i].field, - A[i].offset, - A[i].size); - get_int256_from_qualified_field(value_b, - C[i].field, - C[i].offset, - C[i].size); - - subtract_int256_from_int256(value_b, value_a); - - int overflow = squeeze_int256(value_b); - - if( overflow ) - { - *compute_error |= compute_error_overflow; - } - - // At this point, we assign the sum to *C. - *compute_error |= conditional_stash(C[i].field, C[i].offset, C[i].size, - on_size_error, - int256_get_u128(value_b, 0), - value_b.rdigits, - *rounded++); - } - } - } - static bool multiply_intermediate_is_float; static GCOB_FP128 multiply_intermediate_float; static int128 multiply_intermediate_int128;
