diff --git a/ChocolArm64/ATranslator.cs b/ChocolArm64/ATranslator.cs index 2d9fcb1415..4d501d00da 100644 --- a/ChocolArm64/ATranslator.cs +++ b/ChocolArm64/ATranslator.cs @@ -117,13 +117,11 @@ namespace ChocolArm64 private ATranslatedSub TranslateTier0(AThreadState State, AMemory Memory, long Position) { - ABlock Block = ADecoder.DecodeBasicBlock(State, this, Memory, Position); - - ABlock[] Graph = new ABlock[] { Block }; + (ABlock[] Graph, ABlock Root) = ADecoder.DecodeBasicBlock(State, this, Memory, Position); string SubName = GetSubName(Position); - AILEmitterCtx Context = new AILEmitterCtx(this, Graph, Block, SubName); + AILEmitterCtx Context = new AILEmitterCtx(this, Graph, Root, SubName); do { @@ -137,8 +135,6 @@ namespace ChocolArm64 CachedSubs.AddOrUpdate(Position, Subroutine, (Key, OldVal) => Subroutine); - AOpCode LastOp = Block.GetLastOp(); - return Subroutine; } diff --git a/ChocolArm64/Decoder/ADecoder.cs b/ChocolArm64/Decoder/ADecoder.cs index b154a54cd2..e5090dd1f1 100644 --- a/ChocolArm64/Decoder/ADecoder.cs +++ b/ChocolArm64/Decoder/ADecoder.cs @@ -19,7 +19,7 @@ namespace ChocolArm64.Decoder OpActivators = new ConcurrentDictionary(); } - public static ABlock DecodeBasicBlock( + public static (ABlock[] Graph, ABlock Root) DecodeBasicBlock( AThreadState State, ATranslator Translator, AMemory Memory, @@ -29,7 +29,41 @@ namespace ChocolArm64.Decoder FillBlock(State, Memory, Block); - return Block; + AOpCode LastOp = Block.GetLastOp(); + + if (LastOp is AOpCodeBImm Op && Op.Emitter != AInstEmit.Bl) + { + if (Op.Imm == Start) + { + Block.Branch = Block; + } + else if ((ulong)Op.Imm > (ulong)Start && + (ulong)Op.Imm < (ulong)Block.EndPosition) + { + int NewBlockIndex = (int)((Op.Imm - Start) / 4); + + ABlock NewBlock = new ABlock(Op.Imm); + + for (int Index = NewBlockIndex; Index < Block.OpCodes.Count; Index++) + { + NewBlock.OpCodes.Add(Block.OpCodes[Index]); + } + + Block.OpCodes.RemoveRange(NewBlockIndex, Block.OpCodes.Count - NewBlockIndex); + + NewBlock.EndPosition = Block.EndPosition; + + NewBlock.Branch = NewBlock; + + Block.EndPosition = Op.Imm; + + Block.Next = NewBlock; + + return (new ABlock[] { Block, NewBlock }, Block); + } + } + + return (new ABlock[] { Block }, Block); } public static (ABlock[] Graph, ABlock Root) DecodeSubroutine( diff --git a/ChocolArm64/Instruction/AInstEmitFlow.cs b/ChocolArm64/Instruction/AInstEmitFlow.cs index 89979d0509..49f04a03bb 100644 --- a/ChocolArm64/Instruction/AInstEmitFlow.cs +++ b/ChocolArm64/Instruction/AInstEmitFlow.cs @@ -163,10 +163,18 @@ namespace ChocolArm64.Instruction { AOpCodeBImm Op = (AOpCodeBImm)Context.CurrOp; - if (Context.CurrBlock.Next != null && - Context.CurrBlock.Branch != null) + if (Context.CurrBlock.Branch != null) { Context.EmitCondBranch(Context.GetLabel(Op.Imm), Cond); + + if (Context.CurrBlock.Next == null) + { + Context.EmitStoreState(); + + Context.EmitLdc_I8(Op.Position + 4); + + Context.Emit(OpCodes.Ret); + } } else { @@ -192,10 +200,18 @@ namespace ChocolArm64.Instruction { AOpCodeBImm Op = (AOpCodeBImm)Context.CurrOp; - if (Context.CurrBlock.Next != null && - Context.CurrBlock.Branch != null) + if (Context.CurrBlock.Branch != null) { Context.Emit(ILOp, Context.GetLabel(Op.Imm)); + + if (Context.CurrBlock.Next == null) + { + Context.EmitStoreState(); + + Context.EmitLdc_I8(Op.Position + 4); + + Context.Emit(OpCodes.Ret); + } } else {