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)); }
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); }
public ICompiledMethod JIT(AccCIL.IR.MethodEntry method) { throw new NotImplementedException(); }
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)); }
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; }
/// <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)); }
private static bool SameAssemblyFilter(MethodReference initial, MethodReference parent, MethodReference current) { return(AccCIL.FindAssemblyName(current) == AccCIL.FindAssemblyName(initial)); }