diff options
author | Leonard Chan <leonardchan@google.com> | 2020-04-01 15:25:04 -0700 |
---|---|---|
committer | Leonard Chan <leonardchan@google.com> | 2020-11-19 10:26:17 -0800 |
commit | a97f62837f59620a60b3ed9f29568440c7d0553a (patch) | |
tree | 360eb006af37d0abe1f40757db6f4da7b5246984 /llvm/lib/Analysis/ConstantFolding.cpp | |
parent | 2f3adc54b57356cd207ded2ec2d7f4e1273da0ff (diff) | |
download | llvm-a97f62837f59620a60b3ed9f29568440c7d0553a.zip llvm-a97f62837f59620a60b3ed9f29568440c7d0553a.tar.gz llvm-a97f62837f59620a60b3ed9f29568440c7d0553a.tar.bz2 |
[llvm][IR] Add dso_local_equivalent Constant
The `dso_local_equivalent` constant is a wrapper for functions that represents a
value which is functionally equivalent to the global passed to this. That is, if
this accepts a function, calling this constant should have the same effects as
calling the function directly. This could be a direct reference to the function,
the `@plt` modifier on X86/AArch64, a thunk, or anything that's equivalent to the
resolved function as a call target.
When lowered, the returned address must have a constant offset at link time from
some other symbol defined within the same binary. The address of this value is
also insignificant. The name is leveraged from `dso_local` where use of a function
or variable is resolved to a symbol in the same linkage unit.
In this patch:
- Addition of `dso_local_equivalent` and handling it
- Update Constant::needsRelocation() to strip constant inbound GEPs and take
advantage of `dso_local_equivalent` for relative references
This is useful for the [Relative VTables C++ ABI](https://reviews.llvm.org/D72959)
which makes vtables readonly. This works by replacing the dynamic relocations for
function pointers in them with static relocations that represent the offset between
the vtable and virtual functions. If a function is externally defined,
`dso_local_equivalent` can be used as a generic wrapper for the function to still
allow for this static offset calculation to be done.
See [RFC](http://lists.llvm.org/pipermail/llvm-dev/2020-August/144469.html) for more details.
Differential Revision: https://reviews.llvm.org/D77248
Diffstat (limited to 'llvm/lib/Analysis/ConstantFolding.cpp')
-rw-r--r-- | llvm/lib/Analysis/ConstantFolding.cpp | 21 |
1 files changed, 18 insertions, 3 deletions
diff --git a/llvm/lib/Analysis/ConstantFolding.cpp b/llvm/lib/Analysis/ConstantFolding.cpp index bf44537..d68998d 100644 --- a/llvm/lib/Analysis/ConstantFolding.cpp +++ b/llvm/lib/Analysis/ConstantFolding.cpp @@ -295,7 +295,11 @@ Constant *FoldBitCast(Constant *C, Type *DestTy, const DataLayout &DL) { /// If this constant is a constant offset from a global, return the global and /// the constant. Because of constantexprs, this function is recursive. bool llvm::IsConstantOffsetFromGlobal(Constant *C, GlobalValue *&GV, - APInt &Offset, const DataLayout &DL) { + APInt &Offset, const DataLayout &DL, + DSOLocalEquivalent **DSOEquiv) { + if (DSOEquiv) + *DSOEquiv = nullptr; + // Trivial case, constant is the global. if ((GV = dyn_cast<GlobalValue>(C))) { unsigned BitWidth = DL.getIndexTypeSizeInBits(GV->getType()); @@ -303,6 +307,15 @@ bool llvm::IsConstantOffsetFromGlobal(Constant *C, GlobalValue *&GV, return true; } + if (auto *FoundDSOEquiv = dyn_cast<DSOLocalEquivalent>(C)) { + if (DSOEquiv) + *DSOEquiv = FoundDSOEquiv; + GV = FoundDSOEquiv->getGlobalValue(); + unsigned BitWidth = DL.getIndexTypeSizeInBits(GV->getType()); + Offset = APInt(BitWidth, 0); + return true; + } + // Otherwise, if this isn't a constant expr, bail out. auto *CE = dyn_cast<ConstantExpr>(C); if (!CE) return false; @@ -310,7 +323,8 @@ bool llvm::IsConstantOffsetFromGlobal(Constant *C, GlobalValue *&GV, // Look through ptr->int and ptr->ptr casts. if (CE->getOpcode() == Instruction::PtrToInt || CE->getOpcode() == Instruction::BitCast) - return IsConstantOffsetFromGlobal(CE->getOperand(0), GV, Offset, DL); + return IsConstantOffsetFromGlobal(CE->getOperand(0), GV, Offset, DL, + DSOEquiv); // i32* getelementptr ([5 x i32]* @a, i32 0, i32 5) auto *GEP = dyn_cast<GEPOperator>(CE); @@ -321,7 +335,8 @@ bool llvm::IsConstantOffsetFromGlobal(Constant *C, GlobalValue *&GV, APInt TmpOffset(BitWidth, 0); // If the base isn't a global+constant, we aren't either. - if (!IsConstantOffsetFromGlobal(CE->getOperand(0), GV, TmpOffset, DL)) + if (!IsConstantOffsetFromGlobal(CE->getOperand(0), GV, TmpOffset, DL, + DSOEquiv)) return false; // Otherwise, add any offset that our operands provide. |