This is an archive of the discontinued LLVM Phabricator instance.

NFC: make AtomicOrdering an enum class
ClosedPublic

Authored by jfb on Apr 4 2016, 4:13 PM.

Details

Summary

In the context of http://wg21.link/lwg2445 C++ uses the concept of 'stronger' ordering but doesn't define it properly. This should be fixed in C++17 barring a small question that's still open.

The code currently plays fast and loose with the AtomicOrdering enum. Using an enum class is one step towards tightening things. I later also want to tighten related enums, such as clang's AtomicOrderingKind (which should be shared with LLVM as a 'C++ ABI' enum).

This change touches a few lines of code which can be improved later, I'd like to keep it as NFC for now as it's already quite complex and requires sychronize-with clang.

Diff Detail

Repository
rL LLVM

Event Timeline

jfb updated this revision to Diff 52636.Apr 4 2016, 4:13 PM
jfb retitled this revision from to NFC: make AtomicOrdering an enum class.
jfb updated this object.
jfb added reviewers: jyknight, reames.
jfb added a subscriber: llvm-commits.
jfb added a comment.Apr 4 2016, 4:24 PM

Secret note: I'm also hoping that this is a small step towards making consume easier to experiment with. Shh don't tell anyone.

include/llvm/IR/Instructions.h
64 ↗(On Diff #52636)

This never happens. I can make it unreachable if that seems better.

jyknight edited edge metadata.Apr 6 2016, 8:20 AM

I'm a bit wondering what was the point of making it an enum class? It looks like what you were going for is to remove < and > comparisons with the AtomicOrdering values, and to always use more explicit accessors. But, enum class doesn't actually prevent that, right?

include/llvm/IR/Instructions.h
76 ↗(On Diff #52636)

the "i.e."s here seem pretty obvious from the code

300 ↗(On Diff #52636)

This comment is not actually related to your patch:

I notice this code here (and in other cases below) is depending on the AtomicOrdering values fitting in *3* bits, while the code in AtomicSDNode is checking that it fits in *4* bits. That seems an unfortunate discrepency.

lib/Analysis/MemoryDependenceAnalysis.cpp
521 ↗(On Diff #52636)

Is this an unintentional change? It used to be enforcing ordering requirements on Monotonic or stronger, not only stronger-than Monotonic.

jfb updated this revision to Diff 52821.Apr 6 2016, 10:44 AM
jfb marked an inline comment as done.
jfb edited edge metadata.
  • Address comments.
jfb added a comment.Apr 6 2016, 10:48 AM

I'm a bit wondering what was the point of making it an enum class? It looks like what you were going for is to remove < and > comparisons with the AtomicOrdering values, and to always use more explicit accessors. But, enum class doesn't actually prevent that, right?

Correct, it doesn't prevent it. I want to get this basic change in, and then figure out what the best approach is. I'm not a fan of creating a class for this purpose, seems too heave a solution.

One thing I can do is:

void operator<(AtomicOrdering, AtomicOrdering) {}
void operator>(AtomicOrdering, AtomicOrdering) {}
void operator<=(AtomicOrdering, AtomicOrdering) {}
void operator>=(AtomicOrdering, AtomicOrdering) {}

That'll require fixing the uses of comparison that are OK right now.

WDYT? I can do it in this patch if you want.

include/llvm/IR/Instructions.h
300 ↗(On Diff #52636)

Right, there are a few such things around the codebase :-)

lib/Analysis/MemoryDependenceAnalysis.cpp
521 ↗(On Diff #52636)

Oof yes, good catch! Fixed.

If we're having this churn, I'd at least like to get some safety out of it. :) Looks like = delete would work:

bool operator<(AtomicOrdering, AtomicOrdering) = delete;
bool operator>(AtomicOrdering, AtomicOrdering) = delete;
bool operator<=(AtomicOrdering, AtomicOrdering) = delete;
bool operator>=(AtomicOrdering, AtomicOrdering) = delete;
jfb updated this revision to Diff 52835.Apr 6 2016, 12:39 PM
  • Delete comparison operators.
jfb added a comment.Apr 6 2016, 12:42 PM

If we're having this churn, I'd at least like to get some safety out of it. :) Looks like = delete would work:

bool operator<(AtomicOrdering, AtomicOrdering) = delete;
bool operator>(AtomicOrdering, AtomicOrdering) = delete;
bool operator<=(AtomicOrdering, AtomicOrdering) = delete;
bool operator>=(AtomicOrdering, AtomicOrdering) = delete;

Ha, C++11!

I did this and created two new methods to stand in for comparison. MergeFunctions still does a full-on comparison but that's OK because all it wants is a way to order all Instruction (it doesn't care about atomic ordering).

I created D18840 to update clang accordingly. If it all looks good to you I propose that I commit this patch *without* the deleted operators, then commit the clang one, and then commit the deleted operators. That avoids the dependency with clang, which will reduce bots being sad if they don't sync intelligently (and then send me mail about it).

jfb updated this revision to Diff 52837.Apr 6 2016, 12:44 PM
  • Update docs.
jfb updated this revision to Diff 52840.Apr 6 2016, 12:51 PM
  • Update comments, use array.
jyknight accepted this revision.Apr 6 2016, 1:51 PM
jyknight edited edge metadata.

Your plan sounds fine.

This revision is now accepted and ready to land.Apr 6 2016, 1:51 PM
jfb updated this revision to Diff 52849.Apr 6 2016, 2:17 PM
jfb edited edge metadata.
  • Remove comparison for now.
This revision was automatically updated to reflect the committed changes.

This breaks the ability to hash them :)

IE, i have a hash function that does:
return hash_combine(A->getType(), A->getPointerOperand()->getType(),

A->getValueOperand()->getType(), A->isVolatile(),
A->getAlignment(), A->getOrdering(),
A->getSynchScope());

now the hash on getOrdering fails with wonderful template messages.

Can you define hash_value for it (see ADT/Hashing.h)?

(The hash works on getSynchScope because it's not an enum class, just an
enum)

BTW, this is what i came up with, not sure if anyone has a better way

inline hash_code hash_value(const AtomicOrdering &AO) {

return static_cast<typename

std::underlying_type<AtomicOrdering>::type>(AO);
}

jfb added a comment.Apr 9 2016, 12:50 PM

BTW, this is what i came up with, not sure if anyone has a better way

inline hash_code hash_value(const AtomicOrdering &AO) {

return static_cast<typename

std::underlying_type<AtomicOrdering>::type>(AO);
}

This should be fixed by D18938. It turns out hashing all enum classes was already *intended* to work.