GCC后端及汇编发布(11)

5.        genoutput 工具

5.1. 代码输出的准备

这个工具从 md 文件输出 insn-output.c Insn-output.c 为指定的模式产生汇编指令。

 

967  int

968  main (int argc, char **argv)                                                                 in genoutput.c

969  {

970    rtx desc;

971 

972    progname = "genoutput";

973 

974    if (argc <= 1)

975      fatal ("no input file name");

976 

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

978      return (FATAL_EXIT_CODE);

979 

980    output_prologue ();

981    next_code_number = 0;

982    next_index_number = 0;

983 

984    /* Read the machine description.  */

985 

986    while (1)

987    {

988      int line_no;

989 

990      desc = read_md_rtx (&line_no, &next_code_number );

991      if (desc == NULL)

992        break ;

993 

994      if (GET_CODE (desc) == DEFINE_INSN)

995        gen_insn (desc, line_no);

996      if (GET_CODE (desc) == DEFINE_PEEPHOLE)

997        gen_peephole (desc, line_no);

998      if (GET_CODE (desc) == DEFINE_EXPAND)

999        gen_expand (desc, line_no);

1000           if (GET_CODE (desc) == DEFINE_SPLIT

1001              || GET_CODE (desc) == DEFINE_PEEPHOLE2)

1002             gen_split (desc, line_no);

1003           next_index_number ++;

1004         }

1005

1006   printf("/n/n");

1007   output_operand_data ();

1008   output_insn_data ();

1009   output_get_insn_name ();

1010

1011   fflush (stdout);

1012   return (ferror (stdout) != 0 || have_error

1013        ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE);

1014 }

 

所有的 gen* 工具具有相似的开始。上面在 977 init_md_reader_args 将读入机器描述文件 并构建相应的 rtx 对象 如我们之前所见。出于展示的目的 这里我们再次使用我们在 genconditions 工具 中使用的 define_insn_and_split 模式作为例子。

5.2. define_insn 产生代码

我们已经知道这个模式将被分解为两个模式 ,一个为 define_insn ,另一个是 define_split 。对于 define_insn 模式, gen_insn 将在 995 行被调用。

 

807  static void

808  gen_insn (rtx insn, int lineno)                                                                      in genoutput.c

809  {

810    struct data *d = xmalloc (sizeof (struct data ));

811    int i;

812 

813    d->code_number = next_code_number ;

814    d->index_number = next_index_number ;

815    d->lineno = lineno;

816    if (XSTR (insn, 0)[0])

817      d->name = XSTR (insn, 0);

818    else

819      d->name = 0;

820 

821    /* Build up the list in the same order as the insns are seen

822      i n the machine description.  */

823    d->next = 0;

824    *idata_end = d;

825    idata_end = &d->next;

826 

827    max_opno = -1;

828    num_dups = 0;

829    memset (d->operand, 0, sizeof (d->operand));

830 

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

832      scan_operands (d, XVECEXP (insn, 1, i), 0, 0);

833 

834    d->n_operands = max_opno + 1;

835    d->n_dups = num_dups ;

836 

837    check_constraint_len ();

838    validate_insn_operands (d);

839    validate_insn_alternatives (d);

840    place_operands (d);

841    process_template (d, XTMPL (insn, 3));

842  }

 

上面 810 结构体 data 记录了所有将被输出的信息。这个数据将在 824 行链入 idata_end

 

156  struct data                                                                                            in genoutput.c

157  {

158    struct data *next;

159    const char *name;

160    const char *template;

161    int code_number;

162    int index_number;

163    int lineno;

164    int n_operands;          /* Number of operands this insn recognizes */

165    int n_dups;                /* Number times match_dup appears in pattern */

166    int n_alternatives;             /* Number of alternatives in each constraint */

167    int operand_number;         /* Operand index in the big array.  */

168    int output_format;             /* INSN_OUTPUT_FORMAT_*.  */

169    struct operand_data operand[MAX_MAX_OPERANDS];

170  };

 

122  struct operand_data                                                                               in genoutput.c

123  {

124    struct operand_data *next;

125    int index;

126    const char *predicate;

127    const char *constraint;

128    enum machine_mode mode;

129    unsigned char n_alternatives;

130    char address_p;

131    char strict_low;

132    char eliminable;

133    char seen;

134  };

 

