相关疑难解决方法(0)

什么时候装配比C快?

了解汇编程序的一个原因是,有时可以使用它来编写比使用更高级语言编写代码更高效的代码,特别是C. 但是,我也听过很多次说虽然这并非完全错误,但汇编程序实际上可用于生成更高性能代码的情况极为罕见,需要专业知识和汇编经验.

这个问题甚至没有涉及汇编程序指令将是机器特定的和不可移植的,或汇编程序的任何其他方面的事实.当然,除了这一点之外,还有很多很好的理由知道汇编,但这是一个特定的问题,征求例子和数据,而不是关于汇编语言与高级语言的扩展讨论.

任何人都可以提供一些特定的例子,其中汇编将比使用现代编译器的编写良好的C代码更快,并且您是否可以通过分析证据来支持该声明?我非常有信心这些案例存在,但我真的想知道这些案件究竟有多深奥,因为它似乎是一些争论的焦点.

c performance assembly

458
推荐指数
25
解决办法
10万
查看次数

什么gcc版本支持__int128内在类型?

gcc docs下,128位整数是:

作为扩展,整数标量类型__int128支持具有足够容纳128位的整数模式的目标.只需写入__int128带符号的128位整数,或写入unsigned __int128无符号的128位整数.

GCC中不支持表示__int128长整数小于128位宽的目标的类型的整数常量.

我想知道什么gcc版本增加了对这种类型的支持,或者如果有,可以直接用来测试其存在的宏.

gcc

16
推荐指数
2
解决办法
3532
查看次数

在C中计算64x64 int产品的高64位

我希望我的C函数能够有效地计算两个64位有符号整数的乘积的高64位.我知道如何在x86-64程序集中执行此操作,使用imulq并将结果从%rdx中拉出.但是我完全不知道如何在C语言中编写它,更不用说哄骗编译器有效地执行它了.

有没有人有任何建议用C写这个?这是性能敏感的,因此"手动方法"(如俄罗斯农民或bignum图书馆)已经出局.

我写的这个笨拙的内联汇编函数很有用,大致是我追求的代码:

static long mull_hi(long inp1, long inp2) {
    long output = -1;
    __asm__("movq %[inp1], %%rax;"
            "imulq %[inp2];"
            "movq %%rdx, %[output];"
            : [output] "=r" (output)
            : [inp1] "r" (inp1), [inp2] "r" (inp2)
            :"%rax", "%rdx");
    return output;
}
Run Code Online (Sandbox Code Playgroud)

c math 64-bit

14
推荐指数
3
解决办法
2595
查看次数

gcc内在的扩展除法/乘法

现代CPU可以在两个原生大小的字之间执行扩展乘法,并将低和高结果存储在单独的寄存器中.类似地,当执行除法时,它们将商和余数存储在两个不同的寄存器中,而不是丢弃不需要的部分.

是否存在某种可移植的gcc内在函数,它将采用以下签名:

void extmul(size_t a, size_t b, size_t *lo, size_t *hi);
Run Code Online (Sandbox Code Playgroud)

或类似的东西,以及分裂:

void extdiv(size_t a, size_t b, size_t *q, size_t *r);
Run Code Online (Sandbox Code Playgroud)

我知道我可以通过在代码中抛出#ifdef来使用内联汇编和shoehorn可移植性来实现它,或者我可以使用部分和来模拟乘法部分(这将显着更慢)但我想避免这样做以便于阅读.当然有一些内置函数可以做到这一点?

c gcc

12
推荐指数
2
解决办法
5103
查看次数

高效计算32位整数乘法的高阶位

许多CPU具有用于返回单个组件的操作码的高 32位的整数乘法的序位.通常将两个32位整数相乘会产生64位结果,但如果将其存储为32位整数,则会将其截断为低32位.

例如,在PowerPC上,mulhw操作码在一个时钟内返回32位32位乘法的64位结果的高32位.这正是我正在寻找的,但更便携.在NVidia CUDA中有一个类似的操作码,umulhi().

在C/C++中,是否有一种有效的方法来返回32x32乘法的高阶位?目前我通过转换为64位来计算它,例如:

unsigned int umulhi32(unsigned int x, unsigned int y)
{
  unsigned long long xx=x;
  xx*=y;
  return (unsigned int)(xx>>32);
}
Run Code Online (Sandbox Code Playgroud)

但这比常规的32乘32乘以慢11倍,因为即使是乘法,我也使用了过度的64位数学运算.

有更快的方法来计算高阶位吗?

对于BigInteger库来说,这显然不是最好的解决方案(这是一种过度杀伤并且会产生巨大的开销).

SSE似乎有PMULHUW,16x16 - > 16位版本,但不是32x32 - > 32版本,就像我在寻找.

