Expand call

From reading gcc
Jump to: navigation, search

概要[edit | edit source]

  • expr.c にて定義
  • 関数コールのtreeからRTL式を生成

引数[edit | edit source]

  • exp 関数コールのtree (関数アドレスのtree、引数のtree)
  • target

実装[edit | edit source]

2096 static rtx
2097 expand_call (exp, target)
2098      tree exp;
2099      rtx target;
2100 {
2101   tree actparms = TREE_OPERAND (exp, 1);
2102   register tree p;
2103   int args_size = 0;
2104   register int i;
2105   register tree *argvec;
2106   int num_actuals;
2107   rtx structure_value_addr = 0;
2108 
2109   /* Don't let pending stack adjusts add up to too much.
2110      Also, do all pending adjustments now
2111      if there is any chance this might be a call to alloca.  */
2112 
2113   if (pending_stack_adjust >= 32
2114       || (pending_stack_adjust > 0
2115           &&
2116           /* Unless it's a call to a specific function that isn't alloca,
2117              we must assume it might be alloca.  */
2118           !(p = TREE_OPERAND (exp, 0),
2119             TREE_CODE (p) == ADDR_EXPR
2120             && TREE_CODE (TREE_OPERAND (p, 0)) == FUNCTION_DECL
2121             && strcmp (IDENTIFIER_POINTER (DECL_NAME (TREE_OPERAND (p, 0))),
2122                        "alloca"))))
2123     do_pending_stack_adjust ();
2124 

構造体のアドレス?

2125   if (TYPE_MODE (TREE_TYPE (exp)) == BLKmode)
2126     {
2127       /* This call returns a big structure.  */
2128       if (target)
2129         structure_value_addr = XEXP (target, 0);
2130       else
2131         /* Make room on the stack to hold the value.  */
2132         structure_value_addr = get_structure_value_addr (expr_size (exp));
2133     }
2134 

引数の数だけ領域を確保し、スタックに積む順序で配列に並べる。

2135   for (p = actparms, i = 0; p; p = TREE_CHAIN (p)) i++;
2136   num_actuals = i;
2137   argvec = (tree *) alloca (i * sizeof (tree));
2138 
2139 #ifdef STACK_GROWS_DOWNWARD
2140   /* In this case, must reverse order of args
2141      so that we compute and pust the last arg first.  */
2142   for (p = actparms, i = num_actuals - 1; p; p = TREE_CHAIN (p), i--)
2143     argvec[i] = p;
2144 #else
2145   for (p = actparms, i = 0; p; p = TREE_CHAIN (p), i++)
2146     argvec[i] = p;
2147 #endif
2148 

なにかチェックし、引数をスタックに積む、PUSHのRTL式に変換

2149   for (i = 0; i < num_actuals; i++)
2150     {
2151       register tree p = argvec[i];
2152       register tree pval = TREE_VALUE (p);
2153 
2154       /* Push the next argument.  Note that it has already been converted
2155          if necessary to the type that the called function expects.  */
2156 
2157       if (TREE_CODE (pval) == ERROR_MARK)
2158         ;
2159       else if (TYPE_MODE (TREE_TYPE (pval)) != BLKmode)
2160         {
2161           register int size, used;
2162 
2163           /* Argument is a scalar.
2164              Push it, and if its size is less than the
2165              amount of space allocated to it,
2166              also bump stack pointer by the additional space.
2167              Note that in C the default argument promotions
2168              will prevent such mismatches.  */
2169 
2170           used = size = GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (pval)));
2171           /* Compute how much space the push instruction will push.
2172              On many machines, pushing a byte will advance the stack
2173              pointer by a halfword.  */
2174           size = PUSH_ROUNDING (size);
2175           /* Compute how much space the argument should get:
2176              round up to a multiple of the alignment for arguments.  */
2177           used = (((size + PARM_BOUNDARY / BITS_PER_UNIT - 1)
2178                    / (PARM_BOUNDARY / BITS_PER_UNIT))
2179                   * (PARM_BOUNDARY / BITS_PER_UNIT));
2180 
2181 #ifdef STACK_GROWS_DOWNWARD
2182           if (size != used)
2183             anti_adjust_stack (gen_rtx (CONST_INT, VOIDmode,
2184                                         used - size));
2185 #endif
2186 
2187           emit_push_insn (expand_expr (pval, 0, VOIDmode, 0),
2188                           TYPE_MODE (TREE_TYPE (pval)), 0, 0);
2189 
2190 #ifndef STACK_GROWS_DOWNWARD
2191           if (size != used)
2192             anti_adjust_stack (gen_rtx (CONST_INT, VOIDmode,
2193                                         used - size));
2194 #endif
2195 
2196           /* Account for the space thus used.  */
2197           args_size += used;
2198           current_args_size += used;
2199         }
2200       else
2201         {
2202           register rtx tem = expand_expr (pval, 0, VOIDmode, 0);
2203           register tree size = size_in_bytes (TREE_TYPE (pval));
2204           register tree used;
2205           register int excess;
2206 
2207           /* Pushing a nonscalar.  Round its size up to a multiple
2208              of the allocation unit for arguments.  This part works
2209              on variable-size objects since SIZE and USED are rtx's.  */
2210 
2211           used = convert_units (convert_units (size, BITS_PER_UNIT, PARM_BOUNDARY),
2212                                 PARM_BOUNDARY, BITS_PER_UNIT);
2213 
2214           if (!TREE_LITERAL (used))
2215             abort ();
2216 
2217           excess = TREE_INT_CST_LOW (used) - PUSH_ROUNDING (TREE_INT_CST_LOW (size));
2218 
2219 #ifdef STACK_GROWS_DOWNWARD
2220           if (excess != 0)
2221             anti_adjust_stack (gen_rtx (CONST_INT, VOIDmode, excess));
2222 #endif
2223 
2224           emit_push_insn (tem, TYPE_MODE (TREE_TYPE (pval)),
2225                           expand_expr (size, 0, VOIDmode, 0),
2226                           (TYPE_ALIGN (TREE_TYPE (pval))
2227                            / BITS_PER_UNIT));
2228 
2229 #ifndef STACK_GROWS_DOWNWARD
2230           if (excess != 0)
2231             anti_adjust_stack (gen_rtx (CONST_INT, VOIDmode, excess));
2232 #endif
2233           args_size += TREE_INT_CST_LOW (used);
2234           current_args_size += TREE_INT_CST_LOW (used);
2235         }
2236     }
2237 

