aboutsummaryrefslogtreecommitdiff
path: root/ARMeilleure/CodeGen/X86/CodeGenContext.cs
diff options
context:
space:
mode:
Diffstat (limited to 'ARMeilleure/CodeGen/X86/CodeGenContext.cs')
-rw-r--r--ARMeilleure/CodeGen/X86/CodeGenContext.cs273
1 files changed, 27 insertions, 246 deletions
diff --git a/ARMeilleure/CodeGen/X86/CodeGenContext.cs b/ARMeilleure/CodeGen/X86/CodeGenContext.cs
index 7e96dd85..eee71bd7 100644
--- a/ARMeilleure/CodeGen/X86/CodeGenContext.cs
+++ b/ARMeilleure/CodeGen/X86/CodeGenContext.cs
@@ -1,118 +1,69 @@
-using ARMeilleure.CodeGen.Linking;
using ARMeilleure.CodeGen.RegisterAllocators;
-using ARMeilleure.Common;
using ARMeilleure.IntermediateRepresentation;
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
using System.IO;
+using System.Numerics;
namespace ARMeilleure.CodeGen.X86
{
class CodeGenContext
{
- private const int ReservedBytesForJump = 1;
-
private readonly Stream _stream;
- private readonly bool _relocatable;
+ private readonly Operand[] _blockLabels;
public int StreamOffset => (int)_stream.Length;
public AllocationResult AllocResult { get; }
public Assembler Assembler { get; }
-
public BasicBlock CurrBlock { get; private set; }
public int CallArgsRegionSize { get; }
public int XmmSaveRegionSize { get; }
- private readonly long[] _blockOffsets;
-
- private struct Jump
+ public CodeGenContext(AllocationResult allocResult, int maxCallArgs, int blocksCount, bool relocatable)
{
- public bool IsConditional { get; }
- public X86Condition Condition { get; }
- public BasicBlock Target { get; }
- public long JumpPosition { get; }
- public long RelativeOffset { get; set; }
- public int InstSize { get; set; }
-
- public Jump(BasicBlock target, long jumpPosition, int instSize = 0)
- {
- IsConditional = false;
- Condition = 0;
- Target = target;
- JumpPosition = jumpPosition;
-
- RelativeOffset = 0;
-
- InstSize = instSize;
- }
-
- public Jump(X86Condition condition, BasicBlock target, long jumpPosition, int instSize = 0)
- {
- IsConditional = true;
- Condition = condition;
- Target = target;
- JumpPosition = jumpPosition;
-
- RelativeOffset = 0;
-
- InstSize = instSize;
- }
- }
-
- private readonly List<Jump> _jumps;
-
- private X86Condition _jNearCondition;
- private long _jNearPosition;
- private int _jNearLength;
-
- public CodeGenContext(Stream stream, AllocationResult allocResult, int maxCallArgs, int blocksCount, bool relocatable)
- {
- _stream = stream;
- _relocatable = relocatable;
- _blockOffsets = new long[blocksCount];
- _jumps = new List<Jump>();
+ _stream = new MemoryStream();
+ _blockLabels = new Operand[blocksCount];
AllocResult = allocResult;
- Assembler = new Assembler(stream, relocatable);
+ Assembler = new Assembler(_stream, relocatable);
+
CallArgsRegionSize = GetCallArgsRegionSize(allocResult, maxCallArgs, out int xmmSaveRegionSize);
XmmSaveRegionSize = 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
- // function already pushed 8 bytes (the return address).
+ // We need to add 8 bytes to the total size, as the call to this function already pushed 8 bytes (the
+ // return address).
int intMask = CallingConvention.GetIntCalleeSavedRegisters() & allocResult.IntUsedRegisters;
int vecMask = CallingConvention.GetVecCalleeSavedRegisters() & allocResult.VecUsedRegisters;
- xmmSaveRegionSize = BitUtils.CountBits(vecMask) * 16;
+ xmmSaveRegionSize = BitOperations.PopCount((uint)vecMask) * 16;
- int calleeSaveRegionSize = BitUtils.CountBits(intMask) * 8 + xmmSaveRegionSize + 8;
+ int calleeSaveRegionSize = BitOperations.PopCount((uint)intMask) * 8 + xmmSaveRegionSize + 8;
int argsCount = maxCallArgs;
if (argsCount < 0)
{
- // When the function has no calls, argsCount is -1.
- // In this case, we don't need to allocate the shadow space.
+ // When the function has no calls, argsCount is -1. In this case, we don't need to allocate the shadow
+ // space.
argsCount = 0;
}
else if (argsCount < 4)
{
- // The ABI mandates that the space for at least 4 arguments
- // is reserved on the stack (this is called shadow space).
+ // The ABI mandates that the space for at least 4 arguments is reserved on the stack (this is called
+ // shadow space).
argsCount = 4;
}
+ // TODO: Align XMM save region to 16 bytes because unwinding on Windows requires it.
int frameSize = calleeSaveRegionSize + allocResult.SpillRegionSize;
- // TODO: Instead of always multiplying by 16 (the largest possible size of a variable,
- // since a V128 has 16 bytes), we should calculate the exact size consumed by the
- // arguments passed to the called functions on the stack.
+ // TODO: Instead of always multiplying by 16 (the largest possible size of a variable, since a V128 has 16
+ // bytes), we should calculate the exact size consumed by the arguments passed to the called functions on
+ // the stack.
int callArgsAndFrameSize = frameSize + argsCount * 16;
// Ensure that the Stack Pointer will be aligned to 16 bytes.
@@ -123,201 +74,31 @@ namespace ARMeilleure.CodeGen.X86
public void EnterBlock(BasicBlock block)
{
- _blockOffsets[block.Index] = _stream.Position;
+ Assembler.MarkLabel(GetLabel(block));
CurrBlock = block;
}
public void JumpTo(BasicBlock target)
{
- if (!_relocatable)
- {
- _jumps.Add(new Jump(target, _stream.Position));
-
- WritePadding(ReservedBytesForJump);
- }
- else
- {
- _jumps.Add(new Jump(target, _stream.Position, 5));
-
- WritePadding(5);
- }
+ Assembler.Jmp(GetLabel(target));
}
public void JumpTo(X86Condition condition, BasicBlock target)
{
- if (!_relocatable)
- {
- _jumps.Add(new Jump(condition, target, _stream.Position));
-
- WritePadding(ReservedBytesForJump);
- }
- else
- {
- _jumps.Add(new Jump(condition, target, _stream.Position, 6));
-
- WritePadding(6);
- }
- }
-
- public void JumpToNear(X86Condition condition)
- {
- _jNearCondition = condition;
- _jNearPosition = _stream.Position;
- _jNearLength = Assembler.GetJccLength(0, _relocatable);
-
- _stream.Seek(_jNearLength, SeekOrigin.Current);
+ Assembler.Jcc(condition, GetLabel(target));
}
- public void JumpHere()
+ private Operand GetLabel(BasicBlock block)
{
- long currentPosition = _stream.Position;
-
- _stream.Seek(_jNearPosition, SeekOrigin.Begin);
-
- long offset = currentPosition - (_jNearPosition + _jNearLength);
+ ref Operand label = ref _blockLabels[block.Index];
- Debug.Assert(_jNearLength == Assembler.GetJccLength(offset, _relocatable), "Relative offset doesn't fit on near jump.");
-
- Assembler.Jcc(_jNearCondition, offset);
-
- _stream.Seek(currentPosition, SeekOrigin.Begin);
- }
-
- private void WritePadding(int size)
- {
- while (size-- > 0)
- {
- _stream.WriteByte(0);
- }
- }
-
- public (byte[], RelocInfo) GetCode()
- {
- // Write jump relative offsets.
- bool modified;
-
- do
+ if (label == default)
{
- modified = false;
-
- for (int index = 0; index < _jumps.Count; index++)
- {
- Jump jump = _jumps[index];
-
- long jumpTarget = _blockOffsets[jump.Target.Index];
-
- long offset = jumpTarget - jump.JumpPosition;
-
- if (!_relocatable)
- {
- if (offset < 0)
- {
- for (int index2 = index - 1; index2 >= 0; index2--)
- {
- Jump jump2 = _jumps[index2];
-
- if (jump2.JumpPosition < jumpTarget)
- {
- break;
- }
-
- offset -= jump2.InstSize - ReservedBytesForJump;
- }
- }
- else
- {
- for (int index2 = index + 1; index2 < _jumps.Count; index2++)
- {
- Jump jump2 = _jumps[index2];
-
- if (jump2.JumpPosition >= jumpTarget)
- {
- break;
- }
-
- offset += jump2.InstSize - ReservedBytesForJump;
- }
-
- offset -= ReservedBytesForJump;
- }
-
- if (jump.IsConditional)
- {
- jump.InstSize = Assembler.GetJccLength(offset);
- }
- else
- {
- jump.InstSize = Assembler.GetJmpLength(offset);
- }
-
- // The jump is relative to the next instruction, not the current one.
- // Since we didn't know the next instruction address when calculating
- // the offset (as the size of the current jump instruction was not known),
- // we now need to compensate the offset with the jump instruction size.
- // It's also worth noting that:
- // - This is only needed for backward jumps.
- // - The GetJmpLength and GetJccLength also compensates the offset
- // internally when computing the jump instruction size.
- if (offset < 0)
- {
- offset -= jump.InstSize;
- }
- }
- else
- {
- offset -= jump.InstSize;
- }
-
- if (jump.RelativeOffset != offset)
- {
- modified = true;
- }
-
- jump.RelativeOffset = offset;
-
- _jumps[index] = jump;
- }
+ label = Operand.Factory.Label();
}
- while (modified);
-
- // Write the code, ignoring the dummy bytes after jumps, into a new stream.
- _stream.Seek(0, SeekOrigin.Begin);
-
- using (MemoryStream codeStream = new MemoryStream())
- {
- Assembler assembler = new Assembler(codeStream, _relocatable);
-
- for (int index = 0; index < _jumps.Count; index++)
- {
- Jump jump = _jumps[index];
-
- Span<byte> buffer = new byte[jump.JumpPosition - _stream.Position];
-
- _stream.Read(buffer);
- _stream.Seek(!_relocatable ? ReservedBytesForJump : jump.InstSize, SeekOrigin.Current);
-
- codeStream.Write(buffer);
- if (jump.IsConditional)
- {
- assembler.Jcc(jump.Condition, jump.RelativeOffset);
- }
- else
- {
- assembler.Jmp(jump.RelativeOffset);
- }
- }
-
- _stream.CopyTo(codeStream);
-
- var code = codeStream.ToArray();
- var relocInfo = Assembler.HasRelocs
- ? new RelocInfo(Assembler.Relocs.ToArray())
- : RelocInfo.Empty;
-
- return (code, relocInfo);
- }
+ return label;
}
}
} \ No newline at end of file