Skip to content

Commit

Permalink
[LoongArch64] implements the crossgen2 for LoongArch64.
Browse files Browse the repository at this point in the history
  • Loading branch information
shushanhf committed Feb 15, 2022
1 parent a3688bf commit b05a2b9
Show file tree
Hide file tree
Showing 25 changed files with 899 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,13 @@ public override ObjectData GetData(NodeFactory factory, bool relocsOnly)
arm64Emitter.Builder.AddSymbol(this);
return arm64Emitter.Builder.ToObjectData();

case TargetArchitecture.LoongArch64:
LoongArch64.LoongArch64Emitter loongarch64Emitter = new LoongArch64.LoongArch64Emitter(factory, relocsOnly);
EmitCode(factory, ref loongarch64Emitter, relocsOnly);
loongarch64Emitter.Builder.RequireInitialAlignment(alignment);
loongarch64Emitter.Builder.AddSymbol(this);
return loongarch64Emitter.Builder.ToObjectData();

default:
throw new NotImplementedException();
}
Expand All @@ -77,5 +84,6 @@ public override ObjectData GetData(NodeFactory factory, bool relocsOnly)
protected abstract void EmitCode(NodeFactory factory, ref X86.X86Emitter instructionEncoder, bool relocsOnly);
protected abstract void EmitCode(NodeFactory factory, ref ARM.ARMEmitter instructionEncoder, bool relocsOnly);
protected abstract void EmitCode(NodeFactory factory, ref ARM64.ARM64Emitter instructionEncoder, bool relocsOnly);
protected abstract void EmitCode(NodeFactory factory, ref LoongArch64.LoongArch64Emitter instructionEncoder, bool relocsOnly);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,8 @@ public void EmitReloc(ISymbolNode symbol, RelocType relocType, int delta = 0)
case RelocType.IMAGE_REL_BASED_ARM64_PAGEBASE_REL21:
case RelocType.IMAGE_REL_BASED_ARM64_PAGEOFFSET_12L:
case RelocType.IMAGE_REL_BASED_ARM64_PAGEOFFSET_12A:
case RelocType.IMAGE_REL_BASED_LOONGARCH64_PC:
case RelocType.IMAGE_REL_BASED_LOONGARCH64_JIR:
Debug.Assert(delta == 0);
// Do not vacate space for this kind of relocation, because
// the space is embedded in the instruction.
Expand Down
96 changes: 96 additions & 0 deletions src/coreclr/tools/Common/Compiler/DependencyAnalysis/Relocation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ public enum RelocType
IMAGE_REL_BASED_THUMB_BRANCH24 = 0x13, // Thumb2: based B, BL
IMAGE_REL_BASED_THUMB_MOV32_PCREL = 0x14, // Thumb2: based MOVW/MOVT
IMAGE_REL_BASED_ARM64_BRANCH26 = 0x15, // Arm64: B, BL
IMAGE_REL_BASED_LOONGARCH64_PC = 0x16, // LoongArch64: pcaddu12i+imm12
IMAGE_REL_BASED_LOONGARCH64_JIR = 0x17, // LoongArch64: pcaddu18i+jirl
IMAGE_REL_BASED_RELPTR32 = 0x7C, // 32-bit relative address from byte starting reloc
// This is a special NGEN-specific relocation type
// for relative pointer (used to make NGen relocation
Expand Down Expand Up @@ -294,7 +296,91 @@ private static unsafe void PutArm64Rel28(uint* pCode, long imm28)
Debug.Assert(GetArm64Rel28(pCode) == imm28);
}

private static unsafe int GetLoongArch64PC12(uint* pCode)
{
uint pcInstr = *pCode;

// first shift 6 bits left to set the sign bit,
// then arithmetic shift right by 4 bits
int imm = (int)(((pcInstr >> 5) & 0xFFFFF) << 12);

pcInstr = *(pCode + 1);
imm += ((short)(((pcInstr >> 10) & 0xFFF) << 4)) >> 4;

return imm;
}

