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 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); } }