Skip to content

Commit b05a2b9

Browse files
committed
[LoongArch64] implements the crossgen2 for LoongArch64.
1 parent a3688bf commit b05a2b9

25 files changed

Lines changed: 899 additions & 5 deletions

src/coreclr/tools/Common/Compiler/DependencyAnalysis/AssemblyStubNode.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,13 @@ public override ObjectData GetData(NodeFactory factory, bool relocsOnly)
6868
arm64Emitter.Builder.AddSymbol(this);
6969
return arm64Emitter.Builder.ToObjectData();
7070

71+
case TargetArchitecture.LoongArch64:
72+
LoongArch64.LoongArch64Emitter loongarch64Emitter = new LoongArch64.LoongArch64Emitter(factory, relocsOnly);
73+
EmitCode(factory, ref loongarch64Emitter, relocsOnly);
74+
loongarch64Emitter.Builder.RequireInitialAlignment(alignment);
75+
loongarch64Emitter.Builder.AddSymbol(this);
76+
return loongarch64Emitter.Builder.ToObjectData();
77+
7178
default:
7279
throw new NotImplementedException();
7380
}
@@ -77,5 +84,6 @@ public override ObjectData GetData(NodeFactory factory, bool relocsOnly)
7784
protected abstract void EmitCode(NodeFactory factory, ref X86.X86Emitter instructionEncoder, bool relocsOnly);
7885
protected abstract void EmitCode(NodeFactory factory, ref ARM.ARMEmitter instructionEncoder, bool relocsOnly);
7986
protected abstract void EmitCode(NodeFactory factory, ref ARM64.ARM64Emitter instructionEncoder, bool relocsOnly);
87+
protected abstract void EmitCode(NodeFactory factory, ref LoongArch64.LoongArch64Emitter instructionEncoder, bool relocsOnly);
8088
}
8189
}

src/coreclr/tools/Common/Compiler/DependencyAnalysis/ObjectDataBuilder.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,8 @@ public void EmitReloc(ISymbolNode symbol, RelocType relocType, int delta = 0)
303303
case RelocType.IMAGE_REL_BASED_ARM64_PAGEBASE_REL21:
304304
case RelocType.IMAGE_REL_BASED_ARM64_PAGEOFFSET_12L:
305305
case RelocType.IMAGE_REL_BASED_ARM64_PAGEOFFSET_12A:
306+
case RelocType.IMAGE_REL_BASED_LOONGARCH64_PC:
307+
case RelocType.IMAGE_REL_BASED_LOONGARCH64_JIR:
306308
Debug.Assert(delta == 0);
307309
// Do not vacate space for this kind of relocation, because
308310
// the space is embedded in the instruction.

src/coreclr/tools/Common/Compiler/DependencyAnalysis/Relocation.cs

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ public enum RelocType
1616
IMAGE_REL_BASED_THUMB_BRANCH24 = 0x13, // Thumb2: based B, BL
1717
IMAGE_REL_BASED_THUMB_MOV32_PCREL = 0x14, // Thumb2: based MOVW/MOVT
1818
IMAGE_REL_BASED_ARM64_BRANCH26 = 0x15, // Arm64: B, BL
19+
IMAGE_REL_BASED_LOONGARCH64_PC = 0x16, // LoongArch64: pcaddu12i+imm12
20+
IMAGE_REL_BASED_LOONGARCH64_JIR = 0x17, // LoongArch64: pcaddu18i+jirl
1921
IMAGE_REL_BASED_RELPTR32 = 0x7C, // 32-bit relative address from byte starting reloc
2022
// This is a special NGEN-specific relocation type
2123
// for relative pointer (used to make NGen relocation
@@ -294,7 +296,91 @@ private static unsafe void PutArm64Rel28(uint* pCode, long imm28)
294296
Debug.Assert(GetArm64Rel28(pCode) == imm28);
295297
}
296298

299+
private static unsafe int GetLoongArch64PC12(uint* pCode)
300+
{
301+
uint pcInstr = *pCode;
302+
303+
// first shift 6 bits left to set the sign bit,
304+
// then arithmetic shift right by 4 bits
305+
int imm = (int)(((pcInstr >> 5) & 0xFFFFF) << 12);
306+
307+
pcInstr = *(pCode + 1);
308+
imm += ((short)(((pcInstr >> 10) & 0xFFF) << 4)) >> 4;
309+
310+
return imm;
311+
}
312+
313+
private static unsafe void PutLoongArch64PC12(uint* pCode, long imm32)
314+
{
315+
// Verify that we got a valid offset
316+
Debug.Assert((int)imm32 == imm32);
317+
318+
uint pcInstr = *pCode;
297319

320+
Debug.Assert((pcInstr & 0xFE000000) == 0x1c000000); // Must be pcaddu12i
321+
322+
int relOff = (int)imm32 & 0x800;
323+
int imm = (int)imm32 + relOff;
324+
relOff = ((imm & 0x7ff) - relOff) & 0xfff;
325+
326+
// Assemble the pc-relative hight20bits of 'imm32' into the pcaddu12i instruction
327+
pcInstr |= (uint)(((imm >> 12) & 0xFFFFF) << 5);
328+
329+
*pCode = pcInstr; // write the assembled instruction
330+
331+
pcInstr = *(pCode + 1);
332+
333+
// Assemble the pc-relative low12bits of 'imm32' into the addid or ld instruction
334+
pcInstr |= (uint)(relOff << 10);
335+
336+
*(pCode + 1) = pcInstr; // write the assembled instruction
337+
338+
Debug.Assert(GetLoongArch64PC12(pCode) == imm32);
339+
}
340+
341+
private static unsafe long GetLoongArch64JIR(uint* pCode)
342+
{
343+
uint pcInstr = *pCode;
344+
345+
// first shift 6 bits left to set the sign bit,
346+
// then arithmetic shift right by 4 bits
347+
long imm = ((long)((pcInstr >> 5) & 0xFFFFF) << 18);
348+
349+
pcInstr = *(pCode + 1);
350+
imm += ((long)((short)((pcInstr >> 10) & 0xFFFF))) << 2;
351+
352+
return imm;
353+
}
354+
355+
private static unsafe void PutLoongArch64JIR(uint* pCode, long imm38)
356+
{
357+
// Verify that we got a valid offset
358+
Debug.Assert((imm38 >= -0x2000000000L) && (imm38 < 0x2000000000L));
359+
360+
Debug.Assert((imm38 & 0x3) == 0); // the low two bits must be zero
361+
362+
uint pcInstr = *pCode;
363+
364+
Debug.Assert(pcInstr == 0x1e00000e); // Must be pcaddu18i R14, 0
365+
366+
long relOff = imm38 & 0x20000;
367+
long imm = imm38 + relOff;
368+
relOff = (((imm & 0x1ffff) - relOff) >> 2) & 0xffff;
369+
370+
// Assemble the pc-relative hight20bits of 'imm38' into the pcaddu12i instruction
371+
pcInstr |= (uint)(((imm >> 18) & 0xFFFFF) << 5);
372+
373+
*pCode = pcInstr; // write the assembled instruction
374+
375+
pcInstr = *(pCode + 1);
376+
377+
// Assemble the pc-relative low18bits of 'imm38' into the addid or ld instruction
378+
pcInstr |= (uint)(relOff << 10);
379+
380+
*(pCode + 1) = pcInstr; // write the assembled instruction
381+
382+
Debug.Assert(GetLoongArch64JIR(pCode) == imm38);
383+
}
298384

