1// Copyright 2019 Google LLC 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15export default class Assembler { 16 static get GENERATOR_ID() { return 0; } 17 18 /** 19 * @param {AST} the AST to build the SPIR-V from 20 */ 21 constructor(ast) { 22 this.ast_ = ast; 23 } 24 25 /** 26 * Assembles the AST into binary SPIR-V. 27 * @return {Uint32Array} The SPIR-V binary data. 28 */ 29 assemble() { 30 let total_size = 5; 31 for (const inst of this.ast_.instructions()) { 32 total_size += 1; 33 for (const op of inst.operands()) { 34 total_size += op.length(); 35 } 36 } 37 38 let u = new Uint32Array(total_size); 39 u[0] = 0x07230203; // Magic 40 u[1] = 0x00010500; // Version 1.5 41 u[2] = Assembler.GENERATOR_ID; // Generator magic number 42 u[3] = this.ast_.getIdBounds(); // ID bounds 43 u[4] = 0; // Reserved 44 45 let idx = 5; 46 for (const inst of this.ast_.instructions()) { 47 let op_size = 1; 48 for (const op of inst.operands()) { 49 op_size += op.length(); 50 } 51 52 u[idx++] = op_size << 16 | inst.opcode(); 53 for (const op of inst.operands()) { 54 idx = this.processOp(u, idx, op); 55 } 56 } 57 58 return u; 59 } 60 61 processOp(u, idx, op) { 62 if (op.type() === "string") { 63 let len = 0; 64 let v = 0; 65 for (const ch of op.value()) { 66 v = v | (ch.charCodeAt(0) << (len * 8)); 67 len += 1; 68 69 if (len === 4) { 70 u[idx++] = v; 71 len = 0; 72 v = 0; 73 } 74 } 75 // Make sure either the terminating 0 byte is written or the last 76 // partial word is written. 77 u[idx++] = v; 78 79 } else if (op.type() === "float") { 80 // TODO(dsinclair): Handle 64 bit floats ... 81 let b = new ArrayBuffer(4); 82 let f = new Float32Array(b); 83 f[0] = op.value(); 84 85 let u2 = new Uint32Array(b); 86 87 u[idx++] = u2[0]; 88 } else { 89 u[idx++] = op.value(); 90 } 91 92 for (const param of op.params()) { 93 idx = this.processOp(u, idx, param); 94 } 95 96 return idx; 97 } 98} 99