Compare commits

...

5 Commits

Author SHA1 Message Date
597556cc59 add B and fix add 2026-02-01 12:07:22 +08:00
c1f7a5eabe EnterBlock 2026-01-24 11:30:55 +08:00
100a9d3546 CodeGenerator实现 2026-01-22 21:23:08 +08:00
caf0f58fb0 add指令 2026-01-21 07:51:35 +08:00
ba99106348 寄存器映射 2026-01-10 11:07:27 +08:00
10 changed files with 2483 additions and 0 deletions

View File

@ -0,0 +1,10 @@
{
"permissions": {
"allow": [
"Bash(dir:*)",
"Bash(wc:*)",
"Bash(for f in src/ARMeilleure/CodeGen/X86/*.cs)",
"Bash(done)"
]
}
}

182
CLAUDE.md Normal file
View File

@ -0,0 +1,182 @@
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Project Overview
Ryujinx is an open-source Nintendo Switch emulator written in C#. This is a community fork (Ryubing/Ryujinx) focused on Quality of Life improvements for existing users. The emulator provides high-accuracy emulation of the Nintendo Switch's ARMv8 CPU and Maxwell GPU.
## Build Commands
### Building the Project
```bash
dotnet build -c Release -o build
```
### Code Style Enforcement
Run `dotnet format` before committing to ensure code style compliance:
```bash
dotnet format
```
### Running Tests
```bash
# Run all tests
dotnet test
# Run specific test project
dotnet test src/Ryujinx.Tests/Ryujinx.Tests.csproj
dotnet test src/Ryujinx.Tests.Memory/Ryujinx.Tests.Memory.csproj
dotnet test src/Ryujinx.Tests.Unicorn/Ryujinx.Tests.Unicorn.csproj
```
## Requirements
- .NET 9.0 SDK or higher (version 9.0.100 specified in `global.json`)
- Minimum 8GB RAM for optimal performance
## Architecture Overview
### Three-Layer Architecture
```
┌─────────────────────────────────────┐
│ UI Layer (Avalonia MVVM) │ src/Ryujinx (GUI)
│ Headless Mode (SDL2) │ src/Ryujinx.Headless.SDL2
└────────────────────┬────────────────┘
┌────────────────────┴────────────────┐
│ High-Level Emulation (HLE) │
│ - Ryujinx.HLE │ Horizon OS services emulation
│ - Ryujinx.Horizon │ System services implementation
└────────────────────┬────────────────┘
┌────────────────────┴────────────────┐
│ Core Emulation │
│ - ARMeilleure (CPU) │ ARM instruction translation
│ - Ryujinx.Graphics.Gpu │ Maxwell GPU emulation
│ - Ryujinx.Audio │ Audio engine
└────────────────────┬────────────────┘
┌────────────────────┴────────────────┐
│ Backend Implementations │
│ - OpenGL/Vulkan/Metal (Graphics) │
│ - OpenAL/SDL2/SoundIO (Audio) │
│ - SDL2 (Input) │
└─────────────────────────────────────┘
```
### Key Components
**ARMeilleure (src/ARMeilleure/)**
- CPU emulator that translates ARMv8 instructions to x86/ARM64/Loong64 machine code
- Translation pipeline: ARM decode → Custom IR → Optimizations → Code generation
- Supports Profiled Persistent Translation Cache (PPTC) for faster load times
- Code generation backends in `CodeGen/` for different architectures
**Ryujinx.HLE (src/Ryujinx.HLE/)**
- High-Level Emulation of Nintendo Switch OS (Horizon OS)
- `HOS/Services/` contains system service implementations (am, audio, fs, hid, etc.)
- `HOS/Kernel/` handles thread/process management
- `Loaders/` support ELF, NSO, NRO executable formats
- `Debugger/` provides GDB protocol support
**Graphics Stack**
- `Ryujinx.Graphics.Gpu/` - Main GPU emulation engine (Maxwell architecture)
- `Engine/` subdirectory contains graphics command processors (Compute, DMA, GPFifo, Threed, etc.)
- `Shader/` handles shader compilation and disk caching
- `Ryujinx.Graphics.GAL/` - Graphics Abstraction Layer (backend-agnostic interface)
- Backend implementations: OpenGL, Vulkan, Metal (via MoltenVK on macOS)
- `Ryujinx.Graphics.Shader/` - Shader translation to GLSL/SPIR-V
**Memory Management (src/Ryujinx.Memory/)**
- Three memory manager modes: checked (slowest), untuned, host (default/fastest)
- Balances emulation accuracy vs. performance
**UI (src/Ryujinx/)**
- Built with Avalonia (cross-platform XAML framework)
- MVVM pattern using CommunityToolkit.Mvvm
- UI structure: `UI/Views/`, `UI/ViewModels/`, `UI/Windows/`, `UI/Controls/`
- Locale management with auto-generated code (`Ryujinx.UI.LocaleGenerator`)
### Code Generation
Several components use source generators:
- `Ryujinx.HLE.Generators` - Generates HLE service stubs
- `Ryujinx.Horizon.Generators` - Generates Horizon OS bindings
- `Ryujinx.Horizon.Kernel.Generators` - Generates kernel syscalls
- `Ryujinx.UI.LocaleGenerator` - Generates locale string bindings
- `Spv.Generator` - Generates SPIR-V shader code for Vulkan
## Coding Guidelines
Follow the C# coding style defined in `.editorconfig` and `docs/coding-guidelines/coding-style.md`:
- **Braces**: Allman style (braces on new lines)
- **Indentation**: 4 spaces, no tabs
- **Fields**: `_camelCase` for private instance, `s_` prefix for static, `t_` for thread-static
- **Visibility**: Always specify explicitly (e.g., `private`, `public`)
- **var**: Only use when type is explicitly named on right-hand side
- **Imports**: At top of file, outside namespace declarations
- **Types**: Make internal/private types static or sealed unless derivation needed
- **Magic Numbers**: Define as named constants
Always run `dotnet format` before committing.
## Development Workflow
1. Create a branch off `master` (the main branch, not `main`)
2. Make changes and ensure `dotnet format` is run
3. Build with `dotnet build -c Release` and verify clean build
4. Run relevant tests
5. Submit PR against `master` branch
6. Two team members must review and approve before merge
7. CI runs automatically via GitHub Actions (`.github/workflows/`)
## Important Project Patterns
**Abstraction Layers**: The project uses abstraction layers extensively to support multiple backends:
- Graphics backends (OpenGL/Vulkan/Metal)
- Audio backends (OpenAL/SDL2/SoundIO)
- Input systems (SDL2)
- Memory management modes
**Translation Caching**: ARMeilleure uses a persistent translation cache that significantly improves load times after the third launch of a game.
**Disk Shader Caching**: Compiled shaders are cached to disk to avoid recompilation (`Ryujinx.Graphics.Gpu/Shader/DiskCache/`).
**Platform-Specific Code**: The codebase handles Windows, macOS, and Linux with platform-specific implementations where needed.
## Common File Locations
- **System Files**: User folder (accessible via GUI: File → Open Ryujinx Folder)
- **Logs**: `[Executable Folder]/Logs` - chronologically named
- **Configuration**: `Config.json` in Ryujinx data folder
- **Build Output**: `build/` directory after running build command
## Branches and Releases
- **master**: Main branch for stable releases (released monthly)
- **canary**: Automated builds for every commit on master (may be unstable)
- Current working branch is **Loong64** (architecture support feature branch)
## When Working With Specific Systems
**Adding/Modifying HLE Services**: Follow the service implementation guidelines at https://gist.github.com/gdkchan/84ba88cd50efbe58d1babfaa7cd7c455
**Graphics Work**: Understand the GPU command engine structure in `Ryujinx.Graphics.Gpu/Engine/` - each engine (Compute, DMA, Threed, Twod) handles specific GPU operations.
**CPU Instruction Support**: ARM instruction decoding happens in `ARMeilleure/Decoders/`, implementation in `Instructions/`, and code generation in `CodeGen/`.
**UI Changes**: Follow MVVM pattern - Views in `UI/Views/`, logic in `UI/ViewModels/`. Use FluentAvaloniaUI controls for consistency.
## Third-Party Dependencies
The project uses several key libraries:
- **LibHac**: Nintendo Switch filesystem support
- **Avalonia**: Cross-platform UI framework
- **Silk.NET**: Graphics API bindings
- **SDL2**: Audio/Input/Windowing
- **SharpZipLib**: Archive handling
Contributions using code from other projects must follow permissive licenses and be properly attributed in `distribution/legal/THIRDPARTY.md`.

