9

OS: Linux (Debian 10)

CC: GCC 8.3

CPU: i7-5775C

There is a unsigned __int128/__int128 in GCC, but is there any way to have a uint256_t/int256_t in GCC?

I have read of a __m256i which seems to be from Intel. Is there any header that I can include to get it?

Is it as usable as a hypothetic unsigned __int256? I mean if you can assign from/to it, compare them, bitwise operations, etc.

What is its signed equivalent (if any)?


EDIT 1:

I achieved this:

#include <immintrin.h>
typedef __m256i uint256_t;

and compiled. If I can do some operations with it, I'll update it here.


EDIT 2:

Issues found:

uint256_t   m;
int         l = 5;

m = ~((uint256_t)1 << l);

ouput:

error: can’t convert a value of type ‘int’ to vector type ‘__vector(4) long long int’ which has different size
  m = ~((uint256_t)1 << l);
4

2 回答 2

10

Clang 具有支持除法以外的操作的_ExtInt扩展整数,但 SIMD 对此没有用,因为元素之间有进位1。其他主流 x86-64 编译器甚至没有。您需要一个库或其他东西来定义自定义类型并使用 clang 将使用的相同 add-with-carry 指令。(或纯 C 2中效率较低的仿真)。

__m256i是 AVX2 SIMD 4x uint64_t(或更窄的元素大小,如 8x uint32_t)。 它不是 256 位标量整数类型,您不能将其用于标量操作,__m256i var = 1甚至无法编译. 没有 x86 SIMD支持大于 64 位的整数,并且 Intel 内部类型喜欢__m128i并且__m256i纯粹用于 SIMD。

GCC 的__int128/unsigned __int128通常使用标量add/adc和/或标量mul/ imul,因为 AVX2 通常对扩展精度没有帮助。(仅适用于元素边界无关的按位 AND/OR/XOR。)


脚注 1:对于 BigInteger 类型实际上有一些使用 SIMD 的范围,但只能使用专门的格式。更重要的是,您必须手动选择何时重新规范化(传播进位),因此您的计算必须围绕它进行设计;它不是直接替代品。请参阅 Mysticial 关于长整数例程可以从 SSE 中受益的答案吗?

脚注2:不幸的是,C不提供加法/减法的进位,因此用C编写甚至不方便。/在 sum = a+b没有carry = sum<a进位的情况下进行执行,但是用C编写全加器要困难得多。编译器通常会制作垃圾 asm,而不仅仅是在可用的机器上使用本机 add-with-carry 指令。用于非常大整数的扩展精度库,如GMP,通常用 asm 编写。

于 2019-04-22T23:32:58.497 回答
4

在 Pollard Rho 算法中计算“f(x) = (x^2+a) mod n”时,我确实需要“uint256_t”。函数“f”之外的所有变量都是内置类型 __uint128_t。

我为此目的实现了 uint256_t ,如下所示:

typedef __uint128_t uint256_t[2];

然后我实现了计算“f()”所需的函数:

__uint128_t set_128(unsigned long h, unsigned long l);
void set_256(uint256_t d, __uint128_t l, __uint128_t h);
void add_128(uint256_t d, uint256_t x, __uint128_t a);
void add_256(uint256_t d, uint256_t x, uint256_t a);
void shl_256(uint256_t d, long s);
void sqr_128(uint256_t d, __uint128_t x);
several print functions and macros for printing 128bit and 256bit numbers
__uint128_t mod_256(uint256_t x, __uint128_t n);
__uint128_t f(__uint128_t x);

在这个要点中找到实现:
https ://gist.github.com/Hermann-SW/a20af17ee6666467fe0b5c573dae701d

我确实针对 gmplib 函数对我的代码进行了基准测试,并为所有人(经过大量工作)实现了对 gmplib 的加速,详情:
https ://www.raspberrypi.org/forums/viewtopic.php?f=33&t=311893&p=1873552# p1873552

执行 100 万次函数的运行时间(以纳秒为单位):
在此处输入图像描述

于 2021-06-04T15:00:39.333 回答