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