次のように、.NET で利用可能な SIMD 組み込み関数を使用して、長さ <= 8 の符号なし整数文字列を解析するメソッドを実装しました。
public unsafe static uint ParseUint(string text)
{
fixed (char* c = text)
{
var parsed = Sse3.LoadDquVector128((byte*) c);
var shift = (8 - text.Length) * 2;
var shifted = Sse2.ShiftLeftLogical128BitLane(parsed,
(byte) (shift));
Vector128<byte> digit0 = Vector128.Create((byte) '0');
var reduced = Sse2.SubtractSaturate(shifted, digit0);
var shortMult = Vector128.Create(10, 1, 10, 1, 10, 1, 10, 1);
var collapsed2 = Sse2.MultiplyAddAdjacent(reduced.As<byte, short>(), shortMult);
var repack = Sse41.PackUnsignedSaturate(collapsed2, collapsed2);
var intMult = Vector128.Create((short)0, 0, 0, 0, 100, 1, 100, 1);
var collapsed3 = Sse2.MultiplyAddAdjacent(repack.As<ushort,short>(), intMult);
var e1 = collapsed3.GetElement(2);
var e2 = collapsed3.GetElement(3);
return (uint) (e1 * 10000 + e2);
}
}
悲しいことに、ベースラインと比較するとuint.Parse()
、次のようなやや印象に残らない結果が得られます。
方法 | 平均 | エラー | 標準偏差 |
---|---|---|---|
ベースライン | 15.157ns | 0.0325ns | 0.0304ns |
ParseSimd | 3.269ns | 0.0115ns | 0.0102ns |
上記のコードを改善するには、どのような方法がありますか? 私が特に関心を持っている分野は次のとおりです。
- SIMD レジスタのビット シフトが次のような計算で発生する方法
text.Length
- ~~ s の
MultiplyAddAdjacent
ベクトルを含むを使用した UTF-16 データのアンパックと~~0
1
- を使用して要素を抽出する方法
GetElement()
- おそらくToScalar()
どこかで発生する可能性のある呼び出しがありますか?