private static unsafe void PutLoongArch64PC12(uint* pCode, long imm32)
{
// Verify that we got a valid offset
Debug.Assert((int)imm32 == imm32);

uint pcInstr = *pCode;

Debug.Assert((pcInstr & 0xFE000000) == 0x1c000000); // Must be pcaddu12i

int relOff = (int)imm32 & 0x800;
int imm = (int)imm32 + relOff;
relOff = ((imm & 0x7ff) - relOff) & 0xfff;

// Assemble the pc-relative hight20bits of 'imm32' into the pcaddu12i instruction
pcInstr |= (uint)(((imm >> 12) & 0xFFFFF) << 5);

*pCode = pcInstr; // write the assembled instruction

pcInstr = *(pCode + 1);

// Assemble the pc-relative low12bits of 'imm32' into the addid or ld instruction
pcInstr |= (uint)(relOff << 10);

*(pCode + 1) = pcInstr; // write the assembled instruction

Debug.Assert(GetLoongArch64PC12(pCode) == imm32);
}

private static unsafe long GetLoongArch64JIR(uint* pCode)
{
uint pcInstr = *pCode;

// first shift 6 bits left to set the sign bit,
// then arithmetic shift right by 4 bits
long imm = ((long)((pcInstr >> 5) & 0xFFFFF) << 18);

pcInstr = *(pCode + 1);
imm += ((long)((short)((pcInstr >> 10) & 0xFFFF))) << 2;

return imm;
}

private static unsafe void PutLoongArch64JIR(uint* pCode, long imm38)
{
// Verify that we got a valid offset
Debug.Assert((imm38 >= -0x2000000000L) && (imm38 < 0x2000000000L));

Debug.Assert((imm38 & 0x3) == 0); // the low two bits must be zero

uint pcInstr = *pCode;

Debug.Assert(pcInstr == 0x1e00000e); // Must be pcaddu18i R14, 0

long relOff = imm38 & 0x20000;
long imm = imm38 + relOff;
relOff = (((imm & 0x1ffff) - relOff) >> 2) & 0xffff;

// Assemble the pc-relative hight20bits of 'imm38' into the pcaddu12i instruction
pcInstr |= (uint)(((imm >> 18) & 0xFFFFF) << 5);

*pCode = pcInstr; // write the assembled instruction

pcInstr = *(pCode + 1);

// Assemble the pc-relative low18bits of 'imm38' into the addid or ld instruction
pcInstr |= (uint)(relOff << 10);

*(pCode + 1) = pcInstr; // write the assembled instruction

Debug.Assert(GetLoongArch64JIR(pCode) == imm38);
}

