From 0ee9a84cac65806ef8db69cd78c2be14e1d32ceb Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Sat, 22 Feb 2014 05:39:35 +0000 Subject: [PATCH] [python-bindings] Added OpCode like support for all enumerations with unittests. Also fixed some trailing whitespace issues. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@201929 91177308-0d34-0410-b5e6-96231b3b80d8 --- bindings/python/llvm/core.py | 134 ++++++++++++++++++++---- bindings/python/llvm/tests/test_core.py | 42 +++++--- 2 files changed, 139 insertions(+), 37 deletions(-) diff --git a/bindings/python/llvm/core.py b/bindings/python/llvm/core.py index ebf57d44438..e8bfab8445f 100644 --- a/bindings/python/llvm/core.py +++ b/bindings/python/llvm/core.py @@ -20,6 +20,7 @@ from ctypes import c_uint __all__ = [ "lib", + "Enums", "OpCode", "MemoryBuffer", "Module", @@ -32,42 +33,116 @@ __all__ = [ ] lib = get_library() +Enums = [] -class OpCode(object): - """Represents an individual OpCode enumeration.""" - - _value_map = {} +class LLVMEnumeration(object): + """Represents an individual LLVM enumeration.""" def __init__(self, name, value): self.name = name self.value = value def __repr__(self): - return 'OpCode.%s' % self.name + return '%s.%s' % (self.__class__.__name__, + self.name) - @staticmethod - def from_value(value): - """Obtain an OpCode instance from a numeric value.""" - result = OpCode._value_map.get(value, None) + @classmethod + def from_value(cls, value): + """Obtain an enumeration instance from a numeric value.""" + result = cls._value_map.get(value, None) if result is None: - raise ValueError('Unknown OpCode: %d' % value) + raise ValueError('Unknown %s: %d' % (cls.__name__, + value)) return result - @staticmethod - def register(name, value): - """Registers a new OpCode enumeration. + @classmethod + def register(cls, name, value): + """Registers a new enumeration. This is called by this module for each enumeration defined in enumerations. You should not need to call this outside this module. """ - if value in OpCode._value_map: - raise ValueError('OpCode value already registered: %d' % value) + if value in cls._value_map: + raise ValueError('%s value already registered: %d' % (cls.__name__, + value)) + enum = cls(name, value) + cls._value_map[value] = enum + setattr(cls, name, enum) + #print cls, name, value + +class Attribute(LLVMEnumeration): + """Represents an individual Attribute enumeration.""" + + _value_map = {} + + def __init__(self, name, value): + super(Attribute, self).__init__(name, value) + +class OpCode(LLVMEnumeration): + """Represents an individual OpCode enumeration.""" + + _value_map = {} + + def __init__(self, name, value): + super(OpCode, self).__init__(name, value) + +class TypeKind(LLVMEnumeration): + """Represents an individual TypeKind enumeration.""" + + _value_map = {} + + def __init__(self, name, value): + super(TypeKind, self).__init__(name, value) + +class Linkage(LLVMEnumeration): + """Represents an individual Linkage enumeration.""" + + _value_map = {} + + def __init__(self, name, value): + super(Linkage, self).__init__(name, value) + +class Visibility(LLVMEnumeration): + """Represents an individual visibility enumeration.""" + + _value_map = {} + + def __init__(self, name, value): + super(Visibility, self).__init__(name, value) + +class CallConv(LLVMEnumeration): + """Represents an individual calling convention enumeration.""" - opcode = OpCode(name, value) - OpCode._value_map[value] = opcode - setattr(OpCode, name, opcode) + _value_map = {} + + def __init__(self, name, value): + super(CallConv, self).__init__(name, value) + +class IntPredicate(LLVMEnumeration): + """Represents an individual IntPredicate enumeration.""" + + _value_map = {} + + def __init__(self, name, value): + super(IntPredicate, self).__init__(name, value) + +class RealPredicate(LLVMEnumeration): + """Represents an individual RealPredicate enumeration.""" + + _value_map = {} + + def __init__(self, name, value): + super(RealPredicate, self).__init__(name, value) + +class LandingPadClauseTy(LLVMEnumeration): + """Represents an individual LandingPadClauseTy enumeration.""" + + _value_map = {} + + def __init__(self, name, value): + super(LandingPadClauseTy, self).__init__(name, value) class MemoryBuffer(LLVMObject): """Represents an opaque memory buffer.""" @@ -516,8 +591,25 @@ def register_library(library): library.LLVMGetInstructionOpcode.restype = c_uint def register_enumerations(): - for name, value in enumerations.OpCodes: - OpCode.register(name, value) + if Enums: + return None + enums = [ + (Attribute, enumerations.Attributes), + (OpCode, enumerations.OpCodes), + (TypeKind, enumerations.TypeKinds), + (Linkage, enumerations.Linkages), + (Visibility, enumerations.Visibility), + (CallConv, enumerations.CallConv), + (IntPredicate, enumerations.IntPredicate), + (RealPredicate, enumerations.RealPredicate), + (LandingPadClauseTy, enumerations.LandingPadClauseTy), + ] + s = set([]) + for enum_class, enum_spec in enums: + for name, value in enum_spec: + print name, value + enum_class.register(name, value) + return enums def initialize_llvm(): c = Context.GetGlobalContext() @@ -536,5 +628,5 @@ def initialize_llvm(): lib.LLVMInitializeTarget(p) register_library(lib) -register_enumerations() +Enums = register_enumerations() initialize_llvm() diff --git a/bindings/python/llvm/tests/test_core.py b/bindings/python/llvm/tests/test_core.py index 63f84c828bc..da7b635ec99 100644 --- a/bindings/python/llvm/tests/test_core.py +++ b/bindings/python/llvm/tests/test_core.py @@ -1,20 +1,30 @@ from .base import TestBase -from ..core import OpCode from ..core import MemoryBuffer from ..core import PassRegistry from ..core import Context from ..core import Module +from ..core import Enums +from ..core import OpCode from ..bit_reader import parse_bitcode class TestCore(TestBase): - def test_opcode(self): - self.assertTrue(hasattr(OpCode, 'Ret')) - self.assertTrue(isinstance(OpCode.Ret, OpCode)) - self.assertEqual(OpCode.Ret.value, 1) - - op = OpCode.from_value(1) - self.assertTrue(isinstance(op, OpCode)) - self.assertEqual(op, OpCode.Ret) + def test_enumerations(self): + for enum_cls, enum_spec in Enums: + for enum_name, enum_value in enum_spec: + # First make sure that enum_cls has the name of the enum as an + # attribute. People will access these values as + # EnumCls.EnumName. + self.assertTrue(hasattr(enum_cls, enum_name)) + v_attr = getattr(enum_cls, enum_name) + self.assertTrue(isinstance(v_attr, enum_cls)) + + # Then make sure that the value returned for this attribute is + # correct in both ways. + self.assertEqual(v_attr.value, enum_value) + + e = enum_cls.from_value(enum_value) + self.assertTrue(isinstance(e, enum_cls)) + self.assertEqual(e, v_attr) def test_memory_buffer_create_from_file(self): source = self.get_test_file() @@ -61,7 +71,7 @@ class TestCore(TestBase): target = "thumbv7-apple-ios5.0.0" m.target = target m.print_module_to_file("test2.ll") - + def test_module_function_iteration(self): m = parse_bitcode(MemoryBuffer(filename=self.get_test_bc())) i = 0 @@ -81,19 +91,19 @@ class TestCore(TestBase): def test_function_basicblock_iteration(self): m = parse_bitcode(MemoryBuffer(filename=self.get_test_bc())) i = 0 - + bb_list = ['b1', 'b2', 'end'] - + f = m.first while f.name != "f6": f = f.next - + # Forward for bb in f: self.assertEqual(bb.name, bb_list[i]) bb.dump() i += 1 - + # Backwards for bb in reversed(f): i -= 1 @@ -103,12 +113,12 @@ class TestCore(TestBase): def test_basicblock_instruction_iteration(self): m = parse_bitcode(MemoryBuffer(filename=self.get_test_bc())) i = 0 - + inst_list = [('arg1', OpCode.ExtractValue), ('arg2', OpCode.ExtractValue), ('', OpCode.Call), ('', OpCode.Ret)] - + bb = m.first.first # Forward -- 2.34.1