Add binding for Intrinsics.

Add support for functions that free the resource but is not a destructor.
This commit is contained in:
Siu Kwan Lam 2013-02-07 13:27:03 -06:00
commit 11cc78d780
8 changed files with 92 additions and 4 deletions

View file

@ -92,8 +92,12 @@ _cache = defaultdict(WeakValueDictionary)
def release_ownership(old): def release_ownership(old):
logger.debug('Release %s', old) logger.debug('Release %s', old)
addr = Capsule.getPointer(old) addr = Capsule.getPointer(old)
if _addr2dtor[addr] is None:
# Guard deduplicated release if _addr2dtor.get(addr) is None:
clsname = Capsule.getClassName(old)
if not _pyclasses[clsname]._has_dtor():
return
# Guard duplicated release
raise Exception("Already released") raise Exception("Already released")
_addr2dtor[addr] = None _addr2dtor[addr] = None
@ -117,7 +121,7 @@ def wrap(cap, owned=False):
try: # lookup cached object try: # lookup cached object
return _cache[cls][addr] return _cache[cls][addr]
except KeyError: except KeyError:
if not owned and hasattr(cls, '_delete_'): if not owned and cls._has_dtor():
_addr2dtor[addr] = cls._delete_ _addr2dtor[addr] = cls._delete_
obj = cap.instantiate() obj = cap.instantiate()
_cache[cls][addr] = obj # cache it _cache[cls][addr] = obj # cache it
@ -164,6 +168,10 @@ class Wrapper(object):
def _downcast(self, newcls): def _downcast(self, newcls):
return downcast(self, newcls) return downcast(self, newcls)
@classmethod
def _has_dtor(cls):
return hasattr(cls, '_delete_')
def downcast(obj, cls): def downcast(obj, cls):
import _api import _api
if type(obj) is cls: if type(obj) is cls:

View file

@ -283,6 +283,7 @@ class Method(object):
self.signatures = [] self.signatures = []
self.includes = set() self.includes = set()
self._add_signature(return_type, *args) self._add_signature(return_type, *args)
self.disowning = False
def _add_signature(self, return_type, *args): def _add_signature(self, return_type, *args):
prev_lens = set(map(len, self.signatures)) prev_lens = set(map(len, self.signatures))
@ -350,6 +351,8 @@ class Method(object):
decl = writer.function(self.name, args=('self',), varargs='args') decl = writer.function(self.name, args=('self',), varargs='args')
with decl as (this, varargs): with decl as (this, varargs):
unwrap_this = writer.unwrap(this) unwrap_this = writer.unwrap(this)
if self.disowning:
writer.release_ownership(unwrap_this)
unwrapped = writer.unwrap_many(varargs) unwrapped = writer.unwrap_many(varargs)
self.process_ownedptr_args(writer, unwrapped) self.process_ownedptr_args(writer, unwrapped)

View file

@ -13,6 +13,7 @@
#include <llvm/Module.h> #include <llvm/Module.h>
#include <llvm/Analysis/Verifier.h> #include <llvm/Analysis/Verifier.h>
#include <llvm/Constants.h> #include <llvm/Constants.h>
#include <llvm/Intrinsics.h>
#include "auto_pyobject.h" #include "auto_pyobject.h"
@ -694,3 +695,21 @@ PyObject* ConstantVector_get(PyObject* Elems)
return pycapsule_new(ary, "llvm::Value", "llvm::Constant"); return pycapsule_new(ary, "llvm::Value", "llvm::Constant");
} }
static
PyObject* Intrinsic_getDeclaration(llvm::Module* Mod,
unsigned ID,
PyObject* Types=NULL)
{
using namespace llvm;
Function* Fn = NULL;
if (Types) {
std::vector<Type*> types;
bool ok = extract<Type>::from_py_sequence(types, Types, "llvm::Type");
if (!ok) return NULL;
Fn = Intrinsic::getDeclaration(Mod, (Intrinsic::ID)ID, types);
} else {
Fn = Intrinsic::getDeclaration(Mod, (Intrinsic::ID)ID);
}
return pycapsule_new(Fn, "llvm::Value", "llvm::Function");
}

View file

