Пример #1
0
        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));
            }
        }
Пример #2
0
        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);
            }
        }
Пример #3
0
        public Variable(string name, MRepr staticRepr, bool initOnly)
        {
            Contract.Requires(name != null);

            this.Name       = name;
            this.StaticRepr = staticRepr;
            this.IsInitOnly = initOnly;
        }
Пример #4
0
        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);
        }
Пример #5
0
        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);
        }
Пример #6
0
        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);
        }
Пример #7
0
        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);
                }
            }
        }
Пример #8
0
        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));
        }
Пример #9
0
 private void EmitLoadAndConvert(Variable variable, MRepr targetRepr)
 {
     EmitLoad(variable);
     EmitConvert(variable.StaticRepr, targetRepr);
 }
Пример #10
0
        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));
        }
Пример #11
0
        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;
        }