/// <summary> /// Default ctor /// </summary> public RLRange(RLRange prefix, Instruction first, Instruction last, RegisterSpec resultRegister) { if ((prefix != null) && (prefix.first != null)) first = prefix.first; if ((last == null) && (prefix != null)) last = prefix.last; this.first = first; this.last = last; this.resultRegister = resultRegister; }
/// <summary> /// Default ctor /// </summary> public RLRange(RLRange prefix, Instruction first, Instruction last, RegisterSpec resultRegister) { if ((prefix != null) && (prefix.first != null)) { first = prefix.first; } if ((last == null) && (prefix != null)) { last = prefix.last; } this.first = first; this.last = last; this.resultRegister = resultRegister; }
/// <summary> /// Single instruction range ctor /// </summary> public RLRange(RLRange prefix, Instruction single, RegisterSpec resultRegister) : this(prefix, single, single, resultRegister) { }
/// <summary> /// No code, register only ctor /// </summary> public RLRange(RLRange prefix, RegisterSpec resultRegister) : this(prefix, null, null, resultRegister) { }
/// <summary> /// Create a conversion to int code sequence. /// </summary> private RLRange ConvToInt(ISourceLocation sequencePoint, RLRange arg) { RegisterSpec r; if (!arg.Result.IsWide) { // Float? if (arg.Result.Type.IsFloat()) { r = frame.AllocateTemp(PrimitiveType.Int); return new RLRange(this.Add(sequencePoint, RCode.Float_to_int, r, arg.Result), r); } return arg; } else { // Long/double -> int r = frame.AllocateTemp(PrimitiveType.Int); var code = (arg.Result.Type.IsDouble()) ? RCode.Double_to_int : RCode.Long_to_int; return new RLRange(this.Add(sequencePoint, code, r, arg.Result), r); } }
/// <summary> /// Create a conversion code sequence. /// </summary> private RLRange ConvX(ISourceLocation sequencePoint, RCode code, PrimitiveType type, RLRange arg) { if (code == RCode.Nop) return new RLRange(this.Add(sequencePoint, code), arg.Result); var r = frame.AllocateTemp(type); return new RLRange(this.Add(sequencePoint, code, r, arg.Result), r); }
/// <summary> /// Generate code for a call to a method of an array type. /// </summary> private bool TryVisitArrayTypeMethodCallExpression(AstExpression node, XMethodReference ilMethodRef, List<RLRange> args, AstNode parent, out RLRange result) { var methodName = ilMethodRef.Name; var dimensions = (methodName == "Set") ? args.Count - 2 : args.Count - 1; // Get all but last dimensions var arr = frame.AllocateTemp(FrameworkReferences.Object); var first = this.Add(node.SourceLocation, RCode.Move_object, arr, args[0].Result); for (var d = 0; d < dimensions - 1; d++) { this.Add(node.SourceLocation, RCode.Aget_object, arr, arr, args[d + 1].Result); } // Get/Set value switch (methodName) { case "Get": { var valueType = node.GetResultType(); var lastIndexArg = args[args.Count - 1]; var agetCode = new XArrayType(valueType).AGet(); var resultReg = frame.AllocateTemp(valueType.GetReference(targetPackage)); var last = this.Add(node.SourceLocation, agetCode, resultReg, arr, lastIndexArg.Result); result = new RLRange(first, last, resultReg); return true; } case "Set": { var valueType = node.Arguments[node.Arguments.Count - 1].GetResultType(); var lastIndexArg = args[args.Count - 2]; var aputCode = new XArrayType(valueType).APut(); // Perform type conversion if needed bool isConverted; var valueR = args[args.Count - 1].Result; var converted = this.ConvertTypeBeforeStore(node.SourceLocation, valueType, valueType, valueR, targetPackage, frame, compiler, out isConverted); if (isConverted) valueR = converted.Result; var last = this.Add(node.SourceLocation, aputCode, valueR, arr, lastIndexArg.Result); result = new RLRange(first, last, arr); return true; } default: result = null; return false; } }
/// <summary> /// Apply type/content conversion of arguments just before a method call. /// </summary> private void ConvertParametersBeforeCall(AstExpression node, List<RLRange> args, XMethodReference targetMethod, out int argsOffset, out List<RLRange> originalArgs) { // Convert parameters when needed argsOffset = (args.Count - targetMethod.Parameters.Count) - node.GenericInstanceArgCount; originalArgs = args.ToList(); for (var i = 0; i < targetMethod.Parameters.Count; i++) { var parameterType = targetMethod.Parameters[i].ParameterType; if (parameterType.IsByte()) { // Convert from byte to sbyte var rArg = args[argsOffset + i].Result.Register; this.Add(node.SourceLocation, RCode.Int_to_byte, rArg, rArg); } else if (parameterType.IsUInt16()) { // Convert from ushort to short var rArg = args[argsOffset + i].Result.Register; this.Add(node.SourceLocation, RCode.Int_to_short, rArg, rArg); } else { var nodeArgI = node.Arguments[argsOffset + i]; var nodeArgIType = nodeArgI.GetResultType(); var originalArg = args[argsOffset + i]; var rx = originalArg.Result; if ((parameterType.IsGenericParameter) && (nodeArgIType.IsPrimitive)) { // Convert using (valueOf) var tmp = this.Box(node.SourceLocation, rx, nodeArgIType, targetPackage, frame); args[argsOffset + i] = new RLRange(originalArg.First, originalArg.Last, tmp.Result); } else if ((parameterType.IsGenericParameterArray()) && nodeArgIType.IsPrimitiveArray()) { // Convert using Boxing class var tmp = this.BoxGenericArray(node.SourceLocation, rx, nodeArgIType, targetPackage, frame, compiler); args[argsOffset + i] = new RLRange(originalArg.First, originalArg.Last, tmp.Result); } else { bool isConverted; var tmp = this.ConvertTypeBeforeStore(node.SourceLocation, nodeArgIType, parameterType, rx, targetPackage, frame, compiler, out isConverted); if (isConverted) { args[argsOffset + i] = new RLRange(originalArg.First, originalArg.Last, tmp.Result); } } } } }