X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fexplow.c;h=719421f6cd6e70a25b69e262918cb68f043f56ff;hb=5bf4303e2b3e213e573bf72d7b7b05ad78e9b8bb;hp=1f76dcf081dd629b28b61dd5d1f886d5a6f0f4e5;hpb=dd2acd8374435c683ec974b753193dfdd6065a14;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/explow.c b/gcc/explow.c index 1f76dcf081d..719421f6cd6 100644 --- a/gcc/explow.c +++ b/gcc/explow.c @@ -1,5 +1,6 @@ /* Subroutines for manipulating rtx's in semantically interesting ways. - Copyright (C) 1987, 91, 94-99, 2000 Free Software Foundation, Inc. + Copyright (C) 1987, 1991, 1994, 1995, 1996, 1997, 1998, + 1999, 2000 Free Software Foundation, Inc. This file is part of GNU CC. @@ -51,28 +52,20 @@ trunc_int_for_mode (c, mode) { int width = GET_MODE_BITSIZE (mode); - /* We clear out all bits that don't belong in MODE, unless they and our - sign bit are all one. So we get either a reasonable negative - value or a reasonable unsigned value. */ + /* Canonicalize BImode to 0 and STORE_FLAG_VALUE. */ + if (mode == BImode) + return c & 1 ? STORE_FLAG_VALUE : 0; - if (width < HOST_BITS_PER_WIDE_INT - && ((c & ((HOST_WIDE_INT) (-1) << (width - 1))) - != ((HOST_WIDE_INT) (-1) << (width - 1)))) - c &= ((HOST_WIDE_INT) 1 << width) - 1; + /* Sign-extend for the requested mode. */ - /* If this would be an entire word for the target, but is not for - the host, then sign-extend on the host so that the number will look - the same way on the host that it would on the target. - - For example, when building a 64 bit alpha hosted 32 bit sparc - targeted compiler, then we want the 32 bit unsigned value -1 to be - represented as a 64 bit value -1, and not as 0x00000000ffffffff. - The later confuses the sparc backend. */ - - if (BITS_PER_WORD < HOST_BITS_PER_WIDE_INT - && BITS_PER_WORD == width - && (c & ((HOST_WIDE_INT) 1 << (width - 1)))) - c |= ((HOST_WIDE_INT) (-1) << width); + if (width < HOST_BITS_PER_WIDE_INT) + { + HOST_WIDE_INT sign = 1; + sign <<= width - 1; + c &= (sign << 1) - 1; + c ^= sign; + c -= sign; + } return c; } @@ -105,11 +98,12 @@ plus_constant_wide (x, c) case CONST_DOUBLE: { - HOST_WIDE_INT l1 = CONST_DOUBLE_LOW (x); + unsigned HOST_WIDE_INT l1 = CONST_DOUBLE_LOW (x); HOST_WIDE_INT h1 = CONST_DOUBLE_HIGH (x); - HOST_WIDE_INT l2 = c; + unsigned HOST_WIDE_INT l2 = c; HOST_WIDE_INT h2 = c < 0 ? ~0 : 0; - HOST_WIDE_INT lv, hv; + unsigned HOST_WIDE_INT lv; + HOST_WIDE_INT hv; add_double (l1, h1, l2, h2, &lv, &hv); @@ -123,15 +117,10 @@ plus_constant_wide (x, c) if (GET_CODE (XEXP (x, 0)) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (XEXP (x, 0))) { - /* Any rtl we create here must go in a saveable obstack, since - we might have been called from within combine. */ - push_obstacks_nochange (); - rtl_in_saveable_obstack (); tem = force_const_mem (GET_MODE (x), plus_constant (get_pool_constant (XEXP (x, 0)), c)); - pop_obstacks (); if (memory_address_p (GET_MODE (tem), XEXP (tem, 0))) return tem; } @@ -292,7 +281,7 @@ find_next_ref (reg, insn) return insn; if (GET_CODE (insn) == JUMP_INSN) { - if (simplejump_p (insn)) + if (any_uncondjump_p (insn)) next = JUMP_LABEL (insn); else return 0; @@ -385,6 +374,11 @@ convert_memory_address (to_mode, x) case CONST_DOUBLE: return x; + case SUBREG: + if (GET_MODE (SUBREG_REG (x)) == to_mode) + return SUBREG_REG (x); + break; + case LABEL_REF: temp = gen_rtx_LABEL_REF (to_mode, XEXP (x, 0)); LABEL_REF_NONLOCAL_P (temp) = LABEL_REF_NONLOCAL_P (x); @@ -394,6 +388,7 @@ convert_memory_address (to_mode, x) temp = gen_rtx_SYMBOL_REF (to_mode, XSTR (x, 0)); SYMBOL_REF_FLAG (temp) = SYMBOL_REF_FLAG (x); CONSTANT_POOL_ADDRESS_P (temp) = CONSTANT_POOL_ADDRESS_P (x); + STRING_POOL_ADDRESS_P (temp) = STRING_POOL_ADDRESS_P (x); return temp; case CONST: @@ -582,11 +577,11 @@ memory_address (mode, x) if (oldx == x) return x; else if (GET_CODE (x) == REG) - mark_reg_pointer (x, 1); + mark_reg_pointer (x, BITS_PER_UNIT); else if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 0)) == REG && GET_CODE (XEXP (x, 1)) == CONST_INT) - mark_reg_pointer (XEXP (x, 0), 1); + mark_reg_pointer (XEXP (x, 0), BITS_PER_UNIT); /* OLDX may have been the address on a temporary. Update the address to indicate that X is now used. */ @@ -626,6 +621,93 @@ validize_mem (ref) return change_address (ref, GET_MODE (ref), XEXP (ref, 0)); } +/* Given REF, either a MEM or a REG, and T, either the type of X or + the expression corresponding to REF, set RTX_UNCHANGING_P if + appropriate. */ + +void +maybe_set_unchanging (ref, t) + rtx ref; + tree t; +{ + /* We can set RTX_UNCHANGING_P from TREE_READONLY for decls whose + initialization is only executed once, or whose initializer always + has the same value. Currently we simplify this to PARM_DECLs in the + first case, and decls with TREE_CONSTANT initializers in the second. */ + if ((TREE_READONLY (t) && DECL_P (t) + && (TREE_CODE (t) == PARM_DECL + || DECL_INITIAL (t) == NULL_TREE + || TREE_CONSTANT (DECL_INITIAL (t)))) + || TREE_CODE_CLASS (TREE_CODE (t)) == 'c') + RTX_UNCHANGING_P (ref) = 1; +} + +/* Given REF, a MEM, and T, either the type of X or the expression + corresponding to REF, set the memory attributes. OBJECTP is nonzero + if we are making a new object of this type. */ + +void +set_mem_attributes (ref, t, objectp) + rtx ref; + tree t; + int objectp; +{ + tree type; + + /* It can happen that type_for_mode was given a mode for which there + is no language-level type. In which case it returns NULL, which + we can see here. */ + if (t == NULL_TREE) + return; + + type = TYPE_P (t) ? t : TREE_TYPE (t); + + /* Get the alias set from the expression or type (perhaps using a + front-end routine) and then copy bits from the type. */ + + /* It is incorrect to set RTX_UNCHANGING_P from TREE_READONLY (type) + here, because, in C and C++, the fact that a location is accessed + through a const expression does not mean that the value there can + never change. */ + MEM_ALIAS_SET (ref) = get_alias_set (t); + MEM_VOLATILE_P (ref) = TYPE_VOLATILE (type); + MEM_IN_STRUCT_P (ref) = AGGREGATE_TYPE_P (type); + + /* If we are making an object of this type, we know that it is a scalar if + the type is not an aggregate. */ + if (objectp && ! AGGREGATE_TYPE_P (type)) + MEM_SCALAR_P (ref) = 1; + + /* If T is a type, this is all we can do. Otherwise, we may be able + to deduce some more information about the expression. */ + if (TYPE_P (t)) + return; + + maybe_set_unchanging (ref, t); + if (TREE_THIS_VOLATILE (t)) + MEM_VOLATILE_P (ref) = 1; + + /* Now see if we can say more about whether it's an aggregate or + scalar. If we already know it's an aggregate, don't bother. */ + if (MEM_IN_STRUCT_P (ref)) + return; + + /* Now remove any NOPs: they don't change what the underlying object is. + Likewise for SAVE_EXPR. */ + while (TREE_CODE (t) == NOP_EXPR || TREE_CODE (t) == CONVERT_EXPR + || TREE_CODE (t) == NON_LVALUE_EXPR || TREE_CODE (t) == SAVE_EXPR) + t = TREE_OPERAND (t, 0); + + /* Since we already know the type isn't an aggregate, if this is a decl, + it must be a scalar. Or if it is a reference into an aggregate, + this is part of an aggregate. Otherwise we don't know. */ + if (DECL_P (t)) + MEM_SCALAR_P (ref) = 1; + else if (TREE_CODE (t) == COMPONENT_REF || TREE_CODE (t) == ARRAY_REF + || TREE_CODE (t) == BIT_FIELD_REF) + MEM_IN_STRUCT_P (ref) = 1; +} + /* Return a modified copy of X with its memory address copied into a temporary register to protect it from side effects. If X is not a MEM, it is returned unchanged (and not copied). @@ -636,29 +718,17 @@ stabilize (x) rtx x; { register rtx addr; + if (GET_CODE (x) != MEM) return x; + addr = XEXP (x, 0); if (rtx_unstable_p (addr)) { - rtx temp = copy_all_regs (addr); - rtx mem; - if (GET_CODE (temp) != REG) - temp = copy_to_reg (temp); - mem = gen_rtx_MEM (GET_MODE (x), temp); + rtx temp = force_reg (Pmode, copy_all_regs (addr)); + rtx mem = gen_rtx_MEM (GET_MODE (x), temp); - /* Mark returned memref with in_struct if it's in an array or - structure. Copy const and volatile from original memref. */ - - RTX_UNCHANGING_P (mem) = RTX_UNCHANGING_P (x); MEM_COPY_ATTRIBUTES (mem, x); - if (GET_CODE (addr) == PLUS) - MEM_SET_IN_STRUCT_P (mem, 1); - - /* Since the new MEM is just like the old X, it can alias only - the things that X could. */ - MEM_ALIAS_SET (mem) = MEM_ALIAS_SET (x); - return mem; } return x; @@ -765,8 +835,10 @@ force_not_mem (x) rtx x; { register rtx temp; + if (GET_CODE (x) != MEM || GET_MODE (x) == BLKmode) return x; + temp = gen_reg_rtx (GET_MODE (x)); emit_move_insn (temp, x); return temp; @@ -851,6 +923,11 @@ adjust_stack (adjust) if (adjust == const0_rtx) return; + /* We expect all variable sized adjustments to be multiple of + PREFERRED_STACK_BOUNDARY. */ + if (GET_CODE (adjust) == CONST_INT) + stack_pointer_delta -= INTVAL (adjust); + temp = expand_binop (Pmode, #ifdef STACK_GROWS_DOWNWARD add_optab, @@ -877,6 +954,11 @@ anti_adjust_stack (adjust) if (adjust == const0_rtx) return; + /* We expect all variable sized adjustments to be multiple of + PREFERRED_STACK_BOUNDARY. */ + if (GET_CODE (adjust) == CONST_INT) + stack_pointer_delta += INTVAL (adjust); + temp = expand_binop (Pmode, #ifdef STACK_GROWS_DOWNWARD sub_optab, @@ -1178,6 +1260,13 @@ allocate_dynamic_stack_space (size, target, known_align) if (GET_MODE (size) != VOIDmode && GET_MODE (size) != Pmode) size = convert_to_mode (Pmode, size, 1); + /* We can't attempt to minimize alignment necessary, because we don't + know the final value of preferred_stack_boundary yet while executing + this code. */ +#ifdef PREFERRED_STACK_BOUNDARY + cfun->preferred_stack_boundary = PREFERRED_STACK_BOUNDARY; +#endif + /* We will need to ensure that the address we return is aligned to BIGGEST_ALIGNMENT. If STACK_DYNAMIC_OFFSET is defined, we don't always know its final value at this point in the compilation (it @@ -1198,15 +1287,10 @@ allocate_dynamic_stack_space (size, target, known_align) #endif if (MUST_ALIGN) - { - if (GET_CODE (size) == CONST_INT) - size = GEN_INT (INTVAL (size) - + (BIGGEST_ALIGNMENT / BITS_PER_UNIT - 1)); - else - size = expand_binop (Pmode, add_optab, size, - GEN_INT (BIGGEST_ALIGNMENT / BITS_PER_UNIT - 1), - NULL_RTX, 1, OPTAB_LIB_WIDEN); - } + size + = force_operand (plus_constant (size, + BIGGEST_ALIGNMENT / BITS_PER_UNIT - 1), + NULL_RTX); #ifdef SETJMP_VIA_SAVE_AREA /* If setjmp restores regs from a save area in the stack frame, @@ -1229,12 +1313,12 @@ allocate_dynamic_stack_space (size, target, known_align) #if !defined(PREFERRED_STACK_BOUNDARY) || !defined(MUST_ALIGN) || (PREFERRED_STACK_BOUNDARY != BIGGEST_ALIGNMENT) /* If anyone creates a target with these characteristics, let them know that our optimization cannot work correctly in such a case. */ - abort(); + abort (); #endif if (GET_CODE (size) == CONST_INT) { - int new = INTVAL (size) / align * align; + HOST_WIDE_INT new = INTVAL (size) / align * align; if (INTVAL (size) != new) setjmpless_size = GEN_INT (new); @@ -1287,17 +1371,25 @@ allocate_dynamic_stack_space (size, target, known_align) do_pending_stack_adjust (); + /* We ought to be called always on the toplevel and stack ought to be aligned + propertly. */ +#ifdef PREFERRED_STACK_BOUNDARY + if (stack_pointer_delta % (PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT)) + abort (); +#endif + /* If needed, check that we have the required amount of stack. Take into account what has already been checked. */ if (flag_stack_check && ! STACK_CHECK_BUILTIN) probe_stack_range (STACK_CHECK_MAX_FRAME_SIZE + STACK_CHECK_PROTECT, size); - /* Don't use a TARGET that isn't a pseudo. */ + /* Don't use a TARGET that isn't a pseudo or is the wrong mode. */ if (target == 0 || GET_CODE (target) != REG - || REGNO (target) < FIRST_PSEUDO_REGISTER) + || REGNO (target) < FIRST_PSEUDO_REGISTER + || GET_MODE (target) != Pmode) target = gen_reg_rtx (Pmode); - mark_reg_pointer (target, known_align / BITS_PER_UNIT); + mark_reg_pointer (target, known_align); /* Perform the required allocation from the stack. Some systems do this differently than simply incrementing/decrementing from the @@ -1319,7 +1411,6 @@ allocate_dynamic_stack_space (size, target, known_align) if (mode == VOIDmode) mode = Pmode; - size = convert_modes (mode, ptr_mode, size, 1); pred = insn_data[(int) CODE_FOR_allocate_stack].operand[1].predicate; if (pred && ! ((*pred) (size, mode))) size = copy_to_mode_reg (mode, size); @@ -1332,7 +1423,6 @@ allocate_dynamic_stack_space (size, target, known_align) #ifndef STACK_GROWS_DOWNWARD emit_move_insn (target, virtual_stack_dynamic_rtx); #endif - size = convert_modes (Pmode, ptr_mode, size, 1); /* Check stack bounds if necessary. */ if (current_function_limit_stack) @@ -1371,6 +1461,7 @@ allocate_dynamic_stack_space (size, target, known_align) REG_NOTES (note_target)); } #endif /* SETJMP_VIA_SAVE_AREA */ + #ifdef STACK_GROWS_DOWNWARD emit_move_insn (target, virtual_stack_dynamic_rtx); #endif @@ -1455,12 +1546,20 @@ probe_stack_range (first, size) /* First see if the front end has set up a function for us to call to check the stack. */ if (stack_check_libfunc != 0) - emit_library_call (stack_check_libfunc, 0, VOIDmode, 1, - memory_address (QImode, - gen_rtx (STACK_GROW_OP, Pmode, - stack_pointer_rtx, - plus_constant (size, first))), - ptr_mode); + { + rtx addr = memory_address (QImode, + gen_rtx (STACK_GROW_OP, Pmode, + stack_pointer_rtx, + plus_constant (size, first))); + +#ifdef POINTERS_EXTEND_UNSIGNED + if (GET_MODE (addr) != ptr_mode) + addr = convert_memory_address (ptr_mode, addr); +#endif + + emit_library_call (stack_check_libfunc, 0, VOIDmode, 1, addr, + ptr_mode); + } /* Next see if we have an insn to check the stack. Use it if so. */ #ifdef HAVE_check_stack @@ -1576,17 +1675,20 @@ hard_function_value (valtype, func, outgoing) int outgoing ATTRIBUTE_UNUSED; { rtx val; + #ifdef FUNCTION_OUTGOING_VALUE if (outgoing) val = FUNCTION_OUTGOING_VALUE (valtype, func); else #endif val = FUNCTION_VALUE (valtype, func); + if (GET_CODE (val) == REG && GET_MODE (val) == BLKmode) { - int bytes = int_size_in_bytes (valtype); + unsigned HOST_WIDE_INT bytes = int_size_in_bytes (valtype); enum machine_mode tmpmode; + for (tmpmode = GET_CLASS_NARROWEST_MODE (MODE_INT); tmpmode != VOIDmode; tmpmode = GET_MODE_WIDER_MODE (tmpmode))