View File

@ -0,0 +1,132 @@
using ARMeilleure.IntermediateRepresentation;
using System;
using System.Diagnostics;
using System.IO;
using static ARMeilleure.IntermediateRepresentation.Operand;
namespace ARMeilleure.CodeGen.Loong64
{
class Assembler
{
private readonly Stream _stream;
public Assembler(Stream stream)
{
_stream = stream;
}
public void Add(Operand rd, Operand rj, Operand rk)
{
if (rk.Kind == OperandKind.Constant)
{
Addi(rd, rj, rk.AsInt32());
}
else
{
AddReg(rd, rj, rk);
}
}
public void B(int imm)
{
WriteUInt32(0x50000000 | EncodeSImm26_2(imm));
}
public void Addi(Operand rd, Operand rj, int imm)
{
if (rd.Type == OperandType.I64)
{
WriteUInt32(0x02c00000u | EncodeReg(rd) | EncodeReg(rj) << 5 | EncodeSImm12(imm) << 10);
}
else
{
WriteUInt32(0x02800000u | EncodeReg(rd) | EncodeReg(rj) << 5 | EncodeSImm12(imm) << 10);
}
}
public void AddReg(Operand rd, Operand rj, Operand rk)
{
if (rd.Type == OperandType.I64)
{
WriteUInt32(0x00108000u | EncodeReg(rd) | EncodeReg(rj) << 5 | EncodeReg(rk) << 10);
}
else
{
WriteUInt32(0x00100000u | EncodeReg(rd) | EncodeReg(rj) << 5 | EncodeReg(rk) << 10);
}
}
private static uint EncodeSImm12(int value)
{
uint imm = (uint)value & 0xfff;
Debug.Assert(((int)imm << 20) >> 20 == value, $"Failed to encode constant 0x{value:X}.");
return imm;
}
private static uint EncodeSImm26_2(int value)
{
int shifted = value >> 2;
uint immLo = (uint)shifted & 0xFFFF; // imm[15:0]
uint immHi = ((uint)shifted >> 16) & 0x3FF; // imm[25:16]
uint encoded =
(immLo << 10) | // inst[25:10]
(immHi << 0); // inst[9:0]
uint recon =
((encoded & 0x3FF) << 16) | // inst[9:0] -> imm[25:16]
((encoded >> 10) & 0xFFFF); // inst[25:10] -> imm[15:0]
int decoded = (int)(recon << 6) >> 4;
Debug.Assert(decoded == value, $"Failed to encode constant 0x{value:X}.");
return encoded;
}
private static uint EncodeReg(Operand reg)
{
if (reg.Kind == OperandKind.Constant && reg.Value == 0)
{
return (uint)Loong64Register.zero;
}
uint regIndex = (uint)reg.GetRegister().Index;
Debug.Assert(reg.Kind == OperandKind.Register);
Debug.Assert(regIndex < 32);
return regIndex;
}
#pragma warning disable IDE0051 // Remove unused private member
private void WriteInt16(short value)
{
WriteUInt16((ushort)value);
}
private void WriteInt32(int value)
{
WriteUInt32((uint)value);
}
private void WriteByte(byte value)
{
_stream.WriteByte(value);
}
#pragma warning restore IDE0051
private void WriteUInt16(ushort value)
{
_stream.WriteByte((byte)(value >> 0));
_stream.WriteByte((byte)(value >> 8));
}
private void WriteUInt32(uint value)
{
_stream.WriteByte((byte)(value >> 0));
_stream.WriteByte((byte)(value >> 8));
_stream.WriteByte((byte)(value >> 16));
_stream.WriteByte((byte)(value >> 24));
}
}
}

