Esempio n. 1
0
        /// <summary>
        /// The last Rule is often a 'fallback' rule with an empty condition. If this is the case,
        /// we can sometimes perform an optimisation that reduces the overall code size.
        /// </summary>
        /// <returns>Root of the generated tree.</returns>
        private Node?BuildFallbackSequence()
        {
            // sanity check
            if (ruleSet.NumRules <= 1)
            {
                return(null);
            }

            // check that there is a fallback rule
            RuleSetEntry lastRule = ruleSet[ruleSet.NumRules - 1];

            if (!lastRule.EffectiveCondition.IsEmpty)
            {
                return(null);
            }

            // check that sequence nodes are permitted
            if (!spec.Config.AllowSequence)
            {
                return(null);
            }

            if (spec.Config.Verbose)
            {
                Console.WriteLine("Performing fallback sequence optimisation.");
            }

            // remove the fallback rule and build the tree
            RuleSet rSet    = ruleSet.DeriveExcludingLast();
            var     builder = new TreeBuilder(spec, rSet, this);
            Node    node    = builder.Build();

            // ensure that there is a sequence node including the root
            // of the tree
            SequenceNode seq;

            if (node is SequenceNode)
            {
                seq = (SequenceNode)node;
            }
            else
            {
                seq = new SequenceNode(spec);
                seq.Append(node);
            }

            // now paste the fallback rule onto the end of the sequence
            seq.Append(lastRule.Rule);
            return(seq);
        }
Esempio n. 2
0
        /// <summary>
        /// The sole publicly-visible entry point.  Generates a tree, given a Specification.
        /// </summary>
        /// <param name="spec">The decoder specification.</param>
        /// <returns>The root of the decoder tree.</returns>
        public static Node BuildTree(Specification spec, TristateBitArray?flags)
        {
            if (flags == null)
            {
                flags = new TristateBitArray(spec.NumFlags);
            }

            // initialise a TreeBuilder with an empty condition and a RuleSet
            // including all rules.
            var     initialCondition = new Condition(spec, new TristateBitArray(spec.NumBits), flags);
            RuleSet ruleSet          = new RuleSet(spec).Derive(initialCondition);
            var     builder          = new TreeBuilder(spec, ruleSet);

            return(builder.Build());
        }
Esempio n. 3
0
        /// <summary>
        /// Build a decoder subtree for the given switch case.
        /// </summary>
        /// <param name="node">The enclosing switch node.</param>
        /// <param name="value">Value of case (eg., case 0x0 has value 0).</param>
        /// <returns>Decoder subtree.</returns>
        private Node BuildSwitchCase(SwitchNode node, int value)
        {
            Debug.Assert(value >= 0 && value < node.Expression.NumValues);

            if (spec.Config.Verbose)
            {
                Console.WriteLine("Switch case {0}", value);
            }

            // generate a derived RuleSet for this switch case
            var cond = new Condition(spec,
                                     node.Expression.GetBitsForValue(value),
                                     new TristateBitArray(spec.NumFlags));

            RuleSet derivedSet = ruleSet.Derive(cond);

            // generate a corresponding TreeBuilder and update its totals for
            // switch bits & nesting depth
            var builder = new TreeBuilder(spec, derivedSet, this);

            builder.totalSwitchBits += node.Expression.NumBits;
            builder.switchNestingDepth++;

            // use it to build tree for case label
            Node child = builder.Build();

            // search previously-generated switch cases for functionally identical subtrees
            for (int previousValue = 0; previousValue < value; previousValue++)
            {
                if (node[previousValue].Equals(child))
                {
                    if (spec.Config.Verbose)
                    {
                        Console.WriteLine("Pruning child {0} => {1}", value, previousValue);
                    }

                    // replace generated subtree with a reference to the (identical) subtree
                    child = new ChildReferenceNode(spec, previousValue);
                    break;
                }
            }

            return(child);
        }
Esempio n. 4
0
        /// <summary>
        /// Try to improve efficiency by 'lifting' a test higher up the decoder tree. This is
        /// only done if the test is identical for every member of a rule set.
        /// </summary>
        private Node?BuildLift(string name, Func <Condition, TristateBitArray> extract, Func <TristateBitArray, Condition> init)
        {
            if (ruleSet.NumRules < 2)
            {
                return(null);
            }

            // extract component from 1st rule & verify that flags are specified
            TristateBitArray component = extract(ruleSet[0].EffectiveCondition);

            if (component.IsEmpty)
            {
                return(null);
            }

            // check that all other rules have the same component spec
            for (int i = 1; i < ruleSet.NumRules; i++)
            {
                if (!extract(ruleSet[i].EffectiveCondition).IsEqual(component))
                {
                    return(null);
                }
            }

            if (spec.Config.Verbose)
            {
                Console.WriteLine($"Performing {name} lifting optimisation.");
            }

            // build subtree without flags
            Condition cond    = init(component);
            RuleSet   rSet    = ruleSet.Derive(cond);
            var       builder = new TreeBuilder(spec, rSet, this);
            Node      node    = builder.Build();

            // and attach it to an if-node
            return(new IfElseNode(spec, cond, node, new EmptyNode(spec)));
        }