Example #1
0
        public static Expression OptimizeSingle(Dictionary <Expression, CachedExpression> cache, Expression value)
        {
            if (value is Constant || value is CachedExpression || value is State)
            {
                return(value);
            }
            if (!cache.TryGetValue(value, out var found))
            {
                Expression newValue;
                switch (value)
                {
                case Unary u:
                    newValue = new Unary(u.Operation, OptimizeSingle(cache, u.Operand));
                    break;

                case Binary b:
                    newValue = new Binary(b.Operation, OptimizeSingle(cache, b.OpA), OptimizeSingle(cache, b.OpB));
                    break;

                case Mux m:
                    newValue = new Mux(OptimizeSingle(cache, m.Selector), m.Operands.Select(o => OptimizeSingle(cache, o)));
                    break;

                case ExpressionGroupElement ge:
                    return(new ExpressionGroupElement(OptimizeGroup(cache, ge.Group), ge.Index));

                default:
                    return(value);
                }
                cache.Add(value, found = new CachedExpression(cache.Count, newValue));
            }
            return(found);
        }
Example #2
0
        private static Expression OptimizeInternal(Expression input,
                                                   Dictionary <Expression, Expression> cache)
        {
            switch (input)
            {
            case Constant c: break;

            case Unary u1:
                var u1a = Optimize(u1.Operand, cache);
                var u   = u1a.Equals(u1.Operand) ? u1 : new Unary(u1.Operation, u1a);
                if (u.Operand is Constant c1)
                {
                    return(new Constant(Unary.Evaluate(u.Operation, c1.Value)));
                }
                return(u);

            case Binary b1:
                var b1a = Optimize(b1.OpA, cache);
                var b1b = Optimize(b1.OpB, cache);
                var b   = (b1a.Equals(b1.OpA) && b1b.Equals(b1.OpB)) ? b1 : new Binary(b1.Operation, b1a, b1b);
                var cA  = (b.OpA as Constant)?.Value;
                var cB  = (b.OpB as Constant)?.Value;
                if (cA.HasValue && cB.HasValue)
                {
                    return(new Constant(Binary.Evaluate(b.Operation, cA.Value, cB.Value)));
                }
                switch (b.Operation)
                {
                case Binary.Op.Pow:
                    if (cB == 0 || cA == 1)
                    {
                        return(Constant.One);
                    }
                    if (cA == 0)
                    {
                        return(Constant.Zero);
                    }
                    if (cB == 1)
                    {
                        return(b.OpA);
                    }
                    if (cB == 2)
                    {
                        return(new Binary(Binary.Op.Mul, b.OpA, b.OpA));
                    }
                    break;

                case Binary.Op.Add:
                    if (cA == 0)
                    {
                        return(b.OpB);
                    }
                    if (cB == 0)
                    {
                        return(b.OpA);
                    }
                    break;

                case Binary.Op.Sub:
                    if (cB == 0)
                    {
                        return(b.OpA);
                    }
                    if (b.OpA.Equals(b.OpB))
                    {
                        return(Constant.Zero);
                    }
                    break;

                case Binary.Op.Mul:
                    if (cA == 0 || cB == 0)
                    {
                        return(Constant.Zero);
                    }
                    if (cA == 1)
                    {
                        return(b.OpB);
                    }
                    if (cB == 1)
                    {
                        return(b.OpA);
                    }
                    break;

                case Binary.Op.Div:
                    // TODO: Divide by zero warning?
                    if (cB == 1)
                    {
                        return(b.OpA);
                    }
                    if (b.OpA.Equals(b.OpB))
                    {
                        return(Constant.One);
                    }
                    if (cB.HasValue)
                    {
                        return(new Binary(Binary.Op.Mul, b.OpA, new Constant(1 / cB.Value)));
                    }
                    break;

                case Binary.Op.Rem:
                    // TODO: Divide by zero warning?
                    if (cA == 0 || b.OpA.Equals(b.OpB))
                    {
                        return(Constant.Zero);
                    }
                    break;
                }
                return(b);

            case Mux m1:
                var m = new Mux(Optimize(m1.Selector, cache), m1.Operands.Select(e => Optimize(e, cache)));
                if (m.Operands.Count == 1 || m.Operands.All(o => o.Equals(m.Operands[0])))
                {
                    return(m.Operands[0]);
                }
                if (m.Selector is Constant c2)
                {
                    var idx = c2.Value >= m.Operands.Count ? m.Operands.Count - 1 : (c2.Value < 0 ? 0 : c2.Value);
                    return(m.Operands[(int)idx]);
                }
                return(m);

            case ExpressionGroupElement e1:
                switch (e1.Group)
                {
                // TODO: Merge these
                case Persist p:
                    if (p.NewValue[e1.Index].AllDependent.All(v => (v as State)?.Scope != p.State[0].Scope))
                    {
                        return(p.NewValue[e1.Index]);
                    }
                    break;

                case Loop l:
                    if (l.Body[e1.Index].AllDependent.All(v => (v as State)?.Scope != l.State[0].Scope))
                    {
                        return(l.Body[e1.Index]);
                    }
                    break;
                }
                return(new ExpressionGroupElement(OptimizeGroup(e1.Group, cache), e1.Index));
            }
            return(input);
        }