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 15class Module { 16 constructor() { 17 this.instructions_ = []; 18 this.next_id_ = 1; 19 20 /** 21 * Maps {string, hash} where the string is the type name and the hash is: 22 * type- 'float' or 'int' 23 * width- number of bits needed to store number 24 * signed- the sign of the number 25 */ 26 this.types_ = {}; 27 28 /** 29 * Maps {string, number} where the string is the type name and the number is 30 * the id value. 31 */ 32 this.assigned_ids_ = {}; 33 } 34 35 instructions() { return this.instructions_; } 36 37 instruction(val) { return this.instructions_[val]; } 38 39 addInstruction(inst) { 40 this.instructions_.push(inst); 41 42 // Record type information 43 if (inst.name() === "OpTypeInt" || inst.name() === "OpTypeFloat") { 44 let is_int = inst.name() === "OpTypeInt"; 45 46 this.types_[inst.operand(0).name()] = { 47 type: is_int ? "int" : "float", 48 width: inst.operand(1).value(), 49 signed: is_int ? inst.operand(2).value() : 1 50 }; 51 } 52 53 // Record operand result id's 54 inst.operands().forEach((op) => { 55 if (op.rawValue() !== undefined && op.type() === "result_id") { 56 this.next_id_ = Math.max(this.next_id_, op.rawValue() + 1); 57 } 58 }); 59 } 60 61 getType(name) { return this.types_[name]; } 62 63 getId(name) { 64 if (this.assigned_ids_[name] !== undefined) { 65 return this.assigned_ids_[name]; 66 } 67 68 let next = this.next_id_; 69 this.assigned_ids_[name] = next; 70 71 this.next_id_ += 1; 72 return next; 73 } 74 75 getIdBounds() { return this.next_id_; } 76} 77 78class Instruction { 79 constructor(name, opcode, operands) { 80 this.name_ = name; 81 this.opcode_ = opcode; 82 this.operands_ = operands; 83 } 84 85 name() { return this.name_; } 86 87 opcode() { return this.opcode_; } 88 89 operands() { return this.operands_; } 90 91 operand(val) { return this.operands_[val]; } 92} 93 94class Operand { 95 constructor(mod, name, type, value, params) { 96 this.module_ = mod; 97 this.name_ = name; 98 this.type_ = type; 99 this.value_ = value; 100 this.params_ = params; 101 } 102 103 name() { return this.name_; } 104 105 length() { 106 // Get the value just to force it to be filled. 107 this.value(); 108 109 if (this.type_ === "string") { 110 return Math.ceil((this.value_.length + 1) / 4); 111 } 112 113 let size = 1; 114 for (const param of this.params_) { 115 size += param.length(); 116 } 117 return size; 118 } 119 120 type() { return this.type_; } 121 122 rawValue() { return this.value_; } 123 124 // This method should only be called on ResultId's after the full parse is 125 // complete. This is because the AST will only have the maximum seen numeric 126 // ResultId when the parse is done. 127 value() { 128 if (this.value_ === undefined) { 129 this.value_ = this.module_.getId(this.name_); 130 } 131 return this.value_; 132 } 133 134 params() { return this.params_; } 135} 136 137export { 138 Module, 139 Instruction, 140 Operand 141}; 142