public static void Main(string[] args) { string dirName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); string genCsProjPath = Path.Combine(dirName, "..", "..", ".."); string generatedCsProjPath = Path.Combine(dirName, "..", "..", "..", "..", "AdvSimdGenerated"); AdvSimdMethods.ReadCsv(); PopulateMethods(); GenerateBlogContents(); WriteGeneratedCodeToFile(Path.Combine(generatedCsProjPath, "AdvSimdGenerated.cs")); SplitGeneratedBlog(); PrintVarsAndMethodNames(); }
/// <summary> /// Generate C# code for <paramref name="methodName"/> that will generate the blog content /// for <paramref name="methodName"/>. /// </summary> /// <param name="methodName"></param> /// <param name="isForAdvSimd"></param> private static void GenerateCodeForMethod(string methodName, bool isForAdvSimd) { if (((count - 1) % apisPerBlog) == 0) { count = 1; string placeHolder = $"PART-{sectionCount}-TOC"; if (sectionCount > 1) { // update previous value. Skip adding for 1st because no toc by that time. globalTocBuilder.Add($"PART-{sectionCount - 1}-TOC", tocBuilder); } methodCallBuilder.AppendLine(string.Format(header, sectionCount++, placeHolder)); tocBuilder = new List <string>(); } var details = isForAdvSimd ? advSimdMethods[methodName].First() : arm64Methods[methodName].First(); string signature = details.Item1; string testMethodName = methodName + "Test"; string dummyTestMethodName = "Dummy_" + methodName + "Test"; string testMethodSig = signature.Replace(methodName, testMethodName); string dummyTestMethodSig = signature.Replace(methodName, dummyTestMethodName); var parameters = details.Item2; var cppIntrinsic = details.Item3; // TOC tocBuilder.Add(string.Format("[{0}](#{1}-{2})", methodName, count, methodName.ToLower())); // References string advsimdReference = "[here](" + string.Format(microsoftAdvSimdRefTemplate, methodName.ToLower()) + ")"; string arm64Reference = "[here](" + string.Format(microsoftArm64RefTemplate, methodName.ToLower()) + ")"; string armDocsReference = string.Empty; if (!string.IsNullOrEmpty(cppIntrinsic)) { armDocsReference = ", ARM docs [here](" + string.Format(armRefTemplate, cppIntrinsic) + ")"; } // Overloads StringBuilder overloadBuilder = new StringBuilder(); var otherOverloads = isForAdvSimd ? advSimdMethods[methodName].Skip(1) : arm64Methods[methodName].Skip(1); if (otherOverloads.Count() > 0) { overloadBuilder.AppendLine("// class System.Runtime.Intrinisics.AdvSimd" + (isForAdvSimd ? "" : ".Arm64")); overloadBuilder.Append(string.Join(Environment.NewLine, otherOverloads.Select(sm => sm.Item1))); } if (isForAdvSimd) { // Process AdvSimd.Arm64 methods, if present if (arm64Methods.ContainsKey(methodName)) { var similarMethods = arm64Methods[methodName]; // Add new lines only if similar APIs were present in AdvSimd namespace if (otherOverloads.Count() > 0) { overloadBuilder.AppendLine(); overloadBuilder.AppendLine(); } overloadBuilder.AppendLine("// class System.Runtime.Intrinisics.AdvSimd.Arm64"); overloadBuilder.Append(string.Join(Environment.NewLine, similarMethods.Select(sm => sm.Item1))); advsimdReference += " and " + arm64Reference; } } else { advsimdReference = arm64Reference; // only reference would be from ARM64 namespace. } if (overloadBuilder.Length > 0) { StringBuilder headerOfOverloadSection = new StringBuilder(); headerOfOverloadSection.AppendLine("Similar APIs that operate on different sizes:"); headerOfOverloadSection.AppendLine(); headerOfOverloadSection.AppendLine("```csharp"); overloadBuilder.Insert(0, headerOfOverloadSection.ToString()); overloadBuilder.AppendLine(); overloadBuilder.AppendLine("```"); } // jitasm jitAsmBuilder.Append(testMethodName).Append(" "); // method call List <string> args = new List <string>(); List <string> argsValueToPrint = new List <string>(); StringBuilder argsValuePrintBuilder = new StringBuilder(); Dictionary <string, int> argsTracker = new Dictionary <string, int>(); int argCount = 1; bool isUnsafe = false; bool isVoid = signature.StartsWith("void "); bool isBytePtr = false, isIntPtr = false; foreach (var p in parameters) { bool isPtr = p.Type.ToString().Contains("*"); if (isPtr) { isBytePtr = p.Type.ToString().Contains("byte"); isIntPtr = p.Type.ToString().Contains("int"); } string normalizedType = p.Type.ToString().Replace("<", string.Empty).Replace(">", string.Empty).Replace("*", "Ptr"); int id = 0; if (!argsTracker.ContainsKey(normalizedType)) { argsTracker.Add(normalizedType, id); } string uniqueArgName = normalizedType + "_" + argsTracker[normalizedType]; args.Add(uniqueArgName); argsValueToPrint.Add(isPtr ? "\"<address>\"" : uniqueArgName); uniqueArgs.Add(uniqueArgName); // Track so we can create only these many args for all the methods. argsTracker[normalizedType] += 1; // increment the id. argsValuePrintBuilder.AppendLine(string.Format(argValuePrintTemplate, p.Identifier.Text, "{" + argCount++ + "}")); isUnsafe |= isPtr; } // method defintion var methodParams = string.Join(", ", parameters.Select( (p, index) => { // If byte parameter, then emit the value from csv if (p.Type.ToString() == "byte" && methodName != "DuplicateToVector128" && methodName != "DuplicateToVector64") { return(AdvSimdMethods.GetValue(methodName, p.Identifier.Text, index + 1 /* in csv, col0 is desc */)); } else { return(p.Identifier.Text); } } )); //var methodParams = string.Join(", ", parameters.Select(p => p.Type.ToString() == "byte" ? "(byte)0" : p.Identifier.Text)); string returnStatement = string.Format("{0}.{1}({2})", isForAdvSimd ? "AdvSimd" : "AdvSimd.Arm64", methodName, methodParams); if (!isVoid) { returnStatement = "return " + returnStatement; argsValuePrintBuilder.AppendLine(string.Format(argValuePrintTemplate, "Result", "{" + argCount + "}")); //argsValueToPrint.Add(methodName + "Result"); // result to be passed to Console.WriteLine argsValueToPrint.Add("apiResult"); // result to be passed to Console.WriteLine } string methodDef = string.Format(methodDefinitionTemplate, returnStatement, testMethodSig, isUnsafe ? "unsafe" : string.Empty); string dummyMethodDef = string.Format(methodDefinitionTemplate, returnStatement, dummyTestMethodSig, isUnsafe ? "unsafe" : string.Empty); methodDefBuilder.Append(dummyMethodDef); methodDefBuilder.Append(methodAttribute); methodDefBuilder.AppendLine(methodDef); methodDefBuilder.AppendLine(); string result = methodName; string dummyResult = isVoid ? $"Dummy_{methodName}" : string.Format("var {0}Result = Dummy_{0}", methodName); string dummyMethodCall; if (isVoid) { dummyMethodCall = string.Format(methodCallTemplate, dummyResult, string.Join(", ", args), string.Empty); } else { dummyMethodCall = string.Format(methodCallTemplate, dummyResult, string.Join(", ", args), "apiResult = " + (methodName + "Result.ToString()") + ";"); } string methodCall = string.Format(methodCallTemplate, result, string.Join(", ", args), string.Empty); if (isUnsafe) { if (isBytePtr) { methodCallBuilder.AppendLine("fixed (byte* bytePtr_0 = byteArray)"); methodCallBuilder.AppendLine("{"); } if (isIntPtr) { methodCallBuilder.AppendLine("fixed (int* intPtr_0 = intArray)"); methodCallBuilder.AppendLine("{"); } } if (shouldReadFromCsv) { argsValueToPrint = argsValueToPrint.Select((av, index) => "GetValue(\"" + methodName + "\", " + av + ".ToString(), " + (index + 1) + ")").ToList(); argsValueToPrint.Insert(0, $"GetValue(\"{methodName}\", \"Performs '{methodName}' operation.\", 0)"); } else { argsValueToPrint.Insert(0, $"\"Performs '{methodName}' operation.\""); } // Print method definition and result string methodDefPrint = string.Format(methodDefPrintTemplate, returnStatement, // 0 testMethodSig, // 1 argsValuePrintBuilder.ToString(), // 2 string.Join(", ", argsValueToPrint), // 3 count, // 4 methodName, // 5 signature, // 6 overloadBuilder.ToString(), // 7 advsimdReference, // 8 (count == 1) ? string.Empty : sectionSep, // 9 armDocsReference // 10 ); methodCallBuilder.AppendLine(dummyMethodCall); methodCallBuilder.AppendLine(methodDefPrint); methodCallBuilder.AppendLine(methodCall); if (isUnsafe) { if (isBytePtr) { methodCallBuilder.AppendLine("}"); } if (isIntPtr) { methodCallBuilder.AppendLine("}"); } } if (shouldGenerateCsv) { argsValueToPrint.Insert(0, "\"Performs '" + methodName + "' operation\""); argsValueToPrint.Insert(0, "\"" + methodName + "\""); methodCallBuilder.AppendLine(string.Format(LogInCsvTemplate, string.Join(", ", argsValueToPrint))); } methodCallBuilder.AppendLine("// ----------------------------------------------------------------"); count++; }