我已经开始使用SSE优化代码。本质上,它是一个光线跟踪器,通过将坐标存储在__m128数据类型x,y,z(四根射线的坐标按轴分组)中,一次处理四根射线。但是我有一个分支语句,可以防止被零除,但我似乎无法转换为SSE。依次为:
const float d = wZ == -1.0f ? 1.0f/( 1.0f-wZ) : 1.0f/(1.0f+wZ);
其中wZ是z坐标,并且需要对所有四条射线进行此计算。
如何将其转换为SSE?
我一直在尝试使用SSE相等比较,如下所示(现在wz属于__m128数据类型,其中包含四条射线中每条射线的z值):
_mm_cmpeq_ps(_mm_set1_ps(-1.0f) , wZ )
然后使用它来确定wZ [x] = -1.0的情况,取这种情况的绝对值,然后照常继续计算。
但是,我在这项工作中没有取得太大的成功。
最佳答案
这是一个相当简单的解决方案,它仅使用SSE即可实现标量代码,而无需进一步优化。它可能可以变得更有效率,例如通过利用wZ = -1.0时结果将为0.5的事实,或者甚至通过不考虑除法然后在事实之后将INF
s转换为0.5的事实。
与SSE4之前的版本相比,我为SSE4设置了#ifdef
d,因为SSE4具有“混合”指令,这可能比屏蔽和选择值所需要的三个SSE4之前的指令效率更高。
#include <emmintrin.h>
#ifdef __SSE4_1__
#include <smmintrin.h>
#endif
#include <stdio.h>
int main(void)
{
const __m128 vk1 = _mm_set1_ps(1.0f); // useful constants
const __m128 vk0 = _mm_set1_ps(0.0f);
__m128 wZ, d, d0, d1, vcmp;
#ifndef __SSE4_1__ // pre-SSE4 implementation
__m128 d0_masked, d1_masked;
#endif
wZ = _mm_set_ps(-1.0f, 0.0f, 1.0f, 2.0f); // test inputs
d0 = _mm_add_ps(vk1, wZ); // d0 = 1.0 - wZ
d1 = _mm_sub_ps(vk1, wZ); // d1 = 1.0 + wZ
vcmp = _mm_cmpneq_ps(d1, vk0); // test for d1 != 0.0, i.e. wZ != -1.0
#ifdef __SSE4_1__ // SSE4 implementation
d = _mm_blendv_ps(d0, d1, vcmp);
#else // pre-SSE4 implementation
d0_masked = _mm_andnot_ps(vcmp, d0);
d1_masked = _mm_and_ps(vcmp, d1);
d = _mm_or_ps(d0_masked, d1_masked); // d = wZ == -1.0 ? 1.0 / (1.0 - wZ) : 1.0 / (1.0 + wZ)
#endif
d = _mm_div_ps(vk1, d);
printf("wZ = %vf\n", wZ);
printf("d = %vf\n", d);
return 0;
}