1 / 97

COMPILER CONSTRUCTION

COMPILER CONSTRUCTION. Principles and Practice Kenneth C. Louden. 8. Code Generation. Contents. Part One 8.1 Intermediate Code and Data Structure for code Generation 8.2 Basic Code Generation Techniques Part Two 8.3 Code Generation of Data Structure Reference

darva
Télécharger la présentation

COMPILER CONSTRUCTION

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. COMPILER CONSTRUCTION Principles and Practice Kenneth C. Louden

  2. 8. Code Generation

  3. Contents Part One 8.1 Intermediate Code and Data Structure for code Generation 8.2 Basic Code Generation Techniques Part Two 8.3 Code Generation of Data Structure Reference 8.4 Code Generation of Control Statements and Logical Expression 8.5 Code Generation of Procedure and Function calls Part Three 8.6 Code Generation on Commercial Compilers: Two Case Studies 8.7 TM: A Simple Target Machine 8.8 A Code Generator for the TINY Language 8.9 A Survey of Code Optimization Techniques 8.10 Simple Optimizations for TINY Code Generator

  4. 8.6 Code Generation in Commercial Compilers: Two Case Studies Borland’s C Compiler for 80X86 Sun’s C Compiler for SparcStations

  5. For example, Consider the C procedure Void f ( int x, char c) { int a[10]; double y; … }

  6. The activation record for a call to f would appear as Offset of x Offset of c fp Offset of a Offset of y

  7. Assuming two bytes for integers, four bytes for addresses, one byte for character and eight bytes for double-precision floating point, we would have the following offset values: Now, an access of a[i], would require the computation of the address: (-24+2*i)(fp)

  8. For the expression: ( x = x +3 ) + 4, the p-code and three-address code: Lad x Lod x Ldc 3 Adi t1=x+3 Stn x=t1 Ldc 4 Adi t2=t1+4

  9. 8.6.1 The Borland 3.0 C Compiler for the 80X86

  10. Consider the examples of the output of this compiler with the following assignment (x = x +3 ) + 4 • The assembly code for this expression as produced by the Borland 3.0 compiler for the Intel 80x86 is as follows: mov ax, word ptr [bp-2] add ax, 3 mov word ptr [bp-2], ax add ax, 4 • Notes: • The bp is used as the frame pointer. • The static simulation method is used to convert the intermediate code into the target code.

  11. For the expression: ( x = x +3 ) + 4, • The p-code and three-address code: Lad x Lod x Ldc 3 Adi t1=x+3 Stn x=t1 Ldc 4 Adi t2=t1+4

  12. 1) Array Reference An example: (a [ i + 1 ] = 2 ) + a [ j ] Assume that i j, and a are local variables declared as int i, j; int a[10]; The Borland C compiler generates the following assembly code for the above expression (in next page)

  13. Expression: (a [ i + 1 ] = 2 ) + a [ j ] ( 1 ) mov bx,word ptr [bp-2] ( 2 ) shl bx , 1 ( 3 ) l ea ax, word ptr [bp-22] ( 4 ) add bx , ax ( 5 ) mov ax , 2 ( 6 ) mov word ptr [bx],ax ( 7 ) mov bx,word ptr [bp-4] ( 8 ) shl bx , 1 ( 9 ) l ea dx,word ptr [bp-24] ( 1 0 ) add bx , dx ( 1 1 ) add ax,word ptr [bx] The compiler has applied the algebraic fact to compute address: address(a [ i + 1 ]) = base _ address (a) + (i + 1)*elem_size (a) = (base _ address (a) + elem_size (a)) + i*elem_size (a)

  14. Array reference generated by a code generation procedure. ( a [ i + 1 ] = 2 ) + a [ j ] lda a lod i ldc 1 a d i ixa elem_size(a) ldc 2 s t n lda a lod j ixa elem_size(a) ind 0 adi

  15. 2) Pointer and Field References Assume the declarations of previous examples: typedef struct rec { int i; char c; int j; } Rec; typedef struct treeNode { int val; struct treeNode * lchild, * rchild; } TreeNode; … Rec x; TreeNode *p;

  16. Assume that X and P are declared as local variables and that appropriate allocation of pointers has been done. • Consider, first, the sizes of the data types involved. Integer variable has size 2 bytes; Character variable has size 1 bytes; The pointer has size 2 bytes. • The code generated for the statement x.j =x.i; is mov ax, word ptr [bp-6] mov word ptr [bp-3],ax • Notes: • Local variables are allocated only on even-byte boundaries; • The offset computation for j (-6 + 3 = -3 ) is performed statically by the compiler.

  17. The code generated for the statement p->lchild = p; is mov word ptr [si+2], si • And the statement p = p->rchild; is mov si, word ptr [si+4]

  18. 3) If and While-Statement • The statements we use are if (x>y) y++; else x--; and while (x<y) y -= x; • The Borland compiler generates the following 80x86 code for the given if-statement: cmp bx , dx jle short @1@86 inc dx jmp short @1@114 @1@86 : dec bx @1@114 :

  19. For the given while-statement: jmp short @1@170 @1@142 : sub dx , bx @1@170 : cmp bx , dx jl short @1@142

  20. 4) Function definition and call • The examples are the C function definition: int f( int x, int y) { return x+y+1 ; } • And a corresponding call f (2+3, 4)

  21. The Borland compiler for the call f (2+3, 4): mov ax,4 push ax mov ax,5 push ax call near ptr _f pop cx pop cx • Notes: The arguments are pushed on the stack in reverse order; The caller is responsible for removing the arguments from the stack after the call. The call instruction on the 80x86 automatically pushes the return address onto the stack.

  22. Now, consider the code generated by the Borland compiler for the definition of f: _ f proc near push bp mov bp , sp mov ax, word ptr [bp+4] add ax, word ptr [bp+6] inc ax jmp short @1@58 @1@58 : pop bp ret _ f endp

  23. After these operations, the stack looks as follows: The body of f then corresponds to the code that comes next mov ax, word ptr [bp+4] add ax, word ptr [bp+6] inc ax Finally, the code executes a jump, restores the old bp from the stack, and returns to the caller.

  24. 8.6.2 The Sun 2.0 C Compiler for Sun SPARCstation

  25. Consider again with the assignment (x = x + 3 ) + 4 • The Sun C compiler produces assembly code: ld [ %fp + - 0x4 ] , % o1 add %o1 , 0x3 , %o1 st %o1 , [ %fp + - 0x4 ] ld [ %fp + - 0x4 ] , %o2 add %o2 , 0x4 , %o3

  26. 1) Array Reference ( a [ i + 1 ] = 2 ) + a [ j ] translated to the following assembly code by the Sun compiler: ( 1 ) add %fp , - 0x2c , %o1 /*fp-44 ( 2 ) l d [ %f p + - 0x4 ] , %o2 ( 3 ) sll %o2 , 0x2 , %o3 ( 4 ) mov 0x2 , %o4 ( 5 ) st %o4 , [ %o1 + %o3 ] ( 6 ) add %f p , - 0x30 , %o5 /*fp-48 ( 7 ) ld [ %fp + - 0 x 8 ] , % o 7 ( 8 ) sll %o7 , 0 x 2 , % l 0 ( 9 ) ld [ %o5 + % l 0 ] , %l1 ( 1 0 ) mov 0x2 , %l2 ( 1 1 ) add %l2 , %l1 , %l3

  27. 2)Pointer and Field References typedef struct rec { int i; char c; int j; } Rec; typedef struct treeNode { int val; struct treeNode * lchild, * rchild; } TreeNode; … Rec x; /*allocated only on 4-bytes boundaries. TreeNode p; /*4 bytes sizes.

  28. The code generated for the assignment x.j =x.i; is ld [%fp+-0xc], %o1 st %o1, [%fp+-0x4] • The pointer assignment p =p - > r c h i l d; results in the target code: ld [ % f p + - 0x10 ] , %o4 ld [%o4 +0x8],%o5 st %o5 , [ %f p + - 0x10 ]

  29. 3) If- and while-statements if (x>y) y++; else x--; The Sun SPARCstation compiler generates the following code: ld [ % f p + - 0x4 ] , %o2 ld [ % f p + - 0x8 ] , %o3 cmp %o2 , %o3 bg L16 nop b L15 nop

  30. L16 : ld [ %f p + - 0x8 ] , %o4 add %o4 , 0x1 , %o4 st %o4,[ %fp+-0x8] b L17 nop L15 : ld [ %fp + - 0x4 ] , %o5 sub % o 5 , 0 x 1 , % o 5 st %o5,[ %fp+-0x4] L17 :

  31. and while (x<y) y -= x; The code generated by the Sun compiler for the while-loop is ld [ % f p + - 0x4 ] , %o7 ld [ % f p + - 0x8 ] , %10 cmp %o7 , %10 bl L21 nop b L20 nop L21 :

  32. L18 : ld [ % f p + - 0 x 4 ] , % 1 1 ld [ % f p + - 0 x 8 ] , % 1 2 sub % 1 2 , % 1 1 , % 1 2 st %12,[ %fp+-0x8] ld [ % f p + - 0 x 4 ] , % 1 3 ld [ % f p + - 0 x 8 ] , % 1 4 cmp % 1 3 , % 1 4 bl L18 nop b L22 nop L22 : L20 :

  33. 4) Function Definition and Call We use the same function definition as previously the C function definition: int f( int x, int y) { return x+y+1 ; } and a corresponding call f (2+3, 4) Sun compiler generates the following code: mov 0x5, %o0 mov 0x4, %o1 call _f, 2

  34. And the code generated for the definition f is _ f : !#PROLOGUE# 0 sethi %hi ( LF62) , %gl add %gl , %lo ( L F 6 2 ) , %gl save %sp , %gl , %sp !#PROLOGUE# 1 st %i0 , [ %fp + 0x44 ] st %i1, [%fp+0x48] L64 : . seg " text " ld [ %fp + 0x44 ] , %o0 ld [%fp+0x48] ,%o1

  35. add %o0 , %o1 , %o0 add %o0 , 0x1 , %o0 b LE62 nop LF62 : mov %o0 , %i0 ret Restore • Notes: • The call passes the arguments in register O0 and O1, rather than on the stack; • The call indicates with number 2 how many registers are used for this purpose; • The “o” registers become the “i” registers after call.

  36. 8.7 TM: A Simple Target Machine

  37. In the section following this one will present a code generator for the TINY language Generate target code directly for a very simple machine that can be easily simulated This machine is called TM (for Tiny Machine).

  38. 8.7.1 Basic Architecture of the Tiny Machine

  39. TM consists of a read-only instruction memory, a data memory, and a set of eight general-purpose registers. • These all use nonnegative integer addresses beginning at 0. • Register 7 is the program counter and is the only special register, as described below. • The C declarations #define IADDR_SIZE ... /* size of instruction memory */ #define DADDR_SIZE... /* size of data memory */ #define NO_REGS 8 /* number of registers */ #define PC_REG 7 Instruction iMem[IADDR_SIZE]; int dMem[DADDR_SIZE]; int reg[NO_REGS];

  40. TM performs a conventional fetch-execute cycle: d o /* fetch */ Current Instruction = iMem [reg[pcRegNo]++]; /* execute current instruction */ . . . while (!(halt||error)); • A register-only instruction has the format opcode r, s, t • There are two basic instruction formats: Register only ------ RO instruction; Register-memory ------ RM instruction. • The complete instruction set of the Tiny Machine is listed in the next page.

  41. RO Instructions Format opcode r, s, t Opcode Effect HALT stop execution (operands ignored) IN reg [r] ← integer value read from the standard input (s and t ignored) OUT reg [r] → the standard output (s and t ignored) ADD reg [r] = reg[s] + reg[t] SUB reg [r] = reg[s] - reg[t] MUL reg [r] = reg[s] * reg[t] DIV reg [r] = reg[s] / reg[t](may generate ZERO _ DIV)

  42. RM InstructionsFormat opcode r, d(s) (a=d+ r e g [s]; any reference to DMem [a] generates DEME_ERR if a<0 or a≥DADDR – SIZE ) • Opcode Effect LD reg [r] = dMem[a] (load r with memory value at a) LDA reg [r] = a (load address a directly into r) LDC reg [r] = d (load constant d directly into r – s is ignored) ST dMem[a] = reg[r] (store value in r to memory location a) JLT if (reg [r]<0) reg [PC_REG] = a (jump to instruction a if r is negative, similarly for the following) JLE if (reg [r]<=0 reg [PC_REG] = a JGE if (reg [r]>0) reg [PC_REG] = a JGT if (reg [r]>0) reg [PC_REG] = a TEQ if (reg [r]==0) reg [PC_REG] = a JNE if (reg [r]!=0) reg [PC_REG] = a

  43. A register-memory instruction has the format opcode r,d(s) • RM instructions include three different load instructions corresponding to the three addressing modes • “load constant” (LDC), • “load address” (LDA), • and “load memory” (LD). • Since the instruction set is minimal, some comments are in order about how they can be used to achieve almost all standard programming language operations. • (More detail in the page P456-457) (1) The target register in the arithmetic, IN, and load operations comes first, and the source register(s) come second. (2) All arithmetic operations are restricted to registers.

  44. (3) There are no floating-point operations or floating-point registers. (4) There are no addressing modes specifiable in the operands as in some assembly code. (5) There is no restriction on the use of the pc in any of the instructions. LDA 7, d(s) (6) There is also no indirect jump instruction. LD 7, 0(1) (7) The conditional jump instructions (JLT, etc.) can be made relative to the current position in the program by using the pc as the second register. JEQ 0, 4(7) (8) There is no procedure call or JSUB instruction. LD 7, d(s)

  45. 8.7.2 The TM Simulator

  46. The machine simulator accepts text files containing TM instructions as described above, with the following conventions: • An entirely blank line is ignored. • A line beginning with an asterisk is considered a comment and is ignored. • Any other line must contain an integer instruction location followed by a colon followed by a legal instruction. Any text occurring after the instruction is considered a comment and is ignored. • Figure 8.16 A TM program showing format conventions

  47. * This program inputs an integer, computes * its factorial if it is positive, * and prints the result 0 : IN 0, 0, 0 r0 = read 1 : JLE 0, 6 (7) if 0 < r0 then 2 : LDC 1,1,0 r1 = 1 3 : LDC 2, 1, 0 r2 = 1 * repeat 4 : MUL 1, 1, 0 r1 = r1*r0 5 : SUB 0, 0, 2 r0 = r0-r2 6 : JNE 0, -3 (7) until r0 == 0 7 : OUT 1, 0, 0 write r1 8 : HALT 0, 0, 0 halt * end of program Note: there is no need for location to appear in ascending sequence as they do above.

  48. For example, a code generator is likely to generate the code of Figure 8.16 in the following sequence: 0 : IN 0,0,0 2 : LDC 1,1,0 3 : LDC 2,1,0 4 : MUL 1,1,0 5 : SUB 0,0,2 6 : JNE 0,-3(7) 7 : OUT 1,0,0 1 : JLE 0,6(7) 8 : HALT 0,0,0

  49. 8.8 Code Generation for the Tiny Language

  50. 8.8.1 The TM Interface of the TINY Code Generator

More Related