From f9d71954130c687bf181ef808a1ee51b1dc8d462 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Mon, 13 Aug 2012 15:53:09 -0700 Subject: [PATCH] reorganize --- README.md | 23 - llvm_cbuilder/__init__.py => __init__.py | 0 llvm_cbuilder/builder.py => builder.py | 0 llvm_cbuilder/executor.py => executor.py | 0 llvm_cbuilder/libc.py => libc.py | 0 notebook/llvm_cbuilder_intro.ipynb | 586 ------------------- notebook/llvm_cbuilder_intro.pdf | Bin 73415 -> 0 bytes notebook/parallel_vectorize.ipynb | 251 -------- notebook/parallel_vectorize.pdf | Bin 66363 -> 0 bytes parallel_vectorize.py | 461 --------------- llvm_cbuilder/shortnames.py => shortnames.py | 0 test_parallel_vectorize.py | 130 ---- test_parallel_vectorize_numpy.py | 57 -- test_parallel_vectorize_numpy_2.py | 69 --- test_usecase_1_1.py | 56 -- test_usecase_2_1.py | 58 -- tests/test_atomic_add.py | 115 ---- tests/test_atomic_cmpxchg.py | 122 ---- tests/test_cstr_collide.py | 17 - tests/test_isprime.py | 125 ---- tests/test_loopcontrol.py | 135 ----- tests/test_nestedloops.py | 128 ---- tests/test_print.py | 60 -- tests/test_pthread.py | 90 --- tests/test_struct.py | 52 -- 25 files changed, 2535 deletions(-) delete mode 100644 README.md rename llvm_cbuilder/__init__.py => __init__.py (100%) rename llvm_cbuilder/builder.py => builder.py (100%) rename llvm_cbuilder/executor.py => executor.py (100%) rename llvm_cbuilder/libc.py => libc.py (100%) delete mode 100644 notebook/llvm_cbuilder_intro.ipynb delete mode 100644 notebook/llvm_cbuilder_intro.pdf delete mode 100644 notebook/parallel_vectorize.ipynb delete mode 100644 notebook/parallel_vectorize.pdf delete mode 100644 parallel_vectorize.py rename llvm_cbuilder/shortnames.py => shortnames.py (100%) delete mode 100644 test_parallel_vectorize.py delete mode 100644 test_parallel_vectorize_numpy.py delete mode 100644 test_parallel_vectorize_numpy_2.py delete mode 100644 test_usecase_1_1.py delete mode 100644 test_usecase_2_1.py delete mode 100644 tests/test_atomic_add.py delete mode 100644 tests/test_atomic_cmpxchg.py delete mode 100644 tests/test_cstr_collide.py delete mode 100644 tests/test_isprime.py delete mode 100644 tests/test_loopcontrol.py delete mode 100644 tests/test_nestedloops.py delete mode 100644 tests/test_print.py delete mode 100644 tests/test_pthread.py delete mode 100644 tests/test_struct.py diff --git a/README.md b/README.md deleted file mode 100644 index a63039a..0000000 --- a/README.md +++ /dev/null @@ -1,23 +0,0 @@ -llvm_cbuilder -------------- - -A llvm-py Builder wrapper for writing in slightly higher-level constructs. -This is aiming for two usecases: - -1. Emit LLVM code in a more human-readable way; - -2. Writing low-level code that you can't do it properly/portably with C, e.g - template (generic), atomic operations, memory ordering... - - - -Parallel Vectorize ------------------- - -`parallel_vectorize.py` implements a set of code generator that bases on -llvm_cbuilder to create specialized parallel ufunc. - -See `test_parallel_vectorize_numpy*.py` for testing and demo of the code -with the new `numpy.fromfunc()`. - - diff --git a/llvm_cbuilder/__init__.py b/__init__.py similarity index 100% rename from llvm_cbuilder/__init__.py rename to __init__.py diff --git a/llvm_cbuilder/builder.py b/builder.py similarity index 100% rename from llvm_cbuilder/builder.py rename to builder.py diff --git a/llvm_cbuilder/executor.py b/executor.py similarity index 100% rename from llvm_cbuilder/executor.py rename to executor.py diff --git a/llvm_cbuilder/libc.py b/libc.py similarity index 100% rename from llvm_cbuilder/libc.py rename to libc.py diff --git a/notebook/llvm_cbuilder_intro.ipynb b/notebook/llvm_cbuilder_intro.ipynb deleted file mode 100644 index 9234f3d..0000000 --- a/notebook/llvm_cbuilder_intro.ipynb +++ /dev/null @@ -1,586 +0,0 @@ -{ - "metadata": { - "name": "llvm_cbuilder_intro" - }, - "nbformat": 2, - "worksheets": [ - { - "cells": [ - { - "cell_type": "markdown", - "source": [ - "llvm_cbuilder: A Quick Tour", - "---------------------------", - "", - "Writing code generation logic in pure llvmpy requires one to think like a compiler -- ", - "dealing with basic-blocks, branches, SSA, etc.", - "The resulting code looks like assembly code, with no apparent hint about the control-flow.", - "", - "llvm_cbuilder is originally designed to simplify the translation of C code into llvmpy.", - "It provides a simple API for mimicking C programming in Python.", - "With llvm_cbulder, one can write very low-level code, probably even lower-level than C.", - "At the same time, one can use if-else, loop, structures and a bit of OOP." - ] - }, - { - "cell_type": "markdown", - "source": [ - "A Simple Example", - "----------------", - "", - "Let's see some action.", - "We will define a function that calculates the square of a double-precision float." - ] - }, - { - "cell_type": "code", - "collapsed": true, - "input": [ - "from llvm.core import *", - "from llvm_cbuilder import *", - "import llvm_cbuilder.shortnames as C", - "", - "class Square(CDefinition):", - " # prototype: double square(double x)", - " _name_ = 'square' # function name", - " _retty_ = C.double", - " _argtys_ = [ ('x', C.double) ]", - " ", - " def body(self, x):", - " y = x * x # just write out the expression", - " self.ret(y)" - ], - "language": "python", - "outputs": [], - "prompt_number": 1 - }, - { - "cell_type": "markdown", - "source": [ - "Notice how numerical expressions can be written naturally." - ] - }, - { - "cell_type": "markdown", - "source": [ - "Let's see the emitted code:" - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "m = Module.new('my_module')", - "llvm_square = Square()(m) # define square() in my_module", - "print(m)" - ], - "language": "python", - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "; ModuleID = 'my_module'", - "", - "define double @square(double %x) {", - "decl:", - " %x1 = alloca double", - " br label %body", - "", - "body: ; preds = %decl", - " store double %x, double* %x1", - " %0 = load double* %x1", - " %1 = load double* %x1", - " %2 = fmul double %0, %1", - " ret double %2", - "}", - "" - ] - } - ], - "prompt_number": 2 - }, - { - "cell_type": "markdown", - "source": [ - "Let's generate a ctype function object to call `square()` in the Python code:" - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "exe = CExecutor(m)", - "square = exe.get_ctype_function(llvm_square, \"double, double\")", - "result = square(1.2)", - "print(result)" - ], - "language": "python", - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "1.44" - ] - } - ], - "prompt_number": 3 - }, - { - "cell_type": "markdown", - "source": [ - "Control Flow Constructs", - "-----------------------", - "", - "The main strength of llvm_cbuilder is the control-flow constructs. ", - "They use the python \"with\" statement to setup new code blocks to", - "contain different paths of the control flow.", - "", - "The following example demonstrates both the if-else and loop contructs:" - ] - }, - { - "cell_type": "code", - "collapsed": true, - "input": [ - "class IsPrime(CDefinition):", - " # prototype int isprime(int x)", - " _name_ = 'isprime'", - " _retty_ = C.int", - " _argtys_ = [ ('x', C.int) ]", - " ", - " def body(self, x):", - " two = self.constant(C.int, 2)", - " true = one = self.constant(C.int, 1)", - " false = zero = self.constant(C.int, 0)", - " ", - " with self.ifelse( x <= two ) as ifelse:", - " with ifelse.then():", - " self.ret(true)", - " ", - " with self.ifelse( (x % two) == zero ) as ifelse:", - " with ifelse.then():", - " self.ret(false)", - " ", - " idx = self.var(C.int, 3, name='idx')", - " with self.loop() as loop:", - " with loop.condition() as setcond:", - " setcond( idx < x )", - " ", - " with loop.body():", - " with self.ifelse( (x % idx) == zero ) as ifelse:", - " with ifelse.then():", - " self.ret(false)", - " idx += two", - " self.ret(true)" - ], - "language": "python", - "outputs": [], - "prompt_number": 4 - }, - { - "cell_type": "markdown", - "source": [ - "The code above is quite verbose.", - "It is like writing in Pascal or Ada. ", - "But, it is still easier than writing in llvmpy directly.", - "Take a look at the generated LLVM IR below." - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "llvm_isprime = IsPrime()(m)", - "print(llvm_isprime)" - ], - "language": "python", - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "", - "define i32 @isprime(i32 %x) {", - "decl:", - " %x1 = alloca i32", - " %idx = alloca i32", - " br label %body", - "", - "body: ; preds = %decl", - " store i32 %x, i32* %x1", - " %0 = load i32* %x1", - " %1 = icmp sle i32 %0, 2", - " br i1 %1, label %if.then, label %if.else", - "", - "if.then: ; preds = %body", - " ret i32 1", - "", - "if.else: ; preds = %body", - " br label %if.end", - "", - "if.end: ; preds = %if.else", - " %2 = load i32* %x1", - " %3 = srem i32 %2, 2", - " %4 = icmp eq i32 %3, 0", - " br i1 %4, label %if.then2, label %if.else3", - "", - "if.then2: ; preds = %if.end", - " ret i32 0", - "", - "if.else3: ; preds = %if.end", - " br label %if.end4", - "", - "if.end4: ; preds = %if.else3", - " store i32 3, i32* %idx", - " br label %loop.cond", - "", - "loop.cond: ; preds = %if.end7, %if.end4", - " %5 = load i32* %idx", - " %6 = load i32* %x1", - " %7 = icmp slt i32 %5, %6", - " br i1 %7, label %loop.body, label %loop.end", - "", - "loop.body: ; preds = %loop.cond", - " %8 = load i32* %x1", - " %9 = load i32* %idx", - " %10 = srem i32 %8, %9", - " %11 = icmp eq i32 %10, 0", - " br i1 %11, label %if.then5, label %if.else6", - "", - "loop.end: ; preds = %loop.cond", - " ret i32 1", - "", - "if.then5: ; preds = %loop.body", - " ret i32 0", - "", - "if.else6: ; preds = %loop.body", - " br label %if.end7", - "", - "if.end7: ; preds = %if.else6", - " %12 = load i32* %idx", - " %13 = add i32 %12, 2", - " store i32 %13, i32* %idx", - " br label %loop.cond", - "}", - "" - ] - } - ], - "prompt_number": 5 - }, - { - "cell_type": "markdown", - "source": [ - "We'll setup a ctype function object to try it out:" - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "isprime = exe.get_ctype_function(llvm_isprime, 'int, int')", - "prime_100 = filter(isprime, range(2, 100))", - "print(prime_100)" - ], - "language": "python", - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]" - ] - } - ], - "prompt_number": 6 - }, - { - "cell_type": "markdown", - "source": [ - "Structures", - "----------", - "", - "It is possible to create structures in llvm_cbuilder. ", - "Beware that structures in LLVM are unlike those in C.", - "LLVM type system allows structures to be literal or identified.", - "Literal structures are equivalent iff they have the same elements.", - "Identified structures are equivalent iff they have the same name.", - "In llvm_cbuilder, all structures are, by default, literal types.", - "", - "Here's an example:" - ] - }, - { - "cell_type": "code", - "collapsed": true, - "input": [ - "class Vector2D(CStruct):", - " _fields_ = [", - " ('x', C.float),", - " ('y', C.float),", - " ]" - ], - "language": "python", - "outputs": [], - "prompt_number": 7 - }, - { - "cell_type": "markdown", - "source": [ - "That's all you need for a structure. Very much like defining structures with ctypes.", - "", - "We can also bind methods to structures which inline code to the caller." - ] - }, - { - "cell_type": "code", - "collapsed": true, - "input": [ - "class Vector2D(CStruct):", - " _fields_ = [", - " ('x', C.float),", - " ('y', C.float),", - " ]", - " ", - " def add(self, other):", - " self.x += other.x", - " self.y += other.y" - ], - "language": "python", - "outputs": [], - "prompt_number": 8 - }, - { - "cell_type": "markdown", - "source": [ - "Setup a a test function:" - ] - }, - { - "cell_type": "code", - "collapsed": true, - "input": [ - "class TestVector(CDefinition):", - " _name_ = 'testvector'", - " _retty_ = C.float", - " _argtys_ = [('x', C.float), ", - " ('y', C.float)] ", - " ", - " def body(self, x, y):", - " va = self.var(Vector2D)", - " vb = self.var(Vector2D)", - " va.x.assign(self.constant(C.float, 10))", - " va.y.assign(self.constant(C.float, 20))", - " vb.x.assign(x)", - " vb.y.assign(y)", - " ", - " va.add(vb)", - " ", - " return self.ret(va.x * va.y)", - " " - ], - "language": "python", - "outputs": [], - "prompt_number": 9 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "llvm_testvec = TestVector()(m)", - "testvec = exe.get_ctype_function(llvm_testvec, \"float, float, float\")", - "print(testvec(-8, 5)) # should output 50" - ], - "language": "python", - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "50.0" - ] - } - ], - "prompt_number": 10 - }, - { - "cell_type": "markdown", - "source": [ - "Generic Programming", - "-------------------", - "", - "llvm_cbuilder supports generic function (or template function for C++).", - "When a `CDefinition` defines the `specialize` class method,", - "its constructor will invoke `specialize`.", - "All parameters passed to the constructor are forwarded to `specialize`.", - "", - "The constructor of a generic CDefinition creates a new dynamic class with the original CDefinition subclass as the parent.", - "Thus, `specialize` can modify class attributes without affecting the parent." - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "class GenericSquare(CDefinition):", - " @classmethod", - " def specialize(cls, data_type):", - " cls._name_ = '.'.join(['square', str(data_type)]) # set function name", - " cls._retty_ = data_type # set return type", - " cls._argtys_ = [ ('x', data_type) ] # set argument type", - " ", - " def body(self, x):", - " y = x * x # just write out the expression", - " self.ret(y)", - " ", - "llvm_square_int = GenericSquare(data_type=C.int)(m)", - "llvm_square_float = GenericSquare(data_type=C.float)(m)", - "", - "print(llvm_square_int)", - "print(llvm_square_float)" - ], - "language": "python", - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "", - "define i32 @square.i32(i32 %x) {", - "decl:", - " %x1 = alloca i32", - " br label %body", - "", - "body: ; preds = %decl", - " store i32 %x, i32* %x1", - " %0 = load i32* %x1", - " %1 = load i32* %x1", - " %2 = mul i32 %0, %1", - " ret i32 %2", - "}", - "", - "", - "define float @square.float(float %x) {", - "decl:", - " %x1 = alloca float", - " br label %body", - "", - "body: ; preds = %decl", - " store float %x, float* %x1", - " %0 = load float* %x1", - " %1 = load float* %x1", - " %2 = fmul float %0, %1", - " ret float %2", - "}", - "" - ] - } - ], - "prompt_number": 11 - }, - { - "cell_type": "markdown", - "source": [ - "External Functions", - "------------------", - "", - "`CExternal` is a convenient class to help accessing externally-defined functions.", - "", - "We define an external interface to `sqrtf()` in libm." - ] - }, - { - "cell_type": "code", - "collapsed": true, - "input": [ - "class LibM(CExternal):", - " sqrtf = Type.function(C.float, [C.float])" - ], - "language": "python", - "outputs": [], - "prompt_number": 12 - }, - { - "cell_type": "markdown", - "source": [ - "All class attributes that are `llvm.core.FunctionType` in `CExternal` ", - "are converted to a `CFunc` instance.", - "`CFunc` instances are callable.", - "`CFunc.__call__` generates code that perform the corresponding LLVM function call.", - "", - "The following example demonstrates the usage of `CExternal` and `CFunc`." - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "class TestSqrtf(CDefinition):", - " _name_ = 'test_sqrtf'", - " _retty_ = C.float", - " _argtys_ = [('x', C.float)]", - " ", - " def body(self, x):", - " libm = LibM(self) # init the API", - " y = libm.sqrtf(x) # call sqrtf", - " self.ret(y)", - " ", - "llvm_sqrtf = TestSqrtf()(m)", - "sqrtf = exe.get_ctype_function(llvm_sqrtf, 'float, float')", - "print(sqrtf(144))" - ], - "language": "python", - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "12.0" - ] - } - ], - "prompt_number": 13 - }, - { - "cell_type": "markdown", - "source": [ - "Casting", - "-------", - "", - "Unlike C, llvm_cbuilder does not automatically cast variables.", - "It is up to the user to explicit cast types.", - "All binary operations require both operands to be the same type.", - "All values in llvm_cbuilder has a `cast(destty)` method.", - "", - "For example:" - ] - }, - { - "cell_type": "code", - "collapsed": true, - "input": [ - "class CastExample(CDefinition):", - " _name_ = 'cast_example'", - " _retty_ = C.float", - " _argtys_ = [('x', C.int)]", - " ", - " def body(self, x):", - " y = x.cast(C.float) # cast integer x to float", - " self.ret(y)" - ], - "language": "python", - "outputs": [], - "prompt_number": 14 - }, - { - "cell_type": "markdown", - "source": [ - "More... (TODO)" - ] - } - ] - } - ] -} \ No newline at end of file diff --git a/notebook/llvm_cbuilder_intro.pdf b/notebook/llvm_cbuilder_intro.pdf deleted file mode 100644 index a7b17d48308c8792bce64c244e7678e19f1fc6df..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 73415 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

