diff options
Diffstat (limited to 'ARMeilleure/CodeGen/X86/CodeGenContext.cs')
| -rw-r--r-- | ARMeilleure/CodeGen/X86/CodeGenContext.cs | 273 |
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 |
