1//===--- LoongArch.cpp - LoongArch 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 "LoongArch.h"
10#include "clang/Basic/DiagnosticDriver.h"
11#include "clang/Driver/Driver.h"
12#include "clang/Driver/DriverDiagnostic.h"
13#include "clang/Driver/Options.h"
14#include "llvm/Support/LoongArchTargetParser.h"
15
16using namespace clang::driver;
17using namespace clang::driver::tools;
18using namespace clang;
19using namespace llvm::opt;
20
21StringRef loongarch::getLoongArchABI(const Driver &D, const ArgList &Args,
22                                     const llvm::Triple &Triple) {
23  assert((Triple.getArch() == llvm::Triple::loongarch32 ||
24          Triple.getArch() == llvm::Triple::loongarch64) &&
25         "Unexpected triple");
26  bool IsLA32 = Triple.getArch() == llvm::Triple::loongarch32;
27
28  // Check -m*-float firstly since they have highest priority.
29  if (const Arg *A = Args.getLastArg(options::OPT_mdouble_float,
30                                     options::OPT_msingle_float,
31                                     options::OPT_msoft_float)) {
32    if (A->getOption().matches(options::OPT_mdouble_float))
33      return IsLA32 ? "ilp32d" : "lp64d";
34    if (A->getOption().matches(options::OPT_msingle_float))
35      return IsLA32 ? "ilp32f" : "lp64f";
36    if (A->getOption().matches(options::OPT_msoft_float))
37      return IsLA32 ? "ilp32s" : "lp64s";
38  }
39
40  // If `-mabi=` is specified, use it.
41  if (const Arg *A = Args.getLastArg(options::OPT_mabi_EQ))
42    return A->getValue();
43
44  // Select abi based on -mfpu=xx.
45  if (const Arg *A = Args.getLastArg(options::OPT_mfpu_EQ)) {
46    StringRef FPU = A->getValue();
47    if (FPU == "64")
48      return IsLA32 ? "ilp32d" : "lp64d";
49    if (FPU == "32")
50      return IsLA32 ? "ilp32f" : "lp64f";
51    if (FPU == "0" || FPU == "none")
52      return IsLA32 ? "ilp32s" : "lp64s";
53    D.Diag(diag::err_drv_loongarch_invalid_mfpu_EQ) << FPU;
54  }
55
56  // Choose a default based on the triple.
57  return IsLA32 ? "ilp32d" : "lp64d";
58}
59
60void loongarch::getLoongArchTargetFeatures(const Driver &D,
61                                           const llvm::Triple &Triple,
62                                           const ArgList &Args,
63                                           std::vector<StringRef> &Features) {
64  StringRef ArchName;
65  llvm::LoongArch::ArchKind ArchKind = llvm::LoongArch::ArchKind::AK_INVALID;
66  if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
67    ArchKind = llvm::LoongArch::parseArch(A->getValue());
68    if (ArchKind == llvm::LoongArch::ArchKind::AK_INVALID) {
69      D.Diag(clang::diag::err_drv_invalid_arch_name) << A->getAsString(Args);
70      return;
71    }
72    ArchName = A->getValue();
73  }
74
75  // TODO: handle -march=native and -mtune=xx.
76
77  // Select a default arch name.
78  if (ArchName.empty() && Triple.getArch() == llvm::Triple::loongarch64)
79    ArchName = "loongarch64";
80
81  if (!ArchName.empty())
82    llvm::LoongArch::getArchFeatures(ArchName, Features);
83
84  // Select floating-point features determined by -mdouble-float,
85  // -msingle-float, -msoft-float and -mfpu.
86  // Note: -m*-float wins any other options.
87  if (const Arg *A = Args.getLastArg(options::OPT_mdouble_float,
88                                     options::OPT_msingle_float,
89                                     options::OPT_msoft_float)) {
90    if (A->getOption().matches(options::OPT_mdouble_float)) {
91      Features.push_back("+f");
92      Features.push_back("+d");
93    } else if (A->getOption().matches(options::OPT_msingle_float)) {
94      Features.push_back("+f");
95      Features.push_back("-d");
96    } else /*Soft-float*/ {
97      Features.push_back("-f");
98      Features.push_back("-d");
99    }
100  } else if (const Arg *A = Args.getLastArg(options::OPT_mfpu_EQ)) {
101    StringRef FPU = A->getValue();
102    if (FPU == "64") {
103      Features.push_back("+f");
104      Features.push_back("+d");
105    } else if (FPU == "32") {
106      Features.push_back("+f");
107      Features.push_back("-d");
108    } else if (FPU == "0" || FPU == "none") {
109      Features.push_back("-f");
110      Features.push_back("-d");
111    } else {
112      D.Diag(diag::err_drv_loongarch_invalid_mfpu_EQ) << FPU;
113    }
114  }
115}
116