Next: Pattern Ordering, Previous: Constraints, Up: Machine Desc
这里有一个在编译器的RTL生成过程中有意义的指令名称表,在指令模式中给定这些名字中的一个,则告诉RTL生成过程,其可以使用该指令模式来完成一个特定的任务。
如果操作数0为一个寄存器的subreg,机器模式为m,寄存器自己的机器模式比m更宽,则该指令的效果是将指定的值存储在寄存器的对应于机器模式m的部分。m之外,且与subreg在同一个目标字中的位,为未定义。目标字以外的位保持不变。
这类指令模式有几处特别的地方。首先,每个这些直到整字大小的名字,包括整字大小的,必须被定义,因为没有其它方式来从一个地方将数据复制到另一个地方。如果有接受更大机器模式的操作数的指令模式,则必须为那些大小的整数机器模式定义‘movm’。
第二,这些指令模式不仅用在RTL生成过程。甚至重载过程可以生成move insn将值从栈槽复制到临时寄存器中。当这样的时候,其中一个操作数为硬件寄存器,另一个为需要被重载到寄存器中的操作数。
因此,当给定这样一对操作数时,指令模式必须生成不需要重载,并且不需要临时寄存器的RTL。例如,如果你使用一个define_expand来支持该指令模式,则这种情况下,define_expand一定不能调用force_reg或者任何其它可能生成新的伪寄存器的函数。
甚至对于在RISC机器上的子字机器模式,从内存中获取这些机器模式通常需要多个insn和一些临时变量,该要求也存在。
重载过程中,具有无效地址的内存引用可以被作为操作数。这样的地址将在重载过程的后面被替换成有效地址。这种情况下,可能对地址没有做任何事情,而只是使用它。如果其被复制,则将无法使用有效的地址进行替换。不要尝试将这样的地址变成有效的地址。注意,general_operand当应用到这样的地址的时候将会失败。
全局变量reload_in_progress(其必须被显式的声明)可以用来确定是否需要这样的特殊的处理。
需要进行重载的操作数的种类取决于机器描述的其余部分,不过通常在RISC机器上,只有那些没有获得硬件寄存器的伪寄存器,而在其它机器上,显式的内存引用也有可能需要进行重载。
如果一个scratch寄存器,被需要用来将一个对象与内存之间进行移送,则其可以活跃分析之前,使用gen_reg_rtx来进行分配。
如果在重载过程中,或者之后,有需要scratch寄存器的情况,则你必须提供一个适当的secondary_reload目标钩子。
宏can_create_pseudo_p可以用来确定创建一个新的伪寄存器是否不安全。如果该变量为非零,则调用gen_reg_rtx来分配一个新的伪寄存器是不安全的。
‘movm’上的约束必须允许将任何硬件寄存器移送到任何其它硬件寄存器上,假设HARD_REGNO_MODE_OK在两个寄存器上都允许机器模式m,并且REGISTER_MOVE_COST应用到它们的类别上返回值2。
必须提供浮点‘movm’指令,用于任何可以存放定点值的寄存器,因为联合体和结构体(具有机器模式SImode或DImode)可以在那些寄存器中,并且它们可以具有浮点成员。
还需要支持定点‘movm’指令,用于浮点寄存器。不幸的是,我忘了为什么要这样,并且不知道这是否还是真的。如果HARD_REGNO_MODE_OK排斥在浮点寄存器中的定点值,则定点‘movm’指令的约束必须被设计成,避免尝试重载到一个浮点寄存器。
secondary_reload废弃。
类似‘movm’,不过用于当需要使用scratch寄存器在操作数0和操作数1之间移送的时候。操作数2描述scratch寄存器。参见Register Classes中对SECONDARY_RELOAD_CLASS宏的讨论。
这些指令模式中的match_operand的形式,有一些特殊的限制。首先,只有重载操作数的断言才被检查,即reload_in检查操作数1,而不检查操作数0和2。第二,在约束中只能有一个可选项。第三,约束只能使用单个寄存器类别字母;后续的约束字母都被忽略。一个例外是,空的约束字符串匹配ALL_REGS寄存器类别。这可以减轻后端为这些指令模式定义ALL_REGS约束字母的负担。
subreg,且寄存器的自然机器模式是较宽的,则‘movstrictm’指令保证不会修改属于机器模式m之外的寄存器的任何部分。
该指令模式用于向量化,当展开MISALIGNED_INDIRECT_REF表达式的时候。
只有当目标机器确实具有这样指令的时候才定义该指令模式;如果将内存加载到连续寄存器的最有效的方式,是每次加载一个,则 不用定义该指令模式。
在一些机器上,对于哪些连续寄存器可以存储到内存中,会有一些限制,例如特定的起始寄存器或者结尾寄存器的编号,或者一个有效范围。对于那些机器,使用define_expand (参见Expander Definitions),并当不符合限制的时候,将指令模式变成失败。
将生成的insn写成一个parallel,其元素为一个从适当内存位置到寄存器的set(可能还需要use或元素clobber)。使用match_parallel (参见RTL Template)来识别insn。关于使用该insn模式的例子,可以参见rs6000.md。
N个元素)。第一个输入向量的高N/2个元素被第二个输入向量的高N/2个元素交错的插入。
N个元素)。第一个输入向量的低N/2个元素被第二个输入向量的低N/2个元素交错的插入。
PUSH_ROUNDING被定义时,才被使用。出于历史原因,该指令模式可以缺失,这种情况下使用mov扩展来替代,并用MEM表达式来形成压栈运算。mov扩展方法不被推荐。
NaN,则没有明确指定哪个操作数作为结果返回。
HImode的操作数1和2相乘,并将SImode乘积放在操作数0中。
换句话说,maddmn4类似于mulmn3,只不过其还加上操作数3。
这些指令不允许执行FAIL。
maddmn4,只不过零扩展乘法操作数,而不是有符号扩展它们。
maddmn4,不过所有的运算都必须是有符号饱和的。
umaddmn4,不过所有的运算都必须是无符号饱和的。
换句话说,msubmn4类似于mulmn3,只不过其还减去操作数3。
这些指令不允许执行FAIL。
msubmn4,不过零扩展乘法操作数,而不是有符号扩展它们。
msubmn4,不过所有的运算都必须是有符号饱和的。
umsubmn4,不过所有的运算都必须是无符号饱和的。
对于具有同时产生商和余数的指令的机器,提供‘divmodm4’指令模式,但不要提供‘divm3’ 和 ‘modm3’。这使得当商和余数都被计算的时候,可以优化成相对常见的情况。
如果存在只产生商或者余数的指令,并且比都产生的指令更有效,则将‘divmodm4’的输出例程写成调用find_reg_note,查看商或者余数的REG_UNUSED注解,来产生适当的指令。
TARGET_SHIFT_TRUNCATION_MASK来指定。参见TARGET_SHIFT_TRUNCATION_MASK. 操作数2总是一个标量类型。
ashlm3指令。操作数2总是一个标量类型。
sqrt内建C函数,总是使用对应于C数据类型double的机器模式,sqrtf内建函数使用对应于C数据类型float的机器模式。
fmod内建C函数总是使用对应于C数据类型double的机器模式,fmodf内建函数使用对应于C数据类型float的机器模式。
remainder内建C函数总是使用对应于C数据类型double的机器模式,remainderf内建函数使用对应于C数据类型float的机器模式。
cos内建C函数总是使用对应于C数据类型double的机器模式,cosf内建函数使用对应于C数据类型float的机器模式。
sin内建C函数总是使用对应于C数据类型double的机器模式,sinf内建函数使用对应于C数据类型float的机器模式。
exp内建C函数总是使用对应于C数据类型double的机器模式,expf内建函数使用对应于C数据类型float的机器模式。
log内建C函数总是使用对应于C数据类型double的机器模式,logf内建函数使用对应于C数据类型float的机器模式。
pow内建C函数总是使用对应于C数据类型double的机器模式,powf内建函数使用对应于C数据类型float的机器模式。
atan2内建C函数总是使用对应于C数据类型double的机器模式,atan2f内建函数使用对应于C数据类型float的机器模式。
floor内建C函数总是使用对应于C数据类型double的机器模式,floorf内建函数使用对应于C数据类型float的机器模式。
trunc内建C函数总是使用对应于C数据类型double的机器模式,truncf内建函数使用对应于C数据类型float的机器模式。
round内建C函数总是使用对应于C数据类型double的机器模式,roundf内建函数使用对应于C数据类型float的机器模式。
ceil内建C函数总是使用对应于C数据类型double的机器模式,ceilf内建函数使用对应于C数据类型float的机器模式。
nearbyint内建C函数总是使用对应于C数据类型double的机器模式,nearbyintf内建函数使用对应于C数据类型float的机器模式。
rint内建C函数总是使用对应于C数据类型double的机器模式,rintf内建函数使用对应于C数据类型float的机器模式。
copysign内建C函数总是使用对应于C数据类型double的机器模式,copysignf内建函数使用对应于C数据类型float的机器模式。
ffs内建C函数总是使用对应于C数据类型int的机器模式。
CLZ_DEFINED_VALUE_AT_ZERO (参见Misc)宏定义了结果是否为未定义或者一个有用的值。m为操作数0的机器模式;操作数1的机器模式由指令模式指定,编译器会在生成指令之前,将操作数转成该机器模式。
CTZ_DEFINED_VALUE_AT_ZERO (参见Misc)宏定义了结果是否为未定义或者一个有用的值。m为操作数0的机器模式;操作数1的机器模式由指令模式指定,编译器会在生成指令之前,将操作数转成该机器模式。
(set (cc0) (compare (match_operand:m 0 ...)
(match_operand:m 1 ...)))
(set (cc0) (match_operand:m 0 ...))
‘tstm’指令模式不应该为不使用(cc0)的机器定义。这样做会使得编译器变得迷惑,因为其将会不清楚哪一个set操作为比较。应该使用‘cmpm’。
Pmode的mem:BLK。
要移动的字节数为第三个操作数,机器模式为m。通常,你会将m指定为word_mode。然而,如果你可以生成更好的代码,知道有效长度的范围比一整个字要小,则你应该提供一个指令模式,其机器模式对应于你可以更有效的处理的值的范围(例如,QImode对于范围0–127;注意我们回避了负数),并且一个使用word_mode的指令模式。
第四个操作数为已知的源和目的的共享对齐,形式为一个const_int rtx。因此,如果编译器知道源和目的都是字对齐的,则其可以为该操作数提供值4。
可选的操作数5和6,分别指定了期望的对齐方式和块的大小。期望的对齐方式不同于操作数4中的对齐方式,块并不要求所有的情况下都按照这样对齐。期望的对齐方式也是以字节为单位,类似于操作数4。期望的大小,当不知道的时候,被设置为(const_int -1)。
描述多个movmemm指令模式,只有当对于更小的机器模式的指令模式,对操作数1,2,4具有更少限制的时候,才会获利。注意movmemm中的机器模式m不对块中单独的被移动的数据单元的机器模式做任何限制。
这些指令模式不需要对源和目的可能重叠的情况,进行特殊的考虑。
stpcpy的语义。操作数0为输出操作数,机器模式为Pmode。目的字符串和源字符串的地址为操作数1和2,都是地址为Pmode的mem:BLK。对该指令模式的执行,应该将地址存放在操作数0中,其中NUL终结符存放在目标字符串中。
mem:BLK,其地址的机器模式为Pmode。被设置的字节的数目是第二个操作数,机器模式为m。用于初始化内存的值为第三个操作数。只支持清空内存的目标机应该拒绝任何不为常数0的值。关于对机器模式选择的讨论,参见‘movmemm’。
第四个操作数为目标的已知对齐方式,形式为const_int rtx。因此,如果编译器知道目的操作数是字对齐的,则其可以为该操作数提供值4。
可选的操作数5和6,分别指定了期望的对齐方式和块的大小。期望的对齐方式不同于操作数4中的对齐方式,块并不要求所有的情况下都按照这样对齐。期望的对齐方式也是以字节为单位,类似于操作数4。期望的大小,当不知道的时候,被设置为(const_int -1)。
对多个setmemm的使用,类似于movmemm
Pmode的mem:BLK。
第四个操作数为源和目的的已知共享的对齐方式,形式为const_int rtx。因此,如果编译器知道源和目的都是字对齐的,则其可以为该操作数提供值4。
两个指定的内存块按字节来进行比较,按照字典顺序,从每个字符串的起始处开始。指令不允许一次取多个字节,因为每个字符串都可能在第一个字节中终止,读取后面的字节可能会访问一个无效的页或者段,并产生一个缺失。该指令的效果是将值存放在操作数0中,其符号表示了比较的结果。
mem,指出字符串的第一个字符,操作数2为要查找的字符(通常为零),操作数3为一个常量,描述了字符串起始处的已知对齐方式。
如果机器描述定义了该指令模式,则其还需要定义ftrunc指令模式。
word_mode。操作数1可以具有机器模式byte_mode 或 word_mode;通常word_mode只允许用于寄存器。操作数2和3必须对word_mode有效。
RTL生成过程,生成的该指令,操作数2和3为常量,并且对于操作数2,常量不为零。
位域的值,在存放到操作数0之前,被有符号扩展为一整个字的整数。
word_mode有效)存储到操作数0中的位域,其中操作数1指定了位宽,操作数2指定了起始位。操作数0可以具有机器模式byte_mode 或 word_mode;通常word_mode只允许用于寄存器。操作数1和2必须对word_mode有效。
RTL生成过程,生成的该指令,操作数1和2为常量,并且对于操作数1,常量不为零。
操作数的机器模式不需要与被移送的操作数的相同。一些机器,例如sparc64,具有可以根据浮点条件码,条件移送整数值的指令,以及相反的指令。
如果机器没有条件移送指令,则不要定义这些指令模式。
eq, lt或leu。
当书写match_operand表达式的时候,你来指定操作数必须具有的机器模式。编译器自动的查看你使用的机器模式,并提供那个机器模式的操作数。
对于条件为真时所存储的值,其低位必须为1,不然必须为负。否则,指令就不适合,你应该从机器描述中将其去掉。你可以通过定义宏STORE_FLAG_VALUE (参见Misc),来描述哪个值被存放。如果不能找到一个用于所有‘scond’指令模式的描述,则你应该从机器描述中去掉这些操作。
这些操作可以失败,但应该只在相对不常见的情况下这样做;如果它们对于常见的情况,包括整数比较,会失败,则最好去掉这些指令模式。
如果这些操作被去掉,则编译器通常会生成,将常量复制到目标,并在将零赋值给目标的语句附近进行分支跳转。如果这样的代码比用于‘scond’模式的指令,后面跟着需要将结果转成SImode的1或者零的的指令,更有效,则你应该从机器描述中去掉‘scond’操作。
label_ref指出要跳转到的标号。如果条件码符合条件cond则跳转。
一些机器不遵循这里假设的模型,即一个比较指令,跟随一个条件跳转指令。那种情况下,‘cmpm’ (和 ‘tstm’)指令模式,应该简单的将操作数存放开,并在define_expand (参见Expander Definitions)中为条件分支操作,生成所有需要的insn。所有对扩展‘bcond’指令模式的调用,都会立即优先执行对扩展‘cmpm’或者‘tstm’的调用。
对条件代码值使用伪寄存器的,或者用于比较的机器模式取决于被测试的条件的机器,也应该使用上面的机制。参见Jump Patterns.
上面的讨论也应用在‘movmodecc’和‘scond’指令模式上。
label_ref,指出了跳转的标号。
label_ref,指出了跳转的标号。该指令模式名在所有机器上都是强制必须的。
const_int;操作数2为用作操作数的寄存器数目。
在大多机器上,操作数2没有被实际存放在RTL模式中。提供它是出于安全考虑,一些RISC机器需要将该信息放到汇编代码中;它们可以将其放在RTL中,而不是操作数1中。
操作数0应该为一个mem RTX,其地址为函数的地址。然而注意,该地址可以为一个symbol_ref表达式,即使其在目标机器上可能不是一个合法的内存地址。如果其也不是调用指令的有效参数,则该操作的指令模式应该为一个define_expand (参见Expander Definitions),其将地址放入寄存器中,并在调用指令中使用寄存器。
返回 BLKmode对象的子程序,使用‘call’ insn。
RETURN_POPS_ARGS为非零的时候。它们应该生成一个 parallel,包含函数调用和一个set,来指示对帧指针的调整。
对于RETURN_POPS_ARGS可以为非零的机器,使用这些指令模式可以增加帧指针被消除掉的函数的数目。
parallel表达式,其中每个元素都为一个set表达式,用来指示将函数返回值保存到结果块中。
该指令模式应该被定义,来支持__builtin_apply,在一些机器上,需要特殊的指令来调用一个具有任意参数的子程序,或者将返回值保存。在具有多个寄存器,可以存放一个返回值(即FUNCTION_VALUE_REGNO_P对多个寄存器都为真)的机器上,需要该指令模式。
类似‘movm’指令模式,该指令模式也在RTL生成阶段之后被使用。这种情况下,其用来支持一些机器,从函数中返回通常需要多个指令,但是某些类别的函数只需要一条指令来实现返回。通常,可以适用的函数为那些不需要保存任何寄存器或者分配栈空间的函数。
对于这样的机器,该指令模式中指定的条件,应该只有当reload_completed为非零的时候才为真,并且函数的尾声应该只为一单个指令。对于有寄存器窗口的机器,例程leaf_function_p可以用来确定是否需要对寄存器窗口压栈。
具有条件性返回指令的机器,应该将指令模式定义成
(define_insn ""
[(set (pc)
(if_then_else (match_operator
0 "comparison_operator"
[(cc0) (const_int 0)])
(return)
(pc)))]
"condition"
"...")
其中condition通常为,在‘return’指令模式中指定的相同的条件。
__builtin_return,在一些机器上,需要特殊的指令来返回一个任意类型的值。
操作数0为一个内存位置,存放使用__builtin_apply调用函数的结果;操作数1为一个parallel表达式,每个元素都是一个set表达式,指示了从结果块中恢复函数的返回值。
(const_int 0)将作为一个RTL指令模式。
SImode。
表为jump_insn中的一个addr_vec 或 addr_diff_vec。表中的元素个数为一加上上界和下界的差。
该指令模式需要两个操作数:地址或偏移量,以及一个标号,其直接位于跳转表的前面。如果宏CASE_VECTOR_PC_RELATIVE求值为一个非零值,则第一个操作数为一个偏移量,其从表的地址开始计算;否则,其为一个跳转的绝对地址。这两种情况下,第一个操作数都为Pmode。
‘tablejump’ insn总是其使用的跳转表之前的最后一个insn。其汇编代码通常不需要用到第二个操作数,但是你应该在RTL指令模式中包含它,使得跳转优化不会将表作为不可到达代码删除。
该可选的指令模式只用于合并器,通常被循环优化器使用,当启动强度消减的时候。
const_int,或者如果直到运行时才能确定,则为const0_rtx;操作数2为实际的或者估算的最大迭代数,为一个const_int;操作数3为被包含的循环数,为一个const_int(最内层循环的值为1);操作数4为如果寄存器非零,要跳转的标号。参见Looping Patterns.
该可选的指令模式应该为,具有低开销循环指令的机器定义,循环优化器会尝试修改合适的循环来利用它。如果不支持嵌套的低开销循环,则使用define_expand (参见Expander Definitions),并如果操作数3不为const1_rtx,则使得指令模式失败。类似的,如果实际的或者估算的最大迭代数目对于该指令来说太大,则使其失败。
doloop_end成套的指令,被用于需要执行一些初始化的机器,例如加载用于低开销循环指令中的特定寄存器。如果初始化insn不总是需要被生成,则使用define_expand
(参见Expander Definitions),并使其失败。
操作数0总是一个reg,并具有机器模式Pmode;操作数1可以为一个reg, mem, symbol_ref, const_int等等,也具有机器模式Pmode。
正规化一个函数指针,通常涉及到计算函数的地址,该函数指针用在间接调用中。
只有当目标机器上,对于函数指针可以有不同的值,但是当在间接调用的时候,其还是调用相同的函数的时候,才定义该指令模式。
Pmode的对象。不要在这样的机器上定义这些指令模式。
一些机器要求对栈指针的保存和恢复,进行特殊的处理。在那些机器上,根据非标准的情况来定义指令模式,使用define_expand (参见Expander Definitions)来产生要求的insn。三种保存和恢复类型:
alloca的时候。只有尾声使用被恢复的栈指针,这使得在一些机器上,可以有更简单的保存或恢复序列。
当保存栈指针时,操作数0是保存区域,操作数1是栈指针。用于分配保存区域的机器模式缺省为Pmode,不过你可以通过定义STACK_SAVEAREA_MODE宏(参见Storage Layout)来覆盖该选择。你必须指定一个整数机器模式,或者VOIDmode,如果对于特定的类型不需要保存区域(或者因为没有需要保存的,或者因为可以使用机器特定的保存区域)。操作数0为栈指针,操作数1为用于恢复操作的保存区域。如果‘save_stack_block’被定义,则操作数0一定不能为VOIDmode,因为这些保存操作数可以被任意的嵌套。
当栈指针被保存,是用于非局部goto,则保存区域为一个mem,为一个相对于virtual_stack_vars_rtx的常量偏移,其它两种情况下,保存区域为一个reg。
STACK_GROWS_DOWNWARD未定义)操作数1,来为动态分配的数据创建空间。将由此产生的指向该空间的指针存放在操作数0中。如果你是从主栈中分配空间,则可以通过生成一个insn,将virtual_stack_dynamic_rtx复制到操作数0中。如果你是从其它地方分配空间,则可以生成将该空间的位置复制到操作数0中的代码。对于后者情况,你必须确保该空间当主栈中对应的空间被释放的时候,其也被释放。
如果所有需要做的事情只是减法操作,则不用定义该指令模式。一些机器还要求其它的操作,例如栈探测,或者维护后向链。定义该指令模式除了更新栈指针之外的,来生成那些操作。
在大多上机器上,你不需要定义该指令模式,因为GCC会产生正确的代码,用来加载帧指针和静态链,恢复栈(使用‘restore_stack_nonlocal’指令模式,如果定义),并间接跳转。你只有当该代码在你的机器上不工作的情况下,才需定义该指令模式。
jmp_buf的代码。你通常不需要定义该指令模式。一个典型的,你可以需要定义该指令模式的原因是,如果某个值,例如指向全局表的指针,必须被恢复。尽管如此,还是推荐指针值如果可能(例如,给定一个标号的地址),则应被重新计算。有一单个操作数,
builtin_setjmp_setup。单个操作数为指向jmp_buf的指针。
__builtin_eh_return的方式,并且调用帧异常处理库函数会被建立。其用于处理异常返回路径所需要的非平凡的动作。
函数应该返回的异常处理的地址,被作为操作数传给该指令模式。其通常需要被指令模式复制到某个特定的寄存器或者内存位置。如果该指令模式需要确定目标调用帧的位置,则可以使用EH_RETURN_STACKADJ_RTX。
如果该指令模式没有被定义,缺省的动作为简单的将返回地址复制给EH_RETURN_HANDLER_RTX。或者宏,或者该指令模式,应该被定义,如果使用了调用帧异常处理。
使用一个序言指令模式,通常的方式为定义TARGET_ASM_FUNCTION_PROLOGUE来产生序言的汇编代码。
prologue指令模式对于执行指令调度的目标机尤其有用。
使用尾声指令模式,通常的方式为定义TARGET_ASM_FUNCTION_EPILOGUE,来产生尾声的汇编代码。
prologue指令模式对于执行指令调度的,或者它们的返回指令具有延迟槽的目标机,尤其有用。
sibcall_epilogue指令模式一定不能破坏任何用于传递的参数,或者用于传给当前函数的参数的栈槽。
典型的conditional_trap指令模式型如:
(define_insn "conditional_trap"
[(trap_if (match_operator 0 "trap_operator"
[(cc0) (const_int 0)])
(match_operand 1 "const_int_operand" "i"))]
""
"...")
不支持写预取或者局部性暗示的目标机,可以忽略操作数1和2的值。
该指令模式必须同时显示出操作数0和1被修改。
该指令模式必须产生内存栅栏指令,使得在原子操作之前的所有内存操作,都在原子操作之前发生,所有在原子操作之后的内存操作,都在原子操作之后发生。
sync_compare_and_swapmode类似,除了其比较和交换的比较部分就好像是通过cmpm来发出的。该比较只与EQ和NE分支跳转,以及setcc操作一起使用。
一些目标机确实是通过状态标记来暴露比较并交换操作的成功或失败。理想的,我们不需要一个单独的命名指令模式来利用该特性,但是合并过程无法处理具有多个set的指令模式,而这正是定义sync_compare_and_swapmode所需要的。
“nand”运算为~op0 & op1。
该指令模式必须产生内存栅栏指令,使得在原子操作之前的所有内存操作,都在原子操作之前发生,所有在原子操作之后的内存操作,都在原子操作之后发生。
如果这些指令模式没有被定义,则操作将通过一个比较并交换操作,如果定义,来构建。
该指令模式必须产生内存栅栏指令,使得在原子操作之前的所有内存操作,都在原子操作之前发生,所有在原子操作之后的内存操作,都在原子操作之后发生。
如果这些指令模式没有被定义,则操作将通过一个比较并交换操作,如果定义,来构建。
sync_old_op所对应的指令模式,除了它们返回操作之后内存位置中存在的值,而不是操作之前。
理想的情况下,该操作为一个原子交换操作,内存操作数中之前的值被复制到结果操作数中,值操作数被保存在内存操作数中。
对于能力差些的目标机,任何不为常量1的值操作数,将使用FAIL进行拒绝。这种情况下,目标机可以使用一个原子的测试并置位操作。结果操作数应该包含1,如果该位在之前被设置,或者为0,如果该位在之前被清空。内存操作数的真实内容由实现来定义。
该指令模式必须产生内存栅栏指令,使得在原子操作之前的所有内存操作,都在原子操作之前发生,所有在原子操作之后的内存操作,都在原子操作之后发生。
如果这些指令模式没有被定义,则操作将通过一个比较并交换操作,如果定义,来构建。
sync_lock_test_and_setmode设置的锁。操作数0为包含锁的内存;操作数1为存放在锁中的值。
如果目标机没有实现sync_lock_test_and_setmode的完整语义,则任何不是常量0的值操作数将使用FAIL来拒绝,内存操作数的真实内容由实现来定义。
该指令模式必须产生内存栅栏指令,使得在原子操作之前的所有内存操作,都在原子操作之前发生,所有在原子操作之后的内存操作,都在原子操作之后发生。
如果这些指令模式没有被定义,则会产生一个memory_barrier指令模式,紧跟一个将值存储到内存操作数的操作。
Pmode值移送到内存操作数0中,并在之后不将该值留在寄存器中。这避免在某处泄露该值,从而使得攻击者用来重写栈保护槽。
如果该指令模式没有被定义,则生成一个普通的move指令模式。
Pmode值,在之后不将该值留在寄存器中,并且如果值不等,则分支跳转到操作数2。
如果该指令模式没有被定义,则使用一个普通的比较和条件分支指令模式。
如果该指令模式没有被定义,则使用对库函数__clear_cache的一个调用。