c c++ optimization

10
推荐指数
1
解决办法
2569
查看次数

SIMD使用无符号乘法对64位*64位到128位进行签名

我创建了一个使用SIMD进行64位*64位到128位的功能.目前我已经使用SSE2(acutally SSE4.1)实现了它.这意味着它可以同时运行两个64b*64b到128b的产品.同样的想法可以扩展到AVX2或AVX512,同时提供四个或八个64b*64到128b的产品.我的算法基于http://www.hackersdelight.org/hdcodetxt/muldws.c.txt

该算法进行一次无符号乘法,一次有符号乘法和两次有符号*无符号乘法.签名的*signed和unsigned*unsigned操作很容易使用_mm_mul_epi32_mm_mul_epu32.但混合签名和未签名的产品给我带来了麻烦.例如,考虑一下.

int32_t x = 0x80000000;
uint32_t y = 0x7fffffff;
int64_t z = (int64_t)x*y;
Run Code Online (Sandbox Code Playgroud)

双字产品应该是0xc000000080000000.但是如果你假设你的编译器知道如何处理混合类型,你怎么能得到这个呢?这就是我想出的:

int64_t sign = x<0; sign*=-1;        //get the sign and make it all ones
uint32_t t = abs(x);                 //if x<0 take two's complement again
uint64_t prod = (uint64_t)t*y;       //unsigned product
int64_t z = (prod ^ sign) - sign;    //take two's complement based on the sign
Run Code Online (Sandbox Code Playgroud)

使用SSE可以这样做

__m128i xh;    //(xl2, xh2, xl1, xh1) high is signed, low unsigned
__m128i …
Run Code Online (Sandbox Code Playgroud)

c x86 integer sse bit-manipulation

9
推荐指数
2
解决办法
4203
查看次数

计算C#中乘法的高位

我正在尝试将.Net 4.0的开源库转换为3.5,并且无法轻松转换以下长乘法代码:

    /// <summary>
    /// Calculate the most significant 64 bits of the 128-bit
        product x * y, where x and y are 64-bit integers.
    /// </summary>
    /// <returns>Returns the most significant 64 bits of the product x * y.</returns>
    public static long mul64hi(long x, long y)
    {
 #if !NET35
        BigInteger product = BigInteger.Multiply(x, y);
        product = product >> 64;
        long l = (long)product;
        return l;
 #else
        throw new NotSupportedException(); //TODO!
 #endif
    }
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,作者没有找到这样做的方法.BigInteger在.NET 3.5中不存在.

如何在.NET 3.5上计算64*64乘法的高位64位?

.net c# biginteger multiplication

9
推荐指数
1
解决办法
783
查看次数

如何使用x86汇编语言将两个64位数相乘?

我该怎么办......

  • 乘以两个64位数

  • 乘以两个16位十六进制数

......使用汇编语言.

我只允许使用寄存器%eax,%ebx,%ecx,%edx和堆栈.

编辑:哦,我在x86
EDIT2 上使用ATT语法:不允许反编译成程序集...

x86 assembly

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

Clang中有__int128_t的错误?

这个小代码汇编了GCC和Clang,但给出了不同的结果:

#include <stdio.h>

int main(){

  __int128_t test=10;
  while(test>0){
    int myTest=(int)test;
    printf("? %d\n", myTest);
    test--;
  }

}
Run Code Online (Sandbox Code Playgroud)

对于GCC,这从预期行为从10减少到1,而对于Clang,它继续计入负数.使用Clang,如果我替换test--test-=1then,它也会给出预期的行为.

__int128_t是GCC扩展名,因此上述结果仅适用于非标准C,因此在Clang中__int128_t可能"使用后果自负".

这是Clang中的一个错误,还是我犯了一些我没看到的错误?

编辑:我正在使用gcc(MacPorts gcc48 4.8-20130411_0)4.8.1 20130411(预发布)和Apple clang 4.0版(标签/ Apple/clang-421.0.60)(基于LLVM 3.1svn).

c gcc clang int128

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

如何将64位操作数相乘并获得128位结果?

对于x64,我可以使用这个:

 {
   uint64_t hi, lo;
  // hi,lo = 64bit x 64bit multiply of c[0] and b[0]

   __asm__("mulq %3\n\t"
    : "=d" (hi),
  "=a" (lo)
    : "%a" (c[0]),
  "rm" (b[0])
    : "cc" );

   a[0] += hi;
   a[1] += lo;
 }
Run Code Online (Sandbox Code Playgroud)

但我想以可移植的方式执行相同的计算.例如,在x86上工作.

c assembly gcc

7
推荐指数
3
解决办法
3722
查看次数