File: parent\parent\Common\Compiler\DependencyAnalysis\Target_RiscV64\RiscV64Emitter.cs
Web Access
Project: ILCompiler.Compiler.csproj (ILCompiler.Compiler)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Diagnostics;

namespace ILCompiler.DependencyAnalysis.RiscV64
{
    public struct RiscV64Emitter
    {
        public RiscV64Emitter(NodeFactory factory, bool relocsOnly)
        {
            Builder = new ObjectDataBuilder(factory, relocsOnly);
            TargetRegister = new TargetRegisterMap(factory.Target.OperatingSystem);
        }

        public ObjectDataBuilder Builder;
        public TargetRegisterMap TargetRegister;

        // Assembly stub creation api. TBD, actually make this general purpose

        //ebreak
        public void EmitBreak()
        {
            Builder.EmitUInt(0x00100073);
        }

        public void EmitFENCE_R_RW()
        {
            Builder.EmitUInt(0x0230000f);
        }

        public void EmitLI(Register regDst, int offset)
        {
            Debug.Assert((offset >= -2048) && (offset <= 2047));
            EmitADDI(regDst, Register.X0, offset);
        }

        public void EmitMOV(Register regDst, Register regSrc)
        {
            EmitADDI(regDst, regSrc, 0);
        }

        public void EmitMOV(Register regDst, ISymbolNode symbol)
        {
            Builder.EmitReloc(symbol, RelocType.IMAGE_REL_BASED_RISCV64_PCREL_I);
            //auipc reg, off-hi-20bits
            EmitPC(regDst);
            //addi reg, reg, off-lo-12bits
            EmitADDI(regDst, regDst, 0);
        }

        // auipc regDst, 0
        public void EmitPC(Register regDst)
        {
            Debug.Assert((uint)regDst > 0 && (uint)regDst < 32);
            Builder.EmitUInt(0x00000017u | (uint)regDst << 7);
        }

        // addi regDst, regSrc, offset
        public void EmitADDI(Register regDst, Register regSrc, int offset)
        {
            Debug.Assert((uint)regDst <= 0x1f);
            Debug.Assert((uint)regSrc <= 0x1f);
            Debug.Assert((offset >= -2048) && (offset <= 2047));
            Builder.EmitUInt((uint)(0x00000013u | ((uint)regSrc << 15) | ((uint)regDst << 7) | (uint)((offset & 0xfff) << 20)));
        }

        // xori regDst, regSrc, offset
        public void EmitXORI(Register regDst, Register regSrc, int offset)
        {
            Debug.Assert((offset >= -2048) && (offset <= 2047));
            Builder.EmitUInt((uint)(0x00004013u | ((uint)regSrc << 15) | ((uint)regDst << 7) | (uint)((offset & 0xfff) << 20)));
        }

        // ld regDst, offset(regSrc)
        public void EmitLD(Register regDst, Register regSrc, int offset)
        {
            Debug.Assert((offset >= -2048) && (offset <= 2047));
            Builder.EmitUInt((uint)(0x00003003u | ((uint)regSrc << 15) | ((uint)regDst << 7) | (uint)((offset & 0xfff) << 20)));
        }

        // jalr regDst, offset(regSrc)
        public void EmitJALR(Register regDst, Register regSrc, int offset)
        {
            Debug.Assert((offset >= -2048) && (offset <= 2047));
            Builder.EmitUInt((uint)(0x00000067u | ((uint)regSrc << 15) | ((uint)regDst << 7) | (uint)((offset & 0xfff) << 20)));
        }

        public void EmitLD(Register regDst, ISymbolNode symbol)
        {
            Builder.EmitReloc(symbol, RelocType.IMAGE_REL_BASED_RISCV64_PCREL_I);
            //auipc reg, off-hi-20bits
            EmitPC(regDst);
            //ld reg, off-lo-12bits(reg)
            EmitLD(regDst, regDst, 0);
        }

        public void EmitRET()
        {
            // jalr x0,0(x1)
            EmitJALR(Register.X0, Register.X1, 0);
        }

        public void EmitJMP(Register reg)
        {
            //jalr x0, 0(reg)
            EmitJALR(Register.X0, reg, 0);
        }

        public void EmitJMP(ISymbolNode symbol)
        {
            if (symbol.RepresentsIndirectionCell)
            {
                EmitLD(Register.X29, symbol);
                // jalr x0,0(x29)
                EmitJALR(Register.X0, Register.X29, 0);
            }
            else
            {
                Builder.EmitReloc(symbol, RelocType.IMAGE_REL_BASED_RISCV64_CALL_PLT);
                EmitPC(Register.X29); // auipc x29, 0
                EmitJALR(Register.X0, Register.X29, 0); // jalr x0, 0(x29)
            }
        }

        public void EmitRETIfZero(Register regSrc)
        {
            // bne regSrc, x0, 8
            Builder.EmitUInt((uint)(0x00001463 | ((uint)regSrc << 15)));
            EmitRET();
        }

        public void EmitJMPIfZero(Register regSrc, ISymbolNode symbol)
        {
            uint offset = symbol.RepresentsIndirectionCell ? 28u : 12u;
            uint encodedOffset = ((offset & 0x1e) << 7) | ((offset & 0x7e0) << 20) | ((offset & 0x800) >> 4) | ((offset & 0x1000) << 19);
            // bne regSrc, x0, offset
            Builder.EmitUInt((uint)(0x00001063 | ((uint)regSrc << 15) | encodedOffset));
            EmitJMP(symbol);
        }

        public void EmitNOP()
        {
            Builder.EmitUInt(0x00000013);
        }
    }
}