関数を呼ぶ前に、INSNを吐き出して、queueに入れる。

2238   /* Perform postincrements before actually calling the function.  */
2239   emit_queue ();
2240 


2241   /* Pass the function the address in which to return a structure value.  */
2242   if (structure_value_addr)
2243     {
2244       register rtx reg = gen_rtx (REG, Pmode, STRUCT_VALUE_REGNUM);
2245       emit_move_insn (reg, structure_value_addr);
2246       emit_insn (gen_rtx (USE, VOIDmode, reg));
2247     }
2248 

関数コール

2249   gen_call_1 (expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0),
2250 /* ??? For Pascal, this must pass a context to get the static chain from
2251    in certain cases.  */
2252               0,
2253               args_size / GET_MODE_SIZE (SImode), args_size);
2254 

2255 /* ??? Nothing has been done here to record control flow

2256    when contained functions can do nonlocal gotos.  */
2257 

戻り値が無い

2258   /* If value type not void, return an rtx for the value.  */
2259 
2260   if (TYPE_MODE (TREE_TYPE (exp)) == VOIDmode)
2261     return 0;
2262 
2263   if (structure_value_addr)
2264     {
2265       if (target)
2266         return target;
2267       return gen_rtx (MEM, BLKmode, structure_value_addr);
2268     }
2269 


2270   if (target && GET_MODE (target) == TYPE_MODE (TREE_TYPE (exp)))
2271     {
2272       copy_function_value (target);
2273       return target;
2274     }
2275   return function_value (TYPE_MODE (TREE_TYPE (exp)));
2276 }

情報[edit | edit source]

2091 /* Generate all the code for a function call
2092    and return an rtx for its value.
2093    Store the value in TARGET (specified as an rtx) if convenient.
2094    If the value is stored in TARGET then TARGET is returned.  */