Example #1
0
        protected T DoAccelerate <T>(string assemblyfile, string methodName, Type[] types, params object[] args)
        {
            if (!System.IO.File.Exists(assemblyfile))
            {
                throw new Exception("Could not find program file: " + assemblyfile);
            }

            AssemblyDefinition asm           = AccCIL.LoadAssemblyFile(assemblyfile);
            MethodDefinition   initialMethod = AccCIL.FindMethod(asm, methodName, types);

            if (initialMethod == null)
            {
                throw new Exception("Unable to find a match for " + methodName + " in assembly " + assemblyfile);
            }

            List <ICompiledMethod> methodset;

            m_compilationCache.TryGetValue(initialMethod, out methodset);
            if (methodset == null)
            {
                m_compilationCache.Add(initialMethod, methodset = CompileMethod(initialMethod));
            }

            LoadProgramInternal(methodset, initialMethod, types);

            return(Execute <T>(args));
        }
Example #2
0
        protected List <ICompiledMethod> CompileMethod(MethodDefinition initialMethod)
        {
            Dictionary <MethodReference, string> visitedMethods = new Dictionary <MethodReference, string>();
            List <ICompiledMethod> methods   = new List <ICompiledMethod>();
            ICompiledMethod        initialCm = AccCIL.JIT(this.Compiler, initialMethod);

            methods.Add(initialCm);
            visitedMethods.Add(initialMethod, null);

            Queue <ICompiledMethod> work = new Queue <ICompiledMethod>();

            work.Enqueue(initialCm);

            while (work.Count > 0)
            {
                ICompiledMethod cur   = work.Dequeue();
                var             calls = from x in cur.Method.FlatInstructionList
                                        let code = x.Instruction.OpCode.Code
                                                   where code == Mono.Cecil.Cil.Code.Call || code == Mono.Cecil.Cil.Code.Calli || code == Mono.Cecil.Cil.Code.Callvirt
                                                   select((Mono.Cecil.MethodReference) x.Instruction.Operand);

                foreach (MethodReference mr in calls)
                {
                    if (visitedMethods.ContainsKey(mr))
                    {
                        continue;
                    }

                    visitedMethods.Add(mr, null);

                    if (m_functionFilter(initialMethod, cur.Method.Method, mr))
                    {
                        MethodDefinition md = AccCIL.FindMethod(mr);
                        if (md == null)
                        {
                            throw new Exception("Unable to locate the method " + mr.DeclaringType.FullName + "::" + mr.Name + " in assembly " + mr.DeclaringType.Module.Assembly.Name.FullName);
                        }
                        ICompiledMethod cm = AccCIL.JIT(this.Compiler, md);
                        work.Enqueue(cm);
                        methods.Add(cm);
                    }
                }
            }

            return(methods);
        }
Example #3
0
 public ICompiledMethod JIT(AccCIL.IR.MethodEntry method)
 {
     throw new NotImplementedException();
 }
Example #4
0
        private static void RecursiveTranslate(CompiledMethod state, SPEOpCodeMapper mapper, AccCIL.IR.InstructionElement el, Dictionary<AccCIL.IR.InstructionElement, string> compiled)
        {
            if (compiled.ContainsKey(el))
            {
                System.Diagnostics.Debug.Assert(el.Instruction.OpCode.Code == Mono.Cecil.Cil.Code.Dup);
                return;
            }

            compiled.Add(el, null);

            foreach (AccCIL.IR.InstructionElement els in el.Childnodes)
                RecursiveTranslate(state, mapper, els, compiled);

            int stackdepth = state.VirtualStackDepth;
            System.Reflection.MethodInfo translator;
            if (!_opTranslations.TryGetValue(el.Instruction.OpCode.Code, out translator))
                throw new Exception(string.Format("Missing a translator for CIL code {0}", el.Instruction.OpCode.Code));

            state.StartInstruction(el.Instruction);
            translator.Invoke(mapper, new object[] { el });
            state.EndInstruction();

            //Verify that the instruction handler managed to handle the stack
            System.Diagnostics.Debug.Assert(state.VirtualStackDepth == stackdepth + AccCIL.AccCIL.StackChangeCount(el));
        }
