From f09d54ed2a75b62960b35258136435d7c8d418e1 Mon Sep 17 00:00:00 2001
From: Sean Fertile <sfertile@ca.ibm.com>
Date: Tue, 9 Jul 2019 19:21:01 +0000
Subject: [PATCH] Boilerplate for producing XCOFF object files from the PowerPC
 backend.

Stubs out a number of the classes needed to produce a new object file format
(XCOFF) for the powerpc-aix target. For testing input is an empty module which
produces an object file with just a file header.

Differential Revision: https://reviews.llvm.org/D61694

llvm-svn: 365541
---
 llvm/include/llvm/BinaryFormat/XCOFF.h        | 30 ++++++
 llvm/include/llvm/MC/MCAsmInfoXCOFF.h         | 25 +++++
 llvm/include/llvm/MC/MCContext.h              | 23 +++++
 llvm/include/llvm/MC/MCObjectFileInfo.h       |  1 +
 llvm/include/llvm/MC/MCSection.h              |  2 +-
 llvm/include/llvm/MC/MCSectionXCOFF.h         | 56 +++++++++++
 llvm/include/llvm/MC/MCXCOFFObjectWriter.h    | 41 ++++++++
 llvm/include/llvm/MC/MCXCOFFStreamer.h        | 33 +++++++
 llvm/include/llvm/Support/TargetRegistry.h    |  9 +-
 llvm/lib/MC/CMakeLists.txt                    |  5 +
 llvm/lib/MC/MCAsmBackend.cpp                  |  4 +
 llvm/lib/MC/MCAsmInfoXCOFF.cpp                | 18 ++++
 llvm/lib/MC/MCContext.cpp                     | 35 +++++++
 llvm/lib/MC/MCObjectFileInfo.cpp              | 13 ++-
 llvm/lib/MC/MCSectionXCOFF.cpp                | 33 +++++++
 llvm/lib/MC/MCXCOFFObjectTargetWriter.cpp     | 16 ++++
 llvm/lib/MC/MCXCOFFStreamer.cpp               | 59 ++++++++++++
 llvm/lib/MC/XCOFFObjectWriter.cpp             | 94 +++++++++++++++++++
 .../PowerPC/MCTargetDesc/CMakeLists.txt       |  1 +
 .../PowerPC/MCTargetDesc/PPCAsmBackend.cpp    | 14 +++
 .../PowerPC/MCTargetDesc/PPCMCAsmInfo.cpp     |  6 ++
 .../PowerPC/MCTargetDesc/PPCMCAsmInfo.h       | 10 +-
 .../PowerPC/MCTargetDesc/PPCMCTargetDesc.cpp  | 25 +++++
 .../PowerPC/MCTargetDesc/PPCMCTargetDesc.h    |  3 +
 .../MCTargetDesc/PPCXCOFFObjectWriter.cpp     | 29 ++++++
 llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp     | 11 +++
 llvm/test/CodeGen/PowerPC/aix-xcoff-basic.ll  | 37 ++++++++
 27 files changed, 628 insertions(+), 5 deletions(-)
 create mode 100644 llvm/include/llvm/MC/MCAsmInfoXCOFF.h
 create mode 100644 llvm/include/llvm/MC/MCSectionXCOFF.h
 create mode 100644 llvm/include/llvm/MC/MCXCOFFObjectWriter.h
 create mode 100644 llvm/include/llvm/MC/MCXCOFFStreamer.h
 create mode 100644 llvm/lib/MC/MCAsmInfoXCOFF.cpp
 create mode 100644 llvm/lib/MC/MCSectionXCOFF.cpp
 create mode 100644 llvm/lib/MC/MCXCOFFObjectTargetWriter.cpp
 create mode 100644 llvm/lib/MC/MCXCOFFStreamer.cpp
 create mode 100644 llvm/lib/MC/XCOFFObjectWriter.cpp
 create mode 100644 llvm/lib/Target/PowerPC/MCTargetDesc/PPCXCOFFObjectWriter.cpp
 create mode 100644 llvm/test/CodeGen/PowerPC/aix-xcoff-basic.ll

