Ada语言内嵌汇编

Ada语言内嵌汇编

本文为标准文档翻译

14.1 机器码插入

包 Machine_code 提供了对Ada参考手册中描述的两种分开形式的支持:

● 机器码语句,组成了适合RM节13.8中要求的正确的表达式。
● 一个内部可调用的过程,提供了一个对一个子程序中包含的机器码指令的替代机制。

这两种特征是近似的,都与GNU C编译器中的汇编指令提供的机制密切相关。完全的理解与使用该包中提供的设施需要理解汇编指令,在“使用GNU编译器集合(GCC)”中见节“汇编指令与C表达式操作数”。

对函数asm与过程asm的调用有着如下描述的相同的语法限制与作用。两者都提供了,因此过程调用可以作为语句,函数调用可以组成代码语句(译者注:表达式)。

GCC文档中提供的第一个例子是C汇编指令:
asm(“fsinx %1 %0” : “=f” (result) : “f” (angle));

GNAT中可以等价地写成:
Asm(“fsinx %1 %0”,
My_Float’Asm_Output (“=f” , result),
My_Float’Asm_Input(“f” , angle));

Asm的第一个参数是汇编模板,这与GNU C中的用法是相同的。这个字符串必须是一个静态表达式。第二个参数是输出操作数列表。这既可以是一个单独的asm_output属性引用,也可以是由括号包含的属性引用的一个列表(技术上讲是一个这样的引用的数组集合)。

Asm_output属性指向一个包含两个参数的函数。第一个是字符串,第二个是由属性前缀指定类型的变量的名字。第一个(字符串)参数必须是一个静态表达式并且指定了对参数的约束(比如,要求什么类型的寄存器)。第二个参数是保存(被更新为)结果的变量。可能的关于约束的值与它们在RTL中的用法完全一样,且依赖于用于创建GCC后端的配置文件。如果没有输出操作数,则该参数也可以省略,或严格的给定为 No_Output_Operands 。

My_float’asm_Output函数的第二个参数好像是OUT参数(译者注:可写的参数),这有一点点好奇,所有的名字都有表达式形式,因此不存在语法不均匀性,尽管通常情况下函数将不允许OUT参数。第三个参数是输入操作数列表。它既可以是一个单独的asm_input属性引用,也可以是由括号包含的属性引用的一个列表(技术上讲是一个这样的引用的数组集合)。

Asm_input属性指向一个包含两个参数的函数。第一个是一个字符串,第二个是由属性前缀指定类型的变量的名字。第一个(字符串)参数必须是一个静态表达式并且指定了对参数的约束(比如,要求什么类型的寄存器)。第二个参数是(被用于作为)输入参数的值。可能的关于约束(译者注:原文是constant,可能是笔误)的值与它们在RTL中的用法完全一样,且依赖于用于创建GCC后端的配置文件。如果没有输入操作数,该参数可以省略或严格地给定为 No_Input_Operands 。
第四个参数,没有出现在上面的例子中,是一个寄存器名字的列表,称为破坏参数。这个参数,如果给定,必须是一个静态字符串表达式,并且用空格或一个逗号把寄存器名字隔开,这些寄存器必须被考虑到调用asm之后被破坏。如果该参数是空字符串(默认值),则代码生成器假定没有额外的寄存器被破坏(修改)。

第五个参数,没有出现在上面的例子中,称为稳定参数(volatile argument),默认为FALSE 。它可以被设置为文字值TRUE来向代码生成器表明所有关于指令的优化指派应当被抑制,尤其对一个拥有输出的指令,指令将依然被生成,即使没有输出被使用。在“使用GNU编译器集合(GCC)”中见节“汇编指令与C表达式操作数”来获取完整描述。一般地,强烈建议使用Volatile用于任意的既没有输入也没有输出的汇编语句或当2句或更多的汇编语句以序列出现时,来避免不必要的优化。如果没有遵循该建议,一条警告将生成。

Asm子程序可以以两种方法调用。第一种过程形式可以被用于任何地方且过程调用将是合法的,(过程形式)且与参考手册称为“内置的”(intrinsic)例程相对应。这样的调用可以用其它Ada语句来修饰机器指令。第二种,函数形式,将返回一个受限私有类型Asm_Insn的虚值,可以被用于代码语句,并且事实上这是上下文中这样的调用唯一可用的地方。代码语句以集合的形式出现:
Asm_Insn’(Asm(…));
Asm_Insn’(Asm_Volatile(…));

根据参考手册规则,这样的代码语句仅可以出现在体中全部包含这样的语句的子程序中。是不允许这样的语句与其它Ada语句混合的。

通常的,使用内置过程调用的形式是方便和灵活的。代码语句形式被提供用于满足手册建议关于这样的设施应当可用。下面是对asm调用的完整语法,如果使用了名字指定,参数的给定可以以任意顺序,遵循正常的使用位置和名字参数规则:
ASM_CALL ::= Asm ( [Template =>] static_string_EXPRESSION
[,[Outputs =>] OUTPUT_OPERAND_LIST ]
[,[Inputs =>] INPUT_OPERAND_LIST ]
[,[Clobber =>] static_string_EXPRESSION ]
[,[Volatile =>] static_boolean_EXPRESSION] )

OUTPUT_OPERAND_LIST ::=
[PREFIX.]No_Output_Operands
| OUTPUT_OPERAND_ATTRIBUTE
| (OUTPUT_OPERAND_ATTRIBUTE {,OUTPUT_OPERAND_ATTRIBUTE})

OUTPUT_OPERAND_ATTRIBUTE ::=
SUBTYPE_MARK’Asm_Output (static_string_EXPRESSION, NAME)

INPUT_OPERAND_LIST ::=
[PREFIX.]No_Input_Operands
| INPUT_OPERAND_ATTRIBUTE
| (INPUT_OPERAND_ATTRIBUTE {,INPUT_OPERAND_ATTRIBUTE})

INPUT_OPERAND_ATTRIBUTE ::=
SUBTYPE_MARK’Asm_Input (static_string_EXPRESSION, EXPRESSION)

标示符 No_Input_Operands 与 No_ouput_Operands声明在包 Machine_code中且必须根据正常可见性规则来引用。尤其在如果没有对该包使用use子句时,则需要相称的包名限制。

猜你喜欢

转载自blog.csdn.net/adacore/article/details/82877009