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