"Fossies" - the Fresh Open Source Software Archive

Member "dmd2/src/dmd/dmd/backend/gsroa.d" (20 Nov 2020, 14586 Bytes) of package /linux/misc/dmd.2.094.2.linux.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) D source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 /**
    2  * Compiler implementation of the
    3  * $(LINK2 http://www.dlang.org, D programming language).
    4  *
    5  * Copyright:   Copyright (C) 2016-2020 by The D Language Foundation, All Rights Reserved
    6  * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
    7  * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
    8  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/backend/gsroa.c, backend/gsroa.d)
    9  */
   10 
   11 module dmd.backend.gsroa;
   12 
   13 version (SCPP)
   14     version = COMPILE;
   15 version (MARS)
   16     version = COMPILE;
   17 
   18 version (COMPILE)
   19 {
   20 
   21 import core.stdc.stdio;
   22 import core.stdc.stdlib;
   23 import core.stdc.string;
   24 import core.stdc.time;
   25 
   26 import dmd.backend.cc;
   27 import dmd.backend.cdef;
   28 import dmd.backend.code_x86;
   29 import dmd.backend.oper;
   30 import dmd.backend.global;
   31 import dmd.backend.el;
   32 import dmd.backend.ty;
   33 import dmd.backend.type;
   34 
   35 import dmd.backend.dlist;
   36 import dmd.backend.dvec;
   37 
   38 extern (C++):
   39 
   40 nothrow:
   41 
   42 int REGSIZE();
   43 
   44 alias SLICESIZE = REGSIZE;  // slices are all register-sized
   45 enum MAXSLICES = 2;         // max # of pieces we can slice an aggregate into
   46 
   47 /* This 'slices' a two register wide aggregate into two separate register-sized variables,
   48  * enabling much better enregistering.
   49  * SROA (Scalar Replacement Of Aggregates) is the common term for this.
   50  */
   51 
   52 struct SymInfo
   53 {
   54     bool canSlice;
   55     bool accessSlice;   // if Symbol was accessed as a slice
   56     tym_t[MAXSLICES] ty; // type of each slice
   57     SYMIDX si0;          // index of first slice, the rest follow sequentially
   58 }
   59 
   60 /********************************
   61  * Gather information about slice-able variables by scanning e.
   62  * Params:
   63  *      symtab = symbol table
   64  *      e = expression to scan
   65  *      sia = where to put gathered information
   66  */
   67 extern (D) private void sliceStructs_Gather(const symtab_t* symtab, SymInfo[] sia, const(elem)* e)
   68 {
   69     while (1)
   70     {
   71         switch (e.Eoper)
   72         {
   73             case OPvar:
   74             {
   75                 const si = e.EV.Vsym.Ssymnum;
   76                 if (si >= 0 && sia[si].canSlice)
   77                 {
   78                     assert(si < symtab.top);
   79                     const n = nthSlice(e);
   80                     const sz = getSize(e);
   81                     if (sz == 2 * SLICESIZE && !tyfv(e.Ety) &&
   82                         tybasic(e.Ety) != TYldouble && tybasic(e.Ety) != TYildouble)
   83                     {
   84                         // Rewritten as OPpair later
   85                     }
   86                     else if (n != NOTSLICE)
   87                     {
   88                         if (!sia[si].accessSlice)
   89                         {
   90                             /* [1] default as pointer type
   91                              */
   92                             foreach (ref ty; sia[si].ty)
   93                                 ty = TYnptr;
   94 
   95                             const s = e.EV.Vsym;
   96                             const t = s.Stype;
   97                             if (tybasic(t.Tty) == TYstruct)
   98                             {
   99                                 if (const targ1 = t.Ttag.Sstruct.Sarg1type)
  100                                     if (const targ2 = t.Ttag.Sstruct.Sarg2type)
  101                                     {
  102                                         sia[si].ty[0] = targ1.Tty;
  103                                         sia[si].ty[1] = targ2.Tty;
  104                                     }
  105                             }
  106                         }
  107                         sia[si].accessSlice = true;
  108                         if (sz == SLICESIZE)
  109                             sia[si].ty[n] = tybasic(e.Ety);
  110                     }
  111                     else
  112                     {
  113                         sia[si].canSlice = false;
  114                     }
  115                 }
  116                 return;
  117             }
  118 
  119             default:
  120                 if (OTassign(e.Eoper))
  121                 {
  122                     if (OTbinary(e.Eoper))
  123                         sliceStructs_Gather(symtab, sia, e.EV.E2);
  124 
  125                     // Assignment to a whole var will disallow SROA
  126                     if (e.EV.E1.Eoper == OPvar)
  127                     {
  128                         const e1 = e.EV.E1;
  129                         const si = e1.EV.Vsym.Ssymnum;
  130                         if (si >= 0 && sia[si].canSlice)
  131                         {
  132                             assert(si < symtab.top);
  133                             if (nthSlice(e1) == NOTSLICE)
  134                             {
  135                                 sia[si].canSlice = false;
  136                             }
  137                             // Disable SROA on OSX32 (because XMM registers?)
  138                             // https://issues.dlang.org/show_bug.cgi?id=15206
  139                             // https://github.com/dlang/dmd/pull/8034
  140                             else if (!(config.exe & EX_OSX))
  141                             {
  142                                 sliceStructs_Gather(symtab, sia, e.EV.E1);
  143                             }
  144                         }
  145                         return;
  146                     }
  147                     e = e.EV.E1;
  148                     break;
  149                 }
  150                 if (OTunary(e.Eoper))
  151                 {
  152                     e = e.EV.E1;
  153                     break;
  154                 }
  155                 if (OTbinary(e.Eoper))
  156                 {
  157                     sliceStructs_Gather(symtab, sia, e.EV.E2);
  158                     e = e.EV.E1;
  159                     break;
  160                 }
  161                 return;
  162         }
  163     }
  164 }
  165 
  166 /***********************************
  167  * Rewrite expression tree e based on info in sia[].
  168  * Params:
  169  *      symtab = symbol table
  170  *      sia = slicing info
  171  *      e = expression tree to rewrite in place
  172  */
  173 extern (D) private void sliceStructs_Replace(symtab_t* symtab, const SymInfo[] sia, elem *e)
  174 {
  175     while (1)
  176     {
  177         switch (e.Eoper)
  178         {
  179             case OPvar:
  180             {
  181                 Symbol *s = e.EV.Vsym;
  182                 const si = s.Ssymnum;
  183                 //printf("e: %d %d\n", si, sia[si].canSlice);
  184                 //elem_print(e);
  185                 if (si >= 0 && sia[si].canSlice)
  186                 {
  187                     const n = nthSlice(e);
  188                     if (getSize(e) == 2 * SLICESIZE)
  189                     {
  190                         // Rewrite e as (si0 OPpair si0+1)
  191                         elem *e1 = el_calloc();
  192                         el_copy(e1, e);
  193                         e1.Ety = sia[si].ty[0];
  194 
  195                         elem *e2 = el_calloc();
  196                         el_copy(e2, e);
  197                         Symbol *s1 = symtab.tab[sia[si].si0 + 1]; // +1 for second slice
  198                         e2.Ety = sia[si].ty[1];
  199                         e2.EV.Vsym = s1;
  200                         e2.EV.Voffset = 0;
  201 
  202                         e.Eoper = OPpair;
  203                         e.EV.E1 = e1;
  204                         e.EV.E2 = e2;
  205 
  206                         if (tycomplex(e.Ety))
  207                         {
  208                             /* Ensure complex OPpair operands are floating point types
  209                              * because [1] may have defaulted them to a pointer type.
  210                              * https://issues.dlang.org/show_bug.cgi?id=18936
  211                              */
  212                             tym_t tyop;
  213                             switch (tybasic(e.Ety))
  214                             {
  215                                 case TYcfloat:   tyop = TYfloat;   break;
  216                                 case TYcdouble:  tyop = TYdouble;  break;
  217                                 case TYcldouble: tyop = TYldouble; break;
  218                                 default:
  219                                     assert(0);
  220                             }
  221                             if (!tyfloating(e1.Ety))
  222                                 e1.Ety = tyop;
  223                             if (!tyfloating(e2.Ety))
  224                                 e2.Ety = tyop;
  225                         }
  226                     }
  227                     else if (n == 0)  // the first slice of the symbol is the same as the original
  228                     {
  229                     }
  230                     else // the nth slice
  231                     {
  232                         e.EV.Vsym = symtab.tab[sia[si].si0 + n];
  233                         e.EV.Voffset -= n * SLICESIZE;
  234                         //printf("replaced with:\n");
  235                         //elem_print(e);
  236                     }
  237                 }
  238                 return;
  239             }
  240 
  241             default:
  242                 if (OTunary(e.Eoper))
  243                 {
  244                     e = e.EV.E1;
  245                     break;
  246                 }
  247                 if (OTbinary(e.Eoper))
  248                 {
  249                     sliceStructs_Replace(symtab, sia, e.EV.E2);
  250                     e = e.EV.E1;
  251                     break;
  252                 }
  253                 return;
  254         }
  255     }
  256 }
  257 
  258 void sliceStructs(symtab_t* symtab, block* startblock)
  259 {
  260     if (debugc) printf("sliceStructs() %s\n", funcsym_p.Sident.ptr);
  261     const sia_length = symtab.top;
  262     /* 3 is because it is used for two arrays, sia[] and sia2[].
  263      * sia2[] can grow to twice the size of sia[], as symbols can get split into two.
  264      */
  265     debug
  266         enum tmp_length = 3;
  267     else
  268         enum tmp_length = 6;
  269     SymInfo[tmp_length] tmp = void;
  270     SymInfo* sip;
  271     if (sia_length <= tmp.length / 3)
  272         sip = tmp.ptr;
  273     else
  274     {
  275         sip = cast(SymInfo *)malloc(3 * sia_length * SymInfo.sizeof);
  276         assert(sip);
  277     }
  278     SymInfo[] sia = sip[0 .. sia_length];
  279     SymInfo[] sia2 = sip[sia_length .. sia_length * 3];
  280 
  281     if (0) foreach (si; 0 .. symtab.top)
  282     {
  283         Symbol *s = symtab.tab[si];
  284         printf("[%d]: %p %d %s\n", si, s, cast(int)type_size(s.Stype), s.Sident.ptr);
  285     }
  286 
  287     bool anySlice = false;
  288     foreach (si; 0 .. symtab.top)
  289     {
  290         Symbol *s = symtab.tab[si];
  291         //printf("slice1: %s\n", s.Sident.ptr);
  292 
  293         if (!(s.Sflags & SFLunambig))   // if somebody took the address of s
  294         {
  295             sia[si].canSlice = false;
  296             continue;
  297         }
  298 
  299         const sz = type_size(s.Stype);
  300         if (sz != 2 * SLICESIZE ||
  301             tyfv(s.Stype.Tty) || tybasic(s.Stype.Tty) == TYhptr)    // because there is no TYseg
  302         {
  303             sia[si].canSlice = false;
  304             continue;
  305         }
  306 
  307         switch (s.Sclass)
  308         {
  309             case SCfastpar:
  310             case SCregister:
  311             case SCauto:
  312             case SCshadowreg:
  313             case SCparameter:
  314                 anySlice = true;
  315                 sia[si].canSlice = true;
  316                 sia[si].accessSlice = false;
  317                 // We can't slice whole XMM registers
  318                 if (tyxmmreg(s.Stype.Tty) &&
  319                     isXMMreg(s.Spreg) && s.Spreg2 == NOREG)
  320                 {
  321                     sia[si].canSlice = false;
  322                 }
  323                 break;
  324 
  325             case SCstack:
  326             case SCpseudo:
  327             case SCstatic:
  328             case SCbprel:
  329                 sia[si].canSlice = false;
  330                 break;
  331 
  332             default:
  333                 symbol_print(s);
  334                 assert(0);
  335         }
  336     }
  337 
  338     if (!anySlice)
  339         goto Ldone;
  340 
  341     foreach (b; BlockRange(startblock))
  342     {
  343         if (b.BC == BCasm)
  344             goto Ldone;
  345         if (b.Belem)
  346             sliceStructs_Gather(symtab, sia, b.Belem);
  347     }
  348 
  349     {   // scope needed because of goto skipping declarations
  350         bool any = false;
  351         int n = 0;              // the number of symbols added
  352         foreach (si; 0 .. sia_length)
  353         {
  354             sia2[si + n].canSlice = false;
  355             if (sia[si].canSlice)
  356             {
  357                 // If never did access it as a slice, don't slice
  358                 if (!sia[si].accessSlice)
  359                 {
  360                     sia[si].canSlice = false;
  361                     continue;
  362                 }
  363 
  364                 /* Split slice-able symbol sold into two symbols,
  365                  * (sold,snew) in adjacent slots in the symbol table.
  366                  */
  367                 Symbol *sold = symtab.tab[si + n];
  368 
  369                 const idlen = 2 + strlen(sold.Sident.ptr) + 2;
  370                 char *id = cast(char *)malloc(idlen + 1);
  371                 assert(id);
  372                 sprintf(id, "__%s_%d", sold.Sident.ptr, SLICESIZE);
  373                 if (debugc) printf("creating slice symbol %s\n", id);
  374                 Symbol *snew = symbol_calloc(id, cast(uint)idlen);
  375                 free(id);
  376                 snew.Sclass = sold.Sclass;
  377                 snew.Sfl = sold.Sfl;
  378                 snew.Sflags = sold.Sflags;
  379                 if (snew.Sclass == SCfastpar || snew.Sclass == SCshadowreg)
  380                 {
  381                     snew.Spreg = sold.Spreg2;
  382                     snew.Spreg2 = NOREG;
  383                     sold.Spreg2 = NOREG;
  384                 }
  385                 type_free(sold.Stype);
  386                 sold.Stype = type_fake(sia[si].ty[0]);
  387                 sold.Stype.Tcount++;
  388                 snew.Stype = type_fake(sia[si].ty[1]);
  389                 snew.Stype.Tcount++;
  390 
  391                 // insert snew into symtab.tab[si + n + 1]
  392                 symbol_insert(symtab, snew, si + n + 1);
  393 
  394                 sia2[si + n].canSlice = true;
  395                 sia2[si + n].si0 = si + n;
  396                 sia2[si + n].ty[] = sia[si].ty[];
  397                 ++n;
  398                 any = true;
  399             }
  400         }
  401         if (!any)
  402             goto Ldone;
  403     }
  404 
  405     foreach (si; 0 .. symtab.top)
  406     {
  407         Symbol *s = symtab.tab[si];
  408         assert(s.Ssymnum == si);
  409     }
  410 
  411     foreach (b; BlockRange(startblock))
  412     {
  413         if (b.Belem)
  414             sliceStructs_Replace(symtab, sia2, b.Belem);
  415     }
  416 
  417 Ldone:
  418     if (sip != tmp.ptr)
  419         free(sip);
  420 }
  421 
  422 
  423 /*************************************
  424  * Determine if `e` is a slice.
  425  * Params:
  426  *      e = elem that may be a slice
  427  * Returns:
  428  *      slice number if it is, NOTSLICE if not
  429  */
  430 enum NOTSLICE = -1;
  431 int nthSlice(const(elem)* e)
  432 {
  433     const sz = tysize(e.Ety); // not getSize(e) because type_fake(TYstruct) doesn't work
  434     if (sz == -1)
  435         return NOTSLICE;
  436     const sliceSize = SLICESIZE;
  437 
  438     /* See if e fits in a slice
  439      */
  440     const lwr = e.EV.Voffset;
  441     const upr = lwr + sz;
  442     if (0 <= lwr && upr <= sliceSize)
  443         return 0;
  444     if (sliceSize < lwr && upr <= sliceSize * 2)
  445         return 1;
  446 
  447     return NOTSLICE;
  448 }
  449 
  450 /******************************************
  451  * Get size of an elem e.
  452  */
  453 private int getSize(const(elem)* e)
  454 {
  455     int sz = tysize(e.Ety);
  456     if (sz == -1 && e.ET && (tybasic(e.Ety) == TYstruct || tybasic(e.Ety) == TYarray))
  457         sz = cast(int)type_size(e.ET);
  458     return sz;
  459 }
  460 
  461 }