Пример #1
0
        private static void ReassociateReduction(NamedInstructionBuilder instruction)
        {
            var proto = instruction.Prototype as IntrinsicPrototype;

            if (proto == null)
            {
                return;
            }

            if (IsAssociative(proto))
            {
                var uses          = instruction.Graph.GetAnalysisResult <ValueUses>();
                var reductionArgs = new List <ValueTag>();
                var reductionOps  = new HashSet <ValueTag>();
                ToReductionList(
                    instruction.Instruction.Arguments,
                    proto,
                    reductionArgs,
                    reductionOps,
                    uses,
                    instruction.Graph.ToImmutable());

                if (TrySimplifyReduction(ref reductionArgs, proto, instruction))
                {
                    MaterializeReduction(reductionArgs, proto, instruction);
                    instruction.Graph.RemoveInstructionDefinitions(reductionOps);
                }
            }
        }
Пример #2
0
        private static bool TrySimplifyReduction(
            ref List <ValueTag> args,
            InstructionPrototype prototype,
            NamedInstructionBuilder insertionPoint)
        {
            bool changed = false;
            var  newArgs = new List <ValueTag>();

            foreach (var operand in args)
            {
                if (newArgs.Count > 0)
                {
                    var prevOperand = newArgs[newArgs.Count - 1];
                    var folded      = ConstantFold(prevOperand, operand, prototype, insertionPoint);
                    if (folded == null)
                    {
                        newArgs.Add(operand);
                    }
                    else
                    {
                        newArgs[newArgs.Count - 1] = folded;
                        changed = true;
                    }
                }
                else
                {
                    newArgs.Add(operand);
                }
            }
            args = newArgs;
            return(changed);
        }
Пример #3
0
        private static void CreateFieldwiseCopy(
            ValueTag destinationPointer,
            ValueTag sourcePointer,
            NamedInstructionBuilder loadInsertionPoint,
            NamedInstructionBuilder storeInsertionPoint,
            Dictionary <ValueTag, Dictionary <IField, ValueTag> > replacements)
        {
            foreach (var pair in replacements[destinationPointer].Reverse())
            {
                // Copy each field as follows:
                //
                //     field_ptr = get_field_pointer(field)(load_ptr);
                //     val = load(field_type)(field_ptr);
                //     _ = store(field_replacement, val);
                //
                var fieldPtr = loadInsertionPoint.InsertAfter(
                    Instruction.CreateGetFieldPointer(pair.Key, sourcePointer));

                var fieldValue = fieldPtr.InsertAfter(
                    Instruction.CreateLoad(pair.Key.FieldType, fieldPtr));

                var storeInsert = storeInsertionPoint.Tag == loadInsertionPoint.Tag
                    ? fieldValue
                    : storeInsertionPoint;

                storeInsert.InsertAfter(
                    Instruction.CreateStore(
                        pair.Key.FieldType,
                        pair.Value,
                        fieldValue));
            }
        }
Пример #4
0
        private void FillWith(
            ValueTag array,
            IReadOnlyList <Constant> data,
            IType elementType,
            NamedInstructionBuilder insertionPoint)
        {
            var arrayType = insertionPoint.Graph.GetValueType(array);
            var indexSpec = IndexType.GetIntegerSpecOrNull();

            for (int i = 0; i < data.Count; i++)
            {
                insertionPoint.InsertBefore(
                    Instruction.CreateStoreElementIntrinsic(
                        elementType,
                        arrayType,
                        new[] { IndexType },
                        insertionPoint.InsertBefore(Instruction.CreateConstant(data[i], elementType)),
                        array,
                        new[]
                {
                    insertionPoint.InsertBefore(
                        Instruction.CreateConstant(
                            new IntegerConstant(i, indexSpec),
                            IndexType))
                    .Tag
                }));
            }
        }
Пример #5
0
 private static bool IsArrayInit(NamedInstructionBuilder instruction, out ValueTag array, out ClrFieldDefinition pseudoField)
 {
     if (instruction.Prototype is CallPrototype)
     {
         var call   = (CallPrototype)instruction.Prototype;
         var callee = call.Callee;
         if (callee.IsStatic && callee.Parameters.Count == 2 &&
             callee.FullName.ToString() == "System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray")
         {
             var pseudoFieldRef = instruction.Arguments[1];
             NamedInstructionBuilder pseudoFieldInsn;
             if (instruction.Graph.TryGetInstruction(pseudoFieldRef, out pseudoFieldInsn) &&
                 pseudoFieldInsn.Prototype is ConstantPrototype)
             {
                 var constVal = ((ConstantPrototype)pseudoFieldInsn.Prototype).Value;
                 if (constVal is FieldTokenConstant)
                 {
                     pseudoField = ((FieldTokenConstant)constVal).Field as ClrFieldDefinition;
                     array       = instruction.Arguments[0];
                     return(pseudoField != null);
                 }
             }
         }
     }
     array       = null;
     pseudoField = null;
     return(false);
 }
