Skip to content

Commit 5a2d151

Browse files
authored
[RISC-V] Add crossgen2 for riscv64 (#95188)
* Add crossgen2 for riscv64 * Fix review comments * Fix review
1 parent 7957edc commit 5a2d151

38 files changed

+1193
-8
lines changed

src/coreclr/tools/Common/CommandLineHelpers.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ public static TargetArchitecture GetTargetArchitecture(string token)
9696
Architecture.Arm => TargetArchitecture.ARM,
9797
Architecture.Arm64 => TargetArchitecture.ARM64,
9898
Architecture.LoongArch64 => TargetArchitecture.LoongArch64,
99+
(Architecture)9 => TargetArchitecture.RiscV64, /* TODO: update with Architecture.RiscV64 */
99100
_ => throw new NotImplementedException()
100101
};
101102
}
@@ -108,6 +109,7 @@ public static TargetArchitecture GetTargetArchitecture(string token)
108109
"arm" or "armel" => TargetArchitecture.ARM,
109110
"arm64" => TargetArchitecture.ARM64,
110111
"loongarch64" => TargetArchitecture.LoongArch64,
112+
"riscv64" => TargetArchitecture.RiscV64,
111113
_ => throw new CommandLineException($"Target architecture '{token}' is not supported")
112114
};
113115
}

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,13 @@ public override ObjectData GetData(NodeFactory factory, bool relocsOnly)
7575
loongarch64Emitter.Builder.AddSymbol(this);
7676
return loongarch64Emitter.Builder.ToObjectData();
7777

78+
case TargetArchitecture.RiscV64:
79+
RiscV64.RiscV64Emitter riscv64Emitter = new RiscV64.RiscV64Emitter(factory, relocsOnly);
80+
EmitCode(factory, ref riscv64Emitter, relocsOnly);
81+
riscv64Emitter.Builder.RequireInitialAlignment(alignment);
82+
riscv64Emitter.Builder.AddSymbol(this);
83+
return riscv64Emitter.Builder.ToObjectData();
84+
7885
default:
7986
throw new NotImplementedException();
8087
}
@@ -85,5 +92,6 @@ public override ObjectData GetData(NodeFactory factory, bool relocsOnly)
8592
protected abstract void EmitCode(NodeFactory factory, ref ARM.ARMEmitter instructionEncoder, bool relocsOnly);
8693
protected abstract void EmitCode(NodeFactory factory, ref ARM64.ARM64Emitter instructionEncoder, bool relocsOnly);
8794
protected abstract void EmitCode(NodeFactory factory, ref LoongArch64.LoongArch64Emitter instructionEncoder, bool relocsOnly);
95+
protected abstract void EmitCode(NodeFactory factory, ref RiscV64.RiscV64Emitter instructionEncoder, bool relocsOnly);
8896
}
8997
}

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,9 @@ public void EmitReloc(ISymbolNode symbol, RelocType relocType, int delta = 0)
319319

320320
case RelocType.IMAGE_REL_BASED_LOONGARCH64_PC:
321321
case RelocType.IMAGE_REL_BASED_LOONGARCH64_JIR:
322+
323+
//TODO: consider removal of IMAGE_REL_RISCV64_JALR from runtime too
324+
case RelocType.IMAGE_REL_BASED_RISCV64_PC:
322325
Debug.Assert(delta == 0);
323326
// Do not vacate space for this kind of relocation, because
324327
// the space is embedded in the instruction.

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

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ public enum RelocType
1919
IMAGE_REL_BASED_ARM64_BRANCH26 = 0x15, // Arm64: B, BL
2020
IMAGE_REL_BASED_LOONGARCH64_PC = 0x16, // LoongArch64: pcaddu12i+imm12
2121
IMAGE_REL_BASED_LOONGARCH64_JIR = 0x17, // LoongArch64: pcaddu18i+jirl
22+
IMAGE_REL_BASED_RISCV64_PC = 0x18, // RiscV64: auipc
2223
IMAGE_REL_BASED_RELPTR32 = 0x7C, // 32-bit relative address from byte starting reloc
2324
// This is a special NGEN-specific relocation type
2425
// for relative pointer (used to make NGen relocation
@@ -411,6 +412,47 @@ private static unsafe void PutLoongArch64JIR(uint* pCode, long imm38)
411412
Debug.Assert(GetLoongArch64JIR(pCode) == imm38);
412413
}
413414