public Relocation(RelocType relocType, int offset, ISymbolNode target)
{
Expand Down Expand Up @@ -334,6 +420,12 @@ public static unsafe void WriteValue(RelocType relocType, void* location, long v
case RelocType.IMAGE_REL_BASED_ARM64_PAGEOFFSET_12A:
PutArm64Rel12((uint*)location, (int)value);
break;
case RelocType.IMAGE_REL_BASED_LOONGARCH64_PC:
PutLoongArch64PC12((uint*)location, value);
break;
case RelocType.IMAGE_REL_BASED_LOONGARCH64_JIR:
PutLoongArch64JIR((uint*)location, value);
break;
default:
Debug.Fail("Invalid RelocType: " + relocType);
break;
Expand Down Expand Up @@ -366,6 +458,10 @@ public static unsafe long ReadValue(RelocType relocType, void* location)
return GetArm64Rel21((uint*)location);
case RelocType.IMAGE_REL_BASED_ARM64_PAGEOFFSET_12A:
return GetArm64Rel12((uint*)location);
case RelocType.IMAGE_REL_BASED_LOONGARCH64_PC:
return 0; // (long)GetLoongArch64PC12((uint*)location);
case RelocType.IMAGE_REL_BASED_LOONGARCH64_JIR:
return 0; // (long)GetLoongArch64JIR((uint*)location);
default:
Debug.Fail("Invalid RelocType: " + relocType);
return 0;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;

namespace ILCompiler.DependencyAnalysis.LoongArch64
{
public enum AddrModeSize
{
Int8 = 1,
Int16 = 2,
Int32 = 4,
Int64 = 8,
Int128 = 16
}

public struct AddrMode
{
public readonly Register BaseReg;
public readonly Register? IndexReg;
public readonly int Offset;
public readonly byte Scale;
public readonly AddrModeSize Size;

public AddrMode(Register baseRegister, Register? indexRegister, int offset, byte scale, AddrModeSize size)
{
BaseReg = baseRegister;
IndexReg = indexRegister;
Offset = offset;
Scale = scale;
Size = size;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// 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.LoongArch64
{
public struct LoongArch64Emitter
{
public LoongArch64Emitter(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

public void EmitMOV(Register regDst, ushort imm16)
{
Debug.Assert((uint)regDst <= 0x1f);
Debug.Assert(imm16 <= 0xfff);
uint instruction = 0x03800000u | (uint)((imm16 & 0xfff) << 10) | (uint)regDst;
Builder.EmitUInt(instruction);
}

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

// ld_d regDst, regAddr, offset
public void EmitLD(Register regDst, Register regSrc, int offset)
{
Debug.Assert(offset >= -2048 && offset <= 2047);

Builder.EmitUInt((uint)(0x28c00000 | (uint)((offset & 0xfff) << 12) | ((uint)regSrc << 5) | (uint)regDst));
}

public void EmitJMP(ISymbolNode symbol)
{
if (symbol.RepresentsIndirectionCell)
{
// pcaddi R21, 0
EmitPC(Register.R21);

EmitLD(Register.R21, Register.R21, 0x10);

// ld_d R21, R21, 0
EmitLD(Register.R21, Register.R21, 0);

// jirl R0,R21,0
Builder.EmitUInt(0x4c0002a0);

Builder.EmitReloc(symbol, RelocType.IMAGE_REL_BASED_DIR64);
}
else
{
//Builder.EmitReloc(symbol, RelocType.IMAGE_REL_BASED_LOONGARCH64_PC);
Builder.EmitUInt(0xffffffff); // bad code.
throw new NotImplementedException();
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// 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.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ILCompiler.DependencyAnalysis.LoongArch64
{
public enum Register
{
R0 = 0,
R1 = 1,
R2 = 2,
R3 = 3,
R4 = 4,
R5 = 5,
R6 = 6,
R7 = 7,
R8 = 8,
R9 = 9,
R10 = 10,
R11 = 11,
R12 = 12,
R13 = 13,
R14 = 14,
R15 = 15,
R16 = 16,
R17 = 17,
R18 = 18,
R19 = 19,
R20 = 20,
R21 = 21,
R22 = 22,
R23 = 23,
R24 = 24,
R25 = 25,
R26 = 26,
R27 = 27,
R28 = 28,
R29 = 29,
R30 = 30,
R31 = 31,

None = 32,
NoIndex = 128,
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// 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 Internal.TypeSystem;

namespace ILCompiler.DependencyAnalysis.LoongArch64
{
/// <summary>
/// Maps logical registers to physical registers on a specified OS.
/// </summary>
public struct TargetRegisterMap
{
public readonly Register Arg0;
public readonly Register Arg1;
public readonly Register Arg2;
public readonly Register Arg3;
public readonly Register Arg4;
public readonly Register Arg5;
public readonly Register Arg6;
public readonly Register Arg7;
public readonly Register Result;

public TargetRegisterMap(TargetOS os)
{
Arg0 = Register.R4;
Arg1 = Register.R5;
Arg2 = Register.R6;
Arg3 = Register.R7;
Arg4 = Register.R8;
Arg5 = Register.R9;
Arg6 = Register.R11;
Arg7 = Register.R12;
Result = Register.R4; // TODO: ???
}
}
}
4 changes: 4 additions & 0 deletions src/coreclr/tools/Common/Compiler/InstructionSetSupport.cs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,10 @@ public SimdVectorLength GetVectorTSimdVector()
{
return SimdVectorLength.None;
}
else if (_targetArchitecture == TargetArchitecture.LoongArch64)
{
return SimdVectorLength.None;
}
else
{
Debug.Assert(false); // Unknown architecture
Expand Down
Loading

0 comments on commit b05a2b9

Please sign in to comment.