diff options
author | hubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4> | 2003-01-08 11:20:23 +0000 |
---|---|---|
committer | hubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4> | 2003-01-08 11:20:23 +0000 |
commit | c7bf7428b6105a3dda2c5a6bb77ebf6d97eb342a (patch) | |
tree | 72953eb3d0de3ae4394f101ee93b8dd54f346543 /gcc | |
parent | 1a91686825c95e78b96ace314f8f56591c80ad34 (diff) | |
download | gcc-c7bf7428b6105a3dda2c5a6bb77ebf6d97eb342a.tar.gz |
* 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.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@61038 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 17 | ||||
-rw-r--r-- | gcc/alias.c | 30 | ||||
-rw-r--r-- | gcc/config/i386/i386-protos.h | 1 | ||||
-rw-r--r-- | gcc/config/i386/i386.c | 63 | ||||
-rw-r--r-- | gcc/config/i386/i386.md | 88 | ||||
-rw-r--r-- | gcc/expr.h | 3 | ||||
-rw-r--r-- | gcc/rtl.h | 1 | ||||
-rw-r--r-- | gcc/rtlanal.c | 27 |
8 files changed, 220 insertions, 10 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 6c6fa0b046f..bf91b4b9fa9 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 960475be0c5..ffd4991a2c6 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 a06a160bfbc..01fc203377f 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 c1a760b6358..db361d97916 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 8be5fef2ed0..a364729301a 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 6e8d19e994b..7fe3c1be071 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 3cab166f527..a2c7514a898 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 2aad022fc26..63d7feb6035 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: |