#include "config.h"
#include "system.h"
#include "machmode.h"
#include "rtl.h"
#include "tree.h"
#include "obstack.h"
#include "flags.h"
#include "regs.h"
#include "hard-reg-set.h"
#include "except.h"
#include "function.h"
#include "insn-flags.h"
#include "insn-codes.h"
#include "insn-config.h"
#include "expr.h"
#include "recog.h"
#include "output.h"
#include "typeclass.h"
#include "defaults.h"
#include "toplev.h"
#define CEIL(x,y) (((x) + (y) - 1) / (y))
#ifdef PUSH_ROUNDING
#if defined (STACK_GROWS_DOWNWARD) != defined (ARGS_GROW_DOWNWARD)
#define PUSH_ARGS_REVERSED
#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
int cse_not_expected;
int do_preexpand_calls = 1;
int pending_stack_adjust;
int inhibit_defer_pop;
static rtx saveregs_value;
static rtx apply_args_value;
static int in_check_memory_usage;
static rtx pending_chain;
struct move_by_pieces
{
rtx to;
rtx to_addr;
int autinc_to;
int explicit_inc_to;
int to_struct;
rtx from;
rtx from_addr;
int autinc_from;
int explicit_inc_from;
int from_struct;
int len;
int offset;
int reverse;
};
struct clear_by_pieces
{
rtx to;
rtx to_addr;
int autinc_to;
int explicit_inc_to;
int to_struct;
int len;
int offset;
int reverse;
};
extern struct obstack permanent_obstack;
extern rtx arg_pointer_save_area;
static rtx get_push_address PROTO ((int));
static rtx enqueue_insn PROTO((rtx, rtx));
static void init_queue PROTO((void));
static int move_by_pieces_ninsns PROTO((unsigned int, int));
static void move_by_pieces_1 PROTO((rtx (*) (rtx, ...), enum machine_mode,
struct move_by_pieces *));
static void clear_by_pieces PROTO((rtx, int, int));
static void clear_by_pieces_1 PROTO((rtx (*) (rtx, ...), enum machine_mode,
struct clear_by_pieces *));
static int is_zeros_p PROTO((tree));
static int mostly_zeros_p PROTO((tree));
static void store_constructor_field PROTO((rtx, int, int, enum machine_mode,
tree, tree, int));
static void store_constructor PROTO((tree, rtx, int));
static rtx store_field PROTO((rtx, int, int, enum machine_mode, tree,
enum machine_mode, int, int,
int, int));
static enum memory_use_mode
get_memory_usage_from_modifier PROTO((enum expand_modifier));
static tree save_noncopied_parts PROTO((tree, tree));
static tree init_noncopied_parts PROTO((tree, tree));
static int safe_from_p PROTO((rtx, tree, int));
static int fixed_type_p PROTO((tree));
static rtx var_rtx PROTO((tree));
static int get_pointer_alignment PROTO((tree, unsigned));
static tree string_constant PROTO((tree, tree *));
static tree c_strlen PROTO((tree));
static rtx get_memory_rtx PROTO((tree));
static rtx expand_builtin PROTO((tree, rtx, rtx,
enum machine_mode, int));
static int apply_args_size PROTO((void));
static int apply_result_size PROTO((void));
static rtx result_vector PROTO((int, rtx));
static rtx expand_builtin_apply_args PROTO((void));
static rtx expand_builtin_apply PROTO((rtx, rtx, rtx));
static void expand_builtin_return PROTO((rtx));
static rtx expand_increment PROTO((tree, int, int));
static void preexpand_calls PROTO((tree));
static void do_jump_by_parts_greater PROTO((tree, int, rtx, rtx));
static void do_jump_by_parts_equality PROTO((tree, rtx, rtx));
static void do_jump_for_compare PROTO((rtx, rtx, rtx));
static rtx compare PROTO((tree, enum rtx_code, enum rtx_code));
static rtx do_store_flag PROTO((tree, rtx, enum machine_mode, int));
static char direct_load[NUM_MACHINE_MODES];
static char direct_store[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) < MOVE_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 STRICT_ALIGNMENT
#endif
#ifndef INCOMING_REGNO
#define INCOMING_REGNO(OUT) (OUT)
#endif
#ifndef OUTGOING_REGNO
#define OUTGOING_REGNO(IN) (IN)
#endif
void
init_expr_once ()
{
rtx insn, pat;
enum machine_mode mode;
int num_clobbers;
rtx mem, mem1;
char *free_point;
start_sequence ();
free_point = (char *) oballoc (0);
mem = gen_rtx_MEM (VOIDmode, stack_pointer_rtx);
mem1 = gen_rtx_MEM (VOIDmode, frame_pointer_rtx);
insn = emit_insn (gen_rtx_SET (0, NULL_RTX, NULL_RTX));
pat = PATTERN (insn);
for (mode = VOIDmode; (int) mode < NUM_MACHINE_MODES;
mode = (enum machine_mode) ((int) mode + 1))
{
int regno;
rtx reg;
direct_load[(int) mode] = direct_store[(int) mode] = 0;
PUT_MODE (mem, mode);
PUT_MODE (mem1, 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;
reg = gen_rtx_REG (mode, 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;
}
}
end_sequence ();
obfree (free_point);
}
void
init_expr ()
{
init_queue ();
pending_stack_adjust = 0;
inhibit_defer_pop = 0;
saveregs_value = 0;
apply_args_value = 0;
forced_labels = 0;
}
void
save_expr_status (p)
struct function *p;
{
p->pending_chain = pending_chain;
p->pending_stack_adjust = pending_stack_adjust;
p->inhibit_defer_pop = inhibit_defer_pop;
p->saveregs_value = saveregs_value;
p->apply_args_value = apply_args_value;
p->forced_labels = forced_labels;
pending_chain = NULL_RTX;
pending_stack_adjust = 0;
inhibit_defer_pop = 0;
saveregs_value = 0;
apply_args_value = 0;
forced_labels = 0;
}
void
restore_expr_status (p)
struct function *p;
{
pending_chain = p->pending_chain;
pending_stack_adjust = p->pending_stack_adjust;
inhibit_defer_pop = p->inhibit_defer_pop;
saveregs_value = p->saveregs_value;
apply_args_value = p->apply_args_value;
forced_labels = p->forced_labels;
}
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)
register rtx x;
int modify;
{
register 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)
{
register rtx y = XEXP (x, 0);
register rtx new = gen_rtx_MEM (GET_MODE (x), QUEUED_VAR (y));
RTX_UNCHANGING_P (new) = RTX_UNCHANGING_P (x);
MEM_COPY_ATTRIBUTES (new, x);
MEM_ALIAS_SET (new) = MEM_ALIAS_SET (x);
if (QUEUED_INSN (y))
{
register rtx temp = gen_reg_rtx (GET_MODE (new));
emit_insn_before (gen_move_insn (temp, new),
QUEUED_INSN (y));
return temp;
}
return new;
}
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 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;
{
register 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 ()
{
register rtx p;
while ((p = pending_chain))
{
rtx body = QUEUED_BODY (p);
if (GET_CODE (body) == SEQUENCE)
{
QUEUED_INSN (p) = XVECEXP (QUEUED_BODY (p), 0, 0);
emit_insn (QUEUED_BODY (p));
}
else
QUEUED_INSN (p) = emit_insn (QUEUED_BODY (p));
pending_chain = QUEUED_NEXT (p);
}
}
static void
init_queue ()
{
if (pending_chain)
abort ();
}
void
convert_move (to, from, unsignedp)
register 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 ? 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 (to_real)
{
rtx value;
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 ();
value = emit_library_call_value (libcall, NULL_RTX, 1, to_mode,
1, from, from_mode);
emit_move_insn (to, value);
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_operand_mode[(int) CODE_FOR_slt][0] == word_mode
&& STORE_FLAG_VALUE == -1)
{
emit_cmp_insn (lowfrom, const0_rtx, NE, NULL_RTX,
lowpart_mode, 0, 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 (HAVE_extendpsisi2)
{
emit_unop_insn (CODE_FOR_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)
{
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 (to_mode, 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;
{
register 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 (val);
}
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
void
move_by_pieces (to, from, len, align)
rtx to, from;
int len, align;
{
struct move_by_pieces data;
rtx to_addr = XEXP (to, 0), from_addr = XEXP (from, 0);
int max_size = MOVE_MAX_PIECES + 1;
enum machine_mode mode = VOIDmode, tmode;
enum insn_code icode;
data.offset = 0;
data.to_addr = to_addr;
data.from_addr = from_addr;
data.to = to;
data.from = from;
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.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;
data.reverse
= (GET_CODE (to_addr) == PRE_DEC || GET_CODE (to_addr) == POST_DEC);
if (data.reverse) data.offset = len;
data.len = len;
data.to_struct = MEM_IN_STRUCT_P (to);
data.from_struct = MEM_IN_STRUCT_P (from);
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
|| align > MOVE_MAX || align >= BIGGEST_ALIGNMENT / BITS_PER_UNIT)
align = MOVE_MAX;
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 >= MIN (BIGGEST_ALIGNMENT / BITS_PER_UNIT,
GET_MODE_SIZE (mode)))
move_by_pieces_1 (GEN_FCN (icode), mode, &data);
max_size = GET_MODE_SIZE (mode);
}
if (data.len > 0)
abort ();
}
static int
move_by_pieces_ninsns (l, align)
unsigned int l;
int align;
{
register int n_insns = 0;
int max_size = MOVE_MAX + 1;
if (! SLOW_UNALIGNED_ACCESS
|| align > MOVE_MAX || align >= BIGGEST_ALIGNMENT / BITS_PER_UNIT)
align = MOVE_MAX;
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 >= MIN (BIGGEST_ALIGNMENT / BITS_PER_UNIT,
GET_MODE_SIZE (mode)))
n_insns += l / GET_MODE_SIZE (mode), l %= GET_MODE_SIZE (mode);
max_size = GET_MODE_SIZE (mode);
}
return n_insns;
}
static void
move_by_pieces_1 (genfun, mode, data)
rtx (*genfun) PROTO ((rtx, ...));
enum machine_mode mode;
struct move_by_pieces *data;
{
register int size = GET_MODE_SIZE (mode);
register rtx to1, from1;
while (data->len >= size)
{
if (data->reverse) data->offset -= size;
to1 = (data->autinc_to
? gen_rtx_MEM (mode, data->to_addr)
: copy_rtx (change_address (data->to, mode,
plus_constant (data->to_addr,
data->offset))));
MEM_IN_STRUCT_P (to1) = data->to_struct;
from1
= (data->autinc_from
? gen_rtx_MEM (mode, data->from_addr)
: copy_rtx (change_address (data->from, mode,
plus_constant (data->from_addr,
data->offset))));
MEM_IN_STRUCT_P (from1) = data->from_struct;
if (HAVE_PRE_DECREMENT && data->explicit_inc_to < 0)
emit_insn (gen_add2_insn (data->to_addr, GEN_INT (-size)));
if (HAVE_PRE_DECREMENT && data->explicit_inc_from < 0)
emit_insn (gen_add2_insn (data->from_addr, GEN_INT (-size)));
emit_insn ((*genfun) (to1, from1));
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, align)
rtx x, y;
rtx size;
int align;
{
rtx retval = 0;
#ifdef TARGET_MEM_FUNCTIONS
static tree fn;
tree call_expr, arg_list;
#endif
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 && MOVE_BY_PIECES_P (INTVAL (size), align))
move_by_pieces (x, y, INTVAL (size), align);
else
{
rtx opalign = GEN_INT (align);
enum machine_mode mode;
for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); mode != VOIDmode;
mode = GET_MODE_WIDER_MODE (mode))
{
enum insn_code code = movstr_optab[(int) mode];
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)
&& (insn_operand_predicate[(int) code][0] == 0
|| (*insn_operand_predicate[(int) code][0]) (x, BLKmode))
&& (insn_operand_predicate[(int) code][1] == 0
|| (*insn_operand_predicate[(int) code][1]) (y, BLKmode))
&& (insn_operand_predicate[(int) code][3] == 0
|| (*insn_operand_predicate[(int) code][3]) (opalign,
VOIDmode)))
{
rtx op2;
rtx last = get_last_insn ();
rtx pat;
op2 = convert_to_mode (mode, size, 1);
if (insn_operand_predicate[(int) code][2] != 0
&& ! (*insn_operand_predicate[(int) code][2]) (op2, mode))
op2 = copy_to_mode_reg (mode, op2);
pat = GEN_FCN ((int) code) (x, y, op2, opalign);
if (pat)
{
emit_insn (pat);
return 0;
}
else
delete_insns_since (last);
}
}
x = copy_to_mode_reg (Pmode, XEXP (x, 0));
y = copy_to_mode_reg (Pmode, XEXP (y, 0));
#ifdef TARGET_MEM_FUNCTIONS
size = copy_to_mode_reg (TYPE_MODE (sizetype), size);
#else
size = convert_to_mode (TYPE_MODE (integer_type_node), size,
TREE_UNSIGNED (integer_type_node));
size = copy_to_mode_reg (TYPE_MODE (integer_type_node), size);
#endif
#ifdef TARGET_MEM_FUNCTIONS
if (fn == NULL_TREE)
{
tree fntype;
fn = get_identifier ("memcpy");
push_obstacks_nochange ();
end_temporary_allocation ();
fntype = build_pointer_type (void_type_node);
fntype = build_function_type (fntype, NULL_TREE);
fn = build_decl (FUNCTION_DECL, fn, fntype);
DECL_EXTERNAL (fn) = 1;
TREE_PUBLIC (fn) = 1;
DECL_ARTIFICIAL (fn) = 1;
make_decl_rtl (fn, NULL_PTR, 1);
assemble_external (fn);
pop_obstacks ();
}
arg_list
= build_tree_list (NULL_TREE,
make_tree (build_pointer_type (void_type_node), x));
TREE_CHAIN (arg_list)
= build_tree_list (NULL_TREE,
make_tree (build_pointer_type (void_type_node), y));
TREE_CHAIN (TREE_CHAIN (arg_list))
= build_tree_list (NULL_TREE, make_tree (sizetype, size));
TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (arg_list))) = NULL_TREE;
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);
#else
emit_library_call (bcopy_libfunc, 0,
VOIDmode, 3, y, Pmode, x, Pmode,
convert_to_mode (TYPE_MODE (integer_type_node), size,
TREE_UNSIGNED (integer_type_node)),
TYPE_MODE (integer_type_node));
#endif
}
return retval;
}
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 (word_mode, 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 (size <= UNITS_PER_WORD
&& (mode = mode_for_size (size * BITS_PER_UNIT, MODE_INT, 0)) != BLKmode)
{
emit_move_insn (change_address (x, mode, NULL),
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 (word_mode, regno + i));
}
}
void
emit_group_load (dst, orig_src, ssize, align)
rtx dst, orig_src;
int align, 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));
src = orig_src;
if (GET_CODE (src) != MEM)
{
src = gen_reg_rtx (GET_MODE (orig_src));
emit_move_insn (src, orig_src);
}
for (i = start; i < XVECLEN (dst, 0); i++)
{
enum machine_mode mode = GET_MODE (XEXP (XVECEXP (dst, 0, i), 0));
int bytepos = INTVAL (XEXP (XVECEXP (dst, 0, i), 1));
int bytelen = GET_MODE_SIZE (mode);
int shift = 0;
if (ssize >= 0 && bytepos + bytelen > ssize)
{
shift = (bytelen - (ssize - bytepos)) * BITS_PER_UNIT;
bytelen = ssize - bytepos;
if (bytelen <= 0)
abort();
}
if (GET_CODE (src) == MEM
&& align*BITS_PER_UNIT >= 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],
change_address (src, mode,
plus_constant (XEXP (src, 0),
bytepos)));
}
else
{
tmps[i] = extract_bit_field (src, bytelen*BITS_PER_UNIT,
bytepos*BITS_PER_UNIT, 1, NULL_RTX,
mode, mode, align, 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_store (orig_dst, src, ssize, align)
rtx orig_dst, src;
int ssize, align;
{
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, align);
emit_group_load (dst, temp, ssize, align);
return;
}
else if (GET_CODE (dst) != MEM)
{
dst = gen_reg_rtx (GET_MODE (orig_dst));
emit_move_insn (dst, const0_rtx);
}
else if (! MEM_IN_STRUCT_P (dst))
{
dst = copy_rtx (orig_dst);
MEM_SET_IN_STRUCT_P (dst, 1);
}
for (i = start; i < XVECLEN (src, 0); i++)
{
int bytepos = INTVAL (XEXP (XVECEXP (src, 0, i), 1));
enum machine_mode mode = GET_MODE (tmps[i]);
int bytelen = GET_MODE_SIZE (mode);
if (ssize >= 0 && bytepos + 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) == MEM
&& align*BITS_PER_UNIT >= GET_MODE_ALIGNMENT (mode)
&& bytepos*BITS_PER_UNIT % GET_MODE_ALIGNMENT (mode) == 0
&& bytelen == GET_MODE_SIZE (mode))
{
emit_move_insn (change_address (dst, mode,
plus_constant (XEXP (dst, 0),
bytepos)),
tmps[i]);
}
else
{
store_bit_field (dst, bytelen*BITS_PER_UNIT, bytepos*BITS_PER_UNIT,
mode, tmps[i], align, ssize);
}
}
emit_queue();
if (GET_CODE (dst) == REG)
emit_move_insn (orig_dst, dst);
}
rtx
copy_blkmode_from_reg(tgtblk,srcreg,type)
rtx tgtblk;
rtx srcreg;
tree type;
{
int bytes = int_size_in_bytes (type);
rtx src = NULL, dst = NULL;
int bitsize = MIN (TYPE_ALIGN (type), (unsigned int) BITS_PER_WORD);
int bitpos, xbitpos, big_endian_correction = 0;
if (tgtblk == 0)
{
tgtblk = assign_stack_temp (BLKmode, bytes, 0);
MEM_SET_IN_STRUCT_P (tgtblk, AGGREGATE_TYPE_P (type));
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,
BLKmode);
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,
bitsize / BITS_PER_UNIT,
BITS_PER_WORD),
bitsize / BITS_PER_UNIT, 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, gen_rtx_REG (reg_raw_mode[regno + i], 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);
}
}
static void
clear_by_pieces (to, len, align)
rtx to;
int len, align;
{
struct clear_by_pieces data;
rtx to_addr = XEXP (to, 0);
int max_size = MOVE_MAX_PIECES + 1;
enum machine_mode mode = VOIDmode, tmode;
enum insn_code icode;
data.offset = 0;
data.to_addr = to_addr;
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.explicit_inc_to = 0;
data.reverse
= (GET_CODE (to_addr) == PRE_DEC || GET_CODE (to_addr) == POST_DEC);
if (data.reverse) data.offset = len;
data.len = len;
data.to_struct = MEM_IN_STRUCT_P (to);
if (!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_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
|| align > MOVE_MAX || align >= BIGGEST_ALIGNMENT / BITS_PER_UNIT)
align = MOVE_MAX;
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 >= MIN (BIGGEST_ALIGNMENT / BITS_PER_UNIT,
GET_MODE_SIZE (mode)))
clear_by_pieces_1 (GEN_FCN (icode), mode, &data);
max_size = GET_MODE_SIZE (mode);
}
if (data.len != 0)
abort ();
}
static void
clear_by_pieces_1 (genfun, mode, data)
rtx (*genfun) PROTO ((rtx, ...));
enum machine_mode mode;
struct clear_by_pieces *data;
{
register int size = GET_MODE_SIZE (mode);
register rtx to1;
while (data->len >= size)
{
if (data->reverse) data->offset -= size;
to1 = (data->autinc_to
? gen_rtx_MEM (mode, data->to_addr)
: copy_rtx (change_address (data->to, mode,
plus_constant (data->to_addr,
data->offset))));
MEM_IN_STRUCT_P (to1) = data->to_struct;
if (HAVE_PRE_DECREMENT && data->explicit_inc_to < 0)
emit_insn (gen_add2_insn (data->to_addr, GEN_INT (-size)));
emit_insn ((*genfun) (to1, const0_rtx));
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, align)
rtx object;
rtx size;
int align;
{
#ifdef TARGET_MEM_FUNCTIONS
static tree fn;
tree call_expr, arg_list;
#endif
rtx retval = 0;
if (GET_MODE (object) == BLKmode)
{
object = protect_from_queue (object, 1);
size = protect_from_queue (size, 0);
if (GET_CODE (size) == CONST_INT
&& MOVE_BY_PIECES_P (INTVAL (size), align))
clear_by_pieces (object, INTVAL (size), align);
else
{
rtx opalign = GEN_INT (align);
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];
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)
&& (insn_operand_predicate[(int) code][0] == 0
|| (*insn_operand_predicate[(int) code][0]) (object,
BLKmode))
&& (insn_operand_predicate[(int) code][2] == 0
|| (*insn_operand_predicate[(int) code][2]) (opalign,
VOIDmode)))
{
rtx op1;
rtx last = get_last_insn ();
rtx pat;
op1 = convert_to_mode (mode, size, 1);
if (insn_operand_predicate[(int) code][1] != 0
&& ! (*insn_operand_predicate[(int) code][1]) (op1,
mode))
op1 = copy_to_mode_reg (mode, op1);
pat = GEN_FCN ((int) code) (object, op1, opalign);
if (pat)
{
emit_insn (pat);
return 0;
}
else
delete_insns_since (last);
}
}
object = copy_to_mode_reg (Pmode, XEXP (object, 0));
#ifdef TARGET_MEM_FUNCTIONS
size = copy_to_mode_reg (TYPE_MODE (sizetype), size);
#else
size = convert_to_mode (TYPE_MODE (integer_type_node), size,
TREE_UNSIGNED (integer_type_node));
size = copy_to_mode_reg (TYPE_MODE (integer_type_node), size);
#endif
#ifdef TARGET_MEM_FUNCTIONS
if (fn == NULL_TREE)
{
tree fntype;
fn = get_identifier ("memset");
push_obstacks_nochange ();
end_temporary_allocation ();
fntype = build_pointer_type (void_type_node);
fntype = build_function_type (fntype, NULL_TREE);
fn = build_decl (FUNCTION_DECL, fn, fntype);
DECL_EXTERNAL (fn) = 1;
TREE_PUBLIC (fn) = 1;
DECL_ARTIFICIAL (fn) = 1;
make_decl_rtl (fn, NULL_PTR, 1);
assemble_external (fn);
pop_obstacks ();
}
arg_list
= build_tree_list (NULL_TREE,
make_tree (build_pointer_type (void_type_node),
object));
TREE_CHAIN (arg_list)
= build_tree_list (NULL_TREE,
make_tree (integer_type_node, const0_rtx));
TREE_CHAIN (TREE_CHAIN (arg_list))
= build_tree_list (NULL_TREE, make_tree (sizetype, size));
TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (arg_list))) = NULL_TREE;
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);
#else
emit_library_call (bzero_libfunc, 0,
VOIDmode, 2, object, Pmode, size,
TYPE_MODE (integer_type_node));
#endif
}
}
else
emit_move_insn (object, CONST0_RTX (GET_MODE (object)));
return retval;
}
rtx
emit_move_insn (x, y)
rtx x, y;
{
enum machine_mode mode = GET_MODE (x);
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) && ! LEGITIMATE_CONSTANT_P (y))
y = force_const_mem (mode, y);
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 = change_address (x, VOIDmode, XEXP (x, 0));
if (GET_CODE (y) == MEM
&& (! memory_address_p (GET_MODE (y), XEXP (y, 0))
|| (flag_force_addr
&& CONSTANT_ADDRESS_P (XEXP (y, 0)))))
y = change_address (y, VOIDmode, XEXP (y, 0));
if (mode == BLKmode)
abort ();
return emit_move_insn_1 (x, y);
}
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);
int i;
if (mode >= 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 = mode_for_size ((GET_MODE_UNIT_SIZE (mode)
* BITS_PER_UNIT),
(class == MODE_COMPLEX_INT
? MODE_INT : MODE_FLOAT),
0))
&& (mov_optab->handlers[(int) submode].insn_code
!= CODE_FOR_nothing))
{
int stack = push_operand (x, GET_MODE (x));
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
{
if (x != y
&& ! (reload_in_progress || reload_completed))
{
emit_insn (gen_rtx_CLOBBER (VOIDmode, x));
}
emit_insn (GEN_FCN (mov_optab->handlers[(int) submode].insn_code)
(gen_realpart (submode, x), gen_realpart (submode, y)));
emit_insn (GEN_FCN (mov_optab->handlers[(int) submode].insn_code)
(gen_imagpart (submode, x), gen_imagpart (submode, y)));
}
return get_last_insn ();
}
else if (GET_MODE_SIZE (mode) > UNITS_PER_WORD)
{
rtx last_insn = 0;
#ifdef PUSH_ROUNDING
if (push_operand (x, GET_MODE (x)))
{
anti_adjust_stack (GEN_INT (GET_MODE_SIZE (GET_MODE (x))));
x = change_address (x, VOIDmode, stack_pointer_rtx);
}
#endif
if (x != y
&& ! (reload_in_progress || reload_completed))
{
emit_insn (gen_rtx_CLOBBER (VOIDmode, x));
}
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 ();
last_insn = emit_move_insn (xpart, ypart);
}
return last_insn;
}
else
abort ();
}
rtx
push_block (size, extra, below)
rtx size;
int extra, below;
{
register 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
{
rtx 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);
}
#if defined (STACK_GROWS_DOWNWARD) \
|| (defined (ARGS_GROW_DOWNWARD) \
&& !defined (ACCUMULATE_OUTGOING_ARGS))
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));
#endif
return memory_address (GET_CLASS_NARROWEST_MODE (MODE_INT), temp);
}
rtx
gen_push_operand ()
{
return gen_rtx_fmt_e (STACK_PUSH_CODE, Pmode, stack_pointer_rtx);
}
static rtx
get_push_address (size)
int size;
{
register rtx temp;
if (STACK_PUSH_CODE == POST_DEC)
temp = gen_rtx_PLUS (Pmode, stack_pointer_rtx, GEN_INT (size));
else if (STACK_PUSH_CODE == POST_INC)
temp = gen_rtx_MINUS (Pmode, stack_pointer_rtx, GEN_INT (size));
else
temp = stack_pointer_rtx;
return copy_to_reg (temp);
}
void
emit_push_insn (x, mode, type, size, align, partial, reg, extra,
args_addr, args_so_far, reg_parm_stack_space)
register rtx x;
enum machine_mode mode;
tree type;
rtx size;
int align;
int partial;
rtx reg;
int extra;
rtx args_addr;
rtx args_so_far;
int reg_parm_stack_space;
{
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_INC || 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)
{
register rtx temp;
int used = partial * UNITS_PER_WORD;
int offset = used % (PARM_BOUNDARY / BITS_PER_UNIT);
int skip;
if (size == 0)
abort ();
used -= offset;
if (partial != 0)
xinner = change_address (xinner, BLKmode,
plus_constant (XEXP (xinner, 0), used));
skip = (reg_parm_stack_space == 0) ? 0 : used;
#ifdef PUSH_ROUNDING
if (args_addr == 0
&& GET_CODE (size) == CONST_INT
&& skip == 0
&& (MOVE_BY_PIECES_P ((unsigned) INTVAL (size) - used, align))
&& ((! SLOW_UNALIGNED_ACCESS)
|| align >= BIGGEST_ALIGNMENT / BITS_PER_UNIT
|| PUSH_ROUNDING (align) == align)
&& 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 (gen_rtx_MEM (BLKmode, gen_push_operand ()), xinner,
INTVAL (size) - used, align);
if (current_function_check_memory_usage && ! in_check_memory_usage)
{
rtx temp;
in_check_memory_usage = 1;
temp = get_push_address (INTVAL(size) - used);
if (GET_CODE (x) == MEM && type && AGGREGATE_TYPE_P (type))
emit_library_call (chkr_copy_bitmap_libfunc, 1, VOIDmode, 3,
temp, Pmode,
XEXP (xinner, 0), Pmode,
GEN_INT (INTVAL(size) - used),
TYPE_MODE (sizetype));
else
emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3,
temp, Pmode,
GEN_INT (INTVAL(size) - used),
TYPE_MODE (sizetype),
GEN_INT (MEMORY_USE_RW),
TYPE_MODE (integer_type_node));
in_check_memory_usage = 0;
}
}
else
#endif
{
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 (current_function_check_memory_usage && ! in_check_memory_usage)
{
rtx target;
in_check_memory_usage = 1;
target = copy_to_reg (temp);
if (GET_CODE (x) == MEM && type && AGGREGATE_TYPE_P (type))
emit_library_call (chkr_copy_bitmap_libfunc, 1, VOIDmode, 3,
target, Pmode,
XEXP (xinner, 0), Pmode,
size, TYPE_MODE (sizetype));
else
emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3,
target, Pmode,
size, TYPE_MODE (sizetype),
GEN_INT (MEMORY_USE_RW),
TYPE_MODE (integer_type_node));
in_check_memory_usage = 0;
}
if (GET_CODE (size) == CONST_INT
&& (MOVE_BY_PIECES_P ((unsigned) INTVAL (size), align)))
{
move_by_pieces (gen_rtx_MEM (BLKmode, temp), xinner,
INTVAL (size), align);
goto ret;
}
else
{
rtx opalign = GEN_INT (align);
enum machine_mode mode;
rtx target = gen_rtx_MEM (BLKmode, temp);
for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT);
mode != VOIDmode;
mode = GET_MODE_WIDER_MODE (mode))
{
enum insn_code code = movstr_optab[(int) mode];
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)
&& (insn_operand_predicate[(int) code][0] == 0
|| ((*insn_operand_predicate[(int) code][0])
(target, BLKmode)))
&& (insn_operand_predicate[(int) code][1] == 0
|| ((*insn_operand_predicate[(int) code][1])
(xinner, BLKmode)))
&& (insn_operand_predicate[(int) code][3] == 0
|| ((*insn_operand_predicate[(int) code][3])
(opalign, VOIDmode))))
{
rtx op2 = convert_to_mode (mode, size, 1);
rtx last = get_last_insn ();
rtx pat;
if (insn_operand_predicate[(int) code][2] != 0
&& ! ((*insn_operand_predicate[(int) code][2])
(op2, mode)))
op2 = copy_to_mode_reg (mode, op2);
pat = GEN_FCN ((int) code) (target, xinner,
op2, opalign);
if (pat)
{
emit_insn (pat);
goto ret;
}
else
delete_insns_since (last);
}
}
}
#ifndef 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);
#endif
NO_DEFER_POP;
#ifdef TARGET_MEM_FUNCTIONS
emit_library_call (memcpy_libfunc, 0,
VOIDmode, 3, temp, Pmode, XEXP (xinner, 0), Pmode,
convert_to_mode (TYPE_MODE (sizetype),
size, TREE_UNSIGNED (sizetype)),
TYPE_MODE (sizetype));
#else
emit_library_call (bcopy_libfunc, 0,
VOIDmode, 3, XEXP (xinner, 0), Pmode, temp, Pmode,
convert_to_mode (TYPE_MODE (integer_type_node),
size,
TREE_UNSIGNED (integer_type_node)),
TYPE_MODE (integer_type_node));
#endif
OK_DEFER_POP;
}
}
else if (partial > 0)
{
int size = GET_MODE_SIZE (mode) / UNITS_PER_WORD;
int i;
int not_stack;
int offset = partial % (PARM_BOUNDARY / 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),
word_mode, NULL_TREE, NULL_RTX, align, 0, NULL_RTX,
0, args_addr,
GEN_INT (args_offset + ((i - not_stack + skip)
* UNITS_PER_WORD)),
reg_parm_stack_space);
}
else
{
rtx addr;
rtx target = NULL_RTX;
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)
addr = gen_push_operand ();
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;
}
emit_move_insn (gen_rtx_MEM (mode, addr), x);
if (current_function_check_memory_usage && ! in_check_memory_usage)
{
in_check_memory_usage = 1;
if (target == 0)
target = get_push_address (GET_MODE_SIZE (mode));
if (GET_CODE (x) == MEM && type && AGGREGATE_TYPE_P (type))
emit_library_call (chkr_copy_bitmap_libfunc, 1, VOIDmode, 3,
target, Pmode,
XEXP (x, 0), Pmode,
GEN_INT (GET_MODE_SIZE (mode)),
TYPE_MODE (sizetype));
else
emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3,
target, Pmode,
GEN_INT (GET_MODE_SIZE (mode)),
TYPE_MODE (sizetype),
GEN_INT (MEMORY_USE_RW),
TYPE_MODE (integer_type_node));
in_check_memory_usage = 0;
}
}
ret:
if (partial > 0 && reg != 0)
{
if (GET_CODE (reg) == PARALLEL)
emit_group_load (reg, x, -1, align);
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));
}
rtx
expand_assignment (to, from, want_value, suggest_reg)
tree to, from;
int want_value;
int suggest_reg;
{
register 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)
{
enum machine_mode mode1;
int bitsize;
int bitpos;
tree offset;
int unsignedp;
int volatilep = 0;
tree tem;
int alignment;
push_temp_slots ();
tem = get_inner_reference (to, &bitsize, &bitpos, &offset, &mode1,
&unsignedp, &volatilep, &alignment);
if (mode1 == VOIDmode && want_value)
tem = stabilize_reference (tem);
to_rtx = expand_expr (tem, NULL_RTX, VOIDmode, EXPAND_MEMORY_USE_DONT);
if (offset != 0)
{
rtx offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, 0);
if (GET_CODE (to_rtx) != MEM)
abort ();
if (GET_MODE (offset_rtx) != ptr_mode)
{
#ifdef POINTERS_EXTEND_UNSIGNED
offset_rtx = convert_memory_address (ptr_mode, offset_rtx);
#else
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
&& (bitpos % bitsize) == 0
&& (bitsize % GET_MODE_ALIGNMENT (mode1)) == 0
&& (alignment * BITS_PER_UNIT) == GET_MODE_ALIGNMENT (mode1))
{
rtx temp = change_address (to_rtx, mode1,
plus_constant (XEXP (to_rtx, 0),
(bitpos /
BITS_PER_UNIT)));
if (GET_CODE (XEXP (temp, 0)) == REG)
to_rtx = temp;
else
to_rtx = change_address (to_rtx, mode1,
force_reg (GET_MODE (XEXP (temp, 0)),
XEXP (temp, 0)));
bitpos = 0;
}
to_rtx = change_address (to_rtx, VOIDmode,
gen_rtx_PLUS (ptr_mode, XEXP (to_rtx, 0),
force_reg (ptr_mode, offset_rtx)));
}
if (volatilep)
{
if (GET_CODE (to_rtx) == MEM)
{
if (offset == 0)
to_rtx = copy_rtx (to_rtx);
MEM_VOLATILE_P (to_rtx) = 1;
}
#if 0
else
abort ();
#endif
}
#ifdef NEXT_SEMANTICS
if ((TREE_CODE (TREE_OPERAND (to, 1)) == VAR_DECL
|| TREE_CODE (TREE_OPERAND (to, 1)) == FIELD_DECL)
&& DECL_RELATIVE (TREE_OPERAND (to, 1)))
from = (tree) build_binary_op (MINUS_EXPR, from,
build1 (ADDR_EXPR, TREE_TYPE (to), to));
#endif
if (TREE_CODE (to) == COMPONENT_REF
&& TREE_READONLY (TREE_OPERAND (to, 1)))
{
if (offset == 0)
to_rtx = copy_rtx (to_rtx);
RTX_UNCHANGING_P (to_rtx) = 1;
}
if (current_function_check_memory_usage && GET_CODE (to_rtx) == MEM)
{
rtx to_addr;
int size;
int best_mode_size;
enum machine_mode best_mode;
best_mode = get_best_mode (bitsize, bitpos,
TYPE_ALIGN (TREE_TYPE (tem)),
mode1, volatilep);
if (best_mode == VOIDmode)
best_mode = QImode;
best_mode_size = GET_MODE_BITSIZE (best_mode);
to_addr = plus_constant (XEXP (to_rtx, 0), (bitpos / BITS_PER_UNIT));
size = CEIL ((bitpos % best_mode_size) + bitsize, best_mode_size);
size *= GET_MODE_SIZE (best_mode);
if (size)
emit_library_call (chkr_check_addr_libfunc, 1, VOIDmode, 3,
to_addr, Pmode,
GEN_INT (size), TYPE_MODE (sizetype),
GEN_INT (MEMORY_USE_WO),
TYPE_MODE (integer_type_node));
}
result = store_field (to_rtx, bitsize, bitpos, mode1, from,
(want_value
? (enum machine_mode) TYPE_MODE (TREE_TYPE (to))
: VOIDmode),
unsignedp,
alignment,
int_size_in_bytes (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 && GET_CODE (DECL_RTL (to)) == REG))
{
rtx value;
push_temp_slots ();
value = expand_expr (from, NULL_RTX, VOIDmode, 0);
if (to_rtx == 0)
#ifdef NEXT_SEMANTICS
to_rtx = expand_expr (to, NULL_RTX, VOIDmode, EXPAND_CONST_ADDRESS);
#else
to_rtx = expand_expr (to, NULL_RTX, VOIDmode, EXPAND_MEMORY_USE_WO);
#endif
if (GET_CODE (to_rtx) == PARALLEL)
emit_group_load (to_rtx, value, int_size_in_bytes (TREE_TYPE (from)),
TYPE_ALIGN (TREE_TYPE (from)) / BITS_PER_UNIT);
else if (GET_MODE (to_rtx) == BLKmode)
emit_block_move (to_rtx, value, expr_size (from),
TYPE_ALIGN (TREE_TYPE (from)) / BITS_PER_UNIT);
else
{
#ifdef POINTERS_EXTEND_UNSIGNED
if (TREE_CODE (TREE_TYPE (to)) == REFERENCE_TYPE
|| TREE_CODE (TREE_TYPE (to)) == POINTER_TYPE)
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)
{
#ifdef NEXT_SEMANTICS
to_rtx = expand_expr (to, NULL_RTX, VOIDmode, EXPAND_CONST_ADDRESS);
if ((TREE_CODE (to) == VAR_DECL
|| TREE_CODE (to) == FIELD_DECL)
&& DECL_RELATIVE (to))
{
from = (tree) build_binary_op (MINUS_EXPR, from,
build1 (ADDR_EXPR, TREE_TYPE (to), to));
}
#else
to_rtx = expand_expr (to, NULL_RTX, VOIDmode, EXPAND_MEMORY_USE_WO);
#endif
if (GET_CODE (to_rtx) == MEM)
MEM_ALIAS_SET (to_rtx) = get_alias_set (to);
}
if (TREE_CODE (to) == RESULT_DECL && GET_CODE (to_rtx) == REG)
{
rtx temp;
push_temp_slots ();
temp = expand_expr (from, 0, GET_MODE (to_rtx), 0);
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,
EXPAND_MEMORY_USE_DONT);
if (current_function_check_memory_usage)
emit_library_call (chkr_copy_bitmap_libfunc, 1, 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));
#ifdef TARGET_MEM_FUNCTIONS
emit_library_call (memcpy_libfunc, 0,
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, 0,
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));
#endif
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)
register tree exp;
register rtx target;
int want_value;
{
register rtx temp;
int dont_return_target = 0;
if (TREE_CODE (exp) == COMPOUND_EXPR)
{
expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode, 0);
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, 0);
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, 0);
end_cleanup_deferral ();
emit_queue ();
emit_label (lab2);
OK_DEFER_POP;
return want_value ? 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), 0);
}
else
temp = expand_expr (exp, NULL_RTX, GET_MODE (target), 0);
if (! MEM_VOLATILE_P (target) && want_value)
dont_return_target = 1;
}
else if (want_value && GET_CODE (target) == MEM && ! MEM_VOLATILE_P (target)
&& GET_MODE (target) != BLKmode)
{
temp = expand_expr (exp, cse_not_expected ? NULL_RTX : target,
GET_MODE (target), 0);
if (GET_MODE (temp) != BLKmode && GET_MODE (temp) != VOIDmode)
temp = copy_to_reg (temp);
dont_return_target = 1;
}
else if (GET_CODE (target) == SUBREG && SUBREG_PROMOTED_VAR_P (target))
{
if (! want_value && INTEGRAL_TYPE_P (TREE_TYPE (exp))
&& TREE_TYPE (TREE_TYPE (exp)) == 0)
{
if (TREE_UNSIGNED (TREE_TYPE (exp))
!= SUBREG_PROMOTED_UNSIGNED_P (target))
exp
= convert
(signed_or_unsigned_type (SUBREG_PROMOTED_UNSIGNED_P (target),
TREE_TYPE (exp)),
exp);
exp = convert (type_for_mode (GET_MODE (SUBREG_REG (target)),
SUBREG_PROMOTED_UNSIGNED_P (target)),
exp);
}
temp = expand_expr (exp, NULL_RTX, VOIDmode, 0);
if (GET_CODE (temp) == MEM && want_value
&& (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 (SUBREG_REG (target)),
TYPE_MODE (TREE_TYPE (exp)), temp,
SUBREG_PROMOTED_UNSIGNED_P (target));
convert_move (SUBREG_REG (target), temp,
SUBREG_PROMOTED_UNSIGNED_P (target));
return want_value ? temp : NULL_RTX;
}
else
{
temp = expand_expr (exp, target, GET_MODE (target), 0);
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))
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 (current_function_check_memory_usage
&& GET_CODE (target) == MEM
&& AGGREGATE_TYPE_P (TREE_TYPE (exp)))
{
if (GET_CODE (temp) == MEM)
emit_library_call (chkr_copy_bitmap_libfunc, 1, VOIDmode, 3,
XEXP (target, 0), Pmode,
XEXP (temp, 0), Pmode,
expr_size (exp), TYPE_MODE (sizetype));
else
emit_library_call (chkr_check_addr_libfunc, 1, VOIDmode, 3,
XEXP (target, 0), Pmode,
expr_size (exp), TYPE_MODE (sizetype),
GEN_INT (MEMORY_USE_WO),
TYPE_MODE (integer_type_node));
}
if ((! rtx_equal_p (temp, target)
|| (temp != target && (side_effects_p (temp)
|| side_effects_p (target))))
&& TREE_CODE (exp) != ERROR_MARK)
{
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;
rtx addr;
size = expr_size (exp);
if (GET_CODE (size) == CONST_INT
&& INTVAL (size) < TREE_STRING_LENGTH (exp))
emit_block_move (target, temp, size,
TYPE_ALIGN (TREE_TYPE (exp)) / BITS_PER_UNIT);
else
{
tree copy_size
= size_binop (MIN_EXPR,
make_tree (sizetype, size),
convert (sizetype,
build_int_2 (TREE_STRING_LENGTH (exp), 0)));
rtx copy_size_rtx = expand_expr (copy_size, NULL_RTX,
VOIDmode, 0);
rtx label = 0;
emit_block_move (target, temp, copy_size_rtx,
TYPE_ALIGN (TREE_TYPE (exp)) / BITS_PER_UNIT);
addr = XEXP (target, 0);
addr = convert_modes (ptr_mode, Pmode, addr, 1);
if (GET_CODE (copy_size_rtx) == CONST_INT)
{
addr = plus_constant (addr, TREE_STRING_LENGTH (exp));
size = plus_constant (size, - TREE_STRING_LENGTH (exp));
}
else
{
addr = force_reg (ptr_mode, addr);
addr = expand_binop (ptr_mode, add_optab, addr,
copy_size_rtx, NULL_RTX, 0,
OPTAB_LIB_WIDEN);
size = expand_binop (ptr_mode, sub_optab, size,
copy_size_rtx, NULL_RTX, 0,
OPTAB_LIB_WIDEN);
label = gen_label_rtx ();
emit_cmp_and_jump_insns (size, const0_rtx, LT, NULL_RTX,
GET_MODE (size), 0, 0, label);
}
if (size != const0_rtx)
{
if (current_function_check_memory_usage)
emit_library_call (chkr_check_addr_libfunc, 1, VOIDmode, 3,
addr, Pmode,
size, TYPE_MODE (sizetype),
GEN_INT (MEMORY_USE_WO),
TYPE_MODE (integer_type_node));
#ifdef TARGET_MEM_FUNCTIONS
emit_library_call (memset_libfunc, 0, VOIDmode, 3,
addr, ptr_mode,
const0_rtx, TYPE_MODE (integer_type_node),
convert_to_mode (TYPE_MODE (sizetype),
size,
TREE_UNSIGNED (sizetype)),
TYPE_MODE (sizetype));
#else
emit_library_call (bzero_libfunc, 0, VOIDmode, 2,
addr, ptr_mode,
convert_to_mode (TYPE_MODE (integer_type_node),
size,
TREE_UNSIGNED (integer_type_node)),
TYPE_MODE (integer_type_node));
#endif
}
if (label)
emit_label (label);
}
}
else if (GET_CODE (target) == PARALLEL)
emit_group_load (target, temp, int_size_in_bytes (TREE_TYPE (exp)),
TYPE_ALIGN (TREE_TYPE (exp)) / BITS_PER_UNIT);
else if (GET_MODE (temp) == BLKmode)
emit_block_move (target, temp, expr_size (exp),
TYPE_ALIGN (TREE_TYPE (exp)) / BITS_PER_UNIT);
else
emit_move_insn (target, temp);
}
if (! want_value)
return NULL_RTX;
else if (dont_return_target && GET_CODE (temp) != MEM)
return temp;
else if (want_value && 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:
return is_zeros_p (TREE_OPERAND (exp, 0));
case INTEGER_CST:
return TREE_INT_CST_LOW (exp) == 0 && TREE_INT_CST_HIGH (exp) == 0;
case COMPLEX_CST:
return
is_zeros_p (TREE_REALPART (exp)) && is_zeros_p (TREE_IMAGPART (exp));
case VECTOR_CST:
return (is_zeros_p (TREE_VECTOR_CST_LOW (exp))
&& is_zeros_p (TREE_VECTOR_CST_HIGH (exp)));
case REAL_CST:
return REAL_VALUES_IDENTICAL (TREE_REAL_CST (exp), dconst0);
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)
rtx target;
int bitsize, bitpos;
enum machine_mode mode;
tree exp, type;
int cleared;
{
if (TREE_CODE (exp) == CONSTRUCTOR
&& bitpos % BITS_PER_UNIT == 0
&& (bitpos == 0 || GET_CODE (target) == MEM))
{
if (bitpos != 0)
target = change_address (target, VOIDmode,
plus_constant (XEXP (target, 0),
bitpos / BITS_PER_UNIT));
store_constructor (exp, target, cleared);
}
else
store_field (target, bitsize, bitpos, mode, exp,
VOIDmode, 0, TYPE_ALIGN (type) / BITS_PER_UNIT,
int_size_in_bytes (type), 0);
}
static void
store_constructor (exp, target, cleared)
tree exp;
rtx target;
int cleared;
{
tree type = TREE_TYPE (exp);
rtx exp_size = expr_size (exp);
#if 0
if (GET_CODE (target) == REG && REGNO (target) < FIRST_PSEUDO_REGISTER)
{
rtx temp = gen_reg_rtx (GET_MODE (target));
store_constructor (exp, temp, 0);
emit_move_insn (target, temp);
return;
}
#endif
if (TREE_CODE (type) == RECORD_TYPE || TREE_CODE (type) == UNION_TYPE
|| TREE_CODE (type) == QUAL_UNION_TYPE)
{
register tree elt;
if (TREE_CODE (type) == UNION_TYPE
|| TREE_CODE (type) == QUAL_UNION_TYPE)
emit_insn (gen_rtx_CLOBBER (VOIDmode, target));
else if (GET_CODE (target) == REG && TREE_STATIC (exp)
&& GET_MODE_SIZE (GET_MODE (target)) <= UNITS_PER_WORD)
{
if (! cleared)
emit_move_insn (target, CONST0_RTX (GET_MODE (target)));
cleared = 1;
}
else if ((list_length (CONSTRUCTOR_ELTS (exp))
!= list_length (TYPE_FIELDS (type)))
|| mostly_zeros_p (exp))
{
if (! cleared)
clear_storage (target, expr_size (exp),
TYPE_ALIGN (type) / BITS_PER_UNIT);
cleared = 1;
}
else
emit_insn (gen_rtx_CLOBBER (VOIDmode, target));
for (elt = CONSTRUCTOR_ELTS (exp); elt; elt = TREE_CHAIN (elt))
{
register tree field = TREE_PURPOSE (elt);
tree value = TREE_VALUE (elt);
register enum machine_mode mode;
int bitsize;
int bitpos = 0;
int unsignedp;
tree pos, constant = 0, offset = 0;
rtx to_rtx = target;
if (field == 0)
continue;
if (cleared && is_zeros_p (TREE_VALUE (elt)))
continue;
bitsize = TREE_INT_CST_LOW (DECL_SIZE (field));
unsignedp = TREE_UNSIGNED (field);
mode = DECL_MODE (field);
if (DECL_BIT_FIELD (field))
mode = VOIDmode;
pos = DECL_FIELD_BITPOS (field);
if (TREE_CODE (pos) == INTEGER_CST)
constant = pos;
else if (TREE_CODE (pos) == PLUS_EXPR
&& TREE_CODE (TREE_OPERAND (pos, 1)) == INTEGER_CST)
constant = TREE_OPERAND (pos, 1), offset = TREE_OPERAND (pos, 0);
else
offset = pos;
if (constant)
bitpos = TREE_INT_CST_LOW (constant);
if (offset)
{
rtx offset_rtx;
if (contains_placeholder_p (offset))
offset = build (WITH_RECORD_EXPR, sizetype,
offset, make_tree (TREE_TYPE (exp), target));
offset = size_binop (FLOOR_DIV_EXPR, offset,
size_int (BITS_PER_UNIT));
offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, 0);
if (GET_CODE (to_rtx) != MEM)
abort ();
if (GET_MODE (offset_rtx) != ptr_mode)
{
#ifdef POINTERS_EXTEND_UNSIGNED
offset_rtx = convert_memory_address (ptr_mode, offset_rtx);
#else
offset_rtx = convert_to_mode (ptr_mode, offset_rtx, 0);
#endif
}
to_rtx
= change_address (to_rtx, VOIDmode,
gen_rtx_PLUS (ptr_mode, XEXP (to_rtx, 0),
force_reg (ptr_mode, offset_rtx)));
}
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 (constant
&& GET_CODE (target) == REG
&& bitsize < BITS_PER_WORD
&& bitpos % BITS_PER_WORD == 0
&& GET_MODE_CLASS (mode) == MODE_INT
&& TREE_CODE (value) == INTEGER_CST
&& GET_CODE (exp_size) == CONST_INT
&& bitpos + BITS_PER_WORD <= INTVAL (exp_size) * BITS_PER_UNIT)
{
tree type = TREE_TYPE (value);
if (TYPE_PRECISION (type) < BITS_PER_WORD)
{
type = 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
store_constructor_field (to_rtx, bitsize, bitpos,
mode, value, type, cleared);
}
}
else if (TREE_CODE (type) == ARRAY_TYPE)
{
register tree elt;
register int i;
int need_to_clear;
tree domain = TYPE_DOMAIN (type);
HOST_WIDE_INT minelt = TREE_INT_CST_LOW (TYPE_MIN_VALUE (domain));
HOST_WIDE_INT maxelt = TREE_INT_CST_LOW (TYPE_MAX_VALUE (domain));
tree elttype = TREE_TYPE (type);
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 = 0;
for (elt = CONSTRUCTOR_ELTS (exp);
elt != NULL_TREE;
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 (TREE_CODE (lo_index) != INTEGER_CST
|| TREE_CODE (hi_index) != INTEGER_CST)
{
need_to_clear = 1;
break;
}
this_node_count = TREE_INT_CST_LOW (hi_index)
- TREE_INT_CST_LOW (lo_index) + 1;
}
else
this_node_count = 1;
count += this_node_count;
if (mostly_zeros_p (TREE_VALUE (elt)))
zero_count += this_node_count;
}
if (count < maxelt - minelt + 1
|| 4 * zero_count >= 3 * count)
need_to_clear = 1;
}
if (need_to_clear)
{
if (! cleared)
clear_storage (target, expr_size (exp),
TYPE_ALIGN (type) / BITS_PER_UNIT);
cleared = 1;
}
else
emit_insn (gen_rtx_CLOBBER (VOIDmode, target));
for (elt = CONSTRUCTOR_ELTS (exp), i = 0;
elt;
elt = TREE_CHAIN (elt), i++)
{
register enum machine_mode mode;
int bitsize;
int bitpos;
int unsignedp;
tree value = TREE_VALUE (elt);
tree index = TREE_PURPOSE (elt);
rtx xtarget = target;
if (cleared && is_zeros_p (value))
continue;
mode = TYPE_MODE (elttype);
bitsize = GET_MODE_BITSIZE (mode);
unsignedp = TREE_UNSIGNED (elttype);
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, addr, hi_r, loop_top, loop_end;
struct nesting *loop;
HOST_WIDE_INT lo, hi, count;
tree position;
if (TREE_CODE (lo_index) == INTEGER_CST
&& TREE_CODE (hi_index) == INTEGER_CST
&& (lo = TREE_INT_CST_LOW (lo_index),
hi = TREE_INT_CST_LOW (hi_index),
count = hi - lo + 1,
(GET_CODE (target) != MEM
|| count <= 2
|| (TREE_CODE (TYPE_SIZE (elttype)) == INTEGER_CST
&& TREE_INT_CST_LOW (TYPE_SIZE (elttype)) * count
<= 40 * 8))))
{
lo -= minelt; hi -= minelt;
for (; lo <= hi; lo++)
{
bitpos = lo * TREE_INT_CST_LOW (TYPE_SIZE (elttype));
store_constructor_field (target, bitsize, bitpos,
mode, value, type, cleared);
}
}
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);
DECL_RTL (index) = index_r
= gen_reg_rtx (promote_mode (domain, DECL_MODE (index),
&unsignedp, 0));
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);
position = size_binop (EXACT_DIV_EXPR, TYPE_SIZE (elttype),
size_int (BITS_PER_UNIT));
position = size_binop (MULT_EXPR,
size_binop (MINUS_EXPR, index,
TYPE_MIN_VALUE (domain)),
position);
pos_rtx = expand_expr (position, 0, VOIDmode, 0);
addr = gen_rtx_PLUS (Pmode, XEXP (target, 0), pos_rtx);
xtarget = change_address (target, mode, addr);
if (TREE_CODE (value) == CONSTRUCTOR)
store_constructor (value, xtarget, cleared);
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);
emit_insn (gen_rtx_USE (GET_MODE (target), target));
}
}
else if ((index != 0 && TREE_CODE (index) != INTEGER_CST)
|| TREE_CODE (TYPE_SIZE (elttype)) != INTEGER_CST)
{
rtx pos_rtx, addr;
tree position;
if (index == 0)
index = size_int (i);
if (minelt)
index = size_binop (MINUS_EXPR, index,
TYPE_MIN_VALUE (domain));
position = size_binop (EXACT_DIV_EXPR, TYPE_SIZE (elttype),
size_int (BITS_PER_UNIT));
position = size_binop (MULT_EXPR, index, position);
pos_rtx = expand_expr (position, 0, VOIDmode, 0);
addr = gen_rtx_PLUS (Pmode, XEXP (target, 0), pos_rtx);
xtarget = change_address (target, mode, addr);
store_expr (value, xtarget, 0);
}
else
{
if (index != 0)
bitpos = ((TREE_INT_CST_LOW (index) - minelt)
* TREE_INT_CST_LOW (TYPE_SIZE (elttype)));
else
bitpos = (i * TREE_INT_CST_LOW (TYPE_SIZE (elttype)));
store_constructor_field (target, bitsize, bitpos,
mode, value, type, cleared);
}
}
}
else if (TREE_CODE (type) == SET_TYPE)
{
tree elt = CONSTRUCTOR_ELTS (exp);
int nbytes = int_size_in_bytes (type), nbits;
tree domain = TYPE_DOMAIN (type);
tree domain_min, domain_max, bitlength;
if (elt == NULL_TREE)
{
if (!cleared)
clear_storage (target, expr_size (exp),
TYPE_ALIGN (type) / BITS_PER_UNIT);
return;
}
domain_min = convert (sizetype, TYPE_MIN_VALUE (domain));
domain_max = convert (sizetype, TYPE_MAX_VALUE (domain));
bitlength = size_binop (PLUS_EXPR,
size_binop (MINUS_EXPR, domain_max, domain_min),
size_one_node);
if (nbytes < 0 || TREE_CODE (bitlength) != INTEGER_CST)
abort ();
nbits = TREE_INT_CST_LOW (bitlength);
if (GET_MODE (target) != BLKmode || nbits <= 2 * BITS_PER_WORD
|| (nbytes <= 32 && TREE_CHAIN (elt) != NULL_TREE))
{
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;
int bit_pos = 0;
int ibit = 0;
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 = plus_constant (XEXP (target, 0), offset);
to_rtx = change_address (target, mode, to_rtx);
}
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
: (TREE_CODE (TREE_VALUE (elt)) != INTEGER_CST
|| TREE_CODE (TREE_PURPOSE (elt)) != INTEGER_CST
|| (TREE_INT_CST_LOW (TREE_VALUE (elt))
- TREE_INT_CST_LOW (TREE_PURPOSE (elt)) + 1
!= nbits))))
clear_storage (target, expr_size (exp),
TYPE_ALIGN (type) / BITS_PER_UNIT);
}
for (; elt != NULL_TREE; elt = TREE_CHAIN (elt))
{
tree startbit = TREE_PURPOSE (elt);
tree endbit = TREE_VALUE (elt);
#ifdef TARGET_MEM_FUNCTIONS
HOST_WIDE_INT startb, endb;
#endif
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_stack_temp (GET_MODE (target),
GET_MODE_SIZE (GET_MODE (target)),
0);
emit_move_insn (targetx, target);
}
else if (GET_CODE (target) == MEM)
targetx = target;
else
abort ();
#ifdef TARGET_MEM_FUNCTIONS
if (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, 0,
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
#endif
{
emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__setbits"),
0, 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, align, total_size, alias_set)
rtx target;
int bitsize, bitpos;
enum machine_mode mode;
tree exp;
enum machine_mode value_mode;
int unsignedp;
int align;
int total_size;
int alias_set;
{
HOST_WIDE_INT width_mask = 0;
if (TREE_CODE (exp) == ERROR_MARK)
return const0_rtx;
if (bitsize < HOST_BITS_PER_WIDE_INT)
width_mask = ((HOST_WIDE_INT) 1 << bitsize) - 1;
if (mode == BLKmode
&& (GET_CODE (target) == REG || GET_CODE (target) == SUBREG))
{
rtx object = assign_stack_temp (GET_MODE (target),
GET_MODE_SIZE (GET_MODE (target)), 0);
rtx blk_object = copy_rtx (object);
MEM_SET_IN_STRUCT_P (object, 1);
MEM_SET_IN_STRUCT_P (blk_object, 1);
PUT_MODE (blk_object, BLKmode);
if (bitsize != GET_MODE_BITSIZE (GET_MODE (target)))
emit_move_insn (object, target);
store_field (blk_object, bitsize, bitpos, mode, exp, VOIDmode, 0,
align, total_size, alias_set);
emit_move_insn (target, object);
return blk_object;
}
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
|| (SLOW_UNALIGNED_ACCESS
&& align * BITS_PER_UNIT < GET_MODE_ALIGNMENT (mode))
|| (SLOW_UNALIGNED_ACCESS && bitpos % GET_MODE_ALIGNMENT (mode) != 0))
{
rtx temp = expand_expr (exp, NULL_RTX, VOIDmode, 0);
if (BYTES_BIG_ENDIAN && GET_MODE_CLASS (GET_MODE (temp)) == MODE_INT
&& bitsize < 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 = change_address (target, VOIDmode,
plus_constant (XEXP (target, 0),
bitpos / BITS_PER_UNIT));
emit_block_move (target, temp,
GEN_INT ((bitsize + BITS_PER_UNIT - 1)
/ BITS_PER_UNIT),
1);
return value_mode == VOIDmode ? const0_rtx : target;
}
store_bit_field (target, bitsize, bitpos, mode, temp, align, total_size);
if (value_mode != VOIDmode)
{
if (width_mask != 0
&& ! (GET_CODE (target) == MEM && MEM_VOLATILE_P (target)))
{
tree count;
enum machine_mode tmode;
if (unsignedp)
return expand_and (temp, GEN_INT (width_mask), NULL_RTX);
tmode = GET_MODE (temp);
if (tmode == VOIDmode)
tmode = value_mode;
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, 0, align,
total_size);
}
return const0_rtx;
}
else
{
rtx addr = XEXP (target, 0);
rtx to_rtx;
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)))
addr = copy_to_reg (addr);
to_rtx = copy_rtx (change_address (target, mode,
plus_constant (addr,
(bitpos
/ BITS_PER_UNIT))));
MEM_SET_IN_STRUCT_P (to_rtx, 1);
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, palignment)
tree exp;
int *pbitsize;
int *pbitpos;
tree *poffset;
enum machine_mode *pmode;
int *punsignedp;
int *pvolatilep;
int *palignment;
{
tree orig_exp = exp;
tree size_tree = 0;
enum machine_mode mode = VOIDmode;
tree offset = integer_zero_node;
unsigned int alignment = BIGGEST_ALIGNMENT;
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));
if (mode == BLKmode)
size_tree = TYPE_SIZE (TREE_TYPE (exp));
*pbitsize = GET_MODE_BITSIZE (mode);
*punsignedp = TREE_UNSIGNED (TREE_TYPE (exp));
}
if (size_tree)
{
if (TREE_CODE (size_tree) != INTEGER_CST)
mode = BLKmode, *pbitsize = -1;
else
*pbitsize = TREE_INT_CST_LOW (size_tree);
}
*pbitpos = 0;
while (1)
{
if (TREE_CODE (exp) == COMPONENT_REF || TREE_CODE (exp) == BIT_FIELD_REF)
{
tree pos = (TREE_CODE (exp) == COMPONENT_REF
? DECL_FIELD_BITPOS (TREE_OPERAND (exp, 1))
: TREE_OPERAND (exp, 2));
tree constant = integer_zero_node, var = pos;
if (pos == 0)
break;
if (TREE_CODE (pos) == PLUS_EXPR
&& TREE_CODE (TREE_OPERAND (pos, 1)) == INTEGER_CST)
constant = TREE_OPERAND (pos, 1), var = TREE_OPERAND (pos, 0);
else if (TREE_CODE (pos) == INTEGER_CST)
constant = pos, var = integer_zero_node;
*pbitpos += TREE_INT_CST_LOW (constant);
offset = size_binop (PLUS_EXPR, offset,
size_binop (EXACT_DIV_EXPR, var,
size_int (BITS_PER_UNIT)));
}
else if (TREE_CODE (exp) == ARRAY_REF)
{
tree index = TREE_OPERAND (exp, 1);
tree domain = TYPE_DOMAIN (TREE_TYPE (TREE_OPERAND (exp, 0)));
tree low_bound
= domain ? TYPE_MIN_VALUE (domain) : integer_zero_node;
tree index_type = TREE_TYPE (index);
tree xindex;
if (TYPE_PRECISION (index_type) != TYPE_PRECISION (sizetype))
{
index = convert (type_for_size (TYPE_PRECISION (sizetype), 0),
index);
index_type = TREE_TYPE (index);
}
if (! integer_zerop (low_bound))
index = fold (build (MINUS_EXPR, index_type, index,
convert (sizetype, low_bound)));
if (TREE_CODE (index) == INTEGER_CST)
{
index = convert (sbitsizetype, index);
index_type = TREE_TYPE (index);
}
xindex = fold (build (MULT_EXPR, sbitsizetype, index,
convert (sbitsizetype,
TYPE_SIZE (TREE_TYPE (exp)))));
if (TREE_CODE (xindex) == INTEGER_CST
&& TREE_INT_CST_HIGH (xindex) == 0)
*pbitpos += TREE_INT_CST_LOW (xindex);
else
{
xindex = fold (build (MULT_EXPR, ssizetype, index,
convert (ssizetype,
TYPE_SIZE_UNIT (TREE_TYPE (exp)))));
if (contains_placeholder_p (xindex))
xindex = build (WITH_RECORD_EXPR, sizetype, xindex, exp);
offset = size_binop (PLUS_EXPR, offset, xindex);
}
}
else if (TREE_CODE (exp) != NON_LVALUE_EXPR
&& ! ((TREE_CODE (exp) == NOP_EXPR
|| TREE_CODE (exp) == CONVERT_EXPR)
&& ! (TREE_CODE (TREE_TYPE (exp)) == UNION_TYPE
&& (TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 0)))
!= UNION_TYPE))
&& (TYPE_MODE (TREE_TYPE (exp))
== TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))))))
break;
if (TREE_THIS_VOLATILE (exp))
*pvolatilep = 1;
if (! integer_zerop (offset))
alignment = MIN (alignment, TYPE_ALIGN (TREE_TYPE (exp)));
exp = TREE_OPERAND (exp, 0);
}
if (TREE_CODE_CLASS (TREE_CODE (exp)) == 'd')
alignment = MIN (alignment, DECL_ALIGN (exp));
else if (TREE_TYPE (exp) != 0)
alignment = MIN (alignment, TYPE_ALIGN (TREE_TYPE (exp)));
if (integer_zerop (offset))
offset = 0;
if (offset != 0 && contains_placeholder_p (offset))
offset = build (WITH_RECORD_EXPR, sizetype, offset, orig_exp);
*pmode = mode;
*poffset = offset;
*palignment = alignment / BITS_PER_UNIT;
return exp;
}
static enum memory_use_mode
get_memory_usage_from_modifier (modifier)
enum expand_modifier modifier;
{
switch (modifier)
{
case EXPAND_NORMAL:
case EXPAND_SUM:
return MEMORY_USE_RO;
break;
case EXPAND_MEMORY_USE_WO:
return MEMORY_USE_WO;
break;
case EXPAND_MEMORY_USE_RW:
return MEMORY_USE_RW;
break;
case EXPAND_MEMORY_USE_DONT:
case EXPAND_CONST_ADDRESS:
case EXPAND_INITIALIZER:
return MEMORY_USE_DONT;
case EXPAND_MEMORY_USE_BAD:
default:
abort ();
}
}
rtx
force_operand (value, target)
rtx value, target;
{
register optab binoptab = 0;
rtx tmp;
register rtx op2;
register rtx subtarget = (target != 0 && GET_CODE (target) == REG ? target : 0);
if (flag_pic
&& (GET_CODE (value) == PLUS || GET_CODE (value) == 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 (GET_CODE (value) == PLUS)
binoptab = add_optab;
else if (GET_CODE (value) == MINUS)
binoptab = sub_optab;
else if (GET_CODE (value) == MULT)
{
op2 = XEXP (value, 1);
if (!CONSTANT_P (op2)
&& !(GET_CODE (op2) == REG && op2 != subtarget))
subtarget = 0;
tmp = force_operand (XEXP (value, 0), subtarget);
return expand_mult (GET_MODE (value), tmp,
force_operand (op2, NULL_RTX),
target, 0);
}
if (binoptab)
{
op2 = XEXP (value, 1);
if (!CONSTANT_P (op2)
&& !(GET_CODE (op2) == REG && op2 != subtarget))
subtarget = 0;
if (binoptab == sub_optab && GET_CODE (op2) == CONST_INT)
{
binoptab = add_optab;
op2 = negate_rtx (GET_MODE (value), op2);
}
if (binoptab == add_optab && 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_binop (GET_MODE (value), binoptab,
XEXP (XEXP (value, 0), 0), op2,
subtarget, 0, OPTAB_LIB_WIDEN);
return expand_binop (GET_MODE (value), binoptab, temp,
force_operand (XEXP (XEXP (value, 0), 1), 0),
target, 0, OPTAB_LIB_WIDEN);
}
tmp = force_operand (XEXP (value, 0), subtarget);
return expand_binop (GET_MODE (value), binoptab, tmp,
force_operand (op2, NULL_RTX),
target, 0, OPTAB_LIB_WIDEN);
}
return value;
}
static tree
save_noncopied_parts (lhs, list)
tree lhs;
tree list;
{
tree tail;
tree parts = 0;
for (tail = list; tail; tail = TREE_CHAIN (tail))
if (TREE_CODE (TREE_VALUE (tail)) == TREE_LIST)
parts = chainon (parts, save_noncopied_parts (lhs, TREE_VALUE (tail)));
else
{
tree part = TREE_VALUE (tail);
tree part_type = TREE_TYPE (part);
tree to_be_saved = build (COMPONENT_REF, part_type, lhs, part);
rtx target = assign_temp (part_type, 0, 1, 1);
if (! memory_address_p (TYPE_MODE (part_type), XEXP (target, 0)))
target = change_address (target, TYPE_MODE (part_type), NULL_RTX);
parts = tree_cons (to_be_saved,
build (RTL_EXPR, part_type, NULL_TREE,
(tree) target),
parts);
store_expr (TREE_PURPOSE (parts), RTL_EXPR_RTL (TREE_VALUE (parts)), 0);
}
return parts;
}
static tree
init_noncopied_parts (lhs, list)
tree lhs;
tree list;
{
tree tail;
tree parts = 0;
for (tail = list; tail; tail = TREE_CHAIN (tail))
if (TREE_CODE (TREE_VALUE (tail)) == TREE_LIST)
parts = chainon (parts, init_noncopied_parts (lhs, TREE_VALUE (tail)));
else if (TREE_PURPOSE (tail))
{
tree part = TREE_VALUE (tail);
tree part_type = TREE_TYPE (part);
tree to_be_initialized = build (COMPONENT_REF, part_type, lhs, part);
parts = tree_cons (TREE_PURPOSE (tail), to_be_initialized, parts);
}
return parts;
}
static int
safe_from_p (x, exp, top_p)
rtx x;
tree exp;
int top_p;
{
rtx exp_rtl = 0;
int i, nops;
static int save_expr_count;
static int save_expr_size = 0;
static tree *save_expr_rewritten;
static tree save_expr_trees[256];
if (x == 0
|| (top_p && TREE_TYPE (exp) != 0 && TYPE_SIZE (TREE_TYPE (exp)) != 0
&& 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))
return 1;
if (top_p && save_expr_size == 0)
{
int rtn;
save_expr_count = 0;
save_expr_size = sizeof (save_expr_trees) / sizeof (save_expr_trees[0]);
save_expr_rewritten = &save_expr_trees[0];
rtn = safe_from_p (x, exp, 1);
for (i = 0; i < save_expr_count; ++i)
{
if (TREE_CODE (save_expr_trees[i]) != ERROR_MARK)
abort ();
TREE_SET_CODE (save_expr_trees[i], SAVE_EXPR);
}
save_expr_size = 0;
return rtn;
}
if (GET_CODE (x) == SUBREG)
{
x = SUBREG_REG (x);
if (GET_CODE (x) == REG && REGNO (x) < FIRST_PSEUDO_REGISTER)
return 0;
}
if (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;
switch (TREE_CODE_CLASS (TREE_CODE (exp)))
{
case 'd':
exp_rtl = DECL_RTL (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:
return (staticp (TREE_OPERAND (exp, 0))
|| safe_from_p (x, TREE_OPERAND (exp, 0), 0)
|| TREE_STATIC (exp));
case INDIRECT_REF:
if (GET_CODE (x) == MEM)
return 0;
break;
case CALL_EXPR:
exp_rtl = CALL_EXPR_RTL (exp);
if (exp_rtl == 0)
{
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 = RTL_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 (save_expr_count >= save_expr_size)
return 0;
save_expr_rewritten[save_expr_count++] = exp;
nops = tree_code_length[(int) SAVE_EXPR];
for (i = 0; i < nops; i++)
{
tree operand = TREE_OPERAND (exp, i);
if (operand == NULL_TREE)
continue;
TREE_SET_CODE (exp, ERROR_MARK);
if (!safe_from_p (x, operand, 0))
return 0;
TREE_SET_CODE (exp, SAVE_EXPR);
}
TREE_SET_CODE (exp, ERROR_MARK);
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 = tree_code_length[(int) 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 (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
&& ! TREE_READONLY (exp)));
}
return 1;
}
static int
fixed_type_p (exp)
tree exp;
{
if (TREE_CODE (exp) == PARM_DECL
|| TREE_CODE (exp) == VAR_DECL
|| TREE_CODE (exp) == CALL_EXPR || TREE_CODE (exp) == TARGET_EXPR
|| TREE_CODE (exp) == COMPONENT_REF
|| TREE_CODE (exp) == ARRAY_REF)
return 1;
return 0;
}
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 = TREE_CODE (exp);
enum machine_mode mode;
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)
fatal ("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)
fatal ("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)
fatal ("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)
fatal ("unsupported wide integer operation");
}
}
#endif
rtx
expand_expr (exp, target, tmode, modifier)
register tree exp;
rtx target;
enum machine_mode tmode;
enum expand_modifier modifier;
{
static tree placeholder_list = 0;
register rtx op0, op1, temp;
tree type = TREE_TYPE (exp);
int unsignedp = TREE_UNSIGNED (type);
register enum machine_mode mode;
register enum tree_code code = TREE_CODE (exp);
optab this_optab;
rtx subtarget, original_target;
int ignore;
tree context;
enum expand_modifier ro_modifier;
if (TREE_CODE (exp) == ERROR_MARK)
{
op0 = CONST0_RTX (tmode);
if (op0 != 0)
return op0;
return const0_rtx;
}
mode = TYPE_MODE (type);
subtarget = (target != 0 && GET_CODE (target) == REG ? target : 0);
original_target = target;
ignore = (target == const0_rtx
|| ((code == NON_LVALUE_EXPR || code == NOP_EXPR
|| code == CONVERT_EXPR || code == REFERENCE_EXPR
|| code == COND_EXPR)
&& TREE_CODE (type) == VOID_TYPE));
if (modifier == EXPAND_NORMAL || modifier == EXPAND_SUM
|| modifier == EXPAND_CONST_ADDRESS || modifier == EXPAND_INITIALIZER)
ro_modifier = modifier;
else
ro_modifier = EXPAND_NORMAL;
if (subtarget && REGNO (subtarget) < FIRST_PSEUDO_REGISTER)
subtarget = 0;
if (preserve_subexpressions_p ())
subtarget = 0;
if (ignore)
{
if (! TREE_SIDE_EFFECTS (exp))
return const0_rtx;
if (TREE_THIS_VOLATILE (exp)
&& TREE_CODE (exp) != FUNCTION_DECL
&& mode != VOIDmode && mode != BLKmode)
{
temp = expand_expr (exp, NULL_RTX, VOIDmode, ro_modifier);
if (GET_CODE (temp) == MEM)
temp = copy_to_reg (temp);
return const0_rtx;
}
if (TREE_CODE_CLASS (code) == '1')
return expand_expr (TREE_OPERAND (exp, 0), const0_rtx,
VOIDmode, ro_modifier);
else if (TREE_CODE_CLASS (code) == '2'
|| TREE_CODE_CLASS (code) == '<')
{
expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode, ro_modifier);
expand_expr (TREE_OPERAND (exp, 1), const0_rtx, VOIDmode, ro_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, ro_modifier);
target = 0;
}
#ifdef MAX_INTEGER_COMPUTATION_MODE
if (target
&& TREE_CODE (exp) != INTEGER_CST
&& TREE_CODE (exp) != PARM_DECL
&& TREE_CODE (exp) != ARRAY_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)
{
enum machine_mode mode = GET_MODE (target);
if (GET_MODE_CLASS (mode) == MODE_INT
&& mode > MAX_INTEGER_COMPUTATION_MODE)
fatal ("unsupported wide integer operation");
}
if (TREE_CODE (exp) != INTEGER_CST
&& TREE_CODE (exp) != PARM_DECL
&& TREE_CODE (exp) != ARRAY_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
&& GET_MODE_CLASS (tmode) == MODE_INT
&& tmode > MAX_INTEGER_COMPUTATION_MODE)
fatal ("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))
target = subtarget;
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);
push_obstacks (p->function_obstack,
p->function_maybepermanent_obstack);
p->forced_labels = gen_rtx_EXPR_LIST (VOIDmode,
label_rtx (exp),
p->forced_labels);
pop_obstacks ();
}
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 (exp) == 0)
{
error_with_decl (exp, "prior parameter's size depends on `%s'");
return CONST0_RTX (mode);
}
case VAR_DECL:
if (DECL_SIZE (exp) == 0 && TYPE_SIZE (TREE_TYPE (exp)) != 0
&& (TREE_STATIC (exp) || DECL_EXTERNAL (exp)))
{
push_obstacks_nochange ();
end_temporary_allocation ();
layout_decl (exp, 0);
PUT_MODE (DECL_RTL (exp), DECL_MODE (exp));
pop_obstacks ();
}
if (current_function_check_memory_usage && code == VAR_DECL
&& GET_CODE (DECL_RTL (exp)) == MEM
&& ! AGGREGATE_TYPE_P (TREE_TYPE (exp)))
{
enum memory_use_mode memory_usage;
memory_usage = get_memory_usage_from_modifier (modifier);
if (memory_usage != MEMORY_USE_DONT)
emit_library_call (chkr_check_addr_libfunc, 1, VOIDmode, 3,
XEXP (DECL_RTL (exp), 0), Pmode,
GEN_INT (int_size_in_bytes (type)),
TYPE_MODE (sizetype),
GEN_INT (memory_usage),
TYPE_MODE (integer_type_node));
}
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 ();
mark_addressable (exp);
if (GET_CODE (DECL_RTL (exp)) != MEM)
abort ();
addr = XEXP (DECL_RTL (exp), 0);
if (GET_CODE (addr) == MEM)
addr = gen_rtx_MEM (Pmode,
fix_lexical_addr (XEXP (addr, 0), exp));
else
addr = fix_lexical_addr (addr, exp);
temp = change_address (DECL_RTL (exp), mode, addr);
#if defined (_WIN32) && defined (NEXT_PDO)
if (DECL_DLLIMPORT (exp))
temp = gen_rtx (MEM, Pmode, force_reg (Pmode, temp));
#endif
}
else if (GET_CODE (DECL_RTL (exp)) == MEM
&& GET_CODE (XEXP (DECL_RTL (exp), 0)) == REG)
#if defined (_WIN32) && defined (NEXT_PDO)
{
#endif
temp = change_address (DECL_RTL (exp), GET_MODE (DECL_RTL (exp)),
XEXP (DECL_RTL (exp), 0));
#if defined (_WIN32) && defined (NEXT_PDO)
if (DECL_DLLIMPORT (exp))
temp = gen_rtx (MEM, Pmode, force_reg (Pmode, temp));
}
#endif
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)))
#if defined (_WIN32) && defined (NEXT_PDO)
{
#endif
temp = change_address (DECL_RTL (exp), VOIDmode,
copy_rtx (XEXP (DECL_RTL (exp), 0)));
#if defined (_WIN32) && defined (NEXT_PDO)
if (DECL_DLLIMPORT (exp))
temp = gen_rtx (MEM, Pmode, force_reg (Pmode, temp));
}
#endif
if (temp != 0)
{
if (GET_CODE (temp) == MEM && GET_CODE (XEXP (temp, 0)) == REG)
mark_reg_pointer (XEXP (temp, 0),
DECL_ALIGN (exp) / BITS_PER_UNIT);
return temp;
}
if (GET_CODE (DECL_RTL (exp)) == REG
&& GET_MODE (DECL_RTL (exp)) != mode)
{
if (GET_MODE (DECL_RTL (exp))
!= promote_mode (type, DECL_MODE (exp), &unsignedp, 0))
abort ();
temp = gen_rtx_SUBREG (mode, DECL_RTL (exp), 0);
SUBREG_PROMOTED_VAR_P (temp) = 1;
SUBREG_PROMOTED_UNSIGNED_P (temp) = unsignedp;
#ifdef WIN32
if (DECL_DLLIMPORT (exp))
{
temp = gen_rtx (MEM, Pmode, force_reg (Pmode, temp));
}
#endif
return temp;
}
#ifdef WIN32
{
rtx loc = DECL_RTL (exp);
if (DECL_DLLIMPORT (exp))
{
rtx addr = copy_rtx (loc);
if (modifier == EXPAND_INITIALIZER)
fatal ("dllimport'ed value used as initializer");
PUT_MODE (addr, Pmode);
loc = gen_rtx (MEM, GET_MODE (loc), force_reg (Pmode, addr));
}
return loc;
}
#endif
#ifdef NEXT_SEMANTICS
if (code == VAR_DECL
&& modifier == EXPAND_NORMAL
&& DECL_RELATIVE (exp))
{
rtx op0 = memory_address (mode, XEXP (DECL_RTL (exp), 0));
rtx op1 = gen_rtx (PLUS, mode, op0, DECL_RTL (exp));
temp = gen_rtx (MEM, mode, memory_address (mode, op1));
MEM_IN_STRUCT_P (temp) = 1;
MEM_VOLATILE_P (temp) = TREE_THIS_VOLATILE (exp);
return temp;
}
else
#endif
return DECL_RTL (exp);
case INTEGER_CST:
return immed_double_const (TREE_INT_CST_LOW (exp),
TREE_INT_CST_HIGH (exp),
mode);
case CONST_DECL:
return expand_expr (DECL_INITIAL (exp), target, VOIDmode,
EXPAND_MEMORY_USE_BAD);
case REAL_CST:
return immed_real_const (exp);
case VECTOR_CST:
return immed_vector_const (exp);
case COMPLEX_CST:
case STRING_CST:
if (! TREE_CST_RTL (exp))
output_constant_def (exp);
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 change_address (TREE_CST_RTL (exp), VOIDmode,
copy_rtx (XEXP (TREE_CST_RTL (exp), 0)));
return TREE_CST_RTL (exp);
case EXPR_WITH_FILE_LOCATION:
{
rtx to_return;
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 change_address (temp, mode,
fix_lexical_addr (XEXP (temp, 0), exp));
}
if (SAVE_EXPR_RTL (exp) == 0)
{
if (mode == VOIDmode)
temp = const0_rtx;
else
temp = assign_temp (type, 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_rtx_SUBREG (mode, SAVE_EXPR_RTL (exp), 0);
SUBREG_PROMOTED_VAR_P (temp) = 1;
SUBREG_PROMOTED_UNSIGNED_P (temp) = unsignedp;
}
if (temp == const0_rtx)
expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode,
EXPAND_MEMORY_USE_BAD);
else
store_expr (TREE_OPERAND (exp, 0), temp, 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_rtx_SUBREG (mode, SAVE_EXPR_RTL (exp), 0);
SUBREG_PROMOTED_VAR_P (temp) = 1;
SUBREG_PROMOTED_UNSIGNED_P (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) = unsave_expr_now (TREE_OPERAND (exp, 0));
return temp;
}
case PLACEHOLDER_EXPR:
{
tree placeholder_expr;
for (placeholder_expr = placeholder_list;
placeholder_expr != 0;
placeholder_expr = TREE_CHAIN (placeholder_expr))
{
tree need_type = TYPE_MAIN_VARIANT (type);
tree object = 0;
tree old_list = placeholder_list;
tree elt;
for (elt = TREE_PURPOSE (placeholder_expr);
elt != 0 && object == 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)
object = elt;
for (elt = TREE_PURPOSE (placeholder_expr);
elt != 0 && object == 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))
object = build1 (INDIRECT_REF, need_type, elt);
if (object != 0)
{
placeholder_list = TREE_CHAIN (placeholder_expr);
temp = expand_expr (object, original_target, tmode,
ro_modifier);
placeholder_list = old_list;
return temp;
}
}
}
abort ();
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, ro_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_PTR,
invert_truthvalue (TREE_OPERAND (exp, 0)));
return const0_rtx;
case LABELED_BLOCK_EXPR:
if (LABELED_BLOCK_BODY (exp))
expand_expr_stmt (LABELED_BLOCK_BODY (exp));
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);
expand_expr_stmt (TREE_OPERAND (exp, 0));
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 (0);
if (TREE_OPERAND (exp, 2) != 0
&& ! TREE_USED (TREE_OPERAND (exp, 2)))
insert_block (TREE_OPERAND (exp, 2));
while (vars)
{
if (DECL_RTL (vars) == 0)
{
vars_need_expansion = 1;
expand_decl (vars);
}
expand_decl_init (vars);
vars = TREE_CHAIN (vars);
}
temp = expand_expr (TREE_OPERAND (exp, 1), target, tmode, ro_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_insns (RTL_EXPR_SEQUENCE (exp));
RTL_EXPR_SEQUENCE (exp) = const0_rtx;
}
#ifndef NEXT_SEMANTICS
preserve_rtl_expr_result (RTL_EXPR_RTL (exp));
#endif
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,
EXPAND_MEMORY_USE_BAD);
return const0_rtx;
}
else if ((TREE_STATIC (exp)
&& ((mode == BLKmode
&& ! (target != 0 && safe_from_p (target, exp, 1)))
|| TREE_ADDRESSABLE (exp)
|| (TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST
&& (!MOVE_BY_PIECES_P
(TREE_INT_CST_LOW (TYPE_SIZE (type))/BITS_PER_UNIT,
TYPE_ALIGN (type) / BITS_PER_UNIT))
&& ! mostly_zeros_p (exp))))
|| (modifier == EXPAND_INITIALIZER && TREE_CONSTANT (exp)))
{
rtx constructor = output_constant_def (exp);
if (modifier != EXPAND_CONST_ADDRESS
&& modifier != EXPAND_INITIALIZER
&& modifier != EXPAND_SUM
&& (! memory_address_p (GET_MODE (constructor),
XEXP (constructor, 0))
|| (flag_force_addr
&& GET_CODE (XEXP (constructor, 0)) != REG)))
constructor = change_address (constructor, VOIDmode,
XEXP (constructor, 0));
return constructor;
}
else
{
if (target == 0 || ! safe_from_p (target, exp, 1)
|| GET_CODE (target) == PARALLEL)
{
if (mode != BLKmode && ! TREE_ADDRESSABLE (exp))
target = gen_reg_rtx (tmode != VOIDmode ? tmode : mode);
else
target = assign_temp (type, 0, 1, 1);
}
if (TREE_READONLY (exp))
{
if (GET_CODE (target) == MEM)
target = copy_rtx (target);
RTX_UNCHANGING_P (target) = 1;
}
store_constructor (exp, target, 0);
return target;
}
case INDIRECT_REF:
{
tree exp1 = TREE_OPERAND (exp, 0);
tree exp2;
tree index;
tree string = string_constant (exp1, &index);
int i;
if (string
&& TREE_CODE (string) == STRING_CST
&& TREE_CODE (index) == INTEGER_CST
&& !TREE_INT_CST_HIGH (index)
&& (i = TREE_INT_CST_LOW (index)) < TREE_STRING_LENGTH (string)
&& GET_MODE_CLASS (mode) == MODE_INT
&& GET_MODE_SIZE (mode) == 1
&& modifier != EXPAND_MEMORY_USE_WO)
return GEN_INT (TREE_STRING_POINTER (string)[i]);
op0 = expand_expr (exp1, NULL_RTX, VOIDmode, EXPAND_SUM);
op0 = memory_address (mode, op0);
if (current_function_check_memory_usage && !AGGREGATE_TYPE_P (TREE_TYPE (exp)))
{
enum memory_use_mode memory_usage;
memory_usage = get_memory_usage_from_modifier (modifier);
if (memory_usage != MEMORY_USE_DONT)
{
in_check_memory_usage = 1;
emit_library_call (chkr_check_addr_libfunc, 1, VOIDmode, 3,
op0, Pmode,
GEN_INT (int_size_in_bytes (type)),
TYPE_MODE (sizetype),
GEN_INT (memory_usage),
TYPE_MODE (integer_type_node));
in_check_memory_usage = 0;
}
}
temp = gen_rtx_MEM (mode, op0);
if (TREE_CODE (exp1) == PLUS_EXPR
|| (TREE_CODE (exp1) == SAVE_EXPR
&& TREE_CODE (TREE_OPERAND (exp1, 0)) == PLUS_EXPR)
|| AGGREGATE_TYPE_P (TREE_TYPE (exp))
|| (TREE_CODE (exp1) == ADDR_EXPR
&& (exp2 = TREE_OPERAND (exp1, 0))
&& AGGREGATE_TYPE_P (TREE_TYPE (exp2))))
MEM_SET_IN_STRUCT_P (temp, 1);
MEM_VOLATILE_P (temp) = TREE_THIS_VOLATILE (exp) | flag_volatile;
MEM_ALIAS_SET (temp) = get_alias_set (exp);
RTX_UNCHANGING_P (temp) = TREE_READONLY (exp) & TREE_STATIC (exp);
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 = TREE_OPERAND (exp, 1);
tree index_type = TREE_TYPE (index);
HOST_WIDE_INT i;
if (! integer_zerop (low_bound))
index = fold (build (MINUS_EXPR, index_type, index,
convert (sizetype, low_bound)));
if (TREE_CODE (array) == STRING_CST
&& TREE_CODE (index) == INTEGER_CST
&& !TREE_INT_CST_HIGH (index)
&& (i = TREE_INT_CST_LOW (index)) < TREE_STRING_LENGTH (array)
&& GET_MODE_CLASS (mode) == MODE_INT
&& GET_MODE_SIZE (mode) == 1)
return GEN_INT (TREE_STRING_POINTER (array)[i]);
if (TREE_CODE (array) == CONSTRUCTOR && ! TREE_SIDE_EFFECTS (array))
{
if (TREE_CODE (index) == INTEGER_CST
&& TREE_INT_CST_HIGH (index) == 0)
{
tree elem = CONSTRUCTOR_ELTS (TREE_OPERAND (exp, 0));
i = TREE_INT_CST_LOW (index);
while (elem && i--)
elem = TREE_CHAIN (elem);
if (elem)
return expand_expr (fold (TREE_VALUE (elem)), target,
tmode, ro_modifier);
}
}
else if (optimize >= 1
&& 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);
i = TREE_INT_CST_LOW (index);
if (TREE_CODE (init) == CONSTRUCTOR)
{
tree elem = CONSTRUCTOR_ELTS (init);
while (elem
&& !tree_int_cst_equal (TREE_PURPOSE (elem), index))
elem = TREE_CHAIN (elem);
if (elem)
return expand_expr (fold (TREE_VALUE (elem)), target,
tmode, ro_modifier);
}
else if (TREE_CODE (init) == STRING_CST
&& TREE_INT_CST_HIGH (index) == 0
&& (TREE_INT_CST_LOW (index)
< TREE_STRING_LENGTH (init)))
return (GEN_INT
(TREE_STRING_POINTER
(init)[TREE_INT_CST_LOW (index)]));
}
}
}
case COMPONENT_REF:
#ifdef NEXT_SEMANTICS
if (TREE_CODE (TREE_OPERAND (exp, 0)) == INDIRECT_REF
&& TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 0))) == UNION_TYPE
&& TREE_CODE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)) == NOP_EXPR)
{
tree addr = TREE_OPERAND (TREE_OPERAND (TREE_OPERAND (exp, 0), 0), 0);
tree casted_type = build_pointer_type (TREE_TYPE (exp));
tree casted_addr = build1 (NOP_EXPR, casted_type, addr);
return expand_expr (build1 (INDIRECT_REF, TREE_TYPE (exp), casted_addr),
target, tmode, modifier);
}
#endif
case BIT_FIELD_REF:
if (code != ARRAY_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))))
{
op0 = expand_expr (TREE_VALUE (elt), target, tmode, modifier);
if (DECL_BIT_FIELD (TREE_PURPOSE (elt)))
{
int bitsize = DECL_FIELD_SIZE (TREE_PURPOSE (elt));
if (TREE_UNSIGNED (TREE_TYPE (TREE_PURPOSE (elt))))
{
op1 = GEN_INT (((HOST_WIDE_INT) 1 << bitsize) - 1);
op0 = expand_and (op0, op1, target);
}
else
{
enum machine_mode imode
= TYPE_MODE (TREE_TYPE (TREE_PURPOSE (elt)));
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;
int bitsize;
int bitpos;
tree offset;
int volatilep = 0;
int alignment;
tree tem = get_inner_reference (exp, &bitsize, &bitpos, &offset,
&mode1, &unsignedp, &volatilep,
&alignment);
if (tem == exp)
abort ();
op0 = expand_expr (tem,
(TREE_CODE (TREE_TYPE (tem)) == UNION_TYPE
&& (TREE_CODE (TYPE_SIZE (TREE_TYPE (tem)))
!= INTEGER_CST)
? target : NULL_RTX),
VOIDmode,
modifier == EXPAND_INITIALIZER
? modifier : EXPAND_NORMAL);
if (CONSTANT_P (op0))
{
enum machine_mode mode = TYPE_MODE (TREE_TYPE (tem));
if (mode != BLKmode && LEGITIMATE_CONSTANT_P (op0))
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, 0);
if (GET_CODE (op0) != MEM)
abort ();
if (GET_MODE (offset_rtx) != ptr_mode)
{
#ifdef POINTERS_EXTEND_UNSIGNED
offset_rtx = convert_memory_address (ptr_mode, offset_rtx);
#else
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
&& (bitpos % bitsize) == 0
&& (bitsize % GET_MODE_ALIGNMENT (mode1)) == 0
&& (alignment * BITS_PER_UNIT) == GET_MODE_ALIGNMENT (mode1))
{
rtx temp = change_address (op0, mode1,
plus_constant (XEXP (op0, 0),
(bitpos /
BITS_PER_UNIT)));
if (GET_CODE (XEXP (temp, 0)) == REG)
op0 = temp;
else
op0 = change_address (op0, mode1,
force_reg (GET_MODE (XEXP (temp, 0)),
XEXP (temp, 0)));
bitpos = 0;
}
op0 = change_address (op0, VOIDmode,
gen_rtx_PLUS (ptr_mode, XEXP (op0, 0),
force_reg (ptr_mode, offset_rtx)));
}
if (GET_CODE (op0) == MEM && volatilep && ! MEM_VOLATILE_P (op0))
{
op0 = copy_rtx (op0);
MEM_VOLATILE_P (op0) = 1;
}
if (current_function_check_memory_usage && GET_CODE (op0) == MEM)
{
enum memory_use_mode memory_usage;
memory_usage = get_memory_usage_from_modifier (modifier);
if (memory_usage != MEMORY_USE_DONT)
{
rtx to;
int size;
to = plus_constant (XEXP (op0, 0), (bitpos / BITS_PER_UNIT));
size = (bitpos % BITS_PER_UNIT) + bitsize + BITS_PER_UNIT - 1;
if (size > BITS_PER_UNIT)
emit_library_call (chkr_check_addr_libfunc, 1, VOIDmode, 3,
to, Pmode,
GEN_INT (size / BITS_PER_UNIT),
TYPE_MODE (sizetype),
GEN_INT (memory_usage),
TYPE_MODE (integer_type_node));
}
}
if (mode1 == VOIDmode
|| GET_CODE (op0) == REG || GET_CODE (op0) == SUBREG
|| (modifier != EXPAND_CONST_ADDRESS
&& modifier != EXPAND_INITIALIZER
&& ((mode1 != BLKmode && ! direct_load[(int) mode1]
&& GET_MODE_CLASS (mode) != MODE_COMPLEX_INT
&& GET_MODE_CLASS (mode) != MODE_COMPLEX_FLOAT)
|| (SLOW_UNALIGNED_ACCESS
&& ((TYPE_ALIGN (TREE_TYPE (tem)) < (unsigned int) GET_MODE_ALIGNMENT (mode))
|| (bitpos % GET_MODE_ALIGNMENT (mode) != 0))))))
{
enum machine_mode ext_mode = mode;
if (ext_mode == BLKmode)
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 = change_address (op0, VOIDmode,
plus_constant (XEXP (op0, 0),
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),
1);
return target;
}
op0 = validize_mem (op0);
if (GET_CODE (op0) == MEM && GET_CODE (XEXP (op0, 0)) == REG)
mark_reg_pointer (XEXP (op0, 0), alignment);
op0 = extract_bit_field (op0, bitsize, bitpos,
unsignedp, target, ext_mode, ext_mode,
alignment,
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 < 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_stack_temp (ext_mode,
bitsize / BITS_PER_UNIT, 0);
emit_move_insn (new, op0);
op0 = copy_rtx (new);
PUT_MODE (op0, BLKmode);
MEM_SET_IN_STRUCT_P (op0, 1);
}
return op0;
}
if (mode == BLKmode)
mode1 = BLKmode;
if (modifier == EXPAND_CONST_ADDRESS
|| modifier == EXPAND_SUM || modifier == EXPAND_INITIALIZER)
op0 = gen_rtx_MEM (mode1, plus_constant (XEXP (op0, 0),
(bitpos / BITS_PER_UNIT)));
else
op0 = change_address (op0, mode1,
plus_constant (XEXP (op0, 0),
(bitpos / BITS_PER_UNIT)));
if (GET_CODE (op0) == MEM)
MEM_ALIAS_SET (op0) = get_alias_set (exp);
if (GET_CODE (XEXP (op0, 0)) == REG)
mark_reg_pointer (XEXP (op0, 0), alignment);
MEM_SET_IN_STRUCT_P (op0, 1);
MEM_VOLATILE_P (op0) |= volatilep;
if (mode == mode1 || mode1 == BLKmode || mode1 == tmode
|| modifier == EXPAND_CONST_ADDRESS
|| modifier == EXPAND_INITIALIZER)
#ifdef NEXT_SEMANTICS
target =
#else
return
#endif
op0;
else
#ifdef NEXT_SEMANTICS
{
#endif
if (target == 0)
target = gen_reg_rtx (tmode != VOIDmode ? tmode : mode);
convert_move (target, op0, unsignedp);
#ifdef NEXT_SEMANTICS
}
if (modifier == EXPAND_NORMAL
&& ((TREE_CODE (exp) == VAR_DECL
|| TREE_CODE (exp) == FIELD_DECL)
&& DECL_RELATIVE (TREE_OPERAND (exp, 1))))
{
rtx op0 = memory_address (mode, XEXP (target, 0));
rtx op1 = gen_rtx (PLUS, mode, op0, target);
temp = gen_rtx (MEM, mode, memory_address (mode, op1));
MEM_IN_STRUCT_P (temp) = 1;
MEM_VOLATILE_P (temp) = MEM_VOLATILE_P (target);
return temp;
}
else
#endif
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;
preexpand_calls (exp);
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, 0, 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, 0, 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 (RTL_EXPR_RTL (exp) == 0)
{
RTL_EXPR_RTL (exp)
= expand_expr (TREE_OPERAND (exp, 0), target, tmode, ro_modifier);
expand_decl_cleanup (NULL_TREE, TREE_OPERAND (exp, 2));
TREE_OPERAND (exp, 2) = 0;
}
return RTL_EXPR_RTL (exp);
case CLEANUP_POINT_EXPR:
{
expand_start_bindings (0);
target_temp_slot_level = temp_slot_level;
op0 = expand_expr (TREE_OPERAND (exp, 0), target, tmode, ro_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)))
return expand_builtin (exp, target, subtarget, tmode, ignore);
if (CALL_EXPR_RTL (exp) != 0)
return CALL_EXPR_RTL (exp);
return expand_call (exp, target, ignore);
case NON_LVALUE_EXPR:
case NOP_EXPR:
case CONVERT_EXPR:
case REFERENCE_EXPR:
if (TREE_CODE (type) == UNION_TYPE)
{
tree valtype = TREE_TYPE (TREE_OPERAND (exp, 0));
if (target == 0)
{
if (mode != BLKmode)
target = gen_reg_rtx (tmode != VOIDmode ? tmode : mode);
else
target = assign_temp (type, 0, 1, 1);
}
if (GET_CODE (target) == MEM)
store_expr (TREE_OPERAND (exp, 0),
change_address (target, TYPE_MODE (valtype), 0), 0);
else if (GET_CODE (target) == REG)
store_field (target, GET_MODE_BITSIZE (TYPE_MODE (valtype)), 0,
TYPE_MODE (valtype), TREE_OPERAND (exp, 0),
VOIDmode, 0, 1,
int_size_in_bytes (TREE_TYPE (TREE_OPERAND (exp, 0))),
0);
else
abort ();
return target;
}
if (mode == TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))))
{
op0 = expand_expr (TREE_OPERAND (exp, 0), target, VOIDmode,
ro_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, 0);
if (GET_MODE (op0) == mode)
return op0;
if (CONSTANT_P (op0))
return
convert_modes (mode, TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))),
op0, TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))));
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 PLUS_EXPR:
plus_expr:
this_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)
{
if (TREE_CODE (TREE_OPERAND (exp, 0)) == INTEGER_CST
&& GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
&& TREE_CONSTANT (TREE_OPERAND (exp, 1)))
{
op1 = expand_expr (TREE_OPERAND (exp, 1), subtarget, VOIDmode,
EXPAND_SUM);
op1 = plus_constant (op1, TREE_INT_CST_LOW (TREE_OPERAND (exp, 0)));
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)))
{
op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode,
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;
}
op0 = plus_constant (op0, TREE_INT_CST_LOW (TREE_OPERAND (exp, 1)));
if (modifier != EXPAND_SUM && modifier != EXPAND_INITIALIZER)
op0 = force_operand (op0, target);
return op0;
}
}
if ((modifier != EXPAND_SUM && modifier != EXPAND_INITIALIZER)
|| mode != ptr_mode)
goto binop;
preexpand_calls (exp);
if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1), 1))
subtarget = 0;
op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, ro_modifier);
op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, ro_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, ro_modifier);
rtx op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX,
VOIDmode, ro_modifier);
if (GET_CODE (op1) == CONST_INT)
return plus_constant (op0, - INTVAL (op1));
else
return gen_rtx_MINUS (mode, op0, op1);
}
if (TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST)
{
tree negated = fold (build1 (NEGATE_EXPR, type,
TREE_OPERAND (exp, 1)));
if (TREE_UNSIGNED (type) || TREE_OVERFLOW (negated))
{
tree newtype = signed_type (type);
tree newop0 = convert (newtype, TREE_OPERAND (exp, 0));
tree newop1 = convert (newtype, TREE_OPERAND (exp, 1));
tree newneg = fold (build1 (NEGATE_EXPR, newtype, newop1));
if (! TREE_OVERFLOW (newneg))
return expand_expr (convert (type,
build (PLUS_EXPR, newtype,
newop0, newneg)),
target, tmode, ro_modifier);
}
else
{
exp = build (PLUS_EXPR, type, TREE_OPERAND (exp, 0), negated);
goto plus_expr;
}
}
this_optab = sub_optab;
goto binop;
case MULT_EXPR:
preexpand_calls (exp);
if (TREE_CODE (TREE_OPERAND (exp, 0)) == INTEGER_CST)
{
register 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
&& TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST
&& GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
{
op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode,
EXPAND_SUM);
if (GET_CODE (op0) == PLUS
&& GET_CODE (XEXP (op0, 1)) == CONST_INT)
return gen_rtx_PLUS (mode,
gen_rtx_MULT (mode, XEXP (op0, 0),
GEN_INT (TREE_INT_CST_LOW (TREE_OPERAND (exp, 1)))),
GEN_INT (TREE_INT_CST_LOW (TREE_OPERAND (exp, 1))
* INTVAL (XEXP (op0, 1))));
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 (TREE_INT_CST_LOW (TREE_OPERAND (exp, 1))));
}
if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1), 1))
subtarget = 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 = 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);
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:
preexpand_calls (exp);
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);
return expand_divmod (0, code, mode, op0, op1, target, unsignedp);
case RDIV_EXPR:
this_optab = flodiv_optab;
goto binop;
case TRUNC_MOD_EXPR:
case FLOOR_MOD_EXPR:
case CEIL_MOD_EXPR:
case ROUND_MOD_EXPR:
preexpand_calls (exp);
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);
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)
target = gen_reg_rtx (mode);
expand_fix (target, op0, unsignedp);
return target;
case FLOAT_EXPR:
op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, VOIDmode, 0);
if (target == 0)
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 (target, op0,
TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))));
return target;
case NEGATE_EXPR:
op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
temp = expand_unop (mode, 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 (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,
safe_from_p (target, TREE_OPERAND (exp, 0), 1));
case MAX_EXPR:
case MIN_EXPR:
target = original_target;
if (target == 0 || ! 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 (mode))
{
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);
emit_move_insn (target, op1);
}
else
{
if (code == MAX_EXPR)
temp = (TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 1)))
? compare_from_rtx (target, op1, GEU, 1, mode, NULL_RTX, 0)
: compare_from_rtx (target, op1, GE, 0, mode, NULL_RTX, 0));
else
temp = (TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 1)))
? compare_from_rtx (target, op1, LEU, 1, mode, NULL_RTX, 0)
: compare_from_rtx (target, op1, LE, 0, mode, NULL_RTX, 0));
if (temp == const0_rtx)
emit_move_insn (target, op1);
else if (temp != const_true_rtx)
{
if (bcc_gen_fctn[(int) GET_CODE (temp)] != 0)
emit_jump_insn ((*bcc_gen_fctn[(int) GET_CODE (temp)]) (op0));
else
abort ();
emit_move_insn (target, op1);
}
}
emit_label (op0);
return target;
case BIT_NOT_EXPR:
op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 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);
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:
preexpand_calls (exp);
if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1), 1))
subtarget = 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:
preexpand_calls (exp);
temp = do_store_flag (exp, target, 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 (temp != original_target)
temp = copy_to_reg (temp);
op1 = gen_label_rtx ();
emit_cmp_and_jump_insns (temp, const0_rtx, EQ, NULL_RTX,
GET_MODE (temp), unsignedp, 0, op1);
emit_move_insn (temp, const1_rtx);
emit_label (op1);
return temp;
}
case TRUTH_ANDIF_EXPR:
case TRUTH_ORIF_EXPR:
if (! ignore
&& (target == 0 || ! 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:
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, 0);
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 true = TREE_OPERAND (TREE_OPERAND (exp, 1), 0);
tree false = TREE_OPERAND (TREE_OPERAND (exp, 2), 0);
if ((TREE_CODE_CLASS (TREE_CODE (true)) == '2'
&& operand_equal_p (false, TREE_OPERAND (true, 0), 0))
|| (TREE_CODE_CLASS (TREE_CODE (false)) == '2'
&& operand_equal_p (true, TREE_OPERAND (false, 0), 0))
|| (TREE_CODE_CLASS (TREE_CODE (true)) == '1'
&& operand_equal_p (false, TREE_OPERAND (true, 0), 0))
|| (TREE_CODE_CLASS (TREE_CODE (false)) == '1'
&& operand_equal_p (true, TREE_OPERAND (false, 0), 0)))
return expand_expr (build1 (NOP_EXPR, type,
build (COND_EXPR, TREE_TYPE (true),
TREE_OPERAND (exp, 0),
true, false)),
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,
ro_modifier);
return const0_rtx;
}
op0 = expand_expr (TREE_OPERAND (exp, 0), target, mode, ro_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 (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
&& MEM_VOLATILE_P (original_target)))
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;
optab boptab = (TREE_CODE (binary_op) == PLUS_EXPR ? add_optab
: TREE_CODE (binary_op) == MINUS_EXPR ? sub_optab
: TREE_CODE (binary_op) == BIT_IOR_EXPR ? ior_optab
: xor_optab);
if (singleton == TREE_OPERAND (exp, 1))
TREE_OPERAND (exp, 0)
= invert_truthvalue (TREE_OPERAND (exp, 0));
result = do_store_flag (TREE_OPERAND (exp, 0),
(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);
}
else if (singleton == TREE_OPERAND (exp, 1))
TREE_OPERAND (exp, 0)
= invert_truthvalue (TREE_OPERAND (exp, 0));
}
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, 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);
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, 0);
else
store_expr (build1 (TREE_CODE (unary_op), type,
make_tree (type, temp)),
temp, 0);
op1 = op0;
}
else if (temp
&& 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, 0);
jumpif (TREE_OPERAND (exp, 0), op0);
start_cleanup_deferral ();
store_expr (TREE_OPERAND (exp, 2), temp, 0);
op1 = op0;
}
else if (temp
&& 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, 0);
jumpifnot (TREE_OPERAND (exp, 0), op0);
start_cleanup_deferral ();
store_expr (TREE_OPERAND (exp, 1), temp, 0);
op1 = op0;
}
else
{
op1 = gen_label_rtx ();
jumpifnot (TREE_OPERAND (exp, 0), op0);
start_cleanup_deferral ();
if (temp != 0)
store_expr (TREE_OPERAND (exp, 1), temp, 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)
store_expr (TREE_OPERAND (exp, 2), temp, 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;
if (target == 0)
{
if (DECL_RTL (slot) != 0)
{
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);
DECL_RTL (slot) = target;
if (TREE_ADDRESSABLE (slot))
{
TREE_ADDRESSABLE (slot) = 0;
mark_addressable (slot);
}
if (TREE_OPERAND (exp, 2) == 0)
TREE_OPERAND (exp, 2) = maybe_build_cleanup (slot);
cleanups = TREE_OPERAND (exp, 2);
}
}
else
{
if (DECL_RTL (slot) != 0)
{
target = DECL_RTL (slot);
if (TREE_OPERAND (exp, 1) == NULL_TREE)
return target;
}
else
{
DECL_RTL (slot) = target;
if (TREE_ADDRESSABLE (slot))
{
TREE_ADDRESSABLE (slot) = 0;
mark_addressable (slot);
}
}
}
exp1 = TREE_OPERAND (exp, 3) = TREE_OPERAND (exp, 1);
TREE_OPERAND (exp, 1) = NULL_TREE;
TREE_USED (slot) = 1;
store_expr (exp1, target, 0);
expand_decl_cleanup (NULL_TREE, cleanups);
return target;
}
case INIT_EXPR:
{
tree lhs = TREE_OPERAND (exp, 0);
tree rhs = TREE_OPERAND (exp, 1);
tree noncopied_parts = 0;
tree lhs_type = TREE_TYPE (lhs);
temp = expand_assignment (lhs, rhs, ! ignore, original_target != 0);
if (TYPE_NONCOPIED_PARTS (lhs_type) != 0 && !fixed_type_p (rhs))
noncopied_parts = init_noncopied_parts (stabilize_reference (lhs),
TYPE_NONCOPIED_PARTS (lhs_type));
while (noncopied_parts != 0)
{
expand_assignment (TREE_VALUE (noncopied_parts),
TREE_PURPOSE (noncopied_parts), 0, 0);
noncopied_parts = TREE_CHAIN (noncopied_parts);
}
return temp;
}
case MODIFY_EXPR:
{
tree lhs = TREE_OPERAND (exp, 0);
tree rhs = TREE_OPERAND (exp, 1);
tree noncopied_parts = 0;
tree lhs_type = TREE_TYPE (lhs);
temp = 0;
if (TREE_CODE (lhs) != VAR_DECL
&& TREE_CODE (lhs) != RESULT_DECL
&& TREE_CODE (lhs) != PARM_DECL
&& ! (TREE_CODE (lhs) == INDIRECT_REF
&& TYPE_READONLY (TREE_TYPE (TREE_OPERAND (lhs, 0)))))
preexpand_calls (exp);
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
&& TREE_INT_CST_LOW (DECL_SIZE (TREE_OPERAND (lhs, 1))) == 1
&& TREE_INT_CST_LOW (DECL_SIZE (TREE_OPERAND (TREE_OPERAND (rhs, 1), 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;
}
if (TYPE_NONCOPIED_PARTS (lhs_type) != 0
&& ! (fixed_type_p (lhs) && fixed_type_p (rhs)))
noncopied_parts = save_noncopied_parts (stabilize_reference (lhs),
TYPE_NONCOPIED_PARTS (lhs_type));
temp = expand_assignment (lhs, rhs, ! ignore, original_target != 0);
while (noncopied_parts != 0)
{
expand_assignment (TREE_PURPOSE (noncopied_parts),
TREE_VALUE (noncopied_parts), 0, 0);
noncopied_parts = TREE_CHAIN (noncopied_parts);
}
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:
temp = 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
{
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, 0);
if (CONSTANT_P (op0))
op0 = force_const_mem (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))),
op0);
else if (GET_CODE (op0) == MEM)
{
mark_temp_addr_taken (op0);
temp = XEXP (op0, 0);
}
else if (GET_CODE (op0) == REG || GET_CODE (op0) == SUBREG
|| GET_CODE (op0) == CONCAT || GET_CODE (op0) == ADDRESSOF)
{
tree inner_type = TREE_TYPE (TREE_OPERAND (exp, 0));
rtx memloc = assign_temp (inner_type, 1, 1, 1);
mark_temp_addr_taken (memloc);
emit_move_insn (memloc, op0);
op0 = memloc;
}
if (GET_CODE (op0) != MEM)
abort ();
if (modifier == EXPAND_SUM || modifier == EXPAND_INITIALIZER)
{
temp = XEXP (op0, 0);
#ifdef POINTERS_EXTEND_UNSIGNED
if (GET_MODE (temp) == Pmode && GET_MODE (temp) != mode
&& mode == ptr_mode)
temp = convert_memory_address (ptr_mode, temp);
#endif
return temp;
}
op0 = force_operand (XEXP (op0, 0), target);
}
if (flag_force_addr && GET_CODE (op0) != REG)
op0 = force_reg (Pmode, op0);
if (GET_CODE (op0) == REG
&& ! REG_USERVAR_P (op0))
mark_reg_pointer (op0, TYPE_ALIGN (TREE_TYPE (type)) / BITS_PER_UNIT);
if (temp != 0)
update_temp_slot_address (temp, op0);
#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_insns (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, 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_insns (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 (handler);
return op0;
}
case TRY_FINALLY_EXPR:
{
tree try_block = TREE_OPERAND (exp, 0);
tree finally_block = TREE_OPERAND (exp, 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 (0);
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);
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 POPDCC_EXPR:
{
rtx dcc = get_dynamic_cleanup_chain ();
emit_move_insn (dcc, validize_mem (gen_rtx_MEM (Pmode, dcc)));
return const0_rtx;
}
case POPDHC_EXPR:
{
rtx dhc = get_dynamic_handler_chain ();
emit_move_insn (dhc, validize_mem (gen_rtx_MEM (Pmode, dhc)));
return const0_rtx;
}
default:
return (*lang_expand_expr) (exp, original_target, tmode, modifier);
}
binop:
preexpand_calls (exp);
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:
temp = expand_binop (mode, this_optab, op0, op1, target,
unsignedp, OPTAB_LIB_WIDEN);
if (temp == 0)
abort ();
return temp;
}
static int
get_pointer_alignment (exp, max_align)
tree exp;
unsigned max_align;
{
unsigned align, inner;
if (TREE_CODE (TREE_TYPE (exp)) != POINTER_TYPE)
return 0;
align = TYPE_ALIGN (TREE_TYPE (TREE_TYPE (exp)));
align = MIN (align, max_align);
while (1)
{
switch (TREE_CODE (exp))
{
case NOP_EXPR:
case CONVERT_EXPR:
case NON_LVALUE_EXPR:
exp = TREE_OPERAND (exp, 0);
if (TREE_CODE (TREE_TYPE (exp)) != POINTER_TYPE)
return align;
inner = TYPE_ALIGN (TREE_TYPE (TREE_TYPE (exp)));
align = MIN (inner, max_align);
break;
case PLUS_EXPR:
if (TREE_CODE (TREE_OPERAND (exp, 1)) != INTEGER_CST)
return align;
while (((TREE_INT_CST_LOW (TREE_OPERAND (exp, 1)) * BITS_PER_UNIT)
& (max_align - 1))
!= 0)
max_align >>= 1;
exp = TREE_OPERAND (exp, 0);
break;
case ADDR_EXPR:
exp = TREE_OPERAND (exp, 0);
if (TREE_CODE (exp) == FUNCTION_DECL)
align = FUNCTION_BOUNDARY;
else if (TREE_CODE_CLASS (TREE_CODE (exp)) == 'd')
align = DECL_ALIGN (exp);
#ifdef CONSTANT_ALIGNMENT
else if (TREE_CODE_CLASS (TREE_CODE (exp)) == 'c')
align = CONSTANT_ALIGNMENT (exp, align);
#endif
return MIN (align, max_align);
default:
return align;
}
}
}
static 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 = integer_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 = arg1;
return TREE_OPERAND (arg0, 0);
}
else if (TREE_CODE (arg1) == ADDR_EXPR
&& TREE_CODE (TREE_OPERAND (arg1, 0)) == STRING_CST)
{
*ptr_offset = arg0;
return TREE_OPERAND (arg1, 0);
}
}
return 0;
}
static tree
c_strlen (src)
tree src;
{
tree offset_node;
int offset, max;
char *ptr;
src = string_constant (src, &offset_node);
if (src == 0)
return 0;
max = TREE_STRING_LENGTH (src);
ptr = TREE_STRING_POINTER (src);
if (offset_node && TREE_CODE (offset_node) != INTEGER_CST)
{
int i;
for (i = 0; i < max; i++)
if (ptr[i] == 0)
return 0;
return size_binop (MINUS_EXPR, size_int (max), offset_node);
}
if (offset_node == 0)
offset = 0;
else
{
if (TREE_INT_CST_HIGH (offset_node) != 0)
return 0;
offset = TREE_INT_CST_LOW (offset_node);
}
if (offset < 0 || offset > max)
{
warning ("offset outside bounds of constant string");
return 0;
}
return size_int (strlen (ptr + offset));
}
rtx
expand_builtin_return_addr (fndecl_code, count, tem)
enum built_in_function fndecl_code;
int count;
rtx tem;
{
int i;
#ifdef SETUP_FRAME_ADDRESSES
if (count > 0)
SETUP_FRAME_ADDRESSES ();
#endif
#ifdef RETURN_ADDR_IN_PREVIOUS_FRAME
if (fndecl_code == BUILT_IN_RETURN_ADDRESS)
count--;
#endif
for (i = 0; i < count; i++)
{
#ifdef DYNAMIC_CHAIN_ADDRESS
tem = DYNAMIC_CHAIN_ADDRESS (tem);
#endif
tem = memory_address (Pmode, tem);
tem = copy_to_reg (gen_rtx_MEM (Pmode, tem));
}
if (fndecl_code == BUILT_IN_FRAME_ADDRESS)
return tem;
#ifdef RETURN_ADDR_RTX
tem = RETURN_ADDR_RTX (count, tem);
#else
tem = memory_address (Pmode,
plus_constant (tem, GET_MODE_SIZE (Pmode)));
tem = gen_rtx_MEM (Pmode, tem);
#endif
return tem;
}
rtx
expand_builtin_setjmp (buf_addr, target, first_label, next_label)
rtx buf_addr;
rtx target;
rtx first_label, next_label;
{
rtx lab1 = gen_label_rtx ();
enum machine_mode sa_mode = STACK_SAVEAREA_MODE (SAVE_NONLOCAL);
enum machine_mode value_mode;
rtx stack_save;
value_mode = TYPE_MODE (integer_type_node);
#ifdef POINTERS_EXTEND_UNSIGNED
buf_addr = convert_memory_address (Pmode, buf_addr);
#endif
buf_addr = force_reg (Pmode, buf_addr);
if (target == 0 || GET_CODE (target) != REG
|| REGNO (target) < FIRST_PSEUDO_REGISTER)
target = gen_reg_rtx (value_mode);
emit_queue ();
#ifndef BUILTIN_SETJMP_FRAME_VALUE
#define BUILTIN_SETJMP_FRAME_VALUE virtual_stack_vars_rtx
#endif
emit_move_insn (gen_rtx_MEM (Pmode, buf_addr),
BUILTIN_SETJMP_FRAME_VALUE);
emit_move_insn (validize_mem
(gen_rtx_MEM (Pmode,
plus_constant (buf_addr,
GET_MODE_SIZE (Pmode)))),
force_reg (Pmode, gen_rtx_LABEL_REF (Pmode, lab1)));
stack_save = gen_rtx_MEM (sa_mode,
plus_constant (buf_addr,
2 * GET_MODE_SIZE (Pmode)));
emit_stack_save (SAVE_NONLOCAL, &stack_save, NULL_RTX);
#ifdef HAVE_builtin_setjmp_setup
if (HAVE_builtin_setjmp_setup)
emit_insn (gen_builtin_setjmp_setup (buf_addr));
#endif
emit_move_insn (target, const0_rtx);
emit_jump_insn (gen_jump (first_label));
emit_barrier ();
emit_label (lab1);
current_function_has_nonlocal_label = 1;
nonlocal_goto_handler_labels =
gen_rtx_EXPR_LIST (VOIDmode, lab1, nonlocal_goto_handler_labels);
emit_insn (gen_rtx_USE (VOIDmode, hard_frame_pointer_rtx));
emit_insn (gen_rtx_CLOBBER (VOIDmode, static_chain_rtx));
#ifdef HAVE_nonlocal_goto
if (! HAVE_nonlocal_goto)
#endif
emit_move_insn (virtual_stack_vars_rtx, hard_frame_pointer_rtx);
#if ARG_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
if (fixed_regs[ARG_POINTER_REGNUM])
{
#ifdef ELIMINABLE_REGS
size_t i;
static struct elims {int from, to;} elim_regs[] = ELIMINABLE_REGS;
for (i = 0; i < sizeof elim_regs / sizeof elim_regs[0]; i++)
if (elim_regs[i].from == ARG_POINTER_REGNUM
&& elim_regs[i].to == HARD_FRAME_POINTER_REGNUM)
break;
if (i == sizeof elim_regs / sizeof elim_regs [0])
#endif
{
if (arg_pointer_save_area == 0)
arg_pointer_save_area
= assign_stack_local (Pmode, GET_MODE_SIZE (Pmode), 0);
emit_move_insn (virtual_incoming_args_rtx,
copy_to_reg (arg_pointer_save_area));
}
}
#endif
#ifdef HAVE_builtin_setjmp_receiver
if (HAVE_builtin_setjmp_receiver)
emit_insn (gen_builtin_setjmp_receiver (lab1));
else
#endif
#ifdef HAVE_nonlocal_goto_receiver
if (HAVE_nonlocal_goto_receiver)
emit_insn (gen_nonlocal_goto_receiver ());
else
#endif
{
;
}
emit_move_insn (target, const1_rtx);
emit_jump_insn (gen_jump (next_label));
emit_barrier ();
return target;
}
void
expand_builtin_longjmp (buf_addr, value)
rtx buf_addr, value;
{
rtx fp, lab, stack;
enum machine_mode sa_mode = STACK_SAVEAREA_MODE (SAVE_NONLOCAL);
#ifdef POINTERS_EXTEND_UNSIGNED
buf_addr = convert_memory_address (Pmode, buf_addr);
#endif
buf_addr = force_reg (Pmode, buf_addr);
if (value != const1_rtx)
abort ();
#ifdef HAVE_builtin_longjmp
if (HAVE_builtin_longjmp)
emit_insn (gen_builtin_longjmp (buf_addr));
else
#endif
{
fp = gen_rtx_MEM (Pmode, buf_addr);
lab = gen_rtx_MEM (Pmode, plus_constant (buf_addr,
GET_MODE_SIZE (Pmode)));
stack = gen_rtx_MEM (sa_mode, plus_constant (buf_addr,
2 * GET_MODE_SIZE (Pmode)));
#if HAVE_nonlocal_goto
if (HAVE_nonlocal_goto)
emit_insn (gen_nonlocal_goto (value, fp, stack, lab));
else
#endif
{
lab = copy_to_reg (lab);
emit_move_insn (hard_frame_pointer_rtx, fp);
emit_stack_restore (SAVE_NONLOCAL, stack, NULL_RTX);
emit_insn (gen_rtx_USE (VOIDmode, hard_frame_pointer_rtx));
emit_insn (gen_rtx_USE (VOIDmode, stack_pointer_rtx));
emit_indirect_jump (lab);
}
}
}
static rtx
get_memory_rtx (exp)
tree exp;
{
rtx mem;
int is_aggregate;
mem = gen_rtx_MEM (BLKmode,
memory_address (BLKmode,
expand_expr (exp, NULL_RTX,
ptr_mode, EXPAND_SUM)));
RTX_UNCHANGING_P (mem) = TREE_READONLY (exp);
is_aggregate = 0;
while (TREE_CODE (exp) == NOP_EXPR)
{
tree cast_type = TREE_TYPE (exp);
if (TREE_CODE (cast_type) == POINTER_TYPE
&& AGGREGATE_TYPE_P (TREE_TYPE (cast_type)))
{
is_aggregate = 1;
break;
}
exp = TREE_OPERAND (exp, 0);
}
if (is_aggregate == 0)
{
tree type;
if (TREE_CODE (exp) == ADDR_EXPR)
type = TREE_TYPE (TREE_OPERAND (exp, 0));
else
type = TREE_TYPE (TREE_TYPE (exp));
is_aggregate = AGGREGATE_TYPE_P (type);
}
MEM_SET_IN_STRUCT_P (mem, is_aggregate);
return mem;
}
#define CALLED_AS_BUILT_IN(NODE) \
(!strncmp (IDENTIFIER_POINTER (DECL_NAME (NODE)), "__builtin_", 10))
static rtx
expand_builtin (exp, target, subtarget, mode, ignore)
tree exp;
rtx target;
rtx subtarget;
enum machine_mode mode;
int ignore;
{
tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
tree arglist = TREE_OPERAND (exp, 1);
rtx op0;
rtx lab1, insns;
enum machine_mode value_mode = TYPE_MODE (TREE_TYPE (exp));
optab builtin_optab;
switch (DECL_FUNCTION_CODE (fndecl))
{
case BUILT_IN_ABS:
case BUILT_IN_LABS:
case BUILT_IN_FABS:
abort ();
case BUILT_IN_SIN:
case BUILT_IN_COS:
if (! flag_fast_math)
break;
case BUILT_IN_FSQRT:
if (! optimize)
break;
if (arglist == 0
|| TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != REAL_TYPE)
break;
if (TREE_CODE (TREE_VALUE (arglist)) != VAR_DECL
&& TREE_CODE (TREE_VALUE (arglist)) != PARM_DECL)
{
exp = copy_node (exp);
arglist = copy_node (arglist);
TREE_OPERAND (exp, 1) = arglist;
TREE_VALUE (arglist) = save_expr (TREE_VALUE (arglist));
}
op0 = expand_expr (TREE_VALUE (arglist), subtarget, VOIDmode, 0);
target = gen_reg_rtx (TYPE_MODE (TREE_TYPE (exp)));
emit_queue ();
start_sequence ();
switch (DECL_FUNCTION_CODE (fndecl))
{
case BUILT_IN_SIN:
builtin_optab = sin_optab; break;
case BUILT_IN_COS:
builtin_optab = cos_optab; break;
case BUILT_IN_FSQRT:
builtin_optab = sqrt_optab; break;
default:
abort ();
}
target = expand_unop (TYPE_MODE (TREE_TYPE (TREE_VALUE (arglist))),
builtin_optab, op0, target, 0);
if (target == 0)
{
end_sequence ();
break;
}
if (flag_errno_math && ! flag_fast_math)
{
if (TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT)
abort ();
lab1 = gen_label_rtx ();
emit_cmp_and_jump_insns (target, target, EQ, 0, GET_MODE (target),
0, 0, lab1);
#ifdef TARGET_EDOM
{
#ifdef GEN_ERRNO_RTX
rtx errno_rtx = GEN_ERRNO_RTX;
#else
rtx errno_rtx
= gen_rtx_MEM (word_mode, gen_rtx_SYMBOL_REF (Pmode, "errno"));
#endif
emit_move_insn (errno_rtx, GEN_INT (TARGET_EDOM));
}
#else
NO_DEFER_POP;
expand_call (exp, target, 0);
OK_DEFER_POP;
#endif
emit_label (lab1);
}
insns = get_insns ();
end_sequence ();
emit_insns (insns);
return target;
case BUILT_IN_FMOD:
break;
case BUILT_IN_APPLY_ARGS:
if (apply_args_value != 0)
return apply_args_value;
{
rtx temp;
rtx seq;
start_sequence ();
temp = expand_builtin_apply_args ();
seq = get_insns ();
end_sequence ();
apply_args_value = temp;
push_topmost_sequence ();
emit_insns_before (seq, NEXT_INSN (get_insns ()));
pop_topmost_sequence ();
return temp;
}
case BUILT_IN_APPLY:
if (arglist == 0
|| ! POINTER_TYPE_P (TREE_TYPE (TREE_VALUE (arglist)))
|| TREE_CHAIN (arglist) == 0
|| TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (arglist)))) != POINTER_TYPE
|| TREE_CHAIN (TREE_CHAIN (arglist)) == 0
|| TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))))) != INTEGER_TYPE)
return const0_rtx;
else
{
int i;
tree t;
rtx ops[3];
for (t = arglist, i = 0; t; t = TREE_CHAIN (t), i++)
ops[i] = expand_expr (TREE_VALUE (t), NULL_RTX, VOIDmode, 0);
return expand_builtin_apply (ops[0], ops[1], ops[2]);
}
case BUILT_IN_RETURN:
if (arglist
&& TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) == POINTER_TYPE)
expand_builtin_return (expand_expr (TREE_VALUE (arglist),
NULL_RTX, VOIDmode, 0));
return const0_rtx;
case BUILT_IN_SAVEREGS:
if (saveregs_value != 0)
return saveregs_value;
{
rtx temp;
rtx seq;
start_sequence ();
#ifdef EXPAND_BUILTIN_SAVEREGS
temp = EXPAND_BUILTIN_SAVEREGS (arglist);
#else
if (value_mode != VOIDmode)
{
rtx valreg = hard_libcall_value (value_mode);
rtx saved_valreg = gen_reg_rtx (value_mode);
emit_move_insn (saved_valreg, valreg);
temp = expand_call (exp, target, ignore);
emit_move_insn (valreg, saved_valreg);
}
else
temp = expand_call (exp, target, ignore);
#endif
seq = get_insns ();
end_sequence ();
saveregs_value = temp;
push_topmost_sequence ();
emit_insns_before (seq, NEXT_INSN (get_insns ()));
pop_topmost_sequence ();
return temp;
}
case BUILT_IN_ARGS_INFO:
{
int nwords = sizeof (CUMULATIVE_ARGS) / sizeof (int);
int *word_ptr = (int *) ¤t_function_args_info;
#if 0
int i;
tree type, elts, result;
#endif
if (sizeof (CUMULATIVE_ARGS) % sizeof (int) != 0)
fatal ("CUMULATIVE_ARGS type defined badly; see %s, line %d",
__FILE__, __LINE__);
if (arglist != 0)
{
tree arg = TREE_VALUE (arglist);
if (TREE_CODE (arg) != INTEGER_CST)
error ("argument of `__builtin_args_info' must be constant");
else
{
int wordnum = TREE_INT_CST_LOW (arg);
if (wordnum < 0 || wordnum >= nwords || TREE_INT_CST_HIGH (arg))
error ("argument of `__builtin_args_info' out of range");
else
return GEN_INT (word_ptr[wordnum]);
}
}
else
error ("missing argument in `__builtin_args_info'");
return const0_rtx;
#if 0
for (i = 0; i < nwords; i++)
elts = tree_cons (NULL_TREE, build_int_2 (word_ptr[i], 0));
type = build_array_type (integer_type_node,
build_index_type (build_int_2 (nwords, 0)));
result = build (CONSTRUCTOR, type, NULL_TREE, nreverse (elts));
TREE_CONSTANT (result) = 1;
TREE_STATIC (result) = 1;
result = build (INDIRECT_REF, build_pointer_type (type), result);
TREE_CONSTANT (result) = 1;
return expand_expr (result, NULL_RTX, VOIDmode, EXPAND_MEMORY_USE_BAD);
#endif
}
case BUILT_IN_NEXT_ARG:
{
tree fntype = TREE_TYPE (current_function_decl);
if ((TYPE_ARG_TYPES (fntype) == 0
|| (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
== void_type_node))
&& ! current_function_varargs)
{
error ("`va_start' used in function with fixed args");
return const0_rtx;
}
if (arglist)
{
tree last_parm = tree_last (DECL_ARGUMENTS (current_function_decl));
tree arg = TREE_VALUE (arglist);
while (TREE_CODE (arg) == NOP_EXPR
|| TREE_CODE (arg) == CONVERT_EXPR
|| TREE_CODE (arg) == NON_LVALUE_EXPR
|| TREE_CODE (arg) == INDIRECT_REF)
arg = TREE_OPERAND (arg, 0);
if (arg != last_parm)
warning ("second parameter of `va_start' not last named argument");
}
else if (! current_function_varargs)
warning ("`__builtin_next_arg' called without an argument");
}
return expand_binop (Pmode, add_optab,
current_function_internal_arg_pointer,
current_function_arg_offset_rtx,
NULL_RTX, 0, OPTAB_LIB_WIDEN);
case BUILT_IN_CLASSIFY_TYPE:
if (arglist != 0)
{
tree type = TREE_TYPE (TREE_VALUE (arglist));
enum tree_code code = TREE_CODE (type);
if (code == VOID_TYPE)
return GEN_INT (void_type_class);
if (code == INTEGER_TYPE)
return GEN_INT (integer_type_class);
if (code == CHAR_TYPE)
return GEN_INT (char_type_class);
if (code == ENUMERAL_TYPE)
return GEN_INT (enumeral_type_class);
if (code == BOOLEAN_TYPE)
return GEN_INT (boolean_type_class);
if (code == POINTER_TYPE)
return GEN_INT (pointer_type_class);
if (code == REFERENCE_TYPE)
return GEN_INT (reference_type_class);
if (code == OFFSET_TYPE)
return GEN_INT (offset_type_class);
if (code == REAL_TYPE)
return GEN_INT (real_type_class);
if (code == COMPLEX_TYPE)
return GEN_INT (complex_type_class);
if (code == VECTOR_TYPE)
return GEN_INT (vector_type_class);
if (code == FUNCTION_TYPE)
return GEN_INT (function_type_class);
if (code == METHOD_TYPE)
return GEN_INT (method_type_class);
if (code == RECORD_TYPE)
return GEN_INT (record_type_class);
if (code == UNION_TYPE || code == QUAL_UNION_TYPE)
return GEN_INT (union_type_class);
if (code == ARRAY_TYPE)
{
if (TYPE_STRING_FLAG (type))
return GEN_INT (string_type_class);
else
return GEN_INT (array_type_class);
}
if (code == SET_TYPE)
return GEN_INT (set_type_class);
if (code == FILE_TYPE)
return GEN_INT (file_type_class);
if (code == LANG_TYPE)
return GEN_INT (lang_type_class);
}
return GEN_INT (no_type_class);
case BUILT_IN_CONSTANT_P:
if (arglist == 0)
return const0_rtx;
else
{
tree arg = TREE_VALUE (arglist);
rtx tmp;
STRIP_NOPS (arg);
if (TREE_CODE_CLASS (TREE_CODE (arg)) == 'c'
|| (TREE_CODE (arg) == CONSTRUCTOR
&& TREE_CONSTANT (arg))
|| (TREE_CODE (arg) == ADDR_EXPR
&& TREE_CODE (TREE_OPERAND (arg, 0)) == STRING_CST))
return const1_rtx;
if (TREE_SIDE_EFFECTS (arg) || cse_not_expected
|| AGGREGATE_TYPE_P (TREE_TYPE (arg))
|| POINTER_TYPE_P (TREE_TYPE (arg)))
return const0_rtx;
tmp = expand_expr (arg, NULL_RTX, VOIDmode, 0);
tmp = gen_rtx_CONSTANT_P_RTX (value_mode, tmp);
return tmp;
}
case BUILT_IN_FRAME_ADDRESS:
case BUILT_IN_RETURN_ADDRESS:
if (arglist == 0)
return const0_rtx;
else if (TREE_CODE (TREE_VALUE (arglist)) != INTEGER_CST
|| tree_int_cst_sgn (TREE_VALUE (arglist)) < 0)
{
if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_FRAME_ADDRESS)
error ("invalid arg to `__builtin_frame_address'");
else
error ("invalid arg to `__builtin_return_address'");
return const0_rtx;
}
else
{
rtx tem = expand_builtin_return_addr (DECL_FUNCTION_CODE (fndecl),
TREE_INT_CST_LOW (TREE_VALUE (arglist)),
hard_frame_pointer_rtx);
if (tem == NULL)
{
if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_FRAME_ADDRESS)
warning ("unsupported arg to `__builtin_frame_address'");
else
warning ("unsupported arg to `__builtin_return_address'");
return const0_rtx;
}
if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_FRAME_ADDRESS)
return tem;
if (GET_CODE (tem) != REG
&& ! CONSTANT_P (tem))
tem = copy_to_mode_reg (Pmode, tem);
return tem;
}
case BUILT_IN_AGGREGATE_INCOMING_ADDRESS:
if (arglist != 0
|| ! AGGREGATE_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl)))
|| GET_CODE (DECL_RTL (DECL_RESULT (current_function_decl))) != MEM)
return const0_rtx;
else
return XEXP (DECL_RTL (DECL_RESULT (current_function_decl)), 0);
case BUILT_IN_ALLOCA:
if (arglist == 0
|| TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != INTEGER_TYPE)
break;
op0 = expand_expr (TREE_VALUE (arglist), NULL_RTX, VOIDmode, 0);
return allocate_dynamic_stack_space (op0, target, BITS_PER_UNIT);
case BUILT_IN_FFS:
if (!optimize && ! CALLED_AS_BUILT_IN (fndecl))
break;
if (arglist == 0
|| TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != INTEGER_TYPE)
break;
op0 = expand_expr (TREE_VALUE (arglist), subtarget, VOIDmode, 0);
target = expand_unop (TYPE_MODE (TREE_TYPE (TREE_VALUE (arglist))),
ffs_optab, op0, target, 1);
if (target == 0)
abort ();
return target;
case BUILT_IN_STRLEN:
if (!optimize && ! CALLED_AS_BUILT_IN (fndecl))
break;
if (arglist == 0
|| TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE)
break;
else
{
tree src = TREE_VALUE (arglist);
tree len = c_strlen (src);
int align
= get_pointer_alignment (src, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
rtx result, src_rtx, char_rtx;
enum machine_mode insn_mode = value_mode, char_mode;
enum insn_code icode;
if (len != 0)
return expand_expr (len, target, mode, EXPAND_MEMORY_USE_BAD);
if (align == 0)
break;
while (insn_mode != VOIDmode)
{
icode = strlen_optab->handlers[(int) insn_mode].insn_code;
if (icode != CODE_FOR_nothing)
break;
insn_mode = GET_MODE_WIDER_MODE (insn_mode);
}
if (insn_mode == VOIDmode)
break;
result = target;
if (! (result != 0
&& GET_CODE (result) == REG
&& GET_MODE (result) == insn_mode
&& REGNO (result) >= FIRST_PSEUDO_REGISTER))
result = gen_reg_rtx (insn_mode);
if (! (*insn_operand_predicate[(int)icode][0]) (result, insn_mode))
result = gen_reg_rtx (insn_mode);
src_rtx = memory_address (BLKmode,
expand_expr (src, NULL_RTX, ptr_mode,
EXPAND_NORMAL));
if (! (*insn_operand_predicate[(int)icode][1]) (src_rtx, Pmode))
src_rtx = copy_to_mode_reg (Pmode, src_rtx);
if (current_function_check_memory_usage)
emit_library_call (chkr_check_str_libfunc, 1, VOIDmode, 2,
src_rtx, Pmode,
GEN_INT (MEMORY_USE_RO),
TYPE_MODE (integer_type_node));
char_rtx = const0_rtx;
char_mode = insn_operand_mode[(int)icode][2];
if (! (*insn_operand_predicate[(int)icode][2]) (char_rtx, char_mode))
char_rtx = copy_to_mode_reg (char_mode, char_rtx);
emit_insn (GEN_FCN (icode) (result,
gen_rtx_MEM (BLKmode, src_rtx),
char_rtx, GEN_INT (align)));
if (GET_MODE (result) == value_mode)
return result;
else if (target != 0)
{
convert_move (target, result, 0);
return target;
}
else
return convert_to_mode (value_mode, result, 0);
}
case BUILT_IN_STRCPY:
if (!optimize && ! CALLED_AS_BUILT_IN (fndecl))
break;
if (arglist == 0
|| TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE
|| TREE_CHAIN (arglist) == 0
|| TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (arglist)))) != POINTER_TYPE)
break;
else
{
tree len = c_strlen (TREE_VALUE (TREE_CHAIN (arglist)));
if (len == 0)
break;
len = size_binop (PLUS_EXPR, len, integer_one_node);
chainon (arglist, build_tree_list (NULL_TREE, len));
}
case BUILT_IN_MEMCPY:
if (!optimize && ! CALLED_AS_BUILT_IN (fndecl))
break;
if (arglist == 0
|| TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE
|| TREE_CHAIN (arglist) == 0
|| (TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (arglist))))
!= POINTER_TYPE)
|| TREE_CHAIN (TREE_CHAIN (arglist)) == 0
|| (TREE_CODE (TREE_TYPE (TREE_VALUE
(TREE_CHAIN (TREE_CHAIN (arglist)))))
!= INTEGER_TYPE))
break;
else
{
tree dest = TREE_VALUE (arglist);
tree src = TREE_VALUE (TREE_CHAIN (arglist));
tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
int src_align
= get_pointer_alignment (src, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
int dest_align
= get_pointer_alignment (dest, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
rtx dest_mem, src_mem, dest_addr, len_rtx;
if (src_align == 0 || dest_align == 0)
{
if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_STRCPY)
TREE_CHAIN (TREE_CHAIN (arglist)) = 0;
break;
}
dest_mem = get_memory_rtx (dest);
src_mem = get_memory_rtx (src);
len_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
if (current_function_check_memory_usage)
emit_library_call (chkr_copy_bitmap_libfunc, 1, VOIDmode, 3,
XEXP (dest_mem, 0), Pmode,
XEXP (src_mem, 0), Pmode,
len_rtx, TYPE_MODE (sizetype));
dest_addr
= emit_block_move (dest_mem, src_mem, len_rtx,
MIN (src_align, dest_align));
if (dest_addr == 0)
dest_addr = force_operand (XEXP (dest_mem, 0), NULL_RTX);
return dest_addr;
}
case BUILT_IN_MEMSET:
if (!optimize && ! CALLED_AS_BUILT_IN (fndecl))
break;
if (arglist == 0
|| TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE
|| TREE_CHAIN (arglist) == 0
|| (TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (arglist))))
!= INTEGER_TYPE)
|| TREE_CHAIN (TREE_CHAIN (arglist)) == 0
|| (INTEGER_TYPE
!= (TREE_CODE (TREE_TYPE
(TREE_VALUE
(TREE_CHAIN (TREE_CHAIN (arglist))))))))
break;
else
{
tree dest = TREE_VALUE (arglist);
tree val = TREE_VALUE (TREE_CHAIN (arglist));
tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
int dest_align
= get_pointer_alignment (dest, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
rtx dest_mem, dest_addr, len_rtx;
if (dest_align == 0)
break;
if (TREE_SIDE_EFFECTS (val) || TREE_SIDE_EFFECTS (len))
break;
if (expand_expr (val, NULL_RTX, VOIDmode, 0) != const0_rtx)
break;
len_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
if (GET_CODE (len_rtx) != CONST_INT)
break;
dest_mem = get_memory_rtx (dest);
if (current_function_check_memory_usage)
emit_library_call (chkr_check_addr_libfunc, 1, VOIDmode, 3,
XEXP (dest_mem, 0), Pmode,
len_rtx, TYPE_MODE (sizetype),
GEN_INT (MEMORY_USE_WO),
TYPE_MODE (integer_type_node));
dest_addr = clear_storage (dest_mem, len_rtx, dest_align);
if (dest_addr == 0)
dest_addr = force_operand (XEXP (dest_mem, 0), NULL_RTX);
return dest_addr;
}
#ifdef HAVE_cmpstrsi
case BUILT_IN_STRCMP:
if (!optimize && ! CALLED_AS_BUILT_IN (fndecl))
break;
if (current_function_check_memory_usage)
break;
if (arglist == 0
|| TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE
|| TREE_CHAIN (arglist) == 0
|| TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (arglist)))) != POINTER_TYPE)
break;
else if (!HAVE_cmpstrsi)
break;
{
tree arg1 = TREE_VALUE (arglist);
tree arg2 = TREE_VALUE (TREE_CHAIN (arglist));
tree len, len2;
len = c_strlen (arg1);
if (len)
len = size_binop (PLUS_EXPR, integer_one_node, len);
len2 = c_strlen (arg2);
if (len2)
len2 = size_binop (PLUS_EXPR, integer_one_node, len2);
if (!len || TREE_CODE (len) != INTEGER_CST)
{
if (len2)
len = len2;
else if (len == 0)
break;
}
else if (len2 && TREE_CODE (len2) == INTEGER_CST)
{
if (tree_int_cst_lt (len2, len))
len = len2;
}
chainon (arglist, build_tree_list (NULL_TREE, len));
}
case BUILT_IN_MEMCMP:
if (!optimize && ! CALLED_AS_BUILT_IN (fndecl))
break;
if (current_function_check_memory_usage)
break;
if (arglist == 0
|| TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE
|| TREE_CHAIN (arglist) == 0
|| TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (arglist)))) != POINTER_TYPE
|| TREE_CHAIN (TREE_CHAIN (arglist)) == 0
|| TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))))) != INTEGER_TYPE)
break;
else if (!HAVE_cmpstrsi)
break;
{
tree arg1 = TREE_VALUE (arglist);
tree arg2 = TREE_VALUE (TREE_CHAIN (arglist));
tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
rtx result;
int arg1_align
= get_pointer_alignment (arg1, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
int arg2_align
= get_pointer_alignment (arg2, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
enum machine_mode insn_mode
= insn_operand_mode[(int) CODE_FOR_cmpstrsi][0];
if (arg1_align == 0 || arg2_align == 0)
{
if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_STRCMP)
TREE_CHAIN (TREE_CHAIN (arglist)) = 0;
break;
}
result = target;
if (! (result != 0
&& GET_CODE (result) == REG && GET_MODE (result) == insn_mode
&& REGNO (result) >= FIRST_PSEUDO_REGISTER))
result = gen_reg_rtx (insn_mode);
emit_insn (gen_cmpstrsi (result, get_memory_rtx (arg1),
get_memory_rtx (arg2),
expand_expr (len, NULL_RTX, VOIDmode, 0),
GEN_INT (MIN (arg1_align, arg2_align))));
mode = TYPE_MODE (TREE_TYPE (exp));
if (GET_MODE (result) == mode)
return result;
else if (target != 0)
{
convert_move (target, result, 0);
return target;
}
else
return convert_to_mode (mode, result, 0);
}
#else
case BUILT_IN_STRCMP:
case BUILT_IN_MEMCMP:
break;
#endif
case BUILT_IN_SETJMP:
if (arglist == 0
|| TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE)
break;
else
{
rtx buf_addr = expand_expr (TREE_VALUE (arglist), subtarget,
VOIDmode, 0);
rtx lab = gen_label_rtx ();
rtx ret = expand_builtin_setjmp (buf_addr, target, lab, lab);
emit_label (lab);
return ret;
}
case BUILT_IN_LONGJMP:
if (arglist == 0 || TREE_CHAIN (arglist) == 0
|| TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE)
break;
else
{
rtx buf_addr = expand_expr (TREE_VALUE (arglist), subtarget,
VOIDmode, 0);
rtx value = expand_expr (TREE_VALUE (TREE_CHAIN (arglist)),
NULL_RTX, VOIDmode, 0);
if (value != const1_rtx)
{
error ("__builtin_longjmp second argument must be 1");
return const0_rtx;
}
expand_builtin_longjmp (buf_addr, value);
return const0_rtx;
}
case BUILT_IN_TRAP:
#ifdef HAVE_trap
if (HAVE_trap)
emit_insn (gen_trap ());
else
#endif
error ("__builtin_trap not supported by this target");
emit_barrier ();
return const0_rtx;
case BUILT_IN_UNWIND_INIT:
expand_builtin_unwind_init ();
return const0_rtx;
case BUILT_IN_DWARF_CFA:
return virtual_cfa_rtx;
#ifdef DWARF2_UNWIND_INFO
case BUILT_IN_DWARF_FP_REGNUM:
return expand_builtin_dwarf_fp_regnum ();
case BUILT_IN_DWARF_REG_SIZE:
return expand_builtin_dwarf_reg_size (TREE_VALUE (arglist), target);
#endif
case BUILT_IN_FROB_RETURN_ADDR:
return expand_builtin_frob_return_addr (TREE_VALUE (arglist));
case BUILT_IN_EXTRACT_RETURN_ADDR:
return expand_builtin_extract_return_addr (TREE_VALUE (arglist));
case BUILT_IN_EH_RETURN:
expand_builtin_eh_return (TREE_VALUE (arglist),
TREE_VALUE (TREE_CHAIN (arglist)),
TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))));
return const0_rtx;
default:
#ifdef EXPAND_TARGET_INTRINSIC
if (DECL_TARGET_INTRINSIC_P (fndecl))
return EXPAND_TARGET_INTRINSIC (fndecl, target, value_mode, arglist);
#endif
error ("built-in function `%s' not currently supported",
IDENTIFIER_POINTER (DECL_NAME (fndecl)));
}
return expand_call (exp, target, ignore);
}
static enum machine_mode apply_args_mode[FIRST_PSEUDO_REGISTER];
static enum machine_mode apply_result_mode[FIRST_PSEUDO_REGISTER];
static int apply_args_reg_offset[FIRST_PSEUDO_REGISTER];
int
apply_args_register_offset (regno)
int regno;
{
apply_args_size ();
#ifdef OUTGOING_REGNO
regno = OUTGOING_REGNO(regno);
#endif
return apply_args_reg_offset[regno];
}
static int
apply_args_size ()
{
static int size = -1;
int align, regno;
enum machine_mode mode;
if (size < 0)
{
size = GET_MODE_SIZE (Pmode);
if (struct_value_rtx)
size += GET_MODE_SIZE (Pmode);
for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
if (FUNCTION_ARG_REGNO_P (regno))
{
enum machine_mode best_mode = VOIDmode;
for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT);
mode != VOIDmode;
mode = GET_MODE_WIDER_MODE (mode))
if (HARD_REGNO_MODE_OK (regno, mode)
&& HARD_REGNO_NREGS (regno, mode) == 1)
best_mode = mode;
if (best_mode == VOIDmode)
for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT);
mode != VOIDmode;
mode = GET_MODE_WIDER_MODE (mode))
if (HARD_REGNO_MODE_OK (regno, mode)
&& (mov_optab->handlers[(int) mode].insn_code
!= CODE_FOR_nothing))
best_mode = mode;
if (best_mode == VOIDmode
&& HARD_REGNO_MODE_OK (regno, SVmode)
&& (mov_optab->handlers[(int) SVmode].insn_code
!= CODE_FOR_nothing))
best_mode = SVmode;
mode = best_mode;
if (mode == VOIDmode)
abort ();
align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT;
if (size % align != 0)
size = CEIL (size, align) * align;
apply_args_reg_offset[regno] = size;
size += GET_MODE_SIZE (mode);
apply_args_mode[regno] = mode;
}
else
{
apply_args_mode[regno] = VOIDmode;
apply_args_reg_offset[regno] = 0;
}
}
return size;
}
static int
apply_result_size ()
{
static int size = -1;
int align, regno;
enum machine_mode mode;
if (size < 0)
{
size = 0;
for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
if (FUNCTION_VALUE_REGNO_P (regno))
{
enum machine_mode best_mode = VOIDmode;
for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT);
mode != TImode;
mode = GET_MODE_WIDER_MODE (mode))
if (HARD_REGNO_MODE_OK (regno, mode))
best_mode = mode;
if (best_mode == VOIDmode)
for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT);
mode != VOIDmode;
mode = GET_MODE_WIDER_MODE (mode))
if (HARD_REGNO_MODE_OK (regno, mode)
&& (mov_optab->handlers[(int) mode].insn_code
!= CODE_FOR_nothing))
best_mode = mode;
if (best_mode == VOIDmode
&& HARD_REGNO_MODE_OK (regno, SVmode)
&& (mov_optab->handlers[(int) SVmode].insn_code
!= CODE_FOR_nothing))
best_mode = SVmode;
mode = best_mode;
if (mode == VOIDmode)
abort ();
align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT;
if (size % align != 0)
size = CEIL (size, align) * align;
size += GET_MODE_SIZE (mode);
apply_result_mode[regno] = mode;
}
else
apply_result_mode[regno] = VOIDmode;
#ifdef APPLY_RESULT_SIZE
size = APPLY_RESULT_SIZE;
#endif
}
return size;
}
#if defined (HAVE_untyped_call) || defined (HAVE_untyped_return)
static rtx
result_vector (savep, result)
int savep;
rtx result;
{
int regno, size, align, nelts;
enum machine_mode mode;
rtx reg, mem;
rtx *savevec = (rtx *) alloca (FIRST_PSEUDO_REGISTER * sizeof (rtx));
size = nelts = 0;
for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
if ((mode = apply_result_mode[regno]) != VOIDmode)
{
align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT;
if (size % align != 0)
size = CEIL (size, align) * align;
reg = gen_rtx_REG (mode, savep ? regno : INCOMING_REGNO (regno));
mem = change_address (result, mode,
plus_constant (XEXP (result, 0), size));
savevec[nelts++] = (savep
? gen_rtx_SET (VOIDmode, mem, reg)
: gen_rtx_SET (VOIDmode, reg, mem));
size += GET_MODE_SIZE (mode);
}
return gen_rtx_PARALLEL (VOIDmode, gen_rtvec_v (nelts, savevec));
}
#endif
static rtx
expand_builtin_apply_args ()
{
rtx registers;
int size, align, regno;
enum machine_mode mode;
registers = assign_stack_local (BLKmode, apply_args_size (), -1);
size = GET_MODE_SIZE (Pmode);
if (struct_value_rtx)
size += GET_MODE_SIZE (Pmode);
for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
if ((mode = apply_args_mode[regno]) != VOIDmode)
{
rtx tem;
align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT;
if (size % align != 0)
size = CEIL (size, align) * align;
tem = gen_rtx_REG (mode, INCOMING_REGNO (regno));
#ifdef STACK_REGS
emit_insn (gen_rtx_USE (mode, tem));
#endif
emit_move_insn (change_address (registers, mode,
plus_constant (XEXP (registers, 0),
size)),
tem);
size += GET_MODE_SIZE (mode);
}
emit_move_insn (change_address (registers, Pmode, XEXP (registers, 0)),
copy_to_reg (virtual_incoming_args_rtx));
size = GET_MODE_SIZE (Pmode);
if (struct_value_incoming_rtx)
{
emit_move_insn (change_address (registers, Pmode,
plus_constant (XEXP (registers, 0),
size)),
copy_to_reg (struct_value_incoming_rtx));
size += GET_MODE_SIZE (Pmode);
}
return copy_addr_to_reg (XEXP (registers, 0));
}
static rtx
expand_builtin_apply (function, arguments, argsize)
rtx function, arguments, argsize;
{
int size, align, regno;
enum machine_mode mode;
rtx incoming_args, result, reg, dest, call_insn;
rtx old_stack_level = 0;
rtx call_fusage = 0;
result = assign_stack_local (BLKmode, apply_result_size (), -1);
incoming_args = gen_reg_rtx (Pmode);
emit_move_insn (incoming_args,
gen_rtx_MEM (Pmode, arguments));
#ifndef STACK_GROWS_DOWNWARD
incoming_args = expand_binop (Pmode, sub_optab, incoming_args, argsize,
incoming_args, 0, OPTAB_LIB_WIDEN);
#endif
emit_queue ();
do_pending_stack_adjust ();
#ifdef HAVE_save_stack_nonlocal
if (HAVE_save_stack_nonlocal)
emit_stack_save (SAVE_NONLOCAL, &old_stack_level, NULL_RTX);
else
#endif
emit_stack_save (SAVE_BLOCK, &old_stack_level, NULL_RTX);
dest = allocate_dynamic_stack_space (argsize, 0, 0);
emit_block_move (gen_rtx_MEM (BLKmode, dest),
gen_rtx_MEM (BLKmode, incoming_args),
argsize,
PARM_BOUNDARY / BITS_PER_UNIT);
apply_args_size ();
arguments = gen_rtx_MEM (BLKmode, arguments);
size = GET_MODE_SIZE (Pmode);
if (struct_value_rtx)
size += GET_MODE_SIZE (Pmode);
for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
if ((mode = apply_args_mode[regno]) != VOIDmode)
{
align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT;
if (size % align != 0)
size = CEIL (size, align) * align;
reg = gen_rtx_REG (mode, regno);
emit_move_insn (reg,
change_address (arguments, mode,
plus_constant (XEXP (arguments, 0),
size)));
use_reg (&call_fusage, reg);
size += GET_MODE_SIZE (mode);
}
size = GET_MODE_SIZE (Pmode);
if (struct_value_rtx)
{
rtx value = gen_reg_rtx (Pmode);
emit_move_insn (value,
change_address (arguments, Pmode,
plus_constant (XEXP (arguments, 0),
size)));
emit_move_insn (struct_value_rtx, value);
if (GET_CODE (struct_value_rtx) == REG)
use_reg (&call_fusage, struct_value_rtx);
size += GET_MODE_SIZE (Pmode);
}
function = prepare_call_address (function, NULL_TREE, &call_fusage, 0);
if (GET_CODE (function) != SYMBOL_REF)
function = memory_address (FUNCTION_MODE, function);
#ifdef HAVE_untyped_call
if (HAVE_untyped_call)
emit_call_insn (gen_untyped_call (gen_rtx_MEM (FUNCTION_MODE, function),
result, result_vector (1, result)));
else
#endif
#ifdef HAVE_call_value
if (HAVE_call_value)
{
rtx valreg = 0;
for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
if ((mode = apply_result_mode[regno]) != VOIDmode)
{
if (valreg)
abort ();
valreg = gen_rtx_REG (mode, regno);
}
emit_call_insn (gen_call_value (valreg,
gen_rtx_MEM (FUNCTION_MODE, function),
const0_rtx, NULL_RTX, const0_rtx));
emit_move_insn (change_address (result, GET_MODE (valreg),
XEXP (result, 0)),
valreg);
}
else
#endif
abort ();
for (call_insn = get_last_insn ();
call_insn && GET_CODE (call_insn) != CALL_INSN;
call_insn = PREV_INSN (call_insn))
;
if (! call_insn)
abort ();
if (CALL_INSN_FUNCTION_USAGE (call_insn))
{
rtx link;
for (link = CALL_INSN_FUNCTION_USAGE (call_insn); XEXP (link, 1) != 0;
link = XEXP (link, 1))
;
XEXP (link, 1) = call_fusage;
}
else
CALL_INSN_FUNCTION_USAGE (call_insn) = call_fusage;
#ifdef HAVE_save_stack_nonlocal
if (HAVE_save_stack_nonlocal)
emit_stack_restore (SAVE_NONLOCAL, old_stack_level, NULL_RTX);
else
#endif
emit_stack_restore (SAVE_BLOCK, old_stack_level, NULL_RTX);
return copy_addr_to_reg (XEXP (result, 0));
}
static void
expand_builtin_return (result)
rtx result;
{
int size, align, regno;
enum machine_mode mode;
rtx reg;
rtx call_fusage = 0;
apply_result_size ();
result = gen_rtx_MEM (BLKmode, result);
#ifdef HAVE_untyped_return
if (HAVE_untyped_return)
{
emit_jump_insn (gen_untyped_return (result, result_vector (0, result)));
emit_barrier ();
return;
}
#endif
size = 0;
for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
if ((mode = apply_result_mode[regno]) != VOIDmode)
{
align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT;
if (size % align != 0)
size = CEIL (size, align) * align;
reg = gen_rtx_REG (mode, INCOMING_REGNO (regno));
emit_move_insn (reg,
change_address (result, mode,
plus_constant (XEXP (result, 0),
size)));
push_to_sequence (call_fusage);
emit_insn (gen_rtx_USE (VOIDmode, reg));
call_fusage = get_insns ();
end_sequence ();
size += GET_MODE_SIZE (mode);
}
emit_insns (call_fusage);
expand_null_return ();
}
static rtx
expand_increment (exp, post, ignore)
register tree exp;
int post, ignore;
{
register rtx op0, op1;
register rtx temp, value;
register 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, EXPAND_MEMORY_USE_RW);
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,
EXPAND_MEMORY_USE_BAD);
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 (!post)
{
icode = (int) this_optab->handlers[(int) mode].insn_code;
if (icode != (int) CODE_FOR_nothing
&& (*insn_operand_predicate[icode][0]) (op0, mode)
&& (*insn_operand_predicate[icode][1]) (op0, mode)
&& (*insn_operand_predicate[icode][2]) (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_operand_predicate[icode][0]) (op0, mode)
&& (*insn_operand_predicate[icode][1]) (op0, mode))
{
if (! (*insn_operand_predicate[icode][2]) (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 = change_address (op0, VOIDmode, addr);
temp = force_reg (GET_MODE (op0), op0);
if (! (*insn_operand_predicate[icode][2]) (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,
current_function_check_memory_usage ? NULL_RTX : op0,
TREE_UNSIGNED (TREE_TYPE (exp)), OPTAB_LIB_WIDEN);
if (op1 != op0)
emit_move_insn (op0, op1);
return temp;
}
static void
preexpand_calls (exp)
tree exp;
{
register int nops, i;
int type = TREE_CODE_CLASS (TREE_CODE (exp));
if (! do_preexpand_calls)
return;
if (type != 'e' && type != '<' && type != '1' && type != '2' && type != 'r')
return;
switch (TREE_CODE (exp))
{
case CALL_EXPR:
if (CALL_EXPR_RTL (exp) != 0
|| TREE_CODE (TYPE_SIZE (TREE_TYPE(exp))) != INTEGER_CST
|| (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))))
return;
CALL_EXPR_RTL (exp) = expand_call (exp, NULL_RTX, 0);
return;
case COMPOUND_EXPR:
case COND_EXPR:
case TRUTH_ANDIF_EXPR:
case TRUTH_ORIF_EXPR:
do_pending_stack_adjust ();
return;
case BLOCK:
case RTL_EXPR:
case WITH_CLEANUP_EXPR:
case CLEANUP_POINT_EXPR:
case TRY_CATCH_EXPR:
return;
case SAVE_EXPR:
if (SAVE_EXPR_RTL (exp) != 0)
return;
default:
break;
}
nops = tree_code_length[(int) TREE_CODE (exp)];
for (i = 0; i < nops; i++)
if (TREE_OPERAND (exp, i) != 0)
{
type = TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, i)));
if (type == 'e' || type == '<' || type == '1' || type == '2'
|| type == 'r')
preexpand_calls (TREE_OPERAND (exp, i));
}
}
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)
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;
{
register enum tree_code code = TREE_CODE (exp);
rtx drop_through_label = 0;
rtx temp;
rtx comparison = 0;
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)
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;
#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:
comparison = compare (build (NE_EXPR, TREE_TYPE (exp),
TREE_OPERAND (exp, 0),
TREE_OPERAND (exp, 1)),
NE, NE);
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 = floor_log2 (TREE_INT_CST_LOW (TREE_OPERAND (exp, 1)))) >= 0
&& (mode = mode_for_size (i + 1, MODE_INT, 0)) != BLKmode
&& (type = 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);
start_cleanup_deferral ();
do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label);
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);
start_cleanup_deferral ();
do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_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:
{
int bitsize, bitpos, unsignedp;
enum machine_mode mode;
tree type;
tree offset;
int volatilep = 0;
int alignment;
get_inner_reference (exp, &bitsize, &bitpos, &offset,
&mode, &unsignedp, &volatilep,
&alignment);
type = 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
{
register rtx label1 = gen_label_rtx ();
drop_through_label = gen_label_rtx ();
do_jump (TREE_OPERAND (exp, 0), label1, NULL_RTX);
start_cleanup_deferral ();
do_jump (TREE_OPERAND (exp, 1),
if_false_label ? if_false_label : drop_through_label,
if_true_label ? if_true_label : drop_through_label);
do_pending_stack_adjust ();
emit_label (label1);
do_jump (TREE_OPERAND (exp, 2),
if_false_label ? if_false_label : drop_through_label,
if_true_label ? if_true_label : drop_through_label);
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)))
do_jump (TREE_OPERAND (exp, 0), if_true_label, if_false_label);
else if (GET_MODE_CLASS (TYPE_MODE (inner_type)) == MODE_INT
&& !can_compare_p (TYPE_MODE (inner_type)))
do_jump_by_parts_equality (exp, if_false_label, if_true_label);
else
comparison = compare (exp, EQ, EQ);
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)))
do_jump (TREE_OPERAND (exp, 0), if_false_label, if_true_label);
else if (GET_MODE_CLASS (TYPE_MODE (inner_type)) == MODE_INT
&& !can_compare_p (TYPE_MODE (inner_type)))
do_jump_by_parts_equality (exp, if_true_label, if_false_label);
else
comparison = compare (exp, NE, NE);
break;
}
case LT_EXPR:
if ((GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))))
== MODE_INT)
&& !can_compare_p (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)))))
do_jump_by_parts_greater (exp, 1, if_false_label, if_true_label);
else
comparison = compare (exp, LT, LTU);
break;
case LE_EXPR:
if ((GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))))
== MODE_INT)
&& !can_compare_p (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)))))
do_jump_by_parts_greater (exp, 0, if_true_label, if_false_label);
else
comparison = compare (exp, LE, LEU);
break;
case GT_EXPR:
if ((GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))))
== MODE_INT)
&& !can_compare_p (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)))))
do_jump_by_parts_greater (exp, 0, if_false_label, if_true_label);
else
comparison = compare (exp, GT, GTU);
break;
case GE_EXPR:
if ((GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))))
== MODE_INT)
&& !can_compare_p (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)))))
do_jump_by_parts_greater (exp, 1, if_true_label, if_false_label);
else
comparison = compare (exp, GE, GEU);
break;
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 ();
if (GET_CODE (temp) == CONST_INT)
comparison = (temp == const0_rtx ? const0_rtx : const_true_rtx);
else if (GET_CODE (temp) == LABEL_REF)
comparison = const_true_rtx;
else if (GET_MODE_CLASS (GET_MODE (temp)) == MODE_INT
&& !can_compare_p (GET_MODE (temp)))
do_jump_by_parts_equality_rtx (temp, if_true_label, if_false_label);
else if (GET_MODE (temp) != VOIDmode)
comparison = compare_from_rtx (temp, CONST0_RTX (GET_MODE (temp)),
NE, TREE_UNSIGNED (TREE_TYPE (exp)),
GET_MODE (temp), NULL_RTX, 0);
else
abort ();
}
emit_queue ();
if (comparison == const_true_rtx)
{
if (if_true_label)
emit_jump (if_true_label);
}
else if (comparison == const0_rtx)
{
if (if_false_label)
emit_jump (if_false_label);
}
else if (comparison)
do_jump_for_compare (comparison, if_false_label, if_true_label);
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 nwords = (GET_MODE_SIZE (mode) / UNITS_PER_WORD);
rtx drop_through_label = 0;
int unsignedp = TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 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 comp;
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);
}
comp = compare_from_rtx (op0_word, op1_word,
(unsignedp || i > 0) ? GTU : GT,
unsignedp, word_mode, NULL_RTX, 0);
if (comp == const_true_rtx)
emit_jump (if_true_label);
else if (comp != const0_rtx)
do_jump_for_compare (comp, NULL_RTX, if_true_label);
comp = compare_from_rtx (op0_word, op1_word, NE, unsignedp, word_mode,
NULL_RTX, 0);
if (comp == const_true_rtx)
emit_jump (if_false_label);
else if (comp != const0_rtx)
do_jump_for_compare (comp, 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 comp;
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);
}
comp = compare_from_rtx (op0_word, op1_word,
(unsignedp || i > 0) ? GTU : GT,
unsignedp, word_mode, NULL_RTX, 0);
if (comp == const_true_rtx)
emit_jump (if_true_label);
else if (comp != const0_rtx)
do_jump_for_compare (comp, NULL_RTX, if_true_label);
comp = compare_from_rtx (op0_word, op1_word, NE, unsignedp, word_mode,
NULL_RTX, 0);
if (comp == const_true_rtx)
emit_jump (if_false_label);
else if (comp != const0_rtx)
do_jump_for_compare (comp, 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++)
{
rtx comp = compare_from_rtx (operand_subword_force (op0, i, mode),
operand_subword_force (op1, i, mode),
EQ, TREE_UNSIGNED (TREE_TYPE (exp)),
word_mode, NULL_RTX, 0);
if (comp == const_true_rtx)
emit_jump (if_false_label);
else if (comp != const0_rtx)
do_jump_for_compare (comp, if_false_label, NULL_RTX);
}
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)
{
rtx comp = compare_from_rtx (part, const0_rtx, EQ, 1, word_mode,
NULL_RTX, 0);
if (comp == const_true_rtx)
emit_jump (if_false_label);
else if (comp == const0_rtx)
emit_jump (if_true_label);
else
do_jump_for_compare (comp, if_false_label, if_true_label);
return;
}
if (! if_false_label)
drop_through_label = if_false_label = gen_label_rtx ();
for (i = 0; i < nwords; i++)
{
rtx comp = compare_from_rtx (operand_subword_force (op0, i,
GET_MODE (op0)),
const0_rtx, EQ, 1, word_mode, NULL_RTX, 0);
if (comp == const_true_rtx)
emit_jump (if_false_label);
else if (comp != const0_rtx)
do_jump_for_compare (comp, if_false_label, NULL_RTX);
}
if (if_true_label)
emit_jump (if_true_label);
if (drop_through_label)
emit_label (drop_through_label);
}
static void
do_jump_for_compare (comparison, if_false_label, if_true_label)
rtx comparison, if_false_label, if_true_label;
{
if (if_true_label)
{
if (bcc_gen_fctn[(int) GET_CODE (comparison)] != 0)
emit_jump_insn ((*bcc_gen_fctn[(int) GET_CODE (comparison)])
(if_true_label));
else
abort ();
if (if_false_label)
emit_jump (if_false_label);
}
else if (if_false_label)
{
rtx first = get_last_insn (), insn, branch;
int br_count;
if (bcc_gen_fctn[(int) GET_CODE (comparison)] != 0)
emit_jump_insn ((*bcc_gen_fctn[(int) GET_CODE (comparison)])
(if_false_label));
else
abort ();
if (first == 0)
first = get_insns ();
else if (INSN_DELETED_P (first))
abort ();
else
first = NEXT_INSN (first);
br_count = 0;
branch = NULL_RTX;
for (insn = first; insn ; insn = NEXT_INSN (insn))
if (GET_CODE (insn) == JUMP_INSN)
{
branch = insn;
br_count += 1;
}
if (br_count == 1 && NEXT_INSN (branch) == NULL_RTX)
{
rtx insn_label;
insn_label = XEXP (condjump_label (branch), 0);
JUMP_LABEL (branch) = insn_label;
if (insn_label != if_false_label)
abort ();
if (invert_jump (branch, if_false_label))
return;
}
if_true_label = gen_label_rtx ();
for (insn = first; insn; insn = NEXT_INSN (insn))
if (GET_CODE (insn) == JUMP_INSN)
{
rtx insn_label;
insn_label = XEXP (condjump_label (insn), 0);
JUMP_LABEL (insn) = insn_label;
if (insn_label == if_false_label)
redirect_jump (insn, if_true_label);
}
emit_jump (if_false_label);
emit_label (if_true_label);
}
}
static rtx
compare (exp, signed_code, unsigned_code)
register tree exp;
enum rtx_code signed_code, unsigned_code;
{
register rtx op0, op1;
register tree type;
register 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 op0;
op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, 0);
type = TREE_TYPE (TREE_OPERAND (exp, 0));
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
return compare_from_rtx (op0, op1, code, unsignedp, mode,
((mode == BLKmode)
? expr_size (TREE_OPERAND (exp, 0)) : NULL_RTX),
TYPE_ALIGN (TREE_TYPE (exp)) / BITS_PER_UNIT);
}
rtx
compare_from_rtx (op0, op1, code, unsignedp, mode, size, align)
register rtx op0, op1;
enum rtx_code code;
int unsignedp;
enum machine_mode mode;
rtx size;
int align;
{
rtx tem;
if ((CONSTANT_P (op0) && ! CONSTANT_P (op1))
|| (GET_CODE (op0) == CONST_INT && GET_CODE (op1) != CONST_INT))
{
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 ();
if (GET_CODE (op0) == CONST_INT && GET_CODE (op1) == CONST_INT
&& (tem = simplify_relational_operation (code, 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, align);
return gen_rtx_fmt_ee (code, VOIDmode, cc0_rtx, const0_rtx);
}
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);
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;
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 + TREE_INT_CST_LOW (TREE_OPERAND (inner, 1))
< 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 (subtarget == 0 || GET_CODE (subtarget) != REG
|| 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, GET_MODE (op0), 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 (op0, const1_rtx, subtarget);
return op0;
}
if (! can_compare_p (operand_mode))
return 0;
icode = setcc_gen_code[(int) code];
if (icode == CODE_FOR_nothing
|| (only_cheap && insn_operand_mode[(int) icode][0] != 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;
}
preexpand_calls (exp);
if (subtarget == 0 || GET_CODE (subtarget) != REG
|| 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, 0);
if (GET_CODE (result) == CONST_INT)
return (((result == const0_rtx && ! invert)
|| (result != const0_rtx && invert))
? const0_rtx : const1_rtx);
label = gen_label_rtx ();
if (bcc_gen_fctn[(int) code] == 0)
abort ();
emit_jump_insn ((*bcc_gen_fctn[(int) code]) (label));
emit_move_insn (target, invert ? const1_rtx : const0_rtx);
emit_label (label);
return target;
}
#ifdef HAVE_tablejump
void
do_tablejump (index, mode, range, table_label, default_label)
rtx index, range, table_label, default_label;
enum machine_mode mode;
{
register rtx temp, vector, table_label_ref;
emit_cmp_and_jump_insns (index, range, GTU, NULL_RTX, mode, 1,
0, default_label);
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
table_label_ref = force_reg (Pmode, gen_rtx_LABEL_REF (Pmode, table_label));
index = gen_rtx_PLUS (Pmode,
gen_rtx_MULT (Pmode, index,
GEN_INT (GET_MODE_SIZE (CASE_VECTOR_MODE))),
table_label_ref);
#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);
#ifdef HAVE_tablejump_labelref
emit_jump_insn (gen_tablejump_labelref (temp, table_label_ref, table_label));
#else
emit_jump_insn (gen_tablejump (temp, table_label));
#endif
if (! CASE_VECTOR_PC_RELATIVE && ! flag_pic)
emit_barrier ();
}
#endif