]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/config/sh/sh-mem.cc
Adjust scan string for PIE
[thirdparty/gcc.git] / gcc / config / sh / sh-mem.cc
CommitLineData
ccd57e8a 1/* Helper routines for memory move and comparison insns.
d353bf18 2 Copyright (C) 2013-2015 Free Software Foundation, Inc.
ccd57e8a 3
4This file is part of GCC.
5
6GCC is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 3, or (at your option)
9any later version.
10
11GCC is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GCC; see the file COPYING3. If not see
18<http://www.gnu.org/licenses/>. */
19
20#include "config.h"
21#include "system.h"
22#include "coretypes.h"
23#include "tm.h"
24#include "machmode.h"
25#include "rtl.h"
b20a8bb4 26#include "hash-set.h"
27#include "vec.h"
28#include "double-int.h"
29#include "input.h"
30#include "alias.h"
31#include "symtab.h"
32#include "wide-int.h"
33#include "inchash.h"
ccd57e8a 34#include "tree.h"
35#include "expr.h"
36#include "tm_p.h"
94ea8568 37#include "predict.h"
94ea8568 38#include "hard-reg-set.h"
39#include "input.h"
40#include "function.h"
41#include "dominance.h"
42#include "cfg.h"
43#include "cfgrtl.h"
44#include "cfganal.h"
45#include "lcm.h"
46#include "cfgbuild.h"
47#include "cfgcleanup.h"
ccd57e8a 48#include "basic-block.h"
49
50/* Like force_operand, but guarantees that VALUE ends up in TARGET. */
51static void
52force_into (rtx value, rtx target)
53{
54 value = force_operand (value, target);
55 if (! rtx_equal_p (value, target))
56 emit_insn (gen_move_insn (target, value));
57}
58
59/* Emit code to perform a block move. Choose the best method.
60
61 OPERANDS[0] is the destination.
62 OPERANDS[1] is the source.
63 OPERANDS[2] is the size.
64 OPERANDS[3] is the alignment safe to use. */
65bool
66expand_block_move (rtx *operands)
67{
68 int align = INTVAL (operands[3]);
69 int constp = (CONST_INT_P (operands[2]));
70 int bytes = (constp ? INTVAL (operands[2]) : 0);
71
72 if (! constp)
73 return false;
74
75 /* If we could use mov.l to move words and dest is word-aligned, we
76 can use movua.l for loads and still generate a relatively short
77 and efficient sequence. */
5b271aff 78 if (TARGET_SH4A && align < 4
ccd57e8a 79 && MEM_ALIGN (operands[0]) >= 32
80 && can_move_by_pieces (bytes, 32))
81 {
82 rtx dest = copy_rtx (operands[0]);
83 rtx src = copy_rtx (operands[1]);
84 /* We could use different pseudos for each copied word, but
85 since movua can only load into r0, it's kind of
86 pointless. */
87 rtx temp = gen_reg_rtx (SImode);
88 rtx src_addr = copy_addr_to_reg (XEXP (src, 0));
89 int copied = 0;
90
91 while (copied + 4 <= bytes)
92 {
93 rtx to = adjust_address (dest, SImode, copied);
94 rtx from = adjust_automodify_address (src, BLKmode,
95 src_addr, copied);
96
97 set_mem_size (from, 4);
98 emit_insn (gen_movua (temp, from));
99 emit_move_insn (src_addr, plus_constant (Pmode, src_addr, 4));
100 emit_move_insn (to, temp);
101 copied += 4;
102 }
103
104 if (copied < bytes)
105 move_by_pieces (adjust_address (dest, BLKmode, copied),
106 adjust_automodify_address (src, BLKmode,
107 src_addr, copied),
108 bytes - copied, align, 0);
109
110 return true;
111 }
112
113 /* If it isn't a constant number of bytes, or if it doesn't have 4 byte
114 alignment, or if it isn't a multiple of 4 bytes, then fail. */
115 if (align < 4 || (bytes % 4 != 0))
116 return false;
117
118 if (TARGET_HARD_SH4)
119 {
120 if (bytes < 12)
121 return false;
122 else if (bytes == 12)
123 {
124 rtx func_addr_rtx = gen_reg_rtx (Pmode);
125 rtx r4 = gen_rtx_REG (SImode, 4);
126 rtx r5 = gen_rtx_REG (SImode, 5);
127
128 function_symbol (func_addr_rtx, "__movmemSI12_i4", SFUNC_STATIC);
129 force_into (XEXP (operands[0], 0), r4);
130 force_into (XEXP (operands[1], 0), r5);
131 emit_insn (gen_block_move_real_i4 (func_addr_rtx));
132 return true;
133 }
134 else if (! optimize_size)
135 {
136 const char *entry_name;
137 rtx func_addr_rtx = gen_reg_rtx (Pmode);
138 int dwords;
139 rtx r4 = gen_rtx_REG (SImode, 4);
140 rtx r5 = gen_rtx_REG (SImode, 5);
141 rtx r6 = gen_rtx_REG (SImode, 6);
142
143 entry_name = (bytes & 4 ? "__movmem_i4_odd" : "__movmem_i4_even");
144 function_symbol (func_addr_rtx, entry_name, SFUNC_STATIC);
145 force_into (XEXP (operands[0], 0), r4);
146 force_into (XEXP (operands[1], 0), r5);
147
148 dwords = bytes >> 3;
149 emit_insn (gen_move_insn (r6, GEN_INT (dwords - 1)));
150 emit_insn (gen_block_lump_real_i4 (func_addr_rtx));
151 return true;
152 }
153 else
154 return false;
155 }
156 if (bytes < 64)
157 {
158 char entry[30];
159 rtx func_addr_rtx = gen_reg_rtx (Pmode);
160 rtx r4 = gen_rtx_REG (SImode, 4);
161 rtx r5 = gen_rtx_REG (SImode, 5);
162
163 sprintf (entry, "__movmemSI%d", bytes);
164 function_symbol (func_addr_rtx, entry, SFUNC_STATIC);
165 force_into (XEXP (operands[0], 0), r4);
166 force_into (XEXP (operands[1], 0), r5);
167 emit_insn (gen_block_move_real (func_addr_rtx));
168 return true;
169 }
170
171 /* This is the same number of bytes as a memcpy call, but to a different
172 less common function name, so this will occasionally use more space. */
173 if (! optimize_size)
174 {
175 rtx func_addr_rtx = gen_reg_rtx (Pmode);
176 int final_switch, while_loop;
177 rtx r4 = gen_rtx_REG (SImode, 4);
178 rtx r5 = gen_rtx_REG (SImode, 5);
179 rtx r6 = gen_rtx_REG (SImode, 6);
180
181 function_symbol (func_addr_rtx, "__movmem", SFUNC_STATIC);
182 force_into (XEXP (operands[0], 0), r4);
183 force_into (XEXP (operands[1], 0), r5);
184
185 /* r6 controls the size of the move. 16 is decremented from it
186 for each 64 bytes moved. Then the negative bit left over is used
187 as an index into a list of move instructions. e.g., a 72 byte move
188 would be set up with size(r6) = 14, for one iteration through the
189 big while loop, and a switch of -2 for the last part. */
190
191 final_switch = 16 - ((bytes / 4) % 16);
192 while_loop = ((bytes / 4) / 16 - 1) * 16;
193 emit_insn (gen_move_insn (r6, GEN_INT (while_loop + final_switch)));
194 emit_insn (gen_block_lump_real (func_addr_rtx));
195 return true;
196 }
197
198 return false;
199}
200
f4a24c51 201static const int prob_unlikely = REG_BR_PROB_BASE / 10;
202static const int prob_likely = REG_BR_PROB_BASE / 4;
c2daae6e 203
ccd57e8a 204/* Emit code to perform a strcmp.
205
206 OPERANDS[0] is the destination.
207 OPERANDS[1] is the first string.
208 OPERANDS[2] is the second string.
c2daae6e 209 OPERANDS[3] is the known alignment. */
ccd57e8a 210bool
211sh_expand_cmpstr (rtx *operands)
212{
c2daae6e 213 rtx addr1 = operands[1];
214 rtx addr2 = operands[2];
215 rtx s1_addr = copy_addr_to_reg (XEXP (addr1, 0));
216 rtx s2_addr = copy_addr_to_reg (XEXP (addr2, 0));
ccd57e8a 217 rtx tmp0 = gen_reg_rtx (SImode);
218 rtx tmp1 = gen_reg_rtx (SImode);
219 rtx tmp2 = gen_reg_rtx (SImode);
220 rtx tmp3 = gen_reg_rtx (SImode);
221
c2daae6e 222 rtx jump;
79f6a8ed 223 rtx_code_label *L_return = gen_label_rtx ();
224 rtx_code_label *L_loop_byte = gen_label_rtx ();
225 rtx_code_label *L_end_loop_byte = gen_label_rtx ();
226 rtx_code_label *L_loop_long = gen_label_rtx ();
227 rtx_code_label *L_end_loop_long = gen_label_rtx ();
ccd57e8a 228
b421555d 229 int align = INTVAL (operands[3]);
ccd57e8a 230
231 emit_move_insn (tmp0, const0_rtx);
232
b421555d 233 if (align < 4)
234 {
235 emit_insn (gen_iorsi3 (tmp1, s1_addr, s2_addr));
f07efc97 236 emit_insn (gen_tstsi_t (tmp1, GEN_INT (3)));
b421555d 237 jump = emit_jump_insn (gen_branch_false (L_loop_byte));
238 add_int_reg_note (jump, REG_BR_PROB, prob_likely);
239 }
ccd57e8a 240
c2daae6e 241 addr1 = adjust_automodify_address (addr1, SImode, s1_addr, 0);
242 addr2 = adjust_automodify_address (addr2, SImode, s2_addr, 0);
ccd57e8a 243
244 /* tmp2 is aligned, OK to load. */
245 emit_move_insn (tmp3, addr2);
246 emit_move_insn (s2_addr, plus_constant (Pmode, s2_addr, 4));
247
f4a24c51 248 /* start long loop. */
ccd57e8a 249 emit_label (L_loop_long);
250
251 emit_move_insn (tmp2, tmp3);
252
253 /* tmp1 is aligned, OK to load. */
254 emit_move_insn (tmp1, addr1);
255 emit_move_insn (s1_addr, plus_constant (Pmode, s1_addr, 4));
256
257 /* Is there a 0 byte ? */
258 emit_insn (gen_andsi3 (tmp3, tmp3, tmp1));
259
260 emit_insn (gen_cmpstr_t (tmp0, tmp3));
261 jump = emit_jump_insn (gen_branch_true (L_end_loop_long));
262 add_int_reg_note (jump, REG_BR_PROB, prob_unlikely);
263
264 emit_insn (gen_cmpeqsi_t (tmp1, tmp2));
265
266 /* tmp2 is aligned, OK to load. */
267 emit_move_insn (tmp3, addr2);
268 emit_move_insn (s2_addr, plus_constant (Pmode, s2_addr, 4));
269
270 jump = emit_jump_insn (gen_branch_true (L_loop_long));
271 add_int_reg_note (jump, REG_BR_PROB, prob_likely);
272 /* end loop. */
273
b421555d 274 /* Fallthu, substract words. */
ccd57e8a 275 if (TARGET_LITTLE_ENDIAN)
276 {
277 rtx low_1 = gen_lowpart (HImode, tmp1);
278 rtx low_2 = gen_lowpart (HImode, tmp2);
279
280 emit_insn (gen_rotlhi3_8 (low_1, low_1));
281 emit_insn (gen_rotlhi3_8 (low_2, low_2));
282 emit_insn (gen_rotlsi3_16 (tmp1, tmp1));
283 emit_insn (gen_rotlsi3_16 (tmp2, tmp2));
284 emit_insn (gen_rotlhi3_8 (low_1, low_1));
285 emit_insn (gen_rotlhi3_8 (low_2, low_2));
286 }
287
288 jump = emit_jump_insn (gen_jump_compact (L_return));
289 emit_barrier_after (jump);
290
ccd57e8a 291 emit_label (L_end_loop_long);
292
293 emit_move_insn (s1_addr, plus_constant (Pmode, s1_addr, -4));
294 emit_move_insn (s2_addr, plus_constant (Pmode, s2_addr, -4));
295
b421555d 296 /* start byte loop. */
c2daae6e 297 addr1 = adjust_address (addr1, QImode, 0);
298 addr2 = adjust_address (addr2, QImode, 0);
b421555d 299
ccd57e8a 300 emit_label (L_loop_byte);
301
302 emit_insn (gen_extendqisi2 (tmp2, addr2));
303 emit_move_insn (s2_addr, plus_constant (Pmode, s2_addr, 1));
304
305 emit_insn (gen_extendqisi2 (tmp1, addr1));
306 emit_move_insn (s1_addr, plus_constant (Pmode, s1_addr, 1));
307
308 emit_insn (gen_cmpeqsi_t (tmp2, const0_rtx));
309 jump = emit_jump_insn (gen_branch_true (L_end_loop_byte));
310 add_int_reg_note (jump, REG_BR_PROB, prob_unlikely);
311
312 emit_insn (gen_cmpeqsi_t (tmp1, tmp2));
b421555d 313 if (flag_delayed_branch)
314 emit_insn (gen_zero_extendqisi2 (tmp2, gen_lowpart (QImode, tmp2)));
315 jump = emit_jump_insn (gen_branch_true (L_loop_byte));
ccd57e8a 316 add_int_reg_note (jump, REG_BR_PROB, prob_likely);
317 /* end loop. */
318
319 emit_label (L_end_loop_byte);
320
b421555d 321 if (! flag_delayed_branch)
322 emit_insn (gen_zero_extendqisi2 (tmp2, gen_lowpart (QImode, tmp2)));
ccd57e8a 323 emit_insn (gen_zero_extendqisi2 (tmp1, gen_lowpart (QImode, tmp1)));
324
325 emit_label (L_return);
326
327 emit_insn (gen_subsi3 (operands[0], tmp1, tmp2));
328
329 return true;
330}
331
b421555d 332/* Emit code to perform a strncmp.
333
334 OPERANDS[0] is the destination.
335 OPERANDS[1] is the first string.
336 OPERANDS[2] is the second string.
337 OPERANDS[3] is the length.
c2daae6e 338 OPERANDS[4] is the known alignment. */
b421555d 339bool
340sh_expand_cmpnstr (rtx *operands)
341{
c2daae6e 342 rtx addr1 = operands[1];
343 rtx addr2 = operands[2];
344 rtx s1_addr = copy_addr_to_reg (XEXP (addr1, 0));
345 rtx s2_addr = copy_addr_to_reg (XEXP (addr2, 0));
b421555d 346 rtx tmp1 = gen_reg_rtx (SImode);
347 rtx tmp2 = gen_reg_rtx (SImode);
348
c2daae6e 349 rtx jump;
79f6a8ed 350 rtx_code_label *L_return = gen_label_rtx ();
351 rtx_code_label *L_loop_byte = gen_label_rtx ();
352 rtx_code_label *L_end_loop_byte = gen_label_rtx ();
b421555d 353
b421555d 354 rtx len = force_reg (SImode, operands[3]);
75c9129c 355 int constp = CONST_INT_P (operands[3]);
b421555d 356
f4a24c51 357 /* Loop on a register count. */
75c9129c 358 if (constp)
b421555d 359 {
75c9129c 360 rtx tmp0 = gen_reg_rtx (SImode);
b421555d 361 rtx tmp3 = gen_reg_rtx (SImode);
362 rtx lenw = gen_reg_rtx (SImode);
b421555d 363
79f6a8ed 364 rtx_code_label *L_loop_long = gen_label_rtx ();
365 rtx_code_label *L_end_loop_long = gen_label_rtx ();
b421555d 366
75c9129c 367 int align = INTVAL (operands[4]);
368 int bytes = INTVAL (operands[3]);
369 int witers = bytes / 4;
370
371 if (witers > 1)
f4a24c51 372 {
373 addr1 = adjust_automodify_address (addr1, SImode, s1_addr, 0);
374 addr2 = adjust_automodify_address (addr2, SImode, s2_addr, 0);
375
376 emit_move_insn (tmp0, const0_rtx);
377
378 if (align < 4)
379 {
380 emit_insn (gen_iorsi3 (tmp1, s1_addr, s2_addr));
f07efc97 381 emit_insn (gen_tstsi_t (tmp1, GEN_INT (3)));
f4a24c51 382 jump = emit_jump_insn (gen_branch_false (L_loop_byte));
383 add_int_reg_note (jump, REG_BR_PROB, prob_likely);
384 }
385
386 /* word count. Do we have iterations ? */
387 emit_insn (gen_lshrsi3 (lenw, len, GEN_INT (2)));
388
389 /* start long loop. */
390 emit_label (L_loop_long);
391
392 /* tmp2 is aligned, OK to load. */
393 emit_move_insn (tmp2, addr2);
394 emit_move_insn (s2_addr, plus_constant (Pmode, s2_addr,
395 GET_MODE_SIZE (SImode)));
396
397 /* tmp1 is aligned, OK to load. */
398 emit_move_insn (tmp1, addr1);
399 emit_move_insn (s1_addr, plus_constant (Pmode, s1_addr,
400 GET_MODE_SIZE (SImode)));
401
402 /* Is there a 0 byte ? */
403 emit_insn (gen_andsi3 (tmp3, tmp2, tmp1));
404
405 emit_insn (gen_cmpstr_t (tmp0, tmp3));
406 jump = emit_jump_insn (gen_branch_true (L_end_loop_long));
407 add_int_reg_note (jump, REG_BR_PROB, prob_unlikely);
408
409 emit_insn (gen_cmpeqsi_t (tmp1, tmp2));
410 jump = emit_jump_insn (gen_branch_false (L_end_loop_long));
411 add_int_reg_note (jump, REG_BR_PROB, prob_unlikely);
412
413 if (TARGET_SH2)
414 emit_insn (gen_dect (lenw, lenw));
415 else
416 {
417 emit_insn (gen_addsi3 (lenw, lenw, GEN_INT (-1)));
418 emit_insn (gen_tstsi_t (lenw, lenw));
419 }
420
421 jump = emit_jump_insn (gen_branch_false (L_loop_long));
422 add_int_reg_note (jump, REG_BR_PROB, prob_likely);
423
424 int sbytes = bytes % 4;
425
426 /* end loop. Reached max iterations. */
427 if (sbytes == 0)
428 {
7756601d 429 emit_insn (gen_subsi3 (operands[0], tmp1, tmp2));
f4a24c51 430 jump = emit_jump_insn (gen_jump_compact (L_return));
431 emit_barrier_after (jump);
432 }
433 else
434 {
435 /* Remaining bytes to check. */
436
437 addr1 = adjust_automodify_address (addr1, QImode, s1_addr, 0);
438 addr2 = adjust_automodify_address (addr2, QImode, s2_addr, 0);
439
440 while (sbytes--)
441 {
442 emit_insn (gen_extendqisi2 (tmp1, addr1));
443 emit_insn (gen_extendqisi2 (tmp2, addr2));
444
445 emit_insn (gen_cmpeqsi_t (tmp2, const0_rtx));
446 jump = emit_jump_insn (gen_branch_true (L_end_loop_byte));
447 add_int_reg_note (jump, REG_BR_PROB, prob_unlikely);
448
449 emit_insn (gen_cmpeqsi_t (tmp1, tmp2));
450 if (flag_delayed_branch)
451 emit_insn (gen_zero_extendqisi2 (tmp2,
452 gen_lowpart (QImode,
453 tmp2)));
454 jump = emit_jump_insn (gen_branch_false (L_end_loop_byte));
455 add_int_reg_note (jump, REG_BR_PROB, prob_unlikely);
456
457 addr1 = adjust_address (addr1, QImode,
458 GET_MODE_SIZE (QImode));
459 addr2 = adjust_address (addr2, QImode,
460 GET_MODE_SIZE (QImode));
461 }
462
463 jump = emit_jump_insn (gen_jump_compact( L_end_loop_byte));
464 emit_barrier_after (jump);
465 }
466
467 emit_label (L_end_loop_long);
468
469 /* Found last word. Restart it byte per byte. */
470
471 emit_move_insn (s1_addr, plus_constant (Pmode, s1_addr,
472 -GET_MODE_SIZE (SImode)));
473 emit_move_insn (s2_addr, plus_constant (Pmode, s2_addr,
474 -GET_MODE_SIZE (SImode)));
475
476 /* fall thru. */
477 }
75c9129c 478
479 addr1 = adjust_automodify_address (addr1, QImode, s1_addr, 0);
480 addr2 = adjust_automodify_address (addr2, QImode, s2_addr, 0);
481
482 while (bytes--)
f4a24c51 483 {
484 emit_insn (gen_extendqisi2 (tmp1, addr1));
485 emit_insn (gen_extendqisi2 (tmp2, addr2));
486
487 emit_insn (gen_cmpeqsi_t (tmp2, const0_rtx));
488 jump = emit_jump_insn (gen_branch_true (L_end_loop_byte));
489 add_int_reg_note (jump, REG_BR_PROB, prob_unlikely);
490
491 emit_insn (gen_cmpeqsi_t (tmp1, tmp2));
492 if (flag_delayed_branch)
493 emit_insn (gen_zero_extendqisi2 (tmp2,
494 gen_lowpart (QImode, tmp2)));
495 jump = emit_jump_insn (gen_branch_false (L_end_loop_byte));
496 add_int_reg_note (jump, REG_BR_PROB, prob_unlikely);
497
498 addr1 = adjust_address (addr1, QImode, GET_MODE_SIZE (QImode));
499 addr2 = adjust_address (addr2, QImode, GET_MODE_SIZE (QImode));
500 }
75c9129c 501
502 jump = emit_jump_insn (gen_jump_compact( L_end_loop_byte));
503 emit_barrier_after (jump);
b421555d 504 }
7756601d 505 else
506 {
507 emit_insn (gen_cmpeqsi_t (len, const0_rtx));
508 emit_move_insn (operands[0], const0_rtx);
509 jump = emit_jump_insn (gen_branch_true (L_return));
510 add_int_reg_note (jump, REG_BR_PROB, prob_unlikely);
511 }
b421555d 512
75c9129c 513 addr1 = adjust_automodify_address (addr1, QImode, s1_addr, 0);
514 addr2 = adjust_automodify_address (addr2, QImode, s2_addr, 0);
c2daae6e 515
516 emit_label (L_loop_byte);
517
518 emit_insn (gen_extendqisi2 (tmp2, addr2));
519 emit_move_insn (s2_addr, plus_constant (Pmode, s2_addr, 1));
520
521 emit_insn (gen_extendqisi2 (tmp1, addr1));
522 emit_move_insn (s1_addr, plus_constant (Pmode, s1_addr, 1));
523
524 emit_insn (gen_cmpeqsi_t (tmp2, const0_rtx));
525 jump = emit_jump_insn (gen_branch_true (L_end_loop_byte));
526 add_int_reg_note (jump, REG_BR_PROB, prob_unlikely);
527
528 emit_insn (gen_cmpeqsi_t (tmp1, tmp2));
529 if (flag_delayed_branch)
530 emit_insn (gen_zero_extendqisi2 (tmp2, gen_lowpart (QImode, tmp2)));
531 jump = emit_jump_insn (gen_branch_false (L_end_loop_byte));
532 add_int_reg_note (jump, REG_BR_PROB, prob_unlikely);
533
534 if (TARGET_SH2)
535 emit_insn (gen_dect (len, len));
536 else
537 {
538 emit_insn (gen_addsi3 (len, len, GEN_INT (-1)));
539 emit_insn (gen_tstsi_t (len, len));
540 }
541
542 jump = emit_jump_insn (gen_branch_false (L_loop_byte));
543 add_int_reg_note (jump, REG_BR_PROB, prob_likely);
544 /* end byte loop. */
545
546 emit_label (L_end_loop_byte);
547
548 if (! flag_delayed_branch)
549 emit_insn (gen_zero_extendqisi2 (tmp2, gen_lowpart (QImode, tmp2)));
550 emit_insn (gen_zero_extendqisi2 (tmp1, gen_lowpart (QImode, tmp1)));
551
c2daae6e 552 emit_insn (gen_subsi3 (operands[0], tmp1, tmp2));
553
7756601d 554 emit_label (L_return);
555
c2daae6e 556 return true;
557}
558
f4a24c51 559/* Emit code to perform a strlen.
c2daae6e 560
561 OPERANDS[0] is the destination.
562 OPERANDS[1] is the string.
563 OPERANDS[2] is the char to search.
564 OPERANDS[3] is the alignment. */
565bool
566sh_expand_strlen (rtx *operands)
567{
568 rtx addr1 = operands[1];
569 rtx current_addr = copy_addr_to_reg (XEXP (addr1, 0));
570 rtx start_addr = gen_reg_rtx (Pmode);
571 rtx tmp0 = gen_reg_rtx (SImode);
572 rtx tmp1 = gen_reg_rtx (SImode);
79f6a8ed 573 rtx_code_label *L_return = gen_label_rtx ();
574 rtx_code_label *L_loop_byte = gen_label_rtx ();
c2daae6e 575
576 rtx jump;
79f6a8ed 577 rtx_code_label *L_loop_long = gen_label_rtx ();
578 rtx_code_label *L_end_loop_long = gen_label_rtx ();
c2daae6e 579
580 int align = INTVAL (operands[3]);
581
582 emit_move_insn (operands[0], GEN_INT (-1));
583
584 /* remember start of string. */
585 emit_move_insn (start_addr, current_addr);
586
587 if (align < 4)
588 {
f07efc97 589 emit_insn (gen_tstsi_t (current_addr, GEN_INT (3)));
c2daae6e 590 jump = emit_jump_insn (gen_branch_false (L_loop_byte));
591 add_int_reg_note (jump, REG_BR_PROB, prob_likely);
592 }
593
594 emit_move_insn (tmp0, operands[2]);
595
596 addr1 = adjust_automodify_address (addr1, SImode, current_addr, 0);
597
9c00010f 598 /* start long loop. */
c2daae6e 599 emit_label (L_loop_long);
600
601 /* tmp1 is aligned, OK to load. */
602 emit_move_insn (tmp1, addr1);
603 emit_move_insn (current_addr, plus_constant (Pmode, current_addr, 4));
604
605 /* Is there a 0 byte ? */
606 emit_insn (gen_cmpstr_t (tmp0, tmp1));
b421555d 607
c2daae6e 608 jump = emit_jump_insn (gen_branch_false (L_loop_long));
609 add_int_reg_note (jump, REG_BR_PROB, prob_likely);
610 /* end loop. */
b421555d 611
c2daae6e 612 emit_label (L_end_loop_long);
b421555d 613
c2daae6e 614 emit_move_insn (current_addr, plus_constant (Pmode, current_addr, -4));
b421555d 615
c2daae6e 616 addr1 = adjust_address (addr1, QImode, 0);
b421555d 617
751d4d6f 618 /* unroll remaining bytes. */
9c00010f 619 for (int i = 0; i < 4; ++i)
620 {
621 emit_insn (gen_extendqisi2 (tmp1, addr1));
622 emit_move_insn (current_addr, plus_constant (Pmode, current_addr, 1));
623 emit_insn (gen_cmpeqsi_t (tmp1, const0_rtx));
624 jump = emit_jump_insn (gen_branch_true (L_return));
625 add_int_reg_note (jump, REG_BR_PROB, prob_likely);
626 }
751d4d6f 627
751d4d6f 628 emit_barrier_after (jump);
629
630 /* start byte loop. */
c2daae6e 631 emit_label (L_loop_byte);
b421555d 632
c2daae6e 633 emit_insn (gen_extendqisi2 (tmp1, addr1));
634 emit_move_insn (current_addr, plus_constant (Pmode, current_addr, 1));
b421555d 635
c2daae6e 636 emit_insn (gen_cmpeqsi_t (tmp1, const0_rtx));
637 jump = emit_jump_insn (gen_branch_false (L_loop_byte));
638 add_int_reg_note (jump, REG_BR_PROB, prob_likely);
b421555d 639
c2daae6e 640 /* end loop. */
b421555d 641
751d4d6f 642 emit_label (L_return);
643
9c00010f 644 emit_insn (gen_addsi3 (start_addr, start_addr, GEN_INT (1)));
c2daae6e 645 emit_insn (gen_subsi3 (operands[0], current_addr, start_addr));
b421555d 646
c2daae6e 647 return true;
b421555d 648}
1878fb5b 649
f4a24c51 650/* Emit code to perform a memset.
1878fb5b 651
652 OPERANDS[0] is the destination.
653 OPERANDS[1] is the size;
654 OPERANDS[2] is the char to search.
655 OPERANDS[3] is the alignment. */
656void
657sh_expand_setmem (rtx *operands)
658{
79f6a8ed 659 rtx_code_label *L_loop_byte = gen_label_rtx ();
660 rtx_code_label *L_loop_word = gen_label_rtx ();
661 rtx_code_label *L_return = gen_label_rtx ();
1878fb5b 662 rtx jump;
663 rtx dest = copy_rtx (operands[0]);
664 rtx dest_addr = copy_addr_to_reg (XEXP (dest, 0));
665 rtx val = force_reg (SImode, operands[2]);
666 int align = INTVAL (operands[3]);
1878fb5b 667 rtx len = force_reg (SImode, operands[1]);
668
669 if (! CONST_INT_P (operands[1]))
670 return;
671
f4a24c51 672 int count = INTVAL (operands[1]);
1878fb5b 673
674 if (CONST_INT_P (operands[2])
675 && (INTVAL (operands[2]) == 0 || INTVAL (operands[2]) == -1) && count > 8)
676 {
677 rtx lenw = gen_reg_rtx (SImode);
678
679 if (align < 4)
f4a24c51 680 {
f07efc97 681 emit_insn (gen_tstsi_t (dest_addr, GEN_INT (3)));
f4a24c51 682 jump = emit_jump_insn (gen_branch_false (L_loop_byte));
683 add_int_reg_note (jump, REG_BR_PROB, prob_likely);
684 }
1878fb5b 685
f4a24c51 686 /* word count. Do we have iterations ? */
1878fb5b 687 emit_insn (gen_lshrsi3 (lenw, len, GEN_INT (2)));
688
689 dest = adjust_automodify_address (dest, SImode, dest_addr, 0);
690
691 /* start loop. */
692 emit_label (L_loop_word);
693
694 if (TARGET_SH2)
695 emit_insn (gen_dect (lenw, lenw));
696 else
f4a24c51 697 {
698 emit_insn (gen_addsi3 (lenw, lenw, GEN_INT (-1)));
699 emit_insn (gen_tstsi_t (lenw, lenw));
700 }
1878fb5b 701
702 emit_move_insn (dest, val);
703 emit_move_insn (dest_addr, plus_constant (Pmode, dest_addr,
f4a24c51 704 GET_MODE_SIZE (SImode)));
1878fb5b 705
706
707 jump = emit_jump_insn (gen_branch_false (L_loop_word));
708 add_int_reg_note (jump, REG_BR_PROB, prob_likely);
709 count = count % 4;
710
711 dest = adjust_address (dest, QImode, 0);
712
713 val = gen_lowpart (QImode, val);
714
715 while (count--)
f4a24c51 716 {
717 emit_move_insn (dest, val);
718 emit_move_insn (dest_addr, plus_constant (Pmode, dest_addr,
719 GET_MODE_SIZE (QImode)));
720 }
1878fb5b 721
722 jump = emit_jump_insn (gen_jump_compact (L_return));
723 emit_barrier_after (jump);
724 }
725
726 dest = adjust_automodify_address (dest, QImode, dest_addr, 0);
727
728 /* start loop. */
729 emit_label (L_loop_byte);
730
731 if (TARGET_SH2)
732 emit_insn (gen_dect (len, len));
733 else
734 {
735 emit_insn (gen_addsi3 (len, len, GEN_INT (-1)));
736 emit_insn (gen_tstsi_t (len, len));
737 }
738
739 val = gen_lowpart (QImode, val);
740 emit_move_insn (dest, val);
741 emit_move_insn (dest_addr, plus_constant (Pmode, dest_addr,
742 GET_MODE_SIZE (QImode)));
743
744 jump = emit_jump_insn (gen_branch_false (L_loop_byte));
745 add_int_reg_note (jump, REG_BR_PROB, prob_likely);
746
747 emit_label (L_return);
1878fb5b 748}