GCC后端及汇编发布(9)

4.        genemit 工具

4.1. 代码输出的准备

这个工具从机器描述文件生成文件 insn-emit.c Insn-emit.c 定义了,从机器描述文件中的模式定义生成的,以给定操作数作为参数的模式匹配函数。

 

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");

 

开始看起来都是类似的。在 785 行, init_md_reader_args 读入机器描述文件,并构建对应的 rtx 对象。我们以 genconditions工具 中的 define_insn_and_split 为例,它将被分裂成两个 rtx 对象。

 

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")])

 

那么在下面,在 main 中我们将处理这个 rtx 对象。

 

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.1. define_insn 产生代码

对于我们 define_insn_and_split 模式的例子,其 define_insn 部分如下。

t29

 

29 genemit - define_insn_and_split 模式 – insn 部分

这是一个 define_insn rtx 对象,因此 gen_insn 将被调用。

 

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      }

 

对于我们上面的例子,它在 304 行跳出循环,因为这个模式不破坏任何寄存器。

 

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    }

 

上面。对于将破坏寄存器的模式,这个相关的信息必须被保存在 clobber_list 中。它具有如下的定义:

 

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 为具有相同形式的模式保存 clobber 信息的记录,换而言之,对于两个具有不同形式的模式,它们将属于不同的 clobber_pat 实例。因此 has_hard_reg first_clobber 对于 clobber_ent 中的所有成员都是有意义的,其中 first_clobber 表示在哪一步这个指定的寄存器将被破坏,而 has_hard_reg 指出是否涉及真实的寄存器。

clobber_ent 中的 code_number 区分模式,因为它来自 insn_code_number ,对于指定的模式它是唯一且不变的。显然, clobber_ent 是与模式对应的。对于我们的例子,没有收集 clobber 信息。

 

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");

 

不过,我们的例子在其名字的开头有“ * ”,这意味着这个指令模式不用于产生 RTL 代码,并且这样的一个名字仅用于在 RTL 转储( dump )中识别该指令。因此在真实世界里,它将在 370 行返回,而不做任何事。

现在,我们假定这个‘ * 压根没有出现过。在 372 行,给出我们来自那里的信息。在 375 行, max_operand_vec 找出在该模式中操作数的个数。这个函数相当简单。对于我们的例子, max_opno 将是 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  }

 

那么,从上面的代码片段,我们将得到如下函数的定义(假定模式名字是 fix_truncsi_1 ,而不是 *fix_truncsi_1 )。

 

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  }

 

define_pattern rtx 格式中, RTL 模板具有格式‘ E ’—— rtx 对象的向量。在上面 394 行的 XVECLEN 给出了这个向量的大小,而在 408 XVECEXP 给出该向量中的元素。对于 gen_exp 的参数 x ,它指向以下的 RTL 模板。

 

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)));

 

对于我们这里的例子,编码是 SET ,因此我们直接跑到 251 行。因为这个 set 模式没有带 mode 信息,这个 mode 默认的是 VIODmode 。现在我们得到:

 

rtx

gen_fix_truncsi_1(rtx operand0 ATTRIBUTE_UNUSED,

       rtx operand1 ATTRIBUTE_UNUSED,

       rtx operand2 ATTRIBUTE_UNUSED)

{

return gen_rtx_set (VOIDmode,

 

对于 set 模式,其 rtl 格式是“ ee ”,因此在 263 gen_exp 递归入其孩子。

 

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  }

 

这个 set 模式的第一个孩子是 match_operand ,我们将进入 166 行。注意到 gen_exp 的参数 used null ,因此我们得到:

 

rtx

gen_fix_truncsi_1(rtx operand0 ATTRIBUTE_UNUSED,

       rtx operand1 ATTRIBUTE_UNUSED,

       rtx operand2 ATTRIBUTE_UNUSED)

{

   return gen_rtx_set (VOIDmode,

operand0

 

模式 set 的第二个孩子是 fix ,其 rtl 格式是‘ e ’。再次,我们直接跳到 251 行。并且也将使用 gen_exp 递归其第一个孩子 match_operand 。因此,对于这个 set 模式,我们得到以下代码片段。

 

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));

}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值