220 likes | 383 Views
7. Phase 3 : Code Generation Part II. Reverse Polish (RP) notation. RP expressions and code generation. genExpression . genSubExpression . Operands. Operators. ! . + , - , * , / , % . && , || . == , != , > , < , >= , <=. Reverse Polish Notation.
E N D
7. Phase 3 : Code Generation Part II • Reverse Polish (RP) notation. • RP expressions and code generation. • genExpression. • genSubExpression. • Operands. • Operators. • !. • +, -, *, /, %. • &&, ||. • ==, !=, >, <, >=, <=.
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.
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.
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 ]
Processing RP Expressions : Example II Operand stack Input Current Remaining Operand [ 6 ] 3 2 / - * [ 7 ] [ 42 ] 3 2 / - [ 3 ] 2 / - [ 42 ] [ 2 ] / - [ 3 ] [ 42 ]
Processing RP Expressions : Example III Operand stack Input Current Remaining Operand [ 2 ] - / [ 3 ] [ 42 ] [ 1.5 ] - [ 42 ] [ 1.5 ] - [ 42 ] [ 40.5 ]
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.
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.
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
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.
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.
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.
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“ ;
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.
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.
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.
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.
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.
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.
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:
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.
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.