Gcc源代码分析,insn和rtx的关系

时间:2022-06-14 19:59:43

insn --> mov ax,8

rtx    ax

rtx    8

rtx    mov ax,8

上图可以很清楚的表示出insn和rtx的关系

    可以看出rtl就是一种抽象的汇编语言,汇编一般都是直接操作寄存器,内存地址,当然也有call

ret和jump指令。

instruction既是insn的意思就是指令,既然是指令就应该有操作数,可以是0个,可以是1个,可以是2个。




rtl.def被包含进rtl.h文件中和rtl.c文件中。这3个文件是理解rtx的insn的最好的资料。

里面有rtx的定义,insn的定义,以及怎样打印出hello.c.rtl的代码!

DEF_RTL_EXPR(CALL_INSN, "call_insn", "iuueiee")


(call_insn 7 6 9 (set (reg:SI 0)

       (call (mem:QI (symbol_ref/v:SI ("printf")))
           (const_int 4))) -1 (nil)
   (nil))


第一部分7,第二部分6,第三部分9,第四部分(set (reg:SI 0)       (call (mem:QI (symbol_ref/v:SI ("printf")))      (const_int 4)))
第五部分
-1,第六部分(nil)第七部分(nil)

当然打印任何的rtx都要先打印左括号(和rtx的名字 然后打印格式字符串对应的内容,然后是),既是右括号。


(const_int 4) 也是一个rtx,它的格式字符串为"i",长度为1,当然意义是常数的值。对应insn来说是insn的编号。

DEF_RTL_EXPR(CONST_INT, "const_int", "i")


可以下一个定义:rtx的fmt既格式化字符串前3个字符依次为"iuu"的rtx就是insn。


下面是hello.c.rtl里面一部分的内容:

(call_insn 7 6 9 (set (reg:SI 0)

       (call (mem:QI (symbol_ref/v:SI ("printf")))
           (const_int 4))) -1 (nil)
   (nil))


(insn 9 7 10 (set (reg/i:SI 0)
       (const_int 0)) -1 (nil)
   (nil))


(insn 10 9 11 (use (reg/i:SI 0)) -1 (nil)
   (nil))

(jump_insn 11 10 12 (set (pc)
       (label_ref 15)) -1 (nil)
   (nil))

(barrier 12 11 13)

(note 13 12 15 "" NOTE_INSN_FUNCTION_END)

(code_label 15 13 0 1)


下面是rtl.def的一部分内容:

DEF_RTL_EXPR(INSN, "insn", "iuueiee")

DEF_RTL_EXPR(JUMP_INSN, "jump_insn", "iuueiee0")

DEF_RTL_EXPR(CALL_INSN, "call_insn", "iuueiee")

DEF_RTL_EXPR(BARRIER, "barrier", "iuu")

DEF_RTL_EXPR(CODE_LABEL, "code_label", "iuui0")


insn是rtx的一个子集,也就是insn一定是rtx,但是rtx不一定是insn。


下面的代码能解释出为什么insn输出的顺序是,自己的编号,上一个insn的标号,下一个insn的编号。请注意下面的case:"i"和case"u"的部分!

还有上面的定义中的3个insn都是"iuu"开始的


/* Printing rtl for debugging dumps.  */

static FILE *outfile;

char spaces[] = "                                                                                                                                                                ";

static int sawclose = 0;

/* Print IN_RTX onto OUTFILE.  This is the recursive part of printing.  */