用作例子的 define_insn 模式显示如下。看到该模式的第二个孩子是 rtvec ,其大小是 1 。在上面的 831 行, scan_operands 被调用来检查 rtvec 每个元素所需要的操作数的数目。

t31

31 genouput - define_insn_and_split 模式的例子 – insn 部分

 

423  static void

424  scan_operands (struct data *d, rtx part, int this_address_p,                             in genoutput.c

425                int this_strict_low)

426  {

427    int i, j;

428    const char *format_ptr;

429    int opno;

430 

431    if (part == 0)

432      return ;

433 

434    switch (GET_CODE (part))

435    {

436      case MATCH_OPERAND:

437        opno = XINT (part, 0);

438        if (opno > max_opno )

439          max_opno = opno;

440        if (max_opno >= MAX_MAX_OPERANDS)

441        {

442          message_with_line (d->lineno,

443                 "maximum number of operands exceeded");

444          have_error = 1;

445          return;

446        }

447        if (d->operand[opno].seen)

448        {

449          message_with_line (d->lineno,

450                "repeated operand number %d/n", opno);

451          have_error = 1;

452        }

453 

454        d->operand[opno].seen = 1;

455        d->operand[opno].mode = GET_MODE (part);

456        d->operand[opno].strict_low = this_strict_low;

457        d->operand[opno].predicate = XSTR (part, 1);

458        d->operand[opno].constraint = strip_whitespace (XSTR (part, 2));

459        d->operand[opno].n_alternatives

460           = n_occurrences (',', d->operand[opno].constraint) + 1;

461        d->operand[opno].address_p = this_address_p;

462        d->operand[opno].eliminable = 1;

463        return ;

464 

465      case MATCH_SCRATCH:

466        opno = XINT (part, 0);

467        if (opno > max_opno )

468          max_opno = opno;

469        if (max_opno >= MAX_MAX_OPERANDS)

470        {

471          message_with_line (d->lineno,

472                "maximum number of operands exceeded");

473          have_error = 1;

474          return ;

475        }

476        if (d->operand[opno].seen)

477        {

478          message_with_line (d->lineno,

479                "repeated operand number %d/n", opno);

480          have_error = 1;

481        }

482 

483        d->operand[opno].seen = 1;

484        d->operand[opno].mode = GET_MODE (part);

485        d->operand[opno].strict_low = 0;

486        d->operand[opno].predicate = "scratch_operand";

487        d->operand[opno].constraint = strip_whitespace (XSTR (part, 1));

488        d->operand[opno].n_alternatives

489           = n_occurrences (',', d->operand[opno].constraint) + 1;

490        d->operand[opno].address_p = 0;

491        d->operand[opno].eliminable = 0;

492        return ;

493 

494      case MATCH_OPERATOR:

495      case MATCH_PARALLEL:

496        opno = XINT (part, 0);

497        if (opno > max_opno )

498          max_opno = opno;

499        if (max_opno >= MAX_MAX_OPERANDS)

500        {

501          message_with_line (d->lineno,

502                "maximum number of operands exceeded");

503          have_error = 1;

504          return ;

505        }

506        if (d->operand[opno].seen)

507        {

508          message_with_line (d->lineno,

509                "repeated operand number %d/n", opno);

510          have_error = 1;

511        }

512 

513        d->operand[opno].seen = 1;

514        d->operand[opno].mode = GET_MODE (part);

515        d->operand[opno].strict_low = 0;

516        d->operand[opno].predicate = XSTR (part, 1);

517        d->operand[opno].constraint = 0;

518        d->operand[opno].address_p = 0;

519        d->operand[opno].eliminable = 0;

520        for (i = 0; i < XVECLEN (part, 2); i++)

521          scan_operands (d, XVECEXP (part, 2, i), 0, 0);

522        return ;

523 

524      case MATCH_DUP:

525      case MATCH_OP_DUP:

526      case MATCH_PAR_DUP:

527        ++num_dups ;

528        break ;

529 

530      case ADDRESS:

531        scan_operands (d, XEXP (part, 0), 1, 0);

532        return ;

533 

534      case STRICT_LOW_PART:

535        scan_operands (d, XEXP (part, 0), 0, 1);

536        return ;

537 

538      default :

539         break ;

540    }

541 

542    format_ptr = GET_RTX_FORMAT (GET_CODE (part));

543 

544    for (i = 0; i < GET_RTX_LENGTH (GET_CODE (part)); i++)

545      switch (*format_ptr++)

546      {

547        case 'e':

548        case 'u':

549          scan_operands (d, XEXP (part, i), 0, 0);

550          break ;

551        case 'E':

552          if (XVEC (part, i) != NULL)

553            for (j = 0; j < XVECLEN (part, i); j++)

554              scan_operands (d, XVECEXP (part, i, j), 0, 0);

555            break ;

556      }

557  }

 

