将压缩半字节组合成压缩字节

2024-03-11

给定一个或多个__m128i or __m256i每个 16 位元素包含一个半字节,将它们组合并打包为每个 8 位元素一个字节的最快方法是什么(即(hi << 4) | lo对于相邻的 16 位元素)?

这是我想出的最好方法,不幸的是它与标量代码相当:

const static __m256i shufmask = _mm256_setr_epi8(
  2, 255, 255, 255, 6, 255, 255, 255, 10, 255, 255, 255, 14, 255, 255, 255,
  2, 255, 255, 255, 6, 255, 255, 255, 10, 255, 255, 255, 14, 255, 255, 255);

const static __m256i high4 = _mm256_setr_epi8(
  255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0,
  255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0
);

inline static int64_t hnib2byte(__m256i nibbles) { // (a << 4) | b;
  // hi 0 lo 0, ...
  __m256i upper = _mm256_slli_epi16(nibbles, 4);

  // Align upper and lower halves so they can be ORed vertically
  // lo 0 0 0, ...
  __m256i lower = _mm256_shuffle_epi8(nibbles, shufmask);

  // ab x x x, ...
  __m256i or = _mm256_or_si256(upper, lower);

  // Pack into bytes
  or = _mm256_and_si256(or, high4);
  __m256i pack16 = _mm256_packus_epi16(or, or);
  const int _3to2 = 0b00001000;
  __m256i perm16 = _mm256_permute4x64_epi64(pack16, _3to2); // :(
  __m256i pack8 = _mm256_packus_epi16(perm16, perm16);

  return _mm_cvtsi128_si64(_mm256_castsi256_si128(pack8));
}

AVX2 及之前的指令都是公平的游戏。 AVX-512 中的屏蔽转变开辟了更好的选择。这是在循环中调用的,因此尽早将半字节打包到 8 位元素中也是公平的做法。


解决方案hnib2byte_v2下面的解决方案应该比您的解决方案快一点,至少在英特尔处理器上是这样。

操作说明vpermd或内在的_mm256_permutevar8x32_epi32AMD Ryzen 上速度很慢。在该平台上最好使用_mm256_extracti128_si256提取高 128 位通道pck, 使用_mm256_castsi256_si128提取较低的 128 位通道,并将这两者结合起来_mm256_or_si256得到最低 64 位的答案。

/*
gcc -O3 -m64 -Wall -mavx2 -march=broadwell nibble2byte.c
*/
#include <immintrin.h>
#include <stdio.h>
#include <stdint.h>

int print_avx2_hex(__m256i ymm);


inline static int64_t hnib2byte_v2(__m256i nibbles) {
  __m256i shufmask8  = _mm256_set_epi8(-1,-1,-1,-1,  -1,-1,-1,-1,  14,10,6,2,  -1,-1,-1,-1,  -1,-1,-1,-1,  -1,-1,-1,-1,  -1,-1,-1,-1,  14,10,6,2);
  __m256i shufmask32 = _mm256_set_epi32(7,7,7,7,7,7,5,0);

  __m256i lower      = _mm256_slli_epi32(nibbles, 20);
// 00E0000000C00000 00A0000000800000 0060000000400000 0020000000000000

  __m256i up_lo      = _mm256_or_si256(lower,nibbles);
// 00EF000E00CD000C 00AB000A00890008 0067000600450004 0023000200010000

  __m256i pck        = _mm256_shuffle_epi8(up_lo,shufmask8);
// 0000000000000000 EFCDAB8900000000 0000000000000000 0000000067452301

  __m256i pck64      = _mm256_permutevar8x32_epi32(pck,shufmask32);
// 0000000000000000 0000000000000000 0000000000000000 EFCDAB8967452301

//  print_avx2_hex(lower);
//  print_avx2_hex(up_lo);
//  print_avx2_hex(pck);
//  print_avx2_hex(pck64);

  return _mm_cvtsi128_si64(_mm256_castsi256_si128(pck64));
}


inline static int64_t hnib2byte(__m256i nibbles) { // (a << 4) | b;

__m256i shufmask = _mm256_setr_epi8(
  2, 255, 255, 255, 6, 255, 255, 255, 10, 255, 255, 255, 14, 255, 255, 255,
  2, 255, 255, 255, 6, 255, 255, 255, 10, 255, 255, 255, 14, 255, 255, 255);

__m256i high4 = _mm256_setr_epi8(
  255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0,
  255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0);

  // hi 0 lo 0, ...
  __m256i upper = _mm256_slli_epi16(nibbles, 4);

  // Align upper and lower halves so they can be ORed vertically
  // lo 0 0 0, ...
  __m256i lower = _mm256_shuffle_epi8(nibbles, shufmask);

  // ab x x x, ...
  __m256i or = _mm256_or_si256(upper, lower);

  // Pack into bytes
  or = _mm256_and_si256(or, high4);
  __m256i pack16 = _mm256_packus_epi16(or, or);
  const int _3to2 = 0b00001000;
  __m256i perm16 = _mm256_permute4x64_epi64(pack16, _3to2); // :(
  __m256i pack8 = _mm256_packus_epi16(perm16, perm16);

  return _mm_cvtsi128_si64(_mm256_castsi256_si128(pack8));
}