Пример #6
0
        private void EliminateStore(NamedInstructionBuilder instruction)
        {
            var storeProto = (StorePrototype)instruction.Prototype;

            instruction.Instruction = Instruction.CreateCopy(
                instruction.ResultType,
                storeProto.GetValue(instruction.Instruction));
        }
Пример #7
0
        /// <inheritdoc/>
        public override void Expand(NamedInstructionBuilder instance)
        {
            var insn = instance.Instruction;

            AssertIsPrototypeOf(insn);

            var gfp = instance.InsertBefore(
                Instruction.CreateGetFieldPointer(
                    Field, insn.Arguments[0]));

            instance.Instruction = Instruction.CreateLoad(Field.FieldType, gfp);
        }
        private static ValueTag ConvertThisArgument(
            ValueTag thisArgument,
            IType expectedThisType,
            NamedInstructionBuilder insertionPoint)
        {
            var thisType = insertionPoint.Graph.GetValueType(thisArgument);

            if (thisType != expectedThisType)
            {
                return(insertionPoint.InsertBefore(
                           Instruction.CreateReinterpretCast(
                               (PointerType)expectedThisType,
                               thisArgument)));
            }
            else
            {
                return(thisArgument);
            }
        }
Пример #9
0
        private static void ReassociateNonAssociative(NamedInstructionBuilder instruction)
        {
            // Look for instructions that compute an expression that looks
            // like so: `(a op1 b) op1 c` and replace it with `a op1 (b op2 c)`,
            // where `op2` is some (associative) operator such that the transformation
            // is semantics-preserving, e.g., op1 == (-) and op2 == (+) for integers.
            //
            // Here's why this transformation is useful: consider the following
            // expression: `(((x - 1) - 1) - 1) - 1`. It is clear that this can be
            // optimized to `x - 4`, but it's not super easy to see how: the reduction-
            // based reassociation doesn't apply to nonassociative operators. However,
            // by rewriting the expression as `x - (1 + 1 + 1 + 1)`, we can apply
            // reduction-based reassocation to the RHS.

            var proto = instruction.Prototype as IntrinsicPrototype;
            IntrinsicPrototype rightPrototype;

            if (proto == null || !IsLeftToRightReassociable(proto, out rightPrototype))
            {
                return;
            }

            NamedInstructionBuilder left;

            if (instruction.Graph.TryGetInstruction(instruction.Instruction.Arguments[0], out left) &&
                left.Prototype == proto)
            {
                var uses = instruction.Graph.GetAnalysisResult <ValueUses>();
                if (uses.GetUseCount(left) == 1)
                {
                    var right = instruction.InsertBefore(
                        rightPrototype.Instantiate(
                            new[]
                    {
                        left.Instruction.Arguments[1],
                        instruction.Instruction.Arguments[1]
                    }));
                    instruction.Instruction = proto.Instantiate(new[] { left.Instruction.Arguments[0], right });
                    instruction.Graph.RemoveInstruction(left);
                }
            }
        }
Пример #10
0
        private static void MaterializeReduction(
            IReadOnlyList <ValueTag> args,
            InstructionPrototype prototype,
            NamedInstructionBuilder result)
        {
            if (args.Count == 1)
            {
                result.Instruction = Instruction.CreateCopy(result.ResultType, args[0]);
                return;
            }

            var accumulator = args[0];

            for (int i = 1; i < args.Count - 1; i++)
            {
                accumulator = result.InsertBefore(
                    prototype.Instantiate(new[] { accumulator, args[i] }));
            }
            result.Instruction = prototype.Instantiate(new[] { accumulator, args[args.Count - 1] });
        }
Пример #11
0
        private static NamedInstructionBuilder ConstantFold(
            ValueTag first,
            ValueTag second,
            InstructionPrototype prototype,
            NamedInstructionBuilder insertionPoint)
        {
            var      graph = insertionPoint.Graph;
            Constant firstConstant;
            Constant secondConstant;

            if (IsConstant(first, insertionPoint.Graph.ToImmutable(), out firstConstant) &&
                IsConstant(second, insertionPoint.Graph.ToImmutable(), out secondConstant))
            {
                var newConstant = ConstantPropagation.EvaluateDefault(
                    prototype,
                    new[] { firstConstant, secondConstant });
                if (newConstant != null)
                {
                    return(insertionPoint.InsertBefore(
                               Instruction.CreateConstant(newConstant, prototype.ResultType)));
                }
            }
            return(null);
        }
