llvm libLLVMCore源码分析 21 - Metadata Class

源码路径

llvm\include\llvm\IR\Metadata.h

llvm\include\llvm\IR\DebugInfoMetadata.h

llvm Metadata class

llvm IR中允许使用元数据附在指令和全局对象上,为优化器和代码生成器提供一些额外的信息(比如调试信息)。在llvm中,使用Metadata类表示元数据。Metadata类的继承树如下:

为了高效的管理Metadata对象,Metadata在llvm中的存储分为3种类型:

Uniqued:元数据内容在LLVMContext中唯一,如:%0 = !{ !"test\00", i32 10}。

Distinct:元数据内容在LLVMContext中不唯一,指示llvm不应该根据内容相同合并元数据,如:%0 = distinct !{ !"test\00", i32 10}。

Temporary:元数据内容为临时存在的,用于解决前置引用的问题,Temporary的Metadata会在resolve之后,转换为Uniqued或者Distinct。

MDString

MDString表示一个用双引号包围的字符串,如:!"test\00"

MDString的get方法返回一个MDString对象,MDString对象的Storage为Uniqued,在LLVMContext中唯一。

MDString *MDString::get(LLVMContext &Context, StringRef Str) {
  auto &Store = Context.pImpl->MDStringCache;
  auto I = Store.try_emplace(Str);
  auto &MapEntry = I.first->getValue();
  if (!I.second)
    return &MapEntry;
  MapEntry.Entry = &*I.first;
  return &MapEntry;
}

ValueAsMetadata

ValueAsMetadata类是一个wrapper,用于将Value继承树上的类封装为一个Metadata,这样就可以使用任何的Value子类作为Metadata。

ValueAsMetadata有2个子类:

  • ConstantAsMetadata:用于封装Constant子类的Value。
  • LocalAsMetadata:用于封装Function Local类的Value:Argument和Instruction。

ValueAsMetadata的get方法返回一个ValueAsMetadata对象,ValueAsMetadata对象的Storage为Uniqued,在LLVMContext中唯一。

ValueAsMetadata *ValueAsMetadata::get(Value *V) {
  assert(V && "Unexpected null Value");

  auto &Context = V->getContext();
  auto *&Entry = Context.pImpl->ValuesAsMetadata[V];
  if (!Entry) {
    assert((isa<Constant>(V) || isa<Argument>(V) || isa<Instruction>(V)) &&
           "Expected constant or function-local value");
    assert(!V->IsUsedByMD && "Expected this to be the only metadata use");
    V->IsUsedByMD = true;
    if (auto *C = dyn_cast<Constant>(V))
      Entry = new ConstantAsMetadata(C);
    else
      Entry = new LocalAsMetadata(V);
  }

  return Entry;
}

在get方法中:

  1. 查询Value所在的LLVMContext中是否已经存在ValueAsMetadata,如果存在,直接返回。
  2. 如果Value是Constant,则创建一个ConstantAsMetadata对象,如果Value是Function Local,则创建一个LocalAsMetadata对象。
  3. 将(Value,ValueAsMetadata)对插入LLVMContext中。

ValueAsMetadata类定义如下:

class ValueAsMetadata : public Metadata, ReplaceableMetadataImpl {
    ...
};

ValueAsMetadata类继承了ReplaceableMetadataImpl,用ReplaceableMetadataImpl类来实现RAUW操作。原因是ValueAsMetadata封装的Value可能会进行RAUW操作,生成的新ValueAsMetadata可能与已有的Metadata冲突,需要合并两个Metadata保证Uniqued。代码如下:

void Value::doRAUW(Value *New, ReplaceMetadataUses ReplaceMetaUses) {
  if (ReplaceMetaUses == ReplaceMetadataUses::Yes && isUsedByMetadata())
    ValueAsMetadata::handleRAUW(this, New);
}

void ValueAsMetadata::handleRAUW(Value *From, Value *To) {
  LLVMContext &Context = From->getType()->getContext();
  auto &Store = Context.pImpl->ValuesAsMetadata;
  auto I = Store.find(From);
  if (I == Store.end()) {
    assert(!From->IsUsedByMD && "Expected From not to be used by metadata");
    return;
  }

  // Remove old entry from the map.
  From->IsUsedByMD = false;
  ValueAsMetadata *MD = I->second;
  Store.erase(I);

  if (isa<LocalAsMetadata>(MD)) {
    if (auto *C = dyn_cast<Constant>(To)) {
      // Local became a constant.
      MD->replaceAllUsesWith(ConstantAsMetadata::get(C));
      delete MD;
      return;
    }
    if (getLocalFunctionMetadata(From) && getLocalFunctionMetadata(To) &&
        getLocalFunctionMetadata(From) != getLocalFunctionMetadata(To)) {
      // DISubprogram changed.
      MD->replaceAllUsesWith(nullptr);
      delete MD;
      return;
    }
  } else if (!isa<Constant>(To)) {
    // Changed to function-local value.
    MD->replaceAllUsesWith(nullptr);
    delete MD;
    return;
  }

  auto *&Entry = Store[To];
  if (Entry) {
    // The target already exists.
    MD->replaceAllUsesWith(Entry);
    delete MD;
    return;
  }

  // Update MD in place (and update the map entry).
  assert(!To->IsUsedByMD && "Expected this to be the only metadata use");
  To->IsUsedByMD = true;
  MD->V = To;
  Entry = MD;
}

DistinctMDOperandPlaceholder

