相关疑难解决方法(0)

为什么我的处理器没有内置的BigInt支持?

据我所知,BigInts通常在大多数编程语言中实现为包含数字的数组,例如:当添加其中两个时,每个数字都是一个接一个地添加,就像我们从学校知道的那样,例如:

 246
 816
 * *
----
1062
Run Code Online (Sandbox Code Playgroud)

其中*表示存在溢出.我在学校这样学习,所有BigInt添加函数我已经实现了类似于上面例子的工作.

所以我们都知道我们的处理器只能本地管理从0到2^32/的整数2^64.

这意味着大多数脚本语言为了高级并提供具有大整数的算术,必须实现/使用BigInt库,这些库使用整数作为上面的数组.但当然这意味着它们将比处理器慢得多.

所以我问自己的是:

  • 为什么我的处理器没有内置的BigInt功能?

它可以像任何其他BigInt库一样工作,只是(很多)更快,更低一级:处理器从缓存/ RAM中取一个数字,添加它,然后再将结果写回来.

对我来说似乎是一个好主意,为什么不是那样的?

processor biginteger cpu-architecture

10
推荐指数
2
解决办法
803
查看次数

符号运算符号幅度大整数

我在Delphi中编写一个简单的BigInteger类型.此类型由无符号32位整数数组(我称之为四肢),计数(或大小)和符号位组成.数组中的值被解释为绝对值,因此这是符号幅度表示.这有几个优点,但有一个缺点.

像位运算and,or,xornot有补语义.如果两个BigIntegers都具有正值,则这是没有问题的,但是负BigIntegers 的大小必须通过否定转换为二的补码.这可能是一个性能问题,因为如果我们这样做,比方说

C := -A and -B;
Run Code Online (Sandbox Code Playgroud)

然后我必须否定的大小AB在之前and就可以执行操作.由于结果也应该是否定的,我必须否定结果,以便再次获得正数.对于较大的BigIntegers,否定最多三个值可能是相当大的性能成本.

请注意,我知道如何做到这一点并且结果是正确的,但我想避免由大数组的必要否定引起的缓慢.

例如,我知道一些快捷方式

C := not A;
Run Code Online (Sandbox Code Playgroud)

可以通过计算来实现

C := -1 - A;
Run Code Online (Sandbox Code Playgroud)

这就是我做的,结果很好.这使得not性能与加法或减法相同,因为它避免了操作之前(和之后)的否定.

我的问题是:是否有类似的法律我可以用来避免否定"负面" BigInteger的大小?我的意思是not通过使用减法来计算?

我的意思是简单或不那么简单的法律

not A and not B = not (A or B) // = is Pascal for ==
not A or not B = not (A and B)
Run Code Online (Sandbox Code Playgroud)

但后来为-A和/或-B等我知道

