This is an archive of the discontinued LLVM Phabricator instance.

[clang][Interp] Implement inv and neg unary operations
ClosedPublic

Authored by tbaeder on Aug 17 2022, 11:23 PM.

Details

Summary

Implement inverting and negating values

Diff Detail

Event Timeline

tbaeder created this revision.Aug 17 2022, 11:23 PM
Herald added a project: Restricted Project. · View Herald TranscriptAug 17 2022, 11:23 PM
tbaeder requested review of this revision.Aug 17 2022, 11:23 PM
Herald added a project: Restricted Project. · View Herald TranscriptAug 17 2022, 11:23 PM
Herald added a subscriber: cfe-commits. · View Herald Transcript
tbaeder added inline comments.Aug 17 2022, 11:25 PM
clang/lib/AST/Interp/ByteCodeExprGen.cpp
134–148

Implementing the IntegralToBoolean cast is not necessary for this change, but makes more tests possible.

erichkeane accepted this revision.Aug 18 2022, 6:25 AM
This revision is now accepted and ready to land.Aug 18 2022, 6:25 AM
shafik added a subscriber: shafik.Aug 18 2022, 12:22 PM
shafik added inline comments.
clang/lib/AST/Interp/ByteCodeExprGen.cpp
142

Can you explain this line?

clang/lib/AST/Interp/Interp.h
183

Shouldn't this be

I'd appreciate if we handled unary ~ and + soon after this

clang/lib/AST/Interp/ByteCodeExprGen.cpp
632

This is reachable and will always return true thanks to the magic of integer promotions:

void func() {
  bool b = true;
  b = ~b;
}
clang/test/AST/Interp/literals.cpp
2–15
shafik added inline comments.Aug 18 2022, 1:25 PM
clang/lib/AST/Interp/ByteCodeExprGen.cpp
142

Nevermind, I get it, you are emitting a 0 and then doing a not equal to zero to determine the result.

I feel like a comment explaining what is going on would be helpful for anyone not familiar with the code.

tbaeder added inline comments.Aug 18 2022, 1:35 PM
clang/lib/AST/Interp/ByteCodeExprGen.cpp
632

This code path is not just for boolean values though.

clang/lib/AST/Interp/Interp.h
183

Haha, yes. I already found this bug once before locally but now imported the broken version in my main branch. Thanks for catching that.

clang/test/AST/Interp/literals.cpp
2–15

That works as well but is also fixed after https://reviews.llvm.org/D132136

tbaeder marked 4 inline comments as done.Aug 19 2022, 12:44 AM
tbaeder updated this revision to Diff 453917.Aug 19 2022, 1:18 AM

When changing the test to use -verify=test, I noticed that static_assert(-false) did not assert.

I had to implement integral casts (only from sint32 to bool for now) in this patch as well to make it work.

tbaeder added inline comments.Aug 19 2022, 1:20 AM
clang/lib/AST/Interp/Integral.h
175

I'm a bit out of my element with the template magic here.

aaron.ballman added inline comments.Aug 19 2022, 5:03 AM
clang/lib/AST/Interp/ByteCodeExprGen.cpp
129–130
632

All the more reason to be worried about ~ being marked as unreachable (I mostly worry because people often try to make bit fiddling operations constant expressions when possible, so this seems pretty likely to be hit). Perhaps make it into an assert(false && "operation not supported yet"); or something more loud?

clang/lib/AST/Interp/Integral.h
175

It mostly looks correct to me, but the part I'm struggling with is static_cast<Integral::T>; can you explain what you're trying to do there?

tbaeder added inline comments.Aug 19 2022, 5:20 AM
clang/lib/AST/Interp/ByteCodeExprGen.cpp
632

How is that different? It's just a marker for me so I know later in development that this is not implemented yet. And now that I'm writing this, I guess I see what you mean. Yes, it's not unreachable, but it shouldn't be reached when testing what is currently implemented.

clang/lib/AST/Interp/Integral.h
175

I was trying to implement creating an Integral from a Boolean; the static_cast casts to Integral::T (which in my case is int). It might not be needed.

erichkeane added inline comments.Aug 19 2022, 5:29 AM
clang/lib/AST/Interp/ByteCodeExprGen.cpp
632

Aaron: we tend to NEVER use 'assert(false...' and instead use llvm_unreachable for 'not implemented yet' quite often in clang. I don't see the semantic difference here?

erichkeane added inline comments.Aug 19 2022, 5:36 AM
clang/lib/AST/Interp/ByteCodeExprGen.cpp
632

Aaron clarified offline: the problem is that llvm_unreachable inserts optimization hints in non-asserts builds, so the result is optimizer-caused-UB here. The preference for 'assert(false', though it causing an odd state, at least doesn't allow the optimizer to go hog wild.

So I agree with Aaron here.

We DO do this wrong in some places, which is unfortunate, but should be considered mistakes, not precedent.

aaron.ballman added inline comments.Aug 19 2022, 5:42 AM
clang/lib/AST/Interp/Integral.h
175

Oh!!! I see now why there's so much confusion. You have template <typename T> and I was wondering why you were trying to use that here. I see now that there's Integral::T as a private member.

Can we please rename Integral::T to be something mildly descriptive? (I'm fine if that's done in a follow-up as an NFC change.)

erichkeane added inline comments.Aug 19 2022, 5:47 AM
clang/lib/AST/Interp/Integral.h
175

As Aaron said separately, the 'T' name of the integral member is bonkers and confusing!

So it appears the intent here is to take a non-integral 'Value', cast it to the underlying representation, and then call the version of this on 159.

From a 'style' perspective, I'd prefer this live right next to that version (since it is the inverse SFINAE). In fact, I'd probably prefer you switch this to an 'if constexpr' instead:

template <typename ValTy>
static Integral from (ValTy Value) {
    if constexpr (std::is_integral_v<T>) {
       return Integral(Value);
    } else {
       return Integral(static_cast<Integral::RepTy>(Value));
    }
 }
}
tbaeder updated this revision to Diff 453968.Aug 19 2022, 6:02 AM
tbaeder added inline comments.
clang/lib/AST/Interp/Integral.h
175

That's a cool solution, thanks! And yes I'll push a renaming patch.

tbaeder marked an inline comment as done.Aug 19 2022, 6:04 AM
tbaeder updated this revision to Diff 453970.Aug 19 2022, 6:06 AM
This revision was automatically updated to reflect the committed changes.