static void
print_rtx (in_rtx,file)
     register rtx in_rtx;
{
  static int indent;
  register int i, j;
  register char *format_ptr;

  if (sawclose)
    {
      fprintf (outfile, "\n%s",
           (spaces + (sizeof spaces - indent * 2)));
      sawclose = 0;
    }

  if (in_rtx == 0)
    {
      fprintf (outfile, "(nil)");
      sawclose = 1;
      return;
    }

  /* print name of expression code */
  fprintf (outfile, "(%s", GET_RTX_NAME (GET_CODE (in_rtx)));

  if (in_rtx->in_struct)
    fprintf (outfile, "/s");

  if (in_rtx->volatil)
    fprintf (outfile, "/v");

  if (in_rtx->unchanging)
    fprintf (outfile, "/u");

  if (in_rtx->integrated)
    fprintf (outfile, "/i");

  if (GET_MODE (in_rtx) != VOIDmode)
    {
      /* Print REG_NOTE names for EXPR_LIST and INSN_LIST.  */
      if (GET_CODE (in_rtx) == EXPR_LIST || GET_CODE (in_rtx) == INSN_LIST)
    fprintf (outfile, ":%s", GET_REG_NOTE_NAME (GET_MODE (in_rtx)));
      else
    fprintf (outfile, ":%s", GET_MODE_NAME (GET_MODE (in_rtx)));
    }

  format_ptr = GET_RTX_FORMAT (GET_CODE (in_rtx));

  for (i = 0; i < GET_RTX_LENGTH (GET_CODE (in_rtx)); i++)
    switch (*format_ptr++)
      {
      case 'S':
      case 's':
    if (XSTR (in_rtx, i) == 0)
      fprintf (outfile, " \"\"");
    else
      fprintf (outfile, " (\"%s\")", XSTR (in_rtx, i));
    sawclose = 1;
    break;

    /* 0 indicates a field for internal use that should not be printed.  */
      case '0':
    break;

      case 'e':
    indent += 2;
    if (!sawclose)
      fprintf (outfile, " ");
    print_rtx (XEXP (in_rtx, i));
    indent -= 2;
    break;

      case 'E':
    indent += 2;
    if (sawclose)
      {
        fprintf (outfile, "\n%s",
             (spaces + (sizeof spaces - indent * 2)));
        sawclose = 0;
      }
    fprintf (outfile, "[ ");
    if (NULL != XVEC (in_rtx, i))
      {
        indent += 2;
        if (XVECLEN (in_rtx, i))
          sawclose = 1;

        for (j = 0; j < XVECLEN (in_rtx, i); j++)
          print_rtx (XVECEXP (in_rtx, i, j));

        indent -= 2;
      }
    if (sawclose)
      fprintf (outfile, "\n%s",
           (spaces + (sizeof spaces - indent * 2)));

    fprintf (outfile, "] ");
    sawclose = 1;
    indent -= 2;
    break;

      case 'i':
    fprintf (outfile, " %d", XINT (in_rtx, i));
    sawclose = 0;

    break;

      /* Print NOTE_INSN names rather than integer codes.  */

      case 'n':
    if (XINT (in_rtx, i) <= 0)
      fprintf (outfile, " %s", GET_NOTE_INSN_NAME (XINT (in_rtx, i)));
    else
      fprintf (outfile, " %d", XINT (in_rtx, i));
    sawclose = 0;
    break;

      case 'u':
    if (XEXP (in_rtx, i) != NULL)
      fprintf(outfile, " %d", INSN_UID (XEXP (in_rtx, i)));
    else
      fprintf(outfile, " 0");

    sawclose = 0;
    break;

      default:
    fprintf (stderr,
         "switch format wrong in rtl.print_rtx(). format was: %c.\n",
         format_ptr[-1]);
    abort ();
      }

  fprintf (outfile, ")");
  sawclose = 1;
}

关于GET_RTX_LENGTH,在rtl.h里面定义

#define GET_RTX_LENGTH(CODE)        (rtx_length[(int)(CODE)])

而在init_rtl函数运行的时候就已经初始化了,比如,我们研究的call_insn的长度是strlen("iuueiee")=7。

/* This is called once per compilation, before any rtx's are constructed.
   It initializes the vector `rtx_length'.  */

void
init_rtl ()
{
  int i;

  for (i = 0; i < NUM_RTX_CODE; i++)
    rtx_length[i] = strlen (rtx_format[i]);