GCC后端及汇编发布(5)

来源:互联网 发布:遥感卫星数据产品代理 编辑:程序博客网 时间:2024/05/17 08:49

3.2.3. 向决策序列加入模式的RTL模板

对于上面我们的define_insn例子,在2467行,被传给add_to_sequence的类型是RECOG。而参数pattern是这个define_insn模式的RTL模板。对于我们的例子是:

[(set (reg 17)

       (compare(match_operand:DI 0 "nonimmediate_operand" "r,?mr")

              (match_operand:DI 1 "const0_operand""n,n")))]

 

767  static struct decision*

768  add_to_sequence(rtx pattern, struct decision_head*last,                                in genrecog.c

769                const char *position, enumroutine_type insn_type, int top)

770  {

771    RTX_CODE code;

772   struct decision*this, *sub;

773   struct decision_test*test;

774   struct decision_test**place;

775   char *subpos;

776   size_t i;

777   const char *fmt;

778    int depth = strlen (position);

779    int len;

780    enummachine_mode mode;

781 

782   if (depth > max_depth)

783     max_depth= depth;

784 

785    subpos = xmalloc (depth + 2);

786    strcpy (subpos, position);

787    subpos[depth + 1] = 0;

788 

789   sub = this = new_decision (position, last);

790   place = &this->tests;

791 

792  restart:

793   mode = GET_MODE (pattern);

794   code = GET_CODE (pattern);

795 

796   switch (code)

797   {

798     case PARALLEL:

           

819       break;

820 

821     case MATCH_PARALLEL:

          

831     case MATCH_OPERAND:

832     case MATCH_SCRATCH:

833     case MATCH_OPERATOR:

834     case MATCH_INSN:

835     {

           

915     }

916 

917     case MATCH_OP_DUP:

           

932       goto fini;

933 

934     case MATCH_DUP:

935     case MATCH_PAR_DUP:

936       code = UNKNOWN;

937 

938       test = new_decision_test (DT_dup,&place);

939       test->u.dup = XINT (pattern, 0);

940       goto fini;

941 

942     case ADDRESS:

943       pattern = XEXP (pattern, 0);

944       goto restart;

945 

946     default:

947       break;

948   }

 

当以SET码进入这个函数时,它将进入946行的default语句。在这个层次上,参数position是一个空字符串(“”)。并且注意到在789行,变量subtest指向相同的新分配的决策实例。参见下面的new_decision

 

316  static struct decision*

317  new_decision (const char *position, structdecision_head *last)                       ingenrecog.c

318  {

319   struct decision*new = xcalloc (1, sizeof (struct decision));

320 

321   new->success = *last;

322   new->position = xstrdup (position);

323   new->number = next_number++;

324 

325   last->first = last->last = new;

326   return new;

327  }

 

789行,传递给new_decision的第二个参数是在make_insn_sequence2421行声明的变量head。这个新的decision从头部链入,正如下图所示。

f5

5向决策序列加入RTL模板,图1

 

add_to_sequence (continued)

 

950   fmt = GET_RTX_FORMAT (code);

951   len = GET_RTX_LENGTH (code);

952 

953   /* Do tests against the current nodefirst.  */

954    for(i = 0; i < (size_t) len; i++)

955   {

956     if (fmt[i] == 'i')

957     {

958       if (i == 0)

959       {

960         test = new_decision_test(DT_elt_zero_int, &place);

961         test->u.intval = XINT (pattern, i);

962       }

963       else if (i == 1)

964       {

965         test = new_decision_test(DT_elt_one_int, &place);

966         test->u.intval = XINT (pattern, i);

967       }

968       else

969         abort ();

970     }

971     else if (fmt[i] == 'w')

972     {

973       /* If this value actually fits in an int, wecan use a switch

974          statement here, so indicate that.  */

975       enum decision_typetype

976          = ((int) XWINT (pattern, i) == XWINT(pattern, i))

977             ? DT_elt_zero_wide_safe :DT_elt_zero_wide;

978 

979       if (i != 0)

980         abort ();

981 

982       test = new_decision_test (type,&place);

983       test->u.intval = XWINT (pattern, i);

984      }

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

986     {

987       if (i != 0)

988         abort ();

989 

990       test = new_decision_test (DT_veclen,&place);

991       test->u.veclen = XVECLEN (pattern, i);

992     }

993   }

 

在这里,我们再一次根据其格式处理模式。对于格式中的每个元素,通过new_decision_test构建了一个decision_test的实例。它定义了将要进行的测试。

 

331  static struct decision_test*                                                                          ingenrecog.c

332  new_decision_test(enum decision_typetype, struct decision_test***pplace)

333  {

334   struct decision_test**place = *pplace;

335   struct decision_test*test;

336 

337   test = xmalloc (sizeof (*test));

338   test->next = *place;

339   test->type = type;

340   *place = test;

341 

342   place = &test->next;

343   *pplace = place;

344 

345   return test;

346  }

 

上面,在这里传递给new_decision_test的第二个参数——声明在add_to_sequence790行的变量place,指向变量thistests域,这个变量是在add_to_sequence789行构建的一个decision实例,同时在make_insn_sequence2421this链入以变量head开头的链表。

这个函数看起来有点晕,让我们一步一步来看。

f6

6new_decision_test,步骤1

直到339行,我们可以得到如上图所示的数据。看到新构建的decision_test next域指向旧的decision_test。那么在440行,pplaceplacethis->tests都指向这个新节点,如下图所示。

f7

7new_decision_test,步骤2

new_decision_test的余下部分,placepplace将指向新节点的next域的地址,如下图所示。

f8

8new_decision_test,步骤3

然后对于下一个加入的节点(黄色),直到340行,我们可以得到以下图形。

f9

9new_decision_test,步骤4

最后,pplaceplace将指向这个新加入的节点(黄色)。

f10

10new_decision_test,步骤5

从这些图形,我们可以看到对于进一步加入的节点,它们将被插入到初始节点与上一个被加入节点之间。这意味着对于加入节点序列123n,我们将得到以下的列表:

Thisàtestsà1à2à3…ànà初始节点

对于我们的情形,rtx对象SET具有格式‘ee’,954993行的FOR块将不做任何事。

 

add_to_sequence (continued)

 

995   /* Now test our sub-patterns.  */

996    for(i = 0; i < (size_t) len; i++)

997   {

998     switch (fmt[i])

999     {

1000       case 'e':case 'u':

1001         subpos[depth] = '0' + i;

1002         sub = add_to_sequence(XEXP (pattern, i), &sub->success,

1003                             subpos, insn_type,0);

1004         break;

1005

1006       case 'E':

1007      {

1008        int j;

1009        for (j = 0; j < XVECLEN (pattern, i);j++)

1010             {

1011            subpos[depth] = 'a' + j;

1012            sub = add_to_sequence(XVECEXP (pattern, i, j),

1013                               &sub->success, subpos, insn_type, 0);

1014          }

1015          break;

1016       }

1017

1018       case 'i':case 'w':

1019         /* Handledabove.  */

1020         break;

1021       case '0':

1022         break;

1023

1024       default:

1025         abort ();

1026     }

1027   }

 

954行的FOR块之后,是另一个FOR块。对于我们的例子,它将进入1000行的CASE块。在1001行的subpos保存了这个递归的深度信息。它包含了形如“0123abc45ab”的信息,其中数字用于显示格式元素的序列,而字母用于显示对应某些格式(即‘E’,‘V’)的rtx向量的序列。然后为这个SET对象的两个孩子调用add_to_sequence

对于第一个孩子reg对象,在add_to_sequence中,它直接跑到fini标签处。因为其编码是REG,在1035行构建了一个新的decision_test,并在decision中,链入在其父亲的之后。而且对于我们的reg对象,其modeVOIDmode,正如我们之前看到的。

对于第二个孩子compare对象,它的处理路径与set对象相同。在1000行它为其孩子调用add_to_sequence

 

add_to_sequence (continued)

 

1029 fini:

1030   /* Insert nodestesting mode and code, if they're still relevant,

1031     before any of the nodes we may have addedabove.  */

1032   if (code != UNKNOWN)

1033   {

1034     place = &this->tests;

1035     test = new_decision_test(DT_code, &place);

1036    test->u.code = code;

1037   }

1038

1039   if(mode != VOIDmode)

1040   {

1041     place = &this->tests;

1042     test = new_decision_test(DT_mode, &place);

1043     test->u.mode = mode;

1044   }

1045

1046   /* If we didn'tinsert any tests or accept nodes, hork. */

1047   if (this->tests == NULL)

1048     abort ();

1049

1050 ret:

1051   free (subpos);

1052   return sub;

1053 }

 

