2using System.Collections.Generic;
10 internal class Optimizer
13 #region Private Variables
15 private Executable executable;
21 #region Private Methods
23 private bool Tripleinstruction(
int i)
25 return i < executable.InstructionsInternal.Count - 2;
28 private bool DoubleInstruction(
int i)
30 return i < executable.InstructionsInternal.Count - 1;
33 private bool IsTemporaryVariable(
string identifier)
35 return identifier.StartsWith(
"[");
38 private bool IsTemporaryVariable(Operand operand)
44 return IsTemporaryVariable(operand.
Value.ToString());
48 private bool IsTemporaryVariableIndex(Operand operand)
54 return operand.
Pointer.StartsWith(
"[");
58 private bool IsUnaryOperator(
OpCode opcode)
77 private bool IsBinaryOperator(
OpCode opcode)
104 private void InsertOptimiserInfo(
int i,
string message)
110 executable.InstructionsInternal.Insert(i,
new Instruction(
OpCode.DBG, Operand.Literal(0), Operand.Literal(
"OPTIMIZER: " + message)));
114 private void OptimiseBinaryExpressionEvaluation(
int i)
117 List<Instruction> instructions = executable.InstructionsInternal;
119 Instruction instruction0 = instructions[i];
121 Instruction instruction1 = instructions[i + 1];
123 Instruction instruction2 = instructions[i + 2];
131 if (!IsBinaryOperator(instruction2.
OpCode))
134 if (!IsTemporaryVariable(instruction0.
First))
137 if (!IsTemporaryVariable(instruction1.
First))
140 if (!IsTemporaryVariable(instruction2.
First))
143 if (!IsTemporaryVariable(instruction2.
Second))
155 InsertOptimiserInfo(i,
"Binary Expression Evaluation");
157 instruction1.OpCode = instruction2.
OpCode;
159 instruction1.First = instruction0.
First;
161 instruction2.OpCode =
OpCode.NOP;
163 instruction2.First =
null;
165 instruction2.Second =
null;
171 private void OptimiseUnaryExpressionAssignment(
int iIndex)
174 List<Instruction> listInstructions
175 = executable.InstructionsInternal;
177 Instruction scriptInstruction0 = listInstructions[iIndex];
179 Instruction scriptInstruction1 = listInstructions[iIndex + 1];
181 Instruction scriptInstruction2 = listInstructions[iIndex + 2];
186 if (!IsUnaryOperator(scriptInstruction1.
OpCode))
192 if (!IsTemporaryVariable(scriptInstruction0.
First))
195 if (!IsTemporaryVariable(scriptInstruction1.
First))
198 if (!IsTemporaryVariable(scriptInstruction2.
Second))
207 InsertOptimiserInfo(iIndex,
"Unary Expression Assignment");
209 scriptInstruction0.First = scriptInstruction2.
First;
211 scriptInstruction1.First = scriptInstruction2.
First;
213 scriptInstruction2.OpCode =
OpCode.NOP;
215 scriptInstruction2.First =
null;
217 scriptInstruction2.Second =
null;
223 private void OptimiseBinaryExpressionAssignment(
int iIndex)
226 List<Instruction> listInstructions = executable.InstructionsInternal;
228 Instruction scriptInstruction0 = listInstructions[iIndex];
229 Instruction scriptInstruction1 = listInstructions[iIndex + 1];
230 Instruction scriptInstruction2 = listInstructions[iIndex + 2];
233 if (!IsBinaryOperator(scriptInstruction1.
OpCode))
return;
235 if (!IsTemporaryVariable(scriptInstruction0.
First))
return;
236 if (!IsTemporaryVariable(scriptInstruction1.
First))
return;
237 if (!IsTemporaryVariable(scriptInstruction2.
Second))
return;
245 InsertOptimiserInfo(iIndex,
"Binary Expression Assignment");
247 scriptInstruction0.First = scriptInstruction2.
First;
248 scriptInstruction1.First = scriptInstruction2.
First;
249 scriptInstruction2.OpCode =
OpCode.NOP;
250 scriptInstruction2.First =
null;
251 scriptInstruction2.Second =
null;
256 private void OptimiseInstructionTriples(
int iIndex)
258 OptimiseUnaryExpressionAssignment(iIndex);
260 OptimiseBinaryExpressionEvaluation(iIndex);
261 OptimiseBinaryExpressionAssignment(iIndex);
264 private void OptimisePushOperation(
int iIndex)
267 List<Instruction> listInstructions
268 = executable.InstructionsInternal;
270 Instruction scriptInstruction0
271 = listInstructions[iIndex];
272 Instruction scriptInstruction1
273 = listInstructions[iIndex + 1];
278 if (!IsTemporaryVariable(scriptInstruction0.
First))
return;
279 if (!IsTemporaryVariable(scriptInstruction1.
First))
return;
284 InsertOptimiserInfo(iIndex,
"Push Operation");
286 scriptInstruction0.OpCode =
OpCode.PUSH;
287 scriptInstruction0.First = scriptInstruction0.
Second;
288 scriptInstruction0.Second =
null;
289 scriptInstruction1.OpCode =
OpCode.NOP;
290 scriptInstruction1.First =
null;
291 scriptInstruction1.Second =
null;
296 private void OptimisePopOperation(
int iIndex)
299 List<Instruction> listInstructions
300 = executable.InstructionsInternal;
302 Instruction scriptInstruction0
303 = listInstructions[iIndex];
304 Instruction scriptInstruction1
305 = listInstructions[iIndex + 1];
310 if (!IsTemporaryVariable(scriptInstruction0.
First))
return;
311 if (!IsTemporaryVariable(scriptInstruction1.
Second))
return;
316 InsertOptimiserInfo(iIndex,
"Pop Operation");
318 scriptInstruction0.OpCode =
OpCode.POP;
319 scriptInstruction0.First = scriptInstruction1.
First;
320 scriptInstruction1.OpCode =
OpCode.NOP;
321 scriptInstruction1.First =
null;
322 scriptInstruction1.Second =
null;
327 private void OptimiseLiteralAssignment(
int iIndex)
330 List<Instruction> listInstructions
331 = executable.InstructionsInternal;
333 Instruction scriptInstruction0
334 = listInstructions[iIndex];
335 Instruction scriptInstruction1
336 = listInstructions[iIndex + 1];
339 if (!IsTemporaryVariable(scriptInstruction0.
First))
return;
340 if (!IsTemporaryVariable(scriptInstruction1.
Second))
return;
345 InsertOptimiserInfo(iIndex,
"Literal Assignment");
347 scriptInstruction0.First = scriptInstruction1.
First;
348 scriptInstruction1.OpCode =
OpCode.NOP;
349 scriptInstruction1.First =
null;
350 scriptInstruction1.Second =
null;
355 private void OptimiseConditionalJumps(
int iIndex)
358 List<Instruction> listInstructions
359 = executable.InstructionsInternal;
361 Instruction scriptInstruction0
362 = listInstructions[iIndex];
363 Instruction scriptInstruction1
364 = listInstructions[iIndex + 1];
368 if (!IsTemporaryVariable(scriptInstruction0.
First))
return;
369 if (!IsTemporaryVariable(scriptInstruction1.
First))
return;
374 InsertOptimiserInfo(iIndex,
"Conditional Jump Expressions");
376 scriptInstruction0.OpCode = scriptInstruction1.
OpCode;
377 scriptInstruction0.First = scriptInstruction0.
Second;
378 scriptInstruction0.Second = scriptInstruction1.
Second;
379 scriptInstruction1.OpCode =
OpCode.NOP;
380 scriptInstruction1.First =
null;
381 scriptInstruction1.Second =
null;
386 private void OptimiseArrayIndices(
int iIndex)
389 List<Instruction> listInstructions
390 = executable.InstructionsInternal;
392 Instruction scriptInstruction0
393 = listInstructions[iIndex];
394 Instruction scriptInstruction1
395 = listInstructions[iIndex + 1];
401 if (!IsTemporaryVariable(scriptInstruction0.
First))
return;
402 if (!IsTemporaryVariableIndex(scriptInstruction1.
First))
return;
407 InsertOptimiserInfo(iIndex,
"Array Index");
409 scriptInstruction0.First = scriptInstruction1.
First;
410 scriptInstruction0.First.Pointer
412 scriptInstruction0.Second = scriptInstruction1.
Second;
413 scriptInstruction1.OpCode =
OpCode.NOP;
414 scriptInstruction1.First =
null;
415 scriptInstruction1.Second =
null;
420 private void EliminateSequentialJumps(
int iIndex)
423 List<Instruction> listInstructions
424 = executable.InstructionsInternal;
426 Instruction scriptInstruction0
427 = listInstructions[iIndex];
428 Instruction scriptInstruction1
429 = listInstructions[iIndex + 1];
432 != scriptInstruction1)
return;
434 InsertOptimiserInfo(iIndex,
"Sequentual Jump Elimination");
436 scriptInstruction0.OpCode =
OpCode.NOP;
437 scriptInstruction0.First =
null;
438 scriptInstruction0.Second =
null;
443 private void OptimiseInstructionPairs(
int iIndex)
445 OptimisePushOperation(iIndex);
446 OptimisePopOperation(iIndex);
447 OptimiseLiteralAssignment(iIndex);
448 OptimiseConditionalJumps(iIndex);
449 OptimiseArrayIndices(iIndex);
450 EliminateSequentialJumps(iIndex);
453 private void EliminateSelfAssignments(
int iIndex)
456 Instruction scriptInstruction
457 = executable.InstructionsInternal[iIndex];
459 Operand operand0 = scriptInstruction.
First;
460 Operand operand1 = scriptInstruction.
Second;
461 if (operand0.
Type != operand1.
Type)
return;
466 if (operand0.
Value.ToString() != operand1.
Value.ToString())
468 switch (operand0.
Type)
471 if (operand0.
Member.ToString()
472 != operand1.
Member.ToString())
481 InsertOptimiserInfo(iIndex,
"Self Assignment Removal");
483 scriptInstruction.OpCode =
OpCode.NOP;
484 scriptInstruction.First =
null;
485 scriptInstruction.Second =
null;
490 private void OptimiseConstantConditionalJumps(
int iIndex)
493 List<Instruction> listInstructions
494 = executable.InstructionsInternal;
496 Instruction scriptInstruction
497 = listInstructions[iIndex];
501 if (scriptInstruction.
First.
Value.GetType() != typeof(
bool))
return;
502 bool bCondition = (bool) scriptInstruction.
First.
Value;
504 InsertOptimiserInfo(iIndex,
"Constant Conditional Jump");
507 if ((opcodeJump ==
OpCode.JZ && bCondition)
508 || (opcodeJump ==
OpCode.JNZ && !bCondition))
510 scriptInstruction.OpCode =
OpCode.JMP;
511 scriptInstruction.First = scriptInstruction.
Second;
512 scriptInstruction.Second =
null;
516 scriptInstruction.OpCode =
OpCode.NOP;
517 scriptInstruction.First =
null;
518 scriptInstruction.Second =
null;
524 private void OptimiseIncrementsAndDecrements(
int iIndex)
527 Instruction scriptInstruction
528 = executable.InstructionsInternal[iIndex];
536 object objectLiteral = scriptInstruction.
Second.
Value;
537 Type typeLiteral = objectLiteral.GetType();
538 if (typeLiteral != typeof(
int) && typeLiteral != typeof(
float))
return;
539 if (typeLiteral == typeof(
int) && Math.Abs((
int)objectLiteral) != 1)
return;
540 if (typeLiteral == typeof(
float) && Math.Abs((
float)objectLiteral) != 1.0f)
return;
542 InsertOptimiserInfo(iIndex,
"Increment/Decrement Optimisation");
546 if (typeLiteral == typeof(
int))
547 fValue = (float)(
int)objectLiteral;
549 fValue = (float)objectLiteral;
553 bool bIncrement = opcodeOld == OpCode.ADD && fValue > 0.0f
554 || opcodeOld == OpCode.SUB && fValue < 0.0f;
556 scriptInstruction.OpCode = bIncrement ? OpCode.INC :
OpCode.DEC;
557 scriptInstruction.Second =
null;
562 private void OptimiseSingleInstructions(
int iIndex)
564 EliminateSelfAssignments(iIndex);
565 OptimiseConstantConditionalJumps(iIndex);
566 OptimiseIncrementsAndDecrements(iIndex);
569 private void TraverseActiveInstructions(
570 Dictionary<Instruction, bool> dictScriptInstructionsActive,
575 Instruction scriptInstruction
576 = executable.InstructionsInternal[iNextInstuction];
577 if (dictScriptInstructionsActive.ContainsKey(scriptInstruction))
580 dictScriptInstructionsActive[scriptInstruction] =
true;
582 switch (scriptInstruction.
OpCode)
590 TraverseActiveInstructions(dictScriptInstructionsActive,
596 TraverseActiveInstructions(dictScriptInstructionsActive,
609 private void EliminateDeadCode()
613 Dictionary<Instruction, bool> dictScriptInstructionsActive
614 =
new Dictionary<Instruction, bool>();
616 foreach (
Function scriptFunction
in executable.Functions.Values)
618 TraverseActiveInstructions(dictScriptInstructionsActive,
622 foreach (Instruction scriptInstruction
in executable.InstructionsInternal)
628 if (!dictScriptInstructionsActive.ContainsKey(scriptInstruction))
630 scriptInstruction.OpCode =
OpCode.NOP;
631 scriptInstruction.First =
null;
632 scriptInstruction.Second =
null;
639 private void EliminateUnusedTempVariables()
641 Dictionary<String, Instruction> dictTempVariableAssignments
642 =
new Dictionary<string, Instruction>();
644 foreach (Instruction scriptInstruction
in executable.InstructionsInternal)
648 && IsTemporaryVariable(scriptInstruction.
First))
650 dictTempVariableAssignments[scriptInstruction.
First.
Value.ToString()]
654 Operand operandDest = scriptInstruction.
First;
655 if (operandDest ==
null)
continue;
656 if (opcode !=
OpCode.MOV && IsTemporaryVariable(operandDest))
657 dictTempVariableAssignments.Remove(
658 operandDest.
Value.ToString());
661 && IsTemporaryVariable(operandDest.
Value.ToString()))
662 dictTempVariableAssignments.Remove(
663 operandDest.
Value.ToString());
665 && IsTemporaryVariable(operandDest.
Pointer))
666 dictTempVariableAssignments.Remove(
668 Operand operandSource = scriptInstruction.
Second;
669 if (operandSource ==
null)
continue;
670 switch (operandSource.
Type)
675 if (IsTemporaryVariable(operandSource.
Value.ToString()))
676 dictTempVariableAssignments.Remove(
677 operandSource.
Value.ToString());
680 if (IsTemporaryVariable(operandSource.
Value.ToString()))
681 dictTempVariableAssignments.Remove(
682 operandSource.
Value.ToString());
683 if (IsTemporaryVariable(operandSource.
Pointer))
684 dictTempVariableAssignments.Remove(
689 foreach (Instruction scriptInstruction
690 in dictTempVariableAssignments.Values)
694 scriptInstruction.OpCode =
OpCode.NOP;
695 scriptInstruction.First =
null;
696 scriptInstruction.Second =
null;
699 if (dictTempVariableAssignments.Count > 0)
705 #region Public Methods
707 public Optimizer(Executable executable)
711 this.executable = executable;
715 public void Optimize()
718 List<Instruction> instructions = executable.InstructionsInternal;
726 for (
int i = 0; i < instructions.Count; i++)
729 if (Tripleinstruction(i))
730 OptimiseInstructionTriples(i);
732 if (DoubleInstruction(i))
733 OptimiseInstructionPairs(i);
735 OptimiseSingleInstructions(i);
742 EliminateUnusedTempVariables();
750 public bool OptimizerInfo
752 get {
return verbose; }
753 set { verbose = value; }
override string ToString()
Instruction InstructionPointer