private static void OptimizeReuseStoreVariable(OpcodeGenerator generator, OpcodeGenerator nextGenerator) { Debug.Assert(generator.Instruction.HasStoreVariable); if (nextGenerator.CanReuseFirstOperand || nextGenerator.CanReuseSecondOperand) { if (nextGenerator.CanReuseFirstOperand) { Debug.Assert(nextGenerator.Instruction.OperandCount > 0); var firstOperand = nextGenerator.Instruction.Operands[0]; if (firstOperand.IsVariable) { if (firstOperand.Value == generator.Instruction.StoreVariable.ToByte()) { Debug.WriteLine("{0:x4}: Optimizing {1} between {2} and {3}", generator.Instruction.Address, generator.Instruction.StoreVariable, generator.Instruction.Opcode.Name, nextGenerator.Instruction.Opcode.Name); generator.ReuseStoreVariable = true; nextGenerator.ReuseFirstOperand = true; } } } if (nextGenerator.CanReuseSecondOperand && !nextGenerator.ReuseFirstOperand) { Debug.Assert(nextGenerator.Instruction.OperandCount > 1); var secondOperand = nextGenerator.Instruction.Operands[1]; if (secondOperand.IsVariable) { if (secondOperand.Value == generator.Instruction.StoreVariable.ToByte()) { Debug.WriteLine("{0:x4}: Optimizing {1} between {2} and {3}", generator.Instruction.Address, generator.Instruction.StoreVariable, generator.Instruction.Opcode.Name, nextGenerator.Instruction.Opcode.Name); generator.ReuseStoreVariable = true; nextGenerator.ReuseSecondOperand = true; } } } } else if (nextGenerator.CanReuseStack && generator.Instruction.StoreVariable.Kind == VariableKind.Stack) { Debug.WriteLine("{0:x4}: Optimizing {1} between {2} and {3}", generator.Instruction.Address, generator.Instruction.StoreVariable, generator.Instruction.Opcode.Name, nextGenerator.Instruction.Opcode.Name); generator.ReuseStoreVariable = true; nextGenerator.ReuseStack = true; } }
private static void OptimizeStoreVariableSign(OpcodeGenerator generator, OpcodeGenerator nextGenerator) { Debug.Assert(generator.Instruction.HasStoreVariable); if (nextGenerator.SignsOperands) { Debug.WriteLine("{0:x4}: Optimizing store variable sign between {1} and {2}", generator.Instruction.Address, generator.Instruction.Opcode.Name, nextGenerator.Instruction.Opcode.Name); generator.LeaveStoreVariableSigned = true; } }
public ZCompilerResult Compile() { var sw = Stopwatch.StartNew(); var dm = CreateDynamicMethod(routine); this.il = new ILBuilder(dm.GetILGenerator()); this.calls = new List <ZRoutineCall>(); Profiler_EnterRoutine(); this.controlFlowGraph = ControlFlowGraph.Build(this.routine); this.addressToLabelMap = new Dictionary <int, ILabel>(this.controlFlowGraph.CodeBlocks.Count()); // Determine whether stack, memory, screen and outputStreams are used. foreach (var codeBlock in this.controlFlowGraph.CodeBlocks) { this.addressToLabelMap.Add(codeBlock.Address, il.NewLabel()); foreach (var i in codeBlock.Instructions) { if (!this.usesStack && i.UsesStack()) { this.usesStack = true; } if (!this.usesMemory && i.UsesMemory()) { this.usesMemory = true; } } } var instructionStatistics = new List <InstructionStatistics>(this.routine.Instructions.Length); // Emit IL foreach (var codeBlock in this.controlFlowGraph.CodeBlocks) { var generators = codeBlock.Instructions .Select(i => OpcodeGenerator.GetGenerator(i, machine.Version)) .ToList(); Optimize(generators); foreach (var generator in generators) { ILabel label; if (this.addressToLabelMap.TryGetValue(generator.Instruction.Address, out label)) { label.Mark(); } if (machine.Debugging) { il.Arguments.LoadMachine(); il.Call(Reflection <CompiledZMachine> .GetMethod("Tick", @public: false)); } Profiler_ExecutingInstruction(generator.Instruction); il.DebugWrite(generator.Instruction.PrettyPrint(machine)); var offset = il.Size; generator.Generate(il, this); instructionStatistics.Add(new InstructionStatistics(generator.Instruction, offset, il.Size - offset)); } } var code = (ZRoutineCode)dm.CreateDelegate(typeof(ZRoutineCode), machine); sw.Stop(); var statistics = new RoutineCompilationStatistics( this.routine, il.OpcodeCount, il.LocalCount, il.Size, sw.Elapsed, calculatedLoadVariableCount, calculatedStoreVariableCount, instructionStatistics); return(new ZCompilerResult(this.routine, calls.ToArray(), code, statistics)); }
private static void OptimizeReuseByRefOperand(OpcodeGenerator generator, OpcodeGenerator nextGenerator) { Debug.Assert(generator.Instruction.Opcode.IsFirstOpByRef); Debug.Assert(generator.Instruction.OperandCount > 0); var byRefOperand = generator.Instruction.Operands[0]; if (byRefOperand.Kind == OperandKind.SmallConstant) { if (nextGenerator.CanReuseFirstOperand || nextGenerator.CanReuseSecondOperand) { if (nextGenerator.CanReuseFirstOperand) { Debug.Assert(nextGenerator.Instruction.OperandCount > 0); var firstOperand = nextGenerator.Instruction.Operands[0]; if (firstOperand.IsVariable) { if (firstOperand.Value == byRefOperand.Value) { Debug.WriteLine("{0:x4}: Optimizing {1} between {2} and {3}", generator.Instruction.Address, Variable.FromByte((byte)byRefOperand.Value), generator.Instruction.Opcode.Name, nextGenerator.Instruction.Opcode.Name); generator.ReuseByRefOperand = true; nextGenerator.ReuseFirstOperand = true; } } } if (nextGenerator.CanReuseSecondOperand && !nextGenerator.ReuseFirstOperand) { Debug.Assert(nextGenerator.Instruction.OperandCount > 1); var secondOperand = nextGenerator.Instruction.Operands[1]; if (secondOperand.IsVariable) { if (secondOperand.Value == byRefOperand.Value) { Debug.WriteLine("{0:x4}: Optimizing {1} between {2} and {3}", generator.Instruction.Address, Variable.FromByte((byte)byRefOperand.Value), generator.Instruction.Opcode.Name, nextGenerator.Instruction.Opcode.Name); generator.ReuseByRefOperand = true; nextGenerator.ReuseSecondOperand = true; } } } } else if (nextGenerator.CanReuseStack && byRefOperand.Value == 0) { Debug.WriteLine("{0:x4}: Optimizing {1} between {2} and {3}", generator.Instruction.Address, Variable.FromByte((byte)byRefOperand.Value), generator.Instruction.Opcode.Name, nextGenerator.Instruction.Opcode.Name); generator.ReuseByRefOperand = true; nextGenerator.ReuseStack = true; } } }