aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorMarc Poulhiès <poulhies@adacore.com>2023-09-08 15:15:48 +0000
committerMarc Poulhiès <poulhies@adacore.com>2023-09-19 13:26:42 +0200
commit047269320d433e4024fcb3580f638bcb2aca7664 (patch)
tree0734467aac08433e2acd7b56df0b41df00e833ca /gcc
parent54c16824f0f05313bfc7df5e625f108b4ff7c636 (diff)
downloadgcc-047269320d433e4024fcb3580f638bcb2aca7664.zip
gcc-047269320d433e4024fcb3580f638bcb2aca7664.tar.gz
gcc-047269320d433e4024fcb3580f638bcb2aca7664.tar.bz2
ada: Refine upper array bound for bit packed array
When using bit-packed arrays, the compiler creates new array subtypes of 1-bit component indexed by integers. The existing routine checks the index subtype to find the min/max values. Bit-packed arrays being indexed by integers, the routines gives up as returning the maximum possible integer carries no useful information. This change adds a simple max_value routine that can evaluate very simple expressions by substituting variables by their min/max value. Bit-packed array subtypes are currently declared as: subtype bp_array is packed_bytes1 (0 .. integer((1 * Var + 7) / 8 - 1)); The simple max_value evaluator handles the bare minimum for this expression pattern. gcc/ada/ChangeLog: * gcc-interface/utils.cc (max_value): New. * gcc-interface/gigi.h (max_value): New. * gcc-interface/decl.cc (gnat_to_gnu_entity) <E_Array_Subtype>: When computing gnu_min/gnu_max, try to use max_value if there is an initial expression.
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ada/gcc-interface/decl.cc22
-rw-r--r--gcc/ada/gcc-interface/gigi.h6
-rw-r--r--gcc/ada/gcc-interface/utils.cc95
3 files changed, 123 insertions, 0 deletions
diff --git a/gcc/ada/gcc-interface/decl.cc b/gcc/ada/gcc-interface/decl.cc
index 0cf7d3c..5e16b56 100644
--- a/gcc/ada/gcc-interface/decl.cc
+++ b/gcc/ada/gcc-interface/decl.cc
@@ -2551,6 +2551,17 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, bool definition)
else
gnu_min = gnu_orig_min;
+ if (DECL_P (gnu_min)
+ && DECL_INITIAL (gnu_min) != NULL_TREE
+ && (TREE_CODE (gnu_min) != INTEGER_CST
+ || TREE_OVERFLOW (gnu_min)))
+ {
+ tree tmp = max_value (DECL_INITIAL(gnu_min), false);
+ if (TREE_CODE (tmp) == INTEGER_CST
+ && !TREE_OVERFLOW (tmp))
+ gnu_min = tmp;
+ }
+
if (TREE_CODE (gnu_min) != INTEGER_CST
|| TREE_OVERFLOW (gnu_min))
gnu_min = TYPE_MIN_VALUE (TREE_TYPE (gnu_min));
@@ -2560,6 +2571,17 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, bool definition)
else
gnu_max = gnu_orig_max;
+ if (DECL_P (gnu_max)
+ && DECL_INITIAL (gnu_max) != NULL_TREE
+ && (TREE_CODE (gnu_max) != INTEGER_CST
+ || TREE_OVERFLOW (gnu_max)))
+ {
+ tree tmp = max_value (DECL_INITIAL(gnu_max), true);
+ if (TREE_CODE (tmp) == INTEGER_CST
+ && !TREE_OVERFLOW (tmp))
+ gnu_max = tmp;
+ }
+
if (TREE_CODE (gnu_max) != INTEGER_CST
|| TREE_OVERFLOW (gnu_max))
gnu_max = TYPE_MAX_VALUE (TREE_TYPE (gnu_max));
diff --git a/gcc/ada/gcc-interface/gigi.h b/gcc/ada/gcc-interface/gigi.h
index ec85ce4..eb5496f 100644
--- a/gcc/ada/gcc-interface/gigi.h
+++ b/gcc/ada/gcc-interface/gigi.h
@@ -763,6 +763,12 @@ extern void update_pointer_to (tree old_type, tree new_type);
minimum (if !MAX_P) possible value of the discriminant. */
extern tree max_size (tree exp, bool max_p);
+/* Try to compute the maximum (if MAX_P) or minimum (if !MAX_P) value for the
+ expression EXP, for very simple expressions. Substitute variable references
+ with their respective type's min/max values. Return the computed value if
+ any, or EXP if no value can be computed. */
+extern tree max_value (tree exp, bool max_p);
+
/* Remove all conversions that are done in EXP. This includes converting
from a padded type or to a left-justified modular type. If TRUE_ADDRESS
is true, always return the address of the containing object even if
diff --git a/gcc/ada/gcc-interface/utils.cc b/gcc/ada/gcc-interface/utils.cc
index f720f3a..4e2ed17 100644
--- a/gcc/ada/gcc-interface/utils.cc
+++ b/gcc/ada/gcc-interface/utils.cc
@@ -3830,6 +3830,100 @@ fntype_same_flags_p (const_tree t, tree cico_list, bool return_by_direct_ref_p,
&& TREE_ADDRESSABLE (t) == return_by_invisi_ref_p;
}
+/* Try to compute the maximum (if MAX_P) or minimum (if !MAX_P) value for the
+ expression EXP, for very simple expressions. Substitute variable references
+ with their respective type's min/max values. Return the computed value if
+ any, or EXP if no value can be computed. */
+
+tree
+max_value (tree exp, bool max_p)
+{
+ enum tree_code code = TREE_CODE (exp);
+ tree type = TREE_TYPE (exp);
+ tree op0, op1, op2;
+
+ switch (TREE_CODE_CLASS (code))
+ {
+ case tcc_declaration:
+ if (VAR_P (exp))
+ return fold_convert (type,
+ max_p
+ ? TYPE_MAX_VALUE (type) : TYPE_MIN_VALUE (type));
+ break;
+
+ case tcc_vl_exp:
+ if (code == CALL_EXPR)
+ {
+ tree t;
+
+ t = maybe_inline_call_in_expr (exp);
+ if (t)
+ return max_value (t, max_p);
+ }
+ break;
+
+ case tcc_comparison:
+ return build_int_cst (type, max_p ? 1 : 0);
+
+ case tcc_unary:
+ op0 = TREE_OPERAND (exp, 0);
+
+ if (code == NON_LVALUE_EXPR)
+ return max_value (op0, max_p);
+
+ if (code == NEGATE_EXPR)
+ return max_value (op0, !max_p);
+
+ if (code == NOP_EXPR)
+ return fold_convert (type, max_value (op0, max_p));
+
+ break;
+
+ case tcc_binary:
+ op0 = TREE_OPERAND (exp, 0);
+ op1 = TREE_OPERAND (exp, 1);
+
+ switch (code) {
+ case PLUS_EXPR:
+ case MULT_EXPR:
+ return fold_build2 (code, type, max_value(op0, max_p),
+ max_value (op1, max_p));
+ case MINUS_EXPR:
+ case TRUNC_DIV_EXPR:
+ return fold_build2 (code, type, max_value(op0, max_p),
+ max_value (op1, !max_p));
+ default:
+ break;
+ }
+ break;
+
+ case tcc_expression:
+ if (code == COND_EXPR)
+ {
+ op0 = TREE_OPERAND (exp, 0);
+ op1 = TREE_OPERAND (exp, 1);
+ op2 = TREE_OPERAND (exp, 2);
+
+ if (!op1 || !op2)
+ break;
+
+ op1 = max_value (op1, max_p);
+ op2 = max_value (op2, max_p);
+
+ if (op1 == TREE_OPERAND (exp, 1) && op2 == TREE_OPERAND (exp, 2))
+ break;
+
+ return fold_build2 (max_p ? MAX_EXPR : MIN_EXPR, type, op1, op2);
+ }
+ break;
+
+ default:
+ break;
+ }
+ return exp;
+}
+
+
/* EXP is an expression for the size of an object. If this size contains
discriminant references, replace them with the maximum (if MAX_P) or
minimum (if !MAX_P) possible value of the discriminant.
@@ -3867,6 +3961,7 @@ max_size (tree exp, bool max_p)
n = call_expr_nargs (exp);
gcc_assert (n > 0);
argarray = XALLOCAVEC (tree, n);
+ /* This is used to remove possible placeholder in call args. */
for (i = 0; i < n; i++)
argarray[i] = max_size (CALL_EXPR_ARG (exp, i), max_p);
return build_call_array (type, CALL_EXPR_FN (exp), n, argarray);