299385
public Relocation(RelocType relocType, int offset, ISymbolNode target)
300386
{
@@ -334,6 +420,12 @@ public static unsafe void WriteValue(RelocType relocType, void* location, long v
334420
case RelocType.IMAGE_REL_BASED_ARM64_PAGEOFFSET_12A:
335421
PutArm64Rel12((uint*)location, (int)value);
336422
break;
423+
case RelocType.IMAGE_REL_BASED_LOONGARCH64_PC:
424+
PutLoongArch64PC12((uint*)location, value);
425+
break;
426+
case RelocType.IMAGE_REL_BASED_LOONGARCH64_JIR:
427+
PutLoongArch64JIR((uint*)location, value);
428+
break;
337429
default:
338430
Debug.Fail("Invalid RelocType: " + relocType);
339431
break;
@@ -366,6 +458,10 @@ public static unsafe long ReadValue(RelocType relocType, void* location)
366458
return GetArm64Rel21((uint*)location);
367459
case RelocType.IMAGE_REL_BASED_ARM64_PAGEOFFSET_12A:
368460
return GetArm64Rel12((uint*)location);
461+
case RelocType.IMAGE_REL_BASED_LOONGARCH64_PC:
462+
return 0; // (long)GetLoongArch64PC12((uint*)location);
463+
case RelocType.IMAGE_REL_BASED_LOONGARCH64_JIR:
464+
return 0; // (long)GetLoongArch64JIR((uint*)location);
369465
default:
370466
Debug.Fail("Invalid RelocType: " + relocType);
371467
return 0;
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System;
5+
6+
namespace ILCompiler.DependencyAnalysis.LoongArch64
7+
{
8+
public enum AddrModeSize
9+
{
10+
Int8 = 1,
11+
Int16 = 2,
12+
Int32 = 4,
13+
Int64 = 8,
14+
Int128 = 16
15+
}
16+
17+
public struct AddrMode
18+
{
19+
public readonly Register BaseReg;
20+
public readonly Register? IndexReg;
21+
public readonly int Offset;
22+
public readonly byte Scale;
23+
public readonly AddrModeSize Size;
24+
25+
public AddrMode(Register baseRegister, Register? indexRegister, int offset, byte scale, AddrModeSize size)
26+
{
27+
BaseReg = baseRegister;
28+
IndexReg = indexRegister;
29+
Offset = offset;
30+
Scale = scale;
31+
Size = size;
32+
}
33+
}
34+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System;
5+
using System.Diagnostics;
6+
7+
namespace ILCompiler.DependencyAnalysis.LoongArch64
8+
{
9+
public struct LoongArch64Emitter
10+
{
11+
public LoongArch64Emitter(NodeFactory factory, bool relocsOnly)
12+
{
13+
Builder = new ObjectDataBuilder(factory, relocsOnly);
14+
TargetRegister = new TargetRegisterMap(factory.Target.OperatingSystem);
15+
}
16+
17+
public ObjectDataBuilder Builder;
18+
public TargetRegisterMap TargetRegister;
19+
20+
// Assembly stub creation api. TBD, actually make this general purpose
21+
22+
public void EmitMOV(Register regDst, ushort imm16)
23+
{
24+
Debug.Assert((uint)regDst <= 0x1f);
25+
Debug.Assert(imm16 <= 0xfff);
26+
uint instruction = 0x03800000u | (uint)((imm16 & 0xfff) << 10) | (uint)regDst;
27+
Builder.EmitUInt(instruction);
28+
}
29+
30+
// pcaddi regDst, 0
31+
public void EmitPC(Register regDst)
32+
{
33+
Debug.Assert((uint)regDst > 0 && (uint)regDst < 32);
34+
Builder.EmitUInt(0x18000000 | (uint)regDst);
35+
}
36+
37+
// ld_d regDst, regAddr, offset
38+
public void EmitLD(Register regDst, Register regSrc, int offset)
39+
{
40+
Debug.Assert(offset >= -2048 && offset <= 2047);
41+
42+
Builder.EmitUInt((uint)(0x28c00000 | (uint)((offset & 0xfff) << 12) | ((uint)regSrc << 5) | (uint)regDst));
43+
}
44+
45+
public void EmitJMP(ISymbolNode symbol)
46+
{
47+
if (symbol.RepresentsIndirectionCell)
48+
{
49+
// pcaddi R21, 0
50+
EmitPC(Register.R21);
51+
52+
EmitLD(Register.R21, Register.R21, 0x10);
53+
54+
// ld_d R21, R21, 0
55+
EmitLD(Register.R21, Register.R21, 0);
56+
57+
// jirl R0,R21,0
58+
Builder.EmitUInt(0x4c0002a0);
59+
60+
Builder.EmitReloc(symbol, RelocType.IMAGE_REL_BASED_DIR64);
61+
}
62+
else
63+
{
64+
//Builder.EmitReloc(symbol, RelocType.IMAGE_REL_BASED_LOONGARCH64_PC);
65+
Builder.EmitUInt(0xffffffff); // bad code.
66+
throw new NotImplementedException();
67+
}
68+
}
69+
}
70+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Linq;
7+
using System.Text;
8+
using System.Threading.Tasks;
9+
10+
namespace ILCompiler.DependencyAnalysis.LoongArch64
11+
{
12+
public enum Register
13+
{
14+
R0 = 0,
15+
R1 = 1,
16+
R2 = 2,
17+
R3 = 3,
18+
R4 = 4,
19+
R5 = 5,
20+
R6 = 6,
21+
R7 = 7,
22+
R8 = 8,
23+
R9 = 9,
24+
R10 = 10,
25+
R11 = 11,
26+
R12 = 12,
27+
R13 = 13,
28+
R14 = 14,
29+
R15 = 15,
30+
R16 = 16,
31+
R17 = 17,
32+
R18 = 18,
33+
R19 = 19,
34+
R20 = 20,
35+
R21 = 21,
36+
R22 = 22,
37+
R23 = 23,
38+
R24 = 24,
39+
R25 = 25,
40+
R26 = 26,
41+
R27 = 27,
42+
R28 = 28,
43+
R29 = 29,
44+
R30 = 30,
45+
R31 = 31,
46+
47+
None = 32,
48+
NoIndex = 128,
49+
}
50+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System;
5+
6+
using Internal.TypeSystem;
7+
8+
namespace ILCompiler.DependencyAnalysis.LoongArch64
9+
{
10+
/// <summary>
11+
/// Maps logical registers to physical registers on a specified OS.
12+
/// </summary>
13+
public struct TargetRegisterMap
14+
{
15+
public readonly Register Arg0;
16+
public readonly Register Arg1;
17+
public readonly Register Arg2;
18+
public readonly Register Arg3;
19+
public readonly Register Arg4;
20+
public readonly Register Arg5;
21+
public readonly Register Arg6;
22+
public readonly Register Arg7;
23+
public readonly Register Result;
24+
25+
public TargetRegisterMap(TargetOS os)
26+
{
27+
Arg0 = Register.R4;
28+
Arg1 = Register.R5;
29+
Arg2 = Register.R6;
30+
Arg3 = Register.R7;
31+
Arg4 = Register.R8;
32+
Arg5 = Register.R9;
33+
Arg6 = Register.R11;
34+
Arg7 = Register.R12;
35+
Result = Register.R4; // TODO: ???
36+
}
37+
}
38+
}

src/coreclr/tools/Common/Compiler/InstructionSetSupport.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,10 @@ public SimdVectorLength GetVectorTSimdVector()
110110
{
111111
return SimdVectorLength.None;
112112
}
113+
else if (_targetArchitecture == TargetArchitecture.LoongArch64)
114+
{
115+
return SimdVectorLength.None;
116+
}
113117
else
114118
{
115119
Debug.Assert(false); // Unknown architecture

0 commit comments

Comments
 (0)