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

5.        Tool of genoutput

5.1. Preparation for Code Generation

This tool outputs global array insn-output.c from md file. Insn-output.c produces assemble instructions for specified pattern.

 

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 }

 

All gen* tools have the similar beginning. Above at line 977, init_md_reader_args will read in the machine description file and create corresponding rtx object as we see before. For demonstration purpose, here we again use the define_insn_and_split pattern which we use in 2. Tool of genconditions as the example.

5.2. Generate Code for define_insn

We already know that this pattern will be split into two patterns, one of define_insn, the other of define_split. For the define_insn pattern, at line 995 gen_insn will be invoked.

 

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  }

 

Above, at line 810, structure data records all information that will be outputed. This data will be linked into idata_end at line 824.

 

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

 

The define_insn pattern used as the example is as following. See that the second child of the pattern is the rtvec which has the size of 1. At line 831 above, scan_operands is invoked to check the number of operands each element of rtvec needs.

t31

figure 31  : genouput - example of define_insn_and_split pattern – insn part

 

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  }

 

For our example, the pattern has rtl code of set , then drops to line 542, and recurses for its two children at line 549. The code is quite easy. When it finishes we can get the data structure as following. data represents instruction pattern, and operand_data saves details of operands in the instruction.

t32

figure 32  : genoutput – data produced for define_insn, figure 1

Back to gen_insn , now we have prepared the data from the rtx objects. We have seen that in pattern definition constraint can be used to describe the qualification of the register or memory to be selected to hold the parameter. Different chips can introduce new constraints or redefine existing ones. However some constrains are like reserve words in C or C++, they are not allowed to change the meaning. Function check_constraint_len tries to find out the tampering.

 

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 }

 

From above, the constraints does not allow tampering is ‘,’, ‘#’, ‘*’, ‘+’, ‘=’, ‘&’, ‘%’, ‘!’, ‘1’, ‘2’, ‘3’, ‘4’, ‘5’, ‘6’, ‘7’, ‘8’, ‘9’, and ‘0’. For their meaning please refer to reference [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 }

 

Above at line 1074, DEFAULT_CONSTRAINT_LEN is defined in defaults.h as 1. This definition should not be changed except temper in this function. At line 1084, CONSTRAINT_LEN is also defined in defaults.h by DEFAULT_CONSTRAINT_LEN . This macro can be changed for different machines to accommodate customized constraints. Let’s see an example for 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

 

From the comment, can see that constraints begin with the specified character are of size 3, and DEFAULT_CONSTRAINT_LEN is expanded by definition at line 1082. Once one of above contraints is tampered, condition at line 1065 won’t be met; besides, if in CONSTRAINT_LEN changes constraint under processing, the definition at line 1082 returns -1. Note that before the definition at line 1078, #undef is not given, so if DEFAULT_CONSTRAINT_LEN has inconsist definitions, the compiler will give a warning. Following then we make sure all operands have been visited by scan_operands in validate_insn_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  }

 

Back to gen_insn , at line 839, validate_insn_alternatives again checks the validation of the constraints. Notice that “,”, “#”, “*” can’t be used to form the custom constraint.

 

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  }

 

Though every insn is distinct, it may share the same operands with others, and these data, in assemble code generation, is used as read-only. It is possible and should share them as possible. So, passing the sanity check, place_operands will maintain a singlton for the operand.

 

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  }

 

Above at line 612, variable odata is of type operand_data which is part of data and forms a link. In FOR loop at line 612, it finds if the instance of d is present, if not, it will be added into this link. Notice that as all operand_datas are linked tegother, operand_number records the the index of the unique instance, and index records its positon is in the list. Then process_template is inovked to operate template part of the instruction pattern.

 

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  }

 

Here process_template handles the output template in pattern, we can see the difference between ‘*’ ‘@’ and others. For former both types, output_* functions will be produced for reference by insn_data output later.

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值