private static IILArgumentsProvider BuildPushrExpression(ILInstruction instruction, ILCompilationUnit result) { // Since we treat registers as variables, we should interpret the operand as a variable and add it // as an argument to the expression instead of keeping it just as an operand. This makes it easier // to apply analysis and transformations (such as variable inlining) later, in the same way we do // that with normal variables. IILArgumentsProvider expression = new ILInstructionExpression(instruction); ILVariable registerVar; if (instruction.Operand is VMRegisters.FL) { var dataSources = instruction.ProgramState.Registers[VMRegisters.FL].DataSources .Select(i => i.Offset) .ToArray(); var flagsVariable = result.GetOrCreateFlagsVariable(dataSources); registerVar = flagsVariable; } else { registerVar = result.GetOrCreateVariable(instruction.Operand.ToString()); } var varExpression = new ILVariableExpression(registerVar); expression.Arguments.Add(varExpression); return(expression); }
private static ILStatement BuildPopStatement(ILCompilationUnit result, ILInstruction instruction, ILExpression expression) { // Since we treat registers as variables, we should treat POP instructions as assignment // statements instead of a normal ILExpressionStatement. This makes it easier to apply // analysis and transformations (such as variable inlining) later, in the same way we do // that with normal variables. var register = (VMRegisters)instruction.Operand; // Get the variable associated to the register. FL registers need special care, as they // are used in various optimisation stages. var registerVar = register == VMRegisters.FL ? result.GetOrCreateFlagsVariable(new[] { instruction.Offset }) : result.GetOrCreateVariable(register.ToString()); var value = (ILExpression)((IILArgumentsProvider)expression).Arguments[0].Remove(); return(new ILAssignmentStatement(registerVar, value)); }
private ILExpression BuildExpression(ILInstruction instruction, ILCompilationUnit result) { IILArgumentsProvider expression; switch (instruction.OpCode.Code) { case ILCode.VCALL: expression = new ILVCallExpression((VCallAnnotation)instruction.Annotation); break; case ILCode.PUSHR_BYTE: case ILCode.PUSHR_WORD: case ILCode.PUSHR_DWORD: case ILCode.PUSHR_QWORD: case ILCode.PUSHR_OBJECT: // Since we treat registers as variables, we should interpret the operand as a variable and add it // as an argument to the expression instead of keeping it just as an operand. This makes it easier // to apply analysis and transformations (such as variable inlining) later, in the same way we do // that with normal variables. expression = new ILInstructionExpression(instruction); ILVariable registerVar; if (instruction.Operand is VMRegisters.FL) { var dataSources = instruction.ProgramState.Registers[VMRegisters.FL].DataSources .Select(i => i.Offset) .ToArray(); var flagsVariable = result.GetOrCreateFlagsVariable(dataSources); registerVar = flagsVariable; } else { registerVar = result.GetOrCreateVariable(instruction.Operand.ToString()); } var varExpression = new ILVariableExpression(registerVar); expression.Arguments.Add(varExpression); break; default: expression = new ILInstructionExpression(instruction); break; } for (int i = 0; i < instruction.Dependencies.Count; i++) { ILExpression argument; var firstDataSource = instruction.Dependencies[i].DataSources.First(); if (firstDataSource.Offset == InstructionProcessor.PushExceptionOffset) { var exceptionType = (ITypeDefOrRef)firstDataSource.Operand; argument = new ILExceptionExpression(exceptionType); } else { // Get the variable containing the value of the argument and add it as an argument to the expression. string variableName = GetOperandVariableName(instruction, i); if (_sharedVariables.TryGetValue(variableName, out string realName)) { variableName = realName; } argument = new ILVariableExpression( result.GetOrCreateVariable(variableName)); } expression.Arguments.Add(argument); } return((ILExpression)expression); }