Live data from Hacker News

Two studies in compiler optimisations

hmpcabral.com

11–20 of 27 posts

Re: Two studies in compiler optimisations

#11
> Here, the simplification analysis uses the conditional hidden in the assert() macro to figure out that we only execute the urem instruction if cur It surprises me that the compiler doesn't still take the inference from the assert and just disable emitting the code to perform the check. Over the last 15 years I've worked on many codebases that are written with unnecessary asserts, partly as documentation, but maybe because people assumed it helped the compiler.

I've also worked on many codebases (and written code like this on my own projects) where the code looks like: assert(condition); if (condition) { ... } because I still want that safety check in release builds, and want the exception in debug builds but absolutely not ever in release builds.

Re: Two studies in compiler optimisations

#14

> Here, the simplification analysis uses the conditional hidden in the assert() macro to figure out that we only execute the urem instruction if cur It surprises me that the compiler doesn't still take the inference from the assert and just disable emitting the code to perform the check. Over the last 15 years I've worked on many codebases that are written with unnecessary asserts, partly as documentation, but maybe…

> It surprises me that the compiler doesn't still take the inference from the assert and just disable emitting the code to perform the check.

The compiler isn't as clever as I think you're envisioning: assert() only works that way because it exits the control flow if the statement isn't true.

Re: Two studies in compiler optimisations

#15

> Here, the simplification analysis uses the conditional hidden in the assert() macro to figure out that we only execute the urem instruction if cur It surprises me that the compiler doesn't still take the inference from the assert and just disable emitting the code to perform the check. Over the last 15 years I've worked on many codebases that are written with unnecessary asserts, partly as documentation, but maybe…

> It surprises me that the compiler doesn't still take the inference from the assert and just disable emitting the code to perform the check. The compiler isn't as clever as I think you're envisioning: assert() only works that way because it exits the control flow if the statement isn't true.

My point is that even though the assert() is optimised out, the compiler could still assume that the condition is valid.

Re: Two studies in compiler optimisations

#16

> Here, the simplification analysis uses the conditional hidden in the assert() macro to figure out that we only execute the urem instruction if cur It surprises me that the compiler doesn't still take the inference from the assert and just disable emitting the code to perform the check. Over the last 15 years I've worked on many codebases that are written with unnecessary asserts, partly as documentation, but maybe…

> It surprises me that the compiler doesn't still take the inference from the assert and just disable emitting the code to perform the check.

That's because that's what the assert() must do; it's specified to do and imply nothing when assertions are disabled. (the standard literally fully defines it as `#define assert(...) ((void)0)` when NDEBUG)

Whereas `[[assume(...)]]` is a thing specifically for that "infer things from this without actually emitting any code".

Re: Two studies in compiler optimisations

#17
post #16

> Here, the simplification analysis uses the conditional hidden in the assert() macro to figure out that we only execute the urem instruction if cur It surprises me that the compiler doesn't still take the inference from the assert and just disable emitting the code to perform the check. Over the last 15 years I've worked on many codebases that are written with unnecessary asserts, partly as documentation, but maybe…

> It surprises me that the compiler doesn't still take the inference from the assert and just disable emitting the code to perform the check. That's because that's what the assert() must do; it's specified to do and imply nothing when assertions are disabled. (the standard literally fully defines it as `#define assert(...) ((void)0)` when NDEBUG) Whereas `[[assume(...)]]` is a thing specifically for that "infer thing…

Yeah, good point. Honestly it's been so long since I've added that to a project (it's normally hidden in some include that everything else includes) that I'd forgotten it wasn't a compiler level reserved keyword for C++ code.

Re: Two studies in compiler optimisations

#18

Earlier quoted context omitted.

> It surprises me that the compiler doesn't still take the inference from the assert and just disable emitting the code to perform the check. The compiler isn't as clever as I think you're envisioning: assert() only works that way because it exits the control flow if the statement isn't true.

My point is that even though the assert() is optimised out, the compiler could still assume that the condition is valid.

How? The assert() has no special significance to the compiler at all, it's just code. Usually it's just an empty macro for non-debug builds.

I guess you could define your assert() use [[assume]] in C++ for non-debug builds... but that seems like a very bad idea to me.

Just leave the asserts in prod. They almost certainly don't have measurable overhead. The few that do can be dealt with separately.

The Linux kernel has thousands of asserts which are always checked at runtime (BUG_ON).

Re: Two studies in compiler optimisations

#19
post #7

Interesting. It all seems very brittle, though. And that something has gone very wrong with our ecosystem of tools, languages, and processes when it becomes advisable to massage source until specific passes in a specific version LLVM don't mess things up for other passes. Not picking on the OA in the slightest; just thinking in terms of holistic system design. If you know what you want to happen, and you are smart en…

Having a way to assert that the compiler does what you expect can be helpful in large projects with many contributors of different skill level. Having something fail when a random change breaks autovectorization can save a lot of time profiling. When a compiler upgrade changes codegen I would also prefer an assertion telling me about it so that I can run relevant benchmarks to see whether it’s an improvement or not.…

Haskell has a package to make testing this sort of thing easier https://hackage.haskell.org/package/inspection-testing
Post reply on HN