(-A and …
Run Code Online (Sandbox Code Playgroud)

delphi bit-manipulation

8
推荐指数
1
解决办法
443
查看次数

在长模式下使用64/32位寄存器可能会有任何处罚吗?

可能这甚至都不是微观但纳米优化,但主题让我感兴趣,我想知道在长模式下使用非本机寄存器大小时是否存在任何惩罚?

我从各种来源了解到,部分寄存器更新(比如ax代替eax)会导致eflags停顿并降低性能.但我不确定长模式.对于此处理器操作模式,哪个寄存器大小被视为原生?x86-64仍然是x86架构的扩展,因此我相信32位仍然是原生的.还是我错了?

例如,像

sub eax, r14d
Run Code Online (Sandbox Code Playgroud)

要么

sub rax, r14
Run Code Online (Sandbox Code Playgroud)

具有相同的尺寸,但在使用其中任何一种时可能会有任何处罚吗?在如下连续指令中混合寄存器大小时可能会有任何处罚吗?(假设高dword在所有情况下均为零)

sub ecx, eax
sub r14, rax
Run Code Online (Sandbox Code Playgroud)

optimization x86 assembly micro-optimization

8
推荐指数
1
解决办法
186
查看次数

对象如何在汇编级别的x86中工作?

我试图了解对象如何在汇编级别工作.对象如何存储在内存中,以及成员函数如何访问它们?

(编者注:原始版本过于宽泛,并且首先对装配和结构的工作方式产生了一些困惑.)

c++ x86 assembly

6
推荐指数
2
解决办法
6558
查看次数

什么是局部标志失速?

我刚刚查看了彼得·科德斯(Peter Cordes)的回答,他说,

如果读取标志,则部分标志停顿会发生,如果它们确实发生的话。P4永远不会有部分标志停顿,因为它们永远不需要合并。相反,它具有错误的依赖关系。几个答案/评论混淆了术语。它们描述了一个错误的依赖关系,但随后将其称为部分标志停顿。这是由于仅写入一些标志而导致的速度下降,但是术语“部分标志停顿”是指必须合并部分标志写入时在SnB之前的Intel硬件上发生的情况。英特尔SnB系列CPU插入一个额外的uop来合并标志而不会停顿。Nehalem和更早的失速约7个周期。我不确定AMD CPU会受到多大的损失。

我感觉我还不明白什么是“部分国旗摊位”。我怎么知道一个人发生了?除了读取标志的某些时间之外,什么触发事件?合并标志是什么意思?在什么情况下会“写一些标志”,但不会发生部分标志合并?我需要了解哪些有关旗位的知识才能理解它们?

x86 assembly

6
推荐指数
1
解决办法
291
查看次数

优化第 7 代英特尔酷睿视频 RAM 中递增的 ASCII 十进制计数器

我正在尝试针对特定的 Kaby Lake CPU (i5-7300HQ) 优化以下子例程,理想情况下,与原始形式相比,代码速度至少快 10 倍。该代码在 16 位实模式下作为软盘式引导加载程序运行。它在屏幕上显示一个十位数的十进制计数器,从 0 - 9999999999 计数然后停止。

我查看了 Agner 的微体系结构汇编优化指南、 指令性能表和英特尔的优化参考手册

到目前为止,我能够做的唯一明智的优化是将loop指令交换为dec + jnz在此处进行解释。

另一种可能的优化可能是交换lodsbfor mov + dec,但我发现的关于它的信息一直存在冲突,有些人说它有一点帮助,而另一些人则认为它实际上可能会损害现代 CPU 的性能。

我还尝试切换到 32 位模式并将整个计数器保留在一个未使用的寄存器对中以消除任何内存访问,但在读入一点后我意识到这十位将立即被缓存,并且 L1 缓存之间的延迟差异和寄存器只有大约三倍,所以绝对不值得以这种格式使用计数器的额外开销。

(编者注:add reg延迟为 1 个周期,add [mem]延迟约为 6 个周期,包括 5 个周期的存储转发延迟。如果[mem]像视频 RAM 那样不可缓存,则更糟。)

org 7c00h

pos equ 2*(2*80-2)  ;address on screen

;init
cli
mov ax,3
int 10h
mov …
Run Code Online (Sandbox Code Playgroud)

optimization x86 assembly intel bootloader

6
推荐指数
1
解决办法
258
查看次数

汇编语言(x86):如何创建循环来计算Fibonacci序列

我正在使用Visual Studio 2013 Ultimate在MASM中编写汇编语言(x86).我试图使用数组来计算使用数组的n个元素的Fibonacci序列.换句话说,我试图去一个数组元素,获取它之前的两个元素,添加它们,并将结果存储在另一个数组中.

我无法设置索引寄存器以使其工作.

我的程序设置如下:

TITLE fibonacci.asm

INCLUDE Irvine32.inc

.data
    fibInitial  BYTE 0, 1, 2, 3, 4, 5, 6
    fibComputed BYTE 5 DUP(0)

.code
main PROC

    MOVZX si, fibInitial
    MOVZX di, fibComputed
    MOV   cl, LENGTHOF fibInitial

L1:
    MOV   ax, [si - 1]
    MOV   dx, [si - 2]
    MOV   bp, ax + dx
    MOV   dl, TYPE fibInitial
    MOVZX si, dl
    MOV   [edi], bp
    MOV   dh, TYPE fibComputed
    MOVZX di, dl
    loop L1

exit
main ENDP
END main
Run Code Online (Sandbox Code Playgroud)

我无法编译这个,因为该行的错误消息"错误A2031:必须是索引或基址寄存器" MOV ebp, …

x86 assembly masm irvine32

5
推荐指数
1
解决办法
2万
查看次数

x86_64 - 汇编 - 循环条件和乱序

不是要求基准.

(如果是这样的话,我会自己做的.)


我的问题:

为方便起见,我倾向于避免间接/索引寻址模式.

作为替代,我经常使用立即,绝对或寄存器寻址.

代码:

; %esi has the array address. Say we iterate a doubleword (4bytes) array.
; %ecx is the array elements count
(0x98767) myloop:
    ... ;do whatever with %esi
    add $4, %esi
    dec %ecx
    jnz 0x98767;
Run Code Online (Sandbox Code Playgroud)

在这里,我们有一个序列化的组合(dec和jnz),它可以防止正常的乱序执行(依赖).

有没有办法避免/破坏dep?(我不是装配专家).

assembly loops x86-64 conditional-statements

4
推荐指数
1
解决办法
1070
查看次数

装配ADC(附带进位)

mov eax, ptr_to_num1 ; little endian
mov ebx, ptr_to_num2 ; little endian
xor ecx, ecx
xor edx, edx
clc
bytes_addition:
    mov dl, byte [eax+ecx] ; byte from shortest
    adc dl, byte [ebx+ecx]
    mov byte [eax+ecx], dl
    inc ecx
    cmp ecx, 4 ; counter, 
    jl bytes_addition
Run Code Online (Sandbox Code Playgroud)

考虑一下

EAX:4F2252FF(大端)

EBX:00DFFC00(大端)

这个添加的结果是错误的:50024fff(大端).它应该是50024eff.看起来进位标志受到影响,但为什么呢?

assembly adc

4
推荐指数
1
解决办法
644
查看次数

增加指针比执行"mov [pointer + 1],eax"更快吗?

假设我们想在EDI存储一个字符串.以这种方式存储它会更快吗?

mov byte [edi],0
mov byte [edi+1],1
mov byte [edi+2],2
mov byte [edi+3],3
...
Run Code Online (Sandbox Code Playgroud)

还是这样?

mov byte [edi],0
inc edi
mov byte [edi],1
inc edi
mov byte [edi],2
inc edi
mov byte [edi],3
inc edi
...
Run Code Online (Sandbox Code Playgroud)

有些人可能会在小端看到以下内容:

mov dword [edi],0x3210
Run Code Online (Sandbox Code Playgroud)

或者以下是big-endian:

mov dword [edi],0x0123
Run Code Online (Sandbox Code Playgroud)

但这不是我的问题.我的问题是,增加指针然后执行mov需要更多指令是否更快,或者更快地在每个mov指令中指定添加到EDI指向的偏移地址的数量?如果后者为真,那么在将多少个具有相同数字的mov指令添加到偏移地址之后,是否值得将该数量添加到指针?换句话说,就是这样

mov byte [edi+5],0xFF
mov byte [edi+5],0xFF
mov byte [edi+5],0xFF
mov byte [edi+5],0xFF
Run Code Online (Sandbox Code Playgroud)

比这更快?

add edi,5
mov byte [edi],0xFF
mov byte [edi],0xFF
mov byte [edi],0xFF
mov byte [edi],0xFF
Run Code Online (Sandbox Code Playgroud)

x86 assembly

4
推荐指数
1
解决办法
752
查看次数

如何让BSR指令在64位上工作?

我正在尝试找到无符号 64 位 int 的前导位。我正在使用 BSR,因为我的处理器没有 LZCNT 指令。我的问题是,一旦输入正好是 2^32,它就会返回 2^64 作为前导位值,然后循环返回输出,直到 2^64。

这是我的代码:

unsigned long int LeadingBit(unsigned long int a) {
  if(a==0)
    return 0;
  unsigned long int nlb;
  asm (
       "BSR %1, %0   \n"
       : "=r" (nlb)
       : "mr" (a)
       : "cc"
       );
  return 1<<nlb;

}
Run Code Online (Sandbox Code Playgroud)

这段代码的目的是能够输入一个64位整数,并让它返回前导1的位置的值。例如:a = 65(1000001)返回1000000。

assembly g++ x86-64 inline-assembly

4
推荐指数
1
解决办法
3237
查看次数

汇编:增加2(或更大数字)而不破坏ADC循环中的CF?

我试图在Windows中测试TDM-GCC 64位汇编中的附加功能.我在前一段时间搜索了资源,我遇到了类似的代码(我做了一些修改,在TDM-GCC中编译它).

typedef struct
{
    int size;
    __uint64_t uints[130];
} BigInteger;

void add(BigInteger *X, BigInteger *Y);   // X += Y
    // %rcx holds address of X, and %rdx holds address of Y apparently.

    // calc.s - assembly file
    .globl add
add:
    movq    8(%rdx), %rax
    addq    %rax, 8(%rcx)
    movq    16(%rdx), %rax
    adcq    %rax, 16(%rcx)
    movq    24(%rdx), %rax
    adcq    %rax, 24(%rcx)
    ...     ...
Run Code Online (Sandbox Code Playgroud)

第一个汇编代码有效.不利的是,只要计算最大尺寸就需要很小的数字.所以我改为检查X和Y的大小并设置一个大小条件的循环,这样如果X和Y不大,它就不会总是添加整个数组.

    ...
// %r13 holds X addr, %r14 holds Y addr.
    addq    $8, %r13   // I have tried  incq …
Run Code Online (Sandbox Code Playgroud)

assembly x86-64 bigint extended-precision tdm-gcc

3
推荐指数
1
解决办法
97
查看次数