\f
/* Low-level constructors for expressions. */
-/* Build an expression of code CODE, data type TYPE,
- and operands as specified by the arguments ARG1 and following arguments.
- Expressions and reference nodes can be created this way.
- Constants, decls, types and misc nodes cannot be. */
+/* Build an expression of code CODE, data type TYPE, and operands as
+ specified. Expressions and reference nodes can be created this way.
+ Constants, decls, types and misc nodes cannot be.
+
+ We define 5 non-variadic functions, from 0 to 4 arguments. This is
+ enough for all extant tree codes. These functions can be called
+ directly (preferably!), but can also be obtained via GCC preprocessor
+ magic within the build macro. */
tree
-build (enum tree_code code, tree tt, ...)
+build0 (enum tree_code code, tree tt)
{
tree t;
- int length;
- int i;
- int fro;
- int constant;
- va_list p;
- tree node;
- va_start (p, tt);
+#ifdef ENABLE_CHECKING
+ if (TREE_CODE_LENGTH (code) != 0)
+ abort ();
+#endif
t = make_node (code);
- length = TREE_CODE_LENGTH (code);
TREE_TYPE (t) = tt;
- /* Below, we automatically set TREE_SIDE_EFFECTS and TREE_READONLY for the
- result based on those same flags for the arguments. But if the
- arguments aren't really even `tree' expressions, we shouldn't be trying
- to do this. */
- fro = first_rtl_op (code);
-
- /* Expressions without side effects may be constant if their
- arguments are as well. */
- constant = (TREE_CODE_CLASS (code) == '<'
- || TREE_CODE_CLASS (code) == '1'
- || TREE_CODE_CLASS (code) == '2'
- || TREE_CODE_CLASS (code) == 'c');
-
- if (length == 2)
- {
- /* This is equivalent to the loop below, but faster. */
- tree arg0 = va_arg (p, tree);
- tree arg1 = va_arg (p, tree);
-
- TREE_OPERAND (t, 0) = arg0;
- TREE_OPERAND (t, 1) = arg1;
- TREE_READONLY (t) = 1;
- if (arg0 && fro > 0)
- {
- if (TREE_SIDE_EFFECTS (arg0))
- TREE_SIDE_EFFECTS (t) = 1;
- if (!TREE_READONLY (arg0))
- TREE_READONLY (t) = 0;
- if (!TREE_CONSTANT (arg0))
- constant = 0;
- }
-
- if (arg1 && fro > 1)
- {
- if (TREE_SIDE_EFFECTS (arg1))
- TREE_SIDE_EFFECTS (t) = 1;
- if (!TREE_READONLY (arg1))
- TREE_READONLY (t) = 0;
- if (!TREE_CONSTANT (arg1))
- constant = 0;
- }
- }
- else if (length == 1)
- {
- tree arg0 = va_arg (p, tree);
-
- /* The only one-operand cases we handle here are those with side-effects.
- Others are handled with build1. So don't bother checked if the
- arg has side-effects since we'll already have set it.
-
- ??? This really should use build1 too. */
- if (TREE_CODE_CLASS (code) != 's')
- abort ();
- TREE_OPERAND (t, 0) = arg0;
- }
- else
- {
- for (i = 0; i < length; i++)
- {
- tree operand = va_arg (p, tree);
-
- TREE_OPERAND (t, i) = operand;
- if (operand && fro > i)
- {
- if (TREE_SIDE_EFFECTS (operand))
- TREE_SIDE_EFFECTS (t) = 1;
- if (!TREE_CONSTANT (operand))
- constant = 0;
- }
- }
- }
- va_end (p);
-
- TREE_CONSTANT (t) = constant;
-
- if (code == CALL_EXPR && !TREE_SIDE_EFFECTS (t))
- {
- /* Calls have side-effects, except those to const or
- pure functions. */
- i = call_expr_flags (t);
- if (!(i & (ECF_CONST | ECF_PURE)))
- TREE_SIDE_EFFECTS (t) = 1;
-
- /* And even those have side-effects if their arguments do. */
- else for (node = TREE_OPERAND (t, 1); node; node = TREE_CHAIN (node))
- if (TREE_SIDE_EFFECTS (TREE_VALUE (node)))
- {
- TREE_SIDE_EFFECTS (t) = 1;
- break;
- }
- }
-
return t;
}
-/* Same as above, but only builds for unary operators.
- Saves lions share of calls to `build'; cuts down use
- of varargs, which is expensive for RISC machines. */
-
tree
build1 (enum tree_code code, tree type, tree node)
{
#endif
#ifdef ENABLE_CHECKING
- if (TREE_CODE_CLASS (code) == '2'
- || TREE_CODE_CLASS (code) == '<'
- || TREE_CODE_LENGTH (code) != 1)
+ if (TREE_CODE_LENGTH (code) != 1)
abort ();
#endif /* ENABLE_CHECKING */
return t;
}
+#define PROCESS_ARG(N) \
+ do { \
+ TREE_OPERAND (t, N) = arg##N; \
+ if (arg##N && fro > N) \
+ { \
+ if (TREE_SIDE_EFFECTS (arg##N)) \
+ side_effects = 1; \
+ if (!TREE_READONLY (arg##N)) \
+ read_only = 0; \
+ if (!TREE_CONSTANT (arg##N)) \
+ constant = 0; \
+ } \
+ } while (0)
+
+tree
+build2 (enum tree_code code, tree tt, tree arg0, tree arg1)
+{
+ bool constant, read_only, side_effects;
+ tree t;
+ int fro;
+
+#ifdef ENABLE_CHECKING
+ if (TREE_CODE_LENGTH (code) != 2)
+ abort ();
+#endif
+
+ t = make_node (code);
+ TREE_TYPE (t) = tt;
+
+ /* Below, we automatically set TREE_SIDE_EFFECTS and TREE_READONLY for the
+ result based on those same flags for the arguments. But if the
+ arguments aren't really even `tree' expressions, we shouldn't be trying
+ to do this. */
+ fro = first_rtl_op (code);
+
+ /* Expressions without side effects may be constant if their
+ arguments are as well. */
+ constant = (TREE_CODE_CLASS (code) == '<'
+ || TREE_CODE_CLASS (code) == '2');
+ read_only = 1;
+ side_effects = TREE_SIDE_EFFECTS (t);
+
+ PROCESS_ARG(0);
+ PROCESS_ARG(1);
+
+ if (code == CALL_EXPR && !side_effects)
+ {
+ tree node;
+ int i;
+
+ /* Calls have side-effects, except those to const or
+ pure functions. */
+ i = call_expr_flags (t);
+ if (!(i & (ECF_CONST | ECF_PURE)))
+ side_effects = 1;
+
+ /* And even those have side-effects if their arguments do. */
+ else for (node = TREE_OPERAND (t, 1); node; node = TREE_CHAIN (node))
+ if (TREE_SIDE_EFFECTS (TREE_VALUE (node)))
+ {
+ side_effects = 1;
+ break;
+ }
+ }
+
+ TREE_READONLY (t) = read_only;
+ TREE_CONSTANT (t) = constant;
+ TREE_SIDE_EFFECTS (t) = side_effects;
+
+ return t;
+}
+
+tree
+build3 (enum tree_code code, tree tt, tree arg0, tree arg1, tree arg2)
+{
+ bool constant, read_only, side_effects;
+ tree t;
+ int fro;
+
+ /* ??? Quite a lot of existing code passes one too many arguments to
+ CALL_EXPR. Not going to fix them, because CALL_EXPR is about to
+ grow a new argument, so it would just mean changing them back. */
+ if (code == CALL_EXPR)
+ {
+ if (arg2 != NULL_TREE)
+ abort ();
+ return build2 (code, tt, arg0, arg1);
+ }
+
+#ifdef ENABLE_CHECKING
+ if (TREE_CODE_LENGTH (code) != 3)
+ abort ();
+#endif
+
+ t = make_node (code);
+ TREE_TYPE (t) = tt;
+
+ fro = first_rtl_op (code);
+
+ side_effects = TREE_SIDE_EFFECTS (t);
+
+ PROCESS_ARG(0);
+ PROCESS_ARG(1);
+ PROCESS_ARG(2);
+
+ TREE_SIDE_EFFECTS (t) = side_effects;
+
+ return t;
+}
+
+tree
+build4 (enum tree_code code, tree tt, tree arg0, tree arg1,
+ tree arg2, tree arg3)
+{
+ bool constant, read_only, side_effects;
+ tree t;
+ int fro;
+
+#ifdef ENABLE_CHECKING
+ if (TREE_CODE_LENGTH (code) != 4)
+ abort ();
+#endif
+
+ t = make_node (code);
+ TREE_TYPE (t) = tt;
+
+ fro = first_rtl_op (code);
+
+ side_effects = TREE_SIDE_EFFECTS (t);
+
+ PROCESS_ARG(0);
+ PROCESS_ARG(1);
+ PROCESS_ARG(2);
+ PROCESS_ARG(3);
+
+ TREE_SIDE_EFFECTS (t) = side_effects;
+
+ return t;
+}
+
+/* Backup definition for non-gcc build compilers. */
+
+tree
+(build) (enum tree_code code, tree tt, ...)
+{
+ tree t, arg0, arg1, arg2, arg3;
+ int length = TREE_CODE_LENGTH (code);
+ va_list p;
+
+ va_start (p, tt);
+ switch (length)
+ {
+ case 0:
+ t = build0 (code, tt);
+ break;
+ case 1:
+ arg0 = va_arg (p, tree);
+ t = build1 (code, tt, arg0);
+ break;
+ case 2:
+ arg0 = va_arg (p, tree);
+ arg1 = va_arg (p, tree);
+ t = build2 (code, tt, arg0, arg1);
+ break;
+ case 3:
+ arg0 = va_arg (p, tree);
+ arg1 = va_arg (p, tree);
+ arg2 = va_arg (p, tree);
+ t = build3 (code, tt, arg0, arg1, arg2);
+ break;
+ case 4:
+ arg0 = va_arg (p, tree);
+ arg1 = va_arg (p, tree);
+ arg2 = va_arg (p, tree);
+ arg3 = va_arg (p, tree);
+ t = build4 (code, tt, arg0, arg1, arg2, arg3);
+ break;
+ default:
+ abort ();
+ }
+ va_end (p);
+
+ return t;
+}
+
/* Similar except don't specify the TREE_TYPE
and leave the TREE_SIDE_EFFECTS as 0.
It is permissible for arguments to be null,
extern tree build (enum tree_code, tree, ...);
extern tree build_nt (enum tree_code, ...);
+#if GCC_VERSION >= 3000 || __STDC_VERSION__ >= 199901L
+/* Use preprocessor trickery to map "build" to "buildN" where N is the
+ expected number of arguments. This is used for both efficiency (no
+ varargs), and checking (verifying number of passed arguments). */
+#define build(code, ...) \
+ _buildN1(build, _buildC1(__VA_ARGS__))(code, __VA_ARGS__)
+#define _buildN1(BASE, X) _buildN2(BASE, X)
+#define _buildN2(BASE, X) BASE##X
+#define _buildC1(...) _buildC2(__VA_ARGS__,9,8,7,6,5,4,3,2,1,0,0)
+#define _buildC2(x,a1,a2,a3,a4,a5,a6,a7,a8,a9,c,...) c
+#endif
+
+extern tree build0 (enum tree_code, tree);
+extern tree build1 (enum tree_code, tree, tree);
+extern tree build2 (enum tree_code, tree, tree, tree);
+extern tree build3 (enum tree_code, tree, tree, tree, tree);
+extern tree build4 (enum tree_code, tree, tree, tree, tree, tree);
+
extern tree build_int_2_wide (unsigned HOST_WIDE_INT, HOST_WIDE_INT);
extern tree build_vector (tree, tree);
extern tree build_constructor (tree, tree);
extern tree build_real_from_int_cst (tree, tree);
extern tree build_complex (tree, tree, tree);
extern tree build_string (int, const char *);
-extern tree build1 (enum tree_code, tree, tree);
extern tree build_tree_list (tree, tree);
extern tree build_decl (enum tree_code, tree, tree);
extern tree build_block (tree, tree, tree, tree, tree);