Skip to content

Instantly share code, notes, and snippets.

@omgtehlion
Last active August 18, 2020 00:22
Show Gist options
  • Save omgtehlion/25219feeb1691b489f237178b82fadb1 to your computer and use it in GitHub Desktop.
Save omgtehlion/25219feeb1691b489f237178b82fadb1 to your computer and use it in GitHub Desktop.
this code generates a copy of officedaytime’s intrinsic guide, but for .NET Core
using HtmlAgilityPack;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Xml.Linq;
using System.Xml.XPath;
// generated page is hosted at https://drachev.com/officedaytime/
// more details at https://habr.com/ru/post/507074/ (in Russian)
namespace ConsoleApp4
{
class Program
{
static void Main(string[] args)
{
var htmlDir = @"html";
Directory.CreateDirectory("html");
if (!File.Exists(Path.Combine(htmlDir, "odt.html"))) {
using var client = new WebClient();
Console.WriteLine($"Downloading HTML ...");
client.DownloadFile("https://www.officedaytime.com/simd512e/", Path.Combine(htmlDir, "odt.html"));
}
var doc = new HtmlDocument();
doc.Load(Path.Combine(htmlDir, "odt.html"));
var xmlDoc = XDocument.Load(@"C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\3.1.0\ref\netcoreapp3.1\System.Runtime.Intrinsics.xml");
var summaries = xmlDoc.XPathSelectElements("//summary");
foreach (var intr in doc.DocumentNode.SelectNodes("//span[@class='intr' or @class='intr_S1' or @class='intr_S2']").ToArray()) {
var newParts = new List<string>();
var parts = intr.InnerHtml.Split("<br>").Select(s => s.Trim()).ToArray();
foreach (var part in parts) {
newParts.Add(part);
if (part != "") {
var p = Unbrace(part.Replace(" ", ""));
if (p.Contains("/")) {
var leftRight = new List<string>();
var converted = p.Split("/").Select(pp => MapFunc(summaries, pp).FirstOrDefault());
if (converted.Any(co => co != null))
newParts.Add(string.Join(" / ", converted));
} else {
newParts.AddRange(MapFunc(summaries, p));
}
}
}
intr.InnerHtml = string.Join("<br>", newParts);
}
foreach (var a in doc.DocumentNode.SelectNodes("//a[@href]")) {
var origLink = a.Attributes["href"].Value;
if (!origLink.StartsWith("http"))
a.Attributes["href"].Value = new Uri(new Uri("https://www.officedaytime.com/simd512e/"), origLink).ToString();
}
foreach (var a in doc.DocumentNode.SelectNodes("//img[@src]")) {
var origLink = a.Attributes["src"].Value;
if (!origLink.StartsWith("http") && !origLink.StartsWith("/")) {
var target = Path.Combine(htmlDir, origLink);
if (!File.Exists(target)) {
Directory.CreateDirectory(Path.GetDirectoryName(target));
using var client = new WebClient();
Console.WriteLine($"Downloading {origLink}...");
client.DownloadFile("https://www.officedaytime.com/simd512e/" + origLink, target);
}
}
}
doc.DocumentNode.SelectSingleNode("html/head").AppendChild(
HtmlNode.CreateNode("<style type=\"text/css\">.dotnet { color:rgb(0,147,181) } .dotnet a { text-decoration:none }</style>"));
doc.DocumentNode.SelectSingleNode("html/head/title").InnerHtml += " adapted for .NET Core";
foreach (var link in doc.DocumentNode.SelectNodes("html/head/link[@rel='alternate']"))
link.Remove();
var helpDoc = new HtmlDocument();
helpDoc.LoadHtml(@"<b>What is this page?</b>
<p>
This page is a copy of a great x64 SIMD guide from
<a href='https://www.officedaytime.com/simd512e/'>https://www.officedaytime.com/simd512e/</a>, but adapted for those of us who use C#.
</p>
<p>
I amended it to include the names of intrinsics from the <b>System.Runtime.Intrinsics.X86</b> namespace as of .NET Core 3.1 (future versions pending).<br />
These names are hard to find in MSDN documentation, and they differ from both Intel’s instruction names and C++ intrinsics. Hence, here they are.
</p>
<p>
C# names, when awailable, are written below C++ intrinsics.
</p>
<p>
♯ — links to MSDN documentation are marked with a <i>sharp</i> sign.
</p>
<p>
Some methods not included here are available for AVX and AVX2.
If you can not find what you want, please try and change class name from <b>SseX</b> to <b>Avx</b> or <b>Avx2</b>.
<br>
Same deal with <b>Vector256</b>/<b>Vector128</b>.
<br>
<b>AVX512</b> is completely missing from .NET Core at this point. To highlight only AVX2 instructions, use <a href='?mf=0&amp;mt=8&amp;mc=0'>this link</a>.
</p>");
doc.DocumentNode.SelectSingleNode("html/body/span").Remove();
var replacedA = doc.DocumentNode.SelectSingleNode("html/body/a");
replacedA.ParentNode.ReplaceChild(helpDoc.DocumentNode, replacedA);
var lastBr = doc.DocumentNode.SelectSingleNode("html/body/br[last()]");
RemoveNodesAfter(lastBr);
lastBr.ParentNode.InsertAfter(HtmlNode.CreateNode(
@"<p>Original content by <a href='https://www.officedaytime.com/simd512e/'>daytime</a>. Instruction names © Intel, .net method names © Microsoft.</p>"
), lastBr);
doc.Save(Path.Combine(htmlDir, "index.html"));
}
static void RemoveNodesAfter(HtmlNode node)
{
node = node.NextSibling;
while (node != null) {
var next = node.NextSibling;
node.Remove();
node = next;
}
}
static string Unbrace(string s)
{
var brace = s.IndexOf('(');
return brace != -1 ? s[..brace] : s;
}
static Dictionary<string, string> MyMap = new Dictionary<string, string> {
{ " _mm_set_epi64x _mm_set_epi32 _mm_set_epi16 _mm_set_epi8 _mm_set_pd _mm_set_ps ", "M:System.Runtime.Intrinsics.Vector256.Create" },
{ " _mm_setzero_si128 _mm_setzero_pd _mm_setzero_ps " ,"P:System.Runtime.Intrinsics.Vector256`1.Zero" },
{ " _mm_slli_si128 ", "M:System.Runtime.Intrinsics.X86.Sse2.ShiftLeftLogical128BitLane"},
{ " _mm_srli_si128 ", "M:System.Runtime.Intrinsics.X86.Sse2.ShiftRightLogical128BitLane"},
};
static string[] MapFunc(IEnumerable<XElement> summaries, string p)
{
p = $" {p} ";
var mapped = summaries
.Where(s => s.Value.Contains(p))
.Select(s => Unbrace(s.Parent.Attribute("name").Value ?? ""))
.ToHashSet();
if (mapped.Count == 0)
mapped = MyMap.Where(s => s.Key.Contains(p)).Select(s => s.Value).ToHashSet();
return mapped.Select(s => $"<span class='dotnet'>{Shorten(s)}&nbsp;<a href='{MsdnLink(s)}' target='_blank'>♯</a></span>").ToArray();
}
static string MsdnLink(string s)
{
if (s[1] == ':')
s = s[2..];
return $"https://docs.microsoft.com/en-us/dotnet/api/{s.Replace('`', '-').ToLower()}?view=netcore-3.1";
}
static string Shorten(string s)
{
if (s[1] == ':')
s = s[2..];
if (s.StartsWith("System.Runtime.Intrinsics.X86."))
return s["System.Runtime.Intrinsics.X86.".Length..];
if (s.StartsWith("System.Runtime.Intrinsics."))
return s["System.Runtime.Intrinsics.".Length..];
return s;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment