LLVM积累

10 分钟阅读

官网介绍:llvm

github源码:llvm-project

RTTI

阅读:How to set up LLVM-style RTTI for your class hierarchy

llvm有这些RTTI接口可以使用isa<>dyn_cast<>cast<>等等。

使用这些接口,父类和子列有这些要求:

  • 父类:定义Kind枚举,且构造函数用Kind做入参
  • 子列:构造函数指定kind,且定义classof接口

使用时如果入参可能是空指针,则需要调用dyn_cast_or_null<>转换。

范例如下:

#include "llvm/Support/Casting.h"
class Shape {
 public:
   /// Discriminator for LLVM-style RTTI (dyn_cast<> et al.)
   enum ShapeKind {
     SK_Square,
     SK_Circle
   };
 private:
   const ShapeKind Kind;
 public:
   ShapeKind getKind() const { return Kind; }

   Shape(ShapeKind K) : Kind(K) {}
   virtual double computeArea() = 0;
 };

 class Square : public Shape {
   double SideLength;
 public:
   Square(double S) : Shape(SK_Square), SideLength(S) {}
   double computeArea() override;

   static bool classof(const Shape *S) {
     return S->getKind() == SK_Square;
   }
 };

 class Circle : public Shape {
   double Radius;
 public:
   Circle(double R) : Shape(SK_Circle), Radius(R) {}
   double computeArea() override;

   static bool classof(const Shape *S) {
     return S->getKind() == SK_Circle;
   }
 };

使用参考如下:

Shape *S = ...;
if (isa<Circle>(S)) {
  /* do something ... */
}

数据结构

ArrayRef

头文件include/llvm/ADT/ArrayRef.h,对常量数组的引用,但不包含数组本身。

定义如下:

template<typename T>
class ArrayRef {
  private:
    /// The start of the array, in an external buffer.
    const T *Data = nullptr;
    /// The number of elements.
    size_type Length = 0;
  public:
    /// Construct an ArrayRef from a pointer and length.
    ArrayRef(const T *data, size_t length)
      : Data(data), Length(length) {}
    /// Construct an ArrayRef from a range.
    ArrayRef(const T *begin, const T *end)
      : Data(begin), Length(end - begin) {}
    iterator begin() const { return Data; }
    iterator end() const { return Data + Length; }
    /// empty - Check if the array is empty.
    bool empty() const { return Length == 0; }
    const T *data() const { return Data; }
    /// size - Get the array size.
    size_t size() const { return Length; }
    const T &operator[](size_t Index) const {
      assert(Index < Length && "Invalid index!");
      return Data[Index];
    }
    std::vector<T> vec() const {
      return std::vector<T>(Data, Data+Length);
    }
    operator std::vector<T>() const {
      return std::vector<T>(Data, Data+Length);
    }
    ......
};

可以看出它其实和std::vector功能类似,只是它不包含数据。

在很多数据传递的场景中,可以避免数据的反复拷贝。

StringRef

头文件include/llvm/ADT/StringRef.h,定义如下:

 class StringRef {
    private:
    /// The start of the string, in an external buffer.
    const char *Data = nullptr;
    /// The length of the string.
    size_t Length = 0;
    public:
       /// Construct a string ref from a cstring.
    constexpr StringRef(const char *Str)
        : Data(Str), Length(Str ? strLen(Str) : 0) {}
    /// Construct a string ref from a pointer and length.
    constexpr StringRef(const char *data, size_t length)
        : Data(data), Length(length) {}
    /// Construct a string ref from an std::string.
    StringRef(const std::string &Str)
      : Data(Str.data()), Length(Str.length()) {}
   std::string str() const;
   explicit operator std::string() const { return str(); }
   char operator[](size_t Index) const;
   bool startswith(StringRef Prefix) const;
   bool endswith(StringRef Suffix) const;
   std::string lower() const;
   std::string upper() const;
   StringRef trim(StringRef Chars = " \t\n\v\f\r") const;
   ......

与std::string功能类似,但不包含数据。

SmallVector

头文件llvm-project/llvm/include/llvm/ADT/SmallVector.h,定义如下:

template <typename T, unsigned N = CalculateSmallVectorDefaultInlinedElements<T>::value>
class SmallVector : public SmallVectorImpl<T>, SmallVectorStorage<T, N> {
public:
  SmallVector() : SmallVectorImpl<T>(N) {}

  ~SmallVector() {
    // Destroy the constructed elements in the vector.
    this->destroy_range(this->begin(), this->end());
  }

  explicit SmallVector(size_t Size, const T &Value = T())
    : SmallVectorImpl<T>(N) {
    this->assign(Size, Value);
  }
  ......

与std:vector功能类似,但是固定元素个数。在确定元素个数很少的情况下很有用。

DenseMap

与std::unordered_map功能一致,但是这有些区别:

翻译自这篇回答llvm::DenseMap and std::map

  • unordered_map每个value都单独申请内存保存,DenseMap的key和value使用一整块内存
  • DenseMap默认就申请64对Key/Value空间
  • DenseMap的iterators在插入操作后全部会失效

总体来说DenseMap的效率比较高,使用优先级高于unordered_map

遍历

for (auto it : llvm::zip(headBlock->getArguments(), operands))
    std::get<0>(it).replaceAllUsesWith(std::get<1>(it));

for (const auto &it : llvm::enumerate(returnOp.getOperands()))
    valuesToRepl[it.index()].replaceAllUsesWith(it.value());

贡献代码

参考链接Phabricator

  1. https://reviews.llvm.org/注册账号

  2. 使用以下方式之一创建patch:

    git show HEAD -U999999 > mypatch.patch
    git diff -U999999 @{u} > mypatch.patch
    git diff HEAD~1 -U999999 > mypatch.patch
    
  3. https://reviews.llvm.org/differential页面点击Create Diff,然后upload patch,Repository选择rG LLVM Github Monorepo,Visible To选择Public,然后选择Reviewers

  4. 如果有检视意见需要更新代码,则在旁边按钮点击Update Diff更新,然后再点击Add Action选择Review

  5. 初次提交没有合入代码权限,需要在comment中请帮忙合入,参考https://reviews.llvm.org/D150757。多次提交后可以发邮件申请代码合入权限。