!vaZmL`9&HMV5usg-miO9%<0JmI*Vv&|k9ONu%m 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 num_thread, equally divide the works. - # If total_work % num_thread != 0, the last thread does all remaining works. - # If total_work < num_thread, each thread does one work, - # and set num_thread to total_work - N = dimensions[0] - ChunkSize = self.var_copy(N / num_thread.cast(N.type)) - ChunkSize_NULL = self.constant_null(ChunkSize.type) - with self.ifelse(ChunkSize == ChunkSize_NULL) as ifelse: - with ifelse.then(): - ChunkSize.assign(self.constant(ChunkSize.type, 1)) - num_thread.assign(N.cast(num_thread.type)) - - # Populate workqueue for all threads - self._populate_workqueues(workqueues, N, ChunkSize, num_thread) - - # Populate contexts for all threads - self._populate_context(contexts, common, num_thread) - - # Dispatch worker threads - self._dispatch_worker(worker, contexts, num_thread) - - ## DEBUG ONLY ## - # Check for race condition - if True: - total_completed = self.var(C.intp, 0, name='total_completed') - for t in range(ThreadCount): - cur_ctxt = contexts[t].as_struct(Context) - total_completed += cur_ctxt.completed - # self.debug(cur_ctxt.id, 'completed', cur_ctxt.completed) - - with self.ifelse( total_completed == N ) as ifelse: - with ifelse.then(): - # self.debug("All is well!") - pass # keep quite if all is well - with ifelse.otherwise(): - self.debug("ERROR: race occurred! Trigger segfault") - self.unreachable() - - # Return - self.ret() - - def _populate_workqueues(self, workqueues, N, ChunkSize, num_thread): - '''loop over all threads and populate the workqueue for each of them. - ''' - ONE = self.constant(num_thread.type, 1) - with self.for_range(num_thread) as (loop, i): - cur_wq = workqueues[i].as_struct(WorkQueue) - cur_wq.next.assign(i.cast(ChunkSize.type) * ChunkSize) - cur_wq.last.assign((i + ONE).cast(ChunkSize.type) * ChunkSize) - cur_wq.lock.assign(self.constant(C.int, 0)) - # end loop - last_wq = workqueues[num_thread - ONE].as_struct(WorkQueue) - last_wq.last.assign(N) - - def _populate_context(self, contexts, common, num_thread): - '''loop over all threads and populate contexts for each of them. - ''' - ONE = self.constant(num_thread.type, 1) - with self.for_range(num_thread) as (loop, i): - cur_ctxt = contexts[i].as_struct(Context) - cur_ctxt.common.assign(common.reference()) - cur_ctxt.id.assign(i) - cur_ctxt.completed.assign( - self.constant_null(cur_ctxt.completed.type)) - -class ParallelUFuncPosixMixin(object): - '''ParallelUFunc mixin that implements _dispatch_worker to use pthread. - ''' - def _dispatch_worker(self, worker, contexts, num_thread): - api = PThreadAPI(self) - NULL = self.constant_null(C.void_p) - - threads = self.array(api.pthread_t, num_thread, name='threads') - - # self.debug("launch threads") - # TODO error handling - - ONE = self.constant(num_thread.type, 1) - with self.for_range(num_thread) as (loop, i): - api.pthread_create(threads[i].reference(), NULL, worker, - contexts[i].reference().cast(C.void_p)) - - with self.for_range(num_thread) as (loop, i): - api.pthread_join(threads[i], NULL) - -class UFuncCore(CDefinition): - '''core work of a ufunc worker thread - - Subclass to implement UFuncCore._do_work - - Generates the workqueue handling and work stealing and invoke - the work function for each work item. - ''' - _name_ = 'ufunc_worker' - _argtys_ = [ - ('context', C.pointer(Context.llvm_type())), - ] - - def body(self, context): - context = context.as_struct(Context) - common = context.common.as_struct(ContextCommon) - tid = context.id - - # self.debug("start thread", tid, "/", common.num_thread) - workqueue = common.workqueues[tid].as_struct(WorkQueue) - - self._do_workqueue(common, workqueue, tid, context.completed) - self._do_work_stealing(common, tid, context.completed) # optional - - self.ret() - - def _do_workqueue(self, common, workqueue, tid, completed): - '''process local workqueue. - ''' - ZERO = self.constant_null(C.int) - - with self.forever() as loop: - workqueue.Lock() - # Critical section - item = self.var_copy(workqueue.next, name='item') - workqueue.next += self.constant(item.type, 1) - last = self.var_copy(workqueue.last, name='last') - # Release - workqueue.Unlock() - - with self.ifelse( item >= last ) as ifelse: - with ifelse.then(): - loop.break_loop() - - self._do_work(common, item, tid) - completed += self.constant(completed.type, 1) - - def _do_work_stealing(self, common, tid, completed): - '''steal work from other workqueues. - ''' - # self.debug("start work stealing", tid) - steal_continue = self.var(C.int, 1) - STEAL_STOP = self.constant_null(steal_continue.type) - - # Loop until all workqueues are done. - with self.loop() as loop: - with loop.condition() as setcond: - setcond( steal_continue != STEAL_STOP ) - - with loop.body(): - steal_continue.assign(STEAL_STOP) - self._do_work_stealing_innerloop(common, steal_continue, tid, - completed) - - def _do_work_stealing_innerloop(self, common, steal_continue, tid, - completed): - '''loop over all other threads and try to steal work. - ''' - with self.for_range(common.num_thread) as (loop, i): - with self.ifelse( i != tid ) as ifelse: - with ifelse.then(): - otherqueue = common.workqueues[i].as_struct(WorkQueue) - self._do_work_stealing_check(common, otherqueue, - steal_continue, tid, - completed) - - def _do_work_stealing_check(self, common, otherqueue, steal_continue, tid, - completed): - '''check the workqueue for any remaining work and steal it. - ''' - otherqueue.Lock() - # Acquired - ONE = self.constant(otherqueue.last.type, 1) - STEAL_CONTINUE = self.constant(steal_continue.type, 1) - with self.ifelse(otherqueue.next < otherqueue.last) as ifelse: - with ifelse.then(): - otherqueue.last -= ONE - item = self.var_copy(otherqueue.last) - - otherqueue.Unlock() - # Released - - self._do_work(common, item, tid) - completed += self.constant(completed.type, 1) - - # Mark incomplete thread - steal_continue.assign(STEAL_CONTINUE) - - with ifelse.otherwise(): - otherqueue.Unlock() - # Released - - def _do_work(self, common, item, tid): - '''prepare to call the actual work function - - Implementation depends on number and type of arguments. - ''' - raise NotImplementedError - -class SpecializedParallelUFunc(CDefinition): - '''a generic ufunc that wraps ParallelUFunc, UFuncCore and the workload - ''' - _argtys_ = [ - ('args', C.pointer(C.char_p)), - ('dimensions', C.pointer(C.intp)), - ('steps', C.pointer(C.intp)), - ('data', C.void_p), - ] - - def body(self, args, dimensions, steps, data,): - pufunc = self.depends(self.PUFuncDef) - core = self.depends(self.CoreDef) - func = self.depends(self.FuncDef) - to_void_p = lambda x: x.cast(C.void_p) - pufunc(to_void_p(func), to_void_p(core), args, dimensions, steps, data) - self.ret() - - @classmethod - def specialize(cls, pufunc_def, core_def, func_def): - '''specialize to a combination of ParallelUFunc, UFuncCore and workload - ''' - cls._name_ = 'specialized_%s_%s_%s'% (pufunc_def, core_def, func_def) - cls.PUFuncDef = pufunc_def - cls.CoreDef = core_def - cls.FuncDef = func_def - -class PThreadAPI(CExternal): - '''external declaration of pthread API - ''' - pthread_t = C.void_p - - pthread_create = Type.function(C.int, - [C.pointer(pthread_t), # thread_t - C.void_p, # thread attr - C.void_p, # function - C.void_p]) # arg - - pthread_join = Type.function(C.int, [C.void_p, C.void_p]) - - -class UFuncCoreGeneric(UFuncCore): - '''A generic ufunc core worker from LLVM function type - ''' - def _do_work(self, common, item, tid): - ufunc_type = Type.function(self.RETTY, self.ARGTYS) - ufunc_ptr = CFunc(self, common.func.cast(C.pointer(ufunc_type)).value) - - get_offset = lambda B, S, T: B[item * S].reference().cast(C.pointer(T)) - - indata = [] - for i, argty in enumerate(self.ARGTYS): - ptr = get_offset(common.args[i], common.steps[i], argty) - indata.append(ptr.load()) - - out_index = len(self.ARGTYS) - outptr = get_offset(common.args[out_index], common.steps[out_index], - self.RETTY) - - res = ufunc_ptr(*indata) - outptr.store(res) - - @classmethod - def specialize(cls, fntype): - '''specialize to a LLVM function type - - fntype : a LLVM function type (llvm.core.FunctionType) - ''' - cls._name_ = '.'.join([cls._name_] + - map(str, [fntype.return_type] + fntype.args)) - - cls.RETTY = fntype.return_type - cls.ARGTYS = tuple(fntype.args) - - -if sys.platform not in ['win32']: - class ParallelUFuncPlatform(ParallelUFunc, ParallelUFuncPosixMixin): - pass -else: - raise NotImplementedError("Threading for %s" % sys.platform) - - - -def parallel_vectorize_from_func(lfunc, engine=None): - '''create ufunc from a llvm.core.Function - - If engine is given, return a function object which can be called - from python. (This needs Jay's numpy.fromfunc). - Otherwise, return the specialized ufunc as a llvm.core.Function - ''' - import multiprocessing - NUM_CPU = multiprocessing.cpu_count() - - fntype = lfunc.type.pointee - def_spuf = SpecializedParallelUFunc( - ParallelUFuncPlatform(num_thread=NUM_CPU), - UFuncCoreGeneric(fntype), - CFuncRef(lfunc)) - spuf = def_spuf(lfunc.module) - if engine is None: - return spuf - else: - import numpy as np - - fptr = engine.get_pointer_to_function(spuf) - inct = len(fntype.args) - outct = 1 - - # TODO refactor - typemap = { - 'i8' : np.int8, - 'i16' : np.int16, - 'i32' : np.int32, - 'i64' : np.int64, - 'float' : np.float32, - 'double' : np.float64, - } - try: - ptr_t = long - except: - ptr_t = int - assert False, "Having check this yet" - - get_typenum = lambda T:np.dtype(typemap[str(T)]).num - assert fntype.return_type != C.void - tys = list(map(get_typenum, list(fntype.args) + [fntype.return_type])) - # Becareful that fromfunc does not provide full error checking yet. - # If typenum is out-of-bound, we have nasty memory corruptions. - # For instance, -1 for typenum will cause segfault. - # If elements of type-list (2nd arg) is tuple instead, - # there will also memory corruption. (Seems like code rewrite.) - return np.fromfunc([ptr_t(fptr)], [tys], inct, outct, [None]) - diff --git a/llvm_cbuilder/shortnames.py b/shortnames.py similarity index 100% rename from llvm_cbuilder/shortnames.py rename to shortnames.py diff --git a/test_parallel_vectorize.py b/test_parallel_vectorize.py deleted file mode 100644 index 1a850f5..0000000 --- a/test_parallel_vectorize.py +++ /dev/null @@ -1,130 +0,0 @@ -from parallel_vectorize import * - - -class Work_D_D(CDefinition): - _name_ = 'work_d_d' - _retty_ = C.double - _argtys_ = [ - ('inval', C.double), - ] - def body(self, inval): - self.ret(inval / self.constant(inval.type, 2.345)) - -class UFuncCore_D_D(UFuncCore): - ''' - Specialize UFuncCore for double input, double output. - ''' - _name_ = UFuncCore._name_ + '_d_d' - def _do_work(self, common, item, tid): - ufunc_type = Type.function(C.double, [C.double]) - ufunc_ptr = CFunc(self, common.func.cast(C.pointer(ufunc_type)).value) - - inbase = common.args[0] - outbase = common.args[1] - - instep = common.steps[0] - outstep = common.steps[1] - - indata = inbase[item * instep].reference().cast(C.pointer(C.double)) - outdata = outbase[item * outstep].reference().cast(C.pointer(C.double)) - - res = ufunc_ptr(indata.load()) - outdata.store(res) - -class ParallelUFuncPosix(ParallelUFunc, ParallelUFuncPosixMixin): - pass - -class Tester(CDefinition): - ''' - Generate test. - ''' - _name_ = 'tester' - - def body(self): - # depends - module = self.function.module - - ThreadCount = 2 - ArgCount = 2 - WorkCount = 10000 - - - spufdef = SpecializedParallelUFunc(ParallelUFuncPosix(num_thread=2), - UFuncCore_D_D(), - Work_D_D()) - - sppufunc = self.depends(spufdef) - - # real work - NULL = self.constant_null(C.void_p) - - args = self.array(C.char_p, 2, name='args') - - args_double = [] - for t in range(ThreadCount): - args_for_thread = self.array(C.double, WorkCount) - args[t].assign(args_for_thread.cast(C.char_p)) - args_double.append(args_for_thread) - - dims = self.array(C.intp, 1, name='dims') - dims[0].assign(self.constant(C.intp, WorkCount)) - - steps = self.array(C.intp, ArgCount, name='steps') - - for c in range(ArgCount): - steps[c].assign(self.constant(C.intp, 8)) - - # populate data - inbase = args_double[0] - - i = self.var(C.intp, 0) - with self.loop() as loop: - with loop.condition() as setcond: - setcond( i < self.constant(C.intp, WorkCount) ) - with loop.body(): - inbase[i].assign(i.cast(C.double)) - i += self.constant(C.intp, 1) - - # call parallel ufunc - sppufunc(args, dims, steps, NULL) - - # check error - outbase = args_double[-1] - with self.for_range(self.constant(C.intp, WorkCount)) as (loop, i): - test = outbase[i] != (inbase[i] / self.constant(C.double, 2.345)) - with self.ifelse( test ) as ifelse: - with ifelse.then(): - self.debug("Invalid data at i =", i, outbase[i], inbase[i]) - - self.ret() - -def main(): - module = Module.new(__name__) - - mpm = PassManager.new() - pmbuilder = PassManagerBuilder.new() - pmbuilder.opt_level = 3 - pmbuilder.populate(mpm) - - fntester = Tester.define(module) - -# print(module) - module.verify() - - mpm.run(module) - - print('optimized'.center(80,'-')) - print(module) - - # run - print('run') - exe = CExecutor(module) - func = exe.get_ctype_function(fntester, 'void') - - func() - # Will not reach here is race condition occurred - print('Good') - -if __name__ == '__main__': - main() - diff --git a/test_parallel_vectorize_numpy.py b/test_parallel_vectorize_numpy.py deleted file mode 100644 index 392c81d..0000000 --- a/test_parallel_vectorize_numpy.py +++ /dev/null @@ -1,57 +0,0 @@ -''' -Test parallel-vectorize with numpy.fromfunc. -Uses the work load from test_parallel_vectorize. -''' - -from test_parallel_vectorize import * - -import numpy as np - -def main(): - module = Module.new(__name__) - - spufdef = SpecializedParallelUFunc(ParallelUFuncPosix(num_thread=2), - UFuncCore_D_D(), - Work_D_D()) - - sppufunc = spufdef(module) - - module.verify() - - mpm = PassManager.new() - pmbuilder = PassManagerBuilder.new() - pmbuilder.opt_level = 3 - pmbuilder.populate(mpm) - - mpm.run(module) -# print module - - # run - - exe = CExecutor(module) - funcptr = exe.engine.get_pointer_to_function(sppufunc) - print("Function pointer: %x" % funcptr) - - ptr_t = long # py2 only - - # Becareful that fromfunc does not provide full error checking yet. - # If typenum is out-of-bound, we have nasty memory corruptions. - # For instance, -1 for typenum will cause segfault. - # If elements of type-list (2nd arg) is tuple instead, - # there will also memory corruption. (Seems like code rewrite.) - typenum = np.dtype(np.double).num - ufunc = np.fromfunc([ptr_t(funcptr)], [[typenum, typenum]], 1, 1, [None]) - - x = np.linspace(0., 10., 1000) - x.dtype=np.double -# print x - ans = ufunc(x) -# print ans - - if not ( ans == x/2.345 ).all(): - raise ValueError('Computation failed') - else: - print('Good') - -if __name__ == '__main__': - main() diff --git a/test_parallel_vectorize_numpy_2.py b/test_parallel_vectorize_numpy_2.py deleted file mode 100644 index f846a25..0000000 --- a/test_parallel_vectorize_numpy_2.py +++ /dev/null @@ -1,69 +0,0 @@ -''' -Test parallel-vectorize with numpy.fromfunc. -Uses the work load from test_parallel_vectorize. -This time we pass a function pointer. -''' - -from test_parallel_vectorize import * - -import numpy as np - -def main(): - module = Module.new(__name__) - exe = CExecutor(module) - - workdef = Work_D_D() - workfunc = workdef(module) - - # get pointer to workfunc - workfunc_ptr = exe.engine.get_pointer_to_function(workfunc) - - workdecl = CFuncRef(workfunc.name, workfunc.type.pointee, workfunc_ptr) - - spufdef = SpecializedParallelUFunc(ParallelUFuncPosix(num_thread=2), - UFuncCore_D_D(), - workdecl) - - - sppufunc = spufdef(module) - sppufunc.verify() - print(sppufunc) - module.verify() - - mpm = PassManager.new() - pmbuilder = PassManagerBuilder.new() - pmbuilder.opt_level = 3 - pmbuilder.populate(mpm) - - mpm.run(module) - print(module) - - - # run - - funcptr = exe.engine.get_pointer_to_function(sppufunc) - print("Function pointer: %x" % funcptr) - - ptr_t = long # py2 only - - # Becareful that fromfunc does not provide full error checking yet. - # If typenum is out-of-bound, we have nasty memory corruptions. - # For instance, -1 for typenum will cause segfault. - # If elements of type-list (2nd arg) is tuple instead, - # there will also memory corruption. (Seems like code rewrite.) - typenum = np.dtype(np.double).num - ufunc = np.fromfunc([ptr_t(funcptr)], [[typenum, typenum]], 1, 1, [None]) - - x = np.linspace(0., 10., 1000) - x.dtype=np.double -# print x - ans = ufunc(x) -# print ans - - if not ( ans == x/2.345 ).all(): - raise ValueError('Computation failed') - else: - print('Good') - -if __name__ == '__main__': - main() diff --git a/test_usecase_1_1.py b/test_usecase_1_1.py deleted file mode 100644 index 5cc4d7a..0000000 --- a/test_usecase_1_1.py +++ /dev/null @@ -1,56 +0,0 @@ -from parallel_vectorize import * -from llvm_cbuilder import shortnames as C -from llvm.core import * -import numpy as np -import unittest -from random import random - -class OneOne(CDefinition): - - def body(self, inval): - self.ret( (inval * inval).cast(self.OUT_TYPE) ) - - @classmethod - def specialize(cls, itype, otype): - cls._name_ = '.'.join(map(str, ['oneone', itype, otype])) - cls._retty_ = otype - cls._argtys_ = [ - ('inval', itype), - ] - cls.OUT_TYPE = otype - - -class TestParallelVectorize(unittest.TestCase): - def test_parallelvectorize_d_d(self): - self.template(C.double, C.double) - - def test_parallelvectorize_d_f(self): - self.template(C.double, C.float) - - def template(self, itype, otype): - module = Module.new(__name__) - exe = CExecutor(module) - - def_oneone = OneOne(itype, otype) - oneone = def_oneone(module) - ufunc = parallel_vectorize_from_func(oneone, exe.engine) - # print(module) - module.verify() - - x = np.linspace(.0, 10., 1000) - x.dtype = np.double - - ans = ufunc(x) - gold = x * x - - for x, y in zip(ans, gold): - if y != 0: - err = abs(x - y)/y - self.assertLess(err, 1e-6) - else: - self.assertEqual(x, y) - - -if __name__ == '__main__': - unittest.main() - diff --git a/test_usecase_2_1.py b/test_usecase_2_1.py deleted file mode 100644 index 087ee9f..0000000 --- a/test_usecase_2_1.py +++ /dev/null @@ -1,58 +0,0 @@ -from parallel_vectorize import * -from llvm_cbuilder import shortnames as C -from llvm.core import * -import numpy as np -import unittest -from random import random - -class TwoOne(CDefinition): - - def body(self, a, b): - self.ret( (a * b).cast(self.OUT_TYPE) ) - - @classmethod - def specialize(cls, itype1, itype2, otype): - cls._name_ = '.'.join(map(str, ['oneone', itype1, itype2, otype])) - cls._retty_ = otype - cls._argtys_ = [ - ('a', itype1), - ('b', itype2), - ] - cls.OUT_TYPE = otype - - -class TestParallelVectorize(unittest.TestCase): - def test_parallelvectorize_dd_d(self): - self.template(C.double, C.double, C.double) - - def test_parallelvectorize_dd_f(self): - self.template(C.double, C.double, C.float) - - def template(self, itype1, itype2, otype): - module = Module.new(__name__) - exe = CExecutor(module) - - def_twoone = TwoOne(itype1, itype2, otype) - twoone = def_twoone(module) - ufunc = parallel_vectorize_from_func(twoone, exe.engine) - # print(module) - module.verify() - - A = np.linspace(.0, 10., 1000) - A.dtype = np.double - B = np.linspace(-10., 0., 1000) - B.dtype = np.double - - ans = ufunc(A, B) - gold = A * B - - for x, y in zip(ans, gold): - if y != 0: - err = abs(x - y)/y - self.assertLess(err, 1e-6) - else: - self.assertEqual(x, y) - -if __name__ == '__main__': - unittest.main() - diff --git a/tests/test_atomic_add.py b/tests/test_atomic_add.py deleted file mode 100644 index 27688e7..0000000 --- a/tests/test_atomic_add.py +++ /dev/null @@ -1,115 +0,0 @@ -''' -Base on the test_pthread.py and extend to use atomic instructions -''' - -from llvm.core import * -from llvm.passes import * -from llvm.ee import * -from llvm_cbuilder import * -import llvm_cbuilder.shortnames as C -import unittest, logging - -# logging.basicConfig(level=logging.DEBUG) - -NUM_OF_THREAD = 4 -REPEAT = 10000 - -def gen_test_worker(mod): - cb = CBuilder.new_function(mod, 'worker', C.void, [C.pointer(C.int)]) - pval = cb.args[0] - one = cb.constant(pval.type.pointee, 1) - - ct = cb.var(C.int, 0) - limit = cb.constant(C.int, REPEAT) - with cb.loop() as loop: - with loop.condition() as setcond: - setcond( ct < limit ) - - with loop.body(): - cb.atomic_add(pval, one, 'acq_rel') - ct += one - - cb.ret() - cb.close() - return cb.function - -def gen_test_pthread(mod): - cb = CBuilder.new_function(mod, 'manager', C.int, [C.int]) - arg = cb.args[0] - - worker_func = cb.get_function_named('worker') - pthread_create = cb.get_function_named('pthread_create') - pthread_join = cb.get_function_named('pthread_join') - - - NULL = cb.constant_null(C.void_p) - cast_to_null = lambda x: x.cast(C.void_p) - - threads = cb.array(C.void_p, NUM_OF_THREAD) - - for tid in range(NUM_OF_THREAD): - pthread_create_args = [threads[tid].reference(), - NULL, - worker_func, - arg.reference()] - pthread_create(*map(cast_to_null, pthread_create_args)) - - worker_func(arg.reference()) - - for tid in range(NUM_OF_THREAD): - pthread_join_args = threads[tid], NULL - pthread_join(*map(cast_to_null, pthread_join_args)) - - - cb.ret(arg) - cb.close() - return cb.function - -class TestAtomicAdd(unittest.TestCase): - def test_atomic_add(self): - mod = Module.new(__name__) - # add pthread functions - - mod.add_function(Type.function(C.int, - [C.void_p, C.void_p, C.void_p, C.void_p]), - 'pthread_create') - - mod.add_function(Type.function(C.int, - [C.void_p, C.void_p]), - 'pthread_join') - - lf_test_worker = gen_test_worker(mod) - lf_test_pthread = gen_test_pthread(mod) - logging.debug(mod) - mod.verify() - - # optimize - fpm = FunctionPassManager.new(mod) - mpm = PassManager.new() - pmb = PassManagerBuilder.new() - pmb.vectorize = True - pmb.opt_level = 3 - pmb.populate(fpm) - pmb.populate(mpm) - - fpm.run(lf_test_worker) - fpm.run(lf_test_pthread) - mpm.run(mod) - logging.debug(mod) - mod.verify() - - # run - exe = CExecutor(mod) - exe.engine.get_pointer_to_function(mod.get_function_named('worker')) - func = exe.get_ctype_function(lf_test_pthread, 'int, int') - - inarg = 1234 - gold = inarg + (NUM_OF_THREAD + 1) * REPEAT - - for _ in range(1000): # run many many times to catch race condition - self.assertEqual(func(inarg), gold, "Unexpected race condition") - - -if __name__ == '__main__': - unittest.main() - diff --git a/tests/test_atomic_cmpxchg.py b/tests/test_atomic_cmpxchg.py deleted file mode 100644 index 27fb763..0000000 --- a/tests/test_atomic_cmpxchg.py +++ /dev/null @@ -1,122 +0,0 @@ -''' -Base on the test_pthread.py and extend to use atomic instructions -''' - -from llvm.core import * -from llvm.passes import * -from llvm.ee import * -from llvm_cbuilder import * -import llvm_cbuilder.shortnames as C -import unittest, logging - -# logging.basicConfig(level=logging.DEBUG) - -NUM_OF_THREAD = 4 -REPEAT = 10000 - -def gen_test_worker(mod): - cb = CBuilder.new_function(mod, 'worker', C.void, [C.pointer(C.int)]) - pval = cb.args[0] - one = cb.constant(pval.type.pointee, 1) - - ct = cb.var(C.int, 0) - limit = cb.constant(C.int, REPEAT) - with cb.loop() as loop: - with loop.condition() as setcond: - setcond( ct < limit ) - - with loop.body(): - oldval = pval.atomic_load('acquire') - updated = oldval + one - castmp = pval.atomic_cmpxchg(oldval, updated, 'release') - - with cb.ifelse( castmp == oldval ) as ifelse: - with ifelse.then(): - ct += one - - cb.ret() - cb.close() - return cb.function - -def gen_test_pthread(mod): - cb = CBuilder.new_function(mod, 'manager', C.int, [C.int]) - arg = cb.args[0] - - worker_func = cb.get_function_named('worker') - pthread_create = cb.get_function_named('pthread_create') - pthread_join = cb.get_function_named('pthread_join') - - - NULL = cb.constant_null(C.void_p) - cast_to_null = lambda x: x.cast(C.void_p) - - threads = cb.array(C.void_p, NUM_OF_THREAD) - - for tid in range(NUM_OF_THREAD): - pthread_create_args = [threads[tid].reference(), - NULL, - worker_func, - arg.reference()] - pthread_create(*map(cast_to_null, pthread_create_args)) - - worker_func(arg.reference()) - - for tid in range(NUM_OF_THREAD): - pthread_join_args = threads[tid], NULL - pthread_join(*map(cast_to_null, pthread_join_args)) - - - cb.ret(arg) - cb.close() - return cb.function - -class TestAtomicCmpXchg(unittest.TestCase): - def test_atomic_cmpxchg(self): - mod = Module.new(__name__) - # add pthread functions - - mod.add_function(Type.function(C.int, - [C.void_p, C.void_p, C.void_p, C.void_p]), - 'pthread_create') - - mod.add_function(Type.function(C.int, - [C.void_p, C.void_p]), - 'pthread_join') - - lf_test_worker = gen_test_worker(mod) - lf_test_pthread = gen_test_pthread(mod) - logging.debug(mod) - mod.verify() - - # optimize - fpm = FunctionPassManager.new(mod) - mpm = PassManager.new() - pmb = PassManagerBuilder.new() - pmb.vectorize = True - pmb.opt_level = 3 - pmb.populate(fpm) - pmb.populate(mpm) - - fpm.run(lf_test_worker) - fpm.run(lf_test_pthread) - mpm.run(mod) - logging.debug(mod) - mod.verify() - - # run - exe = CExecutor(mod) - exe.engine.get_pointer_to_function(mod.get_function_named('worker')) - func = exe.get_ctype_function(lf_test_pthread, 'int, int') - - inarg = 1234 - gold = inarg + (NUM_OF_THREAD + 1) * REPEAT - - for _ in range(1000): # run many many times to catch race condition - res = func(inarg) - self.assertEqual(res, gold, - "Unexpected race condition: res = %d" % res) - - -if __name__ == '__main__': - unittest.main() - diff --git a/tests/test_cstr_collide.py b/tests/test_cstr_collide.py deleted file mode 100644 index 4a427c6..0000000 --- a/tests/test_cstr_collide.py +++ /dev/null @@ -1,17 +0,0 @@ -from llvm.core import * -from llvm_cbuilder import * -from llvm_cbuilder import shortnames as C - -import unittest - -class TestCstrCollide(unittest.TestCase): - def test_same_string(self): - mod = Module.new(__name__) - cb = CBuilder.new_function(mod, 'test_cstr_collide', C.void, []) - - a = cb.constant_string("hello") - b = cb.constant_string("hello") - self.assertEqual(a.value, b.value) - -if __name__ == '__main__': - unittest.main() diff --git a/tests/test_isprime.py b/tests/test_isprime.py deleted file mode 100644 index bcc0b9c..0000000 --- a/tests/test_isprime.py +++ /dev/null @@ -1,125 +0,0 @@ -from llvm.core import * -from llvm.passes import * -from llvm.ee import * -from llvm_cbuilder import * -import llvm_cbuilder.shortnames as C -import unittest, logging - -def is_prime(x): - if x <= 2: - return True - if (x % 2) == 0: - return False - for y in range(2, int(1 + x**0.5)): - if (x % y) == 0: - return False - return True - -def gen_is_prime(mod): - functype = Type.function(C.int, [C.int]) - func = mod.add_function(functype, 'isprime') - - cb = CBuilder(func) - - arg = cb.args[0] - - two = cb.constant(C.int, 2) - true = one = cb.constant(C.int, 1) - false = zero = cb.constant(C.int, 0) - - with cb.ifelse( arg <= two ) as ifelse: - with ifelse.then(): - cb.ret(true) - - with cb.ifelse( (arg % two) == zero ) as ifelse: - with ifelse.then(): - cb.ret(false) - - idx = cb.var(C.int, 3, name='idx') - with cb.loop() as loop: - with loop.condition() as setcond: - setcond( idx < arg ) - - with loop.body(): - with cb.ifelse( (arg % idx) == zero ) as ifelse: - with ifelse.then(): - cb.ret(false) - # increment - idx += two - - cb.ret(true) - cb.close() - return func - - -def gen_is_prime_fast(mod): - functype = Type.function(C.int, [C.int]) - func = mod.add_function(functype, 'isprime_fast') - - cb = CBuilder(func) - - arg = cb.args[0] - - two = cb.constant(C.int, 2) - true = one = cb.constant(C.int, 1) - false = zero = cb.constant(C.int, 0) - - with cb.ifelse( arg <= two ) as ifelse: - with ifelse.then(): - cb.ret(true) - - with cb.ifelse( (arg % two) == zero ) as ifelse: - with ifelse.then(): - cb.ret(false) - - idx = cb.var(C.int, 3, name='idx') - - sqrt = cb.get_intrinsic(INTR_SQRT, [C.float]) - - looplimit = one + sqrt(arg.cast(C.float)).cast(C.int) - - - with cb.loop() as loop: - with loop.condition() as setcond: - setcond( idx < looplimit ) - - with loop.body(): - with cb.ifelse( (arg % idx) == zero ) as ifelse: - with ifelse.then(): - cb.ret(false) - # increment - idx += two - - - cb.ret(true) - cb.close() - return func - -class TestIsPrime(unittest.TestCase): - def test_isprime(self): - mod = Module.new(__name__) - lf_isprime = gen_is_prime(mod) - logging.debug(mod) - mod.verify() - - exe = CExecutor(mod) - func = exe.get_ctype_function(lf_isprime, 'bool, int') - for x in range(2, 1000): - msg = "Failed at x = %d" % x - self.assertEqual(func(x), is_prime(x), msg) - - def test_isprime_fast(self): - mod = Module.new(__name__) - lf_isprime = gen_is_prime_fast(mod) - logging.debug(mod) - mod.verify() - - exe = CExecutor(mod) - func = exe.get_ctype_function(lf_isprime, 'bool, int') - for x in range(2, 1000): - msg = "Failed at x = %d" % x - self.assertEqual(func(x), is_prime(x), msg) - -if __name__ == '__main__': - unittest.main() - diff --git a/tests/test_loopcontrol.py b/tests/test_loopcontrol.py deleted file mode 100644 index 7e252bf..0000000 --- a/tests/test_loopcontrol.py +++ /dev/null @@ -1,135 +0,0 @@ -from llvm.core import * -from llvm.passes import * -from llvm.ee import * -from llvm_cbuilder import * -import llvm_cbuilder.shortnames as C -import unittest, logging - -def loopbreak(d): - z = 0 - for x in range(100): - for y in range(100): - z += x + y - if z > 50: - break - z -= d - return z - -def gen_loopbreak(mod): - functype = Type.function(C.int, [C.int]) - func = mod.add_function(functype, 'loopbreak') - - cb = CBuilder(func) - - d = cb.args[0] - x = cb.var(C.int) - y = cb.var(C.int) - z = cb.var(C.int) - - one = cb.constant(C.int, 1) - zero = cb.constant(C.int, 0) - limit = cb.constant(C.int, 100) - fifty = cb.constant(C.int, 50) - - z.assign(zero) - x.assign(zero) - with cb.loop() as outer: - with outer.condition() as setcond: - setcond( x < limit ) - - with outer.body(): - y.assign(zero) - with cb.loop() as inner: - with inner.condition() as setcond: - setcond( y < limit ) - - with inner.body(): - z += x + y - with cb.ifelse( z > fifty ) as ifelse: - with ifelse.then(): - inner.break_loop() - y += one - z -= d - x += one - - cb.ret(z) - cb.close() - return func - -def loopcontinue(d): - z = 0 - for x in range(100): - for y in range(100): - z += x + y - if z > 50: - continue - z += d - return z - -def gen_loopcontinue(mod): - functype = Type.function(C.int, [C.int]) - func = mod.add_function(functype, 'loopcontinue') - - cb = CBuilder(func) - - d = cb.args[0] - x = cb.var(C.int) - y = cb.var(C.int) - z = cb.var(C.int) - - one = cb.constant(C.int, 1) - zero = cb.constant(C.int, 0) - limit = cb.constant(C.int, 100) - fifty = cb.constant(C.int, 50) - - z.assign(zero) - x.assign(zero) - with cb.loop() as outer: - with outer.condition() as setcond: - setcond( x < limit ) - - with outer.body(): - y.assign(zero) - with cb.loop() as inner: - with inner.condition() as setcond: - setcond( y < limit ) - - with inner.body(): - z += x + y - y += one - with cb.ifelse( z > fifty ) as ifelse: - with ifelse.then(): - inner.continue_loop() - z += d - x += one - - cb.ret(z) - cb.close() - return func - -class TestLoopControl(unittest.TestCase): - def test_loopbreak(self): - mod = Module.new(__name__) - lfunc = gen_loopbreak(mod) - logging.debug(mod) - mod.verify() - - exe = CExecutor(mod) - func = exe.get_ctype_function(lfunc, 'int, int') - for x in range(100): - self.assertEqual(func(x), loopbreak(x)) - - def test_loopcontinue(self): - mod = Module.new(__name__) - lfunc = gen_loopcontinue(mod) - logging.debug(mod) - mod.verify() - - exe = CExecutor(mod) - func = exe.get_ctype_function(lfunc, 'int, int') - for x in range(100): - self.assertEqual(func(x), loopcontinue(x)) - -if __name__ == '__main__': - unittest.main() - diff --git a/tests/test_nestedloops.py b/tests/test_nestedloops.py deleted file mode 100644 index 0876bb2..0000000 --- a/tests/test_nestedloops.py +++ /dev/null @@ -1,128 +0,0 @@ -from llvm.core import * -from llvm.passes import * -from llvm.ee import * -from llvm_cbuilder import * -import llvm_cbuilder.shortnames as C -import unittest, logging - -def nestedloop1(d): - z = 0 - for x in range(100): - for y in range(100): - z += x * d + int(y / d) - return z - -def gen_nestedloop1(mod): - functype = Type.function(C.int, [C.int]) - func = mod.add_function(functype, 'nestedloop1') - - cb = CBuilder(func) - - d = cb.args[0] - x = cb.var(C.int) - y = cb.var(C.int) - z = cb.var(C.int) - - one = cb.constant(C.int, 1) - zero = cb.constant(C.int, 0) - limit = cb.constant(C.int, 100) - - z.assign(zero) - x.assign(zero) - with cb.loop() as outer: - with outer.condition() as setcond: - setcond( x < limit ) - - with outer.body(): - y.assign(zero) - with cb.loop() as inner: - with inner.condition() as setcond: - setcond( y < limit ) - - with inner.body(): - z += x * d + y / d - y += one - x += one - - cb.ret(z) - cb.close() - return func - - -def nestedloop2(d): - z = 0 - for x in range(1, 100): - for y in range(1, 100): - if x > y: - z += int(x / y) * d - else: - z += int(y / x) * d - return z - -def gen_nestedloop2(mod): - functype = Type.function(C.int, [C.int]) - func = mod.add_function(functype, 'nestedloop2') - - cb = CBuilder(func) - - d = cb.args[0] - x = cb.var(C.int) - y = cb.var(C.int) - z = cb.var(C.int) - - one = cb.constant(C.int, 1) - zero = cb.constant(C.int, 0) - limit = cb.constant(C.int, 100) - - z.assign(zero) - x.assign(one) - with cb.loop() as outer: - with outer.condition() as setcond: - setcond( x < limit ) - - with outer.body(): - y.assign(one) - with cb.loop() as inner: - with inner.condition() as setcond: - setcond( y < limit ) - - with inner.body(): - with cb.ifelse(x > y) as ifelse: - with ifelse.then(): - z += x / y * d - with ifelse.otherwise(): - z += y / x * d - y += one - x += one - - cb.ret(z) - cb.close() - return func - - -class TestNestedLoop(unittest.TestCase): - def test_nestedloop1(self): - mod = Module.new(__name__) - lfunc = gen_nestedloop1(mod) - logging.debug(mod) - mod.verify() - - exe = CExecutor(mod) - func = exe.get_ctype_function(lfunc, 'int, int') - for x in range(1, 100): - self.assertEqual(func(x), int(nestedloop1(x))) - - def test_nestedloop2(self): - mod = Module.new(__name__) - lfunc = gen_nestedloop2(mod) - logging.debug(mod) - mod.verify() - - exe = CExecutor(mod) - func = exe.get_ctype_function(lfunc, 'int, int') - for x in range(1, 100): - self.assertEqual(func(x), int(nestedloop2(x))) - -if __name__ == '__main__': - unittest.main() - diff --git a/tests/test_print.py b/tests/test_print.py deleted file mode 100644 index d971e31..0000000 --- a/tests/test_print.py +++ /dev/null @@ -1,60 +0,0 @@ -from llvm.core import * -from llvm.passes import * -from llvm.ee import * -from llvm_cbuilder import * -import llvm_cbuilder.shortnames as C -import sys, unittest, logging -from subprocess import Popen, PIPE - -def gen_debugprint(mod): - functype = Type.function(C.void, []) - func = mod.add_function(functype, 'debugprint') - - cb = CBuilder(func) - fmt = cb.constant_string("Show %d %.3f %.3e\n") - - an_int = cb.constant(C.int, 123) - a_float = cb.constant(C.double, 1.234) - a_double = cb.constant(C.double, 1e-31) - cb.printf(fmt, an_int, a_float, a_double) - - cb.debug('an_int =', an_int, 'a_float =', a_float, 'a_double =', a_double) - - cb.ret() - cb.close() - return func - -def main_debugprint(): - # generate code - mod = Module.new(__name__) - lfunc = gen_debugprint(mod) - logging.debug(mod) - mod.verify() - # run - exe = CExecutor(mod) - func = exe.get_ctype_function(lfunc, 'void') - func() - -class TestPrint(unittest.TestCase): - def test_debugprint(self): - p = Popen(["python", "test_print.py", "-child"], stdout=PIPE) - p.wait() - - lines = p.stdout.read().decode().splitlines(False) - - expect = [ - 'Show 123 1.234 1.000e-31', - 'an_int = 123 a_float = 1.234000e+00 a_double = 1.000000e-31', - ] - self.assertEqual(expect, lines) - - p.stdout.close() - -if __name__ == '__main__': - try: - if sys.argv[1] == '-child': - main_debugprint() - except IndexError: - unittest.main() - - diff --git a/tests/test_pthread.py b/tests/test_pthread.py deleted file mode 100644 index d1d3a72..0000000 --- a/tests/test_pthread.py +++ /dev/null @@ -1,90 +0,0 @@ -from llvm.core import * -from llvm.passes import * -from llvm.ee import * -from llvm_cbuilder import * -import llvm_cbuilder.shortnames as C -import unittest, logging - -# logging.basicConfig(level=logging.DEBUG) - -NUM_OF_THREAD = 4 - -def gen_test_worker(mod): - cb = CBuilder.new_function(mod, 'worker', C.void, [C.pointer(C.int)]) - pval = cb.args[0] - val = pval.load() - one = cb.constant(val.type, 1) - pval.store(val + one) - cb.ret() - cb.close() - -def gen_test_pthread(mod): - cb = CBuilder.new_function(mod, 'manager', C.int, [C.int]) - arg = cb.args[0] - - worker_func = cb.get_function_named('worker') - pthread_create = cb.get_function_named('pthread_create') - pthread_join = cb.get_function_named('pthread_join') - - - NULL = cb.constant_null(C.void_p) - cast_to_null = lambda x: x.cast(C.void_p) - - threads = cb.array(C.void_p, NUM_OF_THREAD) - - for tid in range(NUM_OF_THREAD): - pthread_create_args = [threads[tid].reference(), - NULL, - worker_func, - arg.reference()] - pthread_create(*map(cast_to_null, pthread_create_args)) - - worker_func(arg.reference()) - - for tid in range(NUM_OF_THREAD): - pthread_join_args = threads[tid], NULL - pthread_join(*map(cast_to_null, pthread_join_args)) - - cb.ret(arg) - cb.close() - return cb.function - -class TestPThread(unittest.TestCase): - def test_pthread(self): - mod = Module.new(__name__) - # add pthread functions - - mod.add_function(Type.function(C.int, - [C.void_p, C.void_p, C.void_p, C.void_p]), - 'pthread_create') - - mod.add_function(Type.function(C.int, - [C.void_p, C.void_p]), - 'pthread_join') - - gen_test_worker(mod) - lf_test_pthread = gen_test_pthread(mod) - logging.debug(mod) - mod.verify() - - exe = CExecutor(mod) - exe.engine.get_pointer_to_function(mod.get_function_named('worker')) - func = exe.get_ctype_function(lf_test_pthread, 'int, int') - - inarg = 1234 - gold = inarg + NUM_OF_THREAD + 1 - self.assertLessEqual(func(inarg), gold) - # Cannot determine the exact return value due to untamed race condition - - count_race = 0 - for _ in range(2**12): - if func(inarg) != gold: - count_race += 1 - - if count_race > 0: - logging.info("Race condition occured %d times.", count_race) - logging.info("Race condition is expected.") - -if __name__ == '__main__': - unittest.main() - diff --git a/tests/test_struct.py b/tests/test_struct.py deleted file mode 100644 index 35048e6..0000000 --- a/tests/test_struct.py +++ /dev/null @@ -1,52 +0,0 @@ -from llvm.core import * -from llvm_cbuilder import * -import llvm_cbuilder.shortnames as C -import unittest, ctypes - -class Vector2D(CStruct): - _fields_ = [ - ('x', C.float), - ('y', C.float), - ] - -class Vector2DCtype(ctypes.Structure): - _fields_ = [ - ('x', ctypes.c_float), - ('y', ctypes.c_float), - ] - -def gen_vector2d_dist(mod): - functype = Type.function(C.float, [C.pointer(Vector2D.llvm_type())]) - func = mod.add_function(functype, 'vector2d_dist') - - cb = CBuilder(func) - vec = cb.var(Vector2D, cb.args[0].load()) - dist = vec.x * vec.x + vec.y * vec.y - - cb.ret(dist) - cb.close() - return func - - -class TestStruct(unittest.TestCase): - def test_vector2d_dist(self): - # prepare module - mod = Module.new('mod') - lfunc = gen_vector2d_dist(mod) - mod.verify() - # run - exe = CExecutor(mod) - func = exe.get_ctype_function(lfunc, ctypes.c_float, ctypes.POINTER(Vector2DCtype)) - - from random import random - pydist = lambda x, y: x * x + y * y - for _ in range(100): - x, y = random(), random() - vec = Vector2DCtype(x=x, y=y) - ans = func(ctypes.pointer(vec)) - gold = pydist(x, y) - - self.assertLess(abs(ans-gold)/gold, 1e-6) - -if __name__ == '__main__': - unittest.main()