/// <summary> /// Compile a line of Yolol into a runnable C# function /// </summary> /// <param name="line">The line of code to convert</param> /// <param name="lineNumber">The number of this line</param> /// <param name="maxLines">The max number of lines in a valid program (20, in standard Yolol)</param> /// <param name="maxStringLength"></param> /// <param name="internalVariableMap">A dictionary used for mapping variables to integers in all lines in this script</param> /// <param name="externalVariableMap">A dictionary used for mapping externals to integers in all lines in this script</param> /// <param name="staticTypes">Statically known types for variables</param> /// <param name="changeDetection"></param> /// <returns>A function which runs this line of code. Accepts two sections of memory, internal variables and external variables. Returns the line number to go to next</returns> public static Func <ArraySegment <Value>, ArraySegment <Value>, LineResult> Compile( this Line line, int lineNumber, int maxLines, int maxStringLength, InternalsMap internalVariableMap, ExternalsMap externalVariableMap, IReadOnlyDictionary <VariableName, Type>?staticTypes = null, bool changeDetection = false ) { // Locate all accessed variables and load them into the maps var stored = new FindAssignedVariables(); stored.Visit(line); var loaded = new FindReadVariables(); loaded.Visit(line); foreach (var name in stored.Names.Concat(loaded.Names).Distinct()) { var dict = name.IsExternal ? (Dictionary <VariableName, int>)externalVariableMap : internalVariableMap; if (!dict.TryGetValue(name, out _)) { dict[name] = dict.Count; } } return(line.Compile(lineNumber, maxLines, maxStringLength, (IReadonlyInternalsMap)internalVariableMap, externalVariableMap, staticTypes, changeDetection)); }
[NotNull] public static IEnumerable <(VariableName, uint)> FindReadCounts([NotNull] this IBasicBlock block) { var r = new FindReadVariables(); r.Visit(block); return(r.Counts); }
public static IEnumerable <(VariableName, uint)> FindReadCounts(this IBasicBlock block) { var r = new FindReadVariables(); r.Visit(block); return(r.Counts.Select(a => (a.Key, a.Value))); }
public static Program FoldSingleUseVariables(this Program prog) { // Find all variables associated with a count of how many times they are read var readsInProgram = new FindReadVariables(); readsInProgram.Visit(prog); // Find all variables associated with a count of how many times they are assigned var writesInProgram = new FindAssignedVariables(); writesInProgram.Visit(prog); var lines = new List <Line>(); foreach (var item in prog.Lines) { lines.Add(item.Fixpoint(20, line => { // Find all reads in this line var readsInLine = new FindReadVariables(); readsInLine.Visit(line); // Find all writes in this line var writesInLine = new FindAssignedVariables(); writesInLine.Visit(line); // Find variables that can be folded away var toReplace = (from v in readsInLine.Counts where !v.Key.IsExternal where v.Value == 1 // Filter to things only read once in this line where readsInProgram.Counts[v.Key] == 1 // Filter to things only read once in the entire program where writesInProgram.Counts[v.Key] == 1 // Filter to things on written once in the entire program where writesInLine.Counts[v.Key] == 1 // Filter to things written once in this line select v.Key).FirstOrDefault(); // If nothing was found to fold we can break out of the loop if (toReplace == null) { return(line); } // Find the value that was assigned to this var expr = writesInLine.Expressions[toReplace].Single(); // Substitute it into the line var result = new SubstituteVariable(toReplace, expr).Visit(line); return(result); })); } return(new Program(lines)); }
public void EmitLoad(Line line) { // Find every variable that is loaded anywhere in the line var loadFinder = new FindReadVariables(); loadFinder.Visit(line); // Find every variable that is written to anywhere in the line var storeFinder = new FindAssignedVariables(); storeFinder.Visit(line); _mutated.UnionWith(storeFinder.Names); // Only cache things which read or written more than once in the line var toCache = new HashSet <VariableName>(); foreach (var(name, count) in loadFinder.Counts) { if (count > 1) { toCache.Add(name); } } foreach (var(name, count) in storeFinder.Counts) { if (count > 1) { toCache.Add(name); } } // Load up everything that will be read later in the line // The `IsDirty` flags protect against writing back uninitialised variables at the end foreach (var variable in toCache) { var type = _types.TypeOf(variable) ?? StackType.YololValue; var local = _emitter.DeclareLocal(type.ToType(), $"CacheFor_{variable.Name}", false); EmitLoadValue(variable); StaticUnbox(type); _emitter.StoreLocal(local); _cache.Add(variable, new TypedLocal(type, local)); var dirty = _emitter.DeclareLocal(typeof(bool), $"CacheFor_{variable.Name}_IsDirty"); _emitter.LoadConstant(false); _emitter.StoreLocal(dirty); _cacheDirty.Add(variable, dirty); } }
[NotNull] public static IReadOnlyCollection <VariableName> FindUnreadAssignments([NotNull] this IControlFlowGraph cfg) { var assigned = new FindAssignedVariables(); var read = new FindReadVariables(); foreach (var bb in cfg.Vertices) { assigned.Visit(bb); read.Visit(bb); } var result = new HashSet <VariableName>(assigned.Names.Where(n => !n.IsExternal)); result.ExceptWith(read.Names); return(result); }