Z80: optimization of loading constants into registers

ZXNet echo conference «code.zx»

From Ivan Roshin To All 17 October 2000

Hello, All! ═══════════════════ z80_ln_1.W ══════════════════ (c) Ivan Roshchin, Moscow Fido: 2:5020/689.53 ZXNet: 500:95/462.53 E-mail: asder_ffc@softhome.net WWW: http://www.zx.ru/echo/roschin Z80: optimization of loading constants into registers ────────────────────── ─────────────────────── (Radio amateur. Your computer 9/2000) (under the pseudonym BV_Creator) Expanded version. The Z80 processor, manufactured by ZiLOG since 1976, used, in addition to personal computers, and in many other microprocessor devices. So this article will useful not only for Spectrum owners. It is addressed firstly, for those who are planning to write an optimizing compiler any high level language (HLL) for the Z80, and secondly, those who write programs for the Z80 in assembly language and optimize them manually. The optimization techniques discussed here can be are applied by analogy to other types of processors in which load commands "register -> register" or other commands, changing the contents of registers are faster and/or take up fewer bytes than "memory -> register" load instructions. Why is Spectrum the main programming language? is an assembler, and compilers for Pascal, C and other languages are practically not used? After all, in these languages ​​it is much easierwrite programs! The answer is simple: the whole point is that the formed during the compilation process, the program in machine code is obtained longer and slower compared to similar assembler program. And with a small amount of memory and low the performance of the Spectrum is crucial. Why is the program not optimal? Yes because the compiler operates quite primitively. For example, he needs in the program, place the number 0 in the accumulator - it will form command LD A,0. And anyone with any knowledge of In assembly language, the programmer will write the command in the same situation XOR A, which will be both faster and shorter. Programmer also takes into account and uses the fact that by the time the register you need to load a constant, the contents may be known some registers. For example, you need to load into the battery the number is 1, and there is 0. Of course, instead of LD A,1 we write INC A. Another example: you need to load 3 into the accumulator, and to this moment in register H just turns out to be 3 - naturally, we write command LD A,H. It is clear that the compiler also needs to be taught such methods optimization. Then, quite possibly, he will be able to form even more optimal programs than a person - after all, the compiler will consider all possible optimization options and choose the best one, something a person, no matter how much he or she wants, is not capable of doing. Well who,for example, he will guess that if A=0, but it is necessary to obtain A=6, then, with corresponding value of some flags, you can get by with one only by the DAA team? Yes, this is how we come close to the topic of this article. Speech will talk about optimizing the loading of constants into registers and register pairs of Z80s. Commands for loading constants are one of the most commonly used encountered, and their optimization will bring good gains in volume and speed. So what do we have? Suppose that during the program it is necessary put some constant into a register or register pair. To do this, the processor provides the following commands: one of which does not change the flags: LD A,n ┐ LD B,n │ LD C,n │ LD D,n ├──> length: 2 bytes, execution time: 7 clock cycles LD E,n │ LD H,n │ LD L,n ┘ LD XH,n ┐ LD XL,n ├──> length: 3 bytes, execution time: 11 clock cycles LD YH,n │ (these are undocumented commands, however, LD YL,n ┘ used in many programs) LD BC,nn ┐ LD DE,nn ├──> length: 3 bytes, execution time: 10 clock cycles LD HL,nn ┘ LD IX,nn ┐ ─> length: 4 bytes, execution time: 14 clock cycles LD IY,nn ┘ Let by the moment when into a register or into a register pair a constant must be placed, we know at least some of the following: - the contents of all or some processor registers; - values ​​of all or some flags;- the contents of which registers are no longer needed; - the meaning of which flags are no longer needed. So, knowing this, we can often replace the ones mentioned above commands load constants to be shorter and/or faster running commands. Naturally, the more we know, the There will be more opportunities for optimization. ════════════════════════ ════════════════════════ Best regards, Ivan Roshchin. [ZX] [BestView 3.0 - 26%]

From Ivan Roshin To All 17 October 2000