View File

@ -0,0 +1,100 @@
using System;
namespace ARMeilleure.CodeGen.Loong64
{
static class CallingConvention
{
// 寄存器掩码 (32位整数每位代表一个寄存器)
private const int RegistersMask = unchecked((int)0xffffffff);
private const int ReservedRegsMask = (1 << (int)Loong64Register.zero) | (1 << (int)Loong64Register.ra) | (1 << (int)Loong64Register.tp) | (1 << (int)Loong64Register.sp) | (1 << (int)Loong64Register.r21) | (1 << (int)Loong64Register.fp);
public static int GetIntAvailableRegisters()
{
// 返回可用的通用寄存器掩码
return RegistersMask & ~ReservedRegsMask;
}
public static int GetVecAvailableRegisters()
{
// 返回可用的浮点/向量寄存器掩码
return RegistersMask;
}
public static int GetIntCallerSavedRegisters()
{
// 调用者保存的寄存器 (临时寄存器)
return (GetIntCalleeSavedRegisters() ^ RegistersMask) & ~ReservedRegsMask;
}
public static int GetFpCallerSavedRegisters()
{
return GetFpCalleeSavedRegisters() ^ RegistersMask;
}
public static int GetVecCallerSavedRegisters()
{
return GetVecCalleeSavedRegisters() ^ RegistersMask;
}
public static int GetIntCalleeSavedRegisters()
{
// 被调用者保存的寄存器 (需要保存/恢复)
return unchecked((int)0xff000000);
}
public static int GetFpCalleeSavedRegisters()
{
return unchecked((int)0xff000000); // f24 to f31
}
public static int GetVecCalleeSavedRegisters()
{
return 0;
}
public static int GetArgumentsOnRegsCount()
{
return 8;
}
// 参数寄存器 (Loong64: A0-A7 用于参数)
public static int GetIntArgumentRegister(int index)
{
// index 0-7 → A0-A7 寄存器
if ((uint)index < (uint)GetArgumentsOnRegsCount())
{
return index;
}
throw new ArgumentOutOfRangeException(nameof(index));
}
public static int GetVecArgumentRegister(int index)
{
// index 0-7 → FA0-FA7 寄存器
if ((uint)index < (uint)GetArgumentsOnRegsCount())
{
return index;
}
throw new ArgumentOutOfRangeException(nameof(index));
}
// 返回值寄存器
public static int GetIntReturnRegister()
{
return (int)Loong64Register.a0; // 返回值放在 A0
}
public static int GetIntReturnRegisterHigh()
{
return (int)Loong64Register.a1; // 64位返回值高位
}
public static int GetVecReturnRegister()
{
return 0;
}
}
}

