costreamjs
Version:
A high-performance streaming programming language for parallel architecture. This repo (js-version) is created for better using & reading & debugging.
578 lines (563 loc) • 18.5 kB
JavaScript
import { definePrivate } from "./js-hacker.js"
import { error } from "../utils";
export class Node {
constructor(loc) {
this._loc = loc;
['_loc'].forEach(key => {
definePrivate(this, key)
})
}
}
/********************************************************/
/* 1.1 declaration */
/********************************************************/
export class declareNode extends Node {
constructor(loc, type, init_declarator_list) {
super(loc)
this.type = type
this.init_declarator_list = [].concat(init_declarator_list)
}
}
export class idNode extends Node{
constructor(loc, name, arg){
super(loc)
this.name = name
this.arg_list = []
if(arg){
this.isArray = true
this.arg_list.push(arg)
}
}
}
export class declarator extends Node {
constructor(loc, identifier, initializer) {
super(loc)
this.identifier = identifier
initializer && (this.op = '=')
this.initializer = initializer
definePrivate(this, 'type')
}
}
/********************************************************/
/* 1.2 function.definition 函数声明 */
/********************************************************/
export class function_definition extends Node {
constructor(loc, type, declarator,param_list, compound) {
super(loc)
this.type = type
this.name = declarator.name
this.op1 = '('
this.param_list = param_list
this.op2 = ')'
this.funcBody = compound
}
}
/********************************************************/
/* 2. composite */
/********************************************************/
export class compositeNode extends Node {
constructor(loc, head = {}, body = {}) {
super(loc)
Object.assign(this, {
op: 'composite',
compName: head.compName,
inout: head.inout,
body
})
}
}
export class compHeadNode extends Node {
constructor(loc, compName, inout) {
super(loc)
Object.assign(this, { op: 'composite', compName, inout })
}
}
export class ComInOutNode extends Node {
constructor(loc, input_list = [], output_list = []) {
super(loc)
Object.assign(this, { op1: 'input', input_list, op2: 'output', output_list })
}
}
export class inOutdeclNode extends Node {
constructor(loc, strType, id) {
super(loc)
Object.assign(this, { strType, id })
}
}
export class strdclNode extends Node {
constructor(loc, type, identifier) {
super(loc)
this.op = 'stream<'
this.id_list = [
{ type, identifier }
]
this.op2 = '>'
}
copy(){
const copy = new strdclNode(this._loc)
//为每个object申请了一块新的内存
copy.id_list = this.id_list.map(({type,identifier})=>{
const idWithShape = { type,identifier }
definePrivate(idWithShape,'shape') //定义一个不可枚举的shape属性
return idWithShape
})
return copy
}
}
export class compBodyNode extends Node {
constructor(loc, param, stmt_list) {
super(loc)
Object.assign(this, {
op1: '{',
param,
stmt_list,
op2: '}'
})
}
}
export class paramNode extends Node {
constructor(loc, param_list) {
super(loc)
if (param_list) {
this.op = 'param'
}
this.param_list = param_list
}
}
export class operBodyNode extends Node {
constructor(loc, stmt_list, init, work, win) {
super(loc)
Object.assign(this, {
stmt_list: stmt_list || [] ,
op1: 'init', init,
op2: 'work', work,
op3: 'window', win
})
}
}
export class winStmtNode extends Node {
constructor(loc, winName, options = {}) {
super(loc)
Object.assign(this, {
winName,
type: options.type,
arg_list: options.arg_list || []
})
}
}
/********************************************************/
/* 3. statement 花括号内以';'结尾的结构是statement */
/********************************************************/
export class blockNode extends Node {
constructor(loc, op1, stmt_list, op2) {
super(loc)
Object.assign(this, { op1, stmt_list, op2 })
}
}
export class jump_statement extends Node {
constructor(loc, op1, op2) {
super(loc)
Object.assign(this, { op1, op2 })
}
}
export class labeled_statement extends Node {
constructor(loc, op1, op2, op3, statement) {
super(loc)
Object.assign(this, { op1, op2, op3, statement })
}
}
export class selection_statement extends Node {
constructor(loc, op1, op2, exp, op3, statement, op4, else_statement) {
super(loc)
Object.assign(this, {
op1, op2, exp, op3,
statement, op4, else_statement
})
}
}
export class whileNode extends Node {
constructor(loc, exp, statement) {
super(loc)
Object.assign(this, {
type: 'while',
op1: '(',
exp,
op2: ')',
statement
})
}
}
export class doNode extends Node {
constructor(loc, exp, statement) {
super(loc)
Object.assign(this, {
type: 'do',
op1: '(',
statement,
op2: ')',
op3: 'while',
exp
})
}
}
export class forNode extends Node {
constructor(loc, init, cond, next, statement) {
super(loc)
Object.assign(this, {
type: 'for',
op1: '(',
init, cond, next,
op2: ')',
statement
})
}
}
/********************************************************/
/* 4. expression 计算表达式头节点 */
/********************************************************/
export class expNode extends Node {
constructor(loc) {
super(loc)
//检查是否有常量传播插件提供的 getValue 函数
if (expNode.prototype.getValue) {
expNode.prototype.getValue.call(this)
}
}
}
export class unaryNode extends expNode {
constructor(loc, first, second) {
super(loc)
Object.assign(this, { first, second })
}
};
export class castNode extends expNode {
constructor(loc, type, exp) {
super(loc)
Object.assign(this, { op1: '(', type, op2: ')', exp })
}
}
export class binopNode extends expNode {
constructor(loc, left, op, right) {
super(loc)
Object.assign(this, { left, op, right })
}
}
export class ternaryNode extends expNode {
constructor(loc, first, second, third) {
super(loc)
Object.assign(this, { first, op1: '?', second, op2: ':', third })
}
}
export class parenNode extends expNode {
constructor(loc, exp) {
super(loc)
Object.assign(this, { op1: '(', exp, op2: ')' })
}
}
export class callNode extends expNode {
constructor(loc, name, arg_list) {
super(loc)
this.name = name
this.op1 = '('
this.arg_list = arg_list
this.op2 = ')'
}
}
export class constantNode extends expNode {
constructor(loc, sourceStr='') {
super(loc)
this.source = sourceStr.toString()
}
}
/********************************************************/
/* operNode in expression's right */
/********************************************************/
export class operNode extends Node {
constructor(loc) {
super(loc)
this.outputs = []
}
}
export class fileReaderNode extends operNode{
constructor(loc,fileName,dataLength){
super(loc)
this.fileName = fileName
this.operName = 'FileReader'
this.dataLength = dataLength - 0; // 字符串转数字
}
}
export class fileWriterNode extends operNode{
constructor(loc,streamName,fileName,dataLength){
super(loc)
this.inputs = [streamName]
this.operName = "FileWriter"
this.fileName = fileName
this.dataLength = dataLength
}
}
export class compositeCallNode extends operNode {
constructor(loc, compName, inputs, params = []) {
super(loc)
Object.assign(this, {
compName,
op1: '(',
inputs,
op2: ')',
op3: '(',
params,
op4: ')'
})
}
}
export class operatorNode extends operNode {
constructor(loc, operName, inputs, operBody) {
super(loc)
Object.assign(this, { operName, inputs: inputs ||[], operBody })
}
}
export class splitjoinNode extends operNode {
constructor(loc, options = {}) {
super(loc)
this.compName = options.compName
this.inputs = options.inputs
this.stmt_list = options.stmt_list
this.split = options.split
this.body_stmts = options.body_stmts
this.join = options.join
}
}
export class pipelineNode extends operNode {
constructor(loc, options = {}) {
super(loc)
this.compName = options.compName
this.inputs = options.inputs
this.body_stmts = options.body_stmts
}
}
export class splitNode extends Node {
constructor(loc, node = {}) {
super(loc)
this.name = "split"
this.type = node instanceof duplicateNode ? "duplicate" : "roundrobin"
if (node.arg_list) {
Object.assign(this, { op1: '(', arg_list: node.arg_list, op2: ')' })
}
}
}
export class joinNode extends Node {
constructor(loc, node = {}) {
super(loc)
this.name = "join"
this.type = node instanceof duplicateNode ? "duplicate" : "roundrobin"
if (node.arg_list) {
Object.assign(this, { op1: '(', arg_list: node.arg_list, op2: ')' })
}
}
}
export class duplicateNode extends Node {
constructor(loc, arg_list) {
super(loc)
this.arg_list = arg_list
}
}
export class roundrobinNode extends Node {
constructor(loc, arg_list) {
super(loc)
this.arg_list = arg_list
}
}
export class addNode extends Node {
constructor(loc, content) {
super(loc)
this.name = "add"
this.content = content
}
}
/********************************************************/
/* 矩阵相关 node */
/********************************************************/
export class matrix_constant extends expNode{
constructor(loc, rawData){
super(loc)
definePrivate(this,'shape')
this.rawData = rawData.map(x => (
x instanceof matrix_constant ? x.rawData : x
))
if(this.rawData[0] instanceof Array){
if(Array.isArray(this.rawData[0][0])){
error(loc,"暂不支持超过2维的数据, 只能是1维向量或2维矩阵")
return
}
this.shape = [this.rawData.length, this.rawData[0].length]
}else{
// 向量型的矩阵, 行数为1
const cols = this.rawData.length
this.shape = [1, cols]
}
}
}
/* 存放矩阵切片的下标, 例如 vector[0:5] 表示 下标[0,5) 即0~5不含5
兼容多重格式(_表示 undefined), 例如
* [1:5] --- { start: 1, op:':', end: 5 }
* [1:] --- { start: 1, op:':', end: _ }
* [:5] --- { start: _, op:':', end: 5 }
* [:] --- { start: _, op:':', end: _ }
* [0] --- { start: 0, op: _ , end: _ } */
export class matrix_slice_pair extends Node {
constructor(loc, start, op, end) {
super(loc)
this.start = start
this.op = op
this.end = end
}
}
/** 存放 name[1:4, 2:5] 的结构, 寓意为矩阵切片结果 */
export class matrix_section extends expNode{
constructor(loc, exp, slice_pair_list){
super(loc)
this.exp = exp
this.slice_pair_list = slice_pair_list
}
}
export class lib_binopNode extends Node{
constructor(loc, lib_name,function_name){
super(loc)
this.lib_name = lib_name;
this.function_name = function_name;
}
}
/********************************************************/
/* 神经网络相关 node */
/********************************************************/
export class sequentialNode extends operNode {
constructor(loc, options = {}) {
super(loc)
this.compName = options.compName;
this.inputs = options.inputs;
this.arg_list = options.arg_list;
this.body_stmts = options.body_stmts;
}
};
export class layerNode extends Node {
constructor(loc, layerName, arg_list) {
super(loc);
this.layerName = layerName
this.arg_list = arg_list;
this.prevLayer = null;
this.nextLayer = null;
this.inputSize = [];
/** 神经网络层级 */
this.level = 0;
}
/** @returns {number[]} */
getInputSize(/** @type {sequentialNode} */ sequential){
if(this.prevLayer){
if(this.prevLayer instanceof denseLayerNode){
return [1, this.prevLayer.cols, 1] // 设置本层的输入数据规模, 用一个三维向量描述: [rows, cols, depth]
}else if(this.prevLayer instanceof conv2DLayerNode){
return this.prevLayer.outputFeatureMapSize
}else if(this.prevLayer instanceof maxPooling2DLayerNode){
return this.prevLayer.outputPooledSize
}else if(this.prevLayer instanceof averagePooling2DLayerNode){
return this.prevLayer.outputPooledSize
}else if(this.prevLayer instanceof activationLayerNode){
return this.prevLayer.inputSize
}else{
error("未识别的 layer 类型:", this.prevLayer)
}
}else{
if(sequential.arg_list[0] instanceof parenNode){
return sequential.arg_list[0].exp.map(_=>_.value)
}
return [1, sequential.arg_list[0].value, 1] // [rows, cols, depth]
}
}
};
export class denseLayerNode extends layerNode {
constructor(loc, layerName, arg_list = [0]) {
super(loc, layerName, arg_list);
/** 权值矩阵输入 */
this.rows = 0
/** 权值矩阵输出 */
this.cols = arg_list[0].value // FIXME: 这里简单起见直接拿到数字. 应该放到 ast2ssg 中的
}
init(/** @type {sequentialNode} */ sequential){
this.inputSize = this.getInputSize(sequential)
this.rows = this.inputSize.reduce((a,b)=>a*b) // 求得所有维度的乘积, 例如[1,100,1] 返回 1*100*1 = 100
}
}
export class conv2DLayerNode extends layerNode {
// filters, kernel_size, strides, padding
constructor(loc, layerName, arg_list = [3, [2, 2], [1, 1], [0, 0]]) {
super(loc, layerName, arg_list);
try{
this.filters = arg_list[0].value // filters
// 以下三行的 '||' 操作符的意义: 当该参数是 parenNode 时, 取它的 exp. (而当 arg_list 取上方的默认值时,则不需取 exp)
this.kernel_size = (arg_list[1].exp || arg_list[1]) .map(num => num.value) // kernel_size
this.strides = (arg_list[2].exp || arg_list[2]) .map(num => num.value) // strides
this.paddings = (arg_list[3].exp || arg_list[3]) .map(num => num.value) // paddings
}catch(err){
error(loc, "conv2DLayerNode 参数解析错误, 请检查")
}
// 以下三个成员在 init 中进行初始化
this.inputSize = []
this.outputFeatureMapSize = []
this.inputErrorSize = []
}
/** 根据上一层初始化本层输出特征图的尺寸和输入空间的维度 */
init(/** @type {sequentialNode} */ sequential){
this.outputFeatureMapSize = [];
// 本层反向传播过程中 传入误差的尺寸`
this.inputErrorSize = [];
// 按照arg_list爲傳入整個sequential結構的參數列表(rows, cols, depth)
this.inputSize = this.getInputSize(sequential);
this.outputFeatureMapSize = [
(this.inputSize[0] + 2 * this.paddings[0] - this.kernel_size[0]) / this.strides[0] + 1, // rows
(this.inputSize[1] + 2 * this.paddings[1] - this.kernel_size[1]) / this.strides[1] + 1, // cols
this.filters // depth
]
for(let i = 0; i < 2; i++) {
// 2 * (kernel_size - 1) + (outputFeaureMapSize - 1)* stride + 1
this.inputErrorSize.push(2 * (this.kernel_size[i] - 1) + (this.outputFeatureMapSize[i] - 1) * this.strides[i] + 1);
}
}
}
export class maxPooling2DLayerNode extends layerNode {
constructor(loc, layerName, arg_list = [0]){
super(loc, layerName, arg_list)
this.pool_size = arg_list[0].value
this.depth = 0
this.outputPooledSize = []
}
init(/** @type {sequentialNode} */ sequential){
this.inputSize = this.getInputSize(sequential)
this.outputPooledSize[0] = Math.floor(this.inputSize[0] / this.pool_size)
this.outputPooledSize[1] = Math.floor(this.inputSize[1] / this.pool_size)
this.outputPooledSize[2] = this.inputSize[2]
this.depth = this.inputSize[2]
}
}
export class averagePooling2DLayerNode extends layerNode {
constructor(loc, layerName, arg_list = [0]){
super(loc, layerName, arg_list)
this.pool_size = arg_list[0].value
this.depth = 0
}
init(/** @type {sequentialNode} */ sequential){
this.inputSize = this.getInputSize(sequential)
this.outputPooledSize[0] = this.inputSize[0] / this.pool_size
this.outputPooledSize[1] = this.inputSize[1] / this.pool_size
this.outputPooledSize[2] = this.inputSize[2]
this.depth = this.inputSize[2]
}
}
export class activationLayerNode extends layerNode {
constructor(loc, layerName, arg_list){
super(loc, layerName, arg_list)
this.count = 1;
}
init(/** @type {sequentialNode} */ sequential){
this.inputSize = this.getInputSize(sequential)
this.inputSize.forEach(num => this.count*=num)
}
}