Coverage Report

Created: 2024-01-17 10:31

/src/llvm-project/clang/lib/Driver/ToolChains/Arch/LoongArch.cpp
Line
Count
Source (jump to first uncovered line)
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 "ToolChains/CommonArgs.h"
11
#include "clang/Basic/DiagnosticDriver.h"
12
#include "clang/Driver/Driver.h"
13
#include "clang/Driver/DriverDiagnostic.h"
14
#include "clang/Driver/Options.h"
15
#include "llvm/TargetParser/Host.h"
16
#include "llvm/TargetParser/LoongArchTargetParser.h"
17
18
using namespace clang::driver;
19
using namespace clang::driver::tools;
20
using namespace clang;
21
using namespace llvm::opt;
22
23
StringRef loongarch::getLoongArchABI(const Driver &D, const ArgList &Args,
24
0
                                     const llvm::Triple &Triple) {
25
0
  assert((Triple.getArch() == llvm::Triple::loongarch32 ||
26
0
          Triple.getArch() == llvm::Triple::loongarch64) &&
27
0
         "Unexpected triple");
28
0
  bool IsLA32 = Triple.getArch() == llvm::Triple::loongarch32;
29
30
  // Record -mabi value for later use.
31
0
  const Arg *MABIArg = Args.getLastArg(options::OPT_mabi_EQ);
32
0
  StringRef MABIValue;
33
0
  if (MABIArg) {
34
0
    MABIValue = MABIArg->getValue();
35
0
  }
36
37
  // Parse -mfpu value for later use.
38
0
  const Arg *MFPUArg = Args.getLastArg(options::OPT_mfpu_EQ);
39
0
  int FPU = -1;
40
0
  if (MFPUArg) {
41
0
    StringRef V = MFPUArg->getValue();
42
0
    if (V == "64")
43
0
      FPU = 64;
44
0
    else if (V == "32")
45
0
      FPU = 32;
46
0
    else if (V == "0" || V == "none")
47
0
      FPU = 0;
48
0
    else
49
0
      D.Diag(diag::err_drv_loongarch_invalid_mfpu_EQ) << V;
50
0
  }
51
52
  // Check -m*-float firstly since they have highest priority.
53
0
  if (const Arg *A = Args.getLastArg(options::OPT_mdouble_float,
54
0
                                     options::OPT_msingle_float,
55
0
                                     options::OPT_msoft_float)) {
56
0
    StringRef ImpliedABI;
57
0
    int ImpliedFPU = -1;
58
0
    if (A->getOption().matches(options::OPT_mdouble_float)) {
59
0
      ImpliedABI = IsLA32 ? "ilp32d" : "lp64d";
60
0
      ImpliedFPU = 64;
61
0
    }
62
0
    if (A->getOption().matches(options::OPT_msingle_float)) {
63
0
      ImpliedABI = IsLA32 ? "ilp32f" : "lp64f";
64
0
      ImpliedFPU = 32;
65
0
    }
66
0
    if (A->getOption().matches(options::OPT_msoft_float)) {
67
0
      ImpliedABI = IsLA32 ? "ilp32s" : "lp64s";
68
0
      ImpliedFPU = 0;
69
0
    }
70
71
    // Check `-mabi=` and `-mfpu=` settings and report if they conflict with
72
    // the higher-priority settings implied by -m*-float.
73
    //
74
    // ImpliedABI and ImpliedFPU are guaranteed to have valid values because
75
    // one of the match arms must match if execution can arrive here at all.
76
0
    if (!MABIValue.empty() && ImpliedABI != MABIValue)
77
0
      D.Diag(diag::warn_drv_loongarch_conflicting_implied_val)
78
0
          << MABIArg->getAsString(Args) << A->getAsString(Args) << ImpliedABI;
79
80
0
    if (FPU != -1 && ImpliedFPU != FPU)
81
0
      D.Diag(diag::warn_drv_loongarch_conflicting_implied_val)
82
0
          << MFPUArg->getAsString(Args) << A->getAsString(Args) << ImpliedFPU;
83
84
0
    return ImpliedABI;
85
0
  }
86
87
  // If `-mabi=` is specified, use it.
88
0
  if (!MABIValue.empty())
89
0
    return MABIValue;
90
91
  // Select abi based on -mfpu=xx.
92
0
  switch (FPU) {
93
0
  case 64:
94
0
    return IsLA32 ? "ilp32d" : "lp64d";
95
0
  case 32:
96
0
    return IsLA32 ? "ilp32f" : "lp64f";
97
0
  case 0:
98
0
    return IsLA32 ? "ilp32s" : "lp64s";
99
0
  }
100
101
  // Choose a default based on the triple.
102
  // Honor the explicit ABI modifier suffix in triple's environment part if
103
  // present, falling back to {ILP32,LP64}D otherwise.
104
0
  switch (Triple.getEnvironment()) {
105
0
  case llvm::Triple::GNUSF:
106
0
    return IsLA32 ? "ilp32s" : "lp64s";
107
0
  case llvm::Triple::GNUF32:
108
0
    return IsLA32 ? "ilp32f" : "lp64f";
109
0
  case llvm::Triple::GNUF64:
110
    // This was originally permitted (and indeed the canonical way) to
111
    // represent the {ILP32,LP64}D ABIs, but in Feb 2023 Loongson decided to
112
    // drop the explicit suffix in favor of unmarked `-gnu` for the
113
    // "general-purpose" ABIs, among other non-technical reasons.
114
    //
115
    // The spec change did not mention whether existing usages of "gnuf64"
116
    // shall remain valid or not, so we are going to continue recognizing it
117
    // for some time, until it is clear that everyone else has migrated away
118
    // from it.
119
0
    [[fallthrough]];
120
0
  case llvm::Triple::GNU:
121
0
  default:
122
0
    return IsLA32 ? "ilp32d" : "lp64d";
123
0
  }
124
0
}
125
126
void loongarch::getLoongArchTargetFeatures(const Driver &D,
127
                                           const llvm::Triple &Triple,
128
                                           const ArgList &Args,
129
0
                                           std::vector<StringRef> &Features) {
130
0
  std::string ArchName;
131
0
  if (const Arg *A = Args.getLastArg(options::OPT_march_EQ))
132
0
    ArchName = A->getValue();
133
0
  ArchName = postProcessTargetCPUString(ArchName, Triple);
134
0
  llvm::LoongArch::getArchFeatures(ArchName, Features);
135
136
  // Select floating-point features determined by -mdouble-float,
137
  // -msingle-float, -msoft-float and -mfpu.
138
  // Note: -m*-float wins any other options.
139
0
  if (const Arg *A = Args.getLastArg(options::OPT_mdouble_float,
140
0
                                     options::OPT_msingle_float,
141
0
                                     options::OPT_msoft_float)) {
142
0
    if (A->getOption().matches(options::OPT_mdouble_float)) {
143
0
      Features.push_back("+f");
144
0
      Features.push_back("+d");
145
0
    } else if (A->getOption().matches(options::OPT_msingle_float)) {
146
0
      Features.push_back("+f");
147
0
      Features.push_back("-d");
148
0
    } else /*Soft-float*/ {
149
0
      Features.push_back("-f");
150
0
      Features.push_back("-d");
151
0
    }
152
0
  } else if (const Arg *A = Args.getLastArg(options::OPT_mfpu_EQ)) {
153
0
    StringRef FPU = A->getValue();
154
0
    if (FPU == "64") {
155
0
      Features.push_back("+f");
156
0
      Features.push_back("+d");
157
0
    } else if (FPU == "32") {
158
0
      Features.push_back("+f");
159
0
      Features.push_back("-d");
160
0
    } else if (FPU == "0" || FPU == "none") {
161
0
      Features.push_back("-f");
162
0
      Features.push_back("-d");
163
0
    } else {
164
0
      D.Diag(diag::err_drv_loongarch_invalid_mfpu_EQ) << FPU;
165
0
    }
166
0
  }
167
168
  // Select the `ual` feature determined by -m[no-]unaligned-access
169
  // or the alias -m[no-]strict-align.
170
0
  AddTargetFeature(Args, Features, options::OPT_munaligned_access,
171
0
                   options::OPT_mno_unaligned_access, "ual");
172
173
  // Accept but warn about these TargetSpecific options.
174
0
  if (Arg *A = Args.getLastArgNoClaim(options::OPT_mabi_EQ))
175
0
    A->ignoreTargetSpecific();
176
0
  if (Arg *A = Args.getLastArgNoClaim(options::OPT_mfpu_EQ))
177
0
    A->ignoreTargetSpecific();
178
179
  // Select lsx feature determined by -m[no-]lsx.
180
0
  if (const Arg *A = Args.getLastArg(options::OPT_mlsx, options::OPT_mno_lsx)) {
181
    // LSX depends on 64-bit FPU.
182
    // -m*-float and -mfpu=none/0/32 conflict with -mlsx.
183
0
    if (A->getOption().matches(options::OPT_mlsx)) {
184
0
      if (llvm::find(Features, "-d") != Features.end())
185
0
        D.Diag(diag::err_drv_loongarch_wrong_fpu_width_for_lsx);
186
0
      else /*-mlsx*/
187
0
        Features.push_back("+lsx");
188
0
    } else /*-mno-lsx*/ {
189
0
      Features.push_back("-lsx");
190
0
    }
191
0
  }
192
193
  // Select lasx feature determined by -m[no-]lasx.
194
0
  if (const Arg *A =
195
0
          Args.getLastArg(options::OPT_mlasx, options::OPT_mno_lasx)) {
196
    // LASX depends on 64-bit FPU and LSX.
197
    // -mno-lsx conflicts with -mlasx.
198
0
    if (A->getOption().matches(options::OPT_mlasx)) {
199
0
      if (llvm::find(Features, "-d") != Features.end())
200
0
        D.Diag(diag::err_drv_loongarch_wrong_fpu_width_for_lasx);
201
0
      else if (llvm::find(Features, "-lsx") != Features.end())
202
0
        D.Diag(diag::err_drv_loongarch_invalid_simd_option_combination);
203
0
      else { /*-mlasx*/
204
0
        Features.push_back("+lsx");
205
0
        Features.push_back("+lasx");
206
0
      }
207
0
    } else /*-mno-lasx*/
208
0
      Features.push_back("-lasx");
209
0
  }
210
0
}
211
212
std::string loongarch::postProcessTargetCPUString(const std::string &CPU,
213
0
                                                  const llvm::Triple &Triple) {
214
0
  std::string CPUString = CPU;
215
0
  if (CPUString == "native") {
216
0
    CPUString = llvm::sys::getHostCPUName();
217
0
    if (CPUString == "generic")
218
0
      CPUString = llvm::LoongArch::getDefaultArch(Triple.isLoongArch64());
219
0
  }
220
0
  if (CPUString.empty())
221
0
    CPUString = llvm::LoongArch::getDefaultArch(Triple.isLoongArch64());
222
0
  return CPUString;
223
0
}
224
225
std::string loongarch::getLoongArchTargetCPU(const llvm::opt::ArgList &Args,
226
0
                                             const llvm::Triple &Triple) {
227
0
  std::string CPU;
228
  // If we have -march, use that.
229
0
  if (const Arg *A = Args.getLastArg(options::OPT_march_EQ))
230
0
    CPU = A->getValue();
231
0
  return postProcessTargetCPUString(CPU, Triple);
232
0
}