Skip to content

Commit 3231ec6

Browse files
[RISC-V] Require --single-hart to build without the A extension
Without A there is no atomic memory operation to emit, so Interlocked and CmpXchg lower to a plain read/modify/write. Whether that is sufficient depends on the target running on one hart and never being preempted. Neither the ISA nor the ABI says anything about that: a soft-float lp64 image is perfectly normal on rv64imac hardware with threads, and would lose atomicity silently. So it has to be asserted rather than inferred. Add --single-hart to ilc and reject an ISA without A unless it is passed. The flag names the property it claims, and the failure is at compile time rather than at run time. Signed-off-by: Maxim Menshikov <maksim.menshikov@nethermind.io>
1 parent 7fe8cb0 commit 3231ec6

3 files changed

Lines changed: 20 additions & 4 deletions

File tree

‎src/coreclr/tools/Common/InstructionSetHelpers.cs‎

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -96,10 +96,11 @@ public static InstructionSetSupport ConfigureInstructionSetSupport(string instru
9696
}
9797
else if (targetArchitecture == TargetArchitecture.RiscV64)
9898
{
99-
// The rv64gc baseline: D implies F, so "d", "c" and "a" cover
100-
// the G+C extensions. Reduced-ISA targets (e.g. zkVM guests)
101-
// opt out with --instruction-set=-a,-c,-d,-f. The lp64 (soft-float)
102-
// ABI target has no F/D by definition.
99+
// The rv64gc baseline: D implies F, so "d", "c" and "a" cover the G+C
100+
// extensions. The lp64 (soft-float) ABI target has no F/D by definition;
101+
// it still defaults to C and A, and a reduced-ISA target drops those with
102+
// --instruction-set=-a,-c. Dropping A also requires ilc's --single-hart,
103+
// because Interlocked is not atomic without it.
103104
instructionSetSupportBuilder.AddSupportedInstructionSet("base");
104105
if (targetAbi != TargetAbi.NativeAotRiscV64SoftFloat)
105106
{

‎src/coreclr/tools/aot/ILCompiler/ILCompilerRootCommand.cs‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,8 @@ internal sealed class ILCompilerRootCommand : RootCommand
118118
new("--parallelism") { CustomParser = MakeParallelism, DefaultValueFactory = MakeParallelism, Description = "Maximum number of threads to use during compilation" };
119119
public Option<string> InstructionSet { get; } =
120120
new("--instruction-set") { Description = "Instruction set to allow or disallow" };
121+
public Option<bool> SingleHart { get; } =
122+
new("--single-hart") { Description = "RISC-V: the target runs on one hart and is never preempted. Required to build without the A extension, because Interlocked then lowers to a non-atomic read/modify/write" };
121123
public Option<int> MaxVectorTBitWidth { get; } =
122124
new("--max-vectort-bitwidth") { Description = "Maximum width, in bits, that Vector<T> is allowed to be" };
123125
public Option<string> Guard { get; } =
@@ -243,6 +245,7 @@ public ILCompilerRootCommand(string[] args) : base(".NET Native IL Compiler")
243245
Options.Add(RuntimeKnobs);
244246
Options.Add(Parallelism);
245247
Options.Add(InstructionSet);
248+
Options.Add(SingleHart);
246249
Options.Add(MaxVectorTBitWidth);
247250
Options.Add(Guard);
248251
Options.Add(Dehydrate);

‎src/coreclr/tools/aot/ILCompiler/Program.cs‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,18 @@ public int Run()
112112
isReadyToRun: false,
113113
targetAbi: targetAbi);
114114

115+
if (targetArchitecture == TargetArchitecture.RiscV64 &&
116+
!instructionSetSupport.IsInstructionSetSupported(InstructionSet.RiscV64_A) &&
117+
!Get(_command.SingleHart))
118+
{
119+
// Without A there is no atomic memory operation to emit, so Interlocked and
120+
// CmpXchg lower to a plain read/modify/write. Whether that is sufficient is a
121+
// property of the execution environment, not of the ISA or the ABI, so it has
122+
// to be asserted rather than inferred.
123+
throw new CommandLineException(
124+
"Building without the A extension requires --single-hart: Interlocked operations are not atomic without it.");
125+
}
126+
115127
string systemModuleName = Get(_command.SystemModuleName);
116128
string reflectionData = Get(_command.ReflectionData);
117129
bool supportsReflection = reflectionData != "none" && systemModuleName == Helpers.DefaultSystemModule;

0 commit comments

Comments
 (0)