llvm libLLVMCore源码分析 19 - GlobalValue

源码路径

llvm\include\llvm\IR\GlobalValue.h

llvm\include\llvm\IR\GlobalIndirectSymbol.h

llvm\include\llvm\IR\GlobalAlias.h

llvm\include\llvm\IR\GlobalIFunc.h

llvm\include\llvm\IR\GlobalVariable.h

llvm\include\llvm\IR\Function.h

llvm GlobalValue class

在llvm中,GlobalValue用于表示可以在所有的函数中可见的Value(如全局变量,函数等)。

GlobalValue在llvm中都是Memory Objects,所以GlobalValue的Type都是指向存储内容的指针。

GlobalValue类的继承树如下:

GlobalIndirectSymbol

表示间接引用的GlobalObject,通过如下代码可以获取引用的GlobalObject:

const Constant *getIndirectSymbol() const {
    return getOperand(0);
  }

GlobalIndirectSymbol还有一个重要的方法,是getBaseObject:

const GlobalObject *getBaseObject(const DataLayout &DL, APInt &Offset) const {
    return dyn_cast<GlobalObject>(
        getIndirectSymbol()->stripAndAccumulateInBoundsConstantOffsets(DL,
                                                                       Offset));
  }

最终调用的是Value类的stripAndAccumulateConstantOffsets方法,该方法可以:

  • getelememtptr指令:返回指令的Operand,并将偏移累加到Offset。
  • bitcast或者addrspacecast指令:返回指令的Operand。
  • GlobalAlias对象:返回别名引用的对象。
  • call指令:返回具有返回值属性的操作数(?)。
const Value *
Value::stripAndAccumulateConstantOffsets(const DataLayout &DL, APInt &Offset,
                                         bool AllowNonInbounds) const {
  if (!getType()->isPtrOrPtrVectorTy())
    return this;

  unsigned BitWidth = Offset.getBitWidth();
  assert(BitWidth == DL.getIndexTypeSizeInBits(getType()) &&
         "The offset bit width does not match the DL specification.");

  // Even though we don't look through PHI nodes, we could be called on an
  // instruction in an unreachable block, which may be on a cycle.
  SmallPtrSet<const Value *, 4> Visited;
  Visited.insert(this);
  const Value *V = this;
  do {
    if (auto *GEP = dyn_cast<GEPOperator>(V)) {
      // If in-bounds was requested, we do not strip non-in-bounds GEPs.
      if (!AllowNonInbounds && !GEP->isInBounds())
        return V;

      // If one of the values we have visited is an addrspacecast, then
      // the pointer type of this GEP may be different from the type
      // of the Ptr parameter which was passed to this function.  This
      // means when we construct GEPOffset, we need to use the size
      // of GEP's pointer type rather than the size of the original
      // pointer type.
      APInt GEPOffset(DL.getIndexTypeSizeInBits(V->getType()), 0);
      if (!GEP->accumulateConstantOffset(DL, GEPOffset))
        return V;

      // Stop traversal if the pointer offset wouldn't fit in the bit-width
      // provided by the Offset argument. This can happen due to AddrSpaceCast
      // stripping.
      if (GEPOffset.getMinSignedBits() > BitWidth)
        return V;

      Offset += GEPOffset.sextOrTrunc(BitWidth);
      V = GEP->getPointerOperand();
    } else if (Operator::getOpcode(V) == Instruction::BitCast ||
               Operator::getOpcode(V) == Instruction::AddrSpaceCast) {
      V = cast<Operator>(V)->getOperand(0);
    } else if (auto *GA = dyn_cast<GlobalAlias>(V)) {
      if (!GA->isInterposable())
        V = GA->getAliasee();
    } else if (const auto *Call = dyn_cast<CallBase>(V)) {
        if (const Value *RV = Call->getReturnedArgOperand())
          V = RV;
    }
    assert(V->getType()->isPtrOrPtrVectorTy() && "Unexpected operand type!");
  } while (Visited.insert(V).second);

  return V;
}

GlobalAlias

GlobalObject的别名,可以通过getAliasee方法返回引用的GlobalObject:

  const Constant *getAliasee() const {
    return getIndirectSymbol();
  }
  Constant *getAliasee() {
    return getIndirectSymbol();
  }

GlobalAlias定义的语法如下:

@<Name> = [Linkage] [PreemptionSpecifier] [Visibility] [DLLStorageClass] [ThreadLocal] [(unnamed_addr|local_unnamed_addr)] alias <AliaseeTy>, <AliaseeTy>* @<Aliasee>
          [, partition "name"]

GlobalIFunc

表示间接函数Indirect Function,简称ifunc。ifunc是一种可以让开发者对同一个函数提供多种实现,在应用启动时再由动态加载器调用resolver函数(也由开发者实现)从多种实现中选择一种,并且在应用进程的生命周期内不再变化的机制。

