summaryrefslogtreecommitdiff
path: root/gcc/expr.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/expr.c')
-rw-r--r--gcc/expr.c343
1 files changed, 244 insertions, 99 deletions
diff --git a/gcc/expr.c b/gcc/expr.c
index 1715578826b..2f28be5a3e4 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -20,6 +20,7 @@ Boston, MA 02111-1307, USA. */
#include "config.h"
+#include <stdio.h>
#include "machmode.h"
#include "rtl.h"
#include "tree.h"
@@ -528,10 +529,11 @@ queued_subexp_p (x)
case MULT:
case PLUS:
case MINUS:
- return queued_subexp_p (XEXP (x, 0))
- || queued_subexp_p (XEXP (x, 1));
+ return (queued_subexp_p (XEXP (x, 0))
+ || queued_subexp_p (XEXP (x, 1)));
+ default:
+ return 0;
}
- return 0;
}
/* Perform all the pending incrementations. */
@@ -776,6 +778,9 @@ convert_move (to, from, unsignedp)
case TFmode:
libcall = extendsftf2_libfunc;
break;
+
+ default:
+ break;
}
break;
@@ -793,6 +798,9 @@ convert_move (to, from, unsignedp)
case TFmode:
libcall = extenddftf2_libfunc;
break;
+
+ default:
+ break;
}
break;
@@ -806,6 +814,9 @@ convert_move (to, from, unsignedp)
case DFmode:
libcall = truncxfdf2_libfunc;
break;
+
+ default:
+ break;
}
break;
@@ -819,8 +830,14 @@ convert_move (to, from, unsignedp)
case DFmode:
libcall = trunctfdf2_libfunc;
break;
+
+ default:
+ break;
}
break;
+
+ default:
+ break;
}
if (libcall == (rtx) 0)
@@ -1567,14 +1584,19 @@ move_by_pieces_1 (genfun, mode, data)
with mode BLKmode.
SIZE is an rtx that says how long they are.
ALIGN is the maximum alignment we can assume they have,
- measured in bytes. */
+ measured in bytes.
-void
+ Return the address of the new block, if memcpy is called and returns it,
+ 0 otherwise. */
+
+rtx
emit_block_move (x, y, size, align)
rtx x, y;
rtx size;
int align;
{
+ rtx retval = 0;
+
if (GET_MODE (x) != BLKmode)
abort ();
@@ -1639,7 +1661,7 @@ emit_block_move (x, y, size, align)
if (pat)
{
emit_insn (pat);
- return;
+ return 0;
}
else
delete_insns_since (last);
@@ -1647,12 +1669,13 @@ emit_block_move (x, y, size, align)
}
#ifdef TARGET_MEM_FUNCTIONS
- emit_library_call (memcpy_libfunc, 0,
- VOIDmode, 3, XEXP (x, 0), Pmode,
- XEXP (y, 0), Pmode,
- convert_to_mode (TYPE_MODE (sizetype), size,
- TREE_UNSIGNED (sizetype)),
- TYPE_MODE (sizetype));
+ retval
+ = emit_library_call_value (memcpy_libfunc, NULL_RTX, 0,
+ ptr_mode, 3, XEXP (x, 0), Pmode,
+ XEXP (y, 0), Pmode,
+ convert_to_mode (TYPE_MODE (sizetype), size,
+ TREE_UNSIGNED (sizetype)),
+ TYPE_MODE (sizetype));
#else
emit_library_call (bcopy_libfunc, 0,
VOIDmode, 3, XEXP (y, 0), Pmode,
@@ -1662,6 +1685,8 @@ emit_block_move (x, y, size, align)
TYPE_MODE (integer_type_node));
#endif
}
+
+ return retval;
}
/* Copy all or part of a value X into registers starting at REGNO.
@@ -1929,7 +1954,7 @@ use_group_regs (call_fusage, regs)
/* A NULL entry means the parameter goes both on the stack and in
registers. This can also be a MEM for targets that pass values
partially on the stack and partially in registers. */
- if (reg && GET_CODE (reg) == REG)
+ if (reg != 0 && GET_CODE (reg) == REG)
use_reg (call_fusage, reg);
}
}
@@ -2066,14 +2091,18 @@ clear_by_pieces_1 (genfun, mode, data)
/* Write zeros through the storage of OBJECT.
If OBJECT has BLKmode, SIZE is its length in bytes and ALIGN is
- the maximum alignment we can is has, measured in bytes. */
+ the maximum alignment we can is has, measured in bytes.
-void
+ If we call a function that returns the length of the block, return it. */
+
+rtx
clear_storage (object, size, align)
rtx object;
rtx size;
int align;
{
+ rtx retval = 0;
+
if (GET_MODE (object) == BLKmode)
{
object = protect_from_queue (object, 1);
@@ -2127,7 +2156,7 @@ clear_storage (object, size, align)
if (pat)
{
emit_insn (pat);
- return;
+ return 0;
}
else
delete_insns_since (last);
@@ -2136,26 +2165,31 @@ clear_storage (object, size, align)
#ifdef TARGET_MEM_FUNCTIONS
- emit_library_call (memset_libfunc, 0,
- VOIDmode, 3,
- XEXP (object, 0), Pmode,
- const0_rtx, TYPE_MODE (integer_type_node),
- convert_to_mode (TYPE_MODE (sizetype),
- size, TREE_UNSIGNED (sizetype)),
- TYPE_MODE (sizetype));
+ retval
+ = emit_library_call_value (memset_libfunc, NULL_RTX, 0,
+ ptr_mode, 3,
+ XEXP (object, 0), Pmode,
+ const0_rtx,
+ TYPE_MODE (integer_type_node),
+ convert_to_mode
+ (TYPE_MODE (sizetype), size,
+ TREE_UNSIGNED (sizetype)),
+ TYPE_MODE (sizetype));
#else
emit_library_call (bzero_libfunc, 0,
VOIDmode, 2,
XEXP (object, 0), Pmode,
- convert_to_mode (TYPE_MODE (integer_type_node),
- size,
- TREE_UNSIGNED (integer_type_node)),
+ convert_to_mode
+ (TYPE_MODE (integer_type_node), size,
+ TREE_UNSIGNED (integer_type_node)),
TYPE_MODE (integer_type_node));
#endif
}
}
else
emit_move_insn (object, CONST0_RTX (GET_MODE (object)));
+
+ return retval;
}
/* Generate code to copy Y into X.
@@ -2940,9 +2974,11 @@ expand_assignment (to, from, want_value, suggest_reg)
size *= GET_MODE_SIZE (best_mode);
/* Check the access right of the pointer. */
- emit_library_call (chkr_check_addr_libfunc, 1, VOIDmode, 3, to_addr,
- ptr_mode, GEN_INT (size), TYPE_MODE (sizetype),
- GEN_INT (MEMORY_USE_WO), QImode);
+ if (size)
+ emit_library_call (chkr_check_addr_libfunc, 1, VOIDmode, 3,
+ to_addr, ptr_mode,
+ GEN_INT (size), TYPE_MODE (sizetype),
+ GEN_INT (MEMORY_USE_WO), QImode);
}
result = store_field (to_rtx, bitsize, bitpos, mode1, from,
@@ -3450,9 +3486,10 @@ is_zeros_p (exp)
return 0;
return 1;
+
+ default:
+ return 0;
}
-
- return 0;
}
/* Return 1 if EXP contains mostly (3/4) zeros. */
@@ -3570,7 +3607,7 @@ store_constructor (exp, target, cleared)
&& GET_MODE_SIZE (GET_MODE (target)) <= UNITS_PER_WORD)
{
if (! cleared)
- emit_move_insn (target, const0_rtx);
+ emit_move_insn (target, CONST0_RTX (GET_MODE (target)));
cleared = 1;
}
@@ -4080,6 +4117,9 @@ store_field (target, bitsize, bitpos, mode, exp, value_mode,
{
HOST_WIDE_INT width_mask = 0;
+ if (TREE_CODE (exp) == ERROR_MARK)
+ return const0_rtx;
+
if (bitsize < HOST_BITS_PER_WIDE_INT)
width_mask = ((HOST_WIDE_INT) 1 << bitsize) - 1;
@@ -4697,6 +4737,9 @@ safe_from_p (x, exp)
case METHOD_CALL_EXPR:
/* This takes a rtx argument, but shouldn't appear here. */
abort ();
+
+ default:
+ break;
}
/* If we have an rtx, we do not need to scan our operands. */
@@ -5215,51 +5258,59 @@ expand_expr (exp, target, tmode, modifier)
}
case PLACEHOLDER_EXPR:
- /* If there is an object on the head of the placeholder list,
- see if some object in it's references is of type TYPE. For
- further information, see tree.def. */
- if (placeholder_list)
- {
- tree need_type = TYPE_MAIN_VARIANT (type);
- tree object = 0;
- tree old_list = placeholder_list;
- tree elt;
+ {
+ tree placeholder_expr;
+
+ /* If there is an object on the head of the placeholder list,
+ see if some object in it's references is of type TYPE. For
+ further information, see tree.def. */
+ for (placeholder_expr = placeholder_list;
+ placeholder_expr != 0;
+ placeholder_expr = TREE_CHAIN (placeholder_expr))
+ {
+ tree need_type = TYPE_MAIN_VARIANT (type);
+ tree object = 0;
+ tree old_list = placeholder_list;
+ tree elt;
+
+ /* See if the object is the type that we want. */
+ if ((TYPE_MAIN_VARIANT (TREE_TYPE
+ (TREE_PURPOSE (placeholder_expr)))
+ == need_type))
+ object = TREE_PURPOSE (placeholder_expr);
+
+ /* Find the innermost reference that is of the type we want. */
+ for (elt = TREE_PURPOSE (placeholder_expr);
+ elt != 0
+ && (TREE_CODE_CLASS (TREE_CODE (elt)) == 'r'
+ || TREE_CODE_CLASS (TREE_CODE (elt)) == '1'
+ || TREE_CODE_CLASS (TREE_CODE (elt)) == '2'
+ || TREE_CODE_CLASS (TREE_CODE (elt)) == 'e');
+ elt = ((TREE_CODE (elt) == COMPOUND_EXPR
+ || TREE_CODE (elt) == COND_EXPR)
+ ? TREE_OPERAND (elt, 1) : TREE_OPERAND (elt, 0)))
+ if (TREE_CODE_CLASS (TREE_CODE (elt)) == 'r'
+ && (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (elt, 0)))
+ == need_type))
+ {
+ object = TREE_OPERAND (elt, 0);
+ break;
+ }
- /* See if the object is the type that we want. */
- if ((TYPE_MAIN_VARIANT (TREE_TYPE (TREE_PURPOSE (placeholder_list)))
- == need_type))
- object = TREE_PURPOSE (placeholder_list);
-
- /* Find the innermost reference that is of the type we want. */
- for (elt = TREE_PURPOSE (placeholder_list);
- elt != 0
- && (TREE_CODE_CLASS (TREE_CODE (elt)) == 'r'
- || TREE_CODE_CLASS (TREE_CODE (elt)) == '1'
- || TREE_CODE_CLASS (TREE_CODE (elt)) == '2'
- || TREE_CODE_CLASS (TREE_CODE (elt)) == 'e');
- elt = ((TREE_CODE (elt) == COMPOUND_EXPR
- || TREE_CODE (elt) == COND_EXPR)
- ? TREE_OPERAND (elt, 1) : TREE_OPERAND (elt, 0)))
- if (TREE_CODE_CLASS (TREE_CODE (elt)) == 'r'
- && (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (elt, 0)))
- == need_type))
+ if (object != 0)
{
- object = TREE_OPERAND (elt, 0);
- break;
+ /* Expand this object skipping the list entries before
+ it was found in case it is also a PLACEHOLDER_EXPR.
+ In that case, we want to translate it using subsequent
+ entries. */
+ placeholder_list = TREE_CHAIN (placeholder_expr);
+ temp = expand_expr (object, original_target, tmode,
+ ro_modifier);
+ placeholder_list = old_list;
+ return temp;
}
-
- if (object != 0)
- {
- /* Expand this object skipping the list entries before
- it was found in case it is also a PLACEHOLDER_EXPR.
- In that case, we want to translate it using subsequent
- entries. */
- placeholder_list = TREE_CHAIN (placeholder_list);
- temp = expand_expr (object, original_target, tmode, ro_modifier);
- placeholder_list = old_list;
- return temp;
- }
- }
+ }
+ }
/* We can't find the object or there was a missing WITH_RECORD_EXPR. */
abort ();
@@ -5681,11 +5732,12 @@ expand_expr (exp, target, tmode, modifier)
size = (bitpos % BITS_PER_UNIT) + bitsize + BITS_PER_UNIT - 1;
/* Check the access right of the pointer. */
- emit_library_call (chkr_check_addr_libfunc, 1, VOIDmode, 3,
- to, ptr_mode,
- GEN_INT (size / BITS_PER_UNIT),
- TYPE_MODE (sizetype),
- GEN_INT (memory_usage), QImode);
+ if (size > BITS_PER_UNIT)
+ emit_library_call (chkr_check_addr_libfunc, 1, VOIDmode, 3,
+ to, ptr_mode,
+ GEN_INT (size / BITS_PER_UNIT),
+ TYPE_MODE (sizetype),
+ GEN_INT (memory_usage), QImode);
}
}
@@ -6832,7 +6884,8 @@ expand_expr (exp, target, tmode, modifier)
&& integer_zerop (TREE_OPERAND (TREE_OPERAND (exp, 0), 1))
&& operand_equal_p (TREE_OPERAND (TREE_OPERAND (exp, 0), 0),
TREE_OPERAND (exp, 1), 0)
- && ! TREE_SIDE_EFFECTS (TREE_OPERAND (exp, 0))
+ && (! TREE_SIDE_EFFECTS (TREE_OPERAND (exp, 0))
+ || TREE_CODE (TREE_OPERAND (exp, 1)) == SAVE_EXPR)
&& safe_from_p (temp, TREE_OPERAND (exp, 2)))
{
if (GET_CODE (temp) == REG && REGNO (temp) < FIRST_PSEUDO_REGISTER)
@@ -6849,7 +6902,8 @@ expand_expr (exp, target, tmode, modifier)
&& integer_zerop (TREE_OPERAND (TREE_OPERAND (exp, 0), 1))
&& operand_equal_p (TREE_OPERAND (TREE_OPERAND (exp, 0), 0),
TREE_OPERAND (exp, 2), 0)
- && ! TREE_SIDE_EFFECTS (TREE_OPERAND (exp, 0))
+ && (! TREE_SIDE_EFFECTS (TREE_OPERAND (exp, 0))
+ || TREE_CODE (TREE_OPERAND (exp, 2)) == SAVE_EXPR)
&& safe_from_p (temp, TREE_OPERAND (exp, 1)))
{
if (GET_CODE (temp) == REG && REGNO (temp) < FIRST_PSEUDO_REGISTER)
@@ -6928,10 +6982,15 @@ expand_expr (exp, target, tmode, modifier)
}
else
{
- target = assign_temp (type, 2, 1, 1);
+ target = assign_temp (type, 2, 0, 1);
/* All temp slots at this level must not conflict. */
preserve_temp_slots (target);
DECL_RTL (slot) = target;
+ if (TREE_ADDRESSABLE (slot))
+ {
+ TREE_ADDRESSABLE (slot) = 0;
+ mark_addressable (slot);
+ }
/* Since SLOT is not known to the called function
to belong to its stack frame, we must build an explicit
@@ -7775,6 +7834,9 @@ bc_expand_expr (exp)
return;
}
+
+ default:
+ abort ();
}
abort ();
@@ -8672,6 +8734,16 @@ expand_builtin (exp, target, subtarget, mode, ignore)
TREE_INT_CST_LOW (TREE_VALUE (arglist)),
hard_frame_pointer_rtx);
+ /* Some ports cannot access arbitrary stack frames. */
+ if (tem == NULL)
+ {
+ if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_FRAME_ADDRESS)
+ warning ("unsupported arg to `__builtin_frame_address'");
+ else
+ warning ("unsupported arg to `__builtin_return_address'");
+ return const0_rtx;
+ }
+
/* For __builtin_frame_address, return what we've got. */
if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_FRAME_ADDRESS)
return tem;
@@ -8777,13 +8849,19 @@ expand_builtin (exp, target, subtarget, mode, ignore)
if (! (*insn_operand_predicate[(int)icode][0]) (result, insn_mode))
result = gen_reg_rtx (insn_mode);
-
src_rtx = memory_address (BLKmode,
expand_expr (src, NULL_RTX, ptr_mode,
EXPAND_NORMAL));
+
if (! (*insn_operand_predicate[(int)icode][1]) (src_rtx, Pmode))
src_rtx = copy_to_mode_reg (Pmode, src_rtx);
+ /* Check the string is readable and has an end. */
+ if (flag_check_memory_usage)
+ emit_library_call (chkr_check_str_libfunc, 1, VOIDmode, 2,
+ src_rtx, ptr_mode,
+ GEN_INT (MEMORY_USE_RO), QImode);
+
char_rtx = const0_rtx;
char_mode = insn_operand_mode[(int)icode][2];
if (! (*insn_operand_predicate[(int)icode][2]) (char_rtx, char_mode))
@@ -8838,9 +8916,12 @@ expand_builtin (exp, target, subtarget, mode, ignore)
/* Arg could be non-pointer if user redeclared this fcn wrong. */
|| TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE
|| TREE_CHAIN (arglist) == 0
- || TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (arglist)))) != POINTER_TYPE
+ || (TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (arglist))))
+ != POINTER_TYPE)
|| TREE_CHAIN (TREE_CHAIN (arglist)) == 0
- || TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))))) != INTEGER_TYPE)
+ || (TREE_CODE (TREE_TYPE (TREE_VALUE
+ (TREE_CHAIN (TREE_CHAIN (arglist)))))
+ != INTEGER_TYPE))
break;
else
{
@@ -8853,7 +8934,7 @@ expand_builtin (exp, target, subtarget, mode, ignore)
= get_pointer_alignment (src, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
int dest_align
= get_pointer_alignment (dest, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
- rtx dest_rtx, dest_mem, src_mem;
+ rtx dest_rtx, dest_mem, src_mem, src_rtx, dest_addr, len_rtx;
/* If either SRC or DEST is not a pointer type, don't do
this operation in-line. */
@@ -8872,11 +8953,18 @@ expand_builtin (exp, target, subtarget, mode, ignore)
dest = TREE_OPERAND (dest, 0);
type = TREE_TYPE (TREE_TYPE (dest));
MEM_IN_STRUCT_P (dest_mem) = AGGREGATE_TYPE_P (type);
+ src_rtx = expand_expr (src, NULL_RTX, ptr_mode, EXPAND_SUM);
src_mem = gen_rtx (MEM, BLKmode,
- memory_address (BLKmode,
- expand_expr (src, NULL_RTX,
- ptr_mode,
- EXPAND_SUM)));
+ memory_address (BLKmode, src_rtx));
+ len_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
+
+ /* Just copy the rights of SRC to the rights of DEST. */
+ if (flag_check_memory_usage)
+ emit_library_call (chkr_copy_bitmap_libfunc, 1, VOIDmode, 3,
+ src_rtx, ptr_mode,
+ dest_rtx, ptr_mode,
+ len_rtx, TYPE_MODE (sizetype));
+
/* There could be a void* cast on top of the object. */
while (TREE_CODE (src) == NOP_EXPR)
src = TREE_OPERAND (src, 0);
@@ -8884,10 +8972,14 @@ expand_builtin (exp, target, subtarget, mode, ignore)
MEM_IN_STRUCT_P (src_mem) = AGGREGATE_TYPE_P (type);
/* Copy word part most expediently. */
- emit_block_move (dest_mem, src_mem,
- expand_expr (len, NULL_RTX, VOIDmode, 0),
- MIN (src_align, dest_align));
- return force_operand (dest_rtx, NULL_RTX);
+ dest_addr
+ = emit_block_move (dest_mem, src_mem, len_rtx,
+ MIN (src_align, dest_align));
+
+ if (dest_addr == 0)
+ dest_addr = force_operand (dest_rtx, NULL_RTX);
+
+ return dest_addr;
}
case BUILT_IN_MEMSET:
@@ -8916,7 +9008,7 @@ expand_builtin (exp, target, subtarget, mode, ignore)
int dest_align
= get_pointer_alignment (dest, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
- rtx dest_rtx, dest_mem;
+ rtx dest_rtx, dest_mem, dest_addr, len_rtx;
/* If DEST is not a pointer type, don't do this
operation in-line. */
@@ -8930,16 +9022,28 @@ expand_builtin (exp, target, subtarget, mode, ignore)
dest_rtx = expand_expr (dest, NULL_RTX, ptr_mode, EXPAND_SUM);
dest_mem = gen_rtx (MEM, BLKmode,
memory_address (BLKmode, dest_rtx));
+ len_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
+
+ /* Just check DST is writable and mark it as readable. */
+ if (flag_check_memory_usage)
+ emit_library_call (chkr_check_addr_libfunc, 1, VOIDmode, 3,
+ dest_rtx, ptr_mode,
+ len_rtx, TYPE_MODE (sizetype),
+ GEN_INT (MEMORY_USE_WO), QImode);
+
+
/* There could be a void* cast on top of the object. */
while (TREE_CODE (dest) == NOP_EXPR)
dest = TREE_OPERAND (dest, 0);
type = TREE_TYPE (TREE_TYPE (dest));
MEM_IN_STRUCT_P (dest_mem) = AGGREGATE_TYPE_P (type);
- clear_storage (dest_mem, expand_expr (len, NULL_RTX, VOIDmode, 0),
- dest_align);
+ dest_addr = clear_storage (dest_mem, len_rtx, dest_align);
+
+ if (dest_addr == 0)
+ dest_addr = force_operand (dest_rtx, NULL_RTX);
- return force_operand (dest_rtx, NULL_RTX);
+ return dest_addr;
}
/* These comparison functions need an instruction that returns an actual
@@ -8951,6 +9055,10 @@ expand_builtin (exp, target, subtarget, mode, ignore)
if (!optimize && ! CALLED_AS_BUILT_IN (fndecl))
break;
+ /* If we need to check memory accesses, call the library function. */
+ if (flag_check_memory_usage)
+ break;
+
if (arglist == 0
/* Arg could be non-pointer if user redeclared this fcn wrong. */
|| TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE
@@ -9004,6 +9112,10 @@ expand_builtin (exp, target, subtarget, mode, ignore)
if (!optimize && ! CALLED_AS_BUILT_IN (fndecl))
break;
+ /* If we need to check memory accesses, call the library function. */
+ if (flag_check_memory_usage)
+ break;
+
if (arglist == 0
/* Arg could be non-pointer if user redeclared this fcn wrong. */
|| TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE
@@ -9498,7 +9610,7 @@ expand_builtin_apply (function, arguments, argsize)
haven't figured out how the calling convention macros effect this,
but it's likely that the source and/or destination addresses in
the block copy will need updating in machine specific ways. */
- dest = copy_addr_to_reg (push_block (argsize, 0, 0));
+ dest = allocate_dynamic_stack_space (argsize, 0, 0);
emit_block_move (gen_rtx (MEM, BLKmode, dest),
gen_rtx (MEM, BLKmode, incoming_args),
argsize,
@@ -9942,6 +10054,9 @@ preexpand_calls (exp)
case SAVE_EXPR:
if (SAVE_EXPR_RTL (exp) != 0)
return;
+
+ default:
+ break;
}
nops = tree_code_length[(int) TREE_CODE (exp)];
@@ -10566,9 +10681,38 @@ do_jump_by_parts_equality_rtx (op0, if_false_label, if_true_label)
rtx if_false_label, if_true_label;
{
int nwords = GET_MODE_SIZE (GET_MODE (op0)) / UNITS_PER_WORD;
+ rtx part;
int i;
rtx drop_through_label = 0;
+ /* The fastest way of doing this comparison on almost any machine is to
+ "or" all the words and compare the result. If all have to be loaded
+ from memory and this is a very wide item, it's possible this may
+ be slower, but that's highly unlikely. */
+
+ part = gen_reg_rtx (word_mode);
+ emit_move_insn (part, operand_subword_force (op0, 0, GET_MODE (op0)));
+ for (i = 1; i < nwords && part != 0; i++)
+ part = expand_binop (word_mode, ior_optab, part,
+ operand_subword_force (op0, i, GET_MODE (op0)),
+ part, 1, OPTAB_WIDEN);
+
+ if (part != 0)
+ {
+ rtx comp = compare_from_rtx (part, const0_rtx, EQ, 1, word_mode,
+ NULL_RTX, 0);
+
+ if (comp == const_true_rtx)
+ emit_jump (if_false_label);
+ else if (comp == const0_rtx)
+ emit_jump (if_true_label);
+ else
+ do_jump_for_compare (comp, if_false_label, if_true_label);
+
+ return;
+ }
+
+ /* If we couldn't do the "or" simply, do this with a series of compares. */
if (! if_false_label)
drop_through_label = if_false_label = gen_label_rtx ();
@@ -10585,6 +10729,7 @@ do_jump_by_parts_equality_rtx (op0, if_false_label, if_true_label)
if (if_true_label)
emit_jump (if_true_label);
+
if (drop_through_label)
emit_label (drop_through_label);
}