public static void ForwardCopyPropagation(List <CodeBasicBlock> blocks, bool hasReturn, short stackRegisterBegin) { foreach (var b in blocks) { var lst = b.FinalInstructions; HashSet <int> canRemove = b.CanRemove; HashSet <int> 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 <CodeBasicBlock> processedBlocks = new HashSet <CodeBasicBlock>(); Queue <CodeBasicBlock> pendingBlocks = new Queue <CodeBasicBlock>(); 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(); } } }
public static bool GetOpcodeSourceRegister(ref OpCodeR op, bool hasReturn, out short r1, out short r2, out short r3) { r1 = -1; r2 = -1; r3 = -1; switch (op.Code) { case OpCodeREnum.Move: case OpCodeREnum.Conv_I: case OpCodeREnum.Conv_I1: case OpCodeREnum.Conv_I2: case OpCodeREnum.Conv_I4: case OpCodeREnum.Conv_I8: case OpCodeREnum.Conv_Ovf_I: case OpCodeREnum.Conv_Ovf_I1: case OpCodeREnum.Conv_Ovf_I1_Un: case OpCodeREnum.Conv_Ovf_I2: case OpCodeREnum.Conv_Ovf_I2_Un: case OpCodeREnum.Conv_Ovf_I4: case OpCodeREnum.Conv_Ovf_I4_Un: case OpCodeREnum.Conv_Ovf_I8: case OpCodeREnum.Conv_Ovf_I8_Un: case OpCodeREnum.Conv_Ovf_I_Un: case OpCodeREnum.Conv_Ovf_U: case OpCodeREnum.Conv_Ovf_U1: case OpCodeREnum.Conv_Ovf_U1_Un: case OpCodeREnum.Conv_Ovf_U2: case OpCodeREnum.Conv_Ovf_U2_Un: case OpCodeREnum.Conv_Ovf_U4: case OpCodeREnum.Conv_Ovf_U4_Un: case OpCodeREnum.Conv_Ovf_U8: case OpCodeREnum.Conv_Ovf_U8_Un: case OpCodeREnum.Conv_Ovf_U_Un: case OpCodeREnum.Conv_R4: case OpCodeREnum.Conv_R8: case OpCodeREnum.Conv_R_Un: case OpCodeREnum.Conv_U: case OpCodeREnum.Conv_U1: case OpCodeREnum.Conv_U2: case OpCodeREnum.Conv_U4: case OpCodeREnum.Conv_U8: case OpCodeREnum.Not: case OpCodeREnum.Neg: case OpCodeREnum.Box: case OpCodeREnum.Unbox: case OpCodeREnum.Unbox_Any: case OpCodeREnum.Ldind_I: case OpCodeREnum.Ldind_I1: case OpCodeREnum.Ldind_I2: case OpCodeREnum.Ldind_I4: case OpCodeREnum.Ldind_I8: case OpCodeREnum.Ldind_R4: case OpCodeREnum.Ldind_R8: case OpCodeREnum.Ldind_U1: case OpCodeREnum.Ldind_U2: case OpCodeREnum.Ldind_U4: case OpCodeREnum.Ldind_Ref: case OpCodeREnum.Ldobj: case OpCodeREnum.Ldloca: case OpCodeREnum.Ldloca_S: case OpCodeREnum.Ldarg_S: case OpCodeREnum.Ldarga: case OpCodeREnum.Ldarga_S: case OpCodeREnum.Ldlen: case OpCodeREnum.Newarr: case OpCodeREnum.Ldfld: case OpCodeREnum.Ldflda: case OpCodeREnum.Ldvirtftn: case OpCodeREnum.Isinst: r1 = op.Register2; return(true); case OpCodeREnum.Stind_I: case OpCodeREnum.Stind_I1: case OpCodeREnum.Stind_I2: case OpCodeREnum.Stind_I4: case OpCodeREnum.Stind_I8: case OpCodeREnum.Stind_R4: case OpCodeREnum.Stind_R8: case OpCodeREnum.Stind_Ref: case OpCodeREnum.Stobj: case OpCodeREnum.Stfld: r1 = op.Register1; r2 = op.Register2; return(true); case OpCodeREnum.Ldc_I4_0: case OpCodeREnum.Ldc_I4_1: case OpCodeREnum.Ldc_I4_2: case OpCodeREnum.Ldc_I4_3: case OpCodeREnum.Ldc_I4_4: case OpCodeREnum.Ldc_I4_5: case OpCodeREnum.Ldc_I4_6: case OpCodeREnum.Ldc_I4_7: case OpCodeREnum.Ldc_I4_8: case OpCodeREnum.Ldc_I4_M1: case OpCodeREnum.Ldnull: case OpCodeREnum.Ldc_I4: case OpCodeREnum.Ldc_I4_S: case OpCodeREnum.Ldc_I8: case OpCodeREnum.Ldc_R4: case OpCodeREnum.Ldc_R8: case OpCodeREnum.Ldstr: case OpCodeREnum.Ldtoken: case OpCodeREnum.Ldftn: case OpCodeREnum.Ldsfld: case OpCodeREnum.Ldsflda: case OpCodeREnum.Constrained: return(false); case OpCodeREnum.Callvirt: case OpCodeREnum.Call: case OpCodeREnum.Newobj: r1 = op.Register2; r2 = op.Register3; r3 = op.Register4; return(true); case OpCodeREnum.Br_S: case OpCodeREnum.Br: case OpCodeREnum.Nop: case OpCodeREnum.InlineStart: case OpCodeREnum.InlineEnd: case OpCodeREnum.Castclass: case OpCodeREnum.Readonly: case OpCodeREnum.Leave: case OpCodeREnum.Leave_S: case OpCodeREnum.Endfinally: case OpCodeREnum.Volatile: return(false); case OpCodeREnum.Brtrue: case OpCodeREnum.Brtrue_S: case OpCodeREnum.Brfalse: case OpCodeREnum.Brfalse_S: case OpCodeREnum.Push: case OpCodeREnum.Initobj: case OpCodeREnum.Throw: case OpCodeREnum.Stsfld: case OpCodeREnum.Switch: r1 = op.Register1; return(true); case OpCodeREnum.Blt: case OpCodeREnum.Blt_S: case OpCodeREnum.Blt_Un: case OpCodeREnum.Blt_Un_S: case OpCodeREnum.Ble: case OpCodeREnum.Ble_S: case OpCodeREnum.Ble_Un: case OpCodeREnum.Ble_Un_S: case OpCodeREnum.Bgt: case OpCodeREnum.Bgt_S: case OpCodeREnum.Bgt_Un: case OpCodeREnum.Bgt_Un_S: case OpCodeREnum.Bge: case OpCodeREnum.Bge_S: case OpCodeREnum.Bge_Un: case OpCodeREnum.Bge_Un_S: case OpCodeREnum.Beq: case OpCodeREnum.Beq_S: case OpCodeREnum.Bne_Un: case OpCodeREnum.Bne_Un_S: r1 = op.Register1; r2 = op.Register2; return(true); case OpCodeREnum.Add: case OpCodeREnum.Add_Ovf: case OpCodeREnum.Add_Ovf_Un: case OpCodeREnum.Sub: case OpCodeREnum.Sub_Ovf: case OpCodeREnum.Sub_Ovf_Un: case OpCodeREnum.Mul: case OpCodeREnum.Mul_Ovf: case OpCodeREnum.Mul_Ovf_Un: case OpCodeREnum.Div: case OpCodeREnum.Div_Un: case OpCodeREnum.Rem: case OpCodeREnum.Rem_Un: case OpCodeREnum.Xor: case OpCodeREnum.And: case OpCodeREnum.Or: case OpCodeREnum.Shl: case OpCodeREnum.Shr: case OpCodeREnum.Shr_Un: case OpCodeREnum.Clt: case OpCodeREnum.Clt_Un: case OpCodeREnum.Cgt: case OpCodeREnum.Cgt_Un: case OpCodeREnum.Ceq: case OpCodeREnum.Ldelem_I1: case OpCodeREnum.Ldelem_U1: case OpCodeREnum.Ldelem_I2: case OpCodeREnum.Ldelem_U2: case OpCodeREnum.Ldelem_I4: case OpCodeREnum.Ldelem_U4: case OpCodeREnum.Ldelem_I8: case OpCodeREnum.Ldelem_R4: case OpCodeREnum.Ldelem_R8: case OpCodeREnum.Ldelem_Any: case OpCodeREnum.Ldelem_Ref: case OpCodeREnum.Ldelema: r1 = op.Register2; r2 = op.Register3; return(true); case OpCodeREnum.Stelem_I: case OpCodeREnum.Stelem_I1: case OpCodeREnum.Stelem_I2: case OpCodeREnum.Stelem_I4: case OpCodeREnum.Stelem_I8: case OpCodeREnum.Stelem_R4: case OpCodeREnum.Stelem_R8: case OpCodeREnum.Stelem_Ref: case OpCodeREnum.Stelem_Any: r1 = op.Register1; r2 = op.Register2; r3 = op.Register3; return(true); case OpCodeREnum.Ret: if (hasReturn) { r1 = op.Register1; return(true); } else { return(false); } default: throw new NotImplementedException(); } }
public static void BackwardsCopyPropagation(List <CodeBasicBlock> blocks, bool hasReturn, short stackRegisterBegin) { foreach (var b in blocks) { var lst = b.FinalInstructions; HashSet <int> canRemove = b.CanRemove; //HashSet<int> pendingBCP = b.PendingCP; bool isInline = false; for (int i = lst.Count - 1; i >= 0; i--) { if (canRemove.Contains(i)) { continue; } OpCodeR X = lst[i]; if (X.Code == OpCodeREnum.InlineStart) { isInline = false; continue; } if (X.Code == OpCodeREnum.InlineEnd) { isInline = true; continue; } //if (isInline) // continue; if (X.Code == OpCodeREnum.Nop) { 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 stack->local if (xSrc < stackRegisterBegin || xDst >= stackRegisterBegin || isInline) { continue; } bool ended = false; bool propagationInline = false; for (int j = i - 1; j >= 0; j--) { OpCodeR Y = lst[j]; if (Y.Code == OpCodeREnum.InlineStart) { propagationInline = false; } else if (Y.Code == OpCodeREnum.InlineEnd) { propagationInline = true; } short ySrc, ySrc2, ySrc3; if (GetOpcodeSourceRegister(ref Y, hasReturn, out ySrc, out ySrc2, out ySrc3)) { if (ySrc >= 0 && ySrc == xDst) { break; } if (ySrc2 >= 0 && ySrc2 == xDst) { break; } if (ySrc3 >= 0 && ySrc3 == xDst) { break; } } short yDst; if (GetOpcodeDestRegister(ref Y, out yDst)) { if (xDst == yDst && !propagationInline) { ended = true; break; } if (xSrc == yDst) { if (propagationInline) { ended = true; break; } ReplaceOpcodeDest(ref Y, xDst); for (int k = j + 1; k < lst.Count; k++) { OpCodeR Z = lst[k]; bool replaced = false; short zSrc, zSrc2, zSrc3; short zDst; GetOpcodeDestRegister(ref Z, out zDst); if (GetOpcodeSourceRegister(ref Z, hasReturn, out zSrc, out zSrc2, out zSrc3)) { if (zSrc == yDst) { replaced = true; ReplaceOpcodeSource(ref Z, 0, xDst); } if (zSrc2 == yDst) { replaced = true; ReplaceOpcodeSource(ref Z, 1, xDst); } if (zSrc3 == yDst) { replaced = true; ReplaceOpcodeSource(ref Z, 2, xDst); } } if (replaced) { lst[k] = Z; } if (zDst >= 0) { if (zDst == yDst) { break; } } } canRemove.Add(i); ended = true; lst[j] = Y; break; } } } /*if (!ended) * { * if (xDst < stackRegisterBegin) * { * pendingBCP.Add(i); * throw new NotImplementedException(); * } * }*/ } } } }
public static void InlineMethod(CodeBasicBlock block, ILMethod method, RegisterVMSymbolLink symbolLink, ref Dictionary <int, int[]> jumpTables, short baseRegIdx, bool hasReturn) { var ins = block.FinalInstructions; var body = method.BodyRegister; OpCodeR start = new OpCodeR(); start.Code = OpCodeREnum.InlineStart; ins.Add(start); int branchStart = ins.Count; int branchOffset = 0; List <int> reloc = new List <int>(); if (body != null) { for (int i = 0; i < body.Length; i++) { var opcode = body[i]; short r1 = 0; short r2 = 0; short r3 = 0; if (GetOpcodeSourceRegister(ref opcode, hasReturn, out r1, out r2, out r3)) { if (r1 >= 0) { ReplaceOpcodeSource(ref opcode, 0, (short)(r1 + baseRegIdx)); } if (r2 >= 0) { ReplaceOpcodeSource(ref opcode, 1, (short)(r2 + baseRegIdx)); } if (r3 >= 0) { ReplaceOpcodeSource(ref opcode, 2, (short)(r3 + baseRegIdx)); } } if (GetOpcodeDestRegister(ref opcode, out r1)) { if (r1 >= 0) { ReplaceOpcodeDest(ref opcode, (short)(r1 + baseRegIdx)); } } if (opcode.Code == OpCodeREnum.Ret) { bool needMove = hasReturn && opcode.Register1 != baseRegIdx; if (needMove) { opcode.Code = OpCodeREnum.Move; opcode.Register2 = opcode.Register1; opcode.Register1 = baseRegIdx; ins.Add(opcode); branchOffset++; } if (i < body.Length - 1) { if (needMove) { for (int j = branchStart; j < ins.Count; j++) { var op2 = ins[j]; if (IsBranching(op2.Code)) { if (op2.Operand > i) { op2.Operand++; ins[j] = op2; } } else if (IsIntermediateBranching(op2.Code)) { if (op2.Operand4 > i) { op2.Operand4++; ins[j] = op2; } } else if (op2.Code == OpCodeREnum.Switch) { var targets = jumpTables[op2.Operand]; for (int k = 0; k < targets.Length; k++) { if (targets[k] > i) { targets[k]++; } } } } } reloc.Add(ins.Count); opcode.Code = OpCodeREnum.Br; ins.Add(opcode); } continue; } if (IsBranching(opcode.Code)) { opcode.Operand += branchOffset; } if (opcode.Code == OpCodeREnum.Switch) { int[] targets = method.JumpTablesRegister[opcode.Operand]; int[] newTargets = new int[targets.Length]; for (int j = 0; j < targets.Length; j++) { newTargets[j] = targets[j] + branchOffset; } if (jumpTables == null) { jumpTables = new Dictionary <int, int[]>(); } opcode.Operand = newTargets.GetHashCode(); jumpTables.Add(opcode.Operand, newTargets); } #if DEBUG && !DISABLE_ILRUNTIME_DEBUG RegisterVMSymbol oriIns; if (method.RegisterVMSymbols.TryGetValue(i, out oriIns)) { oriIns.ParentSymbol = symbolLink; block.InstructionMapping.Add(ins.Count, oriIns); } #endif ins.Add(opcode); } } foreach (var i in reloc) { var opcode = ins[i]; opcode.Operand = ins.Count - branchStart; ins[i] = opcode; } start.Code = OpCodeREnum.InlineEnd; ins.Add(start); }
void Translate(CodeBasicBlock block, Instruction ins, short locVarRegStart, ref short baseRegIdx) { List <OpCodeR> lst = block.FinalInstructions; OpCodeR op = new OpCodeR(); var code = ins.OpCode; var token = ins.Operand; op.Code = (OpCodeREnum)code.Code; bool hasRet; switch (code.Code) { case Code.Br_S: case Code.Br: op.Operand = entryMapping[(Mono.Cecil.Cil.Instruction)token]; break; case Code.Brtrue: case Code.Brtrue_S: case Code.Brfalse: case Code.Brfalse_S: op.Register1 = --baseRegIdx; op.Operand = entryMapping[(Mono.Cecil.Cil.Instruction)token]; break; case Code.Switch: op.Register1 = --baseRegIdx; PrepareJumpTable(token); op.Operand = token.GetHashCode(); break; case Code.Blt: case Code.Blt_S: case Code.Blt_Un: case Code.Blt_Un_S: case Code.Ble: case Code.Ble_S: case Code.Ble_Un: case Code.Ble_Un_S: case Code.Bgt: case Code.Bgt_S: case Code.Bgt_Un: case Code.Bgt_Un_S: case Code.Bge: case Code.Bge_S: case Code.Bge_Un: case Code.Bge_Un_S: case Code.Beq: case Code.Beq_S: case Code.Bne_Un: case Code.Bne_Un_S: op.Register1 = (short)(baseRegIdx - 2); op.Register2 = (short)(baseRegIdx - 1); baseRegIdx -= 2; op.Operand = entryMapping[(Mono.Cecil.Cil.Instruction)token]; break; case Code.Ldc_I4_0: case Code.Ldc_I4_1: case Code.Ldc_I4_2: case Code.Ldc_I4_3: case Code.Ldc_I4_4: case Code.Ldc_I4_5: case Code.Ldc_I4_6: case Code.Ldc_I4_7: case Code.Ldc_I4_8: case Code.Ldc_I4_M1: case Code.Ldnull: op.Register1 = baseRegIdx++; break; case Code.Ldc_I4: op.Register1 = baseRegIdx++; op.Operand = (int)token; break; case Code.Ldc_I4_S: op.Register1 = baseRegIdx++; op.Operand = (sbyte)token; break; case Code.Ldc_I8: op.Register1 = baseRegIdx++; op.OperandLong = (long)token; break; case Code.Ldc_R4: op.Register1 = baseRegIdx++; op.OperandFloat = (float)token; break; case Code.Ldc_R8: op.Register1 = baseRegIdx++; op.OperandDouble = (double)token; break; case Code.Ldstr: op.Register1 = baseRegIdx++; op.OperandLong = appdomain.CacheString(token); break; case Code.Newobj: { bool canInline, isILMethod; ILMethod toInline; IMethod m; var pCnt = InitializeFunctionParam(ref op, token, out hasRet, out canInline, out m, out toInline, out isILMethod); int pushCnt = Math.Max(pCnt - CallRegisterParamCount, 0); for (int i = pCnt; i > pCnt - pushCnt; i--) { OpCodes.OpCodeR op2 = new OpCodes.OpCodeR(); op2.Code = OpCodes.OpCodeREnum.Push; op2.Register1 = (short)(baseRegIdx - i); lst.Add(op2); } if (pushCnt < pCnt) { switch (pCnt - pushCnt) { case 1: op.Register2 = (short)(baseRegIdx - 1); break; case 2: op.Register3 = (short)(baseRegIdx - 1); op.Register2 = (short)(baseRegIdx - 2); break; case 3: op.Register4 = (short)(baseRegIdx - 1); op.Register3 = (short)(baseRegIdx - 2); op.Register2 = (short)(baseRegIdx - 3); break; } } baseRegIdx -= (short)pCnt; op.Register1 = baseRegIdx++; } break; case Code.Call: case Code.Callvirt: { bool canInline, isILMethod; ILMethod toInline; IMethod m; var pCnt = InitializeFunctionParam(ref op, token, out hasRet, out canInline, out m, out toInline, out isILMethod); bool hasConstrained = false; int constrainIdx = -1; if (lst.Count > 0) { constrainIdx = lst.Count - 1; hasConstrained = lst[constrainIdx].Code == OpCodeREnum.Constrained; } bool needInline = canInline && !hasConstrained; if (needInline) { if (toInline.BodyRegister.Length > Optimizer.MaximalInlineInstructionCount / 2) { needInline = false; } } if (!needInline) { if (code.Code == Code.Callvirt && m is ILMethod) { ILMethod ilm = (ILMethod)m; if (!ilm.Definition.IsAbstract && !ilm.Definition.IsVirtual && !ilm.DeclearingType.IsInterface) { op.Code = OpCodeREnum.Call; } } int pushCnt = hasConstrained ? pCnt : Math.Max(pCnt - CallRegisterParamCount, 0); for (int i = pCnt; i > pCnt - pushCnt; i--) { OpCodes.OpCodeR op2 = new OpCodes.OpCodeR(); op2.Code = OpCodes.OpCodeREnum.Push; op2.Operand = isILMethod ? 1 : 0; op2.Register1 = (short)(baseRegIdx - i); lst.Add(op2); } if (pushCnt < pCnt) { switch (pCnt - pushCnt) { case 1: op.Register2 = (short)(baseRegIdx - 1); break; case 2: op.Register3 = (short)(baseRegIdx - 1); op.Register2 = (short)(baseRegIdx - 2); break; case 3: op.Register4 = (short)(baseRegIdx - 1); op.Register3 = (short)(baseRegIdx - 2); op.Register2 = (short)(baseRegIdx - 3); break; } } if (hasConstrained) { op.Operand4 = 1; var old = lst[constrainIdx]; lst.RemoveAt(constrainIdx); old.Operand2 = op.Operand2; var symbol = block.InstructionMapping[constrainIdx]; block.InstructionMapping.Remove(constrainIdx); block.InstructionMapping.Add(lst.Count, symbol); lst.Add(old); } baseRegIdx -= (short)pCnt; if (hasRet) { op.Register1 = baseRegIdx++; } else { op.Register1 = -1; } } else { baseRegIdx -= (short)pCnt; RegisterVMSymbolLink link = null; #if DEBUG && !DISABLE_ILRUNTIME_DEBUG link = new RegisterVMSymbolLink(); link.BaseRegisterIndex = baseRegIdx; link.Value.Instruction = ins; link.Value.Method = method; #endif #if DEBUG && !NO_PROFILER if (System.Threading.Thread.CurrentThread.ManagedThreadId == method.AppDomain.UnityMainThreadID) #if UNITY_5_5_OR_NEWER { UnityEngine.Profiling.Profiler.BeginSample("JITCompiler.InlineMethod"); } #else { UnityEngine.Profiler.BeginSample("JITCompiler.InlineMethod"); } #endif #endif Optimizer.InlineMethod(block, toInline, link, ref jumptables, baseRegIdx, hasRet); #if DEBUG && !NO_PROFILER if (System.Threading.Thread.CurrentThread.ManagedThreadId == method.AppDomain.UnityMainThreadID) #if UNITY_5_5_OR_NEWER { UnityEngine.Profiling.Profiler.EndSample(); } #else { UnityEngine.Profiler.EndSample(); } #endif #endif if (hasRet) { baseRegIdx++; } return; } } break; case Code.Ldsfld: case Code.Ldsflda: op.Register1 = baseRegIdx++; op.OperandLong = appdomain.GetStaticFieldIndex(token, declaringType, method); break; case Code.Stsfld: op.Register1 = --baseRegIdx; op.OperandLong = appdomain.GetStaticFieldIndex(token, declaringType, method); break; case Code.Initobj: op.Register1 = --baseRegIdx; op.Operand = method.GetTypeTokenHashCode(token); break; case Code.Ret: if (hasReturn) { op.Register1 = --baseRegIdx; } break; case Code.Throw: op.Register1 = --baseRegIdx; break; case Code.Add: case Code.Add_Ovf: case Code.Add_Ovf_Un: case Code.Sub: case Code.Sub_Ovf: case Code.Sub_Ovf_Un: case Code.Mul: case Code.Mul_Ovf: case Code.Mul_Ovf_Un: case Code.Div: case Code.Div_Un: case Code.Rem: case Code.Rem_Un: case Code.Shr: case Code.Shr_Un: case Code.Shl: case Code.Xor: case Code.Or: case Code.And: case Code.Clt: case Code.Clt_Un: case Code.Cgt: case Code.Cgt_Un: case Code.Ceq: case Code.Ldelema: case Code.Ldelem_I1: case Code.Ldelem_U1: case Code.Ldelem_I2: case Code.Ldelem_U2: case Code.Ldelem_I4: case Code.Ldelem_U4: case Code.Ldelem_I8: case Code.Ldelem_R4: case Code.Ldelem_R8: case Code.Ldelem_Any: case Code.Ldelem_Ref: op.Register1 = (short)(baseRegIdx - 2); //explicit use dest register for optimization op.Register2 = (short)(baseRegIdx - 2); op.Register3 = (short)(baseRegIdx - 1); baseRegIdx--; break; case Code.Nop: case Code.Castclass: case Code.Readonly: case Code.Volatile: case Code.Endfinally: break; case Code.Leave: case Code.Leave_S: break; case Code.Stloc_0: op.Code = OpCodes.OpCodeREnum.Move; op.Register1 = locVarRegStart; op.Register2 = --baseRegIdx; break; case Code.Stloc_1: op.Code = OpCodes.OpCodeREnum.Move; op.Register1 = (short)(locVarRegStart + 1); op.Register2 = --baseRegIdx; break; case Code.Stloc_2: op.Code = OpCodes.OpCodeREnum.Move; op.Register1 = (short)(locVarRegStart + 2); op.Register2 = --baseRegIdx; break; case Code.Stloc_3: op.Code = OpCodes.OpCodeREnum.Move; op.Register1 = (short)(locVarRegStart + 3); op.Register2 = --baseRegIdx; break; case Code.Stloc_S: op.Code = OpCodes.OpCodeREnum.Move; op.Register1 = (short)(locVarRegStart + ((VariableDefinition)ins.Operand).Index); op.Register2 = --baseRegIdx; break; case Code.Ldloc_0: op.Code = OpCodes.OpCodeREnum.Move; op.Register1 = baseRegIdx++; op.Register2 = locVarRegStart; break; case Code.Ldloc_1: op.Code = OpCodes.OpCodeREnum.Move; op.Register1 = baseRegIdx++; op.Register2 = (short)(locVarRegStart + 1); break; case Code.Ldloc_2: op.Code = OpCodes.OpCodeREnum.Move; op.Register1 = baseRegIdx++; op.Register2 = (short)(locVarRegStart + 2); break; case Code.Ldloc_3: op.Code = OpCodes.OpCodeREnum.Move; op.Register1 = baseRegIdx++; op.Register2 = (short)(locVarRegStart + 3); break; case Code.Ldloc: case Code.Ldloc_S: op.Code = OpCodes.OpCodeREnum.Move; op.Register1 = baseRegIdx++; op.Register2 = (short)(locVarRegStart + ((VariableDefinition)ins.Operand).Index); break; case Code.Ldloca: case Code.Ldloca_S: op.Register1 = baseRegIdx++; op.Register2 = (short)(locVarRegStart + ((VariableDefinition)ins.Operand).Index); break; case Code.Ldarg_0: case Code.Ldarg_1: case Code.Ldarg_2: case Code.Ldarg_3: op.Code = OpCodes.OpCodeREnum.Move; op.Register1 = baseRegIdx++; op.Register2 = (short)(code.Code - (Code.Ldarg_0)); break; case Code.Ldarg_S: op.Code = OpCodes.OpCodeREnum.Move; op.Register1 = baseRegIdx++; op.Register2 = (short)((ParameterDefinition)ins.Operand).Index; if (def.HasThis) { op.Register2++; } break; case Code.Ldarga: case Code.Ldarga_S: op.Register1 = baseRegIdx++; op.Register2 = (short)((ParameterDefinition)ins.Operand).Index; if (def.HasThis) { op.Register2++; } break; case Code.Starg: case Code.Starg_S: op.Code = OpCodes.OpCodeREnum.Move; op.Register2 = --baseRegIdx; op.Register1 = (short)((ParameterDefinition)ins.Operand).Index; if (def.HasThis) { op.Register1++; } break; case Code.Newarr: op.Register1 = (short)(baseRegIdx - 1); op.Register2 = (short)(baseRegIdx - 1); op.Operand = method.GetTypeTokenHashCode(token); break; case Code.Dup: op.Code = OpCodes.OpCodeREnum.Move; op.Register2 = (short)(baseRegIdx - 1); op.Register1 = baseRegIdx++; break; case Code.Stelem_I: case Code.Stelem_I1: case Code.Stelem_I2: case Code.Stelem_I4: case Code.Stelem_I8: case Code.Stelem_R4: case Code.Stelem_R8: case Code.Stelem_Ref: case Code.Stelem_Any: op.Register1 = (short)(baseRegIdx - 3); op.Register2 = (short)(baseRegIdx - 2); op.Register3 = (short)(baseRegIdx - 1); baseRegIdx -= 3; break; case Code.Stind_I: case Code.Stind_I1: case Code.Stind_I2: case Code.Stind_I4: case Code.Stind_I8: case Code.Stind_R4: case Code.Stind_R8: case Code.Stind_Ref: op.Register1 = (short)(baseRegIdx - 2); op.Register2 = (short)(baseRegIdx - 1); baseRegIdx -= 2; break; case Code.Stobj: op.Register1 = (short)(baseRegIdx - 2); op.Register2 = (short)(baseRegIdx - 1); op.Operand = method.GetTypeTokenHashCode(token); baseRegIdx -= 2; break; case Code.Conv_I: case Code.Conv_I1: case Code.Conv_I2: case Code.Conv_I4: case Code.Conv_I8: case Code.Conv_Ovf_I: case Code.Conv_Ovf_I1: case Code.Conv_Ovf_I1_Un: case Code.Conv_Ovf_I2: case Code.Conv_Ovf_I2_Un: case Code.Conv_Ovf_I4: case Code.Conv_Ovf_I4_Un: case Code.Conv_Ovf_I8: case Code.Conv_Ovf_I8_Un: case Code.Conv_Ovf_I_Un: case Code.Conv_Ovf_U: case Code.Conv_Ovf_U1: case Code.Conv_Ovf_U1_Un: case Code.Conv_Ovf_U2: case Code.Conv_Ovf_U2_Un: case Code.Conv_Ovf_U4: case Code.Conv_Ovf_U4_Un: case Code.Conv_Ovf_U8: case Code.Conv_Ovf_U8_Un: case Code.Conv_Ovf_U_Un: case Code.Conv_R4: case Code.Conv_R8: case Code.Conv_R_Un: case Code.Conv_U: case Code.Conv_U1: case Code.Conv_U2: case Code.Conv_U4: case Code.Conv_U8: case Code.Ldlen: case Code.Ldind_I: case Code.Ldind_I2: case Code.Ldind_I4: case Code.Ldind_I8: case Code.Ldind_R4: case Code.Ldind_R8: case Code.Ldind_U1: case Code.Ldind_U2: case Code.Ldind_U4: case Code.Ldind_Ref: case Code.Neg: case Code.Not: op.Register1 = (short)(baseRegIdx - 1); op.Register2 = (short)(baseRegIdx - 1); break; case Code.Ldobj: op.Register1 = (short)(baseRegIdx - 1); op.Register2 = (short)(baseRegIdx - 1); op.Operand = method.GetTypeTokenHashCode(token); break; case Code.Ldfld: case Code.Ldflda: op.Register1 = (short)(baseRegIdx - 1); op.Register2 = (short)(baseRegIdx - 1); op.OperandLong = appdomain.GetStaticFieldIndex(token, declaringType, method); break; case Code.Stfld: op.Register1 = (short)(baseRegIdx - 2); op.Register2 = (short)(baseRegIdx - 1); op.OperandLong = appdomain.GetStaticFieldIndex(token, declaringType, method); baseRegIdx -= 2; break; case Code.Box: case Code.Unbox: case Code.Unbox_Any: case Code.Isinst: op.Register1 = (short)(baseRegIdx - 1); op.Register2 = (short)(baseRegIdx - 1); op.Operand = method.GetTypeTokenHashCode(token); break; case Code.Constrained: op.Operand = method.GetTypeTokenHashCode(token); break; case Code.Ldtoken: op.Register1 = baseRegIdx++; if (token is FieldReference) { op.Operand = 0; op.OperandLong = appdomain.GetStaticFieldIndex(token, declaringType, method); } else if (token is TypeReference) { op.Operand = 1; op.OperandLong = method.GetTypeTokenHashCode(token); } else { throw new NotImplementedException(); } break; case Code.Ldftn: { op.Register1 = baseRegIdx++; bool hasReturn, canInline, isILMethod; ILMethod toInline; IMethod m; InitializeFunctionParam(ref op, token, out hasReturn, out canInline, out m, out toInline, out isILMethod); } break; case Code.Ldvirtftn: { bool hasReturn, canInline, isILMethod; ILMethod toInline; IMethod m; InitializeFunctionParam(ref op, token, out hasReturn, out canInline, out m, out toInline, out isILMethod); op.Register1 = (short)(baseRegIdx - 1); op.Register2 = (short)(baseRegIdx - 1); } break; case Code.Pop: baseRegIdx--; op.Code = OpCodeREnum.Nop; break; default: throw new NotImplementedException(string.Format("Unknown Opcode:{0}", code.Code)); } RegisterVMSymbol s = new RegisterVMSymbol() { Instruction = ins, Method = method }; block.InstructionMapping.Add(lst.Count, s); lst.Add(op); }
public OpCodeR[] Compile(out int stackRegisterCnt, out Dictionary <int, int[]> switchTargets, Dictionary <Instruction, int> addr, out Dictionary <int, RegisterVMSymbol> symbols) { #if DEBUG && !NO_PROFILER if (System.Threading.Thread.CurrentThread.ManagedThreadId == method.AppDomain.UnityMainThreadID) #if UNITY_5_5_OR_NEWER { UnityEngine.Profiling.Profiler.BeginSample("JITCompiler.Compile"); } #else { UnityEngine.Profiler.BeginSample("JITCompiler.Compile"); } #endif #endif method.Compiling = true; symbols = new Dictionary <int, RegisterVMSymbol>(); var body = def.Body; short locVarRegStart = (short)def.Parameters.Count; if (!def.IsStatic) { locVarRegStart++; } short baseRegIdx = (short)(locVarRegStart + body.Variables.Count); short baseRegStart = baseRegIdx; var blocks = CodeBasicBlock.BuildBasicBlocks(body, out entryMapping); foreach (var i in blocks) { baseRegIdx = baseRegStart; if (IsCatchHandler(i, body)) { baseRegIdx++; } else { if (i.PreviousBlocks.Count > 0) { foreach (var j in i.PreviousBlocks) { if (j.EndRegister >= 0) { baseRegIdx = j.EndRegister; break; } } } } foreach (var ins in i.Instructions) { Translate(i, ins, locVarRegStart, ref baseRegIdx); } i.EndRegister = baseRegIdx; } //Append init local var first = blocks[0]; int idx = 0; int appendIdx = 0; HashSet <CodeBasicBlock> visitedBlocks = body.Variables.Count > 0 ? new HashSet <CodeBasicBlock>() : null; for (short r = locVarRegStart; r < locVarRegStart + body.Variables.Count; r++) { visitedBlocks.Clear(); if (CheckNeedInitObj(first, r, method.ReturnType != method.AppDomain.VoidType, visitedBlocks)) { OpCodeR code = new OpCodeR(); code.Code = OpCodeREnum.Initobj; code.Register1 = r; code.Operand = method.GetTypeTokenHashCode(body.Variables[idx].VariableType); code.Operand2 = 1; first.FinalInstructions.Insert(appendIdx++, code); } idx++; } for (idx = first.FinalInstructions.Count - 1; idx >= 0; idx--) { if (idx >= appendIdx) { RegisterVMSymbol symbol; if (first.InstructionMapping.TryGetValue(idx - appendIdx, out symbol)) { first.InstructionMapping[idx] = first.InstructionMapping[idx - appendIdx]; } } else { first.InstructionMapping.Remove(idx); } } #if OUTPUT_JIT_RESULT int cnt = 1; Console.WriteLine($"JIT Results for {method}:"); foreach (var b in blocks) { Console.WriteLine($"Block {cnt++}, Instructions:{b.FinalInstructions.Count}"); for (int i = 0; i < b.FinalInstructions.Count; i++) { Console.WriteLine($" {i}:{b.FinalInstructions[i].ToString(appdomain)}"); } } #endif Optimizer.ForwardCopyPropagation(blocks, hasReturn, baseRegStart); Optimizer.BackwardsCopyPropagation(blocks, hasReturn, baseRegStart); Optimizer.ForwardCopyPropagation(blocks, hasReturn, baseRegStart); #if OUTPUT_JIT_RESULT cnt = 1; Console.WriteLine($"Optimizer Results for {method}:"); foreach (var b in blocks) { Console.WriteLine($"Block {cnt++}, Instructions:{b.FinalInstructions.Count}"); for (int i = 0; i < b.FinalInstructions.Count; i++) { string canRemove = b.CanRemove.Contains(i) ? "(x)" : ""; Console.WriteLine($" {i}:{canRemove}{b.FinalInstructions[i].ToString(appdomain)}"); } } #endif List <OpCodeR> res = new List <OpCodeR>(); Dictionary <int, int> jumpTargets = new Dictionary <int, int>(); int bIdx = 0; HashSet <int> inlinedBranches = new HashSet <int>(); int curIndex = 0; foreach (var b in blocks) { jumpTargets[bIdx++] = res.Count; bool isInline = false; int inlineOffset = 0; bool inlineAddressSet = false; for (idx = 0; idx < b.FinalInstructions.Count; idx++) { RegisterVMSymbol oriIns; bool hasOri = b.InstructionMapping.TryGetValue(idx, out oriIns); if (hasOri) { if (isInline) { if (!inlineAddressSet) { while (oriIns.ParentSymbol != null) { oriIns = oriIns.ParentSymbol.Value; } addr[oriIns.Instruction] = curIndex; inlineAddressSet = true; } } else { addr[oriIns.Instruction] = curIndex; } } if (b.CanRemove.Contains(idx)) { if (isInline) { inlineOffset--; } continue; } var ins = b.FinalInstructions[idx]; if (ins.Code == OpCodeREnum.InlineStart) { inlineAddressSet = false; isInline = true; inlineOffset = res.Count; } else if (ins.Code == OpCodeREnum.InlineEnd) { isInline = false; } else { if (isInline) { if (Optimizer.IsBranching(ins.Code)) { ins.Operand += inlineOffset; inlinedBranches.Add(res.Count); } else if (ins.Code == OpCodeREnum.Switch) { int[] targets = jumptables[ins.Operand]; for (int j = 0; j < targets.Length; j++) { targets[j] = targets[j] + inlineOffset; } inlinedBranches.Add(res.Count); } } if (hasOri) { symbols.Add(res.Count, oriIns); } curIndex++; res.Add(ins); } } } for (int i = 0; i < res.Count; i++) { var op = res[i]; if (Optimizer.IsBranching(op.Code) && !inlinedBranches.Contains(i)) { op.Operand = jumpTargets[op.Operand]; res[i] = op; } else if (op.Code == OpCodeREnum.Switch && !inlinedBranches.Contains(i)) { int[] targets = jumptables[op.Operand]; for (int j = 0; j < targets.Length; j++) { targets[j] = jumpTargets[targets[j]]; } } else if (op.Code == OpCodeREnum.Leave || op.Code == OpCodeREnum.Leave_S) { var oriIns = symbols[i]; op.Operand = addr[(Instruction)oriIns.Instruction.Operand]; res[i] = op; } } #if DEBUG && !DISABLE_ILRUNTIME_DEBUG //FixSymbol(symbols); #else symbols = null; #endif switchTargets = jumptables; var totalRegCnt = Optimizer.CleanupRegister(res, locVarRegStart, hasReturn); stackRegisterCnt = totalRegCnt - baseRegStart; #if OUTPUT_JIT_RESULT Console.WriteLine($"Final Results for {method}:"); for (int i = 0; i < res.Count; i++) { Console.WriteLine($" {i}:{res[i].ToString(appdomain)}"); } #endif method.Compiling = false; var arr = res.ToArray(); #if DEBUG && !NO_PROFILER if (System.Threading.Thread.CurrentThread.ManagedThreadId == method.AppDomain.UnityMainThreadID) #if UNITY_5_5_OR_NEWER { UnityEngine.Profiling.Profiler.EndSample(); } #else { UnityEngine.Profiler.EndSample(); } #endif #endif return(arr); }
public static void EliminateConstantLoad(List <CodeBasicBlock> blocks, bool hasReturn) { foreach (var b in blocks) { if (!b.NeedLoadConstantElimination) { continue; } var lst = b.FinalInstructions; HashSet <int> canRemove = b.CanRemove; //HashSet<int> pendingBCP = b.PendingCP; bool isInline = false; for (int i = 0; i < lst.Count; i++) { OpCodeR X = lst[i]; if (X.Code == OpCodeREnum.InlineStart) { isInline = true; continue; } if (X.Code == OpCodeREnum.InlineEnd) { isInline = false; continue; } if (isInline) { continue; } if (IsLoadConstant(X.Code)) { short xDst; GetOpcodeDestRegister(ref X, out xDst); 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 r1, r2, r3; GetOpcodeSourceRegister(ref Y, hasReturn, out r1, out r2, out r3); if (r1 == xDst || r2 == xDst || r3 == xDst) { if (SupportIntemediateValue(Y.Code)) { if (r2 == xDst) { if (!propagationInline) { Y.Code = GetIntemediateValueOpcode(Y.Code); ReplaceRegisterWithConstant(ref Y, ref X); lst[j] = Y; canRemove.Add(i); } } else if (r1 == xDst) { if (!propagationInline) { if (SupportOperandSwap(Y.Code)) { ReplaceOpcodeSource(ref Y, 0, r2); Y.Code = GetIntemediateValueOpcode(Y.Code); ReplaceRegisterWithConstant(ref Y, ref X); lst[j] = Y; canRemove.Add(i); } else if (HasInverseOpcode(Y.Code)) { ReplaceOpcodeSource(ref Y, 0, r2); Y.Code = GetIntemediateValueOpcode(GetInverseOpcode(Y.Code)); ReplaceRegisterWithConstant(ref Y, ref X); lst[j] = Y; canRemove.Add(i); } } } } break; } short yDst; GetOpcodeDestRegister(ref Y, out yDst); if (yDst == xDst) { break; } } } } } }