Studying note of GCC-3.4.6 source (47)

4.2.7. Prepare for reload pass

4.2.7.1.    Overview

After init_loop returns, in backend_init, next calls init_reload which prepare for reloading pass.

What does reloading pass for?

Reloading pass renumbers pseudo registers with the hardware registers numbers they were allocated. Pseudo registers that did not get hard registers are replaced with stack slots. Then it finds instructions that are invalid because a value has failed to end up in a register, or has ended up in a register of the wrong kind. It fixes up these instructions by reloading the problematical values temporarily into registers. Additional instructions are generated to do the copying.

The reload pass also optionally eliminates the frame pointer and inserts instructions to save and restore call-clobbered registers around calls.

4.2.7.2.    Initialization

T To make reload pass possible, init_reload now needs collect some informations. These informations include level of indirect addressing via register, level of indirect addressing via symbol, and if addressing supported in form of (frame register + GPR).

 

431    void

432    init_reload (void)                                                                                     in reload1.c

433    {

434      int i;

435   

436      /* Often (MEM (REG n)) is still valid even if (REG n) is put on the stack.

437        Set spill_indirect_levels to the number of levels such addressing is

438        permitted, zero if it is not permitted at all.  */

439   

440      rtx tem

441        = gen_rtx_MEM (Pmode,

442                   gen_rtx_PLUS (Pmode,

443                              gen_rtx_REG (Pmode,

444                                           LAST_VIRTUAL_REGISTER + 1),

445                                       GEN_INT (4)));

 

The function first creates a rtx object representing address in form of memory+register to evaluate the level of indirect addressing via register. gen_rtx_PLUS is defined in genrtl.h. It invokes gen_rtx_fmt_ee to create the rtx object. This function will create a rtx object with two children, both are rtx expressions.

Above, line 440 after executing, following rtx object is created.

Studying note of GCC-3.4.6 source (47)_第1张图片

figure 20: indirect addressing via register

 

init_reload (continue)

 

446      spill_indirect_levels = 0;

447   

448      while (memory_address_p (QImode, tem))

449      {

450        spill_indirect_levels++;

451        tem = gen_rtx_MEM (Pmode, tem);

452      }

 

spill_indirect_levels indicates the level of indirect addressing. Here the indirect addressing just means, for example, if spill_indirect_levels is 1, fetching the content of memory pointed by register n ( we marks as (mem (reg n)) ) is still valid even if register n is spilled out (that means memory can be accessed directly without aid of register). If spill_indirect_level is 2, (mem (mem (reg n))) is still valid even if register n is spilled out.

With spill_indirect_levels, we can avoid unnecessary restore register during reload pass.

For the x86 machine here, memory_address_p returns false, leaves spill_indirect_levels as 0. Next init_reload evaluates the level of indirect addressing via symbol.

 

init_reload (continue)

 

454      /* See if indirect addressing is valid for (MEM (SYMBOL_REF ...)).  */

455   

456      tem = gen_rtx_MEM (Pmode, gen_rtx_SYMBOL_REF (Pmode, "foo"));

457      indirect_symref_ok = memory_address_p (QImode, tem);

 

gen_rtx_SYMBOL_REF also generated ones defined in genrtl.h. It invokes gen_rtx_fmt_s00. Again its name reveals that the rtx object created has 3 children, the first is string, the rest are not used. The rtx object created is shown in following.

 

figure 17: indirect addressing via symbol

Also indirect_symbolref_ok is 0 for x86 machine. This variable if nonzero, indicates indirect addressing is supported when the innermost MEM is of the form (MEM (SYMBOL_REF sym)) (memory pointed by the content of memory referred by symbol). So how about addressing in form of (frame register + GPR)?

 

init_reload (continue)

 

459     /* See if reg+reg is a valid (and offsettable) address.  */

460   

461      for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)

462      {

463        tem = gen_rtx_PLUS (Pmode,

464                         gen_rtx_REG (Pmode, HARD_FRAME_POINTER_REGNUM),

465                         gen_rtx_REG (Pmode, i));

466   

467        /* This way, we make sure that reg+reg is an offsettable address.  */

468        tem = plus_constant (tem, 4);

469   

470        if (memory_address_p (QImode, tem))

471        {

472          double_reg_address_ok = 1;

473          break;

474        }

475      }

 

