Index: lib/Basic/Targets.cpp =================================================================== --- lib/Basic/Targets.cpp +++ lib/Basic/Targets.cpp @@ -697,6 +697,48 @@ } }; +// AIX Target +template +class AIXTargetInfo : public OSTargetInfo { +protected: + void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const override { + DefineStd(Builder, "unix", Opts); + Builder.defineMacro("_IBMR2"); + Builder.defineMacro("_POWER"); + Builder.defineMacro("_AIX"); + Builder.defineMacro("_AIX32"); + Builder.defineMacro("_AIX41"); + Builder.defineMacro("_AIX43"); + Builder.defineMacro("_AIX51"); + Builder.defineMacro("_AIX52"); + Builder.defineMacro("_AIX53"); + Builder.defineMacro("_AIX61"); + Builder.defineMacro("_LONG_LONG"); + // GCC only defines this when compiling C++ code. + if (Opts.CPlusPlus) { + Builder.defineMacro("_ALL_SOURCE"); + } + if (Opts.POSIXThreads) { + Builder.defineMacro("_THREAD_SAFE"); + } + if (this->PointerWidth == 64) { + Builder.defineMacro("__64BIT__"); + } + } + +public: + AIXTargetInfo(const llvm::Triple &Triple) + : OSTargetInfo(Triple) { + this->UserLabelPrefix = ""; + if (this->PointerWidth == 64) { + this->WCharType = this->UnsignedInt; + } else { + this->WCharType = this->UnsignedShort; + } + } +}; + // Windows target template class WindowsTargetInfo : public OSTargetInfo { @@ -1191,8 +1233,10 @@ Builder.defineMacro("__REGISTER_PREFIX__", ""); // FIXME: Should be controlled by command line option. - if (LongDoubleWidth == 128) + if (LongDoubleWidth == 128) { Builder.defineMacro("__LONG_DOUBLE_128__"); + Builder.defineMacro("__LONGDOUBLE128"); + } if (Opts.AltiVec) { Builder.defineMacro("__VEC__", "10206"); @@ -1589,6 +1633,10 @@ PtrDiffType = SignedInt; IntPtrType = SignedInt; break; + case llvm::Triple::AIX: + SizeType = UnsignedLong; + PtrDiffType = SignedLong; + IntPtrType = SignedLong; default: break; } @@ -8318,6 +8366,8 @@ return new OpenBSDTargetInfo(Triple, Opts); case llvm::Triple::RTEMS: return new RTEMSTargetInfo(Triple, Opts); + case llvm::Triple::AIX: + return new AIXTargetInfo(Triple); default: return new PPC32TargetInfo(Triple, Opts); } @@ -8334,6 +8384,8 @@ return new FreeBSDTargetInfo(Triple, Opts); case llvm::Triple::NetBSD: return new NetBSDTargetInfo(Triple, Opts); + case llvm::Triple::AIX: + return new AIXTargetInfo(Triple); default: return new PPC64TargetInfo(Triple, Opts); } Index: lib/Driver/Driver.cpp =================================================================== --- lib/Driver/Driver.cpp +++ lib/Driver/Driver.cpp @@ -2648,6 +2648,9 @@ case llvm::Triple::Solaris: TC = new toolchains::Solaris(*this, Target, Args); break; + case llvm::Triple::AIX: + TC = new toolchains::AIX(*this, Target, Args); + break; case llvm::Triple::AMDHSA: TC = new toolchains::AMDGPUToolChain(*this, Target, Args); break; Index: lib/Driver/ToolChains.h =================================================================== --- lib/Driver/ToolChains.h +++ lib/Driver/ToolChains.h @@ -661,6 +661,24 @@ Tool *buildLinker() const override; }; +class LLVM_LIBRARY_VISIBILITY AIX : public Generic_GCC { +public: + AIX(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); + + bool IsIntegratedAssemblerDefault() const override { return true; } + + void AddClangCXXStdlibIncludeArgs( + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + + unsigned GetDefaultDwarfVersion() const override { return 2; } + +protected: + Tool *buildAssembler() const override; + Tool *buildLinker() const override; +}; + class LLVM_LIBRARY_VISIBILITY MinGW : public ToolChain { public: MinGW(const Driver &D, const llvm::Triple &Triple, Index: lib/Driver/ToolChains.cpp =================================================================== --- lib/Driver/ToolChains.cpp +++ lib/Driver/ToolChains.cpp @@ -2405,6 +2405,40 @@ Result.Multilibs = AndroidArmMultilibs; } +static bool findAIXBiarchMultilibs(const Driver &D, + const llvm::Triple &TargetTriple, + StringRef Path, const ArgList &Args, + bool NeedsBiarchSuffix, + DetectedMultilibs &Result) { + Multilib Default = Multilib() + .flag("+maix32") + .flag("-maix64"); + Multilib Alt64 = Multilib() + .gccSuffix("/ppc64") + .includeSuffix("/ppc64") + .flag("-maix32") + .flag("+maix64"); + + FilterNonExistent NonExistent(Path, "/crtcxa.o", D.getVFS()); + + Result.Multilibs.push_back(Default); + Result.Multilibs.push_back(Alt64); + + Result.Multilibs.FilterOut(NonExistent); + + Multilib::flags_list Flags; + addMultilibFlag(TargetTriple.isArch64Bit(), "maix64", Flags); + addMultilibFlag(TargetTriple.isArch32Bit(), "maix32", Flags); + + if (!Result.Multilibs.select(Flags, Result.SelectedMultilib)) + return false; + + if (Result.SelectedMultilib == Alt64) + Result.BiarchSibling = Default; + + return true; +} + static bool findBiarchMultilibs(const Driver &D, const llvm::Triple &TargetTriple, StringRef Path, const ArgList &Args, @@ -2607,6 +2641,10 @@ } else if (isMipsArch(TargetArch)) { if (!findMIPSMultilibs(D, TargetTriple, LI->getName(), Args, Detected)) continue; + } else if (TargetTriple.getOS() == llvm::Triple::AIX) { + if (!findAIXBiarchMultilibs(D, TargetTriple, LI->getName(), Args, + NeedsBiarchSuffix, Detected)) + continue; } else if (!findBiarchMultilibs(D, TargetTriple, LI->getName(), Args, NeedsBiarchSuffix, Detected)) { continue; @@ -3691,6 +3729,68 @@ } } +/// AIX - AIX tool chain which can call as(1) and ld(1) directly. + +AIX::AIX(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) + : Generic_GCC(D, Triple, Args) { + + GCCInstallation.init(Triple, Args); + + path_list &Paths = getFilePaths(); + if (GCCInstallation.isValid()) { + addPathIfExists(D, GCCInstallation.getInstallPath(), Paths); + addPathIfExists(D, GCCInstallation.getParentLibPath(), Paths); + } + + addPathIfExists(D, getDriver().getInstalledDir(), Paths); + if (getDriver().getInstalledDir() != getDriver().Dir) + addPathIfExists(D, getDriver().Dir, Paths); + + switch (Triple.getArch()) { + case llvm::Triple::ppc: + addPathIfExists(D, getDriver().SysRoot + getDriver().Dir + "/../lib", Paths); + addPathIfExists(D, getDriver().SysRoot + "/usr/lib", Paths); + break; + case llvm::Triple::ppc64: + addPathIfExists(D, getDriver().SysRoot + getDriver().Dir + "/../lib64", Paths); + addPathIfExists(D, getDriver().SysRoot + "/usr/lib64", Paths); + break; + default: + llvm_unreachable("Unsupported architecture"); + } +} + +Tool *AIX::buildAssembler() const { return new tools::aix::Assembler(*this); } + +Tool *AIX::buildLinker() const { return new tools::aix::Linker(*this); } + +void AIX::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + if (DriverArgs.hasArg(options::OPT_nostdlibinc) || + DriverArgs.hasArg(options::OPT_nostdincxx)) + return; + + // We need a detected GCC installation on Linux to provide libstdc++'s + // headers. We handled the libc++ case above. + if (!GCCInstallation.isValid()) + return; + + // By default, look for the C++ headers in an include directory adjacent to + // the lib directory of the GCC installation. Note that this is expect to be + // equivalent to '/usr/include/c++/X.Y' in almost all cases. + StringRef LibDir = GCCInstallation.getParentLibPath(); + StringRef TripleStr = GCCInstallation.getTriple().str(); + const Multilib &Multilib = GCCInstallation.getMultilib(); + const GCCVersion &Version = GCCInstallation.getVersion(); + + // The primary search for libstdc++ supports multiarch variants. + addLibStdCXXIncludePaths(LibDir.str() + "/../include", + "/c++/" + Version.Text, TripleStr, + /*GCCMultiarchTriple*/ "", + /*TargetMultiarchTriple*/ "", + Multilib.includeSuffix(), DriverArgs, CC1Args); +} + /// Distribution (very bare-bones at the moment). enum Distro { Index: lib/Driver/Tools.h =================================================================== --- lib/Driver/Tools.h +++ lib/Driver/Tools.h @@ -652,6 +652,34 @@ }; } // end namespace solaris +/// aix -- Directly call AIX assembler and linker +namespace aix { +class LLVM_LIBRARY_VISIBILITY Assembler : public Tool { +public: + Assembler(const ToolChain &TC) : Tool("aix::Assembler", "assembler", TC) {} + + bool hasIntegratedCPP() const override { return false; } + + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; + +class LLVM_LIBRARY_VISIBILITY Linker : public Tool { +public: + Linker(const ToolChain &TC) : Tool("aix::Linker", "linker", TC) {} + + bool hasIntegratedCPP() const override { return false; } + bool isLinkJob() const override { return true; } + + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; +} // end namespace aix + /// dragonfly -- Directly call GNU Binutils assembler and linker namespace dragonfly { class LLVM_LIBRARY_VISIBILITY Assembler : public GnuTool { Index: lib/Driver/Tools.cpp =================================================================== --- lib/Driver/Tools.cpp +++ lib/Driver/Tools.cpp @@ -5452,6 +5452,7 @@ options::OPT_fuse_cxa_atexit, options::OPT_fno_use_cxa_atexit, !IsWindowsCygnus && !IsWindowsGNU && getToolChain().getTriple().getOS() != llvm::Triple::Solaris && + getToolChain().getTriple().getOS() != llvm::Triple::AIX && getToolChain().getArch() != llvm::Triple::hexagon && getToolChain().getArch() != llvm::Triple::xcore && ((getToolChain().getTriple().getVendor() != @@ -8102,6 +8103,94 @@ C.addCommand(llvm::make_unique(JA, *this, Exec, CmdArgs, Inputs)); } +void aix::Assembler::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + claimNoWarnArgs(Args); + ArgStringList CmdArgs; + + Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); + + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + + for (const auto &II : Inputs) + CmdArgs.push_back(II.getFilename()); + + const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); + C.addCommand(llvm::make_unique(JA, *this, Exec, CmdArgs, Inputs)); +} + +void aix::Linker::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + ArgStringList CmdArgs; + + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_shared)) { + CmdArgs.push_back("-e_start"); + } + + CmdArgs.push_back("-bsvr4"); + + if (Args.hasArg(options::OPT_static)) { + CmdArgs.push_back("-dn"); + } else { + CmdArgs.push_back("-dy"); + if (Args.hasArg(options::OPT_shared)) { + CmdArgs.push_back("-G"); + } else { + CmdArgs.push_back("-brtl"); + } + } + + if (Output.isFilename()) { + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + } else { + assert(Output.isNothing() && "Invalid output."); + } + + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { + if (Args.hasArg(options::OPT_shared)) + CmdArgs.push_back( + Args.MakeArgString(getToolChain().GetFilePath("crtcxa_s.o"))); + else + CmdArgs.push_back( + Args.MakeArgString(getToolChain().GetFilePath("crtcxa.o"))); + } + + getToolChain().AddFilePathLibArgs(Args, CmdArgs); + + Args.AddAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group, + options::OPT_e, options::OPT_r}); + + AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs); + + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { + if (getToolChain().getDriver().CCCIsCXX()) + getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); + CmdArgs.push_back("-lc"); + if (!Args.hasArg(options::OPT_shared)) { + CmdArgs.push_back("-lm"); + } + if (Args.hasArg(options::OPT_shared)) { + CmdArgs.push_back("-lgcc_s"); + } else { + CmdArgs.push_back("-lgcc"); + CmdArgs.push_back("-lgcc_eh"); + } + } + + getToolChain().addProfileRTLibs(Args, CmdArgs); + + const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath()); + C.addCommand(llvm::make_unique(JA, *this, Exec, CmdArgs, Inputs)); +} + void openbsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, Index: tools/libclang/CIndexer.cpp =================================================================== --- tools/libclang/CIndexer.cpp +++ tools/libclang/CIndexer.cpp @@ -37,12 +37,71 @@ #ifdef LLVM_ON_WIN32 #include +#elif defined(_AIX) +#include +#include +#include #else #include #endif using namespace clang; +#ifdef _AIX +static int +test_dir(char ret[PATH_MAX], const char *dir, const char *bin) +{ + struct stat sb; + char fullpath[PATH_MAX]; + + snprintf(fullpath, PATH_MAX, "%s/%s", dir, bin); + if (!realpath(fullpath, ret)) + return 1; + if (stat(fullpath, &sb) != 0) + return 1; + + return 0; +} + +static char * +getprogpath(char ret[PATH_MAX], const char *bin) +{ + char *pv, *s, *t; + + /* First approach: absolute path. */ + if (bin[0] == '/') { + if (test_dir(ret, "/", bin) == 0) + return ret; + return nullptr; + } + + /* Second approach: relative path. */ + if (strchr(bin, '/')) { + char cwd[PATH_MAX]; + if (!getcwd(cwd, PATH_MAX)) + return nullptr; + if (test_dir(ret, cwd, bin) == 0) + return ret; + return nullptr; + } + + /* Third approach: $PATH */ + if ((pv = getenv("PATH")) == nullptr) + return nullptr; + s = pv = strdup(pv); + if (!pv) + return nullptr; + while ((t = strsep(&s, ":")) != nullptr) { + if (test_dir(ret, t, bin) == 0) { + free(pv); + return ret; + } + } + free(pv); + return nullptr; +} +#endif + const std::string &CIndexer::getClangResourcesPath() { // Did we already compute the path? if (!ResourcesPath.empty()) @@ -69,6 +128,11 @@ #endif LibClangPath += llvm::sys::path::parent_path(path); +#elif defined(_AIX) + extern char **argv; + char exe_path[MAXPATHLEN]; + if (getprogpath(exe_path, argv[0]) != NULL) + LibClangPath += llvm::sys::path::parent_path(exe_path); #else // This silly cast below avoids a C++ warning. Dl_info info;