-
Notifications
You must be signed in to change notification settings - Fork 17
/
Copy pathreload.c
1916 lines (1676 loc) · 55.6 KB
/
reload.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/* Search an insn for pseudo regs that must be in hard regs and are not.
Copyright (C) 1987 Free Software Foundation, Inc.
This file is part of GNU CC.
GNU CC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY. No author or distributor
accepts responsibility to anyone for the consequences of using it
or for whether it serves any particular purpose or works at all,
unless he says so in writing. Refer to the GNU CC General Public
License for full details.
Everyone is granted permission to copy, modify and redistribute
GNU CC, but only under the conditions described in the
GNU CC General Public License. A copy of this license is
supposed to have been given to you along with GNU CC so you
can know your rights and responsibilities. It should be in a
file named COPYING. Among other things, the copyright notice
and this notice must be preserved on all copies. */
/* This file contains subroutines used only from the file reload1.c.
It knows how to scan one insn for operands and values
that need to be copied into registers to make valid code.
It also finds other operands and values which are valid
but for which equivalent values in registers exist and
ought to be used instead.
Before processing the first insn of the function, call `init_reload'.
To scan an insn, call `find_reloads'. This does two things:
1. sets up tables describing which values must be reloaded
for this insn, and what kind of hard regs they must be reloaded into;
2. optionally record the locations where those values appear in
the data, so they can be replaced properly later.
This is done only if the second arg to `find_reloads' is nonzero.
The third arg to `find_reloads' specifies the value of `indirect_ok'.
Then you must choose the hard regs to reload those pseudo regs into,
and generate appropriate load insns before this insn and perhaps
also store insns after this insn. Set up the array `reload_reg_rtx'
to contain the REG rtx's for the registers you used. In some
cases `find_reloads' will return a nonzero value in `reload_reg_rtx'
for certain reloads. Then that tells you which register to use,
so you do not need to allocate one. But you still do need to add extra
instructions to copy the value into and out of that register.
Finally you must call `subst_reloads' to substitute the reload reg rtx's
into the locations already recorded.
NOTE SIDE EFFECTS:
find_reloads can alter the operands of the instruction it is called on.
1. Any uses of VOLATILE are removed, since it no longer matters.
2. Pseudo-registers that are equivalent to constants are replaced
with those constants if they are not in hard registers.
3. Two operands of any sort may be interchanged, if they are in a
commutative instruction.
This happens only if find_reloads thinks the instruction will compile
better that way.
In all of these cases, calling find_reloads a second time immediately
after would produce no further change.
*/
/* Tell config.h to use the strict definitions of REG_OK_FOR_INDEX_P, etc.
The strict definitions reject pseudo regs. */
#define REG_OK_STRICT
#include "config.h"
#include "rtl.h"
#include "insn-config.h"
#include "recog.h"
#include "reload.h"
#include "regs.h"
#include "hard-reg-set.h"
extern char insn_operand_address_p[][MAX_RECOG_OPERANDS];
/* The variables set up by `find_reloads' are:
n_reloads number of distinct reloads needed; max reload # + 1
tables indexed by reload number
reload_in rtx for value to reload from
reload_out rtx for where to store reload-reg afterward if nec
(often the same as reload_in)
reload_reg_class enum reg_class, saying what regs to reload into
reload_mode enum machine_mode; mode this operand should have
when reloaded.
reload_optional char, nonzero for an optional reload.
Optional reloads are ignored unless the
value is already sitting in a register.
reload_inc int, amount to increment reload_in by
before this insn.
reload_reg_rtx rtx. This is the register to reload into.
If it is zero when `find_reloads' returns,
you must find a suitable register in the class
specified by reload_reg_class, and store here
an rtx for that register with mode from reload_mode.
*/
int n_reloads;
rtx reload_in[FIRST_PSEUDO_REGISTER];
rtx reload_out[FIRST_PSEUDO_REGISTER];
enum reg_class reload_reg_class[FIRST_PSEUDO_REGISTER];
enum machine_mode reload_mode[FIRST_PSEUDO_REGISTER];
rtx reload_reg_rtx[FIRST_PSEUDO_REGISTER];
char reload_optional[FIRST_PSEUDO_REGISTER];
int reload_inc[FIRST_PSEUDO_REGISTER];
/* Replacing reloads.
If `replace_reloads' is nonzero, then as each reload is recorded
an entry is made for it in the table `replacements'.
Then later `subst_reloads' can look through that table and
perform all the replacements needed. */
/* Nonzero means record the places to replace. */
static int replace_reloads;
/* Each replacement is recorded with a structure like this. */
struct replacement
{
rtx *where; /* Location to store in */
int what; /* which reload this is for */
enum machine_mode mode; /* mode it must have */
};
static struct replacement replacements[MAX_RECOG_OPERANDS * ((MAX_REGS_PER_ADDRESS * 2) + 1)];
/* Number of replacements currently recorded. */
static int n_replacements;
/* The instruction we are doing reloads for;
so we can test whether a register dies in it. */
static rtx this_insn;
/* Nonzero means (MEM (REG n)) is valid even if (REG n) is spilled. */
static int indirect_ok;
/* If hard_regs_live_known is nonzero,
we can tell which hard regs are currently live,
at least enough to succeed in choosing dummy reloads. */
static int hard_regs_live_known;
/* Indexed by hard reg number,
element is nonegative if hard reg has been spilled.
This vector is passed to `find_reloads' as an argument
and is not changed here. */
static short *static_reload_reg_p;
static enum reg_class reg_class_subunion[N_REG_CLASSES][N_REG_CLASSES]
= REG_CLASS_SUBUNION;
static HARD_REG_SET reg_class_contents[] = REG_CLASS_CONTENTS;
static char call_clobbered_regs[] = CALL_USED_REGISTERS;
static rtx find_reloads_toplev ();
static void find_reloads_address ();
static void find_reloads_address_1 ();
static int reg_dead_here_p ();
static int hard_reg_dead_here_p ();
static int hard_reg_set_here_p ();
static int refers_to_regno_p ();
static rtx forget_volatility ();
static rtx subst_reg_equivs ();
rtx find_equiv_reg ();
static int find_inc_amount ();
/* Record one reload that needs to be performed.
IN is an rtx saying where the data are to be found before this instruction.
OUT says where they must be stored after the instruction.
(IN is zero for data not read, and OUT is zero for data not written.)
INLOC and OUTLOC point to the places in the instructions where
IN and OUT were found.
CLASS is a register class required for the reloaded data.
INMODE is the machine mode that the instruction requires
for the reg that replaces IN and OUTMODE is likewise for OUT.
If IN is zero, then OUT's location and mode should be passed as
INLOC and INMODE.
OPTIONAL nonzero means this reload does not need to be performed:
it can be discarded if that is more convenient. */
static int
push_reload (in, out, inloc, outloc, class, inmode, outmode, optional)
register rtx in, out;
rtx *inloc, *outloc;
enum reg_class class;
enum machine_mode inmode, outmode;
int optional;
{
register int i;
enum machine_mode mode = inmode;
if (outloc != 0 && GET_MODE_SIZE (outmode) > GET_MODE_SIZE (mode))
mode = outmode;
/* If IN is a pseudo register everywhere-equivalent to a constant, and
it is not in a hard register, reload straight from the constant,
since we want to get rid of such pseudo registers. */
if (in != 0 && GET_CODE (in) == REG)
{
register int regno = REGNO (in);
if (regno >= FIRST_PSEUDO_REGISTER && reg_renumber[regno] < 0
&& reg_equiv_constant[regno] != 0)
in = reg_equiv_constant[regno];
}
/* Likewise for OUT. Of course, OUT will never be equivalent to
an actual constant, but it might be equivalent to a memory location
(in the case of a parameter). */
if (out != 0 && GET_CODE (out) == REG)
{
register int regno = REGNO (out);
if (regno >= FIRST_PSEUDO_REGISTER && reg_renumber[regno] < 0
&& reg_equiv_constant[regno] != 0)
out = reg_equiv_constant[regno];
}
if (class == NO_REGS)
abort ();
/* Narrow down the class of register wanted if that is
desirable on this machine for efficiency. */
if (in != 0)
class = PREFERRED_RELOAD_CLASS(in, class);
/* We can use an existing reload if the class is right
and at least one of IN and OUT is a match
and the other is at worst neutral.
(A zero compared against anything is neutral.) */
for (i = 0; i < n_reloads; i++)
if (reload_reg_class[i] == class
&& ((in != 0 && reload_in[i] == in
&& (out == 0 || reload_out[i] == 0 || reload_out[i] == out))
||
(out != 0 && reload_out[i] == out
&& (in == 0 || reload_in[i] == 0 || reload_in[i] == in))))
break;
if (i == n_reloads)
{
/* We found no existing reload suitable for re-use.
So add an additional reload. */
reload_in[i] = in;
reload_out[i] = out;
reload_reg_class[i] = class;
reload_mode[i] = mode;
reload_reg_rtx[i] = 0;
reload_optional[i] = optional;
reload_inc[i] = 0;
n_reloads++;
}
else
{
/* We are reusing an existing reload,
but we may have additional information for it.
For example, we may now have both IN and OUT
while the old one may have just one of them. */
if (GET_MODE_SIZE (mode) > GET_MODE_SIZE (reload_mode[i]))
reload_mode[i] = mode;
if (in != 0)
reload_in[i] = in;
if (out != 0)
reload_out[i] = out;
reload_optional[i] &= optional;
}
/* If this is an IN/OUT reload in an insn that sets the CC,
it must be for an autoincrement. It doesn't work to store
the incremented value after the insn because that would clobber the CC.
So we must do the increment of the value reloaded from,
increment it, store it back, then decrement again. */
if (out != 0 && GET_CODE (PATTERN (this_insn)) == SET
&& SET_DEST (PATTERN (this_insn)) == cc0_rtx)
{
out = 0;
reload_out[i] = 0;
reload_inc[i] = find_inc_amount (PATTERN (this_insn), in);
/* If we did not find a nonzero amount-to-increment-by,
that contradicts the belief that IN is being incremented
in an address in this insn. */
if (reload_inc[i] == 0)
abort ();
}
/* If we will replace IN and OUT with the reload-reg,
record where they are located so that substitution need
not do a tree walk. */
if (replace_reloads)
{
if (inloc != 0)
{
register struct replacement *r = &replacements[n_replacements++];
r->what = i;
r->where = inloc;
r->mode = inmode;
}
if (outloc != 0 && outloc != inloc)
{
register struct replacement *r = &replacements[n_replacements++];
r->what = i;
r->where = outloc;
r->mode = outmode;
}
}
/* If this reload is just being introduced and it has both
an incoming quantity and an outgoing quantity that are
supposed to be made to match, see if either one of the two
can serve as the place to reload into.
If one of them is acceptable, set reload_reg_rtx[i]
to that one. */
if (in != 0 && out != 0 && in != out && reload_reg_rtx[i] == 0)
{
/* See if OUT will do. */
while (GET_CODE (out) == SUBREG)
out = SUBREG_REG (out);
if (GET_CODE (out) == REG)
{
register int regno = REGNO (out);
/* When we consider whether the insn uses OUT,
ignore references within IN. They don't prevent us
from copying IN into OUT, because those refs would
move into the insn that reloads IN.
However, we only ignore IN in its role as this operand.
If the insn uses IN elsewhere and it contains OUT,
that counts. We can't be sure it's the "same" operand
so it might not go through this reload. */
*inloc = const0_rtx;
if (reg_renumber[regno] >= 0)
regno = reg_renumber[regno];
if (regno < FIRST_PSEUDO_REGISTER
&& ! refers_to_regno_p (regno, PATTERN (this_insn), outloc)
&& TEST_HARD_REG_BIT (reg_class_contents[(int) reload_reg_class[i]], regno))
{
reload_reg_rtx[i] = out;
/* If the outgoing register already contains the same value
as the incoming one, we can dispense with loading it.
The easiest way to tell the caller that is to give a phony
value for the incoming operand (same as outgoing one). */
if ((GET_CODE (in) == REG || CONSTANT_ADDRESS_P (in))
&& 0 != find_equiv_reg (in, this_insn, 0, REGNO (out),
static_reload_reg_p))
reload_in[i] = out;
}
*inloc = in;
}
while (GET_CODE (in) == SUBREG)
in = SUBREG_REG (in);
/* Consider using IN if OUT was not acceptable
or if OUT dies in this insn (like the quotient in a divmod insn).
We can't use IN unless it is free after this insn,
which means we must know accurately which hard regs are live. */
if (hard_regs_live_known
&& GET_CODE (in) == REG
&& (reload_reg_rtx[i] == 0
|| reg_dead_here_p (REGNO (reload_reg_rtx[i]), this_insn)))
{
register int regno = REGNO (in);
if (reg_dead_here_p (regno, this_insn))
{
if (reg_renumber[regno] >= 0)
regno = reg_renumber[regno];
if (regno < FIRST_PSEUDO_REGISTER
&& ! hard_reg_set_here_p (regno, PATTERN (this_insn))
&& TEST_HARD_REG_BIT (reg_class_contents[(int) reload_reg_class[i]], regno))
{
/* If we were going to use OUT as the reload reg
and changed our mind, it means OUT is a dummy that
dies here. So don't bother copying value to it. */
if (reload_reg_rtx[i] == out)
reload_out[i] = 0;
reload_reg_rtx[i] = in;
}
}
}
}
return i;
}
/* Record an additional place we must replace a value
for which we have already recorded a reload.
RELOADNUM is the value returned by push_reload
when the reload was recorded.
This is used in insn patterns that use match_dup. */
static void
push_replacement (loc, reloadnum, mode)
rtx *loc;
int reloadnum;
enum machine_mode mode;
{
if (replace_reloads)
{
register struct replacement *r = &replacements[n_replacements++];
r->what = reloadnum;
r->where = loc;
r->mode = mode;
}
}
/* This page contains subroutines used mainly for determining
whether the IN or an OUT of a reload can serve as the
reload register. */
/* Return 1 if hard reg number REGNO is on INSN's dead list,
either explicitly or in the guise of a pseudo-reg allocated to REGNO. */
static int
hard_reg_dead_here_p (regno, insn)
register int regno;
rtx insn;
{
register rtx link;
for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
if ((enum reg_note) GET_MODE (link) == REG_DEAD)
{
register int r = REGNO (XEXP (link, 0));
if (reg_renumber[r] >= 0)
r = reg_renumber[r];
if (r == regno)
return 1;
}
return 0;
}
/* Return 1 if hard reg number REGNO is stored in by expression X,
either explicitly or in the guise of a pseudo-reg allocated to REGNO.
X should be the body of an instruction. */
static int
hard_reg_set_here_p (regno, x)
register int regno;
rtx x;
{
if (GET_CODE (x) == SET)
{
register rtx op0 = SET_DEST (x);
if (GET_CODE (op0) == REG)
{
register int r = REGNO (op0);
if (reg_renumber[r] >= 0)
r = reg_renumber[r];
if (r == regno)
return 1;
}
}
else if (GET_CODE (x) == PARALLEL)
{
register int i = XVECLEN (x, 0) - 1;
for (; i >= 0; i--)
if (hard_reg_set_here_p (regno, XVECEXP (x, 0, i)))
return 1;
}
return 0;
}
/* Return nonzero if register number REGNO is explicitly on the
dead-list of INSN. */
static int
reg_dead_here_p (regno, insn)
register int regno;
rtx insn;
{
register rtx link;
for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
if ((enum reg_note) GET_MODE (link) == REG_DEAD
&& REGNO (XEXP (link, 0)) == regno)
return 1;
return 0;
}
/* Return nonzero if hard register REGNO appears
either explicitly or implicitly in X
other than being stored into.
References contained within the substructure at LOC do not count. */
static int
refers_to_regno_p (regno, x, loc)
int regno;
rtx x;
rtx *loc;
{
register int i;
register RTX_CODE code;
register char *fmt;
repeat:
code = GET_CODE (x);
if (code == REG)
{
i = REGNO (x);
if (reg_renumber[i] >= 0)
i = reg_renumber[i];
return i == regno;
}
if (code == SET)
{
if (GET_CODE (SET_DEST (x)) != REG
&& refers_to_regno_p (regno, SET_DEST (x), loc))
return 1;
if (loc == &SET_SRC (x))
return 0;
x = SET_SRC (x);
goto repeat;
}
/* X does not match, so try its subexpressions. */
fmt = GET_RTX_FORMAT (code);
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
if (fmt[i] == 'e' && loc != &XEXP (x, i))
{
if (i == 0)
{
x = XEXP (x, 0);
goto repeat;
}
else
if (refers_to_regno_p (regno, XEXP (x, i), loc))
return 1;
}
else if (fmt[i] == 'E')
{
register int j;
for (j = XVECLEN (x, i) - 1; j >=0; j--)
if (loc != &XVECEXP (x, i, j)
&& refers_to_regno_p (regno, XVECEXP (x, i, j), loc))
return 1;
}
}
return 0;
}
/* Like rtx_equal_p except that it considers two REGs as equal
if they renumber to the same value. */
int
rtx_renumbered_equal_p (x, y)
rtx x, y;
{
register int i;
register RTX_CODE code = GET_CODE (x);
register char *fmt;
if (x == y)
return 1;
if ((code == REG || (code == SUBREG && GET_CODE (SUBREG_REG (x)) == REG))
&& (GET_CODE (y) == REG || (GET_CODE (y) == SUBREG
&& GET_CODE (SUBREG_REG (y)) == REG)))
{
register int j;
if (code == SUBREG)
{
i = REGNO (SUBREG_REG (x));
if (reg_renumber[i] >= 0)
i = reg_renumber[i];
i += SUBREG_WORD (x);
}
else
{
i = REGNO (x);
if (reg_renumber[i] >= 0)
i = reg_renumber[i];
}
if (GET_CODE (y) == SUBREG)
{
j = REGNO (SUBREG_REG (y));
if (reg_renumber[j] >= 0)
j = reg_renumber[j];
j += SUBREG_WORD (y);
}
else
{
j = REGNO (y);
if (reg_renumber[j] >= 0)
j = reg_renumber[j];
}
return i == j;
}
if (code != GET_CODE (y))
return 0;
if (code == LABEL_REF)
return XEXP (x, 0) == XEXP (y, 0);
if (code == SYMBOL_REF)
return XSTR (x, 0) == XSTR (y, 0);
/* (MULT:SI x y) and (MULT:HI x y) are NOT equivalent. */
if (GET_MODE (x) != GET_MODE (y))
return 0;
/* Compare the elements. If any pair of corresponding elements
fail to match, return 0 for the whole things. */
fmt = GET_RTX_FORMAT (code);
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
switch (fmt[i])
{
case 'i':
if (XINT (x, i) != XINT (y, i))
return 0;
break;
case 'e':
if (rtx_renumbered_equal_p (XEXP (x, i), XEXP (y, i)) == 0)
return 0;
break;
case '0':
break;
/* It is believed that rtx's at this level will never
contain anything but integers and other rtx's,
except for within LABEL_REFs and SYMBOL_REFs. */
default:
abort ();
}
}
return 1;
}
/* Main entry point of this file: search the body of INSN
for values that need reloading and record them with push_reload.
REPLACE nonzero means record also where the values occur
so that subst_reloads can be used.
IND_OK says that a memory reference is a valid memory address.
LIVE_KNOWN says we have valid information about which hard
regs are live at each point in the program; this is true when
we are called from global_alloc but false when stupid register
allocation has been done.
RELOAD_REG_P if nonzero is a vector indexed by hard reg number
which is nonzero if the reg has been commandeered for reloading into.
It is copied into STATIC_RELOAD_REG_P and referenced from there
by various subroutines. */
void
find_reloads (insn, replace, ind_ok, live_known, reload_reg_p)
rtx insn;
int replace, ind_ok;
int live_known;
short *reload_reg_p;
{
#ifdef REGISTER_CONSTRAINTS
enum reload_modified { RELOAD_NOTHING, RELOAD_READ, RELOAD_READ_WRITE, RELOAD_WRITE };
register int insn_code_number;
register int i;
int noperands;
char *constraints[MAX_RECOG_OPERANDS];
int this_alternative[MAX_RECOG_OPERANDS];
char this_alternative_win[MAX_RECOG_OPERANDS];
int this_alternative_matches[MAX_RECOG_OPERANDS];
int swapped;
int goal_alternative[MAX_RECOG_OPERANDS];
int this_alternative_number;
int goal_alternative_number;
int operand_reloadnum[MAX_RECOG_OPERANDS];
int goal_alternative_matches[MAX_RECOG_OPERANDS];
int goal_alternative_matched[MAX_RECOG_OPERANDS];
char goal_alternative_win[MAX_RECOG_OPERANDS];
int goal_alternative_swapped;
enum reload_modified modified[MAX_RECOG_OPERANDS];
int best;
int commutative;
char operands_match[MAX_RECOG_OPERANDS][MAX_RECOG_OPERANDS];
rtx body = PATTERN (insn);
this_insn = insn;
n_reloads = 0;
n_replacements = 0;
replace_reloads = replace;
indirect_ok = ind_ok;
hard_regs_live_known = live_known;
static_reload_reg_p = reload_reg_p;
if (GET_CODE (body) == USE || GET_CODE (body) == CLOBBER
|| GET_CODE (body) == ASM_INPUT
|| GET_CODE (body) == ADDR_VEC || GET_CODE (body) == ADDR_DIFF_VEC)
return;
forget_volatility (PATTERN (insn));
insn_code_number = recog_memoized (insn);
noperands = insn_n_operands[insn_code_number];
insn_extract (insn);
if (noperands == 0)
return;
commutative = 0;
bcopy (insn_operand_constraint[insn_code_number],
constraints, sizeof constraints);
/* If we will need to know, later, whether some pair of operands
are the same, we must compare them now and save the result.
Reloading the base and index registers will clobber them
and afterward they will fail to match. */
for (i = 0; i < noperands; i++)
{
register char *p = constraints[i];
register int c;
while (c = *p++)
if (c == '%')
commutative = 1;
else if (c >= '0' && c <= '9')
{
c -= '0';
operands_match[c][i]
= rtx_renumbered_equal_p (recog_operand[c], recog_operand[i]);
if (commutative)
{
if (c == 1 || c == 2)
operands_match[3 - c][i]
= rtx_renumbered_equal_p (recog_operand[3 - c], recog_operand[i]);
if (i == 1 || i == 2)
operands_match[c][3 - i]
= rtx_renumbered_equal_p (recog_operand[c], recog_operand[3 - i]);
/* Note that c is supposed to be less than i.
No need to consider subtracting both c and i from 3
because in that case they are 1 and 2
and the element we want is operands_match[1][2]. */
}
}
}
/* Examine each operand that is a memory reference or memory address
and reload parts of the addresses into index registers.
While we are at it, initialize the array `modified'.
Also here any references to pseudo regs that didn't get hard regs
but are equivalent to constants get replaced in the insn itself
with those constants. Nobody will ever see them again. */
for (i = 0; i < noperands; i++)
{
register RTX_CODE code = GET_CODE (recog_operand[i]);
modified[i] = RELOAD_READ;
if (constraints[i][0] == 'p')
find_reloads_address (VOIDmode,
recog_operand[i], recog_operand_loc[i]);
if (code == MEM)
find_reloads_address (GET_MODE (recog_operand[i]),
XEXP (recog_operand[i], 0),
&XEXP (recog_operand[i], 0));
if (code == SUBREG)
find_reloads_toplev (recog_operand[i]);
if (code == REG)
{
register int regno = REGNO (recog_operand[i]);
if (regno >= FIRST_PSEUDO_REGISTER && reg_renumber[regno] < 0
&& reg_equiv_constant[regno] != 0)
recog_operand[i] = *recog_operand_loc[i]
= reg_equiv_constant[regno];
}
}
/* Now see what we need for pseudo-regs that didn't get hard regs
or got the wrong kind of hard reg. For this, we must consider
all the operands together against the register constraints. */
best = MAX_RECOG_OPERANDS + 100;
swapped = 0;
try_swapped:
this_alternative_number = 0;
/* The constraints are made of several alternatives.
Each operand's constraint looks like foo,bar,... with commas
separating the alternatives. The first alternatives for all
operands go together, the second alternatives go together, etc.
First loop over alternatives. */
while (*constraints[0])
{
/* Loop over operands for one constraint alternative. */
/* LOSERS counts those that don't fit this alternative
and would require loading. */
int losers = 0;
/* BAD is set to 1 if it some operand can't fit this alternative
even after reloading. */
int bad = 0;
/* REJECT is a count of how undesirable this alternative says it is
if any reloading is required. If the alternative matches exactly
then REJECT is ignored, but otherwise it gets this much
counted against it in addition to the reloading needed. */
int reject = 0;
for (i = 0; i < noperands; i++)
{
register char *p = constraints[i];
register int win = 0;
int badop = 1;
int c;
register rtx operand = recog_operand[i];
int offset = 0;
int force_reload = 0;
/* If the operand is a SUBREG, extract
the REG or MEM within. */
while (GET_CODE (operand) == SUBREG)
{
offset += SUBREG_WORD (operand);
operand = SUBREG_REG (operand);
if (GET_CODE (operand) == MEM
/*** This is overcautious, as for BYTES_BIG_ENDIAN it is still possible
to avoid setting force_reload if the mode of the subreg
is SImode or bigger. */
#ifndef BYTES_BIG_ENDIAN
&& offset != 0
#endif
&& !offsetable_address_p (operand))
force_reload = 1;
}
this_alternative[i] = (int) NO_REGS;
this_alternative_win[i] = 0;
this_alternative_matches[i] = -1;
/* Scan this alternative's specs for this operand;
set WIN if the operand fits any letter in this alternative.
Otherwise, clear BADOP if this operand could
fit some letter after reloads. */
while (*p && (c = *p++) != ',')
switch (c)
{
case '=':
modified[i] = RELOAD_WRITE;
break;
case '+':
modified[i] = RELOAD_READ_WRITE;
break;
case '*':
break;
case '%':
commutative = 1;
break;
case '?':
reject++;
break;
case '!':
reject = 100;
break;
case '#':
/* Ignore rest of this alternative as far as
reloading is concerned. */
while (*p && *p != ',') p++;
break;
case '0':
case '1':
case '2':
case '3':
case '4':
c -= '0';
this_alternative_matches[i] = c;
/* We are supposed to match a previous operand.
If we do, we win if that one did.
If we do not, then both of us lose. */
if ((swapped && (c != 1 || i != 2))
/* If we are matching as if operands 1 and 2 were swapped,
also pretend that operands_match had been computed
with them swapped.
But if i is 2 and c is 1, don't exchange them,
because operands_match is valid only on one
side of its diagonal. */
? (operands_match
[(c == 1 || c == 2) ? 3 - c : c]
[(i == 1 || i == 2) ? 3 - i : i])
: operands_match[c][i])
win = this_alternative_win[c];
else
{
if (this_alternative_win[c])
losers++;
this_alternative_win[c] = 0;
if (this_alternative[c] == (int) NO_REGS)
bad = 1;
}
/* This can be fixed with reloads if the operand
we are supposed to match can be fixed with reloads. */
badop = 0;
break;
case 'p':
/* All necessary reloads for an address_operand
were handled in find_reloads_address. */
this_alternative[i] = (int) ALL_REGS;
win = 1;
break;
case 'm':
if (GET_CODE (operand) == MEM
|| (GET_CODE (operand) == REG
&& REGNO (operand) >= FIRST_PSEUDO_REGISTER
&& reg_renumber[REGNO (operand)] < 0))
win = 1;
if (GET_CODE (operand) == CONST_DOUBLE)
bad = 0;
break;
case '<':
if (GET_CODE (operand) == MEM
&& (GET_CODE (XEXP (operand, 0)) == PRE_DEC
|| GET_CODE (XEXP (operand, 0)) == POST_DEC))
win = 1;
break;
case '>':
if (GET_CODE (operand) == MEM
&& (GET_CODE (XEXP (operand, 0)) == PRE_INC
|| GET_CODE (XEXP (operand, 0)) == POST_INC))
win = 1;
break;
/* Memory operand whose address is offsettable. */
case 'o':
if ((GET_CODE (operand) == MEM
&& offsetable_address_p (operand))
|| (GET_CODE (operand) == REG
&& REGNO (operand) >= FIRST_PSEUDO_REGISTER
&& reg_renumber[REGNO (operand)] < 0))
win = 1;
if (GET_CODE (operand) == CONST_DOUBLE)
bad = 0;
break;
case 'F':
if (GET_CODE (operand) == CONST_DOUBLE)
win = 1;
break;
case 'G':
case 'H':
if (GET_CODE (operand) == CONST_DOUBLE
&& CONST_DOUBLE_OK_FOR_LETTER_P (operand, c))
win = 1;
break;
case 's':
if (GET_CODE (operand) == CONST_INT)
break;
case 'i':
if (CONSTANT_ADDRESS_P (operand))
win = 1;
break;
case 'I':
case 'J':
case 'K':
case 'L':
case 'M':
if (GET_CODE (operand) == CONST_INT
&& CONST_OK_FOR_LETTER_P (INTVAL (operand), c))