1# This Source Code Form is subject to the terms of the Mozilla Public 2# License, v. 2.0. If a copy of the MPL was not distributed with this 3# file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 5# This script generates jit/LIROpsGenerated.h (list of LIR instructions) 6# from LIROps.yaml. 7 8import buildconfig 9import yaml 10import six 11from collections import OrderedDict 12from mozbuild.preprocessor import Preprocessor 13 14HEADER_TEMPLATE = """\ 15/* This Source Code Form is subject to the terms of the Mozilla Public 16 * License, v. 2.0. If a copy of the MPL was not distributed with this 17 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 18 19#ifndef %(includeguard)s 20#define %(includeguard)s 21 22/* This file is generated by jit/GenerateLIRFiles.py. Do not edit! */ 23 24%(contents)s 25 26#endif // %(includeguard)s 27""" 28 29 30def load_yaml(yaml_path): 31 # First invoke preprocessor.py so that we can use #ifdef JS_SIMULATOR in 32 # the YAML file. 33 pp = Preprocessor() 34 pp.context.update(buildconfig.defines["ALLDEFINES"]) 35 pp.out = six.StringIO() 36 pp.do_filter("substitution") 37 pp.do_include(yaml_path) 38 contents = pp.out.getvalue() 39 40 # Load into an OrderedDict to ensure order is preserved. Note: Python 3.7 41 # also preserves ordering for normal dictionaries. 42 # Code based on https://stackoverflow.com/a/21912744. 43 class OrderedLoader(yaml.Loader): 44 pass 45 46 def construct_mapping(loader, node): 47 loader.flatten_mapping(node) 48 return OrderedDict(loader.construct_pairs(node)) 49 50 tag = yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG 51 OrderedLoader.add_constructor(tag, construct_mapping) 52 return yaml.load(contents, OrderedLoader) 53 54 55def generate_header(c_out, includeguard, contents): 56 c_out.write( 57 HEADER_TEMPLATE 58 % { 59 "includeguard": includeguard, 60 "contents": contents, 61 } 62 ) 63 64 65operand_types = { 66 "WordSized": "LAllocation", 67 "BoxedValue": "LBoxAllocation", 68 "Int64": "LInt64Allocation", 69} 70 71 72result_types = { 73 "WordSized": "1", 74 "BoxedValue": "BOX_PIECES", 75 "Int64": "INT64_PIECES", 76} 77 78 79def gen_helper_template_value(num_regular_allocs, num_value_allocs, num_int64_allocs): 80 template_str = "" 81 if num_value_allocs: 82 template_str += str(num_value_allocs) + " * BOX_PIECES + " 83 if num_int64_allocs: 84 template_str += str(num_int64_allocs) + " * INT64_PIECES + " 85 template_str += str(num_regular_allocs) 86 return template_str 87 88 89def build_index_def(num_specials_operands, index_value, num_reg_operands, piece): 90 if num_specials_operands: 91 return " static const size_t {} = {} + {} * {};\\\n".format( 92 index_value, num_reg_operands, piece, num_specials_operands 93 ) 94 else: 95 return " static const size_t {} = {};\\\n".format( 96 index_value, num_reg_operands 97 ) 98 99 100def gen_lir_class( 101 name, result_type, operands, arguments, num_temps, call_instruction, mir_op 102): 103 """Generates class definition for a single LIR opcode.""" 104 class_name = "L" + name 105 106 getters = [] 107 setters = [] 108 # Operand index definitions. 109 oper_indices = [] 110 # Parameters for the class constructor. 111 constructor_params = [] 112 113 num_reg_operands = 0 114 num_value_operands = 0 115 num_int64_operands = 0 116 if operands: 117 # Get number of LAllocations to use for defining indices. 118 for operand in operands: 119 if operands[operand] == "WordSized": 120 num_reg_operands += 1 121 122 current_reg_oper = 0 123 for operand in operands: 124 op_type = operands[operand] 125 op_alloc_type = operand_types[op_type] 126 constructor_params.append("const " + op_alloc_type + "& " + operand) 127 if op_type == "WordSized": 128 index_value = str(current_reg_oper) 129 current_reg_oper += 1 130 getters.append( 131 " const " 132 + op_alloc_type 133 + "* " 134 + operand 135 + "() { return getOperand(" 136 + index_value 137 + "); }" 138 ) 139 setters.append(" setOperand(" + index_value + ", " + operand + ");") 140 elif op_type == "BoxedValue": 141 index_value = operand[0].upper() + operand[1:] + "Index" 142 oper_indices.append( 143 build_index_def( 144 num_value_operands, index_value, num_reg_operands, "BOX_PIECES" 145 ) 146 ) 147 num_value_operands += 1 148 # No getters generated for BoxedValue operands. 149 setters.append( 150 " setBoxOperand(" + index_value + ", " + operand + ");" 151 ) 152 elif op_type == "Int64": 153 index_value = operand[0].upper() + operand[1:] + "Index" 154 oper_indices.append( 155 build_index_def( 156 num_int64_operands, 157 index_value, 158 num_reg_operands, 159 "INT64_PIECES", 160 ) 161 ) 162 num_int64_operands += 1 163 getters.append( 164 " const " 165 + op_alloc_type 166 + " " 167 + operand 168 + "() { return getInt64Operand(" 169 + index_value 170 + "); }" 171 ) 172 setters.append( 173 " setInt64Operand(" + index_value + ", " + operand + ");" 174 ) 175 else: 176 raise Exception("Invalid operand type: " + op_type) 177 if num_temps: 178 for temp in range(num_temps): 179 constructor_params.append("const LDefinition& temp" + str(temp)) 180 setters.append(" setTemp(" + str(temp) + ", temp" + str(temp) + ");") 181 getters.append( 182 " const LDefinition* temp" 183 + str(temp) 184 + "() { return getTemp(" 185 + str(temp) 186 + "); }" 187 ) 188 code = "class {} : public LInstructionHelper<".format(class_name) 189 if result_type: 190 code += result_types[result_type] + ", " 191 else: 192 code += "0, " 193 code += gen_helper_template_value( 194 num_reg_operands, num_value_operands, num_int64_operands 195 ) 196 code += ", {}> {{\\\n".format(num_temps) 197 if arguments: 198 for arg_name in arguments: 199 arg_type_sig = arguments[arg_name] 200 constructor_params.append(arg_type_sig + " " + arg_name) 201 code += " " + arg_type_sig + " " + arg_name + "_;\\\n" 202 code += " public:\\\n LIR_HEADER({})\\\n".format(name) 203 code += " explicit {}(".format(class_name) 204 code += ", ".join(constructor_params) 205 code += ") : LInstructionHelper(classOpcode)" 206 if arguments: 207 for arg_name in arguments: 208 code += ", " + arg_name + "_(" + arg_name + ")" 209 code += " {" 210 if call_instruction: 211 code += "\\\n this->setIsCall();" 212 code += "\\\n" 213 code += "\\\n".join(setters) 214 code += "\\\n }\\\n" 215 code += "\\\n".join(getters) 216 if arguments: 217 for arg_name in arguments: 218 code += " " + arguments[arg_name] + " " + arg_name + "() const { " 219 code += "return " + arg_name + "_; }\\\n" 220 code += "\\\n" 221 if operands: 222 code += "\\\n".join(oper_indices) 223 if mir_op: 224 if mir_op is True: 225 code += " M{}* mir() const {{ return mir_->to{}(); }};\\\n".format( 226 name, name 227 ) 228 else: 229 code += " M{}* mir() const {{ return mir_->to{}(); }};\\\n".format( 230 mir_op, mir_op 231 ) 232 code += "};\\\n" 233 return code 234 235 236def generate_lir_header(c_out, yaml_path): 237 data = load_yaml(yaml_path) 238 239 # LIR_OPCODE_LIST opcode. 240 ops = [] 241 242 # Generated LIR op class definitions. 243 lir_op_classes = [] 244 245 for op in data: 246 name = op["name"] 247 248 gen_boilerplate = op.get("gen_boilerplate", True) 249 assert isinstance(gen_boilerplate, bool) 250 251 if gen_boilerplate: 252 result_type = op.get("result_type", None) 253 assert result_type is None or str 254 if result_type: 255 assert result_types[result_type] 256 257 operands = op.get("operands", None) 258 assert operands is None or OrderedDict 259 260 arguments = op.get("arguments", None) 261 assert arguments is None or isinstance(arguments, OrderedDict) 262 263 num_temps = op.get("num_temps", 0) 264 assert num_temps is None or int 265 266 gen_boilerplate = op.get("gen_boilerplate", True) 267 assert isinstance(gen_boilerplate, bool) 268 269 call_instruction = op.get("call_instruction", None) 270 assert call_instruction is None or True 271 272 mir_op = op.get("mir_op", None) 273 assert mir_op is None or True or str 274 275 lir_op_classes.append( 276 gen_lir_class( 277 name, 278 result_type, 279 operands, 280 arguments, 281 num_temps, 282 call_instruction, 283 mir_op, 284 ) 285 ) 286 287 ops.append("_({})".format(name)) 288 289 contents = "#define LIR_OPCODE_LIST(_)\\\n" 290 contents += "\\\n".join(ops) 291 contents += "\n\n" 292 293 contents += "#define LIR_OPCODE_CLASS_GENERATED \\\n" 294 contents += "\\\n".join(lir_op_classes) 295 contents += "\n\n" 296 297 generate_header(c_out, "jit_LIROpsGenerated_h", contents) 298