-
Notifications
You must be signed in to change notification settings - Fork 28
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
The JIT may be generating no-op mov
s
#49
Comments
I don't think you're missing anything! Do you have any ideas for fixing it? I'm not sure if it's something we should fix in Fisk (it does seem silly to make no-op Just some brainstorming thoughts, we could:
It's cool that you found this! |
So! In the past, I remember different assemblers (TASM vs. Idontrememberwhat) generating slightly different instructions, although I don't remember exactly how. I've just tried with NASM a couple of "unoptimized" instructions - All in all, it seems that the role of assemblers is not to optimize (there is an optimize flag in NASM, but it effects only jumps) the code, rather, that it's the role of compilers. Therefore, I'd go for this:
Essentially, this would be a linter that, for simplicity, generates errors instead of warnings. We'd then enable the linter from TJ either always, or, during the build only (say, a flag is passed to TJ, that in turn enables the linter in Fisk). This way, Fisk keeps its traditional role of assembler, and with the flag enabled, it acquires some extra behavior. Using the following strategy:
Would IMO push Fisk a bit too much from what I suppose is the traditional role of assemblers. (On the other hand, TJ has a separate two-tier architecture (JIT + assembler), and the lack of an intermediate representation makes impossible to write a generalized JIT and a specialized assembler; this is not a current concern though, and it may never be) |
Makes sense to me! I want to finish more of the
I think adding an IR would be great, though I don't have any ideas on what would make a good IR. I have no experience designing or working with one, so if you have thoughts I'm all ears (maybe a good thing for the discussions section?) |
I'd like to take this!! 😂 I'll open a tracking/discussion issue on Fisk before though, since it's very open ended (I'll open the issue also in case I won't be able to work on it for any reason) 😄
Yes! I'll open a discussion in the next week. But I have no idea, either 😂 |
Sounds good. I enabled discussions on the Fisk repo! I'm looking forward to the PR. As for an IR, I was reading this and we probably want something either High-Level or Medium-Level. In the short term though, I'm going to work on making TJ run OptCarrot as well as compiling itself. Regardless, I'm looking forward to the IR discussion! 😄 |
I suspect that duplication is caused by temp variables. If this is the case, the problem is that they are an abstraction at Fisk level (AFAIU), so TJ can't really do anything, and Fisk should be turned into an "optimizing" assembler. Nothing wrong with that (after all, temp variables are already something atypical (AFAIK) for an assembler), but it's certainly a design decision 😄 |
Ah, right. We're using r9 and r10 as scratch registers, and r9 happens to be a register used for calling C functions. So we end up with a temp in r9 then move to r9.
I'm fine with adding something like Also we might think more about adding an IR because optimization passes on the IR could solve this too. WDYT? |
Considering that:
What do you think of turning the current This would keep the APIs simpler. Intuitively, optimization should be applied (at least, with the current design) in any Fisk location where a performance check is applied, so I think inevitably, both checking and optimization are going to be ultimately branches of the same codepath - therefore, adding a new API would ultimately lead to the same codepath anyway. |
Ya, that makes sense. I'm keen on having the optimization pass being done at "write" time because I think we could probably add more interesting optimizations than just eliminating useless For TJ, I can't think of a use case where we care about |
IR == 😍 😍 😍 I have two thoughts on IR for TJ/Fisk:
I think that, all in all, the Runtime could be a guide to how to develop the IR framework. This requires though, all the handlers to be fully moved to it. The above is much guesswork on my part 😄 I don't know TJ/Fisk in detail. I'll have a look at Rhizome actually, at a quick look, it seems that TJ/Fisk are based on it 🤩. |
(I may be wrong on this, as I still don't have clear how register allocation works)
While trying some manual register allocation (specifically, directly popping a value into RDI (
rt.pop_reg @fisk.rdi
), so that it could be passed as first parameter of a cfunc (rt.call_cfunc_without_alignment <addr>, [@fisk.rdi, ...]
)), I was curious if TJ/FISK would avoid generating instructions for copying the operand to RDI.Specifically, I was looking around here:
Now, I couldn't actually find any
mov rdi, rdi
, however, I found that other no-op movs are generated (at least, I believe), specifically, a bunch ofmov r9, r9
.I detect this by hacking
fisk.rb -> write_to()
with this (horrendous) code:by running
rake test
you'll see many occurrences. Am I correct, or am I missing something?I dug a little bit in Fisk, and the mov ultimately ends here:
which seems to me, that it's encoding as
mov r9, r9
.ps. On Error Resume Next FTW
The text was updated successfully, but these errors were encountered: