リビジョン | f4e4e414a8e9a2693b6b245c00ea11befb852283 (tree) |
---|---|
日時 | 2015-04-24 13:49:34 |
作者 | thopre01 <thopre01@138b...> |
コミッター | thopre01 |
2015-04-24 Thomas Preud'homme <thomas.preudhomme@arm.com>
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@222398 138bc75d-0d04-0410-961f-82ee72b054a4
@@ -1,3 +1,20 @@ | ||
1 | +2015-04-24 Thomas Preud'homme <thomas.preudhomme@arm.com> | |
2 | + Steven Bosscher <steven@gcc.gnu.org> | |
3 | + | |
4 | + PR rtl-optimization/34503 | |
5 | + * cprop.c (cprop_reg_p): New. | |
6 | + (hash_scan_set): Use above function to check if register can be | |
7 | + propagated. | |
8 | + (find_avail_set): Return up to two sets, one whose source is a | |
9 | + register and one whose source is a constant. Sets are returned in an | |
10 | + array passed as parameter rather than as a return value. | |
11 | + (cprop_insn): Use a do while loop rather than a goto. Try each of the | |
12 | + sets returned by find_avail_set, starting with the one whose source is | |
13 | + a constant. Use cprop_reg_p to check if register can be propagated. | |
14 | + (do_local_cprop): Use cprop_reg_p to check if register can be | |
15 | + propagated. | |
16 | + (implicit_set_cond_p): Likewise. | |
17 | + | |
1 | 18 | 2015-04-23 Jan Hubicka <hubicka@ucw.cz> |
2 | 19 | |
3 | 20 | * ipa-icf.c (sem_function::equals_wpa): Compare thunk info. |
@@ -285,6 +285,15 @@ cprop_constant_p (const_rtx x) | ||
285 | 285 | return CONSTANT_P (x) && (GET_CODE (x) != CONST || shared_const_p (x)); |
286 | 286 | } |
287 | 287 | |
288 | +/* Determine whether the rtx X should be treated as a register that can | |
289 | + be propagated. Any pseudo-register is fine. */ | |
290 | + | |
291 | +static bool | |
292 | +cprop_reg_p (const_rtx x) | |
293 | +{ | |
294 | + return REG_P (x) && !HARD_REGISTER_P (x); | |
295 | +} | |
296 | + | |
288 | 297 | /* Scan SET present in INSN and add an entry to the hash TABLE. |
289 | 298 | IMPLICIT is true if it's an implicit set, false otherwise. */ |
290 | 299 |
@@ -295,8 +304,7 @@ hash_scan_set (rtx set, rtx_insn *insn, struct hash_table_d *table, | ||
295 | 304 | rtx src = SET_SRC (set); |
296 | 305 | rtx dest = SET_DEST (set); |
297 | 306 | |
298 | - if (REG_P (dest) | |
299 | - && ! HARD_REGISTER_P (dest) | |
307 | + if (cprop_reg_p (dest) | |
300 | 308 | && reg_available_p (dest, insn) |
301 | 309 | && can_copy_p (GET_MODE (dest))) |
302 | 310 | { |
@@ -321,9 +329,8 @@ hash_scan_set (rtx set, rtx_insn *insn, struct hash_table_d *table, | ||
321 | 329 | src = XEXP (note, 0), set = gen_rtx_SET (VOIDmode, dest, src); |
322 | 330 | |
323 | 331 | /* Record sets for constant/copy propagation. */ |
324 | - if ((REG_P (src) | |
332 | + if ((cprop_reg_p (src) | |
325 | 333 | && src != dest |
326 | - && ! HARD_REGISTER_P (src) | |
327 | 334 | && reg_available_p (src, insn)) |
328 | 335 | || cprop_constant_p (src)) |
329 | 336 | insert_set_in_table (dest, src, insn, table, implicit); |
@@ -821,15 +828,15 @@ try_replace_reg (rtx from, rtx to, rtx_insn *insn) | ||
821 | 828 | return success; |
822 | 829 | } |
823 | 830 | |
824 | -/* Find a set of REGNOs that are available on entry to INSN's block. Return | |
825 | - NULL no such set is found. */ | |
831 | +/* Find a set of REGNOs that are available on entry to INSN's block. If found, | |
832 | + SET_RET[0] will be assigned a set with a register source and SET_RET[1] a | |
833 | + set with a constant source. If not found the corresponding entry is set to | |
834 | + NULL. */ | |
826 | 835 | |
827 | -static struct cprop_expr * | |
828 | -find_avail_set (int regno, rtx_insn *insn) | |
836 | +static void | |
837 | +find_avail_set (int regno, rtx_insn *insn, struct cprop_expr *set_ret[2]) | |
829 | 838 | { |
830 | - /* SET1 contains the last set found that can be returned to the caller for | |
831 | - use in a substitution. */ | |
832 | - struct cprop_expr *set1 = 0; | |
839 | + set_ret[0] = set_ret[1] = NULL; | |
833 | 840 | |
834 | 841 | /* Loops are not possible here. To get a loop we would need two sets |
835 | 842 | available at the start of the block containing INSN. i.e. we would |
@@ -869,8 +876,10 @@ find_avail_set (int regno, rtx_insn *insn) | ||
869 | 876 | If the source operand changed, we may still use it for the next |
870 | 877 | iteration of this loop, but we may not use it for substitutions. */ |
871 | 878 | |
872 | - if (cprop_constant_p (src) || reg_not_set_p (src, insn)) | |
873 | - set1 = set; | |
879 | + if (cprop_constant_p (src)) | |
880 | + set_ret[1] = set; | |
881 | + else if (reg_not_set_p (src, insn)) | |
882 | + set_ret[0] = set; | |
874 | 883 | |
875 | 884 | /* If the source of the set is anything except a register, then |
876 | 885 | we have reached the end of the copy chain. */ |
@@ -881,10 +890,6 @@ find_avail_set (int regno, rtx_insn *insn) | ||
881 | 890 | and see if we have an available copy into SRC. */ |
882 | 891 | regno = REGNO (src); |
883 | 892 | } |
884 | - | |
885 | - /* SET1 holds the last set that was available and anticipatable at | |
886 | - INSN. */ | |
887 | - return set1; | |
888 | 893 | } |
889 | 894 | |
890 | 895 | /* Subroutine of cprop_insn that tries to propagate constants into |
@@ -1048,40 +1053,40 @@ cprop_insn (rtx_insn *insn) | ||
1048 | 1053 | int changed = 0, changed_this_round; |
1049 | 1054 | rtx note; |
1050 | 1055 | |
1051 | -retry: | |
1052 | - changed_this_round = 0; | |
1053 | - reg_use_count = 0; | |
1054 | - note_uses (&PATTERN (insn), find_used_regs, NULL); | |
1055 | - | |
1056 | - /* We may win even when propagating constants into notes. */ | |
1057 | - note = find_reg_equal_equiv_note (insn); | |
1058 | - if (note) | |
1059 | - find_used_regs (&XEXP (note, 0), NULL); | |
1060 | - | |
1061 | - for (i = 0; i < reg_use_count; i++) | |
1056 | + do | |
1062 | 1057 | { |
1063 | - rtx reg_used = reg_use_table[i]; | |
1064 | - unsigned int regno = REGNO (reg_used); | |
1065 | - rtx src; | |
1066 | - struct cprop_expr *set; | |
1058 | + changed_this_round = 0; | |
1059 | + reg_use_count = 0; | |
1060 | + note_uses (&PATTERN (insn), find_used_regs, NULL); | |
1067 | 1061 | |
1068 | - /* If the register has already been set in this block, there's | |
1069 | - nothing we can do. */ | |
1070 | - if (! reg_not_set_p (reg_used, insn)) | |
1071 | - continue; | |
1062 | + /* We may win even when propagating constants into notes. */ | |
1063 | + note = find_reg_equal_equiv_note (insn); | |
1064 | + if (note) | |
1065 | + find_used_regs (&XEXP (note, 0), NULL); | |
1072 | 1066 | |
1073 | - /* Find an assignment that sets reg_used and is available | |
1074 | - at the start of the block. */ | |
1075 | - set = find_avail_set (regno, insn); | |
1076 | - if (! set) | |
1077 | - continue; | |
1067 | + for (i = 0; i < reg_use_count; i++) | |
1068 | + { | |
1069 | + rtx reg_used = reg_use_table[i]; | |
1070 | + unsigned int regno = REGNO (reg_used); | |
1071 | + rtx src_cst = NULL, src_reg = NULL; | |
1072 | + struct cprop_expr *set[2]; | |
1078 | 1073 | |
1079 | - src = set->src; | |
1074 | + /* If the register has already been set in this block, there's | |
1075 | + nothing we can do. */ | |
1076 | + if (! reg_not_set_p (reg_used, insn)) | |
1077 | + continue; | |
1080 | 1078 | |
1081 | - /* Constant propagation. */ | |
1082 | - if (cprop_constant_p (src)) | |
1083 | - { | |
1084 | - if (constprop_register (reg_used, src, insn)) | |
1079 | + /* Find an assignment that sets reg_used and is available | |
1080 | + at the start of the block. */ | |
1081 | + find_avail_set (regno, insn, set); | |
1082 | + if (set[0]) | |
1083 | + src_reg = set[0]->src; | |
1084 | + if (set[1]) | |
1085 | + src_cst = set[1]->src; | |
1086 | + | |
1087 | + /* Constant propagation. */ | |
1088 | + if (src_cst && cprop_constant_p (src_cst) | |
1089 | + && constprop_register (reg_used, src_cst, insn)) | |
1085 | 1090 | { |
1086 | 1091 | changed_this_round = changed = 1; |
1087 | 1092 | global_const_prop_count++; |
@@ -1091,18 +1096,16 @@ retry: | ||
1091 | 1096 | "GLOBAL CONST-PROP: Replacing reg %d in ", regno); |
1092 | 1097 | fprintf (dump_file, "insn %d with constant ", |
1093 | 1098 | INSN_UID (insn)); |
1094 | - print_rtl (dump_file, src); | |
1099 | + print_rtl (dump_file, src_cst); | |
1095 | 1100 | fprintf (dump_file, "\n"); |
1096 | 1101 | } |
1097 | 1102 | if (insn->deleted ()) |
1098 | 1103 | return 1; |
1099 | 1104 | } |
1100 | - } | |
1101 | - else if (REG_P (src) | |
1102 | - && REGNO (src) >= FIRST_PSEUDO_REGISTER | |
1103 | - && REGNO (src) != regno) | |
1104 | - { | |
1105 | - if (try_replace_reg (reg_used, src, insn)) | |
1105 | + /* Copy propagation. */ | |
1106 | + else if (src_reg && cprop_reg_p (src_reg) | |
1107 | + && REGNO (src_reg) != regno | |
1108 | + && try_replace_reg (reg_used, src_reg, insn)) | |
1106 | 1109 | { |
1107 | 1110 | changed_this_round = changed = 1; |
1108 | 1111 | global_copy_prop_count++; |
@@ -1111,7 +1114,7 @@ retry: | ||
1111 | 1114 | fprintf (dump_file, |
1112 | 1115 | "GLOBAL COPY-PROP: Replacing reg %d in insn %d", |
1113 | 1116 | regno, INSN_UID (insn)); |
1114 | - fprintf (dump_file, " with reg %d\n", REGNO (src)); | |
1117 | + fprintf (dump_file, " with reg %d\n", REGNO (src_reg)); | |
1115 | 1118 | } |
1116 | 1119 | |
1117 | 1120 | /* The original insn setting reg_used may or may not now be |
@@ -1121,12 +1124,10 @@ retry: | ||
1121 | 1124 | and made things worse. */ |
1122 | 1125 | } |
1123 | 1126 | } |
1124 | - | |
1125 | - /* If try_replace_reg simplified the insn, the regs found | |
1126 | - by find_used_regs may not be valid anymore. Start over. */ | |
1127 | - if (changed_this_round) | |
1128 | - goto retry; | |
1129 | 1127 | } |
1128 | + /* If try_replace_reg simplified the insn, the regs found by find_used_regs | |
1129 | + may not be valid anymore. Start over. */ | |
1130 | + while (changed_this_round); | |
1130 | 1131 | |
1131 | 1132 | if (changed && DEBUG_INSN_P (insn)) |
1132 | 1133 | return 0; |
@@ -1189,7 +1190,7 @@ do_local_cprop (rtx x, rtx_insn *insn) | ||
1189 | 1190 | /* Rule out USE instructions and ASM statements as we don't want to |
1190 | 1191 | change the hard registers mentioned. */ |
1191 | 1192 | if (REG_P (x) |
1192 | - && (REGNO (x) >= FIRST_PSEUDO_REGISTER | |
1193 | + && (cprop_reg_p (x) | |
1193 | 1194 | || (GET_CODE (PATTERN (insn)) != USE |
1194 | 1195 | && asm_noperands (PATTERN (insn)) < 0))) |
1195 | 1196 | { |
@@ -1205,7 +1206,7 @@ do_local_cprop (rtx x, rtx_insn *insn) | ||
1205 | 1206 | |
1206 | 1207 | if (cprop_constant_p (this_rtx)) |
1207 | 1208 | newcnst = this_rtx; |
1208 | - if (REG_P (this_rtx) && REGNO (this_rtx) >= FIRST_PSEUDO_REGISTER | |
1209 | + if (cprop_reg_p (this_rtx) | |
1209 | 1210 | /* Don't copy propagate if it has attached REG_EQUIV note. |
1210 | 1211 | At this point this only function parameters should have |
1211 | 1212 | REG_EQUIV notes and if the argument slot is used somewhere |
@@ -1326,9 +1327,8 @@ implicit_set_cond_p (const_rtx cond) | ||
1326 | 1327 | if (GET_CODE (cond) != EQ && GET_CODE (cond) != NE) |
1327 | 1328 | return false; |
1328 | 1329 | |
1329 | - /* The first operand of COND must be a pseudo-reg. */ | |
1330 | - if (! REG_P (XEXP (cond, 0)) | |
1331 | - || HARD_REGISTER_P (XEXP (cond, 0))) | |
1330 | + /* The first operand of COND must be a register we can propagate. */ | |
1331 | + if (!cprop_reg_p (XEXP (cond, 0))) | |
1332 | 1332 | return false; |
1333 | 1333 | |
1334 | 1334 | /* The second operand of COND must be a suitable constant. */ |
@@ -1,3 +1,9 @@ | ||
1 | +2015-04-24 Thomas Preud'homme <thomas.preudhomme@arm.com> | |
2 | + Steven Bosscher <steven@gcc.gnu.org> | |
3 | + | |
4 | + PR rtl-optimization/34503 | |
5 | + * gcc.target/arm/pr64616.c: New file. | |
6 | + | |
1 | 7 | 2015-04-24 Bin Cheng <bin.cheng@arm.com> |
2 | 8 | |
3 | 9 | * gcc.target/arm/pr42172-1.c: Check str instead of ldr. |
@@ -0,0 +1,14 @@ | ||
1 | +/* { dg-do compile } */ | |
2 | +/* { dg-options "-O2" } */ | |
3 | + | |
4 | +int f (int); | |
5 | +unsigned int glob; | |
6 | + | |
7 | +void | |
8 | +g () | |
9 | +{ | |
10 | + while (f (glob)); | |
11 | + glob = 5; | |
12 | +} | |
13 | + | |
14 | +/* { dg-final { scan-assembler-times "ldr" 2 } } */ |