Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Assembly 验证在一个位范围内,只有一个位处于打开状态_Assembly_X86_Bit Manipulation_X86 16_Micro Optimization - Fatal编程技术网

Assembly 验证在一个位范围内,只有一个位处于打开状态

Assembly 验证在一个位范围内,只有一个位处于打开状态,assembly,x86,bit-manipulation,x86-16,micro-optimization,Assembly,X86,Bit Manipulation,X86 16,Micro Optimization,我编写了这个算法,其中计算了三个条件位,以确定文本应如何基于给定地址对齐 7=右对齐6=中间对齐5=左对齐 目前,没有实现默认值,因此如果未定义任何内容,则返回ZF,表明未发生任何事情。不在屏幕上的预期文本也将是一个指示器 test al, 111000000B jz Done 现在这个解决方案适合我,因为作为我正在设计的ABI的一部分,CF表示错误。这满足了需要,并且适用于16/32/64位,但我想有一种更有效的方法,或者至少是一种不那么重要的

我编写了这个算法,其中计算了三个条件位,以确定文本应如何基于给定地址对齐

7=右对齐
6=中间对齐
5=左对齐

目前,没有实现默认值,因此如果未定义任何内容,则返回ZF,表明未发生任何事情。不在屏幕上的预期文本也将是一个指示器

        test    al, 111000000B
        jz      Done
现在这个解决方案适合我,因为作为我正在设计的ABI的一部分,CF表示错误。这满足了需要,并且适用于16/32/64位,但我想有一种更有效的方法,或者至少是一种不那么重要的方法

    0  0FBC46FE          bsf ax,[bp-0x2]
    4  88C3              mov bl,al
    6  0FBD46FE          bsr ax,[bp-0x2]
    A  28C3              sub bl,al
    C = 12 bytes

由于在尾声中对每种情况都有特殊的处理,我可以通过将位AH旋转到进位来捕捉它,并一直这样做直到CY和ZF。如果有进位和非零,那么我知道设置了多个位,或者我可以忽略多余的位,然后根据位位置对函数进行优先级排序。

您可能需要重新设计,在2位字段中使用3或4个值,而不是位图,如果它们都是互斥的。(关于这个问题)

屏蔽非位图位后:

一个很好的方法是使用一个整数作为2的幂。(或者实际上,为了测试它最多设置了1位,而不是完全设置了1位,因为当
n==0
时,该表达式为真)

您可以使用
lea-edx、[rax-1]
/
和edx、eax
/
add-edx、-1
来实现这一点,如果
eax
设置了超过1位,则保留CF设置,否则CF清除。(
add edx,-1
为除
0
之外的每个edx值进位)


关于具有BMI1的CPU VEX前缀在实模式或虚拟8086模式下不可用(与一些旧的实模式约定兼容,即使用以前非法的位模式作为陷阱)。但我认为它们在16位保护模式下是可用的,而且肯定是在32/64位模式下。这是相关的,因为
blsr
是用VEX前缀编码的

有一种非常有效的方法可以通过(重置最低设置位)实现该bithack,因为它以一种非常有用的方式设置标志。几乎就好像指令集架构师知道他们在做什么一样…:

and   eax, 11100000b     ; clear other bits

; requires BMI1
blsr  edx, eax           ; destination = a dummy register, also sets flags

jnz  multiple_bits_were_set       ; and thus edx still has a bit set
jc   input_was_zero
i、 e.它可以在一条指令中完成您想要的一切,甚至可以在不使用
cmc
的情况下使用CF。您的
多个\u位\u已设置
分支目标只能
stc
并落入
输入\u为零

如果(CF==1或ZF==0),则没有跳转,只有
ja
(CF=0和ZF=0)和
jbe
(CF=1或ZF=1)。我认为即使是
cmc
也帮不上忙;我们真的需要补充ZF,而不是CF。(Skylake和更高版本的CPU,最坏的情况是在Haswell上,如果您在cmc有用的地方做一些事情,它将是一个合并uop而不是一个暂停。可能使用不同的用例,因为它似乎对blsr不有用。)

您可能需要两个分支。或者,由于您可能正在对设置的位进行分支,可能只使用
blsr
检查多个位集
,然后使用
cmp al,01000000b
/
jae bits_1_或_2
将事物分为最高或第二高或最低(前3位)或无设置


如果只想为无位或太多位进行一次分支:
adc
不能换行为零,因为根据定义,
blsr
始终保持低位清零<如果BLSR后edx=0,且adc未添加任何内容,则代码>edx只能为零(因此只能设置ZF)


如果您的位掩码不包括寄存器的高位,
adc-edx,edx
也可以工作,节省一个字节。但立即为0的adc可能是,一般情况下为2个UOP。(以后的英特尔CPU总是有1个uop adc,以前的英特尔CPU没有BMI1。AMD CPU总是有1个uop adc。)

如果它们是互斥的,为什么需要3个独立的位,而不是将0..2或1..3整数编码为2位?您可以检查最高2位中是否至少有一位设置为
cmp al,00111111b
/
jna Done
。作为奖励,这将CF设置为无位设置情况。如果要在验证输入后以这种方式而不是使用cmp+ja进行分派,则可以将1..3值用作计算跳转的一部分。如果要优化代码大小,请先调试代码(使用可选检查,不管它们是否有效),然后在不使用检查的情况下构建代码。如果它仍然有效,那么您就有了一个高效的二进制文件,它不会浪费代码字节来验证应该是不变量的东西。特别是如果失败模式是无辜的,就像在设置多个时让一个位“赢”,而不是崩溃。你的目标是哪一组ISA扩展?
和ax,11100000b
/
popcnt bx,ax
/
cmp bl,1
或其他东西对您有用吗?(
popcnt
通常与SSE4.2/Nehalem一起使用)。任何VEX编码的BMI/BMI2指令都无法在16位模式下工作,但使用bithack可能仍然很好:
(n&(n-1))==0
(实际上测试最多只能有1位集,而不是1位集。)@PeterCordes相互排他性方面可能是AVR的习惯,因此,在这一点上,我从来没有一个明确的想法,我想做什么,但这确实很适合我在最后一段中提到的位转换。我认为这里最有效的方法是将位7-5移动到1-0(范围1到3),这样更有利于计算跳跃。到目前为止,只使用了另外一个位,它是一个可以屏蔽的切换,给我留下了一个明确的值,甚至可以在实模式下将向量转换为word或dword数组。@PeterCords引导和初始化到详细程度和用户交互仍在进行中,但这个例程是必不可少的
 AND   eax, mask

 blsr  edx, eax     ; edx = 0 iff no more than 1 bit was set in the input
 ; CF=1 iff eax==0
 adc   edx, 0
 jnz   not_exactly_one_bit_set