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: "power11" , Value: "pwr11" ) |
74 | .Case(S: "future" , Value: "future" ) |
75 | .Case(S: "powerpc" , Value: "ppc" ) |
76 | .Case(S: "powerpc64" , Value: "ppc64" ) |
77 | .Case(S: "powerpc64le" , Value: "ppc64le" ) |
78 | .Default(Value: CPUName.data()); |
79 | } |
80 | |
81 | /// Get the (LLVM) name of the PowerPC cpu we are tuning for. |
82 | std::string ppc::getPPCTuneCPU(const ArgList &Args, const llvm::Triple &T) { |
83 | if (Arg *A = Args.getLastArg(Ids: clang::driver::options::OPT_mtune_EQ)) |
84 | return normalizeCPUName(CPUName: A->getValue(), T); |
85 | return getPPCGenericTargetCPU(T); |
86 | } |
87 | |
88 | /// Get the (LLVM) name of the PowerPC cpu we are targeting. |
89 | std::string ppc::getPPCTargetCPU(const Driver &D, const ArgList &Args, |
90 | const llvm::Triple &T) { |
91 | if (Arg *A = Args.getLastArg(Ids: clang::driver::options::OPT_mcpu_EQ)) |
92 | return normalizeCPUName(CPUName: A->getValue(), T); |
93 | return getPPCGenericTargetCPU(T); |
94 | } |
95 | |
96 | const char *ppc::getPPCAsmModeForCPU(StringRef Name) { |
97 | return llvm::StringSwitch<const char *>(Name) |
98 | .Case(S: "pwr7" , Value: "-mpower7" ) |
99 | .Case(S: "power7" , Value: "-mpower7" ) |
100 | .Case(S: "pwr8" , Value: "-mpower8" ) |
101 | .Case(S: "power8" , Value: "-mpower8" ) |
102 | .Case(S: "ppc64le" , Value: "-mpower8" ) |
103 | .Case(S: "pwr9" , Value: "-mpower9" ) |
104 | .Case(S: "power9" , Value: "-mpower9" ) |
105 | .Case(S: "pwr10" , Value: "-mpower10" ) |
106 | .Case(S: "power10" , Value: "-mpower10" ) |
107 | .Case(S: "pwr11" , Value: "-mpower11" ) |
108 | .Case(S: "power11" , Value: "-mpower11" ) |
109 | .Default(Value: "-many" ); |
110 | } |
111 | |
112 | void ppc::getPPCTargetFeatures(const Driver &D, const llvm::Triple &Triple, |
113 | const ArgList &Args, |
114 | std::vector<StringRef> &Features) { |
115 | if (Triple.getSubArch() == llvm::Triple::PPCSubArch_spe) |
116 | Features.push_back(x: "+spe" ); |
117 | |
118 | handleTargetFeaturesGroup(D, Triple, Args, Features, |
119 | Group: options::OPT_m_ppc_Features_Group); |
120 | |
121 | ppc::FloatABI FloatABI = ppc::getPPCFloatABI(D, Args); |
122 | if (FloatABI == ppc::FloatABI::Soft) |
123 | Features.push_back(x: "-hard-float" ); |
124 | |
125 | ppc::ReadGOTPtrMode ReadGOT = ppc::getPPCReadGOTPtrMode(D, Triple, Args); |
126 | if (ReadGOT == ppc::ReadGOTPtrMode::SecurePlt) |
127 | Features.push_back(x: "+secure-plt" ); |
128 | |
129 | bool UseSeparateSections = isUseSeparateSections(Triple); |
130 | bool HasDefaultDataSections = Triple.isOSBinFormatXCOFF(); |
131 | if (Args.hasArg(Ids: options::OPT_maix_small_local_exec_tls) || |
132 | Args.hasArg(Ids: options::OPT_maix_small_local_dynamic_tls)) { |
133 | if (!Triple.isOSAIX() || !Triple.isArch64Bit()) |
134 | D.Diag(DiagID: diag::err_opt_not_valid_on_target) |
135 | << "-maix-small-local-[exec|dynamic]-tls" ; |
136 | |
137 | // The -maix-small-local-[exec|dynamic]-tls option should only be used with |
138 | // -fdata-sections, as having data sections turned off with this option |
139 | // is not ideal for performance. Moreover, the |
140 | // small-local-[exec|dynamic]-tls region is a limited resource, and should |
141 | // not be used for variables that may be replaced. |
142 | if (!Args.hasFlag(Pos: options::OPT_fdata_sections, |
143 | Neg: options::OPT_fno_data_sections, |
144 | Default: UseSeparateSections || HasDefaultDataSections)) |
145 | D.Diag(DiagID: diag::err_drv_argument_only_allowed_with) |
146 | << "-maix-small-local-[exec|dynamic]-tls" << "-fdata-sections" ; |
147 | } |
148 | } |
149 | |
150 | ppc::ReadGOTPtrMode ppc::getPPCReadGOTPtrMode(const Driver &D, const llvm::Triple &Triple, |
151 | const ArgList &Args) { |
152 | if (Args.getLastArg(Ids: options::OPT_msecure_plt)) |
153 | return ppc::ReadGOTPtrMode::SecurePlt; |
154 | if (Triple.isPPC32SecurePlt()) |
155 | return ppc::ReadGOTPtrMode::SecurePlt; |
156 | else |
157 | return ppc::ReadGOTPtrMode::Bss; |
158 | } |
159 | |
160 | ppc::FloatABI ppc::getPPCFloatABI(const Driver &D, const ArgList &Args) { |
161 | ppc::FloatABI ABI = ppc::FloatABI::Invalid; |
162 | if (Arg *A = |
163 | Args.getLastArg(Ids: options::OPT_msoft_float, Ids: options::OPT_mhard_float, |
164 | Ids: options::OPT_mfloat_abi_EQ)) { |
165 | if (A->getOption().matches(ID: options::OPT_msoft_float)) |
166 | ABI = ppc::FloatABI::Soft; |
167 | else if (A->getOption().matches(ID: options::OPT_mhard_float)) |
168 | ABI = ppc::FloatABI::Hard; |
169 | else { |
170 | ABI = llvm::StringSwitch<ppc::FloatABI>(A->getValue()) |
171 | .Case(S: "soft" , Value: ppc::FloatABI::Soft) |
172 | .Case(S: "hard" , Value: ppc::FloatABI::Hard) |
173 | .Default(Value: ppc::FloatABI::Invalid); |
174 | if (ABI == ppc::FloatABI::Invalid && !StringRef(A->getValue()).empty()) { |
175 | D.Diag(DiagID: clang::diag::err_drv_invalid_mfloat_abi) << A->getAsString(Args); |
176 | ABI = ppc::FloatABI::Hard; |
177 | } |
178 | } |
179 | } |
180 | |
181 | // If unspecified, choose the default based on the platform. |
182 | if (ABI == ppc::FloatABI::Invalid) { |
183 | ABI = ppc::FloatABI::Hard; |
184 | } |
185 | |
186 | return ABI; |
187 | } |
188 | |
189 | bool ppc::hasPPCAbiArg(const ArgList &Args, const char *Value) { |
190 | Arg *A = Args.getLastArg(Ids: options::OPT_mabi_EQ); |
191 | return A && (A->getValue() == StringRef(Value)); |
192 | } |
193 | |