double_reg_adress_ok indicates if addressing can be supported by (reg_frame_pointer+GPR) +constant. The rtx object created at line 463 is as following, it is not the final one.

Studying note of GCC-3.4.6 source (47)_第2张图片

figure 18: addressing in form of (frame register + GPR)

 

As comment says, at line 468, plus_constant adds an offset for the rtx object created above.

 

1432 #define plus_constant(X, C) plus_constant_wide ((X), (HOST_WIDE_INT) (C))    in rtl.h

 

78      rtx

79      plus_constant_wide (rtx x, HOST_WIDE_INT c)                                        in explow.c

80      {

81        RTX_CODE code;

82        rtx y;

83        enum machine_mode mode;

84        rtx tem;

85        int all_constant = 0;

86     

87        if (c == 0)

88          return x;

89     

90      restart:

91     

92        code = GET_CODE (x);

93        mode = GET_MODE (x);

94        y = x;

95     

96        switch (code)

97        {

98          case CONST_INT:

99            return GEN_INT (INTVAL (x) + c);

100   

101        case CONST_DOUBLE:

102        {

     

113         }

114    

115         case MEM:

  

129          break;

130   

131        case CONST:

132          /* If adding to something entirely constant, set a flag

133            so that we can add a CONST around the result.  */

134          x = XEXP (x, 0);

135          all_constant = 1;

136          goto restart;

137   

138        case SYMBOL_REF:

139        case LABEL_REF:

140          all_constant = 1;

141          break;

142   

143        case PLUS:

144          /* The interesting case is adding the integer to a sum.

145            Look for constant term in the sum and combine

146            with C. For an integer constant term, we make a combined

147            integer. For a constant term that is not an explicit integer,

148            we cannot really combine, but group them together anyway.

149   

150            Restart or use a recursive call in case the remaining operand is

151            something that we handle specially, such as a SYMBOL_REF.

152   

153            We may not immediately return from the recursive call here, lest

154            all_constant gets lost.  */

155   

156          if (GET_CODE (XEXP (x, 1)) == CONST_INT)

157          {

158            c += INTVAL (XEXP (x, 1));

159   

160            if (GET_MODE (x) != VOIDmode)

161              c = trunc_int_for_mode (c, GET_MODE (x));

162   

163            x = XEXP (x, 0);

164            goto restart;

165          }

166          else if (CONSTANT_P (XEXP (x, 1)))

167          {

168            x = gen_rtx_PLUS (mode, XEXP (x, 0), plus_constant (XEXP (x, 1), c));

169            c = 0;

170          }

171          else if (find_constant_term_loc (&y))

172          {

173            /* We need to be careful since X may be shared and we can't

174              modify it in place.  */

175            rtx copy = copy_rtx (x);

176            rtx *const_loc = find_constant_term_loc (&copy);

177   

178            *const_loc = plus_constant (*const_loc, c);

179            x = copy;

180            c = 0;

181          }

182          break;

183   

184        default:

185          break;

186      }

187   

188      if (c != 0)

189        x = gen_rtx_PLUS (mode, x, GEN_INT (c));

190   

191      if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF)

192        return x;

193      else if (all_constant)

194        return gen_rtx_CONST (mode, x);

195      else

196        return x;

197    }

 

At line 166, CONSTANT_P checks if the rtx object represents a constant or not.

 

293    #define CONSTANT_P(X)   /                                                                        in rtl.h

294      (GET_CODE (X) == LABEL_REF || GET_CODE (X) == SYMBOL_REF              /

295       || GET_CODE (X) == CONST_INT || GET_CODE (X) == CONST_DOUBLE              /

296       || GET_CODE (X) == CONST || GET_CODE (X) == HIGH                  /

297       || GET_CODE (X) == CONST_VECTOR                                   /

298       || GET_CODE (X) == CONSTANT_P_RTX)

 

For our rtx object, case statement at line 143 will be executed, and then statement at line 171, function find_constant_term_loc.

 

1818 rtx *

