1997 lines
84 KiB
C#
1997 lines
84 KiB
C#
//
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//
|
|
|
|
#if ON_SINGULARITY
|
|
#define NONONNULLTYPECHECK // required on Singularity, no affect on other Windows.
|
|
#endif
|
|
|
|
namespace Bartok {
|
|
|
|
using System;
|
|
using System.IO;
|
|
using System.Text;
|
|
using System.Collections;
|
|
using Bartok.Utility;
|
|
using Bartok.Datatype;
|
|
using Bartok.CfgUtil;
|
|
using Bartok.Ir;
|
|
using Bartok.Lir;
|
|
using Bartok.Analysis;
|
|
using Bartok.Opt.IrCleanup;
|
|
using Bartok.Opt.Ir;
|
|
using Bartok.Opt.Lir;
|
|
using Bartok.Opt;
|
|
using Bartok.Regalloc;
|
|
using Bartok.Opt.Ssa;
|
|
using Bartok.Backend;
|
|
|
|
//
|
|
// Bartok.cs
|
|
//
|
|
// Main entry point for compiler
|
|
|
|
// "public class Bartok {..}" breaks the namespace lookup of Bartok.*
|
|
// Is this a bug?
|
|
public class BartokClass {
|
|
|
|
public static int Main(String[] args) {
|
|
Bartok.MSIL.MetaDataUtil.Configure(new MetaDataOutput());
|
|
|
|
try {
|
|
ProcessCmdLine(args);
|
|
if((fileNames.Count == 0) && (linkNames.Count == 0)) {
|
|
PrintUsage();
|
|
Util.Error("\nno files to process...aborting.");
|
|
Util.Exit(-11);
|
|
}
|
|
|
|
if(StageControl.AtomicSupport) {
|
|
StageControl.TryAllSupport = true;
|
|
}
|
|
|
|
Util.Message(NoiseLevel.PerPhase,
|
|
"fileNames = "
|
|
+ new CollectionFormatter(fileNames));
|
|
Util.Message(NoiseLevel.PerPhase,
|
|
"refFileNames = "
|
|
+ new CollectionFormatter(refFileNames));
|
|
Util.Message(NoiseLevel.PerPhase,
|
|
"libDirNames = "
|
|
+ new CollectionFormatter(libDirNames));
|
|
Util.Message(NoiseLevel.PerPhase,
|
|
"outputDirName = " + outputDirName);
|
|
|
|
if (overrideNames.Count > 0) {
|
|
Util.Message(NoiseLevel.PerPhase,
|
|
"overrideNames = "
|
|
+ new CollectionFormatter(overrideNames));
|
|
}
|
|
if (entryPoints.Count > 0) {
|
|
Util.Message(NoiseLevel.PerPhase,
|
|
"entryPoints = "
|
|
+ new CollectionFormatter(entryPoints));
|
|
}
|
|
|
|
// Create helper data structures
|
|
DateTime startTime = Util.startTime;
|
|
bool fLoadDebugInfo =
|
|
StageControl.SymbolicDebug || StageControl.SymbolicIR;
|
|
StageControl.BartokLinkPhase = false;
|
|
if (StageControl.CompileOnly) {
|
|
// separate compilation
|
|
for (int i=0; i<fileNames.Count; ++i) {
|
|
String fileName = (String) fileNames[i];
|
|
String outputName =
|
|
ComputeOutputName(fileName, outputDirName);
|
|
ArrayList loadFileNames = new ArrayList(1);
|
|
loadFileNames.Add(fileName);
|
|
ArrayList loadMdilFileNames = null;
|
|
if (StageControl.BindMdil) {
|
|
loadMdilFileNames = new ArrayList(1);
|
|
loadMdilFileNames.Add(mdilFileNames[i]);
|
|
}
|
|
String shortName = GetShortName(fileName).ToLower();
|
|
|
|
// we need to compile mscorlib.dll together with
|
|
// system.dll
|
|
bool fDefineOverride = shortName.Equals("mscorlib.dll");
|
|
|
|
TypeData typeData = new TypeData();
|
|
CompileFile(typeData, loadFileNames, loadMdilFileNames,
|
|
refFileNames, overrideNames, overrideDefNames,
|
|
fDefineOverride, outputName,
|
|
startTime, fLoadDebugInfo);
|
|
}
|
|
} else {
|
|
// Create output root name.
|
|
if (outputRootName == null) {
|
|
outputRootName = (String) fileNames[0];
|
|
}
|
|
|
|
if (!StageControl.TargetMdil) {
|
|
outputRootName = StripName(outputRootName);
|
|
}
|
|
bool fDefineOverride = StageControl.WholeProgram;
|
|
TypeData typeData = new TypeData();
|
|
String objFileName =
|
|
CompileFile(typeData, fileNames, mdilFileNames,
|
|
refFileNames, overrideNames, overrideDefNames,
|
|
fDefineOverride, outputRootName,
|
|
startTime, fLoadDebugInfo);
|
|
linkNames.Add(objFileName);
|
|
|
|
if (!StageControl.TargetMdil) {
|
|
StageControl.BartokLinkPhase = true;
|
|
BartokLinker bartokLinker = new BartokLinker();
|
|
typeData = StageControl.WholeProgram ? typeData : null;
|
|
bartokLinker.Link
|
|
(typeData, fileNames, linkNames, refFileNames,
|
|
overrideNames, overrideDefNames, libDirNames,
|
|
entryPoints, initializerSkips, outputRootName);
|
|
}
|
|
}
|
|
} catch(AbortException) {
|
|
// Abort code already dumped the stack
|
|
Util.Exit(-1);
|
|
} catch(Exception e) {
|
|
Util.Error("Internal uncaught {0} exception", e);
|
|
Util.Exit(-1);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
private static String CompileFile(TypeData typeData,
|
|
ArrayList fileNames,
|
|
ArrayList mdilFileNames,
|
|
ArrayList refFileNames,
|
|
ArrayList overrideNames,
|
|
ArrayList overrideDefNames,
|
|
bool fDefineOverride,
|
|
String outputName,
|
|
DateTime startTime,
|
|
bool fLoadDebugInfo) {
|
|
Util.Assert(!StageControl.BindMdil || (mdilFileNames.Count == 1),
|
|
"MDIL support requires exactly one input assembly (got {0})",
|
|
(mdilFileNames != null) ? mdilFileNames.Count : 0);
|
|
MSIL.MetaDataResolver loadResolver;
|
|
MetaDataParser mdParser;
|
|
ConvertMsil2Ir(fileNames, refFileNames, overrideNames,
|
|
overrideDefNames, fDefineOverride, startTime,
|
|
fLoadDebugInfo, typeData,
|
|
out loadResolver, out mdParser);
|
|
|
|
#if SELF_PROFILING
|
|
System.GC.Collect();
|
|
long memoryUsage = System.GC.GetTotalMemory(false);
|
|
Util.Message("memory usage: " + memoryUsage);
|
|
#endif
|
|
|
|
if (entryPoints.Count > 0) {
|
|
Util.Message(NoiseLevel.PerPhase,
|
|
"entryPoints = "
|
|
+ new CollectionFormatter(entryPoints));
|
|
}
|
|
if(!StageControl.CompileOnly && (entryPoints.Count == 0)) {
|
|
Util.UserError("No entry points found");
|
|
}
|
|
|
|
typeData.ComputeEntryMethod(entryPoints);
|
|
Util.Assert(typeData.EntryPoints.Count == entryPoints.Count);
|
|
|
|
// register all global analysis
|
|
AnalysisRegistry analysisRegistry = RegisterAnalysis(typeData);
|
|
|
|
// Create a series of phases that are each applied to the
|
|
// whole program.
|
|
Bartok.Ir.PhaseList phases = new Bartok.Ir.PhaseList("ir");
|
|
|
|
AddPhases(phases, analysisRegistry, outputName, typeData);
|
|
|
|
if (StageControl.PrintContainers) {
|
|
phases.Add(new TypeDataPrintPhase("end-IR"));
|
|
}
|
|
if (StageControl.DumpContainers) {
|
|
phases.Add(new TypeDataPrettyPhase("end-IR"));
|
|
}
|
|
phases.Add(new TypeDataDummyPhase("end-IR"));
|
|
|
|
Util.Message(phases.ComponentPhases.ToString());
|
|
|
|
Bartok.Opt.IrCleanup.Statistics.Reset(typeData);
|
|
BartokList phaseNames = phases.ComponentPhases;
|
|
foreach(Object phaseObj in phaseNames) {
|
|
Util.Assert(phaseObj is String,
|
|
"Non-string in phase name list: {0}", phaseObj);
|
|
String phaseName = (String) phaseObj;
|
|
if((phaseName.IndexOf(' ') != -1)
|
|
|| (phaseName.IndexOf(':') != -1)) {
|
|
Util.Warn("Phase has a space or colon in name: {0}",
|
|
phaseName);
|
|
}
|
|
}
|
|
foreach(PhaseControl control in StageControl.phaseControls) {
|
|
String phaseName = control.PhaseName;
|
|
if(phaseName == null) {
|
|
continue;
|
|
}
|
|
if(phaseNames.Contains(phaseName)) {
|
|
continue;
|
|
}
|
|
if(StageControl.disabledPhaseNamesFound.Contains(phaseName)) {
|
|
continue;
|
|
}
|
|
#if PHXMIR || PHXBRIDGE
|
|
// HACK: allow /disable:gopt to mimic -off:globalopts from phx
|
|
// also allow /noisyphase:gopt
|
|
// also allow /debugphase:PhxGCEncode
|
|
if(phaseName == "gopt" || phaseName == "PhxGCEncode") {
|
|
continue;
|
|
}
|
|
#endif
|
|
Util.UserError("Couldn't find phase: " + phaseName);
|
|
}
|
|
|
|
// append .obj to outputName. We still keep outputName
|
|
// for AsmWriter.
|
|
string objFileName = ComputeObjFileName(outputName);
|
|
phases.Go(typeData);
|
|
Bartok.Opt.IrCleanup.Statistics.Summary();
|
|
|
|
#if PHXBRIDGE
|
|
phases = new Bartok.Ir.PhaseList("convert to phoenixMir");
|
|
// add bartok mir to phx mir phase
|
|
phases.Add(new PhoenixPhases(typeData, fileNames, objFileName,
|
|
outputName, StageControl.GenObjFile));
|
|
phases.Go(typeData);
|
|
#endif
|
|
|
|
#if SELF_PROFILING
|
|
memoryUsage = System.GC.GetTotalMemory(false);
|
|
Util.Message("memory usage: " + memoryUsage);
|
|
#endif
|
|
|
|
#if !PHXBRIDGE
|
|
// backend phases:
|
|
Util.Message(NoiseLevel.PerPhase, "outputRootName = " + outputName);
|
|
|
|
LirPhases.run(typeData, loadResolver, mdParser, fileNames,
|
|
mdilFileNames, objFileName, outputName, StageControl.GenObjFile);
|
|
#endif
|
|
|
|
#if SELF_PROFILING
|
|
System.GC.Collect();
|
|
Util.Message("End of Bartok: " + GC.GetTotalMemory(false));
|
|
#endif
|
|
return objFileName;
|
|
}
|
|
|
|
// sets out parameters (loadResolver for filenames) when /BindMdil=true,
|
|
// to null otherwise
|
|
private static void ConvertMsil2Ir
|
|
(ArrayList fileNames, ArrayList refFileNames,
|
|
ArrayList overrideNames, ArrayList overrideDefNames,
|
|
bool fDefineOverride, DateTime startTime,
|
|
bool fLoadDebugInfo, TypeData typeData,
|
|
out MSIL.MetaDataResolver outLoadResolver,
|
|
out MetaDataParser outMDParser) {
|
|
// Remove redundant fileNames
|
|
// Remove refFileNames that are redundant with fileNames
|
|
for(int i=0; i<fileNames.Count; ++i) {
|
|
String fileI = ((String)fileNames[i]);
|
|
#if !ON_SINGULARITY
|
|
fileI = Path.GetFullPath(fileI);
|
|
#endif
|
|
fileI = fileI.ToLower();
|
|
|
|
for(int j=i+1; j<fileNames.Count; ++j) {
|
|
String fileJ = ((String) fileNames[j]);
|
|
#if !ON_SINGULARITY
|
|
fileJ = Path.GetFullPath(fileJ);
|
|
#endif
|
|
fileJ = fileJ.ToLower();
|
|
|
|
if (fileI == fileJ) {
|
|
Util.Warn
|
|
("Removing redundant input {0} from command line",
|
|
fileNames[j]);
|
|
fileNames.RemoveAt(j);
|
|
}
|
|
}
|
|
|
|
for(int j=0; j<refFileNames.Count; ++j) {
|
|
String fileJ = MSIL.MetaDataResolver.ResolveFileName
|
|
(libDirNames, (String) refFileNames[j]);
|
|
if (fileJ == null) {
|
|
// Future failure in MetaDataResolver will have a better
|
|
// error message so move on.
|
|
continue;
|
|
}
|
|
#if !ON_SINGULARITY
|
|
fileJ = Path.GetFullPath(fileJ);
|
|
#endif
|
|
fileJ = fileJ.ToLower();
|
|
|
|
if(fileI == fileJ) {
|
|
Util.Warn
|
|
("Removing redundant reference {0} from command line",
|
|
refFileNames[j]);
|
|
refFileNames.RemoveAt(j);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
// Remove redundant refFileNames (may be redundant with fileNames
|
|
// or other refFileNames)
|
|
for(int i=0; i<refFileNames.Count; ++i) {
|
|
String fileI = MSIL.MetaDataResolver.ResolveFileName
|
|
(libDirNames, (String) refFileNames[i]);
|
|
if(fileI == null) {
|
|
// Future failure in MetaDataResolver will have a better
|
|
// error message so move on.
|
|
continue;
|
|
}
|
|
#if !ON_SINGULARITY
|
|
fileI = Path.GetFullPath(fileI);
|
|
#endif
|
|
fileI = fileI.ToLower();
|
|
|
|
for(int j=i+1; j<refFileNames.Count; ++j) {
|
|
String fileJ = MSIL.MetaDataResolver.ResolveFileName
|
|
(libDirNames, (String) refFileNames[j]);
|
|
if(fileJ == null) {
|
|
// Future failure in MetaDataResolver will have a better
|
|
// error message so move on.
|
|
continue;
|
|
}
|
|
#if !ON_SINGULARITY
|
|
fileJ = Path.GetFullPath(fileJ);
|
|
#endif
|
|
fileJ = fileJ.ToLower();
|
|
|
|
if(fileI == fileJ) {
|
|
Util.Warn("Removing redundant reference {0} from command line",
|
|
refFileNames[j]);
|
|
refFileNames.RemoveAt(j);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool fTranslateTryAll = StageControl.TryAllSupport;
|
|
bool fTranslateAtomic = StageControl.AtomicSupport;
|
|
bool fMsilMessages = Verbosity.level >= NoiseLevel.PerPhase;
|
|
|
|
Bartok.MSIL.MetaDataResolver libResolver =
|
|
new Bartok.MSIL.MetaDataResolver(refFileNames, libDirNames,
|
|
startTime, fLoadDebugInfo,
|
|
fMsilMessages);
|
|
Bartok.MSIL.MetaDataResolver overrideResolver;
|
|
if (fDefineOverride) {
|
|
// load code
|
|
overrideResolver =
|
|
new Bartok.MSIL.MetaDataResolver(overrideNames,
|
|
startTime,
|
|
fLoadDebugInfo,
|
|
fTranslateTryAll,
|
|
fTranslateAtomic,
|
|
fMsilMessages);
|
|
} else {
|
|
// don't load code
|
|
overrideResolver =
|
|
new Bartok.MSIL.MetaDataResolver(overrideNames,
|
|
libDirNames,
|
|
startTime, fLoadDebugInfo,
|
|
fMsilMessages);
|
|
}
|
|
Bartok.MSIL.MetaDataResolver overrideDefResolver =
|
|
new Bartok.MSIL.MetaDataResolver(overrideDefNames, startTime,
|
|
fLoadDebugInfo,
|
|
fTranslateTryAll,
|
|
fTranslateAtomic,
|
|
fMsilMessages);
|
|
Bartok.MSIL.MetaDataResolver loadResolver =
|
|
new Bartok.MSIL.MetaDataResolver(fileNames, startTime,
|
|
fLoadDebugInfo,
|
|
fTranslateTryAll,
|
|
fTranslateAtomic,
|
|
fMsilMessages);
|
|
Bartok.MSIL.MetaDataResolver[] resolvers =
|
|
new Bartok.MSIL.MetaDataResolver[] {
|
|
libResolver, overrideResolver, overrideDefResolver,
|
|
loadResolver
|
|
};
|
|
Bartok.MSIL.MetaDataResolver.ResolveCustomAttributes(resolvers);
|
|
MetaDataParser parser =
|
|
new MetaDataParser(entryPoints.Count == 0 ? entryPoints : null);
|
|
Util.TimestampMessage(NoiseLevel.PerPhase,
|
|
"translating from MSIL");
|
|
parser.Parse(loadResolver, overrideResolver,
|
|
overrideDefResolver, libResolver,
|
|
typeData, fDefineOverride, false);
|
|
|
|
Util.TimestampMessage(NoiseLevel.PerPhase,
|
|
"finished translating");
|
|
if (StageControl.BindMdil) {
|
|
outLoadResolver = loadResolver;
|
|
outMDParser = parser;
|
|
} else {
|
|
outLoadResolver = null;
|
|
outMDParser = null;
|
|
}
|
|
}
|
|
|
|
private static AnalysisRegistry RegisterAnalysis(TypeData typeData) {
|
|
AnalysisRegistry analysisRegistry = new AnalysisRegistry(typeData);
|
|
analysisRegistry.RegisterAnalysis(VirtualCallAnalysis.makeFactory());
|
|
return analysisRegistry;
|
|
}
|
|
|
|
private static void AddPhases(Bartok.Ir.PhaseList phases,
|
|
AnalysisRegistry analysisRegistry,
|
|
String outputName,
|
|
TypeData typeData) {
|
|
if (StageControl.PrintContainers) {
|
|
phases.Add(new TypeDataPrintPhase("parser"));
|
|
}
|
|
if (StageControl.DumpContainers) {
|
|
phases.Add(new TypeDataPrettyPhase("parser"));
|
|
}
|
|
|
|
// to allow /noisyphase:parser since MetaDataParser is not a phase
|
|
phases.Add(new TypeDataDummyPhase("parser"));
|
|
|
|
phases.Add(new ScalarConversion());
|
|
phases.Add(new TypeChecker());
|
|
|
|
if (StageControl.SingSharpTemplateRemover) {
|
|
phases.Add(new SingSharpTemplateRemover());
|
|
}
|
|
if (StageControl.RuntimeMods) {
|
|
phases.Add(new RuntimeMods());
|
|
}
|
|
|
|
// We need to do some immediate cleanup of the GCs so that the first
|
|
// treeshake will get us down to only the code for the selected GC
|
|
// configuration. In particular, we need to clear out the statements
|
|
// like "switch(gctype)" and remove the code on dead branches.
|
|
if (StageControl.IrMultiPropSimple) {
|
|
phases.Add(new IrMultiPropSimple("System.GC"));
|
|
phases.Add(new IrMultiPropSimple("Microsoft.Bartok.Runtime.GC"));
|
|
}
|
|
if (StageControl.IrDeadAssignmentSimple1) {
|
|
phases.Add(new IrDeadAssignmentSimplePhase("System.GC"));
|
|
phases.Add(new IrDeadAssignmentSimplePhase("Microsoft.Bartok.Runtime.GC"));
|
|
}
|
|
|
|
if (StageControl.IrTreeShake && !StageControl.BindMdil) {
|
|
phases.Add(new IrTreeShake(typeData.EntryPoints,
|
|
dynamicLoads,
|
|
StageControl.WholeProgram,
|
|
analysisRegistry,
|
|
false));
|
|
}
|
|
|
|
//
|
|
//phases.Add
|
|
// (new DynamicCount
|
|
// ("VirtualCallsStart",
|
|
// new DynamicCount.OpcodeFilter
|
|
// (Operator.OpCodes.CallVirtual,
|
|
// Operator.OpCodes.InterfaceCall),
|
|
// new DynamicCount.SiteAndTargetReporting()));
|
|
//
|
|
|
|
//
|
|
//phases.Add
|
|
// (new DynamicCount
|
|
// ("ASCstart",
|
|
// new DynamicCount.OpcodeFilter
|
|
// (Operator.OpCodes.CheckArrayStore,
|
|
// Operator.OpCodes.CheckVectorStore),
|
|
// new DynamicCount.SiteReporting()));
|
|
//
|
|
|
|
if (StageControl.PtrAnalysis || StageControl.PtrAnalysisEarly) {
|
|
phases.Add(PtrTypeSimpleSystem.CreateAnalysis());
|
|
phases.Add(PtrTypeHierarchySystem.CreateAnalysis());
|
|
phases.Add(PtrTypeSetSystem.CreateAnalysis());
|
|
}
|
|
|
|
// create wrapper that insert calls to leaveGCSafeState and
|
|
// enterGCSafeState.
|
|
phases.Add(new CreateEntryPointWrapper());
|
|
|
|
// trap ValueType.Equals and override it by compiler generated
|
|
// routines.
|
|
if (StageControl.IrOverrideValueTypeEquals) {
|
|
phases.Add(new Convert.ValueTypeEquals());
|
|
}
|
|
|
|
if (StageControl.LimitedReflection) {
|
|
phases.Add(new Convert.OverrideVTableInit());
|
|
}
|
|
|
|
if (StageControl.IrConvertSizeofPrimitive) {
|
|
Convert.ToMir.Mask mask = Convert.ToMir.Mask.SizeofPrimitive;
|
|
phases.Add(new Convert.ToMir(mask));
|
|
}
|
|
|
|
if (!StageControl.TargetMdil) {
|
|
phases.Add(new Convert.MarshalPhase());
|
|
}
|
|
|
|
// Perform first- and last-use analysis; add explicit region
|
|
// variables and effects.
|
|
|
|
// must happen after DemandAnalysis, but before any inlining /
|
|
// rearranging basic blocks or calls.
|
|
#if !VC
|
|
if(StageControl.TryAllSupport) {
|
|
phases.Add(new Bartok.Convert.PropagateLogging(analysisRegistry));
|
|
phases.Add(new TypeDataDummyPhase("TryAll-end-pipeline"));
|
|
}
|
|
#endif
|
|
|
|
if (StageControl.IrScanCallEffects) {
|
|
phases.Add(new IrScanCallEffects());
|
|
}
|
|
|
|
if(StageControl.DumpInheritance) {
|
|
phases.Add(new DumpInheritancePhase(StageControl.DumpInheritanceFile));
|
|
}
|
|
|
|
#if PHX_TODO
|
|
phases.Add(new TypeDataToPhoenix());
|
|
#endif
|
|
phases.Add(new TypeInit(initializerSkips));
|
|
|
|
if (StageControl.InstrumentCalls) {
|
|
phases.Add(new InstrumentCalls());
|
|
}
|
|
|
|
if (StageControl.IrStoreChecks) {
|
|
phases.Add(new IrStoreCheckElim());
|
|
}
|
|
if (StageControl.BuildC2Mods
|
|
&& StageControl.UnmanagedStrings) {
|
|
phases.Add(new IrUnmanagedStrings());
|
|
}
|
|
phases.Add(IrCleanup.Create());
|
|
if (StageControl.BuildC2Mods
|
|
&& StageControl.IdentifyAsMethods) {
|
|
phases.Add(new IrIdentifyAsMethods());
|
|
}
|
|
|
|
if (StageControl.WholeProgram
|
|
&& StageControl.IrDeadAssignmentSimpleFormals
|
|
&& StageControl.IrTreeShake
|
|
&& !StageControl.BindMdil) {
|
|
phases.Add(new IrDeadAssignmentSimpleFormalsPhase());
|
|
phases.Add(new IrTreeShake(typeData.EntryPoints,
|
|
dynamicLoads,
|
|
StageControl.WholeProgram,
|
|
analysisRegistry,
|
|
false));
|
|
}
|
|
|
|
if (!StageControl.TargetMdil) {
|
|
phases.Add(new Convert.IrInsertDelegate());
|
|
}
|
|
|
|
phases.Add(new Convert.ToMir(Convert.ToMir.Mask.Constructor));
|
|
|
|
// When only one class implements an interface, replace the interface
|
|
// with the class.
|
|
if (StageControl.IrFindConcrete && StageControl.WholeProgram) {
|
|
phases.Add(new IrFindConcrete());
|
|
}
|
|
|
|
if (StageControl.DevirtualizeCall) {
|
|
phases.Add(new IrDevirtualizeCall(analysisRegistry));
|
|
}
|
|
if (StageControl.IrImproveTypes && StageControl.WholeProgram) {
|
|
phases.Add(new IrImproveTypes(analysisRegistry));
|
|
}
|
|
if(StageControl.IrPeepholeNull) {
|
|
phases.Add(new IrPeepholeNull());
|
|
}
|
|
if (StageControl.IrSimpleInliner) {
|
|
phases.Add(new IrSimpleInliner(new IrInline(), false, false, false));
|
|
} else if (StageControl.IrAttributeInliner) {
|
|
// inline methods that has [inline] attributes.
|
|
phases.Add(new IrSimpleInliner(new IrInline(), false, false));
|
|
}
|
|
|
|
if (StageControl.FailAfterInliner) {
|
|
phases.Add(new FailPhase());
|
|
}
|
|
|
|
if (StageControl.IrMultiPropSimple) {
|
|
phases.Add(new IrMultiPropSimple());
|
|
}
|
|
if (StageControl.IrSuppressExnEdges) {
|
|
phases.Add(new IrSuppressExnEdges());
|
|
}
|
|
|
|
if (StageControl.IrLoadStoreOpt) {
|
|
phases.Add(new IrLoadStoreOpt(analysisRegistry));
|
|
}
|
|
if (StageControl.DevirtualizeCall) {
|
|
phases.Add(new IrDevirtualizeCall(analysisRegistry));
|
|
}
|
|
if (StageControl.IrImproveTypes && StageControl.WholeProgram) {
|
|
phases.Add(new IrImproveTypes(analysisRegistry));
|
|
}
|
|
if(StageControl.IrPeepholeNull) {
|
|
phases.Add(new IrPeepholeNull());
|
|
}
|
|
|
|
if (StageControl.IrSimpleInliner &&
|
|
StageControl.IrInlinerDoIncreaseSize) {
|
|
phases.Add(new IrSimpleInliner(new IrInline(), true, false, false));
|
|
}
|
|
|
|
if (StageControl.LazyTypeInits
|
|
&& StageControl.OptLazyTypeInits) {
|
|
phases.Add(new TypeInit(initializerSkips, true));
|
|
}
|
|
|
|
// Eliminate unnecessary instanceOf/check casts. Only makes
|
|
// 2 passes by punting back edges.
|
|
if (StageControl.IrTypeTestElimPunt) {
|
|
phases.Add(new TypeTestElimPunt());
|
|
}
|
|
|
|
// Eliminate unnecessary instanceOf/check casts - full iterative
|
|
// analysis. More expensive than the above analysis, but yields
|
|
// little improvement in practice - TODO: should be remeasured because
|
|
// of some fixes.
|
|
if (StageControl.IrTypeTestElim) {
|
|
phases.Add(new TypeTestElim());
|
|
}
|
|
|
|
// Deletes all CheckCasts and instanceOf IDisposable for sake of
|
|
// experimentation. Normally not enabled, as it is unsafe.
|
|
|
|
if (StageControl.IrDeleteCheckCasts) {
|
|
phases.Add(new DeleteCheckCast());
|
|
}
|
|
|
|
if (StageControl.IrConvertOpt) {
|
|
phases.Add(new IrConvertOpt());
|
|
phases.Add(new IrDeadAssignmentSimplePhase());
|
|
phases.Add(new IrReverseCopyProp());
|
|
}
|
|
|
|
// Just do thread analysis once.
|
|
IrLockedFields locks = null;
|
|
if (StageControl.ExtendThreadFieldsABCD ||
|
|
StageControl.SsaNullCheckGlobalThreaded ||
|
|
StageControl.IrLoadStoreOptThreaded) {
|
|
|
|
if (StageControl.IrTreeShake && !StageControl.BindMdil) {
|
|
phases.Add(new IrTreeShake(typeData.EntryPoints,
|
|
dynamicLoads,
|
|
StageControl.WholeProgram,
|
|
analysisRegistry,
|
|
false));
|
|
}
|
|
|
|
if(StageControl.OptimisticLocking) {
|
|
locks = new ClassIrLockedFields(analysisRegistry);
|
|
} else {
|
|
locks = new IrLockedFields(analysisRegistry);
|
|
}
|
|
phases.Add(locks);
|
|
}
|
|
|
|
// Array bounds check elimination
|
|
if (StageControl.ABCD) {
|
|
phases.Add(new ABCD(analysisRegistry, locks));
|
|
}
|
|
|
|
if (StageControl.IrConvertArrayBounds) {
|
|
Convert.ToMir.Mask mask = Convert.ToMir.Mask.CheckVectorBounds;
|
|
phases.Add(new Convert.ToMir(mask));
|
|
}
|
|
|
|
#if !LILC
|
|
// not needed in LILC mode because ToMir-Lilc lowers InterfaceCall
|
|
if (StageControl.IrConvertInterface && !StageControl.TargetMdil) {
|
|
Convert.ToMir.Mask mask = Convert.ToMir.Mask.InterfaceCall;
|
|
phases.Add(new Convert.ToMir(mask));
|
|
}
|
|
#endif
|
|
|
|
if (StageControl.IrConvertSimpleArrayAccess) {
|
|
Convert.ToMir.Mask mask = Convert.ToMir.Mask.SimpleArrayAccess;
|
|
phases.Add(new Convert.ToMir(mask));
|
|
}
|
|
|
|
if (StageControl.IrCloneLoopHeader) {
|
|
phases.Add(new IrCloneLoopHeader());
|
|
phases.Add(new IrJumpElim());
|
|
phases.Add(new IrMultiPropSimple());
|
|
}
|
|
|
|
if (StageControl.SsaOpts) {
|
|
if (StageControl.SsaNullCheckGlobalThreaded) {
|
|
phases.Add(SSAPhase.Create(analysisRegistry, locks));
|
|
} else {
|
|
phases.Add(SSAPhase.Create());
|
|
}
|
|
}
|
|
|
|
if(locks != null && !StageControl.IrLoadStoreOptThreaded) {
|
|
locks = null;
|
|
}
|
|
|
|
// IrInsertStructCopy phase insert a StructCopy() method
|
|
// to each struct type, and lower struct Id operators
|
|
// to a call to StructCopy() method.
|
|
phases.Add(new Convert.IrInsertStructCopy());
|
|
|
|
#if !VC
|
|
if(StageControl.TryAllSupport) {
|
|
phases.Add(new IrInsertLogging());
|
|
}
|
|
|
|
if(StageControl.TryAllSupport &&
|
|
StageControl.AtomicSupportUpdateEnlistOptFlow) {
|
|
// without the IrLoadStoreOpt here, EnlistIndirects
|
|
// generated by [Store]StructFields can't be moved.
|
|
phases.Add(new IrLoadStoreOpt(analysisRegistry));
|
|
phases.Add(new IrInsertUpdateEnlistments());
|
|
// otherwise CSE misses things that it should be eliminating
|
|
phases.Add(new IrMultiPropSimple());
|
|
}
|
|
|
|
if (StageControl.TryAllSupport &&
|
|
StageControl.IrKeepManager) {
|
|
phases.Add(new IrKeepManager(analysisRegistry));
|
|
}
|
|
#endif
|
|
|
|
if(StageControl.IrPeepholeNull) {
|
|
phases.Add(new IrPeepholeNull());
|
|
}
|
|
|
|
if(StageControl.IrStructVectorOperations) {
|
|
phases.Add(new IrStruct(true));
|
|
}
|
|
|
|
if (StageControl.IrLoadStoreOpt) {
|
|
if (StageControl.IrLoadStoreOptThreaded) {
|
|
phases.Add(new IrLoadStoreOptTSGlobal(analysisRegistry,
|
|
locks));
|
|
locks = null;
|
|
StageControl.IrLoadStoreOptThreaded = false;
|
|
} else {
|
|
phases.Add(new IrLoadStoreOpt(analysisRegistry));
|
|
}
|
|
}
|
|
|
|
#if !VC
|
|
if (StageControl.TryAllSupport &&
|
|
StageControl.AtomicSupportUpdateEnlistOpt) {
|
|
phases.Add(new IrSimpleAvoidUpgrade());
|
|
}
|
|
#endif
|
|
|
|
if (StageControl.IrConvertComplexArrayAccess) {
|
|
Convert.ToMir.Mask mask = Convert.ToMir.Mask.ComplexArrayAccess;
|
|
phases.Add(new Convert.ToMir(mask));
|
|
}
|
|
|
|
if (StageControl.IrConvertExpandedArrayAccess) {
|
|
Convert.ToMir.Mask mask = Convert.ToMir.Mask.ExpandedArrayAccess;
|
|
phases.Add(new Convert.ToMir(mask));
|
|
}
|
|
|
|
if (StageControl.ArraySupportOptimizePass && StageControl.SsaOpts) {
|
|
phases.Add(SSAPhase.Create());
|
|
}
|
|
|
|
#if !VC
|
|
if (StageControl.TryAllSupport &&
|
|
StageControl.TryAllSupportOptimizePass &&
|
|
StageControl.SsaOpts) {
|
|
phases.Add(SSAPhase.Create());
|
|
}
|
|
#endif
|
|
|
|
if (StageControl.IrInitStaticField) {
|
|
phases.Add(new IrInitStaticField());
|
|
}
|
|
|
|
if (StageControl.LazyTypeInits
|
|
&& StageControl.OptLazyTypeInits
|
|
&& StageControl.TypeInitRemoveEmptyCctors) {
|
|
phases.Add(new TypeInit(initializerSkips, true));
|
|
}
|
|
|
|
if (StageControl.GCType ==
|
|
StageControl.ReferenceCountingCollector) {
|
|
phases.Add(new IrStructRCUpdate());
|
|
}
|
|
|
|
if (StageControl.GCType ==
|
|
StageControl.DeferredReferenceCountingCollector) {
|
|
phases.Add(new IrStructDRCUpdate());
|
|
}
|
|
|
|
if (StageControl.IrTreeShake
|
|
&& StageControl.IrTreeShakeLate
|
|
&& !StageControl.BindMdil) {
|
|
phases.Add(new IrTreeShake(typeData.EntryPoints,
|
|
dynamicLoads,
|
|
StageControl.WholeProgram,
|
|
analysisRegistry,
|
|
false));
|
|
}
|
|
|
|
if (StageControl.TypedReference) {
|
|
Convert.ToMir phase2 =
|
|
new Convert.ToMir(Convert.ToMir.Mask.Vararg2);
|
|
Convert.ToMir phase1 =
|
|
new Convert.ToMir(Convert.ToMir.Mask.Vararg1, phase2);
|
|
phases.Add(phase1);
|
|
|
|
// All of vararg1 must finish before vararg2, so we wrap vararg2
|
|
// in a typedata phase to enforce that.
|
|
phases.Add(new TypeDataMethodPhase(phase2));
|
|
}
|
|
|
|
//
|
|
//// We do not know where all of the calls will be because lowering can
|
|
//// introduce calls. We make a best guess here. If we moved all
|
|
//// call-generating lowering to HIR (via ToMir or equivalent), then
|
|
//// this could be easily done. We are currently missing calls for the
|
|
//// following:
|
|
//// - pinvoke, stubs, etc
|
|
//// - some arithmetic conversions
|
|
//// - casts - can't add because not all are calls
|
|
//// - RC, tryall, atomic
|
|
//// - others?
|
|
//phases.Add
|
|
// (new DynamicCount
|
|
// ("Calls",
|
|
// new DynamicCount.OpcodeFilter
|
|
// (Operator.OpCodes.Call,
|
|
// Operator.OpCodes.CallIndirect,
|
|
// Operator.OpCodes.CallVirtual,
|
|
// Operator.OpCodes.InterfaceCall,
|
|
// Operator.OpCodes.MonitorEnter,
|
|
// Operator.OpCodes.MonitorExit,
|
|
// Operator.OpCodes.IndirectToData,
|
|
// Operator.OpCodes.CustomGetSize,
|
|
// Operator.OpCodes.CheckVectorStore,
|
|
// Operator.OpCodes.CheckVectorElementAddress,
|
|
// Operator.OpCodes.InitVector,
|
|
// Operator.OpCodes.CheckArrayStore,
|
|
// Operator.OpCodes.CheckArrayElementAddress,
|
|
// Operator.OpCodes.InitArray,
|
|
// Operator.OpCodes.InitType,
|
|
// Operator.OpCodes.GetITable,
|
|
// Operator.OpCodes.NewObject,
|
|
// Operator.OpCodes.NewVector,
|
|
// Operator.OpCodes.NewArray),
|
|
// new DynamicCount.GlobalReporting()));
|
|
//phases.Add(new TypeDataDummyPhase("dynamiccount1-end-pipeline"));
|
|
//
|
|
|
|
if (StageControl.DynamicCountVirtualCalls) {
|
|
phases.Add
|
|
(new DynamicCount
|
|
("VirtualCallsEnd",
|
|
new DynamicCount.OpcodeFilter
|
|
(Operator.OpCodes.CallVirtual,
|
|
Operator.OpCodes.InterfaceCall),
|
|
new DynamicCount.SiteAndTargetReporting()));
|
|
}
|
|
|
|
if(StageControl.DynamicCountBoundsChecks) {
|
|
phases.Add
|
|
(new DynamicCount
|
|
("Vector Bounds Checks",
|
|
new DynamicCount.OpcodeFilter
|
|
(Operator.OpCodes.CheckVectorBounds,
|
|
Operator.OpCodes.CompareVectorBounds),
|
|
new DynamicCount.SiteReporting()));
|
|
phases.Add(new TypeDataDummyPhase("dynamiccount2-end-pipeline"));
|
|
}
|
|
|
|
if(StageControl.DynamicCountNullChecks) {
|
|
phases.Add
|
|
(new DynamicCount
|
|
("Null Reference Checks",
|
|
new DynamicCount.OpcodeFilter
|
|
(Operator.OpCodes.CheckNonNull),
|
|
new DynamicCount.SiteReporting()));
|
|
phases.Add(new TypeDataDummyPhase("dynamiccount3-end-pipeline"));
|
|
|
|
phases.Add
|
|
(new DynamicCount
|
|
("Null Check On Operator",
|
|
new DynamicCount.OpAttribsFilter
|
|
(OperatorAttributes.NonNullMemoryAccess),
|
|
new DynamicCount.SiteReporting()));
|
|
phases.Add(new TypeDataDummyPhase("dynamiccount4-end-pipeline"));
|
|
}
|
|
|
|
if(StageControl.DynamicCountLoads) {
|
|
phases.Add
|
|
(new DynamicCount
|
|
("Loads",
|
|
new DynamicCount.OpcodeFilter
|
|
(Operator.OpCodes.ObjectField),
|
|
new DynamicCount.SiteReporting()));
|
|
phases.Add(new TypeDataDummyPhase("dynamiccount5-end-pipeline"));
|
|
}
|
|
|
|
if(StageControl.DynamicCountStores) {
|
|
phases.Add
|
|
(new DynamicCount
|
|
("Stores",
|
|
new DynamicCount.OpcodeFilter
|
|
(Operator.OpCodes.StoreObjectField),
|
|
new DynamicCount.SiteReporting()));
|
|
phases.Add(new TypeDataDummyPhase("dynamiccount6-end-pipeline"));
|
|
}
|
|
|
|
|
|
//
|
|
//phases.Add
|
|
// (new DynamicCount
|
|
// ("ASCend",
|
|
// new DynamicCount.OpcodeFilter
|
|
// (Operator.OpCodes.CheckArrayStore,
|
|
// Operator.OpCodes.CheckVectorStore),
|
|
// new DynamicCount.SiteReporting()));
|
|
//phases.Add(new TypeDataDummyPhase("dynamiccount7-end-pipeline"));
|
|
//
|
|
|
|
//
|
|
//phases.Add
|
|
// (new DynamicCount
|
|
// ("WB",
|
|
// new DynamicCount.OpcodeFilter
|
|
// (Operator.OpCodes.LocWriteBarrier),
|
|
// new DynamicCount.GlobalReporting()));
|
|
//phases.Add(new TypeDataDummyPhase("dynamiccount8-end-pipeline"));
|
|
//
|
|
|
|
if (StageControl.WholeProgram && StageControl.OptRuntimeData) {
|
|
phases.Add(new RuntimeData());
|
|
}
|
|
|
|
if (StageControl.IrConvertArrayOpt) {
|
|
phases.Add(new IrConvertArrayOpt());
|
|
}
|
|
|
|
if (StageControl.PtrAnalysis || StageControl.PtrAnalysisLate) {
|
|
phases.Add(PtrTypeSimpleSystem.CreateAnalysis());
|
|
phases.Add(PtrTypeHierarchySystem.CreateAnalysis());
|
|
phases.Add(PtrTypeSetSystem.CreateAnalysis());
|
|
}
|
|
|
|
#if LILC
|
|
Verbosity.level = NoiseLevel.PerPhase;
|
|
// The Lilc translation adds new types to typedata,
|
|
// thus needs to happen before chooserep
|
|
phases.Add(new Convert.ToMir(Convert.ToMir.Mask.Lilc));
|
|
|
|
// inline polymorphic method just added by ToMir-Lilc
|
|
if (StageControl.IrSimpleInliner) {
|
|
phases.Add(new IrSimpleInliner(new IrInline(), false, true,
|
|
false, 0, 0, 0, true));
|
|
}
|
|
|
|
// Lower NewObject added by ToMir-Lilc and inlining
|
|
phases.Add(new Convert.ToMir(Convert.ToMir.Mask.Constructor));
|
|
#endif
|
|
|
|
// insert write barrier after chooserep so we know the size of
|
|
// of objects. This is needed because we try to remove write
|
|
// barrier when we store to the young generation, however,
|
|
// big objects are in the old generation even though it is
|
|
// newly created. Therefore, we need to know object size to
|
|
// know if it is a big object.
|
|
if (StageControl.InsertWriteBarrier ||
|
|
StageControl.InsertAllBarrier ||
|
|
StageControl.InsertCoCoBarrier) {
|
|
if (StageControl.InsertCoCoBarrier) {
|
|
Util.Message(NoiseLevel.Silence,"Note: Using CoCo barriers!!");
|
|
phases.Add(new IrCoCoBarrier());
|
|
phases.Add(new IrJumpElim());
|
|
} else if (StageControl.InsertAllBarrier) {
|
|
Util.Message(NoiseLevel.Silence,"Note: Using all-barrier");
|
|
phases.Add(new IrAllBarrier());
|
|
} else {
|
|
Util.Message(NoiseLevel.Silence,"Note: Using ref write barrier");
|
|
phases.Add(new IrRefWriteBarrier());
|
|
}
|
|
phases.Add(new IrNoHeapAccess());
|
|
}
|
|
|
|
// convert type tests and sizeof effect to Mir
|
|
Convert.ToMir.Mask typeMask = Convert.ToMir.Mask.Sizeof;
|
|
|
|
if (!StageControl.TargetMdil) {
|
|
typeMask |= Convert.ToMir.Mask.CheckCast;
|
|
}
|
|
|
|
Convert.ToMir.Mask typeMaskRC =
|
|
Convert.ToMir.Mask.GetCurrentThread
|
|
| Convert.ToMir.Mask.InitCopyBlock
|
|
| Convert.ToMir.Mask.AllocStruct
|
|
| Convert.ToMir.Mask.ConvertConvert;
|
|
|
|
typeMaskRC |= Convert.ToMir.Mask.NewArray;
|
|
if (!StageControl.TargetMdil) {
|
|
typeMaskRC |= Convert.ToMir.Mask.ArrayTypeTest;
|
|
|
|
if(StageControl.IrExposeAllocationCall) {
|
|
typeMaskRC |= Convert.ToMir.Mask.Allocation;
|
|
}
|
|
}
|
|
|
|
bool isEitherRCCollector =
|
|
(StageControl.GCType == StageControl.ReferenceCountingCollector)
|
|
|| (StageControl.GCType
|
|
== StageControl.DeferredReferenceCountingCollector);
|
|
|
|
if (!isEitherRCCollector) {
|
|
typeMask |= typeMaskRC;
|
|
}
|
|
if (StageControl.TypedReference
|
|
&& !StageControl.TargetMdil) {
|
|
typeMask |= Convert.ToMir.Mask.TypedRef;
|
|
}
|
|
phases.Add(new Convert.ToMir(typeMask));
|
|
|
|
#if LILC
|
|
if (StageControl.IrSimpleInliner) {
|
|
phases.Add(new IrSimpleInliner(new IrInline(), false, true,
|
|
true, 0, 0, 0, true));
|
|
}
|
|
|
|
if(StageControl.TypeInitElim) {
|
|
phases.Add(new IrTypeInitElim(analysisRegistry));
|
|
}
|
|
|
|
if (StageControl.IrRemoveDoubleCmp) {
|
|
phases.Add(new IrCmpElim());
|
|
}
|
|
|
|
if (StageControl.IrArrayBaseLength) {
|
|
phases.Add(new IrArrayBaseLength());
|
|
phases.Add(new IrDeadAssignmentSimplePhase());
|
|
}
|
|
|
|
if (StageControl.IrTreeShake
|
|
&& StageControl.IrTreeShakeLate
|
|
&& !StageControl.BindMdil) {
|
|
phases.Add(new IrTreeShake(typeData.EntryPoints,
|
|
dynamicLoads,
|
|
StageControl.WholeProgram,
|
|
analysisRegistry,
|
|
true));
|
|
}
|
|
}
|
|
#else
|
|
if (StageControl.IrSimpleInliner) {
|
|
phases.Add(new IrSimpleInliner(new IrInline(), false, true,
|
|
true, 0, 0, 0));
|
|
}
|
|
|
|
if (StageControl.TypeInitElim) {
|
|
phases.Add(new IrTypeInitElim(analysisRegistry));
|
|
}
|
|
|
|
if (StageControl.IrRemoveDoubleCmp) {
|
|
phases.Add(new IrCmpElim());
|
|
}
|
|
|
|
if (StageControl.IrArrayBaseLength) {
|
|
phases.Add(new IrArrayBaseLength());
|
|
phases.Add(new IrDeadAssignmentSimplePhase());
|
|
}
|
|
|
|
if (StageControl.IrInitTypeInliner
|
|
&& StageControl.LazyTypeInits
|
|
&& !StageControl.TargetMdil) {
|
|
phases.Add(new IrInitTypeInliner(typeData, new IrInline()));
|
|
}
|
|
|
|
if (isEitherRCCollector) {
|
|
AddRCPhases(phases, analysisRegistry);
|
|
}
|
|
|
|
if (isEitherRCCollector) {
|
|
phases.Add(new Convert.ToMir(typeMaskRC));
|
|
|
|
if (StageControl.IrSimpleInliner) {
|
|
if (StageControl.RCCollectorOptInlineRCUpdates) {
|
|
phases.Add(new IrSimpleInliner(new IrInline(),
|
|
true, false,
|
|
false));
|
|
} else {
|
|
phases.Add(new IrSimpleInliner(new IrInline(),
|
|
false, true, true,
|
|
0, 0, 0));
|
|
}
|
|
}
|
|
}
|
|
|
|
#if !VC
|
|
if(StageControl.TryAllSupport &&
|
|
StageControl.TryAllDecomposeOpt) {
|
|
phases.Add(new IrDecomposeTransMemChecks(analysisRegistry));
|
|
// IrDecomposeTransMemChecks emits GetCurrentThread ops
|
|
phases.Add(new IrLoadStoreOpt(analysisRegistry));
|
|
Convert.ToMir.Mask mask = Convert.ToMir.Mask.GetCurrentThread;
|
|
phases.Add(new Convert.ToMir(mask));
|
|
}
|
|
|
|
if (StageControl.TryAllSupport &&
|
|
StageControl.IrConvertTryAll) {
|
|
Convert.ToMir.Mask mask = Convert.ToMir.Mask.TryAll;
|
|
phases.Add(new Convert.ToMir(mask));
|
|
if (StageControl.IrSimpleInliner) {
|
|
phases.Add(new IrSimpleInliner(new IrInline(),
|
|
true,
|
|
false));
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// The inliners may inline some of the methods that handle special
|
|
// MSIL opcodes, adding in instructions like Id<Struct> that we
|
|
// don't expect to see this late in the lowering. Add one more
|
|
// scan of the code to remove them.
|
|
phases.Add(new Convert.IrInsertStructCopy());
|
|
|
|
if (StageControl.IrTreeShake
|
|
&& StageControl.IrTreeShakeLate
|
|
&& !StageControl.BindMdil) {
|
|
phases.Add(new IrTreeShake(typeData.EntryPoints,
|
|
dynamicLoads,
|
|
StageControl.WholeProgram,
|
|
analysisRegistry,
|
|
true));
|
|
}
|
|
}
|
|
#endif
|
|
|
|
private static void AddRCPhases(Bartok.Ir.PhaseList phases,
|
|
AnalysisRegistry ar) {
|
|
bool isRC =
|
|
StageControl.GCType ==
|
|
StageControl.ReferenceCountingCollector;
|
|
bool isDRC =
|
|
StageControl.GCType ==
|
|
StageControl.DeferredReferenceCountingCollector;
|
|
|
|
Util.Assert(isRC || isDRC);
|
|
String rcName = isRC ? "RC" : "DRC";
|
|
|
|
if (StageControl.IrStructUnwrapping) {
|
|
phases.Add(new IrStructUnwrap(RCAproposKind.Checker));
|
|
}
|
|
|
|
if (StageControl.RCCollectorShowStatistics) {
|
|
String message = "Before " + rcName + " Update Injection";
|
|
phases.Add(new IrBBStats(message));
|
|
}
|
|
MethodPhase insertionPhase = isRC ?
|
|
(MethodPhase)new IrRCUpdate() : new IrDRCUpdate();
|
|
phases.Add(insertionPhase);
|
|
if (StageControl.RCCollectorShowStatistics) {
|
|
String message = "After " + rcName + " Update Injection";
|
|
phases.Add(new IrBBStats(message));
|
|
}
|
|
|
|
if (StageControl.RCCollectorOptImmortals) {
|
|
phases.Add(new IrImmortalObjectRCUpdates());
|
|
}
|
|
|
|
if (isRC && StageControl.RCCollectorOptORoots) {
|
|
phases.Add(new IrJumpElim());
|
|
IrOverlookingRootsRCOpts orootsRCOpts =
|
|
new IrOverlookingRootsRCOpts(ar);
|
|
phases.Add(orootsRCOpts);
|
|
}
|
|
|
|
if (StageControl.RCCollectorOptCoalescingUpdates) {
|
|
phases.Add(new IrBBLocalCoalesceRCUpdates());
|
|
}
|
|
if (StageControl.RCCollectorOptStaticAcyclicRefTypeUpdates) {
|
|
phases.Add(new IrAcyclicRefTypeRCUpdates());
|
|
}
|
|
if (StageControl.RCCollectorOptNonNullRCUpdates) {
|
|
phases.Add(SSAPhase.NullCheckAnalysis());
|
|
}
|
|
if (StageControl.RCCollectorShowStatistics) {
|
|
String message = "After " + rcName + " Optimizations";
|
|
phases.Add(new IrBBStats(message));
|
|
}
|
|
|
|
phases.Add(new Convert.ToMir(Convert.ToMir.Mask.RCUpdate));
|
|
if (StageControl.RCCollectorOptInlineRCUpdates) {
|
|
phases.Add(new IrRCUpdateInliner());
|
|
}
|
|
phases.Add(new TypeDataDummyPhase("end-RC-end-pipeline"));
|
|
}
|
|
|
|
public static ArrayList fileNames;
|
|
public static ArrayList mdilFileNames;
|
|
public static ArrayList refFileNames;
|
|
public static ArrayList libDirNames;
|
|
private static ArrayList outputDirNames;
|
|
public static String outputDirName;
|
|
public static ArrayList overrideNames;
|
|
public static ArrayList overrideDefNames;
|
|
public static String outputRootName;
|
|
public static ArrayList entryPoints;
|
|
public static ArrayList linkNames;
|
|
private static ArrayList initializerSkips;
|
|
private static ArrayList dynamicLoads;
|
|
private static bool alreadyPrintedUsage = false;
|
|
|
|
private static String StripName(String fileName) {
|
|
// strip off extension, if there is one.
|
|
int dotIndex = fileName.LastIndexOf('.');
|
|
if (dotIndex != -1) {
|
|
String ext = fileName.Substring(dotIndex + 1);
|
|
if (ext.Equals("dll") || ext.Equals("obj")
|
|
|| ext.Equals("exe")) {
|
|
fileName = fileName.Substring(0, dotIndex);
|
|
}
|
|
}
|
|
return fileName;
|
|
}
|
|
|
|
private static String GetShortName(String fileName) {
|
|
int charindex = Math.Max(fileName.LastIndexOf('/'),
|
|
fileName.LastIndexOf('\\'));
|
|
String shortName = (charindex >= 0)
|
|
? fileName.Substring(charindex + 1)
|
|
: fileName;
|
|
return shortName;
|
|
}
|
|
|
|
private static String GetDirName(String fileName) {
|
|
int charindex = Math.Max(fileName.LastIndexOf('/'),
|
|
fileName.LastIndexOf('\\'));
|
|
String dirName = (charindex >= 0)
|
|
? fileName.Substring(0, charindex + 1)
|
|
: "";
|
|
return dirName;
|
|
}
|
|
|
|
private static String ComputeOutputName(String inputFileName,
|
|
String outputDirName) {
|
|
String fileName = Path.GetFileNameWithoutExtension(inputFileName);
|
|
String outputName = outputDirName + '\\' + fileName;
|
|
return outputName;
|
|
}
|
|
|
|
private static String ComputeObjFileName(String outputName) {
|
|
string objFileName;
|
|
int len = outputName.Length;
|
|
string desiredSuffix = StageControl.TargetMdil ? ".mdil" : ".obj";
|
|
int suf = len-desiredSuffix.Length;
|
|
if ((suf > 0)
|
|
&& (String.Compare(outputName.Substring(suf,desiredSuffix.Length),
|
|
desiredSuffix, true)
|
|
== 0)) {
|
|
objFileName = outputName;
|
|
} else {
|
|
objFileName = outputName + desiredSuffix;
|
|
}
|
|
return objFileName;
|
|
}
|
|
|
|
private static void ParseEnvVar(String envVar) {
|
|
#if !ON_SINGULARITY
|
|
String envValue =
|
|
Environment.GetEnvironmentVariable(envVar);
|
|
if (envValue != null) {
|
|
String[] envValueSplit =
|
|
Bartok.Utility.SharedUtil.ParseArgumentString(envValue);
|
|
ParseStringArray(envValueSplit, false);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
// If isCmdLine is false, then the arguments are from an environment
|
|
// variable.
|
|
private static void LoadResponseFile(String filename, bool isCmdLine) {
|
|
StreamReader sr = null;
|
|
try {
|
|
sr = new StreamReader(filename);
|
|
} catch(IOException) {
|
|
Util.UserError("Can't open response file {0}", filename);
|
|
}
|
|
|
|
String s;
|
|
while((s = sr.ReadLine()) != null) {
|
|
String[] args = Bartok.Utility.SharedUtil.sztoszv(s, true);
|
|
ParseStringArray(args, isCmdLine);
|
|
}
|
|
}
|
|
|
|
// If isCmdLine is false, then the arguments are from an environment
|
|
// variable.
|
|
private static void ParseStringArray(String[] args, bool isCmdLine) {
|
|
int index = 0;
|
|
#if ON_SINGULARITY
|
|
index = 1;
|
|
#endif
|
|
while (index < args.Length) {
|
|
String argument = args[index];
|
|
if ((argument[0] == '-') || (argument[0] == '/')) {
|
|
String option = argument.Substring(1);
|
|
ProcessOption(argument, option, args, isCmdLine, ref index);
|
|
} else if (argument[0] == '@') {
|
|
index++;
|
|
String responseFile = argument.Substring(1);
|
|
LoadResponseFile(responseFile, isCmdLine);
|
|
} else {
|
|
index++;
|
|
fileNames.Add(argument);
|
|
}
|
|
}
|
|
}
|
|
|
|
private static void ProcessCmdLine(String[] args) {
|
|
fileNames = new ArrayList();
|
|
refFileNames = new ArrayList();
|
|
libDirNames = new ArrayList();
|
|
overrideNames = new ArrayList();
|
|
overrideDefNames = new ArrayList();
|
|
outputDirNames = new ArrayList();
|
|
entryPoints = new ArrayList();
|
|
initializerSkips = new ArrayList();
|
|
linkNames = new ArrayList();
|
|
dynamicLoads = new ArrayList();
|
|
|
|
ParseEnvVar("BARTOK_COMPILER");
|
|
ParseStringArray(args, true);
|
|
|
|
switch (outputDirNames.Count) {
|
|
case 0: {
|
|
outputDirName = ".\\debug";
|
|
break;
|
|
}
|
|
case 1: {
|
|
outputDirName = (String)outputDirNames[0];
|
|
break;
|
|
}
|
|
default: {
|
|
Util.Error("Specified multiple output directories {0}",
|
|
new CollectionFormatter(outputDirNames));
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (StageControl.BindMdil) {
|
|
mdilFileNames = new ArrayList(fileNames.Count);
|
|
foreach (String file in fileNames) {
|
|
mdilFileNames.Add(file + ".mdil");
|
|
}
|
|
}
|
|
|
|
if (StageControl.TargetMdil) {
|
|
StageControl.Finalizers = false;
|
|
StageControl.OptLazyTypeInits = false;
|
|
StageControl.IrInitStaticField = false;
|
|
StageControl.ConvertArrayInitialization = false;
|
|
StageControl.DirectWbInsertion = true;
|
|
}
|
|
|
|
FixDebugFlags();
|
|
CreateMixinString();
|
|
|
|
if(StageControl.EnableIrExposeAllocationCall
|
|
&& StageControl.DisableIrExposeAllocationCall) {
|
|
Util.UserError("Conflicting flags EnableIrExposeAllocationCall "
|
|
+ " and DisableIrExposeAllocationCall");
|
|
}
|
|
if(StageControl.EnableIrExposeAllocationCall) {
|
|
StageControl.IrExposeAllocationCall = true;
|
|
} else if(StageControl.DisableIrExposeAllocationCall) {
|
|
StageControl.IrExposeAllocationCall = false;
|
|
} else {
|
|
StageControl.IrExposeAllocationCall =
|
|
#if PHXBRIDGE
|
|
//REVIEW: Need to see what CQ impact this has and fix it.
|
|
!StageControl.TargetMdil;
|
|
#else
|
|
StageControl.WholeProgram;
|
|
#endif
|
|
}
|
|
|
|
if((StageControl.GCType == StageControl.ReferenceCountingCollector)
|
|
&& StageControl.StructInheritance) {
|
|
Util.UserError("RC Collector code has not been updated to "
|
|
+ "handle struct inheritance");
|
|
}
|
|
if((StageControl.GCType ==
|
|
StageControl.DeferredReferenceCountingCollector)
|
|
&& StageControl.StructInheritance) {
|
|
Util.UserError("Deferred RC Collector code has not been "
|
|
+ "updated to handle struct inheritance");
|
|
}
|
|
|
|
if(StageControl.TargetMdil) {
|
|
if(!StageControl.GenObjFile) {
|
|
Util.UserError("MDIL code paths do not support asm emission");
|
|
}
|
|
}
|
|
if(StageControl.TargetMdil || StageControl.BindMdil) {
|
|
if(StageControl.LinkedStacks) {
|
|
Util.UserError("MDIL code paths do not support linked stacks");
|
|
}
|
|
if(StageControl.SymbolicDebug) {
|
|
Util.UserError("MDIL code paths do not support symbolic debugging");
|
|
}
|
|
if(StageControl.ProfileLirFunctions) {
|
|
Util.UserError("MDIL code paths do not support ProfileLirFunctions");
|
|
}
|
|
}
|
|
|
|
int codeAlignment = StageControl.DefaultCodeAlignment;
|
|
if (codeAlignment < 1 || codeAlignment > 16 ||
|
|
Util.GetUnsignedPowerOf2((ulong) codeAlignment, 12) == -1) {
|
|
Util.UserError("Default code alignment must be a power of 2 between 1 and 16");
|
|
}
|
|
}
|
|
|
|
private static void FixDebugFlags() {
|
|
if (StageControl.SymbolicDebug) {
|
|
if (StageControl.WholeProgram) {
|
|
// use shortened name for types
|
|
StageControl.FullSymName = false;
|
|
} else {
|
|
// when not whole program, can't do shorten
|
|
// name since we can't detect name clashing
|
|
// between different obj files.
|
|
StageControl.FullSymName = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
private static void CreateMixinString() {
|
|
switch (StageControl.Allocator) {
|
|
case StageControl.BumpAllocator: {
|
|
StageControl.mixinConditionals += ",BumpAllocator";
|
|
break;
|
|
}
|
|
case StageControl.FirstFitAllocator: {
|
|
StageControl.mixinConditionals += ",FirstFitAllocator";
|
|
break;
|
|
}
|
|
case StageControl.SegregatedFreeList: {
|
|
StageControl.mixinConditionals += ",SegregatedFreeList";
|
|
break;
|
|
}
|
|
default: {
|
|
Util.Abort("Unsupported allocator type");
|
|
break;
|
|
}
|
|
}
|
|
if (StageControl.AllThreadMixins) {
|
|
// To avoid having multiple halclass files for different
|
|
// allocators, simply include all the allocator structs in
|
|
// the thread objects (for now). --Bjarne
|
|
StageControl.mixinConditionals += ",AllThreadMixins";
|
|
}
|
|
|
|
switch (StageControl.BumpAllocatorClear) {
|
|
case StageControl.BumpAllocatorPageClear: {
|
|
StageControl.mixinConditionals +=
|
|
",BumpAllocatorPageClear";
|
|
break;
|
|
}
|
|
case StageControl.BumpAllocatorObjectClear: {
|
|
StageControl.mixinConditionals +=
|
|
",BumpAllocatorObjectClear";
|
|
break;
|
|
}
|
|
case StageControl.BumpAllocatorCacheClear: {
|
|
StageControl.mixinConditionals +=
|
|
",BumpAllocatorCacheClear";
|
|
break;
|
|
}
|
|
default: {
|
|
Util.NotReached();
|
|
break;
|
|
}
|
|
}
|
|
|
|
switch (StageControl.GCType) {
|
|
case StageControl.ReferenceCountingCollector: {
|
|
StageControl.mixinConditionals += ",ReferenceCountingGC";
|
|
if (StageControl.RCCollectorVerifyRefCounts) {
|
|
StageControl.mixinConditionals +=
|
|
",ReferenceCountingGCVerification";
|
|
}
|
|
break;
|
|
}
|
|
case StageControl.DeferredReferenceCountingCollector: {
|
|
StageControl.mixinConditionals +=
|
|
",DeferredReferenceCountingGC";
|
|
if (StageControl.RCCollectorVerifyRefCounts) {
|
|
StageControl.mixinConditionals +=
|
|
",DeferredReferenceCountingGCVerification";
|
|
}
|
|
break;
|
|
}
|
|
case StageControl.ConcurrentMSCollector: {
|
|
StageControl.mixinConditionals += ",ConcurrentMSGC";
|
|
break;
|
|
}
|
|
case StageControl.CoCoMSCollector: {
|
|
StageControl.mixinConditionals += ",CoCo,ConcurrentMSGC";
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (StageControl.InsertWriteBarrier == true) {
|
|
switch (StageControl.RemSet) {
|
|
case StageControl.RemSetSSB: {
|
|
StageControl.mixinConditionals += ",SSB";
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (StageControl.GCEnableProfiling) {
|
|
StageControl.mixinConditionals += ",GCProfiling";
|
|
}
|
|
|
|
switch (StageControl.ObjectHeaderKind) {
|
|
case StageControl.ObjectHeaderDefault: {
|
|
StageControl.mixinConditionals += ",ObjectHeaderDefault";
|
|
break;
|
|
}
|
|
case StageControl.ObjectHeaderPostRC: {
|
|
StageControl.mixinConditionals += ",ObjectHeaderPostRC";
|
|
break;
|
|
}
|
|
default: {
|
|
Util.InternalError("Unknown StageControl.ObjectHeaderKind");
|
|
break;
|
|
}
|
|
}
|
|
|
|
switch (StageControl.TargetArch) {
|
|
case StageControl.X86: {
|
|
StageControl.mixinConditionals += ",X86";
|
|
break;
|
|
}
|
|
case StageControl.X64: {
|
|
StageControl.mixinConditionals += ",X64";
|
|
break;
|
|
}
|
|
case StageControl.ARM: {
|
|
StageControl.mixinConditionals += ",ARM";
|
|
break;
|
|
}
|
|
default: {
|
|
Util.InternalError("Unknown StageControl.TargetArch value");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// If isCmdLine is false, then the arguments are from an environment
|
|
// variable.
|
|
private static void ProcessOption(String argument, String option,
|
|
String[] args, bool isCmdLine,
|
|
ref int index) {
|
|
String loweredOption = option.ToLower();
|
|
String optionValue;
|
|
|
|
if (IsOption(args, option, loweredOption, "entry:",
|
|
ref index, out optionValue)) {
|
|
AddSemicolonDelimitedNames(entryPoints, optionValue);
|
|
} else if (IsOption(args, option, loweredOption, "reference:",
|
|
ref index, out optionValue)
|
|
|| IsOption(args, option, loweredOption, "r:",
|
|
ref index, out optionValue)) {
|
|
AddSemicolonDelimitedNames(refFileNames, optionValue);
|
|
} else if (IsOption(args, option, loweredOption, "bartoklink:",
|
|
ref index, out optionValue)) {
|
|
AddSemicolonDelimitedNames(linkNames, optionValue);
|
|
} else if (IsOption(args, option, loweredOption, "override:",
|
|
ref index, out optionValue)) {
|
|
AddSemicolonDelimitedNames(overrideNames, optionValue);
|
|
} else if (IsOption(args, option, loweredOption, "overridedef:",
|
|
ref index, out optionValue)) {
|
|
AddSemicolonDelimitedNames(overrideDefNames, optionValue);
|
|
} else if (IsOption(args, option, loweredOption, "lib:",
|
|
ref index, out optionValue)) {
|
|
AddSemicolonDelimitedNames(libDirNames, optionValue);
|
|
} else if (IsOption(args, option, loweredOption, "out:",
|
|
ref index, out optionValue)) {
|
|
outputRootName = optionValue;
|
|
} else if (IsOption(args, option, loweredOption, "outdir:",
|
|
ref index, out optionValue)) {
|
|
AddSemicolonDelimitedNames(outputDirNames, optionValue);
|
|
} else if (IsOption(args, option, loweredOption, "skip:",
|
|
ref index, out optionValue)) {
|
|
AddSemicolonDelimitedNames(initializerSkips, optionValue);
|
|
} else if (IsOption(args, option, loweredOption, "substitute:",
|
|
ref index, out optionValue)) {
|
|
StageControl.substituteString = optionValue;
|
|
} else if (IsOption(args, option, loweredOption, "dynamicload:",
|
|
ref index, out optionValue)) {
|
|
AddSemicolonDelimitedNames(dynamicLoads, optionValue);
|
|
} else if (IsOption(args, option, loweredOption, "features:",
|
|
ref index, out optionValue)) {
|
|
StageControl.mixinConditionals += "," + optionValue;
|
|
} else if (IsOption(args, option, loweredOption, "verbosity:",
|
|
ref index, out optionValue)) {
|
|
Verbosity.FromString(optionValue);
|
|
} else if (IsOption(args, option, loweredOption,
|
|
"heapsizeconfigurable",
|
|
ref index, out optionValue)) {
|
|
StageControl.HeapSizeConfigurable = true;
|
|
} else if (IsOption(args, option, loweredOption, "marksweepgc",
|
|
ref index, out optionValue)) {
|
|
StageControl.GCType = StageControl.MarkSweepCollector;
|
|
StageControl.GCLargeObjectSize = 2040;
|
|
StageControl.InsertWriteBarrier = false;
|
|
StageControl.Allocator = StageControl.SegregatedFreeList;
|
|
} else if (IsOption(args, option, loweredOption, "tablemarksweepgc",
|
|
ref index, out optionValue)) {
|
|
StageControl.GCType = StageControl.SimpleMarkSweepCollector;
|
|
StageControl.GCLargeObjectSize = 2040;
|
|
StageControl.InsertWriteBarrier = false;
|
|
StageControl.Allocator = StageControl.LocalCacheAllocator;
|
|
} else if (IsOption(args, option, loweredOption, "semispacegc",
|
|
ref index, out optionValue)) {
|
|
StageControl.GCType = StageControl.SemispaceCollector;
|
|
StageControl.InsertWriteBarrier = true;
|
|
StageControl.Allocator = StageControl.BumpAllocator;
|
|
} else if (IsOption(args, option, loweredOption, "slidinggc",
|
|
ref index, out optionValue)) {
|
|
StageControl.GCType = StageControl.SlidingCollector;
|
|
StageControl.InsertWriteBarrier = true;
|
|
StageControl.Allocator = StageControl.BumpAllocator;
|
|
} else if (IsOption(args, option, loweredOption, "adaptivecopyinggc",
|
|
ref index, out optionValue)) {
|
|
StageControl.GCType = StageControl.AdaptiveCopyingCollector;
|
|
StageControl.InsertWriteBarrier = true;
|
|
StageControl.Allocator = StageControl.BumpAllocator;
|
|
} else if (IsOption(args, option, loweredOption,
|
|
"referencecountinggc",
|
|
ref index, out optionValue)) {
|
|
StageControl.GCType = StageControl.ReferenceCountingCollector;
|
|
StageControl.InsertWriteBarrier = false;
|
|
StageControl.Allocator = StageControl.SegregatedFreeList;
|
|
StageControl.GCInlineAllocations = false;
|
|
if (StageControl.ObjectHeaderKind == StageControl.ObjectHeaderDefault) {
|
|
StageControl.ObjectHeaderKind =
|
|
StageControl.ObjectHeaderPostRC;
|
|
}
|
|
if (StageControl.RCCollectorVerifyRefCounts) {
|
|
StageControl.UseVTableBits = true;
|
|
}
|
|
} else if (IsOption
|
|
(args, option, loweredOption, "deferredreferencecountinggc",
|
|
ref index, out optionValue)) {
|
|
|
|
StageControl.GCType = StageControl.DeferredReferenceCountingCollector;
|
|
StageControl.InsertWriteBarrier = false;
|
|
StageControl.Allocator = StageControl.SegregatedFreeList;
|
|
StageControl.GCInlineAllocations = false;
|
|
if (StageControl.ObjectHeaderKind == StageControl.ObjectHeaderDefault) {
|
|
StageControl.ObjectHeaderKind =
|
|
StageControl.ObjectHeaderPostRC;
|
|
}
|
|
if (StageControl.RCCollectorVerifyRefCounts) {
|
|
StageControl.UseVTableBits = true;
|
|
}
|
|
} else if (IsOption(args, option, loweredOption, "concurrentmsgc",
|
|
ref index, out optionValue)) {
|
|
StageControl.GCType = StageControl.ConcurrentMSCollector;
|
|
StageControl.GCLargeObjectSize = 2040;
|
|
StageControl.Wb = StageControl.WbCMS;
|
|
StageControl.GCInlineAllocations = false;
|
|
StageControl.Allocator = StageControl.SegregatedFreeList;
|
|
StageControl.PreWriteBarrier = true;
|
|
StageControl.InsertWriteBarrier = true;
|
|
StageControl.GCInlineWriteBarrier = false;
|
|
StageControl.GCWriteBarrierTracksStaticFields = true;
|
|
} else if (IsOption(args, option, loweredOption, "cocomsgc",
|
|
ref index, out optionValue)) {
|
|
StageControl.GCType = StageControl.CoCoMSCollector;
|
|
StageControl.GCLargeObjectSize = 2040;
|
|
StageControl.Wb = StageControl.WbCoCoMS;
|
|
StageControl.GCInlineAllocations = false;
|
|
StageControl.Allocator = StageControl.SegregatedFreeList;
|
|
StageControl.PreWriteBarrier = true;
|
|
StageControl.InsertWriteBarrier = true;
|
|
StageControl.InsertCoCoBarrier = true;
|
|
StageControl.GCInlineWriteBarrier = true;
|
|
StageControl.GCWriteBarrierTracksStaticFields = true;
|
|
StageControl.IgnorePreInitRefCounts = true;
|
|
// HACKHACK: allowing Bartok+CoCo to build on my computer!
|
|
// without running out of physical memory!
|
|
//StageControl.IrSimpleInliner = false;
|
|
} else if (IsOption(args, option, loweredOption, "nullgc",
|
|
ref index, out optionValue)) {
|
|
StageControl.GCType = StageControl.NullCollector;
|
|
StageControl.InsertWriteBarrier = false;
|
|
StageControl.Allocator = StageControl.BumpAllocator;
|
|
} else if (IsOption(args, option, loweredOption, "atomicrcgc",
|
|
ref index, out optionValue)) {
|
|
StageControl.GCType = StageControl.AtomicRCCollector;
|
|
StageControl.GCLargeObjectSize = 2040;
|
|
StageControl.Wb = StageControl.WbARC;
|
|
StageControl.GCInlineAllocations = false;
|
|
StageControl.Allocator = StageControl.SegregatedFreeList;
|
|
StageControl.InsertWriteBarrier = true;
|
|
StageControl.GCInlineWriteBarrier = false;
|
|
StageControl.GCWriteBarrierTracksStaticFields = true;
|
|
} else if (IsOption(args, option, loweredOption, "minopt",
|
|
ref index, out optionValue)) {
|
|
StageControl.SsaOpts = false;
|
|
StageControl.DevirtualizeCall = false;
|
|
StageControl.IrFindConcrete = false;
|
|
StageControl.IrSimpleInliner = false;
|
|
StageControl.IrTypeTestElim = false;
|
|
StageControl.IrTypeTestElimPunt = false;
|
|
|
|
// IR clean up optimizations
|
|
StageControl.IrDeadAssignmentSimple2 = false;
|
|
StageControl.IrCleanupStructOperations = false;
|
|
StageControl.IrShortCircuitBBlocks = false;
|
|
StageControl.IrTreeShakeLate = false;
|
|
StageControl.IrArrayLoadStoreOpt = false;
|
|
StageControl.IrConvertSimpleArrayAccess = false;
|
|
|
|
// from the backend
|
|
StageControl.RegAllocCoalesce = false;
|
|
StageControl.RegAllocSpill = StageControl.SpillOptimizeSinglePass;
|
|
StageControl.OptLirCompactify = false;
|
|
StageControl.OptLirGlobalConstantProp = false;
|
|
StageControl.OptLirLocalConstantProp = true;
|
|
StageControl.OptLirImproveCC = false;
|
|
StageControl.OptLirPeephole = false;
|
|
StageControl.OptLirReverseCSE = false;
|
|
StageControl.OptLirGlobalCopyProp = false;
|
|
StageControl.OptLirLocalCopyProp = true;
|
|
StageControl.LayoutLoopHeaderLast = false;
|
|
} else if (IsOption(args, option, loweredOption, "nohiropt",
|
|
ref index, out optionValue)) {
|
|
StageControl.ABCD = false;
|
|
StageControl.DevirtualizeCall = false;
|
|
StageControl.IdentifyAsMethods = false;
|
|
StageControl.IrAttributeInliner = false;
|
|
StageControl.IrBBLocalCopyProp = false;
|
|
StageControl.IrCleanup = false;
|
|
StageControl.IrCleanupStructOperations = false;
|
|
StageControl.IrCloneLoopHeader = false;
|
|
StageControl.IrConvertOpt = false;
|
|
StageControl.IrDeadAssignmentSimple1 = false;
|
|
StageControl.IrDeadAssignmentSimple2 = false;
|
|
StageControl.IrFindConcrete = false;
|
|
StageControl.IrInitStaticField = false;
|
|
StageControl.IrJumpElim = false;
|
|
StageControl.IrLoadStoreOpt = false;
|
|
StageControl.IrMultiPropSimple = false;
|
|
StageControl.IrPeepholeNull = false;
|
|
StageControl.IrRemoveDoubleCmp = false;
|
|
StageControl.IrReverseCopyProp = false;
|
|
StageControl.IrShortCircuitBBlocks = false;
|
|
StageControl.IrSimpleInliner = false;
|
|
StageControl.IrStoreChecks = false;
|
|
StageControl.IrTreeShakeLate = false;
|
|
StageControl.IrTypeTestElimPunt = false;
|
|
StageControl.SsaArraySimple = false;
|
|
StageControl.SsaDeadCode = false;
|
|
StageControl.SsaLoopInv = false;
|
|
StageControl.SsaNullCheck = false;
|
|
StageControl.SsaOpts = false;
|
|
StageControl.TypeInitRemoveEmptyCctors = false;
|
|
StageControl.UnmanagedStrings = false;
|
|
} else if (IsOption(args, option, loweredOption, "singularity",
|
|
ref index, out optionValue)) {
|
|
StageControl.SingSharpTemplateRemover = true;
|
|
StageControl.DisablePInvoke = true;
|
|
StageControl.MasmCompatibleSymbols = false;
|
|
StageControl.StrictEcma = true;
|
|
StageControl.CustomAllocatorTypes = true;
|
|
StageControl.SurrogateBoxing = true;
|
|
StageControl.StructInheritance = true;
|
|
StageControl.IrTreeShakeCreatePointedToStructs = true;
|
|
StageControl.IrTreeShakeLate = false; // not tested
|
|
StageControl.TypeInitRemoveEmptyCctors = false; // not tested
|
|
StageControl.CheckNoHeapAllocation = true;
|
|
StageControl.MakeNativeHeadersUsableForSingularityLoader = true;
|
|
StageControl.IncludeBartokFilterInXData = false;
|
|
} else if (IsOption(args, option, loweredOption, "verbosehelp",
|
|
ref index, out optionValue)) {
|
|
PrintUsage();
|
|
StageControl.PrintUsage();
|
|
} else if (IsOption(args, option, loweredOption, "verbosehelpalpha",
|
|
ref index, out optionValue)) {
|
|
PrintUsage();
|
|
StageControl.PrintUsageAlpha();
|
|
} else if (IsOption(args, option, loweredOption, "x86",
|
|
ref index, out optionValue)) {
|
|
StageControl.TargetArch = StageControl.X86;
|
|
StageControl.Target64Bit = false;
|
|
Bartok.MSIL.MetaDataUtil.Target64Bit = false;
|
|
} else if (IsOption(args, option, loweredOption, "x64",
|
|
ref index, out optionValue)) {
|
|
StageControl.TargetArch = StageControl.X64;
|
|
StageControl.Target64Bit = true;
|
|
Bartok.MSIL.MetaDataUtil.Target64Bit = true;
|
|
} else if (IsOption(args, option, loweredOption, "help",
|
|
ref index, out optionValue)
|
|
|| IsOption(args, option, loweredOption, "?",
|
|
ref index, out optionValue)) {
|
|
PrintUsage();
|
|
} else if (IsOption
|
|
(args, option, loweredOption, "centralpt",
|
|
ref index, out optionValue)) {
|
|
StageControl.PTType = StageControl.CentralPT;
|
|
} else if (IsOption
|
|
(args, option, loweredOption, "centralpthimem",
|
|
ref index, out optionValue)) {
|
|
StageControl.PTType = StageControl.CentralPTHimem;
|
|
} else if (IsOption
|
|
(args, option, loweredOption, "flatdistributedpt",
|
|
ref index, out optionValue)) {
|
|
StageControl.PTType = StageControl.FlatDistributedPT;
|
|
} else if (IsOption
|
|
(args, option, loweredOption, "flatdistributedtestpt",
|
|
ref index, out optionValue)) {
|
|
StageControl.PTType = StageControl.FlatDistributedPTTest;
|
|
} else if (isCmdLine
|
|
&& StageControl.SetOptionFromCommandLine(args, option,
|
|
loweredOption,
|
|
ref index)) {
|
|
// continue
|
|
} else if (!isCmdLine
|
|
&& StageControl.SetOptionFromEnvVar(args, option,
|
|
loweredOption,
|
|
ref index)) {
|
|
// continue
|
|
} else if (loweredOption.StartsWith("stagecontrol")) {
|
|
Util.UserError("/stagecontrol no longer supported; "
|
|
+ "use the option directly");
|
|
} else {
|
|
Util.UserError("Unknown option: " + option);
|
|
}
|
|
}
|
|
|
|
private static bool IsOption(String[] args,
|
|
String option, String loweredOption,
|
|
String possibleOptionName,
|
|
ref int index, out String optionValue) {
|
|
return StageControl.IsOption(args, option, loweredOption,
|
|
possibleOptionName,
|
|
ref index, out optionValue);
|
|
}
|
|
|
|
private static void AddSemicolonDelimitedNames(ArrayList names,
|
|
String argument) {
|
|
int index = 0;
|
|
StringBuilder buf = new StringBuilder();
|
|
while (index < argument.Length) {
|
|
if (argument[index] != ';') {
|
|
buf.Append(argument[index]);
|
|
index++;
|
|
}
|
|
else {
|
|
if (buf.Length > 0) {
|
|
names.Add(buf.ToString());
|
|
buf = new StringBuilder();
|
|
}
|
|
index++;
|
|
}
|
|
}
|
|
names.Add(buf.ToString());
|
|
}
|
|
|
|
public static void PrintUsage() {
|
|
if (alreadyPrintedUsage) {
|
|
return;
|
|
}
|
|
alreadyPrintedUsage = true;
|
|
Util.Message(true,
|
|
@"Usage:
|
|
bartok [options] files
|
|
|
|
Bartok main options (case insensitive):
|
|
@<file> options response file
|
|
/entry: <method1>;<method2>;... specify entry points
|
|
/reference: <file1>;<file2>;... reference metadata from assembly files
|
|
/r: <file1>;<file2>;... short form of /reference:
|
|
/bartoklink: <file1>;<file2>;... reference precompiled object files
|
|
/override: <file1>;<file2>;... files overriding /r: metadata
|
|
/lib: <dir1>;<dir2>;... additional dirs to search for references
|
|
/out: <file> output file name
|
|
/outdir: <dir> dir for output .exe, asm, obj, etc.
|
|
(defaults to .\\debug)
|
|
/skip: <type1>;<type2>;... specify type initializers to disable
|
|
if building static ordering
|
|
/substitute:<oldname1>=<newname1>, rename TypeRefs before performing lookup
|
|
<oldname2>=<newname2>,...
|
|
/dynamicload:<typename> make type available for dynamic loading
|
|
/features:<???> << TODO >>
|
|
/verbosity:<noiselevel> set output level {Silence,PerPhase,
|
|
PerClass,PerMethod,PerBlock,
|
|
PerInstruction} (defaults to PerPhase)
|
|
/marksweepgc compile for mark-sweep collector
|
|
/semispacegc compile for semispace collector
|
|
/slidinggc compile for sliding collector
|
|
/adaptivecopyinggc compile for semispace-sliding hybrid
|
|
collector
|
|
/referencecountinggc compile for reference counting collector
|
|
/deferredreferencecountinggc compile for deferred reference counting
|
|
collector
|
|
/concurrentmsgc compile for concurrent mark-sweep
|
|
collector
|
|
/nullgc compile for no collector
|
|
/minopt disable most optimizations
|
|
/nohiropt disable all HIR optimizations
|
|
/singularity set default Singularity options
|
|
/verbosehelp help message including stage control
|
|
options by category
|
|
/verbosehelpalpha help message including stage control
|
|
options in alphabetical order
|
|
/help or /? help message");
|
|
}
|
|
}
|
|
|
|
internal class MetaDataOutput : Bartok.MSIL.IMetaDataOutput {
|
|
public TextWriter Log { get { return Util.Log; } }
|
|
public TextWriter ErrorOut { get { return Util.ErrorOut; } }
|
|
public TextWriter WarnOut { get { return Util.WarnOut; } }
|
|
|
|
public void Error(String msg)
|
|
{
|
|
Util.Error(msg);
|
|
}
|
|
|
|
public void Error(String format, params Object[] objs)
|
|
{
|
|
Util.Error(format, objs);
|
|
}
|
|
|
|
public void ErrorDetail(String msg)
|
|
{
|
|
Util.ErrorDetail(msg);
|
|
}
|
|
|
|
public void Warn(String msg)
|
|
{
|
|
Util.Warn(msg);
|
|
}
|
|
|
|
public void Warn(String format, params Object[] objs)
|
|
{
|
|
Util.Warn(format, objs);
|
|
}
|
|
|
|
public void WarnDetail(String msg)
|
|
{
|
|
Util.WarnDetail(msg);
|
|
}
|
|
|
|
public void Message(String msg)
|
|
{
|
|
Util.Message(msg);
|
|
}
|
|
}
|
|
}
|