diff options
author | Nikita Popov <npopov@redhat.com> | 2025-01-13 14:40:25 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-01-13 14:40:25 +0100 |
commit | 22e9024c9f374c0c740647829050c289673dbb11 (patch) | |
tree | e922529b1189c0423dfad083bd757023201bf16a /llvm/lib/IR/Attributes.cpp | |
parent | d6f7f2a5fa0e305253f936cdc8364eecfd568121 (diff) | |
download | llvm-22e9024c9f374c0c740647829050c289673dbb11.zip llvm-22e9024c9f374c0c740647829050c289673dbb11.tar.gz llvm-22e9024c9f374c0c740647829050c289673dbb11.tar.bz2 |
[IR] Introduce captures attribute (#116990)
This introduces the `captures` attribute as described in:
https://discourse.llvm.org/t/rfc-improvements-to-capture-tracking/81420
This initial patch only introduces the IR/bitcode support for the
attribute and its in-memory representation as `CaptureInfo`. This will
be followed by a patch to upgrade and remove the `nocapture` attribute,
and then by actual inference/analysis support.
Based on the RFC feedback, I've used a syntax similar to the `memory`
attribute, though the only "location" that can be specified is `ret`.
I've added some pretty extensive documentation to LangRef on the
semantics. One non-obvious bit here is that using ptrtoint will not
result in a "return-only" capture, even if the ptrtoint result is only
used in the return value. Without this requirement we wouldn't be able
to continue ordinary capture analysis on the return value.
Diffstat (limited to 'llvm/lib/IR/Attributes.cpp')
-rw-r--r-- | llvm/lib/IR/Attributes.cpp | 34 |
1 files changed, 33 insertions, 1 deletions
diff --git a/llvm/lib/IR/Attributes.cpp b/llvm/lib/IR/Attributes.cpp index e9daa01b..ceb3185 100644 --- a/llvm/lib/IR/Attributes.cpp +++ b/llvm/lib/IR/Attributes.cpp @@ -487,6 +487,12 @@ MemoryEffects Attribute::getMemoryEffects() const { return MemoryEffects::createFromIntValue(pImpl->getValueAsInt()); } +CaptureInfo Attribute::getCaptureInfo() const { + assert(hasAttribute(Attribute::Captures) && + "Can only call getCaptureInfo() on captures attribute"); + return CaptureInfo::createFromIntValue(pImpl->getValueAsInt()); +} + FPClassTest Attribute::getNoFPClass() const { assert(hasAttribute(Attribute::NoFPClass) && "Can only call getNoFPClass() on nofpclass attribute"); @@ -647,6 +653,13 @@ std::string Attribute::getAsString(bool InAttrGrp) const { return Result; } + if (hasAttribute(Attribute::Captures)) { + std::string Result; + raw_string_ostream OS(Result); + OS << getCaptureInfo(); + return Result; + } + if (hasAttribute(Attribute::NoFPClass)) { std::string Result = "nofpclass"; raw_string_ostream OS(Result); @@ -1050,6 +1063,10 @@ AttributeSet::intersectWith(LLVMContext &C, AttributeSet Other) const { Intersected.addMemoryAttr(Attr0.getMemoryEffects() | Attr1.getMemoryEffects()); break; + case Attribute::Captures: + Intersected.addCapturesAttr(Attr0.getCaptureInfo() | + Attr1.getCaptureInfo()); + break; case Attribute::NoFPClass: Intersected.addNoFPClassAttr(Attr0.getNoFPClass() & Attr1.getNoFPClass()); @@ -1170,6 +1187,10 @@ MemoryEffects AttributeSet::getMemoryEffects() const { return SetNode ? SetNode->getMemoryEffects() : MemoryEffects::unknown(); } +CaptureInfo AttributeSet::getCaptureInfo() const { + return SetNode ? SetNode->getCaptureInfo() : CaptureInfo::all(); +} + FPClassTest AttributeSet::getNoFPClass() const { return SetNode ? SetNode->getNoFPClass() : fcNone; } @@ -1358,6 +1379,12 @@ MemoryEffects AttributeSetNode::getMemoryEffects() const { return MemoryEffects::unknown(); } +CaptureInfo AttributeSetNode::getCaptureInfo() const { + if (auto A = findEnumAttribute(Attribute::Captures)) + return A->getCaptureInfo(); + return CaptureInfo::all(); +} + FPClassTest AttributeSetNode::getNoFPClass() const { if (auto A = findEnumAttribute(Attribute::NoFPClass)) return A->getNoFPClass(); @@ -2190,6 +2217,10 @@ AttrBuilder &AttrBuilder::addMemoryAttr(MemoryEffects ME) { return addRawIntAttr(Attribute::Memory, ME.toIntValue()); } +AttrBuilder &AttrBuilder::addCapturesAttr(CaptureInfo CI) { + return addRawIntAttr(Attribute::Captures, CI.toIntValue()); +} + AttrBuilder &AttrBuilder::addNoFPClassAttr(FPClassTest Mask) { if (Mask == fcNone) return *this; @@ -2350,7 +2381,8 @@ AttributeMask AttributeFuncs::typeIncompatible(Type *Ty, AttributeSet AS, .addAttribute(Attribute::DereferenceableOrNull) .addAttribute(Attribute::Writable) .addAttribute(Attribute::DeadOnUnwind) - .addAttribute(Attribute::Initializes); + .addAttribute(Attribute::Initializes) + .addAttribute(Attribute::Captures); if (ASK & ASK_UNSAFE_TO_DROP) Incompatible.addAttribute(Attribute::Nest) .addAttribute(Attribute::SwiftError) |