aboutsummaryrefslogtreecommitdiff
path: root/gcc/c-family/c-pretty-print.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/c-family/c-pretty-print.c')
-rw-r--r--gcc/c-family/c-pretty-print.c356
1 files changed, 332 insertions, 24 deletions
diff --git a/gcc/c-family/c-pretty-print.c b/gcc/c-family/c-pretty-print.c
index 319453d..2095d4b 100644
--- a/gcc/c-family/c-pretty-print.c
+++ b/gcc/c-family/c-pretty-print.c
@@ -22,6 +22,7 @@ along with GCC; see the file COPYING3. If not see
#include "system.h"
#include "coretypes.h"
#include "c-pretty-print.h"
+#include "gimple-pretty-print.h"
#include "diagnostic.h"
#include "stor-layout.h"
#include "stringpool.h"
@@ -30,6 +31,7 @@ along with GCC; see the file COPYING3. If not see
#include "tree-pretty-print.h"
#include "selftest.h"
#include "langhooks.h"
+#include "options.h"
/* The pretty-printer code is primarily designed to closely follow
(GNU) C and C++ grammars. That is to be contrasted with spaghetti
@@ -1334,6 +1336,39 @@ c_pretty_printer::primary_expression (tree e)
pp_c_right_paren (this);
break;
+ case SSA_NAME:
+ if (SSA_NAME_VAR (e))
+ {
+ tree var = SSA_NAME_VAR (e);
+ if (tree id = SSA_NAME_IDENTIFIER (e))
+ {
+ const char *name = IDENTIFIER_POINTER (id);
+ const char *dot;
+ if (DECL_ARTIFICIAL (var) && (dot = strchr (name, '.')))
+ {
+ /* Print the name without the . suffix (such as in VLAs).
+ Use pp_c_identifier so that it can be converted into
+ the appropriate encoding. */
+ size_t size = dot - name;
+ char *ident = XALLOCAVEC (char, size + 1);
+ memcpy (ident, name, size);
+ ident[size] = '\0';
+ pp_c_identifier (this, ident);
+ }
+ else
+ primary_expression (var);
+ }
+ else
+ primary_expression (var);
+ }
+ else
+ {
+ /* Print only the right side of the GIMPLE assignment. */
+ gimple *def_stmt = SSA_NAME_DEF_STMT (e);
+ pp_gimple_stmt_1 (this, def_stmt, 0, TDF_RHS_ONLY);
+ }
+ break;
+
default:
/* FIXME: Make sure we won't get into an infinite loop. */
if (location_wrapper_p (e))
@@ -1780,6 +1815,302 @@ pp_c_call_argument_list (c_pretty_printer *pp, tree t)
pp_c_right_paren (pp);
}
+/* Try to fold *(type *)&op into op.fld.fld2[1] if possible.
+ Only used for printing expressions. Should punt if ambiguous
+ (e.g. in unions). */
+
+static tree
+c_fold_indirect_ref_for_warn (location_t loc, tree type, tree op,
+ offset_int &off)
+{
+ tree optype = TREE_TYPE (op);
+ if (off == 0)
+ {
+ if (lang_hooks.types_compatible_p (optype, type))
+ return op;
+ /* *(foo *)&complexfoo => __real__ complexfoo */
+ else if (TREE_CODE (optype) == COMPLEX_TYPE
+ && lang_hooks.types_compatible_p (type, TREE_TYPE (optype)))
+ return build1_loc (loc, REALPART_EXPR, type, op);
+ }
+ /* ((foo*)&complexfoo)[1] => __imag__ complexfoo */
+ else if (TREE_CODE (optype) == COMPLEX_TYPE
+ && lang_hooks.types_compatible_p (type, TREE_TYPE (optype))
+ && tree_to_uhwi (TYPE_SIZE_UNIT (type)) == off)
+ {
+ off = 0;
+ return build1_loc (loc, IMAGPART_EXPR, type, op);
+ }
+ /* ((foo *)&fooarray)[x] => fooarray[x] */
+ if (TREE_CODE (optype) == ARRAY_TYPE
+ && TYPE_SIZE_UNIT (TREE_TYPE (optype))
+ && TREE_CODE (TYPE_SIZE_UNIT (TREE_TYPE (optype))) == INTEGER_CST
+ && !integer_zerop (TYPE_SIZE_UNIT (TREE_TYPE (optype))))
+ {
+ tree type_domain = TYPE_DOMAIN (optype);
+ tree min_val = size_zero_node;
+ if (type_domain && TYPE_MIN_VALUE (type_domain))
+ min_val = TYPE_MIN_VALUE (type_domain);
+ offset_int el_sz = wi::to_offset (TYPE_SIZE_UNIT (TREE_TYPE (optype)));
+ offset_int idx = off / el_sz;
+ offset_int rem = off % el_sz;
+ if (TREE_CODE (min_val) == INTEGER_CST)
+ {
+ tree index
+ = wide_int_to_tree (sizetype, idx + wi::to_offset (min_val));
+ op = build4_loc (loc, ARRAY_REF, TREE_TYPE (optype), op, index,
+ NULL_TREE, NULL_TREE);
+ off = rem;
+ if (tree ret = c_fold_indirect_ref_for_warn (loc, type, op, off))
+ return ret;
+ return op;
+ }
+ }
+ /* ((foo *)&struct_with_foo_field)[x] => COMPONENT_REF */
+ else if (TREE_CODE (optype) == RECORD_TYPE)
+ {
+ for (tree field = TYPE_FIELDS (optype);
+ field; field = DECL_CHAIN (field))
+ if (TREE_CODE (field) == FIELD_DECL
+ && TREE_TYPE (field) != error_mark_node
+ && TYPE_SIZE_UNIT (TREE_TYPE (field))
+ && TREE_CODE (TYPE_SIZE_UNIT (TREE_TYPE (field))) == INTEGER_CST)
+ {
+ tree pos = byte_position (field);
+ if (TREE_CODE (pos) != INTEGER_CST)
+ continue;
+ offset_int upos = wi::to_offset (pos);
+ offset_int el_sz
+ = wi::to_offset (TYPE_SIZE_UNIT (TREE_TYPE (field)));
+ if (upos <= off && off < upos + el_sz)
+ {
+ tree cop = build3_loc (loc, COMPONENT_REF, TREE_TYPE (field),
+ op, field, NULL_TREE);
+ off = off - upos;
+ if (tree ret = c_fold_indirect_ref_for_warn (loc, type, cop,
+ off))
+ return ret;
+ return cop;
+ }
+ }
+ }
+ /* Similarly for unions, but in this case try to be very conservative,
+ only match if some field has type compatible with type and it is the
+ only such field. */
+ else if (TREE_CODE (optype) == UNION_TYPE)
+ {
+ tree fld = NULL_TREE;
+ for (tree field = TYPE_FIELDS (optype);
+ field; field = DECL_CHAIN (field))
+ if (TREE_CODE (field) == FIELD_DECL
+ && TREE_TYPE (field) != error_mark_node
+ && lang_hooks.types_compatible_p (TREE_TYPE (field), type))
+ {
+ if (fld)
+ return NULL_TREE;
+ else
+ fld = field;
+ }
+ if (fld)
+ {
+ off = 0;
+ return build3_loc (loc, COMPONENT_REF, TREE_TYPE (fld), op, fld,
+ NULL_TREE);
+ }
+ }
+
+ return NULL_TREE;
+}
+
+/* Print the MEM_REF expression REF, including its type and offset.
+ Apply casts as necessary if the type of the access is different
+ from the type of the accessed object. Produce compact output
+ designed to include both the element index as well as any
+ misalignment by preferring
+ ((int*)((char*)p + 1))[2]
+ over
+ *(int*)((char*)p + 9)
+ The former is more verbose but makes it clearer that the access
+ to the third element of the array is misaligned by one byte. */
+
+static void
+print_mem_ref (c_pretty_printer *pp, tree e)
+{
+ tree arg = TREE_OPERAND (e, 0);
+
+ /* The byte offset. Initially equal to the MEM_REF offset, then
+ adjusted to the remainder of the division by the byte size of
+ the access. */
+ offset_int byte_off = wi::to_offset (TREE_OPERAND (e, 1));
+ /* The result of dividing BYTE_OFF by the size of the access. */
+ offset_int elt_idx = 0;
+ /* True to include a cast to char* (for a nonzero final BYTE_OFF). */
+ bool char_cast = false;
+ tree op = NULL_TREE;
+ bool array_ref_only = false;
+ if (TREE_CODE (arg) == ADDR_EXPR)
+ {
+ op = c_fold_indirect_ref_for_warn (EXPR_LOCATION (e), TREE_TYPE (e),
+ TREE_OPERAND (arg, 0), byte_off);
+ /* Try to fold it back to component, array ref or their combination,
+ but print it only if the types and TBAA types are compatible. */
+ if (op
+ && byte_off == 0
+ && lang_hooks.types_compatible_p (TREE_TYPE (e), TREE_TYPE (op))
+ && (!flag_strict_aliasing
+ || (get_deref_alias_set (TREE_OPERAND (e, 1))
+ == get_alias_set (op))))
+ {
+ pp->expression (op);
+ return;
+ }
+ if (op == NULL_TREE)
+ op = TREE_OPERAND (arg, 0);
+ /* If the types or TBAA types are incompatible, undo the
+ UNION_TYPE handling from c_fold_indirect_ref_for_warn, and similarly
+ undo __real__/__imag__ the code below doesn't try to handle. */
+ if (op != TREE_OPERAND (arg, 0)
+ && ((TREE_CODE (op) == COMPONENT_REF
+ && TREE_CODE (TREE_TYPE (TREE_OPERAND (op, 0))) == UNION_TYPE)
+ || TREE_CODE (op) == REALPART_EXPR
+ || TREE_CODE (op) == IMAGPART_EXPR))
+ op = TREE_OPERAND (op, 0);
+ if (op != TREE_OPERAND (arg, 0))
+ {
+ array_ref_only = true;
+ for (tree ref = op; ref != TREE_OPERAND (arg, 0);
+ ref = TREE_OPERAND (ref, 0))
+ if (TREE_CODE (ref) != ARRAY_REF)
+ {
+ array_ref_only = false;
+ break;
+ }
+ }
+ }
+
+ tree access_type = TREE_TYPE (e);
+ tree arg_type = TREE_TYPE (TREE_TYPE (arg));
+ if (tree access_size = TYPE_SIZE_UNIT (access_type))
+ if (byte_off != 0
+ && TREE_CODE (access_size) == INTEGER_CST
+ && !integer_zerop (access_size))
+ {
+ offset_int asize = wi::to_offset (access_size);
+ elt_idx = byte_off / asize;
+ byte_off = byte_off % asize;
+ }
+
+ /* True to include a cast to the accessed type. */
+ const bool access_cast
+ = ((op && op != TREE_OPERAND (arg, 0))
+ || VOID_TYPE_P (arg_type)
+ || !lang_hooks.types_compatible_p (access_type, arg_type));
+ const bool has_off = byte_off != 0 || (op && op != TREE_OPERAND (arg, 0));
+
+ if (has_off && (byte_off != 0 || !array_ref_only))
+ {
+ /* When printing the byte offset for a pointer to a type of
+ a different size than char, include a cast to char* first,
+ before printing the cast to a pointer to the accessed type. */
+ tree size = TYPE_SIZE (arg_type);
+ if (size == NULL_TREE
+ || TREE_CODE (size) != INTEGER_CST
+ || wi::to_wide (size) != BITS_PER_UNIT)
+ char_cast = true;
+ }
+
+ if (elt_idx == 0)
+ pp_c_star (pp);
+ else if (access_cast || char_cast)
+ pp_c_left_paren (pp);
+
+ if (access_cast)
+ {
+ /* Include a cast to the accessed type if it isn't compatible
+ with the type of the referenced object (or if the object
+ is typeless). */
+ pp_c_left_paren (pp);
+ pp->type_id (build_pointer_type (access_type));
+ pp_c_right_paren (pp);
+ }
+
+ if (has_off)
+ pp_c_left_paren (pp);
+
+ if (char_cast)
+ {
+ /* Include a cast to char *. */
+ pp_c_left_paren (pp);
+ pp->type_id (string_type_node);
+ pp_c_right_paren (pp);
+ }
+
+ pp->unary_expression (arg);
+
+ if (op && op != TREE_OPERAND (arg, 0))
+ {
+ auto_vec<tree, 16> refs;
+ tree ref;
+ unsigned i;
+ bool array_refs = true;
+ for (ref = op; ref != TREE_OPERAND (arg, 0); ref = TREE_OPERAND (ref, 0))
+ refs.safe_push (ref);
+ FOR_EACH_VEC_ELT_REVERSE (refs, i, ref)
+ if (array_refs && TREE_CODE (ref) == ARRAY_REF)
+ {
+ pp_c_left_bracket (pp);
+ pp->expression (TREE_OPERAND (ref, 1));
+ pp_c_right_bracket (pp);
+ }
+ else
+ {
+ if (array_refs)
+ {
+ array_refs = false;
+ pp_string (pp, " + offsetof");
+ pp_c_left_paren (pp);
+ pp->type_id (TREE_TYPE (TREE_OPERAND (ref, 0)));
+ pp_comma (pp);
+ }
+ else if (TREE_CODE (ref) == COMPONENT_REF)
+ pp_c_dot (pp);
+ if (TREE_CODE (ref) == COMPONENT_REF)
+ pp->expression (TREE_OPERAND (ref, 1));
+ else
+ {
+ pp_c_left_bracket (pp);
+ pp->expression (TREE_OPERAND (ref, 1));
+ pp_c_right_bracket (pp);
+ }
+ }
+ if (!array_refs)
+ pp_c_right_paren (pp);
+ }
+
+ if (byte_off != 0)
+ {
+ pp_space (pp);
+ pp_plus (pp);
+ pp_space (pp);
+ tree off = wide_int_to_tree (ssizetype, byte_off);
+ pp->constant (off);
+ }
+
+ if (has_off)
+ pp_c_right_paren (pp);
+
+ if (elt_idx != 0)
+ {
+ if (access_cast || char_cast)
+ pp_c_right_paren (pp);
+
+ pp_c_left_bracket (pp);
+ tree idx = wide_int_to_tree (ssizetype, elt_idx);
+ pp->constant (idx);
+ pp_c_right_bracket (pp);
+ }
+}
+
/* unary-expression:
postfix-expression
++ cast-expression
@@ -1837,30 +2168,7 @@ c_pretty_printer::unary_expression (tree e)
break;
case MEM_REF:
- if (TREE_CODE (TREE_OPERAND (e, 0)) == ADDR_EXPR
- && integer_zerop (TREE_OPERAND (e, 1)))
- expression (TREE_OPERAND (TREE_OPERAND (e, 0), 0));
- else
- {
- pp_c_star (this);
- if (!integer_zerop (TREE_OPERAND (e, 1)))
- {
- pp_c_left_paren (this);
- tree type = TREE_TYPE (TREE_TYPE (TREE_OPERAND (e, 0)));
- if (TYPE_SIZE_UNIT (type) == NULL_TREE
- || !integer_onep (TYPE_SIZE_UNIT (type)))
- pp_c_type_cast (this, ptr_type_node);
- }
- pp_c_cast_expression (this, TREE_OPERAND (e, 0));
- if (!integer_zerop (TREE_OPERAND (e, 1)))
- {
- pp_plus (this);
- pp_c_integer_constant (this,
- fold_convert (ssizetype,
- TREE_OPERAND (e, 1)));
- pp_c_right_paren (this);
- }
- }
+ print_mem_ref (this, e);
break;
case TARGET_MEM_REF: