CS536 Homework 3
| ||||||
QuestionsHomework assignments must be done individually. Collaboration on homework assignments is not allowed. In project 5 we are generating JVM code for all the CSX components. For an expression rooted at AST node n, a call to CodeGenerating.visit(n) generates code to evaluate the expression, leaving the result at the top of the JVM's operand stack. While this kind of code is easy to generate, storing intermediate values on the stack rather than in registers can be inefficient. Almost all modern architectures, including Intel's ubiquitous x86, provide hardware registers. Expressions can be computed directly into registers, avoiding use of stack locations. You might think we could instead require that the visit methods for an expression should work as follows:
Unfortunately, this approach does not always work. Question 1:Assume that the AST includes only expressions that involve non short-circuited binary operators, with literals or identifiers at the leaves (no unary operators or function calls as operands). Also assume that in the generated code, all operands must be in registers (i.e., neither operand of a binary operator can be in a memory location, nor can it be a literal value). For the following examples, judge whether the approach described above works. If not, show pseudo-code that uses the least possible number of registers needed to evaluate the expression. Provide the AST of expression and a pseudo-code version of the code to evaluate the expression (code that works, not the erroneous code that would be generated using the approach described above). If the approach described above works, you can just answer "Yes"; you do not need to show the AST and pseudo-code. You can assume that no optimization is done prior to code generation.
Here is a example of AST and pseudo-code for the expression a-b (use the same kind of pseudo-code in your answer):
Note that an expression's operands need not be evaluated left-to-right. For example, the following pseudo-code would also be OK for the expression a - b: load b into T1 // evaluate the right operand first load a into T0 T0 = T0 - T1 Question 2:Use the same assumptions about the AST and the generated code as for Question 1, including the fact that an expression's operands can be evaluated either left-to-right or right-to-left. Also assume that all operators are non-commutative and non-associative (i.e., the expression a op b is not equivalent to the expression b op a, and the expression (a op b) op c is not equivalent to the expression a op (b op c) ). You are to give a recursive algorithm that works as follows:
In other words, complete the following method: int numRegisters(ASTNode node) { // add code to calculate and return the number of // registers required to generate code for the whole // expression (whose root is node) } You may use pseudo-code such as node.leftChild, node.rightChild, max( , ), min( , ), and isLeaf( ). For example, for the expression a - b, the input to the algorithm is the root node of the expression tree. The algorithm will recursively determine that the number of registers required to generate code for each operand is 1 (because each operand is a leaf and thus requires one register). The output of the algorithm for this example should be 2 (because the whole expression can be evaluated using two registers, as illustrated above in Part 1, but it cannot be evaluated using just one register). |