| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105 |
- using ARMeilleure.CodeGen.RegisterAllocators;
- using ARMeilleure.IntermediateRepresentation;
- using Ryujinx.Common.Memory;
- using System.IO;
- using System.Numerics;
- namespace ARMeilleure.CodeGen.X86
- {
- class CodeGenContext
- {
- private readonly Stream _stream;
- 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; }
- public CodeGenContext(AllocationResult allocResult, int maxCallArgs, int blocksCount, bool relocatable)
- {
- _stream = MemoryStreamManager.Shared.GetStream();
- _blockLabels = new Operand[blocksCount];
- AllocResult = allocResult;
- 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).
- int intMask = CallingConvention.GetIntCalleeSavedRegisters() & allocResult.IntUsedRegisters;
- int vecMask = CallingConvention.GetVecCalleeSavedRegisters() & allocResult.VecUsedRegisters;
- xmmSaveRegionSize = BitOperations.PopCount((uint)vecMask) * 16;
- 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.
- 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).
- 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.
- int callArgsAndFrameSize = frameSize + argsCount * 16;
- // Ensure that the Stack Pointer will be aligned to 16 bytes.
- callArgsAndFrameSize = (callArgsAndFrameSize + 0xf) & ~0xf;
- return callArgsAndFrameSize - frameSize;
- }
- public void EnterBlock(BasicBlock block)
- {
- Assembler.MarkLabel(GetLabel(block));
- CurrBlock = block;
- }
- public void JumpTo(BasicBlock target)
- {
- Assembler.Jmp(GetLabel(target));
- }
- public void JumpTo(X86Condition condition, BasicBlock target)
- {
- Assembler.Jcc(condition, GetLabel(target));
- }
- private Operand GetLabel(BasicBlock block)
- {
- ref Operand label = ref _blockLabels[block.Index];
- if (label == default)
- {
- label = Operand.Factory.Label();
- }
- return label;
- }
- }
- }
|