From f81771e17976d2ab3f8de64ed158041e0ed6b692 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Sun, 5 Nov 2023 16:49:11 +0900 Subject: [PATCH] Add support for `--mstat`, `-m` (#124) Resolves #97. --- src/bflat/BuildCommand.cs | 99 +++++++++++++++++++++++++-------------- 1 file changed, 65 insertions(+), 34 deletions(-) diff --git a/src/bflat/BuildCommand.cs b/src/bflat/BuildCommand.cs index 922c2cb..271c9cb 100644 --- a/src/bflat/BuildCommand.cs +++ b/src/bflat/BuildCommand.cs @@ -49,6 +49,7 @@ private BuildCommand() { } private static Option NoPieOption = new Option("--no-pie", "Do not generate position independent executable"); private static Option NoLinkOption = new Option("-c", "Produce object file, but don't run linker"); + private static Option MstatOption = new Option("--mstat", "Produce MSTAT and DGML files for size analysis"); private static Option LdFlagsOption = new Option(new string[] { "--ldflags" }, "Arguments to pass to the linker"); private static Option PrintCommandsOption = new Option("-x", "Print the commands"); @@ -65,13 +66,17 @@ private BuildCommand() { } private static Option TargetArchitectureOption = new Option("--arch", "Target architecture") { - ArgumentHelpName = "x64|arm64" + ArgumentHelpName = "x86|x64|arm64" }; private static Option TargetOSOption = new Option("--os", "Target operating system") { ArgumentHelpName = "linux|windows|uefi" }; - + private static Option TargetIsaOption = new Option("-m", "Target instruction set extensions") + { + ArgumentHelpName = "{isa1}[,{isaN}]|native" + }; + private static Option TargetLibcOption = new Option("--libc", "Target libc (Windows: shcrt|none, Linux: glibc|bionic)"); private static Option MapFileOption = new Option("--map", "Generate an object map file") @@ -98,6 +103,7 @@ public static Command Create() PrintCommandsOption, TargetArchitectureOption, TargetOSOption, + TargetIsaOption, TargetLibcOption, OptimizeSizeOption, OptimizeSpeedOption, @@ -110,6 +116,7 @@ public static Command Create() SeparateSymbolsOption, CommonOptions.NoDebugInfoOption, MapFileOption, + MstatOption, DirectPInvokesOption, FeatureSwitchOption, CommonOptions.ResourceOption, @@ -260,13 +267,42 @@ public override int Handle(ParseResult result) } ms.Seek(0, SeekOrigin.Begin); + string outputFilePath = userSpecificedOutputFileName; + if (outputFilePath == null) + { + outputFilePath = outputNameWithoutSuffix; + if (targetOS == TargetOS.Windows) + { + if (buildTargetType is BuildTargetType.Exe or BuildTargetType.WinExe) + outputFilePath += ".exe"; + else + outputFilePath += ".dll"; + } + else if (targetOS == TargetOS.UEFI) + { + outputFilePath += ".efi"; + } + else + { + if (buildTargetType is not BuildTargetType.Exe and not BuildTargetType.WinExe) + { + outputFilePath += ".so"; + + outputFilePath = Path.Combine( + Path.GetDirectoryName(outputFilePath), + "lib" + Path.GetFileName(outputFilePath)); + } + } + } + var tsTargetOs = targetOS switch { TargetOS.Windows or TargetOS.UEFI => Internal.TypeSystem.TargetOS.Windows, TargetOS.Linux => Internal.TypeSystem.TargetOS.Linux, }; - InstructionSetSupport instructionSetSupport = Helpers.ConfigureInstructionSetSupport(instructionSet: null, maxVectorTBitWidth: 0, isVectorTOptimistic: false, targetArchitecture, tsTargetOs, + string isaArg = result.GetValueForOption(TargetIsaOption); + InstructionSetSupport instructionSetSupport = Helpers.ConfigureInstructionSetSupport(isaArg, maxVectorTBitWidth: 0, isVectorTOptimistic: false, targetArchitecture, tsTargetOs, "Unrecognized instruction set {0}", "Unsupported combination of instruction sets: {0}/{1}", logger, optimizingForSize: optimizationMode == OptimizationMode.PreferSize); @@ -590,12 +626,19 @@ public override int Handle(ParseResult result) .UseInteropStubManager(interopStubManager) .UseLogger(logger); + string scanDgmlLogFileName = result.GetValueForOption(MstatOption) ? Path.ChangeExtension(outputFilePath, ".scan.dgml.xml") : null; + if (scanDgmlLogFileName != null) + scannerBuilder.UseDependencyTracking(DependencyTrackingLevel.First); + IILScanner scanner = scannerBuilder.ToILScanner(); PerfWatch scanWatch = new PerfWatch("Scanner"); scanResults = scanner.Scan(); scanWatch.Complete(); + if (scanDgmlLogFileName != null) + scanResults.WriteDependencyLog(scanDgmlLogFileName); + metadataManager = ((UsageBasedMetadataManager)metadataManager).ToAnalysisBasedMetadataManager(); interopStubManager = scanResults.GetInteropStubManager(interopStateManager, pinvokePolicy); @@ -604,7 +647,9 @@ public override int Handle(ParseResult result) DebugInformationProvider debugInfoProvider = debugInfoFormat == 0 ? new NullDebugInformationProvider() : new DebugInformationProvider(); - DependencyTrackingLevel trackingLevel = DependencyTrackingLevel.None; + string dgmlLogFileName = result.GetValueForOption(MstatOption) ? Path.ChangeExtension(outputFilePath, ".codegen.dgml.xml") : null; ; + DependencyTrackingLevel trackingLevel = dgmlLogFileName == null ? + DependencyTrackingLevel.None : DependencyTrackingLevel.First; bool foldMethodBodies = optimizationMode != OptimizationMode.None; @@ -669,42 +714,23 @@ public override int Handle(ParseResult result) ICompilation compilation = builder.ToCompilation(); - string outputFilePath = userSpecificedOutputFileName; - if (outputFilePath == null) - { - outputFilePath = outputNameWithoutSuffix; - if (targetOS == TargetOS.Windows) - { - if (buildTargetType is BuildTargetType.Exe or BuildTargetType.WinExe) - outputFilePath += ".exe"; - else - outputFilePath += ".dll"; - } - else if (targetOS == TargetOS.UEFI) - { - outputFilePath += ".efi"; - } - else - { - if (buildTargetType is not BuildTargetType.Exe and not BuildTargetType.WinExe) - { - outputFilePath += ".so"; - - outputFilePath = Path.Combine( - Path.GetDirectoryName(outputFilePath), - "lib" + Path.GetFileName(outputFilePath)); - } - } - } - if (logger.IsVerbose) logger.LogMessage("Generating native code"); string mapFileName = result.GetValueForOption(MapFileOption); - ObjectDumper dumper = mapFileName != null ? new XmlObjectDumper(mapFileName) : null; + string mstatFileName = result.GetValueForOption(MstatOption) ? Path.ChangeExtension(outputFilePath, ".mstat") : null; + + List dumpers = new List(); + + if (mapFileName != null) + dumpers.Add(new XmlObjectDumper(mapFileName)); + + if (mstatFileName != null) + dumpers.Add(new MstatObjectDumper(mstatFileName, typeSystemContext)); + string objectFilePath = Path.ChangeExtension(outputFilePath, targetOS is TargetOS.Windows or TargetOS.UEFI ? ".obj" : ".o"); PerfWatch compileWatch = new PerfWatch("Native compile"); - CompilationResults compilationResults = compilation.Compile(objectFilePath, dumper); + CompilationResults compilationResults = compilation.Compile(objectFilePath, ObjectDumper.Compose(dumpers)); compileWatch.Complete(); string exportsFile = null; @@ -721,6 +747,11 @@ public override int Handle(ParseResult result) defFileWriter.EmitExportedMethods(); } + typeSystemContext.LogWarnings(logger); + + if (dgmlLogFileName != null) + compilationResults.WriteDependencyLog(dgmlLogFileName); + if (debugInfoProvider is IDisposable) ((IDisposable)debugInfoProvider).Dispose();