1819 find_constant_term_loc (rtx *p)                                                                  in recog.c

1820 {

1821   rtx *tem;

1822   enum rtx_code code = GET_CODE (*p);

1823

1824   /* If *P IS such a constant term, P is its location.  */

1825

1826   if (code == CONST_INT || code == SYMBOL_REF || code == LABEL_REF

1827       || code == CONST)

1828     return p;

1829

1830   /* Otherwise, if not a sum, it has no constant term.  */

1831

1832   if (GET_CODE (*p) != PLUS)

1833     return 0;

1834

1835   /* If one of the summands is constant, return its location.  */

1836

1837   if (XEXP (*p, 0) && CONSTANT_P (XEXP (*p, 0))

1838       && XEXP (*p, 1) && CONSTANT_P (XEXP (*p, 1)))

1839     return p;

1840

1841   /* Otherwise, check each summand for containing a constant term.  */

1842

1843   if (XEXP (*p, 0) != 0)

1844   {

1845     tem = find_constant_term_loc (&XEXP (*p, 0));

1846     if (tem != 0)

1847       return tem;

1848   }

1849

1850   if (XEXP (*p, 1) != 0)

1851   {

1852     tem = find_constant_term_loc (&XEXP (*p, 1));

1853     if (tem != 0)

1854       return tem;

1855   }

1856

1857   return 0;

1858 }

 

Note that first time this function invoked, the rtx object passed in is the one created in init_reload, at line 463. For the object, in find_constant_term_loc, line 1843 will be executed, which will invoke find_constant_term_loc again for its first child. It will return 0 as result. Then line 1850 will be executed in turn, the invoked find_constant_term_loc returns 0 also. In the end the original invoked find_constant_term_loc returns 0 in plus_constant_wide at line 171.

In plus_constant_wide, at line 189, a new rtx object created as following. Note that the expression takes form of infix notation. It makes operator priority unnecessary.

figure 23: addressing in form of (frame register + GPR) final

Then in init_reload, line 470, memory_address_p invoked again. From above, we know for x86 machine, legitimate_address_p will be the place for the job.

 

6033 int

6034 legitimate_address_p (enum machine_mode mode, rtx addr, int strict)                in i386.c

