1 / 22

7. Phase 3 : Code Generation Part II

7. Phase 3 : Code Generation Part II. Reverse Polish (RP) notation. RP expressions and code generation. genExpression . genSubExpression . Operands. Operators. ! . + , - , * , / , % . && , || . == , != , > , < , >= , <=. Reverse Polish Notation.

yelena
Download Presentation

7. Phase 3 : Code Generation Part II

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. 7. Phase 3 : Code Generation Part II • Reverse Polish (RP) notation. • RP expressions and code generation. • genExpression. • genSubExpression. • Operands. • Operators. • !. • +, -, *, /, %. • &&, ||. • ==, !=, >, <, >=, <=.

  2. Reverse Polish Notation • Reverse Polish (RP) notation was invented by the Polish mathematician Jan Likasiewicz (pronounced Wu-ka-shave-itch). • Consider the following arithmetic expression : ( ( 3 + 4) * 6) - (3 / 2) • In RP notation we write the operations after the operands : 3 4 + 6 * 3 2 / - • Advantages of RP notation : • No brackets required. • Very easy to process automatically using a stack. • Most (all?) computers process arithmetic expressions this way.

  3. Processing RP Expressions • Assume that the expression is read from input. • When an operand is read it is pushed onto a stack. • When an operator is read : • The required operands are popped from the stack. • 1 or 2 for C--. • The operator is applied to the popped operands. • The result of applying the operator is pushed onto the stack. • When all of the expression has been processed the result is at the top of the stack. • The result should be the only value on the stack. If it is not then an error has occurred. • There were too many operands for the number of operators provided.

  4. Processing RP Expressions : Example Operand stack Input Current Remaining Operand [ ] 3 4 + 6 * 3 2 / - [ 3 ] 4 + 6 * 3 2 / - [ 4 ] + 6 * 3 2 / - [ 3 ] [ 4 ] 6 * 3 2 / - + [ 3 ] [ 7 ] 6 * 3 2 / - [ 6 ] * 3 2 / - [ 7 ]

  5. Processing RP Expressions : Example II Operand stack Input Current Remaining Operand [ 6 ] 3 2 / - * [ 7 ] [ 42 ] 3 2 / - [ 3 ] 2 / - [ 42 ] [ 2 ] / - [ 3 ] [ 42 ]

  6. Processing RP Expressions : Example III Operand stack Input Current Remaining Operand [ 2 ] - / [ 3 ] [ 42 ] [ 1.5 ] - [ 42 ] [ 1.5 ] - [ 42 ] [ 40.5 ]

  7. RP Expressions And Code Generation • In the code generator we do not read the expression from input we ‘read’ it from an RPolish data structure : struct RPolish { bool isOperator ; bool isString ; string rator ; string srand ; int irand ; RPolish *next ; } ; // RPolish • This is obviously a linked list. • It is built by calling toRPE (defined in rpolish.cxx) with the expression ast as the parameter : exprrp = toRPE(expr) ; • toRPE does a Post-Order Walk of expr.

  8. RP Expressions And Code Generation II • Like all modern chips the M68K provides hardware support for a stack. • LINK, UNLK, post-increment and pre-decrement address register indirect addressing modes. • We need to know how big a stack we are going to need for each expression. • Only the operands are placed on the stack so a stack big enough to hold all the operands at once will be big enough. • Actually it will probably be far too big but who cares? count = nmrOperands(exprrp) ; • nmrOperands is defined in rpolish.cxx. • Stack size is 4 * count since each operand requires 4 bytes.

  9. genExpression void genExpression(SymTab *st, Expression *expr, int &label, int &finalLabel) { RPolish *exprrp = NULL ; int count = 0 ; exprrp = toRPE(expr) ; count = nmrOperands(exprrp) ; cout << “\tLINK A0,#-” ; cout << count * 4 << endl ; genSubExpression(exprrp, label, finalLabel) ; cout << “\tMOVE.L A0@+,D0\n” ; cout << “\tUNLK A0\n” ; } // genExpression

  10. genSubExpression • This is where the real work gets done. void genSubExpression(RPolish *exprrp, int &label, int &finalLabel) { while (exprrp != NULL) { if (!(exprrp->isOperator)) // Generate code to push operand onto stack. else if (exprrp->rator = “!”) // Generate code for NOT operator. else // Generate code for binary operators. exprrp = exprrp->next ; } } // genSubExpression • ! takes only one operand, the others all take two.

  11. Pushing Operands Onto The Stack • Operands are either variable/constant names (i.e. strings), boolean literals (i.e. strings) or integer literals (i.e. integers). cout << “\tMOVE.L “ ; if (exprrp->isString) cout << exprrp->srand ; else cout << ‘#’ << exprrp->irand ; cout << “,A0@-\n” ; • Note the unwinding of the stack due to the pre-decrement of A0.

  12. Unary Operators • The only unary operand is !. • Required M68K assembly code : MOVE.L A0@+,D7 | Pop operand into D7 NOT.L D7 | Take logical not of D7 MOVE.L D7,A0@- | Push result onto stack • Note that these instructions must be ‘tabbed in’. • Note unwinding and winding of stack.

  13. Binary Operators cout << “\tMOVE.L A0@+,D6\n“ ; cout << “\tMOVE.L A0@+,D7\n“ ; if (Comparison operator) // Generate code for comparisons. else if (&& or ||) // Generate code for boolean operator. else if (+) // Generate code for plus operator. else if (-) // Generate code for minus operator. else if (*) // Generate code for multiplication operator. else if (/) // Generate code for division operator. else if (%) // Generate code for remainder operator. cout << “\tMOVE.L D7,A0@-\n“ ;

  14. Boolean Operators • These are the simplest. • Required M68K assembly code for && : AND.L D6,D7 | And D6 into D7 • Note that this instruction must be ‘tabbed in’. • For || use OR.L rather than AND.L.

  15. Addition & Subtraction • These are also simple. • Required M68K assembly code for + : ADD.W D6,D7 | Add D6 into D7 BVS LfinalLabel | Check V bit EXT.L D7 | Sign extend D7 • Note that these instructions must be ‘tabbed in’. • For subtraction use SUB.W rather than ADD.W. • We add as 16 bit words so that the V bit is set on overflow. • Must sign extend result to get correct 32 bit value.

  16. Multiplication, Division & Remainder • Multiplication, division and remainder aren’t so simple. • M68K will not set the V bit for a multiply. Must do overflow checking ‘by hand’. • M68K will not set the V bit for a division or remainder. However, there is no need for overflow checking. • On divide by 0 VxWorks crashes. • No point doing overflow checking in this case. • Remainder requires bit shifting.

  17. Multiplication & Division • Required M68K assembly code for * : MULS.W D6,D7 | Multiply D6 into D7 CMP.L #INT_MAX_16_BIT,D7 | Check for BGT LfinalLabel | overflow CMP.L #INT_MIN_16_BIT,D7 | Check for BLT LfinalLabel | underflow EXT.L D7 | Sign extend D7 • Required M68K assembly code for / : DIVS.W D6,D7 | Divide D6 into D7 EXT.L D7 | Sign extend D7 • Note that these instructions must be ‘tabbed in’. • Must sign extend result to get correct 32 bit value.

  18. Remainder • DIVS.W operation puts the quotient in LSWord and the remainder in the MSword of the destination. • For / must clear MSWord. Sign extend will handle that. • For % must left shift quotient into LSWord then sign extend. • Required M68K assembly code for % : DIVS.W D6,D7 | Divide D6 into D7 LSR.L #8,D7 | Shift right 8 bits LSR.L #8,D7 | And again EXT.L D7 | Sign extend D7 • Need two LSRs because 8 bits is the maximum distance that can be shifted at once. • Note that these instructions must be ‘tabbed in’. • Must sign extend result to get correct 32 bit value.

  19. Comparison Operators • This is where it gets a bit clunky. • What I wanted to do (e.g. for ==) : CMP.L D6,D7 | Compare D6 with D7 BEQ #2 | Branch round false case MOVE.L #falseval,D7 | Set false result BRA #2 | Branch round true case MOVE.L #trueval,D7 | Set true result • All the books say I can use a literal in a PC relative branch. • The GNU assembler won’t allow it. • Instead we have to use labels. • We’ll have to generate label numbers during code generation. • That’s why we need the label parameter.

  20. Comparison Operators II • Declare two variables, labelT and labelF. Set them as follows : labelT = label++ ; labelF = label++ ; • Note that label must be incremented after each use. • Required M68K assembly code for == : CMP.L D6,D7 | Compare D6 with D7 BEQ.L LlabelT | Branch round false case MOVE.L #falseval,D7 | Set false result BRA LlabelF | Branch round true case LlabelT: MOVE.L #trueval,D7 | Set true result LlabelF:

  21. Comparison Operators III • Code for the other comparison operators is more or less the same. • Only difference is which branch to use after the compare. • != use BNE. • > use BGT. • < use BLT. • >= use BGE. • <= use BLE.

  22. Summary • Print out a copy of rpolish.cxx. • Not necessary that you understand it but it would be good for your souls. • Type in genExpression. • genSubExpression. • Operands. • Operators. • Not. • Booleans. • Add, subtract. • Multiply, divide, remainder. • Comparisons. Monkey see, monkey do. I’ve more or less done this for you. Copy what my gener does.

More Related