相关疑难解决方法(0)

C数据类型如何"大多数计算机直接支持"?

我正在阅读K&R的"The C Programming Language"并且发现了这个声明[Introduction,p.3]:

由于大多数计算机都直接支持C提供的数据类型和控制结构,因此实现自包含程序所需的运行时库很小.

粗体陈述是什么意思?是否存在计算机直接支持的数据类型或控制结构的示例?

c

114
推荐指数
7
解决办法
7189
查看次数

使用进位标志进行高效的128位加法

我在我的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行以使编译器使用内部操作码?

c++ assembly gcc bigint carryflag

39
推荐指数
2
解决办法
8350
查看次数

使用clang的携带代码生成良好的添加

我正在尝试生成代码(目前使用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)

c++ optimization assembly clang adx

26
推荐指数
1
解决办法
1206
查看次数

装配ADC(随附进位)到C++

有汇编指令ADC.我发现这意味着"随身携带".但我不知道意味着什么.或者如何用C++编写这个指令.我知道它不一样ADD.所以做一个简单的求和是不正确的.

信息:
在Windows中编译.我正在使用32位Windows安装.我的处理器是Intel的Core 2 Duo.

c++ x86 assembly

16
推荐指数
5
解决办法
3万
查看次数

在C++内联asm中使用基指针寄存器

我希望能够%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)

c++ x86 assembly red-zone

13
推荐指数
1
解决办法
4119
查看次数

让GCC在没有内联汇编的情况下使用进位逻辑实现任意精度算术?

使用任意精度算术(例如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

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

Visual C++ x64附带进位

因为似乎没有ADC的固有内容而且我不能使用Visual C++的x64架构使用内联汇编程序,如果我想使用add with carry编写函数但是将它包含在C++命名空间中,我该怎么办?

(使用比较运算符进行仿真不是一种选择.这256兆位的添加对性能至关重要.)

c++ 64-bit inline-assembly intrinsics visual-c++

7
推荐指数
2
解决办法
2682
查看次数

这个128位整数乘法如何在汇编(x86-64)中工作?

我正在阅读计算机系统:程序员的观点,家庭作业是描述这种算法是如何工作的.

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

c assembly x86-64 128-bit

7
推荐指数
2
解决办法
2007
查看次数

在 C++ 中进行基本 128 位整数计算的有效方法?

几年前,我需要一种方法来使用 Cuda 进行一些基本的 128 位整数数学运算: cuda 上的 128 位整数?. 现在我遇到了同样的问题,但这次我需要在不支持任何类型的 128 位的 32 位嵌入式系统(英特尔爱迪生)上运行一些基本的 128 位算术(求和、位移和乘法)。但是,有直接支持的 64 位整数(unsigned long long int)。

我天真地尝试使用上次在CPU上回答我的asm代码,但是我得到了一堆错误。我真的没有使用 asm 的经验,所以:使用 64 位整数实现 128 位加法、乘法和位移的最有效方法是什么?

c++ x86 assembly int128 intel-edison

4
推荐指数
2
解决办法
7656
查看次数

意外的GCC内联ASM行为(被覆盖的被破坏的变量)

在我的计算机上,编译的可执行文件省略了在循环顶部执行"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 gcc inline-assembly i386

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