#include "config.h"
#include "system.h"
#include "toplev.h"
#include "insn-config.h"
#include "rtl.h"
#include "tree.h"
#include "tm_p.h"
#include "flags.h"
#include "function.h"
#include "except.h"
#include "expr.h"
#include "optabs.h"
#include "libfuncs.h"
#include "recog.h"
#include "reload.h"
#include "ggc.h"
#include "real.h"
#include "basic-block.h"
optab optab_table[OTI_MAX];
rtx libfunc_table[LTI_MAX];
enum insn_code extendtab[MAX_MACHINE_MODE][MAX_MACHINE_MODE][2];
enum insn_code fixtab[NUM_MACHINE_MODES][NUM_MACHINE_MODES][2];
enum insn_code fixtrunctab[NUM_MACHINE_MODES][NUM_MACHINE_MODES][2];
enum insn_code floattab[NUM_MACHINE_MODES][NUM_MACHINE_MODES][2];
optab code_to_optab[NUM_RTX_CODE + 1];
rtxfun bcc_gen_fctn[NUM_RTX_CODE];
enum insn_code setcc_gen_code[NUM_RTX_CODE];
#ifdef HAVE_conditional_move
enum insn_code movcc_gen_code[NUM_MACHINE_MODES];
#endif
static int add_equal_note PARAMS ((rtx, rtx, enum rtx_code, rtx, rtx));
static rtx widen_operand PARAMS ((rtx, enum machine_mode,
enum machine_mode, int, int));
static int expand_cmplxdiv_straight PARAMS ((rtx, rtx, rtx, rtx,
rtx, rtx, enum machine_mode,
int, enum optab_methods,
enum mode_class, optab));
static int expand_cmplxdiv_wide PARAMS ((rtx, rtx, rtx, rtx,
rtx, rtx, enum machine_mode,
int, enum optab_methods,
enum mode_class, optab));
static void prepare_cmp_insn PARAMS ((rtx *, rtx *, enum rtx_code *, rtx,
enum machine_mode *, int *,
enum can_compare_purpose));
static enum insn_code can_fix_p PARAMS ((enum machine_mode, enum machine_mode,
int, int *));
static enum insn_code can_float_p PARAMS ((enum machine_mode,
enum machine_mode,
int));
static rtx ftruncify PARAMS ((rtx));
static optab new_optab PARAMS ((void));
static inline optab init_optab PARAMS ((enum rtx_code));
static inline optab init_optabv PARAMS ((enum rtx_code));
static void init_libfuncs PARAMS ((optab, int, int, const char *, int));
static void init_integral_libfuncs PARAMS ((optab, const char *, int));
static void init_floating_libfuncs PARAMS ((optab, const char *, int));
#ifdef HAVE_conditional_trap
static void init_traps PARAMS ((void));
#endif
static void emit_cmp_and_jump_insn_1 PARAMS ((rtx, rtx, enum machine_mode,
enum rtx_code, int, rtx));
static void prepare_float_lib_cmp PARAMS ((rtx *, rtx *, enum rtx_code *,
enum machine_mode *, int *));
static rtx expand_vector_binop PARAMS ((enum machine_mode, optab,
rtx, rtx, rtx, int,
enum optab_methods));
static rtx expand_vector_unop PARAMS ((enum machine_mode, optab, rtx, rtx,
int));
static int
add_equal_note (insns, target, code, op0, op1)
rtx insns;
rtx target;
enum rtx_code code;
rtx op0, op1;
{
rtx last_insn, insn, set;
rtx note;
if (! insns
|| ! INSN_P (insns)
|| NEXT_INSN (insns) == NULL_RTX)
abort ();
if (GET_RTX_CLASS (code) != '1' && GET_RTX_CLASS (code) != '2'
&& GET_RTX_CLASS (code) != 'c' && GET_RTX_CLASS (code) != '<')
return 1;
if (GET_CODE (target) == ZERO_EXTRACT)
return 1;
for (last_insn = insns;
NEXT_INSN (last_insn) != NULL_RTX;
last_insn = NEXT_INSN (last_insn))
;
set = single_set (last_insn);
if (set == NULL_RTX)
return 1;
if (! rtx_equal_p (SET_DEST (set), target)
&& (GET_CODE (SET_DEST (set)) != STRICT_LOW_PART
|| ! rtx_equal_p (SUBREG_REG (XEXP (SET_DEST (set), 0)),
target)))
return 1;
if (reg_overlap_mentioned_p (target, op0)
|| (op1 && reg_overlap_mentioned_p (target, op1)))
{
insn = PREV_INSN (last_insn);
while (insn != NULL_RTX)
{
if (reg_set_p (target, insn))
return 0;
insn = PREV_INSN (insn);
}
}
if (GET_RTX_CLASS (code) == '1')
note = gen_rtx_fmt_e (code, GET_MODE (target), copy_rtx (op0));
else
note = gen_rtx_fmt_ee (code, GET_MODE (target), copy_rtx (op0), copy_rtx (op1));
set_unique_reg_note (last_insn, REG_EQUAL, note);
return 1;
}
static rtx
widen_operand (op, mode, oldmode, unsignedp, no_extend)
rtx op;
enum machine_mode mode, oldmode;
int unsignedp;
int no_extend;
{
rtx result;
if (no_extend && GET_MODE (op) == VOIDmode)
return op;
if (! no_extend
|| (GET_CODE (op) == SUBREG && SUBREG_PROMOTED_VAR_P (op)
&& SUBREG_PROMOTED_UNSIGNED_P (op) == unsignedp))
return convert_modes (mode, oldmode, op, unsignedp);
if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD)
return gen_rtx_SUBREG (mode, force_reg (GET_MODE (op), op), 0);
result = gen_reg_rtx (mode);
emit_insn (gen_rtx_CLOBBER (VOIDmode, result));
emit_move_insn (gen_lowpart (GET_MODE (op), result), op);
return result;
}
static int
expand_cmplxdiv_straight (real0, real1, imag0, imag1, realr, imagr, submode,
unsignedp, methods, class, binoptab)
rtx real0, real1, imag0, imag1, realr, imagr;
enum machine_mode submode;
int unsignedp;
enum optab_methods methods;
enum mode_class class;
optab binoptab;
{
rtx divisor;
rtx real_t, imag_t;
rtx temp1, temp2;
rtx res;
optab this_add_optab = add_optab;
optab this_sub_optab = sub_optab;
optab this_neg_optab = neg_optab;
optab this_mul_optab = smul_optab;
if (binoptab == sdivv_optab)
{
this_add_optab = addv_optab;
this_sub_optab = subv_optab;
this_neg_optab = negv_optab;
this_mul_optab = smulv_optab;
}
real0 = force_reg (submode, real0);
real1 = force_reg (submode, real1);
if (imag0 != 0)
imag0 = force_reg (submode, imag0);
imag1 = force_reg (submode, imag1);
temp1 = expand_binop (submode, this_mul_optab, real1, real1,
NULL_RTX, unsignedp, methods);
temp2 = expand_binop (submode, this_mul_optab, imag1, imag1,
NULL_RTX, unsignedp, methods);
if (temp1 == 0 || temp2 == 0)
return 0;
divisor = expand_binop (submode, this_add_optab, temp1, temp2,
NULL_RTX, unsignedp, methods);
if (divisor == 0)
return 0;
if (imag0 == 0)
{
real_t = expand_binop (submode, this_mul_optab, real0, real1,
NULL_RTX, unsignedp, methods);
imag_t = expand_binop (submode, this_mul_optab, real0, imag1,
NULL_RTX, unsignedp, methods);
if (real_t == 0 || imag_t == 0)
return 0;
imag_t = expand_unop (submode, this_neg_optab, imag_t,
NULL_RTX, unsignedp);
}
else
{
temp1 = expand_binop (submode, this_mul_optab, real0, real1,
NULL_RTX, unsignedp, methods);
temp2 = expand_binop (submode, this_mul_optab, imag0, imag1,
NULL_RTX, unsignedp, methods);
if (temp1 == 0 || temp2 == 0)
return 0;
real_t = expand_binop (submode, this_add_optab, temp1, temp2,
NULL_RTX, unsignedp, methods);
temp1 = expand_binop (submode, this_mul_optab, imag0, real1,
NULL_RTX, unsignedp, methods);
temp2 = expand_binop (submode, this_mul_optab, real0, imag1,
NULL_RTX, unsignedp, methods);
if (temp1 == 0 || temp2 == 0)
return 0;
imag_t = expand_binop (submode, this_sub_optab, temp1, temp2,
NULL_RTX, unsignedp, methods);
if (real_t == 0 || imag_t == 0)
return 0;
}
if (class == MODE_COMPLEX_FLOAT)
res = expand_binop (submode, binoptab, real_t, divisor,
realr, unsignedp, methods);
else
res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
real_t, divisor, realr, unsignedp);
if (res == 0)
return 0;
if (res != realr)
emit_move_insn (realr, res);
if (class == MODE_COMPLEX_FLOAT)
res = expand_binop (submode, binoptab, imag_t, divisor,
imagr, unsignedp, methods);
else
res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
imag_t, divisor, imagr, unsignedp);
if (res == 0)
return 0;
if (res != imagr)
emit_move_insn (imagr, res);
return 1;
}
static int
expand_cmplxdiv_wide (real0, real1, imag0, imag1, realr, imagr, submode,
unsignedp, methods, class, binoptab)
rtx real0, real1, imag0, imag1, realr, imagr;
enum machine_mode submode;
int unsignedp;
enum optab_methods methods;
enum mode_class class;
optab binoptab;
{
rtx ratio, divisor;
rtx real_t, imag_t;
rtx temp1, temp2, lab1, lab2;
enum machine_mode mode;
rtx res;
optab this_add_optab = add_optab;
optab this_sub_optab = sub_optab;
optab this_neg_optab = neg_optab;
optab this_mul_optab = smul_optab;
if (binoptab == sdivv_optab)
{
this_add_optab = addv_optab;
this_sub_optab = subv_optab;
this_neg_optab = negv_optab;
this_mul_optab = smulv_optab;
}
real0 = force_reg (submode, real0);
real1 = force_reg (submode, real1);
if (imag0 != 0)
imag0 = force_reg (submode, imag0);
imag1 = force_reg (submode, imag1);
if (unsignedp)
{
temp1 = real1;
temp2 = imag1;
}
else
{
temp1 = expand_abs (submode, real1, NULL_RTX, unsignedp, 1);
temp2 = expand_abs (submode, imag1, NULL_RTX, unsignedp, 1);
}
if (temp1 == 0 || temp2 == 0)
return 0;
mode = GET_MODE (temp1);
lab1 = gen_label_rtx ();
emit_cmp_and_jump_insns (temp1, temp2, LT, NULL_RTX,
mode, unsignedp, lab1);
if (class == MODE_COMPLEX_FLOAT)
ratio = expand_binop (submode, binoptab, imag1, real1,
NULL_RTX, unsignedp, methods);
else
ratio = expand_divmod (0, TRUNC_DIV_EXPR, submode,
imag1, real1, NULL_RTX, unsignedp);
if (ratio == 0)
return 0;
temp1 = expand_binop (submode, this_mul_optab, imag1, ratio,
NULL_RTX, unsignedp, methods);
if (temp1 == 0)
return 0;
divisor = expand_binop (submode, this_add_optab, temp1, real1,
NULL_RTX, unsignedp, methods);
if (divisor == 0)
return 0;
if (imag0 == 0)
{
real_t = real0;
imag_t = expand_binop (submode, this_mul_optab, real0, ratio,
NULL_RTX, unsignedp, methods);
if (imag_t == 0)
return 0;
imag_t = expand_unop (submode, this_neg_optab, imag_t,
NULL_RTX, unsignedp);
if (real_t == 0 || imag_t == 0)
return 0;
}
else
{
temp1 = expand_binop (submode, this_mul_optab, imag0, ratio,
NULL_RTX, unsignedp, methods);
if (temp1 == 0)
return 0;
real_t = expand_binop (submode, this_add_optab, temp1, real0,
NULL_RTX, unsignedp, methods);
temp1 = expand_binop (submode, this_mul_optab, real0, ratio,
NULL_RTX, unsignedp, methods);
if (temp1 == 0)
return 0;
imag_t = expand_binop (submode, this_sub_optab, imag0, temp1,
NULL_RTX, unsignedp, methods);
if (real_t == 0 || imag_t == 0)
return 0;
}
if (class == MODE_COMPLEX_FLOAT)
res = expand_binop (submode, binoptab, real_t, divisor,
realr, unsignedp, methods);
else
res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
real_t, divisor, realr, unsignedp);
if (res == 0)
return 0;
if (res != realr)
emit_move_insn (realr, res);
if (class == MODE_COMPLEX_FLOAT)
res = expand_binop (submode, binoptab, imag_t, divisor,
imagr, unsignedp, methods);
else
res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
imag_t, divisor, imagr, unsignedp);
if (res == 0)
return 0;
if (res != imagr)
emit_move_insn (imagr, res);
lab2 = gen_label_rtx ();
emit_jump_insn (gen_jump (lab2));
emit_barrier ();
emit_label (lab1);
if (class == MODE_COMPLEX_FLOAT)
ratio = expand_binop (submode, binoptab, real1, imag1,
NULL_RTX, unsignedp, methods);
else
ratio = expand_divmod (0, TRUNC_DIV_EXPR, submode,
real1, imag1, NULL_RTX, unsignedp);
if (ratio == 0)
return 0;
temp1 = expand_binop (submode, this_mul_optab, real1, ratio,
NULL_RTX, unsignedp, methods);
if (temp1 == 0)
return 0;
divisor = expand_binop (submode, this_add_optab, temp1, imag1,
NULL_RTX, unsignedp, methods);
if (divisor == 0)
return 0;
if (imag0 == 0)
{
real_t = expand_binop (submode, this_mul_optab, real0, ratio,
NULL_RTX, unsignedp, methods);
imag_t = expand_unop (submode, this_neg_optab, real0,
NULL_RTX, unsignedp);
if (real_t == 0 || imag_t == 0)
return 0;
}
else
{
temp1 = expand_binop (submode, this_mul_optab, real0, ratio,
NULL_RTX, unsignedp, methods);
if (temp1 == 0)
return 0;
real_t = expand_binop (submode, this_add_optab, temp1, imag0,
NULL_RTX, unsignedp, methods);
temp1 = expand_binop (submode, this_mul_optab, imag0, ratio,
NULL_RTX, unsignedp, methods);
if (temp1 == 0)
return 0;
imag_t = expand_binop (submode, this_sub_optab, temp1, real0,
NULL_RTX, unsignedp, methods);
if (real_t == 0 || imag_t == 0)
return 0;
}
if (class == MODE_COMPLEX_FLOAT)
res = expand_binop (submode, binoptab, real_t, divisor,
realr, unsignedp, methods);
else
res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
real_t, divisor, realr, unsignedp);
if (res == 0)
return 0;
if (res != realr)
emit_move_insn (realr, res);
if (class == MODE_COMPLEX_FLOAT)
res = expand_binop (submode, binoptab, imag_t, divisor,
imagr, unsignedp, methods);
else
res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
imag_t, divisor, imagr, unsignedp);
if (res == 0)
return 0;
if (res != imagr)
emit_move_insn (imagr, res);
emit_label (lab2);
return 1;
}
rtx
expand_simple_binop (mode, code, op0, op1, target, unsignedp, methods)
enum machine_mode mode;
enum rtx_code code;
rtx op0, op1;
rtx target;
int unsignedp;
enum optab_methods methods;
{
optab binop = code_to_optab[(int) code];
if (binop == 0)
abort ();
return expand_binop (mode, binop, op0, op1, target, unsignedp, methods);
}
rtx
expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
enum machine_mode mode;
optab binoptab;
rtx op0, op1;
rtx target;
int unsignedp;
enum optab_methods methods;
{
enum optab_methods next_methods
= (methods == OPTAB_LIB || methods == OPTAB_LIB_WIDEN
? OPTAB_WIDEN : methods);
enum mode_class class;
enum machine_mode wider_mode;
rtx temp;
int commutative_op = 0;
int shift_op = (binoptab->code == ASHIFT
|| binoptab->code == ASHIFTRT
|| binoptab->code == LSHIFTRT
|| binoptab->code == ROTATE
|| binoptab->code == ROTATERT);
rtx entry_last = get_last_insn ();
rtx last;
class = GET_MODE_CLASS (mode);
op0 = protect_from_queue (op0, 0);
op1 = protect_from_queue (op1, 0);
if (target)
target = protect_from_queue (target, 1);
if (flag_force_mem)
{
op0 = force_not_mem (op0);
op1 = force_not_mem (op1);
}
if (binoptab == sub_optab && GET_CODE (op1) == CONST_INT)
{
op1 = negate_rtx (mode, op1);
binoptab = add_optab;
}
if (CONSTANT_P (op0) && preserve_subexpressions_p ()
&& rtx_cost (op0, binoptab->code) > COSTS_N_INSNS (1))
op0 = force_reg (mode, op0);
if (CONSTANT_P (op1) && preserve_subexpressions_p ()
&& ! shift_op && rtx_cost (op1, binoptab->code) > COSTS_N_INSNS (1))
op1 = force_reg (mode, op1);
last = get_last_insn ();
if (GET_RTX_CLASS (binoptab->code) == 'c'
|| binoptab == smul_widen_optab
|| binoptab == umul_widen_optab
|| binoptab == smul_highpart_optab
|| binoptab == umul_highpart_optab)
{
commutative_op = 1;
if (((target == 0 || GET_CODE (target) == REG)
? ((GET_CODE (op1) == REG
&& GET_CODE (op0) != REG)
|| target == op1)
: rtx_equal_p (op1, target))
|| GET_CODE (op0) == CONST_INT)
{
temp = op1;
op1 = op0;
op0 = temp;
}
}
if (methods != OPTAB_MUST_WIDEN
&& binoptab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
{
int icode = (int) binoptab->handlers[(int) mode].insn_code;
enum machine_mode mode0 = insn_data[icode].operand[1].mode;
enum machine_mode mode1 = insn_data[icode].operand[2].mode;
rtx pat;
rtx xop0 = op0, xop1 = op1;
if (target)
temp = target;
else
temp = gen_reg_rtx (mode);
if (commutative_op)
{
if (GET_MODE (op0) != mode0 && GET_MODE (op1) != mode1
&& GET_MODE (op0) == mode1 && GET_MODE (op1) == mode0)
{
rtx tmp;
tmp = op0; op0 = op1; op1 = tmp;
tmp = xop0; xop0 = xop1; xop1 = tmp;
}
}
if (GET_MODE (op0) != mode0 && mode0 != VOIDmode)
xop0 = convert_modes (mode0,
GET_MODE (op0) != VOIDmode
? GET_MODE (op0)
: mode,
xop0, unsignedp);
if (GET_MODE (op1) != mode1 && mode1 != VOIDmode)
xop1 = convert_modes (mode1,
GET_MODE (op1) != VOIDmode
? GET_MODE (op1)
: mode,
xop1, unsignedp);
if (! (*insn_data[icode].operand[1].predicate) (xop0, mode0)
&& mode0 != VOIDmode)
xop0 = copy_to_mode_reg (mode0, xop0);
if (! (*insn_data[icode].operand[2].predicate) (xop1, mode1)
&& mode1 != VOIDmode)
xop1 = copy_to_mode_reg (mode1, xop1);
if (! (*insn_data[icode].operand[0].predicate) (temp, mode))
temp = gen_reg_rtx (mode);
pat = GEN_FCN (icode) (temp, xop0, xop1);
if (pat)
{
if (INSN_P (pat) && NEXT_INSN (pat) != NULL_RTX
&& ! add_equal_note (pat, temp, binoptab->code, xop0, xop1))
{
delete_insns_since (last);
return expand_binop (mode, binoptab, op0, op1, NULL_RTX,
unsignedp, methods);
}
emit_insn (pat);
return temp;
}
else
delete_insns_since (last);
}
if (binoptab == smul_optab && GET_MODE_WIDER_MODE (mode) != VOIDmode
&& (((unsignedp ? umul_widen_optab : smul_widen_optab)
->handlers[(int) GET_MODE_WIDER_MODE (mode)].insn_code)
!= CODE_FOR_nothing))
{
temp = expand_binop (GET_MODE_WIDER_MODE (mode),
unsignedp ? umul_widen_optab : smul_widen_optab,
op0, op1, NULL_RTX, unsignedp, OPTAB_DIRECT);
if (temp != 0)
{
if (GET_MODE_CLASS (mode) == MODE_INT)
return gen_lowpart (mode, temp);
else
return convert_to_mode (mode, temp, unsignedp);
}
}
if ((class == MODE_INT || class == MODE_FLOAT || class == MODE_COMPLEX_FLOAT)
&& methods != OPTAB_DIRECT && methods != OPTAB_LIB)
for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode;
wider_mode = GET_MODE_WIDER_MODE (wider_mode))
{
if (binoptab->handlers[(int) wider_mode].insn_code != CODE_FOR_nothing
|| (binoptab == smul_optab
&& GET_MODE_WIDER_MODE (wider_mode) != VOIDmode
&& (((unsignedp ? umul_widen_optab : smul_widen_optab)
->handlers[(int) GET_MODE_WIDER_MODE (wider_mode)].insn_code)
!= CODE_FOR_nothing)))
{
rtx xop0 = op0, xop1 = op1;
int no_extend = 0;
if ((binoptab == ior_optab || binoptab == and_optab
|| binoptab == xor_optab
|| binoptab == add_optab || binoptab == sub_optab
|| binoptab == smul_optab || binoptab == ashl_optab)
&& class == MODE_INT)
no_extend = 1;
xop0 = widen_operand (xop0, wider_mode, mode, unsignedp, no_extend);
xop1 = widen_operand (xop1, wider_mode, mode, unsignedp,
no_extend && binoptab != ashl_optab);
temp = expand_binop (wider_mode, binoptab, xop0, xop1, NULL_RTX,
unsignedp, OPTAB_DIRECT);
if (temp)
{
if (class != MODE_INT)
{
if (target == 0)
target = gen_reg_rtx (mode);
convert_move (target, temp, 0);
return target;
}
else
return gen_lowpart (mode, temp);
}
else
delete_insns_since (last);
}
}
if ((binoptab == and_optab || binoptab == ior_optab || binoptab == xor_optab)
&& class == MODE_INT
&& GET_MODE_SIZE (mode) > UNITS_PER_WORD
&& binoptab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing)
{
int i;
rtx insns;
rtx equiv_value;
if (target == 0 || target == op0 || target == op1)
target = gen_reg_rtx (mode);
start_sequence ();
for (i = 0; i < GET_MODE_BITSIZE (mode) / BITS_PER_WORD; i++)
{
rtx target_piece = operand_subword (target, i, 1, mode);
rtx x = expand_binop (word_mode, binoptab,
operand_subword_force (op0, i, mode),
operand_subword_force (op1, i, mode),
target_piece, unsignedp, next_methods);
if (x == 0)
break;
if (target_piece != x)
emit_move_insn (target_piece, x);
}
insns = get_insns ();
end_sequence ();
if (i == GET_MODE_BITSIZE (mode) / BITS_PER_WORD)
{
if (binoptab->code != UNKNOWN)
equiv_value
= gen_rtx_fmt_ee (binoptab->code, mode,
copy_rtx (op0), copy_rtx (op1));
else
equiv_value = 0;
emit_no_conflict_block (insns, target, op0, op1, equiv_value);
return target;
}
}
if ((binoptab == lshr_optab || binoptab == ashl_optab
|| binoptab == ashr_optab)
&& class == MODE_INT
&& GET_CODE (op1) == CONST_INT
&& GET_MODE_SIZE (mode) == 2 * UNITS_PER_WORD
&& binoptab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing
&& ashl_optab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing
&& lshr_optab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing)
{
rtx insns, inter, equiv_value;
rtx into_target, outof_target;
rtx into_input, outof_input;
int shift_count, left_shift, outof_word;
if (target == 0 || target == op0 || target == op1)
target = gen_reg_rtx (mode);
start_sequence ();
shift_count = INTVAL (op1);
left_shift = binoptab == ashl_optab;
outof_word = left_shift ^ ! WORDS_BIG_ENDIAN;
outof_target = operand_subword (target, outof_word, 1, mode);
into_target = operand_subword (target, 1 - outof_word, 1, mode);
outof_input = operand_subword_force (op0, outof_word, mode);
into_input = operand_subword_force (op0, 1 - outof_word, mode);
if (shift_count >= BITS_PER_WORD)
{
inter = expand_binop (word_mode, binoptab,
outof_input,
GEN_INT (shift_count - BITS_PER_WORD),
into_target, unsignedp, next_methods);
if (inter != 0 && inter != into_target)
emit_move_insn (into_target, inter);
if (inter != 0 && binoptab != ashr_optab)
inter = CONST0_RTX (word_mode);
else if (inter != 0)
inter = expand_binop (word_mode, binoptab,
outof_input,
GEN_INT (BITS_PER_WORD - 1),
outof_target, unsignedp, next_methods);
if (inter != 0 && inter != outof_target)
emit_move_insn (outof_target, inter);
}
else
{
rtx carries;
optab reverse_unsigned_shift, unsigned_shift;
reverse_unsigned_shift = (left_shift ? lshr_optab : ashl_optab);
unsigned_shift = (left_shift ? ashl_optab : lshr_optab);
carries = expand_binop (word_mode, reverse_unsigned_shift,
outof_input,
GEN_INT (BITS_PER_WORD - shift_count),
0, unsignedp, next_methods);
if (carries == 0)
inter = 0;
else
inter = expand_binop (word_mode, unsigned_shift, into_input,
op1, 0, unsignedp, next_methods);
if (inter != 0)
inter = expand_binop (word_mode, ior_optab, carries, inter,
into_target, unsignedp, next_methods);
if (inter != 0 && inter != into_target)
emit_move_insn (into_target, inter);
if (inter != 0)
inter = expand_binop (word_mode, binoptab, outof_input,
op1, outof_target, unsignedp, next_methods);
if (inter != 0 && inter != outof_target)
emit_move_insn (outof_target, inter);
}
insns = get_insns ();
end_sequence ();
if (inter != 0)
{
if (binoptab->code != UNKNOWN)
equiv_value = gen_rtx_fmt_ee (binoptab->code, mode, op0, op1);
else
equiv_value = 0;
emit_no_conflict_block (insns, target, op0, op1, equiv_value);
return target;
}
}
if ((binoptab == rotl_optab || binoptab == rotr_optab)
&& class == MODE_INT
&& GET_CODE (op1) == CONST_INT
&& GET_MODE_SIZE (mode) == 2 * UNITS_PER_WORD
&& ashl_optab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing
&& lshr_optab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing)
{
rtx insns, equiv_value;
rtx into_target, outof_target;
rtx into_input, outof_input;
rtx inter;
int shift_count, left_shift, outof_word;
if (target == 0 || target == op0 || target == op1)
target = gen_reg_rtx (mode);
start_sequence ();
shift_count = INTVAL (op1);
left_shift = (binoptab == rotl_optab);
outof_word = left_shift ^ ! WORDS_BIG_ENDIAN;
outof_target = operand_subword (target, outof_word, 1, mode);
into_target = operand_subword (target, 1 - outof_word, 1, mode);
outof_input = operand_subword_force (op0, outof_word, mode);
into_input = operand_subword_force (op0, 1 - outof_word, mode);
if (shift_count == BITS_PER_WORD)
{
emit_move_insn (outof_target, into_input);
emit_move_insn (into_target, outof_input);
inter = const0_rtx;
}
else
{
rtx into_temp1, into_temp2, outof_temp1, outof_temp2;
rtx first_shift_count, second_shift_count;
optab reverse_unsigned_shift, unsigned_shift;
reverse_unsigned_shift = (left_shift ^ (shift_count < BITS_PER_WORD)
? lshr_optab : ashl_optab);
unsigned_shift = (left_shift ^ (shift_count < BITS_PER_WORD)
? ashl_optab : lshr_optab);
if (shift_count > BITS_PER_WORD)
{
first_shift_count = GEN_INT (shift_count - BITS_PER_WORD);
second_shift_count = GEN_INT (2 * BITS_PER_WORD - shift_count);
}
else
{
first_shift_count = GEN_INT (BITS_PER_WORD - shift_count);
second_shift_count = GEN_INT (shift_count);
}
into_temp1 = expand_binop (word_mode, unsigned_shift,
outof_input, first_shift_count,
NULL_RTX, unsignedp, next_methods);
into_temp2 = expand_binop (word_mode, reverse_unsigned_shift,
into_input, second_shift_count,
NULL_RTX, unsignedp, next_methods);
if (into_temp1 != 0 && into_temp2 != 0)
inter = expand_binop (word_mode, ior_optab, into_temp1, into_temp2,
into_target, unsignedp, next_methods);
else
inter = 0;
if (inter != 0 && inter != into_target)
emit_move_insn (into_target, inter);
outof_temp1 = expand_binop (word_mode, unsigned_shift,
into_input, first_shift_count,
NULL_RTX, unsignedp, next_methods);
outof_temp2 = expand_binop (word_mode, reverse_unsigned_shift,
outof_input, second_shift_count,
NULL_RTX, unsignedp, next_methods);
if (inter != 0 && outof_temp1 != 0 && outof_temp2 != 0)
inter = expand_binop (word_mode, ior_optab,
outof_temp1, outof_temp2,
outof_target, unsignedp, next_methods);
if (inter != 0 && inter != outof_target)
emit_move_insn (outof_target, inter);
}
insns = get_insns ();
end_sequence ();
if (inter != 0)
{
if (binoptab->code != UNKNOWN)
equiv_value = gen_rtx_fmt_ee (binoptab->code, mode, op0, op1);
else
equiv_value = 0;
if (shift_count != BITS_PER_WORD)
emit_no_conflict_block (insns, target, op0, op1, equiv_value);
else
emit_insn (insns);
return target;
}
}
if ((binoptab == add_optab || binoptab == sub_optab)
&& class == MODE_INT
&& GET_MODE_SIZE (mode) >= 2 * UNITS_PER_WORD
&& binoptab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing)
{
unsigned int i;
optab otheroptab = binoptab == add_optab ? sub_optab : add_optab;
const unsigned int nwords = GET_MODE_BITSIZE (mode) / BITS_PER_WORD;
rtx carry_in = NULL_RTX, carry_out = NULL_RTX;
rtx xop0, xop1, xtarget;
#if STORE_FLAG_VALUE == 1 || STORE_FLAG_VALUE == -1
int normalizep = STORE_FLAG_VALUE;
#else
int normalizep = 1;
#endif
xop0 = force_reg (mode, op0);
xop1 = force_reg (mode, op1);
xtarget = gen_reg_rtx (mode);
if (target == 0 || GET_CODE (target) != REG)
target = xtarget;
if (GET_CODE (target) == REG)
emit_insn (gen_rtx_CLOBBER (VOIDmode, xtarget));
for (i = 0; i < nwords; i++)
{
int index = (WORDS_BIG_ENDIAN ? nwords - i - 1 : i);
rtx target_piece = operand_subword (xtarget, index, 1, mode);
rtx op0_piece = operand_subword_force (xop0, index, mode);
rtx op1_piece = operand_subword_force (xop1, index, mode);
rtx x;
x = expand_binop (word_mode, binoptab,
op0_piece, op1_piece,
target_piece, unsignedp, next_methods);
if (x == 0)
break;
if (i + 1 < nwords)
{
carry_out = gen_reg_rtx (word_mode);
carry_out = emit_store_flag_force (carry_out,
(binoptab == add_optab
? LT : GT),
x, op0_piece,
word_mode, 1, normalizep);
}
if (i > 0)
{
rtx newx;
newx = expand_binop (word_mode,
normalizep == 1 ? binoptab : otheroptab,
x, carry_in,
NULL_RTX, 1, next_methods);
if (i + 1 < nwords)
{
rtx carry_tmp = gen_reg_rtx (word_mode);
carry_tmp = emit_store_flag_force (carry_tmp,
(binoptab == add_optab
? LT : GT),
newx, x,
word_mode, 1, normalizep);
carry_out = expand_binop (word_mode, ior_optab,
carry_out, carry_tmp,
carry_out, 0, next_methods);
if (carry_out == 0)
break;
}
emit_move_insn (target_piece, newx);
}
carry_in = carry_out;
}
if (i == GET_MODE_BITSIZE (mode) / (unsigned) BITS_PER_WORD)
{
if (mov_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
{
rtx temp = emit_move_insn (target, xtarget);
set_unique_reg_note (temp,
REG_EQUAL,
gen_rtx_fmt_ee (binoptab->code, mode,
copy_rtx (xop0),
copy_rtx (xop1)));
}
else
target = xtarget;
return target;
}
else
delete_insns_since (last);
}
if (binoptab == smul_optab
&& class == MODE_INT
&& GET_MODE_SIZE (mode) == 2 * UNITS_PER_WORD
&& smul_optab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing
&& add_optab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing
&& ((umul_widen_optab->handlers[(int) mode].insn_code
!= CODE_FOR_nothing)
|| (smul_widen_optab->handlers[(int) mode].insn_code
!= CODE_FOR_nothing)))
{
int low = (WORDS_BIG_ENDIAN ? 1 : 0);
int high = (WORDS_BIG_ENDIAN ? 0 : 1);
rtx op0_high = operand_subword_force (op0, high, mode);
rtx op0_low = operand_subword_force (op0, low, mode);
rtx op1_high = operand_subword_force (op1, high, mode);
rtx op1_low = operand_subword_force (op1, low, mode);
rtx product = 0;
rtx op0_xhigh = NULL_RTX;
rtx op1_xhigh = NULL_RTX;
if (target == op0 || target == op1
|| (target != 0 && GET_CODE (target) != REG))
target = 0;
if (umul_widen_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
{
product = expand_binop (mode, umul_widen_optab, op0_low, op1_low,
target, 1, OPTAB_DIRECT);
if (product == 0)
delete_insns_since (last);
else
op0_xhigh = op0_high, op1_xhigh = op1_high;
}
if (product == 0
&& smul_widen_optab->handlers[(int) mode].insn_code
!= CODE_FOR_nothing)
{
rtx wordm1 = GEN_INT (BITS_PER_WORD - 1);
product = expand_binop (mode, smul_widen_optab, op0_low, op1_low,
target, 1, OPTAB_DIRECT);
op0_xhigh = expand_binop (word_mode, lshr_optab, op0_low, wordm1,
NULL_RTX, 1, next_methods);
if (op0_xhigh)
op0_xhigh = expand_binop (word_mode, add_optab, op0_high,
op0_xhigh, op0_xhigh, 0, next_methods);
else
{
op0_xhigh = expand_binop (word_mode, ashr_optab, op0_low, wordm1,
NULL_RTX, 0, next_methods);
if (op0_xhigh)
op0_xhigh = expand_binop (word_mode, sub_optab, op0_high,
op0_xhigh, op0_xhigh, 0,
next_methods);
}
op1_xhigh = expand_binop (word_mode, lshr_optab, op1_low, wordm1,
NULL_RTX, 1, next_methods);
if (op1_xhigh)
op1_xhigh = expand_binop (word_mode, add_optab, op1_high,
op1_xhigh, op1_xhigh, 0, next_methods);
else
{
op1_xhigh = expand_binop (word_mode, ashr_optab, op1_low, wordm1,
NULL_RTX, 0, next_methods);
if (op1_xhigh)
op1_xhigh = expand_binop (word_mode, sub_optab, op1_high,
op1_xhigh, op1_xhigh, 0,
next_methods);
}
}
if (product && op0_xhigh && op1_xhigh)
{
rtx product_high = operand_subword (product, high, 1, mode);
rtx temp = expand_binop (word_mode, binoptab, op0_low, op1_xhigh,
NULL_RTX, 0, OPTAB_DIRECT);
if (!REG_P (product_high))
product_high = force_reg (word_mode, product_high);
if (temp != 0)
temp = expand_binop (word_mode, add_optab, temp, product_high,
product_high, 0, next_methods);
if (temp != 0 && temp != product_high)
emit_move_insn (product_high, temp);
if (temp != 0)
temp = expand_binop (word_mode, binoptab, op1_low, op0_xhigh,
NULL_RTX, 0, OPTAB_DIRECT);
if (temp != 0)
temp = expand_binop (word_mode, add_optab, temp,
product_high, product_high,
0, next_methods);
if (temp != 0 && temp != product_high)
emit_move_insn (product_high, temp);
emit_move_insn (operand_subword (product, high, 1, mode), product_high);
if (temp != 0)
{
if (mov_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
{
temp = emit_move_insn (product, product);
set_unique_reg_note (temp,
REG_EQUAL,
gen_rtx_fmt_ee (MULT, mode,
copy_rtx (op0),
copy_rtx (op1)));
}
return product;
}
}
delete_insns_since (last);
}
if (class == MODE_VECTOR_INT || class == MODE_VECTOR_FLOAT)
return expand_vector_binop (mode, binoptab, op0, op1, target,
unsignedp, methods);
if (class == MODE_COMPLEX_FLOAT || class == MODE_COMPLEX_INT)
{
rtx real0 = 0, imag0 = 0;
rtx real1 = 0, imag1 = 0;
rtx realr, imagr, res;
rtx seq;
rtx equiv_value;
int ok = 0;
enum machine_mode submode = GET_MODE_INNER(mode);
if (submode == BLKmode)
abort ();
if (! target)
target = gen_reg_rtx (mode);
start_sequence ();
realr = gen_realpart (submode, target);
imagr = gen_imagpart (submode, target);
if (GET_MODE (op0) == mode)
{
real0 = gen_realpart (submode, op0);
imag0 = gen_imagpart (submode, op0);
}
else
real0 = op0;
if (GET_MODE (op1) == mode)
{
real1 = gen_realpart (submode, op1);
imag1 = gen_imagpart (submode, op1);
}
else
real1 = op1;
if (real0 == 0 || real1 == 0 || ! (imag0 != 0 || imag1 != 0))
abort ();
switch (binoptab->code)
{
case PLUS:
case MINUS:
res = expand_binop (submode, binoptab, real0, real1,
realr, unsignedp, methods);
if (res == 0)
break;
else if (res != realr)
emit_move_insn (realr, res);
if (imag0 != 0 && imag1 != 0)
res = expand_binop (submode, binoptab, imag0, imag1,
imagr, unsignedp, methods);
else if (imag0 != 0)
res = imag0;
else if (binoptab->code == MINUS)
res = expand_unop (submode,
binoptab == subv_optab ? negv_optab : neg_optab,
imag1, imagr, unsignedp);
else
res = imag1;
if (res == 0)
break;
else if (res != imagr)
emit_move_insn (imagr, res);
ok = 1;
break;
case MULT:
if (imag0 != 0 && imag1 != 0)
{
rtx temp1, temp2;
real0 = force_reg (submode, real0);
real1 = force_reg (submode, real1);
imag0 = force_reg (submode, imag0);
imag1 = force_reg (submode, imag1);
temp1 = expand_binop (submode, binoptab, real0, real1, NULL_RTX,
unsignedp, methods);
temp2 = expand_binop (submode, binoptab, imag0, imag1, NULL_RTX,
unsignedp, methods);
if (temp1 == 0 || temp2 == 0)
break;
res = (expand_binop
(submode,
binoptab == smulv_optab ? subv_optab : sub_optab,
temp1, temp2, realr, unsignedp, methods));
if (res == 0)
break;
else if (res != realr)
emit_move_insn (realr, res);
temp1 = expand_binop (submode, binoptab, real0, imag1,
NULL_RTX, unsignedp, methods);
temp2 = expand_binop (submode, binoptab, real1, imag0,
NULL_RTX, unsignedp, methods);
if (temp1 == 0 || temp2 == 0)
break;
res = (expand_binop
(submode,
binoptab == smulv_optab ? addv_optab : add_optab,
temp1, temp2, imagr, unsignedp, methods));
if (res == 0)
break;
else if (res != imagr)
emit_move_insn (imagr, res);
ok = 1;
}
else
{
real0 = force_reg (submode, real0);
real1 = force_reg (submode, real1);
res = expand_binop (submode, binoptab, real0, real1,
realr, unsignedp, methods);
if (res == 0)
break;
else if (res != realr)
emit_move_insn (realr, res);
if (imag0 != 0)
res = expand_binop (submode, binoptab,
real1, imag0, imagr, unsignedp, methods);
else
res = expand_binop (submode, binoptab,
real0, imag1, imagr, unsignedp, methods);
if (res == 0)
break;
else if (res != imagr)
emit_move_insn (imagr, res);
ok = 1;
}
break;
case DIV:
if (imag1 == 0)
{
real1 = force_reg (submode, real1);
if (class == MODE_COMPLEX_FLOAT)
res = expand_binop (submode, binoptab, real0, real1,
realr, unsignedp, methods);
else
res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
real0, real1, realr, unsignedp);
if (res == 0)
break;
else if (res != realr)
emit_move_insn (realr, res);
if (class == MODE_COMPLEX_FLOAT)
res = expand_binop (submode, binoptab, imag0, real1,
imagr, unsignedp, methods);
else
res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
imag0, real1, imagr, unsignedp);
if (res == 0)
break;
else if (res != imagr)
emit_move_insn (imagr, res);
ok = 1;
}
else
{
switch (flag_complex_divide_method)
{
case 0:
ok = expand_cmplxdiv_straight (real0, real1, imag0, imag1,
realr, imagr, submode,
unsignedp, methods,
class, binoptab);
break;
case 1:
ok = expand_cmplxdiv_wide (real0, real1, imag0, imag1,
realr, imagr, submode,
unsignedp, methods,
class, binoptab);
break;
default:
abort ();
}
}
break;
default:
abort ();
}
seq = get_insns ();
end_sequence ();
if (ok)
{
if (binoptab->code != UNKNOWN)
equiv_value
= gen_rtx_fmt_ee (binoptab->code, mode,
copy_rtx (op0), copy_rtx (op1));
else
equiv_value = 0;
emit_no_conflict_block (seq, target, op0, op1, equiv_value);
return target;
}
}
if (binoptab->handlers[(int) mode].libfunc
&& (methods == OPTAB_LIB || methods == OPTAB_LIB_WIDEN))
{
rtx insns;
rtx op1x = op1;
enum machine_mode op1_mode = mode;
rtx value;
start_sequence ();
if (shift_op)
{
op1_mode = word_mode;
op1x = convert_to_mode (word_mode, op1, 1);
}
if (GET_MODE (op0) != VOIDmode
&& GET_MODE (op0) != mode)
op0 = convert_to_mode (mode, op0, unsignedp);
value = emit_library_call_value (binoptab->handlers[(int) mode].libfunc,
NULL_RTX, LCT_CONST, mode, 2,
op0, mode, op1x, op1_mode);
insns = get_insns ();
end_sequence ();
target = gen_reg_rtx (mode);
emit_libcall_block (insns, target, value,
gen_rtx_fmt_ee (binoptab->code, mode, op0, op1));
return target;
}
delete_insns_since (last);
if (! (methods == OPTAB_WIDEN || methods == OPTAB_LIB_WIDEN
|| methods == OPTAB_MUST_WIDEN))
{
delete_insns_since (entry_last);
return 0;
}
methods = (methods == OPTAB_LIB_WIDEN ? OPTAB_LIB : OPTAB_DIRECT);
if (class == MODE_INT || class == MODE_FLOAT || class == MODE_COMPLEX_FLOAT)
{
for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode;
wider_mode = GET_MODE_WIDER_MODE (wider_mode))
{
if ((binoptab->handlers[(int) wider_mode].insn_code
!= CODE_FOR_nothing)
|| (methods == OPTAB_LIB
&& binoptab->handlers[(int) wider_mode].libfunc))
{
rtx xop0 = op0, xop1 = op1;
int no_extend = 0;
if ((binoptab == ior_optab || binoptab == and_optab
|| binoptab == xor_optab
|| binoptab == add_optab || binoptab == sub_optab
|| binoptab == smul_optab || binoptab == ashl_optab)
&& class == MODE_INT)
no_extend = 1;
xop0 = widen_operand (xop0, wider_mode, mode,
unsignedp, no_extend);
xop1 = widen_operand (xop1, wider_mode, mode, unsignedp,
no_extend && binoptab != ashl_optab);
temp = expand_binop (wider_mode, binoptab, xop0, xop1, NULL_RTX,
unsignedp, methods);
if (temp)
{
if (class != MODE_INT)
{
if (target == 0)
target = gen_reg_rtx (mode);
convert_move (target, temp, 0);
return target;
}
else
return gen_lowpart (mode, temp);
}
else
delete_insns_since (last);
}
}
}
delete_insns_since (entry_last);
return 0;
}
static rtx
expand_vector_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
enum machine_mode mode;
optab binoptab;
rtx op0, op1;
rtx target;
int unsignedp;
enum optab_methods methods;
{
enum machine_mode submode, tmode;
int size, elts, subsize, subbitsize, i;
rtx t, a, b, res, seq;
enum mode_class class;
class = GET_MODE_CLASS (mode);
size = GET_MODE_SIZE (mode);
submode = GET_MODE_INNER (mode);
for (tmode = GET_CLASS_NARROWEST_MODE (class);
GET_MODE_SIZE (tmode) < GET_MODE_SIZE (mode);
tmode = GET_MODE_WIDER_MODE (tmode))
{
if (GET_MODE_INNER (tmode) == GET_MODE_INNER (mode)
&& binoptab->handlers[(int) tmode].insn_code != CODE_FOR_nothing)
submode = tmode;
}
switch (binoptab->code)
{
case AND:
case IOR:
case XOR:
tmode = int_mode_for_mode (mode);
if (tmode != BLKmode)
submode = tmode;
case PLUS:
case MINUS:
case MULT:
case DIV:
subsize = GET_MODE_SIZE (submode);
subbitsize = GET_MODE_BITSIZE (submode);
elts = size / subsize;
if (subsize == GET_MODE_UNIT_SIZE (mode) && methods == OPTAB_DIRECT)
return 0;
start_sequence ();
if (GET_MODE (op0) != mode)
op0 = copy_to_mode_reg (mode, op0);
if (GET_MODE (op1) != mode)
op1 = copy_to_mode_reg (mode, op1);
if (!target)
target = gen_reg_rtx (mode);
for (i = 0; i < elts; ++i)
{
if (GET_CODE (target) == REG
&& (BYTES_BIG_ENDIAN
? subsize < UNITS_PER_WORD
: ((i * subsize) % UNITS_PER_WORD) != 0))
t = NULL_RTX;
else
t = simplify_gen_subreg (submode, target, mode, i * subsize);
if (CONSTANT_P (op0))
a = simplify_gen_subreg (submode, op0, mode, i * subsize);
else
a = extract_bit_field (op0, subbitsize, i * subbitsize, unsignedp,
NULL_RTX, submode, submode, size);
if (CONSTANT_P (op1))
b = simplify_gen_subreg (submode, op1, mode, i * subsize);
else
b = extract_bit_field (op1, subbitsize, i * subbitsize, unsignedp,
NULL_RTX, submode, submode, size);
if (binoptab->code == DIV)
{
if (class == MODE_VECTOR_FLOAT)
res = expand_binop (submode, binoptab, a, b, t,
unsignedp, methods);
else
res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
a, b, t, unsignedp);
}
else
res = expand_binop (submode, binoptab, a, b, t,
unsignedp, methods);
if (res == 0)
break;
if (t)
emit_move_insn (t, res);
else
store_bit_field (target, subbitsize, i * subbitsize, submode, res,
size);
}
break;
default:
abort ();
}
seq = get_insns ();
end_sequence ();
emit_insn (seq);
return target;
}
static rtx
expand_vector_unop (mode, unoptab, op0, target, unsignedp)
enum machine_mode mode;
optab unoptab;
rtx op0;
rtx target;
int unsignedp;
{
enum machine_mode submode, tmode;
int size, elts, subsize, subbitsize, i;
rtx t, a, res, seq;
size = GET_MODE_SIZE (mode);
submode = GET_MODE_INNER (mode);
for (tmode = GET_CLASS_NARROWEST_MODE (GET_MODE_CLASS (mode));
GET_MODE_SIZE (tmode) < GET_MODE_SIZE (mode);
tmode = GET_MODE_WIDER_MODE (tmode))
{
if (GET_MODE_INNER (tmode) == GET_MODE_INNER (mode)
&& unoptab->handlers[(int) tmode].insn_code != CODE_FOR_nothing)
submode = tmode;
}
if (unoptab == neg_optab && GET_MODE_CLASS (submode) == MODE_INT
&& GET_MODE (op0) == mode)
{
rtx temp;
temp = expand_binop (mode, sub_optab, CONST0_RTX (mode), op0,
target, unsignedp, OPTAB_DIRECT);
if (temp)
return temp;
}
if (unoptab == one_cmpl_optab)
{
tmode = int_mode_for_mode (mode);
if (tmode != BLKmode)
submode = tmode;
}
subsize = GET_MODE_SIZE (submode);
subbitsize = GET_MODE_BITSIZE (submode);
elts = size / subsize;
if (GET_MODE (op0) != mode)
op0 = copy_to_mode_reg (mode, op0);
if (!target)
target = gen_reg_rtx (mode);
start_sequence ();
for (i = 0; i < elts; ++i)
{
if (GET_CODE (target) == REG
&& (BYTES_BIG_ENDIAN
? subsize < UNITS_PER_WORD
: ((i * subsize) % UNITS_PER_WORD) != 0))
t = NULL_RTX;
else
t = simplify_gen_subreg (submode, target, mode, i * subsize);
if (CONSTANT_P (op0))
a = simplify_gen_subreg (submode, op0, mode, i * subsize);
else
a = extract_bit_field (op0, subbitsize, i * subbitsize, unsignedp,
t, submode, submode, size);
res = expand_unop (submode, unoptab, a, t, unsignedp);
if (t)
emit_move_insn (t, res);
else
store_bit_field (target, subbitsize, i * subbitsize, submode, res,
size);
}
seq = get_insns ();
end_sequence ();
emit_insn (seq);
return target;
}
rtx
sign_expand_binop (mode, uoptab, soptab, op0, op1, target, unsignedp, methods)
enum machine_mode mode;
optab uoptab, soptab;
rtx op0, op1, target;
int unsignedp;
enum optab_methods methods;
{
rtx temp;
optab direct_optab = unsignedp ? uoptab : soptab;
struct optab wide_soptab;
temp = expand_binop (mode, direct_optab, op0, op1, target,
unsignedp, OPTAB_DIRECT);
if (temp || methods == OPTAB_DIRECT)
return temp;
wide_soptab = *soptab;
wide_soptab.handlers[(int) mode].insn_code = CODE_FOR_nothing;
wide_soptab.handlers[(int) mode].libfunc = 0;
temp = expand_binop (mode, &wide_soptab, op0, op1, target,
unsignedp, OPTAB_WIDEN);
if (temp == 0 && unsignedp)
temp = expand_binop (mode, uoptab, op0, op1, target,
unsignedp, OPTAB_WIDEN);
if (temp || methods == OPTAB_WIDEN)
return temp;
temp = expand_binop (mode, direct_optab, op0, op1, target, unsignedp, OPTAB_LIB);
if (temp || methods == OPTAB_LIB)
return temp;
temp = expand_binop (mode, &wide_soptab, op0, op1, target,
unsignedp, methods);
if (temp != 0)
return temp;
if (unsignedp)
return expand_binop (mode, uoptab, op0, op1, target,
unsignedp, methods);
return 0;
}
int
expand_twoval_binop (binoptab, op0, op1, targ0, targ1, unsignedp)
optab binoptab;
rtx op0, op1;
rtx targ0, targ1;
int unsignedp;
{
enum machine_mode mode = GET_MODE (targ0 ? targ0 : targ1);
enum mode_class class;
enum machine_mode wider_mode;
rtx entry_last = get_last_insn ();
rtx last;
class = GET_MODE_CLASS (mode);
op0 = protect_from_queue (op0, 0);
op1 = protect_from_queue (op1, 0);
if (flag_force_mem)
{
op0 = force_not_mem (op0);
op1 = force_not_mem (op1);
}
if (CONSTANT_P (op0) && preserve_subexpressions_p ()
&& rtx_cost (op0, binoptab->code) > COSTS_N_INSNS (1))
op0 = force_reg (mode, op0);
if (CONSTANT_P (op1) && preserve_subexpressions_p ()
&& rtx_cost (op1, binoptab->code) > COSTS_N_INSNS (1))
op1 = force_reg (mode, op1);
if (targ0)
targ0 = protect_from_queue (targ0, 1);
else
targ0 = gen_reg_rtx (mode);
if (targ1)
targ1 = protect_from_queue (targ1, 1);
else
targ1 = gen_reg_rtx (mode);
last = get_last_insn ();
if (binoptab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
{
int icode = (int) binoptab->handlers[(int) mode].insn_code;
enum machine_mode mode0 = insn_data[icode].operand[1].mode;
enum machine_mode mode1 = insn_data[icode].operand[2].mode;
rtx pat;
rtx xop0 = op0, xop1 = op1;
if (GET_MODE (op0) != mode0 && mode0 != VOIDmode)
xop0 = convert_modes (mode0,
GET_MODE (op0) != VOIDmode
? GET_MODE (op0)
: mode,
xop0, unsignedp);
if (GET_MODE (op1) != mode1 && mode1 != VOIDmode)
xop1 = convert_modes (mode1,
GET_MODE (op1) != VOIDmode
? GET_MODE (op1)
: mode,
xop1, unsignedp);
if (! (*insn_data[icode].operand[1].predicate) (xop0, mode0))
xop0 = copy_to_mode_reg (mode0, xop0);
if (! (*insn_data[icode].operand[2].predicate) (xop1, mode1))
xop1 = copy_to_mode_reg (mode1, xop1);
if (! (*insn_data[icode].operand[0].predicate) (targ0, mode)
|| ! (*insn_data[icode].operand[3].predicate) (targ1, mode))
abort ();
pat = GEN_FCN (icode) (targ0, xop0, xop1, targ1);
if (pat)
{
emit_insn (pat);
return 1;
}
else
delete_insns_since (last);
}
if (class == MODE_INT || class == MODE_FLOAT || class == MODE_COMPLEX_FLOAT)
{
for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode;
wider_mode = GET_MODE_WIDER_MODE (wider_mode))
{
if (binoptab->handlers[(int) wider_mode].insn_code
!= CODE_FOR_nothing)
{
rtx t0 = gen_reg_rtx (wider_mode);
rtx t1 = gen_reg_rtx (wider_mode);
rtx cop0 = convert_modes (wider_mode, mode, op0, unsignedp);
rtx cop1 = convert_modes (wider_mode, mode, op1, unsignedp);
if (expand_twoval_binop (binoptab, cop0, cop1,
t0, t1, unsignedp))
{
convert_move (targ0, t0, unsignedp);
convert_move (targ1, t1, unsignedp);
return 1;
}
else
delete_insns_since (last);
}
}
}
delete_insns_since (entry_last);
return 0;
}
rtx
expand_simple_unop (mode, code, op0, target, unsignedp)
enum machine_mode mode;
enum rtx_code code;
rtx op0;
rtx target;
int unsignedp;
{
optab unop = code_to_optab[(int) code];
if (unop == 0)
abort ();
return expand_unop (mode, unop, op0, target, unsignedp);
}
rtx
expand_unop (mode, unoptab, op0, target, unsignedp)
enum machine_mode mode;
optab unoptab;
rtx op0;
rtx target;
int unsignedp;
{
enum mode_class class;
enum machine_mode wider_mode;
rtx temp;
rtx last = get_last_insn ();
rtx pat;
class = GET_MODE_CLASS (mode);
op0 = protect_from_queue (op0, 0);
if (flag_force_mem)
{
op0 = force_not_mem (op0);
}
if (target)
target = protect_from_queue (target, 1);
if (unoptab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
{
int icode = (int) unoptab->handlers[(int) mode].insn_code;
enum machine_mode mode0 = insn_data[icode].operand[1].mode;
rtx xop0 = op0;
if (target)
temp = target;
else
temp = gen_reg_rtx (mode);
if (GET_MODE (xop0) != VOIDmode
&& GET_MODE (xop0) != mode0)
xop0 = convert_to_mode (mode0, xop0, unsignedp);
if (! (*insn_data[icode].operand[1].predicate) (xop0, mode0))
xop0 = copy_to_mode_reg (mode0, xop0);
if (! (*insn_data[icode].operand[0].predicate) (temp, mode))
temp = gen_reg_rtx (mode);
pat = GEN_FCN (icode) (temp, xop0);
if (pat)
{
if (INSN_P (pat) && NEXT_INSN (pat) != NULL_RTX
&& ! add_equal_note (pat, temp, unoptab->code, xop0, NULL_RTX))
{
delete_insns_since (last);
return expand_unop (mode, unoptab, op0, NULL_RTX, unsignedp);
}
emit_insn (pat);
return temp;
}
else
delete_insns_since (last);
}
if (class == MODE_INT || class == MODE_FLOAT || class == MODE_COMPLEX_FLOAT)
for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode;
wider_mode = GET_MODE_WIDER_MODE (wider_mode))
{
if (unoptab->handlers[(int) wider_mode].insn_code != CODE_FOR_nothing)
{
rtx xop0 = op0;
xop0 = widen_operand (xop0, wider_mode, mode, unsignedp,
(unoptab == neg_optab
|| unoptab == one_cmpl_optab)
&& class == MODE_INT);
temp = expand_unop (wider_mode, unoptab, xop0, NULL_RTX,
unsignedp);
if (temp)
{
if (class != MODE_INT)
{
if (target == 0)
target = gen_reg_rtx (mode);
convert_move (target, temp, 0);
return target;
}
else
return gen_lowpart (mode, temp);
}
else
delete_insns_since (last);
}
}
if (unoptab == one_cmpl_optab
&& class == MODE_INT
&& GET_MODE_SIZE (mode) > UNITS_PER_WORD
&& unoptab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing)
{
int i;
rtx insns;
if (target == 0 || target == op0)
target = gen_reg_rtx (mode);
start_sequence ();
for (i = 0; i < GET_MODE_BITSIZE (mode) / BITS_PER_WORD; i++)
{
rtx target_piece = operand_subword (target, i, 1, mode);
rtx x = expand_unop (word_mode, unoptab,
operand_subword_force (op0, i, mode),
target_piece, unsignedp);
if (target_piece != x)
emit_move_insn (target_piece, x);
}
insns = get_insns ();
end_sequence ();
emit_no_conflict_block (insns, target, op0, NULL_RTX,
gen_rtx_fmt_e (unoptab->code, mode,
copy_rtx (op0)));
return target;
}
else if (unoptab->code == NEG
&& (class == MODE_COMPLEX_FLOAT || class == MODE_COMPLEX_INT))
{
rtx target_piece;
rtx x;
rtx seq;
enum machine_mode submode = GET_MODE_INNER (mode);
if (submode == BLKmode)
abort ();
if (target == 0)
target = gen_reg_rtx (mode);
start_sequence ();
target_piece = gen_imagpart (submode, target);
x = expand_unop (submode, unoptab,
gen_imagpart (submode, op0),
target_piece, unsignedp);
if (target_piece != x)
emit_move_insn (target_piece, x);
target_piece = gen_realpart (submode, target);
x = expand_unop (submode, unoptab,
gen_realpart (submode, op0),
target_piece, unsignedp);
if (target_piece != x)
emit_move_insn (target_piece, x);
seq = get_insns ();
end_sequence ();
emit_no_conflict_block (seq, target, op0, 0,
gen_rtx_fmt_e (unoptab->code, mode,
copy_rtx (op0)));
return target;
}
if (unoptab->handlers[(int) mode].libfunc)
{
rtx insns;
rtx value;
start_sequence ();
value = emit_library_call_value (unoptab->handlers[(int) mode].libfunc,
NULL_RTX, LCT_CONST, mode, 1, op0, mode);
insns = get_insns ();
end_sequence ();
target = gen_reg_rtx (mode);
emit_libcall_block (insns, target, value,
gen_rtx_fmt_e (unoptab->code, mode, op0));
return target;
}
if (class == MODE_VECTOR_FLOAT || class == MODE_VECTOR_INT)
return expand_vector_unop (mode, unoptab, op0, target, unsignedp);
if (class == MODE_INT || class == MODE_FLOAT || class == MODE_COMPLEX_FLOAT)
{
for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode;
wider_mode = GET_MODE_WIDER_MODE (wider_mode))
{
if ((unoptab->handlers[(int) wider_mode].insn_code
!= CODE_FOR_nothing)
|| unoptab->handlers[(int) wider_mode].libfunc)
{
rtx xop0 = op0;
xop0 = widen_operand (xop0, wider_mode, mode, unsignedp,
(unoptab == neg_optab
|| unoptab == one_cmpl_optab)
&& class == MODE_INT);
temp = expand_unop (wider_mode, unoptab, xop0, NULL_RTX,
unsignedp);
if (temp)
{
if (class != MODE_INT)
{
if (target == 0)
target = gen_reg_rtx (mode);
convert_move (target, temp, 0);
return target;
}
else
return gen_lowpart (mode, temp);
}
else
delete_insns_since (last);
}
}
}
if (unoptab->code == NEG)
{
rtx temp;
temp = expand_binop (mode,
unoptab == negv_optab ? subv_optab : sub_optab,
CONST0_RTX (mode), op0,
target, unsignedp, OPTAB_LIB_WIDEN);
if (temp)
return temp;
}
return 0;
}
rtx
expand_abs (mode, op0, target, result_unsignedp, safe)
enum machine_mode mode;
rtx op0;
rtx target;
int result_unsignedp;
int safe;
{
rtx temp, op1;
if (! flag_trapv)
result_unsignedp = 1;
temp = expand_unop (mode, result_unsignedp ? abs_optab : absv_optab,
op0, target, 0);
if (temp != 0)
return temp;
if (smax_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
{
rtx last = get_last_insn ();
temp = expand_unop (mode, neg_optab, op0, NULL_RTX, 0);
if (temp != 0)
temp = expand_binop (mode, smax_optab, op0, temp, target, 0,
OPTAB_WIDEN);
if (temp != 0)
return temp;
delete_insns_since (last);
}
if (GET_MODE_CLASS (mode) == MODE_INT && BRANCH_COST >= 2)
{
rtx extended = expand_shift (RSHIFT_EXPR, mode, op0,
size_int (GET_MODE_BITSIZE (mode) - 1),
NULL_RTX, 0);
temp = expand_binop (mode, xor_optab, extended, op0, target, 0,
OPTAB_LIB_WIDEN);
if (temp != 0)
temp = expand_binop (mode, result_unsignedp ? sub_optab : subv_optab,
temp, extended, target, 0, OPTAB_LIB_WIDEN);
if (temp != 0)
return temp;
}
if (op0 == target && GET_CODE (op0) == REG
&& REGNO (op0) >= FIRST_PSEUDO_REGISTER)
safe = 1;
op1 = gen_label_rtx ();
if (target == 0 || ! safe
|| GET_MODE (target) != mode
|| (GET_CODE (target) == MEM && MEM_VOLATILE_P (target))
|| (GET_CODE (target) == REG
&& REGNO (target) < FIRST_PSEUDO_REGISTER))
target = gen_reg_rtx (mode);
emit_move_insn (target, op0);
NO_DEFER_POP;
if (GET_MODE_CLASS (mode) == MODE_INT
&& ! can_compare_p (GE, mode, ccp_jump))
do_jump_by_parts_greater_rtx (mode, 0, target, const0_rtx,
NULL_RTX, op1);
else
do_compare_rtx_and_jump (target, CONST0_RTX (mode), GE, 0, mode,
NULL_RTX, NULL_RTX, op1);
op0 = expand_unop (mode, result_unsignedp ? neg_optab : negv_optab,
target, target, 0);
if (op0 != target)
emit_move_insn (target, op0);
emit_label (op1);
OK_DEFER_POP;
return target;
}
rtx
expand_complex_abs (mode, op0, target, unsignedp)
enum machine_mode mode;
rtx op0;
rtx target;
int unsignedp;
{
enum mode_class class = GET_MODE_CLASS (mode);
enum machine_mode wider_mode;
rtx temp;
rtx entry_last = get_last_insn ();
rtx last;
rtx pat;
optab this_abs_optab;
enum machine_mode submode = GET_MODE_INNER (mode);
if (submode == BLKmode)
abort ();
op0 = protect_from_queue (op0, 0);
if (flag_force_mem)
{
op0 = force_not_mem (op0);
}
last = get_last_insn ();
if (target)
target = protect_from_queue (target, 1);
this_abs_optab = ! unsignedp && flag_trapv
&& (GET_MODE_CLASS(mode) == MODE_INT)
? absv_optab : abs_optab;
if (this_abs_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
{
int icode = (int) this_abs_optab->handlers[(int) mode].insn_code;
enum machine_mode mode0 = insn_data[icode].operand[1].mode;
rtx xop0 = op0;
if (target)
temp = target;
else
temp = gen_reg_rtx (submode);
if (GET_MODE (xop0) != VOIDmode
&& GET_MODE (xop0) != mode0)
xop0 = convert_to_mode (mode0, xop0, unsignedp);
if (! (*insn_data[icode].operand[1].predicate) (xop0, mode0))
xop0 = copy_to_mode_reg (mode0, xop0);
if (! (*insn_data[icode].operand[0].predicate) (temp, submode))
temp = gen_reg_rtx (submode);
pat = GEN_FCN (icode) (temp, xop0);
if (pat)
{
if (INSN_P (pat) && NEXT_INSN (pat) != NULL_RTX
&& ! add_equal_note (pat, temp, this_abs_optab->code, xop0,
NULL_RTX))
{
delete_insns_since (last);
return expand_unop (mode, this_abs_optab, op0, NULL_RTX,
unsignedp);
}
emit_insn (pat);
return temp;
}
else
delete_insns_since (last);
}
for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode;
wider_mode = GET_MODE_WIDER_MODE (wider_mode))
{
if (this_abs_optab->handlers[(int) wider_mode].insn_code
!= CODE_FOR_nothing)
{
rtx xop0 = op0;
xop0 = convert_modes (wider_mode, mode, xop0, unsignedp);
temp = expand_complex_abs (wider_mode, xop0, NULL_RTX, unsignedp);
if (temp)
{
if (class != MODE_COMPLEX_INT)
{
if (target == 0)
target = gen_reg_rtx (submode);
convert_move (target, temp, 0);
return target;
}
else
return gen_lowpart (submode, temp);
}
else
delete_insns_since (last);
}
}
if (sqrt_optab->handlers[(int) submode].insn_code != CODE_FOR_nothing
&& ! flag_trapv)
{
rtx real, imag, total;
real = gen_realpart (submode, op0);
imag = gen_imagpart (submode, op0);
real = expand_mult (submode, real, real, NULL_RTX, 0);
imag = expand_mult (submode, imag, imag, NULL_RTX, 0);
total = expand_binop (submode, add_optab, real, imag, NULL_RTX,
0, OPTAB_LIB_WIDEN);
target = expand_unop (submode, sqrt_optab, total, target, 0);
if (target == 0)
delete_insns_since (last);
else
return target;
}
if (this_abs_optab->handlers[(int) mode].libfunc)
{
rtx insns;
rtx value;
start_sequence ();
value = emit_library_call_value (abs_optab->handlers[(int) mode].libfunc,
NULL_RTX, LCT_CONST, submode, 1, op0, mode);
insns = get_insns ();
end_sequence ();
target = gen_reg_rtx (submode);
emit_libcall_block (insns, target, value,
gen_rtx_fmt_e (this_abs_optab->code, mode, op0));
return target;
}
for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode;
wider_mode = GET_MODE_WIDER_MODE (wider_mode))
{
if ((this_abs_optab->handlers[(int) wider_mode].insn_code
!= CODE_FOR_nothing)
|| this_abs_optab->handlers[(int) wider_mode].libfunc)
{
rtx xop0 = op0;
xop0 = convert_modes (wider_mode, mode, xop0, unsignedp);
temp = expand_complex_abs (wider_mode, xop0, NULL_RTX, unsignedp);
if (temp)
{
if (class != MODE_COMPLEX_INT)
{
if (target == 0)
target = gen_reg_rtx (submode);
convert_move (target, temp, 0);
return target;
}
else
return gen_lowpart (submode, temp);
}
else
delete_insns_since (last);
}
}
delete_insns_since (entry_last);
return 0;
}
void
emit_unop_insn (icode, target, op0, code)
int icode;
rtx target;
rtx op0;
enum rtx_code code;
{
rtx temp;
enum machine_mode mode0 = insn_data[icode].operand[1].mode;
rtx pat;
temp = target = protect_from_queue (target, 1);
op0 = protect_from_queue (op0, 0);
if (flag_force_mem && code != SIGN_EXTEND && code != ZERO_EXTEND)
op0 = force_not_mem (op0);
if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
op0 = copy_to_mode_reg (mode0, op0);
if (! (*insn_data[icode].operand[0].predicate) (temp, GET_MODE (temp))
|| (flag_force_mem && GET_CODE (temp) == MEM))
temp = gen_reg_rtx (GET_MODE (temp));
pat = GEN_FCN (icode) (temp, op0);
if (INSN_P (pat) && NEXT_INSN (pat) != NULL_RTX && code != UNKNOWN)
add_equal_note (pat, temp, code, op0, NULL_RTX);
emit_insn (pat);
if (temp != target)
emit_move_insn (target, temp);
}
rtx
emit_no_conflict_block (insns, target, op0, op1, equiv)
rtx insns;
rtx target;
rtx op0, op1;
rtx equiv;
{
rtx prev, next, first, last, insn;
if (GET_CODE (target) != REG || reload_in_progress)
return emit_insn (insns);
else
for (insn = insns; insn; insn = NEXT_INSN (insn))
if (GET_CODE (insn) != INSN
|| find_reg_note (insn, REG_LIBCALL, NULL_RTX))
return emit_insn (insns);
for (insn = insns; insn; insn = next)
{
rtx set = 0, note;
int i;
next = NEXT_INSN (insn);
if ((note = find_reg_note (insn, REG_LIBCALL, NULL)) != NULL)
remove_note (insn, note);
if ((note = find_reg_note (insn, REG_RETVAL, NULL)) != NULL)
remove_note (insn, note);
if (GET_CODE (PATTERN (insn)) == SET || GET_CODE (PATTERN (insn)) == USE
|| GET_CODE (PATTERN (insn)) == CLOBBER)
set = PATTERN (insn);
else if (GET_CODE (PATTERN (insn)) == PARALLEL)
{
for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++)
if (GET_CODE (XVECEXP (PATTERN (insn), 0, i)) == SET)
{
set = XVECEXP (PATTERN (insn), 0, i);
break;
}
}
if (set == 0)
abort ();
if (! reg_overlap_mentioned_p (target, SET_DEST (set)))
{
if (PREV_INSN (insn))
NEXT_INSN (PREV_INSN (insn)) = next;
else
insns = next;
if (next)
PREV_INSN (next) = PREV_INSN (insn);
add_insn (insn);
}
}
prev = get_last_insn ();
if (target != op0 && target != op1)
emit_insn (gen_rtx_CLOBBER (VOIDmode, target));
for (insn = insns; insn; insn = next)
{
next = NEXT_INSN (insn);
add_insn (insn);
if (op1 && GET_CODE (op1) == REG)
REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_NO_CONFLICT, op1,
REG_NOTES (insn));
if (op0 && GET_CODE (op0) == REG)
REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_NO_CONFLICT, op0,
REG_NOTES (insn));
}
if (mov_optab->handlers[(int) GET_MODE (target)].insn_code
!= CODE_FOR_nothing)
{
last = emit_move_insn (target, target);
if (equiv)
set_unique_reg_note (last, REG_EQUAL, equiv);
}
else
{
last = get_last_insn ();
remove_note (last, find_reg_note (last, REG_EQUAL, NULL_RTX));
}
if (prev == 0)
first = get_insns ();
else
first = NEXT_INSN (prev);
REG_NOTES (first) = gen_rtx_INSN_LIST (REG_LIBCALL, last,
REG_NOTES (first));
REG_NOTES (last) = gen_rtx_INSN_LIST (REG_RETVAL, first, REG_NOTES (last));
return last;
}
void
emit_libcall_block (insns, target, result, equiv)
rtx insns;
rtx target;
rtx result;
rtx equiv;
{
rtx final_dest = target;
rtx prev, next, first, last, insn;
if (! REG_P (target) || REG_USERVAR_P (target))
target = gen_reg_rtx (GET_MODE (target));
if (flag_non_call_exceptions && may_trap_p (equiv))
{
for (insn = insns; insn; insn = NEXT_INSN (insn))
if (GET_CODE (insn) == CALL_INSN)
{
rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
if (note != 0 && INTVAL (XEXP (note, 0)) <= 0)
remove_note (insn, note);
}
}
else
for (insn = insns; insn; insn = NEXT_INSN (insn))
if (GET_CODE (insn) == CALL_INSN)
{
rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
if (note != 0)
XEXP (note, 0) = GEN_INT (-1);
else
REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EH_REGION, GEN_INT (-1),
REG_NOTES (insn));
}
for (insn = insns; insn; insn = next)
{
rtx set = single_set (insn);
rtx note;
if ((note = find_reg_note (insn, REG_LIBCALL, NULL)) != NULL)
remove_note (insn, note);
if ((note = find_reg_note (insn, REG_RETVAL, NULL)) != NULL)
remove_note (insn, note);
next = NEXT_INSN (insn);
if (set != 0 && GET_CODE (SET_DEST (set)) == REG
&& REGNO (SET_DEST (set)) >= FIRST_PSEUDO_REGISTER
&& (insn == insns
|| ((! INSN_P(insns)
|| ! reg_mentioned_p (SET_DEST (set), PATTERN (insns)))
&& ! reg_used_between_p (SET_DEST (set), insns, insn)
&& ! modified_in_p (SET_SRC (set), insns)
&& ! modified_between_p (SET_SRC (set), insns, insn))))
{
if (PREV_INSN (insn))
NEXT_INSN (PREV_INSN (insn)) = next;
else
insns = next;
if (next)
PREV_INSN (next) = PREV_INSN (insn);
add_insn (insn);
}
}
prev = get_last_insn ();
for (insn = insns; insn; insn = next)
{
next = NEXT_INSN (insn);
add_insn (insn);
}
last = emit_move_insn (target, result);
if (mov_optab->handlers[(int) GET_MODE (target)].insn_code
!= CODE_FOR_nothing)
set_unique_reg_note (last, REG_EQUAL, copy_rtx (equiv));
else
{
remove_note (last, find_reg_note (last, REG_EQUAL, NULL_RTX));
}
if (final_dest != target)
emit_move_insn (final_dest, target);
if (prev == 0)
first = get_insns ();
else
first = NEXT_INSN (prev);
if (!flag_non_call_exceptions || !may_trap_p (equiv))
{
bool attach_libcall_retval_notes = true;
next = NEXT_INSN (last);
for (insn = first; insn != next; insn = NEXT_INSN (insn))
if (control_flow_insn_p (insn))
{
attach_libcall_retval_notes = false;
break;
}
if (attach_libcall_retval_notes)
{
REG_NOTES (first) = gen_rtx_INSN_LIST (REG_LIBCALL, last,
REG_NOTES (first));
REG_NOTES (last) = gen_rtx_INSN_LIST (REG_RETVAL, first,
REG_NOTES (last));
}
}
}
void
emit_clr_insn (x)
rtx x;
{
emit_move_insn (x, const0_rtx);
}
void
emit_0_to_1_insn (x)
rtx x;
{
emit_move_insn (x, const1_rtx);
}
int
can_compare_p (code, mode, purpose)
enum rtx_code code;
enum machine_mode mode;
enum can_compare_purpose purpose;
{
do
{
if (cmp_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
{
if (purpose == ccp_jump)
return bcc_gen_fctn[(int) code] != NULL;
else if (purpose == ccp_store_flag)
return setcc_gen_code[(int) code] != CODE_FOR_nothing;
else
return 1;
}
if (purpose == ccp_jump
&& cbranch_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
return 1;
if (purpose == ccp_cmov
&& cmov_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
return 1;
if (purpose == ccp_store_flag
&& cstore_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
return 1;
mode = GET_MODE_WIDER_MODE (mode);
}
while (mode != VOIDmode);
return 0;
}
static void
prepare_cmp_insn (px, py, pcomparison, size, pmode, punsignedp, purpose)
rtx *px, *py;
enum rtx_code *pcomparison;
rtx size;
enum machine_mode *pmode;
int *punsignedp;
enum can_compare_purpose purpose;
{
enum machine_mode mode = *pmode;
rtx x = *px, y = *py;
int unsignedp = *punsignedp;
enum mode_class class;
class = GET_MODE_CLASS (mode);
if (mode != BLKmode && flag_force_mem)
{
x = force_not_mem (x);
y = force_not_mem (y);
}
if (CONSTANT_P (x) && preserve_subexpressions_p ()
&& rtx_cost (x, COMPARE) > COSTS_N_INSNS (1))
x = force_reg (mode, x);
if (CONSTANT_P (y) && preserve_subexpressions_p ()
&& rtx_cost (y, COMPARE) > COSTS_N_INSNS (1))
y = force_reg (mode, y);
#ifdef HAVE_cc0
if (CONSTANT_P (x) && ! CONSTANT_P (y))
abort ();
#endif
if (GET_MODE (x) == VOIDmode && GET_MODE (y) == VOIDmode)
x = force_reg (mode, x);
if (mode == BLKmode)
{
rtx result;
enum machine_mode result_mode;
rtx opalign ATTRIBUTE_UNUSED
= GEN_INT (MIN (MEM_ALIGN (x), MEM_ALIGN (y)) / BITS_PER_UNIT);
emit_queue ();
x = protect_from_queue (x, 0);
y = protect_from_queue (y, 0);
if (size == 0)
abort ();
#ifdef HAVE_cmpstrqi
if (HAVE_cmpstrqi
&& GET_CODE (size) == CONST_INT
&& INTVAL (size) < (1 << GET_MODE_BITSIZE (QImode)))
{
result_mode = insn_data[(int) CODE_FOR_cmpstrqi].operand[0].mode;
result = gen_reg_rtx (result_mode);
emit_insn (gen_cmpstrqi (result, x, y, size, opalign));
}
else
#endif
#ifdef HAVE_cmpstrhi
if (HAVE_cmpstrhi
&& GET_CODE (size) == CONST_INT
&& INTVAL (size) < (1 << GET_MODE_BITSIZE (HImode)))
{
result_mode = insn_data[(int) CODE_FOR_cmpstrhi].operand[0].mode;
result = gen_reg_rtx (result_mode);
emit_insn (gen_cmpstrhi (result, x, y, size, opalign));
}
else
#endif
#ifdef HAVE_cmpstrsi
if (HAVE_cmpstrsi)
{
result_mode = insn_data[(int) CODE_FOR_cmpstrsi].operand[0].mode;
result = gen_reg_rtx (result_mode);
size = protect_from_queue (size, 0);
emit_insn (gen_cmpstrsi (result, x, y,
convert_to_mode (SImode, size, 1),
opalign));
}
else
#endif
{
#ifdef TARGET_MEM_FUNCTIONS
result = emit_library_call_value (memcmp_libfunc, NULL_RTX, LCT_PURE_MAKE_BLOCK,
TYPE_MODE (integer_type_node), 3,
XEXP (x, 0), Pmode, XEXP (y, 0), Pmode,
convert_to_mode (TYPE_MODE (sizetype), size,
TREE_UNSIGNED (sizetype)),
TYPE_MODE (sizetype));
#else
result = emit_library_call_value (bcmp_libfunc, NULL_RTX, LCT_PURE_MAKE_BLOCK,
TYPE_MODE (integer_type_node), 3,
XEXP (x, 0), Pmode, XEXP (y, 0), Pmode,
convert_to_mode (TYPE_MODE (integer_type_node),
size,
TREE_UNSIGNED (integer_type_node)),
TYPE_MODE (integer_type_node));
#endif
result_mode = TYPE_MODE (integer_type_node);
}
*px = result;
*py = const0_rtx;
*pmode = result_mode;
return;
}
*px = x;
*py = y;
if (can_compare_p (*pcomparison, mode, purpose))
return;
if (cmp_optab->handlers[(int) mode].libfunc && class != MODE_FLOAT)
{
rtx libfunc = cmp_optab->handlers[(int) mode].libfunc;
rtx result;
if (unsignedp && ucmp_optab->handlers[(int) mode].libfunc)
libfunc = ucmp_optab->handlers[(int) mode].libfunc;
result = emit_library_call_value (libfunc, NULL_RTX, LCT_CONST_MAKE_BLOCK,
word_mode, 2, x, mode, y, mode);
*px = result;
*py = const1_rtx;
*pmode = word_mode;
return;
}
if (class == MODE_FLOAT)
prepare_float_lib_cmp (px, py, pcomparison, pmode, punsignedp);
else
abort ();
}
rtx
prepare_operand (icode, x, opnum, mode, wider_mode, unsignedp)
int icode;
rtx x;
int opnum;
enum machine_mode mode, wider_mode;
int unsignedp;
{
x = protect_from_queue (x, 0);
if (mode != wider_mode)
x = convert_modes (wider_mode, mode, x, unsignedp);
if (! (*insn_data[icode].operand[opnum].predicate)
(x, insn_data[icode].operand[opnum].mode))
x = copy_to_mode_reg (insn_data[icode].operand[opnum].mode, x);
return x;
}
static void
emit_cmp_and_jump_insn_1 (x, y, mode, comparison, unsignedp, label)
rtx x, y;
enum machine_mode mode;
enum rtx_code comparison;
int unsignedp;
rtx label;
{
rtx test = gen_rtx_fmt_ee (comparison, mode, x, y);
enum mode_class class = GET_MODE_CLASS (mode);
enum machine_mode wider_mode = mode;
do
{
enum insn_code icode;
PUT_MODE (test, wider_mode);
if (label)
{
icode = cbranch_optab->handlers[(int) wider_mode].insn_code;
if (icode != CODE_FOR_nothing
&& (*insn_data[icode].operand[0].predicate) (test, wider_mode))
{
x = prepare_operand (icode, x, 1, mode, wider_mode, unsignedp);
y = prepare_operand (icode, y, 2, mode, wider_mode, unsignedp);
emit_jump_insn (GEN_FCN (icode) (test, x, y, label));
return;
}
}
icode = (int) tst_optab->handlers[(int) wider_mode].insn_code;
if (y == CONST0_RTX (mode) && icode != CODE_FOR_nothing)
{
x = prepare_operand (icode, x, 0, mode, wider_mode, unsignedp);
emit_insn (GEN_FCN (icode) (x));
if (label)
emit_jump_insn ((*bcc_gen_fctn[(int) comparison]) (label));
return;
}
icode = (int) cmp_optab->handlers[(int) wider_mode].insn_code;
if (icode != CODE_FOR_nothing)
{
x = prepare_operand (icode, x, 0, mode, wider_mode, unsignedp);
y = prepare_operand (icode, y, 1, mode, wider_mode, unsignedp);
emit_insn (GEN_FCN (icode) (x, y));
if (label)
emit_jump_insn ((*bcc_gen_fctn[(int) comparison]) (label));
return;
}
if (class != MODE_INT && class != MODE_FLOAT
&& class != MODE_COMPLEX_FLOAT)
break;
wider_mode = GET_MODE_WIDER_MODE (wider_mode);
}
while (wider_mode != VOIDmode);
abort ();
}
void
emit_cmp_and_jump_insns (x, y, comparison, size, mode, unsignedp, label)
rtx x, y;
enum rtx_code comparison;
rtx size;
enum machine_mode mode;
int unsignedp;
rtx label;
{
rtx op0 = x, op1 = y;
if (swap_commutative_operands_p (x, y))
{
if (! label)
abort ();
op0 = y, op1 = x;
comparison = swap_condition (comparison);
}
#ifdef HAVE_cc0
if (CONSTANT_P (op0))
op0 = force_reg (mode, op0);
#endif
emit_queue ();
if (unsignedp)
comparison = unsigned_condition (comparison);
prepare_cmp_insn (&op0, &op1, &comparison, size, &mode, &unsignedp,
ccp_jump);
emit_cmp_and_jump_insn_1 (op0, op1, mode, comparison, unsignedp, label);
}
void
emit_cmp_insn (x, y, comparison, size, mode, unsignedp)
rtx x, y;
enum rtx_code comparison;
rtx size;
enum machine_mode mode;
int unsignedp;
{
emit_cmp_and_jump_insns (x, y, comparison, size, mode, unsignedp, 0);
}
static void
prepare_float_lib_cmp (px, py, pcomparison, pmode, punsignedp)
rtx *px, *py;
enum rtx_code *pcomparison;
enum machine_mode *pmode;
int *punsignedp;
{
enum rtx_code comparison = *pcomparison;
rtx tmp;
rtx x = *px = protect_from_queue (*px, 0);
rtx y = *py = protect_from_queue (*py, 0);
enum machine_mode mode = GET_MODE (x);
rtx libfunc = 0;
rtx result;
if (mode == HFmode)
switch (comparison)
{
case EQ:
libfunc = eqhf2_libfunc;
break;
case NE:
libfunc = nehf2_libfunc;
break;
case GT:
libfunc = gthf2_libfunc;
if (libfunc == NULL_RTX)
{
tmp = x; x = y; y = tmp;
*pcomparison = LT;
libfunc = lthf2_libfunc;
}
break;
case GE:
libfunc = gehf2_libfunc;
if (libfunc == NULL_RTX)
{
tmp = x; x = y; y = tmp;
*pcomparison = LE;
libfunc = lehf2_libfunc;
}
break;
case LT:
libfunc = lthf2_libfunc;
if (libfunc == NULL_RTX)
{
tmp = x; x = y; y = tmp;
*pcomparison = GT;
libfunc = gthf2_libfunc;
}
break;
case LE:
libfunc = lehf2_libfunc;
if (libfunc == NULL_RTX)
{
tmp = x; x = y; y = tmp;
*pcomparison = GE;
libfunc = gehf2_libfunc;
}
break;
case UNORDERED:
libfunc = unordhf2_libfunc;
break;
default:
break;
}
else if (mode == SFmode)
switch (comparison)
{
case EQ:
libfunc = eqsf2_libfunc;
break;
case NE:
libfunc = nesf2_libfunc;
break;
case GT:
libfunc = gtsf2_libfunc;
if (libfunc == NULL_RTX)
{
tmp = x; x = y; y = tmp;
*pcomparison = LT;
libfunc = ltsf2_libfunc;
}
break;
case GE:
libfunc = gesf2_libfunc;
if (libfunc == NULL_RTX)
{
tmp = x; x = y; y = tmp;
*pcomparison = LE;
libfunc = lesf2_libfunc;
}
break;
case LT:
libfunc = ltsf2_libfunc;
if (libfunc == NULL_RTX)
{
tmp = x; x = y; y = tmp;
*pcomparison = GT;
libfunc = gtsf2_libfunc;
}
break;
case LE:
libfunc = lesf2_libfunc;
if (libfunc == NULL_RTX)
{
tmp = x; x = y; y = tmp;
*pcomparison = GE;
libfunc = gesf2_libfunc;
}
break;
case UNORDERED:
libfunc = unordsf2_libfunc;
break;
default:
break;
}
else if (mode == DFmode)
switch (comparison)
{
case EQ:
libfunc = eqdf2_libfunc;
break;
case NE:
libfunc = nedf2_libfunc;
break;
case GT:
libfunc = gtdf2_libfunc;
if (libfunc == NULL_RTX)
{
tmp = x; x = y; y = tmp;
*pcomparison = LT;
libfunc = ltdf2_libfunc;
}
break;
case GE:
libfunc = gedf2_libfunc;
if (libfunc == NULL_RTX)
{
tmp = x; x = y; y = tmp;
*pcomparison = LE;
libfunc = ledf2_libfunc;
}
break;
case LT:
libfunc = ltdf2_libfunc;
if (libfunc == NULL_RTX)
{
tmp = x; x = y; y = tmp;
*pcomparison = GT;
libfunc = gtdf2_libfunc;
}
break;
case LE:
libfunc = ledf2_libfunc;
if (libfunc == NULL_RTX)
{
tmp = x; x = y; y = tmp;
*pcomparison = GE;
libfunc = gedf2_libfunc;
}
break;
case UNORDERED:
libfunc = unorddf2_libfunc;
break;
default:
break;
}
else if (mode == XFmode)
switch (comparison)
{
case EQ:
libfunc = eqxf2_libfunc;
break;
case NE:
libfunc = nexf2_libfunc;
break;
case GT:
libfunc = gtxf2_libfunc;
if (libfunc == NULL_RTX)
{
tmp = x; x = y; y = tmp;
*pcomparison = LT;
libfunc = ltxf2_libfunc;
}
break;
case GE:
libfunc = gexf2_libfunc;
if (libfunc == NULL_RTX)
{
tmp = x; x = y; y = tmp;
*pcomparison = LE;
libfunc = lexf2_libfunc;
}
break;
case LT:
libfunc = ltxf2_libfunc;
if (libfunc == NULL_RTX)
{
tmp = x; x = y; y = tmp;
*pcomparison = GT;
libfunc = gtxf2_libfunc;
}
break;
case LE:
libfunc = lexf2_libfunc;
if (libfunc == NULL_RTX)
{
tmp = x; x = y; y = tmp;
*pcomparison = GE;
libfunc = gexf2_libfunc;
}
break;
case UNORDERED:
libfunc = unordxf2_libfunc;
break;
default:
break;
}
else if (mode == TFmode)
switch (comparison)
{
case EQ:
libfunc = eqtf2_libfunc;
break;
case NE:
libfunc = netf2_libfunc;
break;
case GT:
libfunc = gttf2_libfunc;
if (libfunc == NULL_RTX)
{
tmp = x; x = y; y = tmp;
*pcomparison = LT;
libfunc = lttf2_libfunc;
}
break;
case GE:
libfunc = getf2_libfunc;
if (libfunc == NULL_RTX)
{
tmp = x; x = y; y = tmp;
*pcomparison = LE;
libfunc = letf2_libfunc;
}
break;
case LT:
libfunc = lttf2_libfunc;
if (libfunc == NULL_RTX)
{
tmp = x; x = y; y = tmp;
*pcomparison = GT;
libfunc = gttf2_libfunc;
}
break;
case LE:
libfunc = letf2_libfunc;
if (libfunc == NULL_RTX)
{
tmp = x; x = y; y = tmp;
*pcomparison = GE;
libfunc = getf2_libfunc;
}
break;
case UNORDERED:
libfunc = unordtf2_libfunc;
break;
default:
break;
}
else
{
enum machine_mode wider_mode;
for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode;
wider_mode = GET_MODE_WIDER_MODE (wider_mode))
{
if ((cmp_optab->handlers[(int) wider_mode].insn_code
!= CODE_FOR_nothing)
|| (cmp_optab->handlers[(int) wider_mode].libfunc != 0))
{
x = protect_from_queue (x, 0);
y = protect_from_queue (y, 0);
*px = convert_to_mode (wider_mode, x, 0);
*py = convert_to_mode (wider_mode, y, 0);
prepare_float_lib_cmp (px, py, pcomparison, pmode, punsignedp);
return;
}
}
abort ();
}
if (libfunc == 0)
abort ();
result = emit_library_call_value (libfunc, NULL_RTX, LCT_CONST_MAKE_BLOCK,
word_mode, 2, x, mode, y, mode);
*px = result;
*py = const0_rtx;
*pmode = word_mode;
if (comparison == UNORDERED)
*pcomparison = NE;
#ifdef FLOAT_LIB_COMPARE_RETURNS_BOOL
else if (FLOAT_LIB_COMPARE_RETURNS_BOOL (mode, comparison))
*pcomparison = NE;
#endif
*punsignedp = 0;
}
void
emit_indirect_jump (loc)
rtx loc;
{
if (! ((*insn_data[(int) CODE_FOR_indirect_jump].operand[0].predicate)
(loc, Pmode)))
loc = copy_to_mode_reg (Pmode, loc);
emit_jump_insn (gen_indirect_jump (loc));
emit_barrier ();
}
#ifdef HAVE_conditional_move
rtx
emit_conditional_move (target, code, op0, op1, cmode, op2, op3, mode,
unsignedp)
rtx target;
enum rtx_code code;
rtx op0, op1;
enum machine_mode cmode;
rtx op2, op3;
enum machine_mode mode;
int unsignedp;
{
rtx tem, subtarget, comparison, insn;
enum insn_code icode;
enum rtx_code reversed;
if (swap_commutative_operands_p (op0, op1))
{
tem = op0;
op0 = op1;
op1 = tem;
code = swap_condition (code);
}
if (code == LT && GET_CODE (op1) == CONST_INT && INTVAL (op1) == 1)
code = LE, op1 = const0_rtx;
else if (code == GT && GET_CODE (op1) == CONST_INT && INTVAL (op1) == -1)
code = GE, op1 = const0_rtx;
if (cmode == VOIDmode)
cmode = GET_MODE (op0);
if (swap_commutative_operands_p (op2, op3)
&& ((reversed = reversed_comparison_code_parts (code, op0, op1, NULL))
!= UNKNOWN))
{
tem = op2;
op2 = op3;
op3 = tem;
code = reversed;
}
if (mode == VOIDmode)
mode = GET_MODE (op2);
icode = movcc_gen_code[mode];
if (icode == CODE_FOR_nothing)
return 0;
if (flag_force_mem)
{
op2 = force_not_mem (op2);
op3 = force_not_mem (op3);
}
if (target)
target = protect_from_queue (target, 1);
else
target = gen_reg_rtx (mode);
subtarget = target;
emit_queue ();
op2 = protect_from_queue (op2, 0);
op3 = protect_from_queue (op3, 0);
if (! (*insn_data[icode].operand[0].predicate)
(subtarget, insn_data[icode].operand[0].mode))
subtarget = gen_reg_rtx (insn_data[icode].operand[0].mode);
if (! (*insn_data[icode].operand[2].predicate)
(op2, insn_data[icode].operand[2].mode))
op2 = copy_to_mode_reg (insn_data[icode].operand[2].mode, op2);
if (! (*insn_data[icode].operand[3].predicate)
(op3, insn_data[icode].operand[3].mode))
op3 = copy_to_mode_reg (insn_data[icode].operand[3].mode, op3);
comparison
= compare_from_rtx (op0, op1, code, unsignedp, cmode, NULL_RTX);
if (GET_CODE (comparison) != code)
return NULL_RTX;
insn = GEN_FCN (icode) (subtarget, comparison, op2, op3);
if (insn == 0)
return 0;
emit_insn (insn);
if (subtarget != target)
convert_move (target, subtarget, 0);
return target;
}
int
can_conditionally_move_p (mode)
enum machine_mode mode;
{
if (movcc_gen_code[mode] != CODE_FOR_nothing)
return 1;
return 0;
}
#endif
rtx
gen_add2_insn (x, y)
rtx x, y;
{
int icode = (int) add_optab->handlers[(int) GET_MODE (x)].insn_code;
if (! ((*insn_data[icode].operand[0].predicate)
(x, insn_data[icode].operand[0].mode))
|| ! ((*insn_data[icode].operand[1].predicate)
(x, insn_data[icode].operand[1].mode))
|| ! ((*insn_data[icode].operand[2].predicate)
(y, insn_data[icode].operand[2].mode)))
abort ();
return (GEN_FCN (icode) (x, x, y));
}
rtx
gen_add3_insn (r0, r1, c)
rtx r0, r1, c;
{
int icode = (int) add_optab->handlers[(int) GET_MODE (r0)].insn_code;
if (icode == CODE_FOR_nothing
|| ! ((*insn_data[icode].operand[0].predicate)
(r0, insn_data[icode].operand[0].mode))
|| ! ((*insn_data[icode].operand[1].predicate)
(r1, insn_data[icode].operand[1].mode))
|| ! ((*insn_data[icode].operand[2].predicate)
(c, insn_data[icode].operand[2].mode)))
return NULL_RTX;
return (GEN_FCN (icode) (r0, r1, c));
}
int
have_add2_insn (x, y)
rtx x, y;
{
int icode;
if (GET_MODE (x) == VOIDmode)
abort ();
icode = (int) add_optab->handlers[(int) GET_MODE (x)].insn_code;
if (icode == CODE_FOR_nothing)
return 0;
if (! ((*insn_data[icode].operand[0].predicate)
(x, insn_data[icode].operand[0].mode))
|| ! ((*insn_data[icode].operand[1].predicate)
(x, insn_data[icode].operand[1].mode))
|| ! ((*insn_data[icode].operand[2].predicate)
(y, insn_data[icode].operand[2].mode)))
return 0;
return 1;
}
rtx
gen_sub2_insn (x, y)
rtx x, y;
{
int icode = (int) sub_optab->handlers[(int) GET_MODE (x)].insn_code;
if (! ((*insn_data[icode].operand[0].predicate)
(x, insn_data[icode].operand[0].mode))
|| ! ((*insn_data[icode].operand[1].predicate)
(x, insn_data[icode].operand[1].mode))
|| ! ((*insn_data[icode].operand[2].predicate)
(y, insn_data[icode].operand[2].mode)))
abort ();
return (GEN_FCN (icode) (x, x, y));
}
rtx
gen_sub3_insn (r0, r1, c)
rtx r0, r1, c;
{
int icode = (int) sub_optab->handlers[(int) GET_MODE (r0)].insn_code;
if (icode == CODE_FOR_nothing
|| ! ((*insn_data[icode].operand[0].predicate)
(r0, insn_data[icode].operand[0].mode))
|| ! ((*insn_data[icode].operand[1].predicate)
(r1, insn_data[icode].operand[1].mode))
|| ! ((*insn_data[icode].operand[2].predicate)
(c, insn_data[icode].operand[2].mode)))
return NULL_RTX;
return (GEN_FCN (icode) (r0, r1, c));
}
int
have_sub2_insn (x, y)
rtx x, y;
{
int icode;
if (GET_MODE (x) == VOIDmode)
abort ();
icode = (int) sub_optab->handlers[(int) GET_MODE (x)].insn_code;
if (icode == CODE_FOR_nothing)
return 0;
if (! ((*insn_data[icode].operand[0].predicate)
(x, insn_data[icode].operand[0].mode))
|| ! ((*insn_data[icode].operand[1].predicate)
(x, insn_data[icode].operand[1].mode))
|| ! ((*insn_data[icode].operand[2].predicate)
(y, insn_data[icode].operand[2].mode)))
return 0;
return 1;
}
rtx
gen_move_insn (x, y)
rtx x, y;
{
enum machine_mode mode = GET_MODE (x);
enum insn_code insn_code;
rtx seq;
if (mode == VOIDmode)
mode = GET_MODE (y);
insn_code = mov_optab->handlers[(int) mode].insn_code;
if (GET_MODE_CLASS (mode) == MODE_CC && insn_code == CODE_FOR_nothing)
{
enum machine_mode tmode = VOIDmode;
rtx x1 = x, y1 = y;
if (mode != CCmode
&& mov_optab->handlers[(int) CCmode].insn_code != CODE_FOR_nothing)
tmode = CCmode;
else
for (tmode = QImode; tmode != VOIDmode;
tmode = GET_MODE_WIDER_MODE (tmode))
if (GET_MODE_SIZE (tmode) == GET_MODE_SIZE (mode))
break;
if (tmode == VOIDmode)
abort ();
if (reload_in_progress)
{
x = gen_lowpart_common (tmode, x1);
if (x == 0 && GET_CODE (x1) == MEM)
{
x = adjust_address_nv (x1, tmode, 0);
copy_replacements (x1, x);
}
y = gen_lowpart_common (tmode, y1);
if (y == 0 && GET_CODE (y1) == MEM)
{
y = adjust_address_nv (y1, tmode, 0);
copy_replacements (y1, y);
}
}
else
{
x = gen_lowpart (tmode, x);
y = gen_lowpart (tmode, y);
}
insn_code = mov_optab->handlers[(int) tmode].insn_code;
return (GEN_FCN (insn_code) (x, y));
}
start_sequence ();
emit_move_insn_1 (x, y);
seq = get_insns ();
end_sequence ();
return seq;
}
enum insn_code
can_extend_p (to_mode, from_mode, unsignedp)
enum machine_mode to_mode, from_mode;
int unsignedp;
{
#ifdef HAVE_ptr_extend
if (unsignedp < 0)
return CODE_FOR_ptr_extend;
else
#endif
return extendtab[(int) to_mode][(int) from_mode][unsignedp != 0];
}
rtx
gen_extend_insn (x, y, mto, mfrom, unsignedp)
rtx x, y;
enum machine_mode mto, mfrom;
int unsignedp;
{
return (GEN_FCN (extendtab[(int) mto][(int) mfrom][unsignedp != 0]) (x, y));
}
static enum insn_code
can_fix_p (fixmode, fltmode, unsignedp, truncp_ptr)
enum machine_mode fltmode, fixmode;
int unsignedp;
int *truncp_ptr;
{
*truncp_ptr = 0;
if (fixtrunctab[(int) fltmode][(int) fixmode][unsignedp != 0]
!= CODE_FOR_nothing)
return fixtrunctab[(int) fltmode][(int) fixmode][unsignedp != 0];
if (ftrunc_optab->handlers[(int) fltmode].insn_code != CODE_FOR_nothing)
{
*truncp_ptr = 1;
return fixtab[(int) fltmode][(int) fixmode][unsignedp != 0];
}
return CODE_FOR_nothing;
}
static enum insn_code
can_float_p (fltmode, fixmode, unsignedp)
enum machine_mode fixmode, fltmode;
int unsignedp;
{
return floattab[(int) fltmode][(int) fixmode][unsignedp != 0];
}
void
expand_float (to, from, unsignedp)
rtx to, from;
int unsignedp;
{
enum insn_code icode;
rtx target = to;
enum machine_mode fmode, imode;
if (GET_MODE (from) == VOIDmode)
abort ();
for (fmode = GET_MODE (to); fmode != VOIDmode;
fmode = GET_MODE_WIDER_MODE (fmode))
for (imode = GET_MODE (from); imode != VOIDmode;
imode = GET_MODE_WIDER_MODE (imode))
{
int doing_unsigned = unsignedp;
if (fmode != GET_MODE (to)
&& significand_size (fmode) < GET_MODE_BITSIZE (GET_MODE (from)))
continue;
icode = can_float_p (fmode, imode, unsignedp);
if (icode == CODE_FOR_nothing && imode != GET_MODE (from) && unsignedp)
icode = can_float_p (fmode, imode, 0), doing_unsigned = 0;
if (icode != CODE_FOR_nothing)
{
to = protect_from_queue (to, 1);
from = protect_from_queue (from, 0);
if (imode != GET_MODE (from))
from = convert_to_mode (imode, from, unsignedp);
if (fmode != GET_MODE (to))
target = gen_reg_rtx (fmode);
emit_unop_insn (icode, target, from,
doing_unsigned ? UNSIGNED_FLOAT : FLOAT);
if (target != to)
convert_move (to, target, 0);
return;
}
}
if (unsignedp)
{
rtx label = gen_label_rtx ();
rtx temp;
REAL_VALUE_TYPE offset;
emit_queue ();
to = protect_from_queue (to, 1);
from = protect_from_queue (from, 0);
if (flag_force_mem)
from = force_not_mem (from);
for (fmode = GET_MODE (to); fmode != VOIDmode;
fmode = GET_MODE_WIDER_MODE (fmode))
if (GET_MODE_BITSIZE (GET_MODE (from)) < GET_MODE_BITSIZE (fmode)
&& can_float_p (fmode, GET_MODE (from), 0) != CODE_FOR_nothing)
break;
if (fmode == VOIDmode)
{
fmode = GET_MODE (to);
if ((significand_size (fmode) + 1)
< GET_MODE_BITSIZE (GET_MODE (from)))
{
rtx temp1;
rtx neglabel = gen_label_rtx ();
if (GET_CODE (target) != REG
|| REGNO (target) < FIRST_PSEUDO_REGISTER
|| GET_MODE (target) != fmode)
target = gen_reg_rtx (fmode);
imode = GET_MODE (from);
do_pending_stack_adjust ();
emit_cmp_and_jump_insns (from, const0_rtx, LT, NULL_RTX, imode,
0, neglabel);
expand_float (target, from, 0);
emit_jump_insn (gen_jump (label));
emit_barrier ();
emit_label (neglabel);
temp = expand_binop (imode, and_optab, from, const1_rtx,
NULL_RTX, 1, OPTAB_LIB_WIDEN);
temp1 = expand_shift (RSHIFT_EXPR, imode, from, integer_one_node,
NULL_RTX, 1);
temp = expand_binop (imode, ior_optab, temp, temp1, temp, 1,
OPTAB_LIB_WIDEN);
expand_float (target, temp, 0);
temp = expand_binop (fmode, add_optab, target, target,
target, 0, OPTAB_LIB_WIDEN);
if (temp != target)
emit_move_insn (target, temp);
do_pending_stack_adjust ();
emit_label (label);
goto done;
}
}
if (GET_MODE (to) != fmode
|| GET_CODE (to) != REG || REGNO (to) < FIRST_PSEUDO_REGISTER)
target = gen_reg_rtx (fmode);
expand_float (target, from, 0);
do_pending_stack_adjust ();
emit_cmp_and_jump_insns (from, const0_rtx, GE, NULL_RTX, GET_MODE (from),
0, label);
real_2expN (&offset, GET_MODE_BITSIZE (GET_MODE (from)));
temp = expand_binop (fmode, add_optab, target,
CONST_DOUBLE_FROM_REAL_VALUE (offset, fmode),
target, 0, OPTAB_LIB_WIDEN);
if (temp != target)
emit_move_insn (target, temp);
do_pending_stack_adjust ();
emit_label (label);
goto done;
}
{
rtx libfcn;
rtx insns;
rtx value;
to = protect_from_queue (to, 1);
from = protect_from_queue (from, 0);
if (GET_MODE_SIZE (GET_MODE (from)) < GET_MODE_SIZE (SImode))
from = convert_to_mode (SImode, from, unsignedp);
if (flag_force_mem)
from = force_not_mem (from);
if (GET_MODE (to) == SFmode)
{
if (GET_MODE (from) == SImode)
libfcn = floatsisf_libfunc;
else if (GET_MODE (from) == DImode)
libfcn = floatdisf_libfunc;
else if (GET_MODE (from) == TImode)
libfcn = floattisf_libfunc;
else
abort ();
}
else if (GET_MODE (to) == DFmode)
{
if (GET_MODE (from) == SImode)
libfcn = floatsidf_libfunc;
else if (GET_MODE (from) == DImode)
libfcn = floatdidf_libfunc;
else if (GET_MODE (from) == TImode)
libfcn = floattidf_libfunc;
else
abort ();
}
else if (GET_MODE (to) == XFmode)
{
if (GET_MODE (from) == SImode)
libfcn = floatsixf_libfunc;
else if (GET_MODE (from) == DImode)
libfcn = floatdixf_libfunc;
else if (GET_MODE (from) == TImode)
libfcn = floattixf_libfunc;
else
abort ();
}
else if (GET_MODE (to) == TFmode)
{
if (GET_MODE (from) == SImode)
libfcn = floatsitf_libfunc;
else if (GET_MODE (from) == DImode)
libfcn = floatditf_libfunc;
else if (GET_MODE (from) == TImode)
libfcn = floattitf_libfunc;
else
abort ();
}
else
abort ();
start_sequence ();
value = emit_library_call_value (libfcn, NULL_RTX, LCT_CONST,
GET_MODE (to), 1, from,
GET_MODE (from));
insns = get_insns ();
end_sequence ();
emit_libcall_block (insns, target, value,
gen_rtx_FLOAT (GET_MODE (to), from));
}
done:
if (target != to)
{
if (GET_MODE (target) == GET_MODE (to))
emit_move_insn (to, target);
else
convert_move (to, target, 0);
}
}
static rtx
ftruncify (x)
rtx x;
{
rtx temp = gen_reg_rtx (GET_MODE (x));
return expand_unop (GET_MODE (x), ftrunc_optab, x, temp, 0);
}
void
expand_fix (to, from, unsignedp)
rtx to, from;
int unsignedp;
{
enum insn_code icode;
rtx target = to;
enum machine_mode fmode, imode;
int must_trunc = 0;
rtx libfcn = 0;
for (fmode = GET_MODE (from); fmode != VOIDmode;
fmode = GET_MODE_WIDER_MODE (fmode))
for (imode = GET_MODE (to); imode != VOIDmode;
imode = GET_MODE_WIDER_MODE (imode))
{
int doing_unsigned = unsignedp;
icode = can_fix_p (imode, fmode, unsignedp, &must_trunc);
if (icode == CODE_FOR_nothing && imode != GET_MODE (to) && unsignedp)
icode = can_fix_p (imode, fmode, 0, &must_trunc), doing_unsigned = 0;
if (icode != CODE_FOR_nothing)
{
to = protect_from_queue (to, 1);
from = protect_from_queue (from, 0);
if (fmode != GET_MODE (from))
from = convert_to_mode (fmode, from, 0);
if (must_trunc)
from = ftruncify (from);
if (imode != GET_MODE (to))
target = gen_reg_rtx (imode);
emit_unop_insn (icode, target, from,
doing_unsigned ? UNSIGNED_FIX : FIX);
if (target != to)
convert_move (to, target, unsignedp);
return;
}
}
if (unsignedp && GET_MODE_BITSIZE (GET_MODE (to)) <= HOST_BITS_PER_WIDE_INT)
for (fmode = GET_MODE (from); fmode != VOIDmode;
fmode = GET_MODE_WIDER_MODE (fmode))
if (GET_MODE_BITSIZE (fmode) > GET_MODE_BITSIZE (GET_MODE (to))
&& CODE_FOR_nothing != can_fix_p (GET_MODE (to), fmode, 0,
&must_trunc))
{
int bitsize;
REAL_VALUE_TYPE offset;
rtx limit, lab1, lab2, insn;
bitsize = GET_MODE_BITSIZE (GET_MODE (to));
real_2expN (&offset, bitsize - 1);
limit = CONST_DOUBLE_FROM_REAL_VALUE (offset, fmode);
lab1 = gen_label_rtx ();
lab2 = gen_label_rtx ();
emit_queue ();
to = protect_from_queue (to, 1);
from = protect_from_queue (from, 0);
if (flag_force_mem)
from = force_not_mem (from);
if (fmode != GET_MODE (from))
from = convert_to_mode (fmode, from, 0);
do_pending_stack_adjust ();
emit_cmp_and_jump_insns (from, limit, GE, NULL_RTX, GET_MODE (from),
0, lab1);
expand_fix (to, from, 0);
emit_jump_insn (gen_jump (lab2));
emit_barrier ();
emit_label (lab1);
target = expand_binop (GET_MODE (from), sub_optab, from, limit,
NULL_RTX, 0, OPTAB_LIB_WIDEN);
expand_fix (to, target, 0);
target = expand_binop (GET_MODE (to), xor_optab, to,
gen_int_mode
((HOST_WIDE_INT) 1 << (bitsize - 1),
GET_MODE (to)),
to, 1, OPTAB_LIB_WIDEN);
if (target != to)
emit_move_insn (to, target);
emit_label (lab2);
if (mov_optab->handlers[(int) GET_MODE (to)].insn_code
!= CODE_FOR_nothing)
{
insn = emit_move_insn (to, to);
set_unique_reg_note (insn,
REG_EQUAL,
gen_rtx_fmt_e (UNSIGNED_FIX,
GET_MODE (to),
copy_rtx (from)));
}
return;
}
if (GET_MODE_SIZE (GET_MODE (to)) < GET_MODE_SIZE (SImode))
{
target = gen_reg_rtx (SImode);
expand_fix (target, from, unsignedp);
}
else if (GET_MODE (from) == SFmode)
{
if (GET_MODE (to) == SImode)
libfcn = unsignedp ? fixunssfsi_libfunc : fixsfsi_libfunc;
else if (GET_MODE (to) == DImode)
libfcn = unsignedp ? fixunssfdi_libfunc : fixsfdi_libfunc;
else if (GET_MODE (to) == TImode)
libfcn = unsignedp ? fixunssfti_libfunc : fixsfti_libfunc;
else
abort ();
}
else if (GET_MODE (from) == DFmode)
{
if (GET_MODE (to) == SImode)
libfcn = unsignedp ? fixunsdfsi_libfunc : fixdfsi_libfunc;
else if (GET_MODE (to) == DImode)
libfcn = unsignedp ? fixunsdfdi_libfunc : fixdfdi_libfunc;
else if (GET_MODE (to) == TImode)
libfcn = unsignedp ? fixunsdfti_libfunc : fixdfti_libfunc;
else
abort ();
}
else if (GET_MODE (from) == XFmode)
{
if (GET_MODE (to) == SImode)
libfcn = unsignedp ? fixunsxfsi_libfunc : fixxfsi_libfunc;
else if (GET_MODE (to) == DImode)
libfcn = unsignedp ? fixunsxfdi_libfunc : fixxfdi_libfunc;
else if (GET_MODE (to) == TImode)
libfcn = unsignedp ? fixunsxfti_libfunc : fixxfti_libfunc;
else
abort ();
}
else if (GET_MODE (from) == TFmode)
{
if (GET_MODE (to) == SImode)
libfcn = unsignedp ? fixunstfsi_libfunc : fixtfsi_libfunc;
else if (GET_MODE (to) == DImode)
libfcn = unsignedp ? fixunstfdi_libfunc : fixtfdi_libfunc;
else if (GET_MODE (to) == TImode)
libfcn = unsignedp ? fixunstfti_libfunc : fixtfti_libfunc;
else
abort ();
}
else
abort ();
if (libfcn)
{
rtx insns;
rtx value;
to = protect_from_queue (to, 1);
from = protect_from_queue (from, 0);
if (flag_force_mem)
from = force_not_mem (from);
start_sequence ();
value = emit_library_call_value (libfcn, NULL_RTX, LCT_CONST,
GET_MODE (to), 1, from,
GET_MODE (from));
insns = get_insns ();
end_sequence ();
emit_libcall_block (insns, target, value,
gen_rtx_fmt_e (unsignedp ? UNSIGNED_FIX : FIX,
GET_MODE (to), from));
}
if (target != to)
{
if (GET_MODE (to) == GET_MODE (target))
emit_move_insn (to, target);
else
convert_move (to, target, 0);
}
}
int
have_insn_for (code, mode)
enum rtx_code code;
enum machine_mode mode;
{
return (code_to_optab[(int) code] != 0
&& (code_to_optab[(int) code]->handlers[(int) mode].insn_code
!= CODE_FOR_nothing));
}
static optab
new_optab ()
{
int i;
optab op = (optab) ggc_alloc (sizeof (struct optab));
for (i = 0; i < NUM_MACHINE_MODES; i++)
{
op->handlers[i].insn_code = CODE_FOR_nothing;
op->handlers[i].libfunc = 0;
}
return op;
}
static inline optab
init_optab (code)
enum rtx_code code;
{
optab op = new_optab ();
op->code = code;
code_to_optab[(int) code] = op;
return op;
}
static inline optab
init_optabv (code)
enum rtx_code code;
{
optab op = new_optab ();
op->code = code;
return op;
}
static void
init_libfuncs (optable, first_mode, last_mode, opname, suffix)
optab optable;
int first_mode;
int last_mode;
const char *opname;
int suffix;
{
int mode;
unsigned opname_len = strlen (opname);
for (mode = first_mode; (int) mode <= (int) last_mode;
mode = (enum machine_mode) ((int) mode + 1))
{
const char *mname = GET_MODE_NAME (mode);
unsigned mname_len = strlen (mname);
char *libfunc_name = alloca (2 + opname_len + mname_len + 1 + 1);
char *p;
const char *q;
p = libfunc_name;
*p++ = '_';
*p++ = '_';
for (q = opname; *q; )
*p++ = *q++;
for (q = mname; *q; q++)
*p++ = TOLOWER (*q);
*p++ = suffix;
*p = '\0';
optable->handlers[(int) mode].libfunc
= gen_rtx_SYMBOL_REF (Pmode, ggc_alloc_string (libfunc_name,
p - libfunc_name));
}
}
static void
init_integral_libfuncs (optable, opname, suffix)
optab optable;
const char *opname;
int suffix;
{
init_libfuncs (optable, SImode, TImode, opname, suffix);
}
static void
init_floating_libfuncs (optable, opname, suffix)
optab optable;
const char *opname;
int suffix;
{
init_libfuncs (optable, SFmode, TFmode, opname, suffix);
}
rtx
init_one_libfunc (name)
const char *name;
{
tree decl = build_decl (FUNCTION_DECL, get_identifier (name),
build_function_type (integer_type_node, NULL_TREE));
DECL_ARTIFICIAL (decl) = 1;
DECL_EXTERNAL (decl) = 1;
TREE_PUBLIC (decl) = 1;
return XEXP (DECL_RTL (decl), 0);
}
void
init_optabs ()
{
unsigned int i, j, k;
for (i = 0; i < ARRAY_SIZE (fixtab); i++)
for (j = 0; j < ARRAY_SIZE (fixtab[0]); j++)
for (k = 0; k < ARRAY_SIZE (fixtab[0][0]); k++)
fixtab[i][j][k] = CODE_FOR_nothing;
for (i = 0; i < ARRAY_SIZE (fixtrunctab); i++)
for (j = 0; j < ARRAY_SIZE (fixtrunctab[0]); j++)
for (k = 0; k < ARRAY_SIZE (fixtrunctab[0][0]); k++)
fixtrunctab[i][j][k] = CODE_FOR_nothing;
for (i = 0; i < ARRAY_SIZE (floattab); i++)
for (j = 0; j < ARRAY_SIZE (floattab[0]); j++)
for (k = 0; k < ARRAY_SIZE (floattab[0][0]); k++)
floattab[i][j][k] = CODE_FOR_nothing;
for (i = 0; i < ARRAY_SIZE (extendtab); i++)
for (j = 0; j < ARRAY_SIZE (extendtab[0]); j++)
for (k = 0; k < ARRAY_SIZE (extendtab[0][0]); k++)
extendtab[i][j][k] = CODE_FOR_nothing;
for (i = 0; i < NUM_RTX_CODE; i++)
setcc_gen_code[i] = CODE_FOR_nothing;
#ifdef HAVE_conditional_move
for (i = 0; i < NUM_MACHINE_MODES; i++)
movcc_gen_code[i] = CODE_FOR_nothing;
#endif
add_optab = init_optab (PLUS);
addv_optab = init_optabv (PLUS);
sub_optab = init_optab (MINUS);
subv_optab = init_optabv (MINUS);
smul_optab = init_optab (MULT);
smulv_optab = init_optabv (MULT);
smul_highpart_optab = init_optab (UNKNOWN);
umul_highpart_optab = init_optab (UNKNOWN);
smul_widen_optab = init_optab (UNKNOWN);
umul_widen_optab = init_optab (UNKNOWN);
sdiv_optab = init_optab (DIV);
sdivv_optab = init_optabv (DIV);
sdivmod_optab = init_optab (UNKNOWN);
udiv_optab = init_optab (UDIV);
udivmod_optab = init_optab (UNKNOWN);
smod_optab = init_optab (MOD);
umod_optab = init_optab (UMOD);
ftrunc_optab = init_optab (UNKNOWN);
and_optab = init_optab (AND);
ior_optab = init_optab (IOR);
xor_optab = init_optab (XOR);
ashl_optab = init_optab (ASHIFT);
ashr_optab = init_optab (ASHIFTRT);
lshr_optab = init_optab (LSHIFTRT);
rotl_optab = init_optab (ROTATE);
rotr_optab = init_optab (ROTATERT);
smin_optab = init_optab (SMIN);
smax_optab = init_optab (SMAX);
umin_optab = init_optab (UMIN);
umax_optab = init_optab (UMAX);
mov_optab = init_optab (SET);
movstrict_optab = init_optab (STRICT_LOW_PART);
cmp_optab = init_optab (COMPARE);
ucmp_optab = init_optab (UNKNOWN);
tst_optab = init_optab (UNKNOWN);
neg_optab = init_optab (NEG);
negv_optab = init_optabv (NEG);
abs_optab = init_optab (ABS);
absv_optab = init_optabv (ABS);
one_cmpl_optab = init_optab (NOT);
ffs_optab = init_optab (FFS);
sqrt_optab = init_optab (SQRT);
sin_optab = init_optab (UNKNOWN);
cos_optab = init_optab (UNKNOWN);
exp_optab = init_optab (UNKNOWN);
log_optab = init_optab (UNKNOWN);
strlen_optab = init_optab (UNKNOWN);
cbranch_optab = init_optab (UNKNOWN);
cmov_optab = init_optab (UNKNOWN);
cstore_optab = init_optab (UNKNOWN);
push_optab = init_optab (UNKNOWN);
for (i = 0; i < NUM_MACHINE_MODES; i++)
{
movstr_optab[i] = CODE_FOR_nothing;
clrstr_optab[i] = CODE_FOR_nothing;
#ifdef HAVE_SECONDARY_RELOADS
reload_in_optab[i] = reload_out_optab[i] = CODE_FOR_nothing;
#endif
}
init_all_optabs ();
#ifdef FIXUNS_TRUNC_LIKE_FIX_TRUNC
for (i = 0; i < NUM_MACHINE_MODES; i++)
for (j = 0; j < NUM_MACHINE_MODES; j++)
fixtrunctab[i][j][1] = fixtrunctab[i][j][0];
#endif
init_integral_libfuncs (add_optab, "add", '3');
init_floating_libfuncs (add_optab, "add", '3');
init_integral_libfuncs (addv_optab, "addv", '3');
init_floating_libfuncs (addv_optab, "add", '3');
init_integral_libfuncs (sub_optab, "sub", '3');
init_floating_libfuncs (sub_optab, "sub", '3');
init_integral_libfuncs (subv_optab, "subv", '3');
init_floating_libfuncs (subv_optab, "sub", '3');
init_integral_libfuncs (smul_optab, "mul", '3');
init_floating_libfuncs (smul_optab, "mul", '3');
init_integral_libfuncs (smulv_optab, "mulv", '3');
init_floating_libfuncs (smulv_optab, "mul", '3');
init_integral_libfuncs (sdiv_optab, "div", '3');
init_floating_libfuncs (sdiv_optab, "div", '3');
init_integral_libfuncs (sdivv_optab, "divv", '3');
init_integral_libfuncs (udiv_optab, "udiv", '3');
init_integral_libfuncs (sdivmod_optab, "divmod", '4');
init_integral_libfuncs (udivmod_optab, "udivmod", '4');
init_integral_libfuncs (smod_optab, "mod", '3');
init_integral_libfuncs (umod_optab, "umod", '3');
init_floating_libfuncs (ftrunc_optab, "ftrunc", '2');
init_integral_libfuncs (and_optab, "and", '3');
init_integral_libfuncs (ior_optab, "ior", '3');
init_integral_libfuncs (xor_optab, "xor", '3');
init_integral_libfuncs (ashl_optab, "ashl", '3');
init_integral_libfuncs (ashr_optab, "ashr", '3');
init_integral_libfuncs (lshr_optab, "lshr", '3');
init_integral_libfuncs (smin_optab, "min", '3');
init_floating_libfuncs (smin_optab, "min", '3');
init_integral_libfuncs (smax_optab, "max", '3');
init_floating_libfuncs (smax_optab, "max", '3');
init_integral_libfuncs (umin_optab, "umin", '3');
init_integral_libfuncs (umax_optab, "umax", '3');
init_integral_libfuncs (neg_optab, "neg", '2');
init_floating_libfuncs (neg_optab, "neg", '2');
init_integral_libfuncs (negv_optab, "negv", '2');
init_floating_libfuncs (negv_optab, "neg", '2');
init_integral_libfuncs (one_cmpl_optab, "one_cmpl", '2');
init_integral_libfuncs (ffs_optab, "ffs", '2');
init_integral_libfuncs (cmp_optab, "cmp", '2');
init_integral_libfuncs (ucmp_optab, "ucmp", '2');
init_floating_libfuncs (cmp_optab, "cmp", '2');
#ifdef MULSI3_LIBCALL
smul_optab->handlers[(int) SImode].libfunc
= init_one_libfunc (MULSI3_LIBCALL);
#endif
#ifdef MULDI3_LIBCALL
smul_optab->handlers[(int) DImode].libfunc
= init_one_libfunc (MULDI3_LIBCALL);
#endif
#ifdef DIVSI3_LIBCALL
sdiv_optab->handlers[(int) SImode].libfunc
= init_one_libfunc (DIVSI3_LIBCALL);
#endif
#ifdef DIVDI3_LIBCALL
sdiv_optab->handlers[(int) DImode].libfunc
= init_one_libfunc (DIVDI3_LIBCALL);
#endif
#ifdef UDIVSI3_LIBCALL
udiv_optab->handlers[(int) SImode].libfunc
= init_one_libfunc (UDIVSI3_LIBCALL);
#endif
#ifdef UDIVDI3_LIBCALL
udiv_optab->handlers[(int) DImode].libfunc
= init_one_libfunc (UDIVDI3_LIBCALL);
#endif
#ifdef MODSI3_LIBCALL
smod_optab->handlers[(int) SImode].libfunc
= init_one_libfunc (MODSI3_LIBCALL);
#endif
#ifdef MODDI3_LIBCALL
smod_optab->handlers[(int) DImode].libfunc
= init_one_libfunc (MODDI3_LIBCALL);
#endif
#ifdef UMODSI3_LIBCALL
umod_optab->handlers[(int) SImode].libfunc
= init_one_libfunc (UMODSI3_LIBCALL);
#endif
#ifdef UMODDI3_LIBCALL
umod_optab->handlers[(int) DImode].libfunc
= init_one_libfunc (UMODDI3_LIBCALL);
#endif
abs_optab->handlers[(int) DCmode].libfunc
= init_one_libfunc ("cabs");
ffs_optab->handlers[(int) mode_for_size (INT_TYPE_SIZE, MODE_INT, 0)].libfunc
= init_one_libfunc ("ffs");
extendsfdf2_libfunc = init_one_libfunc ("__extendsfdf2");
extendsfxf2_libfunc = init_one_libfunc ("__extendsfxf2");
extendsftf2_libfunc = init_one_libfunc ("__extendsftf2");
extenddfxf2_libfunc = init_one_libfunc ("__extenddfxf2");
extenddftf2_libfunc = init_one_libfunc ("__extenddftf2");
truncdfsf2_libfunc = init_one_libfunc ("__truncdfsf2");
truncxfsf2_libfunc = init_one_libfunc ("__truncxfsf2");
trunctfsf2_libfunc = init_one_libfunc ("__trunctfsf2");
truncxfdf2_libfunc = init_one_libfunc ("__truncxfdf2");
trunctfdf2_libfunc = init_one_libfunc ("__trunctfdf2");
abort_libfunc = init_one_libfunc ("abort");
memcpy_libfunc = init_one_libfunc ("memcpy");
memmove_libfunc = init_one_libfunc ("memmove");
bcopy_libfunc = init_one_libfunc ("bcopy");
memcmp_libfunc = init_one_libfunc ("memcmp");
bcmp_libfunc = init_one_libfunc ("__gcc_bcmp");
memset_libfunc = init_one_libfunc ("memset");
bzero_libfunc = init_one_libfunc ("bzero");
unwind_resume_libfunc = init_one_libfunc (USING_SJLJ_EXCEPTIONS
? "_Unwind_SjLj_Resume"
: "_Unwind_Resume");
#ifndef DONT_USE_BUILTIN_SETJMP
setjmp_libfunc = init_one_libfunc ("__builtin_setjmp");
longjmp_libfunc = init_one_libfunc ("__builtin_longjmp");
#else
setjmp_libfunc = init_one_libfunc ("setjmp");
longjmp_libfunc = init_one_libfunc ("longjmp");
#endif
unwind_sjlj_register_libfunc = init_one_libfunc ("_Unwind_SjLj_Register");
unwind_sjlj_unregister_libfunc
= init_one_libfunc ("_Unwind_SjLj_Unregister");
eqhf2_libfunc = init_one_libfunc ("__eqhf2");
nehf2_libfunc = init_one_libfunc ("__nehf2");
gthf2_libfunc = init_one_libfunc ("__gthf2");
gehf2_libfunc = init_one_libfunc ("__gehf2");
lthf2_libfunc = init_one_libfunc ("__lthf2");
lehf2_libfunc = init_one_libfunc ("__lehf2");
unordhf2_libfunc = init_one_libfunc ("__unordhf2");
eqsf2_libfunc = init_one_libfunc ("__eqsf2");
nesf2_libfunc = init_one_libfunc ("__nesf2");
gtsf2_libfunc = init_one_libfunc ("__gtsf2");
gesf2_libfunc = init_one_libfunc ("__gesf2");
ltsf2_libfunc = init_one_libfunc ("__ltsf2");
lesf2_libfunc = init_one_libfunc ("__lesf2");
unordsf2_libfunc = init_one_libfunc ("__unordsf2");
eqdf2_libfunc = init_one_libfunc ("__eqdf2");
nedf2_libfunc = init_one_libfunc ("__nedf2");
gtdf2_libfunc = init_one_libfunc ("__gtdf2");
gedf2_libfunc = init_one_libfunc ("__gedf2");
ltdf2_libfunc = init_one_libfunc ("__ltdf2");
ledf2_libfunc = init_one_libfunc ("__ledf2");
unorddf2_libfunc = init_one_libfunc ("__unorddf2");
eqxf2_libfunc = init_one_libfunc ("__eqxf2");
nexf2_libfunc = init_one_libfunc ("__nexf2");
gtxf2_libfunc = init_one_libfunc ("__gtxf2");
gexf2_libfunc = init_one_libfunc ("__gexf2");
ltxf2_libfunc = init_one_libfunc ("__ltxf2");
lexf2_libfunc = init_one_libfunc ("__lexf2");
unordxf2_libfunc = init_one_libfunc ("__unordxf2");
eqtf2_libfunc = init_one_libfunc ("__eqtf2");
netf2_libfunc = init_one_libfunc ("__netf2");
gttf2_libfunc = init_one_libfunc ("__gttf2");
getf2_libfunc = init_one_libfunc ("__getf2");
lttf2_libfunc = init_one_libfunc ("__lttf2");
letf2_libfunc = init_one_libfunc ("__letf2");
unordtf2_libfunc = init_one_libfunc ("__unordtf2");
floatsisf_libfunc = init_one_libfunc ("__floatsisf");
floatdisf_libfunc = init_one_libfunc ("__floatdisf");
floattisf_libfunc = init_one_libfunc ("__floattisf");
floatsidf_libfunc = init_one_libfunc ("__floatsidf");
floatdidf_libfunc = init_one_libfunc ("__floatdidf");
floattidf_libfunc = init_one_libfunc ("__floattidf");
floatsixf_libfunc = init_one_libfunc ("__floatsixf");
floatdixf_libfunc = init_one_libfunc ("__floatdixf");
floattixf_libfunc = init_one_libfunc ("__floattixf");
floatsitf_libfunc = init_one_libfunc ("__floatsitf");
floatditf_libfunc = init_one_libfunc ("__floatditf");
floattitf_libfunc = init_one_libfunc ("__floattitf");
fixsfsi_libfunc = init_one_libfunc ("__fixsfsi");
fixsfdi_libfunc = init_one_libfunc ("__fixsfdi");
fixsfti_libfunc = init_one_libfunc ("__fixsfti");
fixdfsi_libfunc = init_one_libfunc ("__fixdfsi");
fixdfdi_libfunc = init_one_libfunc ("__fixdfdi");
fixdfti_libfunc = init_one_libfunc ("__fixdfti");
fixxfsi_libfunc = init_one_libfunc ("__fixxfsi");
fixxfdi_libfunc = init_one_libfunc ("__fixxfdi");
fixxfti_libfunc = init_one_libfunc ("__fixxfti");
fixtfsi_libfunc = init_one_libfunc ("__fixtfsi");
fixtfdi_libfunc = init_one_libfunc ("__fixtfdi");
fixtfti_libfunc = init_one_libfunc ("__fixtfti");
fixunssfsi_libfunc = init_one_libfunc ("__fixunssfsi");
fixunssfdi_libfunc = init_one_libfunc ("__fixunssfdi");
fixunssfti_libfunc = init_one_libfunc ("__fixunssfti");
fixunsdfsi_libfunc = init_one_libfunc ("__fixunsdfsi");
fixunsdfdi_libfunc = init_one_libfunc ("__fixunsdfdi");
fixunsdfti_libfunc = init_one_libfunc ("__fixunsdfti");
fixunsxfsi_libfunc = init_one_libfunc ("__fixunsxfsi");
fixunsxfdi_libfunc = init_one_libfunc ("__fixunsxfdi");
fixunsxfti_libfunc = init_one_libfunc ("__fixunsxfti");
fixunstfsi_libfunc = init_one_libfunc ("__fixunstfsi");
fixunstfdi_libfunc = init_one_libfunc ("__fixunstfdi");
fixunstfti_libfunc = init_one_libfunc ("__fixunstfti");
profile_function_entry_libfunc
= init_one_libfunc ("__cyg_profile_func_enter");
profile_function_exit_libfunc
= init_one_libfunc ("__cyg_profile_func_exit");
#ifdef HAVE_conditional_trap
init_traps ();
#endif
#ifdef INIT_TARGET_OPTABS
INIT_TARGET_OPTABS;
#endif
}
static GTY(()) rtx trap_rtx;
#ifdef HAVE_conditional_trap
static void
init_traps ()
{
if (HAVE_conditional_trap)
{
trap_rtx = gen_rtx_fmt_ee (EQ, VOIDmode, NULL_RTX, NULL_RTX);
}
}
#endif
rtx
gen_cond_trap (code, op1, op2, tcode)
enum rtx_code code ATTRIBUTE_UNUSED;
rtx op1, op2 ATTRIBUTE_UNUSED, tcode ATTRIBUTE_UNUSED;
{
enum machine_mode mode = GET_MODE (op1);
if (mode == VOIDmode)
return 0;
#ifdef HAVE_conditional_trap
if (HAVE_conditional_trap
&& cmp_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
{
rtx insn;
start_sequence ();
emit_insn (GEN_FCN (cmp_optab->handlers[(int) mode].insn_code) (op1, op2));
PUT_CODE (trap_rtx, code);
insn = gen_conditional_trap (trap_rtx, tcode);
if (insn)
{
emit_insn (insn);
insn = get_insns ();
}
end_sequence ();
return insn;
}
#endif
return 0;
}
#include "gt-optabs.h"