6.3.3 Generating assembly code for jump instructions
In this section, we will generate the corresponding assembly instructions for "conditional jump", "unconditional jump" and "indirect jump". The four-tuple of the intermediate instruction is as follows:
< operator opcode, destination operand dst, source operand SRC1, source operand src2>
(1) Conditional jumps, such as "if (a <= b) goto BB2;", four Yuan is:
<JLE,BB2,a,b>
The corresponding assembly code//////////
MOVL A,%eax//The value of the SRC1 is temporarily present in the register EAX
Cmpl B,%eax//Compare the size of EAX and B
Jle. BB2//Perform conditional jumps
(2) Unconditional jump, for example "Goto BB3;", four Yuan is:
<JMP,BB3,NULL,NULL>
The corresponding assembly code///////////////
JMP. BB3
(3) Indirect jumps, such as "Goto (BB4,BB5,BB6) [T0];", when translating a switch statement, an indirect jump instruction is generated, and its four-tuple is:
<IJMP,[BB4,BB5,BB6,NULL],t0,NULL>
The corresponding assembly code///////////////
. Data
swtch Table1: .long . BB4
.long . BB5
.long . bb6
. text
Jmp*swtchtable1 (,%eax,4)
Since the jump instruction is at the very end of the base block, we have written back to the x87 stack top register in section 6.2, "Figure 6.2.3 Emitbblock ()". In this section, we also call the Clearregs function to write back the registers in the x86 CPU, 6.3.7 lines 7th, 26th, and 54th. The control flow is about to enter another base block with the execution of the jump instruction, and the UCC compiler reuses the common subexpression only within the same base block, so even if the operand in the jump instruction is a temporary variable, DST, SRC1, and SRC2 are not necessary for its "long-term" allocation register, in other words, Instead of invoking the Allocatereg function described in the previous section, we call the Putinreg function shown in 6.3.7 line 13th to temporarily store the value of the operand SRC1 in a register.
The Emitbranch function of line 1th to 30th of Figure 6.3.7 is used to generate assembly code for "conditional jump", and when the operand is a floating-point number, we call the Emitx87branch function on line 8th to process. When the operand is an integer, we will make a further judgment in line 11th. Since constants are present in the code area in the form of "immediate number", when the program is run, the CPU reads the machine instruction from the code area and loads the immediate number into the CPU, so when the operand SRC2 is a constant, we do not have to load the SRC1 value into the register, which does not violate the " The two operands of the same X86 assembly instruction may not all be in memory "addressing requirements. This means that we can generate a comparison instruction that is shaped like "Cmpl $, a", but cannot generate a comparison instruction that is shaped like "Cmpl B, a". Figure 6.3.7 the 11th to 14th line in "SRC2 exists and SRC2 is not a constant", the SRC1 value is loaded into a register through the Putinreg function called by row 13th. The 17th line determines whether the value of the SRC1 is in the register, and if the register is loaded, we can change the source operand SRC1 to Src1->reg in line 18th, and then generate a comparison instruction that is shaped like "Cmpl B,%eax". Line 28th calls the Putasmcode function to produce a comparison and jump instruction, as in the form "Cmpl B,%eax;jle." BB2 ".
Figure 6.3.7 Emitbranch () and Emitjump ()
Figure 6.3.7 The Emitx87branch of the 31st to 39th row is used to handle the conditional jump of the floating-point number, we will first load the operand SRC1 into the x87 stack top register on line 34th, and then generate the floating-point comparison and jump instructions on line 37th, as shown in the template 35th to 36th line. We have introduced these instructions in the "1.5 Combined C language", which is not repeated here. Figure 6.3.7 the function Emitjump of line 50th to 56th will generate assembly code for the unconditional jump.
Next, let's talk about the function emitindirectjump,6.3.8, which produces assembly code for "indirect jumps", as shown in. Figure 6.3.8 Line 7th calls the Putinreg function to load the operand SRC1 into the register, and the 10th line is used to produce ". Data", which means that the next content is the dataset, and the 11th to 17th line creates a symbolic object named "SwtchTable1". The 23rd to 33rd row creates a jump table in the data area, as shown in line 19th to 21st. Line 36th outputs ". Text", which indicates that the next content is the code area. Since SRC1 is loaded into register Reg in line 7th, we can use the name of the register in the assembly instruction, so we will change the SRC1 of the intermediate instruction to the corresponding register on line 37th. Line 38th calls Clearregs to write the necessary writeback to the registers in the x86 CPU, and line 41st calls Putasmcode to produce a assembly instruction that is shaped like "jmp*swtchtable1 (,%eax,4)".
Figure 6.3.8 Emitindirectjump ()
C Compiler Anatomy _6.3.3 assembly code Generation _ generate assembly code for jump instructions