@ -1,6 +1,8 @@
from binding import * from binding import *
from namespace import llvm from namespace import llvm
from Value import GlobalValue, Constant, Function, Argument from Value import GlobalValue, Constant, Function, Argument
from BasicBlock import BasicBlock
from Attributes import Attributes
from Type import Type from Type import Type
from DerivedTypes import FunctionType from DerivedTypes import FunctionType
from LLVMContext import LLVMContext from LLVMContext import LLVMContext
@ -21,6 +23,33 @@ class Function:
getCallingConv = Method(CallingConv.ID) getCallingConv = Method(CallingConv.ID)
setCallingConv = Method(Void, CallingConv.ID) setCallingConv = Method(Void, CallingConv.ID)
hasGC = Method(cast(bool, Bool))
getGC = Method(cast(ConstCharPtr, str))
setGC = Method(Void, cast(str, ConstCharPtr))
getArgumentList = CustomMethod('Function_getArgumentList', PyObjectPtr) getArgumentList = CustomMethod('Function_getArgumentList', PyObjectPtr)
getBasicBlockList = CustomMethod('Function_getBasicBlockList', PyObjectPtr) getBasicBlockList = CustomMethod('Function_getBasicBlockList', PyObjectPtr)
getEntryBlock = Method(ref(BasicBlock))
copyAttributesFrom = Method(Void, ptr(GlobalValue))
setDoesNotThrow = Method()
doesNotThrow = Method(cast(Bool, bool))
setDoesNotReturn = Method()
doesNotReturn = Method(cast(Bool, bool))
setOnlyReadsMemory = Method()
onlyReadsMemory = Method(cast(Bool, bool))
setDoesNotAccessMemory = Method()
doesNotAccessMemory = Method(cast(Bool, bool))
deleteBody = Method()
viewCFG = Method()
viewCFGOnly = Method()
addFnAttr = Method(Void, Attributes.AttrVal)
removeFnAttr = Method(Void, ref(Attributes))
eraseFromParent = Method()
eraseFromParent.disowning = True

View file

@ -44,4 +44,6 @@ class GlobalValue:
isDeclaration = Method(cast(Bool, bool)) isDeclaration = Method(cast(Bool, bool))
removeFromParent = Method() removeFromParent = Method()
eraseFromParent = Method() eraseFromParent = Method()
eraseFromParent.disowning = True
getParent = Method(ptr(Module)) getParent = Method(ptr(Module))

View file

@ -45,5 +45,5 @@ class GlobalVariable:
# isExternallyInitialized = Method(cast(Bool, bool)) # isExternallyInitialized = Method(cast(Bool, bool))
# setExternallyinitialized = Method(Void, cast(bool, Bool)) # setExternallyinitialized = Method(Void, cast(bool, Bool))
eraseFromParent = Method()

View file

@ -0,0 +1,17 @@
from binding import *
from namespace import llvm
from Module import Module
from Function import Function
Intrinsic = llvm.Class() # fake class (actually a namespace)
@Intrinsic
class Intrinsic:
getDeclaration = CustomStaticMethod('Intrinsic_getDeclaration',
PyObjectPtr, # Function*
ptr(Module),
cast(int, Unsigned), # intrinsic id
PyObjectPtr, # list of Type
).require_only(2)

View file

@ -319,6 +319,16 @@ def test_constants():
aryconst = api.ConstantArray.get(ary_int32x4, [intconst] * 4) aryconst = api.ConstantArray.get(ary_int32x4, [intconst] * 4)
assert str(aryconst.getAggregateElement(0)) == str(intconst) assert str(aryconst.getAggregateElement(0)) == str(intconst)
def test_intrinsic():
context = api.getGlobalContext()
m = api.Module.new("modname", context)
INTR_SIN = 1652
floatty = api.Type.getFloatTy(context)
fn = api.Intrinsic.getDeclaration(m, INTR_SIN, [floatty])
assert 'llvm.sin.f32' in str(fn)
fn.eraseFromParent()
assert 'llvm.sin.f32' not in str(m)
def main(): def main():
for name, value in globals().items(): for name, value in globals().items():
if name.startswith('test_') and callable(value): if name.startswith('test_') and callable(value):