DistinctMDOperandPlaceholder用作为Distinct MDNode的Operand,解决前置引用下MDNode要先于Operand创建的问题,DistinctMDOperandPlaceholder的Storage是Distinct的。常见的用法如下:

  DistinctMDOperandPlaceholder PH0(7);
  DistinctMDOperandPlaceholder PH1(3);
  Metadata *Ops[] = {&PH0, &PH1};
  auto *D = MDTuple::getDistinct(Context, Ops);
  auto *N0 = MDTuple::get(Context, None);
  auto *N1 = MDTuple::get(Context, N0);
  PH0.replaceUseWith(N0);
  PH1.replaceUseWith(N1);

DistinctMDOperandPlaceholder的RAUW实现如下:

/// Replace the use of this with MD.
  void replaceUseWith(Metadata *MD) {
    if (!Use)
      return;
    *Use = MD;

    if (*Use)
      MetadataTracking::track(*Use);

    Metadata *T = cast<Metadata>(this);
    MetadataTracking::untrack(T);
    assert(!Use && "Use is still being tracked despite being untracked!");
  }

通过MetadataTracking类将对本对象的Use,替换为新的MD。

MDNode

MDNode表示复合类型元数据,如:!{ !"test\00", i32 10}。

MDNode的Storage可以是Uniqued,也可以是Distinct,还可以是Temporary:在前置引用resolve之后再决定是Uniqued还是Distinct。

MDNode的构造函数如下,MDNode通过Operand引用其他Metadata(MDString/ValueAsMetadata/DistinctMDOperandPlaceholder),也可以引用MDNode:

MDNode::MDNode(LLVMContext &Context, unsigned ID, StorageType Storage,
               ArrayRef<Metadata *> Ops1, ArrayRef<Metadata *> Ops2)
    : Metadata(ID, Storage), NumOperands(Ops1.size() + Ops2.size()),
      NumUnresolved(0), Context(Context) {
  unsigned Op = 0;
  for (Metadata *MD : Ops1)
    setOperand(Op++, MD);
  for (Metadata *MD : Ops2)
    setOperand(Op++, MD);

  if (!isUniqued())
    return;

  // Count the unresolved operands.  If there are any, RAUW support will be
  // added lazily on first reference.
  countUnresolvedOperands();
}

MDNode的继承树如下:

MDTuple既简单的Metadata元组,通过get方法可以创建一个新的MDTuple:

static MDTuple *get(LLVMContext &Context, ArrayRef<Metadata *> MDs) {
    return getImpl(Context, MDs, Uniqued);
}

MDTuple *MDTuple::getImpl(LLVMContext &Context, ArrayRef<Metadata *> MDs,
                          StorageType Storage, bool ShouldCreate) {
  unsigned Hash = 0;
  if (Storage == Uniqued) {
    MDTupleInfo::KeyTy Key(MDs);
    if (auto *N = getUniqued(Context.pImpl->MDTuples, Key))
      return N;
    if (!ShouldCreate)
      return nullptr;
    Hash = Key.getHash();
  } else {
    assert(ShouldCreate && "Expected non-uniqued nodes to always be created");
  }

  return storeImpl(new (MDs.size()) MDTuple(Context, Storage, Hash, MDs),
                   Storage, Context.pImpl->MDTuples);
}

template <class T, class StoreT>
T *MDNode::storeImpl(T *N, StorageType Storage, StoreT &Store) {
  switch (Storage) {
  case Uniqued:
    Store.insert(N);
    break;
  case Distinct:
    N->storeDistinctInContext();
    break;
  case Temporary:
    break;
  }
  return N;
}

在get方法中:

  1. 计算元组的Operand的Hash值。
  2. 如果Storage是Uniqued,则查询LLVMContext中是否已经存在该MDTuple,存在则直接返回。
  3. 否则新创建一个MDTuple对象,如果Storage是Uniqued或Distinct,插入LLVMContext。

MDNode其余子类均和调试信息强相关,在后续文章中分析。

Named Metadata

Named metadata是MDNode的有名集合,使用Operands存储包含的MDNode,Named Metadata会被放到Module的Symbol Table中。

语法:

; Some unnamed metadata nodes, which are referenced by the named metadata.
!0 = !{!"zero"}
!1 = !{!"one"}
!2 = !{!"two"}
; A named metadata.
!name = !{!0, !1, !2}

MetadataAsValue

在一些intrinsic中,需要使用Metadata作为Operand,而Operand又必须是Value类型,llvm使用MetadataAsValue来实现。MetadataAsValue是对Metadata类的封装,提供get方法用于将Metadata转换为Value:

MetadataAsValue *MetadataAsValue::get(LLVMContext &Context, Metadata *MD) {
  MD = canonicalizeMetadataForValue(Context, MD);
  auto *&Entry = Context.pImpl->MetadataAsValues[MD];
  if (!Entry)
    Entry = new MetadataAsValue(Type::getMetadataTy(Context), MD);
  return Entry;
}

MetadataAsValue::MetadataAsValue(Type *Ty, Metadata *MD)
    : Value(Ty, MetadataAsValueVal), MD(MD) {
  track();
}

void MetadataAsValue::track() {
  if (MD)
    MetadataTracking::track(&MD, *MD, *this);
}

在get方法中:

  1. 将Metadata进行标准化。
  2. 查询LLVMContext中是否已经存在该MetadataAsValue,如果存在,则直接返回MetadataAsValue。
  3. 否则新创建一个MetadataAsValue对象,再调用MetadataTracking::track建立MetadataAsValue对Metadata的Use关系,既MetadataAsValue是Metadata的Owner之一。再将(Metadata, MetadataAsValue)对插入LLVMContext中。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值