| // 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; | |
| } | |
| } |