aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJan Hubicka <jh@suse.cz>2003-01-08 12:20:23 +0100
committerJan Hubicka <hubicka@gcc.gnu.org>2003-01-08 11:20:23 +0000
commit7b52eedeedb2247bee0018a2d1a81f00ceb350c0 (patch)
tree72953eb3d0de3ae4394f101ee93b8dd54f346543 /gcc
parent67d96a1661226e6f32b9e7512fe7d01befd579ee (diff)
downloadgcc-7b52eedeedb2247bee0018a2d1a81f00ceb350c0.zip
gcc-7b52eedeedb2247bee0018a2d1a81f00ceb350c0.tar.gz
gcc-7b52eedeedb2247bee0018a2d1a81f00ceb350c0.tar.bz2
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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog17
-rw-r--r--gcc/alias.c30
-rw-r--r--gcc/config/i386/i386-protos.h1
-rw-r--r--gcc/config/i386/i386.c63
-rw-r--r--gcc/config/i386/i386.md88
-rw-r--r--gcc/expr.h3
-rw-r--r--gcc/rtl.h1
-rw-r--r--gcc/rtlanal.c27
8 files changed, 220 insertions, 10 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 6c6fa0b..bf91b4b 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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
diff --git a/gcc/alias.c b/gcc/alias.c
index 960475be..ffd4991 100644
--- a/gcc/alias.c
+++ b/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. */
diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h
index a06a160..01fc203 100644
--- a/gcc/config/i386/i386-protos.h
+++ b/gcc/config/i386/i386-protos.h
@@ -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));
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index c1a760b..db361d9 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -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
diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
index 8be5fef..a364729 100644
--- a/gcc/config/i386/i386.md
+++ b/gcc/config/i386/i386.md
@@ -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
diff --git a/gcc/expr.h b/gcc/expr.h
index 6e8d19e..7fe3c1b 100644
--- a/gcc/expr.h
+++ b/gcc/expr.h
@@ -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: */
diff --git a/gcc/rtl.h b/gcc/rtl.h
index 3cab166..a2c7514 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -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 {
diff --git a/gcc/rtlanal.c b/gcc/rtlanal.c
index 2aad022..63d7feb 100644
--- a/gcc/rtlanal.c
+++ b/gcc/rtlanal.c
@@ -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: