[pygobject/llvm: 1/17] Use LLVM compile functions
- From: Johan Dahlin <johan src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [pygobject/llvm: 1/17] Use LLVM compile functions
- Date: Wed, 21 Jul 2010 22:34:56 +0000 (UTC)
commit 7be2b749c38244741eda923ff9a350e99d269ede
Author: Johan Dahlin <johan gnome org>
Date: Fri Jul 2 10:44:04 2010 -0300
Use LLVM compile functions
configure.ac | 6 +-
gi/Makefile.am | 16 ++-
gi/llvm-compiler.cpp | 617 +++++++++++++++++++++++++++++++++++++++++++++++
gi/llvm-compiler.h | 80 ++++++
gi/pygi-info.c | 4 +-
gi/pygi-invoke-llvm.cpp | 58 +++++
gi/pygi-invoke.c | 1 -
gi/pygi-llvm.cpp | 58 +++++
gi/pygi-llvm.h | 34 +++
gi/pygi.h | 10 +
gi/types.py | 19 +-
11 files changed, 893 insertions(+), 10 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index dcf73a9..e66e123 100644
--- a/configure.ac
+++ b/configure.ac
@@ -72,10 +72,12 @@ AC_LIBTOOL_WIN32_DLL
AC_PROG_LIBTOOL
dnl when using libtool 2.x create libtool early, because it's used in configure
m4_ifdef([LT_OUTPUT], [LT_OUTPUT])
-AC_ISC_POSIX
AC_PROG_CC
-AM_PROG_CC_STDC
AM_PROG_CC_C_O
+AC_PROG_CXX
+AC_ISC_POSIX
+AC_HEADER_STDC
+AM_PROG_CC_STDC
JD_PATH_PYTHON(2.5.2)
diff --git a/gi/Makefile.am b/gi/Makefile.am
index fc57edb..d8e05df 100644
--- a/gi/Makefile.am
+++ b/gi/Makefile.am
@@ -16,7 +16,10 @@ pygi_PYTHON = \
importer.py \
__init__.py
-_gi_la_CFLAGS = \
+AM_CFLAGS = \
+ $(PYTHON_INCLUDES) \
+ $(GI_CFLAGS)
+AM_CXXFLAGS = \
$(PYTHON_INCLUDES) \
$(GI_CFLAGS)
_gi_la_LDFLAGS = \
@@ -53,6 +56,17 @@ _gi_la_SOURCES = \
pygobject-external.h \
gimodule.c
+# LLVM
+AM_CXXFLAGS += \
+ $(shell llvm-config --cxxflags core engine linker)
+_gi_la_LDFLAGS += \
+ $(shell llvm-config --ldflags --libs core engine linker)
+_gi_la_SOURCES += \
+ pygi-llvm.cpp \
+ pygi-llvm.h \
+ llvm-compiler.cpp \
+ llvm-compiler.h
+
_gi_cairo_la_CFLAGS = \
$(PYTHON_INCLUDES) \
$(GI_CFLAGS) \
diff --git a/gi/llvm-compiler.cpp b/gi/llvm-compiler.cpp
new file mode 100644
index 0000000..4d79312
--- /dev/null
+++ b/gi/llvm-compiler.cpp
@@ -0,0 +1,617 @@
+/* -*- Mode: C++; c-basic-offset: 2 -*-
+ * vim: tabstop=2 shiftwidth=2 expandtab
+ *
+ * Copyright (C) 2010 Johan Dahlin <johan gnome org>
+ *
+ * llvm-compiler.cpp: pygi llvm compiler
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#include "llvm-compiler.h"
+
+#include <math.h>
+#include <string>
+
+#include <Python.h>
+#define NO_IMPORT_PYGOBJECT
+#include <pygobject.h>
+#include "pygobject-external.h"
+#include "pygi.h"
+#include "pygi-info.h"
+
+#include <llvm/Analysis/Verifier.h>
+#include <llvm/DerivedTypes.h>
+#include <llvm/ExecutionEngine/JIT.h>
+#include <llvm/ExecutionEngine/JITMemoryManager.h>
+#include <llvm/CodeGen/MachineFunction.h>
+#include <llvm/Linker.h>
+#include <llvm/LLVMContext.h>
+#include <llvm/Module.h>
+#include <llvm/Support/IRBuilder.h>
+#include <llvm/Target/TargetSelect.h>
+
+#define DEBUG 1
+#define TIMEIT 1
+
+/*
+ * PyGI LLVM runtime functions
+ */
+// FIXME: replace with o->ob_type == &Py_Type
+long _PyLong_Check(PyObject *o) {
+ return PyLong_Check(o) || PyInt_Check(o);
+}
+
+long _PyFloat_Check(PyObject *o) {
+ return PyFloat_Check(o) || PyInt_Check(o) || PyLong_Check(o);
+}
+
+long _PyString_Check(PyObject *o) {
+ return PyString_Check(o);
+}
+
+long _PyGObject_Check(PyObject *o, GType type) {
+ if (!pygobject_check(o, _PyGObject_Type))
+ return 0;
+ PyGObject *go = (PyGObject*)o;
+ if (!g_type_is_a(G_OBJECT_TYPE(go->obj), type))
+ return 0;
+ return 1;
+}
+
+GObject * _PyGObject_Get(PyObject *o) {
+ return pygobject_get(o);
+}
+
+PyObject* _PyGObject_New(GObject *o) {
+ return pygobject_new(o);
+}
+
+
+/*
+ * LLVMCompiler
+ *
+ */
+
+using namespace pygi;
+
+static llvm::IRBuilder<> Builder(llvm::getGlobalContext());
+// PyObject = { ssize_t ob_refcnt, struct* ob_type }
+// PyTupleObject = { ssize_t ob_refcnt, struct* ob_type, ssize_t ob_size, PyObject* }
+static llvm::Type* pyObjectPtr = NULL;
+static llvm::Type* gObjectPtr = NULL;
+
+LLVMCompiler::LLVMCompiler(llvm::LLVMContext &ctx) :
+ mCtx(ctx)
+{
+ mModule = new llvm::Module("pygi", mCtx);
+ mEE = createExecutionEngine();
+
+}
+
+llvm::ExecutionEngine *
+LLVMCompiler::createExecutionEngine(void)
+{
+ std::string errStr;
+ llvm::ExecutionEngine *EE;
+
+ llvm::InitializeNativeTarget();
+
+ EE = llvm::EngineBuilder(mModule).setErrorStr(&errStr).setEngineKind(llvm::EngineKind::JIT).create();
+ if (!EE) {
+ g_error("Failed to construct ExecutionEngine: %s\n", errStr.c_str());
+ }
+ return EE;
+}
+
+const llvm::Type *
+LLVMCompiler::getTypeFromTypeInfo(GITypeInfo *typeInfo)
+{
+ switch (g_type_info_get_tag(typeInfo)) {
+ case GI_TYPE_TAG_VOID:
+ return llvm::Type::getVoidTy(mCtx);
+ case GI_TYPE_TAG_DOUBLE:
+ return llvm::Type::getDoubleTy(mCtx);
+ case GI_TYPE_TAG_INT8:
+ case GI_TYPE_TAG_UINT8:
+ return llvm::Type::getInt8Ty(mCtx);
+ case GI_TYPE_TAG_INT:
+ if (sizeof(int) == 4)
+ return llvm::Type::getInt32Ty(mCtx);
+ else if (sizeof(int) == 8)
+ return llvm::Type::getInt64Ty(mCtx);
+ else
+ g_assert_not_reached();
+ case GI_TYPE_TAG_INT32:
+ case GI_TYPE_TAG_UINT32:
+ return llvm::Type::getInt32Ty(mCtx);
+ case GI_TYPE_TAG_ARRAY:
+ return llvm::PointerType::getUnqual(llvm::Type::getInt32Ty(mCtx));
+ case GI_TYPE_TAG_UTF8:
+ return llvm::PointerType::getUnqual(llvm::Type::getInt8Ty(mCtx));
+ case GI_TYPE_TAG_INTERFACE:
+ return gObjectPtr;
+ default:
+ g_error("%s: unsupported type tag: %d\n", __FUNCTION__, g_type_info_get_tag(typeInfo));
+ return 0;
+ }
+}
+
+void
+LLVMCompiler::createIf(llvm::BasicBlock **block,
+ llvm::ICmpInst::Predicate pred,
+ llvm::Value* LHS,
+ llvm::Value* RHS,
+ llvm::BasicBlock *exitBB)
+{
+ llvm::Function *parent = (*block)->getParent();
+
+ llvm::BasicBlock *thenBB = llvm::BasicBlock::Create(mCtx, "bb", parent, 0);
+
+ // if (LHS PRED RHS) { okay } else { ... }
+ llvm::ICmpInst* cmpInst = new llvm::ICmpInst(*(*block), pred, LHS, RHS, "c");
+ llvm::BranchInst::Create(exitBB, thenBB, cmpInst, *block);
+
+ *block = thenBB;
+ Builder.SetInsertPoint(thenBB);
+}
+
+const char *
+LLVMCompiler::formatTypeForException(GITypeInfo *typeInfo)
+{
+ switch (g_type_info_get_tag(typeInfo)) {
+ case GI_TYPE_TAG_DOUBLE:
+ case GI_TYPE_TAG_INT:
+ case GI_TYPE_TAG_UINT:
+ case GI_TYPE_TAG_INT8:
+ case GI_TYPE_TAG_UINT8:
+ case GI_TYPE_TAG_INT16:
+ case GI_TYPE_TAG_UINT16:
+ case GI_TYPE_TAG_INT32:
+ case GI_TYPE_TAG_UINT32:
+ case GI_TYPE_TAG_INT64:
+ case GI_TYPE_TAG_UINT64:
+ return "a number";
+ case GI_TYPE_TAG_UTF8:
+ return "a string";
+ default:
+ g_warning("%s: unsupported type tag: %d\n", __FUNCTION__, g_type_info_get_tag(typeInfo));
+ return "an unknown type";
+ }
+}
+
+llvm::BasicBlock *
+LLVMCompiler::createException(GICallableInfo *callableInfo,
+ GIArgInfo *argInfo,
+ GITypeInfo *typeInfo,
+ int i,
+ llvm::BasicBlock *block)
+{
+ llvm::Function *parent = block->getParent();
+ llvm::BasicBlock* exitBB = llvm::BasicBlock::Create(mCtx, "bb", parent, 0);
+
+ llvm::Constant *f = mModule->getOrInsertFunction("PyErr_Format",
+ llvm::Type::getVoidTy(mCtx),
+ pyObjectPtr, llvm::PointerType::getUnqual(llvm::IntegerType::get(mCtx, 8)), NULL);
+
+ std::vector<llvm::Value*> args;
+ llvm::Value *exc = new llvm::GlobalVariable(pyObjectPtr, true, llvm::GlobalValue::ExternalLinkage, 0, "PyExc_TypeError");
+ llvm::Instruction *x = new llvm::LoadInst(exc, "", exitBB);
+ args.push_back(x);
+ // FIXME: add "not a, float" to the end
+ char *msg = g_strdup_printf("argument %d to %s must be %s",
+ i+1, g_base_info_get_name((GIBaseInfo*)callableInfo),
+ this->formatTypeForException(typeInfo));
+ llvm::Value *format = Builder.CreateGlobalStringPtr(msg, "format");
+ g_free(msg);
+ args.push_back(format);
+ llvm::CallInst::Create(f, args.begin(), args.end(), "", exitBB);
+
+ llvm::ReturnInst::Create(mCtx, llvm::ConstantInt::get(llvm::Type::getInt32Ty(mCtx), 0), exitBB);
+ return exitBB;
+}
+
+void
+LLVMCompiler::typeCheck(GICallableInfo *callableInfo,
+ GIArgInfo *argInfo,
+ GITypeInfo *typeInfo,
+ int i,
+ llvm::BasicBlock **block,
+ llvm::Value *value)
+{
+ switch (g_type_info_get_tag(typeInfo)) {
+ case GI_TYPE_TAG_DOUBLE: {
+ llvm::Constant *f = mModule->getOrInsertFunction("_PyFloat_Check", llvm::Type::getInt32Ty(mCtx), pyObjectPtr, NULL);
+ llvm::Value *v = llvm::CallInst::Create(f, value, "l", *block);
+ llvm::BasicBlock *excBlock = this->createException(callableInfo, argInfo, typeInfo, i, *block);
+ this->createIf(block, llvm::ICmpInst::ICMP_EQ, v, llvm::ConstantInt::get(llvm::Type::getInt32Ty(mCtx), 0), excBlock);
+ break;
+ }
+ case GI_TYPE_TAG_INT:
+ case GI_TYPE_TAG_INT8:
+ case GI_TYPE_TAG_UINT8:
+ case GI_TYPE_TAG_INT16:
+ case GI_TYPE_TAG_UINT16:
+ case GI_TYPE_TAG_INT32:
+ case GI_TYPE_TAG_UINT32: {
+ llvm::Constant *f = mModule->getOrInsertFunction("_PyLong_Check", llvm::Type::getInt32Ty(mCtx), pyObjectPtr, NULL);
+ llvm::Value *v = llvm::CallInst::Create(f, value, "l", *block);
+ llvm::BasicBlock *excBlock = this->createException(callableInfo, argInfo, typeInfo, i, *block);
+ this->createIf(block, llvm::ICmpInst::ICMP_EQ, v, llvm::ConstantInt::get(llvm::Type::getInt32Ty(mCtx), 0), excBlock);
+ break;
+ }
+ case GI_TYPE_TAG_UTF8: {
+ llvm::Constant *f = mModule->getOrInsertFunction("_PyString_Check", llvm::Type::getInt32Ty(mCtx), pyObjectPtr, NULL);
+ llvm::Value *v = llvm::CallInst::Create(f, value, "l", *block);
+ llvm::BasicBlock *excBlock = this->createException(callableInfo, argInfo, typeInfo, i, *block);
+ this->createIf(block, llvm::ICmpInst::ICMP_EQ, v, llvm::ConstantInt::get(llvm::Type::getInt32Ty(mCtx), 0), excBlock);
+ break;
+ }
+ case GI_TYPE_TAG_ARRAY: {
+ /* FIXME */
+ break;
+ }
+ case GI_TYPE_TAG_INTERFACE: {
+ GIBaseInfo *ifaceInfo = g_type_info_get_interface(typeInfo);
+ g_assert(ifaceInfo != NULL);
+ GIInfoType infoType = g_base_info_get_type(ifaceInfo);
+ switch (infoType) {
+ case GI_INFO_TYPE_OBJECT: {
+ std::vector<llvm::Value*> args;
+ args.push_back(value);
+ GType objectType = g_registered_type_info_get_g_type((GIRegisteredTypeInfo*)ifaceInfo);
+ args.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(mCtx), objectType));
+ llvm::Constant *f = mModule->getOrInsertFunction("_PyGObject_Check", llvm::Type::getInt32Ty(mCtx), pyObjectPtr,
+ llvm::Type::getInt32Ty(mCtx), NULL);
+ llvm::Value *v = llvm::CallInst::Create(f, value, "l", *block);
+ llvm::BasicBlock *excBlock = this->createException(callableInfo, argInfo, typeInfo, i, *block);
+ this->createIf(block, llvm::ICmpInst::ICMP_EQ, v, llvm::ConstantInt::get(llvm::Type::getInt32Ty(mCtx), 0), excBlock);
+ break;
+ }
+ default:
+ g_error("%s: unsupported info type: %d\n", __FUNCTION__, infoType);
+ break;
+ }
+ g_base_info_unref((GIBaseInfo*)ifaceInfo);
+ break;
+ }
+ default:
+ g_error("%s: unsupported type tag: %d\n", __FUNCTION__, g_type_info_get_tag(typeInfo));
+ break;
+ }
+}
+
+llvm::Value *
+LLVMCompiler::valueAsNative(GITypeInfo *typeInfo,
+ llvm::BasicBlock *parentBB,
+ llvm::Value *value)
+{
+ llvm::Value *retval;
+ bool isSigned = false;
+ switch (g_type_info_get_tag(typeInfo)) {
+ case GI_TYPE_TAG_DOUBLE: {
+ // FIXME: ->ob_fval
+ llvm::Constant *f = mModule->getOrInsertFunction("PyFloat_AsDouble",
+ llvm::Type::getDoubleTy(mCtx), pyObjectPtr, NULL);
+ llvm::CallInst *r = llvm::CallInst::Create(f, value, "arg", parentBB);
+ retval = Builder.CreateSIToFP(r, llvm::Type::getDoubleTy(mCtx), "arg_sitofp");
+ break;
+ }
+ case GI_TYPE_TAG_INT:
+ case GI_TYPE_TAG_INT8:
+ case GI_TYPE_TAG_INT16:
+ case GI_TYPE_TAG_INT32:
+ isSigned = true;
+ case GI_TYPE_TAG_UINT8:
+ case GI_TYPE_TAG_UINT16:
+ case GI_TYPE_TAG_UINT32: {
+ llvm::Constant *f = mModule->getOrInsertFunction("PyLong_AsLong",
+ llvm::Type::getInt32Ty(mCtx), pyObjectPtr, NULL);
+ llvm::Value *v = llvm::CallInst::Create(f, value, "arg", parentBB);
+ retval = Builder.CreateIntCast(v, this->getTypeFromTypeInfo(typeInfo), isSigned, "cast");
+ break;
+ }
+ case GI_TYPE_TAG_UTF8: {
+ llvm::Constant *f = mModule->getOrInsertFunction("PyString_AsString",
+ llvm::PointerType::getUnqual(llvm::IntegerType::get(mCtx, 8)),
+ pyObjectPtr, NULL);
+ retval = llvm::CallInst::Create(f, value, "arg", parentBB);
+ break;
+ }
+ case GI_TYPE_TAG_ARRAY: {
+ retval = llvm::ConstantExpr::getNullValue(llvm::Type::getInt32Ty(mCtx)->getPointerTo());
+ break;
+ }
+ case GI_TYPE_TAG_INTERFACE: {
+ GIBaseInfo *ifaceInfo = g_type_info_get_interface(typeInfo);
+ g_assert(ifaceInfo != NULL);
+ GIInfoType infoType = g_base_info_get_type(ifaceInfo);
+ switch (infoType) {
+ case GI_INFO_TYPE_OBJECT: {
+ llvm::Constant *f = mModule->getOrInsertFunction("_PyGObject_Get",
+ gObjectPtr, pyObjectPtr, NULL);
+ retval = llvm::CallInst::Create(f, value, "arg", parentBB);
+ break;
+ }
+ default:
+ g_error("%s: unsupported info type: %d\n", __FUNCTION__, infoType);
+ retval = 0;
+ break;
+ }
+ g_base_info_unref((GIBaseInfo*)ifaceInfo);
+ break;
+ }
+ default:
+ g_error("%s: unsupported type tag: %d\n", __FUNCTION__, g_type_info_get_tag(typeInfo));
+ retval = 0;
+ break;
+ }
+ return retval;
+}
+
+llvm::Value *
+LLVMCompiler::valueFromNative(GITypeInfo *typeInfo,
+ llvm::BasicBlock *parentBB,
+ llvm::Value *value)
+{
+ llvm::Value *retval;
+ bool isSigned = false;
+ switch (g_type_info_get_tag(typeInfo)) {
+ case GI_TYPE_TAG_DOUBLE: {
+ llvm::Constant *f = mModule->getOrInsertFunction("PyFloat_FromDouble",
+ pyObjectPtr, llvm::Type::getDoubleTy(mCtx), NULL);
+ retval = llvm::CallInst::Create(llvm::cast<llvm::Function>(f), value, "py_retval", parentBB);
+ break;
+ }
+ case GI_TYPE_TAG_INT8:
+ case GI_TYPE_TAG_INT16:
+ case GI_TYPE_TAG_INT32:
+ isSigned = true;
+ case GI_TYPE_TAG_UINT8:
+ case GI_TYPE_TAG_UINT16:
+ case GI_TYPE_TAG_UINT32: {
+ llvm::Constant *f = mModule->getOrInsertFunction("PyLong_FromLong",
+ pyObjectPtr, llvm::Type::getInt32Ty(mCtx), NULL);
+ llvm::Value *casted = Builder.CreateIntCast(value, llvm::Type::getInt32Ty(mCtx), isSigned, "cast");
+ retval = llvm::CallInst::Create(llvm::cast<llvm::Function>(f), casted, "py_retval", parentBB);
+ break;
+ }
+ case GI_TYPE_TAG_UTF8: {
+ llvm::Constant *f = mModule->getOrInsertFunction("PyString_FromString",
+ pyObjectPtr, llvm::PointerType::getUnqual(llvm::IntegerType::get(mCtx, 8)), NULL);
+ retval = llvm::CallInst::Create(llvm::cast<llvm::Function>(f), value, "py_retval", parentBB);
+ break;
+ }
+ case GI_TYPE_TAG_ARRAY: {
+ retval = llvm::ReturnInst::Create(mCtx, llvm::ConstantInt::get(llvm::Type::getInt32Ty(mCtx), 0), parentBB);
+ break;
+ }
+ case GI_TYPE_TAG_INTERFACE: {
+ GIBaseInfo *ifaceInfo = g_type_info_get_interface(typeInfo);
+ g_assert(ifaceInfo != NULL);
+ GIInfoType infoType = g_base_info_get_type(ifaceInfo);
+ switch (infoType) {
+ case GI_INFO_TYPE_OBJECT: {
+ llvm::Constant *f = mModule->getOrInsertFunction("_PyGObject_New",
+ pyObjectPtr, gObjectPtr, NULL);
+ retval = llvm::CallInst::Create(llvm::cast<llvm::Function>(f), value, "py_retval", parentBB);
+ break;
+ }
+ default:
+ g_error("%s: unsupported info type: %d\n", __FUNCTION__, infoType);
+ retval = 0;
+ break;
+ }
+ g_base_info_unref((GIBaseInfo*)ifaceInfo);
+ break;
+ }
+ default:
+ g_error("%s: unsupported type tag: %d\n", __FUNCTION__, g_type_info_get_tag(typeInfo));
+ retval = 0;
+ break;
+ }
+ return retval;
+}
+
+llvm::Value *
+LLVMCompiler::tupleGetItem(llvm::BasicBlock *block,
+ llvm::Value *value,
+ unsigned int i)
+{
+ std::vector<llvm::Value*> args;
+ args.push_back(value);
+ args.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(mCtx), i));
+ std::string Name("py_arg");
+
+ // FIXME: ->ob_item
+ llvm::Constant *f = mModule->getOrInsertFunction("PyTuple_GetItem",
+ pyObjectPtr, pyObjectPtr, llvm::Type::getInt32Ty(mCtx), NULL);
+ llvm::Value *inst = llvm::CallInst::Create(f, args.begin(), args.end(), Name, block);
+ return llvm::cast<llvm::Value>(inst);
+}
+
+static void *
+pyg_get_native_address(GIFunctionInfo *info)
+{
+ void * nativeAddress;
+
+ const gchar * shlib = g_irepository_get_shared_library(NULL, g_base_info_get_namespace((GIBaseInfo*)info));
+ const gchar * symbol = g_function_info_get_symbol(info);
+ GModule *m = g_module_open(shlib, G_MODULE_BIND_LAZY);
+ g_module_symbol(m, symbol, &nativeAddress);
+ g_module_close(m);
+
+ return nativeAddress;
+}
+
+static llvm::Function *
+pyg_create_native_call(llvm::Module *module,
+ const llvm::Type *nativeRetvalType,
+ std::vector<const llvm::Type*> nativeTypes,
+ std::vector<llvm::Value*> nativeArgValues,
+ GIFunctionInfo *functionInfo)
+{
+ std::string symbol(g_function_info_get_symbol(functionInfo));
+
+ // native call
+ llvm::FunctionType *nativeFT = llvm::FunctionType::get(nativeRetvalType, nativeTypes, false);
+ return llvm::Function::Create(nativeFT, llvm::Function::ExternalLinkage, symbol, module);
+}
+
+char *
+LLVMCompiler::getFunctionName(GIFunctionInfo *info)
+{
+ return g_strdup_printf("pygi_wrap_%s_%s",
+ g_base_info_get_namespace((GIBaseInfo*)info),
+ g_base_info_get_name((GIBaseInfo*)info));
+}
+
+llvm::Value *
+LLVMCompiler::createPyNone()
+{
+ llvm::Value *retval = new llvm::GlobalVariable(pyObjectPtr,
+ true,
+ llvm::GlobalValue::ExternalLinkage,
+ 0, "_Py_NoneStruct");
+ // FIXME: Increase reference count
+ return retval;
+}
+
+PyCFunction
+LLVMCompiler::compile(GIFunctionInfo *info)
+{
+ GICallableInfo *callableInfo = (GICallableInfo*)info;
+
+#ifdef TIMEIT
+ struct timeval start_tv;
+ gettimeofday(&start_tv, NULL);
+#endif
+ // llvm
+ static int symbolsLoaded = 0;
+
+ if (!symbolsLoaded) {
+ llvm::Constant *f;
+ pyObjectPtr = llvm::PointerType::getUnqual(llvm::StructType::get(mCtx, NULL, NULL));
+ gObjectPtr = llvm::PointerType::getUnqual(llvm::StructType::get(mCtx, NULL, NULL));
+ f = mModule->getOrInsertFunction("_PyLong_Check", llvm::Type::getInt32Ty(mCtx), pyObjectPtr, NULL);
+ mEE->updateGlobalMapping(llvm::cast<llvm::Function>(f), (void*)&_PyLong_Check);
+ f = mModule->getOrInsertFunction("_PyFloat_Check", llvm::Type::getInt32Ty(mCtx), pyObjectPtr, NULL);
+ mEE->updateGlobalMapping(llvm::cast<llvm::Function>(f), (void*)&_PyFloat_Check);
+ f = mModule->getOrInsertFunction("_PyString_Check", llvm::Type::getInt32Ty(mCtx), pyObjectPtr, NULL);
+ mEE->updateGlobalMapping(llvm::cast<llvm::Function>(f), (void*)&_PyString_Check);
+ f = mModule->getOrInsertFunction("_PyGObject_Check", llvm::Type::getInt32Ty(mCtx), pyObjectPtr,
+ llvm::Type::getInt32Ty(mCtx), NULL);
+ mEE->updateGlobalMapping(llvm::cast<llvm::Function>(f), (void*)&_PyGObject_Check);
+ f = mModule->getOrInsertFunction("_PyGObject_Get", gObjectPtr, pyObjectPtr, NULL);
+ mEE->updateGlobalMapping(llvm::cast<llvm::Function>(f), (void*)&_PyGObject_Get);
+ f = mModule->getOrInsertFunction("_PyGObject_New", pyObjectPtr, gObjectPtr, NULL);
+ mEE->updateGlobalMapping(llvm::cast<llvm::Function>(f), (void*)&_PyGObject_New);
+ symbolsLoaded = 1;
+ }
+
+ // wrapper
+
+ std::vector<const llvm::Type*> wrapperArgTypes(2, pyObjectPtr);
+ llvm::FunctionType *FT = llvm::FunctionType::get(pyObjectPtr, wrapperArgTypes, false);
+
+ char *funcName = this->getFunctionName(info);
+ llvm::Function *wrapperFunc = llvm::Function::Create(FT, llvm::Function::ExternalLinkage, funcName, mModule);
+ g_free(funcName);
+
+ llvm::BasicBlock *funcBB = llvm::BasicBlock::Create(mCtx, "entry", wrapperFunc);
+ Builder.SetInsertPoint(funcBB);
+
+ std::vector<llvm::Value*> wrapperArgValues(2);
+ unsigned Idx = 0;
+ for (llvm::Function::arg_iterator AI = wrapperFunc->arg_begin(); Idx != wrapperArgTypes.size();
+ ++AI, ++Idx) {
+ AI->setName("py_arg0");
+ wrapperArgValues[Idx] = AI;
+ }
+
+ llvm::BasicBlock *block = funcBB;
+
+ // type checking
+ // py->native args
+ std::vector<llvm::Value*> nativeArgValues;
+ std::vector<const llvm::Type*> nativeTypes;
+ int n_args = g_callable_info_get_n_args(callableInfo);
+ for (int i = 0; i < n_args; ++i) {
+ GIArgInfo *argInfo = g_callable_info_get_arg(callableInfo, i);
+ GITypeInfo *typeInfo = g_arg_info_get_type(argInfo);
+ llvm::Value *value;
+
+ if (n_args == 1) {
+ value = wrapperArgValues[1];
+ } else {
+ // PyTuple_GetItem()
+ value = this->tupleGetItem(block, wrapperArgValues[1], i);
+ }
+ // PyXXX_Check()
+ this->typeCheck(callableInfo, argInfo, typeInfo, i, &block, value);
+
+ // PyXXX_FromXXX
+ llvm::Value *arg = this->valueAsNative(typeInfo, block, value);
+ const llvm::Type *type = this->getTypeFromTypeInfo(typeInfo);
+ nativeTypes.push_back(type);
+ nativeArgValues.push_back(arg);
+ g_base_info_unref((GIBaseInfo*)typeInfo);
+ g_base_info_unref((GIBaseInfo*)argInfo);
+ }
+
+ // py->native return type
+ GIArgInfo *retTypeInfo = g_callable_info_get_return_type(callableInfo);
+ const llvm::Type *nativeRetvalType = this->getTypeFromTypeInfo(retTypeInfo);
+ llvm::Function * nativeF = pyg_create_native_call(mModule, nativeRetvalType, nativeTypes, nativeArgValues, info);
+ mEE->updateGlobalMapping(nativeF, pyg_get_native_address(info));
+
+ const char *retValName;
+ if (g_type_info_get_tag(retTypeInfo) == GI_TYPE_TAG_VOID)
+ retValName = "";
+ else
+ retValName = "retval";
+
+ llvm::Value *nativeCallRetval = llvm::CallInst::Create(nativeF, nativeArgValues.begin(), nativeArgValues.end(), retValName, block);
+
+ // arg->py conversion
+ llvm::Value *retval;
+ if (g_type_info_get_tag(retTypeInfo) == GI_TYPE_TAG_VOID) {
+ retval = this->createPyNone();
+ } else {
+ retval = this->valueFromNative(retTypeInfo, block, nativeCallRetval);
+ }
+ llvm::ReturnInst::Create(mCtx, retval, block);
+
+ g_base_info_unref((GIBaseInfo*)retTypeInfo);
+
+#if DEBUG
+ mModule->dump();
+#endif
+
+ // JIT it
+ PyCFunction f = (PyCFunction)mEE->getPointerToFunction(wrapperFunc);
+
+#if TIMEIT
+ struct timeval end_tv;
+ gettimeofday(&end_tv, NULL);
+ g_print("Compiled: %s in %2.2f ms\n", g_function_info_get_symbol(info),
+ (end_tv.tv_usec-start_tv.tv_usec)/1000.0);
+#elif DEBUG
+ g_print("Compiled: %s\n", g_function_info_get_symbol(info));
+#endif
+
+ return f;
+}
diff --git a/gi/llvm-compiler.h b/gi/llvm-compiler.h
new file mode 100644
index 0000000..a2d11c6
--- /dev/null
+++ b/gi/llvm-compiler.h
@@ -0,0 +1,80 @@
+/* -*- Mode: C++; c-basic-offset: 2 -*-
+ * vim: tabstop=2 shiftwidth=2 expandtab
+ *
+ * Copyright (C) 2010 Johan Dahlin <johan gnome org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#ifndef __PYGI_LLVM_COMPILER_H__
+#define __PYGI_LLVM_COMPILER_H__
+
+#include <girepository.h>
+#include <Python.h>
+
+#include <llvm/ExecutionEngine/ExecutionEngine.h>
+#include <llvm/LLVMContext.h>
+#include <llvm/Module.h>
+#include <llvm/Support/IRBuilder.h>
+
+namespace pygi {
+
+ class LLVMCompiler {
+ private:
+ llvm::LLVMContext &mCtx;
+ llvm::ExecutionEngine *mEE;
+ llvm::Module *mModule;
+
+ llvm::ExecutionEngine* createExecutionEngine(void);
+
+ llvm::Value* tupleGetItem(llvm::BasicBlock *block,
+ llvm::Value *value,
+ unsigned i);
+ void typeCheck(GICallableInfo *callableInfo,
+ GIArgInfo *argInfo,
+ GITypeInfo *typeInfo,
+ int i,
+ llvm::BasicBlock **block,
+ llvm::Value *value);
+ llvm::Value* valueAsNative(GITypeInfo *typeInfo,
+ llvm::BasicBlock *parentBB,
+ llvm::Value *value);
+ llvm::Value* valueFromNative(GITypeInfo *typeInfo,
+ llvm::BasicBlock *parentBB,
+ llvm::Value *value);
+ const llvm::Type* getTypeFromTypeInfo(GITypeInfo *typeInfo);
+ llvm::BasicBlock* createException(GICallableInfo *callableInfo,
+ GIArgInfo *argInfo,
+ GITypeInfo *typeInfo,
+ int i,
+ llvm::BasicBlock *block);
+ void createIf(llvm::BasicBlock **block,
+ llvm::ICmpInst::Predicate pred,
+ llvm::Value* LHS,
+ llvm::Value* RHS,
+ llvm::BasicBlock *exitBB);
+ const char * formatTypeForException(GITypeInfo *typeInfo);
+ char * getFunctionName(GIFunctionInfo *info);
+ llvm::Value * createPyNone();
+
+ public:
+ LLVMCompiler(llvm::LLVMContext &ctx);
+ PyCFunction compile(GIFunctionInfo *info);
+ };
+
+} // End pygi namespace
+
+#endif /* __PYGI_LLVM_COMPILER_H__ */
diff --git a/gi/pygi-info.c b/gi/pygi-info.c
index 7888ada..c107818 100644
--- a/gi/pygi-info.c
+++ b/gi/pygi-info.c
@@ -1,7 +1,7 @@
/* -*- Mode: C; c-basic-offset: 4 -*-
* vim: tabstop=4 shiftwidth=4 expandtab
*
- * Copyright (C) 2005-2009 Johan Dahlin <johan gnome org>
+ * Copyright (C) 2005-2010 Johan Dahlin <johan gnome org>
*
* pygi-info.c: GI.*Info wrappers.
*
@@ -22,6 +22,7 @@
*/
#include "pygi-private.h"
+#include "pygi-llvm.h"
#include <pygobject.h>
@@ -462,6 +463,7 @@ static PyMethodDef _PyGIFunctionInfo_methods[] = {
{ "is_constructor", (PyCFunction) _wrap_g_function_info_is_constructor, METH_NOARGS },
{ "is_method", (PyCFunction) _wrap_g_function_info_is_method, METH_NOARGS },
{ "invoke", (PyCFunction) _wrap_g_function_info_invoke, METH_VARARGS },
+ { "llvm_compile", (PyCFunction) _wrap_g_function_info_llvm_compile, METH_VARARGS },
{ NULL, NULL, 0 }
};
diff --git a/gi/pygi-invoke-llvm.cpp b/gi/pygi-invoke-llvm.cpp
new file mode 100644
index 0000000..62d3c69
--- /dev/null
+++ b/gi/pygi-invoke-llvm.cpp
@@ -0,0 +1,58 @@
+/* -*- Mode: C; c-basic-offset: 4 -*-
+ * vim: tabstop=4 shiftwidth=4 expandtab
+ *
+ * Copyright (C) 2010 Johan Dahlin <johan gnome org>
+ *
+ * pygi-llvm-compiler.cpp: LLVM PyGI integration
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#include "llvm-compiler.h"
+
+extern "C" {
+
+PyObject *
+_wrap_g_function_info_llvm_compile(PyGIBaseInfo *self, PyObject *args)
+{
+ PyCFunction func;
+ PyObject *pyfunc;
+ GIFunctionInfo *info;
+ PyMethodDef *def;
+
+ g_print("Compiling...%s\n", g_function_info_get_symbol(self->info));
+ func = llvm_compile(self->info);
+ g_assert(func != NULL);
+
+ def = (PyMethodDef*)malloc(sizeof(PyMethodDef*));
+ def->ml_name = g_base_info_get_name((GIBaseInfo*)self->info);
+ def->ml_meth = func;
+ int n_args = g_callable_info_get_n_args((GICallableInfo*)self->info);
+ if (n_args == 0) {
+ def->ml_flags = METH_NOARGS;
+ } else if (n_args == 1) {
+ def->ml_flags = METH_O;
+ } else {
+ def->ml_flags = METH_VARARGS;
+ }
+
+ pyfunc = PyCFunction_New(def, (PyObject*)self);
+
+ Py_INCREF(pyfunc);
+ return pyfunc;
+}
+
+}
diff --git a/gi/pygi-invoke.c b/gi/pygi-invoke.c
index 022874e..2b5d433 100644
--- a/gi/pygi-invoke.c
+++ b/gi/pygi-invoke.c
@@ -1003,4 +1003,3 @@ _wrap_g_function_info_invoke (PyGIBaseInfo *self, PyObject *py_args)
return state.return_value;
}
-
diff --git a/gi/pygi-llvm.cpp b/gi/pygi-llvm.cpp
new file mode 100644
index 0000000..c616393
--- /dev/null
+++ b/gi/pygi-llvm.cpp
@@ -0,0 +1,58 @@
+/* -*- Mode: C; c-basic-offset: 4 -*-
+ * vim: tabstop=4 shiftwidth=4 expandtab
+ *
+ * Copyright (C) 2010 Johan Dahlin <johan gnome org>
+ *
+ * pygi-llvm.cpp: llvm integration
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#include <pygobject.h>
+#include "pygi-llvm.h"
+
+#include "llvm-compiler.h"
+
+PyObject *
+_wrap_g_function_info_llvm_compile(PyGIBaseInfo *self, PyObject *args)
+{
+ PyCFunction func;
+ PyObject *pyfunc;
+ GIFunctionInfo *info;
+ PyMethodDef *def;
+ static pygi::LLVMCompiler compiler(llvm::getGlobalContext());
+
+ g_print("Compiling...%s\n", g_function_info_get_symbol(self->info));
+ func = compiler.compile(self->info);
+ g_assert(func != NULL);
+
+ def = (PyMethodDef*)malloc(sizeof(PyMethodDef*));
+ def->ml_name = g_base_info_get_name((GIBaseInfo*)self->info);
+ def->ml_meth = func;
+ int n_args = g_callable_info_get_n_args((GICallableInfo*)self->info);
+ if (n_args == 0) {
+ def->ml_flags = METH_NOARGS;
+ } else if (n_args == 1) {
+ def->ml_flags = METH_O;
+ } else {
+ def->ml_flags = METH_VARARGS;
+ }
+
+ pyfunc = PyCFunction_New(def, (PyObject*)self);
+
+ Py_INCREF(pyfunc);
+ return pyfunc;
+}
diff --git a/gi/pygi-llvm.h b/gi/pygi-llvm.h
new file mode 100644
index 0000000..7d720ab
--- /dev/null
+++ b/gi/pygi-llvm.h
@@ -0,0 +1,34 @@
+/* -*- Mode: C; c-basic-offset: 4 -*-
+ * vim: tabstop=4 shiftwidth=4 expandtab
+ *
+ * Copyright (C) 2010 Johan Dahlin <johan gnome org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#ifndef __PYGI_LLVM_H__
+#define __PYGI_LLVM_H__
+
+#include <girepository.h>
+#include <pygi.h>
+
+G_BEGIN_DECLS
+
+PyObject *_wrap_g_function_info_llvm_compile(PyGIBaseInfo *self, PyObject *py_args);
+
+G_END_DECLS
+
+#endif /* __PYGI_LLVM_H__ */
diff --git a/gi/pygi.h b/gi/pygi.h
index 92b7bae..61b5cb0 100644
--- a/gi/pygi.h
+++ b/gi/pygi.h
@@ -123,4 +123,14 @@ pygi_type_import_by_g_type (GType g_type)
#endif /* ENABLE_INTROSPECTION */
+/* Don't leak PACKAGE_* defines from config.h,
+ * as there might be other packages (such as llvm) which
+ * want to use them
+ */
+#undef PACKAGE_BUGREPORT
+#undef PACKAGE_NAME
+#undef PACKAGE_STRING
+#undef PACKAGE_TARNAME
+#undef PACKAGE_VERSION
+
#endif /* __PYGI_H__ */
diff --git a/gi/types.py b/gi/types.py
index 8ac9cab..e1d6c74 100644
--- a/gi/types.py
+++ b/gi/types.py
@@ -33,19 +33,26 @@ from ._gi import \
register_interface_info, \
hook_up_vfunc_implementation
+_gi_llvm = None
-def Function(info):
+def enable_llvm():
+ global _gi_llvm
+ _gi_llvm = True
+def Function(info):
def function(*args):
return info.invoke(*args)
function.__info__ = info
function.__name__ = info.get_name()
function.__module__ = info.get_namespace()
-
- return function
+ if _gi_llvm:
+ return info.llvm_compile()
+ else:
+ return function
def Constructor(info):
+ global _gi_llvm
def constructor(cls, *args):
cls_name = info.get_container().get_name()
@@ -56,8 +63,10 @@ def Constructor(info):
constructor.__info__ = info
constructor.__name__ = info.get_name()
constructor.__module__ = info.get_namespace()
-
- return constructor
+ if _gi_llvm:
+ return info.llvm_compile()
+ else:
+ return constructor
class MetaClassHelper(object):
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]