parent
6bce1b7883
commit
b30f223b0d
|
@ -0,0 +1,894 @@
|
|||
/* 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>
|
||||
|
||||
#undef NULL
|
||||
#define NULL 0
|
||||
|
||||
/* 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) != 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)
|
||||
warning_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)
|
||||
warning_with_decl (decl,
|
||||
"alignment specified for `%s' which is not a variable");
|
||||
|
||||
/* ??? The maximum alignment gcc can currently handle is 16 bytes!
|
||||
We should change the representation to be the log of the
|
||||
actual alignment since we only handle powers of 2 anyway. */
|
||||
else if (align > 255)
|
||||
warning_with_decl (decl,
|
||||
"requested alignment of `%s' exceeds compiler limits");
|
||||
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 ("packed"))
|
||||
{
|
||||
if (TREE_CODE (decl) == FIELD_DECL)
|
||||
DECL_PACKED (decl) = 1;
|
||||
}
|
||||
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)
|
||||
{
|
||||
warning_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
|
||||
{
|
||||
warning_with_decl (decl,"unrecognized format specifier for `%s'");
|
||||
return;
|
||||
}
|
||||
|
||||
if (first_arg_num != 0 && first_arg_num <= format_num)
|
||||
{
|
||||
warning_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);
|
||||
}
|
||||
}
|
||||
|
||||
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. */
|
||||
if (TREE_CODE (value) == NON_LVALUE_EXPR)
|
||||
value = TREE_OPERAND (value, 0);
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
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 (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:
|
||||
opname = "%"; break;
|
||||
case TRUNC_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;
|
||||
}
|
||||
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_lt && !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_gt && unsignedp0)
|
||||
{
|
||||
/* This is the case of (unsigned char)x >?< -1. */
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue