From 8d00baafd0707d5a552a6adb59c7203c49c0ef9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juhani=20Krekel=C3=A4?= Date: Wed, 23 May 2018 21:48:21 +0300 Subject: [PATCH] Add flattenLoops pass --- gir.js | 74 ++++++++++++++++++++++++++++++++++++++++++++++-- ir.md | 30 ++++++++++++++++---- optimizations.md | 13 ++++++++- 3 files changed, 107 insertions(+), 10 deletions(-) diff --git a/gir.js b/gir.js index 3e97e4e..7725207 100644 --- a/gir.js +++ b/gir.js @@ -26,6 +26,11 @@ const loop = Symbol('loop'); // Can have offset property const clear = Symbol('clear'); +// {type: jumpIfZero, target: 5} +const jumpIfZero = Symbol('jumpIfZero'); +// {type: jumpIfNonZero, target: 2} +const jumpIfNonZero = Symbol('jumpIfNonZero'); + // TODO: Add extensions from Eldis // ------------------------------------------------------------------ @@ -158,8 +163,10 @@ function parse(program) { function prettyPrint(parsed) { // ([commandObjects/offsetCommandObjects], string) function printIndented(parsed, indent = '') { - for(let command of parsed) { - let line = indent; + for(let i = 0; i < parsed.length; i++) { + let command = parsed[i]; + + let line = `${indent}${i} `; if(command.type == add) { line += `add ${command.value}`; if('offset' in command) { @@ -194,6 +201,12 @@ function prettyPrint(parsed) { line += ` (${command.offset})`; } console.log(line); + } else if(command.type == jumpIfZero) { + line += `jumpIfZero ${command.target}`; + console.log(line); + } else if(command.type == jumpIfNonZero) { + line += `jumpIfNonZero ${command.target}`; + console.log(line); } else { line += `unknown ${command.type}`; console.log(line); @@ -349,12 +362,67 @@ function addOffsetProperties(parsed) { // TODO: Optimization pass to turn copy loops into copy commands +// ([offsetCommandObjects]) → [flatCommandObjects] +function flattenLoops(offsetted) { + // ([offsetCommandObjects], int) → [flatCommandObjects] + // prevLength tells length of the flattened program up until now + function worker(offsetted, prevLength = 0) { + let flattened = []; + + for(let command of offsetted) { + if(command.type == loop) { + // flattened.length is the index of the next + // command in out flattened + // flattened.length + prevLength is the + // index of it in the resulting combined + // flattened + // Since this should be the index of the + // start of the loop body we want to point + // after the next command, which is going + // to be the jump + let startIndex = flattened.length + + prevLength + 1; + + let loopBody = worker(command.contents, + startIndex // length = index of next + ); + + // startIndex + loopBody.length is the index + // of the next command after the loop body + // The command after it is going to be the + // jump back to the start of the body, so we + // want to point to the command after it + let endIndex = startIndex + + loopBody.length + 1; + + // Add the first jump + flattened.push({type: jumpIfZero, + target: endIndex}); + + // Add the loop body + flattened = flattened.concat(loopBody); + + // Add the second loop + flattened.push({type: jumpIfNonZero, + target: startIndex}); + } else { + flattened.push(command); + } + } + + return flattened; + } + + return worker(offsetted); +} + // ([commandObjects]) → [offsetCommandObjects] function optimize(parsed) { const optimizations = [ joinAdjacentOps, transformClearLoops, - addOffsetProperties + addOffsetProperties, + flattenLoops ] return optimizations.reduce((IR, optimization) => optimization(IR), parsed); diff --git a/ir.md b/ir.md index bb586de..0c84c5b 100644 --- a/ir.md +++ b/ir.md @@ -1,9 +1,10 @@ -Gir uses two types of IR, with and without offsets +Gir uses three types of IR, with and without offsets and flattened. Under +each section each subsection shows the properties the command object of that +type has in given IR Without offsets --------------- -This is produced by `parse`. Each subsection shows the properties the -command object of that type has in IR without offsets +This is produced by `parse` ### add property | value @@ -54,9 +55,7 @@ Not generated by the parser directly, but generated by optimizations With offsets ------------ -This is produced by the optimization pass `addOffsetProperties`. Each -subsection shows the properties the command object of that type has in IR -with offsets +This is produced by the optimization pass `addOffsetProperties` ### add property | value @@ -95,3 +94,22 @@ property | value ---------|------ type | `clear` offset | The location of the cell relative to current tape position + + +Flattened +--------- +This is produced by the optimization pass `flattenLoops`. `loop` doesn't +exist in flattened IR, but all other unlisted commands are the same as in IR +with offsets + +### jumpIfZero +property | value +---------|------ +type | `jumpIfZero` +target | The index of the command to jump to if the current cell is zero + +### jumpIfNonZero +property | value +---------|------ +type | `jumpIfNonZero` +target | The index of the command to jump to if the current cell is nonzero diff --git a/optimizations.md b/optimizations.md index b8d25bf..8730442 100644 --- a/optimizations.md +++ b/optimizations.md @@ -1,4 +1,4 @@ -Gir has three optimization passes. +Gir has four optimization passes. joinAdjacentOps --------------- @@ -36,3 +36,14 @@ current tape head location the operations are performed. It also adds an `isBalanced` property to loops. This property tells if execution of loop body ends at the same cell where it began, which is useful for performing further optimizations. + +flattenLoops +------------ +* *consumes*: commands with offsets +* *produces*: flattened array commands with offsets +* *unknown commands*: passed through unmodified +* *acts on*: `loop` + +`flattenLoops` changes the nested structure where `loop` commands have a +`content` property with the loop body inside to a flat structure with +`jumpIfZero` and `jumpIfNonZero`.