-
Notifications
You must be signed in to change notification settings - Fork 13.6k
nonblocking/nonallocating attributes: 2nd pass caller/callee analysis #99656
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 63 commits
8c5f854
95b7a00
21c780a
ff10413
d472964
f1142db
efe1b93
d4f8dd5
7ffdbef
c39e28e
dec1a61
06ca4c5
9e45e6f
b99f784
dbdd8f8
1b9874f
b8818a3
8390e69
7acda8c
bffacc5
c718b5a
8b225f4
2cb4539
0e07315
47dfce8
fddd9d2
eb536ab
15b399f
dfebc1a
82cb07d
a7060ad
f93ee01
6cc0a62
69e1ae6
076302e
7b891c6
d1fcceb
abcf022
47ebf27
6650c1f
250b80b
e8bcd9f
ea7f3fc
d1a39e2
75365ef
6aadec0
9b123a6
ba57bfb
54feb05
93cb74e
d583c85
cda1a9c
9c971c6
b23e942
9bfbe12
f06909b
adcfd14
17320b8
909d7ff
9367103
eb782e0
eccc7cf
220a1bf
a8fef93
092bc16
ca3f44a
424a74b
273871a
a77d4e3
f8d9189
da725c1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -49,6 +49,7 @@ | |
#include "llvm/Support/PointerLikeTypeTraits.h" | ||
#include "llvm/Support/TrailingObjects.h" | ||
#include "llvm/Support/type_traits.h" | ||
#include <bitset> | ||
#include <cassert> | ||
#include <cstddef> | ||
#include <cstdint> | ||
|
@@ -119,6 +120,8 @@ class EnumDecl; | |
class Expr; | ||
class ExtQualsTypeCommonBase; | ||
class FunctionDecl; | ||
class FunctionEffectsRef; | ||
class FunctionEffectKindSet; | ||
class FunctionEffectSet; | ||
class IdentifierInfo; | ||
class NamedDecl; | ||
|
@@ -4712,12 +4715,13 @@ class FunctionEffect { | |
public: | ||
/// Identifies the particular effect. | ||
enum class Kind : uint8_t { | ||
None = 0, | ||
NonBlocking = 1, | ||
NonAllocating = 2, | ||
Blocking = 3, | ||
Allocating = 4 | ||
NonBlocking = 0, | ||
NonAllocating = 1, | ||
Blocking = 2, | ||
Allocating = 3, | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would there be a value to an Also, is there some meaning to the values of the enums besides just wanting the default behavior of enums? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure, I'll add and use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, we get around that in a few places I think... perhaps you can find what we do in other enums? Not at a computer at the moment, else I'd help search. EDIT TO ADD: It might be "EndList = LastEntry" ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, yes, we do use it quite a bit, you can also see the = , so just do that and use it kinda thing IMO. |
||
}; | ||
constexpr static size_t KindCount = 4; | ||
|
||
/// Flags describing some behaviors of the effect. | ||
using Flags = unsigned; | ||
|
@@ -4743,8 +4747,6 @@ class FunctionEffect { | |
// be considered for uniqueness. | ||
|
||
public: | ||
FunctionEffect() : FKind(Kind::None) {} | ||
|
||
explicit FunctionEffect(Kind K) : FKind(K) {} | ||
|
||
/// The kind of the effect. | ||
|
@@ -4773,35 +4775,43 @@ class FunctionEffect { | |
case Kind::Blocking: | ||
case Kind::Allocating: | ||
return 0; | ||
case Kind::None: | ||
break; | ||
} | ||
llvm_unreachable("unknown effect kind"); | ||
} | ||
|
||
/// The description printed in diagnostics, e.g. 'nonblocking'. | ||
StringRef name() const; | ||
|
||
/// Return true if the effect is allowed to be inferred on the callee, | ||
/// which is either a FunctionDecl or BlockDecl. | ||
friend raw_ostream &operator<<(raw_ostream &OS, | ||
const FunctionEffect &Effect) { | ||
OS << Effect.name(); | ||
return OS; | ||
} | ||
|
||
/// Determine whether the effect is allowed to be inferred on the callee, | ||
/// which is either a FunctionDecl or BlockDecl. If the returned optional | ||
/// is empty, inference is permitted; otherwise it holds the effect which | ||
/// blocked inference. | ||
/// Example: This allows nonblocking(false) to prevent inference for the | ||
/// function. | ||
bool canInferOnFunction(const Decl &Callee) const; | ||
std::optional<FunctionEffect> | ||
effectProhibitingInference(const Decl &Callee, | ||
FunctionEffectKindSet CalleeFX) const; | ||
|
||
// Return false for success. When true is returned for a direct call, then the | ||
// FE_InferrableOnCallees flag may trigger inference rather than an immediate | ||
// diagnostic. Caller should be assumed to have the effect (it may not have it | ||
// explicitly when inferring). | ||
bool shouldDiagnoseFunctionCall(bool Direct, | ||
ArrayRef<FunctionEffect> CalleeFX) const; | ||
FunctionEffectKindSet CalleeFX) const; | ||
|
||
friend bool operator==(const FunctionEffect &LHS, const FunctionEffect &RHS) { | ||
friend bool operator==(FunctionEffect LHS, FunctionEffect RHS) { | ||
return LHS.FKind == RHS.FKind; | ||
} | ||
friend bool operator!=(const FunctionEffect &LHS, const FunctionEffect &RHS) { | ||
friend bool operator!=(FunctionEffect LHS, FunctionEffect RHS) { | ||
return !(LHS == RHS); | ||
} | ||
friend bool operator<(const FunctionEffect &LHS, const FunctionEffect &RHS) { | ||
friend bool operator<(FunctionEffect LHS, FunctionEffect RHS) { | ||
return LHS.FKind < RHS.FKind; | ||
} | ||
}; | ||
|
@@ -4829,13 +4839,14 @@ struct FunctionEffectWithCondition { | |
FunctionEffect Effect; | ||
EffectConditionExpr Cond; | ||
|
||
FunctionEffectWithCondition() = default; | ||
FunctionEffectWithCondition(const FunctionEffect &E, | ||
const EffectConditionExpr &C) | ||
FunctionEffectWithCondition(FunctionEffect E, const EffectConditionExpr &C) | ||
: Effect(E), Cond(C) {} | ||
|
||
/// Return a textual description of the effect, and its condition, if any. | ||
std::string description() const; | ||
|
||
friend raw_ostream &operator<<(raw_ostream &OS, | ||
const FunctionEffectWithCondition &CFE); | ||
}; | ||
|
||
/// Support iteration in parallel through a pair of FunctionEffect and | ||
|
@@ -4940,6 +4951,85 @@ class FunctionEffectsRef { | |
void dump(llvm::raw_ostream &OS) const; | ||
}; | ||
|
||
/// A mutable set of FunctionEffect::Kind. | ||
class FunctionEffectKindSet { | ||
Sirraide marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// For now this only needs to be a bitmap. | ||
constexpr static size_t EndBitPos = FunctionEffect::KindCount; | ||
using KindBitsT = std::bitset<EndBitPos>; | ||
|
||
KindBitsT KindBits{}; | ||
|
||
explicit FunctionEffectKindSet(KindBitsT KB) : KindBits(KB) {} | ||
|
||
// Functions to translate between an effect kind, starting at 1, and a | ||
// position in the bitset. | ||
|
||
constexpr static size_t kindToPos(FunctionEffect::Kind K) { | ||
return static_cast<size_t>(K); | ||
} | ||
|
||
constexpr static FunctionEffect::Kind posToKind(size_t Pos) { | ||
return static_cast<FunctionEffect::Kind>(Pos); | ||
} | ||
|
||
// Iterates through the bits which are set. | ||
class iterator { | ||
Sirraide marked this conversation as resolved.
Show resolved
Hide resolved
|
||
const FunctionEffectKindSet *Outer = nullptr; | ||
size_t Idx = 0; | ||
|
||
// If Idx does not reference a set bit, advance it until it does, | ||
// or until it reaches EndBitPos. | ||
void advanceToNextSetBit() { | ||
while (Idx < EndBitPos && !Outer->KindBits.test(Idx)) | ||
++Idx; | ||
} | ||
|
||
public: | ||
iterator(); | ||
iterator(const FunctionEffectKindSet &O, size_t I) : Outer(&O), Idx(I) { | ||
advanceToNextSetBit(); | ||
} | ||
bool operator==(const iterator &Other) const { return Idx == Other.Idx; } | ||
bool operator!=(const iterator &Other) const { return Idx != Other.Idx; } | ||
|
||
iterator operator++() { | ||
++Idx; | ||
advanceToNextSetBit(); | ||
return *this; | ||
} | ||
|
||
FunctionEffect operator*() const { | ||
assert(Idx < EndBitPos && "Dereference of end iterator"); | ||
return FunctionEffect(posToKind(Idx)); | ||
} | ||
}; | ||
|
||
public: | ||
FunctionEffectKindSet() = default; | ||
explicit FunctionEffectKindSet(FunctionEffectsRef FX) { insert(FX); } | ||
|
||
iterator begin() const { return iterator(*this, 0); } | ||
iterator end() const { return iterator(*this, EndBitPos); } | ||
|
||
void insert(FunctionEffect Effect) { KindBits.set(kindToPos(Effect.kind())); } | ||
void insert(FunctionEffectsRef FX) { | ||
for (FunctionEffect Item : FX.effects()) | ||
insert(Item); | ||
} | ||
void insert(FunctionEffectKindSet Set) { KindBits |= Set.KindBits; } | ||
|
||
bool empty() const { return KindBits.none(); } | ||
bool contains(const FunctionEffect::Kind EK) const { | ||
return KindBits.test(kindToPos(EK)); | ||
} | ||
void dump(llvm::raw_ostream &OS) const; | ||
|
||
static FunctionEffectKindSet difference(FunctionEffectKindSet LHS, | ||
FunctionEffectKindSet RHS) { | ||
return FunctionEffectKindSet(LHS.KindBits & ~RHS.KindBits); | ||
} | ||
}; | ||
|
||
/// A mutable set of FunctionEffects and possibly conditions attached to them. | ||
/// Used to compare and merge effects on declarations. | ||
/// | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would like some elaboration here, reading this after coming in 'cold' I have no idea what this means. Also, why double-tilde's? I think we only use 1 for these? Or is .rst different enough again...?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
RST needs double backticks for code, yeah. And the plan here is that we’ll add a link to the documentation (#109855) in a later pr (a bit like the release note above). Explaining what all of this is about is too much for a release note imo.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the help on the backticks. I think we could probably have the release notes still have a bit more detail. I don't need a full document, but at least a good sentence or of "here is what this is".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we can take this sentence from the documentation:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think even that is a little 'requires existing knowledge'? Basically, the audience for this is 'random redditor trying to figure out what features to use'. So we need to make sure anything like this is sufficiently titillating while not being so long as to lose interest.
For most bugs in release notes, we can assume that if the person cares about it, they know the details about the bug, but for features this is sort of our first chance to 'advertise' them. So I'd like something less vague/that gives some good 'hook' as to why the person wants to use it.
Perhaps I'll make @shafik come in, read the documentation enough to understand it, and propose some text :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I took a shot at something more "hook-y".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I still want @shafik to review it (as someone who hasn't been mentally 'poisoned' here by knowing too much about the feature), but perhaps his work is greatly reduced.