mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-03-19 03:50:26 +08:00
i386.md (adddi3_carry_rex64, [...]): Name pattern.
* i386.md (adddi3_carry_rex64, subdi3_carry_rex64): Name pattern. (addhi3_carry, addqi3_carry, subhi3_carry, subqi3_carry): New patterns. (add??cc): New expanders. * i386.c (expand_int_addcc): New function. * i386-protos.h (expand_int_addcc): Declare. * alias.c (memory_modified_1): New static function. (memory_modified): New static varaible. (memory_modified_in_insn_p): New global function. * rtl.h (memory_modified_in_insn_p): Declare. * rtlanal.c (modified_between_p, modified_in_p): Be smart about memory references. * expr.h (emit_conditional_add): Declare. From-SVN: r61038
This commit is contained in:
parent
67d96a1661
commit
7b52eedeed
@ -1,3 +1,20 @@
|
||||
Wed Jan 8 12:10:57 CET 2003 Jan Hubicka <jh@suse.cz>
|
||||
|
||||
* i386.md (adddi3_carry_rex64, subdi3_carry_rex64): Name pattern.
|
||||
(addhi3_carry, addqi3_carry, subhi3_carry, subqi3_carry): New patterns.
|
||||
(add??cc): New expanders.
|
||||
* i386.c (expand_int_addcc): New function.
|
||||
* i386-protos.h (expand_int_addcc): Declare.
|
||||
|
||||
* alias.c (memory_modified_1): New static function.
|
||||
(memory_modified): New static varaible.
|
||||
(memory_modified_in_insn_p): New global function.
|
||||
* rtl.h (memory_modified_in_insn_p): Declare.
|
||||
* rtlanal.c (modified_between_p, modified_in_p): Be smart about memory
|
||||
references.
|
||||
|
||||
* expr.h (emit_conditional_add): Declare.
|
||||
|
||||
2003-01-07 Janis Johnson <janis187@us.ibm.com>
|
||||
|
||||
PR other/8947
|
||||
|
30
gcc/alias.c
30
gcc/alias.c
@ -119,6 +119,7 @@ static int nonlocal_referenced_p_1 PARAMS ((rtx *, void *));
|
||||
static int nonlocal_referenced_p PARAMS ((rtx));
|
||||
static int nonlocal_set_p_1 PARAMS ((rtx *, void *));
|
||||
static int nonlocal_set_p PARAMS ((rtx));
|
||||
static void memory_modified_1 PARAMS ((rtx, rtx, void *));
|
||||
|
||||
/* Set up all info needed to perform alias analysis on memory references. */
|
||||
|
||||
@ -2703,6 +2704,35 @@ init_alias_once ()
|
||||
alias_sets = splay_tree_new (splay_tree_compare_ints, 0, 0);
|
||||
}
|
||||
|
||||
/* Set MEMORY_MODIFIED when X modifies DATA (that is assumed
|
||||
to be memory reference. */
|
||||
static bool memory_modified;
|
||||
static void
|
||||
memory_modified_1 (x, pat, data)
|
||||
rtx x, pat ATTRIBUTE_UNUSED;
|
||||
void *data;
|
||||
{
|
||||
if (GET_CODE (x) == MEM)
|
||||
{
|
||||
if (anti_dependence (x, (rtx)data) || output_dependence (x, (rtx)data))
|
||||
memory_modified = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Return true when INSN possibly modify memory contents of MEM
|
||||
(ie address can be modified). */
|
||||
bool
|
||||
memory_modified_in_insn_p (mem, insn)
|
||||
rtx mem, insn;
|
||||
{
|
||||
if (!INSN_P (insn))
|
||||
return false;
|
||||
memory_modified = false;
|
||||
note_stores (PATTERN (insn), memory_modified_1, mem);
|
||||
return memory_modified;
|
||||
}
|
||||
|
||||
/* Initialize the aliasing machinery. Initialize the REG_KNOWN_VALUE
|
||||
array. */
|
||||
|
||||
|
@ -141,6 +141,7 @@ extern void ix86_expand_branch PARAMS ((enum rtx_code, rtx));
|
||||
extern int ix86_expand_setcc PARAMS ((enum rtx_code, rtx));
|
||||
extern int ix86_expand_int_movcc PARAMS ((rtx[]));
|
||||
extern int ix86_expand_fp_movcc PARAMS ((rtx[]));
|
||||
extern int ix86_expand_int_addcc PARAMS ((rtx[]));
|
||||
extern void ix86_expand_call PARAMS ((rtx, rtx, rtx, rtx, rtx, int));
|
||||
extern void x86_initialize_trampoline PARAMS ((rtx, rtx, rtx));
|
||||
extern rtx ix86_zero_extend_to_Pmode PARAMS ((rtx));
|
||||
|
@ -9981,6 +9981,69 @@ ix86_expand_fp_movcc (operands)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Expand conditional increment or decrement using adb/sbb instructions.
|
||||
The default case using setcc followed by the conditional move can be
|
||||
done by generic code. */
|
||||
int
|
||||
ix86_expand_int_addcc (operands)
|
||||
rtx operands[];
|
||||
{
|
||||
enum rtx_code code = GET_CODE (operands[1]);
|
||||
rtx compare_op;
|
||||
rtx val = const0_rtx;
|
||||
|
||||
if (operands[3] != const1_rtx
|
||||
&& operands[3] != constm1_rtx)
|
||||
return 0;
|
||||
if (!ix86_expand_carry_flag_compare (code, ix86_compare_op0,
|
||||
ix86_compare_op1, &compare_op))
|
||||
return 0;
|
||||
if (GET_CODE (compare_op) != LTU)
|
||||
val = operands[3] == const1_rtx ? constm1_rtx : const1_rtx;
|
||||
if ((GET_CODE (compare_op) == LTU) == (operands[3] == constm1_rtx))
|
||||
{
|
||||
switch (GET_MODE (operands[0]))
|
||||
{
|
||||
case QImode:
|
||||
emit_insn (gen_subqi3_carry (operands[0], operands[2], val));
|
||||
break;
|
||||
case HImode:
|
||||
emit_insn (gen_subhi3_carry (operands[0], operands[2], val));
|
||||
break;
|
||||
case SImode:
|
||||
emit_insn (gen_subsi3_carry (operands[0], operands[2], val));
|
||||
break;
|
||||
case DImode:
|
||||
emit_insn (gen_subdi3_carry_rex64 (operands[0], operands[2], val));
|
||||
break;
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (GET_MODE (operands[0]))
|
||||
{
|
||||
case QImode:
|
||||
emit_insn (gen_addqi3_carry (operands[0], operands[2], val));
|
||||
break;
|
||||
case HImode:
|
||||
emit_insn (gen_addhi3_carry (operands[0], operands[2], val));
|
||||
break;
|
||||
case SImode:
|
||||
emit_insn (gen_addsi3_carry (operands[0], operands[2], val));
|
||||
break;
|
||||
case DImode:
|
||||
emit_insn (gen_adddi3_carry_rex64 (operands[0], operands[2], val));
|
||||
break;
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
}
|
||||
return 1; /* DONE */
|
||||
}
|
||||
|
||||
|
||||
/* Split operands 0 and 1 into SImode parts. Similar to split_di, but
|
||||
works for floating pointer parameters and nonoffsetable memories.
|
||||
For pushes, it returns just stack offsets; the values will be saved
|
||||
|
@ -4951,7 +4951,7 @@
|
||||
split_di (operands+1, 1, operands+1, operands+4);
|
||||
split_di (operands+2, 1, operands+2, operands+5);")
|
||||
|
||||
(define_insn "*adddi3_carry_rex64"
|
||||
(define_insn "adddi3_carry_rex64"
|
||||
[(set (match_operand:DI 0 "nonimmediate_operand" "=rm,r")
|
||||
(plus:DI (plus:DI (ltu:DI (reg:CC 17) (const_int 0))
|
||||
(match_operand:DI 1 "nonimmediate_operand" "%0,0"))
|
||||
@ -4976,7 +4976,33 @@
|
||||
[(set_attr "type" "alu")
|
||||
(set_attr "mode" "DI")])
|
||||
|
||||
(define_insn "*addsi3_carry"
|
||||
(define_insn "addqi3_carry"
|
||||
[(set (match_operand:QI 0 "nonimmediate_operand" "=rm,r")
|
||||
(plus:QI (plus:QI (ltu:QI (reg:CC 17) (const_int 0))
|
||||
(match_operand:QI 1 "nonimmediate_operand" "%0,0"))
|
||||
(match_operand:QI 2 "general_operand" "ri,rm")))
|
||||
(clobber (reg:CC 17))]
|
||||
"ix86_binary_operator_ok (PLUS, QImode, operands)"
|
||||
"adc{b}\t{%2, %0|%0, %2}"
|
||||
[(set_attr "type" "alu")
|
||||
(set_attr "pent_pair" "pu")
|
||||
(set_attr "mode" "QI")
|
||||
(set_attr "ppro_uops" "few")])
|
||||
|
||||
(define_insn "addhi3_carry"
|
||||
[(set (match_operand:HI 0 "nonimmediate_operand" "=rm,r")
|
||||
(plus:HI (plus:HI (ltu:HI (reg:CC 17) (const_int 0))
|
||||
(match_operand:HI 1 "nonimmediate_operand" "%0,0"))
|
||||
(match_operand:HI 2 "general_operand" "ri,rm")))
|
||||
(clobber (reg:CC 17))]
|
||||
"ix86_binary_operator_ok (PLUS, HImode, operands)"
|
||||
"adc{w}\t{%2, %0|%0, %2}"
|
||||
[(set_attr "type" "alu")
|
||||
(set_attr "pent_pair" "pu")
|
||||
(set_attr "mode" "HI")
|
||||
(set_attr "ppro_uops" "few")])
|
||||
|
||||
(define_insn "addsi3_carry"
|
||||
[(set (match_operand:SI 0 "nonimmediate_operand" "=rm,r")
|
||||
(plus:SI (plus:SI (ltu:SI (reg:CC 17) (const_int 0))
|
||||
(match_operand:SI 1 "nonimmediate_operand" "%0,0"))
|
||||
@ -6653,6 +6679,31 @@
|
||||
[(set_attr "type" "alu")
|
||||
(set_attr "mode" "DI")])
|
||||
|
||||
(define_insn "subqi3_carry"
|
||||
[(set (match_operand:QI 0 "nonimmediate_operand" "=rm,r")
|
||||
(minus:QI (match_operand:QI 1 "nonimmediate_operand" "0,0")
|
||||
(plus:QI (ltu:QI (reg:CC 17) (const_int 0))
|
||||
(match_operand:QI 2 "general_operand" "ri,rm"))))
|
||||
(clobber (reg:CC 17))]
|
||||
"ix86_binary_operator_ok (MINUS, QImode, operands)"
|
||||
"sbb{b}\t{%2, %0|%0, %2}"
|
||||
[(set_attr "type" "alu")
|
||||
(set_attr "pent_pair" "pu")
|
||||
(set_attr "ppro_uops" "few")
|
||||
(set_attr "mode" "QI")])
|
||||
|
||||
(define_insn "subhi3_carry"
|
||||
[(set (match_operand:HI 0 "nonimmediate_operand" "=rm,r")
|
||||
(minus:HI (match_operand:HI 1 "nonimmediate_operand" "0,0")
|
||||
(plus:HI (ltu:HI (reg:CC 17) (const_int 0))
|
||||
(match_operand:HI 2 "general_operand" "ri,rm"))))
|
||||
(clobber (reg:CC 17))]
|
||||
"ix86_binary_operator_ok (MINUS, HImode, operands)"
|
||||
"sbb{w}\t{%2, %0|%0, %2}"
|
||||
[(set_attr "type" "alu")
|
||||
(set_attr "pent_pair" "pu")
|
||||
(set_attr "ppro_uops" "few")
|
||||
(set_attr "mode" "HI")])
|
||||
|
||||
(define_insn "subsi3_carry"
|
||||
[(set (match_operand:SI 0 "nonimmediate_operand" "=rm,r")
|
||||
@ -16459,6 +16510,39 @@
|
||||
(match_dup 1)
|
||||
(match_dup 2)))])
|
||||
|
||||
;; Conditional addition patterns
|
||||
(define_expand "addqicc"
|
||||
[(match_operand:QI 0 "register_operand" "")
|
||||
(match_operand 1 "comparison_operator" "")
|
||||
(match_operand:QI 2 "register_operand" "")
|
||||
(match_operand:QI 3 "const_int_operand" "")]
|
||||
""
|
||||
"if (!ix86_expand_int_addcc (operands)) FAIL; DONE;")
|
||||
|
||||
(define_expand "addhicc"
|
||||
[(match_operand:HI 0 "register_operand" "")
|
||||
(match_operand 1 "comparison_operator" "")
|
||||
(match_operand:HI 2 "register_operand" "")
|
||||
(match_operand:HI 3 "const_int_operand" "")]
|
||||
""
|
||||
"if (!ix86_expand_int_addcc (operands)) FAIL; DONE;")
|
||||
|
||||
(define_expand "addsicc"
|
||||
[(match_operand:SI 0 "register_operand" "")
|
||||
(match_operand 1 "comparison_operator" "")
|
||||
(match_operand:SI 2 "register_operand" "")
|
||||
(match_operand:SI 3 "const_int_operand" "")]
|
||||
""
|
||||
"if (!ix86_expand_int_addcc (operands)) FAIL; DONE;")
|
||||
|
||||
(define_expand "adddicc"
|
||||
[(match_operand:DI 0 "register_operand" "")
|
||||
(match_operand 1 "comparison_operator" "")
|
||||
(match_operand:DI 2 "register_operand" "")
|
||||
(match_operand:DI 3 "const_int_operand" "")]
|
||||
"TARGET_64BIT"
|
||||
"if (!ix86_expand_int_addcc (operands)) FAIL; DONE;")
|
||||
|
||||
;; We can't represent the LT test directly. Do this by swapping the operands.
|
||||
|
||||
(define_split
|
||||
|
@ -307,6 +307,9 @@ rtx emit_conditional_move PARAMS ((rtx, enum rtx_code, rtx, rtx,
|
||||
int can_conditionally_move_p PARAMS ((enum machine_mode mode));
|
||||
|
||||
#endif
|
||||
rtx emit_conditional_add (rtx, enum rtx_code, rtx, rtx,
|
||||
enum machine_mode, rtx, rtx,
|
||||
enum machine_mode, int);
|
||||
|
||||
|
||||
/* Functions from expmed.c: */
|
||||
|
@ -2251,6 +2251,7 @@ extern void init_alias_once PARAMS ((void));
|
||||
extern void init_alias_analysis PARAMS ((void));
|
||||
extern void end_alias_analysis PARAMS ((void));
|
||||
extern rtx addr_side_effect_eval PARAMS ((rtx, int, int));
|
||||
extern bool memory_modified_in_insn_p PARAMS ((rtx, rtx));
|
||||
|
||||
/* In sibcall.c */
|
||||
typedef enum {
|
||||
|
@ -1037,7 +1037,7 @@ regs_set_between_p (x, start, end)
|
||||
|
||||
/* Similar to reg_set_between_p, but check all registers in X. Return 0
|
||||
only if none of them are modified between START and END. Return 1 if
|
||||
X contains a MEM; this routine does not perform any memory aliasing. */
|
||||
X contains a MEM; this routine does usememory aliasing. */
|
||||
|
||||
int
|
||||
modified_between_p (x, start, end)
|
||||
@ -1047,6 +1047,10 @@ modified_between_p (x, start, end)
|
||||
enum rtx_code code = GET_CODE (x);
|
||||
const char *fmt;
|
||||
int i, j;
|
||||
rtx insn;
|
||||
|
||||
if (start == end)
|
||||
return 0;
|
||||
|
||||
switch (code)
|
||||
{
|
||||
@ -1063,10 +1067,14 @@ modified_between_p (x, start, end)
|
||||
return 1;
|
||||
|
||||
case MEM:
|
||||
/* If the memory is not constant, assume it is modified. If it is
|
||||
constant, we still have to check the address. */
|
||||
if (! RTX_UNCHANGING_P (x))
|
||||
if (RTX_UNCHANGING_P (x))
|
||||
return 0;
|
||||
if (modified_between_p (XEXP (x, 0), start, end))
|
||||
return 1;
|
||||
for (insn = NEXT_INSN (start); insn != end; insn = NEXT_INSN (insn))
|
||||
if (memory_modified_in_insn_p (x, insn))
|
||||
return 1;
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case REG:
|
||||
@ -1093,7 +1101,7 @@ modified_between_p (x, start, end)
|
||||
|
||||
/* Similar to reg_set_p, but check all registers in X. Return 0 only if none
|
||||
of them are modified in INSN. Return 1 if X contains a MEM; this routine
|
||||
does not perform any memory aliasing. */
|
||||
does use memory aliasing. */
|
||||
|
||||
int
|
||||
modified_in_p (x, insn)
|
||||
@ -1119,10 +1127,13 @@ modified_in_p (x, insn)
|
||||
return 1;
|
||||
|
||||
case MEM:
|
||||
/* If the memory is not constant, assume it is modified. If it is
|
||||
constant, we still have to check the address. */
|
||||
if (! RTX_UNCHANGING_P (x))
|
||||
if (RTX_UNCHANGING_P (x))
|
||||
return 0;
|
||||
if (modified_in_p (XEXP (x, 0), insn))
|
||||
return 1;
|
||||
if (memory_modified_in_insn_p (x, insn))
|
||||
return 1;
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case REG:
|
||||
|
Loading…
x
Reference in New Issue
Block a user