public void Import(Instruction instruction, ImportContext context, IILImporterProxy importer) { var fallthroughBlock = context.FallThroughBlock; var op1 = importer.PopExpression(); var targets = instruction.Operand as Instruction[]; var jumpTable = new List <string>(targets?.Length ?? 0); if (targets != null) { foreach (var target in targets) { var targetBlock = importer.BasicBlocks[(int)target.Offset]; jumpTable.Add(targetBlock.Label); importer.ImportFallThrough(targetBlock); } } var switchNode = new SwitchEntry(op1, jumpTable); importer.ImportAppendTree(switchNode); // TODO: Can this ever be null? if (fallthroughBlock != null) { importer.ImportFallThrough(fallthroughBlock); } context.StopImporting = true; }
public void Import(Instruction instruction, ImportContext context, IILImporterProxy importer) { var fieldDef = instruction.OperandAs <FieldDef>(); var value = importer.PopExpression(); var addr = importer.PopExpression(); var kind = fieldDef.FieldType.GetStackValueKind(); if (value.Kind != StackValueKind.Int32 && value.Kind != StackValueKind.ValueType && value.Kind != StackValueKind.NativeInt) { throw new NotSupportedException($"Storing to field of type {value.Kind} not supported"); } // Ensure fields have all offsets calculated if (fieldDef.FieldOffset == null) { fieldDef.DeclaringType.ToTypeSig().GetExactSize(); } // TODO: Can this be removed var fieldSize = fieldDef.FieldType.GetExactSize(); var fieldOffset = fieldDef.FieldOffset ?? 0; importer.ImportAppendTree(new StoreIndEntry(addr, value, WellKnownType.Int32, fieldOffset, fieldSize)); }
public void Import(Instruction instruction, ImportContext context, IILImporterProxy importer) { var retNode = new ReturnEntry(); if (context.Method.HasReturnType) { var returnType = context.Method.ReturnType; var value = importer.PopExpression(); if (returnType.IsStruct()) { // Record return buffer argument index // so that code gen can generate code to // copy struct on top of stack to the // return buffer. retNode.ReturnBufferArgIndex = context.Method.HasThis ? 1 : 0; retNode.ReturnTypeExactSize = returnType.GetExactSize(); } else if (value.Kind != StackValueKind.Int32) { throw new NotSupportedException($"Unsupported Return type {value.Kind}"); } retNode.Return = value; } importer.ImportAppendTree(retNode); context.StopImporting = true; }
public void Import(Instruction instruction, ImportContext context, IILImporterProxy importer) { var op2 = importer.PopExpression(); if (op2.Kind != StackValueKind.Int32) { throw new NotSupportedException("Boolean comparisons only supported using int as underlying type"); } StackEntry op1; Operation op = Operation.Eq; switch (instruction.OpCode.Code) { case Code.Cgt: op = Operation.Gt; break; case Code.Cgt_Un: op = Operation.Gt; break; case Code.Clt: op = Operation.Lt; break; case Code.Clt_Un: op = Operation.Lt; break; } op1 = importer.PopExpression(); if (op2.Kind != StackValueKind.Int32) { throw new NotSupportedException("Boolean comparisons only supported using int as underlying type"); } op1 = new BinaryOperator(op, isComparison: true, op1, op2, StackValueKind.Int32); importer.PushExpression(op1); }
public void Import(Instruction instruction, ImportContext context, IILImporterProxy importer) { var op1 = importer.PopExpression(); var op2 = op1.Duplicate(); importer.PushExpression(op1); importer.PushExpression(op2); }
public void Import(Instruction instruction, ImportContext context, IILImporterProxy importer) { var type = GetWellKnownType(instruction.OpCode.Code); var addr = importer.PopExpression(); // TODO: Can this be optimised for I1 & I2?? var node = new IndirectEntry(addr, StackValueKind.Int32, null); // type.GetWellKnownTypeSize()); importer.PushExpression(node); }
public void Import(Instruction instruction, ImportContext context, IILImporterProxy importer) { int index = GetIndex(instruction); var localNumber = importer.ParameterCount + index; var localVariable = importer.LocalVariableTable[localNumber]; var node = new LocalVariableEntry(localNumber, localVariable.Kind, localVariable.ExactSize); importer.PushExpression(node); }
public void Import(Instruction instruction, ImportContext context, IILImporterProxy importer) { var index = GetIndex(instruction); var lclNum = MapIlArgNum(index, importer.ReturnBufferArgIndex); var argument = importer.LocalVariableTable[lclNum]; var node = new LocalVariableEntry(lclNum, argument.Kind, argument.ExactSize); importer.PushExpression(node); }
public void Import(Instruction instruction, ImportContext context, IILImporterProxy importer) { var op1 = importer.PopExpression(); // Need to spill result removed from stack to a temp that will never be used var lclNum = importer.GrabTemp(op1.Kind, op1.ExactSize); var node = new StoreLocalVariableEntry(lclNum, false, op1); // ctor has no return type so just append the tree importer.ImportAppendTree(node); }
public void Import(Instruction instruction, ImportContext context, IILImporterProxy importer) { var value = importer.PopExpression(); if (value.Kind != StackValueKind.Int32 && value.Kind != StackValueKind.ObjRef) { throw new NotSupportedException("Storing to argument other than short, int32 or object refs not supported yet"); } var node = new StoreLocalVariableEntry((instruction.OperandAs <Parameter>()).Index, true, value); importer.ImportAppendTree(node); }
public void Import(Instruction instruction, ImportContext context, IILImporterProxy importer) { int index = GetIndex(instruction); var value = importer.PopExpression(); if (value.Kind != StackValueKind.Int32 && value.Kind != StackValueKind.ObjRef && value.Kind != StackValueKind.ValueType && value.Kind != StackValueKind.NativeInt) { throw new NotSupportedException("Storing variables other than short, int32 ,object refs, or valuetypes not supported yet"); } var localNumber = importer.ParameterCount + index; var node = new StoreLocalVariableEntry(localNumber, false, value); importer.ImportAppendTree(node, true); }
public void Import(Instruction instruction, ImportContext context, IILImporterProxy importer) { var value = importer.PopExpression(); var addr = importer.PopExpression(); if (value.Kind != StackValueKind.Int32) { throw new NotSupportedException(); } // TODO: Can this be optimised to copy less data if Stind_I1, Stind_I2??? WellKnownType type = WellKnownType.Int32; int exactSize = type.GetWellKnownTypeSize(); importer.ImportAppendTree(new StoreIndEntry(addr, value, type, fieldOffset: 0, exactSize)); }
public void Import(Instruction instruction, ImportContext context, IILImporterProxy importer) { var fieldDefOrRef = instruction.Operand as IField; var fieldDef = fieldDefOrRef.ResolveFieldDef(); // Ensure fields have all offsets calculated if (fieldDef.FieldOffset == null) { fieldDef.DeclaringType.ToTypeSig().GetExactSize(); } var fieldOffset = fieldDef.FieldOffset ?? 0; var obj = importer.PopExpression(); if (obj.Kind == StackValueKind.ValueType) { if (obj is LocalVariableEntry) { obj = new LocalVariableAddressEntry((obj.As <LocalVariableEntry>()).LocalNumber); } else if (obj is IndirectEntry) { // If the object is itself an IndirectEntry e.g. resulting from a Ldfld // then we should merge the Ldfld's together // e.g. Ldfld SimpleVector::N // Ldfld Nested::Length // will get converted into a single IndirectEntry node with the field offset // being the combination of the field offsets for N and Length var previousIndirect = obj.As <IndirectEntry>(); fieldOffset = previousIndirect.Offset + fieldOffset; obj = previousIndirect.Op1; } } if (obj.Kind != StackValueKind.ObjRef && obj.Kind != StackValueKind.ByRef && obj.Kind != StackValueKind.NativeInt) { throw new NotImplementedException($"LoadFieldImporter does not support {obj.Kind}"); } var kind = fieldDef.FieldType.GetStackValueKind(); var node = new IndirectEntry(obj, kind, fieldDef.FieldType.GetExactSize(), fieldOffset); importer.PushExpression(node); }
public void Import(Instruction instruction, ImportContext context, IILImporterProxy importer) { var fieldDefOrRef = instruction.Operand as IField; var fieldDef = fieldDefOrRef.ResolveFieldDef(); var obj = importer.PopExpression(); if (obj.Kind != StackValueKind.ObjRef && obj.Kind != StackValueKind.ByRef) { throw new NotImplementedException($"LoadFieldImporter does not support {obj.Kind}"); } var node = new FieldAddressEntry(fieldDef.Name, obj, fieldDef?.FieldOffset ?? 0); importer.PushExpression(node); }
public void Import(Instruction instruction, ImportContext context, IILImporterProxy importer) { var op2 = importer.PopExpression(); var op1 = importer.PopExpression(); // If one of the values is a native int then cast the other to be native int too if (op1.Kind == StackValueKind.NativeInt && op2.Kind == StackValueKind.Int32) { op2 = new CastEntry(Common.TypeSystem.WellKnownType.Object, op2, op1.Kind); } else if (op1.Kind == StackValueKind.Int32 && op2.Kind == StackValueKind.NativeInt) { op1 = new CastEntry(Common.TypeSystem.WellKnownType.Object, op1, op2.Kind); } // StackValueKind is carefully ordered to make this work StackValueKind kind; kind = op1.Kind > op2.Kind ? op1.Kind : op2.Kind; if (kind != StackValueKind.Int32 && kind != StackValueKind.NativeInt) { throw new NotSupportedException($"Binary operation on type {kind} not supported"); } Operation binaryOp; switch (instruction.OpCode.Code) { case Code.Mul_Ovf_Un: // For now this maps to standard multiplication as we have no exception support binaryOp = Operation.Mul; break; default: binaryOp = Operation.Add + (instruction.OpCode.Code - Code.Add); break; } var binaryExpr = new BinaryOperator(binaryOp, isComparison: false, op1, op2, kind); importer.PushExpression(binaryExpr); }
public void Import(Instruction instruction, ImportContext context, IILImporterProxy importer) { var methodDefOrRef = instruction.Operand as IMethodDefOrRef; var methodToCall = methodDefOrRef.ResolveMethodDefThrow(); var declType = methodToCall.DeclaringType; var objType = declType.ToTypeSig(); var objKind = objType.GetStackValueKind(); var objSize = objType.GetExactSize(); if (declType.IsValueType) { // Allocate memory on the stack for the value type as a temp local variable var lclNum = importer.GrabTemp(objKind, objSize); var newObjThisPtr = new LocalVariableAddressEntry(lclNum); // Call the valuetype constructor CallImporter.ImportCall(instruction, context, importer, newObjThisPtr); var node = new LocalVariableEntry(lclNum, objKind, objSize); importer.PushExpression(node); } else { // Allocate memory for object var op1 = new AllocObjEntry((int)declType.ClassSize, objKind); // Store allocated memory address into a temp local variable var lclNum = importer.GrabTemp(objKind, objSize); var asg = new StoreLocalVariableEntry(lclNum, false, op1); importer.ImportAppendTree(asg); // Call the constructor var newObjThisPtr = new LocalVariableEntry(lclNum, objKind, objSize); CallImporter.ImportCall(instruction, context, importer, newObjThisPtr); // Push a local variable entry corresponding to the object here var node = new LocalVariableEntry(lclNum, objKind, objSize); importer.PushExpression(node); } }
public void Import(Instruction instruction, ImportContext context, IILImporterProxy importer) { var op2 = importer.PopExpression(); var op1 = importer.PopExpression(); // operand to be shifted if (op1.Kind != StackValueKind.Int32 && op1.Kind != StackValueKind.NativeInt) { throw new NotSupportedException($"Shift operation on type {op1.Kind} not supported"); } if (op2.Kind != StackValueKind.Int32 && op2.Kind != StackValueKind.NativeInt) { throw new NotSupportedException($"Shift operation with amount of type {op2.Kind} not supported"); } var shiftOp = Operation.Lsh + (instruction.OpCode.Code - Code.Shl); var binaryExpr = new BinaryOperator(shiftOp, isComparison: false, op1, op2, op1.Kind); importer.PushExpression(binaryExpr); }
public void Import(Instruction instruction, ImportContext context, IILImporterProxy importer) { var op2 = importer.PopExpression().As <Int32ConstantEntry>(); if (op2.Kind != StackValueKind.Int32) { throw new NotSupportedException("Localloc requires int size"); } var allocSize = op2.Value; // Ensure we don't allocate less than each stack entry size allocSize = RoundUp(allocSize, 4); // TODO: Is Unknown the right kind to use?? var lclNum = importer.GrabTemp(StackValueKind.Unknown, allocSize); var op1 = new LocalVariableAddressEntry(lclNum); importer.PushExpression(op1); }
public void Import(Instruction instruction, ImportContext context, IILImporterProxy importer) { WellKnownType wellKnownType; switch (instruction.OpCode.Code) { case Code.Conv_I4: wellKnownType = WellKnownType.Int32; break; case Code.Conv_U4: wellKnownType = WellKnownType.UInt32; break; case Code.Conv_I2: wellKnownType = WellKnownType.Int16; break; case Code.Conv_U2: wellKnownType = WellKnownType.UInt16; break; case Code.Conv_I1: wellKnownType = WellKnownType.SByte; break; case Code.Conv_U1: wellKnownType = WellKnownType.Byte; break; case Code.Conv_U: wellKnownType = WellKnownType.UIntPtr; break; case Code.Conv_I: wellKnownType = WellKnownType.IntPtr; break; default: throw new NotImplementedException($"Conversion type not supported for opcode {instruction.OpCode.Code}"); } var op1 = importer.PopExpression(); // Work out if a cast is required if ((op1.Kind == StackValueKind.Int32 && wellKnownType == Common.TypeSystem.WellKnownType.UInt16) || (op1.Kind == StackValueKind.Int32 && wellKnownType == Common.TypeSystem.WellKnownType.Int16) || (op1.Kind == StackValueKind.Int32 && wellKnownType == WellKnownType.Byte) || (op1.Kind == StackValueKind.Int32 && wellKnownType == WellKnownType.SByte)) { op1 = new CastEntry(wellKnownType, op1, op1.Kind); } importer.PushExpression(op1); }
public void Import(Instruction instruction, ImportContext context, IILImporterProxy importer) { importer.PushExpression(new LocalVariableAddressEntry(importer.ParameterCount + (instruction.OperandAs <Local>()).Index)); }
public void Import(Instruction instruction, ImportContext context, IILImporterProxy importer) { // TODO: Need to implement this importer.PopExpression(); }
public void Import(Instruction instruction, ImportContext context, IILImporterProxy importer) { importer.PushExpression(new Int32ConstantEntry(checked ((int)GetValue(instruction)))); }
private static bool ImportIntrinsicCall(MethodDef methodToCall, IList <StackEntry> arguments, IILImporterProxy importer) { // Not yet implemented methods with non void return type if (methodToCall.HasReturnType) { throw new NotSupportedException(); } // Map method name to string that code generator will understand var targetMethodName = ""; switch (methodToCall.Name) { // TODO: Suspect this won't stay as an intrinsic but at least we have the mechanism for instrincs case "Write": if (IsTypeName(methodToCall, "System", "Console")) { var argtype = methodToCall.Parameters[0].Type; targetMethodName = argtype.FullName switch { "System.String" => "WriteString", "System.Int32" => "WriteInt32", "System.UInt32" => "WriteUInt32", "System.Char" => "WriteChar", _ => throw new NotSupportedException(), }; } break; default: return(false); } var callNode = new IntrinsicEntry(targetMethodName, arguments, StackValueKind.Unknown); importer.ImportAppendTree(callNode); return(true); }
public static void ImportCall(Instruction instruction, ImportContext context, IILImporterProxy importer, StackEntry?newObjThis = null) { var methodDefOrRef = instruction.Operand as IMethodDefOrRef; var methodToCall = methodDefOrRef.ResolveMethodDefThrow(); var arguments = new List <StackEntry>(); var firstArgIndex = newObjThis != null ? 1 : 0; for (var i = firstArgIndex; i < methodToCall.Parameters.Count; i++) { var argument = importer.PopExpression(); arguments.Add(argument); } // Add the this pointer if required, e.g. if part of newobj if (newObjThis != null) { arguments.Add(newObjThis); } arguments.Reverse(); // Intrinsic calls if (methodToCall.IsIntrinsic()) { if (!ImportIntrinsicCall(methodToCall, arguments, importer)) { throw new NotSupportedException("Unknown intrinsic"); } return; } string targetMethod; if (methodToCall.IsPinvokeImpl) { targetMethod = methodToCall.ImplMap.Name; } else { targetMethod = context.NameMangler.GetMangledMethodName(methodToCall); } int returnBufferArgIndex = 0; var returnType = methodToCall.ReturnType; if (methodToCall.HasReturnType) { if (returnType.IsStruct()) { returnBufferArgIndex = FixupCallStructReturn(returnType, arguments, importer, methodToCall.HasThis); } } int?returnTypeSize = methodToCall.HasReturnType ? returnType.GetExactSize() : null; var callNode = new CallEntry(targetMethod, arguments, returnType.GetStackValueKind(), returnTypeSize); if (!methodToCall.HasReturnType) { importer.ImportAppendTree(callNode); } else { if (returnType.IsStruct()) { importer.ImportAppendTree(callNode); // Load return buffer to stack var loadTemp = new LocalVariableEntry(returnBufferArgIndex, returnType.GetStackValueKind(), returnType.GetExactSize()); importer.PushExpression(loadTemp); } else { importer.PushExpression(callNode); } } }
public void Import(Instruction instruction, ImportContext context, IILImporterProxy importer) { importer.PushExpression(new StringConstantEntry(instruction.OperandAs <string>())); }
public void Import(Instruction instruction, ImportContext context, IILImporterProxy importer) { var unaryOp = Operation.Neg + (instruction.OpCode.Code - Code.Neg); importer.PushExpression(new UnaryOperator(unaryOp, importer.PopExpression())); }
public void Import(Instruction instruction, ImportContext context, IILImporterProxy importer) { var code = instruction.OpCode.Code; switch (code) { case Code.Br_S: case Code.Blt_S: case Code.Bgt_S: case Code.Ble_S: case Code.Bge_S: case Code.Beq_S: case Code.Bne_Un_S: case Code.Brfalse_S: case Code.Brtrue_S: code += (Code.Br - Code.Br_S); break; } var target = instruction.OperandAs <Instruction>(); var targetBlock = importer.BasicBlocks[(int)target.Offset]; var fallthroughBlock = (code != Code.Br) ? context.FallThroughBlock : null; if (code != Code.Br) { var op2 = importer.PopExpression(); if (op2.Kind != StackValueKind.Int32 && op2.Kind != StackValueKind.NativeInt) { throw new NotSupportedException("Boolean comparisons only supported using int and nativeint as underlying type"); } StackEntry op1; Operation op; if (code != Code.Brfalse && code != Code.Brtrue) { op1 = importer.PopExpression(); op = Operation.Eq + (code - Code.Beq); // If one of the values is a native int then cast the other to be native int too if (op1.Kind == StackValueKind.NativeInt && op2.Kind == StackValueKind.Int32) { op2 = new CastEntry(Common.TypeSystem.WellKnownType.Object, op2, op1.Kind); } else if (op1.Kind == StackValueKind.Int32 && op2.Kind == StackValueKind.NativeInt) { op1 = new CastEntry(Common.TypeSystem.WellKnownType.Object, op1, op2.Kind); } } else { op1 = new Int32ConstantEntry(0); op = (code == Code.Brfalse) ? Operation.Eq : Operation.Ne; } op1 = new BinaryOperator(op, isComparison: true, op1, op2, op1.Kind); importer.ImportAppendTree(new JumpTrueEntry(targetBlock.Label, op1)); } else { importer.ImportAppendTree(new JumpEntry(targetBlock.Label)); } // Fall through handling importer.ImportFallThrough(targetBlock); if (fallthroughBlock != null) { importer.ImportFallThrough(fallthroughBlock); } context.StopImporting = true; }
public void Import(Instruction instruction, ImportContext context, IILImporterProxy importer) { ImportCall(instruction, context, importer); }
static private int FixupCallStructReturn(TypeSig returnType, List <StackEntry> arguments, IILImporterProxy importer, bool hasThis) { // Create temp var lclNum = importer.GrabTemp(returnType.GetStackValueKind(), returnType.GetExactSize()); var returnBufferPtr = new LocalVariableAddressEntry(lclNum); // Ensure return buffer parameter goes after the this parameter if present var returnBufferArgPos = hasThis ? 1 : 0; arguments.Insert(returnBufferArgPos, returnBufferPtr); return(lclNum); }
public void Import(Instruction instruction, ImportContext context, IILImporterProxy importer) { // Nothing to do }