源码路径
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可见,不可以被重载。