【问题标题】:ternary operator for clang's extended vectorsclang 扩展向量的三元运算符
【发布时间】:2014-10-10 07:41:31
【问题描述】:

我尝试过使用 clang 的 extended vectors。三元运算符应该可以工作,但它不适合我。示例:

int main()
{
  using int4 = int __attribute__((ext_vector_type(4)));

  int4 a{0, 1, 3, 4};
  int4 b{2, 1, 4, 5};

  auto const r(a - b ? a : b);

  return 0;
}

请提供我如何使其工作的示例,就像它在 OpenCL 下工作一样。我正在使用clang-3.4.2

错误:

t.cpp:8:16: error: value of type 'int __attribute__((ext_vector_type(4)))' is not contextually convertible to 'bool'
  auto const r(a - b ? a : b);
               ^~~~~
1 error generated.

【问题讨论】:

  • 它对我也不起作用godbolt.org/g/rt67UM
  • 我想出了一些解决方法,如果你愿意,我可以把它粘贴在这里。
  • 是的,请!回答自己的问题并没有错。即使是部分答案也比非.e好
  • @Zboson 已添加,希望对您有所帮助。

标签: c++ clang ternary-operator simd


【解决方案1】:

您可以直接在 Clang 中循环遍历元素。这是 GCC 和 Clang 的解决方案。

#include <inttypes.h>
#include <x86intrin.h>

#if defined(__clang__)
typedef float float4 __attribute__ ((ext_vector_type(4)));
typedef   int   int4 __attribute__ ((ext_vector_type(4)));
#else
typedef float float4 __attribute__ ((vector_size (sizeof(float)*4)));
typedef   int   int4 __attribute__ ((vector_size (sizeof(int)*4)));
#endif

float4 select(int4 s, float4 a, float4 b) {
  float4 c;
  #if defined(__GNUC__) && !defined(__INTEL_COMPILER) && !defined(__clang__)
  c = s ? a : b;
  #else
  for(int i=0; i<4; i++) c[i] = s[i] ? a[i] : b[i];
  #endif
  return c;
}

两者都生成

select(int __vector(4), float __vector(4), float __vector(4)):
  pxor xmm3, xmm3
  pcmpeqd xmm0, xmm3
  blendvps xmm1, xmm2, xmm0
  movaps xmm0, xmm1
  ret

但对于 AVX512,最好使用掩码(例如 __mmask16)。

【讨论】:

  • 这只是一种方法,使用索引序列更好。
  • @user1095108,很酷,我会调查一下并回复你。你能给我一个使用索引序列的例子吗?
  • @user1095108,太棒了!谢谢!给我几天时间看看你的代码并回复你。
【解决方案2】:

这在紧要关头有效:

auto const diff = a-b;
auto const ra( - (diff!=zero) * a - (diff==zero) *b);

我猜这是编译器或您链接的文档中的错误。

【讨论】:

  • 两者都有。我认为是this bug,这表明clang 确实为向量条件实现了?:,但仅限于OpenCL 上下文中。
  • 您提供了一种解决方法:) 乘法与三元运算符不同。
  • @user1095108 在 SIMD 硬件中,这通常更快。如果三元运算符不起作用,那不是我的错
  • @pqnet 我不知道。你确定吗?从我在使用 gcc 编译的代码中看到的 ?: 在代码中没有创建任何分支。
  • @user1095108 如果不是,因为它做了一些类似的操作。您是指运算符的矢量版本吗? gcc 支持吗?当然,如果编译器优化了三元运算符的最终代码和这个版本最终应该是一样的。但是请注意,此实现假定 true = -1,我在这种情况下观察到 true(但不能保证)
【解决方案3】:

最后我选择了这个:

#if defined(__clang__)
template <typename U, typename V>
constexpr inline std::enable_if_t<
  !std::is_arithmetic<V>{},
  V
>
select(V const a, V const b, U const c) noexcept
{
  return V((c & U(a)) | (~c & U(b)));
}
#else
template <typename U, typename V>
constexpr inline std::enable_if_t<
  !std::is_arithmetic<V>{},
  V
>
select(V const a, V const b, U const c) noexcept
{
  return c ? a : b;
}
#endif

同样可以通过其他方式完成,例如使用索引技巧,但它可能不会很好地优化(我不想要任何条件)。

【讨论】:

    猜你喜欢
    • 2015-06-10
    • 1970-01-01
    • 2021-12-05
    • 2017-09-20
    • 1970-01-01
    • 2021-12-08
    • 2020-10-21
    • 2012-09-07
    • 1970-01-01
    相关资源
    最近更新 更多