diff options
| author | Ficture Seven <FICTURE7@gmail.com> | 2020-06-18 07:37:21 +0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-06-18 13:37:21 +1000 |
| commit | 2421186d974446ef4183420c50bc37e58d9fe213 (patch) | |
| tree | e182d974bc8dde8c6dcb206936cd2c4146f2f736 /ARMeilleure/Decoders | |
| parent | 5e724cf24e3d696b95be859c055a617e5d37bf80 (diff) | |
Generalize tail continues (#1298)
* Generalize tail continues
* Fix DecodeBasicBlock
`Next` and `Branch` would be null, which is not the state expected by
the branch instructions. They end up branching or falling into a block
which is never populated by the `Translator`. This causes an assert to
be fired when building the CFG.
* Clean up Decode overloads
* Do not synchronize when branching into exit block
If we're branching into an exit block, that exit block will tail
continue into another translation which already has a synchronization.
* Remove A32 predicate tail continue
If `block` is not an exit block then the `block.Next` must exist (as
per the last instruction of `block`).
* Throw if decoded 0 blocks
Address gdkchan's feedback
* Rebuild block list instead of setting to null
Address gdkchan's feedback
Diffstat (limited to 'ARMeilleure/Decoders')
| -rw-r--r-- | ARMeilleure/Decoders/Block.cs | 3 | ||||
| -rw-r--r-- | ARMeilleure/Decoders/Decoder.cs | 101 | ||||
| -rw-r--r-- | ARMeilleure/Decoders/Optimizations/TailCallRemover.cs | 50 |
3 files changed, 87 insertions, 67 deletions
diff --git a/ARMeilleure/Decoders/Block.cs b/ARMeilleure/Decoders/Block.cs index d38b5a8e..ef0517c0 100644 --- a/ARMeilleure/Decoders/Block.cs +++ b/ARMeilleure/Decoders/Block.cs @@ -12,6 +12,7 @@ namespace ARMeilleure.Decoders public Block Branch { get; set; } public bool TailCall { get; set; } + public bool Exit { get; set; } public List<OpCode> OpCodes { get; private set; } @@ -29,7 +30,7 @@ namespace ARMeilleure.Decoders { int splitIndex = BinarySearch(OpCodes, rightBlock.Address); - if ((ulong)OpCodes[splitIndex].Address < rightBlock.Address) + if (OpCodes[splitIndex].Address < rightBlock.Address) { splitIndex++; } diff --git a/ARMeilleure/Decoders/Decoder.cs b/ARMeilleure/Decoders/Decoder.cs index 6117b807..de62d125 100644 --- a/ARMeilleure/Decoders/Decoder.cs +++ b/ARMeilleure/Decoders/Decoder.cs @@ -17,16 +17,7 @@ namespace ARMeilleure.Decoders // For lower code quality translation, we set a lower limit since we're blocking execution. private const int MaxInstsPerFunctionLowCq = 500; - public static Block[] DecodeBasicBlock(IMemoryManager memory, ulong address, ExecutionMode mode) - { - Block block = new Block(address); - - FillBlock(memory, mode, block, ulong.MaxValue); - - return new Block[] { block }; - } - - public static Block[] DecodeFunction(IMemoryManager memory, ulong address, ExecutionMode mode, bool highCq) + public static Block[] Decode(IMemoryManager memory, ulong address, ExecutionMode mode, bool highCq, bool singleBlock) { List<Block> blocks = new List<Block>(); @@ -42,13 +33,14 @@ namespace ARMeilleure.Decoders { if (!visited.TryGetValue(blkAddress, out Block block)) { - if (opsCount > instructionLimit || !memory.IsMapped(blkAddress)) + block = new Block(blkAddress); + + if ((singleBlock && visited.Count >= 1) || opsCount > instructionLimit || !memory.IsMapped(blkAddress)) { - return null; + block.Exit = true; + block.EndAddress = blkAddress; } - block = new Block(blkAddress); - workQueue.Enqueue(block); visited.Add(blkAddress, block); @@ -71,6 +63,8 @@ namespace ARMeilleure.Decoders throw new InvalidOperationException("Found duplicate block address on the list."); } + currBlock.Exit = false; + nBlock.Split(currBlock); blocks.Insert(nBlkIndex + 1, currBlock); @@ -78,47 +72,50 @@ namespace ARMeilleure.Decoders continue; } - // If we have a block after the current one, set the limit address. - ulong limitAddress = ulong.MaxValue; - - if (nBlkIndex != blocks.Count) + if (!currBlock.Exit) { - Block nBlock = blocks[nBlkIndex]; - - int nextIndex = nBlkIndex + 1; + // If we have a block after the current one, set the limit address. + ulong limitAddress = ulong.MaxValue; - if (nBlock.Address < currBlock.Address && nextIndex < blocks.Count) + if (nBlkIndex != blocks.Count) { - limitAddress = blocks[nextIndex].Address; + Block nBlock = blocks[nBlkIndex]; + + int nextIndex = nBlkIndex + 1; + + if (nBlock.Address < currBlock.Address && nextIndex < blocks.Count) + { + limitAddress = blocks[nextIndex].Address; + } + else if (nBlock.Address > currBlock.Address) + { + limitAddress = blocks[nBlkIndex].Address; + } } - else if (nBlock.Address > currBlock.Address) - { - limitAddress = blocks[nBlkIndex].Address; - } - } - FillBlock(memory, mode, currBlock, limitAddress); + FillBlock(memory, mode, currBlock, limitAddress); - opsCount += currBlock.OpCodes.Count; - - if (currBlock.OpCodes.Count != 0) - { - // Set child blocks. "Branch" is the block the branch instruction - // points to (when taken), "Next" is the block at the next address, - // executed when the branch is not taken. For Unconditional Branches - // (except BL/BLR that are sub calls) or end of executable, Next is null. - OpCode lastOp = currBlock.GetLastOp(); + opsCount += currBlock.OpCodes.Count; - bool isCall = IsCall(lastOp); - - if (lastOp is IOpCodeBImm op && !isCall) + if (currBlock.OpCodes.Count != 0) { - currBlock.Branch = GetBlock((ulong)op.Immediate); - } - - if (!IsUnconditionalBranch(lastOp) || isCall) - { - currBlock.Next = GetBlock(currBlock.EndAddress); + // Set child blocks. "Branch" is the block the branch instruction + // points to (when taken), "Next" is the block at the next address, + // executed when the branch is not taken. For Unconditional Branches + // (except BL/BLR that are sub calls) or end of executable, Next is null. + OpCode lastOp = currBlock.GetLastOp(); + + bool isCall = IsCall(lastOp); + + if (lastOp is IOpCodeBImm op && !isCall) + { + currBlock.Branch = GetBlock((ulong)op.Immediate); + } + + if (!IsUnconditionalBranch(lastOp) || isCall) + { + currBlock.Next = GetBlock(currBlock.EndAddress); + } } } @@ -135,7 +132,15 @@ namespace ARMeilleure.Decoders } } - TailCallRemover.RunPass(address, blocks); + if (blocks.Count == 0) + { + throw new InvalidOperationException($"Decoded 0 blocks. Entry point = 0x{address:X}."); + } + + if (!singleBlock) + { + return TailCallRemover.RunPass(address, blocks); + } return blocks.ToArray(); } diff --git a/ARMeilleure/Decoders/Optimizations/TailCallRemover.cs b/ARMeilleure/Decoders/Optimizations/TailCallRemover.cs index 2d6439ba..e64f9a54 100644 --- a/ARMeilleure/Decoders/Optimizations/TailCallRemover.cs +++ b/ARMeilleure/Decoders/Optimizations/TailCallRemover.cs @@ -1,16 +1,15 @@ -using ARMeilleure.Decoders; -using System; +using System; using System.Collections.Generic; namespace ARMeilleure.Decoders.Optimizations { static class TailCallRemover { - public static void RunPass(ulong entryAddress, List<Block> blocks) + public static Block[] RunPass(ulong entryAddress, List<Block> blocks) { // Detect tail calls: // - Assume this function spans the space covered by contiguous code blocks surrounding the entry address. - // - Unconditional jump to an area outside this contiguous region will be treated as a tail call. + // - A jump to an area outside this contiguous region will be treated as an exit block. // - Include a small allowance for jumps outside the contiguous range. if (!Decoder.BinarySearch(blocks, entryAddress, out int entryBlockId)) @@ -19,57 +18,72 @@ namespace ARMeilleure.Decoders.Optimizations } const ulong allowance = 4; + Block entryBlock = blocks[entryBlockId]; - int startBlockIndex = entryBlockId; + Block startBlock = entryBlock; - int endBlockIndex = entryBlockId; - Block endBlock = entryBlock; + Block endBlock = entryBlock; + + int startBlockIndex = entryBlockId; + int endBlockIndex = entryBlockId; for (int i = entryBlockId + 1; i < blocks.Count; i++) // Search forwards. { Block block = blocks[i]; + if (endBlock.EndAddress < block.Address - allowance) { break; // End of contiguous function. } - endBlock = block; + endBlock = block; endBlockIndex = i; } for (int i = entryBlockId - 1; i >= 0; i--) // Search backwards. { Block block = blocks[i]; + if (startBlock.Address > block.EndAddress + allowance) { break; // End of contiguous function. } - startBlock = block; + startBlock = block; startBlockIndex = i; } if (startBlockIndex == 0 && endBlockIndex == blocks.Count - 1) { - return; // Nothing to do here. + return blocks.ToArray(); // Nothing to do here. } - - // Replace all branches to blocks outside the range with null, and force a tail call. - + + // Mark branches outside of contiguous region as exit blocks. for (int i = startBlockIndex; i <= endBlockIndex; i++) { Block block = blocks[i]; + if (block.Branch != null && (block.Branch.Address > endBlock.EndAddress || block.Branch.EndAddress < startBlock.Address)) { - block.Branch = null; - block.TailCall = true; + block.Branch.Exit = true; + block.Branch.TailCall = true; } } - // Finally, delete all blocks outside the contiguous range. + var newBlocks = new List<Block>(blocks.Count); + + // Finally, rebuild decoded block list, ignoring blocks outside the contiguous range. + for (int i = 0; i < blocks.Count; i++) + { + Block block = blocks[i]; + + if (block.Exit || (i >= startBlockIndex && i <= endBlockIndex)) + { + newBlocks.Add(block); + } + } - blocks.RemoveRange(endBlockIndex + 1, (blocks.Count - endBlockIndex) - 1); - blocks.RemoveRange(0, startBlockIndex); + return newBlocks.ToArray(); } } } |