diff --git a/llvm/include/llvm/BinaryFormat/XCOFF.h b/llvm/include/llvm/BinaryFormat/XCOFF.h
index 9c17559b40d7..7774ab3ed24a 100644
--- a/llvm/include/llvm/BinaryFormat/XCOFF.h
+++ b/llvm/include/llvm/BinaryFormat/XCOFF.h
@@ -22,6 +22,36 @@ namespace XCOFF {
 enum { SectionNameSize = 8, SymbolNameSize = 8 };
 enum ReservedSectionNum { N_DEBUG = -2, N_ABS = -1, N_UNDEF = 0 };
 
+// x_smclas field of x_csect from system header: /usr/include/syms.h
+/// Storage Mapping Class definitions.
+enum StorageMappingClass {
+  //     READ ONLY CLASSES
+  XMC_PR = 0,      ///< Program Code
+  XMC_RO = 1,      ///< Read Only Constant
+  XMC_DB = 2,      ///< Debug Dictionary Table
+  XMC_GL = 6,      ///< Global Linkage (Interfile Interface Code)
+  XMC_XO = 7,      ///< Extended Operation (Pseudo Machine Instruction)
+  XMC_SV = 8,      ///< Supervisor Call (32-bit process only)
+  XMC_SV64 = 17,   ///< Supervisor Call for 64-bit process
+  XMC_SV3264 = 18, ///< Supervisor Call for both 32- and 64-bit processes
+  XMC_TI = 12,     ///< Traceback Index csect
+  XMC_TB = 13,     ///< Traceback Table csect
+
+  //       READ WRITE CLASSES
+  XMC_RW = 5,   ///< Read Write Data
+  XMC_TC0 = 15, ///< TOC Anchor for TOC Addressability
+  XMC_TC = 3,   ///< General TOC item
+  XMC_TD = 16,  ///< Scalar data item in the TOC
+  XMC_DS = 10,  ///< Descriptor csect
+  XMC_UA = 4,   ///< Unclassified - Treated as Read Write
+  XMC_BS = 9,   ///< BSS class (uninitialized static internal)
+  XMC_UC = 11,  ///< Un-named Fortran Common
+
+  XMC_TL = 20, ///< Initialized thread-local variable
+  XMC_UL = 21, ///< Uninitialized thread-local variable
+  XMC_TE = 22  ///< Symbol mapped at the end of TOC
+};
+
 // Flags for defining the section type. Used for the s_flags field of
 // the section header structure. Defined in the system header `scnhdr.h`.
 enum SectionTypeFlags {
diff --git a/llvm/include/llvm/MC/MCAsmInfoXCOFF.h b/llvm/include/llvm/MC/MCAsmInfoXCOFF.h
new file mode 100644
index 000000000000..2a72ba7398a7
--- /dev/null
+++ b/llvm/include/llvm/MC/MCAsmInfoXCOFF.h
@@ -0,0 +1,25 @@
+//===- MCAsmInfoXCOFF.h - XCOFF asm properties ----------------- *- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_MC_MCASMINFOXCOFF_H
+#define LLVM_MC_MCASMINFOXCOFF_H
+
+#include "llvm/MC/MCAsmInfo.h"
+
+namespace llvm {
+
+class MCAsmInfoXCOFF : public MCAsmInfo {
+  virtual void anchor();
+
+protected:
+  MCAsmInfoXCOFF();
+};
+
+} // end namespace llvm
+
+#endif // LLVM_MC_MCASMINFOXCOFF_H
diff --git a/llvm/include/llvm/MC/MCContext.h b/llvm/include/llvm/MC/MCContext.h
index cfe4b9a3143a..5c2124cc0d15 100644
--- a/llvm/include/llvm/MC/MCContext.h
+++ b/llvm/include/llvm/MC/MCContext.h
@@ -18,6 +18,7 @@
 #include "llvm/ADT/StringRef.h"
 #include "llvm/ADT/Twine.h"
 #include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/BinaryFormat/XCOFF.h"
 #include "llvm/MC/MCAsmMacro.h"
 #include "llvm/MC/MCDwarf.h"
 #include "llvm/MC/MCSubtargetInfo.h"
@@ -49,6 +50,7 @@ namespace llvm {
   class MCSectionELF;
   class MCSectionMachO;
   class MCSectionWasm;
+  class MCSectionXCOFF;
   class MCStreamer;
   class MCSymbol;
   class MCSymbolELF;
@@ -91,6 +93,7 @@ namespace llvm {
     SpecificBumpPtrAllocator<MCSectionELF> ELFAllocator;
     SpecificBumpPtrAllocator<MCSectionMachO> MachOAllocator;
     SpecificBumpPtrAllocator<MCSectionWasm> WasmAllocator;
+    SpecificBumpPtrAllocator<MCSectionXCOFF> XCOFFAllocator;
 
     /// Bindings of names to symbols.
     SymbolTable Symbols;
@@ -246,10 +249,25 @@ namespace llvm {
       }
     };
 
+    struct XCOFFSectionKey {
+      std::string SectionName;
+      XCOFF::StorageMappingClass MappingClass;
+
+      XCOFFSectionKey(StringRef SectionName,
+                      XCOFF::StorageMappingClass MappingClass)
+          : SectionName(SectionName), MappingClass(MappingClass) {}
+
+      bool operator<(const XCOFFSectionKey &Other) const {
+        return std::tie(SectionName, MappingClass) <
+               std::tie(Other.SectionName, Other.MappingClass);
+      }
+    };
+
     StringMap<MCSectionMachO *> MachOUniquingMap;
     std::map<ELFSectionKey, MCSectionELF *> ELFUniquingMap;
     std::map<COFFSectionKey, MCSectionCOFF *> COFFUniquingMap;
     std::map<WasmSectionKey, MCSectionWasm *> WasmUniquingMap;
+    std::map<XCOFFSectionKey, MCSectionXCOFF *> XCOFFUniquingMap;
     StringMap<bool> RelSecNames;
 
     SpecificBumpPtrAllocator<MCSubtargetInfo> MCSubtargetAllocator;
@@ -470,6 +488,11 @@ namespace llvm {
                                   const MCSymbolWasm *Group, unsigned UniqueID,
                                   const char *BeginSymName);
 
+    MCSectionXCOFF *getXCOFFSection(StringRef Section,
+                                    XCOFF::StorageMappingClass MappingClass,
+                                    SectionKind K,
+                                    const char *BeginSymName = nullptr);
+
     // Create and save a copy of STI and return a reference to the copy.
     MCSubtargetInfo &getSubtargetCopy(const MCSubtargetInfo &STI);
 
diff --git a/llvm/include/llvm/MC/MCObjectFileInfo.h b/llvm/include/llvm/MC/MCObjectFileInfo.h
index 640b7a48a664..abc87bf27748 100644
--- a/llvm/include/llvm/MC/MCObjectFileInfo.h
+++ b/llvm/include/llvm/MC/MCObjectFileInfo.h
@@ -400,6 +400,7 @@ private:
   void initELFMCObjectFileInfo(const Triple &T, bool Large);
   void initCOFFMCObjectFileInfo(const Triple &T);
   void initWasmMCObjectFileInfo(const Triple &T);
+  void initXCOFFMCObjectFileInfo(const Triple &T);
   MCSection *getDwarfComdatSection(const char *Name, uint64_t Hash) const;
 
 public:
diff --git a/llvm/include/llvm/MC/MCSection.h b/llvm/include/llvm/MC/MCSection.h
index 27490dc89c61..6fad1ec2069c 100644
--- a/llvm/include/llvm/MC/MCSection.h
+++ b/llvm/include/llvm/MC/MCSection.h
@@ -37,7 +37,7 @@ template <> struct ilist_alloc_traits<MCFragment> {
 /// current translation unit.  The MCContext class uniques and creates these.
 class MCSection {
 public:
-  enum SectionVariant { SV_COFF = 0, SV_ELF, SV_MachO, SV_Wasm };
+  enum SectionVariant { SV_COFF = 0, SV_ELF, SV_MachO, SV_Wasm, SV_XCOFF };
 
   /// Express the state of bundle locked groups while emitting code.
   enum BundleLockStateType {
diff --git a/llvm/include/llvm/MC/MCSectionXCOFF.h b/llvm/include/llvm/MC/MCSectionXCOFF.h
new file mode 100644
index 000000000000..2a3f391fd3e2
--- /dev/null
+++ b/llvm/include/llvm/MC/MCSectionXCOFF.h
@@ -0,0 +1,56 @@
+//===- MCSectionXCOFF.h - XCOFF Machine Code Sections -----------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares the MCSectionXCOFF class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_MC_MCSECTIONXCOFF_H
+#define LLVM_MC_MCSECTIONXCOFF_H
+
+#include "llvm/ADT/Twine.h"
+#include "llvm/BinaryFormat/XCOFF.h"
+#include "llvm/MC/MCSection.h"
+
+namespace llvm {
+
+class MCSymbol;
+
+// This class represents an XCOFF `Control Section`, more commonly referred to
+// as a csect. A csect represents the smallest possible unit of data/code which
+// will be relocated as a single block.
+class MCSectionXCOFF final : public MCSection {
+  friend class MCContext;
+
+  StringRef Name;
+  XCOFF::StorageMappingClass MappingClass;
+
+  MCSectionXCOFF(StringRef Section, XCOFF::StorageMappingClass SMC,
+                 SectionKind K, MCSymbol *Begin)
+      : MCSection(SV_XCOFF, K, Begin), Name(Section), MappingClass(SMC) {}
+
+public:
+  ~MCSectionXCOFF();
+
+  static bool classof(const MCSection *S) {
+    return S->getVariant() == SV_XCOFF;
+  }
+
+  StringRef getSectionName() const { return Name; }
+  XCOFF::StorageMappingClass getMappingClass() const { return MappingClass; }
+
+  void PrintSwitchToSection(const MCAsmInfo &MAI, const Triple &T,
+                            raw_ostream &OS,
+                            const MCExpr *Subsection) const override;
+  bool UseCodeAlign() const override;
+  bool isVirtualSection() const override;
+};
+
+} // end namespace llvm
+
+#endif
diff --git a/llvm/include/llvm/MC/MCXCOFFObjectWriter.h b/llvm/include/llvm/MC/MCXCOFFObjectWriter.h
new file mode 100644
index 000000000000..fe4087f70614
--- /dev/null
+++ b/llvm/include/llvm/MC/MCXCOFFObjectWriter.h
@@ -0,0 +1,41 @@
+//===-- llvm/MC/MCXCOFFObjectWriter.h - XCOFF Object Writer ---------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_MC_MCXCOFFOBJECTWRITER_H
+#define LLVM_MC_MCXCOFFOBJECTWRITER_H
+
+#include "llvm/MC/MCObjectWriter.h"
+
+namespace llvm {
+
+class raw_pwrite_stream;
+
+class MCXCOFFObjectTargetWriter : public MCObjectTargetWriter {
+protected:
+  MCXCOFFObjectTargetWriter(bool Is64Bit);
+
+public:
+  ~MCXCOFFObjectTargetWriter() override;
+
+  Triple::ObjectFormatType getFormat() const override { return Triple::XCOFF; }
+  static bool classof(const MCObjectTargetWriter *W) {
+    return W->getFormat() == Triple::XCOFF;
+  }
+  bool is64Bit() const { return Is64Bit; }
+
+private:
+  bool Is64Bit;
+};
+
+std::unique_ptr<MCObjectWriter>
+createXCOFFObjectWriter(std::unique_ptr<MCXCOFFObjectTargetWriter> MOTW,
+                        raw_pwrite_stream &OS);
+
+} // end namespace llvm
+
+#endif // LLVM_MC_MCXCOFFOBJECTWRITER_H
diff --git a/llvm/include/llvm/MC/MCXCOFFStreamer.h b/llvm/include/llvm/MC/MCXCOFFStreamer.h
new file mode 100644
index 000000000000..159ae4818749
--- /dev/null
+++ b/llvm/include/llvm/MC/MCXCOFFStreamer.h
@@ -0,0 +1,33 @@
+//===- MCXCOFFObjectStreamer.h - MCStreamer XCOFF Object File Interface ---===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_MC_MCXCOFFSTREAMER_H
+#define LLVM_MC_MCXCOFFSTREAMER_H
+
+#include "llvm/MC/MCObjectStreamer.h"
+
+namespace llvm {
+
+class MCXCOFFStreamer : public MCObjectStreamer {
+public:
+  MCXCOFFStreamer(MCContext &Context, std::unique_ptr<MCAsmBackend> MAB,
+                  std::unique_ptr<MCObjectWriter> OW,
+                  std::unique_ptr<MCCodeEmitter> Emitter);
+
+  bool EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override;
+  void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
+                        unsigned ByteAlignment) override;
+  void EmitZerofill(MCSection *Section, MCSymbol *Symbol = nullptr,
+                    uint64_t Size = 0, unsigned ByteAlignment = 0,
+                    SMLoc Loc = SMLoc()) override;
+  void EmitInstToData(const MCInst &Inst, const MCSubtargetInfo &) override;
+};
+
+} // end namespace llvm
+
+#endif // LLVM_MC_MCXCOFFSTREAMER_H
diff --git a/llvm/include/llvm/Support/TargetRegistry.h b/llvm/include/llvm/Support/TargetRegistry.h
index 90bfeaad1bf0..bf75650760d0 100644
--- a/llvm/include/llvm/Support/TargetRegistry.h
+++ b/llvm/include/llvm/Support/TargetRegistry.h
@@ -100,6 +100,11 @@ MCStreamer *createWasmStreamer(MCContext &Ctx,
                                std::unique_ptr<MCObjectWriter> &&OW,
                                std::unique_ptr<MCCodeEmitter> &&CE,
                                bool RelaxAll);
+MCStreamer *createXCOFFStreamer(MCContext &Ctx,
+                                std::unique_ptr<MCAsmBackend> &&TAB,
+                                std::unique_ptr<MCObjectWriter> &&OW,
+                                std::unique_ptr<MCCodeEmitter> &&CE,
+                                bool RelaxAll);
 
 MCRelocationInfo *createMCRelocationInfo(const Triple &TT, MCContext &Ctx);
 
@@ -505,7 +510,9 @@ public:
                                std::move(Emitter), RelaxAll);
       break;
     case Triple::XCOFF:
-      report_fatal_error("XCOFF MCObjectStreamer not implemented yet.");
+        S = createXCOFFStreamer(Ctx, std::move(TAB), std::move(OW),
+                                std::move(Emitter), RelaxAll);
+      break;
     }
     if (ObjectTargetStreamerCtorFn)
       ObjectTargetStreamerCtorFn(*S, STI);
diff --git a/llvm/lib/MC/CMakeLists.txt b/llvm/lib/MC/CMakeLists.txt
index ba36d99e8f74..14e965b55fdd 100644
--- a/llvm/lib/MC/CMakeLists.txt
+++ b/llvm/lib/MC/CMakeLists.txt
@@ -7,6 +7,7 @@ add_llvm_library(LLVMMC
   MCAsmInfoDarwin.cpp
   MCAsmInfoELF.cpp
   MCAsmInfoWasm.cpp
+  MCAsmInfoXCOFF.cpp
   MCAsmMacro.cpp
   MCAsmStreamer.cpp
   MCAssembler.cpp
@@ -38,6 +39,7 @@ add_llvm_library(LLVMMC
   MCSectionELF.cpp
   MCSectionMachO.cpp
   MCSectionWasm.cpp
+  MCSectionXCOFF.cpp
   MCStreamer.cpp
   MCSubtargetInfo.cpp
   MCSymbol.cpp
@@ -49,11 +51,14 @@ add_llvm_library(LLVMMC
   MCWin64EH.cpp
   MCWinCOFFStreamer.cpp
   MCWinEH.cpp
+  MCXCOFFObjectTargetWriter.cpp
+  MCXCOFFStreamer.cpp
   MachObjectWriter.cpp
   StringTableBuilder.cpp
   SubtargetFeature.cpp
   WasmObjectWriter.cpp
   WinCOFFObjectWriter.cpp
+  XCOFFObjectWriter.cpp
 
   ADDITIONAL_HEADER_DIRS
   ${LLVM_MAIN_INCLUDE_DIR}/llvm/MC
diff --git a/llvm/lib/MC/MCAsmBackend.cpp b/llvm/lib/MC/MCAsmBackend.cpp
index 912bec919610..9b1102cbe7d1 100644
--- a/llvm/lib/MC/MCAsmBackend.cpp
+++ b/llvm/lib/MC/MCAsmBackend.cpp
@@ -16,6 +16,7 @@
 #include "llvm/MC/MCObjectWriter.h"
 #include "llvm/MC/MCWasmObjectWriter.h"
 #include "llvm/MC/MCWinCOFFObjectWriter.h"
+#include "llvm/MC/MCXCOFFObjectWriter.h"
 #include <cassert>
 #include <cstddef>
 #include <cstdint>
@@ -43,6 +44,9 @@ MCAsmBackend::createObjectWriter(raw_pwrite_stream &OS) const {
   case Triple::Wasm:
     return createWasmObjectWriter(cast<MCWasmObjectTargetWriter>(std::move(TW)),
                                   OS);
+  case Triple::XCOFF:
+    return createXCOFFObjectWriter(
+        cast<MCXCOFFObjectTargetWriter>(std::move(TW)), OS);
   default:
     llvm_unreachable("unexpected object format");
   }
diff --git a/llvm/lib/MC/MCAsmInfoXCOFF.cpp b/llvm/lib/MC/MCAsmInfoXCOFF.cpp
new file mode 100644
index 000000000000..74c21f0c9e6d
--- /dev/null
+++ b/llvm/lib/MC/MCAsmInfoXCOFF.cpp
@@ -0,0 +1,18 @@
+//===- MC/MCAsmInfoXCOFF.cpp - XCOFF asm properties ------------ *- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/MC/MCAsmInfoXCOFF.h"
+
+using namespace llvm;
+
+void MCAsmInfoXCOFF::anchor() {}
+
+MCAsmInfoXCOFF::MCAsmInfoXCOFF() {
+  IsLittleEndian = false;
+  HasDotTypeDotSizeDirective = false;
+}
diff --git a/llvm/lib/MC/MCContext.cpp b/llvm/lib/MC/MCContext.cpp
index 5ec03ee08948..0dc2e2d37caf 100644
--- a/llvm/lib/MC/MCContext.cpp
+++ b/llvm/lib/MC/MCContext.cpp
@@ -26,6 +26,7 @@
 #include "llvm/MC/MCSectionELF.h"
 #include "llvm/MC/MCSectionMachO.h"
 #include "llvm/MC/MCSectionWasm.h"
+#include "llvm/MC/MCSectionXCOFF.h"
 #include "llvm/MC/MCStreamer.h"
 #include "llvm/MC/MCSymbol.h"
 #include "llvm/MC/MCSymbolCOFF.h"
@@ -86,6 +87,7 @@ void MCContext::reset() {
   COFFAllocator.DestroyAll();
   ELFAllocator.DestroyAll();
   MachOAllocator.DestroyAll();
+  XCOFFAllocator.DestroyAll();
 
   MCSubtargetAllocator.DestroyAll();
   UsedNames.clear();
@@ -107,6 +109,7 @@ void MCContext::reset() {
   ELFUniquingMap.clear();
   COFFUniquingMap.clear();
   WasmUniquingMap.clear();
+  XCOFFUniquingMap.clear();
 
   NextID.clear();
   AllowTemporaryLabels = true;
@@ -526,6 +529,38 @@ MCSectionWasm *MCContext::getWasmSection(const Twine &Section, SectionKind Kind,
   return Result;
 }
 
+MCSectionXCOFF *MCContext::getXCOFFSection(StringRef Section,
+                                           XCOFF::StorageMappingClass SMC,
+                                           SectionKind Kind,
+                                           const char *BeginSymName) {
+  // Do the lookup. If we have a hit, return it.
+  auto IterBool = XCOFFUniquingMap.insert(
+      std::make_pair(XCOFFSectionKey{Section.str(), SMC}, nullptr));
+  auto &Entry = *IterBool.first;
+  if (!IterBool.second)
+    return Entry.second;
+
+  // Otherwise, return a new section.
+  StringRef CachedName = Entry.first.SectionName;
+
+  MCSymbol *Begin = nullptr;
+  if (BeginSymName)
+    Begin = createTempSymbol(BeginSymName, false);
+
+  MCSectionXCOFF *Result = new (XCOFFAllocator.Allocate())
+      MCSectionXCOFF(CachedName, SMC, Kind, Begin);
+  Entry.second = Result;
+
+  auto *F = new MCDataFragment();
+  Result->getFragmentList().insert(Result->begin(), F);
+  F->setParent(Result);
+
+  if (Begin)
+    Begin->setFragment(F);
+
+  return Result;
+}
+
 MCSubtargetInfo &MCContext::getSubtargetCopy(const MCSubtargetInfo &STI) {
   return *new (MCSubtargetAllocator.Allocate()) MCSubtargetInfo(STI);
 }
diff --git a/llvm/lib/MC/MCObjectFileInfo.cpp b/llvm/lib/MC/MCObjectFileInfo.cpp
index 0faa236c1539..9f555abe1404 100644
--- a/llvm/lib/MC/MCObjectFileInfo.cpp
+++ b/llvm/lib/MC/MCObjectFileInfo.cpp
@@ -18,6 +18,7 @@
 #include "llvm/MC/MCSectionELF.h"
 #include "llvm/MC/MCSectionMachO.h"
 #include "llvm/MC/MCSectionWasm.h"
+#include "llvm/MC/MCSectionXCOFF.h"
 
 using namespace llvm;
 
@@ -761,6 +762,15 @@ void MCObjectFileInfo::initWasmMCObjectFileInfo(const Triple &T) {
   // TODO: Define more sections.
 }
 
+void MCObjectFileInfo::initXCOFFMCObjectFileInfo(const Triple &T) {
+  // The default csect for program code. Functions without a specified section
+  // get placed into this csect. The choice of csect name is not a property of
+  // the ABI or object file format. For example, the XL compiler uses an unnamed
+  // csect for program code.
+  TextSection = Ctx->getXCOFFSection(
+      ".text", XCOFF::StorageMappingClass::XMC_PR, SectionKind::getText());
+}
+
 void MCObjectFileInfo::InitMCObjectFileInfo(const Triple &TheTriple, bool PIC,
                                             MCContext &ctx,
                                             bool LargeCodeModel) {
@@ -809,8 +819,7 @@ void MCObjectFileInfo::InitMCObjectFileInfo(const Triple &TheTriple, bool PIC,
     break;
   case Triple::XCOFF:
     Env = IsXCOFF;
-    // TODO: Initialize MCObjectFileInfo for XCOFF format when
-    // MCSectionXCOFF is ready.
+    initXCOFFMCObjectFileInfo(TT);
     break;
   case Triple::UnknownObjectFormat:
     report_fatal_error("Cannot initialize MC for unknown object file format.");
diff --git a/llvm/lib/MC/MCSectionXCOFF.cpp b/llvm/lib/MC/MCSectionXCOFF.cpp
new file mode 100644
index 000000000000..d1a637345024
--- /dev/null
+++ b/llvm/lib/MC/MCSectionXCOFF.cpp
@@ -0,0 +1,33 @@
+//===- lib/MC/MCSectionXCOFF.cpp - XCOFF Code Section Representation ------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/MC/MCSectionXCOFF.h"
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCExpr.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+
+MCSectionXCOFF::~MCSectionXCOFF() = default;
+
+void MCSectionXCOFF::PrintSwitchToSection(const MCAsmInfo &MAI, const Triple &T,
+                                          raw_ostream &OS,
+                                          const MCExpr *Subsection) const {
+  if (getKind().isText()) {
+    OS << "\t.csect " << getSectionName() << "["
+       << "PR"
+       << "]" << '\n';
+    return;
+  }
+
+  report_fatal_error("Printing for this SectionKind is unimplemented.");
+}
+
+bool MCSectionXCOFF::UseCodeAlign() const { return getKind().isText(); }
+
+bool MCSectionXCOFF::isVirtualSection() const { return !getKind().isCommon(); }
diff --git a/llvm/lib/MC/MCXCOFFObjectTargetWriter.cpp b/llvm/lib/MC/MCXCOFFObjectTargetWriter.cpp
new file mode 100644
index 000000000000..504e333cb2d4
--- /dev/null
+++ b/llvm/lib/MC/MCXCOFFObjectTargetWriter.cpp
@@ -0,0 +1,16 @@
+//===- MCXCOFFObjectTargetWriter.cpp - XCOFF Target Writer Subclass -------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/MC/MCXCOFFObjectWriter.h"
+
+using namespace llvm;
+
+MCXCOFFObjectTargetWriter::MCXCOFFObjectTargetWriter(bool Is64Bit)
+    : Is64Bit(Is64Bit) {}
+
+MCXCOFFObjectTargetWriter::~MCXCOFFObjectTargetWriter() = default;
diff --git a/llvm/lib/MC/MCXCOFFStreamer.cpp b/llvm/lib/MC/MCXCOFFStreamer.cpp
new file mode 100644
index 000000000000..071de024a3fa
--- /dev/null
+++ b/llvm/lib/MC/MCXCOFFStreamer.cpp
@@ -0,0 +1,59 @@
+//===- lib/MC/MCXCOFFStreamer.cpp - XCOFF Object Output -------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file assembles .s files and emits XCOFF .o object files.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/MC/MCXCOFFStreamer.h"
+#include "llvm/MC/MCAsmBackend.h"
+#include "llvm/MC/MCCodeEmitter.h"
+#include "llvm/MC/MCObjectWriter.h"
+#include "llvm/Support/TargetRegistry.h"
+
+using namespace llvm;
+
+MCXCOFFStreamer::MCXCOFFStreamer(MCContext &Context,
+                                 std::unique_ptr<MCAsmBackend> MAB,
+                                 std::unique_ptr<MCObjectWriter> OW,
+                                 std::unique_ptr<MCCodeEmitter> Emitter)
+    : MCObjectStreamer(Context, std::move(MAB), std::move(OW),
+                       std::move(Emitter)) {}
+
+bool MCXCOFFStreamer::EmitSymbolAttribute(MCSymbol *Symbol,
+                                          MCSymbolAttr Attribute) {
+  report_fatal_error("Symbol attributes not implemented for XCOFF.");
+}
+
+void MCXCOFFStreamer::EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
+                                       unsigned ByteAlignment) {
+  report_fatal_error("Emiting common symbols not implemented for XCOFF.");
+}
+
+void MCXCOFFStreamer::EmitZerofill(MCSection *Section, MCSymbol *Symbol,
+                                   uint64_t Size, unsigned ByteAlignment,
+                                   SMLoc Loc) {
+  report_fatal_error("Zero fill not implemented for XCOFF.");
+}
+
+void MCXCOFFStreamer::EmitInstToData(const MCInst &Inst,
+                                     const MCSubtargetInfo &) {
+  report_fatal_error("Instruction emission not implemented for XCOFF.");
+}
+
+MCStreamer *llvm::createXCOFFStreamer(MCContext &Context,
+                                      std::unique_ptr<MCAsmBackend> &&MAB,
+                                      std::unique_ptr<MCObjectWriter> &&OW,
+                                      std::unique_ptr<MCCodeEmitter> &&CE,
+                                      bool RelaxAll) {
+  MCXCOFFStreamer *S = new MCXCOFFStreamer(Context, std::move(MAB),
+                                           std::move(OW), std::move(CE));
+  if (RelaxAll)
+    S->getAssembler().setRelaxAll(true);
+  return S;
+}
diff --git a/llvm/lib/MC/XCOFFObjectWriter.cpp b/llvm/lib/MC/XCOFFObjectWriter.cpp
new file mode 100644
index 000000000000..ea586d6b527d
--- /dev/null
+++ b/llvm/lib/MC/XCOFFObjectWriter.cpp
@@ -0,0 +1,94 @@
+//===-- lib/MC/XCOFFObjectWriter.cpp - XCOFF file writer ------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements XCOFF object file writer information.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/MC/MCAssembler.h"
+#include "llvm/MC/MCObjectWriter.h"
+#include "llvm/MC/MCValue.h"
+#include "llvm/MC/MCXCOFFObjectWriter.h"
+
+using namespace llvm;
+
+namespace {
+
+class XCOFFObjectWriter : public MCObjectWriter {
+  support::endian::Writer W;
+  std::unique_ptr<MCXCOFFObjectTargetWriter> TargetObjectWriter;
+
+  void executePostLayoutBinding(MCAssembler &, const MCAsmLayout &) override;
+
+  void recordRelocation(MCAssembler &, const MCAsmLayout &, const MCFragment *,
+                        const MCFixup &, MCValue, uint64_t &) override;
+
+  uint64_t writeObject(MCAssembler &, const MCAsmLayout &) override;
+
+public:
+  XCOFFObjectWriter(std::unique_ptr<MCXCOFFObjectTargetWriter> MOTW,
+                    raw_pwrite_stream &OS);
+};
+
+XCOFFObjectWriter::XCOFFObjectWriter(
+    std::unique_ptr<MCXCOFFObjectTargetWriter> MOTW, raw_pwrite_stream &OS)
+    : W(OS, support::big), TargetObjectWriter(std::move(MOTW)) {}
+
+void XCOFFObjectWriter::executePostLayoutBinding(MCAssembler &,
+                                                 const MCAsmLayout &) {
+  // TODO Implement once we have sections and symbols to handle.
+}
+
+void XCOFFObjectWriter::recordRelocation(MCAssembler &, const MCAsmLayout &,
+                                         const MCFragment *, const MCFixup &,
+                                         MCValue, uint64_t &) {
+  report_fatal_error("XCOFF relocations not supported.");
+}
+
+uint64_t XCOFFObjectWriter::writeObject(MCAssembler &Asm, const MCAsmLayout &) {
+  // We always emit a timestamp of 0 for reproducibility, so ensure incremental
+  // linking is not enabled, in case, like with Windows COFF, such a timestamp
+  // is incompatible with incremental linking of XCOFF.
+  if (Asm.isIncrementalLinkerCompatible())
+    report_fatal_error("Incremental linking not supported for XCOFF.");
+
+  if (TargetObjectWriter->is64Bit())
+    report_fatal_error("64-bit XCOFF object files are not supported yet.");
+
+  uint64_t StartOffset = W.OS.tell();
+
+  // TODO FIXME Assign section numbers/finalize sections.
+
+  // TODO FIXME Finalize symbols.
+
+  // Magic.
+  W.write<uint16_t>(0x01df);
+  // Number of sections.
+  W.write<uint16_t>(0);
+  // Timestamp field. For reproducible output we write a 0, which represents no
+  // timestamp.
+  W.write<int32_t>(0);
+  // Byte Offset to the start of the symbol table.
+  W.write<uint32_t>(0);
+  // Number of entries in the symbol table.
+  W.write<int32_t>(0);
+  // Size of the optional header.
+  W.write<uint16_t>(0);
+  // Flags.
+  W.write<uint16_t>(0);
+
+  return W.OS.tell() - StartOffset;
+}
+
+} // end anonymous namespace
+
+std::unique_ptr<MCObjectWriter>
+llvm::createXCOFFObjectWriter(std::unique_ptr<MCXCOFFObjectTargetWriter> MOTW,
+                              raw_pwrite_stream &OS) {
+  return make_unique<XCOFFObjectWriter>(std::move(MOTW), OS);
+}
diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/CMakeLists.txt b/llvm/lib/Target/PowerPC/MCTargetDesc/CMakeLists.txt
index 147e0ef58e61..5a2f60587ea6 100644
--- a/llvm/lib/Target/PowerPC/MCTargetDesc/CMakeLists.txt
+++ b/llvm/lib/Target/PowerPC/MCTargetDesc/CMakeLists.txt
@@ -8,4 +8,5 @@ add_llvm_library(LLVMPowerPCDesc
   PPCPredicates.cpp
   PPCMachObjectWriter.cpp
   PPCELFObjectWriter.cpp
+  PPCXCOFFObjectWriter.cpp
   )
diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp
index ec4eb700563c..8778e916f7e4 100644
--- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp
+++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp
@@ -229,6 +229,17 @@ public:
   Optional<MCFixupKind> getFixupKind(StringRef Name) const override;
 };
 
+class XCOFFPPCAsmBackend : public PPCAsmBackend {
+public:
+  XCOFFPPCAsmBackend(const Target &T, const Triple &TT)
+      : PPCAsmBackend(T, TT) {}
+
+  std::unique_ptr<MCObjectTargetWriter>
+  createObjectTargetWriter() const override {
+    return createPPCXCOFFObjectWriter(TT.isArch64Bit());
+  }
+};
+
 } // end anonymous namespace
 
 Optional<MCFixupKind> ELFPPCAsmBackend::getFixupKind(StringRef Name) const {
@@ -250,5 +261,8 @@ MCAsmBackend *llvm::createPPCAsmBackend(const Target &T,
   if (TT.isOSDarwin())
     return new DarwinPPCAsmBackend(T, TT);
 
+  if (TT.isOSBinFormatXCOFF())
+    return new XCOFFPPCAsmBackend(T, TT);
+
   return new ELFPPCAsmBackend(T, TT);
 }
diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCAsmInfo.cpp b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCAsmInfo.cpp
index b9e35124e794..5f0005ea1d7b 100644
--- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCAsmInfo.cpp
+++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCAsmInfo.cpp
@@ -81,3 +81,9 @@ PPCELFMCAsmInfo::PPCELFMCAsmInfo(bool is64Bit, const Triple& T) {
   UseIntegratedAssembler = true;
 }
 
+void PPCXCOFFMCAsmInfo::anchor() {}
+
+PPCXCOFFMCAsmInfo::PPCXCOFFMCAsmInfo(bool Is64Bit, const Triple &T) {
+  assert(!IsLittleEndian && "Little-endian XCOFF not supported.");
+  CodePointerSize = CalleeSaveStackSlotSize = Is64Bit ? 8 : 4;
+}
diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCAsmInfo.h b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCAsmInfo.h
index 6a10b6eef44b..42cb62ad26a4 100644
--- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCAsmInfo.h
+++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCAsmInfo.h
@@ -6,7 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 //
-// This file contains the declaration of the MCAsmInfoDarwin class.
+// This file contains the declarations of the PowerPC MCAsmInfo classes.
 //
 //===----------------------------------------------------------------------===//
 
@@ -15,6 +15,7 @@
 
 #include "llvm/MC/MCAsmInfoDarwin.h"
 #include "llvm/MC/MCAsmInfoELF.h"
+#include "llvm/MC/MCAsmInfoXCOFF.h"
 
 namespace llvm {
 class Triple;
@@ -33,6 +34,13 @@ public:
   explicit PPCELFMCAsmInfo(bool is64Bit, const Triple &);
 };
 
+class PPCXCOFFMCAsmInfo : public MCAsmInfoXCOFF {
+  virtual void anchor();
+
+public:
+  explicit PPCXCOFFMCAsmInfo(bool is64Bit, const Triple &);
+};
+
 } // namespace llvm
 
 #endif
diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.cpp b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.cpp
index c980d270716d..90c3c8d20edb 100644
--- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.cpp
+++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.cpp
@@ -83,6 +83,8 @@ static MCAsmInfo *createPPCMCAsmInfo(const MCRegisterInfo &MRI,
   MCAsmInfo *MAI;
   if (TheTriple.isOSDarwin())
     MAI = new PPCMCAsmInfoDarwin(isPPC64, TheTriple);
+  else if (TheTriple.isOSBinFormatXCOFF())
+    MAI = new PPCXCOFFMCAsmInfo(isPPC64, TheTriple);
   else
     MAI = new PPCELFMCAsmInfo(isPPC64, TheTriple);
 
@@ -235,6 +237,27 @@ public:
   }
 };
 
+class PPCTargetXCOFFStreamer : public PPCTargetStreamer {
+public:
+  PPCTargetXCOFFStreamer(MCStreamer &S) : PPCTargetStreamer(S) {}
+
+  void emitTCEntry(const MCSymbol &S) override {
+    report_fatal_error("TOC entries not supported yet.");
+  }
+
+  void emitMachine(StringRef CPU) override {
+    llvm_unreachable("Machine pseudo-ops are invalid for XCOFF.");
+  }
+
+  void emitAbiVersion(int AbiVersion) override {
+    llvm_unreachable("ABI-version pseudo-ops are invalid for XCOFF.");
+  }
+
+  void emitLocalEntry(MCSymbolELF *S, const MCExpr *LocalOffset) override {
+    llvm_unreachable("Local-entry pseudo-ops are invalid for XCOFF.");
+  }
+};
+
 } // end anonymous namespace
 
 static MCTargetStreamer *createAsmTargetStreamer(MCStreamer &S,
@@ -249,6 +272,8 @@ createObjectTargetStreamer(MCStreamer &S, const MCSubtargetInfo &STI) {
   const Triple &TT = STI.getTargetTriple();
   if (TT.isOSBinFormatELF())
     return new PPCTargetELFStreamer(S);
+  if (TT.isOSBinFormatXCOFF())
+    return new PPCTargetXCOFFStreamer(S);
   return new PPCTargetMachOStreamer(S);
 }
 
diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.h b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.h
index 4829fedfba7e..74b67bd2e928 100644
--- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.h
+++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.h
@@ -51,6 +51,9 @@ std::unique_ptr<MCObjectTargetWriter> createPPCELFObjectWriter(bool Is64Bit,
 std::unique_ptr<MCObjectTargetWriter>
 createPPCMachObjectWriter(bool Is64Bit, uint32_t CPUType, uint32_t CPUSubtype);
 
+/// Construct a PPC XCOFF object writer.
+std::unique_ptr<MCObjectTargetWriter> createPPCXCOFFObjectWriter(bool Is64Bit);
+
 /// Returns true iff Val consists of one contiguous run of 1s with any number of
 /// 0s on either side.  The 1s are allowed to wrap from LSB to MSB, so
 /// 0x000FFF0, 0x0000FFFF, and 0xFF0000FF are all runs.  0x0F0F0000 is not,
diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCXCOFFObjectWriter.cpp b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCXCOFFObjectWriter.cpp
new file mode 100644
index 000000000000..9c661286d455
--- /dev/null
+++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCXCOFFObjectWriter.cpp
@@ -0,0 +1,29 @@
+//===-- PPCXCOFFObjectWriter.cpp - PowerPC XCOFF Writer -------------------===//
+//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "PPCMCTargetDesc.h"
+#include "llvm/MC/MCXCOFFObjectWriter.h"
+
+using namespace llvm;
+
+namespace {
+class PPCXCOFFObjectWriter : public MCXCOFFObjectTargetWriter {
+
+public:
+  PPCXCOFFObjectWriter(bool Is64Bit);
+};
+} // end anonymous namespace
+
+PPCXCOFFObjectWriter::PPCXCOFFObjectWriter(bool Is64Bit)
+    : MCXCOFFObjectTargetWriter(Is64Bit) {}
+
+std::unique_ptr<MCObjectTargetWriter>
+llvm::createPPCXCOFFObjectWriter(bool Is64Bit) {
+  return llvm::make_unique<PPCXCOFFObjectWriter>(Is64Bit);
+}
diff --git a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
index 0d8c848b5edd..bd87ce06b4fb 100644
--- a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
+++ b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
@@ -158,6 +158,14 @@ public:
   void EmitStartOfAsmFile(Module &M) override;
 };
 
+class PPCAIXAsmPrinter : public PPCAsmPrinter {
+public:
+  PPCAIXAsmPrinter(TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer)
+      : PPCAsmPrinter(TM, std::move(Streamer)) {}
+
+  StringRef getPassName() const override { return "AIX PPC Assembly Printer"; }
+};
+
 } // end anonymous namespace
 
 void PPCAsmPrinter::PrintSymbolOperand(const MachineOperand &MO,
@@ -1644,6 +1652,9 @@ createPPCAsmPrinterPass(TargetMachine &tm,
                         std::unique_ptr<MCStreamer> &&Streamer) {
   if (tm.getTargetTriple().isMacOSX())
     return new PPCDarwinAsmPrinter(tm, std::move(Streamer));
+  if (tm.getTargetTriple().isOSAIX())
+    return new PPCAIXAsmPrinter(tm, std::move(Streamer));
+
   return new PPCLinuxAsmPrinter(tm, std::move(Streamer));
 }
 
diff --git a/llvm/test/CodeGen/PowerPC/aix-xcoff-basic.ll b/llvm/test/CodeGen/PowerPC/aix-xcoff-basic.ll
new file mode 100644
index 000000000000..9d20fd7b1130
--- /dev/null
+++ b/llvm/test/CodeGen/PowerPC/aix-xcoff-basic.ll
@@ -0,0 +1,37 @@
+; RUN: llc -mtriple powerpc-ibm-aix-xcoff -filetype=obj -o %t.o < %s
+; RUN: llvm-readobj --file-headers %t.o | FileCheck %s
+
+; RUN: not llc -mtriple powerpc64-ibm-aix-xcoff -filetype=obj < %s 2>&1 | \
+; RUN: FileCheck --check-prefix=64BIT %s
+
+; RUN: llc -mtriple powerpc-ibm-aix-xcoff < %s | \
+; RUN: FileCheck --check-prefix=ASM %s
+
+; RUN: llc -mtriple powerpc64-ibm-aix-xcoff < %s | \
+; RUN: FileCheck --check-prefix=ASM %s
+
+target datalayout = "E-m:e-p:32:32-i64:64-n32"
+target triple = "powerpc-unknown-aix"
+
+; NOTE: The object file output and the assembly file output do not describe the
+;       same abstract XCOFF content due to the limited amount of functionality
+;       implemented.
+
+; CHECK:      Format: aixcoff-rs6000
+; CHECK-NEXT: Arch: powerpc
+; CHECK-NEXT: AddressSize: 32bit
+; CHECK-NEXT: FileHeader {
+; CHECK-NEXT:   Magic: 0x1DF
+; CHECK-NEXT:   NumberOfSections: 0
+; CHECK-NEXT:   TimeStamp: None (0x0)
+; CHECK-NEXT:   SymbolTableOffset: 0x0
+; CHECK-NEXT:   SymbolTableEntries: 0
+; CHECK-NEXT:   OptionalHeaderSize: 0x0
+; CHECK-NEXT:   Flags: 0x0
+; CHECK-NEXT: }
+
+; 64BIT: LLVM ERROR: 64-bit XCOFF object files are not supported yet.
+
+; The csect does not need to be present, but LLVM's default behavior when
+; emitting asm is to start the file with the .text section.
+; ASM: .csect .text[PR]