对于我们的例子,这个模式的 rtl 编码是 set ,它直接跑到 542 行,并在 549 行递归入其两个孩子。这个代码相当简单。当它完成时,我们得到以下的数据结构。 data 代表指令模式,而 operand_data 保存了指令中操作数的细节。

t32

32 genoutput – define_insn 产生的数据,图 1

回到 gen_insn ,现在我们已经从 rtx 对象准备了数据。我们已经看到在模式定义中,约束( constraint )可以被用于描述,被选用于保存其参数的寄存器或内存的,条件。不同的芯片可以引入新的约束,或重新定义现存的约束。不过某些约束就像 C C++ 中的保留字那样,不允许修改其含义。函数 check_constraint_len 尝试找出这个篡改。

 

1057 static void

1058 check_constraint_len (void)                                                                 in genoutput.c

1059 {

1060   const char *p;

1061   int d;

1062

1063   for (p = ",#*+=&%!1234567890"; *p; p++)

1064     for (d = -9; d < 9; d++)

1065       if (constraint_len (p, d) != d)

1066         abort ();

1067 }

 

从上面,不允许篡改的约束是:‘ , ’,‘ # ’,‘ * ’,‘ + ,’,‘ = ’,‘ & ’,‘ % ’,‘ ! ’,‘ 1 ’,‘ 2 ’,‘ 3 ’,‘ 4 ’,‘ 5 ’,‘ 6 ’,‘ 7 ’,‘ 8 ’,‘ 9 ’,及‘ 0 ’。它们的含义可以参考【 2 】。

 

1069 static int

1070 constraint_len (const char *p, int genoutput_default_constraint_len)       in genoutput.c

1071 {

1072   /* Check that we still match defaults.h . First we do a generation-time

1073     check that fails if the value is not the expected one...  */

1074   if (DEFAULT_CONSTRAINT_LEN (*p, p) != 1)

1075     abort ();

1076   /* And now a compile-time check that should give a diagnostic if the

1077     definition doesn't exactly match.  */

1078 #define DEFAULT_CONSTRAINT_LEN(C,STR) 1

1079   /* Now re-define DEFAULT_CONSTRAINT_LEN so that we can verify it is

1080     being used.  */

1081 #undef DEFAULT_CONSTRAINT_LEN

1082 #define DEFAULT_CONSTRAINT_LEN(C,STR) /

1083   ((C) != *p || STR != p ? -1 : genoutput_default_constraint_len)

1084   return CONSTRAINT_LEN (*p, p);

1085   /* And set it back.  */

1086 #undef DEFAULT_CONSTRAINT_LEN

1087 #define DEFAULT_CONSTRAINT_LEN(C,STR) 1

1088 }

 

上面的 1074 行, DEFAULT_CONSTRAINT_LEN defaults.h 中被定义为 1 。这个定义不应该改变,除非在这个函数中。在 1084 行, CONSTRAINT_LEN 也在 defaults.h 中被定义为 DEFAULT_CONSTRAINT_LEN 。这个宏可以为不同的机器修改,来容纳订制的约束。让我们看一个 Renesas SuperH 的例子。

 