View File

@ -0,0 +1,9 @@
using ARMeilleure.IntermediateRepresentation;
namespace ARMeilleure.CodeGen.Loong64
{
static class CodeGenCommon
{
}
}

View File

@ -0,0 +1,196 @@
using ARMeilleure.CodeGen.Linking;
using ARMeilleure.CodeGen.RegisterAllocators;
using ARMeilleure.IntermediateRepresentation;
using Microsoft.IO;
using Ryujinx.Common.Memory;
using System;
using System.Collections.Generic;
using System.IO;
namespace ARMeilleure.CodeGen.Loong64
{
class CodeGenContext
{
private const int BranchInstLength = 4;
private readonly RecyclableMemoryStream _stream;
public int StreamOffset => (int)_stream.Length;
public AllocationResult AllocResult { get; }
public Assembler Assembler { get; }
public BasicBlock CurrBlock { get; private set; }
public bool HasCall { get; }
public int CallArgsRegionSize { get; }
private readonly Dictionary<BasicBlock, long> _visitedBlocks;
private readonly Dictionary<BasicBlock, List<PendingBranch>> _pendingBranches;
private readonly bool _relocatable;
private readonly struct PendingBranch
{
public readonly Comparison ComparisonType;
public readonly Operand? Operand1;
public readonly Operand? Operand2;
public readonly long BranchPosition;
public PendingBranch(Comparison compType, Operand? op1, Operand? op2, long pos)
{
ComparisonType = compType;
Operand1 = op1;
Operand2 = op2;
BranchPosition = pos;
}
}
public CodeGenContext(AllocationResult allocResult, int maxCallArgs, bool relocatable)
{
_stream = MemoryStreamManager.Shared.GetStream();
AllocResult = allocResult;
Assembler = new Assembler(_stream);
bool hasCall = maxCallArgs >= 0;
HasCall = hasCall;
if (maxCallArgs < 0)
{
maxCallArgs = 0;
}
CallArgsRegionSize = maxCallArgs * 16;
_visitedBlocks = new Dictionary<BasicBlock, long>();
_pendingBranches = new Dictionary<BasicBlock, List<PendingBranch>>();
_relocatable = relocatable;
}
public void EnterBlock(BasicBlock block)
{
CurrBlock = block;
long target = _stream.Position;
// 修补所有跳转到此块的待处理分支
if (_pendingBranches.TryGetValue(block, out List<PendingBranch> list))
{
foreach (PendingBranch pending in list)
{
_stream.Seek(pending.BranchPosition, SeekOrigin.Begin);
WriteBranch(pending.ComparisonType, pending.Operand1, pending.Operand2, target);
}
_stream.Seek(target, SeekOrigin.Begin);
_pendingBranches.Remove(block);
}
_visitedBlocks.Add(block, target);
}
public void JumpTo(BasicBlock target)
{
if (_visitedBlocks.TryGetValue(target, out long offset))
{
// 目标块已生成,直接写入无条件跳转
WriteUnconditionalBranch(offset);
}
else
{
// 目标块未生成,记录待修补(使用特殊的无条件标记)
if (!_pendingBranches.TryGetValue(target, out List<PendingBranch> list))
{
list = new List<PendingBranch>();
_pendingBranches.Add(target, list);
}
// 使用 Comparison.Equal 和 null 操作数表示无条件跳转
list.Add(new PendingBranch(Comparison.Equal, null, null, _stream.Position));
_stream.Seek(BranchInstLength, SeekOrigin.Current);
}
}
public void JumpToIf(Comparison compType, Operand op1, Operand op2, BasicBlock target)
{
if (_visitedBlocks.TryGetValue(target, out long offset))
{
// 目标块已生成,直接写入条件分支
WriteBranch(compType, op1, op2, offset);
}
else
{
// 目标块未生成,记录待修补
if (!_pendingBranches.TryGetValue(target, out List<PendingBranch> list))
{
list = new List<PendingBranch>();
_pendingBranches.Add(target, list);
}
list.Add(new PendingBranch(compType, op1, op2, _stream.Position));
_stream.Seek(BranchInstLength, SeekOrigin.Current);
}
}
private void WriteBranch(Comparison compType, Operand? op1, Operand? op2, long targetPos)
{
// 如果操作数为 null表示无条件跳转
if (op1 == null && op2 == null)
{
WriteUnconditionalBranch(targetPos);
return;
}
int offset = checked((int)(targetPos - _stream.Position));
// TODO: 根据 Comparison 类型调用相应的 Assembler 方法
// 这里需要实现 Loong64 的条件分支指令
switch (compType)
{
case Comparison.Equal:
// Assembler.Beq(op1, op2, offset);
throw new NotImplementedException("Beq not implemented yet");
case Comparison.NotEqual:
// Assembler.Bne(op1, op2, offset);
throw new NotImplementedException("Bne not implemented yet");
case Comparison.Less:
// Assembler.Blt(op1, op2, offset);
throw new NotImplementedException("Blt not implemented yet");
case Comparison.LessOrEqual:
// Assembler.Ble(op1, op2, offset);
throw new NotImplementedException("Ble not implemented yet");
case Comparison.Greater:
// Assembler.Bgt(op1, op2, offset);
throw new NotImplementedException("Bgt not implemented yet");
case Comparison.GreaterOrEqual:
// Assembler.Bge(op1, op2, offset);
throw new NotImplementedException("Bge not implemented yet");
default:
throw new ArgumentException($"Unsupported comparison type: {compType}");
}
}
private void WriteUnconditionalBranch(long targetPos)
{
int offset = checked((int)(targetPos - _stream.Position));
// TODO: 实现 Loong64 的无条件跳转指令
Assembler.B(offset);
throw new NotImplementedException("Unconditional branch not implemented yet");
}
}
}

