This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[c] fold offsetof by hand
- From: Richard Henderson <rth at redhat dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Thu, 26 Aug 2004 17:45:43 -0700
- Subject: [c] fold offsetof by hand
This changes the C front end to fold offsetof to a number by hand,
rather than relying on build_unary_op of ADDR_EXPR to generate a
constant, rather than the address of a COMPONENT_REF.
This is currently redundant with pinskia's TREE_CONSTANT hack in
build_unary_op, which I don't like.
The C++ front end is considerably more wily. I don't have the
proper placement for that yet. But I expect to be able to use
fold_offsetof once templates get resolved properly, etc, etc, so
that's why fold_offsetof is in c-common.c.
Tested on i686-linux.
r~
* c-typeck.c (build_offsetof): Remove.
* c-tree.h (build_offsetof): Remove.
* c-common.c (fold_offsetof_1, fold_offsetof): New.
* c-common.h (fold_offsetof): Declare.
* c-parse.in (offsetof_base): New.
(offsetof_member_designator): Use it. Build references, not just
a tree list.
(primary): Use fold_offsetof, not build_offsetof.
Index: c-common.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-common.c,v
retrieving revision 1.560
diff -c -p -d -r1.560 c-common.c
*** c-common.c 27 Aug 2004 00:27:21 -0000 1.560
--- c-common.c 27 Aug 2004 00:34:17 -0000
*************** c_warn_unused_result (tree *top_p)
*** 5436,5439 ****
--- 5436,5504 ----
}
}
+ /* Build the result of __builtin_offsetof. EXPR is a nested sequence of
+ component references, with an INDIRECT_REF at the bottom; much like
+ the traditional rendering of offsetof as a macro. Returns the folded
+ and properly cast result. */
+
+ static tree
+ fold_offsetof_1 (tree expr)
+ {
+ enum tree_code code = PLUS_EXPR;
+ tree base, off, t;
+
+ switch (TREE_CODE (expr))
+ {
+ case ERROR_MARK:
+ return expr;
+
+ case INDIRECT_REF:
+ return size_zero_node;
+
+ case COMPONENT_REF:
+ base = fold_offsetof_1 (TREE_OPERAND (expr, 0));
+ if (base == error_mark_node)
+ return base;
+
+ t = TREE_OPERAND (expr, 1);
+ if (DECL_C_BIT_FIELD (t))
+ {
+ error ("attempt to take address of bit-field structure "
+ "member `%s'", IDENTIFIER_POINTER (DECL_NAME (t)));
+ return error_mark_node;
+ }
+ off = size_binop (PLUS_EXPR, DECL_FIELD_OFFSET (t),
+ size_int (tree_low_cst (DECL_FIELD_BIT_OFFSET (t), 1)
+ / BITS_PER_UNIT));
+ break;
+
+ case ARRAY_REF:
+ base = fold_offsetof_1 (TREE_OPERAND (expr, 0));
+ if (base == error_mark_node)
+ return base;
+
+ t = TREE_OPERAND (expr, 1);
+ if (TREE_CODE (t) == INTEGER_CST && tree_int_cst_sgn (t) < 0)
+ {
+ code = MINUS_EXPR;
+ t = fold (build1 (NEGATE_EXPR, TREE_TYPE (t), t));
+ }
+ t = convert (sizetype, t);
+ off = size_binop (MULT_EXPR, TYPE_SIZE_UNIT (TREE_TYPE (expr)), t);
+ break;
+
+ default:
+ abort ();
+ }
+
+ return size_binop (code, base, off);
+ }
+
+ tree
+ fold_offsetof (tree expr)
+ {
+ /* Convert back from the internal sizetype to size_t. */
+ return convert (size_type_node, fold_offsetof_1 (expr));
+ }
+
#include "gt-c-common.h"
Index: c-common.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-common.h,v
retrieving revision 1.257
diff -c -p -d -r1.257 c-common.h
*** c-common.h 27 Aug 2004 00:27:23 -0000 1.257
--- c-common.h 27 Aug 2004 00:34:17 -0000
*************** extern void c_warn_unused_result (tree *
*** 870,875 ****
--- 870,877 ----
extern void verify_sequence_points (tree);
+ extern tree fold_offsetof (tree);
+
/* In c-gimplify.c */
extern void c_genericize (tree);
extern int c_gimplify_expr (tree *, tree *, tree *);
Index: c-parse.in
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-parse.in,v
retrieving revision 1.230
diff -c -p -d -r1.230 c-parse.in
*** c-parse.in 26 Aug 2004 20:55:24 -0000 1.230
--- c-parse.in 27 Aug 2004 00:34:17 -0000
*************** static GTY(()) tree all_prefix_attribute
*** 275,280 ****
--- 275,283 ----
all_prefix_attributes. */
static GTY(()) tree declspec_stack;
+ /* INDIRECT_REF with a TREE_TYPE of the type being queried for offsetof. */
+ static tree offsetof_base;
+
/* PUSH_DECLSPEC_STACK is called from setspecs; POP_DECLSPEC_STACK
should be called from the productions making use of setspecs. */
#define PUSH_DECLSPEC_STACK \
*************** primary:
*** 681,688 ****
{ $$.value = build_va_arg ($3.value, groktypename ($5));
$$.original_code = ERROR_MARK; }
! | OFFSETOF '(' typename ',' offsetof_member_designator ')'
! { $$.value = build_offsetof (groktypename ($3), $5);
$$.original_code = ERROR_MARK; }
| OFFSETOF '(' error ')'
{ $$.value = error_mark_node; $$.original_code = ERROR_MARK; }
--- 684,698 ----
{ $$.value = build_va_arg ($3.value, groktypename ($5));
$$.original_code = ERROR_MARK; }
! | OFFSETOF '(' typename ','
! { tree type = groktypename ($3);
! if (type == error_mark_node)
! offsetof_base = error_mark_node;
! else
! offsetof_base = build1 (INDIRECT_REF, type, NULL);
! }
! offsetof_member_designator ')'
! { $$.value = fold_offsetof ($6);
$$.original_code = ERROR_MARK; }
| OFFSETOF '(' error ')'
{ $$.value = error_mark_node; $$.original_code = ERROR_MARK; }
*************** primary:
*** 753,769 ****
/* This is the second argument to __builtin_offsetof. We must have one
identifier, and beyond that we want to accept sub structure and sub
! array references. We return tree list where each element has
! PURPOSE set for component refs or VALUE set for array refs. We'll
! turn this into something real inside build_offsetof. */
offsetof_member_designator:
identifier
! { $$ = tree_cons ($1, NULL_TREE, NULL_TREE); }
| offsetof_member_designator '.' identifier
! { $$ = tree_cons ($3, NULL_TREE, $1); }
| offsetof_member_designator '[' expr ']'
! { $$ = tree_cons (NULL_TREE, $3.value, $1); }
;
old_style_parm_decls:
--- 763,777 ----
/* This is the second argument to __builtin_offsetof. We must have one
identifier, and beyond that we want to accept sub structure and sub
! array references. */
offsetof_member_designator:
identifier
! { $$ = build_component_ref (offsetof_base, $1); }
| offsetof_member_designator '.' identifier
! { $$ = build_component_ref ($1, $3); }
| offsetof_member_designator '[' expr ']'
! { $$ = build_array_ref ($1, $3.value); }
;
old_style_parm_decls:
Index: c-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-tree.h,v
retrieving revision 1.169
diff -c -p -d -r1.169 c-tree.h
*** c-tree.h 25 Aug 2004 23:39:11 -0000 1.169
--- c-tree.h 27 Aug 2004 00:34:17 -0000
*************** extern tree c_finish_return (tree);
*** 277,283 ****
extern tree c_finish_bc_stmt (tree *, bool);
extern tree c_finish_goto_label (tree);
extern tree c_finish_goto_ptr (tree);
- extern tree build_offsetof (tree, tree);
/* Set to 0 at beginning of a function definition, set to 1 if
a return statement that specifies a return value is seen. */
--- 277,282 ----
Index: c-typeck.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-typeck.c,v
retrieving revision 1.362
diff -c -p -d -r1.362 c-typeck.c
*** c-typeck.c 25 Aug 2004 20:38:51 -0000 1.362
--- c-typeck.c 27 Aug 2004 00:34:18 -0000
*************** build_binary_op (enum tree_code code, tr
*** 7583,7613 ****
return result;
}
}
-
- /* Build the result of __builtin_offsetof. TYPE is the first argument to
- offsetof, i.e. a type. LIST is a tree_list that encodes component and
- array references; PURPOSE is set for the former and VALUE is set for
- the later. */
-
- tree
- build_offsetof (tree type, tree list)
- {
- tree t;
-
- /* Build "*(type *)0". */
- t = convert (build_pointer_type (type), null_pointer_node);
- t = build_indirect_ref (t, "");
-
- /* Build COMPONENT and ARRAY_REF expressions as needed. */
- for (list = nreverse (list); list ; list = TREE_CHAIN (list))
- if (TREE_PURPOSE (list))
- t = build_component_ref (t, TREE_PURPOSE (list));
- else
- t = build_array_ref (t, TREE_VALUE (list));
-
- /* Finalize the offsetof expression. For now all we need to do is take
- the address of the expression we created, and cast that to an integer
- type; this mirrors the traditional macro implementation of offsetof. */
- t = build_unary_op (ADDR_EXPR, t, 0);
- return convert (size_type_node, t);
- }
--- 7583,7585 ----