Note
ãã®ããŒãžã«ã¢ã¯ã»ã¹ããã«ã¯ãæ¿èªãå¿ èŠã§ãã ãµã€ã³ã€ã³ãŸãã¯ãã£ã¬ã¯ããªã®å€æŽã詊ãããšãã§ããŸãã
ãã®ããŒãžã«ã¢ã¯ã»ã¹ããã«ã¯ãæ¿èªãå¿ èŠã§ãã ãã£ã¬ã¯ããªã®å€æŽã詊ãããšãã§ããŸãã
SIMD (åäžåœä»€ãè€æ°ããŒã¿) ã¯ã1 ã€ã®åœä»€ãšäžŠè¡ããŠè€æ°ã®ããŒã¿ã« 1 ã€ã®æäœãé©çšããããã®ããŒããŠã§ã¢ ãµããŒãã§ãã ãã¯ã¿ãŒåãããã³ãŒãã§ã¯ãå埩ããšã« 1 ã€ã§ã¯ãªãè€æ°ã®å€ãåŠçãããŸããããã¯ãåãæäœããããã¡ãŒäžã§ç¹°ãè¿ãããæ°å€ãç§åŠçãã°ã©ãã£ãã¯ã¹ãããã¹ãåŠçãããŒã¿äžŠååŠçã®çš®é¡ã®ã¹ã«ãŒããããå€§å¹ ã«åäžãããããšãã§ããŸãã ãã¬ãŒããªãã¯è€éããå¢ãã®ã§ãå ¥åãååã«å€§ãããæž¬å®å€ã§åã¡ã確èªãããå Žåã«æãã¡ãªããããããŸãã
.NETã«ã¯ãããã€ãã®çš®é¡ã® SIMD ãµããŒããçšæãããŠããŸãã å¿ èŠãªã³ã³ãããŒã«ã®éãšãå®è¡ããå¿ èŠãããè€éãã®çšåºŠã«äžèŽãããã®ãéžæããŸãã
.NETã§ã® SIMD ãµããŒãã®çš®é¡
| API | åå空é | ãã€äœ¿çšããã |
|---|---|---|
| åºå®ç®çã®ãã¯ã¿ãŒåãšãããªãã¯ã¹å | System.Numerics | 2 ~ 4 åã®èŠçŽ ãã¯ãã«ãè¡åãåå æ°ãå¹³é¢ã䜿çšããã°ã©ãã£ãã¯ã¹ãšãžãªã¡ããªã®æ°åŠã |
Vector<T> |
System.Numerics | ãã©ãããã©ãŒã ããšã®å¶åŸ¡ãäžèŠãªå Žåã®ãããŒã¿ãã«ã§å¯å€å¹ ã®ãã¯ã¿ãŒåã |
Vector64<T>ãVector128<T>ãVector256<T>ãVector512<T> |
System.Runtime.Intrinsics | ãã现ããªå¶åŸ¡ã«ããã¯ãã¹ãã©ãããã©ãŒã ã®åºå®å¹ ãã¯ã¿ãŒåã ããã¯ãæ°ãããã¯ã¿ãŒåãããã¢ã«ãŽãªãºã ã®æšå¥šãããéå§ç¹ã§ãã |
| ããŒããŠã§ã¢çµã¿èŸŒã¿é¢æ° | System.Runtime.Intrinsics.X86ãSystem.Runtime.Intrinsics.ArmãSystem.Runtime.Intrinsics.Wasm | ããã ãã¹ã§ã®ããã©ãŒãã³ã¹ã®æåŸã®ãããã«ã€ããŠãäžäœã¬ãã«ã® API ã§å ¬éãããªãç¹å®ã®ããã»ããµåœä»€ã |
TensorPrimitives |
System.Numerics.Tensors | Span äžã§ããã«äœ¿ããããã¯ãã«åãããæ°åŠæŒç®ã èªåã§ãã¯ã¿ãŒåãè¡ããŸãã |
ãããã® API ãéè€ããå Žåã¯ãæœè±¡åã®ã¬ã€ã€ãŒãä»ããŠé¢é£ããŸãã ãžã§ããªã㯠ãã¯ã¿ãŒåã¯ãä»ã®ã¬ã€ã€ãŒãééããåºæ¬çãªã€ã³ã¿ãŒãã§ã³ãžåã§ãããããæè¡çã«ã¯æãäœãã¬ãã«ã§ããå¯å€å¹
ã®Vector<T>ã¯ãå®è¡äžã®ããŒããŠã§ã¢ããµããŒãããä»»æã®å¹
ã«æ¡åŒµãããVector64<T>ãéããŠåºå®å¹
ã®Vector512<T>ã«ãªããŸãã
System.Runtime.Intrinsics.X86ãSystem.Runtime.Intrinsics.Armãããã³System.Runtime.Intrinsics.Wasmã®ãã©ãããã©ãŒã åºæã®ããŒããŠã§ã¢çµã¿èŸŒã¿é¢æ°ã¯ããããã®åã«å¯ŸããŠåäœãããããããåã
ã®ããã»ããµåœä»€ã«çŽæ¥ãããã³ã°ãããŸãã ãžã§ããªãã¯åã§æäŸãããã¯ãã¹ãã©ãããã©ãŒã ã®æäœã¯ããã©ãããã©ãŒã åºæã®çµã¿èŸŒã¿é¢æ°ããäžæ®µäžã®æœè±¡åã¬ãã«ã«ãããã¿ãŒã²ããããšã«ããããžå€æãããŸãã ããé«ãå€ã¯ããããã¡ãŒå
šäœ ( Span<T> ãš stringã®ãã¯ã¿ãŒåãããã¡ãœãããããã³ TensorPrimitives) å
šäœã§åäœãããããŒãžã API ã§ããã以äžã®ã¬ã€ã€ãŒäžã«æ§ç¯ããããããææžããè¡ããã« SIMD ã¢ã¯ã»ã©ã¬ãŒã·ã§ã³ãååŸã§ããŸãã
System.Numericsåºå®å³åœ¢åã¯ããã®ã€ã³ã¿ãŒãã§ã³ãž ã¹ã¿ãã¯ã®äžéšã§ã¯ãªããã°ã©ãã£ãã¯ã¹ãšãžãªã¡ããªã®ãã¡ã€ã³åºæã®äŸ¿å©ãªåã§ãã
ãã®èšäºã®æ®ãã®éšåã§ã¯ããããã® API ãæé«ã¬ãã«ããæäœã¬ãã«ãŸã§åŠçãããã¹ãããã³ãããŒã¯ããã¹ã ãã©ã¯ãã£ã¹ã«ã€ããŠèª¬æããŸãã
System.Numerics ãã¯ã¿ãŒåãšãããªãã¯ã¹å
System.Numericsåå空éã¯ãåºå®åœ¢ç¶ã® SIMD ã¢ã¯ã»ã©ã¬ãŒã¿åãæäŸããŸãã
- Vector2ã Vector3ãããã³ Vector4 ã¯ã2ã3ã4 ã® Single å€ã®ãã¯ãã«ã衚ããŸãã
- Matrix3x2 Matrix4x4ã¯ãSingleå€ã® 3x2 ããã³ 4x4 è¡åã衚ããŸãã
- Plane ã¯ã3 次å 空éå ã®å¹³é¢ã衚ããŸãã
- Quaternion ã¯ã3 次å å転ã®ãšã³ã³ãŒãã«äœ¿çšããããã¯ãã«ã衚ããŸãã
ãããã®åã¯ã°ã©ãã£ãã¯ã¹ãšãžãªã¡ããªã«èªç¶ã«ããããããã©ã³ã¿ã€ã ã¯ãããŒããŠã§ã¢ããµããŒããã SIMD åœä»€ã䜿çšããŠæäœãé«éåããŸãã æ¬¡ã®äŸã§ã¯ã2 ã€ã®ãã¯ãã«ã远å ããŸãã
Vector2 v1 = Vector2.Create(0.1f, 0.2f);
Vector2 v2 = Vector2.Create(1.1f, 2.2f);
Vector2 sum = v1 + v2;
ãŸãããããç©ãè·é¢ãã¯ã©ã³ããªã©ãäºæ³ãããäžè¬çãªãã¯ãã«æŒç®ãå ¬éãããŸãã
float dot = Vector2.Dot(v1, v2);
float distance = Vector2.Distance(v1, v2);
Vector2 clamped = Vector2.Clamp(v1, Vector2.Zero, Vector2.One);
è¡ååã¯ã転眮ãä¹ç®ãªã©ã®è¡åã®ç®è¡æŒç®ããµããŒãããŸãã
Matrix4x4 m1 = Matrix4x4.Create(
1.1f, 1.2f, 1.3f, 1.4f,
2.1f, 2.2f, 3.3f, 4.4f,
3.1f, 3.2f, 3.3f, 3.4f,
4.1f, 4.2f, 4.3f, 4.4f);
Matrix4x4 m2 = Matrix4x4.Transpose(m1);
Matrix4x4 product = Matrix4x4.Multiply(m1, m2);
Vector<T>
Vector<T> ã¯ãããªããã£ãæ°å€åã®å¯å€å¹
ãã¯ãã«ã衚ããŸãã ãã®é·ãã¯ããã»ã¹ã®æå¹æéäžã«åºå®ãããŸããã Vector<T>.Count ã®å€ã¯ã³ãŒããå®è¡ãã CPU ã«ãã£ãŠç°ãªããŸãã Just-In-Time (JIT) ã³ã³ãã€ã©ã¯ Count ã宿°ãšããŠæ±ãã®ã§ãããã«å¯ŸããŠæžã蟌ãŸããã«ãŒãã¯é©åã«æé©åãããŸãã
Vector<T> ã§ã¯ãã³ã³ãã€ã«æã«ãã¯ã¿ãŒã®å¹
ãåãããªããŠãããã©ãããã©ãŒã ããšã®ã³ãŒããªãã§ç§»æ€å¯èœãªãã¯ã¿ãŒåãå¯èœã«ãªããŸãã æ¬¡ã®äŸã§ã¯ã2 ã€ã®é
åã®èŠçŽ ããšã®å ç®ãèšç®ããŸãã
// Illustrative: element-wise add with Vector<T>. In practice, prefer the already-accelerated
// TensorPrimitives.Add, which is optimized for every Vector<T>.IsSupported element type.
public static double[] Add(double[] left, double[] right)
{
ArgumentNullException.ThrowIfNull(left);
ArgumentNullException.ThrowIfNull(right);
ArgumentOutOfRangeException.ThrowIfNotEqual(right.Length, left.Length);
double[] result = new double[left.Length];
int i = 0;
// Vector<T>.Count is a JIT-time constant, so the compiler optimizes the loop bound.
int lastVectorStart = left.Length - Vector<double>.Count;
for (; i <= lastVectorStart; i += Vector<double>.Count)
{
Vector<double> v1 = Vector.Create(left.AsSpan(i));
Vector<double> v2 = Vector.Create(right.AsSpan(i));
(v1 + v2).CopyTo(result, i);
}
// Process any remaining elements that don't fill a full vector.
// Simplified for illustration: a scalar tail isn't optimal. A vectorized
// remainder that reprocesses the last full vector avoids the per-element loop.
for (; i < left.Length; i++)
{
result[i] = left[i] + right[i];
}
return result;
}
泚
ãã®äŸã¯äŸç€ºã§ãã
TensorPrimitivesã¯æ¢ã«é«éã¹ãã³ããŒã¹ã®æ°åŠãæäŸããŠããããããã®ãããªã«ãŒããæåã§èšè¿°ããå¿
èŠã¯ã»ãšãã©ãããŸããã ãã®èŠçŽ ããšã®è¿œå 㯠Addã§ããã Sum ãªã©ã®åæžãæäŸãããŸãã ãããã®æäœã¯ã Vector<T> ããµããŒãããèŠçŽ ã®çš®é¡ (Vector<T>.IsSupported) ã«å¯ŸããŠããŒããŠã§ã¢ã«ãã£ãŠé«éåãããŸãã
ããŒããŠã§ã¢ ã¢ã¯ã»ã©ã¬ãŒã·ã§ã³ã確èªãã
SIMD ã¢ã¯ã»ã©ã¬ãŒã¿åã¯ãéé«éãœãããŠã§ã¢å®è£
ã«ãã©ãŒã«ããã¯ãããããSIMD ããµããŒãããŠããªãããŒããŠã§ã¢ãŸã㯠JIT æ§æã§ãæ©èœããŸãã ã¢ã¯ã»ã©ã¬ãŒã·ã§ã³ãå®éã«äœ¿çšå¯èœãã©ãããåå²ããã«ã¯ãé¢é£ãã IsHardwareAccelerated ããããã£ã確èªããŸãã
-
Vector.IsHardwareAccelerated ã¯ã
Vector<T>æäœãé«éåãããŠãããã©ãããå ±åããŸãã -
Vector128.IsHardwareAcceleratedãšåçã®
Vector64/Vector256/Vector512ãåºå®å¹ ããšã«å é床ãå ±åããŸãã
ãããã®ããããã£ã¯ JIT ã«ãã£ãŠå®æ°ã«å€æããããããå®è¡ããªããã©ã³ãã¯åé€ããããã§ãã¯ã®å®è¡æã³ã¹ãã¯çºçããŸããã å€ããã£ãã·ã¥ããªãã§ãã ãããå¿
èŠãªå Žæã§çŽæ¥èªã¿åãã
Countãããã㣠(Vector128<T>.Count ãªã©) ã«ãåãããšãåœãŠã¯ãŸããŸãããã㯠JIT æå®æ°ã§ããããŸãã
æ¡åŒµå¹
ã«å¯Ÿããã»ãšãã©ã®æäœã¯ããèªäœãé«éåãããŸããããã¹ãŠã®æŒç®ã«ã€ããŠãããä¿èšŒãããããã§ã¯ãããŸããã ããšãã°ãæŽæ°é€ç®ãè¡ãããŠããªãå Žåã¯ãæµ®åå°æ°ç¹é€ç®ãé«éåãããå ŽåããããŸãã
Vector256ãé«éåããããšãéåžžã¯Vector128ãè¡ãããŸãããä¿èšŒã¯ãªãããã䜿çšããåå¹
ã確èªããŠãã ããã
ãã³ã
å¿ èŠãªæäœããé¢å¿ã®ãããã©ãããã©ãŒã ã§é«éåãããŠããªãå ŽåããŸãã¯æ°ããã¯ãã¹ãã©ãããã©ãŒã API ãå¿ èŠãªå Žåã¯ã dotnet/runtime ã«åé¡ãæåºããŠãã ããã åãããšããcodegen ã®æ©èœåŒ·åã«ãåœãŠã¯ãŸããŸãã
ãã¹ãŠã®èŠçŽ åããã¹ãŠã®ãã¯ã¿ãŒã«å¯ŸããŠæå¹ãªããã§ã¯ãããŸããã
Vector128<T> ããã³ãã®å
åŒã¯ãçŸåšãããªããã£ãæ°å€å (byteã sbyteã shortã ushortã intã uintã longã ulongã floatã doubleã nintã nuint) ããµããŒãããŠããããã®ã»ããã¯å°æ¥ä»ã®åãå«ãããã«æ¡åŒµãããå¯èœæ§ããããŸãã
Vector128<T>.IsSupportedã䜿çšããŠãç¹å®ã®Tãæå¹ãã©ããã倿ããŸããããã¯ããžã§ããªã㯠ã³ãŒãã§ç¹ã«åœ¹ç«ã¡ãŸãã
charãboolãªã©ããµããŒããããŠããªãåã¯ããããã¡ãŒãåããµã€ãºã®ãµããŒããããŠããåãšããŠåè§£éããããšã§ãã¯ã¿ãŒåã§ããŸãã
Castã䜿çšããŠã¹ãã³ (ããšãã°ãcharã«ushort) ãåè§£éãããããã¯ã¿ãŒã®As<TFrom, TTo>ã¡ãœããã䜿çšããŠãæ¢ã«ä¿æããŠãããã¯ã¿ãŒãåè§£éããŸãã åè§£éã§ã¯ãåºã«ãªããããã§ã¯ãªãåã®ã¿ã倿ŽããããããããŒã¿ãæŽåœ¢åŒã«ä¿ã€ã®ã¯ãŠãŒã¶ãŒã®è²¬ä»»ã§ãã bool 㯠0 ãŸã㯠1ã®ãŸãŸã«ããå¿
èŠãããã char ã¯æå¹ãª UTF-16 ã³ãŒãåäœã®ãŸãŸã§ããå¿
èŠããããŸãã ãã¯ã¿ãŒåãããæäœã§ç¯å²å€ã®å€ãçæãããå¯èœæ§ãããå Žåã¯ãæžãæ»ãåã«çµæãæ£èŠåããããã«æ³šæããŠãã ããã
Vector128 ã䜿çšããã¯ãã¹ãã©ãããã©ãŒã ãã¯ã¿ãŒå
Vector128<T> ã¯ãã¯ã¿ãŒåããµããŒããããã¹ãŠã®ãã©ãããã©ãŒã ã§å
±éã®åæ¯ã§ãããããå§ããã®ã«æé©ãªå Žæã§ãã 128 ãããã®ãã¯ãã«ãæ ŒçŽããŸã: 16 ãã€ãã8 ã® shortã4 ã® int ãŸã㯠floatãããã㯠2 ã® long ãŸã㯠double ã«çžåœããŸãã
------------------------------128-bits---------------------------
| 64 | 64 |
-----------------------------------------------------------------
| 32 | 32 | 32 | 32 |
-----------------------------------------------------------------
| 16 | 16 | 16 | 16 | 16 | 16 | 16 | 16 |
-----------------------------------------------------------------
| 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 |
-----------------------------------------------------------------
Vector256<T> ã¯å¹
ã 2 åãããVector512<T> ã¯ããã«ãã® 2 åã§ãã ãã¹ãŠã®ããŒããŠã§ã¢ã§å€§ããªå¹
ããµããŒããããŠããããã§ã¯ãªããããæ¬¡ã®äŸã§ã¯ç§»æ€æ§ã®ããã« Vector128 ã䜿çšããŠããŸãã
åå¹
ã«ã¯ãããŒã¿ã®ãžã§ããªãã¯å (Vector128<T>) ãšãVector128ãCreateãªã©ã®éçãã¡ã¯ã㪠ã¡ãœãããªã©ãã»ãšãã©ã®æäœãä¿æããéãžã§ããªãã¯éçã¯ã©ã¹ (Load) ããããŸãã
+ã&ã<<ãªã©ã®æŒç®åã¯ãç®è¡æŒç®ãšãããæŒç®ã衚çŸããæ
£çšçãªæ¹æ³ã§ããæŒç®åã®åªå
é äœã®ãã°ãåé¿ããèªã¿ããããåäžãããããã«ãååä»ãã¡ãœãããšåçã®æŒç®åãããæŒç®åãåªå
ããŸãã ãã€ãé ã«äŸåããã¢ã«ãŽãªãºã ã«ã€ããŠã¯ãIsLittleEndian ã§åå²ãè¡ã£ãŠãã ãããJIT ãããã宿°ã«ãã©ãŒã«ãããŸãã
泚
x86/x64 ã§ã¯ã Vector256<T> æäœã¯éåžžã2 ã€ã®ç¬ç«ãã 128 ããã "ã¬ãŒã³" ãšããŠæ±ãããŸãã ã»ãšãã©ã®èŠçŽ ããšã®æäœã§ã¯ééçã§ãããã¬ãŒã³ããŸããæäœ (ã·ã£ããã«ããã¢ã¯ã€ãº/æ°Žå¹³æäœãªã©) ã®åäœãç°ãªãå Žåããåçã® Vector128 ãããã³ã¹ããé«ãå ŽåããããŸãã ããåºããã¯ãã«ãé«éã§ãããšæ³å®ããåã«ããã³ãããŒã¯ã§ç¢ºèªããŠãã ããã
ã¬ãŒã³ã®æšªææäœã§ã¯å¹ ãèªåçã«æ¡å€§ãããããã§ã¯ãããŸãã
èŠçŽ ããšã®æäœã¯å¹
ãæ°ã«ããŸããã v1 + v2 ã¯ã v1 ãš v2 ã Vector128<T> ã Vector256<T>ãã«é¢ä¿ãªããèŠçŽ ããšã®çµæãšåãã§ãããåœä»€ããšã«ãã 1 ã¬ãŒã³åã®ããŒã¿ãåŠçããã ãã§ãã
Add
v = [a, b, c, d]ãšw = [e, f, g, h]ã§ã¯åžžã«åãã€ã³ããã¯ã¹èŠçŽ ãçµåãããŸãã
v: [ a | b | c | d ]
w: [ e | f | g | h ]
+ + + +
r: [a+e|b+f|c+g|d+h]
ã©ã®èŠçŽ ãçµåããããã¯ãã¯ã¿ãŒã®å¹ ã«ãã£ãŠç°ãªããããã¬ãŒã³äº€å·®æäœã§ã¯åçŽã«ã¹ã±ãŒã«ã¢ãããããŸããã ãã¢ã¯ã€ãºçž®å°ã§ã¯ãåãã€ã³ããã¯ã¹ã®èŠçŽ ã§ã¯ãªã 飿¥ãã èŠçŽ ãçµåããããããæ¡å€§ãããšããã¢ã«ãªã£ãèŠçŽ ãå€ãããŸãã
v: [ a | b | c | d ]
\_____/ \_____/
round 1: [ a+b | c+d | a+b | c+d ]
\_________________/
round 2: [ S | S | S | S ] (S = a+b+c+d)
ãŸãã«ãããæ°Žå¹³ãªãã¯ã·ã§ã³ã§ãããã¯ãã«ã®èŠçŽ ãã2 åã®ãã¢ã¯ã€ãºå ç®ã§åèšããŸãã x86/x64 ã§ã¯ã Vector128<float> (4 åã®èŠçŽ ) ã䜿çšããŠã HorizontalAddã 2 ååŒã³åºããŸãã
// Sums all four elements with two rounds of pairwise horizontal adds.
// HorizontalAdd(v, v) on [a, b, c, d] gives [a+b, c+d, a+b, c+d]; a second round
// collapses that to the full sum in every element.
public static float SumVector128(Vector128<float> v)
{
Debug.Assert(Sse3.IsSupported);
Vector128<float> step1 = Sse3.HorizontalAdd(v, v);
Vector128<float> step2 = Sse3.HorizontalAdd(step1, step1);
return step2.ToScalar();
}
åã 2 ååŒã³åºãã®ãã¿ãŒã³ã Vector256<float>ïŒ8 èŠçŽ ïŒã«ãåœãŠã¯ãããšãæ£ããèŠããŸãããå®éã«ã¯ããã§ã¯ãããŸããã
HorizontalAdd ã¯ã256 ããã ãã¯ãã«å
šäœã§åäœããŸãããå 128 ããã ã¬ãŒã³å
ã§ãã¢ã¯ã€ãº ãã¿ãŒã³ãåå¥ã«ç¹°ãè¿ããŸãã 2 ã€ã®ã©ãŠã³ãã䜿çšãããšãäžäœã¬ãŒã³ã®åèš (èŠçŽ 0 ãã 3) ãäžéšã¬ãŒã³å
šäœã§ãããŒããã£ã¹ããããäžäœã¬ãŒã³ã®åèš (èŠçŽ 4 ãã 7) ãäžäœã¬ãŒã³å
šäœã«ãããŒããã£ã¹ããããŸãã8 ã€ã®èŠçŽ ã®åèšã§ã¯ãããŸããã
// The same two-round pattern on Vector256<float> looks like it should sum all eight
// elements, but Avx.HorizontalAdd repeats the pairwise pattern independently within
// each 128-bit lane. The result holds the lower lane's sum (elements 0-3) broadcast
// across the lower lane and the upper lane's sum (elements 4-7) broadcast across the
// upper lane -- ToScalar only returns the lower lane's partial sum, not the total.
public static float SumVector256Naive(Vector256<float> v)
{
Debug.Assert(Avx.IsSupported);
Vector256<float> step1 = Avx.HorizontalAdd(v, v);
Vector256<float> step2 = Avx.HorizontalAdd(step1, step1);
return step2.ToScalar();
}
æ£ããåèšãååŸããã«ã¯ãã¬ãŒã³å¢çãæç€ºçã«ããªããžããŸããåã¬ãŒã³ã®éšååèšã GetLower/GetUpper ã§èªã¿åããããããå ç®ããŸããGetLower ããŠããã¯ãã«ã 1 çªç®ãš 2 çªç®ã®ååã«åå² GetUpper ããŸãã
------------------------------128-bits---------------------------
| LOWER | UPPER |
-----------------------------------------------------------------
| 32 | 32 | 32 | 32 |
-----------------------------------------------------------------
| 16 | 16 | 16 | 16 | 16 | 16 | 16 | 16 |
-----------------------------------------------------------------
| 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 |
-----------------------------------------------------------------
// Getting the full sum needs an explicit step to cross the lane boundary: read each
// lane's partial sum out with GetLower/GetUpper and add them together.
public static float SumVector256(Vector256<float> v)
{
Debug.Assert(Avx.IsSupported);
Vector256<float> step1 = Avx.HorizontalAdd(v, v);
Vector256<float> step2 = Avx.HorizontalAdd(step1, step1);
Vector128<float> lower = step2.GetLower();
Vector128<float> upper = step2.GetUpper();
return lower.ToScalar() + upper.ToScalar();
}
ãã®äœåãªã¹ãããã¯ãè»ç·ã暪æããå®éã®ã³ã¹ãã§ãã ã¬ãŒã³ããŸããã¢ã«ãŽãªãºã ã¯ãèŠçŽ åäœã®ã¢ã«ãŽãªãºã ã®ããã«ãã ã§ãã®ãŸãŸãã¯ãã«å¹ ãåºããããããã§ã¯ãªãããã¯ãã«å¹ ãåºãã»ããæå©ã ãšæ±ºãã€ããåã«ããŸãèšæž¬ãã¹ãã ã
äžè¬çãªæäœ
Vector128 ãšãã®äžäœã®é¢é£è£œåã¯ãåºç¯ãª API ãå
¬éããŠããŸãã ãããèŠããå¿
èŠã¯ãããŸãããã«ããŽãªãç¥ããå¿
èŠãªãšãã«è©³çްã調ã¹ãŸãã ãã¹ãŠã®æäœã«ã¯ãé«éåã§ããªããã©ãããã©ãŒã çšã®ãœãããŠã§ã¢ ãã©ãŒã«ããã¯ããããŸãã æ¬¡ã®è¡šã¯ãåºæ¬çã«è¡šé¢å
šäœã衚ããŠããŸãã
| Category | ãããäœãããã | 代衚ç㪠API |
|---|---|---|
| Constants | å®çŸ©æžã¿ã®å®æ°ãã¯ãã« |
ZeroãOneãNegativeOneãAllBitsSetãIndicesãSignSequenceãEãPiãTauãEpsilonãNaNãPositiveInfinityãNegativeInfinityãNegativeZero |
| äœæ | ã¹ã«ã©ãŒã®ãããŒããã£ã¹ããèŠçŽ ã®èšå®ããŸãã¯ã·ãŒã±ã³ã¹ã®çæ |
Createã CreateScalarã CreateScalarUnsafeã Create(ReadOnlySpan<T>)ã CreateSequenceã CreateGeometricSequenceã CreateHarmonicSequenceã CreateAlternatingSequence |
| èªã¿èŸŒã¿ãšæ ŒçŽ | ã¡ã¢ãªãšãã¯ã¿ãŒã®éã§ããŒã¿ãç§»åãã |
LoadãLoadUnsafeãLoadAlignedãLoadAlignedNonTemporalãStoreãStoreUnsafeãStoreAlignedãStoreAlignedNonTemporalãCopyToãTryCopyTo |
| ç®è¡ | èŠçŽ ããšã®æ°åŠãšåæž |
Add (x + y)ãSubtract (x - y)ãMultiply (x * y)ãDivide (x / y)ãNegate (-x)ãAddSaturateãSubtractSaturateãAbsãSqrtãFusedMultiplyAddãDotãSum |
| ãããæŒç® | ãããããšã®ããžãã¯ãšã·ãã |
BitwiseAnd (x & y)ã BitwiseOr (x \| y)ã Xor (x ^ y)ã AndNot (x & ~y)ã OnesComplement (~x)ã ShiftLeft (x << n)ã ShiftRightArithmetic (x >> n)ã ShiftRightLogical (x >>> n) |
| æå°å€ãæå€§å€ãã¯ã©ã³ã | èŠçŽ ããšã®æå°å€ãæå€§å€ãããã³ç¯å²ã¯ã©ã³ãåŠç |
Minã Maxã Clampã MinMagnitudeã MaxMagnitudeã MinNumberã MaxNumberã MinMagnitudeNumberã MaxMagnitudeNumber |
| äžžã | åèŠçŽ ãæŽæ°å€ã«äžžãã |
CeilingãFloorãRoundãTruncate |
| ç®è¡é¢æ° | 笊å·ãè£éãè§åºŠãè¶ è¶é¢æ°ã®ãã«ããŒé¢æ° |
CopySignãLerpãDegreesToRadiansãRadiansToDegreesãHypotãSinãCosãSinCosãAsinãExpãLogãLog2 |
| Comparison | åèŠçŽ ãæ¯èŒããŸããçµæã¯ãã¯ãã« ãã¹ã¯ã§ãããæŒç®åãäžãã bool ã§ã¯ãããŸãã |
EqualsãGreaterThanãGreaterThanOrEqualãLessThanãLessThanOrEqual |
| Classification | æ°çŽç·äžã®åèŠçŽ ã«å¯Ÿããè¿°èªã§ããããããã¯ã¿ãŒ ãã¹ã¯ãè¿ããŸã |
IsNaNã IsFiniteã IsInfinityã IsPositiveInfinityã IsNegativeInfinityã IsIntegerã IsEvenIntegerã IsOddIntegerã IsNegativeã IsPositiveã IsNormalã IsSubnormalã IsZero |
| æ¯èŒåæ°ã®åæž | èŠçŽ ããšã®æ¯èŒãåäžã®æ¯èŒã«æãããã bool |
EqualsAll (x == y)ãEqualsAnyãGreaterThanAllãGreaterThanAnyãGreaterThanOrEqualAllãGreaterThanOrEqualAnyãLessThanAllãLessThanAnyãLessThanOrEqualAllãLessThanOrEqualAny |
| ãã¯ãã«å šäœã«å¯Ÿããè¿°èª | ãã¯ãã«ã bool ã«éçŽããŸãããã¹ãŠã®èŠçŽ ãããå€ã«çããããããããã®èŠçŽ ããã®å€ã«çãããããŸãã¯ã©ã®èŠçŽ ããã®å€ã«çãããªããããããã¯ïŒWhereAllBitsSet 圢åŒã§ã¯ïŒãã¹ãŠã®ããããèšå®ãããŠãããã©ãããå€å®ããŸãã ãã¹ã¯ãã€ã³ããã¯ã¹ã«å€æãã代ããã«ããã¡ãã䜿çšããŠãã ãã |
Allã Anyã Noneã AllWhereAllBitsSetã AnyWhereAllBitsSetã NoneWhereAllBitsSet |
| Search | å€ã«ãã£ãŠèŠçŽ ãã«ãŠã³ããŸãã¯ç¹å®ããããããã¯ïŒWhereAllBitsSet 圢åŒã§ã¯ïŒãã¹ã¯å
ã®ã¬ãŒã³ãèšå®ãã |
Countã IndexOfã LastIndexOfã CountWhereAllBitsSetã IndexOfWhereAllBitsSetã LastIndexOfWhereAllBitsSet |
| ã€ã³ããã¯ã¹ã«ãã¹ã¯ãã | æ¯èŒãã¹ã¯ãã¹ã«ã©ãŒ ããããã¹ã¯ã«å€æããŠã¹ãã£ã³ãã |
ExtractMostSignificantBits ã§ TrailingZeroCount ãŸã㯠LeadingZeroCount |
| [éžæ] | ãã¹ã¯ã«åŸã£ãŠ 2 ã€ã®ãã¯ãã«ããããåäœã§ãã¬ã³ããã |
ConditionalSelect(x, y, z)ã«çžåœããŸãã (y & x) \| (z & ~x) |
| Conversion | æ°å€åã倿Žããæ°ããå€ãèšç®ãã (ããšãã°ã int ã float) |
ConvertToInt32ã ConvertToInt64ã ConvertToUInt32ã ConvertToUInt64ã ConvertToSingleã ConvertToDouble |
| æ¡å€§ãšçž®å° | èŠçŽ ãããåºãåã«åå²ããããããçãåã«ããã¯ãã |
WidenãWidenLowerãWidenUpperãNarrowãNarrowWithSaturation |
| åè§£é | ãããã倿Žããã«å¥ã®èŠçŽ åãšããŠåè§£éãã |
As<TFrom, TTo>ã AsByteã AsInt32ã AsSingleãããã³ãã®ä»ã® As* èŠçŽ ãã©ãŒã |
| System.Numerics çžäºéçšæ©èœ |
Vector128<T>ãšåºå®å³åœ¢ã®æ°å€åã®éã§åè§£éãã |
AsVectorã AsVector2ã AsVector3ã AsVector4ã AsPlaneã AsQuaternionã AsVector128ã AsVector128Unsafe |
| Reorder | ã€ã³ããã¯ã¹ã䜿çšããŠèŠçŽ ãåé 眮ãããã2 ã€ã®ãã¯ãã«ãã€ã³ã¿ãŒãªãŒããã |
ShuffleãReverseãZipãZipLowerãZipUpperãUnzipãUnzipEvenãUnzipOddãConcatLowerLowerãConcatLowerUpperãConcatUpperLowerãConcatUpperUpper |
| è»ç·ãžã®ã¢ã¯ã»ã¹ | åã ã®èŠçŽ ãšååãèªã¿åãã眮æãããããã¯ã¿ãŒã®ãµã€ãºã倿ŽããŸã |
GetElementã WithElementã ToScalarã GetLowerã GetUpperã WithLowerã WithUpperã ToVector256 |
ãã³ã
ããã€ãã®æäœã«ã¯ãEstimateãNativeãMultiplyAddEstimateãClampNativeãMinNativeãMaxNativeãªã©ãShuffleNativeãšConvertToInt32Nativeããªã¢ã³ãããããŸãã ãããã¯ã粟床ãå€å°ç ç²ã«ããããIEEE ã®ãšããžã±ãŒã¹ä¿èšŒïŒNaN ã®æ±ããªã©ïŒãæŸæ£ããããã代ããã«ãããé«éãªããŒããŠã§ã¢åœä»€ã«ããããããŸãããã®ããããã³ãããŒã¯ã«ãã£ãŠå³å¯çãããã«ããã¯ã§ããããšã瀺ããããã€ç·©åãããæå³è«ã蚱容ã§ããå Žåã«ã®ã¿äœ¿çšããŠãã ããã
泚
Vector256.Shuffle ã¯ããã®å
¥åãåäžã® 256 ããã ãã¯ãã«ãšããŠæ±ããŸãããã©ãããã©ãŒã åºæã® Avx2.Shuffle 㯠2 ã€ã®ç¬ç«ãã 128 ããã ã¬ãŒã³ãšããŠåäœããŸãã ã¯ãã¹ãã©ãããã©ãŒã API ã¯ç§»æ€æ§ã®é«ãéžæè¢ã§ãããæåã§èšè¿°ãããçµã¿èŸŒã¿é¢æ°ãç§»æ€ãããšãã«å¿
èŠãªåäœã確èªããŸãã
ã³ãŒã ãã¹ãæ§æãã
ãã¯ã¿ãŒåãããã¡ãœããã¯éåžžããã¯ã¿ãŒå¹ ããšã®ãã¹ã«åå²ããããã«å ¥åãµã€ãºãå°ããå Žåãã¢ã¯ã»ã©ã¬ãŒã·ã§ã³ã«å¯Ÿå¿ããŠããªãããŒããŠã§ã¢åãã«ã¹ã«ã©ãŒåŠçãžã®ãã©ãŒã«ããã¯ãåããŸãã ããŒããŠã§ã¢ã§ãµããŒããããŠããæå€§ã®ãã¯ã¿ãŒã䜿çšããã«ã¯ãæåã«æãåºããã¯ã¿ãŒã確èªããæ¬¡ã®æäœãè¡ããŸãã
// Sums a buffer, choosing the widest vector the hardware and element type support.
public static T Sum<T>(ReadOnlySpan<T> buffer)
where T : unmanaged, INumberBase<T>
{
// The widest-first order continues with the Vector512 and Vector256 paths, which belong
// here ahead of the Vector128 block below. They're identical to it aside from the wider
// type (for example, Vector512<T> with Vector512.Create and Vector512.Sum), so they're
// omitted for brevity:
//
// if (Vector512.IsHardwareAccelerated && Vector512<T>.IsSupported)
// {
// if (buffer.Length >= Vector512<T>.Count)
// {
// return SumVector512(buffer);
// }
// return SumVectorSmall(buffer);
// }
//
// if (Vector256.IsHardwareAccelerated && Vector256<T>.IsSupported)
// {
// if (buffer.Length >= Vector256<T>.Count)
// {
// return SumVector256(buffer);
// }
// return SumVectorSmall(buffer);
// }
if (Vector128.IsHardwareAccelerated && Vector128<T>.IsSupported)
{
if (buffer.Length >= Vector128<T>.Count)
{
return SumVector128(buffer);
}
return SumVectorSmall(buffer);
}
return SumScalar(buffer);
}
åå¹
ã®å€åŽã¬ãŒãã¯ã Vector128.IsHardwareAccelerated (ãã©ãããã©ãŒã ããã®å¹
ãé«éåãããã©ããã瀺ã JIT æé宿°) ãš Vector128<T>.IsSupported (èŠçŽ ã®çš®é¡ T ããã®å¹
ã«å¯ŸããŠæå¹ãã©ãã) ãçµã¿åããããã®ã§ãã ãµããŒããããŠãããããã¯å
ã§ãå
¥åã®é·ãã Count ãšæ¯èŒããŠããã¯ã¿ãŒåããããã¹ãšå°ããªå
¥åãã©ãŒã«ããã¯ã®ã©ã¡ãããéžæããŸãã ãã®ã¡ãœãã㯠T ã«å¯ŸããŠãžã§ããªãã¯ã§ãããVector256 ãããã¯ãš Vector512 ãããã¯ã¯ãããåºãåã䜿çšããŠããç¹ãé€ãã° Vector128 ãããã¯ãšåäžã§ãããç°¡æœã«ããããã³ã¡ã³ãã¢ãŠãããŠç€ºãããŠããŸãã
2 ã€ã®ç°ãªããã©ãŒã«ããã¯ããããŸãã æãçããã¯ãã«ã§ãã£ãŠãå°ãããããããã¡ãŒããé«éããŒããŠã§ã¢ã§ã¯ãã«ãŒããªãã§å¯èœãªãµããã¯ãã«ã®é·ããåŠçããæç€ºçãªSumVectorSmallãžã£ã³ã ããŒãã«ã§ããswitchã«ç§»åããŸãã
// Sums a buffer smaller than the widest vector. The complete "optimal" shape dispatches on the
// element width so each width uses a switch jump table sized to the number of elements that fit
// in the widest vector (63 for byte, 31 for short, 15 for int/float, 7 for long/double).
private static T SumVectorSmall<T>(ReadOnlySpan<T> buffer)
where T : unmanaged, INumberBase<T>
{
// sizeof(T) is a JIT constant, so only the matching branch survives for a given T.
if (sizeof(T) == 4)
{
return SumVectorSmall4(buffer);
}
// The 1-, 2-, and 8-byte tables share the shape below, sized for their element width.
// They're omitted for brevity, so those widths fall back to a scalar loop here:
//
// if (sizeof(T) == 1) return SumVectorSmall1(buffer); // switch over lengths 0..63
// if (sizeof(T) == 2) return SumVectorSmall2(buffer); // switch over lengths 0..31
// if (sizeof(T) == 8) return SumVectorSmall8(buffer); // switch over lengths 0..7
return SumScalar(buffer);
}
private static T SumVectorSmall4<T>(ReadOnlySpan<T> buffer)
where T : unmanaged, INumberBase<T>
{
Debug.Assert(sizeof(T) == 4);
Debug.Assert(buffer.Length < Vector512<T>.Count);
T result = T.Zero;
// A 4-byte element gives Count == 4/8/16 for Vector128/256/512, so a remainder can be up to
// 15 elements. The larger cases fold the leftover with the widest vector that fits, using two
// overlapping loads (one from the start, one from the end) rather than recursingâthe shape
// TensorPrimitives uses. The loads overlap for lengths that aren't an exact multiple of the
// width, so the tail is masked down to the additive identity before it's summed. That mask is
// only needed because addition is non-idempotent; an idempotent operation such as a search
// could fold the overlapping tail in directly.
switch (buffer.Length)
{
// One or two Vector256's worth of data.
case 15:
case 14:
case 13:
case 12:
case 11:
case 10:
case 9:
case 8:
{
Vector256<T> beg = Vector256.Create(buffer);
Vector256<T> end = Vector256.Create(buffer.Slice(buffer.Length - Vector256<T>.Count));
Vector256<T> msk = CreateRemainderMask256<T>(buffer.Length - Vector256<T>.Count);
end = Vector256.ConditionalSelect(msk, end, Vector256<T>.Zero);
result = Vector256.Sum(beg + end);
break;
}
// One or two Vector128's worth of data.
case 7:
case 6:
case 5:
case 4:
{
Vector128<T> beg = Vector128.Create(buffer);
Vector128<T> end = Vector128.Create(buffer.Slice(buffer.Length - Vector128<T>.Count));
Vector128<T> msk = CreateRemainderMask128<T>(buffer.Length - Vector128<T>.Count);
end = Vector128.ConditionalSelect(msk, end, Vector128<T>.Zero);
result = Vector128.Sum(beg + end);
break;
}
// Smaller than a single vector: each case falls through to the next, accumulating one
// element per label.
case 3:
{
result += buffer[2];
goto case 2;
}
case 2:
{
result += buffer[1];
goto case 1;
}
case 1:
{
result += buffer[0];
goto case 0;
}
case 0:
{
break;
}
}
return result;
}
// Builds a mask whose last `keepLast` lanes are all-bits-set and the rest zero, so an overlapping
// tail load can be folded in without double-counting the lanes the head already covered.
// TensorPrimitives uses an internal table-based helper. The mask is only a bit pattern keyed on
// lane width, so it's built with the same-width integer Indices ([0, 1, 2, ...]) and reinterpreted
// to T: integer comparisons are cheaper than floating-point ones, so a float/double table would
// still compare as int/long rather than in its own element type.
private static Vector256<T> CreateRemainderMask256<T>(int keepLast)
where T : unmanaged, INumberBase<T>
{
Debug.Assert(sizeof(T) == 4);
Vector256<int> firstKept = Vector256.Create(Vector256<int>.Count - keepLast);
return Vector256.GreaterThanOrEqual(Vector256<int>.Indices, firstKept).As<int, T>();
}
private static Vector128<T> CreateRemainderMask128<T>(int keepLast)
where T : unmanaged, INumberBase<T>
{
Debug.Assert(sizeof(T) == 4);
Vector128<int> firstKept = Vector128.Create(Vector128<int>.Count - keepLast);
return Vector128.GreaterThanOrEqual(Vector128<int>.Indices, firstKept).As<int, T>();
}
sizeof(T) 㯠JIT æé宿°ã§ããããŸãããã®ããã SumVectorSmall ã¯ãæãåºããã¯ã¿ãŒã®èŠçŽ ã«å¯Ÿå¿ãããµã€ãºã®ããŒãã«ã«èŠçŽ ã®å¹
ããã£ã¹ãããããŸããããã¯ã TensorPrimitives 䜿çšããã®ãšåãã¢ãããŒãã§ãã (æ°ããã¡ã¢ãª ã»ãŒã ã¢ãã«ãæå¹ã«ãªã£ãŠããå Žåãsizeof(T)å¶çŽãæã€åãã©ã¡ãŒã¿ãŒã®åŒãå®å
šãªã³ãŒãã§unmanagedã§ããŸã)ã4 ãã€ãã®ããŒãã«ã®ã¿ã衚瀺ãããŸãã1 ãã€ãã2 ãã€ããããã³ 8 ãã€ãã®ããŒãã«ã¯ããã®å³åœ¢ãå
±æããŸãã ãã®ãã倧ããªã±ãŒã¹ã§ã¯ãå
é ããã®è² è·ãšæ«å°Ÿããã®è² è·ãšãã 2 ã€ã®éãªãåãè² è·ãçšããŠãVector256 ãŸã㯠Vector128 ã§æ®ããæãããããããçç¥ããã Vector512/Vector256 ãã¹ã«å¯Ÿããããåºãæ®ãã®åŠçãããžã£ã³ãããŒãã«å
ã«ãã®ãŸãŸåãŸãããšã«ãªããŸãã é·ããå¹
ã®æ£ç¢ºãªåæ°ã§ãªãå Žåã¯åžžã« 2 ã€ã®è·éãéãªã£ãŠããã®ã§ãåèšããåã«ãå°Ÿéšã¯ ConditionalSelect ã䜿çšããŠå æ³ ID ã«ãã¹ã¯ãããŸãã ãã®ãã¹ã¯ãå¿
èŠãšãªãã®ã¯ãå ç®ãéã¹ãçã§ããããã§ããæ€çŽ¢ã®ãããªã¹ãçãªæŒç®ã§ããã°ãéè€ããæ«å°ŸéšåãçŽæ¥æã蟌ããŸãã ãã¯ã¿ãŒåããŸã£ãããªãããŒããŠã§ã¢äžã®ãããã¡ãŒã¯ãéåžžã®ã¹ã«ã©ãŒ ã«ãŒãã§ãã SumScalarã«å
¥ããŸãã
å ¥åãã«ãŒãããŠå°äœãåŠçãã
1 ã€ã®ãã¯ã¿ãŒãã倧ãããããã¡ãŒãåŠçããã«ã¯ãäžåºŠã«ãã¯ã¿ãŒãã«ãŒãããŠãããå®å šãªãã¯ã¿ãŒãåããªãæ®ãã®èŠçŽ ãåŠçããŸãã ãã®æ«å°Ÿéšåãå ç¢ã«åŠçããæ¹æ³ã¯ãæåŸã®å®å šãªãã¯ã¿ãŒ1æ¬åã®èŠçŽ ãååŠçããã«ãŒãããã§ã«åŠçããäžéšãšéè€ãããããšã§ããããã«ãããå¥åã®ã¹ã«ã©ãŒã»ãšãããŒã°ãåé¿ã§ããŸãã ãã®éè€ãä¿®æ£ããå¿ èŠããããã©ããã¯ãæäœã«ãã£ãŠç°ãªããŸãã
åã®ãããªéã¹ãçãªæŒç®ã§ã¯ãéè€ããèŠçŽ ã 2 åã«ãŠã³ããããŠããŸããããããããæã蟌ãåã«ããã®æŒç®ã®æçå ãŸã§ãã¹ã¯ããå¿ èŠããããŸãã ããã¯ãåèŠçŽ ã 1 åã ãè²¢ç®ããå¿ èŠãããå Žåã«äœ¿çšããŸãã
// Sums a buffer with an unrolled vector loop plus a masked, jump-table remainder.
private static T SumVector128<T>(ReadOnlySpan<T> buffer)
where T : unmanaged, INumberBase<T>
{
Debug.Assert(Vector128.IsHardwareAccelerated && Vector128<T>.IsSupported);
Debug.Assert(buffer.Length >= Vector128<T>.Count);
// Preload the last full vector, overlapping the tail. Any sub-vector remainder is folded in
// from here (masked) by case 0 of the switch below, so the loop never falls out to a separate
// scalar tailâthe same shape TensorPrimitives uses.
Vector128<T> end = Vector128.Create(buffer.Slice(buffer.Length - Vector128<T>.Count));
// A production implementation would also align the buffer to a vector boundary and, for
// very large inputs, use non-temporal loads/stores so the data doesn't evict useful
// cache lines. Both are omitted here; see TensorPrimitives for a complete treatment.
Vector128<T> sum = Vector128<T>.Zero;
// Only pay for the four independent accumulators when there's enough data to unroll;
// smaller payloads skip straight to the remainder below. Four vectors per iteration lets
// the accumulators pipeline; Vector128.Create reads the first Vector128<T>.Count elements.
if (buffer.Length >= Vector128<T>.Count * 4)
{
Vector128<T> sum0 = Vector128<T>.Zero;
Vector128<T> sum1 = Vector128<T>.Zero;
Vector128<T> sum2 = Vector128<T>.Zero;
Vector128<T> sum3 = Vector128<T>.Zero;
do
{
sum0 += Vector128.Create(buffer);
sum1 += Vector128.Create(buffer.Slice(Vector128<T>.Count));
sum2 += Vector128.Create(buffer.Slice(Vector128<T>.Count * 2));
sum3 += Vector128.Create(buffer.Slice(Vector128<T>.Count * 3));
buffer = buffer.Slice(Vector128<T>.Count * 4);
}
while (buffer.Length >= Vector128<T>.Count * 4);
// Combine pairwise so the two independent adds can pipeline.
sum = (sum0 + sum1) + (sum2 + sum3);
}
// Split the remainder into its full vectors and a sub-vector tail. The full vectors fall
// through the jump table; the tail lands in case 0, where the preloaded end is masked so only
// the trailing elements the full vectors didn't already cover are added.
(int blocks, int trailing) = Math.DivRem(buffer.Length, Vector128<T>.Count);
switch (blocks)
{
case 3:
{
sum += Vector128.Create(buffer.Slice(Vector128<T>.Count * 2));
goto case 2;
}
case 2:
{
sum += Vector128.Create(buffer.Slice(Vector128<T>.Count));
goto case 1;
}
case 1:
{
sum += Vector128.Create(buffer);
goto case 0;
}
case 0:
{
Vector128<T> msk = CreateRemainderMask128<T>(trailing);
sum += Vector128.ConditionalSelect(msk, end, Vector128<T>.Zero);
break;
}
}
// Horizontally add the lanes into a single scalar.
return Vector128.Sum(sum);
}
ãã®ããŒãžã§ã³ã§ã¯ãã¢ã³ããŒã«ããã«ãŒãã if ã§ã¬ãŒãããŠããããããã€ããŒããå°ããå Žå㯠4 ã€ã®ã¢ãã¥ã ã¬ãŒã¿ãå®å
šã«ã¹ããããããã®ãŸãŸå°äœåŠçãžé²ã¿ãŸãã ååãªããŒã¿ãããå Žåã do/while ã¯å埩ããšã« 4 ã€ã®ãã¯ãã«ãç¬ç«ããã¢ãã¥ã ã¬ãŒã¿ã«èç©ããŸããããã«ãããããã»ããµãã€ãã©ã€ã³ã§å ç®ãå¯èœã«ãªãããã¢ããšã«çµåãããŸãã
switch ãžã£ã³ã ããŒãã«ã¯ãæ®ãã® 0ïœ3 åã®ãã«ãã¯ãã«ãšãcase 0 ã«ããããµããã¯ãã«ã®æ«å°Ÿéšåãçµã¿èŸŒã¿ãŸããå
·äœçã«ã¯ããããã¡ã®æ«å°Ÿããäºåã«èªã¿èŸŒãŸãããã«ãã¯ãã«ãåå©çšãããã§ã«åŠçæžã¿ã®èŠçŽ ãšãªãŒããŒã©ããããããã®ãªãŒããŒã©ããéšåã ConditionalSelect ãçšããŠå æ³åäœå
ãŸã§ãã¹ã¯ããããšã§ãæ«å°Ÿéšåãã¹ã«ã©ãŒ ã«ãŒãã«é¥ãããšãªããã¯ãã«åãããç¶æ
ãç¶æããŸãã åãšåæ§ã«ã Vector128.Create ã¯ã¹ãã³ãã Vector128<T>.Count èŠçŽ ãèªã¿åããŸãã JIT ã¯ãäžè¬çãªã¢ã¯ã»ã¹ ãã¿ãŒã³ã®ã¹ãã³ã®å¢çãã§ãã¯ãçç¥ããããã Create ã¯ããã ã«ãŒãã§ãæ£åžžãªæ¢å®å€ã§ãã LoadUnsafe (次ã«èª¬æããŸã) ã¯ããããŒãžãåç
§ã§ãããã¡ãŒããŠã©ãŒã¯ããå Žåã®äžäœã¬ãã«ã®ä»£æ¿ææ®µã§ãã éåžžã«å€§ããªå
¥åã«å¯ŸããŠã¯ãå®å
šãªå®è£
ã§ã¯ããããã¡ã®ã¢ã©ã€ã³ã¡ã³ããè¡ããéãã³ãã©ã«ããŒããšã¹ãã¢ã䜿çšããŠãæçšãªãã£ãã·ã¥ã©ã€ã³ããã£ãã·ã¥ãã远ãåºãããã®ãé²ããŸãããããã«ã€ããŠã¯ãããã§ã¯ã©ã¡ããçç¥ããŠãããTensorPrimitives ã§è©³ããæ±ã£ãŠããŸãã
å€ã®æ€çŽ¢ãªã©ã®ã¹ãçãªæäœã§ã¯ãéè€éšåãåé¡ãªãååŠçã§ããããããã¹ã¯ã䜿çšããã«æåŸã®ãã¯ãã«ãçŽæ¥æã蟌ãããšãã§ããŸã:
// Idempotent search that re-processes the final vector instead of a scalar loop.
public static bool Contains(ReadOnlySpan<int> buffer, int searched)
{
Debug.Assert(Vector128.IsHardwareAccelerated);
Vector128<int> values = Vector128.Create(searched);
ReadOnlySpan<int> remaining = buffer;
while (remaining.Length >= Vector128<int>.Count)
{
if (Vector128.EqualsAny(Vector128.Create(remaining), values))
{
return true;
}
remaining = remaining.Slice(Vector128<int>.Count);
}
if (remaining.IsEmpty)
{
return false;
}
// A partial vector remains. When the buffer holds at least one full vector,
// re-check the last one (overlapping the tail); otherwise scan the few elements directly.
if (buffer.Length >= Vector128<int>.Count)
{
Vector128<int> tail = Vector128.Create(buffer.Slice(buffer.Length - Vector128<int>.Count));
return Vector128.EqualsAny(tail, values);
}
foreach (int value in remaining)
{
if (value == searched)
{
return true;
}
}
return false;
}
Warning
æ®ãã誀ã£ãŠåŠçããããšã¯ããã°ã®äžè¬çãªåå ã§ãã ãããã¡ãŒã®æ«å°Ÿãè¶ããŠèªã¿åãã«ãŒãã¯ãéæ±ºå®çãªçµæãçæããã¯ã©ãã·ã¥ããå¯èœæ§ããããŸãã ã©ã³ã¿ã€ã ã®ãã¹ã ã¹ã€ãŒãã§ã¯ããããã¡ãŒã®çŽåŸã«ã¢ã¯ã»ã¹ãªãã®ããŒãžãé
眮ãã BoundedMemory ãã«ããŒã䜿çšããããããç¯å²å€ã®èªã¿åãã§ã¯ãã¹ãäžã« AccessViolationException ãã¹ããŒãããŸãã é·ãããã¯ãã«å¹
ã®åæ°ã§ã¯ãªããããã¡ãŒãå«ããå°äœããžãã¯ãåžžã«ã«ããŒããŸãã
ãã¯ã¿ãŒãå®å šã«èªã¿èŸŒãã§æ ŒçŽãã
ã»ãšãã©ã®ã³ãŒãã§ã¯ã Vector128.Create(span) ãš CopyTo ã¯ã¹ãã³ãšãã¯ã¿ãŒã®éã§ããŒã¿ãç§»åããæãç°¡åãªæ¹æ³ã§ãããJIT ã¯ããããå¹ççã«ä¿ã¡ãŸãã äœã¬ãã«ã®èªã¿èŸŒã¿ãšæ ŒçŽãå¿
èŠãªå Žå (ããšãã°ããããŒãžãåç
§ã§ãããã¡ãŒããŠã©ãŒã¯ããå Žå)ããããŒãžãåç
§ãšLoadUnsafeèŠçŽ ãªãã»ãããåãåãStoreUnsafeãªãŒããŒããŒããšnuintãªãŒããŒããŒããåªå
ããŸãã ãã€ã³ã¿ãŒããŒã¹ã® Load/Store ãªãŒããŒããŒããšã¯ç°ãªãããããã¡ãŒããã³çãããå¿
èŠã¯ãããŸãããæªå å·¥ã®åç
§ç®è¡æŒç®ãšã¯ç°ãªãã refãæåã§é²ããå¿
èŠã¯ãããŸããã ã©ã¡ãã®æ¹æ³ããã¬ããŒãž ã³ã¬ã¯ã¿ãŒã®æã穎ãã¢ã¯ã»ã¹éåãåŒãèµ·ãããããªãã¹ãæããããŸããã
空ã®ãããã¡ã«ãã£ãŠäŸå€ãçºçããªãããã«ãããããref span[0] ã§ã¯ãªã GetReference (é
åã®å Žå㯠GetArrayDataReference) ããéå§åç
§ãååŸããŸãã
Important
ãªãã»ããç®è¡ã§ã¯ã笊å·ãªã nuintã䜿çšãããŸãã
buffer.Length - Vector128<int>.Countãªã©ã®ãªãã»ãããèšç®ããåã«ããããã¡ãŒã®é·ããåžžã«ç¢ºèªããŠãã ããã ãããã¡ãŒã 1 ã€ã®ãã¯ãã«ããå°ããå Žåããã®æžç®ã¯èšå€§ãªå€ã«ã¢ã³ããŒãããŒããã«ãŒãã¯ç¡å¹ãªã¡ã¢ãªãèªã¿åããŸãã
ãã©ãããã©ãŒã åºæã®ããŒããŠã§ã¢çµã¿èŸŒã¿é¢æ°
ç¹å®ã®ããã»ããµåœä»€ã«ãã£ãŠãç§»æ€å¯èœãª API ã§ã¯æäŸãããŠããªãåªäœæ§ãåŸãããå Žåã¯ãSystem.Runtime.Intrinsics.X86ãSystem.Runtime.Intrinsics.ArmãSystem.Runtime.Intrinsics.Wasm ã®ããŒããŠã§ã¢çµã¿èŸŒã¿é¢æ°ã䜿çšããŸãã åçµã¿èŸŒã¿ã¯ã©ã¹ã«ã¯ IsSupported ãããã㣠(JIT 宿°ã) ããããããç¹æ®åããããã¹ãä¿è·ããå¥ã®å Žæã§ç§»æ€å¯èœãªã³ãŒãã«ãã©ãŒã«ããã¯ã§ããŸãã
// Illustrates per-platform lightup. The portable '(vector & mask) == Zero' below
// already lowers optimally, so prefer it unless a specific instruction measurably wins.
public static bool AllBitsClear(Vector128<byte> vector, Vector128<byte> mask)
{
if (Sse41.IsSupported)
{
// x86/x64: a single ptest instruction.
return Sse41.TestZ(vector, mask);
}
else if (AdvSimd.Arm64.IsSupported)
{
// Arm64: AND, then reduce the maximum byte across every lane.
Vector128<byte> anded = AdvSimd.And(vector, mask);
return AdvSimd.Arm64.MaxAcross(anded).ToScalar() == 0;
}
else if (PackedSimd.IsSupported)
{
// WebAssembly: AND, then test whether any lane is non-zero.
return !PackedSimd.AnyTrue(PackedSimd.And(vector, mask));
}
else
{
// Portable fallback for any other platform.
return (vector & mask) == Vector128<byte>.Zero;
}
}
äžèšã®ã¡ãœããã¯ãå¿
èŠãªãšãã«ã¢ãŒããã¯ãã£ããšã®ã³ãŒã ãã¹ãæããããæ¹æ³ã瀺ããŠããŸãããããã¯æå³çã«åçŽãªäŸã§ããããã§ã¯å®éã«ã¯å¿
èŠãããŸããã ç§»æ€å¯èœãªåŒ (vector & mask) == Vector128<byte>.Zero ã¯ãåãã©ãããã©ãŒã ã§ã®æé©ãªåœä»€ (ããšãã°ãx86/x64 ã® ptest ) ã«æ¢ã«äœäžããŠãããããè€éããªãã§ãææžãã®ãã©ã³ããšåãäœæ¥ãè¡ããŸãã ç¹å®ã®åœä»€ãããŒã¿ãã« API ã«ãã£ãŠçæãããå
å®¹ãæž¬å®çã«äžåãå Žåã«ã®ã¿ãæç€ºçãªçµã¿èŸŒã¿é¢æ°ã«å°éããŸãã
ããŒããŠã§ã¢çµã¿èŸŒã¿é¢æ°ã§ã¯ãåœä»€ã»ããããšã«åå¥ã®å®è£
ãå¿
èŠã§ãããããæ¢å®ã§ã¯ãªããæž¬å®ãããããã ãã¹ã®æé©åãšããŠæ±ããŸãã
Vector128
/
Vector256 API ã¯ãã§ã«åãã©ãããã©ãŒã ã§å¹ççãªåœä»€ã«å€æããããããå®éã«ã¯ãåœä»€ããšã«æé©åãããé«åºŠãªã³ãŒããå¿
ãããæè¯ã®çµæããããããšã¯éããŸããã 远å ã®ã¡ã³ããã³ã¹ã«ã³ãããããåã«ããã³ãããŒã¯ãšã®éãã確èªããŸãã
TensorPrimitives ã䜿çšããäžäœã¬ãã«ã®æ°åŠ
ã¹ãã³ã«å¯ŸããŠãã¯ãã«åãããç®è¡æŒç®ãå¿ èŠã§ãã«ãŒããèªåã§èšè¿°ããããªãå Žåã TensorPrimitives ã¯ãæ¢ã«å éšçã«ãã¯ãã«åããããèŠçŽ ããšã®ç®è¡æŒç®ãææ°æŒç®ããããç©ãäœåŒŠé¡äŒŒåºŠãªã©ã®æžå°ãªã©ã®å€§èŠæš¡ãªæ°å€æŒç®ã»ãããæäŸããŸãã System.Numerics.Tensors NuGet ããã±ãŒãžã§å ¥æã§ããŸãã
// Computes result = (left * right) + addend over the whole span, vectorized internally.
public static float[] MultiplyAdd(float[] left, float[] right, float[] addend)
{
float[] result = new float[left.Length];
TensorPrimitives.Multiply(left, right, result);
TensorPrimitives.Add(result, addend, result);
return result;
}
// Higher-level reductions are available too.
public static float CosineSimilarity(float[] left, float[] right) =>
TensorPrimitives.CosineSimilarity(left, right);
AI ã¯ãŒã¯ããŒããšæ°å€ã¯ãŒã¯ããŒãã®å Žåãå€ãã®å Žåã TensorPrimitives ã¯ãè€éããªãã«ææžã SIMD ã®å©ç¹ã®å€§éšåãæäŸããŸãã
ãã¹ãŠã®ã³ãŒã ãã¹ããã¹ããã
ãã¯ã¿ãŒåãããã¡ãœããã«ã¯è€æ°ã®ã³ãŒã ãã¹ãããããããã¹ãã§ã¯ãVector256 ãã¹ãVector128 ãã¹ãã¹ã«ã©ãŒ ãã¹ã®ããããã«ã€ããŠã广ãåŸãããã»ã©ååã«å€§ããå
¥åãšã广ãåŸãããªãã»ã©å°ããå
¥åã®äž¡æ¹ãã«ããŒããå¿
èŠããããŸãã ãã¹ãã§ã¯å
¥åãµã€ãºã倿Žã§ããŸããããã¹ã ã¬ãã«ã§ããŒããŠã§ã¢ ã¢ã¯ã»ã©ã¬ãŒã·ã§ã³ãåãæ¿ããããšã¯ã§ããŸããã 代ããã«ãããã»ã¹ãéå§ããåã«ç°å¢å€æ°ã§å¶åŸ¡ããŸãã
-
Vector256.IsHardwareAccelerated ã
falseãè¿ãããã«ãDOTNET_EnableAVX2=0ãèšå®ããŸãã - çµã¿èŸŒã¿é¢æ°ãå®å
šã«ç¡å¹ã«ããããã«
DOTNET_EnableHWIntrinsic=0ãèšå®ãããšããã¹ãŠã®Vector128ãVector64ãããã³Vector<T>ãé«éåãå ±åããŸããã
1 å°ã®ã³ã³ãã¥ãŒã¿ãŒã§ãã¹ãŠã®ãã¹ãå®è¡ããã«ã¯ããªãŒããŒã©ã€ããªãã§ãã¹ã ã¹ã€ãŒãã 1 åã DOTNET_EnableAVX2=0ã§ 1 åã DOTNET_EnableHWIntrinsic=0ã§ 1 åå®è¡ããŸãã ä»£æ¿ææ®µã¯ãããããã«ããŒããã®ã«ååãªå€æ§ãªããŒããŠã§ã¢ã§å®è¡ãããŠããŸãã
åœä»€ã»ããæ§æãã
ããã 2 ã€ãè¶
ããŠãã©ã³ã¿ã€ã ã¯åœä»€ã»ããã®è«çã°ã«ãŒãããšã«ãããèªèããåãã¬ãã£ãã¯ã¹ã« DOTNET_ ãä»ããŸãã 1 ã€ã®ããã¯ãããã€ãã®é¢é£ããåœä»€ã»ãã (EnableAVX2 ããšãã°ãã²ãŒã AVX2 ãš BMI1ãBMI2ãF16CãFMAãLZCNTãMOVBE ãªã©) ãã«ããŒã§ããŸãã ããã 0 ã«èšå®ãããšããã®ã°ã«ãŒãå
šäœãšããã®äžã«éããããŠãããã¹ãŠã®ãã®ãç¡å¹ã«ãªããŸãã
1ïŒã»ãšãã©ã®å Žåã®æ¢å®å€ïŒã«èšå®ãããšãã®ã°ã«ãŒããæå¹ã«ã§ããŸãããããŒããŠã§ã¢åŽãå®éã«ããããµããŒãããŠããå¿
èŠããããŸããçŸåšã® CPU ãåããŠããªãèšå®é
ç®ãæå¹ã«ããŠãç¡èŠãããããã䜿çšå¯Ÿè±¡ãçµã蟌ãããšããã§ãããæªå¯Ÿå¿ã®åœä»€ãç¡çã«æå¹ã«ããŠèªåã§å£ããŠããŸãããšã¯ãããŸããã
DOTNET_EnableHWIntrinsic=0 ã¯åŒ·ç¡¬çã§ããåºç€ã¬ãã«ãŸã§ãã¹ãŠãç¡å¹ã«ãããããVector128ãVector64ãVector<T> ã¯ããããã¢ã¯ã»ã©ã¬ãŒã·ã§ã³ãªããšå ±åããã³ãŒãã¯ãœãããŠã§ã¢ãã¹ã«ãã©ãŒã«ããã¯ããŸãã
Important
ãããã¯ãäž»ã«ãã¹ããšæ€èšŒãç®çãšãã蚺æããŒã«ã§ããåã³ãŒã ãã¹ã®å®è¡ãããŒããŠã§ã¢åºæã®åé¡ã®åçŸããã©ãŒã«ããã¯ã®ç¢ºèªãè¡ããŸãã ãããã¯äžè¬çãŸãã¯éçšç°å¢çšã«èšèšãããŠããããå®å®æ§ã³ã³ãã©ã¯ãã§ã¯ãããŸããã æ¬¡ã®ã»ããã¯ã.NET 11 ãèªèããŸãã以åã®ãªãªãŒã¹ã§ã¯ãããŒã¹ã©ã€ã³ãš AVX-512 ãããç¹ã«åæ§æãããå¥ã®ã»ãããå ¬éãããŠãããããã¿ãŒã²ãããšããã©ã³ã¿ã€ã ããŒãžã§ã³ã«å¯ŸããŠååã確èªããŸãã
ãããã®ããŒã«ã«ã¯ãå°éããç¯å²ã«ãå¶éããããŸãã JIT ã®æ±ºå®ãã²ãŒããããããReadyToRun ãŸãã¯ãã€ãã£ã AOT ãéããŠäºåã«ã³ã³ãã€ã«ãããã³ãŒãã«ã¯åœ±é¿ããŸããããŸããã©ã³ã¿ã€ã ãšã³ã¢ ã©ã€ãã©ãªãèªèº«ã§äœ¿çšããå éšã«ãŒãã³ã«ã¯å¿ ããã圱é¿ããŸããã åœä»€ã»ããã®ã°ããŒãã«ãªãã¹ã€ããã§ã¯ãªããç¬èªã® JIT ã³ã³ãã€ã«ã³ãŒããèªå°ããæ¹æ³ãšããŠæ±ããŸãã
åºæ¬ã¹ã€ãããšå¹ ãã£ããã¯ããã¹ãŠã®ã¢ãŒããã¯ãã£ã«é©çšãããŸãã
ãã (ãã¬ãã£ãã¯ã¹ DOTNET_) |
Default | Effect |
|---|---|---|
EnableHWIntrinsic |
1 |
ãã¹ãŠã®ããŒããŠã§ã¢çµã¿èŸŒã¿é¢æ°ã®ãã¹ã¿ãŒ ã¹ã€ããã 0 ã¯å®å
šãªãœãããŠã§ã¢ ãã¹ã匷å¶ããŸãã |
MaxVectorTBitWidth |
ã·ã¹ãã ã®æ¢å®å€ |
Vector<T> ã®æå€§å¹
ããããåäœã§å¶éããŸãã128 æªæºã®å€ãæå®ãããšãã·ã¹ãã æ¢å®å€ã«ãªããŸãã |
PreferredVectorBitWidth |
ã·ã¹ãã ã®æ¢å®å€ |
IsHardwareAcceleratedãå ±åããæå€§åºå®å¹
ãã¯ãã«ããããåäœã§å€§æåã«ããŸãã128 æªæºã®å€ã¯ãã·ã¹ãã ã®æ¢å®å€ãæå³ããŸãã |
MaxVectorTBitWidthã®ã·ã¹ãã ã®æ¢å®å€ã¯ãããŒããŠã§ã¢ãå®å
šã«ãµããŒããããããçããªãå¯èœæ§ããããããVector<T>ã¯äœ¿çšå¯èœãªæãåºããã¯ã¿ãŒã«èªåçã«æ¡åŒµãããŸããã ããšãã°ãVector512<T>.IsHardwareAccelerated 㯠true ã«ã§ããäžæ¹ã§ãVector<T> 㯠256 ãããã®ãŸãŸã§ããVector<T> ãããåºãå¹
ã«ããã«ã¯ãDOTNET_MaxVectorTBitWidth=512 ãèšå®ããŸãã
PreferredVectorBitWidth ã¯ãIsHardwareAccelerated ãå ±åããæå€§ãã¯ã¿ãŒå¹
ã®äžéãèšå®ããŸãã ããŒããŠã§ã¢ããµããŒãããå€ããäœãèšå®ãããšãããåºãå¹
ã¯ç¡å¹ã«ãªããŸãã512 ããã ãã¯ãã«ããµããŒããããã·ã³ã§ã¯ãDOTNET_PreferredVectorBitWidth=256 ã«ãããš Vector512<T>.IsHardwareAccelerated 㯠false ãè¿ããŸãã ããã¯äžè¬çãªããã§ãããx86/x64ã ãã仿¥128以äžã®å¹
ãæäŸããã®ã§ãããã芳枬å¯èœãªå¹æãæã£ãŠããå¯äžã®å Žæã§ãã
x86/x64 åœä»€ã»ããã®åè«çã°ã«ãŒãã«ã¯ãç¬èªã®ã¹ã€ããããããŸãã
ãã (ãã¬ãã£ãã¯ã¹ DOTNET_) |
Default | Gates |
|---|---|---|
EnableAVX |
1 |
AVX ãšäŸåé¢ä¿ |
EnableAVX2 |
1 |
AVX2ãBMI1ãBMI2ãF16CãFMAãLZCNTãMOVBEããªãã³ã«ãããã«äŸåãããã® |
EnableAVX512 |
1 |
AVX-512 F+BW+CD+DQ+VL ããã³äŸåé¢ä¿ |
EnableAVX512BMM |
1 |
AVX-512 BMM |
EnableAVX512v2 |
1 |
AVX-512 IFMA+VBMI |
EnableAVX512v3 |
1 |
AVX-512 BITALG+VBMI2+VPOPCNTDQ+VNNI |
EnableAVX10v1 |
1 |
AVX10.1 |
EnableAVX10v2 |
0 |
AVX10.2 |
EnableAPX |
0 |
APX (æ¡åŒµæ±çšã¬ãžã¹ã¿) |
EnableAES |
1 |
AESãPCLMULQDQ |
EnableAVX512VP2INTERSECT |
1 |
AVX-512 VP2INTERSECT |
EnableAVXIFMA |
1 |
AVX-IFMA |
EnableAVXVNNI |
1 |
AVX-VNNI |
EnableAVXVNNIINT |
1 |
VEX AVX-VNNI-INT8 ããã³ AVX-VNNI-INT16 |
EnableGFNI |
1 |
GFNI |
EnableSHA |
1 |
SHA |
EnableVAES |
1 |
VAESãVPCLMULQDQ |
EnableWAITPKG |
1 |
WAITPKG |
EnableX86Serialize |
1 |
X86 SERIALIZE |
Arm64 ã§ã¯ãåœä»€ã»ããã®è«çã°ã«ãŒãããšã«ç¬èªã®ã¹ã€ããããããŸãã
ãã (ãã¬ãã£ãã¯ã¹ DOTNET_) |
Default | Gates |
|---|---|---|
EnableArm64Aes |
1 |
AES |
EnableArm64Atomics |
1 |
LSE (Large System Extensions) ã¢ããã㯠|
EnableArm64Crc32 |
1 |
CRC32 |
EnableArm64Dczva |
1 |
DC ZVA ãã£ãã·ã¥ã®ãŒãå |
EnableArm64Dp |
1 |
ããã補å |
EnableArm64Rdm |
1 |
åæšäºå ¥ä¹ç®çŽ¯ç© (RDM) |
EnableArm64Sha1 |
1 |
SHA1 |
EnableArm64Sha256 |
1 |
SHA256 |
EnableArm64Rcpc |
1 |
ãªãªãŒã¹æŽåæ§ãããã»ããµæŽåæ§é åºä»ã (RCpc) |
EnableArm64Rcpc2 |
1 |
RCpc2 |
EnableArm64Cssc |
0 |
å ±éçã·ãŒã±ã³ã¹å§çž® (CSSC) |
EnableArm64Sve |
1 |
ã¹ã±ãŒã©ãã« ãã¯ã¿ãŒæ¡åŒµæ©èœ (SVE) |
EnableArm64Sve2 |
1 |
SVE2 |
EnableArm64Sha3 |
1 |
SHA3 |
EnableArm64Sm4 |
1 |
SM4 |
EnableArm64SveAes |
1 |
SVE AES |
EnableArm64SveSha3 |
1 |
SVE SHA3 |
EnableArm64SveSm4 |
1 |
SVE SM4 |
æ¢å®ã§ 0 ãããã (EnableAVX10v2 ã EnableArm64Csscãªã©) ã¯ããŸã ãªã³ã©ã€ã³ã«ãªã£ãŠããåœä»€ã»ãããã²ãŒãããããããªããã€ã³ãããŸã§ãªãã®ãŸãŸã«ãªããŸãã
åå©ã確èªããããã®ãã³ãããŒã¯
ãã¯ãã«åã¯è€éããå¢ãããããã®ãŸãŸæ¡çšãç¶ããåã«ãããã«èŠåã广ããããã©ããã確èªããŠãã ããã
BenchmarkDotNet ã䜿çšããåã«ç€ºããã®ãšåãç°å¢å€æ°ã䜿çšããŠãã¹ã«ã©ãŒãVector128ãããã³Vector256ã®å®è£
ã 1 åã®å®è¡ã§æ¯èŒããŸãã BenchmarkDotNet ã®éã¢ã»ã³ããªèšºæããŒã«ã¯ãçæãããã¢ã»ã³ããªãåºåããããšãã§ããŸããããã¯ãé«ããã©ãŒãã³ã¹ ã³ãŒãããã¥ãŒãã³ã°ããéã«éåžžã«éèŠã§ãã
çæãã¹ãããã€ãã®ç¹ã¯æ¬¡ã®ãšããã§ãã
- å ¥åã倧ããã»ã©ãã¡ãªãããå¢ããŸãã å°ããªãããã¡ãŒã®å Žåããã¯ã¿ãŒåãããã³ãŒãã¯ãã»ããã¢ããã®ãªãŒããŒãããã®ããã«ã¹ã«ã©ãŒ ã³ãŒããããé ããªãå¯èœæ§ããããŸãã åŒã³åºãå ãå®éã«äœ¿çšããå ¥åãµã€ãºããã³ãããŒã¯ããŸãã
- é«éåãå®å šã§ããããšã¯ãŸãã§ãã 32 ãããèŠçŽ ã§åäœãã 256 ããã ãã¯ã¿ãŒã¯ã確å®ã« 8 åé«éã«ãªããŸãããã¡ã¢ãª ã®ã¹ã«ãŒããããã¢ã©ã€ã³ã¡ã³ããåœä»€ã®åŸ ã¡æéãèæ ®ããŸãã
- ã¡ã¢ãªã®é 眮ã¯å®å®æ§ã«åœ±é¿ããŸãã ã©ã³ãã å²ãåœãŠã¢ã©ã€ã³ã¡ã³ãã«ãããå®è¡éã«ãã€ãºã远å ãããŸãã å®å®ããçµæãåŸãããã«ãã¢ã©ã€ã¡ã³ããããã¡ã¢ãªã AlignedAlloc ã«å²ãåœãŠãããBenchmarkDotNet ã®ã¡ã¢ãªã©ã³ãã åãæå¹ã«ããŠå®å šãªåæ£ã芳å¯ãããã§ããŸãã
ãã¹ã ãã©ã¯ãã£ã¹
- ãŸããæ¢åã®äžäœã¬ãã«ã® API ã«ã¢ã¯ã»ã¹ããŸãã
Span<T>ãstringãLINQãTensorPrimitivesãããã³ãã³ãœã«åã¯ãäžè¬çãªå€ãã®æäœããã§ã«é«éåããŠãããŸããæ¢ã«æé©åã»ãã¹ãæžã¿ã®ãã®ããããããèªåã§å®è£ ããªãã§ãã ããã -
Vector128<T>ããå§ããŸããæãåºç¯ãªããŒããŠã§ã¢ ã»ããã§é«éåããããããé©åã§ç§»æ€å¯èœãªå®è£ ãåŸãããã«Vector256<T>å¿ èŠã¯ãããŸããã èšæž¬ã§ç¹å®ãããããããã¹ã«å¯ŸããŠã®ã¿ãããåºãããŒã¿å¹ ãšããŒããŠã§ã¢ã€ã³ããªã³ã·ãã¯ã远å ããã -
IsHardwareAcceleratedãšCountã¯ãã£ãã·ã¥ããã«çŽæ¥ç¢ºèªããŠãã ãããJIT ããããã宿°ã«ããŸãã - åžžã«ã«ãŒãå°äœãåŠçããæ ŒçŽæã«éè€ãããœãŒã¹ ãããã¡ãŒãšå®å ãããã¡ãŒãèæ ®ããŸãã
- æåã«ãšããž ã±ãŒã¹ ãã¹ããèšè¿°ããæ¬¡ã«ã¹ã«ã©ãŒ ãœãªã¥ãŒã·ã§ã³ãèšè¿°ãããã®ã¹ã«ã©ãŒ ããžãã¯ããã¯ã¿ãŒ API ã§è¡šããŸãã
- 远å ãããè€éãã«ã³ãããããåã«ããã¹ãŠã®ã³ãŒã ãã¹ (ã¢ã¯ã»ã¹éåãå«ã) ããã¹ãããçŸå®çãªå ¥åãµã€ãºããã³ãããŒã¯ããŸãã