1318 /* Overview of uppercase letter constraints:

1319   A: Addresses (constraint len == 3)

1320     A c4: sh4 cache operations

1321     A c5: sh5 cache operations

1322   Bxx: miscellaneous constraints

1323     Bsc: SCRATCH - for the scratch register in movsi_ie in the

1324        fldi0 / fldi0 cases

1325   C: Constants other than only CONST_INT (constraint len == 3)

1326     C16: 16 bit constant, literal or symbolic

1327     Csy: label or symbol

1328     Cpg: non-explicit constants that can be directly loaded into a general

1329     purpose register in PIC code. like 's' except we don't allow

1330     PIC_DIRECT_ADDR_P

1331   IJKLMNOP: CONT_INT constants

1332     Ixx: signed xx bit

1333     J16: 0xffffffff00000000 | 0x00000000ffffffff

1334     Kxx: unsigned xx bit

1335     M: 1

1336     N: 0

1337     P27: 1 | 2 | 8 | 16

1338   Q: pc relative load operand

1339   Rxx: reserved for exotic register classes.

1340   S: extra memory (storage) constraints (constraint len == 3)

1341     Sua: unaligned memory operations

1342   W: vector

1343   Z: zero in any mode

1344

1345   unused CONST_INT constraint letters: LO

1346   unused EXTRA_CONSTRAINT letters: D T U Y */

1347

1348 #define CONSTRAINT_LEN(C,STR) /

1349   (((C) == 'A' || (C) == 'B' || (C) == 'C' /

1350     || (C) == 'I' || (C) == 'J' || (C) == 'K' || (C) == 'P' /

1351     || (C) == 'R' || (C) == 'S') /

1352    ? 3 : DEFAULT_CONSTRAINT_LEN ((C), (STR)))                                in sh.h

 

从注释可以看到以特定字符开头的约束长度是 3 DEFAULT_CONSTRAINT_LEN 则被展开为 1082 行的定义。一旦上述的约束被篡改, 1065 行的条件就不能满足;另外,如果在 CONSTRAINT_LEN 中改变了正在处理的约束, 1082 行的定义将返回 -1 。注意在 1078 行的定义之前没有使用 #undef ,如果 DEFAULT_CONSTRAINT_LEN 的定义不一致,编译器将给出一个警告。接着在 validate_insn_operands 中,我们确认所有的操作数都被 scan_operands 访问过了。

 

790  static void

791  validate_insn_operands (struct data *d)                                                 in genoutput.c

792  {

793    int i;

794 

795    for (i = 0; i < d->n_operands; ++i)

796      if (d->operand[i].seen == 0)

797      {

798        message_with_line (d->lineno, "missing operand %d", i);

799        have_error = 1;

800      }

801  }

 

回到 gen_insn ,在 839 行, validate_insn_alternatives 再次检查约束的有效性。注意到“ , ”,“ # ”,“ * ”不能被用于构建订制约束。

 

719  static void

720  validate_insn_alternatives (struct data *d)                                              in genoutput.c

721  {

722    int n = 0, start;

723 

724    /* Make sure all the operands have the same number of alternatives

725      i n their constraints. Let N be that number.  */

726    for (start = 0; start < d->n_operands; start++)

727      if (d->operand[start].n_alternatives > 0)

728      {

729        int len, i;

730        const char *p;

731        char c;

732        int which_alternative = 0;

733        int alternative_count_unsure = 0;

734 

735        for (p = d->operand[start].constraint; (c = *p); p += len)

736        {

737          len = CONSTRAINT_LEN (c, p);

738 

739          if (len < 1 || (len > 1 && strchr (",#*+=&%!0123456789", c)))

740          {

741            message_with_line (d->lineno,

742                    "invalid length %d for char '%c' in alternative %d of operand %d",

743                     len, c, which_alternative, start);

744            len = 1;

745            have_error = 1;

746          }

747 

748          if (c == ',')

749          {

750            which_alternative++;

751            continue ;

752          }

753 

754          for (i = 1; i < len; i++)

755            if (p[i] == '/0')

756            {

757              message_with_line (d->lineno,

758                     "NUL in alternative %d of operand %d",

759                      which_alternative, start);

760              alternative_count_unsure = 1;

761              break ;

762            }

763            else if (strchr (",#*", p[i]))

764            {

765              message_with_line (d->lineno,

766                      "'%c' in alternative %d of operand %d",

767                      p[i], which_alternative, start);

768              alternative_count_unsure = 1;

769            }

770        }

771        if (alternative_count_unsure)

772          have_error = 1;

773        else if (n == 0)

774          n = d->operand[start].n_alternatives;

775        else if (n != d->operand[start].n_alternatives)

776        {

777          message_with_line (d->lineno,

778                    "wrong number of alternatives in operand %d",

779                    start);

780          have_error = 1;

781        }

782      }

783 

784    /* Record the insn's overall number of alternatives.  */

785    d->n_alternatives = n;

786  }

 

