Add flattenLoops pass
This commit is contained in:
parent
3a83ffb366
commit
8d00baafd0
74
gir.js
74
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) <io>
|
||||
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);
|
||||
|
|
30
ir.md
30
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
|
||||
|
|
|
@ -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`.
|
||||
|
|
Loading…
Reference in New Issue