Clang Project

clang_source_code/lib/Driver/ToolChains/Arch/RISCV.cpp
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
19using namespace clang::driver;
20using namespace clang::driver::tools;
21using namespace clang;
22using namespace llvm::opt;
23
24static 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
34static 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
44static 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.
54static bool getExtensionVersion(const Driver &DStringRef MArch,
55                                StringRef ExtStringRef In,
56                                std::string &Majorstd::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    // Expected 'p' to be followed by minor version number.
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  // TODO: Handle extensions with version number.
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// Handle other types of extensions other than the standard
93// general purpose and standard user-level extensions.
94// Parse the ISA string containing non-standard user-level
95// extensions, standard supervisor-level extensions and
96// non-standard supervisor-level extensions.
97// These extensions start with 'x', 's', 'sx' prefixes, follow a
98// canonical order, might have a version number (major, minor)
99// and are separated by a single underscore '_'.
100// Set the hardware features for the extensions that are supported.
101static void getExtensionFeatures(const Driver &D,
102                                 const ArgList &Args,
103                                 std::vector<StringRef> &Features,
104                                 StringRef &MArchStringRef &Exts) {
105  if (Exts.empty())
106    return;
107
108  // Multi-letter extensions are seperated by a single underscore
109  // as described in RISC-V User-Level ISA V2.2.
110  SmallVector<StringRef8Split;
111  Exts.split(Split, StringRef("_"));
112
113  SmallVector<StringRef3Prefix;
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<StringRef8AllExts;
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    // Check ISA extensions are specified in the canonical order.
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    // The order is OK, do not advance I to the next prefix
153    // to allow repeated extension type, e.g.: rv32ixabc_xdef.
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    // Check if duplicated extension.
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    // Extension format is correct, keep parsing the extensions.
182    // TODO: Save Type, Name, Major, Minor to avoid parsing them later.
183    AllExts.push_back(Ext);
184  }
185
186  // Set target features.
187  // TODO: Hardware features to be handled in Support/TargetParser.cpp.
188  // TODO: Use version number when setting target features.
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
202void riscv::getRISCVTargetFeatures(const Driver &Dconst 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    // RISC-V ISA strings must be lowercase.
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    // ISA string must begin with rv32 or rv64.
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    // The canonical order specified in ISA manual.
227    // Ref: Table 22.1 in RISC-V User-Level ISA V2.2
228    StringRef StdExts = "mafdqlcbjtpvn";
229    bool HasF = falseHasD = false;
230    char Baseline = MArch[4];
231
232    // First letter should be 'e', 'i' or 'g'.
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      // Currently LLVM does not support 'e'.
241      // Extension 'e' is not allowed in rv64.
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      // g = imafd
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    // Skip rvxxx
265    StringRef Exts = MArch.substr(5);
266
267    // Remove non-standard extensions and supervisor-level extensions.
268    // They have 'x', 's', 'sx' prefixes. Parse them at the end.
269    // Find the very first occurrence of 's' or 'x'.
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 MajorMinor;
278    if (!getExtensionVersion(D, MArch, std::string(1, Baseline),
279                             Exts, Major, Minor))
280      return;
281
282    // TODO: Use version number when setting target features
283    // and consume the underscore '_' that might follow.
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      // Check ISA extensions are specified in the canonical order.
292      while (StdExtsItr != StdExtsEnd && *StdExtsItr != c)
293        ++StdExtsItr;
294
295      if (StdExtsItr == StdExtsEnd) {
296        // Either c contains a valid extension but it was not given in
297        // canonical order or it is an invalid extension.
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      // Move to next char to prevent repeated letter.
309      ++StdExtsItr;
310
311      if (std::next(I) != E) {
312        // Skip c.
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        // TODO: Use version number when setting target features
320        // and consume the underscore '_' that might follow.
321      }
322
323      // The order is OK, then push it into features.
324      switch (c) {
325      default:
326        // Currently LLVM supports only "mafdc".
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    // Dependency check.
352    // It's illegal to specify the 'd' (double-precision floating point)
353    // extension without also specifying the 'f' (single precision
354    // floating-point) extension.
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    // Additional dependency checks.
360    // TODO: The 'q' extension requires rv64.
361    // TODO: It is illegal to specify 'e' extensions with 'f' and 'd'.
362
363    // Handle all other types of extensions.
364    getExtensionFeatures(D, Args, Features, MArch, OtherExts);
365  }
366
367  // -mrelax is default, unless -mno-relax is specified.
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  // Now add any that the user explicitly requested on the command line,
380  // which may override the defaults.
381  handleTargetFeaturesGroup(Args, Features, options::OPT_m_riscv_Features_Group);
382}
383
384StringRef riscv::getRISCVABI(const ArgList &Argsconst 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