diff options
Diffstat (limited to 'registry/generator.py')
-rw-r--r-- | registry/generator.py | 164 |
1 files changed, 138 insertions, 26 deletions
diff --git a/registry/generator.py b/registry/generator.py index 8bf3c6d..039015e 100644 --- a/registry/generator.py +++ b/registry/generator.py @@ -306,7 +306,7 @@ class OutputGenerator: raise UserWarning( '*** FATAL ERROR in Generator.logMsg: unknown level:' + level) - def enumToValue(self, elem, needsNum): + def enumToValue(self, elem, needsNum, bitwidth = 32, forceSuffix = False): """Parse and convert an `<enum>` tag into a value. Returns a list: @@ -342,6 +342,11 @@ class OutputGenerator: # t = enuminfo.elem.get('type') # if t is not None and t != '' and t != 'i' and t != 's': # value += enuminfo.type + if forceSuffix: + if bitwidth == 64: + value = value + 'ULL' + else: + value = value + 'U' self.logMsg('diag', 'Enum', name, '-> value [', numVal, ',', value, ']') return [numVal, value] if 'bitpos' in elem.keys(): @@ -349,8 +354,10 @@ class OutputGenerator: bitpos = int(value, 0) numVal = 1 << bitpos value = '0x%08x' % numVal - if bitpos >= 32: - value = value + 'ULL' + if bitwidth == 64: + value = value + 'ULL' + elif forceSuffix: + value = value + 'U' self.logMsg('diag', 'Enum', name, '-> bitpos [', numVal, ',', value, ']') return [numVal, value] if 'offset' in elem.keys(): @@ -433,6 +440,12 @@ class OutputGenerator: # Return the list return stripped + def misracstyle(self): + return False; + + def misracppstyle(self): + return False; + def buildEnumCDecl(self, expand, groupinfo, groupName): """Generate the C declaration for an enum""" groupElem = groupinfo.elem @@ -453,47 +466,69 @@ class OutputGenerator: self.logMsg('error', 'Invalid value for bitwidth attribute (', groupElem.get('bitwidth'), ') for ', groupName, ' - must be an integer value\n') exit(1) - # Bitmask types support 64-bit flags, so have different handling + usebitmask = False + usedefine = False + + # Bitmask flags can be generated as either "static const uint{32,64}_t" values, + # or as 32-bit C enums. 64-bit types must use uint64_t values. if groupElem.get('type') == 'bitmask': + if bitwidth > 32 or self.misracppstyle(): + usebitmask = True + if self.misracstyle(): + usedefine = True + if usedefine or usebitmask: # Validate the bitwidth and generate values appropriately - # Bitmask flags up to 64-bit are generated as static const uint64_t values - # Bitmask flags up to 32-bit are generated as C enum values if bitwidth > 64: self.logMsg('error', 'Invalid value for bitwidth attribute (', groupElem.get('bitwidth'), ') for bitmask type ', groupName, ' - must be less than or equal to 64\n') exit(1) - elif bitwidth > 32: - return self.buildEnumCDecl_Bitmask(groupinfo, groupName) else: - return self.buildEnumCDecl_Enum(expand, groupinfo, groupName) + return self.buildEnumCDecl_BitmaskOrDefine(groupinfo, groupName, bitwidth, usedefine) else: # Validate the bitwidth and generate values appropriately - # Enum group types up to 32-bit are generated as C enum values if bitwidth > 32: self.logMsg('error', 'Invalid value for bitwidth attribute (', groupElem.get('bitwidth'), ') for enum type ', groupName, ' - must be less than or equal to 32\n') exit(1) else: return self.buildEnumCDecl_Enum(expand, groupinfo, groupName) - def buildEnumCDecl_Bitmask(self, groupinfo, groupName): + def buildEnumCDecl_BitmaskOrDefine(self, groupinfo, groupName, bitwidth, usedefine): """Generate the C declaration for an "enum" that is actually a set of flag bits""" groupElem = groupinfo.elem - flagTypeName = groupinfo.flagType.elem.get('name') + flagTypeName = groupElem.get('name') # Prefix body = "// Flag bits for " + flagTypeName + "\n" + if bitwidth == 64: + body += "typedef VkFlags64 %s;\n" % flagTypeName; + else: + body += "typedef VkFlags %s;\n" % flagTypeName; + # Maximum allowable value for a flag (unsigned 64-bit integer) maxValidValue = 2**(64) - 1 minValidValue = 0 + # Get a list of nested 'enum' tags. + enums = groupElem.findall('enum') + + # Check for and report duplicates, and return a list with them + # removed. + enums = self.checkDuplicateEnums(enums) + + # Accumulate non-numeric enumerant values separately and append + # them following the numeric values, to allow for aliases. + # NOTE: this doesn't do a topological sort yet, so aliases of + # aliases can still get in the wrong order. + aliasText = '' + # Loop over the nested 'enum' tags. - for elem in groupElem.findall('enum'): + for elem in enums: # Convert the value to an integer and use that to track min/max. # Values of form -(number) are accepted but nothing more complex. # Should catch exceptions here for more complex constructs. Not yet. - (numVal, strVal) = self.enumToValue(elem, True) + (numVal, strVal) = self.enumToValue(elem, True, bitwidth, True) name = elem.get('name') # Range check for the enum value @@ -504,17 +539,63 @@ class OutputGenerator: protect = elem.get('protect') if protect is not None: body += '#ifdef {}\n'.format(protect) - body += self.genRequirements(name, mustBeFound = False) - # Some C compilers only allow initializing a 'static const' variable with a literal value. - # So initializing an alias from another 'static const' value would fail to compile. - # Work around this by chasing the aliases to get the actual value. - while numVal is None: - alias = self.registry.tree.find("enums/enum[@name='" + strVal + "']") - (numVal, strVal) = self.enumToValue(alias, True) - body += "static const {} {} = {};\n".format(flagTypeName, name, strVal) + + decl = self.genRequirements(name, mustBeFound = False) + + if self.isEnumRequired(elem): + if usedefine: + decl += "#define {} {}\n".format(name, strVal) + elif self.misracppstyle(): + decl += "static constexpr {} {} {{{}}};\n".format(flagTypeName, name, strVal) + else: + # Some C compilers only allow initializing a 'static const' variable with a literal value. + # So initializing an alias from another 'static const' value would fail to compile. + # Work around this by chasing the aliases to get the actual value. + while numVal is None: + alias = self.registry.tree.find("enums/enum[@name='" + strVal + "']") + (numVal, strVal) = self.enumToValue(alias, True) + decl += "static const {} {} = {};\n".format(flagTypeName, name, strVal) + + if numVal is not None: + body += decl + else: + aliasText += decl + if protect is not None: body += '#endif\n' + # Now append the non-numeric enumerant values + body += aliasText + + # Generate a range-padding value to ensure the enum is 32 bits, but + # only in code generators, so it doesn't appear in documentation. + # This isn't needed for bitmasks or defines, but keep them around for + # compatibility. + if (self.genOpts.codeGenerator or + self.conventions.generate_max_enum_in_docs): + + # Break the group name into prefix and suffix portions for range + # enum generation + expandName = re.sub(r'([0-9a-z_])([A-Z0-9])', r'\1_\2', groupName).upper() + expandPrefix = expandName + expandSuffix = '' + expandSuffixMatch = re.search(r'[A-Z][A-Z]+$', groupName) + if expandSuffixMatch: + expandSuffix = '_' + expandSuffixMatch.group() + # Strip off the suffix from the prefix + expandPrefix = expandName.rsplit(expandSuffix, 1)[0] + + maxEnum = '0x7FFFFFFFU' + if bitwidth == 64: + maxEnum = '0x7FFFFFFFFFFFFFFFULL' + + if usedefine: + body += "#define {}_MAX_ENUM{} {}\n".format(expandPrefix, expandSuffix, maxEnum) + elif self.misracppstyle(): + body += "static constexpr {} {}_MAX_ENUM{} {{{}}};\n".format(flagTypeName, expandPrefix, expandSuffix, maxEnum) + else: + body += "static const {} {}_MAX_ENUM{} = {};\n".format(flagTypeName, expandPrefix, expandSuffix, maxEnum) + # Postfix return ("bitmask", body) @@ -815,7 +896,9 @@ class OutputGenerator: - aligncol - if non-zero, attempt to align the nested `<name>` element at this column""" indent = ' ' - paramdecl = indent + noneStr(param.text) + paramdecl = indent + prefix = noneStr(param.text) + for elem in param: text = noneStr(elem.text) tail = noneStr(elem.tail) @@ -834,7 +917,16 @@ class OutputGenerator: paramdecl = paramdecl.ljust(aligncol - 1) + ' ' newLen = len(paramdecl) self.logMsg('diag', 'Adjust length of parameter decl from', oldLen, 'to', newLen, ':', paramdecl) - paramdecl += text + tail + + if (self.misracppstyle() and prefix.find('const ') != -1): + # Change pointer type order from e.g. "const void *" to "void const *". + # If the string starts with 'const', reorder it to be after the first type. + paramdecl += prefix.replace('const ', '') + text + ' const' + tail + else: + paramdecl += prefix + text + tail + + # Clear prefix for subsequent iterations + prefix = '' if aligncol == 0: # Squeeze out multiple spaces other than the indentation paramdecl = indent + ' '.join(paramdecl.split()) @@ -1041,8 +1133,28 @@ class OutputGenerator: # Non-indented parameters paramdecl = '(' if n > 0: - paramnames = (''.join(t for t in p.itertext()) - for p in params) + paramnames = [] + if self.misracppstyle(): + for p in params: + param = '' + firstIter = True; + for t in p.itertext(): + if (firstIter): + prefix = t + firstIter = False + else: + # Change pointer type order from e.g. "const void *" to "void const *". + # If the string starts with 'const', reorder it to be after the first type. + if (prefix.find('const ') != -1): + param += prefix.replace('const ', '') + t + ' const ' + else: + param += prefix + t + # Clear prefix for subsequent iterations + prefix = '' + paramnames.append(param); + else: + paramnames = (''.join(t for t in p.itertext()) + for p in params) paramdecl += ', '.join(paramnames) else: paramdecl += 'void' |