clang 8.0.0

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