[pygobject/llvm: 1/17] Use LLVM compile functions



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]