1 / 11

Understanding Intermediate Language (IL) in Compiler Code Generation

This discussion explores the role of Intermediate Language (IL) in compiler design, highlighting the clear distinction between machine-dependent and machine-independent components. By using IL, the same high-level language can be processed on various machines simply by modifying the IL, enabling effective code reuse and optimization. The text explains stack-based implementation, code generation techniques with examples, and the structure of abstract syntax trees (ASTs) in generating three-address code. Key classes like `BinopNode`, `IdNode`, and function manipulation methods are illustrated, reinforcing the importance of IL.

bena
Télécharger la présentation

Understanding Intermediate Language (IL) in Compiler Code Generation

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. Code Generation Discussion Section 11/20/2012

  2. Why iL? • Clear demarcation between machine dependent and independent parts of the compiler • Same language can be processed on different machines using by only changing the IL and re-using the IL->ML conversion • Code optimization is possible at this stage • Consider it as the language of an abstract machine

  3. Stack based implementation • Instead of registers, we use a stack of values to store the intermediate results • A program to compute 7 + 5 using accumulator: • acc := 7 • push acc • acc:= 5 • acc:= acc + top_of_stack • pop stack

  4. Commonly used IL • P-code for Pascal • Bytecode for Java • Three address code • - Language independent • target := operand1 ⊕ operand2 • 4-tuple : (target, operand1, operator, operand2) • class AST { • ... • /** Generate code for me, leaving my value on the stack. */ • virtual void cgen (VM* machine); • } • class BinopNode : public AST { • Operand* cgen (VM* machine) { • Operand* left = getLeft ()->cgen (machine); • Operand* right = getRight ()->cgen (machine); • Operand* result = machine->allocateRegister (); • machine->emitInst (result, translateToInst (getOp ()), left, right); • return result; • } • emitInst produces three-address instructions

  5. identifiers • class IdNode : public AST { • ... • Operand* cgen (VM* machine) { Operand result = machine->allocateRegister (); machine->emitInst (MOVE, result, getDecl() ->getMyLocation(machine)); return result; • } • }

  6. Calls • class CallNode : public AST { ... Operand* cgen (VM* machine) { AST* args = getArgList (); for (inti = args->arity ()-1; i >= 0; i -= 1) machine->emitInst (PARAM, args.get (i)->cgen (machine)); Operand* callable = getCallable ()->cgen (machine); machine->emitInst (CALL, callable, args->arity ()); return Operand::ReturnOperand; } • }

  7. IF • class IfExprNode : public AST { ... Operand* cgen (VM* machine) { Operand* left = getLeft ()->cgen (machine); Operand* right = getRight ()->cgen (machine); Label* elseLabel = machine->newLabel (); Label* doneLabel = machine->newLabel (); machine->emitInst (IFNE, left, right, elseLabel); Operand* result = machine->allocateRegister (); machine->emitInst (MOVE, result, getThenPart ()->cgen (machine)); machine->emitInst (GOTO, doneLabel); machine->placeLabel (elseLabel); machine->emitInst (MOVE, result, getElsePart ()->cgen (machine)); machine->placeLabel (doneLabel); return result; } • }

  8. def • class DefNode : public AST { ... Operand* cgen (VM* machine) { machine->placeLabel (getName ()); machine->emitFunctionPrologue (); Operand* result = getBody ()->cgen (machine); machine->emitInst (MOVE, Operand::ReturnOperand, result); machine->emitFunctionEpilogue (); return Operand::NoneOperand; } • }

  9. Example 1 • int main(void) • { • int i; • int b[10]; • for (i = 0; i < 10; ++i) { • b[i] = i*i; • } • } • Code Generation: • i:= 0 ; assignment • L1: if i >= 10 goto L2 ; conditional jump • t0 := i*i • t1 := &b ; address-of operation • t2 := t1 + i ; t2 holds the address of b[i] • *t2 := t0 ; store through pointer • i := i + 1 • goto L1 • L2: end

  10. Example 2 • def fib(x) = • if x = 1 then 0 else • if x = 2 then 1 else • fib(x - 1) + fib(x – 2) • fib: function prologue • r1 := x • if r1 != 1 then gotoL1 • r2 := 0 • goto L2 • L1: • r3 := x • if r3 != 2 then gotoL3 • r4 := 1 • goto L4 • L3: • r5 := x • r6 := r5 – 1 • paramr6 • call fib, 1 • r7 := rret • r8 := x • r9 := r8 – 2 • paramr9 • call fib, 1 • r10 := r7 + rret • r4 := r10 • L4: • r2 := r4 • L2: • rret:= r2 • function epilogue

  11. More examples • Some more examples

More Related