Closed ncannasse closed 6 years ago
How about haxe.ds.ListSort.sortSingleLinked(l,cmp.bind());
?
Wow, these methods in ListSort are massive. I'm not surprised the JS target refuses to inline them.
The idea is to inline the comparison function, this produces very efficient sorting since there is no function call at all. It's an important feature performance wise when working on linked lists. I would suggest we unit test it to prevent regressions.
I always roll my eyes when you talk about performance related to List. But yes we should add inlining tests.
@Simn it's not about List, it's about anything that you can declare that has a "next" member variable
What exactly is the scope here for inlining functions if they are referenced like that? Would we also inline their expression if you did var f = cmp;
, or is this supposed to be special to arguments to inline functions (which seems strange)?
inline functions which takes a function literal as argument should inline its content.
I have implemented this but I didn't think about it thoroughly enough and I also find it too newfeaturesque for 3.2. Feel free to activate it if you think it's safe, otherwise I'll get back to it after 3.2.
@Simn we have that already in reduce_loop, don't we ?
I was triggered before we moved inline to local vars maybe ? Maybe we shouldn't do that for TFunction, and that would take us back to original optimized behavior
PS : I also want that we add an unit test for that, it's a huge regression speed-wise
You keep mentioning TFunction but here we only have a TField which is not safe to inline in the general case. Though I think it can actually be inlined if it's a Method (not MethDynamic).
I didn't know that this was working at some point and that there was this code in replace_loop
. In that case I agree we should look into it for 3.2.
Ah, right, only the first was supported before, but it seems on JS this was disabling inlining, so I had to rely on the second behavior. If possible I would like to get both to work well for 3.2
I didn't have this on my radar because it was assigned to you and now it's too late to make any changes here. Moving to 3.3 again.
So why would it be crazy to simply use the function expression (with replaced locals) if we take the "closure" of a static inline method? This goes very well with the general concept of inlining and solves this particular problem as a subset.
@Simn I'm not sure I'm understanding what you're proposing here :)
typedef List = { v : Int, next : List };
class Main {
static inline function cmp(a:List, b:List) {
return a.v - b.v;
}
static function main() {
var f = cmp;
}
}
->
static function main() {
var f = function(a:List, b:List) {
return a.v - b.v;
}
}
How does that help ? it will be actually slower unless "f" calls are inlined, and harder to optimize given that now f is a variable that can be written.
It helps because it turns:
haxe.ds.ListSort.sortSingleLinked(l,cmp);
to
haxe.ds.ListSort.sortSingleLinked(l,function(a,b) return a.v - b.v);
which happens to be the case that's already optimized.
Oh, right, got it. So, if we want to substitute the function expr when calling type_inline, it's fine. But we shouldn't do that if inlining is canceled or if no inlining is done.
I don't understand what problems always inlining them like that would cause. In my opinion taking the "closure" of a static inline function should do exactly that.
If sortSingleLinked is not inline, it means we will allocate a closure each time we call it, instead of simply passing the function pointer. The same if for some reason sorteSingleLinked modify its cmpFunc
parameter which will prevent from inlining the call to it
We could solve this as part of the data flow analysis. It's an easy change but we have to drag the typer context into the analyzer because type_inline
requires it.
The first ListSort will correctly inline the local function, but the
cmp
function will not be inlined, while it could/should.PS: on JS, both are not inlined while they should