X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fexpr.c;h=84cfe5c23ee230ed15846f39f1cf9034ad4b14a0;hb=272c56872d18507cdfb6b12d0b953a6587c78084;hp=6e35db2f2e015934c0e584abd81e4a7017e5c06d;hpb=8a2caf10dc2cc415e4b494611dad5c8bffb7c9df;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/expr.c b/gcc/expr.c index 6e35db2f2e0..84cfe5c23ee 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -2180,17 +2180,122 @@ copy_blkmode_from_reg (rtx tgtblk, rtx srcreg, tree type) return tgtblk; } +/* Copy BLKmode value SRC into a register of mode MODE. Return the + register if it contains any data, otherwise return null. + + This is used on targets that return BLKmode values in registers. */ + +rtx +copy_blkmode_to_reg (enum machine_mode mode, tree src) +{ + int i, n_regs; + unsigned HOST_WIDE_INT bitpos, xbitpos, padding_correction = 0, bytes; + unsigned int bitsize; + rtx *dst_words, dst, x, src_word = NULL_RTX, dst_word = NULL_RTX; + enum machine_mode dst_mode; + + gcc_assert (TYPE_MODE (TREE_TYPE (src)) == BLKmode); + + x = expand_normal (src); + + bytes = int_size_in_bytes (TREE_TYPE (src)); + if (bytes == 0) + return NULL_RTX; + + /* If the structure doesn't take up a whole number of words, see + whether the register value should be padded on the left or on + the right. Set PADDING_CORRECTION to the number of padding + bits needed on the left side. + + In most ABIs, the structure will be returned at the least end of + the register, which translates to right padding on little-endian + targets and left padding on big-endian targets. The opposite + holds if the structure is returned at the most significant + end of the register. */ + if (bytes % UNITS_PER_WORD != 0 + && (targetm.calls.return_in_msb (TREE_TYPE (src)) + ? !BYTES_BIG_ENDIAN + : BYTES_BIG_ENDIAN)) + padding_correction = (BITS_PER_WORD - ((bytes % UNITS_PER_WORD) + * BITS_PER_UNIT)); + + n_regs = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD; + dst_words = XALLOCAVEC (rtx, n_regs); + bitsize = MIN (TYPE_ALIGN (TREE_TYPE (src)), BITS_PER_WORD); + + /* Copy the structure BITSIZE bits at a time. */ + for (bitpos = 0, xbitpos = padding_correction; + bitpos < bytes * BITS_PER_UNIT; + bitpos += bitsize, xbitpos += bitsize) + { + /* We need a new destination pseudo each time xbitpos is + on a word boundary and when xbitpos == padding_correction + (the first time through). */ + if (xbitpos % BITS_PER_WORD == 0 + || xbitpos == padding_correction) + { + /* Generate an appropriate register. */ + dst_word = gen_reg_rtx (word_mode); + dst_words[xbitpos / BITS_PER_WORD] = dst_word; + + /* Clear the destination before we move anything into it. */ + emit_move_insn (dst_word, CONST0_RTX (word_mode)); + } + + /* We need a new source operand each time bitpos is on a word + boundary. */ + if (bitpos % BITS_PER_WORD == 0) + src_word = operand_subword_force (x, bitpos / BITS_PER_WORD, BLKmode); + + /* Use bitpos for the source extraction (left justified) and + xbitpos for the destination store (right justified). */ + store_bit_field (dst_word, bitsize, xbitpos % BITS_PER_WORD, + 0, 0, word_mode, + extract_bit_field (src_word, bitsize, + bitpos % BITS_PER_WORD, 1, false, + NULL_RTX, word_mode, word_mode)); + } + + if (mode == BLKmode) + { + /* Find the smallest integer mode large enough to hold the + entire structure. */ + for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); + mode != VOIDmode; + mode = GET_MODE_WIDER_MODE (mode)) + /* Have we found a large enough mode? */ + if (GET_MODE_SIZE (mode) >= bytes) + break; + + /* A suitable mode should have been found. */ + gcc_assert (mode != VOIDmode); + } + + if (GET_MODE_SIZE (mode) < GET_MODE_SIZE (word_mode)) + dst_mode = word_mode; + else + dst_mode = mode; + dst = gen_reg_rtx (dst_mode); + + for (i = 0; i < n_regs; i++) + emit_move_insn (operand_subword (dst, i, 0, dst_mode), dst_words[i]); + + if (mode != dst_mode) + dst = gen_lowpart (mode, dst); + + return dst; +} + /* Add a USE expression for REG to the (possibly empty) list pointed to by CALL_FUSAGE. REG must denote a hard register. */ void -use_reg (rtx *call_fusage, rtx reg) +use_reg_mode (rtx *call_fusage, rtx reg, enum machine_mode mode) { gcc_assert (REG_P (reg) && REGNO (reg) < FIRST_PSEUDO_REGISTER); *call_fusage - = gen_rtx_EXPR_LIST (VOIDmode, - gen_rtx_USE (VOIDmode, reg), *call_fusage); + = gen_rtx_EXPR_LIST (mode, gen_rtx_USE (VOIDmode, reg), *call_fusage); } /* Add USE expressions to *CALL_FUSAGE for each of NREGS consecutive regs, @@ -4439,6 +4544,27 @@ get_bit_range (unsigned HOST_WIDE_INT *bitstart, } } +/* Return the alignment of the object EXP, also considering its type + when we do not know of explicit misalignment. + ??? Note that, in the general case, the type of an expression is not kept + consistent with misalignment information by the front-end, for + example when taking the address of a member of a packed structure. + However, in most of the cases, expressions have the alignment of + their type, so we optimistically fall back to the alignment of the + type when we cannot compute a misalignment. */ + +static unsigned int +get_object_or_type_alignment (tree exp) +{ + unsigned HOST_WIDE_INT misalign; + unsigned int align = get_object_alignment_1 (exp, &misalign); + if (misalign != 0) + align = (misalign & -misalign); + else + align = MAX (TYPE_ALIGN (TREE_TYPE (exp)), align); + return align; +} + /* Expand an assignment that stores the value of FROM into TO. If NONTEMPORAL is true, try generating a nontemporal store. */ @@ -4448,7 +4574,7 @@ expand_assignment (tree to, tree from, bool nontemporal) rtx to_rtx = 0; rtx result; enum machine_mode mode; - int align; + unsigned int align; enum insn_code icode; /* Don't crash if the lhs of the assignment was erroneous. */ @@ -4466,8 +4592,8 @@ expand_assignment (tree to, tree from, bool nontemporal) if ((TREE_CODE (to) == MEM_REF || TREE_CODE (to) == TARGET_MEM_REF) && mode != BLKmode - && ((align = MAX (TYPE_ALIGN (TREE_TYPE (to)), get_object_alignment (to))) - < (signed) GET_MODE_ALIGNMENT (mode)) + && ((align = get_object_or_type_alignment (to)) + < GET_MODE_ALIGNMENT (mode)) && ((icode = optab_handler (movmisalign_optab, mode)) != CODE_FOR_nothing)) { @@ -4721,7 +4847,9 @@ expand_assignment (tree to, tree from, bool nontemporal) if (TREE_CODE (from) == CALL_EXPR && ! aggregate_value_p (from, from) && COMPLETE_TYPE_P (TREE_TYPE (from)) && TREE_CODE (TYPE_SIZE (TREE_TYPE (from))) == INTEGER_CST - && ! (((TREE_CODE (to) == VAR_DECL || TREE_CODE (to) == PARM_DECL) + && ! (((TREE_CODE (to) == VAR_DECL + || TREE_CODE (to) == PARM_DECL + || TREE_CODE (to) == RESULT_DECL) && REG_P (DECL_RTL (to))) || TREE_CODE (to) == SSA_NAME)) { @@ -4767,12 +4895,15 @@ expand_assignment (tree to, tree from, bool nontemporal) rtx temp; push_temp_slots (); - temp = expand_expr (from, NULL_RTX, GET_MODE (to_rtx), EXPAND_NORMAL); + if (REG_P (to_rtx) && TYPE_MODE (TREE_TYPE (from)) == BLKmode) + temp = copy_blkmode_to_reg (GET_MODE (to_rtx), from); + else + temp = expand_expr (from, NULL_RTX, GET_MODE (to_rtx), EXPAND_NORMAL); if (GET_CODE (to_rtx) == PARALLEL) emit_group_load (to_rtx, temp, TREE_TYPE (from), int_size_in_bytes (TREE_TYPE (from))); - else + else if (temp) emit_move_insn (to_rtx, temp); preserve_temp_slots (to_rtx); @@ -5297,6 +5428,7 @@ count_type_elements (const_tree type, bool for_ctor_p) case POINTER_TYPE: case OFFSET_TYPE: case REFERENCE_TYPE: + case NULLPTR_TYPE: return 1; case ERROR_MARK: @@ -8535,27 +8667,9 @@ expand_expr_real_2 (sepops ops, rtx target, enum machine_mode tmode, case VEC_EXTRACT_EVEN_EXPR: case VEC_EXTRACT_ODD_EXPR: - { - expand_operands (treeop0, treeop1, - NULL_RTX, &op0, &op1, EXPAND_NORMAL); - this_optab = optab_for_tree_code (code, type, optab_default); - temp = expand_binop (mode, this_optab, op0, op1, target, unsignedp, - OPTAB_WIDEN); - gcc_assert (temp); - return temp; - } - case VEC_INTERLEAVE_HIGH_EXPR: case VEC_INTERLEAVE_LOW_EXPR: - { - expand_operands (treeop0, treeop1, - NULL_RTX, &op0, &op1, EXPAND_NORMAL); - this_optab = optab_for_tree_code (code, type, optab_default); - temp = expand_binop (mode, this_optab, op0, op1, target, unsignedp, - OPTAB_WIDEN); - gcc_assert (temp); - return temp; - } + goto binop; case VEC_LSHIFT_EXPR: case VEC_RSHIFT_EXPR: @@ -8600,12 +8714,32 @@ expand_expr_real_2 (sepops ops, rtx target, enum machine_mode tmode, return target; } + case VEC_WIDEN_LSHIFT_HI_EXPR: + case VEC_WIDEN_LSHIFT_LO_EXPR: + { + tree oprnd0 = treeop0; + tree oprnd1 = treeop1; + + expand_operands (oprnd0, oprnd1, NULL_RTX, &op0, &op1, EXPAND_NORMAL); + target = expand_widen_pattern_expr (ops, op0, op1, NULL_RTX, + target, unsignedp); + gcc_assert (target); + return target; + } + case VEC_PACK_TRUNC_EXPR: case VEC_PACK_SAT_EXPR: case VEC_PACK_FIX_TRUNC_EXPR: mode = TYPE_MODE (TREE_TYPE (treeop0)); goto binop; + case VEC_PERM_EXPR: + expand_operands (treeop0, treeop1, target, &op0, &op1, EXPAND_NORMAL); + op2 = expand_normal (treeop2); + temp = expand_vec_perm (mode, op0, op1, op2, target); + gcc_assert (temp); + return temp; + case DOT_PROD_EXPR: { tree oprnd0 = treeop0; @@ -8950,10 +9084,15 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, return temp; } - /* If the mode of DECL_RTL does not match that of the decl, it - must be a promoted value. We return a SUBREG of the wanted mode, - but mark it so that we know that it was already extended. */ - if (REG_P (decl_rtl) && GET_MODE (decl_rtl) != DECL_MODE (exp)) + /* If the mode of DECL_RTL does not match that of the decl, + there are two cases: we are dealing with a BLKmode value + that is returned in a register, or we are dealing with + a promoted value. In the latter case, return a SUBREG + of the wanted mode, but mark it so that we know that it + was already extended. */ + if (REG_P (decl_rtl) + && DECL_MODE (exp) != BLKmode + && GET_MODE (decl_rtl) != DECL_MODE (exp)) { enum machine_mode pmode; @@ -9120,7 +9259,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, addr_space_t as = TYPE_ADDR_SPACE (TREE_TYPE (exp)); struct mem_address addr; enum insn_code icode; - int align; + unsigned int align; get_address_description (exp, &addr); op0 = addr_for_mem_ref (&addr, as, true); @@ -9128,9 +9267,9 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, temp = gen_rtx_MEM (mode, op0); set_mem_attributes (temp, exp, 0); set_mem_addr_space (temp, as); - align = MAX (TYPE_ALIGN (TREE_TYPE (exp)), get_object_alignment (exp)); + align = get_object_or_type_alignment (exp); if (mode != BLKmode - && (unsigned) align < GET_MODE_ALIGNMENT (mode) + && align < GET_MODE_ALIGNMENT (mode) /* If the target does not have special handling for unaligned loads of mode then it can use regular moves for them. */ && ((icode = optab_handler (movmisalign_optab, mode)) @@ -9157,7 +9296,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, tree base = TREE_OPERAND (exp, 0); gimple def_stmt; enum insn_code icode; - int align; + unsigned align; /* Handle expansion of non-aliased memory with non-BLKmode. That might end up in a register. */ if (TREE_CODE (base) == ADDR_EXPR) @@ -9208,7 +9347,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, gimple_assign_rhs1 (def_stmt), mask); TREE_OPERAND (exp, 0) = base; } - align = MAX (TYPE_ALIGN (TREE_TYPE (exp)), get_object_alignment (exp)); + align = get_object_or_type_alignment (exp); op0 = expand_expr (base, NULL_RTX, VOIDmode, EXPAND_SUM); op0 = memory_address_addr_space (address_mode, op0, as); if (!integer_zerop (TREE_OPERAND (exp, 1))) @@ -9224,7 +9363,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, if (TREE_THIS_VOLATILE (exp)) MEM_VOLATILE_P (temp) = 1; if (mode != BLKmode - && (unsigned) align < GET_MODE_ALIGNMENT (mode) + && align < GET_MODE_ALIGNMENT (mode) /* If the target does not have special handling for unaligned loads of mode then it can use regular moves for them. */ && ((icode = optab_handler (movmisalign_optab, mode)) @@ -10308,6 +10447,28 @@ do_store_flag (sepops ops, rtx target, enum machine_mode mode) STRIP_NOPS (arg0); STRIP_NOPS (arg1); + + /* For vector typed comparisons emit code to generate the desired + all-ones or all-zeros mask. Conveniently use the VEC_COND_EXPR + expander for this. */ + if (TREE_CODE (ops->type) == VECTOR_TYPE) + { + tree ifexp = build2 (ops->code, ops->type, arg0, arg1); + tree if_true = constant_boolean_node (true, ops->type); + tree if_false = constant_boolean_node (false, ops->type); + return expand_vec_cond_expr (ops->type, ifexp, if_true, if_false, target); + } + + /* For vector typed comparisons emit code to generate the desired + all-ones or all-zeros mask. Conveniently use the VEC_COND_EXPR + expander for this. */ + if (TREE_CODE (ops->type) == VECTOR_TYPE) + { + tree ifexp = build2 (ops->code, ops->type, arg0, arg1); + tree if_true = constant_boolean_node (true, ops->type); + tree if_false = constant_boolean_node (false, ops->type); + return expand_vec_cond_expr (ops->type, ifexp, if_true, if_false, target); + } /* Get the rtx comparison code to use. We know that EXP is a comparison operation of some type. Some comparisons against 1 and -1 can be