static int max_loop_num;
-
-
-
/* Bound on pseudo register number before loop optimization.
A pseudo has valid regscan info if its number is < max_reg_before_loop. */
unsigned int max_reg_before_loop;
static void force_movables PARAMS ((struct movables *));
static void combine_movables PARAMS ((struct movables *, struct loop_regs *));
static int regs_match_p PARAMS ((rtx, rtx, struct movables *));
-static int rtx_equal_for_loop_p PARAMS ((rtx, rtx, struct movables *,
+static int rtx_equal_for_loop_p PARAMS ((rtx, rtx, struct movables *,
struct loop_regs *));
static void add_label_notes PARAMS ((rtx, rtx));
static void move_movables PARAMS ((struct loop *loop, struct movables *,
static rtx combine_givs_p PARAMS ((struct induction *, struct induction *));
static void combine_givs PARAMS ((struct loop_regs *, struct iv_class *));
struct recombine_givs_stats;
-static int find_life_end PARAMS ((const struct loop *, rtx,
+static int find_life_end PARAMS ((const struct loop *, rtx,
struct recombine_givs_stats *,
rtx, rtx));
static void recombine_givs PARAMS ((const struct loop *, struct iv_class *,
static void loop_dump_aux PARAMS ((const struct loop *, FILE *, int));
void debug_loop PARAMS ((const struct loop *));
-typedef struct rtx_pair {
+typedef struct rtx_pair
+{
rtx r1;
rtx r2;
} rtx_pair;
static int compute_luids PARAMS ((rtx, rtx, int));
static int biv_elimination_giv_has_0_offset PARAMS ((struct induction *,
- struct induction *, rtx));
+ struct induction *,
+ rtx));
\f
/* Benefit penalty, if a giv is not replaceable, i.e. must emit an insn to
copy the value of the strength reduced giv to its original register. */
regs->num = nregs;
- count_loop_regs_set (loop, regs->may_not_optimize, regs->single_usage,
+ count_loop_regs_set (loop, regs->may_not_optimize, regs->single_usage,
&insn_count, nregs);
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
&& rtx_equal_p (m->set_src, y))
return 1;
}
- else if (GET_CODE (y) == REG && VARRAY_INT (regs->set_in_loop,
+ else if (GET_CODE (y) == REG && VARRAY_INT (regs->set_in_loop,
REGNO (y)) == -2
&& CONSTANT_P (x))
{
{
rtx mem = gen_rtx_MEM (BLKmode, const0_rtx);
- loop_info->store_mems
+ loop_info->store_mems
= gen_rtx_EXPR_LIST (VOIDmode, mem, loop_info->store_mems);
}
if (loop_info->unknown_constant_address_altered)
rtx mem = gen_rtx_MEM (BLKmode, const0_rtx);
RTX_UNCHANGING_P (mem) = 1;
- loop_info->store_mems
+ loop_info->store_mems
= gen_rtx_EXPR_LIST (VOIDmode, mem, loop_info->store_mems);
}
}
cont. */
if ((INSN_LUID (label)
< INSN_LUID (loop->cont))
- && (INSN_LUID (label)
- > INSN_LUID (loop->start))
+ && (INSN_LUID (label) > INSN_LUID (loop->start))
/* And if there is no later destination already
recorded. */
&& (! loop->cont_dominator
off LABEL_OUTSIDE_LOOP_P bit. */
if (JUMP_LABEL (insn))
{
- for (q = 0,
- r = this_loop->exit_labels;
- r; q = r, r = LABEL_NEXTREF (r))
+ for (q = 0, r = this_loop->exit_labels;
+ r;
+ q = r, r = LABEL_NEXTREF (r))
if (XEXP (r, 0) == JUMP_LABEL (insn))
{
LABEL_OUTSIDE_LOOP_P (r) = 0;
/* Count number of memory writes.
This affects heuristics in strength_reduce. */
loop_info->num_mem_sets++;
-
+
/* BLKmode MEM means all memory is clobbered. */
if (GET_MODE (x) == BLKmode)
{
loop_info->unknown_constant_address_altered = 1;
else
loop_info->unknown_address_altered = 1;
-
+
return;
}
-
- loop_info->store_mems = gen_rtx_EXPR_LIST (VOIDmode, x,
+
+ loop_info->store_mems = gen_rtx_EXPR_LIST (VOIDmode, x,
loop_info->store_mems);
}
v->maybe_dead = 1;
}
else if (v->giv_type == DEST_REG
- && REGNO_FIRST_UID (REGNO (v->dest_reg)) == INSN_UID (v->insn))
+ && REGNO_FIRST_UID (REGNO (v->dest_reg)) == INSN_UID (v->insn))
{
struct induction *v1;
if (! biv_increment_seen
&& reg_set_p (v->src_reg, PATTERN (p)))
biv_increment_seen = 1;
-
+
if (reg_mentioned_p (v->dest_reg, PATTERN (p)))
{
if (biv_increment_seen)
inc_val, mult_val, location))
return 1;
}
- /* ... fall through ... */
+ /* Fall through. */
/* Can accept constant setting of biv only when inside inner most loop.
Otherwise, a biv of an inner loop may be incorrectly recognized
if (loop->level == 1
&& GET_MODE_CLASS (mode) != MODE_CC
&& GET_MODE_CLASS (GET_MODE (dest_reg)) != MODE_CC)
- {
+ {
/* Possible bug here? Perhaps we don't know the mode of X. */
*inc_val = convert_modes (GET_MODE (dest_reg), mode, x, 0);
*mult_val = const0_rtx;
case ZERO_EXTEND:
case TRUNCATE:
/* Conditionally recognize extensions of simple IVs. After we've
- computed loop traversal counts and verified the range of the
+ computed loop traversal counts and verified the range of the
source IV, we'll reevaluate this as a GIV. */
if (*ext_val == NULL_RTX)
{
}
goto do_default;
- case REG:
+ case REG:
/* If this is a new register, we can't deal with it. */
if (REGNO (x) >= max_reg_before_loop)
return 0;
{
int i = m->consec;
tem = m->insn;
- do { tem = NEXT_INSN (tem); } while (--i > 0);
+ do
+ {
+ tem = NEXT_INSN (tem);
+ }
+ while (--i > 0);
tem = find_reg_note (tem, REG_EQUAL, NULL_RTX);
if (tem)
return tem;
}
else if (GET_CODE (tem) == CONST
- && GET_CODE (XEXP (tem, 0)) == PLUS
- && GET_CODE (XEXP (XEXP (tem, 0), 0)) == SYMBOL_REF
- && GET_CODE (XEXP (XEXP (tem, 0), 1)) == CONST_INT)
+ && GET_CODE (XEXP (tem, 0)) == PLUS
+ && GET_CODE (XEXP (XEXP (tem, 0), 0)) == SYMBOL_REF
+ && GET_CODE (XEXP (XEXP (tem, 0), 1)) == CONST_INT)
{
tem = simplify_giv_expr (loop, XEXP (tem, 0),
ext_val, benefit);
a = ra, b = ob;
else
{
- /* Indicates an extra register in B. Strip one level from B and
+ /* Indicates an extra register in B. Strip one level from B and
recurse, hoping B was the higher order expression. */
ob = express_from_1 (a, ob, mult);
if (ob == NULL_RTX)
info_ok = 1;
start_val = INTVAL (bl->initial_value);
u_start_val = start_val;
-
+
neg_incr = 0, abs_incr = INTVAL (incr);
if (INTVAL (incr) < 0)
neg_incr = 1, abs_incr = -abs_incr;
s_end_val = u_end_val;
u_max = GET_MODE_MASK (biv_mode);
s_max = u_max >> 1;
-
+
/* Check zero extension of biv ok. */
if (start_val >= 0
/* Check for host arithmatic overflow. */
{
ze_ok = 1;
}
-
+
/* Check sign extension of biv ok. */
/* ??? While it is true that overflow with signed and pointer
arithmetic is undefined, I fear too many programmers don't
case TRUNCATE:
/* We don't know whether this value is being used as either
signed or unsigned, so to safely truncate we must satisfy
- both. The initial check here verifies the BIV itself;
+ both. The initial check here verifies the BIV itself;
once that is successful we may check its range wrt the
derived GIV. */
if (se_ok && ze_ok)
{
if (loop_dump_stream)
{
- fprintf(loop_dump_stream,
- "Verified ext dependant giv at %d of reg %d\n",
- INSN_UID (v->insn), bl->regno);
+ fprintf (loop_dump_stream,
+ "Verified ext dependant giv at %d of reg %d\n",
+ INSN_UID (v->insn), bl->regno);
}
}
else
why = "biv iteration info incomplete";
}
- fprintf(loop_dump_stream,
- "Failed ext dependant giv at %d, %s\n",
- INSN_UID (v->insn), why);
+ fprintf (loop_dump_stream,
+ "Failed ext dependant giv at %d, %s\n",
+ INSN_UID (v->insn), why);
}
v->ignore = 1;
}
DEST_ADDR targets on hosts with reg+reg addressing, though it can
be seen elsewhere as well. */
if (g1->giv_type == DEST_REG
- && (single_use = VARRAY_RTX (regs->single_usage,
+ && (single_use = VARRAY_RTX (regs->single_usage,
REGNO (g1->dest_reg)))
&& single_use != const0_rtx)
continue;
p = PREV_INSN (p);
if (! INSN_P (p))
continue;
- ends_need_computing -= find_life_end (loop, PATTERN (p),
+ ends_need_computing -= find_life_end (loop, PATTERN (p),
stats, p, biv);
}
while (ends_need_computing);
rtx jump1;
if ((jump1 = prev_nonnote_insn (first_compare)) != loop->cont)
if (GET_CODE (jump1) == JUMP_INSN)
- return 0;
+ return 0;
}
/* Check all of the bivs to see if the compare uses one of them.
if (v->giv_type == DEST_REG
&& reg_mentioned_p (v->dest_reg,
PATTERN (loop_info->first_loop_store_insn))
- && loop_insn_first_p (loop_info->first_loop_store_insn,
+ && loop_insn_first_p (loop_info->first_loop_store_insn,
v->insn))
reversible_mem_store = 0;
}
&& ! loop_info->has_volatile
&& reversible_mem_store
&& (bl->giv_count + bl->biv_count + loop_info->num_mem_sets
- + the_movables.num + compare_and_branch == insn_count)
+ + the_movables.num + compare_and_branch == insn_count)
&& (bl == ivs->loop_iv_list && bl->next == 0))
|| no_use_except_counting)
{
jump_label = XEXP (SET_SRC (PATTERN (PREV_INSN (loop_end))), 1);
if (jump_label == pc_rtx)
jump_label = XEXP (SET_SRC (PATTERN (PREV_INSN (loop_end))), 2);
- new_add_val = GEN_INT (- INTVAL (bl->biv->add_val));
+ new_add_val = GEN_INT (-INTVAL (bl->biv->add_val));
/* Set start_value; if this is not a CONST_INT, we need
to generate a SUB.
/* Inc LABEL_NUSES so that delete_insn will
not delete the label. */
- LABEL_NUSES (XEXP (jump_label, 0)) ++;
+ LABEL_NUSES (XEXP (jump_label, 0))++;
/* Emit an insn after the end of the loop to set the biv's
proper exit value if it is used anywhere outside the loop. */
in cse.c */
while (GET_RTX_CLASS (code) == '<'
- && op1 == CONST0_RTX (GET_MODE (op0))
+ && op1 == CONST0_RTX (GET_MODE (op0))
&& op0 != want_reg)
{
/* Set non-zero when we find something of interest. */
else
loop_info->mems_allocated = 32;
- loop_info->mems = (loop_mem_info*)
+ loop_info->mems = (loop_mem_info *)
xrealloc (loop_info->mems,
loop_info->mems_allocated * sizeof (loop_mem_info));
}
&& GET_CODE (SET_DEST (set)) == REG
&& REGNO (SET_DEST (set)) >= FIRST_PSEUDO_REGISTER
&& REGNO (SET_DEST (set)) < last_max_reg
- && VARRAY_INT (regs->n_times_set,
+ && VARRAY_INT (regs->n_times_set,
REGNO (SET_DEST (set))) == 1
&& rtx_equal_p (SET_SRC (set), mem))
SET_REGNO_REG_SET (&load_copies, REGNO (SET_DEST (set)));
- /* See if this copies the mem from a register that isn't
+ /* See if this copies the mem from a register that isn't
modified afterwards. We'll try to remove the
redundant copy later on by doing a little register
renaming and copy propagation. This will help
to untangle things for the BIV detection code. */
- if (set
- && ! maybe_never
- && GET_CODE (SET_SRC (set)) == REG
- && REGNO (SET_SRC (set)) >= FIRST_PSEUDO_REGISTER
- && REGNO (SET_SRC (set)) < last_max_reg
- && VARRAY_INT (regs->n_times_set, REGNO (SET_SRC (set))) == 1
- && rtx_equal_p (SET_DEST (set), mem))
- SET_REGNO_REG_SET (&store_copies, REGNO (SET_SRC (set)));
-
- /* Replace the memory reference with the shadow register. */
+ if (set
+ && ! maybe_never
+ && GET_CODE (SET_SRC (set)) == REG
+ && REGNO (SET_SRC (set)) >= FIRST_PSEUDO_REGISTER
+ && REGNO (SET_SRC (set)) < last_max_reg
+ && VARRAY_INT (regs->n_times_set, REGNO (SET_SRC (set))) == 1
+ && rtx_equal_p (SET_DEST (set), mem))
+ SET_REGNO_REG_SET (&store_copies, REGNO (SET_SRC (set)));
+
+ /* Replace the memory reference with the shadow register. */
replace_loop_mems (p, loop_info->mems[i].mem,
loop_info->mems[i].reg);
}
}
}
-
/* Try to replace occurrences of pseudo REGNO with REPLACEMENT within
loop LOOP if the order of the sets of these registers can be
swapped. There must be exactly one insn within the loop that sets
{
rtx prev_insn;
rtx prev_set;
-
+
/* Some DEF-USE info would come in handy here to make this
function more general. For now, just check the previous insn
which is the most likely candidate for setting REGNO. */
-
+
prev_insn = PREV_INSN (insn);
-
+
if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
&& (prev_set = single_set (prev_insn))
&& GET_CODE (SET_DEST (prev_set)) == REG
/* We have:
(set (reg regno) (expr))
(set (reg new_regno) (reg regno))
-
+
so try converting this to:
(set (reg new_regno) (expr))
(set (reg regno) (reg new_regno))
if (apply_change_group ())
{
if (loop_dump_stream)
- fprintf (loop_dump_stream,
- " Swapped set of reg %d at %d with reg %d at %d.\n",
- regno, INSN_UID (insn),
+ fprintf (loop_dump_stream,
+ " Swapped set of reg %d at %d with reg %d at %d.\n",
+ regno, INSN_UID (insn),
new_regno, INSN_UID (prev_insn));
/* Update first use of REGNO. */
}
}
-
/* Replace MEM with its associated pseudo register. This function is
called from load_mems via for_each_rtx. DATA is actually a pointer
to a structure describing the instruction currently being scanned
rtx *mem;
void *data;
{
- loop_replace_args *args = (loop_replace_args *)data;
+ loop_replace_args *args = (loop_replace_args *) data;
rtx m = *mem;
if (m == NULL_RTX)
return 0;
}
-
static void
replace_loop_mems (insn, mem, reg)
- rtx insn;
- rtx mem;
- rtx reg;
-{
+ rtx insn;
+ rtx mem;
+ rtx reg;
+{
loop_replace_args args;
args.insn = insn;
for_each_rtx (&insn, replace_loop_mem, &args);
}
-
/* Replace one register with another. Called through for_each_rtx; PX points
- to the rtx being scanned. DATA is actually a pointer to
+ to the rtx being scanned. DATA is actually a pointer to
a structure of arguments. */
static int
void *data;
{
rtx x = *px;
- loop_replace_args *args = (loop_replace_args *)data;
+ loop_replace_args *args = (loop_replace_args *) data;
if (x == NULL_RTX)
return 0;
return 0;
}
-
static void
replace_loop_regs (insn, reg, replacement)
rtx insn;
for_each_rtx (&insn, replace_loop_reg, &args);
}
-
/* Replace occurrences of the old exit label for the loop with the new
one. DATA is an rtx_pair containing the old and new labels,
respectively. */
#define LOOP_INSN_UID(INSN) ((INSN) ? INSN_UID (INSN) : -1)
-static void loop_dump_aux (loop, file, verbose)
+static void
+loop_dump_aux (loop, file, verbose)
const struct loop *loop;
FILE *file;
int verbose;
|| GET_CODE (PREV_INSN (loop->first->head)) != NOTE
|| NOTE_LINE_NUMBER (PREV_INSN (loop->first->head))
!= NOTE_INSN_LOOP_BEG)
- fprintf (file, ";; No NOTE_INSN_LOOP_BEG at %d\n",
+ fprintf (file, ";; No NOTE_INSN_LOOP_BEG at %d\n",
INSN_UID (PREV_INSN (loop->first->head)));
if (! NEXT_INSN (loop->last->end)
|| GET_CODE (NEXT_INSN (loop->last->end)) != NOTE
LOOP_INSN_UID (loop->end));
fprintf (file, ";; top %d (%d), scan start %d (%d)\n",
LOOP_BLOCK_NUM (loop->top),
- LOOP_INSN_UID (loop->top) ,
+ LOOP_INSN_UID (loop->top),
LOOP_BLOCK_NUM (loop->scan_start),
LOOP_INSN_UID (loop->scan_start));
fprintf (file, ";; exit_count %d", loop->exit_count);
}
}
fputs ("\n", file);
-
+
/* This can happen when a marked loop appears as two nested loops,
say from while (a || b) {}. The inner loop won't match
the loop markers but the outer one will. */
fprintf (file, ";; NOTE_INSN_LOOP_CONT not in loop latch\n");
}
}
-
/* Call this function from the debugger to dump LOOP. */
#define LOOP_UNROLL 1
#define LOOP_BCT 2
-
/* Get the loop info pointer of a loop. */
-#define LOOP_INFO(LOOP) ((struct loop_info *) (LOOP)->aux)
+#define LOOP_INFO(LOOP) ((struct loop_info *) (LOOP)->aux)
/* Get a pointer to the loop registers structure. */
#define LOOP_REGS(LOOP) (&LOOP_INFO (loop)->regs)
/* An enum for the two different types of givs, those that are used
as memory addresses and those that are calculated into registers. */
-enum g_types { DEST_ADDR, DEST_REG };
+enum g_types
+{
+ DEST_ADDR,
+ DEST_REG
+};
/* A `struct induction' is created for every instruction that sets
an induction variable (either a biv or a giv). */
/* For a biv, this is the place where add_val
was found. */
enum machine_mode mode; /* The mode of this biv or giv */
- enum machine_mode mem_mode; /* For DEST_ADDR, mode of the memory object. */
+ enum machine_mode mem_mode; /* For DEST_ADDR, mode of the memory object. */
rtx mult_val; /* Multiplicative factor for src_reg. */
rtx add_val; /* Additive constant for that product. */
int benefit; /* Gain from eliminating this insn. */
unsigned always_executed : 1; /* 1 if this set occurs each iteration. */
unsigned maybe_multiple : 1; /* Only used for a biv and 1 if this biv
update may be done multiple times per
- iteration. */
+ iteration. */
unsigned cant_derive : 1; /* For giv's, 1 if this giv cannot derive
another giv. This occurs in many cases
where a giv's lifetime spans an update to
- a biv. */
+ a biv. */
unsigned maybe_dead : 1; /* 1 if this giv might be dead. In that case,
we won't use it to eliminate a biv, it
- would probably lose. */
+ would probably lose. */
unsigned auto_inc_opt : 1; /* 1 if this giv had its increment output next
- to it to try to form an auto-inc address. */
+ to it to try to form an auto-inc address. */
unsigned unrolled : 1; /* 1 if new register has been allocated and
initialized in unrolled loop. */
unsigned shared : 1;
- unsigned no_const_addval : 1; /* 1 if add_val does not contain a const. */
+ unsigned no_const_addval : 1; /* 1 if add_val does not contain a const. */
int lifetime; /* Length of life of this giv */
rtx derive_adjustment; /* If nonzero, is an adjustment to be
subtracted from add_val when this giv
derives another. This occurs when the
- giv spans a biv update by incrementation. */
+ giv spans a biv update by incrementation. */
rtx ext_dependant; /* If nonzero, is a sign or zero extension
if a biv on which this giv is dependant. */
struct induction *next_iv; /* For givs, links together all givs that are
HOST_WIDE_INT const_adjust; /* Used by loop unrolling, when an address giv
is split, and a constant is eliminated from
the address, the -constant is stored here
- for later use. */
+ for later use. */
int ix; /* Used by recombine_givs, as n index into
the stats array. */
struct induction *same_insn; /* If there are multiple identical givs in
field set, and they all point to the giv
that doesn't have this field set. */
rtx last_use; /* For a giv made from a biv increment, this is
- a substitute for the lifetime information. */
+ a substitute for the lifetime information. */
};
/* A `struct iv_class' is created for each biv. */
-struct iv_class {
+struct iv_class
+{
unsigned int regno; /* Pseudo reg which is the biv. */
int biv_count; /* Number of insns setting this reg. */
struct induction *biv; /* List of all insns that set this reg. */
rtx initial_value; /* Value of reg at loop start */
rtx initial_test; /* Test performed on BIV before loop */
struct iv_class *next; /* Links all class structures together */
- rtx init_insn; /* insn which initializes biv, 0 if none. */
- rtx init_set; /* SET of INIT_INSN, if any. */
+ rtx init_insn; /* insn which initializes biv, 0 if none. */
+ rtx init_set; /* SET of INIT_INSN, if any. */
unsigned incremented : 1; /* 1 if somewhere incremented/decremented */
- unsigned eliminable : 1; /* 1 if plausible candidate for elimination. */
- unsigned nonneg : 1; /* 1 if we added a REG_NONNEG note for this. */
+ unsigned eliminable : 1; /* 1 if plausible candidate for elimination. */
+ unsigned nonneg : 1; /* 1 if we added a REG_NONNEG note for this. */
unsigned reversed : 1; /* 1 if we reversed the loop that this
- biv controls. */
+ biv controls. */
};
-
typedef struct loop_mem_info
{
rtx mem; /* The MEM itself. */
int optimize; /* Nonzero if we can optimize access to this MEM. */
} loop_mem_info;
-
struct loop_ivs
{
/* Indexed by register number, indicates whether or not register is
an induction variable, and if so what type. */
varray_type reg_iv_type;
-
+
/* Indexed by register number, contains pointer to `struct
induction' if register is an induction variable. This holds
general info for all induction variables. */
describing the class (a related group) of induction variables
that the biv belongs to. */
struct iv_class **reg_biv_class;
-
+
/* The head of a list which links together (via the next field)
every iv class for the current loop. */
struct iv_class *loop_iv_list;
unsigned int last_increment_giv;
};
-
struct loop_regs
{
int num;
not known equal to a constant.
After code motion, regs moved have 0 (which is accurate now)
while the failed candidates have the original number of times set.
-
+
Therefore, at all times, == 0 indicates an invariant register;
< 0 a conditionally invariant one. */
varray_type set_in_loop;
is not set negative for a reg whose sets have been made candidates
and not set to 0 for a reg that is moved. */
varray_type n_times_set;
-
+
/* Index by register number, 1 indicates that the register
cannot be moved or strength reduced. */
varray_type may_not_optimize;
-
+
/* Contains the insn in which a register was used if it was used
exactly once; contains const0_rtx if it was used more than once. */
varray_type single_usage;
-
+
/* Nonzero means reg N has already been moved out of one loop.
This reduces the desire to move it out of another. */
char *moved_once;
int multiple_uses;
};
-
/* Information pertaining to a loop. */
struct loop_info
};
/* Definitions used by the basic induction variable discovery code. */
-enum iv_mode { UNKNOWN_INDUCT, BASIC_INDUCT, NOT_BASIC_INDUCT,
- GENERAL_INDUCT };
+enum iv_mode
+{
+ UNKNOWN_INDUCT,
+ BASIC_INDUCT,
+ NOT_BASIC_INDUCT,
+ GENERAL_INDUCT
+};
/* Variables declared in loop.c, but also needed in unroll.c. */
rtx biv_total_increment PARAMS ((struct iv_class *));
unsigned HOST_WIDE_INT loop_iterations PARAMS ((struct loop *));
int precondition_loop_p PARAMS ((const struct loop *,
- rtx *, rtx *, rtx *,
- enum machine_mode *mode));
+ rtx *, rtx *, rtx *,
+ enum machine_mode *mode));
rtx final_biv_value PARAMS ((const struct loop *, struct iv_class *));
rtx final_giv_value PARAMS ((const struct loop *, struct induction *));
void emit_unrolled_add PARAMS ((rtx, rtx, rtx));