7 ms·
gcc has some attributes to help with that, for example try __attribute__((pure)) on funcs that will always return the same thing for the same inputs (given the
by dmitrygr 7y ago
gcc has some attributes to help with that, for example try __attribute__((pure)) on funcs that will always return the same thing for the same inputs (given the same global state) and do not modify said input or state (and thus can be called more or fewer times than programmer wrote). Usually gcc will be quite aggressive with optimizations if you use that.
For even more aggressiveness, try __attribute__((const)) which tells it that the func accesses NOTHING but the params, not even global vars. Of course this is quite limiting. You can also use this as a trick when YOU know that the only accessed global state is itself constant but gcc does not know that. This can produce substantial savings in number of calls of funcs that, for example, do lookups in large constant data tables, like table-based versions of sin() and cos().
In the example the article gives, adding __attribute__((pure)) to constFunc() does produce the behaviour author wanted and then some
LWN has more: https://lwn.net/Articles/285332/ https://lwn.net/Articles/285332/
- Ididntdothis 7y agoDoes it enforce these attributes or are they just a promise by the code author?
- dmitrygr 7y agoThey are a promise and that is precisely what makes them powerful. It gives GCC info it might not be able to derive, but you know to be true. You can even promise a func is pure without even implementing it in the same translation unit! That produces lots of improvement. See these two godbolt links: https://godbolt.org/z/v2zqJI https://godbolt.org/z/v2zqJI https://godbolt.org/z/kk3Q3T https://godbolt.org/z/kk3Q3T
- einpoklum 7y ago> You can even promise a func is pure without even implementing it in the same translation unit! Actually that's the main point, as if it's in the same TU, the compiler can probably figure out a function is pure.
- dmitrygr 7y agooften but not always, for example a function using asm() to access, say, some AES intrinsics is pure (const even) since the output only depends on input, but oftentimes compiler by itself will not declare a function with an asm() block pure or const
- einpoklum 7y agoWell, fair point, but - compilers shouldn't be that lazy :-)
- WalterBright 7y agoD has a `pure` attribute for functions, and yes it is enforced. It's enforced even to the point where it becomes a PITA, but when you manage to make functions pure, you know it's solid. One pain point with pure functions is you can't insert debug logging statements. D has a special case for that - purity for a statement isn't checked if it is prefixed with the `debug` keyword: pure int square(int x) { debug printf("called square\n"); return x * x; } which is very, very handy.
- Ididntdothis 7y agoThis seems a very pragmatic solution.
- SomeOldThrow 7y agoThis means you can't re-order the computation, though, or memoize it—at least not the the extent it's possible without IO.
- mhh__ 7y agoThe use of the debug {} block in D is opt-in e.g. the compiler only includes those statements when given the debug flag https://d.godbolt.org/z/Rwu4Cq https://d.godbolt.org/z/Rwu4Cq (remove "-d-debug" to see)
- Gibbon1 7y agoI wonder does that mean you could also enforce freeing memory allocated by a pure function as well?
- egdod 7y ago> try __attribute__((const)) which tells it that the func accesses NOTHING but the params, not even global vars And it doesn’t do anything unintended if you’re lying to it by accessing the global state that you know to be constant?
- dmitrygr 7y agoIt will only assume that it is safe to skip multiple calls to this function with the same parameters, safe to generate extra calls that you did not write, and safe to skip the entire call if the return value is ignored
- pingyong 7y ago>__attribute__((const)) which tells it that the func accesses NOTHING but the params, not even global vars. If you're actually not accessing any global state at all (including making no memory allocation), shouldn't the compiler figure that out anyway? That doesn't seem like something that would be very hard to check for.
- gpderetta 7y agoNot if it is defined in another translation unit and you are not using LTO.
- fluffything 7y agoIn other words, the compiler can infer this from the function definition (or at least clang does), but it cannot infer this from a function declaration, because the implementation is missing - unless you are using LTO like the parent mentions.
- dmitrygr 7y agosometimes it cannot infer it even from function, for example, here is a function that in my particular OS gets me a pointer to my library's globals. To my code the returned pointer never changes, but the compiler has NO way to tell this function is const without my annotation void* __attribute__((const)) getGlobals(void) { void* ret; asm ( " ldr %0, [r9] \n" " ldr %0, [%0, %1] \n" : "=r"(ret) : "I"(MY_MODULE_ID) : ); return ret; }
- gpderetta 7y agoGood point.