Error while trying to optimize a working code.

classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

Error while trying to optimize a working code.

Henoktes722
@LCL
DA=M
@2
DA=A+D
@R13

I copied this snippet from nested call.asm generated from my translator. But when I try to load into the cpu emulator it shows an error, In Line 1 destination expected.

I'm exploiting multiple destination of the hack platform to optimize the translator code as Wbhan, admin,  suggested.
Reply | Threaded
Open this post in threaded view
|

Re: Error while trying to optimize a working code.

Henoktes722
Yeah I got it. It is because the way I wrote the destination. It must be AD not DA as described in fig 4.4
Reply | Threaded
Open this post in threaded view
|

Re: Error while trying to optimize a working code.

ivant
In reply to this post by Henoktes722
Yes, as you wrote it's AD=M and AD=A+D.

Henoktes722 wrote
@LCL
DA=M
@2
DA=A+D
@R13

I copied this snippet from nested call.asm generated from my translator. But when I try to load into the cpu emulator it shows an error, In Line 1 destination expected.

I'm exploiting multiple destination of the hack platform to optimize the translator code as Wbhan, admin,  suggested.
But how is that an optimization? Let's look at the first 3 instructions:

The following table contains the instructions and the values of the A and D registers after execution:

| Instr. |      A | D      |
|--------+--------+--------|
| @LCL   |      1 | ?      |
| AD=M   | RAM[1] | RAM[1] |
| @2     |      2 | RAM[1] |
* RAM[1] means that it's the value, stored in RAM address 1.

Compare that to the following:
| Instr. |      A | D      |
|--------+--------+--------|
| @LCL   |      1 | ?      |
| D=M    |      1 | RAM[1] |
| @2     |      2 | RAM[1] |
There is no difference at the end. The multi-destination assignment doesn't make any difference here.

The same is true for the other 2 instructions, because you again override the value in A without using it.
Reply | Threaded
Open this post in threaded view
|

Re: Error while trying to optimize a working code.

Henoktes722
Yes Ivant. This is not the part I want to show for optimization instead, when I debug the error, destination expected, when I delete the instructions with destination  DA, the emulator works fine. So the intention for the snippet is for the error.

I make my 700 asm instructions to 600 asm instructions and then to 490 instructions using multiple destination technique. But I could't find a short way of pop to LCL and ARG.

Here is my translator outputs for command pop local 0

// get the address of M[local] + 0
@LCL
D=M
@0
D=A+D

// save address
@R13
M=D

// pop stack
@SP
AM=M-1
D=M

// restore address
@R13
A=M

// write to address
M=D

It is 12 line of asm instructions, can we make it less?
Reply | Threaded
Open this post in threaded view
|

Re: Error while trying to optimize a working code.

ivant
Henoktes722 wrote
Yes Ivant. This is not the part I want to show for optimization instead, when I debug the error, destination expected, when I delete the instructions with destination  DA, the emulator works fine. So the intention for the snippet is for the error.
OK. Sorry for the misunderstanding.

Henoktes722 wrote
It is 12 line of asm instructions, can we make it less?
There are various possible optimization goals. You can optimize for program size, for execution speed, for memory usage and so on. Sometimes we get lucky and one optimization technique works for two or more goals. Most of the time though, it's a trade off game: you loose one thing, so that you are able to gain something else. For a compiler, this means that it may need to support different optimization goals. It will then use the optimization techniques, which align with these goal.

For your example, you can optimize the program size by extracting long snippets of code as some sort of assembly subroutines (not to be confused with VM-level functions), jump to them for execution and jump back. E.g. you can extract POP_LOCAL (which will require some additional code to call and to return to the correct place) and just "call" it from wherever it's needed. I'm not sure if it makes sense for push and pop, but it certainly looks a good candidate for call and return.

If you optimize for speed, then you don't want to put the additional setup and jumps if you can avoid them. You'd prefer to generate this code for each pop local instruction. One thing you can do in this case is to have a slightly specialized code for pop local 0 and pop local 1. For the former, you don't need to add anything, so you can remove a couple of instructions. For the latter, you can remove 1 instruction.

You can also make your compiler analyze the usage of local variables and rearrange them, so that the most used one is at offset 0 and the second most used one at offset 1, thus

There are also, so called peep-hole optimizations, where you look for some (generally short) sequence of instructions and replace them with a functionally equivalent one, but which is shorter, or faster or both. This could happen on different levels, like VM-code or ASM-code.

Let's say you have a Jack program, which at some point has this code:

   let x = arg0;

where x is a local variable and arg0 is the first parameter to the function. This will be compiled to something like:

push argument 0
pop local 1

A peep-hole optimizer may find such sequence and instead of compiling each VM instruction separately, it can generate a much more efficient ASM code for the whole sequence.

Similar things are possible on Assembly level as well, where for example the compiler can see that some instructions are doing redundant work and can be simplified or even removed.