6035 {

6036   struct ix86_address parts;

6037   rtx base, index, disp;

6038   HOST_WIDE_INT scale;

6039   const char *reason = NULL;

6040   rtx reason_rtx = NULL_RTX;

6041

6042   if (TARGET_DEBUG_ADDR)

6043   {

6044     fprintf (stderr,

6045        "/n======/nGO_IF_LEGITIMATE_ADDRESS, mode = %s, strict = %d/n",

6046        GET_MODE_NAME (mode), strict);

6047     debug_rtx (addr);

6048   }

6049

6050   if (ix86_decompose_address (addr, &parts) <= 0)

6051   {

6052     reason = "decomposition failed";

6053     goto report_error;

6054   }

 

Again ix86_decompose_address will fill out ix86_address for the addressing expression.

 

5566 static int

5567 ix86_decompose_address (rtx addr, struct ix86_address *out)                             in i386.c

5568 {

5569   rtx base = NULL_RTX;

5570   rtx index = NULL_RTX;

5571   rtx disp = NULL_RTX;

5572   HOST_WIDE_INT scale = 1;

5573   rtx scale_rtx = NULL_RTX;

5574   int retval = 1;

5575   enum ix86_address_seg seg = SEG_DEFAULT;

5576

5577   if (GET_CODE (addr) == REG || GET_CODE (addr) == SUBREG)

5578     base = addr;

5579   else if (GET_CODE (addr) == PLUS)

5580   {

5581     rtx addends[4], op;

5582     int n = 0, i;

5583

5584     op = addr;

5585     do

5586     {

5587       if (n >= 4)

5588         return 0;

5589        addends[n++] = XEXP (op, 1);

5590        op = XEXP (op, 0);

5591     }

5592     while (GET_CODE (op) == PLUS);

5593     if (n >= 4)

5594       return 0;

5595     addends[n] = op;

5596

5597     for (i = n; i >= 0; --i)

5598     {

5599       op = addends[i];

5600       switch (GET_CODE (op))

5601       {

5602         case MULT:

         

5607          break;

5608

5609         case UNSPEC:

             

5616          break;

5617

5618         case REG:

5619         case SUBREG:

5620           if (!base)

5621             base = op;

5622           else if (!index)

5623             index = op;

5624           else

5625             return 0;

5626           break;

5627

5628         case CONST:

5629         case CONST_INT:

5630         case SYMBOL_REF:

5631         case LABEL_REF:

5632           if (disp)

5633             return 0;

5634           disp = op;

5635           break;

5636

5637         default:

5638           return 0;

5639       }

5640     }

5641   }

5642   else if (GET_CODE (addr) == MULT)

5643   {

5644       index = XEXP (addr, 0);         /* index*scale */

5645       scale_rtx = XEXP (addr, 1);

5646   }

5647   else if (GET_CODE (addr) == ASHIFT)

5648   {

     ...

5661   }

5662   else

5663     disp = addr;                /* displacement */

5664

5665   /* Extract the integral value of scale.  */

5666   if (scale_rtx)

5667   {

5668     if (GET_CODE (scale_rtx) != CONST_INT)

5669       return 0;

5670     scale = INTVAL (scale_rtx);

5671   }

5672

5673   /* Allow arg pointer and stack pointer as index if there is not scaling.  */

5674   if (base && index && scale == 1

5675       && (index == arg_pointer_rtx

5676       || index == frame_pointer_rtx

5677       || (REG_P (index) && REGNO (index) == STACK_POINTER_REGNUM)))

5678   {

5679     rtx tmp = base;

5680     base = index;

5681     index = tmp;

5682   }

5683

5684   /* Special case: %ebp cannot be encoded as a base without a displacement.  */

5685   if ((base == hard_frame_pointer_rtx

5686        || base == frame_pointer_rtx

5687        || base == arg_pointer_rtx) && !disp)

5688     disp = const0_rtx;

5689

5690   /* Special case: on K6, [%esi] makes the instruction vector decoded.

5691     Avoid this by transforming to [%esi+0].  */

5692   if (ix86_tune == PROCESSOR_K6 && !optimize_size

5693       && base && !index && !disp

5694       && REG_P (base)

5695       && REGNO_REG_CLASS (REGNO (base)) == SIREG)

5696     disp = const0_rtx;

5697

5698   /* Special case: encode reg+reg instead of reg*2.  */

5699   if (!base && index && scale && scale == 2)

5700     base = index, scale = 1;

5701

5702   /* Special case: scaling cannot be encoded without base or displacement.  */

5703   if (!base && !disp && index && scale != 1)

5704     disp = const0_rtx;

5705

5706   out->base = base;

5707   out->index = index;

5708   out->disp = disp;

5709   out->scale = scale;

5710   out->seg = seg;

5711

5712   return retval;

5713 }

 

Above do…while loop begins at line 5585 handles the infix form expression. Can see infix notation makes the handling so easy. The base will point to rtx object of hard_frame_pointer_rtx, the index will point to the rtx object of the other register, and disp will point to rtx object of 4.

Then in legitimate_address_p following, remember if not within register rename or reload pass, strict will be zero.

 

legitimate_address_p (continue)

 

6056   base = parts.base;

6057   index = parts.index;

6058   disp = parts.disp;

6059   scale = parts.scale;

6060

6061   /* Validate base register.

6062

6063     Don't allow SUBREG's here, it can lead to spill failures when the base

6064     is one word out of a two word structure, which is represented internally

6065     as a DImode int.  */

6066

6067   if (base)

6068   {

6069     reason_rtx = base;

6070

6071     if (GET_CODE (base) != REG)

6072     {

6073       reason = "base is not a register";

6074       goto report_error;

6075     }

6076

6077     if (GET_MODE (base) != Pmode)

6078     {

6079       reason = "base is not in Pmode";

6080       goto report_error;

6081     }

6082

6083     if ((strict && ! REG_OK_FOR_BASE_STRICT_P (base))

6084        || (! strict && ! REG_OK_FOR_BASE_NONSTRICT_P (base)))

6085     {

6086       reason = "base is not valid";

6087       goto report_error;

6088     }

6089   }

6090

6091   /* Validate index register.

6092

6093     Don't allow SUBREG's here, it can lead to spill failures when the index

6094     is one word out of a two word structure, which is represented internally

6095     as a DImode int.  */

6096

6097   if (index)

6098   {

6099     reason_rtx = index;

6100

6101     if (GET_CODE (index) != REG)

6102     {

6103       reason = "index is not a register";

6104       goto report_error;

6105     }

6106

6107     if (GET_MODE (index) != Pmode)

6108     {

6109       reason = "index is not in Pmode";

6110       goto report_error;

6111     }

6112

6113     if ((strict && ! REG_OK_FOR_INDEX_STRICT_P (index))

6114        || (! strict && ! REG_OK_FOR_INDEX_NONSTRICT_P (index)))

6115     {

6116       reason = "index is not valid";

6117       goto report_error;

6118     }

6119   }

 

Macro REG_OK_FOR_INDEX_NONSTRICT_P checks if specified register can hold index for the addressing.

 

1964 #define REG_OK_FOR_INDEX_NONSTRICT_P(X)                     /            in i386.h

1965   (REGNO (X) < STACK_POINTER_REGNUM                                /

1966    || (REGNO (X) >= FIRST_REX_INT_REG                             /

1967        && REGNO (X) <= LAST_REX_INT_REG)                          /

1968    || REGNO (X) >= FIRST_PSEUDO_REGISTER)

 

See that registers of ax, dx, cx, bx, si, di, bp, r8 ~ r15, and pseudo registers can be used to hold address index.

 

legitimate_address_p (continue)

 

6121   /* Validate scale factor.  */

6122   if (scale != 1)

6123   {

   

6136   }

6137

6138   /* Validate displacement.  */

6139   if (disp)

6140   {

6141     reason_rtx = disp;

6142

6143     if (GET_CODE (disp) == CONST

6144         && GET_CODE (XEXP (disp, 0)) == UNSPEC)

     

6166     else if (flag_pic && (SYMBOLIC_CONST (disp)

6167 #if TARGET_MACHO

6168         && !machopic_operand_p (disp)

6169 #endif

6170       ))

6171     {

6214     }

6215     else if (GET_CODE (disp) != LABEL_REF

6216          && GET_CODE (disp) != CONST_INT

6217          && (GET_CODE (disp) != CONST

6218          || !legitimate_constant_p (disp))

6219          && (GET_CODE (disp) != SYMBOL_REF

6220          || !legitimate_constant_p (disp)))

6221       {

6222         reason = "displacement is not constant";

6223         goto report_error;

6224       }

6225       else if (TARGET_64BIT && !x86_64_sign_extended_value (disp))

6226       {

6227         reason = "displacement is out of range";

6228         goto report_error;

6229       }

6230     }

6231  

6232     /* Everything looks valid.  */

6233     if (TARGET_DEBUG_ADDR)

6234       fprintf (stderr, "Success./n");

6235     return TRUE;

6236  

6237   report_error:

6238     if (TARGET_DEBUG_ADDR)

6239     {

6240       fprintf (stderr, "Error: %s/n", reason);

6241       debug_rtx (reason_rtx);

6242     }

6243     return FALSE;

6244   }

 

legitimate_address_p returns true for the first register of ax, and so is memory_address_p. The FOR loop at line 461 is exited immediately and continue running code below.

 

init_reload (continue)

 

477      /* Initialize obstack for our rtl allocation.  */

478      gcc_obstack_init (&reload_obstack);

479      reload_startobj = obstack_alloc (&reload_obstack, 0);

480   

481      INIT_REG_SET (&spilled_pseudos);

482      INIT_REG_SET (&pseudos_counted);

483    }

 

Above at line 481, spilled_pseudos records which pseudos needed to be spilled. And line 482, pseudos_counted is used for communication between function order_regs_for_reload and function count_pseudo, and used to avoid counting one pseudo twice. These two varialbes are of type bitmap. INIT_REG_SET initializes these two variables.

 

你可能感兴趣的:(object,function,report,null,Integer,structure)