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