[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