This is an archive of the discontinued LLVM Phabricator instance.

Make lround builtin constexpr (and others)
Needs ReviewPublic

Authored by zoecarver on Aug 27 2019, 9:00 PM.

Details

Summary

This patch makes some of the lround and lrint builtins constant expressions. Resolves issue 38322.

I can update more builtins but, first wanted to make sure this was the correct way of implementing the constexpr builtins.

Feel free to add other reviewers. I wasn't really sure who to add.

Event Timeline

zoecarver created this revision.Aug 27 2019, 9:00 PM
Herald added a project: Restricted Project. · View Herald TranscriptAug 27 2019, 9:00 PM
Herald added a subscriber: cfe-commits. · View Herald Transcript
zoecarver edited the summary of this revision. (Show Details)Aug 27 2019, 9:06 PM
zoecarver added reviewers: spatel, efriedma.
erichkeane accepted this revision.Aug 29 2019, 10:07 AM
erichkeane added a subscriber: erichkeane.

Small nit, just default construct the APFloats.

This revision is now accepted and ready to land.Aug 29 2019, 10:07 AM

What if the input is nan or infinity or out of range. The spec says an implementation defined value is returned. But we've deferred to whatever library we're compiled with. Which makes our implementation defined behavior outside of clang's control and it now depends on how clang is built.

erichkeane requested changes to this revision.Aug 29 2019, 10:15 AM

Craig topper pointed out to me that constexpr cannot throw exceptions, and at least the rints can raise some exceptions, which aren't allowed in Constexpr. The round functions similarly hit unspecified behavior, so we need to match that behavior.

This revision now requires changes to proceed.Aug 29 2019, 10:15 AM
lebedev.ri added inline comments.
clang/test/SemaCXX/math-builtins.cpp
6

Needs more tests
This looks like you always round up

(from IRC) Add tests for:

  • out of range
  • nan
  • rounding up _and_ down

Also, use the builtin APFloat methods.

rsmith requested changes to this revision.Aug 29 2019, 12:27 PM
rsmith added a subscriber: rsmith.
rsmith added inline comments.
clang/lib/AST/ExprConstant.cpp
9612

It's non-conforming to accept calls to these non-__builtin functions in constant expression evaluation, but it's fine to constant-fold them. Please issue a CCEDiag diagnostic for them (take a look at what we do for Builtin::BIstrlen or Builtin::BIstrcmp for an example; it would probably be reasonable to factor out a local lambda to issue suitable diagnostics for this case).

(For example, we are required to produce a diagnostic for constexpr long n = lround(1.2);, but we are permitted to constant-fold long n = lround(1.2); and emit it with static initialization.)

9616

This assumes that the host double has the same behavior as the target double, which is not true in general. Generally the right thing to do is to implement the relevant functionality on APFloat, taking care to produce the right answer for the floating-point model being used by that APFloat. This also assumes that the host long is the same size as the target long, which again is not true in general. Finally, you need to catch the case where the APFloat does not fit into the target type; in that case, the best response is probably to treat the evaluation as non-constant and leave it to the runtime library to implement whatever error response it chooses.

zoecarver updated this revision to Diff 217973.Aug 29 2019, 2:14 PM
  • remove rint updates (rint uses runtime-defined rounding method)
  • add more tests (nan, overflow, round down)
  • use APFloat rounding methods
  • if rounding fails, bail out to runtime
zoecarver marked 3 inline comments as done.Aug 29 2019, 2:20 PM
zoecarver added inline comments.
clang/lib/AST/ExprConstant.cpp
9612

Thank you for pointing this out. I will do that in a separate patch.

9616

I've updated it to do just that: if there is an error, it will treat this evaluation as non-constant and leave it for the runtime library to handle.

How should I determine the width of the APInt? Because it is run at compile-time, can I use the max size (long long)? Either way, how should I get the correct size, maybe from a builtin long type?

clang/test/SemaCXX/math-builtins.cpp
21

For some reasons, these expected-errors aren't being caught by lit. Any ideas? Do I need to put it in a .fail.cpp file or add something to the RUN: comment?

lebedev.ri added inline comments.Aug 29 2019, 2:26 PM
clang/test/SemaCXX/math-builtins.cpp
2

-verify ?

lebedev.ri added inline comments.Aug 29 2019, 2:28 PM
clang/lib/AST/ExprConstant.cpp
9616

You probably want to look at the original callexpr, take it's return type, and look it up in typesystem (i'm not sure exactly how to do that here)

zoecarver marked 2 inline comments as done.Aug 29 2019, 2:32 PM
zoecarver added inline comments.
clang/lib/AST/ExprConstant.cpp
9616

Ah, good idea. Will do.

clang/test/SemaCXX/math-builtins.cpp
2

Yes, that worked. It was throwing me off the first time I tried because it doesn't expect the nan tests to error. Any ideas on generating a nan float? Thanks for the help :)

craig.topper added inline comments.Aug 29 2019, 2:32 PM
clang/lib/AST/ExprConstant.cpp
9616

Info.Ctx.getIntWidth(E->getType()) I think.

zoecarver marked an inline comment as done.Aug 29 2019, 2:34 PM
zoecarver added inline comments.
clang/lib/AST/ExprConstant.cpp
9616

@craig.topper fantastic, you're the best!

craig.topper added inline comments.Aug 29 2019, 2:37 PM
clang/lib/AST/ExprConstant.cpp
9620

Space after if

9623

Space after if

zoecarver updated this revision to Diff 217976.Aug 29 2019, 2:37 PM
  • fix expected error
  • fix APInt width
  • fix nan tests
zoecarver updated this revision to Diff 217977.Aug 29 2019, 2:38 PM
  • fix: formatting
Harbormaster completed remote builds in B37540: Diff 217977.
rsmith added inline comments.Aug 29 2019, 2:54 PM
clang/lib/AST/ExprConstant.cpp
9617

Please use /*isUnsigned=*/false for the second argument rather than 0.

9618

Please capitalize local variable names to match the convention used in this file.

9625

Just return Success(IVal, E); here. Going via getExtValue will assert if the integer type is wider than 64 bits.

It's probably worth adding testcases for 0.5 and -0.5. I think the current implementation behaves correctly, but it would be easy to mess up with a small change to the code.

Are you intentionally excluding __builtin_lroundl/__builtin_llroundl?

clang/lib/AST/ExprConstant.cpp
9625

getExtVal call here is unnecessary.

zoecarver marked an inline comment as done.Aug 31 2019, 12:04 PM
zoecarver added inline comments.
clang/lib/AST/ExprConstant.cpp
9617

I'm using the default value of isUnsigned (false). Do you want me to specify it? The second argument (0) is the initial value (which is required).

Are you intentionally excluding builtin_lroundl/builtin_llroundl?

I was because convertToDouble could only return up to 64 bytes. But now that I am using the builtin APFloat round function, that works.

  • add roundl builtins
  • add more tests
  • address review comments

Ping. Anything else I am missing?