This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] Check precision in STRIP_NOPS when possible (take 2)
- From: Adam Nemet <anemet at caviumnetworks dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Wed, 10 Jun 2009 18:37:33 -0700
- Subject: [PATCH] Check precision in STRIP_NOPS when possible (take 2)
This is the current version of the patch based on the thread in:
http://gcc.gnu.org/ml/gcc-patches/2009-06/msg00711.html
Eric, Bootstrapping and testing Ada succeeded with the additional assert.
Later however I've found that C++ created nop_expr on aggregate types for
reinterpret_cast. Thus the code falls back on the old TYPE_MODE equality for
aggregate types.
There were some other cases that required special handling; I tried to comment
them appropriately in the code. To summarize I use precision for
INTEGERAL_TYPE_P, POINTER_TYPE_P, OFFSET_TYPE and FLOAT_TYPE_P.
Boostrapped and regtested on x86_64-linux including Ada.
Further comments? OK to install?
Adam
* tree.c (tree_nop_conversion, tree_sign_nop_conversion): New
functions.
* tree.h (STRIP_NOPS, STRIP_SIGN_NOPS): Use them.
testsuite/
* gcc.c-torture/execute/bitfld-5.c: New test.
Index: tree.h
===================================================================
--- tree.h (revision 148091)
+++ tree.h (working copy)
@@ -964,29 +964,17 @@ extern void omp_clause_range_check_faile
case NOP_EXPR: \
case CONVERT_EXPR
-/* Given an expression as a tree, strip any NON_LVALUE_EXPRs and NOP_EXPRs
- that don't change the machine mode. */
+/* Given an expression as a tree, strip any conversion that generates no
+ instruction. */
-#define STRIP_NOPS(EXP) \
- while ((CONVERT_EXPR_P (EXP) \
- || TREE_CODE (EXP) == NON_LVALUE_EXPR) \
- && TREE_OPERAND (EXP, 0) != error_mark_node \
- && (TYPE_MODE (TREE_TYPE (EXP)) \
- == TYPE_MODE (TREE_TYPE (TREE_OPERAND (EXP, 0))))) \
+#define STRIP_NOPS(EXP) \
+ while (tree_nop_conversion (EXP)) \
(EXP) = TREE_OPERAND (EXP, 0)
/* Like STRIP_NOPS, but don't let the signedness change either. */
-#define STRIP_SIGN_NOPS(EXP) \
- while ((CONVERT_EXPR_P (EXP) \
- || TREE_CODE (EXP) == NON_LVALUE_EXPR) \
- && TREE_OPERAND (EXP, 0) != error_mark_node \
- && (TYPE_MODE (TREE_TYPE (EXP)) \
- == TYPE_MODE (TREE_TYPE (TREE_OPERAND (EXP, 0)))) \
- && (TYPE_UNSIGNED (TREE_TYPE (EXP)) \
- == TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (EXP, 0)))) \
- && (POINTER_TYPE_P (TREE_TYPE (EXP)) \
- == POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (EXP, 0))))) \
+#define STRIP_SIGN_NOPS(EXP) \
+ while (tree_sign_nop_conversion (EXP)) \
(EXP) = TREE_OPERAND (EXP, 0)
/* Like STRIP_NOPS, but don't alter the TREE_TYPE either. */
@@ -4628,6 +4616,8 @@ extern bool stdarg_p (tree);
extern bool prototype_p (tree);
extern bool auto_var_in_fn_p (const_tree, const_tree);
extern tree build_low_bits_mask (tree, unsigned);
+extern bool tree_nop_conversion (const_tree);
+extern bool tree_sign_nop_conversion (const_tree);
/* In cgraph.c */
extern void change_decl_assembler_name (tree, tree);
Index: tree.c
===================================================================
--- tree.c (revision 148091)
+++ tree.c (working copy)
@@ -9437,5 +9437,80 @@ list_equal_p (const_tree t1, const_tree
return !t1 && !t2;
}
+/* Return true iff conversion in EXP generates no instruction. */
+
+bool
+tree_nop_conversion (const_tree exp)
+{
+ tree outer_type, inner_type;
+
+ if (!CONVERT_EXPR_P (exp)
+ && TREE_CODE (exp) != NON_LVALUE_EXPR)
+ return false;
+ if (TREE_OPERAND (exp, 0) == error_mark_node)
+ return false;
+
+ /* Ignore qualifiers. */
+ outer_type = TYPE_MAIN_VARIANT (TREE_TYPE (exp));
+ inner_type = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (exp, 0)));
+
+ if (outer_type == inner_type)
+ return true;
+
+ /* Conversion to void does not yield a value. */
+ if (outer_type == void_type_node)
+ return false;
+
+ /* C++ casts a void_zero_node to a pointer type for the dummy
+ object. */
+ if (inner_type == void_type_node)
+ return false;
+
+ /* Use precision rather then machine mode when we can, which gives
+ the correct answer even for submode (bit-field) types. */
+ if (INTEGRAL_TYPE_P (outer_type)
+ || POINTER_TYPE_P (outer_type)
+ || TREE_CODE (outer_type) == OFFSET_TYPE
+ || FLOAT_TYPE_P (outer_type))
+ {
+#ifdef ENABLE_CHECKING
+ /* Don't allow conversion between float and integral+ types. */
+ gcc_assert ((INTEGRAL_TYPE_P (outer_type)
+ || POINTER_TYPE_P (outer_type)
+ || TREE_CODE (outer_type) == OFFSET_TYPE)
+ == ((INTEGRAL_TYPE_P (inner_type)
+ || POINTER_TYPE_P (inner_type)
+ || TREE_CODE (inner_type) == OFFSET_TYPE)));
+#endif
+
+ return TYPE_PRECISION (outer_type) == TYPE_PRECISION (inner_type);
+ }
+ /* Aggregate types have no precision so we fall back on the machine
+ mode. The C++ front-end creates NOP_EXPR of aggregate types for
+ example for reinterpret_cast. */
+ else if (AGGREGATE_TYPE_P (outer_type))
+ return TYPE_MODE (outer_type) == TYPE_MODE (inner_type);
+ else
+ gcc_unreachable ();
+}
+
+/* Return true iff conversion in EXP generates no instruction. Don't
+ consider conversions changing the signedness. */
+
+bool
+tree_sign_nop_conversion (const_tree exp)
+{
+ tree outer_type, inner_type;
+
+ if (!tree_nop_conversion (exp))
+ return false;
+
+ outer_type = TREE_TYPE (exp);
+ inner_type = TREE_TYPE (TREE_OPERAND (exp, 0));
+
+ return (TYPE_UNSIGNED (outer_type) == TYPE_UNSIGNED (inner_type)
+ && POINTER_TYPE_P (outer_type) == POINTER_TYPE_P (inner_type));
+}
+
#include "gt-tree.h"
Index: testsuite/gcc.c-torture/execute/bitfld-5.c
===================================================================
--- testsuite/gcc.c-torture/execute/bitfld-5.c (revision 0)
+++ testsuite/gcc.c-torture/execute/bitfld-5.c (revision 0)
@@ -0,0 +1,35 @@
+/* See http://gcc.gnu.org/ml/gcc/2009-06/msg00072.html. */
+
+extern void abort (void);
+
+struct s
+{
+ unsigned long long a:2;
+ unsigned long long b:40;
+ unsigned long long c:22;
+};
+
+__attribute__ ((noinline)) void
+g (unsigned long long a, unsigned long long b)
+{
+ asm ("");
+ if (a != b)
+ abort ();
+}
+
+__attribute__ ((noinline)) void
+f (struct s s, unsigned long long b)
+{
+ asm ("");
+ g (((unsigned long long) (s.b-8)) + 8, b);
+}
+
+int
+main ()
+{
+ struct s s = {1, 10, 3};
+ struct s t = {1, 2, 3};
+ f (s, 10);
+ f (t, 0x10000000002);
+ return 0;
+}