清除__m128i的高字节

2023-11-25

我该如何清除16 - ia 的高字节__m128i?

我已经尝试过这个;它有效,但我想知道是否有更好(更短,更快)的方法:

int i = ...  //  0 < i < 16

__m128i x = ...

__m128i mask = _mm_set_epi8(
    0,
    (i > 14) ? -1 : 0,
    (i > 13) ? -1 : 0,
    (i > 12) ? -1 : 0,
    (i > 11) ? -1 : 0,
    (i > 10) ? -1 : 0,
    (i >  9) ? -1 : 0,
    (i >  8) ? -1 : 0,
    (i >  7) ? -1 : 0,
    (i >  6) ? -1 : 0,
    (i >  5) ? -1 : 0,
    (i >  4) ? -1 : 0,
    (i >  3) ? -1 : 0,
    (i >  2) ? -1 : 0,
    (i >  1) ? -1 : 0,
    -1);

x = _mm_and_si128(x, mask);

我尝试了几种不同的方法来实现这一点,并在早期的 Core i7 @ 2.67 GHz 和最近的 Haswell @ 3.6 GHz 上使用几个不同的编译器对它们进行了基准测试:

//
// mask_shift_0
//
// use PSHUFB (note: SSSE3 required)
//

inline __m128i mask_shift_0(uint32_t n)
{
  const __m128i vmask = _mm_set1_epi8(255);
  const __m128i vperm = _mm_set_epi8(112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127);
  __m128i vp = _mm_add_epi8(vperm, _mm_set1_epi8(n));
  return _mm_shuffle_epi8(vmask, vp);
}

//
// mask_shift_1
//
// use 16 element LUT
//

