home *** CD-ROM | disk | FTP | other *** search
- /* Subroutines shared by all languages that are variants of C.
- Copyright (C) 1992 Free Software Foundation, Inc.
-
- This file is part of GNU CC.
-
- GNU CC is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- GNU CC is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with GNU CC; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-
- #include "config.h"
- #include "tree.h"
- #include "c-lex.h"
- #include "c-tree.h"
- #include "flags.h"
- #include <stdio.h>
-
- /* Make bindings for __FUNCTION__ and __PRETTY_FUNCTION__. */
-
- void
- declare_function_name ()
- {
- tree decl, init;
- char *name, *printable_name;
-
- if (current_function_decl == NULL)
- {
- name = "";
- printable_name = "top level";
- }
- else
- {
- char *kind = "function";
- if (TREE_CODE (TREE_TYPE (current_function_decl)) == METHOD_TYPE)
- kind = "method";
- /* Allow functions to be nameless (such as artificial ones). */
- if (DECL_NAME (current_function_decl))
- name = IDENTIFIER_POINTER (DECL_NAME (current_function_decl));
- else
- name = "";
- printable_name = (*decl_printable_name) (current_function_decl, &kind);
- }
-
- push_obstacks_nochange ();
- decl = build_decl (VAR_DECL, get_identifier ("__FUNCTION__"),
- char_array_type_node);
- TREE_STATIC (decl) = 1;
- TREE_READONLY (decl) = 1;
- DECL_SOURCE_LINE (decl) = 0;
- DECL_IN_SYSTEM_HEADER (decl) = 1;
- DECL_IGNORED_P (decl) = 1;
- init = build_string (strlen (name) + 1, name);
- TREE_TYPE (init) = char_array_type_node;
- DECL_INITIAL (decl) = init;
- finish_decl (pushdecl (decl), init, NULL_TREE);
-
- push_obstacks_nochange ();
- decl = build_decl (VAR_DECL, get_identifier ("__PRETTY_FUNCTION__"),
- char_array_type_node);
- TREE_STATIC (decl) = 1;
- TREE_READONLY (decl) = 1;
- DECL_SOURCE_LINE (decl) = 0;
- DECL_IN_SYSTEM_HEADER (decl) = 1;
- DECL_IGNORED_P (decl) = 1;
- init = build_string (strlen (printable_name) + 1, printable_name);
- TREE_TYPE (init) = char_array_type_node;
- DECL_INITIAL (decl) = init;
- finish_decl (pushdecl (decl), init, NULL_TREE);
- }
-
- /* Given a chain of STRING_CST nodes,
- concatenate them into one STRING_CST
- and give it a suitable array-of-chars data type. */
-
- tree
- combine_strings (strings)
- tree strings;
- {
- register tree value, t;
- register int length = 1;
- int wide_length = 0;
- int wide_flag = 0;
- int wchar_bytes = TYPE_PRECISION (wchar_type_node) / BITS_PER_UNIT;
- int nchars;
-
- if (TREE_CHAIN (strings))
- {
- /* More than one in the chain, so concatenate. */
- register char *p, *q;
-
- /* Don't include the \0 at the end of each substring,
- except for the last one.
- Count wide strings and ordinary strings separately. */
- for (t = strings; t; t = TREE_CHAIN (t))
- {
- if (TREE_TYPE (t) == wchar_array_type_node)
- {
- wide_length += (TREE_STRING_LENGTH (t) - wchar_bytes);
- wide_flag = 1;
- }
- else
- length += (TREE_STRING_LENGTH (t) - 1);
- }
-
- /* If anything is wide, the non-wides will be converted,
- which makes them take more space. */
- if (wide_flag)
- length = length * wchar_bytes + wide_length;
-
- p = savealloc (length);
-
- /* Copy the individual strings into the new combined string.
- If the combined string is wide, convert the chars to ints
- for any individual strings that are not wide. */
-
- q = p;
- for (t = strings; t; t = TREE_CHAIN (t))
- {
- int len = (TREE_STRING_LENGTH (t)
- - ((TREE_TYPE (t) == wchar_array_type_node)
- ? wchar_bytes : 1));
- if ((TREE_TYPE (t) == wchar_array_type_node) == wide_flag)
- {
- bcopy (TREE_STRING_POINTER (t), q, len);
- q += len;
- }
- else
- {
- int i;
- for (i = 0; i < len; i++)
- ((int *) q)[i] = TREE_STRING_POINTER (t)[i];
- q += len * wchar_bytes;
- }
- }
- if (wide_flag)
- {
- int i;
- for (i = 0; i < wchar_bytes; i++)
- *q++ = 0;
- }
- else
- *q = 0;
-
- value = make_node (STRING_CST);
- TREE_STRING_POINTER (value) = p;
- TREE_STRING_LENGTH (value) = length;
- TREE_CONSTANT (value) = 1;
- }
- else
- {
- value = strings;
- length = TREE_STRING_LENGTH (value);
- if (TREE_TYPE (value) == wchar_array_type_node)
- wide_flag = 1;
- }
-
- /* Compute the number of elements, for the array type. */
- nchars = wide_flag ? length / wchar_bytes : length;
-
- /* Create the array type for the string constant.
- -Wwrite-strings says make the string constant an array of const char
- so that copying it to a non-const pointer will get a warning. */
- if (warn_write_strings
- && (! flag_traditional && ! flag_writable_strings))
- {
- tree elements
- = build_type_variant (wide_flag ? wchar_type_node : char_type_node,
- 1, 0);
- TREE_TYPE (value)
- = build_array_type (elements,
- build_index_type (build_int_2 (nchars - 1, 0)));
- }
- else
- TREE_TYPE (value)
- = build_array_type (wide_flag ? wchar_type_node : char_type_node,
- build_index_type (build_int_2 (nchars - 1, 0)));
- TREE_CONSTANT (value) = 1;
- TREE_STATIC (value) = 1;
- return value;
- }
-
- /* Process the attributes listed in ATTRIBUTES
- and install them in DECL. */
-
- void
- decl_attributes (decl, attributes)
- tree decl, attributes;
- {
- tree a;
- for (a = attributes; a; a = TREE_CHAIN (a))
- if (TREE_VALUE (a) == get_identifier ("packed"))
- {
- if (TREE_CODE (decl) == FIELD_DECL)
- DECL_PACKED (decl) = 1;
- /* We can't set DECL_PACKED for a VAR_DECL, because the bit is
- used for DECL_REGISTER. It wouldn't mean anything anyway. */
- }
- else if (TREE_VALUE (a) != 0
- && TREE_CODE (TREE_VALUE (a)) == TREE_LIST
- && TREE_PURPOSE (TREE_VALUE (a)) == get_identifier ("mode"))
- {
- int i;
- char *specified_name
- = IDENTIFIER_POINTER (TREE_VALUE (TREE_VALUE (a)));
-
- /* Give this decl a type with the specified mode. */
- for (i = 0; i < NUM_MACHINE_MODES; i++)
- if (!strcmp (specified_name, GET_MODE_NAME (i)))
- {
- tree type
- = type_for_mode (i, TREE_UNSIGNED (TREE_TYPE (decl)));
- if (type != 0)
- {
- TREE_TYPE (decl) = type;
- DECL_SIZE (decl) = 0;
- layout_decl (decl, 0);
- }
- else
- error ("no data type for mode `%s'", specified_name);
- break;
- }
- if (i == NUM_MACHINE_MODES)
- error ("unknown machine mode `%s'", specified_name);
- }
- else if (TREE_VALUE (a) != 0
- && TREE_CODE (TREE_VALUE (a)) == TREE_LIST
- && TREE_PURPOSE (TREE_VALUE (a)) == get_identifier ("aligned"))
- {
- int align = TREE_INT_CST_LOW (TREE_VALUE (TREE_VALUE (a)))
- * BITS_PER_UNIT;
-
- if (exact_log2 (align) == -1)
- error_with_decl (decl,
- "requested alignment of `%s' is not a power of 2");
- else if (TREE_CODE (decl) != VAR_DECL
- && TREE_CODE (decl) != FIELD_DECL)
- error_with_decl (decl,
- "alignment specified for `%s'");
- else
- DECL_ALIGN (decl) = align;
- }
- else if (TREE_VALUE (a) != 0
- && TREE_CODE (TREE_VALUE (a)) == TREE_LIST
- && TREE_PURPOSE (TREE_VALUE (a)) == get_identifier ("format"))
- {
- tree list = TREE_VALUE (TREE_VALUE (a));
- tree format_type = TREE_PURPOSE (list);
- int format_num = TREE_INT_CST_LOW (TREE_PURPOSE (TREE_VALUE (list)));
- int first_arg_num = TREE_INT_CST_LOW (TREE_VALUE (TREE_VALUE (list)));
- int is_scan;
-
- if (TREE_CODE (decl) != FUNCTION_DECL)
- {
- error_with_decl (decl,
- "argument format specified for non-function `%s'");
- return;
- }
-
- if (format_type == get_identifier ("printf"))
- is_scan = 0;
- else if (format_type == get_identifier ("scanf"))
- is_scan = 1;
- else
- {
- error_with_decl (decl, "unrecognized format specifier for `%s'");
- return;
- }
-
- if (first_arg_num != 0 && first_arg_num <= format_num)
- {
- error_with_decl (decl,
- "format string arg follows the args to be formatted, for `%s'");
- return;
- }
-
- record_format_info (DECL_NAME (decl), is_scan, format_num,
- first_arg_num);
- }
- }
-
- /* Print a warning if a constant expression had overflow in folding. */
-
- void
- constant_expression_warning (value)
- tree value;
- {
- if (TREE_CODE (value) == INTEGER_CST && TREE_CONSTANT_OVERFLOW (value))
- pedwarn ("overflow in constant expression");
- }
-
- void
- c_expand_expr_stmt (expr)
- tree expr;
- {
- /* Do default conversion if safe and possibly important,
- in case within ({...}). */
- if ((TREE_CODE (TREE_TYPE (expr)) == ARRAY_TYPE && lvalue_p (expr))
- || TREE_CODE (TREE_TYPE (expr)) == FUNCTION_TYPE)
- expr = default_conversion (expr);
-
- if (TREE_TYPE (expr) != error_mark_node
- && TYPE_SIZE (TREE_TYPE (expr)) == 0
- && TREE_CODE (TREE_TYPE (expr)) != ARRAY_TYPE)
- error ("expression statement has incomplete type");
-
- expand_expr_stmt (expr);
- }
-
- /* Validate the expression after `case' and apply default promotions. */
-
- tree
- check_case_value (value)
- tree value;
- {
- if (value == NULL_TREE)
- return value;
-
- /* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue. */
- STRIP_TYPE_NOPS (value);
-
- if (TREE_CODE (value) != INTEGER_CST
- && value != error_mark_node)
- {
- error ("case label does not reduce to an integer constant");
- value = error_mark_node;
- }
- else
- /* Promote char or short to int. */
- value = default_conversion (value);
-
- constant_expression_warning (value);
-
- return value;
- }
-
- /* Return an integer type with BITS bits of precision,
- that is unsigned if UNSIGNEDP is nonzero, otherwise signed. */
-
- tree
- type_for_size (bits, unsignedp)
- unsigned bits;
- int unsignedp;
- {
- if (bits == TYPE_PRECISION (signed_char_type_node))
- return unsignedp ? unsigned_char_type_node : signed_char_type_node;
-
- if (bits == TYPE_PRECISION (short_integer_type_node))
- return unsignedp ? short_unsigned_type_node : short_integer_type_node;
-
- if (bits == TYPE_PRECISION (integer_type_node))
- return unsignedp ? unsigned_type_node : integer_type_node;
-
- if (bits == TYPE_PRECISION (long_integer_type_node))
- return unsignedp ? long_unsigned_type_node : long_integer_type_node;
-
- if (bits == TYPE_PRECISION (long_long_integer_type_node))
- return (unsignedp ? long_long_unsigned_type_node
- : long_long_integer_type_node);
-
- if (bits <= TYPE_PRECISION (intQI_type_node))
- return unsignedp ? unsigned_intQI_type_node : intQI_type_node;
-
- if (bits <= TYPE_PRECISION (intHI_type_node))
- return unsignedp ? unsigned_intHI_type_node : intHI_type_node;
-
- if (bits <= TYPE_PRECISION (intSI_type_node))
- return unsignedp ? unsigned_intSI_type_node : intSI_type_node;
-
- if (bits <= TYPE_PRECISION (intDI_type_node))
- return unsignedp ? unsigned_intDI_type_node : intDI_type_node;
-
- return 0;
- }
-
- /* Return a data type that has machine mode MODE.
- If the mode is an integer,
- then UNSIGNEDP selects between signed and unsigned types. */
-
- tree
- type_for_mode (mode, unsignedp)
- enum machine_mode mode;
- int unsignedp;
- {
- if (mode == TYPE_MODE (signed_char_type_node))
- return unsignedp ? unsigned_char_type_node : signed_char_type_node;
-
- if (mode == TYPE_MODE (short_integer_type_node))
- return unsignedp ? short_unsigned_type_node : short_integer_type_node;
-
- if (mode == TYPE_MODE (integer_type_node))
- return unsignedp ? unsigned_type_node : integer_type_node;
-
- if (mode == TYPE_MODE (long_integer_type_node))
- return unsignedp ? long_unsigned_type_node : long_integer_type_node;
-
- if (mode == TYPE_MODE (long_long_integer_type_node))
- return unsignedp ? long_long_unsigned_type_node : long_long_integer_type_node;
-
- if (mode == TYPE_MODE (intQI_type_node))
- return unsignedp ? unsigned_intQI_type_node : intQI_type_node;
-
- if (mode == TYPE_MODE (intHI_type_node))
- return unsignedp ? unsigned_intHI_type_node : intHI_type_node;
-
- if (mode == TYPE_MODE (intSI_type_node))
- return unsignedp ? unsigned_intSI_type_node : intSI_type_node;
-
- if (mode == TYPE_MODE (intDI_type_node))
- return unsignedp ? unsigned_intDI_type_node : intDI_type_node;
-
- if (mode == TYPE_MODE (float_type_node))
- return float_type_node;
-
- if (mode == TYPE_MODE (double_type_node))
- return double_type_node;
-
- if (mode == TYPE_MODE (long_double_type_node))
- return long_double_type_node;
-
- if (mode == TYPE_MODE (build_pointer_type (char_type_node)))
- return build_pointer_type (char_type_node);
-
- if (mode == TYPE_MODE (build_pointer_type (integer_type_node)))
- return build_pointer_type (integer_type_node);
-
- return 0;
- }
-
- /* Print an error message for invalid operands to arith operation CODE.
- NOP_EXPR is used as a special case (see truthvalue_conversion). */
-
- void
- binary_op_error (code)
- enum tree_code code;
- {
- register char *opname;
- switch (code)
- {
- case NOP_EXPR:
- error ("invalid truth-value expression");
- return;
-
- case PLUS_EXPR:
- opname = "+"; break;
- case MINUS_EXPR:
- opname = "-"; break;
- case MULT_EXPR:
- opname = "*"; break;
- case MAX_EXPR:
- opname = "max"; break;
- case MIN_EXPR:
- opname = "min"; break;
- case EQ_EXPR:
- opname = "=="; break;
- case NE_EXPR:
- opname = "!="; break;
- case LE_EXPR:
- opname = "<="; break;
- case GE_EXPR:
- opname = ">="; break;
- case LT_EXPR:
- opname = "<"; break;
- case GT_EXPR:
- opname = ">"; break;
- case LSHIFT_EXPR:
- opname = "<<"; break;
- case RSHIFT_EXPR:
- opname = ">>"; break;
- case TRUNC_MOD_EXPR:
- case FLOOR_MOD_EXPR:
- opname = "%"; break;
- case TRUNC_DIV_EXPR:
- case FLOOR_DIV_EXPR:
- opname = "/"; break;
- case BIT_AND_EXPR:
- opname = "&"; break;
- case BIT_IOR_EXPR:
- opname = "|"; break;
- case TRUTH_ANDIF_EXPR:
- opname = "&&"; break;
- case TRUTH_ORIF_EXPR:
- opname = "||"; break;
- case BIT_XOR_EXPR:
- opname = "^"; break;
- case LROTATE_EXPR:
- case RROTATE_EXPR:
- opname = "rotate"; break;
- }
- error ("invalid operands to binary %s", opname);
- }
-
- /* Subroutine of build_binary_op, used for comparison operations.
- See if the operands have both been converted from subword integer types
- and, if so, perhaps change them both back to their original type.
-
- The arguments of this function are all pointers to local variables
- of build_binary_op: OP0_PTR is &OP0, OP1_PTR is &OP1,
- RESTYPE_PTR is &RESULT_TYPE and RESCODE_PTR is &RESULTCODE.
-
- If this function returns nonzero, it means that the comparison has
- a constant value. What this function returns is an expression for
- that value. */
-
- tree
- shorten_compare (op0_ptr, op1_ptr, restype_ptr, rescode_ptr)
- tree *op0_ptr, *op1_ptr;
- tree *restype_ptr;
- enum tree_code *rescode_ptr;
- {
- register tree type;
- tree op0 = *op0_ptr;
- tree op1 = *op1_ptr;
- int unsignedp0, unsignedp1;
- int real1, real2;
- tree primop0, primop1;
- enum tree_code code = *rescode_ptr;
-
- /* Throw away any conversions to wider types
- already present in the operands. */
-
- primop0 = get_narrower (op0, &unsignedp0);
- primop1 = get_narrower (op1, &unsignedp1);
-
- /* Handle the case that OP0 does not *contain* a conversion
- but it *requires* conversion to FINAL_TYPE. */
-
- if (op0 == primop0 && TREE_TYPE (op0) != *restype_ptr)
- unsignedp0 = TREE_UNSIGNED (TREE_TYPE (op0));
- if (op1 == primop1 && TREE_TYPE (op1) != *restype_ptr)
- unsignedp1 = TREE_UNSIGNED (TREE_TYPE (op1));
-
- /* If one of the operands must be floated, we cannot optimize. */
- real1 = TREE_CODE (TREE_TYPE (primop0)) == REAL_TYPE;
- real2 = TREE_CODE (TREE_TYPE (primop1)) == REAL_TYPE;
-
- /* If first arg is constant, swap the args (changing operation
- so value is preserved), for canonicalization. */
-
- if (TREE_CONSTANT (primop0))
- {
- register tree tem = primop0;
- register int temi = unsignedp0;
- primop0 = primop1;
- primop1 = tem;
- tem = op0;
- op0 = op1;
- op1 = tem;
- *op0_ptr = op0;
- *op1_ptr = op1;
- unsignedp0 = unsignedp1;
- unsignedp1 = temi;
- temi = real1;
- real1 = real2;
- real2 = temi;
-
- switch (code)
- {
- case LT_EXPR:
- code = GT_EXPR;
- break;
- case GT_EXPR:
- code = LT_EXPR;
- break;
- case LE_EXPR:
- code = GE_EXPR;
- break;
- case GE_EXPR:
- code = LE_EXPR;
- break;
- }
- *rescode_ptr = code;
- }
-
- /* If comparing an integer against a constant more bits wide,
- maybe we can deduce a value of 1 or 0 independent of the data.
- Or else truncate the constant now
- rather than extend the variable at run time.
-
- This is only interesting if the constant is the wider arg.
- Also, it is not safe if the constant is unsigned and the
- variable arg is signed, since in this case the variable
- would be sign-extended and then regarded as unsigned.
- Our technique fails in this case because the lowest/highest
- possible unsigned results don't follow naturally from the
- lowest/highest possible values of the variable operand.
- For just EQ_EXPR and NE_EXPR there is another technique that
- could be used: see if the constant can be faithfully represented
- in the other operand's type, by truncating it and reextending it
- and see if that preserves the constant's value. */
-
- if (!real1 && !real2
- && TREE_CODE (primop1) == INTEGER_CST
- && TYPE_PRECISION (TREE_TYPE (primop0)) < TYPE_PRECISION (*restype_ptr))
- {
- int min_gt, max_gt, min_lt, max_lt;
- tree maxval, minval;
- /* 1 if comparison is nominally unsigned. */
- int unsignedp = TREE_UNSIGNED (*restype_ptr);
- tree val;
-
- type = signed_or_unsigned_type (unsignedp0, TREE_TYPE (primop0));
-
- maxval = TYPE_MAX_VALUE (type);
- minval = TYPE_MIN_VALUE (type);
-
- if (unsignedp && !unsignedp0)
- *restype_ptr = signed_type (*restype_ptr);
-
- if (TREE_TYPE (primop1) != *restype_ptr)
- primop1 = convert (*restype_ptr, primop1);
- if (type != *restype_ptr)
- {
- minval = convert (*restype_ptr, minval);
- maxval = convert (*restype_ptr, maxval);
- }
-
- if (unsignedp && unsignedp0)
- {
- min_gt = INT_CST_LT_UNSIGNED (primop1, minval);
- max_gt = INT_CST_LT_UNSIGNED (primop1, maxval);
- min_lt = INT_CST_LT_UNSIGNED (minval, primop1);
- max_lt = INT_CST_LT_UNSIGNED (maxval, primop1);
- }
- else
- {
- min_gt = INT_CST_LT (primop1, minval);
- max_gt = INT_CST_LT (primop1, maxval);
- min_lt = INT_CST_LT (minval, primop1);
- max_lt = INT_CST_LT (maxval, primop1);
- }
-
- val = 0;
- /* This used to be a switch, but Genix compiler can't handle that. */
- if (code == NE_EXPR)
- {
- if (max_lt || min_gt)
- val = integer_one_node;
- }
- else if (code == EQ_EXPR)
- {
- if (max_lt || min_gt)
- val = integer_zero_node;
- }
- else if (code == LT_EXPR)
- {
- if (max_lt)
- val = integer_one_node;
- if (!min_lt)
- val = integer_zero_node;
- }
- else if (code == GT_EXPR)
- {
- if (min_gt)
- val = integer_one_node;
- if (!max_gt)
- val = integer_zero_node;
- }
- else if (code == LE_EXPR)
- {
- if (!max_gt)
- val = integer_one_node;
- if (min_gt)
- val = integer_zero_node;
- }
- else if (code == GE_EXPR)
- {
- if (!min_lt)
- val = integer_one_node;
- if (max_lt)
- val = integer_zero_node;
- }
-
- /* If primop0 was sign-extended and unsigned comparison specd,
- we did a signed comparison above using the signed type bounds.
- But the comparison we output must be unsigned.
-
- Also, for inequalities, VAL is no good; but if the signed
- comparison had *any* fixed result, it follows that the
- unsigned comparison just tests the sign in reverse
- (positive values are LE, negative ones GE).
- So we can generate an unsigned comparison
- against an extreme value of the signed type. */
-
- if (unsignedp && !unsignedp0)
- {
- if (val != 0)
- switch (code)
- {
- case LT_EXPR:
- case GE_EXPR:
- primop1 = TYPE_MIN_VALUE (type);
- val = 0;
- break;
-
- case LE_EXPR:
- case GT_EXPR:
- primop1 = TYPE_MAX_VALUE (type);
- val = 0;
- break;
- }
- type = unsigned_type (type);
- }
-
- if (!max_gt && !unsignedp0)
- {
- /* This is the case of (char)x >?< 0x80, which people used to use
- expecting old C compilers to change the 0x80 into -0x80. */
- if (val == integer_zero_node)
- warning ("comparison is always 0 due to limited range of data type");
- if (val == integer_one_node)
- warning ("comparison is always 1 due to limited range of data type");
- }
-
- if (!min_lt && unsignedp0)
- {
- /* This is the case of (unsigned char)x >?< -1 or < 0. */
- if (val == integer_zero_node)
- warning ("comparison is always 0 due to limited range of data type");
- if (val == integer_one_node)
- warning ("comparison is always 1 due to limited range of data type");
- }
-
- if (val != 0)
- {
- /* Don't forget to evaluate PRIMOP0 if it has side effects. */
- if (TREE_SIDE_EFFECTS (primop0))
- return build (COMPOUND_EXPR, TREE_TYPE (val), primop0, val);
- return val;
- }
-
- /* Value is not predetermined, but do the comparison
- in the type of the operand that is not constant.
- TYPE is already properly set. */
- }
- else if (real1 && real2
- && TYPE_PRECISION (TREE_TYPE (primop0)) == TYPE_PRECISION (TREE_TYPE (primop1)))
- type = TREE_TYPE (primop0);
-
- /* If args' natural types are both narrower than nominal type
- and both extend in the same manner, compare them
- in the type of the wider arg.
- Otherwise must actually extend both to the nominal
- common type lest different ways of extending
- alter the result.
- (eg, (short)-1 == (unsigned short)-1 should be 0.) */
-
- else if (unsignedp0 == unsignedp1 && real1 == real2
- && TYPE_PRECISION (TREE_TYPE (primop0)) < TYPE_PRECISION (*restype_ptr)
- && TYPE_PRECISION (TREE_TYPE (primop1)) < TYPE_PRECISION (*restype_ptr))
- {
- type = common_type (TREE_TYPE (primop0), TREE_TYPE (primop1));
- type = signed_or_unsigned_type (unsignedp0
- || TREE_UNSIGNED (*restype_ptr),
- type);
- /* Make sure shorter operand is extended the right way
- to match the longer operand. */
- primop0 = convert (signed_or_unsigned_type (unsignedp0, TREE_TYPE (primop0)),
- primop0);
- primop1 = convert (signed_or_unsigned_type (unsignedp1, TREE_TYPE (primop1)),
- primop1);
- }
- else
- {
- /* Here we must do the comparison on the nominal type
- using the args exactly as we received them. */
- type = *restype_ptr;
- primop0 = op0;
- primop1 = op1;
-
- if (!real1 && !real2 && integer_zerop (primop1)
- && TREE_UNSIGNED (TREE_TYPE (primop0)))
- {
- tree value = 0;
- switch (code)
- {
- case GE_EXPR:
- if (extra_warnings)
- warning ("unsigned value >= 0 is always 1");
- value = integer_one_node;
- break;
-
- case LT_EXPR:
- if (extra_warnings)
- warning ("unsigned value < 0 is always 0");
- value = integer_zero_node;
- }
-
- if (value != 0)
- {
- /* Don't forget to evaluate PRIMOP0 if it has side effects. */
- if (TREE_SIDE_EFFECTS (primop0))
- return build (COMPOUND_EXPR, TREE_TYPE (value),
- primop0, value);
- return value;
- }
- }
- }
-
- *op0_ptr = convert (type, primop0);
- *op1_ptr = convert (type, primop1);
-
- *restype_ptr = integer_type_node;
-
- return 0;
- }
-
- /* Prepare expr to be an argument of a TRUTH_NOT_EXPR,
- or validate its data type for an `if' or `while' statement or ?..: exp.
-
- This preparation consists of taking the ordinary
- representation of an expression expr and producing a valid tree
- boolean expression describing whether expr is nonzero. We could
- simply always do build_binary_op (NE_EXPR, expr, integer_zero_node, 1),
- but we optimize comparisons, &&, ||, and !.
-
- The resulting type should always be `integer_type_node'. */
-
- tree
- truthvalue_conversion (expr)
- tree expr;
- {
- register enum tree_code code;
-
- switch (TREE_CODE (expr))
- {
- /* It is simpler and generates better code to have only TRUTH_*_EXPR
- or comparison expressions as truth values at this level. */
- #if 0
- case COMPONENT_REF:
- /* A one-bit unsigned bit-field is already acceptable. */
- if (1 == TREE_INT_CST_LOW (DECL_SIZE (TREE_OPERAND (expr, 1)))
- && TREE_UNSIGNED (TREE_OPERAND (expr, 1)))
- return expr;
- break;
- #endif
-
- case EQ_EXPR:
- /* It is simpler and generates better code to have only TRUTH_*_EXPR
- or comparison expressions as truth values at this level. */
- #if 0
- if (integer_zerop (TREE_OPERAND (expr, 1)))
- return build_unary_op (TRUTH_NOT_EXPR, TREE_OPERAND (expr, 0), 0);
- #endif
- case NE_EXPR: case LE_EXPR: case GE_EXPR: case LT_EXPR: case GT_EXPR:
- case TRUTH_ANDIF_EXPR:
- case TRUTH_ORIF_EXPR:
- case TRUTH_AND_EXPR:
- case TRUTH_OR_EXPR:
- case ERROR_MARK:
- return expr;
-
- case INTEGER_CST:
- return integer_zerop (expr) ? integer_zero_node : integer_one_node;
-
- case REAL_CST:
- return real_zerop (expr) ? integer_zero_node : integer_one_node;
-
- case ADDR_EXPR:
- if (TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 0)))
- return build (COMPOUND_EXPR, integer_type_node,
- TREE_OPERAND (expr, 0), integer_one_node);
- else
- return integer_one_node;
-
- case NEGATE_EXPR:
- case ABS_EXPR:
- case FLOAT_EXPR:
- case FFS_EXPR:
- /* These don't change whether an object is non-zero or zero. */
- return truthvalue_conversion (TREE_OPERAND (expr, 0));
-
- case LROTATE_EXPR:
- case RROTATE_EXPR:
- /* These don't change whether an object is zero or non-zero, but
- we can't ignore them if their second arg has side-effects. */
- if (TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 1)))
- return build (COMPOUND_EXPR, integer_type_node, TREE_OPERAND (expr, 1),
- truthvalue_conversion (TREE_OPERAND (expr, 0)));
- else
- return truthvalue_conversion (TREE_OPERAND (expr, 0));
-
- case COND_EXPR:
- /* Distribute the conversion into the arms of a COND_EXPR. */
- return fold (build (COND_EXPR, integer_type_node, TREE_OPERAND (expr, 0),
- truthvalue_conversion (TREE_OPERAND (expr, 1)),
- truthvalue_conversion (TREE_OPERAND (expr, 2))));
-
- case CONVERT_EXPR:
- /* Don't cancel the effect of a CONVERT_EXPR from a REFERENCE_TYPE,
- since that affects how `default_conversion' will behave. */
- if (TREE_CODE (TREE_TYPE (expr)) == REFERENCE_TYPE
- || TREE_CODE (TREE_TYPE (TREE_OPERAND (expr, 0))) == REFERENCE_TYPE)
- break;
- /* fall through... */
- case NOP_EXPR:
- /* If this is widening the argument, we can ignore it. */
- if (TYPE_PRECISION (TREE_TYPE (expr))
- >= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (expr, 0))))
- return truthvalue_conversion (TREE_OPERAND (expr, 0));
- break;
-
- case BIT_XOR_EXPR:
- case MINUS_EXPR:
- /* These can be changed into a comparison of the two objects. */
- if (TREE_TYPE (TREE_OPERAND (expr, 0))
- == TREE_TYPE (TREE_OPERAND (expr, 1)))
- return build_binary_op (NE_EXPR, TREE_OPERAND (expr, 0),
- TREE_OPERAND (expr, 1), 1);
- return build_binary_op (NE_EXPR, TREE_OPERAND (expr, 0),
- fold (build1 (NOP_EXPR,
- TREE_TYPE (TREE_OPERAND (expr, 0)),
- TREE_OPERAND (expr, 1))), 1);
-
- case MODIFY_EXPR:
- if (warn_parentheses && C_EXP_ORIGINAL_CODE (expr) == MODIFY_EXPR)
- warning ("suggest parentheses around assignment used as truth value");
- break;
- }
-
- return build_binary_op (NE_EXPR, expr, integer_zero_node, 1);
- }
-
- /* Read the rest of a #-directive from input stream FINPUT.
- In normal use, the directive name and the white space after it
- have already been read, so they won't be included in the result.
- We allow for the fact that the directive line may contain
- a newline embedded within a character or string literal which forms
- a part of the directive.
-
- The value is a string in a reusable buffer. It remains valid
- only until the next time this function is called. */
-
- char *
- get_directive_line (finput)
- register FILE *finput;
- {
- static char *directive_buffer = NULL;
- static unsigned buffer_length = 0;
- register char *p;
- register char *buffer_limit;
- register int looking_for = 0;
- register int char_escaped = 0;
-
- if (buffer_length == 0)
- {
- directive_buffer = (char *)xmalloc (128);
- buffer_length = 128;
- }
-
- buffer_limit = &directive_buffer[buffer_length];
-
- for (p = directive_buffer; ; )
- {
- int c;
-
- /* Make buffer bigger if it is full. */
- if (p >= buffer_limit)
- {
- register unsigned bytes_used = (p - directive_buffer);
-
- buffer_length *= 2;
- directive_buffer
- = (char *)xrealloc (directive_buffer, buffer_length);
- p = &directive_buffer[bytes_used];
- buffer_limit = &directive_buffer[buffer_length];
- }
-
- c = getc (finput);
-
- /* Discard initial whitespace. */
- if ((c == ' ' || c == '\t') && p == directive_buffer)
- continue;
-
- /* Detect the end of the directive. */
- if (c == '\n' && looking_for == 0)
- {
- ungetc (c, finput);
- c = '\0';
- }
-
- *p++ = c;
-
- if (c == 0)
- return directive_buffer;
-
- /* Handle string and character constant syntax. */
- if (looking_for)
- {
- if (looking_for == c && !char_escaped)
- looking_for = 0; /* Found terminator... stop looking. */
- }
- else
- if (c == '\'' || c == '"')
- looking_for = c; /* Don't stop buffering until we see another
- another one of these (or an EOF). */
-
- /* Handle backslash. */
- char_escaped = (c == '\\' && ! char_escaped);
- }
- }
-