1 //===--- RISCV.cpp - RISCV Helpers for Tools --------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "RISCV.h"
10 #include "clang/Basic/CharInfo.h"
11 #include "clang/Driver/Driver.h"
12 #include "clang/Driver/DriverDiagnostic.h"
13 #include "clang/Driver/Options.h"
14 #include "llvm/Option/ArgList.h"
15 #include "llvm/Support/TargetParser.h"
16 #include "llvm/Support/raw_ostream.h"
17 #include "ToolChains/CommonArgs.h"
18
19 using namespace clang::driver;
20 using namespace clang::driver::tools;
21 using namespace clang;
22 using namespace llvm::opt;
23
getExtensionTypeDesc(StringRef Ext)24 static StringRef getExtensionTypeDesc(StringRef Ext) {
25 if (Ext.startswith("sx"))
26 return "non-standard supervisor-level extension";
27 if (Ext.startswith("s"))
28 return "standard supervisor-level extension";
29 if (Ext.startswith("x"))
30 return "non-standard user-level extension";
31 return StringRef();
32 }
33
getExtensionType(StringRef Ext)34 static StringRef getExtensionType(StringRef Ext) {
35 if (Ext.startswith("sx"))
36 return "sx";
37 if (Ext.startswith("s"))
38 return "s";
39 if (Ext.startswith("x"))
40 return "x";
41 return StringRef();
42 }
43
isSupportedExtension(StringRef Ext)44 static bool isSupportedExtension(StringRef Ext) {
45 // LLVM does not support "sx", "s" nor "x" extensions.
46 return false;
47 }
48
49 // Extensions may have a version number, and may be separated by
50 // an underscore '_' e.g.: rv32i2_m2.
51 // Version number is divided into major and minor version numbers,
52 // separated by a 'p'. If the minor version is 0 then 'p0' can be
53 // omitted from the version string. E.g., rv32i2p0, rv32i2, rv32i2p1.
getExtensionVersion(const Driver & D,StringRef MArch,StringRef Ext,StringRef In,std::string & Major,std::string & Minor)54 static bool getExtensionVersion(const Driver &D, StringRef MArch,
55 StringRef Ext, StringRef In,
56 std::string &Major, std::string &Minor) {
57 Major = In.take_while(isDigit);
58 In = In.substr(Major.size());
59 if (Major.empty())
60 return true;
61
62 if (In.consume_front("p")) {
63 Minor = In.take_while(isDigit);
64 In = In.substr(Major.size());
65
66 // Expected 'p' to be followed by minor version number.
67 if (Minor.empty()) {
68 std::string Error =
69 "minor version number missing after 'p' for extension";
70 D.Diag(diag::err_drv_invalid_riscv_ext_arch_name)
71 << MArch << Error << Ext;
72 return false;
73 }
74 }
75
76 // TODO: Handle extensions with version number.
77 std::string Error = "unsupported version number " + Major;
78 if (!Minor.empty())
79 Error += "." + Minor;
80 Error += " for extension";
81 D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) << MArch << Error << Ext;
82
83 return false;
84 }
85
86 // Handle other types of extensions other than the standard
87 // general purpose and standard user-level extensions.
88 // Parse the ISA string containing non-standard user-level
89 // extensions, standard supervisor-level extensions and
90 // non-standard supervisor-level extensions.
91 // These extensions start with 'x', 's', 'sx' prefixes, follow a
92 // canonical order, might have a version number (major, minor)
93 // and are separated by a single underscore '_'.
94 // Set the hardware features for the extensions that are supported.
getExtensionFeatures(const Driver & D,const ArgList & Args,std::vector<StringRef> & Features,StringRef & MArch,StringRef & Exts)95 static void getExtensionFeatures(const Driver &D,
96 const ArgList &Args,
97 std::vector<StringRef> &Features,
98 StringRef &MArch, StringRef &Exts) {
99 if (Exts.empty())
100 return;
101
102 // Multi-letter extensions are seperated by a single underscore
103 // as described in RISC-V User-Level ISA V2.2.
104 SmallVector<StringRef, 8> Split;
105 Exts.split(Split, StringRef("_"));
106
107 SmallVector<StringRef, 3> Prefix{"x", "s", "sx"};
108 auto I = Prefix.begin();
109 auto E = Prefix.end();
110
111 SmallVector<StringRef, 8> AllExts;
112
113 for (StringRef Ext : Split) {
114 if (Ext.empty()) {
115 D.Diag(diag::err_drv_invalid_riscv_arch_name) << MArch
116 << "extension name missing after separator '_'";
117 return;
118 }
119
120 StringRef Type = getExtensionType(Ext);
121 StringRef Name(Ext.substr(Type.size()));
122 StringRef Desc = getExtensionTypeDesc(Ext);
123
124 if (Type.empty()) {
125 D.Diag(diag::err_drv_invalid_riscv_ext_arch_name)
126 << MArch << "invalid extension prefix" << Ext;
127 return;
128 }
129
130 // Check ISA extensions are specified in the canonical order.
131 while (I != E && *I != Type)
132 ++I;
133
134 if (I == E) {
135 std::string Error = Desc;
136 Error += " not given in canonical order";
137 D.Diag(diag::err_drv_invalid_riscv_ext_arch_name)
138 << MArch << Error << Ext;
139 return;
140 }
141
142 // The order is OK, do not advance I to the next prefix
143 // to allow repeated extension type, e.g.: rv32ixabc_xdef.
144
145 if (Name.empty()) {
146 std::string Error = Desc;
147 Error += " name missing after";
148 D.Diag(diag::err_drv_invalid_riscv_ext_arch_name)
149 << MArch << Error << Ext;
150 return;
151 }
152
153 std::string Major, Minor;
154 auto Pos = Name.find_if(isDigit);
155 if (Pos != StringRef::npos) {
156 auto Next = Name.substr(Pos);
157 Name = Name.substr(0, Pos);
158 if (!getExtensionVersion(D, MArch, Ext, Next, Major, Minor))
159 return;
160 }
161
162 // Check if duplicated extension.
163 if (llvm::is_contained(AllExts, Ext)) {
164 std::string Error = "duplicated ";
165 Error += Desc;
166 D.Diag(diag::err_drv_invalid_riscv_ext_arch_name)
167 << MArch << Error << Ext;
168 return;
169 }
170
171 // Extension format is correct, keep parsing the extensions.
172 // TODO: Save Type, Name, Major, Minor to avoid parsing them later.
173 AllExts.push_back(Ext);
174 }
175
176 // Set target features.
177 // TODO: Hardware features to be handled in Support/TargetParser.cpp.
178 // TODO: Use version number when setting target features.
179 for (auto Ext : AllExts) {
180 if (!isSupportedExtension(Ext)) {
181 StringRef Desc = getExtensionTypeDesc(getExtensionType(Ext));
182 std::string Error = "unsupported ";
183 Error += Desc;
184 D.Diag(diag::err_drv_invalid_riscv_ext_arch_name)
185 << MArch << Error << Ext;
186 return;
187 }
188 Features.push_back(Args.MakeArgString("+" + Ext));
189 }
190 }
191
getRISCVTargetFeatures(const Driver & D,const ArgList & Args,std::vector<StringRef> & Features)192 void riscv::getRISCVTargetFeatures(const Driver &D, const ArgList &Args,
193 std::vector<StringRef> &Features) {
194 if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
195 StringRef MArch = A->getValue();
196
197 // RISC-V ISA strings must be lowercase.
198 if (llvm::any_of(MArch, [](char c) { return isupper(c); })) {
199 D.Diag(diag::err_drv_invalid_riscv_arch_name)
200 << MArch << "string must be lowercase";
201 return;
202 }
203
204 // ISA string must begin with rv32 or rv64.
205 if (!(MArch.startswith("rv32") || MArch.startswith("rv64")) ||
206 (MArch.size() < 5)) {
207 D.Diag(diag::err_drv_invalid_riscv_arch_name) << MArch
208 << "string must begin with rv32{i,e,g} or rv64{i,g}";
209 return;
210 }
211
212 bool HasRV64 = MArch.startswith("rv64");
213
214 // The canonical order specified in ISA manual.
215 // Ref: Table 22.1 in RISC-V User-Level ISA V2.2
216 StringRef StdExts = "mafdqlcbjtpvn";
217 bool HasF = false, HasD = false;
218 char Baseline = MArch[4];
219
220 // First letter should be 'e', 'i' or 'g'.
221 switch (Baseline) {
222 default:
223 D.Diag(diag::err_drv_invalid_riscv_arch_name) << MArch
224 << "first letter should be 'e', 'i' or 'g'";
225 return;
226 case 'e': {
227 StringRef Error;
228 // Currently LLVM does not support 'e'.
229 // Extension 'e' is not allowed in rv64.
230 if (HasRV64)
231 Error = "standard user-level extension 'e' requires 'rv32'";
232 else
233 Error = "unsupported standard user-level extension 'e'";
234 D.Diag(diag::err_drv_invalid_riscv_arch_name)
235 << MArch << Error;
236 return;
237 }
238 case 'i':
239 break;
240 case 'g':
241 // g = imafd
242 StdExts = StdExts.drop_front(4);
243 Features.push_back("+m");
244 Features.push_back("+a");
245 Features.push_back("+f");
246 Features.push_back("+d");
247 HasF = true;
248 HasD = true;
249 break;
250 }
251
252 // Skip rvxxx
253 StringRef Exts = MArch.substr(5);
254
255 // Remove non-standard extensions and supervisor-level extensions.
256 // They have 'x', 's', 'sx' prefixes. Parse them at the end.
257 // Find the very first occurrence of 's' or 'x'.
258 StringRef OtherExts;
259 size_t Pos = Exts.find_first_of("sx");
260 if (Pos != StringRef::npos) {
261 OtherExts = Exts.substr(Pos);
262 Exts = Exts.substr(0, Pos);
263 }
264
265 std::string Major, Minor;
266 if (!getExtensionVersion(D, MArch, std::string(1, Baseline),
267 Exts, Major, Minor))
268 return;
269
270 // TODO: Use version number when setting target features
271 // and consume the underscore '_' that might follow.
272
273 auto StdExtsItr = StdExts.begin();
274 auto StdExtsEnd = StdExts.end();
275
276 for (auto I = Exts.begin(), E = Exts.end(); I != E; ++I) {
277 char c = *I;
278
279 // Check ISA extensions are specified in the canonical order.
280 while (StdExtsItr != StdExtsEnd && *StdExtsItr != c)
281 ++StdExtsItr;
282
283 if (StdExtsItr == StdExtsEnd) {
284 // Either c contains a valid extension but it was not given in
285 // canonical order or it is an invalid extension.
286 StringRef Error;
287 if (StdExts.contains(c))
288 Error = "standard user-level extension not given in canonical order";
289 else
290 Error = "invalid standard user-level extension";
291 D.Diag(diag::err_drv_invalid_riscv_ext_arch_name)
292 << MArch << Error << std::string(1, c);
293 return;
294 }
295
296 // Move to next char to prevent repeated letter.
297 ++StdExtsItr;
298
299 if (std::next(I) != E) {
300 // Skip c.
301 std::string Next = std::string(std::next(I), E);
302 std::string Major, Minor;
303 if (!getExtensionVersion(D, MArch, std::string(1, c),
304 Next, Major, Minor))
305 return;
306
307 // TODO: Use version number when setting target features
308 // and consume the underscore '_' that might follow.
309 }
310
311 // The order is OK, then push it into features.
312 switch (c) {
313 default:
314 // Currently LLVM supports only "mafdc".
315 D.Diag(diag::err_drv_invalid_riscv_ext_arch_name)
316 << MArch << "unsupported standard user-level extension"
317 << std::string(1, c);
318 return;
319 case 'm':
320 Features.push_back("+m");
321 break;
322 case 'a':
323 Features.push_back("+a");
324 break;
325 case 'f':
326 Features.push_back("+f");
327 HasF = true;
328 break;
329 case 'd':
330 Features.push_back("+d");
331 HasD = true;
332 break;
333 case 'c':
334 Features.push_back("+c");
335 break;
336 }
337 }
338
339 // Dependency check.
340 // It's illegal to specify the 'd' (double-precision floating point)
341 // extension without also specifying the 'f' (single precision
342 // floating-point) extension.
343 if (HasD && !HasF)
344 D.Diag(diag::err_drv_invalid_riscv_arch_name) << MArch
345 << "d requires f extension to also be specified";
346
347 // Additional dependency checks.
348 // TODO: The 'q' extension requires rv64.
349 // TODO: It is illegal to specify 'e' extensions with 'f' and 'd'.
350
351 // Handle all other types of extensions.
352 getExtensionFeatures(D, Args, Features, MArch, OtherExts);
353 }
354
355 // -mrelax is default, unless -mno-relax is specified.
356 if (Args.hasFlag(options::OPT_mrelax, options::OPT_mno_relax, true))
357 Features.push_back("+relax");
358 else
359 Features.push_back("-relax");
360
361 // GCC Compatibility: -mno-save-restore is default, unless -msave-restore is
362 // specified...
363 if (Args.hasFlag(options::OPT_msave_restore, options::OPT_mno_save_restore, false)) {
364 // ... but we don't support -msave-restore, so issue a warning.
365 D.Diag(diag::warn_drv_clang_unsupported)
366 << Args.getLastArg(options::OPT_msave_restore)->getAsString(Args);
367 }
368
369 // Now add any that the user explicitly requested on the command line,
370 // which may override the defaults.
371 handleTargetFeaturesGroup(Args, Features, options::OPT_m_riscv_Features_Group);
372 }
373
getRISCVABI(const ArgList & Args,const llvm::Triple & Triple)374 StringRef riscv::getRISCVABI(const ArgList &Args, const llvm::Triple &Triple) {
375 if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ))
376 return A->getValue();
377
378 return Triple.getArch() == llvm::Triple::riscv32 ? "ilp32" : "lp64";
379 }
380