xref: /freebsd-src/contrib/llvm-project/clang/lib/Driver/ToolChains/AIX.cpp (revision 5ffd83dbcc34f10e07f6d3e968ae6365869615f4)
1480093f4SDimitry Andric //===--- AIX.cpp - AIX ToolChain Implementations ----------------*- C++ -*-===//
2480093f4SDimitry Andric //
3480093f4SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4480093f4SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5480093f4SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6480093f4SDimitry Andric //
7480093f4SDimitry Andric //===----------------------------------------------------------------------===//
8480093f4SDimitry Andric 
9480093f4SDimitry Andric #include "AIX.h"
10480093f4SDimitry Andric #include "Arch/PPC.h"
11480093f4SDimitry Andric #include "CommonArgs.h"
12480093f4SDimitry Andric #include "clang/Driver/Compilation.h"
13480093f4SDimitry Andric #include "clang/Driver/Options.h"
14480093f4SDimitry Andric #include "clang/Driver/SanitizerArgs.h"
15480093f4SDimitry Andric #include "llvm/Option/ArgList.h"
16*5ffd83dbSDimitry Andric #include "llvm/Support/Path.h"
17480093f4SDimitry Andric 
18480093f4SDimitry Andric using AIX = clang::driver::toolchains::AIX;
19480093f4SDimitry Andric using namespace clang::driver;
20480093f4SDimitry Andric using namespace clang::driver::tools;
21*5ffd83dbSDimitry Andric using namespace clang::driver::toolchains;
22480093f4SDimitry Andric 
23480093f4SDimitry Andric using namespace llvm::opt;
24*5ffd83dbSDimitry Andric using namespace llvm::sys;
25480093f4SDimitry Andric 
26480093f4SDimitry Andric void aix::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
27480093f4SDimitry Andric                                   const InputInfo &Output,
28480093f4SDimitry Andric                                   const InputInfoList &Inputs,
29480093f4SDimitry Andric                                   const ArgList &Args,
30480093f4SDimitry Andric                                   const char *LinkingOutput) const {
31480093f4SDimitry Andric   ArgStringList CmdArgs;
32480093f4SDimitry Andric 
33480093f4SDimitry Andric   const bool IsArch32Bit = getToolChain().getTriple().isArch32Bit();
34480093f4SDimitry Andric   const bool IsArch64Bit = getToolChain().getTriple().isArch64Bit();
35480093f4SDimitry Andric   // Only support 32 and 64 bit.
36480093f4SDimitry Andric   if (!IsArch32Bit && !IsArch64Bit)
37480093f4SDimitry Andric     llvm_unreachable("Unsupported bit width value.");
38480093f4SDimitry Andric 
39480093f4SDimitry Andric   // Specify the mode in which the as(1) command operates.
40480093f4SDimitry Andric   if (IsArch32Bit) {
41480093f4SDimitry Andric     CmdArgs.push_back("-a32");
42480093f4SDimitry Andric   } else {
43480093f4SDimitry Andric     // Must be 64-bit, otherwise asserted already.
44480093f4SDimitry Andric     CmdArgs.push_back("-a64");
45480093f4SDimitry Andric   }
46480093f4SDimitry Andric 
47480093f4SDimitry Andric   // Accept an undefined symbol as an extern so that an error message is not
48480093f4SDimitry Andric   // displayed. Otherwise, undefined symbols are flagged with error messages.
49480093f4SDimitry Andric   // FIXME: This should be removed when the assembly generation from the
50480093f4SDimitry Andric   // compiler is able to write externs properly.
51480093f4SDimitry Andric   CmdArgs.push_back("-u");
52480093f4SDimitry Andric 
53480093f4SDimitry Andric   // Accept any mixture of instructions.
54480093f4SDimitry Andric   // On Power for AIX and Linux, this behaviour matches that of GCC for both the
55480093f4SDimitry Andric   // user-provided assembler source case and the compiler-produced assembler
56480093f4SDimitry Andric   // source case. Yet XL with user-provided assembler source would not add this.
57480093f4SDimitry Andric   CmdArgs.push_back("-many");
58480093f4SDimitry Andric 
59480093f4SDimitry Andric   Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
60480093f4SDimitry Andric 
61480093f4SDimitry Andric   // Specify assembler output file.
62480093f4SDimitry Andric   assert((Output.isFilename() || Output.isNothing()) && "Invalid output.");
63480093f4SDimitry Andric   if (Output.isFilename()) {
64480093f4SDimitry Andric     CmdArgs.push_back("-o");
65480093f4SDimitry Andric     CmdArgs.push_back(Output.getFilename());
66480093f4SDimitry Andric   }
67480093f4SDimitry Andric 
68480093f4SDimitry Andric   // Specify assembler input file.
69480093f4SDimitry Andric   // The system assembler on AIX takes exactly one input file. The driver is
70480093f4SDimitry Andric   // expected to invoke as(1) separately for each assembler source input file.
71480093f4SDimitry Andric   if (Inputs.size() != 1)
72480093f4SDimitry Andric     llvm_unreachable("Invalid number of input files.");
73480093f4SDimitry Andric   const InputInfo &II = Inputs[0];
74480093f4SDimitry Andric   assert((II.isFilename() || II.isNothing()) && "Invalid input.");
75480093f4SDimitry Andric   if (II.isFilename())
76480093f4SDimitry Andric     CmdArgs.push_back(II.getFilename());
77480093f4SDimitry Andric 
78480093f4SDimitry Andric   const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as"));
79*5ffd83dbSDimitry Andric   C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(),
80*5ffd83dbSDimitry Andric                                          Exec, CmdArgs, Inputs));
81480093f4SDimitry Andric }
82480093f4SDimitry Andric 
83480093f4SDimitry Andric void aix::Linker::ConstructJob(Compilation &C, const JobAction &JA,
84480093f4SDimitry Andric                                const InputInfo &Output,
85480093f4SDimitry Andric                                const InputInfoList &Inputs, const ArgList &Args,
86480093f4SDimitry Andric                                const char *LinkingOutput) const {
87480093f4SDimitry Andric   const AIX &ToolChain = static_cast<const AIX &>(getToolChain());
88*5ffd83dbSDimitry Andric   const Driver &D = ToolChain.getDriver();
89480093f4SDimitry Andric   ArgStringList CmdArgs;
90480093f4SDimitry Andric 
91480093f4SDimitry Andric   const bool IsArch32Bit = ToolChain.getTriple().isArch32Bit();
92480093f4SDimitry Andric   const bool IsArch64Bit = ToolChain.getTriple().isArch64Bit();
93480093f4SDimitry Andric   // Only support 32 and 64 bit.
94480093f4SDimitry Andric   if (!(IsArch32Bit || IsArch64Bit))
95480093f4SDimitry Andric     llvm_unreachable("Unsupported bit width value.");
96480093f4SDimitry Andric 
97480093f4SDimitry Andric   // Force static linking when "-static" is present.
98480093f4SDimitry Andric   if (Args.hasArg(options::OPT_static))
99480093f4SDimitry Andric     CmdArgs.push_back("-bnso");
100480093f4SDimitry Andric 
101480093f4SDimitry Andric   // Specify linker output file.
102480093f4SDimitry Andric   assert((Output.isFilename() || Output.isNothing()) && "Invalid output.");
103480093f4SDimitry Andric   if (Output.isFilename()) {
104480093f4SDimitry Andric     CmdArgs.push_back("-o");
105480093f4SDimitry Andric     CmdArgs.push_back(Output.getFilename());
106480093f4SDimitry Andric   }
107480093f4SDimitry Andric 
108480093f4SDimitry Andric   // Set linking mode (i.e., 32/64-bit) and the address of
109480093f4SDimitry Andric   // text and data sections based on arch bit width.
110480093f4SDimitry Andric   if (IsArch32Bit) {
111480093f4SDimitry Andric     CmdArgs.push_back("-b32");
112480093f4SDimitry Andric     CmdArgs.push_back("-bpT:0x10000000");
113480093f4SDimitry Andric     CmdArgs.push_back("-bpD:0x20000000");
114480093f4SDimitry Andric   } else {
115480093f4SDimitry Andric     // Must be 64-bit, otherwise asserted already.
116480093f4SDimitry Andric     CmdArgs.push_back("-b64");
117480093f4SDimitry Andric     CmdArgs.push_back("-bpT:0x100000000");
118480093f4SDimitry Andric     CmdArgs.push_back("-bpD:0x110000000");
119480093f4SDimitry Andric   }
120480093f4SDimitry Andric 
121480093f4SDimitry Andric   auto getCrt0Basename = [&Args, IsArch32Bit] {
122480093f4SDimitry Andric     // Enable gprofiling when "-pg" is specified.
123480093f4SDimitry Andric     if (Args.hasArg(options::OPT_pg))
124480093f4SDimitry Andric       return IsArch32Bit ? "gcrt0.o" : "gcrt0_64.o";
125480093f4SDimitry Andric     // Enable profiling when "-p" is specified.
126480093f4SDimitry Andric     else if (Args.hasArg(options::OPT_p))
127480093f4SDimitry Andric       return IsArch32Bit ? "mcrt0.o" : "mcrt0_64.o";
128480093f4SDimitry Andric     else
129480093f4SDimitry Andric       return IsArch32Bit ? "crt0.o" : "crt0_64.o";
130480093f4SDimitry Andric   };
131480093f4SDimitry Andric 
132480093f4SDimitry Andric   if (!Args.hasArg(options::OPT_nostdlib)) {
133480093f4SDimitry Andric     CmdArgs.push_back(
134480093f4SDimitry Andric         Args.MakeArgString(ToolChain.GetFilePath(getCrt0Basename())));
135480093f4SDimitry Andric   }
136480093f4SDimitry Andric 
137*5ffd83dbSDimitry Andric   // Collect all static constructor and destructor functions in CXX mode. This
138*5ffd83dbSDimitry Andric   // has to come before AddLinkerInputs as the implied option needs to precede
139*5ffd83dbSDimitry Andric   // any other '-bcdtors' settings or '-bnocdtors' that '-Wl' might forward.
140*5ffd83dbSDimitry Andric   if (D.CCCIsCXX())
141*5ffd83dbSDimitry Andric     CmdArgs.push_back("-bcdtors:all:0:s");
142*5ffd83dbSDimitry Andric 
143480093f4SDimitry Andric   // Specify linker input file(s).
144480093f4SDimitry Andric   AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);
145480093f4SDimitry Andric 
146480093f4SDimitry Andric   // Add directory to library search path.
147480093f4SDimitry Andric   Args.AddAllArgs(CmdArgs, options::OPT_L);
148480093f4SDimitry Andric   ToolChain.AddFilePathLibArgs(Args, CmdArgs);
149480093f4SDimitry Andric 
150480093f4SDimitry Andric   if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
151480093f4SDimitry Andric     // Support POSIX threads if "-pthreads" or "-pthread" is present.
152480093f4SDimitry Andric     if (Args.hasArg(options::OPT_pthreads, options::OPT_pthread))
153480093f4SDimitry Andric       CmdArgs.push_back("-lpthreads");
154480093f4SDimitry Andric 
155480093f4SDimitry Andric     CmdArgs.push_back("-lc");
156480093f4SDimitry Andric   }
157480093f4SDimitry Andric 
158480093f4SDimitry Andric   const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath());
159*5ffd83dbSDimitry Andric   C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(),
160*5ffd83dbSDimitry Andric                                          Exec, CmdArgs, Inputs));
161480093f4SDimitry Andric }
162480093f4SDimitry Andric 
163480093f4SDimitry Andric /// AIX - AIX tool chain which can call as(1) and ld(1) directly.
164480093f4SDimitry Andric AIX::AIX(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
165480093f4SDimitry Andric     : ToolChain(D, Triple, Args) {
166480093f4SDimitry Andric   getFilePaths().push_back(getDriver().SysRoot + "/usr/lib");
167480093f4SDimitry Andric }
168480093f4SDimitry Andric 
169*5ffd83dbSDimitry Andric // Returns the effective header sysroot path to use.
170*5ffd83dbSDimitry Andric // This comes from either -isysroot or --sysroot.
171*5ffd83dbSDimitry Andric llvm::StringRef
172*5ffd83dbSDimitry Andric AIX::GetHeaderSysroot(const llvm::opt::ArgList &DriverArgs) const {
173*5ffd83dbSDimitry Andric   if (DriverArgs.hasArg(options::OPT_isysroot))
174*5ffd83dbSDimitry Andric     return DriverArgs.getLastArgValue(options::OPT_isysroot);
175*5ffd83dbSDimitry Andric   if (!getDriver().SysRoot.empty())
176*5ffd83dbSDimitry Andric     return getDriver().SysRoot;
177*5ffd83dbSDimitry Andric   return "/";
178*5ffd83dbSDimitry Andric }
179*5ffd83dbSDimitry Andric 
180*5ffd83dbSDimitry Andric void AIX::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
181*5ffd83dbSDimitry Andric                                     ArgStringList &CC1Args) const {
182*5ffd83dbSDimitry Andric   // Return if -nostdinc is specified as a driver option.
183*5ffd83dbSDimitry Andric   if (DriverArgs.hasArg(options::OPT_nostdinc))
184*5ffd83dbSDimitry Andric     return;
185*5ffd83dbSDimitry Andric 
186*5ffd83dbSDimitry Andric   llvm::StringRef Sysroot = GetHeaderSysroot(DriverArgs);
187*5ffd83dbSDimitry Andric   const Driver &D = getDriver();
188*5ffd83dbSDimitry Andric 
189*5ffd83dbSDimitry Andric   // Add the Clang builtin headers (<resource>/include).
190*5ffd83dbSDimitry Andric   if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
191*5ffd83dbSDimitry Andric     SmallString<128> P(D.ResourceDir);
192*5ffd83dbSDimitry Andric     path::append(P, "/include");
193*5ffd83dbSDimitry Andric     addSystemInclude(DriverArgs, CC1Args, P.str());
194*5ffd83dbSDimitry Andric   }
195*5ffd83dbSDimitry Andric 
196*5ffd83dbSDimitry Andric   // Return if -nostdlibinc is specified as a driver option.
197*5ffd83dbSDimitry Andric   if (DriverArgs.hasArg(options::OPT_nostdlibinc))
198*5ffd83dbSDimitry Andric     return;
199*5ffd83dbSDimitry Andric 
200*5ffd83dbSDimitry Andric   // Add <sysroot>/usr/include.
201*5ffd83dbSDimitry Andric   SmallString<128> UP(Sysroot);
202*5ffd83dbSDimitry Andric   path::append(UP, "/usr/include");
203*5ffd83dbSDimitry Andric   addSystemInclude(DriverArgs, CC1Args, UP.str());
204*5ffd83dbSDimitry Andric }
205*5ffd83dbSDimitry Andric 
206480093f4SDimitry Andric auto AIX::buildAssembler() const -> Tool * { return new aix::Assembler(*this); }
207480093f4SDimitry Andric 
208480093f4SDimitry Andric auto AIX::buildLinker() const -> Tool * { return new aix::Linker(*this); }
209