Commit adb4a95302

Andrew Kelley <andrew@ziglang.org>
2022-07-28 20:53:25
update to LLVM 15
release/15.x 37007475ca1b345b4c5d340e228bcd7a62732d81
1 parent e863292
cmake/Findclang.cmake
@@ -17,9 +17,9 @@ find_path(CLANG_INCLUDE_DIRS NAMES clang/Frontend/ASTUnit.h
 if(${LLVM_LINK_MODE} STREQUAL "shared")
   find_library(CLANG_LIBRARIES
     NAMES
-      libclang-cpp.so.14
-      clang-cpp-14.0
-      clang-cpp140
+      libclang-cpp.so.15
+      clang-cpp-15.0
+      clang-cpp150
       clang-cpp
     NAMES_PER_DIR
     HINTS "${LLVM_LIBDIRS}"
cmake/Findlld.cmake
@@ -9,21 +9,21 @@
 find_path(LLD_INCLUDE_DIRS NAMES lld/Common/Driver.h
     HINTS ${LLVM_INCLUDE_DIRS}
     PATHS
-        /usr/lib/llvm-14/include
-        /usr/local/llvm140/include
-        /usr/local/llvm14/include
-        /usr/local/opt/llvm@14/include
-        /opt/homebrew/opt/llvm@14/include
+        /usr/lib/llvm-15/include
+        /usr/local/llvm150/include
+        /usr/local/llvm15/include
+        /usr/local/opt/llvm@15/include
+        /opt/homebrew/opt/llvm@15/include
         /mingw64/include)
 
-find_library(LLD_LIBRARY NAMES lld-14.0 lld140 lld NAMES_PER_DIR
+find_library(LLD_LIBRARY NAMES lld-15.0 lld150 lld NAMES_PER_DIR
     HINTS ${LLVM_LIBDIRS}
     PATHS
-        /usr/lib/llvm-14/lib
-        /usr/local/llvm140/lib
-        /usr/local/llvm14/lib
-        /usr/local/opt/llvm@14/lib
-        /opt/homebrew/opt/llvm@14/lib
+        /usr/lib/llvm-15/lib
+        /usr/local/llvm150/lib
+        /usr/local/llvm15/lib
+        /usr/local/opt/llvm@15/lib
+        /opt/homebrew/opt/llvm@15/lib
 )
 if(EXISTS ${LLD_LIBRARY})
     set(LLD_LIBRARIES ${LLD_LIBRARY})
@@ -34,11 +34,11 @@ else()
             HINTS ${LLVM_LIBDIRS}
             PATHS
                 ${LLD_LIBDIRS}
-                /usr/lib/llvm-14/lib
-                /usr/local/llvm140/lib
-                /usr/local/llvm14/lib
-                /usr/local/opt/llvm@14/lib
-                /opt/homebrew/opt/llvm@14/lib
+                /usr/lib/llvm-15/lib
+                /usr/local/llvm150/lib
+                /usr/local/llvm15/lib
+                /usr/local/opt/llvm@15/lib
+                /opt/homebrew/opt/llvm@15/lib
                 /mingw64/lib
                 /c/msys64/mingw64/lib
                 c:/msys64/mingw64/lib)
cmake/Findllvm.cmake
@@ -13,12 +13,12 @@ if(ZIG_USE_LLVM_CONFIG)
   while(1)
     unset(LLVM_CONFIG_EXE CACHE)
     find_program(LLVM_CONFIG_EXE
-        NAMES llvm-config-14 llvm-config-14.0 llvm-config140 llvm-config14 llvm-config NAMES_PER_DIR
+        NAMES llvm-config-15 llvm-config-15.0 llvm-config150 llvm-config15 llvm-config NAMES_PER_DIR
         PATHS
             "/mingw64/bin"
             "/c/msys64/mingw64/bin"
             "c:/msys64/mingw64/bin"
-            "C:/Libraries/llvm-14.0.0/bin")
+            "C:/Libraries/llvm-15.0.0/bin")
 
     if ("${LLVM_CONFIG_EXE}" STREQUAL "LLVM_CONFIG_EXE-NOTFOUND")
       if (DEFINED LLVM_CONFIG_ERROR_MESSAGE)
@@ -35,9 +35,9 @@ if(ZIG_USE_LLVM_CONFIG)
       OUTPUT_STRIP_TRAILING_WHITESPACE)
 
     get_filename_component(LLVM_CONFIG_DIR "${LLVM_CONFIG_EXE}" DIRECTORY)
-    if("${LLVM_CONFIG_VERSION}" VERSION_LESS 14 OR "${LLVM_CONFIG_VERSION}" VERSION_EQUAL 15 OR "${LLVM_CONFIG_VERSION}" VERSION_GREATER 15)
+    if("${LLVM_CONFIG_VERSION}" VERSION_LESS 15 OR "${LLVM_CONFIG_VERSION}" VERSION_EQUAL 16 OR "${LLVM_CONFIG_VERSION}" VERSION_GREATER 16)
       # Save the error message, in case this is the last llvm-config we find
-      set(LLVM_CONFIG_ERROR_MESSAGE "expected LLVM 14.x but found ${LLVM_CONFIG_VERSION} using ${LLVM_CONFIG_EXE}")
+      set(LLVM_CONFIG_ERROR_MESSAGE "expected LLVM 15.x but found ${LLVM_CONFIG_VERSION} using ${LLVM_CONFIG_EXE}")
 
       # Ignore this directory and try the search again
       list(APPEND CMAKE_IGNORE_PATH "${LLVM_CONFIG_DIR}")
