Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
R
riscv-gcc-1
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
lvzhengyang
riscv-gcc-1
Commits
b30f223b
Commit
b30f223b
authored
Feb 04, 1992
by
Richard Stallman
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Initial revision
From-SVN: r278
parent
6bce1b78
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
894 additions
and
0 deletions
+894
-0
gcc/c-common.c
+894
-0
No files found.
gcc/c-common.c
0 → 100644
View file @
b30f223b
/* 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
);
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment