From 6e6bd1ea71b29617808a3a6c7ea07f207c1a7636 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Wed, 12 Sep 2012 20:00:25 +0200 Subject: [PATCH 1/3] Add support for module named metadata This is mainly useful to get access to top-level debug information through 'llvm.dbg.cu'. Wraps LLVM C-API functions `LLVMGetNamedMetadataNumOperands`, `LLVMGetNamedMetadataOperands` and `LLVMAddNamedMetadataOperand`. Also add testcase. --- llvm/_core.cpp | 23 +++++++++++++++++++++++ llvm/core.py | 9 +++++++++ llvm/test_llvmpy.py | 15 ++++++++++++++- 3 files changed, 46 insertions(+), 1 deletion(-) diff --git a/llvm/_core.cpp b/llvm/_core.cpp index 99642e8..2453479 100644 --- a/llvm/_core.cpp +++ b/llvm/_core.cpp @@ -607,6 +607,27 @@ _wrap_obj2none(LLVMDeleteBasicBlock, LLVMBasicBlockRef) /*===-- MetaData -----------------------------------------------------===*/ _wrap_objlist2obj(LLVMMetaDataGet, LLVMModuleRef, LLVMValueRef, LLVMValueRef) +_wrap_objstrobj2none(LLVMAddNamedMetadataOperand, LLVMModuleRef, LLVMValueRef) + +static PyObject * +_wLLVMGetNamedMetadataOperands(PyObject *self, PyObject *args) +{ + PyObject *obj_module; + const char *name; + + if (!PyArg_ParseTuple(args, "Os", &obj_module, &name)) + return NULL; + + LLVMModuleRef module = (LLVMModuleRef)PyCapsule_GetPointer(obj_module, NULL); + unsigned num_operands = LLVMGetNamedMetadataNumOperands(module, name); + LLVMValueRef *operands = (LLVMValueRef*)malloc(sizeof(LLVMValueRef)*num_operands); + LLVMGetNamedMetadataOperands(module, name, operands); + + PyObject *list = make_list_from_LLVMValueRef_array(operands, num_operands); + free(operands); + + return list; +} /*===-- Instructions -----------------------------------------------------===*/ @@ -1660,6 +1681,8 @@ static PyMethodDef core_methods[] = { /* MetaData */ _method( LLVMMetaDataGet ) + _method( LLVMGetNamedMetadataOperands ) + _method( LLVMAddNamedMetadataOperand ) /* Instructions */ _method( LLVMGetInstructionParent ) diff --git a/llvm/core.py b/llvm/core.py index 215252a..d5b829b 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -1457,6 +1457,15 @@ class MetaData(Value): ptr = _core.LLVMMetaDataGet(module.ptr, vs) return MetaData(ptr) + @staticmethod + def get_named_operands(module, name): + lst = _core.LLVMGetNamedMetadataOperands(module.ptr, name) + return [MetaData(ptr) for ptr in lst] + + @staticmethod + def add_named_operand(module, name, operand): + _core.LLVMAddNamedMetadataOperand(module.ptr, name, operand.ptr) + #===----------------------------------------------------------------------=== # Instruction #===----------------------------------------------------------------------=== diff --git a/llvm/test_llvmpy.py b/llvm/test_llvmpy.py index 6c85d93..5d0d62b 100644 --- a/llvm/test_llvmpy.py +++ b/llvm/test_llvmpy.py @@ -16,7 +16,7 @@ else: from llvm import __version__ from llvm.core import (Module, Type, GlobalVariable, Function, Builder, - Constant) + Constant, MetaData) import llvm.passes as lp import llvm.ee as le @@ -390,6 +390,19 @@ tests.append(TestUses) # --------------------------------------------------------------------------- +class TestMetaData(unittest.TestCase): + # test module metadata + def test_metadata(self): + m = Module.new('a') + metadata = MetaData.get(m, []) # empty metadata node + MetaData.add_named_operand(m, 'foo', metadata) + self.assertEqual(MetaData.get_named_operands(m, 'foo'), [metadata]) + self.assertEqual(MetaData.get_named_operands(m, 'bar'), []) + +tests.append(TestMetaData) + +# --------------------------------------------------------------------------- + def run(verbosity=1): print('llvmpy is installed in: ' + os.path.dirname(__file__)) print('llvmpy version: ' + __version__) From 7f69beb2580d10836686fa55f0e0b6ce30374548 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Wed, 12 Sep 2012 20:58:53 +0200 Subject: [PATCH 2/3] Access to MetaData operands This is not available in the C API, so add functions to extra.cpp: - `LLVMMetaDataGetOperand` wraps MDNode::getOperand - `LLVMMetaDataGetNumOperands` wraps MDNode::getNumOperands --- llvm/_core.cpp | 4 ++++ llvm/core.py | 12 ++++++++++++ llvm/extra.cpp | 10 ++++++++++ llvm/extra.h | 10 ++++++++++ llvm/test_llvmpy.py | 5 ++++- 5 files changed, 40 insertions(+), 1 deletion(-) diff --git a/llvm/_core.cpp b/llvm/_core.cpp index 2453479..15a58dd 100644 --- a/llvm/_core.cpp +++ b/llvm/_core.cpp @@ -608,6 +608,8 @@ _wrap_obj2none(LLVMDeleteBasicBlock, LLVMBasicBlockRef) _wrap_objlist2obj(LLVMMetaDataGet, LLVMModuleRef, LLVMValueRef, LLVMValueRef) _wrap_objstrobj2none(LLVMAddNamedMetadataOperand, LLVMModuleRef, LLVMValueRef) +_wrap_objint2obj(LLVMMetaDataGetOperand, LLVMValueRef, LLVMValueRef) +_wrap_obj2obj(LLVMMetaDataGetNumOperands, LLVMValueRef, int) static PyObject * _wLLVMGetNamedMetadataOperands(PyObject *self, PyObject *args) @@ -1683,6 +1685,8 @@ static PyMethodDef core_methods[] = { _method( LLVMMetaDataGet ) _method( LLVMGetNamedMetadataOperands ) _method( LLVMAddNamedMetadataOperand ) + _method( LLVMMetaDataGetOperand ) + _method( LLVMMetaDataGetNumOperands ) /* Instructions */ _method( LLVMGetInstructionParent ) diff --git a/llvm/core.py b/llvm/core.py index d5b829b..ed0a9b3 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -1466,6 +1466,18 @@ class MetaData(Value): def add_named_operand(module, name, operand): _core.LLVMAddNamedMetadataOperand(module.ptr, name, operand.ptr) + @property + def operand_count(self): + return _core.LLVMMetaDataGetNumOperands(self.ptr) + + @property + def operands(self): + """Yields operands of this metadata.""" + return [self._get_operand(i) for i in range(self.operand_count)] + + def _get_operand(self, i): + return _make_value(_core.LLVMMetaDataGetOperand(self.ptr, i)) + #===----------------------------------------------------------------------=== # Instruction #===----------------------------------------------------------------------=== diff --git a/llvm/extra.cpp b/llvm/extra.cpp index 9925028..ca966bc 100644 --- a/llvm/extra.cpp +++ b/llvm/extra.cpp @@ -149,6 +149,16 @@ LLVMValueRef LLVMMetaDataGet(LLVMModuleRef modref, LLVMValueRef * valrefs, return wrap(node); } +LLVMValueRef LLVMMetaDataGetOperand(LLVMValueRef mdref, unsigned index) +{ + return wrap(llvm::unwrap(mdref)->getOperand(index)); +} + +unsigned LLVMMetaDataGetNumOperands(LLVMValueRef mdref) +{ + return llvm::unwrap(mdref)->getNumOperands(); +} + const char *LLVMGetConstExprOpcodeName(LLVMValueRef inst) { return llvm::unwrap(inst)->getOpcodeName(); diff --git a/llvm/extra.h b/llvm/extra.h index dc0a029..1858469 100644 --- a/llvm/extra.h +++ b/llvm/extra.h @@ -65,6 +65,16 @@ void LLVMInstSetMetaData(LLVMValueRef instref, const char* mdkind, LLVMValueRef LLVMMetaDataGet(LLVMModuleRef modref, LLVMValueRef * valrefs, unsigned valct); +/* + * Wraps MDNode::getOperand() + */ +LLVMValueRef LLVMMetaDataGetOperand(LLVMValueRef mdref, unsigned index); + +/* + * Wraps MDNode::getNumOperands() + */ +unsigned LLVMMetaDataGetNumOperands(LLVMValueRef mdref); + /* * Wraps ConstantExpr::getOpcodeName() */ diff --git a/llvm/test_llvmpy.py b/llvm/test_llvmpy.py index 5d0d62b..f03070a 100644 --- a/llvm/test_llvmpy.py +++ b/llvm/test_llvmpy.py @@ -394,10 +394,13 @@ class TestMetaData(unittest.TestCase): # test module metadata def test_metadata(self): m = Module.new('a') - metadata = MetaData.get(m, []) # empty metadata node + t = Type.int() + metadata = MetaData.get(m, [Constant.int(t, 100)]) MetaData.add_named_operand(m, 'foo', metadata) self.assertEqual(MetaData.get_named_operands(m, 'foo'), [metadata]) self.assertEqual(MetaData.get_named_operands(m, 'bar'), []) + self.assertEqual(len(metadata.operands), 1) + self.assertEqual(metadata.operands[0].z_ext_value, 100) tests.append(TestMetaData) From e2d8079b9373594144525633a844caafff8dda42 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Wed, 12 Sep 2012 21:11:33 +0200 Subject: [PATCH 3/3] Support MetaDataString, and correctly represent MetaData Values in _make_value --- llvm/_core.cpp | 2 ++ llvm/core.py | 13 +++++++++++++ llvm/extra.cpp | 7 +++++++ llvm/extra.h | 5 +++++ llvm/test_llvmpy.py | 7 ++++--- 5 files changed, 31 insertions(+), 3 deletions(-) diff --git a/llvm/_core.cpp b/llvm/_core.cpp index 15a58dd..a833982 100644 --- a/llvm/_core.cpp +++ b/llvm/_core.cpp @@ -610,6 +610,7 @@ _wrap_objlist2obj(LLVMMetaDataGet, LLVMModuleRef, LLVMValueRef, LLVMValueRef) _wrap_objstrobj2none(LLVMAddNamedMetadataOperand, LLVMModuleRef, LLVMValueRef) _wrap_objint2obj(LLVMMetaDataGetOperand, LLVMValueRef, LLVMValueRef) _wrap_obj2obj(LLVMMetaDataGetNumOperands, LLVMValueRef, int) +_wrap_objstr2obj(LLVMMetaDataStringGet, LLVMModuleRef, LLVMValueRef) static PyObject * _wLLVMGetNamedMetadataOperands(PyObject *self, PyObject *args) @@ -1687,6 +1688,7 @@ static PyMethodDef core_methods[] = { _method( LLVMAddNamedMetadataOperand ) _method( LLVMMetaDataGetOperand ) _method( LLVMMetaDataGetNumOperands ) + _method( LLVMMetaDataStringGet ) /* Instructions */ _method( LLVMGetInstructionParent ) diff --git a/llvm/core.py b/llvm/core.py index ed0a9b3..a9c707e 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -1478,6 +1478,17 @@ class MetaData(Value): def _get_operand(self, i): return _make_value(_core.LLVMMetaDataGetOperand(self.ptr, i)) +class MetaDataString(Value): + @staticmethod + def get(module, s): + ptr = _core.LLVMMetaDataStringGet(module.ptr, s) + return MetaDataString(ptr) + + @property + def string(self): + '''Same as MDString::getString''' + return self.name + #===----------------------------------------------------------------------=== # Instruction #===----------------------------------------------------------------------=== @@ -1648,6 +1659,8 @@ __class_for_valueid = { VALUE_CONSTANT_STRUCT : ConstantStruct, VALUE_CONSTANT_VECTOR : ConstantVector, VALUE_CONSTANT_POINTER_NULL : ConstantPointerNull, + VALUE_MD_NODE : MetaData, + VALUE_MD_STRING : MetaDataString, VALUE_INSTRUCTION + OPCODE_PHI : PHINode, VALUE_INSTRUCTION + OPCODE_CALL : CallOrInvokeInstruction, VALUE_INSTRUCTION + OPCODE_INVOKE : CallOrInvokeInstruction, diff --git a/llvm/extra.cpp b/llvm/extra.cpp index ca966bc..3cf0fb4 100644 --- a/llvm/extra.cpp +++ b/llvm/extra.cpp @@ -159,6 +159,13 @@ unsigned LLVMMetaDataGetNumOperands(LLVMValueRef mdref) return llvm::unwrap(mdref)->getNumOperands(); } +LLVMValueRef LLVMMetaDataStringGet(LLVMModuleRef modref, const char *s) +{ + LLVMContext & context = unwrap(modref)->getContext(); + MDString * const mdstring = MDString::get(context, s); + return wrap(mdstring); +} + const char *LLVMGetConstExprOpcodeName(LLVMValueRef inst) { return llvm::unwrap(inst)->getOpcodeName(); diff --git a/llvm/extra.h b/llvm/extra.h index 1858469..1772878 100644 --- a/llvm/extra.h +++ b/llvm/extra.h @@ -75,6 +75,11 @@ LLVMValueRef LLVMMetaDataGetOperand(LLVMValueRef mdref, unsigned index); */ unsigned LLVMMetaDataGetNumOperands(LLVMValueRef mdref); +/* + * Wraps MDString::get() + */ +LLVMValueRef LLVMMetaDataStringGet(LLVMModuleRef modref, const char *s); + /* * Wraps ConstantExpr::getOpcodeName() */ diff --git a/llvm/test_llvmpy.py b/llvm/test_llvmpy.py index f03070a..8a9f155 100644 --- a/llvm/test_llvmpy.py +++ b/llvm/test_llvmpy.py @@ -16,7 +16,7 @@ else: from llvm import __version__ from llvm.core import (Module, Type, GlobalVariable, Function, Builder, - Constant, MetaData) + Constant, MetaData, MetaDataString) import llvm.passes as lp import llvm.ee as le @@ -395,12 +395,13 @@ class TestMetaData(unittest.TestCase): def test_metadata(self): m = Module.new('a') t = Type.int() - metadata = MetaData.get(m, [Constant.int(t, 100)]) + metadata = MetaData.get(m, [Constant.int(t, 100), MetaDataString.get(m, 'abcdef')]) MetaData.add_named_operand(m, 'foo', metadata) self.assertEqual(MetaData.get_named_operands(m, 'foo'), [metadata]) self.assertEqual(MetaData.get_named_operands(m, 'bar'), []) - self.assertEqual(len(metadata.operands), 1) + self.assertEqual(len(metadata.operands), 2) self.assertEqual(metadata.operands[0].z_ext_value, 100) + self.assertEqual(metadata.operands[1].string, 'abcdef') tests.append(TestMetaData)