下列代码既声明了一个ifunc "foo",通过resolver "resolve_foo"动态选择foo的实现:

extern int foo (int);

int my_foo(int a) {
	return a;
}

typedef int (* foo_func)(int);

static foo_func resolve_foo()
{
	return my_foo;
}

int foo (int) __attribute__ ((ifunc ("resolve_foo")));

在llvm的IR中,ifunc定义的语法如下:

@<Name> = [Linkage] [PreemptionSpecifier] [Visibility] ifunc <IFuncTy>, <ResolverTy>* @<Resolver>
          [, partition "name"]

将上述示例代码转换为IR后,可以看到ifunc foo的定义:

@foo = dso_local ifunc i32 (i32), bitcast (i32 (i32)* ()* @resolve_foo to i32 (i32)*)

在源代码中, GlobalIFunc类将Resolver存储在Operand中:

class GlobalIfunc {
  /// These methods retrieve and set ifunc resolver function.
  void setResolver(Constant *Resolver) {
    setIndirectSymbol(Resolver);
  }
  const Constant *getResolver() const {
    return getIndirectSymbol();
  }
  Constant *getResolver() {
    return getIndirectSymbol();
  }
};

GlobalObject

表示独立的对象,既GlobalVariable和Function。

GlobalVariable

表示全局变量,GlobalVariable定义语法如下:

@<GlobalVarName> = [Linkage] [PreemptionSpecifier] [Visibility]
                   [DLLStorageClass] [ThreadLocal]
                   [(unnamed_addr|local_unnamed_addr)] [AddrSpace]
                   [ExternallyInitialized]
                   <global | constant> <Type> [<InitializerConstant>]
                   [, section "name"] [, partition "name"]
                   [, comdat [($name)]] [, align <Alignment>]
                   (, !name !N)*

Function

表示函数,内容详见下一章(待补充)。

llvm Linkage

llvm中GlobalValue的Linkage类型如下所示:

enum LinkageTypes {
    ExternalLinkage = 0,///< Externally visible function
    AvailableExternallyLinkage, ///< Available for inspection, not emission.
    LinkOnceAnyLinkage, ///< Keep one copy of function when linking (inline)
    LinkOnceODRLinkage, ///< Same, but only replaced by something equivalent.
    WeakAnyLinkage,     ///< Keep one copy of named function when linking (weak)
    WeakODRLinkage,     ///< Same, but only replaced by something equivalent.
    AppendingLinkage,   ///< Special purpose, only applies to global arrays
    InternalLinkage,    ///< Rename collisions when linking (static functions).
    PrivateLinkage,     ///< Like Internal, but omit from symbol table.
    ExternalWeakLinkage,///< ExternalWeak linkage description.
    CommonLinkage       ///< Tentative definitions.
  };

external

external可以用于声明和定义,external的GlobalValue会参与链接,并且可以resolve外部符号引用。

available_externally

available_externally只可以用于定义,不可用于声明,available_externally的GlobalValue不会出现在生成的obj中。

linkonce

linkonce的GlobalValue在链接时相同名字的GlobalValue会被合并到一起。linkonce的GlobalValue不可以被Inline或类似的优化,因为链接时会将引用的地方替换为唯一的定义。如果需要使能inline及类似的优化,需要使用linkonce_odr。没有被引用的GlobalValue可以被丢弃。

linkonce_odr

类似linkonce,区别是GlobalValue在链接时,只有定义完全相同才会合并。

weak

类似linkonce,区别是没有被引用的GlobalValue不可以被丢弃。This is used for globals that are declared “weak” in C source code.

weak_odr

类似linkonce_odr,区别是没有被引用的GlobalValue不可以被丢弃。

appending

只能用于数组类型,链接时会将这些数组追加到一起,仅在llvm内部实现中(如llvm.global_ctors)使用。

internal

internal的GlobalValue只能被Module内引用,在链接时可以根据需要重命名以避免名称冲突,在obj的符号表中的为local symbol(如ELF中的STB_LOCAL)。和C语言中的static关键字语义相同。

private

类似internal,区别是不在obj的符号表中。

extern_weak

extern_weak的GlobalValue在链接时类似weak,如果没有找到定义,会被置为null,而不是一个未定义的引用。

common

和weak类似,区别是用于C语言中的tentative definitions,比如int X。common的GlobalValue必须由一个零初始化列表,不能被标记为constant。

llvm Visibility

llvm中GlobalValue的Visibility类型如下所示:

enum VisibilityTypes {
    DefaultVisibility = 0,  ///< The GV is visible
    HiddenVisibility,       ///< The GV is hidden
    ProtectedVisibility     ///< The GV is protected
  };

default

default的GlobalValue对所有的Module可见,可以被重载。

hidden

hidden的GlobalValue不在动态符号表中,其他的Module不可见。

protected

protected的GlobalValue对所有的Module可见,不可以被重载。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值