/// <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));
        }
Example #2
0
        [NotNull] public static IEnumerable <VariableName> FindWrites([NotNull] this IBasicBlock block, ISingleStaticAssignmentTable ssa)
        {
            var r = new FindAssignedVariables();

            r.Visit(block);

            return(r.Names);
        }
        /// <summary>
        /// Replace reads from variables which are never assigned with a constant `0` (the default value for unassigned vars)
        /// </summary>
        /// <param name="cfg"></param>
        /// <returns></returns>
        public static IControlFlowGraph ReplaceUnassignedReads(this IControlFlowGraph cfg)
        {
            var v = new FindAssignedVariables();

            foreach (var vertex in cfg.Vertices)
            {
                v.Visit(vertex);
            }

            return(cfg.VisitBlocks(() => new ReplaceUnassignedReads(new HashSet <VariableName>(v.Names))));
        }
Example #4
0
        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);
            }
        }
Example #6
0
        [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);
        }