Example #5
0
        public ICompiledMethod JIT(AccCIL.IR.MethodEntry method)
        {
            //First we execute all IR/CIL optimizations, except the register allocator
            IRegisterAllocator allocator = null;

            foreach (IOptimizer o in m_optimizers)
                if (this.OptimizationLevel >= o.IncludeLevel)
                {
                    if (o is IRegisterAllocator)
                    {
                        allocator = (IRegisterAllocator)o;
                        continue;
                    }
                    else
                        o.Optimize(method, this.OptimizationLevel);
                }

            CompiledMethod state = new CompiledMethod(method);
            SPEOpCodeMapper mapper = new SPEOpCodeMapper(state);

            state.StartFunction();

            //We store the local variables in the permanent registers followed by the function arguments
            int locals = method.Method.Body.Variables.Count;
            int args = method.Method.Parameters.Count;
            int permRegs = locals + args;

            //TODO: Handle this case by storing the extra data on the stack
            if (permRegs > MAX_LV_REGISTERS)
                throw new Exception("Too many locals+arguments");

            //Make sure the register usage is clean
            method.ResetVirtualRegisters();

            //TODO: should be able to re-use registers used by the arguments, which frees appx 70 extra registers
            List<int> usedRegs =
                this.OptimizationLevel > AccCIL.OptimizationLevel.None ?
                new RegisterAllocator().AllocateRegisters(_LV0 + permRegs, allocator, method) :
                new List<int>();

            //new AccCILVisualizer.Visualizer(new AccCIL.IR.MethodEntry[] { method }).ShowDialog();

            //If we need to store locals, we must preserve the local variable registers
            for (int i = 0; i < permRegs; i++)
            {
                mapper.PushStack(new TemporaryRegister((uint)(_LV0 + i)));
                usedRegs.Remove(_LV0 + i);
            }

            //All remaining used registers must also be preserved
            foreach (int i in usedRegs.Reverse<int>())
                if (i > _LV0)
                    mapper.PushStack(new TemporaryRegister((uint)(i)));

            //Clear as required
            if (method.Method.Body.InitLocals)
                for (int i = 0; i < locals; i++)
                    mapper.ClearRegister((uint)(_LV0 + i));

            //Now copy over the arguments
            for (int i = 0; i < args; i++)
                mapper.CopyRegister((uint)(_ARG0 + i), (uint)(_LV0 + locals + i));

            int requiredStackDepth = state.StackDepth;

            //Now add each parsed subtree
            foreach (AccCIL.IR.InstructionElement el in method.Childnodes)
            {
                System.Diagnostics.Debug.Assert(state.VirtualStackDepth == requiredStackDepth);
                RecursiveTranslate(state, mapper, el, new Dictionary<AccCIL.IR.InstructionElement,string>());
                System.Diagnostics.Debug.Assert(state.VirtualStackDepth == requiredStackDepth);

                System.Diagnostics.Trace.Assert(state.StackDepth >= requiredStackDepth);
            }

            state.EndFunction();

            System.Diagnostics.Trace.Assert(state.StackDepth == requiredStackDepth);

            //All used registers must be preserved
            foreach (int i in usedRegs)
                if (i > _LV0)
                    mapper.PopStack((uint)(i), true);

            //If we had to store locals, we must restore the local variable registers
            for (int i = 0; i < permRegs; i++)
                mapper.PopStack((uint)(_LV0 + (permRegs - i - 1)), true);

            System.Diagnostics.Trace.Assert(state.StackDepth == 0);

            return state;
        }
