digitalmars.D - pragma(inline, true) errors?
- Steven Schveighoffer (50/50) Apr 01 2021 Was diagnosing an issue on raylib-d with inlining. I have found some
- tsbockman (34/41) Apr 01 2021 DMD's inliner often gets confused by multiple `return`
- Steven Schveighoffer (9/51) Apr 01 2021 Yeah, I'm not too concerned with the fact that this can't be inlined,
- Steven Schveighoffer (15/15) Apr 02 2021 Nobody has comments on this? It was not an April fool's joke.
- Johan Engelen (14/26) Apr 02 2021 I'm pretty sure LDC will _never_ give any warning or error on
- Steven Schveighoffer (13/38) Apr 02 2021 I don't really care about inlining or not, but I'm forced to reckon with...
- jmh530 (5/14) Apr 02 2021 It only does warnings when you use the -wi flag right? Otherwise
- Steven Schveighoffer (4/20) Apr 02 2021 Yes that is exactly the case. With -w or no switch there is no
- jmh530 (6/10) Apr 02 2021 So the argument is that it is consistent with the spec, but not
- Johan Engelen (8/34) Apr 03 2021 Pretty much.
- Max Haughton (6/27) Apr 03 2021 LDC will sometimes give up inlining on functions containing naked
- Johan Engelen (6/9) Apr 03 2021 Interesting!
- Max Haughton (9/19) Apr 03 2021 I've used it maybe once or twice in some synthetic benchmarks -
Was diagnosing an issue on raylib-d with inlining. I have found some curious behavior. Observe the following code: ```d extern(C) pragma(inline, true) static float EaseBounceOut(float t, float b, float c, float d) { if ((t/=d) < (1.0f/2.75f)) { return (c*(7.5625f*t*t) + b); } else if (t < (2.0f/2.75f)) { float postFix = t-=(1.5f/2.75f); return (c*(7.5625f*(postFix)*t + 0.75f) + b); } else if (t < (2.5/2.75)) { float postFix = t-=(2.25f/2.75f); return (c*(7.5625f*(postFix)*t + 0.9375f) + b); } else { float postFix = t-=(2.625f/2.75f); return (c*(7.5625f*(postFix)*t + 0.984375f) + b); } } void main() { auto f = EaseBounceOut(0.5, 1, 1, 1); } ``` Here is a relevant run.dlang.io snippet: https://run.dlang.io/is/UEtyE8 Some interesting things about this: 1. With -w, I get no errors. 2. With -wi, I get a warning that the function can be inlined 3. Using ASM view, it appears the function is NOT inlined in either case. I checked historical compilers, and I found that this behavior stems from 2.094. I looked at the changelog, and see this [1]. So I feel like this is a bug, but I'm not sure. I'm assuming the intended behavior is to inline at all costs, and error if it cannot. But I'm not sure of the intended uses of pragma(inline). I feel like if we "fix" this, it will break *a lot* of code. In general, my thoughts on the pragma(inline) feature are that it is a complete failure. It either doesn't do what I want, or it is so fragile that I don't want to use it. My only use case is for a shim that should never really be emitted into the object file. But D tries to inline not just the shim, but every function it calls as well. -Steve [1] https://dlang.org/changelog/2.094.0.html#hasAlwaysInlines
Apr 01 2021
On Thursday, 1 April 2021 at 18:38:45 UTC, Steven Schveighoffer wrote:Here is a relevant run.dlang.io snippet: https://run.dlang.io/is/UEtyE8 Some interesting things about this: 1. With -w, I get no errors. 2. With -wi, I get a warning that the function can be inlined 3. Using ASM view, it appears the function is NOT inlined in either case.DMD's inliner often gets confused by multiple `return` statements. The solution is to either convert to single-`return` style, or use LDC/GDC which do not have this problem. ```D extern(C) pragma(inline, true) static float EaseBounceOut(float t, float b, float c, float d) { float ret; if ((t/=d) < (1.0f/2.75f)) { ret = (c*(7.5625f*t*t) + b); } else if (t < (2.0f/2.75f)) { float postFix = t-=(1.5f/2.75f); ret = (c*(7.5625f*(postFix)*t + 0.75f) + b); } else if (t < (2.5/2.75)) { float postFix = t-=(2.25f/2.75f); ret = (c*(7.5625f*(postFix)*t + 0.9375f) + b); } else { float postFix = t-=(2.625f/2.75f); ret = (c*(7.5625f*(postFix)*t + 0.984375f) + b); } return ret; } ``` (I have no comment on the larger issues that you raised. Also, hurray for rich text formatting!)
Apr 01 2021
On 4/1/21 3:13 PM, tsbockman wrote:On Thursday, 1 April 2021 at 18:38:45 UTC, Steven Schveighoffer wrote:Yeah, I'm not too concerned with the fact that this can't be inlined, though I probably should just remove that from the lib (looks like that was a recent addition). I'm more concerned with the larger issue that it's not doing what it says it should be doing.Here is a relevant run.dlang.io snippet: https://run.dlang.io/is/UEtyE8 Some interesting things about this: 1. With -w, I get no errors. 2. With -wi, I get a warning that the function can be inlined 3. Using ASM view, it appears the function is NOT inlined in either case.DMD's inliner often gets confused by multiple `return` statements. The solution is to either convert to single-`return` style, or use LDC/GDC which do not have this problem. ```D extern(C) pragma(inline, true) static float EaseBounceOut(float t, float b, float c, float d) { float ret; if ((t/=d) < (1.0f/2.75f)) { ret = (c*(7.5625f*t*t) + b); } else if (t < (2.0f/2.75f)) { float postFix = t-=(1.5f/2.75f); ret = (c*(7.5625f*(postFix)*t + 0.75f) + b); } else if (t < (2.5/2.75)) { float postFix = t-=(2.25f/2.75f); ret = (c*(7.5625f*(postFix)*t + 0.9375f) + b); } else { float postFix = t-=(2.625f/2.75f); ret = (c*(7.5625f*(postFix)*t + 0.984375f) + b); } return ret; } ```(I have no comment on the larger issues that you raised. Also, hurray for rich text formatting!)Grrrr... I want formatting too :(. Vladimir, we need an X-DFormat = markdown header or something I can use in Thunderbird. -Steve
Apr 01 2021
Nobody has comments on this? It was not an April fool's joke. To recap: pragma(inline, true) means nothing in the current compiler. Well, it doesn't mean nothing, it only means that in the case of configuring the compiler to treat warnings as informational-only, you will get an informational warning. In the case that warnings are treated as an error, your code always compiles, and the function is only inlined based on implementation definitions. Technically, this is according to spec, as it says what the compiler does if a pragma(inline, true) function cannot be inlined is implementation defined. But it does say "an error message is typical". Given that there is only one front end, the typical (and in fact universal) behavior now is, do nothing. -Steve
Apr 02 2021
On Friday, 2 April 2021 at 14:40:00 UTC, Steven Schveighoffer wrote:pragma(inline, true) means nothing in the current compiler. Well, it doesn't mean nothing, it only means that in the case of configuring the compiler to treat warnings as informational-only, you will get an informational warning. In the case that warnings are treated as an error, your code always compiles, and the function is only inlined based on implementation definitions. Technically, this is according to spec, as it says what the compiler does if a pragma(inline, true) function cannot be inlined is implementation defined. But it does say "an error message is typical". Given that there is only one front end, the typical (and in fact universal) behavior now is, do nothing.I'm pretty sure LDC will _never_ give any warning or error on this pragma. It will almost always inline the function into the caller (I don't know of cases where it can't). I question the value of knowing whether a function was inlined or not. Note that `pragma(inline)` is very different functionality from "not emitting a function to object file", which _is_ useful functionality but there is no method to do that in D that I know of (and should not be called "inline"). cheers, Johan
Apr 02 2021
On 4/2/21 12:27 PM, Johan Engelen wrote:On Friday, 2 April 2021 at 14:40:00 UTC, Steven Schveighoffer wrote:So technically for LDC it will never encounter this case.pragma(inline, true) means nothing in the current compiler. Well, it doesn't mean nothing, it only means that in the case of configuring the compiler to treat warnings as informational-only, you will get an informational warning. In the case that warnings are treated as an error, your code always compiles, and the function is only inlined based on implementation definitions. Technically, this is according to spec, as it says what the compiler does if a pragma(inline, true) function cannot be inlined is implementation defined. But it does say "an error message is typical". Given that there is only one front end, the typical (and in fact universal) behavior now is, do nothing.I'm pretty sure LDC will _never_ give any warning or error on this pragma. It will almost always inline the function into the caller (I don't know of cases where it can't).I question the value of knowing whether a function was inlined or not.I don't really care about inlining or not, but I'm forced to reckon with this, because I've taken over maintenance of a package that puts "pragma(inline, true):" at the top of a module, and therefore warnings are being spat out. So I want to ask the question, is this a bug? What is the expectation? Should we just change the description to "issue a informational warning in some cases when the function cannot be inlined"? Does LDC make any inlining decisions based on this flag?Note that `pragma(inline)` is very different functionality from "not emitting a function to object file", which _is_ useful functionality but there is no method to do that in D that I know of (and should not be called "inline").Yeah, I'm not necessarily invested in a debate about the feature, I just want to know what it really means, so I can make a decision whether to yank the attribute or not. -Steve
Apr 02 2021
On Friday, 2 April 2021 at 17:00:35 UTC, Steven Schveighoffer wrote:[snip] I don't really care about inlining or not, but I'm forced to reckon with this, because I've taken over maintenance of a package that puts "pragma(inline, true):" at the top of a module, and therefore warnings are being spat out. So I want to ask the question, is this a bug? What is the expectation? Should we just change the description to "issue a informational warning in some cases when the function cannot be inlined"? [snip]It only does warnings when you use the -wi flag right? Otherwise it's an error. Is there a problem with the error not being generated when you don't have warnings turned on?
Apr 02 2021
On Friday, 2 April 2021 at 17:25:43 UTC, jmh530 wrote:On Friday, 2 April 2021 at 17:00:35 UTC, Steven Schveighoffer wrote:Yes that is exactly the case. With -w or no switch there is no error or warning. And no inlining. -Steve[snip] I don't really care about inlining or not, but I'm forced to reckon with this, because I've taken over maintenance of a package that puts "pragma(inline, true):" at the top of a module, and therefore warnings are being spat out. So I want to ask the question, is this a bug? What is the expectation? Should we just change the description to "issue a informational warning in some cases when the function cannot be inlined"? [snip]It only does warnings when you use the -wi flag right? Otherwise it's an error. Is there a problem with the error not being generated when you don't have warnings turned on?
Apr 02 2021
On Friday, 2 April 2021 at 18:21:59 UTC, Steven Schveighoffer wrote:[snip] Yes that is exactly the case. With -w or no switch there is no error or warning. And no inlining. -SteveSo the argument is that it is consistent with the spec, but not with the expected behavior after 2.094.0. For whatever reason, I assumed that the change in 2.094.0 was for the spec too, and not just DMD. A little hard to keep track...
Apr 02 2021
On Friday, 2 April 2021 at 17:00:35 UTC, Steven Schveighoffer wrote:On 4/2/21 12:27 PM, Johan Engelen wrote:Pretty much. When the function is recursive, it may prevent inlining.On Friday, 2 April 2021 at 14:40:00 UTC, Steven Schveighoffer wrote:So technically for LDC it will never encounter this case.pragma(inline, true) means nothing in the current compiler. Well, it doesn't mean nothing, it only means that in the case of configuring the compiler to treat warnings as informational-only, you will get an informational warning. In the case that warnings are treated as an error, your code always compiles, and the function is only inlined based on implementation definitions. Technically, this is according to spec, as it says what the compiler does if a pragma(inline, true) function cannot be inlined is implementation defined. But it does say "an error message is typical". Given that there is only one front end, the typical (and in fact universal) behavior now is, do nothing.I'm pretty sure LDC will _never_ give any warning or error on this pragma. It will almost always inline the function into the caller (I don't know of cases where it can't).Does LDC make any inlining decisions based on this flag?Yes: the flag sets the `alwaysinline` attribute on a function, meaning that it will be inlined whenever possible, also at `-O0`. https://d.godbolt.org/z/GEe8zxrro -Johan
Apr 03 2021
On Saturday, 3 April 2021 at 10:32:18 UTC, Johan Engelen wrote:On Friday, 2 April 2021 at 17:00:35 UTC, Steven Schveighoffer wrote:LDC will sometimes give up inlining on functions containing naked asm also, but there is a flag to tell LLVM that it's safe. GCC has a similar set of flags, including ` attribute("flatten")` which inlines the called functions rather than the the function in it's caller.On 4/2/21 12:27 PM, Johan Engelen wrote:Pretty much. When the function is recursive, it may prevent inlining.On Friday, 2 April 2021 at 14:40:00 UTC, Steven Schveighoffer wrote:So technically for LDC it will never encounter this case.[...]I'm pretty sure LDC will _never_ give any warning or error on this pragma. It will almost always inline the function into the caller (I don't know of cases where it can't).Does LDC make any inlining decisions based on this flag?Yes: the flag sets the `alwaysinline` attribute on a function, meaning that it will be inlined whenever possible, also at `-O0`. https://d.godbolt.org/z/GEe8zxrro -Johan
Apr 03 2021
On Saturday, 3 April 2021 at 12:04:18 UTC, Max Haughton wrote:GCC has a similar set of flags, including ` attribute("flatten")` which inlines the called functions rather than the the function in it's caller.Interesting! Is this useful for anyone? We can implement something close to this fairly easily in LDC, but I'd rather wait until this LLVM PR: https://reviews.llvm.org/D70366 -Johan
Apr 03 2021
On Saturday, 3 April 2021 at 20:29:59 UTC, Johan Engelen wrote:On Saturday, 3 April 2021 at 12:04:18 UTC, Max Haughton wrote:I've used it maybe once or twice in some synthetic benchmarks - I'm not entirely sure, however being able to tune the optimizer (particularly the inliner) at source level without extremely ugly things like in C++ could be a huge win for the language e.g. the backend knows where to spend it's efforts (like in loops), but being able to spend more effort on some functions in hot loops is provably a win because you can see LLVM and GCC give up inlining in some examples on godbolt.GCC has a similar set of flags, including ` attribute("flatten")` which inlines the called functions rather than the the function in it's caller.Interesting! Is this useful for anyone? We can implement something close to this fairly easily in LDC, but I'd rather wait until this LLVM PR: https://reviews.llvm.org/D70366 -Johan
Apr 03 2021