int print_avx2_hex(__m256i ymm)
{
    long unsigned int x[4];
        _mm256_storeu_si256((__m256i*)x,ymm);
        printf("%016lX %016lX %016lX %016lX\n", x[3],x[2],x[1],x[0]);

    return 0;
}


int main()
{
   uint64_t x;
    __m256i nibble_x16 = _mm256_set_epi16(0x000F,0x000E,0x000D,0x000C,  0x000B,0x000A,0x0009,0x0008,  
                                          0x0007,0x0006,0x0005,0x0004,  0x0003,0x0002,0x0001,0x0000);
    printf("AVX variable: \n");
    print_avx2_hex(nibble_x16);                                      
    x = hnib2byte(nibble_x16);
    printf("With hnib2byte    x = %016lX \n\n",x);

    printf("AVX variable: \n");
    print_avx2_hex(nibble_x16);                                      
    x = hnib2byte_v2(nibble_x16);
    printf("With hnib2byte_v2 x = %016lX \n",x);
    return 0;
}

输出是:

$ ./a.out
AVX variable: 
000F000E000D000C 000B000A00090008 0007000600050004 0003000200010000
With hnib2byte    x = EFCDAB8967452301 

AVX variable: 
000F000E000D000C 000B000A00090008 0007000600050004 0003000200010000
With hnib2byte_v2 x = EFCDAB8967452301 

对于此处选择的输入,两种方法的输出是相等的。

除了加载应在循环外部完成的随机播放常量之外,它仅编译为五个指令:vpslld,vpor,vpshufb, vpermd,and vmovq,这比您的解决方案少三个。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

