SSEでの整数からdoubleへの変換

利用してint値をdoubleに変換する次の処理をSSEに置き換えるのは次のコードですむ。

int i[4];
double d[4];

d[0] = (double)i[0]; d[1] = (double)i[1]; d[2] = (double)i[2]; d[3] = (double)i[3];
__m123i val; // なんらかの整数

__m128d d01 = _mm_cvtepi32_pd(val);// 前半2要素の変換
__m128d d23 = _mm_cvtepi32_pd(_mm_srli_si128(val, 8));// 後半2要素の変換

しかしuinsigned intをdoubleに変換する次の処理を置き換えるのは一気に複雑になる。

unsigned int i[4];
double d[4];

d[0] = (double)i[0]; d[1] = (double)i[1]; d[2] = (double)i[2]; d[3] = (double)i[3];
__m123i val; // なんらかの整数
__m128d zero = _mm_set1_pd(0.0); // 2つの0.0をセット
__m128d dmax = _mm_set1_pd(4294967296.0);

// 前半2要素

__m128d d01 = _mm_cvtepi32_pd(val);// doubleへ変換(ただしintとして変換される)
__m128d cmp0 = _mm_cmplt_pd(d01, zero);// 0.0より小さいかの判定
// 0.0より小さい場合だけ4294967296.0を加算する
__m128i ofs0 = _mm_and_si128(*(__m128i*)&cmp0, *(__m128i*)&dmax);
d01 = _mm_add_pd(d01, *(__m128d *)&ofs0);

// 後半2要素にも同じ事を行う
__m128d d23 = _mm_cvtepi32_pd(_mm_srli_si128(val, 8));
__m128d cmp1 = _mm_cmplt_pd(d23, zero);
__m128i ofs1 = _mm_and_si128(*(__m128i*)&cmp1, *(__m128i*)&dmax);
d23 = _mm_add_pd(d23, *(__m128d *)&ofs1);

もう少し命令数を減らせそうな気もするけど、思いつかない。