private bool TryGenerateCode(ILInstruction instruction) { switch (instruction.InstructionType) { case ILInstructionType.Nop: MakeNop(); return(true); case ILInstructionType.Break: MakeTrap(); return(true); case ILInstructionType.LdToken: MakeLoadToken(instruction.Argument); return(true); case ILInstructionType.Ldarg: { var index = instruction.GetArgumentAs <int>() - LambdaArgumentOffset; if (index >= 0) { LoadVariable( new VariableRef( index, VariableRefType.Argument)); } } return(true); case ILInstructionType.Ldarga: { var index = instruction.GetArgumentAs <int>() - LambdaArgumentOffset; if (index >= 0) { LoadVariableAddress( new VariableRef( index, VariableRefType.Argument)); } } return(true); case ILInstructionType.Starg: { var index = instruction.GetArgumentAs <int>() - LambdaArgumentOffset; if (index >= 0) { StoreVariable( new VariableRef( index, VariableRefType.Argument)); } } return(true); case ILInstructionType.Ldloc: LoadVariable( new VariableRef( instruction.GetArgumentAs <int>(), VariableRefType.Local)); return(true); case ILInstructionType.Ldloca: LoadVariableAddress( new VariableRef( instruction.GetArgumentAs <int>(), VariableRefType.Local)); return(true); case ILInstructionType.Stloc: StoreVariable( new VariableRef( instruction.GetArgumentAs <int>(), VariableRefType.Local)); return(true); case ILInstructionType.LdI4: Load(instruction.GetArgumentAs <int>()); return(true); case ILInstructionType.LdI8: Load(instruction.GetArgumentAs <long>()); return(true); case ILInstructionType.LdR4: Load(instruction.GetArgumentAs <float>()); return(true); case ILInstructionType.LdR8: Load(instruction.GetArgumentAs <double>()); return(true); case ILInstructionType.Ldstr: LoadString(instruction.GetArgumentAs <string>()); return(true); case ILInstructionType.Dup: MakeDup(); return(true); case ILInstructionType.Pop: MakePop(); return(true); case ILInstructionType.Ret: MakeReturn(); return(true); case ILInstructionType.Call: MakeCall(instruction.GetArgumentAs <MethodBase>()); return(true); case ILInstructionType.Callvirt: MakeVirtualCall(instruction); return(true); case ILInstructionType.Calli: MakeCalli(instruction.Argument); return(true); case ILInstructionType.Jmp: MakeJump(instruction.GetArgumentAs <MethodBase>()); return(true); case ILInstructionType.Box: MakeBox(); return(true); case ILInstructionType.Unbox: MakeUnbox(instruction.GetArgumentAs <Type>()); return(true); case ILInstructionType.Br: MakeBranch(); return(true); case ILInstructionType.Brfalse: MakeBranchFalse(); return(true); case ILInstructionType.Brtrue: MakeBranchTrue(); return(true); case ILInstructionType.Beq: MakeBranch(CompareKind.Equal, instruction.Flags); return(true); case ILInstructionType.Bne: MakeBranch(CompareKind.NotEqual, instruction.Flags); return(true); case ILInstructionType.Bge: MakeBranch(CompareKind.GreaterEqual, instruction.Flags); return(true); case ILInstructionType.Bgt: MakeBranch(CompareKind.GreaterThan, instruction.Flags); return(true); case ILInstructionType.Ble: MakeBranch(CompareKind.LessEqual, instruction.Flags); return(true); case ILInstructionType.Blt: MakeBranch(CompareKind.LessThan, instruction.Flags); return(true); case ILInstructionType.Switch: MakeSwitch(instruction.GetArgumentAs <ILInstructionBranchTargets>()); return(true); case ILInstructionType.Add: MakeArithmetic(BinaryArithmeticKind.Add, instruction); return(true); case ILInstructionType.Sub: MakeArithmetic(BinaryArithmeticKind.Sub, instruction); return(true); case ILInstructionType.Mul: MakeArithmetic(BinaryArithmeticKind.Mul, instruction); return(true); case ILInstructionType.Div: MakeArithmetic(BinaryArithmeticKind.Div, instruction); return(true); case ILInstructionType.Rem: MakeArithmetic(BinaryArithmeticKind.Rem, instruction); return(true); case ILInstructionType.And: MakeArithmetic(BinaryArithmeticKind.And, instruction); return(true); case ILInstructionType.Or: MakeArithmetic(BinaryArithmeticKind.Or, instruction); return(true); case ILInstructionType.Xor: MakeArithmetic(BinaryArithmeticKind.Xor, instruction); return(true); case ILInstructionType.Shl: MakeArithmetic(BinaryArithmeticKind.Shl, instruction); return(true); case ILInstructionType.Shr: MakeArithmetic(BinaryArithmeticKind.Shr, instruction); return(true); case ILInstructionType.Neg: MakeArithmetic(UnaryArithmeticKind.Neg); return(true); case ILInstructionType.Not: MakeArithmetic(UnaryArithmeticKind.Not); return(true); case ILInstructionType.Conv: MakeConvert(instruction.GetArgumentAs <Type>(), instruction.Flags); return(true); case ILInstructionType.Initobj: MakeInitObject(instruction.GetArgumentAs <Type>()); return(true); case ILInstructionType.Newobj: MakeNewObject(instruction.GetArgumentAs <MethodBase>()); return(true); case ILInstructionType.Isinst: MakeIsInstance(instruction.GetArgumentAs <Type>()); return(true); case ILInstructionType.Ldfld: MakeLoadField(instruction.GetArgumentAs <FieldInfo>()); return(true); case ILInstructionType.Ldsfld: MakeLoadStaticField(instruction.GetArgumentAs <FieldInfo>()); return(true); case ILInstructionType.Ldflda: MakeLoadFieldAddress(instruction.GetArgumentAs <FieldInfo>()); return(true); case ILInstructionType.Ldsflda: MakeLoadStaticFieldAddress(instruction.GetArgumentAs <FieldInfo>()); return(true); case ILInstructionType.Stfld: MakeStoreField(instruction.GetArgumentAs <FieldInfo>()); return(true); case ILInstructionType.Stsfld: MakeStoreStaticField(instruction.GetArgumentAs <FieldInfo>()); return(true); case ILInstructionType.Ceq: MakeCompare(CompareKind.Equal, instruction.Flags); return(true); case ILInstructionType.Cgt: MakeCompare(CompareKind.GreaterThan, instruction.Flags); return(true); case ILInstructionType.Clt: MakeCompare(CompareKind.LessThan, instruction.Flags); return(true); case ILInstructionType.Ldobj: case ILInstructionType.Ldind: MakeLoadObject(instruction.GetArgumentAs <Type>()); return(true); case ILInstructionType.Stobj: case ILInstructionType.Stind: MakeStoreObject(instruction.GetArgumentAs <Type>()); return(true); case ILInstructionType.Newarr: MakeNewArray(instruction.GetArgumentAs <Type>()); return(true); case ILInstructionType.Ldelem: MakeLoadElement(instruction.GetArgumentAs <Type>()); return(true); case ILInstructionType.Ldelema: MakeLoadElementAddress(instruction.GetArgumentAs <Type>()); return(true); case ILInstructionType.Stelem: MakeStoreElement(instruction.GetArgumentAs <Type>()); return(true); case ILInstructionType.Ldlen: MakeLoadArrayLength(); return(true); case ILInstructionType.SizeOf: LoadSizeOf(instruction.GetArgumentAs <Type>()); return(true); default: return(false); } }
/// <summary> /// Realizes an arithmetic operation. /// </summary> /// <param name="kind">The kind of the arithmetic operation.</param> /// <param name="instruction">The current IL instruction.</param> private void MakeArithmetic( BinaryArithmeticKind kind, ILInstruction instruction) { var arithmeticFlags = ArithmeticFlags.None; var convertFlags = ConvertFlags.None; if (instruction.HasFlags(ILInstructionFlags.Overflow)) { arithmeticFlags |= ArithmeticFlags.Overflow; } if (instruction.HasFlags(ILInstructionFlags.Unsigned)) { convertFlags |= ConvertFlags.TargetUnsigned; arithmeticFlags |= ArithmeticFlags.Unsigned; } ValueReference result = default; if (Block.PopArithmeticArgs( Location, convertFlags, out var left, out var right) == Block.ArithmeticOperandKind.Pointer) { // This is a pointer access bool isLeftPointer = left.Type.IsPointerType; if (!isLeftPointer) { Utilities.Swap(ref left, ref right); } // Check for raw combinations of two pointer values if ( !right.Type.IsPointerType && // Check whether this can be safely converted into a LEA value kind == BinaryArithmeticKind.Add) { // Check the size of the element type and devide the raw offset // by the element size to retrieve the actual element index. var elementType = left.Type.As <PointerType>(Location).ElementType; var elementSize = Builder.CreateSizeOf(Location, elementType); // Create the actual address computation var leaIndex = Builder.CreateArithmetic( Location, right, elementSize, BinaryArithmeticKind.Div); result = Builder.CreateLoadElementAddress( Location, left, leaIndex); } // Check whether this operation on pointer values can be converted // into a LEA instruction // FIXME: remove this code once we add additional LEA nodes else if ( kind == BinaryArithmeticKind.Add && right is BinaryArithmeticValue baseAddress && TryConvertIntoLoadElementAddress(left, baseAddress, out var lea)) { result = lea; } } if (!result.IsValid) { switch (kind) { case BinaryArithmeticKind.Shl: case BinaryArithmeticKind.Shr: // Convert right operand to 32bits right = CreateConversion( right, Builder.GetPrimitiveType(BasicValueType.Int32), convertFlags); break; } result = Builder.CreateArithmetic( Location, left, right, kind, arithmeticFlags); } Block.Push(result); }