将压缩半字节组合成压缩字节 的相关文章

  • 在 C# 中使用“using”关键字避免多次处置的最佳实践

    当变量是 IDisposable 时 我们有using关键字来管理处置 但是如果我们在方法中返回值怎么办 using twice StringContent stringToStringContent string str using St
  • IEnumerable 的 String.Join(string, string[]) 的类似物

    class String包含非常有用的方法 String Join string string 它从数组创建一个字符串 用给定的符号分隔数组的每个元素 但一般来说 它不会在最后一个元素之后添加分隔符 我将它用于 ASP NET 编码 以用
  • 叮当错误?命名空间模板类的朋友

    以下代码在 clang 下无法编译 但在 gcc 和 VS 下可以编译 template
  • 异常堆栈跟踪不显示抛出异常的位置

    通常 当我抛出异常 捕获它并打印出堆栈跟踪时 我会看到抛出异常的调用 导致该异常的调用 导致该异常的调用that 依此类推回到整个程序的根 现在它只向我显示异常所在的调用caught 而不是它所在的地方thrown 我不明白是什么改变导致了
  • 如果 JSON.NET 中的值为 null 或空格,则防止序列化

    我有一个对象需要以这样的方式序列化 即 null 和 空白 空或只是空格 值都不会序列化 我不控制对象本身 因此无法设置属性 但我知道所有属性都是字符串 环境NullValueHandling显然 忽略 只能让我找到解决方案的一部分 它 似
  • C 中“complex”的默认类型

    根据我读过的文档 C99 和更高版本的支持float complex double complex and long double complex作为复杂类型 但是 此代码在使用时编译时不会发出警告gcc Wall Wextra inclu
  • 为什么需要数字后缀?

    C 语言 我确信还有其他语言 需要在数字文字末尾添加后缀 这些后缀指示文字的类型 例如 5m是一个小数 5f是一个浮点数 我的问题是 这些后缀真的有必要吗 或者是否可以从上下文中推断出文字的类型 例如 代码decimal d 5 0应该推断
  • 通过 C# Mailkit / Mimekit 发送电子邮件,但出现服务器证书错误

    Visual Studio 2015 中的 0 代码 1 我正在使用 Mailkit 最新版本 1 18 1 1 从我自己的电子邮件服务器发送电子邮件 2 电子邮件服务器具有不受信任的自签名证书 3 我在代码中添加了以下两行 以忽略服务器证
  • 子目录中的头文件(例如 gtk/gtk.h 与 gtk-2.0/gtk/gtk.h)

    我正在尝试使用 GTK 构建一个 hello world 其中包括以下行 include
  • 如何使用递归查找数字中的最小元素 [C]

    好的 所以我正在准备我的 C 考试 当谈到递归时我有点卡住了我是大学一年级的学生 这对我来说似乎有点困难 练习要求在给定的数字中使用递归函数我需要找到最小的元素 例如 52873 是 2 程序需要打印 2 include
  • Resharper:IEnumerable 的可能多重枚举

    我正在使用新的 Resharper 版本 6 在我的代码中的几个地方 它给一些文本加了下划线 并警告我可能存在IEnumerable 可能的多重枚举 我理解这意味着什么 并在适当的情况下采纳了建议 但在某些情况下 我不确定这实际上是一个大问
  • 使用多线程进行矩阵乘法?

    我应该使用线程将两个矩阵相乘 有两件事 当我运行程序时 我不断得到 0 我还收到消息错误 对于每个错误 它在粗体行上显示 警告 从不兼容的指针类型传递 printMatrix 的参数1 我尝试打印输出 还要注意 第一个粗体块 这是我解决问题
  • 如何在dll级别读取app.config? [复制]

    这个问题在这里已经有答案了 我在一个解决方案中有一个控制台应用程序项目和库项目 dll The 图书馆项目有 app config 文件 我在其中存储我在库中使用的一些键值对 控制台应用程序引用此 dll 我有另一个 app config
  • 如何将 int 作为“void *”传递给线程启动函数?

    我最初有一个用于斐波那契变量数组的全局变量 但发现这是不允许的 我需要进行基本的多线程处理并处理竞争条件 但我无法在 pthread 创建中将 int 作为 void 参数提供 我尝试过使用常量指针 但没有成功 由于某些奇怪的原因 void
  • “必须声明标量变量”错误[重复]

    这个问题在这里已经有答案了 必须声明标量变量 Id SqlConnection con new SqlConnection connectionstring con Open SqlCommand cmd new SqlCommand cm
  • printf或iostream如何指定点后的最大位数

    字符串采用什么格式printf or iomanip我应该使用 iostream 中的运算符以以下格式打印浮点数 125 0 gt 125 125 1 gt 125 1 125 12312 gt 125 12 1 12345 gt 1 12
  • 如何提高环复杂度?

    对于具有大量决策语句 包括 if while for 语句 的方法 循环复杂度会很高 那么我们该如何改进呢 我正在处理一个大项目 我应该减少 CC gt 10 的方法的 CC 并且有很多方法都存在这个问题 下面我将列出一些例如我遇到的问题的
  • 为什么表达式 a = a + b - ( b = a ) 在 C++ 中给出序列点警告?

    以下是测试代码 int main int a 3 int b 4 a a b b a cout lt lt a lt lt a lt lt lt lt b lt lt b lt lt n return 0 编译此命令会出现以下警告 gt g
  • C++ Boost ASIO 简单的周期性定时器?

    我想要一个非常简单的周期性计时器每 50 毫秒调用我的代码 我可以创建一个始终休眠 50 毫秒的线程 但这很痛苦 我可以开始研究用于制作计时器的 Linux API 但它不可移植 I d like使用升压 我只是不确定这是否可能 boost
  • 嵌入式二进制资源 - 如何枚举嵌入的图像文件?

    我按照中的说明进行操作这本书 http www apress com book view 9781430225492 关于资源等的章节 我不太明白的是 如何替换它 images Add new BitmapImage new Uri Ima

