This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
difference of labels
- To: gcc-patches at gcc dot gnu dot org
- Subject: difference of labels
- From: Richard Henderson <rth at cygnus dot com>
- Date: Fri, 30 Jul 1999 18:16:34 -0700
By request, here's a bit of code to support difference of labels
in static data. Eg.
int foo(int i)
{
static long a[] = { &&l1 - &&l1, &&l2 - &&l1};
void *p;
p = &&l1 + a[i];
goto *p;
l1: return 1;
l2: return 2;
}
This allows jump tables in shared libraries to be written in
such a way that they do not require runtime relocations.
C++ parts written and approved with Jason peeking over my shoulder.
r~
gcc/
* c-typeck.c (initializer_constant_valid_p): Move ...
* c-common.c (initializer_constant_valid_p): ... here. Use
FOO_TYPE_P instead of tests against TREE_CODE. Allow subtraction
of label addresses.
* c-common.h (initializer_constant_valid_p): Declare.
* c-tree.h (initializer_constant_valid_p): Remove.
gcc/cp/
* typeck2.c (initializer_constant_valid_p): Moved to c-common.c.
* cp-tree.h (initializer_constant_valid_p): Remove.
Index: c-common.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/c-common.c,v
retrieving revision 1.62
diff -c -p -d -r1.62 c-common.c
*** c-common.c 1999/07/27 05:43:56 1.62
--- c-common.c 1999/07/31 01:06:39
*************** build_va_arg (expr, type)
*** 3767,3769 ****
--- 3767,3925 ----
{
return build1 (VA_ARG_EXPR, type, expr);
}
+
+ /* Return nonzero if VALUE is a valid constant-valued expression
+ for use in initializing a static variable; one that can be an
+ element of a "constant" initializer.
+
+ Return null_pointer_node if the value is absolute;
+ if it is relocatable, return the variable that determines the relocation.
+ We assume that VALUE has been folded as much as possible;
+ therefore, we do not need to check for such things as
+ arithmetic-combinations of integers. */
+
+ tree
+ initializer_constant_valid_p (value, endtype)
+ tree value;
+ tree endtype;
+ {
+ switch (TREE_CODE (value))
+ {
+ case CONSTRUCTOR:
+ if ((TREE_CODE (TREE_TYPE (value)) == UNION_TYPE
+ || TREE_CODE (TREE_TYPE (value)) == RECORD_TYPE)
+ && TREE_CONSTANT (value)
+ && CONSTRUCTOR_ELTS (value))
+ return
+ initializer_constant_valid_p (TREE_VALUE (CONSTRUCTOR_ELTS (value)),
+ endtype);
+
+ return TREE_STATIC (value) ? null_pointer_node : 0;
+
+ case INTEGER_CST:
+ case REAL_CST:
+ case STRING_CST:
+ case COMPLEX_CST:
+ return null_pointer_node;
+
+ case ADDR_EXPR:
+ return TREE_OPERAND (value, 0);
+
+ case NON_LVALUE_EXPR:
+ return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype);
+
+ case CONVERT_EXPR:
+ case NOP_EXPR:
+ /* Allow conversions between pointer types. */
+ if (POINTER_TYPE_P (TREE_TYPE (value))
+ && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (value, 0))))
+ return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype);
+
+ /* Allow conversions between real types. */
+ if (FLOAT_TYPE_P (TREE_TYPE (value))
+ && FLOAT_TYPE_P (TREE_TYPE (TREE_OPERAND (value, 0))))
+ return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype);
+
+ /* Allow length-preserving conversions between integer types. */
+ if (INTEGRAL_TYPE_P (TREE_TYPE (value))
+ && INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (value, 0)))
+ && (TYPE_PRECISION (TREE_TYPE (value))
+ == TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (value, 0)))))
+ return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype);
+
+ /* Allow conversions between other integer types only if
+ explicit value. */
+ if (INTEGRAL_TYPE_P (TREE_TYPE (value))
+ && INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (value, 0))))
+ {
+ tree inner = initializer_constant_valid_p (TREE_OPERAND (value, 0),
+ endtype);
+ if (inner == null_pointer_node)
+ return null_pointer_node;
+ break;
+ }
+
+ /* Allow (int) &foo provided int is as wide as a pointer. */
+ if (INTEGRAL_TYPE_P (TREE_TYPE (value))
+ && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (value, 0)))
+ && (TYPE_PRECISION (TREE_TYPE (value))
+ >= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (value, 0)))))
+ return initializer_constant_valid_p (TREE_OPERAND (value, 0),
+ endtype);
+
+ /* Likewise conversions from int to pointers, but also allow
+ conversions from 0. */
+ if (POINTER_TYPE_P (TREE_TYPE (value))
+ && INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (value, 0))))
+ {
+ if (integer_zerop (TREE_OPERAND (value, 0)))
+ return null_pointer_node;
+ else if (TYPE_PRECISION (TREE_TYPE (value))
+ <= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (value, 0))))
+ return initializer_constant_valid_p (TREE_OPERAND (value, 0),
+ endtype);
+ }
+
+ /* Allow conversions to union types if the value inside is okay. */
+ if (TREE_CODE (TREE_TYPE (value)) == UNION_TYPE)
+ return initializer_constant_valid_p (TREE_OPERAND (value, 0),
+ endtype);
+ break;
+
+ case PLUS_EXPR:
+ if (! INTEGRAL_TYPE_P (endtype)
+ || TYPE_PRECISION (endtype) >= POINTER_SIZE)
+ {
+ tree valid0 = initializer_constant_valid_p (TREE_OPERAND (value, 0),
+ endtype);
+ tree valid1 = initializer_constant_valid_p (TREE_OPERAND (value, 1),
+ endtype);
+ /* If either term is absolute, use the other terms relocation. */
+ if (valid0 == null_pointer_node)
+ return valid1;
+ if (valid1 == null_pointer_node)
+ return valid0;
+ }
+ break;
+
+ case MINUS_EXPR:
+ if (! INTEGRAL_TYPE_P (endtype)
+ || TYPE_PRECISION (endtype) >= POINTER_SIZE)
+ {
+ tree valid0 = initializer_constant_valid_p (TREE_OPERAND (value, 0),
+ endtype);
+ tree valid1 = initializer_constant_valid_p (TREE_OPERAND (value, 1),
+ endtype);
+ /* Win if second argument is absolute. */
+ if (valid1 == null_pointer_node)
+ return valid0;
+ /* Win if both arguments have the same relocation.
+ Then the value is absolute. */
+ if (valid0 == valid1)
+ return null_pointer_node;
+ }
+
+ /* Support differences between labels. */
+ if (INTEGRAL_TYPE_P (endtype))
+ {
+ tree op0, op1;
+ op0 = TREE_OPERAND (value, 0);
+ op1 = TREE_OPERAND (value, 1);
+ STRIP_NOPS (op0);
+ STRIP_NOPS (op1);
+
+ if (TREE_CODE (op0) == ADDR_EXPR
+ && TREE_CODE (TREE_OPERAND (op0, 0)) == LABEL_DECL
+ && TREE_CODE (op1) == ADDR_EXPR
+ && TREE_CODE (TREE_OPERAND (op1, 0)) == LABEL_DECL)
+ return null_pointer_node;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+ }
+
Index: c-common.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/c-common.h,v
retrieving revision 1.3
diff -c -p -d -r1.3 c-common.h
*** c-common.h 1999/07/26 01:21:02 1.3
--- c-common.h 1999/07/31 01:06:39
*************** extern tree builtin_function PROTO((co
*** 190,192 ****
--- 190,194 ----
extern void c_common_nodes_and_builtins PROTO((int, int, int));
extern tree build_va_arg PROTO((tree, tree));
+
+ extern tree initializer_constant_valid_p PROTO((tree, tree));
Index: c-tree.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/c-tree.h,v
retrieving revision 1.22
diff -c -p -d -r1.22 c-tree.h
*** c-tree.h 1999/07/20 10:40:39 1.22
--- c-tree.h 1999/07/31 01:06:39
*************** extern tree build_compound_expr
*** 282,288 ****
extern tree build_c_cast PROTO((tree, tree));
extern tree build_modify_expr PROTO((tree, enum tree_code,
tree));
- extern tree initializer_constant_valid_p PROTO((tree, tree));
extern void store_init_value PROTO((tree, tree));
extern void error_init PROTO((const char *));
extern void pedwarn_init PROTO((const char *));
--- 282,287 ----
Index: c-typeck.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/c-typeck.c,v
retrieving revision 1.30
diff -c -p -d -r1.30 c-typeck.c
*** c-typeck.c 1999/07/14 15:47:26 1.30
--- c-typeck.c 1999/07/31 01:06:39
*************** warn_for_assignment (msgid, opname, func
*** 4246,4390 ****
pedwarn (msgid, opname);
}
- /* Return nonzero if VALUE is a valid constant-valued expression
- for use in initializing a static variable; one that can be an
- element of a "constant" initializer.
-
- Return null_pointer_node if the value is absolute;
- if it is relocatable, return the variable that determines the relocation.
- We assume that VALUE has been folded as much as possible;
- therefore, we do not need to check for such things as
- arithmetic-combinations of integers. */
-
- tree
- initializer_constant_valid_p (value, endtype)
- tree value;
- tree endtype;
- {
- switch (TREE_CODE (value))
- {
- case CONSTRUCTOR:
- if ((TREE_CODE (TREE_TYPE (value)) == UNION_TYPE
- || TREE_CODE (TREE_TYPE (value)) == RECORD_TYPE)
- && TREE_CONSTANT (value)
- && CONSTRUCTOR_ELTS (value))
- return
- initializer_constant_valid_p (TREE_VALUE (CONSTRUCTOR_ELTS (value)),
- endtype);
-
- return TREE_STATIC (value) ? null_pointer_node : 0;
-
- case INTEGER_CST:
- case REAL_CST:
- case STRING_CST:
- case COMPLEX_CST:
- return null_pointer_node;
-
- case ADDR_EXPR:
- return TREE_OPERAND (value, 0);
-
- case NON_LVALUE_EXPR:
- return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype);
-
- case CONVERT_EXPR:
- case NOP_EXPR:
- /* Allow conversions between pointer types. */
- if (TREE_CODE (TREE_TYPE (value)) == POINTER_TYPE
- && TREE_CODE (TREE_TYPE (TREE_OPERAND (value, 0))) == POINTER_TYPE)
- return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype);
-
- /* Allow conversions between real types. */
- if (TREE_CODE (TREE_TYPE (value)) == REAL_TYPE
- && TREE_CODE (TREE_TYPE (TREE_OPERAND (value, 0))) == REAL_TYPE)
- return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype);
-
- /* Allow length-preserving conversions between integer types. */
- if (TREE_CODE (TREE_TYPE (value)) == INTEGER_TYPE
- && TREE_CODE (TREE_TYPE (TREE_OPERAND (value, 0))) == INTEGER_TYPE
- && (TYPE_PRECISION (TREE_TYPE (value))
- == TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (value, 0)))))
- return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype);
-
- /* Allow conversions between other integer types only if
- explicit value. */
- if (TREE_CODE (TREE_TYPE (value)) == INTEGER_TYPE
- && TREE_CODE (TREE_TYPE (TREE_OPERAND (value, 0))) == INTEGER_TYPE)
- {
- tree inner = initializer_constant_valid_p (TREE_OPERAND (value, 0),
- endtype);
- if (inner == null_pointer_node)
- return null_pointer_node;
- return 0;
- }
-
- /* Allow (int) &foo provided int is as wide as a pointer. */
- if (TREE_CODE (TREE_TYPE (value)) == INTEGER_TYPE
- && TREE_CODE (TREE_TYPE (TREE_OPERAND (value, 0))) == POINTER_TYPE
- && (TYPE_PRECISION (TREE_TYPE (value))
- >= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (value, 0)))))
- return initializer_constant_valid_p (TREE_OPERAND (value, 0),
- endtype);
-
- /* Likewise conversions from int to pointers, but also allow
- conversions from 0. */
- if (TREE_CODE (TREE_TYPE (value)) == POINTER_TYPE
- && TREE_CODE (TREE_TYPE (TREE_OPERAND (value, 0))) == INTEGER_TYPE)
- {
- if (integer_zerop (TREE_OPERAND (value, 0)))
- return null_pointer_node;
- else if (TYPE_PRECISION (TREE_TYPE (value))
- <= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (value, 0))))
- return initializer_constant_valid_p (TREE_OPERAND (value, 0),
- endtype);
- }
-
- /* Allow conversions to union types if the value inside is okay. */
- if (TREE_CODE (TREE_TYPE (value)) == UNION_TYPE)
- return initializer_constant_valid_p (TREE_OPERAND (value, 0),
- endtype);
- return 0;
-
- case PLUS_EXPR:
- if (TREE_CODE (endtype) == INTEGER_TYPE
- && TYPE_PRECISION (endtype) < POINTER_SIZE)
- return 0;
- {
- tree valid0 = initializer_constant_valid_p (TREE_OPERAND (value, 0),
- endtype);
- tree valid1 = initializer_constant_valid_p (TREE_OPERAND (value, 1),
- endtype);
- /* If either term is absolute, use the other terms relocation. */
- if (valid0 == null_pointer_node)
- return valid1;
- if (valid1 == null_pointer_node)
- return valid0;
- return 0;
- }
-
- case MINUS_EXPR:
- if (TREE_CODE (endtype) == INTEGER_TYPE
- && TYPE_PRECISION (endtype) < POINTER_SIZE)
- return 0;
- {
- tree valid0 = initializer_constant_valid_p (TREE_OPERAND (value, 0),
- endtype);
- tree valid1 = initializer_constant_valid_p (TREE_OPERAND (value, 1),
- endtype);
- /* Win if second argument is absolute. */
- if (valid1 == null_pointer_node)
- return valid0;
- /* Win if both arguments have the same relocation.
- Then the value is absolute. */
- if (valid0 == valid1)
- return null_pointer_node;
- return 0;
- }
-
- default:
- return 0;
- }
- }
-
/* If VALUE is a compound expr all of whose expressions are constant, then
return its value. Otherwise, return error_mark_node.
--- 4246,4251 ----
Index: cp/cp-tree.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/cp-tree.h,v
retrieving revision 1.250
diff -c -p -d -r1.250 cp-tree.h
*** cp-tree.h 1999/07/28 00:45:12 1.250
--- cp-tree.h 1999/07/31 01:06:40
*************** extern tree build_functional_cast PROTO
*** 3586,3592 ****
extern char *enum_name_string PROTO((tree, tree));
extern void report_case_error PROTO((int, tree, tree, tree));
extern void check_for_new_type PROTO((const char *, flagged_type_tree));
- extern tree initializer_constant_valid_p PROTO((tree, tree));
/* in xref.c */
extern void GNU_xref_begin PROTO((const char *));
--- 3586,3591 ----
Index: cp/typeck2.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/typeck2.c,v
retrieving revision 1.56
diff -c -p -d -r1.56 typeck2.c
*** typeck2.c 1999/07/26 08:18:12 1.56
--- typeck2.c 1999/07/31 01:06:40
*************** my_friendly_assert (cond, where)
*** 378,523 ****
my_friendly_abort (where);
}
- /* Return nonzero if VALUE is a valid constant-valued expression
- for use in initializing a static variable; one that can be an
- element of a "constant" initializer.
-
- Return null_pointer_node if the value is absolute;
- if it is relocatable, return the variable that determines the relocation.
- We assume that VALUE has been folded as much as possible;
- therefore, we do not need to check for such things as
- arithmetic-combinations of integers. */
-
- tree
- initializer_constant_valid_p (value, endtype)
- tree value;
- tree endtype;
- {
- switch (TREE_CODE (value))
- {
- case CONSTRUCTOR:
- if (TREE_CODE (TREE_TYPE (value)) == UNION_TYPE
- && TREE_CONSTANT (value))
- return
- initializer_constant_valid_p (TREE_VALUE (CONSTRUCTOR_ELTS (value)),
- endtype);
-
- return TREE_STATIC (value) ? null_pointer_node : 0;
-
- case INTEGER_CST:
- case REAL_CST:
- case STRING_CST:
- case COMPLEX_CST:
- case PTRMEM_CST:
- return null_pointer_node;
-
- case ADDR_EXPR:
- return TREE_OPERAND (value, 0);
-
- case NON_LVALUE_EXPR:
- return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype);
-
- case CONVERT_EXPR:
- case NOP_EXPR:
- /* Allow conversions between pointer types. */
- if (POINTER_TYPE_P (TREE_TYPE (value))
- && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (value, 0))))
- return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype);
-
- /* Allow conversions between real types. */
- if (TREE_CODE (TREE_TYPE (value)) == REAL_TYPE
- && TREE_CODE (TREE_TYPE (TREE_OPERAND (value, 0))) == REAL_TYPE)
- return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype);
-
- /* Allow length-preserving conversions between integer types. */
- if (TREE_CODE (TREE_TYPE (value)) == INTEGER_TYPE
- && TREE_CODE (TREE_TYPE (TREE_OPERAND (value, 0))) == INTEGER_TYPE
- && (TYPE_PRECISION (TREE_TYPE (value))
- == TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (value, 0)))))
- return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype);
-
- /* Allow conversions between other integer types only if
- explicit value. */
- if (TREE_CODE (TREE_TYPE (value)) == INTEGER_TYPE
- && TREE_CODE (TREE_TYPE (TREE_OPERAND (value, 0))) == INTEGER_TYPE)
- {
- tree inner = initializer_constant_valid_p (TREE_OPERAND (value, 0),
- endtype);
- if (inner == null_pointer_node)
- return null_pointer_node;
- return 0;
- }
-
- /* Allow (int) &foo provided int is as wide as a pointer. */
- if (TREE_CODE (TREE_TYPE (value)) == INTEGER_TYPE
- && TREE_CODE (TREE_TYPE (TREE_OPERAND (value, 0))) == POINTER_TYPE
- && (TYPE_PRECISION (TREE_TYPE (value))
- >= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (value, 0)))))
- return initializer_constant_valid_p (TREE_OPERAND (value, 0),
- endtype);
-
- /* Likewise conversions from int to pointers, but also allow
- conversions from 0. */
- if (TREE_CODE (TREE_TYPE (value)) == POINTER_TYPE
- && TREE_CODE (TREE_TYPE (TREE_OPERAND (value, 0))) == INTEGER_TYPE)
- {
- if (integer_zerop (TREE_OPERAND (value, 0)))
- return null_pointer_node;
- else if (TYPE_PRECISION (TREE_TYPE (value))
- <= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (value, 0))))
- return initializer_constant_valid_p (TREE_OPERAND (value, 0),
- endtype);
- }
-
- /* Allow conversions to union types if the value inside is okay. */
- if (TREE_CODE (TREE_TYPE (value)) == UNION_TYPE)
- return initializer_constant_valid_p (TREE_OPERAND (value, 0),
- endtype);
- return 0;
-
- case PLUS_EXPR:
- if ((TREE_CODE (endtype) == INTEGER_TYPE)
- && (TYPE_PRECISION (endtype) < POINTER_SIZE))
- return 0;
- {
- tree valid0 = initializer_constant_valid_p (TREE_OPERAND (value, 0),
- endtype);
- tree valid1 = initializer_constant_valid_p (TREE_OPERAND (value, 1),
- endtype);
- /* If either term is absolute, use the other terms relocation. */
- if (valid0 == null_pointer_node)
- return valid1;
- if (valid1 == null_pointer_node)
- return valid0;
- return 0;
- }
-
- case MINUS_EXPR:
- if ((TREE_CODE (endtype) == INTEGER_TYPE)
- && (TYPE_PRECISION (endtype) < POINTER_SIZE))
- return 0;
- {
- tree valid0 = initializer_constant_valid_p (TREE_OPERAND (value, 0),
- endtype);
- tree valid1 = initializer_constant_valid_p (TREE_OPERAND (value, 1),
- endtype);
- /* Win if second argument is absolute. */
- if (valid1 == null_pointer_node)
- return valid0;
- /* Win if both arguments have the same relocation.
- Then the value is absolute. */
- if (valid0 == valid1)
- return null_pointer_node;
- return 0;
- }
-
- default:
- break;
- }
-
- return 0;
- }
-
/* Perform appropriate conversions on the initial value of a variable,
store it in the declaration DECL,
and print any error messages that are appropriate.
--- 378,383 ----