我在下面的C代码中遇到了一个问题,其中包括Sparc Assembly。代码在Debian 9.0 Sparc64上编译并运行。它执行简单的sumation并打印此总和的结果,该结果等于nLoop
。
问题是,对于大于1e + 9的初始迭代次数,末尾的最终总和系统地等于1410065408:我不明白为什么因为我明确unsigned long long int
类型为{{ 1}}变量,因此sum
可以在sum
范围内。
例如,对于[0, +18,446,744,073,709,551,615]
,我希望nLoop = 1e+9
等于sum
。
问题是来自包含无法处理64位变量(在输入或输出中)的Assembly Sparc代码吗?
1e+9
如何解决这个范围问题并允许将64位变量用于Sparc汇编代码?
此致
ps:我尝试用gcc -m64编译,问题仍然存在。
更新1:根据@zwol的要求,在使用以下内容生成的输出程序集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;
}
gcc -O2 -m64 -S loop.c -o loop.s
更新2:
根据@Martin Rosenau的建议,我做了以下修改:
.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
但在汇编时,我得到了:
loop:
add %g2, 1, %g2
subcc %g1, 1, %g1
bpne %icc, loop
bpne %xcc, loop
nop
mov %g2, %o1
有关此编译错误的任何线索?
答案 0 :(得分:1)
subcc %%g1, 1, %%g1 bne loop
您的问题是bne
说明:
与x86-64 CPU不同,Sparc64 CPU不具备32位和64位减法的不同指令:
如果要从0x12345678中减1,结果为0x12345677。如果从0xF00D 12345678 中减去1,则结果为0xF00D 12345677 ,因此如果仅使用寄存器的低32位,则64位减法与32具有相同的效果比特减法。
因此,Sparc64 CPU对64位和32位加法,减法,乘法,左移等没有不同的指令。
当高32位影响低32位(例如右移)时,这些CPU对32位和64位操作有不同的指令。
然而零标志取决于subcc
操作的结果。
为了解决这个问题,Sparc64 CPU有两次整数标志(零,溢出,进位,符号):
如果寄存器的低32位为零,则 32位零标志将被置位;如果寄存器的所有64位都为零,则将设置 64位零标志。
为了与现有的32位程序兼容,bne
指令将检查32位零标志,而不是64位零标志。
系统地等于1410065408
1e10 = 0x200000000 + 1410065408所以在1410065408步之后,达到值0x200000000,其中低32位设置为0,bne
不再跳转。
然而,对于1e11,您不应该得到1410065408但结果是1215752192因为1e11 = 0x1700000000 + 1215752192。
bne
有一条名为bpne
的新指令,最多有4个参数!
在最简单的变体(只有两个参数)中,指令应该(我现在已经使用Sparc 5年了,所以我不确定)是这样工作的:
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
答案 1 :(得分:0)
尝试“bne%xcc,loop”,它应根据64位结果进行分支。