Example #6
0
        /// <summary>
        /// Internal helper function that takes two registers (tmp0 and tmp1) and calculates the absolute LS address of an
        /// array element and stores the address in the output register
        /// </summary>
        /// <param name="el">The instruction being issued</param>
        /// <param name="arraytype">The accepted array element type, all must have same size</param>
        /// <param name="elementIndex">The register that holds the element index, must be _RTMP0 or _RTMP1</param>
        /// <param name="arrayPointer">The register that holds the object pointer index, must be _RTMP0 or _RTMP1</param>
        /// <param name="output">The register into which the resulting address will be written</param>
        private void LoadElementAddress(InstructionElement el, AccCIL.KnownObjectTypes[] arraytypes, uint elementIndex, uint arrayPointer, uint output)
        {
            //Ensure that we are not using the temp registers
            System.Diagnostics.Debug.Assert(elementIndex != _RTMP2 && elementIndex != _RTMP3);
            System.Diagnostics.Debug.Assert(arrayPointer != _RTMP2 && arrayPointer != _RTMP3);

            uint extraTmp = arrayPointer;
            if (extraTmp != _RTMP0 && extraTmp != _RTMP1)
                extraTmp = elementIndex == _RTMP0 ? _RTMP1 : _RTMP0;

            //Test that the array is not null
            //TODO: Jump to an NullException raise function
            m_state.Instructions.Add(new SPEEmulator.OpCodes.brz(arrayPointer, 0));

            //Get the object table entry
            m_state.Instructions.Add(new SPEEmulator.OpCodes.shli(_RTMP2, arrayPointer, 0x4)); //Times 16
            m_state.Instructions.Add(new SPEEmulator.OpCodes.lqd(_RTMP2, _RTMP2, SPEJITCompiler.OBJECT_TABLE_OFFSET / 16));

            uint eldivsize = BuiltInSPEMethods.get_array_elem_len_mult((uint)arraytypes[0]);

            //Verify that the array has the correct type and that the index is within range
            if (!el.IsIndexChecked)
            {
                //TODO: If the array is type object, we need to ensure:
                // 1. That it is actually an array type
                // 2. That the element written to the array has the correct type

                //We need to clear out the type information
                if (arraytypes.Length == 1 && arraytypes[0] == KnownObjectTypes.Object)
                    m_state.Instructions.Add(new SPEEmulator.OpCodes.andi(_RTMP2, _RTMP2, 0xff));

                //TODO: It seems that the CIL is expected to perform the compatible type check?

                if (arraytypes.Length == 1)
                {
                    //Verrify the data type
                    m_state.Instructions.Add(new SPEEmulator.OpCodes.ceqi(_RTMP3, _RTMP2, (uint)arraytypes[0]));
                }
                else
                {
                    //Clear a storage area
                    m_state.Instructions.Add(new SPEEmulator.OpCodes.xor(_RTMP3, _RTMP3, _RTMP3));

                    foreach (KnownObjectTypes t in arraytypes)
                    {
                        //Verrify the data type
                        m_state.Instructions.Add(new SPEEmulator.OpCodes.ceqi(extraTmp, _RTMP2, (uint)t));
                        m_state.Instructions.Add(new SPEEmulator.OpCodes.or(_RTMP3, extraTmp, _RTMP3));
                    }
                }

                //TODO: Jump to an InvalidProgram exception raise function
                m_state.Instructions.Add(new SPEEmulator.OpCodes.brz(_RTMP3, 0));

                //Verify the size of the array
                m_state.Instructions.Add(new SPEEmulator.OpCodes.shlqbyi(extraTmp, _RTMP2, 0x4)); //Move word into position
                m_state.Instructions.Add(new SPEEmulator.OpCodes.rotmi(_RTMP3, extraTmp, (uint)((-eldivsize) & 0x7f))); //Move word into position and divide with elementsize
                m_state.Instructions.Add(new SPEEmulator.OpCodes.cgt(extraTmp, elementIndex, _RTMP3));
                //TODO: Jump to an IndexOutOfRange exception raise function
                m_state.Instructions.Add(new SPEEmulator.OpCodes.brnz(extraTmp, 0x0));
                m_state.Instructions.Add(new SPEEmulator.OpCodes.ceq(extraTmp, elementIndex, _RTMP3));
                //TODO: Jump to an IndexOutOfRange exception raise function
                m_state.Instructions.Add(new SPEEmulator.OpCodes.brnz(extraTmp, 0x0));

                //Re-load the pointer
                m_state.Instructions.Add(new SPEEmulator.OpCodes.shli(_RTMP2, arrayPointer, 0x4)); //Times 16
                m_state.Instructions.Add(new SPEEmulator.OpCodes.lqd(_RTMP2, _RTMP2, SPEJITCompiler.OBJECT_TABLE_OFFSET / 16));

            }

            //Get the base pointer offset
            m_state.Instructions.Add(new SPEEmulator.OpCodes.shlqbyi(_RTMP3, _RTMP2, 0x8));

            //Calculate adress based on index * elsize + offset
            m_state.Instructions.Add(new SPEEmulator.OpCodes.shli(_RTMP2, elementIndex, (uint)eldivsize));
            m_state.Instructions.Add(new SPEEmulator.OpCodes.a(output, _RTMP3, _RTMP2));
        }
Example #7
0
 private static bool SameAssemblyFilter(MethodReference initial, MethodReference parent, MethodReference current)
 {
     return(AccCIL.FindAssemblyName(current) == AccCIL.FindAssemblyName(initial));
 }