public FunctionSignature(ParameterInfo[] parameters, Type returnType) { Contract.Requires(parameters != null); Contract.Requires(returnType != null); foreach (var parameter in parameters) { var parameterType = parameter.ParameterType; if (parameterType.IsByRef) { Contract.Assert(parameter.IsOut); outputs.Add(MRepr.FromCliType(parameterType.GetElementType())); } else { Contract.Assert(outputs.Count == 0); inputs.Add(MRepr.FromCliType(parameterType)); } } Contract.Assert(outputs.Count != 1); if (returnType != typeof(void)) { Contract.Assert(outputs.Count == 0); outputs.Add(MRepr.FromCliType(returnType)); } }
public override void VisitLiteral(Literal node) { using (BeginEmitStore(node.Target)) { MRepr sourceRepr; if (node.Value is double) { var targetType = node.Target.StaticRepr.Type; EmitLoadConstant((double)node.Value, targetType.Class); sourceRepr = new MRepr(targetType, MStructuralClass.Scalar); } else if (node.Value is string) { var str = (string)node.Value; if (str.Length == 1) { cil.LoadInt32((int)str[0]); sourceRepr = MClass.Char.ScalarRepr; } else { cil.LoadString(str); cil.Invoke(typeof(MStrings).GetMethod("FromString")); sourceRepr = MClass.Char.FullArrayRepr; } } else { throw new NotImplementedException("Literals of type " + node.Value.GetType()); } EmitConvert(sourceRepr, node.Target.StaticRepr); } }
public Variable(string name, MRepr staticRepr, bool initOnly) { Contract.Requires(name != null); this.Name = name; this.StaticRepr = staticRepr; this.IsInitOnly = initOnly; }
private static CoercionFlags?GetCoercion(FunctionMethod overload, ImmutableArray <MRepr> inputs) { var coercionFlags = CoercionFlags.None; for (int i = 0; i < inputs.Length; ++i) { MRepr provided = inputs[i]; MRepr expected = overload.Signature.Inputs[i]; if (provided == expected) { continue; } if (expected.IsAny) { coercionFlags |= CoercionFlags.ToAny; continue; } // Check structural class compatibility if (provided.StructuralClass != expected.StructuralClass) { // TODO: Check the subtyping relation of the structural classes if (expected.StructuralClass == MStructuralClass.Scalar) { return(null); } coercionFlags |= CoercionFlags.StructuralClassChange; } // Check complex attribute compatibility if (provided.IsComplex != expected.IsComplex) { if (provided.IsComplex) { return(null); // Complex to real } coercionFlags |= CoercionFlags.RealToComplex; } // Check class compatibility. if (provided.Class != expected.Class) { if (provided.Class.IsInteger && expected.Class.IsReal) { coercionFlags |= CoercionFlags.IntegerToFloat; } else { return(null); } } } return(coercionFlags); }
private void EmitIsTrue(MRepr conditionRepr) { if (conditionRepr.Type == MClass.Logical && conditionRepr.StructuralClass == MStructuralClass.Scalar) { return; } var isTrueFunction = pseudoBuiltins.Lookup("IsTrue", conditionRepr); EmitConvert(conditionRepr, isTrueFunction.Signature.Inputs[0]); cil.Invoke(isTrueFunction.Method); }
private void EmitColonRange(Variable arrayVariable, int dimensionIndex) { var inputReprsBuilder = new ImmutableArray <MRepr> .Builder(2); inputReprsBuilder[0] = arrayVariable.StaticRepr; inputReprsBuilder[1] = new MRepr(MClass.Int32, MStructuralClass.Scalar); var function = pseudoBuiltins.Lookup("GetDimensionRange", inputReprsBuilder.Complete()); EmitLoad(arrayVariable); cil.LoadInt32(dimensionIndex); cil.Invoke(function.Method); }
private void EmitCloneIfNeeded(MRepr type) { var sourceType = type.CliType; if (typeof(MValue).IsAssignableFrom(sourceType)) { var deepCloneMethod = sourceType.GetMethod("DeepClone"); cil.Invoke(deepCloneMethod); if (!sourceType.IsAssignableFrom(deepCloneMethod.ReturnType)) { cil.Instruction(Opcode.Castclass, sourceType); } } }
private static Variable ReadVariable(XElement variableElement) { var name = (string)variableElement.Attribute("name"); MType type = null; var className = (string)variableElement.Attribute("class"); if (className != null) { type = MClass.FromName((string)className); if (type.IsPrimitive) { // If we don't have complex information, then the variable's value // is sometimes real and sometimes complex, which we approximate // by making it always complex, though this can be incorrect. var complex = (bool?)variableElement.Attribute("complex") ?? true; if (complex) { type = ((MPrimitiveClass)type).Complex; } } } bool scalar = ((bool?)variableElement.Attribute("scalar")).GetValueOrDefault(); bool initOnly = ((bool?)variableElement.Attribute("final")).GetValueOrDefault(); string constantString = (string)variableElement.Attribute("constant"); object constantValue = null; if (constantString != null) { if (type.IsReal && type.IsNumeric) { constantValue = double.Parse(constantString, CultureInfo.InvariantCulture); } // TODO: Implement strings } var staticRepr = new MRepr(type, scalar ? MStructuralClass.Scalar : MStructuralClass.FullArray); return(new Variable(name, staticRepr, constantValue, initOnly)); }
private void EmitLoadAndConvert(Variable variable, MRepr targetRepr) { EmitLoad(variable); EmitConvert(variable.StaticRepr, targetRepr); }
private void EmitConvert(MRepr source, MRepr target) { if (source == target) { return; } if (target.IsAny) { if (source.IsMValue) { return; } if (source.IsPrimitiveScalar) { EmitBoxScalar(source.Type); return; } } if (source.Type == target.Type) { var type = source.Type; if (source.StructuralClass == MStructuralClass.Scalar && (target.StructuralClass == MStructuralClass.Array || target.StructuralClass == MStructuralClass.FullArray || target.IsAny)) { // Box a scalar to an array EmitBoxScalar(type); return; } else if (source.IsArray && target.StructuralClass == MStructuralClass.Scalar) { // Convert an array assumed to have size 1x1 to a scalar. var function = pseudoBuiltins.Lookup("ToScalar", source); cil.Invoke(function.Method); return; } else if (source.StructuralClass == MStructuralClass.IntegralRange && (target.IsArray || target.IsAny)) { // Integral range to array var function = pseudoBuiltins.Lookup("ToArray", source); cil.Invoke(function.Method); return; } // Upcast if (source.StructuralClass.IsArray && (target.IsArray || target.IsAny)) { return; } } else if (source.Class == target.Class) { if (target.IsComplex) { // Real to complex promotion // Convert to complex var function = pseudoBuiltins.Lookup("ToComplex", source); cil.Invoke(function.Method); // Change structural class if needed EmitConvert(function.Signature.Outputs[0], target); } else { Contract.Assert(source.IsComplex); // Complex to real demotion // We assume that this happens only in the case of variables // that can be either scalar or complex over their lifetime. var function = pseudoBuiltins.Lookup("GetRealPart", source); cil.Invoke(function.Method); // Change structural class if needed EmitConvert(function.Signature.Outputs[0], target); } return; } else { // Different classes if (source.StructuralClass == MStructuralClass.Scalar && source.Class.IsInteger && source.Type.IsReal) { if (target.Class.IsFloat) { // Int to float if (source.Class.IsUnsignedInteger) { cil.Instruction(Opcode.Conv_R_Un); } else if (target.Class == MClass.Single) { cil.Instruction(Opcode.Conv_R4); } else if (target.Class == MClass.Double) { cil.Instruction(Opcode.Conv_R8); } else { throw new NotSupportedException("Unexpected int-to-float conversion."); } // Do the rest of the conversion (complex, structural class), if needed EmitConvert(new MRepr(target.Class, MStructuralClass.Scalar), target); return; } else if (source.Class == MClass.Int32 && target.Class == MClass.Int64) { // Int32 to Int64 (hack for IntOK) cil.Instruction(Opcode.Conv_I8); return; } } } throw new NotImplementedException( string.Format("Conversion from {0} to {1}.", source, target)); }
public override void VisitRangeFor(RangeFor node) { // Declare loop labels, preserving parent ones var previousContinueTargetLabel = continueTargetLabel; var previousBreakTargetLabel = breakTargetLabel; continueTargetLabel = cil.CreateLabel("for_continue"); breakTargetLabel = cil.CreateLabel("for_break"); var conditionLabel = cil.CreateLabel("for_condition"); var iteratorRepr = new MRepr(node.Iterator.StaticRepr.Type, MStructuralClass.Scalar); Contract.Assert(iteratorRepr.Class.IsNumeric && !iteratorRepr.IsComplex); Contract.Assert(node.Step == null || IsLiteral(node.Step)); // Allocate the the temporaries we need var currentLocal = temporaryPool.Alloc(iteratorRepr.CliType); TemporaryLocalPool.AllocationScope?stepLocal = null, toLocal = null; try { // Setup the iterator variable, "current" EmitLoad(node.From); EmitConvert(node.From.StaticRepr, iteratorRepr); cil.Store(currentLocal.Location); // Save the increment to a local variable if it's not a literal or initonly if (node.Step != null && !IsLiteral(node.Step) && !node.Step.IsInitOnly) { stepLocal = temporaryPool.Alloc(iteratorRepr.CliType); EmitLoad(node.Step); EmitConvert(node.Step.StaticRepr, iteratorRepr); EmitCloneIfNeeded(iteratorRepr); cil.Store(stepLocal.Value.Location); } // Save the "to" variable to a local variable if it's not a literal or initonly if (!IsLiteral(node.To) && !node.To.IsInitOnly) { toLocal = temporaryPool.Alloc(iteratorRepr.CliType); EmitLoad(node.To); EmitConvert(node.To.StaticRepr, iteratorRepr); EmitCloneIfNeeded(iteratorRepr); cil.Store(toLocal.Value.Location); } // Test the loop condition { // condition: if (current > to) goto break; cil.MarkLabel(conditionLabel); cil.Load(currentLocal.Location); // IntOK hack: if the "to" is an integral float and our iterator is an integer, // consider "to" as an integer to avoid a cast. bool useIntegralFloatTo = iteratorRepr.Class == MClass.Int32 && IsLiteral(node.To) && PseudoBuiltins.IsIntegralFloat(Convert.ToDouble(node.To.ConstantValue)); if (!useIntegralFloatTo) { EmitConvert(iteratorRepr, node.To.StaticRepr); // Hack for IntOK } // Load the "to" loop bound variable (or our copy of it) if (toLocal.HasValue) { cil.Load(toLocal.Value.Location); } else { if (useIntegralFloatTo) { cil.LoadInt32((int)Convert.ToDouble(node.To.ConstantValue)); } else { EmitLoad(node.To); } } bool forward = node.Step == null || Convert.ToDouble(node.Step.ConstantValue) > 0; cil.Branch(forward ? Comparison.GreaterThan : Comparison.LessThan, breakTargetLabel); } // Setup the iterator variable (which can be modified inside the loop) cil.Load(currentLocal.Location); EmitConvert(iteratorRepr, node.Iterator.StaticRepr); cil.Store(GetLocation(node.Iterator)); // body EmitStatements(node.Body); // Loop increment { // continue: current += increment; goto condition; cil.MarkLabel(continueTargetLabel); cil.Load(currentLocal.Location); // Load the "step" loop increment variable, our copy of it or the default value of 1 if (stepLocal.HasValue) { cil.Load(stepLocal.Value.Location); } else if (node.Step == null) { if (iteratorRepr.Class.IsInteger) { cil.Instruction(Opcode.Ldc_I4_1); if (iteratorRepr.Class == MClass.Int64) { cil.Instruction(Opcode.Conv_I8); } } else { cil.LoadFloat64(1.0); } } else { EmitLoad(node.Step); EmitConvert(node.Step.StaticRepr, iteratorRepr); } // Increment cil.Instruction(Opcode.Add); cil.Store(currentLocal.Location); } cil.Branch(conditionLabel); } finally { currentLocal.Dispose(); if (stepLocal.HasValue) { stepLocal.Value.Dispose(); } if (toLocal.HasValue) { toLocal.Value.Dispose(); } } // break: cil.MarkLabel(breakTargetLabel); // Restore parent loop labels continueTargetLabel = previousContinueTargetLabel; breakTargetLabel = previousBreakTargetLabel; }