1 | //===--- PPC.cpp - PPC 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 "PPC.h" |
10 | #include "ToolChains/CommonArgs.h" |
11 | #include "clang/Driver/Driver.h" |
12 | #include "clang/Driver/DriverDiagnostic.h" |
13 | #include "clang/Driver/Options.h" |
14 | #include "llvm/ADT/StringSwitch.h" |
15 | #include "llvm/Option/ArgList.h" |
16 | #include "llvm/TargetParser/Host.h" |
17 | |
18 | using namespace clang::driver; |
19 | using namespace clang::driver::tools; |
20 | using namespace clang; |
21 | using namespace llvm::opt; |
22 | |
23 | static std::string getPPCGenericTargetCPU(const llvm::Triple &T) { |
24 | // LLVM may default to generating code for the native CPU, |
25 | // but, like gcc, we default to a more generic option for |
26 | // each architecture. (except on AIX) |
27 | if (T.isOSAIX()) |
28 | return "pwr7" ; |
29 | else if (T.getArch() == llvm::Triple::ppc64le) |
30 | return "ppc64le" ; |
31 | else if (T.getArch() == llvm::Triple::ppc64) |
32 | return "ppc64" ; |
33 | else |
34 | return "ppc" ; |
35 | } |
36 | |
37 | static std::string normalizeCPUName(StringRef CPUName, const llvm::Triple &T) { |
38 | // Clang/LLVM does not actually support code generation |
39 | // for the 405 CPU. However, there are uses of this CPU ID |
40 | // in projects that previously used GCC and rely on Clang |
41 | // accepting it. Clang has always ignored it and passed the |
42 | // generic CPU ID to the back end. |
43 | if (CPUName == "generic" || CPUName == "405" ) |
44 | return getPPCGenericTargetCPU(T); |
45 | |
46 | if (CPUName == "native" ) { |
47 | std::string CPU = std::string(llvm::sys::getHostCPUName()); |
48 | if (!CPU.empty() && CPU != "generic" ) |
49 | return CPU; |
50 | else |
51 | return getPPCGenericTargetCPU(T); |
52 | } |
53 | |
54 | return llvm::StringSwitch<const char *>(CPUName) |
55 | .Case(S: "common" , Value: "generic" ) |
56 | .Case(S: "440fp" , Value: "440" ) |
57 | .Case(S: "630" , Value: "pwr3" ) |
58 | .Case(S: "G3" , Value: "g3" ) |
59 | .Case(S: "G4" , Value: "g4" ) |
60 | .Case(S: "G4+" , Value: "g4+" ) |
61 | .Case(S: "8548" , Value: "e500" ) |
62 | .Case(S: "G5" , Value: "g5" ) |
63 | .Case(S: "power3" , Value: "pwr3" ) |
64 | .Case(S: "power4" , Value: "pwr4" ) |
65 | .Case(S: "power5" , Value: "pwr5" ) |
66 | .Case(S: "power5x" , Value: "pwr5x" ) |
67 | .Case(S: "power6" , Value: "pwr6" ) |
68 | .Case(S: "power6x" , Value: "pwr6x" ) |
69 | .Case(S: "power7" , Value: "pwr7" ) |
70 | .Case(S: "power8" , Value: "pwr8" ) |
71 | .Case(S: "power9" , Value: "pwr9" ) |
72 | .Case(S: "power10" , Value: "pwr10" ) |
73 | .Case(S: "future" , Value: "future" ) |
74 | .Case(S: "powerpc" , Value: "ppc" ) |
75 | .Case(S: "powerpc64" , Value: "ppc64" ) |
76 | .Case(S: "powerpc64le" , Value: "ppc64le" ) |
77 | .Default(Value: CPUName.data()); |
78 | } |
79 | |
80 | /// Get the (LLVM) name of the PowerPC cpu we are tuning for. |
81 | std::string ppc::getPPCTuneCPU(const ArgList &Args, const llvm::Triple &T) { |
82 | if (Arg *A = Args.getLastArg(clang::driver::options::OPT_mtune_EQ)) |
83 | return normalizeCPUName(CPUName: A->getValue(), T); |
84 | return getPPCGenericTargetCPU(T); |
85 | } |
86 | |
87 | /// Get the (LLVM) name of the PowerPC cpu we are targeting. |
88 | std::string ppc::getPPCTargetCPU(const Driver &D, const ArgList &Args, |
89 | const llvm::Triple &T) { |
90 | if (Arg *A = Args.getLastArg(clang::driver::options::OPT_mcpu_EQ)) |
91 | return normalizeCPUName(CPUName: A->getValue(), T); |
92 | return getPPCGenericTargetCPU(T); |
93 | } |
94 | |
95 | const char *ppc::getPPCAsmModeForCPU(StringRef Name) { |
96 | return llvm::StringSwitch<const char *>(Name) |
97 | .Case(S: "pwr7" , Value: "-mpower7" ) |
98 | .Case(S: "power7" , Value: "-mpower7" ) |
99 | .Case(S: "pwr8" , Value: "-mpower8" ) |
100 | .Case(S: "power8" , Value: "-mpower8" ) |
101 | .Case(S: "ppc64le" , Value: "-mpower8" ) |
102 | .Case(S: "pwr9" , Value: "-mpower9" ) |
103 | .Case(S: "power9" , Value: "-mpower9" ) |
104 | .Case(S: "pwr10" , Value: "-mpower10" ) |
105 | .Case(S: "power10" , Value: "-mpower10" ) |
106 | .Default(Value: "-many" ); |
107 | } |
108 | |
109 | void ppc::getPPCTargetFeatures(const Driver &D, const llvm::Triple &Triple, |
110 | const ArgList &Args, |
111 | std::vector<StringRef> &Features) { |
112 | if (Triple.getSubArch() == llvm::Triple::PPCSubArch_spe) |
113 | Features.push_back(x: "+spe" ); |
114 | |
115 | handleTargetFeaturesGroup(D, Triple, Args, Features, |
116 | options::OPT_m_ppc_Features_Group); |
117 | |
118 | ppc::FloatABI FloatABI = ppc::getPPCFloatABI(D, Args); |
119 | if (FloatABI == ppc::FloatABI::Soft) |
120 | Features.push_back(x: "-hard-float" ); |
121 | |
122 | ppc::ReadGOTPtrMode ReadGOT = ppc::getPPCReadGOTPtrMode(D, Triple, Args); |
123 | if (ReadGOT == ppc::ReadGOTPtrMode::SecurePlt) |
124 | Features.push_back(x: "+secure-plt" ); |
125 | |
126 | bool UseSeparateSections = isUseSeparateSections(Triple); |
127 | bool HasDefaultDataSections = Triple.isOSBinFormatXCOFF(); |
128 | if (Args.hasArg(options::OPT_maix_small_local_exec_tls) || |
129 | Args.hasArg(options::OPT_maix_small_local_dynamic_tls)) { |
130 | if (!Triple.isOSAIX() || !Triple.isArch64Bit()) |
131 | D.Diag(diag::DiagID: err_opt_not_valid_on_target) |
132 | << "-maix-small-local-[exec|dynamic]-tls" ; |
133 | |
134 | // The -maix-small-local-[exec|dynamic]-tls option should only be used with |
135 | // -fdata-sections, as having data sections turned off with this option |
136 | // is not ideal for performance. Moreover, the |
137 | // small-local-[exec|dynamic]-tls region is a limited resource, and should |
138 | // not be used for variables that may be replaced. |
139 | if (!Args.hasFlag(options::OPT_fdata_sections, |
140 | options::OPT_fno_data_sections, |
141 | UseSeparateSections || HasDefaultDataSections)) |
142 | D.Diag(diag::DiagID: err_drv_argument_only_allowed_with) |
143 | << "-maix-small-local-[exec|dynamic]-tls" << "-fdata-sections" ; |
144 | } |
145 | } |
146 | |
147 | ppc::ReadGOTPtrMode ppc::getPPCReadGOTPtrMode(const Driver &D, const llvm::Triple &Triple, |
148 | const ArgList &Args) { |
149 | if (Args.getLastArg(options::OPT_msecure_plt)) |
150 | return ppc::ReadGOTPtrMode::SecurePlt; |
151 | if (Triple.isPPC32SecurePlt()) |
152 | return ppc::ReadGOTPtrMode::SecurePlt; |
153 | else |
154 | return ppc::ReadGOTPtrMode::Bss; |
155 | } |
156 | |
157 | ppc::FloatABI ppc::getPPCFloatABI(const Driver &D, const ArgList &Args) { |
158 | ppc::FloatABI ABI = ppc::FloatABI::Invalid; |
159 | if (Arg *A = |
160 | Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float, |
161 | options::OPT_mfloat_abi_EQ)) { |
162 | if (A->getOption().matches(options::ID: OPT_msoft_float)) |
163 | ABI = ppc::FloatABI::Soft; |
164 | else if (A->getOption().matches(options::ID: OPT_mhard_float)) |
165 | ABI = ppc::FloatABI::Hard; |
166 | else { |
167 | ABI = llvm::StringSwitch<ppc::FloatABI>(A->getValue()) |
168 | .Case(S: "soft" , Value: ppc::FloatABI::Soft) |
169 | .Case(S: "hard" , Value: ppc::FloatABI::Hard) |
170 | .Default(Value: ppc::FloatABI::Invalid); |
171 | if (ABI == ppc::FloatABI::Invalid && !StringRef(A->getValue()).empty()) { |
172 | D.Diag(clang::diag::DiagID: err_drv_invalid_mfloat_abi) << A->getAsString(Args); |
173 | ABI = ppc::FloatABI::Hard; |
174 | } |
175 | } |
176 | } |
177 | |
178 | // If unspecified, choose the default based on the platform. |
179 | if (ABI == ppc::FloatABI::Invalid) { |
180 | ABI = ppc::FloatABI::Hard; |
181 | } |
182 | |
183 | return ABI; |
184 | } |
185 | |
186 | bool ppc::hasPPCAbiArg(const ArgList &Args, const char *Value) { |
187 | Arg *A = Args.getLastArg(options::OPT_mabi_EQ); |
188 | return A && (A->getValue() == StringRef(Value)); |
189 | } |
190 | |