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/Translation | |
| 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/Translation')
| -rw-r--r-- | ARMeilleure/Translation/Translator.cs | 65 |
1 files changed, 31 insertions, 34 deletions
diff --git a/ARMeilleure/Translation/Translator.cs b/ARMeilleure/Translation/Translator.cs index 1c2ead4f..d1404796 100644 --- a/ARMeilleure/Translation/Translator.cs +++ b/ARMeilleure/Translation/Translator.cs @@ -183,7 +183,7 @@ namespace ARMeilleure.Translation Logger.StartPass(PassName.Decoding); - Block[] blocks = Decoder.DecodeFunction(memory, address, mode, highCq); + Block[] blocks = Decoder.Decode(memory, address, mode, highCq, singleBlock: false); Logger.EndPass(PassName.Decoding); @@ -242,49 +242,46 @@ namespace ARMeilleure.Translation context.MarkLabel(context.GetLabel(block.Address)); - for (int opcIndex = 0; opcIndex < block.OpCodes.Count; opcIndex++) + if (block.Exit) { - OpCode opCode = block.OpCodes[opcIndex]; + InstEmitFlowHelper.EmitTailContinue(context, Const(block.Address), block.TailCall); + } + else + { + for (int opcIndex = 0; opcIndex < block.OpCodes.Count; opcIndex++) + { + OpCode opCode = block.OpCodes[opcIndex]; - context.CurrOp = opCode; + context.CurrOp = opCode; - bool isLastOp = opcIndex == block.OpCodes.Count - 1; + bool isLastOp = opcIndex == block.OpCodes.Count - 1; - if (isLastOp && block.Branch != null && block.Branch.Address <= block.Address) - { - EmitSynchronization(context); - } + if (isLastOp && block.Branch != null && !block.Branch.Exit && block.Branch.Address <= block.Address) + { + EmitSynchronization(context); + } - Operand lblPredicateSkip = null; + Operand lblPredicateSkip = null; - if (opCode is OpCode32 op && op.Cond < Condition.Al) - { - lblPredicateSkip = Label(); + if (opCode is OpCode32 op && op.Cond < Condition.Al) + { + lblPredicateSkip = Label(); - InstEmitFlowHelper.EmitCondBranch(context, lblPredicateSkip, op.Cond.Invert()); - } + InstEmitFlowHelper.EmitCondBranch(context, lblPredicateSkip, op.Cond.Invert()); + } - if (opCode.Instruction.Emitter != null) - { - opCode.Instruction.Emitter(context); - } - else - { - throw new InvalidOperationException($"Invalid instruction \"{opCode.Instruction.Name}\"."); - } + if (opCode.Instruction.Emitter != null) + { + opCode.Instruction.Emitter(context); + } + else + { + throw new InvalidOperationException($"Invalid instruction \"{opCode.Instruction.Name}\"."); + } - if (lblPredicateSkip != null) - { - context.MarkLabel(lblPredicateSkip); - - // If this is the last op on the block, and there's no "next" block - // after this one, then we have to return right now, with the address - // of the next instruction to be executed (in the case that the condition - // is false, and the branch was not taken, as all basic blocks should end - // with some kind of branch). - if (isLastOp && block.Next == null) + if (lblPredicateSkip != null) { - InstEmitFlowHelper.EmitTailContinue(context, Const(opCode.Address + (ulong)opCode.OpCodeSizeInBytes)); + context.MarkLabel(lblPredicateSkip); } } } |
