From: Robert Dubner <[email protected]>
Date: Wed, 18 Feb 2026 23:01:38 -0500
Subject: [PATCH] cobol: Improve generated code for fast_add and
fast_subtract.
These changes improve the efficiency of generated code by recognizing
more instances where operations are on little-endian binary COBOL
variables and then avoiding calls to libgcobol. The generated code
also reduces the number of intermediate variables created for that
little-endian arithmetic.
gcc/cobol/ChangeLog:
* genapi.cc (tree_type_from_field_type): Move static code.
(compare_binary_binary): Identify little-endian compares.
(psa_FldLiteralN): Eliminate obsolete development code; make the
initialized variables TREE_CONSTANT.
(parser_symbol_add): Adjust for modified FldLiteralN.
* genmath.cc (all_results_binary): Renamed. Modified for fastness.
(all_results_integer): Likewise.
(all_refers_integer): Likewise.
(largest_binary_term): Likewise.
(fast_add): Expand conditions. Use get_binary_value_tree.
(fast_subtract): Likewise.
(fast_multiply): Expand conditions.
(fast_divide): Expand conditions.
(parser_add): Avoid fast_add when error or not-error are
specified.
(parser_multiply): Likewise.
(parser_divide): Likewise.
(parser_subtract): Likewise.
* genutil.cc (tree_type_from_field): Disable; flagged for removal.
(get_binary_value): Use get_binary_value_tree.
(get_binary_value_tree): Avoid intermediate variables when
possible.
(refer_is_clean): Formatting.
(is_pure_integer): Refine test for little-endian binary.
* genutil.h (get_binary_value_tree): New declaration.
(is_pure_integer): New declaration.
* symbols.cc (symbol_table_init): Explanatory ZEROS comment.
libgcobol/ChangeLog:
* gfileio.cc (__gg__file_reopen): Raise exception on failed OPEN
* gmath.cc (__gg__fixed_phase2_assign_to_c): Let pointer
arithmetic
go negative.
(__gg__subtractf2_fixed_phase1): Edit a comment.
---
gcc/cobol/genapi.cc | 253 ++++++++++++++++-----------
gcc/cobol/genmath.cc | 408 +++++++++++++++++++++++++++++++++----------
gcc/cobol/genutil.cc | 197 ++++++++++++++++-----
gcc/cobol/genutil.h | 10 ++
gcc/cobol/symbols.cc | 3 +-
libgcobol/gfileio.cc | 4 +
libgcobol/gmath.cc | 17 +-
7 files changed, 648 insertions(+), 244 deletions(-)
diff --git a/gcc/cobol/genapi.cc b/gcc/cobol/genapi.cc
index 78122c12b16..dcf49c7a90e 100644
--- a/gcc/cobol/genapi.cc
+++ b/gcc/cobol/genapi.cc
@@ -2028,6 +2028,102 @@ normal_normal_compare(bool debugging,
}
}
+static
+tree
+tree_type_from_field_type(cbl_field_t *field, size_t &nbytes)
+ {
+ /* This routine is used to determine what action is taken with type of
a
+ CALL ... USING <var> and the matching PROCEDURE DIVISION USING
<var> of
+ a PROGRAM-ID or FUNCTION-ID
+ */
+ tree retval = COBOL_FUNCTION_RETURN_TYPE;
+ nbytes = 8;
+ if( field )
+ {
+ // This maps a Fldxxx to a C-style variable type:
+ switch(field->type)
+ {
+ case FldGroup:
+ case FldAlphanumeric:
+ case FldAlphaEdited:
+ case FldNumericEdited:
+ retval = CHAR_P;
+ nbytes = field->data.capacity();
+ break;
+
+ case FldNumericDisplay:
+ case FldNumericBinary:
+ case FldPacked:
+ if( field->data.digits > 18 )
+ {
+ retval = UINT128;
+ nbytes = 16;
+ }
+ else
+ {
+ retval = SIZE_T;
+ nbytes = 8;
+ }
+ break;
+
+ case FldNumericBin5:
+ case FldIndex:
+ case FldPointer:
+ if( field->data.capacity() > 8 )
+ {
+ retval = UINT128;
+ nbytes = 16;
+ }
+ else
+ {
+ retval = SIZE_T;
+ nbytes = 8;
+ }
+ break;
+
+ case FldFloat:
+ if( field->data.capacity() == 8 )
+ {
+ retval = DOUBLE;
+ nbytes = 8;
+ }
+ else if( field->data.capacity() == 4 )
+ {
+ retval = FLOAT;
+ nbytes = 4;
+ }
+ else
+ {
+ retval = FLOAT128;
+ nbytes = 16;
+ }
+ break;
+
+ case FldLiteralN:
+ // Assume a 64-bit signed integer. This happens for GOBACK
STATUS 101,
+ // the like
+ retval = LONG;
+ nbytes = 8;
+ break;
+
+ default:
+ cbl_internal_error( "%s: Invalid field type %s:",
+ __func__,
+ cbl_field_type_str(field->type));
+ break;
+ }
+ if( retval == SIZE_T && field->attr & signable_e )
+ {
+ retval = SSIZE_T;
+ }
+ if( retval == UINT128 && field->attr & signable_e )
+ {
+ retval = INT128;
+ }
+ }
+ return retval;
+ }
+
static void
compare_binary_binary(tree return_int,
cbl_refer_t *left_side_ref,
@@ -2040,6 +2136,54 @@ compare_binary_binary(tree return_int,
tree left_side;
tree right_side;
+ // Let's check for the simplified case where both left and right sides
are
+ // little-endian binary values:
+
+ if( is_pure_integer(left_side_ref->field)
+ && is_pure_integer(right_side_ref->field) )
+ {
+ size_t left_bytes;
+ tree left_type = tree_type_from_field_type(left_side_ref->field,
+ left_bytes);
+ size_t right_bytes;
+ tree right_type = tree_type_from_field_type(right_side_ref->field,
+ right_bytes);
+ tree larger;
+ if( TREE_INT_CST_LOW(TYPE_SIZE(left_type))
+ > TREE_INT_CST_LOW(TYPE_SIZE(right_type)) )
+ {
+ larger = left_type;
+ }
+ else
+ {
+ larger = right_type;
+ }
+ left_side = get_binary_value_tree(larger,
+ NULL,
+ *left_side_ref);
+ right_side = get_binary_value_tree(larger,
+ NULL,
+ *right_side_ref);
+ IF( left_side, eq_op, right_side )
+ {
+ gg_assign(return_int, integer_zero_node);
+ }
+ ELSE
+ {
+ IF( left_side, lt_op, right_side )
+ {
+ gg_assign(return_int, integer_minusone_node);
+ }
+ ELSE
+ {
+ gg_assign(return_int, integer_one_node);
+ }
+ ENDIF
+ }
+ ENDIF
+ return;
+ }
+
// Use SIZE128 when we need two 64-bit registers to hold the value.
All
// others fit into 64-bit LONG with pretty much the same efficiency.
@@ -4133,11 +4277,7 @@ psa_FldLiteralN(struct cbl_field_t *field )
uint32_t digits;
int32_t rdigits;
uint64_t attr;
- //// DUBNERHACK. Necessary to prevent UAT lockup:
- const char *source_text = field->data.original()
- ? field->data.original()
- : field->data.initial;
- FIXED_WIDE_INT(128) value = dirty_to_binary(source_text,
+ FIXED_WIDE_INT(128) value = dirty_to_binary(field->data.original(),
capacity,
digits,
rdigits,
@@ -4167,7 +4307,9 @@ psa_FldLiteralN(struct cbl_field_t *field )
tree new_var_decl = gg_define_variable( var_type,
base_name,
vs_static);
- DECL_INITIAL(new_var_decl) = wide_int_to_tree(var_type, value);
+ DECL_INITIAL(new_var_decl) = wide_int_to_tree(var_type, value);
+ TREE_CONSTANT(new_var_decl) = 1;
+
field->data_decl_node = new_var_decl;
// Note that during compilation, the integer value, assuming it can be
@@ -6148,102 +6290,6 @@ vs_file_static);
gg_free(ttbls);
}
-static
-tree
-tree_type_from_field_type(cbl_field_t *field, size_t &nbytes)
- {
- /* This routine is used to determine what action is taken with type of
a
- CALL ... USING <var> and the matching PROCEDURE DIVISION USING
<var> of
- a PROGRAM-ID or FUNCTION-ID
- */
- tree retval = COBOL_FUNCTION_RETURN_TYPE;
- nbytes = 8;
- if( field )
- {
- // This maps a Fldxxx to a C-style variable type:
- switch(field->type)
- {
- case FldGroup:
- case FldAlphanumeric:
- case FldAlphaEdited:
- case FldNumericEdited:
- retval = CHAR_P;
- nbytes = field->data.capacity();
- break;
-
- case FldNumericDisplay:
- case FldNumericBinary:
- case FldPacked:
- if( field->data.digits > 18 )
- {
- retval = UINT128;
- nbytes = 16;
- }
- else
- {
- retval = SIZE_T;
- nbytes = 8;
- }
- break;
-
- case FldNumericBin5:
- case FldIndex:
- case FldPointer:
- if( field->data.capacity() > 8 )
- {
- retval = UINT128;
- nbytes = 16;
- }
- else
- {
- retval = SIZE_T;
- nbytes = 8;
- }
- break;
-
- case FldFloat:
- if( field->data.capacity() == 8 )
- {
- retval = DOUBLE;
- nbytes = 8;
- }
- else if( field->data.capacity() == 4 )
- {
- retval = FLOAT;
- nbytes = 4;
- }
- else
- {
- retval = FLOAT128;
- nbytes = 16;
- }
- break;
-
- case FldLiteralN:
- // Assume a 64-bit signed integer. This happens for GOBACK
STATUS 101,
- // the like
- retval = LONG;
- nbytes = 8;
- break;
-
- default:
- cbl_internal_error( "%s: Invalid field type %s:",
- __func__,
- cbl_field_type_str(field->type));
- break;
- }
- if( retval == SIZE_T && field->attr & signable_e )
- {
- retval = SSIZE_T;
- }
- if( retval == UINT128 && field->attr & signable_e )
- {
- retval = INT128;
- }
- }
- return retval;
- }
-
static void
restore_local_variables()
{
@@ -17428,7 +17474,8 @@ parser_symbol_add(struct cbl_field_t *new_var )
free(level_88_string);
free(class_string);
- if( !(new_var->attr & ( linkage_e | based_e)) )
+ if( !(new_var->attr & ( linkage_e | based_e))
+ && !(new_var->type == FldLiteralN) )
{
static const bool explicitly = false;
static const bool just_once = true;
diff --git a/gcc/cobol/genmath.cc b/gcc/cobol/genmath.cc
index 18ba682f30b..6eb87544ac0 100644
--- a/gcc/cobol/genmath.cc
+++ b/gcc/cobol/genmath.cc
@@ -329,13 +329,29 @@ is_somebody_float(size_t nC, const cbl_num_result_t
*C)
}
static bool
-all_results_binary(size_t nC, const cbl_num_result_t *C)
+all_results_integer(size_t nC, const cbl_num_result_t *C)
{
bool retval = true;
for(size_t i=0; i<nC; i++)
{
- if(C[i].refer.field->data.digits != 0 || C[i].refer.field->type ==
FldFloat )
+ if( !is_pure_integer(C[i].refer.field) )
+ {
+ retval = false;
+ break;
+ }
+ }
+ return retval;
+ }
+
+static bool
+all_refers_integer(size_t nC, const cbl_refer_t *C)
+ {
+ bool retval = true;
+
+ for(size_t i=0; i<nC; i++)
+ {
+ if( !is_pure_integer(C[i].field) )
{
retval = false;
break;
@@ -353,18 +369,20 @@ largest_binary_term(size_t nA, cbl_refer_t *A)
for(size_t i=0; i<nA; i++)
{
- if( A[i].field->data.rdigits || A[i].field->type == FldFloat )
+ if( !is_pure_integer(A[i].field) || A[i].field->type == FldFloat )
{
- // We are prepared to work only with integers
+ // We are prepared to work only with binary integers
retval = NULL_TREE;
break;
}
if( A[i].field->type == FldLiteralN
-// || A[i].field->type == FldNumericDisplay
|| A[i].field->type == FldNumericBinary
|| A[i].field->type == FldNumericBin5
|| A[i].field->type == FldIndex
- || A[i].field->type == FldPointer )
+ || A[i].field->type == FldPointer
+ || ( A[i].field->type == FldAlphanumeric
+ && strcmp(A[i].field->name, "ZEROS") == 0 )
+ )
{
// This is an integer type that can be worked with quickly
is_negative |= ( A[i].field->attr & signable_e );
@@ -386,62 +404,173 @@ fast_add( size_t nC, cbl_num_result_t *C,
size_t nA, cbl_refer_t *A,
cbl_arith_format_t format )
{
+ /* ADD A TO D: nC==1, nA==1, D += A.
+ ADD A B C TO D: nC==1, nA==3, D = (A + B + C)
+ ADD A B C TO D E nC==2, nA==3
+ ADD A TO B GIVING D nC==1, nA==2, format==giving_e
+ ADD A B C TO D GIVING X Y nC==2, nA==3, format==giving_e */
bool retval = false;
- if( all_results_binary(nC, C) )
+ if( all_results_integer(nC, C)
+ && all_refers_integer(nA, A) )
{
Analyze();
// All targets are non-PICTURE binaries:
tree term_type = largest_binary_term(nA, A);
if( term_type )
{
- // All the terms are things we can work with.
-
- // We need to calculate the sum of all the A[] terms using
term_type as
- // the intermediate type:
-
- tree sum = gg_define_variable(term_type);
- tree addend = gg_define_variable(term_type);
- get_binary_value( sum,
- NULL,
- A[0].field,
- refer_offset(A[0]));
-
- // Add in the rest of them:
- for(size_t i=1; i<nA; i++)
+ tree dest_type = tree_type_from_size(
+
C[0].refer.field->data.capacity(),
+ 0);
+ // All the numbers are integers without rdigits
+ if( nC == 1
+ && nA == 1
+ && format != giving_e
+ )
{
- get_binary_value( addend,
- NULL,
- A[i].field,
- refer_offset(A[i]));
- gg_assign(sum, gg_add(sum, addend));
- }
- //gg_printf("The intermediate sum is %ld\n", gg_cast(LONG, sum),
NULL_TREE);
+ // This is the simplest case of all. Just add A to C. We can't
+ // naively add A to multiple C, because of the possibility of
+ // ADD A TO A B C. That would change A before A gets added to B
and
+ // C, which is not how COBOL works.
- // We now either accumulate into C[n] or assign to C[n]:
- for(size_t i=0; i<nC; i++ )
- {
- tree dest_type =
tree_type_from_size(C[i].refer.field->data.capacity(), 0);
- tree dest_addr = gg_add(member(C[i].refer.field->var_decl_node,
"data"),
- refer_offset(C[i].refer));
- tree ptr = gg_cast(build_pointer_type(dest_type), dest_addr);
- if( format == giving_e )
+ tree A_value;
+ if( refer_is_clean(A[0]) )
+ {
+ A_value = get_binary_value_tree(dest_type,
+ NULL, // No rdigits
+ A[0].field,
+ integer_zero_node);
+ }
+ else
{
- // We are assigning
+ A_value = get_binary_value_tree(dest_type,
+ NULL, // No rdigits
+ A[0].field,
+ refer_offset(A[0]));
+ }
+ if( refer_is_clean(C[0].refer) )
+ {
+ tree dest_addr = member(C[0].refer.field->var_decl_node,
+ "data");
+ tree ptr = gg_cast(build_pointer_type(dest_type), dest_addr);
+ // We are accumulating into memory
gg_assign( gg_indirect(ptr),
- gg_cast(dest_type, sum));
+ gg_add( gg_indirect(ptr),
+ A_value));
}
else
{
- // We are accumulating
+ tree dest_addr = gg_add(member(C[0].refer.field->var_decl_node,
+ "data"),
+ refer_offset(C[0].refer));
+ tree ptr = gg_cast(build_pointer_type(dest_type), dest_addr);
+ // We are accumulating into memory
gg_assign( gg_indirect(ptr),
gg_add( gg_indirect(ptr),
- gg_cast(dest_type, sum)));
+ A_value));
+ }
+ }
+ else if( nC == 1
+ && nA == 2
+ && format == giving_e )
+ {
+ // This is the very common ADD A TO B GIVING C
+ {
+ // Make C = A[0] + A[1]
+ tree dest_addr;
+ if( refer_is_clean(C[0].refer) )
+ {
+ dest_addr = member(C[0].refer.field->var_decl_node, "data");
+ }
+ else
+ {
+ dest_addr = gg_add(member(C[0].refer.field->var_decl_node,
"data"),
+ refer_offset(C[0].refer));
+ }
+ dest_addr = gg_cast(build_pointer_type(dest_type), dest_addr);
+
+ tree A_value;
+ if( refer_is_clean(A[0]) )
+ {
+ A_value = get_binary_value_tree(dest_type,
+ NULL, // No rdigits
+ A[0].field,
+ integer_zero_node);
+ }
+ else
+ {
+ A_value = get_binary_value_tree(dest_type,
+ NULL, // No rdigits
+ A[0].field,
+ refer_offset(A[0]));
+ }
+
+ tree B_value;
+ if( refer_is_clean(A[1]) )
+ {
+ B_value = get_binary_value_tree(dest_type,
+ NULL, // No rdigits
+ A[1].field,
+ integer_zero_node);
+ }
+ else
+ {
+ B_value = get_binary_value_tree(dest_type,
+ NULL, // No rdigits
+ A[1].field,
+ refer_offset(A[1]));
+ }
+
+ gg_assign( gg_indirect(dest_addr),
+ gg_add( A_value,
+ B_value));
+ }
+ }
+ else
+ {
+ // We need to calculate the sum of all the A[] terms using
term_type as
+ // the intermediate type:
+
+ tree sum = gg_define_variable(term_type);
+ tree addend = gg_define_variable(term_type);
+ get_binary_value( sum,
+ NULL,
+ A[0].field,
+ refer_offset(A[0]));
+
+ // Add in the rest of them:
+ for(size_t i=1; i<nA; i++)
+ {
+ get_binary_value( addend,
+ NULL,
+ A[i].field,
+ refer_offset(A[i]));
+ gg_assign(sum, gg_add(sum, addend));
+ }
+
+ // We now either accumulate into C[n] or assign to C[n]:
+ for(size_t i=0; i<nC; i++ )
+ {
+ tree dest_addr = gg_add(member(C[i].refer.field->var_decl_node,
+ "data"),
+ refer_offset(C[i].refer));
+ tree ptr = gg_cast(build_pointer_type(dest_type), dest_addr);
+ if( format == giving_e )
+ {
+ // We are assigning
+ gg_assign( gg_indirect(ptr),
+ gg_cast(dest_type, sum));
+ }
+ else
+ {
+ // We are accumulating
+ gg_assign( gg_indirect(ptr),
+ gg_add( gg_indirect(ptr),
+ gg_cast(dest_type, sum)));
+ }
}
}
retval = true;
}
-
- //gg_insert_into_assembler("# DUBNER addition END ");
}
return retval;
}
@@ -452,8 +581,15 @@ fast_subtract(size_t nC, cbl_num_result_t *C,
size_t nB, cbl_refer_t *B,
cbl_arith_format_t format)
{
+ /* SUBTRACT A FROM D: nC==1, nA==1, nB==0: D -= A.
+ SUBTRACT A B C FROM D: nC==1, nA==3, nB==0: D -= (A + B + C)
+ SUBTRACT A B C FROM D E nC==2, nA==3
+ SUBTRACT A B C FROM D GIVING X Y
+ nC==2, nA==3, nB==1 */
bool retval = false;
- if( all_results_binary(nC, C) )
+ if( all_refers_integer(nA, A)
+ && all_refers_integer(nB, B)
+ && all_results_integer(nC, C) )
{
Analyze();
// All targets are non-PICTURE binaries:
@@ -480,48 +616,136 @@ fast_subtract(size_t nC, cbl_num_result_t *C,
if( term_type )
{
// All the terms are things we can work with.
+ // All the numbers are integers without rdigits
+ if( nC == 1
+ && nA == 1
+ && nB <= 1
+ )
+ {
+ // This is the simplest case of all. Just subtract A from C.
+ tree dest_type = tree_type_from_size(
+
C[0].refer.field->data.capacity(),
+ 0);
+ tree A_value;
+ if( refer_is_clean(A[0]) )
+ {
+ A_value = get_binary_value_tree(dest_type,
+ NULL, // No rdigits
+ A[0].field,
+ integer_zero_node);
+ }
+ else
+ {
+ A_value = get_binary_value_tree(dest_type,
+ NULL, // No rdigits
+ A[0].field,
+ refer_offset(A[0]));
+ }
+ if( format == giving_e )
+ {
+ // Make C = B - A
+ tree dest_addr;
+ if( refer_is_clean(C[0].refer) )
+ {
+ dest_addr = member(C[0].refer.field->var_decl_node, "data");
+ }
+ else
+ {
+ dest_addr = gg_add(member(C[0].refer.field->var_decl_node,
"data"),
+ refer_offset(C[0].refer));
+ }
+ dest_addr = gg_cast(build_pointer_type(dest_type), dest_addr);
- // We need to calculate the sum of all the A[] terms using
term_type as
- // the intermediate type:
-
- tree sum = gg_define_variable(term_type);
- tree addend = gg_define_variable(term_type);
- get_binary_value(sum, NULL, A[0].field, refer_offset(A[0]));
+ tree B_value;
+ if( refer_is_clean(B[0]) )
+ {
+ B_value = get_binary_value_tree(dest_type,
+ NULL, // No rdigits
+ B[0].field,
+ integer_zero_node);
+ }
+ else
+ {
+ B_value = get_binary_value_tree(dest_type,
+ NULL, // No rdigits
+ B[0].field,
+ refer_offset(B[0]));
+ }
- // Add in the rest of them:
- for(size_t i=1; i<nA; i++)
- {
- get_binary_value(sum, NULL, A[i].field, refer_offset(A[i]));
- gg_assign(sum, gg_add(sum, addend));
+ gg_assign( gg_indirect(dest_addr),
+ gg_cast(dest_type, gg_subtract( B_value,
+ A_value)));
+ }
+ else
+ {
+ // Make C = C - A
+ if( refer_is_clean(C[0].refer) )
+ {
+ tree dest_addr = member(C[0].refer.field->var_decl_node,
+ "data");
+ tree ptr = gg_cast(build_pointer_type(dest_type), dest_addr);
+ // We are subtracting from memory
+ gg_assign( gg_indirect(ptr),
+ gg_subtract( gg_indirect(ptr),
+ A_value));
+ }
+ else
+ {
+ tree dest_addr =
gg_add(member(C[0].refer.field->var_decl_node,
+ "data"),
+ refer_offset(C[0].refer));
+ tree ptr = gg_cast(build_pointer_type(dest_type), dest_addr);
+ // We are subtracting from memory
+ gg_assign( gg_indirect(ptr),
+ gg_subtract( gg_indirect(ptr),
+ A_value));
+ }
+ }
}
- //gg_printf("The intermediate sum is %ld\n", gg_cast(LONG, sum),
NULL_TREE);
-
- if( format == giving_e )
+ else
{
- // We now subtract the sum from B[0]
- get_binary_value(addend, NULL, B[0].field, refer_offset(B[0]));
- gg_assign(sum, gg_subtract(addend, sum));
- }
+ // We need to calculate the sum of all the A[] terms using
term_type as
+ // the intermediate type:
+
+ tree sum = gg_define_variable(term_type);
+ tree addend = gg_define_variable(term_type);
+ get_binary_value(sum, NULL, A[0].field, refer_offset(A[0]));
+
+ // Add in the rest of them:
+ for(size_t i=1; i<nA; i++)
+ {
+ get_binary_value(addend, NULL, A[i].field, refer_offset(A[i]));
+ gg_assign(sum, gg_add(sum, addend));
+ }
+ //gg_printf("The intermediate sum is %ld\n", gg_cast(LONG, sum),
NULL_TREE);
- // We now either accumulate into C[n] or assign to C[n]:
- for(size_t i=0; i<nC; i++ )
- {
- tree dest_type =
tree_type_from_size(C[i].refer.field->data.capacity(), 0);
- tree dest_addr = gg_add(member(C[i].refer.field->var_decl_node,
"data"),
- refer_offset(C[i].refer));
- tree ptr = gg_cast(build_pointer_type(dest_type), dest_addr);
if( format == giving_e )
{
- // We are assigning
- gg_assign( gg_indirect(ptr),
- gg_cast(dest_type, sum));
+ // We now subtract the sum from B[0]
+ get_binary_value(addend, NULL, B[0].field, refer_offset(B[0]));
+ gg_assign(sum, gg_subtract(addend, sum));
}
- else
+
+ // We now either accumulate into C[n] or assign to C[n]:
+ for(size_t i=0; i<nC; i++ )
{
- // We are subtracting the sum from C[i]
- gg_assign( gg_indirect(ptr),
- gg_subtract(gg_indirect(ptr),
- gg_cast(dest_type, sum)));
+ tree dest_type =
tree_type_from_size(C[i].refer.field->data.capacity(), 0);
+ tree dest_addr = gg_add(member(C[i].refer.field->var_decl_node,
"data"),
+ refer_offset(C[i].refer));
+ tree ptr = gg_cast(build_pointer_type(dest_type), dest_addr);
+ if( format == giving_e )
+ {
+ // We are assigning
+ gg_assign( gg_indirect(ptr),
+ gg_cast(dest_type, sum));
+ }
+ else
+ {
+ // We are subtracting the sum from C[i]
+ gg_assign( gg_indirect(ptr),
+ gg_subtract(gg_indirect(ptr),
+ gg_cast(dest_type, sum)));
+ }
}
}
retval = true;
@@ -536,7 +760,7 @@ fast_multiply(size_t nC, cbl_num_result_t *C,
size_t nB, cbl_refer_t *B)
{
bool retval = false;
- if( all_results_binary(nC, C) )
+ if( all_results_integer(nC, C) )
{
Analyze();
// All targets are non-PICTURE binaries:
@@ -609,7 +833,7 @@ fast_divide(size_t nC, cbl_num_result_t *C,
const cbl_refer_t &remainder)
{
bool retval = false;
- if( all_results_binary(nC, C) )
+ if( all_results_integer(nC, C) )
{
Analyze();
// All targets are non-PICTURE binaries:
@@ -746,9 +970,9 @@ parser_add( size_t nC, cbl_num_result_t *C,
bool handled = false;
- if( fast_add( nC, C,
- nA, A,
- format) )
+ if( !error && !not_error && fast_add(nC, C,
+ nA, A,
+ format) )
{
handled = true;
}
@@ -1017,9 +1241,9 @@ parser_multiply(size_t nC, cbl_num_result_t *C,
SHOW_PARSE_END
}
- if( fast_multiply(nC, C,
- nA, A,
- nB, B) )
+ if( !error && !not_error && fast_multiply(nC, C,
+ nA, A,
+ nB, B) )
{
}
@@ -1108,10 +1332,10 @@ parser_divide( size_t nC, cbl_num_result_t *C,
// C = A / B
SHOW_PARSE_END
}
- if( fast_divide(nC, C,
- nA, A,
- nB, B,
- remainder) )
+ if( !error && !not_error && fast_divide(nC, C,
+ nA, A,
+ nB, B,
+ remainder) )
{
}
@@ -1441,10 +1665,10 @@ parser_subtract(size_t nC, cbl_num_result_t *C, //
C = B - A
bool handled = false;
- if( fast_subtract(nC, C,
- nA, A,
- nB, B,
- format) )
+ if( !error && !not_error && fast_subtract(nC, C,
+ nA, A,
+ nB, B,
+ format) )
{
handled = true;
}
diff --git a/gcc/cobol/genutil.cc b/gcc/cobol/genutil.cc
index a143080542d..25f7b8070fa 100644
--- a/gcc/cobol/genutil.cc
+++ b/gcc/cobol/genutil.cc
@@ -744,17 +744,18 @@ get_data_offset(const cbl_refer_t &refer,
return retval;
}
-static tree tree_type_from_field(const cbl_field_t *field);
+//static tree tree_type_from_field(const cbl_field_t *field);
-void
-get_binary_value( tree value,
- tree rdigits,
- cbl_field_t *field,
- tree field_offset,
- tree hilo
- )
+tree
+get_binary_value_tree(tree return_type,
+ tree rdigits,
+ cbl_field_t *field,
+ tree field_offset,
+ tree hilo
+ )
{
- Analyze();
+ tree retval;
+
if( hilo )
{
gg_assign(hilo, integer_zero_node);
@@ -766,12 +767,12 @@ get_binary_value( tree value,
// Very special case:
if( strcmp(field->name, "ZEROS") == 0 )
{
- gg_assign(value, gg_cast(TREE_TYPE(value), integer_zero_node));
+ retval = gg_cast(return_type, integer_zero_node);
if( rdigits )
{
gg_assign(rdigits, gg_cast(TREE_TYPE(rdigits), integer_zero_node));
}
- return;
+ return retval;
}
static tree pointer = gg_define_variable( UCHAR_P,
@@ -781,7 +782,7 @@ get_binary_value( tree value,
{
case FldLiteralN:
{
- if( SCALAR_FLOAT_TYPE_P(value) )
+ if( return_type == FLOAT )
{
cbl_internal_error("cannot get %<float%> value from %s",
field->name);
}
@@ -792,21 +793,17 @@ get_binary_value( tree value,
gg_assign(rdigits, build_int_cst_type(TREE_TYPE(rdigits),
field->data.rdigits));
}
- tree dest_type = TREE_TYPE(value);
- tree source_type = tree_type_from_field(field);
-
- gg_assign(value,
- gg_cast(dest_type,
- gg_indirect(
gg_cast(build_pointer_type(source_type),
-
gg_get_address_of(field->data_decl_node)))));
+ // tree source_type = tree_type_from_field(field);
+ // retval = gg_cast(return_type,
+ // gg_indirect(
gg_cast(build_pointer_type(source_type),
+ //
gg_get_address_of(field->data_decl_node))));
+ retval = gg_cast(return_type, field->data_decl_node);
}
-
break;
}
case FldNumericDisplay:
{
- Analyzer.Message("FldNumericDisplay");
const charmap_t *charmap =
__gg__get_charmap(field->codeset.encoding);
int stride = charmap->stride();
@@ -829,14 +826,13 @@ get_binary_value( tree value,
build_int_cst_type( TREE_TYPE(rdigits),
get_scaled_rdigits(field)));
}
- gg_assign(value, build_int_cst_type(TREE_TYPE(value),
- 0x7FFFFFFFFFFFFFFFUL));
+ retval = build_int_cst_type(return_type, 0x7FFFFFFFFFFFFFFFUL);
}
ELSE
{
IF( digit, eq_op, build_int_cst(UCHAR, DEGENERATE_LOW_VALUE) )
{
- // We are dealing with LOW-VALUE
+ // We are dealing with LOW-VALUE
if( hilo )
{
gg_assign(hilo, integer_minus_one_node);
@@ -918,7 +914,10 @@ get_binary_value( tree value,
build_int_cst_type(INT,
field->codeset.encoding),
NULL_TREE));
// Assign the value we got from the string to our "return"
value:
- gg_assign(value, gg_cast(TREE_TYPE(value), val128));
+
+ // Note that cppcheck can't understand the run-time IF()
+ // cppcheck-suppress redundantAssignment
+ retval = gg_cast(return_type, val128);
}
ENDIF
}
@@ -931,10 +930,11 @@ get_binary_value( tree value,
{
// As of this writing, the source value is big-endian
// We have to convert it to a little-endian destination.
+ tree value = gg_define_variable(return_type);
tree dest = gg_cast(build_pointer_type(UCHAR),
gg_get_address_of(value));
tree source = get_data_address(field, field_offset);
- size_t dest_nbytes = gg_sizeof(value);
+ size_t dest_nbytes =
TREE_INT_CST_LOW(TYPE_SIZE_UNIT(return_type));
size_t source_nbytes = field->data.capacity();
if( debugging )
@@ -968,7 +968,7 @@ get_binary_value( tree value,
if( field->attr & signable_e )
{
IF( gg_array_value(gg_cast(build_pointer_type(SCHAR), source)),
- lt_op,
+ lt_op,
gg_cast(SCHAR, integer_zero_node) )
{
gg_assign(extension, build_int_cst_type(UCHAR, 0xFF));
@@ -1007,6 +1007,7 @@ get_binary_value( tree value,
hex_dump(dest, dest_nbytes);
gg_printf("\n", NULL_TREE);
}
+ retval = value;
break;
}
@@ -1035,7 +1036,6 @@ get_binary_value( tree value,
}
}
tree source_address = get_data_address(field, field_offset);
- tree dest_type = TREE_TYPE(value);
tree source_type = tree_type_from_size( field->data.capacity(),
field->attr & signable_e);
if( debugging && rdigits)
@@ -1043,10 +1043,9 @@ get_binary_value( tree value,
gg_printf("get_binary_value bin5 rdigits: %d\n", rdigits,
NULL_TREE);
}
- gg_assign(value,
- gg_cast(dest_type,
- gg_indirect(gg_cast(
build_pointer_type(source_type),
- source_address ))));
+ retval = gg_cast(return_type,
+ gg_indirect(gg_cast(
build_pointer_type(source_type),
+ source_address )));
break;
}
@@ -1058,17 +1057,16 @@ get_binary_value( tree value,
build_int_cst_type( TREE_TYPE(rdigits),
get_scaled_rdigits(field)));
}
- tree dest_type = TREE_TYPE(value);
-
- gg_assign(value,
- gg_cast(dest_type,
- gg_call_expr(INT128,
+ tree value = gg_define_variable(return_type);
+ gg_assign(value, gg_cast(return_type,
+ gg_call_expr(INT128,
"__gg__packed_to_binary",
get_data_address( field,
field_offset),
build_int_cst_type(INT,
field->data.capacity()),
NULL_TREE)));
+ retval = value;
break;
}
@@ -1080,13 +1078,14 @@ get_binary_value( tree value,
gg_assign(rdigits,
gg_cast( TREE_TYPE(rdigits), integer_zero_node));
}
- gg_assign(value,
- gg_cast(TREE_TYPE(value),
- gg_call_expr( INT128,
- "__gg__integer_from_float128",
-
gg_get_address_of(field->var_decl_node),
- NULL_TREE)));
+ tree value = gg_define_variable(return_type);
+ gg_assign(value, gg_cast(return_type,
+ gg_call_expr( INT128,
+ "__gg__integer_from_float128",
+
gg_get_address_of(field->var_decl_node),
+ NULL_TREE)));
needs_scaling = false;
+ retval = value;
break;
}
@@ -1108,18 +1107,70 @@ get_binary_value( tree value,
{
if( field->data.rdigits < 0 )
{
+ // Hey, Dubner!
+ // Should that test be != 0 rather than < 0? Maybe not; this
routine
+ // is supposed to be for integers.
+ tree value = gg_define_variable(return_type);
+ gg_assign(value, retval);
scale_by_power_of_ten_N(value, -field->data.rdigits);
+ retval = value;
}
}
}
+ return retval;
+ }
+
+tree
+get_binary_value_tree(tree return_type,
+ tree rdigits,
+ const cbl_refer_t &refer,
+ tree hilo
+ )
+ {
+ tree retval;
+ if( refer_is_clean(refer) )
+ {
+ retval = get_binary_value_tree(return_type,
+ rdigits,
+ refer.field,
+ integer_zero_node,
+ hilo);
+ }
+ else
+ {
+ retval = get_binary_value_tree(return_type,
+ rdigits,
+ refer.field,
+ refer_offset(refer),
+ hilo);
+ }
+ return retval;
+ }
+
+void
+get_binary_value( tree value,
+ tree rdigits,
+ cbl_field_t *field,
+ tree field_offset,
+ tree hilo
+ )
+ {
+ tree return_type = TREE_TYPE(value);
+ gg_assign(value, get_binary_value_tree( return_type,
+ rdigits,
+ field,
+ field_offset,
+ hilo ));
}
+#if 0
static tree
tree_type_from_field(const cbl_field_t *field)
{
gcc_assert(field);
return tree_type_from_size(field->data.capacity(), field->attr &
signable_e);
}
+#endif
tree
get_data_address( cbl_field_t *field,
@@ -1788,7 +1839,7 @@ refer_is_clean(const cbl_refer_t &refer)
// like.
return true;
}
-
+
return !refer.all
&& !refer.addr_of
&& !refer.nsubscript()
@@ -1989,3 +2040,61 @@ get_time_nanoseconds()
#endif
return retval;
}
+
+bool
+is_pure_integer(const cbl_field_t *field)
+ {
+ // Check to see if field is suitable for fast arithmetic. That is, it
is
+ // a native binary integer with no fixed-point decimal places:
+ bool retval = false;
+ switch( field->type )
+ {
+ case FldIndex:
+ case FldPointer:
+ case FldLiteralN:
+ retval = true;
+ break;
+
+ case FldNumericBin5:
+ if( !(field->attr & intermediate_e) && field->data.rdigits == 0 )
+ {
+ // This is a pure integer, with no rdigits
+ switch(field->data.capacity())
+ {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ case 16:
+ // These are the sizes we know how to handle
+ retval = true;
+ break;
+ }
+ }
+ break;
+
+ case FldAlphanumeric:
+ if( strcmp(field->name, "ZEROS") == 0 )
+ {
+ retval = true;
+ }
+ break;
+
+ case FldInvalid:
+ case FldGroup:
+ case FldNumericBinary:
+ case FldFloat:
+ case FldPacked:
+ case FldNumericDisplay:
+ case FldNumericEdited:
+ case FldAlphaEdited:
+ case FldLiteralA:
+ case FldClass:
+ case FldConditional:
+ case FldForward:
+ case FldSwitch:
+ case FldDisplay:
+ break;
+ }
+ return retval;
+ }
diff --git a/gcc/cobol/genutil.h b/gcc/cobol/genutil.h
index f456f203ba5..3a2951e8175 100644
--- a/gcc/cobol/genutil.h
+++ b/gcc/cobol/genutil.h
@@ -91,6 +91,15 @@ void get_binary_value( tree value,
cbl_field_t *field,
tree field_offset,
tree hilo = NULL);
+tree get_binary_value_tree(tree return_type,
+ tree rdigits,
+ cbl_field_t *field,
+ tree field_offset,
+ tree hilo = NULL);
+tree get_binary_value_tree(tree return_type,
+ tree rdigits,
+ const cbl_refer_t &refer,
+ tree hilo = NULL);
tree get_data_address( cbl_field_t *field,
tree offset);
@@ -150,5 +159,6 @@ void build_array_of_fourplets( int ngroup,
void get_depending_on_value_from_odo(tree retval, cbl_field_t *odo);
uint64_t get_time_nanoseconds();
+bool is_pure_integer(const cbl_field_t *field);
#endif
diff --git a/gcc/cobol/symbols.cc b/gcc/cobol/symbols.cc
index ea686ab9c4e..6229365284d 100644
--- a/gcc/cobol/symbols.cc
+++ b/gcc/cobol/symbols.cc
@@ -2295,7 +2295,8 @@ symbol_table_init(void) {
{ FldAlphanumeric, LOW_VALUE_E | constq | register_e,
{1,1,0,0, "L\0\xFF"}, 0, "LOW_VALUES", cp1252 },
{ FldAlphanumeric, ZERO_VALUE_E | constq | register_e,
- {1,1,0,0, "0"}, 0, "ZEROS", cp1252 },
+ {1,1,0,0, "0"}, 0, "ZEROS", cp1252 }, // Don't change "ZEROS";
there are
+ // things that depend on it.
{ FldAlphanumeric, HIGH_VALUE_E | constq | register_e,
{1,1,0,0, "H\0\xFF"}, 0, "HIGH_VALUES", cp1252 },
// IBM standard: QUOTE is a double-quote unless APOST compiler option
diff --git a/libgcobol/gfileio.cc b/libgcobol/gfileio.cc
index 144111ac0a6..884a145dbd5 100644
--- a/libgcobol/gfileio.cc
+++ b/libgcobol/gfileio.cc
@@ -4459,6 +4459,10 @@ __gg__file_reopen(cblc_file_t *file, int mode_char)
done:
file->prior_op = file_op_open;
+ // Call establish_status to raise exception if OPEN failed
+ // This ensures that if file->file_pointer is NULL, an exception is
raised
+ // Patch by George Neill of data-axle.com
+ establish_status(file, -1);
}
static void
diff --git a/libgcobol/gmath.cc b/libgcobol/gmath.cc
index 2078dbedca5..9419986d9be 100644
--- a/libgcobol/gmath.cc
+++ b/libgcobol/gmath.cc
@@ -731,7 +731,7 @@ __gg__fixed_phase2_assign_to_c( cbl_arith_format_t ,
int *compute_error
)
{
- // This is the assignment phase of an ADD Format 2
+ // This is the assignment phase of an ADD or SUBTRACT Format 2
cblc_field_t **C = __gg__treeplet_3f;
const size_t *C_o = __gg__treeplet_3o;
@@ -769,6 +769,15 @@ __gg__fixed_phase2_assign_to_c( cbl_arith_format_t ,
*compute_error |= compute_error_overflow;
}
+ if( C[0]->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.
+ value_a.i128[0] &= 0xFFFFFFFFFFFFFFFFUL;
+ }
+
// At this point, we assign that value to *C.
*compute_error |= conditional_stash(C[0], C_o[0], C_s[0],
on_size_error,
@@ -1056,7 +1065,7 @@ __gg__subtractf2_fixed_phase1(cbl_arith_format_t ,
on_error_flag,
compute_error);
- // Subtract that from the B value:
+ // Subtract the phase1_result from the B value:
int256 value_a = phase1_result;
int rdigits_a = phase1_rdigits;
@@ -1078,8 +1087,8 @@ __gg__subtractf2_fixed_phase1(cbl_arith_format_t ,
scale_int256_by_digits(value_a, rdigits_b - rdigits_a);
}
- // The two numbers have the same number of rdigits. It's now safe to
add
- // them.
+ // The two numbers have the same number of rdigits. It's now safe to
take
+ // the difference.
subtract_int256_from_int256(value_b, value_a);
int overflow = squeeze_int256(value_b, rdigits_b);
--
2.34.1