inline __m128i mask_shift_1(uint32_t n)
{
  static const int8_t mask_lut[16][16] __attribute__ ((aligned(16))) = {
    { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
    { 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
    { 0, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
    { 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
    { 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
    { 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
    { 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
    { 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
    { 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1 },
    { 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1 },
    { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1 },
    { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1 },
    { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1 },
    { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1 },
    { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1 },
    { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1 }
  };
  return _mm_load_si128((__m128i *)&mask_lut[n]);
}

//
// mask_shift_2
//
// use misaligned load from 2 vector LUT
//

inline __m128i mask_shift_2(uint32_t n)
{
  static const int8_t mask_lut[32] = {
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
  };
  return _mm_loadu_si128((__m128i *)(mask_lut + 16 - n));
}

//
// mask_shift_3
//
// use compare and single vector LUT
//

inline __m128i mask_shift_3(uint32_t n)
{
  const __m128i vm = _mm_setr_epi8(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16);
  __m128i vn = _mm_set1_epi8(n);
  return _mm_cmpgt_epi8(vm, vn);
}

//
// mask_shift_4
//
// use jump table and immediate shifts
//

inline __m128i mask_shift_4(uint32_t n)
{
  const __m128i vmask = _mm_set1_epi8(-1);
  switch (n)
  {
    case 0:
      return vmask;
    case 1:
      return _mm_slli_si128(vmask, 1);
    case 2:
      return _mm_slli_si128(vmask, 2);
    case 3:
      return _mm_slli_si128(vmask, 3);
    case 4:
      return _mm_slli_si128(vmask, 4);
    case 5:
      return _mm_slli_si128(vmask, 5);
    case 6:
      return _mm_slli_si128(vmask, 6);
    case 7:
      return _mm_slli_si128(vmask, 7);
    case 8:
      return _mm_slli_si128(vmask, 8);
    case 9:
      return _mm_slli_si128(vmask, 9);
    case 10:
      return _mm_slli_si128(vmask, 10);
    case 11:
      return _mm_slli_si128(vmask, 11);
    case 12:
      return _mm_slli_si128(vmask, 12);
    case 13:
      return _mm_slli_si128(vmask, 13);
    case 14:
      return _mm_slli_si128(vmask, 14);
    case 15:
      return _mm_slli_si128(vmask, 15);
  }
}

//
// lsb_mask_0
//
// Contributed by by @Leeor/@dtb
//
// uses _mm_set_epi64x
//

inline __m128i lsb_mask_0(int n)
{
  if (n >= 8)
    return _mm_set_epi64x(~(-1LL << (n - 8) * 8), -1);
  else
    return _mm_set_epi64x(0, ~(-1LL << (n - 0) * 8));
}

//
// lsb_mask_1
//
// Contributed by by @Leeor/@dtb
//
// same as lsb_mask_0 but uses conditional operator instead of if/else
//

inline __m128i lsb_mask_1(int n)
{
  return _mm_set_epi64x(n >= 8 ? ~(-1LL << (n - 8) * 8) : 0, n >= 8 ? -1 : ~(-1LL << (n - 0) * 8));
}

结果很有趣:

酷睿 i7 @ 2.67 GHz、Apple LLVM gcc 4.2.1 (gcc -O3)

mask_shift_0: 2.23377 ns
mask_shift_1: 2.14724 ns
mask_shift_2: 2.14270 ns
mask_shift_3: 2.15063 ns
mask_shift_4: 2.98304 ns
lsb_mask_0:   2.15782 ns
lsb_mask_1:   2.96628 ns

酷睿 i7 @ 2.67 GHz、Apple clang 4.2 (clang -Os)

mask_shift_0: 1.35014 ns
mask_shift_1: 1.12789 ns
mask_shift_2: 1.04329 ns
mask_shift_3: 1.09258 ns
mask_shift_4: 2.01478 ns
lsb_mask_0:   1.70573 ns
lsb_mask_1:   1.84337 ns

Haswell E3-1285 @ 3.6 GHz,gcc 4.7.2 (gcc -O2)

mask_shift_0: 0.851416 ns
mask_shift_1: 0.575245 ns
mask_shift_2: 0.577746 ns
mask_shift_3: 0.850086 ns
mask_shift_4: 1.398270 ns
lsb_mask_0:   1.359660 ns
lsb_mask_1:   1.709720 ns

So mask_shift_4(switch/case) 似乎是所有情况下最慢的方法,而其他方法非常相似。基于 LUT 的方法似乎始终是最快的。

注意:我得到了一些令人怀疑的快速数字clang -O3 and gcc -O3(仅限 gcc 4.7.2) - 我需要查看这些情况下生成的程序集,以了解编译器正在做什么,并确保它没有做任何“聪明”的事情,例如优化时序测试工具的某些部分。

如果其他人对此有任何进一步的想法或有另一个 mask_shift 实现,他们想尝试,我很乐意将其添加到测试套件并更新结果。

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

清除__m128i的高字节 的相关文章

随机推荐

  • 使用 DataContext 从 LINQ 查询填充 DataTable 的最快方法

    我正在尝试运行 linq 查询 但我需要结果作为数据表 因为我使用它来将来自不同查询的记录存储在同一视图状态对象中 下面的 2 个版本可以编译 但返回一个空集 确切的错误是 值不能为空 参数名称 来源 是的 我已经检查过有数据 MyData
  • 当前分支没有跟踪信息

    我使用 github 的时间相对较短 并且一直使用客户端来执行提交和拉取 我昨天决定从 git bash 尝试一下 并成功创建了一个新的存储库并提交了文件 今天我从另一台计算机对存储库进行了更改 我已经提交了更改 现在我回到家并执行了git
  • React:读取history.push中作为参数传递的数据

    我是新来反应的 我正在尝试发送一些数据作为参数history push 基本上 我在单击按钮时调用一个方法 并在该方法内调用一个 api 如果我得到成功响应 我会重定向到其他页面 并且我还需要传递一些数据 下面是我的代码 class Log
  • 在 ElasticBeanstalk 上运行 Grunt

    我有一个节点应用程序 需要 grunt 进行 构建 然后应用程序才能成功执行 运行源代码的连接 缩小 加速等 我已经在具有 SSH 访问权限的 EC2 实例上运行了它 因为我可以通过 SSH 进入目录并在部署过程中运行 Grunt 然而 为
  • 为什么“gem”和“bundle”不使用相同的 libxml2?

    我似乎陷入了沮丧的递归循环中 我正在尝试 捆绑安装 一个项目 但结果是 An error occurred while installing nokogiri 1 6 6 2 and Bundler cannot continue Make
  • 如何防止两个CUDA程序互相干扰

    我注意到 如果两个用户尝试同时运行 CUDA 程序 它往往会锁定卡或驱动程序 或两者 我们需要重置卡或重新启动机器以恢复正常行为 有没有办法锁定 GPU 以便其他程序在运行时无法干扰它 Edit 操作系统是在服务器上运行的 Ubuntu 1
  • 在Java中,字符串是字符数组吗?

    我想知道 如果String是一个集合 我已经阅读了周围的内容 但仍然很困惑 字符串是不可变的表示字符序列的对象 CharSequence是 String 实现的接口之一 与字符数组和字符集合的主要区别 字符串无法修改 不可能 忽略反射 添加
  • 从两个日期之间的日期范围中选择数据

    我有一张名为Product Sales它保存这样的数据 Product ID Sold by Qty From date To date 3 12 7 2013 01 05 2013 01 07 6 22 14 2013 01 06 201
  • 如何在 React 中使用 RXJS fromEvent?

    我试图在反应中记录按钮上的点击事件 const InputBox gt const clicky fromEvent document getElementById clickMe click subscribe clickety gt c
  • 如何创建数组的随机排列?

    我已经用 C 编写了这个函数 我希望它创建一个随机排列或从 1 到 n 的数字列表 我很难让它没有重复的数字 因此 如果您有 n 4 我希望它返回一个包含 1 4 的随机数组 每个数组仅一次 例如 1 3 4 2 int random in
  • 如何使用 powershell 为 Windows 10 通用应用程序创建桌面快捷方式?

    我有一个创建的 UWP 应用程序 想要使用 powershell 在桌面上创建快捷方式 创建快捷方式对于 exe 来说很容易 TargetFile Path To MyProgram exe ShortcutFile env USERPRO
  • 访问相关对象键而不在App Engine中获取对象

    一般来说 对给定对象执行单个查询比执行多个查询更好 假设我有一堆 儿子 对象 每个对象都有一个 父亲 我得到了所有 儿子 对象 sons Son all 然后 我想找到那群儿子的所有父亲 我愿意 father keys for son in
  • 如何将GET参数传递给jsFiddle

    如何将GET参数传递给jsFiddle 我试过http jsfiddle net mKwcF id 123但我得到的只是http fiddle jshell net mKwcF show 我的示例 js 在上面给定的链接上很简单 alert
  • 如何让建议组件在 SolrNet 中工作?

    我已经配置了 solrconfig xml 和 schema xml 来查询建议 我可以从网址中获取建议 http localhost 8080 solr collection1 suggest q ha wt xml 我的 SolrCon
  • 现代 n 层 ASP.NET Web 应用程序示例?

    所以我的 asp net 非常非常生锈 我正在尝试回到最佳实践以及其他什么 因此 我快速搜索谷歌并开始寻找示例 示例和教程 但我找到了什么 甚至在石器时代 最新 技术发布之前就已经写了一些陈旧的硬壳东西 当然 这些概念可能仍然有效 但实际执
  • 以 UTC 存储时间总是一个好主意,还是在这种情况下以本地时间存储更好?

    一般来说 最好的做法是用 UTC 存储时间 如中所述here and here 假设有一个重复发生的事件 假设结束时间始终为同一当地时间 假设为 17 00 无论该时区是否启用夏令时 并且还要求在特定时区的 DST 打开或关闭时不要手动更改
  • 在 Android 中调整位图大小

    我使用以下代码调整位图的大小 FileOutputStream out new FileOutputStream sdcard mods png Bitmap bmp Bitmap createScaledBitmap pict int p
  • 将数字限制在某个范围内 (Haskell)

    我公开了一个带有两个参数的函数 一个是最小界限 另一个是最大界限 例如 如何使用类型确保最小界限不大于最大界限 我想避免创建一个智能构造函数并返回 Maybe 因为它会使整个使用更加麻烦 谢谢 这并不能完全回答你的问题 但有时有效的一种方法
  • AWS Cognito - 用户池联合与身份池联合

    Question 为什么 AWS Cognito 有两个位置来联合身份提供商 我认为身份池应该与身份提供商联合 并且想知道为什么用户池也可以 请说明为什么有两个地点的原因 Cognito Identity Pool can federate
  • 清除__m128i的高字节

    我该如何清除16 ia 的高字节 m128i 我已经尝试过这个 它有效 但我想知道是否有更好 更短 更快 的方法 int i 0 lt i lt 16 m128i x m128i mask mm set epi8 0 i gt 14 1 0