From b63679d2337246ea2bebf421a802b63ad17ae895 Mon Sep 17 00:00:00 2001 From: rms Date: Wed, 9 Sep 1992 06:38:59 +0000 Subject: [PATCH] (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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@2082 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/expr.c | 295 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 279 insertions(+), 16 deletions(-) diff --git a/gcc/expr.c b/gcc/expr.c index f727956dd12..142dedd2572 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -158,25 +158,26 @@ init_expr_once () /* See if there is some register that can be used in this mode and directly loaded or stored from memory. */ - for (regno = 0; regno < FIRST_PSEUDO_REGISTER - && (direct_load[(int) mode] == 0 || direct_store[(int) mode] == 0); - regno++) - { - if (! HARD_REGNO_MODE_OK (regno, mode)) - continue; + if (mode != VOIDmode && mode != BLKmode) + for (regno = 0; regno < FIRST_PSEUDO_REGISTER + && (direct_load[(int) mode] == 0 || direct_store[(int) mode] == 0); + regno++) + { + if (! HARD_REGNO_MODE_OK (regno, mode)) + continue; - reg = gen_rtx (REG, mode, regno); + reg = gen_rtx (REG, mode, regno); - SET_SRC (pat) = mem; - SET_DEST (pat) = reg; - if (recog (pat, insn, &num_clobbers) >= 0) - direct_load[(int) mode] = 1; + SET_SRC (pat) = mem; + SET_DEST (pat) = reg; + if (recog (pat, insn, &num_clobbers) >= 0) + direct_load[(int) mode] = 1; - SET_SRC (pat) = reg; - SET_DEST (pat) = mem; - if (recog (pat, insn, &num_clobbers) >= 0) - direct_store[(int) mode] = 1; - } + SET_SRC (pat) = reg; + SET_DEST (pat) = mem; + if (recog (pat, insn, &num_clobbers) >= 0) + direct_store[(int) mode] = 1; + } movstr_optab[(int) mode] = CODE_FOR_nothing; } @@ -1320,6 +1321,31 @@ use_regs (regno, nregs) for (i = 0; i < nregs; 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. If OBJECT has BLKmode, SIZE is its length in bytes. */ @@ -1359,6 +1385,8 @@ emit_move_insn (x, y) rtx x, y; { enum machine_mode mode = GET_MODE (x); + enum machine_mode submode; + enum mode_class class = GET_MODE_CLASS (mode); int i; x = protect_from_queue (x, 1); @@ -1388,16 +1416,54 @@ emit_move_insn (x, y) if (mode == BLKmode) 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) return 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. However, you will get better code if you define such patterns, even if they must turn into multiple assembler instructions. */ else if (GET_MODE_SIZE (mode) > UNITS_PER_WORD) { rtx last_insn = 0; + rtx prev_insn = get_last_insn (); for (i = 0; i < (GET_MODE_SIZE (mode) + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD; @@ -1422,6 +1488,9 @@ emit_move_insn (x, y) last_insn = emit_move_insn (xpart, ypart); } + /* Mark these insns as a libcall block. */ + group_insns (prev_insn); + return last_insn; } else @@ -3763,6 +3832,118 @@ expand_expr (exp, target, tmode, modifier) case BUFFER_REF: 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: if (RTL_EXPR_RTL (exp) == 0) { @@ -4841,6 +5022,88 @@ expand_expr (exp, target, tmode, modifier) case ENTRY_VALUE_EXPR: 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: return const0_rtx; -- 2.11.0