Refactor PtcInfo (#2625)

* Refactor `PtcInfo`

This change reduces the coupling of `PtcInfo` by moving relocation
tracking to the backend. `RelocEntry`s remains as `RelocEntry`s through
out the pipeline until it actually needs to be written to the PTC
streams. Keeping this representation makes inspecting and manipulating
relocations after compilations less painful. This is something I needed
to do to patch relocations to 0 to diff dumps.

Contributes to #1125.

* Turn `Symbol` & `RelocInfo` into readonly structs

* Add documentation to `CompiledFunction`

* Remove `Compiler.Compile<T>`

Remove `Compiler.Compile<T>` and replace it by `Map<T>` of the
`CompiledFunction` returned.
This commit is contained in:
FICTURE7 2021-09-14 03:23:37 +04:00 committed by GitHub
parent ac4ec1a015
commit a9343c9364
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 256 additions and 247 deletions

View file

@ -1,17 +1,56 @@
using ARMeilleure.CodeGen.Linking;
using ARMeilleure.CodeGen.Unwinding; using ARMeilleure.CodeGen.Unwinding;
using ARMeilleure.Translation.Cache;
using System;
using System.Runtime.InteropServices;
namespace ARMeilleure.CodeGen namespace ARMeilleure.CodeGen
{ {
struct CompiledFunction /// <summary>
/// Represents a compiled function.
/// </summary>
readonly struct CompiledFunction
{ {
/// <summary>
/// Gets the machine code of the <see cref="CompiledFunction"/>.
/// </summary>
public byte[] Code { get; } public byte[] Code { get; }
/// <summary>
/// Gets the <see cref="Unwinding.UnwindInfo"/> of the <see cref="CompiledFunction"/>.
/// </summary>
public UnwindInfo UnwindInfo { get; } public UnwindInfo UnwindInfo { get; }
public CompiledFunction(byte[] code, UnwindInfo unwindInfo) /// <summary>
/// Gets the <see cref="Linking.RelocInfo"/> of the <see cref="CompiledFunction"/>.
/// </summary>
public RelocInfo RelocInfo { get; }
/// <summary>
/// Initializes a new instance of the <see cref="CompiledFunction"/> struct with the specified machine code,
/// unwind info and relocation info.
/// </summary>
/// <param name="code">Machine code</param>
/// <param name="unwindInfo">Unwind info</param>
/// <param name="relocInfo">Relocation info</param>
internal CompiledFunction(byte[] code, UnwindInfo unwindInfo, RelocInfo relocInfo)
{ {
Code = code; Code = code;
UnwindInfo = unwindInfo; UnwindInfo = unwindInfo;
RelocInfo = relocInfo;
}
/// <summary>
/// Maps the <see cref="CompiledFunction"/> onto the <see cref="JitCache"/> and returns a delegate of type
/// <typeparamref name="T"/> pointing to the mapped function.
/// </summary>
/// <typeparam name="T">Type of delegate</typeparam>
/// <returns>A delegate of type <typeparamref name="T"/> pointing to the mapped function</returns>
public T Map<T>()
{
IntPtr codePtr = JitCache.Map(this);
return Marshal.GetDelegateForFunctionPointer<T>(codePtr);
} }
} }
} }

View file

@ -0,0 +1,38 @@
namespace ARMeilleure.CodeGen.Linking
{
/// <summary>
/// Represents a relocation.
/// </summary>
readonly struct RelocEntry
{
public const int Stride = 13; // Bytes.
/// <summary>
/// Gets the position of the relocation.
/// </summary>
public int Position { get; }
/// <summary>
/// Gets the <see cref="Symbol"/> of the relocation.
/// </summary>
public Symbol Symbol { get; }
/// <summary>
/// Initializes a new instance of the <see cref="RelocEntry"/> struct with the specified position and
/// <see cref="Symbol"/>.
/// </summary>
/// <param name="position">Position of relocation</param>
/// <param name="symbol">Symbol of relocation</param>
public RelocEntry(int position, Symbol symbol)
{
Position = position;
Symbol = symbol;
}
/// <inheritdoc/>
public override string ToString()
{
return $"({nameof(Position)} = {Position}, {nameof(Symbol)} = {Symbol})";
}
}
}

View file

@ -0,0 +1,32 @@
using System;
namespace ARMeilleure.CodeGen.Linking
{
/// <summary>
/// Represents relocation information about a <see cref="CompiledFunction"/>.
/// </summary>
readonly struct RelocInfo
{
/// <summary>
/// Gets an empty <see cref="RelocInfo"/>.
/// </summary>
public static RelocInfo Empty { get; } = new RelocInfo(null);
private readonly RelocEntry[] _entries;
/// <summary>
/// Gets the set of <see cref="RelocEntry"/>.
/// </summary>
public ReadOnlySpan<RelocEntry> Entries => _entries ?? Array.Empty<RelocEntry>();
/// <summary>
/// Initializes a new instance of the <see cref="RelocInfo"/> struct with the specified set of
/// <see cref="RelocEntry"/>.
/// </summary>
/// <param name="entries">Set of <see cref="RelocInfo"/> to use</param>
public RelocInfo(RelocEntry[] entries)
{
_entries = entries ?? Array.Empty<RelocEntry>();
}
}
}

View file

@ -1,11 +1,11 @@
using System; using System;
namespace ARMeilleure.Translation.PTC namespace ARMeilleure.CodeGen.Linking
{ {
/// <summary> /// <summary>
/// Represents a symbol. /// Represents a symbol.
/// </summary> /// </summary>
struct Symbol readonly struct Symbol
{ {
private readonly ulong _value; private readonly ulong _value;

View file

@ -1,4 +1,4 @@
namespace ARMeilleure.Translation.PTC namespace ARMeilleure.CodeGen.Linking
{ {
/// <summary> /// <summary>
/// Types of <see cref="Symbol"/>. /// Types of <see cref="Symbol"/>.
@ -11,17 +11,17 @@
None, None,
/// <summary> /// <summary>
/// Refers to an entry in <see cref="Delegates"/>. /// Refers to an entry in <see cref="Translation.Delegates"/>.
/// </summary> /// </summary>
DelegateTable, DelegateTable,
/// <summary> /// <summary>
/// Refers to an entry in <see cref="Translator.FunctionTable"/>. /// Refers to an entry in <see cref="Translation.Translator.FunctionTable"/>.
/// </summary> /// </summary>
FunctionTable, FunctionTable,
/// <summary> /// <summary>
/// Refers to a special symbol which is handled by <see cref="Ptc.PatchCode"/>. /// Refers to a special symbol which is handled by <see cref="Translation.PTC.Ptc.PatchCode"/>.
/// </summary> /// </summary>
Special Special
} }

View file

@ -1,6 +1,7 @@
using ARMeilleure.CodeGen.Linking;
using ARMeilleure.IntermediateRepresentation; using ARMeilleure.IntermediateRepresentation;
using ARMeilleure.Translation.PTC;
using System; using System;
using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
@ -61,12 +62,12 @@ namespace ARMeilleure.CodeGen.X86
} }
} }
private static InstructionInfo[] _instTable; private readonly static InstructionInfo[] _instTable;
private Stream _stream; private readonly Stream _stream;
private PtcInfo _ptcInfo; public List<RelocEntry> Relocs { get; }
private bool _ptcDisabled; public bool HasRelocs => Relocs != null;
static Assembler() static Assembler()
{ {
@ -294,12 +295,10 @@ namespace ARMeilleure.CodeGen.X86
_instTable[(int)inst] = info; _instTable[(int)inst] = info;
} }
public Assembler(Stream stream, PtcInfo ptcInfo = null) public Assembler(Stream stream, bool relocatable)
{ {
_stream = stream; _stream = stream;
Relocs = relocatable ? new List<RelocEntry>() : null;
_ptcInfo = ptcInfo;
_ptcDisabled = ptcInfo == null;
} }
public void Add(Operand dest, Operand source, OperandType type) public void Add(Operand dest, Operand source, OperandType type)
@ -498,7 +497,7 @@ namespace ARMeilleure.CodeGen.X86
public void Jcc(X86Condition condition, long offset) public void Jcc(X86Condition condition, long offset)
{ {
if (_ptcDisabled && ConstFitsOnS8(offset)) if (!HasRelocs && ConstFitsOnS8(offset))
{ {
WriteByte((byte)(0x70 | (int)condition)); WriteByte((byte)(0x70 | (int)condition));
@ -519,7 +518,7 @@ namespace ARMeilleure.CodeGen.X86
public void Jmp(long offset) public void Jmp(long offset)
{ {
if (_ptcDisabled && ConstFitsOnS8(offset)) if (!HasRelocs && ConstFitsOnS8(offset))
{ {
WriteByte(0xeb); WriteByte(0xeb);
@ -980,9 +979,9 @@ namespace ARMeilleure.CodeGen.X86
WriteByte((byte)(info.OpRImm64 + (dest.GetRegister().Index & 0b111))); WriteByte((byte)(info.OpRImm64 + (dest.GetRegister().Index & 0b111)));
if (_ptcInfo != default && source.Relocatable) if (HasRelocs && source.Relocatable)
{ {
_ptcInfo.WriteRelocEntry(new RelocEntry((int)_stream.Position, source.Symbol)); Relocs.Add(new RelocEntry((int)_stream.Position, source.Symbol));
} }
WriteUInt64(imm); WriteUInt64(imm);
@ -1396,9 +1395,9 @@ namespace ARMeilleure.CodeGen.X86
return ConstFitsOnS32(value); return ConstFitsOnS32(value);
} }
public static int GetJccLength(long offset, bool ptcDisabled = true) public static int GetJccLength(long offset, bool relocatable = false)
{ {
if (ptcDisabled && ConstFitsOnS8(offset < 0 ? offset - 2 : offset)) if (!relocatable && ConstFitsOnS8(offset < 0 ? offset - 2 : offset))
{ {
return 2; return 2;
} }
@ -1412,9 +1411,9 @@ namespace ARMeilleure.CodeGen.X86
} }
} }
public static int GetJmpLength(long offset, bool ptcDisabled = true) public static int GetJmpLength(long offset, bool relocatable = false)
{ {
if (ptcDisabled && ConstFitsOnS8(offset < 0 ? offset - 2 : offset)) if (!relocatable && ConstFitsOnS8(offset < 0 ? offset - 2 : offset))
{ {
return 2; return 2;
} }

View file

@ -1,7 +1,7 @@
using ARMeilleure.CodeGen.Linking;
using ARMeilleure.CodeGen.RegisterAllocators; using ARMeilleure.CodeGen.RegisterAllocators;
using ARMeilleure.Common; using ARMeilleure.Common;
using ARMeilleure.IntermediateRepresentation; using ARMeilleure.IntermediateRepresentation;
using ARMeilleure.Translation.PTC;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
@ -13,10 +13,8 @@ namespace ARMeilleure.CodeGen.X86
{ {
private const int ReservedBytesForJump = 1; private const int ReservedBytesForJump = 1;
private Stream _stream; private readonly Stream _stream;
private readonly bool _relocatable;
private PtcInfo _ptcInfo;
private bool _ptcDisabled;
public int StreamOffset => (int)_stream.Length; public int StreamOffset => (int)_stream.Length;
@ -27,22 +25,17 @@ namespace ARMeilleure.CodeGen.X86
public BasicBlock CurrBlock { get; private set; } public BasicBlock CurrBlock { get; private set; }
public int CallArgsRegionSize { get; } public int CallArgsRegionSize { get; }
public int XmmSaveRegionSize { get; } public int XmmSaveRegionSize { get; }
private long[] _blockOffsets; private readonly long[] _blockOffsets;
private struct Jump private struct Jump
{ {
public bool IsConditional { get; } public bool IsConditional { get; }
public X86Condition Condition { get; } public X86Condition Condition { get; }
public BasicBlock Target { get; } public BasicBlock Target { get; }
public long JumpPosition { get; } public long JumpPosition { get; }
public long RelativeOffset { get; set; } public long RelativeOffset { get; set; }
public int InstSize { get; set; } public int InstSize { get; set; }
public Jump(BasicBlock target, long jumpPosition, int instSize = 0) public Jump(BasicBlock target, long jumpPosition, int instSize = 0)
@ -70,33 +63,26 @@ namespace ARMeilleure.CodeGen.X86
} }
} }
private List<Jump> _jumps; private readonly List<Jump> _jumps;
private X86Condition _jNearCondition; private X86Condition _jNearCondition;
private long _jNearPosition; private long _jNearPosition;
private int _jNearLength; private int _jNearLength;
public CodeGenContext(Stream stream, AllocationResult allocResult, int maxCallArgs, int blocksCount, PtcInfo ptcInfo = null) public CodeGenContext(Stream stream, AllocationResult allocResult, int maxCallArgs, int blocksCount, bool relocatable)
{ {
_stream = stream; _stream = stream;
_relocatable = relocatable;
AllocResult = allocResult;
Assembler = new Assembler(stream, ptcInfo);
CallArgsRegionSize = GetCallArgsRegionSize(allocResult, maxCallArgs, out int xmmSaveRegionSize);
XmmSaveRegionSize = xmmSaveRegionSize;
_blockOffsets = new long[blocksCount]; _blockOffsets = new long[blocksCount];
_jumps = new List<Jump>(); _jumps = new List<Jump>();
_ptcInfo = ptcInfo; AllocResult = allocResult;
_ptcDisabled = ptcInfo == null; Assembler = new Assembler(stream, relocatable);
CallArgsRegionSize = GetCallArgsRegionSize(allocResult, maxCallArgs, out int xmmSaveRegionSize);
XmmSaveRegionSize = xmmSaveRegionSize;
} }
private int GetCallArgsRegionSize(AllocationResult allocResult, int maxCallArgs, out int xmmSaveRegionSize) private static int GetCallArgsRegionSize(AllocationResult allocResult, int maxCallArgs, out int xmmSaveRegionSize)
{ {
// We need to add 8 bytes to the total size, as the call to this // We need to add 8 bytes to the total size, as the call to this
// function already pushed 8 bytes (the return address). // function already pushed 8 bytes (the return address).
@ -144,7 +130,7 @@ namespace ARMeilleure.CodeGen.X86
public void JumpTo(BasicBlock target) public void JumpTo(BasicBlock target)
{ {
if (_ptcDisabled) if (!_relocatable)
{ {
_jumps.Add(new Jump(target, _stream.Position)); _jumps.Add(new Jump(target, _stream.Position));
@ -160,7 +146,7 @@ namespace ARMeilleure.CodeGen.X86
public void JumpTo(X86Condition condition, BasicBlock target) public void JumpTo(X86Condition condition, BasicBlock target)
{ {
if (_ptcDisabled) if (!_relocatable)
{ {
_jumps.Add(new Jump(condition, target, _stream.Position)); _jumps.Add(new Jump(condition, target, _stream.Position));
@ -178,7 +164,7 @@ namespace ARMeilleure.CodeGen.X86
{ {
_jNearCondition = condition; _jNearCondition = condition;
_jNearPosition = _stream.Position; _jNearPosition = _stream.Position;
_jNearLength = Assembler.GetJccLength(0, _ptcDisabled); _jNearLength = Assembler.GetJccLength(0, _relocatable);
_stream.Seek(_jNearLength, SeekOrigin.Current); _stream.Seek(_jNearLength, SeekOrigin.Current);
} }
@ -191,7 +177,7 @@ namespace ARMeilleure.CodeGen.X86
long offset = currentPosition - (_jNearPosition + _jNearLength); long offset = currentPosition - (_jNearPosition + _jNearLength);
Debug.Assert(_jNearLength == Assembler.GetJccLength(offset, _ptcDisabled), "Relative offset doesn't fit on near jump."); Debug.Assert(_jNearLength == Assembler.GetJccLength(offset, _relocatable), "Relative offset doesn't fit on near jump.");
Assembler.Jcc(_jNearCondition, offset); Assembler.Jcc(_jNearCondition, offset);
@ -206,7 +192,7 @@ namespace ARMeilleure.CodeGen.X86
} }
} }
public byte[] GetCode() public (byte[], RelocInfo) GetCode()
{ {
// Write jump relative offsets. // Write jump relative offsets.
bool modified; bool modified;
@ -223,7 +209,7 @@ namespace ARMeilleure.CodeGen.X86
long offset = jumpTarget - jump.JumpPosition; long offset = jumpTarget - jump.JumpPosition;
if (_ptcDisabled) if (!_relocatable)
{ {
if (offset < 0) if (offset < 0)
{ {
@ -300,7 +286,7 @@ namespace ARMeilleure.CodeGen.X86
using (MemoryStream codeStream = new MemoryStream()) using (MemoryStream codeStream = new MemoryStream())
{ {
Assembler assembler = new Assembler(codeStream, _ptcInfo); Assembler assembler = new Assembler(codeStream, _relocatable);
for (int index = 0; index < _jumps.Count; index++) for (int index = 0; index < _jumps.Count; index++)
{ {
@ -309,7 +295,7 @@ namespace ARMeilleure.CodeGen.X86
Span<byte> buffer = new byte[jump.JumpPosition - _stream.Position]; Span<byte> buffer = new byte[jump.JumpPosition - _stream.Position];
_stream.Read(buffer); _stream.Read(buffer);
_stream.Seek(_ptcDisabled ? ReservedBytesForJump : jump.InstSize, SeekOrigin.Current); _stream.Seek(!_relocatable ? ReservedBytesForJump : jump.InstSize, SeekOrigin.Current);
codeStream.Write(buffer); codeStream.Write(buffer);
@ -325,7 +311,12 @@ namespace ARMeilleure.CodeGen.X86
_stream.CopyTo(codeStream); _stream.CopyTo(codeStream);
return codeStream.ToArray(); var code = codeStream.ToArray();
var relocInfo = Assembler.HasRelocs
? new RelocInfo(Assembler.Relocs.ToArray())
: RelocInfo.Empty;
return (code, relocInfo);
} }
} }
} }

View file

@ -1,3 +1,4 @@
using ARMeilleure.CodeGen.Linking;
using ARMeilleure.CodeGen.Optimizations; using ARMeilleure.CodeGen.Optimizations;
using ARMeilleure.CodeGen.RegisterAllocators; using ARMeilleure.CodeGen.RegisterAllocators;
using ARMeilleure.CodeGen.Unwinding; using ARMeilleure.CodeGen.Unwinding;
@ -5,7 +6,6 @@ using ARMeilleure.Common;
using ARMeilleure.Diagnostics; using ARMeilleure.Diagnostics;
using ARMeilleure.IntermediateRepresentation; using ARMeilleure.IntermediateRepresentation;
using ARMeilleure.Translation; using ARMeilleure.Translation;
using ARMeilleure.Translation.PTC;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
@ -91,7 +91,7 @@ namespace ARMeilleure.CodeGen.X86
_instTable[(int)inst] = func; _instTable[(int)inst] = func;
} }
public static CompiledFunction Generate(CompilerContext cctx, PtcInfo ptcInfo = null) public static CompiledFunction Generate(CompilerContext cctx)
{ {
ControlFlowGraph cfg = cctx.Cfg; ControlFlowGraph cfg = cctx.Cfg;
@ -149,53 +149,47 @@ namespace ARMeilleure.CodeGen.X86
Logger.StartPass(PassName.CodeGeneration); Logger.StartPass(PassName.CodeGeneration);
using (MemoryStream stream = new MemoryStream()) bool relocatable = (cctx.Options & CompilerOptions.Relocatable) != 0;
using MemoryStream stream = new();
CodeGenContext context = new(stream, allocResult, maxCallArgs, cfg.Blocks.Count, relocatable);
UnwindInfo unwindInfo = WritePrologue(context);
for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext)
{ {
CodeGenContext context = new CodeGenContext(stream, allocResult, maxCallArgs, cfg.Blocks.Count, ptcInfo); context.EnterBlock(block);
UnwindInfo unwindInfo = WritePrologue(context); for (Operation node = block.Operations.First; node != default; node = node.ListNext)
ptcInfo?.WriteUnwindInfo(unwindInfo);
for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext)
{ {
context.EnterBlock(block); GenerateOperation(context, node);
for (Operation node = block.Operations.First; node != default; node = node.ListNext)
{
GenerateOperation(context, node);
}
if (block.SuccessorsCount == 0)
{
// The only blocks which can have 0 successors are exit blocks.
Operation last = block.Operations.Last;
Debug.Assert(last.Instruction == Instruction.Tailcall ||
last.Instruction == Instruction.Return);
}
else
{
BasicBlock succ = block.GetSuccessor(0);
if (succ != block.ListNext)
{
context.JumpTo(succ);
}
}
} }
byte[] code = context.GetCode(); if (block.SuccessorsCount == 0)
if (ptcInfo != null)
{ {
ptcInfo.Code = code; // The only blocks which can have 0 successors are exit blocks.
Operation last = block.Operations.Last;
Debug.Assert(last.Instruction == Instruction.Tailcall ||
last.Instruction == Instruction.Return);
} }
else
{
BasicBlock succ = block.GetSuccessor(0);
Logger.EndPass(PassName.CodeGeneration); if (succ != block.ListNext)
{
return new CompiledFunction(code, unwindInfo); context.JumpTo(succ);
}
}
} }
(byte[] code, RelocInfo relocInfo) = context.GetCode();
Logger.EndPass(PassName.CodeGeneration);
return new CompiledFunction(code, unwindInfo, relocInfo);
} }
private static void GenerateOperation(CodeGenContext context, Operation operation) private static void GenerateOperation(CodeGenContext context, Operation operation)

View file

@ -1,8 +1,8 @@
using ARMeilleure.CodeGen.Linking;
using ARMeilleure.Decoders; using ARMeilleure.Decoders;
using ARMeilleure.IntermediateRepresentation; using ARMeilleure.IntermediateRepresentation;
using ARMeilleure.State; using ARMeilleure.State;
using ARMeilleure.Translation; using ARMeilleure.Translation;
using ARMeilleure.Translation.Cache;
using ARMeilleure.Translation.PTC; using ARMeilleure.Translation.PTC;
using static ARMeilleure.Instructions.InstEmitHelper; using static ARMeilleure.Instructions.InstEmitHelper;

View file

@ -1,5 +1,5 @@
using ARMeilleure.CodeGen.Linking;
using ARMeilleure.Common; using ARMeilleure.Common;
using ARMeilleure.Translation.PTC;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;

View file

@ -261,7 +261,7 @@ namespace ARMeilleure.Signal
OperandType[] argTypes = new OperandType[] { OperandType.I32, OperandType.I64, OperandType.I64 }; OperandType[] argTypes = new OperandType[] { OperandType.I32, OperandType.I64, OperandType.I64 };
return Compiler.Compile<UnixExceptionHandler>(cfg, argTypes, OperandType.None, CompilerOptions.HighCq); return Compiler.Compile(cfg, argTypes, OperandType.None, CompilerOptions.HighCq).Map<UnixExceptionHandler>();
} }
private static VectoredExceptionHandler GenerateWindowsSignalHandler(IntPtr signalStructPtr) private static VectoredExceptionHandler GenerateWindowsSignalHandler(IntPtr signalStructPtr)
@ -315,7 +315,7 @@ namespace ARMeilleure.Signal
OperandType[] argTypes = new OperandType[] { OperandType.I64 }; OperandType[] argTypes = new OperandType[] { OperandType.I64 };
return Compiler.Compile<VectoredExceptionHandler>(cfg, argTypes, OperandType.I32, CompilerOptions.HighCq); return Compiler.Compile(cfg, argTypes, OperandType.I32, CompilerOptions.HighCq).Map<VectoredExceptionHandler>();
} }
} }
} }

View file

@ -1,3 +1,4 @@
using ARMeilleure.CodeGen.Linking;
using ARMeilleure.Common; using ARMeilleure.Common;
using ARMeilleure.Decoders; using ARMeilleure.Decoders;
using ARMeilleure.Diagnostics; using ARMeilleure.Diagnostics;

View file

@ -2,35 +2,16 @@ using ARMeilleure.CodeGen;
using ARMeilleure.CodeGen.X86; using ARMeilleure.CodeGen.X86;
using ARMeilleure.Diagnostics; using ARMeilleure.Diagnostics;
using ARMeilleure.IntermediateRepresentation; using ARMeilleure.IntermediateRepresentation;
using ARMeilleure.Translation.Cache;
using ARMeilleure.Translation.PTC;
using System;
using System.Runtime.InteropServices;
namespace ARMeilleure.Translation namespace ARMeilleure.Translation
{ {
static class Compiler static class Compiler
{ {
public static T Compile<T>(
ControlFlowGraph cfg,
OperandType[] argTypes,
OperandType retType,
CompilerOptions options,
PtcInfo ptcInfo = null)
{
CompiledFunction func = Compile(cfg, argTypes, retType, options, ptcInfo);
IntPtr codePtr = JitCache.Map(func);
return Marshal.GetDelegateForFunctionPointer<T>(codePtr);
}
public static CompiledFunction Compile( public static CompiledFunction Compile(
ControlFlowGraph cfg, ControlFlowGraph cfg,
OperandType[] argTypes, OperandType[] argTypes,
OperandType retType, OperandType retType,
CompilerOptions options, CompilerOptions options)
PtcInfo ptcInfo = null)
{ {
Logger.StartPass(PassName.Dominance); Logger.StartPass(PassName.Dominance);
@ -57,7 +38,7 @@ namespace ARMeilleure.Translation
CompilerContext cctx = new(cfg, argTypes, retType, options); CompilerContext cctx = new(cfg, argTypes, retType, options);
return CodeGenerator.Generate(cctx, ptcInfo); return CodeGenerator.Generate(cctx);
} }
} }
} }

View file

@ -5,10 +5,11 @@ namespace ARMeilleure.Translation
[Flags] [Flags]
enum CompilerOptions enum CompilerOptions
{ {
None = 0, None = 0,
SsaForm = 1 << 0, SsaForm = 1 << 0,
Optimize = 1 << 1, Optimize = 1 << 1,
Lsra = 1 << 2, Lsra = 1 << 2,
Relocatable = 1 << 3,
MediumCq = SsaForm | Optimize, MediumCq = SsaForm | Optimize,
HighCq = SsaForm | Optimize | Lsra HighCq = SsaForm | Optimize | Lsra

View file

@ -1,9 +1,9 @@
using ARMeilleure.CodeGen; using ARMeilleure.CodeGen;
using ARMeilleure.CodeGen.Linking;
using ARMeilleure.CodeGen.Unwinding; using ARMeilleure.CodeGen.Unwinding;
using ARMeilleure.CodeGen.X86; using ARMeilleure.CodeGen.X86;
using ARMeilleure.Common; using ARMeilleure.Common;
using ARMeilleure.Memory; using ARMeilleure.Memory;
using ARMeilleure.Translation.Cache;
using Ryujinx.Common; using Ryujinx.Common;
using Ryujinx.Common.Configuration; using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
@ -727,15 +727,10 @@ namespace ARMeilleure.Translation.PTC
UnwindInfo unwindInfo, UnwindInfo unwindInfo,
bool highCq) bool highCq)
{ {
CompiledFunction cFunc = new CompiledFunction(code, unwindInfo); var cFunc = new CompiledFunction(code, unwindInfo, RelocInfo.Empty);
var gFunc = cFunc.Map<GuestFunction>();
IntPtr codePtr = JitCache.Map(cFunc); return new TranslatedFunction(gFunc, callCounter, guestSize, highCq);
GuestFunction gFunc = Marshal.GetDelegateForFunctionPointer<GuestFunction>(codePtr);
TranslatedFunction tFunc = new TranslatedFunction(gFunc, callCounter, guestSize, highCq);
return tFunc;
} }
private static void UpdateInfo(InfoEntry infoEntry) private static void UpdateInfo(InfoEntry infoEntry)
@ -889,10 +884,14 @@ namespace ARMeilleure.Translation.PTC
return XXHash128.ComputeHash(memory.GetSpan(address, checked((int)(guestSize)))); return XXHash128.ComputeHash(memory.GetSpan(address, checked((int)(guestSize))));
} }
internal static void WriteInfoCodeRelocUnwindInfo(ulong address, ulong guestSize, Hash128 hash, bool highCq, PtcInfo ptcInfo) internal static void WriteCompiledFunction(ulong address, ulong guestSize, Hash128 hash, bool highCq, CompiledFunction compiledFunc)
{ {
lock (_lock) lock (_lock)
{ {
byte[] code = compiledFunc.Code;
RelocInfo relocInfo = compiledFunc.RelocInfo;
UnwindInfo unwindInfo = compiledFunc.UnwindInfo;
InfoEntry infoEntry = new InfoEntry(); InfoEntry infoEntry = new InfoEntry();
infoEntry.Address = address; infoEntry.Address = address;
@ -900,18 +899,37 @@ namespace ARMeilleure.Translation.PTC
infoEntry.Hash = hash; infoEntry.Hash = hash;
infoEntry.HighCq = highCq; infoEntry.HighCq = highCq;
infoEntry.Stubbed = false; infoEntry.Stubbed = false;
infoEntry.CodeLength = ptcInfo.Code.Length; infoEntry.CodeLength = code.Length;
infoEntry.RelocEntriesCount = ptcInfo.RelocEntriesCount; infoEntry.RelocEntriesCount = relocInfo.Entries.Length;
SerializeStructure(_infosStream, infoEntry); SerializeStructure(_infosStream, infoEntry);
WriteCode(ptcInfo.Code.AsSpan()); WriteCode(code.AsSpan());
// WriteReloc. // WriteReloc.
ptcInfo.RelocStream.WriteTo(_relocsStream); using var relocInfoWriter = new BinaryWriter(_relocsStream, EncodingCache.UTF8NoBOM, true);
foreach (RelocEntry entry in relocInfo.Entries)
{
relocInfoWriter.Write(entry.Position);
relocInfoWriter.Write((byte)entry.Symbol.Type);
relocInfoWriter.Write(entry.Symbol.Value);
}
// WriteUnwindInfo. // WriteUnwindInfo.
ptcInfo.UnwindInfoStream.WriteTo(_unwindInfosStream); using var unwindInfoWriter = new BinaryWriter(_unwindInfosStream, EncodingCache.UTF8NoBOM, true);
unwindInfoWriter.Write(unwindInfo.PushEntries.Length);
foreach (UnwindPushEntry unwindPushEntry in unwindInfo.PushEntries)
{
unwindInfoWriter.Write((int)unwindPushEntry.PseudoOp);
unwindInfoWriter.Write(unwindPushEntry.PrologOffset);
unwindInfoWriter.Write(unwindPushEntry.RegIndex);
unwindInfoWriter.Write(unwindPushEntry.StackOffsetOrAllocSize);
}
unwindInfoWriter.Write(unwindInfo.PrologSize);
} }
} }

View file

@ -1,63 +0,0 @@
using ARMeilleure.CodeGen.Unwinding;
using System;
using System.IO;
namespace ARMeilleure.Translation.PTC
{
class PtcInfo : IDisposable
{
private readonly BinaryWriter _relocWriter;
private readonly BinaryWriter _unwindInfoWriter;
public byte[] Code { get; set; }
public MemoryStream RelocStream { get; }
public MemoryStream UnwindInfoStream { get; }
public int RelocEntriesCount { get; private set; }
public PtcInfo()
{
RelocStream = new MemoryStream();
UnwindInfoStream = new MemoryStream();
_relocWriter = new BinaryWriter(RelocStream, EncodingCache.UTF8NoBOM, true);
_unwindInfoWriter = new BinaryWriter(UnwindInfoStream, EncodingCache.UTF8NoBOM, true);
RelocEntriesCount = 0;
}
public void WriteRelocEntry(RelocEntry relocEntry)
{
_relocWriter.Write((int)relocEntry.Position);
_relocWriter.Write((byte)relocEntry.Symbol.Type);
_relocWriter.Write((ulong)relocEntry.Symbol.Value);
RelocEntriesCount++;
}
public void WriteUnwindInfo(UnwindInfo unwindInfo)
{
_unwindInfoWriter.Write((int)unwindInfo.PushEntries.Length);
foreach (UnwindPushEntry unwindPushEntry in unwindInfo.PushEntries)
{
_unwindInfoWriter.Write((int)unwindPushEntry.PseudoOp);
_unwindInfoWriter.Write((int)unwindPushEntry.PrologOffset);
_unwindInfoWriter.Write((int)unwindPushEntry.RegIndex);
_unwindInfoWriter.Write((int)unwindPushEntry.StackOffsetOrAllocSize);
}
_unwindInfoWriter.Write((int)unwindInfo.PrologSize);
}
public void Dispose()
{
_relocWriter.Dispose();
_unwindInfoWriter.Dispose();
RelocStream.Dispose();
UnwindInfoStream.Dispose();
}
}
}

View file

@ -1,21 +0,0 @@
namespace ARMeilleure.Translation.PTC
{
struct RelocEntry
{
public const int Stride = 13; // Bytes.
public int Position;
public Symbol Symbol;
public RelocEntry(int position, Symbol symbol)
{
Position = position;
Symbol = symbol;
}
public override string ToString()
{
return $"({nameof(Position)} = {Position}, {nameof(Symbol)} = {Symbol})";
}
}
}

View file

@ -1,3 +1,4 @@
using ARMeilleure.CodeGen;
using ARMeilleure.Common; using ARMeilleure.Common;
using ARMeilleure.Decoders; using ARMeilleure.Decoders;
using ARMeilleure.Diagnostics; using ARMeilleure.Diagnostics;
@ -279,32 +280,30 @@ namespace ARMeilleure.Translation
Logger.EndPass(PassName.RegisterUsage); Logger.EndPass(PassName.RegisterUsage);
OperandType[] argTypes = new OperandType[] { OperandType.I64 }; var retType = OperandType.I64;
var argTypes = new OperandType[] { OperandType.I64 };
CompilerOptions options = highCq ? CompilerOptions.HighCq : CompilerOptions.None; var options = highCq ? CompilerOptions.HighCq : CompilerOptions.None;
GuestFunction func; if (context.HasPtc)
if (!context.HasPtc)
{ {
func = Compiler.Compile<GuestFunction>(cfg, argTypes, OperandType.I64, options); options |= CompilerOptions.Relocatable;
} }
else
CompiledFunction compiledFunc = Compiler.Compile(cfg, argTypes, retType, options);
if (context.HasPtc)
{ {
using PtcInfo ptcInfo = new PtcInfo();
func = Compiler.Compile<GuestFunction>(cfg, argTypes, OperandType.I64, options, ptcInfo);
Hash128 hash = Ptc.ComputeHash(Memory, address, funcSize); Hash128 hash = Ptc.ComputeHash(Memory, address, funcSize);
Ptc.WriteInfoCodeRelocUnwindInfo(address, funcSize, hash, highCq, ptcInfo); Ptc.WriteCompiledFunction(address, funcSize, hash, highCq, compiledFunc);
} }
var result = new TranslatedFunction(func, counter, funcSize, highCq); GuestFunction func = compiledFunc.Map<GuestFunction>();
Allocators.ResetAll(); Allocators.ResetAll();
return result; return new TranslatedFunction(func, counter, funcSize, highCq);
} }
private struct Range private struct Range

View file

@ -178,7 +178,7 @@ namespace ARMeilleure.Translation
var retType = OperandType.I64; var retType = OperandType.I64;
var argTypes = new[] { OperandType.I64 }; var argTypes = new[] { OperandType.I64 };
var func = Compiler.Compile<GuestFunction>(cfg, argTypes, retType, CompilerOptions.HighCq); var func = Compiler.Compile(cfg, argTypes, retType, CompilerOptions.HighCq).Map<GuestFunction>();
return Marshal.GetFunctionPointerForDelegate(func); return Marshal.GetFunctionPointerForDelegate(func);
} }
@ -204,7 +204,7 @@ namespace ARMeilleure.Translation
var retType = OperandType.I64; var retType = OperandType.I64;
var argTypes = new[] { OperandType.I64 }; var argTypes = new[] { OperandType.I64 };
var func = Compiler.Compile<GuestFunction>(cfg, argTypes, retType, CompilerOptions.HighCq); var func = Compiler.Compile(cfg, argTypes, retType, CompilerOptions.HighCq).Map<GuestFunction>();
return Marshal.GetFunctionPointerForDelegate(func); return Marshal.GetFunctionPointerForDelegate(func);
} }
@ -242,7 +242,7 @@ namespace ARMeilleure.Translation
var retType = OperandType.None; var retType = OperandType.None;
var argTypes = new[] { OperandType.I64, OperandType.I64 }; var argTypes = new[] { OperandType.I64, OperandType.I64 };
return Compiler.Compile<DispatcherFunction>(cfg, argTypes, retType, CompilerOptions.HighCq); return Compiler.Compile(cfg, argTypes, retType, CompilerOptions.HighCq).Map<DispatcherFunction>();
} }
} }
} }