Hello, All! ═══════════════════ z80_ln_2.W ══════════════════ Now we will analyze in detail in what cases and how exactly it is possible to optimize how the gain in length and speed. 1. If it is known that a register or register pair already contains is the number that needs to be entered there, then no no command is required, and we do not add anything to the object code. The savings will be from 2 to 4 bytes/from 7 to 14 clock cycles, in depending on the type of register/register pair. 2. If you need to place a constant in one of the registers A, B, C, D, E, H,L (let's denote it R1) and it is known that this constant is already contained in another register (also in one of A,B,C,D,E,H, L - let's denote it R2), then we place the command in the object code LD R1,R2. The savings will be 1 byte/3 clock cycles. Example: you need to put #23 in register D; we know that in register B also #23; put the command in the object code LD D,B. Note: under the words "place in object code command..." we will mean placing it in object code machine codes corresponding to this command. Note also that the compiler can generate not an object, but directly executable code. 3. If you need to place a constant in one of the registers XH, XL (let's denote it R1) and it is known that this constant is alreadycontained in another register (in one of A,B,C,D,E,XH,XL - let's denote it R2), then we place the LD command in the object code R1,R2. The savings will be 1 byte/3 clock cycles. Example 1: you need to put #76 in the XH register; we know that in register A also #76; put the command in the object code LD XH,A. Example 2: you need to put #18 in the XL register; we know that in register XH also #18; put the command in the object code LD XL,XH. 4. If you need to place a constant in one of the YH,YL registers (let's denote it R1) and it is known that this constant is already contained in another register (in one of A,B,C,D,E,YH,YL - let's denote it R2), then we place the LD command in the object code R1,R2. The savings will be 1 byte/3 clock cycles. Example 1: you need to put #29 in the YH register; we know that in register E also #29; put the command in the object code LD YH,E. Example 2: you need to put #74 in the YL register; we know that in YH register also #74; put the command in the object code LD YL,YH. 5. If you need to place a constant in one of the BC register pairs, DE,HL,IX,IY and it is known that one of the bytes of the constant is already is in its place, let’s reformulate the problem optimization: you need to place the remaining byte of the constant in the corresponding register of the register pair, and so that do not change the value of a byte already in place.We save at least 1 byte/3 clock cycles. Example: you need to put #2574 in HL; we know that H=#25. Let's try to solve the optimization problem of loading #74 into register L - even if this does not work, there will be a command in the object code LD L,#74, which is still shorter and faster than LD HL,#2574. 6. If you need to place a constant in one of the BC register pairs, DE,HL (we denote this register pair RR) and it is known that the value of the high byte of the constant is in one of the registers A,B,C,D,E,H,L (let’s denote this register R1), and the value the low byte of the constant is also in one of these registers (let’s denote it as R2), then optimization can be execute by placing the commands LD RRH,R1 in the object code: LD RRL,R2 (where RRH and RRL are the high and low registers register pair RR). The savings will be 1 byte/2 clock cycles. Attention! It must be taken into account that after completing the first LD command, the value of the RRH register will change, and if R2 matches RRH, then optimization cannot be performed. Sometimes in In this case, reversing the LD commands helps. Example 1: you need to put #1234 in HL; we know that A=#12, E=#34; We place the commands LD H,A in the object code: LD L,E. Example 2: you need to put #7536 in BC; we know that A=#75, B=#36; put the commands LD C,B into the object code: LD B,A (in that order!).Example 3: you need to put #8762 in DE; we know that D=#62, E=#87. However, optimization cannot be performed. 7. If you need to place a constant in one of the BC register pairs, DE,HL (we denote this register pair RR) and it is known that the value of the AF register pair is exactly equal to this constant (to establish this fact the compiler will have to monitor the value of the flags register, including and undocumented flags), then you can put it in an object PUSH AF command code: POP RR. The savings will be 1 byte/-11 cycles (i.e. we lose speed due to a reduction in length). This can be useful when a small program size is more important speed of its implementation. 8. If you need to place a constant in register pair IX or IY (we denote this pair RR1) and it is known that this constant is already contained in one of the register pairs AF,BC,DE,HL (denote its RR2), then you can put it in the object code of the PUSH command RR2: POP RR1. As in the previous case, the gain in length will be one byte, and the loss in speed will be 11 cycles. ════════════════════════ ════════════════════════ Best regards, Ivan Roshchin. [ZX] [BestView 3.0 - 26%]