虽然每个指令是不一样的,但是其中的操作数却可能是相同的,而且这些数据在汇编代码生成的过程中,只作为只读数据,因此尽可能共享它们是可能而且必要的。因此,通过了有效性检查后, place_operands 将维护该操作数的唯一一个实例。

 

599  static void

600  place_operands (struct data *d)                                                            in genoutput.c

601  {

602    struct operand_data *od, *od2;

603    int i;

604 

605    if (d->n_operands == 0)

606    {

607      d->operand_number = 0;

608      return ;

609    }

610 

611    /* Brute force substring search.  */

612    for (od = odata , i = 0; od; od = od->next, i = 0)

613      if (compare_operands (od, &d->operand[0]))

614      {

615        od2 = od->next;

616        i = 1;

617        while (1)

618        {

619          if (i == d->n_operands)

620            goto full_match;

621           if (od2 == NULL)

622            goto partial_match;

623          if (! compare_operands (od2, &d->operand[i]))

624            break ;

625          ++i, od2 = od2->next;

626        }

627      }

628 

629    /* Either partial match at the end of the list, or no match. In either

630      case, we tack on what operands are remaining to the end of the list.  */

631  partial_match:

632    d->operand_number = next_operand_number - i;

633    for (; i < d->n_operands; ++i)

634    {

635      od2 = &d->operand[i];

636      *odata_end = od2;

637      odata_end = &od2->next;

638      od2->index = next_operand_number ++;

639    }

640    *odata_end = NULL;

641    return ;

642 

643  full_match:

644    d->operand_number = od->index;

645    return ;

646  }

 

上面在 612 行,变量 odata 具有类型 operand_data ,它是 data 的一部分并构成了一个链表。在 612 行的 FOR 循环在其中查找是否存在 d 的实例,没有的话,要加入 odata 链表中。注意到,因为所有的 operand_data 被链接在一起, operand_number 记录了其唯一实例在链表中的位置,而 index 则记录了它在链表中的位置。然后 process_template 被调用来处理指令模式的模板部分。

 

653  static void

654  process_template (struct data *d, const char *template)                           in genoutput.c

655  {

656    const char *cp;

657    int i;

658 

659    /* Templates starting with * contain straight code to be run.  */

660    if (template[0] == '*')

661    {

662       d->template = 0;

663      d->output_format = INSN_OUTPUT_FORMAT_FUNCTION;

664 

665      puts ("/nstatic const char *");

666      printf ("output_%d (rtx *operands ATTRIBUTE_UNUSED, rtx insn ATTRIBUTE_UNUSED)/n",

667          d->code_number);

668      puts ("{");

669 

670      puts (template + 1);

671      puts ("}");

672    }

673 

674    /* If the assembler code template starts with a @ it is a newline-separated

675      list of assembler code templates, one for each alternative.  */

676    else if (template[0] == '@')

677    {

678      d->template = 0;

679      d->output_format = INSN_OUTPUT_FORMAT_MULTI;

680 

681      printf ("/nstatic const char * const output_%d[] = {/n", d->code_number);

682 

683      for (i = 0, cp = &template[1]; *cp; )

684      {

685        while (ISSPACE (*cp))

686          cp++;

687 

688        printf ("  /"");

689        while (!IS_VSPACE (*cp) && *cp != '/0')

690         {

691           putchar (*cp);

692           cp++;

693         }

694 

695         printf ("/",/n");

696         i++;

697      }

698      if (i == 1)

699        message_with_line (d->lineno,

700                "'@' is redundant for output template with single alternative");

701      if (i != d->n_alternatives)

702      {

703        message_with_line (d->lineno,

704                "wrong number of alternatives in the output template");

705        have_error = 1;

706      }

707 

708      printf ("};/n");

709    }

710    else

711    {

712      d->template = template;

713      d->output_format = INSN_OUTPUT_FORMAT_SINGLE;

714    }

715  }

 

在这里 process_template 处理模式中的输出模板,我们可以看到‘ * ’,‘ @ ’与其它之间的不同之处。对于前两者, output_* 函数将被产生,为后面输出的 insn_data 所引用。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值