aboutsummaryrefslogtreecommitdiff
path: root/gcc/ada/gcc-interface/utils.c
diff options
context:
space:
mode:
authorEric Botcazou <ebotcazou@adacore.com>2008-10-06 07:09:41 +0000
committerEric Botcazou <ebotcazou@gcc.gnu.org>2008-10-06 07:09:41 +0000
commitafcea85941826a0b9a7aa561bffffa563d3871c4 (patch)
tree4fd62f20d78cc99caedb6b31b232a5c7004f099f /gcc/ada/gcc-interface/utils.c
parentde27a12c672ace89eec85d195fb9fb6e34488874 (diff)
downloadgcc-afcea85941826a0b9a7aa561bffffa563d3871c4.zip
gcc-afcea85941826a0b9a7aa561bffffa563d3871c4.tar.gz
gcc-afcea85941826a0b9a7aa561bffffa563d3871c4.tar.bz2
utils.c (can_fold_for_view_convert_p): New predicate.
2008-10-06 Eric Botcazou <ebotcazou@adacore.com> * gcc-interface/utils.c (can_fold_for_view_convert_p): New predicate. (unchecked_convert): Use it to disable problematic folding with VIEW_CONVERT_EXPR in the general case. Always disable it for the special VIEW_CONVERT_EXPR built for integral types and cope with its addressability issues by preserving the first conversion. From-SVN: r140902
Diffstat (limited to 'gcc/ada/gcc-interface/utils.c')
-rw-r--r--gcc/ada/gcc-interface/utils.c125
1 files changed, 99 insertions, 26 deletions
diff --git a/gcc/ada/gcc-interface/utils.c b/gcc/ada/gcc-interface/utils.c
index 7f1bc7b..d883d53 100644
--- a/gcc/ada/gcc-interface/utils.c
+++ b/gcc/ada/gcc-interface/utils.c
@@ -4489,8 +4489,72 @@ maybe_unconstrained_array (tree exp)
return exp;
}
+/* Return true if EXPR is an expression that can be folded as an operand
+ of a VIEW_CONVERT_EXPR. See the head comment of unchecked_convert for
+ the rationale. */
+
+static bool
+can_fold_for_view_convert_p (tree expr)
+{
+ tree t1, t2;
+
+ /* The folder will fold NOP_EXPRs between integral types with the same
+ precision (in the middle-end's sense). We cannot allow it if the
+ types don't have the same precision in the Ada sense as well. */
+ if (TREE_CODE (expr) != NOP_EXPR)
+ return true;
+
+ t1 = TREE_TYPE (expr);
+ t2 = TREE_TYPE (TREE_OPERAND (expr, 0));
+
+ /* Defer to the folder for non-integral conversions. */
+ if (!(INTEGRAL_TYPE_P (t1) && INTEGRAL_TYPE_P (t2)))
+ return true;
+
+ /* Only fold conversions that preserve both precisions. */
+ if (TYPE_PRECISION (t1) == TYPE_PRECISION (t2)
+ && operand_equal_p (rm_size (t1), rm_size (t2), 0))
+ return true;
+
+ return false;
+}
+
/* Return an expression that does an unchecked conversion of EXPR to TYPE.
- If NOTRUNC_P is true, truncation operations should be suppressed. */
+ If NOTRUNC_P is true, truncation operations should be suppressed.
+
+ Special care is required with (source or target) integral types whose
+ precision is not equal to their size, to make sure we fetch or assign
+ the value bits whose location might depend on the endianness, e.g.
+
+ Rmsize : constant := 8;
+ subtype Int is Integer range 0 .. 2 ** Rmsize - 1;
+
+ type Bit_Array is array (1 .. Rmsize) of Boolean;
+ pragma Pack (Bit_Array);
+
+ function To_Bit_Array is new Unchecked_Conversion (Int, Bit_Array);
+
+ Value : Int := 2#1000_0001#;
+ Vbits : Bit_Array := To_Bit_Array (Value);
+
+ we expect the 8 bits at Vbits'Address to always contain Value, while
+ their original location depends on the endianness, at Value'Address
+ on a little-endian architecture but not on a big-endian one.
+
+ ??? There is a problematic discrepancy between what is called precision
+ here (and more generally throughout gigi) for integral types and what is
+ called precision in the middle-end. In the former case it's the RM size
+ as given by TYPE_RM_SIZE (or rm_size) whereas it's TYPE_PRECISION in the
+ latter case, the hitch being that they are not equal when they matter,
+ that is when the number of value bits is not equal to the type's size:
+ TYPE_RM_SIZE does give the number of value bits but TYPE_PRECISION is set
+ to the size. The sole exception are BOOLEAN_TYPEs for which both are 1.
+
+ The consequence is that gigi must duplicate code bridging the gap between
+ the type's size and its precision that exists for TYPE_PRECISION in the
+ middle-end, because the latter knows nothing about TYPE_RM_SIZE, and be
+ wary of transformations applied in the middle-end based on TYPE_PRECISION
+ because this value doesn't reflect the actual precision for Ada. */
tree
unchecked_convert (tree type, tree expr, bool notrunc_p)
@@ -4517,14 +4581,10 @@ unchecked_convert (tree type, tree expr, bool notrunc_p)
&& TYPE_JUSTIFIED_MODULAR_P (etype))))
|| TREE_CODE (type) == UNCONSTRAINED_ARRAY_TYPE)
{
- tree rtype = type;
- bool final_unchecked = false;
-
if (TREE_CODE (etype) == INTEGER_TYPE
&& TYPE_BIASED_REPRESENTATION_P (etype))
{
tree ntype = copy_type (etype);
-
TYPE_BIASED_REPRESENTATION_P (ntype) = 0;
TYPE_MAIN_VARIANT (ntype) = ntype;
expr = build1 (NOP_EXPR, ntype, expr);
@@ -4533,15 +4593,18 @@ unchecked_convert (tree type, tree expr, bool notrunc_p)
if (TREE_CODE (type) == INTEGER_TYPE
&& TYPE_BIASED_REPRESENTATION_P (type))
{
- rtype = copy_type (type);
+ tree rtype = copy_type (type);
TYPE_BIASED_REPRESENTATION_P (rtype) = 0;
TYPE_MAIN_VARIANT (rtype) = rtype;
+ expr = convert (rtype, expr);
+ expr = build1 (NOP_EXPR, type, expr);
}
- /* We have another special case: if we are unchecked converting subtype
- into a base type, we need to ensure that VRP doesn't propagate range
- information since this conversion may be done precisely to validate
- that the object is within the range it is supposed to have. */
+ /* We have another special case: if we are unchecked converting either
+ a subtype or a type with limited range into a base type, we need to
+ ensure that VRP doesn't propagate range information because this
+ conversion may be done precisely to validate that the object is
+ within the range it is supposed to have. */
else if (TREE_CODE (expr) != INTEGER_CST
&& TREE_CODE (type) == INTEGER_TYPE && !TREE_TYPE (type)
&& ((TREE_CODE (etype) == INTEGER_TYPE && TREE_TYPE (etype))
@@ -4552,26 +4615,34 @@ unchecked_convert (tree type, tree expr, bool notrunc_p)
in order not to be deemed an useless type conversion, it must
be from subtype to base type.
+ Therefore we first do the bulk of the conversion to a subtype of
+ the final type. And this conversion must itself not be deemed
+ useless if the source type is not a subtype because, otherwise,
+ the final VIEW_CONVERT_EXPR will be deemed so as well. That's
+ why we toggle the unsigned flag in this conversion, which is
+ harmless since the final conversion is only a reinterpretation
+ of the bit pattern.
+
??? This may raise addressability and/or aliasing issues because
VIEW_CONVERT_EXPR gets gimplified as an lvalue, thus causing the
address of its operand to be taken if it is deemed addressable
and not already in GIMPLE form. */
- rtype = gnat_type_for_mode (TYPE_MODE (type), TYPE_UNSIGNED (type));
+ tree rtype
+ = gnat_type_for_mode (TYPE_MODE (type), !TYPE_UNSIGNED (etype));
rtype = copy_type (rtype);
TYPE_MAIN_VARIANT (rtype) = rtype;
TREE_TYPE (rtype) = type;
- final_unchecked = true;
+ expr = convert (rtype, expr);
+ expr = build1 (VIEW_CONVERT_EXPR, type, expr);
}
- expr = convert (rtype, expr);
- if (type != rtype)
- expr = fold_build1 (final_unchecked ? VIEW_CONVERT_EXPR : NOP_EXPR,
- type, expr);
+ else
+ expr = convert (type, expr);
}
- /* If we are converting TO an integral type whose precision is not the
- same as its size, first unchecked convert to a record that contains
- an object of the output type. Then extract the field. */
+ /* If we are converting to an integral type whose precision is not equal
+ to its size, first unchecked convert to a record that contains an
+ object of the output type. Then extract the field. */
else if (INTEGRAL_TYPE_P (type) && TYPE_RM_SIZE (type)
&& 0 != compare_tree_int (TYPE_RM_SIZE (type),
GET_MODE_BITSIZE (TYPE_MODE (type))))
@@ -4587,8 +4658,8 @@ unchecked_convert (tree type, tree expr, bool notrunc_p)
expr = build_component_ref (expr, NULL_TREE, field, 0);
}
- /* Similarly for integral input type whose precision is not equal to its
- size. */
+ /* Similarly if we are converting from an integral type whose precision
+ is not equal to its size. */
else if (INTEGRAL_TYPE_P (etype) && TYPE_RM_SIZE (etype)
&& 0 != compare_tree_int (TYPE_RM_SIZE (etype),
GET_MODE_BITSIZE (TYPE_MODE (etype))))
@@ -4618,13 +4689,15 @@ unchecked_convert (tree type, tree expr, bool notrunc_p)
{
expr = maybe_unconstrained_array (expr);
etype = TREE_TYPE (expr);
- expr = fold_build1 (VIEW_CONVERT_EXPR, type, expr);
+ if (can_fold_for_view_convert_p (expr))
+ expr = fold_build1 (VIEW_CONVERT_EXPR, type, expr);
+ else
+ expr = build1 (VIEW_CONVERT_EXPR, type, expr);
}
- /* If the result is an integral type whose size is not equal to
- the size of the underlying machine type, sign- or zero-extend
- the result. We need not do this in the case where the input is
- an integral type of the same precision and signedness or if the output
+ /* If the result is an integral type whose precision is not equal to its
+ size, sign- or zero-extend the result. We need not do this if the input
+ is an integral type of the same precision and signedness or if the output
is a biased type or if both the input and output are unsigned. */
if (!notrunc_p
&& INTEGRAL_TYPE_P (type) && TYPE_RM_SIZE (type)