From 4c1b9016fb513a96463b68472ec6a5e6c1416912 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 31 Jul 2013 15:12:23 -0500 Subject: [PATCH 01/37] binding compiles with llvm 3.3 --- llvmpy/gen/binding.py | 3 +- llvmpy/include/llvm_binding/extra.h | 83 +++++++++++----- llvmpy/src/Argument.py | 19 +++- llvmpy/src/Attributes.py | 101 +++++++++++++++----- llvmpy/src/DIBuilder.py | 38 +++++--- llvmpy/src/DataLayout.py | 5 +- llvmpy/src/DerivedTypes.py | 5 +- llvmpy/src/Function.py | 22 ++++- llvmpy/src/GlobalValue.py | 5 +- llvmpy/src/IRBuilder.py | 6 +- llvmpy/src/InlineAsm.py | 5 +- llvmpy/src/Instruction.py | 26 +++-- llvmpy/src/LLVMContext.py | 5 +- llvmpy/src/Linker.py | 35 +++---- llvmpy/src/Module.py | 5 +- llvmpy/src/Support/Host.py | 29 ++++-- llvmpy/src/Target/TargetMachine.py | 12 ++- llvmpy/src/TargetTransformInfo.py | 16 +++- llvmpy/src/Transforms/PassManagerBuilder.py | 6 +- llvmpy/src/Type.py | 5 +- llvmpy/src/ValueSymbolTable.py | 5 +- setup.py | 7 +- 22 files changed, 324 insertions(+), 119 deletions(-) diff --git a/llvmpy/gen/binding.py b/llvmpy/gen/binding.py index 8006fd9..db4fdbf 100644 --- a/llvmpy/gen/binding.py +++ b/llvmpy/gen/binding.py @@ -247,7 +247,8 @@ class Class(SubModule, _Type): def __call__(self, defn): assert not self._is_defined # process the definition in "defn" - self.name = defn.__name__ + self.name = getattr(defn, '_name_', defn.__name__) + for k, v in defn.__dict__.items(): if isinstance(v, Method): self.methods.append(v) diff --git a/llvmpy/include/llvm_binding/extra.h b/llvmpy/include/llvm_binding/extra.h index 456f75e..cd1f59c 100644 --- a/llvmpy/include/llvm_binding/extra.h +++ b/llvmpy/include/llvm_binding/extra.h @@ -1,8 +1,22 @@ #include #include -#include -#include -#include +#if LLVM_VERSION_MAJOR >= 3 and LLVM_VERSION_MINOR >= 3 + #include + #include + #include + #include + #include + #include + #include +#else + #include + #include + #include + #include + #include + #include + #include +#endif #include #include #include @@ -12,11 +26,7 @@ #include #include #include -#include #include -#include -#include -#include #include #include @@ -56,6 +66,15 @@ namespace extra{ } +static +PyObject* callwrite(PyObject* self, PyObject* arg) +{ + char meth[] = "method"; + char fmt[] = "O"; + return PyObject_CallMethod(self, meth, fmt, arg); +} + + static PyObject* make_raw_ostream_for_printing(PyObject* self, PyObject* args) { @@ -271,7 +290,7 @@ llvm::ExecutionEngine* ExecutionEngine_create( &ErrorStr, OptLevel, GVsWithCode); auto_pyobject buf = PyBytes_FromString(ErrorStr.c_str()); - if (errout && NULL == PyObject_CallMethod(errout, "write", "O", *buf)){ + if (errout && NULL == callwrite(errout, *buf)){ return NULL; } @@ -298,7 +317,7 @@ llvm::ExecutionEngine* ExecutionEngine_createJIT( ExecutionEngine *ee = ExecutionEngine::createJIT(M, &ErrorStr, JMM, OL, GCsWithCode, RM, CMM); auto_pyobject buf = PyBytes_FromString(ErrorStr.c_str()); - if (errout && NULL == PyObject_CallMethod(errout, "write", "O", *buf)){ + if (errout && NULL == callwrite(errout, *buf)){ return NULL; } // PyFile_WriteString(ErrorStr.c_str(), errout); @@ -483,7 +502,7 @@ PyObject* llvm_ParseBitCodeFile(llvm::StringRef Buf, llvm::LLVMContext& Ctx, std::string ErrStr; M = ParseBitcodeFile(MB, Ctx, &ErrStr); auto_pyobject buf = PyBytes_FromString(ErrStr.c_str()); - if (NULL == PyObject_CallMethod(FObj, "write", "O", *buf)){ + if (NULL == callwrite(FObj, *buf)){ return NULL; } // if (-1 == PyFile_WriteString(ErrStr.c_str(), FObj)) { @@ -507,7 +526,7 @@ PyObject* llvm_WriteBitcodeToFile(const llvm::Module *M, PyObject* FObj) rso.flush(); StringRef ref = rso.str(); auto_pyobject buf = PyBytes_FromStringAndSize(ref.data(), ref.size()); - return PyObject_CallMethod(FObj, "write", "O", *buf); + return callwrite(FObj, *buf); } static @@ -522,7 +541,7 @@ PyObject* llvm_getBitcodeTargetTriple(llvm::StringRef Buf, std::string ErrStr; Triple = getBitcodeTargetTriple(MB, Ctx, &ErrStr); auto_pyobject buf = PyBytes_FromString(ErrStr.c_str()); - if (NULL == PyObject_CallMethod(FObj, "write", "O", *buf)){ + if (NULL == callwrite(FObj, *buf)){ return NULL; } // if (-1 == PyFile_WriteString(ErrStr.c_str(), FObj)) { @@ -594,19 +613,19 @@ PyObject* Linker_LinkInModule(llvm::Linker* Linker, PyObject* ErrMsg) { std::string errmsg; +#if LLVM_VERSION_MAJOR >= 3 && LLVM_VERSION_MINOR >= 3 + bool failed = Linker->linkInModule(Mod, &errmsg); +#else bool failed = Linker->LinkInModule(Mod, &errmsg); +#endif if (! failed) { Py_RETURN_FALSE; } else { auto_pyobject buf = PyBytes_FromString(errmsg.c_str()); - if (NULL == PyObject_CallMethod(ErrMsg, "write", "O", *buf)){ + if (NULL == callwrite(ErrMsg, *buf)){ return NULL; } - -// if (-1 == PyFile_WriteString(errmsg.c_str(), ErrMsg)) { -// return NULL; -// } Py_RETURN_TRUE; } } @@ -623,7 +642,7 @@ PyObject* Linker_LinkModules(llvm::Module* Dest, Py_RETURN_FALSE; } else { auto_pyobject buf = PyBytes_FromString(errmsg.c_str()); - if (NULL == PyObject_CallMethod(ErrMsg, "write", "O", *buf)){ + if (NULL == callwrite(ErrMsg, *buf)){ return NULL; } // if (-1 == PyFile_WriteString(errmsg.c_str(), ErrMsg)) { @@ -689,7 +708,7 @@ PyObject* llvm_verifyModule(const llvm::Module& Fn, if (failed) { auto_pyobject buf = PyBytes_FromString(errmsg.c_str()); - if (NULL == PyObject_CallMethod(ErrMsg, "write", "O", *buf)){ + if (NULL == callwrite(ErrMsg, *buf)){ return NULL; } @@ -819,7 +838,7 @@ PyObject* DynamicLibrary_LoadLibraryPermanently(const char * Filename, failed = DynamicLibrary::LoadLibraryPermanently(Filename, &errmsg); if (failed) { auto_pyobject buf = PyBytes_FromString(errmsg.c_str()); - if (NULL == PyObject_CallMethod(ErrMsg, "write", "O", *buf)){ + if (NULL == callwrite(ErrMsg, *buf)){ return NULL; } // if (-1 == PyFile_WriteString(errmsg.c_str(), ErrMsg)) { @@ -869,7 +888,7 @@ PyObject* TargetRegistry_lookupTarget(const std::string &Triple, if (!target) { // PyFile_WriteString(error.c_str(), Error); auto_pyobject buf = PyBytes_FromString(error.c_str()); - if (NULL == PyObject_CallMethod(Error, "write", "O", *buf)){ + if (NULL == callwrite(Error, *buf)){ return NULL; } @@ -891,7 +910,7 @@ PyObject* TargetRegistry_lookupTarget(const std::string &Arch, if (!target) { // PyFile_WriteString(error.c_str(), Error); auto_pyobject buf = PyBytes_FromString(error.c_str()); - if (NULL == PyObject_CallMethod(Error, "write", "O", *buf)){ + if (NULL == callwrite(Error, *buf)){ return NULL; } @@ -910,7 +929,7 @@ PyObject* TargetRegistry_getClosestTargetForJIT(PyObject* Error) const Target* target = TargetRegistry::getClosestTargetForJIT(error); if (!target) { auto_pyobject buf = PyBytes_FromString(error.c_str()); - if (NULL == PyObject_CallMethod(Error, "write", "O", *buf)){ + if (NULL == callwrite(Error, *buf)){ return NULL; } @@ -945,3 +964,21 @@ PyObject* llvm_sys_getHostCPUFeatures(PyObject* Features) } } + +static +PyObject* llvm_sys_isLittleEndianHost() +{ + if (llvm::sys::IsLittleEndianHost) + Py_RETURN_TRUE; + else + Py_RETURN_FALSE; +} + +static +PyObject* llvm_sys_isBigEndianHost() +{ + if (llvm::sys::IsBigEndianHost) + Py_RETURN_TRUE; + else + Py_RETURN_FALSE; +} \ No newline at end of file diff --git a/llvmpy/src/Argument.py b/llvmpy/src/Argument.py index 6262147..a08cca1 100644 --- a/llvmpy/src/Argument.py +++ b/llvmpy/src/Argument.py @@ -1,16 +1,27 @@ from binding import * from .namespace import llvm from .Value import Argument, Value -from .Attributes import Attributes +if LLVM_VERSION >= (3, 3): + from .Attributes import AttributeSet, Attribute +else: + from .Attributes import Attributes @Argument class Argument: - _include_ = 'llvm/Argument.h' + if LLVM_VERSION >= (3, 3): + _include_ = 'llvm/IR/Argument.h' + else: + _include_ = 'llvm/Argument.h' _downcast_ = Value - addAttr = Method(Void, ref(Attributes)) - removeAttr = Method(Void, ref(Attributes)) + if LLVM_VERSION >= (3, 3): + addAttr = Method(Void, ref(AttributeSet)) + removeAttr = Method(Void, ref(AttributeSet)) + else: + addAttr = Method(Void, ref(Attributes)) + removeAttr = Method(Void, ref(Attributes)) + getParamAlignment = Method(cast(Unsigned, int)) getArgNo = Method(cast(Unsigned, int)) diff --git a/llvmpy/src/Attributes.py b/llvmpy/src/Attributes.py index 4fe7651..303d61d 100644 --- a/llvmpy/src/Attributes.py +++ b/llvmpy/src/Attributes.py @@ -2,38 +2,91 @@ from binding import * from .namespace import llvm from .LLVMContext import LLVMContext -llvm.includes.add('llvm/Attributes.h') +if LLVM_VERSION >= (3, 3): + llvm.includes.add('llvm/IR/Attributes.h') +else: + llvm.includes.add('llvm/Attributes.h') + -Attributes = llvm.Class() AttrBuilder = llvm.Class() - -@Attributes -class Attributes: - AttrVal = Enum('''None, AddressSafety, Alignment, AlwaysInline, - ByVal, InlineHint, InReg, MinSize, - Naked, Nest, NoAlias, NoCapture, - NoImplicitFloat, NoInline, NonLazyBind, NoRedZone, - NoReturn, NoUnwind, OptimizeForSize, ReadNone, - ReadOnly, ReturnsTwice, SExt, StackAlignment, - StackProtect, StackProtectReq, StructRet, UWTable, ZExt''') - - delete = Destructor() - - get = StaticMethod(Attributes, ref(LLVMContext), ref(AttrBuilder)) +if LLVM_VERSION >= (3, 3): + Attribute = llvm.Class() + AttributeSet = llvm.Class() +else: + Attributes = llvm.Class() -@AttrBuilder -class AttrBuilder: +if LLVM_VERSION >= (3, 3): + @Attribute + class Attribute: + AttrKind = Enum('''None, Alignment, AlwaysInline, + ByVal, InlineHint, InReg, + MinSize, Naked, Nest, NoAlias, + NoBuiltin, NoCapture, NoDuplicate, NoImplicitFloat, + NoInline, NonLazyBind, NoRedZone, NoReturn, + NoUnwind, OptimizeForSize, ReadNone, ReadOnly, + Returned, ReturnsTwice, SExt, StackAlignment, + StackProtect, StackProtectReq, StackProtectStrong, StructRet, + SanitizeAddress, SanitizeThread, SanitizeMemory, UWTable, + ZExt, EndAttrKinds''') - new = Constructor() - delete = Destructor() + delete = Destructor() - clear = Method() + get = StaticMethod(Attribute, + ref(LLVMContext), + AttrKind, + cast(int, Uint64)).require_only(2) - addAttribute = Method(ref(AttrBuilder), Attributes.AttrVal) - removeAttribute = Method(ref(AttrBuilder), Attributes.AttrVal) + @AttrBuilder + class AttrBuilder: - addAlignmentAttr = Method(ref(AttrBuilder), cast(int, Unsigned)) + new = Constructor() + delete = Destructor() + + clear = Method() + + addAttribute = Method(ref(AttrBuilder), Attribute.AttrKind) + removeAttribute = Method(ref(AttrBuilder), Attribute.AttrKind) + + addAlignmentAttr = Method(ref(AttrBuilder), cast(int, Unsigned)) + + @AttributeSet + class AttributeSet: + delete = Destructor() + + get = StaticMethod(AttributeSet, + ref(LLVMContext), + cast(int, Unsigned), + ref(AttrBuilder)) + +else: + @Attributes + class Attributes: + AttrVal = Enum('''None, AddressSafety, Alignment, AlwaysInline, + ByVal, InlineHint, InReg, MinSize, + Naked, Nest, NoAlias, NoCapture, + NoImplicitFloat, NoInline, NonLazyBind, NoRedZone, + NoReturn, NoUnwind, OptimizeForSize, ReadNone, + ReadOnly, ReturnsTwice, SExt, StackAlignment, + StackProtect, StackProtectReq, StructRet, UWTable, ZExt''') + + delete = Destructor() + + get = StaticMethod(Attributes, ref(LLVMContext), ref(AttrBuilder)) + + + @AttrBuilder + class AttrBuilder: + + new = Constructor() + delete = Destructor() + + clear = Method() + + addAttribute = Method(ref(AttrBuilder), Attributes.AttrVal) + removeAttribute = Method(ref(AttrBuilder), Attributes.AttrVal) + + addAlignmentAttr = Method(ref(AttrBuilder), cast(int, Unsigned)) diff --git a/llvmpy/src/DIBuilder.py b/llvmpy/src/DIBuilder.py index 9671963..cb934d4 100644 --- a/llvmpy/src/DIBuilder.py +++ b/llvmpy/src/DIBuilder.py @@ -124,17 +124,31 @@ class DIBuilder: ptr(MDNode), # TemplateParms = 0 ).require_only(10) - createStructType = Method(DIType, - ref(DIDescriptor), # Scope - stringref_arg, # Name - ref(DIFile), # File - unsigned_arg, # LineNumber - uint64_arg, # SizeInBits - uint64_arg, # AlignInBits - unsigned_arg, # Flags - ref(DIArray), # Elements - unsigned_arg, # RunTimeLang = 0 - ).require_only(8) + if LLVM_VERSION >= (3, 3): + createStructType = Method(DIType, + ref(DIDescriptor), # Scope + stringref_arg, # Name + ref(DIFile), # File + unsigned_arg, # LineNumber + uint64_arg, # SizeInBits + uint64_arg, # AlignInBits + unsigned_arg, # Flags + ref(DIType), # DerivedFrom + ref(DIArray), # Elements + unsigned_arg, # RunTimeLang = 0 + ).require_only(9) + else: + createStructType = Method(DIType, + ref(DIDescriptor), # Scope + stringref_arg, # Name + ref(DIFile), # File + unsigned_arg, # LineNumber + uint64_arg, # SizeInBits + uint64_arg, # AlignInBits + unsigned_arg, # Flags + ref(DIArray), # Elements + unsigned_arg, # RunTimeLang = 0 + ).require_only(8) createUnionType = Method(DIType, ref(DIDescriptor), # Scope @@ -186,7 +200,7 @@ class DIBuilder: ref(DIType), # Ty ) - createTemporaryType = Method(DIType, ref(DIFile)).require_only(0) + #createTemporaryType = Method(DIType, ref(DIFile)).require_only(0) createForwardDecl = Method(DIType, unsigned_arg, # Tag diff --git a/llvmpy/src/DataLayout.py b/llvmpy/src/DataLayout.py index 812a83d..6741cda 100644 --- a/llvmpy/src/DataLayout.py +++ b/llvmpy/src/DataLayout.py @@ -15,7 +15,10 @@ from .GlobalVariable import GlobalVariable @DataLayout class DataLayout: - _include_ = 'llvm/DataLayout.h' + if LLVM_VERSION >= (3, 3): + _include_ = 'llvm/IR/DataLayout.h' + else: + _include_ = 'llvm/DataLayout.h' _new_string = Constructor(cast(str, StringRef)) _new_module = Constructor(ptr(Module)) diff --git a/llvmpy/src/DerivedTypes.py b/llvmpy/src/DerivedTypes.py index 02eec8c..fde01f3 100644 --- a/llvmpy/src/DerivedTypes.py +++ b/llvmpy/src/DerivedTypes.py @@ -8,7 +8,10 @@ FunctionType = llvm.Class(Type) @FunctionType class FunctionType: - _include_ = 'llvm/DerivedTypes.h' + if LLVM_VERSION >= (3, 3): + _include_ = 'llvm/IR/DerivedTypes.h' + else: + _include_ = 'llvm/DerivedTypes.h' _downcast_ = Type _get = StaticMethod(ptr(FunctionType), ptr(Type), cast(bool, Bool)) diff --git a/llvmpy/src/Function.py b/llvmpy/src/Function.py index 04c3e65..9c2c8b7 100644 --- a/llvmpy/src/Function.py +++ b/llvmpy/src/Function.py @@ -4,7 +4,10 @@ from .Value import GlobalValue, Constant, Function, Argument, Value from .Module import Module from .BasicBlock import BasicBlock from .ValueSymbolTable import ValueSymbolTable -from .Attributes import Attributes +if LLVM_VERSION >= (3, 3): + from .Attributes import Attribute, AttributeSet +else: + from .Attributes import Attributes from .Type import Type from .DerivedTypes import FunctionType from .LLVMContext import LLVMContext @@ -12,7 +15,11 @@ from .CallingConv import CallingConv @Function class Function: - _include_ = 'llvm/Function.h' + if LLVM_VERSION >= (3, 3): + _include_ = 'llvm/IR/Function.h' + else: + _include_ = 'llvm/Function.h' + _downcast_ = GlobalValue, Constant, Value getReturnType = Method(ptr(Type)) @@ -48,10 +55,17 @@ class Function: deleteBody = Method() viewCFG = Method() + viewCFGOnly = Method() - addFnAttr = Method(Void, Attributes.AttrVal) - removeFnAttr = Method(Void, ref(Attributes)) + if LLVM_VERSION >= (3, 3): + addFnAttr = Method(Void, Attribute.AttrKind) + addAttributes = Method(Void, cast(int, Unsigned), ref(AttributeSet)) + removeAttributes = Method(Void, cast(int, Unsigned), ref(AttributeSet)) + #removeFnAttr = Method(Void, Attribute.AttrKind) # 3.4? + else: + addFnAttr = Method(Void, Attributes.AttrVal) + removeFnAttr = Method(Void, ref(Attributes)) #hasFnAttribute = Method(cast(Bool, bool), Attributes.AttrVal) Create = StaticMethod(ptr(Function), diff --git a/llvmpy/src/GlobalValue.py b/llvmpy/src/GlobalValue.py index d954ed0..49071e3 100644 --- a/llvmpy/src/GlobalValue.py +++ b/llvmpy/src/GlobalValue.py @@ -6,7 +6,10 @@ from .ADT.StringRef import StringRef @GlobalValue class GlobalValue: - _include_ = 'llvm/GlobalValue.h' + if LLVM_VERSION >= (3, 3): + _include_ = 'llvm/IR/GlobalValue.h' + else: + _include_ = 'llvm/GlobalValue.h' LinkageTypes = Enum(''' ExternalLinkage, AvailableExternallyLinkage, LinkOnceAnyLinkage, diff --git a/llvmpy/src/IRBuilder.py b/llvmpy/src/IRBuilder.py index c0766e9..c4d8a86 100644 --- a/llvmpy/src/IRBuilder.py +++ b/llvmpy/src/IRBuilder.py @@ -18,7 +18,11 @@ IRBuilder = llvm.Class() @IRBuilder class IRBuilder: - _include_ = 'llvm/IRBuilder.h' + if LLVM_VERSION >= (3, 3): + _include_ = 'llvm/IR/IRBuilder.h' + else: + _include_ = 'llvm/IRBuilder.h' + _realname_ = 'IRBuilder<>' new = Constructor(ref(LLVMContext)) diff --git a/llvmpy/src/InlineAsm.py b/llvmpy/src/InlineAsm.py index 8793343..c96cef0 100644 --- a/llvmpy/src/InlineAsm.py +++ b/llvmpy/src/InlineAsm.py @@ -4,7 +4,10 @@ from .Value import Value from .DerivedTypes import FunctionType from .ADT.StringRef import StringRef -llvm.includes.add('llvm/InlineAsm.h') +if LLVM_VERSION >= (3, 3): + llvm.includes.add('llvm/IR/InlineAsm.h') +else: + llvm.includes.add('llvm/InlineAsm.h') InlineAsm = llvm.Class(Value) diff --git a/llvmpy/src/Instruction.py b/llvmpy/src/Instruction.py index e17e8a1..2771015 100644 --- a/llvmpy/src/Instruction.py +++ b/llvmpy/src/Instruction.py @@ -65,7 +65,10 @@ SynchronizationScope = llvm.Enum('SynchronizationScope', from .ADT.StringRef import StringRef from .CallingConv import CallingConv -from .Attributes import Attributes +if LLVM_VERSION >= (3, 3): + from .Attributes import AttributeSet, Attribute +else: + from .Attributes import Attributes from .Type import Type @@ -142,8 +145,12 @@ class CallInst: getCallingConv = Method(CallingConv.ID) setCallingConv = Method(Void, CallingConv.ID) getParamAlignment = Method(cast(Unsigned, int), cast(int, Unsigned)) - addAttribute = Method(Void, cast(int, Unsigned), ref(Attributes)) - removeAttribute = Method(Void, cast(int, Unsigned), ref(Attributes)) + if LLVM_VERSION >= (3, 3): + addAttribute = Method(Void, cast(int, Unsigned), Attribute.AttrKind) + removeAttribute = Method(Void, cast(int, Unsigned), ref(Attribute)) + else: + addAttribute = Method(Void, cast(int, Unsigned), ref(Attributes)) + removeAttribute = Method(Void, cast(int, Unsigned), ref(Attributes)) getCalledFunction = Method(ptr(Function)) getCalledValue = Method(ptr(Value)) setCalledFunction = Method(Void, ptr(Function)) @@ -264,7 +271,10 @@ class UnaryInstruction: @IntrinsicInst class IntrinsicInst: - _include_ = 'llvm/IntrinsicInst.h' + if LLVM_VERSION >= (3, 3): + _include_ = 'llvm/IR/IntrinsicInst.h' + else: + _include_ = 'llvm/IntrinsicInst.h' _downcast_ = Value, User, Instruction #compare @@ -292,8 +302,12 @@ class InvokeInst: getCallingConv = Method(CallingConv.ID) setCallingConv = Method(Void, CallingConv.ID) getParamAlignment = Method(cast(Unsigned, int), cast(int, Unsigned)) - addAttribute = Method(Void, cast(int, Unsigned), ref(Attributes)) - removeAttribute = Method(Void, cast(int, Unsigned), ref(Attributes)) + if LLVM_VERSION >= (3, 3): + addAttribute = Method(Void, cast(int, Unsigned), Attribute.AttrKind) + removeAttribute = Method(Void, cast(int, Unsigned), ref(Attribute)) + else: + addAttribute = Method(Void, cast(int, Unsigned), ref(Attributes)) + removeAttribute = Method(Void, cast(int, Unsigned), ref(Attributes)) getCalledFunction = Method(ptr(Function)) getCalledValue = Method(ptr(Value)) setCalledFunction = Method(Void, ptr(Function)) diff --git a/llvmpy/src/LLVMContext.py b/llvmpy/src/LLVMContext.py index 4a6b49a..8ec1607 100644 --- a/llvmpy/src/LLVMContext.py +++ b/llvmpy/src/LLVMContext.py @@ -3,6 +3,9 @@ from .namespace import llvm @llvm.Class() class LLVMContext: - _include_ = "llvm/LLVMContext.h" + if LLVM_VERSION >= (3, 3): + _include_ = "llvm/IR/LLVMContext.h" + else: + _include_ = "llvm/LLVMContext.h" llvm.Function('getGlobalContext', ref(LLVMContext)) diff --git a/llvmpy/src/Linker.py b/llvmpy/src/Linker.py index 960bd90..5f1b7af 100644 --- a/llvmpy/src/Linker.py +++ b/llvmpy/src/Linker.py @@ -10,30 +10,33 @@ Linker = llvm.Class() @Linker class Linker: - ControlFlags = Enum('Verbose, QuietWarnings, QuietErrors') + #ControlFlags = Enum('Verbose, QuietWarnings, QuietErrors') LinkerMode = Enum('DestroySource, PreserveSource') - _new_w_empty = Constructor(cast(str, StringRef), - cast(str, StringRef), - ref(LLVMContext), - cast(int, Unsigned)).require_only(3) + if LLVM_VERSION >= (3, 3): + new = Constructor(ptr(Module)) + else: + _new_w_empty = Constructor(cast(str, StringRef), + cast(str, StringRef), + ref(LLVMContext), + cast(int, Unsigned)).require_only(3) - _new_w_existing = Constructor(cast(str, StringRef), - ptr(Module), - cast(int, Unsigned)).require_only(2) + _new_w_existing = Constructor(cast(str, StringRef), + ptr(Module), + cast(int, Unsigned)).require_only(2) - @CustomPythonStaticMethod - def new(progname, module_or_name, *args): - if isinstance(module_or_name, Module): - return _new_w_existing(progname, module_or_name, *args) - else: - return _new_w_empty(progname, module_or_name, *args) + @CustomPythonStaticMethod + def new(progname, module_or_name, *args): + if isinstance(module_or_name, Module): + return _new_w_existing(progname, module_or_name, *args) + else: + return _new_w_empty(progname, module_or_name, *args) delete = Destructor() getModule = Method(ptr(Module)) - releaseModule = Method(ptr(Module)) - getLastError = Method(cast(ConstStdString, str)) + #releaseModule = Method(ptr(Module)) + #getLastError = Method(cast(ConstStdString, str)) LinkInModule = CustomMethod('Linker_LinkInModule', PyObjectPtr, # boolean diff --git a/llvmpy/src/Module.py b/llvmpy/src/Module.py index 46fad5a..9dbe754 100644 --- a/llvmpy/src/Module.py +++ b/llvmpy/src/Module.py @@ -16,7 +16,10 @@ from .Metadata import NamedMDNode @Module class Module: - _include_ = "llvm/Module.h" + if LLVM_VERSION >= (3, 3): + _include_ = "llvm/IR/Module.h" + else: + _include_ = "llvm/Module.h" # Enumerators Endianness = Enum('AnyEndianness', 'LittleEndian', 'BigEndian') PointerSize = Enum('AnyPointerSize', 'Pointer32', 'Pointer64') diff --git a/llvmpy/src/Support/Host.py b/llvmpy/src/Support/Host.py index 8163ebe..cd063e8 100644 --- a/llvmpy/src/Support/Host.py +++ b/llvmpy/src/Support/Host.py @@ -1,18 +1,29 @@ from binding import * from src.namespace import sys -isLittleEndianHost = sys.Function('isLittleEndianHost', - cast(Bool, bool)) - -isBigEndianHost = sys.Function('isBigEndianHost', - cast(Bool, bool)) - getDefaultTargetTriple = sys.Function('getDefaultTargetTriple', cast(ConstStdString, str)) -# llvm 3.3 -#getProcessTriple = sys.Function('getProcessTriple', -# cast(ConstStdString, str)) +if LLVM_VERSION >= (3, 3): + getProcessTriple = sys.Function('getProcessTriple', + cast(ConstStdString, str)) + + isLittleEndianHost = sys.CustomFunction('isLittleEndianHost', + 'llvm_sys_isLittleEndianHost', + cast(Bool, bool)) + + isBigEndianHost = sys.CustomFunction('isBigEndianHost', + 'llvm_sys_isBigEndianHost', + cast(Bool, bool)) + +else: + + isLittleEndianHost = sys.Function('isLittleEndianHost', + cast(Bool, bool)) + + isBigEndianHost = sys.Function('isBigEndianHost', + cast(Bool, bool)) + getHostCPUName = sys.Function('getHostCPUName', cast(ConstStdString, str)) diff --git a/llvmpy/src/Target/TargetMachine.py b/llvmpy/src/Target/TargetMachine.py index 1bd6843..84c0d5d 100644 --- a/llvmpy/src/Target/TargetMachine.py +++ b/llvmpy/src/Target/TargetMachine.py @@ -8,8 +8,10 @@ from src.ADT.StringRef import StringRef from src.Support.CodeGen import CodeModel, TLSModel, CodeGenOpt, Reloc from src.GlobalValue import GlobalValue from src.DataLayout import DataLayout -from src.TargetTransformInfo import (ScalarTargetTransformInfo, - VectorTargetTransformInfo) + +if LLVM_VERSION < (3, 3): + from src.TargetTransformInfo import (ScalarTargetTransformInfo, + VectorTargetTransformInfo) from src.PassManager import PassManagerBase from src.Support.FormattedStream import formatted_raw_ostream @@ -39,9 +41,11 @@ class TargetMachine: setMCUseDwarfDirectory = Method(Void, cast(bool, Bool)) getDataLayout = Method(const(ownedptr(DataLayout))) - getScalarTargetTransformInfo = Method(const( + + if LLVM_VERSION < (3, 3): + getScalarTargetTransformInfo = Method(const( ownedptr(ScalarTargetTransformInfo))) - getVectorTargetTransformInfo = Method(const( + getVectorTargetTransformInfo = Method(const( ownedptr(VectorTargetTransformInfo))) addPassesToEmitFile = Method(cast(bool, Bool), diff --git a/llvmpy/src/TargetTransformInfo.py b/llvmpy/src/TargetTransformInfo.py index 1208050..d51bc52 100644 --- a/llvmpy/src/TargetTransformInfo.py +++ b/llvmpy/src/TargetTransformInfo.py @@ -2,7 +2,10 @@ from binding import * from src.namespace import llvm from src.Pass import ImmutablePass -llvm.includes.add('llvm/TargetTransformInfo.h') +if LLVM_VERSION >= (3, 3): + llvm.includes.add('llvm/Analysis/TargetTransformInfo.h') +else: + llvm.includes.add('llvm/TargetTransformInfo.h') TargetTransformInfo = llvm.Class(ImmutablePass) ScalarTargetTransformInfo = llvm.Class() @@ -11,14 +14,17 @@ VectorTargetTransformInfo = llvm.Class() @ScalarTargetTransformInfo class ScalarTargetTransformInfo: - delete = Destructor() + if LLVM_VERSION < (3, 3): + delete = Destructor() @VectorTargetTransformInfo class VectorTargetTransformInfo: - delete = Destructor() + if LLVM_VERSION < (3, 3): + delete = Destructor() @TargetTransformInfo class TargetTransformInfo: - new = Constructor(ptr(ScalarTargetTransformInfo), - ptr(VectorTargetTransformInfo)) + if LLVM_VERSION < (3, 3): + new = Constructor(ptr(ScalarTargetTransformInfo), + ptr(VectorTargetTransformInfo)) diff --git a/llvmpy/src/Transforms/PassManagerBuilder.py b/llvmpy/src/Transforms/PassManagerBuilder.py index 86be4fb..146d409 100644 --- a/llvmpy/src/Transforms/PassManagerBuilder.py +++ b/llvmpy/src/Transforms/PassManagerBuilder.py @@ -36,7 +36,11 @@ class PassManagerBuilder: DisableSimplifyLibCalls = _attr_bool() DisableUnitAtATime = _attr_bool() DisableUnrollLoops = _attr_bool() - Vectorize = _attr_bool() + if LLVM_VERSION >= (3, 3): + BBVectorize = _attr_bool() + SLPVectorize = _attr_bool() + else: + Vectorize = _attr_bool() LoopVectorize = _attr_bool() LibraryInfo = Attr(getter=ownedptr(TargetLibraryInfo), diff --git a/llvmpy/src/Type.py b/llvmpy/src/Type.py index afc148c..50c4862 100644 --- a/llvmpy/src/Type.py +++ b/llvmpy/src/Type.py @@ -15,7 +15,10 @@ VectorType = llvm.Class(SequentialType) @Type class Type: - _include_ = 'llvm/Type.h' + if LLVM_VERSION >= (3, 3): + _include_ = 'llvm/IR/Type.h' + else: + _include_ = 'llvm/Type.h' TypeID = Enum(''' VoidTyID, HalfTyID, FloatTyID, DoubleTyID, diff --git a/llvmpy/src/ValueSymbolTable.py b/llvmpy/src/ValueSymbolTable.py index 7e8890c..8762156 100644 --- a/llvmpy/src/ValueSymbolTable.py +++ b/llvmpy/src/ValueSymbolTable.py @@ -4,7 +4,10 @@ from .ADT.StringRef import StringRef @ValueSymbolTable class ValueSymbolTable: - _include_ = 'llvm/ValueSymbolTable.h' + if LLVM_VERSION >= (3, 3): + _include_ = 'llvm/IR/ValueSymbolTable.h' + else: + _include_ = 'llvm/ValueSymbolTable.h' new = Constructor() delete = Destructor() lookup = Method(ptr(Value), cast(str, StringRef)) diff --git a/setup.py b/setup.py index 1dc8af8..2c3a38f 100644 --- a/setup.py +++ b/setup.py @@ -61,7 +61,12 @@ def auto_intrinsic_gen(incdir): # let's do auto intrinsic generation print("Generate intrinsic IDs") from tools import intrgen - path = "%s/llvm/Intrinsics.gen" % incdir + + if llvm_version >= (3, 3): + path = "%s/llvm/IR/Intrinsics.gen" % incdir + else: + path = "%s/llvm/Intrinsics.gen" % incdir + with open('llvm/_intrinsic_ids.py', 'w') as fout: intrgen.gen(path, fout) From 6d3253e4ea39a857a0f6119f561b8fd3e3ee50c3 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 31 Jul 2013 15:44:01 -0500 Subject: [PATCH 02/37] Add things to make MCJIT working --- llvm-config-win32.py | 2 ++ llvm/ee.py | 2 +- llvmpy/include/llvm_binding/extra.h | 1 + llvmpy/src/ExecutionEngine/ExecutionEngine.py | 2 ++ setup.py | 2 +- 5 files changed, 7 insertions(+), 2 deletions(-) diff --git a/llvm-config-win32.py b/llvm-config-win32.py index 5f6c401..e191290 100644 --- a/llvm-config-win32.py +++ b/llvm-config-win32.py @@ -53,6 +53,7 @@ LLVMInterpreter LLVMipa LLVMipo LLVMJIT +LLVMMCJIT LLVMLinker LLVMMC LLVMMCParser @@ -71,6 +72,7 @@ LLVMX86Desc LLVMX86Disassembler LLVMX86Info LLVMX86Utils +LLVMDebugInfo Advapi32 Shell32 """.split(): diff --git a/llvm/ee.py b/llvm/ee.py index 7ea90d0..e87777a 100644 --- a/llvm/ee.py +++ b/llvm/ee.py @@ -232,7 +232,7 @@ def initialize_target(target, noraise=False): It is safe to initialize the same target multiple times. """ prefix = 'LLVMInitialize' - postfixes = ['Target', 'TargetInfo', 'TargetMC', 'AsmPrinter'] + postfixes = ['Target', 'TargetInfo', 'TargetMC', 'AsmPrinter', 'AsmParser'] try: for postfix in postfixes: getattr(api, '%s%s%s' % (prefix, target, postfix))() diff --git a/llvmpy/include/llvm_binding/extra.h b/llvmpy/include/llvm_binding/extra.h index cd1f59c..49ac261 100644 --- a/llvmpy/include/llvm_binding/extra.h +++ b/llvmpy/include/llvm_binding/extra.h @@ -30,6 +30,7 @@ #include #include +#include // to make MCJIT working #include "auto_pyobject.h" diff --git a/llvmpy/src/ExecutionEngine/ExecutionEngine.py b/llvmpy/src/ExecutionEngine/ExecutionEngine.py index 3208269..d6dfe43 100644 --- a/llvmpy/src/ExecutionEngine/ExecutionEngine.py +++ b/llvmpy/src/ExecutionEngine/ExecutionEngine.py @@ -101,3 +101,5 @@ class ExecutionEngine: unwrapped = list(map(capsule.unwrap, args)) return self._runFunction(fn, tuple(unwrapped)) + finalizeObject = Method(Void) + diff --git a/setup.py b/setup.py index 2c3a38f..546e77e 100644 --- a/setup.py +++ b/setup.py @@ -124,7 +124,7 @@ else: extra_components = list(extra_components & enabled_components) libs_core, objs_core = get_libs_and_objs( - ['core', 'analysis', 'scalaropts', 'executionengine', + ['core', 'analysis', 'scalaropts', 'executionengine', 'mcjit', 'jit', 'native', 'interpreter', 'bitreader', 'bitwriter', 'instrumentation', 'ipa', 'ipo', 'transformutils', 'asmparser', 'linker', 'support', 'vectorize'] From 625858aa6fc48975c5f0bf45ffd3aa44f3d3b067 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 31 Jul 2013 16:05:24 -0500 Subject: [PATCH 03/37] fixes --- llvmpy/include/llvm_binding/extra.h | 7 ++++--- setup.py | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/llvmpy/include/llvm_binding/extra.h b/llvmpy/include/llvm_binding/extra.h index 49ac261..161c52e 100644 --- a/llvmpy/include/llvm_binding/extra.h +++ b/llvmpy/include/llvm_binding/extra.h @@ -70,7 +70,7 @@ namespace extra{ static PyObject* callwrite(PyObject* self, PyObject* arg) { - char meth[] = "method"; + char meth[] = "write"; char fmt[] = "O"; return PyObject_CallMethod(self, meth, fmt, arg); } @@ -965,7 +965,7 @@ PyObject* llvm_sys_getHostCPUFeatures(PyObject* Features) } } - +#if LLVM_VERSION_MAJOR >= 3 && LLVM_VERSION_MINOR >= 3 static PyObject* llvm_sys_isLittleEndianHost() { @@ -982,4 +982,5 @@ PyObject* llvm_sys_isBigEndianHost() Py_RETURN_TRUE; else Py_RETURN_FALSE; -} \ No newline at end of file +} +#endif diff --git a/setup.py b/setup.py index 546e77e..e94a258 100644 --- a/setup.py +++ b/setup.py @@ -36,6 +36,7 @@ def run_llvm_config(extra_args): return stdout.decode().strip() llvm_version = run_llvm_config(['--version']) + print('LLVM version = %r' % llvm_version) targets_built = run_llvm_config(['--targets-built']) @@ -62,7 +63,7 @@ def auto_intrinsic_gen(incdir): print("Generate intrinsic IDs") from tools import intrgen - if llvm_version >= (3, 3): + if llvm_version.startswith('3.3'): path = "%s/llvm/IR/Intrinsics.gen" % incdir else: path = "%s/llvm/Intrinsics.gen" % incdir From 56a511854a6fd7f6776c58630088498385e5af30 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 31 Jul 2013 16:43:50 -0500 Subject: [PATCH 04/37] update "attribute(s)" ignorance --- llvm/core.py | 78 +++++++++++++++++++++++++++++++++++--------------- llvm/passes.py | 23 +++++++++++---- 2 files changed, 72 insertions(+), 29 deletions(-) diff --git a/llvm/core.py b/llvm/core.py index 9c8501e..d413bef 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -325,11 +325,17 @@ class VisibilityEnum(Enum): VisibilityEnum.declare() -# parameter attributes llvm::Attributes::AttrVal (see llvm/Attributes.h) +# parameter attributes +# LLVM 3.2 llvm::Attributes::AttrVal (see llvm/Attributes.h) +# LLVM 3.3 llvm::Attribute::AttrKind (see llvm/Attributes.h) class AttrEnum(Enum): prefix = 'ATTR_' - AttrVal = api.llvm.Attributes.AttrVal + if llvm.version >= (3, 3): + AttrVal = api.llvm.Attribute.AttrKind + else: + AttrVal = api.llvm.Attributes.AttrVal + ATTR_NONE = AttrVal.None_ ATTR_ZEXT = AttrVal.ZExt ATTR_SEXT = AttrVal.SExt @@ -1436,29 +1442,55 @@ class Argument(Value): _valid_attrs = frozenset([ATTR_BY_VAL, ATTR_NEST, ATTR_NO_ALIAS, ATTR_NO_CAPTURE, ATTR_STRUCT_RET]) - def add_attribute(self, attr): - context = api.llvm.getGlobalContext() - attrbldr = api.llvm.AttrBuilder.new() - attrbldr.addAttribute(attr) - attrs = api.llvm.Attributes.get(context, attrbldr) - self._ptr.addAttr(attrs) - if attr not in self: - raise ValueError("Attribute %s is not valid for arg %s" % - (attr, self)) + if llvm.version >= (3, 3): + def add_attribute(self, attr): + context = api.llvm.getGlobalContext() + attrbldr = api.llvm.AttrBuilder.new() + attrbldr.addAttribute(attr) + attrs = api.llvm.AttributeSet.get(context, 0, attrbldr) + self._ptr.addAttr(attrs) + + if attr not in self: + raise ValueError("Attribute %r is not valid for arg %s" % + (attr, self)) - def remove_attribute(self, attr): - context = api.llvm.getGlobalContext() - attrbldr = api.llvm.AttrBuilder.new() - attrbldr.addAttribute(attr) - attrs = api.llvm.Attributes.get(context, attrbldr) - self._ptr.removeAttr(attrs) + def remove_attribute(self, attr): + context = api.llvm.getGlobalContext() + attrbldr = api.llvm.AttrBuilder.new() + attrbldr.addAttribute(attr) + attrs = api.llvm.AttributeSet.get(context, 0, attrbldr) + self._ptr.removeAttr(attrs) - def _set_alignment(self, align): - context = api.llvm.getGlobalContext() - attrbldr = api.llvm.AttrBuilder.new() - attrbldr.addAlignmentAttr(align) - attrs = api.llvm.Attributes.get(context, attrbldr) - self._ptr.addAttr(attrs) + def _set_alignment(self, align): + context = api.llvm.getGlobalContext() + attrbldr = api.llvm.AttrBuilder.new() + attrbldr.addAlignmentAttr(align) + attrs = api.llvm.AttributeSet.get(context, 0, attrbldr) + self._ptr.addAttr(attrs) + else: + def add_attribute(self, attr): + context = api.llvm.getGlobalContext() + attrbldr = api.llvm.AttrBuilder.new() + attrbldr.addAttribute(attr) + attrs = api.llvm.Attributes.get(context, attrbldr) + self._ptr.addAttr(attrs) + if attr not in self: + raise ValueError("Attribute %r is not valid for arg %s" % + (attr, self)) + + def remove_attribute(self, attr): + context = api.llvm.getGlobalContext() + attrbldr = api.llvm.AttrBuilder.new() + attrbldr.addAttribute(attr) + attrs = api.llvm.Attributes.get(context, attrbldr) + self._ptr.removeAttr(attrs) + + def _set_alignment(self, align): + context = api.llvm.getGlobalContext() + attrbldr = api.llvm.AttrBuilder.new() + attrbldr.addAlignmentAttr(align) + attrs = api.llvm.Attributes.get(context, attrbldr) + self._ptr.addAttr(attrs) def _get_alignment(self): return self._ptr.getParamAlignment() diff --git a/llvm/passes.py b/llvm/passes.py index 068a7a3..b13fa84 100644 --- a/llvm/passes.py +++ b/llvm/passes.py @@ -70,13 +70,24 @@ class PassManagerBuilder(llvm.Wrapper): def size_level(self, sizelevel): self._ptr.SizeLevel = sizelevel - @property - def vectorize(self): - return self._ptr.Vectorize + if llvm.version >= (3, 3): + @property + def bbvectorize(self): + return self._ptr.BBVectorize - @vectorize.setter - def vectorize(self, enable): - self._ptr.Vectorize = enable + @bbvectorize.setter + def bbvectorize(self, enable): + self._ptr.BBVectorize = enable + + vectorize = bbvectorize + else: + @property + def vectorize(self): + return self._ptr.Vectorize + + @vectorize.setter + def vectorize(self, enable): + self._ptr.Vectorize = enable @property From 319984f0e0a69672dc6dd315062c88bdd67987cc Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 31 Jul 2013 16:57:29 -0500 Subject: [PATCH 05/37] add MCJIT test --- llvm/core.py | 6 +++++- llvm/ee.py | 7 ++++++- llvm/test_llvmpy.py | 25 +++++++++++++++++++++++++ 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/llvm/core.py b/llvm/core.py index d413bef..99657d7 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -2454,4 +2454,8 @@ if api.llvm.InitializeNativeTargetAsmPrinter(): # should this be an optional feature? # should user trigger the initialization? raise llvm.LLVMException("No native asm printer!?") - +if api.llvm.InitializeNativeTargetAsmParser(): + # required by MCJIT? + # should this be an optional feature? + # should user trigger the initialization? + raise llvm.LLVMException("No native asm parser!?") diff --git a/llvm/ee.py b/llvm/ee.py index e87777a..583201b 100644 --- a/llvm/ee.py +++ b/llvm/ee.py @@ -152,7 +152,9 @@ class EngineBuilder(llvm.Wrapper): engine = self._ptr.create(tm._ptr) else: engine = self._ptr.create() - return ExecutionEngine(engine) + ee = ExecutionEngine(engine) + ee.finalize_object() # no effect for legacy JIT + return ee def select_target(self, *args): '''get the corresponding target machine @@ -218,6 +220,9 @@ class ExecutionEngine(llvm.Wrapper): def remove_module(self, module): return self._ptr.removeModule(module._ptr) + def finalize_object(self): + return self._ptr.finalizeObject() + @property def target_data(self): ptr = self._ptr.getDataLayout() diff --git a/llvm/test_llvmpy.py b/llvm/test_llvmpy.py index e21a825..8d38ed0 100644 --- a/llvm/test_llvmpy.py +++ b/llvm/test_llvmpy.py @@ -1353,6 +1353,31 @@ class TestCmp(TestCase): tests.append(TestCmp) +# --------------------------------------------------------------------------- + +class TestMCJIT(TestCase): + def test_mcjit(self): + m = Module.new('oidfjs') + fnty = Type.function(Type.int(), [Type.int(), Type.int()]) + func = m.add_function(fnty, 'foo') + bb = func.append_basic_block('') + bldr = Builder.new(bb) + bldr.ret(bldr.add(*func.args)) + + func.verify() + + engine = EngineBuilder.new(m).mcjit(True).create() + ptr = engine.get_pointer_to_function(func) + + from ctypes import c_int, CFUNCTYPE + callee = CFUNCTYPE(c_int, c_int, c_int)(ptr) + self.assertEqual(321 + 123, callee(321, 123)) + +if llvm.version >= (3, 3): + # MCJIT broken in 3.2 + # The test will segfault in OSX? + tests.append(TestMCJIT) + # --------------------------------------------------------------------------- def run(verbosity=1): From c0e9dedc9048e7849b767c193542ef507d21f8c0 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 31 Jul 2013 17:50:30 -0500 Subject: [PATCH 06/37] add binding to dynamiclibrary namespace for multimodule linking --- llvm/ee.py | 14 ++++++++++++++ llvm/test_llvmpy.py | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/llvm/ee.py b/llvm/ee.py index 583201b..fe21ea2 100644 --- a/llvm/ee.py +++ b/llvm/ee.py @@ -195,6 +195,9 @@ class ExecutionEngine(llvm.Wrapper): ptr = self._ptr.runFunction(fn._ptr, list(map(lambda x: x._ptr, args))) return GenericValue(ptr) + def get_pointer_to_named_function(self, name, abort=True): + return self._ptr.getPointerToNamedFunction(name, abort) + def get_pointer_to_function(self, fn): return self._ptr.getPointerToFunction(fn._ptr) @@ -371,3 +374,14 @@ class TargetMachine(llvm.Wrapper): def feature_string(self): return self._ptr.getTargetFeatureString() + + +#===----------------------------------------------------------------------=== +# Dynamic Library +#===----------------------------------------------------------------------=== + +def dylib_add_symbol(name, ptr): + api.llvm.sys.DynamicLibrary.AddSymbol(name, ptr) + +def dylib_address_of_symbol(name): + return api.llvm.sys.DynamicLibrary.SearchForAddressOfSymbol(name) diff --git a/llvm/test_llvmpy.py b/llvm/test_llvmpy.py index 8d38ed0..19c402c 100644 --- a/llvm/test_llvmpy.py +++ b/llvm/test_llvmpy.py @@ -1373,6 +1373,43 @@ class TestMCJIT(TestCase): callee = CFUNCTYPE(c_int, c_int, c_int)(ptr) self.assertEqual(321 + 123, callee(321, 123)) + def test_multi_module_linking(self): + # generate external library module + m = Module.new('external-library-module') + fnty = Type.function(Type.int(), [Type.int(), Type.int()]) + libfname = 'myadd' + func = m.add_function(fnty, libfname) + bb = func.append_basic_block('') + bldr = Builder.new(bb) + bldr.ret(bldr.add(*func.args)) + func.verify() + + # JIT the lib module and bind dynamic symbol + libengine = EngineBuilder.new(m).mcjit(True).create() + myadd_ptr = libengine.get_pointer_to_function(func) + le.dylib_add_symbol(libfname, myadd_ptr) + + # reference external library + m = Module.new('user') + fnty = Type.function(Type.int(), [Type.int(), Type.int()]) + func = m.add_function(fnty, 'foo') + bb = func.append_basic_block('') + bldr = Builder.new(bb) + extadd = m.get_or_insert_function(fnty, name=libfname) + bldr.ret(bldr.call(extadd, func.args)) + func.verify() + + # JIT the user module + engine = EngineBuilder.new(m).mcjit(True).create() + ptr = engine.get_pointer_to_function(func) + self.assertEqual(myadd_ptr, + engine.get_pointer_to_named_function(libfname)) + + from ctypes import c_int, CFUNCTYPE + callee = CFUNCTYPE(c_int, c_int, c_int)(ptr) + self.assertEqual(321 + 123, callee(321, 123)) + + if llvm.version >= (3, 3): # MCJIT broken in 3.2 # The test will segfault in OSX? From c4db61c7f53b513645761dadfdc19a105aa410e0 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Thu, 1 Aug 2013 13:02:45 -0500 Subject: [PATCH 07/37] add test for basic arith operators and problems for div and mod on 32bit platforms --- llvm/test_llvmpy.py | 62 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/llvm/test_llvmpy.py b/llvm/test_llvmpy.py index 19c402c..e51c406 100644 --- a/llvm/test_llvmpy.py +++ b/llvm/test_llvmpy.py @@ -1415,6 +1415,68 @@ if llvm.version >= (3, 3): # The test will segfault in OSX? tests.append(TestMCJIT) + +class TestArith(TestCase): + ''' + Test basic arithmetic support with LLVM old-JIT + ''' + def func_template(self, ty, op): + m = Module.new('dofjaa') + fnty = Type.function(ty, [ty, ty]) + fn = m.add_function(fnty, 'foo') + bldr = Builder.new(fn.append_basic_block('')) + bldr.ret(getattr(bldr, op)(*fn.args)) + + engine = EngineBuilder.new(m).mcjit(True).create() + ptr = engine.get_pointer_to_function(fn) + + from ctypes import c_uint32, c_uint64, c_float, c_double, CFUNCTYPE + + maptypes = { + Type.int(32): c_uint32, + Type.int(64): c_uint64, + Type.float(): c_float, + Type.double(): c_double, + } + cty = maptypes[ty] + prototype = CFUNCTYPE(*[cty] * 3) + callee = prototype(ptr) + callee(12, 23) + + def template(self, iop, fop): + inttys = [Type.int(32), Type.int(64)] + flttys = [Type.float(), Type.double()] + + for ty in inttys: + self.func_template(ty, iop) + for ty in flttys: + self.func_template(ty, fop) + + def test_add(self): + self.template('add', 'fadd') + + def test_sub(self): + self.template('sub', 'fsub') + + def test_mul(self): + self.template('mul', 'fmul') + + def test_div(self): + if BITS == 32: + print('skipped test for div') + print('known failure due to unresolved external symbol __udivdi3') + return + self.template('udiv', 'fdiv') + + def test_rem(self): + if BITS == 32: + print('skipped test for rem') + print('known failure due to unresolved external symbol __umoddi3') + return + self.template('urem', 'frem') + +tests.append(TestArith) + # --------------------------------------------------------------------------- def run(verbosity=1): From 2a25b1c2b3819bb11fe330dfd64674c06d5db00d Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Thu, 1 Aug 2013 11:50:36 -0500 Subject: [PATCH 08/37] fix avx detection for py3 --- llvm/workaround/avx_support.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/llvm/workaround/avx_support.py b/llvm/workaround/avx_support.py index 81cb936..0b1c2da 100644 --- a/llvm/workaround/avx_support.py +++ b/llvm/workaround/avx_support.py @@ -50,8 +50,7 @@ def detect_osx_like(): stdout=subprocess.PIPE) except OSError: return False - - features = info.stdout.read() + features = info.stdout.read().decode('UTF8') features = features.split() return 'AVX1.0' in features and 'OSXSAVE' in features and 'XSAVE' in features From 0421ad8456fe86facbd6d975cf47ea05845f2671 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Fri, 2 Aug 2013 12:12:35 -0500 Subject: [PATCH 09/37] add dev docs --- llvmpy/README | 5 -- llvmpy/README.md | 151 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 151 insertions(+), 5 deletions(-) delete mode 100644 llvmpy/README create mode 100644 llvmpy/README.md diff --git a/llvmpy/README b/llvmpy/README deleted file mode 100644 index 2bfabcd..0000000 --- a/llvmpy/README +++ /dev/null @@ -1,5 +0,0 @@ -# README - -This is a reimplementation of the LLVM binding, aiming to provide a more familiar interface to the C++ API whenever possible. - -The implementation uses a custom DSL in python to describe the interface (under binding directory). The DSL serves as input to *gen.py* for generation of the .cpp and .py files for the actual binding. diff --git a/llvmpy/README.md b/llvmpy/README.md new file mode 100644 index 0000000..4e444f8 --- /dev/null +++ b/llvmpy/README.md @@ -0,0 +1,151 @@ +# README + +This is a reimplementation of the LLVM binding, aiming to provide a more +familiar interface to the C++ API whenever possible. + +The implementation uses a custom DSL in python to describe the interface. +The DSL serves as input to *gen/gen.py* for generation of the .cpp and .py files +for the actual binding. + +# How to Add New Class + +Let's use the `llvm::Module` as an example because it should be one of the most +familiar class in LLVM. + +Reference code in https://github.com/llvmpy/llvmpy/blob/master/llvmpy/src/Module.py +and see LLVM documentation at http://llvm.org/docs/doxygen/html/classllvm_1_1Module.html + +1) Import binding helpers + +```python +from binding import * +# Yes, it is bad practice to import star. +# I will fix it one day. +``` + +2) Import LLVM namespace + +```python +from .namespace import llvm +``` + +3) Declare the class + +```python +Module = llvm.Class() +``` + +4) Import all the dependencies for the definition + +5) Define the class + +```python +@Module +class Module: + ... +``` + +## Inside the definition... + +5.1) Use the ``_include_`` attribute to add include files. + +5.2) Use ``Enum`` to create an enumerator type. + +5.3) Make constructor + +Not every class needs to have a binding for the constructor. +Only add things that will be used. + +```python +new = Constructor(cast(str, StringRef), ref(LLVMContext)) +``` + +The constructor must be named as "new". + +The args to ``Constructor`` are parameters of the signature. +The first parameter means cast Python string to a StringRef. +The second parameter means pass LLVMContext object as a value reference. + +5.4) Make destructor + +Not every class needs to have a binding for the destructor. +Only add things that will be used. +If it is always owned by another object, it usually does not need to have one. + +```python +delete = Destructor() +``` + +The destructor must be named as "delete". + +5.5) Add Simple Methods + +```python +getFunction = Method(ptr(Function), cast(str, StringRef)) +``` + +The first arg is the return type: a ponter to Function. +The rest of the args are for the parameters. + +Note: ``cast(fromtype, totype)`` can be used as return-type as well. +In that case, the ``fromtype`` will usually refer to a LLVM object +and the ``totype`` will refer to the Python object. + +5.6) Add custom methods defined in C++ + +The ``list_functions`` is created as a ``CustomMethod``. + +```python +list_functions = CustomMethod('Module_list_functions', PyObjectPtr) +``` + +The first arg is the name that appears in C++. +The second argument is the return-type. +The rest of the arguments are parameters. + +The definition of ``Module_list_functions`` is located in +"include/llvm_binding/extra.h". + +5.7) Add custom python method + +One can also add custom methods in Python, e.g. ``__str__``. + +```python +@CustomPythonMethod +def __str__(self): + from llvmpy import extra + os = extra.make_raw_ostream_for_printing() + self.print_(os, None) + return os.str() +``` + +The body of ``__str__`` is directly copied to the Python output file. +Thus, it can't reference to anything in current file scope. + +# Static Methods + +``StaticMethod`` https://github.com/llvmpy/llvmpy/blob/master/llvmpy/src/PassRegistry.py + +``CustomStaticMethod`` https://github.com/llvmpy/llvmpy/blob/master/llvmpy/src/Support/TargetRegistry.py + + +# Namespace + +``Namespace`` https://github.com/llvmpy/llvmpy/blob/master/llvmpy/src/Support/CodeGen.py + +# Functions + +``Function`` https://github.com/llvmpy/llvmpy/blob/master/llvmpy/src/Assembly/Parser.py + +``CustomFunction`` https://github.com/llvmpy/llvmpy/blob/master/llvmpy/src/Bitcode/ReaderWriter.py + + + + + +# Other Things from the binding.py + +https://github.com/llvmpy/llvmpy/blob/master/llvmpy/gen/binding.py + +The list of C++ types: https://github.com/llvmpy/llvmpy/blob/master/llvmpy/gen/binding.py#L218 + From 84a95945ea7ec06ff361fc3aa62ca623bb00f516 Mon Sep 17 00:00:00 2001 From: Ilan Schnell Date: Tue, 6 Aug 2013 14:17:14 -0500 Subject: [PATCH 10/37] update marker header file --- llvm-config-win32.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm-config-win32.py b/llvm-config-win32.py index e191290..8c268cb 100644 --- a/llvm-config-win32.py +++ b/llvm-config-win32.py @@ -108,7 +108,7 @@ def main(): elif option == '--includedir': incdir = join(find_llvm_prefix(), 'include') - ensure_file(join(incdir, 'llvm' , 'BasicBlock.h')) + ensure_file(join(incdir, 'llvm' , 'Linker.h')) print(incdir) elif option == '--libdir': From c20c4d776f9b44475cae61b7da8922895dd09817 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Mon, 12 Aug 2013 14:42:49 -0500 Subject: [PATCH 11/37] fix exception handling for TargetMachine --- llvm/ee.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/ee.py b/llvm/ee.py index fe21ea2..832f422 100644 --- a/llvm/ee.py +++ b/llvm/ee.py @@ -282,7 +282,7 @@ class TargetMachine(llvm.Wrapper): with contextlib.closing(BytesIO()) as error: target = api.llvm.TargetRegistry.lookupTarget(triple, error) if not target: - raise llvm.LLVMException(error) + raise llvm.LLVMException(error.getvalue()) if not target.hasTargetMachine(): raise llvm.LLVMException(target, "No target machine.") target_options = api.llvm.TargetOptions.new() From b4d943a6717ff2431c4df6578d6afccbed3f9f62 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Mon, 12 Aug 2013 14:43:23 -0500 Subject: [PATCH 12/37] add autoselect ELF generation for MCJIT --- llvm/ee.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/llvm/ee.py b/llvm/ee.py index 832f422..4090a0f 100644 --- a/llvm/ee.py +++ b/llvm/ee.py @@ -30,6 +30,7 @@ "Execution Engine and related classes." +import sys from io import BytesIO import contextlib @@ -150,6 +151,12 @@ class EngineBuilder(llvm.Wrapper): ''' if tm is not None: engine = self._ptr.create(tm._ptr) + elif (sys.prefix.startswith('win32') and + getattr(self, '_use_mcjit', False)): + # force ELF generation on MCJIT on win32 + triple = get_default_triple() + tm = TargetMachine.new('%s-elf' % triple) + engine = self._ptr.create(tm) else: engine = self._ptr.create() ee = ExecutionEngine(engine) @@ -173,6 +180,7 @@ class EngineBuilder(llvm.Wrapper): '''Enable/disable MCJIT ''' self._ptr.setUseMCJIT(enable) + self._use_mcjit = True return self #===----------------------------------------------------------------------=== From eb4fc653f2ca3e8d9c4f31817b791070a75886d3 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Mon, 12 Aug 2013 14:52:16 -0500 Subject: [PATCH 13/37] ensure MCJIT ELF autoselect works --- llvm/ee.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/llvm/ee.py b/llvm/ee.py index 4090a0f..b91c4cb 100644 --- a/llvm/ee.py +++ b/llvm/ee.py @@ -151,12 +151,12 @@ class EngineBuilder(llvm.Wrapper): ''' if tm is not None: engine = self._ptr.create(tm._ptr) - elif (sys.prefix.startswith('win32') and + elif (sys.platform.startswith('win32') and getattr(self, '_use_mcjit', False)): # force ELF generation on MCJIT on win32 triple = get_default_triple() tm = TargetMachine.new('%s-elf' % triple) - engine = self._ptr.create(tm) + engine = self._ptr.create(tm._ptr) else: engine = self._ptr.create() ee = ExecutionEngine(engine) From 1e9d37a64e489efdd9c06a2b365e7b6063336652 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Mon, 12 Aug 2013 15:59:17 -0500 Subject: [PATCH 14/37] add no-signed-wrap and no-unsigned-wrap flags to IRBuilder --- llvm/core.py | 20 ++++++++++++-------- llvm/test_llvmpy.py | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 8 deletions(-) diff --git a/llvm/core.py b/llvm/core.py index 99657d7..0fbd5ab 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -2124,20 +2124,23 @@ class Builder(llvm.Wrapper): # arithmethic, bitwise and logical - def add(self, lhs, rhs, name=""): - return _make_value(self._ptr.CreateAdd(lhs._ptr, rhs._ptr, name)) + def add(self, lhs, rhs, name="", nuw=False, nsw=False): + return _make_value(self._ptr.CreateAdd(lhs._ptr, rhs._ptr, name, + nuw, nsw)) def fadd(self, lhs, rhs, name=""): return _make_value(self._ptr.CreateFAdd(lhs._ptr, rhs._ptr, name)) - def sub(self, lhs, rhs, name=""): - return _make_value(self._ptr.CreateSub(lhs._ptr, rhs._ptr, name)) + def sub(self, lhs, rhs, name="", nuw=False, nsw=False): + return _make_value(self._ptr.CreateSub(lhs._ptr, rhs._ptr, name, + nuw, nsw)) def fsub(self, lhs, rhs, name=""): return _make_value(self._ptr.CreateFSub(lhs._ptr, rhs._ptr, name)) - def mul(self, lhs, rhs, name=""): - return _make_value(self._ptr.CreateMul(lhs._ptr, rhs._ptr, name)) + def mul(self, lhs, rhs, name="", nuw=False, nsw=False): + return _make_value(self._ptr.CreateMul(lhs._ptr, rhs._ptr, name, + nuw, nsw)) def fmul(self, lhs, rhs, name=""): return _make_value(self._ptr.CreateFMul(lhs._ptr, rhs._ptr, name)) @@ -2160,8 +2163,9 @@ class Builder(llvm.Wrapper): def frem(self, lhs, rhs, name=""): return _make_value(self._ptr.CreateFRem(lhs._ptr, rhs._ptr, name)) - def shl(self, lhs, rhs, name=""): - return _make_value(self._ptr.CreateShl(lhs._ptr, rhs._ptr, name)) + def shl(self, lhs, rhs, name="", nuw=False, nsw=False): + return _make_value(self._ptr.CreateShl(lhs._ptr, rhs._ptr, name, + nuw, nsw)) def lshr(self, lhs, rhs, name=""): return _make_value(self._ptr.CreateLShr(lhs._ptr, rhs._ptr, name)) diff --git a/llvm/test_llvmpy.py b/llvm/test_llvmpy.py index e51c406..9c3e695 100644 --- a/llvm/test_llvmpy.py +++ b/llvm/test_llvmpy.py @@ -1477,6 +1477,40 @@ class TestArith(TestCase): tests.append(TestArith) +class TestNUWNSW(TestCase): + def make_module(self): + mod = Module.new('asdfa') + fnty = Type.function(Type.void(), [Type.int()] * 2) + func = mod.add_function(fnty, 'foo') + bldr = Builder.new(func.append_basic_block('')) + return mod, func, bldr + + def has_nsw(self, inst, op): + self.assertTrue(('%s nsw' % op) in str(inst), "NSW flag does not work") + + def has_nuw(self, inst, op): + self.assertTrue(('%s nuw' % op) in str(inst), "NUW flag does not work") + + def _test_template(self, opf, opname): + mod, func, bldr = self.make_module() + a, b = func.args + self.has_nsw(opf(bldr, a, b, nsw=True), opname) + self.has_nuw(opf(bldr, a, b, nuw=True), opname) + + def test_add_nuw_nsw(self): + self._test_template(Builder.add, 'add') + + def test_sub_nuw_nsw(self): + self._test_template(Builder.sub, 'sub') + + def test_mul_nuw_nsw(self): + self._test_template(Builder.mul, 'mul') + + def test_shl_nuw_nsw(self): + self._test_template(Builder.shl, 'shl') + +tests.append(TestNUWNSW) + # --------------------------------------------------------------------------- def run(verbosity=1): From cfe5e9ea92f617b5a3e02b70aff5f26963f03393 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Mon, 12 Aug 2013 16:11:24 -0500 Subject: [PATCH 15/37] add exact flag to IRBuilder --- llvm/core.py | 20 ++++++++++++-------- llvm/test_llvmpy.py | 31 +++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 8 deletions(-) diff --git a/llvm/core.py b/llvm/core.py index 0fbd5ab..7535b0f 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -2145,11 +2145,13 @@ class Builder(llvm.Wrapper): def fmul(self, lhs, rhs, name=""): return _make_value(self._ptr.CreateFMul(lhs._ptr, rhs._ptr, name)) - def udiv(self, lhs, rhs, name=""): - return _make_value(self._ptr.CreateUDiv(lhs._ptr, rhs._ptr, name)) + def udiv(self, lhs, rhs, name="", exact=False): + return _make_value(self._ptr.CreateUDiv(lhs._ptr, rhs._ptr, name, + exact)) - def sdiv(self, lhs, rhs, name=""): - return _make_value(self._ptr.CreateSDiv(lhs._ptr, rhs._ptr, name)) + def sdiv(self, lhs, rhs, name="", exact=False): + return _make_value(self._ptr.CreateSDiv(lhs._ptr, rhs._ptr, name, + exact)) def fdiv(self, lhs, rhs, name=""): return _make_value(self._ptr.CreateFDiv(lhs._ptr, rhs._ptr, name)) @@ -2167,11 +2169,13 @@ class Builder(llvm.Wrapper): return _make_value(self._ptr.CreateShl(lhs._ptr, rhs._ptr, name, nuw, nsw)) - def lshr(self, lhs, rhs, name=""): - return _make_value(self._ptr.CreateLShr(lhs._ptr, rhs._ptr, name)) + def lshr(self, lhs, rhs, name="", exact=False): + return _make_value(self._ptr.CreateLShr(lhs._ptr, rhs._ptr, name, + exact)) - def ashr(self, lhs, rhs, name=""): - return _make_value(self._ptr.CreateAShr(lhs._ptr, rhs._ptr, name)) + def ashr(self, lhs, rhs, name="", exact=False): + return _make_value(self._ptr.CreateAShr(lhs._ptr, rhs._ptr, name, + exact)) def and_(self, lhs, rhs, name=""): return _make_value(self._ptr.CreateAnd(lhs._ptr, rhs._ptr, name)) diff --git a/llvm/test_llvmpy.py b/llvm/test_llvmpy.py index 9c3e695..250e404 100644 --- a/llvm/test_llvmpy.py +++ b/llvm/test_llvmpy.py @@ -1511,6 +1511,37 @@ class TestNUWNSW(TestCase): tests.append(TestNUWNSW) + +class TestExact(TestCase): + def make_module(self): + mod = Module.new('asdfa') + fnty = Type.function(Type.void(), [Type.int()] * 2) + func = mod.add_function(fnty, 'foo') + bldr = Builder.new(func.append_basic_block('')) + return mod, func, bldr + + def has_exact(self, inst, op): + self.assertTrue(('%s exact' % op) in str(inst), "exact flag does not work") + + def _test_template(self, opf, opname): + mod, func, bldr = self.make_module() + a, b = func.args + self.has_exact(opf(bldr, a, b, exact=True), opname) + + def test_udiv_exact(self): + self._test_template(Builder.udiv, 'udiv') + + def test_sdiv_exact(self): + self._test_template(Builder.sdiv, 'sdiv') + + def test_lshr_exact(self): + self._test_template(Builder.lshr, 'lshr') + + def test_ashr_exact(self): + self._test_template(Builder.ashr, 'ashr') + +tests.append(TestExact) + # --------------------------------------------------------------------------- def run(verbosity=1): From 1ed3c773103a09d126a645c6af9f4bb5809a4d99 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Mon, 12 Aug 2013 16:16:38 -0500 Subject: [PATCH 16/37] add neg nuw nsw --- llvm/core.py | 4 ++-- llvm/test_llvmpy.py | 7 +++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/llvm/core.py b/llvm/core.py index 7535b0f..945dd86 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -2186,8 +2186,8 @@ class Builder(llvm.Wrapper): def xor(self, lhs, rhs, name=""): return _make_value(self._ptr.CreateXor(lhs._ptr, rhs._ptr, name)) - def neg(self, val, name=""): - return _make_value(self._ptr.CreateNeg(val._ptr, name)) + def neg(self, val, name="", nuw=False, nsw=False): + return _make_value(self._ptr.CreateNeg(val._ptr, name, nuw, nsw)) def not_(self, val, name=""): return _make_value(self._ptr.CreateNot(val._ptr, name)) diff --git a/llvm/test_llvmpy.py b/llvm/test_llvmpy.py index 250e404..2a5c1f5 100644 --- a/llvm/test_llvmpy.py +++ b/llvm/test_llvmpy.py @@ -1509,6 +1509,13 @@ class TestNUWNSW(TestCase): def test_shl_nuw_nsw(self): self._test_template(Builder.shl, 'shl') + def test_neg_nuw_nsw(self): + mod, func, bldr = self.make_module() + a, b = func.args + self.has_nsw(bldr.neg(a, nsw=True), 'sub') + self.has_nuw(bldr.neg(a, nuw=True), 'sub') + + tests.append(TestNUWNSW) From d060c10096ea97d091a8cced5610a5bc887971a9 Mon Sep 17 00:00:00 2001 From: majidaldo Date: Tue, 13 Aug 2013 14:42:54 -0500 Subject: [PATCH 17/37] add conda build script --- buildscripts/condarecipe/bld.bat | 6 ++++++ buildscripts/condarecipe/build.sh | 13 +++++++++++++ buildscripts/condarecipe/meta.yaml | 27 +++++++++++++++++++++++++++ buildscripts/condarecipe/run_test.py | 19 +++++++++++++++++++ 4 files changed, 65 insertions(+) create mode 100644 buildscripts/condarecipe/bld.bat create mode 100644 buildscripts/condarecipe/build.sh create mode 100644 buildscripts/condarecipe/meta.yaml create mode 100644 buildscripts/condarecipe/run_test.py diff --git a/buildscripts/condarecipe/bld.bat b/buildscripts/condarecipe/bld.bat new file mode 100644 index 0000000..45ef910 --- /dev/null +++ b/buildscripts/condarecipe/bld.bat @@ -0,0 +1,6 @@ +set LLVMPY_DYNLINK=0 +set INCLUDE=%LIBRARY_INC% +set LIBPATH=%LIBRARY_LIB% +set LIB=%LIBRARY_LIB% +python setup.py install +if errorlevel 1 exit 1 diff --git a/buildscripts/condarecipe/build.sh b/buildscripts/condarecipe/build.sh new file mode 100644 index 0000000..5c98fde --- /dev/null +++ b/buildscripts/condarecipe/build.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +if [[ (`uname` == Linux) && (`uname -m` != armv6l) ]] +then + export CC=gcc + #gcc44 + export CXX=g++ + #g++44 +fi + +export LLVMPY_DYNLINK=$DISTRO_BUILD + +$PYTHON setup.py install diff --git a/buildscripts/condarecipe/meta.yaml b/buildscripts/condarecipe/meta.yaml new file mode 100644 index 0000000..05007f3 --- /dev/null +++ b/buildscripts/condarecipe/meta.yaml @@ -0,0 +1,27 @@ +package: + name: llvmpy + version: master + +source: + git_url: git@github.com:llvmpy/llvmpy.git +# git_tag: 0.12.0 + +requirements: + build: + - llvm + - python + run: + - llvm [unix] + - python + +test: + imports: + - llvm + - llvmpy + - llvmpy._api + - llvmpy._capsule + - llpython + - llvm_array + - llvm_cbuilder + + diff --git a/buildscripts/condarecipe/run_test.py b/buildscripts/condarecipe/run_test.py new file mode 100644 index 0000000..281a599 --- /dev/null +++ b/buildscripts/condarecipe/run_test.py @@ -0,0 +1,19 @@ +import sys +import platform +import llvm + +from llvm.core import Module +from llvm.ee import EngineBuilder +m = Module.new('fjoidajfa') +eb = EngineBuilder.new(m) +target = eb.select_target() + +print('target.triple=%r' % target.triple) +if sys.platform == 'darwin': + s = {'64bit': 'x86_64', '32bit': 'x86'}[platform.architecture()[0]] + assert target.triple.startswith(s + '-apple-darwin') + +assert llvm.test(verbosity=2) == 0 + +print('llvm.__version__: %s' % llvm.__version__) +#assert llvm.__version__ == '0.12.0' From bf0253c9f9d96bb922f4c88ecffc85d01f0ecbb1 Mon Sep 17 00:00:00 2001 From: majidaldo Date: Tue, 13 Aug 2013 14:55:13 -0500 Subject: [PATCH 18/37] add chrpath --- buildscripts/condarecipe/meta.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/buildscripts/condarecipe/meta.yaml b/buildscripts/condarecipe/meta.yaml index 05007f3..15d9f8a 100644 --- a/buildscripts/condarecipe/meta.yaml +++ b/buildscripts/condarecipe/meta.yaml @@ -10,6 +10,7 @@ requirements: build: - llvm - python + - chrpath run: - llvm [unix] - python From 3a289ccace2efe5d3f898f59441768c5865445ff Mon Sep 17 00:00:00 2001 From: majidaldo Date: Tue, 13 Aug 2013 14:55:42 -0500 Subject: [PATCH 19/37] add percent python --- buildscripts/condarecipe/bld.bat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildscripts/condarecipe/bld.bat b/buildscripts/condarecipe/bld.bat index 45ef910..e9177c5 100644 --- a/buildscripts/condarecipe/bld.bat +++ b/buildscripts/condarecipe/bld.bat @@ -2,5 +2,5 @@ set LLVMPY_DYNLINK=0 set INCLUDE=%LIBRARY_INC% set LIBPATH=%LIBRARY_LIB% set LIB=%LIBRARY_LIB% -python setup.py install +%PYTHON% setup.py install if errorlevel 1 exit 1 From 1be8b07cedfff7a73aaad59e4b076a75dde8f03d Mon Sep 17 00:00:00 2001 From: majidaldo Date: Tue, 13 Aug 2013 14:59:33 -0500 Subject: [PATCH 20/37] charpath just for linux --- buildscripts/condarecipe/meta.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildscripts/condarecipe/meta.yaml b/buildscripts/condarecipe/meta.yaml index 15d9f8a..b079986 100644 --- a/buildscripts/condarecipe/meta.yaml +++ b/buildscripts/condarecipe/meta.yaml @@ -10,7 +10,7 @@ requirements: build: - llvm - python - - chrpath + - chrpath [linux] run: - llvm [unix] - python From d10b182479b58a25bb45a6bd5c8d1a6aa8ee468c Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Tue, 13 Aug 2013 15:27:49 -0500 Subject: [PATCH 21/37] dislabe MCJIT tests for LLVM3.2 --- llvm/test_llvmpy.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/llvm/test_llvmpy.py b/llvm/test_llvmpy.py index 2a5c1f5..f8d6adb 100644 --- a/llvm/test_llvmpy.py +++ b/llvm/test_llvmpy.py @@ -1418,7 +1418,7 @@ if llvm.version >= (3, 3): class TestArith(TestCase): ''' - Test basic arithmetic support with LLVM old-JIT + Test basic arithmetic support with LLVM MCJIT ''' def func_template(self, ty, op): m = Module.new('dofjaa') @@ -1475,7 +1475,9 @@ class TestArith(TestCase): return self.template('urem', 'frem') -tests.append(TestArith) +if llvm.version >= (3, 3): + # MCJIT is broken in 3.2 + tests.append(TestArith) class TestNUWNSW(TestCase): def make_module(self): From 07c64779d8e3a86d0ac64139bf0bafd26b629e1e Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Tue, 13 Aug 2013 18:38:41 -0500 Subject: [PATCH 22/37] begin low-level runtime implementation --- llrtc/Makefile | 21 ++++++++++ llrtc/README.md | 25 +++++++++++ llrtc/common.mk | 26 ++++++++++++ llrtc/lib/Makefile | 44 +++++++++++++++++++ llrtc/lib/test_udivmod64.c | 22 ++++++++++ llrtc/lib/test_udivmod64.py | 53 +++++++++++++++++++++++ llrtc/lib/udivmod64.c | 84 +++++++++++++++++++++++++++++++++++++ llrtc/lib/udivmod64.h | 11 +++++ llrtc/tools/striptriple.py | 15 +++++++ 9 files changed, 301 insertions(+) create mode 100644 llrtc/Makefile create mode 100644 llrtc/README.md create mode 100644 llrtc/common.mk create mode 100644 llrtc/lib/Makefile create mode 100644 llrtc/lib/test_udivmod64.c create mode 100644 llrtc/lib/test_udivmod64.py create mode 100644 llrtc/lib/udivmod64.c create mode 100644 llrtc/lib/udivmod64.h create mode 100644 llrtc/tools/striptriple.py diff --git a/llrtc/Makefile b/llrtc/Makefile new file mode 100644 index 0000000..c271d0e --- /dev/null +++ b/llrtc/Makefile @@ -0,0 +1,21 @@ +DIRECTORIES = divmod + +all: + for mydir in $(DIRECTORIES); do \ + make -C $$mydir; \ + done + +test: + for mydir in $(DIRECTORIES); do \ + make -C $$mydir test; \ + done + +clean-test: + for mydir in $(DIRECTORIES); do \ + make -C $$mydir clean-test; \ + done + +clean: + for mydir in $(DIRECTORIES); do \ + make -C $$mydir clean; \ + done \ No newline at end of file diff --git a/llrtc/README.md b/llrtc/README.md new file mode 100644 index 0000000..539d9c3 --- /dev/null +++ b/llrtc/README.md @@ -0,0 +1,25 @@ +# LLRT: Low Level Runtime + +## Why? + +The same reason for LLVM compiler-rt. LLVM generates libgcc symbols, such as +__divdi3 for 64-bit division on 32-bit platform. They are not also available. +We need to ship compiler-rt but it is not Windows ready. +This subproject aims to provide a small portable subset of compiler-rt. +Start small and add only the things we really needed. +Performance is not crucial but should not be terrible. +Functionality and usefullness should be more important than performance. + +## Developer Instructions + +LLRT implements some functionalities in compiler-rt in ANSI C. +The C files are compiled using clang to produce LLVM IR which are shipped. +The IR files are committed in the repository. +So, remember to build the IR files commit them after modifying the C files. + +## Build Requirement + +- Make +- Clang +- Python + diff --git a/llrtc/common.mk b/llrtc/common.mk new file mode 100644 index 0000000..3de9c12 --- /dev/null +++ b/llrtc/common.mk @@ -0,0 +1,26 @@ +CLANG = clang +CF = -Wall -ansi +OUTDIR = .. + +all: ir + +$(OUTPUT).c: $(OUTPUT).h + +$(OUTPUT): test.c $(OUTPUT).c + $(CLANG) $(CF) -ftrapv -o $@ $+ + +test: $(OUTPUT) + python test.py + +ir: + CLANG -m32 $(CF) -O0 -emit-llvm -S $(OUTPUT).c -o $(OUTDIR)/x86/$(OUTPUT).ll + CLANG -m64 $(CF) -O0 -emit-llvm -S $(OUTPUT).c -o $(OUTDIR)/x86_64/$(OUTPUT).ll + python ../tools/striptriple.py $(OUTDIR)/x86/$(OUTPUT).ll + python ../tools/striptriple.py $(OUTDIR)/x86_64/$(OUTPUT).ll + +clean-test: + rm -f $(OUTPUT) + +clean: clean-test + rm -f $(OUTDIR)/x86/$(OUTPUT).ll + rm -f $(OUTDIR)/x86_64/$(OUTPUT).ll diff --git a/llrtc/lib/Makefile b/llrtc/lib/Makefile new file mode 100644 index 0000000..1bb325f --- /dev/null +++ b/llrtc/lib/Makefile @@ -0,0 +1,44 @@ +OUTPUT = llrt +SOURCES = udivmod64.c + +CLANG = clang +CF = -Wall -ansi +CF_TEST = $(CF) -ftrapv +CF_BUILD = $(CF) -O0 -emit-llvm +OUTDIR = .. + +all: ir + +ir: $(SOURCES) + $(CLANG) -m32 $(CF_BUILD) -S -o $(OUTDIR)/$(OUTPUT)_x86.ll -c $(SOURCES) + python ../tools/striptriple.py $(OUTDIR)/$(OUTPUT)_x86.ll + $(CLANG) -m64 $(CF_BUILD) -S -o $(OUTDIR)/$(OUTPUT)_x86_64.ll -c $(SOURCES) + python ../tools/striptriple.py $(OUTDIR)/$(OUTPUT)_x86_64.ll + +lib$(OUTPUT).a: $(SOURCES) + $(CLANG) $(CF) -o $@ -c $+ + +build-test: lib$(OUTPUT).a + for src in $(SOURCES); do \ + $(CLANG) $(CF_TEST) -o test_$${src%.*} test_$$src -L. -lllrt; \ + done; + +test: build-test + for src in $(SOURCES); do \ + echo "testing $${src%.*}"; \ + python test_$${src%.*}.py > test_$${src%.*}.out; \ + done; + +clean-test: + rm -f *.out + rm -f *.a + for src in $(SOURCES); do \ + rm -f test_$${src%.*} ;\ + done; + +clean-dist: + rm $(OUTDIR)/*.ll + +clean: clean-test clean-dist + +udivmod64.c: udivmod64.h diff --git a/llrtc/lib/test_udivmod64.c b/llrtc/lib/test_udivmod64.c new file mode 100644 index 0000000..e2935c5 --- /dev/null +++ b/llrtc/lib/test_udivmod64.c @@ -0,0 +1,22 @@ +#include +#include + +extern uint64_t +udivmod64(uint64_t dividend, uint64_t divisor, uint64_t *remainder); + +int main(int argc, char * argv[]){ + uint64_t n, d, q, r; + if (argc != 3) { + printf("invalid argument: %s dividend divisor", argv[0]); + return 1; + } + sscanf(argv[1], "%llu", &n); + sscanf(argv[2], "%llu", &d); + + q = udivmod64(n, d, &r); + + printf("%llu\n", q); + printf("%llu\n", r); + + return 0; +} \ No newline at end of file diff --git a/llrtc/lib/test_udivmod64.py b/llrtc/lib/test_udivmod64.py new file mode 100644 index 0000000..487a458 --- /dev/null +++ b/llrtc/lib/test_udivmod64.py @@ -0,0 +1,53 @@ +import math +import os +import subprocess +udt = os.path.join('.', 'test_udivmod64') + +def testcase(dividend, divisor): + print 'divmod64(%d, %d)' % (dividend, divisor) + + procargs = ('%s %s %s' % (udt, dividend, divisor)).split() + result = subprocess.check_output(procargs) + gotQ, gotR = map(int, result.splitlines()) + + expectQ = dividend // divisor + expectR = dividend % divisor + + print 'Q = %d, R = %d' % (gotQ, gotR) + + if expectQ != gotQ: + raise ValueError("invalid quotient: got=%d but expect=%d" % + (gotQ, expectQ)) + if expectR != gotR: + raise ValueError("invalid remainder: got=%d but expect=%d" % + (gotR, expectR)) + print 'OK' + +def testsequence(): + subjects = [ + (0, 1), + (0, 0xffffffffffffffff), + (1, 2), + (1, 983219), + (2, 2), + (3, 2), + (1024, 2), + (2048, 512), + (21321, 512), + (9329189, 1031), + (0xffffffff, 2), + (0xffffffff, 0xffff), + (0x1ffffffff, 2), + (0x1ffffffff, 0xffff), + (0xffff, 0xffffffff), + (0xffffffffffffffff, 0xffff), + (0xffffffffffffffff, 0x7fffffffffffffff), + (0xffffffffffffffff, 0xfffffffffffffff0), + (0xffffffffffffffff, 87655678587161901), + ] + + for dvd, dvr in subjects: + testcase(dvd, dvr) + +if __name__ == '__main__': + testsequence() diff --git a/llrtc/lib/udivmod64.c b/llrtc/lib/udivmod64.c new file mode 100644 index 0000000..a028aea --- /dev/null +++ b/llrtc/lib/udivmod64.c @@ -0,0 +1,84 @@ +/* +Implements unsigned divmod using for platform missing 64-bit division and/or +modulo functions. +*/ +#include "udivmod64.h" + +/* +count left zero for 64-bit words + +*/ +static +int clz64(uint64_t x) +{ + const int total_bits = sizeof(x) * BITS_PER_BYTE; + int zc = 0; + + while (zc < total_bits && ((x >> (total_bits - zc - 1)) & 1) == 0) { + ++zc; + } + return zc; +} + +typedef struct div_state_ +{ + uint64_t tmp, dvd; +} div_state; + +/* +Left shift div_state by 1 bit +*/ +static +void div_state_lshift(div_state *state) +{ + state->tmp = (state->tmp << 1) | (state->dvd >> 63); + state->dvd = state->dvd << 1; +} + +/* +Division of unsigned 64-bit word using 64-bit addition and subtration following +the shift-restore division algorithm. +For those interested in 32-bit implementation, +mapping of 64-bit addition and subtraction to 32-bit should be trivial. + +Reference: + - IBM. The PowerPC Compiler Writer's Guide + - LLVM compiler-rt + +Assumptions: + - all operands and results are positive + - unsigned wrapped around +*/ +uint64_t udivmod64(uint64_t dividend, uint64_t divisor, uint64_t *remainder) +{ + div_state state = {0, dividend}; + uint64_t quotient = 0; + int i; + int skipahead; + + if (divisor == 0) { + return 1 / 0; /* intentionally div by zero */ + } + + /* + skipahead to reduce iteration + */ + skipahead = clz64(dividend); + + for (i = 0; i < skipahead; ++i) { + div_state_lshift(&state); + } + + /* + division loop + */ + for (i = skipahead; i < 64; ++i) { + div_state_lshift(&state); + if (state.tmp >= divisor) { + state.tmp = state.tmp - divisor; + quotient |= 1ull << (63 - i); + } + } + *remainder = state.tmp; + return quotient; +} diff --git a/llrtc/lib/udivmod64.h b/llrtc/lib/udivmod64.h new file mode 100644 index 0000000..9cbcd8c --- /dev/null +++ b/llrtc/lib/udivmod64.h @@ -0,0 +1,11 @@ +#ifndef LLRT_UDIVMOD_H_ +#define LLRT_UDIVMOD_H_ + +#include + +#define BITS_PER_BYTE 8 + +uint64_t udivmod64(uint64_t dividend, uint64_t divisor, uint64_t *remainder); + +#endif /* LLRT_UDIVMOD_H_ */ + diff --git a/llrtc/tools/striptriple.py b/llrtc/tools/striptriple.py new file mode 100644 index 0000000..a20ba34 --- /dev/null +++ b/llrtc/tools/striptriple.py @@ -0,0 +1,15 @@ +import sys +import re + +buf = [] +with open(sys.argv[1], 'r') as fin: + tripleline = re.compile('^target\s+triple\s+=\s+') + for line in fin.readlines(): + if not tripleline.match(line): + buf.append(line) + +with open(sys.argv[1], 'w') as fout: + for line in buf: + fout.write(line) + + From 7d1c4c18a0539f61d1aba1e55fdea537a8300ec5 Mon Sep 17 00:00:00 2001 From: majidaldo Date: Wed, 14 Aug 2013 14:39:10 -0500 Subject: [PATCH 23/37] high version number --- buildscripts/condarecipe/meta.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildscripts/condarecipe/meta.yaml b/buildscripts/condarecipe/meta.yaml index b079986..2b05015 100644 --- a/buildscripts/condarecipe/meta.yaml +++ b/buildscripts/condarecipe/meta.yaml @@ -1,6 +1,6 @@ package: name: llvmpy - version: master + version: 99.9.9 source: git_url: git@github.com:llvmpy/llvmpy.git From 8480d55faf0e671326b37576a05d0e1fbd7cb79b Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 14 Aug 2013 15:29:13 -0500 Subject: [PATCH 24/37] add sdivmod; improve build system; --- llrtc/Makefile | 29 ++++++------- llrtc/common.mk | 26 ------------ llrtc/lib/.gitignore | 4 ++ llrtc/lib/Makefile | 68 ++++++++++++++++++++----------- llrtc/lib/{udivmod64.h => llrt.h} | 7 ++-- llrtc/lib/sdivmod64.c | 40 ++++++++++++++++++ llrtc/lib/test_sdivmod64.c | 21 ++++++++++ llrtc/lib/test_sdivmod64.py | 56 +++++++++++++++++++++++++ llrtc/lib/test_udivmod64.c | 6 +-- llrtc/lib/test_udivmod64.py | 2 +- llrtc/lib/udivmod64.c | 4 +- 11 files changed, 190 insertions(+), 73 deletions(-) delete mode 100644 llrtc/common.mk create mode 100644 llrtc/lib/.gitignore rename llrtc/lib/{udivmod64.h => llrt.h} (50%) create mode 100644 llrtc/lib/sdivmod64.c create mode 100644 llrtc/lib/test_sdivmod64.c create mode 100644 llrtc/lib/test_sdivmod64.py diff --git a/llrtc/Makefile b/llrtc/Makefile index c271d0e..bde100e 100644 --- a/llrtc/Makefile +++ b/llrtc/Makefile @@ -1,21 +1,22 @@ -DIRECTORIES = divmod - all: - for mydir in $(DIRECTORIES); do \ - make -C $$mydir; \ - done + make -C lib + +ir: + make -C lib ir test: - for mydir in $(DIRECTORIES); do \ - make -C $$mydir test; \ - done + make -C lib test clean-test: - for mydir in $(DIRECTORIES); do \ - make -C $$mydir clean-test; \ - done + make -C lib clean-test + +clean-temp: + make -C lib clean-temp clean: - for mydir in $(DIRECTORIES); do \ - make -C $$mydir clean; \ - done \ No newline at end of file + make -C lib clean + +install: ir + make -C lib clean-test + make -C lib clean-temp + \ No newline at end of file diff --git a/llrtc/common.mk b/llrtc/common.mk deleted file mode 100644 index 3de9c12..0000000 --- a/llrtc/common.mk +++ /dev/null @@ -1,26 +0,0 @@ -CLANG = clang -CF = -Wall -ansi -OUTDIR = .. - -all: ir - -$(OUTPUT).c: $(OUTPUT).h - -$(OUTPUT): test.c $(OUTPUT).c - $(CLANG) $(CF) -ftrapv -o $@ $+ - -test: $(OUTPUT) - python test.py - -ir: - CLANG -m32 $(CF) -O0 -emit-llvm -S $(OUTPUT).c -o $(OUTDIR)/x86/$(OUTPUT).ll - CLANG -m64 $(CF) -O0 -emit-llvm -S $(OUTPUT).c -o $(OUTDIR)/x86_64/$(OUTPUT).ll - python ../tools/striptriple.py $(OUTDIR)/x86/$(OUTPUT).ll - python ../tools/striptriple.py $(OUTDIR)/x86_64/$(OUTPUT).ll - -clean-test: - rm -f $(OUTPUT) - -clean: clean-test - rm -f $(OUTDIR)/x86/$(OUTPUT).ll - rm -f $(OUTDIR)/x86_64/$(OUTPUT).ll diff --git a/llrtc/lib/.gitignore b/llrtc/lib/.gitignore new file mode 100644 index 0000000..fbcf76a --- /dev/null +++ b/llrtc/lib/.gitignore @@ -0,0 +1,4 @@ +*.o +*.run +*.out +*.ll diff --git a/llrtc/lib/Makefile b/llrtc/lib/Makefile index 1bb325f..8c9361d 100644 --- a/llrtc/lib/Makefile +++ b/llrtc/lib/Makefile @@ -1,44 +1,66 @@ OUTPUT = llrt -SOURCES = udivmod64.c +SOURCES = udivmod64.c sdivmod64.c +TESTS = test_udivmod64.c test_sdivmod64.c CLANG = clang +LLVM_LINK = llvm-link CF = -Wall -ansi CF_TEST = $(CF) -ftrapv CF_BUILD = $(CF) -O0 -emit-llvm OUTDIR = .. +STRIPPER = ../tools/striptriple.py all: ir -ir: $(SOURCES) - $(CLANG) -m32 $(CF_BUILD) -S -o $(OUTDIR)/$(OUTPUT)_x86.ll -c $(SOURCES) - python ../tools/striptriple.py $(OUTDIR)/$(OUTPUT)_x86.ll - $(CLANG) -m64 $(CF_BUILD) -S -o $(OUTDIR)/$(OUTPUT)_x86_64.ll -c $(SOURCES) - python ../tools/striptriple.py $(OUTDIR)/$(OUTPUT)_x86_64.ll +ir: $(OUTDIR)/$(OUTPUT)_x86.ll $(OUTDIR)/$(OUTPUT)_x86_64.ll -lib$(OUTPUT).a: $(SOURCES) - $(CLANG) $(CF) -o $@ -c $+ +$(OUTDIR)/$(OUTPUT)_x86.ll: $(SOURCES:.c=_x86.bc) + $(LLVM_LINK) -S $+ -o $@ + python $(STRIPPER) $@ -build-test: lib$(OUTPUT).a - for src in $(SOURCES); do \ - $(CLANG) $(CF_TEST) -o test_$${src%.*} test_$$src -L. -lllrt; \ - done; +$(OUTDIR)/$(OUTPUT)_x86_64.ll: $(SOURCES:.c=_x86_64.bc) + $(LLVM_LINK) -S $+ -o $@ + python $(STRIPPER) $@ -test: build-test - for src in $(SOURCES); do \ - echo "testing $${src%.*}"; \ - python test_$${src%.*}.py > test_$${src%.*}.out; \ +build-test: $(SOURCES:.c=.o) $(TESTS:.c=.run) + +lib$(OUTPUT).a: $(SOURCES:.c=.o) + $(CLANG) -static $+ -o $@ + +test: $(TESTS:.c=.run) + for src in $+; do \ + echo "testing $${src}"; \ + python $${src%.*}.py > $${src%.*}.out; \ done; clean-test: rm -f *.out - rm -f *.a - for src in $(SOURCES); do \ - rm -f test_$${src%.*} ;\ - done; + rm -f *.o + rm -f *.run -clean-dist: - rm $(OUTDIR)/*.ll +clean-dist: clean-temp + rm -f *.ll + +clean-temp: + rm -f *.bc + rm -f *.o + rm -f *.out clean: clean-test clean-dist -udivmod64.c: udivmod64.h +%.c: llrt.h + +%_x86.bc: %.c + $(CLANG) -m32 $(CF_BUILD) -c $< -o $@ + +%_x86_64.bc: %.c + $(CLANG) -m64 $(CF_BUILD) -c $< -o $@ + +%.o: %.c + $(CLANG) $(CF_TEST) -c $< + +%.run: %.c + $(CLANG) $(CF_TEST) -o $@ $+ + +test_udivmod64.run: udivmod64.o +test_sdivmod64.run: udivmod64.o sdivmod64.o diff --git a/llrtc/lib/udivmod64.h b/llrtc/lib/llrt.h similarity index 50% rename from llrtc/lib/udivmod64.h rename to llrtc/lib/llrt.h index 9cbcd8c..0d26309 100644 --- a/llrtc/lib/udivmod64.h +++ b/llrtc/lib/llrt.h @@ -1,11 +1,12 @@ -#ifndef LLRT_UDIVMOD_H_ -#define LLRT_UDIVMOD_H_ +#ifndef LLRT_H_ +#define LLRT_H_ #include #define BITS_PER_BYTE 8 uint64_t udivmod64(uint64_t dividend, uint64_t divisor, uint64_t *remainder); +int64_t sdivmod64(int64_t dividend, int64_t divisor, int64_t *remainder); -#endif /* LLRT_UDIVMOD_H_ */ +#endif /* LLRT_H_ */ diff --git a/llrtc/lib/sdivmod64.c b/llrtc/lib/sdivmod64.c new file mode 100644 index 0000000..df294b3 --- /dev/null +++ b/llrtc/lib/sdivmod64.c @@ -0,0 +1,40 @@ +#include "llrt.h" +#include + +/* +Calls to udivmod64 internally. +Note: remainder uses sign of divisor. +*/ +int64_t sdivmod64(int64_t dividend, int64_t divisor, int64_t *remainder) +{ + int signbitidx = BITS_PER_BYTE * sizeof(dividend) - 1; + int signed_dividend = dividend < 0; + int signed_divisor = divisor < 0; + int signed_result = signed_divisor ^ signed_dividend; + + int64_t quotient; + uint64_t udvd, udvr, uquotient, uremainder; + + udvd = signed_dividend ? -dividend : dividend; + udvr = signed_divisor ? -divisor : divisor; + uquotient = udivmod64(udvd, udvr, &uremainder); + + if (signed_result){ + if (uremainder) { + quotient = -(int64_t)uquotient - 1; + } else { + quotient = -(int64_t)uquotient; + } + if (remainder) { + /* if signed, there could be unsigned overflow + causing undefined behavior */ + *remainder = (uint64_t)dividend - (uint64_t)quotient * (uint64_t)divisor; + } + } else { + quotient = (int64_t)uquotient; + if (remainder) { + *remainder = signed_divisor ? -uremainder : uremainder; + } + } + return quotient; +} diff --git a/llrtc/lib/test_sdivmod64.c b/llrtc/lib/test_sdivmod64.c new file mode 100644 index 0000000..1e804d6 --- /dev/null +++ b/llrtc/lib/test_sdivmod64.c @@ -0,0 +1,21 @@ +#include +#include +#include "llrt.h" + +int main(int argc, char * argv[]){ + int64_t n, d, q, r; + + if (argc != 3) { + printf("invalid argument: %s dividend divisor", argv[0]); + return 1; + } + sscanf(argv[1], "%lld", &n); + sscanf(argv[2], "%lld", &d); + + q = sdivmod64(n, d, &r); + + printf("%lld\n", q); + printf("%lld\n", r); + + return 0; +} diff --git a/llrtc/lib/test_sdivmod64.py b/llrtc/lib/test_sdivmod64.py new file mode 100644 index 0000000..4aa49a9 --- /dev/null +++ b/llrtc/lib/test_sdivmod64.py @@ -0,0 +1,56 @@ +import math +import os +import subprocess +udt = os.path.join('.', 'test_sdivmod64.run') + +def testcase(dividend, divisor): + print 'divmod64(%d, %d)' % (dividend, divisor) + + procargs = ('%s %s %s' % (udt, dividend, divisor)).split() + result = subprocess.check_output(procargs) + gotQ, gotR = map(int, result.splitlines()) + + expectQ = dividend // divisor + expectR = dividend % divisor + + print 'Q = %d, R = %d' % (gotQ, gotR) + + if expectQ != gotQ: + raise ValueError("invalid quotient: got=%d but expect=%d" % + (gotQ, expectQ)) + if expectR != gotR: + raise ValueError("invalid remainder: got=%d but expect=%d" % + (gotR, expectR)) + print 'OK' + +def testsequence(): + subjects = [ + (0, 1), + (0, 0xffffffff), + (1, 2), + (1, 983219), + (2, 2), + (3, 2), + (1024, 2), + (2048, 512), + (21321, 512), + (9329189, 1031), + (0xffffffff, 2), + (0xffffffff, 0xffff), + (0x1ffffffff, 2), + (0x1ffffffff, 0xffff), + (0xffff, 0xffffffff), + (0x0fffffffffffffff, 0xffff), + (0x7fffffffffffffff, 0x7fffffffffffffff), + (0x7fffffffffffffff, 0x7ffffffffffffff0), + (0x7fffffffffffffff, 87655678587161901), + ] + + for dvd, dvr in subjects: + testcase(dvd, dvr) + testcase(dvd, -dvr) + testcase(-dvd, dvr) + testcase(-dvd, -dvr) + +if __name__ == '__main__': + testsequence() diff --git a/llrtc/lib/test_udivmod64.c b/llrtc/lib/test_udivmod64.c index e2935c5..70b44aa 100644 --- a/llrtc/lib/test_udivmod64.c +++ b/llrtc/lib/test_udivmod64.c @@ -1,8 +1,6 @@ #include #include - -extern uint64_t -udivmod64(uint64_t dividend, uint64_t divisor, uint64_t *remainder); +#include "llrt.h" int main(int argc, char * argv[]){ uint64_t n, d, q, r; @@ -19,4 +17,4 @@ int main(int argc, char * argv[]){ printf("%llu\n", r); return 0; -} \ No newline at end of file +} diff --git a/llrtc/lib/test_udivmod64.py b/llrtc/lib/test_udivmod64.py index 487a458..da07ccb 100644 --- a/llrtc/lib/test_udivmod64.py +++ b/llrtc/lib/test_udivmod64.py @@ -1,7 +1,7 @@ import math import os import subprocess -udt = os.path.join('.', 'test_udivmod64') +udt = os.path.join('.', 'test_udivmod64.run') def testcase(dividend, divisor): print 'divmod64(%d, %d)' % (dividend, divisor) diff --git a/llrtc/lib/udivmod64.c b/llrtc/lib/udivmod64.c index a028aea..5936f98 100644 --- a/llrtc/lib/udivmod64.c +++ b/llrtc/lib/udivmod64.c @@ -2,7 +2,7 @@ Implements unsigned divmod using for platform missing 64-bit division and/or modulo functions. */ -#include "udivmod64.h" +#include "llrt.h" /* count left zero for 64-bit words @@ -79,6 +79,6 @@ uint64_t udivmod64(uint64_t dividend, uint64_t divisor, uint64_t *remainder) quotient |= 1ull << (63 - i); } } - *remainder = state.tmp; + if (remainder) *remainder = state.tmp; return quotient; } From e69048ad3dd6bdf541796e4f64e699962fe5006b Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 14 Aug 2013 17:24:34 -0500 Subject: [PATCH 25/37] add div64 and mod64 --- llrtc/Makefile | 2 +- llrtc/lib/Makefile | 2 +- llrtc/lib/div64.c | 11 +++++++++++ llrtc/lib/llrt.h | 7 +++++++ llrtc/lib/mod64.c | 15 +++++++++++++++ 5 files changed, 35 insertions(+), 2 deletions(-) create mode 100644 llrtc/lib/div64.c create mode 100644 llrtc/lib/mod64.c diff --git a/llrtc/Makefile b/llrtc/Makefile index bde100e..b15eac5 100644 --- a/llrtc/Makefile +++ b/llrtc/Makefile @@ -17,6 +17,6 @@ clean: make -C lib clean install: ir - make -C lib clean-test + cp llrt_*.ll ../llvm/llrt make -C lib clean-temp \ No newline at end of file diff --git a/llrtc/lib/Makefile b/llrtc/lib/Makefile index 8c9361d..9dbfb27 100644 --- a/llrtc/lib/Makefile +++ b/llrtc/lib/Makefile @@ -1,5 +1,5 @@ OUTPUT = llrt -SOURCES = udivmod64.c sdivmod64.c +SOURCES = udivmod64.c sdivmod64.c div64.c mod64.c TESTS = test_udivmod64.c test_sdivmod64.c CLANG = clang diff --git a/llrtc/lib/div64.c b/llrtc/lib/div64.c new file mode 100644 index 0000000..8466965 --- /dev/null +++ b/llrtc/lib/div64.c @@ -0,0 +1,11 @@ +#include "llrt.h" + +uint64_t udiv64(uint64_t dividend, uint64_t divisor) +{ + return udivmod64(dividend, divisor, NULL); +} + +int64_t sdiv64(int64_t dividend, int64_t divisor) +{ + return sdivmod64(dividend, divisor, NULL); +} diff --git a/llrtc/lib/llrt.h b/llrtc/lib/llrt.h index 0d26309..4e9e348 100644 --- a/llrtc/lib/llrt.h +++ b/llrtc/lib/llrt.h @@ -3,10 +3,17 @@ #include +#define NULL 0 #define BITS_PER_BYTE 8 uint64_t udivmod64(uint64_t dividend, uint64_t divisor, uint64_t *remainder); int64_t sdivmod64(int64_t dividend, int64_t divisor, int64_t *remainder); +uint64_t udiv64(uint64_t dividend, uint64_t divisor); +int64_t sdiv64(int64_t dividend, int64_t divisor); + +uint64_t umod64(uint64_t dividend, uint64_t divisor); +int64_t smod64(int64_t dividend, int64_t divisor); + #endif /* LLRT_H_ */ diff --git a/llrtc/lib/mod64.c b/llrtc/lib/mod64.c new file mode 100644 index 0000000..875f6b9 --- /dev/null +++ b/llrtc/lib/mod64.c @@ -0,0 +1,15 @@ +#include "llrt.h" + +uint64_t umod64(uint64_t dividend, uint64_t divisor) +{ + uint64_t rem; + udivmod64(dividend, divisor, &rem); + return rem; +} + +int64_t smod64(int64_t dividend, int64_t divisor) +{ + int64_t rem; + sdivmod64(dividend, divisor, &rem); + return rem; +} From bf8693bb806be4192810b740c08300876d76cb34 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 14 Aug 2013 17:45:38 -0500 Subject: [PATCH 26/37] disable float div/mod test temporarily --- llvm/core.py | 3 + llvm/llrt.py | 77 ++++++++ llvm/llrt/llrt_x86.ll | 371 +++++++++++++++++++++++++++++++++++++++ llvm/llrt/llrt_x86_64.ll | 371 +++++++++++++++++++++++++++++++++++++++ llvm/test_llvmpy.py | 42 ++++- 5 files changed, 858 insertions(+), 6 deletions(-) create mode 100644 llvm/llrt.py create mode 100644 llvm/llrt/llrt_x86.ll create mode 100644 llvm/llrt/llrt_x86_64.ll diff --git a/llvm/core.py b/llvm/core.py index 945dd86..c4fe560 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -1848,6 +1848,9 @@ class Instruction(User): def erase_from_parent(self): return self._ptr.eraseFromParent() + def replace_all_uses_with(self, inst): + self._ptr.replaceAllUsesWith(inst) + class CallOrInvokeInstruction(Instruction): _type_ = api.llvm.CallInst, api.llvm.InvokeInst diff --git a/llvm/llrt.py b/llvm/llrt.py new file mode 100644 index 0000000..b80914e --- /dev/null +++ b/llvm/llrt.py @@ -0,0 +1,77 @@ +import os +import llvm.core as lc +import llvm.passes as lp +import llvm.ee as le + +def replace_divmod64(lfunc): + '''Replaces all 64-bit integer division (sdiv, udiv) and modulo (srem, urem) + ''' + int64 = lc.Type.int(64) + int64ptr = lc.Type.pointer(lc.Type.int(64)) + + functy = lc.Type.function(int64, [int64, int64]) + udiv64 = lfunc.module.get_or_insert_function(functy, '__llrt_udiv64') + sdiv64 = lfunc.module.get_or_insert_function(functy, '__llrt_sdiv64') + umod64 = lfunc.module.get_or_insert_function(functy, '__llrt_umod64') + smod64 = lfunc.module.get_or_insert_function(functy, '__llrt_smod64') + + builder = lc.Builder.new(lfunc.entry_basic_block) + for bb in lfunc.basic_blocks: + for inst in bb.instructions: + if inst.opcode_name == 'sdiv' and inst.type == int64: + _replace_with(builder, inst, sdiv64) + elif inst.opcode_name == 'udiv' and inst.type == int64: + _replace_with(builder, inst, udiv64) + elif inst.opcode_name == 'srem' and inst.type == int64: + _replace_with(builder, inst, smod64) + elif inst.opcode_name == 'urem' and inst.type == int64: + _replace_with(builder, inst, umod64) + +def _replace_with(builder, inst, func): + '''Replace instruction with a call to the function with the same operands + as arguments. + ''' + builder.position_before(inst) + replacement = builder.call(func, inst.operands) + inst.replace_all_uses_with(replacement._ptr) + inst.erase_from_parent() + +def load(arch): + '''Load the LLRT module corresponding to the given architecture + Creates a new module and optimizes it using the information from + the host machine. + ''' + path = os.path.join(os.path.dirname(__file__), 'llrt', 'llrt_%s.ll' % arch) + with open(path) as fin: + lib = lc.Module.from_assembly(fin) + + # run passes to optimize + tm = le.TargetMachine.new() + pms = lp.build_pass_managers(tm, opt=3, fpm=False) + pms.pm.run(lib) + return lib + +class LLRT(object): + def __init__(self): + arch = le.get_default_triple().split('-', 1)[0] + self.module = load(arch) + self.engine = le.EngineBuilder.new(self.module).opt(3).create() + self.installed_symbols = set() + + def install_symbols(self): + '''Bind all the external symbols to the global symbol map. + Any future reference to these symbols will be automatically resolved + by LLVM. + ''' + for lfunc in self.module.functions: + if lfunc.linkage == lc.LINKAGE_EXTERNAL: + mangled = '__llrt_' + lfunc.name + self.installed_symbols.add(mangled) + ptr = self.engine.get_pointer_to_function(lfunc) + le.dylib_add_symbol(mangled, ptr) + + def uninstall_symbols(self): + for sym in self.installed_symbols: + le.dylib_add_symbol(sym, 0) + + diff --git a/llvm/llrt/llrt_x86.ll b/llvm/llrt/llrt_x86.ll new file mode 100644 index 0000000..5096214 --- /dev/null +++ b/llvm/llrt/llrt_x86.ll @@ -0,0 +1,371 @@ +; ModuleID = 'udivmod64_x86.bc' +target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128-n8:16:32-S128" + +%struct.div_state_ = type { i64, i64 } + +define i64 @udivmod64(i64 %dividend, i64 %divisor, i64* %remainder) nounwind ssp { + %1 = alloca i64, align 4 + %2 = alloca i64, align 8 + %3 = alloca i64, align 8 + %4 = alloca i64*, align 4 + %state = alloca %struct.div_state_, align 4 + %quotient = alloca i64, align 8 + %i = alloca i32, align 4 + %skipahead = alloca i32, align 4 + store i64 %dividend, i64* %2, align 8 + store i64 %divisor, i64* %3, align 8 + store i64* %remainder, i64** %4, align 4 + %5 = getelementptr inbounds %struct.div_state_* %state, i32 0, i32 0 + store i64 0, i64* %5, align 4 + %6 = getelementptr inbounds %struct.div_state_* %state, i32 0, i32 1 + %7 = load i64* %2, align 8 + store i64 %7, i64* %6, align 4 + store i64 0, i64* %quotient, align 8 + %8 = load i64* %3, align 8 + %9 = icmp eq i64 %8, 0 + br i1 %9, label %10, label %11 + +;