using System; using System.Collections.Generic; using System.Linq; using System.Text; using ILRuntime.Mono.Cecil; using ILRuntime.Mono.Cecil.Cil; using ILRuntime.CLR.TypeSystem; using ILRuntime.CLR.Method; using ILRuntime.Runtime.Intepreter.OpCodes; namespace ILRuntime.Runtime.Intepreter.RegisterVM { partial class Optimizer { public static void ForwardCopyPropagation(List blocks, bool hasReturn,short stackRegisterBegin) { foreach (var b in blocks) { var lst = b.FinalInstructions; HashSet canRemove = b.CanRemove; HashSet pendingFCP = b.PendingCP; bool isInline = false; for (int i = 0; i < lst.Count; i++) { if (canRemove.Contains(i)) continue; OpCodeR X = lst[i]; if(X.Code == OpCodeREnum.InlineStart) { isInline = true; continue; } if (X.Code == OpCodeREnum.InlineEnd) { isInline = false; continue; } //if (isInline) // continue; if (X.Code == OpCodeREnum.Nop || X.Code == OpCodeREnum.Castclass || X.Code == OpCodeREnum.Readonly || X.Code == OpCodeREnum.Volatile) { canRemove.Add(i); continue; } if (X.Code == OpCodeREnum.Move) { short xSrc, xSrc2, xSrc3, xDst; GetOpcodeSourceRegister(ref X, hasReturn, out xSrc, out xSrc2, out xSrc3); GetOpcodeDestRegister(ref X, out xDst); if (xDst == xSrc) { canRemove.Add(i); continue; } //Only deal with local->stack, local->local, stack->stack if (xSrc >= stackRegisterBegin && xDst < stackRegisterBegin || isInline) continue; bool postPropagation = false; bool ended = false; bool propagationInline = false; for (int j = i + 1; j < lst.Count; j++) { OpCodeR Y = lst[j]; if (Y.Code == OpCodeREnum.InlineStart) propagationInline = true; else if (Y.Code == OpCodeREnum.InlineEnd) { propagationInline = false; } short ySrc, ySrc2, ySrc3; if (GetOpcodeSourceRegister(ref Y, hasReturn, out ySrc, out ySrc2, out ySrc3)) { bool replaced = false; if (ySrc >= 0 && ySrc == xDst) { if (postPropagation) { postPropagation = false; ended = true; break; } if(propagationInline) { ended = true; break; } ReplaceOpcodeSource(ref Y, 0, xSrc); replaced = true; } if (ySrc2 >= 0 && ySrc2 == xDst) { if (postPropagation) { postPropagation = false; ended = true; break; } if (propagationInline) { ended = true; break; } ReplaceOpcodeSource(ref Y, 1, xSrc); replaced = true; } if (ySrc3 >= 0 && ySrc3 == xDst) { if (postPropagation) { postPropagation = false; ended = true; break; } if (propagationInline) { ended = true; break; } ReplaceOpcodeSource(ref Y, 2, xSrc); replaced = true; } if (replaced) lst[j] = Y; } short yDst; if (GetOpcodeDestRegister(ref Y, out yDst)) { if (xSrc == yDst) { postPropagation = true; } if (xDst == yDst) { postPropagation = false; ended = true; if (!propagationInline) canRemove.Add(i); break; } } if(Y.Code == OpCodeREnum.Ret && !propagationInline) { postPropagation = false; canRemove.Add(i); ended = true; break; } } if (postPropagation || !ended) { if (xDst >= stackRegisterBegin) pendingFCP.Add(i); } } } } foreach(var b in blocks) { var pendingFCP = b.PendingCP; if (pendingFCP.Count > 0) { var originBlock = b; HashSet processedBlocks = new HashSet(); Queue pendingBlocks = new Queue(); foreach (var idx in pendingFCP) { var X = originBlock.FinalInstructions[idx]; short xDst, xSrc, xSrc2, xSrc3; GetOpcodeDestRegister(ref X, out xDst); GetOpcodeSourceRegister(ref X, hasReturn, out xSrc, out xSrc2, out xSrc3); pendingBlocks.Clear(); bool cannotRemove = false; bool isAbort = false; processedBlocks.Clear(); foreach (var nb in originBlock.NextBlocks) pendingBlocks.Enqueue(nb); processedBlocks.Add(originBlock); while (pendingBlocks.Count > 0) { var cur = pendingBlocks.Dequeue(); var ins = cur.FinalInstructions; bool propagationInline = false; for (int j = 0; j < ins.Count; j++) { if(cur == originBlock && j == idx) { isAbort = true; break; } var Y = ins[j]; if (Y.Code == OpCodeREnum.InlineStart) propagationInline = true; else if (Y.Code == OpCodeREnum.InlineEnd) { propagationInline = false; } short ySrc, ySrc2, ySrc3, yDst; if (GetOpcodeSourceRegister(ref Y, hasReturn, out ySrc, out ySrc2, out ySrc3)) { bool replaced = false; if (ySrc == xDst) { if (propagationInline || cur.PreviousBlocks.Count > 1) { cannotRemove = true; break; } replaced = true; ReplaceOpcodeSource(ref Y, 0, xSrc); } if (ySrc2 == xDst) { if (propagationInline || cur.PreviousBlocks.Count > 1) { cannotRemove = true; break; } replaced = true; ReplaceOpcodeSource(ref Y, 1, xSrc); } if (ySrc3 == xDst) { if (propagationInline || cur.PreviousBlocks.Count > 1) { cannotRemove = true; break; } replaced = true; ReplaceOpcodeSource(ref Y, 2, xSrc); } if (replaced) ins[j] = Y; } if(GetOpcodeDestRegister(ref Y, out yDst)) { if(yDst == xDst) { isAbort = true; break; } } if(Y.Code == OpCodeREnum.Ret && !propagationInline) { isAbort = true; break; } } if (cannotRemove) break; processedBlocks.Add(cur); if (!isAbort) { foreach (var nb in cur.NextBlocks) { if (!processedBlocks.Contains(nb)) pendingBlocks.Enqueue(nb); } } } if(!cannotRemove) { originBlock.CanRemove.Add(idx); } } pendingFCP.Clear(); } } } } }