public bool AdvanceOpCode() { if (_opcIndex + 1 == CurrBlock.OpCodes.Count && _blkIndex + 1 == _graph.Length) { return(false); } while (++_opcIndex >= (CurrBlock?.OpCodes.Count ?? 0)) { _blkIndex++; _opcIndex = -1; _optOpLastFlagSet = null; _optOpLastCompare = null; _ilBlock = _emitter.GetIlBlock(_blkIndex); } return(true); }
public ILEmitterCtx( TranslatorCache cache, Block[] graph, Block root, string subName) { _cache = cache ?? throw new ArgumentNullException(nameof(cache)); _graph = graph ?? throw new ArgumentNullException(nameof(graph)); _root = root ?? throw new ArgumentNullException(nameof(root)); _labels = new Dictionary <long, ILLabel>(); _emitter = new ILEmitter(graph, root, subName); _ilBlock = _emitter.GetIlBlock(0); _opcIndex = -1; if (graph.Length == 0 || !AdvanceOpCode()) { throw new ArgumentException(nameof(graph)); } }
public long GetVecOutputs(ILBlock block) => _vecPaths[block].GetOutputs();
public long GetVecNotInputs(ILBlock entry) => GetNotInputsImpl(entry, _vecPaths.Values);
public long GetIntOutputs(ILBlock block) => _intPaths[block].GetOutputs();
public void BuildUses(ILBlock entry) { //This will go through all possible paths on the graph, //and store all inputs/outputs for each block. A register //that was previously written to already is not considered an input. //When a block can be reached by more than one path, then the //output from all paths needs to be set for this block, and //only outputs present in all of the parent blocks can be considered //when doing input elimination. Each block chain has a entry, that's where //the code starts executing. They are present on the subroutine start point, //and on call return points too (address written to X30 by BL). HashSet <BlockIo> visited = new HashSet <BlockIo>(); Queue <BlockIo> unvisited = new Queue <BlockIo>(); void Enqueue(BlockIo block) { if (visited.Add(block)) { unvisited.Enqueue(block); } } Enqueue(new BlockIo(entry, entry)); while (unvisited.Count > 0) { BlockIo current = unvisited.Dequeue(); current.IntInputs |= current.Block.IntInputs & ~current.IntOutputs; current.VecInputs |= current.Block.VecInputs & ~current.VecOutputs; current.IntOutputs |= current.Block.IntOutputs; current.VecOutputs |= current.Block.VecOutputs; //Check if this is a exit block //(a block that returns or calls another sub). if ((current.Block.Next == null && current.Block.Branch == null) || current.Block.HasStateStore) { if (!_intPaths.TryGetValue(current.Block, out PathIo intPath)) { _intPaths.Add(current.Block, intPath = new PathIo()); } if (!_vecPaths.TryGetValue(current.Block, out PathIo vecPath)) { _vecPaths.Add(current.Block, vecPath = new PathIo()); } intPath.Set(current.Entry, current.IntInputs, current.IntOutputs); vecPath.Set(current.Entry, current.VecInputs, current.VecOutputs); } void EnqueueFromCurrent(ILBlock block, bool retTarget) { BlockIo blockIo; if (retTarget) { blockIo = new BlockIo(block, block); } else { blockIo = new BlockIo( block, current.Entry, current.IntInputs, current.VecInputs, current.IntOutputs, current.VecOutputs); } Enqueue(blockIo); } if (current.Block.Next != null) { EnqueueFromCurrent(current.Block.Next, current.Block.HasStateStore); } if (current.Block.Branch != null) { EnqueueFromCurrent(current.Block.Branch, false); } } }
public long GetIntNotInputs(ILBlock entry) => GetNotInputsImpl(entry, _intPaths.Values);
public long GetIntInputs(ILBlock root) => GetInputsImpl(root, _intPaths.Values);
public long GetVecInputs(ILBlock root) => GetInputsImpl(root, _vecPaths.Values);
public PathIo(ILBlock root, long inputs, long outputs) : this() { Set(root, inputs, outputs); }
public ILOpCodeStoreState(ILBlock block) { _block = block; }
public ILOpCodeStoreState(ILBlock block, TranslatedSub callSub = null) { _block = block; _callSub = callSub; }
public ILOpCodeLoadState(ILBlock block) { _block = block; }
public ILOpCodeLoadState(ILBlock block, bool isSubEntry = false) { _block = block; _isSubEntry = isSubEntry; }