1 /**
2  * Register allocator
3  *
4  * Compiler implementation of the
5  * $(LINK2 https://www.dlang.org, D programming language).
6  *
7  * Copyright:   Copyright (C) 1985-1998 by Symantec
8  *              Copyright (C) 2000-2023 by The D Language Foundation, All Rights Reserved
9  * Authors:     $(LINK2 https://www.digitalmars.com, Walter Bright)
10  * License:     $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
11  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/backend/cgreg.c, backend/cgreg.d)
12  */
13 
14 module dmd.backend.cgreg;
15 
16 import core.stdc.stdio;
17 import core.stdc.stdlib;
18 import core.stdc.string;
19 
20 import dmd.backend.cdef;
21 import dmd.backend.cc;
22 import dmd.backend.el;
23 import dmd.backend.global;
24 import dmd.backend.code;
25 import dmd.backend.code_x86;
26 import dmd.backend.codebuilder;
27 import dmd.backend.oper;
28 import dmd.backend.symtab;
29 import dmd.backend.ty;
30 import dmd.backend.type;
31 
32 import dmd.backend.barray;
33 import dmd.backend.dlist;
34 import dmd.backend.dvec;
35 
36 
37 nothrow:
38 @safe:
39 
40 private __gshared
41 {
42     int nretblocks;
43 
44     vec_t[REGMAX] regrange;
45 
46     Barray!int weights;
47 }
48 
49 @trusted
50 ref int WEIGHTS(int bi, int si) { return weights[bi * globsym.length + si]; }
51 
52 /******************************************
53  */
54 
55 @trusted
56 void cgreg_init()
57 {
58     if (!(config.flags4 & CFG4optimized))
59         return;
60 
61     // Use calloc() instead because sometimes the alloc is too large
62     //printf("1weights: dfo.length = %d, globsym.length = %d\n", dfo.length, globsym.length);
63     weights.setLength(dfo.length * globsym.length);
64     weights[] = 0;
65 
66     nretblocks = 0;
67     foreach (bi, b; dfo[])
68     {
69         if (b.BC == BCret || b.BC == BCretexp)
70             nretblocks++;
71         if (b.Belem)
72         {
73             //printf("b.Bweight = x%x\n",b.Bweight);
74             el_weights(cast(int)bi,b.Belem,b.Bweight);
75         }
76     }
77     memset(regrange.ptr, 0, regrange.sizeof);
78 
79     // Make adjustments to symbols we might stick in registers
80     for (size_t i = 0; i < globsym.length; i++)
81     {   uint sz;
82         Symbol *s = globsym[i];
83 
84         //printf("considering candidate '%s' for register\n", s.Sident.ptr);
85 
86         if (s.Srange)
87             s.Srange = vec_realloc(s.Srange,dfo.length);
88 
89         // Determine symbols that are not candidates
90         if (!(s.Sflags & GTregcand) ||
91             !s.Srange ||
92             (sz = cast(uint)type_size(s.Stype)) == 0 ||
93             (tysize(s.ty()) == -1) ||
94             (I16 && sz > REGSIZE) ||
95             (tyfloating(s.ty()) && !(config.fpxmmregs && tyxmmreg(s.ty())))
96            )
97         {
98             debug if (debugr)
99             {
100                 printf("not considering variable '%s' for register\n",s.Sident.ptr);
101                 if (!(s.Sflags & GTregcand))
102                     printf("\tnot GTregcand\n");
103                 if (!s.Srange)
104                     printf("\tno Srange\n");
105                 if (sz == 0)
106                     printf("\tsz == 0\n");
107                 if (tysize(s.ty()) == -1)
108                     printf("\ttysize\n");
109             }
110 
111             s.Sflags &= ~GTregcand;
112             continue;
113         }
114 
115         switch (s.Sclass)
116         {
117             case SC.parameter:
118                 // Do not put parameters in registers if they are not used
119                 // more than twice (otherwise we have a net loss).
120                 if (s.Sweight <= 2 && !tyxmmreg(s.ty()))
121                 {
122                     debug if (debugr)
123                         printf("parameter '%s' weight %d is not enough\n",s.Sident.ptr,s.Sweight);
124                     s.Sflags &= ~GTregcand;
125                     continue;
126                 }
127                 break;
128 
129             default:
130                 break;
131         }
132 
133         if (sz == 1)
134             s.Sflags |= GTbyte;
135 
136         if (!s.Slvreg)
137             s.Slvreg = vec_calloc(dfo.length);
138 
139         //printf("dfo.length = %d, numbits = %d\n",dfo.length,vec_numbits(s.Srange));
140         assert(vec_numbits(s.Srange) == dfo.length);
141     }
142 }
143 
144 /******************************************
145  */
146 
147 @trusted
148 void cgreg_term()
149 {
150     if (config.flags4 & CFG4optimized)
151     {
152         for (size_t i = 0; i < globsym.length; i++)
153         {
154             Symbol *s = globsym[i];
155             vec_free(s.Srange);
156             vec_free(s.Slvreg);
157             s.Srange = null;
158             s.Slvreg = null;
159         }
160 
161         for (size_t i = 0; i < regrange.length; i++)
162         {
163             if (regrange[i])
164             {   vec_free(regrange[i]);
165                 regrange[i] = null;
166             }
167         }
168 
169         // weights.dtor();   // save allocation for next time
170     }
171 }
172 
173 /*********************************
174  */
175 
176 @trusted
177 void cgreg_reset()
178 {
179     for (size_t j = 0; j < regrange.length; j++)
180         if (!regrange[j])
181             regrange[j] = vec_calloc(dfo.length);
182         else
183             vec_clear(regrange[j]);
184 }
185 
186 /*******************************
187  * Registers used in block bi.
188  */
189 
190 @trusted
191 void cgreg_used(uint bi,regm_t used)
192 {
193     for (size_t j = 0; used; j++)
194     {   if (used & 1)           // if register j is used
195             vec_setbit(bi,regrange[j]);
196         used >>= 1;
197     }
198 }
199 
200 /*************************
201  * Run through a tree calculating symbol weights.
202  */
203 
204 @trusted
205 private void el_weights(int bi,elem *e,uint weight)
206 {
207     while (1)
208     {   elem_debug(e);
209 
210         int op = e.Eoper;
211         if (!OTleaf(op))
212         {
213             // This prevents variable references within common subexpressions
214             // from adding to the variable's usage count.
215             if (e.Ecount)
216             {
217                 if (e.Ecomsub)
218                     weight = 0;
219                 else
220                     e.Ecomsub = 1;
221             }
222 
223             if (OTbinary(op))
224             {   el_weights(bi,e.EV.E2,weight);
225                 if ((OTopeq(op) || OTpost(op)) && e.EV.E1.Eoper == OPvar)
226                 {
227                     if (weight >= 10)
228                         weight += 10;
229                     else
230                         weight++;
231                 }
232             }
233             e = e.EV.E1;
234         }
235         else
236         {
237             switch (op)
238             {
239                 case OPvar:
240                     Symbol *s = e.EV.Vsym;
241                     if (s.Ssymnum != SYMIDX.max && s.Sflags & GTregcand)
242                     {
243                         s.Sweight += weight;
244                         //printf("adding %d weight to '%s' (block %d, Ssymnum %d), giving Sweight %d\n",weight,s.Sident.ptr,bi,s.Ssymnum,s.Sweight);
245                         if (weights)
246                             WEIGHTS(bi,cast(int)s.Ssymnum) += weight;
247                     }
248                     break;
249 
250                 default:
251                     break;
252             }
253             return;
254         }
255     }
256 }
257 
258 /*****************************************
259  * Determine 'benefit' of assigning symbol s to register reg.
260  * Benefit is roughly the number of clocks saved.
261  * A negative value means that s cannot or should not be assigned to reg.
262  */
263 
264 @trusted
265 private int cgreg_benefit(Symbol *s, reg_t reg, Symbol *retsym)
266 {
267     int benefit;
268     int benefit2;
269     block *b;
270     int bi;
271     int gotoepilog;
272     int retsym_cnt;
273 
274     //printf("cgreg_benefit(s = '%s', reg = %d)\n", s.Sident.ptr, reg);
275 
276     vec_sub(s.Slvreg,s.Srange,regrange[reg]);
277     int si = cast(int)s.Ssymnum;
278 
279     reg_t dst_integer_reg;
280     reg_t dst_float_reg;
281     cgreg_dst_regs(&dst_integer_reg, &dst_float_reg);
282 
283 Lagain:
284     //printf("again\n");
285     benefit = 0;
286     retsym_cnt = 0;
287 
288 static if (1) // causes assert failure in std.range(4488) from std.parallelism's unit tests
289 {
290       // (it works now - but keep an eye on it for the moment)
291     // If s is passed in a register to the function, favor that register
292     if ((s.Sclass == SC.fastpar || s.Sclass == SC.shadowreg) && s.Spreg == reg)
293         ++benefit;
294 }
295 
296     // Make sure we have enough uses to justify
297     // using a register we must save
298     if (fregsaved & (1 << reg) & mfuncreg)
299         benefit -= 1 + nretblocks;
300 
301     for (bi = 0; (bi = cast(uint) vec_index(bi, s.Srange)) < dfo.length; ++bi)
302     {   int inoutp;
303         int inout_;
304 
305         b = dfo[bi];
306         switch (b.BC)
307         {
308             case BCjcatch:
309             case BCcatch:
310             case BC_except:
311             case BC_finally:
312             case BC_lpad:
313             case BC_ret:
314                 s.Sflags &= ~GTregcand;
315                 goto Lcant;             // can't assign to register
316 
317             default:
318                 break;
319         }
320         if (vec_testbit(bi,s.Slvreg))
321         {   benefit += WEIGHTS(bi,si);
322             //printf("WEIGHTS(%d,%d) = %d, benefit = %d\n",bi,si,WEIGHTS(bi,si),benefit);
323             inout_ = 1;
324 
325             if (s == retsym && (reg == dst_integer_reg || reg == dst_float_reg) && b.BC == BCretexp)
326             {   benefit += 1;
327                 retsym_cnt++;
328                 //printf("retsym, benefit = %d\n",benefit);
329                 if (s.Sfl == FLreg && !vec_disjoint(s.Srange,regrange[reg]))
330                     goto Lcant;                         // don't spill if already in register
331             }
332         }
333         else
334             inout_ = -1;
335 
336         // Look at predecessors to see if we need to load in/out of register
337         gotoepilog = 0;
338     L2:
339         inoutp = 0;
340         benefit2 = 0;
341         foreach (bl; ListRange(b.Bpred))
342         {
343             block *bp = list_block(bl);
344             int bpi = bp.Bdfoidx;
345             if (!vec_testbit(bpi,s.Srange))
346                 continue;
347             if (gotoepilog && bp.BC == BCgoto)
348             {
349                 if (vec_testbit(bpi,s.Slvreg))
350                 {
351                     if (inout_ == -1)
352                         benefit2 -= bp.Bweight;        // need to mov into mem
353                 }
354                 else
355                 {
356                     if (inout_ == 1)
357                         benefit2 -= bp.Bweight;        // need to mov into reg
358                 }
359             }
360             else if (vec_testbit(bpi,s.Slvreg))
361             {
362                 switch (inoutp)
363                 {
364                     case 0:
365                         inoutp = 1;
366                         if (inout_ != 1)
367                         {   if (gotoepilog)
368                             {   vec_clearbit(bpi,s.Slvreg);
369                                 goto Lagain;
370                             }
371                             benefit2 -= b.Bweight;     // need to mov into mem
372                         }
373                         break;
374                     case 1:
375                         break;
376                     case -1:
377                         if (gotoepilog == 0)
378                         {   gotoepilog = 1;
379                             goto L2;
380                         }
381                         vec_clearbit(bpi,s.Slvreg);
382                         goto Lagain;
383 
384                     default:
385                         assert(0);
386                 }
387             }
388             else
389             {
390                 switch (inoutp)
391                 {
392                     case 0:
393                         inoutp = -1;
394                         if (inout_ != -1)
395                         {   if (gotoepilog)
396                             {   vec_clearbit(bi,s.Slvreg);
397                                 goto Lagain;
398                             }
399                             benefit2 -= b.Bweight;     // need to mov into reg
400                         }
401                         break;
402                     case 1:
403                         if (gotoepilog == 0)
404                         {   gotoepilog = 1;
405                             goto L2;
406                         }
407                         if (inout_ == 1)
408                         {   vec_clearbit(bi,s.Slvreg);
409                             goto Lagain;
410                         }
411                         goto Lcant;
412                     case -1:
413                         break;
414 
415                     default:
416                         assert(0);
417                 }
418             }
419         }
420         //printf("benefit2 = %d\n", benefit2);
421         benefit += benefit2;
422     }
423 
424     //printf("2weights: dfo.length = %d, globsym.length = %d\n", dfo.length, globsym.length);
425     debug if (benefit > s.Sweight + retsym_cnt + 1)
426         printf("s = '%s', benefit = %d, Sweight = %d, retsym_cnt = x%x\n",s.Sident.ptr,benefit,s.Sweight, retsym_cnt);
427 
428     /* This can happen upon overflow of s.Sweight, but only in extreme cases such as
429      * issues.dlang.org/show_bug.cgi?id=17098
430      * It essentially means "a whole lotta uses in nested loops", where
431      * it should go into a register anyway. So just saturate it at int.max
432      */
433     //assert(benefit <= s.Sweight + retsym_cnt + 1);
434     if (benefit > s.Sweight + retsym_cnt + 1)
435         benefit = int.max;      // saturate instead of overflow error
436     return benefit;
437 
438 Lcant:
439     return -1;                  // can't assign to reg
440 }
441 
442 /*********************************************
443  * Determine if block gets symbol loaded by predecessor epilog (1),
444  * or by prolog (0).
445  */
446 
447 int cgreg_gotoepilog(block *b,Symbol *s)
448 {
449     int bi = b.Bdfoidx;
450 
451     int inout_;
452     if (vec_testbit(bi,s.Slvreg))
453         inout_ = 1;
454     else
455         inout_ = -1;
456 
457     // Look at predecessors to see if we need to load in/out of register
458     int gotoepilog = 0;
459     int inoutp = 0;
460     foreach (bl; ListRange(b.Bpred))
461     {
462         block *bp = list_block(bl);
463         int bpi = bp.Bdfoidx;
464         if (!vec_testbit(bpi,s.Srange))
465             continue;
466         if (vec_testbit(bpi,s.Slvreg))
467         {
468             switch (inoutp)
469             {
470                 case 0:
471                     inoutp = 1;
472                     if (inout_ != 1)
473                     {   if (gotoepilog)
474                             goto Lcant;
475                     }
476                     break;
477                 case 1:
478                     break;
479                 case -1:
480                     if (gotoepilog == 0)
481                     {   gotoepilog = 1;
482                         goto Lret;
483                     }
484                     goto Lcant;
485 
486                 default:
487                     assert(0);
488             }
489         }
490         else
491         {
492             switch (inoutp)
493             {
494                 case 0:
495                     inoutp = -1;
496                     if (inout_ != -1)
497                     {   if (gotoepilog)
498                             goto Lcant;
499                     }
500                     break;
501                 case 1:
502                     if (gotoepilog == 0)
503                     {   gotoepilog = 1;
504                         goto Lret;
505                     }
506                     goto Lcant;
507                 case -1:
508                     break;
509 
510                 default:
511                     assert(0);
512             }
513         }
514     }
515 Lret:
516     return gotoepilog;
517 
518 Lcant:
519     assert(0);
520 //    return -1;                  // can't assign to reg
521 }
522 
523 /**********************************
524  * Determine block prolog code for `s` - it's either
525  * assignments to register, or storing register back in memory.
526  * Params:
527  *      b = block to generate prolog code for
528  *      s = symbol in the block that may need prolog code
529  *      cdbstore = append store code to this
530  *      cdbload = append load code to this
531  */
532 
533 @trusted
534 void cgreg_spillreg_prolog(block *b,Symbol *s,ref CodeBuilder cdbstore,ref CodeBuilder cdbload)
535 {
536     const int bi = b.Bdfoidx;
537 
538     //printf("cgreg_spillreg_prolog(block %d, s = '%s')\n",bi,s.Sident.ptr);
539 
540     // Load register from s
541     void load()
542     {
543         debug if (debugr)
544         {
545             printf("B%d: prolog moving '%s' into %s:%s\n",
546                     bi, s.Sident.ptr, regstring[s.Sregmsw],
547                     type_size(s.Stype) > REGSIZE ? regstring[s.Sreglsw] : "");
548         }
549         gen_spill_reg(cdbload, s, true);
550     }
551 
552     // Store register to s
553     void store()
554     {
555         debug if (debugr)
556         {
557             printf("B%d: prolog moving %s into '%s'\n",bi,regstring[s.Sreglsw],s.Sident.ptr);
558         }
559         gen_spill_reg(cdbstore, s, false);
560     }
561 
562     const live = vec_testbit(bi,s.Slvreg) != 0;   // if s is in a register in block b
563 
564     // If it's startblock, and it's a spilled parameter, we
565     // need to load it
566     if (live && s.Sflags & SFLspill && bi == 0 &&
567         (s.Sclass == SC.parameter || s.Sclass == SC.fastpar || s.Sclass == SC.shadowreg))
568     {
569         return load();
570     }
571 
572     if (cgreg_gotoepilog(b,s))
573         return;
574 
575     // Look at predecessors to see if we need to load in/out of register
576     foreach (bl; ListRange(b.Bpred))
577     {
578         const bpi = list_block(bl).Bdfoidx;
579 
580         if (!vec_testbit(bpi,s.Srange))
581             continue;
582         if (vec_testbit(bpi,s.Slvreg))
583         {
584             if (!live)
585             {
586                 return store();
587             }
588         }
589         else
590         {
591             if (live)
592             {
593                 return load();
594             }
595         }
596     }
597 }
598 
599 /**********************************
600  * Determine block epilog code - it's either
601  * assignments to register, or storing register back in memory.
602  * Params:
603  *      b = block to generate prolog code for
604  *      s = symbol in the block that may need epilog code
605  *      cdbstore = append store code to this
606  *      cdbload = append load code to this
607  */
608 
609 @trusted
610 void cgreg_spillreg_epilog(block *b,Symbol *s,ref CodeBuilder cdbstore, ref CodeBuilder cdbload)
611 {
612     const bi = b.Bdfoidx;
613     //printf("cgreg_spillreg_epilog(block %d, s = '%s')\n",bi,s.Sident.ptr);
614     //assert(b.BC == BCgoto);
615     if (!cgreg_gotoepilog(b.nthSucc(0), s))
616         return;
617 
618     const live = vec_testbit(bi,s.Slvreg) != 0;
619 
620     // Look at successors to see if we need to load in/out of register
621     foreach (bl; ListRange(b.Bsucc))
622     {
623         const bpi = list_block(bl).Bdfoidx;
624         if (!vec_testbit(bpi,s.Srange))
625             continue;
626         if (vec_testbit(bpi,s.Slvreg))
627         {
628             if (!live)
629             {
630                 debug if (debugr)
631                     printf("B%d: epilog moving '%s' into %s\n",bi,s.Sident.ptr,regstring[s.Sreglsw]);
632                 gen_spill_reg(cdbload, s, true);
633                 return;
634             }
635         }
636         else
637         {
638             if (live)
639             {
640                 debug if (debugr)
641                     printf("B%d: epilog moving %s into '%s'\n",bi,regstring[s.Sreglsw],s.Sident.ptr);
642                 gen_spill_reg(cdbstore, s, false);
643                 return;
644             }
645         }
646     }
647 }
648 
649 /***************************
650  * Map symbol s into registers [NOREG,reglsw] or [regmsw, reglsw].
651  */
652 
653 @trusted
654 private void cgreg_map(Symbol *s, reg_t regmsw, reg_t reglsw)
655 {
656     //assert(I64 || reglsw < 8);
657 
658     if (vec_disjoint(s.Srange,regrange[reglsw]) &&
659         (regmsw == NOREG || vec_disjoint(s.Srange,regrange[regmsw]))
660        )
661     {
662         s.Sfl = FLreg;
663         vec_copy(s.Slvreg,s.Srange);
664     }
665     else
666     {
667         s.Sflags |= SFLspill;
668 
669         // Already computed by cgreg_benefit()
670         //vec_sub(s.Slvreg,s.Srange,regrange[reglsw]);
671 
672         if (s.Sfl == FLreg)            // if reassigned
673         {
674             switch (s.Sclass)
675             {
676                 case SC.auto_:
677                 case SC.register:
678                     s.Sfl = FLauto;
679                     break;
680                 case SC.fastpar:
681                     s.Sfl = FLfast;
682                     break;
683                 case SC.bprel:
684                     s.Sfl = FLbprel;
685                     break;
686                 case SC.shadowreg:
687                 case SC.parameter:
688                     s.Sfl = FLpara;
689                     break;
690                 case SC.pseudo:
691                     s.Sfl = FLpseudo;
692                     break;
693                 case SC.stack:
694                     s.Sfl = FLstack;
695                     break;
696                 default:
697                     symbol_print(s);
698                     assert(0);
699             }
700         }
701     }
702     s.Sreglsw = cast(ubyte)reglsw;
703     s.Sregm = (1 << reglsw);
704     mfuncreg &= ~(1 << reglsw);
705     if (regmsw != NOREG)
706         vec_subass(s.Slvreg,regrange[regmsw]);
707     vec_orass(regrange[reglsw],s.Slvreg);
708 
709     if (regmsw == NOREG)
710     {
711         debug
712         {
713             if (debugr)
714             {
715                 printf("symbol '%s' %s in register %s\n    ",
716                     s.Sident.ptr,
717                     (s.Sflags & SFLspill) ? "spilled".ptr : "put".ptr,
718                     regstring[reglsw]);
719                 vec_println(s.Slvreg);
720             }
721         }
722     }
723     else
724     {
725         assert(regmsw < 8);
726         s.Sregmsw = cast(ubyte)regmsw;
727         s.Sregm |= 1 << regmsw;
728         mfuncreg &= ~(1 << regmsw);
729         vec_orass(regrange[regmsw],s.Slvreg);
730 
731         debug
732         {
733             if (debugr)
734                 printf("symbol '%s' %s in register pair %s\n",
735                     s.Sident.ptr,
736                     (s.Sflags & SFLspill) ? "spilled".ptr : "put".ptr,
737                     regm_str(s.Sregm));
738         }
739     }
740 }
741 
742 /********************************************
743  * The register variables in this mask can not be in registers.
744  * "Unregister" them.
745  */
746 
747 @trusted
748 void cgreg_unregister(regm_t conflict)
749 {
750     if (pass == BackendPass.final_)
751         pass = BackendPass.reg;                         // have to codegen at least one more time
752     for (int i = 0; i < globsym.length; i++)
753     {   Symbol *s = globsym[i];
754         if (s.Sfl == FLreg && s.Sregm & conflict)
755         {
756             s.Sflags |= GTunregister;
757         }
758     }
759 }
760 
761 /******************************************
762  * Do register assignments.
763  * Returns:
764  *      !=0     redo code generation
765  *      0       no more register assignments
766  */
767 
768 struct Reg              // data for trial register assignment
769 {
770     Symbol *sym;
771     int benefit;
772     reg_t reglsw;
773     reg_t regmsw;
774 }
775 
776 @trusted
777 int cgreg_assign(Symbol *retsym)
778 {
779     int flag = false;                   // assume no changes
780 
781     /* First do any 'unregistering' which might have happened in the last
782      * code gen pass.
783      */
784     for (size_t si = 0; si < globsym.length; si++)
785     {   Symbol *s = globsym[si];
786 
787         if (s.Sflags & GTunregister)
788         {
789             debug if (debugr)
790             {
791                 printf("symbol '%s' %s register %s\n    ",
792                     s.Sident.ptr,
793                     (s.Sflags & SFLspill) ? "unspilled".ptr : "unregistered".ptr,
794                     regstring[s.Sreglsw]);
795                 vec_println(s.Slvreg);
796             }
797 
798             flag = true;
799             s.Sflags &= ~(GTregcand | GTunregister | SFLspill);
800             if (s.Sfl == FLreg)
801             {
802                 switch (s.Sclass)
803                 {
804                     case SC.auto_:
805                     case SC.register:
806                         s.Sfl = FLauto;
807                         break;
808                     case SC.fastpar:
809                         s.Sfl = FLfast;
810                         break;
811                     case SC.bprel:
812                         s.Sfl = FLbprel;
813                         break;
814                     case SC.shadowreg:
815                     case SC.parameter:
816                         s.Sfl = FLpara;
817                         break;
818                     case SC.pseudo:
819                         s.Sfl = FLpseudo;
820                         break;
821                     case SC.stack:
822                         s.Sfl = FLstack;
823                         break;
824                     default:
825                         debug symbol_print(s);
826                         assert(0);
827                 }
828             }
829         }
830     }
831 
832     vec_t v = vec_calloc(dfo.length);
833 
834     reg_t dst_integer_reg;
835     reg_t dst_float_reg;
836     cgreg_dst_regs(&dst_integer_reg, &dst_float_reg);
837     regm_t dst_integer_mask = 1 << dst_integer_reg;
838     regm_t dst_float_mask = 1 << dst_float_reg;
839 
840     /* Find all the parameters passed as named registers
841      */
842     regm_t regparams = 0;
843     for (size_t si = 0; si < globsym.length; si++)
844     {   Symbol *s = globsym[si];
845         if (s.Sclass == SC.fastpar || s.Sclass == SC.shadowreg)
846             regparams |= s.Spregm();
847     }
848 
849     /* Disallow parameters being put in registers that are used by the 64 bit
850      * prolog generated by prolog_getvarargs()
851      */
852     const regm_t variadicPrologRegs = (I64 && variadic(funcsym_p.Stype))
853         ? (mAX | mR11) |   // these are used by the prolog code
854           ((mDI | mSI | mDX | mCX | mR8 | mR9 | XMMREGS) & ~regparams) // unnamed register arguments
855         : 0;
856 
857     // Find symbol t, which is the most 'deserving' symbol that should be
858     // placed into a register.
859     Reg t;
860     t.sym = null;
861     t.benefit = 0;
862     for (size_t si = 0; si < globsym.length; si++)
863     {   Symbol *s = globsym[si];
864 
865         Reg u;
866         u.sym = s;
867         if (!(s.Sflags & GTregcand) ||
868             s.Sflags & SFLspill ||
869             // Keep trying to reassign retsym into destination register
870             (s.Sfl == FLreg && !(s == retsym && s.Sregm != dst_integer_mask && s.Sregm != dst_float_mask))
871            )
872         {
873             debug if (debugr)
874             {
875                 if (s.Sfl == FLreg)
876                 {
877                     printf("symbol '%s' is in reg %s\n",s.Sident.ptr,regm_str(s.Sregm));
878                 }
879                 else if (s.Sflags & SFLspill)
880                 {
881                     printf("symbol '%s' spilled in reg %s\n",s.Sident.ptr,regm_str(s.Sregm));
882                 }
883                 else if (!(s.Sflags & GTregcand))
884                 {
885                     printf("symbol '%s' is not a reg candidate\n",s.Sident.ptr);
886                 }
887                 else
888                     printf("symbol '%s' is not a candidate\n",s.Sident.ptr);
889             }
890 
891             continue;
892         }
893 
894         tym_t ty = s.ty();
895 
896         debug
897         {
898             if (debugr)
899             {   printf("symbol '%3s', ty x%x weight x%x %s\n   ",
900                 s.Sident.ptr,ty,s.Sweight,
901                 regm_str(s.Spregm()));
902                 vec_println(s.Srange);
903             }
904         }
905 
906         // Select sequence of registers to try to map s onto
907         const(reg_t)* pseq;                     // sequence to try for LSW
908         const(reg_t)* pseqmsw = null;           // sequence to try for MSW, null if none
909         cgreg_set_priorities(ty, &pseq, &pseqmsw);
910 
911         u.benefit = 0;
912         for (int i = 0; pseq[i] != NOREG; i++)
913         {
914             reg_t reg = pseq[i];
915 
916             // Symbols used as return values should only be mapped into return value registers
917             if (s == retsym && !(reg == dst_integer_reg || reg == dst_float_reg))
918                 continue;
919 
920             // If BP isn't available, can't assign to it
921             if (reg == BP && !(allregs & mBP))
922                 continue;
923 
924 static if (0 && TARGET_LINUX)
925 {
926             // Need EBX for static pointer
927             if (reg == BX && !(allregs & mBX))
928                 continue;
929 }
930             /* Don't enregister any parameters to variadicPrologRegs
931              */
932             if (variadicPrologRegs & (1 << reg))
933             {
934                 if (s.Sclass == SC.parameter || s.Sclass == SC.fastpar)
935                     continue;
936                 /* Win64 doesn't use the Posix variadic scheme, so we can skip SCshadowreg
937                  */
938             }
939 
940             /* Don't assign register parameter to another register parameter
941              */
942             if ((s.Sclass == SC.fastpar || s.Sclass == SC.shadowreg) &&
943                 (1 << reg) & regparams &&
944                 reg != s.Spreg)
945                 continue;
946 
947             if (s.Sflags & GTbyte &&
948                 !((1 << reg) & BYTEREGS))
949                     continue;
950 
951             int benefit = cgreg_benefit(s,reg,retsym);
952 
953             debug if (debugr)
954             {   printf(" %s",regstring[reg]);
955                 vec_print(regrange[reg]);
956                 printf(" %d\n",benefit);
957             }
958 
959             if (benefit > u.benefit)
960             {   // successful assigning of lsw
961                 reg_t regmsw = NOREG;
962 
963                 // Now assign MSW
964                 if (pseqmsw)
965                 {
966                     for (uint regj = 0; 1; regj++)
967                     {
968                         regmsw = pseqmsw[regj];
969                         if (regmsw == NOREG)
970                             goto Ltried;                // tried and failed to assign MSW
971                         if (regmsw == reg)              // can't assign msw and lsw to same reg
972                             continue;
973                         if ((s.Sclass == SC.fastpar || s.Sclass == SC.shadowreg) &&
974                             (1 << regmsw) & regparams &&
975                             regmsw != s.Spreg2)
976                             continue;
977 
978                         debug if (debugr)
979                         {   printf(".%s",regstring[regmsw]);
980                             vec_println(regrange[regmsw]);
981                         }
982 
983                         if (vec_disjoint(s.Slvreg,regrange[regmsw]))
984                             break;
985                     }
986                 }
987                 vec_copy(v,s.Slvreg);
988                 u.benefit = benefit;
989                 u.reglsw = reg;
990                 u.regmsw = regmsw;
991             }
992 Ltried:
993         }
994 
995         if (u.benefit > t.benefit)
996         {   t = u;
997             vec_copy(t.sym.Slvreg,v);
998         }
999     }
1000 
1001     if (t.sym && t.benefit > 0)
1002     {
1003         cgreg_map(t.sym,t.regmsw,t.reglsw);
1004         flag = true;
1005     }
1006 
1007     /* See if any scratch registers have become available that we can use.
1008      * Scratch registers are cheaper, as they don't need save/restore.
1009      * All floating point registers are scratch registers, so no need
1010      * to do this for them.
1011      */
1012     if ((I32 || I64) &&                       // not worth the bother for 16 bit code
1013         !flag &&                              // if haven't already assigned registers in this pass
1014         (mfuncreg & ~fregsaved) & ALLREGS &&  // if unused non-floating scratch registers
1015         !(funcsym_p.Sflags & SFLexit))       // don't need save/restore if function never returns
1016     {
1017         for (size_t si = 0; si < globsym.length; si++)
1018         {   Symbol *s = globsym[si];
1019 
1020             if (s.Sfl == FLreg &&                // if assigned to register
1021                 (1 << s.Sreglsw) & fregsaved &&   // and that register is not scratch
1022                 type_size(s.Stype) <= REGSIZE && // don't bother with register pairs
1023                 !tyfloating(s.ty()))             // don't assign floating regs to non-floating regs
1024             {
1025                 s.Sreglsw = findreg((mfuncreg & ~fregsaved) & ALLREGS);
1026                 s.Sregm = 1 << s.Sreglsw;
1027                 flag = true;
1028 
1029                 debug if (debugr)
1030                     printf("re-assigned '%s' to %s\n",s.Sident.ptr,regstring[s.Sreglsw]);
1031 
1032                 break;
1033             }
1034         }
1035     }
1036     vec_free(v);
1037 
1038     return flag;
1039 }