Next: , Previous: Attr Example, Up: Insn Attributes


16.19.5 计算一个Insn的长度

许多机器提供了多种类型的分支指令,针对于不同长度的分支位移。多数情况下, 汇编器会选择使用正确的指令。但是,当汇编器无法做到的时候,如果一个特殊的属性, length属性,被定义,则可以由GCC来完成。 该属性必须通过在它的define_attr中指定一个空字符串, 从而被定义成具有数字值。

对于length属性,在test表达式中允许两个额外形式的算术术语:

(match_dup n)
这是指当前insn的操作数n的地址,其必须为一个label_ref


(pc)
这是指当前insn的地址。或许可以将其设为下一个insn的地址, 从而跟其它地方的用法一致,但是这样容易引起混淆,因为还要计算当前insn的长度。

对于通常的insn,长度将由length属性的值来确定。 对于addr_vecaddr_diff_vec的insn模式, 长度通过向量数乘于每个向量的大小来计算获得。

长度按照可寻址的存储单元(字节)来度量。

下列宏可以用于改进长度计算:

ADJUST_INSN_LENGTH (insn, length)
如果定义,则在上下文中作为函数来使用,用于修改赋予指令insn的长度。 length为一个lvalue(左值)包含了最初计算的insn长度并将使用insn的正确长度来更新。

该宏通常并不需要。一种使用它的情况为ROMP。在这个机器上, 一个addr_vec insn的大小必须被加2用于补偿可能需要的指令对齐。

返回get_attr_lengthlength属性的值)的程序, 可以被输出程序用来确定将要写入的分支指令的形式,正如下面的例子。

作为一个指定可变长度分支的例子,可以考虑一下IBM360。 如果我们采用寄存器将被设为函数起始地址这样的约定, 我们则可以使用一个4字节的指令来跳转到4K范围的标号。 否则,我们需要一个6字节的序列来从内存加载地址并然后分支到那里。

对于这样的机器,可以按照如下的方式来指定一个分支指令模式:

     (define_insn "jump"
       [(set (pc)
             (label_ref (match_operand 0 "" "")))]
       ""
     {
        return (get_attr_length (insn) == 4
                ? "b %l0" : "l r15,=a(%l0); br r15");
     }
       [(set (attr "length")
             (if_then_else (lt (match_dup 0) (const_int 4096))
                           (const_int 4)
                           (const_int 6)))])