View File

@ -0,0 +1,153 @@
using ARMeilleure.CodeGen.Linking;
using ARMeilleure.CodeGen.Optimizations;
using ARMeilleure.CodeGen.RegisterAllocators;
using ARMeilleure.CodeGen.Unwinding;
using ARMeilleure.Common;
using ARMeilleure.Diagnostics;
using ARMeilleure.IntermediateRepresentation;
using ARMeilleure.Translation;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Numerics;
using static ARMeilleure.IntermediateRepresentation.Operand;
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
namespace ARMeilleure.CodeGen.Loong64
{
static class CodeGenerator
{
private const int RegistersCount = 32;
private static readonly Action<CodeGenContext, Operation>[] _instTable;
static CodeGenerator()
{
_instTable = new Action<CodeGenContext, Operation>[EnumUtils.GetCount(typeof(Instruction))];
#pragma warning disable IDE0055 // Disable formatting
Add(Instruction.Add, GenerateAdd);
#pragma warning restore IDE0055
static void Add(Instruction inst, Action<CodeGenContext, Operation> func)
{
_instTable[(int)inst] = func;
}
}
public static CompiledFunction Generate(CompilerContext cctx)
{
ControlFlowGraph cfg = cctx.Cfg;
Logger.StartPass(PassName.Optimization);
if (cctx.Options.HasFlag(CompilerOptions.Optimize))
{
if (cctx.Options.HasFlag(CompilerOptions.SsaForm))
{
Optimizer.RunPass(cfg); // SSA 优化
}
BlockPlacement.RunPass(cfg); // 基本块重排序
}
Logger.EndPass(PassName.Optimization, cfg);
Logger.StartPass(PassName.PreAllocation);
PreAllocator.RunPass(cctx, out int maxCallArgs);
Logger.EndPass(PassName.PreAllocation, cfg);
Logger.StartPass(PassName.RegisterAllocation);
StackAllocator stackAlloc = new();
if (cctx.Options.HasFlag(CompilerOptions.SsaForm))
{
Ssa.Deconstruct(cfg);
}
IRegisterAllocator regAlloc;
if (cctx.Options.HasFlag(CompilerOptions.Lsra))
{
regAlloc = new LinearScanAllocator(); // 快速分配
}
else
{
regAlloc = new HybridAllocator(); // 高质量分配
}
RegisterMasks regMasks = new(
CallingConvention.GetIntAvailableRegisters(),
CallingConvention.GetVecAvailableRegisters(),
CallingConvention.GetIntCallerSavedRegisters(),
CallingConvention.GetVecCallerSavedRegisters(),
CallingConvention.GetIntCalleeSavedRegisters(),
CallingConvention.GetVecCalleeSavedRegisters(),
RegistersCount);
AllocationResult allocResult = regAlloc.RunPass(cfg, stackAlloc, regMasks);
Logger.EndPass(PassName.RegisterAllocation, cfg);
Logger.StartPass(PassName.CodeGeneration);
bool relocatable = (cctx.Options & CompilerOptions.Relocatable) != 0;
CodeGenContext context = new(allocResult, maxCallArgs, relocatable);
UnwindInfo unwindInfo = WritePrologue(context);
for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext)
{
context.EnterBlock(block);
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 is Instruction.Tailcall or
Instruction.Return);
}
else
{
BasicBlock succ = block.GetSuccessor(0);
if (succ != block.ListNext)
{
context.JumpTo(succ);
}
}
}
(byte[] code, RelocInfo relocInfo) = context.Assembler.GetCode();
Logger.EndPass(PassName.CodeGeneration);
return new CompiledFunction(code, unwindInfo, relocInfo);
}
private static void GenerateAdd(CodeGenContext context, Operation operation)
{
Operand dest = operation.Destination;
Operand src1 = operation.GetSource(0);
Operand src2 = operation.GetSource(1);
if (dest.Type.IsInteger())
{
context.Assembler.Add(dest, src1, src2);
}
else
{
// todo
}
}
}
}

