[clang] [llvm] [WIP] ABI Lowering Library (PR #140112)

via cfe-commits cfe-commits at lists.llvm.org
Thu May 29 14:13:42 PDT 2025


https://github.com/vortex73 updated https://github.com/llvm/llvm-project/pull/140112

>From 322c1cfb925f3073f3d3b30abe1b2e35ae7745f3 Mon Sep 17 00:00:00 2001
From: Narayan Sreekumar <nsreekumar6 at gmail.com>
Date: Thu, 15 May 2025 23:13:50 +0530
Subject: [PATCH 1/4] [LLVM ABI] The Typesystem

---
 llvm/include/llvm/ABI/Types.h | 121 ++++++++++++++++++++++++++++++++++
 1 file changed, 121 insertions(+)
 create mode 100644 llvm/include/llvm/ABI/Types.h

diff --git a/llvm/include/llvm/ABI/Types.h b/llvm/include/llvm/ABI/Types.h
new file mode 100644
index 0000000000000..443a6c1eab4e7
--- /dev/null
+++ b/llvm/include/llvm/ABI/Types.h
@@ -0,0 +1,121 @@
+#ifndef LLVM_ABI_TYPES_H
+#define LLVM_ABI_TYPES_H
+
+#include <cstdint>
+#include <memory>
+#include <string>
+
+namespace llvm {
+namespace abi {
+
+enum class TypeKind {
+  Void,
+  Integer,
+  Float,
+  Pointer,
+  Array,
+  Vector,
+  Struct,
+  Union,
+  Function
+};
+class Type {
+protected:
+  TypeKind Kind;
+  uint64_t SizeInBits;
+  uint64_t AlignInBits;
+  bool IsExplicitlyAligned;
+
+  Type(TypeKind K, uint64_t Size, uint64_t Align, bool ExplicitAlign = false)
+      : Kind(K), SizeInBits(Size), AlignInBits(Align),
+        IsExplicitlyAligned(ExplicitAlign) {}
+
+public:
+  virtual ~Type() = default;
+
+  TypeKind getKind() const { return Kind; }
+  uint64_t getSizeInBits() const { return SizeInBits; }
+  uint64_t getAlignInBits() const { return AlignInBits; }
+  bool hasExplicitAlignment() const { return IsExplicitlyAligned; }
+
+  void setExplicitAlignment(uint64_t Align) {
+    AlignInBits = Align;
+    IsExplicitlyAligned = true;
+  }
+
+  bool isVoid() const { return Kind == TypeKind::Void; }
+  bool isInteger() const { return Kind == TypeKind::Integer; }
+  bool isFloat() const { return Kind == TypeKind::Float; }
+  bool isPointer() const { return Kind == TypeKind::Pointer; }
+  bool isArray() const { return Kind == TypeKind::Array; }
+  bool isVector() const { return Kind == TypeKind::Vector; }
+  bool isStruct() const { return Kind == TypeKind::Struct; }
+  bool isUnion() const { return Kind == TypeKind::Union; }
+  bool isFunction() const { return Kind == TypeKind::Function; }
+
+  static bool classof(const Type *) { return true; }
+};
+class VoidType : public Type {
+public:
+  VoidType() : Type(TypeKind::Void, 0, 0) {}
+
+  static bool classof(const Type *T) { return T->getKind() == TypeKind::Void; }
+};
+
+class IntegerType : public Type {
+private:
+  bool IsSigned;
+  bool IsAltRepresentation;
+  std::string TypeName;
+
+public:
+  IntegerType(uint64_t BitWidth, uint64_t Align, bool Signed,
+              bool AltRep = false, const std::string &Name = "")
+      : Type(TypeKind::Integer, BitWidth, Align), IsSigned(Signed),
+        IsAltRepresentation(AltRep), TypeName(Name) {}
+
+  bool isSigned() const { return IsSigned; }
+  bool isAltRepresentation() const { return IsAltRepresentation; }
+  const std::string &getTypeName() const { return TypeName; }
+
+  static bool classof(const Type *T) {
+    return T->getKind() == TypeKind::Integer;
+  }
+};
+class FloatType : public Type {
+private:
+  std::string TypeName;
+
+public:
+  FloatType(uint64_t BitWidth, uint64_t Align, const std::string &Name)
+      : Type(TypeKind::Float, BitWidth, Align), TypeName(Name) {}
+
+  const std::string &getTypeName() const { return TypeName; }
+
+  static bool classof(const Type *T) { return T->getKind() == TypeKind::Float; }
+};
+class PointerType : public Type {
+private:
+  std::unique_ptr<Type> PointeeType;
+  bool IsConst;
+  bool IsVolatile;
+
+public:
+  PointerType(std::unique_ptr<Type> Pointee, uint64_t Size, uint64_t Align,
+              bool Const = false, bool Volatile = false)
+      : Type(TypeKind::Pointer, Size, Align), PointeeType(std::move(Pointee)),
+        IsConst(Const), IsVolatile(Volatile) {}
+
+  const Type *getPointeeType() const { return PointeeType.get(); }
+  bool isConst() const { return IsConst; }
+  bool isVolatile() const { return IsVolatile; }
+
+  static bool classof(const Type *T) {
+    return T->getKind() == TypeKind::Pointer;
+  }
+};
+
+} // namespace abi
+} // namespace llvm
+
+#endif

>From 0858b1f327c7a49c2e2825124a8d5cabbd8654fd Mon Sep 17 00:00:00 2001
From: Narayan Sreekumar <nsreekumar6 at gmail.com>
Date: Fri, 23 May 2025 17:53:53 +0530
Subject: [PATCH 2/4] [LLVMABI] API for Creating types

---
 llvm/include/llvm/ABI/Types.h | 244 +++++++++++++++++++++++++++++-----
 1 file changed, 213 insertions(+), 31 deletions(-)

diff --git a/llvm/include/llvm/ABI/Types.h b/llvm/include/llvm/ABI/Types.h
index 443a6c1eab4e7..84cb586832dbd 100644
--- a/llvm/include/llvm/ABI/Types.h
+++ b/llvm/include/llvm/ABI/Types.h
@@ -1,9 +1,9 @@
 #ifndef LLVM_ABI_TYPES_H
 #define LLVM_ABI_TYPES_H
 
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Support/Allocator.h"
 #include <cstdint>
-#include <memory>
-#include <string>
 
 namespace llvm {
 namespace abi {
@@ -19,6 +19,7 @@ enum class TypeKind {
   Union,
   Function
 };
+
 class Type {
 protected:
   TypeKind Kind;
@@ -31,8 +32,6 @@ class Type {
         IsExplicitlyAligned(ExplicitAlign) {}
 
 public:
-  virtual ~Type() = default;
-
   TypeKind getKind() const { return Kind; }
   uint64_t getSizeInBits() const { return SizeInBits; }
   uint64_t getAlignInBits() const { return AlignInBits; }
@@ -52,9 +51,8 @@ class Type {
   bool isStruct() const { return Kind == TypeKind::Struct; }
   bool isUnion() const { return Kind == TypeKind::Union; }
   bool isFunction() const { return Kind == TypeKind::Function; }
-
-  static bool classof(const Type *) { return true; }
 };
+
 class VoidType : public Type {
 public:
   VoidType() : Type(TypeKind::Void, 0, 0) {}
@@ -65,53 +63,237 @@ class VoidType : public Type {
 class IntegerType : public Type {
 private:
   bool IsSigned;
-  bool IsAltRepresentation;
-  std::string TypeName;
 
 public:
-  IntegerType(uint64_t BitWidth, uint64_t Align, bool Signed,
-              bool AltRep = false, const std::string &Name = "")
-      : Type(TypeKind::Integer, BitWidth, Align), IsSigned(Signed),
-        IsAltRepresentation(AltRep), TypeName(Name) {}
+  IntegerType(uint64_t BitWidth, uint64_t Align, bool Signed)
+      : Type(TypeKind::Integer, BitWidth, Align), IsSigned(Signed) {}
 
   bool isSigned() const { return IsSigned; }
-  bool isAltRepresentation() const { return IsAltRepresentation; }
-  const std::string &getTypeName() const { return TypeName; }
 
   static bool classof(const Type *T) {
     return T->getKind() == TypeKind::Integer;
   }
 };
+
 class FloatType : public Type {
+public:
+  FloatType(uint64_t BitWidth, uint64_t Align)
+      : Type(TypeKind::Float, BitWidth, Align) {}
+
+  static bool classof(const Type *T) { return T->getKind() == TypeKind::Float; }
+};
+
+class PointerType : public Type {
+public:
+  PointerType(uint64_t Size, uint64_t Align)
+      : Type(TypeKind::Pointer, Size, Align) {}
+
+  static bool classof(const Type *T) {
+    return T->getKind() == TypeKind::Pointer;
+  }
+};
+
+class ArrayType : public Type {
 private:
-  std::string TypeName;
+  const Type *ElementType;
+  uint64_t NumElements;
 
 public:
-  FloatType(uint64_t BitWidth, uint64_t Align, const std::string &Name)
-      : Type(TypeKind::Float, BitWidth, Align), TypeName(Name) {}
+  ArrayType(const Type *ElemType, uint64_t NumElems)
+      : Type(TypeKind::Array, ElemType->getSizeInBits() * NumElems,
+             ElemType->getAlignInBits()),
+        ElementType(ElemType), NumElements(NumElems) {}
 
-  const std::string &getTypeName() const { return TypeName; }
+  const Type *getElementType() const { return ElementType; }
+  uint64_t getNumElements() const { return NumElements; }
 
-  static bool classof(const Type *T) { return T->getKind() == TypeKind::Float; }
+  static bool classof(const Type *T) { return T->getKind() == TypeKind::Array; }
 };
-class PointerType : public Type {
+
+class VectorType : public Type {
 private:
-  std::unique_ptr<Type> PointeeType;
-  bool IsConst;
-  bool IsVolatile;
+  const Type *ElementType;
+  uint64_t NumElements;
 
 public:
-  PointerType(std::unique_ptr<Type> Pointee, uint64_t Size, uint64_t Align,
-              bool Const = false, bool Volatile = false)
-      : Type(TypeKind::Pointer, Size, Align), PointeeType(std::move(Pointee)),
-        IsConst(Const), IsVolatile(Volatile) {}
+  VectorType(const Type *ElemType, uint64_t NumElems, uint64_t Align)
+      : Type(TypeKind::Vector, ElemType->getSizeInBits() * NumElems, Align),
+        ElementType(ElemType), NumElements(NumElems) {}
 
-  const Type *getPointeeType() const { return PointeeType.get(); }
-  bool isConst() const { return IsConst; }
-  bool isVolatile() const { return IsVolatile; }
+  const Type *getElementType() const { return ElementType; }
+  uint64_t getNumElements() const { return NumElements; }
 
   static bool classof(const Type *T) {
-    return T->getKind() == TypeKind::Pointer;
+    return T->getKind() == TypeKind::Vector;
+  }
+};
+
+struct FieldInfo {
+  const Type *FieldType;
+  uint64_t OffsetInBits;
+  bool IsBitField;
+  uint64_t BitFieldWidth;
+
+  FieldInfo(const Type *Type, uint64_t Offset = 0, bool BitField = false,
+            uint64_t BFWidth = 0)
+      : FieldType(Type), OffsetInBits(Offset), IsBitField(BitField),
+        BitFieldWidth(BFWidth) {}
+};
+
+enum class StructPacking { Default, Packed, ExplicitPacking };
+
+class StructType : public Type {
+private:
+  const FieldInfo *Fields;
+  uint32_t NumFields;
+  StructPacking Packing;
+
+public:
+  StructType(const FieldInfo *StructFields, uint32_t FieldCount, uint64_t Size,
+             uint64_t Align, StructPacking Pack = StructPacking::Default)
+      : Type(TypeKind::Struct, Size, Align), Fields(StructFields),
+        NumFields(FieldCount), Packing(Pack) {}
+
+  const FieldInfo *getFields() const { return Fields; }
+  uint32_t getNumFields() const { return NumFields; }
+  StructPacking getPacking() const { return Packing; }
+
+  static bool classof(const Type *T) {
+    return T->getKind() == TypeKind::Struct;
+  }
+};
+
+class UnionType : public Type {
+private:
+  const FieldInfo *Fields;
+  uint32_t NumFields;
+  StructPacking Packing;
+
+public:
+  UnionType(const FieldInfo *UnionFields, uint32_t FieldCount, uint64_t Size,
+            uint64_t Align, StructPacking Pack = StructPacking::Default)
+      : Type(TypeKind::Union, Size, Align), Fields(UnionFields),
+        NumFields(FieldCount), Packing(Pack) {}
+
+  const FieldInfo *getFields() const { return Fields; }
+  uint32_t getNumFields() const { return NumFields; }
+  StructPacking getPacking() const { return Packing; }
+
+  static bool classof(const Type *T) { return T->getKind() == TypeKind::Union; }
+};
+
+enum class CallConv {
+  C,
+  // TODO: extend for more CallConvs
+};
+
+class FunctionType : public Type {
+private:
+  const Type *ReturnType;
+  const Type *const *ParameterTypes;
+  uint32_t NumParams;
+  bool IsVarArg;
+  CallConv CC;
+
+public:
+  FunctionType(const Type *RetType, const Type *const *ParamTypes,
+               uint32_t ParamCount, bool VarArgs, CallConv CallConv)
+      : Type(TypeKind::Function, 0, 0), ReturnType(RetType),
+        ParameterTypes(ParamTypes), NumParams(ParamCount), IsVarArg(VarArgs),
+        CC(CallConv) {}
+
+  const Type *getReturnType() const { return ReturnType; }
+  const Type *const *getParameterTypes() const { return ParameterTypes; }
+  uint32_t getNumParameters() const { return NumParams; }
+  const Type *getParameterType(uint32_t Index) const {
+    assert(Index < NumParams && "Parameter index out of bounds");
+    return ParameterTypes[Index];
+  }
+  bool isVarArg() const { return IsVarArg; }
+  CallConv getCallingConv() const { return CC; }
+
+  static bool classof(const Type *T) {
+    return T->getKind() == TypeKind::Function;
+  }
+};
+
+// API for creating ABI Types
+class TypeBuilder {
+private:
+  BumpPtrAllocator &Allocator;
+
+public:
+  explicit TypeBuilder(BumpPtrAllocator &Alloc) : Allocator(Alloc) {}
+
+  const VoidType *getVoidType() {
+    return new (Allocator.Allocate<VoidType>()) VoidType();
+  }
+
+  const IntegerType *getIntegerType(uint64_t BitWidth, uint64_t Align,
+                                    bool Signed) {
+    return new (Allocator.Allocate<IntegerType>())
+        IntegerType(BitWidth, Align, Signed);
+  }
+
+  const FloatType *getFloatType(uint64_t BitWidth, uint64_t Align) {
+    return new (Allocator.Allocate<FloatType>()) FloatType(BitWidth, Align);
+  }
+
+  const PointerType *getPointerType(uint64_t Size, uint64_t Align) {
+    return new (Allocator.Allocate<PointerType>()) PointerType(Size, Align);
+  }
+
+  const ArrayType *getArrayType(const Type *ElementType, uint64_t NumElements) {
+    return new (Allocator.Allocate<ArrayType>())
+        ArrayType(ElementType, NumElements);
+  }
+
+  const VectorType *getVectorType(const Type *ElementType, uint64_t NumElements,
+                                  uint64_t Align) {
+    return new (Allocator.Allocate<VectorType>())
+        VectorType(ElementType, NumElements, Align);
+  }
+
+  const StructType *getStructType(ArrayRef<FieldInfo> Fields, uint64_t Size,
+                                  uint64_t Align,
+                                  StructPacking Pack = StructPacking::Default) {
+    FieldInfo *FieldArray = Allocator.Allocate<FieldInfo>(Fields.size());
+
+    for (size_t I = 0; I < Fields.size(); ++I) {
+      new (&FieldArray[I]) FieldInfo(Fields[I]);
+    }
+
+    return new (Allocator.Allocate<StructType>()) StructType(
+        FieldArray, static_cast<uint32_t>(Fields.size()), Size, Align, Pack);
+  }
+
+  const UnionType *getUnionType(ArrayRef<FieldInfo> Fields, uint64_t Size,
+                                uint64_t Align,
+                                StructPacking Pack = StructPacking::Default) {
+    FieldInfo *FieldArray = Allocator.Allocate<FieldInfo>(Fields.size());
+
+    for (size_t I = 0; I < Fields.size(); ++I) {
+      new (&FieldArray[I]) FieldInfo(Fields[I]);
+    }
+
+    return new (Allocator.Allocate<UnionType>()) UnionType(
+        FieldArray, static_cast<uint32_t>(Fields.size()), Size, Align, Pack);
+  }
+
+  const FunctionType *getFunctionType(const Type *ReturnType,
+                                      ArrayRef<const Type *> ParamTypes,
+                                      bool IsVarArg,
+                                      CallConv CC = CallConv::C) {
+    const Type **ParamArray =
+        Allocator.Allocate<const Type *>(ParamTypes.size());
+
+    for (size_t I = 0; I < ParamTypes.size(); ++I) {
+      ParamArray[I] = ParamTypes[I];
+    }
+
+    return new (Allocator.Allocate<FunctionType>())
+        FunctionType(ReturnType, ParamArray,
+                     static_cast<uint32_t>(ParamTypes.size()), IsVarArg, CC);
   }
 };
 

>From 114cab7c06c080bf9661c31f405b39b2a8575d6d Mon Sep 17 00:00:00 2001
From: Narayan Sreekumar <nsreekumar6 at gmail.com>
Date: Tue, 27 May 2025 03:07:20 +0530
Subject: [PATCH 3/4] [LLVMABI] Mapper Interface

---
 llvm/include/llvm/ABI/QualTypeMapper.h |  52 +++++++++++
 llvm/include/llvm/ABI/Types.h          | 117 ++++++++-----------------
 llvm/lib/ABI/CMakeLists.txt            |  17 ++++
 llvm/lib/ABI/QualTypeMapper.cpp        |  16 ++++
 llvm/lib/CMakeLists.txt                |   1 +
 5 files changed, 123 insertions(+), 80 deletions(-)
 create mode 100644 llvm/include/llvm/ABI/QualTypeMapper.h
 create mode 100644 llvm/lib/ABI/CMakeLists.txt
 create mode 100644 llvm/lib/ABI/QualTypeMapper.cpp

diff --git a/llvm/include/llvm/ABI/QualTypeMapper.h b/llvm/include/llvm/ABI/QualTypeMapper.h
new file mode 100644
index 0000000000000..f408325dad007
--- /dev/null
+++ b/llvm/include/llvm/ABI/QualTypeMapper.h
@@ -0,0 +1,52 @@
+#ifndef LLVM_ABI_QUALTYPE_MAPPER_H
+#define LLVM_ABI_QUALTYPE_MAPPER_H
+
+#include "llvm/Support/Allocator.h"
+#include <clang/AST/ASTContext.h>
+#include <clang/AST/Type.h>
+#include <llvm/ABI/Types.h>
+#include <llvm/ADT/DenseMap.h>
+
+namespace llvm {
+namespace abi {
+
+class QualTypeMapper {
+private:
+  clang::ASTContext &ASTCtx;
+  TypeBuilder Builder;
+
+  // llvm::DenseMap<clang::QualType	, const Type*> TypeCache;
+
+  const Type *convertBuiltinType(const clang::BuiltinType *BT);
+  const Type *convertPointerType(const clang::PointerType *PT);
+  const Type *convertArrayType(const clang::ArrayType *AT);
+  const Type *convertVectorType(const clang::VectorType *VT);
+  const Type *convertRecordType(const clang::RecordType *RT);
+  const Type *convertFunctionType(const clang::FunctionProtoType *FT);
+  const Type *convertEnumType(const clang::EnumType *ET);
+
+  void computeRecordLayout(const clang::RecordDecl *RD,
+                           llvm::SmallVectorImpl<FieldInfo> &Fields,
+                           uint64_t &TotalSize, uint64_t &Alignment,
+                           StructPacking &Packing);
+
+  uint64_t getTypeSize(clang::QualType QT) const;
+  uint64_t getTypeAlign(clang::QualType QT) const;
+  uint64_t getPointerSize() const;
+  uint64_t getPointerAlign() const;
+
+public:
+  explicit QualTypeMapper(clang::ASTContext &Ctx, BumpPtrAllocator &Alloc)
+      : ASTCtx(Ctx), Builder(Alloc) {}
+
+  const Type *convertType(clang::QualType QT);
+
+  // void clearCache() {TypeCache.clear();}
+
+  TypeBuilder getTypeBuilder() { return Builder; }
+};
+
+} // namespace abi
+} // namespace llvm
+
+#endif // !LLVM_ABI_QUALTYPE_MAPPER_H
diff --git a/llvm/include/llvm/ABI/Types.h b/llvm/include/llvm/ABI/Types.h
index 84cb586832dbd..e99bee35acf77 100644
--- a/llvm/include/llvm/ABI/Types.h
+++ b/llvm/include/llvm/ABI/Types.h
@@ -1,9 +1,13 @@
 #ifndef LLVM_ABI_TYPES_H
 #define LLVM_ABI_TYPES_H
 
+#include "llvm/ADT/APFloat.h"
 #include "llvm/ADT/ArrayRef.h"
+#include "llvm/Support/Alignment.h"
 #include "llvm/Support/Allocator.h"
+#include "llvm/Support/TypeSize.h"
 #include <cstdint>
+#include <llvm/IR/CallingConv.h>
 
 namespace llvm {
 namespace abi {
@@ -17,27 +21,26 @@ enum class TypeKind {
   Vector,
   Struct,
   Union,
-  Function
 };
 
 class Type {
 protected:
   TypeKind Kind;
-  uint64_t SizeInBits;
-  uint64_t AlignInBits;
+  TypeSize SizeInBits;
+  Align AlignInBits;
   bool IsExplicitlyAligned;
 
-  Type(TypeKind K, uint64_t Size, uint64_t Align, bool ExplicitAlign = false)
+  Type(TypeKind K, TypeSize Size, Align Align, bool ExplicitAlign = false)
       : Kind(K), SizeInBits(Size), AlignInBits(Align),
         IsExplicitlyAligned(ExplicitAlign) {}
 
 public:
   TypeKind getKind() const { return Kind; }
-  uint64_t getSizeInBits() const { return SizeInBits; }
-  uint64_t getAlignInBits() const { return AlignInBits; }
+  TypeSize getSizeInBits() const { return SizeInBits; }
+  Align getAlignInBits() const { return AlignInBits; }
   bool hasExplicitAlignment() const { return IsExplicitlyAligned; }
 
-  void setExplicitAlignment(uint64_t Align) {
+  void setExplicitAlignment(Align Align) {
     AlignInBits = Align;
     IsExplicitlyAligned = true;
   }
@@ -50,12 +53,11 @@ class Type {
   bool isVector() const { return Kind == TypeKind::Vector; }
   bool isStruct() const { return Kind == TypeKind::Struct; }
   bool isUnion() const { return Kind == TypeKind::Union; }
-  bool isFunction() const { return Kind == TypeKind::Function; }
 };
 
 class VoidType : public Type {
 public:
-  VoidType() : Type(TypeKind::Void, 0, 0) {}
+  VoidType() : Type(TypeKind::Void, TypeSize::getFixed(0), Align(1)) {}
 
   static bool classof(const Type *T) { return T->getKind() == TypeKind::Void; }
 };
@@ -65,8 +67,9 @@ class IntegerType : public Type {
   bool IsSigned;
 
 public:
-  IntegerType(uint64_t BitWidth, uint64_t Align, bool Signed)
-      : Type(TypeKind::Integer, BitWidth, Align), IsSigned(Signed) {}
+  IntegerType(uint64_t BitWidth, Align Align, bool Signed)
+      : Type(TypeKind::Integer, TypeSize::getFixed(BitWidth), Align),
+        IsSigned(Signed) {}
 
   bool isSigned() const { return IsSigned; }
 
@@ -76,17 +79,22 @@ class IntegerType : public Type {
 };
 
 class FloatType : public Type {
+private:
+  const fltSemantics *Semantics;
+
 public:
-  FloatType(uint64_t BitWidth, uint64_t Align)
-      : Type(TypeKind::Float, BitWidth, Align) {}
+  FloatType(const fltSemantics &FloatSemantics, Align Align)
+      : Type(TypeKind::Float,
+             TypeSize::getFixed(APFloat::getSizeInBits(FloatSemantics)), Align),
+        Semantics(&FloatSemantics) {}
 
   static bool classof(const Type *T) { return T->getKind() == TypeKind::Float; }
 };
 
 class PointerType : public Type {
 public:
-  PointerType(uint64_t Size, uint64_t Align)
-      : Type(TypeKind::Pointer, Size, Align) {}
+  PointerType(uint64_t Size, Align Align)
+      : Type(TypeKind::Pointer, TypeSize::getFixed(Size), Align) {}
 
   static bool classof(const Type *T) {
     return T->getKind() == TypeKind::Pointer;
@@ -116,7 +124,7 @@ class VectorType : public Type {
   uint64_t NumElements;
 
 public:
-  VectorType(const Type *ElemType, uint64_t NumElems, uint64_t Align)
+  VectorType(const Type *ElemType, uint64_t NumElems, Align Align)
       : Type(TypeKind::Vector, ElemType->getSizeInBits() * NumElems, Align),
         ElementType(ElemType), NumElements(NumElems) {}
 
@@ -149,8 +157,8 @@ class StructType : public Type {
   StructPacking Packing;
 
 public:
-  StructType(const FieldInfo *StructFields, uint32_t FieldCount, uint64_t Size,
-             uint64_t Align, StructPacking Pack = StructPacking::Default)
+  StructType(const FieldInfo *StructFields, uint32_t FieldCount, TypeSize Size,
+             Align Align, StructPacking Pack = StructPacking::Default)
       : Type(TypeKind::Struct, Size, Align), Fields(StructFields),
         NumFields(FieldCount), Packing(Pack) {}
 
@@ -170,8 +178,8 @@ class UnionType : public Type {
   StructPacking Packing;
 
 public:
-  UnionType(const FieldInfo *UnionFields, uint32_t FieldCount, uint64_t Size,
-            uint64_t Align, StructPacking Pack = StructPacking::Default)
+  UnionType(const FieldInfo *UnionFields, uint32_t FieldCount, TypeSize Size,
+            Align Align, StructPacking Pack = StructPacking::Default)
       : Type(TypeKind::Union, Size, Align), Fields(UnionFields),
         NumFields(FieldCount), Packing(Pack) {}
 
@@ -182,41 +190,6 @@ class UnionType : public Type {
   static bool classof(const Type *T) { return T->getKind() == TypeKind::Union; }
 };
 
-enum class CallConv {
-  C,
-  // TODO: extend for more CallConvs
-};
-
-class FunctionType : public Type {
-private:
-  const Type *ReturnType;
-  const Type *const *ParameterTypes;
-  uint32_t NumParams;
-  bool IsVarArg;
-  CallConv CC;
-
-public:
-  FunctionType(const Type *RetType, const Type *const *ParamTypes,
-               uint32_t ParamCount, bool VarArgs, CallConv CallConv)
-      : Type(TypeKind::Function, 0, 0), ReturnType(RetType),
-        ParameterTypes(ParamTypes), NumParams(ParamCount), IsVarArg(VarArgs),
-        CC(CallConv) {}
-
-  const Type *getReturnType() const { return ReturnType; }
-  const Type *const *getParameterTypes() const { return ParameterTypes; }
-  uint32_t getNumParameters() const { return NumParams; }
-  const Type *getParameterType(uint32_t Index) const {
-    assert(Index < NumParams && "Parameter index out of bounds");
-    return ParameterTypes[Index];
-  }
-  bool isVarArg() const { return IsVarArg; }
-  CallConv getCallingConv() const { return CC; }
-
-  static bool classof(const Type *T) {
-    return T->getKind() == TypeKind::Function;
-  }
-};
-
 // API for creating ABI Types
 class TypeBuilder {
 private:
@@ -229,17 +202,17 @@ class TypeBuilder {
     return new (Allocator.Allocate<VoidType>()) VoidType();
   }
 
-  const IntegerType *getIntegerType(uint64_t BitWidth, uint64_t Align,
+  const IntegerType *getIntegerType(uint64_t BitWidth, Align Align,
                                     bool Signed) {
     return new (Allocator.Allocate<IntegerType>())
         IntegerType(BitWidth, Align, Signed);
   }
 
-  const FloatType *getFloatType(uint64_t BitWidth, uint64_t Align) {
-    return new (Allocator.Allocate<FloatType>()) FloatType(BitWidth, Align);
+  const FloatType *getFloatType(const fltSemantics &Semantics, Align Align) {
+    return new (Allocator.Allocate<FloatType>()) FloatType(Semantics, Align);
   }
 
-  const PointerType *getPointerType(uint64_t Size, uint64_t Align) {
+  const PointerType *getPointerType(uint64_t Size, Align Align) {
     return new (Allocator.Allocate<PointerType>()) PointerType(Size, Align);
   }
 
@@ -249,13 +222,13 @@ class TypeBuilder {
   }
 
   const VectorType *getVectorType(const Type *ElementType, uint64_t NumElements,
-                                  uint64_t Align) {
+                                  Align Align) {
     return new (Allocator.Allocate<VectorType>())
         VectorType(ElementType, NumElements, Align);
   }
 
-  const StructType *getStructType(ArrayRef<FieldInfo> Fields, uint64_t Size,
-                                  uint64_t Align,
+  const StructType *getStructType(ArrayRef<FieldInfo> Fields, TypeSize Size,
+                                  Align Align,
                                   StructPacking Pack = StructPacking::Default) {
     FieldInfo *FieldArray = Allocator.Allocate<FieldInfo>(Fields.size());
 
@@ -267,8 +240,8 @@ class TypeBuilder {
         FieldArray, static_cast<uint32_t>(Fields.size()), Size, Align, Pack);
   }
 
-  const UnionType *getUnionType(ArrayRef<FieldInfo> Fields, uint64_t Size,
-                                uint64_t Align,
+  const UnionType *getUnionType(ArrayRef<FieldInfo> Fields, TypeSize Size,
+                                Align Align,
                                 StructPacking Pack = StructPacking::Default) {
     FieldInfo *FieldArray = Allocator.Allocate<FieldInfo>(Fields.size());
 
@@ -279,22 +252,6 @@ class TypeBuilder {
     return new (Allocator.Allocate<UnionType>()) UnionType(
         FieldArray, static_cast<uint32_t>(Fields.size()), Size, Align, Pack);
   }
-
-  const FunctionType *getFunctionType(const Type *ReturnType,
-                                      ArrayRef<const Type *> ParamTypes,
-                                      bool IsVarArg,
-                                      CallConv CC = CallConv::C) {
-    const Type **ParamArray =
-        Allocator.Allocate<const Type *>(ParamTypes.size());
-
-    for (size_t I = 0; I < ParamTypes.size(); ++I) {
-      ParamArray[I] = ParamTypes[I];
-    }
-
-    return new (Allocator.Allocate<FunctionType>())
-        FunctionType(ReturnType, ParamArray,
-                     static_cast<uint32_t>(ParamTypes.size()), IsVarArg, CC);
-  }
 };
 
 } // namespace abi
diff --git a/llvm/lib/ABI/CMakeLists.txt b/llvm/lib/ABI/CMakeLists.txt
new file mode 100644
index 0000000000000..d6aa9b542cc05
--- /dev/null
+++ b/llvm/lib/ABI/CMakeLists.txt
@@ -0,0 +1,17 @@
+add_llvm_component_library(LLVMABI
+  QualTypeMapper.cpp
+
+  ADDITIONAL_HEADER_DIRS
+  ${LLVM_MAIN_INCLUDE_DIR}/llvm/ABI
+
+  DEPENDS
+  intrinsics_gen
+
+  LINK_COMPONENTS
+  Core
+  Support
+)
+
+target_include_directories(LLVMABI PRIVATE
+  ${LLVM_MAIN_INCLUDE_DIR}
+)
diff --git a/llvm/lib/ABI/QualTypeMapper.cpp b/llvm/lib/ABI/QualTypeMapper.cpp
new file mode 100644
index 0000000000000..fcf3555aaf369
--- /dev/null
+++ b/llvm/lib/ABI/QualTypeMapper.cpp
@@ -0,0 +1,16 @@
+//===-- llvm/ABI/QualTypeMapper.cpp - QualType to ABI Mapping -------------===//
+//
+// 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 contains the logic for converting clang::Qualtype to
+// llvm::abi::Type for ABI Lowering
+//
+//===----------------------------------------------------------------------===//
+
+#include <llvm/ABI/QualTypeMapper.h>
+
+// TODO: Implementation of Qualtype -> abi::Type Mapping
diff --git a/llvm/lib/CMakeLists.txt b/llvm/lib/CMakeLists.txt
index f6465612d30c0..b888f6637a925 100644
--- a/llvm/lib/CMakeLists.txt
+++ b/llvm/lib/CMakeLists.txt
@@ -3,6 +3,7 @@ include(LLVM-Build)
 # `Demangle', `Support' and `TableGen' libraries are added on the top-level
 # CMakeLists.txt
 
+add_subdirectory(ABI)
 add_subdirectory(IR)
 add_subdirectory(FuzzMutate)
 add_subdirectory(FileCheck)

>From dc0ff9f2376b9c0fa2a5f0d0792585579278a7eb Mon Sep 17 00:00:00 2001
From: Narayan Sreekumar <nsreekumar6 at gmail.com>
Date: Fri, 30 May 2025 02:36:05 +0530
Subject: [PATCH 4/4] [LLVMABI] QualType Mapper Implementation

---
 clang/include/clang/ABI/QualTypeMapper.h      |   78 ++
 clang/lib/ABI/CMakeLists.txt                  |    9 +
 clang/lib/ABI/QualTypeMapper.cpp              |  209 ++++
 clang/lib/CMakeLists.txt                      |    1 +
 debug.log                                     |    2 +
 llvm/docs/GitHubMove.rst                      | 1086 +++++++++++++++++
 llvm/docs/VariableNames.rst                   |  399 ++++++
 llvm/include/llvm/ABI/QualTypeMapper.h        |   52 -
 llvm/lib/ABI/CMakeLists.txt                   |   17 -
 llvm/lib/ABI/QualTypeMapper.cpp               |   16 -
 llvm/lib/CMakeLists.txt                       |    2 +-
 .../test/Transforms/InstCombine/pblend_opt.ll |   18 +
 output.ll                                     |   39 +
 13 files changed, 1842 insertions(+), 86 deletions(-)
 create mode 100644 clang/include/clang/ABI/QualTypeMapper.h
 create mode 100644 clang/lib/ABI/CMakeLists.txt
 create mode 100644 clang/lib/ABI/QualTypeMapper.cpp
 create mode 100644 debug.log
 create mode 100644 llvm/docs/GitHubMove.rst
 create mode 100644 llvm/docs/VariableNames.rst
 delete mode 100644 llvm/include/llvm/ABI/QualTypeMapper.h
 delete mode 100644 llvm/lib/ABI/CMakeLists.txt
 delete mode 100644 llvm/lib/ABI/QualTypeMapper.cpp
 create mode 100644 llvm/test/Transforms/InstCombine/pblend_opt.ll
 create mode 100644 output.ll

diff --git a/clang/include/clang/ABI/QualTypeMapper.h b/clang/include/clang/ABI/QualTypeMapper.h
new file mode 100644
index 0000000000000..70ae9e0f83130
--- /dev/null
+++ b/clang/include/clang/ABI/QualTypeMapper.h
@@ -0,0 +1,78 @@
+#ifndef LLVM_ABI_QUALTYPE_MAPPER_H
+#define LLVM_ABI_QUALTYPE_MAPPER_H
+
+#include "llvm/IR/DerivedTypes.h"
+#include "llvm/Support/Allocator.h"
+#include <clang/AST/ASTContext.h>
+#include <clang/AST/Decl.h>
+#include <clang/AST/Type.h>
+#include <llvm/ABI/Types.h>
+#include <llvm/ADT/DenseMap.h>
+
+// Specialization for QualType
+template <> struct llvm::DenseMapInfo<clang::QualType> {
+  static inline clang::QualType getEmptyKey() {
+    return clang::QualType::getFromOpaquePtr(
+        reinterpret_cast<clang::Type *>(-1));
+  }
+
+  static inline clang::QualType getTombstoneKey() {
+    return clang::QualType::getFromOpaquePtr(
+        reinterpret_cast<clang::Type *>(-2));
+  }
+
+  static unsigned getHashValue(const clang::QualType &Val) {
+    return (unsigned)((uintptr_t)Val.getAsOpaquePtr()) ^
+           ((unsigned)((uintptr_t)Val.getAsOpaquePtr() >> 9));
+  }
+
+  static bool isEqual(const clang::QualType &LHS, const clang::QualType &RHS) {
+    return LHS == RHS;
+  }
+};
+
+namespace clang {
+namespace mapper {
+
+class QualTypeMapper {
+private:
+  clang::ASTContext &ASTCtx;
+  llvm::abi::TypeBuilder Builder;
+
+  llvm::DenseMap<clang::QualType, const llvm::abi::Type *> TypeCache;
+
+  const llvm::abi::Type *convertBuiltinType(const clang::BuiltinType *BT);
+  const llvm::abi::Type *convertPointerType(const clang::PointerType *PT);
+  const llvm::abi::Type *convertArrayType(const clang::ArrayType *AT);
+  const llvm::abi::Type *convertVectorType(const clang::VectorType *VT);
+  const llvm::abi::Type *convertRecordType(const clang::RecordType *RT);
+  const llvm::abi::Type *convertEnumType(const clang::EnumType *ET);
+
+  const llvm::abi::StructType *convertStructType(const clang::RecordDecl *RD);
+  const llvm::abi::UnionType *convertUnionType(const clang::RecordDecl *RD);
+  const llvm::abi::Type *createPointerTypeForPointee(QualType PointeeType);
+
+  void computeFieldInfo(const clang::RecordDecl *RD,
+                        SmallVectorImpl<llvm::abi::FieldInfo> &Fields,
+                        const clang::ASTRecordLayout &Layout);
+
+  llvm::TypeSize getTypeSize(clang::QualType QT) const;
+  llvm::Align getTypeAlign(clang::QualType QT) const;
+  uint64_t getPointerSize() const;
+  uint64_t getPointerAlign() const;
+
+public:
+  explicit QualTypeMapper(clang::ASTContext &Ctx, llvm::BumpPtrAllocator &Alloc)
+      : ASTCtx(Ctx), Builder(Alloc) {}
+
+  const llvm::abi::Type *convertType(clang::QualType QT);
+
+  void clearCache() { TypeCache.clear(); }
+
+  llvm::abi::TypeBuilder getTypeBuilder() { return Builder; }
+};
+
+} // namespace mapper
+} // namespace clang
+
+#endif // !LLVM_ABI_QUALTYPE_MAPPER_H
diff --git a/clang/lib/ABI/CMakeLists.txt b/clang/lib/ABI/CMakeLists.txt
new file mode 100644
index 0000000000000..86a8324b5716a
--- /dev/null
+++ b/clang/lib/ABI/CMakeLists.txt
@@ -0,0 +1,9 @@
+add_clang_library(clangABI
+  QualTypeMapper.cpp
+
+  LINK_LIBS
+  clangAST
+  clangBasic
+  LLVMABI
+  LLVMSupport
+)
diff --git a/clang/lib/ABI/QualTypeMapper.cpp b/clang/lib/ABI/QualTypeMapper.cpp
new file mode 100644
index 0000000000000..22070f250026e
--- /dev/null
+++ b/clang/lib/ABI/QualTypeMapper.cpp
@@ -0,0 +1,209 @@
+#include "clang/AST/RecordLayout.h"
+#include "clang/AST/Type.h"
+#include "clang/Analysis/Analyses/ThreadSafetyTIL.h"
+#include "clang/Basic/LLVM.h"
+#include "clang/Basic/TargetInfo.h"
+#include "llvm/ABI/Types.h"
+#include "llvm/Support/Alignment.h"
+#include "llvm/Support/Casting.h"
+#include <clang/ABI/QualTypeMapper.h>
+
+namespace clang {
+namespace mapper {
+
+const llvm::abi::Type *QualTypeMapper::convertType(QualType QT) {
+  QT = QT.getCanonicalType().getUnqualifiedType();
+
+  auto It = TypeCache.find(QT);
+  if (It != TypeCache.end())
+    return It->second;
+
+  const llvm::abi::Type *Result = nullptr;
+  if (const auto *BT = dyn_cast<BuiltinType>(QT.getTypePtr())) {
+    Result = convertBuiltinType(BT);
+  } else if (const auto *PT = dyn_cast<PointerType>(QT.getTypePtr())) {
+    Result = convertPointerType(PT);
+  } else if (const auto *AT = dyn_cast<ArrayType>(QT.getTypePtr())) {
+    Result = convertArrayType(AT);
+  } else if (const auto *VT = dyn_cast<VectorType>(QT.getTypePtr())) {
+    Result = convertVectorType(VT);
+  } else if (const auto *RT = dyn_cast<RecordType>(QT.getTypePtr())) {
+    Result = convertRecordType(RT);
+  } else if (const auto *ET = dyn_cast<EnumType>(QT.getTypePtr())) {
+    Result = convertEnumType(ET);
+  } else {
+    // TODO: Write Fallback logic for unsupported types.
+  }
+  TypeCache[QT] = Result;
+  return Result;
+}
+
+const llvm::abi::Type *
+QualTypeMapper::convertBuiltinType(const BuiltinType *BT) {
+  switch (BT->getKind()) {
+  case BuiltinType::Void:
+    return Builder.getVoidType();
+
+  case BuiltinType::Bool:
+  case BuiltinType::UChar:
+  case BuiltinType::Char_U:
+  case BuiltinType::UShort:
+    return Builder.getIntegerType(ASTCtx.getTypeSize(QualType(BT, 0)),
+                                  getTypeAlign(QualType(BT, 0)), false);
+
+  case BuiltinType::Char_S:
+  case BuiltinType::SChar:
+  case BuiltinType::Short:
+    return Builder.getIntegerType(ASTCtx.getCharWidth(),
+                                  getTypeAlign(QualType(BT, 0)), true);
+
+  case BuiltinType::WChar_U:
+    return Builder.getIntegerType(ASTCtx.getCharWidth(),
+                                  getTypeAlign(QualType(BT, 0)), false);
+
+  case BuiltinType::WChar_S:
+    return Builder.getIntegerType(ASTCtx.getCharWidth(),
+                                  getTypeAlign(QualType(BT, 0)), true);
+
+  case BuiltinType::Char8:
+    return Builder.getIntegerType(8, getTypeAlign(QualType(BT, 0)), false);
+
+  case BuiltinType::Char16:
+    return Builder.getIntegerType(16, getTypeAlign(QualType(BT, 0)), false);
+
+  case BuiltinType::Char32:
+    return Builder.getIntegerType(32, getTypeAlign(QualType(BT, 0)), false);
+
+  case BuiltinType::Int:
+  case BuiltinType::UInt:
+    return Builder.getIntegerType(ASTCtx.getIntWidth(QualType(BT, 0)),
+                                  getTypeAlign(QualType(BT, 0)),
+                                  BT->getKind() == BuiltinType::Int);
+
+  case BuiltinType::Long:
+  case BuiltinType::ULong:
+    return Builder.getIntegerType(ASTCtx.getTypeSize(QualType(BT, 0)),
+                                  getTypeAlign(QualType(BT, 0)),
+                                  BT->getKind() == BuiltinType::Long);
+
+  case BuiltinType::LongLong:
+  case BuiltinType::ULongLong:
+    return Builder.getIntegerType(ASTCtx.getTypeSize(QualType(BT, 0)),
+                                  getTypeAlign(QualType(BT, 0)),
+                                  BT->getKind() == BuiltinType::LongLong);
+
+  case BuiltinType::Int128:
+  case BuiltinType::UInt128:
+    return Builder.getIntegerType(128, getTypeAlign(QualType(BT, 0)),
+                                  BT->getKind() == BuiltinType::Int128);
+
+  case BuiltinType::Half:
+  case BuiltinType::Float16:
+    return Builder.getFloatType(llvm::APFloat::IEEEhalf(),
+                                getTypeAlign(QualType(BT, 0)));
+
+  case BuiltinType::Float:
+    return Builder.getFloatType(llvm::APFloat::IEEEsingle(),
+                                getTypeAlign(QualType(BT, 0)));
+
+  case BuiltinType::Double:
+    return Builder.getFloatType(llvm::APFloat::IEEEdouble(),
+                                getTypeAlign(QualType(BT, 0)));
+
+  case BuiltinType::LongDouble:
+    return Builder.getFloatType(ASTCtx.getFloatTypeSemantics(QualType(BT, 0)),
+                                getTypeAlign(QualType(BT, 0)));
+
+  case BuiltinType::BFloat16:
+    return Builder.getFloatType(llvm::APFloat::BFloat(),
+                                getTypeAlign(QualType(BT, 0)));
+
+  case BuiltinType::Float128:
+    return Builder.getFloatType(llvm::APFloat::IEEEquad(),
+                                getTypeAlign(QualType(BT, 0)));
+
+  default:
+    return Builder.getIntegerType(ASTCtx.getTypeSize(QualType(BT, 0)),
+                                  getTypeAlign(QualType(BT, 0)), false);
+  }
+}
+
+const llvm::abi::Type *
+QualTypeMapper::convertArrayType(const clang::ArrayType *AT) {
+  const llvm::abi::Type *ElementType = convertType(AT->getElementType());
+
+  if (const auto *CAT = dyn_cast<ConstantArrayType>(AT)) {
+    auto NumElements = CAT->getZExtSize();
+    return Builder.getArrayType(ElementType, NumElements);
+  }
+  if (const auto *IAT = dyn_cast<IncompleteArrayType>(AT))
+    return Builder.getArrayType(ElementType, 0);
+  if (const auto *VAT = dyn_cast<VariableArrayType>(AT))
+    return createPointerTypeForPointee(VAT->getPointeeType());
+  // TODO: This of a better fallback.
+  return Builder.getArrayType(ElementType, 1);
+}
+
+const llvm::abi::Type *QualTypeMapper::convertVectorType(const VectorType *VT) {
+  const llvm::abi::Type *ElementType = convertType(VT->getElementType());
+  uint64_t NumElements = VT->getNumElements();
+
+  llvm::Align VectorAlign = getTypeAlign(QualType(VT, 0));
+
+  return Builder.getVectorType(ElementType, NumElements, VectorAlign);
+}
+
+const llvm::abi::Type *QualTypeMapper::convertRecordType(const RecordType *RT) {
+  const RecordDecl *RD = RT->getDecl()->getDefinition();
+  if (!RD) {
+    SmallVector<llvm::abi::FieldInfo, 0> Fields;
+    return Builder.getStructType(Fields, llvm::TypeSize::getFixed(0),
+                                 llvm::Align(1));
+  }
+
+  if (RD->isUnion())
+    return convertUnionType(RD);
+  return convertStructType(RD);
+}
+
+const llvm::abi::Type *
+QualTypeMapper::convertPointerType(const clang::PointerType *PT) {
+  return createPointerTypeForPointee(PT->getPointeeType());
+}
+
+llvm::Align QualTypeMapper::getTypeAlign(QualType QT) const {
+  return llvm::Align(ASTCtx.getTypeAlign(QT));
+}
+
+const llvm::abi::Type *
+QualTypeMapper::createPointerTypeForPointee(QualType PointeeType) {
+  auto AddrSpace = PointeeType.getAddressSpace();
+  auto PointerSize = ASTCtx.getTargetInfo().getPointerWidth(AddrSpace);
+  llvm::Align Alignment =
+      llvm::Align(ASTCtx.getTargetInfo().getPointerAlign(AddrSpace));
+  return Builder.getPointerType(PointerSize, Alignment);
+}
+
+void QualTypeMapper::computeFieldInfo(
+    const RecordDecl *RD, SmallVectorImpl<llvm::abi::FieldInfo> &Fields,
+    const ASTRecordLayout &Layout) {
+  unsigned FieldIndex = 0;
+
+  for (const auto *FD : RD->fields()) {
+    const llvm::abi::Type *FieldType = convertType(FD->getType());
+    uint64_t OffsetInBits = Layout.getFieldOffset(FieldIndex);
+
+    bool IsBitField = FD->isBitField();
+    uint64_t BitFieldWidth = 0;
+
+    if (IsBitField) {
+      BitFieldWidth = FD->getBitWidthValue();
+    }
+
+    Fields.emplace_back(FieldType, OffsetInBits, IsBitField, BitFieldWidth);
+    ++FieldIndex;
+  }
+}
+
+} // namespace mapper
+} // namespace clang
diff --git a/clang/lib/CMakeLists.txt b/clang/lib/CMakeLists.txt
index 4f2218b583e41..f034622c06c2f 100644
--- a/clang/lib/CMakeLists.txt
+++ b/clang/lib/CMakeLists.txt
@@ -1,3 +1,4 @@
+add_subdirectory(ABI)
 add_subdirectory(Headers)
 add_subdirectory(Basic)
 add_subdirectory(APINotes)
diff --git a/debug.log b/debug.log
new file mode 100644
index 0000000000000..9694d8961cbb8
--- /dev/null
+++ b/debug.log
@@ -0,0 +1,2 @@
+opt: Unknown command line argument '-debug-only=instcombine'.  Try: 'build/bin/opt --help'
+opt: Did you mean '--debug-pass=instcombine'?
diff --git a/llvm/docs/GitHubMove.rst b/llvm/docs/GitHubMove.rst
new file mode 100644
index 0000000000000..dbb38ee985442
--- /dev/null
+++ b/llvm/docs/GitHubMove.rst
@@ -0,0 +1,1086 @@
+==============================
+Moving LLVM Projects to GitHub
+==============================
+
+Current Status
+==============
+
+We are planning to complete the transition to GitHub by Oct 21, 2019.  See
+the GitHub migration `status page <https://llvm.org/GitHubMigrationStatus.html>`_
+for the latest updates and instructions for how to migrate your workflows.
+
+.. contents:: Table of Contents
+  :depth: 4
+  :local:
+
+Introduction
+============
+
+This is a proposal to move our current revision control system from our own
+hosted Subversion to GitHub. Below are the financial and technical arguments as
+to why we are proposing such a move and how people (and validation
+infrastructure) will continue to work with a Git-based LLVM.
+
+What This Proposal is *Not* About
+=================================
+
+Changing the development policy.
+
+This proposal relates only to moving the hosting of our source-code repository
+from SVN hosted on our own servers to Git hosted on GitHub. We are not proposing
+using GitHub's issue tracker, pull-requests, or code-review.
+
+Contributors will continue to earn commit access on demand under the Developer
+Policy, except that that a GitHub account will be required instead of SVN
+username/password-hash.
+
+Why Git, and Why GitHub?
+========================
+
+Why Move At All?
+----------------
+
+This discussion began because we currently host our own Subversion server
+and Git mirror on a voluntary basis. The LLVM Foundation sponsors the server and
+provides limited support, but there is only so much it can do.
+
+Volunteers are not sysadmins themselves, but compiler engineers that happen
+to know a thing or two about hosting servers. We also don't have 24/7 support,
+and we sometimes wake up to see that continuous integration is broken because
+the SVN server is either down or unresponsive.
+
+We should take advantage of one of the services out there (GitHub, GitLab,
+and BitBucket, among others) that offer better service (24/7 stability, disk
+space, Git server, code browsing, forking facilities, etc) for free.
+
+Why Git?
+--------
+
+Many new coders nowadays start with Git, and a lot of people have never used
+SVN, CVS, or anything else. Websites like GitHub have changed the landscape
+of open source contributions, reducing the cost of first contribution and
+fostering collaboration.
+
+Git is also the version control many LLVM developers use. Despite the
+sources being stored in a SVN server, these developers are already using Git
+through the Git-SVN integration.
+
+Git allows you to:
+
+* Commit, squash, merge, and fork locally without touching the remote server.
+* Maintain local branches, enabling multiple threads of development.
+* Collaborate on these branches (e.g. through your own fork of llvm on GitHub).
+* Inspect the repository history (blame, log, bisect) without Internet access.
+* Maintain remote forks and branches on Git hosting services and
+  integrate back to the main repository.
+
+In addition, because Git seems to be replacing many OSS projects' version
+control systems, there are many tools that are built over Git.
+Future tooling may support Git first (if not only).
+
+Why GitHub?
+-----------
+
+GitHub, like GitLab and BitBucket, provides free code hosting for open source
+projects. Any of these could replace the code-hosting infrastructure that we
+have today.
+
+These services also have a dedicated team to monitor, migrate, improve and
+distribute the contents of the repositories depending on region and load.
+
+GitHub has one important advantage over GitLab and
+BitBucket: it offers read-write **SVN** access to the repository
+(https://github.com/blog/626-announcing-svn-support).
+This would enable people to continue working post-migration as though our code
+were still canonically in an SVN repository.
+
+In addition, there are already multiple LLVM mirrors on GitHub, indicating that
+part of our community has already settled there.
+
+On Managing Revision Numbers with Git
+-------------------------------------
+
+The current SVN repository hosts all the LLVM sub-projects alongside each other.
+A single revision number (e.g. r123456) thus identifies a consistent version of
+all LLVM sub-projects.
+
+Git does not use sequential integer revision number but instead uses a hash to
+identify each commit.
+
+The loss of a sequential integer revision number has been a sticking point in
+past discussions about Git:
+
+- "The 'branch' I most care about is mainline, and losing the ability to say
+  'fixed in r1234' (with some sort of monotonically increasing number) would
+  be a tragic loss." [LattnerRevNum]_
+- "I like those results sorted by time and the chronology should be obvious, but
+  timestamps are incredibly cumbersome and make it difficult to verify that a
+  given checkout matches a given set of results." [TrickRevNum]_
+- "There is still the major regression with unreadable version numbers.
+  Given the amount of Bugzilla traffic with 'Fixed in...', that's a
+  non-trivial issue." [JSonnRevNum]_
+- "Sequential IDs are important for LNT and llvmlab bisection tool." [MatthewsRevNum]_.
+
+However, Git can emulate this increasing revision number:
+``git rev-list --count <commit-hash>``. This identifier is unique only
+within a single branch, but this means the tuple `(num, branch-name)` uniquely
+identifies a commit.
+
+We can thus use this revision number to ensure that e.g. `clang -v` reports a
+user-friendly revision number (e.g. `main-12345` or `4.0-5321`), addressing
+the objections raised above with respect to this aspect of Git.
+
+What About Branches and Merges?
+-------------------------------
+
+In contrast to SVN, Git makes branching easy. Git's commit history is
+represented as a DAG, a departure from SVN's linear history. However, we propose
+to mandate making merge commits illegal in our canonical Git repository.
+
+Unfortunately, GitHub does not support server side hooks to enforce such a
+policy.  We must rely on the community to avoid pushing merge commits.
+
+GitHub offers a feature called `Status Checks`: a branch protected by
+`status checks` requires commits to be explicitly allowed before the push can happen.
+We could supply a pre-push hook on the client side that would run and check the
+history, before allowing the commit being pushed [statuschecks]_.
+However this solution would be somewhat fragile (how do you update a script
+installed on every developer machine?) and prevents SVN access to the
+repository.
+
+What About Commit Emails?
+-------------------------
+
+We will need a new bot to send emails for each commit. This proposal leaves the
+email format unchanged besides the commit URL.
+
+Straw Man Migration Plan
+========================
+
+Step #1 : Before The Move
+-------------------------
+
+1. Update docs to mention the move, so people are aware of what is going on.
+2. Set up a read-only version of the GitHub project, mirroring our current SVN
+   repository.
+3. Add the required bots to implement the commit emails, as well as the
+   umbrella repository update (if the multirepo is selected) or the read-only
+   Git views for the sub-projects (if the monorepo is selected).
+
+Step #2 : Git Move
+------------------
+
+4. Update the buildbots to pick up updates and commits from the GitHub
+   repository. Not all bots have to migrate at this point, but it'll help
+   provide infrastructure testing.
+5. Update Phabricator to pick up commits from the GitHub repository.
+6. LNT and llvmlab have to be updated: they rely on unique monotonically
+   increasing integer across branch [MatthewsRevNum]_.
+7. Instruct downstream integrators to pick up commits from the GitHub
+   repository.
+8. Review and prepare an update for the LLVM documentation.
+
+Until this point nothing has changed for developers, it will just
+boil down to a lot of work for buildbot and other infrastructure
+owners.
+
+The migration will pause here until all dependencies have cleared, and all
+problems have been solved.
+
+Step #3: Write Access Move
+--------------------------
+
+9. Collect developers' GitHub account information, and add them to the project.
+10. Switch the SVN repository to read-only and allow pushes to the GitHub repository.
+11. Update the documentation.
+12. Mirror Git to SVN.
+
+Step #4 : Post Move
+-------------------
+
+13. Archive the SVN repository.
+14. Update links on the LLVM website pointing to viewvc/klaus/phab etc. to
+    point to GitHub instead.
+
+GitHub Repository Description
+=============================
+
+Monorepo
+----------------
+
+The LLVM git repository hosted at https://github.com/llvm/llvm-project contains all
+sub-projects in a single source tree.  It is often referred to as a monorepo and
+mimics an export of the current SVN repository, with each sub-project having its
+own top-level directory. Not all sub-projects are used for building toolchains.
+For example, www/ and test-suite/ are not part of the monorepo.
+
+Putting all sub-projects in a single checkout makes cross-project refactoring
+naturally simple:
+
+ * New sub-projects can be trivially split out for better reuse and/or layering
+   (e.g., to allow libSupport and/or LIT to be used by runtimes without adding a
+   dependency on LLVM).
+ * Changing an API in LLVM and upgrading the sub-projects will always be done in
+   a single commit, designing away a common source of temporary build breakage.
+ * Moving code across sub-project (during refactoring for instance) in a single
+   commit enables accurate `git blame` when tracking code change history.
+ * Tooling based on `git grep` works natively across sub-projects, allowing to
+   easier find refactoring opportunities across projects (for example reusing a
+   datastructure initially in LLDB by moving it into libSupport).
+ * Having all the sources present encourages maintaining the other sub-projects
+   when changing API.
+
+Finally, the monorepo maintains the property of the existing SVN repository that
+the sub-projects move synchronously, and a single revision number (or commit
+hash) identifies the state of the development across all projects.
+
+.. _build_single_project:
+
+Building a single sub-project
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Even though there is a single source tree, you are not required to build
+all sub-projects together.  It is trivial to configure builds for a single
+sub-project.
+
+For example::
+
+  mkdir build && cd build
+  # Configure only LLVM (default)
+  cmake path/to/monorepo
+  # Configure LLVM and lld
+  cmake path/to/monorepo -DLLVM_ENABLE_PROJECTS=lld
+  # Configure LLVM and clang
+  cmake path/to/monorepo -DLLVM_ENABLE_PROJECTS=clang
+
+.. _git-svn-mirror:
+
+Outstanding Questions
+---------------------
+
+Read-only sub-project mirrors
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+With the Monorepo, it is undecided whether the existing single-subproject
+mirrors (e.g. https://git.llvm.org/git/compiler-rt.git) will continue to
+be maintained.
+
+Read/write SVN bridge
+^^^^^^^^^^^^^^^^^^^^^
+
+GitHub supports a read/write SVN bridge for its repositories.  However,
+there have been issues with this bridge working correctly in the past,
+so it's not clear if this is something that will be supported going forward.
+
+Monorepo Drawbacks
+------------------
+
+ * Using the monolithic repository may add overhead for those contributing to a
+   standalone sub-project, particularly on runtimes like libcxx and compiler-rt
+   that don't rely on LLVM; currently, a fresh clone of libcxx is only 15MB (vs.
+   1GB for the monorepo), and the commit rate of LLVM may cause more frequent
+   `git push` collisions when upstreaming. Affected contributors may be able to
+   use the SVN bridge or the single-subproject Git mirrors. However, it's
+   undecided if these projects will continue to be maintained.
+ * Using the monolithic repository may add overhead for those *integrating* a
+   standalone sub-project, even if they aren't contributing to it, due to the
+   same disk space concern as the point above. The availability of the
+   sub-project Git mirrors would addresses this.
+ * Preservation of the existing read/write SVN-based workflows relies on the
+   GitHub SVN bridge, which is an extra dependency. Maintaining this locks us
+   into GitHub and could restrict future workflow changes.
+
+Workflows
+^^^^^^^^^
+
+ * :ref:`Checkout/Clone a Single Project, without Commit Access <workflow-checkout-commit>`.
+ * :ref:`Checkout/Clone Multiple Projects, with Commit Access <workflow-monocheckout-multicommit>`.
+ * :ref:`Commit an API Change in LLVM and Update the Sub-projects <workflow-cross-repo-commit>`.
+ * :ref:`Branching/Stashing/Updating for Local Development or Experiments <workflow-mono-branching>`.
+ * :ref:`Bisecting <workflow-mono-bisecting>`.
+
+Workflow Before/After
+=====================
+
+This section goes through a few examples of workflows, intended to illustrate
+how end-users or developers would interact with the repository for
+various use-cases.
+
+.. _workflow-checkout-commit:
+
+Checkout/Clone a Single Project, with Commit Access
+---------------------------------------------------
+
+Currently
+^^^^^^^^^
+
+::
+
+  # direct SVN checkout
+  svn co https://user@llvm.org/svn/llvm-project/llvm/trunk llvm
+  # or using the read-only Git view, with git-svn
+  git clone https://llvm.org/git/llvm.git
+  cd llvm
+  git svn init https://llvm.org/svn/llvm-project/llvm/trunk --username=<username>
+  git config svn-remote.svn.fetch :refs/remotes/origin/main
+  git svn rebase -l  # -l avoids fetching ahead of the git mirror.
+
+Commits are performed using `svn commit` or with the sequence `git commit` and
+`git svn dcommit`.
+
+.. _workflow-multicheckout-nocommit:
+
+Monorepo Variant
+^^^^^^^^^^^^^^^^
+
+With the monorepo variant, there are a few options, depending on your
+constraints. First, you could just clone the full repository:
+
+git clone https://github.com/llvm/llvm-project.git
+
+At this point you have every sub-project (llvm, clang, lld, lldb, ...), which
+:ref:`doesn't imply you have to build all of them <build_single_project>`. You
+can still build only compiler-rt for instance. In this way it's not different
+from someone who would check out all the projects with SVN today.
+
+If you want to avoid checking out all the sources, you can hide the other
+directories using a Git sparse checkout::
+
+  git config core.sparseCheckout true
+  echo /compiler-rt > .git/info/sparse-checkout
+  git read-tree -mu HEAD
+
+The data for all sub-projects is still in your `.git` directory, but in your
+checkout, you only see `compiler-rt`.
+Before you push, you'll need to fetch and rebase (`git pull --rebase`) as
+usual.
+
+Note that when you fetch you'll likely pull in changes to sub-projects you don't
+care about. If you are using sparse checkout, the files from other projects
+won't appear on your disk. The only effect is that your commit hash changes.
+
+You can check whether the changes in the last fetch are relevant to your commit
+by running::
+
+  git log origin/main@{1}..origin/main -- libcxx
+
+This command can be hidden in a script so that `git llvmpush` would perform all
+these steps, fail only if such a dependent change exists, and show immediately
+the change that prevented the push. An immediate repeat of the command would
+(almost) certainly result in a successful push.
+Note that today with SVN or git-svn, this step is not possible since the
+"rebase" implicitly happens while committing (unless a conflict occurs).
+
+Checkout/Clone Multiple Projects, with Commit Access
+----------------------------------------------------
+
+Let's look how to assemble llvm+clang+libcxx at a given revision.
+
+Currently
+^^^^^^^^^
+
+::
+
+  svn co https://llvm.org/svn/llvm-project/llvm/trunk llvm -r $REVISION
+  cd llvm/tools
+  svn co https://llvm.org/svn/llvm-project/clang/trunk clang -r $REVISION
+  cd ../projects
+  svn co https://llvm.org/svn/llvm-project/libcxx/trunk libcxx -r $REVISION
+
+Or using git-svn::
+
+  git clone https://llvm.org/git/llvm.git
+  cd llvm/
+  git svn init https://llvm.org/svn/llvm-project/llvm/trunk --username=<username>
+  git config svn-remote.svn.fetch :refs/remotes/origin/main
+  git svn rebase -l
+  git checkout `git svn find-rev -B r258109`
+  cd tools
+  git clone https://llvm.org/git/clang.git
+  cd clang/
+  git svn init https://llvm.org/svn/llvm-project/clang/trunk --username=<username>
+  git config svn-remote.svn.fetch :refs/remotes/origin/main
+  git svn rebase -l
+  git checkout `git svn find-rev -B r258109`
+  cd ../../projects/
+  git clone https://llvm.org/git/libcxx.git
+  cd libcxx
+  git svn init https://llvm.org/svn/llvm-project/libcxx/trunk --username=<username>
+  git config svn-remote.svn.fetch :refs/remotes/origin/main
+  git svn rebase -l
+  git checkout `git svn find-rev -B r258109`
+
+Note that the list would be longer with more sub-projects.
+
+.. _workflow-monocheckout-multicommit:
+
+Monorepo Variant
+^^^^^^^^^^^^^^^^
+
+The repository contains natively the source for every sub-projects at the right
+revision, which makes this straightforward::
+
+  git clone https://github.com/llvm/llvm-project.git
+  cd llvm-projects
+  git checkout $REVISION
+
+As before, at this point clang, llvm, and libcxx are stored in directories
+alongside each other.
+
+.. _workflow-cross-repo-commit:
+
+Commit an API Change in LLVM and Update the Sub-projects
+--------------------------------------------------------
+
+Today this is possible, even though not common (at least not documented) for
+subversion users and for git-svn users. For example, few Git users try to update
+LLD or Clang in the same commit as they change an LLVM API.
+
+The multirepo variant does not address this: one would have to commit and push
+separately in every individual repository. It would be possible to establish a
+protocol whereby users add a special token to their commit messages that causes
+the umbrella repo's updater bot to group all of them into a single revision.
+
+The monorepo variant handles this natively.
+
+Branching/Stashing/Updating for Local Development or Experiments
+----------------------------------------------------------------
+
+Currently
+^^^^^^^^^
+
+SVN does not allow this use case, but developers that are currently using
+git-svn can do it. Let's look in practice what it means when dealing with
+multiple sub-projects.
+
+To update the repository to tip of trunk::
+
+  git pull
+  cd tools/clang
+  git pull
+  cd ../../projects/libcxx
+  git pull
+
+To create a new branch::
+
+  git checkout -b MyBranch
+  cd tools/clang
+  git checkout -b MyBranch
+  cd ../../projects/libcxx
+  git checkout -b MyBranch
+
+To switch branches::
+
+  git checkout AnotherBranch
+  cd tools/clang
+  git checkout AnotherBranch
+  cd ../../projects/libcxx
+  git checkout AnotherBranch
+
+.. _workflow-mono-branching:
+
+Monorepo Variant
+^^^^^^^^^^^^^^^^
+
+Regular Git commands are sufficient, because everything is in a single
+repository:
+
+To update the repository to tip of trunk::
+
+  git pull
+
+To create a new branch::
+
+  git checkout -b MyBranch
+
+To switch branches::
+
+  git checkout AnotherBranch
+
+Bisecting
+---------
+
+Assuming a developer is looking for a bug in clang (or lld, or lldb, ...).
+
+Currently
+^^^^^^^^^
+
+SVN does not have builtin bisection support, but the single revision across
+sub-projects makes it possible to script around.
+
+Using the existing Git read-only view of the repositories, it is possible to use
+the native Git bisection script over the llvm repository, and use some scripting
+to synchronize the clang repository to match the llvm revision.
+
+.. _workflow-mono-bisecting:
+
+Monorepo Variant
+^^^^^^^^^^^^^^^^
+
+Bisecting on the monorepo is straightforward, and very similar to the above,
+except that the bisection script does not need to include the
+`git submodule update` step.
+
+The same example, finding which commit introduces a regression where clang-3.9
+crashes but not clang-3.8 passes, will look like::
+
+  git bisect start releases/3.9.x releases/3.8.x
+  git bisect run ./bisect_script.sh
+
+With the `bisect_script.sh` script being::
+
+  #!/bin/sh
+  cd $BUILD_DIR
+
+  ninja clang || exit 125   # an exit code of 125 asks "git bisect"
+                            # to "skip" the current commit
+
+  ./bin/clang some_crash_test.cpp
+
+Also, since the monorepo handles commits update across multiple projects, you're
+less like to encounter a build failure where a commit change an API in LLVM and
+another later one "fixes" the build in clang.
+
+Moving Local Branches to the Monorepo
+=====================================
+
+Suppose you have been developing against the existing LLVM git
+mirrors.  You have one or more git branches that you want to migrate
+to the "final monorepo".
+
+The simplest way to migrate such branches is with the
+``migrate-downstream-fork.py`` tool at
+https://github.com/jyknight/llvm-git-migration.
+
+Basic migration
+---------------
+
+Basic instructions for ``migrate-downstream-fork.py`` are in the
+Python script and are expanded on below to a more general recipe::
+
+  # Make a repository which will become your final local mirror of the
+  # monorepo.
+  mkdir my-monorepo
+  git -C my-monorepo init
+
+  # Add a remote to the monorepo.
+  git -C my-monorepo remote add upstream/monorepo https://github.com/llvm/llvm-project.git
+
+  # Add remotes for each git mirror you use, from upstream as well as
+  # your local mirror.  All projects are listed here but you need only
+  # import those for which you have local branches.
+  my_projects=( clang
+                clang-tools-extra
+                compiler-rt
+                debuginfo-tests
+                libcxx
+                libcxxabi
+                libunwind
+                lld
+                lldb
+                llvm
+                openmp
+                polly )
+  for p in ${my_projects[@]}; do
+    git -C my-monorepo remote add upstream/split/${p} https://github.com/llvm-mirror/${p}.git
+    git -C my-monorepo remote add local/split/${p} https://my.local.mirror.org/${p}.git
+  done
+
+  # Pull in all the commits.
+  git -C my-monorepo fetch --all
+
+  # Run migrate-downstream-fork to rewrite local branches on top of
+  # the upstream monorepo.
+  (
+     cd my-monorepo
+     migrate-downstream-fork.py \
+       refs/remotes/local \
+       refs/tags \
+       --new-repo-prefix=refs/remotes/upstream/monorepo \
+       --old-repo-prefix=refs/remotes/upstream/split \
+       --source-kind=split \
+       --revmap-out=monorepo-map.txt
+  )
+
+  # Octopus-merge the resulting local split histories to unify them.
+
+  # Assumes local work on local split mirrors is on main (and
+  # upstream is presumably represented by some other branch like
+  # upstream/main).
+  my_local_branch="main"
+
+  git -C my-monorepo branch --no-track local/octopus/main \
+    $(git -C my-monorepo merge-base refs/remotes/upstream/monorepo/main \
+                                    refs/remotes/local/split/llvm/${my_local_branch})
+  git -C my-monorepo checkout local/octopus/${my_local_branch}
+
+  subproject_branches=()
+  for p in ${my_projects[@]}; do
+    subproject_branch=${p}/local/monorepo/${my_local_branch}
+    git -C my-monorepo branch ${subproject_branch} \
+      refs/remotes/local/split/${p}/${my_local_branch}
+    if [[ "${p}" != "llvm" ]]; then
+      subproject_branches+=( ${subproject_branch} )
+    fi
+  done
+
+  git -C my-monorepo merge ${subproject_branches[@]}
+
+  for p in ${my_projects[@]}; do
+    subproject_branch=${p}/local/monorepo/${my_local_branch}
+    git -C my-monorepo branch -d ${subproject_branch}
+  done
+
+  # Create local branches for upstream monorepo branches.
+  for ref in $(git -C my-monorepo for-each-ref --format="%(refname)" \
+                   refs/remotes/upstream/monorepo); do
+    upstream_branch=${ref#refs/remotes/upstream/monorepo/}
+    git -C my-monorepo branch upstream/${upstream_branch} ${ref}
+  done
+
+The above gets you to a state like the following::
+
+  U1 - U2 - U3 <- upstream/main
+    \   \    \
+     \   \    - Llld1 - Llld2 -
+      \   \                    \
+       \   - Lclang1 - Lclang2-- Lmerge <- local/octopus/main
+        \                      /
+         - Lllvm1 - Lllvm2-----
+
+Each branched component has its branch rewritten on top of the
+monorepo and all components are unified by a giant octopus merge.
+
+If additional active local branches need to be preserved, the above
+operations following the assignment to ``my_local_branch`` should be
+done for each branch.  Ref paths will need to be updated to map the
+local branch to the corresponding upstream branch.  If local branches
+have no corresponding upstream branch, then the creation of
+``local/octopus/<local branch>`` need not use ``git-merge-base`` to
+pinpoint its root commit; it may simply be branched from the
+appropriate component branch (say, ``llvm/local_release_X``).
+
+Zipping local history
+---------------------
+
+The octopus merge is suboptimal for many cases, because walking back
+through the history of one component leaves the other components fixed
+at a history that likely makes things unbuildable.
+
+Some downstream users track the order commits were made to subprojects
+with some kind of "umbrella" project that imports the project git
+mirrors as submodules, similar to the multirepo umbrella proposed
+above.  Such an umbrella repository looks something like this::
+
+   UM1 ---- UM2 -- UM3 -- UM4 ---- UM5 ---- UM6 ---- UM7 ---- UM8 <- main
+   |        |             |        |        |        |        |
+  Lllvm1   Llld1         Lclang1  Lclang2  Lllvm2   Llld2     Lmyproj1
+
+The vertical bars represent submodule updates to a particular local
+commit in the project mirror.  ``UM3`` in this case is a commit of
+some local umbrella repository state that is not a submodule update,
+perhaps a ``README`` or project build script update.  Commit ``UM8``
+updates a submodule of local project ``myproj``.
+
+The tool ``zip-downstream-fork.py`` at
+https://github.com/greened/llvm-git-migration/tree/zip can be used to
+convert the umbrella history into a monorepo-based history with
+commits in the order implied by submodule updates::
+
+  U1 - U2 - U3 <- upstream/main
+   \    \    \
+    \    -----\---------------                                    local/zip--.
+     \         \              \                                               |
+    - Lllvm1 - Llld1 - UM3 -  Lclang1 - Lclang2 - Lllvm2 - Llld2 - Lmyproj1 <-'
+
+
+The ``U*`` commits represent upstream commits to the monorepo main
+branch.  Each submodule update in the local ``UM*`` commits brought in
+a subproject tree at some local commit.  The trees in the ``L*1``
+commits represent merges from upstream.  These result in edges from
+the ``U*`` commits to their corresponding rewritten ``L*1`` commits.
+The ``L*2`` commits did not do any merges from upstream.
+
+Note that the merge from ``U2`` to ``Lclang1`` appears redundant, but
+if, say, ``U3`` changed some files in upstream clang, the ``Lclang1``
+commit appearing after the ``Llld1`` commit would actually represent a
+clang tree *earlier* in the upstream clang history.  We want the
+``local/zip`` branch to accurately represent the state of our umbrella
+history and so the edge ``U2 -> Lclang1`` is a visual reminder of what
+clang's tree actually looks like in ``Lclang1``.
+
+Even so, the edge ``U3 -> Llld1`` could be problematic for future
+merges from upstream.  git will think that we've already merged from
+``U3``, and we have, except for the state of the clang tree.  One
+possible mitigation strategy is to manually diff clang between ``U2``
+and ``U3`` and apply those updates to ``local/zip``.  Another,
+possibly simpler strategy is to freeze local work on downstream
+branches and merge all submodules from the latest upstream before
+running ``zip-downstream-fork.py``.  If downstream merged each project
+from upstream in lockstep without any intervening local commits, then
+things should be fine without any special action.  We anticipate this
+to be the common case.
+
+The tree for ``Lclang1`` outside of clang will represent the state of
+things at ``U3`` since all of the upstream projects not participating
+in the umbrella history should be in a state respecting the commit
+``U3``.  The trees for llvm and lld should correctly represent commits
+``Lllvm1`` and ``Llld1``, respectively.
+
+Commit ``UM3`` changed files not related to submodules and we need
+somewhere to put them.  It is not safe in general to put them in the
+monorepo root directory because they may conflict with files in the
+monorepo.  Let's assume we want them in a directory ``local`` in the
+monorepo.
+
+**Example 1: Umbrella looks like the monorepo**
+
+For this example, we'll assume that each subproject appears in its own
+top-level directory in the umbrella, just as they do in the monorepo .
+Let's also assume that we want the files in directory ``myproj`` to
+appear in ``local/myproj``.
+
+Given the above run of ``migrate-downstream-fork.py``, a recipe to
+create the zipped history is below::
+
+  # Import any non-LLVM repositories the umbrella references.
+  git -C my-monorepo remote add localrepo \
+                                https://my.local.mirror.org/localrepo.git
+  git fetch localrepo
+
+  subprojects=( clang clang-tools-extra compiler-rt debuginfo-tests libclc
+                libcxx libcxxabi libunwind lld lldb llgo llvm openmp
+                parallel-libs polly pstl )
+
+  # Import histories for upstream split projects (this was probably
+  # already done for the ``migrate-downstream-fork.py`` run).
+  for project in ${subprojects[@]}; do
+    git remote add upstream/split/${project} \
+                   https://github.com/llvm-mirror/${subproject}.git
+    git fetch umbrella/split/${project}
+  done
+
+  # Import histories for downstream split projects (this was probably
+  # already done for the ``migrate-downstream-fork.py`` run).
+  for project in ${subprojects[@]}; do
+    git remote add local/split/${project} \
+                   https://my.local.mirror.org/${subproject}.git
+    git fetch local/split/${project}
+  done
+
+  # Import umbrella history.
+  git -C my-monorepo remote add umbrella \
+                                https://my.local.mirror.org/umbrella.git
+  git fetch umbrella
+
+  # Put myproj in local/myproj
+  echo "myproj local/myproj" > my-monorepo/submodule-map.txt
+
+  # Rewrite history
+  (
+    cd my-monorepo
+    zip-downstream-fork.py \
+      refs/remotes/umbrella \
+      --new-repo-prefix=refs/remotes/upstream/monorepo \
+      --old-repo-prefix=refs/remotes/upstream/split \
+      --revmap-in=monorepo-map.txt \
+      --revmap-out=zip-map.txt \
+      --subdir=local \
+      --submodule-map=submodule-map.txt \
+      --update-tags
+   )
+
+   # Create the zip branch (assuming umbrella main is wanted).
+   git -C my-monorepo branch --no-track local/zip/main refs/remotes/umbrella/main
+
+Note that if the umbrella has submodules to non-LLVM repositories,
+``zip-downstream-fork.py`` needs to know about them to be able to
+rewrite commits.  That is why the first step above is to fetch commits
+from such repositories.
+
+With ``--update-tags`` the tool will migrate annotated tags pointing
+to submodule commits that were inlined into the zipped history.  If
+the umbrella pulled in an upstream commit that happened to have a tag
+pointing to it, that tag will be migrated, which is almost certainly
+not what is wanted.  The tag can always be moved back to its original
+commit after rewriting, or the ``--update-tags`` option may be
+discarded and any local tags would then be migrated manually.
+
+**Example 2: Nested sources layout**
+
+The tool handles nested submodules (e.g. llvm is a submodule in
+umbrella and clang is a submodule in llvm).  The file
+``submodule-map.txt`` is a list of pairs, one per line.  The first
+pair item describes the path to a submodule in the umbrella
+repository.  The second pair item describes the path where trees for
+that submodule should be written in the zipped history.
+
+Let's say your umbrella repository is actually the llvm repository and
+it has submodules in the "nested sources" layout (clang in
+tools/clang, etc.).  Let's also say ``projects/myproj`` is a submodule
+pointing to some downstream repository.  The submodule map file should
+look like this (we still want myproj mapped the same way as
+previously)::
+
+  tools/clang clang
+  tools/clang/tools/extra clang-tools-extra
+  projects/compiler-rt compiler-rt
+  projects/debuginfo-tests debuginfo-tests
+  projects/libclc libclc
+  projects/libcxx libcxx
+  projects/libcxxabi libcxxabi
+  projects/libunwind libunwind
+  tools/lld lld
+  tools/lldb lldb
+  projects/openmp openmp
+  tools/polly polly
+  projects/myproj local/myproj
+
+If a submodule path does not appear in the map, the tools assumes it
+should be placed in the same place in the monorepo.  That means if you
+use the "nested sources" layout in your umrella, you *must* provide
+map entries for all of the projects in your umbrella (except llvm).
+Otherwise trees from submodule updates will appear underneath llvm in
+the zippped history.
+
+Because llvm is itself the umbrella, we use --subdir to write its
+content into ``llvm`` in the zippped history::
+
+  # Import any non-LLVM repositories the umbrella references.
+  git -C my-monorepo remote add localrepo \
+                                https://my.local.mirror.org/localrepo.git
+  git fetch localrepo
+
+  subprojects=( clang clang-tools-extra compiler-rt debuginfo-tests libclc
+                libcxx libcxxabi libunwind lld lldb llgo llvm openmp
+                parallel-libs polly pstl )
+
+  # Import histories for upstream split projects (this was probably
+  # already done for the ``migrate-downstream-fork.py`` run).
+  for project in ${subprojects[@]}; do
+    git remote add upstream/split/${project} \
+                   https://github.com/llvm-mirror/${subproject}.git
+    git fetch umbrella/split/${project}
+  done
+
+  # Import histories for downstream split projects (this was probably
+  # already done for the ``migrate-downstream-fork.py`` run).
+  for project in ${subprojects[@]}; do
+    git remote add local/split/${project} \
+                   https://my.local.mirror.org/${subproject}.git
+    git fetch local/split/${project}
+  done
+
+  # Import umbrella history.  We want this under a different refspec
+  # so zip-downstream-fork.py knows what it is.
+  git -C my-monorepo remote add umbrella \
+                                 https://my.local.mirror.org/llvm.git
+  git fetch umbrella
+
+  # Create the submodule map.
+  echo "tools/clang clang" > my-monorepo/submodule-map.txt
+  echo "tools/clang/tools/extra clang-tools-extra" >> my-monorepo/submodule-map.txt
+  echo "projects/compiler-rt compiler-rt" >> my-monorepo/submodule-map.txt
+  echo "projects/debuginfo-tests debuginfo-tests" >> my-monorepo/submodule-map.txt
+  echo "projects/libclc libclc" >> my-monorepo/submodule-map.txt
+  echo "projects/libcxx libcxx" >> my-monorepo/submodule-map.txt
+  echo "projects/libcxxabi libcxxabi" >> my-monorepo/submodule-map.txt
+  echo "projects/libunwind libunwind" >> my-monorepo/submodule-map.txt
+  echo "tools/lld lld" >> my-monorepo/submodule-map.txt
+  echo "tools/lldb lldb" >> my-monorepo/submodule-map.txt
+  echo "projects/openmp openmp" >> my-monorepo/submodule-map.txt
+  echo "tools/polly polly" >> my-monorepo/submodule-map.txt
+  echo "projects/myproj local/myproj" >> my-monorepo/submodule-map.txt
+
+  # Rewrite history
+  (
+    cd my-monorepo
+    zip-downstream-fork.py \
+      refs/remotes/umbrella \
+      --new-repo-prefix=refs/remotes/upstream/monorepo \
+      --old-repo-prefix=refs/remotes/upstream/split \
+      --revmap-in=monorepo-map.txt \
+      --revmap-out=zip-map.txt \
+      --subdir=llvm \
+      --submodule-map=submodule-map.txt \
+      --update-tags
+   )
+
+   # Create the zip branch (assuming umbrella main is wanted).
+   git -C my-monorepo branch --no-track local/zip/main refs/remotes/umbrella/main
+
+
+Comments at the top of ``zip-downstream-fork.py`` describe in more
+detail how the tool works and various implications of its operation.
+
+Importing local repositories
+----------------------------
+
+You may have additional repositories that integrate with the LLVM
+ecosystem, essentially extending it with new tools.  If such
+repositories are tightly coupled with LLVM, it may make sense to
+import them into your local mirror of the monorepo.
+
+If such repositories participated in the umbrella repository used
+during the zipping process above, they will automatically be added to
+the monorepo.  For downstream repositories that don't participate in
+an umbrella setup, the ``import-downstream-repo.py`` tool at
+https://github.com/greened/llvm-git-migration/tree/import can help with
+getting them into the monorepo.  A recipe follows::
+
+  # Import downstream repo history into the monorepo.
+  git -C my-monorepo remote add myrepo https://my.local.mirror.org/myrepo.git
+  git fetch myrepo
+
+  my_local_tags=( refs/tags/release
+                  refs/tags/hotfix )
+
+  (
+    cd my-monorepo
+    import-downstream-repo.py \
+      refs/remotes/myrepo \
+      ${my_local_tags[@]} \
+      --new-repo-prefix=refs/remotes/upstream/monorepo \
+      --subdir=myrepo \
+      --tag-prefix="myrepo-"
+   )
+
+   # Preserve release branches.
+   for ref in $(git -C my-monorepo for-each-ref --format="%(refname)" \
+                  refs/remotes/myrepo/release); do
+     branch=${ref#refs/remotes/myrepo/}
+     git -C my-monorepo branch --no-track myrepo/${branch} ${ref}
+   done
+
+   # Preserve main.
+   git -C my-monorepo branch --no-track myrepo/main refs/remotes/myrepo/main
+
+   # Merge main.
+   git -C my-monorepo checkout local/zip/main  # Or local/octopus/main
+   git -C my-monorepo merge myrepo/main
+
+You may want to merge other corresponding branches, for example
+``myrepo`` release branches if they were in lockstep with LLVM project
+releases.
+
+``--tag-prefix`` tells ``import-downstream-repo.py`` to rename
+annotated tags with the given prefix.  Due to limitations with
+``fast_filter_branch.py``, unannotated tags cannot be renamed
+(``fast_filter_branch.py`` considers them branches, not tags).  Since
+the upstream monorepo had its tags rewritten with an "llvmorg-"
+prefix, name conflicts should not be an issue.  ``--tag-prefix`` can
+be used to more clearly indicate which tags correspond to various
+imported repositories.
+
+Given this repository history::
+
+  R1 - R2 - R3 <- main
+       ^
+       |
+    release/1
+
+The above recipe results in a history like this::
+
+  U1 - U2 - U3 <- upstream/main
+   \    \    \
+    \    -----\---------------                                         local/zip--.
+     \         \              \                                                    |
+    - Lllvm1 - Llld1 - UM3 -  Lclang1 - Lclang2 - Lllvm2 - Llld2 - Lmyproj1 - M1 <-'
+                                                                             /
+                                                                 R1 - R2 - R3  <-.
+                                                                      ^           |
+                                                                      |           |
+                                                               myrepo-release/1   |
+                                                                                  |
+                                                                     myrepo/main--'
+
+Commits ``R1``, ``R2`` and ``R3`` have trees that *only* contain blobs
+from ``myrepo``.  If you require commits from ``myrepo`` to be
+interleaved with commits on local project branches (for example,
+interleaved with ``llvm1``, ``llvm2``, etc. above) and myrepo doesn't
+appear in an umbrella repository, a new tool will need to be
+developed.  Creating such a tool would involve:
+
+1. Modifying ``fast_filter_branch.py`` to optionally take a
+   revlist directly rather than generating it itself
+
+2. Creating a tool to generate an interleaved ordering of local
+   commits based on some criteria (``zip-downstream-fork.py`` uses the
+   umbrella history as its criterion)
+
+3. Generating such an ordering and feeding it to
+   ``fast_filter_branch.py`` as a revlist
+
+Some care will also likely need to be taken to handle merge commits,
+to ensure the parents of such commits migrate correctly.
+
+Scrubbing the Local Monorepo
+----------------------------
+
+Once all of the migrating, zipping and importing is done, it's time to
+clean up.  The python tools use ``git-fast-import`` which leaves a lot
+of cruft around and we want to shrink our new monorepo mirror as much
+as possible.  Here is one way to do it::
+
+  git -C my-monorepo checkout main
+
+  # Delete branches we no longer need.  Do this for any other branches
+  # you merged above.
+  git -C my-monorepo branch -D local/zip/main || true
+  git -C my-monorepo branch -D local/octopus/main || true
+
+  # Remove remotes.
+  git -C my-monorepo remote remove upstream/monorepo
+
+  for p in ${my_projects[@]}; do
+    git -C my-monorepo remote remove upstream/split/${p}
+    git -C my-monorepo remote remove local/split/${p}
+  done
+
+  git -C my-monorepo remote remove localrepo
+  git -C my-monorepo remote remove umbrella
+  git -C my-monorepo remote remove myrepo
+
+  # Add anything else here you don't need.  refs/tags/release is
+  # listed below assuming tags have been rewritten with a local prefix.
+  # If not, remove it from this list.
+  refs_to_clean=(
+    refs/original
+    refs/remotes
+    refs/tags/backups
+    refs/tags/release
+  )
+
+  git -C my-monorepo for-each-ref --format="%(refname)" ${refs_to_clean[@]} |
+    xargs -n1 --no-run-if-empty git -C my-monorepo update-ref -d
+
+  git -C my-monorepo reflog expire --all --expire=now
+
+  # fast_filter_branch.py might have gc running in the background.
+  while ! git -C my-monorepo \
+    -c gc.reflogExpire=0 \
+    -c gc.reflogExpireUnreachable=0 \
+    -c gc.rerereresolved=0 \
+    -c gc.rerereunresolved=0 \
+    -c gc.pruneExpire=now \
+    gc --prune=now; do
+    continue
+  done
+
+  # Takes a LOOOONG time!
+  git -C my-monorepo repack -A -d -f --depth=250 --window=250
+
+  git -C my-monorepo prune-packed
+  git -C my-monorepo prune
+
+You should now have a trim monorepo.  Upload it to your git server and
+happy hacking!
+
+References
+==========
+
+.. [LattnerRevNum] Chris Lattner, http://lists.llvm.org/pipermail/llvm-dev/2011-July/041739.html
+.. [TrickRevNum] Andrew Trick, http://lists.llvm.org/pipermail/llvm-dev/2011-July/041721.html
+.. [JSonnRevNum] Joerg Sonnenberger, http://lists.llvm.org/pipermail/llvm-dev/2011-July/041688.html
+.. [MatthewsRevNum] Chris Matthews, http://lists.llvm.org/pipermail/cfe-dev/2016-July/049886.html
+.. [statuschecks] GitHub status-checks, https://help.github.com/articles/about-required-status-checks/
diff --git a/llvm/docs/VariableNames.rst b/llvm/docs/VariableNames.rst
new file mode 100644
index 0000000000000..1739695a5185f
--- /dev/null
+++ b/llvm/docs/VariableNames.rst
@@ -0,0 +1,399 @@
+===================
+Variable Names Plan
+===================
+
+.. contents::
+   :local:
+
+This plan is *provisional*. It is not agreed upon. It is written with the
+intention of capturing the desires and concerns of the LLVM community, and
+forming them into a plan that can be agreed upon.
+The original author is somewhat naïve in the ways of LLVM so there will
+inevitably be some details that are flawed. You can help - you can edit this
+page (preferably with a Phabricator review for larger changes) or reply to the
+`Request For Comments thread
+<http://lists.llvm.org/pipermail/llvm-dev/2019-February/130083.html>`_.
+
+Too Long; Didn't Read
+=====================
+
+Improve the readability of LLVM code.
+
+Introduction
+============
+
+The current `variable naming rule
+<../CodingStandards.html#name-types-functions-variables-and-enumerators-properly>`_
+states:
+
+  Variable names should be nouns (as they represent state). The name should be
+  camel case, and start with an upper case letter (e.g. Leader or Boats).
+
+This rule is the same as that for type names. This is a problem because the
+type name cannot be reused for a variable name [*]_. LLVM developers tend to
+work around this by either prepending ``The`` to the type name::
+
+  Triple TheTriple;
+
+... or more commonly use an acronym, despite the coding standard stating "Avoid
+abbreviations unless they are well known"::
+
+  Triple T;
+
+The proliferation of acronyms leads to hard-to-read code such as `this
+<https://github.com/llvm/llvm-project/blob/0a8bc14ad7f3209fe702d18e250194cd90188596/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp#L7445>`_::
+
+  InnerLoopVectorizer LB(L, PSE, LI, DT, TLI, TTI, AC, ORE, VF.Width, IC,
+                         &LVL, &CM);
+
+Many other coding guidelines [LLDB]_ [Google]_ [WebKit]_ [Qt]_ [Rust]_ [Swift]_
+[Python]_ require that variable names begin with a lower case letter in contrast
+to class names which begin with a capital letter. This convention means that the
+most readable variable name also requires the least thought::
+
+  Triple triple;
+
+There is some agreement that the current rule is broken [LattnerAgree]_
+[ArsenaultAgree]_ [RobinsonAgree]_ and that acronyms are an obstacle to reading
+new code [MalyutinDistinguish]_ [CarruthAcronym]_ [PicusAcronym]_. There are
+some opposing views [ParzyszekAcronym2]_ [RicciAcronyms]_.
+
+This work-in-progress proposal is to change the coding standard for variable
+names to require that they start with a lower case letter.
+
+.. [*] In `some cases
+   <https://github.com/llvm/llvm-project/blob/8b72080d4d7b13072f371712eed333f987b7a18e/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp#L2727>`_
+   the type name *is* reused as a variable name, but this shadows the type name
+   and confuses many debuggers [DenisovCamelBack]_.
+
+Variable Names Coding Standard Options
+======================================
+
+There are two main options for variable names that begin with a lower case
+letter: ``camelBack`` and ``lower_case``. (These are also known by other names
+but here we use the terminology from clang-tidy).
+
+``camelBack`` is consistent with [WebKit]_, [Qt]_ and [Swift]_ while
+``lower_case`` is consistent with [LLDB]_, [Google]_, [Rust]_ and [Python]_.
+
+``camelBack`` is already used for function names, which may be considered an
+advantage [LattnerFunction]_ or a disadvantage [CarruthFunction]_.
+
+Approval for ``camelBack`` was expressed by [DenisovCamelBack]_
+[LattnerFunction]_ [IvanovicDistinguish]_.
+Opposition to ``camelBack`` was expressed by [CarruthCamelBack]_
+[TurnerCamelBack]_.
+Approval for ``lower_case`` was expressed by [CarruthLower]_
+[CarruthCamelBack]_ [TurnerLLDB]_.
+Opposition to ``lower_case`` was expressed by [LattnerLower]_.
+
+Differentiating variable kinds
+------------------------------
+
+An additional requested change is to distinguish between different kinds of
+variables [RobinsonDistinguish]_ [RobinsonDistinguish2]_ [JonesDistinguish]_
+[IvanovicDistinguish]_ [CarruthDistinguish]_ [MalyutinDistinguish]_.
+
+Others oppose this idea [HähnleDistinguish]_ [GreeneDistinguish]_
+[HendersonPrefix]_.
+
+A possibility is for member variables to be prefixed with ``m_`` and for global
+variables to be prefixed with ``g_`` to distinguish them from local variables.
+This is consistent with [LLDB]_. The ``m_`` prefix is consistent with [WebKit]_.
+
+A variation is for member variables to be prefixed with ``m``
+[IvanovicDistinguish]_ [BeylsDistinguish]_. This is consistent with [Mozilla]_.
+
+Another option is for member variables to be suffixed with ``_`` which is
+consistent with [Google]_ and similar to [Python]_. Opposed by
+[ParzyszekDistinguish]_.
+
+Reducing the number of acronyms
+===============================
+
+While switching coding standard will make it easier to use non-acronym names for
+new code, it doesn't improve the existing large body of code that uses acronyms
+extensively to the detriment of its readability. Further, it is natural and
+generally encouraged that new code be written in the style of the surrounding
+code. Therefore it is likely that much newly written code will also use
+acronyms despite what the coding standard says, much as it is today.
+
+As well as changing the case of variable names, they could also be expanded to
+their non-acronym form e.g. ``Triple T`` → ``Triple triple``.
+
+There is support for expanding many acronyms [CarruthAcronym]_ [PicusAcronym]_
+but there is a preference that expanding acronyms be deferred
+[ParzyszekAcronym]_ [CarruthAcronym]_.
+
+The consensus within the community seems to be that at least some acronyms are
+valuable [ParzyszekAcronym]_ [LattnerAcronym]_. The most commonly cited acronym
+is ``TLI`` however that is used to refer to both ``TargetLowering`` and
+``TargetLibraryInfo`` [GreeneDistinguish]_.
+
+The following is a list of acronyms considered sufficiently useful that the
+benefit of using them outweighs the cost of learning them. Acronyms that are
+either not on the list or are used to refer to a different type should be
+expanded.
+
+============================ =============
+Class name                   Variable name
+============================ =============
+DeterministicFiniteAutomaton dfa
+DominatorTree                dt
+LoopInfo                     li
+MachineFunction              mf
+MachineInstr                 mi
+MachineRegisterInfo          mri
+ScalarEvolution              se
+TargetInstrInfo              tii
+TargetLibraryInfo            tli
+TargetRegisterInfo           tri
+============================ =============
+
+In some cases renaming acronyms to the full type name will result in overly
+verbose code. Unlike most classes, a variable's scope is limited and therefore
+some of its purpose can implied from that scope, meaning that fewer words are
+necessary to give it a clear name. For example, in an optimization pass the reader
+can assume that a variable's purpose relates to optimization and therefore an
+``OptimizationRemarkEmitter`` variable could be given the name ``remarkEmitter``
+or even ``remarker``.
+
+The following is a list of longer class names and the associated shorter
+variable name.
+
+========================= =============
+Class name                Variable name
+========================= =============
+BasicBlock                block
+ConstantExpr              expr
+ExecutionEngine           engine
+MachineOperand            operand
+OptimizationRemarkEmitter remarker
+PreservedAnalyses         analyses
+PreservedAnalysesChecker  checker
+TargetLowering            lowering
+TargetMachine             machine
+========================= =============
+
+Transition Options
+==================
+
+There are three main options for transitioning:
+
+1. Keep the current coding standard
+2. Laissez faire
+3. Big bang
+
+Keep the current coding standard
+--------------------------------
+
+Proponents of keeping the current coding standard (i.e. not transitioning at
+all) question whether the cost of transition outweighs the benefit
+[EmersonConcern]_ [ReamesConcern]_ [BradburyConcern]_.
+The costs are that ``git blame`` will become less usable; and that merging the
+changes will be costly for downstream maintainers. See `Big bang`_ for potential
+mitigations.
+
+Laissez faire
+-------------
+
+The coding standard could allow both ``CamelCase`` and ``camelBack`` styles for
+variable names [LattnerTransition]_.
+
+A code review to implement this is at https://reviews.llvm.org/D57896.
+
+Advantages
+**********
+
+ * Very easy to implement initially.
+
+Disadvantages
+*************
+
+ * Leads to inconsistency [BradburyConcern]_ [AminiInconsistent]_.
+ * Inconsistency means it will be hard to know at a guess what name a variable
+   will have [DasInconsistent]_ [CarruthInconsistent]_.
+ * Some large-scale renaming may happen anyway, leading to its disadvantages
+   without any mitigations.
+
+Big bang
+--------
+
+With this approach, variables will be renamed by an automated script in a series
+of large commits.
+
+The principle advantage of this approach is that it minimises the cost of
+inconsistency [BradburyTransition]_ [RobinsonTransition]_.
+
+It goes against a policy of avoiding large-scale reformatting of existing code
+[GreeneDistinguish]_.
+
+It has been suggested that LLD would be a good starter project for the renaming
+[Ueyama]_.
+
+Keeping git blame usable
+************************
+
+``git blame`` (or ``git annotate``) permits quickly identifying the commit that
+changed a given line in a file. After renaming variables, many lines will show
+as being changed by that one commit, requiring a further invocation of ``git
+blame`` to identify prior, more interesting commits [GreeneGitBlame]_
+[RicciAcronyms]_.
+
+**Mitigation**: `git-hyper-blame
+<https://commondatastorage.googleapis.com/chrome-infra-docs/flat/depot_tools/docs/html/git-hyper-blame.html>`_
+can ignore or "look through" a given set of commits.
+A ``.git-blame-ignore-revs`` file identifying the variable renaming commits
+could be added to the LLVM git repository root directory.
+It is being `investigated
+<https://public-inbox.org/git/20190324235020.49706-1-michael@platin.gs/>`_
+whether similar functionality could be added to ``git blame`` itself.
+
+Minimising cost of downstream merges
+************************************
+
+There are many forks of LLVM with downstream changes. Merging a large-scale
+renaming change could be difficult for the fork maintainers.
+
+**Mitigation**: A large-scale renaming would be automated. A fork maintainer can
+merge from the commit immediately before the renaming, then apply the renaming
+script to their own branch. They can then merge again from the renaming commit,
+resolving all conflicts by choosing their own version. This could be tested on
+the [SVE]_ fork.
+
+Provisional Plan
+================
+
+This is a provisional plan for the `Big bang`_ approach. It has not been agreed.
+
+#. Investigate improving ``git blame``. The extent to which it can be made to
+   "look through" commits may impact how big a change can be made.
+
+#. Write a script to expand acronyms.
+
+#. Experiment and perform dry runs of the various refactoring options.
+   Results can be published in forks of the LLVM Git repository.
+
+#. Consider the evidence and agree on the new policy.
+
+#. Agree & announce a date for the renaming of the starter project (LLD).
+
+#. Update the `policy page <../CodingStandards.html>`_. This will explain the
+   old and new rules and which projects each applies to.
+
+#. Refactor the starter project in two commits:
+
+   1. Add or change the project's .clang-tidy to reflect the agreed rules.
+      (This is in a separate commit to enable the merging process described in
+      `Minimising cost of downstream merges`_).
+      Also update the project list on the policy page.
+   2. Apply ``clang-tidy`` to the project's files, with only the
+      ``readability-identifier-naming`` rules enabled. ``clang-tidy`` will also
+      reformat the affected lines according to the rules in ``.clang-format``.
+      It is anticipated that this will be a good dog-fooding opportunity for
+      clang-tidy, and bugs should be fixed in the process, likely including:
+
+        * `readability-identifier-naming incorrectly fixes lambda capture
+          <https://bugs.llvm.org/show_bug.cgi?id=41119>`_.
+        * `readability-identifier-naming incorrectly fixes variables which
+          become keywords <https://bugs.llvm.org/show_bug.cgi?id=41120>`_.
+        * `readability-identifier-naming misses fixing member variables in
+          destructor <https://bugs.llvm.org/show_bug.cgi?id=41122>`_.
+
+#. Gather feedback and refine the process as appropriate.
+
+#. Apply the process to the following projects, with a suitable delay between
+   each (at least 4 weeks after the first change, at least 2 weeks subsequently)
+   to allow gathering further feedback.
+   This list should exclude projects that must adhere to an externally defined
+   standard e.g. libcxx.
+   The list is roughly in chronological order of renaming.
+   Some items may not make sense to rename individually - it is expected that
+   this list will change following experimentation:
+
+   * TableGen
+   * llvm/tools
+   * clang-tools-extra
+   * clang
+   * ARM backend
+   * AArch64 backend
+   * AMDGPU backend
+   * ARC backend
+   * AVR backend
+   * BPF backend
+   * Hexagon backend
+   * Lanai backend
+   * MIPS backend
+   * NVPTX backend
+   * PowerPC backend
+   * RISC-V backend
+   * Sparc backend
+   * SystemZ backend
+   * WebAssembly backend
+   * X86 backend
+   * XCore backend
+   * libLTO
+   * Debug Information
+   * Remainder of llvm
+   * compiler-rt
+   * libunwind
+   * openmp
+   * parallel-libs
+   * polly
+   * lldb
+
+#. Remove the old variable name rule from the policy page.
+
+#. Repeat many of the steps in the sequence, using a script to expand acronyms.
+
+References
+==========
+
+.. [LLDB] LLDB Coding Conventions https://llvm.org/svn/llvm-project/lldb/branches/release_39/www/lldb-coding-conventions.html
+.. [Google] Google C++ Style Guide https://google.github.io/styleguide/cppguide.html#Variable_Names
+.. [WebKit] WebKit Code Style Guidelines https://webkit.org/code-style-guidelines/#names
+.. [Qt] Qt Coding Style https://wiki.qt.io/Qt_Coding_Style#Declaring_variables
+.. [Rust] Rust naming conventions https://doc.rust-lang.org/1.0.0/style/style/naming/README.html
+.. [Swift] Swift API Design Guidelines https://swift.org/documentation/api-design-guidelines/#general-conventions
+.. [Python] Style Guide for Python Code https://www.python.org/dev/peps/pep-0008/#function-and-variable-names
+.. [Mozilla] Mozilla Coding style: Prefixes https://firefox-source-docs.mozilla.org/tools/lint/coding-style/coding_style_cpp.html#prefixes
+.. [SVE] LLVM with support for SVE https://github.com/ARM-software/LLVM-SVE
+.. [AminiInconsistent] Mehdi Amini, http://lists.llvm.org/pipermail/llvm-dev/2019-February/130329.html
+.. [ArsenaultAgree] Matt Arsenault, http://lists.llvm.org/pipermail/llvm-dev/2019-February/129934.html
+.. [BeylsDistinguish] Kristof Beyls, http://lists.llvm.org/pipermail/llvm-dev/2019-February/130292.html
+.. [BradburyConcern] Alex Bradbury, http://lists.llvm.org/pipermail/llvm-dev/2019-February/130266.html
+.. [BradburyTransition] Alex Bradbury, http://lists.llvm.org/pipermail/llvm-dev/2019-February/130388.html
+.. [CarruthAcronym] Chandler Carruth, http://lists.llvm.org/pipermail/llvm-dev/2019-February/130313.html
+.. [CarruthCamelBack] Chandler Carruth, http://lists.llvm.org/pipermail/llvm-dev/2019-February/130214.html
+.. [CarruthDistinguish] Chandler Carruth, http://lists.llvm.org/pipermail/llvm-dev/2019-February/130310.html
+.. [CarruthFunction] Chandler Carruth, http://lists.llvm.org/pipermail/llvm-dev/2019-February/130309.html
+.. [CarruthInconsistent] Chandler Carruth, http://lists.llvm.org/pipermail/llvm-dev/2019-February/130312.html
+.. [CarruthLower] Chandler Carruth, http://lists.llvm.org/pipermail/llvm-dev/2019-February/130430.html
+.. [DasInconsistent] Sanjoy Das, http://lists.llvm.org/pipermail/llvm-dev/2019-February/130304.html
+.. [DenisovCamelBack] Alex Denisov, http://lists.llvm.org/pipermail/llvm-dev/2019-February/130179.html
+.. [EmersonConcern] Amara Emerson, http://lists.llvm.org/pipermail/llvm-dev/2019-February/129894.html
+.. [GreeneDistinguish] David Greene, http://lists.llvm.org/pipermail/llvm-dev/2019-February/130425.html
+.. [GreeneGitBlame] David Greene, http://lists.llvm.org/pipermail/llvm-dev/2019-February/130228.html
+.. [HendersonPrefix] James Henderson, http://lists.llvm.org/pipermail/llvm-dev/2019-February/130465.html
+.. [HähnleDistinguish] Nicolai Hähnle, http://lists.llvm.org/pipermail/llvm-dev/2019-February/129923.html
+.. [IvanovicDistinguish] Nemanja Ivanovic, http://lists.llvm.org/pipermail/llvm-dev/2019-February/130249.html
+.. [JonesDistinguish] JD Jones, http://lists.llvm.org/pipermail/llvm-dev/2019-February/129926.html
+.. [LattnerAcronym] Chris Lattner, http://lists.llvm.org/pipermail/llvm-dev/2019-February/130353.html
+.. [LattnerAgree] Chris Latter, http://lists.llvm.org/pipermail/llvm-dev/2019-February/129907.html
+.. [LattnerFunction] Chris Lattner, http://lists.llvm.org/pipermail/llvm-dev/2019-February/130630.html
+.. [LattnerLower] Chris Lattner, http://lists.llvm.org/pipermail/llvm-dev/2019-February/130629.html
+.. [LattnerTransition] Chris Lattner, http://lists.llvm.org/pipermail/llvm-dev/2019-February/130355.html
+.. [MalyutinDistinguish] Danila Malyutin, http://lists.llvm.org/pipermail/llvm-dev/2019-February/130320.html
+.. [ParzyszekAcronym] Krzysztof Parzyszek, http://lists.llvm.org/pipermail/llvm-dev/2019-February/130306.html
+.. [ParzyszekAcronym2] Krzysztof Parzyszek, http://lists.llvm.org/pipermail/llvm-dev/2019-February/130323.html
+.. [ParzyszekDistinguish] Krzysztof Parzyszek, http://lists.llvm.org/pipermail/llvm-dev/2019-February/129941.html
+.. [PicusAcronym] Diana Picus, http://lists.llvm.org/pipermail/llvm-dev/2019-February/130318.html
+.. [ReamesConcern] Philip Reames, http://lists.llvm.org/pipermail/llvm-dev/2019-February/130181.html
+.. [RicciAcronyms] Bruno Ricci, http://lists.llvm.org/pipermail/llvm-dev/2019-February/130328.html
+.. [RobinsonAgree] Paul Robinson, http://lists.llvm.org/pipermail/llvm-dev/2019-February/130111.html
+.. [RobinsonDistinguish] Paul Robinson, http://lists.llvm.org/pipermail/llvm-dev/2019-February/129920.html
+.. [RobinsonDistinguish2] Paul Robinson, http://lists.llvm.org/pipermail/llvm-dev/2019-February/130229.html
+.. [RobinsonTransition] Paul Robinson, http://lists.llvm.org/pipermail/llvm-dev/2019-February/130415.html
+.. [TurnerCamelBack] Zachary Turner, https://reviews.llvm.org/D57896#1402264
+.. [TurnerLLDB] Zachary Turner, http://lists.llvm.org/pipermail/llvm-dev/2019-February/130213.html
+.. [Ueyama] Rui Ueyama, http://lists.llvm.org/pipermail/llvm-dev/2019-February/130435.html
diff --git a/llvm/include/llvm/ABI/QualTypeMapper.h b/llvm/include/llvm/ABI/QualTypeMapper.h
deleted file mode 100644
index f408325dad007..0000000000000
--- a/llvm/include/llvm/ABI/QualTypeMapper.h
+++ /dev/null
@@ -1,52 +0,0 @@
-#ifndef LLVM_ABI_QUALTYPE_MAPPER_H
-#define LLVM_ABI_QUALTYPE_MAPPER_H
-
-#include "llvm/Support/Allocator.h"
-#include <clang/AST/ASTContext.h>
-#include <clang/AST/Type.h>
-#include <llvm/ABI/Types.h>
-#include <llvm/ADT/DenseMap.h>
-
-namespace llvm {
-namespace abi {
-
-class QualTypeMapper {
-private:
-  clang::ASTContext &ASTCtx;
-  TypeBuilder Builder;
-
-  // llvm::DenseMap<clang::QualType	, const Type*> TypeCache;
-
-  const Type *convertBuiltinType(const clang::BuiltinType *BT);
-  const Type *convertPointerType(const clang::PointerType *PT);
-  const Type *convertArrayType(const clang::ArrayType *AT);
-  const Type *convertVectorType(const clang::VectorType *VT);
-  const Type *convertRecordType(const clang::RecordType *RT);
-  const Type *convertFunctionType(const clang::FunctionProtoType *FT);
-  const Type *convertEnumType(const clang::EnumType *ET);
-
-  void computeRecordLayout(const clang::RecordDecl *RD,
-                           llvm::SmallVectorImpl<FieldInfo> &Fields,
-                           uint64_t &TotalSize, uint64_t &Alignment,
-                           StructPacking &Packing);
-
-  uint64_t getTypeSize(clang::QualType QT) const;
-  uint64_t getTypeAlign(clang::QualType QT) const;
-  uint64_t getPointerSize() const;
-  uint64_t getPointerAlign() const;
-
-public:
-  explicit QualTypeMapper(clang::ASTContext &Ctx, BumpPtrAllocator &Alloc)
-      : ASTCtx(Ctx), Builder(Alloc) {}
-
-  const Type *convertType(clang::QualType QT);
-
-  // void clearCache() {TypeCache.clear();}
-
-  TypeBuilder getTypeBuilder() { return Builder; }
-};
-
-} // namespace abi
-} // namespace llvm
-
-#endif // !LLVM_ABI_QUALTYPE_MAPPER_H
diff --git a/llvm/lib/ABI/CMakeLists.txt b/llvm/lib/ABI/CMakeLists.txt
deleted file mode 100644
index d6aa9b542cc05..0000000000000
--- a/llvm/lib/ABI/CMakeLists.txt
+++ /dev/null
@@ -1,17 +0,0 @@
-add_llvm_component_library(LLVMABI
-  QualTypeMapper.cpp
-
-  ADDITIONAL_HEADER_DIRS
-  ${LLVM_MAIN_INCLUDE_DIR}/llvm/ABI
-
-  DEPENDS
-  intrinsics_gen
-
-  LINK_COMPONENTS
-  Core
-  Support
-)
-
-target_include_directories(LLVMABI PRIVATE
-  ${LLVM_MAIN_INCLUDE_DIR}
-)
diff --git a/llvm/lib/ABI/QualTypeMapper.cpp b/llvm/lib/ABI/QualTypeMapper.cpp
deleted file mode 100644
index fcf3555aaf369..0000000000000
--- a/llvm/lib/ABI/QualTypeMapper.cpp
+++ /dev/null
@@ -1,16 +0,0 @@
-//===-- llvm/ABI/QualTypeMapper.cpp - QualType to ABI Mapping -------------===//
-//
-// 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 contains the logic for converting clang::Qualtype to
-// llvm::abi::Type for ABI Lowering
-//
-//===----------------------------------------------------------------------===//
-
-#include <llvm/ABI/QualTypeMapper.h>
-
-// TODO: Implementation of Qualtype -> abi::Type Mapping
diff --git a/llvm/lib/CMakeLists.txt b/llvm/lib/CMakeLists.txt
index b888f6637a925..c84690abda028 100644
--- a/llvm/lib/CMakeLists.txt
+++ b/llvm/lib/CMakeLists.txt
@@ -3,7 +3,7 @@ include(LLVM-Build)
 # `Demangle', `Support' and `TableGen' libraries are added on the top-level
 # CMakeLists.txt
 
-add_subdirectory(ABI)
+# add_subdirectory(ABI)
 add_subdirectory(IR)
 add_subdirectory(FuzzMutate)
 add_subdirectory(FileCheck)
diff --git a/llvm/test/Transforms/InstCombine/pblend_opt.ll b/llvm/test/Transforms/InstCombine/pblend_opt.ll
new file mode 100644
index 0000000000000..f7860229790a0
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/pblend_opt.ll
@@ -0,0 +1,18 @@
+; ModuleID = 'pblend.ll'
+source_filename = "pblend.ll"
+
+; Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
+define <16 x i8> @simple_blend(<16 x i8> %x, <16 x i8> %y, <4 x i32> %a) local_unnamed_addr #0 {
+entry:
+  %cmp = icmp sgt <4 x i32> %a, zeroinitializer
+  %sext = sext <4 x i1> %cmp to <4 x i32>
+  %mask = bitcast <4 x i32> %sext to <16 x i8>
+  %res = tail call <16 x i8> @llvm.x86.sse41.pblendvb(<16 x i8> %x, <16 x i8> %y, <16 x i8> %mask)
+  ret <16 x i8> %res
+}
+
+; Function Attrs: mustprogress nocallback nofree nosync nounwind willreturn memory(none)
+declare <16 x i8> @llvm.x86.sse41.pblendvb(<16 x i8>, <16 x i8>, <16 x i8>) #1
+
+attributes #0 = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
+attributes #1 = { mustprogress nocallback nofree nosync nounwind willreturn memory(none) }
diff --git a/output.ll b/output.ll
new file mode 100644
index 0000000000000..5f3e70b2f37b0
--- /dev/null
+++ b/output.ll
@@ -0,0 +1,39 @@
+; ModuleID = 'llvm/test/Transforms/InstCombine/pblend.ll'
+source_filename = "llvm/test/Transforms/InstCombine/pblend.ll"
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define <2 x i64> @tricky(<2 x i64> noundef %a, <2 x i64> noundef %b, <2 x i64> noundef %c, <2 x i64> noundef %src) {
+entry:
+  %0 = bitcast <2 x i64> %a to <4 x i32>
+  %cmp.i = icmp sgt <4 x i32> %0, zeroinitializer
+  %sext.i = sext <4 x i1> %cmp.i to <4 x i32>
+  %1 = bitcast <4 x i32> %sext.i to <2 x i64>
+  %2 = bitcast <2 x i64> %b to <4 x i32>
+  %cmp.i21 = icmp sgt <4 x i32> %2, zeroinitializer
+  %sext.i22 = sext <4 x i1> %cmp.i21 to <4 x i32>
+  %3 = bitcast <4 x i32> %sext.i22 to <2 x i64>
+  %4 = bitcast <2 x i64> %c to <4 x i32>
+  %cmp.i23 = icmp sgt <4 x i32> %4, zeroinitializer
+  %sext.i24 = sext <4 x i1> %cmp.i23 to <4 x i32>
+  %5 = bitcast <4 x i32> %sext.i24 to <2 x i64>
+  %and.i = and <2 x i64> %3, %1
+  %xor.i = xor <2 x i64> %and.i, %5
+  %and.i25 = and <2 x i64> %xor.i, %1
+  %and.i26 = and <2 x i64> %xor.i, %3
+  %and.i27 = and <2 x i64> %and.i, %src
+  %6 = bitcast <2 x i64> %and.i27 to <16 x i8>
+  %7 = bitcast <2 x i64> %a to <16 x i8>
+  %8 = bitcast <2 x i64> %and.i25 to <16 x i8>
+  %9 = tail call <16 x i8> @llvm.x86.sse41.pblendvb(<16 x i8> %6, <16 x i8> %7, <16 x i8> %8)
+  %10 = bitcast <2 x i64> %b to <16 x i8>
+  %11 = bitcast <2 x i64> %and.i26 to <16 x i8>
+  %12 = tail call <16 x i8> @llvm.x86.sse41.pblendvb(<16 x i8> %9, <16 x i8> %10, <16 x i8> %11)
+  %13 = bitcast <16 x i8> %12 to <2 x i64>
+  ret <2 x i64> %13
+}
+
+; Function Attrs: nocallback nofree nosync nounwind willreturn memory(none)
+declare <16 x i8> @llvm.x86.sse41.pblendvb(<16 x i8>, <16 x i8>, <16 x i8>) #0
+
+attributes #0 = { nocallback nofree nosync nounwind willreturn memory(none) }



More information about the cfe-commits mailing list