随机推荐

  • 如何从 Julia 程序调用 Python 函数?

    我使用 numpy pandas scikit learn 在 Python 中编写了一些代码 是否可以从 Julia 程序调用此 Python 代码 我认为你可以考虑三种不同的方式从 Julia 调用 Python 代码 按照从最低级别到
  • SwiftUI:全屏覆盖的半透明背景

    所以从技术上讲我想显示一个加载屏幕视图 我在用着fullScreenCover struct ContentView View State private var isLoading false var body some View VSt
  • 在 Postgres 中将逗号分隔的字符串转换为整数数组

    我正在尝试将逗号分隔的字符串转换为整数数组 integer 以在Where 子句中使用 我尝试过演员 Int这不起作用 感谢您的意见 Example Table A Table B ID Set id 2 14 16 17 1 15 19
  • 错误:无法调用类型缺少调用签名的表达式

    我是打字稿的新手 我有两门课 在父类中我有 abstract class Component public deps any public props any public setProp prop string any return
  • Selenium Grid2 - 是否可以运行 10 个 Chrome 实例?

    目前Selenium Grid2在默认配置下运行显示它可以运行5个firefox浏览器 5个chrome浏览器和1个IE 最多同时有 5 个实例 我如何更改它以便它同时运行 10 个 chrome 实例 我已成功更改节点的最大会话参数 最大
  • NSCollectionView sizeForItemAt 在尝试引用其集合中的项目时始终返回异常

    语境 我正在开发一个 macOS 菜单栏应用程序 它显示一系列项目 这些项目存在于集合视图中并包含一个文本字段 现在 集合视图布局的固定高度为 50 我正在尝试根据文本字段的大小动态增加单元格的大小 我相信做到这一点的最好方法是sizeFo
  • PHP 警告:PHP 启动:无法加载动态库

    我运行 PHP 脚本并收到此错误 PHP 警告 PHP 启动 无法加载动态库 usr local lib php extensions no debug non zts 20090626 ixed 5 2 lin usr local lib
  • 无法在路径加载平台

    使用时filemerge解决HG冲突 我得到以下内容error FileMerge 18002 707 Unable to load platform at path Applications Xcode app Contents Deve
  • 声明朋友时必须声明类键

    当我这样声明朋友时 g 编译器会抱怨这个错误 friend MyClass 代替 friend class MyClass 为什么应该class需要关键字吗 顺便说一句 Borland C 编译器不需要它 难道编译器不能简单地在符号表中查找
  • matplotlib 中自动调整图形大小

    有没有办法自动调整图形大小以正确适合 matplotlib pylab 图像中包含的图 我正在创建根据所使用的数据纵横比不同的热图 子 图 我意识到我可以计算纵横比并手动设置它 但肯定有更简单的方法吗 Use bbox inches 紧 i
  • 在 Flutter Canvas 中使用 Gradient 和 Paint 对象

    我可以使用以下示例绘制半圆 Flutter如何画半圆 半圆 https stackoverflow com questions 57748469 flutter how to draw semicircle half circle 但是 那
  • 根据外键选择填充 django-admin 中的值

    我有一个带有外键引用的模型 看起来像这样 class Plan models Model template models ForeignKey PlanTemplate throttle models IntegerField defaul
  • 设置 Java 应用程序的全局字体

    我需要为我的应用程序设置默认字体 有没有一种不依赖 LaF 的方法可以做到这一点 弄清楚了 致电 setUIFont new javax swing plaf FontUIResource new Font MS Mincho Font P
  • CloudFoundry 时区

    我开发了一个非常以 JodaTime 日期时间为中心的应用程序 日历等 在我的本地计算机上一切正常 我已在 cloudfoundry 部署了我的应用程序 但日历中没有可见的日期 我猜这和cloudfoundry的时区有关 我已将本地运行的应
  • 在谷歌应用程序脚本中以 HTML 形式获取谷歌文档[重复]

    这个问题在这里已经有答案了 如何在谷歌应用程序脚本中获取 HTML 形式的谷歌文档 例如 我可以像这样获取文档正文 DocumentApp getActiveDocument getBody 但是当我登录时什么也没有 function do
  • 如何从 iOS SDK 中的 Facebook 对象获取 Facebook 用户 ID?

    我看到 Facebook 对象中提供了访问令牌 但我没有看到 Facebook 用户 ID 我可以向 我 发出图形请求以获取 Facebook Id 但我不想进行额外的 api 调用 现在有一种简单的方法可以做到这一点 假设你已经有一个FB
  • 将图像转换为 pdf php

    我在用csxi http www chestysoft com ximage twainupload asp将文档扫描为图像 但我必须将 pdf 文件上传到服务器 如何在 php 中将图像转换为 PDF 或者有什么方法可以让 csxi 将文
  • 用于应用程序本地部署的 MSVC 2015 通用 CRT

    据宣布 通用 CRT 将是一个可重新分发的 DLL 这样应用程序本地部署仍然是可能的 我已经安装了 Visual Studio 2015 Express Edition 并且在 SDK 目录中查找 ucrtbase dll 但找不到任何内容
  • 如何添加第三方 Java JAR 文件以在 PySpark 中使用

    我有一些 Java 第三方数据库客户端库 我想通过访问它们 java gateway py 例如 要使客户端类 不是 JDBC 驱动程序 通过 Java 网关可供 Python 客户端使用 java import gateway jvm o
  • 将压缩半字节组合成压缩字节

    给定一个或多个 m128i or m256i每个 16 位元素包含一个半字节 将它们组合并打包为每个 8 位元素一个字节的最快方法是什么 即 hi lt lt 4 lo对于相邻的 16 位元素 这是我想出的最好方法 不幸的是它与标量代码相当