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); } } }
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); }
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)); } }
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 })); } }
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); }
private void EliminateStore(NamedInstructionBuilder instruction) { var storeProto = (StorePrototype)instruction.Prototype; instruction.Instruction = Instruction.CreateCopy( instruction.ResultType, storeProto.GetValue(instruction.Instruction)); }
/// <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); } }
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); } } }
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] }); }
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); }
/// <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())); }
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); } }
/// <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);