展开 y86 循环

Posted

技术标签:

【中文标题】展开 y86 循环【英文标题】:Unrolling y86 loop 【发布时间】:2016-10-26 01:37:24 【问题描述】:

我正在尝试在 y86 代码中展开循环,但是当我尝试运行测试程序时,我得到了 2 个不同的值。注册。代码是:

    xorq %rax,%rax      # count = 0;
    andq %rdx,%rdx      # len <= 0?
    jle Done        # if so, goto Done:

Loop:   
    mrmovq (%rdi), %r10 # read val from src...
    rmmovq %r10, (%rsi) # ...and store it to dst
    andq %r10, %r10     # val <= 0?
    jle Npos        # if so, goto Npos:
    #irmovq $1, %r10
    #addq %r10, %rax        
    iaddq $1, %rax      # count++
Npos:   
    irmovq $1, %r10
    subq %r10, %rdx     # len--
    #irmovq $8, %r10
    #addq %r10, %rdi        
    #addq %r10, %rsi        
    iaddq $8, %rdi      # src++
    iaddq $8, %rsi      # dst++
    andq %rdx,%rdx      # len > 0?
    jg Loop         # if so, goto Loop:
Done:
    ret

我制作的展开版是:

xorq %rax,%rax      # count = 0;
    andq %rdx,%rdx      # len <= 0?
    jle Done        # if so, goto Done:

Loop:   
    mrmovq (%rdi), %r10     # read val from src…
    mrmovq 8(%rdi), %r11    # <- from class get second value
    rmmovq %r10, (%rsi)     # ...and store it to dst
    rmmovq %r11, 8(%rsi)         # store second val to dst
    andq %r10, %r10     # val <= 0?
    jle Npos            # if so, goto Npos:
    iaddq $1, %rax

Npos:   
    andq %r11, %r11 # check if src[1] <= 0
    jle Npos2       # if it is, don’t increase count
    iaddq $1, %rax

Npos2: 
    irmvoq %2, %r10
    iaddq $16, %rdi     # increase stack or base pointer to get next 2 vals
    iaddq $16, %rsi     # increase stack or base pointer to store next 2 vals
    subq %r10, %rdx     # decrease length by 2
    jge Loop            # go back into loop if length >= 2

len_cleanup:
    iaddq $2, %rdx

cleanup:
    irmovq $1, %r10
    subq %r10, %rdx
    jl Done             # if length < 0, jmp to Done, no cleanup needed
    mrmovq (%rdi), %r10     # get next val
    rmmovq %r10, (%rsi)     # move val onto stack
    andq %r10, %r10     # check if val <= 0
    jle Done            # skip count if val < 0
    iaddq $1, %rax      # same as iaddq $1, %rax

Done: 
    ret

我应该得到的结果是 2,但从展开的结果返回的结果是 3。我知道有一个额外的 iaddq 正在执行,但我不确定在哪里。我展开循环两次,以便改为检查 2 个值。

【问题讨论】:

【参考方案1】:

我刚刚修好了。我想在开始循环之前减少 %rdx 以正确展开函数。

当您不知道迭代次数是展开因子的倍数时,您需要将 do while(--i &gt;= 0); 展开为类似--i; do while(i-=2 &gt;= 0); 的内容,以确保不会过冲。

【讨论】:

以上是关于展开 y86 循环的主要内容,如果未能解决你的问题,请参考以下文章

优化编译器如何决定何时展开循环以及展开循环的程度?

Loop Unrolling 循环展开

在 MSVC C++ 中强制循环展开

展开循环有效,for循环无效[重复]

Java JIT循环展开策略?

循环展开与循环平铺