Commit 7308a047 by Richard Stallman

(expand_expr): Support IN_EXPR.

(init_expr_once): Don't try HARD_REGNO_MODE_OK on VOIDmode or BLKmode.
(emit_move_insn): When moving word by word,
  mark the whole thing as a libcall block.
(group_insns): New function.
(expand_expr): Implement COMPLEX_EXPR, REALPART_EXPR, IMAGPART_EXPR, CONJ_EXPR.

From-SVN: r2082
parent a11ad2c3
...@@ -158,25 +158,26 @@ init_expr_once () ...@@ -158,25 +158,26 @@ init_expr_once ()
/* See if there is some register that can be used in this mode and /* See if there is some register that can be used in this mode and
directly loaded or stored from memory. */ directly loaded or stored from memory. */
for (regno = 0; regno < FIRST_PSEUDO_REGISTER if (mode != VOIDmode && mode != BLKmode)
&& (direct_load[(int) mode] == 0 || direct_store[(int) mode] == 0); for (regno = 0; regno < FIRST_PSEUDO_REGISTER
regno++) && (direct_load[(int) mode] == 0 || direct_store[(int) mode] == 0);
{ regno++)
if (! HARD_REGNO_MODE_OK (regno, mode)) {
continue; if (! HARD_REGNO_MODE_OK (regno, mode))
continue;
reg = gen_rtx (REG, mode, regno); reg = gen_rtx (REG, mode, regno);
SET_SRC (pat) = mem; SET_SRC (pat) = mem;
SET_DEST (pat) = reg; SET_DEST (pat) = reg;
if (recog (pat, insn, &num_clobbers) >= 0) if (recog (pat, insn, &num_clobbers) >= 0)
direct_load[(int) mode] = 1; direct_load[(int) mode] = 1;
SET_SRC (pat) = reg; SET_SRC (pat) = reg;
SET_DEST (pat) = mem; SET_DEST (pat) = mem;
if (recog (pat, insn, &num_clobbers) >= 0) if (recog (pat, insn, &num_clobbers) >= 0)
direct_store[(int) mode] = 1; direct_store[(int) mode] = 1;
} }
movstr_optab[(int) mode] = CODE_FOR_nothing; movstr_optab[(int) mode] = CODE_FOR_nothing;
} }
...@@ -1320,6 +1321,31 @@ use_regs (regno, nregs) ...@@ -1320,6 +1321,31 @@ use_regs (regno, nregs)
for (i = 0; i < nregs; i++) for (i = 0; i < nregs; i++)
emit_insn (gen_rtx (USE, VOIDmode, gen_rtx (REG, word_mode, regno + i))); emit_insn (gen_rtx (USE, VOIDmode, gen_rtx (REG, word_mode, regno + i)));
} }
/* Mark the instructions since PREV as a libcall block.
Add REG_LIBCALL to PREV and add a REG_RETVAL to the most recent insn. */
static rtx
group_insns (prev)
rtx prev;
{
rtx insn_first;
rtx insn_last;
/* Find the instructions to mark */
if (prev)
insn_first = NEXT_INSN (prev);
else
insn_first = get_insns ();
insn_last = get_last_insn ();
REG_NOTES (insn_last) = gen_rtx (INSN_LIST, REG_RETVAL, insn_first,
REG_NOTES (insn_last));
REG_NOTES (insn_first) = gen_rtx (INSN_LIST, REG_LIBCALL, insn_last,
REG_NOTES (insn_first));
}
/* Write zeros through the storage of OBJECT. /* Write zeros through the storage of OBJECT.
If OBJECT has BLKmode, SIZE is its length in bytes. */ If OBJECT has BLKmode, SIZE is its length in bytes. */
...@@ -1359,6 +1385,8 @@ emit_move_insn (x, y) ...@@ -1359,6 +1385,8 @@ emit_move_insn (x, y)
rtx x, y; rtx x, y;
{ {
enum machine_mode mode = GET_MODE (x); enum machine_mode mode = GET_MODE (x);
enum machine_mode submode;
enum mode_class class = GET_MODE_CLASS (mode);
int i; int i;
x = protect_from_queue (x, 1); x = protect_from_queue (x, 1);
...@@ -1388,16 +1416,54 @@ emit_move_insn (x, y) ...@@ -1388,16 +1416,54 @@ emit_move_insn (x, y)
if (mode == BLKmode) if (mode == BLKmode)
abort (); abort ();
if (class == MODE_COMPLEX_FLOAT || class == MODE_COMPLEX_INT)
submode = mode_for_size (GET_MODE_UNIT_SIZE (mode) * BITS_PER_UNIT,
(class == MODE_COMPLEX_INT
? MODE_INT : MODE_FLOAT),
0);
if (mov_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing) if (mov_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
return return
emit_insn (GEN_FCN (mov_optab->handlers[(int) mode].insn_code) (x, y)); emit_insn (GEN_FCN (mov_optab->handlers[(int) mode].insn_code) (x, y));
/* Expand complex moves by moving real part and imag part, if posible. */
else if ((class == MODE_COMPLEX_FLOAT || class == MODE_COMPLEX_INT)
&& submode != BLKmode
&& (mov_optab->handlers[(int) submode].insn_code
!= CODE_FOR_nothing))
{
/* Don't split destination if it is a stack push. */
int stack = push_operand (x, GET_MODE (x));
rtx prev = get_last_insn ();
/* Tell flow that the whole of the destination is being set. */
if (GET_CODE (x) == REG)
emit_insn (gen_rtx (CLOBBER, VOIDmode, x));
/* If this is a stack, push the highpart first, so it
will be in the argument order.
In that case, change_address is used only to convert
the mode, not to change the address. */
emit_insn (GEN_FCN (mov_optab->handlers[(int) submode].insn_code)
((stack ? change_address (x, submode, (rtx) 0)
: gen_highpart (submode, x)),
gen_highpart (submode, y)));
emit_insn (GEN_FCN (mov_optab->handlers[(int) submode].insn_code)
((stack ? change_address (x, submode, (rtx) 0)
: gen_lowpart (submode, x)),
gen_lowpart (submode, y)));
group_insns (prev);
}
/* This will handle any multi-word mode that lacks a move_insn pattern. /* This will handle any multi-word mode that lacks a move_insn pattern.
However, you will get better code if you define such patterns, However, you will get better code if you define such patterns,
even if they must turn into multiple assembler instructions. */ even if they must turn into multiple assembler instructions. */
else if (GET_MODE_SIZE (mode) > UNITS_PER_WORD) else if (GET_MODE_SIZE (mode) > UNITS_PER_WORD)
{ {
rtx last_insn = 0; rtx last_insn = 0;
rtx prev_insn = get_last_insn ();
for (i = 0; for (i = 0;
i < (GET_MODE_SIZE (mode) + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD; i < (GET_MODE_SIZE (mode) + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD;
...@@ -1422,6 +1488,9 @@ emit_move_insn (x, y) ...@@ -1422,6 +1488,9 @@ emit_move_insn (x, y)
last_insn = emit_move_insn (xpart, ypart); last_insn = emit_move_insn (xpart, ypart);
} }
/* Mark these insns as a libcall block. */
group_insns (prev_insn);
return last_insn; return last_insn;
} }
else else
...@@ -3763,6 +3832,118 @@ expand_expr (exp, target, tmode, modifier) ...@@ -3763,6 +3832,118 @@ expand_expr (exp, target, tmode, modifier)
case BUFFER_REF: case BUFFER_REF:
abort (); abort ();
/* IN_EXPR: Inlined pascal set IN expression.
Algorithm:
rlo = set_low - (set_low%bits_per_word);
the_word = set [ (index - rlo)/bits_per_word ];
bit_index = index % bits_per_word;
bitmask = 1 << bit_index;
return !!(the_word & bitmask); */
case IN_EXPR:
preexpand_calls (exp);
{
tree set = TREE_OPERAND (exp, 0);
tree index = TREE_OPERAND (exp, 1);
tree set_type = TREE_TYPE (set);
tree set_low_bound = TYPE_MIN_VALUE (TYPE_DOMAIN (set_type));
tree set_high_bound = TYPE_MAX_VALUE (TYPE_DOMAIN (set_type));
rtx index_val;
rtx lo_r;
rtx hi_r;
rtx rlow;
rtx diff, quo, rem, addr, bit, result;
rtx setval, setaddr;
enum machine_mode index_mode = TYPE_MODE (TREE_TYPE (index));
if (target == 0)
target = gen_reg_rtx (TYPE_MODE (TREE_TYPE (exp)));
/* If domain is empty, answer is no. */
if (tree_int_cst_lt (set_high_bound, set_low_bound))
return const0_rtx;
index_val = expand_expr (index, 0, VOIDmode, 0);
lo_r = expand_expr (set_low_bound, 0, VOIDmode, 0);
hi_r = expand_expr (set_high_bound, 0, VOIDmode, 0);
setval = expand_expr (set, 0, VOIDmode, 0);
setaddr = XEXP (setval, 0);
/* Compare index against bounds, if they are constant. */
if (GET_CODE (index_val) == CONST_INT
&& GET_CODE (lo_r) == CONST_INT)
{
if (INTVAL (index_val) < INTVAL (lo_r))
return const0_rtx;
}
if (GET_CODE (index_val) == CONST_INT
&& GET_CODE (hi_r) == CONST_INT)
{
if (INTVAL (hi_r) < INTVAL (index_val))
return const0_rtx;
}
/* If we get here, we have to generate the code for both cases
(in range and out of range). */
op0 = gen_label_rtx ();
op1 = gen_label_rtx ();
if (! (GET_CODE (index_val) == CONST_INT
&& GET_CODE (lo_r) == CONST_INT))
{
emit_cmp_insn (index_val, lo_r, LT, 0, GET_MODE (index_val), 0, 0);
emit_jump_insn (gen_blt (op1));
}
if (! (GET_CODE (index_val) == CONST_INT
&& GET_CODE (hi_r) == CONST_INT))
{
emit_cmp_insn (index_val, hi_r, GT, 0, GET_MODE (index_val), 0, 0);
emit_jump_insn (gen_bgt (op1));
}
/* Calculate the element number of bit zero in the first word
of the set. */
if (GET_CODE (lo_r) == CONST_INT)
rlow = gen_rtx (CONST_INT, VOIDmode,
INTVAL (lo_r) & ~ (1 << BITS_PER_UNIT));
else
rlow = expand_binop (index_mode, and_optab,
lo_r, gen_rtx (CONST_INT, VOIDmode,
~ (1 << BITS_PER_UNIT)),
0, 0, OPTAB_LIB_WIDEN);
diff = expand_binop (index_mode, sub_optab,
index_val, rlow, 0, 0, OPTAB_LIB_WIDEN);
quo = expand_divmod (0, TRUNC_DIV_EXPR, index_mode, diff,
gen_rtx (CONST_INT, VOIDmode, BITS_PER_UNIT),
0, 0);
rem = expand_divmod (1, TRUNC_MOD_EXPR, index_mode, index_val,
gen_rtx (CONST_INT, VOIDmode, BITS_PER_UNIT),
0, 0);
addr = memory_address (byte_mode,
expand_binop (index_mode, add_optab,
diff, setaddr));
/* Extract the bit we want to examine */
bit = expand_shift (RSHIFT_EXPR, byte_mode,
gen_rtx (MEM, byte_mode, addr), rem, 0, 1);
result = expand_binop (SImode, and_optab, bit, const1_rtx, target,
1, OPTAB_LIB_WIDEN);
emit_move_insn (target, result);
/* Output the code to handle the out-of-range case. */
emit_jump (op0);
emit_label (op1);
emit_move_insn (target, const0_rtx);
emit_label (op0);
return target;
}
case WITH_CLEANUP_EXPR: case WITH_CLEANUP_EXPR:
if (RTL_EXPR_RTL (exp) == 0) if (RTL_EXPR_RTL (exp) == 0)
{ {
...@@ -4841,6 +5022,88 @@ expand_expr (exp, target, tmode, modifier) ...@@ -4841,6 +5022,88 @@ expand_expr (exp, target, tmode, modifier)
case ENTRY_VALUE_EXPR: case ENTRY_VALUE_EXPR:
abort (); abort ();
/* COMPLEX type for Extended Pascal & Fortran */
case COMPLEX_EXPR:
{
enum machine_mode mode = TYPE_MODE (TREE_TYPE (TREE_TYPE (exp)));
rtx prev;
/* Get the rtx code of the operands. */
op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0);
op1 = expand_expr (TREE_OPERAND (exp, 1), 0, VOIDmode, 0);
if (! target)
target = gen_reg_rtx (TYPE_MODE (TREE_TYPE (exp)));
prev = get_last_insn ();
/* Tell flow that the whole of the destination is being set. */
if (GET_CODE (target) == REG)
emit_insn (gen_rtx (CLOBBER, VOIDmode, target));
/* Move the real (op0) and imaginary (op1) parts to their location. */
emit_move_insn (gen_lowpart (mode, target), op0);
emit_move_insn (gen_highpart (mode, target), op1);
/* Complex construction should appear as a single unit. */
group_insns (prev);
return target;
}
case REALPART_EXPR:
{
enum machine_mode mode = TYPE_MODE (TREE_TYPE (TREE_TYPE (exp)));
op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0);
if (! target)
target = gen_reg_rtx (mode);
emit_move_insn (target, gen_lowpart (mode, op0));
return target;
}
case IMAGPART_EXPR:
{
enum machine_mode mode = TYPE_MODE (TREE_TYPE (TREE_TYPE (exp)));
op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0);
if (! target)
target = gen_reg_rtx (mode);
emit_move_insn (target, gen_highpart (mode, op0));
return target;
}
case CONJ_EXPR:
{
enum machine_mode mode = TYPE_MODE (TREE_TYPE (TREE_TYPE (exp)));
rtx imag_t;
rtx prev;
op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0);
if (! target)
target = gen_reg_rtx (TYPE_MODE (TREE_TYPE (exp)));
prev = get_last_insn ();
/* Tell flow that the whole of the destination is being set. */
if (GET_CODE (target) == REG)
emit_insn (gen_rtx (CLOBBER, VOIDmode, target));
/* Store the realpart and the negated imagpart to target. */
emit_move_insn (gen_lowpart (mode, target), gen_lowpart (mode, op0));
imag_t = gen_highpart (mode, target);
temp = expand_unop (mode, neg_optab,
gen_highpart (mode, op0), imag_t, 0);
if (temp != imag_t)
emit_move_insn (imag_t, temp);
/* Conjugate should appear as a single unit */
group_insns (prev);
return target;
}
case ERROR_MARK: case ERROR_MARK:
return const0_rtx; return const0_rtx;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment