-Obtained from SVN: tags/gcc_4_4_6_release revision 172579
+Obtained from SVN: branches/gcc-4_4-branch revision 180457
TREE_OPERAND (expr, 0));
case COND_EXPR:
- /* Distribute the conversion into the arms of a COND_EXPR. */
- return fold_build3 (COND_EXPR, truthvalue_type_node,
- TREE_OPERAND (expr, 0),
- c_common_truthvalue_conversion (location,
- TREE_OPERAND (expr, 1)),
- c_common_truthvalue_conversion (location,
- TREE_OPERAND (expr, 2)));
+ {
+ tree op1 = TREE_OPERAND (expr, 1);
+ tree op2 = TREE_OPERAND (expr, 2);
+ /* In C++ one of the arms might have void type if it is throw. */
+ if (!VOID_TYPE_P (TREE_TYPE (op1)))
+ op1 = c_common_truthvalue_conversion (location, op1);
+ if (!VOID_TYPE_P (TREE_TYPE (op2)))
+ op2 = c_common_truthvalue_conversion (location, op2);
+ /* Distribute the conversion into the arms of a COND_EXPR. */
+ return fold_build3 (COND_EXPR, truthvalue_type_node,
+ TREE_OPERAND (expr, 0), op1, op2);
+ }
CASE_CONVERT:
/* Don't cancel the effect of a CONVERT_EXPR from a REFERENCE_TYPE,
{
/* Try to simplify the expression further. */
rtx tor = simplify_gen_binary (IOR, mode, XEXP (x, 0), XEXP (x, 1));
- temp = combine_simplify_rtx (tor, mode, in_dest);
+ temp = combine_simplify_rtx (tor, VOIDmode, in_dest);
/* If we could, great. If not, do not go ahead with the IOR
replacement, since PLUS appears in many special purpose
if (req_mode == CCZmode)
return 0;
/* FALLTHRU */
+ case CCZmode:
+ break;
+
case CCAmode:
case CCCmode:
case CCOmode:
case CCSmode:
- case CCZmode:
+ if (set_mode != req_mode)
+ return 0;
break;
default:
(set (match_operand:DI 1 "register_operand" "=S")
(plus:DI (match_dup 3)
(const_int 8)))]
- "TARGET_64BIT"
+ "TARGET_64BIT
+ && !(fixed_regs[SI_REG] || fixed_regs[DI_REG])"
"movsq"
[(set_attr "type" "str")
(set_attr "mode" "DI")
(set (match_operand:SI 1 "register_operand" "=S")
(plus:SI (match_dup 3)
(const_int 4)))]
- "!TARGET_64BIT"
+ "!TARGET_64BIT
+ && !(fixed_regs[SI_REG] || fixed_regs[DI_REG])"
"movs{l|d}"
[(set_attr "type" "str")
(set_attr "mode" "SI")
(set (match_operand:DI 1 "register_operand" "=S")
(plus:DI (match_dup 3)
(const_int 4)))]
- "TARGET_64BIT"
+ "TARGET_64BIT
+ && !(fixed_regs[SI_REG] || fixed_regs[DI_REG])"
"movs{l|d}"
[(set_attr "type" "str")
(set_attr "mode" "SI")
(set (match_operand:SI 1 "register_operand" "=S")
(plus:SI (match_dup 3)
(const_int 2)))]
- "!TARGET_64BIT"
+ "!TARGET_64BIT
+ && !(fixed_regs[SI_REG] || fixed_regs[DI_REG])"
"movsw"
[(set_attr "type" "str")
(set_attr "memory" "both")
(set (match_operand:DI 1 "register_operand" "=S")
(plus:DI (match_dup 3)
(const_int 2)))]
- "TARGET_64BIT"
+ "TARGET_64BIT
+ && !(fixed_regs[SI_REG] || fixed_regs[DI_REG])"
"movsw"
[(set_attr "type" "str")
(set_attr "memory" "both")
(set (match_operand:SI 1 "register_operand" "=S")
(plus:SI (match_dup 3)
(const_int 1)))]
- "!TARGET_64BIT"
+ "!TARGET_64BIT
+ && !(fixed_regs[SI_REG] || fixed_regs[DI_REG])"
"movsb"
[(set_attr "type" "str")
(set_attr "memory" "both")
(set (match_operand:DI 1 "register_operand" "=S")
(plus:DI (match_dup 3)
(const_int 1)))]
- "TARGET_64BIT"
+ "TARGET_64BIT
+ && !(fixed_regs[SI_REG] || fixed_regs[DI_REG])"
"movsb"
[(set_attr "type" "str")
(set_attr "memory" "both")
(set (mem:BLK (match_dup 3))
(mem:BLK (match_dup 4)))
(use (match_dup 5))]
- "TARGET_64BIT"
+ "TARGET_64BIT
+ && !(fixed_regs[CX_REG] || fixed_regs[SI_REG] || fixed_regs[DI_REG])"
"rep{%;} movsq"
[(set_attr "type" "str")
(set_attr "prefix_rep" "1")
(set (mem:BLK (match_dup 3))
(mem:BLK (match_dup 4)))
(use (match_dup 5))]
- "!TARGET_64BIT"
+ "!TARGET_64BIT
+ && !(fixed_regs[CX_REG] || fixed_regs[SI_REG] || fixed_regs[DI_REG])"
"rep{%;} movs{l|d}"
[(set_attr "type" "str")
(set_attr "prefix_rep" "1")
(set (mem:BLK (match_dup 3))
(mem:BLK (match_dup 4)))
(use (match_dup 5))]
- "TARGET_64BIT"
+ "TARGET_64BIT
+ && !(fixed_regs[CX_REG] || fixed_regs[SI_REG] || fixed_regs[DI_REG])"
"rep{%;} movs{l|d}"
[(set_attr "type" "str")
(set_attr "prefix_rep" "1")
(set (mem:BLK (match_dup 3))
(mem:BLK (match_dup 4)))
(use (match_dup 5))]
- "!TARGET_64BIT"
+ "!TARGET_64BIT
+ && !(fixed_regs[CX_REG] || fixed_regs[SI_REG] || fixed_regs[DI_REG])"
"rep{%;} movsb"
[(set_attr "type" "str")
(set_attr "prefix_rep" "1")
(set (mem:BLK (match_dup 3))
(mem:BLK (match_dup 4)))
(use (match_dup 5))]
- "TARGET_64BIT"
+ "TARGET_64BIT
+ && !(fixed_regs[CX_REG] || fixed_regs[SI_REG] || fixed_regs[DI_REG])"
"rep{%;} movsb"
[(set_attr "type" "str")
(set_attr "prefix_rep" "1")
operands[3] = gen_rtx_PLUS (Pmode, operands[0],
GEN_INT (GET_MODE_SIZE (GET_MODE
(operands[2]))));
- if (TARGET_SINGLE_STRINGOP || optimize_insn_for_size_p ())
+ /* Can't use this if the user has appropriated eax or edi. */
+ if ((TARGET_SINGLE_STRINGOP || optimize_insn_for_size_p ())
+ && !(fixed_regs[AX_REG] || fixed_regs[DI_REG]))
{
emit_insn (gen_strset_singleop (operands[0], operands[1], operands[2],
operands[3]));
(set (match_operand:DI 0 "register_operand" "=D")
(plus:DI (match_dup 1)
(const_int 8)))]
- "TARGET_64BIT"
+ "TARGET_64BIT
+ && !(fixed_regs[AX_REG] || fixed_regs[DI_REG])"
"stosq"
[(set_attr "type" "str")
(set_attr "memory" "store")
(set (match_operand:SI 0 "register_operand" "=D")
(plus:SI (match_dup 1)
(const_int 4)))]
- "!TARGET_64BIT"
+ "!TARGET_64BIT
+ && !(fixed_regs[AX_REG] || fixed_regs[DI_REG])"
"stos{l|d}"
[(set_attr "type" "str")
(set_attr "memory" "store")
(set (match_operand:DI 0 "register_operand" "=D")
(plus:DI (match_dup 1)
(const_int 4)))]
- "TARGET_64BIT"
+ "TARGET_64BIT
+ && !(fixed_regs[AX_REG] || fixed_regs[DI_REG])"
"stos{l|d}"
[(set_attr "type" "str")
(set_attr "memory" "store")
(set (match_operand:SI 0 "register_operand" "=D")
(plus:SI (match_dup 1)
(const_int 2)))]
- "!TARGET_64BIT"
+ "!TARGET_64BIT
+ && !(fixed_regs[AX_REG] || fixed_regs[DI_REG])"
"stosw"
[(set_attr "type" "str")
(set_attr "memory" "store")
(set (match_operand:DI 0 "register_operand" "=D")
(plus:DI (match_dup 1)
(const_int 2)))]
- "TARGET_64BIT"
+ "TARGET_64BIT
+ && !(fixed_regs[AX_REG] || fixed_regs[DI_REG])"
"stosw"
[(set_attr "type" "str")
(set_attr "memory" "store")
(set (match_operand:SI 0 "register_operand" "=D")
(plus:SI (match_dup 1)
(const_int 1)))]
- "!TARGET_64BIT"
+ "!TARGET_64BIT
+ && !(fixed_regs[AX_REG] || fixed_regs[DI_REG])"
"stosb"
[(set_attr "type" "str")
(set_attr "memory" "store")
(set (match_operand:DI 0 "register_operand" "=D")
(plus:DI (match_dup 1)
(const_int 1)))]
- "TARGET_64BIT"
+ "TARGET_64BIT
+ && !(fixed_regs[AX_REG] || fixed_regs[DI_REG])"
"stosb"
[(set_attr "type" "str")
(set_attr "memory" "store")
(const_int 0))
(use (match_operand:DI 2 "register_operand" "a"))
(use (match_dup 4))]
- "TARGET_64BIT"
+ "TARGET_64BIT
+ && !(fixed_regs[AX_REG] || fixed_regs[CX_REG] || fixed_regs[DI_REG])"
"rep{%;} stosq"
[(set_attr "type" "str")
(set_attr "prefix_rep" "1")
(const_int 0))
(use (match_operand:SI 2 "register_operand" "a"))
(use (match_dup 4))]
- "!TARGET_64BIT"
+ "!TARGET_64BIT
+ && !(fixed_regs[AX_REG] || fixed_regs[CX_REG] || fixed_regs[DI_REG])"
"rep{%;} stos{l|d}"
[(set_attr "type" "str")
(set_attr "prefix_rep" "1")
(const_int 0))
(use (match_operand:SI 2 "register_operand" "a"))
(use (match_dup 4))]
- "TARGET_64BIT"
+ "TARGET_64BIT
+ && !(fixed_regs[AX_REG] || fixed_regs[CX_REG] || fixed_regs[DI_REG])"
"rep{%;} stos{l|d}"
[(set_attr "type" "str")
(set_attr "prefix_rep" "1")
(const_int 0))
(use (match_operand:QI 2 "register_operand" "a"))
(use (match_dup 4))]
- "!TARGET_64BIT"
+ "!TARGET_64BIT
+ && !(fixed_regs[AX_REG] || fixed_regs[CX_REG] || fixed_regs[DI_REG])"
"rep{%;} stosb"
[(set_attr "type" "str")
(set_attr "prefix_rep" "1")
(const_int 0))
(use (match_operand:QI 2 "register_operand" "a"))
(use (match_dup 4))]
- "TARGET_64BIT"
+ "TARGET_64BIT
+ && !(fixed_regs[AX_REG] || fixed_regs[CX_REG] || fixed_regs[DI_REG])"
"rep{%;} stosb"
[(set_attr "type" "str")
(set_attr "prefix_rep" "1")
if (optimize_insn_for_size_p () && !TARGET_INLINE_ALL_STRINGOPS)
FAIL;
- /* Can't use this if the user has appropriated esi or edi. */
- if (fixed_regs[SI_REG] || fixed_regs[DI_REG])
+ /* Can't use this if the user has appropriated ecx, esi or edi. */
+ if (fixed_regs[CX_REG] || fixed_regs[SI_REG] || fixed_regs[DI_REG])
FAIL;
out = operands[0];
(clobber (match_operand:SI 0 "register_operand" "=S"))
(clobber (match_operand:SI 1 "register_operand" "=D"))
(clobber (match_operand:SI 2 "register_operand" "=c"))]
- "!TARGET_64BIT"
+ "!TARGET_64BIT
+ && !(fixed_regs[CX_REG] || fixed_regs[SI_REG] || fixed_regs[DI_REG])"
"repz{%;} cmpsb"
[(set_attr "type" "str")
(set_attr "mode" "QI")
(clobber (match_operand:DI 0 "register_operand" "=S"))
(clobber (match_operand:DI 1 "register_operand" "=D"))
(clobber (match_operand:DI 2 "register_operand" "=c"))]
- "TARGET_64BIT"
+ "TARGET_64BIT
+ && !(fixed_regs[CX_REG] || fixed_regs[SI_REG] || fixed_regs[DI_REG])"
"repz{%;} cmpsb"
[(set_attr "type" "str")
(set_attr "mode" "QI")
(clobber (match_operand:SI 0 "register_operand" "=S"))
(clobber (match_operand:SI 1 "register_operand" "=D"))
(clobber (match_operand:SI 2 "register_operand" "=c"))]
- "!TARGET_64BIT"
+ "!TARGET_64BIT
+ && !(fixed_regs[CX_REG] || fixed_regs[SI_REG] || fixed_regs[DI_REG])"
"repz{%;} cmpsb"
[(set_attr "type" "str")
(set_attr "mode" "QI")
(clobber (match_operand:DI 0 "register_operand" "=S"))
(clobber (match_operand:DI 1 "register_operand" "=D"))
(clobber (match_operand:DI 2 "register_operand" "=c"))]
- "TARGET_64BIT"
+ "TARGET_64BIT
+ && !(fixed_regs[CX_REG] || fixed_regs[SI_REG] || fixed_regs[DI_REG])"
"repz{%;} cmpsb"
[(set_attr "type" "str")
(set_attr "mode" "QI")
(unspec:SI [(match_operand:BLK 1 "general_operand" "")
(match_operand:QI 2 "immediate_operand" "")
(match_operand 3 "immediate_operand" "")] UNSPEC_SCAS))]
- ""
+ "!TARGET_64BIT"
{
if (ix86_expand_strlen (operands[0], operands[1], operands[2], operands[3]))
DONE;
(unspec:DI [(match_operand:BLK 1 "general_operand" "")
(match_operand:QI 2 "immediate_operand" "")
(match_operand 3 "immediate_operand" "")] UNSPEC_SCAS))]
- ""
+ "TARGET_64BIT"
{
if (ix86_expand_strlen (operands[0], operands[1], operands[2], operands[3]))
DONE;
(match_operand:SI 4 "register_operand" "0")] UNSPEC_SCAS))
(clobber (match_operand:SI 1 "register_operand" "=D"))
(clobber (reg:CC FLAGS_REG))]
- "!TARGET_64BIT"
+ "!TARGET_64BIT
+ && !(fixed_regs[AX_REG] || fixed_regs[CX_REG] || fixed_regs[DI_REG])"
"repnz{%;} scasb"
[(set_attr "type" "str")
(set_attr "mode" "QI")
(match_operand:DI 4 "register_operand" "0")] UNSPEC_SCAS))
(clobber (match_operand:DI 1 "register_operand" "=D"))
(clobber (reg:CC FLAGS_REG))]
- "TARGET_64BIT"
+ "TARGET_64BIT
+ && !(fixed_regs[AX_REG] || fixed_regs[CX_REG] || fixed_regs[DI_REG])"
"repnz{%;} scasb"
[(set_attr "type" "str")
(set_attr "mode" "QI")
(match_operand:SI 3 "const_0_to_255_operand" "n")]
UNSPEC_INSERTPS))]
"TARGET_AVX"
- "vinsertps\t{%3, %2, %1, %0|%0, %1, %2, %3}";
+{
+ if (MEM_P (operands[2]))
+ {
+ unsigned count_s = INTVAL (operands[3]) >> 6;
+ if (count_s)
+ operands[3] = GEN_INT (INTVAL (operands[3]) & 0x3f);
+ operands[2] = adjust_address_nv (operands[2], SFmode, count_s * 4);
+ }
+ return "vinsertps\t{%3, %2, %1, %0|%0, %1, %2, %3}";
+}
[(set_attr "type" "sselog")
(set_attr "prefix" "vex")
(set_attr "mode" "V4SF")])
(match_operand:SI 3 "const_0_to_255_operand" "n")]
UNSPEC_INSERTPS))]
"TARGET_SSE4_1"
- "insertps\t{%3, %2, %0|%0, %2, %3}";
+{
+ if (MEM_P (operands[2]))
+ {
+ unsigned count_s = INTVAL (operands[3]) >> 6;
+ if (count_s)
+ operands[3] = GEN_INT (INTVAL (operands[3]) & 0x3f);
+ operands[2] = adjust_address_nv (operands[2], SFmode, count_s * 4);
+ }
+ return "insertps\t{%3, %2, %0|%0, %2, %3}";
+}
[(set_attr "type" "sselog")
(set_attr "prefix_extra" "1")
(set_attr "mode" "V4SF")])
(set_attr "mode" "V1DF,V2DF,DF,DF,DF")])
(define_insn "sse2_loadhpd"
- [(set (match_operand:V2DF 0 "nonimmediate_operand" "=x,x,x,o,o,o")
+ [(set (match_operand:V2DF 0 "nonimmediate_operand" "=x,x,o,o,o")
(vec_concat:V2DF
(vec_select:DF
- (match_operand:V2DF 1 "nonimmediate_operand" " 0,0,x,0,0,0")
+ (match_operand:V2DF 1 "nonimmediate_operand" " 0,0,0,0,0")
(parallel [(const_int 0)]))
- (match_operand:DF 2 "nonimmediate_operand" " m,x,0,x,*f,r")))]
+ (match_operand:DF 2 "nonimmediate_operand" " m,x,x,*f,r")))]
"TARGET_SSE2 && !(MEM_P (operands[1]) && MEM_P (operands[2]))"
"@
movhpd\t{%2, %0|%0, %2}
unpcklpd\t{%2, %0|%0, %2}
- shufpd\t{$1, %1, %0|%0, %1, 1}
#
#
#"
- [(set_attr "type" "ssemov,sselog,sselog,ssemov,fmov,imov")
- (set_attr "mode" "V1DF,V2DF,V2DF,DF,DF,DF")])
+ [(set_attr "type" "ssemov,sselog,ssemov,fmov,imov")
+ (set_attr "mode" "V1DF,V2DF,DF,DF,DF")])
(define_split
[(set (match_operand:V2DF 0 "memory_operand" "")
[(set (match_operand:AVXMODEF2P 0 "register_operand" "=x")
(unspec:AVXMODEF2P
[(match_operand:AVXMODEF2P 1 "memory_operand" "m")
- (match_operand:<avxpermvecmode> 2 "register_operand" "x")
- (match_dup 0)]
+ (match_operand:<avxpermvecmode> 2 "register_operand" "x")]
UNSPEC_MASKLOAD))]
"TARGET_AVX"
"vmaskmovp<avxmodesuffixf2c>\t{%1, %2, %0|%0, %2, %1}"
bool, tsubst_flags_t);
static void op_error (enum tree_code, enum tree_code, tree, tree,
tree, const char *);
-static tree build_object_call (tree, tree, tsubst_flags_t);
static tree resolve_args (tree);
static struct z_candidate *build_user_type_conversion_1 (tree, tree, int);
static void print_z_candidate (const char *, struct z_candidate *);
return build_over_call (cand, LOOKUP_NORMAL, tf_warning_or_error);
}
-static tree
+tree
build_object_call (tree obj, tree args, tsubst_flags_t complain)
{
struct z_candidate *candidates = 0, *cand;
tsubst_flags_t);
extern tree build_operator_new_call (tree, tree, tree *, tree *,
tree *);
+extern tree build_object_call (tree, tree, tsubst_flags_t);
extern tree build_new_method_call (tree, tree, tree, tree, int,
tree *, tsubst_flags_t);
extern tree build_special_member_call (tree, tree, tree, tree, int,
because we depend on the form of FN. */
args = build_non_dependent_args (args);
object = build_non_dependent_expr (object);
- if (TREE_CODE (fn) == DOTSTAR_EXPR)
- object = cp_build_unary_op (ADDR_EXPR, object, 0, tf_warning_or_error);
- args = tree_cons (NULL_TREE, object, args);
+ if (TREE_CODE (TREE_TYPE (fn)) == METHOD_TYPE)
+ {
+ if (TREE_CODE (fn) == DOTSTAR_EXPR)
+ object = cp_build_unary_op (ADDR_EXPR, object, 0, tf_warning_or_error);
+ args = tree_cons (NULL_TREE, object, args);
+ }
/* Now that the arguments are done, transform FN. */
fn = build_non_dependent_expr (fn);
}
args = tree_cons (NULL_TREE, object_addr, args);
}
- expr = cp_build_function_call (fn, args, tf_warning_or_error);
+ if (CLASS_TYPE_P (TREE_TYPE (fn)))
+ expr = build_object_call (fn, args, tf_warning_or_error);
+ else
+ expr = cp_build_function_call (fn, args, tf_warning_or_error);
if (processing_template_decl && expr != error_mark_node)
return build_min_non_dep_call_list (expr, orig_fn, orig_args);
return expr;
void
mark_used (tree decl)
{
- HOST_WIDE_INT saved_processing_template_decl = 0;
-
/* If DECL is a BASELINK for a single function, then treat it just
like the DECL for the function. Otherwise, if the BASELINK is
for an overloaded function, we don't know which function was
error ("used here");
return;
}
- /* If we don't need a value, then we don't need to synthesize DECL. */
- if (skip_evaluation)
- return;
/* If within finish_function, defer the rest until that function
finishes, otherwise it might recurse. */
DECL. However, if DECL is a static data member initialized with
a constant, we need the value right now because a reference to
such a data member is not value-dependent. */
- if (TREE_CODE (decl) == VAR_DECL
- && DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl)
- && DECL_CLASS_SCOPE_P (decl))
+ if (DECL_INTEGRAL_CONSTANT_VAR_P (decl)
+ && !DECL_INITIAL (decl)
+ && DECL_LANG_SPECIFIC (decl)
+ && DECL_TEMPLATE_INSTANTIATION (decl))
{
/* Don't try to instantiate members of dependent types. We
cannot just use dependent_type_p here because this function
if (CLASSTYPE_TEMPLATE_INFO ((DECL_CONTEXT (decl)))
&& uses_template_parms (CLASSTYPE_TI_ARGS (DECL_CONTEXT (decl))))
return;
- /* Pretend that we are not in a template, even if we are, so
- that the static data member initializer will be processed. */
- saved_processing_template_decl = processing_template_decl;
- processing_template_decl = 0;
+ instantiate_decl (decl, /*defer_ok=*/false,
+ /*expl_inst_class_mem_p=*/false);
}
+ /* If we don't need a value, then we don't need to synthesize DECL. */
+ if (skip_evaluation)
+ return;
+
if (processing_template_decl)
return;
need. Therefore, we always try to defer instantiation. */
instantiate_decl (decl, /*defer_ok=*/true,
/*expl_inst_class_mem_p=*/false);
-
- processing_template_decl = saved_processing_template_decl;
}
/* Given function PARM_DECL PARM, return its index in the function's list
is the number of elements in the array. If STATIC_STORAGE_P is
TRUE, initializers are only generated for entities for which
zero-initialization does not simply mean filling the storage with
- zero bytes. */
+ zero bytes. FIELD_SIZE, if non-NULL, is the bit size of the field,
+ subfields with bit positions at or above that bit size shouldn't
+ be added. */
-tree
-build_zero_init (tree type, tree nelts, bool static_storage_p)
+static tree
+build_zero_init_1 (tree type, tree nelts, bool static_storage_p,
+ tree field_size)
{
tree init = NULL_TREE;
if (TREE_CODE (field) != FIELD_DECL)
continue;
+ /* Don't add virtual bases for base classes if they are beyond
+ the size of the current field, that means it is present
+ somewhere else in the object. */
+ if (field_size)
+ {
+ tree bitpos = bit_position (field);
+ if (TREE_CODE (bitpos) == INTEGER_CST
+ && !tree_int_cst_lt (bitpos, field_size))
+ continue;
+ }
+
/* Note that for class types there will be FIELD_DECLs
corresponding to base classes as well. Thus, iterating
over TYPE_FIELDs will result in correct initialization of
all of the subobjects. */
if (!static_storage_p || !zero_init_p (TREE_TYPE (field)))
{
- tree value = build_zero_init (TREE_TYPE (field),
- /*nelts=*/NULL_TREE,
- static_storage_p);
+ tree new_field_size
+ = (DECL_FIELD_IS_BASE (field)
+ && DECL_SIZE (field)
+ && TREE_CODE (DECL_SIZE (field)) == INTEGER_CST)
+ ? DECL_SIZE (field) : NULL_TREE;
+ tree value = build_zero_init_1 (TREE_TYPE (field),
+ /*nelts=*/NULL_TREE,
+ static_storage_p,
+ new_field_size);
if (value)
CONSTRUCTOR_APPEND_ELT(v, field, value);
}
ce->index = build2 (RANGE_EXPR, sizetype, size_zero_node,
max_index);
- ce->value = build_zero_init (TREE_TYPE (type),
- /*nelts=*/NULL_TREE,
- static_storage_p);
+ ce->value = build_zero_init_1 (TREE_TYPE (type),
+ /*nelts=*/NULL_TREE,
+ static_storage_p, NULL_TREE);
}
/* Build a constructor to contain the initializations. */
return init;
}
+/* Return an expression for the zero-initialization of an object with
+ type T. This expression will either be a constant (in the case
+ that T is a scalar), or a CONSTRUCTOR (in the case that T is an
+ aggregate), or NULL (in the case that T does not require
+ initialization). In either case, the value can be used as
+ DECL_INITIAL for a decl of the indicated TYPE; it is a valid static
+ initializer. If NELTS is non-NULL, and TYPE is an ARRAY_TYPE, NELTS
+ is the number of elements in the array. If STATIC_STORAGE_P is
+ TRUE, initializers are only generated for entities for which
+ zero-initialization does not simply mean filling the storage with
+ zero bytes. */
+
+tree
+build_zero_init (tree type, tree nelts, bool static_storage_p)
+{
+ return build_zero_init_1 (type, nelts, static_storage_p, NULL_TREE);
+}
+
/* Return a suitable initializer for value-initializing an object of type
TYPE, as described in [dcl.init]. */
zero out the object first. */
else if (TYPE_NEEDS_CONSTRUCTING (type))
{
- init = build_zero_init (type, NULL_TREE, /*static_storage_p=*/false);
+ tree field_size = NULL_TREE;
+ if (exp != true_exp && CLASSTYPE_AS_BASE (type) != type)
+ /* Don't clobber already initialized virtual bases. */
+ field_size = TYPE_SIZE (CLASSTYPE_AS_BASE (type));
+ init = build_zero_init_1 (type, NULL_TREE, /*static_storage_p=*/false,
+ field_size);
init = build2 (INIT_EXPR, type, exp, init);
finish_expr_stmt (init);
/* And then call the constructor. */
`&A::B' might be a pointer-to-member, but `&(A::B)' is
not. */
finish_parenthesized_expr (expr);
+ /* DR 705: Wrapping an unqualified name in parentheses
+ suppresses arg-dependent lookup. We want to pass back
+ CP_ID_KIND_QUALIFIED for suppressing vtable lookup
+ (c++/37862), but none of the others. */
+ if (*idk != CP_ID_KIND_QUALIFIED)
+ *idk = CP_ID_KIND_NONE;
}
/* The `>' token might be the end of a template-id or
template-parameter-list now. */
tree u;
if (TREE_CODE (TREE_OPERAND (t, 1)) == AGGR_INIT_EXPR)
- u = build_cplus_new (TREE_TYPE (t), TREE_OPERAND (t, 1));
+ {
+ u = build_cplus_new (TREE_TYPE (t), TREE_OPERAND (t, 1));
+ if (AGGR_INIT_ZERO_FIRST (TREE_OPERAND (t, 1)))
+ AGGR_INIT_ZERO_FIRST (TREE_OPERAND (u, 1)) = true;
+ }
else
u = build_target_expr_with_type (TREE_OPERAND (t, 1), TREE_TYPE (t));
if (!TREE_SIDE_EFFECTS (exp))
init_expr = NULL_TREE;
else if (!real_lvalue_p (exp)
- || !TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (exp)))
+ || (!TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (exp))
+ && !TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (exp))))
{
init_expr = get_target_expr (exp);
exp = TARGET_EXPR_SLOT (init_expr);
/* If temp is constant, we can just compute the result. */
if (GET_CODE (temp) == CONST_INT)
{
- if (INTVAL (temp) != 0)
- emit_move_insn (target, const1_rtx);
- else
+ if (INTVAL (temp) == 0)
emit_move_insn (target, const0_rtx);
+ else if (TYPE_PRECISION (type) == 1 && !TYPE_UNSIGNED (type))
+ emit_move_insn (target, constm1_rtx);
+ else
+ emit_move_insn (target, const1_rtx);
return target;
}
op1 = gen_label_rtx ();
emit_cmp_and_jump_insns (temp, const0_rtx, EQ, NULL_RTX,
GET_MODE (temp), unsignedp, op1);
- emit_move_insn (temp, const1_rtx);
+ emit_move_insn (temp,
+ TYPE_PRECISION (type) == 1 && !TYPE_UNSIGNED (type)
+ ? constm1_rtx : const1_rtx);
emit_label (op1);
return temp;
}
jumpifnot (exp, op1, -1);
if (target)
- emit_move_insn (target, const1_rtx);
+ emit_move_insn (target,
+ TYPE_PRECISION (type) == 1 && !TYPE_UNSIGNED (type)
+ ? constm1_rtx : const1_rtx);
emit_label (op1);
return ignore ? const0_rtx : target;
rtx op0, op1;
enum insn_code icode;
rtx subtarget = target;
- rtx result, label;
+ rtx result, label, trueval = const1_rtx;
/* If this is a TRUTH_NOT_EXPR, set a flag indicating we must invert the
result at the end. We can't simply invert the test since it would
if ((code == NE || code == EQ)
&& TREE_CODE (arg0) == BIT_AND_EXPR && integer_zerop (arg1)
- && integer_pow2p (TREE_OPERAND (arg0, 1)))
+ && integer_pow2p (TREE_OPERAND (arg0, 1))
+ && (TYPE_PRECISION (TREE_TYPE (exp)) != 1
+ || TYPE_UNSIGNED (TREE_TYPE (exp))))
{
tree type = lang_hooks.types.type_for_mode (mode, unsignedp);
return expand_expr (fold_single_bit_test (code == NE ? NE_EXPR : EQ_EXPR,
if (target == 0)
target = gen_reg_rtx (mode);
+ if (TYPE_PRECISION (TREE_TYPE (exp)) == 1
+ && !TYPE_UNSIGNED (TREE_TYPE (exp)))
+ trueval = constm1_rtx;
+
result = emit_store_flag (target, code, op0, op1,
- operand_mode, unsignedp, 1);
+ operand_mode, unsignedp,
+ trueval == const1_rtx ? 1 : -1);
if (result)
{
if (invert)
- result = expand_binop (mode, xor_optab, result, const1_rtx,
+ result = expand_binop (mode, xor_optab, result, trueval,
result, 0, OPTAB_LIB_WIDEN);
return result;
}
|| reg_mentioned_p (target, op0) || reg_mentioned_p (target, op1))
target = gen_reg_rtx (GET_MODE (target));
- emit_move_insn (target, invert ? const0_rtx : const1_rtx);
+ emit_move_insn (target, invert ? const0_rtx : trueval);
label = gen_label_rtx ();
do_compare_rtx_and_jump (op0, op1, code, unsignedp, operand_mode, NULL_RTX,
NULL_RTX, label, -1);
- emit_move_insn (target, invert ? const1_rtx : const0_rtx);
+ emit_move_insn (target, invert ? trueval : const0_rtx);
emit_label (label);
return target;
location_t loc;
expanded_location expanded;
+ /* Make sure we flush any queued register saves in case this
+ clobbers affected registers. */
+ if (dwarf2out_do_frame ())
+ dwarf2out_frame_debug (insn, false);
+
/* There's no telling what that did to the condition codes. */
CC_STATUS_INIT;
ret = MIN (ret, tret);
}
}
+ else
+ {
+ tret = gimplify_expr (&TREE_OPERAND (t, 2), pre_p, post_p,
+ is_gimple_reg, fb_rvalue);
+ ret = MIN (ret, tret);
+ }
- if (!TREE_OPERAND (t, 3))
+ if (TREE_OPERAND (t, 3) == NULL_TREE)
{
tree elmt_type = TREE_TYPE (TREE_TYPE (TREE_OPERAND (t, 0)));
tree elmt_size = unshare_expr (array_ref_element_size (t));
ret = MIN (ret, tret);
}
}
+ else
+ {
+ tret = gimplify_expr (&TREE_OPERAND (t, 3), pre_p, post_p,
+ is_gimple_reg, fb_rvalue);
+ ret = MIN (ret, tret);
+ }
}
else if (TREE_CODE (t) == COMPONENT_REF)
{
/* Set the field offset into T and gimplify it. */
- if (!TREE_OPERAND (t, 2))
+ if (TREE_OPERAND (t, 2) == NULL_TREE)
{
tree offset = unshare_expr (component_ref_field_offset (t));
tree field = TREE_OPERAND (t, 1);
ret = MIN (ret, tret);
}
}
+ else
+ {
+ tret = gimplify_expr (&TREE_OPERAND (t, 2), pre_p, post_p,
+ is_gimple_reg, fb_rvalue);
+ ret = MIN (ret, tret);
+ }
}
}
false_label_p);
append_to_statement_list (t, &expr);
}
- else if (TREE_CODE (pred) == COND_EXPR)
+ else if (TREE_CODE (pred) == COND_EXPR
+ && !VOID_TYPE_P (TREE_TYPE (TREE_OPERAND (pred, 1)))
+ && !VOID_TYPE_P (TREE_TYPE (TREE_OPERAND (pred, 2))))
{
/* As long as we're messing with gotos, turn if (a ? b : c) into
if (a)
if (b) goto yes; else goto no;
else
- if (c) goto yes; else goto no; */
+ if (c) goto yes; else goto no;
+
+ Don't do this if one of the arms has void type, which can happen
+ in C++ when the arm is throw. */
expr = build3 (COND_EXPR, void_type_node, TREE_OPERAND (pred, 0),
shortcut_cond_r (TREE_OPERAND (pred, 1), true_label_p,
false_label_p),
else
edge_flags = 0;
- make_single_succ_edge (rec, second_bb, edge_flags);
+ make_single_succ_edge (rec, second_bb, edge_flags);
+ if (dom_info_available_p (CDI_DOMINATORS))
+ set_immediate_dominator (CDI_DOMINATORS, rec, first_bb);
}
/* This function creates recovery code for INSN. If MUTATE_P is nonzero,
|| num > PARAM_VALUE (PARAM_MAX_RELOAD_SEARCH_INSNS))
return 0;
+ /* Don't reuse register contents from before a setjmp-type
+ function call; on the second return (from the longjmp) it
+ might have been clobbered by a later reuse. It doesn't
+ seem worthwhile to actually go and see if it is actually
+ reused even if that information would be readily available;
+ just don't reuse it across the setjmp call. */
+ if (CALL_P (p) && find_reg_note (p, REG_SETJMP, NULL_RTX))
+ return 0;
+
if (NONJUMP_INSN_P (p)
/* If we don't want spill regs ... */
&& (! (reload_reg_p != 0
{
AND_COMPL_HARD_REG_SET (reg_reloaded_valid, call_used_reg_set);
AND_COMPL_HARD_REG_SET (reg_reloaded_valid, reg_reloaded_call_part_clobbered);
+
+ /* If this is a call to a setjmp-type function, we must not
+ reuse any reload reg contents across the call; that will
+ just be clobbered by other uses of the register in later
+ code, before the longjmp. */
+ if (find_reg_note (insn, REG_SETJMP, NULL_RTX))
+ CLEAR_HARD_REG_SET (reg_reloaded_valid);
}
}
We do this by deleting the INSN containing the SEQUENCE, then
re-emitting the insns separately, and then deleting the RETURN.
This allows the count of the jump target to be properly
- decremented. */
+ decremented.
- /* Clear the from target bit, since these insns are no longer
+ Note that we need to change the INSN_UID of the re-emitted insns
+ since it is used to hash the insns for mark_target_live_regs and
+ the re-emitted insns will no longer be wrapped up in a SEQUENCE.
+
+ Clear the from target bit, since these insns are no longer
in delay slots. */
for (i = 0; i < XVECLEN (pat, 0); i++)
INSN_FROM_TARGET_P (XVECEXP (pat, 0, i)) = 0;
trial = PREV_INSN (insn);
delete_related_insns (insn);
gcc_assert (GET_CODE (pat) == SEQUENCE);
- after = trial;
- for (i = 0; i < XVECLEN (pat, 0); i++)
- {
- rtx this_insn = XVECEXP (pat, 0, i);
- add_insn_after (this_insn, after, NULL);
- after = this_insn;
- }
+ add_insn_after (delay_insn, trial, NULL);
+ after = delay_insn;
+ for (i = 1; i < XVECLEN (pat, 0); i++)
+ after = emit_copy_of_insn_after (XVECEXP (pat, 0, i), after);
delete_scheduled_jump (delay_insn);
continue;
}
}
/* If the first insn at TARGET_LABEL is redundant with a previous
- insn, redirect the jump to the following insn process again. */
- trial = next_active_insn (target_label);
+ insn, redirect the jump to the following insn and process again.
+ We use next_real_insn instead of next_active_insn so we
+ don't skip USE-markers, or we'll end up with incorrect
+ liveness info. */
+ trial = next_real_insn (target_label);
if (trial && GET_CODE (PATTERN (trial)) != SEQUENCE
&& redundant_insn (trial, insn, 0)
&& ! can_throw_internal (trial))
We do this by deleting the INSN containing the SEQUENCE, then
re-emitting the insns separately, and then deleting the jump.
This allows the count of the jump target to be properly
- decremented. */
+ decremented.
- /* Clear the from target bit, since these insns are no longer
+ Note that we need to change the INSN_UID of the re-emitted insns
+ since it is used to hash the insns for mark_target_live_regs and
+ the re-emitted insns will no longer be wrapped up in a SEQUENCE.
+
+ Clear the from target bit, since these insns are no longer
in delay slots. */
for (i = 0; i < XVECLEN (pat, 0); i++)
INSN_FROM_TARGET_P (XVECEXP (pat, 0, i)) = 0;
trial = PREV_INSN (insn);
delete_related_insns (insn);
gcc_assert (GET_CODE (pat) == SEQUENCE);
- after = trial;
- for (i = 0; i < XVECLEN (pat, 0); i++)
- {
- rtx this_insn = XVECEXP (pat, 0, i);
- add_insn_after (this_insn, after, NULL);
- after = this_insn;
- }
+ add_insn_after (delay_insn, trial, NULL);
+ after = delay_insn;
+ for (i = 1; i < XVECLEN (pat, 0); i++)
+ after = emit_copy_of_insn_after (XVECEXP (pat, 0, i), after);
delete_scheduled_jump (delay_insn);
continue;
}
static void move_bb_info (basic_block, basic_block);
static void remove_empty_bb (basic_block, bool);
+static void sel_merge_blocks (basic_block, basic_block);
static void sel_remove_loop_preheader (void);
static bool insn_is_the_only_one_in_bb_p (insn_t);
maybe_tidy_empty_bb (basic_block bb, bool recompute_toporder_p)
{
basic_block succ_bb, pred_bb;
+ VEC (basic_block, heap) *dom_bbs;
edge e;
edge_iterator ei;
bool rescan_p;
succ_bb = single_succ (bb);
rescan_p = true;
pred_bb = NULL;
+ dom_bbs = NULL;
/* Redirect all non-fallthru edges to the next bb. */
while (rescan_p)
if (!(e->flags & EDGE_FALLTHRU))
{
+ /* We will update dominators here only when we'll get
+ an unreachable block when redirecting, otherwise
+ sel_redirect_edge_and_branch will take care of it. */
+ if (e->dest != bb
+ && single_pred_p (e->dest))
+ VEC_safe_push (basic_block, heap, dom_bbs, e->dest);
recompute_toporder_p |= sel_redirect_edge_and_branch (e, succ_bb);
rescan_p = true;
break;
}
}
- /* If it is possible - merge BB with its predecessor. */
if (can_merge_blocks_p (bb->prev_bb, bb))
sel_merge_blocks (bb->prev_bb, bb);
else
- /* Otherwise this is a block without fallthru predecessor.
- Just delete it. */
{
+ /* This is a block without fallthru predecessor. Just delete it. */
gcc_assert (pred_bb != NULL);
if (in_current_region_p (pred_bb))
remove_empty_bb (bb, true);
}
+ if (!VEC_empty (basic_block, dom_bbs))
+ {
+ VEC_safe_push (basic_block, heap, dom_bbs, succ_bb);
+ iterate_fix_dominators (CDI_DOMINATORS, dom_bbs, false);
+ VEC_free (basic_block, heap, dom_bbs);
+ }
+
if (recompute_toporder_p)
sel_recompute_toporder ();
#ifdef ENABLE_CHECKING
verify_backedges ();
+ verify_dominators (CDI_DOMINATORS);
#endif
return true;
static void
sel_remove_bb (basic_block bb, bool remove_from_cfg_p)
{
+ unsigned idx = bb->index;
+
gcc_assert (bb != NULL && BB_NOTE_LIST (bb) == NULL_RTX);
remove_bb_from_region (bb);
return_bb_to_pool (bb);
- bitmap_clear_bit (blocks_to_reschedule, bb->index);
+ bitmap_clear_bit (blocks_to_reschedule, idx);
if (remove_from_cfg_p)
- delete_and_free_basic_block (bb);
+ {
+ basic_block succ = single_succ (bb);
+ delete_and_free_basic_block (bb);
+ set_immediate_dominator (CDI_DOMINATORS, succ,
+ recompute_dominator (CDI_DOMINATORS, succ));
+ }
- rgn_setup_region (CONTAINING_RGN (bb->index));
+ rgn_setup_region (CONTAINING_RGN (idx));
}
/* Concatenate info of EMPTY_BB to info of MERGE_BB. */
}
-/* Remove an empty basic block EMPTY_BB. When MERGE_UP_P is true, we put
- EMPTY_BB's note lists into its predecessor instead of putting them
- into the successor. When REMOVE_FROM_CFG_P is true, also remove
- the empty block. */
-void
-sel_remove_empty_bb (basic_block empty_bb, bool merge_up_p,
- bool remove_from_cfg_p)
-{
- basic_block merge_bb;
-
- gcc_assert (sel_bb_empty_p (empty_bb));
-
- if (merge_up_p)
- {
- merge_bb = empty_bb->prev_bb;
- gcc_assert (EDGE_COUNT (empty_bb->preds) == 1
- && EDGE_PRED (empty_bb, 0)->src == merge_bb);
- }
- else
- {
- edge e;
- edge_iterator ei;
-
- merge_bb = bb_next_bb (empty_bb);
-
- /* Redirect incoming edges (except fallthrough one) of EMPTY_BB to its
- successor block. */
- for (ei = ei_start (empty_bb->preds);
- (e = ei_safe_edge (ei)); )
- {
- if (! (e->flags & EDGE_FALLTHRU))
- sel_redirect_edge_and_branch (e, merge_bb);
- else
- ei_next (&ei);
- }
-
- gcc_assert (EDGE_COUNT (empty_bb->succs) == 1
- && EDGE_SUCC (empty_bb, 0)->dest == merge_bb);
- }
-
- move_bb_info (merge_bb, empty_bb);
- remove_empty_bb (empty_bb, remove_from_cfg_p);
-}
-
/* Remove EMPTY_BB. If REMOVE_FROM_CFG_P is false, remove EMPTY_BB from
region, but keep it in CFG. */
static void
}
/* Merge basic block B into basic block A. */
-void
+static void
sel_merge_blocks (basic_block a, basic_block b)
{
- sel_remove_empty_bb (b, true, false);
- merge_blocks (a, b);
+ gcc_assert (sel_bb_empty_p (b)
+ && EDGE_COUNT (b->preds) == 1
+ && EDGE_PRED (b, 0)->src == b->prev_bb);
+ move_bb_info (b->prev_bb, b);
+ remove_empty_bb (b, false);
+ merge_blocks (a, b);
change_loops_latches (b, a);
}
void
sel_redirect_edge_and_branch_force (edge e, basic_block to)
{
- basic_block jump_bb, src;
+ basic_block jump_bb, src, orig_dest = e->dest;
int prev_max_uid;
rtx jump;
- gcc_assert (!sel_bb_empty_p (e->src));
+ /* This function is now used only for bookkeeping code creation, where
+ we'll never get the single pred of orig_dest block and thus will not
+ hit unreachable blocks when updating dominator info. */
+ gcc_assert (!sel_bb_empty_p (e->src)
+ && !single_pred_p (orig_dest));
src = e->src;
prev_max_uid = get_max_uid ();
jump = find_new_jump (src, jump_bb, prev_max_uid);
if (jump)
sel_init_new_insn (jump, INSN_INIT_TODO_LUID | INSN_INIT_TODO_SIMPLEJUMP);
+ set_immediate_dominator (CDI_DOMINATORS, to,
+ recompute_dominator (CDI_DOMINATORS, to));
+ set_immediate_dominator (CDI_DOMINATORS, orig_dest,
+ recompute_dominator (CDI_DOMINATORS, orig_dest));
}
/* A wrapper for redirect_edge_and_branch. Return TRUE if blocks connected by
sel_redirect_edge_and_branch (edge e, basic_block to)
{
bool latch_edge_p;
- basic_block src;
+ basic_block src, orig_dest = e->dest;
int prev_max_uid;
rtx jump;
edge redirected;
bool recompute_toporder_p = false;
+ bool maybe_unreachable = single_pred_p (orig_dest);
latch_edge_p = (pipelining_p
&& current_loop_nest
if (jump)
sel_init_new_insn (jump, INSN_INIT_TODO_LUID | INSN_INIT_TODO_SIMPLEJUMP);
+ /* Only update dominator info when we don't have unreachable blocks.
+ Otherwise we'll update in maybe_tidy_empty_bb. */
+ if (!maybe_unreachable)
+ {
+ set_immediate_dominator (CDI_DOMINATORS, to,
+ recompute_dominator (CDI_DOMINATORS, to));
+ set_immediate_dominator (CDI_DOMINATORS, orig_dest,
+ recompute_dominator (CDI_DOMINATORS, orig_dest));
+ }
return recompute_toporder_p;
}
if (BB_END (prev_bb) == bb_note (prev_bb))
free_data_sets (prev_bb);
}
+
+ set_immediate_dominator (CDI_DOMINATORS, next_bb,
+ recompute_dominator (CDI_DOMINATORS,
+ next_bb));
}
}
VEC_free (basic_block, heap, preheader_blocks);
extern bool tidy_control_flow (basic_block, bool);
extern void free_bb_note_pool (void);
-extern void sel_remove_empty_bb (basic_block, bool, bool);
extern void purge_empty_blocks (void);
extern basic_block sel_split_edge (edge);
extern basic_block sel_create_recovery_block (insn_t);
-extern void sel_merge_blocks (basic_block, basic_block);
extern bool sel_redirect_edge_and_branch (edge, basic_block);
extern void sel_redirect_edge_and_branch_force (edge, basic_block);
extern void sel_init_pipelining (void);
BB is present in the cfg. */
if (bb == NULL
|| bb->index < NUM_FIXED_BLOCKS
- || bb->index >= n_basic_blocks
+ || bb->index >= last_basic_block
|| BASIC_BLOCK (bb->index) != bb
|| last_stmt (bb) == stmt
|| !gimple_call_noreturn_p (stmt))
CONSTRUCTOR_ELTS (*tp));
*tp = new_tree;
}
+ else if (code == STATEMENT_LIST)
+ /* We used to just abort on STATEMENT_LIST, but we can run into them
+ with statement-expressions (c++/40975). */
+ copy_statement_list (tp);
else if (TREE_CODE_CLASS (code) == tcc_type)
*walk_subtrees = 0;
else if (TREE_CODE_CLASS (code) == tcc_declaration)
*walk_subtrees = 0;
else if (TREE_CODE_CLASS (code) == tcc_constant)
*walk_subtrees = 0;
- else
- gcc_assert (code != STATEMENT_LIST);
return NULL_TREE;
}
{
enum tree_code subcode = gimple_assign_rhs_code (stmt);
- expr->type = NULL_TREE;
-
switch (get_gimple_rhs_class (subcode))
{
case GIMPLE_SINGLE_RHS:
expr->kind = EXPR_SINGLE;
+ expr->type = TREE_TYPE (gimple_assign_rhs1 (stmt));
expr->ops.single.rhs = gimple_assign_rhs1 (stmt);
break;
case GIMPLE_UNARY_RHS:
build_arrays (gimple swtch)
{
tree arr_index_type;
- tree tidx, sub;
+ tree tidx, sub, utype;
gimple stmt;
gimple_stmt_iterator gsi;
int i;
gsi = gsi_for_stmt (swtch);
arr_index_type = build_index_type (info.range_size);
- tidx = make_rename_temp (arr_index_type, "csti");
- sub = fold_build2 (MINUS_EXPR, TREE_TYPE (info.index_expr), info.index_expr,
- fold_convert (TREE_TYPE (info.index_expr),
- info.range_min));
- sub = force_gimple_operand_gsi (&gsi, fold_convert (arr_index_type, sub),
- false, NULL, true, GSI_SAME_STMT);
+
+ /* Make sure we do not generate arithmetics in a subrange. */
+ if (TREE_TYPE (TREE_TYPE (info.index_expr)))
+ utype = lang_hooks.types.type_for_mode
+ (TYPE_MODE (TREE_TYPE (TREE_TYPE (info.index_expr))), 1);
+ else
+ utype = lang_hooks.types.type_for_mode
+ (TYPE_MODE (TREE_TYPE (info.index_expr)), 1);
+
+ tidx = make_rename_temp (utype, "csui");
+ sub = fold_build2 (MINUS_EXPR, utype,
+ fold_convert (utype, info.index_expr),
+ fold_convert (utype, info.range_min));
+ sub = force_gimple_operand_gsi (&gsi, sub, false, NULL, true, GSI_SAME_STMT);
stmt = gimple_build_assign (tidx, sub);
gsi_insert_before (&gsi, stmt, GSI_SAME_STMT);
gimple label1, label2, label3;
tree utype;
- tree tmp_u;
- tree cast;
- gimple cast_assign, minus_assign;
- tree ulb, minus;
+ tree tidx;
tree bound;
gimple cond_stmt;
gcc_assert (info.default_values);
bb0 = gimple_bb (swtch);
- /* Make sure we do not generate arithmetics in a subrange. */
- if (TREE_TYPE (TREE_TYPE (info.index_expr)))
- utype = lang_hooks.types.type_for_mode
- (TYPE_MODE (TREE_TYPE (TREE_TYPE (info.index_expr))), 1);
- else
- utype = lang_hooks.types.type_for_mode
- (TYPE_MODE (TREE_TYPE (info.index_expr)), 1);
+ tidx = gimple_assign_lhs (info.arr_ref_first);
+ utype = TREE_TYPE (tidx);
/* (end of) block 0 */
gsi = gsi_for_stmt (info.arr_ref_first);
- tmp_u = make_rename_temp (utype, "csui");
-
- cast = fold_convert (utype, info.index_expr);
- cast_assign = gimple_build_assign (tmp_u, cast);
- find_new_referenced_vars (cast_assign);
- gsi_insert_before (&gsi, cast_assign, GSI_SAME_STMT);
- mark_symbols_for_renaming (cast_assign);
-
- ulb = fold_convert (utype, info.range_min);
- minus = fold_build2 (MINUS_EXPR, utype, tmp_u, ulb);
- minus = force_gimple_operand_gsi (&gsi, minus, false, NULL, true,
- GSI_SAME_STMT);
- minus_assign = gimple_build_assign (tmp_u, minus);
- find_new_referenced_vars (minus_assign);
- gsi_insert_before (&gsi, minus_assign, GSI_SAME_STMT);
- mark_symbols_for_renaming (minus_assign);
+ gsi_next (&gsi);
bound = fold_convert (utype, info.range_size);
- cond_stmt = gimple_build_cond (LE_EXPR, tmp_u, bound, NULL_TREE, NULL_TREE);
+ cond_stmt = gimple_build_cond (LE_EXPR, tidx, bound, NULL_TREE, NULL_TREE);
find_new_referenced_vars (cond_stmt);
gsi_insert_before (&gsi, cond_stmt, GSI_SAME_STMT);
mark_symbols_for_renaming (cond_stmt);
/* block 2 */
- gsi = gsi_for_stmt (info.arr_ref_first);
label2 = gimple_build_label (label_decl2);
gsi_insert_before (&gsi, label2, GSI_SAME_STMT);
last_assign = gen_def_assigns (&gsi);
/* block 1 */
- gsi = gsi_for_stmt (info.arr_ref_first);
label1 = gimple_build_label (label_decl1);
gsi_insert_before (&gsi, label1, GSI_SAME_STMT);
integer_one_node);
}
+ if (a_acc || m_acc)
+ {
+ /* When the tail call elimination using accumulators is performed,
+ statements adding the accumulated value are inserted at all exits.
+ This turns all other tail calls to non-tail ones. */
+ opt_tailcalls = false;
+ }
+
for (; tailcalls; tailcalls = next)
{
next = tailcalls->next;
op0 + op1 == 0, so we cannot claim that the sum is in ~[0,0].
Note that we are guaranteed to have vr0.type == vr1.type at
this point. */
- if (code == PLUS_EXPR && vr0.type == VR_ANTI_RANGE)
+ if (vr0.type == VR_ANTI_RANGE)
{
- set_value_range_to_varying (vr);
- return;
+ if (code == PLUS_EXPR)
+ {
+ set_value_range_to_varying (vr);
+ return;
+ }
+ /* For MIN_EXPR and MAX_EXPR with two VR_ANTI_RANGEs,
+ the resulting VR_ANTI_RANGE is the same - intersection
+ of the two ranges. */
+ min = vrp_int_const_binop (MAX_EXPR, vr0.min, vr1.min);
+ max = vrp_int_const_binop (MIN_EXPR, vr0.max, vr1.max);
+ }
+ else
+ {
+ /* For operations that make the resulting range directly
+ proportional to the original ranges, apply the operation to
+ the same end of each range. */
+ min = vrp_int_const_binop (code, vr0.min, vr1.min);
+ max = vrp_int_const_binop (code, vr0.max, vr1.max);
}
-
- /* For operations that make the resulting range directly
- proportional to the original ranges, apply the operation to
- the same end of each range. */
- min = vrp_int_const_binop (code, vr0.min, vr1.min);
- max = vrp_int_const_binop (code, vr0.max, vr1.max);
}
else if (code == MULT_EXPR
|| code == TRUNC_DIV_EXPR