LLVM User 重载 new 分析

关于 Value, User , Use 这三个类的一些介绍

Value 表示了 LLVM IR 中需要通过指令运行得到的值。 它是 Instruction 和 Function 的父类。每一个值都持有一个 Type 指针(表达了在 IR 中的值类型)和一个 Use 指针(指向了一个 use list)。

User (Value 的子类) 定义了使用值的接口。Instruction 和 Constants 这两个常见类都是 User 的子类。

Use 表示了了 User 实例对 Value 的使用。

有利于

  1. 通过 Use 查找对应的 User。
  2. 快速查找一个 Value 的所有 Use。

new 重载内存空间分配 - HungOfff 式 User

相关源码如下

void *User::operator new(size_t Size) {
  // Allocate space for a single Use*
  void *Storage = ::operator new(Size + sizeof(Use *));
  Use **HungOffOperandList = static_cast<Use **>(Storage);
  User *Obj = reinterpret_cast<User *>(HungOffOperandList + 1);
  Obj->NumUserOperands = 0;
  Obj->HasHungOffUses = true;
  Obj->HasDescriptor = false;
  *HungOffOperandList = nullptr;
  return Obj;
}

这种 new 下, User 的 HasHungOffUses 为 true

可以看到在分配 User 的空间时, 还额外地分配了一个 Use 的空间。这样获得一块可以放一个user+一个use 指针的空间。

低地址空间用于存放 Use 指针, 高地址空间存放 User。

初始化了 User 的一些值, 并设置 Use 指针为 nullptr

.-------...
| User
'-------'''
    |
    v
    .---.---.---.---...
    | P | P | P | P |
    '---'---'---'---'''

placement new, Intrusive 式User

两个 placement new 都调用了 allocateFixedOperandUser 方法

void *User::operator new(size_t Size, unsigned Us) {
  return allocateFixedOperandUser(Size, Us, 0);
}

void *User::operator new(size_t Size, unsigned Us, unsigned DescBytes) {
  return allocateFixedOperandUser(Size, Us, DescBytes);
}

allocateFixedOperandUser 方法如下


void *User::allocateFixedOperandUser(size_t Size, unsigned Us,
                                     unsigned DescBytes) {
  assert(Us < (1u << NumUserOperandsBits) && "Too many operands");

  static_assert(sizeof(DescriptorInfo) % sizeof(void *) == 0, "Required below");

  unsigned DescBytesToAllocate =
      DescBytes == 0 ? 0 : (DescBytes + sizeof(DescriptorInfo));
  assert(DescBytesToAllocate % sizeof(void *) == 0 &&
         "We need this to satisfy alignment constraints for Uses");

  uint8_t *Storage = static_cast<uint8_t *>(
      ::operator new(Size + sizeof(Use) * Us + DescBytesToAllocate));
  Use *Start = reinterpret_cast<Use *>(Storage + DescBytesToAllocate);
  Use *End = Start + Us;
  User *Obj = reinterpret_cast<User*>(End);
  Obj->NumUserOperands = Us;
  Obj->HasHungOffUses = false;
  Obj->HasDescriptor = DescBytes != 0;
  for (; Start != End; Start++)
    new (Start) Use(Obj);

  if (DescBytes != 0) {
    auto *DescInfo = reinterpret_cast<DescriptorInfo *>(Storage + DescBytes);
    DescInfo->SizeInBytes = DescBytes;
  }

  return Obj;
}

这种 new 下, User 的 HasHungOffUses 为 false

整体上, 这个函数会额外分配 Us 个 Use 实例和描述字符的空间。

低地址存放描述字符, 随后存放了 Use 实例, 最后是分配给 User 实例的空间。

又初始化了 User 的部分属性。 构造了 Us 个 Use 实例。

...---.---.---.---.-------...
  | P | P | P | P | User
'''---'---'---'---'-------'''

获取相应的 Use*

对于 HungOff 式 User , 提供了以下方法:

  const Use *getHungOffOperands() const {
    return *(reinterpret_cast<const Use *const *>(this) - 1);
  }

  Use *&getHungOffOperands() { return *(reinterpret_cast<Use **>(this) - 1); }

对于 Intrusive 式 User , 提供了以下方法:

  const Use *getIntrusiveOperands() const {
    return reinterpret_cast<const Use *>(this) - NumUserOperands;
  }

  Use *getIntrusiveOperands() {
    return reinterpret_cast<Use *>(this) - NumUserOperands;
  }

对于Value , 可以使用 users 方法遍历所有 user

参考

深入浅出 LLVM之 Value 、User 、Use 源码解析 - 知乎

LLVM Programmer’s Manual — LLVM 19.0.0git documentation

  • 12
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值