#include "config.h"
#include "system.h"
#include "machmode.h"
#include "real.h"
#include "rtl.h"
#include "tree.h"
#include "flags.h"
#include "regs.h"
#include "hard-reg-set.h"
#include "except.h"
#include "function.h"
#include "insn-config.h"
#include "insn-attr.h"
#include "expr.h"
#include "optabs.h"
#include "libfuncs.h"
#include "recog.h"
#include "reload.h"
#include "output.h"
#include "typeclass.h"
#include "toplev.h"
#include "ggc.h"
#include "langhooks.h"
#include "intl.h"
#include "tm_p.h"
#include "feedback.h"
#ifdef PUSH_ROUNDING
#ifndef PUSH_ARGS_REVERSED
#if defined (STACK_GROWS_DOWNWARD) != defined (ARGS_GROW_DOWNWARD)
#define PUSH_ARGS_REVERSED
#endif
#endif
#endif
#ifndef STACK_PUSH_CODE
#ifdef STACK_GROWS_DOWNWARD
#define STACK_PUSH_CODE PRE_DEC
#else
#define STACK_PUSH_CODE PRE_INC
#endif
#endif
#ifndef CASE_VECTOR_PC_RELATIVE
#define CASE_VECTOR_PC_RELATIVE 0
#endif
#ifdef TARGET_MEM_FUNCTIONS
#undef TARGET_MEM_FUNCTIONS
#define TARGET_MEM_FUNCTIONS 1
#else
#define TARGET_MEM_FUNCTIONS 0
#endif
int cse_not_expected;
static tree placeholder_list = 0;
struct move_by_pieces
{
rtx to;
rtx to_addr;
int autinc_to;
int explicit_inc_to;
rtx from;
rtx from_addr;
int autinc_from;
int explicit_inc_from;
unsigned HOST_WIDE_INT len;
HOST_WIDE_INT offset;
int reverse;
};
struct store_by_pieces
{
rtx to;
rtx to_addr;
int autinc_to;
int explicit_inc_to;
unsigned HOST_WIDE_INT len;
HOST_WIDE_INT offset;
rtx (*constfun) PARAMS ((PTR, HOST_WIDE_INT, enum machine_mode));
PTR constfundata;
int reverse;
};
static rtx enqueue_insn PARAMS ((rtx, rtx));
static unsigned HOST_WIDE_INT move_by_pieces_ninsns
PARAMS ((unsigned HOST_WIDE_INT,
unsigned int));
static void move_by_pieces_1 PARAMS ((rtx (*) (rtx, ...), enum machine_mode,
struct move_by_pieces *));
static bool block_move_libcall_safe_for_call_parm PARAMS ((void));
static bool emit_block_move_via_movstr PARAMS ((rtx, rtx, rtx, unsigned));
static rtx emit_block_move_via_libcall PARAMS ((rtx, rtx, rtx));
static tree emit_block_move_libcall_fn PARAMS ((int));
static void emit_block_move_via_loop PARAMS ((rtx, rtx, rtx, unsigned));
static rtx clear_by_pieces_1 PARAMS ((PTR, HOST_WIDE_INT,
enum machine_mode));
static void clear_by_pieces PARAMS ((rtx, unsigned HOST_WIDE_INT,
unsigned int));
static void store_by_pieces_1 PARAMS ((struct store_by_pieces *,
unsigned int));
static void store_by_pieces_2 PARAMS ((rtx (*) (rtx, ...),
enum machine_mode,
struct store_by_pieces *));
static bool clear_storage_via_clrstr PARAMS ((rtx, rtx, unsigned));
static rtx clear_storage_via_libcall PARAMS ((rtx, rtx));
static tree clear_storage_libcall_fn PARAMS ((int));
static rtx compress_float_constant PARAMS ((rtx, rtx));
static rtx get_subtarget PARAMS ((rtx));
static int is_zeros_p PARAMS ((tree));
static int mostly_zeros_p PARAMS ((tree));
static void store_constructor_field PARAMS ((rtx, unsigned HOST_WIDE_INT,
HOST_WIDE_INT, enum machine_mode,
tree, tree, int, int));
static void store_constructor PARAMS ((tree, rtx, int, HOST_WIDE_INT));
static rtx store_field PARAMS ((rtx, HOST_WIDE_INT,
HOST_WIDE_INT, enum machine_mode,
tree, enum machine_mode, int, tree,
int));
static rtx var_rtx PARAMS ((tree));
static HOST_WIDE_INT highest_pow2_factor PARAMS ((tree));
static HOST_WIDE_INT highest_pow2_factor_for_type PARAMS ((tree, tree));
static int is_aligning_offset PARAMS ((tree, tree));
static rtx expand_increment PARAMS ((tree, int, int));
static void do_jump_by_parts_greater PARAMS ((tree, int, rtx, rtx));
static void do_jump_by_parts_equality PARAMS ((tree, rtx, rtx));
static void do_compare_and_jump PARAMS ((tree, enum rtx_code, enum rtx_code,
rtx, rtx));
static void do_compare_and_jump_1 PARAMS ((tree, enum rtx_code, enum rtx_code,
rtx, rtx));
static rtx do_store_flag PARAMS ((tree, rtx, enum machine_mode, int));
#ifdef PUSH_ROUNDING
static void emit_single_push_insn PARAMS ((enum machine_mode, rtx, tree));
#endif
static void do_tablejump PARAMS ((rtx, enum machine_mode, rtx, rtx, rtx, tree));
static char direct_load[NUM_MACHINE_MODES];
static char direct_store[NUM_MACHINE_MODES];
static bool float_extend_from_mem[NUM_MACHINE_MODES][NUM_MACHINE_MODES];
#ifndef MOVE_RATIO
#if defined (HAVE_movstrqi) || defined (HAVE_movstrhi) || defined (HAVE_movstrsi) || defined (HAVE_movstrdi) || defined (HAVE_movstrti)
#define MOVE_RATIO 2
#else
#define MOVE_RATIO (optimize_size ? 3 : 15)
#endif
#endif
#ifndef MOVE_BY_PIECES_P
#define MOVE_BY_PIECES_P(SIZE, ALIGN) \
(move_by_pieces_ninsns (SIZE, ALIGN) < (unsigned int) MOVE_RATIO)
#endif
#ifndef CLEAR_RATIO
#if defined (HAVE_clrstrqi) || defined (HAVE_clrstrhi) || defined (HAVE_clrstrsi) || defined (HAVE_clrstrdi) || defined (HAVE_clrstrti)
#define CLEAR_RATIO 2
#else
#define CLEAR_RATIO (optimize_size ? 3 : 15)
#endif
#endif
#ifndef CLEAR_BY_PIECES_P
#define CLEAR_BY_PIECES_P(SIZE, ALIGN) \
(move_by_pieces_ninsns (SIZE, ALIGN) < (unsigned int) CLEAR_RATIO)
#endif
enum insn_code movstr_optab[NUM_MACHINE_MODES];
enum insn_code clrstr_optab[NUM_MACHINE_MODES];
#ifndef SLOW_UNALIGNED_ACCESS
#define SLOW_UNALIGNED_ACCESS(MODE, ALIGN) STRICT_ALIGNMENT
#endif
void
init_expr_once ()
{
rtx insn, pat;
enum machine_mode mode;
int num_clobbers;
rtx mem, mem1;
rtx reg;
mem = gen_rtx_MEM (VOIDmode, stack_pointer_rtx);
mem1 = gen_rtx_MEM (VOIDmode, frame_pointer_rtx);
reg = gen_rtx_REG (VOIDmode, -1);
insn = rtx_alloc (INSN);
pat = gen_rtx_SET (0, NULL_RTX, NULL_RTX);
PATTERN (insn) = pat;
for (mode = VOIDmode; (int) mode < NUM_MACHINE_MODES;
mode = (enum machine_mode) ((int) mode + 1))
{
int regno;
direct_load[(int) mode] = direct_store[(int) mode] = 0;
PUT_MODE (mem, mode);
PUT_MODE (mem1, mode);
PUT_MODE (reg, mode);
if (mode != VOIDmode && mode != BLKmode)
for (regno = 0; regno < FIRST_PSEUDO_REGISTER
&& (direct_load[(int) mode] == 0 || direct_store[(int) mode] == 0);
regno++)
{
if (! HARD_REGNO_MODE_OK (regno, mode))
continue;
REGNO (reg) = regno;
SET_SRC (pat) = mem;
SET_DEST (pat) = reg;
if (recog (pat, insn, &num_clobbers) >= 0)
direct_load[(int) mode] = 1;
SET_SRC (pat) = mem1;
SET_DEST (pat) = reg;
if (recog (pat, insn, &num_clobbers) >= 0)
direct_load[(int) mode] = 1;
SET_SRC (pat) = reg;
SET_DEST (pat) = mem;
if (recog (pat, insn, &num_clobbers) >= 0)
direct_store[(int) mode] = 1;
SET_SRC (pat) = reg;
SET_DEST (pat) = mem1;
if (recog (pat, insn, &num_clobbers) >= 0)
direct_store[(int) mode] = 1;
}
}
mem = gen_rtx_MEM (VOIDmode, gen_rtx_raw_REG (Pmode, 10000));
for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT); mode != VOIDmode;
mode = GET_MODE_WIDER_MODE (mode))
{
enum machine_mode srcmode;
for (srcmode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT); srcmode != mode;
srcmode = GET_MODE_WIDER_MODE (srcmode))
{
enum insn_code ic;
ic = can_extend_p (mode, srcmode, 0);
if (ic == CODE_FOR_nothing)
continue;
PUT_MODE (mem, srcmode);
if ((*insn_data[ic].operand[1].predicate) (mem, srcmode))
float_extend_from_mem[mode][srcmode] = true;
}
}
}
void
init_expr ()
{
cfun->expr = (struct expr_status *) ggc_alloc (sizeof (struct expr_status));
pending_chain = 0;
pending_stack_adjust = 0;
stack_pointer_delta = 0;
inhibit_defer_pop = 0;
saveregs_value = 0;
apply_args_value = 0;
forced_labels = 0;
}
void
finish_expr_for_function ()
{
if (pending_chain)
abort ();
}
static rtx
enqueue_insn (var, body)
rtx var, body;
{
pending_chain = gen_rtx_QUEUED (GET_MODE (var), var, NULL_RTX, NULL_RTX,
body, pending_chain);
return pending_chain;
}
rtx
protect_from_queue (x, modify)
rtx x;
int modify;
{
RTX_CODE code = GET_CODE (x);
#if 0
if (pending_chain == 0)
return x;
#endif
if (code != QUEUED)
{
if (code == MEM && GET_MODE (x) != BLKmode
&& GET_CODE (XEXP (x, 0)) == QUEUED && !modify)
{
rtx y = XEXP (x, 0);
rtx new = replace_equiv_address_nv (x, QUEUED_VAR (y));
if (QUEUED_INSN (y))
{
rtx temp = gen_reg_rtx (GET_MODE (x));
emit_insn_before (gen_move_insn (temp, new),
QUEUED_INSN (y));
return temp;
}
return replace_equiv_address (new, copy_to_reg (XEXP (new, 0)));
}
if (code == MEM)
{
rtx tem = protect_from_queue (XEXP (x, 0), 0);
if (tem != XEXP (x, 0))
{
x = copy_rtx (x);
XEXP (x, 0) = tem;
}
}
else if (code == PLUS || code == MULT)
{
rtx new0 = protect_from_queue (XEXP (x, 0), 0);
rtx new1 = protect_from_queue (XEXP (x, 1), 0);
if (new0 != XEXP (x, 0) || new1 != XEXP (x, 1))
{
x = copy_rtx (x);
XEXP (x, 0) = new0;
XEXP (x, 1) = new1;
}
}
return x;
}
if (QUEUED_INSN (x) == 0)
return copy_to_reg (QUEUED_VAR (x));
if (QUEUED_COPY (x) != 0)
return QUEUED_COPY (x);
QUEUED_COPY (x) = gen_reg_rtx (GET_MODE (QUEUED_VAR (x)));
emit_insn_before (gen_move_insn (QUEUED_COPY (x), QUEUED_VAR (x)),
QUEUED_INSN (x));
return QUEUED_COPY (x);
}
int
queued_subexp_p (x)
rtx x;
{
enum rtx_code code = GET_CODE (x);
switch (code)
{
case QUEUED:
return 1;
case MEM:
return queued_subexp_p (XEXP (x, 0));
case MULT:
case PLUS:
case MINUS:
return (queued_subexp_p (XEXP (x, 0))
|| queued_subexp_p (XEXP (x, 1)));
default:
return 0;
}
}
void
emit_queue ()
{
rtx p;
while ((p = pending_chain))
{
rtx body = QUEUED_BODY (p);
switch (GET_CODE (body))
{
case INSN:
case JUMP_INSN:
case CALL_INSN:
case CODE_LABEL:
case BARRIER:
case NOTE:
QUEUED_INSN (p) = body;
emit_insn (body);
break;
#ifdef ENABLE_CHECKING
case SEQUENCE:
abort ();
break;
#endif
default:
QUEUED_INSN (p) = emit_insn (body);
break;
}
pending_chain = QUEUED_NEXT (p);
}
}
void
convert_move (to, from, unsignedp)
rtx to, from;
int unsignedp;
{
enum machine_mode to_mode = GET_MODE (to);
enum machine_mode from_mode = GET_MODE (from);
int to_real = GET_MODE_CLASS (to_mode) == MODE_FLOAT;
int from_real = GET_MODE_CLASS (from_mode) == MODE_FLOAT;
enum insn_code code;
rtx libcall;
enum rtx_code equiv_code = (unsignedp < 0 ? UNKNOWN
: (unsignedp ? ZERO_EXTEND : SIGN_EXTEND));
to = protect_from_queue (to, 1);
from = protect_from_queue (from, 0);
if (to_real != from_real)
abort ();
if (GET_CODE (from) == SUBREG && SUBREG_PROMOTED_VAR_P (from)
&& (GET_MODE_SIZE (GET_MODE (SUBREG_REG (from)))
>= GET_MODE_SIZE (to_mode))
&& SUBREG_PROMOTED_UNSIGNED_P (from) == unsignedp)
from = gen_lowpart (to_mode, from), from_mode = to_mode;
if (GET_CODE (to) == SUBREG && SUBREG_PROMOTED_VAR_P (to))
abort ();
if (to_mode == from_mode
|| (from_mode == VOIDmode && CONSTANT_P (from)))
{
emit_move_insn (to, from);
return;
}
if (VECTOR_MODE_P (to_mode) || VECTOR_MODE_P (from_mode))
{
if (GET_MODE_BITSIZE (from_mode) != GET_MODE_BITSIZE (to_mode))
abort ();
if (VECTOR_MODE_P (to_mode))
from = simplify_gen_subreg (to_mode, from, GET_MODE (from), 0);
else
to = simplify_gen_subreg (from_mode, to, GET_MODE (to), 0);
emit_move_insn (to, from);
return;
}
if (to_real != from_real)
abort ();
if (to_real)
{
rtx value, insns;
if (GET_MODE_BITSIZE (from_mode) < GET_MODE_BITSIZE (to_mode))
{
if ((code = can_extend_p (to_mode, from_mode, 0))
!= CODE_FOR_nothing)
{
emit_unop_insn (code, to, from, UNKNOWN);
return;
}
}
#ifdef HAVE_trunchfqf2
if (HAVE_trunchfqf2 && from_mode == HFmode && to_mode == QFmode)
{
emit_unop_insn (CODE_FOR_trunchfqf2, to, from, UNKNOWN);
return;
}
#endif
#ifdef HAVE_trunctqfqf2
if (HAVE_trunctqfqf2 && from_mode == TQFmode && to_mode == QFmode)
{
emit_unop_insn (CODE_FOR_trunctqfqf2, to, from, UNKNOWN);
return;
}
#endif
#ifdef HAVE_truncsfqf2
if (HAVE_truncsfqf2 && from_mode == SFmode && to_mode == QFmode)
{
emit_unop_insn (CODE_FOR_truncsfqf2, to, from, UNKNOWN);
return;
}
#endif
#ifdef HAVE_truncdfqf2
if (HAVE_truncdfqf2 && from_mode == DFmode && to_mode == QFmode)
{
emit_unop_insn (CODE_FOR_truncdfqf2, to, from, UNKNOWN);
return;
}
#endif
#ifdef HAVE_truncxfqf2
if (HAVE_truncxfqf2 && from_mode == XFmode && to_mode == QFmode)
{
emit_unop_insn (CODE_FOR_truncxfqf2, to, from, UNKNOWN);
return;
}
#endif
#ifdef HAVE_trunctfqf2
if (HAVE_trunctfqf2 && from_mode == TFmode && to_mode == QFmode)
{
emit_unop_insn (CODE_FOR_trunctfqf2, to, from, UNKNOWN);
return;
}
#endif
#ifdef HAVE_trunctqfhf2
if (HAVE_trunctqfhf2 && from_mode == TQFmode && to_mode == HFmode)
{
emit_unop_insn (CODE_FOR_trunctqfhf2, to, from, UNKNOWN);
return;
}
#endif
#ifdef HAVE_truncsfhf2
if (HAVE_truncsfhf2 && from_mode == SFmode && to_mode == HFmode)
{
emit_unop_insn (CODE_FOR_truncsfhf2, to, from, UNKNOWN);
return;
}
#endif
#ifdef HAVE_truncdfhf2
if (HAVE_truncdfhf2 && from_mode == DFmode && to_mode == HFmode)
{
emit_unop_insn (CODE_FOR_truncdfhf2, to, from, UNKNOWN);
return;
}
#endif
#ifdef HAVE_truncxfhf2
if (HAVE_truncxfhf2 && from_mode == XFmode && to_mode == HFmode)
{
emit_unop_insn (CODE_FOR_truncxfhf2, to, from, UNKNOWN);
return;
}
#endif
#ifdef HAVE_trunctfhf2
if (HAVE_trunctfhf2 && from_mode == TFmode && to_mode == HFmode)
{
emit_unop_insn (CODE_FOR_trunctfhf2, to, from, UNKNOWN);
return;
}
#endif
#ifdef HAVE_truncsftqf2
if (HAVE_truncsftqf2 && from_mode == SFmode && to_mode == TQFmode)
{
emit_unop_insn (CODE_FOR_truncsftqf2, to, from, UNKNOWN);
return;
}
#endif
#ifdef HAVE_truncdftqf2
if (HAVE_truncdftqf2 && from_mode == DFmode && to_mode == TQFmode)
{
emit_unop_insn (CODE_FOR_truncdftqf2, to, from, UNKNOWN);
return;
}
#endif
#ifdef HAVE_truncxftqf2
if (HAVE_truncxftqf2 && from_mode == XFmode && to_mode == TQFmode)
{
emit_unop_insn (CODE_FOR_truncxftqf2, to, from, UNKNOWN);
return;
}
#endif
#ifdef HAVE_trunctftqf2
if (HAVE_trunctftqf2 && from_mode == TFmode && to_mode == TQFmode)
{
emit_unop_insn (CODE_FOR_trunctftqf2, to, from, UNKNOWN);
return;
}
#endif
#ifdef HAVE_truncdfsf2
if (HAVE_truncdfsf2 && from_mode == DFmode && to_mode == SFmode)
{
emit_unop_insn (CODE_FOR_truncdfsf2, to, from, UNKNOWN);
return;
}
#endif
#ifdef HAVE_truncxfsf2
if (HAVE_truncxfsf2 && from_mode == XFmode && to_mode == SFmode)
{
emit_unop_insn (CODE_FOR_truncxfsf2, to, from, UNKNOWN);
return;
}
#endif
#ifdef HAVE_trunctfsf2
if (HAVE_trunctfsf2 && from_mode == TFmode && to_mode == SFmode)
{
emit_unop_insn (CODE_FOR_trunctfsf2, to, from, UNKNOWN);
return;
}
#endif
#ifdef HAVE_truncxfdf2
if (HAVE_truncxfdf2 && from_mode == XFmode && to_mode == DFmode)
{
emit_unop_insn (CODE_FOR_truncxfdf2, to, from, UNKNOWN);
return;
}
#endif
#ifdef HAVE_trunctfdf2
if (HAVE_trunctfdf2 && from_mode == TFmode && to_mode == DFmode)
{
emit_unop_insn (CODE_FOR_trunctfdf2, to, from, UNKNOWN);
return;
}
#endif
libcall = (rtx) 0;
switch (from_mode)
{
case SFmode:
switch (to_mode)
{
case DFmode:
libcall = extendsfdf2_libfunc;
break;
case XFmode:
libcall = extendsfxf2_libfunc;
break;
case TFmode:
libcall = extendsftf2_libfunc;
break;
default:
break;
}
break;
case DFmode:
switch (to_mode)
{
case SFmode:
libcall = truncdfsf2_libfunc;
break;
case XFmode:
libcall = extenddfxf2_libfunc;
break;
case TFmode:
libcall = extenddftf2_libfunc;
break;
default:
break;
}
break;
case XFmode:
switch (to_mode)
{
case SFmode:
libcall = truncxfsf2_libfunc;
break;
case DFmode:
libcall = truncxfdf2_libfunc;
break;
default:
break;
}
break;
case TFmode:
switch (to_mode)
{
case SFmode:
libcall = trunctfsf2_libfunc;
break;
case DFmode:
libcall = trunctfdf2_libfunc;
break;
default:
break;
}
break;
default:
break;
}
if (libcall == (rtx) 0)
abort ();
start_sequence ();
value = emit_library_call_value (libcall, NULL_RTX, LCT_CONST, to_mode,
1, from, from_mode);
insns = get_insns ();
end_sequence ();
emit_libcall_block (insns, to, value, gen_rtx_FLOAT_TRUNCATE (to_mode,
from));
return;
}
if (GET_MODE_BITSIZE (from_mode) < GET_MODE_BITSIZE (to_mode)
&& GET_MODE_BITSIZE (to_mode) > BITS_PER_WORD)
{
rtx insns;
rtx lowpart;
rtx fill_value;
rtx lowfrom;
int i;
enum machine_mode lowpart_mode;
int nwords = CEIL (GET_MODE_SIZE (to_mode), UNITS_PER_WORD);
if ((code = can_extend_p (to_mode, from_mode, unsignedp))
!= CODE_FOR_nothing)
{
if (optimize > 0 && GET_CODE (from) == SUBREG)
from = force_reg (from_mode, from);
emit_unop_insn (code, to, from, equiv_code);
return;
}
else if (GET_MODE_BITSIZE (from_mode) < BITS_PER_WORD
&& ((code = can_extend_p (to_mode, word_mode, unsignedp))
!= CODE_FOR_nothing))
{
if (GET_CODE (to) == REG)
emit_insn (gen_rtx_CLOBBER (VOIDmode, to));
convert_move (gen_lowpart (word_mode, to), from, unsignedp);
emit_unop_insn (code, to,
gen_lowpart (word_mode, to), equiv_code);
return;
}
start_sequence ();
if (reg_overlap_mentioned_p (to, from))
from = force_reg (from_mode, from);
if (GET_MODE_BITSIZE (from_mode) < BITS_PER_WORD)
lowpart_mode = word_mode;
else
lowpart_mode = from_mode;
lowfrom = convert_to_mode (lowpart_mode, from, unsignedp);
lowpart = gen_lowpart (lowpart_mode, to);
emit_move_insn (lowpart, lowfrom);
if (unsignedp)
fill_value = const0_rtx;
else
{
#ifdef HAVE_slt
if (HAVE_slt
&& insn_data[(int) CODE_FOR_slt].operand[0].mode == word_mode
&& STORE_FLAG_VALUE == -1)
{
emit_cmp_insn (lowfrom, const0_rtx, NE, NULL_RTX,
lowpart_mode, 0);
fill_value = gen_reg_rtx (word_mode);
emit_insn (gen_slt (fill_value));
}
else
#endif
{
fill_value
= expand_shift (RSHIFT_EXPR, lowpart_mode, lowfrom,
size_int (GET_MODE_BITSIZE (lowpart_mode) - 1),
NULL_RTX, 0);
fill_value = convert_to_mode (word_mode, fill_value, 1);
}
}
for (i = GET_MODE_SIZE (lowpart_mode) / UNITS_PER_WORD; i < nwords; i++)
{
int index = (WORDS_BIG_ENDIAN ? nwords - i - 1 : i);
rtx subword = operand_subword (to, index, 1, to_mode);
if (subword == 0)
abort ();
if (fill_value != subword)
emit_move_insn (subword, fill_value);
}
insns = get_insns ();
end_sequence ();
emit_no_conflict_block (insns, to, from, NULL_RTX,
gen_rtx_fmt_e (equiv_code, to_mode, copy_rtx (from)));
return;
}
if (GET_MODE_BITSIZE (from_mode) > BITS_PER_WORD
&& GET_MODE_BITSIZE (to_mode) <= BITS_PER_WORD)
{
if (!((GET_CODE (from) == MEM
&& ! MEM_VOLATILE_P (from)
&& direct_load[(int) to_mode]
&& ! mode_dependent_address_p (XEXP (from, 0)))
|| GET_CODE (from) == REG
|| GET_CODE (from) == SUBREG))
from = force_reg (from_mode, from);
convert_move (to, gen_lowpart (word_mode, from), 0);
return;
}
if (to_mode == PQImode)
{
if (from_mode != QImode)
from = convert_to_mode (QImode, from, unsignedp);
#ifdef HAVE_truncqipqi2
if (HAVE_truncqipqi2)
{
emit_unop_insn (CODE_FOR_truncqipqi2, to, from, UNKNOWN);
return;
}
#endif
abort ();
}
if (from_mode == PQImode)
{
if (to_mode != QImode)
{
from = convert_to_mode (QImode, from, unsignedp);
from_mode = QImode;
}
else
{
#ifdef HAVE_extendpqiqi2
if (HAVE_extendpqiqi2)
{
emit_unop_insn (CODE_FOR_extendpqiqi2, to, from, UNKNOWN);
return;
}
#endif
abort ();
}
}
if (to_mode == PSImode)
{
if (from_mode != SImode)
from = convert_to_mode (SImode, from, unsignedp);
#ifdef HAVE_truncsipsi2
if (HAVE_truncsipsi2)
{
emit_unop_insn (CODE_FOR_truncsipsi2, to, from, UNKNOWN);
return;
}
#endif
abort ();
}
if (from_mode == PSImode)
{
if (to_mode != SImode)
{
from = convert_to_mode (SImode, from, unsignedp);
from_mode = SImode;
}
else
{
#ifdef HAVE_extendpsisi2
if (! unsignedp && HAVE_extendpsisi2)
{
emit_unop_insn (CODE_FOR_extendpsisi2, to, from, UNKNOWN);
return;
}
#endif
#ifdef HAVE_zero_extendpsisi2
if (unsignedp && HAVE_zero_extendpsisi2)
{
emit_unop_insn (CODE_FOR_zero_extendpsisi2, to, from, UNKNOWN);
return;
}
#endif
abort ();
}
}
if (to_mode == PDImode)
{
if (from_mode != DImode)
from = convert_to_mode (DImode, from, unsignedp);
#ifdef HAVE_truncdipdi2
if (HAVE_truncdipdi2)
{
emit_unop_insn (CODE_FOR_truncdipdi2, to, from, UNKNOWN);
return;
}
#endif
abort ();
}
if (from_mode == PDImode)
{
if (to_mode != DImode)
{
from = convert_to_mode (DImode, from, unsignedp);
from_mode = DImode;
}
else
{
#ifdef HAVE_extendpdidi2
if (HAVE_extendpdidi2)
{
emit_unop_insn (CODE_FOR_extendpdidi2, to, from, UNKNOWN);
return;
}
#endif
abort ();
}
}
if (GET_MODE_BITSIZE (to_mode) < GET_MODE_BITSIZE (from_mode)
&& TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (to_mode),
GET_MODE_BITSIZE (from_mode)))
{
if (!((GET_CODE (from) == MEM
&& ! MEM_VOLATILE_P (from)
&& direct_load[(int) to_mode]
&& ! mode_dependent_address_p (XEXP (from, 0)))
|| GET_CODE (from) == REG
|| GET_CODE (from) == SUBREG))
from = force_reg (from_mode, from);
if (GET_CODE (from) == REG && REGNO (from) < FIRST_PSEUDO_REGISTER
&& ! HARD_REGNO_MODE_OK (REGNO (from), to_mode))
from = copy_to_reg (from);
emit_move_insn (to, gen_lowpart (to_mode, from));
return;
}
if (GET_MODE_BITSIZE (to_mode) > GET_MODE_BITSIZE (from_mode))
{
if ((code = can_extend_p (to_mode, from_mode, unsignedp))
!= CODE_FOR_nothing)
{
if (flag_force_mem)
from = force_not_mem (from);
emit_unop_insn (code, to, from, equiv_code);
return;
}
else
{
enum machine_mode intermediate;
rtx tmp;
tree shift_amount;
for (intermediate = from_mode; intermediate != VOIDmode;
intermediate = GET_MODE_WIDER_MODE (intermediate))
if (((can_extend_p (to_mode, intermediate, unsignedp)
!= CODE_FOR_nothing)
|| (GET_MODE_SIZE (to_mode) < GET_MODE_SIZE (intermediate)
&& TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (to_mode),
GET_MODE_BITSIZE (intermediate))))
&& (can_extend_p (intermediate, from_mode, unsignedp)
!= CODE_FOR_nothing))
{
convert_move (to, convert_to_mode (intermediate, from,
unsignedp), unsignedp);
return;
}
shift_amount = build_int_2 (GET_MODE_BITSIZE (to_mode)
- GET_MODE_BITSIZE (from_mode), 0);
from = gen_lowpart (to_mode, force_reg (from_mode, from));
tmp = expand_shift (LSHIFT_EXPR, to_mode, from, shift_amount,
to, unsignedp);
tmp = expand_shift (RSHIFT_EXPR, to_mode, tmp, shift_amount,
to, unsignedp);
if (tmp != to)
emit_move_insn (to, tmp);
return;
}
}
if (from_mode == DImode && to_mode == SImode)
{
#ifdef HAVE_truncdisi2
if (HAVE_truncdisi2)
{
emit_unop_insn (CODE_FOR_truncdisi2, to, from, UNKNOWN);
return;
}
#endif
convert_move (to, force_reg (from_mode, from), unsignedp);
return;
}
if (from_mode == DImode && to_mode == HImode)
{
#ifdef HAVE_truncdihi2
if (HAVE_truncdihi2)
{
emit_unop_insn (CODE_FOR_truncdihi2, to, from, UNKNOWN);
return;
}
#endif
convert_move (to, force_reg (from_mode, from), unsignedp);
return;
}
if (from_mode == DImode && to_mode == QImode)
{
#ifdef HAVE_truncdiqi2
if (HAVE_truncdiqi2)
{
emit_unop_insn (CODE_FOR_truncdiqi2, to, from, UNKNOWN);
return;
}
#endif
convert_move (to, force_reg (from_mode, from), unsignedp);
return;
}
if (from_mode == SImode && to_mode == HImode)
{
#ifdef HAVE_truncsihi2
if (HAVE_truncsihi2)
{
emit_unop_insn (CODE_FOR_truncsihi2, to, from, UNKNOWN);
return;
}
#endif
convert_move (to, force_reg (from_mode, from), unsignedp);
return;
}
if (from_mode == SImode && to_mode == QImode)
{
#ifdef HAVE_truncsiqi2
if (HAVE_truncsiqi2)
{
emit_unop_insn (CODE_FOR_truncsiqi2, to, from, UNKNOWN);
return;
}
#endif
convert_move (to, force_reg (from_mode, from), unsignedp);
return;
}
if (from_mode == HImode && to_mode == QImode)
{
#ifdef HAVE_trunchiqi2
if (HAVE_trunchiqi2)
{
emit_unop_insn (CODE_FOR_trunchiqi2, to, from, UNKNOWN);
return;
}
#endif
convert_move (to, force_reg (from_mode, from), unsignedp);
return;
}
if (from_mode == TImode && to_mode == DImode)
{
#ifdef HAVE_trunctidi2
if (HAVE_trunctidi2)
{
emit_unop_insn (CODE_FOR_trunctidi2, to, from, UNKNOWN);
return;
}
#endif
convert_move (to, force_reg (from_mode, from), unsignedp);
return;
}
if (from_mode == TImode && to_mode == SImode)
{
#ifdef HAVE_trunctisi2
if (HAVE_trunctisi2)
{
emit_unop_insn (CODE_FOR_trunctisi2, to, from, UNKNOWN);
return;
}
#endif
convert_move (to, force_reg (from_mode, from), unsignedp);
return;
}
if (from_mode == TImode && to_mode == HImode)
{
#ifdef HAVE_trunctihi2
if (HAVE_trunctihi2)
{
emit_unop_insn (CODE_FOR_trunctihi2, to, from, UNKNOWN);
return;
}
#endif
convert_move (to, force_reg (from_mode, from), unsignedp);
return;
}
if (from_mode == TImode && to_mode == QImode)
{
#ifdef HAVE_trunctiqi2
if (HAVE_trunctiqi2)
{
emit_unop_insn (CODE_FOR_trunctiqi2, to, from, UNKNOWN);
return;
}
#endif
convert_move (to, force_reg (from_mode, from), unsignedp);
return;
}
if (GET_MODE_BITSIZE (to_mode) < GET_MODE_BITSIZE (from_mode))
{
rtx temp = force_reg (to_mode, gen_lowpart (to_mode, from));
emit_move_insn (to, temp);
return;
}
abort ();
}
rtx
convert_to_mode (mode, x, unsignedp)
enum machine_mode mode;
rtx x;
int unsignedp;
{
return convert_modes (mode, VOIDmode, x, unsignedp);
}
rtx
convert_modes (mode, oldmode, x, unsignedp)
enum machine_mode mode, oldmode;
rtx x;
int unsignedp;
{
rtx temp;
if (GET_CODE (x) == SUBREG && SUBREG_PROMOTED_VAR_P (x)
&& GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))) >= GET_MODE_SIZE (mode)
&& SUBREG_PROMOTED_UNSIGNED_P (x) == unsignedp)
x = gen_lowpart (mode, x);
if (GET_MODE (x) != VOIDmode)
oldmode = GET_MODE (x);
if (mode == oldmode)
return x;
if (unsignedp && GET_MODE_CLASS (mode) == MODE_INT
&& GET_MODE_BITSIZE (mode) == 2 * HOST_BITS_PER_WIDE_INT
&& GET_CODE (x) == CONST_INT && INTVAL (x) < 0)
{
HOST_WIDE_INT val = INTVAL (x);
if (oldmode != VOIDmode
&& HOST_BITS_PER_WIDE_INT > GET_MODE_BITSIZE (oldmode))
{
int width = GET_MODE_BITSIZE (oldmode);
val &= ((HOST_WIDE_INT) 1 << width) - 1;
}
return immed_double_const (val, (HOST_WIDE_INT) 0, mode);
}
if ((GET_CODE (x) == CONST_INT
&& GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
|| (GET_MODE_CLASS (mode) == MODE_INT
&& GET_MODE_CLASS (oldmode) == MODE_INT
&& (GET_CODE (x) == CONST_DOUBLE
|| (GET_MODE_SIZE (mode) <= GET_MODE_SIZE (oldmode)
&& ((GET_CODE (x) == MEM && ! MEM_VOLATILE_P (x)
&& direct_load[(int) mode])
|| (GET_CODE (x) == REG
&& TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode),
GET_MODE_BITSIZE (GET_MODE (x)))))))))
{
if (GET_CODE (x) == CONST_INT && oldmode != VOIDmode
&& GET_MODE_SIZE (mode) > GET_MODE_SIZE (oldmode))
{
HOST_WIDE_INT val = INTVAL (x);
int width = GET_MODE_BITSIZE (oldmode);
val &= ((HOST_WIDE_INT) 1 << width) - 1;
if (! unsignedp
&& (val & ((HOST_WIDE_INT) 1 << (width - 1))))
val |= (HOST_WIDE_INT) (-1) << width;
return gen_int_mode (val, mode);
}
return gen_lowpart (mode, x);
}
temp = gen_reg_rtx (mode);
convert_move (temp, x, unsignedp);
return temp;
}
#ifndef MOVE_MAX_PIECES
#define MOVE_MAX_PIECES MOVE_MAX
#endif
#define STORE_MAX_PIECES MIN (MOVE_MAX_PIECES, 2 * sizeof (HOST_WIDE_INT))
void
move_by_pieces (to, from, len, align)
rtx to, from;
unsigned HOST_WIDE_INT len;
unsigned int align;
{
struct move_by_pieces data;
rtx to_addr, from_addr = XEXP (from, 0);
unsigned int max_size = MOVE_MAX_PIECES + 1;
enum machine_mode mode = VOIDmode, tmode;
enum insn_code icode;
data.offset = 0;
data.from_addr = from_addr;
if (to)
{
to_addr = XEXP (to, 0);
data.to = to;
data.autinc_to
= (GET_CODE (to_addr) == PRE_INC || GET_CODE (to_addr) == PRE_DEC
|| GET_CODE (to_addr) == POST_INC || GET_CODE (to_addr) == POST_DEC);
data.reverse
= (GET_CODE (to_addr) == PRE_DEC || GET_CODE (to_addr) == POST_DEC);
}
else
{
to_addr = NULL_RTX;
data.to = NULL_RTX;
data.autinc_to = 1;
#ifdef STACK_GROWS_DOWNWARD
data.reverse = 1;
#else
data.reverse = 0;
#endif
}
data.to_addr = to_addr;
data.from = from;
data.autinc_from
= (GET_CODE (from_addr) == PRE_INC || GET_CODE (from_addr) == PRE_DEC
|| GET_CODE (from_addr) == POST_INC
|| GET_CODE (from_addr) == POST_DEC);
data.explicit_inc_from = 0;
data.explicit_inc_to = 0;
if (data.reverse) data.offset = len;
data.len = len;
if (!(data.autinc_from && data.autinc_to)
&& move_by_pieces_ninsns (len, align) > 2)
{
for (tmode = GET_CLASS_NARROWEST_MODE (MODE_INT);
tmode != VOIDmode; tmode = GET_MODE_WIDER_MODE (tmode))
if (GET_MODE_SIZE (tmode) < max_size)
mode = tmode;
if (USE_LOAD_PRE_DECREMENT (mode) && data.reverse && ! data.autinc_from)
{
data.from_addr = copy_addr_to_reg (plus_constant (from_addr, len));
data.autinc_from = 1;
data.explicit_inc_from = -1;
}
if (USE_LOAD_POST_INCREMENT (mode) && ! data.autinc_from)
{
data.from_addr = copy_addr_to_reg (from_addr);
data.autinc_from = 1;
data.explicit_inc_from = 1;
}
if (!data.autinc_from && CONSTANT_P (from_addr))
data.from_addr = copy_addr_to_reg (from_addr);
if (USE_STORE_PRE_DECREMENT (mode) && data.reverse && ! data.autinc_to)
{
data.to_addr = copy_addr_to_reg (plus_constant (to_addr, len));
data.autinc_to = 1;
data.explicit_inc_to = -1;
}
if (USE_STORE_POST_INCREMENT (mode) && ! data.reverse && ! data.autinc_to)
{
data.to_addr = copy_addr_to_reg (to_addr);
data.autinc_to = 1;
data.explicit_inc_to = 1;
}
if (!data.autinc_to && CONSTANT_P (to_addr))
data.to_addr = copy_addr_to_reg (to_addr);
}
if (! SLOW_UNALIGNED_ACCESS (word_mode, align)
|| align > MOVE_MAX * BITS_PER_UNIT || align >= BIGGEST_ALIGNMENT)
align = MOVE_MAX * BITS_PER_UNIT;
while (max_size > 1)
{
for (tmode = GET_CLASS_NARROWEST_MODE (MODE_INT);
tmode != VOIDmode; tmode = GET_MODE_WIDER_MODE (tmode))
if (GET_MODE_SIZE (tmode) < max_size)
mode = tmode;
if (mode == VOIDmode)
break;
icode = mov_optab->handlers[(int) mode].insn_code;
if (icode != CODE_FOR_nothing && align >= GET_MODE_ALIGNMENT (mode))
move_by_pieces_1 (GEN_FCN (icode), mode, &data);
max_size = GET_MODE_SIZE (mode);
}
if (data.len > 0)
abort ();
}
static unsigned HOST_WIDE_INT
move_by_pieces_ninsns (l, align)
unsigned HOST_WIDE_INT l;
unsigned int align;
{
unsigned HOST_WIDE_INT n_insns = 0;
unsigned HOST_WIDE_INT max_size = MOVE_MAX + 1;
if (! SLOW_UNALIGNED_ACCESS (word_mode, align)
|| align > MOVE_MAX * BITS_PER_UNIT || align >= BIGGEST_ALIGNMENT)
align = MOVE_MAX * BITS_PER_UNIT;
while (max_size > 1)
{
enum machine_mode mode = VOIDmode, tmode;
enum insn_code icode;
for (tmode = GET_CLASS_NARROWEST_MODE (MODE_INT);
tmode != VOIDmode; tmode = GET_MODE_WIDER_MODE (tmode))
if (GET_MODE_SIZE (tmode) < max_size)
mode = tmode;
if (mode == VOIDmode)
break;
icode = mov_optab->handlers[(int) mode].insn_code;
if (icode != CODE_FOR_nothing && align >= GET_MODE_ALIGNMENT (mode))
n_insns += l / GET_MODE_SIZE (mode), l %= GET_MODE_SIZE (mode);
max_size = GET_MODE_SIZE (mode);
}
if (l)
abort ();
return n_insns;
}
static void
move_by_pieces_1 (genfun, mode, data)
rtx (*genfun) PARAMS ((rtx, ...));
enum machine_mode mode;
struct move_by_pieces *data;
{
unsigned int size = GET_MODE_SIZE (mode);
rtx to1 = NULL_RTX, from1;
while (data->len >= size)
{
if (data->reverse)
data->offset -= size;
if (data->to)
{
if (data->autinc_to)
to1 = adjust_automodify_address (data->to, mode, data->to_addr,
data->offset);
else
to1 = adjust_address (data->to, mode, data->offset);
}
if (data->autinc_from)
from1 = adjust_automodify_address (data->from, mode, data->from_addr,
data->offset);
else
from1 = adjust_address (data->from, mode, data->offset);
if (HAVE_PRE_DECREMENT && data->explicit_inc_to < 0)
emit_insn (gen_add2_insn (data->to_addr,
GEN_INT (-(HOST_WIDE_INT)size)));
if (HAVE_PRE_DECREMENT && data->explicit_inc_from < 0)
emit_insn (gen_add2_insn (data->from_addr,
GEN_INT (-(HOST_WIDE_INT)size)));
if (data->to)
emit_insn ((*genfun) (to1, from1));
else
{
#ifdef PUSH_ROUNDING
emit_single_push_insn (mode, from1, NULL);
#else
abort ();
#endif
}
if (HAVE_POST_INCREMENT && data->explicit_inc_to > 0)
emit_insn (gen_add2_insn (data->to_addr, GEN_INT (size)));
if (HAVE_POST_INCREMENT && data->explicit_inc_from > 0)
emit_insn (gen_add2_insn (data->from_addr, GEN_INT (size)));
if (! data->reverse)
data->offset += size;
data->len -= size;
}
}
rtx
emit_block_move (x, y, size, method)
rtx x, y, size;
enum block_op_methods method;
{
bool may_use_call;
rtx retval = 0;
unsigned int align;
switch (method)
{
case BLOCK_OP_NORMAL:
may_use_call = true;
break;
case BLOCK_OP_CALL_PARM:
may_use_call = block_move_libcall_safe_for_call_parm ();
NO_DEFER_POP;
break;
case BLOCK_OP_NO_LIBCALL:
may_use_call = false;
break;
default:
abort ();
}
align = MIN (MEM_ALIGN (x), MEM_ALIGN (y));
if (GET_MODE (x) != BLKmode)
abort ();
if (GET_MODE (y) != BLKmode)
abort ();
x = protect_from_queue (x, 1);
y = protect_from_queue (y, 0);
size = protect_from_queue (size, 0);
if (GET_CODE (x) != MEM)
abort ();
if (GET_CODE (y) != MEM)
abort ();
if (size == 0)
abort ();
if (GET_CODE (size) == CONST_INT)
{
x = shallow_copy_rtx (x);
y = shallow_copy_rtx (y);
set_mem_size (x, size);
set_mem_size (y, size);
}
if (GET_CODE (size) == CONST_INT && MOVE_BY_PIECES_P (INTVAL (size), align))
move_by_pieces (x, y, INTVAL (size), align);
else if (emit_block_move_via_movstr (x, y, size, align))
;
else if (may_use_call)
retval = emit_block_move_via_libcall (x, y, size);
else
emit_block_move_via_loop (x, y, size, align);
if (method == BLOCK_OP_CALL_PARM)
OK_DEFER_POP;
return retval;
}
static bool
block_move_libcall_safe_for_call_parm ()
{
if (PUSH_ARGS)
return true;
else
{
static enum {
takes_regs_uninit, takes_regs_no, takes_regs_yes
} takes_regs = takes_regs_uninit;
switch (takes_regs)
{
case takes_regs_uninit:
{
CUMULATIVE_ARGS args_so_far;
tree fn, arg;
fn = emit_block_move_libcall_fn (false);
INIT_CUMULATIVE_ARGS (args_so_far, TREE_TYPE (fn), NULL_RTX, 0);
arg = TYPE_ARG_TYPES (TREE_TYPE (fn));
for ( ; arg != void_list_node ; arg = TREE_CHAIN (arg))
{
enum machine_mode mode = TYPE_MODE (TREE_VALUE (arg));
rtx tmp = FUNCTION_ARG (args_so_far, mode, NULL_TREE, 1);
if (!tmp || !REG_P (tmp))
goto fail_takes_regs;
#ifdef FUNCTION_ARG_PARTIAL_NREGS
if (FUNCTION_ARG_PARTIAL_NREGS (args_so_far, mode,
NULL_TREE, 1))
goto fail_takes_regs;
#endif
FUNCTION_ARG_ADVANCE (args_so_far, mode, NULL_TREE, 1);
}
}
takes_regs = takes_regs_yes;
case takes_regs_yes:
return true;
fail_takes_regs:
takes_regs = takes_regs_no;
case takes_regs_no:
return false;
default:
abort ();
}
}
}
static bool
emit_block_move_via_movstr (x, y, size, align)
rtx x, y, size;
unsigned int align;
{
rtx opalign = GEN_INT (align / BITS_PER_UNIT);
enum machine_mode mode;
volatile_ok = 1;
for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); mode != VOIDmode;
mode = GET_MODE_WIDER_MODE (mode))
{
enum insn_code code = movstr_optab[(int) mode];
insn_operand_predicate_fn pred;
if (code != CODE_FOR_nothing
&& ((GET_CODE (size) == CONST_INT
&& ((unsigned HOST_WIDE_INT) INTVAL (size)
<= (GET_MODE_MASK (mode) >> 1)))
|| GET_MODE_BITSIZE (mode) >= BITS_PER_WORD)
&& ((pred = insn_data[(int) code].operand[0].predicate) == 0
|| (*pred) (x, BLKmode))
&& ((pred = insn_data[(int) code].operand[1].predicate) == 0
|| (*pred) (y, BLKmode))
&& ((pred = insn_data[(int) code].operand[3].predicate) == 0
|| (*pred) (opalign, VOIDmode)))
{
rtx op2;
rtx last = get_last_insn ();
rtx pat;
op2 = convert_to_mode (mode, size, 1);
pred = insn_data[(int) code].operand[2].predicate;
if (pred != 0 && ! (*pred) (op2, mode))
op2 = copy_to_mode_reg (mode, op2);
pat = GEN_FCN ((int) code) (x, y, op2, opalign);
if (pat)
{
emit_insn (pat);
volatile_ok = 0;
return true;
}
else
delete_insns_since (last);
}
}
volatile_ok = 0;
return false;
}
static rtx
emit_block_move_via_libcall (dst, src, size)
rtx dst, src, size;
{
tree call_expr, arg_list, fn, src_tree, dst_tree, size_tree;
enum machine_mode size_mode;
rtx retval;
dst = copy_to_mode_reg (Pmode, XEXP (dst, 0));
src = copy_to_mode_reg (Pmode, XEXP (src, 0));
if (TARGET_MEM_FUNCTIONS)
size_mode = TYPE_MODE (sizetype);
else
size_mode = TYPE_MODE (unsigned_type_node);
size = convert_to_mode (size_mode, size, 1);
size = copy_to_mode_reg (size_mode, size);
dst_tree = make_tree (ptr_type_node, dst);
src_tree = make_tree (ptr_type_node, src);
if (TARGET_MEM_FUNCTIONS)
size_tree = make_tree (sizetype, size);
else
size_tree = make_tree (unsigned_type_node, size);
fn = emit_block_move_libcall_fn (true);
arg_list = tree_cons (NULL_TREE, size_tree, NULL_TREE);
if (TARGET_MEM_FUNCTIONS)
{
arg_list = tree_cons (NULL_TREE, src_tree, arg_list);
arg_list = tree_cons (NULL_TREE, dst_tree, arg_list);
}
else
{
arg_list = tree_cons (NULL_TREE, dst_tree, arg_list);
arg_list = tree_cons (NULL_TREE, src_tree, arg_list);
}
call_expr = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (fn)), fn);
call_expr = build (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)),
call_expr, arg_list, NULL_TREE);
TREE_SIDE_EFFECTS (call_expr) = 1;
retval = expand_expr (call_expr, NULL_RTX, VOIDmode, 0);
if (RTX_UNCHANGING_P (dst))
emit_insn (gen_rtx_CLOBBER (VOIDmode, dst));
return (TARGET_MEM_FUNCTIONS ? retval : NULL_RTX);
}
static GTY(()) tree block_move_fn;
static tree
emit_block_move_libcall_fn (for_call)
int for_call;
{
static bool emitted_extern;
tree fn = block_move_fn, args;
if (!fn)
{
if (TARGET_MEM_FUNCTIONS)
{
fn = get_identifier ("memcpy");
args = build_function_type_list (ptr_type_node, ptr_type_node,
const_ptr_type_node, sizetype,
NULL_TREE);
}
else
{
fn = get_identifier ("bcopy");
args = build_function_type_list (void_type_node, const_ptr_type_node,
ptr_type_node, unsigned_type_node,
NULL_TREE);
}
fn = build_decl (FUNCTION_DECL, fn, args);
DECL_EXTERNAL (fn) = 1;
TREE_PUBLIC (fn) = 1;
DECL_ARTIFICIAL (fn) = 1;
TREE_NOTHROW (fn) = 1;
block_move_fn = fn;
}
if (for_call && !emitted_extern)
{
emitted_extern = true;
make_decl_rtl (fn, NULL);
assemble_external (fn);
}
return fn;
}
static void
emit_block_move_via_loop (x, y, size, align)
rtx x, y, size;
unsigned int align ATTRIBUTE_UNUSED;
{
rtx cmp_label, top_label, iter, x_addr, y_addr, tmp;
enum machine_mode iter_mode;
iter_mode = GET_MODE (size);
if (iter_mode == VOIDmode)
iter_mode = word_mode;
top_label = gen_label_rtx ();
cmp_label = gen_label_rtx ();
iter = gen_reg_rtx (iter_mode);
emit_move_insn (iter, const0_rtx);
x_addr = force_operand (XEXP (x, 0), NULL_RTX);
y_addr = force_operand (XEXP (y, 0), NULL_RTX);
do_pending_stack_adjust ();
emit_note (NULL, NOTE_INSN_LOOP_BEG);
emit_jump (cmp_label);
emit_label (top_label);
tmp = convert_modes (Pmode, iter_mode, iter, true);
x_addr = gen_rtx_PLUS (Pmode, x_addr, tmp);
y_addr = gen_rtx_PLUS (Pmode, y_addr, tmp);
x = change_address (x, QImode, x_addr);
y = change_address (y, QImode, y_addr);
emit_move_insn (x, y);
tmp = expand_simple_binop (iter_mode, PLUS, iter, const1_rtx, iter,
true, OPTAB_LIB_WIDEN);
if (tmp != iter)
emit_move_insn (iter, tmp);
emit_note (NULL, NOTE_INSN_LOOP_CONT);
emit_label (cmp_label);
emit_cmp_and_jump_insns (iter, size, LT, NULL_RTX, iter_mode,
true, top_label);
emit_note (NULL, NOTE_INSN_LOOP_END);
}
void
move_block_to_reg (regno, x, nregs, mode)
int regno;
rtx x;
int nregs;
enum machine_mode mode;
{
int i;
#ifdef HAVE_load_multiple
rtx pat;
rtx last;
#endif
if (nregs == 0)
return;
if (CONSTANT_P (x) && ! LEGITIMATE_CONSTANT_P (x))
x = validize_mem (force_const_mem (mode, x));
#ifdef HAVE_load_multiple
if (HAVE_load_multiple)
{
last = get_last_insn ();
pat = gen_load_multiple (gen_rtx_REG (word_mode, regno), x,
GEN_INT (nregs));
if (pat)
{
emit_insn (pat);
return;
}
else
delete_insns_since (last);
}
#endif
for (i = 0; i < nregs; i++)
emit_move_insn (gen_rtx_REG (ABI_WIDE_WORD_MODE(GET_MODE(x)), regno + i),
operand_subword_force (x, i, mode));
}
void
move_block_from_reg (regno, x, nregs, size)
int regno;
rtx x;
int nregs;
int size;
{
int i;
#ifdef HAVE_store_multiple
rtx pat;
rtx last;
#endif
enum machine_mode mode;
if (nregs == 0)
return;
if (size <= ABI_UNITS_PER_WORD
&& (mode = mode_for_size (size * BITS_PER_UNIT, MODE_INT, 0)) != BLKmode)
{
emit_move_insn (adjust_address (x, mode, 0), gen_rtx_REG (mode, regno));
return;
}
if (size < UNITS_PER_WORD && BYTES_BIG_ENDIAN)
{
rtx tem = operand_subword (x, 0, 1, BLKmode);
rtx shift;
if (tem == 0)
abort ();
shift = expand_shift (LSHIFT_EXPR, word_mode,
gen_rtx_REG (word_mode, regno),
build_int_2 ((UNITS_PER_WORD - size)
* BITS_PER_UNIT, 0), NULL_RTX, 0);
emit_move_insn (tem, shift);
return;
}
#ifdef HAVE_store_multiple
if (HAVE_store_multiple)
{
last = get_last_insn ();
pat = gen_store_multiple (x, gen_rtx_REG (word_mode, regno),
GEN_INT (nregs));
if (pat)
{
emit_insn (pat);
return;
}
else
delete_insns_since (last);
}
#endif
for (i = 0; i < nregs; i++)
{
rtx tem = operand_subword (x, i, 1, BLKmode);
if (tem == 0)
abort ();
emit_move_insn (tem, gen_rtx_REG (ABI_WIDE_WORD_MODE(GET_MODE(tem)), regno + i));
}
}
rtx
gen_group_rtx (orig)
rtx orig;
{
int i, length;
rtx *tmps;
if (GET_CODE (orig) != PARALLEL)
abort ();
length = XVECLEN (orig, 0);
tmps = (rtx *) alloca (sizeof (rtx) * length);
i = XEXP (XVECEXP (orig, 0, 0), 0) ? 0 : 1;
if (i)
tmps[0] = 0;
for (; i < length; i++)
{
enum machine_mode mode = GET_MODE (XEXP (XVECEXP (orig, 0, i), 0));
rtx offset = XEXP (XVECEXP (orig, 0, i), 1);
tmps[i] = gen_rtx_EXPR_LIST (VOIDmode, gen_reg_rtx (mode), offset);
}
return gen_rtx_PARALLEL (GET_MODE (orig), gen_rtvec_v (length, tmps));
}
#ifndef ALWAYS_PUSH_CONSTS_USING_REGS_P
#define ALWAYS_PUSH_CONSTS_USING_REGS_P 0
#endif
void
emit_group_load (dst, orig_src, ssize)
rtx dst, orig_src;
int ssize;
{
rtx *tmps, src;
int start, i;
if (GET_CODE (dst) != PARALLEL)
abort ();
if (XEXP (XVECEXP (dst, 0, 0), 0))
start = 0;
else
start = 1;
tmps = (rtx *) alloca (sizeof (rtx) * XVECLEN (dst, 0));
for (i = start; i < XVECLEN (dst, 0); i++)
{
enum machine_mode mode = GET_MODE (XEXP (XVECEXP (dst, 0, i), 0));
HOST_WIDE_INT bytepos = INTVAL (XEXP (XVECEXP (dst, 0, i), 1));
unsigned int bytelen = GET_MODE_SIZE (mode);
int shift = 0;
if (ssize >= 0 && bytepos + (HOST_WIDE_INT) bytelen > ssize)
{
shift = (bytelen - (ssize - bytepos)) * BITS_PER_UNIT;
bytelen = ssize - bytepos;
if (bytelen <= 0)
abort ();
}
src = orig_src;
if (GET_CODE (orig_src) != MEM
&& (ALWAYS_PUSH_CONSTS_USING_REGS_P && GET_MODE(dst) != DImode || !CONSTANT_P (orig_src)
|| (GET_MODE (orig_src) != mode
&& GET_MODE (orig_src) != VOIDmode)))
{
if (GET_MODE (orig_src) == VOIDmode)
src = gen_reg_rtx (mode);
else
src = gen_reg_rtx (GET_MODE (orig_src));
emit_move_insn (src, orig_src);
}
if (GET_CODE (src) == MEM
&& MEM_ALIGN (src) >= GET_MODE_ALIGNMENT (mode)
&& bytepos * BITS_PER_UNIT % GET_MODE_ALIGNMENT (mode) == 0
&& bytelen == GET_MODE_SIZE (mode))
{
tmps[i] = gen_reg_rtx (mode);
emit_move_insn (tmps[i], adjust_address (src, mode, bytepos));
}
else if (GET_CODE (src) == CONCAT)
{
unsigned int slen = GET_MODE_SIZE (GET_MODE (src));
unsigned int slen0 = GET_MODE_SIZE (GET_MODE (XEXP (src, 0)));
if ((bytepos == 0 && bytelen == slen0)
|| (bytepos != 0 && bytepos + bytelen <= slen))
{
tmps[i] = XEXP (src, bytepos / slen0);
if (! CONSTANT_P (tmps[i])
&& (GET_CODE (tmps[i]) != REG || GET_MODE (tmps[i]) != mode))
tmps[i] = extract_bit_field (tmps[i], bytelen * BITS_PER_UNIT,
(bytepos % slen0) * BITS_PER_UNIT,
1, NULL_RTX, mode, mode, ssize);
}
else if (bytepos == 0)
{
rtx mem = assign_stack_temp (GET_MODE (src), slen, 0);
emit_move_insn (mem, src);
tmps[i] = adjust_address (mem, mode, 0);
}
else
abort ();
}
else if (CONSTANT_P (src) && GET_MODE(dst) == DImode)
tmps[i] = simplify_gen_subreg (mode, src, GET_MODE(dst), bytepos);
else if (CONSTANT_P (src)
|| (GET_CODE (src) == REG && GET_MODE (src) == mode))
tmps[i] = src;
else
tmps[i] = extract_bit_field (src, bytelen * BITS_PER_UNIT,
bytepos * BITS_PER_UNIT, 1, NULL_RTX,
mode, mode, ssize);
if (BYTES_BIG_ENDIAN && shift)
expand_binop (mode, ashl_optab, tmps[i], GEN_INT (shift),
tmps[i], 0, OPTAB_WIDEN);
}
emit_queue ();
for (i = start; i < XVECLEN (dst, 0); i++)
emit_move_insn (XEXP (XVECEXP (dst, 0, i), 0), tmps[i]);
}
void
emit_group_move (dst, src)
rtx dst, src;
{
int i;
if (GET_CODE (src) != PARALLEL
|| GET_CODE (dst) != PARALLEL
|| XVECLEN (src, 0) != XVECLEN (dst, 0))
abort ();
for (i = XEXP (XVECEXP (src, 0, 0), 0) ? 0 : 1; i < XVECLEN (src, 0); i++)
emit_move_insn (XEXP (XVECEXP (dst, 0, i), 0),
XEXP (XVECEXP (src, 0, i), 0));
}
void
emit_group_store (orig_dst, src, ssize)
rtx orig_dst, src;
int ssize;
{
rtx *tmps, dst;
int start, i;
if (GET_CODE (src) != PARALLEL)
abort ();
if (XEXP (XVECEXP (src, 0, 0), 0))
start = 0;
else
start = 1;
tmps = (rtx *) alloca (sizeof (rtx) * XVECLEN (src, 0));
for (i = start; i < XVECLEN (src, 0); i++)
{
rtx reg = XEXP (XVECEXP (src, 0, i), 0);
tmps[i] = gen_reg_rtx (GET_MODE (reg));
emit_move_insn (tmps[i], reg);
}
emit_queue ();
dst = orig_dst;
if (GET_CODE (dst) == PARALLEL)
{
rtx temp;
if (rtx_equal_p (dst, src))
return;
temp = assign_stack_temp (GET_MODE (dst), ssize, 0);
emit_group_store (temp, src, ssize);
emit_group_load (dst, temp, ssize);
return;
}
else if (GET_CODE (dst) != MEM && GET_CODE (dst) != CONCAT)
{
dst = gen_reg_rtx (GET_MODE (orig_dst));
emit_move_insn (dst, CONST0_RTX (GET_MODE (orig_dst)));
}
for (i = start; i < XVECLEN (src, 0); i++)
{
HOST_WIDE_INT bytepos = INTVAL (XEXP (XVECEXP (src, 0, i), 1));
enum machine_mode mode = GET_MODE (tmps[i]);
unsigned int bytelen = GET_MODE_SIZE (mode);
rtx dest = dst;
if (ssize >= 0 && bytepos + (HOST_WIDE_INT) bytelen > ssize)
{
if (BYTES_BIG_ENDIAN)
{
int shift = (bytelen - (ssize - bytepos)) * BITS_PER_UNIT;
expand_binop (mode, ashr_optab, tmps[i], GEN_INT (shift),
tmps[i], 0, OPTAB_WIDEN);
}
bytelen = ssize - bytepos;
}
if (GET_CODE (dst) == CONCAT)
{
if (bytepos + bytelen <= GET_MODE_SIZE (GET_MODE (XEXP (dst, 0))))
dest = XEXP (dst, 0);
else if (bytepos >= GET_MODE_SIZE (GET_MODE (XEXP (dst, 0))))
{
bytepos -= GET_MODE_SIZE (GET_MODE (XEXP (dst, 0)));
dest = XEXP (dst, 1);
}
else if (bytepos == 0 && XVECLEN (src, 0))
{
dest = assign_stack_temp (GET_MODE (dest),
GET_MODE_SIZE (GET_MODE (dest)), 0);
emit_move_insn (adjust_address (dest, GET_MODE (tmps[i]), bytepos),
tmps[i]);
dst = dest;
break;
}
else
abort ();
}
if (GET_CODE (dest) == MEM
&& MEM_ALIGN (dest) >= GET_MODE_ALIGNMENT (mode)
&& bytepos * BITS_PER_UNIT % GET_MODE_ALIGNMENT (mode) == 0
&& bytelen == GET_MODE_SIZE (mode))
emit_move_insn (adjust_address (dest, mode, bytepos), tmps[i]);
else
store_bit_field (dest, bytelen * BITS_PER_UNIT, bytepos * BITS_PER_UNIT,
mode, tmps[i], ssize);
}
emit_queue ();
if (orig_dst != dst)
emit_move_insn (orig_dst, dst);
}
rtx
copy_blkmode_from_reg (tgtblk, srcreg, type)
rtx tgtblk;
rtx srcreg;
tree type;
{
unsigned HOST_WIDE_INT bytes = int_size_in_bytes (type);
rtx src = NULL, dst = NULL;
unsigned HOST_WIDE_INT bitsize = MIN (TYPE_ALIGN (type), BITS_PER_WORD);
unsigned HOST_WIDE_INT bitpos, xbitpos, big_endian_correction = 0;
if (tgtblk == 0)
{
tgtblk = assign_temp (build_qualified_type (type,
(TYPE_QUALS (type)
| TYPE_QUAL_CONST)),
0, 1, 1);
preserve_temp_slots (tgtblk);
}
if (GET_MODE (srcreg) != BLKmode
&& GET_MODE_SIZE (GET_MODE (srcreg)) < UNITS_PER_WORD)
srcreg = convert_to_mode (word_mode, srcreg, TREE_UNSIGNED (type));
if (BYTES_BIG_ENDIAN
&& bytes % UNITS_PER_WORD)
big_endian_correction
= (BITS_PER_WORD - ((bytes % UNITS_PER_WORD) * BITS_PER_UNIT));
for (bitpos = 0, xbitpos = big_endian_correction;
bitpos < bytes * BITS_PER_UNIT;
bitpos += bitsize, xbitpos += bitsize)
{
if (xbitpos % BITS_PER_WORD == 0
|| xbitpos == big_endian_correction)
src = operand_subword_force (srcreg, xbitpos / BITS_PER_WORD,
GET_MODE (srcreg));
if (bitpos % BITS_PER_WORD == 0)
dst = operand_subword (tgtblk, bitpos / BITS_PER_WORD, 1, BLKmode);
store_bit_field (dst, bitsize, bitpos % BITS_PER_WORD, word_mode,
extract_bit_field (src, bitsize,
xbitpos % BITS_PER_WORD, 1,
NULL_RTX, word_mode, word_mode,
BITS_PER_WORD),
BITS_PER_WORD);
}
return tgtblk;
}
void
use_reg (call_fusage, reg)
rtx *call_fusage, reg;
{
if (GET_CODE (reg) != REG
|| REGNO (reg) >= FIRST_PSEUDO_REGISTER)
abort ();
*call_fusage
= gen_rtx_EXPR_LIST (VOIDmode,
gen_rtx_USE (VOIDmode, reg), *call_fusage);
}
void
use_regs (call_fusage, regno, nregs)
rtx *call_fusage;
int regno;
int nregs;
{
int i;
if (regno + nregs > FIRST_PSEUDO_REGISTER)
abort ();
for (i = 0; i < nregs; i++)
use_reg (call_fusage, regno_reg_rtx[regno + i]);
}
void
use_group_regs (call_fusage, regs)
rtx *call_fusage;
rtx regs;
{
int i;
for (i = 0; i < XVECLEN (regs, 0); i++)
{
rtx reg = XEXP (XVECEXP (regs, 0, i), 0);
if (reg != 0 && GET_CODE (reg) == REG)
use_reg (call_fusage, reg);
}
}
int
can_store_by_pieces (len, constfun, constfundata, align)
unsigned HOST_WIDE_INT len;
rtx (*constfun) PARAMS ((PTR, HOST_WIDE_INT, enum machine_mode));
PTR constfundata;
unsigned int align;
{
unsigned HOST_WIDE_INT max_size, l;
HOST_WIDE_INT offset = 0;
enum machine_mode mode, tmode;
enum insn_code icode;
int reverse;
rtx cst;
if (! MOVE_BY_PIECES_P (len, align))
return 0;
if (! SLOW_UNALIGNED_ACCESS (word_mode, align)
|| align > MOVE_MAX * BITS_PER_UNIT || align >= BIGGEST_ALIGNMENT)
align = MOVE_MAX * BITS_PER_UNIT;
for (reverse = 0;
reverse <= (HAVE_PRE_DECREMENT || HAVE_POST_DECREMENT);
reverse++)
{
l = len;
mode = VOIDmode;
max_size = STORE_MAX_PIECES + 1;
while (max_size > 1)
{
for (tmode = GET_CLASS_NARROWEST_MODE (MODE_INT);
tmode != VOIDmode; tmode = GET_MODE_WIDER_MODE (tmode))
if (GET_MODE_SIZE (tmode) < max_size)
mode = tmode;
if (mode == VOIDmode)
break;
icode = mov_optab->handlers[(int) mode].insn_code;
if (icode != CODE_FOR_nothing
&& align >= GET_MODE_ALIGNMENT (mode))
{
unsigned int size = GET_MODE_SIZE (mode);
while (l >= size)
{
if (reverse)
offset -= size;
cst = (*constfun) (constfundata, offset, mode);
if (!LEGITIMATE_CONSTANT_P (cst))
return 0;
if (!reverse)
offset += size;
l -= size;
}
}
max_size = GET_MODE_SIZE (mode);
}
if (l != 0)
abort ();
}
return 1;
}
void
store_by_pieces (to, len, constfun, constfundata, align)
rtx to;
unsigned HOST_WIDE_INT len;
rtx (*constfun) PARAMS ((PTR, HOST_WIDE_INT, enum machine_mode));
PTR constfundata;
unsigned int align;
{
struct store_by_pieces data;
if (! MOVE_BY_PIECES_P (len, align))
abort ();
to = protect_from_queue (to, 1);
data.constfun = constfun;
data.constfundata = constfundata;
data.len = len;
data.to = to;
store_by_pieces_1 (&data, align);
}
static void
clear_by_pieces (to, len, align)
rtx to;
unsigned HOST_WIDE_INT len;
unsigned int align;
{
struct store_by_pieces data;
data.constfun = clear_by_pieces_1;
data.constfundata = NULL;
data.len = len;
data.to = to;
store_by_pieces_1 (&data, align);
}
static rtx
clear_by_pieces_1 (data, offset, mode)
PTR data ATTRIBUTE_UNUSED;
HOST_WIDE_INT offset ATTRIBUTE_UNUSED;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
return const0_rtx;
}
static void
store_by_pieces_1 (data, align)
struct store_by_pieces *data;
unsigned int align;
{
rtx to_addr = XEXP (data->to, 0);
unsigned HOST_WIDE_INT max_size = STORE_MAX_PIECES + 1;
enum machine_mode mode = VOIDmode, tmode;
enum insn_code icode;
data->offset = 0;
data->to_addr = to_addr;
data->autinc_to
= (GET_CODE (to_addr) == PRE_INC || GET_CODE (to_addr) == PRE_DEC
|| GET_CODE (to_addr) == POST_INC || GET_CODE (to_addr) == POST_DEC);
data->explicit_inc_to = 0;
data->reverse
= (GET_CODE (to_addr) == PRE_DEC || GET_CODE (to_addr) == POST_DEC);
if (data->reverse)
data->offset = data->len;
if (!data->autinc_to
&& move_by_pieces_ninsns (data->len, align) > 2)
{
for (tmode = GET_CLASS_NARROWEST_MODE (MODE_INT);
tmode != VOIDmode; tmode = GET_MODE_WIDER_MODE (tmode))
if (GET_MODE_SIZE (tmode) < max_size)
mode = tmode;
if (USE_STORE_PRE_DECREMENT (mode) && data->reverse && ! data->autinc_to)
{
data->to_addr = copy_addr_to_reg (plus_constant (to_addr, data->len));
data->autinc_to = 1;
data->explicit_inc_to = -1;
}
if (USE_STORE_POST_INCREMENT (mode) && ! data->reverse
&& ! data->autinc_to)
{
data->to_addr = copy_addr_to_reg (to_addr);
data->autinc_to = 1;
data->explicit_inc_to = 1;
}
if ( !data->autinc_to && CONSTANT_P (to_addr))
data->to_addr = copy_addr_to_reg (to_addr);
}
if (! SLOW_UNALIGNED_ACCESS (word_mode, align)
|| align > MOVE_MAX * BITS_PER_UNIT || align >= BIGGEST_ALIGNMENT)
align = MOVE_MAX * BITS_PER_UNIT;
while (max_size > 1)
{
for (tmode = GET_CLASS_NARROWEST_MODE (MODE_INT);
tmode != VOIDmode; tmode = GET_MODE_WIDER_MODE (tmode))
if (GET_MODE_SIZE (tmode) < max_size)
mode = tmode;
if (mode == VOIDmode)
break;
icode = mov_optab->handlers[(int) mode].insn_code;
if (icode != CODE_FOR_nothing && align >= GET_MODE_ALIGNMENT (mode))
store_by_pieces_2 (GEN_FCN (icode), mode, data);
max_size = GET_MODE_SIZE (mode);
}
if (data->len != 0)
abort ();
}
static void
store_by_pieces_2 (genfun, mode, data)
rtx (*genfun) PARAMS ((rtx, ...));
enum machine_mode mode;
struct store_by_pieces *data;
{
unsigned int size = GET_MODE_SIZE (mode);
rtx to1, cst;
while (data->len >= size)
{
if (data->reverse)
data->offset -= size;
if (data->autinc_to)
to1 = adjust_automodify_address (data->to, mode, data->to_addr,
data->offset);
else
to1 = adjust_address (data->to, mode, data->offset);
if (HAVE_PRE_DECREMENT && data->explicit_inc_to < 0)
emit_insn (gen_add2_insn (data->to_addr,
GEN_INT (-(HOST_WIDE_INT) size)));
cst = (*data->constfun) (data->constfundata, data->offset, mode);
emit_insn ((*genfun) (to1, cst));
if (HAVE_POST_INCREMENT && data->explicit_inc_to > 0)
emit_insn (gen_add2_insn (data->to_addr, GEN_INT (size)));
if (! data->reverse)
data->offset += size;
data->len -= size;
}
}
rtx
clear_storage (object, size)
rtx object;
rtx size;
{
rtx retval = 0;
unsigned int align = (GET_CODE (object) == MEM ? MEM_ALIGN (object)
: GET_MODE_ALIGNMENT (GET_MODE (object)));
if (GET_MODE (object) != BLKmode
&& GET_CODE (size) == CONST_INT
&& INTVAL (size) == (HOST_WIDE_INT) GET_MODE_SIZE (GET_MODE (object)))
emit_move_insn (object, CONST0_RTX (GET_MODE (object)));
else
{
object = protect_from_queue (object, 1);
size = protect_from_queue (size, 0);
if (GET_CODE (size) == CONST_INT
&& CLEAR_BY_PIECES_P (INTVAL (size), align))
clear_by_pieces (object, INTVAL (size), align);
else if (clear_storage_via_clrstr (object, size, align))
;
else
retval = clear_storage_via_libcall (object, size);
}
return retval;
}
static bool
clear_storage_via_clrstr (object, size, align)
rtx object, size;
unsigned int align;
{
rtx opalign = GEN_INT (align / BITS_PER_UNIT);
enum machine_mode mode;
for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); mode != VOIDmode;
mode = GET_MODE_WIDER_MODE (mode))
{
enum insn_code code = clrstr_optab[(int) mode];
insn_operand_predicate_fn pred;
if (code != CODE_FOR_nothing
&& ((GET_CODE (size) == CONST_INT
&& ((unsigned HOST_WIDE_INT) INTVAL (size)
<= (GET_MODE_MASK (mode) >> 1)))
|| GET_MODE_BITSIZE (mode) >= BITS_PER_WORD)
&& ((pred = insn_data[(int) code].operand[0].predicate) == 0
|| (*pred) (object, BLKmode))
&& ((pred = insn_data[(int) code].operand[2].predicate) == 0
|| (*pred) (opalign, VOIDmode)))
{
rtx op1;
rtx last = get_last_insn ();
rtx pat;
op1 = convert_to_mode (mode, size, 1);
pred = insn_data[(int) code].operand[1].predicate;
if (pred != 0 && ! (*pred) (op1, mode))
op1 = copy_to_mode_reg (mode, op1);
pat = GEN_FCN ((int) code) (object, op1, opalign);
if (pat)
{
emit_insn (pat);
return true;
}
else
delete_insns_since (last);
}
}
return false;
}
static rtx
clear_storage_via_libcall (object, size)
rtx object, size;
{
tree call_expr, arg_list, fn, object_tree, size_tree;
enum machine_mode size_mode;
rtx retval;
object = copy_to_mode_reg (Pmode, XEXP (object, 0));
if (TARGET_MEM_FUNCTIONS)
size_mode = TYPE_MODE (sizetype);
else
size_mode = TYPE_MODE (unsigned_type_node);
size = convert_to_mode (size_mode, size, 1);
size = copy_to_mode_reg (size_mode, size);
object_tree = make_tree (ptr_type_node, object);
if (TARGET_MEM_FUNCTIONS)
size_tree = make_tree (sizetype, size);
else
size_tree = make_tree (unsigned_type_node, size);
fn = clear_storage_libcall_fn (true);
arg_list = tree_cons (NULL_TREE, size_tree, NULL_TREE);
if (TARGET_MEM_FUNCTIONS)
arg_list = tree_cons (NULL_TREE, integer_zero_node, arg_list);
arg_list = tree_cons (NULL_TREE, object_tree, arg_list);
call_expr = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (fn)), fn);
call_expr = build (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)),
call_expr, arg_list, NULL_TREE);
TREE_SIDE_EFFECTS (call_expr) = 1;
retval = expand_expr (call_expr, NULL_RTX, VOIDmode, 0);
if (RTX_UNCHANGING_P (object))
emit_insn (gen_rtx_CLOBBER (VOIDmode, object));
return (TARGET_MEM_FUNCTIONS ? retval : NULL_RTX);
}
static GTY(()) tree block_clear_fn;
static tree
clear_storage_libcall_fn (for_call)
int for_call;
{
static bool emitted_extern;
tree fn = block_clear_fn, args;
if (!fn)
{
if (TARGET_MEM_FUNCTIONS)
{
fn = get_identifier ("memset");
args = build_function_type_list (ptr_type_node, ptr_type_node,
integer_type_node, sizetype,
NULL_TREE);
}
else
{
fn = get_identifier ("bzero");
args = build_function_type_list (void_type_node, ptr_type_node,
unsigned_type_node, NULL_TREE);
}
fn = build_decl (FUNCTION_DECL, fn, args);
DECL_EXTERNAL (fn) = 1;
TREE_PUBLIC (fn) = 1;
DECL_ARTIFICIAL (fn) = 1;
TREE_NOTHROW (fn) = 1;
block_clear_fn = fn;
}
if (for_call && !emitted_extern)
{
emitted_extern = true;
make_decl_rtl (fn, NULL);
assemble_external (fn);
}
return fn;
}
rtx
emit_move_insn (x, y)
rtx x, y;
{
enum machine_mode mode = GET_MODE (x);
rtx y_cst = NULL_RTX;
rtx last_insn;
x = protect_from_queue (x, 1);
y = protect_from_queue (y, 0);
if (mode == BLKmode || (GET_MODE (y) != mode && GET_MODE (y) != VOIDmode))
abort ();
if (GET_CODE (y) == CONSTANT_P_RTX)
;
else if (CONSTANT_P (y))
{
if (optimize
&& SCALAR_FLOAT_MODE_P (GET_MODE (x))
&& (last_insn = compress_float_constant (x, y)))
return last_insn;
if (!LEGITIMATE_CONSTANT_P (y))
{
y_cst = y;
y = force_const_mem (mode, y);
if (!y)
y = y_cst;
}
}
if (GET_CODE (x) == MEM
&& ((! memory_address_p (GET_MODE (x), XEXP (x, 0))
&& ! push_operand (x, GET_MODE (x)))
|| (flag_force_addr
&& CONSTANT_ADDRESS_P (XEXP (x, 0)))))
x = validize_mem (x);
if (GET_CODE (y) == MEM
&& (! memory_address_p (GET_MODE (y), XEXP (y, 0))
|| (flag_force_addr
&& CONSTANT_ADDRESS_P (XEXP (y, 0)))))
y = validize_mem (y);
if (mode == BLKmode)
abort ();
last_insn = emit_move_insn_1 (x, y);
if (y_cst && GET_CODE (x) == REG)
set_unique_reg_note (last_insn, REG_EQUAL, y_cst);
return last_insn;
}
rtx
emit_move_insn_1 (x, y)
rtx x, y;
{
enum machine_mode mode = GET_MODE (x);
enum machine_mode submode;
enum mode_class class = GET_MODE_CLASS (mode);
if ((unsigned int) mode >= (unsigned int) MAX_MACHINE_MODE)
abort ();
if (mov_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
return
emit_insn (GEN_FCN (mov_optab->handlers[(int) mode].insn_code) (x, y));
else if ((class == MODE_COMPLEX_FLOAT || class == MODE_COMPLEX_INT)
&& BLKmode != (submode = GET_MODE_INNER (mode))
&& (mov_optab->handlers[(int) submode].insn_code
!= CODE_FOR_nothing))
{
int stack = push_operand (x, GET_MODE (x));
#ifdef PUSH_ROUNDING
if (stack
&& (PUSH_ROUNDING (GET_MODE_SIZE (submode))
!= GET_MODE_SIZE (submode)))
{
rtx temp;
HOST_WIDE_INT offset1, offset2;
temp = expand_binop (Pmode,
#ifdef STACK_GROWS_DOWNWARD
sub_optab,
#else
add_optab,
#endif
stack_pointer_rtx,
GEN_INT
(PUSH_ROUNDING
(GET_MODE_SIZE (GET_MODE (x)))),
stack_pointer_rtx, 0, OPTAB_LIB_WIDEN);
if (temp != stack_pointer_rtx)
emit_move_insn (stack_pointer_rtx, temp);
#ifdef STACK_GROWS_DOWNWARD
offset1 = 0;
offset2 = GET_MODE_SIZE (submode);
#else
offset1 = -PUSH_ROUNDING (GET_MODE_SIZE (GET_MODE (x)));
offset2 = (-PUSH_ROUNDING (GET_MODE_SIZE (GET_MODE (x)))
+ GET_MODE_SIZE (submode));
#endif
emit_move_insn (change_address (x, submode,
gen_rtx_PLUS (Pmode,
stack_pointer_rtx,
GEN_INT (offset1))),
gen_realpart (submode, y));
emit_move_insn (change_address (x, submode,
gen_rtx_PLUS (Pmode,
stack_pointer_rtx,
GEN_INT (offset2))),
gen_imagpart (submode, y));
}
else
#endif
if (stack)
{
#ifdef STACK_GROWS_DOWNWARD
emit_insn (GEN_FCN (mov_optab->handlers[(int) submode].insn_code)
(gen_rtx_MEM (submode, XEXP (x, 0)),
gen_imagpart (submode, y)));
emit_insn (GEN_FCN (mov_optab->handlers[(int) submode].insn_code)
(gen_rtx_MEM (submode, XEXP (x, 0)),
gen_realpart (submode, y)));
#else
emit_insn (GEN_FCN (mov_optab->handlers[(int) submode].insn_code)
(gen_rtx_MEM (submode, XEXP (x, 0)),
gen_realpart (submode, y)));
emit_insn (GEN_FCN (mov_optab->handlers[(int) submode].insn_code)
(gen_rtx_MEM (submode, XEXP (x, 0)),
gen_imagpart (submode, y)));
#endif
}
else
{
rtx realpart_x, realpart_y;
rtx imagpart_x, imagpart_y;
if (GET_MODE_BITSIZE (mode) < 2 * BITS_PER_WORD
&& (reload_in_progress | reload_completed) == 0)
{
int packed_dest_p
= (REG_P (x) && REGNO (x) < FIRST_PSEUDO_REGISTER);
int packed_src_p
= (REG_P (y) && REGNO (y) < FIRST_PSEUDO_REGISTER);
if (packed_dest_p || packed_src_p)
{
enum mode_class reg_class = ((class == MODE_COMPLEX_FLOAT)
? MODE_FLOAT : MODE_INT);
enum machine_mode reg_mode
= mode_for_size (GET_MODE_BITSIZE (mode), reg_class, 1);
if (reg_mode != BLKmode)
{
rtx mem = assign_stack_temp (reg_mode,
GET_MODE_SIZE (mode), 0);
rtx cmem = adjust_address (mem, mode, 0);
cfun->cannot_inline
= N_("function using short complex types cannot be inline");
if (packed_dest_p)
{
rtx sreg = gen_rtx_SUBREG (reg_mode, x, 0);
emit_move_insn_1 (cmem, y);
return emit_move_insn_1 (sreg, mem);
}
else
{
rtx sreg = gen_rtx_SUBREG (reg_mode, y, 0);
emit_move_insn_1 (mem, sreg);
return emit_move_insn_1 (x, cmem);
}
}
}
}
realpart_x = gen_realpart (submode, x);
realpart_y = gen_realpart (submode, y);
imagpart_x = gen_imagpart (submode, x);
imagpart_y = gen_imagpart (submode, y);
if (x != y
&& ! (reload_in_progress || reload_completed)
&& (GET_CODE (realpart_x) == SUBREG
|| GET_CODE (imagpart_x) == SUBREG))
emit_insn (gen_rtx_CLOBBER (VOIDmode, x));
emit_insn (GEN_FCN (mov_optab->handlers[(int) submode].insn_code)
(realpart_x, realpart_y));
emit_insn (GEN_FCN (mov_optab->handlers[(int) submode].insn_code)
(imagpart_x, imagpart_y));
}
return get_last_insn ();
}
else if (GET_MODE_SIZE (mode) >= ABI_UNITS_PER_WORD)
{
rtx last_insn = 0;
rtx seq, inner;
int need_clobber;
int i;
#ifdef PUSH_ROUNDING
if (push_operand (x, GET_MODE (x)))
{
rtx temp;
enum rtx_code code;
temp = expand_binop (Pmode,
#ifdef STACK_GROWS_DOWNWARD
sub_optab,
#else
add_optab,
#endif
stack_pointer_rtx,
GEN_INT
(PUSH_ROUNDING
(GET_MODE_SIZE (GET_MODE (x)))),
stack_pointer_rtx, 0, OPTAB_LIB_WIDEN);
if (temp != stack_pointer_rtx)
emit_move_insn (stack_pointer_rtx, temp);
code = GET_CODE (XEXP (x, 0));
if (code == POST_INC)
temp = gen_rtx_PLUS (Pmode, stack_pointer_rtx,
GEN_INT (-((HOST_WIDE_INT)
GET_MODE_SIZE (GET_MODE (x)))));
else if (code == POST_DEC)
temp = gen_rtx_PLUS (Pmode, stack_pointer_rtx,
GEN_INT (GET_MODE_SIZE (GET_MODE (x))));
else
temp = stack_pointer_rtx;
x = change_address (x, VOIDmode, temp);
}
#endif
if (reload_in_progress && GET_CODE (x) == MEM
&& (inner = find_replacement (&XEXP (x, 0))) != XEXP (x, 0))
x = replace_equiv_address_nv (x, inner);
if (reload_in_progress && GET_CODE (y) == MEM
&& (inner = find_replacement (&XEXP (y, 0))) != XEXP (y, 0))
y = replace_equiv_address_nv (y, inner);
start_sequence ();
need_clobber = 0;
for (i = 0;
i < (GET_MODE_SIZE (mode) + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD;
i++)
{
rtx xpart = operand_subword (x, i, 1, mode);
rtx ypart = operand_subword (y, i, 1, mode);
if (ypart == 0 && CONSTANT_P (y))
{
y = force_const_mem (mode, y);
ypart = operand_subword (y, i, 1, mode);
}
else if (ypart == 0)
ypart = operand_subword_force (y, i, mode);
if (xpart == 0 || ypart == 0)
abort ();
need_clobber |= (GET_CODE (xpart) == SUBREG);
last_insn = emit_move_insn (xpart, ypart);
}
seq = get_insns ();
end_sequence ();
if (x != y
&& ! (reload_in_progress || reload_completed)
&& need_clobber != 0)
emit_insn (gen_rtx_CLOBBER (VOIDmode, x));
emit_insn (seq);
return last_insn;
}
else
abort ();
}
static rtx
compress_float_constant (x, y)
rtx x, y;
{
enum machine_mode dstmode = GET_MODE (x);
enum machine_mode orig_srcmode = GET_MODE (y);
enum machine_mode srcmode;
REAL_VALUE_TYPE r;
REAL_VALUE_FROM_CONST_DOUBLE (r, y);
for (srcmode = GET_CLASS_NARROWEST_MODE (GET_MODE_CLASS (orig_srcmode));
srcmode != orig_srcmode;
srcmode = GET_MODE_WIDER_MODE (srcmode))
{
enum insn_code ic;
rtx trunc_y, last_insn;
ic = can_extend_p (dstmode, srcmode, 0);
if (ic == CODE_FOR_nothing)
continue;
if (! exact_real_truncate (srcmode, &r))
continue;
trunc_y = CONST_DOUBLE_FROM_REAL_VALUE (r, srcmode);
if (LEGITIMATE_CONSTANT_P (trunc_y))
{
if (! (*insn_data[ic].operand[1].predicate) (trunc_y, srcmode))
continue;
}
else if (float_extend_from_mem[dstmode][srcmode])
trunc_y = validize_mem (force_const_mem (srcmode, trunc_y));
else
continue;
emit_unop_insn (ic, x, trunc_y, UNKNOWN);
last_insn = get_last_insn ();
if (GET_CODE (x) == REG)
REG_NOTES (last_insn)
= gen_rtx_EXPR_LIST (REG_EQUAL, y, REG_NOTES (last_insn));
return last_insn;
}
return NULL_RTX;
}
rtx
push_block (size, extra, below)
rtx size;
int extra, below;
{
rtx temp;
size = convert_modes (Pmode, ptr_mode, size, 1);
if (CONSTANT_P (size))
anti_adjust_stack (plus_constant (size, extra));
else if (GET_CODE (size) == REG && extra == 0)
anti_adjust_stack (size);
else
{
temp = copy_to_mode_reg (Pmode, size);
if (extra != 0)
temp = expand_binop (Pmode, add_optab, temp, GEN_INT (extra),
temp, 0, OPTAB_LIB_WIDEN);
anti_adjust_stack (temp);
}
#ifndef STACK_GROWS_DOWNWARD
if (0)
#else
if (1)
#endif
{
temp = virtual_outgoing_args_rtx;
if (extra != 0 && below)
temp = plus_constant (temp, extra);
}
else
{
if (GET_CODE (size) == CONST_INT)
temp = plus_constant (virtual_outgoing_args_rtx,
-INTVAL (size) - (below ? 0 : extra));
else if (extra != 0 && !below)
temp = gen_rtx_PLUS (Pmode, virtual_outgoing_args_rtx,
negate_rtx (Pmode, plus_constant (size, extra)));
else
temp = gen_rtx_PLUS (Pmode, virtual_outgoing_args_rtx,
negate_rtx (Pmode, size));
}
return memory_address (GET_CLASS_NARROWEST_MODE (MODE_INT), temp);
}
#ifdef PUSH_ROUNDING
static void
emit_single_push_insn (mode, x, type)
rtx x;
enum machine_mode mode;
tree type;
{
rtx dest_addr;
unsigned rounded_size = PUSH_ROUNDING (GET_MODE_SIZE (mode));
rtx dest;
enum insn_code icode;
insn_operand_predicate_fn pred;
stack_pointer_delta += PUSH_ROUNDING (GET_MODE_SIZE (mode));
icode = push_optab->handlers[(int) mode].insn_code;
if (icode != CODE_FOR_nothing)
{
if (((pred = insn_data[(int) icode].operand[0].predicate)
&& !((*pred) (x, mode))))
x = force_reg (mode, x);
emit_insn (GEN_FCN (icode) (x));
return;
}
if (GET_MODE_SIZE (mode) == rounded_size)
dest_addr = gen_rtx_fmt_e (STACK_PUSH_CODE, Pmode, stack_pointer_rtx);
else
{
#ifdef STACK_GROWS_DOWNWARD
dest_addr = gen_rtx_PLUS (Pmode, stack_pointer_rtx,
GEN_INT (-(HOST_WIDE_INT) rounded_size));
#else
dest_addr = gen_rtx_PLUS (Pmode, stack_pointer_rtx,
GEN_INT (rounded_size));
#endif
dest_addr = gen_rtx_PRE_MODIFY (Pmode, stack_pointer_rtx, dest_addr);
}
dest = gen_rtx_MEM (mode, dest_addr);
if (type != 0)
{
set_mem_attributes (dest, type, 1);
if (flag_optimize_sibling_calls)
set_mem_alias_set (dest, 0);
}
emit_move_insn (dest, x);
}
#endif
void
emit_push_insn (x, mode, type, size, align, partial, reg, extra,
args_addr, args_so_far, reg_parm_stack_space,
alignment_pad)
rtx x;
enum machine_mode mode;
tree type;
rtx size;
unsigned int align;
int partial;
rtx reg;
int extra;
rtx args_addr;
rtx args_so_far;
int reg_parm_stack_space;
rtx alignment_pad;
{
rtx xinner;
enum direction stack_direction
#ifdef STACK_GROWS_DOWNWARD
= downward;
#else
= upward;
#endif
enum direction where_pad = FUNCTION_ARG_PADDING (mode, type);
if (STACK_PUSH_CODE == POST_DEC)
if (where_pad != none)
where_pad = (where_pad == downward ? upward : downward);
xinner = x = protect_from_queue (x, 0);
if (mode == BLKmode)
{
rtx temp;
int used = partial * ABI_UNITS_PER_WORD;
int offset = used % (PARM_BOUNDARY / BITS_PER_UNIT);
int skip;
if (size == 0)
abort ();
used -= offset;
if (partial != 0)
xinner = adjust_address (xinner, BLKmode, used);
skip = (reg_parm_stack_space == 0) ? 0 : used;
#ifdef PUSH_ROUNDING
if (args_addr == 0
&& PUSH_ARGS
&& GET_CODE (size) == CONST_INT
&& skip == 0
&& (MOVE_BY_PIECES_P ((unsigned) INTVAL (size) - used, align))
&& ((! SLOW_UNALIGNED_ACCESS (word_mode, align))
|| align >= BIGGEST_ALIGNMENT
|| (PUSH_ROUNDING (align / BITS_PER_UNIT)
== (align / BITS_PER_UNIT)))
&& PUSH_ROUNDING (INTVAL (size)) == INTVAL (size))
{
if (extra && args_addr == 0
&& where_pad != none && where_pad != stack_direction)
anti_adjust_stack (GEN_INT (extra));
move_by_pieces (NULL, xinner, INTVAL (size) - used, align);
}
else
#endif
{
rtx target;
if (partial != 0)
{
if (GET_CODE (size) == CONST_INT)
size = GEN_INT (INTVAL (size) - used);
else
size = expand_binop (GET_MODE (size), sub_optab, size,
GEN_INT (used), NULL_RTX, 0,
OPTAB_LIB_WIDEN);
}
if (! args_addr)
{
temp = push_block (size, extra, where_pad == downward);
extra = 0;
}
else if (GET_CODE (args_so_far) == CONST_INT)
temp = memory_address (BLKmode,
plus_constant (args_addr,
skip + INTVAL (args_so_far)));
else
temp = memory_address (BLKmode,
plus_constant (gen_rtx_PLUS (Pmode,
args_addr,
args_so_far),
skip));
if (!ACCUMULATE_OUTGOING_ARGS)
{
if (reg_mentioned_p (virtual_stack_dynamic_rtx, temp)
|| reg_mentioned_p (virtual_outgoing_args_rtx, temp))
temp = copy_to_reg (temp);
}
target = gen_rtx_MEM (BLKmode, temp);
if (type != 0)
{
set_mem_attributes (target, type, 1);
set_mem_alias_set (target, 0);
}
set_mem_align (target, align);
emit_block_move (target, xinner, size, BLOCK_OP_CALL_PARM);
}
}
else if (partial > 0)
{
int size = GET_MODE_SIZE (mode) / ABI_UNITS_PER_WORD;
int i;
int not_stack;
int offset = partial % (PARM_BOUNDARY / ABI_BITS_PER_WORD);
int args_offset = INTVAL (args_so_far);
int skip;
if (extra && args_addr == 0
&& where_pad != none && where_pad != stack_direction)
anti_adjust_stack (GEN_INT (extra));
if (args_addr == 0)
offset = 0;
not_stack = partial - offset;
skip = (reg_parm_stack_space == 0) ? 0 : not_stack;
if (CONSTANT_P (x) && ! LEGITIMATE_CONSTANT_P (x))
x = validize_mem (force_const_mem (mode, x));
if ((GET_CODE (x) == REG && REGNO (x) < FIRST_PSEUDO_REGISTER
&& GET_MODE_CLASS (GET_MODE (x)) != MODE_INT))
x = copy_to_reg (x);
#ifndef PUSH_ARGS_REVERSED
for (i = not_stack; i < size; i++)
#else
for (i = size - 1; i >= not_stack; i--)
#endif
if (i >= not_stack + offset)
emit_push_insn (operand_subword_force (x, i, mode),
ABI_WORD_MODE, NULL_TREE, NULL_RTX, align, 0, NULL_RTX,
0, args_addr,
GEN_INT (args_offset + ((i - not_stack + skip)
* ABI_UNITS_PER_WORD)),
reg_parm_stack_space, alignment_pad);
}
else
{
rtx addr;
rtx target = NULL_RTX;
rtx dest;
if (extra && args_addr == 0
&& where_pad != none && where_pad != stack_direction)
anti_adjust_stack (GEN_INT (extra));
#ifdef PUSH_ROUNDING
if (args_addr == 0 && PUSH_ARGS)
emit_single_push_insn (mode, x, type);
else
#endif
{
if (GET_CODE (args_so_far) == CONST_INT)
addr
= memory_address (mode,
plus_constant (args_addr,
INTVAL (args_so_far)));
else
addr = memory_address (mode, gen_rtx_PLUS (Pmode, args_addr,
args_so_far));
target = addr;
dest = gen_rtx_MEM (mode, addr);
if (type != 0)
{
set_mem_attributes (dest, type, 1);
set_mem_alias_set (dest, 0);
}
emit_move_insn (dest, x);
}
}
if (partial > 0 && reg != 0)
{
if (GET_CODE (reg) == PARALLEL)
emit_group_load (reg, x, -1);
else
move_block_to_reg (REGNO (reg), x, partial, mode);
}
if (extra && args_addr == 0 && where_pad == stack_direction)
anti_adjust_stack (GEN_INT (extra));
if (alignment_pad && args_addr == 0)
anti_adjust_stack (alignment_pad);
}
static rtx
get_subtarget (x)
rtx x;
{
return ((x == 0
|| GET_CODE (x) != REG
|| RTX_UNCHANGING_P (x)
|| REGNO (x) < FIRST_PSEUDO_REGISTER
|| preserve_subexpressions_p ())
? 0 : x);
}
rtx
expand_assignment (to, from, want_value, suggest_reg)
tree to, from;
int want_value;
int suggest_reg ATTRIBUTE_UNUSED;
{
rtx to_rtx = 0;
rtx result;
if (TREE_CODE (to) == ERROR_MARK)
{
result = expand_expr (from, NULL_RTX, VOIDmode, 0);
return want_value ? result : NULL_RTX;
}
if (TREE_CODE (to) == COMPONENT_REF || TREE_CODE (to) == BIT_FIELD_REF
|| TREE_CODE (to) == ARRAY_REF || TREE_CODE (to) == ARRAY_RANGE_REF
|| TREE_CODE (TREE_TYPE (to)) == ARRAY_TYPE)
{
enum machine_mode mode1;
HOST_WIDE_INT bitsize, bitpos;
rtx orig_to_rtx;
tree offset;
int unsignedp;
int volatilep = 0;
tree tem;
push_temp_slots ();
tem = get_inner_reference (to, &bitsize, &bitpos, &offset, &mode1,
&unsignedp, &volatilep);
if (mode1 == VOIDmode && want_value)
tem = stabilize_reference (tem);
orig_to_rtx = to_rtx = expand_expr (tem, NULL_RTX, VOIDmode, 0);
if (offset != 0)
{
rtx offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, EXPAND_SUM);
if (GET_CODE (to_rtx) != MEM)
abort ();
#ifdef POINTERS_EXTEND_UNSIGNED
if (GET_MODE (offset_rtx) != Pmode)
offset_rtx = convert_memory_address (Pmode, offset_rtx);
#else
if (GET_MODE (offset_rtx) != ptr_mode)
offset_rtx = convert_to_mode (ptr_mode, offset_rtx, 0);
#endif
if (GET_CODE (to_rtx) == MEM
&& GET_MODE (to_rtx) == BLKmode
&& GET_MODE (XEXP (to_rtx, 0)) != VOIDmode
&& bitsize > 0
&& (bitpos % bitsize) == 0
&& (bitsize % GET_MODE_ALIGNMENT (mode1)) == 0
&& MEM_ALIGN (to_rtx) == GET_MODE_ALIGNMENT (mode1))
{
to_rtx = adjust_address (to_rtx, mode1, bitpos / BITS_PER_UNIT);
bitpos = 0;
}
to_rtx = offset_address (to_rtx, offset_rtx,
highest_pow2_factor_for_type (TREE_TYPE (to),
offset));
}
if (GET_CODE (to_rtx) == MEM)
{
to_rtx = shallow_copy_rtx (to_rtx);
set_mem_attributes_minus_bitpos (to_rtx, to, 0, bitpos);
}
if (volatilep && GET_CODE (to_rtx) == MEM)
{
if (to_rtx == orig_to_rtx)
to_rtx = copy_rtx (to_rtx);
MEM_VOLATILE_P (to_rtx) = 1;
}
if (TREE_CODE (to) == COMPONENT_REF
&& TREE_READONLY (TREE_OPERAND (to, 1)))
{
if (to_rtx == orig_to_rtx)
to_rtx = copy_rtx (to_rtx);
RTX_UNCHANGING_P (to_rtx) = 1;
}
if (GET_CODE (to_rtx) == MEM && ! can_address_p (to))
{
if (to_rtx == orig_to_rtx)
to_rtx = copy_rtx (to_rtx);
MEM_KEEP_ALIAS_SET_P (to_rtx) = 1;
}
result = store_field (to_rtx, bitsize, bitpos, mode1, from,
(want_value
? ((enum machine_mode)
TYPE_MODE (TREE_TYPE (to)))
: VOIDmode),
unsignedp, TREE_TYPE (tem), get_alias_set (to));
preserve_temp_slots (result);
free_temp_slots ();
pop_temp_slots ();
return (want_value ? convert_modes (TYPE_MODE (TREE_TYPE (to)),
TYPE_MODE (TREE_TYPE (from)),
result,
TREE_UNSIGNED (TREE_TYPE (to)))
: NULL_RTX);
}
if (TREE_CODE (from) == CALL_EXPR && ! aggregate_value_p (from)
&& TREE_CODE (TYPE_SIZE (TREE_TYPE (from))) == INTEGER_CST
&& ! ((TREE_CODE (to) == VAR_DECL || TREE_CODE (to) == PARM_DECL)
&& GET_CODE (DECL_RTL (to)) == REG))
{
rtx value;
push_temp_slots ();
value = expand_expr (from, NULL_RTX, VOIDmode, 0);
if (to_rtx == 0)
to_rtx = expand_expr (to, NULL_RTX, VOIDmode, EXPAND_WRITE);
if (GET_CODE (to_rtx) == PARALLEL)
emit_group_load (to_rtx, value, int_size_in_bytes (TREE_TYPE (from)));
else if (GET_MODE (to_rtx) == BLKmode)
emit_block_move (to_rtx, value, expr_size (from), BLOCK_OP_NORMAL);
else
{
#ifdef POINTERS_EXTEND_UNSIGNED
if (POINTER_TYPE_P (TREE_TYPE (to))
&& GET_MODE (to_rtx) != GET_MODE (value))
value = convert_memory_address (GET_MODE (to_rtx), value);
#endif
emit_move_insn (to_rtx, value);
}
preserve_temp_slots (to_rtx);
free_temp_slots ();
pop_temp_slots ();
return want_value ? to_rtx : NULL_RTX;
}
if (to_rtx == 0)
to_rtx = expand_expr (to, NULL_RTX, VOIDmode, EXPAND_WRITE);
if (TREE_CODE (to) == RESULT_DECL
&& (GET_CODE (to_rtx) == REG || GET_CODE (to_rtx) == PARALLEL))
{
rtx temp;
push_temp_slots ();
temp = expand_expr (from, 0, GET_MODE (to_rtx), 0);
if (GET_CODE (to_rtx) == PARALLEL)
emit_group_load (to_rtx, temp, int_size_in_bytes (TREE_TYPE (from)));
else
emit_move_insn (to_rtx, temp);
preserve_temp_slots (to_rtx);
free_temp_slots ();
pop_temp_slots ();
return want_value ? to_rtx : NULL_RTX;
}
if (TREE_CODE (to) == RESULT_DECL && TREE_CODE (from) == INDIRECT_REF
&& current_function_returns_struct
&& !current_function_returns_pcc_struct)
{
rtx from_rtx, size;
push_temp_slots ();
size = expr_size (from);
from_rtx = expand_expr (from, NULL_RTX, VOIDmode, 0);
if (TARGET_MEM_FUNCTIONS)
emit_library_call (memmove_libfunc, LCT_NORMAL,
VOIDmode, 3, XEXP (to_rtx, 0), Pmode,
XEXP (from_rtx, 0), Pmode,
convert_to_mode (TYPE_MODE (sizetype),
size, TREE_UNSIGNED (sizetype)),
TYPE_MODE (sizetype));
else
emit_library_call (bcopy_libfunc, LCT_NORMAL,
VOIDmode, 3, XEXP (from_rtx, 0), Pmode,
XEXP (to_rtx, 0), Pmode,
convert_to_mode (TYPE_MODE (integer_type_node),
size,
TREE_UNSIGNED (integer_type_node)),
TYPE_MODE (integer_type_node));
preserve_temp_slots (to_rtx);
free_temp_slots ();
pop_temp_slots ();
return want_value ? to_rtx : NULL_RTX;
}
push_temp_slots ();
result = store_expr (from, to_rtx, want_value);
preserve_temp_slots (result);
free_temp_slots ();
pop_temp_slots ();
return want_value ? result : NULL_RTX;
}
rtx
store_expr (exp, target, want_value)
tree exp;
rtx target;
int want_value;
{
rtx temp;
int dont_return_target = 0;
int dont_store_target = 0;
if (TREE_CODE (exp) == COMPOUND_EXPR)
{
expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode,
want_value & 2 ? EXPAND_STACK_PARM : EXPAND_NORMAL);
emit_queue ();
return store_expr (TREE_OPERAND (exp, 1), target, want_value);
}
else if (TREE_CODE (exp) == COND_EXPR && GET_MODE (target) == BLKmode)
{
rtx lab1 = gen_label_rtx (), lab2 = gen_label_rtx ();
emit_queue ();
target = protect_from_queue (target, 1);
do_pending_stack_adjust ();
NO_DEFER_POP;
jumpifnot (TREE_OPERAND (exp, 0), lab1);
start_cleanup_deferral ();
store_expr (TREE_OPERAND (exp, 1), target, want_value & 2);
end_cleanup_deferral ();
emit_queue ();
emit_jump_insn (gen_jump (lab2));
emit_barrier ();
emit_label (lab1);
start_cleanup_deferral ();
store_expr (TREE_OPERAND (exp, 2), target, want_value & 2);
end_cleanup_deferral ();
emit_queue ();
emit_label (lab2);
OK_DEFER_POP;
return want_value & 1 ? target : NULL_RTX;
}
else if (queued_subexp_p (target))
{
if (GET_MODE (target) != BLKmode && GET_MODE (target) != VOIDmode)
{
temp = gen_reg_rtx (GET_MODE (target));
temp = expand_expr (exp, temp, GET_MODE (target),
(want_value & 2
? EXPAND_STACK_PARM : EXPAND_NORMAL));
}
else
temp = expand_expr (exp, NULL_RTX, GET_MODE (target),
(want_value & 2
? EXPAND_STACK_PARM : EXPAND_NORMAL));
if (! MEM_VOLATILE_P (target) && (want_value & 1) != 0)
dont_return_target = 1;
}
else if ((want_value & 1) != 0
&& GET_CODE (target) == MEM
&& ! MEM_VOLATILE_P (target)
&& GET_MODE (target) != BLKmode)
{
temp = expand_expr (exp, target, GET_MODE (target),
want_value & 2 ? EXPAND_STACK_PARM : EXPAND_NORMAL);
if (GET_MODE (temp) != BLKmode && GET_MODE (temp) != VOIDmode)
{
if (temp == target
|| (rtx_equal_p (temp, target)
&& ! side_effects_p (temp) && ! side_effects_p (target)))
dont_store_target = 1;
temp = copy_to_reg (temp);
}
dont_return_target = 1;
}
else if (GET_CODE (target) == SUBREG && SUBREG_PROMOTED_VAR_P (target))
{
rtx inner_target = 0;
if ((want_value & 1) == 0
&& INTEGRAL_TYPE_P (TREE_TYPE (exp))
&& TREE_TYPE (TREE_TYPE (exp)) == 0)
{
tree orig_exp = exp;
if (TREE_UNSIGNED (TREE_TYPE (exp))
!= SUBREG_PROMOTED_UNSIGNED_P (target))
exp = convert
((*lang_hooks.types.signed_or_unsigned_type)
(SUBREG_PROMOTED_UNSIGNED_P (target), TREE_TYPE (exp)), exp);
exp = convert ((*lang_hooks.types.type_for_mode)
(GET_MODE (SUBREG_REG (target)),
SUBREG_PROMOTED_UNSIGNED_P (target)),
exp);
clone_rtx_feedback_counter (orig_exp, exp);
inner_target = SUBREG_REG (target);
}
temp = expand_expr (exp, inner_target, VOIDmode,
want_value & 2 ? EXPAND_STACK_PARM : EXPAND_NORMAL);
if (GET_CODE (temp) == MEM && (want_value & 1) != 0
&& (MEM_VOLATILE_P (temp)
|| reg_mentioned_p (SUBREG_REG (target), XEXP (temp, 0))))
temp = copy_to_reg (temp);
if (CONSTANT_P (temp) && GET_MODE (temp) == VOIDmode)
{
temp = convert_modes (GET_MODE (target), TYPE_MODE (TREE_TYPE (exp)),
temp, SUBREG_PROMOTED_UNSIGNED_P (target));
temp = convert_modes (GET_MODE (SUBREG_REG (target)),
GET_MODE (target), temp,
SUBREG_PROMOTED_UNSIGNED_P (target));
}
convert_move (SUBREG_REG (target), temp,
SUBREG_PROMOTED_UNSIGNED_P (target));
if ((want_value & 1) != 0 && GET_MODE (temp) != GET_MODE (target))
{
if (GET_MODE (temp) != VOIDmode)
{
temp = gen_lowpart_SUBREG (GET_MODE (target), temp);
SUBREG_PROMOTED_VAR_P (temp) = 1;
SUBREG_PROMOTED_UNSIGNED_SET (temp,
SUBREG_PROMOTED_UNSIGNED_P (target));
}
else
temp = convert_modes (GET_MODE (target),
GET_MODE (SUBREG_REG (target)),
temp, SUBREG_PROMOTED_UNSIGNED_P (target));
}
return want_value & 1 ? temp : NULL_RTX;
}
else
{
temp = expand_expr (exp, target, GET_MODE (target),
want_value & 2 ? EXPAND_STACK_PARM : EXPAND_NORMAL);
if (!(target && GET_CODE (target) == REG
&& REGNO (target) < FIRST_PSEUDO_REGISTER)
&& !(GET_CODE (target) == MEM && MEM_VOLATILE_P (target))
&& ! rtx_equal_p (temp, target)
&& (CONSTANT_P (temp) || (want_value & 1) != 0))
dont_return_target = 1;
}
if (CONSTANT_P (temp) && GET_MODE (temp) == VOIDmode
&& TREE_CODE (exp) != ERROR_MARK
&& GET_MODE (target) != TYPE_MODE (TREE_TYPE (exp)))
temp = convert_modes (GET_MODE (target), TYPE_MODE (TREE_TYPE (exp)),
temp, TREE_UNSIGNED (TREE_TYPE (exp)));
if ((! rtx_equal_p (temp, target)
|| (temp != target && (side_effects_p (temp)
|| side_effects_p (target))))
&& TREE_CODE (exp) != ERROR_MARK
&& ! dont_store_target
&& (TREE_CODE_CLASS (TREE_CODE (exp)) != 'd'
|| target != DECL_RTL_IF_SET (exp))
&& expr_size (exp) != const0_rtx)
{
target = protect_from_queue (target, 1);
if (GET_MODE (temp) != GET_MODE (target)
&& GET_MODE (temp) != VOIDmode)
{
int unsignedp = TREE_UNSIGNED (TREE_TYPE (exp));
if (dont_return_target)
{
temp = convert_to_mode (GET_MODE (target), temp, unsignedp);
emit_move_insn (target, temp);
}
else
convert_move (target, temp, unsignedp);
}
else if (GET_MODE (temp) == BLKmode && TREE_CODE (exp) == STRING_CST)
{
rtx size = expr_size (exp);
if (GET_CODE (size) == CONST_INT
&& INTVAL (size) < TREE_STRING_LENGTH (exp))
emit_block_move (target, temp, size,
(want_value & 2
? BLOCK_OP_CALL_PARM : BLOCK_OP_NORMAL));
else
{
tree copy_size
= size_binop (MIN_EXPR,
make_tree (sizetype, size),
size_int (TREE_STRING_LENGTH (exp)));
rtx copy_size_rtx
= expand_expr (copy_size, NULL_RTX, VOIDmode,
(want_value & 2
? EXPAND_STACK_PARM : EXPAND_NORMAL));
rtx label = 0;
copy_size_rtx = convert_to_mode (ptr_mode, copy_size_rtx, 0);
emit_block_move (target, temp, copy_size_rtx,
(want_value & 2
? BLOCK_OP_CALL_PARM : BLOCK_OP_NORMAL));
if (GET_CODE (copy_size_rtx) == CONST_INT)
{
size = plus_constant (size, -INTVAL (copy_size_rtx));
target = adjust_address (target, BLKmode,
INTVAL (copy_size_rtx));
}
else
{
size = expand_binop (TYPE_MODE (sizetype), sub_optab, size,
copy_size_rtx, NULL_RTX, 0,
OPTAB_LIB_WIDEN);
#ifdef POINTERS_EXTEND_UNSIGNED
if (GET_MODE (copy_size_rtx) != Pmode)
copy_size_rtx = convert_memory_address (Pmode,
copy_size_rtx);
#endif
target = offset_address (target, copy_size_rtx,
highest_pow2_factor (copy_size));
label = gen_label_rtx ();
emit_cmp_and_jump_insns (size, const0_rtx, LT, NULL_RTX,
GET_MODE (size), 0, label);
}
if (size != const0_rtx)
clear_storage (target, size);
if (label)
emit_label (label);
}
}
else if (GET_CODE (target) == PARALLEL)
emit_group_load (target, temp, int_size_in_bytes (TREE_TYPE (exp)));
else if (GET_MODE (temp) == BLKmode)
emit_block_move (target, temp, expr_size (exp),
(want_value & 2
? BLOCK_OP_CALL_PARM : BLOCK_OP_NORMAL));
else
emit_move_insn (target, temp);
}
if ((want_value & 1) == 0)
return NULL_RTX;
else if (dont_return_target && GET_CODE (temp) != MEM)
return temp;
else if ((want_value & 1) != 0
&& GET_MODE (target) != BLKmode
&& ! (GET_CODE (target) == REG
&& REGNO (target) < FIRST_PSEUDO_REGISTER))
return copy_to_reg (target);
else
return target;
}
static int
is_zeros_p (exp)
tree exp;
{
tree elt;
switch (TREE_CODE (exp))
{
case CONVERT_EXPR:
case NOP_EXPR:
case NON_LVALUE_EXPR:
case VIEW_CONVERT_EXPR:
return is_zeros_p (TREE_OPERAND (exp, 0));
case INTEGER_CST:
return integer_zerop (exp);
case COMPLEX_CST:
return
is_zeros_p (TREE_REALPART (exp)) && is_zeros_p (TREE_IMAGPART (exp));
case REAL_CST:
return REAL_VALUES_IDENTICAL (TREE_REAL_CST (exp), dconst0);
case VECTOR_CST:
for (elt = TREE_VECTOR_CST_ELTS (exp); elt;
elt = TREE_CHAIN (elt))
if (!is_zeros_p (TREE_VALUE (elt)))
return 0;
return 1;
case CONSTRUCTOR:
if (TREE_TYPE (exp) && TREE_CODE (TREE_TYPE (exp)) == SET_TYPE)
return CONSTRUCTOR_ELTS (exp) == NULL_TREE;
for (elt = CONSTRUCTOR_ELTS (exp); elt; elt = TREE_CHAIN (elt))
if (! is_zeros_p (TREE_VALUE (elt)))
return 0;
return 1;
default:
return 0;
}
}
static int
mostly_zeros_p (exp)
tree exp;
{
if (TREE_CODE (exp) == CONSTRUCTOR)
{
int elts = 0, zeros = 0;
tree elt = CONSTRUCTOR_ELTS (exp);
if (TREE_TYPE (exp) && TREE_CODE (TREE_TYPE (exp)) == SET_TYPE)
{
return elt == NULL_TREE;
}
for (; elt; elt = TREE_CHAIN (elt))
{
if (mostly_zeros_p (TREE_VALUE (elt)))
zeros++;
elts++;
}
return 4 * zeros >= 3 * elts;
}
return is_zeros_p (exp);
}
static void
store_constructor_field (target, bitsize, bitpos, mode, exp, type, cleared,
alias_set)
rtx target;
unsigned HOST_WIDE_INT bitsize;
HOST_WIDE_INT bitpos;
enum machine_mode mode;
tree exp, type;
int cleared;
int alias_set;
{
if (TREE_CODE (exp) == CONSTRUCTOR
&& bitpos % BITS_PER_UNIT == 0
&& (bitpos == 0 || GET_CODE (target) == MEM))
{
if (GET_CODE (target) == MEM)
target
= adjust_address (target,
GET_MODE (target) == BLKmode
|| 0 != (bitpos
% GET_MODE_ALIGNMENT (GET_MODE (target)))
? BLKmode : VOIDmode, bitpos / BITS_PER_UNIT);
if (GET_CODE (target) == MEM && ! MEM_KEEP_ALIAS_SET_P (target)
&& MEM_ALIAS_SET (target) != 0)
{
target = copy_rtx (target);
set_mem_alias_set (target, alias_set);
}
store_constructor (exp, target, cleared, bitsize / BITS_PER_UNIT);
}
else
store_field (target, bitsize, bitpos, mode, exp, VOIDmode, 0, type,
alias_set);
}
static void
store_constructor (exp, target, cleared, size)
tree exp;
rtx target;
int cleared;
HOST_WIDE_INT size;
{
tree type = TREE_TYPE (exp);
#ifdef WORD_REGISTER_OPERATIONS
HOST_WIDE_INT exp_size = int_size_in_bytes (type);
#endif
if (TREE_CODE (type) == RECORD_TYPE || TREE_CODE (type) == UNION_TYPE
|| TREE_CODE (type) == QUAL_UNION_TYPE)
{
tree elt;
if ((TREE_CODE (type) == UNION_TYPE
|| TREE_CODE (type) == QUAL_UNION_TYPE)
&& ! cleared
&& ! CONSTRUCTOR_ELTS (exp))
{
clear_storage (target, expr_size (exp));
cleared = 1;
}
else if (! cleared && GET_CODE (target) == REG && TREE_STATIC (exp)
&& GET_MODE_SIZE (GET_MODE (target)) <= UNITS_PER_WORD)
{
emit_move_insn (target, CONST0_RTX (GET_MODE (target)));
cleared = 1;
}
else if (! cleared && size > 0
&& ((list_length (CONSTRUCTOR_ELTS (exp))
!= fields_length (type))
|| mostly_zeros_p (exp))
&& (GET_CODE (target) != REG
|| ((HOST_WIDE_INT) GET_MODE_SIZE (GET_MODE (target))
== size)))
{
clear_storage (target, GEN_INT (size));
cleared = 1;
}
if (! cleared)
emit_insn (gen_rtx_CLOBBER (VOIDmode, target));
for (elt = CONSTRUCTOR_ELTS (exp); elt; elt = TREE_CHAIN (elt))
{
tree field = TREE_PURPOSE (elt);
tree value = TREE_VALUE (elt);
enum machine_mode mode;
HOST_WIDE_INT bitsize;
HOST_WIDE_INT bitpos = 0;
int unsignedp;
tree offset;
rtx to_rtx = target;
if (field == 0)
continue;
if (cleared && is_zeros_p (value))
continue;
if (host_integerp (DECL_SIZE (field), 1))
bitsize = tree_low_cst (DECL_SIZE (field), 1);
else
bitsize = -1;
unsignedp = TREE_UNSIGNED (field);
mode = DECL_MODE (field);
if (DECL_BIT_FIELD (field))
mode = VOIDmode;
offset = DECL_FIELD_OFFSET (field);
if (host_integerp (offset, 0)
&& host_integerp (bit_position (field), 0))
{
bitpos = int_bit_position (field);
offset = 0;
}
else
bitpos = tree_low_cst (DECL_FIELD_BIT_OFFSET (field), 0);
if (offset)
{
rtx offset_rtx;
if (contains_placeholder_p (offset))
offset = build (WITH_RECORD_EXPR, sizetype,
offset, make_tree (TREE_TYPE (exp), target));
offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, 0);
if (GET_CODE (to_rtx) != MEM)
abort ();
#ifdef POINTERS_EXTEND_UNSIGNED
if (GET_MODE (offset_rtx) != Pmode)
offset_rtx = convert_memory_address (Pmode, offset_rtx);
#else
if (GET_MODE (offset_rtx) != ptr_mode)
offset_rtx = convert_to_mode (ptr_mode, offset_rtx, 0);
#endif
to_rtx = offset_address (to_rtx, offset_rtx,
highest_pow2_factor (offset));
}
if (TREE_READONLY (field))
{
if (GET_CODE (to_rtx) == MEM)
to_rtx = copy_rtx (to_rtx);
RTX_UNCHANGING_P (to_rtx) = 1;
}
#ifdef WORD_REGISTER_OPERATIONS
if (GET_CODE (target) == REG
&& bitsize < BITS_PER_WORD
&& bitpos % BITS_PER_WORD == 0
&& GET_MODE_CLASS (mode) == MODE_INT
&& TREE_CODE (value) == INTEGER_CST
&& exp_size >= 0
&& bitpos + BITS_PER_WORD <= exp_size * BITS_PER_UNIT)
{
tree type = TREE_TYPE (value);
if (TYPE_PRECISION (type) < BITS_PER_WORD)
{
type = (*lang_hooks.types.type_for_size)
(BITS_PER_WORD, TREE_UNSIGNED (type));
value = convert (type, value);
}
if (BYTES_BIG_ENDIAN)
value
= fold (build (LSHIFT_EXPR, type, value,
build_int_2 (BITS_PER_WORD - bitsize, 0)));
bitsize = BITS_PER_WORD;
mode = word_mode;
}
#endif
if (GET_CODE (to_rtx) == MEM && !MEM_KEEP_ALIAS_SET_P (to_rtx)
&& DECL_NONADDRESSABLE_P (field))
{
to_rtx = copy_rtx (to_rtx);
MEM_KEEP_ALIAS_SET_P (to_rtx) = 1;
}
store_constructor_field (to_rtx, bitsize, bitpos, mode,
value, type, cleared,
get_alias_set (TREE_TYPE (field)));
}
}
else if (TREE_CODE (type) == ARRAY_TYPE
|| TREE_CODE (type) == VECTOR_TYPE)
{
tree elt;
int i;
int need_to_clear;
tree domain = TYPE_DOMAIN (type);
tree elttype = TREE_TYPE (type);
int const_bounds_p;
HOST_WIDE_INT minelt = 0;
HOST_WIDE_INT maxelt = 0;
if (TREE_CODE (type) == VECTOR_TYPE)
{
domain = TYPE_DEBUG_REPRESENTATION_TYPE (type);
domain = TYPE_DOMAIN (TREE_TYPE (TYPE_FIELDS (domain)));
}
const_bounds_p = (TYPE_MIN_VALUE (domain)
&& TYPE_MAX_VALUE (domain)
&& host_integerp (TYPE_MIN_VALUE (domain), 0)
&& host_integerp (TYPE_MAX_VALUE (domain), 0));
if (const_bounds_p)
{
minelt = tree_low_cst (TYPE_MIN_VALUE (domain), 0);
maxelt = tree_low_cst (TYPE_MAX_VALUE (domain), 0);
}
if (cleared || (GET_CODE (target) == REG && TREE_STATIC (exp)))
need_to_clear = 1;
else
{
HOST_WIDE_INT count = 0, zero_count = 0;
need_to_clear = ! const_bounds_p;
for (elt = CONSTRUCTOR_ELTS (exp);
elt != NULL_TREE && ! need_to_clear;
elt = TREE_CHAIN (elt))
{
tree index = TREE_PURPOSE (elt);
HOST_WIDE_INT this_node_count;
if (index != NULL_TREE && TREE_CODE (index) == RANGE_EXPR)
{
tree lo_index = TREE_OPERAND (index, 0);
tree hi_index = TREE_OPERAND (index, 1);
if (! host_integerp (lo_index, 1)
|| ! host_integerp (hi_index, 1))
{
need_to_clear = 1;
break;
}
this_node_count = (tree_low_cst (hi_index, 1)
- tree_low_cst (lo_index, 1) + 1);
}
else
this_node_count = 1;
count += this_node_count;
if (mostly_zeros_p (TREE_VALUE (elt)))
zero_count += this_node_count;
}
if (! need_to_clear
&& (count < maxelt - minelt + 1 || 4 * zero_count >= 3 * count))
need_to_clear = 1;
}
if (need_to_clear && size > 0)
{
if (! cleared)
{
if (REG_P (target))
emit_move_insn (target, CONST0_RTX (GET_MODE (target)));
else
clear_storage (target, GEN_INT (size));
}
cleared = 1;
}
else if (REG_P (target))
emit_insn (gen_rtx_CLOBBER (VOIDmode, target));
for (elt = CONSTRUCTOR_ELTS (exp), i = 0;
elt;
elt = TREE_CHAIN (elt), i++)
{
enum machine_mode mode;
HOST_WIDE_INT bitsize;
HOST_WIDE_INT bitpos;
int unsignedp;
tree value = TREE_VALUE (elt);
tree index = TREE_PURPOSE (elt);
rtx xtarget = target;
if (cleared && is_zeros_p (value))
continue;
unsignedp = TREE_UNSIGNED (elttype);
mode = TYPE_MODE (elttype);
if (mode == BLKmode)
bitsize = (host_integerp (TYPE_SIZE (elttype), 1)
? tree_low_cst (TYPE_SIZE (elttype), 1)
: -1);
else
bitsize = GET_MODE_BITSIZE (mode);
if (index != NULL_TREE && TREE_CODE (index) == RANGE_EXPR)
{
tree lo_index = TREE_OPERAND (index, 0);
tree hi_index = TREE_OPERAND (index, 1);
rtx index_r, pos_rtx, hi_r, loop_top, loop_end;
struct nesting *loop;
HOST_WIDE_INT lo, hi, count;
tree position;
if (const_bounds_p
&& host_integerp (lo_index, 0)
&& host_integerp (hi_index, 0)
&& (lo = tree_low_cst (lo_index, 0),
hi = tree_low_cst (hi_index, 0),
count = hi - lo + 1,
(GET_CODE (target) != MEM
|| count <= 2
|| (host_integerp (TYPE_SIZE (elttype), 1)
&& (tree_low_cst (TYPE_SIZE (elttype), 1) * count
<= 40 * 8)))))
{
lo -= minelt; hi -= minelt;
for (; lo <= hi; lo++)
{
bitpos = lo * tree_low_cst (TYPE_SIZE (elttype), 0);
if (GET_CODE (target) == MEM
&& !MEM_KEEP_ALIAS_SET_P (target)
&& TREE_CODE (type) == ARRAY_TYPE
&& TYPE_NONALIASED_COMPONENT (type))
{
target = copy_rtx (target);
MEM_KEEP_ALIAS_SET_P (target) = 1;
}
store_constructor_field
(target, bitsize, bitpos, mode, value, type, cleared,
get_alias_set (elttype));
}
}
else
{
hi_r = expand_expr (hi_index, NULL_RTX, VOIDmode, 0);
loop_top = gen_label_rtx ();
loop_end = gen_label_rtx ();
unsignedp = TREE_UNSIGNED (domain);
index = build_decl (VAR_DECL, NULL_TREE, domain);
index_r
= gen_reg_rtx (promote_mode (domain, DECL_MODE (index),
&unsignedp, 0));
SET_DECL_RTL (index, index_r);
if (TREE_CODE (value) == SAVE_EXPR
&& SAVE_EXPR_RTL (value) == 0)
{
expand_expr (value, const0_rtx, VOIDmode, 0);
emit_queue ();
}
store_expr (lo_index, index_r, 0);
loop = expand_start_loop (0, exp);
position
= convert (ssizetype,
fold (build (MINUS_EXPR, TREE_TYPE (index),
index, TYPE_MIN_VALUE (domain))));
position = size_binop (MULT_EXPR, position,
convert (ssizetype,
TYPE_SIZE_UNIT (elttype)));
pos_rtx = expand_expr (position, 0, VOIDmode, 0);
xtarget = offset_address (target, pos_rtx,
highest_pow2_factor (position));
xtarget = adjust_address (xtarget, mode, 0);
if (TREE_CODE (value) == CONSTRUCTOR)
store_constructor (value, xtarget, cleared,
bitsize / BITS_PER_UNIT);
else
store_expr (value, xtarget, 0);
expand_exit_loop_if_false (loop,
build (LT_EXPR, integer_type_node,
index, hi_index));
expand_increment (build (PREINCREMENT_EXPR,
TREE_TYPE (index),
index, integer_one_node), 0, 0);
expand_end_loop ();
emit_label (loop_end);
}
}
else if ((index != 0 && ! host_integerp (index, 0))
|| ! host_integerp (TYPE_SIZE (elttype), 1))
{
tree position;
if (index == 0)
index = ssize_int (1);
if (minelt)
index = convert (ssizetype,
fold (build (MINUS_EXPR, index,
TYPE_MIN_VALUE (domain))));
position = size_binop (MULT_EXPR, index,
convert (ssizetype,
TYPE_SIZE_UNIT (elttype)));
xtarget = offset_address (target,
expand_expr (position, 0, VOIDmode, 0),
highest_pow2_factor (position));
xtarget = adjust_address (xtarget, mode, 0);
store_expr (value, xtarget, 0);
}
else
{
if (index != 0)
bitpos = ((tree_low_cst (index, 0) - minelt)
* tree_low_cst (TYPE_SIZE (elttype), 1));
else
bitpos = (i * tree_low_cst (TYPE_SIZE (elttype), 1));
if (GET_CODE (target) == MEM && !MEM_KEEP_ALIAS_SET_P (target)
&& TREE_CODE (type) == ARRAY_TYPE
&& TYPE_NONALIASED_COMPONENT (type))
{
target = copy_rtx (target);
MEM_KEEP_ALIAS_SET_P (target) = 1;
}
store_constructor_field (target, bitsize, bitpos, mode, value,
type, cleared, get_alias_set (elttype));
}
}
}
else if (TREE_CODE (type) == SET_TYPE)
{
tree elt = CONSTRUCTOR_ELTS (exp);
unsigned HOST_WIDE_INT nbytes = int_size_in_bytes (type), nbits;
tree domain = TYPE_DOMAIN (type);
tree domain_min, domain_max, bitlength;
if (elt == NULL_TREE && size > 0)
{
if (!cleared)
clear_storage (target, GEN_INT (size));
return;
}
domain_min = convert (sizetype, TYPE_MIN_VALUE (domain));
domain_max = convert (sizetype, TYPE_MAX_VALUE (domain));
bitlength = size_binop (PLUS_EXPR,
size_diffop (domain_max, domain_min),
ssize_int (1));
nbits = tree_low_cst (bitlength, 1);
if (GET_MODE (target) != BLKmode || nbits <= 2 * BITS_PER_WORD
|| (nbytes <= 32 && TREE_CHAIN (elt) != NULL_TREE))
{
unsigned int set_word_size = TYPE_ALIGN (TREE_TYPE (exp));
enum machine_mode mode = mode_for_size (set_word_size, MODE_INT, 1);
char *bit_buffer = (char *) alloca (nbits);
HOST_WIDE_INT word = 0;
unsigned int bit_pos = 0;
unsigned int ibit = 0;
unsigned int offset = 0;
elt = get_set_constructor_bits (exp, bit_buffer, nbits);
for (;;)
{
if (bit_buffer[ibit])
{
if (BYTES_BIG_ENDIAN)
word |= (1 << (set_word_size - 1 - bit_pos));
else
word |= 1 << bit_pos;
}
bit_pos++; ibit++;
if (bit_pos >= set_word_size || ibit == nbits)
{
if (word != 0 || ! cleared)
{
rtx datum = GEN_INT (word);
rtx to_rtx;
if (GET_CODE (target) == MEM)
to_rtx = adjust_address (target, mode, offset);
else if (offset == 0)
to_rtx = target;
else
abort ();
emit_move_insn (to_rtx, datum);
}
if (ibit == nbits)
break;
word = 0;
bit_pos = 0;
offset += set_word_size / BITS_PER_UNIT;
}
}
}
else if (!cleared)
if (TREE_CHAIN (elt) != NULL_TREE
|| (TREE_PURPOSE (elt) == NULL_TREE
? nbits != 1
: ( ! host_integerp (TREE_VALUE (elt), 0)
|| ! host_integerp (TREE_PURPOSE (elt), 0)
|| (tree_low_cst (TREE_VALUE (elt), 0)
- tree_low_cst (TREE_PURPOSE (elt), 0) + 1
!= (HOST_WIDE_INT) nbits))))
clear_storage (target, expr_size (exp));
for (; elt != NULL_TREE; elt = TREE_CHAIN (elt))
{
tree startbit = TREE_PURPOSE (elt);
tree endbit = TREE_VALUE (elt);
HOST_WIDE_INT startb, endb;
rtx bitlength_rtx, startbit_rtx, endbit_rtx, targetx;
bitlength_rtx = expand_expr (bitlength,
NULL_RTX, MEM, EXPAND_CONST_ADDRESS);
if (startbit == NULL_TREE)
{
startbit = save_expr (endbit);
endbit = startbit;
}
startbit = convert (sizetype, startbit);
endbit = convert (sizetype, endbit);
if (! integer_zerop (domain_min))
{
startbit = size_binop (MINUS_EXPR, startbit, domain_min);
endbit = size_binop (MINUS_EXPR, endbit, domain_min);
}
startbit_rtx = expand_expr (startbit, NULL_RTX, MEM,
EXPAND_CONST_ADDRESS);
endbit_rtx = expand_expr (endbit, NULL_RTX, MEM,
EXPAND_CONST_ADDRESS);
if (REG_P (target))
{
targetx
= assign_temp
((build_qualified_type ((*lang_hooks.types.type_for_mode)
(GET_MODE (target), 0),
TYPE_QUAL_CONST)),
0, 1, 1);
emit_move_insn (targetx, target);
}
else if (GET_CODE (target) == MEM)
targetx = target;
else
abort ();
if (TARGET_MEM_FUNCTIONS
&& TREE_CODE (startbit) == INTEGER_CST
&& TREE_CODE (endbit) == INTEGER_CST
&& (startb = TREE_INT_CST_LOW (startbit)) % BITS_PER_UNIT == 0
&& (endb = TREE_INT_CST_LOW (endbit) + 1) % BITS_PER_UNIT == 0)
{
emit_library_call (memset_libfunc, LCT_NORMAL,
VOIDmode, 3,
plus_constant (XEXP (targetx, 0),
startb / BITS_PER_UNIT),
Pmode,
constm1_rtx, TYPE_MODE (integer_type_node),
GEN_INT ((endb - startb) / BITS_PER_UNIT),
TYPE_MODE (sizetype));
}
else
emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__setbits"),
LCT_NORMAL, VOIDmode, 4, XEXP (targetx, 0),
Pmode, bitlength_rtx, TYPE_MODE (sizetype),
startbit_rtx, TYPE_MODE (sizetype),
endbit_rtx, TYPE_MODE (sizetype));
if (REG_P (target))
emit_move_insn (target, targetx);
}
}
else
abort ();
}
static rtx
store_field (target, bitsize, bitpos, mode, exp, value_mode, unsignedp, type,
alias_set)
rtx target;
HOST_WIDE_INT bitsize;
HOST_WIDE_INT bitpos;
enum machine_mode mode;
tree exp;
enum machine_mode value_mode;
int unsignedp;
tree type;
int alias_set;
{
HOST_WIDE_INT width_mask = 0;
if (TREE_CODE (exp) == ERROR_MARK)
return const0_rtx;
if (bitsize == 0)
return expand_expr (exp, const0_rtx, VOIDmode, 0);
else if (bitsize >=0 && bitsize < HOST_BITS_PER_WIDE_INT)
width_mask = ((HOST_WIDE_INT) 1 << bitsize) - 1;
if (mode == BLKmode
&& (GET_CODE (target) == REG || GET_CODE (target) == SUBREG))
{
rtx object
= assign_temp
(build_qualified_type (type, TYPE_QUALS (type) | TYPE_QUAL_CONST),
0, 1, 1);
rtx blk_object = adjust_address (object, BLKmode, 0);
if (bitsize != (HOST_WIDE_INT) GET_MODE_BITSIZE (GET_MODE (target)))
emit_move_insn (object, target);
store_field (blk_object, bitsize, bitpos, mode, exp, VOIDmode, 0, type,
alias_set);
emit_move_insn (target, object);
return blk_object;
}
if (GET_CODE (target) == CONCAT)
{
if (bitpos != 0)
abort ();
return store_expr (exp, target, 0);
}
if (mode == VOIDmode
|| (mode != BLKmode && ! direct_store[(int) mode]
&& GET_MODE_CLASS (mode) != MODE_COMPLEX_INT
&& GET_MODE_CLASS (mode) != MODE_COMPLEX_FLOAT)
|| GET_CODE (target) == REG
|| GET_CODE (target) == SUBREG
|| (mode != BLKmode && SLOW_UNALIGNED_ACCESS (mode, MEM_ALIGN (target))
&& (MEM_ALIGN (target) < GET_MODE_ALIGNMENT (mode)
|| bitpos % GET_MODE_ALIGNMENT (mode)))
|| (bitsize >= 0
&& TREE_CODE (TYPE_SIZE (TREE_TYPE (exp))) == INTEGER_CST
&& compare_tree_int (TYPE_SIZE (TREE_TYPE (exp)), bitsize) != 0))
{
rtx temp = expand_expr (exp, NULL_RTX, VOIDmode, 0);
if (BYTES_BIG_ENDIAN && GET_MODE_CLASS (GET_MODE (temp)) == MODE_INT
&& bitsize < (HOST_WIDE_INT) GET_MODE_BITSIZE (GET_MODE (temp))
&& TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE)
temp = expand_shift (RSHIFT_EXPR, GET_MODE (temp), temp,
size_int (GET_MODE_BITSIZE (GET_MODE (temp))
- bitsize),
temp, 1);
if (mode != VOIDmode && mode != BLKmode
&& mode != TYPE_MODE (TREE_TYPE (exp)))
temp = convert_modes (mode, TYPE_MODE (TREE_TYPE (exp)), temp, 1);
if (GET_MODE (target) == BLKmode && GET_MODE (temp) == BLKmode)
{
if (GET_CODE (target) != MEM || GET_CODE (temp) != MEM
|| bitpos % BITS_PER_UNIT != 0)
abort ();
target = adjust_address (target, VOIDmode, bitpos / BITS_PER_UNIT);
emit_block_move (target, temp,
GEN_INT ((bitsize + BITS_PER_UNIT - 1)
/ BITS_PER_UNIT),
BLOCK_OP_NORMAL);
return value_mode == VOIDmode ? const0_rtx : target;
}
store_bit_field (target, bitsize, bitpos, mode, temp,
int_size_in_bytes (type));
if (value_mode != VOIDmode)
{
if (width_mask != 0
&& ! (GET_CODE (target) == MEM && MEM_VOLATILE_P (target)))
{
tree count;
enum machine_mode tmode;
tmode = GET_MODE (temp);
if (tmode == VOIDmode)
tmode = value_mode;
if (unsignedp)
return expand_and (tmode, temp,
gen_int_mode (width_mask, tmode),
NULL_RTX);
count = build_int_2 (GET_MODE_BITSIZE (tmode) - bitsize, 0);
temp = expand_shift (LSHIFT_EXPR, tmode, temp, count, 0, 0);
return expand_shift (RSHIFT_EXPR, tmode, temp, count, 0, 0);
}
return extract_bit_field (target, bitsize, bitpos, unsignedp,
NULL_RTX, value_mode, VOIDmode,
int_size_in_bytes (type));
}
return const0_rtx;
}
else
{
rtx addr = XEXP (target, 0);
rtx to_rtx = target;
if (value_mode != VOIDmode && GET_CODE (addr) != REG
&& ! CONSTANT_ADDRESS_P (addr)
&& ! (GET_CODE (addr) == PLUS
&& GET_CODE (XEXP (addr, 1)) == CONST_INT
&& (XEXP (addr, 0) == virtual_incoming_args_rtx
|| XEXP (addr, 0) == virtual_stack_vars_rtx)))
to_rtx = replace_equiv_address (to_rtx, copy_to_reg (addr));
to_rtx = adjust_address (target, mode, bitpos / BITS_PER_UNIT);
if (to_rtx == target)
to_rtx = copy_rtx (to_rtx);
MEM_SET_IN_STRUCT_P (to_rtx, 1);
if (!MEM_KEEP_ALIAS_SET_P (to_rtx) && MEM_ALIAS_SET (to_rtx) != 0)
set_mem_alias_set (to_rtx, alias_set);
return store_expr (exp, to_rtx, value_mode != VOIDmode);
}
}
tree
get_inner_reference (exp, pbitsize, pbitpos, poffset, pmode,
punsignedp, pvolatilep)
tree exp;
HOST_WIDE_INT *pbitsize;
HOST_WIDE_INT *pbitpos;
tree *poffset;
enum machine_mode *pmode;
int *punsignedp;
int *pvolatilep;
{
tree size_tree = 0;
enum machine_mode mode = VOIDmode;
tree offset = size_zero_node;
tree bit_offset = bitsize_zero_node;
tree placeholder_ptr = 0;
tree tem;
if (TREE_CODE (exp) == COMPONENT_REF)
{
size_tree = DECL_SIZE (TREE_OPERAND (exp, 1));
if (! DECL_BIT_FIELD (TREE_OPERAND (exp, 1)))
mode = DECL_MODE (TREE_OPERAND (exp, 1));
*punsignedp = TREE_UNSIGNED (TREE_OPERAND (exp, 1));
}
else if (TREE_CODE (exp) == BIT_FIELD_REF)
{
size_tree = TREE_OPERAND (exp, 1);
*punsignedp = TREE_UNSIGNED (exp);
}
else
{
mode = TYPE_MODE (TREE_TYPE (exp));
*punsignedp = TREE_UNSIGNED (TREE_TYPE (exp));
if (mode == BLKmode)
size_tree = TYPE_SIZE (TREE_TYPE (exp));
else
*pbitsize = GET_MODE_BITSIZE (mode);
}
if (size_tree != 0)
{
if (! host_integerp (size_tree, 1))
mode = BLKmode, *pbitsize = -1;
else
*pbitsize = tree_low_cst (size_tree, 1);
}
while (1)
{
if (TREE_CODE (exp) == BIT_FIELD_REF)
bit_offset = size_binop (PLUS_EXPR, bit_offset, TREE_OPERAND (exp, 2));
else if (TREE_CODE (exp) == COMPONENT_REF)
{
tree field = TREE_OPERAND (exp, 1);
tree this_offset = DECL_FIELD_OFFSET (field);
tree old_offset = offset;
if (this_offset == 0)
break;
else if (! TREE_CONSTANT (this_offset)
&& contains_placeholder_p (this_offset))
this_offset = build (WITH_RECORD_EXPR, sizetype, this_offset, exp);
offset = size_binop (PLUS_EXPR, offset, this_offset);
if (TREE_CODE (offset) == COND_EXPR)
clone_rtx_feedback_counter (old_offset, offset);
else if (TREE_CODE (offset) == PLUS_EXPR
&& TREE_CODE (TREE_OPERAND (offset, 0)) == COND_EXPR)
clone_rtx_feedback_counter (old_offset,
TREE_OPERAND (offset, 0));
bit_offset = size_binop (PLUS_EXPR, bit_offset,
DECL_FIELD_BIT_OFFSET (field));
}
else if (TREE_CODE (exp) == ARRAY_REF
|| TREE_CODE (exp) == ARRAY_RANGE_REF)
{
tree index = TREE_OPERAND (exp, 1);
tree array = TREE_OPERAND (exp, 0);
tree domain = TYPE_DOMAIN (TREE_TYPE (array));
tree low_bound = (domain ? TYPE_MIN_VALUE (domain) : 0);
tree unit_size = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (array)));
tree old_offset = offset;
if (low_bound != 0 && ! integer_zerop (low_bound))
index = fold (build (MINUS_EXPR, TREE_TYPE (index),
index, low_bound));
if (! TREE_CONSTANT (index)
&& contains_placeholder_p (index))
index = build (WITH_RECORD_EXPR, TREE_TYPE (index), index, exp);
if (! TREE_CONSTANT (unit_size)
&& contains_placeholder_p (unit_size))
unit_size = build (WITH_RECORD_EXPR, sizetype, unit_size, array);
offset = size_binop (PLUS_EXPR, offset,
size_binop (MULT_EXPR,
convert (sizetype, index),
unit_size));
if (TREE_CODE (offset) == COND_EXPR)
{
if (TREE_CODE (index) == COND_EXPR
&& TREE_CODE (old_offset) != COND_EXPR)
clone_rtx_feedback_counter (index, offset);
if (TREE_CODE (old_offset) == COND_EXPR
&& TREE_CODE (index) != COND_EXPR)
clone_rtx_feedback_counter (old_offset, offset);
if (TREE_CODE (old_offset) == COND_EXPR
&& TREE_CODE (index) == COND_EXPR)
{
tree dup;
clone_rtx_feedback_counter (index, offset);
clone_rtx_feedback_counter (old_offset,
TREE_OPERAND (offset, 1));
clone_rtx_feedback_counter (exp,
TREE_OPERAND (offset, 2));
if (TREE_CODE (TREE_OPERAND (offset, 1)) == COND_EXPR
&& (dup = TREE_OPERAND (TREE_OPERAND (offset, 1), 0))
&& n_slots (dup) != 0)
{
tree clone = copy_node (dup);
TREE_OPERAND (TREE_OPERAND (offset, 1), 0) = clone;
clone_rtx_feedback_counter (TREE_OPERAND (offset, 1),
clone);
}
if (TREE_CODE (TREE_OPERAND (offset, 2)) == COND_EXPR
&& (dup = TREE_OPERAND (TREE_OPERAND (offset, 2), 0))
&& n_slots (dup) != 0)
{
tree clone = copy_node (dup);
TREE_OPERAND (TREE_OPERAND (offset, 2), 0) = clone;
clone_rtx_feedback_counter (TREE_OPERAND (offset, 2),
clone);
}
}
}
}
else if (TREE_CODE (exp) == PLACEHOLDER_EXPR)
{
tree new = find_placeholder (exp, &placeholder_ptr);
if (new == 0)
break;
else
exp = new;
continue;
}
else if (TREE_CODE (exp) != NON_LVALUE_EXPR
&& TREE_CODE (exp) != VIEW_CONVERT_EXPR
&& ! ((TREE_CODE (exp) == NOP_EXPR
|| TREE_CODE (exp) == CONVERT_EXPR)
&& (TYPE_MODE (TREE_TYPE (exp))
== TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))))))
break;
if (TREE_THIS_VOLATILE (exp))
*pvolatilep = 1;
exp = TREE_OPERAND (exp, 0);
}
if (host_integerp (offset, 0)
&& 0 != (tem = size_binop (MULT_EXPR, convert (bitsizetype, offset),
bitsize_unit_node))
&& 0 != (tem = size_binop (PLUS_EXPR, tem, bit_offset))
&& host_integerp (tem, 0))
*pbitpos = tree_low_cst (tem, 0), *poffset = 0;
else
*pbitpos = tree_low_cst (bit_offset, 0), *poffset = offset;
*pmode = mode;
return exp;
}
int
handled_component_p (t)
tree t;
{
switch (TREE_CODE (t))
{
case BIT_FIELD_REF:
case COMPONENT_REF:
case ARRAY_REF:
case ARRAY_RANGE_REF:
case NON_LVALUE_EXPR:
case VIEW_CONVERT_EXPR:
return 1;
case NOP_EXPR:
case CONVERT_EXPR:
return (TYPE_MODE (TREE_TYPE (t))
== TYPE_MODE (TREE_TYPE (TREE_OPERAND (t, 0))));
default:
return 0;
}
}
rtx
force_operand (value, target)
rtx value, target;
{
rtx op1, op2;
rtx subtarget = get_subtarget (target);
enum rtx_code code = GET_CODE (value);
if ((code == PLUS || code == MINUS)
&& XEXP (value, 0) == pic_offset_table_rtx
&& (GET_CODE (XEXP (value, 1)) == SYMBOL_REF
|| GET_CODE (XEXP (value, 1)) == LABEL_REF
|| GET_CODE (XEXP (value, 1)) == CONST))
{
if (!subtarget)
subtarget = gen_reg_rtx (GET_MODE (value));
emit_move_insn (subtarget, value);
return subtarget;
}
if (code == ZERO_EXTEND || code == SIGN_EXTEND)
{
if (!target)
target = gen_reg_rtx (GET_MODE (value));
convert_move (target, force_operand (XEXP (value, 0), NULL),
code == ZERO_EXTEND);
return target;
}
if (GET_RTX_CLASS (code) == '2' || GET_RTX_CLASS (code) == 'c')
{
op2 = XEXP (value, 1);
if (!CONSTANT_P (op2) && !(GET_CODE (op2) == REG && op2 != subtarget))
subtarget = 0;
if (code == MINUS && GET_CODE (op2) == CONST_INT)
{
code = PLUS;
op2 = negate_rtx (GET_MODE (value), op2);
}
if (code == PLUS && GET_CODE (op2) == CONST_INT
&& GET_CODE (XEXP (value, 0)) == PLUS
&& GET_CODE (XEXP (XEXP (value, 0), 0)) == REG
&& REGNO (XEXP (XEXP (value, 0), 0)) >= FIRST_VIRTUAL_REGISTER
&& REGNO (XEXP (XEXP (value, 0), 0)) <= LAST_VIRTUAL_REGISTER)
{
rtx temp = expand_simple_binop (GET_MODE (value), code,
XEXP (XEXP (value, 0), 0), op2,
subtarget, 0, OPTAB_LIB_WIDEN);
return expand_simple_binop (GET_MODE (value), code, temp,
force_operand (XEXP (XEXP (value,
0), 1), 0),
target, 0, OPTAB_LIB_WIDEN);
}
op1 = force_operand (XEXP (value, 0), subtarget);
op2 = force_operand (op2, NULL_RTX);
switch (code)
{
case MULT:
return expand_mult (GET_MODE (value), op1, op2, target, 1);
case DIV:
if (!INTEGRAL_MODE_P (GET_MODE (value)))
return expand_simple_binop (GET_MODE (value), code, op1, op2,
target, 1, OPTAB_LIB_WIDEN);
else
return expand_divmod (0,
FLOAT_MODE_P (GET_MODE (value))
? RDIV_EXPR : TRUNC_DIV_EXPR,
GET_MODE (value), op1, op2, target, 0);
break;
case MOD:
return expand_divmod (1, TRUNC_MOD_EXPR, GET_MODE (value), op1, op2,
target, 0);
break;
case UDIV:
return expand_divmod (0, TRUNC_DIV_EXPR, GET_MODE (value), op1, op2,
target, 1);
break;
case UMOD:
return expand_divmod (1, TRUNC_MOD_EXPR, GET_MODE (value), op1, op2,
target, 1);
break;
case ASHIFTRT:
return expand_simple_binop (GET_MODE (value), code, op1, op2,
target, 0, OPTAB_LIB_WIDEN);
break;
default:
return expand_simple_binop (GET_MODE (value), code, op1, op2,
target, 1, OPTAB_LIB_WIDEN);
}
}
if (GET_RTX_CLASS (code) == '1')
{
op1 = force_operand (XEXP (value, 0), NULL_RTX);
return expand_simple_unop (GET_MODE (value), code, op1, target, 0);
}
#ifdef INSN_SCHEDULING
if (GET_CODE (value) == SUBREG && GET_CODE (SUBREG_REG (value)) == MEM
&& (GET_MODE_SIZE (GET_MODE (value))
> GET_MODE_SIZE (GET_MODE (SUBREG_REG (value)))))
value
= simplify_gen_subreg (GET_MODE (value),
force_reg (GET_MODE (SUBREG_REG (value)),
force_operand (SUBREG_REG (value),
NULL_RTX)),
GET_MODE (SUBREG_REG (value)),
SUBREG_BYTE (value));
#endif
return value;
}
int
safe_from_p (x, exp, top_p)
rtx x;
tree exp;
int top_p;
{
rtx exp_rtl = 0;
int i, nops;
static tree save_expr_list;
if (x == 0
|| (top_p && TREE_TYPE (exp) != 0 && COMPLETE_TYPE_P (TREE_TYPE (exp))
&& TREE_CODE (TYPE_SIZE (TREE_TYPE (exp))) != INTEGER_CST
&& (TREE_CODE (TREE_TYPE (exp)) != ARRAY_TYPE
|| TYPE_ARRAY_MAX_SIZE (TREE_TYPE (exp)) == NULL_TREE
|| TREE_CODE (TYPE_ARRAY_MAX_SIZE (TREE_TYPE (exp)))
!= INTEGER_CST)
&& GET_MODE (x) == BLKmode)
|| (GET_CODE (x) == MEM
&& (XEXP (x, 0) == virtual_outgoing_args_rtx
|| (GET_CODE (XEXP (x, 0)) == PLUS
&& XEXP (XEXP (x, 0), 0) == virtual_outgoing_args_rtx))))
return 1;
if (GET_CODE (x) == SUBREG)
{
x = SUBREG_REG (x);
if (GET_CODE (x) == REG && REGNO (x) < FIRST_PSEUDO_REGISTER)
return 0;
}
if (top_p)
{
int rtn;
tree t;
save_expr_list = 0;
rtn = safe_from_p (x, exp, 0);
for (t = save_expr_list; t != 0; t = TREE_CHAIN (t))
TREE_PRIVATE (TREE_PURPOSE (t)) = 0;
return rtn;
}
switch (TREE_CODE_CLASS (TREE_CODE (exp)))
{
case 'd':
exp_rtl = DECL_RTL_IF_SET (exp);
break;
case 'c':
return 1;
case 'x':
if (TREE_CODE (exp) == TREE_LIST)
return ((TREE_VALUE (exp) == 0
|| safe_from_p (x, TREE_VALUE (exp), 0))
&& (TREE_CHAIN (exp) == 0
|| safe_from_p (x, TREE_CHAIN (exp), 0)));
else if (TREE_CODE (exp) == ERROR_MARK)
return 1;
else
return 0;
case '1':
return safe_from_p (x, TREE_OPERAND (exp, 0), 0);
case '2':
case '<':
return (safe_from_p (x, TREE_OPERAND (exp, 0), 0)
&& safe_from_p (x, TREE_OPERAND (exp, 1), 0));
case 'e':
case 'r':
switch (TREE_CODE (exp))
{
case ADDR_EXPR:
if (staticp (TREE_OPERAND (exp, 0))
|| TREE_STATIC (exp)
|| safe_from_p (x, TREE_OPERAND (exp, 0), 0))
return 1;
exp = TREE_OPERAND (exp, 0);
if (DECL_P (exp))
{
if (!DECL_RTL_SET_P (exp)
|| GET_CODE (DECL_RTL (exp)) != MEM)
return 0;
else
exp_rtl = XEXP (DECL_RTL (exp), 0);
}
break;
case INDIRECT_REF:
if (GET_CODE (x) == MEM
&& alias_sets_conflict_p (MEM_ALIAS_SET (x),
get_alias_set (exp)))
return 0;
break;
case CALL_EXPR:
if ((GET_CODE (x) == REG && REGNO (x) < FIRST_PSEUDO_REGISTER)
|| GET_CODE (x) == MEM)
return 0;
break;
case RTL_EXPR:
if (RTL_EXPR_SEQUENCE (exp))
return 0;
exp_rtl = RTL_EXPR_RTL (exp);
break;
case WITH_CLEANUP_EXPR:
exp_rtl = WITH_CLEANUP_EXPR_RTL (exp);
break;
case CLEANUP_POINT_EXPR:
return safe_from_p (x, TREE_OPERAND (exp, 0), 0);
case SAVE_EXPR:
exp_rtl = SAVE_EXPR_RTL (exp);
if (exp_rtl)
break;
if (TREE_PRIVATE (exp))
return 1;
TREE_PRIVATE (exp) = 1;
if (! safe_from_p (x, TREE_OPERAND (exp, 0), 0))
{
TREE_PRIVATE (exp) = 0;
return 0;
}
save_expr_list = tree_cons (exp, NULL_TREE, save_expr_list);
return 1;
case BIND_EXPR:
return safe_from_p (x, TREE_OPERAND (exp, 1), 0);
case METHOD_CALL_EXPR:
abort ();
default:
break;
}
if (exp_rtl)
break;
nops = first_rtl_op (TREE_CODE (exp));
for (i = 0; i < nops; i++)
if (TREE_OPERAND (exp, i) != 0
&& ! safe_from_p (x, TREE_OPERAND (exp, i), 0))
return 0;
if ((unsigned int) TREE_CODE (exp)
>= (unsigned int) LAST_AND_UNUSED_TREE_CODE
&& !(*lang_hooks.safe_from_p) (x, exp))
return 0;
}
if (exp_rtl)
{
if (GET_CODE (exp_rtl) == SUBREG)
{
exp_rtl = SUBREG_REG (exp_rtl);
if (GET_CODE (exp_rtl) == REG
&& REGNO (exp_rtl) < FIRST_PSEUDO_REGISTER)
return 0;
}
return ! (rtx_equal_p (x, exp_rtl)
|| (GET_CODE (x) == MEM && GET_CODE (exp_rtl) == MEM
&& true_dependence (exp_rtl, VOIDmode, x,
rtx_addr_varies_p)));
}
return 1;
}
static rtx
var_rtx (exp)
tree exp;
{
STRIP_NOPS (exp);
switch (TREE_CODE (exp))
{
case PARM_DECL:
case VAR_DECL:
return DECL_RTL (exp);
default:
return 0;
}
}
#ifdef MAX_INTEGER_COMPUTATION_MODE
void
check_max_integer_computation_mode (exp)
tree exp;
{
enum tree_code code;
enum machine_mode mode;
STRIP_NOPS (exp);
code = TREE_CODE (exp);
if (code == NOP_EXPR
&& TREE_CODE (TREE_OPERAND (exp, 0)) == INTEGER_CST)
return;
if (TREE_CODE_CLASS (code) == '1'
|| TREE_CODE_CLASS (code) == '2'
|| TREE_CODE_CLASS (code) == '<')
{
mode = TYPE_MODE (TREE_TYPE (exp));
if (GET_MODE_CLASS (mode) == MODE_INT
&& mode > MAX_INTEGER_COMPUTATION_MODE)
internal_error ("unsupported wide integer operation");
}
if (TREE_CODE_CLASS (code) == '1')
{
mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
if (GET_MODE_CLASS (mode) == MODE_INT
&& mode > MAX_INTEGER_COMPUTATION_MODE)
internal_error ("unsupported wide integer operation");
}
if (TREE_CODE_CLASS (code) == '2' || TREE_CODE_CLASS (code) == '<')
{
mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
if (GET_MODE_CLASS (mode) == MODE_INT
&& mode > MAX_INTEGER_COMPUTATION_MODE)
internal_error ("unsupported wide integer operation");
mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 1)));
if (GET_MODE_CLASS (mode) == MODE_INT
&& mode > MAX_INTEGER_COMPUTATION_MODE)
internal_error ("unsupported wide integer operation");
}
}
#endif
static HOST_WIDE_INT
highest_pow2_factor (exp)
tree exp;
{
HOST_WIDE_INT c0, c1;
switch (TREE_CODE (exp))
{
case INTEGER_CST:
if (TREE_CONSTANT_OVERFLOW (exp))
return BIGGEST_ALIGNMENT;
else
{
c0 = TREE_INT_CST_LOW (exp);
c0 &= -c0;
return c0 ? c0 : BIGGEST_ALIGNMENT;
}
break;
case PLUS_EXPR: case MINUS_EXPR: case MIN_EXPR: case MAX_EXPR:
c0 = highest_pow2_factor (TREE_OPERAND (exp, 0));
c1 = highest_pow2_factor (TREE_OPERAND (exp, 1));
return MIN (c0, c1);
case MULT_EXPR:
c0 = highest_pow2_factor (TREE_OPERAND (exp, 0));
c1 = highest_pow2_factor (TREE_OPERAND (exp, 1));
return c0 * c1;
case ROUND_DIV_EXPR: case TRUNC_DIV_EXPR: case FLOOR_DIV_EXPR:
case CEIL_DIV_EXPR:
if (integer_pow2p (TREE_OPERAND (exp, 1))
&& host_integerp (TREE_OPERAND (exp, 1), 1))
{
c0 = highest_pow2_factor (TREE_OPERAND (exp, 0));
c1 = tree_low_cst (TREE_OPERAND (exp, 1), 1);
return MAX (1, c0 / c1);
}
break;
case NON_LVALUE_EXPR: case NOP_EXPR: case CONVERT_EXPR:
case SAVE_EXPR: case WITH_RECORD_EXPR:
return highest_pow2_factor (TREE_OPERAND (exp, 0));
case COMPOUND_EXPR:
return highest_pow2_factor (TREE_OPERAND (exp, 1));
case COND_EXPR:
c0 = highest_pow2_factor (TREE_OPERAND (exp, 1));
c1 = highest_pow2_factor (TREE_OPERAND (exp, 2));
return MIN (c0, c1);
default:
break;
}
return 1;
}
static HOST_WIDE_INT
highest_pow2_factor_for_type (type, exp)
tree type;
tree exp;
{
HOST_WIDE_INT type_align, factor;
factor = highest_pow2_factor (exp);
type_align = TYPE_ALIGN (type) / BITS_PER_UNIT;
return MAX (factor, type_align);
}
tree
find_placeholder (exp, plist)
tree exp;
tree *plist;
{
tree type = TREE_TYPE (exp);
tree placeholder_expr;
for (placeholder_expr
= plist && *plist ? TREE_CHAIN (*plist) : placeholder_list;
placeholder_expr != 0;
placeholder_expr = TREE_CHAIN (placeholder_expr))
{
tree need_type = TYPE_MAIN_VARIANT (type);
tree elt;
for (elt = TREE_PURPOSE (placeholder_expr); elt != 0;
elt = ((TREE_CODE (elt) == COMPOUND_EXPR
|| TREE_CODE (elt) == COND_EXPR)
? TREE_OPERAND (elt, 1)
: (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')
? TREE_OPERAND (elt, 0) : 0))
if (TYPE_MAIN_VARIANT (TREE_TYPE (elt)) == need_type)
{
if (plist)
*plist = placeholder_expr;
return elt;
}
for (elt = TREE_PURPOSE (placeholder_expr); elt != 0;
elt
= ((TREE_CODE (elt) == COMPOUND_EXPR
|| TREE_CODE (elt) == COND_EXPR)
? TREE_OPERAND (elt, 1)
: (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')
? TREE_OPERAND (elt, 0) : 0))
if (POINTER_TYPE_P (TREE_TYPE (elt))
&& (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (elt)))
== need_type))
{
if (plist)
*plist = placeholder_expr;
return build1 (INDIRECT_REF, need_type, elt);
}
}
return 0;
}
rtx
expand_expr (exp, target, tmode, modifier)
tree exp;
rtx target;
enum machine_mode tmode;
enum expand_modifier modifier;
{
rtx op0, op1, temp;
tree type = TREE_TYPE (exp);
int unsignedp = TREE_UNSIGNED (type);
enum machine_mode mode;
enum tree_code code = TREE_CODE (exp);
optab this_optab;
rtx subtarget, original_target;
int ignore;
tree context;
rtx const_value = NULL_RTX;
if (TREE_CODE (exp) == ERROR_MARK || TREE_CODE (type) == ERROR_MARK)
{
op0 = CONST0_RTX (tmode);
if (op0 != 0)
return op0;
return const0_rtx;
}
mode = TYPE_MODE (type);
subtarget = get_subtarget (target);
original_target = target;
ignore = (target == const0_rtx
|| ((code == NON_LVALUE_EXPR || code == NOP_EXPR
|| code == CONVERT_EXPR || code == REFERENCE_EXPR
|| code == COND_EXPR || code == VIEW_CONVERT_EXPR)
&& TREE_CODE (type) == VOID_TYPE));
if (ignore)
{
if (! TREE_SIDE_EFFECTS (exp))
return const0_rtx;
if (TREE_THIS_VOLATILE (exp)
&& TREE_CODE (exp) != FUNCTION_DECL
&& mode != VOIDmode && mode != BLKmode
&& modifier != EXPAND_CONST_ADDRESS)
{
temp = expand_expr (exp, NULL_RTX, VOIDmode, modifier);
if (GET_CODE (temp) == MEM)
temp = copy_to_reg (temp);
return const0_rtx;
}
if (TREE_CODE_CLASS (code) == '1' || code == COMPONENT_REF
|| code == INDIRECT_REF || code == BUFFER_REF)
return expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode,
modifier);
else if (TREE_CODE_CLASS (code) == '2' || TREE_CODE_CLASS (code) == '<'
|| code == ARRAY_REF || code == ARRAY_RANGE_REF)
{
expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode, modifier);
expand_expr (TREE_OPERAND (exp, 1), const0_rtx, VOIDmode, modifier);
return const0_rtx;
}
else if ((code == TRUTH_ANDIF_EXPR || code == TRUTH_ORIF_EXPR)
&& ! TREE_SIDE_EFFECTS (TREE_OPERAND (exp, 1)))
return expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode,
modifier);
else if (code == BIT_FIELD_REF)
{
expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode, modifier);
expand_expr (TREE_OPERAND (exp, 1), const0_rtx, VOIDmode, modifier);
expand_expr (TREE_OPERAND (exp, 2), const0_rtx, VOIDmode, modifier);
return const0_rtx;
}
target = 0;
}
#ifdef MAX_INTEGER_COMPUTATION_MODE
if (target
&& GET_MODE (target) != mode
&& TREE_CODE (exp) != INTEGER_CST
&& TREE_CODE (exp) != PARM_DECL
&& TREE_CODE (exp) != ARRAY_REF
&& TREE_CODE (exp) != ARRAY_RANGE_REF
&& TREE_CODE (exp) != COMPONENT_REF
&& TREE_CODE (exp) != BIT_FIELD_REF
&& TREE_CODE (exp) != INDIRECT_REF
&& TREE_CODE (exp) != CALL_EXPR
&& TREE_CODE (exp) != VAR_DECL
&& TREE_CODE (exp) != RTL_EXPR)
{
enum machine_mode mode = GET_MODE (target);
if (GET_MODE_CLASS (mode) == MODE_INT
&& mode > MAX_INTEGER_COMPUTATION_MODE)
internal_error ("unsupported wide integer operation");
}
if (tmode != mode
&& TREE_CODE (exp) != INTEGER_CST
&& TREE_CODE (exp) != PARM_DECL
&& TREE_CODE (exp) != ARRAY_REF
&& TREE_CODE (exp) != ARRAY_RANGE_REF
&& TREE_CODE (exp) != COMPONENT_REF
&& TREE_CODE (exp) != BIT_FIELD_REF
&& TREE_CODE (exp) != INDIRECT_REF
&& TREE_CODE (exp) != VAR_DECL
&& TREE_CODE (exp) != CALL_EXPR
&& TREE_CODE (exp) != RTL_EXPR
&& GET_MODE_CLASS (tmode) == MODE_INT
&& tmode > MAX_INTEGER_COMPUTATION_MODE)
internal_error ("unsupported wide integer operation");
check_max_integer_computation_mode (exp);
#endif
if (! cse_not_expected && mode != BLKmode && target
&& (GET_CODE (target) != REG || REGNO (target) < FIRST_PSEUDO_REGISTER)
&& ! (code == CONSTRUCTOR && GET_MODE_SIZE (mode) > UNITS_PER_WORD))
target = 0;
switch (code)
{
case LABEL_DECL:
{
tree function = decl_function_context (exp);
if (function != current_function_decl
&& function != inline_function_decl && function != 0)
{
struct function *p = find_function_data (function);
p->expr->x_forced_labels
= gen_rtx_EXPR_LIST (VOIDmode, label_rtx (exp),
p->expr->x_forced_labels);
}
else
{
if (modifier == EXPAND_INITIALIZER)
forced_labels = gen_rtx_EXPR_LIST (VOIDmode,
label_rtx (exp),
forced_labels);
}
temp = gen_rtx_MEM (FUNCTION_MODE,
gen_rtx_LABEL_REF (Pmode, label_rtx (exp)));
if (function != current_function_decl
&& function != inline_function_decl && function != 0)
LABEL_REF_NONLOCAL_P (XEXP (temp, 0)) = 1;
return temp;
}
case PARM_DECL:
if (!DECL_RTL_SET_P (exp))
{
error_with_decl (exp, "prior parameter's size depends on `%s'");
return CONST0_RTX (mode);
}
case VAR_DECL:
if (DECL_SIZE (exp) == 0 && COMPLETE_TYPE_P (TREE_TYPE (exp))
&& (TREE_STATIC (exp) || DECL_EXTERNAL (exp)))
{
rtx value = DECL_RTL_IF_SET (exp);
layout_decl (exp, 0);
if (value != 0)
{
PUT_MODE (value, DECL_MODE (exp));
SET_DECL_RTL (exp, 0);
set_mem_attributes (value, exp, 1);
SET_DECL_RTL (exp, value);
}
}
case FUNCTION_DECL:
case RESULT_DECL:
if (DECL_RTL (exp) == 0)
abort ();
if (! TREE_USED (exp))
{
assemble_external (exp);
TREE_USED (exp) = 1;
}
temp = 0;
context = decl_function_context (exp);
if (context != 0 && context != current_function_decl
&& context != inline_function_decl
&& ! (GET_CODE (DECL_RTL (exp)) == MEM
&& CONSTANT_P (XEXP (DECL_RTL (exp), 0))))
{
rtx addr;
DECL_NONLOCAL (exp) = 1;
if (DECL_NO_STATIC_CHAIN (current_function_decl))
abort ();
(*lang_hooks.mark_addressable) (exp);
if (GET_CODE (DECL_RTL (exp)) != MEM)
abort ();
addr = XEXP (DECL_RTL (exp), 0);
if (GET_CODE (addr) == MEM)
addr
= replace_equiv_address (addr,
fix_lexical_addr (XEXP (addr, 0), exp));
else
addr = fix_lexical_addr (addr, exp);
temp = replace_equiv_address (DECL_RTL (exp), addr);
}
else if (GET_CODE (DECL_RTL (exp)) == MEM
&& GET_CODE (XEXP (DECL_RTL (exp), 0)) == REG)
temp = validize_mem (DECL_RTL (exp));
else if (GET_CODE (DECL_RTL (exp)) == MEM
&& modifier != EXPAND_CONST_ADDRESS
&& modifier != EXPAND_SUM
&& modifier != EXPAND_INITIALIZER
&& (! memory_address_p (DECL_MODE (exp),
XEXP (DECL_RTL (exp), 0))
|| (flag_force_addr
&& GET_CODE (XEXP (DECL_RTL (exp), 0)) != REG)))
temp = replace_equiv_address (DECL_RTL (exp),
copy_rtx (XEXP (DECL_RTL (exp), 0)));
if (temp != 0)
{
if (GET_CODE (temp) == MEM && GET_CODE (XEXP (temp, 0)) == REG)
mark_reg_pointer (XEXP (temp, 0), DECL_ALIGN (exp));
return temp;
}
if (GET_CODE (DECL_RTL (exp)) == REG
&& GET_MODE (DECL_RTL (exp)) != DECL_MODE (exp))
{
if (GET_MODE (DECL_RTL (exp))
!= promote_mode (type, DECL_MODE (exp), &unsignedp,
(TREE_CODE (exp) == RESULT_DECL ? 1 : 0)))
abort ();
temp = gen_lowpart_SUBREG (mode, DECL_RTL (exp));
SUBREG_PROMOTED_VAR_P (temp) = 1;
SUBREG_PROMOTED_UNSIGNED_SET (temp, unsignedp);
return temp;
}
return DECL_RTL (exp);
case INTEGER_CST:
temp = immed_double_const (TREE_INT_CST_LOW (exp),
TREE_INT_CST_HIGH (exp), mode);
if (TREE_CONSTANT_OVERFLOW (exp)
&& modifier != EXPAND_INITIALIZER)
temp = force_reg (mode, temp);
return temp;
case CONST_DECL:
return expand_expr (DECL_INITIAL (exp), target, VOIDmode, modifier);
case REAL_CST:
return CONST_DOUBLE_FROM_REAL_VALUE (TREE_REAL_CST (exp),
TYPE_MODE (TREE_TYPE (exp)));
case VECTOR_CST:
return immed_vector_const (exp);
case COMPLEX_CST:
case STRING_CST:
if (! TREE_CST_RTL (exp))
output_constant_def (exp, 1);
if (GET_CODE (TREE_CST_RTL (exp)) == MEM
&& modifier != EXPAND_CONST_ADDRESS
&& modifier != EXPAND_INITIALIZER
&& modifier != EXPAND_SUM
&& (! memory_address_p (mode, XEXP (TREE_CST_RTL (exp), 0))
|| (flag_force_addr
&& GET_CODE (XEXP (TREE_CST_RTL (exp), 0)) != REG)))
return replace_equiv_address (TREE_CST_RTL (exp),
copy_rtx (XEXP (TREE_CST_RTL (exp), 0)));
return TREE_CST_RTL (exp);
case EXPR_WITH_FILE_LOCATION:
{
rtx to_return;
const char *saved_input_filename = input_filename;
int saved_lineno = lineno;
input_filename = EXPR_WFL_FILENAME (exp);
lineno = EXPR_WFL_LINENO (exp);
if (EXPR_WFL_EMIT_LINE_NOTE (exp))
emit_line_note (input_filename, lineno);
to_return = expand_expr (EXPR_WFL_NODE (exp), target, tmode, modifier);
input_filename = saved_input_filename;
lineno = saved_lineno;
return to_return;
}
case SAVE_EXPR:
context = decl_function_context (exp);
if (context == 0)
SAVE_EXPR_CONTEXT (exp) = current_function_decl;
if (context == current_function_decl || context == inline_function_decl)
context = 0;
if (context)
{
find_function_data (context);
temp = SAVE_EXPR_RTL (exp);
if (temp && GET_CODE (temp) == REG)
{
put_var_into_stack (exp);
temp = SAVE_EXPR_RTL (exp);
}
if (temp == 0 || GET_CODE (temp) != MEM)
abort ();
return
replace_equiv_address (temp,
fix_lexical_addr (XEXP (temp, 0), exp));
}
if (SAVE_EXPR_RTL (exp) == 0)
{
if (mode == VOIDmode)
temp = const0_rtx;
else
temp = assign_temp (build_qualified_type (type,
(TYPE_QUALS (type)
| TYPE_QUAL_CONST)),
3, 0, 0);
SAVE_EXPR_RTL (exp) = temp;
if (!optimize && GET_CODE (temp) == REG)
save_expr_regs = gen_rtx_EXPR_LIST (VOIDmode, temp,
save_expr_regs);
if (GET_CODE (temp) == REG && GET_MODE (temp) != mode)
{
temp = gen_lowpart_SUBREG (mode, SAVE_EXPR_RTL (exp));
promote_mode (type, mode, &unsignedp, 0);
SUBREG_PROMOTED_VAR_P (temp) = 1;
SUBREG_PROMOTED_UNSIGNED_SET (temp, unsignedp);
}
if (temp == const0_rtx)
expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode, 0);
else
store_expr (TREE_OPERAND (exp, 0), temp,
modifier == EXPAND_STACK_PARM ? 2 : 0);
TREE_USED (exp) = 1;
}
if (GET_CODE (SAVE_EXPR_RTL (exp)) == REG
&& GET_MODE (SAVE_EXPR_RTL (exp)) != mode)
{
promote_mode (type, mode, &unsignedp, 0);
temp = gen_lowpart_SUBREG (mode, SAVE_EXPR_RTL (exp));
SUBREG_PROMOTED_VAR_P (temp) = 1;
SUBREG_PROMOTED_UNSIGNED_SET (temp, unsignedp);
return temp;
}
return SAVE_EXPR_RTL (exp);
case UNSAVE_EXPR:
{
rtx temp;
temp = expand_expr (TREE_OPERAND (exp, 0), target, tmode, modifier);
TREE_OPERAND (exp, 0)
= (*lang_hooks.unsave_expr_now) (TREE_OPERAND (exp, 0));
return temp;
}
case PLACEHOLDER_EXPR:
{
tree old_list = placeholder_list;
tree placeholder_expr = 0;
exp = find_placeholder (exp, &placeholder_expr);
if (exp == 0)
abort ();
placeholder_list = TREE_CHAIN (placeholder_expr);
temp = expand_expr (exp, original_target, tmode, modifier);
placeholder_list = old_list;
return temp;
}
case WITH_RECORD_EXPR:
placeholder_list = tree_cons (TREE_OPERAND (exp, 1), NULL_TREE,
placeholder_list);
target = expand_expr (TREE_OPERAND (exp, 0), original_target, tmode,
modifier);
placeholder_list = TREE_CHAIN (placeholder_list);
return target;
case GOTO_EXPR:
if (TREE_CODE (TREE_OPERAND (exp, 0)) == LABEL_DECL)
expand_goto (TREE_OPERAND (exp, 0));
else
expand_computed_goto (TREE_OPERAND (exp, 0));
return const0_rtx;
case EXIT_EXPR:
expand_exit_loop_if_false (NULL,
invert_truthvalue (TREE_OPERAND (exp, 0)));
return const0_rtx;
case LABELED_BLOCK_EXPR:
if (LABELED_BLOCK_BODY (exp))
expand_expr_stmt_value (LABELED_BLOCK_BODY (exp), 0, 1);
do_pending_stack_adjust ();
emit_label (label_rtx (LABELED_BLOCK_LABEL (exp)));
return const0_rtx;
case EXIT_BLOCK_EXPR:
if (EXIT_BLOCK_RETURN (exp))
sorry ("returned value in block_exit_expr");
expand_goto (LABELED_BLOCK_LABEL (EXIT_BLOCK_LABELED_BLOCK (exp)));
return const0_rtx;
case LOOP_EXPR:
push_temp_slots ();
expand_start_loop (1, exp);
expand_expr_stmt_value (TREE_OPERAND (exp, 0), 0, 1);
expand_end_loop ();
pop_temp_slots ();
return const0_rtx;
case BIND_EXPR:
{
tree vars = TREE_OPERAND (exp, 0);
int vars_need_expansion = 0;
expand_start_bindings (2);
if (TREE_OPERAND (exp, 2) != 0
&& ! TREE_USED (TREE_OPERAND (exp, 2)))
(*lang_hooks.decls.insert_block) (TREE_OPERAND (exp, 2));
while (vars)
{
if (!DECL_RTL_SET_P (vars))
{
vars_need_expansion = 1;
expand_decl (vars);
}
expand_decl_init (vars);
vars = TREE_CHAIN (vars);
}
temp = expand_expr (TREE_OPERAND (exp, 1), target, tmode, modifier);
expand_end_bindings (TREE_OPERAND (exp, 0), 0, 0);
return temp;
}
case RTL_EXPR:
if (RTL_EXPR_SEQUENCE (exp))
{
if (RTL_EXPR_SEQUENCE (exp) == const0_rtx)
abort ();
emit_insn (RTL_EXPR_SEQUENCE (exp));
RTL_EXPR_SEQUENCE (exp) = const0_rtx;
}
preserve_rtl_expr_result (RTL_EXPR_RTL (exp));
free_temps_for_rtl_expr (exp);
return RTL_EXPR_RTL (exp);
case CONSTRUCTOR:
if (ignore)
{
tree elt;
for (elt = CONSTRUCTOR_ELTS (exp); elt; elt = TREE_CHAIN (elt))
expand_expr (TREE_VALUE (elt), const0_rtx, VOIDmode, 0);
return const0_rtx;
}
else if ((TREE_STATIC (exp)
&& ((mode == BLKmode
&& ! (target != 0 && safe_from_p (target, exp, 1)))
|| TREE_ADDRESSABLE (exp)
|| (host_integerp (TYPE_SIZE_UNIT (type), 1)
&& (! MOVE_BY_PIECES_P
(tree_low_cst (TYPE_SIZE_UNIT (type), 1),
TYPE_ALIGN (type)))
&& ((TREE_CODE (type) == VECTOR_TYPE
&& !is_zeros_p (exp))
|| ! mostly_zeros_p (exp)))))
|| (modifier == EXPAND_INITIALIZER && TREE_CONSTANT (exp)))
{
rtx constructor = output_constant_def (exp, 1);
if (modifier != EXPAND_CONST_ADDRESS
&& modifier != EXPAND_INITIALIZER
&& modifier != EXPAND_SUM)
constructor = validize_mem (constructor);
return constructor;
}
else
{
if (target == 0 || ! safe_from_p (target, exp, 1)
|| GET_CODE (target) == PARALLEL
|| modifier == EXPAND_STACK_PARM)
target
= assign_temp (build_qualified_type (type,
(TYPE_QUALS (type)
| (TREE_READONLY (exp)
* TYPE_QUAL_CONST))),
0, TREE_ADDRESSABLE (exp), 1);
store_constructor (exp, target, 0, int_expr_size (exp));
return target;
}
case INDIRECT_REF:
{
tree exp1 = TREE_OPERAND (exp, 0);
tree index;
tree string = string_constant (exp1, &index);
if (string
&& TREE_CODE (string) == STRING_CST
&& TREE_CODE (index) == INTEGER_CST
&& compare_tree_int (index, TREE_STRING_LENGTH (string)) < 0
&& GET_MODE_CLASS (mode) == MODE_INT
&& GET_MODE_SIZE (mode) == 1
&& modifier != EXPAND_WRITE)
return gen_int_mode (TREE_STRING_POINTER (string)
[TREE_INT_CST_LOW (index)], mode);
op0 = expand_expr (exp1, NULL_RTX, VOIDmode, EXPAND_SUM);
op0 = memory_address (mode, op0);
temp = gen_rtx_MEM (mode, op0);
set_mem_attributes (temp, exp, 0);
if (modifier == EXPAND_WRITE && readonly_fields_p (type))
RTX_UNCHANGING_P (temp) = 1;
return temp;
}
case ARRAY_REF:
if (TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 0))) != ARRAY_TYPE)
abort ();
{
tree array = TREE_OPERAND (exp, 0);
tree domain = TYPE_DOMAIN (TREE_TYPE (array));
tree low_bound = domain ? TYPE_MIN_VALUE (domain) : integer_zero_node;
tree index = convert (sizetype, TREE_OPERAND (exp, 1));
HOST_WIDE_INT i;
if (! integer_zerop (low_bound))
index = size_diffop (index, convert (sizetype, low_bound));
if (modifier != EXPAND_CONST_ADDRESS && modifier != EXPAND_INITIALIZER
&& TREE_CODE (array) == STRING_CST
&& TREE_CODE (index) == INTEGER_CST
&& compare_tree_int (index, TREE_STRING_LENGTH (array)) < 0
&& GET_MODE_CLASS (mode) == MODE_INT
&& GET_MODE_SIZE (mode) == 1)
return gen_int_mode (TREE_STRING_POINTER (array)
[TREE_INT_CST_LOW (index)], mode);
if (modifier != EXPAND_CONST_ADDRESS && modifier != EXPAND_INITIALIZER
&& TREE_CODE (array) == CONSTRUCTOR && ! TREE_SIDE_EFFECTS (array)
&& TREE_CODE (index) == INTEGER_CST
&& 0 > compare_tree_int (index,
list_length (CONSTRUCTOR_ELTS
(TREE_OPERAND (exp, 0)))))
{
tree elem;
for (elem = CONSTRUCTOR_ELTS (TREE_OPERAND (exp, 0)),
i = TREE_INT_CST_LOW (index);
elem != 0 && i != 0; i--, elem = TREE_CHAIN (elem))
;
if (elem)
const_value = expand_expr (fold (TREE_VALUE (elem)), target,
tmode, modifier);
}
else if (optimize >= 1
&& modifier != EXPAND_CONST_ADDRESS
&& modifier != EXPAND_INITIALIZER
&& TREE_READONLY (array) && ! TREE_SIDE_EFFECTS (array)
&& TREE_CODE (array) == VAR_DECL && DECL_INITIAL (array)
&& TREE_CODE (DECL_INITIAL (array)) != ERROR_MARK)
{
if (TREE_CODE (index) == INTEGER_CST)
{
tree init = DECL_INITIAL (array);
if (TREE_CODE (init) == CONSTRUCTOR)
{
tree elem;
for (elem = CONSTRUCTOR_ELTS (init);
(elem
&& !tree_int_cst_equal (TREE_PURPOSE (elem), index));
elem = TREE_CHAIN (elem))
;
if (elem && !TREE_SIDE_EFFECTS (TREE_VALUE (elem)))
const_value = expand_expr (fold (TREE_VALUE (elem)),
target, tmode, modifier);
}
else if (TREE_CODE (init) == STRING_CST
&& 0 > compare_tree_int (index,
TREE_STRING_LENGTH (init)))
{
tree type = TREE_TYPE (TREE_TYPE (init));
enum machine_mode mode = TYPE_MODE (type);
if (GET_MODE_CLASS (mode) == MODE_INT
&& GET_MODE_SIZE (mode) == 1)
return gen_int_mode (TREE_STRING_POINTER (init)
[TREE_INT_CST_LOW (index)], mode);
}
}
}
}
case COMPONENT_REF:
case BIT_FIELD_REF:
case ARRAY_RANGE_REF:
if (code == COMPONENT_REF
&& TREE_CODE (TREE_OPERAND (exp, 0)) == CONSTRUCTOR
&& TREE_CST_RTL (TREE_OPERAND (exp, 0)) == 0)
{
tree elt;
for (elt = CONSTRUCTOR_ELTS (TREE_OPERAND (exp, 0)); elt;
elt = TREE_CHAIN (elt))
if (TREE_PURPOSE (elt) == TREE_OPERAND (exp, 1)
&& (! DECL_BIT_FIELD (TREE_PURPOSE (elt))
|| ((GET_MODE_CLASS (DECL_MODE (TREE_PURPOSE (elt)))
== MODE_INT)
&& (GET_MODE_BITSIZE (DECL_MODE (TREE_PURPOSE (elt)))
<= HOST_BITS_PER_WIDE_INT))))
{
if (DECL_BIT_FIELD (TREE_PURPOSE (elt))
&& modifier == EXPAND_STACK_PARM)
target = 0;
op0 = expand_expr (TREE_VALUE (elt), target, tmode, modifier);
if (DECL_BIT_FIELD (TREE_PURPOSE (elt)))
{
HOST_WIDE_INT bitsize
= TREE_INT_CST_LOW (DECL_SIZE (TREE_PURPOSE (elt)));
enum machine_mode imode
= TYPE_MODE (TREE_TYPE (TREE_PURPOSE (elt)));
if (TREE_UNSIGNED (TREE_TYPE (TREE_PURPOSE (elt))))
{
op1 = GEN_INT (((HOST_WIDE_INT) 1 << bitsize) - 1);
op0 = expand_and (imode, op0, op1, target);
}
else
{
tree count
= build_int_2 (GET_MODE_BITSIZE (imode) - bitsize,
0);
op0 = expand_shift (LSHIFT_EXPR, imode, op0, count,
target, 0);
op0 = expand_shift (RSHIFT_EXPR, imode, op0, count,
target, 0);
}
}
return op0;
}
}
{
enum machine_mode mode1;
HOST_WIDE_INT bitsize, bitpos;
tree offset;
int volatilep = 0;
tree tem = get_inner_reference (exp, &bitsize, &bitpos, &offset,
&mode1, &unsignedp, &volatilep);
rtx orig_op0;
if (tem == exp)
abort ();
orig_op0 = op0
= expand_expr (tem,
(TREE_CODE (TREE_TYPE (tem)) == UNION_TYPE
&& (TREE_CODE (TYPE_SIZE (TREE_TYPE (tem)))
!= INTEGER_CST)
&& modifier != EXPAND_STACK_PARM
? target : NULL_RTX),
VOIDmode,
(modifier == EXPAND_INITIALIZER
|| modifier == EXPAND_CONST_ADDRESS
|| modifier == EXPAND_STACK_PARM)
? modifier : EXPAND_NORMAL);
if (CONSTANT_P (op0))
{
enum machine_mode mode = TYPE_MODE (TREE_TYPE (tem));
if (mode != BLKmode && LEGITIMATE_CONSTANT_P (op0)
&& offset == 0)
op0 = force_reg (mode, op0);
else
op0 = validize_mem (force_const_mem (mode, op0));
}
if (offset != 0)
{
rtx offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode,
EXPAND_SUM);
if (GET_CODE (op0) == REG || GET_CODE (op0) == SUBREG
|| GET_CODE (op0) == CONCAT || GET_CODE (op0) == ADDRESSOF)
{
if (TREE_CODE (TREE_OPERAND (exp, 0)) == SAVE_EXPR)
{
put_var_into_stack (TREE_OPERAND (exp, 0));
op0 = SAVE_EXPR_RTL (TREE_OPERAND (exp, 0));
}
else
{
tree nt
= build_qualified_type (TREE_TYPE (tem),
(TYPE_QUALS (TREE_TYPE (tem))
| TYPE_QUAL_CONST));
rtx memloc = assign_temp (nt, 1, 1, 1);
emit_move_insn (memloc, op0);
op0 = memloc;
}
}
if (GET_CODE (op0) != MEM)
abort ();
#ifdef POINTERS_EXTEND_UNSIGNED
if (GET_MODE (offset_rtx) != Pmode)
offset_rtx = convert_memory_address (Pmode, offset_rtx);
#else
if (GET_MODE (offset_rtx) != ptr_mode)
offset_rtx = convert_to_mode (ptr_mode, offset_rtx, 0);
#endif
if (GET_CODE (op0) == MEM
&& GET_MODE (op0) == BLKmode
&& GET_MODE (XEXP (op0, 0)) != VOIDmode
&& bitsize != 0
&& (bitpos % bitsize) == 0
&& (bitsize % GET_MODE_ALIGNMENT (mode1)) == 0
&& MEM_ALIGN (op0) == GET_MODE_ALIGNMENT (mode1))
{
op0 = adjust_address (op0, mode1, bitpos / BITS_PER_UNIT);
bitpos = 0;
}
op0 = offset_address (op0, offset_rtx,
highest_pow2_factor (offset));
}
if (GET_CODE (op0) == MEM && bitpos == 0 && offset != 0
&& is_aligning_offset (offset, tem))
set_mem_align (op0, BIGGEST_ALIGNMENT);
if (GET_CODE (op0) == MEM && volatilep && ! MEM_VOLATILE_P (op0))
{
if (op0 == orig_op0)
op0 = copy_rtx (op0);
MEM_VOLATILE_P (op0) = 1;
}
if (GET_CODE (op0) == CONCAT)
{
if (bitpos != 0 || bitsize != GET_MODE_BITSIZE (GET_MODE (op0)))
abort ();
return op0;
}
if (mode1 == VOIDmode
|| GET_CODE (op0) == REG || GET_CODE (op0) == SUBREG
|| (mode1 != BLKmode && ! direct_load[(int) mode1]
&& GET_MODE_CLASS (mode) != MODE_COMPLEX_INT
&& GET_MODE_CLASS (mode) != MODE_COMPLEX_FLOAT
&& modifier != EXPAND_CONST_ADDRESS
&& modifier != EXPAND_INITIALIZER)
|| (mode1 != BLKmode
&& SLOW_UNALIGNED_ACCESS (mode1, MEM_ALIGN (op0))
&& ((TYPE_ALIGN (TREE_TYPE (tem))
< GET_MODE_ALIGNMENT (mode))
|| (bitpos % GET_MODE_ALIGNMENT (mode) != 0)))
|| (bitsize >= 0
&& (TREE_CODE (TYPE_SIZE (TREE_TYPE (exp)))
== INTEGER_CST)
&& 0 != compare_tree_int (TYPE_SIZE (TREE_TYPE (exp)),
bitsize)))
{
enum machine_mode ext_mode = mode;
if (ext_mode == BLKmode
&& ! (target != 0 && GET_CODE (op0) == MEM
&& GET_CODE (target) == MEM
&& bitpos % BITS_PER_UNIT == 0))
ext_mode = mode_for_size (bitsize, MODE_INT, 1);
if (ext_mode == BLKmode)
{
if (GET_CODE (op0) != MEM
|| (target != 0 && GET_CODE (target) != MEM)
|| bitpos % BITS_PER_UNIT != 0)
abort ();
op0 = adjust_address (op0, VOIDmode, bitpos / BITS_PER_UNIT);
if (target == 0)
target = assign_temp (type, 0, 1, 1);
emit_block_move (target, op0,
GEN_INT ((bitsize + BITS_PER_UNIT - 1)
/ BITS_PER_UNIT),
(modifier == EXPAND_STACK_PARM
? BLOCK_OP_CALL_PARM : BLOCK_OP_NORMAL));
return target;
}
op0 = validize_mem (op0);
if (GET_CODE (op0) == MEM && GET_CODE (XEXP (op0, 0)) == REG)
mark_reg_pointer (XEXP (op0, 0), MEM_ALIGN (op0));
op0 = extract_bit_field (op0, bitsize, bitpos, unsignedp,
(modifier == EXPAND_STACK_PARM
? NULL_RTX : target),
ext_mode, ext_mode,
int_size_in_bytes (TREE_TYPE (tem)));
if (TREE_CODE (type) == RECORD_TYPE && BYTES_BIG_ENDIAN
&& GET_MODE_CLASS (GET_MODE (op0)) == MODE_INT
&& bitsize < (HOST_WIDE_INT) GET_MODE_BITSIZE (GET_MODE (op0)))
op0 = expand_shift (LSHIFT_EXPR, GET_MODE (op0), op0,
size_int (GET_MODE_BITSIZE (GET_MODE (op0))
- bitsize),
op0, 1);
if (mode == BLKmode)
{
rtx new = assign_temp (build_qualified_type
((*lang_hooks.types.type_for_mode)
(ext_mode, 0),
TYPE_QUAL_CONST), 0, 1, 1);
emit_move_insn (new, op0);
op0 = copy_rtx (new);
PUT_MODE (op0, BLKmode);
set_mem_attributes (op0, exp, 1);
}
return op0;
}
if (mode == BLKmode)
mode1 = BLKmode;
if (modifier == EXPAND_CONST_ADDRESS
|| modifier == EXPAND_SUM || modifier == EXPAND_INITIALIZER)
op0 = adjust_address_nv (op0, mode1, bitpos / BITS_PER_UNIT);
else
op0 = adjust_address (op0, mode1, bitpos / BITS_PER_UNIT);
if (op0 == orig_op0)
op0 = copy_rtx (op0);
set_mem_attributes (op0, exp, 0);
if (GET_CODE (XEXP (op0, 0)) == REG)
mark_reg_pointer (XEXP (op0, 0), MEM_ALIGN (op0));
MEM_VOLATILE_P (op0) |= volatilep;
if (mode == mode1 || mode1 == BLKmode || mode1 == tmode
|| modifier == EXPAND_CONST_ADDRESS
|| modifier == EXPAND_INITIALIZER)
{
if (const_value
&& (tmode == VOIDmode || tmode == mode )
&& (mode == SImode || mode == SFmode || mode == DFmode
|| VECTOR_MODE_P (mode)))
{
rtx insn;
if (target == 0)
target = gen_reg_rtx (tmode != VOIDmode ? tmode : mode);
insn = emit_move_insn (target, op0);
REG_NOTES (insn) =
gen_rtx_EXPR_LIST (REG_EQUAL, const_value, REG_NOTES (insn));
return target;
}
else
return op0;
}
else if (target == 0)
target = gen_reg_rtx (tmode != VOIDmode ? tmode : mode);
convert_move (target, op0, unsignedp);
return target;
}
case VTABLE_REF:
{
rtx insn, before = get_last_insn (), vtbl_ref;
subtarget = expand_expr (TREE_OPERAND (exp, 0), target,
tmode, modifier);
if (REG_P (subtarget))
{
target = subtarget;
insn = get_last_insn ();
if (insn == before)
abort ();
if (! INSN_P (insn))
insn = prev_nonnote_insn (insn);
}
else
{
target = gen_reg_rtx (GET_MODE (subtarget));
insn = emit_move_insn (target, subtarget);
}
vtbl_ref = XEXP (DECL_RTL (TREE_OPERAND (exp, 1)), 0);
vtbl_ref = plus_constant (vtbl_ref,
tree_low_cst (TREE_OPERAND (exp, 2), 0));
vtbl_ref = XEXP (vtbl_ref, 0);
REG_NOTES (insn)
= gen_rtx_EXPR_LIST (REG_VTABLE_REF, vtbl_ref, REG_NOTES (insn));
return target;
}
case BUFFER_REF:
abort ();
case IN_EXPR:
{
tree set = TREE_OPERAND (exp, 0);
tree index = TREE_OPERAND (exp, 1);
int iunsignedp = TREE_UNSIGNED (TREE_TYPE (index));
tree set_type = TREE_TYPE (set);
tree set_low_bound = TYPE_MIN_VALUE (TYPE_DOMAIN (set_type));
tree set_high_bound = TYPE_MAX_VALUE (TYPE_DOMAIN (set_type));
rtx index_val = expand_expr (index, 0, VOIDmode, 0);
rtx lo_r = expand_expr (set_low_bound, 0, VOIDmode, 0);
rtx hi_r = expand_expr (set_high_bound, 0, VOIDmode, 0);
rtx setval = expand_expr (set, 0, VOIDmode, 0);
rtx setaddr = XEXP (setval, 0);
enum machine_mode index_mode = TYPE_MODE (TREE_TYPE (index));
rtx rlow;
rtx diff, quo, rem, addr, bit, result;
if (((TREE_CODE (set_high_bound) == INTEGER_CST
&& TREE_CODE (set_low_bound) == INTEGER_CST
&& tree_int_cst_lt (set_high_bound, set_low_bound))
|| (TREE_CODE (index) == INTEGER_CST
&& TREE_CODE (set_low_bound) == INTEGER_CST
&& tree_int_cst_lt (index, set_low_bound))
|| (TREE_CODE (set_high_bound) == INTEGER_CST
&& TREE_CODE (index) == INTEGER_CST
&& tree_int_cst_lt (set_high_bound, index))))
return const0_rtx;
if (target == 0)
target = gen_reg_rtx (tmode != VOIDmode ? tmode : mode);
op0 = gen_label_rtx ();
op1 = gen_label_rtx ();
if (! (GET_CODE (index_val) == CONST_INT
&& GET_CODE (lo_r) == CONST_INT))
emit_cmp_and_jump_insns (index_val, lo_r, LT, NULL_RTX,
GET_MODE (index_val), iunsignedp, op1);
if (! (GET_CODE (index_val) == CONST_INT
&& GET_CODE (hi_r) == CONST_INT))
emit_cmp_and_jump_insns (index_val, hi_r, GT, NULL_RTX,
GET_MODE (index_val), iunsignedp, op1);
if (GET_CODE (lo_r) == CONST_INT)
rlow = GEN_INT (INTVAL (lo_r)
& ~((HOST_WIDE_INT) 1 << BITS_PER_UNIT));
else
rlow = expand_binop (index_mode, and_optab, lo_r,
GEN_INT (~((HOST_WIDE_INT) 1 << BITS_PER_UNIT)),
NULL_RTX, iunsignedp, OPTAB_LIB_WIDEN);
diff = expand_binop (index_mode, sub_optab, index_val, rlow,
NULL_RTX, iunsignedp, OPTAB_LIB_WIDEN);
quo = expand_divmod (0, TRUNC_DIV_EXPR, index_mode, diff,
GEN_INT (BITS_PER_UNIT), NULL_RTX, iunsignedp);
rem = expand_divmod (1, TRUNC_MOD_EXPR, index_mode, index_val,
GEN_INT (BITS_PER_UNIT), NULL_RTX, iunsignedp);
addr = memory_address (byte_mode,
expand_binop (index_mode, add_optab, diff,
setaddr, NULL_RTX, iunsignedp,
OPTAB_LIB_WIDEN));
bit = expand_shift (RSHIFT_EXPR, byte_mode,
gen_rtx_MEM (byte_mode, addr),
make_tree (TREE_TYPE (index), rem),
NULL_RTX, 1);
result = expand_binop (byte_mode, and_optab, bit, const1_rtx,
GET_MODE (target) == byte_mode ? target : 0,
1, OPTAB_LIB_WIDEN);
if (result != target)
convert_move (target, result, 1);
emit_jump (op0);
emit_label (op1);
emit_move_insn (target, const0_rtx);
emit_label (op0);
return target;
}
case WITH_CLEANUP_EXPR:
if (WITH_CLEANUP_EXPR_RTL (exp) == 0)
{
WITH_CLEANUP_EXPR_RTL (exp)
= expand_expr (TREE_OPERAND (exp, 0), target, tmode, modifier);
expand_decl_cleanup_eh (NULL_TREE, TREE_OPERAND (exp, 1),
CLEANUP_EH_ONLY (exp));
TREE_OPERAND (exp, 1) = 0;
}
return WITH_CLEANUP_EXPR_RTL (exp);
case CLEANUP_POINT_EXPR:
{
expand_start_bindings (2);
target_temp_slot_level = temp_slot_level;
op0 = expand_expr (TREE_OPERAND (exp, 0), target, tmode, modifier);
if (! ignore)
op0 = force_not_mem (op0);
preserve_temp_slots (op0);
expand_end_bindings (NULL_TREE, 0, 0);
}
return op0;
case CALL_EXPR:
if (TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR
&& (TREE_CODE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))
== FUNCTION_DECL)
&& DECL_BUILT_IN (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)))
{
if (DECL_BUILT_IN_CLASS (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))
== BUILT_IN_FRONTEND)
return (*lang_hooks.expand_expr) (exp, original_target,
tmode, modifier);
else
return expand_builtin (exp, target, subtarget, tmode, ignore);
}
return expand_call (exp, target, ignore);
case NON_LVALUE_EXPR:
case NOP_EXPR:
case CONVERT_EXPR:
case REFERENCE_EXPR:
if (TREE_OPERAND (exp, 0) == error_mark_node)
return const0_rtx;
if (TREE_CODE (type) == UNION_TYPE)
{
tree valtype = TREE_TYPE (TREE_OPERAND (exp, 0));
if (mode == BLKmode && TYPE_MODE (valtype) == BLKmode)
{
rtx result = expand_expr (TREE_OPERAND (exp, 0), target, tmode,
modifier);
result = copy_rtx (result);
set_mem_attributes (result, exp, 0);
return result;
}
if (target == 0)
target = assign_temp (type, 0, 1, 1);
if (GET_CODE (target) == MEM)
store_expr (TREE_OPERAND (exp, 0),
adjust_address (target, TYPE_MODE (valtype), 0),
modifier == EXPAND_STACK_PARM ? 2 : 0);
else if (GET_CODE (target) == REG)
store_field (target,
MIN ((int_size_in_bytes (TREE_TYPE
(TREE_OPERAND (exp, 0)))
* BITS_PER_UNIT),
(HOST_WIDE_INT) GET_MODE_BITSIZE (mode)),
0, TYPE_MODE (valtype), TREE_OPERAND (exp, 0),
VOIDmode, 0, type, 0);
else
abort ();
return target;
}
if (mode == TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))))
{
op0 = expand_expr (TREE_OPERAND (exp, 0), target, VOIDmode,
modifier);
if (TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))) != unsignedp
&& GET_CODE (op0) == SUBREG)
SUBREG_PROMOTED_VAR_P (op0) = 0;
return op0;
}
op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, mode, modifier);
if (GET_MODE (op0) == mode)
return op0;
if (CONSTANT_P (op0))
{
tree inner_type = TREE_TYPE (TREE_OPERAND (exp, 0));
enum machine_mode inner_mode = TYPE_MODE (inner_type);
if (modifier == EXPAND_INITIALIZER)
return simplify_gen_subreg (mode, op0, inner_mode,
subreg_lowpart_offset (mode,
inner_mode));
else
return convert_modes (mode, inner_mode, op0,
TREE_UNSIGNED (inner_type));
}
if (modifier == EXPAND_INITIALIZER)
return gen_rtx_fmt_e (unsignedp ? ZERO_EXTEND : SIGN_EXTEND, mode, op0);
if (target == 0)
return
convert_to_mode (mode, op0,
TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))));
else
convert_move (target, op0,
TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))));
return target;
case VIEW_CONVERT_EXPR:
op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, mode, modifier);
if (TYPE_MODE (type) == GET_MODE (op0))
;
else if (TYPE_MODE (type) != BLKmode && GET_MODE (op0) != BLKmode
&& GET_MODE_SIZE (TYPE_MODE (type)) <= UNITS_PER_WORD
&& GET_MODE_SIZE (GET_MODE (op0)) <= UNITS_PER_WORD)
op0 = gen_lowpart (TYPE_MODE (type), op0);
else if (GET_CODE (op0) != MEM)
{
tree inner_type = TREE_TYPE (TREE_OPERAND (exp, 0));
if (TREE_ADDRESSABLE (exp))
abort ();
if (target == 0 || GET_MODE (target) != TYPE_MODE (inner_type))
target
= assign_stack_temp_for_type
(TYPE_MODE (inner_type),
GET_MODE_SIZE (TYPE_MODE (inner_type)), 0, inner_type);
emit_move_insn (target, op0);
op0 = target;
}
if (GET_CODE (op0) == MEM)
{
op0 = copy_rtx (op0);
if (TYPE_ALIGN_OK (type))
set_mem_align (op0, MAX (MEM_ALIGN (op0), TYPE_ALIGN (type)));
else if (TYPE_MODE (type) != BLKmode && STRICT_ALIGNMENT
&& MEM_ALIGN (op0) < GET_MODE_ALIGNMENT (TYPE_MODE (type)))
{
tree inner_type = TREE_TYPE (TREE_OPERAND (exp, 0));
HOST_WIDE_INT temp_size
= MAX (int_size_in_bytes (inner_type),
(HOST_WIDE_INT) GET_MODE_SIZE (TYPE_MODE (type)));
rtx new = assign_stack_temp_for_type (TYPE_MODE (type),
temp_size, 0, type);
rtx new_with_op0_mode = adjust_address (new, GET_MODE (op0), 0);
if (TREE_ADDRESSABLE (exp))
abort ();
if (GET_MODE (op0) == BLKmode)
emit_block_move (new_with_op0_mode, op0,
GEN_INT (GET_MODE_SIZE (TYPE_MODE (type))),
(modifier == EXPAND_STACK_PARM
? BLOCK_OP_CALL_PARM : BLOCK_OP_NORMAL));
else
emit_move_insn (new_with_op0_mode, op0);
op0 = new;
}
op0 = adjust_address (op0, TYPE_MODE (type), 0);
}
return op0;
case PLUS_EXPR:
this_optab = ! unsignedp && flag_trapv
&& (GET_MODE_CLASS (mode) == MODE_INT)
? addv_optab : add_optab;
if (TREE_CODE (TREE_OPERAND (exp, 0)) == PLUS_EXPR
&& TREE_CODE (TREE_OPERAND (TREE_OPERAND (exp, 0), 1)) == INTEGER_CST
&& TREE_CODE (TREE_OPERAND (exp, 1)) == RTL_EXPR
&& (RTL_EXPR_RTL (TREE_OPERAND (exp, 1)) == frame_pointer_rtx
|| RTL_EXPR_RTL (TREE_OPERAND (exp, 1)) == stack_pointer_rtx
|| RTL_EXPR_RTL (TREE_OPERAND (exp, 1)) == arg_pointer_rtx))
{
tree t = TREE_OPERAND (exp, 1);
TREE_OPERAND (exp, 1) = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
TREE_OPERAND (TREE_OPERAND (exp, 0), 0) = t;
}
if (modifier == EXPAND_SUM || modifier == EXPAND_INITIALIZER
|| (mode == ptr_mode && (unsignedp || ! flag_trapv)))
{
if (modifier == EXPAND_STACK_PARM)
target = 0;
if (TREE_CODE (TREE_OPERAND (exp, 0)) == INTEGER_CST
&& GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
&& TREE_CONSTANT (TREE_OPERAND (exp, 1)))
{
rtx constant_part;
op1 = expand_expr (TREE_OPERAND (exp, 1), subtarget, VOIDmode,
EXPAND_SUM);
constant_part
= immed_double_const (TREE_INT_CST_LOW (TREE_OPERAND (exp, 0)),
(HOST_WIDE_INT) 0,
TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 1))));
op1 = plus_constant (op1, INTVAL (constant_part));
if (modifier != EXPAND_SUM && modifier != EXPAND_INITIALIZER)
op1 = force_operand (op1, target);
return op1;
}
else if (TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST
&& GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_INT
&& TREE_CONSTANT (TREE_OPERAND (exp, 0)))
{
rtx constant_part;
op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode,
(modifier == EXPAND_INITIALIZER
? EXPAND_INITIALIZER : EXPAND_SUM));
if (! CONSTANT_P (op0))
{
op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX,
VOIDmode, modifier);
if (modifier != EXPAND_SUM && modifier != EXPAND_INITIALIZER)
goto binop2;
goto both_summands;
}
constant_part
= immed_double_const (TREE_INT_CST_LOW (TREE_OPERAND (exp, 1)),
(HOST_WIDE_INT) 0,
TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))));
op0 = plus_constant (op0, INTVAL (constant_part));
if (modifier != EXPAND_SUM && modifier != EXPAND_INITIALIZER)
op0 = force_operand (op0, target);
return op0;
}
}
if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1), 1))
subtarget = 0;
if ((modifier != EXPAND_SUM && modifier != EXPAND_INITIALIZER)
|| mode != ptr_mode)
{
op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, 0);
if (op0 == const0_rtx)
return op1;
if (op1 == const0_rtx)
return op0;
goto binop2;
}
op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, modifier);
op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, modifier);
both_summands:
if (GET_CODE (op0) == PLUS
&& CONSTANT_P (XEXP (op0, 1)))
{
temp = op0;
op0 = op1;
op1 = temp;
}
if (GET_CODE (op1) == PLUS
&& CONSTANT_P (XEXP (op1, 1)))
{
rtx constant_term = const0_rtx;
temp = simplify_binary_operation (PLUS, mode, XEXP (op1, 0), op0);
if (temp != 0)
op0 = temp;
else if (GET_CODE (op0) == MULT)
op0 = gen_rtx_PLUS (mode, op0, XEXP (op1, 0));
else
op0 = gen_rtx_PLUS (mode, XEXP (op1, 0), op0);
op0 = eliminate_constant_term (op0, &constant_term);
temp = simplify_binary_operation (PLUS, mode, constant_term,
XEXP (op1, 1));
if (temp != 0)
op1 = temp;
else
op1 = gen_rtx_PLUS (mode, constant_term, XEXP (op1, 1));
}
if (CONSTANT_P (op0) || GET_CODE (op1) == MULT)
temp = op1, op1 = op0, op0 = temp;
temp = simplify_binary_operation (PLUS, mode, op0, op1);
return temp ? temp : gen_rtx_PLUS (mode, op0, op1);
case MINUS_EXPR:
if ((modifier == EXPAND_SUM || modifier == EXPAND_INITIALIZER)
&& really_constant_p (TREE_OPERAND (exp, 0))
&& really_constant_p (TREE_OPERAND (exp, 1)))
{
rtx op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, VOIDmode,
modifier);
rtx op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode,
modifier);
if (GET_CODE (op1) == CONST_INT)
return plus_constant (op0, - INTVAL (op1));
else
return gen_rtx_MINUS (mode, op0, op1);
}
this_optab = ! unsignedp && flag_trapv
&& (GET_MODE_CLASS(mode) == MODE_INT)
? subv_optab : sub_optab;
if ((modifier != EXPAND_SUM && modifier != EXPAND_INITIALIZER)
|| mode != ptr_mode)
goto binop;
if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1), 1))
subtarget = 0;
op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, modifier);
op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, modifier);
if (GET_CODE (op1) == CONST_INT)
{
op1 = negate_rtx (mode, op1);
goto both_summands;
}
goto binop2;
case MULT_EXPR:
if (TREE_CODE (TREE_OPERAND (exp, 0)) == INTEGER_CST)
{
tree t1 = TREE_OPERAND (exp, 0);
TREE_OPERAND (exp, 0) = TREE_OPERAND (exp, 1);
TREE_OPERAND (exp, 1) = t1;
}
if (modifier == EXPAND_SUM && mode == ptr_mode
&& host_integerp (TREE_OPERAND (exp, 1), 0))
{
tree exp1 = TREE_OPERAND (exp, 1);
op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode,
EXPAND_SUM);
if (GET_CODE (op0) != REG)
op0 = force_operand (op0, NULL_RTX);
if (GET_CODE (op0) != REG)
op0 = copy_to_mode_reg (mode, op0);
return gen_rtx_MULT (mode, op0,
gen_int_mode (tree_low_cst (exp1, 0),
TYPE_MODE (TREE_TYPE (exp1))));
}
if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1), 1))
subtarget = 0;
if (modifier == EXPAND_STACK_PARM)
target = 0;
if (TREE_CODE (TREE_OPERAND (exp, 0)) == NOP_EXPR
&& TREE_CODE (type) == INTEGER_TYPE
&& (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)))
< TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (exp, 0))))
&& ((TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST
&& int_fits_type_p (TREE_OPERAND (exp, 1),
TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)))
&& ((GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 1))))
> HOST_BITS_PER_WIDE_INT)
|| exact_log2 (TREE_INT_CST_LOW (TREE_OPERAND (exp, 1))) < 0))
||
(TREE_CODE (TREE_OPERAND (exp, 1)) == NOP_EXPR
&& (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 1), 0)))
==
TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))))
&& (TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 1), 0)))
==
TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)))))))
{
enum machine_mode innermode
= TYPE_MODE (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)));
optab other_optab = (TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)))
? smul_widen_optab : umul_widen_optab);
this_optab = (TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)))
? umul_widen_optab : smul_widen_optab);
if (mode == GET_MODE_WIDER_MODE (innermode))
{
if (this_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
{
op0 = expand_expr (TREE_OPERAND (TREE_OPERAND (exp, 0), 0),
NULL_RTX, VOIDmode, 0);
if (TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST)
op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX,
VOIDmode, 0);
else
op1 = expand_expr (TREE_OPERAND (TREE_OPERAND (exp, 1), 0),
NULL_RTX, VOIDmode, 0);
goto binop2;
}
else if (other_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing
&& innermode == word_mode)
{
rtx htem;
op0 = expand_expr (TREE_OPERAND (TREE_OPERAND (exp, 0), 0),
NULL_RTX, VOIDmode, 0);
if (TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST)
op1 = convert_modes (innermode, mode,
expand_expr (TREE_OPERAND (exp, 1),
NULL_RTX, VOIDmode, 0),
unsignedp);
else
op1 = expand_expr (TREE_OPERAND (TREE_OPERAND (exp, 1), 0),
NULL_RTX, VOIDmode, 0);
temp = expand_binop (mode, other_optab, op0, op1, target,
unsignedp, OPTAB_LIB_WIDEN);
htem = expand_mult_highpart_adjust (innermode,
gen_highpart (innermode, temp),
op0, op1,
gen_highpart (innermode, temp),
unsignedp);
emit_move_insn (gen_highpart (innermode, temp), htem);
return temp;
}
}
}
op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, 0);
return expand_mult (mode, op0, op1, target, unsignedp);
case TRUNC_DIV_EXPR:
case FLOOR_DIV_EXPR:
case CEIL_DIV_EXPR:
case ROUND_DIV_EXPR:
case EXACT_DIV_EXPR:
if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1), 1))
subtarget = 0;
if (modifier == EXPAND_STACK_PARM)
target = 0;
op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, 0);
return expand_divmod (0, code, mode, op0, op1, target, unsignedp);
case RDIV_EXPR:
if (flag_unsafe_math_optimizations && optimize && !optimize_size
&& TREE_CODE (type) == REAL_TYPE
&& !real_onep (TREE_OPERAND (exp, 0)))
return expand_expr (build (MULT_EXPR, type, TREE_OPERAND (exp, 0),
build (RDIV_EXPR, type,
build_real (type, dconst1),
TREE_OPERAND (exp, 1))),
target, tmode, modifier);
this_optab = sdiv_optab;
goto binop;
case TRUNC_MOD_EXPR:
case FLOOR_MOD_EXPR:
case CEIL_MOD_EXPR:
case ROUND_MOD_EXPR:
if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1), 1))
subtarget = 0;
if (modifier == EXPAND_STACK_PARM)
target = 0;
op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, 0);
return expand_divmod (1, code, mode, op0, op1, target, unsignedp);
case FIX_ROUND_EXPR:
case FIX_FLOOR_EXPR:
case FIX_CEIL_EXPR:
abort ();
case FIX_TRUNC_EXPR:
op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, VOIDmode, 0);
if (target == 0 || modifier == EXPAND_STACK_PARM)
target = gen_reg_rtx (mode);
expand_fix_tree (target, op0, unsignedp, exp);
return target;
case FLOAT_EXPR:
op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, VOIDmode, 0);
if (target == 0 || modifier == EXPAND_STACK_PARM)
target = gen_reg_rtx (mode);
if (GET_MODE (op0) == VOIDmode)
op0 = copy_to_mode_reg (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))),
op0);
expand_float_tree (target, op0,
TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))), exp);
return target;
case NEGATE_EXPR:
op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
if (modifier == EXPAND_STACK_PARM)
target = 0;
temp = expand_unop (mode,
! unsignedp && flag_trapv
&& (GET_MODE_CLASS(mode) == MODE_INT)
? negv_optab : neg_optab, op0, target, 0);
if (temp == 0)
abort ();
return temp;
case ABS_EXPR:
op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
if (modifier == EXPAND_STACK_PARM)
target = 0;
if (GET_MODE_CLASS (mode) == MODE_COMPLEX_INT
|| GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT)
return expand_complex_abs (mode, op0, target, unsignedp);
if (TREE_UNSIGNED (type))
return op0;
return expand_abs (mode, op0, target, unsignedp,
safe_from_p (target, TREE_OPERAND (exp, 0), 1));
case MAX_EXPR:
case MIN_EXPR:
target = original_target;
if (target == 0
|| modifier == EXPAND_STACK_PARM
|| ! safe_from_p (target, TREE_OPERAND (exp, 1), 1)
|| (GET_CODE (target) == MEM && MEM_VOLATILE_P (target))
|| GET_MODE (target) != mode
|| (GET_CODE (target) == REG
&& REGNO (target) < FIRST_PSEUDO_REGISTER))
target = gen_reg_rtx (mode);
op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, 0);
op0 = expand_expr (TREE_OPERAND (exp, 0), target, VOIDmode, 0);
this_optab = (TREE_UNSIGNED (type)
? (code == MIN_EXPR ? umin_optab : umax_optab)
: (code == MIN_EXPR ? smin_optab : smax_optab));
temp = expand_binop (mode, this_optab, op0, op1, target, unsignedp,
OPTAB_WIDEN);
if (temp != 0)
return temp;
if (GET_CODE (target) == MEM)
target = gen_reg_rtx (mode);
if (target != op0)
emit_move_insn (target, op0);
op0 = gen_label_rtx ();
if (GET_MODE_CLASS (mode) == MODE_INT
&& ! can_compare_p (GE, mode, ccp_jump))
{
if (code == MAX_EXPR)
do_jump_by_parts_greater_rtx (mode, TREE_UNSIGNED (type),
target, op1, NULL_RTX, op0);
else
do_jump_by_parts_greater_rtx (mode, TREE_UNSIGNED (type),
op1, target, NULL_RTX, op0);
}
else
{
int unsignedp = TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 1)));
do_compare_rtx_and_jump (target, op1, code == MAX_EXPR ? GE : LE,
unsignedp, mode, NULL_RTX, NULL_RTX,
op0);
}
emit_rtx_feedback_counter (exp, 0, fdo_incoming);
emit_move_insn (target, op1);
emit_label (op0);
return target;
case BIT_NOT_EXPR:
op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
if (modifier == EXPAND_STACK_PARM)
target = 0;
temp = expand_unop (mode, one_cmpl_optab, op0, target, 1);
if (temp == 0)
abort ();
return temp;
case FFS_EXPR:
op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
if (modifier == EXPAND_STACK_PARM)
target = 0;
temp = expand_unop (mode, ffs_optab, op0, target, 1);
if (temp == 0)
abort ();
return temp;
case TRUTH_AND_EXPR:
case BIT_AND_EXPR:
this_optab = and_optab;
goto binop;
case TRUTH_OR_EXPR:
case BIT_IOR_EXPR:
this_optab = ior_optab;
goto binop;
case TRUTH_XOR_EXPR:
case BIT_XOR_EXPR:
this_optab = xor_optab;
goto binop;
case LSHIFT_EXPR:
case RSHIFT_EXPR:
case LROTATE_EXPR:
case RROTATE_EXPR:
if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1), 1))
subtarget = 0;
if (modifier == EXPAND_STACK_PARM)
target = 0;
op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
return expand_shift (code, mode, op0, TREE_OPERAND (exp, 1), target,
unsignedp);
case LT_EXPR:
case LE_EXPR:
case GT_EXPR:
case GE_EXPR:
case EQ_EXPR:
case NE_EXPR:
case UNORDERED_EXPR:
case ORDERED_EXPR:
case UNLT_EXPR:
case UNLE_EXPR:
case UNGT_EXPR:
case UNGE_EXPR:
case UNEQ_EXPR:
temp = do_store_flag (exp,
modifier != EXPAND_STACK_PARM ? target : NULL_RTX,
tmode != VOIDmode ? tmode : mode, 0);
if (temp != 0)
return temp;
if (code == NE_EXPR && integer_zerop (TREE_OPERAND (exp, 1))
&& original_target
&& GET_CODE (original_target) == REG
&& (GET_MODE (original_target)
== TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)))))
{
temp = expand_expr (TREE_OPERAND (exp, 0), original_target,
VOIDmode, 0);
if (GET_CODE (temp) == CONST_INT)
{
if (INTVAL (temp) != 0)
emit_move_insn (target, const1_rtx);
else
emit_move_insn (target, const0_rtx);
return target;
}
if (temp != original_target)
{
enum machine_mode mode1 = GET_MODE (temp);
if (mode1 == VOIDmode)
mode1 = tmode != VOIDmode ? tmode : mode;
temp = copy_to_mode_reg (mode1, temp);
}
op1 = gen_label_rtx ();
emit_cmp_and_jump_insns (temp, const0_rtx, EQ, NULL_RTX,
GET_MODE (temp), unsignedp, op1);
emit_move_insn (temp, const1_rtx);
emit_label (op1);
return temp;
}
case TRUTH_ANDIF_EXPR:
case TRUTH_ORIF_EXPR:
if (! ignore
&& (target == 0
|| modifier == EXPAND_STACK_PARM
|| ! safe_from_p (target, exp, 1)
|| (!optimize && GET_CODE (target) == REG
&& REGNO (target) < FIRST_PSEUDO_REGISTER)))
target = gen_reg_rtx (tmode != VOIDmode ? tmode : mode);
if (target)
emit_clr_insn (target);
op1 = gen_label_rtx ();
jumpifnot (exp, op1);
if (target)
emit_0_to_1_insn (target);
emit_label (op1);
return ignore ? const0_rtx : target;
case TRUTH_NOT_EXPR:
if (modifier == EXPAND_STACK_PARM)
target = 0;
op0 = expand_expr (TREE_OPERAND (exp, 0), target, VOIDmode, 0);
temp = expand_binop (mode, xor_optab, op0, const1_rtx,
target, 1, OPTAB_LIB_WIDEN);
if (temp == 0)
abort ();
return temp;
case COMPOUND_EXPR:
expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode, 0);
emit_queue ();
return expand_expr (TREE_OPERAND (exp, 1),
(ignore ? const0_rtx : target),
VOIDmode, modifier);
case COND_EXPR:
if (TREE_CODE (TREE_OPERAND (exp, 1)) == NOP_EXPR
&& TREE_CODE (TREE_OPERAND (exp, 2)) == NOP_EXPR
&& (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 1), 0))
== TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 2), 0))))
{
tree iftrue = TREE_OPERAND (TREE_OPERAND (exp, 1), 0);
tree iffalse = TREE_OPERAND (TREE_OPERAND (exp, 2), 0);
if ((TREE_CODE_CLASS (TREE_CODE (iftrue)) == '2'
&& operand_equal_p (iffalse, TREE_OPERAND (iftrue, 0), 0))
|| (TREE_CODE_CLASS (TREE_CODE (iffalse)) == '2'
&& operand_equal_p (iftrue, TREE_OPERAND (iffalse, 0), 0))
|| (TREE_CODE_CLASS (TREE_CODE (iftrue)) == '1'
&& operand_equal_p (iffalse, TREE_OPERAND (iftrue, 0), 0))
|| (TREE_CODE_CLASS (TREE_CODE (iffalse)) == '1'
&& operand_equal_p (iftrue, TREE_OPERAND (iffalse, 0), 0)))
{
tree t = build (COND_EXPR, TREE_TYPE (iftrue),
TREE_OPERAND (exp, 0), iftrue, iffalse);
clone_rtx_feedback_counter (exp, t);
return expand_expr (build1 (NOP_EXPR, type, t),
target, tmode, modifier);
}
}
{
tree singleton = 0;
tree binary_op = 0, unary_op = 0;
if (integer_onep (TREE_OPERAND (exp, 1))
&& integer_zerop (TREE_OPERAND (exp, 2))
&& TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, 0))) == '<')
{
if (ignore)
{
expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode,
modifier);
return const0_rtx;
}
if (modifier == EXPAND_STACK_PARM)
target = 0;
op0 = expand_expr (TREE_OPERAND (exp, 0), target, mode, modifier);
if (GET_MODE (op0) == mode)
return op0;
if (target == 0)
target = gen_reg_rtx (mode);
convert_move (target, op0, unsignedp);
return target;
}
if (TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, 1))) == '2'
&& operand_equal_p (TREE_OPERAND (exp, 2),
TREE_OPERAND (TREE_OPERAND (exp, 1), 0), 0))
singleton = TREE_OPERAND (exp, 2), binary_op = TREE_OPERAND (exp, 1);
else if (TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, 2))) == '2'
&& operand_equal_p (TREE_OPERAND (exp, 1),
TREE_OPERAND (TREE_OPERAND (exp, 2), 0), 0))
singleton = TREE_OPERAND (exp, 1), binary_op = TREE_OPERAND (exp, 2);
else if (TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, 1))) == '1'
&& operand_equal_p (TREE_OPERAND (exp, 2),
TREE_OPERAND (TREE_OPERAND (exp, 1), 0), 0))
singleton = TREE_OPERAND (exp, 2), unary_op = TREE_OPERAND (exp, 1);
else if (TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, 2))) == '1'
&& operand_equal_p (TREE_OPERAND (exp, 1),
TREE_OPERAND (TREE_OPERAND (exp, 2), 0), 0))
singleton = TREE_OPERAND (exp, 1), unary_op = TREE_OPERAND (exp, 2);
if (ignore)
temp = 0;
else if (modifier == EXPAND_STACK_PARM)
temp = assign_temp (type, 0, 0, 1);
else if (original_target
&& (safe_from_p (original_target, TREE_OPERAND (exp, 0), 1)
|| (singleton && GET_CODE (original_target) == REG
&& REGNO (original_target) >= FIRST_PSEUDO_REGISTER
&& original_target == var_rtx (singleton)))
&& GET_MODE (original_target) == mode
#ifdef HAVE_conditional_move
&& (! can_conditionally_move_p (mode)
|| GET_CODE (original_target) == REG
|| TREE_ADDRESSABLE (type))
#endif
&& (GET_CODE (original_target) != MEM
|| TREE_ADDRESSABLE (type)))
temp = original_target;
else if (TREE_ADDRESSABLE (type))
abort ();
else
temp = assign_temp (type, 0, 0, 1);
if (temp && singleton && binary_op
&& (TREE_CODE (binary_op) == PLUS_EXPR
|| TREE_CODE (binary_op) == MINUS_EXPR
|| TREE_CODE (binary_op) == BIT_IOR_EXPR
|| TREE_CODE (binary_op) == BIT_XOR_EXPR)
&& (BRANCH_COST >= 3 ? integer_pow2p (TREE_OPERAND (binary_op, 1))
: integer_onep (TREE_OPERAND (binary_op, 1)))
&& TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, 0))) == '<')
{
rtx result;
tree cond;
optab boptab = (TREE_CODE (binary_op) == PLUS_EXPR
? (TYPE_TRAP_SIGNED (TREE_TYPE (binary_op))
? addv_optab : add_optab)
: TREE_CODE (binary_op) == MINUS_EXPR
? (TYPE_TRAP_SIGNED (TREE_TYPE (binary_op))
? subv_optab : sub_optab)
: TREE_CODE (binary_op) == BIT_IOR_EXPR ? ior_optab
: xor_optab);
if (singleton == TREE_OPERAND (exp, 1))
cond = invert_truthvalue (TREE_OPERAND (exp, 0));
else
cond = TREE_OPERAND (exp, 0);
result = do_store_flag (cond, (safe_from_p (temp, singleton, 1)
? temp : NULL_RTX),
mode, BRANCH_COST <= 1);
if (result != 0 && ! integer_onep (TREE_OPERAND (binary_op, 1)))
result = expand_shift (LSHIFT_EXPR, mode, result,
build_int_2 (tree_log2
(TREE_OPERAND
(binary_op, 1)),
0),
(safe_from_p (temp, singleton, 1)
? temp : NULL_RTX), 0);
if (result)
{
op1 = expand_expr (singleton, NULL_RTX, VOIDmode, 0);
return expand_binop (mode, boptab, op1, result, temp,
unsignedp, OPTAB_LIB_WIDEN);
}
}
do_pending_stack_adjust ();
NO_DEFER_POP;
op0 = gen_label_rtx ();
if (singleton && ! TREE_SIDE_EFFECTS (TREE_OPERAND (exp, 0)))
{
if (temp != 0)
{
if ((binary_op
&& ! safe_from_p (temp, TREE_OPERAND (binary_op, 1), 1))
|| (GET_CODE (temp) == REG
&& REGNO (temp) < FIRST_PSEUDO_REGISTER))
temp = gen_reg_rtx (mode);
store_expr (singleton, temp,
modifier == EXPAND_STACK_PARM ? 2 : 0);
}
else
expand_expr (singleton,
ignore ? const0_rtx : NULL_RTX, VOIDmode, 0);
if (singleton == TREE_OPERAND (exp, 1))
jumpif (TREE_OPERAND (exp, 0), op0);
else
jumpifnot (TREE_OPERAND (exp, 0), op0);
emit_rtx_feedback_counter (exp, 0, fdo_block);
start_cleanup_deferral ();
if (binary_op && temp == 0)
expand_expr (TREE_OPERAND (binary_op, 1),
ignore ? const0_rtx : NULL_RTX, VOIDmode, 0);
else if (binary_op)
store_expr (build (TREE_CODE (binary_op), type,
make_tree (type, temp),
TREE_OPERAND (binary_op, 1)),
temp, modifier == EXPAND_STACK_PARM ? 2 : 0);
else
store_expr (build1 (TREE_CODE (unary_op), type,
make_tree (type, temp)),
temp, modifier == EXPAND_STACK_PARM ? 2 : 0);
op1 = op0;
}
else if (temp
&& !(flag_use_feedback || flag_create_feedback)
&& TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, 0))) == '<'
&& 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_CODE (TREE_OPERAND (exp, 1)) == SAVE_EXPR)
&& safe_from_p (temp, TREE_OPERAND (exp, 2), 1))
{
if (GET_CODE (temp) == REG
&& REGNO (temp) < FIRST_PSEUDO_REGISTER)
temp = gen_reg_rtx (mode);
store_expr (TREE_OPERAND (exp, 1), temp,
modifier == EXPAND_STACK_PARM ? 2 : 0);
jumpif (TREE_OPERAND (exp, 0), op0);
emit_rtx_feedback_counter (exp, 0, fdo_block);
start_cleanup_deferral ();
store_expr (TREE_OPERAND (exp, 2), temp,
modifier == EXPAND_STACK_PARM ? 2 : 0);
op1 = op0;
}
else if (temp
&& !(flag_use_feedback || flag_create_feedback)
&& TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, 0))) == '<'
&& 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_CODE (TREE_OPERAND (exp, 2)) == SAVE_EXPR)
&& safe_from_p (temp, TREE_OPERAND (exp, 1), 1))
{
if (GET_CODE (temp) == REG
&& REGNO (temp) < FIRST_PSEUDO_REGISTER)
temp = gen_reg_rtx (mode);
store_expr (TREE_OPERAND (exp, 2), temp,
modifier == EXPAND_STACK_PARM ? 2 : 0);
jumpifnot (TREE_OPERAND (exp, 0), op0);
emit_rtx_feedback_counter (exp, 0, fdo_block);
start_cleanup_deferral ();
store_expr (TREE_OPERAND (exp, 1), temp,
modifier == EXPAND_STACK_PARM ? 2 : 0);
op1 = op0;
}
else
{
op1 = gen_label_rtx ();
jumpifnot (TREE_OPERAND (exp, 0), op0);
emit_rtx_feedback_counter (exp, 0, fdo_block);
start_cleanup_deferral ();
if (temp != 0
&& TREE_TYPE (TREE_OPERAND (exp, 1)) != void_type_node)
store_expr (TREE_OPERAND (exp, 1), temp,
modifier == EXPAND_STACK_PARM ? 2 : 0);
else
expand_expr (TREE_OPERAND (exp, 1),
ignore ? const0_rtx : NULL_RTX, VOIDmode, 0);
end_cleanup_deferral ();
emit_queue ();
emit_jump_insn (gen_jump (op1));
emit_barrier ();
emit_label (op0);
start_cleanup_deferral ();
if (temp != 0
&& TREE_TYPE (TREE_OPERAND (exp, 2)) != void_type_node)
store_expr (TREE_OPERAND (exp, 2), temp,
modifier == EXPAND_STACK_PARM ? 2 : 0);
else
expand_expr (TREE_OPERAND (exp, 2),
ignore ? const0_rtx : NULL_RTX, VOIDmode, 0);
}
end_cleanup_deferral ();
emit_queue ();
emit_label (op1);
OK_DEFER_POP;
return temp;
}
case TARGET_EXPR:
{
tree slot = TREE_OPERAND (exp, 0);
tree cleanups = NULL_TREE;
tree exp1;
if (TREE_CODE (slot) != VAR_DECL)
abort ();
if (! ignore)
target = original_target;
TREE_USED (slot) = 1;
if (target == 0)
{
if (DECL_RTL_SET_P (slot))
{
target = DECL_RTL (slot);
if (TREE_OPERAND (exp, 1) == NULL_TREE)
return target;
}
else
{
target = assign_temp (type, 2, 0, 1);
preserve_temp_slots (target);
SET_DECL_RTL (slot, target);
if (TREE_ADDRESSABLE (slot))
put_var_into_stack (slot);
if (TREE_OPERAND (exp, 2) == 0)
TREE_OPERAND (exp, 2)
= (*lang_hooks.maybe_build_cleanup) (slot);
cleanups = TREE_OPERAND (exp, 2);
}
}
else
{
if (DECL_RTL_SET_P (slot))
{
target = DECL_RTL (slot);
if (TREE_OPERAND (exp, 1) == NULL_TREE)
return target;
}
else
{
SET_DECL_RTL (slot, target);
if (TREE_ADDRESSABLE (slot))
put_var_into_stack (slot);
}
}
exp1 = TREE_OPERAND (exp, 3) = TREE_OPERAND (exp, 1);
TREE_OPERAND (exp, 1) = NULL_TREE;
store_expr (exp1, target, modifier == EXPAND_STACK_PARM ? 2 : 0);
expand_decl_cleanup_eh (NULL_TREE, cleanups, CLEANUP_EH_ONLY (exp));
return target;
}
case INIT_EXPR:
{
tree lhs = TREE_OPERAND (exp, 0);
tree rhs = TREE_OPERAND (exp, 1);
temp = expand_assignment (lhs, rhs, ! ignore, original_target != 0);
return temp;
}
case MODIFY_EXPR:
{
tree lhs = TREE_OPERAND (exp, 0);
tree rhs = TREE_OPERAND (exp, 1);
temp = 0;
if (ignore
&& TREE_CODE (lhs) == COMPONENT_REF
&& (TREE_CODE (rhs) == BIT_IOR_EXPR
|| TREE_CODE (rhs) == BIT_AND_EXPR)
&& TREE_OPERAND (rhs, 0) == lhs
&& TREE_CODE (TREE_OPERAND (rhs, 1)) == COMPONENT_REF
&& integer_onep (DECL_SIZE (TREE_OPERAND (lhs, 1)))
&& integer_onep (DECL_SIZE (TREE_OPERAND (TREE_OPERAND (rhs, 1), 1))))
{
rtx label = gen_label_rtx ();
do_jump (TREE_OPERAND (rhs, 1),
TREE_CODE (rhs) == BIT_IOR_EXPR ? label : 0,
TREE_CODE (rhs) == BIT_AND_EXPR ? label : 0);
expand_assignment (lhs, convert (TREE_TYPE (rhs),
(TREE_CODE (rhs) == BIT_IOR_EXPR
? integer_one_node
: integer_zero_node)),
0, 0);
do_pending_stack_adjust ();
emit_label (label);
return const0_rtx;
}
temp = expand_assignment (lhs, rhs, ! ignore, original_target != 0);
return temp;
}
case RETURN_EXPR:
if (!TREE_OPERAND (exp, 0))
expand_null_return ();
else
expand_return (TREE_OPERAND (exp, 0));
return const0_rtx;
case PREINCREMENT_EXPR:
case PREDECREMENT_EXPR:
return expand_increment (exp, 0, ignore);
case POSTINCREMENT_EXPR:
case POSTDECREMENT_EXPR:
return expand_increment (exp, ! ignore, ignore);
case ADDR_EXPR:
if (modifier == EXPAND_STACK_PARM)
target = 0;
if (TREE_CODE (TREE_OPERAND (exp, 0)) == FUNCTION_DECL
&& decl_function_context (TREE_OPERAND (exp, 0)) != 0
&& ! DECL_NO_STATIC_CHAIN (TREE_OPERAND (exp, 0))
&& ! TREE_STATIC (exp))
{
op0 = trampoline_address (TREE_OPERAND (exp, 0));
op0 = force_operand (op0, target);
}
else if (TREE_CODE (TREE_OPERAND (exp, 0)) == ERROR_MARK)
return const0_rtx;
else if (cfun == 0
&& (TREE_CODE (TREE_OPERAND (exp, 0)) == CONSTRUCTOR
|| (TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, 0)))
== 'c')))
op0 = XEXP (output_constant_def (TREE_OPERAND (exp, 0), 0), 0);
else
{
op0 = expand_expr (TREE_OPERAND (exp, 0),
ignore ? const0_rtx : NULL_RTX, VOIDmode,
(modifier == EXPAND_INITIALIZER
? modifier : EXPAND_CONST_ADDRESS));
if (ignore)
return op0;
op0 = protect_from_queue (op0, 1);
if (CONSTANT_P (op0))
op0 = force_const_mem (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))),
op0);
else if (GET_CODE (op0) == REG || GET_CODE (op0) == SUBREG
|| GET_CODE (op0) == CONCAT || GET_CODE (op0) == ADDRESSOF
|| GET_CODE (op0) == PARALLEL)
{
if (TREE_CODE (TREE_OPERAND (exp, 0)) == SAVE_EXPR)
{
put_var_into_stack (TREE_OPERAND (exp, 0));
op0 = SAVE_EXPR_RTL (TREE_OPERAND (exp, 0));
}
else
{
tree inner_type = TREE_TYPE (TREE_OPERAND (exp, 0));
rtx memloc = assign_temp (inner_type, 1, 1, 1);
if (GET_CODE (op0) == PARALLEL)
emit_group_store (memloc, op0,
int_size_in_bytes (inner_type));
else
emit_move_insn (memloc, op0);
op0 = memloc;
}
}
if (GET_CODE (op0) != MEM)
abort ();
mark_temp_addr_taken (op0);
if (modifier == EXPAND_SUM || modifier == EXPAND_INITIALIZER)
{
op0 = XEXP (op0, 0);
#ifdef POINTERS_EXTEND_UNSIGNED
if (GET_MODE (op0) == Pmode && GET_MODE (op0) != mode
&& mode == ptr_mode)
op0 = convert_memory_address (ptr_mode, op0);
#endif
return op0;
}
if (STRICT_ALIGNMENT && GET_MODE (op0) == BLKmode
&& (TYPE_ALIGN (TREE_TYPE (TREE_OPERAND (exp, 0)))
> MEM_ALIGN (op0))
&& MEM_ALIGN (op0) < BIGGEST_ALIGNMENT)
{
tree inner_type = TREE_TYPE (TREE_OPERAND (exp, 0));
rtx new
= assign_stack_temp_for_type
(TYPE_MODE (inner_type),
MEM_SIZE (op0) ? INTVAL (MEM_SIZE (op0))
: int_size_in_bytes (inner_type),
1, build_qualified_type (inner_type,
(TYPE_QUALS (inner_type)
| TYPE_QUAL_CONST)));
if (TYPE_ALIGN_OK (inner_type))
abort ();
emit_block_move (new, op0, expr_size (TREE_OPERAND (exp, 0)),
(modifier == EXPAND_STACK_PARM
? BLOCK_OP_CALL_PARM : BLOCK_OP_NORMAL));
op0 = new;
}
op0 = force_operand (XEXP (op0, 0), target);
}
if (flag_force_addr
&& GET_CODE (op0) != REG
&& modifier != EXPAND_CONST_ADDRESS
&& modifier != EXPAND_INITIALIZER
&& modifier != EXPAND_SUM)
op0 = force_reg (Pmode, op0);
if (GET_CODE (op0) == REG
&& ! REG_USERVAR_P (op0))
mark_reg_pointer (op0, TYPE_ALIGN (TREE_TYPE (type)));
#ifdef POINTERS_EXTEND_UNSIGNED
if (GET_MODE (op0) == Pmode && GET_MODE (op0) != mode
&& mode == ptr_mode)
op0 = convert_memory_address (ptr_mode, op0);
#endif
return op0;
case ENTRY_VALUE_EXPR:
abort ();
case COMPLEX_EXPR:
{
enum machine_mode mode = TYPE_MODE (TREE_TYPE (TREE_TYPE (exp)));
rtx insns;
op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0);
op1 = expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, 0);
if (! target)
target = gen_reg_rtx (TYPE_MODE (TREE_TYPE (exp)));
start_sequence ();
emit_move_insn (gen_realpart (mode, target), op0);
emit_move_insn (gen_imagpart (mode, target), op1);
insns = get_insns ();
end_sequence ();
if (GET_CODE (target) != CONCAT)
emit_no_conflict_block (insns, target, op0, op1, NULL_RTX);
else
emit_insn (insns);
return target;
}
case REALPART_EXPR:
op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0);
return gen_realpart (mode, op0);
case IMAGPART_EXPR:
op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0);
return gen_imagpart (mode, op0);
case CONJ_EXPR:
{
enum machine_mode partmode = TYPE_MODE (TREE_TYPE (TREE_TYPE (exp)));
rtx imag_t;
rtx insns;
op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0);
if (! target)
target = gen_reg_rtx (mode);
start_sequence ();
emit_move_insn (gen_realpart (partmode, target),
gen_realpart (partmode, op0));
imag_t = gen_imagpart (partmode, target);
temp = expand_unop (partmode,
! unsignedp && flag_trapv
&& (GET_MODE_CLASS(partmode) == MODE_INT)
? negv_optab : neg_optab,
gen_imagpart (partmode, op0), imag_t, 0);
if (temp != imag_t)
emit_move_insn (imag_t, temp);
insns = get_insns ();
end_sequence ();
if (GET_CODE (target) != CONCAT)
emit_no_conflict_block (insns, target, op0, NULL_RTX, NULL_RTX);
else
emit_insn (insns);
return target;
}
case TRY_CATCH_EXPR:
{
tree handler = TREE_OPERAND (exp, 1);
expand_eh_region_start ();
op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0);
expand_eh_region_end_cleanup (handler);
return op0;
}
case TRY_FINALLY_EXPR:
{
tree try_block = TREE_OPERAND (exp, 0);
tree finally_block = TREE_OPERAND (exp, 1);
if (!optimize || unsafe_for_reeval (finally_block) > 1)
{
rtx finally_label = gen_label_rtx ();
rtx done_label = gen_label_rtx ();
rtx return_link = gen_reg_rtx (Pmode);
tree cleanup = build (GOTO_SUBROUTINE_EXPR, void_type_node,
(tree) finally_label, (tree) return_link);
TREE_SIDE_EFFECTS (cleanup) = 1;
expand_start_bindings (2);
target_temp_slot_level = temp_slot_level;
expand_decl_cleanup (NULL_TREE, cleanup);
op0 = expand_expr (try_block, target, tmode, modifier);
preserve_temp_slots (op0);
expand_end_bindings (NULL_TREE, 0, 0);
emit_jump (done_label);
emit_label (finally_label);
expand_expr (finally_block, const0_rtx, VOIDmode, 0);
emit_indirect_jump (return_link);
emit_label (done_label);
}
else
{
expand_start_bindings (2);
target_temp_slot_level = temp_slot_level;
expand_decl_cleanup (NULL_TREE, finally_block);
op0 = expand_expr (try_block, target, tmode, modifier);
preserve_temp_slots (op0);
expand_end_bindings (NULL_TREE, 0, 0);
}
return op0;
}
case GOTO_SUBROUTINE_EXPR:
{
rtx subr = (rtx) TREE_OPERAND (exp, 0);
rtx return_link = *(rtx *) &TREE_OPERAND (exp, 1);
rtx return_address = gen_label_rtx ();
emit_move_insn (return_link,
gen_rtx_LABEL_REF (Pmode, return_address));
emit_jump (subr);
emit_label (return_address);
return const0_rtx;
}
case VA_ARG_EXPR:
return expand_builtin_va_arg (TREE_OPERAND (exp, 0), type);
case EXC_PTR_EXPR:
return get_exception_pointer (cfun);
case FDESC_EXPR:
abort ();
default:
return (*lang_hooks.expand_expr) (exp, original_target, tmode, modifier);
}
binop:
if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1), 1))
subtarget = 0;
op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, 0);
binop2:
if (modifier == EXPAND_STACK_PARM)
target = 0;
temp = expand_binop (mode, this_optab, op0, op1, target,
unsignedp, OPTAB_LIB_WIDEN);
if (temp == 0)
abort ();
return temp;
}
static int
is_aligning_offset (offset, exp)
tree offset;
tree exp;
{
while (TREE_CODE (offset) == NON_LVALUE_EXPR
|| TREE_CODE (offset) == NOP_EXPR
|| TREE_CODE (offset) == CONVERT_EXPR
|| TREE_CODE (offset) == WITH_RECORD_EXPR)
offset = TREE_OPERAND (offset, 0);
if (TREE_CODE (offset) != BIT_AND_EXPR
|| !host_integerp (TREE_OPERAND (offset, 1), 1)
|| compare_tree_int (TREE_OPERAND (offset, 1), BIGGEST_ALIGNMENT) <= 0
|| !exact_log2 (tree_low_cst (TREE_OPERAND (offset, 1), 1) + 1) < 0)
return 0;
offset = TREE_OPERAND (offset, 0);
while (TREE_CODE (offset) == NON_LVALUE_EXPR
|| TREE_CODE (offset) == NOP_EXPR
|| TREE_CODE (offset) == CONVERT_EXPR)
offset = TREE_OPERAND (offset, 0);
if (TREE_CODE (offset) != NEGATE_EXPR)
return 0;
offset = TREE_OPERAND (offset, 0);
while (TREE_CODE (offset) == NON_LVALUE_EXPR
|| TREE_CODE (offset) == NOP_EXPR
|| TREE_CODE (offset) == CONVERT_EXPR)
offset = TREE_OPERAND (offset, 0);
return (TREE_CODE (offset) == ADDR_EXPR
&& (TREE_OPERAND (offset, 0) == exp
|| (TREE_CODE (TREE_OPERAND (offset, 0)) == PLACEHOLDER_EXPR
&& (TREE_TYPE (TREE_OPERAND (offset, 0))
== TREE_TYPE (exp)))));
}
tree
string_constant (arg, ptr_offset)
tree arg;
tree *ptr_offset;
{
STRIP_NOPS (arg);
if (TREE_CODE (arg) == ADDR_EXPR
&& TREE_CODE (TREE_OPERAND (arg, 0)) == STRING_CST)
{
*ptr_offset = size_zero_node;
return TREE_OPERAND (arg, 0);
}
else if (TREE_CODE (arg) == PLUS_EXPR)
{
tree arg0 = TREE_OPERAND (arg, 0);
tree arg1 = TREE_OPERAND (arg, 1);
STRIP_NOPS (arg0);
STRIP_NOPS (arg1);
if (TREE_CODE (arg0) == ADDR_EXPR
&& TREE_CODE (TREE_OPERAND (arg0, 0)) == STRING_CST)
{
*ptr_offset = convert (sizetype, arg1);
return TREE_OPERAND (arg0, 0);
}
else if (TREE_CODE (arg1) == ADDR_EXPR
&& TREE_CODE (TREE_OPERAND (arg1, 0)) == STRING_CST)
{
*ptr_offset = convert (sizetype, arg0);
return TREE_OPERAND (arg1, 0);
}
}
return 0;
}
static rtx
expand_increment (exp, post, ignore)
tree exp;
int post, ignore;
{
rtx op0, op1;
rtx temp, value;
tree incremented = TREE_OPERAND (exp, 0);
optab this_optab = add_optab;
int icode;
enum machine_mode mode = TYPE_MODE (TREE_TYPE (exp));
int op0_is_copy = 0;
int single_insn = 0;
int bad_subreg = 0;
if (!post
|| TREE_CODE (incremented) == BIT_FIELD_REF
|| (TREE_CODE (incremented) == COMPONENT_REF
&& (TREE_CODE (TREE_OPERAND (incremented, 0)) != INDIRECT_REF
|| DECL_BIT_FIELD (TREE_OPERAND (incremented, 1)))))
incremented = stabilize_reference (incremented);
if (TREE_CODE (incremented) == PREINCREMENT_EXPR
|| TREE_CODE (incremented) == PREDECREMENT_EXPR)
incremented = save_expr (incremented);
temp = get_last_insn ();
op0 = expand_expr (incremented, NULL_RTX, VOIDmode, 0);
if (GET_CODE (op0) == SUBREG && SUBREG_PROMOTED_VAR_P (op0))
{
if (post)
SUBREG_REG (op0) = copy_to_reg (SUBREG_REG (op0));
else
bad_subreg = 1;
}
else if (GET_CODE (op0) == SUBREG
&& GET_MODE_BITSIZE (GET_MODE (op0)) < BITS_PER_WORD)
{
if (post)
op0 = copy_to_reg (op0);
else
bad_subreg = 1;
}
op0_is_copy = ((GET_CODE (op0) == SUBREG || GET_CODE (op0) == REG)
&& temp != get_last_insn ());
op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, 0);
if (TREE_CODE (exp) == POSTDECREMENT_EXPR
|| TREE_CODE (exp) == PREDECREMENT_EXPR)
this_optab = sub_optab;
if (this_optab == sub_optab
&& GET_CODE (op1) == CONST_INT)
{
op1 = GEN_INT (-INTVAL (op1));
this_optab = add_optab;
}
if (TYPE_TRAP_SIGNED (TREE_TYPE (exp)))
this_optab = this_optab == add_optab ? addv_optab : subv_optab;
if (!post)
{
icode = (int) this_optab->handlers[(int) mode].insn_code;
if (icode != (int) CODE_FOR_nothing
&& (*insn_data[icode].operand[0].predicate) (op0, mode)
&& (*insn_data[icode].operand[1].predicate) (op0, mode)
&& (*insn_data[icode].operand[2].predicate) (op1, mode))
single_insn = 1;
}
if (op0_is_copy || (!post && !single_insn) || bad_subreg)
{
tree newexp = build (((TREE_CODE (exp) == POSTDECREMENT_EXPR
|| TREE_CODE (exp) == PREDECREMENT_EXPR)
? MINUS_EXPR : PLUS_EXPR),
TREE_TYPE (exp),
incremented,
TREE_OPERAND (exp, 1));
while (TREE_CODE (incremented) == NOP_EXPR
|| TREE_CODE (incremented) == CONVERT_EXPR)
{
newexp = convert (TREE_TYPE (incremented), newexp);
incremented = TREE_OPERAND (incremented, 0);
}
temp = expand_assignment (incremented, newexp, ! post && ! ignore , 0);
return post ? op0 : temp;
}
if (post)
{
#if 0
op0 = stabilize (op0);
#endif
icode = (int) this_optab->handlers[(int) mode].insn_code;
if (icode != (int) CODE_FOR_nothing
&& (*insn_data[icode].operand[0].predicate) (op0, mode)
&& (*insn_data[icode].operand[1].predicate) (op0, mode))
{
if (! (*insn_data[icode].operand[2].predicate) (op1, mode))
op1 = force_reg (mode, op1);
return enqueue_insn (op0, GEN_FCN (icode) (op0, op0, op1));
}
if (icode != (int) CODE_FOR_nothing && GET_CODE (op0) == MEM)
{
rtx addr = (general_operand (XEXP (op0, 0), mode)
? force_reg (Pmode, XEXP (op0, 0))
: copy_to_reg (XEXP (op0, 0)));
rtx temp, result;
op0 = replace_equiv_address (op0, addr);
temp = force_reg (GET_MODE (op0), op0);
if (! (*insn_data[icode].operand[2].predicate) (op1, mode))
op1 = force_reg (mode, op1);
enqueue_insn (op0, gen_move_insn (op0, temp));
result = enqueue_insn (temp, GEN_FCN (icode) (temp, temp, op1));
return result;
}
}
if (post)
temp = value = copy_to_reg (op0);
else
temp = copy_rtx (value = op0);
op1 = expand_binop (mode, this_optab, value, op1, op0,
TREE_UNSIGNED (TREE_TYPE (exp)), OPTAB_LIB_WIDEN);
if (op1 != op0)
emit_move_insn (op0, op1);
return temp;
}
void
init_pending_stack_adjust ()
{
pending_stack_adjust = 0;
}
void
clear_pending_stack_adjust ()
{
#ifdef EXIT_IGNORE_STACK
if (optimize > 0
&& (! flag_omit_frame_pointer || current_function_calls_alloca)
&& EXIT_IGNORE_STACK
&& ! (DECL_INLINE (current_function_decl) && ! flag_no_inline)
&& ! flag_inline_functions)
{
stack_pointer_delta -= pending_stack_adjust,
pending_stack_adjust = 0;
}
#endif
}
void
do_pending_stack_adjust ()
{
if (inhibit_defer_pop == 0)
{
if (pending_stack_adjust != 0)
adjust_stack (GEN_INT (pending_stack_adjust));
pending_stack_adjust = 0;
}
}
void
jumpifnot (exp, label)
tree exp;
rtx label;
{
do_jump (exp, label, NULL_RTX);
}
void
jumpif (exp, label)
tree exp;
rtx label;
{
do_jump (exp, NULL_RTX, label);
}
void
do_jump (exp, if_false_label, if_true_label)
tree exp;
rtx if_false_label, if_true_label;
{
enum tree_code code = TREE_CODE (exp);
rtx drop_through_label = 0;
rtx temp;
int i;
tree type;
enum machine_mode mode;
#ifdef MAX_INTEGER_COMPUTATION_MODE
check_max_integer_computation_mode (exp);
#endif
emit_queue ();
switch (code)
{
case ERROR_MARK:
break;
case INTEGER_CST:
temp = integer_zerop (exp) ? if_false_label : if_true_label;
if (temp)
emit_jump (temp);
break;
#if 0
case ADDR_EXPR:
if (if_true_label)
emit_jump (if_true_label);
break;
#endif
case NOP_EXPR:
if (TREE_CODE (TREE_OPERAND (exp, 0)) == COMPONENT_REF
|| TREE_CODE (TREE_OPERAND (exp, 0)) == BIT_FIELD_REF
|| TREE_CODE (TREE_OPERAND (exp, 0)) == ARRAY_REF
|| TREE_CODE (TREE_OPERAND (exp, 0)) == ARRAY_RANGE_REF)
goto normal;
case CONVERT_EXPR:
if ((TYPE_PRECISION (TREE_TYPE (exp))
< TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (exp, 0)))))
goto normal;
case NON_LVALUE_EXPR:
case REFERENCE_EXPR:
case ABS_EXPR:
case NEGATE_EXPR:
case LROTATE_EXPR:
case RROTATE_EXPR:
do_jump (TREE_OPERAND (exp, 0), if_false_label, if_true_label);
break;
case WITH_RECORD_EXPR:
placeholder_list = tree_cons (TREE_OPERAND (exp, 1), NULL_TREE,
placeholder_list);
do_jump (TREE_OPERAND (exp, 0), if_false_label, if_true_label);
placeholder_list = TREE_CHAIN (placeholder_list);
break;
#if 0
case PLUS_EXPR:
exp = build (MINUS_EXPR, TREE_TYPE (exp),
TREE_OPERAND (exp, 0),
fold (build1 (NEGATE_EXPR, TREE_TYPE (TREE_OPERAND (exp, 1)),
TREE_OPERAND (exp, 1))));
#endif
case MINUS_EXPR:
do_compare_and_jump_1 (build (NE_EXPR, TREE_TYPE (exp),
TREE_OPERAND (exp, 0),
TREE_OPERAND (exp, 1)),
NE, NE, if_false_label, if_true_label);
break;
case BIT_AND_EXPR:
if (! SLOW_BYTE_ACCESS
&& TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST
&& TYPE_PRECISION (TREE_TYPE (exp)) <= HOST_BITS_PER_WIDE_INT
&& (i = tree_floor_log2 (TREE_OPERAND (exp, 1))) >= 0
&& (mode = mode_for_size (i + 1, MODE_INT, 0)) != BLKmode
&& (type = (*lang_hooks.types.type_for_mode) (mode, 1)) != 0
&& TYPE_PRECISION (type) < TYPE_PRECISION (TREE_TYPE (exp))
&& (cmp_optab->handlers[(int) TYPE_MODE (type)].insn_code
!= CODE_FOR_nothing))
{
do_jump (convert (type, exp), if_false_label, if_true_label);
break;
}
goto normal;
case TRUTH_NOT_EXPR:
do_jump (TREE_OPERAND (exp, 0), if_true_label, if_false_label);
break;
case TRUTH_ANDIF_EXPR:
if (if_false_label == 0)
if_false_label = drop_through_label = gen_label_rtx ();
do_jump (TREE_OPERAND (exp, 0), if_false_label, NULL_RTX);
emit_rtx_feedback_counter (exp, 0, fdo_block);
start_cleanup_deferral ();
if (if_true_label)
{
do_jump (TREE_OPERAND (exp, 1), NULL_RTX, if_true_label);
emit_rtx_feedback_counter (exp, 1, fdo_block);
emit_jump (if_false_label);
}
else
{
do_jump (TREE_OPERAND (exp, 1), if_false_label, NULL_RTX);
emit_rtx_feedback_counter (exp, 1, fdo_block);
}
end_cleanup_deferral ();
break;
case TRUTH_ORIF_EXPR:
if (if_true_label == 0)
if_true_label = drop_through_label = gen_label_rtx ();
do_jump (TREE_OPERAND (exp, 0), NULL_RTX, if_true_label);
emit_rtx_feedback_counter (exp, 0, fdo_block);
start_cleanup_deferral ();
do_jump (TREE_OPERAND (exp, 1), NULL_RTX, if_true_label);
emit_rtx_feedback_counter (exp, 1, fdo_block);
if (if_false_label)
emit_jump (if_false_label);
end_cleanup_deferral ();
break;
case COMPOUND_EXPR:
push_temp_slots ();
expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode, 0);
preserve_temp_slots (NULL_RTX);
free_temp_slots ();
pop_temp_slots ();
emit_queue ();
do_pending_stack_adjust ();
do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label);
break;
case COMPONENT_REF:
case BIT_FIELD_REF:
case ARRAY_REF:
case ARRAY_RANGE_REF:
{
HOST_WIDE_INT bitsize, bitpos;
int unsignedp;
enum machine_mode mode;
tree type;
tree offset;
int volatilep = 0;
get_inner_reference (exp, &bitsize, &bitpos, &offset, &mode,
&unsignedp, &volatilep);
type = (*lang_hooks.types.type_for_size) (bitsize, unsignedp);
if (! SLOW_BYTE_ACCESS
&& type != 0 && bitsize >= 0
&& TYPE_PRECISION (type) < TYPE_PRECISION (TREE_TYPE (exp))
&& (cmp_optab->handlers[(int) TYPE_MODE (type)].insn_code
!= CODE_FOR_nothing))
{
do_jump (convert (type, exp), if_false_label, if_true_label);
break;
}
goto normal;
}
case COND_EXPR:
if (integer_onep (TREE_OPERAND (exp, 1))
&& integer_zerop (TREE_OPERAND (exp, 2)))
do_jump (TREE_OPERAND (exp, 0), if_false_label, if_true_label);
else if (integer_zerop (TREE_OPERAND (exp, 1))
&& integer_onep (TREE_OPERAND (exp, 2)))
do_jump (TREE_OPERAND (exp, 0), if_true_label, if_false_label);
else
{
rtx label1 = gen_label_rtx ();
drop_through_label = gen_label_rtx ();
do_jump (TREE_OPERAND (exp, 0), label1, NULL_RTX);
emit_rtx_feedback_counter (exp, 0, fdo_block);
start_cleanup_deferral ();
do_jump (TREE_OPERAND (exp, 1),
if_false_label ? if_false_label : drop_through_label,
NULL_RTX);
emit_rtx_feedback_counter (exp, 2, fdo_block);
emit_jump (if_true_label ? if_true_label : drop_through_label);
do_pending_stack_adjust ();
emit_label (label1);
emit_rtx_feedback_counter (exp, 1, fdo_block);
if (if_false_label)
{
do_jump (TREE_OPERAND (exp, 2),
if_false_label, NULL_RTX);
emit_rtx_feedback_counter (exp, 3, fdo_block);
if (if_true_label)
emit_jump (if_true_label);
}
else
{
do_jump (TREE_OPERAND (exp, 2),
drop_through_label, if_true_label);
emit_rtx_feedback_counter (exp, 3, fdo_block);
}
end_cleanup_deferral ();
}
break;
case EQ_EXPR:
{
tree inner_type = TREE_TYPE (TREE_OPERAND (exp, 0));
if (GET_MODE_CLASS (TYPE_MODE (inner_type)) == MODE_COMPLEX_FLOAT
|| GET_MODE_CLASS (TYPE_MODE (inner_type)) == MODE_COMPLEX_INT)
{
tree exp0 = save_expr (TREE_OPERAND (exp, 0));
tree exp1 = save_expr (TREE_OPERAND (exp, 1));
do_jump
(fold
(build (TRUTH_ANDIF_EXPR, TREE_TYPE (exp),
fold (build (EQ_EXPR, TREE_TYPE (exp),
fold (build1 (REALPART_EXPR,
TREE_TYPE (inner_type),
exp0)),
fold (build1 (REALPART_EXPR,
TREE_TYPE (inner_type),
exp1)))),
fold (build (EQ_EXPR, TREE_TYPE (exp),
fold (build1 (IMAGPART_EXPR,
TREE_TYPE (inner_type),
exp0)),
fold (build1 (IMAGPART_EXPR,
TREE_TYPE (inner_type),
exp1)))))),
if_false_label, if_true_label);
}
else if (integer_zerop (TREE_OPERAND (exp, 1)))
{
if (if_false_label && if_true_label)
{
do_jump (TREE_OPERAND (exp, 0), NULL_RTX, if_false_label);
emit_rtx_feedback_counter (exp, 0, fdo_block);
emit_jump (if_true_label);
}
else
{
do_jump (TREE_OPERAND (exp, 0), if_true_label, if_false_label);
emit_rtx_feedback_counter (exp, 0, fdo_block);
}
}
else if (GET_MODE_CLASS (TYPE_MODE (inner_type)) == MODE_INT
&& !can_compare_p (EQ, TYPE_MODE (inner_type), ccp_jump))
do_jump_by_parts_equality (exp, if_false_label, if_true_label);
else
do_compare_and_jump (exp, EQ, EQ, if_false_label, if_true_label);
break;
}
case NE_EXPR:
{
tree inner_type = TREE_TYPE (TREE_OPERAND (exp, 0));
if (GET_MODE_CLASS (TYPE_MODE (inner_type)) == MODE_COMPLEX_FLOAT
|| GET_MODE_CLASS (TYPE_MODE (inner_type)) == MODE_COMPLEX_INT)
{
tree exp0 = save_expr (TREE_OPERAND (exp, 0));
tree exp1 = save_expr (TREE_OPERAND (exp, 1));
do_jump
(fold
(build (TRUTH_ORIF_EXPR, TREE_TYPE (exp),
fold (build (NE_EXPR, TREE_TYPE (exp),
fold (build1 (REALPART_EXPR,
TREE_TYPE (inner_type),
exp0)),
fold (build1 (REALPART_EXPR,
TREE_TYPE (inner_type),
exp1)))),
fold (build (NE_EXPR, TREE_TYPE (exp),
fold (build1 (IMAGPART_EXPR,
TREE_TYPE (inner_type),
exp0)),
fold (build1 (IMAGPART_EXPR,
TREE_TYPE (inner_type),
exp1)))))),
if_false_label, if_true_label);
}
else if (integer_zerop (TREE_OPERAND (exp, 1)))
{
if (if_true_label && if_false_label)
{
do_jump (TREE_OPERAND (exp, 0), NULL_RTX, if_true_label);
emit_rtx_feedback_counter (exp, 0, fdo_block);
emit_jump (if_false_label);
}
else
{
do_jump (TREE_OPERAND (exp, 0), if_false_label, if_true_label); emit_rtx_feedback_counter (exp, 0, fdo_block);
}
}
else if (GET_MODE_CLASS (TYPE_MODE (inner_type)) == MODE_INT
&& !can_compare_p (NE, TYPE_MODE (inner_type), ccp_jump))
do_jump_by_parts_equality (exp, if_true_label, if_false_label);
else
do_compare_and_jump (exp, NE, NE, if_false_label, if_true_label);
break;
}
case LT_EXPR:
mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
if (GET_MODE_CLASS (mode) == MODE_INT
&& ! can_compare_p (LT, mode, ccp_jump))
do_jump_by_parts_greater (exp, 1, if_false_label, if_true_label);
else
do_compare_and_jump (exp, LT, LTU, if_false_label, if_true_label);
break;
case LE_EXPR:
mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
if (GET_MODE_CLASS (mode) == MODE_INT
&& ! can_compare_p (LE, mode, ccp_jump))
do_jump_by_parts_greater (exp, 0, if_true_label, if_false_label);
else
do_compare_and_jump (exp, LE, LEU, if_false_label, if_true_label);
break;
case GT_EXPR:
mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
if (GET_MODE_CLASS (mode) == MODE_INT
&& ! can_compare_p (GT, mode, ccp_jump))
do_jump_by_parts_greater (exp, 0, if_false_label, if_true_label);
else
do_compare_and_jump (exp, GT, GTU, if_false_label, if_true_label);
break;
case GE_EXPR:
mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
if (GET_MODE_CLASS (mode) == MODE_INT
&& ! can_compare_p (GE, mode, ccp_jump))
do_jump_by_parts_greater (exp, 1, if_true_label, if_false_label);
else
do_compare_and_jump (exp, GE, GEU, if_false_label, if_true_label);
break;
case UNORDERED_EXPR:
case ORDERED_EXPR:
{
enum rtx_code cmp, rcmp;
int do_rev;
if (code == UNORDERED_EXPR)
cmp = UNORDERED, rcmp = ORDERED;
else
cmp = ORDERED, rcmp = UNORDERED;
mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
do_rev = 0;
if (! can_compare_p (cmp, mode, ccp_jump)
&& (can_compare_p (rcmp, mode, ccp_jump)
|| rcmp == UNORDERED))
do_rev = 1;
if (! do_rev)
do_compare_and_jump (exp, cmp, cmp, if_false_label, if_true_label);
else
do_compare_and_jump (exp, rcmp, rcmp, if_true_label, if_false_label);
}
break;
{
enum rtx_code rcode1;
enum tree_code tcode2;
case UNLT_EXPR:
rcode1 = UNLT;
tcode2 = LT_EXPR;
goto unordered_bcc;
case UNLE_EXPR:
rcode1 = UNLE;
tcode2 = LE_EXPR;
goto unordered_bcc;
case UNGT_EXPR:
rcode1 = UNGT;
tcode2 = GT_EXPR;
goto unordered_bcc;
case UNGE_EXPR:
rcode1 = UNGE;
tcode2 = GE_EXPR;
goto unordered_bcc;
case UNEQ_EXPR:
rcode1 = UNEQ;
tcode2 = EQ_EXPR;
goto unordered_bcc;
unordered_bcc:
mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
if (can_compare_p (rcode1, mode, ccp_jump))
do_compare_and_jump (exp, rcode1, rcode1, if_false_label,
if_true_label);
else
{
tree op0 = save_expr (TREE_OPERAND (exp, 0));
tree op1 = save_expr (TREE_OPERAND (exp, 1));
tree cmp0, cmp1;
cmp0 = fold (build (UNORDERED_EXPR, TREE_TYPE (exp), op0, op1));
cmp1 = fold (build (tcode2, TREE_TYPE (exp), op0, op1));
exp = build (TRUTH_ORIF_EXPR, TREE_TYPE (exp), cmp0, cmp1);
do_jump (exp, if_false_label, if_true_label);
}
}
break;
case CALL_EXPR:
if (TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR)
{
tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
tree arglist = TREE_OPERAND (exp, 1);
if (TREE_CODE (fndecl) == FUNCTION_DECL
&& DECL_BUILT_IN (fndecl)
&& DECL_FUNCTION_CODE (fndecl) == BUILT_IN_EXPECT
&& arglist != NULL_TREE
&& TREE_CHAIN (arglist) != NULL_TREE)
{
rtx seq = expand_builtin_expect_jump (exp, if_false_label,
if_true_label);
if (seq != NULL_RTX)
{
emit_insn (seq);
return;
}
}
}
default:
normal:
temp = expand_expr (exp, NULL_RTX, VOIDmode, 0);
#if 0
if (!cse_not_expected && GET_CODE (temp) == MEM)
temp = copy_to_reg (temp);
#endif
do_pending_stack_adjust ();
emit_queue ();
if (GET_CODE (temp) == CONST_INT
|| (GET_CODE (temp) == CONST_DOUBLE && GET_MODE (temp) == VOIDmode)
|| GET_CODE (temp) == LABEL_REF)
{
rtx target = temp == const0_rtx ? if_false_label : if_true_label;
if (target)
emit_jump (target);
}
else if (GET_MODE_CLASS (GET_MODE (temp)) == MODE_INT
&& ! can_compare_p (NE, GET_MODE (temp), ccp_jump))
do_jump_by_parts_equality_rtx (temp, if_true_label, if_false_label);
else if (GET_MODE (temp) != VOIDmode)
do_compare_rtx_and_jump (temp, CONST0_RTX (GET_MODE (temp)),
NE, TREE_UNSIGNED (TREE_TYPE (exp)),
GET_MODE (temp), NULL_RTX,
if_false_label, if_true_label);
else
abort ();
}
if (drop_through_label)
{
do_pending_stack_adjust ();
emit_label (drop_through_label);
}
}
static void
do_jump_by_parts_greater (exp, swap, if_false_label, if_true_label)
tree exp;
int swap;
rtx if_false_label, if_true_label;
{
rtx op0 = expand_expr (TREE_OPERAND (exp, swap), NULL_RTX, VOIDmode, 0);
rtx op1 = expand_expr (TREE_OPERAND (exp, !swap), NULL_RTX, VOIDmode, 0);
enum machine_mode mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
int unsignedp = TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0)));
int nwords = (GET_MODE_SIZE (mode) / UNITS_PER_WORD);
rtx drop_through_label = 0;
int i;
if (! if_true_label || ! if_false_label)
drop_through_label = gen_label_rtx ();
if (! if_true_label)
if_true_label = drop_through_label;
if (! if_false_label)
if_false_label = drop_through_label;
for (i = 0; i < nwords; i++)
{
rtx op0_word, op1_word;
if (WORDS_BIG_ENDIAN)
{
op0_word = operand_subword_force (op0, i, mode);
op1_word = operand_subword_force (op1, i, mode);
}
else
{
op0_word = operand_subword_force (op0, nwords - 1 - i, mode);
op1_word = operand_subword_force (op1, nwords - 1 - i, mode);
}
do_compare_rtx_and_jump (op0_word, op1_word, GT,
(unsignedp || i > 0), word_mode, NULL_RTX,
NULL_RTX, if_true_label);
emit_rtx_feedback_counter (exp, 0, fdo_incoming);
do_compare_rtx_and_jump (op0_word, op1_word, NE, unsignedp, word_mode,
NULL_RTX, NULL_RTX, if_false_label);
}
if (if_false_label)
emit_jump (if_false_label);
if (drop_through_label)
emit_label (drop_through_label);
}
void
do_jump_by_parts_greater_rtx (mode, unsignedp, op0, op1, if_false_label, if_true_label)
enum machine_mode mode;
int unsignedp;
rtx op0, op1;
rtx if_false_label, if_true_label;
{
int nwords = (GET_MODE_SIZE (mode) / UNITS_PER_WORD);
rtx drop_through_label = 0;
int i;
if (! if_true_label || ! if_false_label)
drop_through_label = gen_label_rtx ();
if (! if_true_label)
if_true_label = drop_through_label;
if (! if_false_label)
if_false_label = drop_through_label;
for (i = 0; i < nwords; i++)
{
rtx op0_word, op1_word;
if (WORDS_BIG_ENDIAN)
{
op0_word = operand_subword_force (op0, i, mode);
op1_word = operand_subword_force (op1, i, mode);
}
else
{
op0_word = operand_subword_force (op0, nwords - 1 - i, mode);
op1_word = operand_subword_force (op1, nwords - 1 - i, mode);
}
do_compare_rtx_and_jump (op0_word, op1_word, GT,
(unsignedp || i > 0), word_mode, NULL_RTX,
NULL_RTX, if_true_label);
do_compare_rtx_and_jump (op0_word, op1_word, NE, unsignedp, word_mode,
NULL_RTX, NULL_RTX, if_false_label);
}
if (if_false_label)
emit_jump (if_false_label);
if (drop_through_label)
emit_label (drop_through_label);
}
static void
do_jump_by_parts_equality (exp, if_false_label, if_true_label)
tree exp;
rtx if_false_label, if_true_label;
{
rtx op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, VOIDmode, 0);
rtx op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, 0);
enum machine_mode mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
int nwords = (GET_MODE_SIZE (mode) / UNITS_PER_WORD);
int i;
rtx drop_through_label = 0;
if (! if_false_label)
drop_through_label = if_false_label = gen_label_rtx ();
for (i = 0; i < nwords; i++)
{
do_compare_rtx_and_jump (operand_subword_force (op0, i, mode),
operand_subword_force (op1, i, mode),
EQ, TREE_UNSIGNED (TREE_TYPE (exp)),
word_mode, NULL_RTX, if_false_label, NULL_RTX);
if (i==0)
emit_rtx_feedback_counter (exp, 0, fdo_incoming);
}
if (if_true_label)
emit_jump (if_true_label);
if (drop_through_label)
emit_label (drop_through_label);
}
void
do_jump_by_parts_equality_rtx (op0, if_false_label, if_true_label)
rtx op0;
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;
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)
{
do_compare_rtx_and_jump (part, const0_rtx, EQ, 1, word_mode,
NULL_RTX, if_false_label, if_true_label);
return;
}
if (! if_false_label)
drop_through_label = if_false_label = gen_label_rtx ();
for (i = 0; i < nwords; i++)
do_compare_rtx_and_jump (operand_subword_force (op0, i, GET_MODE (op0)),
const0_rtx, EQ, 1, word_mode, NULL_RTX,
if_false_label, NULL_RTX);
if (if_true_label)
emit_jump (if_true_label);
if (drop_through_label)
emit_label (drop_through_label);
}
rtx
compare_from_rtx (op0, op1, code, unsignedp, mode, size)
rtx op0, op1;
enum rtx_code code;
int unsignedp;
enum machine_mode mode;
rtx size;
{
enum rtx_code ucode;
rtx tem;
if (swap_commutative_operands_p (op0, op1))
{
tem = op0;
op0 = op1;
op1 = tem;
code = swap_condition (code);
}
if (flag_force_mem)
{
op0 = force_not_mem (op0);
op1 = force_not_mem (op1);
}
do_pending_stack_adjust ();
ucode = unsignedp ? unsigned_condition (code) : code;
if ((tem = simplify_relational_operation (ucode, mode, op0, op1)) != 0)
return tem;
#if 0
if ((code == EQ || code == NE) && ! unsignedp
&& GET_MODE_BITSIZE (GET_MODE (op0)) <= HOST_BITS_PER_WIDE_INT)
{
if (GET_CODE (op1) == CONST_INT
&& (INTVAL (op1) & GET_MODE_MASK (GET_MODE (op0))) != INTVAL (op1))
op1 = GEN_INT (INTVAL (op1) & GET_MODE_MASK (GET_MODE (op0)));
unsignedp = 1;
}
#endif
emit_cmp_insn (op0, op1, code, size, mode, unsignedp);
#if HAVE_cc0
return gen_rtx_fmt_ee (code, VOIDmode, cc0_rtx, const0_rtx);
#else
return gen_rtx_fmt_ee (code, VOIDmode, op0, op1);
#endif
}
void
do_compare_rtx_and_jump (op0, op1, code, unsignedp, mode, size,
if_false_label, if_true_label)
rtx op0, op1;
enum rtx_code code;
int unsignedp;
enum machine_mode mode;
rtx size;
rtx if_false_label, if_true_label;
{
enum rtx_code ucode;
rtx tem;
int dummy_true_label = 0;
if (! if_true_label && ! FLOAT_MODE_P (mode))
{
if_true_label = if_false_label;
if_false_label = 0;
code = reverse_condition (code);
}
if (swap_commutative_operands_p (op0, op1))
{
tem = op0;
op0 = op1;
op1 = tem;
code = swap_condition (code);
}
if (flag_force_mem)
{
op0 = force_not_mem (op0);
op1 = force_not_mem (op1);
}
do_pending_stack_adjust ();
ucode = unsignedp ? unsigned_condition (code) : code;
if ((tem = simplify_relational_operation (ucode, mode, op0, op1)) != 0)
{
if (tem == const_true_rtx)
{
if (if_true_label)
emit_jump (if_true_label);
}
else
{
if (if_false_label)
emit_jump (if_false_label);
}
return;
}
#if 0
if ((code == EQ || code == NE) && ! unsignedp
&& GET_MODE_BITSIZE (GET_MODE (op0)) <= HOST_BITS_PER_WIDE_INT)
{
if (GET_CODE (op1) == CONST_INT
&& (INTVAL (op1) & GET_MODE_MASK (GET_MODE (op0))) != INTVAL (op1))
op1 = GEN_INT (INTVAL (op1) & GET_MODE_MASK (GET_MODE (op0)));
unsignedp = 1;
}
#endif
if (! if_true_label)
{
dummy_true_label = 1;
if_true_label = gen_label_rtx ();
}
emit_cmp_and_jump_insns (op0, op1, code, size, mode, unsignedp,
if_true_label);
if (if_false_label)
emit_jump (if_false_label);
if (dummy_true_label)
emit_label (if_true_label);
}
static void
do_compare_and_jump_1 (exp, signed_code, unsigned_code, if_false_label,
if_true_label)
tree exp;
enum rtx_code signed_code, unsigned_code;
rtx if_false_label, if_true_label;
{
rtx op0, op1;
tree type;
enum machine_mode mode;
int unsignedp;
enum rtx_code code;
op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, VOIDmode, 0);
if (TREE_CODE (TREE_OPERAND (exp, 0)) == ERROR_MARK)
return;
op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, 0);
if (TREE_CODE (TREE_OPERAND (exp, 1)) == ERROR_MARK)
return;
type = TREE_TYPE (TREE_OPERAND (exp, 0));
mode = TYPE_MODE (type);
if (TREE_CODE (TREE_OPERAND (exp, 0)) == INTEGER_CST
&& (TREE_CODE (TREE_OPERAND (exp, 1)) != INTEGER_CST
|| (GET_MODE_BITSIZE (mode)
> GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp,
1)))))))
{
type = TREE_TYPE (TREE_OPERAND (exp, 1));
mode = TYPE_MODE (type);
}
unsignedp = TREE_UNSIGNED (type);
code = unsignedp ? unsigned_code : signed_code;
#ifdef HAVE_canonicalize_funcptr_for_compare
if (HAVE_canonicalize_funcptr_for_compare
&& TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 0))) == POINTER_TYPE
&& (TREE_CODE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 0))))
== FUNCTION_TYPE))
{
rtx new_op0 = gen_reg_rtx (mode);
emit_insn (gen_canonicalize_funcptr_for_compare (new_op0, op0));
op0 = new_op0;
}
if (HAVE_canonicalize_funcptr_for_compare
&& TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 1))) == POINTER_TYPE
&& (TREE_CODE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 1))))
== FUNCTION_TYPE))
{
rtx new_op1 = gen_reg_rtx (mode);
emit_insn (gen_canonicalize_funcptr_for_compare (new_op1, op1));
op1 = new_op1;
}
#endif
emit_queue ();
do_compare_rtx_and_jump (op0, op1, code, unsignedp, mode,
((mode == BLKmode)
? expr_size (TREE_OPERAND (exp, 0)) : NULL_RTX),
if_false_label, if_true_label);
}
static void
do_compare_and_jump (exp, signed_code, unsigned_code, if_false_label,
if_true_label)
tree exp;
enum rtx_code signed_code, unsigned_code;
rtx if_false_label, if_true_label;
{
if (if_true_label && if_false_label)
{
do_compare_and_jump_1 (exp, signed_code, unsigned_code,
NULL_RTX, if_true_label);
emit_rtx_feedback_counter (exp, 0, fdo_incoming);
emit_jump (if_false_label);
}
else
{
do_compare_and_jump_1 (exp, signed_code, unsigned_code,
if_false_label, if_true_label);
emit_rtx_feedback_counter (exp, 0, fdo_block);
}
}
static rtx
do_store_flag (exp, target, mode, only_cheap)
tree exp;
rtx target;
enum machine_mode mode;
int only_cheap;
{
enum rtx_code code;
tree arg0, arg1, type;
tree tem;
enum machine_mode operand_mode;
int invert = 0;
int unsignedp;
rtx op0, op1;
enum insn_code icode;
rtx subtarget = target;
rtx result, label;
if (TREE_CODE (exp) == TRUTH_NOT_EXPR)
invert = 1, exp = TREE_OPERAND (exp, 0);
arg0 = TREE_OPERAND (exp, 0);
arg1 = TREE_OPERAND (exp, 1);
if (arg0 == error_mark_node || arg1 == error_mark_node)
return const0_rtx;
type = TREE_TYPE (arg0);
operand_mode = TYPE_MODE (type);
unsignedp = TREE_UNSIGNED (type);
if (operand_mode == BLKmode)
return 0;
#ifdef HAVE_canonicalize_funcptr_for_compare
if (HAVE_canonicalize_funcptr_for_compare
&& ((TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 0))) == POINTER_TYPE
&& (TREE_CODE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 0))))
== FUNCTION_TYPE))
|| (TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 1))) == POINTER_TYPE
&& (TREE_CODE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 1))))
== FUNCTION_TYPE))))
return 0;
#endif
STRIP_NOPS (arg0);
STRIP_NOPS (arg1);
switch (TREE_CODE (exp))
{
case EQ_EXPR:
code = EQ;
break;
case NE_EXPR:
code = NE;
break;
case LT_EXPR:
if (integer_onep (arg1))
arg1 = integer_zero_node, code = unsignedp ? LEU : LE;
else
code = unsignedp ? LTU : LT;
break;
case LE_EXPR:
if (! unsignedp && integer_all_onesp (arg1))
arg1 = integer_zero_node, code = LT;
else
code = unsignedp ? LEU : LE;
break;
case GT_EXPR:
if (! unsignedp && integer_all_onesp (arg1))
arg1 = integer_zero_node, code = GE;
else
code = unsignedp ? GTU : GT;
break;
case GE_EXPR:
if (integer_onep (arg1))
arg1 = integer_zero_node, code = unsignedp ? GTU : GT;
else
code = unsignedp ? GEU : GE;
break;
case UNORDERED_EXPR:
code = UNORDERED;
break;
case ORDERED_EXPR:
code = ORDERED;
break;
case UNLT_EXPR:
code = UNLT;
break;
case UNLE_EXPR:
code = UNLE;
break;
case UNGT_EXPR:
code = UNGT;
break;
case UNGE_EXPR:
code = UNGE;
break;
case UNEQ_EXPR:
code = UNEQ;
break;
default:
abort ();
}
if (TREE_CODE (arg0) == REAL_CST || TREE_CODE (arg0) == INTEGER_CST)
{
tem = arg0; arg0 = arg1; arg1 = tem;
code = swap_condition (code);
}
if ((code == NE || code == EQ)
&& TREE_CODE (arg0) == BIT_AND_EXPR && integer_zerop (arg1)
&& integer_pow2p (TREE_OPERAND (arg0, 1)))
{
tree inner = TREE_OPERAND (arg0, 0);
int bitnum = tree_log2 (TREE_OPERAND (arg0, 1));
int ops_unsignedp;
if (TREE_CODE (inner) == RSHIFT_EXPR
&& TREE_CODE (TREE_OPERAND (inner, 1)) == INTEGER_CST
&& TREE_INT_CST_HIGH (TREE_OPERAND (inner, 1)) == 0
&& bitnum < TYPE_PRECISION (type)
&& 0 > compare_tree_int (TREE_OPERAND (inner, 1),
bitnum - TYPE_PRECISION (type)))
{
bitnum += TREE_INT_CST_LOW (TREE_OPERAND (inner, 1));
inner = TREE_OPERAND (inner, 0);
}
ops_unsignedp = (bitnum == TYPE_PRECISION (type) - 1 ? 1
#ifdef LOAD_EXTEND_OP
: (LOAD_EXTEND_OP (operand_mode) == SIGN_EXTEND ? 0 : 1)
#else
: 1
#endif
);
if (! get_subtarget (subtarget)
|| GET_MODE (subtarget) != operand_mode
|| ! safe_from_p (subtarget, inner, 1))
subtarget = 0;
op0 = expand_expr (inner, subtarget, VOIDmode, 0);
if (bitnum != 0)
op0 = expand_shift (RSHIFT_EXPR, operand_mode, op0,
size_int (bitnum), subtarget, ops_unsignedp);
if (GET_MODE (op0) != mode)
op0 = convert_to_mode (mode, op0, ops_unsignedp);
if ((code == EQ && ! invert) || (code == NE && invert))
op0 = expand_binop (mode, xor_optab, op0, const1_rtx, subtarget,
ops_unsignedp, OPTAB_LIB_WIDEN);
if (bitnum != TYPE_PRECISION (type) - 1)
op0 = expand_and (mode, op0, const1_rtx, subtarget);
return op0;
}
if (! can_compare_p (code, operand_mode, ccp_store_flag))
return 0;
icode = setcc_gen_code[(int) code];
if (icode == CODE_FOR_nothing
|| (only_cheap && insn_data[(int) icode].operand[0].mode != mode))
{
if ((code == LT && integer_zerop (arg1))
|| (! only_cheap && code == GE && integer_zerop (arg1)))
;
else if (BRANCH_COST >= 0
&& ! only_cheap && (code == NE || code == EQ)
&& TREE_CODE (type) != REAL_TYPE
&& ((abs_optab->handlers[(int) operand_mode].insn_code
!= CODE_FOR_nothing)
|| (ffs_optab->handlers[(int) operand_mode].insn_code
!= CODE_FOR_nothing)))
;
else
return 0;
}
if (! get_subtarget (target)
|| GET_MODE (subtarget) != operand_mode
|| ! safe_from_p (subtarget, arg1, 1))
subtarget = 0;
op0 = expand_expr (arg0, subtarget, VOIDmode, 0);
op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
if (target == 0)
target = gen_reg_rtx (mode);
result = emit_store_flag (target, code,
queued_subexp_p (op0) ? copy_rtx (op0) : op0,
queued_subexp_p (op1) ? copy_rtx (op1) : op1,
operand_mode, unsignedp, 1);
if (result)
{
if (invert)
result = expand_binop (mode, xor_optab, result, const1_rtx,
result, 0, OPTAB_LIB_WIDEN);
return result;
}
if (GET_CODE (target) != REG
|| reg_mentioned_p (target, op0) || reg_mentioned_p (target, op1))
target = gen_reg_rtx (GET_MODE (target));
emit_move_insn (target, invert ? const0_rtx : const1_rtx);
result = compare_from_rtx (op0, op1, code, unsignedp,
operand_mode, NULL_RTX);
if (GET_CODE (result) == CONST_INT)
return (((result == const0_rtx && ! invert)
|| (result != const0_rtx && invert))
? const0_rtx : const1_rtx);
code = GET_CODE (result);
label = gen_label_rtx ();
if (bcc_gen_fctn[(int) code] == 0)
abort ();
emit_jump_insn ((*bcc_gen_fctn[(int) code]) (label));
emit_rtx_feedback_counter (exp, 0, fdo_incoming);
emit_move_insn (target, invert ? const1_rtx : const0_rtx);
emit_label (label);
return target;
}
#ifndef HAVE_casesi
# define HAVE_casesi 0
# define gen_casesi(a, b, c, d, e) (0)
# define CODE_FOR_casesi CODE_FOR_nothing
#endif
#ifndef CASE_VALUES_THRESHOLD
#define CASE_VALUES_THRESHOLD (HAVE_casesi ? 4 : 5)
#endif
unsigned int
case_values_threshold ()
{
return CASE_VALUES_THRESHOLD;
}
int
try_casesi (index_type, index_expr, minval, range,
table_label, default_label, t)
tree index_type, index_expr, minval, range;
rtx table_label ATTRIBUTE_UNUSED;
rtx default_label;
tree t ATTRIBUTE_UNUSED;
{
enum machine_mode index_mode = SImode;
int index_bits = GET_MODE_BITSIZE (index_mode);
rtx op1, op2, index;
enum machine_mode op_mode;
if (! HAVE_casesi)
return 0;
if (GET_MODE_BITSIZE (TYPE_MODE (index_type)) > GET_MODE_BITSIZE (index_mode))
{
enum machine_mode omode = TYPE_MODE (index_type);
rtx rangertx = expand_expr (range, NULL_RTX, VOIDmode, 0);
index_expr = build (MINUS_EXPR, index_type,
index_expr, minval);
minval = integer_zero_node;
index = expand_expr (index_expr, NULL_RTX, VOIDmode, 0);
emit_cmp_and_jump_insns (rangertx, index, LTU, NULL_RTX,
omode, 1, default_label);
index = convert_to_mode (index_mode, index, 0);
}
else
{
if (TYPE_MODE (index_type) != index_mode)
{
index_expr = convert ((*lang_hooks.types.type_for_size)
(index_bits, 0), index_expr);
index_type = TREE_TYPE (index_expr);
}
index = expand_expr (index_expr, NULL_RTX, VOIDmode, 0);
}
emit_queue ();
index = protect_from_queue (index, 0);
do_pending_stack_adjust ();
op_mode = insn_data[(int) CODE_FOR_casesi].operand[0].mode;
if (! (*insn_data[(int) CODE_FOR_casesi].operand[0].predicate)
(index, op_mode))
index = copy_to_mode_reg (op_mode, index);
op1 = expand_expr (minval, NULL_RTX, VOIDmode, 0);
op_mode = insn_data[(int) CODE_FOR_casesi].operand[1].mode;
op1 = convert_modes (op_mode, TYPE_MODE (TREE_TYPE (minval)),
op1, TREE_UNSIGNED (TREE_TYPE (minval)));
if (! (*insn_data[(int) CODE_FOR_casesi].operand[1].predicate)
(op1, op_mode))
op1 = copy_to_mode_reg (op_mode, op1);
op2 = expand_expr (range, NULL_RTX, VOIDmode, 0);
op_mode = insn_data[(int) CODE_FOR_casesi].operand[2].mode;
op2 = convert_modes (op_mode, TYPE_MODE (TREE_TYPE (range)),
op2, TREE_UNSIGNED (TREE_TYPE (range)));
if (! (*insn_data[(int) CODE_FOR_casesi].operand[2].predicate)
(op2, op_mode))
op2 = copy_to_mode_reg (op_mode, op2);
emit_jump_insn (gen_casesi (index, op1, op2,
table_label, default_label));
return 1;
}
#ifndef HAVE_tablejump
#define HAVE_tablejump 0
#define gen_tablejump(x, y) (0)
#endif
static void
do_tablejump (index, mode, range, table_label, default_label, t)
rtx index, range, table_label, default_label;
enum machine_mode mode;
tree t;
{
rtx temp, vector;
if (INTVAL (range) > cfun->max_jumptable_ents)
cfun->max_jumptable_ents = INTVAL (range);
emit_cmp_and_jump_insns (index, range, GTU, NULL_RTX, mode, 1,
default_label);
emit_rtx_feedback_counter (t, 1, fdo_incoming);
if (mode != Pmode)
index = convert_to_mode (Pmode, index, 1);
#ifdef PIC_CASE_VECTOR_ADDRESS
if (flag_pic && GET_CODE (index) != REG)
index = copy_to_mode_reg (Pmode, index);
#endif
index = gen_rtx_PLUS (Pmode,
gen_rtx_MULT (Pmode, index,
GEN_INT (GET_MODE_SIZE (CASE_VECTOR_MODE))),
gen_rtx_LABEL_REF (Pmode, table_label));
#ifdef PIC_CASE_VECTOR_ADDRESS
if (flag_pic)
index = PIC_CASE_VECTOR_ADDRESS (index);
else
#endif
index = memory_address_noforce (CASE_VECTOR_MODE, index);
temp = gen_reg_rtx (CASE_VECTOR_MODE);
vector = gen_rtx_MEM (CASE_VECTOR_MODE, index);
RTX_UNCHANGING_P (vector) = 1;
convert_move (temp, vector, 0);
emit_jump_insn (gen_tablejump (temp, table_label));
if (! CASE_VECTOR_PC_RELATIVE && ! flag_pic)
emit_barrier ();
}
int
try_tablejump (index_type, index_expr, minval, range,
table_label, default_label, t)
tree index_type, index_expr, minval, range;
rtx table_label, default_label;
tree t;
{
rtx index;
tree old_index_expr = index_expr;
if (! HAVE_tablejump)
return 0;
index_expr = fold (build (MINUS_EXPR, index_type,
convert (index_type, index_expr),
convert (index_type, minval)));
clone_rtx_feedback_counter (old_index_expr, index_expr);
index = expand_expr (index_expr, NULL_RTX, VOIDmode, 0);
emit_queue ();
index = protect_from_queue (index, 0);
do_pending_stack_adjust ();
do_tablejump (index, TYPE_MODE (index_type),
convert_modes (TYPE_MODE (index_type),
TYPE_MODE (TREE_TYPE (range)),
expand_expr (range, NULL_RTX,
VOIDmode, 0),
TREE_UNSIGNED (TREE_TYPE (range))),
table_label, default_label, t);
return 1;
}
int
vector_mode_valid_p (mode)
enum machine_mode mode;
{
enum mode_class class = GET_MODE_CLASS (mode);
enum machine_mode innermode;
if (class != MODE_VECTOR_INT
&& class != MODE_VECTOR_FLOAT)
return 0;
if (VECTOR_MODE_SUPPORTED_P (mode))
return 1;
innermode = GET_MODE_INNER (mode);
return mov_optab->handlers[innermode].insn_code != CODE_FOR_nothing;
}
#include "gt-expr.h"