Пример #12
0
 /// <summary>
 /// Gets the memory state before a particular instruction has executed.
 /// </summary>
 /// <param name="instruction">An instruction.</param>
 /// <returns>A memory state.</returns>
 public Value GetMemoryBefore(NamedInstructionBuilder instruction)
 {
     return(GetMemoryBefore(instruction.ToImmutable()));
 }
Пример #13
0
        private bool TryRewriteStore(
            NamedInstructionBuilder instruction,
            Dictionary <ValueTag, Dictionary <IField, ValueTag> > replacements)
        {
            var storeProto = (StorePrototype)instruction.Prototype;
            var pointer    = storeProto.GetPointer(instruction.Instruction);
            var value      = storeProto.GetValue(instruction.Instruction);

            NamedInstructionBuilder valueInstruction;

            if (instruction.Graph.TryGetInstruction(value, out valueInstruction) &&
                valueInstruction.Prototype is LoadPrototype)
            {
                var loadPointer = valueInstruction.Arguments[0];
                if (replacements.ContainsKey(pointer))
                {
                    if (replacements.ContainsKey(loadPointer))
                    {
                        foreach (var pair in replacements[pointer].Reverse())
                        {
                            // Copy each field as follows:
                            //
                            //     val = load(field_type)(field_replacement_1);
                            //     _ = store(field_replacement_2, val);
                            //
                            var fieldValue = valueInstruction.InsertAfter(
                                Instruction.CreateLoad(pair.Key.FieldType, replacements[loadPointer][pair.Key]));

                            instruction.InsertAfter(
                                Instruction.CreateStore(
                                    pair.Key.FieldType,
                                    pair.Value,
                                    fieldValue));
                        }
                    }
                    else
                    {
                        CreateFieldwiseCopy(pointer, loadPointer, valueInstruction, instruction, replacements);
                    }

                    // Replace the store with a load, in case someone is
                    // using the value it returns.
                    instruction.Instruction = Instruction.CreateLoad(
                        instruction.Instruction.ResultType,
                        pointer);
                    return(true);
                }
                else if (replacements.ContainsKey(loadPointer) && CanAccessFields(storeProto.ResultType))
                {
                    // We're not scalarrepl'ing the store's address, but we are scalarrepl'ing the store's
                    // value. We could just leave this as-is and have the load lowering hash it out,
                    // but we can generate better code by storing values directly into the destination.
                    foreach (var pair in replacements[loadPointer])
                    {
                        var fieldValue = valueInstruction.InsertBefore(
                            Instruction.CreateLoad(pair.Key.FieldType, pair.Value));

                        var fieldPointer = instruction.InsertBefore(
                            Instruction.CreateGetFieldPointer(pair.Key, pointer));

                        instruction.InsertBefore(
                            Instruction.CreateStore(pair.Key.FieldType, fieldPointer, fieldValue));
                    }
                    instruction.Instruction = Instruction.CreateLoad(
                        instruction.Instruction.ResultType,
                        pointer);
                    return(true);
                }
                else
                {
                    return(false);
                }
            }
            else if (replacements.ContainsKey(pointer))
            {
                // If we're *not* dealing with a pointer-to-pointer copy, then things
                // are going to get ugly: we'll need to store the value in a temporary
                // and then perform a fieldwise copy from that temporary.
                var temporary = instruction.Graph.EntryPoint.InsertInstruction(
                    0,
                    Instruction.CreateAlloca(storeProto.ResultType),
                    pointer.Name + ".scalarrepl.temp");

                var tempStore = instruction.InsertAfter(
                    storeProto.Instantiate(temporary, value));

                CreateFieldwiseCopy(pointer, temporary, tempStore, tempStore, replacements);

                // Replace the store with a load, in case someone is
                // using the value it returns.
                instruction.Instruction = Instruction.CreateLoad(
                    instruction.Instruction.ResultType,
                    pointer);
                return(true);
            }
            else
            {
                return(false);
            }
        }
Пример #14
0
 /// <summary>
 /// Expands this fused instruction to an equivalent nonempty sequence
 /// of core instructions. The instance itself must be replaced by
 /// another instruction. Instruction expansion must be formulaic:
 /// it cannot depend on the rest of the control-flow graph.
 /// </summary>
 /// <param name="instance">
 /// An instance of this prototype to expand.
 /// </param>
 public abstract void Expand(NamedInstructionBuilder instance);