예제 #1
0
        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();
        }
예제 #2
0
        /// <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++;
        }