// 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. class Module { constructor() { this.instructions_ = []; this.next_id_ = 1; /** * Maps {string, hash} where the string is the type name and the hash is: * type- 'float' or 'int' * width- number of bits needed to store number * signed- the sign of the number */ this.types_ = {}; /** * Maps {string, number} where the string is the type name and the number is * the id value. */ this.assigned_ids_ = {}; } instructions() { return this.instructions_; } instruction(val) { return this.instructions_[val]; } addInstruction(inst) { this.instructions_.push(inst); // Record type information if (inst.name() === "OpTypeInt" || inst.name() === "OpTypeFloat") { let is_int = inst.name() === "OpTypeInt"; this.types_[inst.operand(0).name()] = { type: is_int ? "int" : "float", width: inst.operand(1).value(), signed: is_int ? inst.operand(2).value() : 1 }; } // Record operand result id's inst.operands().forEach((op) => { if (op.rawValue() !== undefined && op.type() === "result_id") { this.next_id_ = Math.max(this.next_id_, op.rawValue() + 1); } }); } getType(name) { return this.types_[name]; } getId(name) { if (this.assigned_ids_[name] !== undefined) { return this.assigned_ids_[name]; } let next = this.next_id_; this.assigned_ids_[name] = next; this.next_id_ += 1; return next; } getIdBounds() { return this.next_id_; } } class Instruction { constructor(name, opcode, operands) { this.name_ = name; this.opcode_ = opcode; this.operands_ = operands; } name() { return this.name_; } opcode() { return this.opcode_; } operands() { return this.operands_; } operand(val) { return this.operands_[val]; } } class Operand { constructor(mod, name, type, value, params) { this.module_ = mod; this.name_ = name; this.type_ = type; this.value_ = value; this.params_ = params; } name() { return this.name_; } length() { // Get the value just to force it to be filled. this.value(); if (this.type_ === "string") { return Math.ceil((this.value_.length + 1) / 4); } let size = 1; for (const param of this.params_) { size += param.length(); } return size; } type() { return this.type_; } rawValue() { return this.value_; } // This method should only be called on ResultId's after the full parse is // complete. This is because the AST will only have the maximum seen numeric // ResultId when the parse is done. value() { if (this.value_ === undefined) { this.value_ = this.module_.getId(this.name_); } return this.value_; } params() { return this.params_; } } export { Module, Instruction, Operand };