aboutsummaryrefslogtreecommitdiff
path: root/ChocolArm64/Translation/Translator.cs
diff options
context:
space:
mode:
authorgdkchan <gab.dark.100@gmail.com>2019-04-26 01:55:12 -0300
committerjduncanator <1518948+jduncanator@users.noreply.github.com>2019-04-26 14:55:12 +1000
commit8a7d99cdeae2355511d4eb43aefb76d0d886bcf8 (patch)
tree655d33f4db5dc3eb21c9c4ff5867b1179913585a /ChocolArm64/Translation/Translator.cs
parent2b8eac1bcec6d4870776b4f302d9dd7794223642 (diff)
Refactoring and optimization on CPU translation (#661)
* Refactoring and optimization on CPU translation * Remove now unused property * Rename ilBlock -> block (local) * Change equality comparison on RegisterMask for consistency Co-Authored-By: gdkchan <gab.dark.100@gmail.com> * Add back the aggressive inlining attribute to the Synchronize method * Implement IEquatable on the Register struct * Fix identation
Diffstat (limited to 'ChocolArm64/Translation/Translator.cs')
-rw-r--r--ChocolArm64/Translation/Translator.cs117
1 files changed, 93 insertions, 24 deletions
diff --git a/ChocolArm64/Translation/Translator.cs b/ChocolArm64/Translation/Translator.cs
index bda0bca0..2f88aaf9 100644
--- a/ChocolArm64/Translation/Translator.cs
+++ b/ChocolArm64/Translation/Translator.cs
@@ -1,8 +1,10 @@
using ChocolArm64.Decoders;
using ChocolArm64.Events;
+using ChocolArm64.IntermediateRepresentation;
using ChocolArm64.Memory;
using ChocolArm64.State;
using System;
+using System.Reflection.Emit;
using System.Threading;
namespace ChocolArm64.Translation
@@ -82,7 +84,7 @@ namespace ChocolArm64.Translation
sub = TranslateLowCq(position, state.GetExecutionMode());
}
- if (sub.IsWorthOptimizing())
+ if (sub.Rejit())
{
bool isComplete = cs == CallType.Call ||
cs == CallType.VirtualCall;
@@ -124,58 +126,125 @@ namespace ChocolArm64.Translation
private TranslatedSub TranslateLowCq(long position, ExecutionMode mode)
{
- Block block = Decoder.DecodeBasicBlock(_memory, position, mode);
+ Block[] blocks = Decoder.DecodeBasicBlock(_memory, (ulong)position, mode);
- ILEmitterCtx context = new ILEmitterCtx(_memory, _cache, _queue, TranslationTier.Tier0, block);
+ ILEmitterCtx context = new ILEmitterCtx(_memory, _cache, _queue, TranslationTier.Tier0);
- string subName = GetSubroutineName(position);
+ BasicBlock[] bbs = EmitAndGetBlocks(context, blocks);
- bool isAarch64 = mode == ExecutionMode.Aarch64;
+ TranslatedSubBuilder builder = new TranslatedSubBuilder(mode);
- ILMethodBuilder ilMthdBuilder = new ILMethodBuilder(context.GetILBlocks(), subName, isAarch64);
+ string name = GetSubroutineName(position);
- TranslatedSub subroutine = ilMthdBuilder.GetSubroutine(TranslationTier.Tier0, isWorthOptimizing: true);
+ TranslatedSub subroutine = builder.Build(bbs, name, TranslationTier.Tier0);
- return _cache.GetOrAdd(position, subroutine, block.OpCodes.Count);
+ return _cache.GetOrAdd(position, subroutine, GetOpsCount(bbs));
}
private TranslatedSub TranslateHighCq(long position, ExecutionMode mode, bool isComplete)
{
- Block graph = Decoder.DecodeSubroutine(_memory, position, mode);
+ Block[] blocks = Decoder.DecodeSubroutine(_memory, (ulong)position, mode);
- ILEmitterCtx context = new ILEmitterCtx(_memory, _cache, _queue, TranslationTier.Tier1, graph);
+ ILEmitterCtx context = new ILEmitterCtx(_memory, _cache, _queue, TranslationTier.Tier1);
- ILBlock[] ilBlocks = context.GetILBlocks();
-
- string subName = GetSubroutineName(position);
+ if (blocks[0].Address != (ulong)position)
+ {
+ context.Emit(OpCodes.Br, context.GetLabel(position));
+ }
- bool isAarch64 = mode == ExecutionMode.Aarch64;
+ BasicBlock[] bbs = EmitAndGetBlocks(context, blocks);
isComplete &= !context.HasIndirectJump;
- ILMethodBuilder ilMthdBuilder = new ILMethodBuilder(ilBlocks, subName, isAarch64, isComplete);
+ TranslatedSubBuilder builder = new TranslatedSubBuilder(mode, isComplete);
- TranslatedSub subroutine = ilMthdBuilder.GetSubroutine(TranslationTier.Tier1, context.HasSlowCall);
+ string name = GetSubroutineName(position);
- int ilOpCount = 0;
-
- foreach (ILBlock ilBlock in ilBlocks)
- {
- ilOpCount += ilBlock.Count;
- }
+ TranslatedSub subroutine = builder.Build(bbs, name, TranslationTier.Tier1, context.HasSlowCall);
ForceAheadOfTimeCompilation(subroutine);
- _cache.AddOrUpdate(position, subroutine, ilOpCount);
+ _cache.AddOrUpdate(position, subroutine, GetOpsCount(bbs));
return subroutine;
}
- private string GetSubroutineName(long position)
+ private static BasicBlock[] EmitAndGetBlocks(ILEmitterCtx context, Block[] blocks)
+ {
+ for (int blkIndex = 0; blkIndex < blocks.Length; blkIndex++)
+ {
+ Block block = blocks[blkIndex];
+
+ context.CurrBlock = block;
+
+ context.MarkLabel(context.GetLabel((long)block.Address));
+
+ for (int opcIndex = 0; opcIndex < block.OpCodes.Count; opcIndex++)
+ {
+ OpCode64 opCode = block.OpCodes[opcIndex];
+
+ context.CurrOp = opCode;
+
+ bool isLastOp = opcIndex == block.OpCodes.Count - 1;
+
+ if (isLastOp && block.Branch != null && block.Branch.Address <= block.Address)
+ {
+ context.EmitSynchronization();
+ }
+
+ ILLabel lblPredicateSkip = null;
+
+ if (opCode is OpCode32 op && op.Cond < Condition.Al)
+ {
+ lblPredicateSkip = new ILLabel();
+
+ context.EmitCondBranch(lblPredicateSkip, op.Cond.Invert());
+ }
+
+ opCode.Emitter(context);
+
+ if (lblPredicateSkip != null)
+ {
+ context.MarkLabel(lblPredicateSkip);
+
+ context.ResetBlockStateForPredicatedOp();
+
+ //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)
+ {
+ context.EmitStoreContext();
+ context.EmitLdc_I8(opCode.Position + opCode.OpCodeSizeInBytes);
+
+ context.Emit(OpCodes.Ret);
+ }
+ }
+ }
+ }
+
+ return context.GetBlocks();
+ }
+
+ private static string GetSubroutineName(long position)
{
return $"Sub{position:x16}";
}
+ private static int GetOpsCount(BasicBlock[] blocks)
+ {
+ int opCount = 0;
+
+ foreach (BasicBlock block in blocks)
+ {
+ opCount += block.Count;
+ }
+
+ return opCount;
+ }
+
private void ForceAheadOfTimeCompilation(TranslatedSub subroutine)
{
subroutine.Execute(_dummyThreadState, null);