diff --git a/llvm/_core.c b/llvm/_core.c index 459e82c..506480d 100644 --- a/llvm/_core.c +++ b/llvm/_core.c @@ -531,9 +531,11 @@ _wrap_obj2obj(LLVMInstIsArithmeticShift, LLVMValueRef, int) _wrap_obj2obj(LLVMInstIsAssociative, LLVMValueRef, int) _wrap_obj2obj(LLVMInstIsCommutative, LLVMValueRef, int) _wrap_obj2obj(LLVMInstIsTrapping, LLVMValueRef, int) +_wrap_obj2obj(LLVMInstIsVolatile, LLVMValueRef, int) _wrap_obj2obj(LLVMInstGetOpcode, LLVMValueRef, int) _wrap_obj2str(LLVMInstGetOpcodeName, LLVMValueRef) -_wrap_obj2obj(LLVMInstIsVolatile, LLVMValueRef, int) +_wrap_obj2obj(LLVMInstGetNumOperands, LLVMValueRef, int) +_wrap_objint2obj(LLVMInstGetOperand, LLVMValueRef, LLVMValueRef) /*===-- Call Sites (Call or Invoke) --------------------------------------===*/ @@ -1250,9 +1252,11 @@ static PyMethodDef core_methods[] = { _method( LLVMInstIsAssociative ) _method( LLVMInstIsCommutative ) _method( LLVMInstIsTrapping ) + _method( LLVMInstIsVolatile ) _method( LLVMInstGetOpcode ) _method( LLVMInstGetOpcodeName ) - _method( LLVMInstIsVolatile ) + _method( LLVMInstGetNumOperands ) + _method( LLVMInstGetOperand ) /* Call Sites (Call or Invoke) */ _method( LLVMSetInstructionCallConv ) diff --git a/llvm/core.py b/llvm/core.py index 6e29093..3be813f 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -1772,6 +1772,10 @@ class GlobalValue(Constant): def __init__(self, ptr): Constant.__init__(self, ptr) + # Hang on to the module, don't let it die before we do. + # It is nice to have just a map of functions without + # retaining a ref to the owning module. + self._module_obj = self.module def _get_linkage(self): return _core.LLVMGetLinkage(self.ptr) def _set_linkage(self, value): _core.LLVMSetLinkage(self.ptr, value) @@ -2001,6 +2005,18 @@ class Instruction(Value): def opcode_name(self): return _core.LLVMInstGetOpcodeName(self.ptr) + @property + def operand_count(self): + return _core.LLVMInstGetNumOperands(self.ptr) + + @property + def operands(self): + """Yields operands of this instruction.""" + return [self._get_operand(i) for i in range(self.operand_count)] + + def _get_operand(self, i): + return _make_value(_core.LLVMInstGetOperand(self.ptr, i)) + class CallOrInvokeInstruction(Instruction): diff --git a/llvm/extra.cpp b/llvm/extra.cpp index db3fc5e..3fac3af 100644 --- a/llvm/extra.cpp +++ b/llvm/extra.cpp @@ -237,6 +237,21 @@ unsigned LLVMInstGetOpcode(LLVMValueRef inst) return instp->getOpcode(); } +unsigned LLVMInstGetNumOperands(LLVMValueRef inst) +{ + llvm::Instruction *instp = llvm::unwrap(inst); + assert(instp); + return instp->getNumOperands(); +} + +LLVMValueRef LLVMInstGetOperand(LLVMValueRef inst, unsigned idx) +{ + llvm::Instruction *instp = llvm::unwrap(inst); + assert(instp); + llvm::Value *operand = instp->getOperand(idx); + return llvm::wrap(operand); +} + /* llvm::unwrap a set of `n' wrapped objects starting at `values', * into a vector of pointers to llvm::unwrapped objects `out'. */ template diff --git a/llvm/extra.h b/llvm/extra.h index 060e3e1..8e89391 100644 --- a/llvm/extra.h +++ b/llvm/extra.h @@ -121,6 +121,12 @@ const char *LLVMInstGetOpcodeName(LLVMValueRef inst); /* Wraps llvm::Instruction::getOpcode(). */ unsigned LLVMInstGetOpcode(LLVMValueRef inst); +/* Wraps llvm:Instruction::getNumOperands(). */ +unsigned LLVMInstGetNumOperands(LLVMValueRef inst); + +/* Wraps llvm:Instruction::getOperand(). */ +LLVMValueRef LLVMInstGetOperand(LLVMValueRef inst, unsigned idx); + /* Wraps llvm::ParseAssemblyString(). Returns a module reference or NULL (with * `out' pointing to an error message). Dispose error message after use, via * LLVMDisposeMessage(). */ diff --git a/test/operands.py b/test/operands.py new file mode 100755 index 0000000..e120223 --- /dev/null +++ b/test/operands.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python + +# Tests accessing of instruction operands. + +from llvm.core import * + +#===----------------------------------------------------------------------=== + +# implement a test function +def make_function(): + test_module = """ + define i32 @prod(i32, i32) { + entry: + %2 = mul i32 %0, %1 + ret i32 %2 + } + + define i32 @test_func(i32, i32, i32) { + entry: + %tmp1 = call i32 @prod(i32 %0, i32 %1) + %tmp2 = add i32 %tmp1, %2 + %tmp3 = add i32 %tmp2, 1 + ret i32 %tmp3 + } + """ + class strstream(object): + def __init__(self): pass + def read(self): return test_module + m = Module.from_assembly(strstream()) + print "-"*60 + print m + print "-"*60 + print "Examining function `test_func':" + return m.get_function_named("test_func") + +#===----------------------------------------------------------------------=== + +func = make_function() +idx = 1 +for inst in func.basic_blocks[0].instructions: + print "Instruction #%d:" % (idx,) + print " operand_count =", inst.operand_count + print " operands:" + oidx = 1 + for op in inst.operands: + print " %d: %s" % (oidx, repr(op)) + oidx += 1 + idx += 1 diff --git a/test/testall.py b/test/testall.py index ca4e0e4..fd32767 100644 --- a/test/testall.py +++ b/test/testall.py @@ -292,6 +292,8 @@ def do_instruction(): bb = Builder.new(b) i = bb.ret_void() bb2 = i.basic_block + ops = i.operands + opcount = i.operand_count def do_callorinvokeinstruction():