GCC's bacl-end & assemble emission (9)

4.        Tool of genemit

4.1. Preparation for Code Generation

This tool outputs insn-emit.c file from machine description file. Insn-emit.c defines function sto generate a body for patterns, given operands as arguments.

 

775  int

776  main (int argc, char **argv)                                                                        in genemit.c

777  {

778    rtx desc;

779 

780    progname = "genemit";

781 

782    if (argc <= 1)

783      fatal ("no input file name");

784 

785    if (init_md_reader_args (argc, argv) != SUCCESS_EXIT_CODE)

786      return (FATAL_EXIT_CODE);

787 

788    /* Assign sequential codes to all entries in the machine description

789      i n parallel with the tables in insn-output.c.  */

790 

791    insn_code_number = 0;

792    insn_index_number = 0;

793 

794    printf ("/* Generated automatically by the program `genemit'/n/

795          from the machine description file `md'.  *//n/n");

796 

797    printf ("#include /"config.h/"/n");

798    printf ("#include /"system.h/"/n");

799    printf ("#include /"coretypes.h/"/n");

800    printf ("#include /"tm.h/"/n");

801    printf ("#include /"rtl.h/"/n");

802    printf ("#include /"tm_p.h/"/n");

803    printf ("#include /"function.h/"/n");

804    printf ("#include /"expr.h/"/n");

805    printf ("#include /"optabs.h/"/n");

806    printf ("#include /"real.h/"/n");

807    printf ("#include /"flags.h/"/n");

808    printf ("#include /"output.h/"/n");

809    printf ("#include /"insn-config.h/"/n");

810    printf ("#include /"hard-reg-set.h/"/n");

811    printf ("#include /"recog.h/"/n");

812    printf ("#include /"resource.h/"/n");

813    printf ("#include /"reload.h/"/n");

814    printf ("#include /"toplev.h/"/n");

815    printf ("#include /"ggc.h/"/n/n");

816    printf ("#define FAIL return (end_sequence (), _val)/n");

817    printf ("#define DONE return (_val = get_insns (), end_sequence (), _val)/n/n");

 

The beginning all looks alike. At line 785, init_md_reader_args reads in the machine description file and creates corresponding rtx objects. We just takes the define_insn_and_split example in Tool of genconditions , which will be splited into two rtx objects.

 

4225 (define_insn_and_split "*fix_truncsi_1"                                                       in i386.md

4226   [(set (match_operand:SI 0 "nonimmediate_operand" "=m,?r")

4227        (fix:SI (match_operand 1 "register_operand" "f,f")))]

4228   "TARGET_80387 && FLOAT_MODE_P (GET_MODE (operands[1]))

4229    && !reload_completed && !reload_in_progress

4230    && !SSE_FLOAT_MODE_P (GET_MODE (operands[1]))"

4231   "#"

4232   "&& 1"

4233   [(const_int 0)]

4234 {

4235   ix86_optimize_mode_switching = 1;

4236   operands[2] = assign_386_stack_local (HImode, 1);

4237   operands[3] = assign_386_stack_local (HImode, 2);

4238   if (memory_operand (operands[0], VOIDmode))

4239     emit_insn (gen_fix_truncsi_memory (operands[0], operands[1],

4240                                    operands[2], operands[3]));

4241   else

4242     {

4243       operands[4] = assign_386_stack_local (SImode, 0);

4244       emit_insn (gen_fix_truncsi_nomemory (operands[0], operands[1],

4245                                       operands[2], operands[3],

4246                                       operands[4]));

4247     }

4248   DONE;

4249 }

4250   [(set_attr "type" "fistp")

4251    (set_attr "mode" "SI")])

 

Then in following, in main we will handle the rtx object instead.

 

main (continued)

 

819    /* Read the machine description.  */

820 

821    while (1)

822    {

823      int line_no;

824 

825      desc = read_md_rtx (&line_no, &insn_code_number);

826      if (desc == NULL)

827        break ;

828 

829      switch (GET_CODE (desc))

830      {

831        case DEFINE_INSN:

832           gen_insn (desc, line_no);

833           break ;

834 

835        case DEFINE_EXPAND:

836          printf ("/* %s:%d *//n", read_rtx_filename, line_no);

837           gen_expand (desc);

838          break ;

839 

840        case DEFINE_SPLIT:

841          printf ("/* %s:%d *//n", read_rtx_filename, line_no);

842           gen_split (desc);

843          break ;

844 

845        case DEFINE_PEEPHOLE2:

846          printf ("/* %s:%d *//n", read_rtx_filename, line_no);

847           gen_split (desc);

848          break ;

849 

850        default :

851          break ;

852      }

853      ++insn_index_number;

854    }

855 

856    /* Write out the routines to add CLOBBERs to a pattern and say whether they

857      clobber a hard reg.  */

858    output_add_clobbers ();

859    output_added_clobbers_hard_reg_p ();

860 

861    fflush (stdout);

862    return (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE);

863  }

4.2. Generate Code for define_insn

For our example define_insn_and_split pattern, after read in, the define_insn part is as following.


figure 29  : genemit - example of define_insn_and_split pattern – insn part

It is a define_insn rtx object, so gen_insn will be invoked.

 

287  static void

288  gen_ins n (rtx insn, int lineno)                                                                             in genemit.c

289  {

290    int operands;

291    int i;

292 

293    /* See if the pattern for this insn ends with a group of CLOBBERs of (hard)

294      registers or MATCH_SCRATCHes. If so, store away the information for

295      later.  */

296 

297    if (XVEC (insn, 1))

298    {

299      int has_hard_reg = 0;

300 

301      for (i = XVECLEN (insn, 1) - 1; i > 0; i--)

302      {

303        if (GET_CODE (XVECEXP (insn, 1, i)) != CLOBBER)

304          break ;

305 

306        if (GET_CODE (XEXP (XVECEXP (insn, 1, i), 0)) == REG)

307          has_hard_reg = 1;

308        else if (GET_CODE (XEXP (XVECEXP (insn, 1, i), 0)) != MATCH_SCRATCH)

309          break ;

310      }

 

For our example above, it breaks out the loop at line 304, as the pattern doesn’t clobber any register.

 

gen_insn (continued)

 

312      if (i != XVECLEN (insn, 1) - 1)

313      {

314        struct clobber_pat *p;

315        struct clobber_ent *link = xmalloc (sizeof (struct clobber_ent));

316        int j;

317 

318        link->code_number = insn_code_number ;

319 

320        /* See if any previous CLOBBER_LIST entry is the same as this

321          one.  */

322 

323        for (p = clobber_list ; p; p = p->next)

324        {

325          if (p->first_clobber != i + 1

326             || XVECLEN (p->pattern, 1) != XVECLEN (insn, 1))

327            continue ;

328 

329          for (j = i + 1; j < XVECLEN (insn, 1); j++)

330          {

331            rtx old = XEXP (XVECEXP (p->pattern, 1, j), 0);

332            rtx new = XEXP (XVECEXP (insn, 1, j), 0);

333 

334             /* OLD and NEW are the same if both are to be a SCRATCH

335              of the same mode,

336              or if both are registers of the same mode and number.  */

337            if (! (GET_MODE (old) == GET_MODE (new)

338              && ((GET_CODE (old) == MATCH_SCRATCH

339              && GET_CODE (new) == MATCH_SCRATCH)

340              || (GET_CODE (old) == REG && GET_CODE (new) == REG

341                 && REGNO (old) == REGNO (new)))))

342              break ;

343          }

344 

345          if (j == XVECLEN (insn, 1))

346            break ;

347        }

348 

349        if (p == 0)

350        {

351          p = xmalloc (sizeof (struct clobber_pat));

352 

353          p->insns = 0;

354          p->pattern = insn;

355          p->first_clobber = i + 1;

356          p->next = clobber_list ;

357          p->has_hard_reg = has_hard_reg;

358          clobber_list = p;

359        }

360 

361        link->next = p->insns;

362        p->insns = link;

363      }

364    }

 

Above, for pattern will clobber register, the relative information must be saved in clobber_list. It has following definition:

 

42    struct clobber_pat                                                                                       in genemit.c

43    {

44      struct clobber_ent *insns;

45      rtx pattern;

46      int first_clobber;

47      struct clobber_pat *next;

48      int has_hard_reg;

49    } *clobber_list;

50   

51    /* Records one insn that uses the clobber list.  */

52   

53    struct clobber_ent

54    {

55      int code_number;              /* Counts only insns.  */

56      struct clobber_ent *next;

57    };

 

clobber_pat keeps the record of clobber information for the patterns having the same form,  in other words, for two patterns have different form, they will belong to different clobber_pat instances. So has_hard_reg , first_clobber are meaningful for all members in clobber_ent , in which first_clobber means at which step the specified register will be clobbered and has_hard_reg indicates if real register is involved.

code_number in clobber_ent distincts the patterns, as it comes from insn_code_number , which is unique and invariable for specified pattern. Obviously, clobber_ent is per pattern. And for our example, no clobber information is collected.

 

gen_insn (continued)

 

366    /* Don't mention instructions whose names are the null string

367      or begin with '*'. They are in the machine description just

368      to be recognized.  */

369    if (XSTR (insn, 0)[0] == 0 || XSTR (insn, 0)[0] == '*')

370      return ;

371 

372    printf ("/* %s:%d *//n", read_rtx_filename , lineno);

373 

374    /* Find out how many operands this function has.  */

375    operands = max_operand_vec (insn, 1);

376    if (max_dup_opno >= operands)

377      fatal ("match_dup operand number has no match_operand");

378    /* Output the function name and argument declarations.  */

379    printf ("rtx/ngen_%s (", XSTR (insn, 0));

380    if (operands)

381      for (i = 0; i < operands; i++)

382        if (i)

383          printf (",/n/trtx operand%d ATTRIBUTE_UNUSED", i);

384        else

385          printf ("rtx operand%d ATTRIBUTE_UNUSED", i);

386    else

387      printf ("void");

388    printf (")/n");

389    printf ("{/n");

 

Unfortunatly, our example has ‘*’ at the beginning of its name, which means the instruction pattern is never used for generating RTL code and such a name is used only for identifying the instruction in RTL dumps. So in real world, it will return at line 370 without doing something meaningful.

Now, we assuem that the ‘*’ is not appeared all long. At line 372, it gives information where we are from. At line 375, max_operand_vec finds out the number of operands in the pattern. This function is quite simple. For our example, max_opno will be 2.

 

108  static int

109  max_operand_vec (rtx insn, int arg)                                                            in genemit.c

110  {

111    int len = XVECLEN (insn, arg);

112    int i;

113 

114    max_opno = -1;

115    max_dup_opno = -1;

116    max_scratch_opno = -1;

117 

118    for (i = 0; i < len; i++)

119      max_operand_1 (XVECEXP (insn, arg, i));

120 

121    return max_opno + 1;

122  }

 

72    static void

73    max_operand_1 (rtx x)                                                                               in genemit.c

74    {

75      RTX_CODE code;

76      int i;

77      int len;

78      const char *fmt;

79   

80      if (x == 0)

81        return ;

82   

83      code = GET_CODE (x);

84   

85      if (code == MATCH_OPERAND || code == MATCH_OPERATOR

86          || code == MATCH_PARALLEL)

87        max_opno = MAX (max_opno , XINT (x, 0));

88      if (code == MATCH_DUP || code == MATCH_OP_DUP || code == MATCH_PAR_DUP)

89        max_dup_opno = MAX (max_dup_opno , XINT (x, 0));

90      if (code == MATCH_SCRATCH)

91        max_scratch_opno = MAX (max_scratch_opno , XINT (x, 0));

92   

93      fmt = GET_RTX_FORMAT (code);

94      len = GET_RTX_LENGTH (code);

95      for (i = 0; i < len; i++)

96      {

97        if (fmt[i] == 'e' || fmt[i] == 'u')

98          max_operand_1 (XEXP (x, i));

99        else if (fmt[i] == 'E')

100      {

101        int j;

102        for (j = 0; j < XVECLEN (x, i); j++)

103          max_operand_1 (XVECEXP (x, i, j));

104      }

105    }

106  }

 

Then we will get the function definition as below (assume the pattern name is fix_truncsi_1 instead of *fix_truncsi_1) from above code fragment.

 

rtx

gen_fix_truncsi_1(rtx operand0 ATTRIBUTE_UNUSED,

       rtx operand1 ATTRIBUTE_UNUSED,

       rtx operand2 ATTRIBUTE_UNUSED)

{

 

gen_insn (continued)

 

392    /* Output code to construct and return the rtl for the instruction body.  */

393 

394    if (XVECLEN (insn, 1) == 1)

395    {

396      printf ("  return ");

397      gen_exp (XVECEXP (insn, 1, 0), DEFINE_INSN, NULL);

398      printf (";/n}/n/n");

399    }

400    else

401    {

402      printf ("  return gen_rtx_PARALLEL (VOIDmode, gen_rtvec (%d",

403           XVECLEN (insn, 1));

404 

405      for (i = 0; i < XVECLEN (insn, 1); i++)

406      {

407        printf (",/n/t/t");

408        gen_exp (XVECEXP (insn, 1, i), DEFINE_INSN, NULL);

409      }

410      printf ("));/n}/n/n");

411    }

412  }

 

In rtx format of define_pattern, RTL template has format ‘E’ – vector of rtx objects. Above, at line 394 XVECLEN gets the size of the vector, and at line 408 XVECEXP gets the element in the vector. For parameter x of gen_exp , it points to RTL template as following.

 

4225        [(set (match_operand:SI 0 "nonimmediate_operand" "=m,?r")

4226          (fix:SI (match_operand 1 "register_operand" "f,f")))]

 

148  static void

149  gen_exp (rtx x, enum rtx_code subroutine_type, char *used)                          in genemit.c

150  {

151    RTX_CODE code;

152    int i;

153    int len;

154    const char *fmt;

155 

156    if (x == 0)

157    {

158      printf ("NULL_RTX");

159      return ;

160    }

161 

162    code = GET_CODE (x);

163 

164    switch (code)

165    {

166      case MATCH_OPERAND:

167      case MATCH_DUP:

168        if (used)

169        {

170          if (used[XINT (x, 0)])

171          {

172            printf ("copy_rtx (operand%d)", XINT (x, 0));

173             return ;

174          }

175          used[XINT (x, 0)] = 1;

176        }

177        printf ("operand%d", XINT (x, 0));

178        return ;

179 

180      case MATCH_OP_DUP:

181        printf ("gen_rtx (GET_CODE (operand%d), ", XINT (x, 0));

182        if (GET_MODE (x) == VOIDmode)

183          printf ("GET_MODE (operand%d)", XINT (x, 0));

184        else

185          printf ("%smode", GET_MODE_NAME (GET_MODE (x)));

186        for (i = 0; i < XVECLEN (x, 1); i++)

187        {

188          printf (",/n/t/t");

189          gen_exp (XVECEXP (x, 1, i), subroutine_type, used);

190        }

191        printf (")");

192        return ;

193 

194      case MATCH_OPERATOR:

195        printf ("gen_rtx (GET_CODE (operand%d)", XINT (x, 0));

196        printf (", %smode", GET_MODE_NAME (GET_MODE (x)));

197        for (i = 0; i < XVECLEN (x, 2); i++)

198        {

199          printf (",/n/t/t");

200          gen_exp (XVECEXP (x, 2, i), subroutine_type, used);

201        }

202        printf (")");

203        return ;

204 

205      case MATCH_PARALLEL:

206      case MATCH_PAR_DUP:

207        printf ("operand%d", XINT (x, 0));

208        return ;

209 

210      case MATCH_SCRATCH:

211        gen_rtx_scratch (x, subroutine_type);

212        return ;

213 

214      case ADDRESS:

215        fatal ("ADDRESS expression code used in named instruction pattern");

216 

217      case PC:

218        printf ("pc_rtx");

219        return ;

220 

221      case CC0:

222        printf ("cc0_rtx");

223        return ;

224 

225      case CONST_INT:

226        if (INTVAL (x) == 0)

227          printf ("const0_rtx");

228        else if (INTVAL (x) == 1)

229          printf ("const1_rtx");

230        else if (INTVAL (x) == -1)

231          printf ("constm1_rtx");

232        else if (INTVAL (x) == STORE_FLAG_VALUE)

233          printf ("const_true_rtx");

234        else

235        {

236          printf ("GEN_INT (");

237          printf (HOST_WIDE_INT_PRINT_DEC_C, INTVAL (x));

238           printf (")");

239        }

240        return ;

241 

242      case CONST_DOUBLE:

243        /* These shouldn't be written in MD files. Instead, the appropriate

244          routines in varasm.c should be called.  */

245        abort ();

246 

247      default :

248        break ;

249    }

250 

251    printf ("gen_rtx_");

252    print_code (code);

253    printf (" (%smode", GET_MODE_NAME (GET_MODE (x)));

 

For our example here, the code is SET, so we drop to line 251 directly. As the set pattern hasn’t mode information with it, the mode is VIODmode in default. Now we get:

 

rtx

gen_fix_truncsi_1(rtx operand0 ATTRIBUTE_UNUSED,

       rtx operand1 ATTRIBUTE_UNUSED,

       rtx operand2 ATTRIBUTE_UNUSED)

{

return gen_rtx_set (VOIDmode,

 

For set pattern, its rtl format is “ee”, so recursing gen_exp with its children at line 263.

 

gen_exp (continued)

 

255    fmt = GET_RTX_FORMAT (code);

256    len = GET_RTX_LENGTH (code);

257    for (i = 0; i < len; i++)

258    {

259      if (fmt[i] == '0')

260        break ;

261      printf (",/n/t");

262      if (fmt[i] == 'e' || fmt[i] == 'u')

263        gen_exp (XEXP (x, i), subroutine_type, used);

264      else if (fmt[i] == 'i')

265        printf ("%u", XINT (x, i));

266      else if (fmt[i] == 's')

267        printf ("/"%s/"", XSTR (x, i));

268      else if (fmt[i] == 'E')

269      {

270        int j;

271        printf ("gen_rtvec (%d", XVECLEN (x, i));

272        for (j = 0; j < XVECLEN (x, i); j++)

273        {

274          printf (",/n/t/t");

275          gen_exp (XVECEXP (x, i, j), subroutine_type, used);

276         }

277        printf (")");

278      }

279      else

280        abort ();

281    }

282    printf (")");

283  }

 

The first child of set pattern is match_operand , and we will enter at line 166. Note that the used parameter of the gen_exp is null, so we get:

 

rtx

gen_fix_truncsi_1(rtx operand0 ATTRIBUTE_UNUSED,

       rtx operand1 ATTRIBUTE_UNUSED,

       rtx operand2 ATTRIBUTE_UNUSED)

{

   return gen_rtx_set (VOIDmode,

operand0

 

The second child of set pattern is fix , its rtl format is ‘e’. Again, we just drop to line 251 as set pattern. And it will recurse gen_exp with its first child match_operand too. So we get following code for this set pattern.

 

rtx

gen_fix_truncsi_1(rtx operand0 ATTRIBUTE_UNUSED,

       rtx operand1 ATTRIBUTE_UNUSED,

       rtx operand2 ATTRIBUTE_UNUSED)

{

   return gen_rtx_SET (VOIDmode,

operand0,

gen_rtx_FIX (SImode,

operand1));

}

你可能感兴趣的:(struct,function,gcc,output,parallel,subroutine)