From Ivan Roshin To All 17 October 2000

Hello, All! ═══════════════════ z80_ln_3.W ══════════════════ 9. If you need to place a constant in a register pair HL (or DE), and it is known that the contents of the register pair DE (or HL) is no longer needed, then we do this: try to solve the optimization problem of placing the required constant in DE (HL), and if you can do it in less than 2 bytes and/or 6 cycles, then we place another EX DE command in the object code, H.L. At the same time, it is possible to save in length and/or speed (how much exactly depends on the specific case, maximum - 2 bytes/6 clock cycles). Example 1: you need to place constant #1653 in HL. It is known that DE=#1653 and DE will no longer be needed. Place in object code command EX DE,HL. The savings will be 2 bytes/6 beats Example 2: you need to place the constant #8736 in DE. It is known that HL=#8735, HL will no longer be needed, change the flags it is impossible. Solving the optimization problem of room #8736 in HL, we find that this can be done with the INC HL command in 1 byte/6 beats This satisfies the 2 byte/6 clock limit. We also add the EX DE,HL command to the object code. Savings will be 1 byte/0 clock cycles. 10. If you need to place a constant in one of the BC register pairs, DE,HL and it is known that the values of register pairs BC,DE,HL,BC

From Ivan Roshin To All 17 October 2000

