1 | |
2 | |
3 | |
4 | |
5 | |
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 | |
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 | |
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 | |
44 | static bool isSupportedExtension(StringRef Ext) { |
45 | |
46 | return false; |
47 | } |
48 | |
49 | |
50 | |
51 | |
52 | |
53 | |
54 | static bool getExtensionVersion(const Driver &D, StringRef MArch, |
55 | StringRef Ext, StringRef In, |
56 | std::string &Major, std::string &Minor) { |
57 | auto I = In.begin(); |
58 | auto E = In.end(); |
59 | |
60 | while (I != E && isDigit(*I)) |
61 | Major.append(1, *I++); |
62 | |
63 | if (Major.empty()) |
64 | return true; |
65 | |
66 | if (I != E && *I == 'p') { |
67 | ++I; |
68 | |
69 | while (I != E && isDigit(*I)) |
70 | Minor.append(1, *I++); |
71 | |
72 | |
73 | if (Minor.empty()) { |
74 | std::string Error = |
75 | "minor version number missing after 'p' for extension"; |
76 | D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) |
77 | << MArch << Error << Ext; |
78 | return false; |
79 | } |
80 | } |
81 | |
82 | |
83 | std::string Error = "unsupported version number " + Major; |
84 | if (!Minor.empty()) |
85 | Error += "." + Minor; |
86 | Error += " for extension"; |
87 | D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) << MArch << Error << Ext; |
88 | |
89 | return false; |
90 | } |
91 | |
92 | |
93 | |
94 | |
95 | |
96 | |
97 | |
98 | |
99 | |
100 | |
101 | static void getExtensionFeatures(const Driver &D, |
102 | const ArgList &Args, |
103 | std::vector<StringRef> &Features, |
104 | StringRef &MArch, StringRef &Exts) { |
105 | if (Exts.empty()) |
106 | return; |
107 | |
108 | |
109 | |
110 | SmallVector<StringRef, 8> Split; |
111 | Exts.split(Split, StringRef("_")); |
112 | |
113 | SmallVector<StringRef, 3> Prefix; |
114 | Prefix.push_back("x"); |
115 | Prefix.push_back("s"); |
116 | Prefix.push_back("sx"); |
117 | auto I = Prefix.begin(); |
118 | auto E = Prefix.end(); |
119 | |
120 | SmallVector<StringRef, 8> AllExts; |
121 | |
122 | for (StringRef Ext : Split) { |
123 | |
124 | if (Ext.empty()) { |
125 | D.Diag(diag::err_drv_invalid_riscv_arch_name) << MArch |
126 | << "extension name missing after separator '_'"; |
127 | return; |
128 | } |
129 | |
130 | StringRef Type = getExtensionType(Ext); |
131 | StringRef Name(Ext.substr(Type.size())); |
132 | StringRef Desc = getExtensionTypeDesc(Ext); |
133 | |
134 | if (Type.empty()) { |
135 | D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) |
136 | << MArch << "invalid extension prefix" << Ext; |
137 | return; |
138 | } |
139 | |
140 | |
141 | while (I != E && *I != Type) |
142 | ++I; |
143 | |
144 | if (I == E) { |
145 | std::string Error = Desc; |
146 | Error += " not given in canonical order"; |
147 | D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) |
148 | << MArch << Error << Ext; |
149 | return; |
150 | } |
151 | |
152 | |
153 | |
154 | |
155 | if (Name.empty()) { |
156 | std::string Error = Desc; |
157 | Error += " name missing after"; |
158 | D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) |
159 | << MArch << Error << Ext; |
160 | return; |
161 | } |
162 | |
163 | std::string Major, Minor; |
164 | auto Pos = Name.find_if(isDigit); |
165 | if (Pos != StringRef::npos) { |
166 | auto Next = Name.substr(Pos); |
167 | Name = Name.substr(0, Pos); |
168 | if (!getExtensionVersion(D, MArch, Ext, Next, Major, Minor)) |
169 | return; |
170 | } |
171 | |
172 | |
173 | if (llvm::is_contained(AllExts, Ext)) { |
174 | std::string Error = "duplicated "; |
175 | Error += Desc; |
176 | D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) |
177 | << MArch << Error << Ext; |
178 | return; |
179 | } |
180 | |
181 | |
182 | |
183 | AllExts.push_back(Ext); |
184 | } |
185 | |
186 | |
187 | |
188 | |
189 | for (auto Ext : AllExts) { |
190 | if (!isSupportedExtension(Ext)) { |
191 | StringRef Desc = getExtensionTypeDesc(getExtensionType(Ext)); |
192 | std::string Error = "unsupported "; |
193 | Error += Desc; |
194 | D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) |
195 | << MArch << Error << Ext; |
196 | return; |
197 | } |
198 | Features.push_back(Args.MakeArgString("+" + Ext)); |
199 | } |
200 | } |
201 | |
202 | void riscv::getRISCVTargetFeatures(const Driver &D, const ArgList &Args, |
203 | std::vector<StringRef> &Features) { |
204 | if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) { |
205 | StringRef MArch = A->getValue(); |
206 | |
207 | |
208 | if (std::any_of(std::begin(MArch), std::end(MArch), |
209 | [](char c) { return isupper(c); })) { |
210 | |
211 | D.Diag(diag::err_drv_invalid_riscv_arch_name) << MArch |
212 | << "string must be lowercase"; |
213 | return; |
214 | } |
215 | |
216 | |
217 | if (!(MArch.startswith("rv32") || MArch.startswith("rv64")) || |
218 | (MArch.size() < 5)) { |
219 | D.Diag(diag::err_drv_invalid_riscv_arch_name) << MArch |
220 | << "string must begin with rv32{i,e,g} or rv64{i,g}"; |
221 | return; |
222 | } |
223 | |
224 | bool HasRV64 = MArch.startswith("rv64") ? true : false; |
225 | |
226 | |
227 | |
228 | StringRef StdExts = "mafdqlcbjtpvn"; |
229 | bool HasF = false, HasD = false; |
230 | char Baseline = MArch[4]; |
231 | |
232 | |
233 | switch (Baseline) { |
234 | default: |
235 | D.Diag(diag::err_drv_invalid_riscv_arch_name) << MArch |
236 | << "first letter should be 'e', 'i' or 'g'"; |
237 | return; |
238 | case 'e': { |
239 | StringRef Error; |
240 | |
241 | |
242 | if (HasRV64) |
243 | Error = "standard user-level extension 'e' requires 'rv32'"; |
244 | else |
245 | Error = "unsupported standard user-level extension 'e'"; |
246 | D.Diag(diag::err_drv_invalid_riscv_arch_name) |
247 | << MArch << Error; |
248 | return; |
249 | } |
250 | case 'i': |
251 | break; |
252 | case 'g': |
253 | |
254 | StdExts = StdExts.drop_front(4); |
255 | Features.push_back("+m"); |
256 | Features.push_back("+a"); |
257 | Features.push_back("+f"); |
258 | Features.push_back("+d"); |
259 | HasF = true; |
260 | HasD = true; |
261 | break; |
262 | } |
263 | |
264 | |
265 | StringRef Exts = MArch.substr(5); |
266 | |
267 | |
268 | |
269 | |
270 | StringRef OtherExts; |
271 | size_t Pos = Exts.find_first_of("sx"); |
272 | if (Pos != StringRef::npos) { |
273 | OtherExts = Exts.substr(Pos); |
274 | Exts = Exts.substr(0, Pos); |
275 | } |
276 | |
277 | std::string Major, Minor; |
278 | if (!getExtensionVersion(D, MArch, std::string(1, Baseline), |
279 | Exts, Major, Minor)) |
280 | return; |
281 | |
282 | |
283 | |
284 | |
285 | auto StdExtsItr = StdExts.begin(); |
286 | auto StdExtsEnd = StdExts.end(); |
287 | |
288 | for (auto I = Exts.begin(), E = Exts.end(); I != E; ++I) { |
289 | char c = *I; |
290 | |
291 | |
292 | while (StdExtsItr != StdExtsEnd && *StdExtsItr != c) |
293 | ++StdExtsItr; |
294 | |
295 | if (StdExtsItr == StdExtsEnd) { |
296 | |
297 | |
298 | StringRef Error; |
299 | if (StdExts.contains(c)) |
300 | Error = "standard user-level extension not given in canonical order"; |
301 | else |
302 | Error = "invalid standard user-level extension"; |
303 | D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) |
304 | << MArch << Error << std::string(1, c); |
305 | return; |
306 | } |
307 | |
308 | |
309 | ++StdExtsItr; |
310 | |
311 | if (std::next(I) != E) { |
312 | |
313 | std::string Next = std::string(std::next(I), E); |
314 | std::string Major, Minor; |
315 | if (!getExtensionVersion(D, MArch, std::string(1, c), |
316 | Next, Major, Minor)) |
317 | return; |
318 | |
319 | |
320 | |
321 | } |
322 | |
323 | |
324 | switch (c) { |
325 | default: |
326 | |
327 | D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) |
328 | << MArch << "unsupported standard user-level extension" |
329 | << std::string(1, c); |
330 | return; |
331 | case 'm': |
332 | Features.push_back("+m"); |
333 | break; |
334 | case 'a': |
335 | Features.push_back("+a"); |
336 | break; |
337 | case 'f': |
338 | Features.push_back("+f"); |
339 | HasF = true; |
340 | break; |
341 | case 'd': |
342 | Features.push_back("+d"); |
343 | HasD = true; |
344 | break; |
345 | case 'c': |
346 | Features.push_back("+c"); |
347 | break; |
348 | } |
349 | } |
350 | |
351 | |
352 | |
353 | |
354 | |
355 | if (HasD && !HasF) |
356 | D.Diag(diag::err_drv_invalid_riscv_arch_name) << MArch |
357 | << "d requires f extension to also be specified"; |
358 | |
359 | |
360 | |
361 | |
362 | |
363 | |
364 | getExtensionFeatures(D, Args, Features, MArch, OtherExts); |
365 | } |
366 | |
367 | |
368 | bool Relax = true; |
369 | if (auto *A = Args.getLastArg(options::OPT_mrelax, options::OPT_mno_relax)) { |
370 | if (A->getOption().matches(options::OPT_mno_relax)) { |
371 | Relax = false; |
372 | Features.push_back("-relax"); |
373 | } |
374 | } |
375 | |
376 | if (Relax) |
377 | Features.push_back("+relax"); |
378 | |
379 | |
380 | |
381 | handleTargetFeaturesGroup(Args, Features, options::OPT_m_riscv_Features_Group); |
382 | } |
383 | |
384 | StringRef riscv::getRISCVABI(const ArgList &Args, const llvm::Triple &Triple) { |
385 | if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) |
386 | return A->getValue(); |
387 | |
388 | return Triple.getArch() == llvm::Triple::riscv32 ? "ilp32" : "lp64"; |
389 | } |
390 | |