现在对于在这个compare对象的第二个孩子,其编码是MATCH_OPERAND,将进入add_to_sequence中以下部分的代码。

 

add_to_sequence (continued)

 

831      caseMATCH_OPERAND:

832      caseMATCH_SCRATCH:

833      caseMATCH_OPERATOR:

834      caseMATCH_INSN:

835      {

836        constchar *pred_name;

837       RTX_CODE was_code = code;

838        int allows_const_int = 1;

839 

840        if (code == MATCH_SCRATCH)

841        {

842          pred_name ="scratch_operand";

843          code = UNKNOWN;

844        }

845        else

846        {

847          pred_name = XSTR (pattern, 1);

848          if (code == MATCH_PARALLEL)

849            code = PARALLEL;

850          else

851            code = UNKNOWN;

852        }

853 

854        if (pred_name[0] != 0)

855        {

856          test = new_decision_test(DT_pred, &place);

857          test->u.pred.name = pred_name;

858          test->u.pred.mode = mode;

859 

860          /* See if weknow about this predicate and save its number.

861            If we do, and it only accepts onecode, note that fact.

862 

863            If we know that the predicate doesnot allow CONST_INT,

864            we know that the only way thepredicate can match is if

865            the modes match (here we use thekludge of relying on the

866            fact that "address_operand"accepts CONST_INT; otherwise,

867            it would have to be a special case),so we can test the

868            mode (but we need not). This factshould considerably

869            simplify the generated code.  */

870 

871          for (i= 0; i < NUM_KNOWN_PREDS; i++)

872            if (! strcmp (preds[i].name, pred_name))

873              break;

874 

875           if (i < NUM_KNOWN_PREDS)

876           {

877             int j;

878 

879             test->u.pred.index = i;

880 

881             if (preds[i].codes[1] == 0 &&code == UNKNOWN)

882               code = preds[i].codes[0];

883 

884             allows_const_int = 0;

885             for(j = 0; preds[i].codes[j]!= 0; j++)

886               if (preds[i].codes[j] == CONST_INT)

887               {

888                 allows_const_int = 1;

889                 break;

890               }

891           }

892           else

893             test->u.pred.index = -1;

894        }

895 

896        /* Can't enforce a mode if we allowconst_int.  */

897        if (allows_const_int)

898          mode = VOIDmode;

899 

900        /* Accept theoperand, ie. record it in `operands'.  */

901        test = new_decision_test(DT_accept_op, &place);

902        test->u.opno = XINT(pattern, 0);

903 

904        if (was_code == MATCH_OPERATOR ||was_code == MATCH_PARALLEL)

905        {

906          char base = (was_code == MATCH_OPERATOR? '0' : 'a');

907          for (i= 0; i < (size_t) XVECLEN (pattern, 2); i++)

908          {

909            subpos[depth] = i + base;

910            sub = add_to_sequence(XVECEXP (pattern, 2, i),

911                           &sub->success,subpos, insn_type, 0);

912          }

913        }

914        gotofini;

915      }

 

