From 736c658c274404084b15b450b2ab72d0e7569586 Mon Sep 17 00:00:00 2001 From: Dibyendu Majumdar Date: Fri, 3 Nov 2023 21:21:54 +0000 Subject: Backport changes in Chapter 5 to previous chapters and update Chapter5 documentation (#34) * Backport changes from chapter 5 to older chapters (#30) * Fix wrong indent * Backport to chapter 4 * Backport to chapter 3 * Backport to chapter 2 * Backport to chapter 1 * Add if statement to comment (#32) * Update visuals for chapters 1,2 & 3. Reenable drawing of edges from constants to Start for these chapters. * Update visuals for chapters 4. Revise text to explain the labeling of edges in graphs and that we omit edge from Constant to Start nodes from chapter 4. * Add code snippets for if statement parsing and the duplication and merging of ScopeNodes. Explain how scopeNodes are duplicated and merged. * Add constant check to minus node (#31) * Fix closing root block with } (#33) * Backport fix closing root block with } to chapter 4 and 3 (#35) * Show use-def edge from Phi to Region as dotted edge. Add example of Phi peephole. Update visuals. Add more examples. * Fix visuals in chapter 1 and README in chapter 4. * Remove subheading * Adjust spaces --------- Co-authored-by: XmiliaH <45106915+XmiliaH@users.noreply.github.com> --- chapter05/README.md | 220 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 219 insertions(+), 1 deletion(-) (limited to 'chapter05/README.md') diff --git a/chapter05/README.md b/chapter05/README.md index 23d936c5..78a8b1fe 100644 --- a/chapter05/README.md +++ b/chapter05/README.md @@ -15,7 +15,7 @@ Here is a recap of the nodes introduced in previous chapters: | Node Name | Type | Chapter | Description | Inputs | Value | |-----------|----------------|---------|------------------------------------------------|-------------------------------------------------------------------------------|----------------------------------------------------------------------------| | Multi | Abstract class | 4 | A node that has a tuple result | | A tuple | -| Start | Control | 1 | Start of function, now a MultiNode | A type for the input argument named `arg`. | A tuple with a ctrl token and an `arg` data node | +| Start | Control | 1 | Start of function, now a MultiNode | | A tuple with a ctrl token and an `arg` data node | | Proj | ? | 4 | Projection nodes extract values from MultiNode | A MultiNode and index | Result is the extracted value from the input MultiNode at offset index | | Bool | Data | 4 | Represents results of a comparison operator | Two data nodes | Result is a comparison, represented as integer value where 1=true, 0=false | | Return | Control | 1 | End of function | Predecessor control node and a data node for the return value of the function | Return value of the function | @@ -112,6 +112,115 @@ This involves following: updated to point to the `Phi` node. 10. Finally, we set the `Region` node as the control token, and discard the duplicated `ScopeNode`. +Here is the implementing code. + +```java +/** + * Parses a statement + * + *
+ *     if ( expression ) statement [else statement]
+ * 
+ * @return a {@link Node}, never {@code null} + */ +private Node parseIf() { + require("("); + // Parse predicate + var pred = require(parseExpression(), ")"); + // IfNode takes current control and predicate + IfNode ifNode = (IfNode)new IfNode(ctrl(), pred).peephole(); + // Setup projection nodes + Node ifT = new ProjNode(ifNode, 0, "True" ).peephole(); + Node ifF = new ProjNode(ifNode, 1, "False").peephole(); + // In if true branch, the ifT proj node becomes the ctrl + // But first clone the scope and set it as current + int ndefs = _scope.nIns(); + ScopeNode fScope = _scope.dup(); // Duplicate current scope + _allScopes.push(fScope); // For graph visualization we need all scopes + + // Parse the true side + ctrl(ifT); // set ctrl token to ifTrue projection + parseStatement(); // Parse true-side + ScopeNode tScope = _scope; + + // Parse the false side + _scope = fScope; // Restore scope, then parse else block if any + ctrl(ifF); // Ctrl token is now set to ifFalse projection + if (matchx("else")) parseStatement(); + + if( tScope.nIns() != ndefs || fScope.nIns() != ndefs ) + throw error("Cannot define a new name on one arm of an if"); + + // Merge results + _scope = tScope; + _allScopes.pop(); // Discard pushed from graph display + return ctrl(tScope.mergeScopes(fScope)); +} +``` + +## Operations on ScopeNodes + +As explained above, we duplicate ScopeNodes and merge them at a later point. There are some +subtleties in how this is implemented that is worth going over. + +### Duplicating a ScopeNode + +Below is the code for duplicating a ScopeNode. + +Our goals are: +1) Duplicate the name bindings across all stack levels +2) Make the new ScopeNode a user of all the bound nodes +3) Ensure that the order of defs in the duplicate is the same to allow easy merging + +```java +/** + * Duplicate a ScopeNode; including all levels, up to Nodes. So this is + * neither shallow (would dup the Scope but not the internal HashMap + * tables), nor deep (would dup the Scope, the HashMap tables, but then + * also the program Nodes). + *

+ * The new Scope is a full-fledged Node with proper use<->def edges. + */ +public ScopeNode dup() { + ScopeNode dup = new ScopeNode(); + for( HashMap tab : _scopes ) + dup._scopes.push(new HashMap<>(tab)); + for( int i=0; i