Hello, All! ═══════════════════ z80_ln_4.W ══════════════════ 15. If you need to place a constant in one of the BC register pairs, DE,HL,IX,IY (let’s denote it RR1), and in this register pair the value is found to be one less (more) than the required one (modulo 65536), then we place the INC command in the object code (DEC) RR1. The savings will be 2 bytes/4 clock cycles. Example: you need to place #13FF in BC, and there is #1400. We place the DEC BC command in the object code. 16. If you need to place a constant in one of the registers C, E, L, XL, YL (let's denote it R1, and the register pair into which it included - RR1), the values of the flags cannot be changed, and it is known that this register contains a value one less (more) required (not modulo 256, but absolute value!), then we place the INC (DEC) command in the object code RR1. The savings will be 1 byte/1 clock cycle. Example: you need to put #32 in C; we know that C=#31 and Flag values cannot be changed. Place it in object code INC BC team. 17. If you need to place a constant in one of the registers B, C, D, E, H, L,XH,XL,YH,YL (let's denote it R1, the register pair into which it enters - RR1, and the second register of the pair RR1 - R2), and if the value of RR1 is known, then you can try to do this with using the commands INC RR1, DEC RR1. If R1 is one of the registersH,L,XH,XL,YH,YL, then, in addition to INC/DEC, you can also try commands ADD RR1,RR1; ADD RR1,BC; ADD RR1,DE; ADD RR1,SP, if the flags allow it. At the same time, it must be taken into account that the contents of R2 may be corrupted. The savings will be 1 byte/1 clock cycle when using INC/DEC and 1 byte/-4 clock cycles when using ADD. Example 1: you need to put #82 in D; we know that DE=#81FF, the value of E is no longer needed, the flags cannot be changed. We place the INC DE command in the object code. Example 2: you need to place #40 in H; we know that HL=#2000 and there is no need to save flags. Place the command in the object code ADD HL,HL. Example 3: you need to place #12 in XL; we know that IX=#5309, the XH value will no longer be needed, there is no need to save the flags. We place the ADD IX,IX command in the object code. Example 4: you need to place #25 in H; we know that HL=#1000, BC=#1500; you can change flags except Z. Place in object code command ADD HL,BC. 18. If you need to place a constant in H (XH,YH), the current value H (XH,YH) is known, and the value of L (XL,YL) is unknown, however you cannot change it, you can (if the flags allow) use the following fact: commands ADD HL,BC (ADD IX,BC; ADD IY,BC), ADD HL,DE (ADD IX,DE; ADD IY,DE) and ADD HL,SP (ADD IX,SP; ADD IY,SP) will not change the L register (XL,YL) if the low byteof the second term (BC, DE and SP, respectively) is equal to zero. The savings will be 1 byte/-4 clock cycles. Example: you need to place #70 in XH; we know that XH=#20, SP=#5000; You can change the values of all flags except Z and S. We place the ADD IX,SP command in the object code. 19. If you need to place a constant in L (XL,YL), the current value L (XL,YL) is known, and the value of H (XH,YH) is unknown, however you cannot change it, you can (if the flags allow) use the following fact: commands ADD HL,BC (ADD IX,BC; ADD IY,BC), ADD HL,DE (ADD IX,DE; ADD IY,DE) and ADD HL,SP (ADD IX,SP; ADD IY,SP) will not change the register H (XH,YH), or if the high byte of the second term (BC, DE and SP, respectively) is equal to zero and there will be no transfer to the high byte during addition, or if the most significant byte is #FF and when adding there will be a carry to high byte. The savings will be 1 byte/-4 clock cycles. Example 1: should be placed in L #26; we know that L=#10, BC=#0016, no need to save flags. Place it in object code team ADD HL,BC. Example 2: should be placed in YL #70; we know that YL=#74, DE=#FFFC, no need to save flags. Place in object code command ADD IY,DE. 20. If in one of the register pairs HL,IX,IY (let’s denote it RR1) you need to place a constant that can be obtained with using one of the operations ADD RR1,RR1; ADD RR1,BC; ADD RR1,DE; ADD RR1,SP, then we place the corresponding command (if the flags allow). The savings will be 2 bytes/-1 tact. Example 1: should be placed in HL #AAAA; we know that HL=#5555, no need to save flags. Place it in object code command ADD HL,HL. Example 2: should be placed in IX #7624; we know that IX=#1211, DE=#6413, no need to save flags. Place in object code command ADD IX,DE. 21. If you need to place a constant in a register pair HL, which can be obtained using one of the ADC operations HL,HL; ADC HL,BC; ADC HL,DE; ADC HL,SP; SBC HL,HL; SBC HL,BC; SBC HL,DE; SBC HL,SP, then we put it in object code the appropriate command (if the flags allow). Savings will be 1 byte/-5 clock cycles. Example 1: should be placed in HL 0; we know that CY=0 and there is no need to save flags. Place the command in the object code SBC HL,HL. Example 2: should be placed in HL #2299; we know that HL=#2266, BC=#0032, CY=1 and there is no need to save flags. We place the ADC HL,BC command in the object code. ════════════════════════ ════════════════════════ Best regards, Ivan Roshchin. [ZX] [BestView 3.0 - 26%]

From Ivan Roshin To All 17 October 2000