这个代码类似于validate_pattern的那部分。当我们的例子模式通过这个函数时,我们可以得到以下的树。

f11

11:向决策序列加入RTL模板,图2

然后我们从add_to_sequence返回到make_insn_sequence。在2469行的last指向,由add_to_sequence返回的,上图中poistion域是“11”的decision

 

make_insn_sequence (continued)

 

2465   /* Find the end ofthe test chain on the last node.  */

2466   for (test =last->tests; test->next; test = test->next)

2467     continue;

2468   place = &test->next;

2469

2470   /* Skip the C testif it's known to be true at compile time. */

2471   if (truth == -1)

2472   {

2473     /* Need a newnode if we have another test to add.  */

2474     if (test->type == DT_accept_op)

2475     {

2476       last = new_decision(c_test_pos, &last->success);

2477       place = &last->tests;

2478     }

2479     test = new_decision_test(DT_c_test, &place);

2480     test->u.c_test = c_test;

2481   }

2482

2483   test = new_decision_test(DT_accept_insn, &place);

2484   test->u.insn.code_number = next_insn_code;

2485   test->u.insn.lineno = pattern_lineno;

2486   test->u.insn.num_clobbers_to_add = 0;

 

2475行,truth 2418行的maybe_eval_c_test的结果。正如我们已经在genconditions中看到的,maybe_eval_c_test将返回-1,如果条件测试部分不是编译时常量。对于我们的例子,这个条件测试部分是:

"TARGET_64BIT && ix86_match_ccmode (insn,CCNOmode)"

函数ix86_match_ccmode不是编译时的常量,因此truth在这里将是-1(参见2475行)。注意到在2471行,place指向最后一个test节点next域的地址,在执行了上面的代码后,我们可以得到下面的树。

f12

12向决策序列加入RTL模板,图3

 

make_insn_sequence (continued)

 

2492   switch (type)

2493   {

2494     case RECOG:

2495       /* If this is aDEFINE_INSN and X is a PARALLEL, see if it ends

2496         with a group of CLOBBERs of (hard)registers or MATCH_SCRATCHes.

2497         If so, set up to recognize the patternwithout these CLOBBERs.  */

2498

2499       if (GET_CODE (x) == PARALLEL)

2500       {

2501         int i;

2502

2503         /* Find the last non-clobber in the parallel.  */

2504        for(i = XVECLEN (x, 0); i > 0; i--)

2505         {

2506           rtx y = XVECEXP (x, 0, i - 1);

2507           if (GET_CODE(y) != CLOBBER

2508              || (GET_CODE (XEXP (y, 0)) != REG

2509              && GET_CODE (XEXP (y, 0)) !=MATCH_SCRATCH))

2510             break;

2511         }

2512

2513         if (i != XVECLEN (x, 0))

2514         {

2515           rtx new;

2516           structdecision_head clobber_head;

2517

2518           /* Build asimilar insn without the clobbers.  */

2519           if (i == 1)

2520             new = XVECEXP (x, 0, 0);

2521           else

2522           {

2523             intj;

2524

2525             new = rtx_alloc (PARALLEL);

2526             XVEC (new, 0) = rtvec_alloc (i);

2527             for (j = i -1; j >= 0; j--)

2528               XVECEXP (new, 0, j) = XVECEXP (x, 0,j);

2529           }

2530

2531           /* Recognizeit.  */

2532           memset (&clobber_head, 0, sizeof(clobber_head));

2533           last = add_to_sequence(new, &clobber_head, "", type, 1);

2534

2535           /* Find the end ofthe test chain on the last node.  */

2536           for (test =last->tests; test->next; test = test->next)

2537             continue;

2538

2539           /* We definitelyhave a new test to add -- create a new

2540             node if needed.  */

2541           place = &test->next;

2542           if(test->type == DT_accept_op)

2543           {

2544             last = new_decision ("",&last->success);

2545             place= &last->tests;

2546           }

2547

2548           /* Skip the C testif it's known to be true at compile

2549             time. */

2550           if (truth == -1)

2551           {

2552             test =new_decision_test (DT_c_test, &place);

2553            test->u.c_test = c_test;

2554           }

2555

2556           test = new_decision_test(DT_accept_insn, &place);

2557           test->u.insn.code_number = next_insn_code;

2558           test->u.insn.lineno = pattern_lineno;

2559           test->u.insn.num_clobbers_to_add = XVECLEN(x, 0) - i;

2560

2561           merge_trees(&head, &clobber_head);

2562         }

2563       }

2564       break;

2565

2566     case SPLIT:

2567       /* Define thesubroutine we will call below and emit in genemit.  */

2568       printf ("extern rtx gen_split_%d(rtx *);/n", next_insn_code);

2569       break;

2570

2571     casePEEPHOLE2:

2572       /* Define thesubroutine we will call below and emit in genemit.  */

2573       printf ("extern rtx gen_peephole2_%d(rtx, rtx *);/n",

2574             next_insn_code);

2575       break;

2576   }

2577

2578   return head;

2579 }

 

对于我们的例子模式,其类型是RECOG,并且其编码是SET,因此在函数余下部分不做任何事。

回到main,在make_insn_sequence返回了这棵树的根节点后,这个根节点作为第二个参数传递给merge_trees。我们的例子模式是i386.md中的第一个define_insn模式,因此recog_tree全是0,并在1407行返回。

为了更贴近地看merge_trees可以为我们做什么,我们需要另一个模式。在i386.md里,跟着我们例子的下一个define_insn模式是:

 

497  (define_insn "*cmpdi_minus_1_rex64"

498     [(set (reg 17)

499       (compare (minus:DI (match_operand:DI0 "nonimmediate_operand" "rm,r")

500               (match_operand:DI1 "x86_64_general_operand" "re,mr"))

501           (const_int 0)))]

502  "TARGET_64BIT&& ix86_match_ccmode (insn, CCGOCmode)"

503  "cmp{q}/t{%1, %0|%0, %1}"

504  [(set_attr "type" "icmp")

505  (set_attr"mode" "DI")])

 

而在make_insn_sequence处理之后,对于该模式我们可以得到以下的树。

f13

原创粉丝点击