@@ -61,9 +61,9 @@ if(ZIG_USE_LLVM_CONFIG)
       if (LLVM_CONFIG_ERROR) 
         # Save the error message, in case this is the last llvm-config we find
         if (ZIG_SHARED_LLVM)
-          set(LLVM_CONFIG_ERROR_MESSAGE "LLVM 14.x found at ${LLVM_CONFIG_EXE} does not support linking as a shared library")
+          set(LLVM_CONFIG_ERROR_MESSAGE "LLVM 15.x found at ${LLVM_CONFIG_EXE} does not support linking as a shared library")
         else()
-          set(LLVM_CONFIG_ERROR_MESSAGE "LLVM 14.x found at ${LLVM_CONFIG_EXE} does not support linking as a static library")
+          set(LLVM_CONFIG_ERROR_MESSAGE "LLVM 15.x found at ${LLVM_CONFIG_EXE} does not support linking as a static library")
         endif()
 
         # Ignore this directory and try the search again
src/zig_clang_cc1_main.cpp
@@ -212,7 +212,9 @@ int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
   bool Success = CompilerInvocation::CreateFromArgs(Clang->getInvocation(),
                                                     Argv, Diags, Argv0);
 
-  if (Clang->getFrontendOpts().TimeTrace) {
+  if (Clang->getFrontendOpts().TimeTrace ||
+      !Clang->getFrontendOpts().TimeTracePath.empty()) {
+    Clang->getFrontendOpts().TimeTrace = 1;
     llvm::timeTraceProfilerInitialize(
         Clang->getFrontendOpts().TimeTraceGranularity, Argv0);
   }
@@ -256,12 +258,18 @@ int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
   if (llvm::timeTraceProfilerEnabled()) {
     SmallString<128> Path(Clang->getFrontendOpts().OutputFile);
     llvm::sys::path::replace_extension(Path, "json");
+    if (!Clang->getFrontendOpts().TimeTracePath.empty()) {
+      // replace the suffix to '.json' directly
+      SmallString<128> TracePath(Clang->getFrontendOpts().TimeTracePath);
+      if (llvm::sys::fs::is_directory(TracePath))
+        llvm::sys::path::append(TracePath, llvm::sys::path::filename(Path));
+      Path.assign(TracePath);
+    }
     if (auto profilerOutput = Clang->createOutputFile(
             Path.str(), /*Binary=*/false, /*RemoveFileOnSignal=*/false,
             /*useTemporary=*/false)) {
       llvm::timeTraceProfilerWrite(*profilerOutput);
-      // FIXME(ibiryukov): make profilerOutput flush in destructor instead.
-      profilerOutput->flush();
+      profilerOutput.reset();
       llvm::timeTraceProfilerCleanup();
       Clang->clearOutputFiles(false);
     }
src/zig_clang_cc1as_main.cpp
@@ -137,6 +137,9 @@ struct AssemblerInvocation {
   unsigned IncrementalLinkerCompatible : 1;
   unsigned EmbedBitcode : 1;
 
+  /// Whether to emit DWARF unwind info.
+  EmitDwarfUnwindType EmitDwarfUnwind;
+
   /// The name of the relocation model to use.
   std::string RelocationModel;
 
@@ -144,6 +147,9 @@ struct AssemblerInvocation {
   /// otherwise.
   std::string TargetABI;
 
+  /// Darwin target variant triple, the variant of the deployment target
+  /// for which the code is being compiled.
+  llvm::Optional<llvm::Triple> DarwinTargetVariantTriple;
   /// @}
 
 public:
@@ -164,6 +170,7 @@ public:
     Dwarf64 = 0;
     DwarfVersion = 0;
     EmbedBitcode = 0;
+    EmitDwarfUnwind = EmitDwarfUnwindType::Default;
   }
 
   static bool CreateFromArgs(AssemblerInvocation &Res,
@@ -209,6 +216,9 @@ bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
 
   // Target Options
   Opts.Triple = llvm::Triple::normalize(Args.getLastArgValue(OPT_triple));
+  if (Arg *A = Args.getLastArg(options::OPT_darwin_target_variant_triple))
+    Opts.DarwinTargetVariantTriple = llvm::Triple(A->getValue());
+
   Opts.CPU = std::string(Args.getLastArgValue(OPT_target_cpu));
   Opts.Features = Args.getAllArgValues(OPT_target_feature);
 
@@ -311,6 +321,14 @@ bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
                             .Default(0);
   }
 
+  if (auto *A = Args.getLastArg(OPT_femit_dwarf_unwind_EQ)) {
+    Opts.EmitDwarfUnwind =
+        llvm::StringSwitch<EmitDwarfUnwindType>(A->getValue())
+            .Case("always", EmitDwarfUnwindType::Always)
+            .Case("no-compact-unwind", EmitDwarfUnwindType::NoCompactUnwind)
+            .Case("default", EmitDwarfUnwindType::Default);
+  }
+
   return Success;
 }
 
@@ -361,6 +379,8 @@ static bool ExecuteAssemblerImpl(AssemblerInvocation &Opts,
   assert(MRI && "Unable to create target register info!");
 
   MCTargetOptions MCOptions;
+  MCOptions.EmitDwarfUnwind = Opts.EmitDwarfUnwind;
+
   std::unique_ptr<MCAsmInfo> MAI(
       TheTarget->createMCAsmInfo(*MRI, Opts.Triple, MCOptions));
   assert(MAI && "Unable to create target asm info!");
@@ -407,6 +427,8 @@ static bool ExecuteAssemblerImpl(AssemblerInvocation &Opts,
   // MCObjectFileInfo needs a MCContext reference in order to initialize itself.
   std::unique_ptr<MCObjectFileInfo> MOFI(
       TheTarget->createMCObjectFileInfo(Ctx, PIC));
+  if (Opts.DarwinTargetVariantTriple)
+    MOFI->setDarwinTargetVariantTriple(*Opts.DarwinTargetVariantTriple);
   Ctx.setObjectFileInfo(MOFI.get());
 
   if (Opts.SaveTemporaryLabels)
@@ -455,7 +477,7 @@ static bool ExecuteAssemblerImpl(AssemblerInvocation &Opts,
 
     std::unique_ptr<MCCodeEmitter> CE;
     if (Opts.ShowEncoding)
-      CE.reset(TheTarget->createMCCodeEmitter(*MCII, *MRI, Ctx));
+      CE.reset(TheTarget->createMCCodeEmitter(*MCII, Ctx));
     std::unique_ptr<MCAsmBackend> MAB(
         TheTarget->createMCAsmBackend(*STI, *MRI, MCOptions));
 
@@ -475,7 +497,7 @@ static bool ExecuteAssemblerImpl(AssemblerInvocation &Opts,
     }
 
     std::unique_ptr<MCCodeEmitter> CE(
-        TheTarget->createMCCodeEmitter(*MCII, *MRI, Ctx));
+        TheTarget->createMCCodeEmitter(*MCII, Ctx));
     std::unique_ptr<MCAsmBackend> MAB(
         TheTarget->createMCAsmBackend(*STI, *MRI, MCOptions));
     assert(MAB && "Unable to create asm backend!");
@@ -497,7 +519,7 @@ static bool ExecuteAssemblerImpl(AssemblerInvocation &Opts,
   if (Opts.EmbedBitcode && Ctx.getObjectFileType() == MCContext::IsMachO) {
     MCSection *AsmLabel = Ctx.getMachOSection(
         "__LLVM", "__asm", MachO::S_REGULAR, 4, SectionKind::getReadOnly());
-    Str.get()->SwitchSection(AsmLabel);
+    Str.get()->switchSection(AsmLabel);
     Str.get()->emitZeros(1);
   }
 
src/zig_clang_driver.cpp
@@ -410,18 +410,18 @@ int ZigClang_main(int Argc, const char **Argv) {
   if (ClangCLMode) {
     // Arguments in "CL" are prepended.
     llvm::Optional<std::string> OptCL = llvm::sys::Process::GetEnv("CL");
-    if (OptCL.hasValue()) {
+    if (OptCL) {
       SmallVector<const char *, 8> PrependedOpts;
-      getCLEnvVarOptions(OptCL.getValue(), Saver, PrependedOpts);
+      getCLEnvVarOptions(OptCL.value(), Saver, PrependedOpts);
 
       // Insert right after the program name to prepend to the argument list.
       Args.insert(Args.begin() + 1, PrependedOpts.begin(), PrependedOpts.end());
     }
     // Arguments in "_CL_" are appended.
     llvm::Optional<std::string> Opt_CL_ = llvm::sys::Process::GetEnv("_CL_");
-    if (Opt_CL_.hasValue()) {
+    if (Opt_CL_) {
       SmallVector<const char *, 8> AppendedOpts;
-      getCLEnvVarOptions(Opt_CL_.getValue(), Saver, AppendedOpts);
+      getCLEnvVarOptions(Opt_CL_.value(), Saver, AppendedOpts);
 
       // Insert at the end of the argument list to append.
       Args.append(AppendedOpts.begin(), AppendedOpts.end());
@@ -488,32 +488,39 @@ int ZigClang_main(int Argc, const char **Argv) {
   }
 
   std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(Args));
+
+  Driver::ReproLevel ReproLevel = Driver::ReproLevel::OnCrash;
+  if (Arg *A = C->getArgs().getLastArg(options::OPT_gen_reproducer_eq)) {
+    auto Level = llvm::StringSwitch<Optional<Driver::ReproLevel>>(A->getValue())
+                     .Case("off", Driver::ReproLevel::Off)
+                     .Case("crash", Driver::ReproLevel::OnCrash)
+                     .Case("error", Driver::ReproLevel::OnError)
+                     .Case("always", Driver::ReproLevel::Always)
+                     .Default(None);
+    if (!Level) {
+      llvm::errs() << "Unknown value for " << A->getSpelling() << ": '"
+                   << A->getValue() << "'\n";
+      return 1;
+    }
+    ReproLevel = *Level;
+  }
+  if (!!::getenv("FORCE_CLANG_DIAGNOSTICS_CRASH"))
+    ReproLevel = Driver::ReproLevel::Always;
+
   int Res = 1;
   bool IsCrash = false;
+  Driver::CommandStatus CommandStatus = Driver::CommandStatus::Ok;
+  // Pretend the first command failed if ReproStatus is Always.
+  const Command *FailingCommand = nullptr;
+  if (!C->getJobs().empty())
+    FailingCommand = &*C->getJobs().begin();
   if (C && !C->containsError()) {
     SmallVector<std::pair<int, const Command *>, 4> FailingCommands;
     Res = TheDriver.ExecuteCompilation(*C, FailingCommands);
 
-    // Force a crash to test the diagnostics.
-    if (TheDriver.GenReproducer) {
-      Diags.Report(diag::err_drv_force_crash)
-        << !::getenv("FORCE_CLANG_DIAGNOSTICS_CRASH");
-
-      // Pretend that every command failed.
-      FailingCommands.clear();
-      for (const auto &J : C->getJobs())
-        if (const Command *C = dyn_cast<Command>(&J))
-          FailingCommands.push_back(std::make_pair(-1, C));
-
-      // Print the bug report message that would be printed if we did actually
-      // crash, but only if we're crashing due to FORCE_CLANG_DIAGNOSTICS_CRASH.
-      if (::getenv("FORCE_CLANG_DIAGNOSTICS_CRASH"))
-        llvm::dbgs() << llvm::getBugReportMsg();
-    }
-
     for (const auto &P : FailingCommands) {
       int CommandRes = P.first;
-      const Command *FailingCommand = P.second;
+      FailingCommand = P.second;
       if (!Res)
         Res = CommandRes;
 
@@ -532,13 +539,22 @@ int ZigClang_main(int Argc, const char **Argv) {
       // https://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xcu_chap02.html
       IsCrash |= CommandRes > 128;
 #endif
-      if (IsCrash) {
-        TheDriver.generateCompilationDiagnostics(*C, *FailingCommand);
+      CommandStatus =
+          IsCrash ? Driver::CommandStatus::Crash : Driver::CommandStatus::Error;
+      if (IsCrash)
         break;
-      }
     }
   }
 
+  // Print the bug report message that would be printed if we did actually
+  // crash, but only if we're crashing due to FORCE_CLANG_DIAGNOSTICS_CRASH.
+  if (::getenv("FORCE_CLANG_DIAGNOSTICS_CRASH"))
+    llvm::dbgs() << llvm::getBugReportMsg();
+  if (FailingCommand != nullptr &&
+    TheDriver.maybeGenerateCompilationDiagnostics(CommandStatus, ReproLevel,
+                                                  *C, *FailingCommand))
+    Res = 1;
+
   Diags.getClient()->finish();
 
   if (!UseNewCC1Process && IsCrash) {
src/zig_llvm-ar.cpp
@@ -18,10 +18,15 @@
 #include "llvm/IR/LLVMContext.h"
 #include "llvm/Object/Archive.h"
 #include "llvm/Object/ArchiveWriter.h"
+#include "llvm/Object/COFFImportFile.h"
+#include "llvm/Object/ELFObjectFile.h"
 #include "llvm/Object/IRObjectFile.h"
 #include "llvm/Object/MachO.h"
 #include "llvm/Object/ObjectFile.h"
 #include "llvm/Object/SymbolicFile.h"
+#include "llvm/Object/TapiFile.h"
+#include "llvm/Object/Wasm.h"
+#include "llvm/Object/XCOFFObjectFile.h"
 #include "llvm/Support/Chrono.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/ConvertUTF.h"
@@ -54,6 +59,7 @@
 #endif
 
 using namespace llvm;
+using namespace llvm::object;
 
 // The name this program was invoked as.
 static StringRef ToolName;
@@ -61,37 +67,36 @@ static StringRef ToolName;
 // The basename of this program.
 static StringRef Stem;
 
-const char RanlibHelp[] = R"(OVERVIEW: LLVM Ranlib (llvm-ranlib)
-
-  This program generates an index to speed access to archives
-
-USAGE: llvm-ranlib <archive-file>
-
-OPTIONS:
-  -h --help             - Display available options
-  -v --version          - Display the version of this program
-  -D                    - Use zero for timestamps and uids/gids (default)
-  -U                    - Use actual timestamps and uids/gids
-)";
-
-const char ArHelp[] = R"(OVERVIEW: LLVM Archiver
-
-USAGE: llvm-ar [options] [-]<operation>[modifiers] [relpos] [count] <archive> [files]
-       llvm-ar -M [<mri-script]
+static void printRanLibHelp(StringRef ToolName) {
+  outs() << "OVERVIEW: LLVM Ranlib\n\n"
+         << "This program generates an index to speed access to archives\n\n"
+         << "USAGE: " + ToolName + " <archive-file>\n\n"
+         << "OPTIONS:\n"
+         << "  -h --help             - Display available options\n"
+         << "  -v --version          - Display the version of this program\n"
+         << "  -D                    - Use zero for timestamps and uids/gids "
+            "(default)\n"
+         << "  -U                    - Use actual timestamps and uids/gids\n";
+}
 
-OPTIONS:
+static void printArHelp(StringRef ToolName) {
+  const char ArOptions[] =
+      R"(OPTIONS:
   --format              - archive format to create
     =default            -   default
     =gnu                -   gnu
     =darwin             -   darwin
     =bsd                -   bsd
+    =bigarchive         -   big archive (AIX OS)
   --plugin=<string>     - ignored for compatibility
   -h --help             - display this help and exit
+  --output              - the directory to extract archive members to
   --rsp-quoting         - quoting style for response files
     =posix              -   posix
     =windows            -   windows
   --thin                - create a thin archive
   --version             - print the version and exit
+  -X{32|64|32_64|any}   - object mode (only for AIX OS)
   @<file>               - read options from <file>
 
 OPERATIONS:
@@ -126,11 +131,20 @@ MODIFIERS:
   [V] - display the version and exit
 )";
 
+  outs() << "OVERVIEW: LLVM Archiver\n\n"
+         << "USAGE: " + ToolName +
+                " [options] [-]<operation>[modifiers] [relpos] "
+                "[count] <archive> [files]\n"
+         << "       " + ToolName + " -M [<mri-script]\n\n";
+
+  outs() << ArOptions;
+}
+
 static void printHelpMessage() {
   if (Stem.contains_insensitive("ranlib"))
-    outs() << RanlibHelp;
+    printRanLibHelp(Stem);
   else if (Stem.contains_insensitive("ar"))
-    outs() << ArHelp;
+    printArHelp(Stem);
 }
 
 static unsigned MRILineNumber;
@@ -176,12 +190,16 @@ static void failIfError(Error E, Twine Context = "") {
   });
 }
 
+static void warn(Twine Message) {
+  WithColor::warning(errs(), ToolName) << Message << "\n";
+}
+
 static SmallVector<const char *, 256> PositionalArgs;
 
 static bool MRI;
 
 namespace {
-enum Format { Default, GNU, BSD, DARWIN, Unknown };
+enum Format { Default, GNU, BSD, DARWIN, BIGARCHIVE, Unknown };
 }
 
 static Format FormatType = Default;
@@ -201,6 +219,10 @@ enum ArchiveOperation {
   CreateSymTab     ///< Create a symbol table in an existing archive
 };
 
+enum class BitModeTy { Bit32, Bit64, Bit32_64, Any, Unknown };
+
+static BitModeTy BitMode = BitModeTy::Bit32;
+
 // Modifiers to follow operation to vary behavior
 static bool AddAfter = false;             ///< 'a' modifier
 static bool AddBefore = false;            ///< 'b' modifier
@@ -230,6 +252,9 @@ static int CountParam = 0;
 // command line.
 static std::string ArchiveName;
 
+// Output directory specified by --output.
+static std::string OutputDir;
+
 static std::vector<std::unique_ptr<MemoryBuffer>> ArchiveBuffers;
 static std::vector<std::unique_ptr<object::Archive>> Archives;
 
@@ -447,6 +472,19 @@ static ArchiveOperation parseCommandLine() {
   if (AddLibrary && Operation != QuickAppend)
     badUsage("the 'L' modifier is only applicable to the 'q' operation");
 
+  if (!OutputDir.empty()) {
+    if (Operation != Extract)
+      badUsage("--output is only applicable to the 'x' operation");
+    bool IsDir = false;
+    // If OutputDir is not a directory, create_directories may still succeed if
+    // all components of the path prefix are directories. Test is_directory as
+    // well.
+    if (!sys::fs::create_directories(OutputDir))
+      sys::fs::is_directory(OutputDir, IsDir);
+    if (!IsDir)
+      fail("'" + OutputDir + "' is not a directory");
+  }
+
   // Return the parsed operation to the caller
   return Operation;
 }
@@ -547,7 +585,15 @@ static void doExtract(StringRef Name, const object::Archive::Child &C) {
   failIfError(ModeOrErr.takeError());
   sys::fs::perms Mode = ModeOrErr.get();
 
-  llvm::StringRef outputFilePath = sys::path::filename(Name);
+  StringRef outputFilePath;
+  SmallString<128> path;
+  if (OutputDir.empty()) {
+    outputFilePath = sys::path::filename(Name);
+  } else {
+    sys::path::append(path, OutputDir, sys::path::filename(Name));
+    outputFilePath = path.str();
+  }
+
   if (Verbose)
     outs() << "x - " << outputFilePath << '\n';
 
@@ -600,6 +646,71 @@ static bool shouldCreateArchive(ArchiveOperation Op) {
   llvm_unreachable("Missing entry in covered switch.");
 }
 
+static bool is64BitSymbolicFile(SymbolicFile &Obj) {
+  if (auto *IRObj = dyn_cast<IRObjectFile>(&Obj))
+    return Triple(IRObj->getTargetTriple()).isArch64Bit();
+  if (isa<COFFObjectFile>(Obj) || isa<COFFImportFile>(Obj))
+    return false;
+  if (XCOFFObjectFile *XCOFFObj = dyn_cast<XCOFFObjectFile>(&Obj))
+    return XCOFFObj->is64Bit();
+  if (isa<WasmObjectFile>(Obj))
+    return false;
+  if (TapiFile *Tapi = dyn_cast<TapiFile>(&Obj))
+    return Tapi->is64Bit();
+  if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(&Obj))
+    return MachO->is64Bit();
+  if (ELFObjectFileBase *ElfO = dyn_cast<ELFObjectFileBase>(&Obj))
+    return ElfO->getBytesInAddress() == 8;
+
+  fail("unsupported file format");
+}
+
+static bool isValidInBitMode(Binary &Bin) {
+  if (BitMode == BitModeTy::Bit32_64 || BitMode == BitModeTy::Any)
+    return true;
+
+  if (SymbolicFile *SymFile = dyn_cast<SymbolicFile>(&Bin)) {
+    bool Is64Bit = is64BitSymbolicFile(*SymFile);
+    if ((Is64Bit && (BitMode == BitModeTy::Bit32)) ||
+        (!Is64Bit && (BitMode == BitModeTy::Bit64)))
+      return false;
+  }
+  // In AIX "ar", non-object files are always considered to have a valid bit
+  // mode.
+  return true;
+}
+
+Expected<std::unique_ptr<Binary>> getAsBinary(const NewArchiveMember &NM,
+                                              LLVMContext *Context) {
+  auto BinaryOrErr = createBinary(NM.Buf->getMemBufferRef(), Context);
+  if (BinaryOrErr)
+    return std::move(*BinaryOrErr);
+  return BinaryOrErr.takeError();
+}
+
+Expected<std::unique_ptr<Binary>> getAsBinary(const Archive::Child &C,
+                                              LLVMContext *Context) {
+  return C.getAsBinary(Context);
+}
+
+template <class A> static bool isValidInBitMode(const A &Member) {
+  if (object::Archive::getDefaultKindForHost() != object::Archive::K_AIXBIG)
+    return true;
+  LLVMContext Context;
+  Expected<std::unique_ptr<Binary>> BinOrErr = getAsBinary(Member, &Context);
+  // In AIX "ar", if there is a non-object file member, it is never ignored due
+  // to the bit mode setting.
+  if (!BinOrErr) {
+    consumeError(BinOrErr.takeError());
+    return true;
+  }
+  return isValidInBitMode(*BinOrErr.get());
+}
+
+static void warnInvalidObjectForFileMode(Twine Name) {
+  warn("'" + Name + "' is not valid with the current object file mode");
+}
+
 static void performReadOperation(ArchiveOperation Operation,
                                  object::Archive *OldArchive) {
   if (Operation == Extract && OldArchive->isThin())
@@ -614,6 +725,10 @@ static void performReadOperation(ArchiveOperation Operation,
       failIfError(NameOrErr.takeError());
       StringRef Name = NameOrErr.get();
 
+      // Check whether to ignore this object due to its bitness.
+      if (!isValidInBitMode(C))
+        continue;
+
       if (Filter) {
         auto I = find_if(Members, [Name](StringRef Path) {
           return comparePaths(Name, Path);
@@ -652,8 +767,6 @@ static void performReadOperation(ArchiveOperation Operation,
 static void addChildMember(std::vector<NewArchiveMember> &Members,
                            const object::Archive::Child &M,
                            bool FlattenArchive = false) {
-  if (Thin && !M.getParent()->isThin())
-    fail("cannot convert a regular archive to a thin one");
   Expected<NewArchiveMember> NMOrErr =
       NewArchiveMember::getOldMember(M, Deterministic);
   failIfError(NMOrErr.takeError());
@@ -692,8 +805,7 @@ static void addChildMember(std::vector<NewArchiveMember> &Members,
   Members.push_back(std::move(*NMOrErr));
 }
 
-static void addMember(std::vector<NewArchiveMember> &Members,
-                      StringRef FileName, bool FlattenArchive = false) {
+static NewArchiveMember getArchiveMember(StringRef FileName) {
   Expected<NewArchiveMember> NMOrErr =
       NewArchiveMember::getFile(FileName, Deterministic);
   failIfError(NMOrErr.takeError(), FileName);
@@ -713,9 +825,24 @@ static void addMember(std::vector<NewArchiveMember> &Members,
           PathOrErr ? *PathOrErr : sys::path::convert_to_slash(FileName));
     }
   }
+  return std::move(*NMOrErr);
+}
+
+static void addMember(std::vector<NewArchiveMember> &Members,
+                      NewArchiveMember &NM) {
+  Members.push_back(std::move(NM));
+}
+
+static void addMember(std::vector<NewArchiveMember> &Members,
+                      StringRef FileName, bool FlattenArchive = false) {
+  NewArchiveMember NM = getArchiveMember(FileName);
+  if (!isValidInBitMode(NM)) {
+    warnInvalidObjectForFileMode(FileName);
+    return;
+  }
 
   if (FlattenArchive &&
-      identify_magic(NMOrErr->Buf->getBuffer()) == file_magic::archive) {
+      identify_magic(NM.Buf->getBuffer()) == file_magic::archive) {
     object::Archive &Lib = readLibrary(FileName);
     // When creating thin archives, only flatten if the member is also thin.
     if (!Thin || Lib.isThin()) {
@@ -727,7 +854,7 @@ static void addMember(std::vector<NewArchiveMember> &Members,
       return;
     }
   }
-  Members.push_back(std::move(*NMOrErr));
+  Members.push_back(std::move(NM));
 }
 
 enum InsertAction {
@@ -743,6 +870,9 @@ static InsertAction computeInsertAction(ArchiveOperation Operation,
                                         StringRef Name,
                                         std::vector<StringRef>::iterator &Pos,
                                         StringMap<int> &MemberCount) {
+  if (!isValidInBitMode(Member))
+    return IA_AddOldMember;
+
   if (Operation == QuickAppend || Members.empty())
     return IA_AddOldMember;
   auto MI = find_if(
@@ -804,7 +934,7 @@ computeNewArchiveMembers(ArchiveOperation Operation,
       Expected<StringRef> NameOrErr = Child.getName();
       failIfError(NameOrErr.takeError());
       std::string Name = std::string(NameOrErr.get());
-      if (comparePaths(Name, RelPos)) {
+      if (comparePaths(Name, RelPos) && isValidInBitMode(Child)) {
         assert(AddAfter || AddBefore);
         if (AddBefore)
           InsertPos = Pos;
@@ -815,12 +945,25 @@ computeNewArchiveMembers(ArchiveOperation Operation,
       std::vector<StringRef>::iterator MemberI = Members.end();
       InsertAction Action =
           computeInsertAction(Operation, Child, Name, MemberI, MemberCount);
+
+      auto HandleNewMember = [](auto Member, auto &Members, auto &Child) {
+        NewArchiveMember NM = getArchiveMember(*Member);
+        if (isValidInBitMode(NM))
+          addMember(Members, NM);
+        else {
+          // If a new member is not a valid object for the bit mode, add
+          // the old member back.
+          warnInvalidObjectForFileMode(*Member);
+          addChildMember(Members, Child, /*FlattenArchive=*/Thin);
+        }
+      };
+
       switch (Action) {
       case IA_AddOldMember:
         addChildMember(Ret, Child, /*FlattenArchive=*/Thin);
         break;
       case IA_AddNewMember:
-        addMember(Ret, *MemberI);
+        HandleNewMember(MemberI, Ret, Child);
         break;
       case IA_Delete:
         break;
@@ -828,7 +971,7 @@ computeNewArchiveMembers(ArchiveOperation Operation,
         addChildMember(Moved, Child, /*FlattenArchive=*/Thin);
         break;
       case IA_MoveNewMember:
-        addMember(Moved, *MemberI);
+        HandleNewMember(MemberI, Moved, Child);
         break;
       }
       // When processing elements with the count param, we need to preserve the
@@ -875,48 +1018,18 @@ computeNewArchiveMembers(ArchiveOperation Operation,
   return Ret;
 }
 
-static object::Archive::Kind getDefaultForHost() {
-  return Triple(sys::getProcessTriple()).isOSDarwin()
-             ? object::Archive::K_DARWIN
-             : object::Archive::K_GNU;
-}
-
-static object::Archive::Kind getKindFromMember(const NewArchiveMember &Member) {
-  auto MemBufferRef = Member.Buf->getMemBufferRef();
-  Expected<std::unique_ptr<object::ObjectFile>> OptionalObject =
-      object::ObjectFile::createObjectFile(MemBufferRef);
-
-  if (OptionalObject)
-    return isa<object::MachOObjectFile>(**OptionalObject)
-               ? object::Archive::K_DARWIN
-               : object::Archive::K_GNU;
-
-  // squelch the error in case we had a non-object file
-  consumeError(OptionalObject.takeError());
-
-  // If we're adding a bitcode file to the archive, detect the Archive kind
-  // based on the target triple.
-  LLVMContext Context;
-  if (identify_magic(MemBufferRef.getBuffer()) == file_magic::bitcode) {
-    if (auto ObjOrErr = object::SymbolicFile::createSymbolicFile(
-            MemBufferRef, file_magic::bitcode, &Context)) {
-      auto &IRObject = cast<object::IRObjectFile>(**ObjOrErr);
-      return Triple(IRObject.getTargetTriple()).isOSDarwin()
-                 ? object::Archive::K_DARWIN
-                 : object::Archive::K_GNU;
-    } else {
-      // Squelch the error in case this was not a SymbolicFile.
-      consumeError(ObjOrErr.takeError());
-    }
-  }
-
-  return getDefaultForHost();
-}
-
 static void performWriteOperation(ArchiveOperation Operation,
                                   object::Archive *OldArchive,
                                   std::unique_ptr<MemoryBuffer> OldArchiveBuf,
                                   std::vector<NewArchiveMember> *NewMembersP) {
+  if (OldArchive) {
+    if (Thin && !OldArchive->isThin())
+      fail("cannot convert a regular archive to a thin one");
+
+    if (OldArchive->isThin())
+      Thin = true;
+  }
+
   std::vector<NewArchiveMember> NewMembers;
   if (!NewMembersP)
     NewMembers = computeNewArchiveMembers(Operation, OldArchive);
@@ -926,14 +1039,23 @@ static void performWriteOperation(ArchiveOperation Operation,
   case Default:
     if (Thin)
       Kind = object::Archive::K_GNU;
-    else if (OldArchive)
+    else if (OldArchive) {
       Kind = OldArchive->kind();
-    else if (NewMembersP)
-      Kind = !NewMembersP->empty() ? getKindFromMember(NewMembersP->front())
-                                   : getDefaultForHost();
+      if (Kind == object::Archive::K_BSD) {
+        auto InferredKind = object::Archive::K_BSD;
+        if (NewMembersP && !NewMembersP->empty())
+          InferredKind = NewMembersP->front().detectKindFromObject();
+        else if (!NewMembers.empty())
+          InferredKind = NewMembers.front().detectKindFromObject();
+        if (InferredKind == object::Archive::K_DARWIN)
+          Kind = object::Archive::K_DARWIN;
+      }
+    } else if (NewMembersP)
+      Kind = !NewMembersP->empty() ? NewMembersP->front().detectKindFromObject()
+                                   : object::Archive::getDefaultKindForHost();
     else
-      Kind = !NewMembers.empty() ? getKindFromMember(NewMembers.front())
-                                 : getDefaultForHost();
+      Kind = !NewMembers.empty() ? NewMembers.front().detectKindFromObject()
+                                 : object::Archive::getDefaultKindForHost();
     break;
   case GNU:
     Kind = object::Archive::K_GNU;
@@ -948,6 +1070,11 @@ static void performWriteOperation(ArchiveOperation Operation,
       fail("only the gnu format has a thin mode");
     Kind = object::Archive::K_DARWIN;
     break;
+  case BIGARCHIVE:
+    if (Thin)
+      fail("only the gnu format has a thin mode");
+    Kind = object::Archive::K_AIXBIG;
+    break;
   case Unknown:
     llvm_unreachable("");
   }
@@ -1029,8 +1156,7 @@ static int performOperation(ArchiveOperation Operation,
   } else {
     if (!Create) {
       // Produce a warning if we should and we're creating the archive
-      WithColor::warning(errs(), ToolName)
-          << "creating " << ArchiveName << "\n";
+      warn("creating " + ArchiveName);
     }
   }
 
@@ -1073,8 +1199,12 @@ static void runMRIScript() {
 
     switch (Command) {
     case MRICommand::AddLib: {
+      if (!Create)
+        fail("no output archive has been opened");
       object::Archive &Lib = readLibrary(Rest);
       {
+        if (Thin && !Lib.isThin())
+          fail("cannot add a regular archive's contents to a thin archive");
         Error Err = Error::success();
         for (auto &Member : Lib.children(Err))
           addChildMember(NewMembers, Member, /*FlattenArchive=*/Thin);
@@ -1083,6 +1213,8 @@ static void runMRIScript() {
       break;
     }
     case MRICommand::AddMod:
+      if (!Create)
+        fail("no output archive has been opened");
       addMember(NewMembers, Rest);
       break;
     case MRICommand::CreateThin:
@@ -1095,6 +1227,8 @@ static void runMRIScript() {
       if (Saved)
         fail("file already saved");
       ArchiveName = std::string(Rest);
+      if (ArchiveName.empty())
+        fail("missing archive name");
       break;
     case MRICommand::Delete: {
       llvm::erase_if(NewMembers, [=](NewArchiveMember &M) {
@@ -1116,7 +1250,8 @@ static void runMRIScript() {
 
   // Nothing to do if not saved.
   if (Saved)
-    performOperation(ReplaceOrInsert, &NewMembers);
+    performOperation(ReplaceOrInsert, /*OldArchive=*/nullptr,
+                     /*OldArchiveBuf=*/nullptr, &NewMembers);
   exit(0);
 }
 
@@ -1132,6 +1267,15 @@ static bool handleGenericOption(StringRef arg) {
   return false;
 }
 
+static BitModeTy getBitMode(const char *RawBitMode) {
+  return StringSwitch<BitModeTy>(RawBitMode)
+      .Case("32", BitModeTy::Bit32)
+      .Case("64", BitModeTy::Bit64)
+      .Case("32_64", BitModeTy::Bit32_64)
+      .Case("any", BitModeTy::Any)
+      .Default(BitModeTy::Unknown);
+}
+
 static const char *matchFlagWithArg(StringRef Expected,
                                     ArrayRef<const char *>::iterator &ArgIt,
                                     ArrayRef<const char *> Args) {
@@ -1181,6 +1325,14 @@ static int ar_main(int argc, char **argv) {
 
   cl::ExpandResponseFiles(Saver, getRspQuoting(makeArrayRef(argv, argc)), Argv);
 
+  // Get BitMode from enviorment variable "OBJECT_MODE" for AIX OS, if
+  // specified.
+  if (object::Archive::getDefaultKindForHost() == object::Archive::K_AIXBIG) {
+    BitMode = getBitMode(getenv("OBJECT_MODE"));
+    if (BitMode == BitModeTy::Unknown)
+      BitMode = BitModeTy::Bit32;
+  }
+
   for (ArrayRef<const char *>::iterator ArgIt = Argv.begin();
        ArgIt != Argv.end(); ++ArgIt) {
     const char *Match = nullptr;
@@ -1219,16 +1371,35 @@ static int ar_main(int argc, char **argv) {
                        .Case("gnu", GNU)
                        .Case("darwin", DARWIN)
                        .Case("bsd", BSD)
+                       .Case("bigarchive", BIGARCHIVE)
                        .Default(Unknown);
       if (FormatType == Unknown)
         fail(std::string("Invalid format ") + Match);
       continue;
     }
 
+    if ((Match = matchFlagWithArg("output", ArgIt, Argv))) {
+      OutputDir = Match;
+      continue;
+    }
+
     if (matchFlagWithArg("plugin", ArgIt, Argv) ||
         matchFlagWithArg("rsp-quoting", ArgIt, Argv))
       continue;
 
+    if (strncmp(*ArgIt, "-X", 2) == 0) {
+      if (object::Archive::getDefaultKindForHost() ==
+          object::Archive::K_AIXBIG) {
+        Match = *(*ArgIt + 2) != '\0' ? *ArgIt + 2 : *(++ArgIt);
+        BitMode = getBitMode(Match);
+        if (BitMode == BitModeTy::Unknown)
+          fail(Twine("invalid bit mode: ") + Match);
+        continue;
+      } else {
+        fail(Twine(*ArgIt) + " option not supported on non AIX OS");
+      }
+    }
+
     Options += *ArgIt + 1;
   }
 
CMakeLists.txt
@@ -108,9 +108,9 @@ else()
     set(ZIG_USE_LLVM_CONFIG OFF CACHE BOOL "use llvm-config to find LLVM libraries")
 endif()
 
-find_package(llvm 14)
-find_package(clang 14)
-find_package(lld 14)
+find_package(llvm 15)
+find_package(clang 15)
+find_package(lld 15)
 
 if(ZIG_STATIC_ZLIB)
     list(REMOVE_ITEM LLVM_LIBRARIES "-lz")