// Copyright 2019 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. export default class Assembler { static get GENERATOR_ID() { return 0; } /** * @param {AST} the AST to build the SPIR-V from */ constructor(ast) { this.ast_ = ast; } /** * Assembles the AST into binary SPIR-V. * @return {Uint32Array} The SPIR-V binary data. */ assemble() { let total_size = 5; for (const inst of this.ast_.instructions()) { total_size += 1; for (const op of inst.operands()) { total_size += op.length(); } } let u = new Uint32Array(total_size); u[0] = 0x07230203; // Magic u[1] = 0x00010500; // Version 1.5 u[2] = Assembler.GENERATOR_ID; // Generator magic number u[3] = this.ast_.getIdBounds(); // ID bounds u[4] = 0; // Reserved let idx = 5; for (const inst of this.ast_.instructions()) { let op_size = 1; for (const op of inst.operands()) { op_size += op.length(); } u[idx++] = op_size << 16 | inst.opcode(); for (const op of inst.operands()) { idx = this.processOp(u, idx, op); } } return u; } processOp(u, idx, op) { if (op.type() === "string") { let len = 0; let v = 0; for (const ch of op.value()) { v = v | (ch.charCodeAt(0) << (len * 8)); len += 1; if (len === 4) { u[idx++] = v; len = 0; v = 0; } } // Make sure either the terminating 0 byte is written or the last // partial word is written. u[idx++] = v; } else if (op.type() === "float") { // TODO(dsinclair): Handle 64 bit floats ... let b = new ArrayBuffer(4); let f = new Float32Array(b); f[0] = op.value(); let u2 = new Uint32Array(b); u[idx++] = u2[0]; } else { u[idx++] = op.value(); } for (const param of op.params()) { idx = this.processOp(u, idx, param); } return idx; } }