我正在阅读K&R的"The C Programming Language"并且发现了这个声明[Introduction,p.3]:
由于大多数计算机都直接支持C提供的数据类型和控制结构,因此实现自包含程序所需的运行时库很小.
粗体陈述是什么意思?是否存在计算机不直接支持的数据类型或控制结构的示例?
我在我的C++代码的内部循环中使用了128位整数计数器.(不相关背景:实际应用是评估规则网格上的有限差分方程,其中涉及重复递增大整数,甚至64位也不够精确,因为小的舍入累积足以影响答案.)
我将整数表示为两个64位无符号长整数.我现在需要将这些值递增128位常数.这并不难,但你必须手动捕捉低字到高字的进位.
我有这样的工作代码:
inline void increment128(unsigned long &hiWord, unsigned long &loWord)
{
const unsigned long hiAdd=0x0000062DE49B5241;
const unsigned long loAdd=0x85DC198BCDD714BA;
loWord += loAdd;
if (loWord < loAdd) ++hiWord; // test_and_add_carry
hiWord += hiAdd;
}
Run Code Online (Sandbox Code Playgroud)
这是一个紧凑而简单的代码.有用.
不幸的是,这大约是我运行时的20%.这条杀手线就是低价测试.如果我删除它,我显然得到了错误的答案,但运行时开销从20%下降到4%!因此携带测试特别昂贵!
我的问题:C++是否公开了硬件进位标志,即使是作为GCC的扩展?如果实际编译的指令使用最后一个进位指令进行添加,似乎可以在没有上面的测试和添加进位线的情况下完成添加.有没有办法重写test-and-add-carry行以使编译器使用内部操作码?
我正在尝试生成代码(目前使用clang ++ - 3.8),它添加了两个由多个机器字组成的数字.为了简化目前我只添加128位数字,但我希望能够概括这一点.
首先是一些typedef:
typedef unsigned long long unsigned_word;
typedef __uint128_t unsigned_128;
Run Code Online (Sandbox Code Playgroud)
而"结果"类型:
struct Result
{
unsigned_word lo;
unsigned_word hi;
};
Run Code Online (Sandbox Code Playgroud)
第一个函数f采用两对无符号字并返回结果,作为一个中间步骤,在添加它们之前将这两个64位字放入一个128位字中,如下所示:
Result f (unsigned_word lo1, unsigned_word hi1, unsigned_word lo2, unsigned_word hi2)
{
Result x;
unsigned_128 n1 = lo1 + (static_cast<unsigned_128>(hi1) << 64);
unsigned_128 n2 = lo2 + (static_cast<unsigned_128>(hi2) << 64);
unsigned_128 r1 = n1 + n2;
x.lo = r1 & ((static_cast<unsigned_128>(1) << 64) - 1);
x.hi = r1 >> 64;
return x;
}
Run Code Online (Sandbox Code Playgroud)
这实际上非常好地内联:
movq 8(%rsp), …Run Code Online (Sandbox Code Playgroud) 有汇编指令ADC.我发现这意味着"随身携带".但我不知道这意味着什么.或者如何用C++编写这个指令.我知道它不一样ADD.所以做一个简单的求和是不正确的.
信息:
在Windows中编译.我正在使用32位Windows安装.我的处理器是Intel的Core 2 Duo.
我希望能够%rbp在内联asm中使用基指针寄存器().这样的玩具示例是这样的:
void Foo(int &x)
{
asm volatile ("pushq %%rbp;" // 'prologue'
"movq %%rsp, %%rbp;" // 'prologue'
"subq $12, %%rsp;" // make room
"movl $5, -12(%%rbp);" // some asm instruction
"movq %%rbp, %%rsp;" // 'epilogue'
"popq %%rbp;" // 'epilogue'
: : : );
x = 5;
}
int main()
{
int x;
Foo(x);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我希望,因为我使用通常的序幕/结尾函数调用方法来推送和弹出旧的%rbp,这样就可以了.但是,当我尝试在内x联asm之后访问时,它会出现故障.
GCC生成的汇编代码(略微剥离)是:
_Foo:
pushq %rbp
movq %rsp, %rbp
movq %rdi, -8(%rbp)
# INLINEASM
pushq %rbp; // prologue
movq %rsp, …Run Code Online (Sandbox Code Playgroud) 使用任意精度算术(例如512位整数)时,有没有办法让GCC在不使用内联汇编的情况下使用ADC和类似指令?
乍一看GMP的源代码显示,它们只是为每个支持的平台提供了汇编实现.
这是我编写的测试代码,它从命令行添加两个128位数字并打印结果.(受mini-gmp的add_n启发):
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
int main (int argc, char **argv)
{
uint32_t a[4];
uint32_t b[4];
uint32_t c[4];
uint32_t carry = 0;
for (int i = 0; i < 4; ++i)
{
a[i] = strtoul (argv[i+1], NULL, 16);
b[i] = strtoul (argv[i+5], NULL, 16);
}
for (int i = 0; i < 4; ++i)
{
uint32_t aa = a[i];
uint32_t bb = b[i];
uint32_t r = aa + carry;
carry = (r < carry);
r += …Run Code Online (Sandbox Code Playgroud) c optimization gcc compiler-optimization arbitrary-precision
因为似乎没有ADC的固有内容而且我不能使用Visual C++的x64架构使用内联汇编程序,如果我想使用add with carry编写函数但是将它包含在C++命名空间中,我该怎么办?
(使用比较运算符进行仿真不是一种选择.这256兆位的添加对性能至关重要.)
我正在阅读计算机系统:程序员的观点,家庭作业是描述这种算法是如何工作的.
C功能:
void store_prod(__int128 *dest, int64_t x, int64_t y) {
*dest = x * (__int128)y;
}
Run Code Online (Sandbox Code Playgroud)
部件:
movq %rdx, %rax
cqto
movq %rsi, %rcx
sarq $63, %rcx
imulq %rax, %rcx
imulq %rsi, %rdx
addq %rdx, %rcx
mulq %rsi
addq %rcx, %rdx
movq %rax, (%rdi)
movq %rdx, 8(%rdi)
ret
Run Code Online (Sandbox Code Playgroud)
我不知道它为什么表现: xh * yl + yh * xl = value which we add after unsigned multiplication
几年前,我需要一种方法来使用 Cuda 进行一些基本的 128 位整数数学运算: cuda 上的 128 位整数?. 现在我遇到了同样的问题,但这次我需要在不支持任何类型的 128 位的 32 位嵌入式系统(英特尔爱迪生)上运行一些基本的 128 位算术(求和、位移和乘法)。但是,有直接支持的 64 位整数(unsigned long long int)。
我天真地尝试使用上次在CPU上回答我的asm代码,但是我得到了一堆错误。我真的没有使用 asm 的经验,所以:使用 64 位整数实现 128 位加法、乘法和位移的最有效方法是什么?
在我的计算机上,编译的可执行文件省略了在循环顶部执行"mov%2,%% ax"
当"添加%1,%% ax"取消注释时.
有人要进行双重检查或评论?
#include <stdio.h>
int main() {
short unsigned result, low ,high;
low = 0;
high = 1;
__asm__ (
"movl $10, %%ecx \n\t"
"loop: mov %2, %%ax \n\t"
// "add %1, %%ax \n\t" // uncomment and result = 10
"mov %%ax, %0 \n\t"
"subl $1, %%ecx \n\t"
"jnz loop"
: "=r" (result)
: "r" (low) , "r" (high)
: "%ecx" ,"%eax" );
printf("%d\n", result);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
跟随生成的程序集
movl $1, %esi
xorl %edx, %edx
/APP
movl …Run Code Online (Sandbox Code Playgroud) assembly ×7
c++ ×6
c ×3
gcc ×3
x86 ×3
optimization ×2
128-bit ×1
64-bit ×1
adx ×1
bigint ×1
carryflag ×1
clang ×1
i386 ×1
int128 ×1
intel-edison ×1
intrinsics ×1
red-zone ×1
visual-c++ ×1
x86-64 ×1