Hello, All! ═══════════════════ z80_ln_5.W ══════════════════ 22. Let's take two sets of commands: the first - (ADD HL,HL, ADD HL, BC, ADD HL,DE), second - (ADD HL,HL, ADD HL,BC, ADD HL,DE, INC H, DEC H, INC L, DEC L, INC HL, DEC HL). If in register pair HL must be placed as a constant, then you can try (if the flags allow) to do this with two teams, one of which is taken from the first set, and the other is from the second. The memory savings will be 1 byte, and performance loss will depend on which command was selected from the second set: INC H, DEC H, INC L or DEC L - 5 cycles; INC HL or DEC HL - 7 bars; ADD HL,HL, ADD HL,BC or ADD HL,DE - 12 clock cycles. Example 1: should be placed in HL #8080; we know that HL=#2020 and there is no need to save flags. Place commands in object code ADD HL,HL: ADD HL,HL. Example 2: should be placed in HL #8081; we know that HL=#4040 and there is no need to save flags. Place commands in object code ADD HL,HL: INC L. Example 3: should be placed in HL #8082; we know that HL=#4040 and there is no need to save flags. Place commands in object code INC L:ADD HL,HL. Example 4: should be placed in HL #1234; we know that HL=#1111, DE=#0111, BC = #0012 and there is no need to save the flags. We place the ADD HL,DE commands in the object code: ADD HL,BC.23. If in one of the register pairs HL,IX,IY (let’s denote it RR1) you need to place a constant that can be obtained with using one of the operations ADD RR1,RR1; ADD RR1,BC; ADD RR1, DE; ADD RR1,SP, and if it is known that the contents of the flag transfer cannot be changed, and as a result of executing the command ADD it will change to the opposite, then after placing in object code of the ADD command we also place the CCF command (invert transfer flag). The savings will be 1 byte/-5 clock cycles. Example 1: should be placed in HL #1234; we know that HL=#1123, DE=#0111, carry flag is set and change it it is impossible. We place the ADD HL,DE: CCF commands in the object code. Example 2: should be placed in IY 0; we know that IY=#FFF0, BC=#0010, the carry flag is cleared and cannot be changed. We place the ADD IY,BC: CCF commands in the object code. When optimizing, you need to try to apply each of the twenty-three rules listed above, and if they fit right away several rules, choose the one that provides the best result. If the program being optimized is required maximum performance, you will have to discard such options optimizations that reduce program length by increasing constant loading time. Pay attention to rules 9 and 10. When applying each of these, we have to change the optimization problem (let's call thismodified problem by subtask) and solve it (to do this again applying all the rules to it). When solving a subtask it is necessary exclude that rule (9 or 10) from the list of rules when applying which this subtask arose. This is necessary to avoid looping. While writing this article, I had some thoughts: not directly related to its topic, but indirectly related to her. I'll try to outline them. Maybe someone would like to write a Java compiler for Spectrum, but it is stopped by problems such as implementation editor, user interface, etc.? I can advise Here's what: the ZX ASM 3.10 assembler has an excellent interface, and the compiler is made as a separate overlay. Thus, no one is stopping you from writing a compiler for any other language (C, Pascal, etc.) and connect it to the ZX ASM. And I’ll also touch on the issue of optimization. I would like it to There was a site on the Internet specifically dedicated to optimizing the Z80 code, so that programmers from all over the world can use information posted there (and add your own). I don't know - perhaps something similar already exists? If not - maybe will anyone do this? ════════════════════════ ════════════════════════ Best regards, Ivan Roshchin. [ZX] [BestView 3.0 - 26%]

From Kirill Frolov To All 23 October 2000