View File

@ -0,0 +1,73 @@
using System.Diagnostics.CodeAnalysis;
namespace ARMeilleure.CodeGen.Loong64
{
enum Loong64Register
{
zero = 0,
ra = 1,
tp = 2,
sp = 3,
a0 = 4,
a1 = 5,
a2 = 6,
a3 = 7,
a4 = 8,
a5 = 9,
a6 = 10,
a7 = 11,
t0 = 12,
t1 = 13,
t2 = 14,
t3 = 15,
t4 = 16,
t5 = 17,
t6 = 18,
t7 = 19,
t8 = 20,
r21 = 21,
fp = 22,
s0 = 23,
s1 = 24,
s2 = 25,
s3 = 26,
s4 = 27,
s5 = 28,
s6 = 29,
s7 = 30,
s8 = 31,
fa0 = 0,
fa1 = 1,
fa2 = 2,
fa3 = 3,
fa4 = 4,
fa5 = 5,
fa6 = 6,
fa7 = 7,
ft0 = 8,
ft1 = 9,
ft2 = 10,
ft3 = 11,
ft4 = 12,
ft5 = 13,
ft6 = 14,
ft7 = 15,
ft8 = 16,
ft9 = 17,
ft10 = 18,
ft11 = 19,
ft12 = 20,
ft13 = 21,
ft14 = 22,
ft15 = 23,
fs0 = 24,
fs1 = 25,
fs2 = 26,
fs3 = 27,
fs4 = 28,
fs5 = 29,
fs6 = 30,
fs7 = 31,
}
}

View File

@ -0,0 +1,18 @@
using ARMeilleure.IntermediateRepresentation;
using ARMeilleure.Translation;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
using static ARMeilleure.IntermediateRepresentation.Operation.Factory;
namespace ARMeilleure.CodeGen.Loong64
{
static class PreAllocator
{
public static void RunPass(CompilerContext cctx, out int maxCallArgs)
{
maxCallArgs = -1;
}
}
}

File diff suppressed because it is too large Load Diff