415+
private static unsafe int GetRiscV64PC(uint* pCode)
416+
{
417+
uint auipcInstr = *pCode;
418+
Debug.Assert((auipcInstr & 0x7f) == 0x00000017);
419+
// first get the high 20 bits,
420+
int imm = (int)((auipcInstr & 0xfffff000));
421+
// then get the low 12 bits,
422+
uint addiInstr = *(pCode + 1);
423+
Debug.Assert((addiInstr & 0x707f) == 0x00000013);
424+
imm += ((int)(addiInstr)) >> 20;
425+
426+
return imm;
427+
}
428+
429+
// INS_OPTS_RELOC: placeholders. 2-ins:
430+
// case:EA_HANDLE_CNS_RELOC
431+
// auipc reg, off-hi-20bits
432+
// addi reg, reg, off-lo-12bits
433+
// case:EA_PTR_DSP_RELOC
434+
// auipc reg, off-hi-20bits
435+
// ld reg, reg, off-lo-12bits
436+
private static unsafe void PutRiscV64PC(uint* pCode, long imm32)
437+
{
438+
// Verify that we got a valid offset
439+
Debug.Assert((int)imm32 == imm32);
440+
441+
int doff = (int)(imm32 & 0xfff);
442+
uint auipcInstr = *pCode;
443+
Debug.Assert((auipcInstr & 0x7f) == 0x00000017);
444+
445+
auipcInstr |= (uint)((imm32 + 0x800) & 0xfffff000);
446+
*pCode = auipcInstr;
447+
448+
uint addiInstr = *(pCode + 1);
449+
Debug.Assert((addiInstr & 0x707f) == 0x00000013);
450+
addiInstr |= (uint)((doff & 0xfff) << 20);
451+
*(pCode + 1) = addiInstr;
452+
453+
Debug.Assert(GetRiscV64PC(pCode) == imm32);
454+
}
455+
414456
public Relocation(RelocType relocType, int offset, ISymbolNode target)
415457
{
416458
RelocType = relocType;
@@ -455,6 +497,9 @@ public static unsafe void WriteValue(RelocType relocType, void* location, long v
455497
case RelocType.IMAGE_REL_BASED_LOONGARCH64_JIR:
456498
PutLoongArch64JIR((uint*)location, value);
457499
break;
500+
case RelocType.IMAGE_REL_BASED_RISCV64_PC:
501+
PutRiscV64PC((uint*)location, value);
502+
break;
458503
default:
459504
Debug.Fail("Invalid RelocType: " + relocType);
460505
break;
@@ -517,6 +562,8 @@ public static unsafe long ReadValue(RelocType relocType, void* location)
517562
return (long)GetLoongArch64PC12((uint*)location);
518563
case RelocType.IMAGE_REL_BASED_LOONGARCH64_JIR:
519564
return (long)GetLoongArch64JIR((uint*)location);
565+
case RelocType.IMAGE_REL_BASED_RISCV64_PC:
566+
return (long)GetRiscV64PC((uint*)location);
520567
default:
521568
Debug.Fail("Invalid RelocType: " + relocType);
522569
return 0;
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
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+
namespace ILCompiler.DependencyAnalysis.RiscV64
5+
{
6+
public enum AddrModeSize
7+
{
8+
Int8 = 1,
9+
Int16 = 2,
10+
Int32 = 4,
11+
Int64 = 8,
12+
Int128 = 16
13+
}
14+
15+
public struct AddrMode
16+
{
17+
public readonly Register BaseReg;
18+
public readonly Register? IndexReg;
19+
public readonly int Offset;
20+
public readonly byte Scale;
21+
public readonly AddrModeSize Size;
22+
23+
public AddrMode(Register baseRegister, Register? indexRegister, int offset, byte scale, AddrModeSize size)
24+
{
25+
BaseReg = baseRegister;
26+
IndexReg = indexRegister;
27+
Offset = offset;
28+
Scale = scale;
29+
Size = size;
30+
}
31+
}
32+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
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+
namespace ILCompiler.DependencyAnalysis.RiscV64
5+
{
6+
public enum Register
7+
{
8+
X0,
9+
X1,
10+
X2,
11+
X3,
12+
X4,
13+
X5,
14+
X6,
15+
X7,
16+
X8,
17+
X9,
18+
X10,
19+
X11,
20+
X12,
21+
X13,
22+
X14,
23+
X15,
24+
X16,
25+
X17,
26+
X18,
27+
X19,
28+
X20,
29+
X21,
30+
X22,
31+
X23,
32+
X24,
33+
X25,
34+
X26,
35+
X27,
36+
X28,
37+
X29,
38+
X30,
39+
X31,
40+
41+
None,
42+
NoIndex = 128
43+
}
44+
}
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
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.RiscV64
8+
{
9+
public struct RiscV64Emitter
10+
{
11+
public RiscV64Emitter(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+
//ebreak
23+
public void EmitBreak()
24+
{
25+
Builder.EmitUInt(0x00100073);
26+
}
27+
28+
public void EmitLI(Register regDst, int offset)
29+
{
30+
Debug.Assert((offset >= -2048) && (offset <= 2047));
31+
EmitADDI(regDst, Register.X0, offset);
32+
}
33+
34+
public void EmitMOV(Register regDst, Register regSrc)
35+
{
36+
EmitADDI(regDst, regSrc, 0);
37+
}
38+
39+
public void EmitMOV(Register regDst, ISymbolNode symbol)
40+
{
41+
Builder.EmitReloc(symbol, RelocType.IMAGE_REL_BASED_RISCV64_PC);
42+
//auipc reg, off-hi-20bits
43+
EmitPC(regDst);
44+
//addi reg, reg, off-lo-12bits
45+
EmitADDI(regDst, regDst, 0);
46+
}
47+
48+
// auipc regDst, 0
49+
public void EmitPC(Register regDst)
50+
{
51+
Debug.Assert((uint)regDst > 0 && (uint)regDst < 32);
52+
Builder.EmitUInt(0x00000017u | (uint)regDst << 7);
53+
}
54+
55+
// addi regDst, regSrc, offset
56+
public void EmitADDI(Register regDst, Register regSrc, int offset)
57+
{
58+
Debug.Assert((uint)regDst <= 0x1f);
59+
Debug.Assert((uint)regSrc <= 0x1f);
60+
Debug.Assert((offset >= -2048) && (offset <= 2047));
61+
Builder.EmitUInt((uint)(0x00000013u | ((uint)regSrc << 15) | ((uint)regDst << 7) | (uint)((offset & 0xfff) << 20)));
62+
}
63+
64+
// xori regDst, regSrc, offset
65+
public void EmitXORI(Register regDst, Register regSrc, int offset)
66+
{
67+
Debug.Assert((offset >= -2048) && (offset <= 2047));
68+
Builder.EmitUInt((uint)(0x00004013u | ((uint)regSrc << 15) | ((uint)regDst << 7) | (uint)((offset & 0xfff) << 20)));
69+
}
70+
71+
// ld regDst, offset(regSrc)
72+
public void EmitLD(Register regDst, Register regSrc, int offset)
73+
{
74+
Debug.Assert((offset >= -2048) && (offset <= 2047));
75+
Builder.EmitUInt((uint)(0x00003003u | ((uint)regSrc << 15) | ((uint)regDst << 7) | (uint)((offset & 0xfff) << 20)));
76+
}
77+
78+
// jalr regDst, offset(regSrc)
79+
public void EmitJALR(Register regDst, Register regSrc, int offset)
80+
{
81+
Debug.Assert((offset >= -2048) && (offset <= 2047));
82+
Builder.EmitUInt((uint)(0x00000067u | ((uint)regSrc << 15) | ((uint)regDst << 7) | (uint)((offset & 0xfff) << 20)));
83+
}
84+
85+
public void EmitRET()
86+
{
87+
// jalr x0,0(x1)
88+
EmitJALR(Register.X0, Register.X1, 0);
89+
}
90+
91+
public void EmitJMP(Register reg)
92+
{
93+
//jalr x0, 0(reg)
94+
EmitJALR(Register.X0, reg, 0);
95+
}
96+
97+
public void EmitJMP(ISymbolNode symbol)
98+
{
99+
if (symbol.RepresentsIndirectionCell)
100+
{
101+
//auipc x29, 0
102+
EmitPC(Register.X29);
103+
//ld x29,16(x29)
104+
EmitLD(Register.X29, Register.X29, 16);
105+
//ld x29,0(x29)
106+
EmitLD(Register.X29, Register.X29, 0);
107+
//jalr x0,0(x29)
108+
EmitJALR(Register.X0, Register.X29, 0);
109+
110+
Builder.EmitReloc(symbol, RelocType.IMAGE_REL_BASED_DIR64);
111+
}
112+
else
113+
{
114+
Builder.EmitUInt(0x00000000); // bad code.
115+
throw new NotImplementedException();
116+
}
117+
}
118+
119+
public void EmitRETIfZero(Register regSrc)
120+
{
121+
// bne regSrc, x0, 8
122+
Builder.EmitUInt((uint)(0x00001463 | ((uint)regSrc << 15)));
123+
EmitRET();
124+
}
125+
126+
public void EmitJMPIfZero(Register regSrc, ISymbolNode symbol)
127+
{
128+
uint offset = symbol.RepresentsIndirectionCell ? 28u : 8u;
129+
uint encodedOffset = ((offset & 0x1e) << 7) | ((offset & 0x7e0) << 20) | ((offset & 0x800) >> 4) | ((offset & 0x1000) << 19);
130+
// bne regSrc, x0, offset
131+
Builder.EmitUInt((uint)(0x00001063 | ((uint)regSrc << 15) | encodedOffset));
132+
EmitJMP(symbol);
133+
}
134+
}
135+
}
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 Internal.TypeSystem;
5+
6+
namespace ILCompiler.DependencyAnalysis.RiscV64
7+
{
8+
/// <summary>
9+
/// Maps logical registers to physical registers on a specified OS.
10+
/// </summary>
11+
public struct TargetRegisterMap
12+
{
13+
public readonly Register Arg0;
14+
public readonly Register Arg1;
15+
public readonly Register Arg2;
16+
public readonly Register Arg3;
17+
public readonly Register Arg4;
18+
public readonly Register Arg5;
19+
public readonly Register Arg6;
20+
public readonly Register Arg7;
21+
public readonly Register IntraProcedureCallScratch1;
22+
public readonly Register Result;
23+
24+
public TargetRegisterMap(TargetOS os)
25+
{
26+
Arg0 = Register.X10;
27+
Arg1 = Register.X11;
28+
Arg2 = Register.X12;
29+
Arg3 = Register.X13;
30+
Arg4 = Register.X14;
31+
Arg5 = Register.X15;
32+
Arg6 = Register.X16;
33+
Arg7 = Register.X17;
34+
IntraProcedureCallScratch1 = Register.X28;
35+
Result = Register.X10;
36+
}
37+
}
38+
}

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,10 @@ public SimdVectorLength GetVectorTSimdVector()
141141
{
142142
return SimdVectorLength.None;
143143
}
144+
else if (_targetArchitecture == TargetArchitecture.RiscV64)
145+
{
146+
return SimdVectorLength.None;
147+
}
144148
else
145149
{
146150
Debug.Assert(false); // Unknown architecture

0 commit comments

Comments
 (0)