================================================================================ * Forwarded by Kirill Frolov (500:812/23.25) * Area : ZX.SPECTRUM (Emulator people hanging out) * From : Alex Letaev, 2:5020/689.53 (21 Oct 00 06:33) * To : All * Subj : Z80: optimization of loading constants into registers ================================================================================ Hi, All! (c) Ivan Roshchin, Moscow Fido: 2:5020/689.53 ZXNet: 500:95/462.53 E-mail: asder_ffc@softhome.net WWW: http://www.zx.ru/echo/roschin Z80: optimization of loading constants into registers ────────────────────── ─────────────────────── (Radio amateur. Your computer 9/2000) (under the pseudonym BV_Creator) Expanded version. The Z80 processor, manufactured by ZiLOG since 1976, used, in addition to personal computers, and in many other microprocessor devices. So this article will useful not only for Spectrum owners. It is addressed firstly, for those who are planning to write an optimizing compiler any high level language (HLL) for the Z80, and secondly, those who write programs for the Z80 in assembly language and optimize them manually. The optimization techniques discussed here can be are applied by analogy to other types of processors in which load commands "register -> register" or other commands, changing the contents of registers are faster and/ortake up fewer bytes than "memory -> register" load instructions. Why is Spectrum the main programming language? is an assembler, and compilers for Pascal, C and other languages are practically not used? After all, in these languages it is much easier write programs! The answer is simple: the whole point is that the formed during the compilation process, the program in machine code is obtained longer and slower compared to similar assembler program. And with a small amount of memory and low the performance of the Spectrum is crucial. Why is the program not optimal? Yes because the compiler operates quite primitively. For example, he needs in the program, place the number 0 in the accumulator - it will form command LD A,0. And anyone with any knowledge of In assembly language, the programmer will write the command in the same situation XOR A, which will be both faster and shorter. Programmer also takes into account and uses the fact that by the time the register you need to load a constant, the contents may be known some registers. For example, you need to load the battery the number is 1, and there is 0. Of course, instead of LD A,1 we write INC A. Another example: you need to load 3 into the accumulator, and to this moment in register H just turns out to be 3 - naturally, we write command LD A,H. It is clear that the compiler also needs to be taught such methodsoptimization. Then, quite possibly, he will be able to form even more optimal programs than a person - after all, the compiler will consider all possible optimization options and choose the best one, something a person, no matter how much he or she wants, is not capable of doing. Well who, for example, he will guess that if A=0, but it is necessary to obtain A=6, then, with corresponding value of some flags, you can get by with one only by the DAA team? Yes, this is how we come close to the topic of this article. Speech will talk about optimizing the loading of constants into registers and register pairs of Z80s. Commands for loading constants are one of the most commonly used encountered, and their optimization will bring good gains in volume and speed. So what do we have? Suppose that during the program it is necessary put some constant into a register or register pair. To do this, the processor provides the following commands: one of which does not change the flags: LD A,n ┐ LD B,n │ LD C,n │ LD D,n ├──> length: 2 bytes, execution time: 7 clock cycles LD E,n │ LD H,n │ LD L,n ┘ LD XH,n ┐ LD XL,n ├──> length: 3 bytes, execution time: 11 clock cycles LD YH,n │ (these are undocumented commands, however, LD YL,n ┘ used in many programs) LD BC,nn ┐ LD DE,nn ├──> length: 3 bytes, execution time: 10 clock cycles LD HL,nn ┘ LD IX,nn ┐ ─> length: 4 bytes, execution time: 14 clock cycles LD IY,nn ┘Let by the moment when into a register or into a register pair a constant must be placed, we know at least some of the following: - the contents of all or some processor registers; - values ​​of all or some flags; - the contents of which registers are no longer needed; - the meaning of which flags are no longer needed. So, knowing this, we can often replace the ones mentioned above commands load constants to be shorter and/or faster running commands. Naturally, the more we know, the There will be more opportunities for optimization. Now we will analyze in detail in what cases and how exactly it is possible to optimize how the gain in length and speed. 1. If it is known that a register or register pair already contains is the number that needs to be entered there, then no no command is required, and we do not add anything to the object code. The savings will be from 2 to 4 bytes/from 7 to 14 clock cycles, in depending on the type of register/register pair. 2. If you need to place a constant in one of the registers A, B, C, D, E, H,L (let's denote it R1) and it is known that this constant is already contained in another register (also in one of A,B,C,D,E,H, L - let's denote it R2), then we place the command in the object code LD R1,R2. The savings will be 1 byte/3 clock cycles. Example: you need to put #23 in register D; we know thatin register B also #23; put the command in the object code LD D,B. Note: under the words "place in object code command..." we will mean placing it in object code machine codes corresponding to this command. Note also that the compiler can generate not an object, but directly executable code. 3. If you need to place a constant in one of the registers XH, XL (let's denote it R1) and it is known that this constant is already contained in another register (in one of A,B,C,D,E,XH,XL - let's denote it R2), then we place the LD command in the object code R1,R2. The savings will be 1 byte/3 clock cycles. Example 1: you need to put #76 in the XH register; we know that in register A also #76; put the command in the object code LD XH,A. Example 2: you need to put #18 in the XL register; we know that in register XH also #18; put the command in the object code LD XL,XH. 4. If you need to place a constant in one of the YH,YL registers (let's denote it R1) and it is known that this constant is already contained in another register (in one of A,B,C,D,E,YH,YL - let's denote it R2), then we place the LD command in the object code R1,R2. The savings will be 1 byte/3 clock cycles. Example 1: you need to put #29 in the YH register; we know that in register E also #29; put the command in the object code LD YH,E.Example 2: you need to put #74 in the YL register; we know that in YH register also #74; put the command in the object code LD YL,YH. 5. If you need to place a constant in one of the BC register pairs, DE,HL,IX,IY and it is known that one of the bytes of the constant is already is in its place, let’s reformulate the problem optimization: you need to place the remaining byte of the constant in the corresponding register of the register pair, and so that do not change the value of a byte already in place. We save at least 1 byte/3 clock cycles. Example: you need to put #2574 in HL; we know that H=#25. Let's try to solve the optimization problem of loading #74 into register L - even if this does not work, there will be a command in the object code LD L,#74, which is still shorter and faster than LD HL,#2574. 6. If you need to place a constant in one of the BC register pairs, DE,HL (we denote this register pair RR) and it is known that the value of the high byte of the constant is in one of the registers A,B,C,D,E,H,L (let’s denote this register R1), and the value the low byte of the constant is also in one of these registers (let’s denote it as R2), then optimization can be execute by placing the commands LD RRH,R1 in the object code: LD RRL,R2 (where RRH and RRL are the high and low registers register pair RR). The savings will be 1 byte/2 clock cycles.Attention! It should be taken into account that after completing the first LD command, the value of the RRH register will change, and if R2 matches RRH, then optimization cannot be performed. Sometimes in In this case, reversing the LD commands helps. Example 1: you need to put #1234 in HL; we know that A=#12, E=#34; We place the commands LD H,A in the object code: LD L,E. Example 2: you need to put #7536 in BC; we know that A=#75, B=#36; put the commands LD C,B into the object code: LD B,A (in that order!). Example 3: you need to put #8762 in DE; we know that D=#62, E=#87. However, optimization cannot be performed. 7. If you need to place a constant in one of the BC register pairs, DE,HL (we denote this register pair RR) and it is known that the value of the AF register pair is exactly equal to this constant (to establish this fact the compiler will have to monitor the value of the flags register, including and undocumented flags), then you can put it in an object PUSH AF command code: POP RR. The savings will be 1 byte/-11 cycles (i.e. we lose speed due to a reduction in length). This can be useful when a small program size is more important speed of its implementation. 8. If you need to place a constant in register pair IX or IY (we denote this pair RR1) and it is known that this constant is alreadycontained in one of the register pairs AF,BC,DE,HL (denote its RR2), then you can put it in the object code of the PUSH command RR2: POP RR1. As in the previous case, the gain in length will be one byte, and the loss in speed will be 11 cycles. 9. If you need to place a constant in a register pair HL (or DE), and it is known that the contents of the register pair DE (or HL) is no longer needed, then we do this: try to solve the optimization problem of placing the required constant in DE (HL), and if you can do it in less than 2 bytes and/or 6 cycles, then we place another EX DE command in the object code, H.L. At the same time, it is possible to save in length and/or speed (how much exactly depends on the specific case, maximum - 2 bytes/6 clock cycles). Example 1: you need to place constant #1653 in HL. It is known that DE=#1653 and DE will no longer be needed. Place in object code command EX DE,HL. The savings will be 2 bytes/6 beats Example 2: you need to place the constant #8736 in DE. It is known that HL=#8735, HL will no longer be needed, change the flags it is impossible. Solving the optimization problem of room #8736 in HL, we find that this can be done with the INC HL command in 1 byte/6 beats This satisfies the 2 byte/6 clock limit. We also add the EX DE,HL command to the object code. Savings will be 1 byte/0 clock cycles.10. If you need to place a constant in one of the BC register pairs, DE,HL and it is known that the values of register pairs BC,DE,HL,BC