gpt4 book ai didi

c - sparc64 上 sparc 汇编代码的 unsigned long long int 问题

转载 作者:太空宇宙 更新时间:2023-11-04 03:17:45 25 4
gpt4 key购买 nike

我在下面包含 Sparc 程序集的 C 代码中遇到问题。代码在 Debian 9.0 Sparc64 上编译运行。它做一个简单的求和并打印这个总和的结果等于nLoop .

问题是对于大于 1e+9 的初始迭代次数,最后的总和系统地等于 141006540​​8 :我不明白为什么,因为我明确地输入了 unsigned long long int输入 sum变量等等 sum可以在[0, +18,446,744,073,709,551,615]范围。

例如,对于 nLoop = 1e+9 , 我期待 sum等于1e+9 .

问题是否来自无法处理 64 位变量(输入或输出)的包含的 Assembly Sparc 代码?

#include <stdio.h>
#include <stdlib.h>

int main (int argc, char *argv[])
{
int i;
// Init sum
unsigned long long int sum = 0ULL;
// Number of iterations
unsigned long long int nLoop = 10000000000ULL;

// Loop with Sparc assembly into C source
asm volatile ("clr %%g1\n\t"
"clr %%g2\n\t"
"mov %1, %%g1\n" // %1 = input parameter
"loop:\n\t"
"add %%g2, 1, %%g2\n\t"
"subcc %%g1, 1, %%g1\n\t"
"bne loop\n\t"
"nop\n\t"
"mov %%g2, %0\n" // %0 = output parameter
: "=r" (sum) // output
: "r" (nLoop) // input
: "g1", "g2"); // clobbers

// Print results
printf("Sum = %llu\n", sum);

return 0;

}

如何解决这个范围问题并允许在 Sparc 汇编代码中使用 64 位变量?

PS:我尝试用 gcc -m64 编译,问题依旧。

更新1

应@zwol 的要求,下面是生成的输出 Assembly Sparc 代码:gcc -O2 -m64 -S loop.c -o loop.s

        .file   "loop.c"
.section ".text"
.section .rodata.str1.8,"aMS",@progbits,1
.align 8
.LC0:
.asciz "Sum = %llu\n"
.section .text.startup,"ax",@progbits
.align 4
.global main
.type main, #function
.proc 04
main:
.register %g2, #scratch
save %sp, -176, %sp
sethi %hi(_GLOBAL_OFFSET_TABLE_-4), %l7
call __sparc_get_pc_thunk.l7
add %l7, %lo(_GLOBAL_OFFSET_TABLE_+4), %l7
sethi %hi(9764864), %o1
or %o1, 761, %o1
sllx %o1, 10, %o1
#APP
! 13 "loop.c" 1
clr %g1
clr %g2
mov %o1, %g1
loop:
add %g2, 1, %g2
subcc %g1, 1, %g1
bne loop
nop
mov %g2, %o1

! 0 "" 2
#NO_APP
mov 0, %i0
sethi %gdop_hix22(.LC0), %o0
xor %o0, %gdop_lox10(.LC0), %o0
call printf, 0
ldx [%l7 + %o0], %o0, %gdop(.LC0)
return %i7+8
nop
.size main, .-main
.ident "GCC: (Debian 7.3.0-15) 7.3.0"
.section .text.__sparc_get_pc_thunk.l7,"axG",@progbits,__sparc_get_pc_thunk.l7,comdat
.align 4
.weak __sparc_get_pc_thunk.l7
.hidden __sparc_get_pc_thunk.l7
.type __sparc_get_pc_thunk.l7, #function
.proc 020
__sparc_get_pc_thunk.l7:
jmp %o7+8
add %o7, %l7, %l7
.section .note.GNU-stack,"",@progbits

更新 2:

根据@Martin Rosenau 的建议,我做了以下修改:

loop:
add %g2, 1, %g2
subcc %g1, 1, %g1
bpne %icc, loop
bpne %xcc, loop
nop
mov %g2, %o1

但是在编译时,我得到:

Error: Unknown opcode: `bpne'

这个编译错误可能是什么原因?

最佳答案

subcc %%g1, 1, %%g1
bne loop

你的问题是 bne 指令:

与 x86-64 CPU 不同,Sparc64 CPU 没有不同的 32 位和 64 位减法指令:

如果你想从 0x12345678 中减去 1,结果是 0x12345677。如果您从 0xF00D12345678 中减去 1,则结果为 0xF00D12345677 因此,如果您仅使用寄存器的低 32 位,则 64 位减法与 32 位减法具有相同的效果-位减法。

因此 Sparc64 CPU 没有不同的 64 位和 32 位加法、减法、乘法、左移等指令。

当高 32 位影响低 32 位(例如右移)时,这些 CPU 对 32 位和 64 位操作有不同的指令。

然而,零标志 取决于subcc 操作的结果。

为了解决这个问题,Sparc64 CPU 将每个整数标志(零、溢出、进位、符号)都设置了两次:

如果寄存器的低 32 位为零,则设置 32 位零标志;如果寄存器的所有 64 位都为零,将设置 64 位零标志

为了与现有的 32 位程序兼容,bne 指令将检查 32 位零标志,而不是 64 位零标志。

is systematically equal to 1410065408

1e10 = 0x200000000 + 141006540​​8 所以在 141006540​​8 步之后达到值 0x200000000,其低 32 位设置为 0,bne 将不再跳转。

然而,对于 1e11,您不应该得到 141006540​​8,而是 1215752192,因为 1e11 = 0x1700000000 + 1215752192。

bne

有一个名为 bpne 的新指令,最多有 4 个参数!

在最简单的变体(只有两个参数)中,指令应该(我已经 5 年没有使用 Sparc,所以我不确定)像这样工作:

bpne %icc, loop   # Like bne (based on the 32-bit result)
bpne %xcc, loop # Like bne, but based on the 64-bit result

编辑

Error: Unknown opcode: 'bpne'

我刚刚尝试使用 GNU 汇编程序:

GNU 汇编程序将新指令命名为 bne - 就像旧指令一样:

bne loop         # Old variant
bne %icc, loop # New variant based on the 32-bit result
bne %xcc, loop # (New variant) Based on the 64-bit result
  subcc %g1, 1, %g1
bpne %icc, loop
bpne %xcc, loop
nop

第一个 bpne(或 bne)没有意义:只要第一行跳转,第二行也会跳转。如果您不使用 .reorder(但这是默认设置),您还需要在两个分支指令之间添加一个 nop...

代码应该如下所示(假设您的汇编器也命名为 bpne bne):

   subcc %g1, 1, %g1
bne %xcc, loop
nop

关于c - sparc64 上 sparc 汇编代码的 unsigned long long int 问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49801769/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com