UNPKG

js-slang

Version:

Javascript-based implementations of Source, written in Typescript

176 lines 6.38 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const walkers_1 = require("../../utils/walkers"); /* * GPU Body verifier helps to ensure the body is parallelizable * It does a series of checks to make sure the loop can be parallelized easily * Upon termination will update: * @state: number that indicates the dimensions you can parallize till (max 3) * @localVar: local variables in the body * @outputArray: array that is being written to */ class GPUBodyVerifier { /** * * @param node body to be verified * @param counters list of for loop counters (to check array assignment) */ constructor(program, node, counters) { /* * Checks if the GPU body is valid * 1. No return/function declarations/break/continue * 2. No functions except math_* * 3. Only ONE assignment to a global result variable * 4. Assigning to an array at specific indices (i, j, k from for loop counters) */ this.checkBody = (node) => { let ok = true; // 1. check illegal statements (0, walkers_1.simple)(node, { FunctionDeclaration() { ok = false; }, ArrowFunctionExpression() { ok = false; }, ReturnStatement() { ok = false; }, BreakStatement() { ok = false; }, ContinueStatement() { ok = false; } }); if (!ok) { return; } // 2. check function calls are only to math_* const mathFuncCheck = new RegExp(/^math_[a-z]+$/); (0, walkers_1.simple)(node, { CallExpression(nx) { if (nx.callee.type !== 'Identifier') { ok = false; return; } const functionName = nx.callee.name; if (!mathFuncCheck.test(functionName)) { ok = false; return; } } }); if (!ok) { return; } // 3. check there is only ONE assignment to a global result variable // get all local variables const localVar = new Set(); (0, walkers_1.simple)(node, { VariableDeclaration(nx) { if (nx.declarations[0].id.type === 'Identifier') { localVar.add(nx.declarations[0].id.name); } } }); this.localVar = localVar; // make sure only one assignment const resultExpr = []; const checker = this.getArrayName; (0, walkers_1.simple)(node, { AssignmentExpression(nx) { // assigning to local val, it's okay if (nx.left.type === 'Identifier' && localVar.has(nx.left.name)) { return; } if (nx.left.type === 'MemberExpression') { const chk = checker(nx.left); if (localVar.has(chk.name)) { return; } } resultExpr.push(nx); } }); // too many assignments! if (resultExpr.length !== 1) { return; } // 4. check assigning to array at specific indices // not assigning to array if (resultExpr[0].left.type !== 'MemberExpression') { return; } // check res assignment and its counters const res = this.getPropertyAccess(resultExpr[0].left); if (res.length === 0 || res.length > this.counters.length) { return; } // check result variable is not used anywhere with wrong indices const getProp = this.getPropertyAccess; const resArr = this.outputArray; (0, walkers_1.simple)(node, { MemberExpression(nx) { const chk = checker(nx); if (chk.name !== resArr.name) { return; } // get indices const indices = getProp(nx); if (JSON.stringify(indices) === JSON.stringify(res)) { return; } ok = false; } }, // tslint:disable-next-line (0, walkers_1.make)({ MemberExpression: () => { } })); if (!ok) { return; } for (let i = 0; i < this.counters.length; i++) { if (res[i] !== this.counters[i]) break; this.state++; } // we only can have upto 3 states if (this.state > 3) this.state = 3; }; this.getArrayName = (node) => { let curr = node; while (curr.type === 'MemberExpression') { curr = curr.object; } return curr; }; // helper function that helps to get indices accessed from array // e.g. returns i, j for res[i][j] this.getPropertyAccess = (node) => { const res = []; let ok = true; let curr = node; while (curr.type === 'MemberExpression') { if (curr.property.type !== 'Identifier') { ok = false; break; } res.push(curr.property.name); curr = curr.object; } if (!ok) { return []; } this.outputArray = curr; return res.reverse(); }; this.program = program; this.node = node; this.counters = counters; this.state = 0; this.checkBody(node); } } exports.default = GPUBodyVerifier; //# sourceMappingURL=bodyVerifier.js.map