1#!/usr/bin/env python 2# 3# Copyright (C) 2017 The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16# 17 18import getopt 19import json 20import string 21import sys 22 23def generate_header_file(filename, with_guard, printer): 24 f = open(filename, 'w') 25 orig_stdout = sys.stdout 26 sys.stdout = f 27 print '// DO NOT MODIFY. AUTO-GENERATED.\n' 28 if with_guard: 29 print "#pragma once" 30 print 31 print "namespace android {" 32 print "namespace spirit {" 33 print 34 printer() 35 if with_guard: 36 print "} // namespace spirit" 37 print "} // namespace android" 38 f.close() 39 sys.stdout = orig_stdout 40 41 42 43################################################################################ 44# 45# Generate Builder class: the .h and .cpp files. 46# 47################################################################################ 48 49def factory_method_name(opname, outlined): 50 if outlined: 51 return "Builder::Make%s" % opname_noprefix(opname) 52 else: 53 return "Make%s" % opname_noprefix(opname) 54 55 56 57def factory_method_prototype(inst, outlined): 58 opname = inst['opname'] 59 operands = inst.get('operands') 60 str = "%s *%s(" % (class_name(opname), factory_method_name(opname, outlined)) 61 first = True; 62 for type, var, quantifier, comment in generate_member_list(operands): 63 if var != "mResult": 64 param = var[1:] 65 if first: 66 first = False 67 else: 68 str += ', ' 69 if quantifier == '?': 70 str += '%s *%s=nullptr' % (type, param) 71 elif quantifier == '*': 72 vecTy = "std::vector<%s>" % type 73 str += '%s %s=%s()' % (vecTy, param, vecTy) 74 else: 75 str += '%s %s' % (type, param) 76 str += ')' 77 return str 78 79 80 81def factory_method_body(inst): 82 opname = inst['opname'] 83 operands = inst.get('operands') 84 clazz = class_name(opname) 85 str = "%s *ret = new %s(" % (clazz, clazz) 86 first = True 87 for type, var, quantifier, comment in generate_member_list(operands): 88 if var != "mResult" and quantifier != '*' and quantifier != '?': 89 param = var[1:] 90 if first: 91 first = False 92 else: 93 str += ', ' 94 str += param 95 str += """); 96 if (!ret) { 97 return nullptr; 98 } 99""" 100 str += """ 101 if (ret->hasResult()) { 102 ret->setId(Module::getCurrentModule()->nextId()); 103 } 104""" 105 for type, var, quantifier, comment in generate_member_list(operands): 106 param = var[1:] 107 # TODO: use vector::swap() or move instead of copy 108 if quantifier == '?' or quantifier == '*': 109 str += " ret->%s = %s;\n" % (var, param) 110 str += " return ret;" 111 return str 112 113 114 115def print_factory_method(inst): 116 print """%s { 117 %s 118}""" % (factory_method_prototype(inst, False), 119 factory_method_body(inst)) 120 121 122 123def print_factory_methods(insts): 124 for inst in insts: 125 print_factory_method(inst) 126 127 128 129################################################################################ 130# 131# Generate type defintions 132# 133################################################################################ 134 135def enum_enumerants(ty, enumerants): 136 str = "" 137 for enumerant in enumerants: 138 name = enumerant['enumerant'] 139 val = enumerant['value'] 140 if name[0].isalpha(): 141 str += " %s = %sU,\n" % (name, val) 142 else: 143 str += " %s%s = %sU,\n" % (ty, name, val) 144 return str 145 146 147def generate_enum(ty): 148 typeName = ty['kind'] 149 print """enum class %s : uint32_t {\n%s}; 150""" % (typeName, 151 enum_enumerants(typeName, ty['enumerants'])) 152 153 154def generate_composite_fields(bases): 155 str = "" 156 i = 0 157 for field in bases: 158 str += " %s mField%d;\n" % (field, i) 159 i = i + 1 160 return str 161 162 163 164def print_type_definitions(operand_kinds): 165 for ty in operand_kinds: 166 category = ty['category'] 167 if category == 'BitEnum' or category == 'ValueEnum': 168 generate_enum(ty) 169 elif category == 'Composite': 170 print "struct %s {\n%s};\n" % (ty['kind'], 171 generate_composite_fields(ty['bases'])) 172 173 174 175################################################################################ 176# 177# Generate class defintions for all instructions 178# 179################################################################################ 180 181def opname_noprefix(opname): 182 return opname[2:] 183 184def class_name(opname): 185 return "%sInst" % opname_noprefix(opname) 186 187 188 189def generate_member_list(operands): 190 members = [] 191 if operands is None: 192 return members 193 index = 1 194 for operand in operands: 195 type = operand['kind'] 196 if type == 'IdResultType' or type == 'IdResult': 197 varName = "m%s" % type[2:] 198 else: 199 varName = "mOperand%d" % index 200 index = index + 1 201 quantifier = operand.get('quantifier') 202 comment = operand.get('name'); 203 members.append((type, varName, quantifier, comment)) 204 return members 205 206def fixed_word_count(member_list): 207 wc = 1 # for the first word of opcode and word count 208 for type, var, quant, comment in member_list: 209 if quant != '?' and quant != '*': 210 wc += 1 211 return wc 212 213def string_for_members(opname, member_list): 214 if member_list == []: 215 return "" 216 member_str = "\n static constexpr OpCode mOpCode=%s;\n" % opname 217 for type, var, quantifier, comment in member_list: 218 if comment is not None and comment.find('\n') != -1: 219 member_str += " /* %s\n */\n" % comment 220 member_str += " " 221 if quantifier == '?': 222 type = type + '*'; 223 elif quantifier == '*': 224 type = 'std::vector<%s>' % type; 225 member_str += "%s %s;" % (type, var) 226 if comment is not None and comment.find('\n') == -1: 227 member_str += " // %s" % comment 228 member_str += "\n" 229 return member_str 230 231def string_for_constructor(opname, opcode, members): 232 # Default constructor 233 initializer = "Instruction(%s, %d)" % (opname, fixed_word_count(members)) 234 first = True 235 for type, var, quantifier, comment in members: 236 if quantifier == '?': 237 initializer += ", %s(nullptr)" % var 238 str = "%s() : %s {}" % (class_name(opname), initializer) 239 240 # Constructor with values for members 241 if members == [] or (len(members) == 1 and members[0][0]=='IdResult'): 242 return str 243 nonOptionalOperandExists = False 244 for type, var, quantifier, comment in members: 245 if quantifier is None: 246 nonOptionalOperandExists = True 247 if not nonOptionalOperandExists: 248 return str 249 params = "" 250 initializer = "Instruction(%s, %d)" % (opname, fixed_word_count(members)) 251 first = True 252 for type, var, quantifier, comment in members: 253 if var != "mResult" and quantifier != '*': 254 initializer += ", " 255 if quantifier == '?': 256 initializer += "%s(nullptr)" % var 257 else: 258 if first: 259 first = False 260 else: 261 params += ", " 262 param = var[1:] # remove the prefix "m" 263 params += "%s %s" % (type, param) 264 initializer += "%s(%s)" % (var, param) 265 if params != "": 266 str += "\n %s(%s) :\n %s {}" % (class_name(opname), params, initializer) 267 str += "\n virtual ~%s() {}" % class_name(opname) 268 return str 269 270def string_for_serializer_body(opcode, members): 271 body = "setWordCount();\n" 272 body += " OS << mCodeAndCount;\n" 273 for type, var, quantifier, comment in members: 274 if quantifier == '?': 275 body += " if (%s!=nullptr) { OS << *%s; }\n" % (var, var) 276 elif quantifier == '*': 277 body += """ for (auto val : %s) { OS << val; }\n""" % var 278 else: 279 body += " OS << %s;\n" % var 280 body += " SerializeExtraOperands(OS);\n" 281 return body 282 283def string_for_deserializer_body(name, members): 284 body = "return DeserializeFirstWord(IS, %s)" % name 285 for type, var, quantifier, comment in members: 286 body += " &&\n " 287 if quantifier == '?': 288 body += "DeserializeOptionallyOne(IS, &%s)" % var 289 elif quantifier == '*': 290 body += "DeserializeZeroOrMoreOperands(IS, &%s)" % var 291 else: 292 body += "DeserializeExactlyOne(IS, &%s)" % var 293 body += " &&\n DeserializeExtraOperands(IS);\n" 294 return body 295 296def string_for_get_word_count(members): 297 str = """uint16_t getWordCount() const override { 298 uint16_t count = mFixedWordCount;\n""" 299 for type, var, quantifier, comment in members: 300 if quantifier == '?': 301 str += " if (%s) count += WordCount(*%s);\n" % (var, var) 302 elif quantifier == '*': 303 str += " if (!%s.empty()) count += WordCount(%s[0]) * %s.size();\n" % (var, var, var) 304 elif type == 'LiteralString': 305 str += " count += WordCount(%s) - 1;\n" % var 306 307 str += """ count += mExtraOperands.size(); 308 return count; 309 }""" 310 return str 311 312def string_for_accept(): 313 return """ 314 void accept(IVisitor *v) override { v->visit(this); } 315""" 316 317def has_result(members): 318 for type, val, quantifier, comment in members: 319 if type == 'IdResult': 320 return True 321 return False 322 323 324def string_for_has_result(hasResult): 325 if hasResult: 326 retVal = "true" 327 else: 328 retVal = "false" 329 return "bool hasResult() const override { return %s; }" % retVal 330 331def string_for_get_all_refs(members): 332 str = """std::vector<const IdRef*> getAllIdRefs() const override { 333 std::vector<const IdRef*> ret = {""" 334 first = True 335 # TODO: what if references are in * operands? 336 for type, var, quantifier, comment in members: 337 if type == 'IdRef' or type == 'IdResultType' or type == 'IdMemorySemantics' or type == 'IdScope': 338 if quantifier == '*': 339 pass 340 else: 341 if first: 342 first = False 343 else: 344 str += ", " 345 if quantifier == '?': 346 str += "%s" % var 347 else: 348 str += "&%s" % var 349 str += """}; 350""" 351 for type, var, quantifier, comment in members: 352 if type == 'IdRef' or type == 'IdResultType' or type == 'IdMemorySemantics' or type == 'IdScope': 353 if quantifier == '*': 354 str+=""" 355 for(const auto &ref : %s) { 356 ret.push_back(&ref); 357 } 358""" % var 359 str += """ 360 return ret; 361 }""" 362 return str 363 364def string_for_get_set_id(hasResult): 365 if hasResult: 366 return """IdResult getId() const override { return mResult; } 367 void setId(IdResult id) override { mResult = id; }""" 368 else: 369 retVal = "0" 370 return """IdResult getId() const override { return 0; } 371 void setId(IdResult) override {}""" 372 373 374def print_instruction_class(inst): 375 opname = inst['opname'] 376 opcode = inst['opcode'] 377 operands = inst.get('operands') 378 members = generate_member_list(operands) 379 hasResult = has_result(members) 380 print """class %s : public Instruction { 381 public: 382 %s 383 384 void Serialize(OutputWordStream &OS) const override { 385 %s } 386 387 bool DeserializeInternal(InputWordStream &IS) override { 388 %s } 389 390 void accept(IVisitor *v) override { v->visit(this); } 391 392 %s 393 394 %s 395 396 %s 397 398 %s 399%s}; 400""" % (class_name(opname), 401 string_for_constructor(opname, opcode, members), 402 string_for_serializer_body(opcode, members), 403 string_for_deserializer_body(opname, members), 404 string_for_get_word_count(members), 405 string_for_has_result(hasResult), 406 string_for_get_set_id(hasResult), 407 string_for_get_all_refs(members), 408 string_for_members(opname, members)) 409 410def print_all_instruction_classes(insts): 411 for inst in insts: 412 print_instruction_class(inst) 413 414################################################################################ 415# 416# Generate opcode enum 417# 418################################################################################ 419 420def print_opcode_enum(insts): 421 print "enum OpCode {" 422 for inst in insts: 423 opname = inst['opname'] 424 opcode = inst['opcode'] 425 print " %s = %d," % (opname, opcode) 426 print "};" 427 428 429 430################################################################################ 431# 432# Generate dispatching code 433# 434################################################################################ 435 436def print_dispatches(insts): 437 for inst in insts: 438 opname = inst['opname'] 439 print "HANDLE_INSTRUCTION(%s,%s)" % (opname, class_name(opname)) 440 441def print_type_inst_dispatches(insts): 442 for inst in insts: 443 opname = inst['opname'] 444 if opname[:6] == "OpType": 445 print "HANDLE_INSTRUCTION(%s, %s)" % (opname, class_name(opname)) 446 447def print_const_inst_dispatches(insts): 448 for inst in insts: 449 opname = inst['opname'] 450 if opname[:10] == "OpConstant": 451 print "HANDLE_INSTRUCTION(%s, %s)" % (opname, class_name(opname)) 452 453def print_enum_dispatches(operand_kinds): 454 for ty in operand_kinds: 455 category = ty['category'] 456 if category == 'BitEnum' or category == 'ValueEnum': 457 print "HANDLE_ENUM(%s)" % ty['kind'] 458 459 460 461################################################################################ 462# 463# main 464# 465################################################################################ 466 467def main(): 468 try: 469 opts, args = getopt.getopt(sys.argv[2:],"h",["instructions=", 470 "types=", 471 "opcodes=", 472 "instruction_dispatches=", 473 "enum_dispatches=", 474 "type_inst_dispatches=", 475 "const_inst_dispatches=", 476 "factory_methods="]) 477 except getopt.GetoptError: 478 print sys.argv[0], '' 479 sys.exit(2) 480 481 with open(sys.argv[1]) as grammar_file: 482 grammar = json.load(grammar_file) 483 484 instructions = grammar['instructions'] 485 486 for opt, arg in opts: 487 if opt == "--instructions": 488 generate_header_file(arg, True, lambda: print_all_instruction_classes(instructions)) 489 elif opt == "--types": 490 kinds = grammar['operand_kinds'] 491 generate_header_file(arg, True, lambda: print_type_definitions(kinds)) 492 elif opt == "--opcodes": 493 generate_header_file(arg, True, lambda: print_opcode_enum(instructions)) 494 elif opt == "--instruction_dispatches": 495 generate_header_file(arg, False, lambda: print_dispatches(instructions)) 496 elif opt == "--enum_dispatches": 497 kinds = grammar['operand_kinds'] 498 generate_header_file(arg, False, lambda: print_enum_dispatches(kinds)) 499 elif opt == "--type_inst_dispatches": 500 generate_header_file(arg, False, lambda: print_type_inst_dispatches(instructions)) 501 elif opt == "--const_inst_dispatches": 502 generate_header_file(arg, False, lambda: print_const_inst_dispatches(instructions)) 503 elif opt == "--factory_methods": 504 generate_header_file(arg, False, lambda: print_factory_methods(instructions)) 505 506if __name__ == '__main__': 507 main() 508