From 5ce63d00ccc0ef09abfc65de2576fe9bfe705f46 Mon Sep 17 00:00:00 2001 From: Ilan Schnell Date: Tue, 10 Jul 2012 14:36:38 -0500 Subject: [PATCH 001/675] REL: bump version for release --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 47e94f2..0fd578b 100755 --- a/setup.py +++ b/setup.py @@ -32,7 +32,7 @@ import sys, os from distutils.core import setup, Extension -LLVM_PY_VERSION = '0.8' +LLVM_PY_VERSION = '0.8.1' def _run(cmd): From 635ca202cba23583fc3d0ba365d1c6360b9ee155 Mon Sep 17 00:00:00 2001 From: Ilan Schnell Date: Tue, 10 Jul 2012 14:37:42 -0500 Subject: [PATCH 002/675] REL: master now 0.8.2 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 0fd578b..317d67a 100755 --- a/setup.py +++ b/setup.py @@ -32,7 +32,7 @@ import sys, os from distutils.core import setup, Extension -LLVM_PY_VERSION = '0.8.1' +LLVM_PY_VERSION = '0.8.2' def _run(cmd): From aadf140a065d33d6bc35565e60d7c0b7d4691b24 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Fri, 20 Jul 2012 17:18:28 -0700 Subject: [PATCH 003/675] Added gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b25c15b --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*~ From 9bbeee519b56cff58f1ee8851ec05406ae1e6545 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Fri, 20 Jul 2012 20:15:21 -0700 Subject: [PATCH 004/675] Added Module.id property (getter+setter). Updated test/asm.py to use unittest. --- .gitignore | 1 + llvm/_core.c | 8 ++++++-- llvm/core.py | 9 ++++++++- llvm/extra.cpp | 10 ++++++++++ llvm/extra.h | 11 +++++++++++ test/asm.py | 30 +++++++++++++++++++++--------- 6 files changed, 57 insertions(+), 12 deletions(-) diff --git a/.gitignore b/.gitignore index b25c15b..bdc5af0 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ *~ +build diff --git a/llvm/_core.c b/llvm/_core.c index f9e76fe..50ceee6 100644 --- a/llvm/_core.c +++ b/llvm/_core.c @@ -85,6 +85,8 @@ _wLLVMModuleCreateWithName(PyObject *self, PyObject *args) _wrap_obj2str(LLVMGetDataLayout, LLVMModuleRef) _wrap_objstr2none(LLVMSetDataLayout, LLVMModuleRef) +_wrap_obj2str(LLVMGetModuleIdentifier, LLVMModuleRef) +_wrap_objstr2none(LLVMSetModuleIdentifier, LLVMModuleRef) _wrap_obj2str(LLVMGetTarget, LLVMModuleRef) _wrap_objstr2none(LLVMSetTarget, LLVMModuleRef) _wrap_objstr2none(LLVMModuleAddLibrary, LLVMModuleRef) @@ -94,7 +96,7 @@ _wrap_obj2none(LLVMDisposeModule, LLVMModuleRef) _wrap_dumper(LLVMDumpModuleToString, LLVMModuleRef) _wrap_obj2obj(LLVMModuleGetPointerSize, LLVMModuleRef, int) _wrap_objstrobj2obj(LLVMModuleGetOrInsertFunction, LLVMModuleRef, - LLVMTypeRef, LLVMValueRef) + LLVMTypeRef, LLVMValueRef) static PyObject * _wLLVMVerifyModule(PyObject *self, PyObject *args) @@ -1319,7 +1321,9 @@ static PyMethodDef core_methods[] = { /* Modules */ _method( LLVMModuleCreateWithName ) _method( LLVMGetDataLayout ) - _method( LLVMSetDataLayout ) + _method( LLVMSetDataLayout ) + _method( LLVMGetModuleIdentifier ) + _method( LLVMSetModuleIdentifier ) _method( LLVMGetTarget ) _method( LLVMSetTarget ) _method( LLVMModuleAddLibrary ) diff --git a/llvm/core.py b/llvm/core.py index 0992dde..acbb257 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -507,7 +507,14 @@ class Module(llvm.Ownable, llvm.Cacheable): def add_library(self, name): return _core.LLVMModuleAddLibrary(self.ptr, name) - + + def _get_id(self): + return _core.LLVMGetModuleIdentifier(self.ptr) + + def _set_id(self, string): + _core.LLVMSetModuleIdentifier(self.ptr, string) + + id = property(_get_id, _set_id) #===----------------------------------------------------------------------=== # Types diff --git a/llvm/extra.cpp b/llvm/extra.cpp index d7b33e5..bd65e7b 100644 --- a/llvm/extra.cpp +++ b/llvm/extra.cpp @@ -90,6 +90,16 @@ char *do_print(W obj) return strdup(buf.str().c_str()); } +char *LLVMGetModuleIdentifier(LLVMModuleRef module) +{ + return strdup(llvm::unwrap(module)->getModuleIdentifier().c_str()); +} + +void LLVMSetModuleIdentifier(LLVMModuleRef module, const char * name) +{ + llvm::unwrap(module)->setModuleIdentifier(name); +} + char *LLVMDumpModuleToString(LLVMModuleRef module) { std::string s; diff --git a/llvm/extra.h b/llvm/extra.h index 3bdb070..9e9ae1b 100644 --- a/llvm/extra.h +++ b/llvm/extra.h @@ -41,6 +41,17 @@ extern "C" { #endif + +/* + * Wraps llvm::Module::getModuleIdentifier() + */ +char *LLVMGetModuleIdentifier(LLVMModuleRef module); + +/* + * Wraps llvm::Module::setModuleIdentifier() + */ +void LLVMSetModuleIdentifier(LLVMModuleRef module, const char * name); + /* Notes: * - Some returned strings must be disposed of by LLVMDisposeMessage. These are * indicated in the comments. Where it is not indicated, DO NOT call dispose. diff --git a/test/asm.py b/test/asm.py index 9f028bd..dd564ae 100755 --- a/test/asm.py +++ b/test/asm.py @@ -3,15 +3,27 @@ from llvm import * from llvm.core import * -# create a module -m = Module.new('module1') -m.add_global_variable(Type.int(), 'i') +import unittest -# write it's assembly representation to a file -asm = str(m) -print(asm, file=file("/tmp/testasm.ll", "w")) +class TestAsm(unittest.TestCase): + def test_asm(self): + # create a module + m = Module.new('module1') + m.add_global_variable(Type.int(), 'i') -# read it back into a module -m2 = Module.from_assembly(file("/tmp/testasm.ll")) -print(m2) + # write it's assembly representation to a file + asm = str(m) + with open("/tmp/testasm.ll", "w") as fout: + fout.write(asm) + + # read it back into a module + with open("/tmp/testasm.ll") as fin: + m2 = Module.from_assembly(fin) + # The default `m.id` is ''. + m2.id = m.id # Copy the name from `m` + + self.assertEqual(str(m2).strip(), asm.strip()) + +if __name__ == '__main__': + unittest.main() From a9370d933d3fbf10b1bed38444893a50e3a81aa3 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Fri, 20 Jul 2012 21:46:23 -0700 Subject: [PATCH 005/675] Updated more tests to use unittest. --- test/call-jit-ctypes.py | 93 ++++++++++++----------- test/example-jit.py | 57 ++++++++------ test/example.py | 76 +++++++++++-------- test/intrinsic.py | 161 ++++++++++++++++++++++++---------------- test/issue10.py | 28 ++++--- 5 files changed, 245 insertions(+), 170 deletions(-) diff --git a/test/call-jit-ctypes.py b/test/call-jit-ctypes.py index 735dfd9..ee54bc0 100755 --- a/test/call-jit-ctypes.py +++ b/test/call-jit-ctypes.py @@ -3,61 +3,68 @@ from llvm.core import Module,Type,Builder from llvm.ee import ExecutionEngine import llvm.core + import ctypes -def test_jit_ctypes(): +import logging +import unittest - # This example demonstrates calling an LLVM defined function using - # ctypes. It illustrates the common C pattern of having an output - # variable in the argument list to the function. The function also - # returns an error code upon exit. +class TestCallJITCtypes(unittest.TestCase): + def test_jit_ctypes(self): - # setup llvm types - ty_errcode = Type.int() - ty_float = Type.float() - ty_ptr_float = Type.pointer(Type.float()) - ty_func = Type.function(ty_errcode, [ty_float, ty_float, ty_ptr_float]) + # This example demonstrates calling an LLVM defined function using + # ctypes. It illustrates the common C pattern of having an output + # variable in the argument list to the function. The function also + # returns an error code upon exit. - # setup ctypes types - ct_errcode = ctypes.c_int - ct_float = ctypes.c_float - ct_ptr_float = ctypes.POINTER(ct_float) - ct_argtypes = [ct_float, ct_float, ct_ptr_float] + # setup llvm types + ty_errcode = Type.int() + ty_float = Type.float() + ty_ptr_float = Type.pointer(Type.float()) + ty_func = Type.function(ty_errcode, [ty_float, ty_float, ty_ptr_float]) - # generate the function using LLVM - my_module = Module.new('my_module') + # setup ctypes types + ct_errcode = ctypes.c_int + ct_float = ctypes.c_float + ct_ptr_float = ctypes.POINTER(ct_float) + ct_argtypes = [ct_float, ct_float, ct_ptr_float] - mult = my_module.add_function(ty_func, "mult") - mult.args[0].name = "a" - mult.args[1].name = "b" - mult.args[2].name = "out" - mult.args[2].add_attribute(llvm.core.ATTR_NO_CAPTURE) # add nocapture to output arg - mult.does_not_throw = True # add nounwind attribute to function + # generate the function using LLVM + my_module = Module.new('my_module') - bb = mult.append_basic_block("entry") - builder = Builder.new(bb) - tmp = builder.fmul( mult.args[0], mult.args[1] ) - builder.store( tmp, mult.args[2] ) - builder.ret(llvm.core.Constant.int(ty_errcode, 0)) + mult = my_module.add_function(ty_func, "mult") + mult.args[0].name = "a" + mult.args[1].name = "b" + mult.args[2].name = "out" + # add nocapture to output arg + mult.args[2].add_attribute(llvm.core.ATTR_NO_CAPTURE) + mult.does_not_throw = True # add nounwind attribute to function + + bb = mult.append_basic_block("entry") + builder = Builder.new(bb) + tmp = builder.fmul( mult.args[0], mult.args[1] ) + builder.store( tmp, mult.args[2] ) + builder.ret(llvm.core.Constant.int(ty_errcode, 0)) - if 0: # print the created module - print(my_module) + logging.debug(my_module) - # compile the function - ee = ExecutionEngine.new(my_module) + # compile the function + ee = ExecutionEngine.new(my_module) - # let ctypes know about the function - func_ptr_int = ee.get_pointer_to_function( mult ) - FUNC_TYPE = ctypes.CFUNCTYPE(ct_errcode, *ct_argtypes) - py_mult = FUNC_TYPE(func_ptr_int) + # let ctypes know about the function + func_ptr_int = ee.get_pointer_to_function( mult ) + FUNC_TYPE = ctypes.CFUNCTYPE(ct_errcode, *ct_argtypes) + py_mult = FUNC_TYPE(func_ptr_int) - # now run the function, calling via ctypes - output_value = ct_float(123456.0) - errcode = py_mult( 2.0, 3.0, ctypes.byref(output_value) ) - if errcode != 0: - raise RuntimeError('unexpected error') - assert output_value.value == 6.0 + # now run the function, calling via ctypes + output_value = ct_float(123456.0) + errcode = py_mult( 2.0, 3.0, ctypes.byref(output_value) ) + + self.assertEqual(errcode, 0, msg='unexpected error') + + self.assertEqual(output_value.value, 6.0) if __name__=='__main__': - test_jit_ctypes() + unittest.main() + diff --git a/test/example-jit.py b/test/example-jit.py index 3a4e88b..67556f1 100755 --- a/test/example-jit.py +++ b/test/example-jit.py @@ -5,29 +5,44 @@ from llvm import * from llvm.core import * from llvm.ee import * # new import: ee = Execution Engine -# Create a module, as in the previous example. -my_module = Module.new('my_module') -ty_int = Type.int() # by default 32 bits -ty_func = Type.function(ty_int, [ty_int, ty_int]) -f_sum = my_module.add_function(ty_func, "sum") -f_sum.args[0].name = "a" -f_sum.args[1].name = "b" -bb = f_sum.append_basic_block("entry") -builder = Builder.new(bb) -tmp = builder.add(f_sum.args[0], f_sum.args[1], "tmp") -builder.ret(tmp) +import logging +import unittest -# Create an execution engine object. This will create a JIT compiler -# on platforms that support it, or an interpreter otherwise. -ee = ExecutionEngine.new(my_module) -# The arguments needs to be passed as "GenericValue" objects. -arg1 = GenericValue.int(ty_int, 100) -arg2 = GenericValue.int(ty_int, 42) +class TestExampleJIT(unittest.TestCase): + def test_example_jit(self): + # Create a module, as in the previous example. + my_module = Module.new('my_module') + ty_int = Type.int() # by default 32 bits + ty_func = Type.function(ty_int, [ty_int, ty_int]) + f_sum = my_module.add_function(ty_func, "sum") + f_sum.args[0].name = "a" + f_sum.args[1].name = "b" + bb = f_sum.append_basic_block("entry") + builder = Builder.new(bb) + tmp = builder.add(f_sum.args[0], f_sum.args[1], "tmp") + builder.ret(tmp) -# Now let's compile and run! -retval = ee.run_function(f_sum, [arg1, arg2]) + # Create an execution engine object. This will create a JIT compiler + # on platforms that support it, or an interpreter otherwise. + ee = ExecutionEngine.new(my_module) -# The return value is also GenericValue. Let's print it. -print("returned", retval.as_int()) + # The arguments needs to be passed as "GenericValue" objects. + arg1_value = 100 + arg2_value = 42 + + arg1 = GenericValue.int(ty_int, arg1_value) + arg2 = GenericValue.int(ty_int, arg2_value) + + # Now let's compile and run! + retval = ee.run_function(f_sum, [arg1, arg2]) + + # The return value is also GenericValue. Let's print it. + logging.debug("returned %d", retval.as_int()) + + self.assertEqual(retval.as_int(), (arg1_value + arg2_value)) + + +if __name__ == '__main__': + unittest.main() diff --git a/test/example.py b/test/example.py index 8c8b17e..58c4ce4 100755 --- a/test/example.py +++ b/test/example.py @@ -4,42 +4,58 @@ from llvm import * from llvm.core import * -# Create an (empty) module. -my_module = Module.new('my_module') +import logging +import unittest -# All the types involved here are "int"s. This type is represented -# by an object of the llvm.core.Type class: -ty_int = Type.int() # by default 32 bits -# We need to represent the class of functions that accept two integers -# and return an integer. This is represented by an object of the -# function type (llvm.core.FunctionType): -ty_func = Type.function(ty_int, [ty_int, ty_int]) +class TestExample(unittest.TestCase): + def test_example(self): + # Create an (empty) module. + my_module = Module.new('my_module') -# Now we need a function named 'sum' of this type. Functions are not -# free-standing (in llvm-py); it needs to be contained in a module. -f_sum = my_module.add_function(ty_func, "sum") + # All the types involved here are "int"s. This type is represented + # by an object of the llvm.core.Type class: + ty_int = Type.int() # by default 32 bits -# Let's name the function arguments as 'a' and 'b'. -f_sum.args[0].name = "a" -f_sum.args[1].name = "b" + # We need to represent the class of functions that accept two integers + # and return an integer. This is represented by an object of the + # function type (llvm.core.FunctionType): + ty_func = Type.function(ty_int, [ty_int, ty_int]) -# Our function needs a "basic block" -- a set of instructions that -# end with a terminator (like return, branch etc.). By convention -# the first block is called "entry". -bb = f_sum.append_basic_block("entry") + # Now we need a function named 'sum' of this type. Functions are not + # free-standing (in llvm-py); it needs to be contained in a module. + f_sum = my_module.add_function(ty_func, "sum") -# Let's add instructions into the block. For this, we need an -# instruction builder: -builder = Builder.new(bb) + self.assertEqual(str(f_sum).strip(), 'declare i32 @sum(i32, i32)') -# OK, now for the instructions themselves. We'll create an add -# instruction that returns the sum as a value, which we'll use -# a ret instruction to return. -tmp = builder.add(f_sum.args[0], f_sum.args[1], "tmp") -builder.ret(tmp) + # Let's name the function arguments as 'a' and 'b'. + f_sum.args[0].name = "a" + f_sum.args[1].name = "b" -# We've completed the definition now! Let's see the LLVM assembly -# language representation of what we've created: -print(my_module) + # Our function needs a "basic block" -- a set of instructions that + # end with a terminator (like return, branch etc.). By convention + # the first block is called "entry". + bb = f_sum.append_basic_block("entry") + + # Let's add instructions into the block. For this, we need an + # instruction builder: + builder = Builder.new(bb) + + # OK, now for the instructions themselves. We'll create an add + # instruction that returns the sum as a value, which we'll use + # a ret instruction to return. + tmp = builder.add(f_sum.args[0], f_sum.args[1], "tmp") + + self.assertEqual(str(tmp).strip(), '%tmp = add i32 %a, %b') + + builder.ret(tmp) + + # We've completed the definition now! Let's see the LLVM assembly + # language representation of what we've created: + logging.debug(my_module) + + + +if __name__ == '__main__': + unittest.main() diff --git a/test/intrinsic.py b/test/intrinsic.py index e9e4cfe..34c70c8 100755 --- a/test/intrinsic.py +++ b/test/intrinsic.py @@ -5,75 +5,106 @@ from llvm.core import * from llvm.ee import * -# setup a function and a builder -mod = Module.new('test') -functy = Type.function(Type.void(), []) -func = mod.add_function(functy, "showme") -block = func.append_basic_block("entry") -b = Builder.new(block) +import logging +import unittest +import math -# let's do bswap on a 32-bit integer using llvm.bswap -val = Constant.int(Type.int(), 42) -bswap = Function.intrinsic(mod, INTR_BSWAP, [Type.int()]) -b.call(bswap, [val]) -print(mod) +class TestIntrinsic(unittest.TestCase): + def test_bswap(self): + # setup a function and a builder + mod = Module.new('test') + functy = Type.function(Type.int(), []) + func = mod.add_function(functy, "showme") + block = func.append_basic_block("entry") + b = Builder.new(block) -# the output is: -# -# ; ModuleID = 'test' -# -# define void @showme() { -# entry: -# call i32 @llvm.bswap.i32( i32 42 ) ; :0 [#uses=0] -# } -# -# declare i32 @llvm.bswap.i32(i32) nounwind readnone -# + # let's do bswap on a 32-bit integer using llvm.bswap + val = Constant.int(Type.int(), 0x42) + bswap = Function.intrinsic(mod, INTR_BSWAP, [Type.int()]) -# mysin(x) = sqrt(1.0 - pow(cos(x), 2)) + bswap_res = b.call(bswap, [val]) + b.ret(bswap_res) -float = Type.float() -mysinty = Type.function( float, [float] ) -mysin = mod.add_function(mysinty, "mysin") -block = mysin.append_basic_block("entry") -b = Builder.new(block) + # see the generated IR + logging.debug(mod) -sqrt = Function.intrinsic(mod, INTR_SQRT, [float]) -pow = Function.intrinsic(mod, INTR_POWI, [float]) -cos = Function.intrinsic(mod, INTR_COS, [float]) + # the output is: + # + # ; ModuleID = 'test' + # + # define void @showme() { + # entry: + # %0 = call i32 @llvm.bswap.i32(i32 42) + # ret i32 %0 + # } -mysin.args[0].name = "x" -x = mysin.args[0] -one = Constant.real(float, "1") -cosx = b.call(cos, [x], "cosx") -cos2 = b.call(pow, [cosx, Constant.int(Type.int(), 2)], "cos2") -onemc2 = b.sub(one, cos2, "onemc2") -sin = b.call(sqrt, [onemc2], "sin") -b.ret(sin) -print(mod) + # let's run the function + ee = ExecutionEngine.new(mod) + retval = ee.run_function(func, []) + self.assertEqual(retval.as_int(), 0x42000000) + + + def test_mysin(self): + # mysin(x) = sqrt(1.0 - pow(cos(x), 2)) + mod = Module.new('test') + + float = Type.float() + mysinty = Type.function( float, [float] ) + mysin = mod.add_function(mysinty, "mysin") + block = mysin.append_basic_block("entry") + b = Builder.new(block) + + sqrt = Function.intrinsic(mod, INTR_SQRT, [float]) + pow = Function.intrinsic(mod, INTR_POWI, [float]) + cos = Function.intrinsic(mod, INTR_COS, [float]) + + mysin.args[0].name = "x" + x = mysin.args[0] + one = Constant.real(float, "1") + cosx = b.call(cos, [x], "cosx") + cos2 = b.call(pow, [cosx, Constant.int(Type.int(), 2)], "cos2") + onemc2 = b.fsub(one, cos2, "onemc2") # Should use fsub + sin = b.call(sqrt, [onemc2], "sin") + b.ret(sin) + + logging.debug(mod) + + # + # ; ModuleID = 'test' + # + # define void @showme() { + # entry: + # call i32 @llvm.bswap.i32( i32 42 ) ; :0 [#uses=0] + # } + # + # declare i32 @llvm.bswap.i32(i32) nounwind readnone + # + # define float @mysin(float %x) { + # entry: + # %cosx = call float @llvm.cos.f32( float %x ) ; [#uses=1] + # %cos2 = call float @llvm.powi.f32( float %cosx, i32 2 ) ; [#uses=1] + # %onemc2 = sub float 1.000000e+00, %cos2 ; [#uses=1] + # %sin = call float @llvm.sqrt.f32( float %onemc2 ) ; [#uses=1] + # ret float %sin + # } + # + # declare float @llvm.sqrt.f32(float) nounwind readnone + # + # declare float @llvm.powi.f32(float, i32) nounwind readnone + # + # declare float @llvm.cos.f32(float) nounwind readnone + # + + # let's run the function + ee = ExecutionEngine.new(mod) + arg = GenericValue.real(Type.float(), 1.234) + retval = ee.run_function(mysin, [arg]) + + golden = math.sin(1.234) + answer = retval.as_real(Type.float()) + self.assertLess(abs(answer-golden)/golden, 1e-5) + + +if __name__ == '__main__': + unittest.main() -# -# ; ModuleID = 'test' -# -# define void @showme() { -# entry: -# call i32 @llvm.bswap.i32( i32 42 ) ; :0 [#uses=0] -# } -# -# declare i32 @llvm.bswap.i32(i32) nounwind readnone -# -# define float @mysin(float %x) { -# entry: -# %cosx = call float @llvm.cos.f32( float %x ) ; [#uses=1] -# %cos2 = call float @llvm.powi.f32( float %cosx, i32 2 ) ; [#uses=1] -# %onemc2 = sub float 1.000000e+00, %cos2 ; [#uses=1] -# %sin = call float @llvm.sqrt.f32( float %onemc2 ) ; [#uses=1] -# ret float %sin -# } -# -# declare float @llvm.sqrt.f32(float) nounwind readnone -# -# declare float @llvm.powi.f32(float, i32) nounwind readnone -# -# declare float @llvm.cos.f32(float) nounwind readnone -# diff --git a/test/issue10.py b/test/issue10.py index 2969564..9c654f4 100755 --- a/test/issue10.py +++ b/test/issue10.py @@ -1,21 +1,27 @@ #!/usr/bin/env python from llvm.core import * -import llvm._core -m = Module.new('a') -ti = Type.int() -tf = Type.function(ti, [ti, ti]) +import unittest -f = m.add_function(tf, "func1") +class TestIssue10(unittest.TestCase): + def test_issue10(self): + m = Module.new('a') + ti = Type.int() + tf = Type.function(ti, [ti, ti]) -bb = f.append_basic_block('entry') + f = m.add_function(tf, "func1") -b = Builder.new(bb) + bb = f.append_basic_block('entry') -# There are no instructions in bb. Positioning of the -# builder at beginning (or end) should succeed (trivially). + b = Builder.new(bb) -b.position_at_end(bb) -b.position_at_beginning(bb) + # There are no instructions in bb. Positioning of the + # builder at beginning (or end) should succeed (trivially). + + b.position_at_end(bb) + b.position_at_beginning(bb) + +if __name__ == '__main__': + unittest.main() From badac267cc2486e910ab60cfaba07f43d92c6c7a Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Sat, 21 Jul 2012 15:57:39 -0700 Subject: [PATCH 006/675] Fix: Object cache was removing objects properly. Continue to update test to use unittest. --- llvm/__init__.py | 5 +- test/objcache.py | 163 +++++++++++++++++++++++------------------------ 2 files changed, 84 insertions(+), 84 deletions(-) diff --git a/llvm/__init__.py b/llvm/__init__.py index 9128c70..a537015 100644 --- a/llvm/__init__.py +++ b/llvm/__init__.py @@ -128,8 +128,9 @@ class _ObjectCache(type): @staticmethod def forget(obj): objid = _core.PyCObjectVoidPtrToPyLong(obj.ptr) - if objid in _ObjectCache.__instances: - del _ObjectCache.__instances[objid] + key = "%s:%d" % (type(obj).__name__, objid) + if key in _ObjectCache.__instances: + del _ObjectCache.__instances[key] #===----------------------------------------------------------------------=== diff --git a/test/objcache.py b/test/objcache.py index f978f80..7342439 100755 --- a/test/objcache.py +++ b/test/objcache.py @@ -2,107 +2,106 @@ from llvm.core import * -def check(a, b): - if a is b: - print("OK") - else: - print("FAIL") +import logging, unittest -def check_isnot(a, b): - if not (a is b): - print("OK") - else: - print("FAIL") +class TestObjCache(unittest.TestCase): + def test_objcache(self): + logging.debug("Testing module aliasing ..") + m1 = Module.new('a') + t = Type.int() + ft = Type.function(t, [t]) + f1 = m1.add_function(ft, "func") + m2 = f1.module + self.assertIs(m1, m2) -print("Testing module aliasing ..", end=' ') -m1 = Module.new('a') -t = Type.int() -ft = Type.function(t, [t]) -f1 = m1.add_function(ft, "func") -m2 = f1.module -check(m1, m2) + logging.debug("Testing global vairable aliasing 1 .. ") + gv1 = GlobalVariable.new(m1, t, "gv") + gv2 = GlobalVariable.get(m1, "gv") + self.assertIs(gv1, gv2) -print("Testing global vairable aliasing 1 .. ", end=' ') -gv1 = GlobalVariable.new(m1, t, "gv") -gv2 = GlobalVariable.get(m1, "gv") -check(gv1, gv2) + logging.debug("Testing global vairable aliasing 2 .. ") + gv3 = m1.global_variables[0] + self.assertIs(gv1, gv3) -print("Testing global vairable aliasing 2 .. ", end=' ') -gv3 = m1.global_variables[0] -check(gv1, gv3) + logging.debug("Testing global vairable aliasing 3 .. ") -print("Testing global vairable aliasing 3 .. ", end=' ') -gv2 = None -gv3 = None -gv1.delete() -gv4 = GlobalVariable.new(m1, t, "gv") -check_isnot(gv1, gv4) + gv2 = None + gv3 = None -print("Testing function aliasing 1 ..", end=' ') -b1 = f1.append_basic_block('entry') -f2 = b1.function -check(f1, f2) + gv1.delete() + gv4 = GlobalVariable.new(m1, t, "gv") -print("Testing function aliasing 2 ..", end=' ') -f3 = m1.get_function_named("func") -check(f1, f3) + self.assertIsNot(gv1, gv4) -print("Testing function aliasing 3 ..", end=' ') -f4 = Function.get_or_insert(m1, ft, "func") -check(f1, f4) + logging.debug("Testing function aliasing 1 ..") + b1 = f1.append_basic_block('entry') + f2 = b1.function + self.assertIs(f1, f2) -print("Testing function aliasing 4 ..", end=' ') -f5 = Function.get(m1, "func") -check(f1, f5) + logging.debug("Testing function aliasing 2 ..") + f3 = m1.get_function_named("func") + self.assertIs(f1, f3) -print("Testing function aliasing 5 ..", end=' ') -f6 = m1.get_or_insert_function(ft, "func") -check(f1, f6) + logging.debug("Testing function aliasing 3 ..") + f4 = Function.get_or_insert(m1, ft, "func") + self.assertIs(f1, f4) -print("Testing function aliasing 6 ..", end=' ') -f7 = m1.functions[0] -check(f1, f7) + logging.debug("Testing function aliasing 4 ..") + f5 = Function.get(m1, "func") + self.assertIs(f1, f5) -print("Testing argument aliasing .. ", end=' ') -a1 = f1.args[0] -a2 = f1.args[0] -check(a1, a2) + logging.debug("Testing function aliasing 5 ..") + f6 = m1.get_or_insert_function(ft, "func") + self.assertIs(f1, f6) -print("Testing basic block aliasing 1 .. ", end=' ') -b2 = f1.basic_blocks[0] -check(b1, b2) + logging.debug("Testing function aliasing 6 ..") + f7 = m1.functions[0] + self.assertIs(f1, f7) -print("Testing basic block aliasing 2 .. ", end=' ') -b3 = f1.get_entry_basic_block() -check(b1, b3) + logging.debug("Testing argument aliasing .. ") + a1 = f1.args[0] + a2 = f1.args[0] + self.assertIs(a1, a2) -print("Testing basic block aliasing 3 .. ", end=' ') -b31 = f1.entry_basic_block -check(b1, b31) + logging.debug("Testing basic block aliasing 1 .. ") + b2 = f1.basic_blocks[0] + self.assertIs(b1, b2) -print("Testing basic block aliasing 4 .. ", end=' ') -bldr = Builder.new(b1) -b4 = bldr.basic_block -check(b1, b4) + logging.debug("Testing basic block aliasing 2 .. ") + b3 = f1.get_entry_basic_block() + self.assertIs(b1, b3) -print("Testing basic block aliasing 5 .. ", end=' ') -i1 = bldr.ret_void() -b5 = i1.basic_block -check(b1, b5) + logging.debug("Testing basic block aliasing 3 .. ") + b31 = f1.entry_basic_block + self.assertIs(b1, b31) -print("Testing instruction aliasing 1 .. ", end=' ') -i2 = b5.instructions[0] -check(i1, i2) + logging.debug("Testing basic block aliasing 4 .. ") + bldr = Builder.new(b1) + b4 = bldr.basic_block + self.assertIs(b1, b4) -# phi node -phi = bldr.phi(t) -phi.add_incoming(f1.args[0], b1) -v2 = phi.get_incoming_value(0) -b6 = phi.get_incoming_block(0) + logging.debug("Testing basic block aliasing 5 .. ") + i1 = bldr.ret_void() + b5 = i1.basic_block + self.assertIs(b1, b5) -print("Testing PHI / basic block aliasing 5 .. ", end=' ') -check(b1, b6) + logging.debug("Testing instruction aliasing 1 .. ") + i2 = b5.instructions[0] + self.assertIs(i1, i2) -print("Testing PHI / value aliasing .. ", end=' ') -check(f1.args[0], v2) + # phi node + phi = bldr.phi(t) + phi.add_incoming(f1.args[0], b1) + v2 = phi.get_incoming_value(0) + b6 = phi.get_incoming_block(0) + logging.debug("Testing PHI / basic block aliasing 5 .. ") + self.assertIs(b1, b6) + + logging.debug("Testing PHI / value aliasing .. ") + self.assertIs(f1.args[0], v2) + + + +if __name__ == '__main__': + unittest.main() From c68c5b0aac09d5a9d816c59d105ba4c90bbfb3f0 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Sat, 21 Jul 2012 20:27:14 -0700 Subject: [PATCH 007/675] Continue to update test to use unittest. Replace custom class strstream with StringIO. --- test/operands.py | 92 +++++++++++++++++++++++++----------------------- test/passes.py | 85 +++++++++++++++++++++++++++++--------------- 2 files changed, 104 insertions(+), 73 deletions(-) diff --git a/test/operands.py b/test/operands.py index 36a4c85..b1a47ac 100755 --- a/test/operands.py +++ b/test/operands.py @@ -3,6 +3,8 @@ # Tests accessing of instruction operands. from llvm.core import * +from StringIO import StringIO +import logging, unittest m = None @@ -24,54 +26,54 @@ entry: ret i32 %tmp3 } """ -class strstream(object): - def __init__(self): pass - def read(self): return test_module -m = Module.from_assembly(strstream()) -print("-"*60) -print(m) -print("-"*60) -test_func = m.get_function_named("test_func") -prod = m.get_function_named("prod") +class TestOperands(unittest.TestCase): + def test_operands(self): + m = Module.from_assembly(StringIO(test_module)) + logging.debug("-"*60) + logging.debug(m) + logging.debug("-"*60) -#===----------------------------------------------------------------------=== -# test operands + test_func = m.get_function_named("test_func") + prod = m.get_function_named("prod") -print() -i1 = test_func.basic_blocks[0].instructions[0] -i2 = test_func.basic_blocks[0].instructions[1] -print("Testing User.operand_count ..", end=' ') -if i1.operand_count == 3 and i2.operand_count == 2: - print("OK") -else: - print("FAIL") + #===----------------------------------------------------------------------=== + # test operands -print("Testing User.operands ..", end=' ') -c1 = i1.operands[0] is prod -c2 = i1.operands[1] is test_func.args[0] -c3 = i1.operands[2] is test_func.args[1] -c4 = i2.operands[0] is i1 -c5 = i2.operands[1] is test_func.args[2] -c6 = len(i1.operands) == 3 -c7 = len(i2.operands) == 2 -if c1 and c2 and c3 and c5 and c6 and c7: - print("OK") -else: - print("FAIL") -print() -#===----------------------------------------------------------------------=== -# show test_function + i1 = test_func.basic_blocks[0].instructions[0] + i2 = test_func.basic_blocks[0].instructions[1] + logging.debug("Testing User.operand_count ..") + + self.assertEqual(i1.operand_count, 3) + self.assertEqual(i2.operand_count, 2) + + logging.debug("Testing User.operands ..") + + self.assertIs(i1.operands[-1], prod) + self.assertIs(i1.operands[0], test_func.args[0]) + self.assertIs(i1.operands[1], test_func.args[1]) + self.assertIs(i2.operands[0], i1) + self.assertIs(i2.operands[1], test_func.args[2]) + self.assertEqual(len(i1.operands), 3) + self.assertEqual(len(i2.operands), 2) + + #===----------------------------------------------------------------------=== + # show test_function + + logging.debug("Examining test_function `test_test_func':") + + idx = 1 + for inst in test_func.basic_blocks[0].instructions: + logging.debug("Instruction #%d:", idx) + logging.debug(" operand_count = %d", inst.operand_count) + logging.debug(" operands:") + oidx = 1 + for op in inst.operands: + logging.debug(" %d: %s", oidx, repr(op)) + oidx += 1 + idx += 1 + +if __name__ == '__main__': + unittest.main() -print("Examining test_function `test_test_func':") -idx = 1 -for inst in test_func.basic_blocks[0].instructions: - print("Instruction #%d:" % (idx,)) - print(" operand_count =", inst.operand_count) - print(" operands:") - oidx = 1 - for op in inst.operands: - print(" %d: %s" % (oidx, repr(op))) - oidx += 1 - idx += 1 diff --git a/test/passes.py b/test/passes.py index 03447e9..669bdf3 100755 --- a/test/passes.py +++ b/test/passes.py @@ -4,6 +4,10 @@ from llvm.core import * from llvm.passes import * from llvm.ee import * +from StringIO import StringIO + +import logging, unittest + # A helper class. class strstream(object): def __init__(self, s): @@ -35,43 +39,68 @@ entry: ret i32 %tmp } """ -m = Module.from_assembly(strstream(asm)) -print("-"*72) -print(m) -# Let's run a module-level inlining pass. First, create a pass manager. -pm = PassManager.new() +class TestPasses(unittest.TestCase): + def test_passes(self): + m = Module.from_assembly(StringIO(asm)) + logging.debug("-"*72) + logging.debug(m) -# Add the target data as the first "pass". This is mandatory. -pm.add( TargetData.new('') ) + fn_test1 = m.get_function_named('test1') + fn_test2 = m.get_function_named('test2') -# Add the inlining pass. -pm.add( PASS_FUNCTION_INLINING ) + original_test1 = str(fn_test1) + original_test2 = str(fn_test2) -# Run it! -pm.run(m) + # Let's run a module-level inlining pass. First, create a pass manager. + pm = PassManager.new() -# Done with the pass manager. -del pm + # Add the target data as the first "pass". This is mandatory. + pm.add( TargetData.new('') ) -# Print the result. Note the change in @test2. -print("-"*72) -print(m) + # Add the inlining pass. + pm.add( PASS_FUNCTION_INLINING ) + + # Run it! + pm.run(m) -# Let's run a DCE pass on the the function 'test1' now. First create a -# function pass manager. -fpm = FunctionPassManager.new(m) + # Done with the pass manager. + del pm -# Add the target data as first "pass". This is mandatory. -fpm.add( TargetData.new('') ) + # Print the result. Note the change in @test2. + logging.debug("-"*72) + logging.debug(m) -# Add a DCE pass -fpm.add( PASS_AGGRESSIVE_DCE ) + # Make sure test2 is inlined + self.assertNotEqual(str(fn_test2).strip(), original_test2.strip()) -# Run the pass on the function 'test1' -fpm.run( m.get_function_named('test1') ) + bb_entry = fn_test2.basic_blocks[0] + + self.assertEqual(len(bb_entry.instructions), 1) + self.assertEqual(bb_entry.instructions[0].opcode_name, 'ret') + + # Let's run a DCE pass on the the function 'test1' now. First create a + # function pass manager. + fpm = FunctionPassManager.new(m) + + # Add the target data as first "pass". This is mandatory. + fpm.add( TargetData.new('') ) + + # Add a DCE pass + fpm.add( PASS_AGGRESSIVE_DCE ) + + # Run the pass on the function 'test1' + fpm.run( m.get_function_named('test1') ) + + # Print the result. Note the change in @test1. + logging.debug("-"*72) + logging.debug(m) + + # Make sure test1 is modified + self.assertNotEqual(str(fn_test1).strip(), original_test1.strip()) + + +if __name__ == '__main__': + unittest.main() -# Print the result. Note the change in @test1. -print("-"*72) -print(m) From b71d22b5707b6a28dccb80b01a55cbb99b9ec9f4 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Sun, 22 Jul 2012 00:00:04 -0700 Subject: [PATCH 008/675] Update StructType to LLVM 3.x (incomplete). Bring back StructType.elements. --- llvm/_core.c | 486 +++++++++++++++++++++++++------------------------ llvm/core.py | 49 +++-- llvm/extra.cpp | 19 ++ llvm/extra.h | 15 ++ llvm/wrap.h | 118 +++++++++--- test/test.py | 57 ++++-- 6 files changed, 444 insertions(+), 300 deletions(-) diff --git a/llvm/_core.c b/llvm/_core.c index 50ceee6..63b6ad5 100644 --- a/llvm/_core.c +++ b/llvm/_core.c @@ -11,7 +11,7 @@ * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * - * * Neither the name of this software, nor the names of its + * * Neither the name of this software, nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * @@ -53,7 +53,7 @@ typedef int Py_ssize_t; #endif /* Project-wide setting */ -#if (PY_MAJOR_VERSION >= 3) +#if (PY_MAJOR_VERSION >= 3) #define LLVM_PY_USE_PYCAPSULE #endif @@ -72,13 +72,13 @@ _wLLVMModuleCreateWithName(PyObject *self, PyObject *args) if (!PyArg_ParseTuple(args, "U:LLVMModuleCreateWithName", &s_)) { return NULL; } - + s = PyUnicode_AS_DATA(s_); #else if (!PyArg_ParseTuple(args, "s", &s)) return NULL; #endif - + module = LLVMModuleCreateWithName(s); return ctor_LLVMModuleRef(module); } @@ -95,8 +95,8 @@ _wrap_obj2none(LLVMDumpModule, LLVMModuleRef) _wrap_obj2none(LLVMDisposeModule, LLVMModuleRef) _wrap_dumper(LLVMDumpModuleToString, LLVMModuleRef) _wrap_obj2obj(LLVMModuleGetPointerSize, LLVMModuleRef, int) -_wrap_objstrobj2obj(LLVMModuleGetOrInsertFunction, LLVMModuleRef, - LLVMTypeRef, LLVMValueRef) +_wrap_objstrobj2obj(LLVMModuleGetOrInsertFunction, LLVMModuleRef, + LLVMTypeRef, LLVMValueRef) static PyObject * _wLLVMVerifyModule(PyObject *self, PyObject *args) @@ -188,7 +188,7 @@ static PyObject * _wLLVMLinkModules(PyObject *self, PyObject *args) { PyObject *dest_obj, *src_obj, *ret; - LLVMModuleRef dest, src; + LLVMModuleRef dest, src; char *errmsg; unsigned int mode = 0; @@ -212,7 +212,7 @@ _wLLVMLinkModules(PyObject *self, PyObject *args) } return ret; } - + /* note: success => None, failure => string with error message */ Py_RETURN_NONE; } @@ -298,15 +298,19 @@ _wLLVMGetFunctionTypeParams(PyObject *self, PyObject *args) /*===-- Struct types -----------------------------------------------------===*/ _wrap_listint2obj(LLVMStructType, LLVMTypeRef, LLVMTypeRef) +_wrap_str2obj(LLVMStructTypeIdentified, LLVMTypeRef) +_wrap_objlistint2none(LLVMSetStructBody, LLVMTypeRef, LLVMTypeRef) _wrap_obj2obj(LLVMCountStructElementTypes, LLVMTypeRef, int) +_wrap_obj2str(LLVMGetStructName, LLVMTypeRef) +_wrap_objstr2none(LLVMSetStructName, LLVMTypeRef) + -/* static PyObject * _wLLVMGetStructElementTypes(PyObject *self, PyObject *args) { return obj2arr(self, args, LLVMCountStructElementTypes, LLVMGetStructElementTypes); } -*/ + _wrap_obj2obj(LLVMIsPackedStruct, LLVMTypeRef, int) @@ -398,13 +402,13 @@ _wLLVMConstInt(PyObject *self, PyObject *args) int sign_extend; LLVMTypeRef ty; LLVMValueRef val; - + if (!PyArg_ParseTuple(args, "OKi", &obj, &n, &sign_extend)) return NULL; #ifdef LLVM_PY_USE_PYCAPSULE ty = (LLVMTypeRef) PyCapsule_GetPointer(obj, NULL); -#else +#else ty = (LLVMTypeRef)(PyCObject_AsVoidPtr(obj)); #endif @@ -419,10 +423,10 @@ _wLLVMConstReal(PyObject *self, PyObject *args) double d; LLVMTypeRef ty; LLVMValueRef val; - + if (!PyArg_ParseTuple(args, "Od", &obj, &d)) return NULL; - + #ifdef LLVM_PY_USE_PYCAPSULE ty = (LLVMTypeRef) PyCapsule_GetPointer(obj, NULL); #else @@ -449,13 +453,13 @@ _wLLVMConstString(PyObject *self, PyObject *args) if (!PyArg_ParseTuple(args, "Ui:LLVMConstString", &s_, &dont_null_terminate)) { return NULL; } - + s = PyUnicode_AS_DATA(s_); -#else +#else if (!PyArg_ParseTuple(args, "si", &s, &dont_null_terminate)) return NULL; #endif - + val = LLVMConstString(s, strlen(s), dont_null_terminate); return ctor_LLVMValueRef(val); } @@ -520,7 +524,7 @@ _wrap_objobjobj2obj(LLVMConstShuffleVector, LLVMValueRef, LLVMValueRef, LLVMValu _wrap_obj2obj(LLVMGetGlobalParent, LLVMValueRef, LLVMModuleRef) _wrap_obj2obj(LLVMIsDeclaration, LLVMValueRef, int) _wrap_obj2obj(LLVMGetLinkage, LLVMValueRef, int) -_wrap_objenum2none(LLVMSetLinkage, LLVMValueRef, LLVMLinkage) +_wrap_objenum2none(LLVMSetLinkage, LLVMValueRef, LLVMLinkage) _wrap_obj2str(LLVMGetSection, LLVMValueRef) _wrap_objstr2none(LLVMSetSection, LLVMValueRef) _wrap_obj2obj(LLVMGetVisibility, LLVMValueRef, int) @@ -545,7 +549,7 @@ _wrap_obj2obj(LLVMIsGlobalConstant, LLVMValueRef, int) /*===-- Functions --------------------------------------------------------===*/ -_wrap_objstrobj2obj(LLVMAddFunction, LLVMModuleRef, LLVMTypeRef, LLVMValueRef) +_wrap_objstrobj2obj(LLVMAddFunction, LLVMModuleRef, LLVMTypeRef, LLVMValueRef) _wrap_objstr2obj(LLVMGetNamedFunction, LLVMModuleRef, LLVMValueRef) _wrap_obj2obj(LLVMGetFirstFunction, LLVMModuleRef, LLVMValueRef) _wrap_obj2obj(LLVMGetNextFunction, LLVMValueRef, LLVMValueRef) @@ -675,12 +679,12 @@ _wLLVMBuildInvoke(PyObject *self, PyObject *args) if (!PyArg_ParseTuple(args, "OOOOOU:LLVMBuildInvoke", &obj1, &obj2, &obj3, &obj4, &obj5, &name_)) { return NULL; } - + name = PyUnicode_AS_DATA(name_); #else if (!PyArg_ParseTuple(args, "OOOOOs", &obj1, &obj2, &obj3, &obj4, &obj5, &name)) return NULL; -#endif +#endif #ifdef LLVM_PY_USE_PYCAPSULE builder = (LLVMBuilderRef) PyCapsule_GetPointer(obj1, NULL); @@ -694,7 +698,7 @@ _wLLVMBuildInvoke(PyObject *self, PyObject *args) fnargs = (LLVMValueRef *)make_array_from_list(obj3, fnarg_count); if (!fnargs) return PyErr_NoMemory(); - + #ifdef LLVM_PY_USE_PYCAPSULE then_blk = (LLVMBasicBlockRef) PyCapsule_GetPointer(obj4, NULL); catch_blk = (LLVMBasicBlockRef) PyCapsule_GetPointer(obj5, NULL); @@ -799,13 +803,13 @@ _wLLVMCreateMemoryBufferWithContentsOfFile(PyObject *self, PyObject *args) if (!PyArg_ParseTuple(args, "U:LLVMCreateMemoryBufferWithContentsOfFile", &path_)) { return NULL; } - + path = PyUnicode_AS_DATA(path_); #else if (!PyArg_ParseTuple(args, "s", &path)) return NULL; #endif - + if (!LLVMCreateMemoryBufferWithContentsOfFile(path, &ref, &outmsg)) { ret = ctor_LLVMMemoryBufferRef(ref); } else { @@ -980,10 +984,10 @@ _wrap_objobj2obj(LLVMCallFrameAlignmentOfType, LLVMTargetDataRef, LLVMTypeRef, int) _wrap_objobj2obj(LLVMPreferredAlignmentOfType, LLVMTargetDataRef, LLVMTypeRef, int) -_wrap_objobj2obj(LLVMPreferredAlignmentOfGlobal, LLVMTargetDataRef, +_wrap_objobj2obj(LLVMPreferredAlignmentOfGlobal, LLVMTargetDataRef, LLVMValueRef, int) _wrap_objobjull2obj(LLVMElementAtOffset, LLVMTargetDataRef, LLVMTypeRef, int) -_wrap_objobjint2obj(LLVMOffsetOfElement, LLVMTargetDataRef, LLVMTypeRef, +_wrap_objobjint2obj(LLVMOffsetOfElement, LLVMTargetDataRef, LLVMTypeRef, llvmwrap_ull) @@ -1263,7 +1267,7 @@ _wLLVMLoadLibraryPermanently(PyObject *self, PyObject *args) if (!PyArg_ParseTuple(args, "U:LLVMLoadLibraryPermanently", &filename_)) { return NULL; } - + filename = PyUnicode_AS_DATA(filename_); #else if (!PyArg_ParseTuple(args, "s", &filename)) { @@ -1292,7 +1296,7 @@ static PyObject * _wPyCObjectVoidPtrToPyLong(PyObject *self, PyObject *args) { void *p; - + if (!(p = get_object_arg(args))) return NULL; @@ -1319,13 +1323,13 @@ _wPyCObjectVoidPtrToPyLong(PyObject *self, PyObject *args) static PyMethodDef core_methods[] = { /* Modules */ - _method( LLVMModuleCreateWithName ) - _method( LLVMGetDataLayout ) + _method( LLVMModuleCreateWithName ) + _method( LLVMGetDataLayout ) _method( LLVMSetDataLayout ) - _method( LLVMGetModuleIdentifier ) - _method( LLVMSetModuleIdentifier ) - _method( LLVMGetTarget ) - _method( LLVMSetTarget ) + _method( LLVMGetModuleIdentifier ) + _method( LLVMSetModuleIdentifier ) + _method( LLVMGetTarget ) + _method( LLVMSetTarget ) _method( LLVMModuleAddLibrary ) _method( LLVMGetTypeByName ) _method( LLVMDumpModule ) @@ -1342,68 +1346,72 @@ static PyMethodDef core_methods[] = { /* Types */ /* General */ - _method( LLVMGetTypeKind ) + _method( LLVMGetTypeKind ) _method( LLVMDumpTypeToString ) /* Integer types */ - _method( LLVMInt1Type ) - _method( LLVMInt8Type ) - _method( LLVMInt16Type ) - _method( LLVMInt32Type ) - _method( LLVMInt64Type ) - _method( LLVMIntType ) - _method( LLVMGetIntTypeWidth ) + _method( LLVMInt1Type ) + _method( LLVMInt8Type ) + _method( LLVMInt16Type ) + _method( LLVMInt32Type ) + _method( LLVMInt64Type ) + _method( LLVMIntType ) + _method( LLVMGetIntTypeWidth ) /* Floating-point types */ - _method( LLVMFloatType ) - _method( LLVMDoubleType ) - _method( LLVMX86FP80Type ) - _method( LLVMFP128Type ) - _method( LLVMPPCFP128Type ) + _method( LLVMFloatType ) + _method( LLVMDoubleType ) + _method( LLVMX86FP80Type ) + _method( LLVMFP128Type ) + _method( LLVMPPCFP128Type ) /* Function types */ - _method( LLVMFunctionType ) - _method( LLVMIsFunctionVarArg ) - _method( LLVMGetReturnType ) - _method( LLVMCountParamTypes ) - _method( LLVMGetFunctionTypeParams ) + _method( LLVMFunctionType ) + _method( LLVMIsFunctionVarArg ) + _method( LLVMGetReturnType ) + _method( LLVMCountParamTypes ) + _method( LLVMGetFunctionTypeParams ) /* Struct types */ - _method( LLVMStructType ) - _method( LLVMCountStructElementTypes ) - //_method( LLVMGetStructElementTypes ) - _method( LLVMIsPackedStruct ) + _method( LLVMStructType ) + _method( LLVMStructTypeIdentified ) + _method( LLVMSetStructBody ) + _method( LLVMCountStructElementTypes ) + _method( LLVMGetStructElementTypes ) + _method( LLVMIsPackedStruct ) + _method( LLVMGetStructName ) + _method( LLVMSetStructName ) /* Array types */ - _method( LLVMArrayType ) - _method( LLVMGetElementType ) - _method( LLVMGetArrayLength ) + _method( LLVMArrayType ) + _method( LLVMGetElementType ) + _method( LLVMGetArrayLength ) /* Pointer types */ - _method( LLVMPointerType ) - _method( LLVMGetPointerAddressSpace ) + _method( LLVMPointerType ) + _method( LLVMGetPointerAddressSpace ) /* Vector type */ - _method( LLVMVectorType ) - _method( LLVMGetVectorSize ) + _method( LLVMVectorType ) + _method( LLVMGetVectorSize ) /* Other types */ - _method( LLVMVoidType ) - _method( LLVMLabelType ) + _method( LLVMVoidType ) + _method( LLVMLabelType ) /* Type handles */ /* - _method( LLVMResolveTypeHandle ) + _method( LLVMResolveTypeHandle ) _method( LLVMDisposeTypeHandle ) */ /* Values */ /* Operations on all values */ - _method( LLVMTypeOf ) - _method( LLVMGetValueName ) - _method( LLVMSetValueName ) - _method( LLVMDumpValue ) + _method( LLVMTypeOf ) + _method( LLVMGetValueName ) + _method( LLVMSetValueName ) + _method( LLVMDumpValue ) _method( LLVMDumpValueToString ) _method( LLVMValueGetID ) _method( LLVMValueGetNumUses ) @@ -1417,102 +1425,102 @@ static PyMethodDef core_methods[] = { /* Constant Values */ /* Operations on constants of any type */ - _method( LLVMConstNull ) - _method( LLVMConstAllOnes ) - _method( LLVMGetUndef ) - _method( LLVMIsConstant ) - _method( LLVMIsNull ) - _method( LLVMIsUndef ) + _method( LLVMConstNull ) + _method( LLVMConstAllOnes ) + _method( LLVMGetUndef ) + _method( LLVMIsConstant ) + _method( LLVMIsNull ) + _method( LLVMIsUndef ) /* Operations on scalar constants */ - _method( LLVMConstInt ) - _method( LLVMConstReal ) - _method( LLVMConstRealOfString ) + _method( LLVMConstInt ) + _method( LLVMConstReal ) + _method( LLVMConstRealOfString ) /* Operations on composite constants */ - _method( LLVMConstString ) - _method( LLVMConstArray ) - _method( LLVMConstStruct ) - _method( LLVMConstVector ) + _method( LLVMConstString ) + _method( LLVMConstArray ) + _method( LLVMConstStruct ) + _method( LLVMConstVector ) /* Constant expressions */ - _method( LLVMSizeOf ) - _method( LLVMConstNeg ) - _method( LLVMConstNot ) - _method( LLVMConstAdd ) + _method( LLVMSizeOf ) + _method( LLVMConstNeg ) + _method( LLVMConstNot ) + _method( LLVMConstAdd ) _method( LLVMConstFAdd ) - _method( LLVMConstSub ) - _method( LLVMConstFSub ) - _method( LLVMConstMul ) - _method( LLVMConstFMul ) - _method( LLVMConstUDiv ) - _method( LLVMConstSDiv ) - _method( LLVMConstFDiv ) - _method( LLVMConstURem ) - _method( LLVMConstSRem ) - _method( LLVMConstFRem ) - _method( LLVMConstAnd ) - _method( LLVMConstOr ) - _method( LLVMConstXor ) - _method( LLVMConstICmp ) - _method( LLVMConstFCmp ) - _method( LLVMConstShl ) - _method( LLVMConstLShr ) - _method( LLVMConstAShr ) - _method( LLVMConstGEP ) - _method( LLVMConstTrunc ) - _method( LLVMConstSExt ) - _method( LLVMConstZExt ) - _method( LLVMConstFPTrunc ) - _method( LLVMConstFPExt ) - _method( LLVMConstUIToFP ) - _method( LLVMConstSIToFP ) - _method( LLVMConstFPToUI ) - _method( LLVMConstFPToSI ) - _method( LLVMConstPtrToInt ) - _method( LLVMConstIntToPtr ) - _method( LLVMConstBitCast ) - _method( LLVMConstSelect ) - _method( LLVMConstExtractElement ) - _method( LLVMConstInsertElement ) - _method( LLVMConstShuffleVector ) + _method( LLVMConstSub ) + _method( LLVMConstFSub ) + _method( LLVMConstMul ) + _method( LLVMConstFMul ) + _method( LLVMConstUDiv ) + _method( LLVMConstSDiv ) + _method( LLVMConstFDiv ) + _method( LLVMConstURem ) + _method( LLVMConstSRem ) + _method( LLVMConstFRem ) + _method( LLVMConstAnd ) + _method( LLVMConstOr ) + _method( LLVMConstXor ) + _method( LLVMConstICmp ) + _method( LLVMConstFCmp ) + _method( LLVMConstShl ) + _method( LLVMConstLShr ) + _method( LLVMConstAShr ) + _method( LLVMConstGEP ) + _method( LLVMConstTrunc ) + _method( LLVMConstSExt ) + _method( LLVMConstZExt ) + _method( LLVMConstFPTrunc ) + _method( LLVMConstFPExt ) + _method( LLVMConstUIToFP ) + _method( LLVMConstSIToFP ) + _method( LLVMConstFPToUI ) + _method( LLVMConstFPToSI ) + _method( LLVMConstPtrToInt ) + _method( LLVMConstIntToPtr ) + _method( LLVMConstBitCast ) + _method( LLVMConstSelect ) + _method( LLVMConstExtractElement ) + _method( LLVMConstInsertElement ) + _method( LLVMConstShuffleVector ) /* Globals */ /* Globals (general) */ - _method( LLVMGetGlobalParent ) - _method( LLVMIsDeclaration ) - _method( LLVMGetLinkage ) - _method( LLVMSetLinkage ) - _method( LLVMGetSection ) - _method( LLVMSetSection ) - _method( LLVMGetVisibility ) - _method( LLVMSetVisibility ) - _method( LLVMGetAlignment ) - _method( LLVMSetAlignment ) + _method( LLVMGetGlobalParent ) + _method( LLVMIsDeclaration ) + _method( LLVMGetLinkage ) + _method( LLVMSetLinkage ) + _method( LLVMGetSection ) + _method( LLVMSetSection ) + _method( LLVMGetVisibility ) + _method( LLVMSetVisibility ) + _method( LLVMGetAlignment ) + _method( LLVMSetAlignment ) /* Global Variables */ - _method( LLVMAddGlobal ) - _method( LLVMGetNamedGlobal ) + _method( LLVMAddGlobal ) + _method( LLVMGetNamedGlobal ) _method( LLVMGetFirstGlobal ) _method( LLVMGetNextGlobal ) - _method( LLVMDeleteGlobal ) - _method( LLVMHasInitializer ) - _method( LLVMGetInitializer ) - _method( LLVMSetInitializer ) - _method( LLVMSetThreadLocal ) - _method( LLVMSetGlobalConstant ) - _method( LLVMIsThreadLocal ) - _method( LLVMIsGlobalConstant ) + _method( LLVMDeleteGlobal ) + _method( LLVMHasInitializer ) + _method( LLVMGetInitializer ) + _method( LLVMSetInitializer ) + _method( LLVMSetThreadLocal ) + _method( LLVMSetGlobalConstant ) + _method( LLVMIsThreadLocal ) + _method( LLVMIsGlobalConstant ) /* Functions */ - _method( LLVMAddFunction ) - _method( LLVMGetNamedFunction ) - _method( LLVMGetFirstFunction ) - _method( LLVMGetNextFunction ) - _method( LLVMDeleteFunction ) - _method( LLVMGetIntrinsicID ) - _method( LLVMGetFunctionCallConv ) + _method( LLVMAddFunction ) + _method( LLVMGetNamedFunction ) + _method( LLVMGetFirstFunction ) + _method( LLVMGetNextFunction ) + _method( LLVMDeleteFunction ) + _method( LLVMGetIntrinsicID ) + _method( LLVMGetFunctionCallConv ) _method( LLVMSetFunctionCallConv ) _method( LLVMGetGC ) _method( LLVMSetGC ) @@ -1525,27 +1533,27 @@ static PyMethodDef core_methods[] = { _method( LLVMRemoveFunctionAttr ) /* Arguments */ - _method( LLVMCountParams ) - _method( LLVMGetFirstParam ) - _method( LLVMGetNextParam ) - _method( LLVMGetParamParent ) + _method( LLVMCountParams ) + _method( LLVMGetFirstParam ) + _method( LLVMGetNextParam ) + _method( LLVMGetParamParent ) _method( LLVMAddAttribute ) _method( LLVMRemoveAttribute ) - _method( LLVMSetParamAlignment ) - _method( LLVMGetParamAlignment ) + _method( LLVMSetParamAlignment ) + _method( LLVMGetParamAlignment ) /* Basic Blocks */ - _method( LLVMGetBasicBlockParent ) - _method( LLVMCountBasicBlocks ) + _method( LLVMGetBasicBlockParent ) + _method( LLVMCountBasicBlocks ) _method( LLVMGetFirstBasicBlock ) _method( LLVMGetNextBasicBlock ) - _method( LLVMGetEntryBasicBlock ) - _method( LLVMAppendBasicBlock ) - _method( LLVMInsertBasicBlock ) - _method( LLVMDeleteBasicBlock ) + _method( LLVMGetEntryBasicBlock ) + _method( LLVMAppendBasicBlock ) + _method( LLVMInsertBasicBlock ) + _method( LLVMDeleteBasicBlock ) /* Instructions */ - _method( LLVMGetInstructionParent ) + _method( LLVMGetInstructionParent ) _method( LLVMGetFirstInstruction ) _method( LLVMGetNextInstruction ) _method( LLVMInstIsTerminator ) @@ -1561,102 +1569,102 @@ static PyMethodDef core_methods[] = { _method( LLVMInstGetOpcodeName ) /* Call Sites (Call or Invoke) */ - _method( LLVMSetInstructionCallConv ) - _method( LLVMGetInstructionCallConv ) + _method( LLVMSetInstructionCallConv ) + _method( LLVMGetInstructionCallConv ) _method( LLVMIsTailCall ) _method( LLVMSetTailCall ) - _method( LLVMAddInstrAttribute ) - _method( LLVMRemoveInstrAttribute ) - _method( LLVMSetInstrParamAlignment ) + _method( LLVMAddInstrAttribute ) + _method( LLVMRemoveInstrAttribute ) + _method( LLVMSetInstrParamAlignment ) /* PHI Nodes */ - _method( LLVMAddIncoming1 ) - _method( LLVMCountIncoming ) - _method( LLVMGetIncomingValue ) - _method( LLVMGetIncomingBlock ) + _method( LLVMAddIncoming1 ) + _method( LLVMCountIncoming ) + _method( LLVMGetIncomingValue ) + _method( LLVMGetIncomingBlock ) /* Comparison Instructions */ _method( LLVMCmpInstGetPredicate ) /* Instruction builders */ - _method( LLVMCreateBuilder ) - _method( LLVMPositionBuilderBefore ) - _method( LLVMPositionBuilderAtEnd ) - _method( LLVMGetInsertBlock ) - _method( LLVMDisposeBuilder ) + _method( LLVMCreateBuilder ) + _method( LLVMPositionBuilderBefore ) + _method( LLVMPositionBuilderAtEnd ) + _method( LLVMGetInsertBlock ) + _method( LLVMDisposeBuilder ) /* Terminators */ - _method( LLVMBuildRetVoid ) - _method( LLVMBuildRet ) - _method( LLVMBuildRetMultiple ) - _method( LLVMBuildBr ) - _method( LLVMBuildCondBr ) - _method( LLVMBuildSwitch ) - _method( LLVMBuildInvoke ) - _method( LLVMBuildUnreachable ) + _method( LLVMBuildRetVoid ) + _method( LLVMBuildRet ) + _method( LLVMBuildRetMultiple ) + _method( LLVMBuildBr ) + _method( LLVMBuildCondBr ) + _method( LLVMBuildSwitch ) + _method( LLVMBuildInvoke ) + _method( LLVMBuildUnreachable ) /* Add a case to the switch instruction */ - _method( LLVMAddCase ) + _method( LLVMAddCase ) /* Arithmetic */ - _method( LLVMBuildAdd ) + _method( LLVMBuildAdd ) _method( LLVMBuildFAdd) _method( LLVMBuildSub ) - _method( LLVMBuildFSub) - _method( LLVMBuildMul ) + _method( LLVMBuildFSub) + _method( LLVMBuildMul ) _method( LLVMBuildFMul) - _method( LLVMBuildUDiv ) - _method( LLVMBuildSDiv ) - _method( LLVMBuildFDiv ) - _method( LLVMBuildURem ) - _method( LLVMBuildSRem ) - _method( LLVMBuildFRem ) - _method( LLVMBuildShl ) - _method( LLVMBuildLShr ) - _method( LLVMBuildAShr ) - _method( LLVMBuildAnd ) - _method( LLVMBuildOr ) - _method( LLVMBuildXor ) - _method( LLVMBuildNeg ) - _method( LLVMBuildNot ) + _method( LLVMBuildUDiv ) + _method( LLVMBuildSDiv ) + _method( LLVMBuildFDiv ) + _method( LLVMBuildURem ) + _method( LLVMBuildSRem ) + _method( LLVMBuildFRem ) + _method( LLVMBuildShl ) + _method( LLVMBuildLShr ) + _method( LLVMBuildAShr ) + _method( LLVMBuildAnd ) + _method( LLVMBuildOr ) + _method( LLVMBuildXor ) + _method( LLVMBuildNeg ) + _method( LLVMBuildNot ) /* Memory */ - _method( LLVMBuildMalloc ) - _method( LLVMBuildArrayMalloc ) - _method( LLVMBuildAlloca ) - _method( LLVMBuildArrayAlloca ) - _method( LLVMBuildFree ) - _method( LLVMBuildLoad ) - _method( LLVMBuildStore ) - _method( LLVMBuildGEP ) + _method( LLVMBuildMalloc ) + _method( LLVMBuildArrayMalloc ) + _method( LLVMBuildAlloca ) + _method( LLVMBuildArrayAlloca ) + _method( LLVMBuildFree ) + _method( LLVMBuildLoad ) + _method( LLVMBuildStore ) + _method( LLVMBuildGEP ) /* Casts */ - _method( LLVMBuildTrunc ) - _method( LLVMBuildZExt ) - _method( LLVMBuildSExt ) - _method( LLVMBuildFPToUI ) - _method( LLVMBuildFPToSI ) - _method( LLVMBuildUIToFP ) - _method( LLVMBuildSIToFP ) - _method( LLVMBuildFPTrunc ) - _method( LLVMBuildFPExt ) - _method( LLVMBuildPtrToInt ) - _method( LLVMBuildIntToPtr ) - _method( LLVMBuildBitCast ) + _method( LLVMBuildTrunc ) + _method( LLVMBuildZExt ) + _method( LLVMBuildSExt ) + _method( LLVMBuildFPToUI ) + _method( LLVMBuildFPToSI ) + _method( LLVMBuildUIToFP ) + _method( LLVMBuildSIToFP ) + _method( LLVMBuildFPTrunc ) + _method( LLVMBuildFPExt ) + _method( LLVMBuildPtrToInt ) + _method( LLVMBuildIntToPtr ) + _method( LLVMBuildBitCast ) /* Comparisons */ - _method( LLVMBuildICmp ) - _method( LLVMBuildFCmp ) + _method( LLVMBuildICmp ) + _method( LLVMBuildFCmp ) /* Miscellaneous instructions */ - _method( LLVMBuildGetResult ) - _method( LLVMBuildPhi ) - _method( LLVMBuildCall ) - _method( LLVMBuildSelect ) - _method( LLVMBuildVAArg ) - _method( LLVMBuildExtractElement ) - _method( LLVMBuildInsertElement ) - _method( LLVMBuildShuffleVector ) + _method( LLVMBuildGetResult ) + _method( LLVMBuildPhi ) + _method( LLVMBuildCall ) + _method( LLVMBuildSelect ) + _method( LLVMBuildVAArg ) + _method( LLVMBuildExtractElement ) + _method( LLVMBuildInsertElement ) + _method( LLVMBuildShuffleVector ) /* Memory Buffer */ _method( LLVMCreateMemoryBufferWithContentsOfFile ) @@ -1664,12 +1672,12 @@ static PyMethodDef core_methods[] = { _method( LLVMDisposeMemoryBuffer ) /* Pass Manager */ - _method( LLVMCreatePassManager ) - _method( LLVMCreateFunctionPassManagerForModule ) - _method( LLVMRunPassManager ) - _method( LLVMInitializeFunctionPassManager ) - _method( LLVMRunFunctionPassManager ) - _method( LLVMFinalizeFunctionPassManager ) + _method( LLVMCreatePassManager ) + _method( LLVMCreateFunctionPassManagerForModule ) + _method( LLVMRunPassManager ) + _method( LLVMInitializeFunctionPassManager ) + _method( LLVMRunFunctionPassManager ) + _method( LLVMFinalizeFunctionPassManager ) _method( LLVMDisposePassManager ) /* Passes */ @@ -1838,7 +1846,7 @@ init_core(void) if (module == NULL) INITERROR; #if PY_MAJOR_VERSION >= 3 - + return module; #endif } diff --git a/llvm/core.py b/llvm/core.py index acbb257..9cc6409 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -585,24 +585,42 @@ class Type(object): var_arg), TYPE_FUNCTION) @staticmethod - def struct(element_tys): # not packed + def struct(element_tys, name=''): # not packed """Create a (unpacked) structure type. Creates a structure type with elements of types as given in the iterable `element_tys'. This method creates a unpacked - structure. For a packed one, use the packed_struct() method.""" + structure. For a packed one, use the packed_struct() method. + + If name is not '', creates a identified type; + otherwise, creates a literal type.""" elems = unpack_types(element_tys) - return _make_type(_core.LLVMStructType(elems, 0), TYPE_STRUCT) + + if name: # create Identified StructType + objptr = _core.LLVMStructTypeIdentified(name) + _core.LLVMSetStructBody(objptr, elems, 0) + else: # create Literal StructType + objptr = _core.LLVMStructType(elems, 0) + + return _make_type(objptr, TYPE_STRUCT) @staticmethod - def packed_struct(element_tys): + def packed_struct(element_tys, name=''): """Create a (packed) structure type. Creates a structure type with elements of types as given in the iterable `element_tys'. This method creates a packed - structure. For an unpacked one, use the struct() method.""" + structure. For an unpacked one, use the struct() method. + + If name is not '', creates a identified type; + otherwise, creates a literal type.""" elems = unpack_types(element_tys) - return _make_type(_core.LLVMStructType(elems, 1), TYPE_STRUCT) + + if name: # create Identified StructType + objptr = _core.LLVMStructTypeIdentified(name) + _core.LLVMSetStructBody(objptr, elems, 0) + else: # create Literal StructType + objptr = _core.LLVMStructType(elems, 1) @staticmethod def array(element_ty, count): @@ -725,18 +743,25 @@ class StructType(Type): Same as len(obj.elements), but faster.""" return _core.LLVMCountStructElementTypes(self.ptr) - #@property - #def elements(self): - # """An iterable that yieldsd Type objects, representing the types of the - # elements (members) of the structure, in order.""" - # pp = _core.LLVMGetStructElementTypes(self.ptr) - # return [ _make_type(p, _core.LLVMGetTypeKind(p)) for p in pp ] + @property + def elements(self): + """An iterable that yieldsd Type objects, representing the types of the + elements (members) of the structure, in order.""" + pp = _core.LLVMGetStructElementTypes(self.ptr) + return [ _make_type(p, _core.LLVMGetTypeKind(p)) for p in pp ] @property def packed(self): """True if the structure is packed, False otherwise.""" return _core.LLVMIsPackedStruct(self.ptr) != 0 + def _set_name(self, name): + _core.LLVMSetStructName(self.ptr, name) + + def _get_name(self): + return _core.LLVMGetStructName(self.ptr) + + name = property(_get_name, _set_name) class ArrayType(Type): """Represents an array type.""" diff --git a/llvm/extra.cpp b/llvm/extra.cpp index bd65e7b..d4030af 100644 --- a/llvm/extra.cpp +++ b/llvm/extra.cpp @@ -90,6 +90,25 @@ char *do_print(W obj) return strdup(buf.str().c_str()); } +LLVMTypeRef LLVMStructTypeIdentified(const char * name) +{ + using namespace llvm; + return wrap(StructType::create(getGlobalContext(), name)); +} + +void LLVMSetStructBody(LLVMTypeRef type, LLVMTypeRef* elemtys, unsigned elemct, int is_packed) +{ + using namespace llvm; + ArrayRef elemtys_aryref(unwrap(elemtys), elemct); + unwrap(type)->setBody(elemtys_aryref, is_packed); +} + +void LLVMSetStructName(LLVMTypeRef type, const char * name) +{ + llvm::StructType *st = llvm::unwrap(type); + st->setName(name); +} + char *LLVMGetModuleIdentifier(LLVMModuleRef module) { return strdup(llvm::unwrap(module)->getModuleIdentifier().c_str()); diff --git a/llvm/extra.h b/llvm/extra.h index 9e9ae1b..c3772aa 100644 --- a/llvm/extra.h +++ b/llvm/extra.h @@ -41,6 +41,21 @@ extern "C" { #endif +/* + * Wraps StructType::create() + */ +LLVMTypeRef LLVMStructTypeIdentified(const char * name); + +/* + * StructType::setBody() + */ +void LLVMSetStructBody(LLVMTypeRef type, LLVMTypeRef* elemtys, unsigned elemct, int is_packed); + +/* + * Wraps llvm::StructType::setName() + */ +void LLVMSetStructName(LLVMTypeRef type, const char * name); + /* * Wraps llvm::Module::getModuleIdentifier() diff --git a/llvm/wrap.h b/llvm/wrap.h index f45f8b6..096200b 100644 --- a/llvm/wrap.h +++ b/llvm/wrap.h @@ -11,7 +11,7 @@ * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * - * * Neither the name of this software, nor the names of its + * * Neither the name of this software, nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * @@ -30,7 +30,7 @@ /** * Functions and macros to aid in wrapping. - */ + */ #ifndef LLVM_PY_WRAP_H #define LLVM_PY_WRAP_H @@ -169,7 +169,7 @@ _w ## func (PyObject *self, PyObject *args) \ } /** - * Wrap LLVM functions of the type + * Wrap LLVM functions of the type * outtype func(intype1 arg1, intype2 arg2) */ #define _wrap_objobj2obj(func, intype1, intype2, outtype)\ @@ -232,7 +232,7 @@ _w ## func (PyObject *self, PyObject *args) \ } /** - * Wrap LLVM functions of the type + * Wrap LLVM functions of the type * outtype func(intype1 arg1, intype2 arg2, intype3 arg3) */ #define _wrap_objobjobj2obj(func, intype1, intype2, intype3, outtype) \ @@ -255,7 +255,7 @@ _w ## func (PyObject *self, PyObject *args) \ } /** - * Wrap LLVM functions of the type + * Wrap LLVM functions of the type * void func(intype1 arg1, intype2 arg2, intype3 arg3) */ #define _wrap_objobjobj2none(func, intype1, intype2, intype3) \ @@ -474,7 +474,7 @@ _w ## func (PyObject *self, PyObject *args) \ } /** - * Wrap LLVM functions of the type + * Wrap LLVM functions of the type * outtype func(intype1 arg1, intype2 arg2, const char *arg3) */ #define _wrap_objobjstr2obj(func, intype1, intype2, outtype) \ @@ -497,7 +497,7 @@ _w ## func (PyObject *self, PyObject *args) \ } /** - * Wrap LLVM functions of the type + * Wrap LLVM functions of the type * outtype func(intype1 arg1, intype2 arg2, int arg3) */ #define _wrap_objobjint2obj(func, intype1, intype2, outtype) \ @@ -519,7 +519,7 @@ _w ## func (PyObject *self, PyObject *args) \ } /** - * Wrap LLVM functions of the type + * Wrap LLVM functions of the type * outtype func(intype1 arg1, intype2 arg2, unsigned long long arg3) */ #define _wrap_objobjull2obj(func, intype1, intype2, outtype) \ @@ -541,7 +541,7 @@ _w ## func (PyObject *self, PyObject *args) \ } /** - * Wrap LLVM functions of the type + * Wrap LLVM functions of the type * void func(intype1 arg1, arg2, arg3) */ #define _wrap_objintint2none(func, intype1) \ @@ -562,7 +562,7 @@ _w ## func (PyObject *self, PyObject *args) \ } /** - * Wrap LLVM functions of the type + * Wrap LLVM functions of the type * void func(intype1 arg1, arg2, enum_intype3 arg3) */ #define _wrap_objintenum2none(func, intype1, intype3) \ @@ -584,7 +584,7 @@ _w ## func (PyObject *self, PyObject *args) \ } /** - * Wrap LLVM functions of the type + * Wrap LLVM functions of the type * outtype func(intype1 arg1, const char *arg2, intype3 arg3) */ #define _wrap_objstrobj2obj(func, intype1, intype3, outtype) \ @@ -608,7 +608,7 @@ _w ## func (PyObject *self, PyObject *args) \ /** - * Wrap LLVM functions of the type + * Wrap LLVM functions of the type * outtype func(intype1 arg1, intype2 arg2, int arg3, const char *arg4) */ #define _wrap_objobjintstr2obj(func, intype1, intype2, outtype) \ @@ -632,7 +632,7 @@ _w ## func (PyObject *self, PyObject *args) \ } /** - * Wrap LLVM functions of the type + * Wrap LLVM functions of the type * outtype func(intype1 arg1, intype2 arg2, intype3 arg3, const char *arg4) */ #define _wrap_objobjobjstr2obj(func, intype1, intype2, intype3, outtype)\ @@ -657,7 +657,7 @@ _w ## func (PyObject *self, PyObject *args) \ } /** - * Wrap LLVM functions of the type + * Wrap LLVM functions of the type * outtype func(intype1 arg1, intype2 arg2, intype3 arg3, arg4) */ #define _wrap_objobjobjint2obj(func, intype1, intype2, intype3, outtype) \ @@ -681,7 +681,7 @@ _w ## func (PyObject *self, PyObject *args) \ } /** - * Wrap LLVM functions of the type + * Wrap LLVM functions of the type * outtype func(intype1 arg1, intype2 arg2, intype3 arg3, intype arg4) */ #define _wrap_objobjobjobj2obj(func, intype1, intype2, intype3, intype4, outtype) \ @@ -706,7 +706,7 @@ _w ## func (PyObject *self, PyObject *args) } /** - * Wrap LLVM functions of the type + * Wrap LLVM functions of the type * outtype func(intype1 arg1, intype2 arg2, intype3 arg3, intype arg4, const char *arg5) */ #define _wrap_objobjobjobjstr2obj(func, intype1, intype2, intype3, intype4, outtype)\ @@ -868,6 +868,35 @@ _w ## func (PyObject *self, PyObject *args) \ return ctor_ ## outtype (ret); \ } + +/** + * Wrap LLVM functions of the type + * void func(intype1 arg1, intype2 *arg2v, unsigned arg2n, int arg3) + * where arg2v is an array of intype2 elements, arg2n in length. + */ +#define _wrap_objlistint2none(func, intype1, intype2) \ +static PyObject * \ +_w ## func (PyObject *self, PyObject *args) \ +{ \ + PyObject *obj1, *obj2; \ + intype1 arg1; \ + intype2 *arg2v; \ + unsigned arg2n; \ + int arg3; \ + \ + if (!PyArg_ParseTuple(args, "OOi", &obj1, &obj2, &arg3)) \ + return NULL; \ + \ + arg1 = ( intype1 ) PyCapsule_GetPointer(obj1, NULL); \ + arg2n = (unsigned) PyList_Size(obj2); \ + if (!(arg2v = ( intype2 *)make_array_from_list(obj2, arg2n)))\ + return PyErr_NoMemory(); \ + \ + func (arg1, arg2v, arg2n, arg3); \ + free(arg2v); \ + Py_RETURN_NONE; \ +} + /** * Wrap LLVM functions of the type * outtype func(intype1 arg1, int arg2, intype3 *arg3v, unsigned arg3n) @@ -1022,7 +1051,7 @@ _w ## func (PyObject *self, PyObject *args) \ } /** - * Wrap LLVM functions of the type + * Wrap LLVM functions of the type * outtype func(intype1 arg1, intype2 arg2) */ #define _wrap_objobj2obj(func, intype1, intype2, outtype) \ @@ -1082,7 +1111,7 @@ _w ## func (PyObject *self, PyObject *args) \ } /** - * Wrap LLVM functions of the type + * Wrap LLVM functions of the type * outtype func(intype1 arg1, intype2 arg2, intype3 arg3) */ #define _wrap_objobjobj2obj(func, intype1, intype2, intype3, outtype) \ @@ -1105,7 +1134,7 @@ _w ## func (PyObject *self, PyObject *args) \ } /** - * Wrap LLVM functions of the type + * Wrap LLVM functions of the type * void func(intype1 arg1, intype2 arg2, intype3 arg3) */ #define _wrap_objobjobj2none(func, intype1, intype2, intype3) \ @@ -1319,7 +1348,7 @@ _w ## func (PyObject *self, PyObject *args) \ } /** - * Wrap LLVM functions of the type + * Wrap LLVM functions of the type * outtype func(intype1 arg1, intype2 arg2, const char *arg3) */ #define _wrap_objobjstr2obj(func, intype1, intype2, outtype) \ @@ -1341,7 +1370,7 @@ _w ## func (PyObject *self, PyObject *args) \ } /** - * Wrap LLVM functions of the type + * Wrap LLVM functions of the type * outtype func(intype1 arg1, intype2 arg2, int arg3) */ #define _wrap_objobjint2obj(func, intype1, intype2, outtype) \ @@ -1363,7 +1392,7 @@ _w ## func (PyObject *self, PyObject *args) \ } /** - * Wrap LLVM functions of the type + * Wrap LLVM functions of the type * outtype func(intype1 arg1, intype2 arg2, unsigned long long arg3) */ #define _wrap_objobjull2obj(func, intype1, intype2, outtype) \ @@ -1385,7 +1414,7 @@ _w ## func (PyObject *self, PyObject *args) \ } /** - * Wrap LLVM functions of the type + * Wrap LLVM functions of the type * void func(intype1 arg1, arg2, arg3) */ #define _wrap_objintint2none(func, intype1) \ @@ -1406,7 +1435,7 @@ _w ## func (PyObject *self, PyObject *args) \ } /** - * Wrap LLVM functions of the type + * Wrap LLVM functions of the type * void func(intype1 arg1, arg2, enum_intype3 arg3) */ #define _wrap_objintenum2none(func, intype1, intype3) \ @@ -1428,7 +1457,7 @@ _w ## func (PyObject *self, PyObject *args) \ } /** - * Wrap LLVM functions of the type + * Wrap LLVM functions of the type * outtype func(intype1 arg1, const char *arg2, intype3 arg3) */ #define _wrap_objstrobj2obj(func, intype1, intype3, outtype) \ @@ -1451,7 +1480,7 @@ _w ## func (PyObject *self, PyObject *args) \ /** - * Wrap LLVM functions of the type + * Wrap LLVM functions of the type * outtype func(intype1 arg1, intype2 arg2, int arg3, const char *arg4) */ #define _wrap_objobjintstr2obj(func, intype1, intype2, outtype) \ @@ -1474,7 +1503,7 @@ _w ## func (PyObject *self, PyObject *args) \ } /** - * Wrap LLVM functions of the type + * Wrap LLVM functions of the type * outtype func(intype1 arg1, intype2 arg2, intype3 arg3, const char *arg4) */ #define _wrap_objobjobjstr2obj(func, intype1, intype2, intype3, outtype) \ @@ -1498,7 +1527,7 @@ _w ## func (PyObject *self, PyObject *args) \ } /** - * Wrap LLVM functions of the type + * Wrap LLVM functions of the type * outtype func(intype1 arg1, intype2 arg2, intype3 arg3, arg4) */ #define _wrap_objobjobjint2obj(func, intype1, intype2, intype3, outtype) \ @@ -1522,7 +1551,7 @@ _w ## func (PyObject *self, PyObject *args) \ } /** - * Wrap LLVM functions of the type + * Wrap LLVM functions of the type * outtype func(intype1 arg1, intype2 arg2, intype3 arg3, intype arg4) */ #define _wrap_objobjobjobj2obj(func, intype1, intype2, intype3, intype4, outtype) \ @@ -1547,7 +1576,7 @@ _w ## func (PyObject *self, PyObject *args) \ } /** - * Wrap LLVM functions of the type + * Wrap LLVM functions of the type * outtype func(intype1 arg1, intype2 arg2, intype3 arg3, intype arg4, const char *arg5) */ #define _wrap_objobjobjobjstr2obj(func, intype1, intype2, intype3, intype4, outtype) \ @@ -1706,6 +1735,35 @@ _w ## func (PyObject *self, PyObject *args) \ return ctor_ ## outtype (ret); \ } +/** + * Wrap LLVM functions of the type + * void func(intype1 arg1, intype2 *arg2v, unsigned arg2n, int arg3) + * where arg2v is an array of intype2 elements, arg2n in length. + */ +#define _wrap_objlistint2none(func, intype1, intype2) \ +static PyObject * \ +_w ## func (PyObject *self, PyObject *args) \ +{ \ + PyObject *obj1, *obj2; \ + intype1 arg1; \ + intype2 *arg2v; \ + unsigned arg2n; \ + int arg3; \ + \ + if (!PyArg_ParseTuple(args, "OOi", &obj1, &obj2, &arg3)) \ + return NULL; \ + \ + arg1 = ( intype1 ) PyCObject_AsVoidPtr(obj1); \ + arg2n = (unsigned) PyList_Size(obj2); \ + if (!(arg2v = ( intype2 *)make_array_from_list(obj2, arg2n))) \ + return PyErr_NoMemory(); \ + \ + func (arg1, arg2v, arg2n, arg3); \ + free(arg2v); \ + Py_RETURN_NONE; \ +} + + /** * Wrap LLVM functions of the type * outtype func(intype1 arg1, int arg2, intype3 *arg3v, unsigned arg3n) diff --git a/test/test.py b/test/test.py index 6d97c1a..10fe019 100755 --- a/test/test.py +++ b/test/test.py @@ -3,17 +3,17 @@ # watch out for uncollected objects import gc -import unittest, sys +import unittest, sys, logging from llvm import * from llvm.core import * + class TestModule(unittest.TestCase): def setUp(self): pass - def testdata_layout(self): """Data layout property.""" m = Module.new("test2.1") @@ -33,23 +33,39 @@ class TestModule(unittest.TestCase): reqd = '; ModuleID = \'test3.1\'\ntarget triple = "some_value"\n' self.assertEqual(str(m), reqd) + # Type system is rewritten in LLVM 3.0. + # Only named StructType is supported. + # See http://blog.llvm.org/2011/11/llvm-30-type-system-rewrite.html + # + # def testtype_name(self): + # """Type names.""" + # m = Module.new("test4.1") + # r = m.add_type_name("typename41", Type.int()) + # self.assertEqual(r, 0) + # r = m.add_type_name("typename41", Type.int()) + # self.assertEqual(r, 1) + # reqd = "; ModuleID = 'test4.1'\n\n%typename41 = type i32\n" + # self.assertEqual(str(m), reqd) + # r = m.delete_type_name("typename41") + # reqd = "; ModuleID = 'test4.1'\n" + # self.assertEqual(str(m), reqd) + # r = m.delete_type_name("no such name") # nothing should happen + # reqd = "; ModuleID = 'test4.1'\n" + # self.assertEqual(str(m), reqd) def testtype_name(self): - """Type names.""" m = Module.new("test4.1") - r = m.add_type_name("typename41", Type.int()) - self.assertEqual(r, 0) - r = m.add_type_name("typename41", Type.int()) - self.assertEqual(r, 1) - reqd = "; ModuleID = 'test4.1'\n\n%typename41 = type i32\n" - self.assertEqual(str(m), reqd) - r = m.delete_type_name("typename41") - reqd = "; ModuleID = 'test4.1'\n" - self.assertEqual(str(m), reqd) - r = m.delete_type_name("no such name") # nothing should happen - reqd = "; ModuleID = 'test4.1'\n" - self.assertEqual(str(m), reqd) + struct = Type.struct([Type.int(), Type.int()], name="struct.two.int") + self.assertEqual(struct.name, "struct.two.int") + got_struct = m.get_type_named(struct.name) + self.assertEqual(got_struct.name, struct.name) + self.assertEqual(got_struct.element_count, struct.element_count) + self.assertEqual(len(struct.elements), struct.element_count) + + self.assertEqual(struct.elements, got_struct.elements) + for elty in struct.elements: + self.assertEqual(elty, Type.int()) def testglobal_variable(self): """Global variables.""" @@ -65,11 +81,14 @@ def main(): gc.set_debug(gc.DEBUG_LEAK) # run tests - unittest.main() + unittest.main(exit=False) # set exit to False so that it will return. # done - if gc.garbage: - print("garbage = ", gc.garbage) + for it in gc.garbage: + logging.debug('garbage = %s', it) + +if __name__ == '__main__': + main() + -main() From c9902ab8cf2ea34df7255faae303345b84684e30 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Sun, 22 Jul 2012 15:14:52 -0700 Subject: [PATCH 009/675] Add opaque StructType; Remove test/typehandle.py; Add test/opaque.py to demonstrate recursive type. --- llvm/_core.c | 4 +++ llvm/core.py | 60 +++++++++++++++++++++++++++++------- llvm/extra.cpp | 5 +++ llvm/extra.h | 5 +++ test/opaque.py | 40 ++++++++++++++++++++++++ test/test.py | 19 ++++++++++++ test/testattrs.py | 23 +++++++------- test/typehandle.py | 19 ------------ test/uses.py | 76 +++++++++++++++++++++++----------------------- 9 files changed, 171 insertions(+), 80 deletions(-) create mode 100755 test/opaque.py delete mode 100755 test/typehandle.py diff --git a/llvm/_core.c b/llvm/_core.c index 63b6ad5..269d57f 100644 --- a/llvm/_core.c +++ b/llvm/_core.c @@ -313,6 +313,8 @@ _wLLVMGetStructElementTypes(PyObject *self, PyObject *args) _wrap_obj2obj(LLVMIsPackedStruct, LLVMTypeRef, int) +_wrap_obj2obj(LLVMIsOpaqueStruct, LLVMTypeRef, int) +_wrap_obj2obj(LLVMIsLiteralStruct, LLVMTypeRef, int) /*===-- Array types ------------------------------------------------------===*/ @@ -1379,6 +1381,8 @@ static PyMethodDef core_methods[] = { _method( LLVMCountStructElementTypes ) _method( LLVMGetStructElementTypes ) _method( LLVMIsPackedStruct ) + _method( LLVMIsOpaqueStruct ) + _method( LLVMIsLiteralStruct ) _method( LLVMGetStructName ) _method( LLVMSetStructName ) diff --git a/llvm/core.py b/llvm/core.py index 9cc6409..c3a77cc 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -507,13 +507,13 @@ class Module(llvm.Ownable, llvm.Cacheable): def add_library(self, name): return _core.LLVMModuleAddLibrary(self.ptr, name) - + def _get_id(self): return _core.LLVMGetModuleIdentifier(self.ptr) - + def _set_id(self, string): _core.LLVMSetModuleIdentifier(self.ptr, string) - + id = property(_get_id, _set_id) #===----------------------------------------------------------------------=== @@ -584,6 +584,15 @@ class Type(object): return _make_type(_core.LLVMFunctionType(return_ty.ptr, params, var_arg), TYPE_FUNCTION) + @staticmethod + def opaque(name): + """Create a opaque StructType""" + if not name: + raise llvm.LLVMException("Must specify a name") + + objptr = _core.LLVMStructTypeIdentified(name) + return _make_type(objptr, TYPE_STRUCT) + @staticmethod def struct(element_tys, name=''): # not packed """Create a (unpacked) structure type. @@ -591,17 +600,17 @@ class Type(object): Creates a structure type with elements of types as given in the iterable `element_tys'. This method creates a unpacked structure. For a packed one, use the packed_struct() method. - - If name is not '', creates a identified type; + + If name is not '', creates a identified type; otherwise, creates a literal type.""" elems = unpack_types(element_tys) - + if name: # create Identified StructType objptr = _core.LLVMStructTypeIdentified(name) _core.LLVMSetStructBody(objptr, elems, 0) else: # create Literal StructType objptr = _core.LLVMStructType(elems, 0) - + return _make_type(objptr, TYPE_STRUCT) @staticmethod @@ -611,11 +620,11 @@ class Type(object): Creates a structure type with elements of types as given in the iterable `element_tys'. This method creates a packed structure. For an unpacked one, use the struct() method. - - If name is not '', creates a identified type; + + If name is not '', creates a identified type; otherwise, creates a literal type.""" elems = unpack_types(element_tys) - + if name: # create Identified StructType objptr = _core.LLVMStructTypeIdentified(name) _core.LLVMSetStructBody(objptr, elems, 0) @@ -750,6 +759,23 @@ class StructType(Type): pp = _core.LLVMGetStructElementTypes(self.ptr) return [ _make_type(p, _core.LLVMGetTypeKind(p)) for p in pp ] + def set_body(self, elems, packed=False): + """Filled the body of a opaque type. + """ + # check + if not self.is_opaque: + raise llvm.LLVMException("Body is already defined.") + + # prepare arguments + elems = unpack_types(elems) + if packed: + packed = 1 + else: + packed = 0 + + # call c API + _core.LLVMSetStructBody(self.ptr, elems, packed) + @property def packed(self): """True if the structure is packed, False otherwise.""" @@ -757,12 +783,24 @@ class StructType(Type): def _set_name(self, name): _core.LLVMSetStructName(self.ptr, name) - + def _get_name(self): return _core.LLVMGetStructName(self.ptr) name = property(_get_name, _set_name) + @property + def is_literal(self): + return bool(_core.LLVMIsLiteralStruct(self.ptr)) + + @property + def is_identified(self): + return not _core.LLVMIsLiteralStruct(self.ptr) + + @property + def is_opaque(self): + return bool(_core.LLVMIsOpaqueStruct(self.ptr)) + class ArrayType(Type): """Represents an array type.""" diff --git a/llvm/extra.cpp b/llvm/extra.cpp index d4030af..60b7ef9 100644 --- a/llvm/extra.cpp +++ b/llvm/extra.cpp @@ -90,6 +90,11 @@ char *do_print(W obj) return strdup(buf.str().c_str()); } +int LLVMIsLiteralStruct(LLVMTypeRef type) +{ + return llvm::unwrap(type)->isLiteral(); +} + LLVMTypeRef LLVMStructTypeIdentified(const char * name) { using namespace llvm; diff --git a/llvm/extra.h b/llvm/extra.h index c3772aa..ed52a10 100644 --- a/llvm/extra.h +++ b/llvm/extra.h @@ -41,6 +41,11 @@ extern "C" { #endif +/* + * Wraps StructType::isLiteral() + */ +int LLVMIsLiteralStruct(LLVMTypeRef type); + /* * Wraps StructType::create() */ diff --git a/test/opaque.py b/test/opaque.py new file mode 100755 index 0000000..329a673 --- /dev/null +++ b/test/opaque.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python + +from llvm.core import * +from llvm import LLVMException + +import logging, unittest + +class TestOpaque(unittest.TestCase): + def test_opaque(self): + # Create an opaque type + ts = Type.opaque('mystruct') + self.assertIn('type opaque', str(ts)) + self.assertTrue(ts.is_opaque) + self.assertTrue(ts.is_identified) + self.assertFalse(ts.is_literal) + + logging.debug(ts) + + # Create a recursive type + ts.set_body([Type.int(), Type.pointer(ts)]) + + self.assertEqual(ts.elements[0], Type.int()) + self.assertEqual(ts.elements[1], Type.pointer(ts)) + self.assertEqual(ts.elements[1].pointee, ts) + self.assertFalse(ts.is_opaque) # is not longer a opaque type + + logging.debug(ts) + + with self.assertRaises(LLVMException): + # Cannot redefine + ts.set_body([]) + + def test_opaque_with_no_name(self): + with self.assertRaises(LLVMException): + Type.opaque('') + +if __name__ == '__main__': + unittest.main() + + diff --git a/test/test.py b/test/test.py index 10fe019..bbc43f4 100755 --- a/test/test.py +++ b/test/test.py @@ -67,6 +67,25 @@ class TestModule(unittest.TestCase): for elty in struct.elements: self.assertEqual(elty, Type.int()) + # rename identified type + struct.name = 'new_name' + self.assertEqual(struct.name, 'new_name') + self.assertIs(m.get_type_named("struct.two.int"), None) + + self.assertEqual(got_struct.name, struct.name) + + # remove identified type + struct.name = '' + + self.assertIs(m.get_type_named("struct.two.int"), None) + self.assertIs(m.get_type_named("new_name"), None) + + # another name + + struct.name = 'another.name' + self.assertEqual(struct.name, 'another.name') + self.assertEqual(got_struct.name, struct.name) + def testglobal_variable(self): """Global variables.""" m = Module.new("test5.1") diff --git a/test/testattrs.py b/test/testattrs.py index 10381fb..24a7b46 100755 --- a/test/testattrs.py +++ b/test/testattrs.py @@ -3,9 +3,10 @@ from llvm.core import * from io import StringIO +import unittest def make_module(): - test_module = """ + test_module = u""" define i32 @sum(i32, i32) { entry: %2 = add i32 %0, %1 @@ -14,15 +15,13 @@ def make_module(): """ return Module.from_assembly(StringIO(test_module)) +class TestAttr(unittest.TestCase): + def test_align(self): + m = make_module() + f = m.get_function_named('sum') + f.args[0].alignment = 16 + self.assertIn("align 16", str(f)) + self.assertEqual(f.args[0].alignment, 16) -def test_align(m): - f = m.get_function_named('sum') - f.args[0].alignment = 16 - assert "align 16" in str(f) - assert f.args[0].alignment == 16 - - -m = make_module() -test_align(m) - - +if __name__ == '__main__': + unittest.main() diff --git a/test/typehandle.py b/test/typehandle.py deleted file mode 100755 index 4adb53d..0000000 --- a/test/typehandle.py +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/env python - -from llvm.core import * - -# create a type handle object -th = TypeHandle.new(Type.opaque()) - -# create the struct with an opaque* instead of self* -ts = Type.struct([ Type.int(), Type.pointer(th.type) ]) - -# unify the types -th.type.refine(ts) - -# create a module, and add a "typedef" -m = Module.new('mod1') -m.add_type_name("struct.node", th.type) - -# show what we created -print(m) diff --git a/test/uses.py b/test/uses.py index d0c7e21..97040fa 100755 --- a/test/uses.py +++ b/test/uses.py @@ -2,44 +2,44 @@ from llvm.core import * -m = Module.new('a') -t = Type.int() -ft = Type.function(t, [t, t, t]) -f = m.add_function(ft, "func") -b = f.append_basic_block('entry') -bld = Builder.new(b) -tmp1 = bld.add(Constant.int(t, 100), f.args[0], "tmp1") -tmp2 = bld.add(tmp1, f.args[1], "tmp2") -tmp3 = bld.add(tmp1, f.args[2], "tmp3") -bld.ret(tmp3) +import unittest, logging -print("-"*60) -print(m) -print("-"*60) +class TestUses(unittest.TestCase): + def test_uses(self): + m = Module.new('a') + t = Type.int() + ft = Type.function(t, [t, t, t]) + f = m.add_function(ft, "func") + b = f.append_basic_block('entry') + bld = Builder.new(b) + tmp1 = bld.add(Constant.int(t, 100), f.args[0], "tmp1") + tmp2 = bld.add(tmp1, f.args[1], "tmp2") + tmp3 = bld.add(tmp1, f.args[2], "tmp3") + bld.ret(tmp3) -print("Testing use count ..", end=' ') -c1 = f.args[0].use_count == 1 -c2 = f.args[1].use_count == 1 -c3 = f.args[2].use_count == 1 -c4 = tmp1.use_count == 2 -c5 = tmp2.use_count == 0 -c6 = tmp3.use_count == 1 -if c1 and c2 and c3 and c4 and c5 and c6: - print("OK") -else: - print("FAIL") + logging.debug("-"*60) + logging.debug(m) + logging.debug("-"*60) + + logging.debug("Testing use count ..", end=' ') + self.assertEqual(f.args[0].use_count, 1) + self.assertEqual(f.args[1].use_count, 1) + self.assertEqual(f.args[2].use_count, 1) + self.assertEqual(tmp1.use_count, 2) + self.assertEqual(tmp2.use_count, 0) + self.assertEqual(tmp3.use_count, 1) + + logging.debug("Testing uses ..", end=' ') + self.assertIs(f.args[0].uses[0], tmp1) + self.assertEqual(len(f.args[0].uses), 1) + self.assertIs(f.args[1].uses[0], tmp2) + self.assertEqual(len(f.args[1].uses), 1) + self.assertIs(f.args[2].uses[0], tmp3) + self.assertEqual(len(f.args[2].uses), 1) + self.assertEqual(len(tmp1.uses), 2) + self.assertEqual(len(tmp2.uses), 0) + self.assertEqual(len(tmp3.uses), 1) + +if __name__ == '__main__': + unittest.main() -print("Testing uses ..", end=' ') -c1 = f.args[0].uses[0] is tmp1 -c2 = len(f.args[0].uses) == 1 -c3 = f.args[1].uses[0] is tmp2 -c4 = len(f.args[1].uses) == 1 -c5 = f.args[2].uses[0] is tmp3 -c6 = len(f.args[2].uses) == 1 -c7 = len(tmp1.uses) == 2 -c8 = len(tmp2.uses) == 0 -c9 = len(tmp3.uses) == 1 -if c1 and c2 and c3 and c4 and c5 and c6 and c7 and c8 and c9: - print("OK") -else: - print("FAIL") From 54a0a95fafdfec7c92b33f74f4eeae2705b2c1f2 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Mon, 23 Jul 2012 09:27:24 -0700 Subject: [PATCH 010/675] Fix missing return in llvm/core.py and do some refactoring; Update test/testall.py. TODO: Need to update the passes. --- .gitignore | 1 + llvm/core.py | 28 ++++++++++++++----------- test/testall.py | 56 +++++++++++++++++++++++++++++++------------------ 3 files changed, 53 insertions(+), 32 deletions(-) diff --git a/.gitignore b/.gitignore index bdc5af0..6a0d5e6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ *~ build +*.pyc diff --git a/llvm/core.py b/llvm/core.py index c3a77cc..80753e3 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -603,15 +603,7 @@ class Type(object): If name is not '', creates a identified type; otherwise, creates a literal type.""" - elems = unpack_types(element_tys) - - if name: # create Identified StructType - objptr = _core.LLVMStructTypeIdentified(name) - _core.LLVMSetStructBody(objptr, elems, 0) - else: # create Literal StructType - objptr = _core.LLVMStructType(elems, 0) - - return _make_type(objptr, TYPE_STRUCT) + return Type.__struct(element_tys, packed=False, name=name) @staticmethod def packed_struct(element_tys, name=''): @@ -623,13 +615,25 @@ class Type(object): If name is not '', creates a identified type; otherwise, creates a literal type.""" + return Type.__struct(element_tys, packed=True, name=name) + + @staticmethod + def __struct(element_tys, packed, name): elems = unpack_types(element_tys) + if packed: + packed=1 + else: + packed=0 + if name: # create Identified StructType objptr = _core.LLVMStructTypeIdentified(name) - _core.LLVMSetStructBody(objptr, elems, 0) + _core.LLVMSetStructBody(objptr, elems, packed) else: # create Literal StructType - objptr = _core.LLVMStructType(elems, 1) + objptr = _core.LLVMStructType(elems, packed) + + return _make_type(objptr, TYPE_STRUCT) + @staticmethod def array(element_ty, count): @@ -765,7 +769,7 @@ class StructType(Type): # check if not self.is_opaque: raise llvm.LLVMException("Body is already defined.") - + # prepare arguments elems = unpack_types(elems) if packed: diff --git a/test/testall.py b/test/testall.py index 8bd57de..acf330b 100755 --- a/test/testall.py +++ b/test/testall.py @@ -55,8 +55,11 @@ def do_module(): a = m.target m.data_layout = 'a' a = m.data_layout - m.add_type_name('a', ti) - m.delete_type_name('a') + # m.add_type_name('a', ti) + # m.delete_type_name('a') + Type.struct([ti], name='a') + m.get_type_named('a').name='' + s = str(m) s = m == Module.new('a') m.add_global_variable(ti, 'b') @@ -86,7 +89,9 @@ def do_module(): ss = strstream() m2 = Module.new('test') - m2.add_type_name('myint', ti) + # m2.add_type_name('myint', ti) + Type.struct([ti], 'myint') + m2.to_bitcode(ss) m3 = Module.from_bitcode(ss) t = m2 == m3 @@ -119,10 +124,11 @@ def do_type(): Type.vector(ti, 100) Type.void() Type.label() - Type.opaque() + + Type.opaque('an_opaque_type') s = str(ti) s = ti == Type.float() - Type.opaque().refine(Type.int()) + Type.opaque('whatever').set_body([Type.int()]) s = ti.width ft = Type.function(ti, [ti]*10) ft.return_type @@ -149,12 +155,12 @@ def do_type(): Type.int(32) != Type.int(64) Type.int(32) != Type.float() - -def do_typehandle(): - print(" Testing class TypeHandle") - th = TypeHandle.new(Type.opaque()) - ts = Type.struct([ Type.int(), Type.pointer(th.type) ]) - th.type.refine(ts) +### Removed +#def do_typehandle(): +# print(" Testing class TypeHandle") +# th = TypeHandle.new(Type.opaque()) +# ts = Type.struct([ Type.int(), Type.pointer(th.type) ]) +# th.type.refine(ts) def do_value(): @@ -210,6 +216,7 @@ def do_constant(): vi = Constant.vector([Constant.int(ti,42)]*10) vf = Constant.vector([Constant.real(Type.float(), 3.14)]*10) k.shl(k).lshr(k).ashr(k) + return # TODO gep k.trunc(Type.int(1)) k.sext(Type.int(64)) @@ -414,7 +421,7 @@ def do_builder(): b.cbranch(Constant.int(Type.int(1), 1), blk, blk) b.switch(f.args[0], blk) b.invoke(f, [Constant.int(ti,10)], blk, blk) - b.unwind() + # b.unwind() # removed b.unreachable() v = f.args[0] fv = Constant.real(Type.float(), "1.0") @@ -462,6 +469,7 @@ def do_builder(): b.icmp(IPRED_ULT, v, v) b.fcmp(RPRED_ULT, fv, fv) vi = Constant.vector([Constant.int(ti,42)]*10) + vi_mask = Constant.vector([Constant.int(ti, X) for X in range(20)]) vf = Constant.vector([Constant.real(Type.float(), 3.14)]*10) # TODO b.extract_value(v, 0) b.call(f, [v]) @@ -469,7 +477,7 @@ def do_builder(): b.vaarg(v, Type.int()) b.extract_element(vi, v) b.insert_element(vi, v, v) - b.shuffle_vector(vi, vi, vi) + b.shuffle_vector(vi, vi, vi_mask) # NOTE: phi nodes without incoming values segfaults in LLVM during # destruction. i = b.phi(Type.int()) @@ -491,7 +499,7 @@ def do_llvm_core(): print(" Testing module llvm.core") do_module() do_type() - do_typehandle() + # do_typehandle() do_value() do_user() do_constant() @@ -577,11 +585,18 @@ def do_passmanager(): print(" Testing class PassManager") pm = PassManager.new() pm.add(TargetData.new('')) - for i in [getattr(llvm.passes, x) for x in \ - dir(llvm.passes) if x.startswith('PASS_') and x not in \ - ('PASS_OPTIMAL_EDGE_PROFILER', 'PASS_EDGE_PROFILER', \ - 'PASS_PROFILE_LOADER', 'PASS_AAEVAL')]: - pm.add(i) + + print('.........Begging for rewrite!!!') + ### It is not practical to maintain all PASS_* constants. + # + # passes = ('PASS_OPTIMAL_EDGE_PROFILER', 'PASS_EDGE_PROFILER', + # 'PASS_PROFILE_LOADER', 'PASS_AAEVAL') + # all_these = [getattr(llvm.passes, x) + # for x in dir(llvm.passes) + # if x.startswith('PASS_') and x not in passes] + # for i in all_these: + # print i + # pm.add(i) pm.run(Module.new('a')) @@ -615,7 +630,8 @@ def main(): do_llvm_passes() -main() +if __name__ == '__main__': + main() # to add: # IntegerType From 6fb55db69d3bba737ff893ed971d155950d266ea Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Mon, 23 Jul 2012 13:05:11 -0700 Subject: [PATCH 011/675] Added test for constants -- int, float, double, string, struct, vector. --- test/constants.py | 299 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 299 insertions(+) create mode 100755 test/constants.py diff --git a/test/constants.py b/test/constants.py new file mode 100755 index 0000000..4a2e543 --- /dev/null +++ b/test/constants.py @@ -0,0 +1,299 @@ +#! /usr/bin/env python + +''' +Test and stress Constants. +''' + +from llvm.core import * +from llvm.ee import * +from ctypes import * + +import unittest, logging + +# logging.basicConfig(level=logging.DEBUG) + +def _build_test_module(datatype, constants): + mod = Module.new('module_test_const_%s' % datatype) + fnty_callback = Type.function(Type.void(), [datatype]) + fnty_subject = Type.function(Type.void(), [Type.pointer(fnty_callback)]) + func_subject = mod.add_function(fnty_subject, 'test_const_%s' % datatype) + + bb_entry = func_subject.append_basic_block('entry') + builder = Builder.new(bb_entry) + + + + for k in constants: + builder.call(func_subject.args[0], [k]) + + builder.ret_void() + + func_subject.verify() + + return mod, func_subject + +def _build_test_module_array(datatype, constants): + mod = Module.new('module_test_const_%s' % datatype) + fnty_callback = Type.function(Type.void(), [datatype]) + fnty_subject = Type.function(Type.void(), [Type.pointer(fnty_callback)]) + func_subject = mod.add_function(fnty_subject, 'test_const_%s' % datatype) + + bb_entry = func_subject.append_basic_block('entry') + builder = Builder.new(bb_entry) + + + for k in constants: + ptr = builder.alloca(k.type) + builder.store(k, ptr) + builder.call(func_subject.args[0], + [builder.gep(ptr, [Constant.int(Type.int(), 0)]*2)]) + + builder.ret_void() + + func_subject.verify() + + return mod, func_subject + +def _build_test_module_struct(datatype, constants): + mod = Module.new('module_test_const_%s' % datatype) + fnty_callback = Type.function(Type.void(), [datatype]) + fnty_subject = Type.function(Type.void(), [Type.pointer(fnty_callback)]) + func_subject = mod.add_function(fnty_subject, 'test_const_%s' % datatype) + + bb_entry = func_subject.append_basic_block('entry') + builder = Builder.new(bb_entry) + + for k in constants: + ptr = builder.alloca(k.type) + builder.store(k, ptr) + builder.call(func_subject.args[0], [ptr]) + + builder.ret_void() + + func_subject.verify() + + return mod, func_subject + +class TestConstants(unittest.TestCase): + def test_const_int(self): + from random import randint + values = [0, -1, 1, 0xfffffffe, 0xffffffff, 0x100000000] + values += [randint(0, 0xffffffff) for x in range(100)] + + constant_list = map(lambda X: Constant.int(Type.int(), X), values) + mod, func_subject = _build_test_module(Type.int(), constant_list) + + # done function generation + logging.debug(func_subject) + + # prepare execution + ee = ExecutionEngine.new(mod) + + cf_callback = CFUNCTYPE(None, c_uint32) + cf_test = CFUNCTYPE(None, cf_callback) + + test_subject = cf_test(ee.get_pointer_to_function(func_subject)) + + # setup callback + results = [] + def callback(value): + results.append(value) + + test_subject(cf_callback(callback)) + + # check result + for result, golden in zip(results, values): + self.assertEqual(result, golden & 0xffffffff) + + def test_const_float(self): + from random import random + values = [0., 1., -1.] + [random() for x in range(100)] + + constant_list = map(lambda X: Constant.real(Type.float(), X), values) + mod, func_subject = _build_test_module(Type.float(), constant_list) + + # done function generation + logging.debug(func_subject) + + # prepare execution + ee = ExecutionEngine.new(mod) + + cf_callback = CFUNCTYPE(None, c_float) + cf_test = CFUNCTYPE(None, cf_callback) + + test_subject = cf_test(ee.get_pointer_to_function(func_subject)) + + # setup callback + results = [] + def callback(value): + results.append(value) + + test_subject(cf_callback(callback)) + + # check result + for result, golden in zip(results, values): + if golden == 0: + self.assertEqual(result, golden) + else: + self.assertLess(abs(result-golden)/golden, 1e-7) + + def test_const_double(self): + from random import random + values = [0., 1., -1.] + [random() for x in range(100)] + + constant_list = map(lambda X: Constant.real(Type.double(), X), values) + mod, func_subject = _build_test_module(Type.double(), constant_list) + + # done function generation + logging.debug(func_subject) + + # prepare execution + ee = ExecutionEngine.new(mod) + + cf_callback = CFUNCTYPE(None, c_double) + cf_test = CFUNCTYPE(None, cf_callback) + + test_subject = cf_test(ee.get_pointer_to_function(func_subject)) + + # setup callback + results = [] + def callback(value): + results.append(value) + + test_subject(cf_callback(callback)) + + # check result + for result, golden in zip(results, values): + self.assertEqual(result, golden) + + def test_const_string(self): + values = ["hello", "world", "", "\n"] + + constant_list = map(Constant.stringz, values) + mod, func_subject = _build_test_module_array(Type.pointer(Type.int(8)), + constant_list) + + # done function generation + logging.debug(func_subject) + + # prepare execution + ee = ExecutionEngine.new(mod) + + cf_callback = CFUNCTYPE(None, c_char_p) + cf_test = CFUNCTYPE(None, cf_callback) + + test_subject = cf_test(ee.get_pointer_to_function(func_subject)) + + # setup callback + results = [] + def callback(value): + results.append(value) + + test_subject(cf_callback(callback)) + + # check result + for result, golden in zip(results, values): + self.assertEqual(result, golden) + + def test_const_struct(self): + from random import randint, random + values = [ + (0, 0., 0.), + (-1, -1., -1.), + (1, 1., 1.), + ] + [(randint(0, 0xffffffff), random(), random()) for _ in xrange(100)] + + struct_type = Type.struct([Type.int(), Type.float(), Type.double()]) + + def map_constant(packed_values): + vi, vf, vd = packed_values + return Constant.struct([ + Constant.int(Type.int(), vi), + Constant.real(Type.float(), vf), + Constant.real(Type.double(), vd), + ]) + + constant_list = map(map_constant, values) + + mod, func_subject = _build_test_module_struct(Type.pointer(struct_type), + constant_list) + + # done function generation + logging.debug(func_subject) + + # prepare execution + ee = ExecutionEngine.new(mod) + + class c_struct_type(Structure): + _fields_ = [ ('vi', c_uint32), + ('vf', c_float), + ('vd', c_double), ] + + def __iter__(self): + return iter([self.vi, self.vf, self.vd]) + + cf_callback = CFUNCTYPE(None, POINTER(c_struct_type)) + cf_test = CFUNCTYPE(None, cf_callback) + + test_subject = cf_test(ee.get_pointer_to_function(func_subject)) + + # setup callback + results = [] + def callback(value): + results.append(tuple(value[0])) + + test_subject(cf_callback(callback)) + + # check result + for result, golden in zip(results, values): + self.assertEqual(result[0], golden[0] & 0xffffffff) + if golden[1] == 0: + self.assertEqual(result[1], golden[1]) + else: + self.assertLess(abs(result[1]-golden[1])/golden[1], 1e-7) + self.assertEqual(result[2], golden[2]) + + def test_const_vector(self): + from random import randint + randgen = lambda: randint(0, 0xffffffff) + values = [ + (0, 0, 0, 0), + (1, 1, 1, 1), + (-1, -1, -1, -1), + ] + [ (randgen(), randgen(), randgen(), randgen()) for _ in xrange(100) ] + + def map_constant(packed_values): + consts = [ Constant.int(Type.int(), i) for i in packed_values ] + return Constant.vector(consts) + + constant_list = map(map_constant, values) + mod, func_subject = _build_test_module_array(Type.pointer(Type.int()), + constant_list) + + # done function generation + logging.debug(func_subject) + + # prepare execution + ee = ExecutionEngine.new(mod) + + cf_callback = CFUNCTYPE(None, POINTER(c_uint32)) + cf_test = CFUNCTYPE(None, cf_callback) + + test_subject = cf_test(ee.get_pointer_to_function(func_subject)) + + # setup callback + results = [] + def callback(value): + results.append(tuple(value[0:4])) + + test_subject(cf_callback(callback)) + + # check result + for result, golden in zip(results, values): + self.assertEqual(result, + tuple(map(lambda X: X & 0xffffffff, golden))) + + +if __name__ == '__main__': + unittest.main() + From 2d79cfa437e324860f4cd3031a225b3cdcd94bd7 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Mon, 23 Jul 2012 17:39:40 -0700 Subject: [PATCH 012/675] Replaced PASS_* constants with pass name lookup. --- llvm/_core.c | 17 ++++ llvm/extra.cpp | 64 ++++++++++++-- llvm/extra.h | 43 +++++---- llvm/passes.py | 230 ++++++++----------------------------------------- llvm/wrap.h | 30 +++++++ test/passes.py | 6 +- 6 files changed, 176 insertions(+), 214 deletions(-) diff --git a/llvm/_core.c b/llvm/_core.c index 269d57f..61c34e0 100644 --- a/llvm/_core.c +++ b/llvm/_core.c @@ -853,12 +853,24 @@ _wrap_obj2obj(LLVMInitializeFunctionPassManager, LLVMPassManagerRef, int) _wrap_objobj2obj(LLVMRunFunctionPassManager, LLVMPassManagerRef, LLVMValueRef, int) _wrap_obj2obj(LLVMFinalizeFunctionPassManager, LLVMPassManagerRef, int) _wrap_obj2none(LLVMDisposePassManager, LLVMPassManagerRef) +_wrap_none2str(LLVMDumpPasses) +_wrap_objstr2obj(LLVMAddPassByName, LLVMPassManagerRef, int) + +static PyObject * +_wLLVMInitializePasses(PyObject * self, PyObject * args) +{ + if (!PyArg_ParseTuple(args, "")) + return NULL; + LLVMInitializePasses(); + Py_RETURN_NONE; +} /*===----------------------------------------------------------------------===*/ /* Passes */ /*===----------------------------------------------------------------------===*/ + #define _wrap_pass(P) \ _wrap_obj2none( LLVMAdd ## P ## Pass, LLVMPassManagerRef) @@ -1683,8 +1695,13 @@ static PyMethodDef core_methods[] = { _method( LLVMRunFunctionPassManager ) _method( LLVMFinalizeFunctionPassManager ) _method( LLVMDisposePassManager ) + _method( LLVMDumpPasses ) + _method( LLVMAddPassByName ) + _method( LLVMInitializePasses ) /* Passes */ + + _pass( AAEval ) _pass( AggressiveDCE ) _pass( AliasAnalysisCounter ) diff --git a/llvm/extra.cpp b/llvm/extra.cpp index 60b7ef9..8e6ec83 100644 --- a/llvm/extra.cpp +++ b/llvm/extra.cpp @@ -11,7 +11,7 @@ * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * - * * Neither the name of this software, nor the names of its + * * Neither the name of this software, nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * @@ -78,6 +78,22 @@ //using namespace llvm; +/* + * For use in LLVMDumpPasses to dump passes. + */ +class PassRegistryPrinter : public llvm::PassRegistrationListener{ +public: + std::ostringstream stringstream; + + void passEnumerate(const llvm::PassInfo * pass_info){ + stringstream << pass_info->getPassArgument() + << "\t" + << pass_info->getPassName() + << "\n"; + } +}; + + /* Helper method for LLVMDumpXXXToString() methods. */ template char *do_print(W obj) @@ -90,6 +106,44 @@ char *do_print(W obj) return strdup(buf.str().c_str()); } +int LLVMAddPassByName(LLVMPassManagerRef pm, const char * name) +{ + using namespace llvm; + const PassInfo * pi = Pass::lookupPassInfo(StringRef(name)); + if (pi){ + unwrap(pm)->add(pi->createPass()); + return 1; // success + } else { + return 0; // fail -- cannot find pass + } +} + +void LLVMInitializePasses(){ + using namespace llvm; + PassRegistry ®istry = *PassRegistry::getPassRegistry(); + initializeCore(registry); + initializeScalarOpts(registry); + initializeVectorization(registry); + initializeIPO(registry); + initializeAnalysis(registry); + initializeIPA(registry); + initializeTransformUtils(registry); + initializeInstCombine(registry); + initializeInstrumentation(registry); + initializeTarget(registry); +} + + +const char * LLVMDumpPasses() +{ + using namespace llvm; + PassRegistry ®istry = *PassRegistry::getPassRegistry(); + PassRegistryPrinter prp; + registry.enumerateWith(&prp); + return strdup(prp.stringstream.str().c_str()); +} + + int LLVMIsLiteralStruct(LLVMTypeRef type) { return llvm::unwrap(type)->isLiteral(); @@ -263,7 +317,7 @@ void unwrap_cvec(W *values, unsigned n, std::vector& out) } } -LLVMValueRef LLVMBuildRetMultiple(LLVMBuilderRef builder, +LLVMValueRef LLVMBuildRetMultiple(LLVMBuilderRef builder, LLVMValueRef *values, unsigned n_values) { assert(values); @@ -277,7 +331,7 @@ LLVMValueRef LLVMBuildRetMultiple(LLVMBuilderRef builder, return llvm::wrap(builderp->CreateAggregateRet(&values_vec[0], values_vec.size())); } -LLVMValueRef LLVMBuildGetResult(LLVMBuilderRef builder, +LLVMValueRef LLVMBuildGetResult(LLVMBuilderRef builder, LLVMValueRef value, unsigned index, const char *name) { assert(name); @@ -380,7 +434,7 @@ LLVMValueRef LLVMGetIntrinsic(LLVMModuleRef module, int id, llvm::Module *modulep = llvm::unwrap(module); assert(modulep); - llvm::Function *intfunc = llvm::Intrinsic::getDeclaration(modulep, + llvm::Function *intfunc = llvm::Intrinsic::getDeclaration(modulep, llvm::Intrinsic::ID(id), types_vec[0]); return wrap(intfunc); @@ -428,7 +482,7 @@ LLVMModuleRef LLVMGetModuleFromBitcode(const char *bitcode, unsigned bclen, return wrap(modulep); } -unsigned LLVMLinkModules(LLVMModuleRef dest, LLVMModuleRef src, unsigned int mode, +unsigned LLVMLinkModules(LLVMModuleRef dest, LLVMModuleRef src, unsigned int mode, char **out) { llvm::Module *sourcep = llvm::unwrap(src); diff --git a/llvm/extra.h b/llvm/extra.h index ed52a10..a77e54b 100644 --- a/llvm/extra.h +++ b/llvm/extra.h @@ -11,7 +11,7 @@ * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * - * * Neither the name of this software, nor the names of its + * * Neither the name of this software, nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * @@ -41,6 +41,19 @@ extern "C" { #endif +int LLVMAddPassByName(LLVMPassManagerRef pm, const char * name); + +/* + * Wraps initialize* + */ +void LLVMInitializePasses(); + +/* + * Wraps PassRegistry::enumerateWith() + * Returns a '\n' separated string of all passes available to `opt`. + */ +const char * LLVMDumpPasses(); + /* * Wraps StructType::isLiteral() */ @@ -48,7 +61,7 @@ int LLVMIsLiteralStruct(LLVMTypeRef type); /* * Wraps StructType::create() - */ + */ LLVMTypeRef LLVMStructTypeIdentified(const char * name); /* @@ -58,18 +71,18 @@ void LLVMSetStructBody(LLVMTypeRef type, LLVMTypeRef* elemtys, unsigned elemct, /* * Wraps llvm::StructType::setName() - */ + */ void LLVMSetStructName(LLVMTypeRef type, const char * name); /* * Wraps llvm::Module::getModuleIdentifier() - */ + */ char *LLVMGetModuleIdentifier(LLVMModuleRef module); /* * Wraps llvm::Module::setModuleIdentifier() - */ + */ void LLVMSetModuleIdentifier(LLVMModuleRef module, const char * name); /* Notes: @@ -129,14 +142,14 @@ LLVMValueRef LLVMConstVICmp(LLVMIntPredicate predicate, LLVMValueRef lhs, LLVMValueRef LLVMConstVFCmp(LLVMRealPredicate predicate, LLVMValueRef lhs, LLVMValueRef rhs); -/* Wraps llvm::IRBuilder::CreateVICmp(). */ +/* Wraps llvm::IRBuilder::CreateVICmp(). */ LLVMValueRef LLVMBuildVICmp(LLVMBuilderRef builder, LLVMIntPredicate predicate, LLVMValueRef lhs, LLVMValueRef rhs, const char *name); -/* Wraps llvm::IRBuilder::CreateVFCmp(). */ +/* Wraps llvm::IRBuilder::CreateVFCmp(). */ LLVMValueRef LLVMBuildVFCmp(LLVMBuilderRef builder, LLVMRealPredicate predicate, LLVMValueRef lhs, LLVMValueRef rhs, const char *name); - + /* Wraps llvm::Intrinsic::getDeclaration(). */ LLVMValueRef LLVMGetIntrinsic(LLVMModuleRef builder, int id, LLVMTypeRef *types, unsigned n_types); @@ -151,12 +164,12 @@ void LLVMSetDoesNotThrow(LLVMValueRef fn, int DoesNotThrow); unsigned LLVMModuleGetPointerSize(LLVMModuleRef module); /* Wraps llvm::Module::getOrInsertFunction(). */ -LLVMValueRef LLVMModuleGetOrInsertFunction(LLVMModuleRef module, +LLVMValueRef LLVMModuleGetOrInsertFunction(LLVMModuleRef module, const char *name, LLVMTypeRef function_type); -/* Wraps llvm::GlobalVariable::hasInitializer(). */ +/* Wraps llvm::GlobalVariable::hasInitializer(). */ int LLVMHasInitializer(LLVMValueRef global_var); - + /* The following functions wrap various llvm::Instruction::isXXX() functions. * All of them take an instruction and return 0 (isXXX returned false) or 1 * (isXXX returned false). */ @@ -197,7 +210,7 @@ LLVMModuleRef LLVMGetModuleFromBitcode(const char *bc, unsigned bclen, /* Wraps llvm::Linker::LinkModules(). Returns 0 on failure (with errmsg * filled in) and 1 on success. Dispose error message after use with * LLVMDisposeMessage(). */ -unsigned LLVMLinkModules(LLVMModuleRef dest, LLVMModuleRef src, +unsigned LLVMLinkModules(LLVMModuleRef dest, LLVMModuleRef src, unsigned int, char **errmsg); /* Returns pointer to a heap-allocated block of `*len' bytes containing bit code @@ -209,12 +222,12 @@ unsigned char *LLVMGetBitcodeFromModule(LLVMModuleRef module, unsigned *len); * use, via LLVMDisposeMessage(). */ unsigned LLVMLoadLibraryPermanently(const char* filename, char **errmsg); -/* Wraps llvm::ExecutionEngine::getPointerToFunction(). Returns a pointer +/* Wraps llvm::ExecutionEngine::getPointerToFunction(). Returns a pointer * to the JITted function. */ void *LLVMGetPointerToFunction(LLVMExecutionEngineRef ee, LLVMValueRef fn); -/* Wraps llvm::InlineFunction(). Inlines a function. C is the call - * instruction, created by LLVMBuildCall. Even if it fails, the Function +/* Wraps llvm::InlineFunction(). Inlines a function. C is the call + * instruction, created by LLVMBuildCall. Even if it fails, the Function * containing the call is still in a proper state (not changed). */ //int LLVMInlineFunction(LLVMValueRef call); diff --git a/llvm/passes.py b/llvm/passes.py index 96860f7..b39b367 100644 --- a/llvm/passes.py +++ b/llvm/passes.py @@ -40,188 +40,6 @@ import llvm.ee as ee # target data import llvm.core as core # module, function etc. import llvm._core as _core # C wrappers - -# passes -PASS_AAEVAL = 1 -PASS_AGGRESSIVE_DCE = 3 -PASS_ALIAS_ANALYSIS_COUNTER = 4 -PASS_ALWAYS_INLINER = 5 -PASS_ARGUMENT_PROMOTION = 6 -PASS_BASIC_ALIAS_ANALYSIS = 7 -PASS_BLOCK_PLACEMENT = 8 -PASS_BREAK_CRITICAL_EDGES = 9 -PASS_CFG_SIMPLIFICATION = 10 -PASS_CODE_GEN_PREPARE = 11 -PASS_CONSTANT_MERGE = 12 -PASS_CONSTANT_PROPAGATION = 13 -PASS_DBG_INFO_PRINTER = 14 -PASS_DEAD_ARG_ELIMINATION = 15 -PASS_DEAD_CODE_ELIMINATION = 16 -PASS_DEAD_INST_ELIMINATION = 17 -PASS_DEAD_STORE_ELIMINATION = 18 -PASS_DEAD_TYPE_ELIMINATION = 19 -PASS_DEMOTE_REGISTER_TO_MEMORY = 20 -PASS_DOM_ONLY_PRINTER = 21 -PASS_DOM_ONLY_VIEWER = 22 -PASS_DOM_PRINTER = 23 -PASS_DOM_VIEWER = 24 -PASS_EDGE_PROFILER = 25 -PASS_FUNCTION_ATTRS = 26 -PASS_FUNCTION_INLINING = 27 -#PASS_GEP_SPLITTER = 28 -PASS_GLOBAL_DCE = 29 -PASS_GLOBAL_OPTIMIZER = 30 -PASS_GLOBALS_MOD_REF = 31 -PASS_GVN = 32 -PASS_IND_VAR_SIMPLIFY = 33 -PASS_INST_COUNT = 34 -PASS_INSTRUCTION_COMBINING = 35 -PASS_INSTRUCTION_NAMER = 36 -PASS_IP_CONSTANT_PROPAGATION = 37 -PASS_IPSCCP = 38 -PASS_JUMP_THREADING = 39 -PASS_LAZY_VALUE_INFO = 40 -PASS_LCSSA = 41 -PASS_LICM = 42 -#PASS_LIVE_VALUES = 43 -PASS_LOOP_DELETION = 44 -PASS_LOOP_DEPENDENCE_ANALYSIS = 45 -PASS_LOOP_EXTRACTOR = 46 -#PASS_LOOP_INDEX_SPLIT = 47 -PASS_LOOP_ROTATE = 48 -PASS_LOOP_SIMPLIFY = 49 -PASS_LOOP_STRENGTH_REDUCE = 50 -PASS_LOOP_UNROLL = 51 -PASS_LOOP_UNSWITCH = 52 -PASS_LOWER_INVOKE = 53 -PASS_LOWER_SET_JMP = 54 -PASS_LOWER_SWITCH = 55 -PASS_MEM_CPY_OPT = 56 -PASS_MERGE_FUNCTIONS = 57 -PASS_NO_AA = 58 -PASS_NO_PROFILE_INFO = 59 -PASS_OPTIMAL_EDGE_PROFILER = 60 -PASS_PARTIAL_INLINING = 61 -#PASS_PARTIAL_SPECIALIZATION = 62 -#PASS_POST_DOM_ONLY_PRINTER = 63 -#PASS_POST_DOM_ONLY_VIEWER = 64 -#PASS_POST_DOM_PRINTER = 65 -#PASS_POST_DOM_VIEWER = 66 -PASS_PROFILE_ESTIMATOR = 67 -PASS_PROFILE_LOADER = 68 -PASS_PROFILE_VERIFIER = 69 -PASS_PROMOTE_MEMORY_TO_REGISTER = 70 -PASS_PRUNE_EH = 71 -PASS_REASSOCIATE = 72 -PASS_SCALAR_EVOLUTION_ALIAS_ANALYSIS = 73 -PASS_SCALAR_REPL_AGGREGATES = 74 -PASS_SCCP = 76 -#PASS_SIMPLIFY_HALF_POWR_LIB_CALLS = 77 -PASS_SIMPLIFY_LIB_CALLS = 78 -PASS_SINGLE_LOOP_EXTRACTOR = 79 -PASS_STRIP_DEAD_PROTOTYPES = 82 -PASS_STRIP_NON_DEBUG_SYMBOLS = 83 -PASS_STRIP_SYMBOLS = 84 -PASS_STRUCT_RET_PROMOTION = 85 -PASS_TAIL_CALL_ELIMINATION = 86 -PASS_TAIL_DUPLICATION = 87 -PASS_UNIFY_FUNCTION_EXIT_NODES = 88 -PASS_INTERNALIZE = 89 - - - -#===----------------------------------------------------------------------=== -# Helper functions -#===----------------------------------------------------------------------=== - -_pass_creator = { - PASS_AAEVAL : _core.LLVMAddAAEvalPass, - PASS_AGGRESSIVE_DCE : _core.LLVMAddAggressiveDCEPass, - PASS_ALIAS_ANALYSIS_COUNTER : _core.LLVMAddAliasAnalysisCounterPass, - PASS_ALWAYS_INLINER : _core.LLVMAddAlwaysInlinerPass, - PASS_ARGUMENT_PROMOTION : _core.LLVMAddArgumentPromotionPass, - PASS_BASIC_ALIAS_ANALYSIS : _core.LLVMAddBasicAliasAnalysisPass, - PASS_BLOCK_PLACEMENT : _core.LLVMAddBlockPlacementPass, - PASS_BREAK_CRITICAL_EDGES : _core.LLVMAddBreakCriticalEdgesPass, - PASS_CFG_SIMPLIFICATION : _core.LLVMAddCFGSimplificationPass, - PASS_CODE_GEN_PREPARE : _core.LLVMAddCodeGenPreparePass, - PASS_CONSTANT_MERGE : _core.LLVMAddConstantMergePass, - PASS_CONSTANT_PROPAGATION : _core.LLVMAddConstantPropagationPass, - PASS_DBG_INFO_PRINTER : _core.LLVMAddDbgInfoPrinterPass, - PASS_DEAD_ARG_ELIMINATION : _core.LLVMAddDeadArgEliminationPass, - PASS_DEAD_CODE_ELIMINATION : _core.LLVMAddDeadCodeEliminationPass, - PASS_DEAD_INST_ELIMINATION : _core.LLVMAddDeadInstEliminationPass, - PASS_DEAD_STORE_ELIMINATION : _core.LLVMAddDeadStoreEliminationPass, -# PASS_DEAD_TYPE_ELIMINATION : _core.LLVMAddDeadTypeEliminationPass, - PASS_DEMOTE_REGISTER_TO_MEMORY : _core.LLVMAddDemoteRegisterToMemoryPass, - PASS_DOM_ONLY_PRINTER : _core.LLVMAddDomOnlyPrinterPass, - PASS_DOM_ONLY_VIEWER : _core.LLVMAddDomOnlyViewerPass, - PASS_DOM_PRINTER : _core.LLVMAddDomPrinterPass, - PASS_DOM_VIEWER : _core.LLVMAddDomViewerPass, - PASS_EDGE_PROFILER : _core.LLVMAddEdgeProfilerPass, - PASS_FUNCTION_ATTRS : _core.LLVMAddFunctionAttrsPass, - PASS_FUNCTION_INLINING : _core.LLVMAddFunctionInliningPass, -# PASS_GEP_SPLITTER : _core.LLVMAddGEPSplitterPass, - PASS_GLOBAL_DCE : _core.LLVMAddGlobalDCEPass, - PASS_GLOBAL_OPTIMIZER : _core.LLVMAddGlobalOptimizerPass, - PASS_GLOBALS_MOD_REF : _core.LLVMAddGlobalsModRefPass, - PASS_GVN : _core.LLVMAddGVNPass, - PASS_IND_VAR_SIMPLIFY : _core.LLVMAddIndVarSimplifyPass, - PASS_INST_COUNT : _core.LLVMAddInstCountPass, - PASS_INSTRUCTION_COMBINING : _core.LLVMAddInstructionCombiningPass, - PASS_INSTRUCTION_NAMER : _core.LLVMAddInstructionNamerPass, - PASS_IP_CONSTANT_PROPAGATION : _core.LLVMAddIPConstantPropagationPass, - PASS_IPSCCP : _core.LLVMAddIPSCCPPass, - PASS_JUMP_THREADING : _core.LLVMAddJumpThreadingPass, - PASS_LAZY_VALUE_INFO : _core.LLVMAddLazyValueInfoPass, - PASS_LCSSA : _core.LLVMAddLCSSAPass, - PASS_LICM : _core.LLVMAddLICMPass, -# PASS_LIVE_VALUES : _core.LLVMAddLiveValuesPass, - PASS_LOOP_DELETION : _core.LLVMAddLoopDeletionPass, - PASS_LOOP_DEPENDENCE_ANALYSIS : _core.LLVMAddLoopDependenceAnalysisPass, - PASS_LOOP_EXTRACTOR : _core.LLVMAddLoopExtractorPass, -# PASS_LOOP_INDEX_SPLIT : _core.LLVMAddLoopIndexSplitPass, - PASS_LOOP_ROTATE : _core.LLVMAddLoopRotatePass, - PASS_LOOP_SIMPLIFY : _core.LLVMAddLoopSimplifyPass, - PASS_LOOP_STRENGTH_REDUCE : _core.LLVMAddLoopStrengthReducePass, - PASS_LOOP_UNROLL : _core.LLVMAddLoopUnrollPass, - PASS_LOOP_UNSWITCH : _core.LLVMAddLoopUnswitchPass, - PASS_LOWER_INVOKE : _core.LLVMAddLowerInvokePass, - PASS_LOWER_SWITCH : _core.LLVMAddLowerSwitchPass, - PASS_MEM_CPY_OPT : _core.LLVMAddMemCpyOptPass, - PASS_MERGE_FUNCTIONS : _core.LLVMAddMergeFunctionsPass, - PASS_NO_AA : _core.LLVMAddNoAAPass, - PASS_NO_PROFILE_INFO : _core.LLVMAddNoProfileInfoPass, - PASS_OPTIMAL_EDGE_PROFILER : _core.LLVMAddOptimalEdgeProfilerPass, - PASS_PARTIAL_INLINING : _core.LLVMAddPartialInliningPass, -# PASS_PARTIAL_SPECIALIZATION : _core.LLVMAddPartialSpecializationPass, -# PASS_POST_DOM_ONLY_PRINTER : _core.LLVMAddPostDomOnlyPrinterPass, -# PASS_POST_DOM_ONLY_VIEWER : _core.LLVMAddPostDomOnlyViewerPass, -# PASS_POST_DOM_PRINTER : _core.LLVMAddPostDomPrinterPass, -# PASS_POST_DOM_VIEWER : _core.LLVMAddPostDomViewerPass, - PASS_PROFILE_ESTIMATOR : _core.LLVMAddProfileEstimatorPass, - PASS_PROFILE_LOADER : _core.LLVMAddProfileLoaderPass, - PASS_PROFILE_VERIFIER : _core.LLVMAddProfileVerifierPass, - PASS_PROMOTE_MEMORY_TO_REGISTER : _core.LLVMAddPromoteMemoryToRegisterPass, - PASS_PRUNE_EH : _core.LLVMAddPruneEHPass, - PASS_REASSOCIATE : _core.LLVMAddReassociatePass, - PASS_SCALAR_EVOLUTION_ALIAS_ANALYSIS : _core.LLVMAddScalarEvolutionAliasAnalysisPass, - PASS_SCALAR_REPL_AGGREGATES : _core.LLVMAddScalarReplAggregatesPass, - PASS_SCCP : _core.LLVMAddSCCPPass, -# PASS_SIMPLIFY_HALF_POWR_LIB_CALLS : _core.LLVMAddSimplifyHalfPowrLibCallsPass, - PASS_SIMPLIFY_LIB_CALLS : _core.LLVMAddSimplifyLibCallsPass, - PASS_SINGLE_LOOP_EXTRACTOR : _core.LLVMAddSingleLoopExtractorPass, - PASS_STRIP_DEAD_PROTOTYPES : _core.LLVMAddStripDeadPrototypesPass, - PASS_STRIP_NON_DEBUG_SYMBOLS : _core.LLVMAddStripNonDebugSymbolsPass, - PASS_STRIP_SYMBOLS : _core.LLVMAddStripSymbolsPass, -# PASS_STRUCT_RET_PROMOTION : _core.LLVMAddStructRetPromotionPass, - PASS_TAIL_CALL_ELIMINATION : _core.LLVMAddTailCallEliminationPass, -# PASS_TAIL_DUPLICATION : _core.LLVMAddTailDuplicationPass, - PASS_UNIFY_FUNCTION_EXIT_NODES : _core.LLVMAddUnifyFunctionExitNodesPass, - PASS_INTERNALIZE : _core.LLVMAddInternalize2Pass, -} - - #===----------------------------------------------------------------------=== # Pass manager #===----------------------------------------------------------------------=== @@ -238,26 +56,27 @@ class PassManager(object): def __del__(self): _core.LLVMDisposePassManager(self.ptr) - def add(self, tgt_data_or_pass_id): - if isinstance(tgt_data_or_pass_id, ee.TargetData): - self._add_target_data(tgt_data_or_pass_id) - elif tgt_data_or_pass_id in _pass_creator: - self._add_pass(tgt_data_or_pass_id) + def add(self, tgt_data_or_pass_name): + if isinstance(tgt_data_or_pass_name, ee.TargetData): + self._add_target_data(tgt_data_or_pass_name) + elif isinstance(tgt_data_or_pass_name, basestring): + self._add_pass(tgt_data_or_pass_name) else: - raise llvm.LLVMException("invalid pass_id (%s)" % str(tgt_data_or_pass_id)) + raise llvm.LLVMException("invalid pass_id (%s)" % str(tgt_data_or_pass_name)) def _add_target_data(self, tgt): _core.LLVMAddTargetData(tgt.ptr, self.ptr) - def _add_pass(self, pass_id): - cfn = _pass_creator[pass_id] - cfn(self.ptr) + def _add_pass(self, pass_name): + status = _core.LLVMAddPassByName(self.ptr, pass_name) + if not status: + assert pass_name not in PASSES, "Registered but not found?" + raise llvm.LLVMException('Invalid pass name "%s"' % pass_name) def run(self, module): core.check_is_module(module) return _core.LLVMRunPassManager(self.ptr, module.ptr) - class FunctionPassManager(PassManager): @staticmethod @@ -279,3 +98,30 @@ class FunctionPassManager(PassManager): def finalize(self): _core.LLVMFinalizeFunctionPassManager(self.ptr) +# Intialize passes +PASSES = None + +def _dump_all_passes(): + passes_sep_by_line = _core.LLVMDumpPasses() + strip = lambda S : S.strip() + for line in passes_sep_by_line.splitlines(): + passarg, passname = map(strip, line.split('\t', 1)) + if passarg: + yield passarg, passname + +def _initialize_passes(): + global PASSES + _core.LLVMInitializePasses() + PASSES = dict(_dump_all_passes()) + + # build globals + def transform(name): + return "PASS_%s" % (name.upper().replace('-', '_')) + + global_symbols = globals() + for i in PASSES: + assert i not in global_symbols + global_symbols[transform(i)] = i + +_initialize_passes() + diff --git a/llvm/wrap.h b/llvm/wrap.h index 096200b..9d1b04b 100644 --- a/llvm/wrap.h +++ b/llvm/wrap.h @@ -355,6 +355,21 @@ _w ## func (PyObject *self, PyObject *args) \ return ctor_ ## outtype ( func ()); \ } + +/** + * Wrap LLVM functions of the type + * const char * func() + */ + #define _wrap_none2str(func) \ +static PyObject * \ +_w ## func (PyObject *self, PyObject *args) \ +{ \ + if (!PyArg_ParseTuple(args, "")) \ + return NULL; \ + return PyBytes_FromString(func()); \ +} + + /** * Wrap LLVM functions of the type * const char *func(intype1 arg1) @@ -1231,6 +1246,21 @@ _w ## func (PyObject *self, PyObject *args) \ return ctor_ ## outtype ( func ()); \ } + +/** + * Wrap LLVM functions of the type + * const char * func() + */ + #define _wrap_none2str(func) \ +static PyObject * \ +_w ## func (PyObject *self, PyObject *args) \ +{ \ + if (!PyArg_ParseTuple(args, "")) \ + return NULL; \ + return PyBytes_FromString(func()); \ +} + + /** * Wrap LLVM functions of the type * const char *func(intype1 arg1) diff --git a/test/passes.py b/test/passes.py index 669bdf3..fc0a478 100755 --- a/test/passes.py +++ b/test/passes.py @@ -59,7 +59,7 @@ class TestPasses(unittest.TestCase): pm.add( TargetData.new('') ) # Add the inlining pass. - pm.add( PASS_FUNCTION_INLINING ) + pm.add( PASS_INLINE ) # Run it! pm.run(m) @@ -88,7 +88,7 @@ class TestPasses(unittest.TestCase): fpm.add( TargetData.new('') ) # Add a DCE pass - fpm.add( PASS_AGGRESSIVE_DCE ) + fpm.add( PASS_ADCE ) # Run the pass on the function 'test1' fpm.run( m.get_function_named('test1') ) @@ -100,6 +100,8 @@ class TestPasses(unittest.TestCase): # Make sure test1 is modified self.assertNotEqual(str(fn_test1).strip(), original_test1.strip()) + def test_dump_passes(self): + self.assertTrue(len(PASSES)>0, msg="Cannot have no passes") if __name__ == '__main__': unittest.main() From 99c7a0736e18b4d32f94ffda33e8f182ab573283 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Tue, 24 Jul 2012 12:25:42 -0700 Subject: [PATCH 013/675] Comment out pass constants in C files. --- llvm/_core.c | 13 +++++++------ llvm/extra.cpp | 8 +++++--- llvm/extra.h | 2 ++ 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/llvm/_core.c b/llvm/_core.c index 61c34e0..55a64f3 100644 --- a/llvm/_core.c +++ b/llvm/_core.c @@ -856,11 +856,11 @@ _wrap_obj2none(LLVMDisposePassManager, LLVMPassManagerRef) _wrap_none2str(LLVMDumpPasses) _wrap_objstr2obj(LLVMAddPassByName, LLVMPassManagerRef, int) -static PyObject * +static PyObject * _wLLVMInitializePasses(PyObject * self, PyObject * args) { - if (!PyArg_ParseTuple(args, "")) - return NULL; + if (!PyArg_ParseTuple(args, "")) + return NULL; LLVMInitializePasses(); Py_RETURN_NONE; } @@ -869,7 +869,7 @@ _wLLVMInitializePasses(PyObject * self, PyObject * args) /*===----------------------------------------------------------------------===*/ /* Passes */ /*===----------------------------------------------------------------------===*/ - +/* #define _wrap_pass(P) \ _wrap_obj2none( LLVMAdd ## P ## Pass, LLVMPassManagerRef) @@ -958,7 +958,7 @@ _wrap_pass( TailCallElimination ) _wrap_pass( UnifyFunctionExitNodes ) _wrap_pass( Internalize2 ) - +*/ /*===----------------------------------------------------------------------===*/ /* Target Data */ /*===----------------------------------------------------------------------===*/ @@ -1701,7 +1701,7 @@ static PyMethodDef core_methods[] = { /* Passes */ - + /* _pass( AAEval ) _pass( AggressiveDCE ) _pass( AliasAnalysisCounter ) @@ -1786,6 +1786,7 @@ static PyMethodDef core_methods[] = { _pass( UnifyFunctionExitNodes ) _pass( Internalize2 ) + */ /* Target Data */ _method( LLVMCreateTargetData ) diff --git a/llvm/extra.cpp b/llvm/extra.cpp index 8e6ec83..876921b 100644 --- a/llvm/extra.cpp +++ b/llvm/extra.cpp @@ -585,10 +585,11 @@ unsigned LLVMGetParamAlignment(LLVMValueRef arg) return argp->getParent()->getParamAlignment(argno + 1); } + /* Passes. A few passes (listed below) are used directly from LLVM-C, * rest are defined here. */ - +/* #define define_pass(P) \ void LLVMAdd ## P ## Pass (LLVMPassManagerRef passmgr) { \ using namespace llvm; \ @@ -646,8 +647,9 @@ define_pass( StripNonDebugSymbols ) //define_pass( StructRetPromotion ) //define_pass( TailDuplication ) define_pass( UnifyFunctionExitNodes ) - +*/ /* we support only internalize(true) */ +/* llvm::ModulePass *createInternalize2Pass() { return llvm::createInternalizePass(true); } define_pass( Internalize2 ) - +*/ diff --git a/llvm/extra.h b/llvm/extra.h index a77e54b..bd6a264 100644 --- a/llvm/extra.h +++ b/llvm/extra.h @@ -238,6 +238,7 @@ unsigned LLVMGetParamAlignment(LLVMValueRef arg); /* Passes. Some passes are used directly from LLVM-C, rest are declared * here. */ +/* #define declare_pass(P) \ void LLVMAdd ## P ## Pass (LLVMPassManagerRef PM); @@ -292,6 +293,7 @@ declare_pass( TailDuplication ) declare_pass( UnifyFunctionExitNodes ) declare_pass( Internalize2 ) +*/ #ifdef __cplusplus } /* extern "C" */ From 6a02c36f0407e2bd7d63cc3fb10706c3ea6aefdd Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Tue, 24 Jul 2012 23:42:28 -0700 Subject: [PATCH 014/675] Added PassManagerBuilder. Updated test/passes.py for PassManagerBuilder. --- llvm/_core.c | 73 ++++++++++++++++++++++++++++++++++++++++++++ llvm/core.py | 6 +--- llvm/extra.cpp | 38 +++++++++++++++++++++-- llvm/extra.h | 44 ++++++++++++++++++++++++-- llvm/passes.py | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++ llvm/wrap.c | 12 +++++--- llvm/wrap.h | 8 +++++ test/passes.py | 73 +++++++++++++++++++++++++++++++++++++++++--- 8 files changed, 318 insertions(+), 19 deletions(-) diff --git a/llvm/_core.c b/llvm/_core.c index 55a64f3..1aaa62e 100644 --- a/llvm/_core.c +++ b/llvm/_core.c @@ -842,6 +842,50 @@ _wLLVMCreateMemoryBufferWithSTDIN(PyObject *self, PyObject *args) _wrap_obj2none(LLVMDisposeMemoryBuffer, LLVMMemoryBufferRef) +/*===----------------------------------------------------------------------===*/ +/* Pass Manager Builder */ +/*===----------------------------------------------------------------------===*/ + +_wrap_none2obj(LLVMPassManagerBuilderCreate, LLVMPassManagerBuilderRef) +_wrap_obj2none(LLVMPassManagerBuilderDispose, LLVMPassManagerBuilderRef) + +_wrap_objint2none(LLVMPassManagerBuilderSetOptLevel, LLVMPassManagerBuilderRef) +_wrap_obj2obj(LLVMPassManagerBuilderGetOptLevel, LLVMPassManagerBuilderRef, int) + +_wrap_objint2none(LLVMPassManagerBuilderSetSizeLevel, LLVMPassManagerBuilderRef) +_wrap_obj2obj(LLVMPassManagerBuilderGetSizeLevel, LLVMPassManagerBuilderRef, int) + +_wrap_objint2none(LLVMPassManagerBuilderSetVectorize, LLVMPassManagerBuilderRef) +_wrap_obj2obj(LLVMPassManagerBuilderGetVectorize, LLVMPassManagerBuilderRef, int) + +_wrap_objint2none(LLVMPassManagerBuilderSetDisableUnitAtATime, + LLVMPassManagerBuilderRef) +_wrap_obj2obj(LLVMPassManagerBuilderGetDisableUnitAtATime, + LLVMPassManagerBuilderRef, int) + +_wrap_objint2none(LLVMPassManagerBuilderSetDisableUnrollLoops, + LLVMPassManagerBuilderRef) +_wrap_obj2obj(LLVMPassManagerBuilderGetDisableUnrollLoops, + LLVMPassManagerBuilderRef, int) + +_wrap_objint2none(LLVMPassManagerBuilderSetDisableSimplifyLibCalls, + LLVMPassManagerBuilderRef) +_wrap_obj2obj(LLVMPassManagerBuilderGetDisableSimplifyLibCalls, + LLVMPassManagerBuilderRef, int) + +_wrap_objint2none(LLVMPassManagerBuilderUseInlinerWithThreshold, + LLVMPassManagerBuilderRef) + + +_wrap_objobj2none(LLVMPassManagerBuilderPopulateFunctionPassManager, + LLVMPassManagerBuilderRef, + LLVMPassManagerRef) + +_wrap_objobj2none(LLVMPassManagerBuilderPopulateModulePassManager, + LLVMPassManagerBuilderRef, + LLVMPassManagerRef) + + /*===----------------------------------------------------------------------===*/ /* Pass Manager */ /*===----------------------------------------------------------------------===*/ @@ -1687,6 +1731,35 @@ static PyMethodDef core_methods[] = { _method( LLVMCreateMemoryBufferWithSTDIN ) _method( LLVMDisposeMemoryBuffer ) + /* Pass Manager Builder */ + + _method( LLVMPassManagerBuilderCreate ) + _method( LLVMPassManagerBuilderDispose ) + + _method( LLVMPassManagerBuilderSetOptLevel ) + _method( LLVMPassManagerBuilderGetOptLevel ) + + _method( LLVMPassManagerBuilderSetSizeLevel ) + _method( LLVMPassManagerBuilderGetSizeLevel ) + + _method( LLVMPassManagerBuilderSetVectorize ) + _method( LLVMPassManagerBuilderGetVectorize ) + + + _method( LLVMPassManagerBuilderSetDisableUnitAtATime ) + _method( LLVMPassManagerBuilderGetDisableUnitAtATime ) + + _method( LLVMPassManagerBuilderSetDisableUnrollLoops ) + _method( LLVMPassManagerBuilderGetDisableUnrollLoops ) + + _method( LLVMPassManagerBuilderSetDisableSimplifyLibCalls ) + _method( LLVMPassManagerBuilderGetDisableSimplifyLibCalls ) + + _method( LLVMPassManagerBuilderUseInlinerWithThreshold ) + + _method( LLVMPassManagerBuilderPopulateFunctionPassManager ) + _method( LLVMPassManagerBuilderPopulateModulePassManager ) + /* Pass Manager */ _method( LLVMCreatePassManager ) _method( LLVMCreateFunctionPassManagerForModule ) diff --git a/llvm/core.py b/llvm/core.py index 80753e3..1658846 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -620,11 +620,7 @@ class Type(object): @staticmethod def __struct(element_tys, packed, name): elems = unpack_types(element_tys) - - if packed: - packed=1 - else: - packed=0 + packed = int(bool(packed)) if name: # create Identified StructType objptr = _core.LLVMStructTypeIdentified(name) diff --git a/llvm/extra.cpp b/llvm/extra.cpp index 876921b..86067c0 100644 --- a/llvm/extra.cpp +++ b/llvm/extra.cpp @@ -76,8 +76,6 @@ // our includes #include "extra.h" -//using namespace llvm; - /* * For use in LLVMDumpPasses to dump passes. */ @@ -106,6 +104,42 @@ char *do_print(W obj) return strdup(buf.str().c_str()); } + +int LLVMPassManagerBuilderGetOptLevel(LLVMPassManagerBuilderRef pmb) +{ + return llvm::unwrap(pmb)->OptLevel; +} + +int LLVMPassManagerBuilderGetSizeLevel(LLVMPassManagerBuilderRef pmb) +{ + return llvm::unwrap(pmb)->SizeLevel; +} + +void LLVMPassManagerBuilderSetVectorize(LLVMPassManagerBuilderRef pmb, int flag) +{ + llvm::unwrap(pmb)->Vectorize = flag; +} + +int LLVMPassManagerBuilderGetVectorize(LLVMPassManagerBuilderRef pmb){ + return llvm::unwrap(pmb)->Vectorize; +} + +int LLVMPassManagerBuilderGetDisableUnitAtATime(LLVMPassManagerBuilderRef pmb) +{ + return llvm::unwrap(pmb)->DisableUnitAtATime; +} + +int LLVMPassManagerBuilderGetDisableUnrollLoops(LLVMPassManagerBuilderRef pmb) +{ + return llvm::unwrap(pmb)->DisableUnrollLoops; +} + +int LLVMPassManagerBuilderGetDisableSimplifyLibCalls(LLVMPassManagerBuilderRef pmb) +{ + return llvm::unwrap(pmb)->DisableSimplifyLibCalls; +} + + int LLVMAddPassByName(LLVMPassManagerRef pm, const char * name) { using namespace llvm; diff --git a/llvm/extra.h b/llvm/extra.h index bd6a264..27fadfc 100644 --- a/llvm/extra.h +++ b/llvm/extra.h @@ -37,22 +37,62 @@ #ifndef LLVM_PY_EXTRA_H #define LLVM_PY_EXTRA_H +#include "llvm-c/Transforms/PassManagerBuilder.h" + #ifdef __cplusplus extern "C" { #endif +/* + * Wraps PassManagerBuilder::OptLevel + */ +int LLVMPassManagerBuilderGetOptLevel(LLVMPassManagerBuilderRef pmb); + +/* + * Wraps PassManagerBuilder::SizeLevel + */ +int LLVMPassManagerBuilderGetSizeLevel(LLVMPassManagerBuilderRef pmb); + +/* + * Wraps PassManagerBuilder::Vectorize + */ +void LLVMPassManagerBuilderSetVectorize(LLVMPassManagerBuilderRef pmb, int flag); + +/* + * Wraps PassManagerBuilder::Vectorize + */ +int LLVMPassManagerBuilderGetVectorize(LLVMPassManagerBuilderRef pmb); + +/* + * Wraps PassManagerBuilder::DisableUnitAtATime + */ +int LLVMPassManagerBuilderGetDisableUnitAtATime(LLVMPassManagerBuilderRef pmb); + +/* + * Wraps PassManagerBuilder::DisableUnrollLoops + */ +int LLVMPassManagerBuilderGetDisableUnrollLoops(LLVMPassManagerBuilderRef pmb); + +/* + * Wraps PassManagerBuilder::DisableSimplifyLibCalls + */ +int LLVMPassManagerBuilderGetDisableSimplifyLibCalls(LLVMPassManagerBuilderRef pmb); + +/* + * Wraps PassManager::add + */ int LLVMAddPassByName(LLVMPassManagerRef pm, const char * name); /* * Wraps initialize* */ -void LLVMInitializePasses(); +void LLVMInitializePasses(void); /* * Wraps PassRegistry::enumerateWith() * Returns a '\n' separated string of all passes available to `opt`. */ -const char * LLVMDumpPasses(); +const char * LLVMDumpPasses(void); /* * Wraps StructType::isLiteral() diff --git a/llvm/passes.py b/llvm/passes.py index b39b367..0b64c11 100644 --- a/llvm/passes.py +++ b/llvm/passes.py @@ -40,6 +40,89 @@ import llvm.ee as ee # target data import llvm.core as core # module, function etc. import llvm._core as _core # C wrappers + +#===----------------------------------------------------------------------=== +# Pass manager builder +#===----------------------------------------------------------------------=== + +class PassManagerBuilder(object): + @staticmethod + def new(): + return PassManagerBuilder(_core.LLVMPassManagerBuilderCreate()) + + def __init__(self, ptr): + self.ptr = ptr + + def __del__(self): + _core.LLVMPassManagerBuilderDispose(self.ptr) + + def populate(self, pm): + if isinstance(pm, FunctionPassManager): + return _core.LLVMPassManagerBuilderPopulateFunctionPassManager( + self.ptr, pm.ptr) + else: + return _core.LLVMPassManagerBuilderPopulateModulePassManager( + self.ptr, pm.ptr) + + + def _set_opt_level(self, optlevel): + _core.LLVMPassManagerBuilderSetOptLevel(self.ptr, optlevel) + + def _get_opt_level(self): + return _core.LLVMPassManagerBuilderGetOptLevel(self.ptr) + + opt_level = property(_get_opt_level, _set_opt_level) + + def _set_size_level(self, sizelevel): + _core.LLVMPassManagerBuilderSetSizeLevel(self.ptr, sizelevel) + + def _get_size_level(self): + return _core.LLVMPassManagerBuilderGetSizeLevel(self.ptr) + + size_level = property(_get_size_level, _set_size_level) + + def _set_vectorize(self, enable): + _core.LLVMPassManagerBuilderSetVectorize(self.ptr, int(bool(enable))) + + def _get_vectorize(self): + return bool(_core.LLVMPassManagerBuilderGetVectorize(self.ptr)) + + vectorize = property(_get_vectorize, _set_vectorize) + + def _set_disable_unit_at_a_time(self, disable): + return _core.LLVMPassManagerBuilderSetDisableUnitAtATime( + self.ptr, disable) + + def _get_disable_unit_at_a_time(self): + return _core.LLVMPassManagerBuilderGetDisableUnitAtATime( + self.ptr) + + disable_unit_at_a_time = property(_get_disable_unit_at_a_time, + _set_disable_unit_at_a_time) + + def _set_disable_unroll_loops(self, disable): + return _core.LLVMPassManagerBuilderGetDisableUnrollLoops( + self.ptr, disable) + + def _get_disable_unroll_loops(self): + return _core.LLVMPassManagerBuilderGetDisableUnrollLoops(self.ptr) + + disable_unroll_loops = property(_get_disable_unroll_loops, + _set_disable_unroll_loops) + + def _set_disable_simplify_lib_calls(self, disable): + return _core.LLVMPassManagerBuilderGetDisableSimplifyLibCalls( + self.ptr, disable) + + def _get_disable_simplify_lib_calls(self): + return _core.LLVMPassManagerBuilderGetDisableSimplifyLibCalls(self.ptr) + + disable_simplify_lib_calls = property(_get_disable_simplify_lib_calls, + _set_disable_simplify_lib_calls) + + def use_inliner_with_threshold(self, threshold): + _core.LLVMPassManagerBuilderUseInlinerWithThreshold(self.ptr, threshold) + #===----------------------------------------------------------------------=== # Pass manager #===----------------------------------------------------------------------=== diff --git a/llvm/wrap.c b/llvm/wrap.c index 9bd7e5b..3653061 100644 --- a/llvm/wrap.c +++ b/llvm/wrap.c @@ -11,7 +11,7 @@ * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * - * * Neither the name of this software, nor the names of its + * * Neither the name of this software, nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * @@ -31,7 +31,7 @@ #include "wrap.h" /* Project-wide setting */ -#if (PY_MAJOR_VERSION >= 3) +#if (PY_MAJOR_VERSION >= 3) #define LLVM_PY_USE_PYCAPSULE #endif @@ -39,7 +39,7 @@ /* Helper functions/macros */ /*===----------------------------------------------------------------------===*/ -#ifdef LLVM_PY_USE_PYCAPSULE +#ifdef LLVM_PY_USE_PYCAPSULE #define _define_std_ctor(typ) \ PyObject * ctor_ ## typ ( typ p) \ @@ -76,6 +76,8 @@ _define_std_ctor(LLVMExecutionEngineRef) _define_std_ctor(LLVMTargetDataRef) _define_std_ctor(LLVMGenericValueRef) +_define_std_ctor(LLVMPassManagerBuilderRef) + PyObject *ctor_int(int i) { return PyLong_FromLong((long)i); @@ -108,7 +110,7 @@ void **make_array_from_list(PyObject *list, int n) { int i; void **arr; - + arr = (void **)malloc(sizeof(void *) * n); if (!arr) return NULL; @@ -121,7 +123,7 @@ void **make_array_from_list(PyObject *list, int n) arr[i] = PyCObject_AsVoidPtr(e); #endif } - + return arr; } diff --git a/llvm/wrap.h b/llvm/wrap.h index 9d1b04b..9fd5636 100644 --- a/llvm/wrap.h +++ b/llvm/wrap.h @@ -45,6 +45,10 @@ #include "llvm-c/Analysis.h" #include "llvm-c/ExecutionEngine.h" #include "llvm-c/Target.h" +// workaround missing bool type +#define bool int +#include "llvm-c/Transforms/PassManagerBuilder.h" +#undef bool /* Project-wide setting */ #if PY_MAJOR_VERSION >= 3 @@ -58,6 +62,7 @@ typedef unsigned long long llvmwrap_ull; + /*===----------------------------------------------------------------------===*/ /* Type ctor/dtor */ /*===----------------------------------------------------------------------===*/ @@ -83,6 +88,9 @@ _declare_std_ctor(LLVMExecutionEngineRef) _declare_std_ctor(LLVMTargetDataRef) _declare_std_ctor(LLVMGenericValueRef) +// extra LLVM class not defined in LLVM-C +_declare_std_ctor(LLVMPassManagerBuilderRef) + /* standard types */ _declare_std_ctor(int) _declare_std_ctor(llvmwrap_ull) diff --git a/test/passes.py b/test/passes.py index fc0a478..6415b68 100755 --- a/test/passes.py +++ b/test/passes.py @@ -9,11 +9,11 @@ from StringIO import StringIO import logging, unittest # A helper class. -class strstream(object): - def __init__(self, s): - self.s = s - def read(self): - return self.s +#class strstream(object): +# def __init__(self, s): +# self.s = s +# def read(self): +# return self.s # Create a module. asm = """ @@ -100,9 +100,72 @@ class TestPasses(unittest.TestCase): # Make sure test1 is modified self.assertNotEqual(str(fn_test1).strip(), original_test1.strip()) + def test_passes_with_pmb(self): + m = Module.from_assembly(StringIO(asm)) + logging.debug("-"*72) + logging.debug(m) + + fn_test1 = m.get_function_named('test1') + fn_test2 = m.get_function_named('test2') + + original_test1 = str(fn_test1) + original_test2 = str(fn_test2) + + # Try out the PassManagerBuilder + + pmb = PassManagerBuilder.new() + + self.assertEqual(pmb.opt_level, 2) # ensure default is level 2 + pmb.opt_level = 3 + self.assertEqual(pmb.opt_level, 3) # make sure it works + + self.assertEqual(pmb.size_level, 0) # ensure default is level 0 + pmb.size_level = 2 + self.assertEqual(pmb.size_level, 2) # make sure it works + + self.assertFalse(pmb.vectorize) # ensure default is False + pmb.vectorize = True + self.assertTrue(pmb.vectorize) # make sure it works + + # make sure the default is False + self.assertFalse(pmb.disable_unit_at_a_time) + self.assertFalse(pmb.disable_unroll_loops) + self.assertFalse(pmb.disable_simplify_lib_calls) + + # Do function pass + fpm = FunctionPassManager.new(m) + + pmb.populate(fpm) + + fpm.run(fn_test1) + + # Print the result. Note the change in @test1. + logging.debug("-"*72) + logging.debug(m) + + # Make sure test1 has changed + self.assertNotEqual(str(fn_test1).strip(), original_test1.strip()) + + + # Do module pass + pm = PassManager.new() + + pmb.populate(pm) + + pm.run(m) + + # Print the result. Note the change in @test2. + logging.debug("-"*72) + logging.debug(m) + + # Make sure test2 has changed + self.assertNotEqual(str(fn_test2).strip(), original_test2.strip()) + + def test_dump_passes(self): self.assertTrue(len(PASSES)>0, msg="Cannot have no passes") + if __name__ == '__main__': unittest.main() From 5bb4b8affbba56e254ace1a92f1ec8652e15c10a Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 25 Jul 2012 15:31:18 -0700 Subject: [PATCH 015/675] Added EngineBuilder. Added test/enginebuilder. --- llvm/_core.c | 39 +++++++++++++++++++++++++++ llvm/ee.py | 43 +++++++++++++++++++++++++++++- llvm/extra.cpp | 62 ++++++++++++++++++++++++++++++++++++++++++- llvm/extra.h | 34 ++++++++++++++++++++++++ llvm/llvm_c_extra.h | 29 ++++++++++++++++++++ llvm/wrap.c | 1 + llvm/wrap.h | 6 ++++- test/enginebuilder.py | 56 ++++++++++++++++++++++++++++++++++++++ 8 files changed, 267 insertions(+), 3 deletions(-) create mode 100644 llvm/llvm_c_extra.h create mode 100644 test/enginebuilder.py diff --git a/llvm/_core.c b/llvm/_core.c index 1aaa62e..54e5764 100644 --- a/llvm/_core.c +++ b/llvm/_core.c @@ -1049,6 +1049,36 @@ _wrap_objobjint2obj(LLVMOffsetOfElement, LLVMTargetDataRef, LLVMTypeRef, llvmwrap_ull) +/*===----------------------------------------------------------------------===*/ +/* Engine Builder */ +/*===----------------------------------------------------------------------===*/ + +_wrap_obj2obj(LLVMCreateEngineBuilder, LLVMModuleRef, LLVMEngineBuilderRef) +_wrap_obj2none(LLVMDisposeEngineBuilder, LLVMEngineBuilderRef) +_wrap_obj2none(LLVMEngineBuilderForceJIT, LLVMEngineBuilderRef) +_wrap_obj2none(LLVMEngineBuilderForceInterpreter, LLVMEngineBuilderRef) +_wrap_objint2none(LLVMEngineBuilderSetOptLevel, LLVMEngineBuilderRef) + +static PyObject * +_wLLVMEngineBuilderCreate(PyObject *self, PyObject *args) +{ + LLVMEngineBuilderRef obj; + if (!(obj = (LLVMEngineBuilderRef)get_object_arg(args))) + return NULL; + + char * outmsg = 0; + + PyObject * ret; + ret = LLVMEngineBuilderCreate(obj, &outmsg); + + if( outmsg ){ // check if error message is set. + ret = PyBytes_FromString(outmsg); + free(outmsg); + } + + return ctor_LLVMExecutionEngineRef(ret); +} + /*===----------------------------------------------------------------------===*/ /* Execution Engine */ /*===----------------------------------------------------------------------===*/ @@ -1879,6 +1909,15 @@ static PyMethodDef core_methods[] = { _method( LLVMElementAtOffset ) _method( LLVMOffsetOfElement ) + /* Engine Builder */ + + _method( LLVMCreateEngineBuilder ) + _method( LLVMDisposeEngineBuilder ) + _method( LLVMEngineBuilderForceJIT ) + _method( LLVMEngineBuilderForceInterpreter ) + _method( LLVMEngineBuilderSetOptLevel ) + _method( LLVMEngineBuilderCreate ) + /* Execution Engine */ _method( LLVMCreateExecutionEngine ) _method( LLVMDisposeExecutionEngine ) diff --git a/llvm/ee.py b/llvm/ee.py index a54698d..24b9325 100644 --- a/llvm/ee.py +++ b/llvm/ee.py @@ -145,7 +145,7 @@ class GenericValue(object): core.check_is_type(ty) ptr = _core.LLVMCreateGenericValueOfPointer(ty.ptr, intval) return GenericValue(ptr) - + def __init__(self, ptr): self.ptr = ptr @@ -172,6 +172,47 @@ def _unpack_generic_values(objlist): return _util.unpack_gen(objlist, check_is_generic_value) +#===----------------------------------------------------------------------=== +# Engine builder +#===----------------------------------------------------------------------=== + +class EngineBuilder(object): + @staticmethod + def new(module): + core.check_is_module(module) + _util.check_is_unowned(module) + obj = _core.LLVMCreateEngineBuilder(module.ptr) + return EngineBuilder(obj, module) + + def __init__(self, ptr, module): + self.ptr = ptr + self._module = module + + def __del__(self): + _core.LLVMDisposeEngineBuilder(self.ptr) + + def force_jit(self): + _core.LLVMEngineBuilderForceJIT(self.ptr) + return self + + def force_interpreter(self): + _core.LLVMEngineBuilderForceInterpreter(self.ptr) + return self + + def opt(self, level): + ''' + level valid [0, 1, 2, 3] -- [None, Less, Default, Aggressive] + ''' + assert level in range(4) + _core.LLVMEngineBuilderSetOptLevel(self.ptr, level) + return self + + def create(self): + ret = _core.LLVMEngineBuilderCreate(self.ptr) + if isinstance(ret, basestring): + raise llvm.LLVMException(ret) + return ExecutionEngine(ret, self._module) + #===----------------------------------------------------------------------=== # Execution engine #===----------------------------------------------------------------------=== diff --git a/llvm/extra.cpp b/llvm/extra.cpp index 86067c0..0b5a874 100644 --- a/llvm/extra.cpp +++ b/llvm/extra.cpp @@ -69,13 +69,20 @@ #include "llvm/Linker.h" #include "llvm/Support/SourceMgr.h" + + // LLVM-C includes #include "llvm-c/Core.h" #include "llvm-c/ExecutionEngine.h" // our includes #include "extra.h" +#include "llvm_c_extra.h" + +namespace llvm{ +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(EngineBuilder, LLVMEngineBuilderRef) +} /* * For use in LLVMDumpPasses to dump passes. */ @@ -104,6 +111,58 @@ char *do_print(W obj) return strdup(buf.str().c_str()); } +LLVMEngineBuilderRef LLVMCreateEngineBuilder(LLVMModuleRef mod) +{ + using namespace llvm; + return wrap(new EngineBuilder(unwrap(mod))); +} + +void LLVMDisposeEngineBuilder(LLVMEngineBuilderRef eb) +{ + delete llvm::unwrap(eb); +} + +void LLVMEngineBuilderForceJIT(LLVMEngineBuilderRef eb) +{ + using namespace llvm; + unwrap(eb)->setEngineKind(EngineKind::JIT); +} + +void LLVMEngineBuilderForceInterpreter(LLVMEngineBuilderRef eb) +{ + using namespace llvm; + unwrap(eb)->setEngineKind(EngineKind::Interpreter); +} + +void LLVMEngineBuilderSetOptLevel(LLVMEngineBuilderRef eb, int level) +{ + using namespace llvm; + const CodeGenOpt::Level level_map[] = { + CodeGenOpt::None, + CodeGenOpt::Less, + CodeGenOpt::Default, + CodeGenOpt::Aggressive, + }; + + unwrap(eb)->setOptLevel(level_map[level]); +} + + +LLVMExecutionEngineRef LLVMEngineBuilderCreate(LLVMEngineBuilderRef eb, char **err) +{ + using namespace llvm; + std::string errstring; + LLVMExecutionEngineRef ret; + + ret = wrap(unwrap(eb)->setErrorStr(&errstring).create()); + + if ( !errstring.empty() ) { + *err = strdup(errstring.c_str()); + return 0; + } else { + return ret; + } +} int LLVMPassManagerBuilderGetOptLevel(LLVMPassManagerBuilderRef pmb) { @@ -189,7 +248,8 @@ LLVMTypeRef LLVMStructTypeIdentified(const char * name) return wrap(StructType::create(getGlobalContext(), name)); } -void LLVMSetStructBody(LLVMTypeRef type, LLVMTypeRef* elemtys, unsigned elemct, int is_packed) +void LLVMSetStructBody(LLVMTypeRef type, LLVMTypeRef* elemtys, + unsigned elemct, int is_packed) { using namespace llvm; ArrayRef elemtys_aryref(unwrap(elemtys), elemct); diff --git a/llvm/extra.h b/llvm/extra.h index 27fadfc..9c73098 100644 --- a/llvm/extra.h +++ b/llvm/extra.h @@ -39,10 +39,44 @@ #include "llvm-c/Transforms/PassManagerBuilder.h" +#include "llvm_c_extra.h" + #ifdef __cplusplus extern "C" { #endif +/* + * Wraps new EngineBuilder + */ +LLVMEngineBuilderRef LLVMCreateEngineBuilder(LLVMModuleRef mod); + +/* + * Wraps delete EngineBuilder + */ +void LLVMDisposeEngineBuilder(LLVMEngineBuilderRef eb); + + +/* + * Wraps EngineBuilder::setEngineKind(EngineKind::JIT) + */ +void LLVMEngineBuilderForceJIT(LLVMEngineBuilderRef eb); + +/* + * Wraps EngineBuilder::setEngineKind(EngineKind::Interpreter) + */ +void LLVMEngineBuilderForceInterpreter(LLVMEngineBuilderRef eb); + + +/* + * Wraps EngineBuilder::setOptLevel + */ +void LLVMEngineBuilderSetOptLevel(LLVMEngineBuilderRef eb, int level); + +/* + * Wraps EngineBuilder::setErrorStr and EngineBuilder::create + */ +LLVMExecutionEngineRef LLVMEngineBuilderCreate(LLVMEngineBuilderRef eb, char **err); + /* * Wraps PassManagerBuilder::OptLevel */ diff --git a/llvm/llvm_c_extra.h b/llvm/llvm_c_extra.h new file mode 100644 index 0000000..fc2b711 --- /dev/null +++ b/llvm/llvm_c_extra.h @@ -0,0 +1,29 @@ +#ifndef LLVM_C_EXTRA_H_ +#define LLVM_C_EXTRA_H_ + +#include + + +#ifdef __cplusplus + extern "C" { +#endif + +// Resurrect from llvm-c/Core.h +#define DEFINE_SIMPLE_CONVERSION_FUNCTIONS(ty, ref) \ +inline ty *unwrap(ref P) { \ + return reinterpret_cast(P); \ +} \ + \ +inline ref wrap(const ty *P) { \ + return reinterpret_cast(const_cast(P)); \ +} + +typedef struct LLVMOpaqueEngineBuilder *LLVMEngineBuilderRef; + + +#ifdef __cplusplus + } +#endif + +#endif //LLVM_C_EXTRA_H_ + diff --git a/llvm/wrap.c b/llvm/wrap.c index 3653061..25ea30c 100644 --- a/llvm/wrap.c +++ b/llvm/wrap.c @@ -77,6 +77,7 @@ _define_std_ctor(LLVMTargetDataRef) _define_std_ctor(LLVMGenericValueRef) _define_std_ctor(LLVMPassManagerBuilderRef) +_define_std_ctor(LLVMEngineBuilderRef) PyObject *ctor_int(int i) { diff --git a/llvm/wrap.h b/llvm/wrap.h index 9fd5636..ca963b0 100644 --- a/llvm/wrap.h +++ b/llvm/wrap.h @@ -45,11 +45,14 @@ #include "llvm-c/Analysis.h" #include "llvm-c/ExecutionEngine.h" #include "llvm-c/Target.h" + // workaround missing bool type #define bool int #include "llvm-c/Transforms/PassManagerBuilder.h" #undef bool +#include "llvm_c_extra.h" + /* Project-wide setting */ #if PY_MAJOR_VERSION >= 3 #define LLVM_PY_USE_PYCAPSULE @@ -88,8 +91,9 @@ _declare_std_ctor(LLVMExecutionEngineRef) _declare_std_ctor(LLVMTargetDataRef) _declare_std_ctor(LLVMGenericValueRef) -// extra LLVM class not defined in LLVM-C +// extra LLVM classes _declare_std_ctor(LLVMPassManagerBuilderRef) +_declare_std_ctor(LLVMEngineBuilderRef) /* standard types */ _declare_std_ctor(int) diff --git a/test/enginebuilder.py b/test/enginebuilder.py new file mode 100644 index 0000000..81b6163 --- /dev/null +++ b/test/enginebuilder.py @@ -0,0 +1,56 @@ +from llvm.ee import * +from llvm.core import * +from llvm import _util, LLVMException + +from ctypes import * + +import unittest, logging + +class TestEngineBuilder(unittest.TestCase): + + def make_test_module(self): + module = Module.new("testmodule") + fnty = Type.function(Type.int(), []) + function = module.add_function(fnty, 'foo') + bb_entry = function.append_basic_block('entry') + builder = Builder.new(bb_entry) + builder.ret(Constant.int(Type.int(), 0xcafe)) + module.verify() + return module + + def run_foo(self, ee, module): + function = module.get_function_named('foo') + retval = ee.run_function(function, []) + self.assertEqual(retval.as_int(), 0xcafe) + + + def test_enginebuilder_basic(self): + module = self.make_test_module() + ee = EngineBuilder.new(module).create() + + with self.assertRaises(LLVMException): + # Ensure the module is owned. + _util.check_is_unowned(module) + + self.run_foo(ee, module) + + def test_enginebuilder_force_jit(self): + module = self.make_test_module() + ee = EngineBuilder.new(module).force_jit().create() + + self.run_foo(ee, module) + + def test_enginebuilder_force_interpreter(self): + module = self.make_test_module() + ee = EngineBuilder.new(module).force_interpreter().create() + + self.run_foo(ee, module) + + def test_enginebuilder_opt(self): + module = self.make_test_module() + ee = EngineBuilder.new(module).opt(3).create() + + self.run_foo(ee, module) + +if __name__ == '__main__': + unittest.main() From 93c25ca98bbc41a5ec7b058217bdd702cb0952ef Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 25 Jul 2012 18:25:25 -0700 Subject: [PATCH 016/675] Fix _wLLVMEngineBuilderCreate. --- llvm/_core.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/llvm/_core.c b/llvm/_core.c index 54e5764..2bd8484 100644 --- a/llvm/_core.c +++ b/llvm/_core.c @@ -1067,16 +1067,19 @@ _wLLVMEngineBuilderCreate(PyObject *self, PyObject *args) return NULL; char * outmsg = 0; - - PyObject * ret; - ret = LLVMEngineBuilderCreate(obj, &outmsg); + LLVMExecutionEngineRef ee = LLVMEngineBuilderCreate(obj, &outmsg); + + + PyObject * ret; if( outmsg ){ // check if error message is set. ret = PyBytes_FromString(outmsg); free(outmsg); + }else{ + ret = ctor_LLVMExecutionEngineRef(ee); } - return ctor_LLVMExecutionEngineRef(ret); + return ret; } /*===----------------------------------------------------------------------===*/ From afcdd30c889492f29d4c6e953bf7a95523216a4e Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 25 Jul 2012 18:32:21 -0700 Subject: [PATCH 017/675] Stick with C++ for everything. --- llvm/{_core.c => _core.cpp} | 7 +++++-- llvm/{wrap.c => wrap.cpp} | 0 setup.py | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) rename llvm/{_core.c => _core.cpp} (99%) rename llvm/{wrap.c => wrap.cpp} (100%) diff --git a/llvm/_core.c b/llvm/_core.cpp similarity index 99% rename from llvm/_core.c rename to llvm/_core.cpp index 2bd8484..bccd959 100644 --- a/llvm/_core.c +++ b/llvm/_core.cpp @@ -1067,7 +1067,7 @@ _wLLVMEngineBuilderCreate(PyObject *self, PyObject *args) return NULL; char * outmsg = 0; - + LLVMExecutionEngineRef ee = LLVMEngineBuilderCreate(obj, &outmsg); @@ -1953,7 +1953,8 @@ static PyMethodDef core_methods[] = { // Module main function, hairy because of py3k port - +extern "C" { + #if (PY_MAJOR_VERSION >= 3) struct PyModuleDef module_def = { PyModuleDef_HEAD_INIT, @@ -1987,3 +1988,5 @@ init_core(void) return module; #endif } + +} // end extern C diff --git a/llvm/wrap.c b/llvm/wrap.cpp similarity index 100% rename from llvm/wrap.c rename to llvm/wrap.cpp diff --git a/setup.py b/setup.py index 317d67a..d1450b8 100755 --- a/setup.py +++ b/setup.py @@ -95,7 +95,7 @@ def call_setup(llvm_config): ext_core = Extension( 'llvm._core', - ['llvm/_core.c', 'llvm/wrap.c', 'llvm/extra.cpp'], + ['llvm/_core.cpp', 'llvm/wrap.cpp', 'llvm/extra.cpp'], define_macros = [ ('__STDC_CONSTANT_MACROS', None), ('__STDC_LIMIT_MACROS', None), From 0ca676eb8c27f916acd6abfc4dddd9b53e6efa80 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 25 Jul 2012 19:55:22 -0700 Subject: [PATCH 018/675] Fix Py3 incompatible in tests. --- test/operands.py | 6 +++++- test/passes.py | 5 ++++- test/testattrs.py | 6 +++++- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/test/operands.py b/test/operands.py index b1a47ac..d7f8132 100755 --- a/test/operands.py +++ b/test/operands.py @@ -3,7 +3,11 @@ # Tests accessing of instruction operands. from llvm.core import * -from StringIO import StringIO +try: + from StringIO import StringIO +except ImportError: + from io import StringIO + import logging, unittest m = None diff --git a/test/passes.py b/test/passes.py index 6415b68..ff8f6d1 100755 --- a/test/passes.py +++ b/test/passes.py @@ -3,8 +3,11 @@ from llvm.core import * from llvm.passes import * from llvm.ee import * +try: + from StringIO import StringIO +except ImportError: + from io import StringIO -from StringIO import StringIO import logging, unittest diff --git a/test/testattrs.py b/test/testattrs.py index 24a7b46..09deced 100755 --- a/test/testattrs.py +++ b/test/testattrs.py @@ -1,7 +1,11 @@ #!/usr/bin/env python from llvm.core import * -from io import StringIO +try: + from StringIO import StringIO +except ImportError: + from io import StringIO + import unittest From 9aadd489c346bc0e1d1966a0d3876c7e9b31a8d6 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Thu, 26 Jul 2012 15:25:23 -0700 Subject: [PATCH 019/675] Python3 ready. Py2.7 and Py3 working. Drop PyCObject for all. Pre Py2.7 support should be possible by including "capsulethunk.h". (See llvm/wrap.h) --- llvm/__init__.py | 16 +- llvm/_core.cpp | 212 +++-------- llvm/_util.py | 19 + llvm/core.py | 2 +- llvm/ee.py | 2 +- llvm/extra.cpp | 13 +- llvm/extra.h | 6 +- llvm/passes.py | 6 +- llvm/wrap.cpp | 31 +- llvm/wrap.h | 954 ++-------------------------------------------- setup-win32.py | 16 +- test/asm.py | 20 + test/constants.py | 6 +- test/testattrs.py | 2 +- 14 files changed, 163 insertions(+), 1142 deletions(-) diff --git a/llvm/__init__.py b/llvm/__init__.py index a537015..b540270 100644 --- a/llvm/__init__.py +++ b/llvm/__init__.py @@ -137,8 +137,18 @@ class _ObjectCache(type): # Cacheables #===----------------------------------------------------------------------=== -class Cacheable(object): - __metaclass__ = _ObjectCache +# version 2/3 compatibility help +# version 2 metaclass +# class Cacheable(object): +# __metaclass__ = _ObjectCache # Doing nothing for version 3 +# +# version 3 metaclass +# class Cacheable(metaclass=_ObjectCache): +# +# Reference: http://mikewatkins.ca/2008/11/29/python-2-and-3-metaclasses/#using-the-metaclass-in-python-3-x +ObjectCache = _ObjectCache('ObjectCache', (object, ), {}) + +class Cacheable(ObjectCache): """Objects that can be cached. Objects that wrap a PyCObject are cached to avoid "aliasing", i.e., @@ -146,5 +156,5 @@ class Cacheable(object): to the same C pointer.""" def forget(self): - _ObjectCache.forget(self) + ObjectCache.forget(self) diff --git a/llvm/_core.cpp b/llvm/_core.cpp index bccd959..52310f1 100644 --- a/llvm/_core.cpp +++ b/llvm/_core.cpp @@ -52,11 +52,6 @@ typedef int Py_ssize_t; #endif -/* Project-wide setting */ -#if (PY_MAJOR_VERSION >= 3) -#define LLVM_PY_USE_PYCAPSULE -#endif - /*===----------------------------------------------------------------------===*/ /* Modules */ /*===----------------------------------------------------------------------===*/ @@ -67,18 +62,10 @@ _wLLVMModuleCreateWithName(PyObject *self, PyObject *args) const char *s; LLVMModuleRef module; -#ifdef LLVM_PY_USE_PYCAPSULE - PyObject *s_; - if (!PyArg_ParseTuple(args, "U:LLVMModuleCreateWithName", &s_)) { + if (!PyArg_ParseTuple(args, "s:LLVMModuleCreateWithName", &s)) { return NULL; } - s = PyUnicode_AS_DATA(s_); -#else - if (!PyArg_ParseTuple(args, "s", &s)) - return NULL; -#endif - module = LLVMModuleCreateWithName(s); return ctor_LLVMModuleRef(module); } @@ -112,37 +99,62 @@ _wLLVMVerifyModule(PyObject *self, PyObject *args) (void) LLVMVerifyModule(m, LLVMReturnStatusAction, &outmsg); if (outmsg) { - ret = PyBytes_FromString(outmsg); + ret = PyUnicode_FromString(outmsg); LLVMDisposeMessage(outmsg); } else { - ret = PyBytes_FromString(""); + ret = PyUnicode_FromString(""); } return ret; } -typedef LLVMModuleRef (*asm_or_bc_fn_t)(const char *A, unsigned Len, - char **OutMessage); +///// unused +// typedef LLVMModuleRef (*asm_or_bc_fn_t)(const char *A, unsigned Len, char **OutMessage); + + +static PyObject* +_wLLVMGetModuleFromAssembly(PyObject *self, PyObject *args) +{ + char * str; + if ( !PyArg_ParseTuple(args, "s", &str) ){ + return NULL; + } + + char * outmsg = 0; + LLVMModuleRef mod = LLVMGetModuleFromAssembly(str, &outmsg); + + if ( !mod ){ + if ( outmsg ){ + PyObject * ret = PyUnicode_FromString(outmsg); + LLVMDisposeMessage(outmsg); + return ret; + } else { + Py_RETURN_NONE; + } + } + + return ctor_LLVMModuleRef(mod); +} static PyObject * -_get_asm_or_bc(asm_or_bc_fn_t fn, PyObject *self, PyObject *args) +_wLLVMGetModuleFromBitcode(PyObject *self, PyObject *args) { PyObject *obj, *ret; Py_ssize_t len; char *start, *outmsg; LLVMModuleRef m; - if (!PyArg_ParseTuple(args, "O", &obj)) + if (!PyArg_ParseTuple(args, "S", &obj)) return NULL; start = PyBytes_AsString(obj); len = PyBytes_Size(obj); outmsg = 0; - m = fn(start, len, &outmsg); + m = LLVMGetModuleFromBitcode(start, len, &outmsg); if (!m) { if (outmsg) { - ret = PyBytes_FromString(outmsg); + ret = PyUnicode_FromString(outmsg); LLVMDisposeMessage(outmsg); return ret; } else { @@ -153,18 +165,6 @@ _get_asm_or_bc(asm_or_bc_fn_t fn, PyObject *self, PyObject *args) return ctor_LLVMModuleRef(m); } -static PyObject * -_wLLVMGetModuleFromAssembly(PyObject *self, PyObject *args) -{ - return _get_asm_or_bc(LLVMGetModuleFromAssembly, self, args); -} - -static PyObject * -_wLLVMGetModuleFromBitcode(PyObject *self, PyObject *args) -{ - return _get_asm_or_bc(LLVMGetModuleFromBitcode, self, args); -} - static PyObject * _wLLVMGetBitcodeFromModule(PyObject *self, PyObject *args) { @@ -195,20 +195,15 @@ _wLLVMLinkModules(PyObject *self, PyObject *args) if (!PyArg_ParseTuple(args, "OO|I", &dest_obj, &src_obj, &mode)) return NULL; -#ifdef LLVM_PY_USE_PYCAPSULE dest = (LLVMModuleRef) PyCapsule_GetPointer(dest_obj, NULL); src = (LLVMModuleRef) PyCapsule_GetPointer(src_obj, NULL); -#else - dest = (LLVMModuleRef) PyCObject_AsVoidPtr(dest_obj); - src = (LLVMModuleRef) PyCObject_AsVoidPtr(src_obj); -#endif if (!LLVMLinkModules(dest, src, mode, &errmsg)) { if (errmsg) { - ret = PyBytes_FromString(errmsg); + ret = PyUnicode_FromString(errmsg); LLVMDisposeMessage(errmsg); } else { - ret = PyBytes_FromString("Link error"); + ret = PyUnicode_FromString("Link error"); } return ret; } @@ -408,11 +403,7 @@ _wLLVMConstInt(PyObject *self, PyObject *args) if (!PyArg_ParseTuple(args, "OKi", &obj, &n, &sign_extend)) return NULL; -#ifdef LLVM_PY_USE_PYCAPSULE ty = (LLVMTypeRef) PyCapsule_GetPointer(obj, NULL); -#else - ty = (LLVMTypeRef)(PyCObject_AsVoidPtr(obj)); -#endif val = LLVMConstInt(ty, n, sign_extend); return ctor_LLVMValueRef(val); @@ -429,11 +420,7 @@ _wLLVMConstReal(PyObject *self, PyObject *args) if (!PyArg_ParseTuple(args, "Od", &obj, &d)) return NULL; -#ifdef LLVM_PY_USE_PYCAPSULE ty = (LLVMTypeRef) PyCapsule_GetPointer(obj, NULL); -#else - ty = (LLVMTypeRef)(PyCObject_AsVoidPtr(obj)); -#endif val = LLVMConstReal(ty, d); return ctor_LLVMValueRef(val); @@ -450,18 +437,10 @@ _wLLVMConstString(PyObject *self, PyObject *args) int dont_null_terminate; LLVMValueRef val; -#ifdef LLVM_PY_USE_PYCAPSULE - PyObject *s_; - if (!PyArg_ParseTuple(args, "Ui:LLVMConstString", &s_, &dont_null_terminate)) { + if (!PyArg_ParseTuple(args, "si:LLVMConstString", &s, &dont_null_terminate)) { return NULL; } - s = PyUnicode_AS_DATA(s_); -#else - if (!PyArg_ParseTuple(args, "si", &s, &dont_null_terminate)) - return NULL; -#endif - val = LLVMConstString(s, strlen(s), dont_null_terminate); return ctor_LLVMValueRef(val); } @@ -676,38 +655,22 @@ _wLLVMBuildInvoke(PyObject *self, PyObject *args) LLVMBasicBlockRef then_blk, catch_blk; LLVMValueRef inst; -#ifdef LLVM_PY_USE_PYCAPSULE - PyObject *name_; - if (!PyArg_ParseTuple(args, "OOOOOU:LLVMBuildInvoke", &obj1, &obj2, &obj3, &obj4, &obj5, &name_)) { + if (!PyArg_ParseTuple(args, "OOOOOs:LLVMBuildInvoke", &obj1, &obj2, &obj3, &obj4, &obj5, &name)) { return NULL; } - name = PyUnicode_AS_DATA(name_); -#else - if (!PyArg_ParseTuple(args, "OOOOOs", &obj1, &obj2, &obj3, &obj4, &obj5, &name)) - return NULL; -#endif - -#ifdef LLVM_PY_USE_PYCAPSULE builder = (LLVMBuilderRef) PyCapsule_GetPointer(obj1, NULL); func = (LLVMValueRef) PyCapsule_GetPointer(obj2, NULL); -#else - builder = (LLVMBuilderRef)(PyCObject_AsVoidPtr(obj1)); - func = (LLVMValueRef)(PyCObject_AsVoidPtr(obj2)); -#endif + fnarg_count = (unsigned) PyList_Size(obj3); fnargs = (LLVMValueRef *)make_array_from_list(obj3, fnarg_count); if (!fnargs) return PyErr_NoMemory(); -#ifdef LLVM_PY_USE_PYCAPSULE then_blk = (LLVMBasicBlockRef) PyCapsule_GetPointer(obj4, NULL); catch_blk = (LLVMBasicBlockRef) PyCapsule_GetPointer(obj5, NULL); -#else - then_blk = (LLVMBasicBlockRef)(PyCObject_AsVoidPtr(obj4)); - catch_blk = (LLVMBasicBlockRef)(PyCObject_AsVoidPtr(obj5)); -#endif + inst = LLVMBuildInvoke(builder, func, fnargs, fnarg_count, then_blk, catch_blk, name); @@ -800,22 +763,14 @@ _wLLVMCreateMemoryBufferWithContentsOfFile(PyObject *self, PyObject *args) char *outmsg; PyObject *ret; -#ifdef LLVM_PY_USE_PYCAPSULE - PyObject *path_; - if (!PyArg_ParseTuple(args, "U:LLVMCreateMemoryBufferWithContentsOfFile", &path_)) { + if (!PyArg_ParseTuple(args, "s:LLVMCreateMemoryBufferWithContentsOfFile", &path)) { return NULL; } - path = PyUnicode_AS_DATA(path_); -#else - if (!PyArg_ParseTuple(args, "s", &path)) - return NULL; -#endif - if (!LLVMCreateMemoryBufferWithContentsOfFile(path, &ref, &outmsg)) { ret = ctor_LLVMMemoryBufferRef(ref); } else { - ret = PyBytes_FromString(outmsg); + ret = PyUnicode_FromString(outmsg); LLVMDisposeMessage(outmsg); } @@ -832,7 +787,7 @@ _wLLVMCreateMemoryBufferWithSTDIN(PyObject *self, PyObject *args) if (!LLVMCreateMemoryBufferWithSTDIN(&ref, &outmsg)) { ret = ctor_LLVMMemoryBufferRef(ref); } else { - ret = PyBytes_FromString(outmsg); + ret = PyUnicode_FromString(outmsg); LLVMDisposeMessage(outmsg); } @@ -1021,7 +976,7 @@ _wLLVMTargetDataAsString(PyObject *self, PyObject *args) return NULL; tdrep = LLVMCopyStringRepOfTargetData(td); - ret = PyBytes_FromString(tdrep); + ret = PyUnicode_FromString(tdrep); LLVMDisposeMessage(tdrep); return ret; } @@ -1066,15 +1021,13 @@ _wLLVMEngineBuilderCreate(PyObject *self, PyObject *args) if (!(obj = (LLVMEngineBuilderRef)get_object_arg(args))) return NULL; - char * outmsg = 0; - - LLVMExecutionEngineRef ee = LLVMEngineBuilderCreate(obj, &outmsg); + std::string outmsg; + LLVMExecutionEngineRef ee = LLVMEngineBuilderCreate(obj, outmsg); PyObject * ret; - if( outmsg ){ // check if error message is set. - ret = PyBytes_FromString(outmsg); - free(outmsg); + if( !ee ){ // check if error message is set. + ret = PyUnicode_FromString(outmsg.c_str()); }else{ ret = ctor_LLVMExecutionEngineRef(ee); } @@ -1100,11 +1053,7 @@ _wLLVMCreateExecutionEngine(PyObject *self, PyObject *args) if (!PyArg_ParseTuple(args, "Oi", &obj, &force_interpreter)) return NULL; -#ifdef LLVM_PY_USE_PYCAPSULE mod = (LLVMModuleRef) PyCapsule_GetPointer(obj, NULL); -#else - mod = (LLVMModuleRef) PyCObject_AsVoidPtr(obj); -#endif if (force_interpreter) error = LLVMCreateInterpreterForModule(&ee, mod, &outmsg); @@ -1112,7 +1061,7 @@ _wLLVMCreateExecutionEngine(PyObject *self, PyObject *args) error = LLVMCreateJITCompilerForModule(&ee, mod, 1 /*fast*/, &outmsg); if (error) { - ret = PyBytes_FromString(outmsg); + ret = PyUnicode_FromString(outmsg); LLVMDisposeMessage(outmsg); } else { ret = ctor_LLVMExecutionEngineRef(ee); @@ -1132,13 +1081,8 @@ _wLLVMGetPointerToFunction(PyObject *self, PyObject *args) if (!PyArg_ParseTuple(args, "OO", &obj_ee, &obj_fn)) return NULL; -#ifdef LLVM_PY_USE_PYCAPSULE ee = (LLVMExecutionEngineRef) PyCapsule_GetPointer(obj_ee, NULL); fn = (LLVMValueRef) PyCapsule_GetPointer(obj_fn, NULL); -#else - ee = (LLVMExecutionEngineRef) PyCObject_AsVoidPtr(obj_ee); - fn = (LLVMValueRef) PyCObject_AsVoidPtr(obj_fn); -#endif return PyLong_FromVoidPtr(LLVMGetPointerToFunction(ee,fn)); } @@ -1163,23 +1107,18 @@ _wLLVMRemoveModule2(PyObject *self, PyObject *args) if (!PyArg_ParseTuple(args, "OO", &obj_ee, &obj_mod)) return NULL; -#ifdef LLVM_PY_USE_PYCAPSULE ee = (LLVMExecutionEngineRef) PyCapsule_GetPointer(obj_ee, NULL); mod = (LLVMModuleRef) PyCapsule_GetPointer(obj_mod, NULL); -#else - ee = (LLVMExecutionEngineRef) PyCObject_AsVoidPtr(obj_ee); - mod = (LLVMModuleRef) PyCObject_AsVoidPtr(obj_mod); -#endif LLVMRemoveModule(ee, mod, &mod_new, &outmsg); if (mod_new) { ret = ctor_LLVMModuleRef(mod_new); } else { if (outmsg) { - ret = PyBytes_FromString(outmsg); + ret = PyUnicode_FromString(outmsg); LLVMDisposeMessage(outmsg); } else { - ret = PyBytes_FromString("error"); + ret = PyUnicode_FromString("error"); } } @@ -1215,11 +1154,7 @@ _wLLVMCreateGenericValueOfInt(PyObject *self, PyObject *args) if (!PyArg_ParseTuple(args, "OLi", &obj1, &n, &is_signed)) return NULL; -#ifdef LLVM_PY_USE_PYCAPSULE ty = (LLVMTypeRef) PyCapsule_GetPointer(obj1, NULL); -#else - ty = (LLVMTypeRef) PyCObject_AsVoidPtr(obj1); -#endif gv = LLVMCreateGenericValueOfInt(ty, n, is_signed); return ctor_LLVMGenericValueRef(gv); @@ -1236,11 +1171,7 @@ _wLLVMCreateGenericValueOfFloat(PyObject *self, PyObject *args) if (!PyArg_ParseTuple(args, "Od", &obj1, &d)) return NULL; -#ifdef LLVM_PY_USE_PYCAPSULE ty = (LLVMTypeRef) PyCapsule_GetPointer(obj1, NULL); -#else - ty = (LLVMTypeRef) PyCObject_AsVoidPtr(obj1); -#endif gv = LLVMCreateGenericValueOfFloat(ty, d); return ctor_LLVMGenericValueRef(gv); @@ -1260,11 +1191,7 @@ _wLLVMCreateGenericValueOfPointer(PyObject *self, PyObject *args) n=n_; -#ifdef LLVM_PY_USE_PYCAPSULE ty = (LLVMTypeRef) PyCapsule_GetPointer(obj1, NULL); -#else - ty = (LLVMTypeRef) PyCObject_AsVoidPtr(obj1); -#endif gv = LLVMCreateGenericValueOfPointer((void*)n); return ctor_LLVMGenericValueRef(gv); @@ -1281,11 +1208,7 @@ _wLLVMGenericValueToInt(PyObject *self, PyObject *args) if (!PyArg_ParseTuple(args, "Oi", &obj1, &is_signed)) return NULL; -#ifdef LLVM_PY_USE_PYCAPSULE gv = (LLVMGenericValueRef) PyCapsule_GetPointer(obj1, NULL); -#else - gv = (LLVMGenericValueRef) PyCObject_AsVoidPtr(obj1); -#endif val = LLVMGenericValueToInt(gv, is_signed); return is_signed ? @@ -1304,13 +1227,8 @@ _wLLVMGenericValueToFloat(PyObject *self, PyObject *args) if (!PyArg_ParseTuple(args, "OO", &obj1, &obj2)) return NULL; -#ifdef LLVM_PY_USE_PYCAPSULE ty = (LLVMTypeRef) PyCapsule_GetPointer(obj1, NULL); gv = (LLVMGenericValueRef) PyCapsule_GetPointer(obj2, NULL); -#else - ty = (LLVMTypeRef) PyCObject_AsVoidPtr(obj1); - gv = (LLVMGenericValueRef) PyCObject_AsVoidPtr(obj2); -#endif val = LLVMGenericValueToFloat(ty, gv); return PyFloat_FromDouble(val); @@ -1326,11 +1244,7 @@ _wLLVMGenericValueToPointer(PyObject *self, PyObject *args) if (!PyArg_ParseTuple(args, "O", &obj1)) return NULL; -#ifdef LLVM_PY_USE_PYCAPSULE gv = (LLVMGenericValueRef) PyCapsule_GetPointer(obj1, NULL); -#else - gv = (LLVMGenericValueRef) PyCObject_AsVoidPtr(obj1); -#endif val = LLVMGenericValueToPointer(gv); return PyLong_FromVoidPtr(val); @@ -1353,23 +1267,14 @@ _wLLVMLoadLibraryPermanently(PyObject *self, PyObject *args) char *outmsg; PyObject *ret; -#ifdef LLVM_PY_USE_PYCAPSULE - PyObject *filename_; - if (!PyArg_ParseTuple(args, "U:LLVMLoadLibraryPermanently", &filename_)) { + if (!PyArg_ParseTuple(args, "s:LLVMLoadLibraryPermanently", &filename)) { return NULL; } - filename = PyUnicode_AS_DATA(filename_); -#else - if (!PyArg_ParseTuple(args, "s", &filename)) { - return NULL; - } -#endif - outmsg = 0; if (!LLVMLoadLibraryPermanently(filename, &outmsg)) { if (outmsg) { - ret = PyBytes_FromString(outmsg); + ret = PyUnicode_FromString(outmsg); LLVMDisposeMessage(outmsg); return ret; } @@ -1399,18 +1304,9 @@ _wPyCObjectVoidPtrToPyLong(PyObject *self, PyObject *args) /* Python member method table */ /*===----------------------------------------------------------------------===*/ -#ifdef LLVM_PY_USE_PYCAPSULE - #define _method( func ) { # func , ( PyCFunction )_w ## func , METH_VARARGS , NULL }, #define _pass( P ) _method( LLVMAdd ## P ## Pass ) -#else - -#define _method( func ) { # func , _w ## func , METH_VARARGS }, -#define _pass( P ) _method( LLVMAdd ## P ## Pass ) - -#endif - static PyMethodDef core_methods[] = { /* Modules */ @@ -1954,7 +1850,7 @@ static PyMethodDef core_methods[] = { // Module main function, hairy because of py3k port extern "C" { - + #if (PY_MAJOR_VERSION >= 3) struct PyModuleDef module_def = { PyModuleDef_HEAD_INIT, diff --git a/llvm/_util.py b/llvm/_util.py index 1ff4cc9..1766d6f 100644 --- a/llvm/_util.py +++ b/llvm/_util.py @@ -77,3 +77,22 @@ def wrapiter(first, next, container, wrapper): ptr = next(ptr) return ret + +#===----------------------------------------------------------------------=== +# Py2/3 compatibility string check +#===----------------------------------------------------------------------=== +def _isstring_py2(x): + return isinstance(x, basestring) + +def _isstring_py3(x): + return isinstance(x, str) + +def _isstring_choose(): + try: + basestring + return _isstring_py2 + except: + return _isstring_py3 + +isstring = _isstring_choose() + diff --git a/llvm/core.py b/llvm/core.py index 1658846..f4c75bf 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -348,7 +348,7 @@ class Module(llvm.Ownable, llvm.Cacheable): ret = _core.LLVMGetModuleFromBitcode(data) if not ret: raise llvm.LLVMException("Unable to create module from bitcode") - elif isinstance(ret, str): + elif _util.isstring(ret): raise llvm.LLVMException(ret) else: return Module(ret) diff --git a/llvm/ee.py b/llvm/ee.py index 24b9325..62795a0 100644 --- a/llvm/ee.py +++ b/llvm/ee.py @@ -209,7 +209,7 @@ class EngineBuilder(object): def create(self): ret = _core.LLVMEngineBuilderCreate(self.ptr) - if isinstance(ret, basestring): + if isinstance(ret, str): raise llvm.LLVMException(ret) return ExecutionEngine(ret, self._module) diff --git a/llvm/extra.cpp b/llvm/extra.cpp index 0b5a874..858fbcf 100644 --- a/llvm/extra.cpp +++ b/llvm/extra.cpp @@ -148,17 +148,15 @@ void LLVMEngineBuilderSetOptLevel(LLVMEngineBuilderRef eb, int level) } -LLVMExecutionEngineRef LLVMEngineBuilderCreate(LLVMEngineBuilderRef eb, char **err) +LLVMExecutionEngineRef LLVMEngineBuilderCreate(LLVMEngineBuilderRef eb, std::string & error) { using namespace llvm; - std::string errstring; LLVMExecutionEngineRef ret; - ret = wrap(unwrap(eb)->setErrorStr(&errstring).create()); + ret = wrap(unwrap(eb)->setErrorStr(&error).create()); - if ( !errstring.empty() ) { - *err = strdup(errstring.c_str()); - return 0; + if ( !error.empty() ) { // error string is set + return NULL; } else { return ret; } @@ -534,8 +532,7 @@ LLVMValueRef LLVMGetIntrinsic(LLVMModuleRef module, int id, return wrap(intfunc); } -LLVMModuleRef LLVMGetModuleFromAssembly(const char *asmtext, unsigned txtlen, - char **out) +LLVMModuleRef LLVMGetModuleFromAssembly(const char *asmtext, char **out) { assert(asmtext); assert(out); diff --git a/llvm/extra.h b/llvm/extra.h index 9c73098..b0bacc8 100644 --- a/llvm/extra.h +++ b/llvm/extra.h @@ -75,7 +75,8 @@ void LLVMEngineBuilderSetOptLevel(LLVMEngineBuilderRef eb, int level); /* * Wraps EngineBuilder::setErrorStr and EngineBuilder::create */ -LLVMExecutionEngineRef LLVMEngineBuilderCreate(LLVMEngineBuilderRef eb, char **err); +LLVMExecutionEngineRef LLVMEngineBuilderCreate(LLVMEngineBuilderRef eb, + std::string &error); /* * Wraps PassManagerBuilder::OptLevel @@ -272,8 +273,7 @@ unsigned LLVMCmpInstGetPredicate(LLVMValueRef cmpinst); /* Wraps llvm::ParseAssemblyString(). Returns a module reference or NULL (with * `out' pointing to an error message). Dispose error message after use, via * LLVMDisposeMessage(). */ -LLVMModuleRef LLVMGetModuleFromAssembly(const char *asmtxt, unsigned txten, - char **out); +LLVMModuleRef LLVMGetModuleFromAssembly(const char *asmtxt, char **out); /* Wraps llvm::ParseBitcodeFile(). Returns a module reference or NULL (with * `out' pointing to an error message). Dispose error message after use, via diff --git a/llvm/passes.py b/llvm/passes.py index 0b64c11..fb5dc7c 100644 --- a/llvm/passes.py +++ b/llvm/passes.py @@ -39,7 +39,7 @@ import llvm # top-level, for common stuff import llvm.ee as ee # target data import llvm.core as core # module, function etc. import llvm._core as _core # C wrappers - +import llvm._util as _util # Utility functions #===----------------------------------------------------------------------=== # Pass manager builder @@ -142,10 +142,10 @@ class PassManager(object): def add(self, tgt_data_or_pass_name): if isinstance(tgt_data_or_pass_name, ee.TargetData): self._add_target_data(tgt_data_or_pass_name) - elif isinstance(tgt_data_or_pass_name, basestring): + elif _util.isstring(tgt_data_or_pass_name): self._add_pass(tgt_data_or_pass_name) else: - raise llvm.LLVMException("invalid pass_id (%s)" % str(tgt_data_or_pass_name)) + raise llvm.LLVMException("invalid pass_id (%s)" % tgt_data_or_pass_name) def _add_target_data(self, tgt): _core.LLVMAddTargetData(tgt.ptr, self.ptr) diff --git a/llvm/wrap.cpp b/llvm/wrap.cpp index 25ea30c..4527912 100644 --- a/llvm/wrap.cpp +++ b/llvm/wrap.cpp @@ -30,37 +30,19 @@ #include "wrap.h" -/* Project-wide setting */ -#if (PY_MAJOR_VERSION >= 3) -#define LLVM_PY_USE_PYCAPSULE -#endif - /*===----------------------------------------------------------------------===*/ /* Helper functions/macros */ /*===----------------------------------------------------------------------===*/ -#ifdef LLVM_PY_USE_PYCAPSULE - #define _define_std_ctor(typ) \ PyObject * ctor_ ## typ ( typ p) \ { \ - if (p) \ + if (p){ \ return PyCapsule_New(p, NULL, NULL); \ + } \ Py_RETURN_NONE; \ } -#else - -#define _define_std_ctor(typ) \ -PyObject * ctor_ ## typ ( typ p) \ -{ \ - if (p) \ - return PyCObject_FromVoidPtr(p, NULL); \ - Py_RETURN_NONE; \ -} - -#endif - /*===----------------------------------------------------------------------===*/ /* Type ctor/dtor */ /*===----------------------------------------------------------------------===*/ @@ -100,11 +82,8 @@ void *get_object_arg(PyObject *args) if (!PyArg_ParseTuple(args, "O", &o)) return NULL; -#ifdef LLVM_PY_USE_PYCAPSULE + return PyCapsule_GetPointer(o, NULL); -#else - return PyCObject_AsVoidPtr(o); -#endif } void **make_array_from_list(PyObject *list, int n) @@ -118,11 +97,7 @@ void **make_array_from_list(PyObject *list, int n) for (i=0; i -#include +// #include //unused? + +//// For pre-2.7 compatbility, use the following include, which provides +//// alias for PyCapsule. +//// See http://docs.python.org/py3k/howto/cporting.html +// #include // pre-2.7 compatibility for PyCapsule + /* llvm includes */ #include "llvm-c/Core.h" @@ -53,19 +59,12 @@ #include "llvm_c_extra.h" -/* Project-wide setting */ -#if PY_MAJOR_VERSION >= 3 -#define LLVM_PY_USE_PYCAPSULE -#endif - /*===----------------------------------------------------------------------===*/ /* Typedefs */ /*===----------------------------------------------------------------------===*/ typedef unsigned long long llvmwrap_ull; - - /*===----------------------------------------------------------------------===*/ /* Type ctor/dtor */ /*===----------------------------------------------------------------------===*/ @@ -140,8 +139,6 @@ PyObject *make_list_from_LLVMValueRef_array(LLVMValueRef *p, unsigned n); */ - -#ifdef LLVM_PY_USE_PYCAPSULE /****************************************************************************** ****************************************************************************** *** PyCapsule Calls @@ -342,14 +339,11 @@ _w ## func (PyObject *self, PyObject *args) \ static PyObject * \ _w ## func (PyObject *self, PyObject *args) \ { \ - PyObject *arg1_; \ const char *arg1; \ \ - if (!PyArg_ParseTuple(args, "U", &arg1_)) \ + if (!PyArg_ParseTuple(args, "s", &arg1)) \ return NULL; \ \ - arg1 = PyUnicode_AS_DATA(arg1_); \ - \ return ctor_ ## outtype ( func (arg1)); \ } @@ -378,7 +372,7 @@ _w ## func (PyObject *self, PyObject *args) \ { \ if (!PyArg_ParseTuple(args, "")) \ return NULL; \ - return PyBytes_FromString(func()); \ + return PyUnicode_FromString(func()); \ } @@ -395,7 +389,7 @@ _w ## func (PyObject *self, PyObject *args) \ if (!(arg1 = ( intype1 )get_object_arg(args))) \ return NULL; \ \ - return PyBytes_FromString( func (arg1)); \ + return PyUnicode_FromString( func (arg1)); \ } /** @@ -423,15 +417,14 @@ _w ## func (PyObject *self, PyObject *args) \ static PyObject * \ _w ## func (PyObject *self, PyObject *args) \ { \ - PyObject *obj1, *arg2_; \ + PyObject *obj1; \ const char *arg2; \ intype1 arg1; \ \ - if (!PyArg_ParseTuple(args, "OU", &obj1, &arg2_)) \ + if (!PyArg_ParseTuple(args, "Os", &obj1, &arg2)) \ return NULL; \ \ arg1 = ( intype1 ) PyCapsule_GetPointer(obj1, NULL);\ - arg2 = PyUnicode_AS_DATA(arg2_); \ \ func (arg1, arg2); \ Py_RETURN_NONE; \ @@ -445,15 +438,14 @@ _w ## func (PyObject *self, PyObject *args) \ static PyObject * \ _w ## func (PyObject *self, PyObject *args) \ { \ - PyObject *obj1, *arg2_; \ + PyObject *obj1; \ const char *arg2; \ intype1 arg1; \ \ - if (!PyArg_ParseTuple(args, "OU", &obj1, &arg2_)) \ + if (!PyArg_ParseTuple(args, "Os", &obj1, &arg2)) \ return NULL; \ \ arg1 = ( intype1 ) PyCapsule_GetPointer(obj1, NULL);\ - arg2 = PyUnicode_AS_DATA(arg2_); \ \ return ctor_ ## outtype ( func (arg1, arg2)); \ } @@ -508,17 +500,16 @@ _w ## func (PyObject *self, PyObject *args) \ static PyObject * \ _w ## func (PyObject *self, PyObject *args) \ { \ - PyObject *obj1, *obj2, *arg3_; \ + PyObject *obj1, *obj2; \ intype1 arg1; \ intype2 arg2; \ const char *arg3; \ \ - if (!PyArg_ParseTuple(args, "OOU", &obj1, &obj2, &arg3_)) \ + if (!PyArg_ParseTuple(args, "OOs", &obj1, &obj2, &arg3)) \ return NULL; \ \ arg1 = ( intype1 ) PyCapsule_GetPointer(obj1, NULL); \ arg2 = ( intype2 ) PyCapsule_GetPointer(obj2, NULL); \ - arg3 = PyUnicode_AS_DATA(arg3_); \ \ return ctor_ ## outtype ( func (arg1, arg2, arg3)); \ } @@ -618,16 +609,15 @@ _w ## func (PyObject *self, PyObject *args) \ static PyObject * \ _w ## func (PyObject *self, PyObject *args) \ { \ - PyObject *obj1, *obj3, *arg2_; \ + PyObject *obj1, *obj3; \ intype1 arg1; \ const char *arg2; \ intype3 arg3; \ \ - if (!PyArg_ParseTuple(args, "OUO", &obj1, &arg2_, &obj3)) \ + if (!PyArg_ParseTuple(args, "OsO", &obj1, &arg2, &obj3)) \ return NULL; \ \ arg1 = ( intype1 ) PyCapsule_GetPointer(obj1, NULL); \ - arg2 = PyUnicode_AS_DATA(arg2_); \ arg3 = ( intype3 ) PyCapsule_GetPointer(obj3, NULL); \ \ return ctor_ ## outtype ( func (arg1, arg2, arg3)); \ @@ -642,18 +632,17 @@ _w ## func (PyObject *self, PyObject *args) \ static PyObject * \ _w ## func (PyObject *self, PyObject *args) \ { \ - PyObject *obj1, *obj2, *arg4_; \ + PyObject *obj1, *obj2; \ intype1 arg1; \ intype2 arg2; \ int arg3; \ const char *arg4; \ \ - if (!PyArg_ParseTuple(args, "OOiU", &obj1, &obj2, &arg3, &arg4_)) \ + if (!PyArg_ParseTuple(args, "OOis", &obj1, &obj2, &arg3, &arg4)) \ return NULL; \ \ arg1 = ( intype1 ) PyCapsule_GetPointer(obj1, NULL); \ arg2 = ( intype2 ) PyCapsule_GetPointer(obj2, NULL); \ - arg4 = PyUnicode_AS_DATA(arg4_); \ \ return ctor_ ## outtype ( func (arg1, arg2, arg3, arg4)) ; \ } @@ -666,19 +655,18 @@ _w ## func (PyObject *self, PyObject *args) \ static PyObject * \ _w ## func (PyObject *self, PyObject *args) \ { \ - PyObject *obj1, *obj2, *obj3, *arg4_; \ + PyObject *obj1, *obj2, *obj3; \ intype1 arg1; \ intype2 arg2; \ intype3 arg3; \ const char *arg4; \ \ - if (!PyArg_ParseTuple(args, "OOOU", &obj1, &obj2, &obj3, &arg4_)) \ + if (!PyArg_ParseTuple(args, "OOOs", &obj1, &obj2, &obj3, &arg4)) \ return NULL; \ \ arg1 = ( intype1 ) PyCapsule_GetPointer(obj1, NULL); \ arg2 = ( intype2 ) PyCapsule_GetPointer(obj2, NULL); \ arg3 = ( intype3 ) PyCapsule_GetPointer(obj3, NULL); \ - arg4 = PyUnicode_AS_DATA(arg4_); \ \ return ctor_ ## outtype ( func (arg1, arg2, arg3, arg4)); \ } @@ -740,21 +728,20 @@ _w ## func (PyObject *self, PyObject *args) static PyObject * \ _w ## func (PyObject *self, PyObject *args) \ { \ - PyObject *obj1, *obj2, *obj3, *obj4, *arg5_; \ + PyObject *obj1, *obj2, *obj3, *obj4; \ intype1 arg1; \ intype2 arg2; \ intype3 arg3; \ intype4 arg4; \ const char *arg5; \ \ - if (!PyArg_ParseTuple(args, "OOOOU", &obj1, &obj2, &obj3, &obj4, &arg5_)) \ + if (!PyArg_ParseTuple(args, "OOOOs", &obj1, &obj2, &obj3, &obj4, &arg5)) \ return NULL; \ \ arg1 = ( intype1 ) PyCapsule_GetPointer(obj1, NULL); \ arg2 = ( intype2 ) PyCapsule_GetPointer(obj2, NULL); \ arg3 = ( intype3 ) PyCapsule_GetPointer(obj3, NULL); \ arg4 = ( intype4 ) PyCapsule_GetPointer(obj4, NULL); \ - arg5 = PyUnicode_AS_DATA(arg5_); \ \ return ctor_ ## outtype ( func (arg1, arg2, arg3, arg4, arg5)); \ } @@ -767,20 +754,19 @@ _w ## func (PyObject *self, PyObject *args) static PyObject * \ _w ## func (PyObject *self, PyObject *args) \ { \ - PyObject *obj1, *obj3, *obj4, *arg5_; \ + PyObject *obj1, *obj3, *obj4; \ intype1 arg1; \ intype2 arg2; \ intype3 arg3; \ intype4 arg4; \ const char *arg5; \ \ - if (!PyArg_ParseTuple(args, "OiOOU", &obj1, &arg2, &obj3, &obj4, &arg5_)) \ + if (!PyArg_ParseTuple(args, "OiOOs", &obj1, &arg2, &obj3, &obj4, &arg5)) \ return NULL; \ \ arg1 = ( intype1 ) PyCapsule_GetPointer(obj1, NULL); \ arg3 = ( intype3 ) PyCapsule_GetPointer(obj3, NULL); \ arg4 = ( intype4 ) PyCapsule_GetPointer(obj4, NULL); \ - arg5 = PyUnicode_AS_DATA(arg5_); \ \ return ctor_ ## outtype ( func (arg1, arg2, arg3, arg4, arg5)); \ } @@ -992,7 +978,7 @@ _w ## func (PyObject *self, PyObject *args) \ static PyObject * \ _w ## func (PyObject *self, PyObject *args) \ { \ - PyObject *obj1, *obj2, *obj3, *arg4_; \ + PyObject *obj1, *obj2, *obj3; \ const char *arg4; \ intype1 arg1; \ intype2 arg2; \ @@ -1000,13 +986,12 @@ _w ## func (PyObject *self, PyObject *args) \ unsigned arg3n; \ outtype ret; \ \ - if (!PyArg_ParseTuple(args, "OOOU", &obj1, &obj2, &obj3, &arg4_)) \ + if (!PyArg_ParseTuple(args, "OOOs", &obj1, &obj2, &obj3, &arg4)) \ return NULL; \ \ arg1 = ( intype1 ) PyCapsule_GetPointer(obj1, NULL); \ arg2 = ( intype2 ) PyCapsule_GetPointer(obj2, NULL); \ arg3n = ( unsigned ) PyList_Size(obj3); \ - arg4 = PyUnicode_AS_DATA(arg4_); \ if (!(arg3v = ( intype3 *)make_array_from_list(obj3, arg3n))) \ return PyErr_NoMemory(); \ \ @@ -1033,892 +1018,11 @@ _w ## func (PyObject *self, PyObject *args) \ return NULL; \ \ val = func (arg1); \ - ret = PyBytes_FromString(val); \ + ret = PyUnicode_FromString(val); \ LLVMDisposeMessage(val); \ return ret; \ } -#else -/****************************************************************************** - ****************************************************************************** - *** PyCObject calls - ****************************************************************************** - *****************************************************************************/ -/** - * Wrap LLVM functions of the type - * outtype func(intype1 arg1) - */ -#define _wrap_obj2obj(func, intype1, outtype) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - intype1 arg1; \ - \ - if (!(arg1 = ( intype1 )get_object_arg(args))) \ - return NULL; \ - \ - return ctor_ ## outtype ( func (arg1)); \ -} - -/** - * Wrap LLVM functions of the type - * outtype func(int arg1) - */ -#define _wrap_int2obj(func, outtype) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - int arg1; \ - \ - if (!PyArg_ParseTuple(args, "i", &arg1)) \ - return NULL; \ - \ - return ctor_ ## outtype ( func (arg1)); \ -} - -/** - * Wrap LLVM functions of the type - * outtype func(intype1 arg1, intype2 arg2) - */ -#define _wrap_objobj2obj(func, intype1, intype2, outtype) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - PyObject *obj1, *obj2; \ - intype1 arg1; \ - intype2 arg2; \ - \ - if (!PyArg_ParseTuple(args, "OO", &obj1, &obj2)) \ - return NULL; \ - arg1 = ( intype1 ) PyCObject_AsVoidPtr(obj1); \ - arg2 = ( intype2 ) PyCObject_AsVoidPtr(obj2); \ - \ - return ctor_ ## outtype ( func (arg1, arg2)); \ -} - -/** - * Wrap LLVM functions of the type - * void func(intype1 arg1, intype2 arg2) - */ -#define _wrap_objobj2none(func, intype1, intype2) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - PyObject *obj1, *obj2; \ - intype1 arg1; \ - intype2 arg2; \ - \ - if (!PyArg_ParseTuple(args, "OO", &obj1, &obj2)) \ - return NULL; \ - arg1 = ( intype1 ) PyCObject_AsVoidPtr(obj1); \ - arg2 = ( intype2 ) PyCObject_AsVoidPtr(obj2); \ - \ - func (arg1, arg2); \ - Py_RETURN_NONE; \ -} - -/** - * Wrap LLVM functions of the type - * outtype func(intype1 arg1, arg2) - */ -#define _wrap_objint2obj(func, intype1, outtype) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - PyObject *obj1; \ - intype1 arg1; \ - unsigned int arg2; \ - \ - if (!PyArg_ParseTuple(args, "OI", &obj1, &arg2)) \ - return NULL; \ - arg1 = ( intype1 ) PyCObject_AsVoidPtr(obj1); \ - \ - return ctor_ ## outtype ( func (arg1, arg2)); \ -} - -/** - * Wrap LLVM functions of the type - * outtype func(intype1 arg1, intype2 arg2, intype3 arg3) - */ -#define _wrap_objobjobj2obj(func, intype1, intype2, intype3, outtype) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - PyObject *obj1, *obj2, *obj3; \ - intype1 arg1; \ - intype2 arg2; \ - intype3 arg3; \ - \ - if (!PyArg_ParseTuple(args, "OOO", &obj1, &obj2, &obj3)) \ - return NULL; \ - \ - arg1 = ( intype1 ) PyCObject_AsVoidPtr(obj1); \ - arg2 = ( intype2 ) PyCObject_AsVoidPtr(obj2); \ - arg3 = ( intype3 ) PyCObject_AsVoidPtr(obj3); \ - \ - return ctor_ ## outtype ( func (arg1, arg2, arg3)); \ -} - -/** - * Wrap LLVM functions of the type - * void func(intype1 arg1, intype2 arg2, intype3 arg3) - */ -#define _wrap_objobjobj2none(func, intype1, intype2, intype3) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - PyObject *obj1, *obj2, *obj3; \ - intype1 arg1; \ - intype2 arg2; \ - intype3 arg3; \ - \ - if (!PyArg_ParseTuple(args, "OOO", &obj1, &obj2, &obj3)) \ - return NULL; \ - \ - arg1 = ( intype1 ) PyCObject_AsVoidPtr(obj1); \ - arg2 = ( intype2 ) PyCObject_AsVoidPtr(obj2); \ - arg3 = ( intype3 ) PyCObject_AsVoidPtr(obj3); \ - \ - func (arg1, arg2, arg3); \ - Py_RETURN_NONE; \ -} - -/** - * Wrap LLVM functions of the type - * outtype func( arg1, intype2 arg2, intype3 arg3) - */ -#define _wrap_intobjobj2obj(func, intype2, intype3, outtype) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - unsigned int arg1; \ - PyObject *obj2, *obj3; \ - intype2 arg2; \ - intype3 arg3; \ - \ - if (!PyArg_ParseTuple(args, "IOO", &arg1, &obj2, &obj3)) \ - return NULL; \ - \ - arg2 = ( intype2 ) PyCObject_AsVoidPtr(obj2); \ - arg3 = ( intype3 ) PyCObject_AsVoidPtr(obj3); \ - \ - return ctor_ ## outtype ( func (arg1, arg2, arg3)); \ -} - -/** - * Wrap LLVM functions of the type - * outtype func(enum_intype1 arg1, intype2 arg2, intype3 arg3) - */ -#define _wrap_enumobjobj2obj(func, intype1, intype2, intype3, outtype) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - intype1 arg1; \ - PyObject *obj2, *obj3; \ - intype2 arg2; \ - intype3 arg3; \ - \ - if (!PyArg_ParseTuple(args, "IOO", &arg1, &obj2, &obj3)) \ - return NULL; \ - \ - arg2 = ( intype2 ) PyCObject_AsVoidPtr(obj2); \ - arg3 = ( intype3 ) PyCObject_AsVoidPtr(obj3); \ - \ - return ctor_ ## outtype ( func (arg1, arg2, arg3)); \ -} - -/** - * Wrap LLVM functions of the type - * outtype func(const char *s) - */ -#define _wrap_str2obj(func, outtype) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - const char *arg1; \ - \ - if (!PyArg_ParseTuple(args, "s", &arg1)) \ - return NULL; \ - \ - return ctor_ ## outtype ( func (arg1)); \ -} - -/** - * Wrap LLVM functions of the type - * outtype func() - */ -#define _wrap_none2obj(func, outtype) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - if (!PyArg_ParseTuple(args, "")) \ - return NULL; \ - \ - return ctor_ ## outtype ( func ()); \ -} - - -/** - * Wrap LLVM functions of the type - * const char * func() - */ - #define _wrap_none2str(func) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - if (!PyArg_ParseTuple(args, "")) \ - return NULL; \ - return PyBytes_FromString(func()); \ -} - - -/** - * Wrap LLVM functions of the type - * const char *func(intype1 arg1) - */ -#define _wrap_obj2str(func, intype1) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - intype1 arg1; \ - \ - if (!(arg1 = ( intype1 )get_object_arg(args))) \ - return NULL; \ - \ - return PyBytes_FromString( func (arg1)); \ -} - -/** - * Wrap LLVM functions of the type - * void func(intype1 arg1) - */ -#define _wrap_obj2none(func, intype1) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - intype1 arg1; \ - \ - if (!(arg1 = ( intype1 )get_object_arg(args))) \ - return NULL; \ - \ - func (arg1); \ - Py_RETURN_NONE; \ -} - -/** - * Wrap LLVM functions of the type - * void func(intype1 arg1, const char *arg2) - */ -#define _wrap_objstr2none(func, intype1) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - PyObject *obj1; \ - const char *arg2; \ - intype1 arg1; \ - \ - if (!PyArg_ParseTuple(args, "Os", &obj1, &arg2)) \ - return NULL; \ - \ - arg1 = ( intype1 ) PyCObject_AsVoidPtr(obj1); \ - \ - func (arg1, arg2); \ - Py_RETURN_NONE; \ -} - -/** - * Wrap LLVM functions of the type - * outtype func(intype1 arg1, const char *arg2) - */ -#define _wrap_objstr2obj(func, intype1, outtype) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - PyObject *obj1; \ - const char *arg2; \ - intype1 arg1; \ - \ - if (!PyArg_ParseTuple(args, "Os", &obj1, &arg2)) \ - return NULL; \ - \ - arg1 = ( intype1 ) PyCObject_AsVoidPtr(obj1); \ - \ - return ctor_ ## outtype ( func (arg1, arg2)); \ -} - -/** - * Wrap LLVM functions of the type - * void func(intype1 arg1, arg2) - */ -#define _wrap_objint2none(func, intype1) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - PyObject *obj1; \ - int arg2; \ - intype1 arg1; \ - \ - if (!PyArg_ParseTuple(args, "Oi", &obj1, &arg2)) \ - return NULL; \ - \ - arg1 = ( intype1 ) PyCObject_AsVoidPtr(obj1); \ - \ - func (arg1, arg2); \ - Py_RETURN_NONE; \ -} - -/** - * Wrap LLVM functions of the type - * void func(intype1 arg1, enum_intype2 arg2) - */ -#define _wrap_objenum2none(func, intype1, intype2) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - PyObject *obj1; \ - intype1 arg1; \ - intype2 arg2; \ - \ - if (!PyArg_ParseTuple(args, "Oi", &obj1, &arg2)) \ - return NULL; \ - \ - arg1 = ( intype1 ) PyCObject_AsVoidPtr(obj1); \ - \ - func (arg1, arg2); \ - Py_RETURN_NONE; \ -} - -/** - * Wrap LLVM functions of the type - * outtype func(intype1 arg1, intype2 arg2, const char *arg3) - */ -#define _wrap_objobjstr2obj(func, intype1, intype2, outtype) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - PyObject *obj1, *obj2; \ - intype1 arg1; \ - intype2 arg2; \ - const char *arg3; \ - \ - if (!PyArg_ParseTuple(args, "OOs", &obj1, &obj2, &arg3)) \ - return NULL; \ - \ - arg1 = ( intype1 ) PyCObject_AsVoidPtr(obj1); \ - arg2 = ( intype2 ) PyCObject_AsVoidPtr(obj2); \ - \ - return ctor_ ## outtype ( func (arg1, arg2, arg3)) ;\ -} - -/** - * Wrap LLVM functions of the type - * outtype func(intype1 arg1, intype2 arg2, int arg3) - */ -#define _wrap_objobjint2obj(func, intype1, intype2, outtype) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - PyObject *obj1, *obj2; \ - intype1 arg1; \ - intype2 arg2; \ - int arg3; \ - \ - if (!PyArg_ParseTuple(args, "OOi", &obj1, &obj2, &arg3)) \ - return NULL; \ - \ - arg1 = ( intype1 ) PyCObject_AsVoidPtr(obj1); \ - arg2 = ( intype2 ) PyCObject_AsVoidPtr(obj2); \ - \ - return ctor_ ## outtype ( func (arg1, arg2, arg3)) ;\ -} - -/** - * Wrap LLVM functions of the type - * outtype func(intype1 arg1, intype2 arg2, unsigned long long arg3) - */ -#define _wrap_objobjull2obj(func, intype1, intype2, outtype) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - PyObject *obj1, *obj2; \ - intype1 arg1; \ - intype2 arg2; \ - unsigned long long arg3; \ - \ - if (!PyArg_ParseTuple(args, "OOK", &obj1, &obj2, &arg3)) \ - return NULL; \ - \ - arg1 = ( intype1 ) PyCObject_AsVoidPtr(obj1); \ - arg2 = ( intype2 ) PyCObject_AsVoidPtr(obj2); \ - \ - return ctor_ ## outtype ( func (arg1, arg2, arg3)) ;\ -} - -/** - * Wrap LLVM functions of the type - * void func(intype1 arg1, arg2, arg3) - */ -#define _wrap_objintint2none(func, intype1) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - PyObject *obj1; \ - intype1 arg1; \ - int arg2, arg3; \ - \ - if (!PyArg_ParseTuple(args, "Oii", &obj1, &arg2, &arg3)) \ - return NULL; \ - \ - arg1 = ( intype1 ) PyCObject_AsVoidPtr(obj1); \ - \ - func (arg1, arg2, arg3); \ - Py_RETURN_NONE; \ -} - -/** - * Wrap LLVM functions of the type - * void func(intype1 arg1, arg2, enum_intype3 arg3) - */ -#define _wrap_objintenum2none(func, intype1, intype3) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - PyObject *obj1; \ - intype1 arg1; \ - int arg2; \ - intype3 arg3; \ - \ - if (!PyArg_ParseTuple(args, "Oii", &obj1, &arg2, &arg3)) \ - return NULL; \ - \ - arg1 = ( intype1 ) PyCObject_AsVoidPtr(obj1); \ - \ - func (arg1, arg2, arg3); \ - Py_RETURN_NONE; \ -} - -/** - * Wrap LLVM functions of the type - * outtype func(intype1 arg1, const char *arg2, intype3 arg3) - */ -#define _wrap_objstrobj2obj(func, intype1, intype3, outtype) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - PyObject *obj1, *obj3; \ - intype1 arg1; \ - const char *arg2; \ - intype3 arg3; \ - \ - if (!PyArg_ParseTuple(args, "OsO", &obj1, &arg2, &obj3)) \ - return NULL; \ - \ - arg1 = ( intype1 ) PyCObject_AsVoidPtr(obj1); \ - arg3 = ( intype3 ) PyCObject_AsVoidPtr(obj3); \ - \ - return ctor_ ## outtype ( func (arg1, arg2, arg3)); \ -} - - -/** - * Wrap LLVM functions of the type - * outtype func(intype1 arg1, intype2 arg2, int arg3, const char *arg4) - */ -#define _wrap_objobjintstr2obj(func, intype1, intype2, outtype) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - PyObject *obj1, *obj2; \ - intype1 arg1; \ - intype2 arg2; \ - int arg3; \ - const char *arg4; \ - \ - if (!PyArg_ParseTuple(args, "OOis", &obj1, &obj2, &arg3, &arg4)) \ - return NULL; \ - \ - arg1 = ( intype1 ) PyCObject_AsVoidPtr(obj1); \ - arg2 = ( intype2 ) PyCObject_AsVoidPtr(obj2); \ - \ - return ctor_ ## outtype ( func (arg1, arg2, arg3, arg4)) ;\ -} - -/** - * Wrap LLVM functions of the type - * outtype func(intype1 arg1, intype2 arg2, intype3 arg3, const char *arg4) - */ -#define _wrap_objobjobjstr2obj(func, intype1, intype2, intype3, outtype) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - PyObject *obj1, *obj2, *obj3; \ - intype1 arg1; \ - intype2 arg2; \ - intype3 arg3; \ - const char *arg4; \ - \ - if (!PyArg_ParseTuple(args, "OOOs", &obj1, &obj2, &obj3, &arg4)) \ - return NULL; \ - \ - arg1 = ( intype1 ) PyCObject_AsVoidPtr(obj1); \ - arg2 = ( intype2 ) PyCObject_AsVoidPtr(obj2); \ - arg3 = ( intype3 ) PyCObject_AsVoidPtr(obj3); \ - \ - return ctor_ ## outtype ( func (arg1, arg2, arg3, arg4)); \ -} - -/** - * Wrap LLVM functions of the type - * outtype func(intype1 arg1, intype2 arg2, intype3 arg3, arg4) - */ -#define _wrap_objobjobjint2obj(func, intype1, intype2, intype3, outtype) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - PyObject *obj1, *obj2, *obj3; \ - intype1 arg1; \ - intype2 arg2; \ - intype3 arg3; \ - int arg4; \ - \ - if (!PyArg_ParseTuple(args, "OOOi", &obj1, &obj2, &obj3, &arg4)) \ - return NULL; \ - \ - arg1 = ( intype1 ) PyCObject_AsVoidPtr(obj1); \ - arg2 = ( intype2 ) PyCObject_AsVoidPtr(obj2); \ - arg3 = ( intype3 ) PyCObject_AsVoidPtr(obj3); \ - \ - return ctor_ ## outtype ( func (arg1, arg2, arg3, arg4)); \ -} - -/** - * Wrap LLVM functions of the type - * outtype func(intype1 arg1, intype2 arg2, intype3 arg3, intype arg4) - */ -#define _wrap_objobjobjobj2obj(func, intype1, intype2, intype3, intype4, outtype) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - PyObject *obj1, *obj2, *obj3, *obj4; \ - intype1 arg1; \ - intype2 arg2; \ - intype3 arg3; \ - intype4 arg4; \ - \ - if (!PyArg_ParseTuple(args, "OOOO", &obj1, &obj2, &obj3, &obj4)) \ - return NULL; \ - \ - arg1 = ( intype1 ) PyCObject_AsVoidPtr(obj1); \ - arg2 = ( intype2 ) PyCObject_AsVoidPtr(obj2); \ - arg3 = ( intype3 ) PyCObject_AsVoidPtr(obj3); \ - arg4 = ( intype4 ) PyCObject_AsVoidPtr(obj4); \ - \ - return ctor_ ## outtype ( func (arg1, arg2, arg3, arg4)); \ -} - -/** - * Wrap LLVM functions of the type - * outtype func(intype1 arg1, intype2 arg2, intype3 arg3, intype arg4, const char *arg5) - */ -#define _wrap_objobjobjobjstr2obj(func, intype1, intype2, intype3, intype4, outtype) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - PyObject *obj1, *obj2, *obj3, *obj4; \ - intype1 arg1; \ - intype2 arg2; \ - intype3 arg3; \ - intype4 arg4; \ - const char *arg5; \ - \ - if (!PyArg_ParseTuple(args, "OOOOs", &obj1, &obj2, &obj3, &obj4, &arg5)) \ - return NULL; \ - \ - arg1 = ( intype1 ) PyCObject_AsVoidPtr(obj1); \ - arg2 = ( intype2 ) PyCObject_AsVoidPtr(obj2); \ - arg3 = ( intype3 ) PyCObject_AsVoidPtr(obj3); \ - arg4 = ( intype4 ) PyCObject_AsVoidPtr(obj4); \ - \ - return ctor_ ## outtype ( func (arg1, arg2, arg3, arg4, arg5)); \ -} - -/** - * Wrap LLVM functions of the type - * outtype func(intype1 arg1, enum_intype2 arg2, intype3 arg3, intype4 arg4, const char *arg5) - */ -#define _wrap_objenumobjobjstr2obj(func, intype1, intype2, intype3, intype4, outtype) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - PyObject *obj1, *obj3, *obj4; \ - intype1 arg1; \ - intype2 arg2; \ - intype3 arg3; \ - intype4 arg4; \ - const char *arg5; \ - \ - if (!PyArg_ParseTuple(args, "OiOOs", &obj1, &arg2, &obj3, &obj4, &arg5)) \ - return NULL; \ - \ - arg1 = ( intype1 ) PyCObject_AsVoidPtr(obj1); \ - arg3 = ( intype3 ) PyCObject_AsVoidPtr(obj3); \ - arg4 = ( intype4 ) PyCObject_AsVoidPtr(obj4); \ - \ - return ctor_ ## outtype ( func (arg1, arg2, arg3, arg4, arg5)); \ -} - -/** - * Wrap LLVM functions of the type - * outtype func(intype1 arg1, intype2 *arg2v, unsigned arg2n) - * where arg2v is an array of intype2 elements, arg2n in length. - */ -#define _wrap_objlist2obj(func, intype1, intype2, outtype) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - PyObject *obj1, *obj2; \ - intype1 arg1; \ - intype2 *arg2v; \ - unsigned arg2n; \ - outtype ret; \ - \ - if (!PyArg_ParseTuple(args, "OO", &obj1, &obj2)) \ - return NULL; \ - arg1 = ( intype1 ) PyCObject_AsVoidPtr(obj1); \ - arg2n = (unsigned) PyList_Size(obj2); \ - if (!(arg2v = ( intype2 *)make_array_from_list(obj2, arg2n))) \ - return PyErr_NoMemory(); \ - \ - ret = func (arg1, arg2v, arg2n); \ - free(arg2v); \ - return ctor_ ## outtype (ret); \ -} - -/** - * Wrap LLVM functions of the type - * outtype func(intype1 *arg1v, unsigned arg1n, int arg2) - * where arg1v is an array of intype1 elements, arg1n in length. - */ -#define _wrap_listint2obj(func, intype1, outtype) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - PyObject *obj1; \ - int arg2; \ - intype1 *arg1v; \ - unsigned arg1n; \ - outtype ret; \ - \ - if (!PyArg_ParseTuple(args, "Oi", &obj1, &arg2)) \ - return NULL; \ - \ - arg1n = (unsigned) PyList_Size(obj1); \ - if (!(arg1v = ( intype1 *)make_array_from_list(obj1, arg1n))) \ - return PyErr_NoMemory(); \ - \ - ret = func (arg1v, arg1n, arg2); \ - free(arg1v); \ - return ctor_ ## outtype (ret); \ -} - -/** - * Wrap LLVM functions of the type - * outtype func(intype1 *arg1v, unsigned arg1n) - * where arg1v is an array of intype1 elements, arg1n in length. - */ -#define _wrap_list2obj(func, intype1, outtype) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - PyObject *obj1; \ - intype1 *arg1v; \ - unsigned arg1n; \ - outtype ret; \ - \ - if (!PyArg_ParseTuple(args, "O", &obj1)) \ - return NULL; \ - \ - arg1n = (unsigned) PyList_Size(obj1); \ - if (!(arg1v = ( intype1 *)make_array_from_list(obj1, arg1n))) \ - return PyErr_NoMemory(); \ - \ - ret = func (arg1v, arg1n); \ - free(arg1v); \ - return ctor_ ## outtype (ret); \ -} - -/** - * Wrap LLVM functions of the type - * outtype func(intype1 arg1, intype2 *arg2v, unsigned arg2n, int arg3) - * where arg2v is an array of intype2 elements, arg2n in length. - */ -#define _wrap_objlistint2obj(func, intype1, intype2, outtype) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - PyObject *obj1, *obj2; \ - intype1 arg1; \ - intype2 *arg2v; \ - unsigned arg2n; \ - int arg3; \ - outtype ret; \ - \ - if (!PyArg_ParseTuple(args, "OOi", &obj1, &obj2, &arg3)) \ - return NULL; \ - \ - arg1 = ( intype1 ) PyCObject_AsVoidPtr(obj1); \ - arg2n = (unsigned) PyList_Size(obj2); \ - if (!(arg2v = ( intype2 *)make_array_from_list(obj2, arg2n))) \ - return PyErr_NoMemory(); \ - \ - ret = func (arg1, arg2v, arg2n, arg3); \ - free(arg2v); \ - return ctor_ ## outtype (ret); \ -} - -/** - * Wrap LLVM functions of the type - * void func(intype1 arg1, intype2 *arg2v, unsigned arg2n, int arg3) - * where arg2v is an array of intype2 elements, arg2n in length. - */ -#define _wrap_objlistint2none(func, intype1, intype2) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - PyObject *obj1, *obj2; \ - intype1 arg1; \ - intype2 *arg2v; \ - unsigned arg2n; \ - int arg3; \ - \ - if (!PyArg_ParseTuple(args, "OOi", &obj1, &obj2, &arg3)) \ - return NULL; \ - \ - arg1 = ( intype1 ) PyCObject_AsVoidPtr(obj1); \ - arg2n = (unsigned) PyList_Size(obj2); \ - if (!(arg2v = ( intype2 *)make_array_from_list(obj2, arg2n))) \ - return PyErr_NoMemory(); \ - \ - func (arg1, arg2v, arg2n, arg3); \ - free(arg2v); \ - Py_RETURN_NONE; \ -} - - -/** - * Wrap LLVM functions of the type - * outtype func(intype1 arg1, int arg2, intype3 *arg3v, unsigned arg3n) - * where arg3v is an array of intype3 elements, arg3n in length. - */ -#define _wrap_objintlist2obj(func, intype1, intype3, outtype) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - PyObject *obj1, *obj3; \ - intype1 arg1; \ - int arg2; \ - intype3 *arg3v; \ - unsigned arg3n; \ - outtype ret; \ - \ - if (!PyArg_ParseTuple(args, "OiO", &obj1, &arg2, &obj3)) \ - return NULL; \ - \ - arg1 = ( intype1 ) PyCObject_AsVoidPtr(obj1); \ - arg3n = (unsigned) PyList_Size(obj3); \ - if (!(arg3v = ( intype3 *)make_array_from_list(obj3, arg3n))) \ - return PyErr_NoMemory(); \ - \ - ret = func (arg1, arg2, arg3v, arg3n); \ - free(arg3v); \ - return ctor_ ## outtype (ret); \ -} - -/** - * Wrap LLVM functions of the type - * outtype func(intype1 arg1, intype2 arg2, intype3 *arg3v, unsigned arg3n) - * where arg3v is an array of intype3 elements, arg3n in length. - */ -#define _wrap_objobjlist2obj(func, intype1, intype2, intype3, outtype) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - PyObject *obj1, *obj2, *obj3; \ - intype1 arg1; \ - intype2 arg2; \ - intype3 *arg3v; \ - unsigned arg3n; \ - outtype ret; \ - \ - if (!PyArg_ParseTuple(args, "OOO", &obj1, &obj2, &obj3)) \ - return NULL; \ - \ - arg1 = ( intype1 ) PyCObject_AsVoidPtr(obj1); \ - arg2 = ( intype2 ) PyCObject_AsVoidPtr(obj2); \ - arg3n = (unsigned) PyList_Size(obj3); \ - if (!(arg3v = ( intype3 *)make_array_from_list(obj3, arg3n))) \ - return PyErr_NoMemory(); \ - \ - ret = func (arg1, arg2, arg3v, arg3n); \ - free(arg3v); \ - return ctor_ ## outtype (ret); \ -} - -/** - * Wrap LLVM functions of the type - * outtype func(intype1 arg1, intype2 arg2, intype3 *arg3v, unsigned arg3n, const char *arg4) - * where arg3v is an array of intype3 elements, arg3n in length. - */ -#define _wrap_objobjliststr2obj(func, intype1, intype2, intype3, outtype) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - PyObject *obj1, *obj2, *obj3; \ - const char *arg4; \ - intype1 arg1; \ - intype2 arg2; \ - intype3 *arg3v; \ - unsigned arg3n; \ - outtype ret; \ - \ - if (!PyArg_ParseTuple(args, "OOOs", &obj1, &obj2, &obj3, &arg4))\ - return NULL; \ - \ - arg1 = ( intype1 ) PyCObject_AsVoidPtr(obj1); \ - arg2 = ( intype2 ) PyCObject_AsVoidPtr(obj2); \ - arg3n = ( unsigned ) PyList_Size(obj3); \ - if (!(arg3v = ( intype3 *)make_array_from_list(obj3, arg3n))) \ - return PyErr_NoMemory(); \ - \ - ret = func (arg1, arg2, arg3v, arg3n, arg4); \ - free(arg3v); \ - return ctor_ ## outtype (ret); \ -} - -/** - * Wrap LLVM dump-to-string functions of the type - * char *func(intype1) - * where the return value has to be disposed after use by calling - * LLVMDisposeMessage. - */ -#define _wrap_dumper(func, intype1) \ -static PyObject * \ -_w ## func (PyObject *self, PyObject *args) \ -{ \ - intype1 arg1; \ - char *val; \ - PyObject *ret; \ - \ - if (!(arg1= ( intype1 ) get_object_arg(args))) \ - return NULL; \ - \ - val = func (arg1); \ - ret = PyBytes_FromString(val); \ - LLVMDisposeMessage(val); \ - return ret; \ -} - -#endif /* LLVM_PY_USE_PYCAPSULE */ #endif /* LLVM_PY_WRAP_H */ diff --git a/setup-win32.py b/setup-win32.py index 46cc69c..fc066d8 100644 --- a/setup-win32.py +++ b/setup-win32.py @@ -1,21 +1,21 @@ #!/usr/bin/env python -# +# # Copyright (c) 2008, Mahadevan R All rights reserved. -# +# # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: -# +# # * Redistributions of source code must retain the above copyright notice, # this list of conditions and the following disclaimer. -# +# # * Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. -# -# * Neither the name of this software, nor the names of its +# +# * Neither the name of this software, nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. -# +# # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR @@ -123,7 +123,7 @@ def call_setup(llvm_dir, llvm_build_dir): ext_core = Extension( 'llvm._core', - ['llvm/_core.c', 'llvm/wrap.c', 'llvm/extra.cpp'], + ['llvm/_core.cpp', 'llvm/wrap.cpp', 'llvm/extra.cpp'], include_dirs = incdirs, library_dirs = [libdir], libraries = std_libs + libs_core, diff --git a/test/asm.py b/test/asm.py index dd564ae..ed003c1 100755 --- a/test/asm.py +++ b/test/asm.py @@ -25,5 +25,25 @@ class TestAsm(unittest.TestCase): self.assertEqual(str(m2).strip(), asm.strip()) + + def test_bitcode(self): + # create a module + m = Module.new('module1') + m.add_global_variable(Type.int(), 'i') + + # write it's assembly representation to a file + asm = str(m) + + with open("/tmp/testasm.bc", "wb") as fout: + m.to_bitcode(fout) + + # read it back into a module + with open("/tmp/testasm.bc", "rb") as fin: + m2 = Module.from_bitcode(fin) + # The default `m.id` is ''. + m2.id = m.id # Copy the name from `m` + + self.assertEqual(str(m2).strip(), asm.strip()) + if __name__ == '__main__': unittest.main() diff --git a/test/constants.py b/test/constants.py index 4a2e543..c8e4000 100755 --- a/test/constants.py +++ b/test/constants.py @@ -193,7 +193,7 @@ class TestConstants(unittest.TestCase): # check result for result, golden in zip(results, values): - self.assertEqual(result, golden) + self.assertEqual(result.decode(), golden) def test_const_struct(self): from random import randint, random @@ -201,7 +201,7 @@ class TestConstants(unittest.TestCase): (0, 0., 0.), (-1, -1., -1.), (1, 1., 1.), - ] + [(randint(0, 0xffffffff), random(), random()) for _ in xrange(100)] + ] + [(randint(0, 0xffffffff), random(), random()) for _ in range(100)] struct_type = Type.struct([Type.int(), Type.float(), Type.double()]) @@ -260,7 +260,7 @@ class TestConstants(unittest.TestCase): (0, 0, 0, 0), (1, 1, 1, 1), (-1, -1, -1, -1), - ] + [ (randgen(), randgen(), randgen(), randgen()) for _ in xrange(100) ] + ] + [ (randgen(), randgen(), randgen(), randgen()) for _ in range(100) ] def map_constant(packed_values): consts = [ Constant.int(Type.int(), i) for i in packed_values ] diff --git a/test/testattrs.py b/test/testattrs.py index 09deced..8801f62 100755 --- a/test/testattrs.py +++ b/test/testattrs.py @@ -10,7 +10,7 @@ except ImportError: import unittest def make_module(): - test_module = u""" + test_module = """ define i32 @sum(i32, i32) { entry: %2 = add i32 %0, %1 From 4783429804db4cef7c3197bd5c5264155a1f3146 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Thu, 26 Jul 2012 15:44:53 -0700 Subject: [PATCH 020/675] Drop unused argument for GenericValue.pointer(). --- llvm/_core.cpp | 8 ++++---- llvm/ee.py | 24 +++++++++++++++++++++--- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/llvm/_core.cpp b/llvm/_core.cpp index 52310f1..765d106 100644 --- a/llvm/_core.cpp +++ b/llvm/_core.cpp @@ -1180,18 +1180,18 @@ _wLLVMCreateGenericValueOfFloat(PyObject *self, PyObject *args) static PyObject * _wLLVMCreateGenericValueOfPointer(PyObject *self, PyObject *args) { - PyObject *obj1; - LLVMTypeRef ty; +// PyObject *obj1; +// LLVMTypeRef ty; //unused? unsigned long long n_; size_t n; LLVMGenericValueRef gv; - if (!PyArg_ParseTuple(args, "OL", &obj1, &n_)) + if (!PyArg_ParseTuple(args, "L", &n_)) return NULL; n=n_; - ty = (LLVMTypeRef) PyCapsule_GetPointer(obj1, NULL); +// ty = (LLVMTypeRef) PyCapsule_GetPointer(obj1, NULL); gv = LLVMCreateGenericValueOfPointer((void*)n); return ctor_LLVMGenericValueRef(gv); diff --git a/llvm/ee.py b/llvm/ee.py index 62795a0..904716e 100644 --- a/llvm/ee.py +++ b/llvm/ee.py @@ -36,7 +36,9 @@ import llvm # top-level, for common stuff import llvm.core as core # module, function etc. import llvm._core as _core # C wrappers import llvm._util as _util # utility functions +import logging +logger = logging.getLogger(__name__) #===----------------------------------------------------------------------=== # Enumerations @@ -141,9 +143,25 @@ class GenericValue(object): return GenericValue(ptr) @staticmethod - def pointer(ty, intval): - core.check_is_type(ty) - ptr = _core.LLVMCreateGenericValueOfPointer(ty.ptr, intval) + def pointer(*args): + ''' + One argument version takes (addr). + Two argument version takes (ty, addr). [Deprecated] + + `ty` is unused. + `addr` is an integer representing an address. + + TODO: remove two argument version. + ''' + if len(args)==2: + logger.warning("Deprecated: Two argument version of " + "GenericValue.pointer() is deprecated.") + addr = args[1] + elif len(args)!=1: + raise TypeError("pointer() takes 1 or 2 arguments.") + else: + addr = args[0] + ptr = _core.LLVMCreateGenericValueOfPointer(addr) return GenericValue(ptr) def __init__(self, ptr): From 066480fbb898ca63a60aacf830086b4d3d07f5d6 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 1 Aug 2012 19:02:58 -0700 Subject: [PATCH 021/675] Add parallel-vectorize prototype. Add llvm_cbuilder. --- llvm_cbuilder/__init__.py | 2 + llvm_cbuilder/builder.py | 515 ++++++++++++++++++++++++++++++++++++ llvm_cbuilder/executor.py | 50 ++++ llvm_cbuilder/shortnames.py | 17 ++ tests/test_isprime.py | 120 +++++++++ tests/test_pthread.py | 79 ++++++ 6 files changed, 783 insertions(+) create mode 100644 llvm_cbuilder/__init__.py create mode 100644 llvm_cbuilder/builder.py create mode 100644 llvm_cbuilder/executor.py create mode 100644 llvm_cbuilder/shortnames.py create mode 100644 tests/test_isprime.py create mode 100644 tests/test_pthread.py diff --git a/llvm_cbuilder/__init__.py b/llvm_cbuilder/__init__.py new file mode 100644 index 0000000..e623129 --- /dev/null +++ b/llvm_cbuilder/__init__.py @@ -0,0 +1,2 @@ +from .builder import CBuilder +from .executor import CExecutor diff --git a/llvm_cbuilder/builder.py b/llvm_cbuilder/builder.py new file mode 100644 index 0000000..ee866df --- /dev/null +++ b/llvm_cbuilder/builder.py @@ -0,0 +1,515 @@ +# +# TODO: Add support for vector. +# + +import contextlib +import llvm.core as lc + + +def _is_int(ty): + return isinstance(ty, lc.IntegerType) + +def _is_real(ty): + tys = [ lc.Type.float(), + lc.Type.double(), + lc.Type.x86_fp80(), + lc.Type.fp128(), + lc.Type.ppc_fp128() ] + return any(ty == x for x in tys) + +def _is_pointer(ty): + return isinstance(ty, lc.PointerType) + +def _is_block_terminated(bb): + instrs = bb.instructions + return len(instrs) > 0 and instrs[-1].is_terminator + +@contextlib.contextmanager +def _change_block_temporarily(builder, bb): + origbb = builder.basic_block + builder.position_at_end(bb) + yield + builder.position_at_end(origbb) + +class _IfElse(object): + def __init__(self, parent, cond): + self.parent = parent + self.cond = cond + self._to_close = [] + + @contextlib.contextmanager + def then(self): + self._bbif = self.parent.function.append_basic_block('if.then') + self._bbelse = self.parent.function.append_basic_block('if.else') + + builder = self.parent.builder + builder.cbranch(self.cond.value, self._bbif, self._bbelse) + + builder.position_at_end(self._bbif) + + yield + + self._to_close.extend([self._bbif, self._bbelse]) + + @contextlib.contextmanager + def otherwise(self): + self.parent.builder.position_at_end(self._bbelse) + yield + + def close(self): + bbend = self.parent.function.append_basic_block('if.end') + builder = self.parent.builder + for bb in self._to_close: + if not _is_block_terminated(bb): + with _change_block_temporarily(builder, bb): + builder.branch(bbend) + builder.position_at_end(bbend) + +class _Loop(object): + def __init__(self, parent): + self.parent = parent + + @contextlib.contextmanager + def condition(self): + builder = self.parent.builder + self._bbcond = self.parent.function.append_basic_block('loop.cond') + self._bbbody = self.parent.function.append_basic_block('loop.body') + self._bbend = self.parent.function.append_basic_block('loop.end') + + builder.branch(self._bbcond) + + builder.position_at_end(self._bbcond) + + def setcond(cond): + builder.cbranch(cond.value, self._bbbody, self._bbend) + + yield setcond + + @contextlib.contextmanager + def body(self): + builder = self.parent.builder + builder.position_at_end(self._bbbody) + + yield self + + if not _is_block_terminated(builder.basic_block): + builder.branch(self._bbcond) + + def break_loop(self): + self.branch(self._bbend) + + def continue_loop(self): + self.branch(self._bbcond) + + def close(self): + self.parent.builder.position_at_end(self._bbend) + + +class CBuilder(object): + ''' + A wrapper class for features in llvm-py package + to allow user to use C-like high-level language contruct easily. + ''' + def __init__(self, function): + self.function = function + self.declare_block = self.function.append_basic_block('decl') + self.first_body_block = self.function.append_basic_block('body') + self.builder = lc.Builder.new(self.first_body_block) + + # prepare arguments + self.args = [] + for arg in function.args: + var = self.var(arg.type, arg, name=arg.name) + self.args.append(var) + + @staticmethod + def new_function(mod, name, ret, args): + functype = lc.Type.function(ret, args) + func = mod.add_function(functype, name=name) + return CBuilder(func) + + def var(self, ty, value=None, name=''): + ''' + Only allocate in the first block + ''' + with _change_block_temporarily(self.builder, self.declare_block): + ptr = self.builder.alloca(ty, name=name) + if value is not None: + if not isinstance(value, lc.Value): + value = self.constant(ty, value).value + self.builder.store(value, ptr) + return CVar(self, ptr) + + def array(self, ty, count, name=''): + with _change_block_temporarily(self.builder, self.declare_block): + if not isinstance(count, lc.Value): + count = self.constant(lc.Type.int(), count).value + ptr = self.builder.alloca_array(ty, count, name=name) + return CArray(self, ptr) + + def ret(self, val=None): + retty = self.function.type.pointee.return_type + if val is not None: + if val.type != retty: + errmsg = "Return type mismatch" + raise TypeError(errmsg) + self.builder.ret(val.value) + else: + if retty != lc.Type.void(): + errmsg = "Cannot return void" + raise TypeError(errmsg) + self.builder.ret_void() + + @contextlib.contextmanager + def ifelse(self, cond): + cb = _IfElse(self, cond) + yield cb + cb.close() + + @contextlib.contextmanager + def loop(self): + cb = _Loop(self) + yield cb + cb.close() + + def position_at_end(self, bb): + self.basic_block = bb + self.builder.position_at_end(bb) + + def close(self): + # Close declaration block + with _change_block_temporarily(self.builder, self.declare_block): + self.builder.branch(self.first_body_block) + + def constant(self, ty, val): + if isinstance(ty, lc.IntegerType): + res = lc.Constant.int(ty, val) + elif ty==lc.Type.float() or ty==lc.Type.double(): + res = lc.Constant.real(ty, val) + else: + raise TypeError("Cannot auto build constant " + "from %s and value %s" % (ty, val)) + return CTemp(self, res) + + def constant_null(self, ty): + res = lc.Constant.null(ty) + return CTemp(self, res) + + def get_intrinsic(self, intrinsic_id, tys): + lfunc = lc.Function.intrinsic(self.function.module, intrinsic_id, tys) + return CFunc(self, lfunc) + + def get_function_named(self, name): + m = self.function.module + func = m.get_function_named(name) + return CFunc(self, func) + + def is_terminated(self): + ''' + Is the current basic-block terminated? + ''' + return _is_block_terminated(self.builder.basic_block) + + +class CValue(object): + ''' + = Signess = + Since LLVM type does not provide signess attribute. This information + is provided in the CValue.unsigned attribute. The default value is + `None`, meaning that this attribute is not set. + + In casting operation, signess information is passed as an optional arg. + + In binary operation, signess of the left operand is used. + ''' + + # Attribute for for integer values. + unsigned = None + + _BINOP_MAP = { + # op-name : (signed int, unsigned int, real) + 'add' : (lc.Builder.add, lc.Builder.add, lc.Builder.fadd), + 'sub' : (lc.Builder.sub, lc.Builder.sub, lc.Builder.fsub), + 'mul' : (lc.Builder.mul, lc.Builder.mul, lc.Builder.fmul), + 'div' : (lc.Builder.sdiv, lc.Builder.udiv, lc.Builder.fdiv), + 'mod' : (lc.Builder.srem, lc.Builder.urem, lc.Builder.frem), + } + + _BITWISE_MAP = { + # op-name : (signed int, unsigned int) + 'lshift' : (lc.Builder.shl, lc.Builder.shl), + 'rshift' : (lc.Builder.lshr, lc.Builder.ashr), + 'and' : (lc.Builder.and_, lc.Builder.and_), + 'or' : (lc.Builder.or_, lc.Builder.or_), + 'xor' : (lc.Builder.xor, lc.Builder.xor), + } + + _CMP_MAP = { + # op-name : (signed int, unsigned int, real) + 'eq' : (lc.ICMP_EQ, lc.ICMP_EQ, lc.FCMP_OEQ), + 'ne' : (lc.ICMP_NE, lc.ICMP_NE, lc.FCMP_ONE), + 'lt' : (lc.ICMP_SLT, lc.ICMP_ULT, lc.FCMP_OLT), + 'le' : (lc.ICMP_SLE, lc.ICMP_ULE, lc.FCMP_OLE), + 'gt' : (lc.ICMP_SGT, lc.ICMP_UGT, lc.FCMP_OGT), + 'ge' : (lc.ICMP_SGE, lc.ICMP_UGE, lc.FCMP_OGE), + } + + def __init__(self, parent): + self.parent = parent + + def _use_binop(self, op): + def wrapped(rhs): + self._ensure_same_type(rhs) + binop = self._BINOP_MAP[op] + if self.is_int: + if not self.unsigned: + idx = 0 + else: + idx = 1 + elif self.is_real: + idx = 2 + else: + errmsg = "Binary operation %s does not support type %s" + raise TypeError(errmsg % (op, self.type)) + res = binop[idx](self.parent.builder, self.value, rhs.value) + return CTemp(self.parent, res) + return wrapped + + def _use_bitwise(self, op): + def wrapped(rhs): + self._ensure_same_type(rhs) + if not self.is_int: + errmsg = "Bitwise operation %s does not support type %s" + raise TypeError(op, self.type) + if not self.unsigned: + idx = 0 + else: + idx = 1 + res = self._BITWISE_MAP[idx](self.parent.builder, + self.value, rhs.value) + return CTemp(self.parent, res) + return wrapped + + def __add__(self, rhs): + return self._use_binop('add')(rhs) + + def __sub__(self, rhs): + return self._use_binop('sub')(rhs) + + def __mul__(self, rhs): + return self._use_binop('mul')(rhs) + + def __div__(self, rhs): + return self._use_binop('div')(rhs) + + def __mod__(self, rhs): + return self._use_binop('mod')(rhs) + + def __lshift__(self, rhs): + return self._use_bitwise('lshift')(rhs) + + def __rshift__(self, rhs): + return self._use_bitwise('rshift')(rhs) + + def __and__(self, rhs): + return self._use_bitwise('and')(rhs) + + def __or__(self, rhs): + return self._use_bitwise('or')(rhs) + + def __xor__(self, rhs): + return self._use_bitwise('xor')(rhs) + + def _ensure_same_type(self, val): + if self.type != val.type: + errmsg = "Type mismatch: %s != %s" + raise TypeError(errmsg % (self.type, val.type)) + + @property + def is_int(self): + return _is_int(self.type) + + @property + def is_real(self): + return _is_real(self.type) + + def cast(self, ty, unsigned=False): + make = lambda X: CTemp(self.parent, X) + if self.type == ty: + return self # pass thru + elif self.is_pointer and _is_pointer(ty): + builder = self.parent.builder + return make(builder.bitcast(self.value, ty)) + elif self.is_int: + if _is_int(ty): + if self.type.width > ty.width: + if not unsigned: + return make(self.parent.builder.sext(self.value, ty)) + else: + return make(self.parent.builder.zext(self.value, ty)) + else: + return make(self.parent.trunc(self.value, ty)) + elif _is_real(ty): + if not unsigned: + return make(self.parent.builder.sitofp(self.value, ty)) + else: + return make(self.parent.builder.uitofp(self.value, ty)) + elif self.is_real: + if not unsigned: + return make(self.parent.builder.fptosi(self.value, ty)) + else: + return make(self.parent.builder.fptoui(self.value, ty)) + + errmsg = "Cast from %s to %s is not possible." + raise TypeError(errmsg % (self.type, ty)) + + def _cmp_op(self, name): + def wrapped(rhs): + make = lambda X: CTemp(self.parent, X) + self._ensure_same_type(rhs) + + flag_bag = self._CMP_MAP[name] + if self.is_int: + comparator = self.parent.builder.icmp + if not self.unsigned: + flag = flag_bag[0] + else: + flag = flag_bag[1] + elif self.is_real: + comparator = self.parent.builder.fcmp + flag = flag_bag[2] + else: + errmsg = "Comparision between %s and %s is not supported." + raise TypeError(errmsg % (self.type, rhs.type)) + + return CTemp(self.parent, comparator(flag, self.value, rhs.value)) + return wrapped + + def __eq__(self, rhs): + return self._cmp_op('eq')(rhs) + + def __ne__(self, rhs): + return self._cmp_op('ne')(rhs) + + def __lt__(self, rhs): + return self._cmp_op('lt')(rhs) + + def __le__(self, rhs): + return self._cmp_op('le')(rhs) + + def __gt__(self, rhs): + return self._cmp_op('gt')(rhs) + + def __ge__(self, rhs): + return self._cmp_op('ge')(rhs) + + + @property + def is_pointer(self): + return _is_pointer(self.type) + + def _ensure_is_pointer(self): + if not self.is_pointer: + raise TypeError("Must be a pointer") + + +class CFunc(CValue): + def __init__(self, parent, func): + super(CFunc, self).__init__(parent) + self.function = func + + def __call__(self, *args): + arg_value = map(lambda x: x.value, args) + res = self.parent.builder.call(self.function, arg_value) + return CTemp(self.parent, res) + + @property + def value(self): + return self.function + + @property + def type(self): + return self.function.type + +class CTemp(CValue): + def __init__(self, parent, value): + super(CTemp, self).__init__(parent) + self.value = value + + @property + def type(self): + return self.value.type + +class CVar(CValue): + def __init__(self, parent, ptr): + super(CVar, self).__init__(parent) + self.ptr = ptr + + def _inplace_op(self, op): + def wrapped(rhs): + res = self._use_binop('add')(rhs) + self.assign(res) + return self + return wrapped + + def __iadd__(self, rhs): + return self._inplace_op('add')(rhs) + + def __isub__(self, rhs): + return self._inplace_op('sub')(rhs) + + def __imul__(self, rhs): + return self._inplace_op('mul')(rhs) + + def __idiv__(self, rhs): + return self._inplace_op('div')(rhs) + + def __imod__(self, rhs): + return self._inplace_op('mod')(rhs) + + @property + def value(self): + return self.parent.builder.load(self.ptr) + + def assign(self, val): + self.parent.builder.store(val.value, self.ptr) + + @property + def type(self): + return self.ptr.type.pointee + + def load(self): + self._ensure_is_pointer() + loaded = self.parent.builder.load(self.value) + return CTemp(self.parent, loaded) + + def store(self, val): + self._ensure_is_pointer() + self.parent.builder.store(val.value, self.value) + + def reference(self): + return CTemp(self.parent, self.ptr) + +class CArray(CValue): + def __init__(self, parent, base): + super(CArray, self).__init__(parent) + self.base_ptr = base + + @property + def value(self): + return self.base_ptr + + @property + def type(self): + return self.base_ptr.type + + def __getitem__(self, idx): + self._ensure_is_pointer() + builder = self.parent.builder + if isinstance(idx, CValue): + idx = idx.value + elif not isinstance(idx, lc.Value): + idx = self.parent.constant(lc.Type.int(), idx).value + ptr = builder.gep(self.value, [idx]) + return CVar(self.parent, ptr) + diff --git a/llvm_cbuilder/executor.py b/llvm_cbuilder/executor.py new file mode 100644 index 0000000..e5aa1c0 --- /dev/null +++ b/llvm_cbuilder/executor.py @@ -0,0 +1,50 @@ +from llvm.core import Type, Module +import llvm.ee as le +import ctypes as ct + +MAP_CTYPES = { +'void' : None, +'bool' : ct.c_bool, +'char' : ct.c_char, +'uchar' : ct.c_ubyte, +'short' : ct.c_short, +'ushort' : ct.c_ushort, +'int' : ct.c_int, +'uint' : ct.c_uint, +'long' : ct.c_long, +'ulong' : ct.c_ulong, + +'int8' : ct.c_int8, +'uint8' : ct.c_uint8, +'int16' : ct.c_int16, +'uint16' : ct.c_uint16, +'int32' : ct.c_int32, +'uint32' : ct.c_uint32, +'int64' : ct.c_int64, +'uint64' : ct.c_uint64, + +'float' : ct.c_float, +'double' : ct.c_double, +'longdouble' : ct.c_longdouble, +} + +class CExecutor(object): + def __init__(self, mod_or_engine): + if isinstance(mod_or_engine, Module): + self.engine = le.ExecutionEngine.new(mod_or_engine) + else: + self.engine = mod_or_engine + + def get_ctype_function(self, fn, typeinfo): + types = [ MAP_CTYPES[s.strip()] for s in typeinfo.split(',') ] + if not types: + retty = None + argtys = [] + else: + retty = types[0] + argtys = types[1:] + + prototype = ct.CFUNCTYPE(retty, *argtys) + fnptr = self.engine.get_pointer_to_function(fn) + return prototype(fnptr) + diff --git a/llvm_cbuilder/shortnames.py b/llvm_cbuilder/shortnames.py new file mode 100644 index 0000000..c0e65ca --- /dev/null +++ b/llvm_cbuilder/shortnames.py @@ -0,0 +1,17 @@ +from llvm.core import Type + +void = Type.void() +char = Type.int(8) +short = Type.int(16) +int = Type.int(32) +int16 = short +int32 = int +int64 = Type.int(64) +float = Type.float() +double = Type.double() + +# pointers + +pointer = Type.pointer + +void_p = pointer(char) diff --git a/tests/test_isprime.py b/tests/test_isprime.py new file mode 100644 index 0000000..5c6b78e --- /dev/null +++ b/tests/test_isprime.py @@ -0,0 +1,120 @@ +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') + + 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_pthread.py b/tests/test_pthread.py new file mode 100644 index 0000000..e86dbdb --- /dev/null +++ b/tests/test_pthread.py @@ -0,0 +1,79 @@ +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)) + + for tid in range(NUM_OF_THREAD): + pthread_join_args = threads[tid], NULL + pthread_join(*map(cast_to_null, pthread_join_args)) + + worker_func(arg.reference()) + + 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 + self.assertEqual(func(inarg), inarg+NUM_OF_THREAD+1) + +if __name__ == '__main__': + unittest.main() + From 6981206096679347d2db346e93b963844f11aac1 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 1 Aug 2012 20:14:34 -0700 Subject: [PATCH 022/675] Add TODO and README files. --- TODO | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 TODO diff --git a/TODO b/TODO new file mode 100644 index 0000000..9a0e689 --- /dev/null +++ b/TODO @@ -0,0 +1,2 @@ +* add atomic operation to llvm-py +* add volatile load/store to llvm-py From c7afaf98dbd2213adaf27d301f97f210985bbe9f Mon Sep 17 00:00:00 2001 From: "Travis E. Oliphant" Date: Thu, 2 Aug 2012 02:46:10 -0500 Subject: [PATCH 023/675] Update license and README --- LICENSE | 1 + README.md | 12 ++++++------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/LICENSE b/LICENSE index 579d556..8117ae1 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,5 @@ Copyright (c) 2008-10, Mahadevan R All rights reserved. +Copyright (c) 2012, Continuum Analytics, Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/README.md b/README.md index 74194eb..f0d1f09 100644 --- a/README.md +++ b/README.md @@ -2,22 +2,22 @@ llvm-py provides Python bindings for LLVM. ## Home page ## -https://github.com/AndrewBC/llvm-py +http://www.llvmpy.org ## Versions ## -This package has only been tested with LLVM 2.9, and Python 2.7, (not Python 3.x). +This package has only been tested with LLVM 3.1, and Python 2.7, (not Python 3.x). ## Quickstart ## -1. Get 2.9 version of LLVM, build it. Make sure '--enable-pic' is passed to LLVM's 'configure'. +1. Get 3.1 version of LLVM, build it. Make sure '--enable-pic' is passed to LLVM's 'configure'. 2. Get llvm-py and install it: ``` -$ git clone git@github.com:AndrewBC/llvm-py.git -$ cd llvm-py +$ git clone git@github.com:llvmpy/llvmpy.git +$ cd llvmpy $ python setup.py install ``` -3. See documentation at 'www/web/index.html' and examples under 'test'. +3. See documentation at 'http://www.llvmpy.org/pages.html' and examples under 'test'. ## LICENSE ## llvm-py is distributed under the new BSD license, which is similar to the LLVM license itself. From 7238fecc7f9f5d03320b296fe29840c1b04970e5 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Thu, 2 Aug 2012 14:20:02 -0700 Subject: [PATCH 024/675] add build & test instruction to README --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..cab0f28 --- /dev/null +++ b/README.md @@ -0,0 +1,7 @@ +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... + + From 9d068fd582659b1650ab37801879d09e8e3428be Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Thu, 2 Aug 2012 16:51:42 -0700 Subject: [PATCH 025/675] Add methods to set volatile inst. --- llvm/_core.cpp | 2 ++ llvm/core.py | 17 +++++++++++---- test/volatile.py | 55 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 70 insertions(+), 4 deletions(-) create mode 100644 test/volatile.py diff --git a/llvm/_core.cpp b/llvm/_core.cpp index 765d106..821537e 100644 --- a/llvm/_core.cpp +++ b/llvm/_core.cpp @@ -596,6 +596,7 @@ _wrap_obj2obj(LLVMInstIsArithmeticShift, LLVMValueRef, int) _wrap_obj2obj(LLVMInstIsAssociative, LLVMValueRef, int) _wrap_obj2obj(LLVMInstIsCommutative, LLVMValueRef, int) _wrap_obj2obj(LLVMInstIsVolatile, LLVMValueRef, int) +_wrap_objint2none(LLVMSetVolatile, LLVMValueRef) _wrap_obj2obj(LLVMInstGetOpcode, LLVMValueRef, int) _wrap_obj2str(LLVMInstGetOpcodeName, LLVMValueRef) @@ -1554,6 +1555,7 @@ static PyMethodDef core_methods[] = { _method( LLVMInstIsAssociative ) _method( LLVMInstIsCommutative ) _method( LLVMInstIsVolatile ) + _method( LLVMSetVolatile ) _method( LLVMInstGetOpcode ) _method( LLVMInstGetOpcodeName ) diff --git a/llvm/core.py b/llvm/core.py index f4c75bf..f1cade7 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -1458,6 +1458,9 @@ class Instruction(User): """True if this is a volatile load or store.""" return _core.LLVMInstIsVolatile(self.ptr) != 0 + def set_volatile(self, flag): + return _core.LLVMSetVolatile(self.ptr, int(bool(flag))) + @property def opcode(self): return _core.LLVMInstGetOpcode(self.ptr) @@ -1827,14 +1830,20 @@ class Builder(object): check_is_value(ptr) return _make_value(_core.LLVMBuildFree(self.ptr, ptr.ptr)) - def load(self, ptr, name=""): + def load(self, ptr, name="", volatile=False): check_is_value(ptr) - return _make_value(_core.LLVMBuildLoad(self.ptr, ptr.ptr, name)) + inst = _make_value(_core.LLVMBuildLoad(self.ptr, ptr.ptr, name)) + if volatile: + inst.set_volatile(volatile) + return inst - def store(self, value, ptr): + def store(self, value, ptr, volatile=False): check_is_value(value) check_is_value(ptr) - return _make_value(_core.LLVMBuildStore(self.ptr, value.ptr, ptr.ptr)) + inst = _make_value(_core.LLVMBuildStore(self.ptr, value.ptr, ptr.ptr)) + if volatile: + inst.set_volatile(volatile) + return inst def gep(self, ptr, indices, name=""): check_is_value(ptr) diff --git a/test/volatile.py b/test/volatile.py new file mode 100644 index 0000000..e567a80 --- /dev/null +++ b/test/volatile.py @@ -0,0 +1,55 @@ +from llvm.core import * +import unittest + +class TestVolatile(unittest.TestCase): + def test_volatile(self): + mod = Module.new('mod') + functype = Type.function(Type.void(), []) + func = mod.add_function(functype, name='foo') + bb = func.append_basic_block('entry') + bldr = Builder.new(bb) + ptr = bldr.alloca(Type.int()) + + # test load inst + val = bldr.load(ptr) + self.assertFalse(val.is_volatile, "default must be non-volatile") + val.set_volatile(True) + self.assertTrue(val.is_volatile, "fail to set volatile") + val.set_volatile(False) + self.assertFalse(val.is_volatile, "fail to unset volatile") + + # test store inst + store_inst = bldr.store(val, ptr) + self.assertFalse(store_inst.is_volatile, "default must be non-volatile") + store_inst.set_volatile(True) + self.assertTrue(store_inst.is_volatile, "fail to set volatile") + store_inst.set_volatile(False) + self.assertFalse(store_inst.is_volatile, "fail to unset volatile") + + def test_volatile_another(self): + mod = Module.new('mod') + functype = Type.function(Type.void(), []) + func = mod.add_function(functype, name='foo') + bb = func.append_basic_block('entry') + bldr = Builder.new(bb) + ptr = bldr.alloca(Type.int()) + + # test load inst + val = bldr.load(ptr, volatile=True) + self.assertTrue(val.is_volatile, "volatile kwarg does not work") + val.set_volatile(False) + self.assertFalse(val.is_volatile, "fail to unset volatile") + val.set_volatile(True) + self.assertTrue(val.is_volatile, "fail to set volatile") + + # test store inst + store_inst = bldr.store(val, ptr, volatile=True) + self.assertTrue(store_inst.is_volatile, "volatile kwarg does not work") + store_inst.set_volatile(False) + self.assertFalse(store_inst.is_volatile, "fail to unset volatile") + store_inst.set_volatile(True) + self.assertTrue(store_inst.is_volatile, "fail to set volatile") + + +if __name__ == '__main__': + unittest.main() From acad5c9d8badf380b1fcd55845eff72e0c3a2e7b Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Thu, 2 Aug 2012 17:54:40 -0700 Subject: [PATCH 026/675] Added atomic cmpxchg. --- llvm/_core.cpp | 7 +++++++ llvm/core.py | 9 +++++++++ llvm/extra.cpp | 39 +++++++++++++++++++++++++++++++++++++++ llvm/extra.h | 8 ++++++++ llvm/wrap.h | 28 ++++++++++++++++++++++++++++ test/atomic.py | 36 ++++++++++++++++++++++++++++++++++++ 6 files changed, 127 insertions(+) create mode 100644 test/atomic.py diff --git a/llvm/_core.cpp b/llvm/_core.cpp index 821537e..d1100ea 100644 --- a/llvm/_core.cpp +++ b/llvm/_core.cpp @@ -740,6 +740,10 @@ _wrap_objobjobjstr2obj(LLVMBuildBitCast, LLVMBuilderRef, LLVMValueRef, LLVMTypeR _wrap_objenumobjobjstr2obj(LLVMBuildICmp, LLVMBuilderRef, LLVMIntPredicate, LLVMValueRef, LLVMValueRef, LLVMValueRef) _wrap_objenumobjobjstr2obj(LLVMBuildFCmp, LLVMBuilderRef, LLVMRealPredicate, LLVMValueRef, LLVMValueRef, LLVMValueRef) + +/* Atomics */ +_wrap_objobjobjobjstrint2obj(LLVMBuildAtomicCmpXchg, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) + /* Miscellaneous instructions */ _wrap_objobjintstr2obj(LLVMBuildGetResult, LLVMBuilderRef, LLVMValueRef, LLVMValueRef) @@ -1647,6 +1651,9 @@ static PyMethodDef core_methods[] = { _method( LLVMBuildICmp ) _method( LLVMBuildFCmp ) + /* Atomics */ + _method( LLVMBuildAtomicCmpXchg ) + /* Miscellaneous instructions */ _method( LLVMBuildGetResult ) _method( LLVMBuildPhi ) diff --git a/llvm/core.py b/llvm/core.py index f1cade7..7ae22ea 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -1996,6 +1996,15 @@ class Builder(object): _core.LLVMBuildShuffleVector(self.ptr, vecA.ptr, vecB.ptr, mask.ptr, name)) + # atomics + + def atomic_cmpxchg(self, ptr, old, new, ordering, crossthread=True): + check_is_value(ptr) + check_is_value(old) + check_is_value(new) + inst = _core.LLVMBuildAtomicCmpXchg(self.ptr, ptr.ptr, old.ptr, new.ptr, + ordering.lower(), int(bool(crossthread))) + return _make_value(inst) #===----------------------------------------------------------------------=== # Memory buffer diff --git a/llvm/extra.cpp b/llvm/extra.cpp index 858fbcf..0d71065 100644 --- a/llvm/extra.cpp +++ b/llvm/extra.cpp @@ -111,6 +111,45 @@ char *do_print(W obj) return strdup(buf.str().c_str()); } +LLVMValueRef LLVMBuildAtomicCmpXchg(LLVMBuilderRef builder, LLVMValueRef ptr, + LLVMValueRef cmp, LLVMValueRef val, + const char* ordering, int crossthread) +{ + using namespace llvm; + + AtomicOrdering ordering_enum; + + if ( strcmp(ordering, "unordered") == 0 ) + ordering_enum = Unordered; + else if ( strcmp(ordering, "monotonic") == 0 ) + ordering_enum = Monotonic; + else if ( strcmp(ordering, "acquire") == 0 ) + ordering_enum = Acquire; + else if ( strcmp(ordering, "release") == 0 ) + ordering_enum = Release; + else if ( strcmp(ordering, "acq_rel") == 0 ) + ordering_enum = AcquireRelease; + else if ( strcmp(ordering, "seq_cst") == 0 ) + ordering_enum = SequentiallyConsistent; + else + ordering_enum = NotAtomic; + + SynchronizationScope crossthread_enum; + switch( crossthread ){ + case 0: + crossthread_enum = SingleThread; + break; + default: + crossthread_enum = CrossThread; + } + + + Value * inst = unwrap(builder)->CreateAtomicCmpXchg( + unwrap(ptr), unwrap(cmp), unwrap(val), + ordering_enum, crossthread_enum); + return wrap(inst); +} + LLVMEngineBuilderRef LLVMCreateEngineBuilder(LLVMModuleRef mod) { using namespace llvm; diff --git a/llvm/extra.h b/llvm/extra.h index b0bacc8..b02c527 100644 --- a/llvm/extra.h +++ b/llvm/extra.h @@ -45,6 +45,14 @@ extern "C" { #endif + +/* + * Wraps IRBuilder::CreateAtomicCmpXchg + */ +LLVMValueRef LLVMBuildAtomicCmpXchg(LLVMBuilderRef builder, LLVMValueRef ptr, + LLVMValueRef cmp, LLVMValueRef val, + const char* ordering, int crossthread); + /* * Wraps new EngineBuilder */ diff --git a/llvm/wrap.h b/llvm/wrap.h index 754d9d0..f754b02 100644 --- a/llvm/wrap.h +++ b/llvm/wrap.h @@ -671,6 +671,34 @@ _w ## func (PyObject *self, PyObject *args) \ return ctor_ ## outtype ( func (arg1, arg2, arg3, arg4)); \ } + +/** + * Wrap LLVM functions of the type + * outtype func(intype1 arg1, intype2 arg2, intype3 arg3, intype4, const char *arg5, arg6) + */ +#define _wrap_objobjobjobjstrint2obj(func, intype1, intype2, intype3, intype4, outtype)\ +static PyObject * \ +_w ## func (PyObject *self, PyObject *args) \ +{ \ + PyObject *obj1, *obj2, *obj3, *obj4; \ + intype1 arg1; \ + intype2 arg2; \ + intype3 arg3; \ + intype4 arg4; \ + const char *arg5; \ + int arg6; \ + \ + if (!PyArg_ParseTuple(args, "OOOOsi", &obj1, &obj2, &obj3, &obj4, &arg5, &arg6)) \ + return NULL; \ + \ + arg1 = ( intype1 ) PyCapsule_GetPointer(obj1, NULL); \ + arg2 = ( intype2 ) PyCapsule_GetPointer(obj2, NULL); \ + arg3 = ( intype3 ) PyCapsule_GetPointer(obj3, NULL); \ + arg4 = ( intype4 ) PyCapsule_GetPointer(obj4, NULL); \ + \ + return ctor_ ## outtype ( func (arg1, arg2, arg3, arg4, arg5, arg6)); \ +} + /** * Wrap LLVM functions of the type * outtype func(intype1 arg1, intype2 arg2, intype3 arg3, arg4) diff --git a/test/atomic.py b/test/atomic.py new file mode 100644 index 0000000..7cbbf49 --- /dev/null +++ b/test/atomic.py @@ -0,0 +1,36 @@ +from llvm.core import * +import unittest + +test_these_orderings = filter(bool, map(lambda s:s.strip(), +''' +unordered +monotonic +acquire +release +acq_rel +seq_cst +'''.splitlines())) + +class TestAtomic(unittest.TestCase): + def test_atomic(self): + mod = Module.new('mod') + functype = Type.function(Type.void(), []) + func = mod.add_function(functype, name='foo') + bb = func.append_basic_block('entry') + bldr = Builder.new(bb) + ptr = bldr.alloca(Type.int()) + + old = bldr.load(ptr) + new = Constant.int(Type.int(), 1234) + + + for ordering in test_these_orderings: + inst = bldr.atomic_cmpxchg(ptr, old, new, ordering) + self.assertEqual(ordering, str(inst).split(' ')[-1]) + + + inst = bldr.atomic_cmpxchg(ptr, old, new, ordering, crossthread=False) + self.assertEqual('singlethread', str(inst).split(' ')[-2]) + +if __name__ == '__main__': + unittest.main() From fb72ab5c8d6feb69a47b6cabf5d99e13f2f75466 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Fri, 3 Aug 2012 10:14:09 -0700 Subject: [PATCH 027/675] Add the rest of atomic op. --- llvm/_core.cpp | 2 + llvm/core.py | 10 ++++- llvm/extra.cpp | 100 ++++++++++++++++++++++++++++++++++++------------- llvm/extra.h | 6 +++ llvm/wrap.h | 26 +++++++++++++ test/atomic.py | 48 +++++++++++++++++++++--- 6 files changed, 159 insertions(+), 33 deletions(-) diff --git a/llvm/_core.cpp b/llvm/_core.cpp index d1100ea..7b0d31a 100644 --- a/llvm/_core.cpp +++ b/llvm/_core.cpp @@ -743,6 +743,7 @@ _wrap_objenumobjobjstr2obj(LLVMBuildFCmp, LLVMBuilderRef, LLVMRealPredicate, LLV /* Atomics */ _wrap_objobjobjobjstrint2obj(LLVMBuildAtomicCmpXchg, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) +_wrap_objstrobjobjstrint2obj(LLVMBuildAtomicRMW, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) /* Miscellaneous instructions */ @@ -1653,6 +1654,7 @@ static PyMethodDef core_methods[] = { /* Atomics */ _method( LLVMBuildAtomicCmpXchg ) + _method( LLVMBuildAtomicRMW ) /* Miscellaneous instructions */ _method( LLVMBuildGetResult ) diff --git a/llvm/core.py b/llvm/core.py index 7ae22ea..2219aa7 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -2003,7 +2003,15 @@ class Builder(object): check_is_value(old) check_is_value(new) inst = _core.LLVMBuildAtomicCmpXchg(self.ptr, ptr.ptr, old.ptr, new.ptr, - ordering.lower(), int(bool(crossthread))) + ordering.lower(), + int(bool(crossthread))) + return _make_value(inst) + + def atomic_rmw(self, op, ptr, val, ordering, crossthread=True): + check_is_value(ptr) + check_is_value(val) + inst = _core.LLVMBuildAtomicRMW(self.ptr, op.lower(), ptr.ptr, val.ptr, + ordering.lower(), int(bool(crossthread))) return _make_value(inst) #===----------------------------------------------------------------------=== diff --git a/llvm/extra.cpp b/llvm/extra.cpp index 0d71065..e36ef99 100644 --- a/llvm/extra.cpp +++ b/llvm/extra.cpp @@ -110,6 +110,76 @@ char *do_print(W obj) p->print(buf); return strdup(buf.str().c_str()); } +static +llvm::AtomicOrdering atomic_ordering_from_string(const char * ordering) +{ + using namespace llvm; + + if ( strcmp(ordering, "unordered") == 0 ) + return Unordered; + else if ( strcmp(ordering, "monotonic") == 0 ) + return Monotonic; + else if ( strcmp(ordering, "acquire") == 0 ) + return Acquire; + else if ( strcmp(ordering, "release") == 0 ) + return Release; + else if ( strcmp(ordering, "acq_rel") == 0 ) + return AcquireRelease; + else if ( strcmp(ordering, "seq_cst") == 0 ) + return SequentiallyConsistent; + else + return NotAtomic; +} + +static +llvm::SynchronizationScope sync_scope_from_int(int crossthread) +{ + if( crossthread ) + return llvm::CrossThread; + else + return llvm::SingleThread; +} + +LLVMValueRef LLVMBuildAtomicRMW(LLVMBuilderRef builder, const char * opname, + LLVMValueRef ptr, LLVMValueRef val, + const char* ordering, int crossthread) +{ + using namespace llvm; + + AtomicRMWInst::BinOp op; + + if( strcmp(opname, "xchg") == 0 ) + op = AtomicRMWInst::Xchg; + else if( strcmp(opname, "add") == 0 ) + op = AtomicRMWInst::Add; + else if( strcmp(opname, "sub") == 0 ) + op = AtomicRMWInst::Sub; + else if( strcmp(opname, "and") == 0 ) + op = AtomicRMWInst::And; + else if( strcmp(opname, "nand") == 0 ) + op = AtomicRMWInst::Nand; + else if( strcmp(opname, "or") == 0 ) + op = AtomicRMWInst::Or; + else if( strcmp(opname, "xor") == 0 ) + op = AtomicRMWInst::Xor; + else if( strcmp(opname, "max") == 0 ) + op = AtomicRMWInst::Max; + else if( strcmp(opname, "min") == 0 ) + op = AtomicRMWInst::Min; + else if( strcmp(opname, "umax") == 0 ) + op = AtomicRMWInst::UMax; + else if( strcmp(opname, "umin") == 0 ) + op = AtomicRMWInst::UMin; + else + op = AtomicRMWInst::BAD_BINOP; + + AtomicOrdering atomic_order = atomic_ordering_from_string(ordering); + SynchronizationScope sync_scope = sync_scope_from_int(crossthread); + + Value * inst = unwrap(builder)->CreateAtomicRMW(op, unwrap(ptr), unwrap(val), + atomic_order, sync_scope); + return wrap(inst); +} LLVMValueRef LLVMBuildAtomicCmpXchg(LLVMBuilderRef builder, LLVMValueRef ptr, LLVMValueRef cmp, LLVMValueRef val, @@ -117,36 +187,12 @@ LLVMValueRef LLVMBuildAtomicCmpXchg(LLVMBuilderRef builder, LLVMValueRef ptr, { using namespace llvm; - AtomicOrdering ordering_enum; - - if ( strcmp(ordering, "unordered") == 0 ) - ordering_enum = Unordered; - else if ( strcmp(ordering, "monotonic") == 0 ) - ordering_enum = Monotonic; - else if ( strcmp(ordering, "acquire") == 0 ) - ordering_enum = Acquire; - else if ( strcmp(ordering, "release") == 0 ) - ordering_enum = Release; - else if ( strcmp(ordering, "acq_rel") == 0 ) - ordering_enum = AcquireRelease; - else if ( strcmp(ordering, "seq_cst") == 0 ) - ordering_enum = SequentiallyConsistent; - else - ordering_enum = NotAtomic; - - SynchronizationScope crossthread_enum; - switch( crossthread ){ - case 0: - crossthread_enum = SingleThread; - break; - default: - crossthread_enum = CrossThread; - } - + AtomicOrdering atomic_order = atomic_ordering_from_string(ordering); + SynchronizationScope sync_scope = sync_scope_from_int(crossthread); Value * inst = unwrap(builder)->CreateAtomicCmpXchg( unwrap(ptr), unwrap(cmp), unwrap(val), - ordering_enum, crossthread_enum); + atomic_order, sync_scope); return wrap(inst); } diff --git a/llvm/extra.h b/llvm/extra.h index b02c527..5a11d0b 100644 --- a/llvm/extra.h +++ b/llvm/extra.h @@ -45,6 +45,12 @@ extern "C" { #endif +/* + * Wraps IRBuilder::CreateAtomicRMW + */ +LLVMValueRef LLVMBuildAtomicRMW(LLVMBuilderRef builder, const char * op, + LLVMValueRef ptr, LLVMValueRef val, + const char* ordering, int crossthread); /* * Wraps IRBuilder::CreateAtomicCmpXchg diff --git a/llvm/wrap.h b/llvm/wrap.h index f754b02..15c90e9 100644 --- a/llvm/wrap.h +++ b/llvm/wrap.h @@ -699,6 +699,32 @@ _w ## func (PyObject *self, PyObject *args) \ return ctor_ ## outtype ( func (arg1, arg2, arg3, arg4, arg5, arg6)); \ } +/** + * Wrap LLVM functions of the type + * outtype func(intype1 arg1, const char* arg2, intype3 arg3, intype4, const char *arg5, arg6) + */ +#define _wrap_objstrobjobjstrint2obj(func, intype1, intype3, intype4, outtype)\ +static PyObject * \ +_w ## func (PyObject *self, PyObject *args) \ +{ \ + PyObject *obj1, *obj3, *obj4; \ + intype1 arg1; \ + const char *arg2; \ + intype3 arg3; \ + intype4 arg4; \ + const char *arg5; \ + int arg6; \ + \ + if (!PyArg_ParseTuple(args, "OsOOsi", &obj1, &arg2, &obj3, &obj4, &arg5, &arg6)) \ + return NULL; \ + \ + arg1 = ( intype1 ) PyCapsule_GetPointer(obj1, NULL); \ + arg3 = ( intype3 ) PyCapsule_GetPointer(obj3, NULL); \ + arg4 = ( intype4 ) PyCapsule_GetPointer(obj4, NULL); \ + \ + return ctor_ ## outtype ( func (arg1, arg2, arg3, arg4, arg5, arg6)); \ +} + /** * Wrap LLVM functions of the type * outtype func(intype1 arg1, intype2 arg2, intype3 arg3, arg4) diff --git a/test/atomic.py b/test/atomic.py index 7cbbf49..5e3d9b0 100644 --- a/test/atomic.py +++ b/test/atomic.py @@ -1,7 +1,7 @@ from llvm.core import * import unittest -test_these_orderings = filter(bool, map(lambda s:s.strip(), +test_these_orderings = list(filter(bool, map(lambda s:s.strip(), ''' unordered monotonic @@ -9,10 +9,25 @@ acquire release acq_rel seq_cst -'''.splitlines())) +'''.splitlines()))) + +test_these_atomic_op = list(filter(bool, map(lambda s:s.strip(), +''' +xchg +add +sub +and +nand +or +xor +max +min +umax +umin +'''.splitlines()))) class TestAtomic(unittest.TestCase): - def test_atomic(self): + def test_atomic_cmpxchg(self): mod = Module.new('mod') functype = Type.function(Type.void(), []) func = mod.add_function(functype, name='foo') @@ -26,11 +41,34 @@ class TestAtomic(unittest.TestCase): for ordering in test_these_orderings: inst = bldr.atomic_cmpxchg(ptr, old, new, ordering) - self.assertEqual(ordering, str(inst).split(' ')[-1]) + self.assertEqual(ordering, str(inst).strip().split(' ')[-1]) inst = bldr.atomic_cmpxchg(ptr, old, new, ordering, crossthread=False) - self.assertEqual('singlethread', str(inst).split(' ')[-2]) + self.assertEqual('singlethread', str(inst).strip().split(' ')[-2]) + + def test_atomic_rmw(self): + mod = Module.new('mod') + functype = Type.function(Type.void(), []) + func = mod.add_function(functype, name='foo') + bb = func.append_basic_block('entry') + bldr = Builder.new(bb) + ptr = bldr.alloca(Type.int()) + + old = bldr.load(ptr) + val = Constant.int(Type.int(), 1234) + + for ordering in test_these_orderings: + inst = bldr.atomic_rmw('xchg', ptr, val, ordering) + self.assertEqual(ordering, str(inst).split(' ')[-1]) + + for op in test_these_atomic_op: + inst = bldr.atomic_rmw(op, ptr, val, ordering) + self.assertEqual(op, str(inst).strip().split(' ')[3]) + + inst = bldr.atomic_rmw('xchg', ptr, val, ordering, crossthread=False) + self.assertEqual('singlethread', str(inst).strip().split(' ')[-2]) + if __name__ == '__main__': unittest.main() From 4d763680f6c7cebfd18de8aec99c9762360cd86f Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Fri, 3 Aug 2012 10:28:17 -0700 Subject: [PATCH 028/675] Add easier atomic api --- llvm/core.py | 34 ++++++++++++++++++++++++++++++++++ test/atomic.py | 6 ++++++ 2 files changed, 40 insertions(+) diff --git a/llvm/core.py b/llvm/core.py index 2219aa7..5186c55 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -2014,6 +2014,40 @@ class Builder(object): ordering.lower(), int(bool(crossthread))) return _make_value(inst) + def atomic_xchg(self, *args, **kwargs): + return self.atomic_rmw('xchg', *args, **kwargs) + + def atomic_add(self, *args, **kwargs): + return self.atomic_rmw('add', *args, **kwargs) + + def atomic_sub(self, *args, **kwargs): + return self.atomic_rmw('sub', *args, **kwargs) + + def atomic_and(self, *args, **kwargs): + return self.atomic_rmw('and', *args, **kwargs) + + def atomic_nand(self, *args, **kwargs): + return self.atomic_rmw('nand', *args, **kwargs) + + def atomic_or(self, *args, **kwargs): + return self.atomic_rmw('or', *args, **kwargs) + + def atomic_xor(self, *args, **kwargs): + return self.atomic_rmw('xor', *args, **kwargs) + + def atomic_max(self, *args, **kwargs): + return self.atomic_rmw('max', *args, **kwargs) + + def atomic_min(self, *args, **kwargs): + return self.atomic_rmw('min', *args, **kwargs) + + def atomic_umax(self, *args, **kwargs): + return self.atomic_rmw('umax', *args, **kwargs) + + def atomic_umin(self, *args, **kwargs): + return self.atomic_rmw('umin', *args, **kwargs) + + #===----------------------------------------------------------------------=== # Memory buffer #===----------------------------------------------------------------------=== diff --git a/test/atomic.py b/test/atomic.py index 5e3d9b0..92be0e7 100644 --- a/test/atomic.py +++ b/test/atomic.py @@ -62,6 +62,7 @@ class TestAtomic(unittest.TestCase): inst = bldr.atomic_rmw('xchg', ptr, val, ordering) self.assertEqual(ordering, str(inst).split(' ')[-1]) + for op in test_these_atomic_op: inst = bldr.atomic_rmw(op, ptr, val, ordering) self.assertEqual(op, str(inst).strip().split(' ')[3]) @@ -70,5 +71,10 @@ class TestAtomic(unittest.TestCase): self.assertEqual('singlethread', str(inst).strip().split(' ')[-2]) + for op in test_these_atomic_op: + atomic_op = getattr(bldr, 'atomic_%s' % op) + inst = atomic_op(ptr, val, ordering) + self.assertEqual(op, str(inst).strip().split(' ')[3]) + if __name__ == '__main__': unittest.main() From 6ac0f3c3697abf3690e8036851336465d3c03d57 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Fri, 3 Aug 2012 11:56:59 -0700 Subject: [PATCH 029/675] Add atomic load/store --- llvm/_core.cpp | 4 ++++ llvm/core.py | 22 ++++++++++++++++++++++ llvm/extra.cpp | 29 +++++++++++++++++++++++++++++ llvm/extra.h | 13 +++++++++++++ llvm/wrap.h | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ test/atomic.py | 20 ++++++++++++++++++++ 6 files changed, 136 insertions(+) diff --git a/llvm/_core.cpp b/llvm/_core.cpp index 7b0d31a..7abee27 100644 --- a/llvm/_core.cpp +++ b/llvm/_core.cpp @@ -744,6 +744,8 @@ _wrap_objenumobjobjstr2obj(LLVMBuildFCmp, LLVMBuilderRef, LLVMRealPredicate, LLV /* Atomics */ _wrap_objobjobjobjstrint2obj(LLVMBuildAtomicCmpXchg, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) _wrap_objstrobjobjstrint2obj(LLVMBuildAtomicRMW, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) +_wrap_objobjstrint2obj(LLVMBuildAtomicLoad, LLVMBuilderRef, LLVMValueRef, LLVMValueRef) +_wrap_objobjobjstrint2obj(LLVMBuildAtomicStore, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) /* Miscellaneous instructions */ @@ -1655,6 +1657,8 @@ static PyMethodDef core_methods[] = { /* Atomics */ _method( LLVMBuildAtomicCmpXchg ) _method( LLVMBuildAtomicRMW ) + _method( LLVMBuildAtomicLoad ) + _method( LLVMBuildAtomicStore ) /* Miscellaneous instructions */ _method( LLVMBuildGetResult ) diff --git a/llvm/core.py b/llvm/core.py index 5186c55..bdb1485 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -2048,6 +2048,28 @@ class Builder(object): return self.atomic_rmw('umin', *args, **kwargs) + def atomic_load(self, ptr, ordering, crossthread=True, volatile=False, name=""): + check_is_value(ptr) + inst = _make_value(_core.LLVMBuildAtomicLoad( + self.ptr, ptr.ptr, ordering.lower(), + int(bool(crossthread)))) + if volatile: + inst.set_volatile(volatile) + if inst: + inst.name = name + return inst + + def atomic_store(self, value, ptr, ordering, crossthread=True, + volatile=False): + check_is_value(value) + check_is_value(ptr) + inst = _make_value(_core.LLVMBuildAtomicStore( + self.ptr, ptr.ptr, value.ptr, + ordering.lower(), int(bool(crossthread)))) + if volatile: + inst.set_volatile(volatile) + return inst + #===----------------------------------------------------------------------=== # Memory buffer #===----------------------------------------------------------------------=== diff --git a/llvm/extra.cpp b/llvm/extra.cpp index e36ef99..ca5e0ea 100644 --- a/llvm/extra.cpp +++ b/llvm/extra.cpp @@ -181,6 +181,35 @@ LLVMValueRef LLVMBuildAtomicRMW(LLVMBuilderRef builder, const char * opname, return wrap(inst); } +LLVMValueRef LLVMBuildAtomicLoad(LLVMBuilderRef builder, LLVMValueRef ptr, + const char* ordering, int crossthread) +{ + using namespace llvm; + AtomicOrdering atomic_order = atomic_ordering_from_string(ordering); + SynchronizationScope sync_scope = sync_scope_from_int(crossthread); + + LoadInst * inst = unwrap(builder)->CreateLoad(unwrap(ptr)); + + inst->setAtomic(atomic_order, sync_scope); + + return wrap(inst); +} + +LLVMValueRef LLVMBuildAtomicStore(LLVMBuilderRef builder, + LLVMValueRef ptr, LLVMValueRef val, + const char* ordering, int crossthread) +{ + using namespace llvm; + AtomicOrdering atomic_order = atomic_ordering_from_string(ordering); + SynchronizationScope sync_scope = sync_scope_from_int(crossthread); + + StoreInst * inst = unwrap(builder)->CreateStore(unwrap(val), unwrap(ptr)); + + inst->setAtomic(atomic_order, sync_scope); + + return wrap(inst); +} + LLVMValueRef LLVMBuildAtomicCmpXchg(LLVMBuilderRef builder, LLVMValueRef ptr, LLVMValueRef cmp, LLVMValueRef val, const char* ordering, int crossthread) diff --git a/llvm/extra.h b/llvm/extra.h index 5a11d0b..b773f19 100644 --- a/llvm/extra.h +++ b/llvm/extra.h @@ -45,6 +45,19 @@ extern "C" { #endif + +/* + * Wraps IRBuilder::CreateLoad, setAtomic + */ +LLVMValueRef LLVMBuildAtomicLoad(LLVMBuilderRef builder, LLVMValueRef ptr, + const char* ordering, int crossthread); +/* + * Wraps IRBuilder::CreateStore, setAtomic + */ +LLVMValueRef LLVMBuildAtomicStore(LLVMBuilderRef builder, + LLVMValueRef ptr, LLVMValueRef val, + const char* ordering, int crossthread); + /* * Wraps IRBuilder::CreateAtomicRMW */ diff --git a/llvm/wrap.h b/llvm/wrap.h index 15c90e9..fec5b72 100644 --- a/llvm/wrap.h +++ b/llvm/wrap.h @@ -671,6 +671,54 @@ _w ## func (PyObject *self, PyObject *args) \ return ctor_ ## outtype ( func (arg1, arg2, arg3, arg4)); \ } +/** + * Wrap LLVM functions of the type + * outtype func(intype1 arg1, intype2 arg2, const char *arg3, arg4) + */ +#define _wrap_objobjstrint2obj(func, intype1, intype2, outtype)\ +static PyObject * \ +_w ## func (PyObject *self, PyObject *args) \ +{ \ + PyObject *obj1, *obj2; \ + intype1 arg1; \ + intype2 arg2; \ + const char *arg3; \ + int arg4; \ + \ + if (!PyArg_ParseTuple(args, "OOsi", &obj1, &obj2, &arg3, &arg4)) \ + return NULL; \ + \ + arg1 = ( intype1 ) PyCapsule_GetPointer(obj1, NULL); \ + arg2 = ( intype2 ) PyCapsule_GetPointer(obj2, NULL); \ + \ + return ctor_ ## outtype ( func (arg1, arg2, arg3, arg4)); \ +} + +/** + * Wrap LLVM functions of the type + * outtype func(intype1 arg1, intype2 arg2, intype3, const char *arg4, arg5) + */ +#define _wrap_objobjobjstrint2obj(func, intype1, intype2, intype3, outtype)\ +static PyObject * \ +_w ## func (PyObject *self, PyObject *args) \ +{ \ + PyObject *obj1, *obj2, *obj3; \ + intype1 arg1; \ + intype2 arg2; \ + intype3 arg3; \ + const char *arg4; \ + int arg5; \ + \ + if (!PyArg_ParseTuple(args, "OOOsi", &obj1, &obj2, &obj3, &arg4, &arg5)) \ + return NULL; \ + \ + arg1 = ( intype1 ) PyCapsule_GetPointer(obj1, NULL); \ + arg2 = ( intype2 ) PyCapsule_GetPointer(obj2, NULL); \ + arg3 = ( intype3 ) PyCapsule_GetPointer(obj3, NULL); \ + \ + return ctor_ ## outtype ( func (arg1, arg2, arg3, arg4, arg5)); \ +} + /** * Wrap LLVM functions of the type diff --git a/test/atomic.py b/test/atomic.py index 92be0e7..ad99525 100644 --- a/test/atomic.py +++ b/test/atomic.py @@ -76,5 +76,25 @@ class TestAtomic(unittest.TestCase): inst = atomic_op(ptr, val, ordering) self.assertEqual(op, str(inst).strip().split(' ')[3]) + def test_atomic_ldst(self): + mod = Module.new('mod') + functype = Type.function(Type.void(), []) + func = mod.add_function(functype, name='foo') + bb = func.append_basic_block('entry') + bldr = Builder.new(bb) + ptr = bldr.alloca(Type.int()) + + val = Constant.int(Type.int(), 1234) + + for ordering in test_these_orderings: + loaded = bldr.atomic_load(ptr, ordering) + self.assertIn('load atomic', str(loaded)) + self.assertEqual(ordering, str(loaded).strip().split(' ')[-1]) + stored = bldr.atomic_store(loaded, ptr, ordering) + self.assertIn('store atomic', str(stored)) + self.assertEqual(ordering, str(stored).strip().split(' ')[-1]) + if __name__ == '__main__': unittest.main() + + From f479f85676f25006afa680662ae6e5c65875a8c9 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Fri, 3 Aug 2012 12:30:01 -0700 Subject: [PATCH 030/675] Add memory fence --- llvm/_core.cpp | 2 ++ llvm/core.py | 5 +++++ llvm/extra.cpp | 11 +++++++++++ llvm/extra.h | 10 ++++++++-- llvm/wrap.h | 23 +++++++++++++++++++++++ test/atomic.py | 5 +++++ 6 files changed, 54 insertions(+), 2 deletions(-) diff --git a/llvm/_core.cpp b/llvm/_core.cpp index 7abee27..c904ad1 100644 --- a/llvm/_core.cpp +++ b/llvm/_core.cpp @@ -746,6 +746,7 @@ _wrap_objobjobjobjstrint2obj(LLVMBuildAtomicCmpXchg, LLVMBuilderRef, LLVMValueRe _wrap_objstrobjobjstrint2obj(LLVMBuildAtomicRMW, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) _wrap_objobjstrint2obj(LLVMBuildAtomicLoad, LLVMBuilderRef, LLVMValueRef, LLVMValueRef) _wrap_objobjobjstrint2obj(LLVMBuildAtomicStore, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) +_wrap_objstrint2obj(LLVMBuildFence, LLVMBuilderRef, LLVMValueRef) /* Miscellaneous instructions */ @@ -1659,6 +1660,7 @@ static PyMethodDef core_methods[] = { _method( LLVMBuildAtomicRMW ) _method( LLVMBuildAtomicLoad ) _method( LLVMBuildAtomicStore ) + _method( LLVMBuildFence ) /* Miscellaneous instructions */ _method( LLVMBuildGetResult ) diff --git a/llvm/core.py b/llvm/core.py index bdb1485..962b018 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -2070,6 +2070,11 @@ class Builder(object): inst.set_volatile(volatile) return inst + def fence(self, ordering, crossthread=True): + inst = _make_value(_core.LLVMBuildFence(self.ptr, ordering.lower(), + int(bool(crossthread)))) + return inst + #===----------------------------------------------------------------------=== # Memory buffer #===----------------------------------------------------------------------=== diff --git a/llvm/extra.cpp b/llvm/extra.cpp index ca5e0ea..cd6aeee 100644 --- a/llvm/extra.cpp +++ b/llvm/extra.cpp @@ -140,6 +140,17 @@ llvm::SynchronizationScope sync_scope_from_int(int crossthread) return llvm::SingleThread; } +LLVMValueRef LLVMBuildFence(LLVMBuilderRef builder, const char* ordering, + int crossthread) +{ + using namespace llvm; + AtomicOrdering atomic_order = atomic_ordering_from_string(ordering); + SynchronizationScope sync_scope = sync_scope_from_int(crossthread); + + Value * inst = unwrap(builder)->CreateFence(atomic_order, sync_scope); + return wrap(inst); +} + LLVMValueRef LLVMBuildAtomicRMW(LLVMBuilderRef builder, const char * opname, LLVMValueRef ptr, LLVMValueRef val, const char* ordering, int crossthread) diff --git a/llvm/extra.h b/llvm/extra.h index b773f19..9bd0ddb 100644 --- a/llvm/extra.h +++ b/llvm/extra.h @@ -47,12 +47,18 @@ extern "C" { /* - * Wraps IRBuilder::CreateLoad, setAtomic + * Wraps IRBuilder::CreateFence + */ +LLVMValueRef LLVMBuildFence(LLVMBuilderRef builder, const char* ordering, + int crossthread); + +/* + * Wraps IRBuilder::CreateLoad, LoadInst::setAtomic */ LLVMValueRef LLVMBuildAtomicLoad(LLVMBuilderRef builder, LLVMValueRef ptr, const char* ordering, int crossthread); /* - * Wraps IRBuilder::CreateStore, setAtomic + * Wraps IRBuilder::CreateStore, StoreInst::setAtomic */ LLVMValueRef LLVMBuildAtomicStore(LLVMBuilderRef builder, LLVMValueRef ptr, LLVMValueRef val, diff --git a/llvm/wrap.h b/llvm/wrap.h index fec5b72..9cebd74 100644 --- a/llvm/wrap.h +++ b/llvm/wrap.h @@ -694,6 +694,29 @@ _w ## func (PyObject *self, PyObject *args) \ return ctor_ ## outtype ( func (arg1, arg2, arg3, arg4)); \ } + +/** + * Wrap LLVM functions of the type + * outtype func(intype1 arg1, const char *arg2, arg3) + */ +#define _wrap_objstrint2obj(func, intype1, outtype)\ +static PyObject * \ +_w ## func (PyObject *self, PyObject *args) \ +{ \ + PyObject *obj1; \ + intype1 arg1; \ + const char *arg2; \ + int arg3; \ + \ + if (!PyArg_ParseTuple(args, "Osi", &obj1, &arg2, &arg3)) \ + return NULL; \ + \ + arg1 = ( intype1 ) PyCapsule_GetPointer(obj1, NULL); \ + \ + return ctor_ ## outtype ( func (arg1, arg2, arg3)); \ +} + + /** * Wrap LLVM functions of the type * outtype func(intype1 arg1, intype2 arg2, intype3, const char *arg4, arg5) diff --git a/test/atomic.py b/test/atomic.py index ad99525..dc4896d 100644 --- a/test/atomic.py +++ b/test/atomic.py @@ -90,10 +90,15 @@ class TestAtomic(unittest.TestCase): loaded = bldr.atomic_load(ptr, ordering) self.assertIn('load atomic', str(loaded)) self.assertEqual(ordering, str(loaded).strip().split(' ')[-1]) + stored = bldr.atomic_store(loaded, ptr, ordering) self.assertIn('store atomic', str(stored)) self.assertEqual(ordering, str(stored).strip().split(' ')[-1]) + fenced = bldr.fence(ordering) + self.assertEqual(['fence', ordering], str(fenced).strip().split(' ')) + + if __name__ == '__main__': unittest.main() From 5e15b2790982edf84016e0794713933e354beb92 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Fri, 3 Aug 2012 14:13:22 -0700 Subject: [PATCH 031/675] Atomic load/store must explicit define alignment. --- llvm/_core.cpp | 4 ++-- llvm/core.py | 11 +++++----- llvm/extra.cpp | 8 ++++++-- llvm/extra.h | 6 ++++-- llvm/wrap.h | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++ test/atomic.py | 9 ++++++--- 6 files changed, 78 insertions(+), 14 deletions(-) diff --git a/llvm/_core.cpp b/llvm/_core.cpp index c904ad1..14143f2 100644 --- a/llvm/_core.cpp +++ b/llvm/_core.cpp @@ -744,8 +744,8 @@ _wrap_objenumobjobjstr2obj(LLVMBuildFCmp, LLVMBuilderRef, LLVMRealPredicate, LLV /* Atomics */ _wrap_objobjobjobjstrint2obj(LLVMBuildAtomicCmpXchg, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) _wrap_objstrobjobjstrint2obj(LLVMBuildAtomicRMW, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) -_wrap_objobjstrint2obj(LLVMBuildAtomicLoad, LLVMBuilderRef, LLVMValueRef, LLVMValueRef) -_wrap_objobjobjstrint2obj(LLVMBuildAtomicStore, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) +_wrap_objobjintstrint2obj(LLVMBuildAtomicLoad, LLVMBuilderRef, LLVMValueRef, LLVMValueRef) +_wrap_objobjobjintstrint2obj(LLVMBuildAtomicStore, LLVMBuilderRef, LLVMValueRef, LLVMValueRef, LLVMValueRef) _wrap_objstrint2obj(LLVMBuildFence, LLVMBuilderRef, LLVMValueRef) /* Miscellaneous instructions */ diff --git a/llvm/core.py b/llvm/core.py index 962b018..47b3b8a 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -2048,23 +2048,24 @@ class Builder(object): return self.atomic_rmw('umin', *args, **kwargs) - def atomic_load(self, ptr, ordering, crossthread=True, volatile=False, name=""): + def atomic_load(self, ptr, ordering, align=1, crossthread=True, + volatile=False, name=""): check_is_value(ptr) inst = _make_value(_core.LLVMBuildAtomicLoad( - self.ptr, ptr.ptr, ordering.lower(), - int(bool(crossthread)))) + self.ptr, ptr.ptr, int(align), + ordering.lower(), int(bool(crossthread)))) if volatile: inst.set_volatile(volatile) if inst: inst.name = name return inst - def atomic_store(self, value, ptr, ordering, crossthread=True, + def atomic_store(self, value, ptr, ordering, align=1, crossthread=True, volatile=False): check_is_value(value) check_is_value(ptr) inst = _make_value(_core.LLVMBuildAtomicStore( - self.ptr, ptr.ptr, value.ptr, + self.ptr, ptr.ptr, value.ptr, int(align), ordering.lower(), int(bool(crossthread)))) if volatile: inst.set_volatile(volatile) diff --git a/llvm/extra.cpp b/llvm/extra.cpp index cd6aeee..122d387 100644 --- a/llvm/extra.cpp +++ b/llvm/extra.cpp @@ -193,7 +193,8 @@ LLVMValueRef LLVMBuildAtomicRMW(LLVMBuilderRef builder, const char * opname, } LLVMValueRef LLVMBuildAtomicLoad(LLVMBuilderRef builder, LLVMValueRef ptr, - const char* ordering, int crossthread) + unsigned align, const char* ordering, + int crossthread) { using namespace llvm; AtomicOrdering atomic_order = atomic_ordering_from_string(ordering); @@ -202,13 +203,15 @@ LLVMValueRef LLVMBuildAtomicLoad(LLVMBuilderRef builder, LLVMValueRef ptr, LoadInst * inst = unwrap(builder)->CreateLoad(unwrap(ptr)); inst->setAtomic(atomic_order, sync_scope); + inst->setAlignment(align); return wrap(inst); } LLVMValueRef LLVMBuildAtomicStore(LLVMBuilderRef builder, LLVMValueRef ptr, LLVMValueRef val, - const char* ordering, int crossthread) + unsigned align, const char* ordering, + int crossthread) { using namespace llvm; AtomicOrdering atomic_order = atomic_ordering_from_string(ordering); @@ -217,6 +220,7 @@ LLVMValueRef LLVMBuildAtomicStore(LLVMBuilderRef builder, StoreInst * inst = unwrap(builder)->CreateStore(unwrap(val), unwrap(ptr)); inst->setAtomic(atomic_order, sync_scope); + inst->setAlignment(align); return wrap(inst); } diff --git a/llvm/extra.h b/llvm/extra.h index 9bd0ddb..b13c80f 100644 --- a/llvm/extra.h +++ b/llvm/extra.h @@ -56,13 +56,15 @@ LLVMValueRef LLVMBuildFence(LLVMBuilderRef builder, const char* ordering, * Wraps IRBuilder::CreateLoad, LoadInst::setAtomic */ LLVMValueRef LLVMBuildAtomicLoad(LLVMBuilderRef builder, LLVMValueRef ptr, - const char* ordering, int crossthread); + unsigned align, const char* ordering, + int crossthread); /* * Wraps IRBuilder::CreateStore, StoreInst::setAtomic */ LLVMValueRef LLVMBuildAtomicStore(LLVMBuilderRef builder, LLVMValueRef ptr, LLVMValueRef val, - const char* ordering, int crossthread); + unsigned align, const char* ordering, + int crossthread); /* * Wraps IRBuilder::CreateAtomicRMW diff --git a/llvm/wrap.h b/llvm/wrap.h index 9cebd74..bceca87 100644 --- a/llvm/wrap.h +++ b/llvm/wrap.h @@ -695,6 +695,31 @@ _w ## func (PyObject *self, PyObject *args) \ } + +/** + * Wrap LLVM functions of the type + * outtype func(intype1 arg1, intype2 arg2, arg3, const char *arg4, arg5) + */ +#define _wrap_objobjintstrint2obj(func, intype1, intype2, outtype)\ +static PyObject * \ +_w ## func (PyObject *self, PyObject *args) \ +{ \ + PyObject *obj1, *obj2; \ + intype1 arg1; \ + intype2 arg2; \ + int arg3; \ + const char *arg4; \ + int arg5; \ + \ + if (!PyArg_ParseTuple(args, "OOisi", &obj1, &obj2, &arg3, &arg4, &arg5)) \ + return NULL; \ + \ + arg1 = ( intype1 ) PyCapsule_GetPointer(obj1, NULL); \ + arg2 = ( intype2 ) PyCapsule_GetPointer(obj2, NULL); \ + \ + return ctor_ ## outtype ( func (arg1, arg2, arg3, arg4, arg5)); \ +} + /** * Wrap LLVM functions of the type * outtype func(intype1 arg1, const char *arg2, arg3) @@ -743,6 +768,34 @@ _w ## func (PyObject *self, PyObject *args) \ } + + +/** + * Wrap LLVM functions of the type + * outtype func(intype1 arg1, intype2 arg2, intype3, arg4, const char *arg5, arg6) + */ +#define _wrap_objobjobjintstrint2obj(func, intype1, intype2, intype3, outtype)\ +static PyObject * \ +_w ## func (PyObject *self, PyObject *args) \ +{ \ + PyObject *obj1, *obj2, *obj3; \ + intype1 arg1; \ + intype2 arg2; \ + intype3 arg3; \ + int arg4; \ + const char *arg5; \ + int arg6; \ + \ + if (!PyArg_ParseTuple(args, "OOOisi", &obj1, &obj2, &obj3, &arg4, &arg5, &arg6)) \ + return NULL; \ + \ + arg1 = ( intype1 ) PyCapsule_GetPointer(obj1, NULL); \ + arg2 = ( intype2 ) PyCapsule_GetPointer(obj2, NULL); \ + arg3 = ( intype3 ) PyCapsule_GetPointer(obj3, NULL); \ + \ + return ctor_ ## outtype ( func (arg1, arg2, arg3, arg4, arg5, arg6)); \ +} + /** * Wrap LLVM functions of the type * outtype func(intype1 arg1, intype2 arg2, intype3 arg3, intype4, const char *arg5, arg6) @@ -770,6 +823,7 @@ _w ## func (PyObject *self, PyObject *args) \ return ctor_ ## outtype ( func (arg1, arg2, arg3, arg4, arg5, arg6)); \ } + /** * Wrap LLVM functions of the type * outtype func(intype1 arg1, const char* arg2, intype3 arg3, intype4, const char *arg5, arg6) diff --git a/test/atomic.py b/test/atomic.py index dc4896d..fd565cc 100644 --- a/test/atomic.py +++ b/test/atomic.py @@ -89,16 +89,19 @@ class TestAtomic(unittest.TestCase): for ordering in test_these_orderings: loaded = bldr.atomic_load(ptr, ordering) self.assertIn('load atomic', str(loaded)) - self.assertEqual(ordering, str(loaded).strip().split(' ')[-1]) + self.assertEqual(ordering, + str(loaded).strip().split(' ')[-3].rstrip(',')) + self.assertIn('align 1', str(loaded)) stored = bldr.atomic_store(loaded, ptr, ordering) self.assertIn('store atomic', str(stored)) - self.assertEqual(ordering, str(stored).strip().split(' ')[-1]) + self.assertEqual(ordering, + str(stored).strip().split(' ')[-3].rstrip(',')) + self.assertIn('align 1', str(stored)) fenced = bldr.fence(ordering) self.assertEqual(['fence', ordering], str(fenced).strip().split(' ')) - if __name__ == '__main__': unittest.main() From 8381b25f6629572755ec3add65f7f4dbc06d26bd Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Fri, 3 Aug 2012 16:26:46 -0700 Subject: [PATCH 032/675] Add atomic ops --- TODO | 2 - llvm_cbuilder/builder.py | 108 ++++++++++++++++++++++++++++++++- llvm_cbuilder/executor.py | 2 +- tests/test_atomic_add.py | 115 +++++++++++++++++++++++++++++++++++ tests/test_atomic_ldst.py | 122 ++++++++++++++++++++++++++++++++++++++ tests/test_isprime.py | 5 ++ tests/test_pthread.py | 17 +++++- 7 files changed, 362 insertions(+), 9 deletions(-) delete mode 100644 TODO create mode 100644 tests/test_atomic_add.py create mode 100644 tests/test_atomic_ldst.py diff --git a/TODO b/TODO deleted file mode 100644 index 9a0e689..0000000 --- a/TODO +++ /dev/null @@ -1,2 +0,0 @@ -* add atomic operation to llvm-py -* add volatile load/store to llvm-py diff --git a/llvm_cbuilder/builder.py b/llvm_cbuilder/builder.py index ee866df..ce96222 100644 --- a/llvm_cbuilder/builder.py +++ b/llvm_cbuilder/builder.py @@ -4,6 +4,7 @@ import contextlib import llvm.core as lc +import llvm.ee as le def _is_int(ty): @@ -115,6 +116,7 @@ class CBuilder(object): self.declare_block = self.function.append_basic_block('decl') self.first_body_block = self.function.append_basic_block('body') self.builder = lc.Builder.new(self.first_body_block) + self.target_data = le.TargetData.new(self.function.module.data_layout) # prepare arguments self.args = [] @@ -210,6 +212,81 @@ class CBuilder(object): ''' return _is_block_terminated(self.builder.basic_block) + def atomic_cmpxchg(self, ptr, old, val, ordering, crossthread=True): + res = self.builder.atomic_cmpxchg(ptr.value, old.value, val.value, + ordering, crossthread) + return CTemp(self, res) + + def atomic_xchg(self, ptr, val, ordering, crossthread=True): + res = self.builder.atomic_xchg(ptr.value, val.value, + ordering, crossthread) + return CTemp(self, res) + + def atomic_add(self, ptr, val, ordering, crossthread=True): + res = self.builder.atomic_add(ptr.value, val.value, + ordering, crossthread) + return CTemp(self, res) + + def atomic_sub(self, ptr, val, ordering, crossthread=True): + res = self.builder.atomic_sub(ptr.value, val.value, + ordering, crossthread) + return CTemp(self, res) + + def atomic_and(self, ptr, val, ordering, crossthread=True): + res = self.builder.atomic_and(ptr.value, val.value, + ordering, crossthread) + return CTemp(self, res) + + def atomic_nand(self, ptr, val, ordering, crossthread=True): + res = self.builder.atomic_nand(ptr.value, val.value, + ordering, crossthread) + return CTemp(self, res) + + def atomic_or(self, ptr, val, ordering, crossthread=True): + res = self.builder.atomic_or(ptr.value, val.value, + ordering, crossthread) + return CTemp(self, res) + + def atomic_xor(self, ptr, val, ordering, crossthread=True): + res = self.builder.atomic_xor(ptr.value, val.value, + ordering, crossthread) + return CTemp(self, res) + + def atomic_max(self, ptr, val, ordering, crossthread=True): + res = self.builder.atomic_max(ptr.value, val.value, + ordering, crossthread) + return CTemp(self, res) + + def atomic_min(self, ptr, val, ordering, crossthread=True): + res = self.builder.atomic_min(ptr.value, val.value, + ordering, crossthread) + return CTemp(self, res) + + def atomic_umax(self, ptr, val, ordering, crossthread=True): + res = self.builder.atomic_umax(ptr.value, val.value, + ordering, crossthread) + return CTemp(self, res) + + def atomic_umin(self, ptr, val, ordering, crossthread=True): + res = self.builder.atomic_umin(ptr.value, val.value, + ordering, crossthread) + return CTemp(self, res) + + def atomic_load(self, ptr, ordering, align=1, crossthread=True): + res = self.builder.atomic_load(ptr.value, ordering, align, crossthread) + return CTemp(self, res) + + def atomic_store(self, val, ptr, ordering, align=1, crossthread=True): + res = self.builder.atomic_store(val.value, ptr.value, ordering, + align, crossthread) + return CTemp(self, res) + + def fence(self, ordering, crossthread=True): + res = self.builder.fence(ordering, crossthread) + return CTemp(self, res) + + def alignment(self, ty): + return self.target_data.abi_alignment(ty) class CValue(object): ''' @@ -419,7 +496,7 @@ class CFunc(CValue): self.function = func def __call__(self, *args): - arg_value = map(lambda x: x.value, args) + arg_value = list(map(lambda x: x.value, args)) res = self.parent.builder.call(self.function, arg_value) return CTemp(self.parent, res) @@ -441,6 +518,7 @@ class CTemp(CValue): return self.value.type class CVar(CValue): + def __init__(self, parent, ptr): super(CVar, self).__init__(parent) self.ptr = ptr @@ -478,15 +556,39 @@ class CVar(CValue): def type(self): return self.ptr.type.pointee - def load(self): + def load(self, volatile=False): self._ensure_is_pointer() - loaded = self.parent.builder.load(self.value) + loaded = self.parent.builder.load(self.value, volatile=volatile) return CTemp(self.parent, loaded) def store(self, val): self._ensure_is_pointer() self.parent.builder.store(val.value, self.value) + def atomic_load(self, ordering, align=None, crossthread=True, volatile=False): + self._ensure_is_pointer() + if align is None: + align = self.parent.alignment(self.type.pointee) + inst = self.parent.builder.atomic_load(self.value, ordering, align, + crossthread=crossthread, + volatile=volatile) + return CTemp(self.parent, inst) + + def atomic_store(self, value, ordering, align=None, crossthread=True, + volatile=False): + self._ensure_is_pointer() + if align is None: + align = self.parent.alignment(self.type.pointee) + self.parent.builder.atomic_store(value.value, self.value, ordering, + align=align, crossthread=crossthread) + + def atomic_cmpxchg(self, old, new, ordering, crossthread=True, volatile=False): + self._ensure_is_pointer() + inst = self.parent.builder.atomic_cmpxchg(self.value, old.value, + new.value, ordering, + crossthread=crossthread) + return CTemp(self.parent, inst) + def reference(self): return CTemp(self.parent, self.ptr) diff --git a/llvm_cbuilder/executor.py b/llvm_cbuilder/executor.py index e5aa1c0..03324e8 100644 --- a/llvm_cbuilder/executor.py +++ b/llvm_cbuilder/executor.py @@ -31,7 +31,7 @@ MAP_CTYPES = { class CExecutor(object): def __init__(self, mod_or_engine): if isinstance(mod_or_engine, Module): - self.engine = le.ExecutionEngine.new(mod_or_engine) + self.engine = le.EngineBuilder.new(mod_or_engine).create() else: self.engine = mod_or_engine diff --git a/tests/test_atomic_add.py b/tests/test_atomic_add.py new file mode 100644 index 0000000..eb63a44 --- /dev/null +++ b/tests/test_atomic_add.py @@ -0,0 +1,115 @@ +''' +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 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') + + 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_ldst.py b/tests/test_atomic_ldst.py new file mode 100644 index 0000000..147ec59 --- /dev/null +++ b/tests/test_atomic_ldst.py @@ -0,0 +1,122 @@ +''' +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 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') + + 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_isprime.py b/tests/test_isprime.py index 5c6b78e..c36c71b 100644 --- a/tests/test_isprime.py +++ b/tests/test_isprime.py @@ -73,8 +73,12 @@ def gen_is_prime_fast(mod): 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 ) @@ -86,6 +90,7 @@ def gen_is_prime_fast(mod): # increment idx += two + cb.ret(true) cb.close() return func diff --git a/tests/test_pthread.py b/tests/test_pthread.py index e86dbdb..d5212b0 100644 --- a/tests/test_pthread.py +++ b/tests/test_pthread.py @@ -39,12 +39,12 @@ def gen_test_pthread(mod): 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)) - worker_func(arg.reference()) - cb.ret(arg) cb.close() return cb.function @@ -72,7 +72,18 @@ class TestPThread(unittest.TestCase): func = exe.get_ctype_function(lf_test_pthread, 'int, int') inarg = 1234 - self.assertEqual(func(inarg), inarg+NUM_OF_THREAD+1) + 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() From aebb9857ebf2781ff4f59d6740aa5383ccbe53c5 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Fri, 3 Aug 2012 16:31:23 -0700 Subject: [PATCH 033/675] Drop volatile option in atomic ops. Add volatile option to store. --- llvm_cbuilder/builder.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/llvm_cbuilder/builder.py b/llvm_cbuilder/builder.py index ce96222..5bc31d1 100644 --- a/llvm_cbuilder/builder.py +++ b/llvm_cbuilder/builder.py @@ -561,28 +561,26 @@ class CVar(CValue): loaded = self.parent.builder.load(self.value, volatile=volatile) return CTemp(self.parent, loaded) - def store(self, val): + def store(self, val, volatile=False): self._ensure_is_pointer() - self.parent.builder.store(val.value, self.value) + self.parent.builder.store(val.value, self.value, volatile=volatile) - def atomic_load(self, ordering, align=None, crossthread=True, volatile=False): + def atomic_load(self, ordering, align=None, crossthread=True): self._ensure_is_pointer() if align is None: align = self.parent.alignment(self.type.pointee) inst = self.parent.builder.atomic_load(self.value, ordering, align, - crossthread=crossthread, - volatile=volatile) + crossthread=crossthread) return CTemp(self.parent, inst) - def atomic_store(self, value, ordering, align=None, crossthread=True, - volatile=False): + def atomic_store(self, value, ordering, align=None, crossthread=True): self._ensure_is_pointer() if align is None: align = self.parent.alignment(self.type.pointee) self.parent.builder.atomic_store(value.value, self.value, ordering, align=align, crossthread=crossthread) - def atomic_cmpxchg(self, old, new, ordering, crossthread=True, volatile=False): + def atomic_cmpxchg(self, old, new, ordering, crossthread=True): self._ensure_is_pointer() inst = self.parent.builder.atomic_cmpxchg(self.value, old.value, new.value, ordering, From f1e10e849f63210b491d1be4b0c548f00330182c Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Fri, 3 Aug 2012 17:02:01 -0700 Subject: [PATCH 034/675] Fix __div__ for py3. Add test for nested-loops. --- llvm_cbuilder/builder.py | 3 + tests/test_atomic_add.py | 4 +- ..._atomic_ldst.py => test_atomic_cmpxchg.py} | 4 +- tests/test_nestedloops.py | 128 ++++++++++++++++++ 4 files changed, 135 insertions(+), 4 deletions(-) rename tests/{test_atomic_ldst.py => test_atomic_cmpxchg.py} (97%) create mode 100644 tests/test_nestedloops.py diff --git a/llvm_cbuilder/builder.py b/llvm_cbuilder/builder.py index 5bc31d1..0582a25 100644 --- a/llvm_cbuilder/builder.py +++ b/llvm_cbuilder/builder.py @@ -379,6 +379,9 @@ class CValue(object): def __div__(self, rhs): return self._use_binop('div')(rhs) + def __truediv__(self, rhs): + return self.__div__(rhs) + def __mod__(self, rhs): return self._use_binop('mod')(rhs) diff --git a/tests/test_atomic_add.py b/tests/test_atomic_add.py index eb63a44..63b795a 100644 --- a/tests/test_atomic_add.py +++ b/tests/test_atomic_add.py @@ -65,8 +65,8 @@ def gen_test_pthread(mod): cb.close() return cb.function -class TestPThread(unittest.TestCase): - def test_pthread(self): +class TestAtomicAdd(unittest.TestCase): + def test_atomic_add(self): mod = Module.new(__name__) # add pthread functions diff --git a/tests/test_atomic_ldst.py b/tests/test_atomic_cmpxchg.py similarity index 97% rename from tests/test_atomic_ldst.py rename to tests/test_atomic_cmpxchg.py index 147ec59..eb2a45b 100644 --- a/tests/test_atomic_ldst.py +++ b/tests/test_atomic_cmpxchg.py @@ -70,8 +70,8 @@ def gen_test_pthread(mod): cb.close() return cb.function -class TestPThread(unittest.TestCase): - def test_pthread(self): +class TestAtomicCmpXchg(unittest.TestCase): + def test_atomic_cmpxchg(self): mod = Module.new(__name__) # add pthread functions diff --git a/tests/test_nestedloops.py b/tests/test_nestedloops.py new file mode 100644 index 0000000..823a54f --- /dev/null +++ b/tests/test_nestedloops.py @@ -0,0 +1,128 @@ +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, '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(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() + From 184e4ea1a119b1e29b6fa3764ce75a2fc377867e Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Fri, 3 Aug 2012 22:30:54 -0700 Subject: [PATCH 035/675] Add API for structure --- llvm_cbuilder/__init__.py | 3 ++- llvm_cbuilder/builder.py | 36 ++++++++++++++++++++++--- llvm_cbuilder/executor.py | 18 ++++++++----- llvm_cbuilder/shortnames.py | 12 +++++++++ tests/test_struct.py | 52 +++++++++++++++++++++++++++++++++++++ 5 files changed, 109 insertions(+), 12 deletions(-) create mode 100644 tests/test_struct.py diff --git a/llvm_cbuilder/__init__.py b/llvm_cbuilder/__init__.py index e623129..b32e754 100644 --- a/llvm_cbuilder/__init__.py +++ b/llvm_cbuilder/__init__.py @@ -1,2 +1,3 @@ -from .builder import CBuilder +from .builder import * from .executor import CExecutor + diff --git a/llvm_cbuilder/builder.py b/llvm_cbuilder/builder.py index 0582a25..7dc338b 100644 --- a/llvm_cbuilder/builder.py +++ b/llvm_cbuilder/builder.py @@ -25,6 +25,12 @@ def _is_block_terminated(bb): instrs = bb.instructions return len(instrs) > 0 and instrs[-1].is_terminator +def _is_cstruct(ty): + try: + return issubclass(ty, CStruct) + except TypeError: + return False + @contextlib.contextmanager def _change_block_temporarily(builder, bb): origbb = builder.basic_block @@ -135,11 +141,21 @@ class CBuilder(object): Only allocate in the first block ''' with _change_block_temporarily(self.builder, self.declare_block): + is_cstruct = _is_cstruct(ty) + if is_cstruct: + cstruct = ty + ty = ty.llvm_type() ptr = self.builder.alloca(ty, name=name) - if value is not None: - if not isinstance(value, lc.Value): - value = self.constant(ty, value).value - self.builder.store(value, ptr) + # back to the body + if value is not None: + if isinstance(value, CValue): + value = value.value + if not isinstance(value, lc.Value): + value = self.constant(ty, value).value + self.builder.store(value, ptr) + if is_cstruct: + return cstruct(self, ptr) + else: return CVar(self, ptr) def array(self, ty, count, name=''): @@ -616,3 +632,15 @@ class CArray(CValue): ptr = builder.gep(self.value, [idx]) return CVar(self.parent, ptr) +class CStruct(CValue): + @classmethod + def llvm_type(cls): + return lc.Type.struct([v for k, v in cls._fields_]) + + def __init__(self, parent, ptr): + super(CStruct, self).__init__(parent) + makeind = lambda x: self.parent.constant(lc.Type.int(), x).value + for i, (fd, _) in enumerate(self._fields_): + gep = self.parent.builder.gep(ptr, [makeind(0), makeind(i)]) + setattr(self, fd, CVar(self.parent, gep)) + diff --git a/llvm_cbuilder/executor.py b/llvm_cbuilder/executor.py index 03324e8..a2f558e 100644 --- a/llvm_cbuilder/executor.py +++ b/llvm_cbuilder/executor.py @@ -35,14 +35,18 @@ class CExecutor(object): else: self.engine = mod_or_engine - def get_ctype_function(self, fn, typeinfo): - types = [ MAP_CTYPES[s.strip()] for s in typeinfo.split(',') ] - if not types: - retty = None - argtys = [] + def get_ctype_function(self, fn, *typeinfo): + if len(typeinfo)==1 and isinstance(typeinfo[0], str): + types = [ MAP_CTYPES[s.strip()] for s in typeinfo[0].split(',') ] + if not types: + retty = None + argtys = [] + else: + retty = types[0] + argtys = types[1:] else: - retty = types[0] - argtys = types[1:] + retty = typeinfo[0] + argtys = typeinfo[1:] prototype = ct.CFUNCTYPE(retty, *argtys) fnptr = self.engine.get_pointer_to_function(fn) diff --git a/llvm_cbuilder/shortnames.py b/llvm_cbuilder/shortnames.py index c0e65ca..d3fc5af 100644 --- a/llvm_cbuilder/shortnames.py +++ b/llvm_cbuilder/shortnames.py @@ -7,6 +7,7 @@ int = Type.int(32) int16 = short int32 = int int64 = Type.int(64) + float = Type.float() double = Type.double() @@ -15,3 +16,14 @@ double = Type.double() pointer = Type.pointer void_p = pointer(char) + +# platform dependent + +def _determine_pointer_size(): + from ctypes import sizeof, c_void_p + return sizeof(c_void_p) * 8 + +pointer_size = _determine_pointer_size() + +intp = {32: int32, 64: int64}[pointer_size] + diff --git a/tests/test_struct.py b/tests/test_struct.py new file mode 100644 index 0000000..35048e6 --- /dev/null +++ b/tests/test_struct.py @@ -0,0 +1,52 @@ +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() From b45c768cc5af27cce538d6a25baa92240a848835 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Sat, 4 Aug 2012 15:14:09 -0700 Subject: [PATCH 036/675] Fix --- llvm_cbuilder/builder.py | 41 +++++++++++++++++++++++++++++++--------- 1 file changed, 32 insertions(+), 9 deletions(-) diff --git a/llvm_cbuilder/builder.py b/llvm_cbuilder/builder.py index 7dc338b..cb33214 100644 --- a/llvm_cbuilder/builder.py +++ b/llvm_cbuilder/builder.py @@ -103,10 +103,10 @@ class _Loop(object): builder.branch(self._bbcond) def break_loop(self): - self.branch(self._bbend) + self.parent.builder.branch(self._bbend) def continue_loop(self): - self.branch(self._bbcond) + self.parent.builder.branch(self._bbcond) def close(self): self.parent.builder.position_at_end(self._bbend) @@ -542,27 +542,50 @@ class CVar(CValue): super(CVar, self).__init__(parent) self.ptr = ptr - def _inplace_op(self, op): + def _inplace_binop(self, op): def wrapped(rhs): - res = self._use_binop('add')(rhs) + res = self._use_binop(op)(rhs) self.assign(res) return self return wrapped def __iadd__(self, rhs): - return self._inplace_op('add')(rhs) + return self._inplace_binop('add')(rhs) def __isub__(self, rhs): - return self._inplace_op('sub')(rhs) + return self._inplace_binop('sub')(rhs) def __imul__(self, rhs): - return self._inplace_op('mul')(rhs) + return self._inplace_binop('mul')(rhs) def __idiv__(self, rhs): - return self._inplace_op('div')(rhs) + return self._inplace_binop('div')(rhs) def __imod__(self, rhs): - return self._inplace_op('mod')(rhs) + return self._inplace_binop('mod')(rhs) + + + def _inplace_bitwise(self, op): + def wrapped(rhs): + res = self._use_bitwise(op)(rhs) + self.assign(res) + return self + return wrapped + + def __ilshift__(self, rhs): + return self._inplace_bitwise('lshift')(rhs) + + def __irshift__(self, rhs): + return self._inplace_bitwise('rshift')(rhs) + + def __iand__(self, rhs): + return self._inplace_bitwise('and')(rhs) + + def __ior__(self, rhs): + return self._inplace_bitwise('or')(rhs) + + def __ixor__(self, rhs): + return self._inplace_bitwise('xor')(rhs) @property def value(self): From 673ada6a4ea36a8a61a4b8ce0e9739a5716c2b2a Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Sat, 4 Aug 2012 15:18:41 -0700 Subject: [PATCH 037/675] Fix and add tests. --- tests/test_isprime.py | 2 +- tests/test_loopcontrol.py | 135 ++++++++++++++++++++++++++++++++++++++ tests/test_nestedloops.py | 2 +- 3 files changed, 137 insertions(+), 2 deletions(-) create mode 100644 tests/test_loopcontrol.py diff --git a/tests/test_isprime.py b/tests/test_isprime.py index c36c71b..bcc0b9c 100644 --- a/tests/test_isprime.py +++ b/tests/test_isprime.py @@ -54,7 +54,7 @@ def gen_is_prime(mod): def gen_is_prime_fast(mod): functype = Type.function(C.int, [C.int]) - func = mod.add_function(functype, 'isprime') + func = mod.add_function(functype, 'isprime_fast') cb = CBuilder(func) diff --git a/tests/test_loopcontrol.py b/tests/test_loopcontrol.py new file mode 100644 index 0000000..7e252bf --- /dev/null +++ b/tests/test_loopcontrol.py @@ -0,0 +1,135 @@ +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 index 823a54f..0876bb2 100644 --- a/tests/test_nestedloops.py +++ b/tests/test_nestedloops.py @@ -61,7 +61,7 @@ def nestedloop2(d): def gen_nestedloop2(mod): functype = Type.function(C.int, [C.int]) - func = mod.add_function(functype, 'nestedloop1') + func = mod.add_function(functype, 'nestedloop2') cb = CBuilder(func) From 0654e00ab157ecc964c59fbadb22f4d1244d3fe0 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Sat, 4 Aug 2012 19:13:35 -0700 Subject: [PATCH 038/675] Add printf() and friends. Disable logging in old tests. --- llvm_cbuilder/builder.py | 46 ++++++++++++++++++++++++--- tests/test_atomic_add.py | 2 +- tests/test_atomic_cmpxchg.py | 2 +- tests/test_print.py | 60 ++++++++++++++++++++++++++++++++++++ tests/test_pthread.py | 2 +- 5 files changed, 105 insertions(+), 7 deletions(-) create mode 100644 tests/test_print.py diff --git a/llvm_cbuilder/builder.py b/llvm_cbuilder/builder.py index cb33214..16f6daf 100644 --- a/llvm_cbuilder/builder.py +++ b/llvm_cbuilder/builder.py @@ -6,7 +6,6 @@ import contextlib import llvm.core as lc import llvm.ee as le - def _is_int(ty): return isinstance(ty, lc.IntegerType) @@ -31,6 +30,9 @@ def _is_cstruct(ty): except TypeError: return False +def _list_values(iterable): + return [i.value for i in iterable] + @contextlib.contextmanager def _change_block_temporarily(builder, bb): origbb = builder.basic_block @@ -111,7 +113,6 @@ class _Loop(object): def close(self): self.parent.builder.position_at_end(self._bbend) - class CBuilder(object): ''' A wrapper class for features in llvm-py package @@ -136,6 +137,32 @@ class CBuilder(object): func = mod.add_function(functype, name=name) return CBuilder(func) + def printf(self, fmt, *args): + mod = self.function.module + int_t = lc.Type.int() + char_ptr_t = lc.Type.pointer(lc.Type.int(8)) + functype = lc.Type.function(int_t, [char_ptr_t], True) + printf = mod.get_or_insert_function(functype, name='printf') + ret = self.builder.call(printf, [fmt.value]+_list_values(args)) + return CTemp(self, ret) + + def debug(self, *args): + type_mapper = { + 'i32': '%d', + 'double': '%e', + } + itemsfmt = [] + items = [] + for i in args: + if isinstance(i, str): + itemsfmt.append(i.replace('%', '%%')) + else: + ty = type_mapper[str(i.type)] + itemsfmt.append(ty) + items.append(i) + fmt = ' '.join(itemsfmt) + '\n' + return self.printf(self.constant_string(fmt), *items) + def var(self, ty, value=None, name=''): ''' Only allocate in the first block @@ -150,7 +177,7 @@ class CBuilder(object): if value is not None: if isinstance(value, CValue): value = value.value - if not isinstance(value, lc.Value): + elif not isinstance(value, lc.Value): value = self.constant(ty, value).value self.builder.store(value, ptr) if is_cstruct: @@ -213,6 +240,16 @@ class CBuilder(object): res = lc.Constant.null(ty) return CTemp(self, res) + def constant_string(self, string): + mod = self.function.module + name = '.conststr.%x' % hash(string) + content = lc.Constant.stringz(string) + globalstr = mod.add_global_variable(content.type, name=name) + globalstr.initializer = content + ptr = mod.add_global_variable(lc.Type.pointer(content.type.element), + name=name+".ptr") + return CTemp(self, globalstr.bitcast(lc.Type.pointer(content.type.element))) + def get_intrinsic(self, intrinsic_id, tys): lfunc = lc.Function.intrinsic(self.function.module, intrinsic_id, tys) return CFunc(self, lfunc) @@ -515,7 +552,7 @@ class CFunc(CValue): self.function = func def __call__(self, *args): - arg_value = list(map(lambda x: x.value, args)) + arg_value = _list_values(args) res = self.parent.builder.call(self.function, arg_value) return CTemp(self.parent, res) @@ -667,3 +704,4 @@ class CStruct(CValue): gep = self.parent.builder.gep(ptr, [makeind(0), makeind(i)]) setattr(self, fd, CVar(self.parent, gep)) + diff --git a/tests/test_atomic_add.py b/tests/test_atomic_add.py index 63b795a..27688e7 100644 --- a/tests/test_atomic_add.py +++ b/tests/test_atomic_add.py @@ -9,7 +9,7 @@ from llvm_cbuilder import * import llvm_cbuilder.shortnames as C import unittest, logging -logging.basicConfig(level=logging.DEBUG) +# logging.basicConfig(level=logging.DEBUG) NUM_OF_THREAD = 4 REPEAT = 10000 diff --git a/tests/test_atomic_cmpxchg.py b/tests/test_atomic_cmpxchg.py index eb2a45b..27fb763 100644 --- a/tests/test_atomic_cmpxchg.py +++ b/tests/test_atomic_cmpxchg.py @@ -9,7 +9,7 @@ from llvm_cbuilder import * import llvm_cbuilder.shortnames as C import unittest, logging -logging.basicConfig(level=logging.DEBUG) +# logging.basicConfig(level=logging.DEBUG) NUM_OF_THREAD = 4 REPEAT = 10000 diff --git a/tests/test_print.py b/tests/test_print.py new file mode 100644 index 0000000..d971e31 --- /dev/null +++ b/tests/test_print.py @@ -0,0 +1,60 @@ +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 index d5212b0..d1d3a72 100644 --- a/tests/test_pthread.py +++ b/tests/test_pthread.py @@ -5,7 +5,7 @@ from llvm_cbuilder import * import llvm_cbuilder.shortnames as C import unittest, logging -logging.basicConfig(level=logging.DEBUG) +# logging.basicConfig(level=logging.DEBUG) NUM_OF_THREAD = 4 From 891daa1164d0941a71ebc1629c59429c091579ac Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Sun, 5 Aug 2012 21:35:02 -0700 Subject: [PATCH 039/675] Added test implementation of parallel-vectorize (incomplete). Various fix. --- llvm_cbuilder/builder.py | 213 ++++++++++++++++++------ llvm_cbuilder/executor.py | 2 +- llvm_cbuilder/shortnames.py | 1 + parallel_vectorize.py | 318 ++++++++++++++++++++++++++++++++++++ test_parallel_vectorize.py | 73 +++++++++ 5 files changed, 555 insertions(+), 52 deletions(-) create mode 100644 parallel_vectorize.py create mode 100644 test_parallel_vectorize.py diff --git a/llvm_cbuilder/builder.py b/llvm_cbuilder/builder.py index 16f6daf..ee308d6 100644 --- a/llvm_cbuilder/builder.py +++ b/llvm_cbuilder/builder.py @@ -40,6 +40,10 @@ def _change_block_temporarily(builder, bb): yield builder.position_at_end(origbb) +@contextlib.contextmanager +def _change_block_temporarily_dummy(*args): + yield + class _IfElse(object): def __init__(self, parent, cond): self.parent = parent @@ -58,14 +62,17 @@ class _IfElse(object): yield - self._to_close.extend([self._bbif, self._bbelse]) + self._to_close.extend([self._bbif, self._bbelse, builder.basic_block]) @contextlib.contextmanager def otherwise(self): - self.parent.builder.position_at_end(self._bbelse) + builder = self.parent.builder + builder.position_at_end(self._bbelse) yield + self._to_close.append(builder.basic_block) def close(self): + self._to_close.append(self.parent.builder.basic_block) bbend = self.parent.function.append_basic_block('if.end') builder = self.parent.builder for bb in self._to_close: @@ -111,7 +118,11 @@ class _Loop(object): self.parent.builder.branch(self._bbcond) def close(self): - self.parent.builder.position_at_end(self._bbend) + builder = self.parent.builder +# if not _is_block_terminated(builder.basic_block): +# with _change_block_temporarily(builder, builder.basic_block): +# builder.branch(self._bbend) + builder.position_at_end(self._bbend) class CBuilder(object): ''' @@ -148,7 +159,10 @@ class CBuilder(object): def debug(self, *args): type_mapper = { + 'i8' : '%c', + 'i16': '%hd', 'i32': '%d', + 'i64': '%ld', 'double': '%e', } itemsfmt = [] @@ -185,9 +199,23 @@ class CBuilder(object): else: return CVar(self, ptr) + def var_copy(self, val, name=''): + return self.var(val.type, val, name=name) + def array(self, ty, count, name=''): - with _change_block_temporarily(self.builder, self.declare_block): - if not isinstance(count, lc.Value): + if isinstance(count, int) or isinstance(count, lc.Constant): + contexthelper = _change_block_temporarily + else: + contexthelper = _change_block_temporarily_dummy + + with contexthelper(self.builder, self.declare_block): + is_cstruct = _is_cstruct(ty) + if is_cstruct: + cstruct = ty + ty = ty.llvm_type() + if isinstance(count, CValue): + count = count.value + elif not isinstance(count, lc.Value): count = self.constant(lc.Type.int(), count).value ptr = self.builder.alloca_array(ty, count, name=name) return CArray(self, ptr) @@ -341,6 +369,40 @@ class CBuilder(object): def alignment(self, ty): return self.target_data.abi_alignment(ty) + def unreachable(self): + self.builder.unreachable() + +class CDefinition(CBuilder): + ''' + Inherit this class to for defining functions + ''' + _name_ = 'unamed' # name of the function; should overide in subclass + _retty_ = lc.Type.void() # return type; can overide in subclass + _argtys_ = [] # a list of tuple(name, type); can overide in subclass + + @classmethod + def define(cls, module, **kws): + functype = lc.Type.function(cls._retty_, [v for k, v in cls._argtys_]) + func = module.get_or_insert_function(functype, name=cls._name_) + if not func.is_declaration: # already defined? + raise NameError('Function %s has already been defined' % cls.name) + + # Name all arguments + for i, (name, _) in enumerate(cls._argtys_): + func.args[i].name = name + + # Create builder and populate body + cbuilder = cls(func) + cbuilder.body(*cbuilder.args, **kws) + cbuilder.close() + return func + + def body(self): + ''' + Overide this function to define the body. + ''' + raise NotImplementedError + class CValue(object): ''' = Signess = @@ -475,13 +537,13 @@ class CValue(object): return make(builder.bitcast(self.value, ty)) elif self.is_int: if _is_int(ty): - if self.type.width > ty.width: + if self.type.width < ty.width: if not unsigned: return make(self.parent.builder.sext(self.value, ty)) else: return make(self.parent.builder.zext(self.value, ty)) else: - return make(self.parent.trunc(self.value, ty)) + return make(self.parent.builder.trunc(self.value, ty)) elif _is_real(ty): if not unsigned: return make(self.parent.builder.sitofp(self.value, ty)) @@ -543,7 +605,46 @@ class CValue(object): def _ensure_is_pointer(self): if not self.is_pointer: - raise TypeError("Must be a pointer") + raise TypeError("Must be a pointer; got %s" % self.type) + + def __getitem__(self, idx): + self._ensure_is_pointer() + if not isinstance(idx, CValue): + idx = self.parent.constant(lc.Type.int(), idx) + bldr = self.parent.builder + ptr = bldr.gep(self.value, [idx.value]) + return CVar(self.parent, ptr) + + def load(self, volatile=False): + self._ensure_is_pointer() + loaded = self.parent.builder.load(self.value, volatile=volatile) + return CTemp(self.parent, loaded) + + def store(self, val, volatile=False): + self._ensure_is_pointer() + self.parent.builder.store(val.value, self.value, volatile=volatile) + + def atomic_load(self, ordering, align=None, crossthread=True): + self._ensure_is_pointer() + if align is None: + align = self.parent.alignment(self.type.pointee) + inst = self.parent.builder.atomic_load(self.value, ordering, align, + crossthread=crossthread) + return CTemp(self.parent, inst) + + def atomic_store(self, value, ordering, align=None, crossthread=True): + self._ensure_is_pointer() + if align is None: + align = self.parent.alignment(self.type.pointee) + self.parent.builder.atomic_store(value.ptr, self.value, ordering, + align=align, crossthread=crossthread) + + def atomic_cmpxchg(self, old, new, ordering, crossthread=True): + self._ensure_is_pointer() + inst = self.parent.builder.atomic_cmpxchg(self.value, old.value, + new.value, ordering, + crossthread=crossthread) + return CTemp(self.parent, inst) class CFunc(CValue): @@ -552,8 +653,14 @@ class CFunc(CValue): self.function = func def __call__(self, *args): - arg_value = _list_values(args) - res = self.parent.builder.call(self.function, arg_value) + arg_values = _list_values(args) + ftype = self.function.type.pointee + for i, (exp, got) in enumerate(zip(ftype.args, arg_values)): + if exp != got.type: + raise TypeError("At call to %s, " + "argument %d mismatch: %s != %s" + % (self.function.name, i, exp, got.type)) + res = self.parent.builder.call(self.function, arg_values) return CTemp(self.parent, res) @property @@ -601,7 +708,6 @@ class CVar(CValue): def __imod__(self, rhs): return self._inplace_binop('mod')(rhs) - def _inplace_bitwise(self, op): def wrapped(rhs): res = self._use_bitwise(op)(rhs) @@ -629,46 +735,23 @@ class CVar(CValue): return self.parent.builder.load(self.ptr) def assign(self, val): + self._ensure_same_type(val) self.parent.builder.store(val.value, self.ptr) @property def type(self): return self.ptr.type.pointee - def load(self, volatile=False): - self._ensure_is_pointer() - loaded = self.parent.builder.load(self.value, volatile=volatile) - return CTemp(self.parent, loaded) - - def store(self, val, volatile=False): - self._ensure_is_pointer() - self.parent.builder.store(val.value, self.value, volatile=volatile) - - def atomic_load(self, ordering, align=None, crossthread=True): - self._ensure_is_pointer() - if align is None: - align = self.parent.alignment(self.type.pointee) - inst = self.parent.builder.atomic_load(self.value, ordering, align, - crossthread=crossthread) - return CTemp(self.parent, inst) - - def atomic_store(self, value, ordering, align=None, crossthread=True): - self._ensure_is_pointer() - if align is None: - align = self.parent.alignment(self.type.pointee) - self.parent.builder.atomic_store(value.value, self.value, ordering, - align=align, crossthread=crossthread) - - def atomic_cmpxchg(self, old, new, ordering, crossthread=True): - self._ensure_is_pointer() - inst = self.parent.builder.atomic_cmpxchg(self.value, old.value, - new.value, ordering, - crossthread=crossthread) - return CTemp(self.parent, inst) - def reference(self): return CTemp(self.parent, self.ptr) + def as_struct(self, cstruct_class, volatile=False): + if _is_pointer(self.type): + ptr = self.parent.builder.load(self.ptr, volatile=volatile) + return cstruct_class(self.parent, ptr) + else: + return cstruct_class(self.parent, self.ptr) + class CArray(CValue): def __init__(self, parent, base): super(CArray, self).__init__(parent) @@ -678,19 +761,23 @@ class CArray(CValue): def value(self): return self.base_ptr + def reference(self): + return CTemp(self.parent, self.base_ptr) + @property def type(self): return self.base_ptr.type - def __getitem__(self, idx): - self._ensure_is_pointer() - builder = self.parent.builder - if isinstance(idx, CValue): - idx = idx.value - elif not isinstance(idx, lc.Value): - idx = self.parent.constant(lc.Type.int(), idx).value - ptr = builder.gep(self.value, [idx]) - return CVar(self.parent, ptr) +## Moved to CValue +# def __getitem__(self, idx): +# self._ensure_is_pointer() +# builder = self.parent.builder +# if isinstance(idx, CValue): +# idx = idx.value +# elif not isinstance(idx, lc.Value): +# idx = self.parent.constant(lc.Type.int(), idx).value +# ptr = builder.gep(self.value, [idx]) +# return CVar(self.parent, ptr) class CStruct(CValue): @classmethod @@ -700,8 +787,32 @@ class CStruct(CValue): def __init__(self, parent, ptr): super(CStruct, self).__init__(parent) makeind = lambda x: self.parent.constant(lc.Type.int(), x).value + self.ptr = ptr for i, (fd, _) in enumerate(self._fields_): gep = self.parent.builder.gep(ptr, [makeind(0), makeind(i)]) + gep.name = "%s.%s" % (type(self).__name__, fd) setattr(self, fd, CVar(self.parent, gep)) + def reference(self): + return CTemp(self.parent, self.ptr) + +class CExternal(object): + def __init__(self, cbuilder): + is_func = lambda x: isinstance(x, lc.FunctionType) + non_magic = lambda s: not ( s.startswith('__') and s.endswith('__') ) + + to_declare = [] + for fname in filter(non_magic, vars(type(self))): + ftype = getattr(self, fname) + if is_func(ftype): + to_declare.append((fname, ftype)) + + mod = cbuilder.function.module + for fname, ftype in to_declare: + func = mod.get_or_insert_function(ftype, name=fname) + if func.type.pointee != ftype: + raise NameError("Function has already been declared " + "with a different type: %s != %s" + % (func.type, ftype) ) + setattr(self, fname, CFunc(cbuilder, func)) diff --git a/llvm_cbuilder/executor.py b/llvm_cbuilder/executor.py index a2f558e..bd7d78c 100644 --- a/llvm_cbuilder/executor.py +++ b/llvm_cbuilder/executor.py @@ -31,7 +31,7 @@ MAP_CTYPES = { class CExecutor(object): def __init__(self, mod_or_engine): if isinstance(mod_or_engine, Module): - self.engine = le.EngineBuilder.new(mod_or_engine).create() + self.engine = le.EngineBuilder.new(mod_or_engine).opt(3).create() else: self.engine = mod_or_engine diff --git a/llvm_cbuilder/shortnames.py b/llvm_cbuilder/shortnames.py index d3fc5af..beaaad3 100644 --- a/llvm_cbuilder/shortnames.py +++ b/llvm_cbuilder/shortnames.py @@ -16,6 +16,7 @@ double = Type.double() pointer = Type.pointer void_p = pointer(char) +char_p = pointer(char) # platform dependent diff --git a/parallel_vectorize.py b/parallel_vectorize.py new file mode 100644 index 0000000..1f83ad5 --- /dev/null +++ b/parallel_vectorize.py @@ -0,0 +1,318 @@ +from llvm.core import * +from llvm.passes import * + +from llvm_cbuilder import * +import llvm_cbuilder.shortnames as C + +class WorkQueue(CStruct): + _fields_ = [ + ('next', C.intp), + ('last', C.intp), + ('lock', C.int), + ] + + + def Lock(self): + with self.parent.loop() as loop: + with loop.condition() as setcond: + unlocked = self.parent.constant(self.lock.type, 0) + locked = self.parent.constant(self.lock.type, 1) + + res = self.lock.reference().atomic_cmpxchg(unlocked, locked, + ordering='acquire') + setcond( res != unlocked ) + + with loop.body(): + pass + + def Unlock(self): + unlocked = self.parent.constant(self.lock.type, 0) + locked = self.parent.constant(self.lock.type, 1) + + res = self.lock.reference().atomic_cmpxchg(locked, unlocked, + ordering='release') + + with self.parent.ifelse( res != locked ) as ifelse: + with ifelse.then(): + # This shall kill the program + self.parent.unreachable() + + +class ContextCommon(CStruct): + _fields_ = [ + # loop ufunc args + ('args', C.pointer(C.char_p)), + ('dimensions', C.pointer(C.intp)), + ('steps', C.pointer(C.intp)), + ('data', C.void_p), + # specifics for work queues + ('func', C.void_p), + ('num_thread', C.int), + ('workqueues', C.pointer(WorkQueue.llvm_type())), + ] + +class Context(CStruct): + _fields_ = [ + ('common', C.pointer(ContextCommon.llvm_type())), + ('id', C.int), + ('completed', C.intp), + ] + +class ParallelUFunc(CDefinition): + _name_ = 'parallel_ufunc' + _retty_ = C.void + _argtys_ = [ + ('func', C.void_p), + ('worker', C.void_p), + ('args', C.pointer(C.char_p)), + ('dimensions', C.pointer(C.intp)), + ('steps', C.pointer(C.intp)), + ('data', C.void_p), + ] + + def body(self, func, worker, args, dimensions, steps, data, ThreadCount=1): + + + common = self.var(ContextCommon, name='common') + workqueues = self.array(WorkQueue, ThreadCount, name='workqueues') + contexts = self.array(Context, ThreadCount, name='contexts') + + num_thread = self.var(C.int, ThreadCount, name='num_thread') + + common.args.assign(args) + common.dimensions.assign(dimensions) + common.steps.assign(steps) + common.data.assign(data) + common.func.assign(func) + common.num_thread.assign(num_thread.cast(C.int)) + common.workqueues.assign(workqueues.reference()) + + 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)) + + self._populate_workqueues(workqueues, N, ChunkSize, num_thread) + self._populate_context(contexts, common, num_thread) + + self._dispatch_worker(worker, contexts, num_thread) + + # Check for race condition + 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!") + with ifelse.otherwise(): + self.debug("ERROR: race occurred!") + + self.ret() + + def _populate_workqueues(self, workqueues, N, ChunkSize, num_thread): + i = self.var(num_thread.type, 0, name='i') + ONE = self.constant(i.type, 1) + with self.loop() as loop: + with loop.condition() as setcond: + setcond( i < num_thread ) + with loop.body(): + 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)) + # increment + i += ONE + # end loop + last_wq = workqueues[num_thread - ONE].as_struct(WorkQueue) + last_wq.last.assign(N) + + def _populate_context(self, contexts, common, num_thread): + i = self.var(num_thread.type, 0, name='i') + ONE = self.constant(i.type, 1) + with self.loop() as loop: + with loop.condition() as setcond: + setcond( i < num_thread ) + with loop.body(): + 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)) + # increment + i += ONE + + +class ParallelUFuncPosix(ParallelUFunc): + 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 + + i = self.var(num_thread.type, 0, name='i') + ONE = self.constant(i.type, 1) + with self.loop() as loop: + with loop.condition() as setcond: + setcond( i < num_thread ) + with loop.body(): + api.pthread_create(threads[i].reference(), NULL, worker, + contexts[i].reference().cast(C.void_p)) + i += ONE + + # self.debug("join threads") + i.assign(self.constant_null(i.type)) + with self.loop() as loop: + with loop.condition() as setcond: + setcond( i < num_thread ) + with loop.body(): + api.pthread_join(threads[i], NULL) + i += ONE + # self.debug("closing") + +class UFuncCore(CDefinition): + _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.loop() as loop: + with loop.condition() as setcond: + setcond(ZERO == ZERO) # loop forever + + with loop.body(): + 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) + + def _do_work_stealing(self, common, tid, completed): + ''' + Steal work from other workqueues + ''' + # self.debug("start work stealing", tid) + incomplete_thread_ct = self.var(C.int, 1) + ITC_NULL = self.constant_null(incomplete_thread_ct.type) + with self.loop() as loop: + with loop.condition() as setcond: + setcond( incomplete_thread_ct != ITC_NULL ) + + with loop.body(): + incomplete_thread_ct.assign(ITC_NULL) + self._do_work_stealing_innerloop(common, incomplete_thread_ct, + tid, completed) + + def _do_work_stealing_innerloop(self, common, incomplete_thread_ct, tid, + completed): + i = self.var(C.int, 0) + with self.loop() as loop: + with loop.condition() as setcond: + setcond( i < common.num_thread ) + + with loop.body(): + with self.ifelse( i != tid ) as ifelse: + with ifelse.then(): + otherqueue = common.workqueues[i].as_struct(WorkQueue) + self._do_work_stealing_check(common, otherqueue, + incomplete_thread_ct, tid, + completed) + + # increment + i += self.constant(i.type, 1) + + def _do_work_stealing_check(self, common, otherqueue, + incomplete_thread_ct, tid, completed): + otherqueue.Lock() + ONE = self.constant(otherqueue.last.type, 1) + ITC_ONE = self.constant(incomplete_thread_ct.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) + + # Mark incomplete thread + incomplete_thread_ct.assign(ITC_ONE) + + with ifelse.otherwise(): + otherqueue.Unlock() + + def _do_work(self, common, item, tid, completed): + # self.debug(" tid", tid, "item", item) + completed += self.constant(completed.type, 1) + + +class PThreadAPI(CExternal): + 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]) + + +def _main(): + NUM_THREAD = 2 + module = Module.new(__name__) + + fpm = FunctionPassManager.new(module) + PassManagerBuilder.new().populate(fpm) + + f1 = ParallelUFuncPosix.define(module, ThreadCount=NUM_THREAD) + f2 = UFuncCore.define(module) + #print(module) +# print(f1) + print(f2) + module.verify() + + fpm.run(f1) + fpm.run(f2) + print('optimized'.center(80,'-')) + print(f2) + +if __name__ == '__main__': + _main() + diff --git a/test_parallel_vectorize.py b/test_parallel_vectorize.py new file mode 100644 index 0000000..b3ffb5c --- /dev/null +++ b/test_parallel_vectorize.py @@ -0,0 +1,73 @@ +from parallel_vectorize import * + +''' +void parallel_ufunc(void * func, void * worker, + char **args, npy_intp *dimensions, + npy_intp *steps, void *data) +''' +class Tester(CDefinition): + _name_ = 'tester' + + def body(self): + # depends + module = self.function.module + + ThreadCount = 2 + ArgCount = 2 + WorkCount = 1000000 + + parallel_ufunc = CFunc(self, ParallelUFuncPosix.define(module, + ThreadCount=ThreadCount)) + worker = CFunc(self, UFuncCore.define(module)) + + # real work + NULL = self.constant_null(C.void_p) + + args = self.array(C.char_p, 2, name='args') + + for t in range(ThreadCount): + args_for_thread = self.array(C.double, 4) + args[t].assign(args_for_thread.cast(C.char_p)) + + 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)) + + parallel_ufunc(NULL, worker.cast(C.void_p), args, dims, steps, NULL) + + self.ret() + +def main(): + NUM_THREAD = 2 + 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 + exe = CExecutor(module) + exe.engine.get_pointer_to_function(fntester) + func = exe.get_ctype_function(fntester, 'void') + + func() + + +if __name__ == '__main__': + main() + From 1594e5456a887caa29e3f2f8628d5bcb27c47590 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Mon, 6 Aug 2012 11:35:03 -0700 Subject: [PATCH 040/675] Got test_parallel_vectorize working. --- llvm_cbuilder/builder.py | 56 +++++++- parallel_vectorize.py | 267 +++++++++++++++++++------------------ test_parallel_vectorize.py | 72 ++++++++-- 3 files changed, 253 insertions(+), 142 deletions(-) diff --git a/llvm_cbuilder/builder.py b/llvm_cbuilder/builder.py index ee308d6..eaa159e 100644 --- a/llvm_cbuilder/builder.py +++ b/llvm_cbuilder/builder.py @@ -5,6 +5,7 @@ import contextlib import llvm.core as lc import llvm.ee as le +from llvm import LLVMException def _is_int(ty): return isinstance(ty, lc.IntegerType) @@ -245,6 +246,44 @@ class CBuilder(object): yield cb cb.close() + @contextlib.contextmanager + def forever(self): + with self.loop() as loop: + with loop.condition() as setcond: + NULL = self.constant_null(lc.Type.int()) + setcond( NULL == NULL ) + with loop.body(): + yield loop + + @contextlib.contextmanager + def for_range(self, *args): + def check_arg(x): + if isinstance(x, int): + return self.constant(lc.Type.int(), x) + if not x.is_int: + raise TypeError(x, "All args must be of integer type.") + return x + + if len(args) == 3: + start, stop, step = map(check_arg, args) + elif len(args) == 2: + start, stop = map(check_arg, args) + step = self.constant(start.type, 1) + elif len(args) == 1: + stop = check_arg(args[0]) + start = self.constant(stop.type, 0) + step = self.constant(stop.type, 1) + else: + raise TypeError("Invalid # of arguments: 1, 2 or 3") + + idx = self.var_copy(start) + with self.loop() as loop: + with loop.condition() as setcond: + setcond( idx < stop ) + with loop.body(): + yield loop, idx + idx += step + def position_at_end(self, bb): self.basic_block = bb self.builder.position_at_end(bb) @@ -270,13 +309,18 @@ class CBuilder(object): def constant_string(self, string): mod = self.function.module - name = '.conststr.%x' % hash(string) + name = '.conststr.%x_%x' % (hash(string), len(string)) content = lc.Constant.stringz(string) - globalstr = mod.add_global_variable(content.type, name=name) - globalstr.initializer = content - ptr = mod.add_global_variable(lc.Type.pointer(content.type.element), - name=name+".ptr") - return CTemp(self, globalstr.bitcast(lc.Type.pointer(content.type.element))) + try: + globalstr = mod.get_global_variable_named(name) + except LLVMException: + globalstr = mod.add_global_variable(content.type, name=name) + globalstr.initializer = content +# ptr = mod.add_global_variable(lc.Type.pointer(content.type.element), +# name=name+".ptr") + return CTemp(self, globalstr.bitcast( + lc.Type.pointer(content.type.element))) + def get_intrinsic(self, intrinsic_id, tys): lfunc = lc.Function.intrinsic(self.function.module, intrinsic_id, tys) diff --git a/parallel_vectorize.py b/parallel_vectorize.py index 1f83ad5..25176b8 100644 --- a/parallel_vectorize.py +++ b/parallel_vectorize.py @@ -1,3 +1,15 @@ +''' +This file implements the code-generator for parallel-vectorize. + +ParallelUFunc is the platform independent base class for generating +the thread dispatcher. This thread dispatcher launches threads +that execute the generated function of UFuncCore. +UFuncCore is subclassed to specialize for the input/output types. +The actual workload is invoked inside the function generated by UFuncCore. +UFuncCore also defines a work-stealing mechanism that allows idle threads +to steal works from other threads. +''' + from llvm.core import * from llvm.passes import * @@ -5,14 +17,21 @@ from llvm_cbuilder import * import llvm_cbuilder.shortnames as C class WorkQueue(CStruct): + ''' + Structure for workqueue for parallel-ufunc. + ''' + _fields_ = [ - ('next', C.intp), - ('last', C.intp), - ('lock', C.int), + ('next', C.intp), # next index of work item + ('last', C.intp), # last index of work item (exlusive) + ('lock', C.int), # for locking the workqueue ] def Lock(self): + ''' + Inline the lock procedure. + ''' with self.parent.loop() as loop: with loop.condition() as setcond: unlocked = self.parent.constant(self.lock.type, 0) @@ -26,6 +45,9 @@ class WorkQueue(CStruct): pass def Unlock(self): + ''' + Inline the unlock procedure. + ''' unlocked = self.parent.constant(self.lock.type, 0) locked = self.parent.constant(self.lock.type, 1) @@ -39,6 +61,9 @@ class WorkQueue(CStruct): class ContextCommon(CStruct): + ''' + Structure for thread-shared context information in parallel-ufunc. + ''' _fields_ = [ # loop ufunc args ('args', C.pointer(C.char_p)), @@ -52,6 +77,9 @@ class ContextCommon(CStruct): ] class Context(CStruct): + ''' + Structure for thread-specific context information in parallel-ufunc. + ''' _fields_ = [ ('common', C.pointer(ContextCommon.llvm_type())), ('id', C.int), @@ -71,14 +99,14 @@ class ParallelUFunc(CDefinition): ] def body(self, func, worker, args, dimensions, steps, data, ThreadCount=1): - - + # Setup variables common = self.var(ContextCommon, name='common') workqueues = self.array(WorkQueue, ThreadCount, name='workqueues') contexts = self.array(Context, ThreadCount, name='contexts') num_thread = self.var(C.int, ThreadCount, name='num_thread') + # Initialize ContextCommon common.args.assign(args) common.dimensions.assign(dimensions) common.steps.assign(steps) @@ -87,6 +115,11 @@ class ParallelUFunc(CDefinition): common.num_thread.assign(num_thread.cast(C.int)) common.workqueues.assign(workqueues.reference()) + # Determine chunksize, initial count of work-items per thread. + # If total_work >= 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) @@ -95,60 +128,70 @@ class ParallelUFunc(CDefinition): 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 - 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) + 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!") - with ifelse.otherwise(): - self.debug("ERROR: race occurred!") + with self.ifelse( total_completed == N ) as ifelse: + with ifelse.then(): + self.debug("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): - i = self.var(num_thread.type, 0, name='i') - ONE = self.constant(i.type, 1) - with self.loop() as loop: - with loop.condition() as setcond: - setcond( i < num_thread ) - with loop.body(): - 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)) - # increment - i += ONE + ''' + 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): - i = self.var(num_thread.type, 0, name='i') - ONE = self.constant(i.type, 1) - with self.loop() as loop: - with loop.condition() as setcond: - setcond( i < num_thread ) - with loop.body(): - 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)) - # increment - i += ONE + ''' + 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)) + def _dispatch_worker(self, worker, contexts, num_thread): + ''' + Dispatch worker threads. + ''' + raise NotImplementedError class ParallelUFuncPosix(ParallelUFunc): + ''' + Implements _dispatch_worker to use pthread. + ''' def _dispatch_worker(self, worker, contexts, num_thread): api = PThreadAPI(self) NULL = self.constant_null(C.void_p) @@ -158,27 +201,19 @@ class ParallelUFuncPosix(ParallelUFunc): # self.debug("launch threads") # TODO error handling - i = self.var(num_thread.type, 0, name='i') - ONE = self.constant(i.type, 1) - with self.loop() as loop: - with loop.condition() as setcond: - setcond( i < num_thread ) - with loop.body(): - api.pthread_create(threads[i].reference(), NULL, worker, - contexts[i].reference().cast(C.void_p)) - i += ONE + 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)) - # self.debug("join threads") - i.assign(self.constant_null(i.type)) - with self.loop() as loop: - with loop.condition() as setcond: - setcond( i < num_thread ) - with loop.body(): - api.pthread_join(threads[i], NULL) - i += ONE - # self.debug("closing") + with self.for_range(num_thread) as (loop, i): + api.pthread_join(threads[i], NULL) class UFuncCore(CDefinition): + ''' + 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())), @@ -203,64 +238,61 @@ class UFuncCore(CDefinition): ''' ZERO = self.constant_null(C.int) - with self.loop() as loop: - with loop.condition() as setcond: - setcond(ZERO == ZERO) # loop forever + 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 loop.body(): - 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() - with self.ifelse( item >= last ) as ifelse: - with ifelse.then(): - loop.break_loop() - - self._do_work(common, item, tid, completed) + 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 + Steal work from other workqueues. ''' # self.debug("start work stealing", tid) - incomplete_thread_ct = self.var(C.int, 1) - ITC_NULL = self.constant_null(incomplete_thread_ct.type) + 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( incomplete_thread_ct != ITC_NULL ) + setcond( steal_continue != STEAL_STOP ) with loop.body(): - incomplete_thread_ct.assign(ITC_NULL) - self._do_work_stealing_innerloop(common, incomplete_thread_ct, - tid, completed) + steal_continue.assign(STEAL_STOP) + self._do_work_stealing_innerloop(common, steal_continue, tid, + completed) - def _do_work_stealing_innerloop(self, common, incomplete_thread_ct, tid, + def _do_work_stealing_innerloop(self, common, steal_continue, tid, completed): - i = self.var(C.int, 0) - with self.loop() as loop: - with loop.condition() as setcond: - setcond( i < common.num_thread ) + ''' + 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) - with loop.body(): - with self.ifelse( i != tid ) as ifelse: - with ifelse.then(): - otherqueue = common.workqueues[i].as_struct(WorkQueue) - self._do_work_stealing_check(common, otherqueue, - incomplete_thread_ct, tid, - completed) - - # increment - i += self.constant(i.type, 1) - - def _do_work_stealing_check(self, common, otherqueue, - incomplete_thread_ct, 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() ONE = self.constant(otherqueue.last.type, 1) - ITC_ONE = self.constant(incomplete_thread_ct.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 @@ -269,17 +301,20 @@ class UFuncCore(CDefinition): otherqueue.Unlock() # Released - self._do_work(common, item, tid, completed) + self._do_work(common, item, tid) + completed += self.constant(completed.type, 1) # Mark incomplete thread - incomplete_thread_ct.assign(ITC_ONE) + steal_continue.assign(STEAL_CONTINUE) with ifelse.otherwise(): otherqueue.Unlock() - def _do_work(self, common, item, tid, completed): - # self.debug(" tid", tid, "item", item) - completed += self.constant(completed.type, 1) + def _do_work(self, common, item, tid): + ''' + Prepare to call the actual work function. + ''' + raise NotImplementedError class PThreadAPI(CExternal): @@ -294,25 +329,3 @@ class PThreadAPI(CExternal): pthread_join = Type.function(C.int, [C.void_p, C.void_p]) -def _main(): - NUM_THREAD = 2 - module = Module.new(__name__) - - fpm = FunctionPassManager.new(module) - PassManagerBuilder.new().populate(fpm) - - f1 = ParallelUFuncPosix.define(module, ThreadCount=NUM_THREAD) - f2 = UFuncCore.define(module) - #print(module) -# print(f1) - print(f2) - module.verify() - - fpm.run(f1) - fpm.run(f2) - print('optimized'.center(80,'-')) - print(f2) - -if __name__ == '__main__': - _main() - diff --git a/test_parallel_vectorize.py b/test_parallel_vectorize.py index b3ffb5c..fbcb133 100644 --- a/test_parallel_vectorize.py +++ b/test_parallel_vectorize.py @@ -1,11 +1,40 @@ from parallel_vectorize import * -''' -void parallel_ufunc(void * func, void * worker, - char **args, npy_intp *dimensions, - npy_intp *steps, void *data) -''' + +class Work_D_D(CDefinition): + _name_ = 'copy_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. + ''' + 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[0] + + 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 Tester(CDefinition): + ''' + Generate test. + ''' _name_ = 'tester' def body(self): @@ -14,20 +43,23 @@ class Tester(CDefinition): ThreadCount = 2 ArgCount = 2 - WorkCount = 1000000 + WorkCount = 10000 parallel_ufunc = CFunc(self, ParallelUFuncPosix.define(module, ThreadCount=ThreadCount)) - worker = CFunc(self, UFuncCore.define(module)) + ufunc_core = CFunc(self, UFuncCore_D_D.define(module)) + worker = CFunc(self, Work_D_D.define(module)) # 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, 4) + 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)) @@ -37,7 +69,28 @@ class Tester(CDefinition): for c in range(ArgCount): steps[c].assign(self.constant(C.intp, 8)) - parallel_ufunc(NULL, worker.cast(C.void_p), args, dims, steps, NULL) + # 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 + parallel_ufunc(worker.cast(C.void_p), ufunc_core.cast(C.void_p), 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() @@ -61,6 +114,7 @@ def main(): print(module) # run + print('run') exe = CExecutor(module) exe.engine.get_pointer_to_function(fntester) func = exe.get_ctype_function(fntester, 'void') From c43b27356be5b4bcaa95babfc6185c1bb0c8be65 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Mon, 6 Aug 2012 14:23:43 -0700 Subject: [PATCH 041/675] Fix --- llvm_cbuilder/builder.py | 2 +- test_parallel_vectorize.py | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/llvm_cbuilder/builder.py b/llvm_cbuilder/builder.py index eaa159e..661c2b1 100644 --- a/llvm_cbuilder/builder.py +++ b/llvm_cbuilder/builder.py @@ -429,7 +429,7 @@ class CDefinition(CBuilder): functype = lc.Type.function(cls._retty_, [v for k, v in cls._argtys_]) func = module.get_or_insert_function(functype, name=cls._name_) if not func.is_declaration: # already defined? - raise NameError('Function %s has already been defined' % cls.name) + raise NameError('Function %s has already been defined' % cls._name_) # Name all arguments for i, (name, _) in enumerate(cls._argtys_): diff --git a/test_parallel_vectorize.py b/test_parallel_vectorize.py index fbcb133..fd7cc52 100644 --- a/test_parallel_vectorize.py +++ b/test_parallel_vectorize.py @@ -95,7 +95,6 @@ class Tester(CDefinition): self.ret() def main(): - NUM_THREAD = 2 module = Module.new(__name__) mpm = PassManager.new() From fef9c2efbf50d194a9e715f152fd7627fe3870fa Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Mon, 6 Aug 2012 14:46:27 -0700 Subject: [PATCH 042/675] Add CBuilder.depends to automatically insert depending function. --- llvm_cbuilder/builder.py | 9 ++++++++- parallel_vectorize.py | 27 +++++++++++++++++++-------- test_parallel_vectorize.py | 10 ++++++---- 3 files changed, 33 insertions(+), 13 deletions(-) diff --git a/llvm_cbuilder/builder.py b/llvm_cbuilder/builder.py index 661c2b1..3fce585 100644 --- a/llvm_cbuilder/builder.py +++ b/llvm_cbuilder/builder.py @@ -149,6 +149,13 @@ class CBuilder(object): func = mod.add_function(functype, name=name) return CBuilder(func) + def depends(self, cdef, **kwargs): + try: + func = cdef.define(self.function.module, **kwargs) + except NameError as e: + (func,) = e + return CFunc(self, func) + def printf(self, fmt, *args): mod = self.function.module int_t = lc.Type.int() @@ -429,7 +436,7 @@ class CDefinition(CBuilder): functype = lc.Type.function(cls._retty_, [v for k, v in cls._argtys_]) func = module.get_or_insert_function(functype, name=cls._name_) if not func.is_declaration: # already defined? - raise NameError('Function %s has already been defined' % cls._name_) + raise NameError(func) # Name all arguments for i, (name, _) in enumerate(cls._argtys_): diff --git a/parallel_vectorize.py b/parallel_vectorize.py index 25176b8..42aea26 100644 --- a/parallel_vectorize.py +++ b/parallel_vectorize.py @@ -87,8 +87,15 @@ class Context(CStruct): ] class ParallelUFunc(CDefinition): + ''' + Platform dependent threading function is implemented in + + def _dispatch_worker(self, worker, contexts, num_thread): + ... + + which should be implemented in subclass or mixin. + ''' _name_ = 'parallel_ufunc' - _retty_ = C.void _argtys_ = [ ('func', C.void_p), ('worker', C.void_p), @@ -182,13 +189,7 @@ class ParallelUFunc(CDefinition): cur_ctxt.completed.assign( self.constant_null(cur_ctxt.completed.type)) - def _dispatch_worker(self, worker, contexts, num_thread): - ''' - Dispatch worker threads. - ''' - raise NotImplementedError - -class ParallelUFuncPosix(ParallelUFunc): +class ParallelUFuncPosixMixin(object): ''' Implements _dispatch_worker to use pthread. ''' @@ -316,6 +317,16 @@ class UFuncCore(CDefinition): ''' raise NotImplementedError +class _SpecializedParallelUFunc(ParallelUFunc, ParallelUFuncPosixMixin): + _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, ThreadCount=1): + pass class PThreadAPI(CExternal): pthread_t = C.void_p diff --git a/test_parallel_vectorize.py b/test_parallel_vectorize.py index fd7cc52..4fde372 100644 --- a/test_parallel_vectorize.py +++ b/test_parallel_vectorize.py @@ -30,6 +30,8 @@ class UFuncCore_D_D(UFuncCore): res = ufunc_ptr(indata.load()) outdata.store(res) +class ParallelUFuncPosix(ParallelUFunc, ParallelUFuncPosixMixin): + pass class Tester(CDefinition): ''' @@ -45,10 +47,10 @@ class Tester(CDefinition): ArgCount = 2 WorkCount = 10000 - parallel_ufunc = CFunc(self, ParallelUFuncPosix.define(module, - ThreadCount=ThreadCount)) - ufunc_core = CFunc(self, UFuncCore_D_D.define(module)) - worker = CFunc(self, Work_D_D.define(module)) + parallel_ufunc = self.depends(ParallelUFuncPosix, + ThreadCount=ThreadCount) + ufunc_core = self.depends(UFuncCore_D_D) + worker = self.depends(Work_D_D) # real work NULL = self.constant_null(C.void_p) From 150f497ed08be2d5ec82a607513a3bdbefe2dc02 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Mon, 6 Aug 2012 15:33:36 -0700 Subject: [PATCH 043/675] Add specializable parallel ufunc. Update test. Some fixes. --- llvm_cbuilder/builder.py | 3 ++- parallel_vectorize.py | 16 ++++++++++++---- test_parallel_vectorize.py | 18 ++++++++++++------ 3 files changed, 26 insertions(+), 11 deletions(-) diff --git a/llvm_cbuilder/builder.py b/llvm_cbuilder/builder.py index 3fce585..88516df 100644 --- a/llvm_cbuilder/builder.py +++ b/llvm_cbuilder/builder.py @@ -434,7 +434,8 @@ class CDefinition(CBuilder): @classmethod def define(cls, module, **kws): functype = lc.Type.function(cls._retty_, [v for k, v in cls._argtys_]) - func = module.get_or_insert_function(functype, name=cls._name_) + name = cls._name_ % kws + func = module.get_or_insert_function(functype, name=name) if not func.is_declaration: # already defined? raise NameError(func) diff --git a/parallel_vectorize.py b/parallel_vectorize.py index 42aea26..2d9421f 100644 --- a/parallel_vectorize.py +++ b/parallel_vectorize.py @@ -95,7 +95,7 @@ class ParallelUFunc(CDefinition): which should be implemented in subclass or mixin. ''' - _name_ = 'parallel_ufunc' + _name_ = 'parallel_ufunc_%(ThreadCount)d' _argtys_ = [ ('func', C.void_p), ('worker', C.void_p), @@ -317,7 +317,9 @@ class UFuncCore(CDefinition): ''' raise NotImplementedError -class _SpecializedParallelUFunc(ParallelUFunc, ParallelUFuncPosixMixin): + +class SpecializedParallelUFunc(CDefinition): + _name_ = 'specialized_parallel_ufunc_%(ThreadCount)d_%(FuncName)s' _argtys_ = [ ('args', C.pointer(C.char_p)), ('dimensions', C.pointer(C.intp)), @@ -325,8 +327,14 @@ class _SpecializedParallelUFunc(ParallelUFunc, ParallelUFuncPosixMixin): ('data', C.void_p), ] - def body(self, args, dimensions, steps, data, ThreadCount=1): - pass + def body(self, args, dimensions, steps, data, + PUFuncDef, CoreDef, Func, FuncName, ThreadCount=1): + pufunc = self.depends(PUFuncDef, ThreadCount=ThreadCount) + core = self.depends(CoreDef) + func = self.depends(Func) + 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() class PThreadAPI(CExternal): pthread_t = C.void_p diff --git a/test_parallel_vectorize.py b/test_parallel_vectorize.py index 4fde372..e16d206 100644 --- a/test_parallel_vectorize.py +++ b/test_parallel_vectorize.py @@ -47,10 +47,17 @@ class Tester(CDefinition): ArgCount = 2 WorkCount = 10000 - parallel_ufunc = self.depends(ParallelUFuncPosix, - ThreadCount=ThreadCount) - ufunc_core = self.depends(UFuncCore_D_D) - worker = self.depends(Work_D_D) +# parallel_ufunc = self.depends(ParallelUFuncPosix, +# ThreadCount=ThreadCount) +# ufunc_core = self.depends(UFuncCore_D_D) +# worker = self.depends(Work_D_D) + + sppufunc = self.depends(SpecializedParallelUFunc, + PUFuncDef = ParallelUFuncPosix, + CoreDef = UFuncCore_D_D, + Func = Work_D_D, + FuncName = Work_D_D._name_, + ThreadCount = 2) # real work NULL = self.constant_null(C.void_p) @@ -83,8 +90,7 @@ class Tester(CDefinition): i += self.constant(C.intp, 1) # call parallel ufunc - parallel_ufunc(worker.cast(C.void_p), ufunc_core.cast(C.void_p), args, - dims, steps, NULL) + sppufunc(args, dims, steps, NULL) # check error outbase = args_double[-1] From b5893d4ebb69fe920ae432db7e598aada5de8cda Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Mon, 6 Aug 2012 17:02:04 -0700 Subject: [PATCH 044/675] Add test to use numpy.fromfunc. Depends on numpy branch "ufunc-from-function-pointer" in git://github.com/jayvius/numpy.git --- parallel_vectorize.py | 5 ++-- test_parallel_vectorize.py | 11 +++----- test_parallel_vectorize_numpy.py | 46 ++++++++++++++++++++++++++++++++ 3 files changed, 52 insertions(+), 10 deletions(-) create mode 100644 test_parallel_vectorize_numpy.py diff --git a/parallel_vectorize.py b/parallel_vectorize.py index 2d9421f..bef04eb 100644 --- a/parallel_vectorize.py +++ b/parallel_vectorize.py @@ -151,11 +151,12 @@ class ParallelUFunc(CDefinition): 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) + # 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!") + # self.debug("All is well!") + pass # keep quite if all is well with ifelse.otherwise(): self.debug("ERROR: race occurred! Trigger segfault") self.unreachable() diff --git a/test_parallel_vectorize.py b/test_parallel_vectorize.py index e16d206..ed2010d 100644 --- a/test_parallel_vectorize.py +++ b/test_parallel_vectorize.py @@ -2,7 +2,7 @@ from parallel_vectorize import * class Work_D_D(CDefinition): - _name_ = 'copy_d_d' + _name_ = 'work_d_d' _retty_ = C.double _argtys_ = [ ('inval', C.double), @@ -47,11 +47,6 @@ class Tester(CDefinition): ArgCount = 2 WorkCount = 10000 -# parallel_ufunc = self.depends(ParallelUFuncPosix, -# ThreadCount=ThreadCount) -# ufunc_core = self.depends(UFuncCore_D_D) -# worker = self.depends(Work_D_D) - sppufunc = self.depends(SpecializedParallelUFunc, PUFuncDef = ParallelUFuncPosix, CoreDef = UFuncCore_D_D, @@ -123,11 +118,11 @@ def main(): # run print('run') exe = CExecutor(module) - exe.engine.get_pointer_to_function(fntester) 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 new file mode 100644 index 0000000..dc3557f --- /dev/null +++ b/test_parallel_vectorize_numpy.py @@ -0,0 +1,46 @@ +from test_parallel_vectorize import * + +import numpy as np + +def main(): + module = Module.new(__name__) + sppufunc = SpecializedParallelUFunc.define(module, + PUFuncDef = ParallelUFuncPosix, + CoreDef = UFuncCore_D_D, + Func = Work_D_D, + FuncName = Work_D_D._name_, + ThreadCount = 2) + 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 + + 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() From 01054c726fd9f0f193c8b2842f7c01531384e7ce Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Mon, 6 Aug 2012 20:25:36 -0700 Subject: [PATCH 045/675] Add specialize() for cleaner specialization of CDefinition. --- parallel_vectorize.py | 38 ++++++++++++++++++++++++-------- test_parallel_vectorize.py | 11 +++++---- test_parallel_vectorize_numpy.py | 11 +++++---- 3 files changed, 39 insertions(+), 21 deletions(-) diff --git a/parallel_vectorize.py b/parallel_vectorize.py index bef04eb..b5a03f5 100644 --- a/parallel_vectorize.py +++ b/parallel_vectorize.py @@ -95,7 +95,7 @@ class ParallelUFunc(CDefinition): which should be implemented in subclass or mixin. ''' - _name_ = 'parallel_ufunc_%(ThreadCount)d' + #_name_ = 'parallel_ufunc_%(ThreadCount)d' _argtys_ = [ ('func', C.void_p), ('worker', C.void_p), @@ -105,8 +105,18 @@ class ParallelUFunc(CDefinition): ('data', C.void_p), ] - def body(self, func, worker, args, dimensions, steps, data, ThreadCount=1): + @classmethod + def specialize(cls, num_thread): + name = 'parallel_ufunc_%d' % num_thread + newcls = type(name, (cls,), { + '_name_' : name, + 'ThreadCount': num_thread, + }) + return newcls + + def body(self, func, worker, args, dimensions, steps, data): # Setup variables + ThreadCount = self.ThreadCount common = self.var(ContextCommon, name='common') workqueues = self.array(WorkQueue, ThreadCount, name='workqueues') contexts = self.array(Context, ThreadCount, name='contexts') @@ -318,9 +328,7 @@ class UFuncCore(CDefinition): ''' raise NotImplementedError - class SpecializedParallelUFunc(CDefinition): - _name_ = 'specialized_parallel_ufunc_%(ThreadCount)d_%(FuncName)s' _argtys_ = [ ('args', C.pointer(C.char_p)), ('dimensions', C.pointer(C.intp)), @@ -328,15 +336,27 @@ class SpecializedParallelUFunc(CDefinition): ('data', C.void_p), ] - def body(self, args, dimensions, steps, data, - PUFuncDef, CoreDef, Func, FuncName, ThreadCount=1): - pufunc = self.depends(PUFuncDef, ThreadCount=ThreadCount) - core = self.depends(CoreDef) - func = self.depends(Func) + 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): + name = 'specialized_%s_%s_%s'% (pufunc_def._name_, + core_def._name_, + func_def._name_) + newcls = type(name, (cls,), { + '_name_' : name, + 'PUFuncDef': pufunc_def, + 'CoreDef' : core_def, + 'FuncDef' : func_def, + }) + return newcls + class PThreadAPI(CExternal): pthread_t = C.void_p diff --git a/test_parallel_vectorize.py b/test_parallel_vectorize.py index ed2010d..ab28363 100644 --- a/test_parallel_vectorize.py +++ b/test_parallel_vectorize.py @@ -14,6 +14,7 @@ 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) @@ -47,12 +48,10 @@ class Tester(CDefinition): ArgCount = 2 WorkCount = 10000 - sppufunc = self.depends(SpecializedParallelUFunc, - PUFuncDef = ParallelUFuncPosix, - CoreDef = UFuncCore_D_D, - Func = Work_D_D, - FuncName = Work_D_D._name_, - ThreadCount = 2) + PUfuncDef = ParallelUFuncPosix.specialize(num_thread=2) + SPUF = SpecializedParallelUFunc.specialize( + PUfuncDef, UFuncCore_D_D, Work_D_D) + sppufunc = self.depends(SPUF) # real work NULL = self.constant_null(C.void_p) diff --git a/test_parallel_vectorize_numpy.py b/test_parallel_vectorize_numpy.py index dc3557f..7b1ca51 100644 --- a/test_parallel_vectorize_numpy.py +++ b/test_parallel_vectorize_numpy.py @@ -4,12 +4,11 @@ import numpy as np def main(): module = Module.new(__name__) - sppufunc = SpecializedParallelUFunc.define(module, - PUFuncDef = ParallelUFuncPosix, - CoreDef = UFuncCore_D_D, - Func = Work_D_D, - FuncName = Work_D_D._name_, - ThreadCount = 2) + PUfuncDef = ParallelUFuncPosix.specialize(num_thread=2) + SPUF = SpecializedParallelUFunc.specialize( + PUfuncDef, UFuncCore_D_D, Work_D_D) + sppufunc = SPUF.define(module) + module.verify() mpm = PassManager.new() From 938763ef07cd0687854f0b02c8539310ba4cec91 Mon Sep 17 00:00:00 2001 From: "Bradley M. Froehle" Date: Tue, 7 Aug 2012 15:38:06 -0700 Subject: [PATCH 046/675] Fix broken testall.py (NameError: PASS_AGGRESSIVE_DCE) Commit 2d79cfa43 renamed PASS_AGGRESSIVE_DCE -> PASS_ADCE but missed an instance in one test. --- test/testall.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/testall.py b/test/testall.py index acf330b..ed7a8a1 100755 --- a/test/testall.py +++ b/test/testall.py @@ -610,7 +610,7 @@ def do_functionpassmanager(): b.ret(Constant.int(ti, 42)) fpm = FunctionPassManager.new(m) fpm.add(TargetData.new('')) - fpm.add(PASS_AGGRESSIVE_DCE) + fpm.add(PASS_ADCE) fpm.initialize() fpm.run(f) fpm.finalize() From d3548e5377a88489c84ac75195768520c7b68e46 Mon Sep 17 00:00:00 2001 From: "Bradley M. Froehle" Date: Tue, 7 Aug 2012 15:56:05 -0700 Subject: [PATCH 047/675] test_uses: Fix unexpected keyword argument 'end' with `nosetests uses.py` Logging does not know about the keyword argument 'end'. The existing code works only because the default logging level prevents debug messages from running. When running the test under `nosetests` the debug messages are enabled leading to the error. --- test/uses.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/uses.py b/test/uses.py index 97040fa..1b13aa6 100755 --- a/test/uses.py +++ b/test/uses.py @@ -21,7 +21,7 @@ class TestUses(unittest.TestCase): logging.debug(m) logging.debug("-"*60) - logging.debug("Testing use count ..", end=' ') + logging.debug("Testing use count ..") self.assertEqual(f.args[0].use_count, 1) self.assertEqual(f.args[1].use_count, 1) self.assertEqual(f.args[2].use_count, 1) @@ -29,7 +29,7 @@ class TestUses(unittest.TestCase): self.assertEqual(tmp2.use_count, 0) self.assertEqual(tmp3.use_count, 1) - logging.debug("Testing uses ..", end=' ') + logging.debug("Testing uses ..") self.assertIs(f.args[0].uses[0], tmp1) self.assertEqual(len(f.args[0].uses), 1) self.assertIs(f.args[1].uses[0], tmp2) From 2acc0709845cdaa571c110c13e9cbaabe229e90f Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Tue, 7 Aug 2012 16:55:33 -0700 Subject: [PATCH 048/675] Refactor. Modify the way CDefinition is specialized. --- llvm_cbuilder/builder.py | 92 +++++++++++++++++++++++--------- parallel_vectorize.py | 25 +++------ test_parallel_vectorize.py | 10 ++-- test_parallel_vectorize_numpy.py | 20 +++++-- 4 files changed, 96 insertions(+), 51 deletions(-) diff --git a/llvm_cbuilder/builder.py b/llvm_cbuilder/builder.py index 88516df..e591e9d 100644 --- a/llvm_cbuilder/builder.py +++ b/llvm_cbuilder/builder.py @@ -6,6 +6,7 @@ import contextlib import llvm.core as lc import llvm.ee as le from llvm import LLVMException +from . import shortnames as types def _is_int(ty): return isinstance(ty, lc.IntegerType) @@ -149,18 +150,12 @@ class CBuilder(object): func = mod.add_function(functype, name=name) return CBuilder(func) - def depends(self, cdef, **kwargs): - try: - func = cdef.define(self.function.module, **kwargs) - except NameError as e: - (func,) = e - return CFunc(self, func) + def depends(self, fndecl): + return CFunc(self, fndecl(self.function.module)) def printf(self, fmt, *args): mod = self.function.module - int_t = lc.Type.int() - char_ptr_t = lc.Type.pointer(lc.Type.int(8)) - functype = lc.Type.function(int_t, [char_ptr_t], True) + functype = lc.Type.function(types.int, [types.char_p], True) printf = mod.get_or_insert_function(functype, name='printf') ret = self.builder.call(printf, [fmt.value]+_list_values(args)) return CTemp(self, ret) @@ -224,7 +219,7 @@ class CBuilder(object): if isinstance(count, CValue): count = count.value elif not isinstance(count, lc.Value): - count = self.constant(lc.Type.int(), count).value + count = self.constant(types.int, count).value ptr = self.builder.alloca_array(ty, count, name=name) return CArray(self, ptr) @@ -236,7 +231,7 @@ class CBuilder(object): raise TypeError(errmsg) self.builder.ret(val.value) else: - if retty != lc.Type.void(): + if retty != types.void: errmsg = "Cannot return void" raise TypeError(errmsg) self.builder.ret_void() @@ -257,7 +252,7 @@ class CBuilder(object): def forever(self): with self.loop() as loop: with loop.condition() as setcond: - NULL = self.constant_null(lc.Type.int()) + NULL = self.constant_null(types.int) setcond( NULL == NULL ) with loop.body(): yield loop @@ -266,7 +261,7 @@ class CBuilder(object): def for_range(self, *args): def check_arg(x): if isinstance(x, int): - return self.constant(lc.Type.int(), x) + return self.constant(types.int, x) if not x.is_int: raise TypeError(x, "All args must be of integer type.") return x @@ -303,7 +298,7 @@ class CBuilder(object): def constant(self, ty, val): if isinstance(ty, lc.IntegerType): res = lc.Constant.int(ty, val) - elif ty==lc.Type.float() or ty==lc.Type.double(): + elif ty == types.float or ty == types.double: res = lc.Constant.real(ty, val) else: raise TypeError("Cannot auto build constant " @@ -316,6 +311,8 @@ class CBuilder(object): def constant_string(self, string): mod = self.function.module + # TODO + # Is this a safe way for uniquing identifying string name = '.conststr.%x_%x' % (hash(string), len(string)) content = lc.Constant.stringz(string) try: @@ -323,10 +320,8 @@ class CBuilder(object): except LLVMException: globalstr = mod.add_global_variable(content.type, name=name) globalstr.initializer = content -# ptr = mod.add_global_variable(lc.Type.pointer(content.type.element), -# name=name+".ptr") return CTemp(self, globalstr.bitcast( - lc.Type.pointer(content.type.element))) + types.pointer(content.type.element))) def get_intrinsic(self, intrinsic_id, tys): @@ -423,18 +418,62 @@ class CBuilder(object): def unreachable(self): self.builder.unreachable() +class _DeclareCDef(object): + def __init__(self, cdef): + self.cdef = cdef + + def __str__(self): + return self.cdef._name_ + + def __call__(self, module): + try: + func = self.cdef.define(module) + except NameError as e: + (func,) = e + return func + +class CDeclare(object): + def __init__(self, name, ty, ptr): + self._name = name + self._type = ty + self._ptr = ptr + + def __call__(self, module): + fnptr = types.pointer(self._type) + ptr = lc.Constant.int(types.intp, self._ptr) + ptr = ptr.inttoptr(fnptr) + return ptr + + def __str__(self): + return self._name + class CDefinition(CBuilder): ''' Inherit this class to for defining functions ''' - _name_ = 'unamed' # name of the function; should overide in subclass - _retty_ = lc.Type.void() # return type; can overide in subclass + _name_ = '' # name of the function; should overide in subclass + _retty_ = types.void # return type; can overide in subclass _argtys_ = [] # a list of tuple(name, type); can overide in subclass + def __new__(cls, *args, **kws): + try: + fnsp = getattr(cls, 'specialize') + except AttributeError: + pass + else: + cls = type('%s_Specialized' % cls.__name__, (cls,), {}) + fnsp(*args, **kws) + + obj = object.__new__(_DeclareCDef) + obj.__init__(cls) + return obj + @classmethod - def define(cls, module, **kws): + def define(cls, module): functype = lc.Type.function(cls._retty_, [v for k, v in cls._argtys_]) - name = cls._name_ % kws + name = cls._name_ + if not name: + raise NameError("Function name cannot be empty.") func = module.get_or_insert_function(functype, name=name) if not func.is_declaration: # already defined? raise NameError(func) @@ -444,8 +483,9 @@ class CDefinition(CBuilder): func.args[i].name = name # Create builder and populate body - cbuilder = cls(func) - cbuilder.body(*cbuilder.args, **kws) + cbuilder = object.__new__(cls) + cbuilder.__init__(func) + cbuilder.body(*cbuilder.args) cbuilder.close() return func @@ -662,7 +702,7 @@ class CValue(object): def __getitem__(self, idx): self._ensure_is_pointer() if not isinstance(idx, CValue): - idx = self.parent.constant(lc.Type.int(), idx) + idx = self.parent.constant(types.int, idx) bldr = self.parent.builder ptr = bldr.gep(self.value, [idx.value]) return CVar(self.parent, ptr) @@ -827,7 +867,7 @@ class CArray(CValue): # if isinstance(idx, CValue): # idx = idx.value # elif not isinstance(idx, lc.Value): -# idx = self.parent.constant(lc.Type.int(), idx).value +# idx = self.parent.constant(types.int, idx).value # ptr = builder.gep(self.value, [idx]) # return CVar(self.parent, ptr) @@ -838,7 +878,7 @@ class CStruct(CValue): def __init__(self, parent, ptr): super(CStruct, self).__init__(parent) - makeind = lambda x: self.parent.constant(lc.Type.int(), x).value + makeind = lambda x: self.parent.constant(types.int, x).value self.ptr = ptr for i, (fd, _) in enumerate(self._fields_): gep = self.parent.builder.gep(ptr, [makeind(0), makeind(i)]) diff --git a/parallel_vectorize.py b/parallel_vectorize.py index b5a03f5..4c8daab 100644 --- a/parallel_vectorize.py +++ b/parallel_vectorize.py @@ -95,7 +95,7 @@ class ParallelUFunc(CDefinition): which should be implemented in subclass or mixin. ''' - #_name_ = 'parallel_ufunc_%(ThreadCount)d' + _argtys_ = [ ('func', C.void_p), ('worker', C.void_p), @@ -107,12 +107,9 @@ class ParallelUFunc(CDefinition): @classmethod def specialize(cls, num_thread): - name = 'parallel_ufunc_%d' % num_thread - newcls = type(name, (cls,), { - '_name_' : name, - 'ThreadCount': num_thread, - }) - return newcls + print num_thread + cls._name_ = 'parallel_ufunc_%d' % num_thread + cls.ThreadCount = num_thread def body(self, func, worker, args, dimensions, steps, data): # Setup variables @@ -346,16 +343,10 @@ class SpecializedParallelUFunc(CDefinition): @classmethod def specialize(cls, pufunc_def, core_def, func_def): - name = 'specialized_%s_%s_%s'% (pufunc_def._name_, - core_def._name_, - func_def._name_) - newcls = type(name, (cls,), { - '_name_' : name, - 'PUFuncDef': pufunc_def, - 'CoreDef' : core_def, - 'FuncDef' : func_def, - }) - return newcls + 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): pthread_t = C.void_p diff --git a/test_parallel_vectorize.py b/test_parallel_vectorize.py index ab28363..54d6b14 100644 --- a/test_parallel_vectorize.py +++ b/test_parallel_vectorize.py @@ -48,10 +48,12 @@ class Tester(CDefinition): ArgCount = 2 WorkCount = 10000 - PUfuncDef = ParallelUFuncPosix.specialize(num_thread=2) - SPUF = SpecializedParallelUFunc.specialize( - PUfuncDef, UFuncCore_D_D, Work_D_D) - sppufunc = self.depends(SPUF) + + 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) diff --git a/test_parallel_vectorize_numpy.py b/test_parallel_vectorize_numpy.py index 7b1ca51..392c81d 100644 --- a/test_parallel_vectorize_numpy.py +++ b/test_parallel_vectorize_numpy.py @@ -1,13 +1,20 @@ +''' +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__) - PUfuncDef = ParallelUFuncPosix.specialize(num_thread=2) - SPUF = SpecializedParallelUFunc.specialize( - PUfuncDef, UFuncCore_D_D, Work_D_D) - sppufunc = SPUF.define(module) + + spufdef = SpecializedParallelUFunc(ParallelUFuncPosix(num_thread=2), + UFuncCore_D_D(), + Work_D_D()) + + sppufunc = spufdef(module) module.verify() @@ -27,6 +34,11 @@ def main(): 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]) From 8b45094e20c69f8a5c9aa9ca74de40763d27b8f2 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Tue, 7 Aug 2012 16:56:28 -0700 Subject: [PATCH 049/675] Add test that uses function pointer. --- test_parallel_vectorize_numpy_2.py | 69 ++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 test_parallel_vectorize_numpy_2.py diff --git a/test_parallel_vectorize_numpy_2.py b/test_parallel_vectorize_numpy_2.py new file mode 100644 index 0000000..a511980 --- /dev/null +++ b/test_parallel_vectorize_numpy_2.py @@ -0,0 +1,69 @@ +''' +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 = CDeclare(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() From 68e2359ad2ddefba0dca44831e1c5c53a89122fb Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 8 Aug 2012 15:17:31 -0700 Subject: [PATCH 050/675] cleanup and doc --- llvm_cbuilder/builder.py | 423 ++++++++++++++++++++++++++++++++----- llvm_cbuilder/executor.py | 14 ++ llvm_cbuilder/libc.py | 8 + tests/test_cstr_collide.py | 17 ++ 4 files changed, 406 insertions(+), 56 deletions(-) create mode 100644 llvm_cbuilder/libc.py create mode 100644 tests/test_cstr_collide.py diff --git a/llvm_cbuilder/builder.py b/llvm_cbuilder/builder.py index e591e9d..99133e6 100644 --- a/llvm_cbuilder/builder.py +++ b/llvm_cbuilder/builder.py @@ -8,6 +8,10 @@ import llvm.ee as le from llvm import LLVMException from . import shortnames as types +### +# Utilities +### + def _is_int(ty): return isinstance(ty, lc.IntegerType) @@ -47,6 +51,19 @@ def _change_block_temporarily_dummy(*args): yield class _IfElse(object): + '''if-else construct. + + Example + ------- + with cbuilder.ifelse(cond) as ifelse: + with ifelse.then(): + # code when cond is true + # this block is mandatory + with ifelse.otherwise(): + # code when cond is false + # this block is optional + ''' + def __init__(self, parent, cond): self.parent = parent self.cond = cond @@ -84,6 +101,22 @@ class _IfElse(object): builder.position_at_end(bbend) class _Loop(object): + '''while...do loop. + + Example + ------- + with cbuilder.loop() as loop: + with loop.condition() as setcond: + # Put the condition evaluation here + setcond( cond ) # set loop condition + # Do not put code after setcond(...) + with loop.body(): + # Put the code of the loop body here + + Use loop.break_loop() to break out of the loop. + Use loop.continue_loop() to jump the condition evaulation. + ''' + def __init__(self, parent): self.parent = parent @@ -107,9 +140,8 @@ class _Loop(object): def body(self): builder = self.parent.builder builder.position_at_end(self._bbbody) - yield self - + # close last block if not _is_block_terminated(builder.basic_block): builder.branch(self._bbcond) @@ -121,9 +153,6 @@ class _Loop(object): def close(self): builder = self.parent.builder -# if not _is_block_terminated(builder.basic_block): -# with _change_block_temporarily(builder, builder.basic_block): -# builder.branch(self._bbend) builder.position_at_end(self._bbend) class CBuilder(object): @@ -131,14 +160,18 @@ class CBuilder(object): A wrapper class for features in llvm-py package to allow user to use C-like high-level language contruct easily. ''' + def __init__(self, function): + '''constructor + + function : is an empty function to be populating. + ''' self.function = function self.declare_block = self.function.append_basic_block('decl') self.first_body_block = self.function.append_basic_block('body') self.builder = lc.Builder.new(self.first_body_block) self.target_data = le.TargetData.new(self.function.module.data_layout) - - # prepare arguments + # Prepare arguments. Make all function arguments behave like variables. self.args = [] for arg in function.args: var = self.var(arg.type, arg, name=arg.name) @@ -146,21 +179,40 @@ class CBuilder(object): @staticmethod def new_function(mod, name, ret, args): + '''factory method + + Create a new function in the module and return a CBuilder instance. + ''' functype = lc.Type.function(ret, args) func = mod.add_function(functype, name=name) return CBuilder(func) def depends(self, fndecl): + '''add function dependency + + Returns a CFunc instance and define the function if it is not defined. + + fndecl : is a callable that takes a `llvm.core.Module` and returns + a function pointer. + ''' return CFunc(self, fndecl(self.function.module)) def printf(self, fmt, *args): - mod = self.function.module - functype = lc.Type.function(types.int, [types.char_p], True) - printf = mod.get_or_insert_function(functype, name='printf') - ret = self.builder.call(printf, [fmt.value]+_list_values(args)) + '''printf() from libc + + fmt : a character string holding printf format string. + *args : additional variable arguments. + ''' + from .libc import LibC + libc = LibC(self) + ret = libc.printf(fmt, *args) return CTemp(self, ret) def debug(self, *args): + '''debug print + + Use printf to dump the values of all arguments. + ''' type_mapper = { 'i8' : '%c', 'i16': '%hd', @@ -174,17 +226,27 @@ class CBuilder(object): if isinstance(i, str): itemsfmt.append(i.replace('%', '%%')) else: - ty = type_mapper[str(i.type)] + tyname = str(i.type) + if tyname == 'float': + # auto convert float to double + ty = '%e' + i = i.cast(types.double) + else: + ty = type_mapper[tyname] itemsfmt.append(ty) items.append(i) fmt = ' '.join(itemsfmt) + '\n' return self.printf(self.constant_string(fmt), *items) def var(self, ty, value=None, name=''): - ''' - Only allocate in the first block + '''allocate variable on the stack + + ty : variable type + value : [optional] initializer value + name : [optional] name used in LLVM IR ''' with _change_block_temporarily(self.builder, self.declare_block): + # goto the first block is_cstruct = _is_cstruct(ty) if is_cstruct: cstruct = ty @@ -203,27 +265,45 @@ class CBuilder(object): return CVar(self, ptr) def var_copy(self, val, name=''): + '''allocate a new variable by copying another value + + The new variable has the same type and value of `val`. + ''' return self.var(val.type, val, name=name) def array(self, ty, count, name=''): + '''allocate an array on the stack + + ty : array element type + count : array size; can be python int, llvm.core.Constant, or CValue + name : [optional] name used in LLVM IR + ''' if isinstance(count, int) or isinstance(count, lc.Constant): + # Only go to the first block if array size is fixed. contexthelper = _change_block_temporarily else: + # Do not go to the first block if the array size is dynamic. contexthelper = _change_block_temporarily_dummy with contexthelper(self.builder, self.declare_block): - is_cstruct = _is_cstruct(ty) - if is_cstruct: + if _is_cstruct(ty): # array of struct? cstruct = ty ty = ty.llvm_type() + if isinstance(count, CValue): count = count.value elif not isinstance(count, lc.Value): count = self.constant(types.int, count).value + ptr = self.builder.alloca_array(ty, count, name=name) return CArray(self, ptr) def ret(self, val=None): + '''insert return statement + + val : if is `None`, insert return-void + else, return `val` + ''' retty = self.function.type.pointee.return_type if val is not None: if val.type != retty: @@ -238,18 +318,26 @@ class CBuilder(object): @contextlib.contextmanager def ifelse(self, cond): + '''start a if-else block + + cond : branch condition + ''' cb = _IfElse(self, cond) yield cb cb.close() @contextlib.contextmanager def loop(self): + '''start a loop block + ''' cb = _Loop(self) yield cb cb.close() @contextlib.contextmanager def forever(self): + '''start a forever loop block + ''' with self.loop() as loop: with loop.condition() as setcond: NULL = self.constant_null(types.int) @@ -259,6 +347,10 @@ class CBuilder(object): @contextlib.contextmanager def for_range(self, *args): + '''start a for-range block. + + *args : same as arguments of builtin `range()` + ''' def check_arg(x): if isinstance(x, int): return self.constant(types.int, x) @@ -287,15 +379,26 @@ class CBuilder(object): idx += step def position_at_end(self, bb): + '''reposition inserter to the end of basic-block + + bb : a basic block + ''' self.basic_block = bb self.builder.position_at_end(bb) def close(self): + '''end code generation + ''' # Close declaration block with _change_block_temporarily(self.builder, self.declare_block): self.builder.branch(self.first_body_block) def constant(self, ty, val): + '''create a constant + + ty : data type + val : initializer + ''' if isinstance(ty, lc.IntegerType): res = lc.Constant.int(ty, val) elif ty == types.float or ty == types.double: @@ -306,119 +409,239 @@ class CBuilder(object): return CTemp(self, res) def constant_null(self, ty): + '''create a zero filled constant + + ty : data type + ''' res = lc.Constant.null(ty) return CTemp(self, res) def constant_string(self, string): + '''create a constant string + + This will de-duplication string of same content to minimize memory use. + ''' mod = self.function.module - # TODO - # Is this a safe way for uniquing identifying string - name = '.conststr.%x_%x' % (hash(string), len(string)) + collision = 0 + name_fmt = '.conststr.%x.%x' content = lc.Constant.stringz(string) - try: - globalstr = mod.get_global_variable_named(name) - except LLVMException: - globalstr = mod.add_global_variable(content.type, name=name) - globalstr.initializer = content - return CTemp(self, globalstr.bitcast( - types.pointer(content.type.element))) + while True: + name = name_fmt % (hash(string), collision) + try: + # check if the name already exists + globalstr = mod.get_global_variable_named(name) + except LLVMException: + # new constant string + globalstr = mod.add_global_variable(content.type, name=name) + globalstr.initializer = content + globalstr.global_constant = True + else: + # compare existing content + existed = str(globalstr.initializer) + if existed != str(content): + collision += 1 + continue # loop until we resolve the name collision + + return CTemp(self, globalstr.bitcast( + types.pointer(content.type.element))) def get_intrinsic(self, intrinsic_id, tys): + '''get intrinsic function + + intrinsic_id : numerical ID of target intrinsic + tys : type argument for the intrinsic + ''' lfunc = lc.Function.intrinsic(self.function.module, intrinsic_id, tys) return CFunc(self, lfunc) def get_function_named(self, name): + '''get function by name + ''' m = self.function.module func = m.get_function_named(name) return CFunc(self, func) def is_terminated(self): - ''' - Is the current basic-block terminated? + '''is the current basic-block terminated? ''' return _is_block_terminated(self.builder.basic_block) def atomic_cmpxchg(self, ptr, old, val, ordering, crossthread=True): + '''atomic compare-exchange + + ptr : pointer to data + old : old value to compare to + val : new value + ordering : memory ordering as a string + crossthread : set to `False` for single-thread code + + Returns the old value on success. + ''' res = self.builder.atomic_cmpxchg(ptr.value, old.value, val.value, ordering, crossthread) return CTemp(self, res) def atomic_xchg(self, ptr, val, ordering, crossthread=True): + '''atomic exchange + + ptr : pointer to data + val : new value + ordering : memory ordering as a string + crossthread : set to `False` for single-thread code + + Returns the old value + ''' + res = self.builder.atomic_xchg(ptr.value, val.value, ordering, crossthread) return CTemp(self, res) def atomic_add(self, ptr, val, ordering, crossthread=True): + '''atomic add + + ptr : pointer to data + val : new value + ordering : memory ordering as a string + crossthread : set to `False` for single-thread code + + Returns the computation result of the operation + ''' + res = self.builder.atomic_add(ptr.value, val.value, ordering, crossthread) return CTemp(self, res) def atomic_sub(self, ptr, val, ordering, crossthread=True): + '''atomic sub + + See `atomic_add` for parameters documentation + ''' res = self.builder.atomic_sub(ptr.value, val.value, ordering, crossthread) return CTemp(self, res) def atomic_and(self, ptr, val, ordering, crossthread=True): + '''atomic bitwise and + + See `atomic_add` for parameters documentation + ''' res = self.builder.atomic_and(ptr.value, val.value, ordering, crossthread) return CTemp(self, res) def atomic_nand(self, ptr, val, ordering, crossthread=True): + '''atomic bitwise nand + + See `atomic_add` for parameters documentation + ''' res = self.builder.atomic_nand(ptr.value, val.value, ordering, crossthread) return CTemp(self, res) def atomic_or(self, ptr, val, ordering, crossthread=True): + '''atomic bitwise or + + See `atomic_add` for parameters documentation + ''' res = self.builder.atomic_or(ptr.value, val.value, ordering, crossthread) return CTemp(self, res) def atomic_xor(self, ptr, val, ordering, crossthread=True): + '''atomic bitwise xor + + See `atomic_add` for parameters documentation + ''' + res = self.builder.atomic_xor(ptr.value, val.value, ordering, crossthread) return CTemp(self, res) def atomic_max(self, ptr, val, ordering, crossthread=True): + '''atomic signed maximum between value at `ptr` and `val` + + See `atomic_add` for parameters documentation + ''' res = self.builder.atomic_max(ptr.value, val.value, ordering, crossthread) return CTemp(self, res) def atomic_min(self, ptr, val, ordering, crossthread=True): + '''atomic signed minimum between value at `ptr` and `val` + + See `atomic_add` for parameters documentation + ''' res = self.builder.atomic_min(ptr.value, val.value, ordering, crossthread) return CTemp(self, res) def atomic_umax(self, ptr, val, ordering, crossthread=True): + '''atomic unsigned maximum between value at `ptr` and `val` + + See `atomic_add` for parameters documentation + ''' res = self.builder.atomic_umax(ptr.value, val.value, ordering, crossthread) return CTemp(self, res) def atomic_umin(self, ptr, val, ordering, crossthread=True): + '''atomic unsigned minimum between value at `ptr` and `val` + + See `atomic_add` for parameters documentation + ''' res = self.builder.atomic_umin(ptr.value, val.value, ordering, crossthread) return CTemp(self, res) def atomic_load(self, ptr, ordering, align=1, crossthread=True): + '''atomic load + + ptr : pointer to the value to load + align : memory alignment in bytes + See `atomic_add` for other documentation of other parameters + ''' res = self.builder.atomic_load(ptr.value, ordering, align, crossthread) return CTemp(self, res) def atomic_store(self, val, ptr, ordering, align=1, crossthread=True): + '''atomic store + + ptr : pointer to where to store + val : value to store + align : memory alignment in bytes + See `atomic_add` for other documentation of other parameters + ''' + res = self.builder.atomic_store(val.value, ptr.value, ordering, align, crossthread) return CTemp(self, res) def fence(self, ordering, crossthread=True): + '''insert memory fence + ''' res = self.builder.fence(ordering, crossthread) return CTemp(self, res) def alignment(self, ty): + '''get minimum alignment of `ty` + ''' return self.target_data.abi_alignment(ty) def unreachable(self): + '''insert instruction that causes segfault some platform (Intel), + or no-op on others. + + It has no defined semantic. + ''' self.builder.unreachable() class _DeclareCDef(object): + '''create a function a CDefinition to use with `CBuilder.depends` + + An instance of this class is created by the constructor of CDefinition. + Do not use directly. + ''' def __init__(self, cdef): self.cdef = cdef @@ -433,6 +656,9 @@ class _DeclareCDef(object): return func class CDeclare(object): + '''create a function from name, type and pointer to use with + `CBuilder.depends` + ''' def __init__(self, name, ty, ptr): self._name = name self._type = ty @@ -448,33 +674,51 @@ class CDeclare(object): return self._name class CDefinition(CBuilder): - ''' - Inherit this class to for defining functions + '''represents function definition + + Inherit from this class to create a new function definition. + + Class Members + ------------- + _name_ : name of the function + _retty_ : return type + _argtys_ : argument names and types as list of tuples; + e.g. [ ( 'myarg', lc.Type.int() ), ... ] ''' _name_ = '' # name of the function; should overide in subclass _retty_ = types.void # return type; can overide in subclass _argtys_ = [] # a list of tuple(name, type); can overide in subclass def __new__(cls, *args, **kws): - try: - fnsp = getattr(cls, 'specialize') - except AttributeError: - pass - else: + if cls.is_generic(): + # Call specialize if it is defined. cls = type('%s_Specialized' % cls.__name__, (cls,), {}) - fnsp(*args, **kws) + cls.specialize(*args, **kws) obj = object.__new__(_DeclareCDef) obj.__init__(cls) return obj + @classmethod + def is_generic(cls): + '''Is this a generic definition? + ''' + return hasattr(cls, 'specialize') + @classmethod def define(cls, module): + '''define the function in the module. + + Raises NameError if a function of the same name has already been + defined. + ''' functype = lc.Type.function(cls._retty_, [v for k, v in cls._argtys_]) name = cls._name_ if not name: - raise NameError("Function name cannot be empty.") + raise AttributeError("Function name cannot be empty.") + func = module.get_or_insert_function(functype, name=name) + if not func.is_declaration: # already defined? raise NameError(func) @@ -490,25 +734,24 @@ class CDefinition(CBuilder): return func def body(self): - ''' - Overide this function to define the body. + '''overide this function to define the body. ''' raise NotImplementedError class CValue(object): ''' - = Signess = - Since LLVM type does not provide signess attribute. This information + Signedness + ---------- + Since LLVM type does not provide signedness attribute. This information is provided in the CValue.unsigned attribute. The default value is `None`, meaning that this attribute is not set. - In casting operation, signess information is passed as an optional arg. + In casting operation, signednss information is passed as an optional arg. - In binary operation, signess of the left operand is used. + In binary operation, signedness of the left operand is used. ''' - # Attribute for for integer values. - unsigned = None + unsigned = None # attribute for for integer values. _BINOP_MAP = { # op-name : (signed int, unsigned int, real) @@ -542,6 +785,8 @@ class CValue(object): self.parent = parent def _use_binop(self, op): + '''implements binary operations + ''' def wrapped(rhs): self._ensure_same_type(rhs) binop = self._BINOP_MAP[op] @@ -560,6 +805,8 @@ class CValue(object): return wrapped def _use_bitwise(self, op): + '''implements bitwise operations + ''' def wrapped(rhs): self._ensure_same_type(rhs) if not self.is_int: @@ -608,6 +855,10 @@ class CValue(object): return self._use_bitwise('xor')(rhs) def _ensure_same_type(self, val): + '''ensure that this instance has the same type as `val` + + Raises TypeError if `self.type != val.type` + ''' if self.type != val.type: errmsg = "Type mismatch: %s != %s" raise TypeError(errmsg % (self.type, val.type)) @@ -621,6 +872,10 @@ class CValue(object): return _is_real(self.type) def cast(self, ty, unsigned=False): + '''cast to another type + + If `ty == self.type`, then pass thru + ''' make = lambda X: CTemp(self.parent, X) if self.type == ty: return self # pass thru @@ -651,6 +906,8 @@ class CValue(object): raise TypeError(errmsg % (self.type, ty)) def _cmp_op(self, name): + '''implements comparison operations + ''' def wrapped(rhs): make = lambda X: CTemp(self.parent, X) self._ensure_same_type(rhs) @@ -700,6 +957,10 @@ class CValue(object): raise TypeError("Must be a pointer; got %s" % self.type) def __getitem__(self, idx): + '''implement access indexing + + Uses GEP. + ''' self._ensure_is_pointer() if not isinstance(idx, CValue): idx = self.parent.constant(types.int, idx) @@ -708,15 +969,26 @@ class CValue(object): return CVar(self.parent, ptr) def load(self, volatile=False): + '''memory load for pointer types + ''' self._ensure_is_pointer() loaded = self.parent.builder.load(self.value, volatile=volatile) return CTemp(self.parent, loaded) def store(self, val, volatile=False): + '''memory store for pointer types + ''' self._ensure_is_pointer() self.parent.builder.store(val.value, self.value, volatile=volatile) def atomic_load(self, ordering, align=None, crossthread=True): + '''atomic load memory for pointer types + + align : overide to control memory alignment; otherwise the default + alignment of the type is used. + + Other parameters are the same as `CBuilder.atomic_load` + ''' self._ensure_is_pointer() if align is None: align = self.parent.alignment(self.type.pointee) @@ -725,6 +997,13 @@ class CValue(object): return CTemp(self.parent, inst) def atomic_store(self, value, ordering, align=None, crossthread=True): + '''atomic memory store for pointer types + + align : overide to control memory alignment; otherwise the default + alignment of the type is used. + + Other parameters are the same as `CBuilder.atomic_store` + ''' self._ensure_is_pointer() if align is None: align = self.parent.alignment(self.type.pointee) @@ -732,6 +1011,10 @@ class CValue(object): align=align, crossthread=crossthread) def atomic_cmpxchg(self, old, new, ordering, crossthread=True): + '''atomic compare-exchange for pointer types + + Other parameters are the same as `CBuilder.atomic_cmpxchg` + ''' self._ensure_is_pointer() inst = self.parent.builder.atomic_cmpxchg(self.value, old.value, new.value, ordering, @@ -740,11 +1023,17 @@ class CValue(object): class CFunc(CValue): + '''Wraps function pointer + ''' def __init__(self, parent, func): super(CFunc, self).__init__(parent) self.function = func def __call__(self, *args): + '''Call the function with the given arguments + + *args : variable arguments of CValue instances + ''' arg_values = _list_values(args) ftype = self.function.type.pointee for i, (exp, got) in enumerate(zip(ftype.args, arg_values)): @@ -764,6 +1053,8 @@ class CFunc(CValue): return self.function.type class CTemp(CValue): + '''Wraps temporary values + ''' def __init__(self, parent, value): super(CTemp, self).__init__(parent) self.value = value @@ -773,6 +1064,10 @@ class CTemp(CValue): return self.value.type class CVar(CValue): + '''Wraps variables + + Similar to C variables. + ''' def __init__(self, parent, ptr): super(CVar, self).__init__(parent) @@ -827,6 +1122,8 @@ class CVar(CValue): return self.parent.builder.load(self.ptr) def assign(self, val): + '''assign new value to the variable + ''' self._ensure_same_type(val) self.parent.builder.store(val.value, self.ptr) @@ -835,9 +1132,13 @@ class CVar(CValue): return self.ptr.type.pointee def reference(self): + '''get a pointer reference of the variable + ''' return CTemp(self.parent, self.ptr) def as_struct(self, cstruct_class, volatile=False): + '''load a pointer to a structure and assume a structure interface + ''' if _is_pointer(self.type): ptr = self.parent.builder.load(self.ptr, volatile=volatile) return cstruct_class(self.parent, ptr) @@ -845,6 +1146,10 @@ class CVar(CValue): return cstruct_class(self.parent, self.ptr) class CArray(CValue): + '''wraps a array + + Similar to C arrays + ''' def __init__(self, parent, base): super(CArray, self).__init__(parent) self.base_ptr = base @@ -860,18 +1165,17 @@ class CArray(CValue): def type(self): return self.base_ptr.type -## Moved to CValue -# def __getitem__(self, idx): -# self._ensure_is_pointer() -# builder = self.parent.builder -# if isinstance(idx, CValue): -# idx = idx.value -# elif not isinstance(idx, lc.Value): -# idx = self.parent.constant(types.int, idx).value -# ptr = builder.gep(self.value, [idx]) -# return CVar(self.parent, ptr) - class CStruct(CValue): + '''Wraps a structure + + Structure in LLVM can be identified by name of layout. + + Subclass to define a new structure. All fields are defined in the + `_fields_` class attribute as a list of tuple (name, type). + + Can define new methods which gets inlined to the parent CBuilder. + ''' + @classmethod def llvm_type(cls): return lc.Type.struct([v for k, v in cls._fields_]) @@ -883,12 +1187,19 @@ class CStruct(CValue): for i, (fd, _) in enumerate(self._fields_): gep = self.parent.builder.gep(ptr, [makeind(0), makeind(i)]) gep.name = "%s.%s" % (type(self).__name__, fd) + if hasattr(self, fd): + raise AttributeError("Field name shadows another attribute") setattr(self, fd, CVar(self.parent, gep)) def reference(self): return CTemp(self.parent, self.ptr) class CExternal(object): + '''subclass to define external interface + + All class attributes that are `llvm.core.FunctionType` are converted + to `CFunc` instance during instantiation. + ''' def __init__(self, cbuilder): is_func = lambda x: isinstance(x, lc.FunctionType) non_magic = lambda s: not ( s.startswith('__') and s.endswith('__') ) diff --git a/llvm_cbuilder/executor.py b/llvm_cbuilder/executor.py index bd7d78c..acfd13d 100644 --- a/llvm_cbuilder/executor.py +++ b/llvm_cbuilder/executor.py @@ -1,3 +1,7 @@ +''' +This is mostly a convenience module for testing with ctypes. +''' + from llvm.core import Type, Module import llvm.ee as le import ctypes as ct @@ -29,6 +33,8 @@ MAP_CTYPES = { } class CExecutor(object): + '''a convenient class for creating ctype functions from LLVM modules + ''' def __init__(self, mod_or_engine): if isinstance(mod_or_engine, Module): self.engine = le.EngineBuilder.new(mod_or_engine).opt(3).create() @@ -36,6 +42,14 @@ class CExecutor(object): self.engine = mod_or_engine def get_ctype_function(self, fn, *typeinfo): + '''create a ctype function from a LLVM function + + typeinfo : string of types (see `MAP_CTYPES`) or + list of ctypes datatype. + First value is the return type. + A function that takes no argument and return nothing + should use `"void"` or `None`. + ''' if len(typeinfo)==1 and isinstance(typeinfo[0], str): types = [ MAP_CTYPES[s.strip()] for s in typeinfo[0].split(',') ] if not types: diff --git a/llvm_cbuilder/libc.py b/llvm_cbuilder/libc.py new file mode 100644 index 0000000..8d4a5c1 --- /dev/null +++ b/llvm_cbuilder/libc.py @@ -0,0 +1,8 @@ +from .builder import CExternal +import llvm.core as lc +from . import shortnames as types + +class LibC(CExternal): + printf = lc.Type.function(types.int, [types.char_p], True) + # TODO a lot more to add + diff --git a/tests/test_cstr_collide.py b/tests/test_cstr_collide.py new file mode 100644 index 0000000..4a427c6 --- /dev/null +++ b/tests/test_cstr_collide.py @@ -0,0 +1,17 @@ +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() From 3009d8468f3ca85650852d3777ca1c547c57c06d Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 8 Aug 2012 15:29:16 -0700 Subject: [PATCH 051/675] more cleanup and doc --- README.md | 16 +++++++++++ parallel_vectorize.py | 63 +++++++++++++++++++++++-------------------- 2 files changed, 50 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index cab0f28..a63039a 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,23 @@ +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/parallel_vectorize.py b/parallel_vectorize.py index 4c8daab..f26ad46 100644 --- a/parallel_vectorize.py +++ b/parallel_vectorize.py @@ -17,8 +17,7 @@ from llvm_cbuilder import * import llvm_cbuilder.shortnames as C class WorkQueue(CStruct): - ''' - Structure for workqueue for parallel-ufunc. + '''structure for workqueue for parallel-ufunc. ''' _fields_ = [ @@ -29,8 +28,7 @@ class WorkQueue(CStruct): def Lock(self): - ''' - Inline the lock procedure. + '''inline the lock procedure. ''' with self.parent.loop() as loop: with loop.condition() as setcond: @@ -45,8 +43,7 @@ class WorkQueue(CStruct): pass def Unlock(self): - ''' - Inline the unlock procedure. + '''inline the unlock procedure. ''' unlocked = self.parent.constant(self.lock.type, 0) locked = self.parent.constant(self.lock.type, 1) @@ -61,8 +58,7 @@ class WorkQueue(CStruct): class ContextCommon(CStruct): - ''' - Structure for thread-shared context information in parallel-ufunc. + '''structure for thread-shared context information in parallel-ufunc. ''' _fields_ = [ # loop ufunc args @@ -77,8 +73,7 @@ class ContextCommon(CStruct): ] class Context(CStruct): - ''' - Structure for thread-specific context information in parallel-ufunc. + '''structure for thread-specific context information in parallel-ufunc. ''' _fields_ = [ ('common', C.pointer(ContextCommon.llvm_type())), @@ -87,7 +82,11 @@ class Context(CStruct): ] class ParallelUFunc(CDefinition): - ''' + '''the generic parallel vectorize mechanism + + Can be specialized to the maximum number of threads on the platform. + + Platform dependent threading function is implemented in def _dispatch_worker(self, worker, contexts, num_thread): @@ -107,7 +106,8 @@ class ParallelUFunc(CDefinition): @classmethod def specialize(cls, num_thread): - print num_thread + '''specialize to the maximum # of thread + ''' cls._name_ = 'parallel_ufunc_%d' % num_thread cls.ThreadCount = num_thread @@ -172,8 +172,7 @@ class ParallelUFunc(CDefinition): self.ret() def _populate_workqueues(self, workqueues, N, ChunkSize, num_thread): - ''' - Loop over all threads and populate the workqueue for each of them. + '''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): @@ -186,8 +185,7 @@ class ParallelUFunc(CDefinition): last_wq.last.assign(N) def _populate_context(self, contexts, common, num_thread): - ''' - Loop over all threads and populate contexts for each of them. + '''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): @@ -198,8 +196,7 @@ class ParallelUFunc(CDefinition): self.constant_null(cur_ctxt.completed.type)) class ParallelUFuncPosixMixin(object): - ''' - Implements _dispatch_worker to use pthread. + '''ParallelUFunc mixin that implements _dispatch_worker to use pthread. ''' def _dispatch_worker(self, worker, contexts, num_thread): api = PThreadAPI(self) @@ -219,7 +216,10 @@ class ParallelUFuncPosixMixin(object): 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. ''' @@ -242,8 +242,7 @@ class UFuncCore(CDefinition): self.ret() def _do_workqueue(self, common, workqueue, tid, completed): - ''' - Process local workqueue. + '''process local workqueue. ''' ZERO = self.constant_null(C.int) @@ -264,8 +263,7 @@ class UFuncCore(CDefinition): completed += self.constant(completed.type, 1) def _do_work_stealing(self, common, tid, completed): - ''' - Steal work from other workqueues. + '''steal work from other workqueues. ''' # self.debug("start work stealing", tid) steal_continue = self.var(C.int, 1) @@ -283,8 +281,7 @@ class UFuncCore(CDefinition): def _do_work_stealing_innerloop(self, common, steal_continue, tid, completed): - ''' - Loop over all other threads and try to steal work. + '''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: @@ -296,10 +293,10 @@ class UFuncCore(CDefinition): def _do_work_stealing_check(self, common, otherqueue, steal_continue, tid, completed): - ''' - Check the workqueue for any remaining work and steal it. + '''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: @@ -318,14 +315,18 @@ class UFuncCore(CDefinition): with ifelse.otherwise(): otherqueue.Unlock() + # Released def _do_work(self, common, item, tid): - ''' - Prepare to call the actual work function. + '''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)), @@ -343,12 +344,16 @@ class SpecializedParallelUFunc(CDefinition): @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, From d0f0bae1c5093d0e307b45c974993308728bcea7 Mon Sep 17 00:00:00 2001 From: "Travis E. Oliphant" Date: Wed, 8 Aug 2012 17:49:24 -0500 Subject: [PATCH 052/675] Add Sphinx documentation. --- docs/Makefile | 157 ++ docs/gh-pages.py | 138 ++ docs/source/conf.py | 242 +++ docs/source/doc/comparision.md | 119 ++ docs/source/doc/comparision.rst | 147 ++ docs/source/doc/examples.md | 154 ++ docs/source/doc/examples/JITTutorial1.md | 38 + docs/source/doc/examples/JITTutorial2.md | 57 + docs/source/doc/functions.md | 198 ++ .../doc/kaleidoscope/PythonLangImpl1.md | 330 +++ .../doc/kaleidoscope/PythonLangImpl2.md | 998 +++++++++ .../doc/kaleidoscope/PythonLangImpl3.md | 1062 ++++++++++ .../doc/kaleidoscope/PythonLangImpl4.md | 941 +++++++++ .../doc/kaleidoscope/PythonLangImpl5.md | 1464 ++++++++++++++ .../doc/kaleidoscope/PythonLangImpl6.md | 1535 ++++++++++++++ .../doc/kaleidoscope/PythonLangImpl7.md | 1794 +++++++++++++++++ .../doc/kaleidoscope/PythonLangImpl8.md | 275 +++ docs/source/doc/llvm-py_package.md | 92 + docs/source/doc/llvm.core.Argument.md | 57 + docs/source/doc/llvm.core.ArrayType.md | 26 + docs/source/doc/llvm.core.BasicBlock.md | 40 + docs/source/doc/llvm.core.Builder.md | 326 +++ docs/source/doc/llvm.core.Constant.md | 296 +++ docs/source/doc/llvm.core.Function.md | 129 ++ docs/source/doc/llvm.core.FunctionType.md | 53 + docs/source/doc/llvm.core.GlobalValue.md | 99 + docs/source/doc/llvm.core.GlobalVariable.md | 94 + docs/source/doc/llvm.core.Instruction.md | 215 ++ docs/source/doc/llvm.core.IntegerType.md | 20 + docs/source/doc/llvm.core.Module.md | 219 ++ docs/source/doc/llvm.core.PointerType.md | 26 + docs/source/doc/llvm.core.StructType.md | 70 + docs/source/doc/llvm.core.Type.md | 148 ++ docs/source/doc/llvm.core.User.md | 34 + docs/source/doc/llvm.core.Value.md | 50 + docs/source/doc/llvm.core.VectorType.md | 26 + docs/source/doc/llvm.ee.EngineBuilder.md | 49 + docs/source/doc/llvm.ee.ExecutionEngine.md | 52 + docs/source/doc/llvm.ee.GenericValue.md | 55 + docs/source/doc/llvm.ee.TargetData.md | 48 + .../doc/llvm.passes.FunctionPassManager.md | 35 + docs/source/doc/llvm.passes.PassManager.md | 23 + .../doc/llvm.passes.PassManagerBuilder.md | 59 + docs/source/doc/llvm_concepts.md | 242 +++ docs/source/doc/types.md | 146 ++ docs/source/doc/userguide.md | 159 ++ docs/source/doc/values.md | 88 + docs/source/index.rst | 22 + 48 files changed, 12647 insertions(+) create mode 100644 docs/Makefile create mode 100755 docs/gh-pages.py create mode 100644 docs/source/conf.py create mode 100644 docs/source/doc/comparision.md create mode 100644 docs/source/doc/comparision.rst create mode 100644 docs/source/doc/examples.md create mode 100644 docs/source/doc/examples/JITTutorial1.md create mode 100644 docs/source/doc/examples/JITTutorial2.md create mode 100644 docs/source/doc/functions.md create mode 100644 docs/source/doc/kaleidoscope/PythonLangImpl1.md create mode 100644 docs/source/doc/kaleidoscope/PythonLangImpl2.md create mode 100644 docs/source/doc/kaleidoscope/PythonLangImpl3.md create mode 100644 docs/source/doc/kaleidoscope/PythonLangImpl4.md create mode 100644 docs/source/doc/kaleidoscope/PythonLangImpl5.md create mode 100644 docs/source/doc/kaleidoscope/PythonLangImpl6.md create mode 100644 docs/source/doc/kaleidoscope/PythonLangImpl7.md create mode 100644 docs/source/doc/kaleidoscope/PythonLangImpl8.md create mode 100644 docs/source/doc/llvm-py_package.md create mode 100644 docs/source/doc/llvm.core.Argument.md create mode 100644 docs/source/doc/llvm.core.ArrayType.md create mode 100644 docs/source/doc/llvm.core.BasicBlock.md create mode 100644 docs/source/doc/llvm.core.Builder.md create mode 100644 docs/source/doc/llvm.core.Constant.md create mode 100644 docs/source/doc/llvm.core.Function.md create mode 100644 docs/source/doc/llvm.core.FunctionType.md create mode 100644 docs/source/doc/llvm.core.GlobalValue.md create mode 100644 docs/source/doc/llvm.core.GlobalVariable.md create mode 100644 docs/source/doc/llvm.core.Instruction.md create mode 100644 docs/source/doc/llvm.core.IntegerType.md create mode 100644 docs/source/doc/llvm.core.Module.md create mode 100644 docs/source/doc/llvm.core.PointerType.md create mode 100644 docs/source/doc/llvm.core.StructType.md create mode 100644 docs/source/doc/llvm.core.Type.md create mode 100644 docs/source/doc/llvm.core.User.md create mode 100644 docs/source/doc/llvm.core.Value.md create mode 100644 docs/source/doc/llvm.core.VectorType.md create mode 100644 docs/source/doc/llvm.ee.EngineBuilder.md create mode 100644 docs/source/doc/llvm.ee.ExecutionEngine.md create mode 100644 docs/source/doc/llvm.ee.GenericValue.md create mode 100644 docs/source/doc/llvm.ee.TargetData.md create mode 100644 docs/source/doc/llvm.passes.FunctionPassManager.md create mode 100644 docs/source/doc/llvm.passes.PassManager.md create mode 100644 docs/source/doc/llvm.passes.PassManagerBuilder.md create mode 100644 docs/source/doc/llvm_concepts.md create mode 100644 docs/source/doc/types.md create mode 100644 docs/source/doc/userguide.md create mode 100644 docs/source/doc/values.md create mode 100644 docs/source/index.rst diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 0000000..8e563cc --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,157 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = _build +SRCDIR = source + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) $(SRCDIR) +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext + +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + +clean: + -rm -rf $(BUILDDIR)/* + +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/llvmpy.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/llvmpy.qhc" + +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/llvmpy" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/llvmpy" + @echo "# devhelp" + +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." + +gh-pages: clean html + python gh-pages.py diff --git a/docs/gh-pages.py b/docs/gh-pages.py new file mode 100755 index 0000000..d9c8614 --- /dev/null +++ b/docs/gh-pages.py @@ -0,0 +1,138 @@ +#!/usr/bin/env python +"""Script to commit the doc build outputs into the github-pages repo. + +Use: + + gh-pages.py [tag] + +If no tag is given, the current output of 'git describe' is used. If given, +that is how the resulting directory will be named. + +In practice, you should use either actual clean tags from a current build or +something like 'current' as a stable URL for the most current version of the """ + +#----------------------------------------------------------------------------- +# Imports +#----------------------------------------------------------------------------- +import os +import re +import shutil +import sys +from os import chdir as cd +from os.path import join as pjoin + +from subprocess import Popen, PIPE, CalledProcessError, check_call + +#----------------------------------------------------------------------------- +# Globals +#----------------------------------------------------------------------------- + +pages_dir = 'gh-pages' +html_dir = '_build/html' +pdf_dir = '_build/latex' +pages_repo = 'git@github.com:llvmpy/llvmpy-doc.git' + +#----------------------------------------------------------------------------- +# Functions +#----------------------------------------------------------------------------- +def sh(cmd): + """Execute command in a subshell, return status code.""" + return check_call(cmd, shell=True) + + +def sh2(cmd): + """Execute command in a subshell, return stdout. + + Stderr is unbuffered from the subshell.x""" + p = Popen(cmd, stdout=PIPE, shell=True) + out = p.communicate()[0] + retcode = p.returncode + if retcode: + raise CalledProcessError(retcode, cmd) + else: + return out.rstrip() + + +def sh3(cmd): + """Execute command in a subshell, return stdout, stderr + + If anything appears in stderr, print it out to sys.stderr""" + p = Popen(cmd, stdout=PIPE, stderr=PIPE, shell=True) + out, err = p.communicate() + retcode = p.returncode + if retcode: + raise CalledProcessError(retcode, cmd) + else: + return out.rstrip(), err.rstrip() + + +def init_repo(path): + """clone the gh-pages repo if we haven't already.""" + sh("git clone %s %s"%(pages_repo, path)) + here = os.getcwdu() + cd(path) + sh('git checkout gh-pages') + cd(here) + +#----------------------------------------------------------------------------- +# Script starts +#----------------------------------------------------------------------------- +if __name__ == '__main__': + # The tag can be given as a positional argument + try: + tag = sys.argv[1] + except IndexError: + try: + tag = sh2('git describe --exact-match') + except CalledProcessError: + tag = "dev" # Fallback + + startdir = os.getcwdu() + if not os.path.exists(pages_dir): + # init the repo + init_repo(pages_dir) + else: + # ensure up-to-date before operating + cd(pages_dir) + sh('git checkout gh-pages') + sh('git pull') + cd(startdir) + + dest = pjoin(pages_dir, tag) + + # don't `make html` here, because gh-pages already depends on html in Makefile + # sh('make html') + if tag != 'dev': + # only build pdf for non-dev targets + #sh2('make pdf') + pass + + # This is pretty unforgiving: we unconditionally nuke the destination + # directory, and then copy the html tree in there + shutil.rmtree(dest, ignore_errors=True) + shutil.copytree(html_dir, dest) + if tag != 'dev': + #shutil.copy(pjoin(pdf_dir, 'ipython.pdf'), pjoin(dest, 'ipython.pdf')) + pass + + try: + cd(pages_dir) + status = sh2('git status | head -1') + branch = re.match('\# On branch (.*)$', status).group(1) + if branch != 'gh-pages': + e = 'On %r, git branch is %r, MUST be "gh-pages"' % (pages_dir, + branch) + raise RuntimeError(e) + + sh('git add -A %s' % tag) + sh('git commit -m"Updated doc release: %s"' % tag) + print + print 'Most recent 3 commits:' + sys.stdout.flush() + sh('git --no-pager log --oneline HEAD~3..') + finally: + cd(startdir) + + print + print 'Now verify the build in: %r' % dest + print "If everything looks good, 'git push'" diff --git a/docs/source/conf.py b/docs/source/conf.py new file mode 100644 index 0000000..b7a7342 --- /dev/null +++ b/docs/source/conf.py @@ -0,0 +1,242 @@ +# -*- coding: utf-8 -*- +# +# llvmpy documentation build configuration file, created by +# sphinx-quickstart on Wed Aug 8 17:33:58 2012. +# +# This file is execfile()d with the current directory set to its containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys, os + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +#sys.path.insert(0, os.path.abspath('.')) + +# -- General configuration ----------------------------------------------------- + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be extensions +# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +extensions = ['sphinx.ext.mathjax'] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix of source filenames. +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'llvmpy' +copyright = u'2012, Mahadevan R (2008-2010), Continuum Analytics (2012)' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '0.8' +# The full version, including alpha/beta/rc tags. +release = '0.8.2' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +#language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ['_build'] + +# The reST default role (used for this markup: `text`) to use for all documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + + +# -- Options for HTML output --------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = 'default' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Output file base name for HTML help builder. +htmlhelp_basename = 'llvmpydoc' + + +# -- Options for LaTeX output -------------------------------------------------- + +latex_elements = { +# The paper size ('letterpaper' or 'a4paper'). +#'papersize': 'letterpaper', + +# The font size ('10pt', '11pt' or '12pt'). +#'pointsize': '10pt', + +# Additional stuff for the LaTeX preamble. +#'preamble': '', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, author, documentclass [howto/manual]). +latex_documents = [ + ('index', 'llvmpy.tex', u'llvmpy Documentation', + u'Mahadevan R (2008-2010), Continuum Analytics (2012)', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output -------------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ('index', 'llvmpy', u'llvmpy Documentation', + [u'Mahadevan R (2008-2010), Continuum Analytics (2012)'], 1) +] + +# If true, show URL addresses after external links. +#man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------------ + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + ('index', 'llvmpy', u'llvmpy Documentation', + u'Mahadevan R (2008-2010), Continuum Analytics (2012)', 'llvmpy', 'One line description of project.', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +#texinfo_appendices = [] + +# If false, no module index is generated. +#texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#texinfo_show_urls = 'footnote' diff --git a/docs/source/doc/comparision.md b/docs/source/doc/comparision.md new file mode 100644 index 0000000..43073c7 --- /dev/null +++ b/docs/source/doc/comparision.md @@ -0,0 +1,119 @@ +--- +layout: page +title: Comparison Operations +--- + +# Integer Comparision # {#icmp} + +Predicates for use with `icmp` instruction are listed below. All +of these are integer constants defined in the `llvm.core` module. + +##`ICMP_EQ` + +Equality + +##`ICMP_NE` + +Inequality + +##`ICMP_UGT` + +Unsigned greater than + +##`ICMP_UGE` + +Unsigned greater than or equal + +##`ICMP_ULT` + +Unsigned less than + +##`ICMP_ULE` + +Unsigned less than or equal + +##`ICMP_SGT` + +Signed greater than + +##`ICMP_SGE` + +Signed greater than or equal + +##`ICMP_SLT` + +Signed less than + +##`ICMP_SLE` + +Signed less than or equal + +# Float Comparision # {#fcmp} + +Predicates for use with `fcmp` instruction are listed below. All +of these are integer constants defined in the `llvm.core` module. + +##`FCMP_FALSE` + +Always false + +##`FCMP_OEQ` + +True if ordered and equal + +##`FCMP_OGT` + +True if ordered and greater than + +##`FCMP_OGE` + +True if ordered and greater than or equal + +##`FCMP_OLT` + +True if ordered and less than + +##`FCMP_OLE` + +True if ordered and less than or equal + +##`FCMP_ONE` + +True if ordered and operands are unequal + +##`FCMP_ORD` + +True if ordered (no NaNs) + +##`FCMP_UNO` + +True if unordered: `isnan(X) | isnan(Y)` + +##`FCMP_UEQ` + +True if unordered or equal + +##`FCMP_UGT` + +True if unordered or greater than + +##`FCMP_UGE` + +True if unordered, greater than or equal + +##`FCMP_ULT` + +True if unordered, or less than + +##`FCMP_ULE` + +True if unordered, less than or equal + +##`FCMP_UNE` + +True if unordered or not equal + +##`FCMP_TRUE` + +Always true + diff --git a/docs/source/doc/comparision.rst b/docs/source/doc/comparision.rst new file mode 100644 index 0000000..2f1b87b --- /dev/null +++ b/docs/source/doc/comparision.rst @@ -0,0 +1,147 @@ ++--------------------------------+ +| layout: page | ++--------------------------------+ +| title: Comparison Operations | ++--------------------------------+ + +Integer Comparision # {#icmp} +============================= + +Predicates for use with ``icmp`` instruction are listed below. All of +these are integer constants defined in the ``llvm.core`` module. + +``ICMP_EQ`` +----------- + +Equality + +``ICMP_NE`` +----------- + +Inequality + +``ICMP_UGT`` +------------ + +Unsigned greater than + +``ICMP_UGE`` +------------ + +Unsigned greater than or equal + +``ICMP_ULT`` +------------ + +Unsigned less than + +``ICMP_ULE`` +------------ + +Unsigned less than or equal + +``ICMP_SGT`` +------------ + +Signed greater than + +``ICMP_SGE`` +------------ + +Signed greater than or equal + +``ICMP_SLT`` +------------ + +Signed less than + +``ICMP_SLE`` +------------ + +Signed less than or equal + +Float Comparision # {#fcmp} +=========================== + +Predicates for use with ``fcmp`` instruction are listed below. All of +these are integer constants defined in the ``llvm.core`` module. + +``FCMP_FALSE`` +-------------- + +Always false + +``FCMP_OEQ`` +------------ + +True if ordered and equal + +``FCMP_OGT`` +------------ + +True if ordered and greater than + +``FCMP_OGE`` +------------ + +True if ordered and greater than or equal + +``FCMP_OLT`` +------------ + +True if ordered and less than + +``FCMP_OLE`` +------------ + +True if ordered and less than or equal + +``FCMP_ONE`` +------------ + +True if ordered and operands are unequal + +``FCMP_ORD`` +------------ + +True if ordered (no NaNs) + +``FCMP_UNO`` +------------ + +True if unordered: ``isnan(X) | isnan(Y)`` + +``FCMP_UEQ`` +------------ + +True if unordered or equal + +``FCMP_UGT`` +------------ + +True if unordered or greater than + +``FCMP_UGE`` +------------ + +True if unordered, greater than or equal + +``FCMP_ULT`` +------------ + +True if unordered, or less than + +``FCMP_ULE`` +------------ + +True if unordered, less than or equal + +``FCMP_UNE`` +------------ + +True if unordered or not equal + +``FCMP_TRUE`` +------------- + +Always true diff --git a/docs/source/doc/examples.md b/docs/source/doc/examples.md new file mode 100644 index 0000000..337f09a --- /dev/null +++ b/docs/source/doc/examples.md @@ -0,0 +1,154 @@ +--- +layout: page +title: Examples and LLVM Tutorials +--- + +* This will become a table of contents (this text will be scraped). +{:toc} + +# Examples + +## A Simple Function + +Let's create a (LLVM) module containing a single function, corresponding +to the `C` function: + +{% highlight c %} +int sum(int a, int b) +{ + return a + b; +} +{% endhighlight %} + +Here's how it looks like: + +{% highlight python %} +#!/usr/bin/env python + +# Import the llvm-py modules. +from llvm import * +from llvm.core import * + +# Create an (empty) module. +my_module = Module.new('my_module') + +# All the types involved here are "int"s. This type is represented +# by an object of the llvm.core.Type class: +ty_int = Type.int() # by default 32 bits + +# We need to represent the class of functions that accept two integers +# and return an integer. This is represented by an object of the +# function type (llvm.core.FunctionType): +ty_func = Type.function(ty_int, [ty_int, ty_int]) + +# Now we need a function named 'sum' of this type. Functions are not +# free-standing (in llvm-py); it needs to be contained in a module. +f_sum = my_module.add_function(ty_func, "sum") + +# Let's name the function arguments as 'a' and 'b'. +f_sum.args[0].name = "a" +f_sum.args[1].name = "b" + +# Our function needs a "basic block" -- a set of instructions that +# end with a terminator (like return, branch etc.). By convention +# the first block is called "entry". +bb = f_sum.append_basic_block("entry") + +# Let's add instructions into the block. For this, we need an +# instruction builder: +builder = Builder.new(bb) + +# OK, now for the instructions themselves. We'll create an add +# instruction that returns the sum as a value, which we'll use +# a ret instruction to return. +tmp = builder.add(f_sum.args[0], f_sum.args[1], "tmp") +builder.ret(tmp) + +# We've completed the definition now! Let's see the LLVM assembly +# language representation of what we've created: +print my_module +{% endhighlight %} + +Here is the output: + +{% highlight llvm %} +; ModuleID = 'my_module' + +define i32 @sum(i32 %a, i32 %b) { +entry: + %tmp = add i32 %a, %b ; [#uses=1] + ret i32 %tmp +} +{% endhighlight %} + + +## Adding JIT Compilation + +Let's compile this function in-memory and run it. + +{% highlight python %} +#!/usr/bin/env python + +# Import the llvm-py modules. +from llvm import * +from llvm.core import * +from llvm.ee import * # new import: ee = Execution Engine + +# Create a module, as in the previous example. +my_module = Module.new('my_module') +ty_int = Type.int() # by default 32 bits +ty_func = Type.function(ty_int, [ty_int, ty_int]) +f_sum = my_module.add_function(ty_func, "sum") +f_sum.args[0].name = "a" +f_sum.args[1].name = "b" +bb = f_sum.append_basic_block("entry") +builder = Builder.new(bb) +tmp = builder.add(f_sum.args[0], f_sum.args[1], "tmp") +builder.ret(tmp) + +# Create an execution engine object. This will create a JIT compiler +# on platforms that support it, or an interpreter otherwise. +ee = ExecutionEngine.new(my_module) + +# The arguments needs to be passed as "GenericValue" objects. +arg1 = GenericValue.int(ty_int, 100) +arg2 = GenericValue.int(ty_int, 42) + +# Now let's compile and run! +retval = ee.run_function(f_sum, [arg1, arg2]) + +# The return value is also GenericValue. Let's print it. +print "returned", retval.as_int() +{% endhighlight %} + +And here's the output: + + returned 142 + +* * * + +# LLVM Tutorials + +## Simple JIT Tutorials + +The following JIT tutorials were contributed by Sebastien Binet. + +1. [A First Function](examples/JITTutorial1.html) +2. [A More Complicated Function](examples/JITTutorial2.html) + +## Kaleidoscope ## {#kaleidoscope} + +Implementing a Language with LLVM + +The LLVM [Kaleidoscope](http://www.llvm.org/docs/tutorial/) tutorial +has been ported to llvm-py by Max Shawabkeh. + +1. [Tutorial Introduction and the Lexer](kaleidoscope/PythonLangImpl1.html) +2. [Implementing a Parser and AST](kaleidoscope/PythonLangImpl2.html) +3. [Implementing Code Generation to LLVM IR](kaleidoscope/PythonLangImpl3.html) +4. [Adding JIT and Optimizer Support](kaleidoscope/PythonLangImpl4.html) +5. [Extending the language: control flow](kaleidoscope/PythonLangImpl5.html) +6. [Extending the language: user-defined operators](kaleidoscope/PythonLangImpl6.html) +7. [Extending the language: mutable variables / SSA construction](kaleidoscope/PythonLangImpl7.html) +8. [Conclusion and other useful LLVM tidbits](kaleidoscope/PythonLangImpl8.html) + diff --git a/docs/source/doc/examples/JITTutorial1.md b/docs/source/doc/examples/JITTutorial1.md new file mode 100644 index 0000000..32186de --- /dev/null +++ b/docs/source/doc/examples/JITTutorial1.md @@ -0,0 +1,38 @@ +--- +layout: page +title: JIT Tutorial 1 +--- + +{% highlight python %} +#!/usr/bin/env python + +from llvm.core import * + +# create a module +module = Module.new ("tut1") + +# create a function type taking 3 32-bit integers, return a 32-bit integer +ty_int = Type.int (32) +func_type = Type.function (ty_int, (ty_int,)*3) + +# create a function of that type +mul_add = Function.new (module, func_type, "mul_add") +mul_add.calling_convention = CC_C +x = mul_add.args[0]; x.name = "x" +y = mul_add.args[1]; y.name = "y" +z = mul_add.args[2]; z.name = "z" + +# implement the function + +# new block +blk = mul_add.append_basic_block ("entry") + +# IR builder +bldr = Builder.new (blk) +tmp_1 = bldr.mul (x, y, "tmp_1") +tmp_2 = bldr.add (tmp_1, z, "tmp_2") + +bldr.ret (tmp_2) + +print(module) +{% endhighlight %} diff --git a/docs/source/doc/examples/JITTutorial2.md b/docs/source/doc/examples/JITTutorial2.md new file mode 100644 index 0000000..7ce36d7 --- /dev/null +++ b/docs/source/doc/examples/JITTutorial2.md @@ -0,0 +1,57 @@ +--- +layout: page +title: JIT Tutorial 2 +--- + +{% highlight python %} +#!/usr/bin/env python + +from llvm.core import * + +# create a module +module = Module.new ("tut2") + +# create a function type taking 2 integers, return a 32-bit integer +ty_int = Type.int (32) +func_type = Type.function (ty_int, (ty_int, ty_int)) + +# create a function of that type +gcd = Function.new (module, func_type, "gcd") + +# name function args +x = gcd.args[0]; x.name = "x" +y = gcd.args[1]; y.name = "y" + +# implement the function + +# blocks... +entry = gcd.append_basic_block ("entry") +ret = gcd.append_basic_block ("return") +cond_false = gcd.append_basic_block ("cond_false") +cond_true = gcd.append_basic_block ("cond_true") +cond_false_2 = gcd.append_basic_block ("cond_false_2") + +# create a llvm::IRBuilder +bldr = Builder.new (entry) +x_eq_y = bldr.icmp (IPRED_EQ, x, y, "tmp") +bldr.cbranch (x_eq_y, ret, cond_false) + +bldr.position_at_end (ret) +bldr.ret(x) + +bldr.position_at_end (cond_false) +x_lt_y = bldr.icmp (IPRED_ULT, x, y, "tmp") +bldr.cbranch (x_lt_y, cond_true, cond_false_2) + +bldr.position_at_end (cond_true) +y_sub_x = bldr.sub (y, x, "tmp") +recur_1 = bldr.call (gcd, (x, y_sub_x,), "tmp") +bldr.ret (recur_1) + +bldr.position_at_end (cond_false_2) +x_sub_y = bldr.sub (x, y, "x_sub_y") +recur_2 = bldr.call (gcd, (x_sub_y, y,), "tmp") +bldr.ret (recur_2) + +print(module) +{% endhighlight %} diff --git a/docs/source/doc/functions.md b/docs/source/doc/functions.md new file mode 100644 index 0000000..0f88262 --- /dev/null +++ b/docs/source/doc/functions.md @@ -0,0 +1,198 @@ +--- +layout: page +title: Functions +--- + +Functions are represented by [llvm.core.Function][] objects. +They are contained within modules, and can be created either with the method +`module_obj.add_function` or the static constructor `Function.new`. +References to functions already present in a module can be retrieved via +`module.get_function_named` or by the static constructor method +`Function.get`. All functions in a module can be enumerated by iterating +over `module_obj.functions`. + +{% highlight python %} +# create a type, representing functions that take an integer and return +# a floating point value. +ft = Type.function( Type.float(), [ Type.int() ] ) + +# create a function of this type +f1 = module_obj.add_function(ft, "func1") + +# or equivalently, like this: +f2 = Function.new(module_obj, ft, "func2") + +# get a reference to an existing function +f3 = module_obj.get_function_named("func3") + +# or like this: +f4 = Function.get(module_obj, "func4") + +# list all function names in a module +for f in module_obj.functions: + print f.name +{% endhighlight %} + + +# Intrinsic + +References to intrinsic functions can be got via the static constructor +`intrinsic`. This returns a `Function` object, calling which is +equivalent to invoking the intrinsic. The `intrinsic` method has to be +called with a module object, an intrinsic ID (which is a numeric +constant) and a list of the types of arguments (which LLVM uses to +resolve overloaded intrinsic functions). + +{% highlight python %} +# get a reference to the llvm.bswap intrinsic +bswap = Function.intrinsic(mod, INTR_BSWAP, [Type.int()]) + +# call it +builder.call(bswap, [value]) +{% endhighlight %} + +Here, the constant `INTR_BSWAP`, available from `llvm.core`, represents the +LLVM intrinsic [llvm.bswap](http://www.llvm.org/docs/LangRef.html#int_bswap). +The `[Type.int()]` selects the version of `llvm.bswap` that has a single 32-bit +integer argument. The list of intrinsic IDs defined as integer constants +in `llvm.core`. These are: + +{% include intrinsics.csv %} + +There are also target-specific intrinsics (which correspond to that +target's CPU instructions) available, but are omitted here for brevity. +Full list can be seen from +[_intrinsic_ids.py](https://github.com/numba/llvm-py/blob/master/llvm/_intrinsic_ids.py). +See the [LLVM Language Reference](http://www.llvm.org/docs/LangRef.html) +for more information on the intrinsics, and the +[test](https://github.com/numba/llvm-py/blob/master/test/intrinsic.py) +directory in the source distribution for more examples. The intrinsic ID +can be retrieved from a function object with the read-only property +`intrinsic_id`. + +> **Auto-generation of Intrinsic IDs** +> +> +> A script (tool/intrgen.py in source tree) generates the intrinsic IDs +> automatically. This is necessary when compiling llvm-py with a different +> version of LLVM. + +# Calling Convention # {#callconv} +The function's calling convention can be set using the +`calling_convention` property. The following (integer) constants defined +in `llvm.core` can be used as values: + +Value | Equivalent LLVM Assembly Keyword | +------|----------------------------------| +`CC_C` | `ccc` | +`CC_FASTCALL` | `fastcc` | +`CC_COLDCALL` | `coldcc` | +`CC_X86_STDCALL` | `x86_stdcallcc` | +`CC_X86_FASTCALL` | `x86_fastcallcc` | + +See the [LLVM docs](http://www.llvm.org/docs/LangRef.html#callingconv) for +more information on each. Backend-specific numbered conventions can be +directly passed as integers. + +An arbitrary string identifying which garbage collector to use can be +set or got with the property `collector`. + +The value objects corresponding to the arguments of a function can be +got using the read-only property `args`. These can be iterated over, and +also be indexed via integers. An example: + +{% highlight python %} +# list all argument names and types +for arg in fn.args: + print arg.name, "of type", arg.type + +# change the name of the first argument +fn.args[0].name = "objptr" +{% endhighlight %} + +Basic blocks (see later) are contained within functions. When newly +created, a function has no basic blocks. They have to be added +explicitly, using the `append_basic_block` method, which adds a new, +empty basic block as the last one in the function. The first basic block +of the function can be retrieved using the `get_entry_basic_block` +method. The existing basic blocks can be enumerated by iterating over +using the read-only property `basic_blocks`. The number of basic blocks +can be got via `basic_block_count` method. Note that +`get_entry_basic_block` is slightly faster than `basic_blocks[0]` and so +is `basic_block_count`, over `len(f.basic_blocks)`. + +{% highlight python %} +# add a basic block +b1 = fn.append_basic_block("entry") + +# get the first one +b2 = fn.get_entry_basic_block() +b2 = fn.basic_mdblocks[0] # slower than previous method + +# print names of all basic blocks +for b in fn.basic_blocks: + print b.name + +# get number of basic blocks +n = fn.basic_block_count +n = len(fn.basic_blocks) # slower than previous method +{% endhighlight %} + +Functions can be deleted using the method `delete`. This deletes them +from their containing module. All references to the function object +should be dropped after `delete` has been called. + +Functions can be verified with the `verify` method. Note that this may +not work properly (aborts on errors). + +# Function Attributes # {#fnattr} +Function attributes, as documented +[here](http://www.llvm.org/docs/LangRef.html#fnattrs), can be +set on functions using the methods `add_attribute` and +`remove_attribute`. The following values may be used to refer to the +LLVM attributes: + + +Value | Equivalent LLVM Assembly Keyword | +------|----------------------------------| +`ATTR_ALWAYS_INLINE`|`alwaysinline` | +`ATTR_INLINE_HINT`|`inlinehint` | +`ATTR_NO_INLINE`|`noinline` | +`ATTR_OPTIMIZE_FOR_SIZE`|`optsize` | +`ATTR_NO_RETURN`|`noreturn` | +`ATTR_NO_UNWIND`|`nounwind` | +`ATTR_READ_NONE`|`readnone` | +`ATTR_READONLY`|`readonly` | +`ATTR_STACK_PROTECT`|`ssp` | +`ATTR_STACK_PROTECT_REQ`|`sspreq` | +`ATTR_NO_REDZONE`|`noredzone` | +`ATTR_NO_IMPLICIT_FLOAT`|`noimplicitfloat` | +`ATTR_NAKED`|`naked` | + + +Here is how attributes can be set and removed: + +{% highlight python %} +# create a function +ti = Type.int(32) +tf = Type.function(ti, [ti, ti]) +m = Module.new('mod') +f = m.add_function(tf, 'sum') +print f +# declare i32 @sum(i32, i32) + +# add a couple of attributes +f.add_attribute(ATTR_NO_UNWIND) +f.add_attribute(ATTR_READONLY) +print f +# declare i32 @sum(i32, i32) nounwind readonly +{% endhighlight %} + +**Related Links** + +[llvm.core.Function][], +[llvm.core.Argument][] + +[llvm.core.Function]: llvm.core.Function.html +[llvm.core.Argument]: llvm.core.Argument.html + diff --git a/docs/source/doc/kaleidoscope/PythonLangImpl1.md b/docs/source/doc/kaleidoscope/PythonLangImpl1.md new file mode 100644 index 0000000..4502432 --- /dev/null +++ b/docs/source/doc/kaleidoscope/PythonLangImpl1.md @@ -0,0 +1,330 @@ +--- +layout: page +title: "Kaleidoscope: Chapter 1" +--- + +# Tutorial Introduction and the Lexer + +Written by [Chris Lattner](mailto:sabre@nondot.org) +and [Max Shawabkeh](http://max99x.com) + +**Chapter 1** + + +* This will become a table of contents (this text will be scraped). +{:toc} + +[**Chapter 2: Implementing a Parser and AST**](PythonLangImpl2.html) + +# Introduction + +Welcome to the "Implementing a language with LLVM" tutorial. This tutorial +runs through the implementation of a simple language, showing how fun and +easy it can be. This tutorial will get you up and started as well as help to +build a framework you can extend to other languages. The code in this +tutorial can also be used as a playground to hack on other LLVM specific +things. + +It is useful to point out ahead of time that this tutorial is really about +teaching compiler techniques and LLVM specifically, *not* about teaching +modern and sane software engineering principles. In practice, this means that +we'll take a number of shortcuts to simplify the exposition. If you dig in and +use the code as a basis for future projects, fixing its deficiencies shouldn't +be hard. + + +We've tried to put this tutorial together in a way that makes chapters easy +to skip over if you are already familiar with or are uninterested in the +various pieces. The structure of the tutorial is: + +* **[Chapter 1](#language): Introduction to the Kaleidoscope language, +and the definition of its Lexer** -- This shows where we are going +and the basic functionality that we want it to do. In order to make this +tutorial maximally understandable and hackable, we choose to implement +everything in Python instead of using lexer and parser generators. LLVM +obviously works just fine with such tools, feel free to use one if you prefer. + +* **[Chapter 2](PythonLangImpl2.html): Implementing a Parser and AST** -- +With the lexer in place, we can talk about parsing techniques and +basic AST construction. This tutorial describes recursive descent parsing and +operator precedence parsing. Nothing in Chapters 1 or 2 is LLVM-specific, +the code doesn't even import the LLVM modules at this point. :) + +* **[Chapter 3](PythonLangImpl3.html): Code generation to LLVM IR** -- With +the AST ready, we can show off how easy generation of LLVM IR really is. + +* **[Chapter 4](PythonLangImpl4.html): Adding JIT and Optimizer support** -- +Because a lot of people are interested in using LLVM as a JIT, +we'll dive right into it and show you the 3 lines it takes to add JIT support. +LLVM is also useful in many other ways, but this is one simple and "sexy" way +to shows off its power. :) + +* **[Chapter 5](PythonLangImpl5.html): Extending the Language: Control Flow** + -- With the language up and running, we show how to extend it +with control flow operations (if/then/else and a 'for' loop). This gives us a +chance to talk about simple SSA construction and control flow. + +* **[Chapter 6](PythonLangImpl6.html): Extending the Language: +User-defined Operators** -- This is a silly but fun chapter that talks about +extending the language to let the user program define their own arbitrary +unary and binary operators (with assignable precedence!). This lets us build +a significant piece of the "language" as library routines. + +* **[Chapter 7](PythonLangImpl7.html): Extending the Language: +Mutable Variables** -- This chapter talks about adding user-defined local +variables along with an assignment operator. The interesting part about this +is how easy and trivial it is to construct SSA form in LLVM: no, LLVM does +*not* require your front-end to construct SSA form! + +* **[Chapter 8](PythonLangImpl8.html): Conclusion and other +useful LLVM tidbits** -- This chapter wraps up the series by talking about +potential ways to extend the language, but also includes a bunch of pointers to +info about "special topics" like adding garbage collection support, exceptions, +debugging, support for "spaghetti stacks", and a bunch of other tips and +tricks. + +By the end of the tutorial, we'll have written a bit less than 540 lines of +non-comment, non-blank, lines of code. With this small amount of code, we'll +have built up a very reasonable compiler for a non-trivial language including +a hand-written lexer, parser, AST, as well as code generation support with a JIT +compiler. While other systems may have interesting "hello world" tutorials, +I think the breadth of this tutorial is a great testament to the strengths of +LLVM and why you should consider it if you're interested in language or compiler +design. + +A note about this tutorial: we expect you to extend the language and play +with it on your own. Take the code and go crazy hacking away at it, compilers +don't need to be scary creatures - it can be a lot of fun to play with +languages! + +* * * + +# The Basic Language # {#language} + +This tutorial will be illustrated with a toy language that we'll call +"[Kaleidoscope](http://en.wikipedia.org/wiki/Kaleidoscope)" (derived +from "meaning beautiful, form, and view"). +Kaleidoscope is a procedural language that allows you to define functions, use +conditionals, math, etc. Over the course of the tutorial, we'll extend +Kaleidoscope to support the if/then/else construct, a for loop, user defined +operators, JIT compilation with a simple command line interface, etc. + +Because we want to keep things simple, the only datatype in Kaleidoscope is a +64-bit floating point type. As such, all values are implicitly double precision +and the language doesn't require type declarations. This gives the language a +very nice and simple syntax. For example, the following simple example computes +[Fibonacci numbers](http://en.wikipedia.org/wiki/Fibonacci_number): + +{% highlight python %} +# Compute the x'th fibonacci number. +def fib(x) + if x < 3 then + 1 + else + fib(x-1)+fib(x-2) + +# This expression will compute the 40th number. +fib(40) +{% endhighlight %} + + +We also allow Kaleidoscope to call into standard library functions (the LLVM +JIT makes this completely trivial). This means that you can use the 'extern' +keyword to define a function before you use it (this is also useful for mutually +recursive functions). For example: + +{% highlight python %} +extern sin(arg); +extern cos(arg); +extern atan2(arg1 arg2); + +atan2(sin(0.4), cos(42)) +{% endhighlight %} + + +A more interesting example is included in Chapter 6 where we write a little +Kaleidoscope application that [displays](PythonLangImpl6.html#example) +a Mandelbrot Set at various levels of magnification. + +Lets dive into the implementation of this language! + +* * * + +# The Lexer # {#lexer} + + +When it comes to implementing a language, the first thing needed is +the ability to process a text file and recognize what it says. +The traditional way to do this is to use a +[lexer](http://en.wikipedia.org/wiki/Lexical_analysis)" (aka 'scanner') +to break the input up into "tokens". Each token returned by the lexer includes +a token type and potentially some metadata (e.g. the numeric value of a number). +First, we define the possibilities: + + +{% highlight python %} +# The lexer yields one of these types for each token. +class EOFToken(object): + pass + +class DefToken(object): + pass + +class ExternToken(object): + pass + +class IdentifierToken(object): + def __init__(self, name): self.name = name + +class NumberToken(object): + def __init__(self, value): self.value = value + +class CharacterToken(object): + def __init__(self, char): self.char = char + def __eq__(self, other): + return isinstance(other, CharacterToken) and self.char == other.char + def __ne__(self, other): return not self == other +{% endhighlight %} + + +Each token yielded by our lexer will be of one of the above types. For simple +tokens that are always the same, like the "def" keyword, the lexer will yield +`DefToken()`>. Identifiers, numbers and characters, on the other +hand, have extra data, so when the lexer encounteres the number 123.45, it will +emit it as `NumberToken(123.45)`. An identifier `foo` will be +emitted as `IdentifierToken('foo')`. And finally, an unknown character +like '+' will be returned as `CharacterToken('+')`. You may notice that +we overload the equality and inequality operators for the characters; this will +later simplify character comparisons in the parser code. + +The actual implementation of the lexer is a single function called `Tokenize`, +which takes a string and +[yields](http://docs.python.org/reference/simple_stmts.html#the-yield-statement) +tokens. For simplicity, we will use +[regular expressions](http://docs.python.org/library/re.html) +to parse out the tokens. This is terribly inefficient, but +perfectly sufficient for our needs. + +First, we define the regular expressions for our tokens. Numbers and strings +of digits, optionally followed by a period and another string of digits. +Identifiers (and keywords) are alphanumeric string starting with a letter and +comments are anything between a hash (`#`) and the end of the line. + + +{% highlight python %} +import re + +... + +# Regular expressions that tokens and comments of our language. +REGEX_NUMBER = re.compile('[0-9]+(?:\.[0-9]+)?') +REGEX_IDENTIFIER = re.compile('[a-zA-Z][a-zA-Z0-9]*') +REGEX_COMMENT = re.compile('#.*') + +{% endhighlight %} + +Next, let's start defining the `Tokenize` function itself. The first +thing we need to do is set up a loop that scans the string, while ignoring +whitespace between tokens: + + +{% highlight python %} +def Tokenize(string): + while string: + # Skip whitespace. + if string[0].isspace(): + string = string[1:] + continue + + ... + +{% endhighlight %} + +Next we want to find out what the next token is. For this we run the regexes +we defined above on the remainder of the string. To simplify the rest of the +code, we run all three regexes each time. As mentioned above, inefficiencies are +ignored for the purpose of this tutorial: + + +{% highlight python %} + # Run regexes. + comment_match = REGEX_COMMENT.match(string) + number_match = REGEX_NUMBER.match(string) + identifier_match = REGEX_IDENTIFIER.match(string) +{% endhighlight %} + + +Now se check if any of the regexes matched. For comments, we simply +ignore the captured match: + + +{% highlight python %} + # Check if any of the regexes matched and yield the appropriate result. + if comment_match: + comment = comment_match.group(0) + string = string[len(comment):] +{% endhighlight python %} + +For numbers, we yield the captured match, converted to a float and tagged +with the appropriate token type: + + + +{% highlight python %} + elif number_match: + number = number_match.group(0) + yield NumberToken(float(number)) + string = string[len(number):] +{% endhighlight %} + +The identifier case is a little more complex. We have to check for keywords +to decide whether we have captured an identifier or a keyword: + + +{% highlight python %} + elif identifier_match: + identifier = identifier_match.group(0) + # Check if we matched a keyword. + if identifier == 'def': + yield DefToken() + elif identifier == 'extern': + yield ExternToken() + else: + yield IdentifierToken(identifier) + string = string[len(identifier):] +{% endhighlight %} + +Finally, if we haven't recognized a comment, a number of an identifier, we +yield the current character as an "unknown character" token. This is used, for +example, for operators like `+` or `*`: + + +{% highlight python %} + else: + # Yield the unknown character. + yield CharacterToken(string[0]) + string = string[1:] +{% endhighlight %} + +Once we're done with the loop, we return a final end-of-file token: + + +{% highlight python %} + yield EOFToken() +{% endhighlight %} + + +With this, we have the complete lexer for the basic Kaleidoscope language +(the [full code listing](PythonLangImpl2.html#code) for the Lexer is +available in the [next chapter](PythonLangImpl2.html) of the +tutorial). Next we'll [build a simple parser that +uses this to build an Abstract Syntax Tree](PythonLangImpl2.html). +When we have that, we'll +include a driver so that you can use the lexer and parser together. + +* * * + +**[Next: Implementing a Parser and AST](PythonLangImpl2.html)** + + + diff --git a/docs/source/doc/kaleidoscope/PythonLangImpl2.md b/docs/source/doc/kaleidoscope/PythonLangImpl2.md new file mode 100644 index 0000000..143894c --- /dev/null +++ b/docs/source/doc/kaleidoscope/PythonLangImpl2.md @@ -0,0 +1,998 @@ +--- +layout: page +title: "Kaleidoscope: Chapter 2" +--- + +# Implementing a Parser and AST + +Written by [Chris Lattner](mailto:sabre@nondot.org) +and [Max Shawabkeh](http://max99x.com) + + +**Chapter 2** + + +* This will become a table of contents (this text will be scraped). +{:toc} + + +**[Chapter 3: Code generation to LLVM IR](PythonLangImpl3.html)** + + +# Introduction # {#intro} + +Welcome to Chapter 2 of the +[Implementing a language with LLVM](http://www.llvm.org/docs/tutorial/index.html) +tutorial. +This chapter shows you how to use the lexer, built in +[Chapter 1](PythonLangImpl1.html), to build a full +[parser](http://en.wikipedia.org/wiki/Parsing) for +our Kaleidoscope language. Once we have a parser, we'll define and build an +[Abstract Syntax Tree](http://en.wikipedia.org/wiki/Abstract_syntax_tree) +(AST). + +The parser we will build uses a combination of [Recursive Descent +Parsing](http://en.wikipedia.org/wiki/Recursive_descent_parser) and +[Operator-Precedence Parsing](http://en.wikipedia.org/wiki/Operator-precedence_parser) +to parse the Kaleidoscope language (the latter for +binary expressions and the former for everything else). Before we get to +parsing though, lets talk about the output of the parser: the Abstract Syntax +Tree. + +* * * + + +# The Abstract Syntax Tree (AST) # {#ast} + +The AST for a program captures its behavior in such a way that it is easy for +later stages of the compiler (e.g. code generation) to interpret. We basically +want one object for each construct in the language, and the AST should closely +model the language. In Kaleidoscope, we have expressions, a prototype, and a +function object. We'll start with expressions first: + +{% highlight python %} +# Base class for all expression nodes. +class ExpressionNode(object): + pass + +# Expression class for numeric literals like "1.0". +class NumberExpressionNode(ExpressionNode): + def __init__(self, value): + self.value = value + +{% endhighlight %} + +The code above shows the definition of the base ExpressionNode class and one +subclass which we use for numeric literals. The important thing to note about +this code is that the NumberExpressionNode class captures the numeric value of +the literal as an instance variable. This allows later phases of the compiler to +know what the stored numeric value is. + +Right now we only create the AST, so there are no useful methods on them. +It would be very easy to add a virtual method to pretty print the code, for +example. Here are the other expression AST node definitions that we'll use +in the basic form of the Kaleidoscope language: + +{% highlight python %} +# Expression class for referencing a variable, like "a". +class VariableExpressionNode(ExpressionNode): + def __init__(self, name): + self.name = name + +# Expression class for a binary operator. +class BinaryOperatorExpressionNode(ExpressionNode): + def __init__(self, operator, left, right): + self.operator = operator + self.left = left + self.right = right + +# Expression class for function calls. +class CallExpressionNode(ExpressionNode): + def __init__(self, callee, args): + self.callee = callee + self.args = args +{% endhighlight %} + +This is all (intentionally) rather straight-forward: variables capture the +variable name, binary operators capture their opcode (e.g. '+'), and calls +capture a function name as well as a list of any argument expressions. One thing +that is nice about our AST is that it captures the language features without +talking about the syntax of the language. Note that there is no discussion about +precedence of binary operators, lexical structure, etc. + +For our basic language, these are all of the expression nodes we'll define. +Because it doesn't have conditional control flow, it isn't Turing-complete; +we'll fix that in a later installment. The two things we need next are a way +to talk about the interface to a function, and a way to talk about functions +themselves: + + +{% highlight python %} +# This class represents the "prototype" for a function, which captures its name, +# and its argument names (thus implicitly the number of arguments the function +# takes). +class PrototypeNode(object): + def __init__(self, name, args): + self.name = name + self.args = args + +# This class represents a function definition itself. +class FunctionNode(object): + def __init__(self, prototype, body): + self.prototype = prototype + self.body = body +{% endhighlight %} + +In Kaleidoscope, functions are typed with just a count of their arguments. +Since all values are double precision floating point, the type of each argument +doesn't need to be stored anywhere. In a more aggressive and realistic +language, the `ExpressionNode` class would probably have a type field. + +With this scaffolding, we can now talk about parsing expressions and function +bodies in Kaleidoscope. + +* * * + + +# Parser Basics # {#parserbasics} + +Now that we have an AST to build, we need to define the parser code to build +it. The idea here is that we want to parse something like `x + y` (which +is returned as three tokens by the lexer) into an AST that could be generated +with calls like this: + +{% highlight python %} + x = VariableExpressionNode('x') + y = VariableExpressionNode('y') + result = BinaryOperatorExpressionNode('+', x, y) +{% endhighlight %} + +In order to do this, we'll start by defining a lightweight `Parser` +class with some basic helper routines: + +{% highlight python %} +class Parser(object): + + def __init__(self, tokens, binop_precedence): + self.tokens = tokens + self.binop_precedence = binop_precedence + self.Next() + + # Provide a simple token buffer. Parser.current is the current token the + # parser is looking at. Parser.Next() reads another token from the lexer and + # updates Parser.current with its results. + def Next(self): + self.current = self.tokens.next() +{% endhighlight %} + + +This implements a simple token buffer around the lexer. This allows +us to look one token ahead at what the lexer is returning. Every function in +our parser will assume that `self.current` is the current token that +needs to be parsed. Note that the first token is read as soon as the parser is +instantiated. Let us ignore the `binop_precedence` parameter for now. It +will be explained when we start [parsing binary operators](#parserbinops). + +With these basic helper functions, we can implement the first +piece of our grammar: numeric literals. + +* * * + +# Basic Expression Parsing # {#parserprimexprs} + +We start with numeric literals, because they are the simplest to process. +For each production in our grammar, we'll define a function which parses that +production. For numeric literals, we have: + +{% highlight python %} + # numberexpr ::= number + def ParseNumberExpr(self): + result = NumberExpressionNode(self.current.value) + self.Next() # consume the number. + return result +{% endhighlight %} + + +This method is very simple: it expects to be called when the current token +is a `NumberToken`. It takes the current number value, creates a +`NumberExpressionNode`, advances to the next token, and finally returns. + + +There are some interesting aspects to this. The most important one is that +this routine eats all of the tokens that correspond to the production and +returns the lexer buffer with the next token (which is not part of the grammar +production) ready to go. This is a fairly standard way to go for recursive +descent parsers. For a better example, the parenthesis operator is defined like +this: + +{% highlight python %} + # parenexpr ::= '(' expression ')' + def ParseParenExpr(self): + self.Next() # eat '('. + + contents = self.ParseExpression() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")".') + self.Next() # eat ')'. + + return contents +{% endhighlight %} + + +This function illustrates an interesting aspect of the parser. The function +uses recursion by calling `ParseExpression` (we will soon see that +`ParseExpression` can call `ParseParenExpr`). This is powerful +because it allows us to handle recursive grammars, and keeps each production +very simple. Note that parentheses do not cause construction of AST nodes +themselves. While we could do it this way, the most important role of +parentheses are to guide the parser and provide grouping. Once the parser +constructs the AST, parentheses are not needed. + +The next simple production is for handling variable references and function +calls: + +{% highlight python %} + # identifierexpr ::= identifier | identifier '(' expression* ')' + def ParseIdentifierExpr(self): + identifier_name = self.current.name + self.Next() # eat identifier. + + if self.current != CharacterToken('('): # Simple variable reference. + return VariableExpressionNode(identifier_name); + + # Call. + self.Next() # eat '('. + args = [] + if self.current != CharacterToken(')'): + while True: + args.append(self.ParseExpression()) + if self.current == CharacterToken(')'): + break + elif self.current != CharacterToken(','): + raise RuntimeError('Expected ")" or "," in argument list.') + self.Next() + + self.Next() # eat ')'. + return CallExpressionNode(identifier_name, args) +{% endhighlight %} + + +This routine follows the same style as the other routines. It expects to be +called if the current token is an `IdentifierToken`. It also has +recursion and error handling. One interesting aspect of this is that it uses +*look-ahead* to determine if the current identifier is a stand alone +variable reference or if it is a function call expression. It handles this by +checking to see if the token after the identifier is a '(' token, constructing +either a `VariableExpressionNode` or `CallExpressionNode` as +appropriate. + +Now that we have all of our simple expression-parsing logic in place, we can +define a helper function to wrap it together into one entry point. We call this +class of expressions "primary" expressions, for reasons that will become more +clear [later in the tutorial](PythonLangImpl6.html#unary). In order +to parse an arbitrary primary expression, we need to determine what sort of +expression it is: + +{% highlight python %} + # primary ::= identifierexpr | numberexpr | parenexpr + def ParsePrimary(self): + if isinstance(self.current, IdentifierToken): + return self.ParseIdentifierExpr() + elif isinstance(self.current, NumberToken): + return self.ParseNumberExpr(); + elif self.current == CharacterToken('('): + return self.ParseParenExpr() + else: + raise RuntimeError('Unknown token when expecting an expression.') +{% endhighlight %} + + +Now that you see the definition of this function, it is more obvious why we +can assume the state of `Parser.current` in the various functions. This +uses look-ahead to determine which sort of expression is being inspected, and +then parses it with a function call. + +Now that basic expressions are handled, we need to handle binary expressions. +They are a bit more complex. + + + + +* * * + +# Binary Expression Parsing # {#parserbinops} + +Binary expressions are significantly harder to parse because they are often +ambiguous. For example, when given the string `x+y*z`, the parser can choose +to parse it as either `(x+y)*z` or `x+(y*z)`. With common definitions from +mathematics, we expect the later parse, because `*` (multiplication) has +higher *precedence* than `+` (addition). + +There are many ways to handle this, but an elegant and efficient way is +to use [Operator-Precedence Parsing](http://en.wikipedia.org/wiki/Operator-precedence_parser). +This parsing technique uses the precedence of binary operators to +guide recursion. To start with, we need a table of precedences. Remember the +`binop_precedence` parameter we passed to the `Parser` +constructor? Now is the time to use it: + +{% highlight python %} +def main(): + # Install standard binary operators. + # 1 is lowest possible precedence. 40 is the highest. + operator_precedence = { + '<': 10, + '+': 20, + '-': 20, + '*': 40 + } + + # Run the main `interpreter loop`. + while True: + + ... + + parser = Parser(Tokenize(raw), operator_precedence) + +{% endhighlight %} + +For the basic form of Kaleidoscope, we will only support 4 binary operators +(this can obviously be extended by you, our brave and intrepid reader). Having a +dictionary makes it easy to add new operators and makes it clear that the +algorithm doesn't depend on the specific operators involved, but it would be +easy enough to eliminate the map and hardcode the comparisons. + +We also define a helper function to get the precedence of the current token, +or -1 if the token is not a binary operator: + + +{% highlight python %} + # Gets the precedence of the current token, or -1 if the token is not a binary + # operator. + def GetCurrentTokenPrecedence(self): + if isinstance(self.current, CharacterToken): + return self.binop_precedence.get(self.current.char, -1) + else: + return -1 +{% endhighlight %} + +With the helper above defined, we can now start parsing binary expressions. +The basic idea of operator precedence parsing is to break down an expression +with potentially ambiguous binary operators into pieces. Consider, for example, +the expression `a+b+(c+d)*e*f+g`. Operator precedence parsing considers this +as a stream of primary expressions separated by binary operators. As such, +it will first parse the leading primary expression `a`, then it will see the +pairs `[+, b] [+, (c+d)] [*, e] [*, f] and [+, g]`. Note that because parentheses +are primary expressions, the binary expression parser doesn't need to worry +about nested subexpressions like (c+d) at all. + + + +To start, an expression is a primary expression potentially followed by a +sequence of `[binop,primaryexpr]` pairs: + +{% highlight python %} + # expression ::= primary binoprhs + def ParseExpression(self): + left = self.ParsePrimary() + return self.ParseBinOpRHS(left, 0) +{% endhighlight %} + +`ParseBinOpRHS` is the function that parses the sequence of pairs for +us. It takes a precedence and a pointer to an expression for the part that has +been parsed so far. Note that `x` is a perfectly valid expression: As such, +`binoprhs` is allowed to be empty, in which case it returns the expression that +is passed into it. In our example above, the code passes the expression for `a` +into `ParseBinOpRHS` and the current token is `+`. + +The precedence value passed into `ParseBinOpRHS` indicates the * +minimal operator precedence* that the function is allowed to eat. For +example, if the current pair stream is `[+, x]` and `ParseBinOpRHS` is +passed in a precedence of 40, it will not consume any tokens (because the +precedence of '+' is only 20). With this in mind, `ParseBinOpRHS` starts +with: + +{% highlight python %} + # binoprhs ::= (operator primary)* + def ParseBinOpRHS(self, left, left_precedence): + # If this is a binary operator, find its precedence. + while True: + precedence = self.GetCurrentTokenPrecedence() + + # If this is a binary operator that binds at least as tightly as the + # current one, consume it; otherwise we are done. + if precedence < left_precedence: + return left +{% endhighlight %} + +This code gets the precedence of the current token and checks to see if if is +too low. Because we defined invalid tokens to have a precedence of -1, this +check implicitly knows that the pair-stream ends when the token stream runs out +of binary operators. If this check succeeds, we know that the token is a binary +operator and that it will be included in this expression: + +{% highlight python %} + binary_operator = self.current.char + self.Next() # eat the operator. + + # Parse the primary expression after the binary operator. + right = self.ParsePrimary() +{% endhighlight %} + +As such, this code eats (and remembers) the binary operator and then parses +the primary expression that follows. This builds up the whole pair, the first of +which is `[+, b]` for the running example. + +Now that we parsed the left-hand side of an expression and one pair of the +RHS sequence, we have to decide which way the expression associates. In +particular, we could have `(a+b) binop unparsed` or `a + (b binop unparsed)`. +To determine this, we look ahead at `binop` to determine its precedence and +compare it to BinOp's precedence (which is '+' in this case): + + +{% highlight python %} + # If binary_operator binds less tightly with right than the operator after + # right, let the pending operator take right as its left. + next_precedence = self.GetCurrentTokenPrecedence() + if precedence < next_precedence: +{% endhighlight %} + +If the precedence of the binop to the right of `RHS` is lower or equal to the +precedence of our current operator, then we know that the parentheses associate +as `(a+b) binop ...`. In our example, the current operator is `+` and the next +operator is `+`, we know that they have the same precedence. In this case we'll +create the AST node for `a+b`, and then continue parsing: + +{% highlight python %} + if precedence < next_precedence: + ... if body omitted ... + + # Merge left/right. + left = BinaryOperatorExpressionNode(binary_operator, left, right); +{% endhighlight %} + +In our example above, this will turn `a+b+` into `(a+b)` and execute the next +iteration of the loop, with `+` as the current token. The code above will eat, +remember, and parse `(c+d)` as the primary expression, which makes the +current pair equal to `[+, (c+d)]`. It will then evaluate the 'if' conditional +above with `*` as the binop to the right of the primary. In this case, the +precedence of `*` is higher than the precedence of `+` so the if condition will +be entered. + +The critical question left here is `how can the if condition parse the right +hand side in full`? In particular, to build the AST correctly for our example, +it needs to get all of ` ( c + d ) * e * f` as the RHS expression variable. The code to +do this is surprisingly simple (code from the above two blocks duplicated for +context): + +{% highlight python %} + # If binary_operator binds less tightly with right than the operator after + # right, let the pending operator take right as its left. + next_precedence = self.GetCurrentTokenPrecedence() + if precedence < next_precedence: + right = self.ParseBinOpRHS(right, precedence + 1) + + # Merge left/right. + left = BinaryOperatorExpressionNode(binary_operator, left, right) +{% endhighlight %} + +At this point, we know that the binary operator to the RHS of our primary +has higher precedence than the binop we are currently parsing. As such, we know +that any sequence of pairs whose operators are all higher precedence than `+` +should be parsed together and returned as `RHS`. To do this, we recursively +invoke the `ParseBinOpRHS` function specifying `precedence + 1` as the +minimum precedence required for it to continue. In our example above, this +will cause it to return the AST node for `(c+d)*e*f` as RHS, which is then set +as the RHS of the '+' expression. + +Finally, on the next iteration of the while loop, the `+g` piece is parsed +and added to the AST. With this little bit of code (11 non-trivial lines), we +correctly handle fully general binary expression parsing in a very elegant way. +This was a whirlwind tour of this code, and it is somewhat subtle. I recommend +running through it with a few tough examples to see how it works. + + +This wraps up handling of expressions. At this point, we can point the +parser at an arbitrary token stream and build an expression from it, stopping +at the first token that is not part of the expression. Next up we need to +handle function definitions, etc. + + +* * * + +# Parsing the Rest # {#parsertop} + + +The next thing missing is handling of function prototypes. In Kaleidoscope, +these are used both for 'extern' function declarations as well as function body +definitions. The code to do this is straight-forward and not very interesting +(once you've survived expressions): + +{% highlight python %} + # prototype ::= id '(' id* ')' + def ParsePrototype(self): + if not isinstance(self.current, IdentifierToken): + raise RuntimeError('Expected function name in prototype.') + + function_name = self.current.name + self.Next() # eat function name. + + if self.current != CharacterToken('('): + raise RuntimeError('Expected "(" in prototype.') + self.Next() # eat '('. + + arg_names = [] + while isinstance(self.current, IdentifierToken): + arg_names.append(self.current.name) + self.Next() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")" in prototype.') + + # Success. + self.Next() # eat ')'. + + return PrototypeNode(function_name, arg_names) +{% endhighlight %} + + +Given this, a function definition is very simple, just a prototype plus +an expression to implement the body: + + +{% highlight python %} + # definition ::= 'def' prototype expression + def ParseDefinition(self): + self.Next() # eat def. + proto = self.ParsePrototype() + body = self.ParseExpression() + return FunctionNode(proto, body) +{% endhighlight %} + + +In addition, we support 'extern' to declare functions like 'sin' and 'cos' as +well as to support forward declaration of user functions. These 'extern's are +just prototypes with no body: + + +{% highlight python %} + # external ::= 'extern' prototype + def ParseExtern(self): + self.Next() # eat extern. + return self.ParsePrototype() +{% endhighlight %} + + +Finally, we'll also let the user type in arbitrary top-level expressions and +evaluate them on the fly. We will handle this by defining anonymous nullary +(zero argument) functions for them: + + +{% highlight python %} + # toplevelexpr ::= expression + def ParseTopLevelExpr(self): + proto = PrototypeNode('', []) + return FunctionNode(proto, self.ParseExpression()) +{% endhighlight %} + + +Now that we have all the pieces, let's build a little driver that will let us +actually *execute* this code we've built! + + + +* * * + +# The Driver # {#driver} + + +The driver for this simply invokes all of the parsing pieces with a top-level +dispatch loop. There isn't much interesting here, so I'll just include the +top-level loop. See [below](#code) for full code. + + +{% highlight python %} + # Run the main "interpreter loop". + while True: + print 'ready>', + try: + raw = raw_input() + except KeyboardInterrupt: + return + + parser = Parser(Tokenize(raw), operator_precedence) + while True: + # top ::= definition | external | expression | EOF + if isinstance(parser.current, EOFToken): + break + if isinstance(parser.current, DefToken): + parser.HandleDefinition() + elif isinstance(parser.current, ExternToken): + parser.HandleExtern() + else: + parser.HandleTopLevelExpression() +{% endhighlight %} + + +Here we create a new `Parser` for each line read, and try to parse out +all the expressions, declarations and definitions in the line. We also allow the +user to quit using Ctrl+C. + + + +* * * + +# Conclusions # {#conclusions} + + +With just under 330 lines of commented code (200 lines of non-comment, +non-blank code), we fully defined our minimal language, including a lexer, +parser, and AST builder. With this done, the executable will validate +Kaleidoscope code and tell us if it is grammatically invalid. For +example, here is a sample interaction: + + +{% highlight python %} +$ python kaleidoscope.py +ready> def foo(x y) x+foo(y, 4.0) +Parsed a function definition. +ready> def foo(x y) x+y y +Parsed a function definition. +Parsed a top-level expression. +ready> def foo(x y) x+y ) +Parsed a function definition. +Error: Unknown token when expecting an expression. +ready> extern sin(a); +Parsed an extern. +ready> ^C +$ +{% endhighlight %} + +There is a lot of room for extension here. You can define new AST nodes, +extend the language in many ways, etc. In the +[next installment](PythonLangImpl3.html), we will describe how to +generate LLVM Intermediate Representation (IR) from the AST. + + +* * * + +# Full Code Listing # {#code} + + +Here is the complete code listing for this and the previous chapter. +Note that it is fully self-contained: you don't need LLVM or any external +libraries at all for this. + + +{% highlight python %} +#!/usr/bin/env python + +import re + +################################################################################ +## Lexer +################################################################################ + +# The lexer yields one of these types for each token. +class EOFToken(object): + pass + +class DefToken(object): + pass + +class ExternToken(object): + pass + +class IdentifierToken(object): + def __init__(self, name): self.name = name + +class NumberToken(object): + def __init__(self, value): self.value = value + +class CharacterToken(object): + def __init__(self, char): self.char = char + def __eq__(self, other): + return isinstance(other, CharacterToken) and self.char == other.char + def __ne__(self, other): return not self == other + +# Regular expressions that tokens and comments of our language. +REGEX_NUMBER = re.compile('[0-9]+(?:\.[0-9]+)?') +REGEX_IDENTIFIER = re.compile('[a-zA-Z][a-zA-Z0-9]*') +REGEX_COMMENT = re.compile('#.*') + +def Tokenize(string): + while string: + # Skip whitespace. + if string[0].isspace(): + string = string[1:] + continue + + # Run regexes. + comment_match = REGEX_COMMENT.match(string) + number_match = REGEX_NUMBER.match(string) + identifier_match = REGEX_IDENTIFIER.match(string) + + # Check if any of the regexes matched and yield the appropriate result. + if comment_match: + comment = comment_match.group(0) + string = string[len(comment):] + elif number_match: + number = number_match.group(0) + yield NumberToken(float(number)) + string = string[len(number):] + elif identifier_match: + identifier = identifier_match.group(0) + # Check if we matched a keyword. + if identifier == 'def': + yield DefToken() + elif identifier == 'extern': + yield ExternToken() + else: + yield IdentifierToken(identifier) + string = string[len(identifier):] + else: + # Yield the ASCII value of the unknown character. + yield CharacterToken(string[0]) + string = string[1:] + + yield EOFToken() + +################################################################################ +## Abstract Syntax Tree (aka Parse Tree) +################################################################################ + +# Base class for all expression nodes. +class ExpressionNode(object): + pass + +# Expression class for numeric literals like "1.0". +class NumberExpressionNode(ExpressionNode): + def __init__(self, value): + self.value = value + +# Expression class for referencing a variable, like "a". +class VariableExpressionNode(ExpressionNode): + def __init__(self, name): + self.name = name + +# Expression class for a binary operator. +class BinaryOperatorExpressionNode(ExpressionNode): + def __init__(self, operator, left, right): + self.operator = operator + self.left = left + self.right = right + +# Expression class for function calls. +class CallExpressionNode(ExpressionNode): + def __init__(self, callee, args): + self.callee = callee + self.args = args + +# This class represents the "prototype" for a function, which captures its name, +# and its argument names (thus implicitly the number of arguments the function +# takes). +class PrototypeNode(object): + def __init__(self, name, args): + self.name = name + self.args = args + +# This class represents a function definition itself. +class FunctionNode(object): + def __init__(self, prototype, body): + self.prototype = prototype + self.body = body + + +################################################################################ +## Parser +################################################################################ + +class Parser(object): + + def __init__(self, tokens, binop_precedence): + self.tokens = tokens + self.binop_precedence = binop_precedence + self.Next() + + # Provide a simple token buffer. Parser.current is the current token the + # parser is looking at. Parser.Next() reads another token from the lexer and + # updates Parser.current with its results. + def Next(self): + self.current = self.tokens.next() + + # Gets the precedence of the current token, or -1 if the token is not a binary + # operator. + def GetCurrentTokenPrecedence(self): + if isinstance(self.current, CharacterToken): + return self.binop_precedence.get(self.current.char, -1) + else: + return -1 + + # identifierexpr ::= identifier | identifier '(' expression* ')' + def ParseIdentifierExpr(self): + identifier_name = self.current.name + self.Next() # eat identifier. + + if self.current != CharacterToken('('): # Simple variable reference. + return VariableExpressionNode(identifier_name) + + # Call. + self.Next() # eat '('. + args = [] + if self.current != CharacterToken(')'): + while True: + args.append(self.ParseExpression()) + if self.current == CharacterToken(')'): + break + elif self.current != CharacterToken(','): + raise RuntimeError('Expected ")" or "," in argument list.') + self.Next() + + self.Next() # eat ')'. + return CallExpressionNode(identifier_name, args) + + # numberexpr ::= number + def ParseNumberExpr(self): + result = NumberExpressionNode(self.current.value) + self.Next() # consume the number. + return result + + # parenexpr ::= '(' expression ')' + def ParseParenExpr(self): + self.Next() # eat '('. + + contents = self.ParseExpression() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")".') + self.Next() # eat ')'. + + return contents + + # primary ::= identifierexpr | numberexpr | parenexpr + def ParsePrimary(self): + if isinstance(self.current, IdentifierToken): + return self.ParseIdentifierExpr() + elif isinstance(self.current, NumberToken): + return self.ParseNumberExpr() + elif self.current == CharacterToken('('): + return self.ParseParenExpr() + else: + raise RuntimeError('Unknown token when expecting an expression.') + + # binoprhs ::= (operator primary)* + def ParseBinOpRHS(self, left, left_precedence): + # If this is a binary operator, find its precedence. + while True: + precedence = self.GetCurrentTokenPrecedence() + + # If this is a binary operator that binds at least as tightly as the + # current one, consume it; otherwise we are done. + if precedence < left_precedence: + return left + + binary_operator = self.current.char + self.Next() # eat the operator. + + # Parse the primary expression after the binary operator. + right = self.ParsePrimary() + + # If binary_operator binds less tightly with right than the operator after + # right, let the pending operator take right as its left. + next_precedence = self.GetCurrentTokenPrecedence() + if precedence < next_precedence: + right = self.ParseBinOpRHS(right, precedence + 1) + + # Merge left/right. + left = BinaryOperatorExpressionNode(binary_operator, left, right) + + # expression ::= primary binoprhs + def ParseExpression(self): + left = self.ParsePrimary() + return self.ParseBinOpRHS(left, 0) + + # prototype ::= id '(' id* ')' + def ParsePrototype(self): + if not isinstance(self.current, IdentifierToken): + raise RuntimeError('Expected function name in prototype.') + + function_name = self.current.name + self.Next() # eat function name. + + if self.current != CharacterToken('('): + raise RuntimeError('Expected "(" in prototype.') + self.Next() # eat '('. + + arg_names = [] + while isinstance(self.current, IdentifierToken): + arg_names.append(self.current.name) + self.Next() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")" in prototype.') + + # Success. + self.Next() # eat ')'. + + return PrototypeNode(function_name, arg_names) + + # definition ::= 'def' prototype expression + def ParseDefinition(self): + self.Next() # eat def. + proto = self.ParsePrototype() + body = self.ParseExpression() + return FunctionNode(proto, body) + + # toplevelexpr ::= expression + def ParseTopLevelExpr(self): + proto = PrototypeNode('', []) + return FunctionNode(proto, self.ParseExpression()) + + # external ::= 'extern' prototype + def ParseExtern(self): + self.Next() # eat extern. + return self.ParsePrototype() + + # Top-Level parsing + def HandleDefinition(self): + self.Handle(self.ParseDefinition, 'Parsed a function definition.') + + def HandleExtern(self): + self.Handle(self.ParseExtern, 'Parsed an extern.') + + def HandleTopLevelExpression(self): + self.Handle(self.ParseTopLevelExpr, 'Parsed a top-level expression.') + + def Handle(self, function, message): + try: + function() + print message + except Exception, e: + print 'Error:', e + try: + self.Next() # Skip for error recovery. + except: + pass + +################################################################################ +## Main driver code. +################################################################################ + +def main(): + # Install standard binary operators. + # 1 is lowest possible precedence. 40 is the highest. + operator_precedence = { + '<': 10, + '+': 20, + '-': 20, + '*': 40 + } + + # Run the main "interpreter loop". + while True: + print 'ready>', + try: + raw = raw_input() + except KeyboardInterrupt: + return + + parser = Parser(Tokenize(raw), operator_precedence) + while True: + # top ::= definition | external | expression | EOF + if isinstance(parser.current, EOFToken): + break + if isinstance(parser.current, DefToken): + parser.HandleDefinition() + elif isinstance(parser.current, ExternToken): + parser.HandleExtern() + else: + parser.HandleTopLevelExpression() + +if __name__ == '__main__': + main() +{% endhighlight %} + + +* * * + +**[Next: Implementing Code Generation to LLVM IR](PythonLangImpl3.html)** diff --git a/docs/source/doc/kaleidoscope/PythonLangImpl3.md b/docs/source/doc/kaleidoscope/PythonLangImpl3.md new file mode 100644 index 0000000..5045592 --- /dev/null +++ b/docs/source/doc/kaleidoscope/PythonLangImpl3.md @@ -0,0 +1,1062 @@ +--- +layout: page +title: "Kaleidoscope: Chapter 3" +--- + +# Code generation to LLVM IR + +Written by [Chris Lattner](mailto:sabre@nondot.org) +and [Max Shawabkeh](http://max99x.com) + + +**Chapter 3** + + +* This will become a table of contents (this text will be scraped). +{:toc} + + +**[Chapter 4: Adding JIT and Optimizer Support](PythonLangImpl4.html)** + + +# Introduction # {#intro} + +Welcome to Chapter 3 of the +[Implementing a language with LLVM](http://www.llvm.org/docs/tutorial/index.html) +tutorial. This chapter shows you how to transform the +[Abstract Syntax Tree](PythonLangImpl2.html), built in Chapter 2, into +LLVM IR. This will teach you a little bit about how LLVM does things, as well as +demonstrate how easy it is to use. It's much more work to build a lexer and +parser than it is to generate LLVM IR code. :) + + +**Please note**: the code in this chapter and later requires llvm-py 0.6 +and LLVM 2.7. Earlier versions will most likely not work with it. Also note +that you need to use a version of this tutorial that matches your llvm-py +release: If you are using an official llvm-py release, use the version of the +documentation on the [llvm-py examples page](http://www.mdevan.org/llvm-py/examples.html) + +* * * + +# Code Generation Setup # {#basics} + + +In order to generate LLVM IR, we want some simple setup to get started. First +we define code generation methods in each AST node class: + + +{% highlight python %} +# Expression class for numeric literals like "1.0". +class NumberExpressionNode(ExpressionNode): + + def __init__(self, value): + self.value = value + + def CodeGen(self): + ... + +# Expression class for referencing a variable, like "a". +class VariableExpressionNode(ExpressionNode): + + def __init__(self, name): + self.name = name + + def CodeGen(self): + ... + +... +{% endhighlight %} + + +The `CodeGen` method says to emit IR for that AST node along with all +the things it depends on, and they all return an LLVM Value object. "Value" is +the class used to represent a +"[Static Single Assignment (SSA)](http://en.wikipedia.org/wiki/Static_single_assignment_form) +register" or "SSA value" in LLVM. The most distinct aspect +of SSA values is that their value is computed as the related instruction +executes, and it does not get a new value until (and if) the instruction +re-executes. In other words, there is no way to "change" an SSA value. For +more information, please read up on +[Static Single Assignment](http://en.wikipedia.org/wiki/Static_single_assignment_form) + - the concepts are really quite natural once you grok them. + +We will also need to define some global variables which we will be used +during code generation: + + +{% highlight python %} +# The LLVM module, which holds all the IR code. +g_llvm_module = Module.new('my cool jit') + +# The LLVM instruction builder. Created whenever a new function is entered. +g_llvm_builder = None + +# A dictionary that keeps track of which values are defined in the current scope +# and what their LLVM representation is. +g_named_values = {} +{% endhighlight %} + + +`g_llvm_module` is the LLVM construct that contains all of the +functions and global variables in a chunk of code. In many ways, it is the +top-level structure that the LLVM IR uses to contain code. + +`g_llvm_builder` is a helper object that makes it easy to generate +LLVM instructions. Instances of the +[llvm.core.Builder](llvm.core.Builder.html) class keep track of the current place to insert +instructions and have methods to create new instructions. Note that we do not +initialize this variable; instead, it will be initialized whenever we start +generating code for a function. + +Finally, `g_named_values` is a dictionary that keeps track of which +values are defined in the current scope and what their LLVM representation is. +In other words, it is a symbol table for the code. In this form of +Kaleidoscope, the only things that can be referenced are function parameters. +As such, function parameters will be in this map when generating code for their +function body. + + +With these basics in place, we can start talking about how to generate code for +each expression. Note that this assumes that `g_llvm_builder` has been +set up to generate code *into* something. For now, we'll assume that +this has already been done, and we'll just use it to emit code. + + + + +* * * + + +# Expression Code Generation # {#exprs} + + +Generating LLVM code for expression nodes is very straightforward: less +than 35 lines of commented code for all four of our expression nodes. First +we'll do numeric literals: + + +{% highlight python %} + def CodeGen(self): + return Constant.real(Type.double(), self.value) +{% endhighlight %} + + +In llvm-py, floating point numeric constants are represented with the +`llvm.core.ConstantFP` class. To create one, we can use the static +`real()` method in the `llvm.core.Constant` class. This code +basically just creates and returns a `ConstantFP`. Note that in the LLVM +IR constants are all uniqued together and shared. For this reason, we create +the constant through a factory method instead of instantiating one directly. + + +{% highlight python %} + def CodeGen(self): + if self.name in g_named_values: + return g_named_values[self.name] + else: + raise RuntimeError('Unknown variable name: ' + self.name) +{% endhighlight %} + + +References to variables are also quite simple using LLVM. In the simple +version of Kaleidoscope, we assume that the variable has already been emitted +somewhere and its value is available. In practice, the only values that can be +in the `g_named_values` dictionary are function arguments. This code +simply checks to see that the specified name is in the map (if not, an unknown +variable is being referenced) and returns the value for it. In future chapters, +we'll add support for +[loop induction variables](PythonLangImpl5.html#for) in the symbol table, +and for [local variables](PythonLangImpl7.html#localvars). + +{% highlight python %} + def CodeGen(self): + left = self.left.CodeGen() + right = self.right.CodeGen() + + if self.operator == '+': + return g_llvm_builder.fadd(left, right, 'addtmp') + elif self.operator == '-': + return g_llvm_builder.fsub(left, right, 'subtmp') + elif self.operator == '*': + return g_llvm_builder.fmul(left, right, 'multmp') + elif self.operator == '<': + result = g_llvm_builder.fcmp(FCMP_ULT, left, right, 'cmptmp') + # Convert bool 0 or 1 to double 0.0 or 1.0. + return g_llvm_builder.uitofp(result, Type.double(), 'booltmp') + else: + raise RuntimeError('Unknown binary operator.') +{% endhighlight %} + + +Binary operators start to get more interesting. The basic idea here is that +we recursively emit code for the left-hand side of the expression, then the +right-hand side, then we compute the result of the binary expression depending +on which operator is being used. + + +In the example above, the LLVM builder class is starting to show its value. +`g_llvm_builder` knows where to insert the newly created instruction, all +you have to do is specify what instruction to create (e.g. with `add`), +which operands to use (`left` and `right` here) and optionally +provide a name for the generated instruction. + +One nice thing about LLVM is that the name is just a hint. For instance, if +the code above emits multiple "addtmp" variables, LLVM will automatically +provide each one with an increasing, unique numeric suffix. Local value names +for instructions are purely optional, but it makes it much easier to read the +IR dumps. + +[LLVM instructions](http://www.llvm.org/docs/LangRef.html#instref) +are constrained by strict rules: for example, the Left and Right operators of +an [add instruction](http://www.llvm.org/docs/LangRef.html#i_add) +must have the same type, and the result type of the add must match the operand +types. Because all values in Kaleidoscope are doubles, this makes for very +simple code for add, sub and mul. + +On the other hand, LLVM specifies that the +[fcmp instruction](http://www.llvm.org/docs/LangRef.html#i_fcmp) always +returns an 'i1' value (a one bit integer). The problem with this is that +Kaleidoscope wants the value to be a 0.0 or 1.0 value. In order to get these +semantics, we combine the fcmp instruction with a +[uitofp instruction](http://www.llvm.org/docs/LangRef.html#i_uitofp). +This instruction converts its input integer into a floating point value by +treating the input as an unsigned value. In contrast, if we used the +[sitofp instruction](http://www.llvm.org/docs/LangRef.html#i_sitofp), +the Kaleidoscope `<` operator would return 0.0 and -1.0, depending on the +input value. + + +{% highlight python %} + def CodeGen(self): + # Look up the name in the global module table. + callee = g_llvm_module.get_function_named(self.callee) + + # Check for argument mismatch error. + if len(callee.args) != len(self.args): + raise RuntimeError('Incorrect number of arguments passed.') + + arg_values = [i.CodeGen() for i in self.args] + + return g_llvm_builder.call(callee, arg_values, 'calltmp') +{% endhighlight %} + + +Code generation for function calls is quite straightforward with LLVM. The +code above initially does a function name lookup in the LLVM Module's symbol +table. Recall that the LLVM Module is the container that holds all of the +functions we are JIT'ing. By giving each function the same name as what the +user specifies, we can use the LLVM symbol table to resolve function names for +us. + +Once we have the function to call, we codegen each argument that is to be +passed in, and create an LLVM +[call instruction](http://www.llvm.org/docs/LangRef.html#i_call). +Note that LLVM uses the native C calling conventions by default, allowing these +calls to also call into standard library functions like "sin" and "cos", with no +additional effort. + +This wraps up our handling of the four basic expressions that we have so far +in Kaleidoscope. Feel free to go in and add some more. For example, by +browsing the [LLVM language reference](http://www.llvm.org/docs/LangRef.html) +you'll find several other interesting instructions that are really +easy to plug into our basic framework. + + +* * * + + +# Function Code Generation # {#funcs} + + +Code generation for prototypes and functions must handle a number of +details, which make their code less beautiful than expression code +generation, but allows us to illustrate some important points. First, let's +talk about code generation for prototypes: they are used both for function +bodies and external function declarations. The code starts with: + + +{% highlight python %} + def CodeGen(self): + # Make the function type, eg. double(double,double). + funct_type = Type.function( + Type.double(), [Type.double()] * len(self.args), False) + + function = Function.new(g_llvm_module, funct_type, self.name) +{% endhighlight %} + + +The call to `Type.function` creates the `FunctionType` that +should be used for a given Prototype. Since all function arguments in +Kaleidoscope are of type double, the first line creates a list of "N" LLVM +double types. It then uses the `Type.function` method to create a +function type that takes "N" doubles as arguments, returns one double as a +result, and that is not vararg (the False parameter indicates this). Note that +Types in LLVM are uniqued just like Constants are, so you don't instantiate them +directly. + +The final line above actually creates the function that the prototype will +correspond to. This indicates the type and name to use, as well as which +module to insert into. Note that by default, the function will have +[external linkage]( 4+5 +Read a top-level expression: +define double @0() { +entry: + ret double 9.000000e+00 +} +{% endhighlight %} + + +Note how the parser turns the top-level expression into anonymous functions +for us. This will be handy when we add JIT +support in the next chapter. Also note that the code is very literally +transcribed, no optimizations are being performed except simple constant +folding done by the Builder. We will +add optimizations explicitly +in the next chapter. + + +{% highlight bash %} +ready> def foo(a b) a*a + 2*a*b + b*b +Read a function definition: +define double @foo(double %a, double %b) { +entry: + %multmp = fmul double %a, %a ; [#uses=1] + %multmp1 = fmul double 2.000000e+00, %a ; [#uses=1] + %multmp2 = fmul double %multmp1, %b ; [#uses=1] + %addtmp = fadd double %multmp, %multmp2 ; [#uses=1] + %multmp3 = fmul double %b, %b ; [#uses=1] + %addtmp4 = fadd double %addtmp, %multmp3 ; [#uses=1] + ret double %addtmp4 +} +{% endhighlight %} + + +This shows some simple arithmetic. Notice the striking similarity to the +LLVM builder calls that we use to create the instructions. + + +{% highlight bash %} +ready> def bar(a) foo(a, 4.0) + bar(31337) +Read a function definition: +define double @bar(double %a) { +entry: + %calltmp = call double @foo(double %a, double 4.000000e+00) ; [#uses=1] + %calltmp1 = call double @bar(double 3.133700e+04) ; [#uses=1] + %addtmp = fadd double %calltmp, %calltmp1 ; [#uses=1] + ret double %addtmp +} +{% endhighlight %} + + +This shows some function calls. Note that this function will take a long +time to execute if you call it. In the future we'll add conditional control +flow to actually make recursion useful :). + + +{% highlight bash %} +ready> extern cos(x) +Read extern: +declare double @cos(double) + +ready> cos(1.234) +Read a top-level expression: +define double @1() { +entry: + %calltmp = call double @cos(double 1.234000e+00) ; [#uses=1] + ret double %calltmp +} +{% endhighlight %} + + +This shows an extern for the libm "cos" function, and a call to it. + + + +{% highlight bash %} +ready> ^C +; ModuleID = 'my cool jit' + +define double @0() { +entry: + ret double 9.000000e+00 +} + +define double @foo(double %a, double %b) { +entry: + %multmp = fmul double %a, %a ; [#uses=1] + %multmp1 = fmul double 2.000000e+00, %a ; [#uses=1] + %multmp2 = fmul double %multmp1, %b ; [#uses=1] + %addtmp = fadd double %multmp, %multmp2 ; [#uses=1] + %multmp3 = fmul double %b, %b ; [#uses=1] + %addtmp4 = fadd double %addtmp, %multmp3 ; [#uses=1] + ret double %addtmp4 +} + +define double @bar(double %a) { +entry: + %calltmp = call double @foo(double %a, double 4.000000e+00) ; [#uses=1] + %calltmp1 = call double @bar(double 3.133700e+04) ; [#uses=1] + %addtmp = fadd double %calltmp, %calltmp1 ; [#uses=1] + ret double %addtmp +} + +declare double @cos(double) + +define double @1() { +entry: + %calltmp = call double @cos(double 1.234000e+00) ; [#uses=1] + ret double %calltmp +} +{% endhighlight %} + + +When you quit the current demo, it dumps out the IR for the entire module +generated. Here you can see the big picture with all the functions referencing +each other. + +This wraps up the third chapter of the Kaleidoscope tutorial. Up next, we'll +describe how to [add JIT codegen and optimizer support](PythonLangImpl4.html) +to this so we can actually start running code! + + + + +* * * + + +# Full Code Listing # {#code} + +Here is the complete code listing for our running example, enhanced with the +LLVM code generator. Because this uses the llvm-py libraries, you need to +[download](../download.html) and +[install](../userguide.html#install) them. + + + +{% highlight python %} +#!/usr/bin/env python + +import re +from llvm.core import Module, Constant, Type, Function, Builder, FCMP_ULT + +################################################################################ +## Globals +################################################################################ + +# The LLVM module, which holds all the IR code. +g_llvm_module = Module.new('my cool jit') + +# The LLVM instruction builder. Created whenever a new function is entered. +g_llvm_builder = None + +# A dictionary that keeps track of which values are defined in the current scope +# and what their LLVM representation is. +g_named_values = {} + +################################################################################ +## Lexer +################################################################################ + +# The lexer yields one of these types for each token. +class EOFToken(object): + pass + +class DefToken(object): + pass + +class ExternToken(object): + pass + +class IdentifierToken(object): + def __init__(self, name): self.name = name + +class NumberToken(object): + def __init__(self, value): self.value = value + +class CharacterToken(object): + def __init__(self, char): self.char = char + def __eq__(self, other): + return isinstance(other, CharacterToken) and self.char == other.char + def __ne__(self, other): return not self == other + +# Regular expressions that tokens and comments of our language. +REGEX_NUMBER = re.compile('[0-9]+(?:\.[0-9]+)?') +REGEX_IDENTIFIER = re.compile('[a-zA-Z][a-zA-Z0-9]*') +REGEX_COMMENT = re.compile('#.*') + +def Tokenize(string): + while string: + # Skip whitespace. + if string[0].isspace(): + string = string[1:] + continue + + # Run regexes. + comment_match = REGEX_COMMENT.match(string) + number_match = REGEX_NUMBER.match(string) + identifier_match = REGEX_IDENTIFIER.match(string) + + # Check if any of the regexes matched and yield the appropriate result. + if comment_match: + comment = comment_match.group(0) + string = string[len(comment):] + elif number_match: + number = number_match.group(0) + yield NumberToken(float(number)) + string = string[len(number):] + elif identifier_match: + identifier = identifier_match.group(0) + # Check if we matched a keyword. + if identifier == 'def': + yield DefToken() + elif identifier == 'extern': + yield ExternToken() + else: + yield IdentifierToken(identifier) + string = string[len(identifier):] + else: + # Yield the ASCII value of the unknown character. + yield CharacterToken(string[0]) + string = string[1:] + + yield EOFToken() + +################################################################################ +## Abstract Syntax Tree (aka Parse Tree) +################################################################################ + +# Base class for all expression nodes. +class ExpressionNode(object): + pass + +# Expression class for numeric literals like "1.0". +class NumberExpressionNode(ExpressionNode): + + def __init__(self, value): + self.value = value + + def CodeGen(self): + return Constant.real(Type.double(), self.value) + +# Expression class for referencing a variable, like "a". +class VariableExpressionNode(ExpressionNode): + + def __init__(self, name): + self.name = name + + def CodeGen(self): + if self.name in g_named_values: + return g_named_values[self.name] + else: + raise RuntimeError('Unknown variable name: ' + self.name) + +# Expression class for a binary operator. +class BinaryOperatorExpressionNode(ExpressionNode): + + def __init__(self, operator, left, right): + self.operator = operator + self.left = left + self.right = right + + def CodeGen(self): + left = self.left.CodeGen() + right = self.right.CodeGen() + + if self.operator == '+': + return g_llvm_builder.fadd(left, right, 'addtmp') + elif self.operator == '-': + return g_llvm_builder.fsub(left, right, 'subtmp') + elif self.operator == '*': + return g_llvm_builder.fmul(left, right, 'multmp') + elif self.operator == '<': + result = g_llvm_builder.fcmp(FCMP_ULT, left, right, 'cmptmp') + # Convert bool 0 or 1 to double 0.0 or 1.0. + return g_llvm_builder.uitofp(result, Type.double(), 'booltmp') + else: + raise RuntimeError('Unknown binary operator.') + +# Expression class for function calls. +class CallExpressionNode(ExpressionNode): + + def __init__(self, callee, args): + self.callee = callee + self.args = args + + def CodeGen(self): + # Look up the name in the global module table. + callee = g_llvm_module.get_function_named(self.callee) + + # Check for argument mismatch error. + if len(callee.args) != len(self.args): + raise RuntimeError('Incorrect number of arguments passed.') + + arg_values = [i.CodeGen() for i in self.args] + + return g_llvm_builder.call(callee, arg_values, 'calltmp') + +# This class represents the "prototype" for a function, which captures its name, +# and its argument names (thus implicitly the number of arguments the function +# takes). +class PrototypeNode(object): + + def __init__(self, name, args): + self.name = name + self.args = args + + def CodeGen(self): + # Make the function type, eg. double(double,double). + funct_type = Type.function( + Type.double(), [Type.double()] * len(self.args), False) + + function = Function.new(g_llvm_module, funct_type, self.name) + + # If the name conflicted, there was already something with the same name. + # If it has a body, don't allow redefinition or reextern. + if function.name != self.name: + function.delete() + function = g_llvm_module.get_function_named(self.name) + + # If the function already has a body, reject this. + if not function.is_declaration: + raise RuntimeError('Redefinition of function.') + + # If F took a different number of args, reject. + if len(callee.args) != len(self.args): + raise RuntimeError('Redeclaration of a function with different number ' + 'of args.') + + # Set names for all arguments and add them to the variables symbol table. + for arg, arg_name in zip(function.args, self.args): + arg.name = arg_name + # Add arguments to variable symbol table. + g_named_values[arg_name] = arg + + return function + +# This class represents a function definition itself. +class FunctionNode(object): + + def __init__(self, prototype, body): + self.prototype = prototype + self.body = body + + def CodeGen(self): + # Clear scope. + g_named_values.clear() + + # Create a function object. + function = self.prototype.CodeGen() + + # Create a new basic block to start insertion into. + block = function.append_basic_block('entry') + global g_llvm_builder + g_llvm_builder = Builder.new(block) + + # Finish off the function. + try: + return_value = self.body.CodeGen() + g_llvm_builder.ret(return_value) + + # Validate the generated code, checking for consistency. + function.verify() + except: + function.delete() + raise + + return function + + +################################################################################ +## Parser +################################################################################ + +class Parser(object): + + def __init__(self, tokens, binop_precedence): + self.tokens = tokens + self.binop_precedence = binop_precedence + self.Next() + + # Provide a simple token buffer. Parser.current is the current token the + # parser is looking at. Parser.Next() reads another token from the lexer and + # updates Parser.current with its results. + def Next(self): + self.current = self.tokens.next() + + # Gets the precedence of the current token, or -1 if the token is not a binary + # operator. + def GetCurrentTokenPrecedence(self): + if isinstance(self.current, CharacterToken): + return self.binop_precedence.get(self.current.char, -1) + else: + return -1 + + # identifierexpr ::= identifier | identifier '(' expression* ')' + def ParseIdentifierExpr(self): + identifier_name = self.current.name + self.Next() # eat identifier. + + if self.current != CharacterToken('('): # Simple variable reference. + return VariableExpressionNode(identifier_name) + + # Call. + self.Next() # eat '('. + args = [] + if self.current != CharacterToken(')'): + while True: + args.append(self.ParseExpression()) + if self.current == CharacterToken(')'): + break + elif self.current != CharacterToken(','): + raise RuntimeError('Expected ")" or "," in argument list.') + self.Next() + + self.Next() # eat ')'. + return CallExpressionNode(identifier_name, args) + + # numberexpr ::= number + def ParseNumberExpr(self): + result = NumberExpressionNode(self.current.value) + self.Next() # consume the number. + return result + + # parenexpr ::= '(' expression ')' + def ParseParenExpr(self): + self.Next() # eat '('. + + contents = self.ParseExpression() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")".') + self.Next() # eat ')'. + + return contents + + # primary ::= identifierexpr | numberexpr | parenexpr + def ParsePrimary(self): + if isinstance(self.current, IdentifierToken): + return self.ParseIdentifierExpr() + elif isinstance(self.current, NumberToken): + return self.ParseNumberExpr() + elif self.current == CharacterToken('('): + return self.ParseParenExpr() + else: + raise RuntimeError('Unknown token when expecting an expression.') + + # binoprhs ::= (operator primary)* + def ParseBinOpRHS(self, left, left_precedence): + # If this is a binary operator, find its precedence. + while True: + precedence = self.GetCurrentTokenPrecedence() + + # If this is a binary operator that binds at least as tightly as the + # current one, consume it; otherwise we are done. + if precedence < left_precedence: + return left + + binary_operator = self.current.char + self.Next() # eat the operator. + + # Parse the primary expression after the binary operator. + right = self.ParsePrimary() + + # If binary_operator binds less tightly with right than the operator after + # right, let the pending operator take right as its left. + next_precedence = self.GetCurrentTokenPrecedence() + if precedence < next_precedence: + right = self.ParseBinOpRHS(right, precedence + 1) + + # Merge left/right. + left = BinaryOperatorExpressionNode(binary_operator, left, right) + + # expression ::= primary binoprhs + def ParseExpression(self): + left = self.ParsePrimary() + return self.ParseBinOpRHS(left, 0) + + # prototype ::= id '(' id* ')' + def ParsePrototype(self): + if not isinstance(self.current, IdentifierToken): + raise RuntimeError('Expected function name in prototype.') + + function_name = self.current.name + self.Next() # eat function name. + + if self.current != CharacterToken('('): + raise RuntimeError('Expected "(" in prototype.') + self.Next() # eat '('. + + arg_names = [] + while isinstance(self.current, IdentifierToken): + arg_names.append(self.current.name) + self.Next() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")" in prototype.') + + # Success. + self.Next() # eat ')'. + + return PrototypeNode(function_name, arg_names) + + # definition ::= 'def' prototype expression + def ParseDefinition(self): + self.Next() # eat def. + proto = self.ParsePrototype() + body = self.ParseExpression() + return FunctionNode(proto, body) + + # toplevelexpr ::= expression + def ParseTopLevelExpr(self): + proto = PrototypeNode('', []) + return FunctionNode(proto, self.ParseExpression()) + + # external ::= 'extern' prototype + def ParseExtern(self): + self.Next() # eat extern. + return self.ParsePrototype() + + # Top-Level parsing + def HandleDefinition(self): + self.Handle(self.ParseDefinition, 'Read a function definition:') + + def HandleExtern(self): + self.Handle(self.ParseExtern, 'Read an extern:') + + def HandleTopLevelExpression(self): + self.Handle(self.ParseTopLevelExpr, 'Read a top-level expression:') + + def Handle(self, function, message): + try: + print message, function().CodeGen() + except Exception, e: + print 'Error:', e + try: + self.Next() # Skip for error recovery. + except: + pass + +################################################################################ +## Main driver code. +################################################################################ + +def main(): + # Install standard binary operators. + # 1 is lowest possible precedence. 40 is the highest. + operator_precedence = { + '<': 10, + '+': 20, + '-': 20, + '*': 40 + } + + # Run the main "interpreter loop". + while True: + print 'ready>', + try: + raw = raw_input() + except KeyboardInterrupt: + break + + parser = Parser(Tokenize(raw), operator_precedence) + while True: + # top ::= definition | external | expression | EOF + if isinstance(parser.current, EOFToken): + break + if isinstance(parser.current, DefToken): + parser.HandleDefinition() + elif isinstance(parser.current, ExternToken): + parser.HandleExtern() + else: + parser.HandleTopLevelExpression() + + # Print out all of the generated code. + print '\n', g_llvm_module + +if __name__ == '__main__': + main() +{% endhighlight %} + +* * * + +**[Next: Adding JIT and Optimizer Support](PythonLangImpl4.html)** + diff --git a/docs/source/doc/kaleidoscope/PythonLangImpl4.md b/docs/source/doc/kaleidoscope/PythonLangImpl4.md new file mode 100644 index 0000000..d113f49 --- /dev/null +++ b/docs/source/doc/kaleidoscope/PythonLangImpl4.md @@ -0,0 +1,941 @@ +--- +layout: page +title: "Kaleidoscope: Chapter 4" +--- + +# Adding JIT and Optimizer Support + +Written by [Chris Lattner](mailto:sabre@nondot.org) +and [Max Shawabkeh](http://max99x.com) + + +**Chapter 4** + + +* This will become a table of contents (this text will be scraped). +{:toc} + + +**[Chapter 5: Extending the Language: Control Flow](PythonLangImpl5.html)** + + +# Introduction # {#intro} + +Welcome to Chapter 4 of the +[Implementing a language with LLVM](http://www.llvm.org/docs/tutorial/index.html) +tutorial. Chapters 1-3 described the implementation of a simple +language and added support for generating LLVM IR. This chapter describes +two new techniques: adding optimizer support to your language, and adding JIT +compiler support. These additions will demonstrate how to get nice, efficient +code for the Kaleidoscope language. + + +* * * + +# Trivial Constant Folding # {#trivialconstfold} + +Our demonstration for Chapter 3 is elegant and easy to extend. Unfortunately, +it does not produce wonderful code. The LLVM Builder, however, does give us +obvious optimizations when compiling simple code: + + +{% highlight bash %} +ready> def test(x) 1+2+x +Read function definition: +define double @test(double %x) { +entry: + %addtmp = fadd double 3.000000e+00, %x + ret double %addtmp +} +{% endhighlight %} + + +This code is not a literal transcription of the AST built by parsing the +input. That would be: + + +{% highlight bash %} +ready> def test(x) 1+2+x +Read function definition: +define double @test(double %x) { +entry: + %addtmp = fadd double 2.000000e+00, 1.000000e+00 + %addtmp1 = fadd double %addtmp, %x + ret double %addtmp1 +} +{% endhighlight %} + + +Constant folding, as seen above, in particular, is a very common and very +important optimization: so much so that many language implementors implement +constant folding support in their AST representation. + +With LLVM, you don't need this support in the AST. Since all calls to build +LLVM IR go through the LLVM IR builder, the builder itself checked to see if +there was a constant folding opportunity when you call it. If so, it just does +the constant fold and return the constant instead of creating an instruction. + +Well, that was easy :). In practice, we recommend always using +`llvm.core.Builder` when generating code like this. It has no +"syntactic overhead" for its use (you don't have to uglify your compiler with +constant checks everywhere) and it can dramatically reduce the amount of +LLVM IR that is generated in some cases (particular for languages with a macro +preprocessor or that use a lot of constants). + +On the other hand, the `Builder` is limited by the fact that it does +all of its analysis inline with the code as it is built. If you take a slightly +more complex example: + + +{% highlight bash %} +ready> def test(x) (1+2+x)*(x+(1+2)) +Read a function definition: +define double @test(double %x) { +entry: + %addtmp = fadd double 3.000000e+00, %x ; [#uses=1] + %addtmp1 = fadd double %x, 3.000000e+00 ; [#uses=1] + %multmp = fmul double %addtmp, %addtmp1 ; [#uses=1] + ret double %multmp +} +{% endhighlight %} + + +In this case, the LHS and RHS of the multiplication are the same value. We'd +really like to see this generate"`tmp = x+3; result = tmp*tmp;` instead +of computing `x+3` twice. + +Unfortunately, no amount of local analysis will be able to detect and correct +this. This requires two transformations: reassociation of expressions (to +make the add's lexically identical) and Common Subexpression Elimination (CSE) +to delete the redundant add instruction. Fortunately, LLVM provides a broad +range of optimizations that you can use, in the form of "passes". + + +* * * + +# LLVM Optimization Passes # {#optimizerpasses} + +LLVM provides many optimization passes, which do many different sorts of +things and have different tradeoffs. Unlike other systems, LLVM doesn't hold +to the mistaken notion that one set of optimizations is right for all languages +and for all situations. LLVM allows a compiler implementor to make complete +decisions about what optimizations to use, in which order, and in what +situation. + +As a concrete example, LLVM supports both "whole module" passes, which look +across as large of body of code as they can (often a whole file, but if run +at link time, this can be a substantial portion of the whole program). It also +supports and includes "per-function" passes which just operate on a single +function at a time, without looking at other functions. For more information +on passes and how they are run, see the +[How to Write a Pass](http://www.llvm.org/docs/WritingAnLLVMPass.html) +document and the +[List of LLVM Passes](http://www.llvm.org/docs/Passes.html). + +For Kaleidoscope, we are currently generating functions on the fly, one at +a time, as the user types them in. We aren't shooting for the ultimate +optimization experience in this setting, but we also want to catch the easy and +quick stuff where possible. As such, we will choose to run a few per-function +optimizations as the user types the function in. If we wanted to make a "static +Kaleidoscope compiler", we would use exactly the code we have now, except that +we would defer running the optimizer until the entire file has been parsed. + +In order to get per-function optimizations going, we need to set up a +[FunctionPassManager](http://www.llvm.org/docs/WritingAnLLVMPass.html#passmanager) +to hold and organize the LLVM optimizations that we want +to run. Once we have that, we can add a set of optimizations to run. The code +looks like this: + + +{% highlight python %} +# The function optimization passes manager. +g_llvm_pass_manager = FunctionPassManager.new(g_llvm_module) + +# The LLVM execution engine. +g_llvm_executor = ExecutionEngine.new(g_llvm_module) + +... + +def main(): + # Set up the optimizer pipeline. Start with registering info about how the + # target lays out data structures. + g_llvm_pass_manager.add(g_llvm_executor.target_data) + # Do simple "peephole" optimizations and bit-twiddling optzns. + g_llvm_pass_manager.add(PASS_INSTRUCTION_COMBINING) + # Reassociate expressions. + g_llvm_pass_manager.add(PASS_REASSOCIATE) + # Eliminate Common SubExpressions. + g_llvm_pass_manager.add(PASS_GVN) + # Simplify the control flow graph (deleting unreachable blocks, etc). + g_llvm_pass_manager.add(PASS_CFG_SIMPLIFICATION) + + g_llvm_pass_manager.initialize() +{% endhighlight %} + + +This code defines a `FunctionPassManager`, +`g_llvm_pass_manager`. Once it is set up, we use a series of "add" calls +to add a bunch of LLVM passes. The first pass is basically boilerplate, it adds +a pass so that later optimizations know how the data structures in the program +are laid out. (The "`g_llvm_executor`" variable is related to the JIT, +which we will get to in the next section.) In this case, we choose to add 4 +optimization passes. The passes we chose here are a pretty standard set of +"cleanup" optimizations that are useful for a wide variety of code. I won't +delve into what they do but, believe me, they are a good starting place :). + +Once the pass manager is set up, we need to make use of it. We do this by +running it after our newly created function is constructed (in +`FunctionNode.CodeGen`), but before it is returned to the client: + + +{% highlight python %} + return_value = self.body.CodeGen() + g_llvm_builder.ret(return_value) + + # Validate the generated code, checking for consistency. + function.verify() + + # Optimize the function. + g_llvm_pass_manager.run(function) +{% endhighlight %} + + +As you can see, this is pretty straightforward. The +`FunctionPassManager` optimizes and updates the LLVM Function in place, +improving (hopefully) its body. With this in place, we can try our test above +again: + + +{% highlight bash %} +ready> def test(x) (1+2+x)*(x+(1+2)) +Read a function definition: +define double @test(double %x) { +entry: + %addtmp = fadd double %x, 3.000000e+00 ; [#uses=2] + %multmp = fmul double %addtmp, %addtmp ; [#uses=1] + ret double %multmp +} +{% endhighlight %} + + +As expected, we now get our nicely optimized code, saving a floating point +add instruction from every execution of this function. + +LLVM provides a wide variety of optimizations that can be used in certain +circumstances. Some +[documentation about the various passes](http://www.llvm.org/docs/Passes.html) +is available, but it isn't very complete. Another good source of +ideas can come from looking at the passes that `llvm-gcc` or +`llvm-ld` run to get started. The `opt` tool allows you to +experiment with passes from the command line, so you can see if they do +anything. + +Now that we have reasonable code coming out of our front-end, lets talk about +executing it! + +* * * + +# Adding a JIT Compiler # {#jit} + +Code that is available in LLVM IR can have a wide variety of tools +applied to it. For example, you can run optimizations on it (as we did above), +you can dump it out in textual or binary forms, you can compile the code to an +assembly file (.s) for some target, or you can JIT compile it. The nice thing +about the LLVM IR representation is that it is the "common currency" between +many different parts of the compiler. + + +In this section, we'll add JIT compiler support to our interpreter. The +basic idea that we want for Kaleidoscope is to have the user enter function +bodies as they do now, but immediately evaluate the top-level expressions they +type in. For example, if they type in "1 + 2", we should evaluate and print +out 3. If they define a function, they should be able to call it from the +command line. + +In order to do this, we first declare and initialize the JIT. This is done +by adding and initializing a global variable: + + +{% highlight python %} +# The LLVM execution engine. +g_llvm_executor = ExecutionEngine.new(g_llvm_module) +{% endhighlight %} + + +This creates an abstract "Execution Engine" which can be either a JIT +compiler or the LLVM interpreter. LLVM will automatically pick a JIT compiler +for you if one is available for your platform, otherwise it will fall back to +the interpreter. + +Once the `ExecutionEngine` is created, the JIT is ready to be used. +We can use the `run_function` method of the execution engine to execute +a compiled function and get its return value. In our case, this means that we +can change the code that parses a top-level expression to look like this: + + +{% highlight python %} + def HandleTopLevelExpression(self): + try: + function = self.ParseTopLevelExpr().CodeGen() + result = g_llvm_executor.run_function(function, []) + print 'Evaluated to:', result.as_real(Type.double()) + except Exception, e: + print 'Error:', e + try: + self.Next() # Skip for error recovery. + except: + pass +{% endhighlight %} + + +Recall that we compile top-level expressions into a self-contained LLVM +function that takes no arguments and returns the computed double. + +With just these two changes, lets see how Kaleidoscope works now! + + +{% highlight python %} +ready> 4+5 +Read a top level expression: +define double @0() { +entry: + ret double 9.000000e+00 +} + +Evaluated to: 9.0 +{% endhighlight %} + + +Well this looks like it is basically working. The dump of the function +shows the "no argument function that always returns double" that we synthesize +for each top-level expression that is typed in. This demonstrates very basic +functionality, but can we do more? + + +{% highlight python %} +ready> def testfunc(x y) x + y*2 +Read a function definition: +define double @testfunc(double %x, double %y) { +entry: + %multmp = fmul double %y, 2.000000e+00 ; [#uses=1] + %addtmp = fadd double %multmp, %x ; [#uses=1] + ret double %addtmp +} + +ready> testfunc(4, 10) +Read a top level expression: +define double @0() { +entry: + %calltmp = call double @testfunc(double 4.000000e+00, double 1.000000e+01) ; [#uses=1] + ret double %calltmp +} + +*Evaluated to: 24.0* +{% endhighlight %} + + +This illustrates that we can now call user code, but there is something a bit +subtle going on here. Note that we only invoke the JIT on the anonymous +functions that *call testfunc*, but we never invoked it +on *testfunc* itself. What actually happened here is that the JIT +scanned for all non-JIT'd functions transitively called from the anonymous +function and compiled all of them before returning from `run_function()`. + + +The JIT provides a number of other more advanced interfaces for things like +freeing allocated machine code, rejit'ing functions to update them, etc. +However, even with this simple code, we get some surprisingly powerful +capabilities - check this out (I removed the dump of the anonymous functions, +you should get the idea by now :) : + + +{% highlight bash %} +ready> extern sin(x) +Read an extern: +declare double @sin(double) + +ready> extern cos(x) +Read an extern: +declare double @cos(double) + +ready> sin(1.0) +*Evaluated to: 0.841470984808* + +ready> def foo(x) sin(x)*sin(x) + cos(x)*cos(x) +Read a function definition: +define double @foo(double %x) { +entry: + %calltmp = call double @sin(double %x) ; [#uses=1] + %calltmp1 = call double @sin(double %x) ; [#uses=1] + %multmp = fmul double %calltmp, %calltmp1 ; [#uses=1] + %calltmp2 = call double @cos(double %x) ; [#uses=1] + %calltmp3 = call double @cos(double %x) ; [#uses=1] + %multmp4 = fmul double %calltmp2, %calltmp3 ; [#uses=1] + %addtmp = fadd double %multmp, %multmp4 ; [#uses=1] + ret double %addtmp +} + +ready> foo(4.0) +*Evaluated to: 1.000000* +{% endhighlight %} + + +Whoa, how does the JIT know about sin and cos? The answer is surprisingly +simple: in this example, the JIT started execution of a function and got to a +function call. It realized that the function was not yet JIT compiled and +invoked the standard set of routines to resolve the function. In this case, +there is no body defined for the function, so the JIT ended up calling +`dlsym("sin")` on the Python process that is hosting our Kaleidoscope +prompt. Since `sin` is defined within the JIT's address space, it +simply patches up calls in the module to call the libm version of `sin` +directly. + +One interesting application of this is that we can now extend the language +by writing arbitrary C++ code to implement operations. For example, we can +create a C file with the following simple function: + + + +{% highlight c %} +#include + +double putchard(double x) { + putchar((char)x); + return 0; +} +{% endhighlight %} + + +We can then compile this into a shared library with GCC: + + +{% highlight bash %} +gcc -shared -fPIC -o putchard.so putchard.c +{% endhighlight %} + + +Now we can load this library into the Python process using +`llvm.core.load_library_permanently` and access it from Kaleidoscope to +produce simple output to the console: + + +{% highlight python %} +>>> import llvm.core +>>> llvm.core.load_library_permanently('/home/max/llvm-py-tutorial/putchard.so') +>>> import kaleidoscope +>>> kaleidoscope.main() +ready> extern putchard(x) +Read an extern: +declare double @putchard(double) + +ready> putchard(65) + putchard(66) + putchard(67) + putchard(10) +*ABC* +Evaluated to: 0.0 +{% endhighlight %} + + +Similar code could be used to implement file I/O, console input, and many +other capabilities in Kaleidoscope. + +This completes the JIT and optimizer chapter of the Kaleidoscope tutorial. At +this point, we can compile a non-Turing-complete programming language, optimize +and JIT compile it in a user-driven way. Next up we'll look into +[extending the language with control flow constructs](PythonLangImpl5.html), +tackling some interesting LLVM IR issues along the way. + + +* * * + +# Full Code Listing # {#code} + +Here is the complete code listing for our running example, enhanced with the +LLVM JIT and optimizer: + + + +{% highlight python %} +#!/usr/bin/env python + +import re +from llvm.core import Module, Constant, Type, Function, Builder, FCMP_ULT +from llvm.ee import ExecutionEngine, TargetData +from llvm.passes import FunctionPassManager +from llvm.passes import (PASS_INSTRUCTION_COMBINING, + PASS_REASSOCIATE, + PASS_GVN, + PASS_CFG_SIMPLIFICATION) + +################################################################################ +## Globals +################################################################################ + +# The LLVM module, which holds all the IR code. +g_llvm_module = Module.new('my cool jit') + +# The LLVM instruction builder. Created whenever a new function is entered. +g_llvm_builder = None + +# A dictionary that keeps track of which values are defined in the current scope +# and what their LLVM representation is. +g_named_values = {} + +# The function optimization passes manager. +g_llvm_pass_manager = FunctionPassManager.new(g_llvm_module) + +# The LLVM execution engine. +g_llvm_executor = ExecutionEngine.new(g_llvm_module) + +################################################################################ +## Lexer +################################################################################ + +# The lexer yields one of these types for each token. +class EOFToken(object): + pass + +class DefToken(object): + pass + +class ExternToken(object): + pass + +class IdentifierToken(object): + def __init__(self, name): self.name = name + +class NumberToken(object): + def __init__(self, value): self.value = value + +class CharacterToken(object): + def __init__(self, char): self.char = char + def __eq__(self, other): + return isinstance(other, CharacterToken) and self.char == other.char + def __ne__(self, other): return not self == other + +# Regular expressions that tokens and comments of our language. +REGEX_NUMBER = re.compile('[0-9]+(?:\.[0-9]+)?') +REGEX_IDENTIFIER = re.compile('[a-zA-Z][a-zA-Z0-9]*') +REGEX_COMMENT = re.compile('#.*') + +def Tokenize(string): + while string: + # Skip whitespace. + if string[0].isspace(): + string = string[1:] + continue + + # Run regexes. + comment_match = REGEX_COMMENT.match(string) + number_match = REGEX_NUMBER.match(string) + identifier_match = REGEX_IDENTIFIER.match(string) + + # Check if any of the regexes matched and yield the appropriate result. + if comment_match: + comment = comment_match.group(0) + string = string[len(comment):] + elif number_match: + number = number_match.group(0) + yield NumberToken(float(number)) + string = string[len(number):] + elif identifier_match: + identifier = identifier_match.group(0) + # Check if we matched a keyword. + if identifier == 'def': + yield DefToken() + elif identifier == 'extern': + yield ExternToken() + else: + yield IdentifierToken(identifier) + string = string[len(identifier):] + else: + # Yield the ASCII value of the unknown character. + yield CharacterToken(string[0]) + string = string[1:] + + yield EOFToken() + +################################################################################ +## Abstract Syntax Tree (aka Parse Tree) +################################################################################ + +# Base class for all expression nodes. +class ExpressionNode(object): + pass + +# Expression class for numeric literals like "1.0". +class NumberExpressionNode(ExpressionNode): + + def __init__(self, value): + self.value = value + + def CodeGen(self): + return Constant.real(Type.double(), self.value) + +# Expression class for referencing a variable, like "a". +class VariableExpressionNode(ExpressionNode): + + def __init__(self, name): + self.name = name + + def CodeGen(self): + if self.name in g_named_values: + return g_named_values[self.name] + else: + raise RuntimeError('Unknown variable name: ' + self.name) + +# Expression class for a binary operator. +class BinaryOperatorExpressionNode(ExpressionNode): + + def __init__(self, operator, left, right): + self.operator = operator + self.left = left + self.right = right + + def CodeGen(self): + left = self.left.CodeGen() + right = self.right.CodeGen() + + if self.operator == '+': + return g_llvm_builder.fadd(left, right, 'addtmp') + elif self.operator == '-': + return g_llvm_builder.fsub(left, right, 'subtmp') + elif self.operator == '*': + return g_llvm_builder.fmul(left, right, 'multmp') + elif self.operator == '<': + result = g_llvm_builder.fcmp(FCMP_ULT, left, right, 'cmptmp') + # Convert bool 0 or 1 to double 0.0 or 1.0. + return g_llvm_builder.uitofp(result, Type.double(), 'booltmp') + else: + raise RuntimeError('Unknown binary operator.') + +# Expression class for function calls. +class CallExpressionNode(ExpressionNode): + + def __init__(self, callee, args): + self.callee = callee + self.args = args + + def CodeGen(self): + # Look up the name in the global module table. + callee = g_llvm_module.get_function_named(self.callee) + + # Check for argument mismatch error. + if len(callee.args) != len(self.args): + raise RuntimeError('Incorrect number of arguments passed.') + + arg_values = [i.CodeGen() for i in self.args] + + return g_llvm_builder.call(callee, arg_values, 'calltmp') + +# This class represents the "prototype" for a function, which captures its name, +# and its argument names (thus implicitly the number of arguments the function +# takes). +class PrototypeNode(object): + + def __init__(self, name, args): + self.name = name + self.args = args + + def CodeGen(self): + # Make the function type, eg. double(double,double). + funct_type = Type.function( + Type.double(), [Type.double()] * len(self.args), False) + + function = Function.new(g_llvm_module, funct_type, self.name) + + # If the name conflicted, there was already something with the same name. + # If it has a body, don't allow redefinition or reextern. + if function.name != self.name: + function.delete() + function = g_llvm_module.get_function_named(self.name) + + # If the function already has a body, reject this. + if not function.is_declaration: + raise RuntimeError('Redefinition of function.') + + # If F took a different number of args, reject. + if len(callee.args) != len(self.args): + raise RuntimeError('Redeclaration of a function with different number ' + 'of args.') + + # Set names for all arguments and add them to the variables symbol table. + for arg, arg_name in zip(function.args, self.args): + arg.name = arg_name + # Add arguments to variable symbol table. + g_named_values[arg_name] = arg + + return function + +# This class represents a function definition itself. +class FunctionNode(object): + + def __init__(self, prototype, body): + self.prototype = prototype + self.body = body + + def CodeGen(self): + # Clear scope. + g_named_values.clear() + + # Create a function object. + function = self.prototype.CodeGen() + + # Create a new basic block to start insertion into. + block = function.append_basic_block('entry') + global g_llvm_builder + g_llvm_builder = Builder.new(block) + + # Finish off the function. + try: + return_value = self.body.CodeGen() + g_llvm_builder.ret(return_value) + + # Validate the generated code, checking for consistency. + function.verify() + + # Optimize the function. + g_llvm_pass_manager.run(function) + except: + function.delete() + raise + + return function + + +################################################################################ +## Parser +################################################################################ + +class Parser(object): + + def __init__(self, tokens, binop_precedence): + self.tokens = tokens + self.binop_precedence = binop_precedence + self.Next() + + # Provide a simple token buffer. Parser.current is the current token the + # parser is looking at. Parser.Next() reads another token from the lexer and + # updates Parser.current with its results. + def Next(self): + self.current = self.tokens.next() + + # Gets the precedence of the current token, or -1 if the token is not a binary + # operator. + def GetCurrentTokenPrecedence(self): + if isinstance(self.current, CharacterToken): + return self.binop_precedence.get(self.current.char, -1) + else: + return -1 + + # identifierexpr ::= identifier | identifier '(' expression* ')' + def ParseIdentifierExpr(self): + identifier_name = self.current.name + self.Next() # eat identifier. + + if self.current != CharacterToken('('): # Simple variable reference. + return VariableExpressionNode(identifier_name) + + # Call. + self.Next() # eat '('. + args = [] + if self.current != CharacterToken(')'): + while True: + args.append(self.ParseExpression()) + if self.current == CharacterToken(')'): + break + elif self.current != CharacterToken(','): + raise RuntimeError('Expected ")" or "," in argument list.') + self.Next() + + self.Next() # eat ')'. + return CallExpressionNode(identifier_name, args) + + # numberexpr ::= number + def ParseNumberExpr(self): + result = NumberExpressionNode(self.current.value) + self.Next() # consume the number. + return result + + # parenexpr ::= '(' expression ')' + def ParseParenExpr(self): + self.Next() # eat '('. + + contents = self.ParseExpression() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")".') + self.Next() # eat ')'. + + return contents + + # primary ::= identifierexpr | numberexpr | parenexpr + def ParsePrimary(self): + if isinstance(self.current, IdentifierToken): + return self.ParseIdentifierExpr() + elif isinstance(self.current, NumberToken): + return self.ParseNumberExpr() + elif self.current == CharacterToken('('): + return self.ParseParenExpr() + else: + raise RuntimeError('Unknown token when expecting an expression.') + + # binoprhs ::= (operator primary)* + def ParseBinOpRHS(self, left, left_precedence): + # If this is a binary operator, find its precedence. + while True: + precedence = self.GetCurrentTokenPrecedence() + + # If this is a binary operator that binds at least as tightly as the + # current one, consume it; otherwise we are done. + if precedence < left_precedence: + return left + + binary_operator = self.current.char + self.Next() # eat the operator. + + # Parse the primary expression after the binary operator. + right = self.ParsePrimary() + + # If binary_operator binds less tightly with right than the operator after + # right, let the pending operator take right as its left. + next_precedence = self.GetCurrentTokenPrecedence() + if precedence < next_precedence: + right = self.ParseBinOpRHS(right, precedence + 1) + + # Merge left/right. + left = BinaryOperatorExpressionNode(binary_operator, left, right) + + # expression ::= primary binoprhs + def ParseExpression(self): + left = self.ParsePrimary() + return self.ParseBinOpRHS(left, 0) + + # prototype ::= id '(' id* ')' + def ParsePrototype(self): + if not isinstance(self.current, IdentifierToken): + raise RuntimeError('Expected function name in prototype.') + + function_name = self.current.name + self.Next() # eat function name. + + if self.current != CharacterToken('('): + raise RuntimeError('Expected "(" in prototype.') + self.Next() # eat '('. + + arg_names = [] + while isinstance(self.current, IdentifierToken): + arg_names.append(self.current.name) + self.Next() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")" in prototype.') + + # Success. + self.Next() # eat ')'. + + return PrototypeNode(function_name, arg_names) + + # definition ::= 'def' prototype expression + def ParseDefinition(self): + self.Next() # eat def. + proto = self.ParsePrototype() + body = self.ParseExpression() + return FunctionNode(proto, body) + + # toplevelexpr ::= expression + def ParseTopLevelExpr(self): + proto = PrototypeNode('', []) + return FunctionNode(proto, self.ParseExpression()) + + # external ::= 'extern' prototype + def ParseExtern(self): + self.Next() # eat extern. + return self.ParsePrototype() + + # Top-Level parsing + def HandleDefinition(self): + self.Handle(self.ParseDefinition, 'Read a function definition:') + + def HandleExtern(self): + self.Handle(self.ParseExtern, 'Read an extern:') + + def HandleTopLevelExpression(self): + try: + function = self.ParseTopLevelExpr().CodeGen() + result = g_llvm_executor.run_function(function, []) + print 'Evaluated to:', result.as_real(Type.double()) + except Exception, e: + print 'Error:', e + try: + self.Next() # Skip for error recovery. + except: + pass + + def Handle(self, function, message): + try: + print message, function().CodeGen() + except Exception, e: + print 'Error:', e + try: + self.Next() # Skip for error recovery. + except: + pass + +################################################################################ +## Main driver code. +################################################################################ + +def main(): + # Set up the optimizer pipeline. Start with registering info about how the + # target lays out data structures. + g_llvm_pass_manager.add(g_llvm_executor.target_data) + # Do simple "peephole" optimizations and bit-twiddling optzns. + g_llvm_pass_manager.add(PASS_INSTRUCTION_COMBINING) + # Reassociate expressions. + g_llvm_pass_manager.add(PASS_REASSOCIATE) + # Eliminate Common SubExpressions. + g_llvm_pass_manager.add(PASS_GVN) + # Simplify the control flow graph (deleting unreachable blocks, etc). + g_llvm_pass_manager.add(PASS_CFG_SIMPLIFICATION) + + g_llvm_pass_manager.initialize() + + # Install standard binary operators. + # 1 is lowest possible precedence. 40 is the highest. + operator_precedence = { + '<': 10, + '+': 20, + '-': 20, + '*': 40 + } + + # Run the main "interpreter loop". + while True: + print 'ready>', + try: + raw = raw_input() + except KeyboardInterrupt: + break + + parser = Parser(Tokenize(raw), operator_precedence) + while True: + # top ::= definition | external | expression | EOF + if isinstance(parser.current, EOFToken): + break + if isinstance(parser.current, DefToken): + parser.HandleDefinition() + elif isinstance(parser.current, ExternToken): + parser.HandleExtern() + else: + parser.HandleTopLevelExpression() + + # Print out all of the generated code. + print '\n', g_llvm_module + +if __name__ == '__main__': + main() +{% endhighlight %} + +* * * + +**[Next: Extending the language: control flow](PythonLangImpl5.html)** + diff --git a/docs/source/doc/kaleidoscope/PythonLangImpl5.md b/docs/source/doc/kaleidoscope/PythonLangImpl5.md new file mode 100644 index 0000000..93f4a36 --- /dev/null +++ b/docs/source/doc/kaleidoscope/PythonLangImpl5.md @@ -0,0 +1,1464 @@ +--- +layout: page +title: "Kaleidoscope: Chapter 5" +--- + +# Extending the Language: Control Flow + +Written by [Chris Lattner](mailto:sabre@nondot.org) +and [Max Shawabkeh](http://max99x.com) + + +**Chapter 5** + + +* This will become a table of contents (this text will be scraped). +{:toc} + + +**[Chapter 6: Extending the Language: User-defined Operators](PythonLangImpl6.html)** + + +# Introduction # {#intro} + + +Welcome to Chapter 5 of the +[Implementing a language with LLVM](http://www.llvm.org/docs/tutorial/index.html) +tutorial. Parts 1-4 described the implementation of the simple +Kaleidoscope language and included support for generating LLVM IR, followed by +optimizations and a JIT compiler. Unfortunately, as presented, Kaleidoscope is +mostly useless: it has no control flow other than call and return. This means +that you can't have conditional branches in the code, significantly limiting its +power. In this episode of "build that compiler", we'll extend Kaleidoscope to +have an if/then/else expression plus a simple 'for' loop. + + +* * * + +# If/Then/Else # {#ifthen} + +Extending Kaleidoscope to support if/then/else is quite straightforward. It +basically requires adding lexer support for this "new" concept to the lexer, +parser, AST, and LLVM code emitter. This example is nice, because it shows how +easy it is to "grow" a language over time, incrementally extending it as new +ideas are discovered. + +Before we get going on "how" we add this extension, lets talk about "what" we +want. The basic idea is that we want to be able to write this sort of thing: + + + +{% highlight python %} +def fib(x) + if x < 3 then + 1 + else + fib(x-1) + fib(x-2) +{% endhighlight %} + + +In Kaleidoscope, every construct is an expression: there are no statements. +As such, the if/then/else expression needs to return a value like any other. +Since we're using a mostly functional form, we'll have it evaluate its +conditional, then return the 'then' or 'else' value based on how the condition +was resolved. This is very similar to the C "?:" expression. + +The semantics of the if/then/else expression is that it evaluates the +condition to a boolean equality value: 0.0 is considered to be false and +everything else is considered to be true. +If the condition is true, the first subexpression is evaluated and returned, if +the condition is false, the second subexpression is evaluated and returned. +Since Kaleidoscope allows side-effects, this behavior is important to nail down. + + +Now that we know what we "want", let's break this down into its constituent +pieces. + + + +## Lexer Extensions for If/Then/Else ## {#iflexer} + +The lexer extensions are straightforward. First we add new token classes for +the relevant tokens: + +{% highlight python %} +class IfToken(object): pass +class ThenToken(object): pass +class ElseToken(object): pass +{% endhighlight %} + + +Once we have that, we recognize the new keywords in the lexer. This is pretty +simple stuff: + + +{% highlight python %} + ... + if identifier == 'def': + yield DefToken() + elif identifier == 'extern': + yield ExternToken() + elif identifier == 'if': + yield IfToken() + elif identifier == 'then': + yield ThenToken() + elif identifier == 'else': + yield ElseToken() + else: + yield IdentifierToken(identifier) +{% endhighlight %} + + +## AST Extensions for If/Then/Else ## {#ifast} + +To represent the new expression we add a new AST node for it: + +{% highlight python %} +# Expression class for if/then/else. +class IfExpressionNode(ExpressionNode): + + def __init__(self, condition, then_branch, else_branch): + self.condition = condition + self.then_branch = then_branch + self.else_branch = else_branch + + def CodeGen(self): + ... +{% endhighlight %} + + +The AST node just has pointers to the various subexpressions. + +## Parser Extensions for If/Then/Else ## {#ifparser} + +Now that we have the relevant tokens coming from the lexer and we have the +AST node to build, our parsing logic is relatively straightforward. First we +define a new parsing function: + + +{% highlight python %} + # ifexpr ::= 'if' expression 'then' expression 'else' expression + def ParseIfExpr(self): + self.Next() # eat the if. + + # condition. + condition = self.ParseExpression() + + if not isinstance(self.current, ThenToken): + raise RuntimeError('Expected "then".') + self.Next() # eat the then. + + then_branch = self.ParseExpression() + + if not isinstance(self.current, ElseToken): + raise RuntimeError('Expected "else".') + self.Next() # eat the else. + + else_branch = self.ParseExpression() + + return IfExpressionNode(condition, then_branch, else_branch) +{% endhighlight %} + + +Next we hook it up as a primary expression: + + +{% highlight python %} + def ParsePrimary(self): + if isinstance(self.current, IdentifierToken): + return self.ParseIdentifierExpr() + elif isinstance(self.current, NumberToken): + return self.ParseNumberExpr(); + elif isinstance(self.current, IfToken): + return self.ParseIfExpr() + elif self.current == CharacterToken('('): + return self.ParseParenExpr() + else: + raise RuntimeError('Unknown token when expecting an expression.') +{% endhighlight %} + + +## LLVM IR for If/Then/Else ## {#ifir} + +Now that we have it parsing and building the AST, the final piece is adding +LLVM code generation support. This is the most interesting part of the +if/then/else example, because this is where it starts to introduce new concepts. +All of the code above has been thoroughly described in previous chapters. + + +To motivate the code we want to produce, lets take a look at a simple +example. Consider: + + +{% highlight python %} +extern foo(); +extern bar(); +def baz(x) if x then foo() else bar(); +{% endhighlight %} + + +If you disable optimizations, the code you'll (soon) get from Kaleidoscope +looks something like this: + + + +{% highlight llvm %} +declare double @foo() +declare double @bar() +define double @baz(double %x) { +entry: + %ifcond = fcmp one double %x, 0.000000e+00 + br i1 %ifcond, label %then, label %else +then: ; preds = %entry + %calltmp1 = call double @bar() +else: ; preds = %entry + %calltmp1 = call double @bar() + br label %ifcont +ifcont: ; preds = %else, %then + %iftmp = phi double [ %calltmp, %then ], [ %calltmp1, %else ] + ret double %iftmp +} +{% endhighlight %} + + +To visualize the control flow graph, you can use a nifty feature of the LLVM +[opt](http://llvm.org/cmds/opt.html) tool. If you put this LLVM IR +into "t.ll" and run `llvm-as < t.ll | opt -analyze -view-cfg`, a +[window will pop up](http://www.llvm.org/docs/ProgrammersManual.html#ViewGraph) + and you'll see this graph: + +Example CFG + +Another way to get this is to call "`function.viewCFG()`" or +"`function.viewCFGOnly()`" (where F is a "`llvm.core.Function`") +either by inserting actual calls into the code and recompiling or by calling +these in the debugger. LLVM has many nice features for visualizing various +graphs, but note that these are available only if your LLVM was built with +Graphviz support (accomplished by having Graphviz and Ghostview installed when +building LLVM). + +Getting back to the generated code, it is fairly simple: the entry block +evaluates the conditional expression ("x" in our case here) and compares the +result to 0.0 with the +[fcmp](http://www.llvm.org/docs/LangRef.html#i_fcmp) one +instruction ('one' is "Ordered and Not Equal"). Based on the result of this +expression, the code jumps to either the "then" or "else" blocks, which contain +the expressions for the true/false cases. + +Once the then/else blocks are finished executing, they both branch back to +the 'ifcont' block to execute the code that happens after the if/then/else. In +this case the only thing left to do is to return to the caller of the function. +The question then becomes: how does the code know which expression to return? + + +The answer to this question involves an important SSA operation: the +[Phi operation](http://en.wikipedia.org/wiki/Static_single_assignment_form). +If you're not familiar with SSA, +[the wikipedia article](http://en.wikipedia.org/wiki/Static_single_assignment_form) +is a good introduction and there are various other introductions to +it available on your favorite search engine. The short version is that +"execution" of the Phi operation requires "remembering" which block control came +from. The Phi operation takes on the value corresponding to the input control +block. In this case, if control comes in from the "then" block, it gets the +value of "calltmp". If control comes from the "else" block, it gets the value +of "calltmp1". + +At this point, you are probably starting to think "Oh no! This means my +simple and elegant front-end will have to start generating SSA form in order to +use LLVM!". Fortunately, this is not the case, and we strongly advise +*not* implementing an SSA construction algorithm in your front-end +unless there is an amazingly good reason to do so. In practice, there are two +sorts of values that float around in code written for your average imperative +programming language that might need Phi nodes: + +1. Code that involves user variables: `x = 1; x = x + 1;` +2. Values that are implicit in the structure of your AST, + such as the Phi node in this case. + +In [Chapter 7](PythonLangImpl7.html) of this tutorial ("mutable +variables"), we'll talk about #1 in depth. For now, just believe me that you +don't need SSA construction to handle this case. For #2, you have the choice of +using the techniques that we will describe for #1, or you can insert Phi nodes +directly, if convenient. In this case, it is really really easy to generate +the Phi node, so we choose to do it directly. + +Okay, enough of the motivation and overview, lets generate code! + + +## Code Generation for If/Then/Else ## {#ifcodegen} + +In order to generate code for this, we implement the `Codegen` method +for `IfExpressionNode`: + + +{% highlight python %} + def CodeGen(self): + condition = self.condition.CodeGen() + + # Convert condition to a bool by comparing equal to 0.0. + condition_bool = g_llvm_builder.fcmp( + FCMP_ONE, condition, Constant.real(Type.double(), 0), 'ifcond') +{% endhighlight %} + + +This code is straightforward and similar to what we saw before. We emit the +expression for the condition, then compare that value to zero to get a truth +value as a 1-bit (bool) value. + + +{% highlight python %} + function = g_llvm_builder.basic_block.function + + # Create blocks for the then and else cases. Insert the 'then' block at the + # end of the function. + then_block = function.append_basic_block('then') + else_block = function.append_basic_block('else') + merge_block = function.append_basic_block('ifcond') + + g_llvm_builder.cbranch(condition_bool, then_block, else_block) +{% endhighlight %} + + +This code creates the basic blocks that are related to the if/then/else +statement, and correspond directly to the blocks in the example above. The +first line gets the current Function object that is being built. It +gets this by asking the builder for the current BasicBlock, and asking that +block for its "parent" (the function it is currently embedded into). + +Once it has that, it creates three block which are automatically inserted +into the end of the function. Once the blocks are created, we can emit the +conditional branch that chooses between them. Note that creating new blocks +does not implicitly affect the Builder, so it is still inserting into the block +that the condition went into. + + +{% highlight python %} + # Emit then value. + g_llvm_builder.position_at_end(then_block) + then_value = self.then_branch.CodeGen() + g_llvm_builder.branch(merge_block) + + # Codegen of 'Then' can change the current block; update then_block for the + # PHI node. + then_block = g_llvm_builder.basic_block +{% endhighlight %} + + +After the conditional branch is inserted, we move the builder to start +inserting into the "then" block. Strictly speaking, this call moves the +insertion point to be at the end of the specified block. However, since the +"then" block is empty, it also starts out by inserting at the beginning of the +block. :) + +Once the insertion point is set, we recursively codegen the "then" expression +from the AST. To finish off the "then" block, we create an unconditional branch +to the merge block. One interesting (and very important) aspect of the LLVM IR +is that it +[requires all basic blocks to be "terminated"](http://www.llvm.org/docs/LangRef.html#functionstructure) with a +[control flow instruction](http://www.llvm.org/docs/LangRef.html#terminators) + such as return or branch. This means that all control flow, +*including fallthroughs* must be made explicit in the LLVM IR. If you +violate this rule, the verifier will emit an error. + +The final line here is quite subtle, but is very important. The basic issue +is that when we create the Phi node in the merge block, we need to set up the +block/value pairs that indicate how the Phi will work. Importantly, the Phi +node expects to have an entry for each predecessor of the block in the CFG. Why +then, are we getting the current block when we just set it to then_block 5 lines +above? The problem is that the "Then" expression may actually itself change the +block that the Builder is emitting into if, for example, it contains a nested +"if/then/else" expression. Because calling Codegen recursively could +arbitrarily change the notion of the current block, we are required to get an +up-to-date value for code that will set up the Phi node. + + +{% highlight python %} + # Emit else block. + g_llvm_builder.position_at_end(else_block) + else_value = self.else_branch.CodeGen() + g_llvm_builder.branch(merge_block) + + # Codegen of 'Else' can change the current block, update else_block for the + # PHI node. + else_block = g_llvm_builder.basic_block +{% endhighlight %} + + +Code generation for the 'else' block is basically identical to codegen for +the 'then' block. The only significant difference is the first line, which adds +the 'else' block to the function. Recall previously that the 'else' block was +created, but not added to the function. Now that the 'then' and 'else' blocks +are emitted, we can finish up with the merge code: + + +{% highlight python %} + # Emit merge block. + g_llvm_builder.position_at_end(merge_block) + phi = g_llvm_builder.phi(Type.double(), 'iftmp') + phi.add_incoming(then_value, then_block) + phi.add_incoming(else_value, else_block) + + return phi +{% endhighlight %} + + +The first line changes the insertion point so that newly created code will go +into the "merge" block. Once that is done, we need to create the PHI node and +set up the block/value pairs for the PHI. + +Finally, the CodeGen function returns the phi node as the value computed by +the if/then/else expression. In our example above, this returned value will +feed into the code for the top-level function, which will create the return +instruction. + +Overall, we now have the ability to execute conditional code in +Kaleidoscope. With this extension, Kaleidoscope is a fairly complete language +that can calculate a wide variety of numeric functions. Next up we'll add +another useful expression that is familiar from non-functional languages... + + +* * * + +# 'for' Loop Expression # {#for} + + +Now that we know how to add basic control flow constructs to the language, +we have the tools to add more powerful things. Lets add something more +aggressive, a 'for' expression: + + +{% highlight python %} + extern putchard(char) + def printstar(n) + for i = 1, i < n, 1.0 in + putchard(42) # ascii 42 = '*' + + # print 100 '*' characters + printstar(100) +{% endhighlight %} + + +This expression defines a new variable (`i` in this case) which iterates from +a starting value, while the condition (`i < n` in this case) is true, +incrementing by an optional step value ("1.0" in this case). If the step value +is omitted, it defaults to 1.0. While the loop is true, it executes its +body expression. Because we don't have anything better to return, we'll just +define the loop as always returning 0.0. In the future when we have mutable +variables, it will get more useful. + +As before, lets talk about the changes that we need to Kaleidoscope to +support this. + + +## Lexer Extensions for the 'for' Loop ## {#forlexer} + +The lexer extensions are the same sort of thing as for if/then/else: + + +{% highlight python %} +... + +class ThenToken(object): pass +class ElseToken(object): pass +class ForToken(object): pass +class InToken(object): pass + +... + +def Tokenize(string): + + ... + + elif identifier == 'else': + yield ElseToken() + elif identifier == 'for': + yield ForToken() + elif identifier == 'in': + yield InToken() + else: + yield IdentifierToken(identifier) +{% endhighlight %} + + +## AST Extensions for the 'for' Loop ## {#forast} + +The AST node is just as simple. It basically boils down to capturing +the variable name and the constituent expressions in the node. + + +{% highlight python %} +# Expression class for for/in. +class ForExpressionNode(ExpressionNode): + + def __init__(self, loop_variable, start, end, step, body): + self.loop_variable = loop_variable + self.start = start + self.end = end + self.step = step + self.body = body + + def CodeGen(self): + ... +{% endhighlight %} + + +## Parser Extensions for the 'for' Loop ## {#forparser} + +The parser code is also fairly standard. The only interesting thing here is +handling of the optional step value. The parser code handles it by checking to +see if the second comma is present. If not, it sets the step value to null in +the AST node: + + +{% highlight python %} + # forexpr ::= 'for' identifier '=' expr ',' expr (',' expr)? 'in' expression + def ParseForExpr(self): + self.Next() # eat the for. + + if not isinstance(self.current, IdentifierToken): + raise RuntimeError('Expected identifier after for.') + + loop_variable = self.current.name + self.Next() # eat the identifier. + + if self.current != CharacterToken('='): + raise RuntimeError('Expected "=" after for variable.') + self.Next() # eat the '='. + + start = self.ParseExpression() + + if self.current != CharacterToken(','): + raise RuntimeError('Expected "," after for start value.') + self.Next() # eat the ','. + + end = self.ParseExpression() + + # The step value is optional. + if self.current == CharacterToken(','): + self.Next() # eat the ','. + step = self.ParseExpression() + else: + step = None + + if not isinstance(self.current, InToken): + raise RuntimeError('Expected "in" after for variable specification.') + self.Next() # eat 'in'. + + body = self.ParseExpression() + + return ForExpressionNode(loop_variable, start, end, step, body) +{% endhighlight %} + + +## LLVM IR for the 'for' Loop ## {#forir} + +Now we get to the good part: the LLVM IR we want to generate for this thing. +With the simple example above, we get this LLVM IR (note that this dump is +generated with optimizations disabled for clarity): + + + +{% highlight llvm %} +declare double @putchard(double) +define double @printstar(double %n) { +entry: + ; initial value = 1.0 (inlined into phi) + br label %loop +loop: ; preds = %loop, %entry + %i = phi double [ 1.000000e+00, %entry ], [ %nextvar, %loop ] + ; body + %calltmp = call double @putchard(double 4.200000e+01) + ; increment + %nextvar = fadd double %i, 1.000000e+00 + ; termination test + %cmptmp = fcmp ult double %i, %n + %booltmp = uitofp i1 %cmptmp to double + %loopcond = fcmp one double %booltmp, 0.000000e+00 + br i1 %loopcond, label %loop, label %afterloop +afterloop: ; preds = %loop + ; loop always returns 0.0 + ret double 0.000000e+00 +} +{% endhighlight %} + + +This loop contains all the same constructs we saw before: a phi node, several +expressions, and some basic blocks. Lets see how this fits together. + + + + +## Code Generation for the 'for' Loop ## {#forcodegen} + +The first part of Codegen is very simple: we just output the start expression +for the loop value: + + +{% highlight python %} + def CodeGen(self): + # Emit the start code first, without 'variable' in scope. + start_value = self.start.CodeGen() +{% endhighlight %} + + +With this out of the way, the next step is to set up the LLVM basic block +for the start of the loop body. In the case above, the whole loop body is one +block, but remember that the body code itself could consist of multiple blocks +(e.g. if it contains an if/then/else or a for/in expression). + + +{% highlight python %} + # Make the new basic block for the loop header, inserting after current + # block. + function = g_llvm_builder.basic_block.function + pre_header_block = g_llvm_builder.basic_block + loop_block = function.append_basic_block('loop') + + # Insert an explicit fallthrough from the current block to the loop_block. + g_llvm_builder.branch(loop_block) +{% endhighlight %} + + +This code is similar to what we saw for if/then/else. Because we will need +it to create the Phi node, we remember the block that falls through into the +loop. Once we have that, we create the actual block that starts the loop and +create an unconditional branch for the fall-through between the two blocks. + + +{% highlight python %} + # Start insertion in loop_block. + g_llvm_builder.position_at_end(loop_block); + + # Start the PHI node with an entry for start. + variable_phi = g_llvm_builder.phi(Type.double(), self.loop_variable) + variable_phi.add_incoming(start_value, pre_header_block) +{% endhighlight %} + + +Now that the "pre_header_block" for the loop is set up, we switch to emitting +code for the loop body. To begin with, we move the insertion point and create +the PHI node for the loop induction variable. Since we already know the +incoming value for the starting value, we add it to the Phi node. Note that the +Phi will eventually get a second value for the backedge, but we can't set it up +yet (because it doesn't exist!). + + +{% highlight python %} + # Within the loop, the variable is defined equal to the PHI node. If it + # shadows an existing variable, we have to restore it, so save it now. + old_value = g_named_values.get(self.loop_variable, None) + g_named_values[self.loop_variable] = variable_phi + + # Emit the body of the loop. This, like any other expr, can change the + # current BB. Note that we ignore the value computed by the body. + self.body.CodeGen() +{% endhighlight %} + + +Now the code starts to get more interesting. Our 'for' loop introduces a new +variable to the symbol table. This means that our symbol table can now contain +either function arguments or loop variables. To handle this, before we codegen +the body of the loop, we add the loop variable as the current value for its +name. Note that it is possible that there is a variable of the same name in the +outer scope. It would be easy to make this an error (emit an error and return +null if there is already an entry for VarName) but we choose to allow shadowing +of variables. In order to handle this correctly, we remember the Value that +we are potentially shadowing in `old_value` (which will be None if there +is no shadowed variable). + +Once the loop variable is set into the symbol table, the code recursively +codegen's the body. This allows the body to use the loop variable: any +references to it will naturally find it in the symbol table. + + +{% highlight python %} + # Emit the step value. + if self.step: + step_value = self.step.CodeGen() + else: + # If not specified, use 1.0. + step_value = Constant.real(Type.double(), 1) + + next_value = g_llvm_builder.fadd(variable_phi, step_value, 'next') +{% endhighlight %} + + +Now that the body is emitted, we compute the next value of the iteration +variable by adding the step value, or 1.0 if it isn't present. +`next_value` will be the value of the loop variable on the next iteration +of the loop. + + +{% highlight python %} + # Compute the end condition and convert it to a bool by comparing to 0.0. + end_condition = self.end.CodeGen() + end_condition_bool = g_llvm_builder.fcmp( + FCMP_ONE, end_condition, Constant.real(Type.double(), 0), 'loopcond') +{% endhighlight %} + + +Finally, we evaluate the exit value of the loop, to determine whether the +loop should exit. This mirrors the condition evaluation for the if/then/else +statement. + + +{% highlight python %} + # Create the "after loop" block and insert it. + loop_end_block = g_llvm_builder.basic_block + after_block = function.append_basic_block('afterloop') + + # Insert the conditional branch into the end of loop_end_block. + g_llvm_builder.cbranch(end_condition_bool, loop_block, after_block) + + # Any new code will be inserted in after_block. + g_llvm_builder.position_at_end(after_block) +{% endhighlight %} + + +With the code for the body of the loop complete, we just need to finish up +the control flow for it. This code remembers the end block (for the phi node), +then creates the block for the loop exit ("afterloop"). Based on the value of +the exit condition, it creates a conditional branch that chooses between +executing the loop again and exiting the loop. Any future code is emitted in +the "afterloop" block, so it sets the insertion position to it. + + +{% highlight python %} + # Add a new entry to the PHI node for the backedge. + variable_phi.add_incoming(next_value, loop_end_block) + + # Restore the unshadowed variable. + if old_value: + g_named_values[self.loop_variable] = old_value + else: + del g_named_values[self.loop_variable] + + # for expr always returns 0.0. + return Constant.real(Type.double(), 0) +{% endhighlight %} + + +The final code handles various cleanups: now that we have the "next_value", +we can add the incoming value to the loop PHI node. After that, we remove the +loop variable from the symbol table, so that it isn't in scope after the for +loop. Finally, code generation of the for loop always returns 0.0, so that is +what we return from `ForExpressionNode::CodeGen`. + +With this, we conclude the "adding control flow to Kaleidoscope" chapter of +the tutorial. In this chapter we added two control flow constructs, and used +them to motivate a couple of aspects of the LLVM IR that are important for +front-end implementors to know. In the next chapter of our saga, we will get a +bit crazier and add [user-defined operators](PythonLangImpl6.html) to +our poor innocent language. + +* * * + +# Full Code Listing # {#code} + +Here is the complete code listing for our running example, enhanced with the +if/then/else and for expressions: + + +{% highlight python %} +#!/usr/bin/env python + +import re +from llvm.core import Module, Constant, Type, Function, Builder +from llvm.ee import ExecutionEngine, TargetData +from llvm.passes import FunctionPassManager + +from llvm.core import FCMP_ULT, FCMP_ONE +from llvm.passes import (PASS_INSTRUCTION_COMBINING, + PASS_REASSOCIATE, + PASS_GVN, + PASS_CFG_SIMPLIFICATION) + +################################################################################ +## Globals +################################################################################ + +# The LLVM module, which holds all the IR code. +g_llvm_module = Module.new('my cool jit') + +# The LLVM instruction builder. Created whenever a new function is entered. +g_llvm_builder = None + +# A dictionary that keeps track of which values are defined in the current scope +# and what their LLVM representation is. +g_named_values = {} + +# The function optimization passes manager. +g_llvm_pass_manager = FunctionPassManager.new(g_llvm_module) + +# The LLVM execution engine. +g_llvm_executor = ExecutionEngine.new(g_llvm_module) + +################################################################################ +## Lexer +################################################################################ + +# The lexer yields one of these types for each token. +class EOFToken(object): pass +class DefToken(object): pass +class ExternToken(object): pass +class IfToken(object): pass +class ThenToken(object): pass +class ElseToken(object): pass +class ForToken(object): pass +class InToken(object): pass + +class IdentifierToken(object): + def __init__(self, name): self.name = name + +class NumberToken(object): + def __init__(self, value): self.value = value + +class CharacterToken(object): + def __init__(self, char): self.char = char + def __eq__(self, other): + return isinstance(other, CharacterToken) and self.char == other.char + def __ne__(self, other): return not self == other + +# Regular expressions that tokens and comments of our language. +REGEX_NUMBER = re.compile('[0-9]+(?:\.[0-9]+)?') +REGEX_IDENTIFIER = re.compile('[a-zA-Z][a-zA-Z0-9]*') +REGEX_COMMENT = re.compile('#.*') + +def Tokenize(string): + while string: + # Skip whitespace. + if string[0].isspace(): + string = string[1:] + continue + + # Run regexes. + comment_match = REGEX_COMMENT.match(string) + number_match = REGEX_NUMBER.match(string) + identifier_match = REGEX_IDENTIFIER.match(string) + + # Check if any of the regexes matched and yield the appropriate result. + if comment_match: + comment = comment_match.group(0) + string = string[len(comment):] + elif number_match: + number = number_match.group(0) + yield NumberToken(float(number)) + string = string[len(number):] + elif identifier_match: + identifier = identifier_match.group(0) + # Check if we matched a keyword. + if identifier == 'def': + yield DefToken() + elif identifier == 'extern': + yield ExternToken() + elif identifier == 'if': + yield IfToken() + elif identifier == 'then': + yield ThenToken() + elif identifier == 'else': + yield ElseToken() + elif identifier == 'for': + yield ForToken() + elif identifier == 'in': + yield InToken() + else: + yield IdentifierToken(identifier) + string = string[len(identifier):] + else: + # Yield the ASCII value of the unknown character. + yield CharacterToken(string[0]) + string = string[1:] + + yield EOFToken() + +################################################################################ +## Abstract Syntax Tree (aka Parse Tree) +################################################################################ + +# Base class for all expression nodes. +class ExpressionNode(object): + pass + +# Expression class for numeric literals like "1.0". +class NumberExpressionNode(ExpressionNode): + + def __init__(self, value): + self.value = value + + def CodeGen(self): + return Constant.real(Type.double(), self.value) + +# Expression class for referencing a variable, like "a". +class VariableExpressionNode(ExpressionNode): + + def __init__(self, name): + self.name = name + + def CodeGen(self): + if self.name in g_named_values: + return g_named_values[self.name] + else: + raise RuntimeError('Unknown variable name: ' + self.name) + +# Expression class for a binary operator. +class BinaryOperatorExpressionNode(ExpressionNode): + + def __init__(self, operator, left, right): + self.operator = operator + self.left = left + self.right = right + + def CodeGen(self): + left = self.left.CodeGen() + right = self.right.CodeGen() + + if self.operator == '+': + return g_llvm_builder.fadd(left, right, 'addtmp') + elif self.operator == '-': + return g_llvm_builder.fsub(left, right, 'subtmp') + elif self.operator == '*': + return g_llvm_builder.fmul(left, right, 'multmp') + elif self.operator == '<': + result = g_llvm_builder.fcmp(FCMP_ULT, left, right, 'cmptmp') + # Convert bool 0 or 1 to double 0.0 or 1.0. + return g_llvm_builder.uitofp(result, Type.double(), 'booltmp') + else: + raise RuntimeError('Unknown binary operator.') + +# Expression class for function calls. +class CallExpressionNode(ExpressionNode): + + def __init__(self, callee, args): + self.callee = callee + self.args = args + + def CodeGen(self): + # Look up the name in the global module table. + callee = g_llvm_module.get_function_named(self.callee) + + # Check for argument mismatch error. + if len(callee.args) != len(self.args): + raise RuntimeError('Incorrect number of arguments passed.') + + arg_values = [i.CodeGen() for i in self.args] + + return g_llvm_builder.call(callee, arg_values, 'calltmp') + +# Expression class for if/then/else. +class IfExpressionNode(ExpressionNode): + + def __init__(self, condition, then_branch, else_branch): + self.condition = condition + self.then_branch = then_branch + self.else_branch = else_branch + + def CodeGen(self): + condition = self.condition.CodeGen() + + # Convert condition to a bool by comparing equal to 0.0. + condition_bool = g_llvm_builder.fcmp( + FCMP_ONE, condition, Constant.real(Type.double(), 0), 'ifcond') + + function = g_llvm_builder.basic_block.function + + # Create blocks for the then and else cases. Insert the 'then' block at the + # end of the function. + then_block = function.append_basic_block('then') + else_block = function.append_basic_block('else') + merge_block = function.append_basic_block('ifcond') + + g_llvm_builder.cbranch(condition_bool, then_block, else_block) + + # Emit then value. + g_llvm_builder.position_at_end(then_block) + then_value = self.then_branch.CodeGen() + g_llvm_builder.branch(merge_block) + + # Codegen of 'Then' can change the current block; update then_block for the + # PHI node. + then_block = g_llvm_builder.basic_block + + # Emit else block. + g_llvm_builder.position_at_end(else_block) + else_value = self.else_branch.CodeGen() + g_llvm_builder.branch(merge_block) + + # Codegen of 'Else' can change the current block, update else_block for the + # PHI node. + else_block = g_llvm_builder.basic_block + + # Emit merge block. + g_llvm_builder.position_at_end(merge_block) + phi = g_llvm_builder.phi(Type.double(), 'iftmp') + phi.add_incoming(then_value, then_block) + phi.add_incoming(else_value, else_block) + + return phi + +# Expression class for for/in. +class ForExpressionNode(ExpressionNode): + + def __init__(self, loop_variable, start, end, step, body): + self.loop_variable = loop_variable + self.start = start + self.end = end + self.step = step + self.body = body + + def CodeGen(self): + # Output this as: + # ... + # start = startexpr + # goto loop + # loop: + # variable = phi [start, loopheader], [nextvariable, loopend] + # ... + # bodyexpr + # ... + # loopend: + # step = stepexpr + # nextvariable = variable + step + # endcond = endexpr + # br endcond, loop, endloop + # outloop: + + # Emit the start code first, without 'variable' in scope. + start_value = self.start.CodeGen() + + # Make the new basic block for the loop header, inserting after current + # block. + function = g_llvm_builder.basic_block.function + pre_header_block = g_llvm_builder.basic_block + loop_block = function.append_basic_block('loop') + + # Insert an explicit fallthrough from the current block to the loop_block. + g_llvm_builder.branch(loop_block) + + # Start insertion in loop_block. + g_llvm_builder.position_at_end(loop_block) + + # Start the PHI node with an entry for start. + variable_phi = g_llvm_builder.phi(Type.double(), self.loop_variable) + variable_phi.add_incoming(start_value, pre_header_block) + + # Within the loop, the variable is defined equal to the PHI node. If it + # shadows an existing variable, we have to restore it, so save it now. + old_value = g_named_values.get(self.loop_variable, None) + g_named_values[self.loop_variable] = variable_phi + + # Emit the body of the loop. This, like any other expr, can change the + # current BB. Note that we ignore the value computed by the body. + self.body.CodeGen() + + # Emit the step value. + if self.step: + step_value = self.step.CodeGen() + else: + # If not specified, use 1.0. + step_value = Constant.real(Type.double(), 1) + + next_value = g_llvm_builder.fadd(variable_phi, step_value, 'next') + + # Compute the end condition and convert it to a bool by comparing to 0.0. + end_condition = self.end.CodeGen() + end_condition_bool = g_llvm_builder.fcmp( + FCMP_ONE, end_condition, Constant.real(Type.double(), 0), 'loopcond') + + # Create the "after loop" block and insert it. + loop_end_block = g_llvm_builder.basic_block + after_block = function.append_basic_block('afterloop') + + # Insert the conditional branch into the end of loop_end_block. + g_llvm_builder.cbranch(end_condition_bool, loop_block, after_block) + + # Any new code will be inserted in after_block. + g_llvm_builder.position_at_end(after_block) + + # Add a new entry to the PHI node for the backedge. + variable_phi.add_incoming(next_value, loop_end_block) + + # Restore the unshadowed variable. + if old_value: + g_named_values[self.loop_variable] = old_value + else: + del g_named_values[self.loop_variable] + + # for expr always returns 0.0. + return Constant.real(Type.double(), 0) + +# This class represents the "prototype" for a function, which captures its name, +# and its argument names (thus implicitly the number of arguments the function +# takes). +class PrototypeNode(object): + + def __init__(self, name, args): + self.name = name + self.args = args + + def CodeGen(self): + # Make the function type, eg. double(double,double). + funct_type = Type.function( + Type.double(), [Type.double()] * len(self.args), False) + + function = Function.new(g_llvm_module, funct_type, self.name) + + # If the name conflicted, there was already something with the same name. + # If it has a body, don't allow redefinition or reextern. + if function.name != self.name: + function.delete() + function = g_llvm_module.get_function_named(self.name) + + # If the function already has a body, reject this. + if not function.is_declaration: + raise RuntimeError('Redefinition of function.') + + # If the function took a different number of args, reject. + if len(function.args) != len(self.args): + raise RuntimeError('Redeclaration of a function with different number ' + 'of args.') + + # Set names for all arguments and add them to the variables symbol table. + for arg, arg_name in zip(function.args, self.args): + arg.name = arg_name + # Add arguments to variable symbol table. + g_named_values[arg_name] = arg + + return function + +# This class represents a function definition itself. +class FunctionNode(object): + + def __init__(self, prototype, body): + self.prototype = prototype + self.body = body + + def CodeGen(self): + # Clear scope. + g_named_values.clear() + + # Create a function object. + function = self.prototype.CodeGen() + + # Create a new basic block to start insertion into. + block = function.append_basic_block('entry') + global g_llvm_builder + g_llvm_builder = Builder.new(block) + + # Finish off the function. + try: + return_value = self.body.CodeGen() + g_llvm_builder.ret(return_value) + + # Validate the generated code, checking for consistency. + function.verify() + + # Optimize the function. + g_llvm_pass_manager.run(function) + except: + function.delete() + raise + + return function + + +################################################################################ +## Parser +################################################################################ + +class Parser(object): + + def __init__(self, tokens, binop_precedence): + self.tokens = tokens + self.binop_precedence = binop_precedence + self.Next() + + # Provide a simple token buffer. Parser.current is the current token the + # parser is looking at. Parser.Next() reads another token from the lexer and + # updates Parser.current with its results. + def Next(self): + self.current = self.tokens.next() + + # Gets the precedence of the current token, or -1 if the token is not a binary + # operator. + def GetCurrentTokenPrecedence(self): + if isinstance(self.current, CharacterToken): + return self.binop_precedence.get(self.current.char, -1) + else: + return -1 + + # identifierexpr ::= identifier | identifier '(' expression* ')' + def ParseIdentifierExpr(self): + identifier_name = self.current.name + self.Next() # eat identifier. + + if self.current != CharacterToken('('): # Simple variable reference. + return VariableExpressionNode(identifier_name) + + # Call. + self.Next() # eat '('. + args = [] + if self.current != CharacterToken(')'): + while True: + args.append(self.ParseExpression()) + if self.current == CharacterToken(')'): + break + elif self.current != CharacterToken(','): + raise RuntimeError('Expected ")" or "," in argument list.') + self.Next() + + self.Next() # eat ')'. + return CallExpressionNode(identifier_name, args) + + # numberexpr ::= number + def ParseNumberExpr(self): + result = NumberExpressionNode(self.current.value) + self.Next() # consume the number. + return result + + # parenexpr ::= '(' expression ')' + def ParseParenExpr(self): + self.Next() # eat '('. + + contents = self.ParseExpression() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")".') + self.Next() # eat ')'. + + return contents + + # ifexpr ::= 'if' expression 'then' expression 'else' expression + def ParseIfExpr(self): + self.Next() # eat the if. + + # condition. + condition = self.ParseExpression() + + if not isinstance(self.current, ThenToken): + raise RuntimeError('Expected "then".') + self.Next() # eat the then. + + then_branch = self.ParseExpression() + + if not isinstance(self.current, ElseToken): + raise RuntimeError('Expected "else".') + self.Next() # eat the else. + + else_branch = self.ParseExpression() + + return IfExpressionNode(condition, then_branch, else_branch) + + # forexpr ::= 'for' identifier '=' expr ',' expr (',' expr)? 'in' expression + def ParseForExpr(self): + self.Next() # eat the for. + + if not isinstance(self.current, IdentifierToken): + raise RuntimeError('Expected identifier after for.') + + loop_variable = self.current.name + self.Next() # eat the identifier. + + if self.current != CharacterToken('='): + raise RuntimeError('Expected "=" after for variable.') + self.Next() # eat the '='. + + start = self.ParseExpression() + + if self.current != CharacterToken(','): + raise RuntimeError('Expected "," after for start value.') + self.Next() # eat the ','. + + end = self.ParseExpression() + + # The step value is optional. + if self.current == CharacterToken(','): + self.Next() # eat the ','. + step = self.ParseExpression() + else: + step = None + + if not isinstance(self.current, InToken): + raise RuntimeError('Expected "in" after for variable specification.') + self.Next() # eat 'in'. + + body = self.ParseExpression() + + return ForExpressionNode(loop_variable, start, end, step, body) + + # primary ::= identifierexpr | numberexpr | parenexpr | ifexpr | forexpr + def ParsePrimary(self): + if isinstance(self.current, IdentifierToken): + return self.ParseIdentifierExpr() + elif isinstance(self.current, NumberToken): + return self.ParseNumberExpr() + elif isinstance(self.current, IfToken): + return self.ParseIfExpr() + elif isinstance(self.current, ForToken): + return self.ParseForExpr() + elif self.current == CharacterToken('('): + return self.ParseParenExpr() + else: + raise RuntimeError('Unknown token when expecting an expression.') + + # binoprhs ::= (operator primary)* + def ParseBinOpRHS(self, left, left_precedence): + # If this is a binary operator, find its precedence. + while True: + precedence = self.GetCurrentTokenPrecedence() + + # If this is a binary operator that binds at least as tightly as the + # current one, consume it; otherwise we are done. + if precedence < left_precedence: + return left + + binary_operator = self.current.char + self.Next() # eat the operator. + + # Parse the primary expression after the binary operator. + right = self.ParsePrimary() + + # If binary_operator binds less tightly with right than the operator after + # right, let the pending operator take right as its left. + next_precedence = self.GetCurrentTokenPrecedence() + if precedence < next_precedence: + right = self.ParseBinOpRHS(right, precedence + 1) + + # Merge left/right. + left = BinaryOperatorExpressionNode(binary_operator, left, right) + + # expression ::= primary binoprhs + def ParseExpression(self): + left = self.ParsePrimary() + return self.ParseBinOpRHS(left, 0) + + # prototype ::= id '(' id* ')' + def ParsePrototype(self): + if not isinstance(self.current, IdentifierToken): + raise RuntimeError('Expected function name in prototype.') + + function_name = self.current.name + self.Next() # eat function name. + + if self.current != CharacterToken('('): + raise RuntimeError('Expected "(" in prototype.') + self.Next() # eat '('. + + arg_names = [] + while isinstance(self.current, IdentifierToken): + arg_names.append(self.current.name) + self.Next() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")" in prototype.') + + # Success. + self.Next() # eat ')'. + + return PrototypeNode(function_name, arg_names) + + # definition ::= 'def' prototype expression + def ParseDefinition(self): + self.Next() # eat def. + proto = self.ParsePrototype() + body = self.ParseExpression() + return FunctionNode(proto, body) + + # toplevelexpr ::= expression + def ParseTopLevelExpr(self): + proto = PrototypeNode('', []) + return FunctionNode(proto, self.ParseExpression()) + + # external ::= 'extern' prototype + def ParseExtern(self): + self.Next() # eat extern. + return self.ParsePrototype() + + # Top-Level parsing + def HandleDefinition(self): + self.Handle(self.ParseDefinition, 'Read a function definition:') + + def HandleExtern(self): + self.Handle(self.ParseExtern, 'Read an extern:') + + def HandleTopLevelExpression(self): + try: + function = self.ParseTopLevelExpr().CodeGen() + result = g_llvm_executor.run_function(function, []) + print 'Evaluated to:', result.as_real(Type.double()) + except Exception, e: + print 'Error:', e + try: + self.Next() # Skip for error recovery. + except: + pass + + def Handle(self, function, message): + try: + print message, function().CodeGen() + except Exception, e: + print 'Error:', e + try: + self.Next() # Skip for error recovery. + except: + pass + +################################################################################ +## Main driver code. +################################################################################ + +def main(): + # Set up the optimizer pipeline. Start with registering info about how the + # target lays out data structures. + g_llvm_pass_manager.add(g_llvm_executor.target_data) + # Do simple "peephole" optimizations and bit-twiddling optzns. + g_llvm_pass_manager.add(PASS_INSTRUCTION_COMBINING) + # Reassociate expressions. + g_llvm_pass_manager.add(PASS_REASSOCIATE) + # Eliminate Common SubExpressions. + g_llvm_pass_manager.add(PASS_GVN) + # Simplify the control flow graph (deleting unreachable blocks, etc). + g_llvm_pass_manager.add(PASS_CFG_SIMPLIFICATION) + + g_llvm_pass_manager.initialize() + + # Install standard binary operators. + # 1 is lowest possible precedence. 40 is the highest. + operator_precedence = { + '<': 10, + '+': 20, + '-': 20, + '*': 40 + } + + # Run the main "interpreter loop". + while True: + print 'ready>', + try: + raw = raw_input() + except KeyboardInterrupt: + break + + parser = Parser(Tokenize(raw), operator_precedence) + while True: + # top ::= definition | external | expression | EOF + if isinstance(parser.current, EOFToken): + break + if isinstance(parser.current, DefToken): + parser.HandleDefinition() + elif isinstance(parser.current, ExternToken): + parser.HandleExtern() + else: + parser.HandleTopLevelExpression() + + # Print out all of the generated code. + print '\n', g_llvm_module + +if __name__ == '__main__': + main() +{% endhighlight %} + +* * * + +**[Next: Extending the language: user-defined operators](PythonLangImpl6.html)** + diff --git a/docs/source/doc/kaleidoscope/PythonLangImpl6.md b/docs/source/doc/kaleidoscope/PythonLangImpl6.md new file mode 100644 index 0000000..74385cb --- /dev/null +++ b/docs/source/doc/kaleidoscope/PythonLangImpl6.md @@ -0,0 +1,1535 @@ +--- +layout: page +title: "Kaleidoscope: Chapter 6" +--- + +# Extending the Language: User-defined Operators + +Written by [Chris Lattner](mailto:sabre@nondot.org) +and [Max Shawabkeh](http://max99x.com) + + +**Chapter 6** + + +* This will become a table of contents (this text will be scraped). +{:toc} + + +**[Chapter 7: Extending the Language: Mutable +Variables / SSA Construction](PythonLangImpl7.html)** + + +# Introduction # {#intro} + + +Welcome to Chapter 6 of the +[Implementing a language with LLVM](http://www.llvm.org/docs/tutorial/index.html) tutorial. At this point in our tutorial, we now have a fully +functional language that is fairly minimal, but also useful. There +is still one big problem with it, however. Our language doesn't have many +useful operators (like division, logical negation, or even any comparisons +besides less-than). + +This chapter of the tutorial takes a wild digression into adding user-defined +operators to the simple and beautiful Kaleidoscope language. This digression now +gives us a simple and ugly language in some ways, but also a powerful one at the +same time. One of the great things about creating your own language is that you +get to decide what is good or bad. In this tutorial we'll assume that it is +okay to use this as a way to show some interesting parsing techniques. + +At the end of this tutorial, we'll run through an example Kaleidoscope +application that [renders the Mandelbrot set](#example). This gives +an example of what you can build with Kaleidoscope and its feature set. + +# User-defined Operators: the Idea # {#idea} + +The "operator overloading" that we will add to Kaleidoscope is more general than +languages like C++. In C++, you are only allowed to redefine existing +operators: you can't programatically change the grammar, introduce new +operators, change precedence levels, etc. In this chapter, we will add this +capability to Kaleidoscope, which will let the user round out the set of +operators that are supported. + +The point of going into user-defined operators in a tutorial like this is to +show the power and flexibility of using a hand-written parser. Thus far, the +parser we have been implementing uses recursive descent for most parts of the +grammar and operator precedence parsing for the expressions. +See [Chapter 2](PythonLangImpl2.html) for details. Without using operator +precedence parsing, it would be very difficult to allow the programmer to +introduce new operators into the grammar: the grammar is dynamically extensible +as the JIT runs. + +The two specific features we'll add are programmable unary operators (right +now, Kaleidoscope has no unary operators at all) as well as binary operators. +An example of this is: + + +{% highlight python %} +# Logical unary not. +def unary!(v) + if v then + 0 + else + 1 + +# Define > with the same precedence as <. +def binary> 10 (LHS RHS) + RHS < LHS + +# Binary "logical or", (note that it does not "short circuit"). +def binary| 5 (LHS RHS) + if LHS then + 1 + else if RHS then + 1 + else + 0 + +# Define = with slightly lower precedence than relationals. +def binary= 9 (LHS RHS) + !(LHS < RHS | LHS > RHS) +{% endhighlight %} + + +Many languages aspire to being able to implement their standard runtime +library in the language itself. In Kaleidoscope, we can implement significant +parts of the language in the library! + +We will break down implementation of these features into two parts: +implementing support for user-defined binary operators and adding unary +operators. + +* * * + +# User-defined Binary Operators # {#binary} + +Adding support for user-defined binary operators is pretty simple with our +current framework. We'll first add support for the unary/binary keywords: + + +{% highlight python %} +class InToken(object): pass +class BinaryToken(object): pass +class UnaryToken(object): pass +... +def Tokenize(string): + ... + elif identifier == 'in': + yield InToken() + elif identifier == 'binary': + yield BinaryToken() + elif identifier == 'unary': + yield UnaryToken() + else: + yield IdentifierToken(identifier) +{% endhighlight %} + + +This just adds lexer support for the unary and binary keywords, like we +did in [previous chapters](PythonLangImpl5.html#iflexer). One nice +thing about our current AST, is that we represent binary operators with full +generalisation by using their ASCII code as the opcode. For our extended +operators, we'll use this same representation, so we don't need any new AST or +parser support. + +On the other hand, we have to be able to represent the definitions of these +new operators, in the "def binary| 5" part of the function definition. In our +grammar so far, the "name" for the function definition is parsed as the +"prototype" production and into the `PrototypeNode`. To represent our +new user-defined operators as prototypes, we have to extend the +`PrototypeNode` like this: + + +{% highlight python %} +# This class represents the "prototype" for a function, which captures its name, +# and its argument names (thus implicitly the number of arguments the function +# takes), as well as if it is an operator. +class PrototypeNode(object): + + def __init__(self, name, args, is_operator=False, precedence=0): + self.name = name + self.args = args + self.is_operator = is_operator + self.precedence = precedence + + def IsBinaryOp(self): + return self.is_operator and len(self.args) == 2 + + def GetOperatorName(self): + assert self.is_operator + return self.name[-1] + + def CodeGen(self): + ... +{% endhighlight %} + + +Basically, in addition to knowing a name for the prototype, we now keep track +of whether it was an operator, and if it was, what precedence level the operator +is at. The precedence is only used for binary operators (as you'll see below, +it just doesn't apply for unary operators). Now that we have a way to represent +the prototype for a user-defined operator, we need to parse it: + + +{% highlight python %} + # prototype + # ::= id '(' id* ')' + # ::= binary LETTER number? (id, id) + # ::= unary LETTER (id) + def ParsePrototype(self): + precedence = None + if isinstance(self.current, IdentifierToken): + kind = 'normal' + function_name = self.current.name + self.Next() # eat function name. + elif isinstance(self.current, BinaryToken): + kind = 'binary' + self.Next() # eat 'binary'. + if not isinstance(self.current, CharacterToken): + raise RuntimeError('Expected an operator after "binary".') + function_name = 'binary' + self.current.char + self.Next() # eat the operator. + if isinstance(self.current, NumberToken): + if not 1 <= self.current.value <= 100: + raise RuntimeError('Invalid precedence: must be in range [1, 100].') + precedence = self.current.value + self.Next() # eat the precedence. + else: + raise RuntimeError('Expected function name, "unary" or "binary" in ' + 'prototype.') + + if self.current != CharacterToken('('): + raise RuntimeError('Expected "(" in prototype.') + self.Next() # eat '('. + + arg_names = [] + while isinstance(self.current, IdentifierToken): + arg_names.append(self.current.name) + self.Next() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")" in prototype.') + + # Success. + self.Next() # eat ')'. + + if kind == 'binary' and len(arg_names) != 2: + raise RuntimeError('Invalid number of arguments for a binary operator.') + + return PrototypeNode(function_name, arg_names, kind != 'normal', precedence) + +{% endhighlight %} + + +This is all fairly straightforward parsing code, and we have already seen +a lot of similar code in the past. One interesting part about the code above is +the couple lines that set up `function_name` for operators. This builds +names like "binary@" for a newly defined "@" operator. This then takes +advantage of the fact that symbol names in the LLVM symbol table are allowed to +have any character in them. + +The next interesting thing to add, is codegen support for these binary +operators. Given our current structure, this is a simple addition of a default +case for our existing binary operator node: + + +{% highlight python %} + def CodeGen(self): + left = self.left.CodeGen() + right = self.right.CodeGen() + + if self.operator == '+': + return g_llvm_builder.fadd(left, right, 'addtmp') + elif self.operator == '-': + return g_llvm_builder.fsub(left, right, 'subtmp') + elif self.operator == '*': + return g_llvm_builder.fmul(left, right, 'multmp') + elif self.operator == '<': + result = g_llvm_builder.fcmp(FCMP_ULT, left, right, 'cmptmp') + # Convert bool 0 or 1 to double 0.0 or 1.0. + return g_llvm_builder.uitofp(result, Type.double(), 'booltmp') + else: + function = g_llvm_module.get_function_named('binary' + self.operator) + return g_llvm_builder.call(function, [left, right], 'binop') +{% endhighlight %} + + +As you can see above, the new code is actually really simple. It just does +a lookup for the appropriate operator in the symbol table and generates a +function call to it. Since user-defined operators are just built as normal +functions (because the "prototype" boils down to a function with the right +name) everything falls into place. + +The final piece of code we are missing, is a bit of top-level magic. We will +need to make the dinary precedence map global and modify it whenever we define a +new binary operator: + + +{% highlight python %} +# The binary operator precedence chart. +g_binop_precedence = {} +... +class FunctionNode(object): + ... + def CodeGen(self): + ... + # Create a function object. + function = self.prototype.CodeGen() + + # If this is a binary operator, install its precedence. + if self.prototype.IsBinaryOp(): + operator = self.prototype.GetOperatorName() + g_binop_precedence[operator] = self.prototype.precedence + ... + # Finish off the function. + try: + ... + except: + function.delete() + if self.prototype.IsBinaryOp(): + del g_binop_precedence[self.prototype.GetOperatorName()] + raise + + return function +... +def main(): + ... + g_binop_precedence['<'] = 10 + g_binop_precedence['+'] = 20 + g_binop_precedence['-'] = 20 + g_binop_precedence['*'] = 40 + ... +{% endhighlight %} + + +Basically, before CodeGening a function, if it is a user-defined operator, we +register it in the precedence table. This allows the binary operator parsing +logic we already have in place to handle it. Since we are working on a +fully-general operator precedence parser, this is all we need to do to "extend +the grammar". + +Now we have useful user-defined binary operators. This builds a lot +on the previous framework we built for other operators. Adding unary operators +is a bit more challenging, because we don't have any framework for it yet - +let's see what it takes. + +# User-defined Unary Operators # {#unary} + +Since we don't currently support unary operators in the Kaleidoscope +language, we'll need to add everything to support them. Above, we added simple +support for the 'unary' keyword to the lexer. In addition to that, we need an +AST node: + + +{% highlight python %} +# Expression class for a unary operator. +class UnaryExpressionNode(ExpressionNode): + + def __init__(self, operator, operand): + self.operator = operator + self.operand = operand + + def CodeGen(self): + ... +{% endhighlight %} + + +This AST node is very simple and obvious by now. It directly mirrors the +binary operator AST node, except that it only has one child. With this, we +need to add the parsing logic. Parsing a unary operator is pretty simple: we'll +add a new function to do it: + + +{% highlight python %} + # unary ::= primary | unary_operator unary + def ParseUnary(self): + # If the current token is not an operator, it must be a primary expression. + if (not isinstance(self.current, CharacterToken) or + self.current in [CharacterToken('('), CharacterToken(',')]): + return self.ParsePrimary() + + # If this is a unary operator, read it. + operator = self.current.char + self.Next() # eat the operator. + return UnaryExpressionNode(operator, self.ParseUnary()) +{% endhighlight %} + + +The grammar we add is pretty straightforward here. If we see a unary +operator when parsing a primary operator, we eat the operator as a prefix and +parse the remaining piece as another unary operator. This allows us to handle +multiple unary operators (e.g. `!!x`). Note that unary operators can't have +ambiguous parses like binary operators can, so there is no need for precedence +information. + +The problem with this function, is that we need to call ParseUnary from +somewhere. To do this, we change previous callers of ParsePrimary to call +ParseUnary instead: + + +{% highlight python %} + # binoprhs ::= (binary_operator unary)* + def ParseBinOpRHS(self, left, left_precedence): + ... + # Parse the unary expression after the binary operator. + right = self.ParseUnary() + ... + + # expression ::= unary binoprhs + def ParseExpression(self): + left = self.ParseUnary() + return self.ParseBinOpRHS(left, 0) +{% endhighlight %} + + +With these two simple changes, we are now able to parse unary operators and +build the AST for them. Next up, we need to add parser support for prototypes, +to parse the unary operator prototype. We extend the binary operator code above +with: + + +{% highlight python %} + # prototype + # ::= id '(' id* ')' + # ::= binary LETTER number? (id, id) + # ::= unary LETTER (id) + def ParsePrototype(self): + precedence = None + if isinstance(self.current, IdentifierToken): + ... + elif isinstance(self.current, UnaryToken): + kind = 'unary' + self.Next() # eat 'unary'. + if not isinstance(self.current, CharacterToken): + raise RuntimeError('Expected an operator after "unary".') + function_name = 'unary' + self.current.char + self.Next() # eat the operator. + elif isinstance(self.current, BinaryToken): + ... + else: + raise RuntimeError('Expected function name, "unary" or "binary" in ' + 'prototype.') + ... + if kind == 'unary' and len(arg_names) != 1: + raise RuntimeError('Invalid number of arguments for a unary operator.') + elif kind == 'binary' and len(arg_names) != 2: + raise RuntimeError('Invalid number of arguments for a binary operator.') + + return PrototypeNode(function_name, arg_names, kind != 'normal', precedence) +{% endhighlight %} + + +As with binary operators, we name unary operators with a name that includes +the operator character. This assists us at code generation time. Speaking of, +the final piece we need to add is codegen support for unary operators. It looks +like this: + + +{% highlight python %} +class UnaryExpressionNode(ExpressionNode): + ... + def CodeGen(self): + operand = self.operand.CodeGen() + function = g_llvm_module.get_function_named('unary' + self.operator) + return g_llvm_builder.call(function, [operand], 'unop') +{% endhighlight %} + + +This code is similar to, but simpler than, the code for binary operators. It +is simpler primarily because it doesn't need to handle any predefined operators. + +* * * + +# Kicking the Tires # {#example} + +It is somewhat hard to believe, but with a few simple extensions we've +covered in the last chapters, we have grown a real-ish language. With this, we +can do a lot of interesting things, including I/O, math, and a bunch of other +things. For example, we can now add a nice sequencing operator (assuming we +import `putchard` as described in +Chapter +4): + + +{% highlight python %} +ready> def binary : 1 (x y) 0 # Low-precedence operator that ignores operands. +... +ready> extern putchard(x) +... +ready> def printd(x) putchard(x) : putchard(10) +.. +ready> printd(65) : printd(66) : printd(67) +A +B +C +Evaluated to: 0.0 +{% endhighlight %} + + +We can also define a bunch of other "primitive" operations, such as: + + +{% highlight python %} +# Logical unary not. +def unary!(v) + if v then + 0 + else + 1 + +# Unary negate. +def unary-(v) + 0-v + +# Define > with the same precedence as <. +def binary> 10 (LHS RHS) + RHS < LHS + +# Binary logical or, which does not short circuit. +def binary| 5 (LHS RHS) + if LHS then + 1 + else if RHS then + 1 + else + 0 + +# Binary logical and, which does not short circuit. +def binary& 6 (LHS RHS) + if !LHS then + 0 + else + !!RHS + +# Define = with slightly lower precedence than relationals. +def binary = 9 (LHS RHS) + !(LHS < RHS | LHS > RHS) + +{% endhighlight %} + + + +Given the previous if/then/else support, we can also define interesting +functions for I/O. For example, the following prints out a character whose +"density" reflects the value passed in: the lower the value, the denser the +character: + + +{% highlight python %} +ready> + +extern putchard(char) +def printdensity(d) + if d > 8 then + putchard(32) # ' ' + else if d > 4 then + putchard(46) # '.' + else if d > 2 then + putchard(43) # '+' + else + putchard(42); # '*' +... +ready> printdensity(1): printdensity(2): printdensity(3) : + printdensity(4): printdensity(5): printdensity(9): putchard(10) +*++.. +Evaluated to 0.000000 +{% endhighlight %} + + +Based on these simple primitive operations, we can start to define more +interesting things. For example, here's a little function that solves for the +number of iterations it takes a function in the complex plane to +converge: + + +{% highlight python %} +# determine whether the specific location diverges. +# Solve for z = z^2 + c in the complex plane. +def mandelconverger(real imag iters creal cimag) + if iters > 255 | (real*real + imag*imag > 4) then + iters + else + mandelconverger(real*real - imag*imag + creal, + 2*real*imag + cimag, + iters+1, creal, cimag) + +# return the number of iterations required for the iteration to escape +def mandelconverge(real imag) + mandelconverger(real, imag, 0, real, imag) +{% endhighlight %} + + +This "z = z2 + c" function is a beautiful little creature that is +the basis for computation of the +[Mandelbrot Set](http://en.wikipedia.org/wiki/Mandelbrot_set). Our +`mandelconverge` function returns the number of iterations that it takes +for a complex orbit to escape, saturating to 255. This is not a very useful +function by itself, but if you plot its value over a two-dimensional plane, +you can see the Mandelbrot set. Given that we are limited to using putchard +here, our amazing graphical output is limited, but we can whip together +something using the density plotter above: + + +{% highlight python %} +# compute and plot the mandlebrot set with the specified 2 dimensional range +# info. +def mandelhelp(xmin xmax xstep ymin ymax ystep) + for y = ymin, y < ymax, ystep in ( + (for x = xmin, x < xmax, xstep in + printdensity(mandleconverge(x,y))) + : putchard(10) + ) + +# mandel - This is a convenient helper function for ploting the mandelbrot set +# from the specified position with the specified Magnification. +def mandel(realstart imagstart realmag imagmag) + mandelhelp(realstart, realstart+realmag*78, realmag, + imagstart, imagstart+imagmag*40, imagmag); +{% endhighlight %} + + +Given this, we can try plotting out the mandlebrot set! Lets try it out: + + +{% highlight bash %} +ready> mandel(-2.3, -1.3, 0.05, 0.07) +******************************************************************************* +******************************************************************************* +****************************************++++++********************************* +************************************+++++...++++++***************************** +*********************************++++++++.. ...+++++*************************** +*******************************++++++++++.. ..+++++************************** +******************************++++++++++. ..++++++************************* +****************************+++++++++.... ..++++++************************ +**************************++++++++....... .....++++*********************** +*************************++++++++. . ... .++********************** +***********************++++++++... ++********************** +*********************+++++++++.... .+++********************* +******************+++..+++++.... ..+++******************** +**************++++++. .......... +++******************** +***********++++++++.. .. .++******************** +*********++++++++++... .++++******************* +********++++++++++.. .++++******************* +*******++++++..... ..++++******************* +*******+........ ...++++******************* +*******+... .... ...++++******************* +*******+++++...... ..++++******************* +*******++++++++++... .++++******************* +*********++++++++++... ++++******************* +**********+++++++++.. .. ..++******************** +*************++++++.. .......... +++******************** +******************+++...+++..... ..+++******************** +*********************+++++++++.... ..++********************* +***********************++++++++... +++********************* +*************************+++++++.. . ... .++********************** +**************************++++++++....... ......+++*********************** +****************************+++++++++.... ..++++++************************ +*****************************++++++++++.. ..++++++************************* +*******************************++++++++++.. ...+++++************************** +*********************************++++++++.. ...+++++*************************** +***********************************++++++....+++++***************************** +***************************************++++++++******************************** +******************************************************************************* +******************************************************************************* +******************************************************************************* +******************************************************************************* +******************************************************************************* +Evaluated to 0.0 +ready> mandel(-2, -1, 0.02, 0.04) +******************************************************************+++++++++++++ +****************************************************************+++++++++++++++ +*************************************************************++++++++++++++++++ +***********************************************************++++++++++++++++++++ +********************************************************+++++++++++++++++++++++ +******************************************************++++++++++++++++++++++... +***************************************************+++++++++++++++++++++....... +*************************************************++++++++++++++++++++.......... +***********************************************+++++++++++++++++++... ... +********************************************++++++++++++++++++++...... +******************************************++++++++++++++++++++....... +***************************************+++++++++++++++++++++.......... +************************************++++++++++++++++++++++........... +********************************++++++++++++++++++++++++......... +***************************++++++++...........+++++.............. +*********************++++++++++++.... ......................... +***************+++++++++++++++++.... ......... ............ +***********+++++++++++++++++++++..... ...... +********+++++++++++++++++++++++....... +******+++++++++++++++++++++++++........ +****+++++++++++++++++++++++++....... +***+++++++++++++++++++++++......... +**++++++++++++++++........... +*++++++++++++................ +*++++.................... + +*++++.................... +*++++++++++++................ +**++++++++++++++++........... +***+++++++++++++++++++++++......... +****+++++++++++++++++++++++++....... +******+++++++++++++++++++++++++........ +********+++++++++++++++++++++++....... +***********+++++++++++++++++++++..... ...... +***************+++++++++++++++++.... ......... ............ +*********************++++++++++++.... ......................... +***************************++++++++...........+++++.............. +********************************++++++++++++++++++++++++......... +************************************++++++++++++++++++++++........... +***************************************+++++++++++++++++++++.......... +******************************************++++++++++++++++++++....... +Evaluated to: 0.0 +ready> mandel(-0.9, -1.4, 0.02, 0.03) +******************************************************************************* +******************************************************************************* +******************************************************************************* +******************************************************************************* +******************************************************************************* +******************************************************************************* +******************************************************************************* +******************************************************************************* +****************************+++++++++++++++++********************************** +***********************+++++++++++...++++++++++++****************************** +********************+++++++++++++.. . .++++++++++++++************************** +*****************++++++++++++++++... ......++++++++++++************************ +**************+++++++++++++++++++... .......+++++++++++********************** +************++++++++++++++++++++.... .... ..++++++++++++******************** +**********++++++++++++++++++++++...... ...++++++++++++******************* +********+++++++++++++++++++++++....... .....++++++++++++++***************** +******++++++++++++++++++++++++....... .....+++++++++++++++**************** +****+++++++++++++++++++++++++.... . .....+++++++++++++++*************** +**+++++++++++++++++++++++++.... ...++++++++++++++++************* +*+++++++++++++++++++++++....... ....++++++++++++++++************ ++++++++++++++++++++++.......... .....++++++++++++++++*********** +++++++++++++++++++............. .......+++++++++++++++********** ++++++++++++++++................ ............++++++++++********** ++++++++++++++................. .................+++++********* ++++++++++++... .... .......... .+++++******** +++++++++++..... ........ ...+++++******* +++++++++...... ..++++++****** ++++++++........ ..+++++****** ++++++.......... ..++++++***** +++++.......... ....++++++***** +++.......... ....+++++++**** +.......... ......+++++++*** +.......... .....+++++++*** +.......... .....++++++*** +......... .+++++++** +........ .+++++++** + ...... ...+++++++* + . ....++++++++* + ...++++++++* + ..+++++++++ + ..+++++++++ +Evaluated to: 0.0 +ready> ^C +{% endhighlight %} + + +At this point, you may be starting to realize that Kaleidoscope is a real +and powerful language. It may not be self-similar :), but it can be used to +plot things that are! + +With this, we conclude the "adding user-defined operators" chapter of the +tutorial. We have successfully augmented our language, adding the ability to extend the +language in the library, and we have shown how this can be used to build a simple but +interesting end-user application in Kaleidoscope. At this point, Kaleidoscope +can build a variety of applications that are functional and can call functions +with side-effects, but it can't actually define and mutate a variable itself. + + +Strikingly, variable mutation is an important feature of some +languages, and it is not at all obvious how to +[add support for mutable variables](PythonLangImpl7.html) without +having to add an "SSA construction" phase to your front-end. In the next +chapter, we will describe how you can add variable mutation without building SSA +in your front-end. + +* * * + +# Full Code Listing # {#code} + +Here is the complete code listing for our running example, enhanced with the +if/then/else and for expressions: + + +{% highlight python %} +#!/usr/bin/env python + +import re +from llvm.core import Module, Constant, Type, Function, Builder +from llvm.ee import ExecutionEngine, TargetData +from llvm.passes import FunctionPassManager + +from llvm.core import FCMP_ULT, FCMP_ONE +from llvm.passes import (PASS_INSTRUCTION_COMBINING, + PASS_REASSOCIATE, + PASS_GVN, + PASS_CFG_SIMPLIFICATION) + +################################################################################ +## Globals +################################################################################ + +# The LLVM module, which holds all the IR code. +g_llvm_module = Module.new('my cool jit') + +# The LLVM instruction builder. Created whenever a new function is entered. +g_llvm_builder = None + +# A dictionary that keeps track of which values are defined in the current scope +# and what their LLVM representation is. +g_named_values = {} + +# The function optimization passes manager. +g_llvm_pass_manager = FunctionPassManager.new(g_llvm_module) + +# The LLVM execution engine. +g_llvm_executor = ExecutionEngine.new(g_llvm_module) + +# The binary operator precedence chart. +g_binop_precedence = {} + +################################################################################ +## Lexer +################################################################################ + +# The lexer yields one of these types for each token. +class EOFToken(object): pass +class DefToken(object): pass +class ExternToken(object): pass +class IfToken(object): pass +class ThenToken(object): pass +class ElseToken(object): pass +class ForToken(object): pass +class InToken(object): pass +class BinaryToken(object): pass +class UnaryToken(object): pass + +class IdentifierToken(object): + def __init__(self, name): self.name = name + +class NumberToken(object): + def __init__(self, value): self.value = value + +class CharacterToken(object): + def __init__(self, char): self.char = char + def __eq__(self, other): + return isinstance(other, CharacterToken) and self.char == other.char + def __ne__(self, other): return not self == other + +# Regular expressions that tokens and comments of our language. +REGEX_NUMBER = re.compile('[0-9]+(?:\.[0-9]+)?') +REGEX_IDENTIFIER = re.compile('[a-zA-Z][a-zA-Z0-9]*') +REGEX_COMMENT = re.compile('#.*') + +def Tokenize(string): + while string: + # Skip whitespace. + if string[0].isspace(): + string = string[1:] + continue + + # Run regexes. + comment_match = REGEX_COMMENT.match(string) + number_match = REGEX_NUMBER.match(string) + identifier_match = REGEX_IDENTIFIER.match(string) + + # Check if any of the regexes matched and yield the appropriate result. + if comment_match: + comment = comment_match.group(0) + string = string[len(comment):] + elif number_match: + number = number_match.group(0) + yield NumberToken(float(number)) + string = string[len(number):] + elif identifier_match: + identifier = identifier_match.group(0) + # Check if we matched a keyword. + if identifier == 'def': + yield DefToken() + elif identifier == 'extern': + yield ExternToken() + elif identifier == 'if': + yield IfToken() + elif identifier == 'then': + yield ThenToken() + elif identifier == 'else': + yield ElseToken() + elif identifier == 'for': + yield ForToken() + elif identifier == 'in': + yield InToken() + elif identifier == 'binary': + yield BinaryToken() + elif identifier == 'unary': + yield UnaryToken() + else: + yield IdentifierToken(identifier) + string = string[len(identifier):] + else: + # Yield the ASCII value of the unknown character. + yield CharacterToken(string[0]) + string = string[1:] + + yield EOFToken() + +################################################################################ +## Abstract Syntax Tree (aka Parse Tree) +################################################################################ + +# Base class for all expression nodes. +class ExpressionNode(object): + pass + +# Expression class for numeric literals like "1.0". +class NumberExpressionNode(ExpressionNode): + + def __init__(self, value): + self.value = value + + def CodeGen(self): + return Constant.real(Type.double(), self.value) + +# Expression class for referencing a variable, like "a". +class VariableExpressionNode(ExpressionNode): + + def __init__(self, name): + self.name = name + + def CodeGen(self): + if self.name in g_named_values: + return g_named_values[self.name] + else: + raise RuntimeError('Unknown variable name: ' + self.name) + +# Expression class for a binary operator. +class BinaryOperatorExpressionNode(ExpressionNode): + + def __init__(self, operator, left, right): + self.operator = operator + self.left = left + self.right = right + + def CodeGen(self): + left = self.left.CodeGen() + right = self.right.CodeGen() + + if self.operator == '+': + return g_llvm_builder.fadd(left, right, 'addtmp') + elif self.operator == '-': + return g_llvm_builder.fsub(left, right, 'subtmp') + elif self.operator == '*': + return g_llvm_builder.fmul(left, right, 'multmp') + elif self.operator == '<': + result = g_llvm_builder.fcmp(FCMP_ULT, left, right, 'cmptmp') + # Convert bool 0 or 1 to double 0.0 or 1.0. + return g_llvm_builder.uitofp(result, Type.double(), 'booltmp') + else: + function = g_llvm_module.get_function_named('binary' + self.operator) + return g_llvm_builder.call(function, [left, right], 'binop') + +# Expression class for function calls. +class CallExpressionNode(ExpressionNode): + + def __init__(self, callee, args): + self.callee = callee + self.args = args + + def CodeGen(self): + # Look up the name in the global module table. + callee = g_llvm_module.get_function_named(self.callee) + + # Check for argument mismatch error. + if len(callee.args) != len(self.args): + raise RuntimeError('Incorrect number of arguments passed.') + + arg_values = [i.CodeGen() for i in self.args] + + return g_llvm_builder.call(callee, arg_values, 'calltmp') + +# Expression class for if/then/else. +class IfExpressionNode(ExpressionNode): + + def __init__(self, condition, then_branch, else_branch): + self.condition = condition + self.then_branch = then_branch + self.else_branch = else_branch + + def CodeGen(self): + condition = self.condition.CodeGen() + + # Convert condition to a bool by comparing equal to 0.0. + condition_bool = g_llvm_builder.fcmp( + FCMP_ONE, condition, Constant.real(Type.double(), 0), 'ifcond') + + function = g_llvm_builder.basic_block.function + + # Create blocks for the then and else cases. Insert the 'then' block at the + # end of the function. + then_block = function.append_basic_block('then') + else_block = function.append_basic_block('else') + merge_block = function.append_basic_block('ifcond') + + g_llvm_builder.cbranch(condition_bool, then_block, else_block) + + # Emit then value. + g_llvm_builder.position_at_end(then_block) + then_value = self.then_branch.CodeGen() + g_llvm_builder.branch(merge_block) + + # Codegen of 'Then' can change the current block; update then_block for the + # PHI node. + then_block = g_llvm_builder.basic_block + + # Emit else block. + g_llvm_builder.position_at_end(else_block) + else_value = self.else_branch.CodeGen() + g_llvm_builder.branch(merge_block) + + # Codegen of 'Else' can change the current block, update else_block for the + # PHI node. + else_block = g_llvm_builder.basic_block + + # Emit merge block. + g_llvm_builder.position_at_end(merge_block) + phi = g_llvm_builder.phi(Type.double(), 'iftmp') + phi.add_incoming(then_value, then_block) + phi.add_incoming(else_value, else_block) + + return phi + +# Expression class for for/in. +class ForExpressionNode(ExpressionNode): + + def __init__(self, loop_variable, start, end, step, body): + self.loop_variable = loop_variable + self.start = start + self.end = end + self.step = step + self.body = body + + def CodeGen(self): + # Output this as: + # ... + # start = startexpr + # goto loop + # loop: + # variable = phi [start, loopheader], [nextvariable, loopend] + # ... + # bodyexpr + # ... + # loopend: + # step = stepexpr + # nextvariable = variable + step + # endcond = endexpr + # br endcond, loop, endloop + # outloop: + + # Emit the start code first, without 'variable' in scope. + start_value = self.start.CodeGen() + + # Make the new basic block for the loop header, inserting after current + # block. + function = g_llvm_builder.basic_block.function + pre_header_block = g_llvm_builder.basic_block + loop_block = function.append_basic_block('loop') + + # Insert an explicit fallthrough from the current block to the loop_block. + g_llvm_builder.branch(loop_block) + + # Start insertion in loop_block. + g_llvm_builder.position_at_end(loop_block) + + # Start the PHI node with an entry for start. + variable_phi = g_llvm_builder.phi(Type.double(), self.loop_variable) + variable_phi.add_incoming(start_value, pre_header_block) + + # Within the loop, the variable is defined equal to the PHI node. If it + # shadows an existing variable, we have to restore it, so save it now. + old_value = g_named_values.get(self.loop_variable, None) + g_named_values[self.loop_variable] = variable_phi + + # Emit the body of the loop. This, like any other expr, can change the + # current BB. Note that we ignore the value computed by the body. + self.body.CodeGen() + + # Emit the step value. + if self.step: + step_value = self.step.CodeGen() + else: + # If not specified, use 1.0. + step_value = Constant.real(Type.double(), 1) + + next_value = g_llvm_builder.fadd(variable_phi, step_value, 'next') + + # Compute the end condition and convert it to a bool by comparing to 0.0. + end_condition = self.end.CodeGen() + end_condition_bool = g_llvm_builder.fcmp( + FCMP_ONE, end_condition, Constant.real(Type.double(), 0), 'loopcond') + + # Create the "after loop" block and insert it. + loop_end_block = g_llvm_builder.basic_block + after_block = function.append_basic_block('afterloop') + + # Insert the conditional branch into the end of loop_end_block. + g_llvm_builder.cbranch(end_condition_bool, loop_block, after_block) + + # Any new code will be inserted in after_block. + g_llvm_builder.position_at_end(after_block) + + # Add a new entry to the PHI node for the backedge. + variable_phi.add_incoming(next_value, loop_end_block) + + # Restore the unshadowed variable. + if old_value: + g_named_values[self.loop_variable] = old_value + else: + del g_named_values[self.loop_variable] + + # for expr always returns 0.0. + return Constant.real(Type.double(), 0) + +# Expression class for a unary operator. +class UnaryExpressionNode(ExpressionNode): + + def __init__(self, operator, operand): + self.operator = operator + self.operand = operand + + def CodeGen(self): + operand = self.operand.CodeGen() + function = g_llvm_module.get_function_named('unary' + self.operator) + return g_llvm_builder.call(function, [operand], 'unop') + +# This class represents the "prototype" for a function, which captures its name, +# and its argument names (thus implicitly the number of arguments the function +# takes), as well as if it is an operator. +class PrototypeNode(object): + + def __init__(self, name, args, is_operator=False, precedence=0): + self.name = name + self.args = args + self.is_operator = is_operator + self.precedence = precedence + + def IsBinaryOp(self): + return self.is_operator and len(self.args) == 2 + + def GetOperatorName(self): + assert self.is_operator + return self.name[-1] + + def CodeGen(self): + # Make the function type, eg. double(double,double). + funct_type = Type.function( + Type.double(), [Type.double()] * len(self.args), False) + + function = Function.new(g_llvm_module, funct_type, self.name) + + # If the name conflicted, there was already something with the same name. + # If it has a body, don't allow redefinition or reextern. + if function.name != self.name: + function.delete() + function = g_llvm_module.get_function_named(self.name) + + # If the function already has a body, reject this. + if not function.is_declaration: + raise RuntimeError('Redefinition of function.') + + # If the function took a different number of args, reject. + if len(function.args) != len(self.args): + raise RuntimeError('Redeclaration of a function with different number ' + 'of args.') + + # Set names for all arguments and add them to the variables symbol table. + for arg, arg_name in zip(function.args, self.args): + arg.name = arg_name + # Add arguments to variable symbol table. + g_named_values[arg_name] = arg + + return function + +# This class represents a function definition itself. +class FunctionNode(object): + + def __init__(self, prototype, body): + self.prototype = prototype + self.body = body + + def CodeGen(self): + # Clear scope. + g_named_values.clear() + + # Create a function object. + function = self.prototype.CodeGen() + + # If this is a binary operator, install its precedence. + if self.prototype.IsBinaryOp(): + operator = self.prototype.GetOperatorName() + g_binop_precedence[operator] = self.prototype.precedence + + # Create a new basic block to start insertion into. + block = function.append_basic_block('entry') + global g_llvm_builder + g_llvm_builder = Builder.new(block) + + # Finish off the function. + try: + return_value = self.body.CodeGen() + g_llvm_builder.ret(return_value) + + # Validate the generated code, checking for consistency. + function.verify() + + # Optimize the function. + g_llvm_pass_manager.run(function) + except: + function.delete() + if self.prototype.IsBinaryOp(): + del g_binop_precedence[self.prototype.GetOperatorName()] + raise + + return function + + +################################################################################ +## Parser +################################################################################ + +class Parser(object): + + def __init__(self, tokens): + self.tokens = tokens + self.Next() + + # Provide a simple token buffer. Parser.current is the current token the + # parser is looking at. Parser.Next() reads another token from the lexer and + # updates Parser.current with its results. + def Next(self): + self.current = self.tokens.next() + + # Gets the precedence of the current token, or -1 if the token is not a binary + # operator. + def GetCurrentTokenPrecedence(self): + if isinstance(self.current, CharacterToken): + return g_binop_precedence.get(self.current.char, -1) + else: + return -1 + + # identifierexpr ::= identifier | identifier '(' expression* ')' + def ParseIdentifierExpr(self): + identifier_name = self.current.name + self.Next() # eat identifier. + + if self.current != CharacterToken('('): # Simple variable reference. + return VariableExpressionNode(identifier_name) + + # Call. + self.Next() # eat '('. + args = [] + if self.current != CharacterToken(')'): + while True: + args.append(self.ParseExpression()) + if self.current == CharacterToken(')'): + break + elif self.current != CharacterToken(','): + raise RuntimeError('Expected ")" or "," in argument list.') + self.Next() + + self.Next() # eat ')'. + return CallExpressionNode(identifier_name, args) + + # numberexpr ::= number + def ParseNumberExpr(self): + result = NumberExpressionNode(self.current.value) + self.Next() # consume the number. + return result + + # parenexpr ::= '(' expression ')' + def ParseParenExpr(self): + self.Next() # eat '('. + + contents = self.ParseExpression() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")".') + self.Next() # eat ')'. + + return contents + + # ifexpr ::= 'if' expression 'then' expression 'else' expression + def ParseIfExpr(self): + self.Next() # eat the if. + + # condition. + condition = self.ParseExpression() + + if not isinstance(self.current, ThenToken): + raise RuntimeError('Expected "then".') + self.Next() # eat the then. + + then_branch = self.ParseExpression() + + if not isinstance(self.current, ElseToken): + raise RuntimeError('Expected "else".') + self.Next() # eat the else. + + else_branch = self.ParseExpression() + + return IfExpressionNode(condition, then_branch, else_branch) + + # forexpr ::= 'for' identifier '=' expr ',' expr (',' expr)? 'in' expression + def ParseForExpr(self): + self.Next() # eat the for. + + if not isinstance(self.current, IdentifierToken): + raise RuntimeError('Expected identifier after for.') + + loop_variable = self.current.name + self.Next() # eat the identifier. + + if self.current != CharacterToken('='): + raise RuntimeError('Expected "=" after for variable.') + self.Next() # eat the '='. + + start = self.ParseExpression() + + if self.current != CharacterToken(','): + raise RuntimeError('Expected "," after for start value.') + self.Next() # eat the ','. + + end = self.ParseExpression() + + # The step value is optional. + if self.current == CharacterToken(','): + self.Next() # eat the ','. + step = self.ParseExpression() + else: + step = None + + if not isinstance(self.current, InToken): + raise RuntimeError('Expected "in" after for variable specification.') + self.Next() # eat 'in'. + + body = self.ParseExpression() + + return ForExpressionNode(loop_variable, start, end, step, body) + + # primary ::= identifierexpr | numberexpr | parenexpr | ifexpr | forexpr + def ParsePrimary(self): + if isinstance(self.current, IdentifierToken): + return self.ParseIdentifierExpr() + elif isinstance(self.current, NumberToken): + return self.ParseNumberExpr() + elif isinstance(self.current, IfToken): + return self.ParseIfExpr() + elif isinstance(self.current, ForToken): + return self.ParseForExpr() + elif self.current == CharacterToken('('): + return self.ParseParenExpr() + else: + raise RuntimeError('Unknown token when expecting an expression.') + + # unary ::= primary | unary_operator unary + def ParseUnary(self): + # If the current token is not an operator, it must be a primary expression. + if (not isinstance(self.current, CharacterToken) or + self.current in [CharacterToken('('), CharacterToken(',')]): + return self.ParsePrimary() + + # If this is a unary operator, read it. + operator = self.current.char + self.Next() # eat the operator. + return UnaryExpressionNode(operator, self.ParseUnary()) + + # binoprhs ::= (binary_operator unary)* + def ParseBinOpRHS(self, left, left_precedence): + # If this is a binary operator, find its precedence. + while True: + precedence = self.GetCurrentTokenPrecedence() + + # If this is a binary operator that binds at least as tightly as the + # current one, consume it; otherwise we are done. + if precedence < left_precedence: + return left + + binary_operator = self.current.char + self.Next() # eat the operator. + + # Parse the unary expression after the binary operator. + right = self.ParseUnary() + + # If binary_operator binds less tightly with right than the operator after + # right, let the pending operator take right as its left. + next_precedence = self.GetCurrentTokenPrecedence() + if precedence < next_precedence: + right = self.ParseBinOpRHS(right, precedence + 1) + + # Merge left/right. + left = BinaryOperatorExpressionNode(binary_operator, left, right) + + # expression ::= unary binoprhs + def ParseExpression(self): + left = self.ParseUnary() + return self.ParseBinOpRHS(left, 0) + + # prototype + # ::= id '(' id* ')' + # ::= binary LETTER number? (id, id) + # ::= unary LETTER (id) + def ParsePrototype(self): + precedence = None + if isinstance(self.current, IdentifierToken): + kind = 'normal' + function_name = self.current.name + self.Next() # eat function name. + elif isinstance(self.current, UnaryToken): + kind = 'unary' + self.Next() # eat 'unary'. + if not isinstance(self.current, CharacterToken): + raise RuntimeError('Expected an operator after "unary".') + function_name = 'unary' + self.current.char + self.Next() # eat the operator. + elif isinstance(self.current, BinaryToken): + kind = 'binary' + self.Next() # eat 'binary'. + if not isinstance(self.current, CharacterToken): + raise RuntimeError('Expected an operator after "binary".') + function_name = 'binary' + self.current.char + self.Next() # eat the operator. + if isinstance(self.current, NumberToken): + if not 1 <= self.current.value <= 100: + raise RuntimeError('Invalid precedence: must be in range [1, 100].') + precedence = self.current.value + self.Next() # eat the precedence. + else: + raise RuntimeError('Expected function name, "unary" or "binary" in ' + 'prototype.') + + if self.current != CharacterToken('('): + raise RuntimeError('Expected "(" in prototype.') + self.Next() # eat '('. + + arg_names = [] + while isinstance(self.current, IdentifierToken): + arg_names.append(self.current.name) + self.Next() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")" in prototype.') + + # Success. + self.Next() # eat ')'. + + if kind == 'unary' and len(arg_names) != 1: + raise RuntimeError('Invalid number of arguments for a unary operator.') + elif kind == 'binary' and len(arg_names) != 2: + raise RuntimeError('Invalid number of arguments for a binary operator.') + + return PrototypeNode(function_name, arg_names, kind != 'normal', precedence) + + # definition ::= 'def' prototype expression + def ParseDefinition(self): + self.Next() # eat def. + proto = self.ParsePrototype() + body = self.ParseExpression() + return FunctionNode(proto, body) + + # toplevelexpr ::= expression + def ParseTopLevelExpr(self): + proto = PrototypeNode('', []) + return FunctionNode(proto, self.ParseExpression()) + + # external ::= 'extern' prototype + def ParseExtern(self): + self.Next() # eat extern. + return self.ParsePrototype() + + # Top-Level parsing + def HandleDefinition(self): + self.Handle(self.ParseDefinition, 'Read a function definition:') + + def HandleExtern(self): + self.Handle(self.ParseExtern, 'Read an extern:') + + def HandleTopLevelExpression(self): + try: + function = self.ParseTopLevelExpr().CodeGen() + result = g_llvm_executor.run_function(function, []) + print 'Evaluated to:', result.as_real(Type.double()) + except Exception, e: + print 'Error:', e + try: + self.Next() # Skip for error recovery. + except: + pass + + def Handle(self, function, message): + try: + print message, function().CodeGen() + except Exception, e: + print 'Error:', e + try: + self.Next() # Skip for error recovery. + except: + pass + +################################################################################ +## Main driver code. +################################################################################ + +def main(): + # Set up the optimizer pipeline. Start with registering info about how the + # target lays out data structures. + g_llvm_pass_manager.add(g_llvm_executor.target_data) + # Do simple "peephole" optimizations and bit-twiddling optzns. + g_llvm_pass_manager.add(PASS_INSTRUCTION_COMBINING) + # Reassociate expressions. + g_llvm_pass_manager.add(PASS_REASSOCIATE) + # Eliminate Common SubExpressions. + g_llvm_pass_manager.add(PASS_GVN) + # Simplify the control flow graph (deleting unreachable blocks, etc). + g_llvm_pass_manager.add(PASS_CFG_SIMPLIFICATION) + + g_llvm_pass_manager.initialize() + + # Install standard binary operators. + # 1 is lowest possible precedence. 40 is the highest. + g_binop_precedence['<'] = 10 + g_binop_precedence['+'] = 20 + g_binop_precedence['-'] = 20 + g_binop_precedence['*'] = 40 + + # Run the main "interpreter loop". + while True: + print 'ready>', + try: + raw = raw_input() + except KeyboardInterrupt: + break + + parser = Parser(Tokenize(raw)) + while True: + # top ::= definition | external | expression | EOF + if isinstance(parser.current, EOFToken): + break + if isinstance(parser.current, DefToken): + parser.HandleDefinition() + elif isinstance(parser.current, ExternToken): + parser.HandleExtern() + else: + parser.HandleTopLevelExpression() + + # Print out all of the generated code. + print '\n', g_llvm_module + +if __name__ == '__main__': + main() +{% endhighlight %} + + +* * * + +**[Next: Extending the language: mutable variables / SSA construction](PythonLangImpl7.html)** + + diff --git a/docs/source/doc/kaleidoscope/PythonLangImpl7.md b/docs/source/doc/kaleidoscope/PythonLangImpl7.md new file mode 100644 index 0000000..5603ee4 --- /dev/null +++ b/docs/source/doc/kaleidoscope/PythonLangImpl7.md @@ -0,0 +1,1794 @@ +--- +layout: page +title: "Kaleidoscope: Chapter 7" +--- + +# Extending the Language: Mutable Variables / SSA construction + +Written by [Chris Lattner](mailto:sabre@nondot.org) +and [Max Shawabkeh](http://max99x.com) + + +**Chapter 7** + + +* This will become a table of contents (this text will be scraped). +{:toc} + + +**[Chapter 8: Conclusion and other useful LLVM tidbits](PythonLangImpl8.html)** + + +# Introduction # {#intro} + +Welcome to Chapter 7 of the +[Implementing a language with LLVM](http://www.llvm.org/docs/tutorial/index.html) +tutorial. In chapters 1 through 6, we've built a very +respectable, albeit simple, +[functional programming language](http://en.wikipedia.org/wiki/Functional_programming). +In our journey, we learned some parsing techniques, +how to build and represent an AST, how to build LLVM IR, and how to optimize +the resultant code as well as JIT compile it. + +While Kaleidoscope is interesting as a functional language, the fact that it +is functional makes it "too easy" to generate LLVM IR for it. In particular, a +functional language makes it very easy to build LLVM IR directly in +[SSA form](http://en.wikipedia.org/wiki/Static_single_assignment_form). +Since LLVM requires that the input code be in SSA form, this is a very nice +property and it is often unclear to newcomers how to generate code for an +imperative language with mutable variables. + +The short (and happy) summary of this chapter is that there is no need for +your front-end to build SSA form: LLVM provides highly tuned and well tested +support for this, though the way it works is a bit unexpected for some. + + +# Why is this a hard problem? # {#why} + +To understand why mutable variables cause complexities in SSA construction, +consider this extremely simple C example: + + + +{% highlight python %} +int G, H; +int test(_Bool Condition) { + int X; + if (Condition) + X = G; + else + X = H; + return X; +} +{% endhighlight %} + + +In this case, we have the variable "X", whose value depends on the path +executed in the program. Because there are two different possible values for X +before the return instruction, a PHI node is inserted to merge the two values. +The LLVM IR that we want for this example looks like this: + + +{% highlight llvm %} +@G = weak global i32 0 ; type of @G is i32* +@H = weak global i32 0 ; type of @H is i32* +define i32 @test(i1 %Condition) { +entry: + br i1 %Condition, label %cond_true, label %cond_false +cond_true: + %X.0 = load i32* @G + br label %cond_next +cond_false: + %X.1 = load i32* @H + br label %cond_next +cond_next: + %X.2 = phi i32 [ %X.1, %cond_false ], [ %X.0, %cond_true ] + ret i32 %X.2 +} +{% endhighlight %} + + +In this example, the loads from the G and H global variables are explicit in +the LLVM IR, and they live in the then/else branches of the if statement +(cond_true/cond_false). In order to merge the incoming values, the X.2 phi node +in the cond_next block selects the right value to use based on where control +flow is coming from: if control flow comes from the cond_false block, X.2 gets +the value of X.1. Alternatively, if control flow comes from cond_true, it gets +the value of X.0. The intent of this chapter is not to explain the details of +SSA form. For more information, see one of the many +[online references](http://en.wikipedia.org/wiki/Static_single_assignment_form). + +The question for this article is "who places the phi nodes when lowering +assignments to mutable variables?". The issue here is that LLVM +*requires* that its IR be in SSA form: there is no "non-ssa" mode for it. +However, SSA construction requires non-trivial algorithms and data structures, +so it is inconvenient and wasteful for every front-end to have to reproduce this +logic. + +# Memory in LLVM # {#memory} + +The 'trick' here is that while LLVM does require all register values to be +in SSA form, it does not require (or permit) memory objects to be in SSA form. +In the example above, note that the loads from G and H are direct accesses to +G and H: they are not renamed or versioned. This differs from some other +compiler systems, which do try to version memory objects. In LLVM, instead of +encoding dataflow analysis of memory into the LLVM IR, it is handled with +[Analysis Passes](http://www.llvm.org/docs/WritingAnLLVMPass.html) +which are computed on demand. + + +With this in mind, the high-level idea is that we want to make a stack variable +(which lives in memory, because it is on the stack) for each mutable object in +a function. To take advantage of this trick, we need to talk about how LLVM +represents stack variables. + + +In LLVM, all memory accesses are explicit with load/store instructions, and +it is carefully designed not to have (or need) an "address-of" operator. +Notice how the type of the @G/@H global variables is actually "i32*" even though +the variable is defined as "i32". What this means is that @G defines +*space* for an i32 in the global data area, but its *name* +actually refers to the address for that space. Stack variables work the same +way, except that instead of being declared with global variable definitions, +they are declared with the +[LLVM alloca instruction](http://www.llvm.org/docs/LangRef.html#i_alloca): + + +{% highlight python %} +define i32 @example() { +entry: + %X = alloca i32 ; type of %X is i32*. + ... + %tmp = load i32* %X ; load the stack value %X from the stack. + %tmp2 = add i32 %tmp, 1 ; increment it + store i32 %tmp2, i32* %X ; store it back + ... +{% endhighlight %} + + +This code shows an example of how you can declare and manipulate a stack +variable in the LLVM IR. Stack memory allocated with the alloca instruction is +fully general: you can pass the address of the stack slot to functions, you can +store it in other variables, etc. In our example above, we could rewrite the +example to use the alloca technique to avoid using a PHI node: + + +{% highlight llvm %} +@G = weak global i32 0 ; type of @G is i32* +@H = weak global i32 0 ; type of @H is i32* +define i32 @test(i1 %Condition) { +entry: + %X = alloca i32 ; type of %X is i32*. + br i1 %Condition, label %cond_true, label %cond_false +cond_true: + %X.0 = load i32* @G + store i32 %X.0, i32* %X ; Update X + br label %cond_next +cond_false: + %X.1 = load i32* @H + store i32 %X.1, i32* %X ; Update X + br label %cond_next +cond_next: + %X.2 = load i32* %X ; Read X + ret i32 %X.2 +} +{% endhighlight %} + + +With this, we have discovered a way to handle arbitrary mutable variables +without the need to create Phi nodes at all: + +
    +
  1. Each mutable variable becomes a stack allocation.
  2. +
  3. Each read of the variable becomes a load from the stack.
  4. +
  5. Each update of the variable becomes a store to the stack.
  6. +
  7. Taking the address of a variable just uses the stack address directly.
  8. +
+ +While this solution has solved our immediate problem, it introduced another +one: we have now apparently introduced a lot of stack traffic for very simple +and common operations, a major performance problem. Fortunately for us, the +LLVM optimizer has a highly-tuned optimization pass named "mem2reg" that handles +this case, promoting allocas like this into SSA registers, inserting Phi nodes +as appropriate. If you run this example through the pass, for example, you'll +get: + +{% highlight bash %} +$ llvm-as < example.ll | opt -mem2reg | llvm-dis +{% endhighlight %} + +{% highlight llvm %} +@G = weak global i32 0 +@H = weak global i32 0 +define i32 @test(i1 %Condition) { +entry: + br i1 %Condition, label %cond_true, label %cond_false +cond_true: + %X.0 = load i32* @G + br label %cond_next +cond_false: + %X.1 = load i32* @H + br label %cond_next +cond_next: + %X.01 = phi i32 [ %X.1, %cond_false ], [ %X.0, %cond_true ] + ret i32 %X.01 +} +{% endhighlight %} + +The mem2reg pass implements the standard "iterated dominance frontier" +algorithm for constructing SSA form and has a number of optimizations that speed +up (very common) degenerate cases. The mem2reg optimization pass is the answer +to dealing with mutable variables, and we highly recommend that you depend on +it. Note that mem2reg only works on variables in certain circumstances: + +* mem2reg is alloca-driven: it looks for allocas and if it can handle them, it + promotes them. It does not apply to global variables or heap allocations. + +* mem2reg only looks for alloca instructions in the entry block of the + function. Being in the entry block guarantees that the alloca is only + executed once, which makes analysis simpler. + +* mem2reg only promotes allocas whose uses are direct loads and stores. If + the address of the stack object is passed to a function, or if any funny + pointer arithmetic is involved, the alloca will not be promoted. + +* mem2reg only works on allocas of + [first class](http://www.llvm.org/docs/LangRef.html#t_classifications) + values (such as pointers, scalars and vectors), and only if the array size + of the allocation is 1 (or missing in the .ll file). mem2reg is not capable + of promoting structs or arrays to registers. Note that the "scalarrepl" pass + is more powerful and can promote structs, "unions", and arrays in many cases. + + +All of these properties are easy to satisfy for most imperative languages, and +we'll illustrate it below with Kaleidoscope. The final question you may be +asking is: should I bother with this nonsense for my front-end? Wouldn't it be +better if I just did SSA construction directly, avoiding use of the mem2reg +optimization pass? In short, we strongly recommend that you use this technique +for building SSA form, unless there is an extremely good reason not to. Using +this technique is: + +* Proven and well tested: llvm-gcc and clang both use this technique for local + mutable variables. As such, the most common clients of LLVM are using this to + handle a bulk of their variables. You can be sure that bugs are found fast + and fixed early. + +* Extremely Fast: mem2reg has a number of special cases that make it fast in + common cases as well as fully general. For example, it has fast-paths for + variables that are only used in a single block, variables that only have one + assignment point, good heuristics to avoid insertion of unneeded phi nodes, etc. + + +* Needed for debug info generation: + [Debug information in LLVM](http://www.llvm.org/docs/SourceLevelDebugging.html) + relies on having the address of the variable exposed so that debug + info can be attached to it. This technique dovetails very naturally with this + style of debug info. + + +If nothing else, this makes it much easier to get your front-end up and +running, and is very simple to implement. Lets extend Kaleidoscope with mutable +variables now! + + +* * * + +# Mutable Variables in Kaleidoscope # {#kalvars} + +Now that we know the sort of problem we want to tackle, lets see what this +looks like in the context of our little Kaleidoscope language. We're going to +add two features: + +* The ability to mutate variables with the '=' operator. +* The ability to define new variables. + +While the first item is really what this is about, we only have variables +for incoming arguments as well as for induction variables, and redefining those +only goes so far :). Also, the ability to define new variables is a +useful thing regardless of whether you will be mutating them. Here's a +motivating example that shows how we could use these: + + +{% highlight python %} +# Define ':' for sequencing: as a low-precedence operator that ignores operands +# and just returns the RHS. +def binary : 1 (x y) y; + +# Recursive fib, we could do this before. +def fib(x) + if (x < 3) then + 1 + else + fib(x-1) + fib(x-2) + +# Iterative fib. +def fibi(x) + var a = 1, b = 1, c in + (for i = 3, i < x in + c = a + b : + a = b : + b = c) : + b + +# Call it. +fibi(10) +{% endhighlight %} + + + +In order to mutate variables, we have to change our existing variables to use +the "alloca trick". Once we have that, we'll add our new operator, then extend +Kaleidoscope to support new variable definitions. + + +* * * + +# Adjusting Existing Variables for Mutation # {#adjustments} + +The symbol table in Kaleidoscope is managed at code generation time by the +`g_named_values` map. This map currently keeps track of the LLVM +"Value" that holds the double value for the named variable. In order to support +mutation, we need to change this slightly, so that it holds the *memory +location* of the variable in question. Note that this change is a +refactoring: it changes the structure of the code, but does not (by itself) +change the behavior of the compiler. All of these changes are isolated in the +Kaleidoscope code generator. + + +At this point in Kaleidoscope's development, it only supports variables for two +things: incoming arguments to functions and the induction variable of 'for' +loops. For consistency, we'll allow mutation of these variables in addition to +other user-defined variables. This means that these will both need memory +locations. + + +To start our transformation of Kaleidoscope, we will need to create the +allocas that we will store in `g_named_values`. We'll use a helper +function that ensures that the allocas are created in the entry block of the +function: + + +{% highlight python %} +# Creates an alloca instruction in the entry block of the function. This is used +# for mutable variables. +def CreateEntryBlockAlloca(function, var_name): + entry = function.get_entry_basic_block() + builder = Builder.new(entry) + builder.position_at_beginning(entry) + return builder.alloca(Type.double(), var_name) +{% endhighlight %} + + +This code creates a temporary `llvm.core.Builder` that is pointing at +the first instruction of the entry block. It then creates an alloca with the +expected name and returns it. Because all values in Kaleidoscope are doubles, +there is no need to pass in a type to use. + +With this in place, the first functionality change we want to make is to +variable references. In our new scheme, variables live on the stack, so code +generating a reference to them actually needs to produce a load from the stack +slot: + + +{% highlight python %} + def CodeGen(self): + if self.name in g_named_values: + return g_llvm_builder.load(g_named_values[self.name], self.name) + else: + raise RuntimeError('Unknown variable name: ' + self.name) +{% endhighlight %} + + +As you can see, this is pretty straightforward. Now we need to update the +things that define the variables to set up the alloca. We'll start with +`ForExpressionNode.CodeGen` (see the [full code listing](#code) for the +unabridged code): + + +{% highlight python %} + def CodeGen(self): + function = g_llvm_builder.basic_block.function + + # Create an alloca for the variable in the entry block. + alloca = CreateEntryBlockAlloca(function, self.loop_variable) + + # Emit the start code first, without 'variable' in scope. + start_value = self.start.CodeGen() + + # Store the value into the alloca. + g_llvm_builder.store(start_value, alloca) + ... + # Compute the end condition. + end_condition = self.end.CodeGen() + + # Reload, increment, and restore the alloca. This handles the case where + # the body of the loop mutates the variable. + cur_value = g_llvm_builder.load(alloca, self.loop_variable) + next_value = g_llvm_builder.fadd(cur_value, step_value, 'nextvar') + g_llvm_builder.store(next_value, alloca) + + # Convert condition to a bool by comparing equal to 0.0. + end_condition_bool = g_llvm_builder.fcmp( + FCMP_ONE, end_condition, Constant.real(Type.double(), 0), 'loopcond') + ... +{% endhighlight %} + + +This code is virtually identical to the code +[before we allowed mutable variables](PythonLangImpl5.html#forcodegen). +The big difference is that we no longer have to construct a PHI node, and we use +load/store to access the variable as needed. + +To support mutable argument variables, we need to also make allocas for them. +The code for this is also pretty simple: + + +{% highlight python %} +class PrototypeNode(object): + ... + # Create an alloca for each argument and register the argument in the symbol + # table so that references to it will succeed. + def CreateArgumentAllocas(self, function): + for arg_name, arg in zip(self.args, function.args): + alloca = CreateEntryBlockAlloca(function, arg_name) + g_llvm_builder.store(arg, alloca) + g_named_values[arg_name] = alloca +{% endhighlight %} + + +For each argument, we make an alloca, store the input value to the function +into the alloca, and register the alloca as the memory location for the +argument. This method gets invoked by `FunctionNode.CodeGen` right after +it sets up the entry block for the function. + +The final missing piece is adding the mem2reg pass, which allows us to get +good codegen once again: + + +{% highlight python %} +from llvm.passes import (PASS_PROMOTE_MEMORY_TO_REGISTER, + PASS_INSTRUCTION_COMBINING, + PASS_REASSOCIATE, + PASS_GVN, + PASS_CFG_SIMPLIFICATION) +... +def main(): + # Set up the optimizer pipeline. Start with registering info about how the + # target lays out data structures. + g_llvm_pass_manager.add(g_llvm_executor.target_data) + # Promote allocas to registers. + g_llvm_pass_manager.add(PASS_PROMOTE_MEMORY_TO_REGISTER) + # Do simple "peephole" optimizations and bit-twiddling optzns. + g_llvm_pass_manager.add(PASS_INSTRUCTION_COMBINING) + # Reassociate expressions. + g_llvm_pass_manager.add(PASS_REASSOCIATE) +{% endhighlight %} + + +It is interesting to see what the code looks like before and after the +mem2reg optimization runs. For example, this is the before/after code for our +recursive fib function. Before the optimization: + + +{% highlight llvm %} +define double @fib(double %x) { +entry: + %x1 = alloca double + store double %x, double* %x1 + %x2 = load double* %x1 + %cmptmp = fcmp ult double %x2, 3.000000e+00 + %booltmp = uitofp i1 %cmptmp to double + %ifcond = fcmp one double %booltmp, 0.000000e+00 + br i1 %ifcond, label %then, label %else +then: ; preds = %entry + br label %ifcont +else: ; preds = %entry + %x3 = load double* %x1 + %subtmp = fsub double %x3, 1.000000e+00 + %calltmp = call double @fib(double %subtmp) + %x4 = load double* %x1 + %subtmp5 = fsub double %x4, 2.000000e+00 + %calltmp6 = call double @fib(double %subtmp5) + %addtmp = fadd double %calltmp, %calltmp6 + br label %ifcont +ifcont: ; preds = %else, %then + %iftmp = phi double [ 1.000000e+00, %then ], [ %addtmp, %else ] + ret double %iftmp +} +{% endhighlight %} + + +Here there is only one variable (x, the input argument) but you can still +see the extremely simple-minded code generation strategy we are using. In the +entry block, an alloca is created, and the initial input value is stored into +it. Each reference to the variable does a reload from the stack. Also, note +that we didn't modify the if/then/else expression, so it still inserts a PHI +node. While we could make an alloca for it, it is actually easier to create a +PHI node for it, so we still just make the PHI. + +Here is the code after the mem2reg pass runs: + + +{% highlight llvm %} +define double @fib(double %x) { +entry: + %cmptmp = fcmp ult double %x, 3.000000e+00 + %booltmp = uitofp i1 %cmptmp to double + %ifcond = fcmp one double %booltmp, 0.000000e+00 + br i1 %ifcond, label %then, label %else +then: + br label %ifcont +else: + %subtmp = fsub double %x, 1.000000e+00 + %calltmp = call double @fib(double %subtmp) + %subtmp5 = fsub double %x, 2.000000e+00 + %calltmp6 = call double @fib(double %subtmp5) + %addtmp = fadd double %calltmp, %calltmp6 + br label %ifcont +ifcont: ; preds = %else, %then + %iftmp = phi double [ 1.000000e+00, %then ], [ %addtmp, %else ] + ret double %iftmp +} +{% endhighlight %} + + +This is a trivial case for mem2reg, since there are no redefinitions of the +variable. The point of showing this is to calm your tension about inserting +such blatent inefficiencies :). + +After the rest of the optimizers run, we get: + + +{% highlight llvm %} +define double @fib(double %x) { +entry: + %cmptmp = fcmp ult double %x, 3.000000e+00 + %booltmp = uitofp i1 %cmptmp to double + %ifcond = fcmp ueq double %booltmp, 0.000000e+00 + br i1 %ifcond, label %else, label %ifcont +else: + %subtmp = fsub double %x, 1.000000e+00 + %calltmp = call double @fib(double %subtmp) + %subtmp5 = fsub double %x, 2.000000e+00 + %calltmp6 = call double @fib(double %subtmp5) + %addtmp = fadd double %calltmp, %calltmp6 + ret double %addtmp +ifcont: + ret double 1.000000e+00 +} +{% endhighlight %} + + +Here we see that the simplifycfg pass decided to clone the return instruction +into the end of the 'else' block. This allowed it to eliminate some branches +and the PHI node. + +Now that all symbol table references are updated to use stack variables, +we'll add the assignment operator. + + +* * * + +# New Assignment Operator # {#assignment} + +With our current framework, adding a new assignment operator is really +simple. We will parse it just like any other binary operator, but handle it +internally (instead of allowing the user to define it). The first step is to +set a precedence: + + +{% highlight python %} +def main(): + ... + # Install standard binary operators. + # 1 is lowest possible precedence. 40 is the highest. + g_binop_precedence['='] = 2 + g_binop_precedence['<'] = 10 + g_binop_precedence['+'] = 20 + g_binop_precedence['-'] = 20 +{% endhighlight %} + + +Now that the parser knows the precedence of the binary operator, it takes +care of all the parsing and AST generation. We just need to implement codegen +for the assignment operator. This looks like: + + +{% highlight python %} +class BinaryOperatorExpressionNode(ExpressionNode): + ... + def CodeGen(self): + # A special case for '=' because we don't want to emit the LHS as an + # expression. + if self.operator == '=': + # Assignment requires the LHS to be an identifier. + if not isinstance(self.left, VariableExpressionNode): + raise RuntimeError('Destination of "=" must be a variable.') +{% endhighlight %} + + +Unlike the rest of the binary operators, our assignment operator doesn't +follow the "emit LHS, emit RHS, do computation" model. As such, it is handled +as a special case before the other binary operators are handled. The other +strange thing is that it requires the LHS to be a variable. It is invalid to +have `(x+1) = expr` -- only things like `x = expr` are allowed. + + +{% highlight python %} + # Codegen the RHS. + value = self.right.CodeGen() + + # Look up the name. + variable = g_named_values[self.left.name] + + # Store the value and return it. + g_llvm_builder.store(value, variable) + + return value + ... +{% endhighlight %} + + +Once we have the variable, CodeGening the assignment is straightforward: +we emit the RHS of the assignment, create a store, and return the computed +value. Returning a value allows for chained assignments like `X = (Y = Z)`. + +Now that we have an assignment operator, we can mutate loop variables and +arguments. For example, we can now run code like this: + + +{% highlight python %} +# Function to print a double. +extern printd(x) + +# Define ':' for sequencing: as a low-precedence operator that ignores operands +# and just returns the RHS. +def binary : 1 (x y) y + +def test(x) + printd(x) : + x = 4 : + printd(x) + +test(123) +{% endhighlight %} + + +When run, this example prints "123" and then "4", showing that we did +actually mutate the value! Okay, we have now officially implemented our goal: +getting this to work requires SSA construction in the general case. However, +to be really useful, we want the ability to define our own local variables. +Let's add this next! + + +* * * + +# User-defined Local Variables # {#localvars} + +Adding var/in is just like any other other extensions we made to +Kaleidoscope: we extend the lexer, the parser, the AST and the code generator. +The first step for adding our new 'var/in' construct is to extend the lexer. +As before, this is pretty trivial, the code looks like this: + + +{% highlight python %} +... +class UnaryToken(object): pass +class VarToken(object): pass +... +def Tokenize(string): + ... + elif identifier == 'unary': + yield UnaryToken() + elif identifier == 'var': + yield VarToken() + else: + yield IdentifierToken(identifier) +{% endhighlight %} + + +The next step is to define the AST node that we will construct. For var/in, +it looks like this: + + +{% highlight python %} +# Expression class for var/in. +class VarExpressionNode(ExpressionNode): + + def __init__(self, variables, body): + self.variables = variables + self.body = body + + def CodeGen(self): + ... +{% endhighlight %} + + +var/in allows a list of names to be defined all at once, and each name can +optionally have an initializer value. As such, we capture this information in +the variables list. Also, var/in has a body, this body is allowed to access +the variables defined by the var/in. + +With this in place, we can define the parser pieces. The first thing we do +is add it as a primary expression: + + +{% highlight python %} + # primary ::= + # dentifierexpr | numberexpr | parenexpr | ifexpr | forexpr | varexpr + def ParsePrimary(self): + if isinstance(self.current, IdentifierToken): + return self.ParseIdentifierExpr() + elif isinstance(self.current, NumberToken): + return self.ParseNumberExpr() + elif isinstance(self.current, IfToken): + return self.ParseIfExpr() + elif isinstance(self.current, ForToken): + return self.ParseForExpr() + elif isinstance(self.current, VarToken): + return self.ParseVarExpr() + elif self.current == CharacterToken('('): + return self.ParseParenExpr() + else: + raise RuntimeError('Unknown token when expecting an expression.') +{% endhighlight %} + + +Next we define ParseVarExpr: + + +{% highlight python %} + # varexpr ::= 'var' (identifier ('=' expression)?)+ 'in' expression + def ParseVarExpr(self): + self.Next() # eat 'var'. + + variables = {} + + # At least one variable name is required. + if not isinstance(self.current, IdentifierToken): + raise RuntimeError('Expected identifier after "var".') +{% endhighlight %} + + +The first part of this code parses the list of identifier/expr pairs into the +local `variables` list. + + +{% highlight python %} + while True: + var_name = self.current.name + self.Next() # eat the identifier. + + # Read the optional initializer. + if self.current == CharacterToken('='): + self.Next() # eat '='. + variables[var_name] = self.ParseExpression() + else: + variables[var_name] = None + + # End of var list, exit loop. + if self.current != CharacterToken(','): + break + self.Next() # eat ','. + + if not isinstance(self.current, IdentifierToken): + raise RuntimeError('Expected identifier after "," in a var expression.') +{% endhighlight %} + + +Once all the variables are parsed, we then parse the body and create the +AST node: + + +{% highlight python %} + # At this point, we have to have 'in'. + if not isinstance(self.current, InToken): + raise RuntimeError('Expected "in" keyword after "var".') + self.Next() # eat 'in'. + + body = self.ParseExpression() + + return VarExpressionNode(variables, body) +{% endhighlight %} + + +Now that we can parse and represent the code, we need to support emission of +LLVM IR for it. This code starts out with: + + +{% highlight python %} +class VarExpressionNode(ExpressionNode): + ... + def CodeGen(self): + old_bindings = {} + function = g_llvm_builder.basic_block.function + + # Register all variables and emit their initializer. + for var_name, var_expression in self.variables.iteritems(): + # Emit the initializer before adding the variable to scope, this prevents + # the initializer from referencing the variable itself, and permits stuff + # like this: + # var a = 1 in + # var a = a in ... # refers to outer 'a'. + if var_expression is not None: + var_value = var_expression.CodeGen() + else: + var_value = Constant.real(Type.double(), 0) + + alloca = CreateEntryBlockAlloca(function, var_name) + g_llvm_builder.store(var_value, alloca) + + # Remember the old variable binding so that we can restore the binding + # when we unrecurse. + old_bindings[var_name] = g_named_values.get(var_name, None) + + # Remember this binding. + g_named_values[var_name] = alloca +{% endhighlight %} + + +Basically it loops over all the variables, installing them one at a time. +For each variable we put into the symbol table, we remember the previous value +that we replace in `old_bindings`. + +There are more comments here than code. The basic idea is that we emit the +initializer, create the alloca, then update the symbol table to point to it. +Once all the variables are installed in the symbol table, we evaluate the body +of the var/in expression: + + +{% highlight python %} + # Codegen the body, now that all vars are in scope. + body = self.body.CodeGen() +{% endhighlight %} + + +Finally, before returning, we restore the previous variable bindings: + + +{% highlight python %} + # Pop all our variables from scope. + for var_name in self.variables: + if old_bindings[var_name] is not None: + g_named_values[var_name] = old_bindings[var_name] + else: + del g_named_values[var_name] + + # Return the body computation. + return body +{% endhighlight %} + + +The end result of all of this is that we get properly scoped variable +definitions, and we even (trivially) allow mutation of them :). + +With this, we completed what we set out to do. Our nice iterative fib +example from the intro compiles and runs just fine. The mem2reg pass optimizes +all of our stack variables into SSA registers, inserting PHI nodes where needed, +and our front-end remains simple: no "iterated dominance frontier" computation +anywhere in sight. + +* * * + +# Full Code Listing # {#code} + +Here is the complete code listing for our running example, enhanced with mutable +variables and var/in support: + + +{% highlight python %} +#!/usr/bin/env python + +import re +from llvm.core import Module, Constant, Type, Function, Builder +from llvm.ee import ExecutionEngine, TargetData +from llvm.passes import FunctionPassManager + +from llvm.core import FCMP_ULT, FCMP_ONE +from llvm.passes import (PASS_PROMOTE_MEMORY_TO_REGISTER, + PASS_INSTRUCTION_COMBINING, + PASS_REASSOCIATE, + PASS_GVN, + PASS_CFG_SIMPLIFICATION) + +################################################################################ +## Globals +################################################################################ + +# The LLVM module, which holds all the IR code. +g_llvm_module = Module.new('my cool jit') + +# The LLVM instruction builder. Created whenever a new function is entered. +g_llvm_builder = None + +# A dictionary that keeps track of which values are defined in the current scope +# and what their LLVM representation is. +g_named_values = {} + +# The function optimization passes manager. +g_llvm_pass_manager = FunctionPassManager.new(g_llvm_module) + +# The LLVM execution engine. +g_llvm_executor = ExecutionEngine.new(g_llvm_module) + +# The binary operator precedence chart. +g_binop_precedence = {} + +# Creates an alloca instruction in the entry block of the function. This is used +# for mutable variables. +def CreateEntryBlockAlloca(function, var_name): + entry = function.get_entry_basic_block() + builder = Builder.new(entry) + builder.position_at_beginning(entry) + return builder.alloca(Type.double(), var_name) + +################################################################################ +## Lexer +################################################################################ + +# The lexer yields one of these types for each token. +class EOFToken(object): pass +class DefToken(object): pass +class ExternToken(object): pass +class IfToken(object): pass +class ThenToken(object): pass +class ElseToken(object): pass +class ForToken(object): pass +class InToken(object): pass +class BinaryToken(object): pass +class UnaryToken(object): pass +class VarToken(object): pass + +class IdentifierToken(object): + def __init__(self, name): self.name = name + +class NumberToken(object): + def __init__(self, value): self.value = value + +class CharacterToken(object): + def __init__(self, char): self.char = char + def __eq__(self, other): + return isinstance(other, CharacterToken) and self.char == other.char + def __ne__(self, other): return not self == other + +# Regular expressions that tokens and comments of our language. +REGEX_NUMBER = re.compile('[0-9]+(?:\.[0-9]+)?') +REGEX_IDENTIFIER = re.compile('[a-zA-Z][a-zA-Z0-9]*') +REGEX_COMMENT = re.compile('#.*') + +def Tokenize(string): + while string: + # Skip whitespace. + if string[0].isspace(): + string = string[1:] + continue + + # Run regexes. + comment_match = REGEX_COMMENT.match(string) + number_match = REGEX_NUMBER.match(string) + identifier_match = REGEX_IDENTIFIER.match(string) + + # Check if any of the regexes matched and yield the appropriate result. + if comment_match: + comment = comment_match.group(0) + string = string[len(comment):] + elif number_match: + number = number_match.group(0) + yield NumberToken(float(number)) + string = string[len(number):] + elif identifier_match: + identifier = identifier_match.group(0) + # Check if we matched a keyword. + if identifier == 'def': + yield DefToken() + elif identifier == 'extern': + yield ExternToken() + elif identifier == 'if': + yield IfToken() + elif identifier == 'then': + yield ThenToken() + elif identifier == 'else': + yield ElseToken() + elif identifier == 'for': + yield ForToken() + elif identifier == 'in': + yield InToken() + elif identifier == 'binary': + yield BinaryToken() + elif identifier == 'unary': + yield UnaryToken() + elif identifier == 'var': + yield VarToken() + else: + yield IdentifierToken(identifier) + string = string[len(identifier):] + else: + # Yield the ASCII value of the unknown character. + yield CharacterToken(string[0]) + string = string[1:] + + yield EOFToken() + +################################################################################ +## Abstract Syntax Tree (aka Parse Tree) +################################################################################ + +# Base class for all expression nodes. +class ExpressionNode(object): + pass + +# Expression class for numeric literals like "1.0". +class NumberExpressionNode(ExpressionNode): + + def __init__(self, value): + self.value = value + + def CodeGen(self): + return Constant.real(Type.double(), self.value) + +# Expression class for referencing a variable, like "a". +class VariableExpressionNode(ExpressionNode): + + def __init__(self, name): + self.name = name + + def CodeGen(self): + if self.name in g_named_values: + return g_llvm_builder.load(g_named_values[self.name], self.name) + else: + raise RuntimeError('Unknown variable name: ' + self.name) + +# Expression class for a binary operator. +class BinaryOperatorExpressionNode(ExpressionNode): + + def __init__(self, operator, left, right): + self.operator = operator + self.left = left + self.right = right + + def CodeGen(self): + # A special case for '=' because we don't want to emit the LHS as an + # expression. + if self.operator == '=': + # Assignment requires the LHS to be an identifier. + if not isinstance(self.left, VariableExpressionNode): + raise RuntimeError('Destination of "=" must be a variable.') + + # Codegen the RHS. + value = self.right.CodeGen() + + # Look up the name. + variable = g_named_values[self.left.name] + + # Store the value and return it. + g_llvm_builder.store(value, variable) + + return value + + left = self.left.CodeGen() + right = self.right.CodeGen() + + if self.operator == '+': + return g_llvm_builder.fadd(left, right, 'addtmp') + elif self.operator == '-': + return g_llvm_builder.fsub(left, right, 'subtmp') + elif self.operator == '*': + return g_llvm_builder.fmul(left, right, 'multmp') + elif self.operator == '<': + result = g_llvm_builder.fcmp(FCMP_ULT, left, right, 'cmptmp') + # Convert bool 0 or 1 to double 0.0 or 1.0. + return g_llvm_builder.uitofp(result, Type.double(), 'booltmp') + else: + function = g_llvm_module.get_function_named('binary' + self.operator) + return g_llvm_builder.call(function, [left, right], 'binop') + +# Expression class for function calls. +class CallExpressionNode(ExpressionNode): + + def __init__(self, callee, args): + self.callee = callee + self.args = args + + def CodeGen(self): + # Look up the name in the global module table. + callee = g_llvm_module.get_function_named(self.callee) + + # Check for argument mismatch error. + if len(callee.args) != len(self.args): + raise RuntimeError('Incorrect number of arguments passed.') + + arg_values = [i.CodeGen() for i in self.args] + + return g_llvm_builder.call(callee, arg_values, 'calltmp') + +# Expression class for if/then/else. +class IfExpressionNode(ExpressionNode): + + def __init__(self, condition, then_branch, else_branch): + self.condition = condition + self.then_branch = then_branch + self.else_branch = else_branch + + def CodeGen(self): + condition = self.condition.CodeGen() + + # Convert condition to a bool by comparing equal to 0.0. + condition_bool = g_llvm_builder.fcmp( + FCMP_ONE, condition, Constant.real(Type.double(), 0), 'ifcond') + + function = g_llvm_builder.basic_block.function + + # Create blocks for the then and else cases. Insert the 'then' block at the + # end of the function. + then_block = function.append_basic_block('then') + else_block = function.append_basic_block('else') + merge_block = function.append_basic_block('ifcond') + + g_llvm_builder.cbranch(condition_bool, then_block, else_block) + + # Emit then value. + g_llvm_builder.position_at_end(then_block) + then_value = self.then_branch.CodeGen() + g_llvm_builder.branch(merge_block) + + # Codegen of 'Then' can change the current block; update then_block for the + # PHI node. + then_block = g_llvm_builder.basic_block + + # Emit else block. + g_llvm_builder.position_at_end(else_block) + else_value = self.else_branch.CodeGen() + g_llvm_builder.branch(merge_block) + + # Codegen of 'Else' can change the current block, update else_block for the + # PHI node. + else_block = g_llvm_builder.basic_block + + # Emit merge block. + g_llvm_builder.position_at_end(merge_block) + phi = g_llvm_builder.phi(Type.double(), 'iftmp') + phi.add_incoming(then_value, then_block) + phi.add_incoming(else_value, else_block) + + return phi + +# Expression class for for/in. +class ForExpressionNode(ExpressionNode): + + def __init__(self, loop_variable, start, end, step, body): + self.loop_variable = loop_variable + self.start = start + self.end = end + self.step = step + self.body = body + + def CodeGen(self): + # Output this as: + # var = alloca double + # ... + # start = startexpr + # store start -> var + # goto loop + # loop: + # ... + # bodyexpr + # ... + # loopend: + # step = stepexpr + # endcond = endexpr + # + # curvar = load var + # nextvar = curvar + step + # store nextvar -> var + # br endcond, loop, endloop + # outloop: + + function = g_llvm_builder.basic_block.function + + # Create an alloca for the variable in the entry block. + alloca = CreateEntryBlockAlloca(function, self.loop_variable) + + # Emit the start code first, without 'variable' in scope. + start_value = self.start.CodeGen() + + # Store the value into the alloca. + g_llvm_builder.store(start_value, alloca) + + # Make the new basic block for the loop, inserting after current block. + loop_block = function.append_basic_block('loop') + + # Insert an explicit fall through from the current block to the loop_block. + g_llvm_builder.branch(loop_block) + + # Start insertion in loop_block. + g_llvm_builder.position_at_end(loop_block) + + # Within the loop, the variable is defined equal to the alloca. If it + # shadows an existing variable, we have to restore it, so save it now. + old_value = g_named_values.get(self.loop_variable, None) + g_named_values[self.loop_variable] = alloca + + # Emit the body of the loop. This, like any other expr, can change the + # current BB. Note that we ignore the value computed by the body. + self.body.CodeGen() + + # Emit the step value. + if self.step: + step_value = self.step.CodeGen() + else: + # If not specified, use 1.0. + step_value = Constant.real(Type.double(), 1) + + # Compute the end condition. + end_condition = self.end.CodeGen() + + # Reload, increment, and restore the alloca. This handles the case where + # the body of the loop mutates the variable. + cur_value = g_llvm_builder.load(alloca, self.loop_variable) + next_value = g_llvm_builder.fadd(cur_value, step_value, 'nextvar') + g_llvm_builder.store(next_value, alloca) + + # Convert condition to a bool by comparing equal to 0.0. + end_condition_bool = g_llvm_builder.fcmp( + FCMP_ONE, end_condition, Constant.real(Type.double(), 0), 'loopcond') + + # Create the "after loop" block and insert it. + after_block = function.append_basic_block('afterloop') + + # Insert the conditional branch into the end of loop_block. + g_llvm_builder.cbranch(end_condition_bool, loop_block, after_block) + + # Any new code will be inserted in after_block. + g_llvm_builder.position_at_end(after_block) + + # Restore the unshadowed variable. + if old_value is not None: + g_named_values[self.loop_variable] = old_value + else: + del g_named_values[self.loop_variable] + + # for expr always returns 0.0. + return Constant.real(Type.double(), 0) + +# Expression class for a unary operator. +class UnaryExpressionNode(ExpressionNode): + + def __init__(self, operator, operand): + self.operator = operator + self.operand = operand + + def CodeGen(self): + operand = self.operand.CodeGen() + function = g_llvm_module.get_function_named('unary' + self.operator) + return g_llvm_builder.call(function, [operand], 'unop') + +# Expression class for var/in. +class VarExpressionNode(ExpressionNode): + + def __init__(self, variables, body): + self.variables = variables + self.body = body + + def CodeGen(self): + old_bindings = {} + function = g_llvm_builder.basic_block.function + + # Register all variables and emit their initializer. + for var_name, var_expression in self.variables.iteritems(): + # Emit the initializer before adding the variable to scope, this prevents + # the initializer from referencing the variable itself, and permits stuff + # like this: + # var a = 1 in + # var a = a in ... # refers to outer 'a'. + if var_expression is not None: + var_value = var_expression.CodeGen() + else: + var_value = Constant.real(Type.double(), 0) + + alloca = CreateEntryBlockAlloca(function, var_name) + g_llvm_builder.store(var_value, alloca) + + # Remember the old variable binding so that we can restore the binding + # when we unrecurse. + old_bindings[var_name] = g_named_values.get(var_name, None) + + # Remember this binding. + g_named_values[var_name] = alloca + + # Codegen the body, now that all vars are in scope. + body = self.body.CodeGen() + + # Pop all our variables from scope. + for var_name in self.variables: + if old_bindings[var_name] is not None: + g_named_values[var_name] = old_bindings[var_name] + else: + del g_named_values[var_name] + + # Return the body computation. + return body + +# This class represents the "prototype" for a function, which captures its name, +# and its argument names (thus implicitly the number of arguments the function +# takes), as well as if it is an operator. +class PrototypeNode(object): + + def __init__(self, name, args, is_operator=False, precedence=0): + self.name = name + self.args = args + self.is_operator = is_operator + self.precedence = precedence + + def IsBinaryOp(self): + return self.is_operator and len(self.args) == 2 + + def GetOperatorName(self): + assert self.is_operator + return self.name[-1] + + def CodeGen(self): + # Make the function type, eg. double(double,double). + funct_type = Type.function( + Type.double(), [Type.double()] * len(self.args), False) + + function = Function.new(g_llvm_module, funct_type, self.name) + + # If the name conflicted, there was already something with the same name. + # If it has a body, don't allow redefinition or reextern. + if function.name != self.name: + function.delete() + function = g_llvm_module.get_function_named(self.name) + + # If the function already has a body, reject this. + if not function.is_declaration: + raise RuntimeError('Redefinition of function.') + + # If the function took a different number of args, reject. + if len(function.args) != len(self.args): + raise RuntimeError('Redeclaration of a function with different number ' + 'of args.') + + # Set names for all arguments and add them to the variables symbol table. + for arg, arg_name in zip(function.args, self.args): + arg.name = arg_name + + return function + + # Create an alloca for each argument and register the argument in the symbol + # table so that references to it will succeed. + def CreateArgumentAllocas(self, function): + for arg_name, arg in zip(self.args, function.args): + alloca = CreateEntryBlockAlloca(function, arg_name) + g_llvm_builder.store(arg, alloca) + g_named_values[arg_name] = alloca + +# This class represents a function definition itself. +class FunctionNode(object): + + def __init__(self, prototype, body): + self.prototype = prototype + self.body = body + + def CodeGen(self): + # Clear scope. + g_named_values.clear() + + # Create a function object. + function = self.prototype.CodeGen() + + # If this is a binary operator, install its precedence. + if self.prototype.IsBinaryOp(): + operator = self.prototype.GetOperatorName() + g_binop_precedence[operator] = self.prototype.precedence + + # Create a new basic block to start insertion into. + block = function.append_basic_block('entry') + global g_llvm_builder + g_llvm_builder = Builder.new(block) + + # Add all arguments to the symbol table and create their allocas. + self.prototype.CreateArgumentAllocas(function) + + # Finish off the function. + try: + return_value = self.body.CodeGen() + g_llvm_builder.ret(return_value) + + # Validate the generated code, checking for consistency. + function.verify() + + # Optimize the function. + g_llvm_pass_manager.run(function) + except: + function.delete() + if self.prototype.IsBinaryOp(): + del g_binop_precedence[self.prototype.GetOperatorName()] + raise + + return function + + +################################################################################ +## Parser +################################################################################ + +class Parser(object): + + def __init__(self, tokens): + self.tokens = tokens + self.Next() + + # Provide a simple token buffer. Parser.current is the current token the + # parser is looking at. Parser.Next() reads another token from the lexer and + # updates Parser.current with its results. + def Next(self): + self.current = self.tokens.next() + + # Gets the precedence of the current token, or -1 if the token is not a binary + # operator. + def GetCurrentTokenPrecedence(self): + if isinstance(self.current, CharacterToken): + return g_binop_precedence.get(self.current.char, -1) + else: + return -1 + + # identifierexpr ::= identifier | identifier '(' expression* ')' + def ParseIdentifierExpr(self): + identifier_name = self.current.name + self.Next() # eat identifier. + + if self.current != CharacterToken('('): # Simple variable reference. + return VariableExpressionNode(identifier_name) + + # Call. + self.Next() # eat '('. + args = [] + if self.current != CharacterToken(')'): + while True: + args.append(self.ParseExpression()) + if self.current == CharacterToken(')'): + break + elif self.current != CharacterToken(','): + raise RuntimeError('Expected ")" or "," in argument list.') + self.Next() + + self.Next() # eat ')'. + return CallExpressionNode(identifier_name, args) + + # numberexpr ::= number + def ParseNumberExpr(self): + result = NumberExpressionNode(self.current.value) + self.Next() # consume the number. + return result + + # parenexpr ::= '(' expression ')' + def ParseParenExpr(self): + self.Next() # eat '('. + + contents = self.ParseExpression() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")".') + self.Next() # eat ')'. + + return contents + + # ifexpr ::= 'if' expression 'then' expression 'else' expression + def ParseIfExpr(self): + self.Next() # eat the if. + + # condition. + condition = self.ParseExpression() + + if not isinstance(self.current, ThenToken): + raise RuntimeError('Expected "then".') + self.Next() # eat the then. + + then_branch = self.ParseExpression() + + if not isinstance(self.current, ElseToken): + raise RuntimeError('Expected "else".') + self.Next() # eat the else. + + else_branch = self.ParseExpression() + + return IfExpressionNode(condition, then_branch, else_branch) + + # forexpr ::= 'for' identifier '=' expr ',' expr (',' expr)? 'in' expression + def ParseForExpr(self): + self.Next() # eat the for. + + if not isinstance(self.current, IdentifierToken): + raise RuntimeError('Expected identifier after for.') + + loop_variable = self.current.name + self.Next() # eat the identifier. + + if self.current != CharacterToken('='): + raise RuntimeError('Expected "=" after for variable.') + self.Next() # eat the '='. + + start = self.ParseExpression() + + if self.current != CharacterToken(','): + raise RuntimeError('Expected "," after for start value.') + self.Next() # eat the ','. + + end = self.ParseExpression() + + # The step value is optional. + if self.current == CharacterToken(','): + self.Next() # eat the ','. + step = self.ParseExpression() + else: + step = None + + if not isinstance(self.current, InToken): + raise RuntimeError('Expected "in" after for variable specification.') + self.Next() # eat 'in'. + + body = self.ParseExpression() + + return ForExpressionNode(loop_variable, start, end, step, body) + + # varexpr ::= 'var' (identifier ('=' expression)?)+ 'in' expression + def ParseVarExpr(self): + self.Next() # eat 'var'. + + variables = {} + + # At least one variable name is required. + if not isinstance(self.current, IdentifierToken): + raise RuntimeError('Expected identifier after "var".') + + while True: + var_name = self.current.name + self.Next() # eat the identifier. + + # Read the optional initializer. + if self.current == CharacterToken('='): + self.Next() # eat '='. + variables[var_name] = self.ParseExpression() + else: + variables[var_name] = None + + # End of var list, exit loop. + if self.current != CharacterToken(','): + break + self.Next() # eat ','. + + if not isinstance(self.current, IdentifierToken): + raise RuntimeError('Expected identifier after "," in a var expression.') + + # At this point, we have to have 'in'. + if not isinstance(self.current, InToken): + raise RuntimeError('Expected "in" keyword after "var".') + self.Next() # eat 'in'. + + body = self.ParseExpression() + + return VarExpressionNode(variables, body) + + # primary ::= + # dentifierexpr | numberexpr | parenexpr | ifexpr | forexpr | varexpr + def ParsePrimary(self): + if isinstance(self.current, IdentifierToken): + return self.ParseIdentifierExpr() + elif isinstance(self.current, NumberToken): + return self.ParseNumberExpr() + elif isinstance(self.current, IfToken): + return self.ParseIfExpr() + elif isinstance(self.current, ForToken): + return self.ParseForExpr() + elif isinstance(self.current, VarToken): + return self.ParseVarExpr() + elif self.current == CharacterToken('('): + return self.ParseParenExpr() + else: + raise RuntimeError('Unknown token when expecting an expression.') + + # unary ::= primary | unary_operator unary + def ParseUnary(self): + # If the current token is not an operator, it must be a primary expression. + if (not isinstance(self.current, CharacterToken) or + self.current in [CharacterToken('('), CharacterToken(',')]): + return self.ParsePrimary() + + # If this is a unary operator, read it. + operator = self.current.char + self.Next() # eat the operator. + return UnaryExpressionNode(operator, self.ParseUnary()) + + # binoprhs ::= (binary_operator unary)* + def ParseBinOpRHS(self, left, left_precedence): + # If this is a binary operator, find its precedence. + while True: + precedence = self.GetCurrentTokenPrecedence() + + # If this is a binary operator that binds at least as tightly as the + # current one, consume it; otherwise we are done. + if precedence < left_precedence: + return left + + binary_operator = self.current.char + self.Next() # eat the operator. + + # Parse the unary expression after the binary operator. + right = self.ParseUnary() + + # If binary_operator binds less tightly with right than the operator after + # right, let the pending operator take right as its left. + next_precedence = self.GetCurrentTokenPrecedence() + if precedence < next_precedence: + right = self.ParseBinOpRHS(right, precedence + 1) + + # Merge left/right. + left = BinaryOperatorExpressionNode(binary_operator, left, right) + + # expression ::= unary binoprhs + def ParseExpression(self): + left = self.ParseUnary() + return self.ParseBinOpRHS(left, 0) + + # prototype + # ::= id '(' id* ')' + # ::= binary LETTER number? (id, id) + # ::= unary LETTER (id) + def ParsePrototype(self): + precedence = None + if isinstance(self.current, IdentifierToken): + kind = 'normal' + function_name = self.current.name + self.Next() # eat function name. + elif isinstance(self.current, UnaryToken): + kind = 'unary' + self.Next() # eat 'unary'. + if not isinstance(self.current, CharacterToken): + raise RuntimeError('Expected an operator after "unary".') + function_name = 'unary' + self.current.char + self.Next() # eat the operator. + elif isinstance(self.current, BinaryToken): + kind = 'binary' + self.Next() # eat 'binary'. + if not isinstance(self.current, CharacterToken): + raise RuntimeError('Expected an operator after "binary".') + function_name = 'binary' + self.current.char + self.Next() # eat the operator. + if isinstance(self.current, NumberToken): + if not 1 <= self.current.value <= 100: + raise RuntimeError('Invalid precedence: must be in range [1, 100].') + precedence = self.current.value + self.Next() # eat the precedence. + else: + raise RuntimeError('Expected function name, "unary" or "binary" in ' + 'prototype.') + + if self.current != CharacterToken('('): + raise RuntimeError('Expected "(" in prototype.') + self.Next() # eat '('. + + arg_names = [] + while isinstance(self.current, IdentifierToken): + arg_names.append(self.current.name) + self.Next() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")" in prototype.') + + # Success. + self.Next() # eat ')'. + + if kind == 'unary' and len(arg_names) != 1: + raise RuntimeError('Invalid number of arguments for a unary operator.') + elif kind == 'binary' and len(arg_names) != 2: + raise RuntimeError('Invalid number of arguments for a binary operator.') + + return PrototypeNode(function_name, arg_names, kind != 'normal', precedence) + + # definition ::= 'def' prototype expression + def ParseDefinition(self): + self.Next() # eat def. + proto = self.ParsePrototype() + body = self.ParseExpression() + return FunctionNode(proto, body) + + # toplevelexpr ::= expression + def ParseTopLevelExpr(self): + proto = PrototypeNode('', []) + return FunctionNode(proto, self.ParseExpression()) + + # external ::= 'extern' prototype + def ParseExtern(self): + self.Next() # eat extern. + return self.ParsePrototype() + + # Top-Level parsing + def HandleDefinition(self): + self.Handle(self.ParseDefinition, 'Read a function definition:') + + def HandleExtern(self): + self.Handle(self.ParseExtern, 'Read an extern:') + + def HandleTopLevelExpression(self): + try: + function = self.ParseTopLevelExpr().CodeGen() + result = g_llvm_executor.run_function(function, []) + print 'Evaluated to:', result.as_real(Type.double()) + except Exception, e: + raise#print 'Error:', e + try: + self.Next() # Skip for error recovery. + except: + pass + + def Handle(self, function, message): + try: + print message, function().CodeGen() + except Exception, e: + raise#print 'Error:', e + try: + self.Next() # Skip for error recovery. + except: + pass + +################################################################################ +## Main driver code. +################################################################################ + +def main(): + # Set up the optimizer pipeline. Start with registering info about how the + # target lays out data structures. + g_llvm_pass_manager.add(g_llvm_executor.target_data) + # Promote allocas to registers. + g_llvm_pass_manager.add(PASS_PROMOTE_MEMORY_TO_REGISTER) + # Do simple "peephole" optimizations and bit-twiddling optzns. + g_llvm_pass_manager.add(PASS_INSTRUCTION_COMBINING) + # Reassociate expressions. + g_llvm_pass_manager.add(PASS_REASSOCIATE) + # Eliminate Common SubExpressions. + g_llvm_pass_manager.add(PASS_GVN) + # Simplify the control flow graph (deleting unreachable blocks, etc). + g_llvm_pass_manager.add(PASS_CFG_SIMPLIFICATION) + + g_llvm_pass_manager.initialize() + + # Install standard binary operators. + # 1 is lowest possible precedence. 40 is the highest. + g_binop_precedence['='] = 2 + g_binop_precedence['<'] = 10 + g_binop_precedence['+'] = 20 + g_binop_precedence['-'] = 20 + g_binop_precedence['*'] = 40 + + # Run the main "interpreter loop". + while True: + print 'ready<', + try: + raw = raw_input() + except KeyboardInterrupt: + break + + parser = Parser(Tokenize(raw)) + while True: + # top ::= definition | external | expression | EOF + if isinstance(parser.current, EOFToken): + break + if isinstance(parser.current, DefToken): + parser.HandleDefinition() + elif isinstance(parser.current, ExternToken): + parser.HandleExtern() + else: + parser.HandleTopLevelExpression() + + # Print out all of the generated code. + print '\n', g_llvm_module + +if __name__ == '__main__': + main() +{% endhighlight %} + +* * * + +**[Next: Conclusion and other useful LLVM tidbits](PythonLangImpl8.html)** + + diff --git a/docs/source/doc/kaleidoscope/PythonLangImpl8.md b/docs/source/doc/kaleidoscope/PythonLangImpl8.md new file mode 100644 index 0000000..def3ded --- /dev/null +++ b/docs/source/doc/kaleidoscope/PythonLangImpl8.md @@ -0,0 +1,275 @@ +--- +layout: page +title: "Kaleidoscope: Chapter 8" +--- + +# Conclusion and other useful LLVM tidbits + +Written by [Chris Lattner](mailto:sabre@nondot.org) + +**Chapter 8** + + +* This will become a table of contents (this text will be scraped). +{:toc} + +# Tutorial Conclusion # {#conclusion} + +Welcome to the the final chapter of the +[Implementing a language with LLVM](http://www.llvm.org/docs/tutorial/index.html) +tutorial. In the course of this tutorial, we have grown +our little Kaleidoscope language from being a useless toy, to being a +semi-interesting (but probably still useless) toy. :) + +It is interesting to see how far we've come, and how little code it has +taken. We built the entire lexer, parser, AST, code generator, and an +interactive run-loop (with a JIT!) by-hand in under 540 lines of +(non-comment/non-blank) code. + +Our little language supports a couple of interesting features: it supports +user defined binary and unary operators, it uses JIT compilation for immediate +evaluation, and it supports a few control flow constructs with SSA construction. + + +Part of the idea of this tutorial was to show you how easy and fun it can be +to define, build, and play with languages. Building a compiler need not be a +scary or mystical process! Now that you've seen some of the basics, I strongly +encourage you to take the code and hack on it. For example, try adding: + + + +* **global variables** -- While global variables have questional value in + modern software engineering, they are often useful when putting together quick + little hacks like the Kaleidoscope compiler itself. Fortunately, our current + setup makes it very easy to add global variables: just have value lookup check + to see if an unresolved variable is in the global variable symbol table before + rejecting it. To create a new global variable, make an instance of the LLVM + `GlobalVariable` class. + +* **typed variables** -- Kaleidoscope currently only supports variables of + type double. This gives the language a very nice elegance, because only + supporting one type means that you never have to specify types. Different + languages have different ways of handling this. The easiest way is to require + the user to specify types for every variable definition, and record the type + of the variable in the symbol table along with its Value\*. + +* **arrays, structs, vectors, etc** -- Once you add types, you can start + extending the type system in all sorts of interesting ways. Simple arrays are + very easy and are quite useful for many different applications. Adding them is + mostly an exercise in learning how the LLVM + [getelementptr](http://www.llvm.org/docs/LangRef.html#i_getelementptr) + instruction works: it is so nifty/unconventional, it + [has its own FAQ](http://www.llvm.org/docs/GetElementPtr.html)! If you + add support for recursive types (e.g. linked lists), make sure to read the + [section in the LLVM Programmer's Manual](http://www.llvm.org/docs/ProgrammersManual.html#TypeResolve) + that describes how to construct them. + +* **standard runtime** -- Our current language allows the user to access + arbitrary external functions, and we use it for things like "putchard". As you + extend the language to add higher-level constructs, often these constructs make + the most sense if they are lowered to calls into a language-supplied runtime. + For example, if you add hash tables to the language, it would probably make + sense to add the routines to a runtime, instead of inlining them all the way. + +* **memory management** -- Currently we can only access the stack in + Kaleidoscope. It would also be useful to be able to allocate heap memory, + either with calls to the standard libc malloc/free interface or with a garbage + collector. If you would like to use garbage collection, note that LLVM fully + supports + [Accurate Garbage Collection](http://www.llvm.org/docs/GarbageCollection.html) + including algorithms that move objects and need to + scan/update the stack. + +* **debugger support** -- LLVM supports generation of + [DWARF Debug info](http://www.llvm.org/docs/SourceLevelDebugging.html) + which is understood by common debuggers like GDB. Adding support for debug + info is fairly straightforward. The best way to understand it is to compile + some C/C++ code with "`llvm-gcc -g -O0`" and taking a look at + what it produces. + +* **exception handling support** - LLVM supports generation of + [zero cost exceptions](http://www.llvm.org/docs/ExceptionHandling.html) + which interoperate with code compiled in other languages. You could also + generate code by implicitly making every function return an error value and + checking it. You could also make explicit use of setjmp/longjmp. There are + many different ways to go here. + +* **object orientation, generics, database access, complex numbers, + geometric programming, ...** -- Really, there is + no end of crazy features that you can add to the language. + +* **unusual domains** -- We've been talking about applying LLVM to a domain + that many people are interested in: building a compiler for a specific language. + However, there are many other domains that can use compiler technology that are + not typically considered. For example, LLVM has been used to implement OpenGL + graphics acceleration, translate C++ code to ActionScript, and many other + cute and clever things. Maybe you will be the first to JIT compile a regular + expression interpreter into native code with LLVM? + + +Have fun - try doing something crazy and unusual. Building a language like +everyone else always has, is much less fun than trying something a little crazy +or off the wall and seeing how it turns out. If you get stuck or want to talk +about it, feel free to email the +[llvmdev mailing list](http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev): +it has lots of people who are interested in languages and are often +willing to help out. + + +Before we end this tutorial, I want to talk about some "tips and tricks" for +generating LLVM IR. These are some of the more subtle things that may not be +obvious, but are very useful if you want to take advantage of LLVM's +capabilities. + +* * * + +# Properties of the LLVM IR # {#llvmirproperties} + +We have a couple common questions about code in the LLVM IR form - let's just +get these out of the way right now, shall we? + +## Target Independence ## {#targetindep} + +Kaleidoscope is an example of a "portable language": any program written in +Kaleidoscope will work the same way on any target that it runs on. Many other +languages have this property, e.g. LISP, Java, Haskell, Javascript, Python, etc. +(note that while these languages are portable, not all their libraries are). + +One nice aspect of LLVM is that it is often capable of preserving target +independence in the IR: you can take the LLVM IR for a Kaleidoscope-compiled +program and run it on any target that LLVM supports, even emitting C code and +compiling that on targets that LLVM doesn't support natively. You can trivially +tell that the Kaleidoscope compiler generates target-independent code because it +never queries for any target-specific information when generating code. + +The fact that LLVM provides a compact, target-independent, representation for +code gets a lot of people excited. Unfortunately, these people are usually +thinking about C or a language from the C family when they are asking questions +about language portability. I say "unfortunately", because there is really no +way to make (fully general) C code portable, other than shipping the source code +around (and of course, C source code is not actually portable in general +either - ever port a really old application from 32- to 64-bits?). + +The problem with C (again, in its full generality) is that it is heavily +laden with target specific assumptions. As one simple example, the preprocessor +often destructively removes target-independence from the code when it processes +the input text: + + +{% highlight c %} +#ifdef __i386__ + int X = 1; +#else + int X = 42; +#endif +{% endhighlight %} + + +While it is possible to engineer more and more complex solutions to problems +like this, it cannot be solved in full generality in a way that is better than +shipping the actual source code. + +That said, there are interesting subsets of C that can be made portable. If +you are willing to fix primitive types to a fixed size (say int = 32-bits, +and long = 64-bits), don't care about ABI compatibility with existing binaries, +and are willing to give up some other minor features, you can have portable +code. This can make sense for specialized domains such as an +in-kernel language. + + +## Safety Guarantees ## {#safety} + +Many of the languages above are also "safe" languages: it is impossible for +a program written in Java to corrupt its address space and crash the process +(assuming the JVM has no bugs). +Safety is an interesting property that requires a combination of language +design, runtime support, and often operating system support. + +It is certainly possible to implement a safe language in LLVM, but LLVM IR +does not itself guarantee safety. The LLVM IR allows unsafe pointer casts, +use after free bugs, buffer over-runs, and a variety of other problems. Safety +needs to be implemented as a layer on top of LLVM and, conveniently, several +groups have investigated this. Ask on the +[llvmdev mailing list](http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev) +if you are interested in more details. + + +## Language-Specific Optimizations ## {#langspecific} + +One thing about LLVM that turns off many people is that it does not solve all +the world's problems in one system (sorry 'world hunger', someone else will have +to solve you some other day). One specific complaint is that people perceive +LLVM as being incapable of performing high-level language-specific optimization: +LLVM "loses too much information". + +Unfortunately, this is really not the place to give you a full and unified +version of "Chris Lattner's theory of compiler design". Instead, I'll make a +few observations: + +First, you're right that LLVM does lose information. For example, as of this +writing, there is no way to distinguish in the LLVM IR whether an SSA-value came +from a C "int" or a C "long" on an ILP32 machine (other than debug info). Both +get compiled down to an 'i32' value and the information about what it came from +is lost. The more general issue here, is that the LLVM type system uses +"structural equivalence" instead of "name equivalence". Another place this +surprises people is if you have two types in a high-level language that have the +same structure (e.g. two different structs that have a single int field): these +types will compile down into a single LLVM type and it will be impossible to +tell what it came from. + +Second, while LLVM does lose information, LLVM is not a fixed target: we +continue to enhance and improve it in many different ways. In addition to +adding new features (LLVM did not always support exceptions or debug info), we +also extend the IR to capture important information for optimization (e.g. +whether an argument is sign or zero extended, information about pointers +aliasing, etc). Many of the enhancements are user-driven: people want LLVM to +include some specific feature, so they go ahead and extend it. + +Third, it is *possible and easy* to add language-specific +optimizations, and you have a number of choices in how to do it. As one trivial +example, it is easy to add language-specific optimization passes that +"know" things about code compiled for a language. In the case of the C family, +there is an optimization pass that "knows" about the standard C library +functions. If you call "exit(0)" in main(), it knows that it is safe to +optimize that into "return 0;" because C specifies what the 'exit' +function does. + +In addition to simple library knowledge, it is possible to embed a variety of +other language-specific information into the LLVM IR. If you have a specific +need and run into a wall, please bring the topic up on the llvmdev list. At the +very worst, you can always treat LLVM as if it were a "dumb code generator" and +implement the high-level optimizations you desire in your front-end, on the +language-specific AST. + +* * * + +# Tips and Tricks # {#tipsandtricks} + +There is a variety of useful tips and tricks that you come to know after +working on/with LLVM that aren't obvious at first glance. Instead of letting +everyone rediscover them, this section talks about some of these issues. + +## Implementing portable offsetof/sizeof ## {#offsetofsizeof} + +One interesting thing that comes up, if you are trying to keep the code +generated by your compiler "target independent", is that you often need to know +the size of some LLVM type or the offset of some field in an llvm structure. +For example, you might need to pass the size of a type into a function that +allocates memory. + +Unfortunately, this can vary widely across targets: for example the width of +a pointer is trivially target-specific. However, there is a +[clever way to use the getelementptr instruction](http://nondot.org/sabre/LLVMNotes/SizeOf-OffsetOf-VariableSizedStructs.txt) +that allows you to compute this in a portable way. + +## Garbage Collected Stack Frames ## {#gcstack} + +Some languages want to explicitly manage their stack frames, often so that +they are garbage collected or to allow easy implementation of closures. There +are often better ways to implement these features than explicit stack frames, +but [LLVM does support them](http://nondot.org/sabre/LLVMNotes/ExplicitlyManagedStackFrames.txt), +if you want. It requires your front-end to convert the code into +[Continuation Passing Style](http://en.wikipedia.org/wiki/Continuation-passing_style) +and the use of tail calls (which LLVM also supports). + + diff --git a/docs/source/doc/llvm-py_package.md b/docs/source/doc/llvm-py_package.md new file mode 100644 index 0000000..d314b6a --- /dev/null +++ b/docs/source/doc/llvm-py_package.md @@ -0,0 +1,92 @@ +--- +layout: page +title: The llvm-py Package +--- + +The llvm-py is a Python package, consisting of 6 modules, that wrap +over enough LLVM APIs to allow the implementation of your own +compiler/VM backend in pure Python. If you're come this far, you +probably know why this is a good idea. + +Out of the 6 modules, one is an "extension" module (i.e., it is +written in C), and another one is a small private utility module, which +leaves 4 public modules. These are: + +- *llvm* -- top-level package, common classes (like exceptions) +- *llvm.core* -- IR-related APIs +- *llvm.ee* -- execution engine related APIs +- *llvm.passes* -- pass manager and passes related APIs + +The modules contain only classes and (integer) constants. Mostly simple +Python constructs are used (deliberately) -- +[property()](http://docs.python.org/lib/built-in-funcs.html) and +[property decorators](http://wiki.python.org/moin/PythonDecoratorLibrary) are probably the most exotic animals around. All classes are +"new style" classes. The APIs are designed to be navigable (and +guessable!) once you know a few conventions. These conventions are +highlighted in the sections below. + +Here is a quick overview of the contents of each package: + + +## llvm + +- LLVMException -- exception class (currently the only one) + +## llvm.core +- [Module](llvm.core.Module.html) -- represents an LLVM Module +- [Type](types.html) -- represents an LLVM Type +- [Value](values.html) -- represents an LLVM Value, including: + globals, constants, variables, arguments, functions, instructions, etc.. +- [BasicBlock](llvm.core.BasicBlock.html) -- another derived of Value, + represents an LLVM basic block +- [Builder](llvm.core.Builder.html) -- used for creating instructions, + wraps LLVM IRBuilder helper + class +- constants *TYPE_\** that represents various types +- constants *CC_\** that represent calling conventions +- constants *ICMP_\** and *FCMP_\** that represent integer and real + comparison predicates (like less than, greater than etc.) +- constants *LINKAGE_\** that represent linkage of symbols (external, + internal etc.) +- constants *VISIBILITY_\** that represents visibility of symbols + (default, hidden, protected) +- constants *ATTR_\** that represent function parameter attributes + +## llvm.ee +- [ExecutionEngine](llvm.ee.ExecutionEngine.html) + -- represents an execution engine (which can be an + either an interpreter or a JIT) +- [TargetData](llvm.ee.TargetData.html) + -- represents the ABI of the target platform (details like + sizes and alignment of primitive types, endinanness etc) + +## llvm.passes +- [PassManager](llvm.passes.PassManager.html) + -- represents an LLVM pass manager +- [FunctionPassManager](llvm.passes.FunctionPassManager.html) + -- represents an LLVM function pass manager +- constants *PASS_\** that represent various passes + +## A note on the importing of these modules +Pythonically, modules are imported with the statement `import +llvm.core`. However, you might find it more convenient to import +llvm-py modules thus: + +{% highlight python %} +from llvm import * +from llvm.core import * +from llvm.ee import * +from llvm.passes import * +{% endhighlight %} + +This avoids quite some typing. Both conventions work, however. + +> **Tip** +> +> +> Python-style documentation strings (`__doc__`) are present in +> llvm-py. You can use the `help()` of the interactive Python +> interpreter or the `object?` of [IPython](http://ipython.scipy.org/moin/) +> to get online help. (Note: not complete yet!) + + diff --git a/docs/source/doc/llvm.core.Argument.md b/docs/source/doc/llvm.core.Argument.md new file mode 100644 index 0000000..d9e8890 --- /dev/null +++ b/docs/source/doc/llvm.core.Argument.md @@ -0,0 +1,57 @@ +--- +layout: page +title: Argument (llvm.core) +--- + +The `args` property of `llvm.core.Function` objects yields +`llvm.core.Argument` objects. This allows for setting attributes for +functions arguments. `Argument` objects cannot be constructed from user +code, the only way to get a reference to these are from `Function` +objects. + +The method `add_attribute` and `remove_attribute` can be used to add or +remove the following attributes: + +Value| Equivalent LLVM Assembly Keyword | +-----|----------------------------------| +`ATTR_ZEXT`| `zeroext` | +`ATTR_SEXT`| `signext` | +`ATTR_IN_REG`| `inreg` | +`ATTR_BY_VAL`| `byval` | +`ATTR_STRUCT_RET`| `sret` | +`ATTR_NO_ALIAS`| `noalias` | +`ATTR_NO_CAPTURE`| `nocapture` | +`ATTR_NEST`| `nest` | + +These method work exactly like the +[corresponding methods](functions.html#fnattr) +of the `Function` class above. Refer +[LLVM docs](http://www.llvm.org/docs/LangRef.html#paramattrs) +for information on what each attribute means. + +The alignment of any argument can be set via the `alignment` +property, to any power of 2. + +# llvm.core.Argument + +## Base Class + +- [llvm.core.Value](llvm.core.Value.html) + +## Properties + +### `alignment` + +The alignment of the argument. Must be a power of 2. + +## Methods + +### `add_attribute(attr)` + +Add an attribute `attr` to the argument, from the set listed above. + +### `remove_attribute(attr)` + +Remove the attribute `attr` of the argument. + + diff --git a/docs/source/doc/llvm.core.ArrayType.md b/docs/source/doc/llvm.core.ArrayType.md new file mode 100644 index 0000000..4aec7bd --- /dev/null +++ b/docs/source/doc/llvm.core.ArrayType.md @@ -0,0 +1,26 @@ +--- +layout: page +title: ArrayType (llvm.core) +--- + + +# llvm.core.ArrayType + +## Base Class + +- [llvm.core.Type](llvm.core.Type.html) + +## Properties + + +### `element` +\[read-only\] + +A `Type` object representing the type of the element of the array. + + +### `count` +\[read-only\] + +The number of elements in the array. + diff --git a/docs/source/doc/llvm.core.BasicBlock.md b/docs/source/doc/llvm.core.BasicBlock.md new file mode 100644 index 0000000..873634c --- /dev/null +++ b/docs/source/doc/llvm.core.BasicBlock.md @@ -0,0 +1,40 @@ +--- +layout: page +title: BasicBlock (llvm.core) +--- + +A basicblock is a list of instructions. +A wellformed basicblock should end with a terminator. +`Function.verify()` will verify that. +A terminator is either a branch instruction or return instruction. +It is not possible to have instructions after a branch or return instruction. + +# llvm.core.BasicBlock + +## Base Class + +- [llvm.core.Value][] + +## Methods + +### `delete(self)` + +Delete this basicblock from the function (`self.function`). + +### `insert_before(self, name)` + +TODO + +## Proporties + +### `function` + +The parent function of this basicblock. + +### `instructions` + +A list of instructions in this basicblock. + + +[llvm.core.Value]: llvm.core.Value.html +[llvm.core.Function]: llvm.core.Function.html diff --git a/docs/source/doc/llvm.core.Builder.md b/docs/source/doc/llvm.core.Builder.md new file mode 100644 index 0000000..75fffd4 --- /dev/null +++ b/docs/source/doc/llvm.core.Builder.md @@ -0,0 +1,326 @@ +--- +layout: page +title: Builder (llvm.core) +--- + +The `Builder` class corresponds to the +[IRBuilder](http://llvm.org/docs/doxygen/html/classllvm_1_1IRBuilder.html) +in C++ llvm. It provides an uniform API to +populating [BasicBlocks][llvm.core.BasicBlock]. +Most of the methods in `Builder` correspond to the instructions in the LLVM IR. +See [LLVM documentation](http://llvm.org/docs/LangRef.html) for detail. +These methods have the `name` argument for overiding the name +of the result variable. When it is an empty string (default value), +LLVM will set a numeric ID for the result variable. + +# llvm.core.Builder + +* This will become a table of contents (this text will be scraped). +{:toc} + +## Static Factor Method + +### `new(basic_block)` + +Create an instance of `Builder` at [BasicBlock][llvm.core.BasicBlock]. + +## Methods + +### `add(self, lhs, rhs, name='')` + +Insert an instruction that computes `lhs+rhs` for integer values only. + +### `alloca(self, ty, name='')` + +Insert an instruction that allocates stack memory for a value of type `ty`. + +### `alloca_array(self, ty, size, name='')` + +Insert an instruction that allocates stack memory for a `size` elements array +of type `ty`. + +### `and_(self, lhs, rhs, name='')` + +Insert an instruction that computes `lhs & rhs`. + +### `ashr(self, lhs, rhs, name='')` + +Insert an instruction that computes `lhs >> rhs` using arithmetic shift. + +### `bitcast(self, value, dest_ty, name='')` + +Insert an instruction that cast `value` to type `dest_ty`. + +### `branch(self, bblk)` + +Insert an instruction that branch to basicblock `bblk`. + +### `call(self, fn, args, name='')` + +Insert an instruction that call function `fn` with a iterable of +arguments `args`. + +### `cbranch(self, if_value, then_blk, else_blk)` + +Insert an instruction that conditionally branch base on +the predicate `if_value`. +If `if_value` is `True`, branch to `then_blk`; +Otherwise, branch to `else_blk`. + +### `extract_element(self, vec_val, idx_val, name='')` + +Insert an instruction that extracts an element from a value `vec_val` of +[llvm.core.VectorType][] at index `idx_val`. + +### `extract_value(self, retval, idx, name='')` + +Insert an instruction that extracts an element from an aggregate value `retval` +at index `idx`. + +### `fadd(self, lhs, rhs, name='')` + +Insert an instruction that computes `lhs + rhs` for floating-point values. + +### `fcmp(self, rpred, lhs, rhs, name='')` + +Insert an instruction that compares `lhs` and `rhs` using the comparision +operation defined by `rpred`. +See [here](comparision.html#fcmp) for a list of comparators. + +### `fdiv(self, lhs, rhs, name='')` + +Insert an instruction that computes `lhs / rhs` for floating-point values. + +### `fmul(self, lhs, rhs, name='')` + +Insert an instruction that computes `lhs * rhs` for floating-point values. + +### `fpext(self, value, dest_ty, name='')` + +Insert an instruction that extends `value` to a float type `dest_ty`. + +### `fptosi(self, value, dest_ty, name='')` + +Insert an instruction that converts a floating-point value `value` +to a signed integer type `dest_ty`. + +### `fptoui(self, value, dest_ty, name='')` + +Insert an instruction that converts a floating-point value `value` +to an unsigned integer type `dest_ty`. + +### `fptrunc(self, value, dest_ty, name='')` + +Insert an instruction that truncates a floating-point value `value` +to a float type `dest_ty`. + +### `free(self, ptr)` + +Insert an instruction that call performs heap deallocation on pointer `ptr`. + +### `frem(self, lhs, rhs, name='')` + +Insert an instruction that computes `lhs % rhs` for floating-point values. + +### `fsub(self, lhs, rhs, name='')` + +Insert an instruction that computes `lhs - rhs` for floating-point values. + +### `gep(self, ptr, indices, name='')` + +See [GEP](http://llvm.org/docs/LangRef.html#i_getelementptr). + +### `getresult(self, retval, idx, name='')` + +same as `extract_value`. + +### `icmp(self, ipred, lhs, rhs, name='')` + +Insert an instruction that compares `lhs` and `rhs` using the comparision +operation defined by `ipred`. +See [here](comparision.html#icmp) for a list of comparators. + +### `insert_element(self, vec_val, elt_val, idx_val, name='')` + +Insert an instruction that inserts a value `elt_val` into `vec_val` of +[llvm.core.VectorType][] at index `idx_val`. + +### `inttoptr(self, value, dest_ty, name='')` + +Insert an instruction that converts an integer `value` to pointer `dest_ty`. + +### `invoke(self, func, args, then_blk, catch_blk, name='')` + +See [invoke](http://llvm.org/docs/LangRef.html#i_invoke) + +### `load(self, ptr, name='')` + +Insert an instruction that loads a value at the memory pointed by `ptr`. + +### `lshr(self, lhs, rhs, name='')` + +Insert an instruction that computes `lhs >> rhs` using logical shift. + +### `malloc(self, ty, name='')` + +Insert an instruction that allocates heap memory of type `ty`. +The instruction returns a pointer that points to a value of type `ty`. + +### `malloc_array(self, ty, size, name='')` + +Similar to `malloc` but allocates an array of `size` elements. + +### `mul(self, lhs, rhs, name='')` + +Insert an instruction that computes `lhs * rhs` for integer types. + +### `neg(self, val, name='')` + +Insert an instruction that computes `0 - val`. + +### `not_(self, val, name='')` + +Insert an instruction that computes an one's complement of `val`. + +### `or_(self, lhs, rhs, name='')` + +Insert an instruction that computes `lhs | rhs`. + +### `phi(self, ty, name='')` + +Create a PHI node of type `ty`. + +### `position_at_beginning(self, bblk)` +Position the builder at the beginning of the given block. +Next instruction inserted will be first one in the block. + +### `position_at_end(self, bblk)` + +Position the builder at the end of the given block. +Next instruction inserted will be last one in the block. + +### `position_before(self, instr)` + +Position the builder before the given instruction. +The instruction can belong to a basic block other than the current one. + +### `ptrtoint(self, value, dest_ty, name='')` + +Insert an instruction that converts a pointer to an integer `value` of +type `dest_ty`. + +### `ret(self, value)` + +Insert an instruction that returns `value`. + +### `ret_many(self, values)` + +Insert an instruction that returns `values` which is an iterable of +[llvm.core.Value][]. + +### `ret_void(self)` + +Insert an instruction that returns nothing (void). + +### `sdiv(self, lhs, rhs, name='')` + +Insert an instruction that computes `lhs / rhs` for signed integers. + +### `select(self, cond, then_value, else_value, name='')` + +Insert an instruction that computes `cond ? then_value : else_value`. + +### `sext(self, value, dest_ty, name='')` + +Insert an instruction that sign extends an integer `value` to type `dest_ty`. + +### `shl(self, lhs, rhs, name='')` + +Insert an instruction that computes `lhs << rhs`. + +### `shuffle_vector(self, vecA, vecB, mask, name='')` + +Insert an instruction that performs a vector shuffle base on the two vectors -- +`vecA` and `vecB`, base on a bit mask `mask`. The mask must be a constant. + +See [LLVM document](http://llvm.org/docs/LangRef.html#i_shufflevector) +for detail. + +### `sitofp(self, value, dest_ty, name='')` + +Insert an instruction that converts a signed integer `value` to a floating-point +type `dest_ty`. + +### `srem(self, lhs, rhs, name='')` + +Insert an instruction that computes `lhs % rhs` for signed integers. + +### `store(self, value, ptr)` + +Insert an instruction that stores `value` into the memory pointed by `ptr`. + +### `sub(self, lhs, rhs, name='')` + +Insert an instruction that computes `lhs - rhs`. + +### `switch(self, value, else_blk, n=10)` + +Insert an instruction that transfer control flow depending on the `value`. +`else_blk` is the default case. `n` sets the number of additional cases. + +This method returns an instance of +[SwitchInstruction](llvm.core.Instruction.html#switchinstr) +for adding cases to the switch. + +### `trunc(self, value, dest_ty, name='')` + +Insert an instruction that truncates an integer `value` to the destination +integer type `dest_ty`. + +### `udiv(self, lhs, rhs, name='')` + +Insert an instruction that computes `lhs / rhs` for unsigned integers. + +### `uitofp(self, value, dest_ty, name='')` + +Insert an instruction that converts an unsigned integer `value` to a +floating-point type `dest_ty`. + +### `unreachable(self)` + +Insert an unreachabe instruction, which has no defined semantics. +See [LLVM document](http://llvm.org/docs/LangRef.html#i_unreachable) +for detail. + +### `urem(self, lhs, rhs, name='')` + +Insert an instruction that computes `lhs % rhs` for unsigned integers. + +### `vaarg(self, list_val, ty, name='')` + +This is used to access variable arguments given as `list_val` of type `ty`. +see [LLVM document](http://llvm.org/docs/LangRef.html#int_varargs) +about variable argument intrinsics. + +### `xor(self, lhs, rhs, name='')` + +Insert an instruction that computes `lhs xor rhs`. + +### `zext(self, value, dest_ty, name='')` + +Insert an instruction that zero extends `value` to type `dest_ty`. + +## Properties + +### `basic_block` + +The [BasicBlock][llvm.core.BasicBlock] where the builder is positioned. + +### `block` + +Deprecated. Same as `basic_block` + +[llvm.core.BasicBlock]: llvm.core.BasicBlock.html +[llvm.core.Value]: llvm.core.Value.html +[llvm.core.VectorType]: llvm.core.VectorType.html + diff --git a/docs/source/doc/llvm.core.Constant.md b/docs/source/doc/llvm.core.Constant.md new file mode 100644 index 0000000..23b6671 --- /dev/null +++ b/docs/source/doc/llvm.core.Constant.md @@ -0,0 +1,296 @@ +--- +layout: page +title: Constant (llvm.core) +--- + +`Constant`-s represents constants that appear within the code. The +values of such objects are known at creation time. Constants can be +created from Python constants. A constant expression is also a constant +-- given a `Constant` object, an operation (like addition, subtraction +etc) can be specified, to yield a new `Constant` object. Let's see some +examples: + +{% highlight python %} +#!/usr/bin/env python + +ti = Type.int() # a 32-bit int type + +k1 = Constant.int(ti, 42) # "int k1 = 42;" +k2 = k1.add( Constant.int( ti, 10 ) ) # "int k2 = k1 + 10;" + +tr = Type.float() + +r1 = Constant.real(tr, "3.141592") # create from a string +r2 = Constant.real(tr, 1.61803399) # create from a Python float +{% endhighlight %} + +# llvm.core.Constant + + +* This will become a table of contents (this text will be scraped). +{:toc} + + +## Static factory methods + +### `null(ty)` + +A null value (all zeros) of type `ty` + +### `all_ones(ty)` + +All 1's value of type `ty` + +### `undef(ty)` + +An undefined value of type `ty` + +### `int(ty, value)` + +Integer of type `ty`, with value `value` (a Python int or long) + +### `int_signextend(ty, value)` + +Integer of signed type `ty` (use for signed types) + +### `real(ty, value)` + +Floating point value of type `ty`, with value `value` (a Python float) + +### `stringz(value)` + +A null-terminated string. `value` is a Python string + +### `string(value)` + +As `string(ty)`, but not null terminated + +### `array(ty, consts)` + +Array of type `ty`, initialized with `consts` (an iterable yielding `Constant` +objects of the appropriate type) + +### `struct(ty, consts)` + +Struct (unpacked) of type `ty`, initialized with `consts` (an iterable yielding +`Constant` objects of the appropriate type) + +### `packed_struct(ty, consts)` + +As `struct(ty, consts)` but packed + +### `vector(consts)` + +Vector, initialized with `consts` (an iterable yielding `Constant` objects of +the appropriate type) + +### `sizeof(ty)` + +Constant value representing the sizeof the type `ty` + + +## Methods + +The following operations on constants are supported. For more details on +any operation, consult the +[Constant Expressions](http://www.llvm.org/docs/LangRef.html#constantexprs) +section of the LLVM Language Reference. + +### `k.neg()` + +negation, same as `0 - k` + +### `k.not_()` + +1's complement of `k`. Note trailing underscore. + +### `k.add(k2)` + +`k + k2`, where `k` and `k2` are integers. + + +### `k.fadd(k2)` + +`k + k2`, where `k` and `k2` are floating-point. + +### `k.sub(k2)` + +`k - k2`, where `k` and `k2` are integers. + +### `k.fsub(k2)` + +`k - k2`, where `k` and `k2` are floating-point. + +### `k.mul(k2)` + +`k * k2`, where `k` and `k2` are integers. + +### `k.fmul(k2)` + +`k * k2`, where `k` and `k2` are floating-point. + +### `k.udiv(k2)` + +Quotient of unsigned division of `k` with `k2` + +### `k.sdiv(k2)` + +Quotient of signed division of `k` with `k2` + +### `k.fdiv(k2)` + +Quotient of floating point division of `k` with `k2` + +### `k.urem(k2)` + +Reminder of unsigned division of `k` with `k2` + +### `k.srem(k2)` + +Reminder of signed division of `k` with `k2` + +### `k.frem(k2)` + +Reminder of floating point division of `k` with `k2` + +### `k.and_(k2)` + +Bitwise and of `k` and `k2`. Note trailing underscore. + +### `k.or_(k2)` + +Bitwise or of `k` and `k2`. Note trailing underscore. + +### `k.xor(k2)` + +Bitwise exclusive-or of `k` and `k2`. + +### `k.icmp(icmp, k2)` + +Compare `k` with `k2` using the predicate `icmp`. +See [here](comparision.html#icmp) for +list of predicates for integer operands. + +### `k.fcmp(fcmp, k2)` + +Compare `k` with `k2` using the predicate `fcmp`. +See [here](comparision.html#fcmp) for list +of predicates for real operands. + +### `k.shl(k2)` + +Shift `k` left by `k2` bits. + +### `k.lshr(k2)` + +Shift `k` logically right by `k2` bits (new bits are 0s). + +### `k.ashr(k2)` + +Shift `k` arithmetically right by `k2` bits (new bits are same as previous sign bit). + +### `k.gep(indices)` + +GEP, see [LLVM docs](http://www.llvm.org/docs/GetElementPtr.html). + +### `k.trunc(ty)` + +Truncate `k` to a type `ty` of lower bitwidth. + +### `k.sext(ty)` + +Sign extend `k` to a type `ty` of higher bitwidth, while extending the sign bit. + +### `k.zext(ty)` + +Sign extend `k` to a type `ty` of higher bitwidth, all new bits are 0s. + +### `k.fptrunc(ty)` + +Truncate floating point constant `k` to floating point type `ty` of lower size +than k's. + +### `k.fpext(ty)` + +Extend floating point constant `k` to floating point type `ty` of higher size +than k's. + +### `k.uitofp(ty)` + +Convert an unsigned integer constant `k` to floating point constant of +type `ty`. + +### `k.sitofp(ty)` + +Convert a signed integer constant `k` to floating point constant of type `ty`. + +### `k.fptoui(ty)` + +Convert a floating point constant `k` to an unsigned integer constant of type `ty`. + +### `k.fptosi(ty)` + +Convert a floating point constant `k` to a signed integer constant of type `ty`. + +### `k.ptrtoint(ty)` + +Convert a pointer constant `k` to an integer constant of type `ty`. + +### `k.inttoptr(ty)` + +Convert an integer constant `k` to a pointer constant of type `ty`. + +### `k.bitcast(ty)` + +Convert `k` to a (equal-width) constant of type `ty`. + +### `k.select(cond,k2,k3)` + +Replace value with `k2` if the 1-bit integer constant `cond` is 1, +else with `k3`. + +### `k.extract_element(idx)` + +Extract value at `idx` (integer constant) from a vector constant `k`. + +### `k.insert_element(k2,idx)` + +Insert value `k2` (scalar constant) at index `idx` (integer constant) of vector +constant `k`. + +### `k.shuffle_vector(k2,mask)` + +Shuffle vector constant `k` based on vector constants `k2` and `mask`. + +* * * + +# Other Constant Classes + +The following subclasses of `Constant` do not provide additional +methods, **they serve only to provide richer type information.** + + +Subclass | LLVM C++ Class | Remarks | +---------|----------------|---------| +`ConstantExpr` | `llvmConstantExpr` | A constant expression | +`ConstantAggregateZero`| `llvmConstantAggregateZero`| All-zero constant | +`ConstantInt`| `llvmConstantInt`| An integer constant | +`ConstantFP`| `llvmConstantFP`| A floating-point constant | +`ConstantArray`| `llvmConstantArray`| An array constant | +`ConstantStruct`| `llvmConstantStruct`| A structure constant | +`ConstantVector`| `llvmConstantVector`| A vector constant | +`ConstantPointerNull`| `llvmConstantPointerNull`| All-zero pointer constant | +`UndefValue`| `llvmUndefValue`| corresponds to `undef` of LLVM IR | + + +These types are helpful in `isinstance` checks, like so: + +{% highlight python %} +ti = Type.int(32) +k1 = Constant.int(ti, 42) # int32_t k1 = 42; +k2 = Constant.array(ti, [k1, k1]) # int32_t k2[] = { k1, k1 }; + +assert isinstance(k1, ConstantInt) +assert isinstance(k2, ConstantArray) +{% endhighlight %} + diff --git a/docs/source/doc/llvm.core.Function.md b/docs/source/doc/llvm.core.Function.md new file mode 100644 index 0000000..60e8db9 --- /dev/null +++ b/docs/source/doc/llvm.core.Function.md @@ -0,0 +1,129 @@ +--- +layout: page +title: Function (llvm.core) +--- + +# llvm.core.Function + +* This will become a table of contents (this text will be scraped). +{:toc} + + +## Base Class + +- [llvm.core.GlobalValue](llvm.core.GlobalValue.html) + +## Static Constructors + +### `new(module_obj, func_ty, name)` + +Create a function named `name` of type `func_ty` in the module +`module_obj` and return a `Function` object that represents it. + +### `get(module_obj, name)` + +Return a `Function` object to represent the function +named `name` in the module `module_obj` or raise `LLVMException` if +such a function does not exist. + +### `get_or_insert(module_obj, func_ty, name)` + +Similar to `get`, except that if the function does not exist it +is added first, as though with `new`. + +### `intrinsic(module_obj, intrinsic_id, types)` + +Create and return a `Function` object that refers to an intrinsic +function, as described [here](functions.html#intrinsic). + +## Properties + +### `calling_convention` + +The calling convention for the function, +as listed [here](functions.html#callconv). + +### `collector` + +A string holding the name of the garbage collection algorithm. +See [LLVM docs](http://www.llvm.org/docs/LangRef.html#gc). + +### `does_not_throw` + +Setting to True sets the `ATTR_NO_UNWIND` attribute, False +removes it. Shortcut to using `f.add_attribute(ATTR_NO_UNWIND)` +and `f.remove_attribute(ATTR_NO_UNWIND)`. + +### `args` + +\[read-only\] + +List of [llvm.core.Argument][] objects representing the formal +arguments of the function. + +### `basic_block_count` + +\[read-only\] + +Number of basic blocks belonging to this function. Same as +`len(f.basic_blocks)` but faster if you just want the count. + +### `entry_basic_block` + +\[read-only\] + +The [llvm.core.BasicBlock][] object representing the entry +basic block for this function, or `None` if there are no +basic blocks. + +### `basic_blocks` + +\[read-only\] + +List of [llvm.core.BasicBlock][] objects representing the +basic blocks belonging to this function. + +### `intrinsic_id` + +\[read-only\] + +Returns the ID of the intrinsic if this object represents an +intrinsic instruction. Otherwise 0. + +## Methods + +### `delete()` + +Deletes the function from it's module. Do not hold any +references to this object after calling `delete` on it. + +### `append_basic_block(name)` + +Add a new basic block named `name`, and return a corresponding +[llvm.core.BasicBlock][] object. Note that if this is not the +entry basic block, you'll have to add appropriate branch +instructions from other basic blocks yourself. + +### `add_attribute(attr)` + +Add an attribute `attr` to the function, from the set listed above. + +### `remove_attribute(attr)` + +Remove the attribute `attr` of the function. + +### `viewCFG()` + +Displays the control flow graph using the GraphViz tool. + +### `viewCFGOnly()` + +Displays the control flow graph using the GraphViz tool, but +omitting function bodies. + +### `verify()` + +Verifies the function. See [LLVM docs](http://llvm.org/docs/Passes.html#verify). + +[llvm.core.Argument]: llvm.core.Argument.html +[llvm.core.BasicBlock]: llvm.core.BasicBlock.html diff --git a/docs/source/doc/llvm.core.FunctionType.md b/docs/source/doc/llvm.core.FunctionType.md new file mode 100644 index 0000000..26cf40b --- /dev/null +++ b/docs/source/doc/llvm.core.FunctionType.md @@ -0,0 +1,53 @@ +--- +layout: page +title: FunctionType (llvm.core) +--- + +# llvm.core.FunctionType + +## Base Class + +- [llvm.core.Type](llvm.core.Type.html) + +## Properties + +### `return_type` + + +\[read-only\] + +A [Type][llvm.core.Type] object, representing the return type of the function. + +### `vararg` + + +\[read-only\] + +`True` if the function is variadic. + +### `args` + + +\[read-only\] + +Returns an iterable object that yields [Type][llvm.core.Type] objects that +represent, in order, the types of the arguments accepted by the +function. Used like this: + +{% highlight python %} +func_type = Type.function( Type.int(), [ Type.int(), Type.int() ] ) +for arg in func_type.args: + assert arg.kind == TYPE_INTEGER + assert arg == Type.int() +assert func_type.arg_count == len(func_type.args) +{% endhighlight %} + + +### `arg_count` + + +\[read-only\] + +The number of arguments. Same as `len(obj.args)`, but faster. + +[llvm.core.Type]: llvm.core.Type.html diff --git a/docs/source/doc/llvm.core.GlobalValue.md b/docs/source/doc/llvm.core.GlobalValue.md new file mode 100644 index 0000000..5d46a2e --- /dev/null +++ b/docs/source/doc/llvm.core.GlobalValue.md @@ -0,0 +1,99 @@ +--- +layout: page +title: GlobalValue (llvm.core) +--- + +The class `llvm.core.GlobalValue` represents module-scope aliases, variables +and functions. Global variables are represented by the sub-class +[llvm.core.GlobalVariable][] and functions by [llvm.core.Function][]. + +Global values have the read-write properties `linkage`, `section`, +`visibility` and `alignment`. Use one of the following constants (from +llvm.core) as values for `linkage` +(see [LLVM documentaion](http://www.llvm.org/docs/LangRef.html#linkage) for +details on each): + + +Value | Equivalent LLVM Assembly Keyword | +------|----------------------------------| +`LINKAGE_EXTERNAL` | `externally_visible` | +`LINKAGE_AVAILABLE_EXTERNALLY` | `available_externally` | +`LINKAGE_LINKONCE_ANY` | `linkonce` | +`LINKAGE_LINKONCE_ODR` | `linkonce_odr` | +`LINKAGE_WEAK_ANY` | `weak` | +`LINKAGE_WEAK_ODR` | `weak_odr` | +`LINKAGE_APPENDING` | `appending` | +`LINKAGE_INTERNAL` | `internal` | +`LINKAGE_PRIVATE` | `private` | +`LINKAGE_DLLIMPORT` | `dllimport` | +`LINKAGE_DLLEXPORT` | `dllexport` | +`LINKAGE_EXTERNAL_WEAK` | `extern_weak` | +`LINKAGE_GHOST` | deprecated -- do not use | +`LINKAGE_COMMON` | `common` | +`LINKAGE_LINKER_PRIVATE` | `linker_private` | + +
+ +The `section` property can be assigned strings (like ".rodata"), which +will be used if the target supports it. Visibility property can be set +to one of thse constants (from llvm.core, see also +[LLVM docs](http://www.llvm.org/docs/LangRef.html#visibility)): + + +Value | Equivalent LLVM Assembly Keyword | +------|----------------------------------| +`VISIBILITY_DEFAULT` | `default` | +`VISIBILITY_HIDDEN` | `hidden` | +`VISIBILITY_PROTECTED` | `protected` | + +
+ + +The `alignment` property can be 0 (default), or can be set to a power of 2. +The read-only property `is_declaration` can be used to check if the +global is a declaration or not. The module to which the global belongs +to can be retrieved using the `module` property (read-only). + +# llvm.core.GlobalValue + + +* This will become a table of contents (this text will be scraped). +{:toc} + + +## Base Class + +- [llvm.core.Constant](llvm.core.Constant.html) + +## Properties + +### `linkage` + +The linkage type, takes one of the constants listed above (LINKAGE_\*). + +### `section` + +A string like ".rodata", indicating the section into which the +global is placed into. + +### `visibility` + +The visibility type, takes one of the constants listed above (VISIBILITY_\*). + +### `alignment` + +A power-of-2 integer indicating the boundary to align to. + +### `is_declaration` +\[read-only\] + +`True` if the global is a declaration, `False` otherwise. + +### `module` +\[read-only\] + + The module object to which this global belongs to. + +[llvm.core.GlobalVariable]: llvm.core.GlobalVariable.html +[llvm.core.Function]: llvm.core.Function.html + diff --git a/docs/source/doc/llvm.core.GlobalVariable.md b/docs/source/doc/llvm.core.GlobalVariable.md new file mode 100644 index 0000000..05792a0 --- /dev/null +++ b/docs/source/doc/llvm.core.GlobalVariable.md @@ -0,0 +1,94 @@ +--- +layout: page +title: GlobalVariable (llvm.core) +--- + +Global variables (`llvm.core.GlobalVariable`) are subclasses of +[llvm.core.GlobalValue][] and represent module-level variables. These can +have optional initializers and can be marked as constants. Global +variables can be created either by using the `add_global_variable` +method of the [Module][llvm.core.Module] class, or by using the static method +`GlobalVariable.new`. + +{% highlight python %} +# create a global variable using add_global_variable method +gv1 = module_obj.add_global_variable(Type.int(), "gv1") + +# or equivalently, using a static constructor method +gv2 = GlobalVariable.new(module_obj, Type.int(), "gv2") +{% endhighlight %} + +Existing global variables of a module can be accessed by name using +`module_obj.get_global_variable_named(name)` or `GlobalVariable.get`. +All existing global variables can be enumerated via iterating over the +property `module_obj.global_variables`. + +{% highlight python %} +# retrieve a reference to the global variable gv1, +# using the get_global_variable_named method +gv1 = module_obj.get_global_variable_named("gv1") + +# or equivalently, using the static `get` method: +gv2 = GlobalVariable.get(module_obj, "gv2") + +# list all global variables in a module +for gv in module_obj.global_variables: + print gv.name, "of type", gv.type +{% endhighlight %} + +The initializer for a global variable can be set by assigning to the +`initializer` property of the object. The `is_global_constant` property +can be used to indicate that the variable is a global constant. + +Global variables can be delete using the `delete` method. Do not use the +object after calling `delete` on it. + +{% highlight python %} +# add an initializer 10 (32-bit integer) +gv.initializer = Constant.int( Type.int(), 10 ) + +# delete the global +gv.delete() +# DO NOT dereference `gv' beyond this point! +gv = None +{% endhighlight %} + +# llvm.core.GlobalVariable +## Base Class + +- [llvm.core.GlobalValue](llvm.core.GlobalValue.html) + +## Static Constructors + +### `new(module_obj, ty, name)` + +Create a global variable named `name` of type `ty` in the module +`module_obj` and return a `GlobalVariable` object that represents it. + +### `get(module_obj, name)` + +Return a `GlobalVariable` object to represent the global variable +named `name` in the module `module_obj` or raise `LLVMException` if +such a variable does not exist. + +## Properties + +### `initializer` + +The intializer of the variable. Set to [llvm.core.Constant][] (or +derived). Gets the initializer constant, or `None` if none exists. +`global_constant` +`True` if the variable is a global constant, `False` otherwise. + +## Methods + +### `delete()` +Deletes the global variable from it's module. +**Do not hold any references to this object after calling `delete` on it.** + + +[llvm.core.Module]: llvm.core.Module.html +[llvm.core.Constant]: llvm.core.Constant.html +[llvm.core.GlobalValue]: llvm.core.GlobalValue.html + + diff --git a/docs/source/doc/llvm.core.Instruction.md b/docs/source/doc/llvm.core.Instruction.md new file mode 100644 index 0000000..cef3041 --- /dev/null +++ b/docs/source/doc/llvm.core.Instruction.md @@ -0,0 +1,215 @@ +--- +layout: page +title: Instruction (llvm.core) +--- + +An `llvm.core.Instruction` object represents an LLVM instruction. This +class is the root of a small hierarchy: + + + Instruction + CallOrInvokeInstruction + PHINode + SwitchInstruction + CompareInstruction + + +Instructions are not created directly, but via a builder. The builder +both creates instructions and adds them to a basic block at the same +time. One way of getting instruction objects are from basic blocks. + +Being derived from [llvm.core.User][], the instruction +is-a user, i.e., an instruction in turn uses other values. The values +an instruction uses are its operands. These may be accessed using +`operands` property from the [llvm.core.User][] base. + +The name of the instruction (like `add`, `mul` etc) can be got +via the `opcode_name` property. The `basic_block` property gives +the basic block to which the instruction belongs to. Note that +llvm-py does not allow free-standing instruction objects (i.e., +all instructions are created contained within a basic block). + +Classes of instructions can be got via the properties +`is_terminator`, `is_binary_op`, `is_shift` etc. See below for +the full list. + + + +* This will become a table of contents (this text will be scraped). +{:toc} + + +# llvm.core.Instruction + +## Base Class + +- [llvm.core.User](llvm.core.User.html) + +## Properties + +### `basic_block` +\[read-only\] +The basic block to which this instruction belongs to. + +### `is_terminator` +\[read-only\] +True if the instruction is a terminator instruction. + +### `is_binary_op` +\[read-only\] +True if the instruction is a binary operator. + +### `is_shift` +\[read-only\] +True if the instruction is a shift instruction. + +### `is_cast` +\[read-only\] +True if the instruction is a cast instruction. + +### `is_logical_shift` +\[read-only\] +True if the instruction is a logical shift instruction. + +### `is_arithmetic_shift` +\[read-only\] +True if the instruction is an arithmetic shift instruction. + +### `is_associative` +\[read-only\] +True if the instruction is associative. + +### `is_commutative` +\[read-only\] +True if the instruction is commutative. + +### `is_volatile` +\[read-only\] +True if the instruction is a volatile load or store. + +### `opcode` +\[read-only\] +The numeric opcode value of the instruction. Do not rely +on the absolute value of this number, it may change with +LLVM version. + +### `opcode_name` +\[read-only\] +The name of the instruction, like `add`, `sub` etc. + +* * * + +# llvm.core.CallOrInvokeInstruction + +The `llvm.core.CallOrInvokeInstruction` is a subclass of +`llvm.core.Instruction`, and represents either a `call` or an +`invoke` instruction. + +## Base Class + +- `llvm.core.Instruction` + +## Properties + +`calling_convention` + Get or set the calling convention. See [here](functions.html#callconv) + for possible values. + +## Methods + +### `add_parameter_attribute(idx, attr)` + +Add an attribute `attr` to the `idx`-th argument. See +[here](llvm.core.Argument.html) for possible values of `attr`. + +### `remove_parameter_attribute(idx, attr)` + +Remove an attribute `attr` from the `idx`-th argument. See +[here](llvm.core.Argument.html) for possible values of `attr`. + +### `set_parameter_alignment(idx, align)` + +Set the alignment of the `idx`-th argument to `align`. +`align` should be a power of two. + +* * * + +# llvm.core.PHINode + +The `llvm.core.PHINode` is a subclass of +`llvm.core.Instruction`, and represents the `phi` instruction. When +created (using `Builder.phi`) the phi node contains no incoming +blocks (nor their corresponding values). To add an incoming arc to +the phi node, use the `add_incoming` method, which takes a source +block ([llvm.core.BasicBlock][] object) and a value (object of +[llvm.core.Value][] or of a class derived from it) that the phi node +will take on if control branches in from that block. + + +## Base Class + +- `llvm.core.Instruction` + +## Properties +`incoming_count` +\[read-only\] + The number of incoming arcs for this phi node. + +## Methods + +### `add_incoming(value, block)` + +Add an incoming arc, from the [llvm.core.BasicBlock][] object +`block`, with the corresponding value `value`. `value` should +be an object of [llvm.core.Value][] (or of a descendent class). + +### `get_incoming_value(idx)` + +Returns the `idx`-th incoming arc's value. + +### `get_incoming_block(idx)` + +Returns the `idx`-th incoming arc's block. + + +# llvm.core.SwitchInstruction # {#switchinstr} + +(TODO describe) + +## Base Class + +- `llvm.core.Instruction` + +## Methods + +### `add_case(const, block)` +Add another case to the switch statement. When the expression +being evaluated equals `const`, then control branches to +`block`. Here `const` must be of type +[llvm.core.ConstantInt][llvm.core.Constant]. + +* * * + +# llvm.core.CompareInstruction + +(TODO describe) + +## Base Class + +- `llvm.core.Instruction` + +## Properties + +###`predicate` +\[read-only\] + +The predicate of the compare instruction, one of the `ICMP_*` or +`FCMP_*` constants. + + +[llvm.core.User]: llvm.core.User.html +[llvm.core.BasicBlock]: llvm.core.BasicBlock.html +[llvm.core.Value]: llvm.core.Value.html +[llvm.core.Constant]: llvm.core.Constant.html + + diff --git a/docs/source/doc/llvm.core.IntegerType.md b/docs/source/doc/llvm.core.IntegerType.md new file mode 100644 index 0000000..da62f5c --- /dev/null +++ b/docs/source/doc/llvm.core.IntegerType.md @@ -0,0 +1,20 @@ +--- +layout: page +title: IntegerType (llvm.core) +--- + +# llvm.core.IntegerType + +## Base Class + +- [llvm.core.Type](llvm.core.Type.html) + +## Properties + + +### `width` +\[read-only\] + +The width of the integer type, in number of bits. + + diff --git a/docs/source/doc/llvm.core.Module.md b/docs/source/doc/llvm.core.Module.md new file mode 100644 index 0000000..80a4784 --- /dev/null +++ b/docs/source/doc/llvm.core.Module.md @@ -0,0 +1,219 @@ +--- +layout: page +title: Module (llvm.core) +--- + +Modules are top-level container objects. You need to create a module +object first, before you can add global variables, aliases or functions. +Modules are created using the static method `Module.new`: + +{% highlight python %} +#!/usr/bin/env python + +from llvm import * +from llvm.core import * + +# create a module +my_module = Module.new('my_module') +{% endhighlight %} + +The constructor of the Module class should _not_ be used to instantiate +a Module object. This is a common feature for all llvm-py classes. + +> **Convention** +> +> *All* llvm-py objects are instantiated using static methods of +> corresponding classes. Constructors _should not_ be used. +> +> The argument `my_module` is a module identifier (a plain string). A +> module can also be constructed via deserialization from a bit code file, +> using the static method `from_bitcode`. This method takes a file-like +> object as argument, i.e., it should have a `read()` method that returns +> the entire data in a single call, as is the case with the builtin file +> object. Here is an example: + +{% highlight python %} +# create a module from a bit code file +bcfile = file("test.bc") +my_module = Module.from_bitcode(bcfile) +{% endhighlight %} + +There is corresponding serialization method also, called `to_bitcode`: + +{% highlight python %} +# write out a bit code file from the module +bcfile = file("test.bc", "w") +my_module.to_bitcode(bcfile) +{% endhighlight %} + +Modules can also be constructed from LLVM assembly files (`.ll` files). +The static method `from_assembly` can be used for this. Similar to the +`from_bitcode` method, this one also takes a file-like object as +argument: + +{% highlight python %} +# create a module from an assembly file +llfile = file("test.ll") +my_module = Module.from_assembly(llfile) +{% endhighlight %} + +Modules can be converted into their assembly representation by +stringifying them (see below). + +* * * + + +# llvm.core.Module + +* This will become a table of contents (this text will be scraped). +{:toc} + +## Static Constructors + +### `new(module_id)` + +Create a new `Module` instance with given `module_id`. The `module_id` +should be a string. + +### `from_bitcode(fileobj)` + +Create a new `Module` instance by deserializing the bitcode file +represented by the file-like object `fileobj`. + +### `from_assembly(fileobj)` + +Create a new `Module` instance by parsing the LLVM assembly file +represented by the file-like object `fileobj`. + +## Properties + +### `data_layout` + +A string representing the ABI of the platform. + +### `target` + +A string like `i386-pc-linux-gnu` or `i386-pc-solaris2.8`. + +### `pointer_size` +\[read-only\] + +The size in bits of pointers, of the target platform. A value of +zero represents `llvm::Module::AnyPointerSize`. + +### `global_variables` +\[read-only\] + +An iterable that yields [GlobalVariable][llvm.core.GlobalVariable] objects, +that represent the global variables of the module. + +### `functions` +\[read-only\] + +An iterable that yields [Function][llvm.core.Function] objects, +that represent functions in the module. + +### `id` + +A string that represents the module identifier (name). + +## Methods + +### `get_type_named(name)` + +Return a [StructType][llvm.core.StructType] object for the given name. + +The definition of this method was changed to work with LLVM 3.0+, in which +the type system was rewritten. +See [LLVM Blog](http://blog.llvm.org/2011/11/llvm-30-type-system-rewrite.html). + +{% comment %} +++++++++REMOVED+++++++++++ +### `add_type_name(name, ty)` + +Add an alias (typedef) for the type `ty` with the name `name`. + +### `delete_type_name(name)` + +Delete an alias with the name `name`. +++++++++END-REMOVED+++++++++++ +{% endcomment %} + +### `add_global_variable(ty, name)` + +Add a global variable of the type `ty` with the name `name`. +Returns a [GlobalVariable][llvm.core.GlobalVariable] object. + +### `get_global_variable_named(name)` + +Get a [GlobalVariable][llvm.core.GlobalVariable] object corresponding to +the global variable with the name `name`. +Raises `LLVMException` if such a variable does not exist. + +### `add_library(name)` + +Add a dependent library to the Module. This only adds a name to a list of +dependent library. **No linking is performed**. + +### `add_function(ty, name)` + +Add a function named `name` with the function type `ty`. `ty` must +of an object of type [FunctionType][llvm.core.FunctionType]. + +### `get_function_named(name)` + +Get a [Function][llvm.core.Function] object corresponding to the function with +the name `name`. Raises `LLVMException` if such a function does not exist. + +### `get_or_insert_function(ty, name)` + +Like `get_function_named`, but adds the function first, if not +present (like `add_function`). + +### `verify()` + +Verify the correctness of the module. Raises `LLVMException` on +errors. + +### `to_bitcode(fileobj)` + +Write the bitcode representation of the module to the file-like +object `fileobj`. + +### `link_in(other)` + +Link in another module `other` into this module. Global variables, +functions etc. are matched and resolved. The `other` module is no +longer valid and should not be used after this operation. This API +might be replaced with a full-fledged Linker class in the future. + +## Special Methods + + +### `__str__` + +`Module` objects can be stringified into it's LLVM assembly language +representation. + +### `__eq__` + +`Module` objects can be compared for equality. Internally, this +converts both arguments into their LLVM assembly representations and +compares the resultant strings. + +> **Convention** +> +> *All* llvm-py objects (where it makes sense), when stringified, return +> the LLVM assembly representation. `print module_obj` for example, +> prints the LLVM assembly form of the entire module. +> +> Such objects, when compared for equality, internally compare these +> string representations. + +[llvm.core.Function]: llvm.core.Function.html +[llvm.core.FunctionType]: llvm.core.FunctionType.html +[llvm.core.GlobalVariable]: llvm.core.GlobalVariable.html +[llvm.core.BasicBlock]: llvm.core.BasicBlock.html +[llvm.core.Type]: llvm.core.Type.html +[llvm.core.StructType]: llvm.core.StructType.html + diff --git a/docs/source/doc/llvm.core.PointerType.md b/docs/source/doc/llvm.core.PointerType.md new file mode 100644 index 0000000..7adfbe6 --- /dev/null +++ b/docs/source/doc/llvm.core.PointerType.md @@ -0,0 +1,26 @@ +--- +layout: page +title: PointerType (llvm.core) +--- + + +# llvm.core.PointerType + +## Base Class + +- [llvm.core.Type](llvm.core.Type.html) + +## Properties + + +### `address_space` +\[read-only\] + +The address space of the pointer. + + +### `pointee` +\[read-only\] + +A [Type](llvm.core.Type.html) object representing the type of the value pointed to. + diff --git a/docs/source/doc/llvm.core.StructType.md b/docs/source/doc/llvm.core.StructType.md new file mode 100644 index 0000000..5156814 --- /dev/null +++ b/docs/source/doc/llvm.core.StructType.md @@ -0,0 +1,70 @@ +--- +layout: page +title: StructType (llvm.core) +--- + +# llvm.core.StructType + +## Base Class + +- [llvm.core.Type](llvm.core.Type.html) + +## Methods + +### `set_body(self, elems, packed=False)` + +Define the body for opaque identified structure. + +`elems` is an iterable of [llvm.core.Type](llvm.core.Type.html) +If `packed` is `True`, creates a packed structure. + +## Properties + +### `is_identified` +\[read-only\] + +`True` if this is an identified structure. + +### `is_literal` +\[read-only\] + +`True` if this is a literal structure. + +### `is_opaque` +\[read-only\] + +`True` if this is an opaque structure. +Only identified structure can be opaque. + +### `packed` +\[read-only\] + +`True` if the structure is packed (no padding between elements). + +### `name` + +Use in identified structure. +If set to empty, the identified structure is removed from the global context. + +### `elements` +\[read-only\] + +Returns an iterable object that yields [Type](llvm.core.Type.html) objects that +represent, in order, the types of the elements of the structure. +Used like this: + +{% highlight python %} +struct_type = Type.struct( [ Type.int(), Type.int() ] ) +for elem in struct_type.elements: + assert elem.kind == TYPE_INTEGER + assert elem == Type.int() +assert struct_type.element_count == len(struct_type.elements) +{% endhighlight %} + + +### `element_count` +\[read-only\] + +The number of elements. Same as `len(obj.elements)`, but faster. + + diff --git a/docs/source/doc/llvm.core.Type.md b/docs/source/doc/llvm.core.Type.md new file mode 100644 index 0000000..2616b7e --- /dev/null +++ b/docs/source/doc/llvm.core.Type.md @@ -0,0 +1,148 @@ +--- +layout: page +title: Type (llvm.core) +--- + +# llvm.core.Type + +* This will become a table of contents (this text will be scraped). +{:toc} + +## Static Constructors + +### `int(n)` + +Create an integer type of bit width `n`. + +### `float()` + +Create a 32-bit floating point type. + + +### `double()` + +Create a 64-bit floating point type. + + +### `x86_fp80()` + +Create a 80-bit 80x87-style floating point type. + + +### `fp128()` + +Create a 128-bit floating point type (112-bit mantissa). + + +### `ppc_fp128()` + +Create a 128-bit float (two 64-bits). + + +### `function(ret, params, vararg=False)` + +Create a function type, having the return type `ret` (must be a +`Type`), accepting the parameters `params`, where `params` is an +iterable, that yields `Type` objects representing the type of +each function argument in order. If `vararg` is `True`, function is +variadic. + + +### `struct(eltys, name='')` + +Create an unpacked structure. `eltys` is an iterable, that yields +`Type` objects representing the type of each element in order. + +If `name` is evaulates `True` (not empty), create +an *identified structure*; otherwise, create a *literal structure* +by default. + + +### `packed_struct(eltys, name='')` + +Like `struct(eltys)`, but creates a packed struct. + + +### `array(elty, count)` + +Creates an array type, holding `count` elements, each of type `elty` +(which should be a `Type`). + + +### `pointer(pty, addrspc=0)` + +Create a pointer to type `pty` (which should be a `Type`). `addrspc` +is an integer that represents the address space of the pointer (see +LLVM docs or ask on llvm-dev for more info). + + +### `void()` + +Creates a void type. Used for function return types. + + +### `label()` + +Creates a label type. + + +### `opaque(name)` + +Opaque [StructType](llvm.core.StructType.html), used for creating self-referencing types. + +## Properties + + +### `kind` +\[read-only\] + +A value (enum) representing the "type" of the object. It will be +one of the following constants defined in `llvm.core`: + +{% highlight python %} +# Warning: do not rely on actual numerical values! +TYPE_VOID = 0 +TYPE_FLOAT = 1 +TYPE_DOUBLE = 2 +TYPE_X86_FP80 = 3 +TYPE_FP128 = 4 +TYPE_PPC_FP128 = 5 +TYPE_LABEL = 6 +TYPE_INTEGER = 7 +TYPE_FUNCTION = 8 +TYPE_STRUCT = 9 +TYPE_ARRAY = 10 +TYPE_POINTER = 11 +TYPE_OPAQUE = 12 +TYPE_VECTOR = 13 +TYPE_METADATA = 14 +TYPE_UNION = 15 +{% endhighlight %} + +#### Example: +{% highlight python %} +assert Type.int().kind == TYPE_INTEGER +assert Type.void().kind == TYPE_VOID +{% endhighlight %} + +## Methods + +### `refine` + +Used for constructing self-referencing types. See the documentation +of [TypeHandle](llvm.core.TypeHandle.html) objects. + +## Special Methods + +### `__str__` + +`Type` objects can be stringified into it's LLVM assembly language +representation. + +### `__eq__` + +`Type` objects can be compared for equality. Internally, this +converts both arguments into their LLVM assembly representations and +compares the resultant strings. + + diff --git a/docs/source/doc/llvm.core.User.md b/docs/source/doc/llvm.core.User.md new file mode 100644 index 0000000..8a2353f --- /dev/null +++ b/docs/source/doc/llvm.core.User.md @@ -0,0 +1,34 @@ +--- +layout: page +title: User (llvm.core) +--- + +`User`-s are values that refer to other values. The values so refered +can be retrived by the properties of `User`. This is the reverse of +the `Value.uses`. Together these can be used to traverse the use-def +chains of the SSA. + +* * * + + +# llvm.core.User # {#user} +## Base Class +- [llvm.core.Value][] + +## Properties + +### `operands` +\[read-only\] + +The list of operands (values, of type [llvm.core.Value][]) that this +value refers to. + +### `operand_count` +\[read-only\] + +The number of operands that this value referes to. Same as +`len(uses.operands)` but faster if you just want the count. + + +[llvm.core.Value]: llvm.core.Value.html + diff --git a/docs/source/doc/llvm.core.Value.md b/docs/source/doc/llvm.core.Value.md new file mode 100644 index 0000000..7c0555e --- /dev/null +++ b/docs/source/doc/llvm.core.Value.md @@ -0,0 +1,50 @@ +--- +layout: page +title: Value (llvm.core) +--- + +# llvm.core.Value + +* This will become a table of contents (this text will be scraped). +{:toc} + +## Properties +### `name` + +The name of the value. + +### `type` +\[read-only\] + +An `llvm.core.Type` object representing the type of the value. + +### `uses` +\[read-only\] + +The list of values (`llvm.core.Value`) that use this value. + +### `use_count` +\[read-only\] + +The number of values that use (refer) this value. Same as `len(val.uses)` +but faster if you just want the count. + +### `value_id` +\[read-only\] + +Returns `llvmValuegetValueID()`. Refer LLVM documentation +for more info. + +## Special Methods + +### `__str__` + +`Value` objects can be stringified into it's LLVM assembly language +representation. + +### `__eq__` + +`Value` objects can be compared for equality. Internally, this +converts both arguments into their LLVM assembly representations and +compares the resultant strings. + diff --git a/docs/source/doc/llvm.core.VectorType.md b/docs/source/doc/llvm.core.VectorType.md new file mode 100644 index 0000000..b227077 --- /dev/null +++ b/docs/source/doc/llvm.core.VectorType.md @@ -0,0 +1,26 @@ +--- +layout: page +title: VectorType (llvm.core) +--- + +# llvm.core.VectorType + +## Base Class + +- [llvm.core.Type](llvm.core.Type.html) + +## Properties + + +### `element` +\[read-only\] + +A [Type](llvm.core.Type.html) object representing the type of the element of +the vector. + + +### `count` +\[read-only\] + +The number of elements in the vector. + diff --git a/docs/source/doc/llvm.ee.EngineBuilder.md b/docs/source/doc/llvm.ee.EngineBuilder.md new file mode 100644 index 0000000..a7f6c36 --- /dev/null +++ b/docs/source/doc/llvm.ee.EngineBuilder.md @@ -0,0 +1,49 @@ +--- +layout: page +title: EngineBuilder (llvm.ee) +--- + +# llvm.ee.EngineBuilder + +A convenient class for building [llvm.ee.ExecutionEngine]. +Each `EngineBuilder` instance can only create one `ExecutionEngine`. + + +## Methods + +### `create(self)` + +Create and return a new [ExecutionEngine][llvm.ee.ExecutionEngine] instance. + +Raise `llvm.LLVMException` if the builder cannot create an `ExecutionEngine` +base on the given configuration. + +### `force_interpreter(self)` + +Force the output the output `ExecutionEngine` to be an LLVM IR interpreter. + +### `force_jit(self)` + +Force the output the output `ExecutionEngine` to be a JIT engine. + +### `opt(self, level)` + +Set the code generation optimization level for a JIT engine. +Valid value of `level` is 0-3, inclusive. +The default setting is 2. +To use vector instructions, such as SSE on Intel processors, +`level` must be 3 (aggressive). + +## Static Factory Methods + +### `new(module)` + +Create a new EngineBuilder. `module` must be a [llvm.core.Module][] instance. +Its ownership is transferred to the resulting +[ExecutionEngine][llvm.ee.ExecutionEngine]. +Therefore, it is impossible to create more than one `ExecutionEngine` with +a single `EngineBuilder` + + +[llvm.core.Module]: llvm.core.Module.html +[llvm.ee.ExecutionEngine]: llvm.ee.ExecutionEngine.html diff --git a/docs/source/doc/llvm.ee.ExecutionEngine.md b/docs/source/doc/llvm.ee.ExecutionEngine.md new file mode 100644 index 0000000..39ef661 --- /dev/null +++ b/docs/source/doc/llvm.ee.ExecutionEngine.md @@ -0,0 +1,52 @@ +--- +layout: page +title: ExecutionEngine (llvm.ee) +--- + +# llvm.ee.ExecutionEngine + +## Methods + +### `add_module(self, module)` + +Add a new module to the ExecutionEngine. +The ownership is of `module` is transferred. +When the `ExecutionEngine` is destroyed, the module is destroyed. + +### `free_machine_code_for(self, fn)` + +Release memory used for the machine code generated for +the function `fn`. + +### `get_pointer_to_function(self, fn)` + +Obtain the pointer to the function `fn`. +This forces the ExecutionEngine to generate the machine code +in lazy mode. + +If `fn` is not defined, `ExecutionEngine` will lookup the +symbol through `dlsym`. + +The returned function pointer can be wrapped as a `ctypes` function. + +### `remove_module(self, module)` + +Remove the `module`. + +### `run_function(self, fn, args)` + +Execute the function `fn` with an iterable of arguments `args` +which are of `GenericValue`. This method returns whatever +that is returned by `fn` as a `GenericValue`. + +### `run_static_ctors(self)` + +### `run_static_dtors(self)` + +## Properties + +### `target_data` + +Access the [TargetData](llvm.ee.TargetData.html) +instance associated with the `ExecutionEngine`. + diff --git a/docs/source/doc/llvm.ee.GenericValue.md b/docs/source/doc/llvm.ee.GenericValue.md new file mode 100644 index 0000000..eca6975 --- /dev/null +++ b/docs/source/doc/llvm.ee.GenericValue.md @@ -0,0 +1,55 @@ +--- +layout: page +title: GenericValue (llvm.ee) +--- + +# llvm.ee.GenericValue + +* This will become a table of contents (this text will be scraped). +{:toc} + +## Methods + +### `as_int(self)` + +Return the value of this `GenericValue` instance as an unsigned integer + +### `as_int_signed(self)` + +Return the value of this `GenericValue` instance as a signed integer. + +### `as_pointer(self)` + +Return the value of this `GenericValue` instance as a pointer. +The type of the return value is `int`. + +### `as_real(self, ty)` + +Return the value of this `GenericValue` instance as a real number +which type is specified by `ty`. `ty` must be a [Type][] instance +of a real number type. + +## Static Factory Methods + +### `int(ty, intval)` + +Create a `GenericValue` instance with a `int` value, +which is zero-extended if necessary. +The type of the value is specified by `ty`, which is a [Type][] instance. + +### `int_signed(ty, intval)` + +Create a `GenericValue` instance with a `int` value, +which is sign-extended if necessary. +The type of the value is specified by `ty`, which is a [Type][] instance. + +### `pointer(ty, addr)` or `pointer(addr)` + +Create a `GenericValue` instance with a `int` value, +which is representing a pointer value. + +The two argument version is **deprecated**. +The old code never used `ty` anyway. + + +[Type]: llvm.core.Type.html diff --git a/docs/source/doc/llvm.ee.TargetData.md b/docs/source/doc/llvm.ee.TargetData.md new file mode 100644 index 0000000..537d680 --- /dev/null +++ b/docs/source/doc/llvm.ee.TargetData.md @@ -0,0 +1,48 @@ +--- +layout: page +title: TargetData (llvm.ee) +--- + +# llvm.ee.TargetData + +* This will become a table of contents (this text will be scraped). +{:toc} + +## Methods + +### `abi_alignment(self, ty)` + +Returns the minimum ABI-required alignment for the specified type `ty`. + +### `abi_size(self, ty)` + +### `callframe_alignment(self, ty)` + +Returns the minimum ABI-required alignment for the specified type `ty` when it is part of a call frame. + +### `element_at_offset(self, ty, ofs)` + +### `offset_of_element(self, ty, el)` + +### `preferred_alignment(self, ty_or_gv)` + +### `size(self, ty)` + +### `store_size(self, ty)` + +### `__str__(self)` +Returns the string representation. + +## Static Factory Methods + +### `new(strrep)` +Construct a new `TargetData` instance from the string representation + +## Properties + +### `byte_order` + +### `pointer_size` + +### `target_integer_type` + diff --git a/docs/source/doc/llvm.passes.FunctionPassManager.md b/docs/source/doc/llvm.passes.FunctionPassManager.md new file mode 100644 index 0000000..e1bc068 --- /dev/null +++ b/docs/source/doc/llvm.passes.FunctionPassManager.md @@ -0,0 +1,35 @@ +--- +layout: page +title: FunctionPassManager (llvm.passes) +--- + +# llvm.passes.FunctionPassManager + +## Base Classes + +- [llvm.passes.PassManager](llvm.passes.PassManager.html) + +## Methods + +### `finalize(self)` + +Finalizes all associated function passes in the LLVM system. + +Beware that this destroys all associated passes even if another +pass manager is using those passes. This may result is a segfault. + +### `initialize(self)` + +Initializes all associated function passes in the LLVM system. + +### `run(self, fn)` + +Run all passes on the given function `fn`. + +## Static Factory Methods + +### `new(module)` + +Create a `FunctionPassManager` instance for a given `module`. + + diff --git a/docs/source/doc/llvm.passes.PassManager.md b/docs/source/doc/llvm.passes.PassManager.md new file mode 100644 index 0000000..1883516 --- /dev/null +++ b/docs/source/doc/llvm.passes.PassManager.md @@ -0,0 +1,23 @@ +--- +layout: page +title: PassManager (llvm.passes) +--- + +# llvm.passes.PassManager + +## Methods + +### `add(self, tgt_data_or_pass_id)` + +Add a pass by its ID. A pass IDs are defined as `PASS_*`. + +### `run(self, module)` + +Run all passes on the given `module`. + +## Static Factory Methods + +### `new()` + +Creates a new `PassManager` instance. + diff --git a/docs/source/doc/llvm.passes.PassManagerBuilder.md b/docs/source/doc/llvm.passes.PassManagerBuilder.md new file mode 100644 index 0000000..7992de4 --- /dev/null +++ b/docs/source/doc/llvm.passes.PassManagerBuilder.md @@ -0,0 +1,59 @@ +--- +layout: page +title: PassManagerBuilder (llvm.passes) +--- + +# llvm.passes.PassManagerBuilder + +Provide a simple API to populate pass managers for language like C/C++. +Refer to +[LLVM API Documentation](http://llvm.org/docs/doxygen/html/classllvm_1_1PassManagerBuilder.html) +for detail. + +## Methods + +### `populate(self, pm)` + +Populate a [FunctionPassManager](llvm.passes.FunctionPassManager.html) +or [PassManager](llvm.passes.PassManager.html) given as `pm`. + +### `use_inliner_with_threshold(self, threshold)` + +Use an inliner pass with the given `threshold`. + +## Properties + +The following properties can be overriden to customize how pass managers +are populated. + +### `disable_simplify_lib_calls` + +Boolean. Default is `False`. + +### `disable_unit_at_a_time` + +Boolean. Default is `False`. + +### `disable_unroll_loops` + +Boolean. Default is `False`. + +### `opt_level` + +Default is `2`. Valid values are 0-3. Corresponds to O0, O1, O2, O3 as in C/C++ +optimization options. + +### `size_level` + +Default is `0`. + +### `vectorize` + +Default is `False`. + +## Static Factory Methods + +### `new()` + +Creates a new `PassManagerBuilder` instance. + diff --git a/docs/source/doc/llvm_concepts.md b/docs/source/doc/llvm_concepts.md new file mode 100644 index 0000000..acd27ce --- /dev/null +++ b/docs/source/doc/llvm_concepts.md @@ -0,0 +1,242 @@ +--- +layout: page +title: LLVM Concepts +--- + +This section explains a few concepts related to LLVM, not specific +to llvm-py. + + +# Intermediate Representation + +The intermediate representation, or IR for short, is an in-memory data +structure that represents executable code. The IR data structures allow +for creation of types, constants, functions, function arguments, +instructions, global variables and so on. For example, to create a +function _sum_ that takes two integers and returns their sum, we need to +follow these steps: + +- create an integer type _ti_ of required bitwidth +- create a function type _tf_ which takes two _ti_ -s and returns + another _ti_ +- create a function of type _tf_ named _sum_ +- add a _basic block_ to the function +- using a helper object called an _instruction builder_, add two + instructions into the basic block: + . an instruction to add the two arguments and store the result into + a temporary variable + . a return instruction to return the value of the temporary variable + +(A basic block is a block of instructions.) + +LLVM has it's own instruction set; the instructions used above (*add* +and *ret*) are from this set. The LLVM instructions are at a higher +level than the usual assembly language; for example there are +instructions related to variable argument handling, exception handling, +and garbage collection. These allow high-level languages to be +represented cleanly in the IR. + +* * * + +# SSA Form and PHI Nodes + +All LLVM instructions are represented in the _Static Single Assignment_ +(SSA) form. Essentially, this means that any variable can be assigned to +only once. Such a representation facilitates better optimization, among +other benefits. + +A consequence of single assignment are PHI (Φ) nodes. These +are required when a variable can be assigned a different value based on +the path of control flow. For example, the value of *b* at the end of +execution of the snippet below: + +{% highlight c %} +a = 1; +if (v < 10) + a = 2; +b = a; +{% endhighlight %} + +cannot be determined statically. The value of '2' cannot be assigned to +the 'original' *a*, since *a* can be assigned to only once. There are +two *a* 's in there, and the last assignment has to choose between which +version to pick. This is accomplished by adding a PHI node: + +{% highlight c %} +a1 = 1; +if (v < 10) + a2 = 2; +b = PHI(a1, a2); +{% endhighlight %} + +The PHI node selects *a1* or *a2*, depending on where the control +reached the PHI node. The argument *a1* of the PHI node is associated +with the block *"a1 = 1;"* and *a2* with the block *"a2 = 2;"*. + +PHI nodes have to be explicitly created in the LLVM IR. Accordingly the +LLVM instruction set has an instruction called *phi*. + + +* * * + +# LLVM Assembly Language + +The LLVM IR can be represented offline in two formats + +- a textual, human-readable form, similar to assembly language, + called the LLVM assembly language (files with .ll extension) +- a binary form, called the LLVM bitcode (files with .bc extension) + +All three formats +(the in-memory IR, the LLVM assembly language and the LLVM bitcode) +represent the _same_ information. Each format can be +converted into the other two formats (using LLVM APIs). + +The [LLVM demo page](http://www.llvm.org/demo/) lets you type in C or C++ +code, converts it into LLVM IR and outputs the IR as LLVM assembly +language code. + +Just to get a feel of the LLVM assembly language, here's a function in C, +and the corresponding LLVM assembly (as generated by the demo page): + +{% highlight c %} +/* compute sum of 1..n */ +unsigned sum(unsigned n) +{ + if (n == 0) + return 0; + else + return n + sum(n-1); +} +{% endhighlight %} + +The corresponding LLVM assembly: + +{% highlight llvm %} +; ModuleID = '/tmp/webcompile/_7149_0.bc' +target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64" +target triple = "x86_64-linux-gnu" + +define i32 @sum(i32 %n) nounwind readnone { +entry: + %0 = icmp eq i32 %n, 0 ; [#uses=1] + br i1 %0, label %bb2, label %bb1 + +bb1: ; preds = %entry + %1 = add i32 %n, -1 ; [#uses=2] + %2 = icmp eq i32 %1, 0 ; [#uses=1] + br i1 %2, label %sum.exit, label %bb1.i + +bb1.i: ; preds = %bb1 + %3 = add i32 %n, -2 ; [#uses=1] + %4 = tail call i32 @sum(i32 %3) nounwind ; [#uses=1] + %5 = add i32 %4, %1 ; [#uses=1] + br label %sum.exit + +sum.exit: ; preds = %bb1.i, %bb1 + %6 = phi i32 [ %5, %bb1.i ], [ 0, %bb1 ] ; [#uses=1] + %7 = add i32 %6, %n ; [#uses=1] + ret i32 %7 + +bb2: ; preds = %entry + ret i32 0 +} +{% endhighlight %} + +Note the usage of SSA form. The long string called `target datalayout` is a +specification of the platform ABI (like endianness, sizes of types, +alignment etc.). + +The [LLVM Language Reference](http://www.llvm.org/docs/LangRef.html) +defines the LLVM assembly language including the entire instruction set. + + +* * * + +# Modules + +[Modules](./llvm.core.Module.html), in the LLVM IR, are similar to a single *C* language source +file (.c file). A module contains: + +- functions (declarations and definitions) +- global variables and constants +- global type aliases for structures + +Modules are top-level containers; all executable code representation is +contained within modules. Modules may be combined (linked) together to +give a bigger resultant module. During this process LLVM attempts to +reconcile the references between the combined modules. + + +* * * + +# Optimization and Passes + + +LLVM provides quite a few optimization algorithms that work on the IR. +These algorithms are organized as _passes_. Each pass does something +specific, like combining redundant instructions. Passes need not always +optimize the IR, it can also do other operations like inserting +instrumentation code, or analyzing the IR (the result of which can be +used by passes that do optimizations) or even printing call graphs. + +This LLVM [documentation page](http://www.llvm.org/docs/Passes.html) +describes all the available passes, and what they do. + +LLVM does not automatically choose to run any passes, anytime. Passes +have to be explicitly selected and run on each module. This gives you +the flexibility to choose transformations and optimizations that are +most suitable for the code in the module. + +There is an LLVM binary called [opt](http://www.llvm.org/cmds/opt.html), +which lets you run passes on bitcode files from the command line. You +can write your own passes (in C/C++, as a shared library). This can be +loaded and executed by +opt+. (Although llvm-py does not allow you to +write your own passes, it does allow you to navigate the entire IR at +any stage, and perform any transforms on it as you like.) + +A "pass manager" is responsible for loading passes, selecting the +correct objects to run them on (for example, a pass may work only +on functions, individually) and actually runs them. `opt` is a +command-line wrapper for the pass manager. + +LLVM defines two kinds of pass managers: + +* The [FunctionPassManager](http://llvm.org/docs/doxygen/html/classllvm_1_1FunctionPassManager.html) + manages function or basic-block passes. These lighter weight passes + can be used immediately after each generated function to reduce memory + footprint. + +* The [PassManager](http://llvm.org/docs/doxygen/html/classllvm_1_1PassManager.html) + manages module passes for optimizing the entire module. + +* * * + + +# Bitcode + +LLVM IR can be represented as a bitcode format for disk storage. It is [suitable for fast loading by JIT compiler](http://llvm.org/docs/LangRef.html#introduction). +See [LLVM documentation](http://llvm.org/docs/BitCodeFormat.html) +for detail about the bitcode format. + + +* * * + +# Execution Engine, JIT and Interpreter + +The *execution engine* implements execution of LLVM IR through an +interpreter or a JIT dynamic compiler. An *execution engine* can +contain multiple modules. + +> **Note** +> +> +> Inter-module reference is not possible. That is module `A` +> cannot call a function in module `B`, directly. + + +* * * + +**Next** -- [llvm-py Package](./llvm-py_package.html) + + diff --git a/docs/source/doc/types.md b/docs/source/doc/types.md new file mode 100644 index 0000000..c414061 --- /dev/null +++ b/docs/source/doc/types.md @@ -0,0 +1,146 @@ +--- +layout: page +title: Types +--- + +Types are what you think they are. A instance of [llvm.core.Type][], or +one of its derived classes, represent a type. llvm-py does not use as +many classes to represent types as does LLVM itself. Some types are +represented using [llvm.core.Type][] itself and the rest are represented +using derived classes of [llvm.core.Type][]. As usual, an instance is created +via one of the static methods of [Type][llvm.core.Type]. These methods return an +instance of either [llvm.core.Type][] itself or one of its derived +classes. + +The following table lists all the available types along with the static +method which has to be used to construct it and the name of the class whose +object is actually returned by the static method. + + +Name | Constructor Method | Class | +-----|:------------------:|:-----:| +integer of bitwidth *n* | Type.int(n) | [IntegerType][llvm.core.IntegerType] | +32-bit float | Type.float() | [Type][llvm.core.Type] | +64-bit double | Type.double() | [Type][llvm.core.Type] | +80-bit float | Type.x86_fp80() | [Type][llvm.core.Type] | +128-bit float (112-bit mantissa) | Type.fp128() | [Type][llvm.core.Type] | +128-bit float (two 64-bits) | Type.ppc_fp128() | [Type][llvm.core.Type] | +function | Type.function(r, p, v) | [FunctionType][llvm.core.FunctionType] | +unpacked struct | Type.struct(eltys, name) | [StructType][llvm.core.StructType] | +packed struct | Type.packed_struct(eltys, name) | [StructType][llvm.core.StructType] | +opaque struct | Type.opaque(name) | [StructType][llvm.core.StructType] | +array | Type.array(elty, count) | [ArrayType][llvm.core.ArrayType] | +pointer to value of type *pty* | Type.pointer(pty, addrspc) | [PointerType][llvm.core.PointerType] | +vector | Type.vector(elty, count) | [VectorType][llvm.core.VectorType] | +void | Type.void() | [Type][llvm.core.Type] | +label | Type.label() | [Type][llvm.core.Type] | + + +
+ + +The class hierarchy is: + + + Type + IntegerType + FunctionType + StructType + ArrayType + PointerType + VectorType + + + +* * * + +## An Example + +Here is an example that demonstrates the creation of types: + +{% highlight python %} +#!/usr/bin/env python + +# integers +int_ty = Type.int() +bool_ty = Type.int(1) +int_64bit = Type.int(64) + +# floats +sprec_real = Type.float() +dprec_real = Type.double() + +# arrays and vectors +intar_ty = Type.array( int_ty, 10 ) # "typedef int intar_ty[10];" +twodim = Type.array( intar_ty , 10 ) # "typedef int twodim[10][10];" +vec = Type.array( int_ty, 10 ) + +# structures +s1_ty = Type.struct( [ int_ty, sprec_real ] ) + # "struct s1_ty { int v1; float v2; };" + +# pointers +intptr_ty = Type.pointer(int_ty) # "typedef int *intptr_ty;" + +# functions +f1 = Type.function( int_ty, [ int_ty ] ) + # functions that take 1 int_ty and return 1 int_ty + +f2 = Type.function( Type.void(), [ int_ty, int_ty ] ) + # functions that take 2 int_tys and return nothing + +f3 = Type.function( Type.void(), ( int_ty, int_ty ) ) + # same as f2; any iterable can be used + +fnargs = [ Type.pointer( Type.int(8) ) ] +printf = Type.function( Type.int(), fnargs, True ) # variadic function +{% endhighlight %} + +* * * + +## Another Example: Recursive Type + +The type system was rewritten in LLVM 3.0. +The old opaque type was removed. +Instead, identified `StructType` can now be defined without a body. +Doing so creates a opaque structure. +One can then set the body after the construction of a structure. + + +(See [LLVM Blog](http://blog.llvm.org/2011/11/llvm-30-type-system-rewrite.html) +for detail about the new type system.) + +The following code defines a opaque structure, named "mystruct". +The body is defined after the construction using `StructType.set_body`. +The second subtype is a pointer to a "mystruct" type. + +{% highlight python %} +ts = Type.opaque('mystruct') +ts.set_body([Type.int(), Type.pointer(ts)]) +{% endhighlight %} + +* * * + +**Related Links** +[llvm.core.Type][], +[llvm.core.IntegerType][], +[llvm.core.FunctionType][], +[llvm.core.StructType][], +[llvm.core.ArrayType][], +[llvm.core.PointerType][], +[llvm.core.VectorType][], +[llvm.core.TypeHandle][] + + + + + +[llvm.core.Type]: llvm.core.Type.html +[llvm.core.IntegerType]: llvm.core.IntegerType.html +[llvm.core.FunctionType]: llvm.core.FunctionType.html +[llvm.core.StructType]: llvm.core.StructType.html +[llvm.core.ArrayType]: llvm.core.ArrayType.html +[llvm.core.PointerType]: llvm.core.PointerType.html +[llvm.core.VectorType]: llvm.core.VectorType.html +[llvm.core.TypeHandle]: llvm.core.TypeHandle.html + diff --git a/docs/source/doc/userguide.md b/docs/source/doc/userguide.md new file mode 100644 index 0000000..16c0bff --- /dev/null +++ b/docs/source/doc/userguide.md @@ -0,0 +1,159 @@ +--- +layout: page +title: User Guide +--- + +llvm-py provides Python bindings for LLVM. This document explains how you can setup and use it. A working knowledge of Python and a basic idea of LLVM is assumed. + +# Introduction + +[LLVM](http://www.llvm.org/) (Low-Level Virtual Machine) provides enough +infrastructure to use it as the backend for your compiled, or +JIT-compiled language. It provides extensive optimization support, and +static and dynamic (JIT) backends for many platforms. See the website at + to discover more. + +Python bindings for LLVM provides a gentler learning curve for working +with the LLVM APIs. It should also be easier to create working +prototypes and experimental languages using this medium. + +Together with [clang](http://clang.llvm.org/) or +[llvm-gcc](http://llvm.org/cmds/llvmgcc.html) it also a provides a means +to quickly instrument C and C++ sources. For e.g., llvm-gcc can be used to +generate the LLVM assembly for a given C source file, which can then be +loaded and manipulated (adding profiling code to every function, say) using +a llvm-py based Python script. + +## License +Both LLVM and llvm-py are distributed under (different) permissive +open source licenses. llvm-py uses the +[new BSD license](http://opensource.org/licenses/bsd-license.php). More +information is available [here](https://github.com/numba/llvm-py/blob/master/LICENSE). + +## Platforms +llvm-py has been built/tested/reported to work on various GNU/Linux +flavours, BSD, Mac OS X; on i386 and amd64 architectures. Windows is not +supported, for a variety of reasons. + +## Versions +llvm-py 0.8.2 requires version 3.1 of LLVM. It may not work with previous +versions. + +llvm-py has been built and tested with Python 2.7. It should work with +earlier versions. It has not been tried with Python 3.x (patches welcome). + + +* * * + + +# Installation + +The Git repo of llvm-py is at . You'll +need to build and install it before it can be used. +At least the following will be required for this: + +- C and C++ compilers (gcc/g++) +- Python itself +- Python development files (headers and libraries) +- LLVM, either installed or built + +On debian-based systems, the first three can be installed with the +command `sudo apt-get install gcc g++ python python-dev`. Ensure that your +distro's repository has the appropriate version of LLVM! + +It does not matter which compiler LLVM itself was built with (`g++`, +`llvm-g++` or any other); llvm-py can be built with any compiler. It has +been tried only with gcc/g++ though. + +## LLVM and `--enable-pic` + +The result of an LLVM build is a set of static libraries and object +files. The llvm-py contains an extension package that is built into a +shared object (_core.so) which links to these static libraries and +object files. It is therefore required that the LLVM libraries and +object files be built with the `-fPIC` option (generate position +independent code). Be sure to use the `--enable-pic` option while +configuring LLVM (default is no PIC), like this: + +{% highlight bash %} +~/llvm$ ./configure --enable-pic --enable-optimized +{% endhighlight %} + + +## llvm-config + +In order to build llvm-py, it's build script needs to know from where it +can invoke the llvm helper program, `llvm-config`. If you've installed +LLVM, then this will be available in your `PATH`, and nothing further +needs to be done. If you've built LLVM yourself, or for any reason +`llvm-config` is not in your `PATH`, you'll need to pass the full path +of `llvm-config` to the build script. + +You'll need to be 'root' to install llvm-py. Remember that your `PATH` +is different from that of 'root', so even if `llvm-config` is in your +`PATH`, it may not be available when you do `sudo`. + + + +## Steps + +Get 3.1 version of LLVM, build it. Make sure '--enable-pic' is passed to LLVM's 'configure'. + +Get llvm-py and install it: + +{% highlight bash %} +$ git clone git@github.com:numba/llvm-py.git +$ cd llvm-py +$ python setup.py install +{% endhighlight %} + +If you need to tell the build script where `llvm-config` is, do it this +way: + +{% highlight bash %} +$ python setup.py install --user --llvm-config=/home/mdevan/llvm/Release/bin/llvm-config +{% endhighlight %} + +To build a debug version of llvm-py, that links against the debug +libraries of LLVM, use this: + +{% highlight bash %} +$ python setup.py build -g --llvm-config=/home/mdevan/llvm/Debug/bin/llvm-config +$ python setup.py install --user --llvm-config=/home/mdevan/llvm/Debug/bin/llvm-config +{% endhighlight %} + +Be warned that debug binaries will be huge (100MB+) ! They are required +only if you need to debug into LLVM also. + +`setup.py` is a standard Python distutils script. See the Python +documentation regarding +[Installing Python Modules](http://docs.python.org/inst/inst.html) and +[Distributing Python Modules](http://docs.python.org/dist/dist.html) +for more information on such scripts. + +* * * + +# Uninstall # {#uninstall} + +If you'd installed llvm-py with the `--user` option, then llvm-py +would be present under `~/.local/lib/python2.7/site-packages`. +Otherwise, it might be under `/usr/lib/python2.7/site-packages` +or `/usr/local/lib/python2.7/site-packages`. The directory would +vary with your Python version and OS flavour. Look around. + +Once you've located the site-packages directory, the modules and +the "egg" can be removed like so: + +{% highlight bash %} +$ rm -rf /llvm /llvm_py-.egg-info +{% endhighlight %} + + +See the [Python documentation](http://docs.python.org/install/index.html) +for more information. + +* * * + +**Next** -- [LLVM concepts](./llvm_concepts.html) + + diff --git a/docs/source/doc/values.md b/docs/source/doc/values.md new file mode 100644 index 0000000..39ba6b2 --- /dev/null +++ b/docs/source/doc/values.md @@ -0,0 +1,88 @@ +--- +layout: page +title: Values +--- + +[llvm.core.Value][] is the base class of all values computed by a program +that may be used as operands to other values. A value has a type +associated with it (an object of [llvm.core.Type][]). + +The class hierarchy is: + + + Value + User + Constant + ConstantExpr + ConstantAggregateZero + ConstantInt + ConstantFP + ConstantArray + ConstantStruct + ConstantVector + ConstantPointerNull + UndefValue + GlobalValue + GlobalVariable + Function + Instruction + CallOrInvokeInstruction + PHINode + SwitchInstruction + CompareInstruction + Argument + BasicBlock + + +The [Value][llvm.core.Value] class is abstract, it's not meant to be +instantiated. [User][llvm.core.User] is a [Value][llvm.core.Value] + that in turn uses (i.e., can refer to) other values (for +e.g., a constant expression 1+2 refers to two constant values 1 and 2). + +[Constant][llvm.core.Constant]-s represent constants that appear within code or +as initializers of globals. They are constructed using static methods of +[Constant][llvm.core.Constant]. Various types of constants are represented by +various subclasses of [Constant][llvm.core.Constant]. +However, most of them are empty and do not provide any additional attributes or methods over [Constant][llvm.core.Constant]. + +The [Function][functions] object represents an instance of a +function type. Such objects contain [Argument][llvm.core.Argument] objects, +which represent the actual, +local-variable-like arguments of the function (not to be confused with +the arguments returned by a function _type_ object -- these represent +the _type_ of the arguments). + +The various [Instruction][llvm.core.Instruction]-s are created +by the [Builder][llvm.core.Builder] class. Most +instructions are represented by [Instruction][llvm.core.Instruction] itself, +but there are a few subclasses that represent interesting instructions. + +[Value][llvm.core.Value] objects have a type (read-only), +and a name (read-write). + +**Related Links** +[functions][], +[comparision][], +[llvm.core.Value][], +[llvm.core.User][], +[llvm.core.Constant][], +[llvm.core.GlobalValue][], +[llvm.core.GlobalVariable][], +[llvm.core.Argument][], +[llvm.core.Instruction][], +[llvm.core.Builder][], +[llvm.core.BasicBlock][] + + +[llvm.core.Type]: types.html +[functions]: functions.html +[comparision]: comparision.html +[llvm.core.Value]: llvm.core.Value.html +[llvm.core.User]: llvm.core.User.html +[llvm.core.Constant]: llvm.core.Constant.html +[llvm.core.GlobalValue]: llvm.core.GlobalValue.html +[llvm.core.GlobalVariable]: llvm.core.GlobalVariable.html +[llvm.core.Argument]: llvm.core.Argument.html +[llvm.core.Instruction]: llvm.core.Instruction.html +[llvm.core.Builder]: llvm.core.Builder.html +[llvm.core.BasicBlock]: llvm.core.BasicBlock.html diff --git a/docs/source/index.rst b/docs/source/index.rst new file mode 100644 index 0000000..1ef8eaf --- /dev/null +++ b/docs/source/index.rst @@ -0,0 +1,22 @@ +.. llvmpy documentation master file, created by + sphinx-quickstart on Wed Aug 8 17:33:58 2012. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to llvmpy's documentation! +================================== + +Contents: + +.. toctree:: + :maxdepth: 2 + + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` + From 0e223a61c29d50f321053338afa0375429c4e681 Mon Sep 17 00:00:00 2001 From: "Travis E. Oliphant" Date: Wed, 8 Aug 2012 18:07:13 -0500 Subject: [PATCH 053/675] Remove .md files and add .rst files --- docs/source/doc/comparision.md | 119 -- docs/source/doc/examples.md | 154 -- docs/source/doc/examples.rst | 203 ++ docs/source/doc/examples/JITTutorial1.md | 38 - docs/source/doc/examples/JITTutorial1.rst | 45 + docs/source/doc/examples/JITTutorial2.md | 57 - docs/source/doc/examples/JITTutorial2.rst | 62 + docs/source/doc/functions.md | 198 -- docs/source/doc/functions.rst | 200 ++ .../doc/kaleidoscope/PythonLangImpl1.md | 330 --- .../doc/kaleidoscope/PythonLangImpl1.rst | 286 +++ .../doc/kaleidoscope/PythonLangImpl2.md | 998 --------- .../doc/kaleidoscope/PythonLangImpl2.rst | 892 ++++++++ .../doc/kaleidoscope/PythonLangImpl3.md | 1062 ---------- .../doc/kaleidoscope/PythonLangImpl3.rst | 936 +++++++++ .../doc/kaleidoscope/PythonLangImpl4.md | 941 --------- .../doc/kaleidoscope/PythonLangImpl4.rst | 803 ++++++++ .../doc/kaleidoscope/PythonLangImpl5.md | 1464 -------------- .../doc/kaleidoscope/PythonLangImpl5.rst | 1339 ++++++++++++ .../doc/kaleidoscope/PythonLangImpl6.md | 1535 -------------- .../doc/kaleidoscope/PythonLangImpl6.rst | 1361 +++++++++++++ .../doc/kaleidoscope/PythonLangImpl7.md | 1794 ----------------- .../doc/kaleidoscope/PythonLangImpl7.rst | 1574 +++++++++++++++ .../doc/kaleidoscope/PythonLangImpl8.md | 275 --- .../doc/kaleidoscope/PythonLangImpl8.rst | 286 +++ docs/source/doc/llvm-py_package.md | 92 - docs/source/doc/llvm.core.Argument.md | 57 - docs/source/doc/llvm.core.Argument.rst | 58 + docs/source/doc/llvm.core.ArrayType.md | 26 - docs/source/doc/llvm.core.ArrayType.rst | 30 + docs/source/doc/llvm.core.BasicBlock.md | 40 - docs/source/doc/llvm.core.BasicBlock.rst | 44 + docs/source/doc/llvm.core.Builder.md | 326 --- docs/source/doc/llvm.core.Builder.rst | 411 ++++ docs/source/doc/llvm.core.Constant.md | 296 --- docs/source/doc/llvm.core.Constant.rst | 354 ++++ docs/source/doc/llvm.core.Function.md | 129 -- docs/source/doc/llvm.core.Function.rst | 151 ++ docs/source/doc/llvm.core.FunctionType.md | 53 - docs/source/doc/llvm.core.FunctionType.rst | 52 + docs/source/doc/llvm.core.GlobalValue.md | 99 - docs/source/doc/llvm.core.GlobalValue.rst | 97 + docs/source/doc/llvm.core.GlobalVariable.md | 94 - docs/source/doc/llvm.core.GlobalVariable.rst | 103 + docs/source/doc/llvm.core.Instruction.md | 215 -- docs/source/doc/llvm.core.Instruction.rst | 242 +++ docs/source/doc/llvm.core.IntegerType.md | 20 - docs/source/doc/llvm.core.IntegerType.rst | 23 + docs/source/doc/llvm.core.Module.md | 219 -- docs/source/doc/llvm.core.Module.rst | 233 +++ docs/source/doc/llvm.core.PointerType.md | 26 - docs/source/doc/llvm.core.PointerType.rst | 31 + docs/source/doc/llvm.core.StructType.md | 70 - docs/source/doc/llvm.core.StructType.rst | 84 + docs/source/doc/llvm.core.Type.md | 148 -- docs/source/doc/llvm.core.Type.rst | 145 ++ docs/source/doc/llvm.core.User.md | 34 - docs/source/doc/llvm.core.User.rst | 39 + docs/source/doc/llvm.core.Value.md | 50 - docs/source/doc/llvm.core.Value.rst | 65 + docs/source/doc/llvm.core.VectorType.md | 26 - docs/source/doc/llvm.core.VectorType.rst | 31 + docs/source/doc/llvm.ee.EngineBuilder.md | 49 - docs/source/doc/llvm.ee.EngineBuilder.rst | 56 + docs/source/doc/llvm.ee.ExecutionEngine.md | 52 - docs/source/doc/llvm.ee.ExecutionEngine.rst | 62 + docs/source/doc/llvm.ee.GenericValue.md | 55 - docs/source/doc/llvm.ee.GenericValue.rst | 64 + docs/source/doc/llvm.ee.TargetData.md | 48 - docs/source/doc/llvm.ee.TargetData.rst | 70 + .../doc/llvm.passes.FunctionPassManager.md | 35 - .../doc/llvm.passes.FunctionPassManager.rst | 42 + docs/source/doc/llvm.passes.PassManager.md | 23 - docs/source/doc/llvm.passes.PassManager.rst | 29 + .../doc/llvm.passes.PassManagerBuilder.md | 59 - .../doc/llvm.passes.PassManagerBuilder.rst | 72 + docs/source/doc/llvm_concepts.md | 242 --- docs/source/doc/llvm_concepts.rst | 214 ++ docs/source/doc/llvmpy_package.rst | 96 + docs/source/doc/types.md | 146 -- docs/source/doc/types.rst | 138 ++ docs/source/doc/userguide.md | 159 -- docs/source/doc/userguide.rst | 165 ++ docs/source/doc/values.md | 88 - docs/source/doc/values.rst | 78 + docs/source/index.rst | 11 +- 86 files changed, 11275 insertions(+), 11943 deletions(-) delete mode 100644 docs/source/doc/comparision.md delete mode 100644 docs/source/doc/examples.md create mode 100644 docs/source/doc/examples.rst delete mode 100644 docs/source/doc/examples/JITTutorial1.md create mode 100644 docs/source/doc/examples/JITTutorial1.rst delete mode 100644 docs/source/doc/examples/JITTutorial2.md create mode 100644 docs/source/doc/examples/JITTutorial2.rst delete mode 100644 docs/source/doc/functions.md create mode 100644 docs/source/doc/functions.rst delete mode 100644 docs/source/doc/kaleidoscope/PythonLangImpl1.md create mode 100644 docs/source/doc/kaleidoscope/PythonLangImpl1.rst delete mode 100644 docs/source/doc/kaleidoscope/PythonLangImpl2.md create mode 100644 docs/source/doc/kaleidoscope/PythonLangImpl2.rst delete mode 100644 docs/source/doc/kaleidoscope/PythonLangImpl3.md create mode 100644 docs/source/doc/kaleidoscope/PythonLangImpl3.rst delete mode 100644 docs/source/doc/kaleidoscope/PythonLangImpl4.md create mode 100644 docs/source/doc/kaleidoscope/PythonLangImpl4.rst delete mode 100644 docs/source/doc/kaleidoscope/PythonLangImpl5.md create mode 100644 docs/source/doc/kaleidoscope/PythonLangImpl5.rst delete mode 100644 docs/source/doc/kaleidoscope/PythonLangImpl6.md create mode 100644 docs/source/doc/kaleidoscope/PythonLangImpl6.rst delete mode 100644 docs/source/doc/kaleidoscope/PythonLangImpl7.md create mode 100644 docs/source/doc/kaleidoscope/PythonLangImpl7.rst delete mode 100644 docs/source/doc/kaleidoscope/PythonLangImpl8.md create mode 100644 docs/source/doc/kaleidoscope/PythonLangImpl8.rst delete mode 100644 docs/source/doc/llvm-py_package.md delete mode 100644 docs/source/doc/llvm.core.Argument.md create mode 100644 docs/source/doc/llvm.core.Argument.rst delete mode 100644 docs/source/doc/llvm.core.ArrayType.md create mode 100644 docs/source/doc/llvm.core.ArrayType.rst delete mode 100644 docs/source/doc/llvm.core.BasicBlock.md create mode 100644 docs/source/doc/llvm.core.BasicBlock.rst delete mode 100644 docs/source/doc/llvm.core.Builder.md create mode 100644 docs/source/doc/llvm.core.Builder.rst delete mode 100644 docs/source/doc/llvm.core.Constant.md create mode 100644 docs/source/doc/llvm.core.Constant.rst delete mode 100644 docs/source/doc/llvm.core.Function.md create mode 100644 docs/source/doc/llvm.core.Function.rst delete mode 100644 docs/source/doc/llvm.core.FunctionType.md create mode 100644 docs/source/doc/llvm.core.FunctionType.rst delete mode 100644 docs/source/doc/llvm.core.GlobalValue.md create mode 100644 docs/source/doc/llvm.core.GlobalValue.rst delete mode 100644 docs/source/doc/llvm.core.GlobalVariable.md create mode 100644 docs/source/doc/llvm.core.GlobalVariable.rst delete mode 100644 docs/source/doc/llvm.core.Instruction.md create mode 100644 docs/source/doc/llvm.core.Instruction.rst delete mode 100644 docs/source/doc/llvm.core.IntegerType.md create mode 100644 docs/source/doc/llvm.core.IntegerType.rst delete mode 100644 docs/source/doc/llvm.core.Module.md create mode 100644 docs/source/doc/llvm.core.Module.rst delete mode 100644 docs/source/doc/llvm.core.PointerType.md create mode 100644 docs/source/doc/llvm.core.PointerType.rst delete mode 100644 docs/source/doc/llvm.core.StructType.md create mode 100644 docs/source/doc/llvm.core.StructType.rst delete mode 100644 docs/source/doc/llvm.core.Type.md create mode 100644 docs/source/doc/llvm.core.Type.rst delete mode 100644 docs/source/doc/llvm.core.User.md create mode 100644 docs/source/doc/llvm.core.User.rst delete mode 100644 docs/source/doc/llvm.core.Value.md create mode 100644 docs/source/doc/llvm.core.Value.rst delete mode 100644 docs/source/doc/llvm.core.VectorType.md create mode 100644 docs/source/doc/llvm.core.VectorType.rst delete mode 100644 docs/source/doc/llvm.ee.EngineBuilder.md create mode 100644 docs/source/doc/llvm.ee.EngineBuilder.rst delete mode 100644 docs/source/doc/llvm.ee.ExecutionEngine.md create mode 100644 docs/source/doc/llvm.ee.ExecutionEngine.rst delete mode 100644 docs/source/doc/llvm.ee.GenericValue.md create mode 100644 docs/source/doc/llvm.ee.GenericValue.rst delete mode 100644 docs/source/doc/llvm.ee.TargetData.md create mode 100644 docs/source/doc/llvm.ee.TargetData.rst delete mode 100644 docs/source/doc/llvm.passes.FunctionPassManager.md create mode 100644 docs/source/doc/llvm.passes.FunctionPassManager.rst delete mode 100644 docs/source/doc/llvm.passes.PassManager.md create mode 100644 docs/source/doc/llvm.passes.PassManager.rst delete mode 100644 docs/source/doc/llvm.passes.PassManagerBuilder.md create mode 100644 docs/source/doc/llvm.passes.PassManagerBuilder.rst delete mode 100644 docs/source/doc/llvm_concepts.md create mode 100644 docs/source/doc/llvm_concepts.rst create mode 100644 docs/source/doc/llvmpy_package.rst delete mode 100644 docs/source/doc/types.md create mode 100644 docs/source/doc/types.rst delete mode 100644 docs/source/doc/userguide.md create mode 100644 docs/source/doc/userguide.rst delete mode 100644 docs/source/doc/values.md create mode 100644 docs/source/doc/values.rst diff --git a/docs/source/doc/comparision.md b/docs/source/doc/comparision.md deleted file mode 100644 index 43073c7..0000000 --- a/docs/source/doc/comparision.md +++ /dev/null @@ -1,119 +0,0 @@ ---- -layout: page -title: Comparison Operations ---- - -# Integer Comparision # {#icmp} - -Predicates for use with `icmp` instruction are listed below. All -of these are integer constants defined in the `llvm.core` module. - -##`ICMP_EQ` - -Equality - -##`ICMP_NE` - -Inequality - -##`ICMP_UGT` - -Unsigned greater than - -##`ICMP_UGE` - -Unsigned greater than or equal - -##`ICMP_ULT` - -Unsigned less than - -##`ICMP_ULE` - -Unsigned less than or equal - -##`ICMP_SGT` - -Signed greater than - -##`ICMP_SGE` - -Signed greater than or equal - -##`ICMP_SLT` - -Signed less than - -##`ICMP_SLE` - -Signed less than or equal - -# Float Comparision # {#fcmp} - -Predicates for use with `fcmp` instruction are listed below. All -of these are integer constants defined in the `llvm.core` module. - -##`FCMP_FALSE` - -Always false - -##`FCMP_OEQ` - -True if ordered and equal - -##`FCMP_OGT` - -True if ordered and greater than - -##`FCMP_OGE` - -True if ordered and greater than or equal - -##`FCMP_OLT` - -True if ordered and less than - -##`FCMP_OLE` - -True if ordered and less than or equal - -##`FCMP_ONE` - -True if ordered and operands are unequal - -##`FCMP_ORD` - -True if ordered (no NaNs) - -##`FCMP_UNO` - -True if unordered: `isnan(X) | isnan(Y)` - -##`FCMP_UEQ` - -True if unordered or equal - -##`FCMP_UGT` - -True if unordered or greater than - -##`FCMP_UGE` - -True if unordered, greater than or equal - -##`FCMP_ULT` - -True if unordered, or less than - -##`FCMP_ULE` - -True if unordered, less than or equal - -##`FCMP_UNE` - -True if unordered or not equal - -##`FCMP_TRUE` - -Always true - diff --git a/docs/source/doc/examples.md b/docs/source/doc/examples.md deleted file mode 100644 index 337f09a..0000000 --- a/docs/source/doc/examples.md +++ /dev/null @@ -1,154 +0,0 @@ ---- -layout: page -title: Examples and LLVM Tutorials ---- - -* This will become a table of contents (this text will be scraped). -{:toc} - -# Examples - -## A Simple Function - -Let's create a (LLVM) module containing a single function, corresponding -to the `C` function: - -{% highlight c %} -int sum(int a, int b) -{ - return a + b; -} -{% endhighlight %} - -Here's how it looks like: - -{% highlight python %} -#!/usr/bin/env python - -# Import the llvm-py modules. -from llvm import * -from llvm.core import * - -# Create an (empty) module. -my_module = Module.new('my_module') - -# All the types involved here are "int"s. This type is represented -# by an object of the llvm.core.Type class: -ty_int = Type.int() # by default 32 bits - -# We need to represent the class of functions that accept two integers -# and return an integer. This is represented by an object of the -# function type (llvm.core.FunctionType): -ty_func = Type.function(ty_int, [ty_int, ty_int]) - -# Now we need a function named 'sum' of this type. Functions are not -# free-standing (in llvm-py); it needs to be contained in a module. -f_sum = my_module.add_function(ty_func, "sum") - -# Let's name the function arguments as 'a' and 'b'. -f_sum.args[0].name = "a" -f_sum.args[1].name = "b" - -# Our function needs a "basic block" -- a set of instructions that -# end with a terminator (like return, branch etc.). By convention -# the first block is called "entry". -bb = f_sum.append_basic_block("entry") - -# Let's add instructions into the block. For this, we need an -# instruction builder: -builder = Builder.new(bb) - -# OK, now for the instructions themselves. We'll create an add -# instruction that returns the sum as a value, which we'll use -# a ret instruction to return. -tmp = builder.add(f_sum.args[0], f_sum.args[1], "tmp") -builder.ret(tmp) - -# We've completed the definition now! Let's see the LLVM assembly -# language representation of what we've created: -print my_module -{% endhighlight %} - -Here is the output: - -{% highlight llvm %} -; ModuleID = 'my_module' - -define i32 @sum(i32 %a, i32 %b) { -entry: - %tmp = add i32 %a, %b ; [#uses=1] - ret i32 %tmp -} -{% endhighlight %} - - -## Adding JIT Compilation - -Let's compile this function in-memory and run it. - -{% highlight python %} -#!/usr/bin/env python - -# Import the llvm-py modules. -from llvm import * -from llvm.core import * -from llvm.ee import * # new import: ee = Execution Engine - -# Create a module, as in the previous example. -my_module = Module.new('my_module') -ty_int = Type.int() # by default 32 bits -ty_func = Type.function(ty_int, [ty_int, ty_int]) -f_sum = my_module.add_function(ty_func, "sum") -f_sum.args[0].name = "a" -f_sum.args[1].name = "b" -bb = f_sum.append_basic_block("entry") -builder = Builder.new(bb) -tmp = builder.add(f_sum.args[0], f_sum.args[1], "tmp") -builder.ret(tmp) - -# Create an execution engine object. This will create a JIT compiler -# on platforms that support it, or an interpreter otherwise. -ee = ExecutionEngine.new(my_module) - -# The arguments needs to be passed as "GenericValue" objects. -arg1 = GenericValue.int(ty_int, 100) -arg2 = GenericValue.int(ty_int, 42) - -# Now let's compile and run! -retval = ee.run_function(f_sum, [arg1, arg2]) - -# The return value is also GenericValue. Let's print it. -print "returned", retval.as_int() -{% endhighlight %} - -And here's the output: - - returned 142 - -* * * - -# LLVM Tutorials - -## Simple JIT Tutorials - -The following JIT tutorials were contributed by Sebastien Binet. - -1. [A First Function](examples/JITTutorial1.html) -2. [A More Complicated Function](examples/JITTutorial2.html) - -## Kaleidoscope ## {#kaleidoscope} - -Implementing a Language with LLVM - -The LLVM [Kaleidoscope](http://www.llvm.org/docs/tutorial/) tutorial -has been ported to llvm-py by Max Shawabkeh. - -1. [Tutorial Introduction and the Lexer](kaleidoscope/PythonLangImpl1.html) -2. [Implementing a Parser and AST](kaleidoscope/PythonLangImpl2.html) -3. [Implementing Code Generation to LLVM IR](kaleidoscope/PythonLangImpl3.html) -4. [Adding JIT and Optimizer Support](kaleidoscope/PythonLangImpl4.html) -5. [Extending the language: control flow](kaleidoscope/PythonLangImpl5.html) -6. [Extending the language: user-defined operators](kaleidoscope/PythonLangImpl6.html) -7. [Extending the language: mutable variables / SSA construction](kaleidoscope/PythonLangImpl7.html) -8. [Conclusion and other useful LLVM tidbits](kaleidoscope/PythonLangImpl8.html) - diff --git a/docs/source/doc/examples.rst b/docs/source/doc/examples.rst new file mode 100644 index 0000000..bbce175 --- /dev/null +++ b/docs/source/doc/examples.rst @@ -0,0 +1,203 @@ ++--------------------------------------+ +| layout: page | ++--------------------------------------+ +| title: Examples and LLVM Tutorials | ++--------------------------------------+ + +- This will become a table of contents (this text will be scraped). + {:toc} + +Examples +======== + +A Simple Function +----------------- + +Let's create a (LLVM) module containing a single function, corresponding +to the ``C`` function: + +{% highlight c %} int sum(int a, int b) { return a + b; } {% +endhighlight %} + +Here's how it looks like: + +{% highlight python %} #!/usr/bin/env python + +Import the llvm-py modules. +=========================== + +from llvm import \* from llvm.core import \* + +Create an (empty) module. +========================= + +my\_module = Module.new('my\_module') + +All the types involved here are "int"s. This type is represented +================================================================ + +by an object of the llvm.core.Type class: +========================================= + +ty\_int = Type.int() # by default 32 bits + +We need to represent the class of functions that accept two integers +==================================================================== + +and return an integer. This is represented by an object of the +============================================================== + +function type (llvm.core.FunctionType): +======================================= + +ty\_func = Type.function(ty\_int, [ty\_int, ty\_int]) + +Now we need a function named 'sum' of this type. Functions are not +================================================================== + +free-standing (in llvm-py); it needs to be contained in a module. +================================================================= + +f\_sum = my\_module.add\_function(ty\_func, "sum") + +Let's name the function arguments as 'a' and 'b'. +================================================= + +f\_sum.args[0].name = "a" f\_sum.args[1].name = "b" + +Our function needs a "basic block" -- a set of instructions that +================================================================ + +end with a terminator (like return, branch etc.). By convention +=============================================================== + +the first block is called "entry". +================================== + +bb = f\_sum.append\_basic\_block("entry") + +Let's add instructions into the block. For this, we need an +=========================================================== + +instruction builder: +==================== + +builder = Builder.new(bb) + +OK, now for the instructions themselves. We'll create an add +============================================================ + +instruction that returns the sum as a value, which we'll use +============================================================ + +a ret instruction to return. +============================ + +tmp = builder.add(f\_sum.args[0], f\_sum.args[1], "tmp") +builder.ret(tmp) + +We've completed the definition now! Let's see the LLVM assembly +=============================================================== + +language representation of what we've created: +============================================== + +print my\_module {% endhighlight %} + +Here is the output: + +{% highlight llvm %} ; ModuleID = 'my\_module' + +define i32 @sum(i32 %a, i32 %b) { entry: %tmp = add i32 %a, %b ; +[#uses=1] ret i32 %tmp } {% endhighlight %} + +Adding JIT Compilation +---------------------- + +Let's compile this function in-memory and run it. + +{% highlight python %} #!/usr/bin/env python + +Import the llvm-py modules. +=========================== + +from llvm import \* from llvm.core import \* from llvm.ee import \* # +new import: ee = Execution Engine + +Create a module, as in the previous example. +============================================ + +my\_module = Module.new('my\_module') ty\_int = Type.int() # by default +32 bits ty\_func = Type.function(ty\_int, [ty\_int, ty\_int]) f\_sum = +my\_module.add\_function(ty\_func, "sum") f\_sum.args[0].name = "a" +f\_sum.args[1].name = "b" bb = f\_sum.append\_basic\_block("entry") +builder = Builder.new(bb) tmp = builder.add(f\_sum.args[0], +f\_sum.args[1], "tmp") builder.ret(tmp) + +Create an execution engine object. This will create a JIT compiler +================================================================== + +on platforms that support it, or an interpreter otherwise. +========================================================== + +ee = ExecutionEngine.new(my\_module) + +The arguments needs to be passed as "GenericValue" objects. +=========================================================== + +arg1 = GenericValue.int(ty\_int, 100) arg2 = GenericValue.int(ty\_int, +42) + +Now let's compile and run! +========================== + +retval = ee.run\_function(f\_sum, [arg1, arg2]) + +The return value is also GenericValue. Let's print it. +====================================================== + +print "returned", retval.as\_int() {% endhighlight %} + +And here's the output: + +:: + + returned 142 + +-------------- + +LLVM Tutorials +============== + +Simple JIT Tutorials +-------------------- + +The following JIT tutorials were contributed by Sebastien Binet. + +1. `A First Function `_ +2. `A More Complicated Function `_ + +Kaleidoscope ## {#kaleidoscope} +------------------------------- + +Implementing a Language with LLVM + +The LLVM `Kaleidoscope `_ tutorial +has been ported to llvm-py by Max Shawabkeh. + +1. `Tutorial Introduction and the + Lexer `_ +2. `Implementing a Parser and AST `_ +3. `Implementing Code Generation to LLVM + IR `_ +4. `Adding JIT and Optimizer + Support `_ +5. `Extending the language: control + flow `_ +6. `Extending the language: user-defined + operators `_ +7. `Extending the language: mutable variables / SSA + construction `_ +8. `Conclusion and other useful LLVM + tidbits `_ + diff --git a/docs/source/doc/examples/JITTutorial1.md b/docs/source/doc/examples/JITTutorial1.md deleted file mode 100644 index 32186de..0000000 --- a/docs/source/doc/examples/JITTutorial1.md +++ /dev/null @@ -1,38 +0,0 @@ ---- -layout: page -title: JIT Tutorial 1 ---- - -{% highlight python %} -#!/usr/bin/env python - -from llvm.core import * - -# create a module -module = Module.new ("tut1") - -# create a function type taking 3 32-bit integers, return a 32-bit integer -ty_int = Type.int (32) -func_type = Type.function (ty_int, (ty_int,)*3) - -# create a function of that type -mul_add = Function.new (module, func_type, "mul_add") -mul_add.calling_convention = CC_C -x = mul_add.args[0]; x.name = "x" -y = mul_add.args[1]; y.name = "y" -z = mul_add.args[2]; z.name = "z" - -# implement the function - -# new block -blk = mul_add.append_basic_block ("entry") - -# IR builder -bldr = Builder.new (blk) -tmp_1 = bldr.mul (x, y, "tmp_1") -tmp_2 = bldr.add (tmp_1, z, "tmp_2") - -bldr.ret (tmp_2) - -print(module) -{% endhighlight %} diff --git a/docs/source/doc/examples/JITTutorial1.rst b/docs/source/doc/examples/JITTutorial1.rst new file mode 100644 index 0000000..7c02fb1 --- /dev/null +++ b/docs/source/doc/examples/JITTutorial1.rst @@ -0,0 +1,45 @@ ++-------------------------+ +| layout: page | ++-------------------------+ +| title: JIT Tutorial 1 | ++-------------------------+ + +{% highlight python %} #!/usr/bin/env python + +from llvm.core import \* + +create a module +=============== + +module = Module.new ("tut1") + +create a function type taking 3 32-bit integers, return a 32-bit integer +======================================================================== + +ty\_int = Type.int (32) func\_type = Type.function (ty\_int, +(ty\_int,)\*3) + +create a function of that type +============================== + +mul\_add = Function.new (module, func\_type, "mul\_add") +mul\_add.calling\_convention = CC\_C x = mul\_add.args[0]; x.name = "x" +y = mul\_add.args[1]; y.name = "y" z = mul\_add.args[2]; z.name = "z" + +implement the function +====================== + +new block +========= + +blk = mul\_add.append\_basic\_block ("entry") + +IR builder +========== + +bldr = Builder.new (blk) tmp\_1 = bldr.mul (x, y, "tmp\_1") tmp\_2 = +bldr.add (tmp\_1, z, "tmp\_2") + +bldr.ret (tmp\_2) + +print(module) {% endhighlight %} diff --git a/docs/source/doc/examples/JITTutorial2.md b/docs/source/doc/examples/JITTutorial2.md deleted file mode 100644 index 7ce36d7..0000000 --- a/docs/source/doc/examples/JITTutorial2.md +++ /dev/null @@ -1,57 +0,0 @@ ---- -layout: page -title: JIT Tutorial 2 ---- - -{% highlight python %} -#!/usr/bin/env python - -from llvm.core import * - -# create a module -module = Module.new ("tut2") - -# create a function type taking 2 integers, return a 32-bit integer -ty_int = Type.int (32) -func_type = Type.function (ty_int, (ty_int, ty_int)) - -# create a function of that type -gcd = Function.new (module, func_type, "gcd") - -# name function args -x = gcd.args[0]; x.name = "x" -y = gcd.args[1]; y.name = "y" - -# implement the function - -# blocks... -entry = gcd.append_basic_block ("entry") -ret = gcd.append_basic_block ("return") -cond_false = gcd.append_basic_block ("cond_false") -cond_true = gcd.append_basic_block ("cond_true") -cond_false_2 = gcd.append_basic_block ("cond_false_2") - -# create a llvm::IRBuilder -bldr = Builder.new (entry) -x_eq_y = bldr.icmp (IPRED_EQ, x, y, "tmp") -bldr.cbranch (x_eq_y, ret, cond_false) - -bldr.position_at_end (ret) -bldr.ret(x) - -bldr.position_at_end (cond_false) -x_lt_y = bldr.icmp (IPRED_ULT, x, y, "tmp") -bldr.cbranch (x_lt_y, cond_true, cond_false_2) - -bldr.position_at_end (cond_true) -y_sub_x = bldr.sub (y, x, "tmp") -recur_1 = bldr.call (gcd, (x, y_sub_x,), "tmp") -bldr.ret (recur_1) - -bldr.position_at_end (cond_false_2) -x_sub_y = bldr.sub (x, y, "x_sub_y") -recur_2 = bldr.call (gcd, (x_sub_y, y,), "tmp") -bldr.ret (recur_2) - -print(module) -{% endhighlight %} diff --git a/docs/source/doc/examples/JITTutorial2.rst b/docs/source/doc/examples/JITTutorial2.rst new file mode 100644 index 0000000..8c420c5 --- /dev/null +++ b/docs/source/doc/examples/JITTutorial2.rst @@ -0,0 +1,62 @@ ++-------------------------+ +| layout: page | ++-------------------------+ +| title: JIT Tutorial 2 | ++-------------------------+ + +{% highlight python %} #!/usr/bin/env python + +from llvm.core import \* + +create a module +=============== + +module = Module.new ("tut2") + +create a function type taking 2 integers, return a 32-bit integer +================================================================= + +ty\_int = Type.int (32) func\_type = Type.function (ty\_int, (ty\_int, +ty\_int)) + +create a function of that type +============================== + +gcd = Function.new (module, func\_type, "gcd") + +name function args +================== + +x = gcd.args[0]; x.name = "x" y = gcd.args[1]; y.name = "y" + +implement the function +====================== + +blocks... +========= + +entry = gcd.append\_basic\_block ("entry") ret = +gcd.append\_basic\_block ("return") cond\_false = +gcd.append\_basic\_block ("cond\_false") cond\_true = +gcd.append\_basic\_block ("cond\_true") cond\_false\_2 = +gcd.append\_basic\_block ("cond\_false\_2") + +create a llvm::IRBuilder +======================== + +bldr = Builder.new (entry) x\_eq\_y = bldr.icmp (IPRED\_EQ, x, y, "tmp") +bldr.cbranch (x\_eq\_y, ret, cond\_false) + +bldr.position\_at\_end (ret) bldr.ret(x) + +bldr.position\_at\_end (cond\_false) x\_lt\_y = bldr.icmp (IPRED\_ULT, +x, y, "tmp") bldr.cbranch (x\_lt\_y, cond\_true, cond\_false\_2) + +bldr.position\_at\_end (cond\_true) y\_sub\_x = bldr.sub (y, x, "tmp") +recur\_1 = bldr.call (gcd, (x, y\_sub\_x,), "tmp") bldr.ret (recur\_1) + +bldr.position\_at\_end (cond\_false\_2) x\_sub\_y = bldr.sub (x, y, +"x\_sub\_y") recur\_2 = bldr.call (gcd, (x\_sub\_y, y,), "tmp") bldr.ret +(recur\_2) + +print(module) {% endhighlight %} diff --git a/docs/source/doc/functions.md b/docs/source/doc/functions.md deleted file mode 100644 index 0f88262..0000000 --- a/docs/source/doc/functions.md +++ /dev/null @@ -1,198 +0,0 @@ ---- -layout: page -title: Functions ---- - -Functions are represented by [llvm.core.Function][] objects. -They are contained within modules, and can be created either with the method -`module_obj.add_function` or the static constructor `Function.new`. -References to functions already present in a module can be retrieved via -`module.get_function_named` or by the static constructor method -`Function.get`. All functions in a module can be enumerated by iterating -over `module_obj.functions`. - -{% highlight python %} -# create a type, representing functions that take an integer and return -# a floating point value. -ft = Type.function( Type.float(), [ Type.int() ] ) - -# create a function of this type -f1 = module_obj.add_function(ft, "func1") - -# or equivalently, like this: -f2 = Function.new(module_obj, ft, "func2") - -# get a reference to an existing function -f3 = module_obj.get_function_named("func3") - -# or like this: -f4 = Function.get(module_obj, "func4") - -# list all function names in a module -for f in module_obj.functions: - print f.name -{% endhighlight %} - - -# Intrinsic - -References to intrinsic functions can be got via the static constructor -`intrinsic`. This returns a `Function` object, calling which is -equivalent to invoking the intrinsic. The `intrinsic` method has to be -called with a module object, an intrinsic ID (which is a numeric -constant) and a list of the types of arguments (which LLVM uses to -resolve overloaded intrinsic functions). - -{% highlight python %} -# get a reference to the llvm.bswap intrinsic -bswap = Function.intrinsic(mod, INTR_BSWAP, [Type.int()]) - -# call it -builder.call(bswap, [value]) -{% endhighlight %} - -Here, the constant `INTR_BSWAP`, available from `llvm.core`, represents the -LLVM intrinsic [llvm.bswap](http://www.llvm.org/docs/LangRef.html#int_bswap). -The `[Type.int()]` selects the version of `llvm.bswap` that has a single 32-bit -integer argument. The list of intrinsic IDs defined as integer constants -in `llvm.core`. These are: - -{% include intrinsics.csv %} - -There are also target-specific intrinsics (which correspond to that -target's CPU instructions) available, but are omitted here for brevity. -Full list can be seen from -[_intrinsic_ids.py](https://github.com/numba/llvm-py/blob/master/llvm/_intrinsic_ids.py). -See the [LLVM Language Reference](http://www.llvm.org/docs/LangRef.html) -for more information on the intrinsics, and the -[test](https://github.com/numba/llvm-py/blob/master/test/intrinsic.py) -directory in the source distribution for more examples. The intrinsic ID -can be retrieved from a function object with the read-only property -`intrinsic_id`. - -> **Auto-generation of Intrinsic IDs** -> -> -> A script (tool/intrgen.py in source tree) generates the intrinsic IDs -> automatically. This is necessary when compiling llvm-py with a different -> version of LLVM. - -# Calling Convention # {#callconv} -The function's calling convention can be set using the -`calling_convention` property. The following (integer) constants defined -in `llvm.core` can be used as values: - -Value | Equivalent LLVM Assembly Keyword | -------|----------------------------------| -`CC_C` | `ccc` | -`CC_FASTCALL` | `fastcc` | -`CC_COLDCALL` | `coldcc` | -`CC_X86_STDCALL` | `x86_stdcallcc` | -`CC_X86_FASTCALL` | `x86_fastcallcc` | - -See the [LLVM docs](http://www.llvm.org/docs/LangRef.html#callingconv) for -more information on each. Backend-specific numbered conventions can be -directly passed as integers. - -An arbitrary string identifying which garbage collector to use can be -set or got with the property `collector`. - -The value objects corresponding to the arguments of a function can be -got using the read-only property `args`. These can be iterated over, and -also be indexed via integers. An example: - -{% highlight python %} -# list all argument names and types -for arg in fn.args: - print arg.name, "of type", arg.type - -# change the name of the first argument -fn.args[0].name = "objptr" -{% endhighlight %} - -Basic blocks (see later) are contained within functions. When newly -created, a function has no basic blocks. They have to be added -explicitly, using the `append_basic_block` method, which adds a new, -empty basic block as the last one in the function. The first basic block -of the function can be retrieved using the `get_entry_basic_block` -method. The existing basic blocks can be enumerated by iterating over -using the read-only property `basic_blocks`. The number of basic blocks -can be got via `basic_block_count` method. Note that -`get_entry_basic_block` is slightly faster than `basic_blocks[0]` and so -is `basic_block_count`, over `len(f.basic_blocks)`. - -{% highlight python %} -# add a basic block -b1 = fn.append_basic_block("entry") - -# get the first one -b2 = fn.get_entry_basic_block() -b2 = fn.basic_mdblocks[0] # slower than previous method - -# print names of all basic blocks -for b in fn.basic_blocks: - print b.name - -# get number of basic blocks -n = fn.basic_block_count -n = len(fn.basic_blocks) # slower than previous method -{% endhighlight %} - -Functions can be deleted using the method `delete`. This deletes them -from their containing module. All references to the function object -should be dropped after `delete` has been called. - -Functions can be verified with the `verify` method. Note that this may -not work properly (aborts on errors). - -# Function Attributes # {#fnattr} -Function attributes, as documented -[here](http://www.llvm.org/docs/LangRef.html#fnattrs), can be -set on functions using the methods `add_attribute` and -`remove_attribute`. The following values may be used to refer to the -LLVM attributes: - - -Value | Equivalent LLVM Assembly Keyword | -------|----------------------------------| -`ATTR_ALWAYS_INLINE`|`alwaysinline` | -`ATTR_INLINE_HINT`|`inlinehint` | -`ATTR_NO_INLINE`|`noinline` | -`ATTR_OPTIMIZE_FOR_SIZE`|`optsize` | -`ATTR_NO_RETURN`|`noreturn` | -`ATTR_NO_UNWIND`|`nounwind` | -`ATTR_READ_NONE`|`readnone` | -`ATTR_READONLY`|`readonly` | -`ATTR_STACK_PROTECT`|`ssp` | -`ATTR_STACK_PROTECT_REQ`|`sspreq` | -`ATTR_NO_REDZONE`|`noredzone` | -`ATTR_NO_IMPLICIT_FLOAT`|`noimplicitfloat` | -`ATTR_NAKED`|`naked` | - - -Here is how attributes can be set and removed: - -{% highlight python %} -# create a function -ti = Type.int(32) -tf = Type.function(ti, [ti, ti]) -m = Module.new('mod') -f = m.add_function(tf, 'sum') -print f -# declare i32 @sum(i32, i32) - -# add a couple of attributes -f.add_attribute(ATTR_NO_UNWIND) -f.add_attribute(ATTR_READONLY) -print f -# declare i32 @sum(i32, i32) nounwind readonly -{% endhighlight %} - -**Related Links** - -[llvm.core.Function][], -[llvm.core.Argument][] - -[llvm.core.Function]: llvm.core.Function.html -[llvm.core.Argument]: llvm.core.Argument.html - diff --git a/docs/source/doc/functions.rst b/docs/source/doc/functions.rst new file mode 100644 index 0000000..97ce73b --- /dev/null +++ b/docs/source/doc/functions.rst @@ -0,0 +1,200 @@ ++--------------------+ +| layout: page | ++--------------------+ +| title: Functions | ++--------------------+ + +Functions are represented by +`llvm.core.Function `_ objects. They are +contained within modules, and can be created either with the method +``module_obj.add_function`` or the static constructor ``Function.new``. +References to functions already present in a module can be retrieved via +``module.get_function_named`` or by the static constructor method +``Function.get``. All functions in a module can be enumerated by +iterating over ``module_obj.functions``. + +{% highlight python %} # create a type, representing functions that take +an integer and return # a floating point value. ft = Type.function( +Type.float(), [ Type.int() ] ) + +create a function of this type +============================== + +f1 = module\_obj.add\_function(ft, "func1") + +or equivalently, like this: +=========================== + +f2 = Function.new(module\_obj, ft, "func2") + +get a reference to an existing function +======================================= + +f3 = module\_obj.get\_function\_named("func3") + +or like this: +============= + +f4 = Function.get(module\_obj, "func4") + +list all function names in a module +=================================== + +for f in module\_obj.functions: print f.name {% endhighlight %} + +Intrinsic +========= + +References to intrinsic functions can be got via the static constructor +``intrinsic``. This returns a ``Function`` object, calling which is +equivalent to invoking the intrinsic. The ``intrinsic`` method has to be +called with a module object, an intrinsic ID (which is a numeric +constant) and a list of the types of arguments (which LLVM uses to +resolve overloaded intrinsic functions). + +{% highlight python %} # get a reference to the llvm.bswap intrinsic +bswap = Function.intrinsic(mod, INTR\_BSWAP, [Type.int()]) + +call it +======= + +builder.call(bswap, [value]) {% endhighlight %} + +Here, the constant ``INTR_BSWAP``, available from ``llvm.core``, +represents the LLVM intrinsic +`llvm.bswap `_. The +``[Type.int()]`` selects the version of ``llvm.bswap`` that has a single +32-bit integer argument. The list of intrinsic IDs defined as integer +constants in ``llvm.core``. These are: + +{% include intrinsics.csv %} + +There are also target-specific intrinsics (which correspond to that +target's CPU instructions) available, but are omitted here for brevity. +Full list can be seen from +[*intrinsic\_ids.py](https://github.com/numba/llvm-py/blob/master/llvm/*\ intrinsic\_ids.py). +See the `LLVM Language +Reference `_ for more information +on the intrinsics, and the +`test `_ +directory in the source distribution for more examples. The intrinsic ID +can be retrieved from a function object with the read-only property +``intrinsic_id``. + + **Auto-generation of Intrinsic IDs** + + A script (tool/intrgen.py in source tree) generates the intrinsic + IDs automatically. This is necessary when compiling llvm-py with a + different version of LLVM. + +Calling Convention # {#callconv} +================================ + +The function's calling convention can be set using the +``calling_convention`` property. The following (integer) constants +defined in ``llvm.core`` can be used as values: + +Value \| Equivalent LLVM Assembly Keyword \| +------\|----------------------------------\| ``CC_C`` \| ``ccc`` \| +``CC_FASTCALL`` \| ``fastcc`` \| ``CC_COLDCALL`` \| ``coldcc`` \| +``CC_X86_STDCALL`` \| ``x86_stdcallcc`` \| ``CC_X86_FASTCALL`` \| +``x86_fastcallcc`` \| + +See the `LLVM docs `_ +for more information on each. Backend-specific numbered conventions can +be directly passed as integers. + +An arbitrary string identifying which garbage collector to use can be +set or got with the property ``collector``. + +The value objects corresponding to the arguments of a function can be +got using the read-only property ``args``. These can be iterated over, +and also be indexed via integers. An example: + +{% highlight python %} # list all argument names and types for arg in +fn.args: print arg.name, "of type", arg.type + +change the name of the first argument +===================================== + +fn.args[0].name = "objptr" {% endhighlight %} + +Basic blocks (see later) are contained within functions. When newly +created, a function has no basic blocks. They have to be added +explicitly, using the ``append_basic_block`` method, which adds a new, +empty basic block as the last one in the function. The first basic block +of the function can be retrieved using the ``get_entry_basic_block`` +method. The existing basic blocks can be enumerated by iterating over +using the read-only property ``basic_blocks``. The number of basic +blocks can be got via ``basic_block_count`` method. Note that +``get_entry_basic_block`` is slightly faster than ``basic_blocks[0]`` +and so is ``basic_block_count``, over ``len(f.basic_blocks)``. + +{% highlight python %} # add a basic block b1 = +fn.append\_basic\_block("entry") + +get the first one +================= + +b2 = fn.get\_entry\_basic\_block() b2 = fn.basic\_mdblocks[0] # slower +than previous method + +print names of all basic blocks +=============================== + +for b in fn.basic\_blocks: print b.name + +get number of basic blocks +========================== + +n = fn.basic\_block\_count n = len(fn.basic\_blocks) # slower than +previous method {% endhighlight %} + +Functions can be deleted using the method ``delete``. This deletes them +from their containing module. All references to the function object +should be dropped after ``delete`` has been called. + +Functions can be verified with the ``verify`` method. Note that this may +not work properly (aborts on errors). + +Function Attributes # {#fnattr} +=============================== + +Function attributes, as documented +`here `_, can be set on +functions using the methods ``add_attribute`` and ``remove_attribute``. +The following values may be used to refer to the LLVM attributes: + +Value \| Equivalent LLVM Assembly Keyword \| +------\|----------------------------------\| +``ATTR_ALWAYS_INLINE``\ \|\ ``alwaysinline`` \| +``ATTR_INLINE_HINT``\ \|\ ``inlinehint`` \| +``ATTR_NO_INLINE``\ \|\ ``noinline`` \| +``ATTR_OPTIMIZE_FOR_SIZE``\ \|\ ``optsize`` \| +``ATTR_NO_RETURN``\ \|\ ``noreturn`` \| +``ATTR_NO_UNWIND``\ \|\ ``nounwind`` \| +``ATTR_READ_NONE``\ \|\ ``readnone`` \| +``ATTR_READONLY``\ \|\ ``readonly`` \| +``ATTR_STACK_PROTECT``\ \|\ ``ssp`` \| +``ATTR_STACK_PROTECT_REQ``\ \|\ ``sspreq`` \| +``ATTR_NO_REDZONE``\ \|\ ``noredzone`` \| +``ATTR_NO_IMPLICIT_FLOAT``\ \|\ ``noimplicitfloat`` \| +``ATTR_NAKED``\ \|\ ``naked`` \| + +Here is how attributes can be set and removed: + +{% highlight python %} # create a function ti = Type.int(32) tf = +Type.function(ti, [ti, ti]) m = Module.new('mod') f = +m.add\_function(tf, 'sum') print f # declare i32 @sum(i32, i32) + +add a couple of attributes +========================== + +f.add\_attribute(ATTR\_NO\_UNWIND) f.add\_attribute(ATTR\_READONLY) +print f # declare i32 @sum(i32, i32) nounwind readonly {% endhighlight +%} + +**Related Links** + +`llvm.core.Function `_, +`llvm.core.Argument `_ diff --git a/docs/source/doc/kaleidoscope/PythonLangImpl1.md b/docs/source/doc/kaleidoscope/PythonLangImpl1.md deleted file mode 100644 index 4502432..0000000 --- a/docs/source/doc/kaleidoscope/PythonLangImpl1.md +++ /dev/null @@ -1,330 +0,0 @@ ---- -layout: page -title: "Kaleidoscope: Chapter 1" ---- - -# Tutorial Introduction and the Lexer - -Written by [Chris Lattner](mailto:sabre@nondot.org) -and [Max Shawabkeh](http://max99x.com) - -**Chapter 1** - - -* This will become a table of contents (this text will be scraped). -{:toc} - -[**Chapter 2: Implementing a Parser and AST**](PythonLangImpl2.html) - -# Introduction - -Welcome to the "Implementing a language with LLVM" tutorial. This tutorial -runs through the implementation of a simple language, showing how fun and -easy it can be. This tutorial will get you up and started as well as help to -build a framework you can extend to other languages. The code in this -tutorial can also be used as a playground to hack on other LLVM specific -things. - -It is useful to point out ahead of time that this tutorial is really about -teaching compiler techniques and LLVM specifically, *not* about teaching -modern and sane software engineering principles. In practice, this means that -we'll take a number of shortcuts to simplify the exposition. If you dig in and -use the code as a basis for future projects, fixing its deficiencies shouldn't -be hard. - - -We've tried to put this tutorial together in a way that makes chapters easy -to skip over if you are already familiar with or are uninterested in the -various pieces. The structure of the tutorial is: - -* **[Chapter 1](#language): Introduction to the Kaleidoscope language, -and the definition of its Lexer** -- This shows where we are going -and the basic functionality that we want it to do. In order to make this -tutorial maximally understandable and hackable, we choose to implement -everything in Python instead of using lexer and parser generators. LLVM -obviously works just fine with such tools, feel free to use one if you prefer. - -* **[Chapter 2](PythonLangImpl2.html): Implementing a Parser and AST** -- -With the lexer in place, we can talk about parsing techniques and -basic AST construction. This tutorial describes recursive descent parsing and -operator precedence parsing. Nothing in Chapters 1 or 2 is LLVM-specific, -the code doesn't even import the LLVM modules at this point. :) - -* **[Chapter 3](PythonLangImpl3.html): Code generation to LLVM IR** -- With -the AST ready, we can show off how easy generation of LLVM IR really is. - -* **[Chapter 4](PythonLangImpl4.html): Adding JIT and Optimizer support** -- -Because a lot of people are interested in using LLVM as a JIT, -we'll dive right into it and show you the 3 lines it takes to add JIT support. -LLVM is also useful in many other ways, but this is one simple and "sexy" way -to shows off its power. :) - -* **[Chapter 5](PythonLangImpl5.html): Extending the Language: Control Flow** - -- With the language up and running, we show how to extend it -with control flow operations (if/then/else and a 'for' loop). This gives us a -chance to talk about simple SSA construction and control flow. - -* **[Chapter 6](PythonLangImpl6.html): Extending the Language: -User-defined Operators** -- This is a silly but fun chapter that talks about -extending the language to let the user program define their own arbitrary -unary and binary operators (with assignable precedence!). This lets us build -a significant piece of the "language" as library routines. - -* **[Chapter 7](PythonLangImpl7.html): Extending the Language: -Mutable Variables** -- This chapter talks about adding user-defined local -variables along with an assignment operator. The interesting part about this -is how easy and trivial it is to construct SSA form in LLVM: no, LLVM does -*not* require your front-end to construct SSA form! - -* **[Chapter 8](PythonLangImpl8.html): Conclusion and other -useful LLVM tidbits** -- This chapter wraps up the series by talking about -potential ways to extend the language, but also includes a bunch of pointers to -info about "special topics" like adding garbage collection support, exceptions, -debugging, support for "spaghetti stacks", and a bunch of other tips and -tricks. - -By the end of the tutorial, we'll have written a bit less than 540 lines of -non-comment, non-blank, lines of code. With this small amount of code, we'll -have built up a very reasonable compiler for a non-trivial language including -a hand-written lexer, parser, AST, as well as code generation support with a JIT -compiler. While other systems may have interesting "hello world" tutorials, -I think the breadth of this tutorial is a great testament to the strengths of -LLVM and why you should consider it if you're interested in language or compiler -design. - -A note about this tutorial: we expect you to extend the language and play -with it on your own. Take the code and go crazy hacking away at it, compilers -don't need to be scary creatures - it can be a lot of fun to play with -languages! - -* * * - -# The Basic Language # {#language} - -This tutorial will be illustrated with a toy language that we'll call -"[Kaleidoscope](http://en.wikipedia.org/wiki/Kaleidoscope)" (derived -from "meaning beautiful, form, and view"). -Kaleidoscope is a procedural language that allows you to define functions, use -conditionals, math, etc. Over the course of the tutorial, we'll extend -Kaleidoscope to support the if/then/else construct, a for loop, user defined -operators, JIT compilation with a simple command line interface, etc. - -Because we want to keep things simple, the only datatype in Kaleidoscope is a -64-bit floating point type. As such, all values are implicitly double precision -and the language doesn't require type declarations. This gives the language a -very nice and simple syntax. For example, the following simple example computes -[Fibonacci numbers](http://en.wikipedia.org/wiki/Fibonacci_number): - -{% highlight python %} -# Compute the x'th fibonacci number. -def fib(x) - if x < 3 then - 1 - else - fib(x-1)+fib(x-2) - -# This expression will compute the 40th number. -fib(40) -{% endhighlight %} - - -We also allow Kaleidoscope to call into standard library functions (the LLVM -JIT makes this completely trivial). This means that you can use the 'extern' -keyword to define a function before you use it (this is also useful for mutually -recursive functions). For example: - -{% highlight python %} -extern sin(arg); -extern cos(arg); -extern atan2(arg1 arg2); - -atan2(sin(0.4), cos(42)) -{% endhighlight %} - - -A more interesting example is included in Chapter 6 where we write a little -Kaleidoscope application that [displays](PythonLangImpl6.html#example) -a Mandelbrot Set at various levels of magnification. - -Lets dive into the implementation of this language! - -* * * - -# The Lexer # {#lexer} - - -When it comes to implementing a language, the first thing needed is -the ability to process a text file and recognize what it says. -The traditional way to do this is to use a -[lexer](http://en.wikipedia.org/wiki/Lexical_analysis)" (aka 'scanner') -to break the input up into "tokens". Each token returned by the lexer includes -a token type and potentially some metadata (e.g. the numeric value of a number). -First, we define the possibilities: - - -{% highlight python %} -# The lexer yields one of these types for each token. -class EOFToken(object): - pass - -class DefToken(object): - pass - -class ExternToken(object): - pass - -class IdentifierToken(object): - def __init__(self, name): self.name = name - -class NumberToken(object): - def __init__(self, value): self.value = value - -class CharacterToken(object): - def __init__(self, char): self.char = char - def __eq__(self, other): - return isinstance(other, CharacterToken) and self.char == other.char - def __ne__(self, other): return not self == other -{% endhighlight %} - - -Each token yielded by our lexer will be of one of the above types. For simple -tokens that are always the same, like the "def" keyword, the lexer will yield -`DefToken()`>. Identifiers, numbers and characters, on the other -hand, have extra data, so when the lexer encounteres the number 123.45, it will -emit it as `NumberToken(123.45)`. An identifier `foo` will be -emitted as `IdentifierToken('foo')`. And finally, an unknown character -like '+' will be returned as `CharacterToken('+')`. You may notice that -we overload the equality and inequality operators for the characters; this will -later simplify character comparisons in the parser code. - -The actual implementation of the lexer is a single function called `Tokenize`, -which takes a string and -[yields](http://docs.python.org/reference/simple_stmts.html#the-yield-statement) -tokens. For simplicity, we will use -[regular expressions](http://docs.python.org/library/re.html) -to parse out the tokens. This is terribly inefficient, but -perfectly sufficient for our needs. - -First, we define the regular expressions for our tokens. Numbers and strings -of digits, optionally followed by a period and another string of digits. -Identifiers (and keywords) are alphanumeric string starting with a letter and -comments are anything between a hash (`#`) and the end of the line. - - -{% highlight python %} -import re - -... - -# Regular expressions that tokens and comments of our language. -REGEX_NUMBER = re.compile('[0-9]+(?:\.[0-9]+)?') -REGEX_IDENTIFIER = re.compile('[a-zA-Z][a-zA-Z0-9]*') -REGEX_COMMENT = re.compile('#.*') - -{% endhighlight %} - -Next, let's start defining the `Tokenize` function itself. The first -thing we need to do is set up a loop that scans the string, while ignoring -whitespace between tokens: - - -{% highlight python %} -def Tokenize(string): - while string: - # Skip whitespace. - if string[0].isspace(): - string = string[1:] - continue - - ... - -{% endhighlight %} - -Next we want to find out what the next token is. For this we run the regexes -we defined above on the remainder of the string. To simplify the rest of the -code, we run all three regexes each time. As mentioned above, inefficiencies are -ignored for the purpose of this tutorial: - - -{% highlight python %} - # Run regexes. - comment_match = REGEX_COMMENT.match(string) - number_match = REGEX_NUMBER.match(string) - identifier_match = REGEX_IDENTIFIER.match(string) -{% endhighlight %} - - -Now se check if any of the regexes matched. For comments, we simply -ignore the captured match: - - -{% highlight python %} - # Check if any of the regexes matched and yield the appropriate result. - if comment_match: - comment = comment_match.group(0) - string = string[len(comment):] -{% endhighlight python %} - -For numbers, we yield the captured match, converted to a float and tagged -with the appropriate token type: - - - -{% highlight python %} - elif number_match: - number = number_match.group(0) - yield NumberToken(float(number)) - string = string[len(number):] -{% endhighlight %} - -The identifier case is a little more complex. We have to check for keywords -to decide whether we have captured an identifier or a keyword: - - -{% highlight python %} - elif identifier_match: - identifier = identifier_match.group(0) - # Check if we matched a keyword. - if identifier == 'def': - yield DefToken() - elif identifier == 'extern': - yield ExternToken() - else: - yield IdentifierToken(identifier) - string = string[len(identifier):] -{% endhighlight %} - -Finally, if we haven't recognized a comment, a number of an identifier, we -yield the current character as an "unknown character" token. This is used, for -example, for operators like `+` or `*`: - - -{% highlight python %} - else: - # Yield the unknown character. - yield CharacterToken(string[0]) - string = string[1:] -{% endhighlight %} - -Once we're done with the loop, we return a final end-of-file token: - - -{% highlight python %} - yield EOFToken() -{% endhighlight %} - - -With this, we have the complete lexer for the basic Kaleidoscope language -(the [full code listing](PythonLangImpl2.html#code) for the Lexer is -available in the [next chapter](PythonLangImpl2.html) of the -tutorial). Next we'll [build a simple parser that -uses this to build an Abstract Syntax Tree](PythonLangImpl2.html). -When we have that, we'll -include a driver so that you can use the lexer and parser together. - -* * * - -**[Next: Implementing a Parser and AST](PythonLangImpl2.html)** - - - diff --git a/docs/source/doc/kaleidoscope/PythonLangImpl1.rst b/docs/source/doc/kaleidoscope/PythonLangImpl1.rst new file mode 100644 index 0000000..4bbb81f --- /dev/null +++ b/docs/source/doc/kaleidoscope/PythonLangImpl1.rst @@ -0,0 +1,286 @@ ++------------------------------------+ +| layout: page | ++------------------------------------+ +| title: "Kaleidoscope: Chapter 1" | ++------------------------------------+ + +Tutorial Introduction and the Lexer +=================================== + +Written by `Chris Lattner `_ and `Max +Shawabkeh `_ + +**Chapter 1** + +- This will become a table of contents (this text will be scraped). + {:toc} + +`**Chapter 2: Implementing a Parser and AST** `_ + +Introduction +============ + +Welcome to the "Implementing a language with LLVM" tutorial. This +tutorial runs through the implementation of a simple language, showing +how fun and easy it can be. This tutorial will get you up and started as +well as help to build a framework you can extend to other languages. The +code in this tutorial can also be used as a playground to hack on other +LLVM specific things. + +It is useful to point out ahead of time that this tutorial is really +about teaching compiler techniques and LLVM specifically, *not* about +teaching modern and sane software engineering principles. In practice, +this means that we'll take a number of shortcuts to simplify the +exposition. If you dig in and use the code as a basis for future +projects, fixing its deficiencies shouldn't be hard. + +We've tried to put this tutorial together in a way that makes chapters +easy to skip over if you are already familiar with or are uninterested +in the various pieces. The structure of the tutorial is: + +- **`Chapter 1 <#language>`_: Introduction to the Kaleidoscope + language, and the definition of its Lexer** -- This shows where we + are going and the basic functionality that we want it to do. In order + to make this tutorial maximally understandable and hackable, we + choose to implement everything in Python instead of using lexer and + parser generators. LLVM obviously works just fine with such tools, + feel free to use one if you prefer. + +- **`Chapter 2 `_: Implementing a Parser and + AST** -- With the lexer in place, we can talk about parsing + techniques and basic AST construction. This tutorial describes + recursive descent parsing and operator precedence parsing. Nothing in + Chapters 1 or 2 is LLVM-specific, the code doesn't even import the + LLVM modules at this point. :) + +- **`Chapter 3 `_: Code generation to LLVM IR** + -- With the AST ready, we can show off how easy generation of LLVM IR + really is. + +- **`Chapter 4 `_: Adding JIT and Optimizer + support** -- Because a lot of people are interested in using LLVM as + a JIT, we'll dive right into it and show you the 3 lines it takes to + add JIT support. LLVM is also useful in many other ways, but this is + one simple and "sexy" way to shows off its power. :) + +- **`Chapter 5 `_: Extending the Language: + Control Flow** -- With the language up and running, we show how to + extend it with control flow operations (if/then/else and a 'for' + loop). This gives us a chance to talk about simple SSA construction + and control flow. + +- **`Chapter 6 `_: Extending the Language: + User-defined Operators** -- This is a silly but fun chapter that + talks about extending the language to let the user program define + their own arbitrary unary and binary operators (with assignable + precedence!). This lets us build a significant piece of the + "language" as library routines. + +- **`Chapter 7 `_: Extending the Language: + Mutable Variables** -- This chapter talks about adding user-defined + local variables along with an assignment operator. The interesting + part about this is how easy and trivial it is to construct SSA form + in LLVM: no, LLVM does *not* require your front-end to construct SSA + form! + +- **`Chapter 8 `_: Conclusion and other useful + LLVM tidbits** -- This chapter wraps up the series by talking about + potential ways to extend the language, but also includes a bunch of + pointers to info about "special topics" like adding garbage + collection support, exceptions, debugging, support for "spaghetti + stacks", and a bunch of other tips and tricks. + +By the end of the tutorial, we'll have written a bit less than 540 lines +of non-comment, non-blank, lines of code. With this small amount of +code, we'll have built up a very reasonable compiler for a non-trivial +language including a hand-written lexer, parser, AST, as well as code +generation support with a JIT compiler. While other systems may have +interesting "hello world" tutorials, I think the breadth of this +tutorial is a great testament to the strengths of LLVM and why you +should consider it if you're interested in language or compiler design. + +A note about this tutorial: we expect you to extend the language and +play with it on your own. Take the code and go crazy hacking away at it, +compilers don't need to be scary creatures - it can be a lot of fun to +play with languages! + +-------------- + +The Basic Language # {#language} +================================ + +This tutorial will be illustrated with a toy language that we'll call +"`Kaleidoscope `_\ " (derived +from "meaning beautiful, form, and view"). Kaleidoscope is a procedural +language that allows you to define functions, use conditionals, math, +etc. Over the course of the tutorial, we'll extend Kaleidoscope to +support the if/then/else construct, a for loop, user defined operators, +JIT compilation with a simple command line interface, etc. + +Because we want to keep things simple, the only datatype in Kaleidoscope +is a 64-bit floating point type. As such, all values are implicitly +double precision and the language doesn't require type declarations. +This gives the language a very nice and simple syntax. For example, the +following simple example computes `Fibonacci +numbers `_: + +{% highlight python %} # Compute the x'th fibonacci number. def fib(x) +if x < 3 then 1 else fib(x-1)+fib(x-2) + +This expression will compute the 40th number. +============================================= + +fib(40) {% endhighlight %} + +We also allow Kaleidoscope to call into standard library functions (the +LLVM JIT makes this completely trivial). This means that you can use the +'extern' keyword to define a function before you use it (this is also +useful for mutually recursive functions). For example: + +{% highlight python %} extern sin(arg); extern cos(arg); extern +atan2(arg1 arg2); + +atan2(sin(0.4), cos(42)) {% endhighlight %} + +A more interesting example is included in Chapter 6 where we write a +little Kaleidoscope application that +`displays `_ a Mandelbrot Set at various +levels of magnification. + +Lets dive into the implementation of this language! + +-------------- + +The Lexer # {#lexer} +==================== + +When it comes to implementing a language, the first thing needed is the +ability to process a text file and recognize what it says. The +traditional way to do this is to use a +`lexer `_" (aka +'scanner') to break the input up into "tokens". Each token returned by +the lexer includes a token type and potentially some metadata (e.g. the +numeric value of a number). First, we define the possibilities: + +{% highlight python %} # The lexer yields one of these types for each +token. class EOFToken(object): pass + +class DefToken(object): pass + +class ExternToken(object): pass + +class IdentifierToken(object): def **init**\ (self, name): self.name = +name + +class NumberToken(object): def **init**\ (self, value): self.value = +value + +class CharacterToken(object): def **init**\ (self, char): self.char = +char def **eq**\ (self, other): return isinstance(other, CharacterToken) +and self.char == other.char def **ne**\ (self, other): return not self +== other {% endhighlight %} + +Each token yielded by our lexer will be of one of the above types. For +simple tokens that are always the same, like the "def" keyword, the +lexer will yield ``DefToken()``>. Identifiers, numbers and characters, +on the other hand, have extra data, so when the lexer encounteres the +number 123.45, it will emit it as ``NumberToken(123.45)``. An identifier +``foo`` will be emitted as ``IdentifierToken('foo')``. And finally, an +unknown character like '+' will be returned as ``CharacterToken('+')``. +You may notice that we overload the equality and inequality operators +for the characters; this will later simplify character comparisons in +the parser code. + +The actual implementation of the lexer is a single function called +``Tokenize``, which takes a string and +`yields `_ +tokens. For simplicity, we will use `regular +expressions `_ to parse out the +tokens. This is terribly inefficient, but perfectly sufficient for our +needs. + +First, we define the regular expressions for our tokens. Numbers and +strings of digits, optionally followed by a period and another string of +digits. Identifiers (and keywords) are alphanumeric string starting with +a letter and comments are anything between a hash (``#``) and the end of +the line. + +{% highlight python %} import re + +... + +Regular expressions that tokens and comments of our language. +============================================================= + +REGEX\_NUMBER = re.compile('[0-9]+(?:.[0-9]+)?') REGEX\_IDENTIFIER = +re.compile('[a-zA-Z][a-zA-Z0-9]\ *') REGEX\_COMMENT = re.compile('#.*') + +{% endhighlight %} + +Next, let's start defining the ``Tokenize`` function itself. The first +thing we need to do is set up a loop that scans the string, while +ignoring whitespace between tokens: + +{% highlight python %} def Tokenize(string): while string: # Skip +whitespace. if string[0].isspace(): string = string[1:] continue + +:: + + ... + +{% endhighlight %} + +Next we want to find out what the next token is. For this we run the +regexes we defined above on the remainder of the string. To simplify the +rest of the code, we run all three regexes each time. As mentioned +above, inefficiencies are ignored for the purpose of this tutorial: + +{% highlight python %} # Run regexes. comment\_match = +REGEX\_COMMENT.match(string) number\_match = REGEX\_NUMBER.match(string) +identifier\_match = REGEX\_IDENTIFIER.match(string) {% endhighlight %} + +Now se check if any of the regexes matched. For comments, we simply +ignore the captured match: + +{% highlight python %} # Check if any of the regexes matched and yield +the appropriate result. if comment\_match: comment = +comment\_match.group(0) string = string[len(comment):] {% endhighlight +python %} + +For numbers, we yield the captured match, converted to a float and +tagged with the appropriate token type: + +{% highlight python %} elif number\_match: number = +number\_match.group(0) yield NumberToken(float(number)) string = +string[len(number):] {% endhighlight %} + +The identifier case is a little more complex. We have to check for +keywords to decide whether we have captured an identifier or a keyword: + +{% highlight python %} elif identifier\_match: identifier = +identifier\_match.group(0) # Check if we matched a keyword. if +identifier == 'def': yield DefToken() elif identifier == 'extern': yield +ExternToken() else: yield IdentifierToken(identifier) string = +string[len(identifier):] {% endhighlight %} + +Finally, if we haven't recognized a comment, a number of an identifier, +we yield the current character as an "unknown character" token. This is +used, for example, for operators like ``+`` or ``*``: + +{% highlight python %} else: # Yield the unknown character. yield +CharacterToken(string[0]) string = string[1:] {% endhighlight %} + +Once we're done with the loop, we return a final end-of-file token: + +{% highlight python %} yield EOFToken() {% endhighlight %} + +With this, we have the complete lexer for the basic Kaleidoscope +language (the `full code listing `_ for the +Lexer is available in the `next chapter `_ of the +tutorial). Next we'll `build a simple parser that uses this to build an +Abstract Syntax Tree `_. When we have that, we'll +include a driver so that you can use the lexer and parser together. + +-------------- + +**`Next: Implementing a Parser and AST `_** diff --git a/docs/source/doc/kaleidoscope/PythonLangImpl2.md b/docs/source/doc/kaleidoscope/PythonLangImpl2.md deleted file mode 100644 index 143894c..0000000 --- a/docs/source/doc/kaleidoscope/PythonLangImpl2.md +++ /dev/null @@ -1,998 +0,0 @@ ---- -layout: page -title: "Kaleidoscope: Chapter 2" ---- - -# Implementing a Parser and AST - -Written by [Chris Lattner](mailto:sabre@nondot.org) -and [Max Shawabkeh](http://max99x.com) - - -**Chapter 2** - - -* This will become a table of contents (this text will be scraped). -{:toc} - - -**[Chapter 3: Code generation to LLVM IR](PythonLangImpl3.html)** - - -# Introduction # {#intro} - -Welcome to Chapter 2 of the -[Implementing a language with LLVM](http://www.llvm.org/docs/tutorial/index.html) -tutorial. -This chapter shows you how to use the lexer, built in -[Chapter 1](PythonLangImpl1.html), to build a full -[parser](http://en.wikipedia.org/wiki/Parsing) for -our Kaleidoscope language. Once we have a parser, we'll define and build an -[Abstract Syntax Tree](http://en.wikipedia.org/wiki/Abstract_syntax_tree) -(AST). - -The parser we will build uses a combination of [Recursive Descent -Parsing](http://en.wikipedia.org/wiki/Recursive_descent_parser) and -[Operator-Precedence Parsing](http://en.wikipedia.org/wiki/Operator-precedence_parser) -to parse the Kaleidoscope language (the latter for -binary expressions and the former for everything else). Before we get to -parsing though, lets talk about the output of the parser: the Abstract Syntax -Tree. - -* * * - - -# The Abstract Syntax Tree (AST) # {#ast} - -The AST for a program captures its behavior in such a way that it is easy for -later stages of the compiler (e.g. code generation) to interpret. We basically -want one object for each construct in the language, and the AST should closely -model the language. In Kaleidoscope, we have expressions, a prototype, and a -function object. We'll start with expressions first: - -{% highlight python %} -# Base class for all expression nodes. -class ExpressionNode(object): - pass - -# Expression class for numeric literals like "1.0". -class NumberExpressionNode(ExpressionNode): - def __init__(self, value): - self.value = value - -{% endhighlight %} - -The code above shows the definition of the base ExpressionNode class and one -subclass which we use for numeric literals. The important thing to note about -this code is that the NumberExpressionNode class captures the numeric value of -the literal as an instance variable. This allows later phases of the compiler to -know what the stored numeric value is. - -Right now we only create the AST, so there are no useful methods on them. -It would be very easy to add a virtual method to pretty print the code, for -example. Here are the other expression AST node definitions that we'll use -in the basic form of the Kaleidoscope language: - -{% highlight python %} -# Expression class for referencing a variable, like "a". -class VariableExpressionNode(ExpressionNode): - def __init__(self, name): - self.name = name - -# Expression class for a binary operator. -class BinaryOperatorExpressionNode(ExpressionNode): - def __init__(self, operator, left, right): - self.operator = operator - self.left = left - self.right = right - -# Expression class for function calls. -class CallExpressionNode(ExpressionNode): - def __init__(self, callee, args): - self.callee = callee - self.args = args -{% endhighlight %} - -This is all (intentionally) rather straight-forward: variables capture the -variable name, binary operators capture their opcode (e.g. '+'), and calls -capture a function name as well as a list of any argument expressions. One thing -that is nice about our AST is that it captures the language features without -talking about the syntax of the language. Note that there is no discussion about -precedence of binary operators, lexical structure, etc. - -For our basic language, these are all of the expression nodes we'll define. -Because it doesn't have conditional control flow, it isn't Turing-complete; -we'll fix that in a later installment. The two things we need next are a way -to talk about the interface to a function, and a way to talk about functions -themselves: - - -{% highlight python %} -# This class represents the "prototype" for a function, which captures its name, -# and its argument names (thus implicitly the number of arguments the function -# takes). -class PrototypeNode(object): - def __init__(self, name, args): - self.name = name - self.args = args - -# This class represents a function definition itself. -class FunctionNode(object): - def __init__(self, prototype, body): - self.prototype = prototype - self.body = body -{% endhighlight %} - -In Kaleidoscope, functions are typed with just a count of their arguments. -Since all values are double precision floating point, the type of each argument -doesn't need to be stored anywhere. In a more aggressive and realistic -language, the `ExpressionNode` class would probably have a type field. - -With this scaffolding, we can now talk about parsing expressions and function -bodies in Kaleidoscope. - -* * * - - -# Parser Basics # {#parserbasics} - -Now that we have an AST to build, we need to define the parser code to build -it. The idea here is that we want to parse something like `x + y` (which -is returned as three tokens by the lexer) into an AST that could be generated -with calls like this: - -{% highlight python %} - x = VariableExpressionNode('x') - y = VariableExpressionNode('y') - result = BinaryOperatorExpressionNode('+', x, y) -{% endhighlight %} - -In order to do this, we'll start by defining a lightweight `Parser` -class with some basic helper routines: - -{% highlight python %} -class Parser(object): - - def __init__(self, tokens, binop_precedence): - self.tokens = tokens - self.binop_precedence = binop_precedence - self.Next() - - # Provide a simple token buffer. Parser.current is the current token the - # parser is looking at. Parser.Next() reads another token from the lexer and - # updates Parser.current with its results. - def Next(self): - self.current = self.tokens.next() -{% endhighlight %} - - -This implements a simple token buffer around the lexer. This allows -us to look one token ahead at what the lexer is returning. Every function in -our parser will assume that `self.current` is the current token that -needs to be parsed. Note that the first token is read as soon as the parser is -instantiated. Let us ignore the `binop_precedence` parameter for now. It -will be explained when we start [parsing binary operators](#parserbinops). - -With these basic helper functions, we can implement the first -piece of our grammar: numeric literals. - -* * * - -# Basic Expression Parsing # {#parserprimexprs} - -We start with numeric literals, because they are the simplest to process. -For each production in our grammar, we'll define a function which parses that -production. For numeric literals, we have: - -{% highlight python %} - # numberexpr ::= number - def ParseNumberExpr(self): - result = NumberExpressionNode(self.current.value) - self.Next() # consume the number. - return result -{% endhighlight %} - - -This method is very simple: it expects to be called when the current token -is a `NumberToken`. It takes the current number value, creates a -`NumberExpressionNode`, advances to the next token, and finally returns. - - -There are some interesting aspects to this. The most important one is that -this routine eats all of the tokens that correspond to the production and -returns the lexer buffer with the next token (which is not part of the grammar -production) ready to go. This is a fairly standard way to go for recursive -descent parsers. For a better example, the parenthesis operator is defined like -this: - -{% highlight python %} - # parenexpr ::= '(' expression ')' - def ParseParenExpr(self): - self.Next() # eat '('. - - contents = self.ParseExpression() - - if self.current != CharacterToken(')'): - raise RuntimeError('Expected ")".') - self.Next() # eat ')'. - - return contents -{% endhighlight %} - - -This function illustrates an interesting aspect of the parser. The function -uses recursion by calling `ParseExpression` (we will soon see that -`ParseExpression` can call `ParseParenExpr`). This is powerful -because it allows us to handle recursive grammars, and keeps each production -very simple. Note that parentheses do not cause construction of AST nodes -themselves. While we could do it this way, the most important role of -parentheses are to guide the parser and provide grouping. Once the parser -constructs the AST, parentheses are not needed. - -The next simple production is for handling variable references and function -calls: - -{% highlight python %} - # identifierexpr ::= identifier | identifier '(' expression* ')' - def ParseIdentifierExpr(self): - identifier_name = self.current.name - self.Next() # eat identifier. - - if self.current != CharacterToken('('): # Simple variable reference. - return VariableExpressionNode(identifier_name); - - # Call. - self.Next() # eat '('. - args = [] - if self.current != CharacterToken(')'): - while True: - args.append(self.ParseExpression()) - if self.current == CharacterToken(')'): - break - elif self.current != CharacterToken(','): - raise RuntimeError('Expected ")" or "," in argument list.') - self.Next() - - self.Next() # eat ')'. - return CallExpressionNode(identifier_name, args) -{% endhighlight %} - - -This routine follows the same style as the other routines. It expects to be -called if the current token is an `IdentifierToken`. It also has -recursion and error handling. One interesting aspect of this is that it uses -*look-ahead* to determine if the current identifier is a stand alone -variable reference or if it is a function call expression. It handles this by -checking to see if the token after the identifier is a '(' token, constructing -either a `VariableExpressionNode` or `CallExpressionNode` as -appropriate. - -Now that we have all of our simple expression-parsing logic in place, we can -define a helper function to wrap it together into one entry point. We call this -class of expressions "primary" expressions, for reasons that will become more -clear [later in the tutorial](PythonLangImpl6.html#unary). In order -to parse an arbitrary primary expression, we need to determine what sort of -expression it is: - -{% highlight python %} - # primary ::= identifierexpr | numberexpr | parenexpr - def ParsePrimary(self): - if isinstance(self.current, IdentifierToken): - return self.ParseIdentifierExpr() - elif isinstance(self.current, NumberToken): - return self.ParseNumberExpr(); - elif self.current == CharacterToken('('): - return self.ParseParenExpr() - else: - raise RuntimeError('Unknown token when expecting an expression.') -{% endhighlight %} - - -Now that you see the definition of this function, it is more obvious why we -can assume the state of `Parser.current` in the various functions. This -uses look-ahead to determine which sort of expression is being inspected, and -then parses it with a function call. - -Now that basic expressions are handled, we need to handle binary expressions. -They are a bit more complex. - - - - -* * * - -# Binary Expression Parsing # {#parserbinops} - -Binary expressions are significantly harder to parse because they are often -ambiguous. For example, when given the string `x+y*z`, the parser can choose -to parse it as either `(x+y)*z` or `x+(y*z)`. With common definitions from -mathematics, we expect the later parse, because `*` (multiplication) has -higher *precedence* than `+` (addition). - -There are many ways to handle this, but an elegant and efficient way is -to use [Operator-Precedence Parsing](http://en.wikipedia.org/wiki/Operator-precedence_parser). -This parsing technique uses the precedence of binary operators to -guide recursion. To start with, we need a table of precedences. Remember the -`binop_precedence` parameter we passed to the `Parser` -constructor? Now is the time to use it: - -{% highlight python %} -def main(): - # Install standard binary operators. - # 1 is lowest possible precedence. 40 is the highest. - operator_precedence = { - '<': 10, - '+': 20, - '-': 20, - '*': 40 - } - - # Run the main `interpreter loop`. - while True: - - ... - - parser = Parser(Tokenize(raw), operator_precedence) - -{% endhighlight %} - -For the basic form of Kaleidoscope, we will only support 4 binary operators -(this can obviously be extended by you, our brave and intrepid reader). Having a -dictionary makes it easy to add new operators and makes it clear that the -algorithm doesn't depend on the specific operators involved, but it would be -easy enough to eliminate the map and hardcode the comparisons. - -We also define a helper function to get the precedence of the current token, -or -1 if the token is not a binary operator: - - -{% highlight python %} - # Gets the precedence of the current token, or -1 if the token is not a binary - # operator. - def GetCurrentTokenPrecedence(self): - if isinstance(self.current, CharacterToken): - return self.binop_precedence.get(self.current.char, -1) - else: - return -1 -{% endhighlight %} - -With the helper above defined, we can now start parsing binary expressions. -The basic idea of operator precedence parsing is to break down an expression -with potentially ambiguous binary operators into pieces. Consider, for example, -the expression `a+b+(c+d)*e*f+g`. Operator precedence parsing considers this -as a stream of primary expressions separated by binary operators. As such, -it will first parse the leading primary expression `a`, then it will see the -pairs `[+, b] [+, (c+d)] [*, e] [*, f] and [+, g]`. Note that because parentheses -are primary expressions, the binary expression parser doesn't need to worry -about nested subexpressions like (c+d) at all. - - - -To start, an expression is a primary expression potentially followed by a -sequence of `[binop,primaryexpr]` pairs: - -{% highlight python %} - # expression ::= primary binoprhs - def ParseExpression(self): - left = self.ParsePrimary() - return self.ParseBinOpRHS(left, 0) -{% endhighlight %} - -`ParseBinOpRHS` is the function that parses the sequence of pairs for -us. It takes a precedence and a pointer to an expression for the part that has -been parsed so far. Note that `x` is a perfectly valid expression: As such, -`binoprhs` is allowed to be empty, in which case it returns the expression that -is passed into it. In our example above, the code passes the expression for `a` -into `ParseBinOpRHS` and the current token is `+`. - -The precedence value passed into `ParseBinOpRHS` indicates the * -minimal operator precedence* that the function is allowed to eat. For -example, if the current pair stream is `[+, x]` and `ParseBinOpRHS` is -passed in a precedence of 40, it will not consume any tokens (because the -precedence of '+' is only 20). With this in mind, `ParseBinOpRHS` starts -with: - -{% highlight python %} - # binoprhs ::= (operator primary)* - def ParseBinOpRHS(self, left, left_precedence): - # If this is a binary operator, find its precedence. - while True: - precedence = self.GetCurrentTokenPrecedence() - - # If this is a binary operator that binds at least as tightly as the - # current one, consume it; otherwise we are done. - if precedence < left_precedence: - return left -{% endhighlight %} - -This code gets the precedence of the current token and checks to see if if is -too low. Because we defined invalid tokens to have a precedence of -1, this -check implicitly knows that the pair-stream ends when the token stream runs out -of binary operators. If this check succeeds, we know that the token is a binary -operator and that it will be included in this expression: - -{% highlight python %} - binary_operator = self.current.char - self.Next() # eat the operator. - - # Parse the primary expression after the binary operator. - right = self.ParsePrimary() -{% endhighlight %} - -As such, this code eats (and remembers) the binary operator and then parses -the primary expression that follows. This builds up the whole pair, the first of -which is `[+, b]` for the running example. - -Now that we parsed the left-hand side of an expression and one pair of the -RHS sequence, we have to decide which way the expression associates. In -particular, we could have `(a+b) binop unparsed` or `a + (b binop unparsed)`. -To determine this, we look ahead at `binop` to determine its precedence and -compare it to BinOp's precedence (which is '+' in this case): - - -{% highlight python %} - # If binary_operator binds less tightly with right than the operator after - # right, let the pending operator take right as its left. - next_precedence = self.GetCurrentTokenPrecedence() - if precedence < next_precedence: -{% endhighlight %} - -If the precedence of the binop to the right of `RHS` is lower or equal to the -precedence of our current operator, then we know that the parentheses associate -as `(a+b) binop ...`. In our example, the current operator is `+` and the next -operator is `+`, we know that they have the same precedence. In this case we'll -create the AST node for `a+b`, and then continue parsing: - -{% highlight python %} - if precedence < next_precedence: - ... if body omitted ... - - # Merge left/right. - left = BinaryOperatorExpressionNode(binary_operator, left, right); -{% endhighlight %} - -In our example above, this will turn `a+b+` into `(a+b)` and execute the next -iteration of the loop, with `+` as the current token. The code above will eat, -remember, and parse `(c+d)` as the primary expression, which makes the -current pair equal to `[+, (c+d)]`. It will then evaluate the 'if' conditional -above with `*` as the binop to the right of the primary. In this case, the -precedence of `*` is higher than the precedence of `+` so the if condition will -be entered. - -The critical question left here is `how can the if condition parse the right -hand side in full`? In particular, to build the AST correctly for our example, -it needs to get all of ` ( c + d ) * e * f` as the RHS expression variable. The code to -do this is surprisingly simple (code from the above two blocks duplicated for -context): - -{% highlight python %} - # If binary_operator binds less tightly with right than the operator after - # right, let the pending operator take right as its left. - next_precedence = self.GetCurrentTokenPrecedence() - if precedence < next_precedence: - right = self.ParseBinOpRHS(right, precedence + 1) - - # Merge left/right. - left = BinaryOperatorExpressionNode(binary_operator, left, right) -{% endhighlight %} - -At this point, we know that the binary operator to the RHS of our primary -has higher precedence than the binop we are currently parsing. As such, we know -that any sequence of pairs whose operators are all higher precedence than `+` -should be parsed together and returned as `RHS`. To do this, we recursively -invoke the `ParseBinOpRHS` function specifying `precedence + 1` as the -minimum precedence required for it to continue. In our example above, this -will cause it to return the AST node for `(c+d)*e*f` as RHS, which is then set -as the RHS of the '+' expression. - -Finally, on the next iteration of the while loop, the `+g` piece is parsed -and added to the AST. With this little bit of code (11 non-trivial lines), we -correctly handle fully general binary expression parsing in a very elegant way. -This was a whirlwind tour of this code, and it is somewhat subtle. I recommend -running through it with a few tough examples to see how it works. - - -This wraps up handling of expressions. At this point, we can point the -parser at an arbitrary token stream and build an expression from it, stopping -at the first token that is not part of the expression. Next up we need to -handle function definitions, etc. - - -* * * - -# Parsing the Rest # {#parsertop} - - -The next thing missing is handling of function prototypes. In Kaleidoscope, -these are used both for 'extern' function declarations as well as function body -definitions. The code to do this is straight-forward and not very interesting -(once you've survived expressions): - -{% highlight python %} - # prototype ::= id '(' id* ')' - def ParsePrototype(self): - if not isinstance(self.current, IdentifierToken): - raise RuntimeError('Expected function name in prototype.') - - function_name = self.current.name - self.Next() # eat function name. - - if self.current != CharacterToken('('): - raise RuntimeError('Expected "(" in prototype.') - self.Next() # eat '('. - - arg_names = [] - while isinstance(self.current, IdentifierToken): - arg_names.append(self.current.name) - self.Next() - - if self.current != CharacterToken(')'): - raise RuntimeError('Expected ")" in prototype.') - - # Success. - self.Next() # eat ')'. - - return PrototypeNode(function_name, arg_names) -{% endhighlight %} - - -Given this, a function definition is very simple, just a prototype plus -an expression to implement the body: - - -{% highlight python %} - # definition ::= 'def' prototype expression - def ParseDefinition(self): - self.Next() # eat def. - proto = self.ParsePrototype() - body = self.ParseExpression() - return FunctionNode(proto, body) -{% endhighlight %} - - -In addition, we support 'extern' to declare functions like 'sin' and 'cos' as -well as to support forward declaration of user functions. These 'extern's are -just prototypes with no body: - - -{% highlight python %} - # external ::= 'extern' prototype - def ParseExtern(self): - self.Next() # eat extern. - return self.ParsePrototype() -{% endhighlight %} - - -Finally, we'll also let the user type in arbitrary top-level expressions and -evaluate them on the fly. We will handle this by defining anonymous nullary -(zero argument) functions for them: - - -{% highlight python %} - # toplevelexpr ::= expression - def ParseTopLevelExpr(self): - proto = PrototypeNode('', []) - return FunctionNode(proto, self.ParseExpression()) -{% endhighlight %} - - -Now that we have all the pieces, let's build a little driver that will let us -actually *execute* this code we've built! - - - -* * * - -# The Driver # {#driver} - - -The driver for this simply invokes all of the parsing pieces with a top-level -dispatch loop. There isn't much interesting here, so I'll just include the -top-level loop. See [below](#code) for full code. - - -{% highlight python %} - # Run the main "interpreter loop". - while True: - print 'ready>', - try: - raw = raw_input() - except KeyboardInterrupt: - return - - parser = Parser(Tokenize(raw), operator_precedence) - while True: - # top ::= definition | external | expression | EOF - if isinstance(parser.current, EOFToken): - break - if isinstance(parser.current, DefToken): - parser.HandleDefinition() - elif isinstance(parser.current, ExternToken): - parser.HandleExtern() - else: - parser.HandleTopLevelExpression() -{% endhighlight %} - - -Here we create a new `Parser` for each line read, and try to parse out -all the expressions, declarations and definitions in the line. We also allow the -user to quit using Ctrl+C. - - - -* * * - -# Conclusions # {#conclusions} - - -With just under 330 lines of commented code (200 lines of non-comment, -non-blank code), we fully defined our minimal language, including a lexer, -parser, and AST builder. With this done, the executable will validate -Kaleidoscope code and tell us if it is grammatically invalid. For -example, here is a sample interaction: - - -{% highlight python %} -$ python kaleidoscope.py -ready> def foo(x y) x+foo(y, 4.0) -Parsed a function definition. -ready> def foo(x y) x+y y -Parsed a function definition. -Parsed a top-level expression. -ready> def foo(x y) x+y ) -Parsed a function definition. -Error: Unknown token when expecting an expression. -ready> extern sin(a); -Parsed an extern. -ready> ^C -$ -{% endhighlight %} - -There is a lot of room for extension here. You can define new AST nodes, -extend the language in many ways, etc. In the -[next installment](PythonLangImpl3.html), we will describe how to -generate LLVM Intermediate Representation (IR) from the AST. - - -* * * - -# Full Code Listing # {#code} - - -Here is the complete code listing for this and the previous chapter. -Note that it is fully self-contained: you don't need LLVM or any external -libraries at all for this. - - -{% highlight python %} -#!/usr/bin/env python - -import re - -################################################################################ -## Lexer -################################################################################ - -# The lexer yields one of these types for each token. -class EOFToken(object): - pass - -class DefToken(object): - pass - -class ExternToken(object): - pass - -class IdentifierToken(object): - def __init__(self, name): self.name = name - -class NumberToken(object): - def __init__(self, value): self.value = value - -class CharacterToken(object): - def __init__(self, char): self.char = char - def __eq__(self, other): - return isinstance(other, CharacterToken) and self.char == other.char - def __ne__(self, other): return not self == other - -# Regular expressions that tokens and comments of our language. -REGEX_NUMBER = re.compile('[0-9]+(?:\.[0-9]+)?') -REGEX_IDENTIFIER = re.compile('[a-zA-Z][a-zA-Z0-9]*') -REGEX_COMMENT = re.compile('#.*') - -def Tokenize(string): - while string: - # Skip whitespace. - if string[0].isspace(): - string = string[1:] - continue - - # Run regexes. - comment_match = REGEX_COMMENT.match(string) - number_match = REGEX_NUMBER.match(string) - identifier_match = REGEX_IDENTIFIER.match(string) - - # Check if any of the regexes matched and yield the appropriate result. - if comment_match: - comment = comment_match.group(0) - string = string[len(comment):] - elif number_match: - number = number_match.group(0) - yield NumberToken(float(number)) - string = string[len(number):] - elif identifier_match: - identifier = identifier_match.group(0) - # Check if we matched a keyword. - if identifier == 'def': - yield DefToken() - elif identifier == 'extern': - yield ExternToken() - else: - yield IdentifierToken(identifier) - string = string[len(identifier):] - else: - # Yield the ASCII value of the unknown character. - yield CharacterToken(string[0]) - string = string[1:] - - yield EOFToken() - -################################################################################ -## Abstract Syntax Tree (aka Parse Tree) -################################################################################ - -# Base class for all expression nodes. -class ExpressionNode(object): - pass - -# Expression class for numeric literals like "1.0". -class NumberExpressionNode(ExpressionNode): - def __init__(self, value): - self.value = value - -# Expression class for referencing a variable, like "a". -class VariableExpressionNode(ExpressionNode): - def __init__(self, name): - self.name = name - -# Expression class for a binary operator. -class BinaryOperatorExpressionNode(ExpressionNode): - def __init__(self, operator, left, right): - self.operator = operator - self.left = left - self.right = right - -# Expression class for function calls. -class CallExpressionNode(ExpressionNode): - def __init__(self, callee, args): - self.callee = callee - self.args = args - -# This class represents the "prototype" for a function, which captures its name, -# and its argument names (thus implicitly the number of arguments the function -# takes). -class PrototypeNode(object): - def __init__(self, name, args): - self.name = name - self.args = args - -# This class represents a function definition itself. -class FunctionNode(object): - def __init__(self, prototype, body): - self.prototype = prototype - self.body = body - - -################################################################################ -## Parser -################################################################################ - -class Parser(object): - - def __init__(self, tokens, binop_precedence): - self.tokens = tokens - self.binop_precedence = binop_precedence - self.Next() - - # Provide a simple token buffer. Parser.current is the current token the - # parser is looking at. Parser.Next() reads another token from the lexer and - # updates Parser.current with its results. - def Next(self): - self.current = self.tokens.next() - - # Gets the precedence of the current token, or -1 if the token is not a binary - # operator. - def GetCurrentTokenPrecedence(self): - if isinstance(self.current, CharacterToken): - return self.binop_precedence.get(self.current.char, -1) - else: - return -1 - - # identifierexpr ::= identifier | identifier '(' expression* ')' - def ParseIdentifierExpr(self): - identifier_name = self.current.name - self.Next() # eat identifier. - - if self.current != CharacterToken('('): # Simple variable reference. - return VariableExpressionNode(identifier_name) - - # Call. - self.Next() # eat '('. - args = [] - if self.current != CharacterToken(')'): - while True: - args.append(self.ParseExpression()) - if self.current == CharacterToken(')'): - break - elif self.current != CharacterToken(','): - raise RuntimeError('Expected ")" or "," in argument list.') - self.Next() - - self.Next() # eat ')'. - return CallExpressionNode(identifier_name, args) - - # numberexpr ::= number - def ParseNumberExpr(self): - result = NumberExpressionNode(self.current.value) - self.Next() # consume the number. - return result - - # parenexpr ::= '(' expression ')' - def ParseParenExpr(self): - self.Next() # eat '('. - - contents = self.ParseExpression() - - if self.current != CharacterToken(')'): - raise RuntimeError('Expected ")".') - self.Next() # eat ')'. - - return contents - - # primary ::= identifierexpr | numberexpr | parenexpr - def ParsePrimary(self): - if isinstance(self.current, IdentifierToken): - return self.ParseIdentifierExpr() - elif isinstance(self.current, NumberToken): - return self.ParseNumberExpr() - elif self.current == CharacterToken('('): - return self.ParseParenExpr() - else: - raise RuntimeError('Unknown token when expecting an expression.') - - # binoprhs ::= (operator primary)* - def ParseBinOpRHS(self, left, left_precedence): - # If this is a binary operator, find its precedence. - while True: - precedence = self.GetCurrentTokenPrecedence() - - # If this is a binary operator that binds at least as tightly as the - # current one, consume it; otherwise we are done. - if precedence < left_precedence: - return left - - binary_operator = self.current.char - self.Next() # eat the operator. - - # Parse the primary expression after the binary operator. - right = self.ParsePrimary() - - # If binary_operator binds less tightly with right than the operator after - # right, let the pending operator take right as its left. - next_precedence = self.GetCurrentTokenPrecedence() - if precedence < next_precedence: - right = self.ParseBinOpRHS(right, precedence + 1) - - # Merge left/right. - left = BinaryOperatorExpressionNode(binary_operator, left, right) - - # expression ::= primary binoprhs - def ParseExpression(self): - left = self.ParsePrimary() - return self.ParseBinOpRHS(left, 0) - - # prototype ::= id '(' id* ')' - def ParsePrototype(self): - if not isinstance(self.current, IdentifierToken): - raise RuntimeError('Expected function name in prototype.') - - function_name = self.current.name - self.Next() # eat function name. - - if self.current != CharacterToken('('): - raise RuntimeError('Expected "(" in prototype.') - self.Next() # eat '('. - - arg_names = [] - while isinstance(self.current, IdentifierToken): - arg_names.append(self.current.name) - self.Next() - - if self.current != CharacterToken(')'): - raise RuntimeError('Expected ")" in prototype.') - - # Success. - self.Next() # eat ')'. - - return PrototypeNode(function_name, arg_names) - - # definition ::= 'def' prototype expression - def ParseDefinition(self): - self.Next() # eat def. - proto = self.ParsePrototype() - body = self.ParseExpression() - return FunctionNode(proto, body) - - # toplevelexpr ::= expression - def ParseTopLevelExpr(self): - proto = PrototypeNode('', []) - return FunctionNode(proto, self.ParseExpression()) - - # external ::= 'extern' prototype - def ParseExtern(self): - self.Next() # eat extern. - return self.ParsePrototype() - - # Top-Level parsing - def HandleDefinition(self): - self.Handle(self.ParseDefinition, 'Parsed a function definition.') - - def HandleExtern(self): - self.Handle(self.ParseExtern, 'Parsed an extern.') - - def HandleTopLevelExpression(self): - self.Handle(self.ParseTopLevelExpr, 'Parsed a top-level expression.') - - def Handle(self, function, message): - try: - function() - print message - except Exception, e: - print 'Error:', e - try: - self.Next() # Skip for error recovery. - except: - pass - -################################################################################ -## Main driver code. -################################################################################ - -def main(): - # Install standard binary operators. - # 1 is lowest possible precedence. 40 is the highest. - operator_precedence = { - '<': 10, - '+': 20, - '-': 20, - '*': 40 - } - - # Run the main "interpreter loop". - while True: - print 'ready>', - try: - raw = raw_input() - except KeyboardInterrupt: - return - - parser = Parser(Tokenize(raw), operator_precedence) - while True: - # top ::= definition | external | expression | EOF - if isinstance(parser.current, EOFToken): - break - if isinstance(parser.current, DefToken): - parser.HandleDefinition() - elif isinstance(parser.current, ExternToken): - parser.HandleExtern() - else: - parser.HandleTopLevelExpression() - -if __name__ == '__main__': - main() -{% endhighlight %} - - -* * * - -**[Next: Implementing Code Generation to LLVM IR](PythonLangImpl3.html)** diff --git a/docs/source/doc/kaleidoscope/PythonLangImpl2.rst b/docs/source/doc/kaleidoscope/PythonLangImpl2.rst new file mode 100644 index 0000000..d7d3bd1 --- /dev/null +++ b/docs/source/doc/kaleidoscope/PythonLangImpl2.rst @@ -0,0 +1,892 @@ ++------------------------------------+ +| layout: page | ++------------------------------------+ +| title: "Kaleidoscope: Chapter 2" | ++------------------------------------+ + +Implementing a Parser and AST +============================= + +Written by `Chris Lattner `_ and `Max +Shawabkeh `_ + +**Chapter 2** + +- This will become a table of contents (this text will be scraped). + {:toc} + +**`Chapter 3: Code generation to LLVM IR `_** + +Introduction # {#intro} +======================= + +Welcome to Chapter 2 of the `Implementing a language with +LLVM `_ tutorial. This +chapter shows you how to use the lexer, built in `Chapter +1 `_, to build a full +`parser `_ for our Kaleidoscope +language. Once we have a parser, we'll define and build an `Abstract +Syntax Tree `_ (AST). + +The parser we will build uses a combination of `Recursive Descent +Parsing `_ and +`Operator-Precedence +Parsing `_ to +parse the Kaleidoscope language (the latter for binary expressions and +the former for everything else). Before we get to parsing though, lets +talk about the output of the parser: the Abstract Syntax Tree. + +-------------- + +The Abstract Syntax Tree (AST) # {#ast} +======================================= + +The AST for a program captures its behavior in such a way that it is +easy for later stages of the compiler (e.g. code generation) to +interpret. We basically want one object for each construct in the +language, and the AST should closely model the language. In +Kaleidoscope, we have expressions, a prototype, and a function object. +We'll start with expressions first: + +{% highlight python %} # Base class for all expression nodes. class +ExpressionNode(object): pass + +Expression class for numeric literals like "1.0". +================================================= + +class NumberExpressionNode(ExpressionNode): def **init**\ (self, value): +self.value = value + +{% endhighlight %} + +The code above shows the definition of the base ExpressionNode class and +one subclass which we use for numeric literals. The important thing to +note about this code is that the NumberExpressionNode class captures the +numeric value of the literal as an instance variable. This allows later +phases of the compiler to know what the stored numeric value is. + +Right now we only create the AST, so there are no useful methods on +them. It would be very easy to add a virtual method to pretty print the +code, for example. Here are the other expression AST node definitions +that we'll use in the basic form of the Kaleidoscope language: + +{% highlight python %} # Expression class for referencing a variable, +like "a". class VariableExpressionNode(ExpressionNode): def +**init**\ (self, name): self.name = name + +Expression class for a binary operator. +======================================= + +class BinaryOperatorExpressionNode(ExpressionNode): def **init**\ (self, +operator, left, right): self.operator = operator self.left = left +self.right = right + +Expression class for function calls. +==================================== + +class CallExpressionNode(ExpressionNode): def **init**\ (self, callee, +args): self.callee = callee self.args = args {% endhighlight %} + +This is all (intentionally) rather straight-forward: variables capture +the variable name, binary operators capture their opcode (e.g. '+'), and +calls capture a function name as well as a list of any argument +expressions. One thing that is nice about our AST is that it captures +the language features without talking about the syntax of the language. +Note that there is no discussion about precedence of binary operators, +lexical structure, etc. + +For our basic language, these are all of the expression nodes we'll +define. Because it doesn't have conditional control flow, it isn't +Turing-complete; we'll fix that in a later installment. The two things +we need next are a way to talk about the interface to a function, and a +way to talk about functions themselves: + +{% highlight python %} # This class represents the "prototype" for a +function, which captures its name, # and its argument names (thus +implicitly the number of arguments the function # takes). class +PrototypeNode(object): def **init**\ (self, name, args): self.name = +name self.args = args + +This class represents a function definition itself. +=================================================== + +class FunctionNode(object): def **init**\ (self, prototype, body): +self.prototype = prototype self.body = body {% endhighlight %} + +In Kaleidoscope, functions are typed with just a count of their +arguments. Since all values are double precision floating point, the +type of each argument doesn't need to be stored anywhere. In a more +aggressive and realistic language, the ``ExpressionNode`` class would +probably have a type field. + +With this scaffolding, we can now talk about parsing expressions and +function bodies in Kaleidoscope. + +-------------- + +Parser Basics # {#parserbasics} +=============================== + +Now that we have an AST to build, we need to define the parser code to +build it. The idea here is that we want to parse something like +``x + y`` (which is returned as three tokens by the lexer) into an AST +that could be generated with calls like this: + +{% highlight python %} x = VariableExpressionNode('x') y = +VariableExpressionNode('y') result = BinaryOperatorExpressionNode('+', +x, y) {% endhighlight %} + +In order to do this, we'll start by defining a lightweight ``Parser`` +class with some basic helper routines: + +{% highlight python %} class Parser(object): + +def **init**\ (self, tokens, binop\_precedence): self.tokens = tokens +self.binop\_precedence = binop\_precedence self.Next() + +# Provide a simple token buffer. Parser.current is the current token the +# parser is looking at. Parser.Next() reads another token from the lexer +and # updates Parser.current with its results. def Next(self): +self.current = self.tokens.next() {% endhighlight %} + +This implements a simple token buffer around the lexer. This allows us +to look one token ahead at what the lexer is returning. Every function +in our parser will assume that ``self.current`` is the current token +that needs to be parsed. Note that the first token is read as soon as +the parser is instantiated. Let us ignore the ``binop_precedence`` +parameter for now. It will be explained when we start `parsing binary +operators <#parserbinops>`_. + +With these basic helper functions, we can implement the first piece of +our grammar: numeric literals. + +-------------- + +Basic Expression Parsing # {#parserprimexprs} +============================================= + +We start with numeric literals, because they are the simplest to +process. For each production in our grammar, we'll define a function +which parses that production. For numeric literals, we have: + +{% highlight python %} # numberexpr ::= number def +ParseNumberExpr(self): result = NumberExpressionNode(self.current.value) +self.Next() # consume the number. return result {% endhighlight %} + +This method is very simple: it expects to be called when the current +token is a ``NumberToken``. It takes the current number value, creates a +``NumberExpressionNode``, advances to the next token, and finally +returns. + +There are some interesting aspects to this. The most important one is +that this routine eats all of the tokens that correspond to the +production and returns the lexer buffer with the next token (which is +not part of the grammar production) ready to go. This is a fairly +standard way to go for recursive descent parsers. For a better example, +the parenthesis operator is defined like this: + +{% highlight python %} # parenexpr ::= '(' expression ')' def +ParseParenExpr(self): self.Next() # eat '('. + +:: + + contents = self.ParseExpression() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")".') + self.Next() # eat ')'. + + return contents + +{% endhighlight %} + +This function illustrates an interesting aspect of the parser. The +function uses recursion by calling ``ParseExpression`` (we will soon see +that ``ParseExpression`` can call ``ParseParenExpr``). This is powerful +because it allows us to handle recursive grammars, and keeps each +production very simple. Note that parentheses do not cause construction +of AST nodes themselves. While we could do it this way, the most +important role of parentheses are to guide the parser and provide +grouping. Once the parser constructs the AST, parentheses are not +needed. + +The next simple production is for handling variable references and +function calls: + +{% highlight python %} # identifierexpr ::= identifier \| identifier '(' +expression\* ')' def ParseIdentifierExpr(self): identifier\_name = +self.current.name self.Next() # eat identifier. + +:: + + if self.current != CharacterToken('('): # Simple variable reference. + return VariableExpressionNode(identifier_name); + + # Call. + self.Next() # eat '('. + args = [] + if self.current != CharacterToken(')'): + while True: + args.append(self.ParseExpression()) + if self.current == CharacterToken(')'): + break + elif self.current != CharacterToken(','): + raise RuntimeError('Expected ")" or "," in argument list.') + self.Next() + + self.Next() # eat ')'. + return CallExpressionNode(identifier_name, args) + +{% endhighlight %} + +This routine follows the same style as the other routines. It expects to +be called if the current token is an ``IdentifierToken``. It also has +recursion and error handling. One interesting aspect of this is that it +uses *look-ahead* to determine if the current identifier is a stand +alone variable reference or if it is a function call expression. It +handles this by checking to see if the token after the identifier is a +'(' token, constructing either a ``VariableExpressionNode`` or +``CallExpressionNode`` as appropriate. + +Now that we have all of our simple expression-parsing logic in place, we +can define a helper function to wrap it together into one entry point. +We call this class of expressions "primary" expressions, for reasons +that will become more clear `later in the +tutorial `_. In order to parse an arbitrary +primary expression, we need to determine what sort of expression it is: + +{% highlight python %} # primary ::= identifierexpr \| numberexpr \| +parenexpr def ParsePrimary(self): if isinstance(self.current, +IdentifierToken): return self.ParseIdentifierExpr() elif +isinstance(self.current, NumberToken): return self.ParseNumberExpr(); +elif self.current == CharacterToken('('): return self.ParseParenExpr() +else: raise RuntimeError('Unknown token when expecting an expression.') +{% endhighlight %} + +Now that you see the definition of this function, it is more obvious why +we can assume the state of ``Parser.current`` in the various functions. +This uses look-ahead to determine which sort of expression is being +inspected, and then parses it with a function call. + +Now that basic expressions are handled, we need to handle binary +expressions. They are a bit more complex. + +-------------- + +Binary Expression Parsing # {#parserbinops} +=========================================== + +Binary expressions are significantly harder to parse because they are +often ambiguous. For example, when given the string ``x+y*z``, the +parser can choose to parse it as either ``(x+y)*z`` or ``x+(y*z)``. With +common definitions from mathematics, we expect the later parse, because +``*`` (multiplication) has higher *precedence* than ``+`` (addition). + +There are many ways to handle this, but an elegant and efficient way is +to use `Operator-Precedence +Parsing `_. +This parsing technique uses the precedence of binary operators to guide +recursion. To start with, we need a table of precedences. Remember the +``binop_precedence`` parameter we passed to the ``Parser`` constructor? +Now is the time to use it: + +{% highlight python %} def main(): # Install standard binary operators. +# 1 is lowest possible precedence. 40 is the highest. +operator\_precedence = { '<': 10, '+': 20, '-': 20, '\*': 40 } + +# Run the main ``interpreter loop``. while True: + +:: + + ... + + parser = Parser(Tokenize(raw), operator_precedence) + +{% endhighlight %} + +For the basic form of Kaleidoscope, we will only support 4 binary +operators (this can obviously be extended by you, our brave and intrepid +reader). Having a dictionary makes it easy to add new operators and +makes it clear that the algorithm doesn't depend on the specific +operators involved, but it would be easy enough to eliminate the map and +hardcode the comparisons. + +We also define a helper function to get the precedence of the current +token, or -1 if the token is not a binary operator: + +{% highlight python %} # Gets the precedence of the current token, or -1 +if the token is not a binary # operator. def +GetCurrentTokenPrecedence(self): if isinstance(self.current, +CharacterToken): return self.binop\_precedence.get(self.current.char, +-1) else: return -1 {% endhighlight %} + +With the helper above defined, we can now start parsing binary +expressions. The basic idea of operator precedence parsing is to break +down an expression with potentially ambiguous binary operators into +pieces. Consider, for example, the expression ``a+b+(c+d)*e*f+g``. +Operator precedence parsing considers this as a stream of primary +expressions separated by binary operators. As such, it will first parse +the leading primary expression ``a``, then it will see the pairs +``[+, b] [+, (c+d)] [*, e] [*, f] and [+, g]``. Note that because +parentheses are primary expressions, the binary expression parser +doesn't need to worry about nested subexpressions like (c+d) at all. + +To start, an expression is a primary expression potentially followed by +a sequence of ``[binop,primaryexpr]`` pairs: + +{% highlight python %} # expression ::= primary binoprhs def +ParseExpression(self): left = self.ParsePrimary() return +self.ParseBinOpRHS(left, 0) {% endhighlight %} + +``ParseBinOpRHS`` is the function that parses the sequence of pairs for +us. It takes a precedence and a pointer to an expression for the part +that has been parsed so far. Note that ``x`` is a perfectly valid +expression: As such, ``binoprhs`` is allowed to be empty, in which case +it returns the expression that is passed into it. In our example above, +the code passes the expression for ``a`` into ``ParseBinOpRHS`` and the +current token is ``+``. + +The precedence value passed into ``ParseBinOpRHS`` indicates the \* +minimal operator precedence\* that the function is allowed to eat. For +example, if the current pair stream is ``[+, x]`` and ``ParseBinOpRHS`` +is passed in a precedence of 40, it will not consume any tokens (because +the precedence of '+' is only 20). With this in mind, ``ParseBinOpRHS`` +starts with: + +{% highlight python %} # binoprhs ::= (operator primary)\* def +ParseBinOpRHS(self, left, left\_precedence): # If this is a binary +operator, find its precedence. while True: precedence = +self.GetCurrentTokenPrecedence() + +:: + + # If this is a binary operator that binds at least as tightly as the + # current one, consume it; otherwise we are done. + if precedence < left_precedence: + return left + +{% endhighlight %} + +This code gets the precedence of the current token and checks to see if +if is too low. Because we defined invalid tokens to have a precedence of +-1, this check implicitly knows that the pair-stream ends when the token +stream runs out of binary operators. If this check succeeds, we know +that the token is a binary operator and that it will be included in this +expression: + +{% highlight python %} binary\_operator = self.current.char self.Next() +# eat the operator. + +:: + + # Parse the primary expression after the binary operator. + right = self.ParsePrimary() + +{% endhighlight %} + +As such, this code eats (and remembers) the binary operator and then +parses the primary expression that follows. This builds up the whole +pair, the first of which is ``[+, b]`` for the running example. + +Now that we parsed the left-hand side of an expression and one pair of +the RHS sequence, we have to decide which way the expression associates. +In particular, we could have ``(a+b) binop unparsed`` or +``a + (b binop unparsed)``. To determine this, we look ahead at +``binop`` to determine its precedence and compare it to BinOp's +precedence (which is '+' in this case): + +{% highlight python %} # If binary\_operator binds less tightly with +right than the operator after # right, let the pending operator take +right as its left. next\_precedence = self.GetCurrentTokenPrecedence() +if precedence < next\_precedence: {% endhighlight %} + +If the precedence of the binop to the right of ``RHS`` is lower or equal +to the precedence of our current operator, then we know that the +parentheses associate as ``(a+b) binop ...``. In our example, the +current operator is ``+`` and the next operator is ``+``, we know that +they have the same precedence. In this case we'll create the AST node +for ``a+b``, and then continue parsing: + +{% highlight python %} if precedence < next\_precedence: ... if body +omitted ... + +:: + + # Merge left/right. + left = BinaryOperatorExpressionNode(binary_operator, left, right); + +{% endhighlight %} + +In our example above, this will turn ``a+b+`` into ``(a+b)`` and execute +the next iteration of the loop, with ``+`` as the current token. The +code above will eat, remember, and parse ``(c+d)`` as the primary +expression, which makes the current pair equal to ``[+, (c+d)]``. It +will then evaluate the 'if' conditional above with ``*`` as the binop to +the right of the primary. In this case, the precedence of ``*`` is +higher than the precedence of ``+`` so the if condition will be entered. + +The critical question left here is +``how can the if condition parse the right hand side in full``? In +particular, to build the AST correctly for our example, it needs to get +all of ``( c + d ) * e * f`` as the RHS expression variable. The code to +do this is surprisingly simple (code from the above two blocks +duplicated for context): + +{% highlight python %} # If binary\_operator binds less tightly with +right than the operator after # right, let the pending operator take +right as its left. next\_precedence = self.GetCurrentTokenPrecedence() +if precedence < next\_precedence: right = self.ParseBinOpRHS(right, +precedence + 1) + +:: + + # Merge left/right. + left = BinaryOperatorExpressionNode(binary_operator, left, right) + +{% endhighlight %} + +At this point, we know that the binary operator to the RHS of our +primary has higher precedence than the binop we are currently parsing. +As such, we know that any sequence of pairs whose operators are all +higher precedence than ``+`` should be parsed together and returned as +``RHS``. To do this, we recursively invoke the ``ParseBinOpRHS`` +function specifying ``precedence + 1`` as the minimum precedence +required for it to continue. In our example above, this will cause it to +return the AST node for ``(c+d)*e*f`` as RHS, which is then set as the +RHS of the '+' expression. + +Finally, on the next iteration of the while loop, the ``+g`` piece is +parsed and added to the AST. With this little bit of code (11 +non-trivial lines), we correctly handle fully general binary expression +parsing in a very elegant way. This was a whirlwind tour of this code, +and it is somewhat subtle. I recommend running through it with a few +tough examples to see how it works. + +This wraps up handling of expressions. At this point, we can point the +parser at an arbitrary token stream and build an expression from it, +stopping at the first token that is not part of the expression. Next up +we need to handle function definitions, etc. + +-------------- + +Parsing the Rest # {#parsertop} +=============================== + +The next thing missing is handling of function prototypes. In +Kaleidoscope, these are used both for 'extern' function declarations as +well as function body definitions. The code to do this is +straight-forward and not very interesting (once you've survived +expressions): + +{% highlight python %} # prototype ::= id '(' id\* ')' def +ParsePrototype(self): if not isinstance(self.current, IdentifierToken): +raise RuntimeError('Expected function name in prototype.') + +:: + + function_name = self.current.name + self.Next() # eat function name. + + if self.current != CharacterToken('('): + raise RuntimeError('Expected "(" in prototype.') + self.Next() # eat '('. + + arg_names = [] + while isinstance(self.current, IdentifierToken): + arg_names.append(self.current.name) + self.Next() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")" in prototype.') + + # Success. + self.Next() # eat ')'. + + return PrototypeNode(function_name, arg_names) + +{% endhighlight %} + +Given this, a function definition is very simple, just a prototype plus +an expression to implement the body: + +{% highlight python %} # definition ::= 'def' prototype expression def +ParseDefinition(self): self.Next() # eat def. proto = +self.ParsePrototype() body = self.ParseExpression() return +FunctionNode(proto, body) {% endhighlight %} + +In addition, we support 'extern' to declare functions like 'sin' and +'cos' as well as to support forward declaration of user functions. These +'extern's are just prototypes with no body: + +{% highlight python %} # external ::= 'extern' prototype def +ParseExtern(self): self.Next() # eat extern. return +self.ParsePrototype() {% endhighlight %} + +Finally, we'll also let the user type in arbitrary top-level expressions +and evaluate them on the fly. We will handle this by defining anonymous +nullary (zero argument) functions for them: + +{% highlight python %} # toplevelexpr ::= expression def +ParseTopLevelExpr(self): proto = PrototypeNode('', []) return +FunctionNode(proto, self.ParseExpression()) {% endhighlight %} + +Now that we have all the pieces, let's build a little driver that will +let us actually *execute* this code we've built! + +-------------- + +The Driver # {#driver} +====================== + +The driver for this simply invokes all of the parsing pieces with a +top-level dispatch loop. There isn't much interesting here, so I'll just +include the top-level loop. See `below <#code>`_ for full code. + +{% highlight python %} # Run the main "interpreter loop". while True: +print 'ready>', try: raw = raw\_input() except KeyboardInterrupt: return + +:: + + parser = Parser(Tokenize(raw), operator_precedence) + while True: + # top ::= definition | external | expression | EOF + if isinstance(parser.current, EOFToken): + break + if isinstance(parser.current, DefToken): + parser.HandleDefinition() + elif isinstance(parser.current, ExternToken): + parser.HandleExtern() + else: + parser.HandleTopLevelExpression() + +{% endhighlight %} + +Here we create a new ``Parser`` for each line read, and try to parse out +all the expressions, declarations and definitions in the line. We also +allow the user to quit using Ctrl+C. + +-------------- + +Conclusions # {#conclusions} +============================ + +With just under 330 lines of commented code (200 lines of non-comment, +non-blank code), we fully defined our minimal language, including a +lexer, parser, and AST builder. With this done, the executable will +validate Kaleidoscope code and tell us if it is grammatically invalid. +For example, here is a sample interaction: + +{% highlight python %} $ python kaleidoscope.py ready> def foo(x y) +x+foo(y, 4.0) Parsed a function definition. ready> def foo(x y) x+y y +Parsed a function definition. Parsed a top-level expression. ready> def +foo(x y) x+y ) Parsed a function definition. Error: Unknown token when +expecting an expression. ready> extern sin(a); Parsed an extern. ready> +^C $ {% endhighlight %} + +There is a lot of room for extension here. You can define new AST nodes, +extend the language in many ways, etc. In the `next +installment `_, we will describe how to generate +LLVM Intermediate Representation (IR) from the AST. + +-------------- + +Full Code Listing # {#code} +=========================== + +Here is the complete code listing for this and the previous chapter. +Note that it is fully self-contained: you don't need LLVM or any +external libraries at all for this. + +{% highlight python %} #!/usr/bin/env python + +import re + +Lexer +----- + +The lexer yields one of these types for each token. +=================================================== + +class EOFToken(object): pass + +class DefToken(object): pass + +class ExternToken(object): pass + +class IdentifierToken(object): def **init**\ (self, name): self.name = +name + +class NumberToken(object): def **init**\ (self, value): self.value = +value + +class CharacterToken(object): def **init**\ (self, char): self.char = +char def **eq**\ (self, other): return isinstance(other, CharacterToken) +and self.char == other.char def **ne**\ (self, other): return not self +== other + +Regular expressions that tokens and comments of our language. +============================================================= + +REGEX\_NUMBER = re.compile('[0-9]+(?:.[0-9]+)?') REGEX\_IDENTIFIER = +re.compile('[a-zA-Z][a-zA-Z0-9]\ *') REGEX\_COMMENT = re.compile('#.*') + +def Tokenize(string): while string: # Skip whitespace. if +string[0].isspace(): string = string[1:] continue + +:: + + # Run regexes. + comment_match = REGEX_COMMENT.match(string) + number_match = REGEX_NUMBER.match(string) + identifier_match = REGEX_IDENTIFIER.match(string) + + # Check if any of the regexes matched and yield the appropriate result. + if comment_match: + comment = comment_match.group(0) + string = string[len(comment):] + elif number_match: + number = number_match.group(0) + yield NumberToken(float(number)) + string = string[len(number):] + elif identifier_match: + identifier = identifier_match.group(0) + # Check if we matched a keyword. + if identifier == 'def': + yield DefToken() + elif identifier == 'extern': + yield ExternToken() + else: + yield IdentifierToken(identifier) + string = string[len(identifier):] + else: + # Yield the ASCII value of the unknown character. + yield CharacterToken(string[0]) + string = string[1:] + +yield EOFToken() + +Abstract Syntax Tree (aka Parse Tree) +------------------------------------- + +Base class for all expression nodes. +==================================== + +class ExpressionNode(object): pass + +Expression class for numeric literals like "1.0". +================================================= + +class NumberExpressionNode(ExpressionNode): def **init**\ (self, value): +self.value = value + +Expression class for referencing a variable, like "a". +====================================================== + +class VariableExpressionNode(ExpressionNode): def **init**\ (self, +name): self.name = name + +Expression class for a binary operator. +======================================= + +class BinaryOperatorExpressionNode(ExpressionNode): def **init**\ (self, +operator, left, right): self.operator = operator self.left = left +self.right = right + +Expression class for function calls. +==================================== + +class CallExpressionNode(ExpressionNode): def **init**\ (self, callee, +args): self.callee = callee self.args = args + +This class represents the "prototype" for a function, which captures its name, +============================================================================== + +and its argument names (thus implicitly the number of arguments the function +============================================================================ + +takes). +======= + +class PrototypeNode(object): def **init**\ (self, name, args): self.name += name self.args = args + +This class represents a function definition itself. +=================================================== + +class FunctionNode(object): def **init**\ (self, prototype, body): +self.prototype = prototype self.body = body + +Parser +------ + +class Parser(object): + +def **init**\ (self, tokens, binop\_precedence): self.tokens = tokens +self.binop\_precedence = binop\_precedence self.Next() + +# Provide a simple token buffer. Parser.current is the current token the +# parser is looking at. Parser.Next() reads another token from the lexer +and # updates Parser.current with its results. def Next(self): +self.current = self.tokens.next() + +# Gets the precedence of the current token, or -1 if the token is not a +binary # operator. def GetCurrentTokenPrecedence(self): if +isinstance(self.current, CharacterToken): return +self.binop\_precedence.get(self.current.char, -1) else: return -1 + +# identifierexpr ::= identifier \| identifier '(' expression\* ')' def +ParseIdentifierExpr(self): identifier\_name = self.current.name +self.Next() # eat identifier. + +:: + + if self.current != CharacterToken('('): # Simple variable reference. + return VariableExpressionNode(identifier_name) + + # Call. + self.Next() # eat '('. + args = [] + if self.current != CharacterToken(')'): + while True: + args.append(self.ParseExpression()) + if self.current == CharacterToken(')'): + break + elif self.current != CharacterToken(','): + raise RuntimeError('Expected ")" or "," in argument list.') + self.Next() + + self.Next() # eat ')'. + return CallExpressionNode(identifier_name, args) + +# numberexpr ::= number def ParseNumberExpr(self): result = +NumberExpressionNode(self.current.value) self.Next() # consume the +number. return result + +# parenexpr ::= '(' expression ')' def ParseParenExpr(self): self.Next() +# eat '('. + +:: + + contents = self.ParseExpression() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")".') + self.Next() # eat ')'. + + return contents + +# primary ::= identifierexpr \| numberexpr \| parenexpr def +ParsePrimary(self): if isinstance(self.current, IdentifierToken): return +self.ParseIdentifierExpr() elif isinstance(self.current, NumberToken): +return self.ParseNumberExpr() elif self.current == CharacterToken('('): +return self.ParseParenExpr() else: raise RuntimeError('Unknown token +when expecting an expression.') + +# binoprhs ::= (operator primary)\* def ParseBinOpRHS(self, left, +left\_precedence): # If this is a binary operator, find its precedence. +while True: precedence = self.GetCurrentTokenPrecedence() + +:: + + # If this is a binary operator that binds at least as tightly as the + # current one, consume it; otherwise we are done. + if precedence < left_precedence: + return left + + binary_operator = self.current.char + self.Next() # eat the operator. + + # Parse the primary expression after the binary operator. + right = self.ParsePrimary() + + # If binary_operator binds less tightly with right than the operator after + # right, let the pending operator take right as its left. + next_precedence = self.GetCurrentTokenPrecedence() + if precedence < next_precedence: + right = self.ParseBinOpRHS(right, precedence + 1) + + # Merge left/right. + left = BinaryOperatorExpressionNode(binary_operator, left, right) + +# expression ::= primary binoprhs def ParseExpression(self): left = +self.ParsePrimary() return self.ParseBinOpRHS(left, 0) + +# prototype ::= id '(' id\* ')' def ParsePrototype(self): if not +isinstance(self.current, IdentifierToken): raise RuntimeError('Expected +function name in prototype.') + +:: + + function_name = self.current.name + self.Next() # eat function name. + + if self.current != CharacterToken('('): + raise RuntimeError('Expected "(" in prototype.') + self.Next() # eat '('. + + arg_names = [] + while isinstance(self.current, IdentifierToken): + arg_names.append(self.current.name) + self.Next() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")" in prototype.') + + # Success. + self.Next() # eat ')'. + + return PrototypeNode(function_name, arg_names) + +# definition ::= 'def' prototype expression def ParseDefinition(self): +self.Next() # eat def. proto = self.ParsePrototype() body = +self.ParseExpression() return FunctionNode(proto, body) + +# toplevelexpr ::= expression def ParseTopLevelExpr(self): proto = +PrototypeNode('', []) return FunctionNode(proto, self.ParseExpression()) + +# external ::= 'extern' prototype def ParseExtern(self): self.Next() # +eat extern. return self.ParsePrototype() + +# Top-Level parsing def HandleDefinition(self): +self.Handle(self.ParseDefinition, 'Parsed a function definition.') + +def HandleExtern(self): self.Handle(self.ParseExtern, 'Parsed an +extern.') + +def HandleTopLevelExpression(self): self.Handle(self.ParseTopLevelExpr, +'Parsed a top-level expression.') + +def Handle(self, function, message): try: function() print message +except Exception, e: print 'Error:', e try: self.Next() # Skip for error +recovery. except: pass + +Main driver code. +----------------- + +def main(): # Install standard binary operators. # 1 is lowest possible +precedence. 40 is the highest. operator\_precedence = { '<': 10, '+': +20, '-': 20, '\*': 40 } + +# Run the main "interpreter loop". while True: print 'ready>', try: raw += raw\_input() except KeyboardInterrupt: return + +:: + + parser = Parser(Tokenize(raw), operator_precedence) + while True: + # top ::= definition | external | expression | EOF + if isinstance(parser.current, EOFToken): + break + if isinstance(parser.current, DefToken): + parser.HandleDefinition() + elif isinstance(parser.current, ExternToken): + parser.HandleExtern() + else: + parser.HandleTopLevelExpression() + +if **name** == '**main**\ ': main() {% endhighlight %} + +-------------- + +**`Next: Implementing Code Generation to LLVM +IR `_** diff --git a/docs/source/doc/kaleidoscope/PythonLangImpl3.md b/docs/source/doc/kaleidoscope/PythonLangImpl3.md deleted file mode 100644 index 5045592..0000000 --- a/docs/source/doc/kaleidoscope/PythonLangImpl3.md +++ /dev/null @@ -1,1062 +0,0 @@ ---- -layout: page -title: "Kaleidoscope: Chapter 3" ---- - -# Code generation to LLVM IR - -Written by [Chris Lattner](mailto:sabre@nondot.org) -and [Max Shawabkeh](http://max99x.com) - - -**Chapter 3** - - -* This will become a table of contents (this text will be scraped). -{:toc} - - -**[Chapter 4: Adding JIT and Optimizer Support](PythonLangImpl4.html)** - - -# Introduction # {#intro} - -Welcome to Chapter 3 of the -[Implementing a language with LLVM](http://www.llvm.org/docs/tutorial/index.html) -tutorial. This chapter shows you how to transform the -[Abstract Syntax Tree](PythonLangImpl2.html), built in Chapter 2, into -LLVM IR. This will teach you a little bit about how LLVM does things, as well as -demonstrate how easy it is to use. It's much more work to build a lexer and -parser than it is to generate LLVM IR code. :) - - -**Please note**: the code in this chapter and later requires llvm-py 0.6 -and LLVM 2.7. Earlier versions will most likely not work with it. Also note -that you need to use a version of this tutorial that matches your llvm-py -release: If you are using an official llvm-py release, use the version of the -documentation on the [llvm-py examples page](http://www.mdevan.org/llvm-py/examples.html) - -* * * - -# Code Generation Setup # {#basics} - - -In order to generate LLVM IR, we want some simple setup to get started. First -we define code generation methods in each AST node class: - - -{% highlight python %} -# Expression class for numeric literals like "1.0". -class NumberExpressionNode(ExpressionNode): - - def __init__(self, value): - self.value = value - - def CodeGen(self): - ... - -# Expression class for referencing a variable, like "a". -class VariableExpressionNode(ExpressionNode): - - def __init__(self, name): - self.name = name - - def CodeGen(self): - ... - -... -{% endhighlight %} - - -The `CodeGen` method says to emit IR for that AST node along with all -the things it depends on, and they all return an LLVM Value object. "Value" is -the class used to represent a -"[Static Single Assignment (SSA)](http://en.wikipedia.org/wiki/Static_single_assignment_form) -register" or "SSA value" in LLVM. The most distinct aspect -of SSA values is that their value is computed as the related instruction -executes, and it does not get a new value until (and if) the instruction -re-executes. In other words, there is no way to "change" an SSA value. For -more information, please read up on -[Static Single Assignment](http://en.wikipedia.org/wiki/Static_single_assignment_form) - - the concepts are really quite natural once you grok them. - -We will also need to define some global variables which we will be used -during code generation: - - -{% highlight python %} -# The LLVM module, which holds all the IR code. -g_llvm_module = Module.new('my cool jit') - -# The LLVM instruction builder. Created whenever a new function is entered. -g_llvm_builder = None - -# A dictionary that keeps track of which values are defined in the current scope -# and what their LLVM representation is. -g_named_values = {} -{% endhighlight %} - - -`g_llvm_module` is the LLVM construct that contains all of the -functions and global variables in a chunk of code. In many ways, it is the -top-level structure that the LLVM IR uses to contain code. - -`g_llvm_builder` is a helper object that makes it easy to generate -LLVM instructions. Instances of the -[llvm.core.Builder](llvm.core.Builder.html) class keep track of the current place to insert -instructions and have methods to create new instructions. Note that we do not -initialize this variable; instead, it will be initialized whenever we start -generating code for a function. - -Finally, `g_named_values` is a dictionary that keeps track of which -values are defined in the current scope and what their LLVM representation is. -In other words, it is a symbol table for the code. In this form of -Kaleidoscope, the only things that can be referenced are function parameters. -As such, function parameters will be in this map when generating code for their -function body. - - -With these basics in place, we can start talking about how to generate code for -each expression. Note that this assumes that `g_llvm_builder` has been -set up to generate code *into* something. For now, we'll assume that -this has already been done, and we'll just use it to emit code. - - - - -* * * - - -# Expression Code Generation # {#exprs} - - -Generating LLVM code for expression nodes is very straightforward: less -than 35 lines of commented code for all four of our expression nodes. First -we'll do numeric literals: - - -{% highlight python %} - def CodeGen(self): - return Constant.real(Type.double(), self.value) -{% endhighlight %} - - -In llvm-py, floating point numeric constants are represented with the -`llvm.core.ConstantFP` class. To create one, we can use the static -`real()` method in the `llvm.core.Constant` class. This code -basically just creates and returns a `ConstantFP`. Note that in the LLVM -IR constants are all uniqued together and shared. For this reason, we create -the constant through a factory method instead of instantiating one directly. - - -{% highlight python %} - def CodeGen(self): - if self.name in g_named_values: - return g_named_values[self.name] - else: - raise RuntimeError('Unknown variable name: ' + self.name) -{% endhighlight %} - - -References to variables are also quite simple using LLVM. In the simple -version of Kaleidoscope, we assume that the variable has already been emitted -somewhere and its value is available. In practice, the only values that can be -in the `g_named_values` dictionary are function arguments. This code -simply checks to see that the specified name is in the map (if not, an unknown -variable is being referenced) and returns the value for it. In future chapters, -we'll add support for -[loop induction variables](PythonLangImpl5.html#for) in the symbol table, -and for [local variables](PythonLangImpl7.html#localvars). - -{% highlight python %} - def CodeGen(self): - left = self.left.CodeGen() - right = self.right.CodeGen() - - if self.operator == '+': - return g_llvm_builder.fadd(left, right, 'addtmp') - elif self.operator == '-': - return g_llvm_builder.fsub(left, right, 'subtmp') - elif self.operator == '*': - return g_llvm_builder.fmul(left, right, 'multmp') - elif self.operator == '<': - result = g_llvm_builder.fcmp(FCMP_ULT, left, right, 'cmptmp') - # Convert bool 0 or 1 to double 0.0 or 1.0. - return g_llvm_builder.uitofp(result, Type.double(), 'booltmp') - else: - raise RuntimeError('Unknown binary operator.') -{% endhighlight %} - - -Binary operators start to get more interesting. The basic idea here is that -we recursively emit code for the left-hand side of the expression, then the -right-hand side, then we compute the result of the binary expression depending -on which operator is being used. - - -In the example above, the LLVM builder class is starting to show its value. -`g_llvm_builder` knows where to insert the newly created instruction, all -you have to do is specify what instruction to create (e.g. with `add`), -which operands to use (`left` and `right` here) and optionally -provide a name for the generated instruction. - -One nice thing about LLVM is that the name is just a hint. For instance, if -the code above emits multiple "addtmp" variables, LLVM will automatically -provide each one with an increasing, unique numeric suffix. Local value names -for instructions are purely optional, but it makes it much easier to read the -IR dumps. - -[LLVM instructions](http://www.llvm.org/docs/LangRef.html#instref) -are constrained by strict rules: for example, the Left and Right operators of -an [add instruction](http://www.llvm.org/docs/LangRef.html#i_add) -must have the same type, and the result type of the add must match the operand -types. Because all values in Kaleidoscope are doubles, this makes for very -simple code for add, sub and mul. - -On the other hand, LLVM specifies that the -[fcmp instruction](http://www.llvm.org/docs/LangRef.html#i_fcmp) always -returns an 'i1' value (a one bit integer). The problem with this is that -Kaleidoscope wants the value to be a 0.0 or 1.0 value. In order to get these -semantics, we combine the fcmp instruction with a -[uitofp instruction](http://www.llvm.org/docs/LangRef.html#i_uitofp). -This instruction converts its input integer into a floating point value by -treating the input as an unsigned value. In contrast, if we used the -[sitofp instruction](http://www.llvm.org/docs/LangRef.html#i_sitofp), -the Kaleidoscope `<` operator would return 0.0 and -1.0, depending on the -input value. - - -{% highlight python %} - def CodeGen(self): - # Look up the name in the global module table. - callee = g_llvm_module.get_function_named(self.callee) - - # Check for argument mismatch error. - if len(callee.args) != len(self.args): - raise RuntimeError('Incorrect number of arguments passed.') - - arg_values = [i.CodeGen() for i in self.args] - - return g_llvm_builder.call(callee, arg_values, 'calltmp') -{% endhighlight %} - - -Code generation for function calls is quite straightforward with LLVM. The -code above initially does a function name lookup in the LLVM Module's symbol -table. Recall that the LLVM Module is the container that holds all of the -functions we are JIT'ing. By giving each function the same name as what the -user specifies, we can use the LLVM symbol table to resolve function names for -us. - -Once we have the function to call, we codegen each argument that is to be -passed in, and create an LLVM -[call instruction](http://www.llvm.org/docs/LangRef.html#i_call). -Note that LLVM uses the native C calling conventions by default, allowing these -calls to also call into standard library functions like "sin" and "cos", with no -additional effort. - -This wraps up our handling of the four basic expressions that we have so far -in Kaleidoscope. Feel free to go in and add some more. For example, by -browsing the [LLVM language reference](http://www.llvm.org/docs/LangRef.html) -you'll find several other interesting instructions that are really -easy to plug into our basic framework. - - -* * * - - -# Function Code Generation # {#funcs} - - -Code generation for prototypes and functions must handle a number of -details, which make their code less beautiful than expression code -generation, but allows us to illustrate some important points. First, let's -talk about code generation for prototypes: they are used both for function -bodies and external function declarations. The code starts with: - - -{% highlight python %} - def CodeGen(self): - # Make the function type, eg. double(double,double). - funct_type = Type.function( - Type.double(), [Type.double()] * len(self.args), False) - - function = Function.new(g_llvm_module, funct_type, self.name) -{% endhighlight %} - - -The call to `Type.function` creates the `FunctionType` that -should be used for a given Prototype. Since all function arguments in -Kaleidoscope are of type double, the first line creates a list of "N" LLVM -double types. It then uses the `Type.function` method to create a -function type that takes "N" doubles as arguments, returns one double as a -result, and that is not vararg (the False parameter indicates this). Note that -Types in LLVM are uniqued just like Constants are, so you don't instantiate them -directly. - -The final line above actually creates the function that the prototype will -correspond to. This indicates the type and name to use, as well as which -module to insert into. Note that by default, the function will have -[external linkage]( 4+5 -Read a top-level expression: -define double @0() { -entry: - ret double 9.000000e+00 -} -{% endhighlight %} - - -Note how the parser turns the top-level expression into anonymous functions -for us. This will be handy when we add JIT -support in the next chapter. Also note that the code is very literally -transcribed, no optimizations are being performed except simple constant -folding done by the Builder. We will -add optimizations explicitly -in the next chapter. - - -{% highlight bash %} -ready> def foo(a b) a*a + 2*a*b + b*b -Read a function definition: -define double @foo(double %a, double %b) { -entry: - %multmp = fmul double %a, %a ; [#uses=1] - %multmp1 = fmul double 2.000000e+00, %a ; [#uses=1] - %multmp2 = fmul double %multmp1, %b ; [#uses=1] - %addtmp = fadd double %multmp, %multmp2 ; [#uses=1] - %multmp3 = fmul double %b, %b ; [#uses=1] - %addtmp4 = fadd double %addtmp, %multmp3 ; [#uses=1] - ret double %addtmp4 -} -{% endhighlight %} - - -This shows some simple arithmetic. Notice the striking similarity to the -LLVM builder calls that we use to create the instructions. - - -{% highlight bash %} -ready> def bar(a) foo(a, 4.0) + bar(31337) -Read a function definition: -define double @bar(double %a) { -entry: - %calltmp = call double @foo(double %a, double 4.000000e+00) ; [#uses=1] - %calltmp1 = call double @bar(double 3.133700e+04) ; [#uses=1] - %addtmp = fadd double %calltmp, %calltmp1 ; [#uses=1] - ret double %addtmp -} -{% endhighlight %} - - -This shows some function calls. Note that this function will take a long -time to execute if you call it. In the future we'll add conditional control -flow to actually make recursion useful :). - - -{% highlight bash %} -ready> extern cos(x) -Read extern: -declare double @cos(double) - -ready> cos(1.234) -Read a top-level expression: -define double @1() { -entry: - %calltmp = call double @cos(double 1.234000e+00) ; [#uses=1] - ret double %calltmp -} -{% endhighlight %} - - -This shows an extern for the libm "cos" function, and a call to it. - - - -{% highlight bash %} -ready> ^C -; ModuleID = 'my cool jit' - -define double @0() { -entry: - ret double 9.000000e+00 -} - -define double @foo(double %a, double %b) { -entry: - %multmp = fmul double %a, %a ; [#uses=1] - %multmp1 = fmul double 2.000000e+00, %a ; [#uses=1] - %multmp2 = fmul double %multmp1, %b ; [#uses=1] - %addtmp = fadd double %multmp, %multmp2 ; [#uses=1] - %multmp3 = fmul double %b, %b ; [#uses=1] - %addtmp4 = fadd double %addtmp, %multmp3 ; [#uses=1] - ret double %addtmp4 -} - -define double @bar(double %a) { -entry: - %calltmp = call double @foo(double %a, double 4.000000e+00) ; [#uses=1] - %calltmp1 = call double @bar(double 3.133700e+04) ; [#uses=1] - %addtmp = fadd double %calltmp, %calltmp1 ; [#uses=1] - ret double %addtmp -} - -declare double @cos(double) - -define double @1() { -entry: - %calltmp = call double @cos(double 1.234000e+00) ; [#uses=1] - ret double %calltmp -} -{% endhighlight %} - - -When you quit the current demo, it dumps out the IR for the entire module -generated. Here you can see the big picture with all the functions referencing -each other. - -This wraps up the third chapter of the Kaleidoscope tutorial. Up next, we'll -describe how to [add JIT codegen and optimizer support](PythonLangImpl4.html) -to this so we can actually start running code! - - - - -* * * - - -# Full Code Listing # {#code} - -Here is the complete code listing for our running example, enhanced with the -LLVM code generator. Because this uses the llvm-py libraries, you need to -[download](../download.html) and -[install](../userguide.html#install) them. - - - -{% highlight python %} -#!/usr/bin/env python - -import re -from llvm.core import Module, Constant, Type, Function, Builder, FCMP_ULT - -################################################################################ -## Globals -################################################################################ - -# The LLVM module, which holds all the IR code. -g_llvm_module = Module.new('my cool jit') - -# The LLVM instruction builder. Created whenever a new function is entered. -g_llvm_builder = None - -# A dictionary that keeps track of which values are defined in the current scope -# and what their LLVM representation is. -g_named_values = {} - -################################################################################ -## Lexer -################################################################################ - -# The lexer yields one of these types for each token. -class EOFToken(object): - pass - -class DefToken(object): - pass - -class ExternToken(object): - pass - -class IdentifierToken(object): - def __init__(self, name): self.name = name - -class NumberToken(object): - def __init__(self, value): self.value = value - -class CharacterToken(object): - def __init__(self, char): self.char = char - def __eq__(self, other): - return isinstance(other, CharacterToken) and self.char == other.char - def __ne__(self, other): return not self == other - -# Regular expressions that tokens and comments of our language. -REGEX_NUMBER = re.compile('[0-9]+(?:\.[0-9]+)?') -REGEX_IDENTIFIER = re.compile('[a-zA-Z][a-zA-Z0-9]*') -REGEX_COMMENT = re.compile('#.*') - -def Tokenize(string): - while string: - # Skip whitespace. - if string[0].isspace(): - string = string[1:] - continue - - # Run regexes. - comment_match = REGEX_COMMENT.match(string) - number_match = REGEX_NUMBER.match(string) - identifier_match = REGEX_IDENTIFIER.match(string) - - # Check if any of the regexes matched and yield the appropriate result. - if comment_match: - comment = comment_match.group(0) - string = string[len(comment):] - elif number_match: - number = number_match.group(0) - yield NumberToken(float(number)) - string = string[len(number):] - elif identifier_match: - identifier = identifier_match.group(0) - # Check if we matched a keyword. - if identifier == 'def': - yield DefToken() - elif identifier == 'extern': - yield ExternToken() - else: - yield IdentifierToken(identifier) - string = string[len(identifier):] - else: - # Yield the ASCII value of the unknown character. - yield CharacterToken(string[0]) - string = string[1:] - - yield EOFToken() - -################################################################################ -## Abstract Syntax Tree (aka Parse Tree) -################################################################################ - -# Base class for all expression nodes. -class ExpressionNode(object): - pass - -# Expression class for numeric literals like "1.0". -class NumberExpressionNode(ExpressionNode): - - def __init__(self, value): - self.value = value - - def CodeGen(self): - return Constant.real(Type.double(), self.value) - -# Expression class for referencing a variable, like "a". -class VariableExpressionNode(ExpressionNode): - - def __init__(self, name): - self.name = name - - def CodeGen(self): - if self.name in g_named_values: - return g_named_values[self.name] - else: - raise RuntimeError('Unknown variable name: ' + self.name) - -# Expression class for a binary operator. -class BinaryOperatorExpressionNode(ExpressionNode): - - def __init__(self, operator, left, right): - self.operator = operator - self.left = left - self.right = right - - def CodeGen(self): - left = self.left.CodeGen() - right = self.right.CodeGen() - - if self.operator == '+': - return g_llvm_builder.fadd(left, right, 'addtmp') - elif self.operator == '-': - return g_llvm_builder.fsub(left, right, 'subtmp') - elif self.operator == '*': - return g_llvm_builder.fmul(left, right, 'multmp') - elif self.operator == '<': - result = g_llvm_builder.fcmp(FCMP_ULT, left, right, 'cmptmp') - # Convert bool 0 or 1 to double 0.0 or 1.0. - return g_llvm_builder.uitofp(result, Type.double(), 'booltmp') - else: - raise RuntimeError('Unknown binary operator.') - -# Expression class for function calls. -class CallExpressionNode(ExpressionNode): - - def __init__(self, callee, args): - self.callee = callee - self.args = args - - def CodeGen(self): - # Look up the name in the global module table. - callee = g_llvm_module.get_function_named(self.callee) - - # Check for argument mismatch error. - if len(callee.args) != len(self.args): - raise RuntimeError('Incorrect number of arguments passed.') - - arg_values = [i.CodeGen() for i in self.args] - - return g_llvm_builder.call(callee, arg_values, 'calltmp') - -# This class represents the "prototype" for a function, which captures its name, -# and its argument names (thus implicitly the number of arguments the function -# takes). -class PrototypeNode(object): - - def __init__(self, name, args): - self.name = name - self.args = args - - def CodeGen(self): - # Make the function type, eg. double(double,double). - funct_type = Type.function( - Type.double(), [Type.double()] * len(self.args), False) - - function = Function.new(g_llvm_module, funct_type, self.name) - - # If the name conflicted, there was already something with the same name. - # If it has a body, don't allow redefinition or reextern. - if function.name != self.name: - function.delete() - function = g_llvm_module.get_function_named(self.name) - - # If the function already has a body, reject this. - if not function.is_declaration: - raise RuntimeError('Redefinition of function.') - - # If F took a different number of args, reject. - if len(callee.args) != len(self.args): - raise RuntimeError('Redeclaration of a function with different number ' - 'of args.') - - # Set names for all arguments and add them to the variables symbol table. - for arg, arg_name in zip(function.args, self.args): - arg.name = arg_name - # Add arguments to variable symbol table. - g_named_values[arg_name] = arg - - return function - -# This class represents a function definition itself. -class FunctionNode(object): - - def __init__(self, prototype, body): - self.prototype = prototype - self.body = body - - def CodeGen(self): - # Clear scope. - g_named_values.clear() - - # Create a function object. - function = self.prototype.CodeGen() - - # Create a new basic block to start insertion into. - block = function.append_basic_block('entry') - global g_llvm_builder - g_llvm_builder = Builder.new(block) - - # Finish off the function. - try: - return_value = self.body.CodeGen() - g_llvm_builder.ret(return_value) - - # Validate the generated code, checking for consistency. - function.verify() - except: - function.delete() - raise - - return function - - -################################################################################ -## Parser -################################################################################ - -class Parser(object): - - def __init__(self, tokens, binop_precedence): - self.tokens = tokens - self.binop_precedence = binop_precedence - self.Next() - - # Provide a simple token buffer. Parser.current is the current token the - # parser is looking at. Parser.Next() reads another token from the lexer and - # updates Parser.current with its results. - def Next(self): - self.current = self.tokens.next() - - # Gets the precedence of the current token, or -1 if the token is not a binary - # operator. - def GetCurrentTokenPrecedence(self): - if isinstance(self.current, CharacterToken): - return self.binop_precedence.get(self.current.char, -1) - else: - return -1 - - # identifierexpr ::= identifier | identifier '(' expression* ')' - def ParseIdentifierExpr(self): - identifier_name = self.current.name - self.Next() # eat identifier. - - if self.current != CharacterToken('('): # Simple variable reference. - return VariableExpressionNode(identifier_name) - - # Call. - self.Next() # eat '('. - args = [] - if self.current != CharacterToken(')'): - while True: - args.append(self.ParseExpression()) - if self.current == CharacterToken(')'): - break - elif self.current != CharacterToken(','): - raise RuntimeError('Expected ")" or "," in argument list.') - self.Next() - - self.Next() # eat ')'. - return CallExpressionNode(identifier_name, args) - - # numberexpr ::= number - def ParseNumberExpr(self): - result = NumberExpressionNode(self.current.value) - self.Next() # consume the number. - return result - - # parenexpr ::= '(' expression ')' - def ParseParenExpr(self): - self.Next() # eat '('. - - contents = self.ParseExpression() - - if self.current != CharacterToken(')'): - raise RuntimeError('Expected ")".') - self.Next() # eat ')'. - - return contents - - # primary ::= identifierexpr | numberexpr | parenexpr - def ParsePrimary(self): - if isinstance(self.current, IdentifierToken): - return self.ParseIdentifierExpr() - elif isinstance(self.current, NumberToken): - return self.ParseNumberExpr() - elif self.current == CharacterToken('('): - return self.ParseParenExpr() - else: - raise RuntimeError('Unknown token when expecting an expression.') - - # binoprhs ::= (operator primary)* - def ParseBinOpRHS(self, left, left_precedence): - # If this is a binary operator, find its precedence. - while True: - precedence = self.GetCurrentTokenPrecedence() - - # If this is a binary operator that binds at least as tightly as the - # current one, consume it; otherwise we are done. - if precedence < left_precedence: - return left - - binary_operator = self.current.char - self.Next() # eat the operator. - - # Parse the primary expression after the binary operator. - right = self.ParsePrimary() - - # If binary_operator binds less tightly with right than the operator after - # right, let the pending operator take right as its left. - next_precedence = self.GetCurrentTokenPrecedence() - if precedence < next_precedence: - right = self.ParseBinOpRHS(right, precedence + 1) - - # Merge left/right. - left = BinaryOperatorExpressionNode(binary_operator, left, right) - - # expression ::= primary binoprhs - def ParseExpression(self): - left = self.ParsePrimary() - return self.ParseBinOpRHS(left, 0) - - # prototype ::= id '(' id* ')' - def ParsePrototype(self): - if not isinstance(self.current, IdentifierToken): - raise RuntimeError('Expected function name in prototype.') - - function_name = self.current.name - self.Next() # eat function name. - - if self.current != CharacterToken('('): - raise RuntimeError('Expected "(" in prototype.') - self.Next() # eat '('. - - arg_names = [] - while isinstance(self.current, IdentifierToken): - arg_names.append(self.current.name) - self.Next() - - if self.current != CharacterToken(')'): - raise RuntimeError('Expected ")" in prototype.') - - # Success. - self.Next() # eat ')'. - - return PrototypeNode(function_name, arg_names) - - # definition ::= 'def' prototype expression - def ParseDefinition(self): - self.Next() # eat def. - proto = self.ParsePrototype() - body = self.ParseExpression() - return FunctionNode(proto, body) - - # toplevelexpr ::= expression - def ParseTopLevelExpr(self): - proto = PrototypeNode('', []) - return FunctionNode(proto, self.ParseExpression()) - - # external ::= 'extern' prototype - def ParseExtern(self): - self.Next() # eat extern. - return self.ParsePrototype() - - # Top-Level parsing - def HandleDefinition(self): - self.Handle(self.ParseDefinition, 'Read a function definition:') - - def HandleExtern(self): - self.Handle(self.ParseExtern, 'Read an extern:') - - def HandleTopLevelExpression(self): - self.Handle(self.ParseTopLevelExpr, 'Read a top-level expression:') - - def Handle(self, function, message): - try: - print message, function().CodeGen() - except Exception, e: - print 'Error:', e - try: - self.Next() # Skip for error recovery. - except: - pass - -################################################################################ -## Main driver code. -################################################################################ - -def main(): - # Install standard binary operators. - # 1 is lowest possible precedence. 40 is the highest. - operator_precedence = { - '<': 10, - '+': 20, - '-': 20, - '*': 40 - } - - # Run the main "interpreter loop". - while True: - print 'ready>', - try: - raw = raw_input() - except KeyboardInterrupt: - break - - parser = Parser(Tokenize(raw), operator_precedence) - while True: - # top ::= definition | external | expression | EOF - if isinstance(parser.current, EOFToken): - break - if isinstance(parser.current, DefToken): - parser.HandleDefinition() - elif isinstance(parser.current, ExternToken): - parser.HandleExtern() - else: - parser.HandleTopLevelExpression() - - # Print out all of the generated code. - print '\n', g_llvm_module - -if __name__ == '__main__': - main() -{% endhighlight %} - -* * * - -**[Next: Adding JIT and Optimizer Support](PythonLangImpl4.html)** - diff --git a/docs/source/doc/kaleidoscope/PythonLangImpl3.rst b/docs/source/doc/kaleidoscope/PythonLangImpl3.rst new file mode 100644 index 0000000..7679c8c --- /dev/null +++ b/docs/source/doc/kaleidoscope/PythonLangImpl3.rst @@ -0,0 +1,936 @@ ++------------------------------------+ +| layout: page | ++------------------------------------+ +| title: "Kaleidoscope: Chapter 3" | ++------------------------------------+ + +Code generation to LLVM IR +========================== + +Written by `Chris Lattner `_ and `Max +Shawabkeh `_ + +**Chapter 3** + +- This will become a table of contents (this text will be scraped). + {:toc} + +**`Chapter 4: Adding JIT and Optimizer +Support `_** + +Introduction # {#intro} +======================= + +Welcome to Chapter 3 of the `Implementing a language with +LLVM `_ tutorial. This +chapter shows you how to transform the `Abstract Syntax +Tree `_, built in Chapter 2, into LLVM IR. This +will teach you a little bit about how LLVM does things, as well as +demonstrate how easy it is to use. It's much more work to build a lexer +and parser than it is to generate LLVM IR code. :) + +**Please note**: the code in this chapter and later requires llvm-py 0.6 +and LLVM 2.7. Earlier versions will most likely not work with it. Also +note that you need to use a version of this tutorial that matches your +llvm-py release: If you are using an official llvm-py release, use the +version of the documentation on the `llvm-py examples +page `_ + +-------------- + +Code Generation Setup # {#basics} +================================= + +In order to generate LLVM IR, we want some simple setup to get started. +First we define code generation methods in each AST node class: + +{% highlight python %} # Expression class for numeric literals like +"1.0". class NumberExpressionNode(ExpressionNode): + +def **init**\ (self, value): self.value = value + +def CodeGen(self): ... + +Expression class for referencing a variable, like "a". +====================================================== + +class VariableExpressionNode(ExpressionNode): + +def **init**\ (self, name): self.name = name + +def CodeGen(self): ... + +... {% endhighlight %} + +The ``CodeGen`` method says to emit IR for that AST node along with all +the things it depends on, and they all return an LLVM Value object. +"Value" is the class used to represent a "`Static Single Assignment +(SSA) `_ +register" or "SSA value" in LLVM. The most distinct aspect of SSA values +is that their value is computed as the related instruction executes, and +it does not get a new value until (and if) the instruction re-executes. +In other words, there is no way to "change" an SSA value. For more +information, please read up on `Static Single +Assignment `_ +- the concepts are really quite natural once you grok them. + +We will also need to define some global variables which we will be used +during code generation: + +{% highlight python %} # The LLVM module, which holds all the IR code. +g\_llvm\_module = Module.new('my cool jit') + +The LLVM instruction builder. Created whenever a new function is entered. +========================================================================= + +g\_llvm\_builder = None + +A dictionary that keeps track of which values are defined in the current scope +============================================================================== + +and what their LLVM representation is. +====================================== + +g\_named\_values = {} {% endhighlight %} + +``g_llvm_module`` is the LLVM construct that contains all of the +functions and global variables in a chunk of code. In many ways, it is +the top-level structure that the LLVM IR uses to contain code. + +``g_llvm_builder`` is a helper object that makes it easy to generate +LLVM instructions. Instances of the +`llvm.core.Builder `_ class keep track of the +current place to insert instructions and have methods to create new +instructions. Note that we do not initialize this variable; instead, it +will be initialized whenever we start generating code for a function. + +Finally, ``g_named_values`` is a dictionary that keeps track of which +values are defined in the current scope and what their LLVM +representation is. In other words, it is a symbol table for the code. In +this form of Kaleidoscope, the only things that can be referenced are +function parameters. As such, function parameters will be in this map +when generating code for their function body. + +With these basics in place, we can start talking about how to generate +code for each expression. Note that this assumes that ``g_llvm_builder`` +has been set up to generate code *into* something. For now, we'll assume +that this has already been done, and we'll just use it to emit code. + +-------------- + +Expression Code Generation # {#exprs} +===================================== + +Generating LLVM code for expression nodes is very straightforward: less +than 35 lines of commented code for all four of our expression nodes. +First we'll do numeric literals: + +{% highlight python %} def CodeGen(self): return +Constant.real(Type.double(), self.value) {% endhighlight %} + +In llvm-py, floating point numeric constants are represented with the +``llvm.core.ConstantFP`` class. To create one, we can use the static +``real()`` method in the ``llvm.core.Constant`` class. This code +basically just creates and returns a ``ConstantFP``. Note that in the +LLVM IR constants are all uniqued together and shared. For this reason, +we create the constant through a factory method instead of instantiating +one directly. + +{% highlight python %} def CodeGen(self): if self.name in +g\_named\_values: return g\_named\_values[self.name] else: raise +RuntimeError('Unknown variable name: ' + self.name) {% endhighlight %} + +References to variables are also quite simple using LLVM. In the simple +version of Kaleidoscope, we assume that the variable has already been +emitted somewhere and its value is available. In practice, the only +values that can be in the ``g_named_values`` dictionary are function +arguments. This code simply checks to see that the specified name is in +the map (if not, an unknown variable is being referenced) and returns +the value for it. In future chapters, we'll add support for `loop +induction variables `_ in the symbol table, +and for `local variables `_. + +{% highlight python %} def CodeGen(self): left = self.left.CodeGen() +right = self.right.CodeGen() + +:: + + if self.operator == '+': + return g_llvm_builder.fadd(left, right, 'addtmp') + elif self.operator == '-': + return g_llvm_builder.fsub(left, right, 'subtmp') + elif self.operator == '*': + return g_llvm_builder.fmul(left, right, 'multmp') + elif self.operator == '<': + result = g_llvm_builder.fcmp(FCMP_ULT, left, right, 'cmptmp') + # Convert bool 0 or 1 to double 0.0 or 1.0. + return g_llvm_builder.uitofp(result, Type.double(), 'booltmp') + else: + raise RuntimeError('Unknown binary operator.') + +{% endhighlight %} + +Binary operators start to get more interesting. The basic idea here is +that we recursively emit code for the left-hand side of the expression, +then the right-hand side, then we compute the result of the binary +expression depending on which operator is being used. + +In the example above, the LLVM builder class is starting to show its +value. ``g_llvm_builder`` knows where to insert the newly created +instruction, all you have to do is specify what instruction to create +(e.g. with ``add``), which operands to use (``left`` and ``right`` here) +and optionally provide a name for the generated instruction. + +One nice thing about LLVM is that the name is just a hint. For instance, +if the code above emits multiple "addtmp" variables, LLVM will +automatically provide each one with an increasing, unique numeric +suffix. Local value names for instructions are purely optional, but it +makes it much easier to read the IR dumps. + +`LLVM instructions `_ are +constrained by strict rules: for example, the Left and Right operators +of an `add instruction `_ +must have the same type, and the result type of the add must match the +operand types. Because all values in Kaleidoscope are doubles, this +makes for very simple code for add, sub and mul. + +On the other hand, LLVM specifies that the `fcmp +instruction `_ always +returns an 'i1' value (a one bit integer). The problem with this is that +Kaleidoscope wants the value to be a 0.0 or 1.0 value. In order to get +these semantics, we combine the fcmp instruction with a `uitofp +instruction `_. This +instruction converts its input integer into a floating point value by +treating the input as an unsigned value. In contrast, if we used the +`sitofp instruction `_, +the Kaleidoscope ``<`` operator would return 0.0 and -1.0, depending on +the input value. + +{% highlight python %} def CodeGen(self): # Look up the name in the +global module table. callee = +g\_llvm\_module.get\_function\_named(self.callee) + +:: + + # Check for argument mismatch error. + if len(callee.args) != len(self.args): + raise RuntimeError('Incorrect number of arguments passed.') + + arg_values = [i.CodeGen() for i in self.args] + + return g_llvm_builder.call(callee, arg_values, 'calltmp') + +{% endhighlight %} + +Code generation for function calls is quite straightforward with LLVM. +The code above initially does a function name lookup in the LLVM +Module's symbol table. Recall that the LLVM Module is the container that +holds all of the functions we are JIT'ing. By giving each function the +same name as what the user specifies, we can use the LLVM symbol table +to resolve function names for us. + +Once we have the function to call, we codegen each argument that is to +be passed in, and create an LLVM `call +instruction `_. Note that +LLVM uses the native C calling conventions by default, allowing these +calls to also call into standard library functions like "sin" and "cos", +with no additional effort. + +This wraps up our handling of the four basic expressions that we have so +far in Kaleidoscope. Feel free to go in and add some more. For example, +by browsing the `LLVM language +reference `_ you'll find several +other interesting instructions that are really easy to plug into our +basic framework. + +-------------- + +Function Code Generation # {#funcs} +=================================== + +Code generation for prototypes and functions must handle a number of +details, which make their code less beautiful than expression code +generation, but allows us to illustrate some important points. First, +let's talk about code generation for prototypes: they are used both for +function bodies and external function declarations. The code starts +with: + +{% highlight python %} def CodeGen(self): # Make the function type, eg. +double(double,double). funct\_type = Type.function( Type.double(), +[Type.double()] \* len(self.args), False) + +:: + + function = Function.new(g_llvm_module, funct_type, self.name) + +{% endhighlight %} + +The call to ``Type.function`` creates the ``FunctionType`` that should +be used for a given Prototype. Since all function arguments in +Kaleidoscope are of type double, the first line creates a list of "N" +LLVM double types. It then uses the ``Type.function`` method to create a +function type that takes "N" doubles as arguments, returns one double as +a result, and that is not vararg (the False parameter indicates this). +Note that Types in LLVM are uniqued just like Constants are, so you +don't instantiate them directly. + +The final line above actually creates the function that the prototype +will correspond to. This indicates the type and name to use, as well as +which module to insert into. Note that by default, the function will +have `external +linkage <`_, which means +that the function may be defined outside the current module and/or that +it is callable by functions outside the module. The name passed in is +the name the user specified: since ``g_llvm_module`` is specified, this +name is registered in ``g_llvm_module``'s symbol table, which is used by +the function call code above. + +{% highlight python %} # If the name conflicted, there was already +something with the same name. # If it has a body, don't allow +redefinition or reextern. if function.name != self.name: +function.delete() function = +g\_llvm\_module.get\_function\_named(self.name) {% endhighlight %} + +The Module symbol table works just like the Function symbol table when +it comes to name conflicts: if a new function is created with a name was +previously added to the symbol table, it will get implicitly renamed +when added to the Module. The code above exploits this fact to determine +if there was a previous definition of this function. + +In Kaleidoscope, we choose to allow redefinitions of functions in two +cases: first, we want to allow 'extern'ing a function more than once, as +long as the prototypes for the externs match (since all arguments have +the same type, we just have to check that the number of arguments +match). Second, we want to allow 'extern'ing a function and then +defining a body for it. This is useful when defining mutually recursive +functions. + +In order to implement this, the code above first checks to see if there +is a collision on the name of the function. If so, it deletes the +function we just created (by calling ``delete``) and then calling +``get_function_named`` to get the existing function with the specified +name. + +{% highlight python %} # If the function already has a body, reject +this. if not function.is\_declaration: raise RuntimeError('Redefinition +of function.') + +:: + + # If F took a different number of args, reject. + if len(callee.args) != len(self.args): + raise RuntimeError('Redeclaration of a function with different number ' + 'of args.') + +{% endhighlight %} + +In order to verify the logic above, we first check to see if the +pre-existing function is a forward declaration. Since we don't allow +anything after a full definition of the function, the code rejects this +case. If the previous reference to a function was an 'extern', we simply +verify that the number of arguments for that definition and this one +match up. If not, we emit an error. + +{% highlight python %} # Set names for all arguments and add them to the +variables symbol table. for arg, arg\_name in zip(function.args, +self.args): arg.name = arg\_name # Add arguments to variable symbol +table. g\_named\_values[arg\_name] = arg + +:: + + return function + +{% endhighlight %} + +The last bit of code for prototypes loops over all of the arguments in +the function, setting the name of the LLVM Argument objects to match, +and registering the arguments in the ``g_named_values`` map for future +use by the ``VariableExpressionNode``. Note that we don't check for +conflicting argument names here (e.g. "extern foo(a b a)"). Doing so +would be very straight-forward with the mechanics we have already used +above. Once this is all set up, it returns the Function object to the +caller. + +{% highlight python %} def CodeGen(self): # Clear scope. +g\_named\_values.clear() + +:: + + # Create a function object. + function = self.prototype.CodeGen() + +{% endhighlight %} + +Code generation for function definitions starts out simply enough: we +just clear out the ``g_named_values`` dictionary to make sure that there +isn't anything in it from the last function we compiled and codegen the +prototype. Code generation of the prototype ensures that there is an +LLVM Function object that is ready to go for us. + +{% highlight python %} # Create a new basic block to start insertion +into. block = function.append\_basic\_block('entry') global +g\_llvm\_builder g\_llvm\_builder = Builder.new(block) {% endhighlight +%} + +Now we get to the point where ``g_llvm_builder`` is set up. The first +line creates a new `basic +block `_ (named "entry"), +which is inserted into the function. The second line declares that the +global ``g_llvm_builder`` object is to be changed. The last line creates +a new builder that is set up to insert new instructions into the basic +block we just created. Basic blocks in LLVM are an important part of +functions that define the `Control Flow +Graph `_. Since we +don't have any control flow, our functions will only contain one block +at this point. We'll fix this in `Chapter 5 `_ :). + +{% highlight python %} # Finish off the function. try: return\_value = +self.body.CodeGen() g\_llvm\_builder.ret(return\_value) + +:: + + # Validate the generated code, checking for consistency. + function.verify() + +{% endhighlight %} + +Once the insertion point is set up, we call the ``CodeGen`` method for +the root expression of the function. If no error happens, this emits +code to compute the expression into the entry block and returns the +value that was computed. Assuming no error, we then create an LLVM `ret +instruction `_, which +completes the function. Once the function is built, we call ``verify``, +which is provided by LLVM. This function does a variety of consistency +checks on the generated code, to determine if our compiler is doing +everything right. Using this is important: it can catch a lot of bugs. +Once the function is finished and validated, we return it. + +{% highlight python %} except: function.delete() raise + +:: + + return function + +{% endhighlight %} + +The only piece left here is handling of the error case. For simplicity, +we handle this by merely deleting the function we produced with the +``delete`` method. This allows the user to redefine a function that they +incorrectly typed in before: if we didn't delete it, it would live in +the symbol table, with a body, preventing future redefinition. + +This code does have a bug, though. Since the ``PrototypeNode::CodeGen`` +can return a previously defined forward declaration, our code can +actually delete a forward declaration. There are a number of ways to fix +this bug; see what you can come up with! Here is a testcase: + +{% highlight python %} extern foo(a b) # ok, defines foo. def foo(a b) c +# error, 'c' is invalid. def bar() foo(1, 2) # error, unknown function +"foo" {% endhighlight %} + +-------------- + +Driver Changes and Closing Thoughts # {#driver} +=============================================== + +For now, code generation to LLVM doesn't really get us much, except that +we can look at the pretty IR calls. The sample code inserts calls to +CodeGen into the ``Handle*`` functions, and then dumps out the LLVM IR. +This gives a nice way to look at the LLVM IR for simple functions. For +example: + +{% highlight bash %} ready> 4+5 Read a top-level expression: define +double @0() { entry: ret double 9.000000e+00 } {% endhighlight %} + +Note how the parser turns the top-level expression into anonymous +functions for us. This will be handy when we add JIT support in the next +chapter. Also note that the code is very literally transcribed, no +optimizations are being performed except simple constant folding done by +the Builder. We will add optimizations explicitly in the next chapter. + +{% highlight bash %} ready> def foo(a b) a\ *a + 2*\ a\ *b + b*\ b Read +a function definition: define double @foo(double %a, double %b) { entry: +%multmp = fmul double %a, %a ; [#uses=1] %multmp1 = fmul double +2.000000e+00, %a ; [#uses=1] %multmp2 = fmul double %multmp1, %b ; +[#uses=1] %addtmp = fadd double %multmp, %multmp2 ; [#uses=1] %multmp3 = +fmul double %b, %b ; [#uses=1] %addtmp4 = fadd double %addtmp, %multmp3 +; [#uses=1] ret double %addtmp4 } {% endhighlight %} + +This shows some simple arithmetic. Notice the striking similarity to the +LLVM builder calls that we use to create the instructions. + +{% highlight bash %} ready> def bar(a) foo(a, 4.0) + bar(31337) Read a +function definition: define double @bar(double %a) { entry: %calltmp = +call double @foo(double %a, double 4.000000e+00) ; [#uses=1] %calltmp1 = +call double @bar(double 3.133700e+04) ; [#uses=1] %addtmp = fadd double +%calltmp, %calltmp1 ; [#uses=1] ret double %addtmp } {% endhighlight %} + +This shows some function calls. Note that this function will take a long +time to execute if you call it. In the future we'll add conditional +control flow to actually make recursion useful :). + +{% highlight bash %} ready> extern cos(x) Read extern: declare double +@cos(double) + +ready> cos(1.234) Read a top-level expression: define double @1() { +entry: %calltmp = call double @cos(double 1.234000e+00) ; [#uses=1] ret +double %calltmp } {% endhighlight %} + +This shows an extern for the libm "cos" function, and a call to it. + +{% highlight bash %} ready> ^C ; ModuleID = 'my cool jit' + +define double @0() { entry: ret double 9.000000e+00 } + +define double @foo(double %a, double %b) { entry: %multmp = fmul double +%a, %a ; [#uses=1] %multmp1 = fmul double 2.000000e+00, %a ; [#uses=1] +%multmp2 = fmul double %multmp1, %b ; [#uses=1] %addtmp = fadd double +%multmp, %multmp2 ; [#uses=1] %multmp3 = fmul double %b, %b ; [#uses=1] +%addtmp4 = fadd double %addtmp, %multmp3 ; [#uses=1] ret double %addtmp4 +} + +define double @bar(double %a) { entry: %calltmp = call double +@foo(double %a, double 4.000000e+00) ; [#uses=1] %calltmp1 = call double +@bar(double 3.133700e+04) ; [#uses=1] %addtmp = fadd double %calltmp, +%calltmp1 ; [#uses=1] ret double %addtmp } + +declare double @cos(double) + +define double @1() { entry: %calltmp = call double @cos(double +1.234000e+00) ; [#uses=1] ret double %calltmp } {% endhighlight %} + +When you quit the current demo, it dumps out the IR for the entire +module generated. Here you can see the big picture with all the +functions referencing each other. + +This wraps up the third chapter of the Kaleidoscope tutorial. Up next, +we'll describe how to `add JIT codegen and optimizer +support `_ to this so we can actually start +running code! + +-------------- + +Full Code Listing # {#code} +=========================== + +Here is the complete code listing for our running example, enhanced with +the LLVM code generator. Because this uses the llvm-py libraries, you +need to `download <../download.html>`_ and +`install <../userguide.html#install>`_ them. + +{% highlight python %} #!/usr/bin/env python + +import re from llvm.core import Module, Constant, Type, Function, +Builder, FCMP\_ULT + +Globals +------- + +The LLVM module, which holds all the IR code. +============================================= + +g\_llvm\_module = Module.new('my cool jit') + +The LLVM instruction builder. Created whenever a new function is entered. +========================================================================= + +g\_llvm\_builder = None + +A dictionary that keeps track of which values are defined in the current scope +============================================================================== + +and what their LLVM representation is. +====================================== + +g\_named\_values = {} + +Lexer +----- + +The lexer yields one of these types for each token. +=================================================== + +class EOFToken(object): pass + +class DefToken(object): pass + +class ExternToken(object): pass + +class IdentifierToken(object): def **init**\ (self, name): self.name = +name + +class NumberToken(object): def **init**\ (self, value): self.value = +value + +class CharacterToken(object): def **init**\ (self, char): self.char = +char def **eq**\ (self, other): return isinstance(other, CharacterToken) +and self.char == other.char def **ne**\ (self, other): return not self +== other + +Regular expressions that tokens and comments of our language. +============================================================= + +REGEX\_NUMBER = re.compile('[0-9]+(?:.[0-9]+)?') REGEX\_IDENTIFIER = +re.compile('[a-zA-Z][a-zA-Z0-9]\ *') REGEX\_COMMENT = re.compile('#.*') + +def Tokenize(string): while string: # Skip whitespace. if +string[0].isspace(): string = string[1:] continue + +:: + + # Run regexes. + comment_match = REGEX_COMMENT.match(string) + number_match = REGEX_NUMBER.match(string) + identifier_match = REGEX_IDENTIFIER.match(string) + + # Check if any of the regexes matched and yield the appropriate result. + if comment_match: + comment = comment_match.group(0) + string = string[len(comment):] + elif number_match: + number = number_match.group(0) + yield NumberToken(float(number)) + string = string[len(number):] + elif identifier_match: + identifier = identifier_match.group(0) + # Check if we matched a keyword. + if identifier == 'def': + yield DefToken() + elif identifier == 'extern': + yield ExternToken() + else: + yield IdentifierToken(identifier) + string = string[len(identifier):] + else: + # Yield the ASCII value of the unknown character. + yield CharacterToken(string[0]) + string = string[1:] + +yield EOFToken() + +Abstract Syntax Tree (aka Parse Tree) +------------------------------------- + +Base class for all expression nodes. +==================================== + +class ExpressionNode(object): pass + +Expression class for numeric literals like "1.0". +================================================= + +class NumberExpressionNode(ExpressionNode): + +def **init**\ (self, value): self.value = value + +def CodeGen(self): return Constant.real(Type.double(), self.value) + +Expression class for referencing a variable, like "a". +====================================================== + +class VariableExpressionNode(ExpressionNode): + +def **init**\ (self, name): self.name = name + +def CodeGen(self): if self.name in g\_named\_values: return +g\_named\_values[self.name] else: raise RuntimeError('Unknown variable +name: ' + self.name) + +Expression class for a binary operator. +======================================= + +class BinaryOperatorExpressionNode(ExpressionNode): + +def **init**\ (self, operator, left, right): self.operator = operator +self.left = left self.right = right + +def CodeGen(self): left = self.left.CodeGen() right = +self.right.CodeGen() + +:: + + if self.operator == '+': + return g_llvm_builder.fadd(left, right, 'addtmp') + elif self.operator == '-': + return g_llvm_builder.fsub(left, right, 'subtmp') + elif self.operator == '*': + return g_llvm_builder.fmul(left, right, 'multmp') + elif self.operator == '<': + result = g_llvm_builder.fcmp(FCMP_ULT, left, right, 'cmptmp') + # Convert bool 0 or 1 to double 0.0 or 1.0. + return g_llvm_builder.uitofp(result, Type.double(), 'booltmp') + else: + raise RuntimeError('Unknown binary operator.') + +Expression class for function calls. +==================================== + +class CallExpressionNode(ExpressionNode): + +def **init**\ (self, callee, args): self.callee = callee self.args = +args + +def CodeGen(self): # Look up the name in the global module table. callee += g\_llvm\_module.get\_function\_named(self.callee) + +:: + + # Check for argument mismatch error. + if len(callee.args) != len(self.args): + raise RuntimeError('Incorrect number of arguments passed.') + + arg_values = [i.CodeGen() for i in self.args] + + return g_llvm_builder.call(callee, arg_values, 'calltmp') + +This class represents the "prototype" for a function, which captures its name, +============================================================================== + +and its argument names (thus implicitly the number of arguments the function +============================================================================ + +takes). +======= + +class PrototypeNode(object): + +def **init**\ (self, name, args): self.name = name self.args = args + +def CodeGen(self): # Make the function type, eg. double(double,double). +funct\_type = Type.function( Type.double(), [Type.double()] \* +len(self.args), False) + +:: + + function = Function.new(g_llvm_module, funct_type, self.name) + + # If the name conflicted, there was already something with the same name. + # If it has a body, don't allow redefinition or reextern. + if function.name != self.name: + function.delete() + function = g_llvm_module.get_function_named(self.name) + + # If the function already has a body, reject this. + if not function.is_declaration: + raise RuntimeError('Redefinition of function.') + + # If F took a different number of args, reject. + if len(callee.args) != len(self.args): + raise RuntimeError('Redeclaration of a function with different number ' + 'of args.') + + # Set names for all arguments and add them to the variables symbol table. + for arg, arg_name in zip(function.args, self.args): + arg.name = arg_name + # Add arguments to variable symbol table. + g_named_values[arg_name] = arg + + return function + +This class represents a function definition itself. +=================================================== + +class FunctionNode(object): + +def **init**\ (self, prototype, body): self.prototype = prototype +self.body = body + +def CodeGen(self): # Clear scope. g\_named\_values.clear() + +:: + + # Create a function object. + function = self.prototype.CodeGen() + + # Create a new basic block to start insertion into. + block = function.append_basic_block('entry') + global g_llvm_builder + g_llvm_builder = Builder.new(block) + + # Finish off the function. + try: + return_value = self.body.CodeGen() + g_llvm_builder.ret(return_value) + + # Validate the generated code, checking for consistency. + function.verify() + except: + function.delete() + raise + + return function + +Parser +------ + +class Parser(object): + +def **init**\ (self, tokens, binop\_precedence): self.tokens = tokens +self.binop\_precedence = binop\_precedence self.Next() + +# Provide a simple token buffer. Parser.current is the current token the +# parser is looking at. Parser.Next() reads another token from the lexer +and # updates Parser.current with its results. def Next(self): +self.current = self.tokens.next() + +# Gets the precedence of the current token, or -1 if the token is not a +binary # operator. def GetCurrentTokenPrecedence(self): if +isinstance(self.current, CharacterToken): return +self.binop\_precedence.get(self.current.char, -1) else: return -1 + +# identifierexpr ::= identifier \| identifier '(' expression\* ')' def +ParseIdentifierExpr(self): identifier\_name = self.current.name +self.Next() # eat identifier. + +:: + + if self.current != CharacterToken('('): # Simple variable reference. + return VariableExpressionNode(identifier_name) + + # Call. + self.Next() # eat '('. + args = [] + if self.current != CharacterToken(')'): + while True: + args.append(self.ParseExpression()) + if self.current == CharacterToken(')'): + break + elif self.current != CharacterToken(','): + raise RuntimeError('Expected ")" or "," in argument list.') + self.Next() + + self.Next() # eat ')'. + return CallExpressionNode(identifier_name, args) + +# numberexpr ::= number def ParseNumberExpr(self): result = +NumberExpressionNode(self.current.value) self.Next() # consume the +number. return result + +# parenexpr ::= '(' expression ')' def ParseParenExpr(self): self.Next() +# eat '('. + +:: + + contents = self.ParseExpression() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")".') + self.Next() # eat ')'. + + return contents + +# primary ::= identifierexpr \| numberexpr \| parenexpr def +ParsePrimary(self): if isinstance(self.current, IdentifierToken): return +self.ParseIdentifierExpr() elif isinstance(self.current, NumberToken): +return self.ParseNumberExpr() elif self.current == CharacterToken('('): +return self.ParseParenExpr() else: raise RuntimeError('Unknown token +when expecting an expression.') + +# binoprhs ::= (operator primary)\* def ParseBinOpRHS(self, left, +left\_precedence): # If this is a binary operator, find its precedence. +while True: precedence = self.GetCurrentTokenPrecedence() + +:: + + # If this is a binary operator that binds at least as tightly as the + # current one, consume it; otherwise we are done. + if precedence < left_precedence: + return left + + binary_operator = self.current.char + self.Next() # eat the operator. + + # Parse the primary expression after the binary operator. + right = self.ParsePrimary() + + # If binary_operator binds less tightly with right than the operator after + # right, let the pending operator take right as its left. + next_precedence = self.GetCurrentTokenPrecedence() + if precedence < next_precedence: + right = self.ParseBinOpRHS(right, precedence + 1) + + # Merge left/right. + left = BinaryOperatorExpressionNode(binary_operator, left, right) + +# expression ::= primary binoprhs def ParseExpression(self): left = +self.ParsePrimary() return self.ParseBinOpRHS(left, 0) + +# prototype ::= id '(' id\* ')' def ParsePrototype(self): if not +isinstance(self.current, IdentifierToken): raise RuntimeError('Expected +function name in prototype.') + +:: + + function_name = self.current.name + self.Next() # eat function name. + + if self.current != CharacterToken('('): + raise RuntimeError('Expected "(" in prototype.') + self.Next() # eat '('. + + arg_names = [] + while isinstance(self.current, IdentifierToken): + arg_names.append(self.current.name) + self.Next() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")" in prototype.') + + # Success. + self.Next() # eat ')'. + + return PrototypeNode(function_name, arg_names) + +# definition ::= 'def' prototype expression def ParseDefinition(self): +self.Next() # eat def. proto = self.ParsePrototype() body = +self.ParseExpression() return FunctionNode(proto, body) + +# toplevelexpr ::= expression def ParseTopLevelExpr(self): proto = +PrototypeNode('', []) return FunctionNode(proto, self.ParseExpression()) + +# external ::= 'extern' prototype def ParseExtern(self): self.Next() # +eat extern. return self.ParsePrototype() + +# Top-Level parsing def HandleDefinition(self): +self.Handle(self.ParseDefinition, 'Read a function definition:') + +def HandleExtern(self): self.Handle(self.ParseExtern, 'Read an extern:') + +def HandleTopLevelExpression(self): self.Handle(self.ParseTopLevelExpr, +'Read a top-level expression:') + +def Handle(self, function, message): try: print message, +function().CodeGen() except Exception, e: print 'Error:', e try: +self.Next() # Skip for error recovery. except: pass + +Main driver code. +----------------- + +def main(): # Install standard binary operators. # 1 is lowest possible +precedence. 40 is the highest. operator\_precedence = { '<': 10, '+': +20, '-': 20, '\*': 40 } + +# Run the main "interpreter loop". while True: print 'ready>', try: raw += raw\_input() except KeyboardInterrupt: break + +:: + + parser = Parser(Tokenize(raw), operator_precedence) + while True: + # top ::= definition | external | expression | EOF + if isinstance(parser.current, EOFToken): + break + if isinstance(parser.current, DefToken): + parser.HandleDefinition() + elif isinstance(parser.current, ExternToken): + parser.HandleExtern() + else: + parser.HandleTopLevelExpression() + +# Print out all of the generated code. print '', g\_llvm\_module + +if **name** == '**main**\ ': main() {% endhighlight %} + +-------------- + +**`Next: Adding JIT and Optimizer Support `_** diff --git a/docs/source/doc/kaleidoscope/PythonLangImpl4.md b/docs/source/doc/kaleidoscope/PythonLangImpl4.md deleted file mode 100644 index d113f49..0000000 --- a/docs/source/doc/kaleidoscope/PythonLangImpl4.md +++ /dev/null @@ -1,941 +0,0 @@ ---- -layout: page -title: "Kaleidoscope: Chapter 4" ---- - -# Adding JIT and Optimizer Support - -Written by [Chris Lattner](mailto:sabre@nondot.org) -and [Max Shawabkeh](http://max99x.com) - - -**Chapter 4** - - -* This will become a table of contents (this text will be scraped). -{:toc} - - -**[Chapter 5: Extending the Language: Control Flow](PythonLangImpl5.html)** - - -# Introduction # {#intro} - -Welcome to Chapter 4 of the -[Implementing a language with LLVM](http://www.llvm.org/docs/tutorial/index.html) -tutorial. Chapters 1-3 described the implementation of a simple -language and added support for generating LLVM IR. This chapter describes -two new techniques: adding optimizer support to your language, and adding JIT -compiler support. These additions will demonstrate how to get nice, efficient -code for the Kaleidoscope language. - - -* * * - -# Trivial Constant Folding # {#trivialconstfold} - -Our demonstration for Chapter 3 is elegant and easy to extend. Unfortunately, -it does not produce wonderful code. The LLVM Builder, however, does give us -obvious optimizations when compiling simple code: - - -{% highlight bash %} -ready> def test(x) 1+2+x -Read function definition: -define double @test(double %x) { -entry: - %addtmp = fadd double 3.000000e+00, %x - ret double %addtmp -} -{% endhighlight %} - - -This code is not a literal transcription of the AST built by parsing the -input. That would be: - - -{% highlight bash %} -ready> def test(x) 1+2+x -Read function definition: -define double @test(double %x) { -entry: - %addtmp = fadd double 2.000000e+00, 1.000000e+00 - %addtmp1 = fadd double %addtmp, %x - ret double %addtmp1 -} -{% endhighlight %} - - -Constant folding, as seen above, in particular, is a very common and very -important optimization: so much so that many language implementors implement -constant folding support in their AST representation. - -With LLVM, you don't need this support in the AST. Since all calls to build -LLVM IR go through the LLVM IR builder, the builder itself checked to see if -there was a constant folding opportunity when you call it. If so, it just does -the constant fold and return the constant instead of creating an instruction. - -Well, that was easy :). In practice, we recommend always using -`llvm.core.Builder` when generating code like this. It has no -"syntactic overhead" for its use (you don't have to uglify your compiler with -constant checks everywhere) and it can dramatically reduce the amount of -LLVM IR that is generated in some cases (particular for languages with a macro -preprocessor or that use a lot of constants). - -On the other hand, the `Builder` is limited by the fact that it does -all of its analysis inline with the code as it is built. If you take a slightly -more complex example: - - -{% highlight bash %} -ready> def test(x) (1+2+x)*(x+(1+2)) -Read a function definition: -define double @test(double %x) { -entry: - %addtmp = fadd double 3.000000e+00, %x ; [#uses=1] - %addtmp1 = fadd double %x, 3.000000e+00 ; [#uses=1] - %multmp = fmul double %addtmp, %addtmp1 ; [#uses=1] - ret double %multmp -} -{% endhighlight %} - - -In this case, the LHS and RHS of the multiplication are the same value. We'd -really like to see this generate"`tmp = x+3; result = tmp*tmp;` instead -of computing `x+3` twice. - -Unfortunately, no amount of local analysis will be able to detect and correct -this. This requires two transformations: reassociation of expressions (to -make the add's lexically identical) and Common Subexpression Elimination (CSE) -to delete the redundant add instruction. Fortunately, LLVM provides a broad -range of optimizations that you can use, in the form of "passes". - - -* * * - -# LLVM Optimization Passes # {#optimizerpasses} - -LLVM provides many optimization passes, which do many different sorts of -things and have different tradeoffs. Unlike other systems, LLVM doesn't hold -to the mistaken notion that one set of optimizations is right for all languages -and for all situations. LLVM allows a compiler implementor to make complete -decisions about what optimizations to use, in which order, and in what -situation. - -As a concrete example, LLVM supports both "whole module" passes, which look -across as large of body of code as they can (often a whole file, but if run -at link time, this can be a substantial portion of the whole program). It also -supports and includes "per-function" passes which just operate on a single -function at a time, without looking at other functions. For more information -on passes and how they are run, see the -[How to Write a Pass](http://www.llvm.org/docs/WritingAnLLVMPass.html) -document and the -[List of LLVM Passes](http://www.llvm.org/docs/Passes.html). - -For Kaleidoscope, we are currently generating functions on the fly, one at -a time, as the user types them in. We aren't shooting for the ultimate -optimization experience in this setting, but we also want to catch the easy and -quick stuff where possible. As such, we will choose to run a few per-function -optimizations as the user types the function in. If we wanted to make a "static -Kaleidoscope compiler", we would use exactly the code we have now, except that -we would defer running the optimizer until the entire file has been parsed. - -In order to get per-function optimizations going, we need to set up a -[FunctionPassManager](http://www.llvm.org/docs/WritingAnLLVMPass.html#passmanager) -to hold and organize the LLVM optimizations that we want -to run. Once we have that, we can add a set of optimizations to run. The code -looks like this: - - -{% highlight python %} -# The function optimization passes manager. -g_llvm_pass_manager = FunctionPassManager.new(g_llvm_module) - -# The LLVM execution engine. -g_llvm_executor = ExecutionEngine.new(g_llvm_module) - -... - -def main(): - # Set up the optimizer pipeline. Start with registering info about how the - # target lays out data structures. - g_llvm_pass_manager.add(g_llvm_executor.target_data) - # Do simple "peephole" optimizations and bit-twiddling optzns. - g_llvm_pass_manager.add(PASS_INSTRUCTION_COMBINING) - # Reassociate expressions. - g_llvm_pass_manager.add(PASS_REASSOCIATE) - # Eliminate Common SubExpressions. - g_llvm_pass_manager.add(PASS_GVN) - # Simplify the control flow graph (deleting unreachable blocks, etc). - g_llvm_pass_manager.add(PASS_CFG_SIMPLIFICATION) - - g_llvm_pass_manager.initialize() -{% endhighlight %} - - -This code defines a `FunctionPassManager`, -`g_llvm_pass_manager`. Once it is set up, we use a series of "add" calls -to add a bunch of LLVM passes. The first pass is basically boilerplate, it adds -a pass so that later optimizations know how the data structures in the program -are laid out. (The "`g_llvm_executor`" variable is related to the JIT, -which we will get to in the next section.) In this case, we choose to add 4 -optimization passes. The passes we chose here are a pretty standard set of -"cleanup" optimizations that are useful for a wide variety of code. I won't -delve into what they do but, believe me, they are a good starting place :). - -Once the pass manager is set up, we need to make use of it. We do this by -running it after our newly created function is constructed (in -`FunctionNode.CodeGen`), but before it is returned to the client: - - -{% highlight python %} - return_value = self.body.CodeGen() - g_llvm_builder.ret(return_value) - - # Validate the generated code, checking for consistency. - function.verify() - - # Optimize the function. - g_llvm_pass_manager.run(function) -{% endhighlight %} - - -As you can see, this is pretty straightforward. The -`FunctionPassManager` optimizes and updates the LLVM Function in place, -improving (hopefully) its body. With this in place, we can try our test above -again: - - -{% highlight bash %} -ready> def test(x) (1+2+x)*(x+(1+2)) -Read a function definition: -define double @test(double %x) { -entry: - %addtmp = fadd double %x, 3.000000e+00 ; [#uses=2] - %multmp = fmul double %addtmp, %addtmp ; [#uses=1] - ret double %multmp -} -{% endhighlight %} - - -As expected, we now get our nicely optimized code, saving a floating point -add instruction from every execution of this function. - -LLVM provides a wide variety of optimizations that can be used in certain -circumstances. Some -[documentation about the various passes](http://www.llvm.org/docs/Passes.html) -is available, but it isn't very complete. Another good source of -ideas can come from looking at the passes that `llvm-gcc` or -`llvm-ld` run to get started. The `opt` tool allows you to -experiment with passes from the command line, so you can see if they do -anything. - -Now that we have reasonable code coming out of our front-end, lets talk about -executing it! - -* * * - -# Adding a JIT Compiler # {#jit} - -Code that is available in LLVM IR can have a wide variety of tools -applied to it. For example, you can run optimizations on it (as we did above), -you can dump it out in textual or binary forms, you can compile the code to an -assembly file (.s) for some target, or you can JIT compile it. The nice thing -about the LLVM IR representation is that it is the "common currency" between -many different parts of the compiler. - - -In this section, we'll add JIT compiler support to our interpreter. The -basic idea that we want for Kaleidoscope is to have the user enter function -bodies as they do now, but immediately evaluate the top-level expressions they -type in. For example, if they type in "1 + 2", we should evaluate and print -out 3. If they define a function, they should be able to call it from the -command line. - -In order to do this, we first declare and initialize the JIT. This is done -by adding and initializing a global variable: - - -{% highlight python %} -# The LLVM execution engine. -g_llvm_executor = ExecutionEngine.new(g_llvm_module) -{% endhighlight %} - - -This creates an abstract "Execution Engine" which can be either a JIT -compiler or the LLVM interpreter. LLVM will automatically pick a JIT compiler -for you if one is available for your platform, otherwise it will fall back to -the interpreter. - -Once the `ExecutionEngine` is created, the JIT is ready to be used. -We can use the `run_function` method of the execution engine to execute -a compiled function and get its return value. In our case, this means that we -can change the code that parses a top-level expression to look like this: - - -{% highlight python %} - def HandleTopLevelExpression(self): - try: - function = self.ParseTopLevelExpr().CodeGen() - result = g_llvm_executor.run_function(function, []) - print 'Evaluated to:', result.as_real(Type.double()) - except Exception, e: - print 'Error:', e - try: - self.Next() # Skip for error recovery. - except: - pass -{% endhighlight %} - - -Recall that we compile top-level expressions into a self-contained LLVM -function that takes no arguments and returns the computed double. - -With just these two changes, lets see how Kaleidoscope works now! - - -{% highlight python %} -ready> 4+5 -Read a top level expression: -define double @0() { -entry: - ret double 9.000000e+00 -} - -Evaluated to: 9.0 -{% endhighlight %} - - -Well this looks like it is basically working. The dump of the function -shows the "no argument function that always returns double" that we synthesize -for each top-level expression that is typed in. This demonstrates very basic -functionality, but can we do more? - - -{% highlight python %} -ready> def testfunc(x y) x + y*2 -Read a function definition: -define double @testfunc(double %x, double %y) { -entry: - %multmp = fmul double %y, 2.000000e+00 ; [#uses=1] - %addtmp = fadd double %multmp, %x ; [#uses=1] - ret double %addtmp -} - -ready> testfunc(4, 10) -Read a top level expression: -define double @0() { -entry: - %calltmp = call double @testfunc(double 4.000000e+00, double 1.000000e+01) ; [#uses=1] - ret double %calltmp -} - -*Evaluated to: 24.0* -{% endhighlight %} - - -This illustrates that we can now call user code, but there is something a bit -subtle going on here. Note that we only invoke the JIT on the anonymous -functions that *call testfunc*, but we never invoked it -on *testfunc* itself. What actually happened here is that the JIT -scanned for all non-JIT'd functions transitively called from the anonymous -function and compiled all of them before returning from `run_function()`. - - -The JIT provides a number of other more advanced interfaces for things like -freeing allocated machine code, rejit'ing functions to update them, etc. -However, even with this simple code, we get some surprisingly powerful -capabilities - check this out (I removed the dump of the anonymous functions, -you should get the idea by now :) : - - -{% highlight bash %} -ready> extern sin(x) -Read an extern: -declare double @sin(double) - -ready> extern cos(x) -Read an extern: -declare double @cos(double) - -ready> sin(1.0) -*Evaluated to: 0.841470984808* - -ready> def foo(x) sin(x)*sin(x) + cos(x)*cos(x) -Read a function definition: -define double @foo(double %x) { -entry: - %calltmp = call double @sin(double %x) ; [#uses=1] - %calltmp1 = call double @sin(double %x) ; [#uses=1] - %multmp = fmul double %calltmp, %calltmp1 ; [#uses=1] - %calltmp2 = call double @cos(double %x) ; [#uses=1] - %calltmp3 = call double @cos(double %x) ; [#uses=1] - %multmp4 = fmul double %calltmp2, %calltmp3 ; [#uses=1] - %addtmp = fadd double %multmp, %multmp4 ; [#uses=1] - ret double %addtmp -} - -ready> foo(4.0) -*Evaluated to: 1.000000* -{% endhighlight %} - - -Whoa, how does the JIT know about sin and cos? The answer is surprisingly -simple: in this example, the JIT started execution of a function and got to a -function call. It realized that the function was not yet JIT compiled and -invoked the standard set of routines to resolve the function. In this case, -there is no body defined for the function, so the JIT ended up calling -`dlsym("sin")` on the Python process that is hosting our Kaleidoscope -prompt. Since `sin` is defined within the JIT's address space, it -simply patches up calls in the module to call the libm version of `sin` -directly. - -One interesting application of this is that we can now extend the language -by writing arbitrary C++ code to implement operations. For example, we can -create a C file with the following simple function: - - - -{% highlight c %} -#include - -double putchard(double x) { - putchar((char)x); - return 0; -} -{% endhighlight %} - - -We can then compile this into a shared library with GCC: - - -{% highlight bash %} -gcc -shared -fPIC -o putchard.so putchard.c -{% endhighlight %} - - -Now we can load this library into the Python process using -`llvm.core.load_library_permanently` and access it from Kaleidoscope to -produce simple output to the console: - - -{% highlight python %} ->>> import llvm.core ->>> llvm.core.load_library_permanently('/home/max/llvm-py-tutorial/putchard.so') ->>> import kaleidoscope ->>> kaleidoscope.main() -ready> extern putchard(x) -Read an extern: -declare double @putchard(double) - -ready> putchard(65) + putchard(66) + putchard(67) + putchard(10) -*ABC* -Evaluated to: 0.0 -{% endhighlight %} - - -Similar code could be used to implement file I/O, console input, and many -other capabilities in Kaleidoscope. - -This completes the JIT and optimizer chapter of the Kaleidoscope tutorial. At -this point, we can compile a non-Turing-complete programming language, optimize -and JIT compile it in a user-driven way. Next up we'll look into -[extending the language with control flow constructs](PythonLangImpl5.html), -tackling some interesting LLVM IR issues along the way. - - -* * * - -# Full Code Listing # {#code} - -Here is the complete code listing for our running example, enhanced with the -LLVM JIT and optimizer: - - - -{% highlight python %} -#!/usr/bin/env python - -import re -from llvm.core import Module, Constant, Type, Function, Builder, FCMP_ULT -from llvm.ee import ExecutionEngine, TargetData -from llvm.passes import FunctionPassManager -from llvm.passes import (PASS_INSTRUCTION_COMBINING, - PASS_REASSOCIATE, - PASS_GVN, - PASS_CFG_SIMPLIFICATION) - -################################################################################ -## Globals -################################################################################ - -# The LLVM module, which holds all the IR code. -g_llvm_module = Module.new('my cool jit') - -# The LLVM instruction builder. Created whenever a new function is entered. -g_llvm_builder = None - -# A dictionary that keeps track of which values are defined in the current scope -# and what their LLVM representation is. -g_named_values = {} - -# The function optimization passes manager. -g_llvm_pass_manager = FunctionPassManager.new(g_llvm_module) - -# The LLVM execution engine. -g_llvm_executor = ExecutionEngine.new(g_llvm_module) - -################################################################################ -## Lexer -################################################################################ - -# The lexer yields one of these types for each token. -class EOFToken(object): - pass - -class DefToken(object): - pass - -class ExternToken(object): - pass - -class IdentifierToken(object): - def __init__(self, name): self.name = name - -class NumberToken(object): - def __init__(self, value): self.value = value - -class CharacterToken(object): - def __init__(self, char): self.char = char - def __eq__(self, other): - return isinstance(other, CharacterToken) and self.char == other.char - def __ne__(self, other): return not self == other - -# Regular expressions that tokens and comments of our language. -REGEX_NUMBER = re.compile('[0-9]+(?:\.[0-9]+)?') -REGEX_IDENTIFIER = re.compile('[a-zA-Z][a-zA-Z0-9]*') -REGEX_COMMENT = re.compile('#.*') - -def Tokenize(string): - while string: - # Skip whitespace. - if string[0].isspace(): - string = string[1:] - continue - - # Run regexes. - comment_match = REGEX_COMMENT.match(string) - number_match = REGEX_NUMBER.match(string) - identifier_match = REGEX_IDENTIFIER.match(string) - - # Check if any of the regexes matched and yield the appropriate result. - if comment_match: - comment = comment_match.group(0) - string = string[len(comment):] - elif number_match: - number = number_match.group(0) - yield NumberToken(float(number)) - string = string[len(number):] - elif identifier_match: - identifier = identifier_match.group(0) - # Check if we matched a keyword. - if identifier == 'def': - yield DefToken() - elif identifier == 'extern': - yield ExternToken() - else: - yield IdentifierToken(identifier) - string = string[len(identifier):] - else: - # Yield the ASCII value of the unknown character. - yield CharacterToken(string[0]) - string = string[1:] - - yield EOFToken() - -################################################################################ -## Abstract Syntax Tree (aka Parse Tree) -################################################################################ - -# Base class for all expression nodes. -class ExpressionNode(object): - pass - -# Expression class for numeric literals like "1.0". -class NumberExpressionNode(ExpressionNode): - - def __init__(self, value): - self.value = value - - def CodeGen(self): - return Constant.real(Type.double(), self.value) - -# Expression class for referencing a variable, like "a". -class VariableExpressionNode(ExpressionNode): - - def __init__(self, name): - self.name = name - - def CodeGen(self): - if self.name in g_named_values: - return g_named_values[self.name] - else: - raise RuntimeError('Unknown variable name: ' + self.name) - -# Expression class for a binary operator. -class BinaryOperatorExpressionNode(ExpressionNode): - - def __init__(self, operator, left, right): - self.operator = operator - self.left = left - self.right = right - - def CodeGen(self): - left = self.left.CodeGen() - right = self.right.CodeGen() - - if self.operator == '+': - return g_llvm_builder.fadd(left, right, 'addtmp') - elif self.operator == '-': - return g_llvm_builder.fsub(left, right, 'subtmp') - elif self.operator == '*': - return g_llvm_builder.fmul(left, right, 'multmp') - elif self.operator == '<': - result = g_llvm_builder.fcmp(FCMP_ULT, left, right, 'cmptmp') - # Convert bool 0 or 1 to double 0.0 or 1.0. - return g_llvm_builder.uitofp(result, Type.double(), 'booltmp') - else: - raise RuntimeError('Unknown binary operator.') - -# Expression class for function calls. -class CallExpressionNode(ExpressionNode): - - def __init__(self, callee, args): - self.callee = callee - self.args = args - - def CodeGen(self): - # Look up the name in the global module table. - callee = g_llvm_module.get_function_named(self.callee) - - # Check for argument mismatch error. - if len(callee.args) != len(self.args): - raise RuntimeError('Incorrect number of arguments passed.') - - arg_values = [i.CodeGen() for i in self.args] - - return g_llvm_builder.call(callee, arg_values, 'calltmp') - -# This class represents the "prototype" for a function, which captures its name, -# and its argument names (thus implicitly the number of arguments the function -# takes). -class PrototypeNode(object): - - def __init__(self, name, args): - self.name = name - self.args = args - - def CodeGen(self): - # Make the function type, eg. double(double,double). - funct_type = Type.function( - Type.double(), [Type.double()] * len(self.args), False) - - function = Function.new(g_llvm_module, funct_type, self.name) - - # If the name conflicted, there was already something with the same name. - # If it has a body, don't allow redefinition or reextern. - if function.name != self.name: - function.delete() - function = g_llvm_module.get_function_named(self.name) - - # If the function already has a body, reject this. - if not function.is_declaration: - raise RuntimeError('Redefinition of function.') - - # If F took a different number of args, reject. - if len(callee.args) != len(self.args): - raise RuntimeError('Redeclaration of a function with different number ' - 'of args.') - - # Set names for all arguments and add them to the variables symbol table. - for arg, arg_name in zip(function.args, self.args): - arg.name = arg_name - # Add arguments to variable symbol table. - g_named_values[arg_name] = arg - - return function - -# This class represents a function definition itself. -class FunctionNode(object): - - def __init__(self, prototype, body): - self.prototype = prototype - self.body = body - - def CodeGen(self): - # Clear scope. - g_named_values.clear() - - # Create a function object. - function = self.prototype.CodeGen() - - # Create a new basic block to start insertion into. - block = function.append_basic_block('entry') - global g_llvm_builder - g_llvm_builder = Builder.new(block) - - # Finish off the function. - try: - return_value = self.body.CodeGen() - g_llvm_builder.ret(return_value) - - # Validate the generated code, checking for consistency. - function.verify() - - # Optimize the function. - g_llvm_pass_manager.run(function) - except: - function.delete() - raise - - return function - - -################################################################################ -## Parser -################################################################################ - -class Parser(object): - - def __init__(self, tokens, binop_precedence): - self.tokens = tokens - self.binop_precedence = binop_precedence - self.Next() - - # Provide a simple token buffer. Parser.current is the current token the - # parser is looking at. Parser.Next() reads another token from the lexer and - # updates Parser.current with its results. - def Next(self): - self.current = self.tokens.next() - - # Gets the precedence of the current token, or -1 if the token is not a binary - # operator. - def GetCurrentTokenPrecedence(self): - if isinstance(self.current, CharacterToken): - return self.binop_precedence.get(self.current.char, -1) - else: - return -1 - - # identifierexpr ::= identifier | identifier '(' expression* ')' - def ParseIdentifierExpr(self): - identifier_name = self.current.name - self.Next() # eat identifier. - - if self.current != CharacterToken('('): # Simple variable reference. - return VariableExpressionNode(identifier_name) - - # Call. - self.Next() # eat '('. - args = [] - if self.current != CharacterToken(')'): - while True: - args.append(self.ParseExpression()) - if self.current == CharacterToken(')'): - break - elif self.current != CharacterToken(','): - raise RuntimeError('Expected ")" or "," in argument list.') - self.Next() - - self.Next() # eat ')'. - return CallExpressionNode(identifier_name, args) - - # numberexpr ::= number - def ParseNumberExpr(self): - result = NumberExpressionNode(self.current.value) - self.Next() # consume the number. - return result - - # parenexpr ::= '(' expression ')' - def ParseParenExpr(self): - self.Next() # eat '('. - - contents = self.ParseExpression() - - if self.current != CharacterToken(')'): - raise RuntimeError('Expected ")".') - self.Next() # eat ')'. - - return contents - - # primary ::= identifierexpr | numberexpr | parenexpr - def ParsePrimary(self): - if isinstance(self.current, IdentifierToken): - return self.ParseIdentifierExpr() - elif isinstance(self.current, NumberToken): - return self.ParseNumberExpr() - elif self.current == CharacterToken('('): - return self.ParseParenExpr() - else: - raise RuntimeError('Unknown token when expecting an expression.') - - # binoprhs ::= (operator primary)* - def ParseBinOpRHS(self, left, left_precedence): - # If this is a binary operator, find its precedence. - while True: - precedence = self.GetCurrentTokenPrecedence() - - # If this is a binary operator that binds at least as tightly as the - # current one, consume it; otherwise we are done. - if precedence < left_precedence: - return left - - binary_operator = self.current.char - self.Next() # eat the operator. - - # Parse the primary expression after the binary operator. - right = self.ParsePrimary() - - # If binary_operator binds less tightly with right than the operator after - # right, let the pending operator take right as its left. - next_precedence = self.GetCurrentTokenPrecedence() - if precedence < next_precedence: - right = self.ParseBinOpRHS(right, precedence + 1) - - # Merge left/right. - left = BinaryOperatorExpressionNode(binary_operator, left, right) - - # expression ::= primary binoprhs - def ParseExpression(self): - left = self.ParsePrimary() - return self.ParseBinOpRHS(left, 0) - - # prototype ::= id '(' id* ')' - def ParsePrototype(self): - if not isinstance(self.current, IdentifierToken): - raise RuntimeError('Expected function name in prototype.') - - function_name = self.current.name - self.Next() # eat function name. - - if self.current != CharacterToken('('): - raise RuntimeError('Expected "(" in prototype.') - self.Next() # eat '('. - - arg_names = [] - while isinstance(self.current, IdentifierToken): - arg_names.append(self.current.name) - self.Next() - - if self.current != CharacterToken(')'): - raise RuntimeError('Expected ")" in prototype.') - - # Success. - self.Next() # eat ')'. - - return PrototypeNode(function_name, arg_names) - - # definition ::= 'def' prototype expression - def ParseDefinition(self): - self.Next() # eat def. - proto = self.ParsePrototype() - body = self.ParseExpression() - return FunctionNode(proto, body) - - # toplevelexpr ::= expression - def ParseTopLevelExpr(self): - proto = PrototypeNode('', []) - return FunctionNode(proto, self.ParseExpression()) - - # external ::= 'extern' prototype - def ParseExtern(self): - self.Next() # eat extern. - return self.ParsePrototype() - - # Top-Level parsing - def HandleDefinition(self): - self.Handle(self.ParseDefinition, 'Read a function definition:') - - def HandleExtern(self): - self.Handle(self.ParseExtern, 'Read an extern:') - - def HandleTopLevelExpression(self): - try: - function = self.ParseTopLevelExpr().CodeGen() - result = g_llvm_executor.run_function(function, []) - print 'Evaluated to:', result.as_real(Type.double()) - except Exception, e: - print 'Error:', e - try: - self.Next() # Skip for error recovery. - except: - pass - - def Handle(self, function, message): - try: - print message, function().CodeGen() - except Exception, e: - print 'Error:', e - try: - self.Next() # Skip for error recovery. - except: - pass - -################################################################################ -## Main driver code. -################################################################################ - -def main(): - # Set up the optimizer pipeline. Start with registering info about how the - # target lays out data structures. - g_llvm_pass_manager.add(g_llvm_executor.target_data) - # Do simple "peephole" optimizations and bit-twiddling optzns. - g_llvm_pass_manager.add(PASS_INSTRUCTION_COMBINING) - # Reassociate expressions. - g_llvm_pass_manager.add(PASS_REASSOCIATE) - # Eliminate Common SubExpressions. - g_llvm_pass_manager.add(PASS_GVN) - # Simplify the control flow graph (deleting unreachable blocks, etc). - g_llvm_pass_manager.add(PASS_CFG_SIMPLIFICATION) - - g_llvm_pass_manager.initialize() - - # Install standard binary operators. - # 1 is lowest possible precedence. 40 is the highest. - operator_precedence = { - '<': 10, - '+': 20, - '-': 20, - '*': 40 - } - - # Run the main "interpreter loop". - while True: - print 'ready>', - try: - raw = raw_input() - except KeyboardInterrupt: - break - - parser = Parser(Tokenize(raw), operator_precedence) - while True: - # top ::= definition | external | expression | EOF - if isinstance(parser.current, EOFToken): - break - if isinstance(parser.current, DefToken): - parser.HandleDefinition() - elif isinstance(parser.current, ExternToken): - parser.HandleExtern() - else: - parser.HandleTopLevelExpression() - - # Print out all of the generated code. - print '\n', g_llvm_module - -if __name__ == '__main__': - main() -{% endhighlight %} - -* * * - -**[Next: Extending the language: control flow](PythonLangImpl5.html)** - diff --git a/docs/source/doc/kaleidoscope/PythonLangImpl4.rst b/docs/source/doc/kaleidoscope/PythonLangImpl4.rst new file mode 100644 index 0000000..7aa4c85 --- /dev/null +++ b/docs/source/doc/kaleidoscope/PythonLangImpl4.rst @@ -0,0 +1,803 @@ ++------------------------------------+ +| layout: page | ++------------------------------------+ +| title: "Kaleidoscope: Chapter 4" | ++------------------------------------+ + +Adding JIT and Optimizer Support +================================ + +Written by `Chris Lattner `_ and `Max +Shawabkeh `_ + +**Chapter 4** + +- This will become a table of contents (this text will be scraped). + {:toc} + +**`Chapter 5: Extending the Language: Control +Flow `_** + +Introduction # {#intro} +======================= + +Welcome to Chapter 4 of the `Implementing a language with +LLVM `_ tutorial. Chapters +1-3 described the implementation of a simple language and added support +for generating LLVM IR. This chapter describes two new techniques: +adding optimizer support to your language, and adding JIT compiler +support. These additions will demonstrate how to get nice, efficient +code for the Kaleidoscope language. + +-------------- + +Trivial Constant Folding # {#trivialconstfold} +============================================== + +Our demonstration for Chapter 3 is elegant and easy to extend. +Unfortunately, it does not produce wonderful code. The LLVM Builder, +however, does give us obvious optimizations when compiling simple code: + +{% highlight bash %} ready> def test(x) 1+2+x Read function definition: +define double @test(double %x) { entry: %addtmp = fadd double +3.000000e+00, %x ret double %addtmp } {% endhighlight %} + +This code is not a literal transcription of the AST built by parsing the +input. That would be: + +{% highlight bash %} ready> def test(x) 1+2+x Read function definition: +define double @test(double %x) { entry: %addtmp = fadd double +2.000000e+00, 1.000000e+00 %addtmp1 = fadd double %addtmp, %x ret double +%addtmp1 } {% endhighlight %} + +Constant folding, as seen above, in particular, is a very common and +very important optimization: so much so that many language implementors +implement constant folding support in their AST representation. + +With LLVM, you don't need this support in the AST. Since all calls to +build LLVM IR go through the LLVM IR builder, the builder itself checked +to see if there was a constant folding opportunity when you call it. If +so, it just does the constant fold and return the constant instead of +creating an instruction. + +Well, that was easy :). In practice, we recommend always using +``llvm.core.Builder`` when generating code like this. It has no +"syntactic overhead" for its use (you don't have to uglify your compiler +with constant checks everywhere) and it can dramatically reduce the +amount of LLVM IR that is generated in some cases (particular for +languages with a macro preprocessor or that use a lot of constants). + +On the other hand, the ``Builder`` is limited by the fact that it does +all of its analysis inline with the code as it is built. If you take a +slightly more complex example: + +{% highlight bash %} ready> def test(x) (1+2+x)\*(x+(1+2)) Read a +function definition: define double @test(double %x) { entry: %addtmp = +fadd double 3.000000e+00, %x ; [#uses=1] %addtmp1 = fadd double %x, +3.000000e+00 ; [#uses=1] %multmp = fmul double %addtmp, %addtmp1 ; +[#uses=1] ret double %multmp } {% endhighlight %} + +In this case, the LHS and RHS of the multiplication are the same value. +We'd really like to see this generate"``tmp = x+3; result = tmp*tmp;`` +instead of computing ``x+3`` twice. + +Unfortunately, no amount of local analysis will be able to detect and +correct this. This requires two transformations: reassociation of +expressions (to make the add's lexically identical) and Common +Subexpression Elimination (CSE) to delete the redundant add instruction. +Fortunately, LLVM provides a broad range of optimizations that you can +use, in the form of "passes". + +-------------- + +LLVM Optimization Passes # {#optimizerpasses} +============================================= + +LLVM provides many optimization passes, which do many different sorts of +things and have different tradeoffs. Unlike other systems, LLVM doesn't +hold to the mistaken notion that one set of optimizations is right for +all languages and for all situations. LLVM allows a compiler implementor +to make complete decisions about what optimizations to use, in which +order, and in what situation. + +As a concrete example, LLVM supports both "whole module" passes, which +look across as large of body of code as they can (often a whole file, +but if run at link time, this can be a substantial portion of the whole +program). It also supports and includes "per-function" passes which just +operate on a single function at a time, without looking at other +functions. For more information on passes and how they are run, see the +`How to Write a Pass `_ +document and the `List of LLVM +Passes `_. + +For Kaleidoscope, we are currently generating functions on the fly, one +at a time, as the user types them in. We aren't shooting for the +ultimate optimization experience in this setting, but we also want to +catch the easy and quick stuff where possible. As such, we will choose +to run a few per-function optimizations as the user types the function +in. If we wanted to make a "static Kaleidoscope compiler", we would use +exactly the code we have now, except that we would defer running the +optimizer until the entire file has been parsed. + +In order to get per-function optimizations going, we need to set up a +`FunctionPassManager `_ +to hold and organize the LLVM optimizations that we want to run. Once we +have that, we can add a set of optimizations to run. The code looks like +this: + +{% highlight python %} # The function optimization passes manager. +g\_llvm\_pass\_manager = FunctionPassManager.new(g\_llvm\_module) + +The LLVM execution engine. +========================== + +g\_llvm\_executor = ExecutionEngine.new(g\_llvm\_module) + +... + +def main(): # Set up the optimizer pipeline. Start with registering info +about how the # target lays out data structures. +g\_llvm\_pass\_manager.add(g\_llvm\_executor.target\_data) # Do simple +"peephole" optimizations and bit-twiddling optzns. +g\_llvm\_pass\_manager.add(PASS\_INSTRUCTION\_COMBINING) # Reassociate +expressions. g\_llvm\_pass\_manager.add(PASS\_REASSOCIATE) # Eliminate +Common SubExpressions. g\_llvm\_pass\_manager.add(PASS\_GVN) # Simplify +the control flow graph (deleting unreachable blocks, etc). +g\_llvm\_pass\_manager.add(PASS\_CFG\_SIMPLIFICATION) + +g\_llvm\_pass\_manager.initialize() {% endhighlight %} + +This code defines a ``FunctionPassManager``, ``g_llvm_pass_manager``. +Once it is set up, we use a series of "add" calls to add a bunch of LLVM +passes. The first pass is basically boilerplate, it adds a pass so that +later optimizations know how the data structures in the program are laid +out. (The "``g_llvm_executor``\ " variable is related to the JIT, which +we will get to in the next section.) In this case, we choose to add 4 +optimization passes. The passes we chose here are a pretty standard set +of "cleanup" optimizations that are useful for a wide variety of code. I +won't delve into what they do but, believe me, they are a good starting +place :). + +Once the pass manager is set up, we need to make use of it. We do this +by running it after our newly created function is constructed (in +``FunctionNode.CodeGen``), but before it is returned to the client: + +{% highlight python %} return\_value = self.body.CodeGen() +g\_llvm\_builder.ret(return\_value) + +:: + + # Validate the generated code, checking for consistency. + function.verify() + + # Optimize the function. + g_llvm_pass_manager.run(function) + +{% endhighlight %} + +As you can see, this is pretty straightforward. The +``FunctionPassManager`` optimizes and updates the LLVM Function in +place, improving (hopefully) its body. With this in place, we can try +our test above again: + +{% highlight bash %} ready> def test(x) (1+2+x)\*(x+(1+2)) Read a +function definition: define double @test(double %x) { entry: %addtmp = +fadd double %x, 3.000000e+00 ; [#uses=2] %multmp = fmul double %addtmp, +%addtmp ; [#uses=1] ret double %multmp } {% endhighlight %} + +As expected, we now get our nicely optimized code, saving a floating +point add instruction from every execution of this function. + +LLVM provides a wide variety of optimizations that can be used in +certain circumstances. Some `documentation about the various +passes `_ is available, but it +isn't very complete. Another good source of ideas can come from looking +at the passes that ``llvm-gcc`` or ``llvm-ld`` run to get started. The +``opt`` tool allows you to experiment with passes from the command line, +so you can see if they do anything. + +Now that we have reasonable code coming out of our front-end, lets talk +about executing it! + +-------------- + +Adding a JIT Compiler # {#jit} +============================== + +Code that is available in LLVM IR can have a wide variety of tools +applied to it. For example, you can run optimizations on it (as we did +above), you can dump it out in textual or binary forms, you can compile +the code to an assembly file (.s) for some target, or you can JIT +compile it. The nice thing about the LLVM IR representation is that it +is the "common currency" between many different parts of the compiler. + +In this section, we'll add JIT compiler support to our interpreter. The +basic idea that we want for Kaleidoscope is to have the user enter +function bodies as they do now, but immediately evaluate the top-level +expressions they type in. For example, if they type in "1 + 2", we +should evaluate and print out 3. If they define a function, they should +be able to call it from the command line. + +In order to do this, we first declare and initialize the JIT. This is +done by adding and initializing a global variable: + +{% highlight python %} # The LLVM execution engine. g\_llvm\_executor = +ExecutionEngine.new(g\_llvm\_module) {% endhighlight %} + +This creates an abstract "Execution Engine" which can be either a JIT +compiler or the LLVM interpreter. LLVM will automatically pick a JIT +compiler for you if one is available for your platform, otherwise it +will fall back to the interpreter. + +Once the ``ExecutionEngine`` is created, the JIT is ready to be used. We +can use the ``run_function`` method of the execution engine to execute a +compiled function and get its return value. In our case, this means that +we can change the code that parses a top-level expression to look like +this: + +{% highlight python %} def HandleTopLevelExpression(self): try: function += self.ParseTopLevelExpr().CodeGen() result = +g\_llvm\_executor.run\_function(function, []) print 'Evaluated to:', +result.as\_real(Type.double()) except Exception, e: print 'Error:', e +try: self.Next() # Skip for error recovery. except: pass {% endhighlight +%} + +Recall that we compile top-level expressions into a self-contained LLVM +function that takes no arguments and returns the computed double. + +With just these two changes, lets see how Kaleidoscope works now! + +{% highlight python %} ready> 4+5 Read a top level expression: define +double @0() { entry: ret double 9.000000e+00 } + +Evaluated to: 9.0 {% endhighlight %} + +Well this looks like it is basically working. The dump of the function +shows the "no argument function that always returns double" that we +synthesize for each top-level expression that is typed in. This +demonstrates very basic functionality, but can we do more? + +{% highlight python %} ready> def testfunc(x y) x + y\*2 Read a function +definition: define double @testfunc(double %x, double %y) { entry: +%multmp = fmul double %y, 2.000000e+00 ; [#uses=1] %addtmp = fadd double +%multmp, %x ; [#uses=1] ret double %addtmp } + +ready> testfunc(4, 10) Read a top level expression: define double @0() { +entry: %calltmp = call double @testfunc(double 4.000000e+00, double +1.000000e+01) ; [#uses=1] ret double %calltmp } + +*Evaluated to: 24.0* {% endhighlight %} + +This illustrates that we can now call user code, but there is something +a bit subtle going on here. Note that we only invoke the JIT on the +anonymous functions that *call testfunc*, but we never invoked it on +*testfunc* itself. What actually happened here is that the JIT scanned +for all non-JIT'd functions transitively called from the anonymous +function and compiled all of them before returning from +``run_function()``. + +The JIT provides a number of other more advanced interfaces for things +like freeing allocated machine code, rejit'ing functions to update them, +etc. However, even with this simple code, we get some surprisingly +powerful capabilities - check this out (I removed the dump of the +anonymous functions, you should get the idea by now :) : + +{% highlight bash %} ready> extern sin(x) Read an extern: declare double +@sin(double) + +ready> extern cos(x) Read an extern: declare double @cos(double) + +ready> sin(1.0) *Evaluated to: 0.841470984808* + +ready> def foo(x) sin(x)\ *sin(x) + cos(x)*\ cos(x) Read a function +definition: define double @foo(double %x) { entry: %calltmp = call +double @sin(double %x) ; [#uses=1] %calltmp1 = call double @sin(double +%x) ; [#uses=1] %multmp = fmul double %calltmp, %calltmp1 ; [#uses=1] +%calltmp2 = call double @cos(double %x) ; [#uses=1] %calltmp3 = call +double @cos(double %x) ; [#uses=1] %multmp4 = fmul double %calltmp2, +%calltmp3 ; [#uses=1] %addtmp = fadd double %multmp, %multmp4 ; +[#uses=1] ret double %addtmp } + +ready> foo(4.0) *Evaluated to: 1.000000* {% endhighlight %} + +Whoa, how does the JIT know about sin and cos? The answer is +surprisingly simple: in this example, the JIT started execution of a +function and got to a function call. It realized that the function was +not yet JIT compiled and invoked the standard set of routines to resolve +the function. In this case, there is no body defined for the function, +so the JIT ended up calling ``dlsym("sin")`` on the Python process that +is hosting our Kaleidoscope prompt. Since ``sin`` is defined within the +JIT's address space, it simply patches up calls in the module to call +the libm version of ``sin`` directly. + +One interesting application of this is that we can now extend the +language by writing arbitrary C++ code to implement operations. For +example, we can create a C file with the following simple function: + +{% highlight c %} #include + +double putchard(double x) { putchar((char)x); return 0; } {% +endhighlight %} + +We can then compile this into a shared library with GCC: + +{% highlight bash %} gcc -shared -fPIC -o putchard.so putchard.c {% +endhighlight %} + +Now we can load this library into the Python process using +``llvm.core.load_library_permanently`` and access it from Kaleidoscope +to produce simple output to the console: + +{% highlight python %} >>> import llvm.core >>> +llvm.core.load\_library\_permanently('/home/max/llvm-py-tutorial/putchard.so') +>>> import kaleidoscope >>> kaleidoscope.main() ready> extern +putchard(x) Read an extern: declare double @putchard(double) + +ready> putchard(65) + putchard(66) + putchard(67) + putchard(10) *ABC* +Evaluated to: 0.0 {% endhighlight %} + +Similar code could be used to implement file I/O, console input, and +many other capabilities in Kaleidoscope. + +This completes the JIT and optimizer chapter of the Kaleidoscope +tutorial. At this point, we can compile a non-Turing-complete +programming language, optimize and JIT compile it in a user-driven way. +Next up we'll look into `extending the language with control flow +constructs `_, tackling some interesting LLVM IR +issues along the way. + +-------------- + +Full Code Listing # {#code} +=========================== + +Here is the complete code listing for our running example, enhanced with +the LLVM JIT and optimizer: + +{% highlight python %} #!/usr/bin/env python + +import re from llvm.core import Module, Constant, Type, Function, +Builder, FCMP\_ULT from llvm.ee import ExecutionEngine, TargetData from +llvm.passes import FunctionPassManager from llvm.passes import +(PASS\_INSTRUCTION\_COMBINING, PASS\_REASSOCIATE, PASS\_GVN, +PASS\_CFG\_SIMPLIFICATION) + +Globals +------- + +The LLVM module, which holds all the IR code. +============================================= + +g\_llvm\_module = Module.new('my cool jit') + +The LLVM instruction builder. Created whenever a new function is entered. +========================================================================= + +g\_llvm\_builder = None + +A dictionary that keeps track of which values are defined in the current scope +============================================================================== + +and what their LLVM representation is. +====================================== + +g\_named\_values = {} + +The function optimization passes manager. +========================================= + +g\_llvm\_pass\_manager = FunctionPassManager.new(g\_llvm\_module) + +The LLVM execution engine. +========================== + +g\_llvm\_executor = ExecutionEngine.new(g\_llvm\_module) + +Lexer +----- + +The lexer yields one of these types for each token. +=================================================== + +class EOFToken(object): pass + +class DefToken(object): pass + +class ExternToken(object): pass + +class IdentifierToken(object): def **init**\ (self, name): self.name = +name + +class NumberToken(object): def **init**\ (self, value): self.value = +value + +class CharacterToken(object): def **init**\ (self, char): self.char = +char def **eq**\ (self, other): return isinstance(other, CharacterToken) +and self.char == other.char def **ne**\ (self, other): return not self +== other + +Regular expressions that tokens and comments of our language. +============================================================= + +REGEX\_NUMBER = re.compile('[0-9]+(?:.[0-9]+)?') REGEX\_IDENTIFIER = +re.compile('[a-zA-Z][a-zA-Z0-9]\ *') REGEX\_COMMENT = re.compile('#.*') + +def Tokenize(string): while string: # Skip whitespace. if +string[0].isspace(): string = string[1:] continue + +:: + + # Run regexes. + comment_match = REGEX_COMMENT.match(string) + number_match = REGEX_NUMBER.match(string) + identifier_match = REGEX_IDENTIFIER.match(string) + + # Check if any of the regexes matched and yield the appropriate result. + if comment_match: + comment = comment_match.group(0) + string = string[len(comment):] + elif number_match: + number = number_match.group(0) + yield NumberToken(float(number)) + string = string[len(number):] + elif identifier_match: + identifier = identifier_match.group(0) + # Check if we matched a keyword. + if identifier == 'def': + yield DefToken() + elif identifier == 'extern': + yield ExternToken() + else: + yield IdentifierToken(identifier) + string = string[len(identifier):] + else: + # Yield the ASCII value of the unknown character. + yield CharacterToken(string[0]) + string = string[1:] + +yield EOFToken() + +Abstract Syntax Tree (aka Parse Tree) +------------------------------------- + +Base class for all expression nodes. +==================================== + +class ExpressionNode(object): pass + +Expression class for numeric literals like "1.0". +================================================= + +class NumberExpressionNode(ExpressionNode): + +def **init**\ (self, value): self.value = value + +def CodeGen(self): return Constant.real(Type.double(), self.value) + +Expression class for referencing a variable, like "a". +====================================================== + +class VariableExpressionNode(ExpressionNode): + +def **init**\ (self, name): self.name = name + +def CodeGen(self): if self.name in g\_named\_values: return +g\_named\_values[self.name] else: raise RuntimeError('Unknown variable +name: ' + self.name) + +Expression class for a binary operator. +======================================= + +class BinaryOperatorExpressionNode(ExpressionNode): + +def **init**\ (self, operator, left, right): self.operator = operator +self.left = left self.right = right + +def CodeGen(self): left = self.left.CodeGen() right = +self.right.CodeGen() + +:: + + if self.operator == '+': + return g_llvm_builder.fadd(left, right, 'addtmp') + elif self.operator == '-': + return g_llvm_builder.fsub(left, right, 'subtmp') + elif self.operator == '*': + return g_llvm_builder.fmul(left, right, 'multmp') + elif self.operator == '<': + result = g_llvm_builder.fcmp(FCMP_ULT, left, right, 'cmptmp') + # Convert bool 0 or 1 to double 0.0 or 1.0. + return g_llvm_builder.uitofp(result, Type.double(), 'booltmp') + else: + raise RuntimeError('Unknown binary operator.') + +Expression class for function calls. +==================================== + +class CallExpressionNode(ExpressionNode): + +def **init**\ (self, callee, args): self.callee = callee self.args = +args + +def CodeGen(self): # Look up the name in the global module table. callee += g\_llvm\_module.get\_function\_named(self.callee) + +:: + + # Check for argument mismatch error. + if len(callee.args) != len(self.args): + raise RuntimeError('Incorrect number of arguments passed.') + + arg_values = [i.CodeGen() for i in self.args] + + return g_llvm_builder.call(callee, arg_values, 'calltmp') + +This class represents the "prototype" for a function, which captures its name, +============================================================================== + +and its argument names (thus implicitly the number of arguments the function +============================================================================ + +takes). +======= + +class PrototypeNode(object): + +def **init**\ (self, name, args): self.name = name self.args = args + +def CodeGen(self): # Make the function type, eg. double(double,double). +funct\_type = Type.function( Type.double(), [Type.double()] \* +len(self.args), False) + +:: + + function = Function.new(g_llvm_module, funct_type, self.name) + + # If the name conflicted, there was already something with the same name. + # If it has a body, don't allow redefinition or reextern. + if function.name != self.name: + function.delete() + function = g_llvm_module.get_function_named(self.name) + + # If the function already has a body, reject this. + if not function.is_declaration: + raise RuntimeError('Redefinition of function.') + + # If F took a different number of args, reject. + if len(callee.args) != len(self.args): + raise RuntimeError('Redeclaration of a function with different number ' + 'of args.') + + # Set names for all arguments and add them to the variables symbol table. + for arg, arg_name in zip(function.args, self.args): + arg.name = arg_name + # Add arguments to variable symbol table. + g_named_values[arg_name] = arg + + return function + +This class represents a function definition itself. +=================================================== + +class FunctionNode(object): + +def **init**\ (self, prototype, body): self.prototype = prototype +self.body = body + +def CodeGen(self): # Clear scope. g\_named\_values.clear() + +:: + + # Create a function object. + function = self.prototype.CodeGen() + + # Create a new basic block to start insertion into. + block = function.append_basic_block('entry') + global g_llvm_builder + g_llvm_builder = Builder.new(block) + + # Finish off the function. + try: + return_value = self.body.CodeGen() + g_llvm_builder.ret(return_value) + + # Validate the generated code, checking for consistency. + function.verify() + + # Optimize the function. + g_llvm_pass_manager.run(function) + except: + function.delete() + raise + + return function + +Parser +------ + +class Parser(object): + +def **init**\ (self, tokens, binop\_precedence): self.tokens = tokens +self.binop\_precedence = binop\_precedence self.Next() + +# Provide a simple token buffer. Parser.current is the current token the +# parser is looking at. Parser.Next() reads another token from the lexer +and # updates Parser.current with its results. def Next(self): +self.current = self.tokens.next() + +# Gets the precedence of the current token, or -1 if the token is not a +binary # operator. def GetCurrentTokenPrecedence(self): if +isinstance(self.current, CharacterToken): return +self.binop\_precedence.get(self.current.char, -1) else: return -1 + +# identifierexpr ::= identifier \| identifier '(' expression\* ')' def +ParseIdentifierExpr(self): identifier\_name = self.current.name +self.Next() # eat identifier. + +:: + + if self.current != CharacterToken('('): # Simple variable reference. + return VariableExpressionNode(identifier_name) + + # Call. + self.Next() # eat '('. + args = [] + if self.current != CharacterToken(')'): + while True: + args.append(self.ParseExpression()) + if self.current == CharacterToken(')'): + break + elif self.current != CharacterToken(','): + raise RuntimeError('Expected ")" or "," in argument list.') + self.Next() + + self.Next() # eat ')'. + return CallExpressionNode(identifier_name, args) + +# numberexpr ::= number def ParseNumberExpr(self): result = +NumberExpressionNode(self.current.value) self.Next() # consume the +number. return result + +# parenexpr ::= '(' expression ')' def ParseParenExpr(self): self.Next() +# eat '('. + +:: + + contents = self.ParseExpression() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")".') + self.Next() # eat ')'. + + return contents + +# primary ::= identifierexpr \| numberexpr \| parenexpr def +ParsePrimary(self): if isinstance(self.current, IdentifierToken): return +self.ParseIdentifierExpr() elif isinstance(self.current, NumberToken): +return self.ParseNumberExpr() elif self.current == CharacterToken('('): +return self.ParseParenExpr() else: raise RuntimeError('Unknown token +when expecting an expression.') + +# binoprhs ::= (operator primary)\* def ParseBinOpRHS(self, left, +left\_precedence): # If this is a binary operator, find its precedence. +while True: precedence = self.GetCurrentTokenPrecedence() + +:: + + # If this is a binary operator that binds at least as tightly as the + # current one, consume it; otherwise we are done. + if precedence < left_precedence: + return left + + binary_operator = self.current.char + self.Next() # eat the operator. + + # Parse the primary expression after the binary operator. + right = self.ParsePrimary() + + # If binary_operator binds less tightly with right than the operator after + # right, let the pending operator take right as its left. + next_precedence = self.GetCurrentTokenPrecedence() + if precedence < next_precedence: + right = self.ParseBinOpRHS(right, precedence + 1) + + # Merge left/right. + left = BinaryOperatorExpressionNode(binary_operator, left, right) + +# expression ::= primary binoprhs def ParseExpression(self): left = +self.ParsePrimary() return self.ParseBinOpRHS(left, 0) + +# prototype ::= id '(' id\* ')' def ParsePrototype(self): if not +isinstance(self.current, IdentifierToken): raise RuntimeError('Expected +function name in prototype.') + +:: + + function_name = self.current.name + self.Next() # eat function name. + + if self.current != CharacterToken('('): + raise RuntimeError('Expected "(" in prototype.') + self.Next() # eat '('. + + arg_names = [] + while isinstance(self.current, IdentifierToken): + arg_names.append(self.current.name) + self.Next() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")" in prototype.') + + # Success. + self.Next() # eat ')'. + + return PrototypeNode(function_name, arg_names) + +# definition ::= 'def' prototype expression def ParseDefinition(self): +self.Next() # eat def. proto = self.ParsePrototype() body = +self.ParseExpression() return FunctionNode(proto, body) + +# toplevelexpr ::= expression def ParseTopLevelExpr(self): proto = +PrototypeNode('', []) return FunctionNode(proto, self.ParseExpression()) + +# external ::= 'extern' prototype def ParseExtern(self): self.Next() # +eat extern. return self.ParsePrototype() + +# Top-Level parsing def HandleDefinition(self): +self.Handle(self.ParseDefinition, 'Read a function definition:') + +def HandleExtern(self): self.Handle(self.ParseExtern, 'Read an extern:') + +def HandleTopLevelExpression(self): try: function = +self.ParseTopLevelExpr().CodeGen() result = +g\_llvm\_executor.run\_function(function, []) print 'Evaluated to:', +result.as\_real(Type.double()) except Exception, e: print 'Error:', e +try: self.Next() # Skip for error recovery. except: pass + +def Handle(self, function, message): try: print message, +function().CodeGen() except Exception, e: print 'Error:', e try: +self.Next() # Skip for error recovery. except: pass + +Main driver code. +----------------- + +def main(): # Set up the optimizer pipeline. Start with registering info +about how the # target lays out data structures. +g\_llvm\_pass\_manager.add(g\_llvm\_executor.target\_data) # Do simple +"peephole" optimizations and bit-twiddling optzns. +g\_llvm\_pass\_manager.add(PASS\_INSTRUCTION\_COMBINING) # Reassociate +expressions. g\_llvm\_pass\_manager.add(PASS\_REASSOCIATE) # Eliminate +Common SubExpressions. g\_llvm\_pass\_manager.add(PASS\_GVN) # Simplify +the control flow graph (deleting unreachable blocks, etc). +g\_llvm\_pass\_manager.add(PASS\_CFG\_SIMPLIFICATION) + +g\_llvm\_pass\_manager.initialize() + +# Install standard binary operators. # 1 is lowest possible precedence. +40 is the highest. operator\_precedence = { '<': 10, '+': 20, '-': 20, +'\*': 40 } + +# Run the main "interpreter loop". while True: print 'ready>', try: raw += raw\_input() except KeyboardInterrupt: break + +:: + + parser = Parser(Tokenize(raw), operator_precedence) + while True: + # top ::= definition | external | expression | EOF + if isinstance(parser.current, EOFToken): + break + if isinstance(parser.current, DefToken): + parser.HandleDefinition() + elif isinstance(parser.current, ExternToken): + parser.HandleExtern() + else: + parser.HandleTopLevelExpression() + +# Print out all of the generated code. print '', g\_llvm\_module + +if **name** == '**main**\ ': main() {% endhighlight %} + +-------------- + +**`Next: Extending the language: control flow `_** diff --git a/docs/source/doc/kaleidoscope/PythonLangImpl5.md b/docs/source/doc/kaleidoscope/PythonLangImpl5.md deleted file mode 100644 index 93f4a36..0000000 --- a/docs/source/doc/kaleidoscope/PythonLangImpl5.md +++ /dev/null @@ -1,1464 +0,0 @@ ---- -layout: page -title: "Kaleidoscope: Chapter 5" ---- - -# Extending the Language: Control Flow - -Written by [Chris Lattner](mailto:sabre@nondot.org) -and [Max Shawabkeh](http://max99x.com) - - -**Chapter 5** - - -* This will become a table of contents (this text will be scraped). -{:toc} - - -**[Chapter 6: Extending the Language: User-defined Operators](PythonLangImpl6.html)** - - -# Introduction # {#intro} - - -Welcome to Chapter 5 of the -[Implementing a language with LLVM](http://www.llvm.org/docs/tutorial/index.html) -tutorial. Parts 1-4 described the implementation of the simple -Kaleidoscope language and included support for generating LLVM IR, followed by -optimizations and a JIT compiler. Unfortunately, as presented, Kaleidoscope is -mostly useless: it has no control flow other than call and return. This means -that you can't have conditional branches in the code, significantly limiting its -power. In this episode of "build that compiler", we'll extend Kaleidoscope to -have an if/then/else expression plus a simple 'for' loop. - - -* * * - -# If/Then/Else # {#ifthen} - -Extending Kaleidoscope to support if/then/else is quite straightforward. It -basically requires adding lexer support for this "new" concept to the lexer, -parser, AST, and LLVM code emitter. This example is nice, because it shows how -easy it is to "grow" a language over time, incrementally extending it as new -ideas are discovered. - -Before we get going on "how" we add this extension, lets talk about "what" we -want. The basic idea is that we want to be able to write this sort of thing: - - - -{% highlight python %} -def fib(x) - if x < 3 then - 1 - else - fib(x-1) + fib(x-2) -{% endhighlight %} - - -In Kaleidoscope, every construct is an expression: there are no statements. -As such, the if/then/else expression needs to return a value like any other. -Since we're using a mostly functional form, we'll have it evaluate its -conditional, then return the 'then' or 'else' value based on how the condition -was resolved. This is very similar to the C "?:" expression. - -The semantics of the if/then/else expression is that it evaluates the -condition to a boolean equality value: 0.0 is considered to be false and -everything else is considered to be true. -If the condition is true, the first subexpression is evaluated and returned, if -the condition is false, the second subexpression is evaluated and returned. -Since Kaleidoscope allows side-effects, this behavior is important to nail down. - - -Now that we know what we "want", let's break this down into its constituent -pieces. - - - -## Lexer Extensions for If/Then/Else ## {#iflexer} - -The lexer extensions are straightforward. First we add new token classes for -the relevant tokens: - -{% highlight python %} -class IfToken(object): pass -class ThenToken(object): pass -class ElseToken(object): pass -{% endhighlight %} - - -Once we have that, we recognize the new keywords in the lexer. This is pretty -simple stuff: - - -{% highlight python %} - ... - if identifier == 'def': - yield DefToken() - elif identifier == 'extern': - yield ExternToken() - elif identifier == 'if': - yield IfToken() - elif identifier == 'then': - yield ThenToken() - elif identifier == 'else': - yield ElseToken() - else: - yield IdentifierToken(identifier) -{% endhighlight %} - - -## AST Extensions for If/Then/Else ## {#ifast} - -To represent the new expression we add a new AST node for it: - -{% highlight python %} -# Expression class for if/then/else. -class IfExpressionNode(ExpressionNode): - - def __init__(self, condition, then_branch, else_branch): - self.condition = condition - self.then_branch = then_branch - self.else_branch = else_branch - - def CodeGen(self): - ... -{% endhighlight %} - - -The AST node just has pointers to the various subexpressions. - -## Parser Extensions for If/Then/Else ## {#ifparser} - -Now that we have the relevant tokens coming from the lexer and we have the -AST node to build, our parsing logic is relatively straightforward. First we -define a new parsing function: - - -{% highlight python %} - # ifexpr ::= 'if' expression 'then' expression 'else' expression - def ParseIfExpr(self): - self.Next() # eat the if. - - # condition. - condition = self.ParseExpression() - - if not isinstance(self.current, ThenToken): - raise RuntimeError('Expected "then".') - self.Next() # eat the then. - - then_branch = self.ParseExpression() - - if not isinstance(self.current, ElseToken): - raise RuntimeError('Expected "else".') - self.Next() # eat the else. - - else_branch = self.ParseExpression() - - return IfExpressionNode(condition, then_branch, else_branch) -{% endhighlight %} - - -Next we hook it up as a primary expression: - - -{% highlight python %} - def ParsePrimary(self): - if isinstance(self.current, IdentifierToken): - return self.ParseIdentifierExpr() - elif isinstance(self.current, NumberToken): - return self.ParseNumberExpr(); - elif isinstance(self.current, IfToken): - return self.ParseIfExpr() - elif self.current == CharacterToken('('): - return self.ParseParenExpr() - else: - raise RuntimeError('Unknown token when expecting an expression.') -{% endhighlight %} - - -## LLVM IR for If/Then/Else ## {#ifir} - -Now that we have it parsing and building the AST, the final piece is adding -LLVM code generation support. This is the most interesting part of the -if/then/else example, because this is where it starts to introduce new concepts. -All of the code above has been thoroughly described in previous chapters. - - -To motivate the code we want to produce, lets take a look at a simple -example. Consider: - - -{% highlight python %} -extern foo(); -extern bar(); -def baz(x) if x then foo() else bar(); -{% endhighlight %} - - -If you disable optimizations, the code you'll (soon) get from Kaleidoscope -looks something like this: - - - -{% highlight llvm %} -declare double @foo() -declare double @bar() -define double @baz(double %x) { -entry: - %ifcond = fcmp one double %x, 0.000000e+00 - br i1 %ifcond, label %then, label %else -then: ; preds = %entry - %calltmp1 = call double @bar() -else: ; preds = %entry - %calltmp1 = call double @bar() - br label %ifcont -ifcont: ; preds = %else, %then - %iftmp = phi double [ %calltmp, %then ], [ %calltmp1, %else ] - ret double %iftmp -} -{% endhighlight %} - - -To visualize the control flow graph, you can use a nifty feature of the LLVM -[opt](http://llvm.org/cmds/opt.html) tool. If you put this LLVM IR -into "t.ll" and run `llvm-as < t.ll | opt -analyze -view-cfg`, a -[window will pop up](http://www.llvm.org/docs/ProgrammersManual.html#ViewGraph) - and you'll see this graph: - -Example CFG - -Another way to get this is to call "`function.viewCFG()`" or -"`function.viewCFGOnly()`" (where F is a "`llvm.core.Function`") -either by inserting actual calls into the code and recompiling or by calling -these in the debugger. LLVM has many nice features for visualizing various -graphs, but note that these are available only if your LLVM was built with -Graphviz support (accomplished by having Graphviz and Ghostview installed when -building LLVM). - -Getting back to the generated code, it is fairly simple: the entry block -evaluates the conditional expression ("x" in our case here) and compares the -result to 0.0 with the -[fcmp](http://www.llvm.org/docs/LangRef.html#i_fcmp) one -instruction ('one' is "Ordered and Not Equal"). Based on the result of this -expression, the code jumps to either the "then" or "else" blocks, which contain -the expressions for the true/false cases. - -Once the then/else blocks are finished executing, they both branch back to -the 'ifcont' block to execute the code that happens after the if/then/else. In -this case the only thing left to do is to return to the caller of the function. -The question then becomes: how does the code know which expression to return? - - -The answer to this question involves an important SSA operation: the -[Phi operation](http://en.wikipedia.org/wiki/Static_single_assignment_form). -If you're not familiar with SSA, -[the wikipedia article](http://en.wikipedia.org/wiki/Static_single_assignment_form) -is a good introduction and there are various other introductions to -it available on your favorite search engine. The short version is that -"execution" of the Phi operation requires "remembering" which block control came -from. The Phi operation takes on the value corresponding to the input control -block. In this case, if control comes in from the "then" block, it gets the -value of "calltmp". If control comes from the "else" block, it gets the value -of "calltmp1". - -At this point, you are probably starting to think "Oh no! This means my -simple and elegant front-end will have to start generating SSA form in order to -use LLVM!". Fortunately, this is not the case, and we strongly advise -*not* implementing an SSA construction algorithm in your front-end -unless there is an amazingly good reason to do so. In practice, there are two -sorts of values that float around in code written for your average imperative -programming language that might need Phi nodes: - -1. Code that involves user variables: `x = 1; x = x + 1;` -2. Values that are implicit in the structure of your AST, - such as the Phi node in this case. - -In [Chapter 7](PythonLangImpl7.html) of this tutorial ("mutable -variables"), we'll talk about #1 in depth. For now, just believe me that you -don't need SSA construction to handle this case. For #2, you have the choice of -using the techniques that we will describe for #1, or you can insert Phi nodes -directly, if convenient. In this case, it is really really easy to generate -the Phi node, so we choose to do it directly. - -Okay, enough of the motivation and overview, lets generate code! - - -## Code Generation for If/Then/Else ## {#ifcodegen} - -In order to generate code for this, we implement the `Codegen` method -for `IfExpressionNode`: - - -{% highlight python %} - def CodeGen(self): - condition = self.condition.CodeGen() - - # Convert condition to a bool by comparing equal to 0.0. - condition_bool = g_llvm_builder.fcmp( - FCMP_ONE, condition, Constant.real(Type.double(), 0), 'ifcond') -{% endhighlight %} - - -This code is straightforward and similar to what we saw before. We emit the -expression for the condition, then compare that value to zero to get a truth -value as a 1-bit (bool) value. - - -{% highlight python %} - function = g_llvm_builder.basic_block.function - - # Create blocks for the then and else cases. Insert the 'then' block at the - # end of the function. - then_block = function.append_basic_block('then') - else_block = function.append_basic_block('else') - merge_block = function.append_basic_block('ifcond') - - g_llvm_builder.cbranch(condition_bool, then_block, else_block) -{% endhighlight %} - - -This code creates the basic blocks that are related to the if/then/else -statement, and correspond directly to the blocks in the example above. The -first line gets the current Function object that is being built. It -gets this by asking the builder for the current BasicBlock, and asking that -block for its "parent" (the function it is currently embedded into). - -Once it has that, it creates three block which are automatically inserted -into the end of the function. Once the blocks are created, we can emit the -conditional branch that chooses between them. Note that creating new blocks -does not implicitly affect the Builder, so it is still inserting into the block -that the condition went into. - - -{% highlight python %} - # Emit then value. - g_llvm_builder.position_at_end(then_block) - then_value = self.then_branch.CodeGen() - g_llvm_builder.branch(merge_block) - - # Codegen of 'Then' can change the current block; update then_block for the - # PHI node. - then_block = g_llvm_builder.basic_block -{% endhighlight %} - - -After the conditional branch is inserted, we move the builder to start -inserting into the "then" block. Strictly speaking, this call moves the -insertion point to be at the end of the specified block. However, since the -"then" block is empty, it also starts out by inserting at the beginning of the -block. :) - -Once the insertion point is set, we recursively codegen the "then" expression -from the AST. To finish off the "then" block, we create an unconditional branch -to the merge block. One interesting (and very important) aspect of the LLVM IR -is that it -[requires all basic blocks to be "terminated"](http://www.llvm.org/docs/LangRef.html#functionstructure) with a -[control flow instruction](http://www.llvm.org/docs/LangRef.html#terminators) - such as return or branch. This means that all control flow, -*including fallthroughs* must be made explicit in the LLVM IR. If you -violate this rule, the verifier will emit an error. - -The final line here is quite subtle, but is very important. The basic issue -is that when we create the Phi node in the merge block, we need to set up the -block/value pairs that indicate how the Phi will work. Importantly, the Phi -node expects to have an entry for each predecessor of the block in the CFG. Why -then, are we getting the current block when we just set it to then_block 5 lines -above? The problem is that the "Then" expression may actually itself change the -block that the Builder is emitting into if, for example, it contains a nested -"if/then/else" expression. Because calling Codegen recursively could -arbitrarily change the notion of the current block, we are required to get an -up-to-date value for code that will set up the Phi node. - - -{% highlight python %} - # Emit else block. - g_llvm_builder.position_at_end(else_block) - else_value = self.else_branch.CodeGen() - g_llvm_builder.branch(merge_block) - - # Codegen of 'Else' can change the current block, update else_block for the - # PHI node. - else_block = g_llvm_builder.basic_block -{% endhighlight %} - - -Code generation for the 'else' block is basically identical to codegen for -the 'then' block. The only significant difference is the first line, which adds -the 'else' block to the function. Recall previously that the 'else' block was -created, but not added to the function. Now that the 'then' and 'else' blocks -are emitted, we can finish up with the merge code: - - -{% highlight python %} - # Emit merge block. - g_llvm_builder.position_at_end(merge_block) - phi = g_llvm_builder.phi(Type.double(), 'iftmp') - phi.add_incoming(then_value, then_block) - phi.add_incoming(else_value, else_block) - - return phi -{% endhighlight %} - - -The first line changes the insertion point so that newly created code will go -into the "merge" block. Once that is done, we need to create the PHI node and -set up the block/value pairs for the PHI. - -Finally, the CodeGen function returns the phi node as the value computed by -the if/then/else expression. In our example above, this returned value will -feed into the code for the top-level function, which will create the return -instruction. - -Overall, we now have the ability to execute conditional code in -Kaleidoscope. With this extension, Kaleidoscope is a fairly complete language -that can calculate a wide variety of numeric functions. Next up we'll add -another useful expression that is familiar from non-functional languages... - - -* * * - -# 'for' Loop Expression # {#for} - - -Now that we know how to add basic control flow constructs to the language, -we have the tools to add more powerful things. Lets add something more -aggressive, a 'for' expression: - - -{% highlight python %} - extern putchard(char) - def printstar(n) - for i = 1, i < n, 1.0 in - putchard(42) # ascii 42 = '*' - - # print 100 '*' characters - printstar(100) -{% endhighlight %} - - -This expression defines a new variable (`i` in this case) which iterates from -a starting value, while the condition (`i < n` in this case) is true, -incrementing by an optional step value ("1.0" in this case). If the step value -is omitted, it defaults to 1.0. While the loop is true, it executes its -body expression. Because we don't have anything better to return, we'll just -define the loop as always returning 0.0. In the future when we have mutable -variables, it will get more useful. - -As before, lets talk about the changes that we need to Kaleidoscope to -support this. - - -## Lexer Extensions for the 'for' Loop ## {#forlexer} - -The lexer extensions are the same sort of thing as for if/then/else: - - -{% highlight python %} -... - -class ThenToken(object): pass -class ElseToken(object): pass -class ForToken(object): pass -class InToken(object): pass - -... - -def Tokenize(string): - - ... - - elif identifier == 'else': - yield ElseToken() - elif identifier == 'for': - yield ForToken() - elif identifier == 'in': - yield InToken() - else: - yield IdentifierToken(identifier) -{% endhighlight %} - - -## AST Extensions for the 'for' Loop ## {#forast} - -The AST node is just as simple. It basically boils down to capturing -the variable name and the constituent expressions in the node. - - -{% highlight python %} -# Expression class for for/in. -class ForExpressionNode(ExpressionNode): - - def __init__(self, loop_variable, start, end, step, body): - self.loop_variable = loop_variable - self.start = start - self.end = end - self.step = step - self.body = body - - def CodeGen(self): - ... -{% endhighlight %} - - -## Parser Extensions for the 'for' Loop ## {#forparser} - -The parser code is also fairly standard. The only interesting thing here is -handling of the optional step value. The parser code handles it by checking to -see if the second comma is present. If not, it sets the step value to null in -the AST node: - - -{% highlight python %} - # forexpr ::= 'for' identifier '=' expr ',' expr (',' expr)? 'in' expression - def ParseForExpr(self): - self.Next() # eat the for. - - if not isinstance(self.current, IdentifierToken): - raise RuntimeError('Expected identifier after for.') - - loop_variable = self.current.name - self.Next() # eat the identifier. - - if self.current != CharacterToken('='): - raise RuntimeError('Expected "=" after for variable.') - self.Next() # eat the '='. - - start = self.ParseExpression() - - if self.current != CharacterToken(','): - raise RuntimeError('Expected "," after for start value.') - self.Next() # eat the ','. - - end = self.ParseExpression() - - # The step value is optional. - if self.current == CharacterToken(','): - self.Next() # eat the ','. - step = self.ParseExpression() - else: - step = None - - if not isinstance(self.current, InToken): - raise RuntimeError('Expected "in" after for variable specification.') - self.Next() # eat 'in'. - - body = self.ParseExpression() - - return ForExpressionNode(loop_variable, start, end, step, body) -{% endhighlight %} - - -## LLVM IR for the 'for' Loop ## {#forir} - -Now we get to the good part: the LLVM IR we want to generate for this thing. -With the simple example above, we get this LLVM IR (note that this dump is -generated with optimizations disabled for clarity): - - - -{% highlight llvm %} -declare double @putchard(double) -define double @printstar(double %n) { -entry: - ; initial value = 1.0 (inlined into phi) - br label %loop -loop: ; preds = %loop, %entry - %i = phi double [ 1.000000e+00, %entry ], [ %nextvar, %loop ] - ; body - %calltmp = call double @putchard(double 4.200000e+01) - ; increment - %nextvar = fadd double %i, 1.000000e+00 - ; termination test - %cmptmp = fcmp ult double %i, %n - %booltmp = uitofp i1 %cmptmp to double - %loopcond = fcmp one double %booltmp, 0.000000e+00 - br i1 %loopcond, label %loop, label %afterloop -afterloop: ; preds = %loop - ; loop always returns 0.0 - ret double 0.000000e+00 -} -{% endhighlight %} - - -This loop contains all the same constructs we saw before: a phi node, several -expressions, and some basic blocks. Lets see how this fits together. - - - - -## Code Generation for the 'for' Loop ## {#forcodegen} - -The first part of Codegen is very simple: we just output the start expression -for the loop value: - - -{% highlight python %} - def CodeGen(self): - # Emit the start code first, without 'variable' in scope. - start_value = self.start.CodeGen() -{% endhighlight %} - - -With this out of the way, the next step is to set up the LLVM basic block -for the start of the loop body. In the case above, the whole loop body is one -block, but remember that the body code itself could consist of multiple blocks -(e.g. if it contains an if/then/else or a for/in expression). - - -{% highlight python %} - # Make the new basic block for the loop header, inserting after current - # block. - function = g_llvm_builder.basic_block.function - pre_header_block = g_llvm_builder.basic_block - loop_block = function.append_basic_block('loop') - - # Insert an explicit fallthrough from the current block to the loop_block. - g_llvm_builder.branch(loop_block) -{% endhighlight %} - - -This code is similar to what we saw for if/then/else. Because we will need -it to create the Phi node, we remember the block that falls through into the -loop. Once we have that, we create the actual block that starts the loop and -create an unconditional branch for the fall-through between the two blocks. - - -{% highlight python %} - # Start insertion in loop_block. - g_llvm_builder.position_at_end(loop_block); - - # Start the PHI node with an entry for start. - variable_phi = g_llvm_builder.phi(Type.double(), self.loop_variable) - variable_phi.add_incoming(start_value, pre_header_block) -{% endhighlight %} - - -Now that the "pre_header_block" for the loop is set up, we switch to emitting -code for the loop body. To begin with, we move the insertion point and create -the PHI node for the loop induction variable. Since we already know the -incoming value for the starting value, we add it to the Phi node. Note that the -Phi will eventually get a second value for the backedge, but we can't set it up -yet (because it doesn't exist!). - - -{% highlight python %} - # Within the loop, the variable is defined equal to the PHI node. If it - # shadows an existing variable, we have to restore it, so save it now. - old_value = g_named_values.get(self.loop_variable, None) - g_named_values[self.loop_variable] = variable_phi - - # Emit the body of the loop. This, like any other expr, can change the - # current BB. Note that we ignore the value computed by the body. - self.body.CodeGen() -{% endhighlight %} - - -Now the code starts to get more interesting. Our 'for' loop introduces a new -variable to the symbol table. This means that our symbol table can now contain -either function arguments or loop variables. To handle this, before we codegen -the body of the loop, we add the loop variable as the current value for its -name. Note that it is possible that there is a variable of the same name in the -outer scope. It would be easy to make this an error (emit an error and return -null if there is already an entry for VarName) but we choose to allow shadowing -of variables. In order to handle this correctly, we remember the Value that -we are potentially shadowing in `old_value` (which will be None if there -is no shadowed variable). - -Once the loop variable is set into the symbol table, the code recursively -codegen's the body. This allows the body to use the loop variable: any -references to it will naturally find it in the symbol table. - - -{% highlight python %} - # Emit the step value. - if self.step: - step_value = self.step.CodeGen() - else: - # If not specified, use 1.0. - step_value = Constant.real(Type.double(), 1) - - next_value = g_llvm_builder.fadd(variable_phi, step_value, 'next') -{% endhighlight %} - - -Now that the body is emitted, we compute the next value of the iteration -variable by adding the step value, or 1.0 if it isn't present. -`next_value` will be the value of the loop variable on the next iteration -of the loop. - - -{% highlight python %} - # Compute the end condition and convert it to a bool by comparing to 0.0. - end_condition = self.end.CodeGen() - end_condition_bool = g_llvm_builder.fcmp( - FCMP_ONE, end_condition, Constant.real(Type.double(), 0), 'loopcond') -{% endhighlight %} - - -Finally, we evaluate the exit value of the loop, to determine whether the -loop should exit. This mirrors the condition evaluation for the if/then/else -statement. - - -{% highlight python %} - # Create the "after loop" block and insert it. - loop_end_block = g_llvm_builder.basic_block - after_block = function.append_basic_block('afterloop') - - # Insert the conditional branch into the end of loop_end_block. - g_llvm_builder.cbranch(end_condition_bool, loop_block, after_block) - - # Any new code will be inserted in after_block. - g_llvm_builder.position_at_end(after_block) -{% endhighlight %} - - -With the code for the body of the loop complete, we just need to finish up -the control flow for it. This code remembers the end block (for the phi node), -then creates the block for the loop exit ("afterloop"). Based on the value of -the exit condition, it creates a conditional branch that chooses between -executing the loop again and exiting the loop. Any future code is emitted in -the "afterloop" block, so it sets the insertion position to it. - - -{% highlight python %} - # Add a new entry to the PHI node for the backedge. - variable_phi.add_incoming(next_value, loop_end_block) - - # Restore the unshadowed variable. - if old_value: - g_named_values[self.loop_variable] = old_value - else: - del g_named_values[self.loop_variable] - - # for expr always returns 0.0. - return Constant.real(Type.double(), 0) -{% endhighlight %} - - -The final code handles various cleanups: now that we have the "next_value", -we can add the incoming value to the loop PHI node. After that, we remove the -loop variable from the symbol table, so that it isn't in scope after the for -loop. Finally, code generation of the for loop always returns 0.0, so that is -what we return from `ForExpressionNode::CodeGen`. - -With this, we conclude the "adding control flow to Kaleidoscope" chapter of -the tutorial. In this chapter we added two control flow constructs, and used -them to motivate a couple of aspects of the LLVM IR that are important for -front-end implementors to know. In the next chapter of our saga, we will get a -bit crazier and add [user-defined operators](PythonLangImpl6.html) to -our poor innocent language. - -* * * - -# Full Code Listing # {#code} - -Here is the complete code listing for our running example, enhanced with the -if/then/else and for expressions: - - -{% highlight python %} -#!/usr/bin/env python - -import re -from llvm.core import Module, Constant, Type, Function, Builder -from llvm.ee import ExecutionEngine, TargetData -from llvm.passes import FunctionPassManager - -from llvm.core import FCMP_ULT, FCMP_ONE -from llvm.passes import (PASS_INSTRUCTION_COMBINING, - PASS_REASSOCIATE, - PASS_GVN, - PASS_CFG_SIMPLIFICATION) - -################################################################################ -## Globals -################################################################################ - -# The LLVM module, which holds all the IR code. -g_llvm_module = Module.new('my cool jit') - -# The LLVM instruction builder. Created whenever a new function is entered. -g_llvm_builder = None - -# A dictionary that keeps track of which values are defined in the current scope -# and what their LLVM representation is. -g_named_values = {} - -# The function optimization passes manager. -g_llvm_pass_manager = FunctionPassManager.new(g_llvm_module) - -# The LLVM execution engine. -g_llvm_executor = ExecutionEngine.new(g_llvm_module) - -################################################################################ -## Lexer -################################################################################ - -# The lexer yields one of these types for each token. -class EOFToken(object): pass -class DefToken(object): pass -class ExternToken(object): pass -class IfToken(object): pass -class ThenToken(object): pass -class ElseToken(object): pass -class ForToken(object): pass -class InToken(object): pass - -class IdentifierToken(object): - def __init__(self, name): self.name = name - -class NumberToken(object): - def __init__(self, value): self.value = value - -class CharacterToken(object): - def __init__(self, char): self.char = char - def __eq__(self, other): - return isinstance(other, CharacterToken) and self.char == other.char - def __ne__(self, other): return not self == other - -# Regular expressions that tokens and comments of our language. -REGEX_NUMBER = re.compile('[0-9]+(?:\.[0-9]+)?') -REGEX_IDENTIFIER = re.compile('[a-zA-Z][a-zA-Z0-9]*') -REGEX_COMMENT = re.compile('#.*') - -def Tokenize(string): - while string: - # Skip whitespace. - if string[0].isspace(): - string = string[1:] - continue - - # Run regexes. - comment_match = REGEX_COMMENT.match(string) - number_match = REGEX_NUMBER.match(string) - identifier_match = REGEX_IDENTIFIER.match(string) - - # Check if any of the regexes matched and yield the appropriate result. - if comment_match: - comment = comment_match.group(0) - string = string[len(comment):] - elif number_match: - number = number_match.group(0) - yield NumberToken(float(number)) - string = string[len(number):] - elif identifier_match: - identifier = identifier_match.group(0) - # Check if we matched a keyword. - if identifier == 'def': - yield DefToken() - elif identifier == 'extern': - yield ExternToken() - elif identifier == 'if': - yield IfToken() - elif identifier == 'then': - yield ThenToken() - elif identifier == 'else': - yield ElseToken() - elif identifier == 'for': - yield ForToken() - elif identifier == 'in': - yield InToken() - else: - yield IdentifierToken(identifier) - string = string[len(identifier):] - else: - # Yield the ASCII value of the unknown character. - yield CharacterToken(string[0]) - string = string[1:] - - yield EOFToken() - -################################################################################ -## Abstract Syntax Tree (aka Parse Tree) -################################################################################ - -# Base class for all expression nodes. -class ExpressionNode(object): - pass - -# Expression class for numeric literals like "1.0". -class NumberExpressionNode(ExpressionNode): - - def __init__(self, value): - self.value = value - - def CodeGen(self): - return Constant.real(Type.double(), self.value) - -# Expression class for referencing a variable, like "a". -class VariableExpressionNode(ExpressionNode): - - def __init__(self, name): - self.name = name - - def CodeGen(self): - if self.name in g_named_values: - return g_named_values[self.name] - else: - raise RuntimeError('Unknown variable name: ' + self.name) - -# Expression class for a binary operator. -class BinaryOperatorExpressionNode(ExpressionNode): - - def __init__(self, operator, left, right): - self.operator = operator - self.left = left - self.right = right - - def CodeGen(self): - left = self.left.CodeGen() - right = self.right.CodeGen() - - if self.operator == '+': - return g_llvm_builder.fadd(left, right, 'addtmp') - elif self.operator == '-': - return g_llvm_builder.fsub(left, right, 'subtmp') - elif self.operator == '*': - return g_llvm_builder.fmul(left, right, 'multmp') - elif self.operator == '<': - result = g_llvm_builder.fcmp(FCMP_ULT, left, right, 'cmptmp') - # Convert bool 0 or 1 to double 0.0 or 1.0. - return g_llvm_builder.uitofp(result, Type.double(), 'booltmp') - else: - raise RuntimeError('Unknown binary operator.') - -# Expression class for function calls. -class CallExpressionNode(ExpressionNode): - - def __init__(self, callee, args): - self.callee = callee - self.args = args - - def CodeGen(self): - # Look up the name in the global module table. - callee = g_llvm_module.get_function_named(self.callee) - - # Check for argument mismatch error. - if len(callee.args) != len(self.args): - raise RuntimeError('Incorrect number of arguments passed.') - - arg_values = [i.CodeGen() for i in self.args] - - return g_llvm_builder.call(callee, arg_values, 'calltmp') - -# Expression class for if/then/else. -class IfExpressionNode(ExpressionNode): - - def __init__(self, condition, then_branch, else_branch): - self.condition = condition - self.then_branch = then_branch - self.else_branch = else_branch - - def CodeGen(self): - condition = self.condition.CodeGen() - - # Convert condition to a bool by comparing equal to 0.0. - condition_bool = g_llvm_builder.fcmp( - FCMP_ONE, condition, Constant.real(Type.double(), 0), 'ifcond') - - function = g_llvm_builder.basic_block.function - - # Create blocks for the then and else cases. Insert the 'then' block at the - # end of the function. - then_block = function.append_basic_block('then') - else_block = function.append_basic_block('else') - merge_block = function.append_basic_block('ifcond') - - g_llvm_builder.cbranch(condition_bool, then_block, else_block) - - # Emit then value. - g_llvm_builder.position_at_end(then_block) - then_value = self.then_branch.CodeGen() - g_llvm_builder.branch(merge_block) - - # Codegen of 'Then' can change the current block; update then_block for the - # PHI node. - then_block = g_llvm_builder.basic_block - - # Emit else block. - g_llvm_builder.position_at_end(else_block) - else_value = self.else_branch.CodeGen() - g_llvm_builder.branch(merge_block) - - # Codegen of 'Else' can change the current block, update else_block for the - # PHI node. - else_block = g_llvm_builder.basic_block - - # Emit merge block. - g_llvm_builder.position_at_end(merge_block) - phi = g_llvm_builder.phi(Type.double(), 'iftmp') - phi.add_incoming(then_value, then_block) - phi.add_incoming(else_value, else_block) - - return phi - -# Expression class for for/in. -class ForExpressionNode(ExpressionNode): - - def __init__(self, loop_variable, start, end, step, body): - self.loop_variable = loop_variable - self.start = start - self.end = end - self.step = step - self.body = body - - def CodeGen(self): - # Output this as: - # ... - # start = startexpr - # goto loop - # loop: - # variable = phi [start, loopheader], [nextvariable, loopend] - # ... - # bodyexpr - # ... - # loopend: - # step = stepexpr - # nextvariable = variable + step - # endcond = endexpr - # br endcond, loop, endloop - # outloop: - - # Emit the start code first, without 'variable' in scope. - start_value = self.start.CodeGen() - - # Make the new basic block for the loop header, inserting after current - # block. - function = g_llvm_builder.basic_block.function - pre_header_block = g_llvm_builder.basic_block - loop_block = function.append_basic_block('loop') - - # Insert an explicit fallthrough from the current block to the loop_block. - g_llvm_builder.branch(loop_block) - - # Start insertion in loop_block. - g_llvm_builder.position_at_end(loop_block) - - # Start the PHI node with an entry for start. - variable_phi = g_llvm_builder.phi(Type.double(), self.loop_variable) - variable_phi.add_incoming(start_value, pre_header_block) - - # Within the loop, the variable is defined equal to the PHI node. If it - # shadows an existing variable, we have to restore it, so save it now. - old_value = g_named_values.get(self.loop_variable, None) - g_named_values[self.loop_variable] = variable_phi - - # Emit the body of the loop. This, like any other expr, can change the - # current BB. Note that we ignore the value computed by the body. - self.body.CodeGen() - - # Emit the step value. - if self.step: - step_value = self.step.CodeGen() - else: - # If not specified, use 1.0. - step_value = Constant.real(Type.double(), 1) - - next_value = g_llvm_builder.fadd(variable_phi, step_value, 'next') - - # Compute the end condition and convert it to a bool by comparing to 0.0. - end_condition = self.end.CodeGen() - end_condition_bool = g_llvm_builder.fcmp( - FCMP_ONE, end_condition, Constant.real(Type.double(), 0), 'loopcond') - - # Create the "after loop" block and insert it. - loop_end_block = g_llvm_builder.basic_block - after_block = function.append_basic_block('afterloop') - - # Insert the conditional branch into the end of loop_end_block. - g_llvm_builder.cbranch(end_condition_bool, loop_block, after_block) - - # Any new code will be inserted in after_block. - g_llvm_builder.position_at_end(after_block) - - # Add a new entry to the PHI node for the backedge. - variable_phi.add_incoming(next_value, loop_end_block) - - # Restore the unshadowed variable. - if old_value: - g_named_values[self.loop_variable] = old_value - else: - del g_named_values[self.loop_variable] - - # for expr always returns 0.0. - return Constant.real(Type.double(), 0) - -# This class represents the "prototype" for a function, which captures its name, -# and its argument names (thus implicitly the number of arguments the function -# takes). -class PrototypeNode(object): - - def __init__(self, name, args): - self.name = name - self.args = args - - def CodeGen(self): - # Make the function type, eg. double(double,double). - funct_type = Type.function( - Type.double(), [Type.double()] * len(self.args), False) - - function = Function.new(g_llvm_module, funct_type, self.name) - - # If the name conflicted, there was already something with the same name. - # If it has a body, don't allow redefinition or reextern. - if function.name != self.name: - function.delete() - function = g_llvm_module.get_function_named(self.name) - - # If the function already has a body, reject this. - if not function.is_declaration: - raise RuntimeError('Redefinition of function.') - - # If the function took a different number of args, reject. - if len(function.args) != len(self.args): - raise RuntimeError('Redeclaration of a function with different number ' - 'of args.') - - # Set names for all arguments and add them to the variables symbol table. - for arg, arg_name in zip(function.args, self.args): - arg.name = arg_name - # Add arguments to variable symbol table. - g_named_values[arg_name] = arg - - return function - -# This class represents a function definition itself. -class FunctionNode(object): - - def __init__(self, prototype, body): - self.prototype = prototype - self.body = body - - def CodeGen(self): - # Clear scope. - g_named_values.clear() - - # Create a function object. - function = self.prototype.CodeGen() - - # Create a new basic block to start insertion into. - block = function.append_basic_block('entry') - global g_llvm_builder - g_llvm_builder = Builder.new(block) - - # Finish off the function. - try: - return_value = self.body.CodeGen() - g_llvm_builder.ret(return_value) - - # Validate the generated code, checking for consistency. - function.verify() - - # Optimize the function. - g_llvm_pass_manager.run(function) - except: - function.delete() - raise - - return function - - -################################################################################ -## Parser -################################################################################ - -class Parser(object): - - def __init__(self, tokens, binop_precedence): - self.tokens = tokens - self.binop_precedence = binop_precedence - self.Next() - - # Provide a simple token buffer. Parser.current is the current token the - # parser is looking at. Parser.Next() reads another token from the lexer and - # updates Parser.current with its results. - def Next(self): - self.current = self.tokens.next() - - # Gets the precedence of the current token, or -1 if the token is not a binary - # operator. - def GetCurrentTokenPrecedence(self): - if isinstance(self.current, CharacterToken): - return self.binop_precedence.get(self.current.char, -1) - else: - return -1 - - # identifierexpr ::= identifier | identifier '(' expression* ')' - def ParseIdentifierExpr(self): - identifier_name = self.current.name - self.Next() # eat identifier. - - if self.current != CharacterToken('('): # Simple variable reference. - return VariableExpressionNode(identifier_name) - - # Call. - self.Next() # eat '('. - args = [] - if self.current != CharacterToken(')'): - while True: - args.append(self.ParseExpression()) - if self.current == CharacterToken(')'): - break - elif self.current != CharacterToken(','): - raise RuntimeError('Expected ")" or "," in argument list.') - self.Next() - - self.Next() # eat ')'. - return CallExpressionNode(identifier_name, args) - - # numberexpr ::= number - def ParseNumberExpr(self): - result = NumberExpressionNode(self.current.value) - self.Next() # consume the number. - return result - - # parenexpr ::= '(' expression ')' - def ParseParenExpr(self): - self.Next() # eat '('. - - contents = self.ParseExpression() - - if self.current != CharacterToken(')'): - raise RuntimeError('Expected ")".') - self.Next() # eat ')'. - - return contents - - # ifexpr ::= 'if' expression 'then' expression 'else' expression - def ParseIfExpr(self): - self.Next() # eat the if. - - # condition. - condition = self.ParseExpression() - - if not isinstance(self.current, ThenToken): - raise RuntimeError('Expected "then".') - self.Next() # eat the then. - - then_branch = self.ParseExpression() - - if not isinstance(self.current, ElseToken): - raise RuntimeError('Expected "else".') - self.Next() # eat the else. - - else_branch = self.ParseExpression() - - return IfExpressionNode(condition, then_branch, else_branch) - - # forexpr ::= 'for' identifier '=' expr ',' expr (',' expr)? 'in' expression - def ParseForExpr(self): - self.Next() # eat the for. - - if not isinstance(self.current, IdentifierToken): - raise RuntimeError('Expected identifier after for.') - - loop_variable = self.current.name - self.Next() # eat the identifier. - - if self.current != CharacterToken('='): - raise RuntimeError('Expected "=" after for variable.') - self.Next() # eat the '='. - - start = self.ParseExpression() - - if self.current != CharacterToken(','): - raise RuntimeError('Expected "," after for start value.') - self.Next() # eat the ','. - - end = self.ParseExpression() - - # The step value is optional. - if self.current == CharacterToken(','): - self.Next() # eat the ','. - step = self.ParseExpression() - else: - step = None - - if not isinstance(self.current, InToken): - raise RuntimeError('Expected "in" after for variable specification.') - self.Next() # eat 'in'. - - body = self.ParseExpression() - - return ForExpressionNode(loop_variable, start, end, step, body) - - # primary ::= identifierexpr | numberexpr | parenexpr | ifexpr | forexpr - def ParsePrimary(self): - if isinstance(self.current, IdentifierToken): - return self.ParseIdentifierExpr() - elif isinstance(self.current, NumberToken): - return self.ParseNumberExpr() - elif isinstance(self.current, IfToken): - return self.ParseIfExpr() - elif isinstance(self.current, ForToken): - return self.ParseForExpr() - elif self.current == CharacterToken('('): - return self.ParseParenExpr() - else: - raise RuntimeError('Unknown token when expecting an expression.') - - # binoprhs ::= (operator primary)* - def ParseBinOpRHS(self, left, left_precedence): - # If this is a binary operator, find its precedence. - while True: - precedence = self.GetCurrentTokenPrecedence() - - # If this is a binary operator that binds at least as tightly as the - # current one, consume it; otherwise we are done. - if precedence < left_precedence: - return left - - binary_operator = self.current.char - self.Next() # eat the operator. - - # Parse the primary expression after the binary operator. - right = self.ParsePrimary() - - # If binary_operator binds less tightly with right than the operator after - # right, let the pending operator take right as its left. - next_precedence = self.GetCurrentTokenPrecedence() - if precedence < next_precedence: - right = self.ParseBinOpRHS(right, precedence + 1) - - # Merge left/right. - left = BinaryOperatorExpressionNode(binary_operator, left, right) - - # expression ::= primary binoprhs - def ParseExpression(self): - left = self.ParsePrimary() - return self.ParseBinOpRHS(left, 0) - - # prototype ::= id '(' id* ')' - def ParsePrototype(self): - if not isinstance(self.current, IdentifierToken): - raise RuntimeError('Expected function name in prototype.') - - function_name = self.current.name - self.Next() # eat function name. - - if self.current != CharacterToken('('): - raise RuntimeError('Expected "(" in prototype.') - self.Next() # eat '('. - - arg_names = [] - while isinstance(self.current, IdentifierToken): - arg_names.append(self.current.name) - self.Next() - - if self.current != CharacterToken(')'): - raise RuntimeError('Expected ")" in prototype.') - - # Success. - self.Next() # eat ')'. - - return PrototypeNode(function_name, arg_names) - - # definition ::= 'def' prototype expression - def ParseDefinition(self): - self.Next() # eat def. - proto = self.ParsePrototype() - body = self.ParseExpression() - return FunctionNode(proto, body) - - # toplevelexpr ::= expression - def ParseTopLevelExpr(self): - proto = PrototypeNode('', []) - return FunctionNode(proto, self.ParseExpression()) - - # external ::= 'extern' prototype - def ParseExtern(self): - self.Next() # eat extern. - return self.ParsePrototype() - - # Top-Level parsing - def HandleDefinition(self): - self.Handle(self.ParseDefinition, 'Read a function definition:') - - def HandleExtern(self): - self.Handle(self.ParseExtern, 'Read an extern:') - - def HandleTopLevelExpression(self): - try: - function = self.ParseTopLevelExpr().CodeGen() - result = g_llvm_executor.run_function(function, []) - print 'Evaluated to:', result.as_real(Type.double()) - except Exception, e: - print 'Error:', e - try: - self.Next() # Skip for error recovery. - except: - pass - - def Handle(self, function, message): - try: - print message, function().CodeGen() - except Exception, e: - print 'Error:', e - try: - self.Next() # Skip for error recovery. - except: - pass - -################################################################################ -## Main driver code. -################################################################################ - -def main(): - # Set up the optimizer pipeline. Start with registering info about how the - # target lays out data structures. - g_llvm_pass_manager.add(g_llvm_executor.target_data) - # Do simple "peephole" optimizations and bit-twiddling optzns. - g_llvm_pass_manager.add(PASS_INSTRUCTION_COMBINING) - # Reassociate expressions. - g_llvm_pass_manager.add(PASS_REASSOCIATE) - # Eliminate Common SubExpressions. - g_llvm_pass_manager.add(PASS_GVN) - # Simplify the control flow graph (deleting unreachable blocks, etc). - g_llvm_pass_manager.add(PASS_CFG_SIMPLIFICATION) - - g_llvm_pass_manager.initialize() - - # Install standard binary operators. - # 1 is lowest possible precedence. 40 is the highest. - operator_precedence = { - '<': 10, - '+': 20, - '-': 20, - '*': 40 - } - - # Run the main "interpreter loop". - while True: - print 'ready>', - try: - raw = raw_input() - except KeyboardInterrupt: - break - - parser = Parser(Tokenize(raw), operator_precedence) - while True: - # top ::= definition | external | expression | EOF - if isinstance(parser.current, EOFToken): - break - if isinstance(parser.current, DefToken): - parser.HandleDefinition() - elif isinstance(parser.current, ExternToken): - parser.HandleExtern() - else: - parser.HandleTopLevelExpression() - - # Print out all of the generated code. - print '\n', g_llvm_module - -if __name__ == '__main__': - main() -{% endhighlight %} - -* * * - -**[Next: Extending the language: user-defined operators](PythonLangImpl6.html)** - diff --git a/docs/source/doc/kaleidoscope/PythonLangImpl5.rst b/docs/source/doc/kaleidoscope/PythonLangImpl5.rst new file mode 100644 index 0000000..326a5bf --- /dev/null +++ b/docs/source/doc/kaleidoscope/PythonLangImpl5.rst @@ -0,0 +1,1339 @@ ++------------------------------------+ +| layout: page | ++------------------------------------+ +| title: "Kaleidoscope: Chapter 5" | ++------------------------------------+ + +Extending the Language: Control Flow +==================================== + +Written by `Chris Lattner `_ and `Max +Shawabkeh `_ + +**Chapter 5** + +- This will become a table of contents (this text will be scraped). + {:toc} + +**`Chapter 6: Extending the Language: User-defined +Operators `_** + +Introduction # {#intro} +======================= + +Welcome to Chapter 5 of the `Implementing a language with +LLVM `_ tutorial. Parts +1-4 described the implementation of the simple Kaleidoscope language and +included support for generating LLVM IR, followed by optimizations and a +JIT compiler. Unfortunately, as presented, Kaleidoscope is mostly +useless: it has no control flow other than call and return. This means +that you can't have conditional branches in the code, significantly +limiting its power. In this episode of "build that compiler", we'll +extend Kaleidoscope to have an if/then/else expression plus a simple +'for' loop. + +-------------- + +If/Then/Else # {#ifthen} +======================== + +Extending Kaleidoscope to support if/then/else is quite straightforward. +It basically requires adding lexer support for this "new" concept to the +lexer, parser, AST, and LLVM code emitter. This example is nice, because +it shows how easy it is to "grow" a language over time, incrementally +extending it as new ideas are discovered. + +Before we get going on "how" we add this extension, lets talk about +"what" we want. The basic idea is that we want to be able to write this +sort of thing: + +{% highlight python %} def fib(x) if x < 3 then 1 else fib(x-1) + +fib(x-2) {% endhighlight %} + +In Kaleidoscope, every construct is an expression: there are no +statements. As such, the if/then/else expression needs to return a value +like any other. Since we're using a mostly functional form, we'll have +it evaluate its conditional, then return the 'then' or 'else' value +based on how the condition was resolved. This is very similar to the C +"?:" expression. + +The semantics of the if/then/else expression is that it evaluates the +condition to a boolean equality value: 0.0 is considered to be false and +everything else is considered to be true. If the condition is true, the +first subexpression is evaluated and returned, if the condition is +false, the second subexpression is evaluated and returned. Since +Kaleidoscope allows side-effects, this behavior is important to nail +down. + +Now that we know what we "want", let's break this down into its +constituent pieces. + +Lexer Extensions for If/Then/Else ## {#iflexer} +----------------------------------------------- + +The lexer extensions are straightforward. First we add new token classes +for the relevant tokens: + +{% highlight python %} class IfToken(object): pass class +ThenToken(object): pass class ElseToken(object): pass {% endhighlight %} + +Once we have that, we recognize the new keywords in the lexer. This is +pretty simple stuff: + +{% highlight python %} ... if identifier == 'def': yield DefToken() elif +identifier == 'extern': yield ExternToken() elif identifier == 'if': +yield IfToken() elif identifier == 'then': yield ThenToken() elif +identifier == 'else': yield ElseToken() else: yield +IdentifierToken(identifier) {% endhighlight %} + +AST Extensions for If/Then/Else ## {#ifast} +------------------------------------------- + +To represent the new expression we add a new AST node for it: + +{% highlight python %} # Expression class for if/then/else. class +IfExpressionNode(ExpressionNode): + +def **init**\ (self, condition, then\_branch, else\_branch): +self.condition = condition self.then\_branch = then\_branch +self.else\_branch = else\_branch + +def CodeGen(self): ... {% endhighlight %} + +The AST node just has pointers to the various subexpressions. + +Parser Extensions for If/Then/Else ## {#ifparser} +------------------------------------------------- + +Now that we have the relevant tokens coming from the lexer and we have +the AST node to build, our parsing logic is relatively straightforward. +First we define a new parsing function: + +{% highlight python %} # ifexpr ::= 'if' expression 'then' expression +'else' expression def ParseIfExpr(self): self.Next() # eat the if. + +:: + + # condition. + condition = self.ParseExpression() + + if not isinstance(self.current, ThenToken): + raise RuntimeError('Expected "then".') + self.Next() # eat the then. + + then_branch = self.ParseExpression() + + if not isinstance(self.current, ElseToken): + raise RuntimeError('Expected "else".') + self.Next() # eat the else. + + else_branch = self.ParseExpression() + + return IfExpressionNode(condition, then_branch, else_branch) + +{% endhighlight %} + +Next we hook it up as a primary expression: + +{% highlight python %} def ParsePrimary(self): if +isinstance(self.current, IdentifierToken): return +self.ParseIdentifierExpr() elif isinstance(self.current, NumberToken): +return self.ParseNumberExpr(); elif isinstance(self.current, IfToken): +return self.ParseIfExpr() elif self.current == CharacterToken('('): +return self.ParseParenExpr() else: raise RuntimeError('Unknown token +when expecting an expression.') {% endhighlight %} + +LLVM IR for If/Then/Else ## {#ifir} +----------------------------------- + +Now that we have it parsing and building the AST, the final piece is +adding LLVM code generation support. This is the most interesting part +of the if/then/else example, because this is where it starts to +introduce new concepts. All of the code above has been thoroughly +described in previous chapters. + +To motivate the code we want to produce, lets take a look at a simple +example. Consider: + +{% highlight python %} extern foo(); extern bar(); def baz(x) if x then +foo() else bar(); {% endhighlight %} + +If you disable optimizations, the code you'll (soon) get from +Kaleidoscope looks something like this: + +{% highlight llvm %} declare double @foo() declare double @bar() define +double @baz(double %x) { entry: %ifcond = fcmp one double %x, +0.000000e+00 br i1 %ifcond, label %then, label %else then: ; preds = +%entry %calltmp1 = call double @bar() else: ; preds = %entry %calltmp1 = +call double @bar() br label %ifcont ifcont: ; preds = %else, %then +%iftmp = phi double [ %calltmp, %then ], [ %calltmp1, %else ] ret double +%iftmp } {% endhighlight %} + +To visualize the control flow graph, you can use a nifty feature of the +LLVM `opt `_ tool. If you put this LLVM +IR into "t.ll" and run ``llvm-as < t.ll | opt -analyze -view-cfg``, a +`window will pop +up `_ and +you'll see this graph: + +Another way to get this is to call "``function.viewCFG()``\ " or +"``function.viewCFGOnly()``\ " (where F is a "``llvm.core.Function``\ ") +either by inserting actual calls into the code and recompiling or by +calling these in the debugger. LLVM has many nice features for +visualizing various graphs, but note that these are available only if +your LLVM was built with Graphviz support (accomplished by having +Graphviz and Ghostview installed when building LLVM). + +Getting back to the generated code, it is fairly simple: the entry block +evaluates the conditional expression ("x" in our case here) and compares +the result to 0.0 with the +`fcmp `_ one instruction +('one' is "Ordered and Not Equal"). Based on the result of this +expression, the code jumps to either the "then" or "else" blocks, which +contain the expressions for the true/false cases. + +Once the then/else blocks are finished executing, they both branch back +to the 'ifcont' block to execute the code that happens after the +if/then/else. In this case the only thing left to do is to return to the +caller of the function. The question then becomes: how does the code +know which expression to return? + +The answer to this question involves an important SSA operation: the +`Phi +operation `_. +If you're not familiar with SSA, `the wikipedia +article `_ +is a good introduction and there are various other introductions to it +available on your favorite search engine. The short version is that +"execution" of the Phi operation requires "remembering" which block +control came from. The Phi operation takes on the value corresponding to +the input control block. In this case, if control comes in from the +"then" block, it gets the value of "calltmp". If control comes from the +"else" block, it gets the value of "calltmp1". + +At this point, you are probably starting to think "Oh no! This means my +simple and elegant front-end will have to start generating SSA form in +order to use LLVM!". Fortunately, this is not the case, and we strongly +advise *not* implementing an SSA construction algorithm in your +front-end unless there is an amazingly good reason to do so. In +practice, there are two sorts of values that float around in code +written for your average imperative programming language that might need +Phi nodes: + +1. Code that involves user variables: ``x = 1; x = x + 1;`` +2. Values that are implicit in the structure of your AST, such as the + Phi node in this case. + +In `Chapter 7 `_ of this tutorial ("mutable +variables"), we'll talk about #1 in depth. For now, just believe me that +you don't need SSA construction to handle this case. For #2, you have +the choice of using the techniques that we will describe for #1, or you +can insert Phi nodes directly, if convenient. In this case, it is really +really easy to generate the Phi node, so we choose to do it directly. + +Okay, enough of the motivation and overview, lets generate code! + +Code Generation for If/Then/Else ## {#ifcodegen} +------------------------------------------------ + +In order to generate code for this, we implement the ``Codegen`` method +for ``IfExpressionNode``: + +{% highlight python %} def CodeGen(self): condition = +self.condition.CodeGen() + +:: + + # Convert condition to a bool by comparing equal to 0.0. + condition_bool = g_llvm_builder.fcmp( + FCMP_ONE, condition, Constant.real(Type.double(), 0), 'ifcond') + +{% endhighlight %} + +This code is straightforward and similar to what we saw before. We emit +the expression for the condition, then compare that value to zero to get +a truth value as a 1-bit (bool) value. + +{% highlight python %} function = g\_llvm\_builder.basic\_block.function + +:: + + # Create blocks for the then and else cases. Insert the 'then' block at the + # end of the function. + then_block = function.append_basic_block('then') + else_block = function.append_basic_block('else') + merge_block = function.append_basic_block('ifcond') + + g_llvm_builder.cbranch(condition_bool, then_block, else_block) + +{% endhighlight %} + +This code creates the basic blocks that are related to the if/then/else +statement, and correspond directly to the blocks in the example above. +The first line gets the current Function object that is being built. It +gets this by asking the builder for the current BasicBlock, and asking +that block for its "parent" (the function it is currently embedded +into). + +Once it has that, it creates three block which are automatically +inserted into the end of the function. Once the blocks are created, we +can emit the conditional branch that chooses between them. Note that +creating new blocks does not implicitly affect the Builder, so it is +still inserting into the block that the condition went into. + +{% highlight python %} # Emit then value. +g\_llvm\_builder.position\_at\_end(then\_block) then\_value = +self.then\_branch.CodeGen() g\_llvm\_builder.branch(merge\_block) + +:: + + # Codegen of 'Then' can change the current block; update then_block for the + # PHI node. + then_block = g_llvm_builder.basic_block + +{% endhighlight %} + +After the conditional branch is inserted, we move the builder to start +inserting into the "then" block. Strictly speaking, this call moves the +insertion point to be at the end of the specified block. However, since +the "then" block is empty, it also starts out by inserting at the +beginning of the block. :) + +Once the insertion point is set, we recursively codegen the "then" +expression from the AST. To finish off the "then" block, we create an +unconditional branch to the merge block. One interesting (and very +important) aspect of the LLVM IR is that it `requires all basic blocks +to be +"terminated" `_ +with a `control flow +instruction `_ such +as return or branch. This means that all control flow, *including +fallthroughs* must be made explicit in the LLVM IR. If you violate this +rule, the verifier will emit an error. + +The final line here is quite subtle, but is very important. The basic +issue is that when we create the Phi node in the merge block, we need to +set up the block/value pairs that indicate how the Phi will work. +Importantly, the Phi node expects to have an entry for each predecessor +of the block in the CFG. Why then, are we getting the current block when +we just set it to then\_block 5 lines above? The problem is that the +"Then" expression may actually itself change the block that the Builder +is emitting into if, for example, it contains a nested "if/then/else" +expression. Because calling Codegen recursively could arbitrarily change +the notion of the current block, we are required to get an up-to-date +value for code that will set up the Phi node. + +{% highlight python %} # Emit else block. +g\_llvm\_builder.position\_at\_end(else\_block) else\_value = +self.else\_branch.CodeGen() g\_llvm\_builder.branch(merge\_block) + +:: + + # Codegen of 'Else' can change the current block, update else_block for the + # PHI node. + else_block = g_llvm_builder.basic_block + +{% endhighlight %} + +Code generation for the 'else' block is basically identical to codegen +for the 'then' block. The only significant difference is the first line, +which adds the 'else' block to the function. Recall previously that the +'else' block was created, but not added to the function. Now that the +'then' and 'else' blocks are emitted, we can finish up with the merge +code: + +{% highlight python %} # Emit merge block. +g\_llvm\_builder.position\_at\_end(merge\_block) phi = +g\_llvm\_builder.phi(Type.double(), 'iftmp') +phi.add\_incoming(then\_value, then\_block) +phi.add\_incoming(else\_value, else\_block) + +:: + + return phi + +{% endhighlight %} + +The first line changes the insertion point so that newly created code +will go into the "merge" block. Once that is done, we need to create the +PHI node and set up the block/value pairs for the PHI. + +Finally, the CodeGen function returns the phi node as the value computed +by the if/then/else expression. In our example above, this returned +value will feed into the code for the top-level function, which will +create the return instruction. + +Overall, we now have the ability to execute conditional code in +Kaleidoscope. With this extension, Kaleidoscope is a fairly complete +language that can calculate a wide variety of numeric functions. Next up +we'll add another useful expression that is familiar from non-functional +languages... + +-------------- + +'for' Loop Expression # {#for} +============================== + +Now that we know how to add basic control flow constructs to the +language, we have the tools to add more powerful things. Lets add +something more aggressive, a 'for' expression: + +{% highlight python %} extern putchard(char) def printstar(n) for i = 1, +i < n, 1.0 in putchard(42) # ascii 42 = '\*' + +:: + + # print 100 '*' characters + printstar(100) + +{% endhighlight %} + +This expression defines a new variable (``i`` in this case) which +iterates from a starting value, while the condition (``i < n`` in this +case) is true, incrementing by an optional step value ("1.0" in this +case). If the step value is omitted, it defaults to 1.0. While the loop +is true, it executes its body expression. Because we don't have anything +better to return, we'll just define the loop as always returning 0.0. In +the future when we have mutable variables, it will get more useful. + +As before, lets talk about the changes that we need to Kaleidoscope to +support this. + +Lexer Extensions for the 'for' Loop ## {#forlexer} +-------------------------------------------------- + +The lexer extensions are the same sort of thing as for if/then/else: + +{% highlight python %} ... + +class ThenToken(object): pass class ElseToken(object): pass class +ForToken(object): pass class InToken(object): pass + +... + +def Tokenize(string): + +:: + + ... + + elif identifier == 'else': + yield ElseToken() + elif identifier == 'for': + yield ForToken() + elif identifier == 'in': + yield InToken() + else: + yield IdentifierToken(identifier) + +{% endhighlight %} + +AST Extensions for the 'for' Loop ## {#forast} +---------------------------------------------- + +The AST node is just as simple. It basically boils down to capturing the +variable name and the constituent expressions in the node. + +{% highlight python %} # Expression class for for/in. class +ForExpressionNode(ExpressionNode): + +def **init**\ (self, loop\_variable, start, end, step, body): +self.loop\_variable = loop\_variable self.start = start self.end = end +self.step = step self.body = body + +def CodeGen(self): ... {% endhighlight %} + +Parser Extensions for the 'for' Loop ## {#forparser} +---------------------------------------------------- + +The parser code is also fairly standard. The only interesting thing here +is handling of the optional step value. The parser code handles it by +checking to see if the second comma is present. If not, it sets the step +value to null in the AST node: + +{% highlight python %} # forexpr ::= 'for' identifier '=' expr ',' expr +(',' expr)? 'in' expression def ParseForExpr(self): self.Next() # eat +the for. + +:: + + if not isinstance(self.current, IdentifierToken): + raise RuntimeError('Expected identifier after for.') + + loop_variable = self.current.name + self.Next() # eat the identifier. + + if self.current != CharacterToken('='): + raise RuntimeError('Expected "=" after for variable.') + self.Next() # eat the '='. + + start = self.ParseExpression() + + if self.current != CharacterToken(','): + raise RuntimeError('Expected "," after for start value.') + self.Next() # eat the ','. + + end = self.ParseExpression() + + # The step value is optional. + if self.current == CharacterToken(','): + self.Next() # eat the ','. + step = self.ParseExpression() + else: + step = None + + if not isinstance(self.current, InToken): + raise RuntimeError('Expected "in" after for variable specification.') + self.Next() # eat 'in'. + + body = self.ParseExpression() + + return ForExpressionNode(loop_variable, start, end, step, body) + +{% endhighlight %} + +LLVM IR for the 'for' Loop ## {#forir} +-------------------------------------- + +Now we get to the good part: the LLVM IR we want to generate for this +thing. With the simple example above, we get this LLVM IR (note that +this dump is generated with optimizations disabled for clarity): + +{% highlight llvm %} declare double @putchard(double) define double +@printstar(double %n) { entry: ; initial value = 1.0 (inlined into phi) +br label %loop loop: ; preds = %loop, %entry %i = phi double [ +1.000000e+00, %entry ], [ %nextvar, %loop ] ; body %calltmp = call +double @putchard(double 4.200000e+01) ; increment %nextvar = fadd double +%i, 1.000000e+00 ; termination test %cmptmp = fcmp ult double %i, %n +%booltmp = uitofp i1 %cmptmp to double %loopcond = fcmp one double +%booltmp, 0.000000e+00 br i1 %loopcond, label %loop, label %afterloop +afterloop: ; preds = %loop ; loop always returns 0.0 ret double +0.000000e+00 } {% endhighlight %} + +This loop contains all the same constructs we saw before: a phi node, +several expressions, and some basic blocks. Lets see how this fits +together. + +Code Generation for the 'for' Loop ## {#forcodegen} +--------------------------------------------------- + +The first part of Codegen is very simple: we just output the start +expression for the loop value: + +{% highlight python %} def CodeGen(self): # Emit the start code first, +without 'variable' in scope. start\_value = self.start.CodeGen() {% +endhighlight %} + +With this out of the way, the next step is to set up the LLVM basic +block for the start of the loop body. In the case above, the whole loop +body is one block, but remember that the body code itself could consist +of multiple blocks (e.g. if it contains an if/then/else or a for/in +expression). + +{% highlight python %} # Make the new basic block for the loop header, +inserting after current # block. function = +g\_llvm\_builder.basic\_block.function pre\_header\_block = +g\_llvm\_builder.basic\_block loop\_block = +function.append\_basic\_block('loop') + +:: + + # Insert an explicit fallthrough from the current block to the loop_block. + g_llvm_builder.branch(loop_block) + +{% endhighlight %} + +This code is similar to what we saw for if/then/else. Because we will +need it to create the Phi node, we remember the block that falls through +into the loop. Once we have that, we create the actual block that starts +the loop and create an unconditional branch for the fall-through between +the two blocks. + +{% highlight python %} # Start insertion in loop\_block. +g\_llvm\_builder.position\_at\_end(loop\_block); + +:: + + # Start the PHI node with an entry for start. + variable_phi = g_llvm_builder.phi(Type.double(), self.loop_variable) + variable_phi.add_incoming(start_value, pre_header_block) + +{% endhighlight %} + +Now that the "pre\_header\_block" for the loop is set up, we switch to +emitting code for the loop body. To begin with, we move the insertion +point and create the PHI node for the loop induction variable. Since we +already know the incoming value for the starting value, we add it to the +Phi node. Note that the Phi will eventually get a second value for the +backedge, but we can't set it up yet (because it doesn't exist!). + +{% highlight python %} # Within the loop, the variable is defined equal +to the PHI node. If it # shadows an existing variable, we have to +restore it, so save it now. old\_value = +g\_named\_values.get(self.loop\_variable, None) +g\_named\_values[self.loop\_variable] = variable\_phi + +:: + + # Emit the body of the loop. This, like any other expr, can change the + # current BB. Note that we ignore the value computed by the body. + self.body.CodeGen() + +{% endhighlight %} + +Now the code starts to get more interesting. Our 'for' loop introduces a +new variable to the symbol table. This means that our symbol table can +now contain either function arguments or loop variables. To handle this, +before we codegen the body of the loop, we add the loop variable as the +current value for its name. Note that it is possible that there is a +variable of the same name in the outer scope. It would be easy to make +this an error (emit an error and return null if there is already an +entry for VarName) but we choose to allow shadowing of variables. In +order to handle this correctly, we remember the Value that we are +potentially shadowing in ``old_value`` (which will be None if there is +no shadowed variable). + +Once the loop variable is set into the symbol table, the code +recursively codegen's the body. This allows the body to use the loop +variable: any references to it will naturally find it in the symbol +table. + +{% highlight python %} # Emit the step value. if self.step: step\_value += self.step.CodeGen() else: # If not specified, use 1.0. step\_value = +Constant.real(Type.double(), 1) + +:: + + next_value = g_llvm_builder.fadd(variable_phi, step_value, 'next') + +{% endhighlight %} + +Now that the body is emitted, we compute the next value of the iteration +variable by adding the step value, or 1.0 if it isn't present. +``next_value`` will be the value of the loop variable on the next +iteration of the loop. + +{% highlight python %} # Compute the end condition and convert it to a +bool by comparing to 0.0. end\_condition = self.end.CodeGen() +end\_condition\_bool = g\_llvm\_builder.fcmp( FCMP\_ONE, end\_condition, +Constant.real(Type.double(), 0), 'loopcond') {% endhighlight %} + +Finally, we evaluate the exit value of the loop, to determine whether +the loop should exit. This mirrors the condition evaluation for the +if/then/else statement. + +{% highlight python %} # Create the "after loop" block and insert it. +loop\_end\_block = g\_llvm\_builder.basic\_block after\_block = +function.append\_basic\_block('afterloop') + +:: + + # Insert the conditional branch into the end of loop_end_block. + g_llvm_builder.cbranch(end_condition_bool, loop_block, after_block) + + # Any new code will be inserted in after_block. + g_llvm_builder.position_at_end(after_block) + +{% endhighlight %} + +With the code for the body of the loop complete, we just need to finish +up the control flow for it. This code remembers the end block (for the +phi node), then creates the block for the loop exit ("afterloop"). Based +on the value of the exit condition, it creates a conditional branch that +chooses between executing the loop again and exiting the loop. Any +future code is emitted in the "afterloop" block, so it sets the +insertion position to it. + +{% highlight python %} # Add a new entry to the PHI node for the +backedge. variable\_phi.add\_incoming(next\_value, loop\_end\_block) + +:: + + # Restore the unshadowed variable. + if old_value: + g_named_values[self.loop_variable] = old_value + else: + del g_named_values[self.loop_variable] + + # for expr always returns 0.0. + return Constant.real(Type.double(), 0) + +{% endhighlight %} + +The final code handles various cleanups: now that we have the +"next\_value", we can add the incoming value to the loop PHI node. After +that, we remove the loop variable from the symbol table, so that it +isn't in scope after the for loop. Finally, code generation of the for +loop always returns 0.0, so that is what we return from +``ForExpressionNode::CodeGen``. + +With this, we conclude the "adding control flow to Kaleidoscope" chapter +of the tutorial. In this chapter we added two control flow constructs, +and used them to motivate a couple of aspects of the LLVM IR that are +important for front-end implementors to know. In the next chapter of our +saga, we will get a bit crazier and add `user-defined +operators `_ to our poor innocent language. + +-------------- + +Full Code Listing # {#code} +=========================== + +Here is the complete code listing for our running example, enhanced with +the if/then/else and for expressions: + +{% highlight python %} #!/usr/bin/env python + +import re from llvm.core import Module, Constant, Type, Function, +Builder from llvm.ee import ExecutionEngine, TargetData from llvm.passes +import FunctionPassManager + +from llvm.core import FCMP\_ULT, FCMP\_ONE from llvm.passes import +(PASS\_INSTRUCTION\_COMBINING, PASS\_REASSOCIATE, PASS\_GVN, +PASS\_CFG\_SIMPLIFICATION) + +Globals +------- + +The LLVM module, which holds all the IR code. +============================================= + +g\_llvm\_module = Module.new('my cool jit') + +The LLVM instruction builder. Created whenever a new function is entered. +========================================================================= + +g\_llvm\_builder = None + +A dictionary that keeps track of which values are defined in the current scope +============================================================================== + +and what their LLVM representation is. +====================================== + +g\_named\_values = {} + +The function optimization passes manager. +========================================= + +g\_llvm\_pass\_manager = FunctionPassManager.new(g\_llvm\_module) + +The LLVM execution engine. +========================== + +g\_llvm\_executor = ExecutionEngine.new(g\_llvm\_module) + +Lexer +----- + +The lexer yields one of these types for each token. +=================================================== + +class EOFToken(object): pass class DefToken(object): pass class +ExternToken(object): pass class IfToken(object): pass class +ThenToken(object): pass class ElseToken(object): pass class +ForToken(object): pass class InToken(object): pass + +class IdentifierToken(object): def **init**\ (self, name): self.name = +name + +class NumberToken(object): def **init**\ (self, value): self.value = +value + +class CharacterToken(object): def **init**\ (self, char): self.char = +char def **eq**\ (self, other): return isinstance(other, CharacterToken) +and self.char == other.char def **ne**\ (self, other): return not self +== other + +Regular expressions that tokens and comments of our language. +============================================================= + +REGEX\_NUMBER = re.compile('[0-9]+(?:.[0-9]+)?') REGEX\_IDENTIFIER = +re.compile('[a-zA-Z][a-zA-Z0-9]\ *') REGEX\_COMMENT = re.compile('#.*') + +def Tokenize(string): while string: # Skip whitespace. if +string[0].isspace(): string = string[1:] continue + +:: + + # Run regexes. + comment_match = REGEX_COMMENT.match(string) + number_match = REGEX_NUMBER.match(string) + identifier_match = REGEX_IDENTIFIER.match(string) + + # Check if any of the regexes matched and yield the appropriate result. + if comment_match: + comment = comment_match.group(0) + string = string[len(comment):] + elif number_match: + number = number_match.group(0) + yield NumberToken(float(number)) + string = string[len(number):] + elif identifier_match: + identifier = identifier_match.group(0) + # Check if we matched a keyword. + if identifier == 'def': + yield DefToken() + elif identifier == 'extern': + yield ExternToken() + elif identifier == 'if': + yield IfToken() + elif identifier == 'then': + yield ThenToken() + elif identifier == 'else': + yield ElseToken() + elif identifier == 'for': + yield ForToken() + elif identifier == 'in': + yield InToken() + else: + yield IdentifierToken(identifier) + string = string[len(identifier):] + else: + # Yield the ASCII value of the unknown character. + yield CharacterToken(string[0]) + string = string[1:] + +yield EOFToken() + +Abstract Syntax Tree (aka Parse Tree) +------------------------------------- + +Base class for all expression nodes. +==================================== + +class ExpressionNode(object): pass + +Expression class for numeric literals like "1.0". +================================================= + +class NumberExpressionNode(ExpressionNode): + +def **init**\ (self, value): self.value = value + +def CodeGen(self): return Constant.real(Type.double(), self.value) + +Expression class for referencing a variable, like "a". +====================================================== + +class VariableExpressionNode(ExpressionNode): + +def **init**\ (self, name): self.name = name + +def CodeGen(self): if self.name in g\_named\_values: return +g\_named\_values[self.name] else: raise RuntimeError('Unknown variable +name: ' + self.name) + +Expression class for a binary operator. +======================================= + +class BinaryOperatorExpressionNode(ExpressionNode): + +def **init**\ (self, operator, left, right): self.operator = operator +self.left = left self.right = right + +def CodeGen(self): left = self.left.CodeGen() right = +self.right.CodeGen() + +:: + + if self.operator == '+': + return g_llvm_builder.fadd(left, right, 'addtmp') + elif self.operator == '-': + return g_llvm_builder.fsub(left, right, 'subtmp') + elif self.operator == '*': + return g_llvm_builder.fmul(left, right, 'multmp') + elif self.operator == '<': + result = g_llvm_builder.fcmp(FCMP_ULT, left, right, 'cmptmp') + # Convert bool 0 or 1 to double 0.0 or 1.0. + return g_llvm_builder.uitofp(result, Type.double(), 'booltmp') + else: + raise RuntimeError('Unknown binary operator.') + +Expression class for function calls. +==================================== + +class CallExpressionNode(ExpressionNode): + +def **init**\ (self, callee, args): self.callee = callee self.args = +args + +def CodeGen(self): # Look up the name in the global module table. callee += g\_llvm\_module.get\_function\_named(self.callee) + +:: + + # Check for argument mismatch error. + if len(callee.args) != len(self.args): + raise RuntimeError('Incorrect number of arguments passed.') + + arg_values = [i.CodeGen() for i in self.args] + + return g_llvm_builder.call(callee, arg_values, 'calltmp') + +Expression class for if/then/else. +================================== + +class IfExpressionNode(ExpressionNode): + +def **init**\ (self, condition, then\_branch, else\_branch): +self.condition = condition self.then\_branch = then\_branch +self.else\_branch = else\_branch + +def CodeGen(self): condition = self.condition.CodeGen() + +:: + + # Convert condition to a bool by comparing equal to 0.0. + condition_bool = g_llvm_builder.fcmp( + FCMP_ONE, condition, Constant.real(Type.double(), 0), 'ifcond') + + function = g_llvm_builder.basic_block.function + + # Create blocks for the then and else cases. Insert the 'then' block at the + # end of the function. + then_block = function.append_basic_block('then') + else_block = function.append_basic_block('else') + merge_block = function.append_basic_block('ifcond') + + g_llvm_builder.cbranch(condition_bool, then_block, else_block) + + # Emit then value. + g_llvm_builder.position_at_end(then_block) + then_value = self.then_branch.CodeGen() + g_llvm_builder.branch(merge_block) + + # Codegen of 'Then' can change the current block; update then_block for the + # PHI node. + then_block = g_llvm_builder.basic_block + + # Emit else block. + g_llvm_builder.position_at_end(else_block) + else_value = self.else_branch.CodeGen() + g_llvm_builder.branch(merge_block) + + # Codegen of 'Else' can change the current block, update else_block for the + # PHI node. + else_block = g_llvm_builder.basic_block + + # Emit merge block. + g_llvm_builder.position_at_end(merge_block) + phi = g_llvm_builder.phi(Type.double(), 'iftmp') + phi.add_incoming(then_value, then_block) + phi.add_incoming(else_value, else_block) + + return phi + +Expression class for for/in. +============================ + +class ForExpressionNode(ExpressionNode): + +def **init**\ (self, loop\_variable, start, end, step, body): +self.loop\_variable = loop\_variable self.start = start self.end = end +self.step = step self.body = body + +def CodeGen(self): # Output this as: # ... # start = startexpr # goto +loop # loop: # variable = phi [start, loopheader], [nextvariable, +loopend] # ... # bodyexpr # ... # loopend: # step = stepexpr # +nextvariable = variable + step # endcond = endexpr # br endcond, loop, +endloop # outloop: + +:: + + # Emit the start code first, without 'variable' in scope. + start_value = self.start.CodeGen() + + # Make the new basic block for the loop header, inserting after current + # block. + function = g_llvm_builder.basic_block.function + pre_header_block = g_llvm_builder.basic_block + loop_block = function.append_basic_block('loop') + + # Insert an explicit fallthrough from the current block to the loop_block. + g_llvm_builder.branch(loop_block) + + # Start insertion in loop_block. + g_llvm_builder.position_at_end(loop_block) + + # Start the PHI node with an entry for start. + variable_phi = g_llvm_builder.phi(Type.double(), self.loop_variable) + variable_phi.add_incoming(start_value, pre_header_block) + + # Within the loop, the variable is defined equal to the PHI node. If it + # shadows an existing variable, we have to restore it, so save it now. + old_value = g_named_values.get(self.loop_variable, None) + g_named_values[self.loop_variable] = variable_phi + + # Emit the body of the loop. This, like any other expr, can change the + # current BB. Note that we ignore the value computed by the body. + self.body.CodeGen() + + # Emit the step value. + if self.step: + step_value = self.step.CodeGen() + else: + # If not specified, use 1.0. + step_value = Constant.real(Type.double(), 1) + + next_value = g_llvm_builder.fadd(variable_phi, step_value, 'next') + + # Compute the end condition and convert it to a bool by comparing to 0.0. + end_condition = self.end.CodeGen() + end_condition_bool = g_llvm_builder.fcmp( + FCMP_ONE, end_condition, Constant.real(Type.double(), 0), 'loopcond') + + # Create the "after loop" block and insert it. + loop_end_block = g_llvm_builder.basic_block + after_block = function.append_basic_block('afterloop') + + # Insert the conditional branch into the end of loop_end_block. + g_llvm_builder.cbranch(end_condition_bool, loop_block, after_block) + + # Any new code will be inserted in after_block. + g_llvm_builder.position_at_end(after_block) + + # Add a new entry to the PHI node for the backedge. + variable_phi.add_incoming(next_value, loop_end_block) + + # Restore the unshadowed variable. + if old_value: + g_named_values[self.loop_variable] = old_value + else: + del g_named_values[self.loop_variable] + + # for expr always returns 0.0. + return Constant.real(Type.double(), 0) + +This class represents the "prototype" for a function, which captures its name, +============================================================================== + +and its argument names (thus implicitly the number of arguments the function +============================================================================ + +takes). +======= + +class PrototypeNode(object): + +def **init**\ (self, name, args): self.name = name self.args = args + +def CodeGen(self): # Make the function type, eg. double(double,double). +funct\_type = Type.function( Type.double(), [Type.double()] \* +len(self.args), False) + +:: + + function = Function.new(g_llvm_module, funct_type, self.name) + + # If the name conflicted, there was already something with the same name. + # If it has a body, don't allow redefinition or reextern. + if function.name != self.name: + function.delete() + function = g_llvm_module.get_function_named(self.name) + + # If the function already has a body, reject this. + if not function.is_declaration: + raise RuntimeError('Redefinition of function.') + + # If the function took a different number of args, reject. + if len(function.args) != len(self.args): + raise RuntimeError('Redeclaration of a function with different number ' + 'of args.') + + # Set names for all arguments and add them to the variables symbol table. + for arg, arg_name in zip(function.args, self.args): + arg.name = arg_name + # Add arguments to variable symbol table. + g_named_values[arg_name] = arg + + return function + +This class represents a function definition itself. +=================================================== + +class FunctionNode(object): + +def **init**\ (self, prototype, body): self.prototype = prototype +self.body = body + +def CodeGen(self): # Clear scope. g\_named\_values.clear() + +:: + + # Create a function object. + function = self.prototype.CodeGen() + + # Create a new basic block to start insertion into. + block = function.append_basic_block('entry') + global g_llvm_builder + g_llvm_builder = Builder.new(block) + + # Finish off the function. + try: + return_value = self.body.CodeGen() + g_llvm_builder.ret(return_value) + + # Validate the generated code, checking for consistency. + function.verify() + + # Optimize the function. + g_llvm_pass_manager.run(function) + except: + function.delete() + raise + + return function + +Parser +------ + +class Parser(object): + +def **init**\ (self, tokens, binop\_precedence): self.tokens = tokens +self.binop\_precedence = binop\_precedence self.Next() + +# Provide a simple token buffer. Parser.current is the current token the +# parser is looking at. Parser.Next() reads another token from the lexer +and # updates Parser.current with its results. def Next(self): +self.current = self.tokens.next() + +# Gets the precedence of the current token, or -1 if the token is not a +binary # operator. def GetCurrentTokenPrecedence(self): if +isinstance(self.current, CharacterToken): return +self.binop\_precedence.get(self.current.char, -1) else: return -1 + +# identifierexpr ::= identifier \| identifier '(' expression\* ')' def +ParseIdentifierExpr(self): identifier\_name = self.current.name +self.Next() # eat identifier. + +:: + + if self.current != CharacterToken('('): # Simple variable reference. + return VariableExpressionNode(identifier_name) + + # Call. + self.Next() # eat '('. + args = [] + if self.current != CharacterToken(')'): + while True: + args.append(self.ParseExpression()) + if self.current == CharacterToken(')'): + break + elif self.current != CharacterToken(','): + raise RuntimeError('Expected ")" or "," in argument list.') + self.Next() + + self.Next() # eat ')'. + return CallExpressionNode(identifier_name, args) + +# numberexpr ::= number def ParseNumberExpr(self): result = +NumberExpressionNode(self.current.value) self.Next() # consume the +number. return result + +# parenexpr ::= '(' expression ')' def ParseParenExpr(self): self.Next() +# eat '('. + +:: + + contents = self.ParseExpression() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")".') + self.Next() # eat ')'. + + return contents + +# ifexpr ::= 'if' expression 'then' expression 'else' expression def +ParseIfExpr(self): self.Next() # eat the if. + +:: + + # condition. + condition = self.ParseExpression() + + if not isinstance(self.current, ThenToken): + raise RuntimeError('Expected "then".') + self.Next() # eat the then. + + then_branch = self.ParseExpression() + + if not isinstance(self.current, ElseToken): + raise RuntimeError('Expected "else".') + self.Next() # eat the else. + + else_branch = self.ParseExpression() + + return IfExpressionNode(condition, then_branch, else_branch) + +# forexpr ::= 'for' identifier '=' expr ',' expr (',' expr)? 'in' +expression def ParseForExpr(self): self.Next() # eat the for. + +:: + + if not isinstance(self.current, IdentifierToken): + raise RuntimeError('Expected identifier after for.') + + loop_variable = self.current.name + self.Next() # eat the identifier. + + if self.current != CharacterToken('='): + raise RuntimeError('Expected "=" after for variable.') + self.Next() # eat the '='. + + start = self.ParseExpression() + + if self.current != CharacterToken(','): + raise RuntimeError('Expected "," after for start value.') + self.Next() # eat the ','. + + end = self.ParseExpression() + + # The step value is optional. + if self.current == CharacterToken(','): + self.Next() # eat the ','. + step = self.ParseExpression() + else: + step = None + + if not isinstance(self.current, InToken): + raise RuntimeError('Expected "in" after for variable specification.') + self.Next() # eat 'in'. + + body = self.ParseExpression() + + return ForExpressionNode(loop_variable, start, end, step, body) + +# primary ::= identifierexpr \| numberexpr \| parenexpr \| ifexpr \| +forexpr def ParsePrimary(self): if isinstance(self.current, +IdentifierToken): return self.ParseIdentifierExpr() elif +isinstance(self.current, NumberToken): return self.ParseNumberExpr() +elif isinstance(self.current, IfToken): return self.ParseIfExpr() elif +isinstance(self.current, ForToken): return self.ParseForExpr() elif +self.current == CharacterToken('('): return self.ParseParenExpr() else: +raise RuntimeError('Unknown token when expecting an expression.') + +# binoprhs ::= (operator primary)\* def ParseBinOpRHS(self, left, +left\_precedence): # If this is a binary operator, find its precedence. +while True: precedence = self.GetCurrentTokenPrecedence() + +:: + + # If this is a binary operator that binds at least as tightly as the + # current one, consume it; otherwise we are done. + if precedence < left_precedence: + return left + + binary_operator = self.current.char + self.Next() # eat the operator. + + # Parse the primary expression after the binary operator. + right = self.ParsePrimary() + + # If binary_operator binds less tightly with right than the operator after + # right, let the pending operator take right as its left. + next_precedence = self.GetCurrentTokenPrecedence() + if precedence < next_precedence: + right = self.ParseBinOpRHS(right, precedence + 1) + + # Merge left/right. + left = BinaryOperatorExpressionNode(binary_operator, left, right) + +# expression ::= primary binoprhs def ParseExpression(self): left = +self.ParsePrimary() return self.ParseBinOpRHS(left, 0) + +# prototype ::= id '(' id\* ')' def ParsePrototype(self): if not +isinstance(self.current, IdentifierToken): raise RuntimeError('Expected +function name in prototype.') + +:: + + function_name = self.current.name + self.Next() # eat function name. + + if self.current != CharacterToken('('): + raise RuntimeError('Expected "(" in prototype.') + self.Next() # eat '('. + + arg_names = [] + while isinstance(self.current, IdentifierToken): + arg_names.append(self.current.name) + self.Next() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")" in prototype.') + + # Success. + self.Next() # eat ')'. + + return PrototypeNode(function_name, arg_names) + +# definition ::= 'def' prototype expression def ParseDefinition(self): +self.Next() # eat def. proto = self.ParsePrototype() body = +self.ParseExpression() return FunctionNode(proto, body) + +# toplevelexpr ::= expression def ParseTopLevelExpr(self): proto = +PrototypeNode('', []) return FunctionNode(proto, self.ParseExpression()) + +# external ::= 'extern' prototype def ParseExtern(self): self.Next() # +eat extern. return self.ParsePrototype() + +# Top-Level parsing def HandleDefinition(self): +self.Handle(self.ParseDefinition, 'Read a function definition:') + +def HandleExtern(self): self.Handle(self.ParseExtern, 'Read an extern:') + +def HandleTopLevelExpression(self): try: function = +self.ParseTopLevelExpr().CodeGen() result = +g\_llvm\_executor.run\_function(function, []) print 'Evaluated to:', +result.as\_real(Type.double()) except Exception, e: print 'Error:', e +try: self.Next() # Skip for error recovery. except: pass + +def Handle(self, function, message): try: print message, +function().CodeGen() except Exception, e: print 'Error:', e try: +self.Next() # Skip for error recovery. except: pass + +Main driver code. +----------------- + +def main(): # Set up the optimizer pipeline. Start with registering info +about how the # target lays out data structures. +g\_llvm\_pass\_manager.add(g\_llvm\_executor.target\_data) # Do simple +"peephole" optimizations and bit-twiddling optzns. +g\_llvm\_pass\_manager.add(PASS\_INSTRUCTION\_COMBINING) # Reassociate +expressions. g\_llvm\_pass\_manager.add(PASS\_REASSOCIATE) # Eliminate +Common SubExpressions. g\_llvm\_pass\_manager.add(PASS\_GVN) # Simplify +the control flow graph (deleting unreachable blocks, etc). +g\_llvm\_pass\_manager.add(PASS\_CFG\_SIMPLIFICATION) + +g\_llvm\_pass\_manager.initialize() + +# Install standard binary operators. # 1 is lowest possible precedence. +40 is the highest. operator\_precedence = { '<': 10, '+': 20, '-': 20, +'\*': 40 } + +# Run the main "interpreter loop". while True: print 'ready>', try: raw += raw\_input() except KeyboardInterrupt: break + +:: + + parser = Parser(Tokenize(raw), operator_precedence) + while True: + # top ::= definition | external | expression | EOF + if isinstance(parser.current, EOFToken): + break + if isinstance(parser.current, DefToken): + parser.HandleDefinition() + elif isinstance(parser.current, ExternToken): + parser.HandleExtern() + else: + parser.HandleTopLevelExpression() + +# Print out all of the generated code. print '', g\_llvm\_module + +if **name** == '**main**\ ': main() {% endhighlight %} + +-------------- + +**`Next: Extending the language: user-defined +operators `_** diff --git a/docs/source/doc/kaleidoscope/PythonLangImpl6.md b/docs/source/doc/kaleidoscope/PythonLangImpl6.md deleted file mode 100644 index 74385cb..0000000 --- a/docs/source/doc/kaleidoscope/PythonLangImpl6.md +++ /dev/null @@ -1,1535 +0,0 @@ ---- -layout: page -title: "Kaleidoscope: Chapter 6" ---- - -# Extending the Language: User-defined Operators - -Written by [Chris Lattner](mailto:sabre@nondot.org) -and [Max Shawabkeh](http://max99x.com) - - -**Chapter 6** - - -* This will become a table of contents (this text will be scraped). -{:toc} - - -**[Chapter 7: Extending the Language: Mutable -Variables / SSA Construction](PythonLangImpl7.html)** - - -# Introduction # {#intro} - - -Welcome to Chapter 6 of the -[Implementing a language with LLVM](http://www.llvm.org/docs/tutorial/index.html) tutorial. At this point in our tutorial, we now have a fully -functional language that is fairly minimal, but also useful. There -is still one big problem with it, however. Our language doesn't have many -useful operators (like division, logical negation, or even any comparisons -besides less-than). - -This chapter of the tutorial takes a wild digression into adding user-defined -operators to the simple and beautiful Kaleidoscope language. This digression now -gives us a simple and ugly language in some ways, but also a powerful one at the -same time. One of the great things about creating your own language is that you -get to decide what is good or bad. In this tutorial we'll assume that it is -okay to use this as a way to show some interesting parsing techniques. - -At the end of this tutorial, we'll run through an example Kaleidoscope -application that [renders the Mandelbrot set](#example). This gives -an example of what you can build with Kaleidoscope and its feature set. - -# User-defined Operators: the Idea # {#idea} - -The "operator overloading" that we will add to Kaleidoscope is more general than -languages like C++. In C++, you are only allowed to redefine existing -operators: you can't programatically change the grammar, introduce new -operators, change precedence levels, etc. In this chapter, we will add this -capability to Kaleidoscope, which will let the user round out the set of -operators that are supported. - -The point of going into user-defined operators in a tutorial like this is to -show the power and flexibility of using a hand-written parser. Thus far, the -parser we have been implementing uses recursive descent for most parts of the -grammar and operator precedence parsing for the expressions. -See [Chapter 2](PythonLangImpl2.html) for details. Without using operator -precedence parsing, it would be very difficult to allow the programmer to -introduce new operators into the grammar: the grammar is dynamically extensible -as the JIT runs. - -The two specific features we'll add are programmable unary operators (right -now, Kaleidoscope has no unary operators at all) as well as binary operators. -An example of this is: - - -{% highlight python %} -# Logical unary not. -def unary!(v) - if v then - 0 - else - 1 - -# Define > with the same precedence as <. -def binary> 10 (LHS RHS) - RHS < LHS - -# Binary "logical or", (note that it does not "short circuit"). -def binary| 5 (LHS RHS) - if LHS then - 1 - else if RHS then - 1 - else - 0 - -# Define = with slightly lower precedence than relationals. -def binary= 9 (LHS RHS) - !(LHS < RHS | LHS > RHS) -{% endhighlight %} - - -Many languages aspire to being able to implement their standard runtime -library in the language itself. In Kaleidoscope, we can implement significant -parts of the language in the library! - -We will break down implementation of these features into two parts: -implementing support for user-defined binary operators and adding unary -operators. - -* * * - -# User-defined Binary Operators # {#binary} - -Adding support for user-defined binary operators is pretty simple with our -current framework. We'll first add support for the unary/binary keywords: - - -{% highlight python %} -class InToken(object): pass -class BinaryToken(object): pass -class UnaryToken(object): pass -... -def Tokenize(string): - ... - elif identifier == 'in': - yield InToken() - elif identifier == 'binary': - yield BinaryToken() - elif identifier == 'unary': - yield UnaryToken() - else: - yield IdentifierToken(identifier) -{% endhighlight %} - - -This just adds lexer support for the unary and binary keywords, like we -did in [previous chapters](PythonLangImpl5.html#iflexer). One nice -thing about our current AST, is that we represent binary operators with full -generalisation by using their ASCII code as the opcode. For our extended -operators, we'll use this same representation, so we don't need any new AST or -parser support. - -On the other hand, we have to be able to represent the definitions of these -new operators, in the "def binary| 5" part of the function definition. In our -grammar so far, the "name" for the function definition is parsed as the -"prototype" production and into the `PrototypeNode`. To represent our -new user-defined operators as prototypes, we have to extend the -`PrototypeNode` like this: - - -{% highlight python %} -# This class represents the "prototype" for a function, which captures its name, -# and its argument names (thus implicitly the number of arguments the function -# takes), as well as if it is an operator. -class PrototypeNode(object): - - def __init__(self, name, args, is_operator=False, precedence=0): - self.name = name - self.args = args - self.is_operator = is_operator - self.precedence = precedence - - def IsBinaryOp(self): - return self.is_operator and len(self.args) == 2 - - def GetOperatorName(self): - assert self.is_operator - return self.name[-1] - - def CodeGen(self): - ... -{% endhighlight %} - - -Basically, in addition to knowing a name for the prototype, we now keep track -of whether it was an operator, and if it was, what precedence level the operator -is at. The precedence is only used for binary operators (as you'll see below, -it just doesn't apply for unary operators). Now that we have a way to represent -the prototype for a user-defined operator, we need to parse it: - - -{% highlight python %} - # prototype - # ::= id '(' id* ')' - # ::= binary LETTER number? (id, id) - # ::= unary LETTER (id) - def ParsePrototype(self): - precedence = None - if isinstance(self.current, IdentifierToken): - kind = 'normal' - function_name = self.current.name - self.Next() # eat function name. - elif isinstance(self.current, BinaryToken): - kind = 'binary' - self.Next() # eat 'binary'. - if not isinstance(self.current, CharacterToken): - raise RuntimeError('Expected an operator after "binary".') - function_name = 'binary' + self.current.char - self.Next() # eat the operator. - if isinstance(self.current, NumberToken): - if not 1 <= self.current.value <= 100: - raise RuntimeError('Invalid precedence: must be in range [1, 100].') - precedence = self.current.value - self.Next() # eat the precedence. - else: - raise RuntimeError('Expected function name, "unary" or "binary" in ' - 'prototype.') - - if self.current != CharacterToken('('): - raise RuntimeError('Expected "(" in prototype.') - self.Next() # eat '('. - - arg_names = [] - while isinstance(self.current, IdentifierToken): - arg_names.append(self.current.name) - self.Next() - - if self.current != CharacterToken(')'): - raise RuntimeError('Expected ")" in prototype.') - - # Success. - self.Next() # eat ')'. - - if kind == 'binary' and len(arg_names) != 2: - raise RuntimeError('Invalid number of arguments for a binary operator.') - - return PrototypeNode(function_name, arg_names, kind != 'normal', precedence) - -{% endhighlight %} - - -This is all fairly straightforward parsing code, and we have already seen -a lot of similar code in the past. One interesting part about the code above is -the couple lines that set up `function_name` for operators. This builds -names like "binary@" for a newly defined "@" operator. This then takes -advantage of the fact that symbol names in the LLVM symbol table are allowed to -have any character in them. - -The next interesting thing to add, is codegen support for these binary -operators. Given our current structure, this is a simple addition of a default -case for our existing binary operator node: - - -{% highlight python %} - def CodeGen(self): - left = self.left.CodeGen() - right = self.right.CodeGen() - - if self.operator == '+': - return g_llvm_builder.fadd(left, right, 'addtmp') - elif self.operator == '-': - return g_llvm_builder.fsub(left, right, 'subtmp') - elif self.operator == '*': - return g_llvm_builder.fmul(left, right, 'multmp') - elif self.operator == '<': - result = g_llvm_builder.fcmp(FCMP_ULT, left, right, 'cmptmp') - # Convert bool 0 or 1 to double 0.0 or 1.0. - return g_llvm_builder.uitofp(result, Type.double(), 'booltmp') - else: - function = g_llvm_module.get_function_named('binary' + self.operator) - return g_llvm_builder.call(function, [left, right], 'binop') -{% endhighlight %} - - -As you can see above, the new code is actually really simple. It just does -a lookup for the appropriate operator in the symbol table and generates a -function call to it. Since user-defined operators are just built as normal -functions (because the "prototype" boils down to a function with the right -name) everything falls into place. - -The final piece of code we are missing, is a bit of top-level magic. We will -need to make the dinary precedence map global and modify it whenever we define a -new binary operator: - - -{% highlight python %} -# The binary operator precedence chart. -g_binop_precedence = {} -... -class FunctionNode(object): - ... - def CodeGen(self): - ... - # Create a function object. - function = self.prototype.CodeGen() - - # If this is a binary operator, install its precedence. - if self.prototype.IsBinaryOp(): - operator = self.prototype.GetOperatorName() - g_binop_precedence[operator] = self.prototype.precedence - ... - # Finish off the function. - try: - ... - except: - function.delete() - if self.prototype.IsBinaryOp(): - del g_binop_precedence[self.prototype.GetOperatorName()] - raise - - return function -... -def main(): - ... - g_binop_precedence['<'] = 10 - g_binop_precedence['+'] = 20 - g_binop_precedence['-'] = 20 - g_binop_precedence['*'] = 40 - ... -{% endhighlight %} - - -Basically, before CodeGening a function, if it is a user-defined operator, we -register it in the precedence table. This allows the binary operator parsing -logic we already have in place to handle it. Since we are working on a -fully-general operator precedence parser, this is all we need to do to "extend -the grammar". - -Now we have useful user-defined binary operators. This builds a lot -on the previous framework we built for other operators. Adding unary operators -is a bit more challenging, because we don't have any framework for it yet - -let's see what it takes. - -# User-defined Unary Operators # {#unary} - -Since we don't currently support unary operators in the Kaleidoscope -language, we'll need to add everything to support them. Above, we added simple -support for the 'unary' keyword to the lexer. In addition to that, we need an -AST node: - - -{% highlight python %} -# Expression class for a unary operator. -class UnaryExpressionNode(ExpressionNode): - - def __init__(self, operator, operand): - self.operator = operator - self.operand = operand - - def CodeGen(self): - ... -{% endhighlight %} - - -This AST node is very simple and obvious by now. It directly mirrors the -binary operator AST node, except that it only has one child. With this, we -need to add the parsing logic. Parsing a unary operator is pretty simple: we'll -add a new function to do it: - - -{% highlight python %} - # unary ::= primary | unary_operator unary - def ParseUnary(self): - # If the current token is not an operator, it must be a primary expression. - if (not isinstance(self.current, CharacterToken) or - self.current in [CharacterToken('('), CharacterToken(',')]): - return self.ParsePrimary() - - # If this is a unary operator, read it. - operator = self.current.char - self.Next() # eat the operator. - return UnaryExpressionNode(operator, self.ParseUnary()) -{% endhighlight %} - - -The grammar we add is pretty straightforward here. If we see a unary -operator when parsing a primary operator, we eat the operator as a prefix and -parse the remaining piece as another unary operator. This allows us to handle -multiple unary operators (e.g. `!!x`). Note that unary operators can't have -ambiguous parses like binary operators can, so there is no need for precedence -information. - -The problem with this function, is that we need to call ParseUnary from -somewhere. To do this, we change previous callers of ParsePrimary to call -ParseUnary instead: - - -{% highlight python %} - # binoprhs ::= (binary_operator unary)* - def ParseBinOpRHS(self, left, left_precedence): - ... - # Parse the unary expression after the binary operator. - right = self.ParseUnary() - ... - - # expression ::= unary binoprhs - def ParseExpression(self): - left = self.ParseUnary() - return self.ParseBinOpRHS(left, 0) -{% endhighlight %} - - -With these two simple changes, we are now able to parse unary operators and -build the AST for them. Next up, we need to add parser support for prototypes, -to parse the unary operator prototype. We extend the binary operator code above -with: - - -{% highlight python %} - # prototype - # ::= id '(' id* ')' - # ::= binary LETTER number? (id, id) - # ::= unary LETTER (id) - def ParsePrototype(self): - precedence = None - if isinstance(self.current, IdentifierToken): - ... - elif isinstance(self.current, UnaryToken): - kind = 'unary' - self.Next() # eat 'unary'. - if not isinstance(self.current, CharacterToken): - raise RuntimeError('Expected an operator after "unary".') - function_name = 'unary' + self.current.char - self.Next() # eat the operator. - elif isinstance(self.current, BinaryToken): - ... - else: - raise RuntimeError('Expected function name, "unary" or "binary" in ' - 'prototype.') - ... - if kind == 'unary' and len(arg_names) != 1: - raise RuntimeError('Invalid number of arguments for a unary operator.') - elif kind == 'binary' and len(arg_names) != 2: - raise RuntimeError('Invalid number of arguments for a binary operator.') - - return PrototypeNode(function_name, arg_names, kind != 'normal', precedence) -{% endhighlight %} - - -As with binary operators, we name unary operators with a name that includes -the operator character. This assists us at code generation time. Speaking of, -the final piece we need to add is codegen support for unary operators. It looks -like this: - - -{% highlight python %} -class UnaryExpressionNode(ExpressionNode): - ... - def CodeGen(self): - operand = self.operand.CodeGen() - function = g_llvm_module.get_function_named('unary' + self.operator) - return g_llvm_builder.call(function, [operand], 'unop') -{% endhighlight %} - - -This code is similar to, but simpler than, the code for binary operators. It -is simpler primarily because it doesn't need to handle any predefined operators. - -* * * - -# Kicking the Tires # {#example} - -It is somewhat hard to believe, but with a few simple extensions we've -covered in the last chapters, we have grown a real-ish language. With this, we -can do a lot of interesting things, including I/O, math, and a bunch of other -things. For example, we can now add a nice sequencing operator (assuming we -import `putchard` as described in -Chapter -4): - - -{% highlight python %} -ready> def binary : 1 (x y) 0 # Low-precedence operator that ignores operands. -... -ready> extern putchard(x) -... -ready> def printd(x) putchard(x) : putchard(10) -.. -ready> printd(65) : printd(66) : printd(67) -A -B -C -Evaluated to: 0.0 -{% endhighlight %} - - -We can also define a bunch of other "primitive" operations, such as: - - -{% highlight python %} -# Logical unary not. -def unary!(v) - if v then - 0 - else - 1 - -# Unary negate. -def unary-(v) - 0-v - -# Define > with the same precedence as <. -def binary> 10 (LHS RHS) - RHS < LHS - -# Binary logical or, which does not short circuit. -def binary| 5 (LHS RHS) - if LHS then - 1 - else if RHS then - 1 - else - 0 - -# Binary logical and, which does not short circuit. -def binary& 6 (LHS RHS) - if !LHS then - 0 - else - !!RHS - -# Define = with slightly lower precedence than relationals. -def binary = 9 (LHS RHS) - !(LHS < RHS | LHS > RHS) - -{% endhighlight %} - - - -Given the previous if/then/else support, we can also define interesting -functions for I/O. For example, the following prints out a character whose -"density" reflects the value passed in: the lower the value, the denser the -character: - - -{% highlight python %} -ready> - -extern putchard(char) -def printdensity(d) - if d > 8 then - putchard(32) # ' ' - else if d > 4 then - putchard(46) # '.' - else if d > 2 then - putchard(43) # '+' - else - putchard(42); # '*' -... -ready> printdensity(1): printdensity(2): printdensity(3) : - printdensity(4): printdensity(5): printdensity(9): putchard(10) -*++.. -Evaluated to 0.000000 -{% endhighlight %} - - -Based on these simple primitive operations, we can start to define more -interesting things. For example, here's a little function that solves for the -number of iterations it takes a function in the complex plane to -converge: - - -{% highlight python %} -# determine whether the specific location diverges. -# Solve for z = z^2 + c in the complex plane. -def mandelconverger(real imag iters creal cimag) - if iters > 255 | (real*real + imag*imag > 4) then - iters - else - mandelconverger(real*real - imag*imag + creal, - 2*real*imag + cimag, - iters+1, creal, cimag) - -# return the number of iterations required for the iteration to escape -def mandelconverge(real imag) - mandelconverger(real, imag, 0, real, imag) -{% endhighlight %} - - -This "z = z2 + c" function is a beautiful little creature that is -the basis for computation of the -[Mandelbrot Set](http://en.wikipedia.org/wiki/Mandelbrot_set). Our -`mandelconverge` function returns the number of iterations that it takes -for a complex orbit to escape, saturating to 255. This is not a very useful -function by itself, but if you plot its value over a two-dimensional plane, -you can see the Mandelbrot set. Given that we are limited to using putchard -here, our amazing graphical output is limited, but we can whip together -something using the density plotter above: - - -{% highlight python %} -# compute and plot the mandlebrot set with the specified 2 dimensional range -# info. -def mandelhelp(xmin xmax xstep ymin ymax ystep) - for y = ymin, y < ymax, ystep in ( - (for x = xmin, x < xmax, xstep in - printdensity(mandleconverge(x,y))) - : putchard(10) - ) - -# mandel - This is a convenient helper function for ploting the mandelbrot set -# from the specified position with the specified Magnification. -def mandel(realstart imagstart realmag imagmag) - mandelhelp(realstart, realstart+realmag*78, realmag, - imagstart, imagstart+imagmag*40, imagmag); -{% endhighlight %} - - -Given this, we can try plotting out the mandlebrot set! Lets try it out: - - -{% highlight bash %} -ready> mandel(-2.3, -1.3, 0.05, 0.07) -******************************************************************************* -******************************************************************************* -****************************************++++++********************************* -************************************+++++...++++++***************************** -*********************************++++++++.. ...+++++*************************** -*******************************++++++++++.. ..+++++************************** -******************************++++++++++. ..++++++************************* -****************************+++++++++.... ..++++++************************ -**************************++++++++....... .....++++*********************** -*************************++++++++. . ... .++********************** -***********************++++++++... ++********************** -*********************+++++++++.... .+++********************* -******************+++..+++++.... ..+++******************** -**************++++++. .......... +++******************** -***********++++++++.. .. .++******************** -*********++++++++++... .++++******************* -********++++++++++.. .++++******************* -*******++++++..... ..++++******************* -*******+........ ...++++******************* -*******+... .... ...++++******************* -*******+++++...... ..++++******************* -*******++++++++++... .++++******************* -*********++++++++++... ++++******************* -**********+++++++++.. .. ..++******************** -*************++++++.. .......... +++******************** -******************+++...+++..... ..+++******************** -*********************+++++++++.... ..++********************* -***********************++++++++... +++********************* -*************************+++++++.. . ... .++********************** -**************************++++++++....... ......+++*********************** -****************************+++++++++.... ..++++++************************ -*****************************++++++++++.. ..++++++************************* -*******************************++++++++++.. ...+++++************************** -*********************************++++++++.. ...+++++*************************** -***********************************++++++....+++++***************************** -***************************************++++++++******************************** -******************************************************************************* -******************************************************************************* -******************************************************************************* -******************************************************************************* -******************************************************************************* -Evaluated to 0.0 -ready> mandel(-2, -1, 0.02, 0.04) -******************************************************************+++++++++++++ -****************************************************************+++++++++++++++ -*************************************************************++++++++++++++++++ -***********************************************************++++++++++++++++++++ -********************************************************+++++++++++++++++++++++ -******************************************************++++++++++++++++++++++... -***************************************************+++++++++++++++++++++....... -*************************************************++++++++++++++++++++.......... -***********************************************+++++++++++++++++++... ... -********************************************++++++++++++++++++++...... -******************************************++++++++++++++++++++....... -***************************************+++++++++++++++++++++.......... -************************************++++++++++++++++++++++........... -********************************++++++++++++++++++++++++......... -***************************++++++++...........+++++.............. -*********************++++++++++++.... ......................... -***************+++++++++++++++++.... ......... ............ -***********+++++++++++++++++++++..... ...... -********+++++++++++++++++++++++....... -******+++++++++++++++++++++++++........ -****+++++++++++++++++++++++++....... -***+++++++++++++++++++++++......... -**++++++++++++++++........... -*++++++++++++................ -*++++.................... - -*++++.................... -*++++++++++++................ -**++++++++++++++++........... -***+++++++++++++++++++++++......... -****+++++++++++++++++++++++++....... -******+++++++++++++++++++++++++........ -********+++++++++++++++++++++++....... -***********+++++++++++++++++++++..... ...... -***************+++++++++++++++++.... ......... ............ -*********************++++++++++++.... ......................... -***************************++++++++...........+++++.............. -********************************++++++++++++++++++++++++......... -************************************++++++++++++++++++++++........... -***************************************+++++++++++++++++++++.......... -******************************************++++++++++++++++++++....... -Evaluated to: 0.0 -ready> mandel(-0.9, -1.4, 0.02, 0.03) -******************************************************************************* -******************************************************************************* -******************************************************************************* -******************************************************************************* -******************************************************************************* -******************************************************************************* -******************************************************************************* -******************************************************************************* -****************************+++++++++++++++++********************************** -***********************+++++++++++...++++++++++++****************************** -********************+++++++++++++.. . .++++++++++++++************************** -*****************++++++++++++++++... ......++++++++++++************************ -**************+++++++++++++++++++... .......+++++++++++********************** -************++++++++++++++++++++.... .... ..++++++++++++******************** -**********++++++++++++++++++++++...... ...++++++++++++******************* -********+++++++++++++++++++++++....... .....++++++++++++++***************** -******++++++++++++++++++++++++....... .....+++++++++++++++**************** -****+++++++++++++++++++++++++.... . .....+++++++++++++++*************** -**+++++++++++++++++++++++++.... ...++++++++++++++++************* -*+++++++++++++++++++++++....... ....++++++++++++++++************ -+++++++++++++++++++++.......... .....++++++++++++++++*********** -++++++++++++++++++............. .......+++++++++++++++********** -+++++++++++++++................ ............++++++++++********** -+++++++++++++................. .................+++++********* -+++++++++++... .... .......... .+++++******** -++++++++++..... ........ ...+++++******* -++++++++...... ..++++++****** -+++++++........ ..+++++****** -+++++.......... ..++++++***** -++++.......... ....++++++***** -++.......... ....+++++++**** -.......... ......+++++++*** -.......... .....+++++++*** -.......... .....++++++*** -......... .+++++++** -........ .+++++++** - ...... ...+++++++* - . ....++++++++* - ...++++++++* - ..+++++++++ - ..+++++++++ -Evaluated to: 0.0 -ready> ^C -{% endhighlight %} - - -At this point, you may be starting to realize that Kaleidoscope is a real -and powerful language. It may not be self-similar :), but it can be used to -plot things that are! - -With this, we conclude the "adding user-defined operators" chapter of the -tutorial. We have successfully augmented our language, adding the ability to extend the -language in the library, and we have shown how this can be used to build a simple but -interesting end-user application in Kaleidoscope. At this point, Kaleidoscope -can build a variety of applications that are functional and can call functions -with side-effects, but it can't actually define and mutate a variable itself. - - -Strikingly, variable mutation is an important feature of some -languages, and it is not at all obvious how to -[add support for mutable variables](PythonLangImpl7.html) without -having to add an "SSA construction" phase to your front-end. In the next -chapter, we will describe how you can add variable mutation without building SSA -in your front-end. - -* * * - -# Full Code Listing # {#code} - -Here is the complete code listing for our running example, enhanced with the -if/then/else and for expressions: - - -{% highlight python %} -#!/usr/bin/env python - -import re -from llvm.core import Module, Constant, Type, Function, Builder -from llvm.ee import ExecutionEngine, TargetData -from llvm.passes import FunctionPassManager - -from llvm.core import FCMP_ULT, FCMP_ONE -from llvm.passes import (PASS_INSTRUCTION_COMBINING, - PASS_REASSOCIATE, - PASS_GVN, - PASS_CFG_SIMPLIFICATION) - -################################################################################ -## Globals -################################################################################ - -# The LLVM module, which holds all the IR code. -g_llvm_module = Module.new('my cool jit') - -# The LLVM instruction builder. Created whenever a new function is entered. -g_llvm_builder = None - -# A dictionary that keeps track of which values are defined in the current scope -# and what their LLVM representation is. -g_named_values = {} - -# The function optimization passes manager. -g_llvm_pass_manager = FunctionPassManager.new(g_llvm_module) - -# The LLVM execution engine. -g_llvm_executor = ExecutionEngine.new(g_llvm_module) - -# The binary operator precedence chart. -g_binop_precedence = {} - -################################################################################ -## Lexer -################################################################################ - -# The lexer yields one of these types for each token. -class EOFToken(object): pass -class DefToken(object): pass -class ExternToken(object): pass -class IfToken(object): pass -class ThenToken(object): pass -class ElseToken(object): pass -class ForToken(object): pass -class InToken(object): pass -class BinaryToken(object): pass -class UnaryToken(object): pass - -class IdentifierToken(object): - def __init__(self, name): self.name = name - -class NumberToken(object): - def __init__(self, value): self.value = value - -class CharacterToken(object): - def __init__(self, char): self.char = char - def __eq__(self, other): - return isinstance(other, CharacterToken) and self.char == other.char - def __ne__(self, other): return not self == other - -# Regular expressions that tokens and comments of our language. -REGEX_NUMBER = re.compile('[0-9]+(?:\.[0-9]+)?') -REGEX_IDENTIFIER = re.compile('[a-zA-Z][a-zA-Z0-9]*') -REGEX_COMMENT = re.compile('#.*') - -def Tokenize(string): - while string: - # Skip whitespace. - if string[0].isspace(): - string = string[1:] - continue - - # Run regexes. - comment_match = REGEX_COMMENT.match(string) - number_match = REGEX_NUMBER.match(string) - identifier_match = REGEX_IDENTIFIER.match(string) - - # Check if any of the regexes matched and yield the appropriate result. - if comment_match: - comment = comment_match.group(0) - string = string[len(comment):] - elif number_match: - number = number_match.group(0) - yield NumberToken(float(number)) - string = string[len(number):] - elif identifier_match: - identifier = identifier_match.group(0) - # Check if we matched a keyword. - if identifier == 'def': - yield DefToken() - elif identifier == 'extern': - yield ExternToken() - elif identifier == 'if': - yield IfToken() - elif identifier == 'then': - yield ThenToken() - elif identifier == 'else': - yield ElseToken() - elif identifier == 'for': - yield ForToken() - elif identifier == 'in': - yield InToken() - elif identifier == 'binary': - yield BinaryToken() - elif identifier == 'unary': - yield UnaryToken() - else: - yield IdentifierToken(identifier) - string = string[len(identifier):] - else: - # Yield the ASCII value of the unknown character. - yield CharacterToken(string[0]) - string = string[1:] - - yield EOFToken() - -################################################################################ -## Abstract Syntax Tree (aka Parse Tree) -################################################################################ - -# Base class for all expression nodes. -class ExpressionNode(object): - pass - -# Expression class for numeric literals like "1.0". -class NumberExpressionNode(ExpressionNode): - - def __init__(self, value): - self.value = value - - def CodeGen(self): - return Constant.real(Type.double(), self.value) - -# Expression class for referencing a variable, like "a". -class VariableExpressionNode(ExpressionNode): - - def __init__(self, name): - self.name = name - - def CodeGen(self): - if self.name in g_named_values: - return g_named_values[self.name] - else: - raise RuntimeError('Unknown variable name: ' + self.name) - -# Expression class for a binary operator. -class BinaryOperatorExpressionNode(ExpressionNode): - - def __init__(self, operator, left, right): - self.operator = operator - self.left = left - self.right = right - - def CodeGen(self): - left = self.left.CodeGen() - right = self.right.CodeGen() - - if self.operator == '+': - return g_llvm_builder.fadd(left, right, 'addtmp') - elif self.operator == '-': - return g_llvm_builder.fsub(left, right, 'subtmp') - elif self.operator == '*': - return g_llvm_builder.fmul(left, right, 'multmp') - elif self.operator == '<': - result = g_llvm_builder.fcmp(FCMP_ULT, left, right, 'cmptmp') - # Convert bool 0 or 1 to double 0.0 or 1.0. - return g_llvm_builder.uitofp(result, Type.double(), 'booltmp') - else: - function = g_llvm_module.get_function_named('binary' + self.operator) - return g_llvm_builder.call(function, [left, right], 'binop') - -# Expression class for function calls. -class CallExpressionNode(ExpressionNode): - - def __init__(self, callee, args): - self.callee = callee - self.args = args - - def CodeGen(self): - # Look up the name in the global module table. - callee = g_llvm_module.get_function_named(self.callee) - - # Check for argument mismatch error. - if len(callee.args) != len(self.args): - raise RuntimeError('Incorrect number of arguments passed.') - - arg_values = [i.CodeGen() for i in self.args] - - return g_llvm_builder.call(callee, arg_values, 'calltmp') - -# Expression class for if/then/else. -class IfExpressionNode(ExpressionNode): - - def __init__(self, condition, then_branch, else_branch): - self.condition = condition - self.then_branch = then_branch - self.else_branch = else_branch - - def CodeGen(self): - condition = self.condition.CodeGen() - - # Convert condition to a bool by comparing equal to 0.0. - condition_bool = g_llvm_builder.fcmp( - FCMP_ONE, condition, Constant.real(Type.double(), 0), 'ifcond') - - function = g_llvm_builder.basic_block.function - - # Create blocks for the then and else cases. Insert the 'then' block at the - # end of the function. - then_block = function.append_basic_block('then') - else_block = function.append_basic_block('else') - merge_block = function.append_basic_block('ifcond') - - g_llvm_builder.cbranch(condition_bool, then_block, else_block) - - # Emit then value. - g_llvm_builder.position_at_end(then_block) - then_value = self.then_branch.CodeGen() - g_llvm_builder.branch(merge_block) - - # Codegen of 'Then' can change the current block; update then_block for the - # PHI node. - then_block = g_llvm_builder.basic_block - - # Emit else block. - g_llvm_builder.position_at_end(else_block) - else_value = self.else_branch.CodeGen() - g_llvm_builder.branch(merge_block) - - # Codegen of 'Else' can change the current block, update else_block for the - # PHI node. - else_block = g_llvm_builder.basic_block - - # Emit merge block. - g_llvm_builder.position_at_end(merge_block) - phi = g_llvm_builder.phi(Type.double(), 'iftmp') - phi.add_incoming(then_value, then_block) - phi.add_incoming(else_value, else_block) - - return phi - -# Expression class for for/in. -class ForExpressionNode(ExpressionNode): - - def __init__(self, loop_variable, start, end, step, body): - self.loop_variable = loop_variable - self.start = start - self.end = end - self.step = step - self.body = body - - def CodeGen(self): - # Output this as: - # ... - # start = startexpr - # goto loop - # loop: - # variable = phi [start, loopheader], [nextvariable, loopend] - # ... - # bodyexpr - # ... - # loopend: - # step = stepexpr - # nextvariable = variable + step - # endcond = endexpr - # br endcond, loop, endloop - # outloop: - - # Emit the start code first, without 'variable' in scope. - start_value = self.start.CodeGen() - - # Make the new basic block for the loop header, inserting after current - # block. - function = g_llvm_builder.basic_block.function - pre_header_block = g_llvm_builder.basic_block - loop_block = function.append_basic_block('loop') - - # Insert an explicit fallthrough from the current block to the loop_block. - g_llvm_builder.branch(loop_block) - - # Start insertion in loop_block. - g_llvm_builder.position_at_end(loop_block) - - # Start the PHI node with an entry for start. - variable_phi = g_llvm_builder.phi(Type.double(), self.loop_variable) - variable_phi.add_incoming(start_value, pre_header_block) - - # Within the loop, the variable is defined equal to the PHI node. If it - # shadows an existing variable, we have to restore it, so save it now. - old_value = g_named_values.get(self.loop_variable, None) - g_named_values[self.loop_variable] = variable_phi - - # Emit the body of the loop. This, like any other expr, can change the - # current BB. Note that we ignore the value computed by the body. - self.body.CodeGen() - - # Emit the step value. - if self.step: - step_value = self.step.CodeGen() - else: - # If not specified, use 1.0. - step_value = Constant.real(Type.double(), 1) - - next_value = g_llvm_builder.fadd(variable_phi, step_value, 'next') - - # Compute the end condition and convert it to a bool by comparing to 0.0. - end_condition = self.end.CodeGen() - end_condition_bool = g_llvm_builder.fcmp( - FCMP_ONE, end_condition, Constant.real(Type.double(), 0), 'loopcond') - - # Create the "after loop" block and insert it. - loop_end_block = g_llvm_builder.basic_block - after_block = function.append_basic_block('afterloop') - - # Insert the conditional branch into the end of loop_end_block. - g_llvm_builder.cbranch(end_condition_bool, loop_block, after_block) - - # Any new code will be inserted in after_block. - g_llvm_builder.position_at_end(after_block) - - # Add a new entry to the PHI node for the backedge. - variable_phi.add_incoming(next_value, loop_end_block) - - # Restore the unshadowed variable. - if old_value: - g_named_values[self.loop_variable] = old_value - else: - del g_named_values[self.loop_variable] - - # for expr always returns 0.0. - return Constant.real(Type.double(), 0) - -# Expression class for a unary operator. -class UnaryExpressionNode(ExpressionNode): - - def __init__(self, operator, operand): - self.operator = operator - self.operand = operand - - def CodeGen(self): - operand = self.operand.CodeGen() - function = g_llvm_module.get_function_named('unary' + self.operator) - return g_llvm_builder.call(function, [operand], 'unop') - -# This class represents the "prototype" for a function, which captures its name, -# and its argument names (thus implicitly the number of arguments the function -# takes), as well as if it is an operator. -class PrototypeNode(object): - - def __init__(self, name, args, is_operator=False, precedence=0): - self.name = name - self.args = args - self.is_operator = is_operator - self.precedence = precedence - - def IsBinaryOp(self): - return self.is_operator and len(self.args) == 2 - - def GetOperatorName(self): - assert self.is_operator - return self.name[-1] - - def CodeGen(self): - # Make the function type, eg. double(double,double). - funct_type = Type.function( - Type.double(), [Type.double()] * len(self.args), False) - - function = Function.new(g_llvm_module, funct_type, self.name) - - # If the name conflicted, there was already something with the same name. - # If it has a body, don't allow redefinition or reextern. - if function.name != self.name: - function.delete() - function = g_llvm_module.get_function_named(self.name) - - # If the function already has a body, reject this. - if not function.is_declaration: - raise RuntimeError('Redefinition of function.') - - # If the function took a different number of args, reject. - if len(function.args) != len(self.args): - raise RuntimeError('Redeclaration of a function with different number ' - 'of args.') - - # Set names for all arguments and add them to the variables symbol table. - for arg, arg_name in zip(function.args, self.args): - arg.name = arg_name - # Add arguments to variable symbol table. - g_named_values[arg_name] = arg - - return function - -# This class represents a function definition itself. -class FunctionNode(object): - - def __init__(self, prototype, body): - self.prototype = prototype - self.body = body - - def CodeGen(self): - # Clear scope. - g_named_values.clear() - - # Create a function object. - function = self.prototype.CodeGen() - - # If this is a binary operator, install its precedence. - if self.prototype.IsBinaryOp(): - operator = self.prototype.GetOperatorName() - g_binop_precedence[operator] = self.prototype.precedence - - # Create a new basic block to start insertion into. - block = function.append_basic_block('entry') - global g_llvm_builder - g_llvm_builder = Builder.new(block) - - # Finish off the function. - try: - return_value = self.body.CodeGen() - g_llvm_builder.ret(return_value) - - # Validate the generated code, checking for consistency. - function.verify() - - # Optimize the function. - g_llvm_pass_manager.run(function) - except: - function.delete() - if self.prototype.IsBinaryOp(): - del g_binop_precedence[self.prototype.GetOperatorName()] - raise - - return function - - -################################################################################ -## Parser -################################################################################ - -class Parser(object): - - def __init__(self, tokens): - self.tokens = tokens - self.Next() - - # Provide a simple token buffer. Parser.current is the current token the - # parser is looking at. Parser.Next() reads another token from the lexer and - # updates Parser.current with its results. - def Next(self): - self.current = self.tokens.next() - - # Gets the precedence of the current token, or -1 if the token is not a binary - # operator. - def GetCurrentTokenPrecedence(self): - if isinstance(self.current, CharacterToken): - return g_binop_precedence.get(self.current.char, -1) - else: - return -1 - - # identifierexpr ::= identifier | identifier '(' expression* ')' - def ParseIdentifierExpr(self): - identifier_name = self.current.name - self.Next() # eat identifier. - - if self.current != CharacterToken('('): # Simple variable reference. - return VariableExpressionNode(identifier_name) - - # Call. - self.Next() # eat '('. - args = [] - if self.current != CharacterToken(')'): - while True: - args.append(self.ParseExpression()) - if self.current == CharacterToken(')'): - break - elif self.current != CharacterToken(','): - raise RuntimeError('Expected ")" or "," in argument list.') - self.Next() - - self.Next() # eat ')'. - return CallExpressionNode(identifier_name, args) - - # numberexpr ::= number - def ParseNumberExpr(self): - result = NumberExpressionNode(self.current.value) - self.Next() # consume the number. - return result - - # parenexpr ::= '(' expression ')' - def ParseParenExpr(self): - self.Next() # eat '('. - - contents = self.ParseExpression() - - if self.current != CharacterToken(')'): - raise RuntimeError('Expected ")".') - self.Next() # eat ')'. - - return contents - - # ifexpr ::= 'if' expression 'then' expression 'else' expression - def ParseIfExpr(self): - self.Next() # eat the if. - - # condition. - condition = self.ParseExpression() - - if not isinstance(self.current, ThenToken): - raise RuntimeError('Expected "then".') - self.Next() # eat the then. - - then_branch = self.ParseExpression() - - if not isinstance(self.current, ElseToken): - raise RuntimeError('Expected "else".') - self.Next() # eat the else. - - else_branch = self.ParseExpression() - - return IfExpressionNode(condition, then_branch, else_branch) - - # forexpr ::= 'for' identifier '=' expr ',' expr (',' expr)? 'in' expression - def ParseForExpr(self): - self.Next() # eat the for. - - if not isinstance(self.current, IdentifierToken): - raise RuntimeError('Expected identifier after for.') - - loop_variable = self.current.name - self.Next() # eat the identifier. - - if self.current != CharacterToken('='): - raise RuntimeError('Expected "=" after for variable.') - self.Next() # eat the '='. - - start = self.ParseExpression() - - if self.current != CharacterToken(','): - raise RuntimeError('Expected "," after for start value.') - self.Next() # eat the ','. - - end = self.ParseExpression() - - # The step value is optional. - if self.current == CharacterToken(','): - self.Next() # eat the ','. - step = self.ParseExpression() - else: - step = None - - if not isinstance(self.current, InToken): - raise RuntimeError('Expected "in" after for variable specification.') - self.Next() # eat 'in'. - - body = self.ParseExpression() - - return ForExpressionNode(loop_variable, start, end, step, body) - - # primary ::= identifierexpr | numberexpr | parenexpr | ifexpr | forexpr - def ParsePrimary(self): - if isinstance(self.current, IdentifierToken): - return self.ParseIdentifierExpr() - elif isinstance(self.current, NumberToken): - return self.ParseNumberExpr() - elif isinstance(self.current, IfToken): - return self.ParseIfExpr() - elif isinstance(self.current, ForToken): - return self.ParseForExpr() - elif self.current == CharacterToken('('): - return self.ParseParenExpr() - else: - raise RuntimeError('Unknown token when expecting an expression.') - - # unary ::= primary | unary_operator unary - def ParseUnary(self): - # If the current token is not an operator, it must be a primary expression. - if (not isinstance(self.current, CharacterToken) or - self.current in [CharacterToken('('), CharacterToken(',')]): - return self.ParsePrimary() - - # If this is a unary operator, read it. - operator = self.current.char - self.Next() # eat the operator. - return UnaryExpressionNode(operator, self.ParseUnary()) - - # binoprhs ::= (binary_operator unary)* - def ParseBinOpRHS(self, left, left_precedence): - # If this is a binary operator, find its precedence. - while True: - precedence = self.GetCurrentTokenPrecedence() - - # If this is a binary operator that binds at least as tightly as the - # current one, consume it; otherwise we are done. - if precedence < left_precedence: - return left - - binary_operator = self.current.char - self.Next() # eat the operator. - - # Parse the unary expression after the binary operator. - right = self.ParseUnary() - - # If binary_operator binds less tightly with right than the operator after - # right, let the pending operator take right as its left. - next_precedence = self.GetCurrentTokenPrecedence() - if precedence < next_precedence: - right = self.ParseBinOpRHS(right, precedence + 1) - - # Merge left/right. - left = BinaryOperatorExpressionNode(binary_operator, left, right) - - # expression ::= unary binoprhs - def ParseExpression(self): - left = self.ParseUnary() - return self.ParseBinOpRHS(left, 0) - - # prototype - # ::= id '(' id* ')' - # ::= binary LETTER number? (id, id) - # ::= unary LETTER (id) - def ParsePrototype(self): - precedence = None - if isinstance(self.current, IdentifierToken): - kind = 'normal' - function_name = self.current.name - self.Next() # eat function name. - elif isinstance(self.current, UnaryToken): - kind = 'unary' - self.Next() # eat 'unary'. - if not isinstance(self.current, CharacterToken): - raise RuntimeError('Expected an operator after "unary".') - function_name = 'unary' + self.current.char - self.Next() # eat the operator. - elif isinstance(self.current, BinaryToken): - kind = 'binary' - self.Next() # eat 'binary'. - if not isinstance(self.current, CharacterToken): - raise RuntimeError('Expected an operator after "binary".') - function_name = 'binary' + self.current.char - self.Next() # eat the operator. - if isinstance(self.current, NumberToken): - if not 1 <= self.current.value <= 100: - raise RuntimeError('Invalid precedence: must be in range [1, 100].') - precedence = self.current.value - self.Next() # eat the precedence. - else: - raise RuntimeError('Expected function name, "unary" or "binary" in ' - 'prototype.') - - if self.current != CharacterToken('('): - raise RuntimeError('Expected "(" in prototype.') - self.Next() # eat '('. - - arg_names = [] - while isinstance(self.current, IdentifierToken): - arg_names.append(self.current.name) - self.Next() - - if self.current != CharacterToken(')'): - raise RuntimeError('Expected ")" in prototype.') - - # Success. - self.Next() # eat ')'. - - if kind == 'unary' and len(arg_names) != 1: - raise RuntimeError('Invalid number of arguments for a unary operator.') - elif kind == 'binary' and len(arg_names) != 2: - raise RuntimeError('Invalid number of arguments for a binary operator.') - - return PrototypeNode(function_name, arg_names, kind != 'normal', precedence) - - # definition ::= 'def' prototype expression - def ParseDefinition(self): - self.Next() # eat def. - proto = self.ParsePrototype() - body = self.ParseExpression() - return FunctionNode(proto, body) - - # toplevelexpr ::= expression - def ParseTopLevelExpr(self): - proto = PrototypeNode('', []) - return FunctionNode(proto, self.ParseExpression()) - - # external ::= 'extern' prototype - def ParseExtern(self): - self.Next() # eat extern. - return self.ParsePrototype() - - # Top-Level parsing - def HandleDefinition(self): - self.Handle(self.ParseDefinition, 'Read a function definition:') - - def HandleExtern(self): - self.Handle(self.ParseExtern, 'Read an extern:') - - def HandleTopLevelExpression(self): - try: - function = self.ParseTopLevelExpr().CodeGen() - result = g_llvm_executor.run_function(function, []) - print 'Evaluated to:', result.as_real(Type.double()) - except Exception, e: - print 'Error:', e - try: - self.Next() # Skip for error recovery. - except: - pass - - def Handle(self, function, message): - try: - print message, function().CodeGen() - except Exception, e: - print 'Error:', e - try: - self.Next() # Skip for error recovery. - except: - pass - -################################################################################ -## Main driver code. -################################################################################ - -def main(): - # Set up the optimizer pipeline. Start with registering info about how the - # target lays out data structures. - g_llvm_pass_manager.add(g_llvm_executor.target_data) - # Do simple "peephole" optimizations and bit-twiddling optzns. - g_llvm_pass_manager.add(PASS_INSTRUCTION_COMBINING) - # Reassociate expressions. - g_llvm_pass_manager.add(PASS_REASSOCIATE) - # Eliminate Common SubExpressions. - g_llvm_pass_manager.add(PASS_GVN) - # Simplify the control flow graph (deleting unreachable blocks, etc). - g_llvm_pass_manager.add(PASS_CFG_SIMPLIFICATION) - - g_llvm_pass_manager.initialize() - - # Install standard binary operators. - # 1 is lowest possible precedence. 40 is the highest. - g_binop_precedence['<'] = 10 - g_binop_precedence['+'] = 20 - g_binop_precedence['-'] = 20 - g_binop_precedence['*'] = 40 - - # Run the main "interpreter loop". - while True: - print 'ready>', - try: - raw = raw_input() - except KeyboardInterrupt: - break - - parser = Parser(Tokenize(raw)) - while True: - # top ::= definition | external | expression | EOF - if isinstance(parser.current, EOFToken): - break - if isinstance(parser.current, DefToken): - parser.HandleDefinition() - elif isinstance(parser.current, ExternToken): - parser.HandleExtern() - else: - parser.HandleTopLevelExpression() - - # Print out all of the generated code. - print '\n', g_llvm_module - -if __name__ == '__main__': - main() -{% endhighlight %} - - -* * * - -**[Next: Extending the language: mutable variables / SSA construction](PythonLangImpl7.html)** - - diff --git a/docs/source/doc/kaleidoscope/PythonLangImpl6.rst b/docs/source/doc/kaleidoscope/PythonLangImpl6.rst new file mode 100644 index 0000000..c0c1f0e --- /dev/null +++ b/docs/source/doc/kaleidoscope/PythonLangImpl6.rst @@ -0,0 +1,1361 @@ ++------------------------------------+ +| layout: page | ++------------------------------------+ +| title: "Kaleidoscope: Chapter 6" | ++------------------------------------+ + +Extending the Language: User-defined Operators +============================================== + +Written by `Chris Lattner `_ and `Max +Shawabkeh `_ + +**Chapter 6** + +- This will become a table of contents (this text will be scraped). + {:toc} + +**`Chapter 7: Extending the Language: Mutable Variables / SSA +Construction `_** + +Introduction # {#intro} +======================= + +Welcome to Chapter 6 of the `Implementing a language with +LLVM `_ tutorial. At this +point in our tutorial, we now have a fully functional language that is +fairly minimal, but also useful. There is still one big problem with it, +however. Our language doesn't have many useful operators (like division, +logical negation, or even any comparisons besides less-than). + +This chapter of the tutorial takes a wild digression into adding +user-defined operators to the simple and beautiful Kaleidoscope +language. This digression now gives us a simple and ugly language in +some ways, but also a powerful one at the same time. One of the great +things about creating your own language is that you get to decide what +is good or bad. In this tutorial we'll assume that it is okay to use +this as a way to show some interesting parsing techniques. + +At the end of this tutorial, we'll run through an example Kaleidoscope +application that `renders the Mandelbrot set <#example>`_. This gives an +example of what you can build with Kaleidoscope and its feature set. + +User-defined Operators: the Idea # {#idea} +========================================== + +The "operator overloading" that we will add to Kaleidoscope is more +general than languages like C++. In C++, you are only allowed to +redefine existing operators: you can't programatically change the +grammar, introduce new operators, change precedence levels, etc. In this +chapter, we will add this capability to Kaleidoscope, which will let the +user round out the set of operators that are supported. + +The point of going into user-defined operators in a tutorial like this +is to show the power and flexibility of using a hand-written parser. +Thus far, the parser we have been implementing uses recursive descent +for most parts of the grammar and operator precedence parsing for the +expressions. See `Chapter 2 `_ for details. +Without using operator precedence parsing, it would be very difficult to +allow the programmer to introduce new operators into the grammar: the +grammar is dynamically extensible as the JIT runs. + +The two specific features we'll add are programmable unary operators +(right now, Kaleidoscope has no unary operators at all) as well as +binary operators. An example of this is: + +{% highlight python %} # Logical unary not. def unary!(v) if v then 0 +else 1 + +Define > with the same precedence as <. +======================================= + +def binary> 10 (LHS RHS) RHS < LHS + +Binary "logical or", (note that it does not "short circuit"). +============================================================= + +def binary\| 5 (LHS RHS) if LHS then 1 else if RHS then 1 else 0 + +Define = with slightly lower precedence than relationals. +========================================================= + +def binary= 9 (LHS RHS) !(LHS < RHS \| LHS > RHS) {% endhighlight %} + +Many languages aspire to being able to implement their standard runtime +library in the language itself. In Kaleidoscope, we can implement +significant parts of the language in the library! + +We will break down implementation of these features into two parts: +implementing support for user-defined binary operators and adding unary +operators. + +-------------- + +User-defined Binary Operators # {#binary} +========================================= + +Adding support for user-defined binary operators is pretty simple with +our current framework. We'll first add support for the unary/binary +keywords: + +{% highlight python %} class InToken(object): pass class +BinaryToken(object): pass class UnaryToken(object): pass ... def +Tokenize(string): ... elif identifier == 'in': yield InToken() elif +identifier == 'binary': yield BinaryToken() elif identifier == 'unary': +yield UnaryToken() else: yield IdentifierToken(identifier) {% +endhighlight %} + +This just adds lexer support for the unary and binary keywords, like we +did in `previous chapters `_. One nice +thing about our current AST, is that we represent binary operators with +full generalisation by using their ASCII code as the opcode. For our +extended operators, we'll use this same representation, so we don't need +any new AST or parser support. + +On the other hand, we have to be able to represent the definitions of +these new operators, in the "def binary\| 5" part of the function +definition. In our grammar so far, the "name" for the function +definition is parsed as the "prototype" production and into the +``PrototypeNode``. To represent our new user-defined operators as +prototypes, we have to extend the ``PrototypeNode`` like this: + +{% highlight python %} # This class represents the "prototype" for a +function, which captures its name, # and its argument names (thus +implicitly the number of arguments the function # takes), as well as if +it is an operator. class PrototypeNode(object): + +def **init**\ (self, name, args, is\_operator=False, precedence=0): +self.name = name self.args = args self.is\_operator = is\_operator +self.precedence = precedence + +def IsBinaryOp(self): return self.is\_operator and len(self.args) == 2 + +def GetOperatorName(self): assert self.is\_operator return self.name[-1] + +def CodeGen(self): ... {% endhighlight %} + +Basically, in addition to knowing a name for the prototype, we now keep +track of whether it was an operator, and if it was, what precedence +level the operator is at. The precedence is only used for binary +operators (as you'll see below, it just doesn't apply for unary +operators). Now that we have a way to represent the prototype for a +user-defined operator, we need to parse it: + +{% highlight python %} # prototype # ::= id '(' id\* ')' # ::= binary +LETTER number? (id, id) # ::= unary LETTER (id) def +ParsePrototype(self): precedence = None if isinstance(self.current, +IdentifierToken): kind = 'normal' function\_name = self.current.name +self.Next() # eat function name. elif isinstance(self.current, +BinaryToken): kind = 'binary' self.Next() # eat 'binary'. if not +isinstance(self.current, CharacterToken): raise RuntimeError('Expected +an operator after "binary".') function\_name = 'binary' + +self.current.char self.Next() # eat the operator. if +isinstance(self.current, NumberToken): if not 1 <= self.current.value <= +100: raise RuntimeError('Invalid precedence: must be in range [1, +100].') precedence = self.current.value self.Next() # eat the +precedence. else: raise RuntimeError('Expected function name, "unary" or +"binary" in ' 'prototype.') + +:: + + if self.current != CharacterToken('('): + raise RuntimeError('Expected "(" in prototype.') + self.Next() # eat '('. + + arg_names = [] + while isinstance(self.current, IdentifierToken): + arg_names.append(self.current.name) + self.Next() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")" in prototype.') + + # Success. + self.Next() # eat ')'. + + if kind == 'binary' and len(arg_names) != 2: + raise RuntimeError('Invalid number of arguments for a binary operator.') + + return PrototypeNode(function_name, arg_names, kind != 'normal', precedence) + +{% endhighlight %} + +This is all fairly straightforward parsing code, and we have already +seen a lot of similar code in the past. One interesting part about the +code above is the couple lines that set up ``function_name`` for +operators. This builds names like "binary@" for a newly defined "@" +operator. This then takes advantage of the fact that symbol names in the +LLVM symbol table are allowed to have any character in them. + +The next interesting thing to add, is codegen support for these binary +operators. Given our current structure, this is a simple addition of a +default case for our existing binary operator node: + +{% highlight python %} def CodeGen(self): left = self.left.CodeGen() +right = self.right.CodeGen() + +:: + + if self.operator == '+': + return g_llvm_builder.fadd(left, right, 'addtmp') + elif self.operator == '-': + return g_llvm_builder.fsub(left, right, 'subtmp') + elif self.operator == '*': + return g_llvm_builder.fmul(left, right, 'multmp') + elif self.operator == '<': + result = g_llvm_builder.fcmp(FCMP_ULT, left, right, 'cmptmp') + # Convert bool 0 or 1 to double 0.0 or 1.0. + return g_llvm_builder.uitofp(result, Type.double(), 'booltmp') + else: + function = g_llvm_module.get_function_named('binary' + self.operator) + return g_llvm_builder.call(function, [left, right], 'binop') + +{% endhighlight %} + +As you can see above, the new code is actually really simple. It just +does a lookup for the appropriate operator in the symbol table and +generates a function call to it. Since user-defined operators are just +built as normal functions (because the "prototype" boils down to a +function with the right name) everything falls into place. + +The final piece of code we are missing, is a bit of top-level magic. We +will need to make the dinary precedence map global and modify it +whenever we define a new binary operator: + +{% highlight python %} # The binary operator precedence chart. +g\_binop\_precedence = {} ... class FunctionNode(object): ... def +CodeGen(self): ... # Create a function object. function = +self.prototype.CodeGen() + +:: + + # If this is a binary operator, install its precedence. + if self.prototype.IsBinaryOp(): + operator = self.prototype.GetOperatorName() + g_binop_precedence[operator] = self.prototype.precedence + ... + # Finish off the function. + try: + ... + except: + function.delete() + if self.prototype.IsBinaryOp(): + del g_binop_precedence[self.prototype.GetOperatorName()] + raise + + return function + +... def main(): ... g\_binop\_precedence['<'] = 10 +g\_binop\_precedence['+'] = 20 g\_binop\_precedence['-'] = 20 +g\_binop\_precedence['\*'] = 40 ... {% endhighlight %} + +Basically, before CodeGening a function, if it is a user-defined +operator, we register it in the precedence table. This allows the binary +operator parsing logic we already have in place to handle it. Since we +are working on a fully-general operator precedence parser, this is all +we need to do to "extend the grammar". + +Now we have useful user-defined binary operators. This builds a lot on +the previous framework we built for other operators. Adding unary +operators is a bit more challenging, because we don't have any framework +for it yet - let's see what it takes. + +User-defined Unary Operators # {#unary} +======================================= + +Since we don't currently support unary operators in the Kaleidoscope +language, we'll need to add everything to support them. Above, we added +simple support for the 'unary' keyword to the lexer. In addition to +that, we need an AST node: + +{% highlight python %} # Expression class for a unary operator. class +UnaryExpressionNode(ExpressionNode): + +def **init**\ (self, operator, operand): self.operator = operator +self.operand = operand + +def CodeGen(self): ... {% endhighlight %} + +This AST node is very simple and obvious by now. It directly mirrors the +binary operator AST node, except that it only has one child. With this, +we need to add the parsing logic. Parsing a unary operator is pretty +simple: we'll add a new function to do it: + +{% highlight python %} # unary ::= primary \| unary\_operator unary def +ParseUnary(self): # If the current token is not an operator, it must be +a primary expression. if (not isinstance(self.current, CharacterToken) +or self.current in [CharacterToken('('), CharacterToken(',')]): return +self.ParsePrimary() + +:: + + # If this is a unary operator, read it. + operator = self.current.char + self.Next() # eat the operator. + return UnaryExpressionNode(operator, self.ParseUnary()) + +{% endhighlight %} + +The grammar we add is pretty straightforward here. If we see a unary +operator when parsing a primary operator, we eat the operator as a +prefix and parse the remaining piece as another unary operator. This +allows us to handle multiple unary operators (e.g. ``!!x``). Note that +unary operators can't have ambiguous parses like binary operators can, +so there is no need for precedence information. + +The problem with this function, is that we need to call ParseUnary from +somewhere. To do this, we change previous callers of ParsePrimary to +call ParseUnary instead: + +{% highlight python %} # binoprhs ::= (binary\_operator unary)\* def +ParseBinOpRHS(self, left, left\_precedence): ... # Parse the unary +expression after the binary operator. right = self.ParseUnary() ... + +# expression ::= unary binoprhs def ParseExpression(self): left = +self.ParseUnary() return self.ParseBinOpRHS(left, 0) {% endhighlight %} + +With these two simple changes, we are now able to parse unary operators +and build the AST for them. Next up, we need to add parser support for +prototypes, to parse the unary operator prototype. We extend the binary +operator code above with: + +{% highlight python %} # prototype # ::= id '(' id\* ')' # ::= binary +LETTER number? (id, id) # ::= unary LETTER (id) def +ParsePrototype(self): precedence = None if isinstance(self.current, +IdentifierToken): ... elif isinstance(self.current, UnaryToken): kind = +'unary' self.Next() # eat 'unary'. if not isinstance(self.current, +CharacterToken): raise RuntimeError('Expected an operator after +"unary".') function\_name = 'unary' + self.current.char self.Next() # +eat the operator. elif isinstance(self.current, BinaryToken): ... else: +raise RuntimeError('Expected function name, "unary" or "binary" in ' +'prototype.') ... if kind == 'unary' and len(arg\_names) != 1: raise +RuntimeError('Invalid number of arguments for a unary operator.') elif +kind == 'binary' and len(arg\_names) != 2: raise RuntimeError('Invalid +number of arguments for a binary operator.') + +:: + + return PrototypeNode(function_name, arg_names, kind != 'normal', precedence) + +{% endhighlight %} + +As with binary operators, we name unary operators with a name that +includes the operator character. This assists us at code generation +time. Speaking of, the final piece we need to add is codegen support for +unary operators. It looks like this: + +{% highlight python %} class UnaryExpressionNode(ExpressionNode): ... +def CodeGen(self): operand = self.operand.CodeGen() function = +g\_llvm\_module.get\_function\_named('unary' + self.operator) return +g\_llvm\_builder.call(function, [operand], 'unop') {% endhighlight %} + +This code is similar to, but simpler than, the code for binary +operators. It is simpler primarily because it doesn't need to handle any +predefined operators. + +-------------- + +Kicking the Tires # {#example} +============================== + +It is somewhat hard to believe, but with a few simple extensions we've +covered in the last chapters, we have grown a real-ish language. With +this, we can do a lot of interesting things, including I/O, math, and a +bunch of other things. For example, we can now add a nice sequencing +operator (assuming we import ``putchard`` as described in Chapter 4): + +{% highlight python %} ready> def binary : 1 (x y) 0 # Low-precedence +operator that ignores operands. ... ready> extern putchard(x) ... ready> +def printd(x) putchard(x) : putchard(10) .. ready> printd(65) : +printd(66) : printd(67) A B C Evaluated to: 0.0 {% endhighlight %} + +We can also define a bunch of other "primitive" operations, such as: + +{% highlight python %} # Logical unary not. def unary!(v) if v then 0 +else 1 + +Unary negate. +============= + +def unary-(v) 0-v + +Define > with the same precedence as <. +======================================= + +def binary> 10 (LHS RHS) RHS < LHS + +Binary logical or, which does not short circuit. +================================================ + +def binary\| 5 (LHS RHS) if LHS then 1 else if RHS then 1 else 0 + +Binary logical and, which does not short circuit. +================================================= + +def binary& 6 (LHS RHS) if !LHS then 0 else !!RHS + +Define = with slightly lower precedence than relationals. +========================================================= + +def binary = 9 (LHS RHS) !(LHS < RHS \| LHS > RHS) + +{% endhighlight %} + +Given the previous if/then/else support, we can also define interesting +functions for I/O. For example, the following prints out a character +whose "density" reflects the value passed in: the lower the value, the +denser the character: + +{% highlight python %} ready> + +extern putchard(char) def printdensity(d) if d > 8 then putchard(32) # ' +' else if d > 4 then putchard(46) # '.' else if d > 2 then putchard(43) +# '+' else putchard(42); # '*' ... ready> printdensity(1): +printdensity(2): printdensity(3) : printdensity(4): printdensity(5): +printdensity(9): putchard(10)*\ ++.. Evaluated to 0.000000 {% +endhighlight %} + +Based on these simple primitive operations, we can start to define more +interesting things. For example, here's a little function that solves +for the number of iterations it takes a function in the complex plane to +converge: + +{% highlight python %} # determine whether the specific location +diverges. # Solve for z = z^2 + c in the complex plane. def +mandelconverger(real imag iters creal cimag) if iters > 255 \| +(real\ *real + imag*\ imag > 4) then iters else +mandelconverger(real\ *real - imag*\ imag + creal, 2\ *real*\ imag + +cimag, iters+1, creal, cimag) + +return the number of iterations required for the iteration to escape +==================================================================== + +def mandelconverge(real imag) mandelconverger(real, imag, 0, real, imag) +{% endhighlight %} + +This "z = z2 + c" function is a beautiful little creature that is the +basis for computation of the `Mandelbrot +Set `_. Our +``mandelconverge`` function returns the number of iterations that it +takes for a complex orbit to escape, saturating to 255. This is not a +very useful function by itself, but if you plot its value over a +two-dimensional plane, you can see the Mandelbrot set. Given that we are +limited to using putchard here, our amazing graphical output is limited, +but we can whip together something using the density plotter above: + +{% highlight python %} # compute and plot the mandlebrot set with the +specified 2 dimensional range # info. def mandelhelp(xmin xmax xstep +ymin ymax ystep) for y = ymin, y < ymax, ystep in ( (for x = xmin, x < +xmax, xstep in printdensity(mandleconverge(x,y))) : putchard(10) ) + +mandel - This is a convenient helper function for ploting the mandelbrot set +============================================================================ + +from the specified position with the specified Magnification. +============================================================= + +def mandel(realstart imagstart realmag imagmag) mandelhelp(realstart, +realstart+realmag\ *78, realmag, imagstart, imagstart+imagmag*\ 40, +imagmag); {% endhighlight %} + +Given this, we can try plotting out the mandlebrot set! Lets try it out: + +{% highlight bash %} ready> mandel(-2.3, -1.3, 0.05, 0.07) +\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* +\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* +\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* +\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++...++++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* +\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++.. +...+++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* +\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++++.. +..+++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* +\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++++. +..++++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* +\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++++++.... +..++++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* +\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++....... +.....++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* +\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++. . ... +.++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* +\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++... +++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* +\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++++++.... +.+++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* +\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++..+++++.... +..+++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* +\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++. .......... ++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* +\*\*\*\*\*\*\*\*\*\*\*++++++++.. .. +.++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* +\*\*\*\*\*\*\*\*\*++++++++++... +.++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* \*\*\*\*\*\*\*\*++++++++++.. +.++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* \*\*\*\*\*\*\*++++++..... +..++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* \*\*\*\*\*\*\*+........ +...++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* \*\*\*\*\*\*\*+... .... +...++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* \*\*\*\*\*\*\*+++++...... +..++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* \*\*\*\*\*\*\*++++++++++... +.++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* +\*\*\*\*\*\*\*\*\*++++++++++... +++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* +\*\*\*\*\*\*\*\*\*\*+++++++++.. .. +..++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* +\*\*\*\*\*\*\*\*\*\*\*\*\*++++++.. .......... ++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* +\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++...+++..... +..+++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* +\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++++++.... +..++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* +\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++... ++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* +\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++++.. . ... +.++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* +\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++....... +......+++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* +\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++++++.... +..++++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* +\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++++.. +..++++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* +\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++++.. +...+++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* +\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++.. +...+++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* +\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++....+++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* +\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* +\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* +\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* +\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* +\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* +\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* +Evaluated to 0.0 ready> mandel(-2, -1, 0.02, 0.04) +\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++++++++++ +\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++++++++++++ +\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++++++++++++ +\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++++++++++++++ +\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++++++++++++++++++++ +\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++++++++++++++++... +\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++++++++++++++++++....... +\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++++++++++++++.......... +\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++++++++++++++++... +... +\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++++++++++++++...... +\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++++++++++++++....... +\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++++++++++++++++++.......... +\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++++++++++++++++........... +\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++++++++++++++++++......... +\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++...........+++++.............. +\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++++++.... +......................... +\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++++++++++++++.... ......... +............ \*\*\*\*\*\*\*\*\*\*\*+++++++++++++++++++++..... ...... +\*\*\*\*\*\*\*\*+++++++++++++++++++++++....... +\*\*\*\*\*\*+++++++++++++++++++++++++........ +\*\*\*\*+++++++++++++++++++++++++....... +***+++++++++++++++++++++++.........**\ ++++++++++++++++...........*\ ++++++++++++................ +\*++++.................... + +*++++....................*\ ++++++++++++................ +**++++++++++++++++...........**\ *+++++++++++++++++++++++......... +\*\*\*\*+++++++++++++++++++++++++....... +\*\*\*\*\*\*+++++++++++++++++++++++++........ +\*\*\*\*\*\*\*\*+++++++++++++++++++++++....... +\*\*\*\*\*\*\*\*\*\*\*+++++++++++++++++++++..... ...... +\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++++++++++++++.... ......... +............ \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++++++.... +......................... +\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++...........+++++.............. +\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++++++++++++++++++......... +\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++++++++++++++++........... +\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++++++++++++++++++.......... +\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++++++++++++++....... +Evaluated to: 0.0 ready> mandel(-0.9, -1.4, 0.02, 0.03) +\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* +\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* +\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* +\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* +\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* +\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* +\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* +\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* +\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++++++++++++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* +\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++++++++...++++++++++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* +\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++++++++++.. . +.++++++++++++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* +\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++++++++++... +......++++++++++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* +\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++++++++++++++++... +.......+++++++++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* +\*\*\*\*\*\*\*\*\*\*\*\*++++++++++++++++++++.... .... +..++++++++++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* +\*\*\*\*\*\*\*\*\*\*++++++++++++++++++++++...... +...++++++++++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* +\*\*\*\*\*\*\*\*+++++++++++++++++++++++....... +.....++++++++++++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* +\*\*\*\*\*\*++++++++++++++++++++++++....... +.....+++++++++++++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* +\*\*\*\*+++++++++++++++++++++++++.... . +.....+++++++++++++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* +**+++++++++++++++++++++++++.... +...++++++++++++++++**\ \*\*\*\*\*\*\*\*\*\*\**\ +++++++++++++++++++++++....... +....++++++++++++++++\*\*\*\*\*\*\*\*\*\*\*\* ++++++++++++++++++++++.......... +.....++++++++++++++++\*\*\*\*\*\*\*\*\*\*\* +++++++++++++++++++............. +.......+++++++++++++++\*\*\*\*\*\*\*\*\*\* ++++++++++++++++................ +............++++++++++\*\*\*\*\*\*\*\*\*\* ++++++++++++++................. .................+++++\*\*\*\*\*\*\*\*\* ++++++++++++... .... .......... .+++++\*\*\*\*\*\*\*\* ++++++++++..... +........ ...+++++\*\*\*\*\*\*\* ++++++++...... ..++++++\*\*\*\*\*\* ++++++++........ ..+++++\*\*\*\*\*\* +++++.......... ..++++++\*\*\*\*\* +++++.......... ....++++++\*\*\*\*\* ++.......... ....+++++++\*\*\*\* +.......... ......+++++++\ **\* .......... .....+++++++**\ \* .......... +.....++++++\ **\* ......... .+++++++** ........ .+++++++\ *\* ...... +...+++++++* . ....++++++++\* ...++++++++\* ..+++++++++ ..+++++++++ +Evaluated to: 0.0 ready> ^C {% endhighlight %} + +At this point, you may be starting to realize that Kaleidoscope is a +real and powerful language. It may not be self-similar :), but it can be +used to plot things that are! + +With this, we conclude the "adding user-defined operators" chapter of +the tutorial. We have successfully augmented our language, adding the +ability to extend the language in the library, and we have shown how +this can be used to build a simple but interesting end-user application +in Kaleidoscope. At this point, Kaleidoscope can build a variety of +applications that are functional and can call functions with +side-effects, but it can't actually define and mutate a variable itself. + +Strikingly, variable mutation is an important feature of some languages, +and it is not at all obvious how to `add support for mutable +variables `_ without having to add an "SSA +construction" phase to your front-end. In the next chapter, we will +describe how you can add variable mutation without building SSA in your +front-end. + +-------------- + +Full Code Listing # {#code} +=========================== + +Here is the complete code listing for our running example, enhanced with +the if/then/else and for expressions: + +{% highlight python %} #!/usr/bin/env python + +import re from llvm.core import Module, Constant, Type, Function, +Builder from llvm.ee import ExecutionEngine, TargetData from llvm.passes +import FunctionPassManager + +from llvm.core import FCMP\_ULT, FCMP\_ONE from llvm.passes import +(PASS\_INSTRUCTION\_COMBINING, PASS\_REASSOCIATE, PASS\_GVN, +PASS\_CFG\_SIMPLIFICATION) + +Globals +------- + +The LLVM module, which holds all the IR code. +============================================= + +g\_llvm\_module = Module.new('my cool jit') + +The LLVM instruction builder. Created whenever a new function is entered. +========================================================================= + +g\_llvm\_builder = None + +A dictionary that keeps track of which values are defined in the current scope +============================================================================== + +and what their LLVM representation is. +====================================== + +g\_named\_values = {} + +The function optimization passes manager. +========================================= + +g\_llvm\_pass\_manager = FunctionPassManager.new(g\_llvm\_module) + +The LLVM execution engine. +========================== + +g\_llvm\_executor = ExecutionEngine.new(g\_llvm\_module) + +The binary operator precedence chart. +===================================== + +g\_binop\_precedence = {} + +Lexer +----- + +The lexer yields one of these types for each token. +=================================================== + +class EOFToken(object): pass class DefToken(object): pass class +ExternToken(object): pass class IfToken(object): pass class +ThenToken(object): pass class ElseToken(object): pass class +ForToken(object): pass class InToken(object): pass class +BinaryToken(object): pass class UnaryToken(object): pass + +class IdentifierToken(object): def **init**\ (self, name): self.name = +name + +class NumberToken(object): def **init**\ (self, value): self.value = +value + +class CharacterToken(object): def **init**\ (self, char): self.char = +char def **eq**\ (self, other): return isinstance(other, CharacterToken) +and self.char == other.char def **ne**\ (self, other): return not self +== other + +Regular expressions that tokens and comments of our language. +============================================================= + +REGEX\_NUMBER = re.compile('[0-9]+(?:.[0-9]+)?') REGEX\_IDENTIFIER = +re.compile('[a-zA-Z][a-zA-Z0-9]\ *') REGEX\_COMMENT = re.compile('#.*') + +def Tokenize(string): while string: # Skip whitespace. if +string[0].isspace(): string = string[1:] continue + +:: + + # Run regexes. + comment_match = REGEX_COMMENT.match(string) + number_match = REGEX_NUMBER.match(string) + identifier_match = REGEX_IDENTIFIER.match(string) + + # Check if any of the regexes matched and yield the appropriate result. + if comment_match: + comment = comment_match.group(0) + string = string[len(comment):] + elif number_match: + number = number_match.group(0) + yield NumberToken(float(number)) + string = string[len(number):] + elif identifier_match: + identifier = identifier_match.group(0) + # Check if we matched a keyword. + if identifier == 'def': + yield DefToken() + elif identifier == 'extern': + yield ExternToken() + elif identifier == 'if': + yield IfToken() + elif identifier == 'then': + yield ThenToken() + elif identifier == 'else': + yield ElseToken() + elif identifier == 'for': + yield ForToken() + elif identifier == 'in': + yield InToken() + elif identifier == 'binary': + yield BinaryToken() + elif identifier == 'unary': + yield UnaryToken() + else: + yield IdentifierToken(identifier) + string = string[len(identifier):] + else: + # Yield the ASCII value of the unknown character. + yield CharacterToken(string[0]) + string = string[1:] + +yield EOFToken() + +Abstract Syntax Tree (aka Parse Tree) +------------------------------------- + +Base class for all expression nodes. +==================================== + +class ExpressionNode(object): pass + +Expression class for numeric literals like "1.0". +================================================= + +class NumberExpressionNode(ExpressionNode): + +def **init**\ (self, value): self.value = value + +def CodeGen(self): return Constant.real(Type.double(), self.value) + +Expression class for referencing a variable, like "a". +====================================================== + +class VariableExpressionNode(ExpressionNode): + +def **init**\ (self, name): self.name = name + +def CodeGen(self): if self.name in g\_named\_values: return +g\_named\_values[self.name] else: raise RuntimeError('Unknown variable +name: ' + self.name) + +Expression class for a binary operator. +======================================= + +class BinaryOperatorExpressionNode(ExpressionNode): + +def **init**\ (self, operator, left, right): self.operator = operator +self.left = left self.right = right + +def CodeGen(self): left = self.left.CodeGen() right = +self.right.CodeGen() + +:: + + if self.operator == '+': + return g_llvm_builder.fadd(left, right, 'addtmp') + elif self.operator == '-': + return g_llvm_builder.fsub(left, right, 'subtmp') + elif self.operator == '*': + return g_llvm_builder.fmul(left, right, 'multmp') + elif self.operator == '<': + result = g_llvm_builder.fcmp(FCMP_ULT, left, right, 'cmptmp') + # Convert bool 0 or 1 to double 0.0 or 1.0. + return g_llvm_builder.uitofp(result, Type.double(), 'booltmp') + else: + function = g_llvm_module.get_function_named('binary' + self.operator) + return g_llvm_builder.call(function, [left, right], 'binop') + +Expression class for function calls. +==================================== + +class CallExpressionNode(ExpressionNode): + +def **init**\ (self, callee, args): self.callee = callee self.args = +args + +def CodeGen(self): # Look up the name in the global module table. callee += g\_llvm\_module.get\_function\_named(self.callee) + +:: + + # Check for argument mismatch error. + if len(callee.args) != len(self.args): + raise RuntimeError('Incorrect number of arguments passed.') + + arg_values = [i.CodeGen() for i in self.args] + + return g_llvm_builder.call(callee, arg_values, 'calltmp') + +Expression class for if/then/else. +================================== + +class IfExpressionNode(ExpressionNode): + +def **init**\ (self, condition, then\_branch, else\_branch): +self.condition = condition self.then\_branch = then\_branch +self.else\_branch = else\_branch + +def CodeGen(self): condition = self.condition.CodeGen() + +:: + + # Convert condition to a bool by comparing equal to 0.0. + condition_bool = g_llvm_builder.fcmp( + FCMP_ONE, condition, Constant.real(Type.double(), 0), 'ifcond') + + function = g_llvm_builder.basic_block.function + + # Create blocks for the then and else cases. Insert the 'then' block at the + # end of the function. + then_block = function.append_basic_block('then') + else_block = function.append_basic_block('else') + merge_block = function.append_basic_block('ifcond') + + g_llvm_builder.cbranch(condition_bool, then_block, else_block) + + # Emit then value. + g_llvm_builder.position_at_end(then_block) + then_value = self.then_branch.CodeGen() + g_llvm_builder.branch(merge_block) + + # Codegen of 'Then' can change the current block; update then_block for the + # PHI node. + then_block = g_llvm_builder.basic_block + + # Emit else block. + g_llvm_builder.position_at_end(else_block) + else_value = self.else_branch.CodeGen() + g_llvm_builder.branch(merge_block) + + # Codegen of 'Else' can change the current block, update else_block for the + # PHI node. + else_block = g_llvm_builder.basic_block + + # Emit merge block. + g_llvm_builder.position_at_end(merge_block) + phi = g_llvm_builder.phi(Type.double(), 'iftmp') + phi.add_incoming(then_value, then_block) + phi.add_incoming(else_value, else_block) + + return phi + +Expression class for for/in. +============================ + +class ForExpressionNode(ExpressionNode): + +def **init**\ (self, loop\_variable, start, end, step, body): +self.loop\_variable = loop\_variable self.start = start self.end = end +self.step = step self.body = body + +def CodeGen(self): # Output this as: # ... # start = startexpr # goto +loop # loop: # variable = phi [start, loopheader], [nextvariable, +loopend] # ... # bodyexpr # ... # loopend: # step = stepexpr # +nextvariable = variable + step # endcond = endexpr # br endcond, loop, +endloop # outloop: + +:: + + # Emit the start code first, without 'variable' in scope. + start_value = self.start.CodeGen() + + # Make the new basic block for the loop header, inserting after current + # block. + function = g_llvm_builder.basic_block.function + pre_header_block = g_llvm_builder.basic_block + loop_block = function.append_basic_block('loop') + + # Insert an explicit fallthrough from the current block to the loop_block. + g_llvm_builder.branch(loop_block) + + # Start insertion in loop_block. + g_llvm_builder.position_at_end(loop_block) + + # Start the PHI node with an entry for start. + variable_phi = g_llvm_builder.phi(Type.double(), self.loop_variable) + variable_phi.add_incoming(start_value, pre_header_block) + + # Within the loop, the variable is defined equal to the PHI node. If it + # shadows an existing variable, we have to restore it, so save it now. + old_value = g_named_values.get(self.loop_variable, None) + g_named_values[self.loop_variable] = variable_phi + + # Emit the body of the loop. This, like any other expr, can change the + # current BB. Note that we ignore the value computed by the body. + self.body.CodeGen() + + # Emit the step value. + if self.step: + step_value = self.step.CodeGen() + else: + # If not specified, use 1.0. + step_value = Constant.real(Type.double(), 1) + + next_value = g_llvm_builder.fadd(variable_phi, step_value, 'next') + + # Compute the end condition and convert it to a bool by comparing to 0.0. + end_condition = self.end.CodeGen() + end_condition_bool = g_llvm_builder.fcmp( + FCMP_ONE, end_condition, Constant.real(Type.double(), 0), 'loopcond') + + # Create the "after loop" block and insert it. + loop_end_block = g_llvm_builder.basic_block + after_block = function.append_basic_block('afterloop') + + # Insert the conditional branch into the end of loop_end_block. + g_llvm_builder.cbranch(end_condition_bool, loop_block, after_block) + + # Any new code will be inserted in after_block. + g_llvm_builder.position_at_end(after_block) + + # Add a new entry to the PHI node for the backedge. + variable_phi.add_incoming(next_value, loop_end_block) + + # Restore the unshadowed variable. + if old_value: + g_named_values[self.loop_variable] = old_value + else: + del g_named_values[self.loop_variable] + + # for expr always returns 0.0. + return Constant.real(Type.double(), 0) + +Expression class for a unary operator. +====================================== + +class UnaryExpressionNode(ExpressionNode): + +def **init**\ (self, operator, operand): self.operator = operator +self.operand = operand + +def CodeGen(self): operand = self.operand.CodeGen() function = +g\_llvm\_module.get\_function\_named('unary' + self.operator) return +g\_llvm\_builder.call(function, [operand], 'unop') + +This class represents the "prototype" for a function, which captures its name, +============================================================================== + +and its argument names (thus implicitly the number of arguments the function +============================================================================ + +takes), as well as if it is an operator. +======================================== + +class PrototypeNode(object): + +def **init**\ (self, name, args, is\_operator=False, precedence=0): +self.name = name self.args = args self.is\_operator = is\_operator +self.precedence = precedence + +def IsBinaryOp(self): return self.is\_operator and len(self.args) == 2 + +def GetOperatorName(self): assert self.is\_operator return self.name[-1] + +def CodeGen(self): # Make the function type, eg. double(double,double). +funct\_type = Type.function( Type.double(), [Type.double()] \* +len(self.args), False) + +:: + + function = Function.new(g_llvm_module, funct_type, self.name) + + # If the name conflicted, there was already something with the same name. + # If it has a body, don't allow redefinition or reextern. + if function.name != self.name: + function.delete() + function = g_llvm_module.get_function_named(self.name) + + # If the function already has a body, reject this. + if not function.is_declaration: + raise RuntimeError('Redefinition of function.') + + # If the function took a different number of args, reject. + if len(function.args) != len(self.args): + raise RuntimeError('Redeclaration of a function with different number ' + 'of args.') + + # Set names for all arguments and add them to the variables symbol table. + for arg, arg_name in zip(function.args, self.args): + arg.name = arg_name + # Add arguments to variable symbol table. + g_named_values[arg_name] = arg + + return function + +This class represents a function definition itself. +=================================================== + +class FunctionNode(object): + +def **init**\ (self, prototype, body): self.prototype = prototype +self.body = body + +def CodeGen(self): # Clear scope. g\_named\_values.clear() + +:: + + # Create a function object. + function = self.prototype.CodeGen() + + # If this is a binary operator, install its precedence. + if self.prototype.IsBinaryOp(): + operator = self.prototype.GetOperatorName() + g_binop_precedence[operator] = self.prototype.precedence + + # Create a new basic block to start insertion into. + block = function.append_basic_block('entry') + global g_llvm_builder + g_llvm_builder = Builder.new(block) + + # Finish off the function. + try: + return_value = self.body.CodeGen() + g_llvm_builder.ret(return_value) + + # Validate the generated code, checking for consistency. + function.verify() + + # Optimize the function. + g_llvm_pass_manager.run(function) + except: + function.delete() + if self.prototype.IsBinaryOp(): + del g_binop_precedence[self.prototype.GetOperatorName()] + raise + + return function + +Parser +------ + +class Parser(object): + +def **init**\ (self, tokens): self.tokens = tokens self.Next() + +# Provide a simple token buffer. Parser.current is the current token the +# parser is looking at. Parser.Next() reads another token from the lexer +and # updates Parser.current with its results. def Next(self): +self.current = self.tokens.next() + +# Gets the precedence of the current token, or -1 if the token is not a +binary # operator. def GetCurrentTokenPrecedence(self): if +isinstance(self.current, CharacterToken): return +g\_binop\_precedence.get(self.current.char, -1) else: return -1 + +# identifierexpr ::= identifier \| identifier '(' expression\* ')' def +ParseIdentifierExpr(self): identifier\_name = self.current.name +self.Next() # eat identifier. + +:: + + if self.current != CharacterToken('('): # Simple variable reference. + return VariableExpressionNode(identifier_name) + + # Call. + self.Next() # eat '('. + args = [] + if self.current != CharacterToken(')'): + while True: + args.append(self.ParseExpression()) + if self.current == CharacterToken(')'): + break + elif self.current != CharacterToken(','): + raise RuntimeError('Expected ")" or "," in argument list.') + self.Next() + + self.Next() # eat ')'. + return CallExpressionNode(identifier_name, args) + +# numberexpr ::= number def ParseNumberExpr(self): result = +NumberExpressionNode(self.current.value) self.Next() # consume the +number. return result + +# parenexpr ::= '(' expression ')' def ParseParenExpr(self): self.Next() +# eat '('. + +:: + + contents = self.ParseExpression() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")".') + self.Next() # eat ')'. + + return contents + +# ifexpr ::= 'if' expression 'then' expression 'else' expression def +ParseIfExpr(self): self.Next() # eat the if. + +:: + + # condition. + condition = self.ParseExpression() + + if not isinstance(self.current, ThenToken): + raise RuntimeError('Expected "then".') + self.Next() # eat the then. + + then_branch = self.ParseExpression() + + if not isinstance(self.current, ElseToken): + raise RuntimeError('Expected "else".') + self.Next() # eat the else. + + else_branch = self.ParseExpression() + + return IfExpressionNode(condition, then_branch, else_branch) + +# forexpr ::= 'for' identifier '=' expr ',' expr (',' expr)? 'in' +expression def ParseForExpr(self): self.Next() # eat the for. + +:: + + if not isinstance(self.current, IdentifierToken): + raise RuntimeError('Expected identifier after for.') + + loop_variable = self.current.name + self.Next() # eat the identifier. + + if self.current != CharacterToken('='): + raise RuntimeError('Expected "=" after for variable.') + self.Next() # eat the '='. + + start = self.ParseExpression() + + if self.current != CharacterToken(','): + raise RuntimeError('Expected "," after for start value.') + self.Next() # eat the ','. + + end = self.ParseExpression() + + # The step value is optional. + if self.current == CharacterToken(','): + self.Next() # eat the ','. + step = self.ParseExpression() + else: + step = None + + if not isinstance(self.current, InToken): + raise RuntimeError('Expected "in" after for variable specification.') + self.Next() # eat 'in'. + + body = self.ParseExpression() + + return ForExpressionNode(loop_variable, start, end, step, body) + +# primary ::= identifierexpr \| numberexpr \| parenexpr \| ifexpr \| +forexpr def ParsePrimary(self): if isinstance(self.current, +IdentifierToken): return self.ParseIdentifierExpr() elif +isinstance(self.current, NumberToken): return self.ParseNumberExpr() +elif isinstance(self.current, IfToken): return self.ParseIfExpr() elif +isinstance(self.current, ForToken): return self.ParseForExpr() elif +self.current == CharacterToken('('): return self.ParseParenExpr() else: +raise RuntimeError('Unknown token when expecting an expression.') + +# unary ::= primary \| unary\_operator unary def ParseUnary(self): # If +the current token is not an operator, it must be a primary expression. +if (not isinstance(self.current, CharacterToken) or self.current in +[CharacterToken('('), CharacterToken(',')]): return self.ParsePrimary() + +:: + + # If this is a unary operator, read it. + operator = self.current.char + self.Next() # eat the operator. + return UnaryExpressionNode(operator, self.ParseUnary()) + +# binoprhs ::= (binary\_operator unary)\* def ParseBinOpRHS(self, left, +left\_precedence): # If this is a binary operator, find its precedence. +while True: precedence = self.GetCurrentTokenPrecedence() + +:: + + # If this is a binary operator that binds at least as tightly as the + # current one, consume it; otherwise we are done. + if precedence < left_precedence: + return left + + binary_operator = self.current.char + self.Next() # eat the operator. + + # Parse the unary expression after the binary operator. + right = self.ParseUnary() + + # If binary_operator binds less tightly with right than the operator after + # right, let the pending operator take right as its left. + next_precedence = self.GetCurrentTokenPrecedence() + if precedence < next_precedence: + right = self.ParseBinOpRHS(right, precedence + 1) + + # Merge left/right. + left = BinaryOperatorExpressionNode(binary_operator, left, right) + +# expression ::= unary binoprhs def ParseExpression(self): left = +self.ParseUnary() return self.ParseBinOpRHS(left, 0) + +# prototype # ::= id '(' id\* ')' # ::= binary LETTER number? (id, id) # +::= unary LETTER (id) def ParsePrototype(self): precedence = None if +isinstance(self.current, IdentifierToken): kind = 'normal' +function\_name = self.current.name self.Next() # eat function name. elif +isinstance(self.current, UnaryToken): kind = 'unary' self.Next() # eat +'unary'. if not isinstance(self.current, CharacterToken): raise +RuntimeError('Expected an operator after "unary".') function\_name = +'unary' + self.current.char self.Next() # eat the operator. elif +isinstance(self.current, BinaryToken): kind = 'binary' self.Next() # eat +'binary'. if not isinstance(self.current, CharacterToken): raise +RuntimeError('Expected an operator after "binary".') function\_name = +'binary' + self.current.char self.Next() # eat the operator. if +isinstance(self.current, NumberToken): if not 1 <= self.current.value <= +100: raise RuntimeError('Invalid precedence: must be in range [1, +100].') precedence = self.current.value self.Next() # eat the +precedence. else: raise RuntimeError('Expected function name, "unary" or +"binary" in ' 'prototype.') + +:: + + if self.current != CharacterToken('('): + raise RuntimeError('Expected "(" in prototype.') + self.Next() # eat '('. + + arg_names = [] + while isinstance(self.current, IdentifierToken): + arg_names.append(self.current.name) + self.Next() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")" in prototype.') + + # Success. + self.Next() # eat ')'. + + if kind == 'unary' and len(arg_names) != 1: + raise RuntimeError('Invalid number of arguments for a unary operator.') + elif kind == 'binary' and len(arg_names) != 2: + raise RuntimeError('Invalid number of arguments for a binary operator.') + + return PrototypeNode(function_name, arg_names, kind != 'normal', precedence) + +# definition ::= 'def' prototype expression def ParseDefinition(self): +self.Next() # eat def. proto = self.ParsePrototype() body = +self.ParseExpression() return FunctionNode(proto, body) + +# toplevelexpr ::= expression def ParseTopLevelExpr(self): proto = +PrototypeNode('', []) return FunctionNode(proto, self.ParseExpression()) + +# external ::= 'extern' prototype def ParseExtern(self): self.Next() # +eat extern. return self.ParsePrototype() + +# Top-Level parsing def HandleDefinition(self): +self.Handle(self.ParseDefinition, 'Read a function definition:') + +def HandleExtern(self): self.Handle(self.ParseExtern, 'Read an extern:') + +def HandleTopLevelExpression(self): try: function = +self.ParseTopLevelExpr().CodeGen() result = +g\_llvm\_executor.run\_function(function, []) print 'Evaluated to:', +result.as\_real(Type.double()) except Exception, e: print 'Error:', e +try: self.Next() # Skip for error recovery. except: pass + +def Handle(self, function, message): try: print message, +function().CodeGen() except Exception, e: print 'Error:', e try: +self.Next() # Skip for error recovery. except: pass + +Main driver code. +----------------- + +def main(): # Set up the optimizer pipeline. Start with registering info +about how the # target lays out data structures. +g\_llvm\_pass\_manager.add(g\_llvm\_executor.target\_data) # Do simple +"peephole" optimizations and bit-twiddling optzns. +g\_llvm\_pass\_manager.add(PASS\_INSTRUCTION\_COMBINING) # Reassociate +expressions. g\_llvm\_pass\_manager.add(PASS\_REASSOCIATE) # Eliminate +Common SubExpressions. g\_llvm\_pass\_manager.add(PASS\_GVN) # Simplify +the control flow graph (deleting unreachable blocks, etc). +g\_llvm\_pass\_manager.add(PASS\_CFG\_SIMPLIFICATION) + +g\_llvm\_pass\_manager.initialize() + +# Install standard binary operators. # 1 is lowest possible precedence. +40 is the highest. g\_binop\_precedence['<'] = 10 +g\_binop\_precedence['+'] = 20 g\_binop\_precedence['-'] = 20 +g\_binop\_precedence['\*'] = 40 + +# Run the main "interpreter loop". while True: print 'ready>', try: raw += raw\_input() except KeyboardInterrupt: break + +:: + + parser = Parser(Tokenize(raw)) + while True: + # top ::= definition | external | expression | EOF + if isinstance(parser.current, EOFToken): + break + if isinstance(parser.current, DefToken): + parser.HandleDefinition() + elif isinstance(parser.current, ExternToken): + parser.HandleExtern() + else: + parser.HandleTopLevelExpression() + +# Print out all of the generated code. print '', g\_llvm\_module + +if **name** == '**main**\ ': main() {% endhighlight %} + +-------------- + +**`Next: Extending the language: mutable variables / SSA +construction `_** diff --git a/docs/source/doc/kaleidoscope/PythonLangImpl7.md b/docs/source/doc/kaleidoscope/PythonLangImpl7.md deleted file mode 100644 index 5603ee4..0000000 --- a/docs/source/doc/kaleidoscope/PythonLangImpl7.md +++ /dev/null @@ -1,1794 +0,0 @@ ---- -layout: page -title: "Kaleidoscope: Chapter 7" ---- - -# Extending the Language: Mutable Variables / SSA construction - -Written by [Chris Lattner](mailto:sabre@nondot.org) -and [Max Shawabkeh](http://max99x.com) - - -**Chapter 7** - - -* This will become a table of contents (this text will be scraped). -{:toc} - - -**[Chapter 8: Conclusion and other useful LLVM tidbits](PythonLangImpl8.html)** - - -# Introduction # {#intro} - -Welcome to Chapter 7 of the -[Implementing a language with LLVM](http://www.llvm.org/docs/tutorial/index.html) -tutorial. In chapters 1 through 6, we've built a very -respectable, albeit simple, -[functional programming language](http://en.wikipedia.org/wiki/Functional_programming). -In our journey, we learned some parsing techniques, -how to build and represent an AST, how to build LLVM IR, and how to optimize -the resultant code as well as JIT compile it. - -While Kaleidoscope is interesting as a functional language, the fact that it -is functional makes it "too easy" to generate LLVM IR for it. In particular, a -functional language makes it very easy to build LLVM IR directly in -[SSA form](http://en.wikipedia.org/wiki/Static_single_assignment_form). -Since LLVM requires that the input code be in SSA form, this is a very nice -property and it is often unclear to newcomers how to generate code for an -imperative language with mutable variables. - -The short (and happy) summary of this chapter is that there is no need for -your front-end to build SSA form: LLVM provides highly tuned and well tested -support for this, though the way it works is a bit unexpected for some. - - -# Why is this a hard problem? # {#why} - -To understand why mutable variables cause complexities in SSA construction, -consider this extremely simple C example: - - - -{% highlight python %} -int G, H; -int test(_Bool Condition) { - int X; - if (Condition) - X = G; - else - X = H; - return X; -} -{% endhighlight %} - - -In this case, we have the variable "X", whose value depends on the path -executed in the program. Because there are two different possible values for X -before the return instruction, a PHI node is inserted to merge the two values. -The LLVM IR that we want for this example looks like this: - - -{% highlight llvm %} -@G = weak global i32 0 ; type of @G is i32* -@H = weak global i32 0 ; type of @H is i32* -define i32 @test(i1 %Condition) { -entry: - br i1 %Condition, label %cond_true, label %cond_false -cond_true: - %X.0 = load i32* @G - br label %cond_next -cond_false: - %X.1 = load i32* @H - br label %cond_next -cond_next: - %X.2 = phi i32 [ %X.1, %cond_false ], [ %X.0, %cond_true ] - ret i32 %X.2 -} -{% endhighlight %} - - -In this example, the loads from the G and H global variables are explicit in -the LLVM IR, and they live in the then/else branches of the if statement -(cond_true/cond_false). In order to merge the incoming values, the X.2 phi node -in the cond_next block selects the right value to use based on where control -flow is coming from: if control flow comes from the cond_false block, X.2 gets -the value of X.1. Alternatively, if control flow comes from cond_true, it gets -the value of X.0. The intent of this chapter is not to explain the details of -SSA form. For more information, see one of the many -[online references](http://en.wikipedia.org/wiki/Static_single_assignment_form). - -The question for this article is "who places the phi nodes when lowering -assignments to mutable variables?". The issue here is that LLVM -*requires* that its IR be in SSA form: there is no "non-ssa" mode for it. -However, SSA construction requires non-trivial algorithms and data structures, -so it is inconvenient and wasteful for every front-end to have to reproduce this -logic. - -# Memory in LLVM # {#memory} - -The 'trick' here is that while LLVM does require all register values to be -in SSA form, it does not require (or permit) memory objects to be in SSA form. -In the example above, note that the loads from G and H are direct accesses to -G and H: they are not renamed or versioned. This differs from some other -compiler systems, which do try to version memory objects. In LLVM, instead of -encoding dataflow analysis of memory into the LLVM IR, it is handled with -[Analysis Passes](http://www.llvm.org/docs/WritingAnLLVMPass.html) -which are computed on demand. - - -With this in mind, the high-level idea is that we want to make a stack variable -(which lives in memory, because it is on the stack) for each mutable object in -a function. To take advantage of this trick, we need to talk about how LLVM -represents stack variables. - - -In LLVM, all memory accesses are explicit with load/store instructions, and -it is carefully designed not to have (or need) an "address-of" operator. -Notice how the type of the @G/@H global variables is actually "i32*" even though -the variable is defined as "i32". What this means is that @G defines -*space* for an i32 in the global data area, but its *name* -actually refers to the address for that space. Stack variables work the same -way, except that instead of being declared with global variable definitions, -they are declared with the -[LLVM alloca instruction](http://www.llvm.org/docs/LangRef.html#i_alloca): - - -{% highlight python %} -define i32 @example() { -entry: - %X = alloca i32 ; type of %X is i32*. - ... - %tmp = load i32* %X ; load the stack value %X from the stack. - %tmp2 = add i32 %tmp, 1 ; increment it - store i32 %tmp2, i32* %X ; store it back - ... -{% endhighlight %} - - -This code shows an example of how you can declare and manipulate a stack -variable in the LLVM IR. Stack memory allocated with the alloca instruction is -fully general: you can pass the address of the stack slot to functions, you can -store it in other variables, etc. In our example above, we could rewrite the -example to use the alloca technique to avoid using a PHI node: - - -{% highlight llvm %} -@G = weak global i32 0 ; type of @G is i32* -@H = weak global i32 0 ; type of @H is i32* -define i32 @test(i1 %Condition) { -entry: - %X = alloca i32 ; type of %X is i32*. - br i1 %Condition, label %cond_true, label %cond_false -cond_true: - %X.0 = load i32* @G - store i32 %X.0, i32* %X ; Update X - br label %cond_next -cond_false: - %X.1 = load i32* @H - store i32 %X.1, i32* %X ; Update X - br label %cond_next -cond_next: - %X.2 = load i32* %X ; Read X - ret i32 %X.2 -} -{% endhighlight %} - - -With this, we have discovered a way to handle arbitrary mutable variables -without the need to create Phi nodes at all: - -
    -
  1. Each mutable variable becomes a stack allocation.
  2. -
  3. Each read of the variable becomes a load from the stack.
  4. -
  5. Each update of the variable becomes a store to the stack.
  6. -
  7. Taking the address of a variable just uses the stack address directly.
  8. -
- -While this solution has solved our immediate problem, it introduced another -one: we have now apparently introduced a lot of stack traffic for very simple -and common operations, a major performance problem. Fortunately for us, the -LLVM optimizer has a highly-tuned optimization pass named "mem2reg" that handles -this case, promoting allocas like this into SSA registers, inserting Phi nodes -as appropriate. If you run this example through the pass, for example, you'll -get: - -{% highlight bash %} -$ llvm-as < example.ll | opt -mem2reg | llvm-dis -{% endhighlight %} - -{% highlight llvm %} -@G = weak global i32 0 -@H = weak global i32 0 -define i32 @test(i1 %Condition) { -entry: - br i1 %Condition, label %cond_true, label %cond_false -cond_true: - %X.0 = load i32* @G - br label %cond_next -cond_false: - %X.1 = load i32* @H - br label %cond_next -cond_next: - %X.01 = phi i32 [ %X.1, %cond_false ], [ %X.0, %cond_true ] - ret i32 %X.01 -} -{% endhighlight %} - -The mem2reg pass implements the standard "iterated dominance frontier" -algorithm for constructing SSA form and has a number of optimizations that speed -up (very common) degenerate cases. The mem2reg optimization pass is the answer -to dealing with mutable variables, and we highly recommend that you depend on -it. Note that mem2reg only works on variables in certain circumstances: - -* mem2reg is alloca-driven: it looks for allocas and if it can handle them, it - promotes them. It does not apply to global variables or heap allocations. - -* mem2reg only looks for alloca instructions in the entry block of the - function. Being in the entry block guarantees that the alloca is only - executed once, which makes analysis simpler. - -* mem2reg only promotes allocas whose uses are direct loads and stores. If - the address of the stack object is passed to a function, or if any funny - pointer arithmetic is involved, the alloca will not be promoted. - -* mem2reg only works on allocas of - [first class](http://www.llvm.org/docs/LangRef.html#t_classifications) - values (such as pointers, scalars and vectors), and only if the array size - of the allocation is 1 (or missing in the .ll file). mem2reg is not capable - of promoting structs or arrays to registers. Note that the "scalarrepl" pass - is more powerful and can promote structs, "unions", and arrays in many cases. - - -All of these properties are easy to satisfy for most imperative languages, and -we'll illustrate it below with Kaleidoscope. The final question you may be -asking is: should I bother with this nonsense for my front-end? Wouldn't it be -better if I just did SSA construction directly, avoiding use of the mem2reg -optimization pass? In short, we strongly recommend that you use this technique -for building SSA form, unless there is an extremely good reason not to. Using -this technique is: - -* Proven and well tested: llvm-gcc and clang both use this technique for local - mutable variables. As such, the most common clients of LLVM are using this to - handle a bulk of their variables. You can be sure that bugs are found fast - and fixed early. - -* Extremely Fast: mem2reg has a number of special cases that make it fast in - common cases as well as fully general. For example, it has fast-paths for - variables that are only used in a single block, variables that only have one - assignment point, good heuristics to avoid insertion of unneeded phi nodes, etc. - - -* Needed for debug info generation: - [Debug information in LLVM](http://www.llvm.org/docs/SourceLevelDebugging.html) - relies on having the address of the variable exposed so that debug - info can be attached to it. This technique dovetails very naturally with this - style of debug info. - - -If nothing else, this makes it much easier to get your front-end up and -running, and is very simple to implement. Lets extend Kaleidoscope with mutable -variables now! - - -* * * - -# Mutable Variables in Kaleidoscope # {#kalvars} - -Now that we know the sort of problem we want to tackle, lets see what this -looks like in the context of our little Kaleidoscope language. We're going to -add two features: - -* The ability to mutate variables with the '=' operator. -* The ability to define new variables. - -While the first item is really what this is about, we only have variables -for incoming arguments as well as for induction variables, and redefining those -only goes so far :). Also, the ability to define new variables is a -useful thing regardless of whether you will be mutating them. Here's a -motivating example that shows how we could use these: - - -{% highlight python %} -# Define ':' for sequencing: as a low-precedence operator that ignores operands -# and just returns the RHS. -def binary : 1 (x y) y; - -# Recursive fib, we could do this before. -def fib(x) - if (x < 3) then - 1 - else - fib(x-1) + fib(x-2) - -# Iterative fib. -def fibi(x) - var a = 1, b = 1, c in - (for i = 3, i < x in - c = a + b : - a = b : - b = c) : - b - -# Call it. -fibi(10) -{% endhighlight %} - - - -In order to mutate variables, we have to change our existing variables to use -the "alloca trick". Once we have that, we'll add our new operator, then extend -Kaleidoscope to support new variable definitions. - - -* * * - -# Adjusting Existing Variables for Mutation # {#adjustments} - -The symbol table in Kaleidoscope is managed at code generation time by the -`g_named_values` map. This map currently keeps track of the LLVM -"Value" that holds the double value for the named variable. In order to support -mutation, we need to change this slightly, so that it holds the *memory -location* of the variable in question. Note that this change is a -refactoring: it changes the structure of the code, but does not (by itself) -change the behavior of the compiler. All of these changes are isolated in the -Kaleidoscope code generator. - - -At this point in Kaleidoscope's development, it only supports variables for two -things: incoming arguments to functions and the induction variable of 'for' -loops. For consistency, we'll allow mutation of these variables in addition to -other user-defined variables. This means that these will both need memory -locations. - - -To start our transformation of Kaleidoscope, we will need to create the -allocas that we will store in `g_named_values`. We'll use a helper -function that ensures that the allocas are created in the entry block of the -function: - - -{% highlight python %} -# Creates an alloca instruction in the entry block of the function. This is used -# for mutable variables. -def CreateEntryBlockAlloca(function, var_name): - entry = function.get_entry_basic_block() - builder = Builder.new(entry) - builder.position_at_beginning(entry) - return builder.alloca(Type.double(), var_name) -{% endhighlight %} - - -This code creates a temporary `llvm.core.Builder` that is pointing at -the first instruction of the entry block. It then creates an alloca with the -expected name and returns it. Because all values in Kaleidoscope are doubles, -there is no need to pass in a type to use. - -With this in place, the first functionality change we want to make is to -variable references. In our new scheme, variables live on the stack, so code -generating a reference to them actually needs to produce a load from the stack -slot: - - -{% highlight python %} - def CodeGen(self): - if self.name in g_named_values: - return g_llvm_builder.load(g_named_values[self.name], self.name) - else: - raise RuntimeError('Unknown variable name: ' + self.name) -{% endhighlight %} - - -As you can see, this is pretty straightforward. Now we need to update the -things that define the variables to set up the alloca. We'll start with -`ForExpressionNode.CodeGen` (see the [full code listing](#code) for the -unabridged code): - - -{% highlight python %} - def CodeGen(self): - function = g_llvm_builder.basic_block.function - - # Create an alloca for the variable in the entry block. - alloca = CreateEntryBlockAlloca(function, self.loop_variable) - - # Emit the start code first, without 'variable' in scope. - start_value = self.start.CodeGen() - - # Store the value into the alloca. - g_llvm_builder.store(start_value, alloca) - ... - # Compute the end condition. - end_condition = self.end.CodeGen() - - # Reload, increment, and restore the alloca. This handles the case where - # the body of the loop mutates the variable. - cur_value = g_llvm_builder.load(alloca, self.loop_variable) - next_value = g_llvm_builder.fadd(cur_value, step_value, 'nextvar') - g_llvm_builder.store(next_value, alloca) - - # Convert condition to a bool by comparing equal to 0.0. - end_condition_bool = g_llvm_builder.fcmp( - FCMP_ONE, end_condition, Constant.real(Type.double(), 0), 'loopcond') - ... -{% endhighlight %} - - -This code is virtually identical to the code -[before we allowed mutable variables](PythonLangImpl5.html#forcodegen). -The big difference is that we no longer have to construct a PHI node, and we use -load/store to access the variable as needed. - -To support mutable argument variables, we need to also make allocas for them. -The code for this is also pretty simple: - - -{% highlight python %} -class PrototypeNode(object): - ... - # Create an alloca for each argument and register the argument in the symbol - # table so that references to it will succeed. - def CreateArgumentAllocas(self, function): - for arg_name, arg in zip(self.args, function.args): - alloca = CreateEntryBlockAlloca(function, arg_name) - g_llvm_builder.store(arg, alloca) - g_named_values[arg_name] = alloca -{% endhighlight %} - - -For each argument, we make an alloca, store the input value to the function -into the alloca, and register the alloca as the memory location for the -argument. This method gets invoked by `FunctionNode.CodeGen` right after -it sets up the entry block for the function. - -The final missing piece is adding the mem2reg pass, which allows us to get -good codegen once again: - - -{% highlight python %} -from llvm.passes import (PASS_PROMOTE_MEMORY_TO_REGISTER, - PASS_INSTRUCTION_COMBINING, - PASS_REASSOCIATE, - PASS_GVN, - PASS_CFG_SIMPLIFICATION) -... -def main(): - # Set up the optimizer pipeline. Start with registering info about how the - # target lays out data structures. - g_llvm_pass_manager.add(g_llvm_executor.target_data) - # Promote allocas to registers. - g_llvm_pass_manager.add(PASS_PROMOTE_MEMORY_TO_REGISTER) - # Do simple "peephole" optimizations and bit-twiddling optzns. - g_llvm_pass_manager.add(PASS_INSTRUCTION_COMBINING) - # Reassociate expressions. - g_llvm_pass_manager.add(PASS_REASSOCIATE) -{% endhighlight %} - - -It is interesting to see what the code looks like before and after the -mem2reg optimization runs. For example, this is the before/after code for our -recursive fib function. Before the optimization: - - -{% highlight llvm %} -define double @fib(double %x) { -entry: - %x1 = alloca double - store double %x, double* %x1 - %x2 = load double* %x1 - %cmptmp = fcmp ult double %x2, 3.000000e+00 - %booltmp = uitofp i1 %cmptmp to double - %ifcond = fcmp one double %booltmp, 0.000000e+00 - br i1 %ifcond, label %then, label %else -then: ; preds = %entry - br label %ifcont -else: ; preds = %entry - %x3 = load double* %x1 - %subtmp = fsub double %x3, 1.000000e+00 - %calltmp = call double @fib(double %subtmp) - %x4 = load double* %x1 - %subtmp5 = fsub double %x4, 2.000000e+00 - %calltmp6 = call double @fib(double %subtmp5) - %addtmp = fadd double %calltmp, %calltmp6 - br label %ifcont -ifcont: ; preds = %else, %then - %iftmp = phi double [ 1.000000e+00, %then ], [ %addtmp, %else ] - ret double %iftmp -} -{% endhighlight %} - - -Here there is only one variable (x, the input argument) but you can still -see the extremely simple-minded code generation strategy we are using. In the -entry block, an alloca is created, and the initial input value is stored into -it. Each reference to the variable does a reload from the stack. Also, note -that we didn't modify the if/then/else expression, so it still inserts a PHI -node. While we could make an alloca for it, it is actually easier to create a -PHI node for it, so we still just make the PHI. - -Here is the code after the mem2reg pass runs: - - -{% highlight llvm %} -define double @fib(double %x) { -entry: - %cmptmp = fcmp ult double %x, 3.000000e+00 - %booltmp = uitofp i1 %cmptmp to double - %ifcond = fcmp one double %booltmp, 0.000000e+00 - br i1 %ifcond, label %then, label %else -then: - br label %ifcont -else: - %subtmp = fsub double %x, 1.000000e+00 - %calltmp = call double @fib(double %subtmp) - %subtmp5 = fsub double %x, 2.000000e+00 - %calltmp6 = call double @fib(double %subtmp5) - %addtmp = fadd double %calltmp, %calltmp6 - br label %ifcont -ifcont: ; preds = %else, %then - %iftmp = phi double [ 1.000000e+00, %then ], [ %addtmp, %else ] - ret double %iftmp -} -{% endhighlight %} - - -This is a trivial case for mem2reg, since there are no redefinitions of the -variable. The point of showing this is to calm your tension about inserting -such blatent inefficiencies :). - -After the rest of the optimizers run, we get: - - -{% highlight llvm %} -define double @fib(double %x) { -entry: - %cmptmp = fcmp ult double %x, 3.000000e+00 - %booltmp = uitofp i1 %cmptmp to double - %ifcond = fcmp ueq double %booltmp, 0.000000e+00 - br i1 %ifcond, label %else, label %ifcont -else: - %subtmp = fsub double %x, 1.000000e+00 - %calltmp = call double @fib(double %subtmp) - %subtmp5 = fsub double %x, 2.000000e+00 - %calltmp6 = call double @fib(double %subtmp5) - %addtmp = fadd double %calltmp, %calltmp6 - ret double %addtmp -ifcont: - ret double 1.000000e+00 -} -{% endhighlight %} - - -Here we see that the simplifycfg pass decided to clone the return instruction -into the end of the 'else' block. This allowed it to eliminate some branches -and the PHI node. - -Now that all symbol table references are updated to use stack variables, -we'll add the assignment operator. - - -* * * - -# New Assignment Operator # {#assignment} - -With our current framework, adding a new assignment operator is really -simple. We will parse it just like any other binary operator, but handle it -internally (instead of allowing the user to define it). The first step is to -set a precedence: - - -{% highlight python %} -def main(): - ... - # Install standard binary operators. - # 1 is lowest possible precedence. 40 is the highest. - g_binop_precedence['='] = 2 - g_binop_precedence['<'] = 10 - g_binop_precedence['+'] = 20 - g_binop_precedence['-'] = 20 -{% endhighlight %} - - -Now that the parser knows the precedence of the binary operator, it takes -care of all the parsing and AST generation. We just need to implement codegen -for the assignment operator. This looks like: - - -{% highlight python %} -class BinaryOperatorExpressionNode(ExpressionNode): - ... - def CodeGen(self): - # A special case for '=' because we don't want to emit the LHS as an - # expression. - if self.operator == '=': - # Assignment requires the LHS to be an identifier. - if not isinstance(self.left, VariableExpressionNode): - raise RuntimeError('Destination of "=" must be a variable.') -{% endhighlight %} - - -Unlike the rest of the binary operators, our assignment operator doesn't -follow the "emit LHS, emit RHS, do computation" model. As such, it is handled -as a special case before the other binary operators are handled. The other -strange thing is that it requires the LHS to be a variable. It is invalid to -have `(x+1) = expr` -- only things like `x = expr` are allowed. - - -{% highlight python %} - # Codegen the RHS. - value = self.right.CodeGen() - - # Look up the name. - variable = g_named_values[self.left.name] - - # Store the value and return it. - g_llvm_builder.store(value, variable) - - return value - ... -{% endhighlight %} - - -Once we have the variable, CodeGening the assignment is straightforward: -we emit the RHS of the assignment, create a store, and return the computed -value. Returning a value allows for chained assignments like `X = (Y = Z)`. - -Now that we have an assignment operator, we can mutate loop variables and -arguments. For example, we can now run code like this: - - -{% highlight python %} -# Function to print a double. -extern printd(x) - -# Define ':' for sequencing: as a low-precedence operator that ignores operands -# and just returns the RHS. -def binary : 1 (x y) y - -def test(x) - printd(x) : - x = 4 : - printd(x) - -test(123) -{% endhighlight %} - - -When run, this example prints "123" and then "4", showing that we did -actually mutate the value! Okay, we have now officially implemented our goal: -getting this to work requires SSA construction in the general case. However, -to be really useful, we want the ability to define our own local variables. -Let's add this next! - - -* * * - -# User-defined Local Variables # {#localvars} - -Adding var/in is just like any other other extensions we made to -Kaleidoscope: we extend the lexer, the parser, the AST and the code generator. -The first step for adding our new 'var/in' construct is to extend the lexer. -As before, this is pretty trivial, the code looks like this: - - -{% highlight python %} -... -class UnaryToken(object): pass -class VarToken(object): pass -... -def Tokenize(string): - ... - elif identifier == 'unary': - yield UnaryToken() - elif identifier == 'var': - yield VarToken() - else: - yield IdentifierToken(identifier) -{% endhighlight %} - - -The next step is to define the AST node that we will construct. For var/in, -it looks like this: - - -{% highlight python %} -# Expression class for var/in. -class VarExpressionNode(ExpressionNode): - - def __init__(self, variables, body): - self.variables = variables - self.body = body - - def CodeGen(self): - ... -{% endhighlight %} - - -var/in allows a list of names to be defined all at once, and each name can -optionally have an initializer value. As such, we capture this information in -the variables list. Also, var/in has a body, this body is allowed to access -the variables defined by the var/in. - -With this in place, we can define the parser pieces. The first thing we do -is add it as a primary expression: - - -{% highlight python %} - # primary ::= - # dentifierexpr | numberexpr | parenexpr | ifexpr | forexpr | varexpr - def ParsePrimary(self): - if isinstance(self.current, IdentifierToken): - return self.ParseIdentifierExpr() - elif isinstance(self.current, NumberToken): - return self.ParseNumberExpr() - elif isinstance(self.current, IfToken): - return self.ParseIfExpr() - elif isinstance(self.current, ForToken): - return self.ParseForExpr() - elif isinstance(self.current, VarToken): - return self.ParseVarExpr() - elif self.current == CharacterToken('('): - return self.ParseParenExpr() - else: - raise RuntimeError('Unknown token when expecting an expression.') -{% endhighlight %} - - -Next we define ParseVarExpr: - - -{% highlight python %} - # varexpr ::= 'var' (identifier ('=' expression)?)+ 'in' expression - def ParseVarExpr(self): - self.Next() # eat 'var'. - - variables = {} - - # At least one variable name is required. - if not isinstance(self.current, IdentifierToken): - raise RuntimeError('Expected identifier after "var".') -{% endhighlight %} - - -The first part of this code parses the list of identifier/expr pairs into the -local `variables` list. - - -{% highlight python %} - while True: - var_name = self.current.name - self.Next() # eat the identifier. - - # Read the optional initializer. - if self.current == CharacterToken('='): - self.Next() # eat '='. - variables[var_name] = self.ParseExpression() - else: - variables[var_name] = None - - # End of var list, exit loop. - if self.current != CharacterToken(','): - break - self.Next() # eat ','. - - if not isinstance(self.current, IdentifierToken): - raise RuntimeError('Expected identifier after "," in a var expression.') -{% endhighlight %} - - -Once all the variables are parsed, we then parse the body and create the -AST node: - - -{% highlight python %} - # At this point, we have to have 'in'. - if not isinstance(self.current, InToken): - raise RuntimeError('Expected "in" keyword after "var".') - self.Next() # eat 'in'. - - body = self.ParseExpression() - - return VarExpressionNode(variables, body) -{% endhighlight %} - - -Now that we can parse and represent the code, we need to support emission of -LLVM IR for it. This code starts out with: - - -{% highlight python %} -class VarExpressionNode(ExpressionNode): - ... - def CodeGen(self): - old_bindings = {} - function = g_llvm_builder.basic_block.function - - # Register all variables and emit their initializer. - for var_name, var_expression in self.variables.iteritems(): - # Emit the initializer before adding the variable to scope, this prevents - # the initializer from referencing the variable itself, and permits stuff - # like this: - # var a = 1 in - # var a = a in ... # refers to outer 'a'. - if var_expression is not None: - var_value = var_expression.CodeGen() - else: - var_value = Constant.real(Type.double(), 0) - - alloca = CreateEntryBlockAlloca(function, var_name) - g_llvm_builder.store(var_value, alloca) - - # Remember the old variable binding so that we can restore the binding - # when we unrecurse. - old_bindings[var_name] = g_named_values.get(var_name, None) - - # Remember this binding. - g_named_values[var_name] = alloca -{% endhighlight %} - - -Basically it loops over all the variables, installing them one at a time. -For each variable we put into the symbol table, we remember the previous value -that we replace in `old_bindings`. - -There are more comments here than code. The basic idea is that we emit the -initializer, create the alloca, then update the symbol table to point to it. -Once all the variables are installed in the symbol table, we evaluate the body -of the var/in expression: - - -{% highlight python %} - # Codegen the body, now that all vars are in scope. - body = self.body.CodeGen() -{% endhighlight %} - - -Finally, before returning, we restore the previous variable bindings: - - -{% highlight python %} - # Pop all our variables from scope. - for var_name in self.variables: - if old_bindings[var_name] is not None: - g_named_values[var_name] = old_bindings[var_name] - else: - del g_named_values[var_name] - - # Return the body computation. - return body -{% endhighlight %} - - -The end result of all of this is that we get properly scoped variable -definitions, and we even (trivially) allow mutation of them :). - -With this, we completed what we set out to do. Our nice iterative fib -example from the intro compiles and runs just fine. The mem2reg pass optimizes -all of our stack variables into SSA registers, inserting PHI nodes where needed, -and our front-end remains simple: no "iterated dominance frontier" computation -anywhere in sight. - -* * * - -# Full Code Listing # {#code} - -Here is the complete code listing for our running example, enhanced with mutable -variables and var/in support: - - -{% highlight python %} -#!/usr/bin/env python - -import re -from llvm.core import Module, Constant, Type, Function, Builder -from llvm.ee import ExecutionEngine, TargetData -from llvm.passes import FunctionPassManager - -from llvm.core import FCMP_ULT, FCMP_ONE -from llvm.passes import (PASS_PROMOTE_MEMORY_TO_REGISTER, - PASS_INSTRUCTION_COMBINING, - PASS_REASSOCIATE, - PASS_GVN, - PASS_CFG_SIMPLIFICATION) - -################################################################################ -## Globals -################################################################################ - -# The LLVM module, which holds all the IR code. -g_llvm_module = Module.new('my cool jit') - -# The LLVM instruction builder. Created whenever a new function is entered. -g_llvm_builder = None - -# A dictionary that keeps track of which values are defined in the current scope -# and what their LLVM representation is. -g_named_values = {} - -# The function optimization passes manager. -g_llvm_pass_manager = FunctionPassManager.new(g_llvm_module) - -# The LLVM execution engine. -g_llvm_executor = ExecutionEngine.new(g_llvm_module) - -# The binary operator precedence chart. -g_binop_precedence = {} - -# Creates an alloca instruction in the entry block of the function. This is used -# for mutable variables. -def CreateEntryBlockAlloca(function, var_name): - entry = function.get_entry_basic_block() - builder = Builder.new(entry) - builder.position_at_beginning(entry) - return builder.alloca(Type.double(), var_name) - -################################################################################ -## Lexer -################################################################################ - -# The lexer yields one of these types for each token. -class EOFToken(object): pass -class DefToken(object): pass -class ExternToken(object): pass -class IfToken(object): pass -class ThenToken(object): pass -class ElseToken(object): pass -class ForToken(object): pass -class InToken(object): pass -class BinaryToken(object): pass -class UnaryToken(object): pass -class VarToken(object): pass - -class IdentifierToken(object): - def __init__(self, name): self.name = name - -class NumberToken(object): - def __init__(self, value): self.value = value - -class CharacterToken(object): - def __init__(self, char): self.char = char - def __eq__(self, other): - return isinstance(other, CharacterToken) and self.char == other.char - def __ne__(self, other): return not self == other - -# Regular expressions that tokens and comments of our language. -REGEX_NUMBER = re.compile('[0-9]+(?:\.[0-9]+)?') -REGEX_IDENTIFIER = re.compile('[a-zA-Z][a-zA-Z0-9]*') -REGEX_COMMENT = re.compile('#.*') - -def Tokenize(string): - while string: - # Skip whitespace. - if string[0].isspace(): - string = string[1:] - continue - - # Run regexes. - comment_match = REGEX_COMMENT.match(string) - number_match = REGEX_NUMBER.match(string) - identifier_match = REGEX_IDENTIFIER.match(string) - - # Check if any of the regexes matched and yield the appropriate result. - if comment_match: - comment = comment_match.group(0) - string = string[len(comment):] - elif number_match: - number = number_match.group(0) - yield NumberToken(float(number)) - string = string[len(number):] - elif identifier_match: - identifier = identifier_match.group(0) - # Check if we matched a keyword. - if identifier == 'def': - yield DefToken() - elif identifier == 'extern': - yield ExternToken() - elif identifier == 'if': - yield IfToken() - elif identifier == 'then': - yield ThenToken() - elif identifier == 'else': - yield ElseToken() - elif identifier == 'for': - yield ForToken() - elif identifier == 'in': - yield InToken() - elif identifier == 'binary': - yield BinaryToken() - elif identifier == 'unary': - yield UnaryToken() - elif identifier == 'var': - yield VarToken() - else: - yield IdentifierToken(identifier) - string = string[len(identifier):] - else: - # Yield the ASCII value of the unknown character. - yield CharacterToken(string[0]) - string = string[1:] - - yield EOFToken() - -################################################################################ -## Abstract Syntax Tree (aka Parse Tree) -################################################################################ - -# Base class for all expression nodes. -class ExpressionNode(object): - pass - -# Expression class for numeric literals like "1.0". -class NumberExpressionNode(ExpressionNode): - - def __init__(self, value): - self.value = value - - def CodeGen(self): - return Constant.real(Type.double(), self.value) - -# Expression class for referencing a variable, like "a". -class VariableExpressionNode(ExpressionNode): - - def __init__(self, name): - self.name = name - - def CodeGen(self): - if self.name in g_named_values: - return g_llvm_builder.load(g_named_values[self.name], self.name) - else: - raise RuntimeError('Unknown variable name: ' + self.name) - -# Expression class for a binary operator. -class BinaryOperatorExpressionNode(ExpressionNode): - - def __init__(self, operator, left, right): - self.operator = operator - self.left = left - self.right = right - - def CodeGen(self): - # A special case for '=' because we don't want to emit the LHS as an - # expression. - if self.operator == '=': - # Assignment requires the LHS to be an identifier. - if not isinstance(self.left, VariableExpressionNode): - raise RuntimeError('Destination of "=" must be a variable.') - - # Codegen the RHS. - value = self.right.CodeGen() - - # Look up the name. - variable = g_named_values[self.left.name] - - # Store the value and return it. - g_llvm_builder.store(value, variable) - - return value - - left = self.left.CodeGen() - right = self.right.CodeGen() - - if self.operator == '+': - return g_llvm_builder.fadd(left, right, 'addtmp') - elif self.operator == '-': - return g_llvm_builder.fsub(left, right, 'subtmp') - elif self.operator == '*': - return g_llvm_builder.fmul(left, right, 'multmp') - elif self.operator == '<': - result = g_llvm_builder.fcmp(FCMP_ULT, left, right, 'cmptmp') - # Convert bool 0 or 1 to double 0.0 or 1.0. - return g_llvm_builder.uitofp(result, Type.double(), 'booltmp') - else: - function = g_llvm_module.get_function_named('binary' + self.operator) - return g_llvm_builder.call(function, [left, right], 'binop') - -# Expression class for function calls. -class CallExpressionNode(ExpressionNode): - - def __init__(self, callee, args): - self.callee = callee - self.args = args - - def CodeGen(self): - # Look up the name in the global module table. - callee = g_llvm_module.get_function_named(self.callee) - - # Check for argument mismatch error. - if len(callee.args) != len(self.args): - raise RuntimeError('Incorrect number of arguments passed.') - - arg_values = [i.CodeGen() for i in self.args] - - return g_llvm_builder.call(callee, arg_values, 'calltmp') - -# Expression class for if/then/else. -class IfExpressionNode(ExpressionNode): - - def __init__(self, condition, then_branch, else_branch): - self.condition = condition - self.then_branch = then_branch - self.else_branch = else_branch - - def CodeGen(self): - condition = self.condition.CodeGen() - - # Convert condition to a bool by comparing equal to 0.0. - condition_bool = g_llvm_builder.fcmp( - FCMP_ONE, condition, Constant.real(Type.double(), 0), 'ifcond') - - function = g_llvm_builder.basic_block.function - - # Create blocks for the then and else cases. Insert the 'then' block at the - # end of the function. - then_block = function.append_basic_block('then') - else_block = function.append_basic_block('else') - merge_block = function.append_basic_block('ifcond') - - g_llvm_builder.cbranch(condition_bool, then_block, else_block) - - # Emit then value. - g_llvm_builder.position_at_end(then_block) - then_value = self.then_branch.CodeGen() - g_llvm_builder.branch(merge_block) - - # Codegen of 'Then' can change the current block; update then_block for the - # PHI node. - then_block = g_llvm_builder.basic_block - - # Emit else block. - g_llvm_builder.position_at_end(else_block) - else_value = self.else_branch.CodeGen() - g_llvm_builder.branch(merge_block) - - # Codegen of 'Else' can change the current block, update else_block for the - # PHI node. - else_block = g_llvm_builder.basic_block - - # Emit merge block. - g_llvm_builder.position_at_end(merge_block) - phi = g_llvm_builder.phi(Type.double(), 'iftmp') - phi.add_incoming(then_value, then_block) - phi.add_incoming(else_value, else_block) - - return phi - -# Expression class for for/in. -class ForExpressionNode(ExpressionNode): - - def __init__(self, loop_variable, start, end, step, body): - self.loop_variable = loop_variable - self.start = start - self.end = end - self.step = step - self.body = body - - def CodeGen(self): - # Output this as: - # var = alloca double - # ... - # start = startexpr - # store start -> var - # goto loop - # loop: - # ... - # bodyexpr - # ... - # loopend: - # step = stepexpr - # endcond = endexpr - # - # curvar = load var - # nextvar = curvar + step - # store nextvar -> var - # br endcond, loop, endloop - # outloop: - - function = g_llvm_builder.basic_block.function - - # Create an alloca for the variable in the entry block. - alloca = CreateEntryBlockAlloca(function, self.loop_variable) - - # Emit the start code first, without 'variable' in scope. - start_value = self.start.CodeGen() - - # Store the value into the alloca. - g_llvm_builder.store(start_value, alloca) - - # Make the new basic block for the loop, inserting after current block. - loop_block = function.append_basic_block('loop') - - # Insert an explicit fall through from the current block to the loop_block. - g_llvm_builder.branch(loop_block) - - # Start insertion in loop_block. - g_llvm_builder.position_at_end(loop_block) - - # Within the loop, the variable is defined equal to the alloca. If it - # shadows an existing variable, we have to restore it, so save it now. - old_value = g_named_values.get(self.loop_variable, None) - g_named_values[self.loop_variable] = alloca - - # Emit the body of the loop. This, like any other expr, can change the - # current BB. Note that we ignore the value computed by the body. - self.body.CodeGen() - - # Emit the step value. - if self.step: - step_value = self.step.CodeGen() - else: - # If not specified, use 1.0. - step_value = Constant.real(Type.double(), 1) - - # Compute the end condition. - end_condition = self.end.CodeGen() - - # Reload, increment, and restore the alloca. This handles the case where - # the body of the loop mutates the variable. - cur_value = g_llvm_builder.load(alloca, self.loop_variable) - next_value = g_llvm_builder.fadd(cur_value, step_value, 'nextvar') - g_llvm_builder.store(next_value, alloca) - - # Convert condition to a bool by comparing equal to 0.0. - end_condition_bool = g_llvm_builder.fcmp( - FCMP_ONE, end_condition, Constant.real(Type.double(), 0), 'loopcond') - - # Create the "after loop" block and insert it. - after_block = function.append_basic_block('afterloop') - - # Insert the conditional branch into the end of loop_block. - g_llvm_builder.cbranch(end_condition_bool, loop_block, after_block) - - # Any new code will be inserted in after_block. - g_llvm_builder.position_at_end(after_block) - - # Restore the unshadowed variable. - if old_value is not None: - g_named_values[self.loop_variable] = old_value - else: - del g_named_values[self.loop_variable] - - # for expr always returns 0.0. - return Constant.real(Type.double(), 0) - -# Expression class for a unary operator. -class UnaryExpressionNode(ExpressionNode): - - def __init__(self, operator, operand): - self.operator = operator - self.operand = operand - - def CodeGen(self): - operand = self.operand.CodeGen() - function = g_llvm_module.get_function_named('unary' + self.operator) - return g_llvm_builder.call(function, [operand], 'unop') - -# Expression class for var/in. -class VarExpressionNode(ExpressionNode): - - def __init__(self, variables, body): - self.variables = variables - self.body = body - - def CodeGen(self): - old_bindings = {} - function = g_llvm_builder.basic_block.function - - # Register all variables and emit their initializer. - for var_name, var_expression in self.variables.iteritems(): - # Emit the initializer before adding the variable to scope, this prevents - # the initializer from referencing the variable itself, and permits stuff - # like this: - # var a = 1 in - # var a = a in ... # refers to outer 'a'. - if var_expression is not None: - var_value = var_expression.CodeGen() - else: - var_value = Constant.real(Type.double(), 0) - - alloca = CreateEntryBlockAlloca(function, var_name) - g_llvm_builder.store(var_value, alloca) - - # Remember the old variable binding so that we can restore the binding - # when we unrecurse. - old_bindings[var_name] = g_named_values.get(var_name, None) - - # Remember this binding. - g_named_values[var_name] = alloca - - # Codegen the body, now that all vars are in scope. - body = self.body.CodeGen() - - # Pop all our variables from scope. - for var_name in self.variables: - if old_bindings[var_name] is not None: - g_named_values[var_name] = old_bindings[var_name] - else: - del g_named_values[var_name] - - # Return the body computation. - return body - -# This class represents the "prototype" for a function, which captures its name, -# and its argument names (thus implicitly the number of arguments the function -# takes), as well as if it is an operator. -class PrototypeNode(object): - - def __init__(self, name, args, is_operator=False, precedence=0): - self.name = name - self.args = args - self.is_operator = is_operator - self.precedence = precedence - - def IsBinaryOp(self): - return self.is_operator and len(self.args) == 2 - - def GetOperatorName(self): - assert self.is_operator - return self.name[-1] - - def CodeGen(self): - # Make the function type, eg. double(double,double). - funct_type = Type.function( - Type.double(), [Type.double()] * len(self.args), False) - - function = Function.new(g_llvm_module, funct_type, self.name) - - # If the name conflicted, there was already something with the same name. - # If it has a body, don't allow redefinition or reextern. - if function.name != self.name: - function.delete() - function = g_llvm_module.get_function_named(self.name) - - # If the function already has a body, reject this. - if not function.is_declaration: - raise RuntimeError('Redefinition of function.') - - # If the function took a different number of args, reject. - if len(function.args) != len(self.args): - raise RuntimeError('Redeclaration of a function with different number ' - 'of args.') - - # Set names for all arguments and add them to the variables symbol table. - for arg, arg_name in zip(function.args, self.args): - arg.name = arg_name - - return function - - # Create an alloca for each argument and register the argument in the symbol - # table so that references to it will succeed. - def CreateArgumentAllocas(self, function): - for arg_name, arg in zip(self.args, function.args): - alloca = CreateEntryBlockAlloca(function, arg_name) - g_llvm_builder.store(arg, alloca) - g_named_values[arg_name] = alloca - -# This class represents a function definition itself. -class FunctionNode(object): - - def __init__(self, prototype, body): - self.prototype = prototype - self.body = body - - def CodeGen(self): - # Clear scope. - g_named_values.clear() - - # Create a function object. - function = self.prototype.CodeGen() - - # If this is a binary operator, install its precedence. - if self.prototype.IsBinaryOp(): - operator = self.prototype.GetOperatorName() - g_binop_precedence[operator] = self.prototype.precedence - - # Create a new basic block to start insertion into. - block = function.append_basic_block('entry') - global g_llvm_builder - g_llvm_builder = Builder.new(block) - - # Add all arguments to the symbol table and create their allocas. - self.prototype.CreateArgumentAllocas(function) - - # Finish off the function. - try: - return_value = self.body.CodeGen() - g_llvm_builder.ret(return_value) - - # Validate the generated code, checking for consistency. - function.verify() - - # Optimize the function. - g_llvm_pass_manager.run(function) - except: - function.delete() - if self.prototype.IsBinaryOp(): - del g_binop_precedence[self.prototype.GetOperatorName()] - raise - - return function - - -################################################################################ -## Parser -################################################################################ - -class Parser(object): - - def __init__(self, tokens): - self.tokens = tokens - self.Next() - - # Provide a simple token buffer. Parser.current is the current token the - # parser is looking at. Parser.Next() reads another token from the lexer and - # updates Parser.current with its results. - def Next(self): - self.current = self.tokens.next() - - # Gets the precedence of the current token, or -1 if the token is not a binary - # operator. - def GetCurrentTokenPrecedence(self): - if isinstance(self.current, CharacterToken): - return g_binop_precedence.get(self.current.char, -1) - else: - return -1 - - # identifierexpr ::= identifier | identifier '(' expression* ')' - def ParseIdentifierExpr(self): - identifier_name = self.current.name - self.Next() # eat identifier. - - if self.current != CharacterToken('('): # Simple variable reference. - return VariableExpressionNode(identifier_name) - - # Call. - self.Next() # eat '('. - args = [] - if self.current != CharacterToken(')'): - while True: - args.append(self.ParseExpression()) - if self.current == CharacterToken(')'): - break - elif self.current != CharacterToken(','): - raise RuntimeError('Expected ")" or "," in argument list.') - self.Next() - - self.Next() # eat ')'. - return CallExpressionNode(identifier_name, args) - - # numberexpr ::= number - def ParseNumberExpr(self): - result = NumberExpressionNode(self.current.value) - self.Next() # consume the number. - return result - - # parenexpr ::= '(' expression ')' - def ParseParenExpr(self): - self.Next() # eat '('. - - contents = self.ParseExpression() - - if self.current != CharacterToken(')'): - raise RuntimeError('Expected ")".') - self.Next() # eat ')'. - - return contents - - # ifexpr ::= 'if' expression 'then' expression 'else' expression - def ParseIfExpr(self): - self.Next() # eat the if. - - # condition. - condition = self.ParseExpression() - - if not isinstance(self.current, ThenToken): - raise RuntimeError('Expected "then".') - self.Next() # eat the then. - - then_branch = self.ParseExpression() - - if not isinstance(self.current, ElseToken): - raise RuntimeError('Expected "else".') - self.Next() # eat the else. - - else_branch = self.ParseExpression() - - return IfExpressionNode(condition, then_branch, else_branch) - - # forexpr ::= 'for' identifier '=' expr ',' expr (',' expr)? 'in' expression - def ParseForExpr(self): - self.Next() # eat the for. - - if not isinstance(self.current, IdentifierToken): - raise RuntimeError('Expected identifier after for.') - - loop_variable = self.current.name - self.Next() # eat the identifier. - - if self.current != CharacterToken('='): - raise RuntimeError('Expected "=" after for variable.') - self.Next() # eat the '='. - - start = self.ParseExpression() - - if self.current != CharacterToken(','): - raise RuntimeError('Expected "," after for start value.') - self.Next() # eat the ','. - - end = self.ParseExpression() - - # The step value is optional. - if self.current == CharacterToken(','): - self.Next() # eat the ','. - step = self.ParseExpression() - else: - step = None - - if not isinstance(self.current, InToken): - raise RuntimeError('Expected "in" after for variable specification.') - self.Next() # eat 'in'. - - body = self.ParseExpression() - - return ForExpressionNode(loop_variable, start, end, step, body) - - # varexpr ::= 'var' (identifier ('=' expression)?)+ 'in' expression - def ParseVarExpr(self): - self.Next() # eat 'var'. - - variables = {} - - # At least one variable name is required. - if not isinstance(self.current, IdentifierToken): - raise RuntimeError('Expected identifier after "var".') - - while True: - var_name = self.current.name - self.Next() # eat the identifier. - - # Read the optional initializer. - if self.current == CharacterToken('='): - self.Next() # eat '='. - variables[var_name] = self.ParseExpression() - else: - variables[var_name] = None - - # End of var list, exit loop. - if self.current != CharacterToken(','): - break - self.Next() # eat ','. - - if not isinstance(self.current, IdentifierToken): - raise RuntimeError('Expected identifier after "," in a var expression.') - - # At this point, we have to have 'in'. - if not isinstance(self.current, InToken): - raise RuntimeError('Expected "in" keyword after "var".') - self.Next() # eat 'in'. - - body = self.ParseExpression() - - return VarExpressionNode(variables, body) - - # primary ::= - # dentifierexpr | numberexpr | parenexpr | ifexpr | forexpr | varexpr - def ParsePrimary(self): - if isinstance(self.current, IdentifierToken): - return self.ParseIdentifierExpr() - elif isinstance(self.current, NumberToken): - return self.ParseNumberExpr() - elif isinstance(self.current, IfToken): - return self.ParseIfExpr() - elif isinstance(self.current, ForToken): - return self.ParseForExpr() - elif isinstance(self.current, VarToken): - return self.ParseVarExpr() - elif self.current == CharacterToken('('): - return self.ParseParenExpr() - else: - raise RuntimeError('Unknown token when expecting an expression.') - - # unary ::= primary | unary_operator unary - def ParseUnary(self): - # If the current token is not an operator, it must be a primary expression. - if (not isinstance(self.current, CharacterToken) or - self.current in [CharacterToken('('), CharacterToken(',')]): - return self.ParsePrimary() - - # If this is a unary operator, read it. - operator = self.current.char - self.Next() # eat the operator. - return UnaryExpressionNode(operator, self.ParseUnary()) - - # binoprhs ::= (binary_operator unary)* - def ParseBinOpRHS(self, left, left_precedence): - # If this is a binary operator, find its precedence. - while True: - precedence = self.GetCurrentTokenPrecedence() - - # If this is a binary operator that binds at least as tightly as the - # current one, consume it; otherwise we are done. - if precedence < left_precedence: - return left - - binary_operator = self.current.char - self.Next() # eat the operator. - - # Parse the unary expression after the binary operator. - right = self.ParseUnary() - - # If binary_operator binds less tightly with right than the operator after - # right, let the pending operator take right as its left. - next_precedence = self.GetCurrentTokenPrecedence() - if precedence < next_precedence: - right = self.ParseBinOpRHS(right, precedence + 1) - - # Merge left/right. - left = BinaryOperatorExpressionNode(binary_operator, left, right) - - # expression ::= unary binoprhs - def ParseExpression(self): - left = self.ParseUnary() - return self.ParseBinOpRHS(left, 0) - - # prototype - # ::= id '(' id* ')' - # ::= binary LETTER number? (id, id) - # ::= unary LETTER (id) - def ParsePrototype(self): - precedence = None - if isinstance(self.current, IdentifierToken): - kind = 'normal' - function_name = self.current.name - self.Next() # eat function name. - elif isinstance(self.current, UnaryToken): - kind = 'unary' - self.Next() # eat 'unary'. - if not isinstance(self.current, CharacterToken): - raise RuntimeError('Expected an operator after "unary".') - function_name = 'unary' + self.current.char - self.Next() # eat the operator. - elif isinstance(self.current, BinaryToken): - kind = 'binary' - self.Next() # eat 'binary'. - if not isinstance(self.current, CharacterToken): - raise RuntimeError('Expected an operator after "binary".') - function_name = 'binary' + self.current.char - self.Next() # eat the operator. - if isinstance(self.current, NumberToken): - if not 1 <= self.current.value <= 100: - raise RuntimeError('Invalid precedence: must be in range [1, 100].') - precedence = self.current.value - self.Next() # eat the precedence. - else: - raise RuntimeError('Expected function name, "unary" or "binary" in ' - 'prototype.') - - if self.current != CharacterToken('('): - raise RuntimeError('Expected "(" in prototype.') - self.Next() # eat '('. - - arg_names = [] - while isinstance(self.current, IdentifierToken): - arg_names.append(self.current.name) - self.Next() - - if self.current != CharacterToken(')'): - raise RuntimeError('Expected ")" in prototype.') - - # Success. - self.Next() # eat ')'. - - if kind == 'unary' and len(arg_names) != 1: - raise RuntimeError('Invalid number of arguments for a unary operator.') - elif kind == 'binary' and len(arg_names) != 2: - raise RuntimeError('Invalid number of arguments for a binary operator.') - - return PrototypeNode(function_name, arg_names, kind != 'normal', precedence) - - # definition ::= 'def' prototype expression - def ParseDefinition(self): - self.Next() # eat def. - proto = self.ParsePrototype() - body = self.ParseExpression() - return FunctionNode(proto, body) - - # toplevelexpr ::= expression - def ParseTopLevelExpr(self): - proto = PrototypeNode('', []) - return FunctionNode(proto, self.ParseExpression()) - - # external ::= 'extern' prototype - def ParseExtern(self): - self.Next() # eat extern. - return self.ParsePrototype() - - # Top-Level parsing - def HandleDefinition(self): - self.Handle(self.ParseDefinition, 'Read a function definition:') - - def HandleExtern(self): - self.Handle(self.ParseExtern, 'Read an extern:') - - def HandleTopLevelExpression(self): - try: - function = self.ParseTopLevelExpr().CodeGen() - result = g_llvm_executor.run_function(function, []) - print 'Evaluated to:', result.as_real(Type.double()) - except Exception, e: - raise#print 'Error:', e - try: - self.Next() # Skip for error recovery. - except: - pass - - def Handle(self, function, message): - try: - print message, function().CodeGen() - except Exception, e: - raise#print 'Error:', e - try: - self.Next() # Skip for error recovery. - except: - pass - -################################################################################ -## Main driver code. -################################################################################ - -def main(): - # Set up the optimizer pipeline. Start with registering info about how the - # target lays out data structures. - g_llvm_pass_manager.add(g_llvm_executor.target_data) - # Promote allocas to registers. - g_llvm_pass_manager.add(PASS_PROMOTE_MEMORY_TO_REGISTER) - # Do simple "peephole" optimizations and bit-twiddling optzns. - g_llvm_pass_manager.add(PASS_INSTRUCTION_COMBINING) - # Reassociate expressions. - g_llvm_pass_manager.add(PASS_REASSOCIATE) - # Eliminate Common SubExpressions. - g_llvm_pass_manager.add(PASS_GVN) - # Simplify the control flow graph (deleting unreachable blocks, etc). - g_llvm_pass_manager.add(PASS_CFG_SIMPLIFICATION) - - g_llvm_pass_manager.initialize() - - # Install standard binary operators. - # 1 is lowest possible precedence. 40 is the highest. - g_binop_precedence['='] = 2 - g_binop_precedence['<'] = 10 - g_binop_precedence['+'] = 20 - g_binop_precedence['-'] = 20 - g_binop_precedence['*'] = 40 - - # Run the main "interpreter loop". - while True: - print 'ready<', - try: - raw = raw_input() - except KeyboardInterrupt: - break - - parser = Parser(Tokenize(raw)) - while True: - # top ::= definition | external | expression | EOF - if isinstance(parser.current, EOFToken): - break - if isinstance(parser.current, DefToken): - parser.HandleDefinition() - elif isinstance(parser.current, ExternToken): - parser.HandleExtern() - else: - parser.HandleTopLevelExpression() - - # Print out all of the generated code. - print '\n', g_llvm_module - -if __name__ == '__main__': - main() -{% endhighlight %} - -* * * - -**[Next: Conclusion and other useful LLVM tidbits](PythonLangImpl8.html)** - - diff --git a/docs/source/doc/kaleidoscope/PythonLangImpl7.rst b/docs/source/doc/kaleidoscope/PythonLangImpl7.rst new file mode 100644 index 0000000..ada3043 --- /dev/null +++ b/docs/source/doc/kaleidoscope/PythonLangImpl7.rst @@ -0,0 +1,1574 @@ ++------------------------------------+ +| layout: page | ++------------------------------------+ +| title: "Kaleidoscope: Chapter 7" | ++------------------------------------+ + +Extending the Language: Mutable Variables / SSA construction +============================================================ + +Written by `Chris Lattner `_ and `Max +Shawabkeh `_ + +**Chapter 7** + +- This will become a table of contents (this text will be scraped). + {:toc} + +**`Chapter 8: Conclusion and other useful LLVM +tidbits `_** + +Introduction # {#intro} +======================= + +Welcome to Chapter 7 of the `Implementing a language with +LLVM `_ tutorial. In +chapters 1 through 6, we've built a very respectable, albeit simple, +`functional programming +language `_. In our +journey, we learned some parsing techniques, how to build and represent +an AST, how to build LLVM IR, and how to optimize the resultant code as +well as JIT compile it. + +While Kaleidoscope is interesting as a functional language, the fact +that it is functional makes it "too easy" to generate LLVM IR for it. In +particular, a functional language makes it very easy to build LLVM IR +directly in `SSA +form `_. +Since LLVM requires that the input code be in SSA form, this is a very +nice property and it is often unclear to newcomers how to generate code +for an imperative language with mutable variables. + +The short (and happy) summary of this chapter is that there is no need +for your front-end to build SSA form: LLVM provides highly tuned and +well tested support for this, though the way it works is a bit +unexpected for some. + +Why is this a hard problem? # {#why} +==================================== + +To understand why mutable variables cause complexities in SSA +construction, consider this extremely simple C example: + +{% highlight python %} int G, H; int test(\_Bool Condition) { int X; if +(Condition) X = G; else X = H; return X; } {% endhighlight %} + +In this case, we have the variable "X", whose value depends on the path +executed in the program. Because there are two different possible values +for X before the return instruction, a PHI node is inserted to merge the +two values. The LLVM IR that we want for this example looks like this: + +{% highlight llvm %} @G = weak global i32 0 ; type of @G is i32\* @H = +weak global i32 0 ; type of @H is i32\* define i32 @test(i1 %Condition) +{ entry: br i1 %Condition, label %cond\_true, label %cond\_false +cond\_true: %X.0 = load i32\* @G br label %cond\_next cond\_false: %X.1 += load i32\* @H br label %cond\_next cond\_next: %X.2 = phi i32 [ %X.1, +%cond\_false ], [ %X.0, %cond\_true ] ret i32 %X.2 } {% endhighlight %} + +In this example, the loads from the G and H global variables are +explicit in the LLVM IR, and they live in the then/else branches of the +if statement (cond\_true/cond\_false). In order to merge the incoming +values, the X.2 phi node in the cond\_next block selects the right value +to use based on where control flow is coming from: if control flow comes +from the cond\_false block, X.2 gets the value of X.1. Alternatively, if +control flow comes from cond\_true, it gets the value of X.0. The intent +of this chapter is not to explain the details of SSA form. For more +information, see one of the many `online +references `_. + +The question for this article is "who places the phi nodes when lowering +assignments to mutable variables?". The issue here is that LLVM +*requires* that its IR be in SSA form: there is no "non-ssa" mode for +it. However, SSA construction requires non-trivial algorithms and data +structures, so it is inconvenient and wasteful for every front-end to +have to reproduce this logic. + +Memory in LLVM # {#memory} +========================== + +The 'trick' here is that while LLVM does require all register values to +be in SSA form, it does not require (or permit) memory objects to be in +SSA form. In the example above, note that the loads from G and H are +direct accesses to G and H: they are not renamed or versioned. This +differs from some other compiler systems, which do try to version memory +objects. In LLVM, instead of encoding dataflow analysis of memory into +the LLVM IR, it is handled with `Analysis +Passes `_ which are +computed on demand. + +With this in mind, the high-level idea is that we want to make a stack +variable (which lives in memory, because it is on the stack) for each +mutable object in a function. To take advantage of this trick, we need +to talk about how LLVM represents stack variables. + +In LLVM, all memory accesses are explicit with load/store instructions, +and it is carefully designed not to have (or need) an "address-of" +operator. Notice how the type of the @G/@H global variables is actually +"i32\ *" even though the variable is defined as "i32". What this means +is that @G defines*\ space\* for an i32 in the global data area, but its +*name* actually refers to the address for that space. Stack variables +work the same way, except that instead of being declared with global +variable definitions, they are declared with the `LLVM alloca +instruction `_: + +{% highlight python %} define i32 @example() { entry: %X = alloca i32 ; +type of %X is i32\ *. ... %tmp = load i32* %X ; load the stack value %X +from the stack. %tmp2 = add i32 %tmp, 1 ; increment it store i32 %tmp2, +i32\* %X ; store it back ... {% endhighlight %} + +This code shows an example of how you can declare and manipulate a stack +variable in the LLVM IR. Stack memory allocated with the alloca +instruction is fully general: you can pass the address of the stack slot +to functions, you can store it in other variables, etc. In our example +above, we could rewrite the example to use the alloca technique to avoid +using a PHI node: + +{% highlight llvm %} @G = weak global i32 0 ; type of @G is i32\* @H = +weak global i32 0 ; type of @H is i32\* define i32 @test(i1 %Condition) +{ entry: %X = alloca i32 ; type of %X is i32\ *. br i1 %Condition, label +%cond\_true, label %cond\_false cond\_true: %X.0 = load i32* @G store +i32 %X.0, i32\* %X ; Update X br label %cond\_next cond\_false: %X.1 = +load i32\* @H store i32 %X.1, i32\* %X ; Update X br label %cond\_next +cond\_next: %X.2 = load i32\* %X ; Read X ret i32 %X.2 } {% endhighlight +%} + +With this, we have discovered a way to handle arbitrary mutable +variables without the need to create Phi nodes at all: + +.. raw:: html + +
    +
  1. + +Each mutable variable becomes a stack allocation. + +.. raw:: html + +
  2. +
  3. + +Each read of the variable becomes a load from the stack. + +.. raw:: html + +
  4. +
  5. + +Each update of the variable becomes a store to the stack. + +.. raw:: html + +
  6. +
  7. + +Taking the address of a variable just uses the stack address directly. + +.. raw:: html + +
  8. +
+ +While this solution has solved our immediate problem, it introduced +another one: we have now apparently introduced a lot of stack traffic +for very simple and common operations, a major performance problem. +Fortunately for us, the LLVM optimizer has a highly-tuned optimization +pass named "mem2reg" that handles this case, promoting allocas like this +into SSA registers, inserting Phi nodes as appropriate. If you run this +example through the pass, for example, you'll get: + +{% highlight bash %} $ llvm-as < example.ll \| opt -mem2reg \| llvm-dis +{% endhighlight %} + +{% highlight llvm %} @G = weak global i32 0 @H = weak global i32 0 +define i32 @test(i1 %Condition) { entry: br i1 %Condition, label +%cond\_true, label %cond\_false cond\_true: %X.0 = load i32\* @G br +label %cond\_next cond\_false: %X.1 = load i32\* @H br label %cond\_next +cond\_next: %X.01 = phi i32 [ %X.1, %cond\_false ], [ %X.0, %cond\_true +] ret i32 %X.01 } {% endhighlight %} + +The mem2reg pass implements the standard "iterated dominance frontier" +algorithm for constructing SSA form and has a number of optimizations +that speed up (very common) degenerate cases. The mem2reg optimization +pass is the answer to dealing with mutable variables, and we highly +recommend that you depend on it. Note that mem2reg only works on +variables in certain circumstances: + +- mem2reg is alloca-driven: it looks for allocas and if it can handle + them, it promotes them. It does not apply to global variables or heap + allocations. + +- mem2reg only looks for alloca instructions in the entry block of the + function. Being in the entry block guarantees that the alloca is only + executed once, which makes analysis simpler. + +- mem2reg only promotes allocas whose uses are direct loads and stores. + If the address of the stack object is passed to a function, or if any + funny pointer arithmetic is involved, the alloca will not be + promoted. + +- mem2reg only works on allocas of `first + class `_ + values (such as pointers, scalars and vectors), and only if the array + size of the allocation is 1 (or missing in the .ll file). mem2reg is + not capable of promoting structs or arrays to registers. Note that + the "scalarrepl" pass is more powerful and can promote structs, + "unions", and arrays in many cases. + +All of these properties are easy to satisfy for most imperative +languages, and we'll illustrate it below with Kaleidoscope. The final +question you may be asking is: should I bother with this nonsense for my +front-end? Wouldn't it be better if I just did SSA construction +directly, avoiding use of the mem2reg optimization pass? In short, we +strongly recommend that you use this technique for building SSA form, +unless there is an extremely good reason not to. Using this technique +is: + +- Proven and well tested: llvm-gcc and clang both use this technique + for local mutable variables. As such, the most common clients of LLVM + are using this to handle a bulk of their variables. You can be sure + that bugs are found fast and fixed early. + +- Extremely Fast: mem2reg has a number of special cases that make it + fast in common cases as well as fully general. For example, it has + fast-paths for variables that are only used in a single block, + variables that only have one assignment point, good heuristics to + avoid insertion of unneeded phi nodes, etc. + +- Needed for debug info generation: `Debug information in + LLVM `_ relies on + having the address of the variable exposed so that debug info can be + attached to it. This technique dovetails very naturally with this + style of debug info. + +If nothing else, this makes it much easier to get your front-end up and +running, and is very simple to implement. Lets extend Kaleidoscope with +mutable variables now! + +-------------- + +Mutable Variables in Kaleidoscope # {#kalvars} +============================================== + +Now that we know the sort of problem we want to tackle, lets see what +this looks like in the context of our little Kaleidoscope language. +We're going to add two features: + +- The ability to mutate variables with the '=' operator. +- The ability to define new variables. + +While the first item is really what this is about, we only have +variables for incoming arguments as well as for induction variables, and +redefining those only goes so far :). Also, the ability to define new +variables is a useful thing regardless of whether you will be mutating +them. Here's a motivating example that shows how we could use these: + +{% highlight python %} # Define ':' for sequencing: as a low-precedence +operator that ignores operands # and just returns the RHS. def binary : +1 (x y) y; + +Recursive fib, we could do this before. +======================================= + +def fib(x) if (x < 3) then 1 else fib(x-1) + fib(x-2) + +Iterative fib. +============== + +def fibi(x) var a = 1, b = 1, c in (for i = 3, i < x in c = a + b : a = +b : b = c) : b + +Call it. +======== + +fibi(10) {% endhighlight %} + +In order to mutate variables, we have to change our existing variables +to use the "alloca trick". Once we have that, we'll add our new +operator, then extend Kaleidoscope to support new variable definitions. + +-------------- + +Adjusting Existing Variables for Mutation # {#adjustments} +========================================================== + +The symbol table in Kaleidoscope is managed at code generation time by +the ``g_named_values`` map. This map currently keeps track of the LLVM +"Value" that holds the double value for the named variable. In order to +support mutation, we need to change this slightly, so that it holds the +*memory location* of the variable in question. Note that this change is +a refactoring: it changes the structure of the code, but does not (by +itself) change the behavior of the compiler. All of these changes are +isolated in the Kaleidoscope code generator. + +At this point in Kaleidoscope's development, it only supports variables +for two things: incoming arguments to functions and the induction +variable of 'for' loops. For consistency, we'll allow mutation of these +variables in addition to other user-defined variables. This means that +these will both need memory locations. + +To start our transformation of Kaleidoscope, we will need to create the +allocas that we will store in ``g_named_values``. We'll use a helper +function that ensures that the allocas are created in the entry block of +the function: + +{% highlight python %} # Creates an alloca instruction in the entry +block of the function. This is used # for mutable variables. def +CreateEntryBlockAlloca(function, var\_name): entry = +function.get\_entry\_basic\_block() builder = Builder.new(entry) +builder.position\_at\_beginning(entry) return +builder.alloca(Type.double(), var\_name) {% endhighlight %} + +This code creates a temporary ``llvm.core.Builder`` that is pointing at +the first instruction of the entry block. It then creates an alloca with +the expected name and returns it. Because all values in Kaleidoscope are +doubles, there is no need to pass in a type to use. + +With this in place, the first functionality change we want to make is to +variable references. In our new scheme, variables live on the stack, so +code generating a reference to them actually needs to produce a load +from the stack slot: + +{% highlight python %} def CodeGen(self): if self.name in +g\_named\_values: return +g\_llvm\_builder.load(g\_named\_values[self.name], self.name) else: +raise RuntimeError('Unknown variable name: ' + self.name) {% +endhighlight %} + +As you can see, this is pretty straightforward. Now we need to update +the things that define the variables to set up the alloca. We'll start +with ``ForExpressionNode.CodeGen`` (see the `full code listing <#code>`_ +for the unabridged code): + +{% highlight python %} def CodeGen(self): function = +g\_llvm\_builder.basic\_block.function + +:: + + # Create an alloca for the variable in the entry block. + alloca = CreateEntryBlockAlloca(function, self.loop_variable) + + # Emit the start code first, without 'variable' in scope. + start_value = self.start.CodeGen() + + # Store the value into the alloca. + g_llvm_builder.store(start_value, alloca) + ... + # Compute the end condition. + end_condition = self.end.CodeGen() + + # Reload, increment, and restore the alloca. This handles the case where + # the body of the loop mutates the variable. + cur_value = g_llvm_builder.load(alloca, self.loop_variable) + next_value = g_llvm_builder.fadd(cur_value, step_value, 'nextvar') + g_llvm_builder.store(next_value, alloca) + + # Convert condition to a bool by comparing equal to 0.0. + end_condition_bool = g_llvm_builder.fcmp( + FCMP_ONE, end_condition, Constant.real(Type.double(), 0), 'loopcond') + ... + +{% endhighlight %} + +This code is virtually identical to the code `before we allowed mutable +variables `_. The big difference is +that we no longer have to construct a PHI node, and we use load/store to +access the variable as needed. + +To support mutable argument variables, we need to also make allocas for +them. The code for this is also pretty simple: + +{% highlight python %} class PrototypeNode(object): ... # Create an +alloca for each argument and register the argument in the symbol # table +so that references to it will succeed. def CreateArgumentAllocas(self, +function): for arg\_name, arg in zip(self.args, function.args): alloca = +CreateEntryBlockAlloca(function, arg\_name) g\_llvm\_builder.store(arg, +alloca) g\_named\_values[arg\_name] = alloca {% endhighlight %} + +For each argument, we make an alloca, store the input value to the +function into the alloca, and register the alloca as the memory location +for the argument. This method gets invoked by ``FunctionNode.CodeGen`` +right after it sets up the entry block for the function. + +The final missing piece is adding the mem2reg pass, which allows us to +get good codegen once again: + +{% highlight python %} from llvm.passes import +(PASS\_PROMOTE\_MEMORY\_TO\_REGISTER, PASS\_INSTRUCTION\_COMBINING, +PASS\_REASSOCIATE, PASS\_GVN, PASS\_CFG\_SIMPLIFICATION) ... def main(): +# Set up the optimizer pipeline. Start with registering info about how +the # target lays out data structures. +g\_llvm\_pass\_manager.add(g\_llvm\_executor.target\_data) # Promote +allocas to registers. +g\_llvm\_pass\_manager.add(PASS\_PROMOTE\_MEMORY\_TO\_REGISTER) # Do +simple "peephole" optimizations and bit-twiddling optzns. +g\_llvm\_pass\_manager.add(PASS\_INSTRUCTION\_COMBINING) # Reassociate +expressions. g\_llvm\_pass\_manager.add(PASS\_REASSOCIATE) {% +endhighlight %} + +It is interesting to see what the code looks like before and after the +mem2reg optimization runs. For example, this is the before/after code +for our recursive fib function. Before the optimization: + +{% highlight llvm %} define double @fib(double %x) { entry: %x1 = alloca +double store double %x, double\* %x1 %x2 = load double\* %x1 %cmptmp = +fcmp ult double %x2, 3.000000e+00 %booltmp = uitofp i1 %cmptmp to double +%ifcond = fcmp one double %booltmp, 0.000000e+00 br i1 %ifcond, label +%then, label %else then: ; preds = %entry br label %ifcont else: ; preds += %entry %x3 = load double\* %x1 %subtmp = fsub double %x3, 1.000000e+00 +%calltmp = call double @fib(double %subtmp) %x4 = load double\* %x1 +%subtmp5 = fsub double %x4, 2.000000e+00 %calltmp6 = call double +@fib(double %subtmp5) %addtmp = fadd double %calltmp, %calltmp6 br label +%ifcont ifcont: ; preds = %else, %then %iftmp = phi double [ +1.000000e+00, %then ], [ %addtmp, %else ] ret double %iftmp } {% +endhighlight %} + +Here there is only one variable (x, the input argument) but you can +still see the extremely simple-minded code generation strategy we are +using. In the entry block, an alloca is created, and the initial input +value is stored into it. Each reference to the variable does a reload +from the stack. Also, note that we didn't modify the if/then/else +expression, so it still inserts a PHI node. While we could make an +alloca for it, it is actually easier to create a PHI node for it, so we +still just make the PHI. + +Here is the code after the mem2reg pass runs: + +{% highlight llvm %} define double @fib(double %x) { entry: %cmptmp = +fcmp ult double %x, 3.000000e+00 %booltmp = uitofp i1 %cmptmp to double +%ifcond = fcmp one double %booltmp, 0.000000e+00 br i1 %ifcond, label +%then, label %else then: br label %ifcont else: %subtmp = fsub double +%x, 1.000000e+00 %calltmp = call double @fib(double %subtmp) %subtmp5 = +fsub double %x, 2.000000e+00 %calltmp6 = call double @fib(double +%subtmp5) %addtmp = fadd double %calltmp, %calltmp6 br label %ifcont +ifcont: ; preds = %else, %then %iftmp = phi double [ 1.000000e+00, %then +], [ %addtmp, %else ] ret double %iftmp } {% endhighlight %} + +This is a trivial case for mem2reg, since there are no redefinitions of +the variable. The point of showing this is to calm your tension about +inserting such blatent inefficiencies :). + +After the rest of the optimizers run, we get: + +{% highlight llvm %} define double @fib(double %x) { entry: %cmptmp = +fcmp ult double %x, 3.000000e+00 %booltmp = uitofp i1 %cmptmp to double +%ifcond = fcmp ueq double %booltmp, 0.000000e+00 br i1 %ifcond, label +%else, label %ifcont else: %subtmp = fsub double %x, 1.000000e+00 +%calltmp = call double @fib(double %subtmp) %subtmp5 = fsub double %x, +2.000000e+00 %calltmp6 = call double @fib(double %subtmp5) %addtmp = +fadd double %calltmp, %calltmp6 ret double %addtmp ifcont: ret double +1.000000e+00 } {% endhighlight %} + +Here we see that the simplifycfg pass decided to clone the return +instruction into the end of the 'else' block. This allowed it to +eliminate some branches and the PHI node. + +Now that all symbol table references are updated to use stack variables, +we'll add the assignment operator. + +-------------- + +New Assignment Operator # {#assignment} +======================================= + +With our current framework, adding a new assignment operator is really +simple. We will parse it just like any other binary operator, but handle +it internally (instead of allowing the user to define it). The first +step is to set a precedence: + +{% highlight python %} def main(): ... # Install standard binary +operators. # 1 is lowest possible precedence. 40 is the highest. +g\_binop\_precedence['='] = 2 g\_binop\_precedence['<'] = 10 +g\_binop\_precedence['+'] = 20 g\_binop\_precedence['-'] = 20 {% +endhighlight %} + +Now that the parser knows the precedence of the binary operator, it +takes care of all the parsing and AST generation. We just need to +implement codegen for the assignment operator. This looks like: + +{% highlight python %} class +BinaryOperatorExpressionNode(ExpressionNode): ... def CodeGen(self): # A +special case for '=' because we don't want to emit the LHS as an # +expression. if self.operator == '=': # Assignment requires the LHS to be +an identifier. if not isinstance(self.left, VariableExpressionNode): +raise RuntimeError('Destination of "=" must be a variable.') {% +endhighlight %} + +Unlike the rest of the binary operators, our assignment operator doesn't +follow the "emit LHS, emit RHS, do computation" model. As such, it is +handled as a special case before the other binary operators are handled. +The other strange thing is that it requires the LHS to be a variable. It +is invalid to have ``(x+1) = expr`` -- only things like ``x = expr`` are +allowed. + +{% highlight python %} # Codegen the RHS. value = self.right.CodeGen() + +:: + + # Look up the name. + variable = g_named_values[self.left.name] + + # Store the value and return it. + g_llvm_builder.store(value, variable) + + return value + ... + +{% endhighlight %} + +Once we have the variable, CodeGening the assignment is straightforward: +we emit the RHS of the assignment, create a store, and return the +computed value. Returning a value allows for chained assignments like +``X = (Y = Z)``. + +Now that we have an assignment operator, we can mutate loop variables +and arguments. For example, we can now run code like this: + +{% highlight python %} # Function to print a double. extern printd(x) + +Define ':' for sequencing: as a low-precedence operator that ignores operands +============================================================================= + +and just returns the RHS. +========================= + +def binary : 1 (x y) y + +def test(x) printd(x) : x = 4 : printd(x) + +test(123) {% endhighlight %} + +When run, this example prints "123" and then "4", showing that we did +actually mutate the value! Okay, we have now officially implemented our +goal: getting this to work requires SSA construction in the general +case. However, to be really useful, we want the ability to define our +own local variables. Let's add this next! + +-------------- + +User-defined Local Variables # {#localvars} +=========================================== + +Adding var/in is just like any other other extensions we made to +Kaleidoscope: we extend the lexer, the parser, the AST and the code +generator. The first step for adding our new 'var/in' construct is to +extend the lexer. As before, this is pretty trivial, the code looks like +this: + +{% highlight python %} ... class UnaryToken(object): pass class +VarToken(object): pass ... def Tokenize(string): ... elif identifier == +'unary': yield UnaryToken() elif identifier == 'var': yield VarToken() +else: yield IdentifierToken(identifier) {% endhighlight %} + +The next step is to define the AST node that we will construct. For +var/in, it looks like this: + +{% highlight python %} # Expression class for var/in. class +VarExpressionNode(ExpressionNode): + +def **init**\ (self, variables, body): self.variables = variables +self.body = body + +def CodeGen(self): ... {% endhighlight %} + +var/in allows a list of names to be defined all at once, and each name +can optionally have an initializer value. As such, we capture this +information in the variables list. Also, var/in has a body, this body is +allowed to access the variables defined by the var/in. + +With this in place, we can define the parser pieces. The first thing we +do is add it as a primary expression: + +{% highlight python %} # primary ::= # dentifierexpr \| numberexpr \| +parenexpr \| ifexpr \| forexpr \| varexpr def ParsePrimary(self): if +isinstance(self.current, IdentifierToken): return +self.ParseIdentifierExpr() elif isinstance(self.current, NumberToken): +return self.ParseNumberExpr() elif isinstance(self.current, IfToken): +return self.ParseIfExpr() elif isinstance(self.current, ForToken): +return self.ParseForExpr() elif isinstance(self.current, VarToken): +return self.ParseVarExpr() elif self.current == CharacterToken('('): +return self.ParseParenExpr() else: raise RuntimeError('Unknown token +when expecting an expression.') {% endhighlight %} + +Next we define ParseVarExpr: + +{% highlight python %} # varexpr ::= 'var' (identifier ('=' +expression)?)+ 'in' expression def ParseVarExpr(self): self.Next() # eat +'var'. + +:: + + variables = {} + + # At least one variable name is required. + if not isinstance(self.current, IdentifierToken): + raise RuntimeError('Expected identifier after "var".') + +{% endhighlight %} + +The first part of this code parses the list of identifier/expr pairs +into the local ``variables`` list. + +{% highlight python %} while True: var\_name = self.current.name +self.Next() # eat the identifier. + +:: + + # Read the optional initializer. + if self.current == CharacterToken('='): + self.Next() # eat '='. + variables[var_name] = self.ParseExpression() + else: + variables[var_name] = None + + # End of var list, exit loop. + if self.current != CharacterToken(','): + break + self.Next() # eat ','. + + if not isinstance(self.current, IdentifierToken): + raise RuntimeError('Expected identifier after "," in a var expression.') + +{% endhighlight %} + +Once all the variables are parsed, we then parse the body and create the +AST node: + +{% highlight python %} # At this point, we have to have 'in'. if not +isinstance(self.current, InToken): raise RuntimeError('Expected "in" +keyword after "var".') self.Next() # eat 'in'. + +:: + + body = self.ParseExpression() + + return VarExpressionNode(variables, body) + +{% endhighlight %} + +Now that we can parse and represent the code, we need to support +emission of LLVM IR for it. This code starts out with: + +{% highlight python %} class VarExpressionNode(ExpressionNode): ... def +CodeGen(self): old\_bindings = {} function = +g\_llvm\_builder.basic\_block.function + +:: + + # Register all variables and emit their initializer. + for var_name, var_expression in self.variables.iteritems(): + # Emit the initializer before adding the variable to scope, this prevents + # the initializer from referencing the variable itself, and permits stuff + # like this: + # var a = 1 in + # var a = a in ... # refers to outer 'a'. + if var_expression is not None: + var_value = var_expression.CodeGen() + else: + var_value = Constant.real(Type.double(), 0) + + alloca = CreateEntryBlockAlloca(function, var_name) + g_llvm_builder.store(var_value, alloca) + + # Remember the old variable binding so that we can restore the binding + # when we unrecurse. + old_bindings[var_name] = g_named_values.get(var_name, None) + + # Remember this binding. + g_named_values[var_name] = alloca + +{% endhighlight %} + +Basically it loops over all the variables, installing them one at a +time. For each variable we put into the symbol table, we remember the +previous value that we replace in ``old_bindings``. + +There are more comments here than code. The basic idea is that we emit +the initializer, create the alloca, then update the symbol table to +point to it. Once all the variables are installed in the symbol table, +we evaluate the body of the var/in expression: + +{% highlight python %} # Codegen the body, now that all vars are in +scope. body = self.body.CodeGen() {% endhighlight %} + +Finally, before returning, we restore the previous variable bindings: + +{% highlight python %} # Pop all our variables from scope. for var\_name +in self.variables: if old\_bindings[var\_name] is not None: +g\_named\_values[var\_name] = old\_bindings[var\_name] else: del +g\_named\_values[var\_name] + +:: + + # Return the body computation. + return body + +{% endhighlight %} + +The end result of all of this is that we get properly scoped variable +definitions, and we even (trivially) allow mutation of them :). + +With this, we completed what we set out to do. Our nice iterative fib +example from the intro compiles and runs just fine. The mem2reg pass +optimizes all of our stack variables into SSA registers, inserting PHI +nodes where needed, and our front-end remains simple: no "iterated +dominance frontier" computation anywhere in sight. + +-------------- + +Full Code Listing # {#code} +=========================== + +Here is the complete code listing for our running example, enhanced with +mutable variables and var/in support: + +{% highlight python %} #!/usr/bin/env python + +import re from llvm.core import Module, Constant, Type, Function, +Builder from llvm.ee import ExecutionEngine, TargetData from llvm.passes +import FunctionPassManager + +from llvm.core import FCMP\_ULT, FCMP\_ONE from llvm.passes import +(PASS\_PROMOTE\_MEMORY\_TO\_REGISTER, PASS\_INSTRUCTION\_COMBINING, +PASS\_REASSOCIATE, PASS\_GVN, PASS\_CFG\_SIMPLIFICATION) + +Globals +------- + +The LLVM module, which holds all the IR code. +============================================= + +g\_llvm\_module = Module.new('my cool jit') + +The LLVM instruction builder. Created whenever a new function is entered. +========================================================================= + +g\_llvm\_builder = None + +A dictionary that keeps track of which values are defined in the current scope +============================================================================== + +and what their LLVM representation is. +====================================== + +g\_named\_values = {} + +The function optimization passes manager. +========================================= + +g\_llvm\_pass\_manager = FunctionPassManager.new(g\_llvm\_module) + +The LLVM execution engine. +========================== + +g\_llvm\_executor = ExecutionEngine.new(g\_llvm\_module) + +The binary operator precedence chart. +===================================== + +g\_binop\_precedence = {} + +Creates an alloca instruction in the entry block of the function. This is used +============================================================================== + +for mutable variables. +====================== + +def CreateEntryBlockAlloca(function, var\_name): entry = +function.get\_entry\_basic\_block() builder = Builder.new(entry) +builder.position\_at\_beginning(entry) return +builder.alloca(Type.double(), var\_name) + +Lexer +----- + +The lexer yields one of these types for each token. +=================================================== + +class EOFToken(object): pass class DefToken(object): pass class +ExternToken(object): pass class IfToken(object): pass class +ThenToken(object): pass class ElseToken(object): pass class +ForToken(object): pass class InToken(object): pass class +BinaryToken(object): pass class UnaryToken(object): pass class +VarToken(object): pass + +class IdentifierToken(object): def **init**\ (self, name): self.name = +name + +class NumberToken(object): def **init**\ (self, value): self.value = +value + +class CharacterToken(object): def **init**\ (self, char): self.char = +char def **eq**\ (self, other): return isinstance(other, CharacterToken) +and self.char == other.char def **ne**\ (self, other): return not self +== other + +Regular expressions that tokens and comments of our language. +============================================================= + +REGEX\_NUMBER = re.compile('[0-9]+(?:.[0-9]+)?') REGEX\_IDENTIFIER = +re.compile('[a-zA-Z][a-zA-Z0-9]\ *') REGEX\_COMMENT = re.compile('#.*') + +def Tokenize(string): while string: # Skip whitespace. if +string[0].isspace(): string = string[1:] continue + +:: + + # Run regexes. + comment_match = REGEX_COMMENT.match(string) + number_match = REGEX_NUMBER.match(string) + identifier_match = REGEX_IDENTIFIER.match(string) + + # Check if any of the regexes matched and yield the appropriate result. + if comment_match: + comment = comment_match.group(0) + string = string[len(comment):] + elif number_match: + number = number_match.group(0) + yield NumberToken(float(number)) + string = string[len(number):] + elif identifier_match: + identifier = identifier_match.group(0) + # Check if we matched a keyword. + if identifier == 'def': + yield DefToken() + elif identifier == 'extern': + yield ExternToken() + elif identifier == 'if': + yield IfToken() + elif identifier == 'then': + yield ThenToken() + elif identifier == 'else': + yield ElseToken() + elif identifier == 'for': + yield ForToken() + elif identifier == 'in': + yield InToken() + elif identifier == 'binary': + yield BinaryToken() + elif identifier == 'unary': + yield UnaryToken() + elif identifier == 'var': + yield VarToken() + else: + yield IdentifierToken(identifier) + string = string[len(identifier):] + else: + # Yield the ASCII value of the unknown character. + yield CharacterToken(string[0]) + string = string[1:] + +yield EOFToken() + +Abstract Syntax Tree (aka Parse Tree) +------------------------------------- + +Base class for all expression nodes. +==================================== + +class ExpressionNode(object): pass + +Expression class for numeric literals like "1.0". +================================================= + +class NumberExpressionNode(ExpressionNode): + +def **init**\ (self, value): self.value = value + +def CodeGen(self): return Constant.real(Type.double(), self.value) + +Expression class for referencing a variable, like "a". +====================================================== + +class VariableExpressionNode(ExpressionNode): + +def **init**\ (self, name): self.name = name + +def CodeGen(self): if self.name in g\_named\_values: return +g\_llvm\_builder.load(g\_named\_values[self.name], self.name) else: +raise RuntimeError('Unknown variable name: ' + self.name) + +Expression class for a binary operator. +======================================= + +class BinaryOperatorExpressionNode(ExpressionNode): + +def **init**\ (self, operator, left, right): self.operator = operator +self.left = left self.right = right + +def CodeGen(self): # A special case for '=' because we don't want to +emit the LHS as an # expression. if self.operator == '=': # Assignment +requires the LHS to be an identifier. if not isinstance(self.left, +VariableExpressionNode): raise RuntimeError('Destination of "=" must be +a variable.') + +:: + + # Codegen the RHS. + value = self.right.CodeGen() + + # Look up the name. + variable = g_named_values[self.left.name] + + # Store the value and return it. + g_llvm_builder.store(value, variable) + + return value + + left = self.left.CodeGen() + right = self.right.CodeGen() + + if self.operator == '+': + return g_llvm_builder.fadd(left, right, 'addtmp') + elif self.operator == '-': + return g_llvm_builder.fsub(left, right, 'subtmp') + elif self.operator == '*': + return g_llvm_builder.fmul(left, right, 'multmp') + elif self.operator == '<': + result = g_llvm_builder.fcmp(FCMP_ULT, left, right, 'cmptmp') + # Convert bool 0 or 1 to double 0.0 or 1.0. + return g_llvm_builder.uitofp(result, Type.double(), 'booltmp') + else: + function = g_llvm_module.get_function_named('binary' + self.operator) + return g_llvm_builder.call(function, [left, right], 'binop') + +Expression class for function calls. +==================================== + +class CallExpressionNode(ExpressionNode): + +def **init**\ (self, callee, args): self.callee = callee self.args = +args + +def CodeGen(self): # Look up the name in the global module table. callee += g\_llvm\_module.get\_function\_named(self.callee) + +:: + + # Check for argument mismatch error. + if len(callee.args) != len(self.args): + raise RuntimeError('Incorrect number of arguments passed.') + + arg_values = [i.CodeGen() for i in self.args] + + return g_llvm_builder.call(callee, arg_values, 'calltmp') + +Expression class for if/then/else. +================================== + +class IfExpressionNode(ExpressionNode): + +def **init**\ (self, condition, then\_branch, else\_branch): +self.condition = condition self.then\_branch = then\_branch +self.else\_branch = else\_branch + +def CodeGen(self): condition = self.condition.CodeGen() + +:: + + # Convert condition to a bool by comparing equal to 0.0. + condition_bool = g_llvm_builder.fcmp( + FCMP_ONE, condition, Constant.real(Type.double(), 0), 'ifcond') + + function = g_llvm_builder.basic_block.function + + # Create blocks for the then and else cases. Insert the 'then' block at the + # end of the function. + then_block = function.append_basic_block('then') + else_block = function.append_basic_block('else') + merge_block = function.append_basic_block('ifcond') + + g_llvm_builder.cbranch(condition_bool, then_block, else_block) + + # Emit then value. + g_llvm_builder.position_at_end(then_block) + then_value = self.then_branch.CodeGen() + g_llvm_builder.branch(merge_block) + + # Codegen of 'Then' can change the current block; update then_block for the + # PHI node. + then_block = g_llvm_builder.basic_block + + # Emit else block. + g_llvm_builder.position_at_end(else_block) + else_value = self.else_branch.CodeGen() + g_llvm_builder.branch(merge_block) + + # Codegen of 'Else' can change the current block, update else_block for the + # PHI node. + else_block = g_llvm_builder.basic_block + + # Emit merge block. + g_llvm_builder.position_at_end(merge_block) + phi = g_llvm_builder.phi(Type.double(), 'iftmp') + phi.add_incoming(then_value, then_block) + phi.add_incoming(else_value, else_block) + + return phi + +Expression class for for/in. +============================ + +class ForExpressionNode(ExpressionNode): + +def **init**\ (self, loop\_variable, start, end, step, body): +self.loop\_variable = loop\_variable self.start = start self.end = end +self.step = step self.body = body + +def CodeGen(self): # Output this as: # var = alloca double # ... # start += startexpr # store start -> var # goto loop # loop: # ... # bodyexpr # +... # loopend: # step = stepexpr # endcond = endexpr # # curvar = load +var # nextvar = curvar + step # store nextvar -> var # br endcond, loop, +endloop # outloop: + +:: + + function = g_llvm_builder.basic_block.function + + # Create an alloca for the variable in the entry block. + alloca = CreateEntryBlockAlloca(function, self.loop_variable) + + # Emit the start code first, without 'variable' in scope. + start_value = self.start.CodeGen() + + # Store the value into the alloca. + g_llvm_builder.store(start_value, alloca) + + # Make the new basic block for the loop, inserting after current block. + loop_block = function.append_basic_block('loop') + + # Insert an explicit fall through from the current block to the loop_block. + g_llvm_builder.branch(loop_block) + + # Start insertion in loop_block. + g_llvm_builder.position_at_end(loop_block) + + # Within the loop, the variable is defined equal to the alloca. If it + # shadows an existing variable, we have to restore it, so save it now. + old_value = g_named_values.get(self.loop_variable, None) + g_named_values[self.loop_variable] = alloca + + # Emit the body of the loop. This, like any other expr, can change the + # current BB. Note that we ignore the value computed by the body. + self.body.CodeGen() + + # Emit the step value. + if self.step: + step_value = self.step.CodeGen() + else: + # If not specified, use 1.0. + step_value = Constant.real(Type.double(), 1) + + # Compute the end condition. + end_condition = self.end.CodeGen() + + # Reload, increment, and restore the alloca. This handles the case where + # the body of the loop mutates the variable. + cur_value = g_llvm_builder.load(alloca, self.loop_variable) + next_value = g_llvm_builder.fadd(cur_value, step_value, 'nextvar') + g_llvm_builder.store(next_value, alloca) + + # Convert condition to a bool by comparing equal to 0.0. + end_condition_bool = g_llvm_builder.fcmp( + FCMP_ONE, end_condition, Constant.real(Type.double(), 0), 'loopcond') + + # Create the "after loop" block and insert it. + after_block = function.append_basic_block('afterloop') + + # Insert the conditional branch into the end of loop_block. + g_llvm_builder.cbranch(end_condition_bool, loop_block, after_block) + + # Any new code will be inserted in after_block. + g_llvm_builder.position_at_end(after_block) + + # Restore the unshadowed variable. + if old_value is not None: + g_named_values[self.loop_variable] = old_value + else: + del g_named_values[self.loop_variable] + + # for expr always returns 0.0. + return Constant.real(Type.double(), 0) + +Expression class for a unary operator. +====================================== + +class UnaryExpressionNode(ExpressionNode): + +def **init**\ (self, operator, operand): self.operator = operator +self.operand = operand + +def CodeGen(self): operand = self.operand.CodeGen() function = +g\_llvm\_module.get\_function\_named('unary' + self.operator) return +g\_llvm\_builder.call(function, [operand], 'unop') + +Expression class for var/in. +============================ + +class VarExpressionNode(ExpressionNode): + +def **init**\ (self, variables, body): self.variables = variables +self.body = body + +def CodeGen(self): old\_bindings = {} function = +g\_llvm\_builder.basic\_block.function + +:: + + # Register all variables and emit their initializer. + for var_name, var_expression in self.variables.iteritems(): + # Emit the initializer before adding the variable to scope, this prevents + # the initializer from referencing the variable itself, and permits stuff + # like this: + # var a = 1 in + # var a = a in ... # refers to outer 'a'. + if var_expression is not None: + var_value = var_expression.CodeGen() + else: + var_value = Constant.real(Type.double(), 0) + + alloca = CreateEntryBlockAlloca(function, var_name) + g_llvm_builder.store(var_value, alloca) + + # Remember the old variable binding so that we can restore the binding + # when we unrecurse. + old_bindings[var_name] = g_named_values.get(var_name, None) + + # Remember this binding. + g_named_values[var_name] = alloca + + # Codegen the body, now that all vars are in scope. + body = self.body.CodeGen() + + # Pop all our variables from scope. + for var_name in self.variables: + if old_bindings[var_name] is not None: + g_named_values[var_name] = old_bindings[var_name] + else: + del g_named_values[var_name] + + # Return the body computation. + return body + +This class represents the "prototype" for a function, which captures its name, +============================================================================== + +and its argument names (thus implicitly the number of arguments the function +============================================================================ + +takes), as well as if it is an operator. +======================================== + +class PrototypeNode(object): + +def **init**\ (self, name, args, is\_operator=False, precedence=0): +self.name = name self.args = args self.is\_operator = is\_operator +self.precedence = precedence + +def IsBinaryOp(self): return self.is\_operator and len(self.args) == 2 + +def GetOperatorName(self): assert self.is\_operator return self.name[-1] + +def CodeGen(self): # Make the function type, eg. double(double,double). +funct\_type = Type.function( Type.double(), [Type.double()] \* +len(self.args), False) + +:: + + function = Function.new(g_llvm_module, funct_type, self.name) + + # If the name conflicted, there was already something with the same name. + # If it has a body, don't allow redefinition or reextern. + if function.name != self.name: + function.delete() + function = g_llvm_module.get_function_named(self.name) + + # If the function already has a body, reject this. + if not function.is_declaration: + raise RuntimeError('Redefinition of function.') + + # If the function took a different number of args, reject. + if len(function.args) != len(self.args): + raise RuntimeError('Redeclaration of a function with different number ' + 'of args.') + + # Set names for all arguments and add them to the variables symbol table. + for arg, arg_name in zip(function.args, self.args): + arg.name = arg_name + + return function + +# Create an alloca for each argument and register the argument in the +symbol # table so that references to it will succeed. def +CreateArgumentAllocas(self, function): for arg\_name, arg in +zip(self.args, function.args): alloca = CreateEntryBlockAlloca(function, +arg\_name) g\_llvm\_builder.store(arg, alloca) +g\_named\_values[arg\_name] = alloca + +This class represents a function definition itself. +=================================================== + +class FunctionNode(object): + +def **init**\ (self, prototype, body): self.prototype = prototype +self.body = body + +def CodeGen(self): # Clear scope. g\_named\_values.clear() + +:: + + # Create a function object. + function = self.prototype.CodeGen() + + # If this is a binary operator, install its precedence. + if self.prototype.IsBinaryOp(): + operator = self.prototype.GetOperatorName() + g_binop_precedence[operator] = self.prototype.precedence + + # Create a new basic block to start insertion into. + block = function.append_basic_block('entry') + global g_llvm_builder + g_llvm_builder = Builder.new(block) + + # Add all arguments to the symbol table and create their allocas. + self.prototype.CreateArgumentAllocas(function) + + # Finish off the function. + try: + return_value = self.body.CodeGen() + g_llvm_builder.ret(return_value) + + # Validate the generated code, checking for consistency. + function.verify() + + # Optimize the function. + g_llvm_pass_manager.run(function) + except: + function.delete() + if self.prototype.IsBinaryOp(): + del g_binop_precedence[self.prototype.GetOperatorName()] + raise + + return function + +Parser +------ + +class Parser(object): + +def **init**\ (self, tokens): self.tokens = tokens self.Next() + +# Provide a simple token buffer. Parser.current is the current token the +# parser is looking at. Parser.Next() reads another token from the lexer +and # updates Parser.current with its results. def Next(self): +self.current = self.tokens.next() + +# Gets the precedence of the current token, or -1 if the token is not a +binary # operator. def GetCurrentTokenPrecedence(self): if +isinstance(self.current, CharacterToken): return +g\_binop\_precedence.get(self.current.char, -1) else: return -1 + +# identifierexpr ::= identifier \| identifier '(' expression\* ')' def +ParseIdentifierExpr(self): identifier\_name = self.current.name +self.Next() # eat identifier. + +:: + + if self.current != CharacterToken('('): # Simple variable reference. + return VariableExpressionNode(identifier_name) + + # Call. + self.Next() # eat '('. + args = [] + if self.current != CharacterToken(')'): + while True: + args.append(self.ParseExpression()) + if self.current == CharacterToken(')'): + break + elif self.current != CharacterToken(','): + raise RuntimeError('Expected ")" or "," in argument list.') + self.Next() + + self.Next() # eat ')'. + return CallExpressionNode(identifier_name, args) + +# numberexpr ::= number def ParseNumberExpr(self): result = +NumberExpressionNode(self.current.value) self.Next() # consume the +number. return result + +# parenexpr ::= '(' expression ')' def ParseParenExpr(self): self.Next() +# eat '('. + +:: + + contents = self.ParseExpression() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")".') + self.Next() # eat ')'. + + return contents + +# ifexpr ::= 'if' expression 'then' expression 'else' expression def +ParseIfExpr(self): self.Next() # eat the if. + +:: + + # condition. + condition = self.ParseExpression() + + if not isinstance(self.current, ThenToken): + raise RuntimeError('Expected "then".') + self.Next() # eat the then. + + then_branch = self.ParseExpression() + + if not isinstance(self.current, ElseToken): + raise RuntimeError('Expected "else".') + self.Next() # eat the else. + + else_branch = self.ParseExpression() + + return IfExpressionNode(condition, then_branch, else_branch) + +# forexpr ::= 'for' identifier '=' expr ',' expr (',' expr)? 'in' +expression def ParseForExpr(self): self.Next() # eat the for. + +:: + + if not isinstance(self.current, IdentifierToken): + raise RuntimeError('Expected identifier after for.') + + loop_variable = self.current.name + self.Next() # eat the identifier. + + if self.current != CharacterToken('='): + raise RuntimeError('Expected "=" after for variable.') + self.Next() # eat the '='. + + start = self.ParseExpression() + + if self.current != CharacterToken(','): + raise RuntimeError('Expected "," after for start value.') + self.Next() # eat the ','. + + end = self.ParseExpression() + + # The step value is optional. + if self.current == CharacterToken(','): + self.Next() # eat the ','. + step = self.ParseExpression() + else: + step = None + + if not isinstance(self.current, InToken): + raise RuntimeError('Expected "in" after for variable specification.') + self.Next() # eat 'in'. + + body = self.ParseExpression() + + return ForExpressionNode(loop_variable, start, end, step, body) + +# varexpr ::= 'var' (identifier ('=' expression)?)+ 'in' expression def +ParseVarExpr(self): self.Next() # eat 'var'. + +:: + + variables = {} + + # At least one variable name is required. + if not isinstance(self.current, IdentifierToken): + raise RuntimeError('Expected identifier after "var".') + + while True: + var_name = self.current.name + self.Next() # eat the identifier. + + # Read the optional initializer. + if self.current == CharacterToken('='): + self.Next() # eat '='. + variables[var_name] = self.ParseExpression() + else: + variables[var_name] = None + + # End of var list, exit loop. + if self.current != CharacterToken(','): + break + self.Next() # eat ','. + + if not isinstance(self.current, IdentifierToken): + raise RuntimeError('Expected identifier after "," in a var expression.') + + # At this point, we have to have 'in'. + if not isinstance(self.current, InToken): + raise RuntimeError('Expected "in" keyword after "var".') + self.Next() # eat 'in'. + + body = self.ParseExpression() + + return VarExpressionNode(variables, body) + +# primary ::= # dentifierexpr \| numberexpr \| parenexpr \| ifexpr \| +forexpr \| varexpr def ParsePrimary(self): if isinstance(self.current, +IdentifierToken): return self.ParseIdentifierExpr() elif +isinstance(self.current, NumberToken): return self.ParseNumberExpr() +elif isinstance(self.current, IfToken): return self.ParseIfExpr() elif +isinstance(self.current, ForToken): return self.ParseForExpr() elif +isinstance(self.current, VarToken): return self.ParseVarExpr() elif +self.current == CharacterToken('('): return self.ParseParenExpr() else: +raise RuntimeError('Unknown token when expecting an expression.') + +# unary ::= primary \| unary\_operator unary def ParseUnary(self): # If +the current token is not an operator, it must be a primary expression. +if (not isinstance(self.current, CharacterToken) or self.current in +[CharacterToken('('), CharacterToken(',')]): return self.ParsePrimary() + +:: + + # If this is a unary operator, read it. + operator = self.current.char + self.Next() # eat the operator. + return UnaryExpressionNode(operator, self.ParseUnary()) + +# binoprhs ::= (binary\_operator unary)\* def ParseBinOpRHS(self, left, +left\_precedence): # If this is a binary operator, find its precedence. +while True: precedence = self.GetCurrentTokenPrecedence() + +:: + + # If this is a binary operator that binds at least as tightly as the + # current one, consume it; otherwise we are done. + if precedence < left_precedence: + return left + + binary_operator = self.current.char + self.Next() # eat the operator. + + # Parse the unary expression after the binary operator. + right = self.ParseUnary() + + # If binary_operator binds less tightly with right than the operator after + # right, let the pending operator take right as its left. + next_precedence = self.GetCurrentTokenPrecedence() + if precedence < next_precedence: + right = self.ParseBinOpRHS(right, precedence + 1) + + # Merge left/right. + left = BinaryOperatorExpressionNode(binary_operator, left, right) + +# expression ::= unary binoprhs def ParseExpression(self): left = +self.ParseUnary() return self.ParseBinOpRHS(left, 0) + +# prototype # ::= id '(' id\* ')' # ::= binary LETTER number? (id, id) # +::= unary LETTER (id) def ParsePrototype(self): precedence = None if +isinstance(self.current, IdentifierToken): kind = 'normal' +function\_name = self.current.name self.Next() # eat function name. elif +isinstance(self.current, UnaryToken): kind = 'unary' self.Next() # eat +'unary'. if not isinstance(self.current, CharacterToken): raise +RuntimeError('Expected an operator after "unary".') function\_name = +'unary' + self.current.char self.Next() # eat the operator. elif +isinstance(self.current, BinaryToken): kind = 'binary' self.Next() # eat +'binary'. if not isinstance(self.current, CharacterToken): raise +RuntimeError('Expected an operator after "binary".') function\_name = +'binary' + self.current.char self.Next() # eat the operator. if +isinstance(self.current, NumberToken): if not 1 <= self.current.value <= +100: raise RuntimeError('Invalid precedence: must be in range [1, +100].') precedence = self.current.value self.Next() # eat the +precedence. else: raise RuntimeError('Expected function name, "unary" or +"binary" in ' 'prototype.') + +:: + + if self.current != CharacterToken('('): + raise RuntimeError('Expected "(" in prototype.') + self.Next() # eat '('. + + arg_names = [] + while isinstance(self.current, IdentifierToken): + arg_names.append(self.current.name) + self.Next() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")" in prototype.') + + # Success. + self.Next() # eat ')'. + + if kind == 'unary' and len(arg_names) != 1: + raise RuntimeError('Invalid number of arguments for a unary operator.') + elif kind == 'binary' and len(arg_names) != 2: + raise RuntimeError('Invalid number of arguments for a binary operator.') + + return PrototypeNode(function_name, arg_names, kind != 'normal', precedence) + +# definition ::= 'def' prototype expression def ParseDefinition(self): +self.Next() # eat def. proto = self.ParsePrototype() body = +self.ParseExpression() return FunctionNode(proto, body) + +# toplevelexpr ::= expression def ParseTopLevelExpr(self): proto = +PrototypeNode('', []) return FunctionNode(proto, self.ParseExpression()) + +# external ::= 'extern' prototype def ParseExtern(self): self.Next() # +eat extern. return self.ParsePrototype() + +# Top-Level parsing def HandleDefinition(self): +self.Handle(self.ParseDefinition, 'Read a function definition:') + +def HandleExtern(self): self.Handle(self.ParseExtern, 'Read an extern:') + +def HandleTopLevelExpression(self): try: function = +self.ParseTopLevelExpr().CodeGen() result = +g\_llvm\_executor.run\_function(function, []) print 'Evaluated to:', +result.as\_real(Type.double()) except Exception, e: raise#print +'Error:', e try: self.Next() # Skip for error recovery. except: pass + +def Handle(self, function, message): try: print message, +function().CodeGen() except Exception, e: raise#print 'Error:', e try: +self.Next() # Skip for error recovery. except: pass + +Main driver code. +----------------- + +def main(): # Set up the optimizer pipeline. Start with registering info +about how the # target lays out data structures. +g\_llvm\_pass\_manager.add(g\_llvm\_executor.target\_data) # Promote +allocas to registers. +g\_llvm\_pass\_manager.add(PASS\_PROMOTE\_MEMORY\_TO\_REGISTER) # Do +simple "peephole" optimizations and bit-twiddling optzns. +g\_llvm\_pass\_manager.add(PASS\_INSTRUCTION\_COMBINING) # Reassociate +expressions. g\_llvm\_pass\_manager.add(PASS\_REASSOCIATE) # Eliminate +Common SubExpressions. g\_llvm\_pass\_manager.add(PASS\_GVN) # Simplify +the control flow graph (deleting unreachable blocks, etc). +g\_llvm\_pass\_manager.add(PASS\_CFG\_SIMPLIFICATION) + +g\_llvm\_pass\_manager.initialize() + +# Install standard binary operators. # 1 is lowest possible precedence. +40 is the highest. g\_binop\_precedence['='] = 2 +g\_binop\_precedence['<'] = 10 g\_binop\_precedence['+'] = 20 +g\_binop\_precedence['-'] = 20 g\_binop\_precedence['\*'] = 40 + +# Run the main "interpreter loop". while True: print 'ready<', try: raw += raw\_input() except KeyboardInterrupt: break + +:: + + parser = Parser(Tokenize(raw)) + while True: + # top ::= definition | external | expression | EOF + if isinstance(parser.current, EOFToken): + break + if isinstance(parser.current, DefToken): + parser.HandleDefinition() + elif isinstance(parser.current, ExternToken): + parser.HandleExtern() + else: + parser.HandleTopLevelExpression() + +# Print out all of the generated code. print '', g\_llvm\_module + +if **name** == '**main**\ ': main() {% endhighlight %} + +-------------- + +**`Next: Conclusion and other useful LLVM +tidbits `_** diff --git a/docs/source/doc/kaleidoscope/PythonLangImpl8.md b/docs/source/doc/kaleidoscope/PythonLangImpl8.md deleted file mode 100644 index def3ded..0000000 --- a/docs/source/doc/kaleidoscope/PythonLangImpl8.md +++ /dev/null @@ -1,275 +0,0 @@ ---- -layout: page -title: "Kaleidoscope: Chapter 8" ---- - -# Conclusion and other useful LLVM tidbits - -Written by [Chris Lattner](mailto:sabre@nondot.org) - -**Chapter 8** - - -* This will become a table of contents (this text will be scraped). -{:toc} - -# Tutorial Conclusion # {#conclusion} - -Welcome to the the final chapter of the -[Implementing a language with LLVM](http://www.llvm.org/docs/tutorial/index.html) -tutorial. In the course of this tutorial, we have grown -our little Kaleidoscope language from being a useless toy, to being a -semi-interesting (but probably still useless) toy. :) - -It is interesting to see how far we've come, and how little code it has -taken. We built the entire lexer, parser, AST, code generator, and an -interactive run-loop (with a JIT!) by-hand in under 540 lines of -(non-comment/non-blank) code. - -Our little language supports a couple of interesting features: it supports -user defined binary and unary operators, it uses JIT compilation for immediate -evaluation, and it supports a few control flow constructs with SSA construction. - - -Part of the idea of this tutorial was to show you how easy and fun it can be -to define, build, and play with languages. Building a compiler need not be a -scary or mystical process! Now that you've seen some of the basics, I strongly -encourage you to take the code and hack on it. For example, try adding: - - - -* **global variables** -- While global variables have questional value in - modern software engineering, they are often useful when putting together quick - little hacks like the Kaleidoscope compiler itself. Fortunately, our current - setup makes it very easy to add global variables: just have value lookup check - to see if an unresolved variable is in the global variable symbol table before - rejecting it. To create a new global variable, make an instance of the LLVM - `GlobalVariable` class. - -* **typed variables** -- Kaleidoscope currently only supports variables of - type double. This gives the language a very nice elegance, because only - supporting one type means that you never have to specify types. Different - languages have different ways of handling this. The easiest way is to require - the user to specify types for every variable definition, and record the type - of the variable in the symbol table along with its Value\*. - -* **arrays, structs, vectors, etc** -- Once you add types, you can start - extending the type system in all sorts of interesting ways. Simple arrays are - very easy and are quite useful for many different applications. Adding them is - mostly an exercise in learning how the LLVM - [getelementptr](http://www.llvm.org/docs/LangRef.html#i_getelementptr) - instruction works: it is so nifty/unconventional, it - [has its own FAQ](http://www.llvm.org/docs/GetElementPtr.html)! If you - add support for recursive types (e.g. linked lists), make sure to read the - [section in the LLVM Programmer's Manual](http://www.llvm.org/docs/ProgrammersManual.html#TypeResolve) - that describes how to construct them. - -* **standard runtime** -- Our current language allows the user to access - arbitrary external functions, and we use it for things like "putchard". As you - extend the language to add higher-level constructs, often these constructs make - the most sense if they are lowered to calls into a language-supplied runtime. - For example, if you add hash tables to the language, it would probably make - sense to add the routines to a runtime, instead of inlining them all the way. - -* **memory management** -- Currently we can only access the stack in - Kaleidoscope. It would also be useful to be able to allocate heap memory, - either with calls to the standard libc malloc/free interface or with a garbage - collector. If you would like to use garbage collection, note that LLVM fully - supports - [Accurate Garbage Collection](http://www.llvm.org/docs/GarbageCollection.html) - including algorithms that move objects and need to - scan/update the stack. - -* **debugger support** -- LLVM supports generation of - [DWARF Debug info](http://www.llvm.org/docs/SourceLevelDebugging.html) - which is understood by common debuggers like GDB. Adding support for debug - info is fairly straightforward. The best way to understand it is to compile - some C/C++ code with "`llvm-gcc -g -O0`" and taking a look at - what it produces. - -* **exception handling support** - LLVM supports generation of - [zero cost exceptions](http://www.llvm.org/docs/ExceptionHandling.html) - which interoperate with code compiled in other languages. You could also - generate code by implicitly making every function return an error value and - checking it. You could also make explicit use of setjmp/longjmp. There are - many different ways to go here. - -* **object orientation, generics, database access, complex numbers, - geometric programming, ...** -- Really, there is - no end of crazy features that you can add to the language. - -* **unusual domains** -- We've been talking about applying LLVM to a domain - that many people are interested in: building a compiler for a specific language. - However, there are many other domains that can use compiler technology that are - not typically considered. For example, LLVM has been used to implement OpenGL - graphics acceleration, translate C++ code to ActionScript, and many other - cute and clever things. Maybe you will be the first to JIT compile a regular - expression interpreter into native code with LLVM? - - -Have fun - try doing something crazy and unusual. Building a language like -everyone else always has, is much less fun than trying something a little crazy -or off the wall and seeing how it turns out. If you get stuck or want to talk -about it, feel free to email the -[llvmdev mailing list](http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev): -it has lots of people who are interested in languages and are often -willing to help out. - - -Before we end this tutorial, I want to talk about some "tips and tricks" for -generating LLVM IR. These are some of the more subtle things that may not be -obvious, but are very useful if you want to take advantage of LLVM's -capabilities. - -* * * - -# Properties of the LLVM IR # {#llvmirproperties} - -We have a couple common questions about code in the LLVM IR form - let's just -get these out of the way right now, shall we? - -## Target Independence ## {#targetindep} - -Kaleidoscope is an example of a "portable language": any program written in -Kaleidoscope will work the same way on any target that it runs on. Many other -languages have this property, e.g. LISP, Java, Haskell, Javascript, Python, etc. -(note that while these languages are portable, not all their libraries are). - -One nice aspect of LLVM is that it is often capable of preserving target -independence in the IR: you can take the LLVM IR for a Kaleidoscope-compiled -program and run it on any target that LLVM supports, even emitting C code and -compiling that on targets that LLVM doesn't support natively. You can trivially -tell that the Kaleidoscope compiler generates target-independent code because it -never queries for any target-specific information when generating code. - -The fact that LLVM provides a compact, target-independent, representation for -code gets a lot of people excited. Unfortunately, these people are usually -thinking about C or a language from the C family when they are asking questions -about language portability. I say "unfortunately", because there is really no -way to make (fully general) C code portable, other than shipping the source code -around (and of course, C source code is not actually portable in general -either - ever port a really old application from 32- to 64-bits?). - -The problem with C (again, in its full generality) is that it is heavily -laden with target specific assumptions. As one simple example, the preprocessor -often destructively removes target-independence from the code when it processes -the input text: - - -{% highlight c %} -#ifdef __i386__ - int X = 1; -#else - int X = 42; -#endif -{% endhighlight %} - - -While it is possible to engineer more and more complex solutions to problems -like this, it cannot be solved in full generality in a way that is better than -shipping the actual source code. - -That said, there are interesting subsets of C that can be made portable. If -you are willing to fix primitive types to a fixed size (say int = 32-bits, -and long = 64-bits), don't care about ABI compatibility with existing binaries, -and are willing to give up some other minor features, you can have portable -code. This can make sense for specialized domains such as an -in-kernel language. - - -## Safety Guarantees ## {#safety} - -Many of the languages above are also "safe" languages: it is impossible for -a program written in Java to corrupt its address space and crash the process -(assuming the JVM has no bugs). -Safety is an interesting property that requires a combination of language -design, runtime support, and often operating system support. - -It is certainly possible to implement a safe language in LLVM, but LLVM IR -does not itself guarantee safety. The LLVM IR allows unsafe pointer casts, -use after free bugs, buffer over-runs, and a variety of other problems. Safety -needs to be implemented as a layer on top of LLVM and, conveniently, several -groups have investigated this. Ask on the -[llvmdev mailing list](http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev) -if you are interested in more details. - - -## Language-Specific Optimizations ## {#langspecific} - -One thing about LLVM that turns off many people is that it does not solve all -the world's problems in one system (sorry 'world hunger', someone else will have -to solve you some other day). One specific complaint is that people perceive -LLVM as being incapable of performing high-level language-specific optimization: -LLVM "loses too much information". - -Unfortunately, this is really not the place to give you a full and unified -version of "Chris Lattner's theory of compiler design". Instead, I'll make a -few observations: - -First, you're right that LLVM does lose information. For example, as of this -writing, there is no way to distinguish in the LLVM IR whether an SSA-value came -from a C "int" or a C "long" on an ILP32 machine (other than debug info). Both -get compiled down to an 'i32' value and the information about what it came from -is lost. The more general issue here, is that the LLVM type system uses -"structural equivalence" instead of "name equivalence". Another place this -surprises people is if you have two types in a high-level language that have the -same structure (e.g. two different structs that have a single int field): these -types will compile down into a single LLVM type and it will be impossible to -tell what it came from. - -Second, while LLVM does lose information, LLVM is not a fixed target: we -continue to enhance and improve it in many different ways. In addition to -adding new features (LLVM did not always support exceptions or debug info), we -also extend the IR to capture important information for optimization (e.g. -whether an argument is sign or zero extended, information about pointers -aliasing, etc). Many of the enhancements are user-driven: people want LLVM to -include some specific feature, so they go ahead and extend it. - -Third, it is *possible and easy* to add language-specific -optimizations, and you have a number of choices in how to do it. As one trivial -example, it is easy to add language-specific optimization passes that -"know" things about code compiled for a language. In the case of the C family, -there is an optimization pass that "knows" about the standard C library -functions. If you call "exit(0)" in main(), it knows that it is safe to -optimize that into "return 0;" because C specifies what the 'exit' -function does. - -In addition to simple library knowledge, it is possible to embed a variety of -other language-specific information into the LLVM IR. If you have a specific -need and run into a wall, please bring the topic up on the llvmdev list. At the -very worst, you can always treat LLVM as if it were a "dumb code generator" and -implement the high-level optimizations you desire in your front-end, on the -language-specific AST. - -* * * - -# Tips and Tricks # {#tipsandtricks} - -There is a variety of useful tips and tricks that you come to know after -working on/with LLVM that aren't obvious at first glance. Instead of letting -everyone rediscover them, this section talks about some of these issues. - -## Implementing portable offsetof/sizeof ## {#offsetofsizeof} - -One interesting thing that comes up, if you are trying to keep the code -generated by your compiler "target independent", is that you often need to know -the size of some LLVM type or the offset of some field in an llvm structure. -For example, you might need to pass the size of a type into a function that -allocates memory. - -Unfortunately, this can vary widely across targets: for example the width of -a pointer is trivially target-specific. However, there is a -[clever way to use the getelementptr instruction](http://nondot.org/sabre/LLVMNotes/SizeOf-OffsetOf-VariableSizedStructs.txt) -that allows you to compute this in a portable way. - -## Garbage Collected Stack Frames ## {#gcstack} - -Some languages want to explicitly manage their stack frames, often so that -they are garbage collected or to allow easy implementation of closures. There -are often better ways to implement these features than explicit stack frames, -but [LLVM does support them](http://nondot.org/sabre/LLVMNotes/ExplicitlyManagedStackFrames.txt), -if you want. It requires your front-end to convert the code into -[Continuation Passing Style](http://en.wikipedia.org/wiki/Continuation-passing_style) -and the use of tail calls (which LLVM also supports). - - diff --git a/docs/source/doc/kaleidoscope/PythonLangImpl8.rst b/docs/source/doc/kaleidoscope/PythonLangImpl8.rst new file mode 100644 index 0000000..cb9eebf --- /dev/null +++ b/docs/source/doc/kaleidoscope/PythonLangImpl8.rst @@ -0,0 +1,286 @@ ++------------------------------------+ +| layout: page | ++------------------------------------+ +| title: "Kaleidoscope: Chapter 8" | ++------------------------------------+ + +Conclusion and other useful LLVM tidbits +======================================== + +Written by `Chris Lattner `_ + +**Chapter 8** + +- This will become a table of contents (this text will be scraped). + {:toc} + +Tutorial Conclusion # {#conclusion} +=================================== + +Welcome to the the final chapter of the `Implementing a language with +LLVM `_ tutorial. In the +course of this tutorial, we have grown our little Kaleidoscope language +from being a useless toy, to being a semi-interesting (but probably +still useless) toy. :) + +It is interesting to see how far we've come, and how little code it has +taken. We built the entire lexer, parser, AST, code generator, and an +interactive run-loop (with a JIT!) by-hand in under 540 lines of +(non-comment/non-blank) code. + +Our little language supports a couple of interesting features: it +supports user defined binary and unary operators, it uses JIT +compilation for immediate evaluation, and it supports a few control flow +constructs with SSA construction. + +Part of the idea of this tutorial was to show you how easy and fun it +can be to define, build, and play with languages. Building a compiler +need not be a scary or mystical process! Now that you've seen some of +the basics, I strongly encourage you to take the code and hack on it. +For example, try adding: + +- **global variables** -- While global variables have questional value + in modern software engineering, they are often useful when putting + together quick little hacks like the Kaleidoscope compiler itself. + Fortunately, our current setup makes it very easy to add global + variables: just have value lookup check to see if an unresolved + variable is in the global variable symbol table before rejecting it. + To create a new global variable, make an instance of the LLVM + ``GlobalVariable`` class. + +- **typed variables** -- Kaleidoscope currently only supports variables + of type double. This gives the language a very nice elegance, because + only supporting one type means that you never have to specify types. + Different languages have different ways of handling this. The easiest + way is to require the user to specify types for every variable + definition, and record the type of the variable in the symbol table + along with its Value\*. + +- **arrays, structs, vectors, etc** -- Once you add types, you can + start extending the type system in all sorts of interesting ways. + Simple arrays are very easy and are quite useful for many different + applications. Adding them is mostly an exercise in learning how the + LLVM + `getelementptr `_ + instruction works: it is so nifty/unconventional, it `has its own + FAQ `_! If you add + support for recursive types (e.g. linked lists), make sure to read + the `section in the LLVM Programmer's + Manual `_ + that describes how to construct them. + +- **standard runtime** -- Our current language allows the user to + access arbitrary external functions, and we use it for things like + "putchard". As you extend the language to add higher-level + constructs, often these constructs make the most sense if they are + lowered to calls into a language-supplied runtime. For example, if + you add hash tables to the language, it would probably make sense to + add the routines to a runtime, instead of inlining them all the way. + +- **memory management** -- Currently we can only access the stack in + Kaleidoscope. It would also be useful to be able to allocate heap + memory, either with calls to the standard libc malloc/free interface + or with a garbage collector. If you would like to use garbage + collection, note that LLVM fully supports `Accurate Garbage + Collection `_ + including algorithms that move objects and need to scan/update the + stack. + +- **debugger support** -- LLVM supports generation of `DWARF Debug + info `_ which is + understood by common debuggers like GDB. Adding support for debug + info is fairly straightforward. The best way to understand it is to + compile some C/C++ code with "``llvm-gcc -g -O0``\ " and taking a + look at what it produces. + +- **exception handling support** - LLVM supports generation of `zero + cost exceptions `_ + which interoperate with code compiled in other languages. You could + also generate code by implicitly making every function return an + error value and checking it. You could also make explicit use of + setjmp/longjmp. There are many different ways to go here. + +- **object orientation, generics, database access, complex numbers, + geometric programming, ...** -- Really, there is no end of crazy + features that you can add to the language. + +- **unusual domains** -- We've been talking about applying LLVM to a + domain that many people are interested in: building a compiler for a + specific language. However, there are many other domains that can use + compiler technology that are not typically considered. For example, + LLVM has been used to implement OpenGL graphics acceleration, + translate C++ code to ActionScript, and many other cute and clever + things. Maybe you will be the first to JIT compile a regular + expression interpreter into native code with LLVM? + +Have fun - try doing something crazy and unusual. Building a language +like everyone else always has, is much less fun than trying something a +little crazy or off the wall and seeing how it turns out. If you get +stuck or want to talk about it, feel free to email the `llvmdev mailing +list `_: it has lots +of people who are interested in languages and are often willing to help +out. + +Before we end this tutorial, I want to talk about some "tips and tricks" +for generating LLVM IR. These are some of the more subtle things that +may not be obvious, but are very useful if you want to take advantage of +LLVM's capabilities. + +-------------- + +Properties of the LLVM IR # {#llvmirproperties} +=============================================== + +We have a couple common questions about code in the LLVM IR form - let's +just get these out of the way right now, shall we? + +Target Independence ## {#targetindep} +------------------------------------- + +Kaleidoscope is an example of a "portable language": any program written +in Kaleidoscope will work the same way on any target that it runs on. +Many other languages have this property, e.g. LISP, Java, Haskell, +Javascript, Python, etc. (note that while these languages are portable, +not all their libraries are). + +One nice aspect of LLVM is that it is often capable of preserving target +independence in the IR: you can take the LLVM IR for a +Kaleidoscope-compiled program and run it on any target that LLVM +supports, even emitting C code and compiling that on targets that LLVM +doesn't support natively. You can trivially tell that the Kaleidoscope +compiler generates target-independent code because it never queries for +any target-specific information when generating code. + +The fact that LLVM provides a compact, target-independent, +representation for code gets a lot of people excited. Unfortunately, +these people are usually thinking about C or a language from the C +family when they are asking questions about language portability. I say +"unfortunately", because there is really no way to make (fully general) +C code portable, other than shipping the source code around (and of +course, C source code is not actually portable in general either - ever +port a really old application from 32- to 64-bits?). + +The problem with C (again, in its full generality) is that it is heavily +laden with target specific assumptions. As one simple example, the +preprocessor often destructively removes target-independence from the +code when it processes the input text: + +{% highlight c %} #ifdef **i386** int X = 1; #else int X = 42; #endif {% +endhighlight %} + +While it is possible to engineer more and more complex solutions to +problems like this, it cannot be solved in full generality in a way that +is better than shipping the actual source code. + +That said, there are interesting subsets of C that can be made portable. +If you are willing to fix primitive types to a fixed size (say int = +32-bits, and long = 64-bits), don't care about ABI compatibility with +existing binaries, and are willing to give up some other minor features, +you can have portable code. This can make sense for specialized domains +such as an in-kernel language. + +Safety Guarantees ## {#safety} +------------------------------ + +Many of the languages above are also "safe" languages: it is impossible +for a program written in Java to corrupt its address space and crash the +process (assuming the JVM has no bugs). Safety is an interesting +property that requires a combination of language design, runtime +support, and often operating system support. + +It is certainly possible to implement a safe language in LLVM, but LLVM +IR does not itself guarantee safety. The LLVM IR allows unsafe pointer +casts, use after free bugs, buffer over-runs, and a variety of other +problems. Safety needs to be implemented as a layer on top of LLVM and, +conveniently, several groups have investigated this. Ask on the `llvmdev +mailing list `_ if +you are interested in more details. + +Language-Specific Optimizations ## {#langspecific} +-------------------------------------------------- + +One thing about LLVM that turns off many people is that it does not +solve all the world's problems in one system (sorry 'world hunger', +someone else will have to solve you some other day). One specific +complaint is that people perceive LLVM as being incapable of performing +high-level language-specific optimization: LLVM "loses too much +information". + +Unfortunately, this is really not the place to give you a full and +unified version of "Chris Lattner's theory of compiler design". Instead, +I'll make a few observations: + +First, you're right that LLVM does lose information. For example, as of +this writing, there is no way to distinguish in the LLVM IR whether an +SSA-value came from a C "int" or a C "long" on an ILP32 machine (other +than debug info). Both get compiled down to an 'i32' value and the +information about what it came from is lost. The more general issue +here, is that the LLVM type system uses "structural equivalence" instead +of "name equivalence". Another place this surprises people is if you +have two types in a high-level language that have the same structure +(e.g. two different structs that have a single int field): these types +will compile down into a single LLVM type and it will be impossible to +tell what it came from. + +Second, while LLVM does lose information, LLVM is not a fixed target: we +continue to enhance and improve it in many different ways. In addition +to adding new features (LLVM did not always support exceptions or debug +info), we also extend the IR to capture important information for +optimization (e.g. whether an argument is sign or zero extended, +information about pointers aliasing, etc). Many of the enhancements are +user-driven: people want LLVM to include some specific feature, so they +go ahead and extend it. + +Third, it is *possible and easy* to add language-specific optimizations, +and you have a number of choices in how to do it. As one trivial +example, it is easy to add language-specific optimization passes that +"know" things about code compiled for a language. In the case of the C +family, there is an optimization pass that "knows" about the standard C +library functions. If you call "exit(0)" in main(), it knows that it is +safe to optimize that into "return 0;" because C specifies what the +'exit' function does. + +In addition to simple library knowledge, it is possible to embed a +variety of other language-specific information into the LLVM IR. If you +have a specific need and run into a wall, please bring the topic up on +the llvmdev list. At the very worst, you can always treat LLVM as if it +were a "dumb code generator" and implement the high-level optimizations +you desire in your front-end, on the language-specific AST. + +-------------- + +Tips and Tricks # {#tipsandtricks} +================================== + +There is a variety of useful tips and tricks that you come to know after +working on/with LLVM that aren't obvious at first glance. Instead of +letting everyone rediscover them, this section talks about some of these +issues. + +Implementing portable offsetof/sizeof ## {#offsetofsizeof} +---------------------------------------------------------- + +One interesting thing that comes up, if you are trying to keep the code +generated by your compiler "target independent", is that you often need +to know the size of some LLVM type or the offset of some field in an +llvm structure. For example, you might need to pass the size of a type +into a function that allocates memory. + +Unfortunately, this can vary widely across targets: for example the +width of a pointer is trivially target-specific. However, there is a +`clever way to use the getelementptr +instruction `_ +that allows you to compute this in a portable way. + +Garbage Collected Stack Frames ## {#gcstack} +-------------------------------------------- + +Some languages want to explicitly manage their stack frames, often so +that they are garbage collected or to allow easy implementation of +closures. There are often better ways to implement these features than +explicit stack frames, but `LLVM does support +them `_, +if you want. It requires your front-end to convert the code into +`Continuation Passing +Style `_ and +the use of tail calls (which LLVM also supports). diff --git a/docs/source/doc/llvm-py_package.md b/docs/source/doc/llvm-py_package.md deleted file mode 100644 index d314b6a..0000000 --- a/docs/source/doc/llvm-py_package.md +++ /dev/null @@ -1,92 +0,0 @@ ---- -layout: page -title: The llvm-py Package ---- - -The llvm-py is a Python package, consisting of 6 modules, that wrap -over enough LLVM APIs to allow the implementation of your own -compiler/VM backend in pure Python. If you're come this far, you -probably know why this is a good idea. - -Out of the 6 modules, one is an "extension" module (i.e., it is -written in C), and another one is a small private utility module, which -leaves 4 public modules. These are: - -- *llvm* -- top-level package, common classes (like exceptions) -- *llvm.core* -- IR-related APIs -- *llvm.ee* -- execution engine related APIs -- *llvm.passes* -- pass manager and passes related APIs - -The modules contain only classes and (integer) constants. Mostly simple -Python constructs are used (deliberately) -- -[property()](http://docs.python.org/lib/built-in-funcs.html) and -[property decorators](http://wiki.python.org/moin/PythonDecoratorLibrary) are probably the most exotic animals around. All classes are -"new style" classes. The APIs are designed to be navigable (and -guessable!) once you know a few conventions. These conventions are -highlighted in the sections below. - -Here is a quick overview of the contents of each package: - - -## llvm - -- LLVMException -- exception class (currently the only one) - -## llvm.core -- [Module](llvm.core.Module.html) -- represents an LLVM Module -- [Type](types.html) -- represents an LLVM Type -- [Value](values.html) -- represents an LLVM Value, including: - globals, constants, variables, arguments, functions, instructions, etc.. -- [BasicBlock](llvm.core.BasicBlock.html) -- another derived of Value, - represents an LLVM basic block -- [Builder](llvm.core.Builder.html) -- used for creating instructions, - wraps LLVM IRBuilder helper - class -- constants *TYPE_\** that represents various types -- constants *CC_\** that represent calling conventions -- constants *ICMP_\** and *FCMP_\** that represent integer and real - comparison predicates (like less than, greater than etc.) -- constants *LINKAGE_\** that represent linkage of symbols (external, - internal etc.) -- constants *VISIBILITY_\** that represents visibility of symbols - (default, hidden, protected) -- constants *ATTR_\** that represent function parameter attributes - -## llvm.ee -- [ExecutionEngine](llvm.ee.ExecutionEngine.html) - -- represents an execution engine (which can be an - either an interpreter or a JIT) -- [TargetData](llvm.ee.TargetData.html) - -- represents the ABI of the target platform (details like - sizes and alignment of primitive types, endinanness etc) - -## llvm.passes -- [PassManager](llvm.passes.PassManager.html) - -- represents an LLVM pass manager -- [FunctionPassManager](llvm.passes.FunctionPassManager.html) - -- represents an LLVM function pass manager -- constants *PASS_\** that represent various passes - -## A note on the importing of these modules -Pythonically, modules are imported with the statement `import -llvm.core`. However, you might find it more convenient to import -llvm-py modules thus: - -{% highlight python %} -from llvm import * -from llvm.core import * -from llvm.ee import * -from llvm.passes import * -{% endhighlight %} - -This avoids quite some typing. Both conventions work, however. - -> **Tip** -> -> -> Python-style documentation strings (`__doc__`) are present in -> llvm-py. You can use the `help()` of the interactive Python -> interpreter or the `object?` of [IPython](http://ipython.scipy.org/moin/) -> to get online help. (Note: not complete yet!) - - diff --git a/docs/source/doc/llvm.core.Argument.md b/docs/source/doc/llvm.core.Argument.md deleted file mode 100644 index d9e8890..0000000 --- a/docs/source/doc/llvm.core.Argument.md +++ /dev/null @@ -1,57 +0,0 @@ ---- -layout: page -title: Argument (llvm.core) ---- - -The `args` property of `llvm.core.Function` objects yields -`llvm.core.Argument` objects. This allows for setting attributes for -functions arguments. `Argument` objects cannot be constructed from user -code, the only way to get a reference to these are from `Function` -objects. - -The method `add_attribute` and `remove_attribute` can be used to add or -remove the following attributes: - -Value| Equivalent LLVM Assembly Keyword | ------|----------------------------------| -`ATTR_ZEXT`| `zeroext` | -`ATTR_SEXT`| `signext` | -`ATTR_IN_REG`| `inreg` | -`ATTR_BY_VAL`| `byval` | -`ATTR_STRUCT_RET`| `sret` | -`ATTR_NO_ALIAS`| `noalias` | -`ATTR_NO_CAPTURE`| `nocapture` | -`ATTR_NEST`| `nest` | - -These method work exactly like the -[corresponding methods](functions.html#fnattr) -of the `Function` class above. Refer -[LLVM docs](http://www.llvm.org/docs/LangRef.html#paramattrs) -for information on what each attribute means. - -The alignment of any argument can be set via the `alignment` -property, to any power of 2. - -# llvm.core.Argument - -## Base Class - -- [llvm.core.Value](llvm.core.Value.html) - -## Properties - -### `alignment` - -The alignment of the argument. Must be a power of 2. - -## Methods - -### `add_attribute(attr)` - -Add an attribute `attr` to the argument, from the set listed above. - -### `remove_attribute(attr)` - -Remove the attribute `attr` of the argument. - - diff --git a/docs/source/doc/llvm.core.Argument.rst b/docs/source/doc/llvm.core.Argument.rst new file mode 100644 index 0000000..2481665 --- /dev/null +++ b/docs/source/doc/llvm.core.Argument.rst @@ -0,0 +1,58 @@ ++-------------------------------+ +| layout: page | ++-------------------------------+ +| title: Argument (llvm.core) | ++-------------------------------+ + +The ``args`` property of ``llvm.core.Function`` objects yields +``llvm.core.Argument`` objects. This allows for setting attributes for +functions arguments. ``Argument`` objects cannot be constructed from +user code, the only way to get a reference to these are from +``Function`` objects. + +The method ``add_attribute`` and ``remove_attribute`` can be used to add +or remove the following attributes: + +Value\| Equivalent LLVM Assembly Keyword \| +-----\|----------------------------------\| ``ATTR_ZEXT``\ \| +``zeroext`` \| ``ATTR_SEXT``\ \| ``signext`` \| ``ATTR_IN_REG``\ \| +``inreg`` \| ``ATTR_BY_VAL``\ \| ``byval`` \| ``ATTR_STRUCT_RET``\ \| +``sret`` \| ``ATTR_NO_ALIAS``\ \| ``noalias`` \| ``ATTR_NO_CAPTURE``\ \| +``nocapture`` \| ``ATTR_NEST``\ \| ``nest`` \| + +These method work exactly like the `corresponding +methods `_ of the ``Function`` class above. Refer +`LLVM docs `_ for +information on what each attribute means. + +The alignment of any argument can be set via the ``alignment`` property, +to any power of 2. + +llvm.core.Argument +================== + +Base Class +---------- + +- `llvm.core.Value `_ + +Properties +---------- + +``alignment`` +~~~~~~~~~~~~~ + +The alignment of the argument. Must be a power of 2. + +Methods +------- + +``add_attribute(attr)`` +~~~~~~~~~~~~~~~~~~~~~~~ + +Add an attribute ``attr`` to the argument, from the set listed above. + +``remove_attribute(attr)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Remove the attribute ``attr`` of the argument. diff --git a/docs/source/doc/llvm.core.ArrayType.md b/docs/source/doc/llvm.core.ArrayType.md deleted file mode 100644 index 4aec7bd..0000000 --- a/docs/source/doc/llvm.core.ArrayType.md +++ /dev/null @@ -1,26 +0,0 @@ ---- -layout: page -title: ArrayType (llvm.core) ---- - - -# llvm.core.ArrayType - -## Base Class - -- [llvm.core.Type](llvm.core.Type.html) - -## Properties - - -### `element` -\[read-only\] - -A `Type` object representing the type of the element of the array. - - -### `count` -\[read-only\] - -The number of elements in the array. - diff --git a/docs/source/doc/llvm.core.ArrayType.rst b/docs/source/doc/llvm.core.ArrayType.rst new file mode 100644 index 0000000..f8b5e0c --- /dev/null +++ b/docs/source/doc/llvm.core.ArrayType.rst @@ -0,0 +1,30 @@ ++--------------------------------+ +| layout: page | ++--------------------------------+ +| title: ArrayType (llvm.core) | ++--------------------------------+ + +llvm.core.ArrayType +=================== + +Base Class +---------- + +- `llvm.core.Type `_ + +Properties +---------- + +``element`` +~~~~~~~~~~~ + +[read-only] + +A ``Type`` object representing the type of the element of the array. + +``count`` +~~~~~~~~~ + +[read-only] + +The number of elements in the array. diff --git a/docs/source/doc/llvm.core.BasicBlock.md b/docs/source/doc/llvm.core.BasicBlock.md deleted file mode 100644 index 873634c..0000000 --- a/docs/source/doc/llvm.core.BasicBlock.md +++ /dev/null @@ -1,40 +0,0 @@ ---- -layout: page -title: BasicBlock (llvm.core) ---- - -A basicblock is a list of instructions. -A wellformed basicblock should end with a terminator. -`Function.verify()` will verify that. -A terminator is either a branch instruction or return instruction. -It is not possible to have instructions after a branch or return instruction. - -# llvm.core.BasicBlock - -## Base Class - -- [llvm.core.Value][] - -## Methods - -### `delete(self)` - -Delete this basicblock from the function (`self.function`). - -### `insert_before(self, name)` - -TODO - -## Proporties - -### `function` - -The parent function of this basicblock. - -### `instructions` - -A list of instructions in this basicblock. - - -[llvm.core.Value]: llvm.core.Value.html -[llvm.core.Function]: llvm.core.Function.html diff --git a/docs/source/doc/llvm.core.BasicBlock.rst b/docs/source/doc/llvm.core.BasicBlock.rst new file mode 100644 index 0000000..74806a6 --- /dev/null +++ b/docs/source/doc/llvm.core.BasicBlock.rst @@ -0,0 +1,44 @@ ++---------------------------------+ +| layout: page | ++---------------------------------+ +| title: BasicBlock (llvm.core) | ++---------------------------------+ + +A basicblock is a list of instructions. A wellformed basicblock should +end with a terminator. ``Function.verify()`` will verify that. A +terminator is either a branch instruction or return instruction. It is +not possible to have instructions after a branch or return instruction. + +llvm.core.BasicBlock +==================== + +Base Class +---------- + +- `llvm.core.Value `_ + +Methods +------- + +``delete(self)`` +~~~~~~~~~~~~~~~~ + +Delete this basicblock from the function (``self.function``). + +``insert_before(self, name)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +TODO + +Proporties +---------- + +``function`` +~~~~~~~~~~~~ + +The parent function of this basicblock. + +``instructions`` +~~~~~~~~~~~~~~~~ + +A list of instructions in this basicblock. diff --git a/docs/source/doc/llvm.core.Builder.md b/docs/source/doc/llvm.core.Builder.md deleted file mode 100644 index 75fffd4..0000000 --- a/docs/source/doc/llvm.core.Builder.md +++ /dev/null @@ -1,326 +0,0 @@ ---- -layout: page -title: Builder (llvm.core) ---- - -The `Builder` class corresponds to the -[IRBuilder](http://llvm.org/docs/doxygen/html/classllvm_1_1IRBuilder.html) -in C++ llvm. It provides an uniform API to -populating [BasicBlocks][llvm.core.BasicBlock]. -Most of the methods in `Builder` correspond to the instructions in the LLVM IR. -See [LLVM documentation](http://llvm.org/docs/LangRef.html) for detail. -These methods have the `name` argument for overiding the name -of the result variable. When it is an empty string (default value), -LLVM will set a numeric ID for the result variable. - -# llvm.core.Builder - -* This will become a table of contents (this text will be scraped). -{:toc} - -## Static Factor Method - -### `new(basic_block)` - -Create an instance of `Builder` at [BasicBlock][llvm.core.BasicBlock]. - -## Methods - -### `add(self, lhs, rhs, name='')` - -Insert an instruction that computes `lhs+rhs` for integer values only. - -### `alloca(self, ty, name='')` - -Insert an instruction that allocates stack memory for a value of type `ty`. - -### `alloca_array(self, ty, size, name='')` - -Insert an instruction that allocates stack memory for a `size` elements array -of type `ty`. - -### `and_(self, lhs, rhs, name='')` - -Insert an instruction that computes `lhs & rhs`. - -### `ashr(self, lhs, rhs, name='')` - -Insert an instruction that computes `lhs >> rhs` using arithmetic shift. - -### `bitcast(self, value, dest_ty, name='')` - -Insert an instruction that cast `value` to type `dest_ty`. - -### `branch(self, bblk)` - -Insert an instruction that branch to basicblock `bblk`. - -### `call(self, fn, args, name='')` - -Insert an instruction that call function `fn` with a iterable of -arguments `args`. - -### `cbranch(self, if_value, then_blk, else_blk)` - -Insert an instruction that conditionally branch base on -the predicate `if_value`. -If `if_value` is `True`, branch to `then_blk`; -Otherwise, branch to `else_blk`. - -### `extract_element(self, vec_val, idx_val, name='')` - -Insert an instruction that extracts an element from a value `vec_val` of -[llvm.core.VectorType][] at index `idx_val`. - -### `extract_value(self, retval, idx, name='')` - -Insert an instruction that extracts an element from an aggregate value `retval` -at index `idx`. - -### `fadd(self, lhs, rhs, name='')` - -Insert an instruction that computes `lhs + rhs` for floating-point values. - -### `fcmp(self, rpred, lhs, rhs, name='')` - -Insert an instruction that compares `lhs` and `rhs` using the comparision -operation defined by `rpred`. -See [here](comparision.html#fcmp) for a list of comparators. - -### `fdiv(self, lhs, rhs, name='')` - -Insert an instruction that computes `lhs / rhs` for floating-point values. - -### `fmul(self, lhs, rhs, name='')` - -Insert an instruction that computes `lhs * rhs` for floating-point values. - -### `fpext(self, value, dest_ty, name='')` - -Insert an instruction that extends `value` to a float type `dest_ty`. - -### `fptosi(self, value, dest_ty, name='')` - -Insert an instruction that converts a floating-point value `value` -to a signed integer type `dest_ty`. - -### `fptoui(self, value, dest_ty, name='')` - -Insert an instruction that converts a floating-point value `value` -to an unsigned integer type `dest_ty`. - -### `fptrunc(self, value, dest_ty, name='')` - -Insert an instruction that truncates a floating-point value `value` -to a float type `dest_ty`. - -### `free(self, ptr)` - -Insert an instruction that call performs heap deallocation on pointer `ptr`. - -### `frem(self, lhs, rhs, name='')` - -Insert an instruction that computes `lhs % rhs` for floating-point values. - -### `fsub(self, lhs, rhs, name='')` - -Insert an instruction that computes `lhs - rhs` for floating-point values. - -### `gep(self, ptr, indices, name='')` - -See [GEP](http://llvm.org/docs/LangRef.html#i_getelementptr). - -### `getresult(self, retval, idx, name='')` - -same as `extract_value`. - -### `icmp(self, ipred, lhs, rhs, name='')` - -Insert an instruction that compares `lhs` and `rhs` using the comparision -operation defined by `ipred`. -See [here](comparision.html#icmp) for a list of comparators. - -### `insert_element(self, vec_val, elt_val, idx_val, name='')` - -Insert an instruction that inserts a value `elt_val` into `vec_val` of -[llvm.core.VectorType][] at index `idx_val`. - -### `inttoptr(self, value, dest_ty, name='')` - -Insert an instruction that converts an integer `value` to pointer `dest_ty`. - -### `invoke(self, func, args, then_blk, catch_blk, name='')` - -See [invoke](http://llvm.org/docs/LangRef.html#i_invoke) - -### `load(self, ptr, name='')` - -Insert an instruction that loads a value at the memory pointed by `ptr`. - -### `lshr(self, lhs, rhs, name='')` - -Insert an instruction that computes `lhs >> rhs` using logical shift. - -### `malloc(self, ty, name='')` - -Insert an instruction that allocates heap memory of type `ty`. -The instruction returns a pointer that points to a value of type `ty`. - -### `malloc_array(self, ty, size, name='')` - -Similar to `malloc` but allocates an array of `size` elements. - -### `mul(self, lhs, rhs, name='')` - -Insert an instruction that computes `lhs * rhs` for integer types. - -### `neg(self, val, name='')` - -Insert an instruction that computes `0 - val`. - -### `not_(self, val, name='')` - -Insert an instruction that computes an one's complement of `val`. - -### `or_(self, lhs, rhs, name='')` - -Insert an instruction that computes `lhs | rhs`. - -### `phi(self, ty, name='')` - -Create a PHI node of type `ty`. - -### `position_at_beginning(self, bblk)` -Position the builder at the beginning of the given block. -Next instruction inserted will be first one in the block. - -### `position_at_end(self, bblk)` - -Position the builder at the end of the given block. -Next instruction inserted will be last one in the block. - -### `position_before(self, instr)` - -Position the builder before the given instruction. -The instruction can belong to a basic block other than the current one. - -### `ptrtoint(self, value, dest_ty, name='')` - -Insert an instruction that converts a pointer to an integer `value` of -type `dest_ty`. - -### `ret(self, value)` - -Insert an instruction that returns `value`. - -### `ret_many(self, values)` - -Insert an instruction that returns `values` which is an iterable of -[llvm.core.Value][]. - -### `ret_void(self)` - -Insert an instruction that returns nothing (void). - -### `sdiv(self, lhs, rhs, name='')` - -Insert an instruction that computes `lhs / rhs` for signed integers. - -### `select(self, cond, then_value, else_value, name='')` - -Insert an instruction that computes `cond ? then_value : else_value`. - -### `sext(self, value, dest_ty, name='')` - -Insert an instruction that sign extends an integer `value` to type `dest_ty`. - -### `shl(self, lhs, rhs, name='')` - -Insert an instruction that computes `lhs << rhs`. - -### `shuffle_vector(self, vecA, vecB, mask, name='')` - -Insert an instruction that performs a vector shuffle base on the two vectors -- -`vecA` and `vecB`, base on a bit mask `mask`. The mask must be a constant. - -See [LLVM document](http://llvm.org/docs/LangRef.html#i_shufflevector) -for detail. - -### `sitofp(self, value, dest_ty, name='')` - -Insert an instruction that converts a signed integer `value` to a floating-point -type `dest_ty`. - -### `srem(self, lhs, rhs, name='')` - -Insert an instruction that computes `lhs % rhs` for signed integers. - -### `store(self, value, ptr)` - -Insert an instruction that stores `value` into the memory pointed by `ptr`. - -### `sub(self, lhs, rhs, name='')` - -Insert an instruction that computes `lhs - rhs`. - -### `switch(self, value, else_blk, n=10)` - -Insert an instruction that transfer control flow depending on the `value`. -`else_blk` is the default case. `n` sets the number of additional cases. - -This method returns an instance of -[SwitchInstruction](llvm.core.Instruction.html#switchinstr) -for adding cases to the switch. - -### `trunc(self, value, dest_ty, name='')` - -Insert an instruction that truncates an integer `value` to the destination -integer type `dest_ty`. - -### `udiv(self, lhs, rhs, name='')` - -Insert an instruction that computes `lhs / rhs` for unsigned integers. - -### `uitofp(self, value, dest_ty, name='')` - -Insert an instruction that converts an unsigned integer `value` to a -floating-point type `dest_ty`. - -### `unreachable(self)` - -Insert an unreachabe instruction, which has no defined semantics. -See [LLVM document](http://llvm.org/docs/LangRef.html#i_unreachable) -for detail. - -### `urem(self, lhs, rhs, name='')` - -Insert an instruction that computes `lhs % rhs` for unsigned integers. - -### `vaarg(self, list_val, ty, name='')` - -This is used to access variable arguments given as `list_val` of type `ty`. -see [LLVM document](http://llvm.org/docs/LangRef.html#int_varargs) -about variable argument intrinsics. - -### `xor(self, lhs, rhs, name='')` - -Insert an instruction that computes `lhs xor rhs`. - -### `zext(self, value, dest_ty, name='')` - -Insert an instruction that zero extends `value` to type `dest_ty`. - -## Properties - -### `basic_block` - -The [BasicBlock][llvm.core.BasicBlock] where the builder is positioned. - -### `block` - -Deprecated. Same as `basic_block` - -[llvm.core.BasicBlock]: llvm.core.BasicBlock.html -[llvm.core.Value]: llvm.core.Value.html -[llvm.core.VectorType]: llvm.core.VectorType.html - diff --git a/docs/source/doc/llvm.core.Builder.rst b/docs/source/doc/llvm.core.Builder.rst new file mode 100644 index 0000000..1e90908 --- /dev/null +++ b/docs/source/doc/llvm.core.Builder.rst @@ -0,0 +1,411 @@ ++------------------------------+ +| layout: page | ++------------------------------+ +| title: Builder (llvm.core) | ++------------------------------+ + +The ``Builder`` class corresponds to the +`IRBuilder `_ +in C++ llvm. It provides an uniform API to populating +`BasicBlocks `_. Most of the methods in +``Builder`` correspond to the instructions in the LLVM IR. See `LLVM +documentation `_ for detail. These +methods have the ``name`` argument for overiding the name of the result +variable. When it is an empty string (default value), LLVM will set a +numeric ID for the result variable. + +llvm.core.Builder +================= + +- This will become a table of contents (this text will be scraped). + {:toc} + +Static Factor Method +-------------------- + +``new(basic_block)`` +~~~~~~~~~~~~~~~~~~~~ + +Create an instance of ``Builder`` at +`BasicBlock `_. + +Methods +------- + +``add(self, lhs, rhs, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that computes ``lhs+rhs`` for integer values only. + +``alloca(self, ty, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that allocates stack memory for a value of type +``ty``. + +``alloca_array(self, ty, size, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that allocates stack memory for a ``size`` +elements array of type ``ty``. + +``and_(self, lhs, rhs, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that computes ``lhs & rhs``. + +``ashr(self, lhs, rhs, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that computes ``lhs >> rhs`` using arithmetic +shift. + +``bitcast(self, value, dest_ty, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that cast ``value`` to type ``dest_ty``. + +``branch(self, bblk)`` +~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that branch to basicblock ``bblk``. + +``call(self, fn, args, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that call function ``fn`` with a iterable of +arguments ``args``. + +``cbranch(self, if_value, then_blk, else_blk)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that conditionally branch base on the predicate +``if_value``. If ``if_value`` is ``True``, branch to ``then_blk``; +Otherwise, branch to ``else_blk``. + +``extract_element(self, vec_val, idx_val, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that extracts an element from a value ``vec_val`` +of `llvm.core.VectorType `_ at index +``idx_val``. + +``extract_value(self, retval, idx, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that extracts an element from an aggregate value +``retval`` at index ``idx``. + +``fadd(self, lhs, rhs, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that computes ``lhs + rhs`` for floating-point +values. + +``fcmp(self, rpred, lhs, rhs, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that compares ``lhs`` and ``rhs`` using the +comparision operation defined by ``rpred``. See +`here `_ for a list of comparators. + +``fdiv(self, lhs, rhs, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that computes ``lhs / rhs`` for floating-point +values. + +``fmul(self, lhs, rhs, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that computes ``lhs * rhs`` for floating-point +values. + +``fpext(self, value, dest_ty, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that extends ``value`` to a float type +``dest_ty``. + +``fptosi(self, value, dest_ty, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that converts a floating-point value ``value`` to +a signed integer type ``dest_ty``. + +``fptoui(self, value, dest_ty, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that converts a floating-point value ``value`` to +an unsigned integer type ``dest_ty``. + +``fptrunc(self, value, dest_ty, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that truncates a floating-point value ``value`` to +a float type ``dest_ty``. + +``free(self, ptr)`` +~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that call performs heap deallocation on pointer +``ptr``. + +``frem(self, lhs, rhs, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that computes ``lhs % rhs`` for floating-point +values. + +``fsub(self, lhs, rhs, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that computes ``lhs - rhs`` for floating-point +values. + +``gep(self, ptr, indices, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +See `GEP `_. + +``getresult(self, retval, idx, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +same as ``extract_value``. + +``icmp(self, ipred, lhs, rhs, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that compares ``lhs`` and ``rhs`` using the +comparision operation defined by ``ipred``. See +`here `_ for a list of comparators. + +``insert_element(self, vec_val, elt_val, idx_val, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that inserts a value ``elt_val`` into ``vec_val`` +of `llvm.core.VectorType `_ at index +``idx_val``. + +``inttoptr(self, value, dest_ty, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that converts an integer ``value`` to pointer +``dest_ty``. + +``invoke(self, func, args, then_blk, catch_blk, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +See `invoke `_ + +``load(self, ptr, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that loads a value at the memory pointed by +``ptr``. + +``lshr(self, lhs, rhs, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that computes ``lhs >> rhs`` using logical shift. + +``malloc(self, ty, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that allocates heap memory of type ``ty``. The +instruction returns a pointer that points to a value of type ``ty``. + +``malloc_array(self, ty, size, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Similar to ``malloc`` but allocates an array of ``size`` elements. + +``mul(self, lhs, rhs, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that computes ``lhs * rhs`` for integer types. + +``neg(self, val, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that computes ``0 - val``. + +``not_(self, val, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that computes an one's complement of ``val``. + +``or_(self, lhs, rhs, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that computes ``lhs | rhs``. + +``phi(self, ty, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Create a PHI node of type ``ty``. + +``position_at_beginning(self, bblk)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Position the builder at the beginning of the given block. Next +instruction inserted will be first one in the block. + +``position_at_end(self, bblk)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Position the builder at the end of the given block. Next instruction +inserted will be last one in the block. + +``position_before(self, instr)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Position the builder before the given instruction. The instruction can +belong to a basic block other than the current one. + +``ptrtoint(self, value, dest_ty, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that converts a pointer to an integer ``value`` of +type ``dest_ty``. + +``ret(self, value)`` +~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that returns ``value``. + +``ret_many(self, values)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that returns ``values`` which is an iterable of +`llvm.core.Value `_. + +``ret_void(self)`` +~~~~~~~~~~~~~~~~~~ + +Insert an instruction that returns nothing (void). + +``sdiv(self, lhs, rhs, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that computes ``lhs / rhs`` for signed integers. + +``select(self, cond, then_value, else_value, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that computes ``cond ? then_value : else_value``. + +``sext(self, value, dest_ty, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that sign extends an integer ``value`` to type +``dest_ty``. + +``shl(self, lhs, rhs, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that computes ``lhs << rhs``. + +``shuffle_vector(self, vecA, vecB, mask, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that performs a vector shuffle base on the two +vectors -- ``vecA`` and ``vecB``, base on a bit mask ``mask``. The mask +must be a constant. + +See `LLVM document `_ +for detail. + +``sitofp(self, value, dest_ty, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that converts a signed integer ``value`` to a +floating-point type ``dest_ty``. + +``srem(self, lhs, rhs, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that computes ``lhs % rhs`` for signed integers. + +``store(self, value, ptr)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that stores ``value`` into the memory pointed by +``ptr``. + +``sub(self, lhs, rhs, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that computes ``lhs - rhs``. + +``switch(self, value, else_blk, n=10)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that transfer control flow depending on the +``value``. ``else_blk`` is the default case. ``n`` sets the number of +additional cases. + +This method returns an instance of +`SwitchInstruction `_ for adding +cases to the switch. + +``trunc(self, value, dest_ty, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that truncates an integer ``value`` to the +destination integer type ``dest_ty``. + +``udiv(self, lhs, rhs, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that computes ``lhs / rhs`` for unsigned integers. + +``uitofp(self, value, dest_ty, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that converts an unsigned integer ``value`` to a +floating-point type ``dest_ty``. + +``unreachable(self)`` +~~~~~~~~~~~~~~~~~~~~~ + +Insert an unreachabe instruction, which has no defined semantics. See +`LLVM document `_ for +detail. + +``urem(self, lhs, rhs, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that computes ``lhs % rhs`` for unsigned integers. + +``vaarg(self, list_val, ty, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This is used to access variable arguments given as ``list_val`` of type +``ty``. see `LLVM +document `_ about +variable argument intrinsics. + +``xor(self, lhs, rhs, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that computes ``lhs xor rhs``. + +``zext(self, value, dest_ty, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that zero extends ``value`` to type ``dest_ty``. + +Properties +---------- + +``basic_block`` +~~~~~~~~~~~~~~~ + +The `BasicBlock `_ where the builder is +positioned. + +``block`` +~~~~~~~~~ + +Deprecated. Same as ``basic_block`` diff --git a/docs/source/doc/llvm.core.Constant.md b/docs/source/doc/llvm.core.Constant.md deleted file mode 100644 index 23b6671..0000000 --- a/docs/source/doc/llvm.core.Constant.md +++ /dev/null @@ -1,296 +0,0 @@ ---- -layout: page -title: Constant (llvm.core) ---- - -`Constant`-s represents constants that appear within the code. The -values of such objects are known at creation time. Constants can be -created from Python constants. A constant expression is also a constant --- given a `Constant` object, an operation (like addition, subtraction -etc) can be specified, to yield a new `Constant` object. Let's see some -examples: - -{% highlight python %} -#!/usr/bin/env python - -ti = Type.int() # a 32-bit int type - -k1 = Constant.int(ti, 42) # "int k1 = 42;" -k2 = k1.add( Constant.int( ti, 10 ) ) # "int k2 = k1 + 10;" - -tr = Type.float() - -r1 = Constant.real(tr, "3.141592") # create from a string -r2 = Constant.real(tr, 1.61803399) # create from a Python float -{% endhighlight %} - -# llvm.core.Constant - - -* This will become a table of contents (this text will be scraped). -{:toc} - - -## Static factory methods - -### `null(ty)` - -A null value (all zeros) of type `ty` - -### `all_ones(ty)` - -All 1's value of type `ty` - -### `undef(ty)` - -An undefined value of type `ty` - -### `int(ty, value)` - -Integer of type `ty`, with value `value` (a Python int or long) - -### `int_signextend(ty, value)` - -Integer of signed type `ty` (use for signed types) - -### `real(ty, value)` - -Floating point value of type `ty`, with value `value` (a Python float) - -### `stringz(value)` - -A null-terminated string. `value` is a Python string - -### `string(value)` - -As `string(ty)`, but not null terminated - -### `array(ty, consts)` - -Array of type `ty`, initialized with `consts` (an iterable yielding `Constant` -objects of the appropriate type) - -### `struct(ty, consts)` - -Struct (unpacked) of type `ty`, initialized with `consts` (an iterable yielding -`Constant` objects of the appropriate type) - -### `packed_struct(ty, consts)` - -As `struct(ty, consts)` but packed - -### `vector(consts)` - -Vector, initialized with `consts` (an iterable yielding `Constant` objects of -the appropriate type) - -### `sizeof(ty)` - -Constant value representing the sizeof the type `ty` - - -## Methods - -The following operations on constants are supported. For more details on -any operation, consult the -[Constant Expressions](http://www.llvm.org/docs/LangRef.html#constantexprs) -section of the LLVM Language Reference. - -### `k.neg()` - -negation, same as `0 - k` - -### `k.not_()` - -1's complement of `k`. Note trailing underscore. - -### `k.add(k2)` - -`k + k2`, where `k` and `k2` are integers. - - -### `k.fadd(k2)` - -`k + k2`, where `k` and `k2` are floating-point. - -### `k.sub(k2)` - -`k - k2`, where `k` and `k2` are integers. - -### `k.fsub(k2)` - -`k - k2`, where `k` and `k2` are floating-point. - -### `k.mul(k2)` - -`k * k2`, where `k` and `k2` are integers. - -### `k.fmul(k2)` - -`k * k2`, where `k` and `k2` are floating-point. - -### `k.udiv(k2)` - -Quotient of unsigned division of `k` with `k2` - -### `k.sdiv(k2)` - -Quotient of signed division of `k` with `k2` - -### `k.fdiv(k2)` - -Quotient of floating point division of `k` with `k2` - -### `k.urem(k2)` - -Reminder of unsigned division of `k` with `k2` - -### `k.srem(k2)` - -Reminder of signed division of `k` with `k2` - -### `k.frem(k2)` - -Reminder of floating point division of `k` with `k2` - -### `k.and_(k2)` - -Bitwise and of `k` and `k2`. Note trailing underscore. - -### `k.or_(k2)` - -Bitwise or of `k` and `k2`. Note trailing underscore. - -### `k.xor(k2)` - -Bitwise exclusive-or of `k` and `k2`. - -### `k.icmp(icmp, k2)` - -Compare `k` with `k2` using the predicate `icmp`. -See [here](comparision.html#icmp) for -list of predicates for integer operands. - -### `k.fcmp(fcmp, k2)` - -Compare `k` with `k2` using the predicate `fcmp`. -See [here](comparision.html#fcmp) for list -of predicates for real operands. - -### `k.shl(k2)` - -Shift `k` left by `k2` bits. - -### `k.lshr(k2)` - -Shift `k` logically right by `k2` bits (new bits are 0s). - -### `k.ashr(k2)` - -Shift `k` arithmetically right by `k2` bits (new bits are same as previous sign bit). - -### `k.gep(indices)` - -GEP, see [LLVM docs](http://www.llvm.org/docs/GetElementPtr.html). - -### `k.trunc(ty)` - -Truncate `k` to a type `ty` of lower bitwidth. - -### `k.sext(ty)` - -Sign extend `k` to a type `ty` of higher bitwidth, while extending the sign bit. - -### `k.zext(ty)` - -Sign extend `k` to a type `ty` of higher bitwidth, all new bits are 0s. - -### `k.fptrunc(ty)` - -Truncate floating point constant `k` to floating point type `ty` of lower size -than k's. - -### `k.fpext(ty)` - -Extend floating point constant `k` to floating point type `ty` of higher size -than k's. - -### `k.uitofp(ty)` - -Convert an unsigned integer constant `k` to floating point constant of -type `ty`. - -### `k.sitofp(ty)` - -Convert a signed integer constant `k` to floating point constant of type `ty`. - -### `k.fptoui(ty)` - -Convert a floating point constant `k` to an unsigned integer constant of type `ty`. - -### `k.fptosi(ty)` - -Convert a floating point constant `k` to a signed integer constant of type `ty`. - -### `k.ptrtoint(ty)` - -Convert a pointer constant `k` to an integer constant of type `ty`. - -### `k.inttoptr(ty)` - -Convert an integer constant `k` to a pointer constant of type `ty`. - -### `k.bitcast(ty)` - -Convert `k` to a (equal-width) constant of type `ty`. - -### `k.select(cond,k2,k3)` - -Replace value with `k2` if the 1-bit integer constant `cond` is 1, -else with `k3`. - -### `k.extract_element(idx)` - -Extract value at `idx` (integer constant) from a vector constant `k`. - -### `k.insert_element(k2,idx)` - -Insert value `k2` (scalar constant) at index `idx` (integer constant) of vector -constant `k`. - -### `k.shuffle_vector(k2,mask)` - -Shuffle vector constant `k` based on vector constants `k2` and `mask`. - -* * * - -# Other Constant Classes - -The following subclasses of `Constant` do not provide additional -methods, **they serve only to provide richer type information.** - - -Subclass | LLVM C++ Class | Remarks | ----------|----------------|---------| -`ConstantExpr` | `llvmConstantExpr` | A constant expression | -`ConstantAggregateZero`| `llvmConstantAggregateZero`| All-zero constant | -`ConstantInt`| `llvmConstantInt`| An integer constant | -`ConstantFP`| `llvmConstantFP`| A floating-point constant | -`ConstantArray`| `llvmConstantArray`| An array constant | -`ConstantStruct`| `llvmConstantStruct`| A structure constant | -`ConstantVector`| `llvmConstantVector`| A vector constant | -`ConstantPointerNull`| `llvmConstantPointerNull`| All-zero pointer constant | -`UndefValue`| `llvmUndefValue`| corresponds to `undef` of LLVM IR | - - -These types are helpful in `isinstance` checks, like so: - -{% highlight python %} -ti = Type.int(32) -k1 = Constant.int(ti, 42) # int32_t k1 = 42; -k2 = Constant.array(ti, [k1, k1]) # int32_t k2[] = { k1, k1 }; - -assert isinstance(k1, ConstantInt) -assert isinstance(k2, ConstantArray) -{% endhighlight %} - diff --git a/docs/source/doc/llvm.core.Constant.rst b/docs/source/doc/llvm.core.Constant.rst new file mode 100644 index 0000000..1656381 --- /dev/null +++ b/docs/source/doc/llvm.core.Constant.rst @@ -0,0 +1,354 @@ ++-------------------------------+ +| layout: page | ++-------------------------------+ +| title: Constant (llvm.core) | ++-------------------------------+ + +``Constant``-s represents constants that appear within the code. The +values of such objects are known at creation time. Constants can be +created from Python constants. A constant expression is also a constant +-- given a ``Constant`` object, an operation (like addition, subtraction +etc) can be specified, to yield a new ``Constant`` object. Let's see +some examples: + +{% highlight python %} #!/usr/bin/env python + +ti = Type.int() # a 32-bit int type + +k1 = Constant.int(ti, 42) # "int k1 = 42;" k2 = k1.add( Constant.int( +ti, 10 ) ) # "int k2 = k1 + 10;" + +tr = Type.float() + +r1 = Constant.real(tr, "3.141592") # create from a string r2 = +Constant.real(tr, 1.61803399) # create from a Python float {% +endhighlight %} + +llvm.core.Constant +================== + +- This will become a table of contents (this text will be scraped). + {:toc} + +Static factory methods +---------------------- + +``null(ty)`` +~~~~~~~~~~~~ + +A null value (all zeros) of type ``ty`` + +``all_ones(ty)`` +~~~~~~~~~~~~~~~~ + +All 1's value of type ``ty`` + +``undef(ty)`` +~~~~~~~~~~~~~ + +An undefined value of type ``ty`` + +``int(ty, value)`` +~~~~~~~~~~~~~~~~~~ + +Integer of type ``ty``, with value ``value`` (a Python int or long) + +``int_signextend(ty, value)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Integer of signed type ``ty`` (use for signed types) + +``real(ty, value)`` +~~~~~~~~~~~~~~~~~~~ + +Floating point value of type ``ty``, with value ``value`` (a Python +float) + +``stringz(value)`` +~~~~~~~~~~~~~~~~~~ + +A null-terminated string. ``value`` is a Python string + +``string(value)`` +~~~~~~~~~~~~~~~~~ + +As ``string(ty)``, but not null terminated + +``array(ty, consts)`` +~~~~~~~~~~~~~~~~~~~~~ + +Array of type ``ty``, initialized with ``consts`` (an iterable yielding +``Constant`` objects of the appropriate type) + +``struct(ty, consts)`` +~~~~~~~~~~~~~~~~~~~~~~ + +Struct (unpacked) of type ``ty``, initialized with ``consts`` (an +iterable yielding ``Constant`` objects of the appropriate type) + +``packed_struct(ty, consts)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +As ``struct(ty, consts)`` but packed + +``vector(consts)`` +~~~~~~~~~~~~~~~~~~ + +Vector, initialized with ``consts`` (an iterable yielding ``Constant`` +objects of the appropriate type) + +``sizeof(ty)`` +~~~~~~~~~~~~~~ + +Constant value representing the sizeof the type ``ty`` + +Methods +------- + +The following operations on constants are supported. For more details on +any operation, consult the `Constant +Expressions `_ +section of the LLVM Language Reference. + +``k.neg()`` +~~~~~~~~~~~ + +negation, same as ``0 - k`` + +``k.not_()`` +~~~~~~~~~~~~ + +1's complement of ``k``. Note trailing underscore. + +``k.add(k2)`` +~~~~~~~~~~~~~ + +``k + k2``, where ``k`` and ``k2`` are integers. + +``k.fadd(k2)`` +~~~~~~~~~~~~~~ + +``k + k2``, where ``k`` and ``k2`` are floating-point. + +``k.sub(k2)`` +~~~~~~~~~~~~~ + +``k - k2``, where ``k`` and ``k2`` are integers. + +``k.fsub(k2)`` +~~~~~~~~~~~~~~ + +``k - k2``, where ``k`` and ``k2`` are floating-point. + +``k.mul(k2)`` +~~~~~~~~~~~~~ + +``k * k2``, where ``k`` and ``k2`` are integers. + +``k.fmul(k2)`` +~~~~~~~~~~~~~~ + +``k * k2``, where ``k`` and ``k2`` are floating-point. + +``k.udiv(k2)`` +~~~~~~~~~~~~~~ + +Quotient of unsigned division of ``k`` with ``k2`` + +``k.sdiv(k2)`` +~~~~~~~~~~~~~~ + +Quotient of signed division of ``k`` with ``k2`` + +``k.fdiv(k2)`` +~~~~~~~~~~~~~~ + +Quotient of floating point division of ``k`` with ``k2`` + +``k.urem(k2)`` +~~~~~~~~~~~~~~ + +Reminder of unsigned division of ``k`` with ``k2`` + +``k.srem(k2)`` +~~~~~~~~~~~~~~ + +Reminder of signed division of ``k`` with ``k2`` + +``k.frem(k2)`` +~~~~~~~~~~~~~~ + +Reminder of floating point division of ``k`` with ``k2`` + +``k.and_(k2)`` +~~~~~~~~~~~~~~ + +Bitwise and of ``k`` and ``k2``. Note trailing underscore. + +``k.or_(k2)`` +~~~~~~~~~~~~~ + +Bitwise or of ``k`` and ``k2``. Note trailing underscore. + +``k.xor(k2)`` +~~~~~~~~~~~~~ + +Bitwise exclusive-or of ``k`` and ``k2``. + +``k.icmp(icmp, k2)`` +~~~~~~~~~~~~~~~~~~~~ + +Compare ``k`` with ``k2`` using the predicate ``icmp``. See +`here `_ for list of predicates for integer +operands. + +``k.fcmp(fcmp, k2)`` +~~~~~~~~~~~~~~~~~~~~ + +Compare ``k`` with ``k2`` using the predicate ``fcmp``. See +`here `_ for list of predicates for real +operands. + +``k.shl(k2)`` +~~~~~~~~~~~~~ + +Shift ``k`` left by ``k2`` bits. + +``k.lshr(k2)`` +~~~~~~~~~~~~~~ + +Shift ``k`` logically right by ``k2`` bits (new bits are 0s). + +``k.ashr(k2)`` +~~~~~~~~~~~~~~ + +Shift ``k`` arithmetically right by ``k2`` bits (new bits are same as +previous sign bit). + +``k.gep(indices)`` +~~~~~~~~~~~~~~~~~~ + +GEP, see `LLVM docs `_. + +``k.trunc(ty)`` +~~~~~~~~~~~~~~~ + +Truncate ``k`` to a type ``ty`` of lower bitwidth. + +``k.sext(ty)`` +~~~~~~~~~~~~~~ + +Sign extend ``k`` to a type ``ty`` of higher bitwidth, while extending +the sign bit. + +``k.zext(ty)`` +~~~~~~~~~~~~~~ + +Sign extend ``k`` to a type ``ty`` of higher bitwidth, all new bits are +0s. + +``k.fptrunc(ty)`` +~~~~~~~~~~~~~~~~~ + +Truncate floating point constant ``k`` to floating point type ``ty`` of +lower size than k's. + +``k.fpext(ty)`` +~~~~~~~~~~~~~~~ + +Extend floating point constant ``k`` to floating point type ``ty`` of +higher size than k's. + +``k.uitofp(ty)`` +~~~~~~~~~~~~~~~~ + +Convert an unsigned integer constant ``k`` to floating point constant of +type ``ty``. + +``k.sitofp(ty)`` +~~~~~~~~~~~~~~~~ + +Convert a signed integer constant ``k`` to floating point constant of +type ``ty``. + +``k.fptoui(ty)`` +~~~~~~~~~~~~~~~~ + +Convert a floating point constant ``k`` to an unsigned integer constant +of type ``ty``. + +``k.fptosi(ty)`` +~~~~~~~~~~~~~~~~ + +Convert a floating point constant ``k`` to a signed integer constant of +type ``ty``. + +``k.ptrtoint(ty)`` +~~~~~~~~~~~~~~~~~~ + +Convert a pointer constant ``k`` to an integer constant of type ``ty``. + +``k.inttoptr(ty)`` +~~~~~~~~~~~~~~~~~~ + +Convert an integer constant ``k`` to a pointer constant of type ``ty``. + +``k.bitcast(ty)`` +~~~~~~~~~~~~~~~~~ + +Convert ``k`` to a (equal-width) constant of type ``ty``. + +``k.select(cond,k2,k3)`` +~~~~~~~~~~~~~~~~~~~~~~~~ + +Replace value with ``k2`` if the 1-bit integer constant ``cond`` is 1, +else with ``k3``. + +``k.extract_element(idx)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Extract value at ``idx`` (integer constant) from a vector constant +``k``. + +``k.insert_element(k2,idx)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert value ``k2`` (scalar constant) at index ``idx`` (integer +constant) of vector constant ``k``. + +``k.shuffle_vector(k2,mask)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Shuffle vector constant ``k`` based on vector constants ``k2`` and +``mask``. + +-------------- + +Other Constant Classes +====================== + +The following subclasses of ``Constant`` do not provide additional +methods, **they serve only to provide richer type information.** + +Subclass \| LLVM C++ Class \| Remarks \| +---------\|----------------\|---------\| ``ConstantExpr`` \| +``llvmConstantExpr`` \| A constant expression \| +``ConstantAggregateZero``\ \| ``llvmConstantAggregateZero``\ \| All-zero +constant \| ``ConstantInt``\ \| ``llvmConstantInt``\ \| An integer +constant \| ``ConstantFP``\ \| ``llvmConstantFP``\ \| A floating-point +constant \| ``ConstantArray``\ \| ``llvmConstantArray``\ \| An array +constant \| ``ConstantStruct``\ \| ``llvmConstantStruct``\ \| A +structure constant \| ``ConstantVector``\ \| ``llvmConstantVector``\ \| +A vector constant \| ``ConstantPointerNull``\ \| +``llvmConstantPointerNull``\ \| All-zero pointer constant \| +``UndefValue``\ \| ``llvmUndefValue``\ \| corresponds to ``undef`` of +LLVM IR \| + +These types are helpful in ``isinstance`` checks, like so: + +{% highlight python %} ti = Type.int(32) k1 = Constant.int(ti, 42) # +int32\_t k1 = 42; k2 = Constant.array(ti, [k1, k1]) # int32\_t k2[] = { +k1, k1 }; + +assert isinstance(k1, ConstantInt) assert isinstance(k2, ConstantArray) +{% endhighlight %} diff --git a/docs/source/doc/llvm.core.Function.md b/docs/source/doc/llvm.core.Function.md deleted file mode 100644 index 60e8db9..0000000 --- a/docs/source/doc/llvm.core.Function.md +++ /dev/null @@ -1,129 +0,0 @@ ---- -layout: page -title: Function (llvm.core) ---- - -# llvm.core.Function - -* This will become a table of contents (this text will be scraped). -{:toc} - - -## Base Class - -- [llvm.core.GlobalValue](llvm.core.GlobalValue.html) - -## Static Constructors - -### `new(module_obj, func_ty, name)` - -Create a function named `name` of type `func_ty` in the module -`module_obj` and return a `Function` object that represents it. - -### `get(module_obj, name)` - -Return a `Function` object to represent the function -named `name` in the module `module_obj` or raise `LLVMException` if -such a function does not exist. - -### `get_or_insert(module_obj, func_ty, name)` - -Similar to `get`, except that if the function does not exist it -is added first, as though with `new`. - -### `intrinsic(module_obj, intrinsic_id, types)` - -Create and return a `Function` object that refers to an intrinsic -function, as described [here](functions.html#intrinsic). - -## Properties - -### `calling_convention` - -The calling convention for the function, -as listed [here](functions.html#callconv). - -### `collector` - -A string holding the name of the garbage collection algorithm. -See [LLVM docs](http://www.llvm.org/docs/LangRef.html#gc). - -### `does_not_throw` - -Setting to True sets the `ATTR_NO_UNWIND` attribute, False -removes it. Shortcut to using `f.add_attribute(ATTR_NO_UNWIND)` -and `f.remove_attribute(ATTR_NO_UNWIND)`. - -### `args` - -\[read-only\] - -List of [llvm.core.Argument][] objects representing the formal -arguments of the function. - -### `basic_block_count` - -\[read-only\] - -Number of basic blocks belonging to this function. Same as -`len(f.basic_blocks)` but faster if you just want the count. - -### `entry_basic_block` - -\[read-only\] - -The [llvm.core.BasicBlock][] object representing the entry -basic block for this function, or `None` if there are no -basic blocks. - -### `basic_blocks` - -\[read-only\] - -List of [llvm.core.BasicBlock][] objects representing the -basic blocks belonging to this function. - -### `intrinsic_id` - -\[read-only\] - -Returns the ID of the intrinsic if this object represents an -intrinsic instruction. Otherwise 0. - -## Methods - -### `delete()` - -Deletes the function from it's module. Do not hold any -references to this object after calling `delete` on it. - -### `append_basic_block(name)` - -Add a new basic block named `name`, and return a corresponding -[llvm.core.BasicBlock][] object. Note that if this is not the -entry basic block, you'll have to add appropriate branch -instructions from other basic blocks yourself. - -### `add_attribute(attr)` - -Add an attribute `attr` to the function, from the set listed above. - -### `remove_attribute(attr)` - -Remove the attribute `attr` of the function. - -### `viewCFG()` - -Displays the control flow graph using the GraphViz tool. - -### `viewCFGOnly()` - -Displays the control flow graph using the GraphViz tool, but -omitting function bodies. - -### `verify()` - -Verifies the function. See [LLVM docs](http://llvm.org/docs/Passes.html#verify). - -[llvm.core.Argument]: llvm.core.Argument.html -[llvm.core.BasicBlock]: llvm.core.BasicBlock.html diff --git a/docs/source/doc/llvm.core.Function.rst b/docs/source/doc/llvm.core.Function.rst new file mode 100644 index 0000000..1d6070c --- /dev/null +++ b/docs/source/doc/llvm.core.Function.rst @@ -0,0 +1,151 @@ ++-------------------------------+ +| layout: page | ++-------------------------------+ +| title: Function (llvm.core) | ++-------------------------------+ + +llvm.core.Function +================== + +- This will become a table of contents (this text will be scraped). + {:toc} + +Base Class +---------- + +- `llvm.core.GlobalValue `_ + +Static Constructors +------------------- + +``new(module_obj, func_ty, name)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Create a function named ``name`` of type ``func_ty`` in the module +``module_obj`` and return a ``Function`` object that represents it. + +``get(module_obj, name)`` +~~~~~~~~~~~~~~~~~~~~~~~~~ + +Return a ``Function`` object to represent the function named ``name`` in +the module ``module_obj`` or raise ``LLVMException`` if such a function +does not exist. + +``get_or_insert(module_obj, func_ty, name)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Similar to ``get``, except that if the function does not exist it is +added first, as though with ``new``. + +``intrinsic(module_obj, intrinsic_id, types)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Create and return a ``Function`` object that refers to an intrinsic +function, as described `here `_. + +Properties +---------- + +``calling_convention`` +~~~~~~~~~~~~~~~~~~~~~~ + +The calling convention for the function, as listed +`here `_. + +``collector`` +~~~~~~~~~~~~~ + +A string holding the name of the garbage collection algorithm. See `LLVM +docs `_. + +``does_not_throw`` +~~~~~~~~~~~~~~~~~~ + +Setting to True sets the ``ATTR_NO_UNWIND`` attribute, False removes it. +Shortcut to using ``f.add_attribute(ATTR_NO_UNWIND)`` and +``f.remove_attribute(ATTR_NO_UNWIND)``. + +``args`` +~~~~~~~~ + +[read-only] + +List of `llvm.core.Argument `_ objects +representing the formal arguments of the function. + +``basic_block_count`` +~~~~~~~~~~~~~~~~~~~~~ + +[read-only] + +Number of basic blocks belonging to this function. Same as +``len(f.basic_blocks)`` but faster if you just want the count. + +``entry_basic_block`` +~~~~~~~~~~~~~~~~~~~~~ + +[read-only] + +The `llvm.core.BasicBlock `_ object +representing the entry basic block for this function, or ``None`` if +there are no basic blocks. + +``basic_blocks`` +~~~~~~~~~~~~~~~~ + +[read-only] + +List of `llvm.core.BasicBlock `_ objects +representing the basic blocks belonging to this function. + +``intrinsic_id`` +~~~~~~~~~~~~~~~~ + +[read-only] + +Returns the ID of the intrinsic if this object represents an intrinsic +instruction. Otherwise 0. + +Methods +------- + +``delete()`` +~~~~~~~~~~~~ + +Deletes the function from it's module. Do not hold any references to +this object after calling ``delete`` on it. + +``append_basic_block(name)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Add a new basic block named ``name``, and return a corresponding +`llvm.core.BasicBlock `_ object. Note that if +this is not the entry basic block, you'll have to add appropriate branch +instructions from other basic blocks yourself. + +``add_attribute(attr)`` +~~~~~~~~~~~~~~~~~~~~~~~ + +Add an attribute ``attr`` to the function, from the set listed above. + +``remove_attribute(attr)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Remove the attribute ``attr`` of the function. + +``viewCFG()`` +~~~~~~~~~~~~~ + +Displays the control flow graph using the GraphViz tool. + +``viewCFGOnly()`` +~~~~~~~~~~~~~~~~~ + +Displays the control flow graph using the GraphViz tool, but omitting +function bodies. + +``verify()`` +~~~~~~~~~~~~ + +Verifies the function. See `LLVM +docs `_. diff --git a/docs/source/doc/llvm.core.FunctionType.md b/docs/source/doc/llvm.core.FunctionType.md deleted file mode 100644 index 26cf40b..0000000 --- a/docs/source/doc/llvm.core.FunctionType.md +++ /dev/null @@ -1,53 +0,0 @@ ---- -layout: page -title: FunctionType (llvm.core) ---- - -# llvm.core.FunctionType - -## Base Class - -- [llvm.core.Type](llvm.core.Type.html) - -## Properties - -### `return_type` - - -\[read-only\] - -A [Type][llvm.core.Type] object, representing the return type of the function. - -### `vararg` - - -\[read-only\] - -`True` if the function is variadic. - -### `args` - - -\[read-only\] - -Returns an iterable object that yields [Type][llvm.core.Type] objects that -represent, in order, the types of the arguments accepted by the -function. Used like this: - -{% highlight python %} -func_type = Type.function( Type.int(), [ Type.int(), Type.int() ] ) -for arg in func_type.args: - assert arg.kind == TYPE_INTEGER - assert arg == Type.int() -assert func_type.arg_count == len(func_type.args) -{% endhighlight %} - - -### `arg_count` - - -\[read-only\] - -The number of arguments. Same as `len(obj.args)`, but faster. - -[llvm.core.Type]: llvm.core.Type.html diff --git a/docs/source/doc/llvm.core.FunctionType.rst b/docs/source/doc/llvm.core.FunctionType.rst new file mode 100644 index 0000000..6704ebe --- /dev/null +++ b/docs/source/doc/llvm.core.FunctionType.rst @@ -0,0 +1,52 @@ ++-----------------------------------+ +| layout: page | ++-----------------------------------+ +| title: FunctionType (llvm.core) | ++-----------------------------------+ + +llvm.core.FunctionType +====================== + +Base Class +---------- + +- `llvm.core.Type `_ + +Properties +---------- + +``return_type`` +~~~~~~~~~~~~~~~ + +[read-only] + +A `Type `_ object, representing the return type of +the function. + +``vararg`` +~~~~~~~~~~ + +[read-only] + +``True`` if the function is variadic. + +``args`` +~~~~~~~~ + +[read-only] + +Returns an iterable object that yields `Type `_ +objects that represent, in order, the types of the arguments accepted by +the function. Used like this: + +{% highlight python %} func\_type = Type.function( Type.int(), [ +Type.int(), Type.int() ] ) for arg in func\_type.args: assert arg.kind +== TYPE\_INTEGER assert arg == Type.int() assert func\_type.arg\_count +== len(func\_type.args) {% endhighlight %} + +``arg_count`` +~~~~~~~~~~~~~ + +[read-only] + +The number of arguments. Same as ``len(obj.args)``, but faster. diff --git a/docs/source/doc/llvm.core.GlobalValue.md b/docs/source/doc/llvm.core.GlobalValue.md deleted file mode 100644 index 5d46a2e..0000000 --- a/docs/source/doc/llvm.core.GlobalValue.md +++ /dev/null @@ -1,99 +0,0 @@ ---- -layout: page -title: GlobalValue (llvm.core) ---- - -The class `llvm.core.GlobalValue` represents module-scope aliases, variables -and functions. Global variables are represented by the sub-class -[llvm.core.GlobalVariable][] and functions by [llvm.core.Function][]. - -Global values have the read-write properties `linkage`, `section`, -`visibility` and `alignment`. Use one of the following constants (from -llvm.core) as values for `linkage` -(see [LLVM documentaion](http://www.llvm.org/docs/LangRef.html#linkage) for -details on each): - - -Value | Equivalent LLVM Assembly Keyword | -------|----------------------------------| -`LINKAGE_EXTERNAL` | `externally_visible` | -`LINKAGE_AVAILABLE_EXTERNALLY` | `available_externally` | -`LINKAGE_LINKONCE_ANY` | `linkonce` | -`LINKAGE_LINKONCE_ODR` | `linkonce_odr` | -`LINKAGE_WEAK_ANY` | `weak` | -`LINKAGE_WEAK_ODR` | `weak_odr` | -`LINKAGE_APPENDING` | `appending` | -`LINKAGE_INTERNAL` | `internal` | -`LINKAGE_PRIVATE` | `private` | -`LINKAGE_DLLIMPORT` | `dllimport` | -`LINKAGE_DLLEXPORT` | `dllexport` | -`LINKAGE_EXTERNAL_WEAK` | `extern_weak` | -`LINKAGE_GHOST` | deprecated -- do not use | -`LINKAGE_COMMON` | `common` | -`LINKAGE_LINKER_PRIVATE` | `linker_private` | - -
- -The `section` property can be assigned strings (like ".rodata"), which -will be used if the target supports it. Visibility property can be set -to one of thse constants (from llvm.core, see also -[LLVM docs](http://www.llvm.org/docs/LangRef.html#visibility)): - - -Value | Equivalent LLVM Assembly Keyword | -------|----------------------------------| -`VISIBILITY_DEFAULT` | `default` | -`VISIBILITY_HIDDEN` | `hidden` | -`VISIBILITY_PROTECTED` | `protected` | - -
- - -The `alignment` property can be 0 (default), or can be set to a power of 2. -The read-only property `is_declaration` can be used to check if the -global is a declaration or not. The module to which the global belongs -to can be retrieved using the `module` property (read-only). - -# llvm.core.GlobalValue - - -* This will become a table of contents (this text will be scraped). -{:toc} - - -## Base Class - -- [llvm.core.Constant](llvm.core.Constant.html) - -## Properties - -### `linkage` - -The linkage type, takes one of the constants listed above (LINKAGE_\*). - -### `section` - -A string like ".rodata", indicating the section into which the -global is placed into. - -### `visibility` - -The visibility type, takes one of the constants listed above (VISIBILITY_\*). - -### `alignment` - -A power-of-2 integer indicating the boundary to align to. - -### `is_declaration` -\[read-only\] - -`True` if the global is a declaration, `False` otherwise. - -### `module` -\[read-only\] - - The module object to which this global belongs to. - -[llvm.core.GlobalVariable]: llvm.core.GlobalVariable.html -[llvm.core.Function]: llvm.core.Function.html - diff --git a/docs/source/doc/llvm.core.GlobalValue.rst b/docs/source/doc/llvm.core.GlobalValue.rst new file mode 100644 index 0000000..70dee7b --- /dev/null +++ b/docs/source/doc/llvm.core.GlobalValue.rst @@ -0,0 +1,97 @@ ++----------------------------------+ +| layout: page | ++----------------------------------+ +| title: GlobalValue (llvm.core) | ++----------------------------------+ + +The class ``llvm.core.GlobalValue`` represents module-scope aliases, +variables and functions. Global variables are represented by the +sub-class `llvm.core.GlobalVariable `_ +and functions by `llvm.core.Function `_. + +Global values have the read-write properties ``linkage``, ``section``, +``visibility`` and ``alignment``. Use one of the following constants +(from llvm.core) as values for ``linkage`` (see `LLVM +documentaion `_ for +details on each): + +Value \| Equivalent LLVM Assembly Keyword \| +------\|----------------------------------\| ``LINKAGE_EXTERNAL`` \| +``externally_visible`` \| ``LINKAGE_AVAILABLE_EXTERNALLY`` \| +``available_externally`` \| ``LINKAGE_LINKONCE_ANY`` \| ``linkonce`` \| +``LINKAGE_LINKONCE_ODR`` \| ``linkonce_odr`` \| ``LINKAGE_WEAK_ANY`` \| +``weak`` \| ``LINKAGE_WEAK_ODR`` \| ``weak_odr`` \| +``LINKAGE_APPENDING`` \| ``appending`` \| ``LINKAGE_INTERNAL`` \| +``internal`` \| ``LINKAGE_PRIVATE`` \| ``private`` \| +``LINKAGE_DLLIMPORT`` \| ``dllimport`` \| ``LINKAGE_DLLEXPORT`` \| +``dllexport`` \| ``LINKAGE_EXTERNAL_WEAK`` \| ``extern_weak`` \| +``LINKAGE_GHOST`` \| deprecated -- do not use \| ``LINKAGE_COMMON`` \| +``common`` \| ``LINKAGE_LINKER_PRIVATE`` \| ``linker_private`` \| + +The ``section`` property can be assigned strings (like ".rodata"), which +will be used if the target supports it. Visibility property can be set +to one of thse constants (from llvm.core, see also `LLVM +docs `_): + +Value \| Equivalent LLVM Assembly Keyword \| +------\|----------------------------------\| ``VISIBILITY_DEFAULT`` \| +``default`` \| ``VISIBILITY_HIDDEN`` \| ``hidden`` \| +``VISIBILITY_PROTECTED`` \| ``protected`` \| + +The ``alignment`` property can be 0 (default), or can be set to a power +of 2. The read-only property ``is_declaration`` can be used to check if +the global is a declaration or not. The module to which the global +belongs to can be retrieved using the ``module`` property (read-only). + +llvm.core.GlobalValue +===================== + +- This will become a table of contents (this text will be scraped). + {:toc} + +Base Class +---------- + +- `llvm.core.Constant `_ + +Properties +---------- + +``linkage`` +~~~~~~~~~~~ + +The linkage type, takes one of the constants listed above (LINKAGE\_\*). + +``section`` +~~~~~~~~~~~ + +A string like ".rodata", indicating the section into which the global is +placed into. + +``visibility`` +~~~~~~~~~~~~~~ + +The visibility type, takes one of the constants listed above +(VISIBILITY\_\*). + +``alignment`` +~~~~~~~~~~~~~ + +A power-of-2 integer indicating the boundary to align to. + +``is_declaration`` +~~~~~~~~~~~~~~~~~~ + +[read-only] + +``True`` if the global is a declaration, ``False`` otherwise. + +``module`` +~~~~~~~~~~ + +[read-only] + +:: + + The module object to which this global belongs to. + diff --git a/docs/source/doc/llvm.core.GlobalVariable.md b/docs/source/doc/llvm.core.GlobalVariable.md deleted file mode 100644 index 05792a0..0000000 --- a/docs/source/doc/llvm.core.GlobalVariable.md +++ /dev/null @@ -1,94 +0,0 @@ ---- -layout: page -title: GlobalVariable (llvm.core) ---- - -Global variables (`llvm.core.GlobalVariable`) are subclasses of -[llvm.core.GlobalValue][] and represent module-level variables. These can -have optional initializers and can be marked as constants. Global -variables can be created either by using the `add_global_variable` -method of the [Module][llvm.core.Module] class, or by using the static method -`GlobalVariable.new`. - -{% highlight python %} -# create a global variable using add_global_variable method -gv1 = module_obj.add_global_variable(Type.int(), "gv1") - -# or equivalently, using a static constructor method -gv2 = GlobalVariable.new(module_obj, Type.int(), "gv2") -{% endhighlight %} - -Existing global variables of a module can be accessed by name using -`module_obj.get_global_variable_named(name)` or `GlobalVariable.get`. -All existing global variables can be enumerated via iterating over the -property `module_obj.global_variables`. - -{% highlight python %} -# retrieve a reference to the global variable gv1, -# using the get_global_variable_named method -gv1 = module_obj.get_global_variable_named("gv1") - -# or equivalently, using the static `get` method: -gv2 = GlobalVariable.get(module_obj, "gv2") - -# list all global variables in a module -for gv in module_obj.global_variables: - print gv.name, "of type", gv.type -{% endhighlight %} - -The initializer for a global variable can be set by assigning to the -`initializer` property of the object. The `is_global_constant` property -can be used to indicate that the variable is a global constant. - -Global variables can be delete using the `delete` method. Do not use the -object after calling `delete` on it. - -{% highlight python %} -# add an initializer 10 (32-bit integer) -gv.initializer = Constant.int( Type.int(), 10 ) - -# delete the global -gv.delete() -# DO NOT dereference `gv' beyond this point! -gv = None -{% endhighlight %} - -# llvm.core.GlobalVariable -## Base Class - -- [llvm.core.GlobalValue](llvm.core.GlobalValue.html) - -## Static Constructors - -### `new(module_obj, ty, name)` - -Create a global variable named `name` of type `ty` in the module -`module_obj` and return a `GlobalVariable` object that represents it. - -### `get(module_obj, name)` - -Return a `GlobalVariable` object to represent the global variable -named `name` in the module `module_obj` or raise `LLVMException` if -such a variable does not exist. - -## Properties - -### `initializer` - -The intializer of the variable. Set to [llvm.core.Constant][] (or -derived). Gets the initializer constant, or `None` if none exists. -`global_constant` -`True` if the variable is a global constant, `False` otherwise. - -## Methods - -### `delete()` -Deletes the global variable from it's module. -**Do not hold any references to this object after calling `delete` on it.** - - -[llvm.core.Module]: llvm.core.Module.html -[llvm.core.Constant]: llvm.core.Constant.html -[llvm.core.GlobalValue]: llvm.core.GlobalValue.html - - diff --git a/docs/source/doc/llvm.core.GlobalVariable.rst b/docs/source/doc/llvm.core.GlobalVariable.rst new file mode 100644 index 0000000..bee596d --- /dev/null +++ b/docs/source/doc/llvm.core.GlobalVariable.rst @@ -0,0 +1,103 @@ ++-------------------------------------+ +| layout: page | ++-------------------------------------+ +| title: GlobalVariable (llvm.core) | ++-------------------------------------+ + +Global variables (``llvm.core.GlobalVariable``) are subclasses of +`llvm.core.GlobalValue `_ and represent +module-level variables. These can have optional initializers and can be +marked as constants. Global variables can be created either by using the +``add_global_variable`` method of the `Module `_ +class, or by using the static method ``GlobalVariable.new``. + +{% highlight python %} # create a global variable using +add\_global\_variable method gv1 = +module\_obj.add\_global\_variable(Type.int(), "gv1") + +or equivalently, using a static constructor method +================================================== + +gv2 = GlobalVariable.new(module\_obj, Type.int(), "gv2") {% endhighlight +%} + +Existing global variables of a module can be accessed by name using +``module_obj.get_global_variable_named(name)`` or +``GlobalVariable.get``. All existing global variables can be enumerated +via iterating over the property ``module_obj.global_variables``. + +{% highlight python %} # retrieve a reference to the global variable +gv1, # using the get\_global\_variable\_named method gv1 = +module\_obj.get\_global\_variable\_named("gv1") + +or equivalently, using the static ``get`` method: +================================================= + +gv2 = GlobalVariable.get(module\_obj, "gv2") + +list all global variables in a module +===================================== + +for gv in module\_obj.global\_variables: print gv.name, "of type", +gv.type {% endhighlight %} + +The initializer for a global variable can be set by assigning to the +``initializer`` property of the object. The ``is_global_constant`` +property can be used to indicate that the variable is a global constant. + +Global variables can be delete using the ``delete`` method. Do not use +the object after calling ``delete`` on it. + +{% highlight python %} # add an initializer 10 (32-bit integer) +gv.initializer = Constant.int( Type.int(), 10 ) + +delete the global +================= + +gv.delete() # DO NOT dereference \`gv' beyond this point! gv = None {% +endhighlight %} + +llvm.core.GlobalVariable +======================== + +Base Class +---------- + +- `llvm.core.GlobalValue `_ + +Static Constructors +------------------- + +``new(module_obj, ty, name)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Create a global variable named ``name`` of type ``ty`` in the module +``module_obj`` and return a ``GlobalVariable`` object that represents +it. + +``get(module_obj, name)`` +~~~~~~~~~~~~~~~~~~~~~~~~~ + +Return a ``GlobalVariable`` object to represent the global variable +named ``name`` in the module ``module_obj`` or raise ``LLVMException`` +if such a variable does not exist. + +Properties +---------- + +``initializer`` +~~~~~~~~~~~~~~~ + +The intializer of the variable. Set to +`llvm.core.Constant `_ (or derived). Gets the +initializer constant, or ``None`` if none exists. ``global_constant`` +``True`` if the variable is a global constant, ``False`` otherwise. + +Methods +------- + +``delete()`` +~~~~~~~~~~~~ + +Deletes the global variable from it's module. **Do not hold any +references to this object after calling ``delete`` on it.** diff --git a/docs/source/doc/llvm.core.Instruction.md b/docs/source/doc/llvm.core.Instruction.md deleted file mode 100644 index cef3041..0000000 --- a/docs/source/doc/llvm.core.Instruction.md +++ /dev/null @@ -1,215 +0,0 @@ ---- -layout: page -title: Instruction (llvm.core) ---- - -An `llvm.core.Instruction` object represents an LLVM instruction. This -class is the root of a small hierarchy: - - - Instruction - CallOrInvokeInstruction - PHINode - SwitchInstruction - CompareInstruction - - -Instructions are not created directly, but via a builder. The builder -both creates instructions and adds them to a basic block at the same -time. One way of getting instruction objects are from basic blocks. - -Being derived from [llvm.core.User][], the instruction -is-a user, i.e., an instruction in turn uses other values. The values -an instruction uses are its operands. These may be accessed using -`operands` property from the [llvm.core.User][] base. - -The name of the instruction (like `add`, `mul` etc) can be got -via the `opcode_name` property. The `basic_block` property gives -the basic block to which the instruction belongs to. Note that -llvm-py does not allow free-standing instruction objects (i.e., -all instructions are created contained within a basic block). - -Classes of instructions can be got via the properties -`is_terminator`, `is_binary_op`, `is_shift` etc. See below for -the full list. - - - -* This will become a table of contents (this text will be scraped). -{:toc} - - -# llvm.core.Instruction - -## Base Class - -- [llvm.core.User](llvm.core.User.html) - -## Properties - -### `basic_block` -\[read-only\] -The basic block to which this instruction belongs to. - -### `is_terminator` -\[read-only\] -True if the instruction is a terminator instruction. - -### `is_binary_op` -\[read-only\] -True if the instruction is a binary operator. - -### `is_shift` -\[read-only\] -True if the instruction is a shift instruction. - -### `is_cast` -\[read-only\] -True if the instruction is a cast instruction. - -### `is_logical_shift` -\[read-only\] -True if the instruction is a logical shift instruction. - -### `is_arithmetic_shift` -\[read-only\] -True if the instruction is an arithmetic shift instruction. - -### `is_associative` -\[read-only\] -True if the instruction is associative. - -### `is_commutative` -\[read-only\] -True if the instruction is commutative. - -### `is_volatile` -\[read-only\] -True if the instruction is a volatile load or store. - -### `opcode` -\[read-only\] -The numeric opcode value of the instruction. Do not rely -on the absolute value of this number, it may change with -LLVM version. - -### `opcode_name` -\[read-only\] -The name of the instruction, like `add`, `sub` etc. - -* * * - -# llvm.core.CallOrInvokeInstruction - -The `llvm.core.CallOrInvokeInstruction` is a subclass of -`llvm.core.Instruction`, and represents either a `call` or an -`invoke` instruction. - -## Base Class - -- `llvm.core.Instruction` - -## Properties - -`calling_convention` - Get or set the calling convention. See [here](functions.html#callconv) - for possible values. - -## Methods - -### `add_parameter_attribute(idx, attr)` - -Add an attribute `attr` to the `idx`-th argument. See -[here](llvm.core.Argument.html) for possible values of `attr`. - -### `remove_parameter_attribute(idx, attr)` - -Remove an attribute `attr` from the `idx`-th argument. See -[here](llvm.core.Argument.html) for possible values of `attr`. - -### `set_parameter_alignment(idx, align)` - -Set the alignment of the `idx`-th argument to `align`. -`align` should be a power of two. - -* * * - -# llvm.core.PHINode - -The `llvm.core.PHINode` is a subclass of -`llvm.core.Instruction`, and represents the `phi` instruction. When -created (using `Builder.phi`) the phi node contains no incoming -blocks (nor their corresponding values). To add an incoming arc to -the phi node, use the `add_incoming` method, which takes a source -block ([llvm.core.BasicBlock][] object) and a value (object of -[llvm.core.Value][] or of a class derived from it) that the phi node -will take on if control branches in from that block. - - -## Base Class - -- `llvm.core.Instruction` - -## Properties -`incoming_count` -\[read-only\] - The number of incoming arcs for this phi node. - -## Methods - -### `add_incoming(value, block)` - -Add an incoming arc, from the [llvm.core.BasicBlock][] object -`block`, with the corresponding value `value`. `value` should -be an object of [llvm.core.Value][] (or of a descendent class). - -### `get_incoming_value(idx)` - -Returns the `idx`-th incoming arc's value. - -### `get_incoming_block(idx)` - -Returns the `idx`-th incoming arc's block. - - -# llvm.core.SwitchInstruction # {#switchinstr} - -(TODO describe) - -## Base Class - -- `llvm.core.Instruction` - -## Methods - -### `add_case(const, block)` -Add another case to the switch statement. When the expression -being evaluated equals `const`, then control branches to -`block`. Here `const` must be of type -[llvm.core.ConstantInt][llvm.core.Constant]. - -* * * - -# llvm.core.CompareInstruction - -(TODO describe) - -## Base Class - -- `llvm.core.Instruction` - -## Properties - -###`predicate` -\[read-only\] - -The predicate of the compare instruction, one of the `ICMP_*` or -`FCMP_*` constants. - - -[llvm.core.User]: llvm.core.User.html -[llvm.core.BasicBlock]: llvm.core.BasicBlock.html -[llvm.core.Value]: llvm.core.Value.html -[llvm.core.Constant]: llvm.core.Constant.html - - diff --git a/docs/source/doc/llvm.core.Instruction.rst b/docs/source/doc/llvm.core.Instruction.rst new file mode 100644 index 0000000..b03ce33 --- /dev/null +++ b/docs/source/doc/llvm.core.Instruction.rst @@ -0,0 +1,242 @@ ++----------------------------------+ +| layout: page | ++----------------------------------+ +| title: Instruction (llvm.core) | ++----------------------------------+ + +An ``llvm.core.Instruction`` object represents an LLVM instruction. This +class is the root of a small hierarchy: + +:: + + Instruction + CallOrInvokeInstruction + PHINode + SwitchInstruction + CompareInstruction + +Instructions are not created directly, but via a builder. The builder +both creates instructions and adds them to a basic block at the same +time. One way of getting instruction objects are from basic blocks. + +Being derived from `llvm.core.User `_, the +instruction is-a user, i.e., an instruction in turn uses other values. +The values an instruction uses are its operands. These may be accessed +using ``operands`` property from the +`llvm.core.User `_ base. + +The name of the instruction (like ``add``, ``mul`` etc) can be got via +the ``opcode_name`` property. The ``basic_block`` property gives the +basic block to which the instruction belongs to. Note that llvm-py does +not allow free-standing instruction objects (i.e., all instructions are +created contained within a basic block). + +Classes of instructions can be got via the properties ``is_terminator``, +``is_binary_op``, ``is_shift`` etc. See below for the full list. + +- This will become a table of contents (this text will be scraped). + {:toc} + +llvm.core.Instruction +===================== + +Base Class +---------- + +- `llvm.core.User `_ + +Properties +---------- + +``basic_block`` +~~~~~~~~~~~~~~~ + +[read-only] The basic block to which this instruction belongs to. + +``is_terminator`` +~~~~~~~~~~~~~~~~~ + +[read-only] True if the instruction is a terminator instruction. + +``is_binary_op`` +~~~~~~~~~~~~~~~~ + +[read-only] True if the instruction is a binary operator. + +``is_shift`` +~~~~~~~~~~~~ + +[read-only] True if the instruction is a shift instruction. + +``is_cast`` +~~~~~~~~~~~ + +[read-only] True if the instruction is a cast instruction. + +``is_logical_shift`` +~~~~~~~~~~~~~~~~~~~~ + +[read-only] True if the instruction is a logical shift instruction. + +``is_arithmetic_shift`` +~~~~~~~~~~~~~~~~~~~~~~~ + +[read-only] True if the instruction is an arithmetic shift instruction. + +``is_associative`` +~~~~~~~~~~~~~~~~~~ + +[read-only] True if the instruction is associative. + +``is_commutative`` +~~~~~~~~~~~~~~~~~~ + +[read-only] True if the instruction is commutative. + +``is_volatile`` +~~~~~~~~~~~~~~~ + +[read-only] True if the instruction is a volatile load or store. + +``opcode`` +~~~~~~~~~~ + +[read-only] The numeric opcode value of the instruction. Do not rely on +the absolute value of this number, it may change with LLVM version. + +``opcode_name`` +~~~~~~~~~~~~~~~ + +[read-only] The name of the instruction, like ``add``, ``sub`` etc. + +-------------- + +llvm.core.CallOrInvokeInstruction +================================= + +The ``llvm.core.CallOrInvokeInstruction`` is a subclass of +``llvm.core.Instruction``, and represents either a ``call`` or an +``invoke`` instruction. + +Base Class +---------- + +- ``llvm.core.Instruction`` + +Properties +---------- + +``calling_convention`` Get or set the calling convention. See +`here `_ for possible values. + +Methods +------- + +``add_parameter_attribute(idx, attr)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Add an attribute ``attr`` to the ``idx``-th argument. See +`here `_ for possible values of ``attr``. + +``remove_parameter_attribute(idx, attr)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Remove an attribute ``attr`` from the ``idx``-th argument. See +`here `_ for possible values of ``attr``. + +``set_parameter_alignment(idx, align)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Set the alignment of the ``idx``-th argument to ``align``. ``align`` +should be a power of two. + +-------------- + +llvm.core.PHINode +================= + +The ``llvm.core.PHINode`` is a subclass of ``llvm.core.Instruction``, +and represents the ``phi`` instruction. When created (using +``Builder.phi``) the phi node contains no incoming blocks (nor their +corresponding values). To add an incoming arc to the phi node, use the +``add_incoming`` method, which takes a source block +(`llvm.core.BasicBlock `_ object) and a value +(object of `llvm.core.Value `_ or of a class +derived from it) that the phi node will take on if control branches in +from that block. + +Base Class +---------- + +- ``llvm.core.Instruction`` + +Properties +---------- + +``incoming_count`` [read-only] The number of incoming arcs for this phi +node. + +Methods +------- + +``add_incoming(value, block)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Add an incoming arc, from the +`llvm.core.BasicBlock `_ object ``block``, +with the corresponding value ``value``. ``value`` should be an object of +`llvm.core.Value `_ (or of a descendent class). + +``get_incoming_value(idx)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Returns the ``idx``-th incoming arc's value. + +``get_incoming_block(idx)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Returns the ``idx``-th incoming arc's block. + +llvm.core.SwitchInstruction # {#switchinstr} +============================================ + +(TODO describe) + +Base Class +---------- + +- ``llvm.core.Instruction`` + +Methods +------- + +``add_case(const, block)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Add another case to the switch statement. When the expression being +evaluated equals ``const``, then control branches to ``block``. Here +``const`` must be of type +`llvm.core.ConstantInt `_. + +-------------- + +llvm.core.CompareInstruction +============================ + +(TODO describe) + +Base Class +---------- + +- ``llvm.core.Instruction`` + +Properties +---------- + +``predicate`` +~~~~~~~~~~~~~ + +[read-only] + +The predicate of the compare instruction, one of the ``ICMP_*`` or +``FCMP_*`` constants. diff --git a/docs/source/doc/llvm.core.IntegerType.md b/docs/source/doc/llvm.core.IntegerType.md deleted file mode 100644 index da62f5c..0000000 --- a/docs/source/doc/llvm.core.IntegerType.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -layout: page -title: IntegerType (llvm.core) ---- - -# llvm.core.IntegerType - -## Base Class - -- [llvm.core.Type](llvm.core.Type.html) - -## Properties - - -### `width` -\[read-only\] - -The width of the integer type, in number of bits. - - diff --git a/docs/source/doc/llvm.core.IntegerType.rst b/docs/source/doc/llvm.core.IntegerType.rst new file mode 100644 index 0000000..f62907c --- /dev/null +++ b/docs/source/doc/llvm.core.IntegerType.rst @@ -0,0 +1,23 @@ ++----------------------------------+ +| layout: page | ++----------------------------------+ +| title: IntegerType (llvm.core) | ++----------------------------------+ + +llvm.core.IntegerType +===================== + +Base Class +---------- + +- `llvm.core.Type `_ + +Properties +---------- + +``width`` +~~~~~~~~~ + +[read-only] + +The width of the integer type, in number of bits. diff --git a/docs/source/doc/llvm.core.Module.md b/docs/source/doc/llvm.core.Module.md deleted file mode 100644 index 80a4784..0000000 --- a/docs/source/doc/llvm.core.Module.md +++ /dev/null @@ -1,219 +0,0 @@ ---- -layout: page -title: Module (llvm.core) ---- - -Modules are top-level container objects. You need to create a module -object first, before you can add global variables, aliases or functions. -Modules are created using the static method `Module.new`: - -{% highlight python %} -#!/usr/bin/env python - -from llvm import * -from llvm.core import * - -# create a module -my_module = Module.new('my_module') -{% endhighlight %} - -The constructor of the Module class should _not_ be used to instantiate -a Module object. This is a common feature for all llvm-py classes. - -> **Convention** -> -> *All* llvm-py objects are instantiated using static methods of -> corresponding classes. Constructors _should not_ be used. -> -> The argument `my_module` is a module identifier (a plain string). A -> module can also be constructed via deserialization from a bit code file, -> using the static method `from_bitcode`. This method takes a file-like -> object as argument, i.e., it should have a `read()` method that returns -> the entire data in a single call, as is the case with the builtin file -> object. Here is an example: - -{% highlight python %} -# create a module from a bit code file -bcfile = file("test.bc") -my_module = Module.from_bitcode(bcfile) -{% endhighlight %} - -There is corresponding serialization method also, called `to_bitcode`: - -{% highlight python %} -# write out a bit code file from the module -bcfile = file("test.bc", "w") -my_module.to_bitcode(bcfile) -{% endhighlight %} - -Modules can also be constructed from LLVM assembly files (`.ll` files). -The static method `from_assembly` can be used for this. Similar to the -`from_bitcode` method, this one also takes a file-like object as -argument: - -{% highlight python %} -# create a module from an assembly file -llfile = file("test.ll") -my_module = Module.from_assembly(llfile) -{% endhighlight %} - -Modules can be converted into their assembly representation by -stringifying them (see below). - -* * * - - -# llvm.core.Module - -* This will become a table of contents (this text will be scraped). -{:toc} - -## Static Constructors - -### `new(module_id)` - -Create a new `Module` instance with given `module_id`. The `module_id` -should be a string. - -### `from_bitcode(fileobj)` - -Create a new `Module` instance by deserializing the bitcode file -represented by the file-like object `fileobj`. - -### `from_assembly(fileobj)` - -Create a new `Module` instance by parsing the LLVM assembly file -represented by the file-like object `fileobj`. - -## Properties - -### `data_layout` - -A string representing the ABI of the platform. - -### `target` - -A string like `i386-pc-linux-gnu` or `i386-pc-solaris2.8`. - -### `pointer_size` -\[read-only\] - -The size in bits of pointers, of the target platform. A value of -zero represents `llvm::Module::AnyPointerSize`. - -### `global_variables` -\[read-only\] - -An iterable that yields [GlobalVariable][llvm.core.GlobalVariable] objects, -that represent the global variables of the module. - -### `functions` -\[read-only\] - -An iterable that yields [Function][llvm.core.Function] objects, -that represent functions in the module. - -### `id` - -A string that represents the module identifier (name). - -## Methods - -### `get_type_named(name)` - -Return a [StructType][llvm.core.StructType] object for the given name. - -The definition of this method was changed to work with LLVM 3.0+, in which -the type system was rewritten. -See [LLVM Blog](http://blog.llvm.org/2011/11/llvm-30-type-system-rewrite.html). - -{% comment %} -++++++++REMOVED+++++++++++ -### `add_type_name(name, ty)` - -Add an alias (typedef) for the type `ty` with the name `name`. - -### `delete_type_name(name)` - -Delete an alias with the name `name`. -++++++++END-REMOVED+++++++++++ -{% endcomment %} - -### `add_global_variable(ty, name)` - -Add a global variable of the type `ty` with the name `name`. -Returns a [GlobalVariable][llvm.core.GlobalVariable] object. - -### `get_global_variable_named(name)` - -Get a [GlobalVariable][llvm.core.GlobalVariable] object corresponding to -the global variable with the name `name`. -Raises `LLVMException` if such a variable does not exist. - -### `add_library(name)` - -Add a dependent library to the Module. This only adds a name to a list of -dependent library. **No linking is performed**. - -### `add_function(ty, name)` - -Add a function named `name` with the function type `ty`. `ty` must -of an object of type [FunctionType][llvm.core.FunctionType]. - -### `get_function_named(name)` - -Get a [Function][llvm.core.Function] object corresponding to the function with -the name `name`. Raises `LLVMException` if such a function does not exist. - -### `get_or_insert_function(ty, name)` - -Like `get_function_named`, but adds the function first, if not -present (like `add_function`). - -### `verify()` - -Verify the correctness of the module. Raises `LLVMException` on -errors. - -### `to_bitcode(fileobj)` - -Write the bitcode representation of the module to the file-like -object `fileobj`. - -### `link_in(other)` - -Link in another module `other` into this module. Global variables, -functions etc. are matched and resolved. The `other` module is no -longer valid and should not be used after this operation. This API -might be replaced with a full-fledged Linker class in the future. - -## Special Methods - - -### `__str__` - -`Module` objects can be stringified into it's LLVM assembly language -representation. - -### `__eq__` - -`Module` objects can be compared for equality. Internally, this -converts both arguments into their LLVM assembly representations and -compares the resultant strings. - -> **Convention** -> -> *All* llvm-py objects (where it makes sense), when stringified, return -> the LLVM assembly representation. `print module_obj` for example, -> prints the LLVM assembly form of the entire module. -> -> Such objects, when compared for equality, internally compare these -> string representations. - -[llvm.core.Function]: llvm.core.Function.html -[llvm.core.FunctionType]: llvm.core.FunctionType.html -[llvm.core.GlobalVariable]: llvm.core.GlobalVariable.html -[llvm.core.BasicBlock]: llvm.core.BasicBlock.html -[llvm.core.Type]: llvm.core.Type.html -[llvm.core.StructType]: llvm.core.StructType.html - diff --git a/docs/source/doc/llvm.core.Module.rst b/docs/source/doc/llvm.core.Module.rst new file mode 100644 index 0000000..e5e2e04 --- /dev/null +++ b/docs/source/doc/llvm.core.Module.rst @@ -0,0 +1,233 @@ ++-----------------------------+ +| layout: page | ++-----------------------------+ +| title: Module (llvm.core) | ++-----------------------------+ + +Modules are top-level container objects. You need to create a module +object first, before you can add global variables, aliases or functions. +Modules are created using the static method ``Module.new``: + +{% highlight python %} #!/usr/bin/env python + +from llvm import \* from llvm.core import \* + +create a module +=============== + +my\_module = Module.new('my\_module') {% endhighlight %} + +The constructor of the Module class should *not* be used to instantiate +a Module object. This is a common feature for all llvm-py classes. + + **Convention** + + *All* llvm-py objects are instantiated using static methods of + corresponding classes. Constructors *should not* be used. + + The argument ``my_module`` is a module identifier (a plain string). + A module can also be constructed via deserialization from a bit code + file, using the static method ``from_bitcode``. This method takes a + file-like object as argument, i.e., it should have a ``read()`` + method that returns the entire data in a single call, as is the case + with the builtin file object. Here is an example: + +{% highlight python %} # create a module from a bit code file bcfile = +file("test.bc") my\_module = Module.from\_bitcode(bcfile) {% +endhighlight %} + +There is corresponding serialization method also, called ``to_bitcode``: + +{% highlight python %} # write out a bit code file from the module +bcfile = file("test.bc", "w") my\_module.to\_bitcode(bcfile) {% +endhighlight %} + +Modules can also be constructed from LLVM assembly files (``.ll`` +files). The static method ``from_assembly`` can be used for this. +Similar to the ``from_bitcode`` method, this one also takes a file-like +object as argument: + +{% highlight python %} # create a module from an assembly file llfile = +file("test.ll") my\_module = Module.from\_assembly(llfile) {% +endhighlight %} + +Modules can be converted into their assembly representation by +stringifying them (see below). + +-------------- + +llvm.core.Module +================ + +- This will become a table of contents (this text will be scraped). + {:toc} + +Static Constructors +------------------- + +``new(module_id)`` +~~~~~~~~~~~~~~~~~~ + +Create a new ``Module`` instance with given ``module_id``. The +``module_id`` should be a string. + +``from_bitcode(fileobj)`` +~~~~~~~~~~~~~~~~~~~~~~~~~ + +Create a new ``Module`` instance by deserializing the bitcode file +represented by the file-like object ``fileobj``. + +``from_assembly(fileobj)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Create a new ``Module`` instance by parsing the LLVM assembly file +represented by the file-like object ``fileobj``. + +Properties +---------- + +``data_layout`` +~~~~~~~~~~~~~~~ + +A string representing the ABI of the platform. + +``target`` +~~~~~~~~~~ + +A string like ``i386-pc-linux-gnu`` or ``i386-pc-solaris2.8``. + +``pointer_size`` +~~~~~~~~~~~~~~~~ + +[read-only] + +The size in bits of pointers, of the target platform. A value of zero +represents ``llvm::Module::AnyPointerSize``. + +``global_variables`` +~~~~~~~~~~~~~~~~~~~~ + +[read-only] + +An iterable that yields +`GlobalVariable `_ objects, that +represent the global variables of the module. + +``functions`` +~~~~~~~~~~~~~ + +[read-only] + +An iterable that yields `Function `_ objects, +that represent functions in the module. + +``id`` +~~~~~~ + +A string that represents the module identifier (name). + +Methods +------- + +``get_type_named(name)`` +~~~~~~~~~~~~~~~~~~~~~~~~ + +Return a `StructType `_ object for the given +name. + +The definition of this method was changed to work with LLVM 3.0+, in +which the type system was rewritten. See `LLVM +Blog `_. + +{% comment %} ++++++++REMOVED+++++++++++ ### ``add_type_name(name, ty)`` + +Add an alias (typedef) for the type ``ty`` with the name ``name``. + +``delete_type_name(name)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Delete an alias with the name ``name``. ++++++++END-REMOVED+++++++++++ +{% endcomment %} + +``add_global_variable(ty, name)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Add a global variable of the type ``ty`` with the name ``name``. Returns +a `GlobalVariable `_ object. + +``get_global_variable_named(name)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Get a `GlobalVariable `_ object +corresponding to the global variable with the name ``name``. Raises +``LLVMException`` if such a variable does not exist. + +``add_library(name)`` +~~~~~~~~~~~~~~~~~~~~~ + +Add a dependent library to the Module. This only adds a name to a list +of dependent library. **No linking is performed**. + +``add_function(ty, name)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Add a function named ``name`` with the function type ``ty``. ``ty`` must +of an object of type `FunctionType `_. + +``get_function_named(name)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Get a `Function `_ object corresponding to the +function with the name ``name``. Raises ``LLVMException`` if such a +function does not exist. + +``get_or_insert_function(ty, name)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Like ``get_function_named``, but adds the function first, if not present +(like ``add_function``). + +``verify()`` +~~~~~~~~~~~~ + +Verify the correctness of the module. Raises ``LLVMException`` on +errors. + +``to_bitcode(fileobj)`` +~~~~~~~~~~~~~~~~~~~~~~~ + +Write the bitcode representation of the module to the file-like object +``fileobj``. + +``link_in(other)`` +~~~~~~~~~~~~~~~~~~ + +Link in another module ``other`` into this module. Global variables, +functions etc. are matched and resolved. The ``other`` module is no +longer valid and should not be used after this operation. This API might +be replaced with a full-fledged Linker class in the future. + +Special Methods +--------------- + +``__str__`` +~~~~~~~~~~~ + +``Module`` objects can be stringified into it's LLVM assembly language +representation. + +``__eq__`` +~~~~~~~~~~ + +``Module`` objects can be compared for equality. Internally, this +converts both arguments into their LLVM assembly representations and +compares the resultant strings. + + **Convention** + + *All* llvm-py objects (where it makes sense), when stringified, + return the LLVM assembly representation. ``print module_obj`` for + example, prints the LLVM assembly form of the entire module. + + Such objects, when compared for equality, internally compare these + string representations. diff --git a/docs/source/doc/llvm.core.PointerType.md b/docs/source/doc/llvm.core.PointerType.md deleted file mode 100644 index 7adfbe6..0000000 --- a/docs/source/doc/llvm.core.PointerType.md +++ /dev/null @@ -1,26 +0,0 @@ ---- -layout: page -title: PointerType (llvm.core) ---- - - -# llvm.core.PointerType - -## Base Class - -- [llvm.core.Type](llvm.core.Type.html) - -## Properties - - -### `address_space` -\[read-only\] - -The address space of the pointer. - - -### `pointee` -\[read-only\] - -A [Type](llvm.core.Type.html) object representing the type of the value pointed to. - diff --git a/docs/source/doc/llvm.core.PointerType.rst b/docs/source/doc/llvm.core.PointerType.rst new file mode 100644 index 0000000..a869fba --- /dev/null +++ b/docs/source/doc/llvm.core.PointerType.rst @@ -0,0 +1,31 @@ ++----------------------------------+ +| layout: page | ++----------------------------------+ +| title: PointerType (llvm.core) | ++----------------------------------+ + +llvm.core.PointerType +===================== + +Base Class +---------- + +- `llvm.core.Type `_ + +Properties +---------- + +``address_space`` +~~~~~~~~~~~~~~~~~ + +[read-only] + +The address space of the pointer. + +``pointee`` +~~~~~~~~~~~ + +[read-only] + +A `Type `_ object representing the type of the +value pointed to. diff --git a/docs/source/doc/llvm.core.StructType.md b/docs/source/doc/llvm.core.StructType.md deleted file mode 100644 index 5156814..0000000 --- a/docs/source/doc/llvm.core.StructType.md +++ /dev/null @@ -1,70 +0,0 @@ ---- -layout: page -title: StructType (llvm.core) ---- - -# llvm.core.StructType - -## Base Class - -- [llvm.core.Type](llvm.core.Type.html) - -## Methods - -### `set_body(self, elems, packed=False)` - -Define the body for opaque identified structure. - -`elems` is an iterable of [llvm.core.Type](llvm.core.Type.html) -If `packed` is `True`, creates a packed structure. - -## Properties - -### `is_identified` -\[read-only\] - -`True` if this is an identified structure. - -### `is_literal` -\[read-only\] - -`True` if this is a literal structure. - -### `is_opaque` -\[read-only\] - -`True` if this is an opaque structure. -Only identified structure can be opaque. - -### `packed` -\[read-only\] - -`True` if the structure is packed (no padding between elements). - -### `name` - -Use in identified structure. -If set to empty, the identified structure is removed from the global context. - -### `elements` -\[read-only\] - -Returns an iterable object that yields [Type](llvm.core.Type.html) objects that -represent, in order, the types of the elements of the structure. -Used like this: - -{% highlight python %} -struct_type = Type.struct( [ Type.int(), Type.int() ] ) -for elem in struct_type.elements: - assert elem.kind == TYPE_INTEGER - assert elem == Type.int() -assert struct_type.element_count == len(struct_type.elements) -{% endhighlight %} - - -### `element_count` -\[read-only\] - -The number of elements. Same as `len(obj.elements)`, but faster. - - diff --git a/docs/source/doc/llvm.core.StructType.rst b/docs/source/doc/llvm.core.StructType.rst new file mode 100644 index 0000000..df0df17 --- /dev/null +++ b/docs/source/doc/llvm.core.StructType.rst @@ -0,0 +1,84 @@ ++---------------------------------+ +| layout: page | ++---------------------------------+ +| title: StructType (llvm.core) | ++---------------------------------+ + +llvm.core.StructType +==================== + +Base Class +---------- + +- `llvm.core.Type `_ + +Methods +------- + +``set_body(self, elems, packed=False)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Define the body for opaque identified structure. + +``elems`` is an iterable of `llvm.core.Type `_ If +``packed`` is ``True``, creates a packed structure. + +Properties +---------- + +``is_identified`` +~~~~~~~~~~~~~~~~~ + +[read-only] + +``True`` if this is an identified structure. + +``is_literal`` +~~~~~~~~~~~~~~ + +[read-only] + +``True`` if this is a literal structure. + +``is_opaque`` +~~~~~~~~~~~~~ + +[read-only] + +``True`` if this is an opaque structure. Only identified structure can +be opaque. + +``packed`` +~~~~~~~~~~ + +[read-only] + +``True`` if the structure is packed (no padding between elements). + +``name`` +~~~~~~~~ + +Use in identified structure. If set to empty, the identified structure +is removed from the global context. + +``elements`` +~~~~~~~~~~~~ + +[read-only] + +Returns an iterable object that yields `Type `_ +objects that represent, in order, the types of the elements of the +structure. Used like this: + +{% highlight python %} struct\_type = Type.struct( [ Type.int(), +Type.int() ] ) for elem in struct\_type.elements: assert elem.kind == +TYPE\_INTEGER assert elem == Type.int() assert +struct\_type.element\_count == len(struct\_type.elements) {% +endhighlight %} + +``element_count`` +~~~~~~~~~~~~~~~~~ + +[read-only] + +The number of elements. Same as ``len(obj.elements)``, but faster. diff --git a/docs/source/doc/llvm.core.Type.md b/docs/source/doc/llvm.core.Type.md deleted file mode 100644 index 2616b7e..0000000 --- a/docs/source/doc/llvm.core.Type.md +++ /dev/null @@ -1,148 +0,0 @@ ---- -layout: page -title: Type (llvm.core) ---- - -# llvm.core.Type - -* This will become a table of contents (this text will be scraped). -{:toc} - -## Static Constructors - -### `int(n)` - -Create an integer type of bit width `n`. - -### `float()` - -Create a 32-bit floating point type. - - -### `double()` - -Create a 64-bit floating point type. - - -### `x86_fp80()` - -Create a 80-bit 80x87-style floating point type. - - -### `fp128()` - -Create a 128-bit floating point type (112-bit mantissa). - - -### `ppc_fp128()` - -Create a 128-bit float (two 64-bits). - - -### `function(ret, params, vararg=False)` - -Create a function type, having the return type `ret` (must be a -`Type`), accepting the parameters `params`, where `params` is an -iterable, that yields `Type` objects representing the type of -each function argument in order. If `vararg` is `True`, function is -variadic. - - -### `struct(eltys, name='')` - -Create an unpacked structure. `eltys` is an iterable, that yields -`Type` objects representing the type of each element in order. - -If `name` is evaulates `True` (not empty), create -an *identified structure*; otherwise, create a *literal structure* -by default. - - -### `packed_struct(eltys, name='')` - -Like `struct(eltys)`, but creates a packed struct. - - -### `array(elty, count)` - -Creates an array type, holding `count` elements, each of type `elty` -(which should be a `Type`). - - -### `pointer(pty, addrspc=0)` - -Create a pointer to type `pty` (which should be a `Type`). `addrspc` -is an integer that represents the address space of the pointer (see -LLVM docs or ask on llvm-dev for more info). - - -### `void()` - -Creates a void type. Used for function return types. - - -### `label()` - -Creates a label type. - - -### `opaque(name)` - -Opaque [StructType](llvm.core.StructType.html), used for creating self-referencing types. - -## Properties - - -### `kind` -\[read-only\] - -A value (enum) representing the "type" of the object. It will be -one of the following constants defined in `llvm.core`: - -{% highlight python %} -# Warning: do not rely on actual numerical values! -TYPE_VOID = 0 -TYPE_FLOAT = 1 -TYPE_DOUBLE = 2 -TYPE_X86_FP80 = 3 -TYPE_FP128 = 4 -TYPE_PPC_FP128 = 5 -TYPE_LABEL = 6 -TYPE_INTEGER = 7 -TYPE_FUNCTION = 8 -TYPE_STRUCT = 9 -TYPE_ARRAY = 10 -TYPE_POINTER = 11 -TYPE_OPAQUE = 12 -TYPE_VECTOR = 13 -TYPE_METADATA = 14 -TYPE_UNION = 15 -{% endhighlight %} - -#### Example: -{% highlight python %} -assert Type.int().kind == TYPE_INTEGER -assert Type.void().kind == TYPE_VOID -{% endhighlight %} - -## Methods - -### `refine` - -Used for constructing self-referencing types. See the documentation -of [TypeHandle](llvm.core.TypeHandle.html) objects. - -## Special Methods - -### `__str__` - -`Type` objects can be stringified into it's LLVM assembly language -representation. - -### `__eq__` - -`Type` objects can be compared for equality. Internally, this -converts both arguments into their LLVM assembly representations and -compares the resultant strings. - - diff --git a/docs/source/doc/llvm.core.Type.rst b/docs/source/doc/llvm.core.Type.rst new file mode 100644 index 0000000..7cd43ae --- /dev/null +++ b/docs/source/doc/llvm.core.Type.rst @@ -0,0 +1,145 @@ ++---------------------------+ +| layout: page | ++---------------------------+ +| title: Type (llvm.core) | ++---------------------------+ + +llvm.core.Type +============== + +- This will become a table of contents (this text will be scraped). + {:toc} + +Static Constructors +------------------- + +``int(n)`` +~~~~~~~~~~ + +Create an integer type of bit width ``n``. + +``float()`` +~~~~~~~~~~~ + +Create a 32-bit floating point type. + +``double()`` +~~~~~~~~~~~~ + +Create a 64-bit floating point type. + +``x86_fp80()`` +~~~~~~~~~~~~~~ + +Create a 80-bit 80x87-style floating point type. + +``fp128()`` +~~~~~~~~~~~ + +Create a 128-bit floating point type (112-bit mantissa). + +``ppc_fp128()`` +~~~~~~~~~~~~~~~ + +Create a 128-bit float (two 64-bits). + +``function(ret, params, vararg=False)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Create a function type, having the return type ``ret`` (must be a +``Type``), accepting the parameters ``params``, where ``params`` is an +iterable, that yields ``Type`` objects representing the type of each +function argument in order. If ``vararg`` is ``True``, function is +variadic. + +``struct(eltys, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Create an unpacked structure. ``eltys`` is an iterable, that yields +``Type`` objects representing the type of each element in order. + +If ``name`` is evaulates ``True`` (not empty), create an *identified +structure*; otherwise, create a *literal structure* by default. + +``packed_struct(eltys, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Like ``struct(eltys)``, but creates a packed struct. + +``array(elty, count)`` +~~~~~~~~~~~~~~~~~~~~~~ + +Creates an array type, holding ``count`` elements, each of type ``elty`` +(which should be a ``Type``). + +``pointer(pty, addrspc=0)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Create a pointer to type ``pty`` (which should be a ``Type``). +``addrspc`` is an integer that represents the address space of the +pointer (see LLVM docs or ask on llvm-dev for more info). + +``void()`` +~~~~~~~~~~ + +Creates a void type. Used for function return types. + +``label()`` +~~~~~~~~~~~ + +Creates a label type. + +``opaque(name)`` +~~~~~~~~~~~~~~~~ + +Opaque `StructType `_, used for creating +self-referencing types. + +Properties +---------- + +``kind`` +~~~~~~~~ + +[read-only] + +A value (enum) representing the "type" of the object. It will be one of +the following constants defined in ``llvm.core``: + +{% highlight python %} # Warning: do not rely on actual numerical +values! TYPE\_VOID = 0 TYPE\_FLOAT = 1 TYPE\_DOUBLE = 2 TYPE\_X86\_FP80 += 3 TYPE\_FP128 = 4 TYPE\_PPC\_FP128 = 5 TYPE\_LABEL = 6 TYPE\_INTEGER = +7 TYPE\_FUNCTION = 8 TYPE\_STRUCT = 9 TYPE\_ARRAY = 10 TYPE\_POINTER = +11 TYPE\_OPAQUE = 12 TYPE\_VECTOR = 13 TYPE\_METADATA = 14 TYPE\_UNION = +15 {% endhighlight %} + +Example: +^^^^^^^^ + +{% highlight python %} assert Type.int().kind == TYPE\_INTEGER assert +Type.void().kind == TYPE\_VOID {% endhighlight %} + +Methods +------- + +``refine`` +~~~~~~~~~~ + +Used for constructing self-referencing types. See the documentation of +`TypeHandle `_ objects. + +Special Methods +--------------- + +``__str__`` +~~~~~~~~~~~ + +``Type`` objects can be stringified into it's LLVM assembly language +representation. + +``__eq__`` +~~~~~~~~~~ + +``Type`` objects can be compared for equality. Internally, this converts +both arguments into their LLVM assembly representations and compares the +resultant strings. diff --git a/docs/source/doc/llvm.core.User.md b/docs/source/doc/llvm.core.User.md deleted file mode 100644 index 8a2353f..0000000 --- a/docs/source/doc/llvm.core.User.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -layout: page -title: User (llvm.core) ---- - -`User`-s are values that refer to other values. The values so refered -can be retrived by the properties of `User`. This is the reverse of -the `Value.uses`. Together these can be used to traverse the use-def -chains of the SSA. - -* * * - - -# llvm.core.User # {#user} -## Base Class -- [llvm.core.Value][] - -## Properties - -### `operands` -\[read-only\] - -The list of operands (values, of type [llvm.core.Value][]) that this -value refers to. - -### `operand_count` -\[read-only\] - -The number of operands that this value referes to. Same as -`len(uses.operands)` but faster if you just want the count. - - -[llvm.core.Value]: llvm.core.Value.html - diff --git a/docs/source/doc/llvm.core.User.rst b/docs/source/doc/llvm.core.User.rst new file mode 100644 index 0000000..0762729 --- /dev/null +++ b/docs/source/doc/llvm.core.User.rst @@ -0,0 +1,39 @@ ++---------------------------+ +| layout: page | ++---------------------------+ +| title: User (llvm.core) | ++---------------------------+ + +``User``-s are values that refer to other values. The values so refered +can be retrived by the properties of ``User``. This is the reverse of +the ``Value.uses``. Together these can be used to traverse the use-def +chains of the SSA. + +-------------- + +llvm.core.User # {#user} +======================== + +Base Class +---------- + +- `llvm.core.Value `_ + +Properties +---------- + +``operands`` +~~~~~~~~~~~~ + +[read-only] + +The list of operands (values, of type +`llvm.core.Value `_) that this value refers to. + +``operand_count`` +~~~~~~~~~~~~~~~~~ + +[read-only] + +The number of operands that this value referes to. Same as +``len(uses.operands)`` but faster if you just want the count. diff --git a/docs/source/doc/llvm.core.Value.md b/docs/source/doc/llvm.core.Value.md deleted file mode 100644 index 7c0555e..0000000 --- a/docs/source/doc/llvm.core.Value.md +++ /dev/null @@ -1,50 +0,0 @@ ---- -layout: page -title: Value (llvm.core) ---- - -# llvm.core.Value - -* This will become a table of contents (this text will be scraped). -{:toc} - -## Properties -### `name` - -The name of the value. - -### `type` -\[read-only\] - -An `llvm.core.Type` object representing the type of the value. - -### `uses` -\[read-only\] - -The list of values (`llvm.core.Value`) that use this value. - -### `use_count` -\[read-only\] - -The number of values that use (refer) this value. Same as `len(val.uses)` -but faster if you just want the count. - -### `value_id` -\[read-only\] - -Returns `llvmValuegetValueID()`. Refer LLVM documentation -for more info. - -## Special Methods - -### `__str__` - -`Value` objects can be stringified into it's LLVM assembly language -representation. - -### `__eq__` - -`Value` objects can be compared for equality. Internally, this -converts both arguments into their LLVM assembly representations and -compares the resultant strings. - diff --git a/docs/source/doc/llvm.core.Value.rst b/docs/source/doc/llvm.core.Value.rst new file mode 100644 index 0000000..fdff4cc --- /dev/null +++ b/docs/source/doc/llvm.core.Value.rst @@ -0,0 +1,65 @@ ++----------------------------+ +| layout: page | ++----------------------------+ +| title: Value (llvm.core) | ++----------------------------+ + +llvm.core.Value +=============== + +- This will become a table of contents (this text will be scraped). + {:toc} + +Properties +---------- + +``name`` +~~~~~~~~ + +The name of the value. + +``type`` +~~~~~~~~ + +[read-only] + +An ``llvm.core.Type`` object representing the type of the value. + +``uses`` +~~~~~~~~ + +[read-only] + +The list of values (``llvm.core.Value``) that use this value. + +``use_count`` +~~~~~~~~~~~~~ + +[read-only] + +The number of values that use (refer) this value. Same as +``len(val.uses)`` but faster if you just want the count. + +``value_id`` +~~~~~~~~~~~~ + +[read-only] + +Returns ``llvmValuegetValueID()``. Refer LLVM documentation for more +info. + +Special Methods +--------------- + +``__str__`` +~~~~~~~~~~~ + +``Value`` objects can be stringified into it's LLVM assembly language +representation. + +``__eq__`` +~~~~~~~~~~ + +``Value`` objects can be compared for equality. Internally, this +converts both arguments into their LLVM assembly representations and +compares the resultant strings. diff --git a/docs/source/doc/llvm.core.VectorType.md b/docs/source/doc/llvm.core.VectorType.md deleted file mode 100644 index b227077..0000000 --- a/docs/source/doc/llvm.core.VectorType.md +++ /dev/null @@ -1,26 +0,0 @@ ---- -layout: page -title: VectorType (llvm.core) ---- - -# llvm.core.VectorType - -## Base Class - -- [llvm.core.Type](llvm.core.Type.html) - -## Properties - - -### `element` -\[read-only\] - -A [Type](llvm.core.Type.html) object representing the type of the element of -the vector. - - -### `count` -\[read-only\] - -The number of elements in the vector. - diff --git a/docs/source/doc/llvm.core.VectorType.rst b/docs/source/doc/llvm.core.VectorType.rst new file mode 100644 index 0000000..19b98e6 --- /dev/null +++ b/docs/source/doc/llvm.core.VectorType.rst @@ -0,0 +1,31 @@ ++---------------------------------+ +| layout: page | ++---------------------------------+ +| title: VectorType (llvm.core) | ++---------------------------------+ + +llvm.core.VectorType +==================== + +Base Class +---------- + +- `llvm.core.Type `_ + +Properties +---------- + +``element`` +~~~~~~~~~~~ + +[read-only] + +A `Type `_ object representing the type of the +element of the vector. + +``count`` +~~~~~~~~~ + +[read-only] + +The number of elements in the vector. diff --git a/docs/source/doc/llvm.ee.EngineBuilder.md b/docs/source/doc/llvm.ee.EngineBuilder.md deleted file mode 100644 index a7f6c36..0000000 --- a/docs/source/doc/llvm.ee.EngineBuilder.md +++ /dev/null @@ -1,49 +0,0 @@ ---- -layout: page -title: EngineBuilder (llvm.ee) ---- - -# llvm.ee.EngineBuilder - -A convenient class for building [llvm.ee.ExecutionEngine]. -Each `EngineBuilder` instance can only create one `ExecutionEngine`. - - -## Methods - -### `create(self)` - -Create and return a new [ExecutionEngine][llvm.ee.ExecutionEngine] instance. - -Raise `llvm.LLVMException` if the builder cannot create an `ExecutionEngine` -base on the given configuration. - -### `force_interpreter(self)` - -Force the output the output `ExecutionEngine` to be an LLVM IR interpreter. - -### `force_jit(self)` - -Force the output the output `ExecutionEngine` to be a JIT engine. - -### `opt(self, level)` - -Set the code generation optimization level for a JIT engine. -Valid value of `level` is 0-3, inclusive. -The default setting is 2. -To use vector instructions, such as SSE on Intel processors, -`level` must be 3 (aggressive). - -## Static Factory Methods - -### `new(module)` - -Create a new EngineBuilder. `module` must be a [llvm.core.Module][] instance. -Its ownership is transferred to the resulting -[ExecutionEngine][llvm.ee.ExecutionEngine]. -Therefore, it is impossible to create more than one `ExecutionEngine` with -a single `EngineBuilder` - - -[llvm.core.Module]: llvm.core.Module.html -[llvm.ee.ExecutionEngine]: llvm.ee.ExecutionEngine.html diff --git a/docs/source/doc/llvm.ee.EngineBuilder.rst b/docs/source/doc/llvm.ee.EngineBuilder.rst new file mode 100644 index 0000000..e317acc --- /dev/null +++ b/docs/source/doc/llvm.ee.EngineBuilder.rst @@ -0,0 +1,56 @@ ++----------------------------------+ +| layout: page | ++----------------------------------+ +| title: EngineBuilder (llvm.ee) | ++----------------------------------+ + +llvm.ee.EngineBuilder +===================== + +A convenient class for building +`llvm.ee.ExecutionEngine `_. Each +``EngineBuilder`` instance can only create one ``ExecutionEngine``. + +Methods +------- + +``create(self)`` +~~~~~~~~~~~~~~~~ + +Create and return a new +`ExecutionEngine `_ instance. + +Raise ``llvm.LLVMException`` if the builder cannot create an +``ExecutionEngine`` base on the given configuration. + +``force_interpreter(self)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Force the output the output ``ExecutionEngine`` to be an LLVM IR +interpreter. + +``force_jit(self)`` +~~~~~~~~~~~~~~~~~~~ + +Force the output the output ``ExecutionEngine`` to be a JIT engine. + +``opt(self, level)`` +~~~~~~~~~~~~~~~~~~~~ + +Set the code generation optimization level for a JIT engine. Valid value +of ``level`` is 0-3, inclusive. The default setting is 2. To use vector +instructions, such as SSE on Intel processors, ``level`` must be 3 +(aggressive). + +Static Factory Methods +---------------------- + +``new(module)`` +~~~~~~~~~~~~~~~ + +Create a new EngineBuilder. ``module`` must be a +`llvm.core.Module `_ instance. Its ownership is +transferred to the resulting +`ExecutionEngine `_. Therefore, it is +impossible to create more than one ``ExecutionEngine`` with a single +``EngineBuilder`` diff --git a/docs/source/doc/llvm.ee.ExecutionEngine.md b/docs/source/doc/llvm.ee.ExecutionEngine.md deleted file mode 100644 index 39ef661..0000000 --- a/docs/source/doc/llvm.ee.ExecutionEngine.md +++ /dev/null @@ -1,52 +0,0 @@ ---- -layout: page -title: ExecutionEngine (llvm.ee) ---- - -# llvm.ee.ExecutionEngine - -## Methods - -### `add_module(self, module)` - -Add a new module to the ExecutionEngine. -The ownership is of `module` is transferred. -When the `ExecutionEngine` is destroyed, the module is destroyed. - -### `free_machine_code_for(self, fn)` - -Release memory used for the machine code generated for -the function `fn`. - -### `get_pointer_to_function(self, fn)` - -Obtain the pointer to the function `fn`. -This forces the ExecutionEngine to generate the machine code -in lazy mode. - -If `fn` is not defined, `ExecutionEngine` will lookup the -symbol through `dlsym`. - -The returned function pointer can be wrapped as a `ctypes` function. - -### `remove_module(self, module)` - -Remove the `module`. - -### `run_function(self, fn, args)` - -Execute the function `fn` with an iterable of arguments `args` -which are of `GenericValue`. This method returns whatever -that is returned by `fn` as a `GenericValue`. - -### `run_static_ctors(self)` - -### `run_static_dtors(self)` - -## Properties - -### `target_data` - -Access the [TargetData](llvm.ee.TargetData.html) -instance associated with the `ExecutionEngine`. - diff --git a/docs/source/doc/llvm.ee.ExecutionEngine.rst b/docs/source/doc/llvm.ee.ExecutionEngine.rst new file mode 100644 index 0000000..718358c --- /dev/null +++ b/docs/source/doc/llvm.ee.ExecutionEngine.rst @@ -0,0 +1,62 @@ ++------------------------------------+ +| layout: page | ++------------------------------------+ +| title: ExecutionEngine (llvm.ee) | ++------------------------------------+ + +llvm.ee.ExecutionEngine +======================= + +Methods +------- + +``add_module(self, module)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Add a new module to the ExecutionEngine. The ownership is of ``module`` +is transferred. When the ``ExecutionEngine`` is destroyed, the module is +destroyed. + +``free_machine_code_for(self, fn)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Release memory used for the machine code generated for the function +``fn``. + +``get_pointer_to_function(self, fn)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Obtain the pointer to the function ``fn``. This forces the +ExecutionEngine to generate the machine code in lazy mode. + +If ``fn`` is not defined, ``ExecutionEngine`` will lookup the symbol +through ``dlsym``. + +The returned function pointer can be wrapped as a ``ctypes`` function. + +``remove_module(self, module)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Remove the ``module``. + +``run_function(self, fn, args)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Execute the function ``fn`` with an iterable of arguments ``args`` which +are of ``GenericValue``. This method returns whatever that is returned +by ``fn`` as a ``GenericValue``. + +``run_static_ctors(self)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +``run_static_dtors(self)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Properties +---------- + +``target_data`` +~~~~~~~~~~~~~~~ + +Access the `TargetData `_ instance associated +with the ``ExecutionEngine``. diff --git a/docs/source/doc/llvm.ee.GenericValue.md b/docs/source/doc/llvm.ee.GenericValue.md deleted file mode 100644 index eca6975..0000000 --- a/docs/source/doc/llvm.ee.GenericValue.md +++ /dev/null @@ -1,55 +0,0 @@ ---- -layout: page -title: GenericValue (llvm.ee) ---- - -# llvm.ee.GenericValue - -* This will become a table of contents (this text will be scraped). -{:toc} - -## Methods - -### `as_int(self)` - -Return the value of this `GenericValue` instance as an unsigned integer - -### `as_int_signed(self)` - -Return the value of this `GenericValue` instance as a signed integer. - -### `as_pointer(self)` - -Return the value of this `GenericValue` instance as a pointer. -The type of the return value is `int`. - -### `as_real(self, ty)` - -Return the value of this `GenericValue` instance as a real number -which type is specified by `ty`. `ty` must be a [Type][] instance -of a real number type. - -## Static Factory Methods - -### `int(ty, intval)` - -Create a `GenericValue` instance with a `int` value, -which is zero-extended if necessary. -The type of the value is specified by `ty`, which is a [Type][] instance. - -### `int_signed(ty, intval)` - -Create a `GenericValue` instance with a `int` value, -which is sign-extended if necessary. -The type of the value is specified by `ty`, which is a [Type][] instance. - -### `pointer(ty, addr)` or `pointer(addr)` - -Create a `GenericValue` instance with a `int` value, -which is representing a pointer value. - -The two argument version is **deprecated**. -The old code never used `ty` anyway. - - -[Type]: llvm.core.Type.html diff --git a/docs/source/doc/llvm.ee.GenericValue.rst b/docs/source/doc/llvm.ee.GenericValue.rst new file mode 100644 index 0000000..8680093 --- /dev/null +++ b/docs/source/doc/llvm.ee.GenericValue.rst @@ -0,0 +1,64 @@ ++---------------------------------+ +| layout: page | ++---------------------------------+ +| title: GenericValue (llvm.ee) | ++---------------------------------+ + +llvm.ee.GenericValue +==================== + +- This will become a table of contents (this text will be scraped). + {:toc} + +Methods +------- + +``as_int(self)`` +~~~~~~~~~~~~~~~~ + +Return the value of this ``GenericValue`` instance as an unsigned +integer + +``as_int_signed(self)`` +~~~~~~~~~~~~~~~~~~~~~~~ + +Return the value of this ``GenericValue`` instance as a signed integer. + +``as_pointer(self)`` +~~~~~~~~~~~~~~~~~~~~ + +Return the value of this ``GenericValue`` instance as a pointer. The +type of the return value is ``int``. + +``as_real(self, ty)`` +~~~~~~~~~~~~~~~~~~~~~ + +Return the value of this ``GenericValue`` instance as a real number +which type is specified by ``ty``. ``ty`` must be a +`Type `_ instance of a real number type. + +Static Factory Methods +---------------------- + +``int(ty, intval)`` +~~~~~~~~~~~~~~~~~~~ + +Create a ``GenericValue`` instance with a ``int`` value, which is +zero-extended if necessary. The type of the value is specified by +``ty``, which is a `Type `_ instance. + +``int_signed(ty, intval)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Create a ``GenericValue`` instance with a ``int`` value, which is +sign-extended if necessary. The type of the value is specified by +``ty``, which is a `Type `_ instance. + +``pointer(ty, addr)`` or ``pointer(addr)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Create a ``GenericValue`` instance with a ``int`` value, which is +representing a pointer value. + +The two argument version is **deprecated**. The old code never used +``ty`` anyway. diff --git a/docs/source/doc/llvm.ee.TargetData.md b/docs/source/doc/llvm.ee.TargetData.md deleted file mode 100644 index 537d680..0000000 --- a/docs/source/doc/llvm.ee.TargetData.md +++ /dev/null @@ -1,48 +0,0 @@ ---- -layout: page -title: TargetData (llvm.ee) ---- - -# llvm.ee.TargetData - -* This will become a table of contents (this text will be scraped). -{:toc} - -## Methods - -### `abi_alignment(self, ty)` - -Returns the minimum ABI-required alignment for the specified type `ty`. - -### `abi_size(self, ty)` - -### `callframe_alignment(self, ty)` - -Returns the minimum ABI-required alignment for the specified type `ty` when it is part of a call frame. - -### `element_at_offset(self, ty, ofs)` - -### `offset_of_element(self, ty, el)` - -### `preferred_alignment(self, ty_or_gv)` - -### `size(self, ty)` - -### `store_size(self, ty)` - -### `__str__(self)` -Returns the string representation. - -## Static Factory Methods - -### `new(strrep)` -Construct a new `TargetData` instance from the string representation - -## Properties - -### `byte_order` - -### `pointer_size` - -### `target_integer_type` - diff --git a/docs/source/doc/llvm.ee.TargetData.rst b/docs/source/doc/llvm.ee.TargetData.rst new file mode 100644 index 0000000..5a774b8 --- /dev/null +++ b/docs/source/doc/llvm.ee.TargetData.rst @@ -0,0 +1,70 @@ ++-------------------------------+ +| layout: page | ++-------------------------------+ +| title: TargetData (llvm.ee) | ++-------------------------------+ + +llvm.ee.TargetData +================== + +- This will become a table of contents (this text will be scraped). + {:toc} + +Methods +------- + +``abi_alignment(self, ty)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Returns the minimum ABI-required alignment for the specified type +``ty``. + +``abi_size(self, ty)`` +~~~~~~~~~~~~~~~~~~~~~~ + +``callframe_alignment(self, ty)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Returns the minimum ABI-required alignment for the specified type ``ty`` +when it is part of a call frame. + +``element_at_offset(self, ty, ofs)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +``offset_of_element(self, ty, el)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +``preferred_alignment(self, ty_or_gv)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +``size(self, ty)`` +~~~~~~~~~~~~~~~~~~ + +``store_size(self, ty)`` +~~~~~~~~~~~~~~~~~~~~~~~~ + +``__str__(self)`` +~~~~~~~~~~~~~~~~~ + +Returns the string representation. + +Static Factory Methods +---------------------- + +``new(strrep)`` +~~~~~~~~~~~~~~~ + +Construct a new ``TargetData`` instance from the string representation + +Properties +---------- + +``byte_order`` +~~~~~~~~~~~~~~ + +``pointer_size`` +~~~~~~~~~~~~~~~~ + +``target_integer_type`` +~~~~~~~~~~~~~~~~~~~~~~~ + diff --git a/docs/source/doc/llvm.passes.FunctionPassManager.md b/docs/source/doc/llvm.passes.FunctionPassManager.md deleted file mode 100644 index e1bc068..0000000 --- a/docs/source/doc/llvm.passes.FunctionPassManager.md +++ /dev/null @@ -1,35 +0,0 @@ ---- -layout: page -title: FunctionPassManager (llvm.passes) ---- - -# llvm.passes.FunctionPassManager - -## Base Classes - -- [llvm.passes.PassManager](llvm.passes.PassManager.html) - -## Methods - -### `finalize(self)` - -Finalizes all associated function passes in the LLVM system. - -Beware that this destroys all associated passes even if another -pass manager is using those passes. This may result is a segfault. - -### `initialize(self)` - -Initializes all associated function passes in the LLVM system. - -### `run(self, fn)` - -Run all passes on the given function `fn`. - -## Static Factory Methods - -### `new(module)` - -Create a `FunctionPassManager` instance for a given `module`. - - diff --git a/docs/source/doc/llvm.passes.FunctionPassManager.rst b/docs/source/doc/llvm.passes.FunctionPassManager.rst new file mode 100644 index 0000000..137cf74 --- /dev/null +++ b/docs/source/doc/llvm.passes.FunctionPassManager.rst @@ -0,0 +1,42 @@ ++--------------------------------------------+ +| layout: page | ++--------------------------------------------+ +| title: FunctionPassManager (llvm.passes) | ++--------------------------------------------+ + +llvm.passes.FunctionPassManager +=============================== + +Base Classes +------------ + +- `llvm.passes.PassManager `_ + +Methods +------- + +``finalize(self)`` +~~~~~~~~~~~~~~~~~~ + +Finalizes all associated function passes in the LLVM system. + +Beware that this destroys all associated passes even if another pass +manager is using those passes. This may result is a segfault. + +``initialize(self)`` +~~~~~~~~~~~~~~~~~~~~ + +Initializes all associated function passes in the LLVM system. + +``run(self, fn)`` +~~~~~~~~~~~~~~~~~ + +Run all passes on the given function ``fn``. + +Static Factory Methods +---------------------- + +``new(module)`` +~~~~~~~~~~~~~~~ + +Create a ``FunctionPassManager`` instance for a given ``module``. diff --git a/docs/source/doc/llvm.passes.PassManager.md b/docs/source/doc/llvm.passes.PassManager.md deleted file mode 100644 index 1883516..0000000 --- a/docs/source/doc/llvm.passes.PassManager.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -layout: page -title: PassManager (llvm.passes) ---- - -# llvm.passes.PassManager - -## Methods - -### `add(self, tgt_data_or_pass_id)` - -Add a pass by its ID. A pass IDs are defined as `PASS_*`. - -### `run(self, module)` - -Run all passes on the given `module`. - -## Static Factory Methods - -### `new()` - -Creates a new `PassManager` instance. - diff --git a/docs/source/doc/llvm.passes.PassManager.rst b/docs/source/doc/llvm.passes.PassManager.rst new file mode 100644 index 0000000..e0a2536 --- /dev/null +++ b/docs/source/doc/llvm.passes.PassManager.rst @@ -0,0 +1,29 @@ ++------------------------------------+ +| layout: page | ++------------------------------------+ +| title: PassManager (llvm.passes) | ++------------------------------------+ + +llvm.passes.PassManager +======================= + +Methods +------- + +``add(self, tgt_data_or_pass_id)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Add a pass by its ID. A pass IDs are defined as ``PASS_*``. + +``run(self, module)`` +~~~~~~~~~~~~~~~~~~~~~ + +Run all passes on the given ``module``. + +Static Factory Methods +---------------------- + +``new()`` +~~~~~~~~~ + +Creates a new ``PassManager`` instance. diff --git a/docs/source/doc/llvm.passes.PassManagerBuilder.md b/docs/source/doc/llvm.passes.PassManagerBuilder.md deleted file mode 100644 index 7992de4..0000000 --- a/docs/source/doc/llvm.passes.PassManagerBuilder.md +++ /dev/null @@ -1,59 +0,0 @@ ---- -layout: page -title: PassManagerBuilder (llvm.passes) ---- - -# llvm.passes.PassManagerBuilder - -Provide a simple API to populate pass managers for language like C/C++. -Refer to -[LLVM API Documentation](http://llvm.org/docs/doxygen/html/classllvm_1_1PassManagerBuilder.html) -for detail. - -## Methods - -### `populate(self, pm)` - -Populate a [FunctionPassManager](llvm.passes.FunctionPassManager.html) -or [PassManager](llvm.passes.PassManager.html) given as `pm`. - -### `use_inliner_with_threshold(self, threshold)` - -Use an inliner pass with the given `threshold`. - -## Properties - -The following properties can be overriden to customize how pass managers -are populated. - -### `disable_simplify_lib_calls` - -Boolean. Default is `False`. - -### `disable_unit_at_a_time` - -Boolean. Default is `False`. - -### `disable_unroll_loops` - -Boolean. Default is `False`. - -### `opt_level` - -Default is `2`. Valid values are 0-3. Corresponds to O0, O1, O2, O3 as in C/C++ -optimization options. - -### `size_level` - -Default is `0`. - -### `vectorize` - -Default is `False`. - -## Static Factory Methods - -### `new()` - -Creates a new `PassManagerBuilder` instance. - diff --git a/docs/source/doc/llvm.passes.PassManagerBuilder.rst b/docs/source/doc/llvm.passes.PassManagerBuilder.rst new file mode 100644 index 0000000..99e1935 --- /dev/null +++ b/docs/source/doc/llvm.passes.PassManagerBuilder.rst @@ -0,0 +1,72 @@ ++-------------------------------------------+ +| layout: page | ++-------------------------------------------+ +| title: PassManagerBuilder (llvm.passes) | ++-------------------------------------------+ + +llvm.passes.PassManagerBuilder +============================== + +Provide a simple API to populate pass managers for language like C/C++. +Refer to `LLVM API +Documentation `_ +for detail. + +Methods +------- + +``populate(self, pm)`` +~~~~~~~~~~~~~~~~~~~~~~ + +Populate a `FunctionPassManager `_ +or `PassManager `_ given as ``pm``. + +``use_inliner_with_threshold(self, threshold)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Use an inliner pass with the given ``threshold``. + +Properties +---------- + +The following properties can be overriden to customize how pass managers +are populated. + +``disable_simplify_lib_calls`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Boolean. Default is ``False``. + +``disable_unit_at_a_time`` +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Boolean. Default is ``False``. + +``disable_unroll_loops`` +~~~~~~~~~~~~~~~~~~~~~~~~ + +Boolean. Default is ``False``. + +``opt_level`` +~~~~~~~~~~~~~ + +Default is ``2``. Valid values are 0-3. Corresponds to O0, O1, O2, O3 as +in C/C++ optimization options. + +``size_level`` +~~~~~~~~~~~~~~ + +Default is ``0``. + +``vectorize`` +~~~~~~~~~~~~~ + +Default is ``False``. + +Static Factory Methods +---------------------- + +``new()`` +~~~~~~~~~ + +Creates a new ``PassManagerBuilder`` instance. diff --git a/docs/source/doc/llvm_concepts.md b/docs/source/doc/llvm_concepts.md deleted file mode 100644 index acd27ce..0000000 --- a/docs/source/doc/llvm_concepts.md +++ /dev/null @@ -1,242 +0,0 @@ ---- -layout: page -title: LLVM Concepts ---- - -This section explains a few concepts related to LLVM, not specific -to llvm-py. - - -# Intermediate Representation - -The intermediate representation, or IR for short, is an in-memory data -structure that represents executable code. The IR data structures allow -for creation of types, constants, functions, function arguments, -instructions, global variables and so on. For example, to create a -function _sum_ that takes two integers and returns their sum, we need to -follow these steps: - -- create an integer type _ti_ of required bitwidth -- create a function type _tf_ which takes two _ti_ -s and returns - another _ti_ -- create a function of type _tf_ named _sum_ -- add a _basic block_ to the function -- using a helper object called an _instruction builder_, add two - instructions into the basic block: - . an instruction to add the two arguments and store the result into - a temporary variable - . a return instruction to return the value of the temporary variable - -(A basic block is a block of instructions.) - -LLVM has it's own instruction set; the instructions used above (*add* -and *ret*) are from this set. The LLVM instructions are at a higher -level than the usual assembly language; for example there are -instructions related to variable argument handling, exception handling, -and garbage collection. These allow high-level languages to be -represented cleanly in the IR. - -* * * - -# SSA Form and PHI Nodes - -All LLVM instructions are represented in the _Static Single Assignment_ -(SSA) form. Essentially, this means that any variable can be assigned to -only once. Such a representation facilitates better optimization, among -other benefits. - -A consequence of single assignment are PHI (Φ) nodes. These -are required when a variable can be assigned a different value based on -the path of control flow. For example, the value of *b* at the end of -execution of the snippet below: - -{% highlight c %} -a = 1; -if (v < 10) - a = 2; -b = a; -{% endhighlight %} - -cannot be determined statically. The value of '2' cannot be assigned to -the 'original' *a*, since *a* can be assigned to only once. There are -two *a* 's in there, and the last assignment has to choose between which -version to pick. This is accomplished by adding a PHI node: - -{% highlight c %} -a1 = 1; -if (v < 10) - a2 = 2; -b = PHI(a1, a2); -{% endhighlight %} - -The PHI node selects *a1* or *a2*, depending on where the control -reached the PHI node. The argument *a1* of the PHI node is associated -with the block *"a1 = 1;"* and *a2* with the block *"a2 = 2;"*. - -PHI nodes have to be explicitly created in the LLVM IR. Accordingly the -LLVM instruction set has an instruction called *phi*. - - -* * * - -# LLVM Assembly Language - -The LLVM IR can be represented offline in two formats - -- a textual, human-readable form, similar to assembly language, - called the LLVM assembly language (files with .ll extension) -- a binary form, called the LLVM bitcode (files with .bc extension) - -All three formats -(the in-memory IR, the LLVM assembly language and the LLVM bitcode) -represent the _same_ information. Each format can be -converted into the other two formats (using LLVM APIs). - -The [LLVM demo page](http://www.llvm.org/demo/) lets you type in C or C++ -code, converts it into LLVM IR and outputs the IR as LLVM assembly -language code. - -Just to get a feel of the LLVM assembly language, here's a function in C, -and the corresponding LLVM assembly (as generated by the demo page): - -{% highlight c %} -/* compute sum of 1..n */ -unsigned sum(unsigned n) -{ - if (n == 0) - return 0; - else - return n + sum(n-1); -} -{% endhighlight %} - -The corresponding LLVM assembly: - -{% highlight llvm %} -; ModuleID = '/tmp/webcompile/_7149_0.bc' -target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64" -target triple = "x86_64-linux-gnu" - -define i32 @sum(i32 %n) nounwind readnone { -entry: - %0 = icmp eq i32 %n, 0 ; [#uses=1] - br i1 %0, label %bb2, label %bb1 - -bb1: ; preds = %entry - %1 = add i32 %n, -1 ; [#uses=2] - %2 = icmp eq i32 %1, 0 ; [#uses=1] - br i1 %2, label %sum.exit, label %bb1.i - -bb1.i: ; preds = %bb1 - %3 = add i32 %n, -2 ; [#uses=1] - %4 = tail call i32 @sum(i32 %3) nounwind ; [#uses=1] - %5 = add i32 %4, %1 ; [#uses=1] - br label %sum.exit - -sum.exit: ; preds = %bb1.i, %bb1 - %6 = phi i32 [ %5, %bb1.i ], [ 0, %bb1 ] ; [#uses=1] - %7 = add i32 %6, %n ; [#uses=1] - ret i32 %7 - -bb2: ; preds = %entry - ret i32 0 -} -{% endhighlight %} - -Note the usage of SSA form. The long string called `target datalayout` is a -specification of the platform ABI (like endianness, sizes of types, -alignment etc.). - -The [LLVM Language Reference](http://www.llvm.org/docs/LangRef.html) -defines the LLVM assembly language including the entire instruction set. - - -* * * - -# Modules - -[Modules](./llvm.core.Module.html), in the LLVM IR, are similar to a single *C* language source -file (.c file). A module contains: - -- functions (declarations and definitions) -- global variables and constants -- global type aliases for structures - -Modules are top-level containers; all executable code representation is -contained within modules. Modules may be combined (linked) together to -give a bigger resultant module. During this process LLVM attempts to -reconcile the references between the combined modules. - - -* * * - -# Optimization and Passes - - -LLVM provides quite a few optimization algorithms that work on the IR. -These algorithms are organized as _passes_. Each pass does something -specific, like combining redundant instructions. Passes need not always -optimize the IR, it can also do other operations like inserting -instrumentation code, or analyzing the IR (the result of which can be -used by passes that do optimizations) or even printing call graphs. - -This LLVM [documentation page](http://www.llvm.org/docs/Passes.html) -describes all the available passes, and what they do. - -LLVM does not automatically choose to run any passes, anytime. Passes -have to be explicitly selected and run on each module. This gives you -the flexibility to choose transformations and optimizations that are -most suitable for the code in the module. - -There is an LLVM binary called [opt](http://www.llvm.org/cmds/opt.html), -which lets you run passes on bitcode files from the command line. You -can write your own passes (in C/C++, as a shared library). This can be -loaded and executed by +opt+. (Although llvm-py does not allow you to -write your own passes, it does allow you to navigate the entire IR at -any stage, and perform any transforms on it as you like.) - -A "pass manager" is responsible for loading passes, selecting the -correct objects to run them on (for example, a pass may work only -on functions, individually) and actually runs them. `opt` is a -command-line wrapper for the pass manager. - -LLVM defines two kinds of pass managers: - -* The [FunctionPassManager](http://llvm.org/docs/doxygen/html/classllvm_1_1FunctionPassManager.html) - manages function or basic-block passes. These lighter weight passes - can be used immediately after each generated function to reduce memory - footprint. - -* The [PassManager](http://llvm.org/docs/doxygen/html/classllvm_1_1PassManager.html) - manages module passes for optimizing the entire module. - -* * * - - -# Bitcode - -LLVM IR can be represented as a bitcode format for disk storage. It is [suitable for fast loading by JIT compiler](http://llvm.org/docs/LangRef.html#introduction). -See [LLVM documentation](http://llvm.org/docs/BitCodeFormat.html) -for detail about the bitcode format. - - -* * * - -# Execution Engine, JIT and Interpreter - -The *execution engine* implements execution of LLVM IR through an -interpreter or a JIT dynamic compiler. An *execution engine* can -contain multiple modules. - -> **Note** -> -> -> Inter-module reference is not possible. That is module `A` -> cannot call a function in module `B`, directly. - - -* * * - -**Next** -- [llvm-py Package](./llvm-py_package.html) - - diff --git a/docs/source/doc/llvm_concepts.rst b/docs/source/doc/llvm_concepts.rst new file mode 100644 index 0000000..19bdd39 --- /dev/null +++ b/docs/source/doc/llvm_concepts.rst @@ -0,0 +1,214 @@ ++------------------------+ +| layout: page | ++------------------------+ +| title: LLVM Concepts | ++------------------------+ + +This section explains a few concepts related to LLVM, not specific to +llvmpy. + +Intermediate Representation +=========================== + +The intermediate representation, or IR for short, is an in-memory data +structure that represents executable code. The IR data structures allow +for creation of types, constants, functions, function arguments, +instructions, global variables and so on. For example, to create a +function *sum* that takes two integers and returns their sum, we need to +follow these steps: + +- create an integer type *ti* of required bitwidth +- create a function type *tf* which takes two *ti* -s and returns + another *ti* +- create a function of type *tf* named *sum* +- add a *basic block* to the function +- using a helper object called an *instruction builder*, add two + instructions into the basic block: . an instruction to add the two + arguments and store the result into a temporary variable . a return + instruction to return the value of the temporary variable + +(A basic block is a block of instructions.) + +LLVM has it's own instruction set; the instructions used above (*add* +and *ret*) are from this set. The LLVM instructions are at a higher +level than the usual assembly language; for example there are +instructions related to variable argument handling, exception handling, +and garbage collection. These allow high-level languages to be +represented cleanly in the IR. + +-------------- + +SSA Form and PHI Nodes +====================== + +All LLVM instructions are represented in the *Static Single Assignment* +(SSA) form. Essentially, this means that any variable can be assigned to +only once. Such a representation facilitates better optimization, among +other benefits. + +A consequence of single assignment are PHI (Φ) nodes. These are required +when a variable can be assigned a different value based on the path of +control flow. For example, the value of *b* at the end of execution of +the snippet below: + +{% highlight c %} a = 1; if (v < 10) a = 2; b = a; {% endhighlight %} + +cannot be determined statically. The value of '2' cannot be assigned to +the 'original' *a*, since *a* can be assigned to only once. There are +two *a* 's in there, and the last assignment has to choose between which +version to pick. This is accomplished by adding a PHI node: + +{% highlight c %} a1 = 1; if (v < 10) a2 = 2; b = PHI(a1, a2); {% +endhighlight %} + +The PHI node selects *a1* or *a2*, depending on where the control +reached the PHI node. The argument *a1* of the PHI node is associated +with the block *"a1 = 1;"* and *a2* with the block *"a2 = 2;"*. + +PHI nodes have to be explicitly created in the LLVM IR. Accordingly the +LLVM instruction set has an instruction called *phi*. + +-------------- + +LLVM Assembly Language +====================== + +The LLVM IR can be represented offline in two formats + +- a textual, human-readable form, similar to assembly language, called + the LLVM assembly language (files with .ll extension) +- a binary form, called the LLVM bitcode (files with .bc extension) + +All three formats (the in-memory IR, the LLVM assembly language and the +LLVM bitcode) represent the *same* information. Each format can be +converted into the other two formats (using LLVM APIs). + +The `LLVM demo page `_ lets you type in C or +C++ code, converts it into LLVM IR and outputs the IR as LLVM assembly +language code. + +Just to get a feel of the LLVM assembly language, here's a function in +C, and the corresponding LLVM assembly (as generated by the demo page): + +{% highlight c %} /\* compute sum of 1..n \*/ unsigned sum(unsigned n) { +if (n == 0) return 0; else return n + sum(n-1); } {% endhighlight %} + +The corresponding LLVM assembly: + +{% highlight llvm %} ; ModuleID = '/tmp/webcompile/\_7149\_0.bc' target +datalayout = +"e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64" +target triple = "x86\_64-linux-gnu" + +define i32 @sum(i32 %n) nounwind readnone { entry: %0 = icmp eq i32 %n, +0 ; [#uses=1] br i1 %0, label %bb2, label %bb1 + +bb1: ; preds = %entry %1 = add i32 %n, -1 ; [#uses=2] %2 = icmp eq i32 +%1, 0 ; [#uses=1] br i1 %2, label %sum.exit, label %bb1.i + +bb1.i: ; preds = %bb1 %3 = add i32 %n, -2 ; [#uses=1] %4 = tail call i32 +@sum(i32 %3) nounwind ; [#uses=1] %5 = add i32 %4, %1 ; [#uses=1] br +label %sum.exit + +sum.exit: ; preds = %bb1.i, %bb1 %6 = phi i32 [ %5, %bb1.i ], [ 0, %bb1 +] ; [#uses=1] %7 = add i32 %6, %n ; [#uses=1] ret i32 %7 + +bb2: ; preds = %entry ret i32 0 } {% endhighlight %} + +Note the usage of SSA form. The long string called ``target datalayout`` +is a specification of the platform ABI (like endianness, sizes of types, +alignment etc.). + +The `LLVM Language Reference `_ +defines the LLVM assembly language including the entire instruction set. + +-------------- + +Modules +======= + +`Modules <./llvm.core.Module.html>`_, in the LLVM IR, are similar to a +single *C* language source file (.c file). A module contains: + +- functions (declarations and definitions) +- global variables and constants +- global type aliases for structures + +Modules are top-level containers; all executable code representation is +contained within modules. Modules may be combined (linked) together to +give a bigger resultant module. During this process LLVM attempts to +reconcile the references between the combined modules. + +-------------- + +Optimization and Passes +======================= + +LLVM provides quite a few optimization algorithms that work on the IR. +These algorithms are organized as *passes*. Each pass does something +specific, like combining redundant instructions. Passes need not always +optimize the IR, it can also do other operations like inserting +instrumentation code, or analyzing the IR (the result of which can be +used by passes that do optimizations) or even printing call graphs. + +This LLVM `documentation page `_ +describes all the available passes, and what they do. + +LLVM does not automatically choose to run any passes, anytime. Passes +have to be explicitly selected and run on each module. This gives you +the flexibility to choose transformations and optimizations that are +most suitable for the code in the module. + +There is an LLVM binary called +`opt `_, which lets you run passes on +bitcode files from the command line. You can write your own passes (in +C/C++, as a shared library). This can be loaded and executed by +opt+. +(Although llvm-py does not allow you to write your own passes, it does +allow you to navigate the entire IR at any stage, and perform any +transforms on it as you like.) + +A "pass manager" is responsible for loading passes, selecting the +correct objects to run them on (for example, a pass may work only on +functions, individually) and actually runs them. ``opt`` is a +command-line wrapper for the pass manager. + +LLVM defines two kinds of pass managers: + +- The + `FunctionPassManager `_ + manages function or basic-block passes. These lighter weight passes + can be used immediately after each generated function to reduce + memory footprint. + +- The + `PassManager `_ + manages module passes for optimizing the entire module. + +-------------- + +Bitcode +======= + +LLVM IR can be represented as a bitcode format for disk storage. It is +`suitable for fast loading by JIT +compiler `_. See `LLVM +documentation `_ for detail +about the bitcode format. + +-------------- + +Execution Engine, JIT and Interpreter +===================================== + +The *execution engine* implements execution of LLVM IR through an +interpreter or a JIT dynamic compiler. An *execution engine* can contain +multiple modules. + + **Note** + + Inter-module reference is not possible. That is module ``A`` cannot + call a function in module ``B``, directly. + +-------------- + +**Next** -- `llvm-py Package <./llvm-py_package.html>`_ diff --git a/docs/source/doc/llvmpy_package.rst b/docs/source/doc/llvmpy_package.rst new file mode 100644 index 0000000..8fd8a9f --- /dev/null +++ b/docs/source/doc/llvmpy_package.rst @@ -0,0 +1,96 @@ ++------------------------------+ +| layout: page | ++------------------------------+ +| title: The llvm-py Package | ++------------------------------+ + +The llvm-py is a Python package, consisting of 6 modules, that wrap over +enough LLVM APIs to allow the implementation of your own compiler/VM +backend in pure Python. If you're come this far, you probably know why +this is a good idea. + +Out of the 6 modules, one is an "extension" module (i.e., it is written +in C), and another one is a small private utility module, which leaves 4 +public modules. These are: + +- *llvm* -- top-level package, common classes (like exceptions) +- *llvm.core* -- IR-related APIs +- *llvm.ee* -- execution engine related APIs +- *llvm.passes* -- pass manager and passes related APIs + +The modules contain only classes and (integer) constants. Mostly simple +Python constructs are used (deliberately) -- +`property() `_ and +`property +decorators `_ are +probably the most exotic animals around. All classes are "new style" +classes. The APIs are designed to be navigable (and guessable!) once you +know a few conventions. These conventions are highlighted in the +sections below. + +Here is a quick overview of the contents of each package: + +llvm +---- + +- LLVMException -- exception class (currently the only one) + +llvm.core +--------- + +- `Module `_ -- represents an LLVM Module +- `Type `_ -- represents an LLVM Type +- `Value `_ -- represents an LLVM Value, including: + globals, constants, variables, arguments, functions, instructions, + etc.. +- `BasicBlock `_ -- another derived of + Value, represents an LLVM basic block +- `Builder `_ -- used for creating + instructions, wraps LLVM IRBuilder helper class +- constants *TYPE\_\** that represents various types +- constants *CC\_\** that represent calling conventions +- constants *ICMP\_\** and *FCMP\_\** that represent integer and real + comparison predicates (like less than, greater than etc.) +- constants *LINKAGE\_\** that represent linkage of symbols (external, + internal etc.) +- constants *VISIBILITY\_\** that represents visibility of symbols + (default, hidden, protected) +- constants *ATTR\_\** that represent function parameter attributes + +llvm.ee +------- + +- `ExecutionEngine `_ -- represents an + execution engine (which can be an either an interpreter or a JIT) +- `TargetData `_ -- represents the ABI of the + target platform (details like sizes and alignment of primitive types, + endinanness etc) + +llvm.passes +----------- + +- `PassManager `_ -- represents an LLVM + pass manager +- `FunctionPassManager `_ -- + represents an LLVM function pass manager +- constants *PASS\_\** that represent various passes + +A note on the importing of these modules +---------------------------------------- + +Pythonically, modules are imported with the statement +``import llvm.core``. However, you might find it more convenient to +import llvm-py modules thus: + +{% highlight python %} from llvm import \* from llvm.core import \* from +llvm.ee import \* from llvm.passes import \* {% endhighlight %} + +This avoids quite some typing. Both conventions work, however. + + **Tip** + + Python-style documentation strings (``__doc__``) are present in + llvm-py. You can use the ``help()`` of the interactive Python + interpreter or the ``object?`` of + `IPython `_ to get online help. + (Note: not complete yet!) diff --git a/docs/source/doc/types.md b/docs/source/doc/types.md deleted file mode 100644 index c414061..0000000 --- a/docs/source/doc/types.md +++ /dev/null @@ -1,146 +0,0 @@ ---- -layout: page -title: Types ---- - -Types are what you think they are. A instance of [llvm.core.Type][], or -one of its derived classes, represent a type. llvm-py does not use as -many classes to represent types as does LLVM itself. Some types are -represented using [llvm.core.Type][] itself and the rest are represented -using derived classes of [llvm.core.Type][]. As usual, an instance is created -via one of the static methods of [Type][llvm.core.Type]. These methods return an -instance of either [llvm.core.Type][] itself or one of its derived -classes. - -The following table lists all the available types along with the static -method which has to be used to construct it and the name of the class whose -object is actually returned by the static method. - - -Name | Constructor Method | Class | ------|:------------------:|:-----:| -integer of bitwidth *n* | Type.int(n) | [IntegerType][llvm.core.IntegerType] | -32-bit float | Type.float() | [Type][llvm.core.Type] | -64-bit double | Type.double() | [Type][llvm.core.Type] | -80-bit float | Type.x86_fp80() | [Type][llvm.core.Type] | -128-bit float (112-bit mantissa) | Type.fp128() | [Type][llvm.core.Type] | -128-bit float (two 64-bits) | Type.ppc_fp128() | [Type][llvm.core.Type] | -function | Type.function(r, p, v) | [FunctionType][llvm.core.FunctionType] | -unpacked struct | Type.struct(eltys, name) | [StructType][llvm.core.StructType] | -packed struct | Type.packed_struct(eltys, name) | [StructType][llvm.core.StructType] | -opaque struct | Type.opaque(name) | [StructType][llvm.core.StructType] | -array | Type.array(elty, count) | [ArrayType][llvm.core.ArrayType] | -pointer to value of type *pty* | Type.pointer(pty, addrspc) | [PointerType][llvm.core.PointerType] | -vector | Type.vector(elty, count) | [VectorType][llvm.core.VectorType] | -void | Type.void() | [Type][llvm.core.Type] | -label | Type.label() | [Type][llvm.core.Type] | - - -
- - -The class hierarchy is: - - - Type - IntegerType - FunctionType - StructType - ArrayType - PointerType - VectorType - - - -* * * - -## An Example - -Here is an example that demonstrates the creation of types: - -{% highlight python %} -#!/usr/bin/env python - -# integers -int_ty = Type.int() -bool_ty = Type.int(1) -int_64bit = Type.int(64) - -# floats -sprec_real = Type.float() -dprec_real = Type.double() - -# arrays and vectors -intar_ty = Type.array( int_ty, 10 ) # "typedef int intar_ty[10];" -twodim = Type.array( intar_ty , 10 ) # "typedef int twodim[10][10];" -vec = Type.array( int_ty, 10 ) - -# structures -s1_ty = Type.struct( [ int_ty, sprec_real ] ) - # "struct s1_ty { int v1; float v2; };" - -# pointers -intptr_ty = Type.pointer(int_ty) # "typedef int *intptr_ty;" - -# functions -f1 = Type.function( int_ty, [ int_ty ] ) - # functions that take 1 int_ty and return 1 int_ty - -f2 = Type.function( Type.void(), [ int_ty, int_ty ] ) - # functions that take 2 int_tys and return nothing - -f3 = Type.function( Type.void(), ( int_ty, int_ty ) ) - # same as f2; any iterable can be used - -fnargs = [ Type.pointer( Type.int(8) ) ] -printf = Type.function( Type.int(), fnargs, True ) # variadic function -{% endhighlight %} - -* * * - -## Another Example: Recursive Type - -The type system was rewritten in LLVM 3.0. -The old opaque type was removed. -Instead, identified `StructType` can now be defined without a body. -Doing so creates a opaque structure. -One can then set the body after the construction of a structure. - - -(See [LLVM Blog](http://blog.llvm.org/2011/11/llvm-30-type-system-rewrite.html) -for detail about the new type system.) - -The following code defines a opaque structure, named "mystruct". -The body is defined after the construction using `StructType.set_body`. -The second subtype is a pointer to a "mystruct" type. - -{% highlight python %} -ts = Type.opaque('mystruct') -ts.set_body([Type.int(), Type.pointer(ts)]) -{% endhighlight %} - -* * * - -**Related Links** -[llvm.core.Type][], -[llvm.core.IntegerType][], -[llvm.core.FunctionType][], -[llvm.core.StructType][], -[llvm.core.ArrayType][], -[llvm.core.PointerType][], -[llvm.core.VectorType][], -[llvm.core.TypeHandle][] - - - - - -[llvm.core.Type]: llvm.core.Type.html -[llvm.core.IntegerType]: llvm.core.IntegerType.html -[llvm.core.FunctionType]: llvm.core.FunctionType.html -[llvm.core.StructType]: llvm.core.StructType.html -[llvm.core.ArrayType]: llvm.core.ArrayType.html -[llvm.core.PointerType]: llvm.core.PointerType.html -[llvm.core.VectorType]: llvm.core.VectorType.html -[llvm.core.TypeHandle]: llvm.core.TypeHandle.html - diff --git a/docs/source/doc/types.rst b/docs/source/doc/types.rst new file mode 100644 index 0000000..89098c7 --- /dev/null +++ b/docs/source/doc/types.rst @@ -0,0 +1,138 @@ ++----------------+ +| layout: page | ++----------------+ +| title: Types | ++----------------+ + +Types are what you think they are. A instance of +`llvm.core.Type `_, or one of its derived classes, +represent a type. llvm-py does not use as many classes to represent +types as does LLVM itself. Some types are represented using +`llvm.core.Type `_ itself and the rest are +represented using derived classes of +`llvm.core.Type `_. As usual, an instance is +created via one of the static methods of `Type `_. +These methods return an instance of either +`llvm.core.Type `_ itself or one of its derived +classes. + +The following table lists all the available types along with the static +method which has to be used to construct it and the name of the class +whose object is actually returned by the static method. + +Name \| Constructor Method \| Class \| +-----\|:------------------:\|:-----:\| integer of bitwidth *n* \| +Type.int(n) \| `IntegerType `_ \| 32-bit +float \| Type.float() \| `Type `_ \| 64-bit double +\| Type.double() \| `Type `_ \| 80-bit float \| +Type.x86\_fp80() \| `Type `_ \| 128-bit float +(112-bit mantissa) \| Type.fp128() \| `Type `_ \| +128-bit float (two 64-bits) \| Type.ppc\_fp128() \| +`Type `_ \| function \| Type.function(r, p, v) \| +`FunctionType `_ \| unpacked struct \| +Type.struct(eltys, name) \| `StructType `_ \| +packed struct \| Type.packed\_struct(eltys, name) \| +`StructType `_ \| opaque struct \| +Type.opaque(name) \| `StructType `_ \| array +\| Type.array(elty, count) \| `ArrayType `_ \| +pointer to value of type *pty* \| Type.pointer(pty, addrspc) \| +`PointerType `_ \| vector \| +Type.vector(elty, count) \| `VectorType `_ \| +void \| Type.void() \| `Type `_ \| label \| +Type.label() \| `Type `_ \| + +The class hierarchy is: + +:: + + Type + IntegerType + FunctionType + StructType + ArrayType + PointerType + VectorType + +-------------- + +An Example +---------- + +Here is an example that demonstrates the creation of types: + +{% highlight python %} #!/usr/bin/env python + +integers +======== + +int\_ty = Type.int() bool\_ty = Type.int(1) int\_64bit = Type.int(64) + +floats +====== + +sprec\_real = Type.float() dprec\_real = Type.double() + +arrays and vectors +================== + +intar\_ty = Type.array( int\_ty, 10 ) # "typedef int intar\_ty[10];" +twodim = Type.array( intar\_ty , 10 ) # "typedef int twodim[10][10];" +vec = Type.array( int\_ty, 10 ) + +structures +========== + +s1\_ty = Type.struct( [ int\_ty, sprec\_real ] ) # "struct s1\_ty { int +v1; float v2; };" + +pointers +======== + +intptr\_ty = Type.pointer(int\_ty) # "typedef int \*intptr\_ty;" + +functions +========= + +f1 = Type.function( int\_ty, [ int\_ty ] ) # functions that take 1 +int\_ty and return 1 int\_ty + +f2 = Type.function( Type.void(), [ int\_ty, int\_ty ] ) # functions that +take 2 int\_tys and return nothing + +f3 = Type.function( Type.void(), ( int\_ty, int\_ty ) ) # same as f2; +any iterable can be used + +fnargs = [ Type.pointer( Type.int(8) ) ] printf = Type.function( +Type.int(), fnargs, True ) # variadic function {% endhighlight %} + +-------------- + +Another Example: Recursive Type +------------------------------- + +The type system was rewritten in LLVM 3.0. The old opaque type was +removed. Instead, identified ``StructType`` can now be defined without a +body. Doing so creates a opaque structure. One can then set the body +after the construction of a structure. + +(See `LLVM +Blog `_ +for detail about the new type system.) + +The following code defines a opaque structure, named "mystruct". The +body is defined after the construction using ``StructType.set_body``. +The second subtype is a pointer to a "mystruct" type. + +{% highlight python %} ts = Type.opaque('mystruct') +ts.set\_body([Type.int(), Type.pointer(ts)]) {% endhighlight %} + +-------------- + +**Related Links** `llvm.core.Type `_, +`llvm.core.IntegerType `_, +`llvm.core.FunctionType `_, +`llvm.core.StructType `_, +`llvm.core.ArrayType `_, +`llvm.core.PointerType `_, +`llvm.core.VectorType `_, +`llvm.core.TypeHandle `_ diff --git a/docs/source/doc/userguide.md b/docs/source/doc/userguide.md deleted file mode 100644 index 16c0bff..0000000 --- a/docs/source/doc/userguide.md +++ /dev/null @@ -1,159 +0,0 @@ ---- -layout: page -title: User Guide ---- - -llvm-py provides Python bindings for LLVM. This document explains how you can setup and use it. A working knowledge of Python and a basic idea of LLVM is assumed. - -# Introduction - -[LLVM](http://www.llvm.org/) (Low-Level Virtual Machine) provides enough -infrastructure to use it as the backend for your compiled, or -JIT-compiled language. It provides extensive optimization support, and -static and dynamic (JIT) backends for many platforms. See the website at - to discover more. - -Python bindings for LLVM provides a gentler learning curve for working -with the LLVM APIs. It should also be easier to create working -prototypes and experimental languages using this medium. - -Together with [clang](http://clang.llvm.org/) or -[llvm-gcc](http://llvm.org/cmds/llvmgcc.html) it also a provides a means -to quickly instrument C and C++ sources. For e.g., llvm-gcc can be used to -generate the LLVM assembly for a given C source file, which can then be -loaded and manipulated (adding profiling code to every function, say) using -a llvm-py based Python script. - -## License -Both LLVM and llvm-py are distributed under (different) permissive -open source licenses. llvm-py uses the -[new BSD license](http://opensource.org/licenses/bsd-license.php). More -information is available [here](https://github.com/numba/llvm-py/blob/master/LICENSE). - -## Platforms -llvm-py has been built/tested/reported to work on various GNU/Linux -flavours, BSD, Mac OS X; on i386 and amd64 architectures. Windows is not -supported, for a variety of reasons. - -## Versions -llvm-py 0.8.2 requires version 3.1 of LLVM. It may not work with previous -versions. - -llvm-py has been built and tested with Python 2.7. It should work with -earlier versions. It has not been tried with Python 3.x (patches welcome). - - -* * * - - -# Installation - -The Git repo of llvm-py is at . You'll -need to build and install it before it can be used. -At least the following will be required for this: - -- C and C++ compilers (gcc/g++) -- Python itself -- Python development files (headers and libraries) -- LLVM, either installed or built - -On debian-based systems, the first three can be installed with the -command `sudo apt-get install gcc g++ python python-dev`. Ensure that your -distro's repository has the appropriate version of LLVM! - -It does not matter which compiler LLVM itself was built with (`g++`, -`llvm-g++` or any other); llvm-py can be built with any compiler. It has -been tried only with gcc/g++ though. - -## LLVM and `--enable-pic` - -The result of an LLVM build is a set of static libraries and object -files. The llvm-py contains an extension package that is built into a -shared object (_core.so) which links to these static libraries and -object files. It is therefore required that the LLVM libraries and -object files be built with the `-fPIC` option (generate position -independent code). Be sure to use the `--enable-pic` option while -configuring LLVM (default is no PIC), like this: - -{% highlight bash %} -~/llvm$ ./configure --enable-pic --enable-optimized -{% endhighlight %} - - -## llvm-config - -In order to build llvm-py, it's build script needs to know from where it -can invoke the llvm helper program, `llvm-config`. If you've installed -LLVM, then this will be available in your `PATH`, and nothing further -needs to be done. If you've built LLVM yourself, or for any reason -`llvm-config` is not in your `PATH`, you'll need to pass the full path -of `llvm-config` to the build script. - -You'll need to be 'root' to install llvm-py. Remember that your `PATH` -is different from that of 'root', so even if `llvm-config` is in your -`PATH`, it may not be available when you do `sudo`. - - - -## Steps - -Get 3.1 version of LLVM, build it. Make sure '--enable-pic' is passed to LLVM's 'configure'. - -Get llvm-py and install it: - -{% highlight bash %} -$ git clone git@github.com:numba/llvm-py.git -$ cd llvm-py -$ python setup.py install -{% endhighlight %} - -If you need to tell the build script where `llvm-config` is, do it this -way: - -{% highlight bash %} -$ python setup.py install --user --llvm-config=/home/mdevan/llvm/Release/bin/llvm-config -{% endhighlight %} - -To build a debug version of llvm-py, that links against the debug -libraries of LLVM, use this: - -{% highlight bash %} -$ python setup.py build -g --llvm-config=/home/mdevan/llvm/Debug/bin/llvm-config -$ python setup.py install --user --llvm-config=/home/mdevan/llvm/Debug/bin/llvm-config -{% endhighlight %} - -Be warned that debug binaries will be huge (100MB+) ! They are required -only if you need to debug into LLVM also. - -`setup.py` is a standard Python distutils script. See the Python -documentation regarding -[Installing Python Modules](http://docs.python.org/inst/inst.html) and -[Distributing Python Modules](http://docs.python.org/dist/dist.html) -for more information on such scripts. - -* * * - -# Uninstall # {#uninstall} - -If you'd installed llvm-py with the `--user` option, then llvm-py -would be present under `~/.local/lib/python2.7/site-packages`. -Otherwise, it might be under `/usr/lib/python2.7/site-packages` -or `/usr/local/lib/python2.7/site-packages`. The directory would -vary with your Python version and OS flavour. Look around. - -Once you've located the site-packages directory, the modules and -the "egg" can be removed like so: - -{% highlight bash %} -$ rm -rf /llvm /llvm_py-.egg-info -{% endhighlight %} - - -See the [Python documentation](http://docs.python.org/install/index.html) -for more information. - -* * * - -**Next** -- [LLVM concepts](./llvm_concepts.html) - - diff --git a/docs/source/doc/userguide.rst b/docs/source/doc/userguide.rst new file mode 100644 index 0000000..fd220e8 --- /dev/null +++ b/docs/source/doc/userguide.rst @@ -0,0 +1,165 @@ ++---------------------+ +| layout: page | ++---------------------+ +| title: User Guide | ++---------------------+ + +llvm-py provides Python bindings for LLVM. This document explains how +you can setup and use it. A working knowledge of Python and a basic idea +of LLVM is assumed. + +Introduction +============ + +`LLVM `_ (Low-Level Virtual Machine) provides +enough infrastructure to use it as the backend for your compiled, or +JIT-compiled language. It provides extensive optimization support, and +static and dynamic (JIT) backends for many platforms. See the website at +http://www.llvm.org/ to discover more. + +Python bindings for LLVM provides a gentler learning curve for working +with the LLVM APIs. It should also be easier to create working +prototypes and experimental languages using this medium. + +Together with `clang `_ or +`llvm-gcc `_ it also a provides a +means to quickly instrument C and C++ sources. For e.g., llvm-gcc can be +used to generate the LLVM assembly for a given C source file, which can +then be loaded and manipulated (adding profiling code to every function, +say) using a llvm-py based Python script. + +License +------- + +Both LLVM and llvm-py are distributed under (different) permissive open +source licenses. llvm-py uses the `new BSD +license `_. More +information is available +`here `_. + +Platforms +--------- + +llvm-py has been built/tested/reported to work on various GNU/Linux +flavours, BSD, Mac OS X; on i386 and amd64 architectures. Windows is not +supported, for a variety of reasons. + +Versions +-------- + +llvm-py 0.8.2 requires version 3.1 of LLVM. It may not work with +previous versions. + +llvm-py has been built and tested with Python 2.7. It should work with +earlier versions. It has not been tried with Python 3.x (patches +welcome). + +-------------- + +Installation +============ + +The Git repo of llvm-py is at https://github.com/numba/llvm-py.git. +You'll need to build and install it before it can be used. At least the +following will be required for this: + +- C and C++ compilers (gcc/g++) +- Python itself +- Python development files (headers and libraries) +- LLVM, either installed or built + +On debian-based systems, the first three can be installed with the +command ``sudo apt-get install gcc g++ python python-dev``. Ensure that +your distro's repository has the appropriate version of LLVM! + +It does not matter which compiler LLVM itself was built with (``g++``, +``llvm-g++`` or any other); llvm-py can be built with any compiler. It +has been tried only with gcc/g++ though. + +LLVM and ``--enable-pic`` +------------------------- + +The result of an LLVM build is a set of static libraries and object +files. The llvm-py contains an extension package that is built into a +shared object (\_core.so) which links to these static libraries and +object files. It is therefore required that the LLVM libraries and +object files be built with the ``-fPIC`` option (generate position +independent code). Be sure to use the ``--enable-pic`` option while +configuring LLVM (default is no PIC), like this: + +{% highlight bash %} ~/llvm$ ./configure --enable-pic --enable-optimized +{% endhighlight %} + +llvm-config +----------- + +In order to build llvm-py, it's build script needs to know from where it +can invoke the llvm helper program, ``llvm-config``. If you've installed +LLVM, then this will be available in your ``PATH``, and nothing further +needs to be done. If you've built LLVM yourself, or for any reason +``llvm-config`` is not in your ``PATH``, you'll need to pass the full +path of ``llvm-config`` to the build script. + +You'll need to be 'root' to install llvm-py. Remember that your ``PATH`` +is different from that of 'root', so even if ``llvm-config`` is in your +``PATH``, it may not be available when you do ``sudo``. + +Steps +----- + +Get 3.1 version of LLVM, build it. Make sure '--enable-pic' is passed to +LLVM's 'configure'. + +Get llvm-py and install it: + +{% highlight bash %} $ git clone git@github.com:numba/llvm-py.git $ cd +llvm-py $ python setup.py install {% endhighlight %} + +If you need to tell the build script where ``llvm-config`` is, do it +this way: + +{% highlight bash %} $ python setup.py install --user +--llvm-config=/home/mdevan/llvm/Release/bin/llvm-config {% endhighlight +%} + +To build a debug version of llvm-py, that links against the debug +libraries of LLVM, use this: + +{% highlight bash %} $ python setup.py build -g +--llvm-config=/home/mdevan/llvm/Debug/bin/llvm-config $ python setup.py +install --user --llvm-config=/home/mdevan/llvm/Debug/bin/llvm-config {% +endhighlight %} + +Be warned that debug binaries will be huge (100MB+) ! They are required +only if you need to debug into LLVM also. + +``setup.py`` is a standard Python distutils script. See the Python +documentation regarding `Installing Python +Modules `_ and `Distributing +Python Modules `_ for more +information on such scripts. + +-------------- + +Uninstall # {#uninstall} +======================== + +If you'd installed llvm-py with the ``--user`` option, then llvm-py +would be present under ``~/.local/lib/python2.7/site-packages``. +Otherwise, it might be under ``/usr/lib/python2.7/site-packages`` or +``/usr/local/lib/python2.7/site-packages``. The directory would vary +with your Python version and OS flavour. Look around. + +Once you've located the site-packages directory, the modules and the +"egg" can be removed like so: + +{% highlight bash %} $ rm -rf /llvm /llvm\_py-.egg-info {% endhighlight +%} + +See the `Python +documentation `_ for more +information. + +-------------- + +**Next** -- :doc:`llvm_concepts` diff --git a/docs/source/doc/values.md b/docs/source/doc/values.md deleted file mode 100644 index 39ba6b2..0000000 --- a/docs/source/doc/values.md +++ /dev/null @@ -1,88 +0,0 @@ ---- -layout: page -title: Values ---- - -[llvm.core.Value][] is the base class of all values computed by a program -that may be used as operands to other values. A value has a type -associated with it (an object of [llvm.core.Type][]). - -The class hierarchy is: - - - Value - User - Constant - ConstantExpr - ConstantAggregateZero - ConstantInt - ConstantFP - ConstantArray - ConstantStruct - ConstantVector - ConstantPointerNull - UndefValue - GlobalValue - GlobalVariable - Function - Instruction - CallOrInvokeInstruction - PHINode - SwitchInstruction - CompareInstruction - Argument - BasicBlock - - -The [Value][llvm.core.Value] class is abstract, it's not meant to be -instantiated. [User][llvm.core.User] is a [Value][llvm.core.Value] - that in turn uses (i.e., can refer to) other values (for -e.g., a constant expression 1+2 refers to two constant values 1 and 2). - -[Constant][llvm.core.Constant]-s represent constants that appear within code or -as initializers of globals. They are constructed using static methods of -[Constant][llvm.core.Constant]. Various types of constants are represented by -various subclasses of [Constant][llvm.core.Constant]. -However, most of them are empty and do not provide any additional attributes or methods over [Constant][llvm.core.Constant]. - -The [Function][functions] object represents an instance of a -function type. Such objects contain [Argument][llvm.core.Argument] objects, -which represent the actual, -local-variable-like arguments of the function (not to be confused with -the arguments returned by a function _type_ object -- these represent -the _type_ of the arguments). - -The various [Instruction][llvm.core.Instruction]-s are created -by the [Builder][llvm.core.Builder] class. Most -instructions are represented by [Instruction][llvm.core.Instruction] itself, -but there are a few subclasses that represent interesting instructions. - -[Value][llvm.core.Value] objects have a type (read-only), -and a name (read-write). - -**Related Links** -[functions][], -[comparision][], -[llvm.core.Value][], -[llvm.core.User][], -[llvm.core.Constant][], -[llvm.core.GlobalValue][], -[llvm.core.GlobalVariable][], -[llvm.core.Argument][], -[llvm.core.Instruction][], -[llvm.core.Builder][], -[llvm.core.BasicBlock][] - - -[llvm.core.Type]: types.html -[functions]: functions.html -[comparision]: comparision.html -[llvm.core.Value]: llvm.core.Value.html -[llvm.core.User]: llvm.core.User.html -[llvm.core.Constant]: llvm.core.Constant.html -[llvm.core.GlobalValue]: llvm.core.GlobalValue.html -[llvm.core.GlobalVariable]: llvm.core.GlobalVariable.html -[llvm.core.Argument]: llvm.core.Argument.html -[llvm.core.Instruction]: llvm.core.Instruction.html -[llvm.core.Builder]: llvm.core.Builder.html -[llvm.core.BasicBlock]: llvm.core.BasicBlock.html diff --git a/docs/source/doc/values.rst b/docs/source/doc/values.rst new file mode 100644 index 0000000..a999740 --- /dev/null +++ b/docs/source/doc/values.rst @@ -0,0 +1,78 @@ ++-----------------+ +| layout: page | ++-----------------+ +| title: Values | ++-----------------+ + +`llvm.core.Value `_ is the base class of all +values computed by a program that may be used as operands to other +values. A value has a type associated with it (an object of +`llvm.core.Type `_). + +The class hierarchy is: + +:: + + Value + User + Constant + ConstantExpr + ConstantAggregateZero + ConstantInt + ConstantFP + ConstantArray + ConstantStruct + ConstantVector + ConstantPointerNull + UndefValue + GlobalValue + GlobalVariable + Function + Instruction + CallOrInvokeInstruction + PHINode + SwitchInstruction + CompareInstruction + Argument + BasicBlock + +The `Value `_ class is abstract, it's not meant to +be instantiated. `User `_ is a +`Value `_ that in turn uses (i.e., can refer to) +other values (for e.g., a constant expression 1+2 refers to two constant +values 1 and 2). + +`Constant `_-s represent constants that appear +within code or as initializers of globals. They are constructed using +static methods of `Constant `_. Various types +of constants are represented by various subclasses of +`Constant `_. However, most of them are empty +and do not provide any additional attributes or methods over +`Constant `_. + +The `Function `_ object represents an instance of a +function type. Such objects contain +`Argument `_ objects, which represent the +actual, local-variable-like arguments of the function (not to be +confused with the arguments returned by a function *type* object -- +these represent the *type* of the arguments). + +The various `Instruction `_-s are created by +the `Builder `_ class. Most instructions are +represented by `Instruction `_ itself, but +there are a few subclasses that represent interesting instructions. + +`Value `_ objects have a type (read-only), and a +name (read-write). + +**Related Links** `functions `_, +`comparision `_, +`llvm.core.Value `_, +`llvm.core.User `_, +`llvm.core.Constant `_, +`llvm.core.GlobalValue `_, +`llvm.core.GlobalVariable `_, +`llvm.core.Argument `_, +`llvm.core.Instruction `_, +`llvm.core.Builder `_, +`llvm.core.BasicBlock `_ diff --git a/docs/source/index.rst b/docs/source/index.rst index 1ef8eaf..aabe218 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -3,14 +3,21 @@ You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. -Welcome to llvmpy's documentation! -================================== +Documenation for llvmpy +================= Contents: .. toctree:: :maxdepth: 2 + doc/userguide.rst + doc/llvmpy_package.rst + doc/llvm_concepts.rst + doc/types.rst + doc/examples/JITTutorial1.rst + doc/examples/JITTutorial2.rst + doc/kaleidoscope/PythonLangImpl1.rst Indices and tables From 3b0aeea6f28c07acac864c25f90cfde9e0efd15a Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 8 Aug 2012 16:27:57 -0700 Subject: [PATCH 054/675] change CDeclare to CFuncRef --- llvm_cbuilder/builder.py | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/llvm_cbuilder/builder.py b/llvm_cbuilder/builder.py index 99133e6..3b854b5 100644 --- a/llvm_cbuilder/builder.py +++ b/llvm_cbuilder/builder.py @@ -655,16 +655,36 @@ class _DeclareCDef(object): (func,) = e return func -class CDeclare(object): - '''create a function from name, type and pointer to use with - `CBuilder.depends` +class CFuncRef(object): + '''create a function reference to use with `CBuilder.depends` + + Either from name, type and pointer, + Or from a llvm.core.FunctionType instance ''' - def __init__(self, name, ty, ptr): - self._name = name - self._type = ty - self._ptr = ptr + def __init__(self, *args, **kwargs): + def one_arg(fn): + self._fn = fn + self._name = fn.name + + def three_arg(name, ty, ptr): + self._name = name + self._type = ty + self._ptr = ptr + + try: + three_arg(*args, **kwargs) + self._meth = self._from_pointer + except TypeError: + one_arg(*args, **kwargs) + self._meth = self._from_func def __call__(self, module): + return self._meth() + + def _from_func(self): + return self._fn + + def _from_pointer(self): fnptr = types.pointer(self._type) ptr = lc.Constant.int(types.intp, self._ptr) ptr = ptr.inttoptr(fnptr) From e35b8ca636cf0f4ff0cabb2d523c954aacbd42c6 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 8 Aug 2012 17:32:39 -0700 Subject: [PATCH 055/675] Add some float casting --- llvm_cbuilder/builder.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/llvm_cbuilder/builder.py b/llvm_cbuilder/builder.py index 3b854b5..15ef477 100644 --- a/llvm_cbuilder/builder.py +++ b/llvm_cbuilder/builder.py @@ -917,10 +917,19 @@ class CValue(object): else: return make(self.parent.builder.uitofp(self.value, ty)) elif self.is_real: - if not unsigned: - return make(self.parent.builder.fptosi(self.value, ty)) + if _is_int(ty): + if not unsigned: + return make(self.parent.builder.fptosi(self.value, ty)) + else: + return make(self.parent.builder.fptoui(self.value, ty)) else: - return make(self.parent.builder.fptoui(self.value, ty)) + if ty == types.double: + assert self.type == types.float + return make(self.parent.builder.fpext(self.value, ty)) + else: + assert ty == types.float + assert self.type == types.double + return make(self.parent.builder.fptrunc(self.value, ty)) errmsg = "Cast from %s to %s is not possible." raise TypeError(errmsg % (self.type, ty)) From b23d7909fbd4b1c59e4320d3025b7ca0a7ce6924 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 8 Aug 2012 17:33:00 -0700 Subject: [PATCH 056/675] add parallel_vectorize_from_func --- parallel_vectorize.py | 84 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/parallel_vectorize.py b/parallel_vectorize.py index f26ad46..f70954b 100644 --- a/parallel_vectorize.py +++ b/parallel_vectorize.py @@ -16,6 +16,8 @@ from llvm.passes import * from llvm_cbuilder import * import llvm_cbuilder.shortnames as C +import sys + class WorkQueue(CStruct): '''structure for workqueue for parallel-ufunc. ''' @@ -365,3 +367,85 @@ class PThreadAPI(CExternal): 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): + fntype = lfunc.type.pointee + def_spuf = SpecializedParallelUFunc(ParallelUFuncPlatform(num_thread=2), + 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.uint8, + 'i16' : np.uint16, + 'i32' : np.uint32, + 'i64' : np.uint64, + '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]) + From 753f74d48562193ecbd6dc9cd5ec52bdf59fe26c Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 8 Aug 2012 17:33:24 -0700 Subject: [PATCH 057/675] Fix tests --- test_parallel_vectorize.py | 2 +- test_parallel_vectorize_numpy_2.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test_parallel_vectorize.py b/test_parallel_vectorize.py index 54d6b14..1a850f5 100644 --- a/test_parallel_vectorize.py +++ b/test_parallel_vectorize.py @@ -23,7 +23,7 @@ class UFuncCore_D_D(UFuncCore): outbase = common.args[1] instep = common.steps[0] - outstep = 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)) diff --git a/test_parallel_vectorize_numpy_2.py b/test_parallel_vectorize_numpy_2.py index a511980..f846a25 100644 --- a/test_parallel_vectorize_numpy_2.py +++ b/test_parallel_vectorize_numpy_2.py @@ -18,7 +18,7 @@ def main(): # get pointer to workfunc workfunc_ptr = exe.engine.get_pointer_to_function(workfunc) - workdecl = CDeclare(workfunc.name, workfunc.type.pointee, workfunc_ptr) + workdecl = CFuncRef(workfunc.name, workfunc.type.pointee, workfunc_ptr) spufdef = SpecializedParallelUFunc(ParallelUFuncPosix(num_thread=2), UFuncCore_D_D(), From c6d5538eade22fec6587a0177631dcb5fabfa63e Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 8 Aug 2012 17:33:34 -0700 Subject: [PATCH 058/675] Add usecase tests --- test_usecase_1_1.py | 56 +++++++++++++++++++++++++++++++++++++++++++ test_usecase_2_1.py | 58 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 114 insertions(+) create mode 100644 test_usecase_1_1.py create mode 100644 test_usecase_2_1.py diff --git a/test_usecase_1_1.py b/test_usecase_1_1.py new file mode 100644 index 0000000..5cc4d7a --- /dev/null +++ b/test_usecase_1_1.py @@ -0,0 +1,56 @@ +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 new file mode 100644 index 0000000..087ee9f --- /dev/null +++ b/test_usecase_2_1.py @@ -0,0 +1,58 @@ +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() + From 9ccc6782c7b5a9afeeefc2ed6acd13ca30c95c3f Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Wed, 8 Aug 2012 17:46:20 -0700 Subject: [PATCH 059/675] Add doc for parallel_vectorize_from_func. Add FunctionAlreadyExists exception. --- llvm_cbuilder/builder.py | 7 +++++-- parallel_vectorize.py | 6 ++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/llvm_cbuilder/builder.py b/llvm_cbuilder/builder.py index 15ef477..fc4baa3 100644 --- a/llvm_cbuilder/builder.py +++ b/llvm_cbuilder/builder.py @@ -12,6 +12,9 @@ from . import shortnames as types # Utilities ### +class FunctionAlreadyExists(NameError): + pass + def _is_int(ty): return isinstance(ty, lc.IntegerType) @@ -651,7 +654,7 @@ class _DeclareCDef(object): def __call__(self, module): try: func = self.cdef.define(module) - except NameError as e: + except FunctionAlreadyExists as e: (func,) = e return func @@ -740,7 +743,7 @@ class CDefinition(CBuilder): func = module.get_or_insert_function(functype, name=name) if not func.is_declaration: # already defined? - raise NameError(func) + raise FunctionAlreadyExists(func) # Name all arguments for i, (name, _) in enumerate(cls._argtys_): diff --git a/parallel_vectorize.py b/parallel_vectorize.py index f70954b..210dea8 100644 --- a/parallel_vectorize.py +++ b/parallel_vectorize.py @@ -410,6 +410,12 @@ else: 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 + ''' fntype = lfunc.type.pointee def_spuf = SpecializedParallelUFunc(ParallelUFuncPlatform(num_thread=2), UFuncCoreGeneric(fntype), From 75ca0289b5bc6c33abfe9eaaa439cdfafb9be6a4 Mon Sep 17 00:00:00 2001 From: "Travis E. Oliphant" Date: Thu, 9 Aug 2012 01:16:36 -0500 Subject: [PATCH 060/675] Update llvm-py to llvmpy and fix more docs --- docs/source/doc/examples.rst | 8 ++-- docs/source/doc/functions.rst | 6 +-- .../doc/kaleidoscope/PythonLangImpl3.rst | 12 ++--- .../doc/kaleidoscope/PythonLangImpl4.rst | 2 +- docs/source/doc/llvm.core.Instruction.rst | 2 +- docs/source/doc/llvm.core.Module.rst | 6 +-- docs/source/doc/llvm_concepts.rst | 4 +- docs/source/doc/llvmpy_package.rst | 8 ++-- docs/source/doc/types.rst | 2 +- docs/source/doc/userguide.rst | 44 +++++++++---------- docs/source/index.rst | 11 ++--- 11 files changed, 49 insertions(+), 56 deletions(-) diff --git a/docs/source/doc/examples.rst b/docs/source/doc/examples.rst index bbce175..98552bf 100644 --- a/docs/source/doc/examples.rst +++ b/docs/source/doc/examples.rst @@ -23,7 +23,7 @@ Here's how it looks like: {% highlight python %} #!/usr/bin/env python -Import the llvm-py modules. +Import the llvmpy modules. =========================== from llvm import \* from llvm.core import \* @@ -55,7 +55,7 @@ ty\_func = Type.function(ty\_int, [ty\_int, ty\_int]) Now we need a function named 'sum' of this type. Functions are not ================================================================== -free-standing (in llvm-py); it needs to be contained in a module. +free-standing (in llvmpy); it needs to be contained in a module. ================================================================= f\_sum = my\_module.add\_function(ty\_func, "sum") @@ -118,7 +118,7 @@ Let's compile this function in-memory and run it. {% highlight python %} #!/usr/bin/env python -Import the llvm-py modules. +Import the llvmpy modules. =========================== from llvm import \* from llvm.core import \* from llvm.ee import \* # @@ -183,7 +183,7 @@ Kaleidoscope ## {#kaleidoscope} Implementing a Language with LLVM The LLVM `Kaleidoscope `_ tutorial -has been ported to llvm-py by Max Shawabkeh. +has been ported to llvmpy by Max Shawabkeh. 1. `Tutorial Introduction and the Lexer `_ diff --git a/docs/source/doc/functions.rst b/docs/source/doc/functions.rst index 97ce73b..e56afe6 100644 --- a/docs/source/doc/functions.rst +++ b/docs/source/doc/functions.rst @@ -72,11 +72,11 @@ constants in ``llvm.core``. These are: There are also target-specific intrinsics (which correspond to that target's CPU instructions) available, but are omitted here for brevity. Full list can be seen from -[*intrinsic\_ids.py](https://github.com/numba/llvm-py/blob/master/llvm/*\ intrinsic\_ids.py). +[*intrinsic\_ids.py](https://github.com/numba/llvmpy/blob/master/llvm/*\ intrinsic\_ids.py). See the `LLVM Language Reference `_ for more information on the intrinsics, and the -`test `_ +`test `_ directory in the source distribution for more examples. The intrinsic ID can be retrieved from a function object with the read-only property ``intrinsic_id``. @@ -84,7 +84,7 @@ can be retrieved from a function object with the read-only property **Auto-generation of Intrinsic IDs** A script (tool/intrgen.py in source tree) generates the intrinsic - IDs automatically. This is necessary when compiling llvm-py with a + IDs automatically. This is necessary when compiling llvmpy with a different version of LLVM. Calling Convention # {#callconv} diff --git a/docs/source/doc/kaleidoscope/PythonLangImpl3.rst b/docs/source/doc/kaleidoscope/PythonLangImpl3.rst index 7679c8c..61594b1 100644 --- a/docs/source/doc/kaleidoscope/PythonLangImpl3.rst +++ b/docs/source/doc/kaleidoscope/PythonLangImpl3.rst @@ -29,12 +29,12 @@ will teach you a little bit about how LLVM does things, as well as demonstrate how easy it is to use. It's much more work to build a lexer and parser than it is to generate LLVM IR code. :) -**Please note**: the code in this chapter and later requires llvm-py 0.6 +**Please note**: the code in this chapter and later requires llvmpy 0.6 and LLVM 2.7. Earlier versions will most likely not work with it. Also note that you need to use a version of this tutorial that matches your -llvm-py release: If you are using an official llvm-py release, use the -version of the documentation on the `llvm-py examples -page `_ +llvmpy release: If you are using an official llvm-py release, use the +version of the documentation on the `llvmpy examples +page `_ -------------- @@ -128,7 +128,7 @@ First we'll do numeric literals: {% highlight python %} def CodeGen(self): return Constant.real(Type.double(), self.value) {% endhighlight %} -In llvm-py, floating point numeric constants are represented with the +In llvmpy, floating point numeric constants are represented with the ``llvm.core.ConstantFP`` class. To create one, we can use the static ``real()`` method in the ``llvm.core.Constant`` class. This code basically just creates and returns a ``ConstantFP``. Note that in the @@ -514,7 +514,7 @@ Full Code Listing # {#code} =========================== Here is the complete code listing for our running example, enhanced with -the LLVM code generator. Because this uses the llvm-py libraries, you +the LLVM code generator. Because this uses the llvmpy libraries, you need to `download <../download.html>`_ and `install <../userguide.html#install>`_ them. diff --git a/docs/source/doc/kaleidoscope/PythonLangImpl4.rst b/docs/source/doc/kaleidoscope/PythonLangImpl4.rst index 7aa4c85..14cefb5 100644 --- a/docs/source/doc/kaleidoscope/PythonLangImpl4.rst +++ b/docs/source/doc/kaleidoscope/PythonLangImpl4.rst @@ -329,7 +329,7 @@ Now we can load this library into the Python process using to produce simple output to the console: {% highlight python %} >>> import llvm.core >>> -llvm.core.load\_library\_permanently('/home/max/llvm-py-tutorial/putchard.so') +llvm.core.load\_library\_permanently('/home/max/llvmpy-tutorial/putchard.so') >>> import kaleidoscope >>> kaleidoscope.main() ready> extern putchard(x) Read an extern: declare double @putchard(double) diff --git a/docs/source/doc/llvm.core.Instruction.rst b/docs/source/doc/llvm.core.Instruction.rst index b03ce33..95aeb81 100644 --- a/docs/source/doc/llvm.core.Instruction.rst +++ b/docs/source/doc/llvm.core.Instruction.rst @@ -27,7 +27,7 @@ using ``operands`` property from the The name of the instruction (like ``add``, ``mul`` etc) can be got via the ``opcode_name`` property. The ``basic_block`` property gives the -basic block to which the instruction belongs to. Note that llvm-py does +basic block to which the instruction belongs to. Note that llvmpy does not allow free-standing instruction objects (i.e., all instructions are created contained within a basic block). diff --git a/docs/source/doc/llvm.core.Module.rst b/docs/source/doc/llvm.core.Module.rst index e5e2e04..19b810a 100644 --- a/docs/source/doc/llvm.core.Module.rst +++ b/docs/source/doc/llvm.core.Module.rst @@ -18,11 +18,11 @@ create a module my\_module = Module.new('my\_module') {% endhighlight %} The constructor of the Module class should *not* be used to instantiate -a Module object. This is a common feature for all llvm-py classes. +a Module object. This is a common feature for all llvmpy classes. **Convention** - *All* llvm-py objects are instantiated using static methods of + *All* llvmpy objects are instantiated using static methods of corresponding classes. Constructors *should not* be used. The argument ``my_module`` is a module identifier (a plain string). @@ -225,7 +225,7 @@ compares the resultant strings. **Convention** - *All* llvm-py objects (where it makes sense), when stringified, + *All* llvmpy objects (where it makes sense), when stringified, return the LLVM assembly representation. ``print module_obj`` for example, prints the LLVM assembly form of the entire module. diff --git a/docs/source/doc/llvm_concepts.rst b/docs/source/doc/llvm_concepts.rst index 19bdd39..a5b449b 100644 --- a/docs/source/doc/llvm_concepts.rst +++ b/docs/source/doc/llvm_concepts.rst @@ -163,7 +163,7 @@ There is an LLVM binary called `opt `_, which lets you run passes on bitcode files from the command line. You can write your own passes (in C/C++, as a shared library). This can be loaded and executed by +opt+. -(Although llvm-py does not allow you to write your own passes, it does +(Although llvmpy does not allow you to write your own passes, it does allow you to navigate the entire IR at any stage, and perform any transforms on it as you like.) @@ -211,4 +211,4 @@ multiple modules. -------------- -**Next** -- `llvm-py Package <./llvm-py_package.html>`_ +**Next** -- `llvmpy Package <./llvm-py_package.html>`_ diff --git a/docs/source/doc/llvmpy_package.rst b/docs/source/doc/llvmpy_package.rst index 8fd8a9f..1a9ad6f 100644 --- a/docs/source/doc/llvmpy_package.rst +++ b/docs/source/doc/llvmpy_package.rst @@ -1,10 +1,10 @@ +------------------------------+ | layout: page | +------------------------------+ -| title: The llvm-py Package | +| title: The llvmpy Package | +------------------------------+ -The llvm-py is a Python package, consisting of 6 modules, that wrap over +The llvmpy is a Python package, consisting of 6 modules, that wrap over enough LLVM APIs to allow the implementation of your own compiler/VM backend in pure Python. If you're come this far, you probably know why this is a good idea. @@ -80,7 +80,7 @@ A note on the importing of these modules Pythonically, modules are imported with the statement ``import llvm.core``. However, you might find it more convenient to -import llvm-py modules thus: +import llvmpy modules thus: {% highlight python %} from llvm import \* from llvm.core import \* from llvm.ee import \* from llvm.passes import \* {% endhighlight %} @@ -90,7 +90,7 @@ This avoids quite some typing. Both conventions work, however. **Tip** Python-style documentation strings (``__doc__``) are present in - llvm-py. You can use the ``help()`` of the interactive Python + llvmpy. You can use the ``help()`` of the interactive Python interpreter or the ``object?`` of `IPython `_ to get online help. (Note: not complete yet!) diff --git a/docs/source/doc/types.rst b/docs/source/doc/types.rst index 89098c7..2ca095c 100644 --- a/docs/source/doc/types.rst +++ b/docs/source/doc/types.rst @@ -6,7 +6,7 @@ Types are what you think they are. A instance of `llvm.core.Type `_, or one of its derived classes, -represent a type. llvm-py does not use as many classes to represent +represent a type. llvmpy does not use as many classes to represent types as does LLVM itself. Some types are represented using `llvm.core.Type `_ itself and the rest are represented using derived classes of diff --git a/docs/source/doc/userguide.rst b/docs/source/doc/userguide.rst index fd220e8..8b5c267 100644 --- a/docs/source/doc/userguide.rst +++ b/docs/source/doc/userguide.rst @@ -1,10 +1,8 @@ -+---------------------+ -| layout: page | -+---------------------+ -| title: User Guide | -+---------------------+ +************ +User Guide +************ -llvm-py provides Python bindings for LLVM. This document explains how +llvmpy provides Python bindings for LLVM. This document explains how you can setup and use it. A working knowledge of Python and a basic idea of LLVM is assumed. @@ -26,31 +24,31 @@ Together with `clang `_ or means to quickly instrument C and C++ sources. For e.g., llvm-gcc can be used to generate the LLVM assembly for a given C source file, which can then be loaded and manipulated (adding profiling code to every function, -say) using a llvm-py based Python script. +say) using a llvmpy based Python script. License ------- -Both LLVM and llvm-py are distributed under (different) permissive open -source licenses. llvm-py uses the `new BSD +Both LLVM and llvmpy are distributed under (different) permissive open +source licenses. llvmpy uses the `new BSD license `_. More information is available -`here `_. +`here `_. Platforms --------- -llvm-py has been built/tested/reported to work on various GNU/Linux +llvmpy has been built/tested/reported to work on various GNU/Linux flavours, BSD, Mac OS X; on i386 and amd64 architectures. Windows is not supported, for a variety of reasons. Versions -------- -llvm-py 0.8.2 requires version 3.1 of LLVM. It may not work with +llvmpy 0.8.2 requires version 3.1 of LLVM. It may not work with previous versions. -llvm-py has been built and tested with Python 2.7. It should work with +llvmpy has been built and tested with Python 2.7. It should work with earlier versions. It has not been tried with Python 3.x (patches welcome). @@ -59,7 +57,7 @@ welcome). Installation ============ -The Git repo of llvm-py is at https://github.com/numba/llvm-py.git. +The Git repo of llvmpy is at https://github.com/numba/llvmpy.git. You'll need to build and install it before it can be used. At least the following will be required for this: @@ -73,14 +71,14 @@ command ``sudo apt-get install gcc g++ python python-dev``. Ensure that your distro's repository has the appropriate version of LLVM! It does not matter which compiler LLVM itself was built with (``g++``, -``llvm-g++`` or any other); llvm-py can be built with any compiler. It +``llvm-g++`` or any other); llvmpy can be built with any compiler. It has been tried only with gcc/g++ though. LLVM and ``--enable-pic`` ------------------------- The result of an LLVM build is a set of static libraries and object -files. The llvm-py contains an extension package that is built into a +files. The llvmpy contains an extension package that is built into a shared object (\_core.so) which links to these static libraries and object files. It is therefore required that the LLVM libraries and object files be built with the ``-fPIC`` option (generate position @@ -93,14 +91,14 @@ configuring LLVM (default is no PIC), like this: llvm-config ----------- -In order to build llvm-py, it's build script needs to know from where it +In order to build llvmpy, it's build script needs to know from where it can invoke the llvm helper program, ``llvm-config``. If you've installed LLVM, then this will be available in your ``PATH``, and nothing further needs to be done. If you've built LLVM yourself, or for any reason ``llvm-config`` is not in your ``PATH``, you'll need to pass the full path of ``llvm-config`` to the build script. -You'll need to be 'root' to install llvm-py. Remember that your ``PATH`` +You'll need to be 'root' to install llvmpy. Remember that your ``PATH`` is different from that of 'root', so even if ``llvm-config`` is in your ``PATH``, it may not be available when you do ``sudo``. @@ -110,10 +108,10 @@ Steps Get 3.1 version of LLVM, build it. Make sure '--enable-pic' is passed to LLVM's 'configure'. -Get llvm-py and install it: +Get llvmpy and install it: -{% highlight bash %} $ git clone git@github.com:numba/llvm-py.git $ cd -llvm-py $ python setup.py install {% endhighlight %} +{% highlight bash %} $ git clone git@github.com:numba/llvmpy.git $ cd +llvmpy $ python setup.py install {% endhighlight %} If you need to tell the build script where ``llvm-config`` is, do it this way: @@ -122,7 +120,7 @@ this way: --llvm-config=/home/mdevan/llvm/Release/bin/llvm-config {% endhighlight %} -To build a debug version of llvm-py, that links against the debug +To build a debug version of llvmpy, that links against the debug libraries of LLVM, use this: {% highlight bash %} $ python setup.py build -g @@ -144,7 +142,7 @@ information on such scripts. Uninstall # {#uninstall} ======================== -If you'd installed llvm-py with the ``--user`` option, then llvm-py +If you'd installed llvmpy with the ``--user`` option, then llvmpy would be present under ``~/.local/lib/python2.7/site-packages``. Otherwise, it might be under ``/usr/lib/python2.7/site-packages`` or ``/usr/local/lib/python2.7/site-packages``. The directory would vary diff --git a/docs/source/index.rst b/docs/source/index.rst index aabe218..76670e6 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -3,21 +3,16 @@ You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. -Documenation for llvmpy +Documentation for llvmpy ================= Contents: .. toctree:: - :maxdepth: 2 + :titlesonly: doc/userguide.rst - doc/llvmpy_package.rst - doc/llvm_concepts.rst - doc/types.rst - doc/examples/JITTutorial1.rst - doc/examples/JITTutorial2.rst - doc/kaleidoscope/PythonLangImpl1.rst + doc/examples.rst Indices and tables From 415c01f74545fa4a83602ffa1f48046a341cca53 Mon Sep 17 00:00:00 2001 From: "Travis E. Oliphant" Date: Thu, 9 Aug 2012 13:53:21 -0500 Subject: [PATCH 061/675] DOC: Add first version of updated documentation. --- docs/source/doc/examples.rst | 207 +----------------- docs/source/doc/examples/JITTutorial1.rst | 61 +++--- docs/source/doc/examples/JITTutorial2.rst | 87 ++++---- docs/source/doc/examples/index.rst | 10 + docs/source/doc/firstexample.rst | 125 +++++++++++ docs/source/doc/getting_started.rst | 153 +++++++++++++ .../doc/kaleidoscope/PythonLangImpl1.rst | 20 +- .../doc/kaleidoscope/PythonLangImpl2.rst | 18 +- .../doc/kaleidoscope/PythonLangImpl3.rst | 21 +- .../doc/kaleidoscope/PythonLangImpl4.rst | 19 +- .../doc/kaleidoscope/PythonLangImpl5.rst | 19 +- .../doc/kaleidoscope/PythonLangImpl6.rst | 19 +- .../doc/kaleidoscope/PythonLangImpl7.rst | 19 +- .../doc/kaleidoscope/PythonLangImpl8.rst | 15 +- docs/source/doc/kaleidoscope/index.rst | 21 ++ docs/source/doc/llvm_concepts.rst | 88 +++++--- docs/source/doc/llvmpy_package.rst | 8 +- docs/source/doc/userguide.rst | 158 +------------ docs/source/index.rst | 1 + 19 files changed, 474 insertions(+), 595 deletions(-) create mode 100644 docs/source/doc/examples/index.rst create mode 100644 docs/source/doc/firstexample.rst create mode 100644 docs/source/doc/getting_started.rst create mode 100644 docs/source/doc/kaleidoscope/index.rst diff --git a/docs/source/doc/examples.rst b/docs/source/doc/examples.rst index 98552bf..9e01700 100644 --- a/docs/source/doc/examples.rst +++ b/docs/source/doc/examples.rst @@ -1,203 +1,12 @@ -+--------------------------------------+ -| layout: page | -+--------------------------------------+ -| title: Examples and LLVM Tutorials | -+--------------------------------------+ +******************************** +Examples and LLVM Tutorials +******************************** -- This will become a table of contents (this text will be scraped). - {:toc} +.. toctree:: + :maxdepth: 1 -Examples -======== + firstexample.rst + examples/index.rst + kaleidoscope/index.rst -A Simple Function ------------------ - -Let's create a (LLVM) module containing a single function, corresponding -to the ``C`` function: - -{% highlight c %} int sum(int a, int b) { return a + b; } {% -endhighlight %} - -Here's how it looks like: - -{% highlight python %} #!/usr/bin/env python - -Import the llvmpy modules. -=========================== - -from llvm import \* from llvm.core import \* - -Create an (empty) module. -========================= - -my\_module = Module.new('my\_module') - -All the types involved here are "int"s. This type is represented -================================================================ - -by an object of the llvm.core.Type class: -========================================= - -ty\_int = Type.int() # by default 32 bits - -We need to represent the class of functions that accept two integers -==================================================================== - -and return an integer. This is represented by an object of the -============================================================== - -function type (llvm.core.FunctionType): -======================================= - -ty\_func = Type.function(ty\_int, [ty\_int, ty\_int]) - -Now we need a function named 'sum' of this type. Functions are not -================================================================== - -free-standing (in llvmpy); it needs to be contained in a module. -================================================================= - -f\_sum = my\_module.add\_function(ty\_func, "sum") - -Let's name the function arguments as 'a' and 'b'. -================================================= - -f\_sum.args[0].name = "a" f\_sum.args[1].name = "b" - -Our function needs a "basic block" -- a set of instructions that -================================================================ - -end with a terminator (like return, branch etc.). By convention -=============================================================== - -the first block is called "entry". -================================== - -bb = f\_sum.append\_basic\_block("entry") - -Let's add instructions into the block. For this, we need an -=========================================================== - -instruction builder: -==================== - -builder = Builder.new(bb) - -OK, now for the instructions themselves. We'll create an add -============================================================ - -instruction that returns the sum as a value, which we'll use -============================================================ - -a ret instruction to return. -============================ - -tmp = builder.add(f\_sum.args[0], f\_sum.args[1], "tmp") -builder.ret(tmp) - -We've completed the definition now! Let's see the LLVM assembly -=============================================================== - -language representation of what we've created: -============================================== - -print my\_module {% endhighlight %} - -Here is the output: - -{% highlight llvm %} ; ModuleID = 'my\_module' - -define i32 @sum(i32 %a, i32 %b) { entry: %tmp = add i32 %a, %b ; -[#uses=1] ret i32 %tmp } {% endhighlight %} - -Adding JIT Compilation ----------------------- - -Let's compile this function in-memory and run it. - -{% highlight python %} #!/usr/bin/env python - -Import the llvmpy modules. -=========================== - -from llvm import \* from llvm.core import \* from llvm.ee import \* # -new import: ee = Execution Engine - -Create a module, as in the previous example. -============================================ - -my\_module = Module.new('my\_module') ty\_int = Type.int() # by default -32 bits ty\_func = Type.function(ty\_int, [ty\_int, ty\_int]) f\_sum = -my\_module.add\_function(ty\_func, "sum") f\_sum.args[0].name = "a" -f\_sum.args[1].name = "b" bb = f\_sum.append\_basic\_block("entry") -builder = Builder.new(bb) tmp = builder.add(f\_sum.args[0], -f\_sum.args[1], "tmp") builder.ret(tmp) - -Create an execution engine object. This will create a JIT compiler -================================================================== - -on platforms that support it, or an interpreter otherwise. -========================================================== - -ee = ExecutionEngine.new(my\_module) - -The arguments needs to be passed as "GenericValue" objects. -=========================================================== - -arg1 = GenericValue.int(ty\_int, 100) arg2 = GenericValue.int(ty\_int, -42) - -Now let's compile and run! -========================== - -retval = ee.run\_function(f\_sum, [arg1, arg2]) - -The return value is also GenericValue. Let's print it. -====================================================== - -print "returned", retval.as\_int() {% endhighlight %} - -And here's the output: - -:: - - returned 142 - --------------- - -LLVM Tutorials -============== - -Simple JIT Tutorials --------------------- - -The following JIT tutorials were contributed by Sebastien Binet. - -1. `A First Function `_ -2. `A More Complicated Function `_ - -Kaleidoscope ## {#kaleidoscope} -------------------------------- - -Implementing a Language with LLVM - -The LLVM `Kaleidoscope `_ tutorial -has been ported to llvmpy by Max Shawabkeh. - -1. `Tutorial Introduction and the - Lexer `_ -2. `Implementing a Parser and AST `_ -3. `Implementing Code Generation to LLVM - IR `_ -4. `Adding JIT and Optimizer - Support `_ -5. `Extending the language: control - flow `_ -6. `Extending the language: user-defined - operators `_ -7. `Extending the language: mutable variables / SSA - construction `_ -8. `Conclusion and other useful LLVM - tidbits `_ diff --git a/docs/source/doc/examples/JITTutorial1.rst b/docs/source/doc/examples/JITTutorial1.rst index 7c02fb1..09f3c33 100644 --- a/docs/source/doc/examples/JITTutorial1.rst +++ b/docs/source/doc/examples/JITTutorial1.rst @@ -1,45 +1,36 @@ -+-------------------------+ -| layout: page | -+-------------------------+ -| title: JIT Tutorial 1 | -+-------------------------+ +A First Function +================== -{% highlight python %} #!/usr/bin/env python +.. code-block:: python -from llvm.core import \* + #!/usr/bin/env python + + from llvm.core import * -create a module -=============== + #create a module + module = Module.new("tut1") -module = Module.new ("tut1") + #create a function type taking 3 32-bit integers, return a 32-bit integer + ty_int = Type.int(32) + func_type = Type.function(ty_int, (ty_int,)*3) -create a function type taking 3 32-bit integers, return a 32-bit integer -======================================================================== + #create a function of that type + mul_add = Function.new (module, func_type, "mul_add") + mul_add.calling_convention = CC_C + x = mul_add.args[0]; x.name = "x" + y = mul_add.args[1]; y.name = "y" + z = mul_add.args[2]; z.name = "z" -ty\_int = Type.int (32) func\_type = Type.function (ty\_int, -(ty\_int,)\*3) + #implement the function -create a function of that type -============================== + #new block + blk = mul_add.append_basic_block("entry") -mul\_add = Function.new (module, func\_type, "mul\_add") -mul\_add.calling\_convention = CC\_C x = mul\_add.args[0]; x.name = "x" -y = mul\_add.args[1]; y.name = "y" z = mul\_add.args[2]; z.name = "z" + #IR builder + bldr = Builder.new(blk) + tmp_1 = bldr.mul(x, y, "tmp_1") + tmp_2 = bldr.add(tmp_1, z, "tmp_2") -implement the function -====================== + bldr.ret(tmp_2) -new block -========= - -blk = mul\_add.append\_basic\_block ("entry") - -IR builder -========== - -bldr = Builder.new (blk) tmp\_1 = bldr.mul (x, y, "tmp\_1") tmp\_2 = -bldr.add (tmp\_1, z, "tmp\_2") - -bldr.ret (tmp\_2) - -print(module) {% endhighlight %} + print module diff --git a/docs/source/doc/examples/JITTutorial2.rst b/docs/source/doc/examples/JITTutorial2.rst index 8c420c5..a9a9979 100644 --- a/docs/source/doc/examples/JITTutorial2.rst +++ b/docs/source/doc/examples/JITTutorial2.rst @@ -1,62 +1,55 @@ -+-------------------------+ -| layout: page | -+-------------------------+ -| title: JIT Tutorial 2 | -+-------------------------+ +A More Complicated Function +==================== -{% highlight python %} #!/usr/bin/env python +.. code-block:: python -from llvm.core import \* + #!/usr/bin/env python -create a module -=============== + from llvm.core import * -module = Module.new ("tut2") + #create a module + module = Module.new("tut2") -create a function type taking 2 integers, return a 32-bit integer -================================================================= + #create a function type taking 2 integers, return a 32-bit integer + ty_int = Type.int(32) + func_type = Type.function(ty_int, (ty_int, ty_int)) -ty\_int = Type.int (32) func\_type = Type.function (ty\_int, (ty\_int, -ty\_int)) + #create a function of that type + gcd = Function.new(module, func_type, "gcd") -create a function of that type -============================== + #name function args + x = gcd.args[0]; x.name = "x" + y = gcd.args[1]; y.name = "y" -gcd = Function.new (module, func\_type, "gcd") + #implement the function -name function args -================== + #blocks... + entry = gcd.append_basic_block("entry") + ret = gcd.append_basic_block("return") + cond_false = gcd.append_basic_block("cond_false") + cond_true = gcd.append_basic_block("cond_true") + cond_false_2 = gcd.append_basic_block("cond_false_2") -x = gcd.args[0]; x.name = "x" y = gcd.args[1]; y.name = "y" + #create a llvm::IRBuilder + bldr = Builder.new(entry) + x_eq_y = bldr.icmp(IPRED_EQ, x, y, "tmp") + bldr.cbranch(x_eq_y, ret, cond_false) -implement the function -====================== + bldr.position_at_end (ret) + bldr.ret(x) -blocks... -========= + bldr.position_at_end(cond_false) + x_lt_y = bldr.icmp(IPRED_ULT, x, y, "tmp") + bldr.cbranch(x_lt_y, cond_true, cond_false_2) -entry = gcd.append\_basic\_block ("entry") ret = -gcd.append\_basic\_block ("return") cond\_false = -gcd.append\_basic\_block ("cond\_false") cond\_true = -gcd.append\_basic\_block ("cond\_true") cond\_false\_2 = -gcd.append\_basic\_block ("cond\_false\_2") + bldr.position_at_end(cond_true) + y_sub_x = bldr.sub(y, x, "tmp") + recur_1 = bldr.call(gcd, (x, y_sub_x,), "tmp") + bldr.ret(recur_1) -create a llvm::IRBuilder -======================== + bldr.position_at_end(cond_false_2) + x_sub_y = bldr.sub(x, y, "x_sub_y") + recur_2 = bldr.call(gcd, (x_sub_y, y,), "tmp") + bldr.ret(recur_2) -bldr = Builder.new (entry) x\_eq\_y = bldr.icmp (IPRED\_EQ, x, y, "tmp") -bldr.cbranch (x\_eq\_y, ret, cond\_false) - -bldr.position\_at\_end (ret) bldr.ret(x) - -bldr.position\_at\_end (cond\_false) x\_lt\_y = bldr.icmp (IPRED\_ULT, -x, y, "tmp") bldr.cbranch (x\_lt\_y, cond\_true, cond\_false\_2) - -bldr.position\_at\_end (cond\_true) y\_sub\_x = bldr.sub (y, x, "tmp") -recur\_1 = bldr.call (gcd, (x, y\_sub\_x,), "tmp") bldr.ret (recur\_1) - -bldr.position\_at\_end (cond\_false\_2) x\_sub\_y = bldr.sub (x, y, -"x\_sub\_y") recur\_2 = bldr.call (gcd, (x\_sub\_y, y,), "tmp") bldr.ret -(recur\_2) - -print(module) {% endhighlight %} + print module diff --git a/docs/source/doc/examples/index.rst b/docs/source/doc/examples/index.rst new file mode 100644 index 0000000..0cd3532 --- /dev/null +++ b/docs/source/doc/examples/index.rst @@ -0,0 +1,10 @@ +LLVM Tutorials +============== + +The following JIT tutorials were contributed by Sebastien Binet. + +.. toctree:: + :titlesonly: + + JITTutorial1.rst + JITTutorial2.rst diff --git a/docs/source/doc/firstexample.rst b/docs/source/doc/firstexample.rst new file mode 100644 index 0000000..0f6a4d0 --- /dev/null +++ b/docs/source/doc/firstexample.rst @@ -0,0 +1,125 @@ +Examples +======== + +A Simple Function +----------------- + +Let's create a (LLVM) module containing a single function, corresponding +to the ``C`` function: + +.. code-block:: c + + int sum(int a, int b) + { + return a + b; + } + +Here's how it looks in llvmpy: + +.. code-block:: python + + #!/usr/bin/env python + + # Import the llvmpy modules. + from llvm import * + from llvm.core import * + + # Create an (empty) module. + my_module = Module.new('my_module') + + # All the types involved here are "int"s. This type is represented + # by an object of the llvm.core.Type class: + ty_int = Type.int() # by default 32 bits + + # We need to represent the class of functions that accept two integers + # and return an integer. This is represented by an object of the + # function type (llvm.core.FunctionType): + ty_func = Type.function(ty_int, [ty_int, ty_int]) + + # Now we need a function named 'sum' of this type. Functions are not + # free-standing (in llvmpy); it needs to be contained in a module. + + f_sum = my_module.add_function(ty_func, "sum") + + # Let's name the function arguments as 'a' and 'b'. + f_sum.args[0].name = "a" + f_sum.args[1].name = "b" + + # Our function needs a "basic block" -- a set of instructions that + # end with a terminator (like return, branch etc.). By convention + # the first block is called "entry". + bb = f_sum.append_basic_block("entry") + + # Let's add instructions into the block. For this, we need an + # instruction builder: + builder = Builder.new(bb) + + # OK, now for the instructions themselves. We'll create an add + # instruction that returns the sum as a value, which we'll use + # a ret instruction to return. + tmp = builder.add(f_sum.args[0], f_sum.args[1], "tmp") + builder.ret(tmp) + + # We've completed the definition now! Let's see the LLVM assembly + # language representation of what we've created: + + print my_module + +Here is the output: + +.. code-block:: llvm + + ; ModuleID = 'my_module' + + define i32 @sum(i32 %a, i32 %b) { + entry: + %tmp = add i32 %a, %b ; [#uses=1] + ret i32 %tmp + } + +Adding JIT Compilation +---------------------- + +Let's compile this function in-memory and run it. + +.. code-block:: python + + #!/usr/bin/env python + + # Import the llvmpy modules. + + from llvm import * + from llvm.core import * + from llvm.ee import * # new import: ee = Execution Engine + + #Create a module, as in the previous example. + my_module = Module.new('my_module') + ty_int = Type.int() # by default 32 bits + ty_func = Type.function(ty_int, [ty_int, ty_int]) + f_sum = my_module.add_function(ty_func, "sum") + f_sum.args[0].name = "a" + f_sum.args[1].name = "b" + bb = f_sum.append_basic_block("entry") + builder = Builder.new(bb) + tmp = builder.add(f_sum.args[0], f_sum.args[1], "tmp") + builder.ret(tmp) + + # Create an execution engine object. This will create a JIT compiler + # on platforms that support it, or an interpreter otherwise. + ee = ExecutionEngine.new(my_module) + + # The arguments needs to be passed as "GenericValue" objects. + arg1 = GenericValue.int(ty_int, 100) + arg2 = GenericValue.int(ty_int, 42) + + # Now let's compile and run! + retval = ee.run_function(f_sum, [arg1, arg2]) + + # The return value is also GenericValue. Let's print it. + print "returned", retval.as_int() + +And here's the output: + +:: + + returned 142 diff --git a/docs/source/doc/getting_started.rst b/docs/source/doc/getting_started.rst new file mode 100644 index 0000000..4d35074 --- /dev/null +++ b/docs/source/doc/getting_started.rst @@ -0,0 +1,153 @@ + +Introduction +============ + +`LLVM `_ (Low-Level Virtual Machine) provides +enough infrastructure to use it as the backend for your compiled, or +JIT-compiled language. It provides extensive optimization support, and +static and dynamic (JIT) backends for many platforms. See the website at +http://www.llvm.org/ to discover more. + +Python bindings for LLVM provides a gentler learning curve for working +with the LLVM APIs. It should also be easier to create working +prototypes and experimental languages using this medium. + +Together with `clang `_ or +`llvm-gcc `_ it also a provides a +means to quickly instrument C and C++ sources. For e.g., llvm-gcc can be +used to generate the LLVM assembly for a given C source file, which can +then be loaded and manipulated (adding profiling code to every function, +say) using a llvmpy based Python script. + +License +------- + +Both LLVM and llvmpy are distributed under (different) permissive open +source licenses. llvmpy uses the `new BSD +license `_. More +information is available +`here `_. + +Platforms +--------- + +llvmpy has been built/tested/reported to work on various GNU/Linux +flavours, BSD, Mac OS X; on i386 and amd64 architectures. Windows is not +supported, for a variety of reasons. + +Versions +-------- + +llvmpy 0.8.2 requires version 3.1 of LLVM. It may not work with +previous versions. + +llvmpy has been built and tested with Python 2.7. It should work with +earlier versions. It has not been tried with Python 3.x (patches +welcome). + + +Installation +============ + +The Git repo of llvmpy is at https://github.com/numba/llvmpy.git. +You'll need to build and install it before it can be used. At least the +following will be required for this: + +- C and C++ compilers (gcc/g++) +- Python itself +- Python development files (headers and libraries) +- LLVM, either installed or built + +On debian-based systems, the first three can be installed with the +command ``sudo apt-get install gcc g++ python python-dev``. Ensure that +your distro's repository has the appropriate version of LLVM! + +It does not matter which compiler LLVM itself was built with (``g++``, +``llvm-g++`` or any other); llvmpy can be built with any compiler. It +has been tried only with gcc/g++ though. + + +LLVM and ``--enable-pic`` +------------------------- + +The result of an LLVM build is a set of static libraries and object +files. The llvmpy contains an extension package that is built into a +shared object (\_core.so) which links to these static libraries and +object files. It is therefore required that the LLVM libraries and +object files be built with the ``-fPIC`` option (generate position +independent code). Be sure to use the ``--enable-pic`` option while +configuring LLVM (default is no PIC), like this: + +{% highlight bash %} ~/llvm$ ./configure --enable-pic --enable-optimized +{% endhighlight %} + +llvm-config +----------- + +In order to build llvmpy, it's build script needs to know from where it +can invoke the llvm helper program, ``llvm-config``. If you've installed +LLVM, then this will be available in your ``PATH``, and nothing further +needs to be done. If you've built LLVM yourself, or for any reason +``llvm-config`` is not in your ``PATH``, you'll need to pass the full +path of ``llvm-config`` to the build script. + +You'll need to be 'root' to install llvmpy. Remember that your ``PATH`` +is different from that of 'root', so even if ``llvm-config`` is in your +``PATH``, it may not be available when you do ``sudo``. + +Steps +----- + +Get 3.1 version of LLVM, build it. Make sure '--enable-pic' is passed to +LLVM's 'configure'. + +Get llvmpy and install it: + +{% highlight bash %} $ git clone git@github.com:numba/llvmpy.git $ cd +llvmpy $ python setup.py install {% endhighlight %} + +If you need to tell the build script where ``llvm-config`` is, do it +this way: + +{% highlight bash %} $ python setup.py install --user +--llvm-config=/home/mdevan/llvm/Release/bin/llvm-config {% endhighlight +%} + +To build a debug version of llvmpy, that links against the debug +libraries of LLVM, use this: + +{% highlight bash %} $ python setup.py build -g +--llvm-config=/home/mdevan/llvm/Debug/bin/llvm-config $ python setup.py +install --user --llvm-config=/home/mdevan/llvm/Debug/bin/llvm-config {% +endhighlight %} + +Be warned that debug binaries will be huge (100MB+) ! They are required +only if you need to debug into LLVM also. + +``setup.py`` is a standard Python distutils script. See the Python +documentation regarding `Installing Python +Modules `_ and `Distributing +Python Modules `_ for more +information on such scripts. + + +Uninstall +============== + +If you'd installed llvmpy with the ``--user`` option, then llvmpy +would be present under ``~/.local/lib/python2.7/site-packages``. +Otherwise, it might be under ``/usr/lib/python2.7/site-packages`` or +``/usr/local/lib/python2.7/site-packages``. The directory would vary +with your Python version and OS flavour. Look around. + +Once you've located the site-packages directory, the modules and the +"egg" can be removed like so: + +{% highlight bash %} $ rm -rf /llvm /llvm\_py-.egg-info {% endhighlight +%} + +See the `Python +documentation `_ for more +information. + +-------------- diff --git a/docs/source/doc/kaleidoscope/PythonLangImpl1.rst b/docs/source/doc/kaleidoscope/PythonLangImpl1.rst index 4bbb81f..3314187 100644 --- a/docs/source/doc/kaleidoscope/PythonLangImpl1.rst +++ b/docs/source/doc/kaleidoscope/PythonLangImpl1.rst @@ -1,24 +1,12 @@ -+------------------------------------+ -| layout: page | -+------------------------------------+ -| title: "Kaleidoscope: Chapter 1" | -+------------------------------------+ - -Tutorial Introduction and the Lexer -=================================== +************************************************* +Chapter 1: Tutorial Introduction and the Lexer +************************************************* Written by `Chris Lattner `_ and `Max Shawabkeh `_ -**Chapter 1** - -- This will become a table of contents (this text will be scraped). - {:toc} - -`**Chapter 2: Implementing a Parser and AST** `_ - Introduction -============ +========= Welcome to the "Implementing a language with LLVM" tutorial. This tutorial runs through the implementation of a simple language, showing diff --git a/docs/source/doc/kaleidoscope/PythonLangImpl2.rst b/docs/source/doc/kaleidoscope/PythonLangImpl2.rst index d7d3bd1..f918633 100644 --- a/docs/source/doc/kaleidoscope/PythonLangImpl2.rst +++ b/docs/source/doc/kaleidoscope/PythonLangImpl2.rst @@ -1,22 +1,10 @@ -+------------------------------------+ -| layout: page | -+------------------------------------+ -| title: "Kaleidoscope: Chapter 2" | -+------------------------------------+ - -Implementing a Parser and AST -============================= +*************************************************** +Chapter 2: Implementing a Parser and AST +*************************************************** Written by `Chris Lattner `_ and `Max Shawabkeh `_ -**Chapter 2** - -- This will become a table of contents (this text will be scraped). - {:toc} - -**`Chapter 3: Code generation to LLVM IR `_** - Introduction # {#intro} ======================= diff --git a/docs/source/doc/kaleidoscope/PythonLangImpl3.rst b/docs/source/doc/kaleidoscope/PythonLangImpl3.rst index 61594b1..562f0f3 100644 --- a/docs/source/doc/kaleidoscope/PythonLangImpl3.rst +++ b/docs/source/doc/kaleidoscope/PythonLangImpl3.rst @@ -1,23 +1,10 @@ -+------------------------------------+ -| layout: page | -+------------------------------------+ -| title: "Kaleidoscope: Chapter 3" | -+------------------------------------+ - -Code generation to LLVM IR -========================== +******************************************* +Chapter 3: Code generation to LLVM IR +******************************************* Written by `Chris Lattner `_ and `Max Shawabkeh `_ -**Chapter 3** - -- This will become a table of contents (this text will be scraped). - {:toc} - -**`Chapter 4: Adding JIT and Optimizer -Support `_** - Introduction # {#intro} ======================= @@ -32,7 +19,7 @@ and parser than it is to generate LLVM IR code. :) **Please note**: the code in this chapter and later requires llvmpy 0.6 and LLVM 2.7. Earlier versions will most likely not work with it. Also note that you need to use a version of this tutorial that matches your -llvmpy release: If you are using an official llvm-py release, use the +llvmpy release: If you are using an official llvmpy release, use the version of the documentation on the `llvmpy examples page `_ diff --git a/docs/source/doc/kaleidoscope/PythonLangImpl4.rst b/docs/source/doc/kaleidoscope/PythonLangImpl4.rst index 14cefb5..d9e32da 100644 --- a/docs/source/doc/kaleidoscope/PythonLangImpl4.rst +++ b/docs/source/doc/kaleidoscope/PythonLangImpl4.rst @@ -1,23 +1,10 @@ -+------------------------------------+ -| layout: page | -+------------------------------------+ -| title: "Kaleidoscope: Chapter 4" | -+------------------------------------+ - -Adding JIT and Optimizer Support -================================ +************************************************* +Chapter 4: Adding JIT and Optimizer Support +************************************************* Written by `Chris Lattner `_ and `Max Shawabkeh `_ -**Chapter 4** - -- This will become a table of contents (this text will be scraped). - {:toc} - -**`Chapter 5: Extending the Language: Control -Flow `_** - Introduction # {#intro} ======================= diff --git a/docs/source/doc/kaleidoscope/PythonLangImpl5.rst b/docs/source/doc/kaleidoscope/PythonLangImpl5.rst index 326a5bf..e66944e 100644 --- a/docs/source/doc/kaleidoscope/PythonLangImpl5.rst +++ b/docs/source/doc/kaleidoscope/PythonLangImpl5.rst @@ -1,23 +1,10 @@ -+------------------------------------+ -| layout: page | -+------------------------------------+ -| title: "Kaleidoscope: Chapter 5" | -+------------------------------------+ - -Extending the Language: Control Flow -==================================== +***************************************************** +Chapter 5: Extending the Language: Control Flow +***************************************************** Written by `Chris Lattner `_ and `Max Shawabkeh `_ -**Chapter 5** - -- This will become a table of contents (this text will be scraped). - {:toc} - -**`Chapter 6: Extending the Language: User-defined -Operators `_** - Introduction # {#intro} ======================= diff --git a/docs/source/doc/kaleidoscope/PythonLangImpl6.rst b/docs/source/doc/kaleidoscope/PythonLangImpl6.rst index c0c1f0e..c7e354d 100644 --- a/docs/source/doc/kaleidoscope/PythonLangImpl6.rst +++ b/docs/source/doc/kaleidoscope/PythonLangImpl6.rst @@ -1,23 +1,10 @@ -+------------------------------------+ -| layout: page | -+------------------------------------+ -| title: "Kaleidoscope: Chapter 6" | -+------------------------------------+ - -Extending the Language: User-defined Operators -============================================== +********************************************************************** +Chapter 6: Extending the Language: User-defined Operators +********************************************************************** Written by `Chris Lattner `_ and `Max Shawabkeh `_ -**Chapter 6** - -- This will become a table of contents (this text will be scraped). - {:toc} - -**`Chapter 7: Extending the Language: Mutable Variables / SSA -Construction `_** - Introduction # {#intro} ======================= diff --git a/docs/source/doc/kaleidoscope/PythonLangImpl7.rst b/docs/source/doc/kaleidoscope/PythonLangImpl7.rst index ada3043..cc44969 100644 --- a/docs/source/doc/kaleidoscope/PythonLangImpl7.rst +++ b/docs/source/doc/kaleidoscope/PythonLangImpl7.rst @@ -1,23 +1,10 @@ -+------------------------------------+ -| layout: page | -+------------------------------------+ -| title: "Kaleidoscope: Chapter 7" | -+------------------------------------+ - -Extending the Language: Mutable Variables / SSA construction -============================================================ +******************************************************************************* +Chapter 7: Extending the Language: Mutable Variables / SSA construction +******************************************************************************* Written by `Chris Lattner `_ and `Max Shawabkeh `_ -**Chapter 7** - -- This will become a table of contents (this text will be scraped). - {:toc} - -**`Chapter 8: Conclusion and other useful LLVM -tidbits `_** - Introduction # {#intro} ======================= diff --git a/docs/source/doc/kaleidoscope/PythonLangImpl8.rst b/docs/source/doc/kaleidoscope/PythonLangImpl8.rst index cb9eebf..d9b81ac 100644 --- a/docs/source/doc/kaleidoscope/PythonLangImpl8.rst +++ b/docs/source/doc/kaleidoscope/PythonLangImpl8.rst @@ -1,18 +1,9 @@ -+------------------------------------+ -| layout: page | -+------------------------------------+ -| title: "Kaleidoscope: Chapter 8" | -+------------------------------------+ - -Conclusion and other useful LLVM tidbits -======================================== +***************************************************************** +Chapter 8: Conclusion and other useful LLVM tidbits +***************************************************************** Written by `Chris Lattner `_ -**Chapter 8** - -- This will become a table of contents (this text will be scraped). - {:toc} Tutorial Conclusion # {#conclusion} =================================== diff --git a/docs/source/doc/kaleidoscope/index.rst b/docs/source/doc/kaleidoscope/index.rst new file mode 100644 index 0000000..6099fea --- /dev/null +++ b/docs/source/doc/kaleidoscope/index.rst @@ -0,0 +1,21 @@ +Kaleidoscope +-------------- + +Implementing a Language with LLVM + +The LLVM `Kaleidoscope `_ tutorial +has been ported to llvmpy by Max Shawabkeh. + +.. toctree:: + :titlesonly: + :numbered: + + PythonLangImpl1.rst + PythonLangImpl2.rst + PythonLangImpl3.rst + PythonLangImpl4.rst + PythonLangImpl5.rst + PythonLangImpl6.rst + PythonLangImpl7.rst + PythonLangImpl8.rst + diff --git a/docs/source/doc/llvm_concepts.rst b/docs/source/doc/llvm_concepts.rst index a5b449b..c5f74aa 100644 --- a/docs/source/doc/llvm_concepts.rst +++ b/docs/source/doc/llvm_concepts.rst @@ -1,12 +1,16 @@ -+------------------------+ -| layout: page | -+------------------------+ -| title: LLVM Concepts | -+------------------------+ +******************** +LLVM Concepts +******************** This section explains a few concepts related to LLVM, not specific to llvmpy. +.. toctree:: + :hidden: + + + + Intermediate Representation =========================== @@ -36,7 +40,6 @@ instructions related to variable argument handling, exception handling, and garbage collection. These allow high-level languages to be represented cleanly in the IR. --------------- SSA Form and PHI Nodes ====================== @@ -51,15 +54,24 @@ when a variable can be assigned a different value based on the path of control flow. For example, the value of *b* at the end of execution of the snippet below: -{% highlight c %} a = 1; if (v < 10) a = 2; b = a; {% endhighlight %} +.. code-block:: c + + a = 1; + if (v < 10) + a = 2; + b = a; cannot be determined statically. The value of '2' cannot be assigned to the 'original' *a*, since *a* can be assigned to only once. There are two *a* 's in there, and the last assignment has to choose between which version to pick. This is accomplished by adding a PHI node: -{% highlight c %} a1 = 1; if (v < 10) a2 = 2; b = PHI(a1, a2); {% -endhighlight %} +.. code-block:: c + + a1 = 1; + if (v < 10) + a2 = 2; + b = PHI(a1, a2); The PHI node selects *a1* or *a2*, depending on where the control reached the PHI node. The argument *a1* of the PHI node is associated @@ -68,7 +80,6 @@ with the block *"a1 = 1;"* and *a2* with the block *"a2 = 2;"*. PHI nodes have to be explicitly created in the LLVM IR. Accordingly the LLVM instruction set has an instruction called *phi*. --------------- LLVM Assembly Language ====================== @@ -90,30 +101,48 @@ language code. Just to get a feel of the LLVM assembly language, here's a function in C, and the corresponding LLVM assembly (as generated by the demo page): -{% highlight c %} /\* compute sum of 1..n \*/ unsigned sum(unsigned n) { -if (n == 0) return 0; else return n + sum(n-1); } {% endhighlight %} +.. code-block:: c + + /* compute sum of 1..n */ + unsigned sum(unsigned n) { + if (n == 0) + return 0; + else + return n + sum(n-1); + } The corresponding LLVM assembly: -{% highlight llvm %} ; ModuleID = '/tmp/webcompile/\_7149\_0.bc' target -datalayout = -"e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64" -target triple = "x86\_64-linux-gnu" +.. code-block:: llvm -define i32 @sum(i32 %n) nounwind readnone { entry: %0 = icmp eq i32 %n, -0 ; [#uses=1] br i1 %0, label %bb2, label %bb1 + ; ModuleID = '/tmp/webcompile/_7149_0.bc' + target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64" + target triple = "x86_64-linux-gnu" -bb1: ; preds = %entry %1 = add i32 %n, -1 ; [#uses=2] %2 = icmp eq i32 -%1, 0 ; [#uses=1] br i1 %2, label %sum.exit, label %bb1.i + define i32 @sum(i32 %n) nounwind readnone { + entry: + %0 = icmp eq i32 %n, 0 ; [#uses=1] + br i1 %0, label %bb2, label %bb1 -bb1.i: ; preds = %bb1 %3 = add i32 %n, -2 ; [#uses=1] %4 = tail call i32 -@sum(i32 %3) nounwind ; [#uses=1] %5 = add i32 %4, %1 ; [#uses=1] br -label %sum.exit + bb1: ; preds = %entry + %1 = add i32 %n, -1 ; [#uses=2] + %2 = icmp eq i32 %1, 0 ; [#uses=1] + br i1 %2, label %sum.exit, label %bb1.i -sum.exit: ; preds = %bb1.i, %bb1 %6 = phi i32 [ %5, %bb1.i ], [ 0, %bb1 -] ; [#uses=1] %7 = add i32 %6, %n ; [#uses=1] ret i32 %7 + bb1.i: ; preds = %bb1 + %3 = add i32 %n, -2 ; [#uses=1] + %4 = tail call i32 @sum(i32 %3) nounwind ; [#uses=1] + %5 = add i32 %4, %1 ; [#uses=1] + br label %sum.exit -bb2: ; preds = %entry ret i32 0 } {% endhighlight %} + sum.exit: ; preds = %bb1.i, %bb1 + %6 = phi i32 [ %5, %bb1.i ], [ 0, %bb1 ] ; [#uses=1] + %7 = add i32 %6, %n ; [#uses=1] + ret i32 %7 + + bb2: ; preds = %entry + ret i32 0 + } Note the usage of SSA form. The long string called ``target datalayout`` is a specification of the platform ABI (like endianness, sizes of types, @@ -122,7 +151,6 @@ alignment etc.). The `LLVM Language Reference `_ defines the LLVM assembly language including the entire instruction set. --------------- Modules ======= @@ -139,7 +167,6 @@ contained within modules. Modules may be combined (linked) together to give a bigger resultant module. During this process LLVM attempts to reconcile the references between the combined modules. --------------- Optimization and Passes ======================= @@ -184,7 +211,6 @@ LLVM defines two kinds of pass managers: `PassManager `_ manages module passes for optimizing the entire module. --------------- Bitcode ======= @@ -195,7 +221,6 @@ compiler `_. See `LLVM documentation `_ for detail about the bitcode format. --------------- Execution Engine, JIT and Interpreter ===================================== @@ -209,6 +234,3 @@ multiple modules. Inter-module reference is not possible. That is module ``A`` cannot call a function in module ``B``, directly. --------------- - -**Next** -- `llvmpy Package <./llvm-py_package.html>`_ diff --git a/docs/source/doc/llvmpy_package.rst b/docs/source/doc/llvmpy_package.rst index 1a9ad6f..fc690fc 100644 --- a/docs/source/doc/llvmpy_package.rst +++ b/docs/source/doc/llvmpy_package.rst @@ -1,8 +1,6 @@ -+------------------------------+ -| layout: page | -+------------------------------+ -| title: The llvmpy Package | -+------------------------------+ +*********************** +The llvmpy Package +*********************** The llvmpy is a Python package, consisting of 6 modules, that wrap over enough LLVM APIs to allow the implementation of your own compiler/VM diff --git a/docs/source/doc/userguide.rst b/docs/source/doc/userguide.rst index 8b5c267..1bb4b4f 100644 --- a/docs/source/doc/userguide.rst +++ b/docs/source/doc/userguide.rst @@ -6,158 +6,12 @@ llvmpy provides Python bindings for LLVM. This document explains how you can setup and use it. A working knowledge of Python and a basic idea of LLVM is assumed. -Introduction -============ +.. toctree:: + :maxdepth: 1 -`LLVM `_ (Low-Level Virtual Machine) provides -enough infrastructure to use it as the backend for your compiled, or -JIT-compiled language. It provides extensive optimization support, and -static and dynamic (JIT) backends for many platforms. See the website at -http://www.llvm.org/ to discover more. + getting_started.rst + llvm_concepts.rst + llvmpy_package.rst + -Python bindings for LLVM provides a gentler learning curve for working -with the LLVM APIs. It should also be easier to create working -prototypes and experimental languages using this medium. -Together with `clang `_ or -`llvm-gcc `_ it also a provides a -means to quickly instrument C and C++ sources. For e.g., llvm-gcc can be -used to generate the LLVM assembly for a given C source file, which can -then be loaded and manipulated (adding profiling code to every function, -say) using a llvmpy based Python script. - -License -------- - -Both LLVM and llvmpy are distributed under (different) permissive open -source licenses. llvmpy uses the `new BSD -license `_. More -information is available -`here `_. - -Platforms ---------- - -llvmpy has been built/tested/reported to work on various GNU/Linux -flavours, BSD, Mac OS X; on i386 and amd64 architectures. Windows is not -supported, for a variety of reasons. - -Versions --------- - -llvmpy 0.8.2 requires version 3.1 of LLVM. It may not work with -previous versions. - -llvmpy has been built and tested with Python 2.7. It should work with -earlier versions. It has not been tried with Python 3.x (patches -welcome). - --------------- - -Installation -============ - -The Git repo of llvmpy is at https://github.com/numba/llvmpy.git. -You'll need to build and install it before it can be used. At least the -following will be required for this: - -- C and C++ compilers (gcc/g++) -- Python itself -- Python development files (headers and libraries) -- LLVM, either installed or built - -On debian-based systems, the first three can be installed with the -command ``sudo apt-get install gcc g++ python python-dev``. Ensure that -your distro's repository has the appropriate version of LLVM! - -It does not matter which compiler LLVM itself was built with (``g++``, -``llvm-g++`` or any other); llvmpy can be built with any compiler. It -has been tried only with gcc/g++ though. - -LLVM and ``--enable-pic`` -------------------------- - -The result of an LLVM build is a set of static libraries and object -files. The llvmpy contains an extension package that is built into a -shared object (\_core.so) which links to these static libraries and -object files. It is therefore required that the LLVM libraries and -object files be built with the ``-fPIC`` option (generate position -independent code). Be sure to use the ``--enable-pic`` option while -configuring LLVM (default is no PIC), like this: - -{% highlight bash %} ~/llvm$ ./configure --enable-pic --enable-optimized -{% endhighlight %} - -llvm-config ------------ - -In order to build llvmpy, it's build script needs to know from where it -can invoke the llvm helper program, ``llvm-config``. If you've installed -LLVM, then this will be available in your ``PATH``, and nothing further -needs to be done. If you've built LLVM yourself, or for any reason -``llvm-config`` is not in your ``PATH``, you'll need to pass the full -path of ``llvm-config`` to the build script. - -You'll need to be 'root' to install llvmpy. Remember that your ``PATH`` -is different from that of 'root', so even if ``llvm-config`` is in your -``PATH``, it may not be available when you do ``sudo``. - -Steps ------ - -Get 3.1 version of LLVM, build it. Make sure '--enable-pic' is passed to -LLVM's 'configure'. - -Get llvmpy and install it: - -{% highlight bash %} $ git clone git@github.com:numba/llvmpy.git $ cd -llvmpy $ python setup.py install {% endhighlight %} - -If you need to tell the build script where ``llvm-config`` is, do it -this way: - -{% highlight bash %} $ python setup.py install --user ---llvm-config=/home/mdevan/llvm/Release/bin/llvm-config {% endhighlight -%} - -To build a debug version of llvmpy, that links against the debug -libraries of LLVM, use this: - -{% highlight bash %} $ python setup.py build -g ---llvm-config=/home/mdevan/llvm/Debug/bin/llvm-config $ python setup.py -install --user --llvm-config=/home/mdevan/llvm/Debug/bin/llvm-config {% -endhighlight %} - -Be warned that debug binaries will be huge (100MB+) ! They are required -only if you need to debug into LLVM also. - -``setup.py`` is a standard Python distutils script. See the Python -documentation regarding `Installing Python -Modules `_ and `Distributing -Python Modules `_ for more -information on such scripts. - --------------- - -Uninstall # {#uninstall} -======================== - -If you'd installed llvmpy with the ``--user`` option, then llvmpy -would be present under ``~/.local/lib/python2.7/site-packages``. -Otherwise, it might be under ``/usr/lib/python2.7/site-packages`` or -``/usr/local/lib/python2.7/site-packages``. The directory would vary -with your Python version and OS flavour. Look around. - -Once you've located the site-packages directory, the modules and the -"egg" can be removed like so: - -{% highlight bash %} $ rm -rf /llvm /llvm\_py-.egg-info {% endhighlight -%} - -See the `Python -documentation `_ for more -information. - --------------- - -**Next** -- :doc:`llvm_concepts` diff --git a/docs/source/index.rst b/docs/source/index.rst index 76670e6..fbca2ec 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -10,6 +10,7 @@ Contents: .. toctree:: :titlesonly: + :maxdepth: 2 doc/userguide.rst doc/examples.rst From bed4f24cbd5aded73297949bad6ca59e85dd59c0 Mon Sep 17 00:00:00 2001 From: Siu Kwan Lam Date: Thu, 9 Aug 2012 15:41:55 -0700 Subject: [PATCH 062/675] Added Module.to_native_object() and Module.to_native_assembly(). Added test for these new functions. --- llvm/_core.cpp | 28 +++++++++++++++++++ llvm/core.py | 19 +++++++++++++ llvm/extra.cpp | 73 +++++++++++++++++++++++++++++++++++++++++++++++--- llvm/extra.h | 5 ++++ test/native.py | 53 ++++++++++++++++++++++++++++++++++++ 5 files changed, 175 insertions(+), 3 deletions(-) create mode 100755 test/native.py diff --git a/llvm/_core.cpp b/llvm/_core.cpp index 14143f2..3366d58 100644 --- a/llvm/_core.cpp +++ b/llvm/_core.cpp @@ -184,6 +184,30 @@ _wLLVMGetBitcodeFromModule(PyObject *self, PyObject *args) return ret; } +static PyObject * +_wLLVMGetNativeCodeFromModule(PyObject * self, PyObject * args) +{ + PyObject * ret; + unsigned len; + unsigned char * bytes; + LLVMModuleRef m; + + PyObject * arg_m; + int arg_use_asm; + + if (!PyArg_ParseTuple(args, "Oi", &arg_m, &arg_use_asm)) + return NULL; + + m = (LLVMModuleRef) PyCapsule_GetPointer(arg_m, NULL); + + if ( !(bytes = LLVMGetNativeCodeFromModule(m, arg_use_asm, &len)) ) + Py_RETURN_NONE; + + ret = PyBytes_FromStringAndSize((char *)bytes, (Py_ssize_t)len); + delete [] bytes; + return ret; +} + static PyObject * _wLLVMLinkModules(PyObject *self, PyObject *args) { @@ -873,6 +897,8 @@ _wLLVMInitializePasses(PyObject * self, PyObject * args) Py_RETURN_NONE; } +_wrap_none2obj(LLVMInitializeNativeTarget, int) + /*===----------------------------------------------------------------------===*/ /* Passes */ @@ -1335,6 +1361,7 @@ static PyMethodDef core_methods[] = { _method( LLVMGetModuleFromAssembly ) _method( LLVMGetModuleFromBitcode ) _method( LLVMGetBitcodeFromModule ) + _method( LLVMGetNativeCodeFromModule ) _method( LLVMModuleGetPointerSize ) _method( LLVMModuleGetOrInsertFunction ) _method( LLVMLinkModules ) @@ -1717,6 +1744,7 @@ static PyMethodDef core_methods[] = { _method( LLVMDumpPasses ) _method( LLVMAddPassByName ) _method( LLVMInitializePasses ) + _method( LLVMInitializeNativeTarget ) /* Passes */ diff --git a/llvm/core.py b/llvm/core.py index 47b3b8a..7366d41 100644 --- a/llvm/core.py +++ b/llvm/core.py @@ -516,6 +516,16 @@ class Module(llvm.Ownable, llvm.Cacheable): id = property(_get_id, _set_id) + def to_native_object(self): + '''returns byte string of the module as native object code + ''' + return _core.LLVMGetNativeCodeFromModule(self.ptr, 0) + + def to_native_assembly(self): + '''returns byte string of the module as native assembly code + ''' + return _core.LLVMGetNativeCodeFromModule(self.ptr, 1) + #===----------------------------------------------------------------------=== # Types #===----------------------------------------------------------------------=== @@ -2126,3 +2136,12 @@ def inline_function(call): check_is_value(call) return _core.LLVMInlineFunction(call.ptr) + + +#===----------------------------------------------------------------------=== +# Initialization +#===----------------------------------------------------------------------=== +if _core.LLVMInitializeNativeTarget(): + raise llvm.LLVMException("No native target!?") + + diff --git a/llvm/extra.cpp b/llvm/extra.cpp index 122d387..5d22200 100644 --- a/llvm/extra.cpp +++ b/llvm/extra.cpp @@ -52,6 +52,10 @@ //#include "llvm/TypeSymbolTable.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/CallSite.h" +#include "llvm/Support/FormattedStream.h" +#include "llvm/Target/TargetData.h" +#include "llvm/Support/TargetSelect.h" + #include "llvm/IntrinsicInst.h" #include "llvm/Analysis/Verifier.h" #include "llvm/Assembly/Parser.h" @@ -69,8 +73,6 @@ #include "llvm/Linker.h" #include "llvm/Support/SourceMgr.h" - - // LLVM-C includes #include "llvm-c/Core.h" #include "llvm-c/ExecutionEngine.h" @@ -110,6 +112,72 @@ char *do_print(W obj) p->print(buf); return strdup(buf.str().c_str()); } + +unsigned char* LLVMGetNativeCodeFromModule(LLVMModuleRef module, int assembly, + unsigned * lenp) +{ + using namespace llvm; + assert(lenp); + + InitializeNativeTargetAsmPrinter(); + + Module *modulep = unwrap(module); + assert(modulep); + + // get objectcode into a string + std::string s; + raw_string_ostream buf(s); + + formatted_raw_ostream fso(buf); + + TargetMachine * tm = EngineBuilder(modulep).selectTarget(); + + PassManager pm; + + if (!tm->getTargetData()){ + printf("No target data in target machine"); + return NULL; + } + + //printf("%s\n", modulep->getDataLayout().c_str()); + + pm.add(new TargetData(*tm->getTargetData())); + + bool failed; + if( assembly ) { + failed = tm->addPassesToEmitFile(pm, fso, TargetMachine::CGFT_AssemblyFile); + } else { + failed = tm->addPassesToEmitFile(pm, fso, TargetMachine::CGFT_ObjectFile); + } + + if ( failed ) { + printf("No support\n"); + printf("%s\n", tm->getTargetData()->getStringRepresentation().c_str()); + return NULL; + } + + pm.run(*modulep); + + // flush all streams + fso.flush(); + buf.flush(); + + const std::string& bc = buf.str(); + + // and then into a new buffer + size_t bclen = bc.size(); + unsigned char *bytes = new unsigned char[bclen]; + if (!bytes){ + return NULL; + } + memcpy(bytes, bc.data(), bclen); + + /* return */ + *lenp = bclen; + return bytes; +} + + static llvm::AtomicOrdering atomic_ordering_from_string(const char * ordering) { @@ -353,7 +421,6 @@ void LLVMInitializePasses(){ initializeTarget(registry); } - const char * LLVMDumpPasses() { using namespace llvm; diff --git a/llvm/extra.h b/llvm/extra.h index b13c80f..f405679 100644 --- a/llvm/extra.h +++ b/llvm/extra.h @@ -45,6 +45,11 @@ extern "C" { #endif +/* + * Wraps TargetMachine::addPassesToEmitFile + */ +unsigned char* LLVMGetNativeCodeFromModule(LLVMModuleRef module, int assembly, + unsigned * lenp); /* * Wraps IRBuilder::CreateFence diff --git a/test/native.py b/test/native.py new file mode 100755 index 0000000..f4287c9 --- /dev/null +++ b/test/native.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python + +from llvm import * +from llvm.core import * + +import unittest, subprocess + +class TestNative(unittest.TestCase): + + def _make_module(self): + m = Module.new('module1') + m.add_global_variable(Type.int(), 'i') + + fty = Type.function(Type.int(), []) + f = m.add_function(fty, name='main') + + bldr = Builder.new(f.append_basic_block('entry')) + bldr.ret(Constant.int(Type.int(), 0xab)) + + return m + + def _compile(self, src): + dst = '/tmp/llvmobj.out' + s = subprocess.call(['cc', '-o', dst, src]) + if s != 0: + raise Exception("Cannot compile") + + s = subprocess.call([dst]) + self.assertEqual(s, 0xab) + + + def test_assembly(self): + m = self._make_module() + output = m.to_native_assembly() + + src = '/tmp/llvmasm.s' + with open(src, 'wb') as fout: + fout.write(output) + + self._compile(src) + + def test_object(self): + m = self._make_module() + output = m.to_native_object() + + src = '/tmp/llvmobj.o' + with open(src, 'wb') as fout: + fout.write(output) + + self._compile(src) + +if __name__ == '__main__': + unittest.main() From ce8884aa337c6071a0b421af097af923e98bf74c Mon Sep 17 00:00:00 2001 From: "Travis E. Oliphant" Date: Fri, 10 Aug 2012 08:52:51 -0500 Subject: [PATCH 063/675] Fix up code-highlighting sections. --- docs/source/doc/functions.rst | 149 +- docs/source/doc/getting_started.rst | 54 +- .../doc/kaleidoscope/PythonLangImpl1.rst | 177 +- .../doc/kaleidoscope/PythonLangImpl2.rst | 1037 ++++---- .../doc/kaleidoscope/PythonLangImpl3.rst | 1192 +++++---- .../doc/kaleidoscope/PythonLangImpl4.rst | 1096 ++++---- .../doc/kaleidoscope/PythonLangImpl5.rst | 1857 +++++++------ .../doc/kaleidoscope/PythonLangImpl6.rst | 2187 +++++++-------- .../doc/kaleidoscope/PythonLangImpl7.rst | 2364 +++++++++-------- .../doc/kaleidoscope/PythonLangImpl8.rst | 277 -- docs/source/doc/llvm.core.Constant.rst | 675 +++-- docs/source/doc/llvm.core.FunctionType.rst | 14 +- docs/source/doc/llvm.core.GlobalVariable.rst | 112 +- docs/source/doc/llvm.core.Module.rst | 228 +- docs/source/doc/llvm.core.StructType.rst | 84 - docs/source/doc/llvm.core.Type.rst | 45 +- docs/source/doc/llvmpy_package.rst | 13 +- docs/source/doc/types.rst | 87 +- 18 files changed, 5611 insertions(+), 6037 deletions(-) diff --git a/docs/source/doc/functions.rst b/docs/source/doc/functions.rst index e56afe6..8922dd0 100644 --- a/docs/source/doc/functions.rst +++ b/docs/source/doc/functions.rst @@ -13,34 +13,29 @@ References to functions already present in a module can be retrieved via ``Function.get``. All functions in a module can be enumerated by iterating over ``module_obj.functions``. -{% highlight python %} # create a type, representing functions that take -an integer and return # a floating point value. ft = Type.function( -Type.float(), [ Type.int() ] ) -create a function of this type -============================== +.. code-block:: python -f1 = module\_obj.add\_function(ft, "func1") + # create a type, representing functions that take + an integer and return # a floating point value. ft = Type.function( + Type.float(), [ Type.int() ] ) + + # create a function of this type + f1 = module_obj.add_function(ft, "func1") + + # or equivalently, like this: + f2 = Function.new(module_obj, ft, "func2") + + # get a reference to an existing function + f3 = module_obj.get_function_named("func3") + + # or like this: + f4 = Function.get(module_obj, "func4") + + # list all function names in a module + for f in module_obj.functions: print f.name -or equivalently, like this: -=========================== -f2 = Function.new(module\_obj, ft, "func2") - -get a reference to an existing function -======================================= - -f3 = module\_obj.get\_function\_named("func3") - -or like this: -============= - -f4 = Function.get(module\_obj, "func4") - -list all function names in a module -=================================== - -for f in module\_obj.functions: print f.name {% endhighlight %} Intrinsic ========= @@ -52,13 +47,16 @@ called with a module object, an intrinsic ID (which is a numeric constant) and a list of the types of arguments (which LLVM uses to resolve overloaded intrinsic functions). -{% highlight python %} # get a reference to the llvm.bswap intrinsic -bswap = Function.intrinsic(mod, INTR\_BSWAP, [Type.int()]) -call it -======= +.. code-block:: python + + # get a reference to the llvm.bswap intrinsic + bswap = Function.intrinsic(mod, INTR_BSWAP, [Type.int()]) + + # call it + builder.call(bswap, [value]) + -builder.call(bswap, [value]) {% endhighlight %} Here, the constant ``INTR_BSWAP``, available from ``llvm.core``, represents the LLVM intrinsic @@ -111,13 +109,16 @@ The value objects corresponding to the arguments of a function can be got using the read-only property ``args``. These can be iterated over, and also be indexed via integers. An example: -{% highlight python %} # list all argument names and types for arg in -fn.args: print arg.name, "of type", arg.type -change the name of the first argument -===================================== +.. code-block:: python + + # list all argument names and types for arg in + fn.args: print arg.name, "of type", arg.type + + # change the name of the first argument + fn.args[0].name = "objptr" + -fn.args[0].name = "objptr" {% endhighlight %} Basic blocks (see later) are contained within functions. When newly created, a function has no basic blocks. They have to be added @@ -130,71 +131,19 @@ blocks can be got via ``basic_block_count`` method. Note that ``get_entry_basic_block`` is slightly faster than ``basic_blocks[0]`` and so is ``basic_block_count``, over ``len(f.basic_blocks)``. -{% highlight python %} # add a basic block b1 = -fn.append\_basic\_block("entry") -get the first one -================= +.. code-block:: python -b2 = fn.get\_entry\_basic\_block() b2 = fn.basic\_mdblocks[0] # slower -than previous method - -print names of all basic blocks -=============================== - -for b in fn.basic\_blocks: print b.name - -get number of basic blocks -========================== - -n = fn.basic\_block\_count n = len(fn.basic\_blocks) # slower than -previous method {% endhighlight %} - -Functions can be deleted using the method ``delete``. This deletes them -from their containing module. All references to the function object -should be dropped after ``delete`` has been called. - -Functions can be verified with the ``verify`` method. Note that this may -not work properly (aborts on errors). - -Function Attributes # {#fnattr} -=============================== - -Function attributes, as documented -`here `_, can be set on -functions using the methods ``add_attribute`` and ``remove_attribute``. -The following values may be used to refer to the LLVM attributes: - -Value \| Equivalent LLVM Assembly Keyword \| -------\|----------------------------------\| -``ATTR_ALWAYS_INLINE``\ \|\ ``alwaysinline`` \| -``ATTR_INLINE_HINT``\ \|\ ``inlinehint`` \| -``ATTR_NO_INLINE``\ \|\ ``noinline`` \| -``ATTR_OPTIMIZE_FOR_SIZE``\ \|\ ``optsize`` \| -``ATTR_NO_RETURN``\ \|\ ``noreturn`` \| -``ATTR_NO_UNWIND``\ \|\ ``nounwind`` \| -``ATTR_READ_NONE``\ \|\ ``readnone`` \| -``ATTR_READONLY``\ \|\ ``readonly`` \| -``ATTR_STACK_PROTECT``\ \|\ ``ssp`` \| -``ATTR_STACK_PROTECT_REQ``\ \|\ ``sspreq`` \| -``ATTR_NO_REDZONE``\ \|\ ``noredzone`` \| -``ATTR_NO_IMPLICIT_FLOAT``\ \|\ ``noimplicitfloat`` \| -``ATTR_NAKED``\ \|\ ``naked`` \| - -Here is how attributes can be set and removed: - -{% highlight python %} # create a function ti = Type.int(32) tf = -Type.function(ti, [ti, ti]) m = Module.new('mod') f = -m.add\_function(tf, 'sum') print f # declare i32 @sum(i32, i32) - -add a couple of attributes -========================== - -f.add\_attribute(ATTR\_NO\_UNWIND) f.add\_attribute(ATTR\_READONLY) -print f # declare i32 @sum(i32, i32) nounwind readonly {% endhighlight -%} - -**Related Links** - -`llvm.core.Function `_, -`llvm.core.Argument `_ + # add a basic block b1 = + fn.append_basic_block("entry") + + # get the first one + b2 = fn.get_entry_basic_block() b2 = fn.basic_mdblocks[0] # slower + than previous method + + # print names of all basic blocks + for b in fn.basic_blocks: print b.name + + # get number of basic blocks + n = fn.basic_block_count n = len(fn.basic_blocks) # slower than + previous method diff --git a/docs/source/doc/getting_started.rst b/docs/source/doc/getting_started.rst index 4d35074..d703785 100644 --- a/docs/source/doc/getting_started.rst +++ b/docs/source/doc/getting_started.rst @@ -78,8 +78,9 @@ object files be built with the ``-fPIC`` option (generate position independent code). Be sure to use the ``--enable-pic`` option while configuring LLVM (default is no PIC), like this: -{% highlight bash %} ~/llvm$ ./configure --enable-pic --enable-optimized -{% endhighlight %} +.. code-block:: bash + + $ ~/llvm ./configure --enable-pic --enable-optimized llvm-config ----------- @@ -103,51 +104,8 @@ LLVM's 'configure'. Get llvmpy and install it: -{% highlight bash %} $ git clone git@github.com:numba/llvmpy.git $ cd -llvmpy $ python setup.py install {% endhighlight %} -If you need to tell the build script where ``llvm-config`` is, do it -this way: +.. code-block:: bash -{% highlight bash %} $ python setup.py install --user ---llvm-config=/home/mdevan/llvm/Release/bin/llvm-config {% endhighlight -%} - -To build a debug version of llvmpy, that links against the debug -libraries of LLVM, use this: - -{% highlight bash %} $ python setup.py build -g ---llvm-config=/home/mdevan/llvm/Debug/bin/llvm-config $ python setup.py -install --user --llvm-config=/home/mdevan/llvm/Debug/bin/llvm-config {% -endhighlight %} - -Be warned that debug binaries will be huge (100MB+) ! They are required -only if you need to debug into LLVM also. - -``setup.py`` is a standard Python distutils script. See the Python -documentation regarding `Installing Python -Modules `_ and `Distributing -Python Modules `_ for more -information on such scripts. - - -Uninstall -============== - -If you'd installed llvmpy with the ``--user`` option, then llvmpy -would be present under ``~/.local/lib/python2.7/site-packages``. -Otherwise, it might be under ``/usr/lib/python2.7/site-packages`` or -``/usr/local/lib/python2.7/site-packages``. The directory would vary -with your Python version and OS flavour. Look around. - -Once you've located the site-packages directory, the modules and the -"egg" can be removed like so: - -{% highlight bash %} $ rm -rf /llvm /llvm\_py-.egg-info {% endhighlight -%} - -See the `Python -documentation `_ for more -information. - --------------- + $ git clone git@github.com:numba/llvmpy.git $ cd + llvmpy $ python setup.py install diff --git a/docs/source/doc/kaleidoscope/PythonLangImpl1.rst b/docs/source/doc/kaleidoscope/PythonLangImpl1.rst index 3314187..9259d42 100644 --- a/docs/source/doc/kaleidoscope/PythonLangImpl1.rst +++ b/docs/source/doc/kaleidoscope/PythonLangImpl1.rst @@ -112,23 +112,36 @@ This gives the language a very nice and simple syntax. For example, the following simple example computes `Fibonacci numbers `_: -{% highlight python %} # Compute the x'th fibonacci number. def fib(x) -if x < 3 then 1 else fib(x-1)+fib(x-2) -This expression will compute the 40th number. -============================================= +.. code-block:: + + # Compute the x'th fibonacci number. + def fib(x): + if x < 3: + return 1 + else: + return fib(x-1)+fib(x-2) + + # This expression will compute the 40th number. + fib(40) + -fib(40) {% endhighlight %} We also allow Kaleidoscope to call into standard library functions (the LLVM JIT makes this completely trivial). This means that you can use the 'extern' keyword to define a function before you use it (this is also useful for mutually recursive functions). For example: -{% highlight python %} extern sin(arg); extern cos(arg); extern -atan2(arg1 arg2); -atan2(sin(0.4), cos(42)) {% endhighlight %} +.. code-block:: + + extern sin(arg); + extern cos(arg); + extern atan2(arg1 arg2); + + atan2(sin(0.4), cos(42)) + + A more interesting example is included in Chapter 6 where we write a little Kaleidoscope application that @@ -150,23 +163,32 @@ traditional way to do this is to use a the lexer includes a token type and potentially some metadata (e.g. the numeric value of a number). First, we define the possibilities: -{% highlight python %} # The lexer yields one of these types for each -token. class EOFToken(object): pass -class DefToken(object): pass +.. code-block:: python -class ExternToken(object): pass + # The lexer yields one of these types for each token. + class EOFToken(object): pass + + class DefToken(object): pass + + class ExternToken(object): pass + + class IdentifierToken(object): + def __init__(self, name): + self.name = name + + class NumberToken(object): + def __init__(self, value): + self.value = value + + class CharacterToken(object): + def __init__(self, char): + self.char = char + def __eq__(self, other): + return isinstance(other, CharacterToken) and self.char == other.char + def __ne__(self, other): + return not self == other -class IdentifierToken(object): def **init**\ (self, name): self.name = -name - -class NumberToken(object): def **init**\ (self, value): self.value = -value - -class CharacterToken(object): def **init**\ (self, char): self.char = -char def **eq**\ (self, other): return isinstance(other, CharacterToken) -and self.char == other.char def **ne**\ (self, other): return not self -== other {% endhighlight %} Each token yielded by our lexer will be of one of the above types. For simple tokens that are always the same, like the "def" keyword, the @@ -193,82 +215,109 @@ digits. Identifiers (and keywords) are alphanumeric string starting with a letter and comments are anything between a hash (``#``) and the end of the line. -{% highlight python %} import re -... +.. code-block:: python -Regular expressions that tokens and comments of our language. -============================================================= - -REGEX\_NUMBER = re.compile('[0-9]+(?:.[0-9]+)?') REGEX\_IDENTIFIER = -re.compile('[a-zA-Z][a-zA-Z0-9]\ *') REGEX\_COMMENT = re.compile('#.*') - -{% endhighlight %} + import re + + ... + + # Regular expressions that tokens and comments of our language. + REGEX_NUMBER = re.compile('[0-9]+(?:.[0-9]+)?') + REGEX_IDENTIFIER = re.compile('[a-zA-Z][a-zA-Z0-9]\ *') + REGEX_COMMENT = re.compile('#.*') + Next, let's start defining the ``Tokenize`` function itself. The first thing we need to do is set up a loop that scans the string, while ignoring whitespace between tokens: -{% highlight python %} def Tokenize(string): while string: # Skip -whitespace. if string[0].isspace(): string = string[1:] continue -:: +.. code-block:: python + + def Tokenize(string): + while string: # Skip whitespace. + if string[0].isspace(): + string = string[1:] + continue + + :: + + ... + + - ... -{% endhighlight %} Next we want to find out what the next token is. For this we run the regexes we defined above on the remainder of the string. To simplify the rest of the code, we run all three regexes each time. As mentioned above, inefficiencies are ignored for the purpose of this tutorial: -{% highlight python %} # Run regexes. comment\_match = -REGEX\_COMMENT.match(string) number\_match = REGEX\_NUMBER.match(string) -identifier\_match = REGEX\_IDENTIFIER.match(string) {% endhighlight %} -Now se check if any of the regexes matched. For comments, we simply +.. code-block:: python + + # Run regexes. + comment_match = REGEX_COMMENT.match(string) + number_match = REGEX_NUMBER.match(string) + identifier_match = REGEX_IDENTIFIER.match(string) + + +Now we check if any of the regexes matched. For comments, we simply ignore the captured match: -{% highlight python %} # Check if any of the regexes matched and yield -the appropriate result. if comment\_match: comment = -comment\_match.group(0) string = string[len(comment):] {% endhighlight -python %} +.. code-block:: python + + # Check if any of the regexes matched and yield + # the appropriate result. + if comment_match: + comment = comment_match.group(0) + string = string[len(comment):] + For numbers, we yield the captured match, converted to a float and tagged with the appropriate token type: - -{% highlight python %} elif number\_match: number = -number\_match.group(0) yield NumberToken(float(number)) string = -string[len(number):] {% endhighlight %} + +.. code-block:: python + + elif number_match: + number = number_match.group(0) + yield NumberToken(float(number)) + string = string[len(number):] The identifier case is a little more complex. We have to check for keywords to decide whether we have captured an identifier or a keyword: -{% highlight python %} elif identifier\_match: identifier = -identifier\_match.group(0) # Check if we matched a keyword. if -identifier == 'def': yield DefToken() elif identifier == 'extern': yield -ExternToken() else: yield IdentifierToken(identifier) string = -string[len(identifier):] {% endhighlight %} +.. code-block:: python + + elif identifier_match: + identifier = identifier_match.group(0) + # Check if we matched a keyword. + if identifier == 'def': + yield DefToken() + elif identifier == 'extern': + yield ExternToken() + else: + yield IdentifierToken(identifier) + string = string[len(identifier):] + Finally, if we haven't recognized a comment, a number of an identifier, we yield the current character as an "unknown character" token. This is used, for example, for operators like ``+`` or ``*``: -{% highlight python %} else: # Yield the unknown character. yield -CharacterToken(string[0]) string = string[1:] {% endhighlight %} + +.. code-block:: python + + else: # Yield the unknown character. + yield CharacterToken(string[0]) + string = string[1:] + Once we're done with the loop, we return a final end-of-file token: -{% highlight python %} yield EOFToken() {% endhighlight %} -With this, we have the complete lexer for the basic Kaleidoscope -language (the `full code listing `_ for the -Lexer is available in the `next chapter `_ of the -tutorial). Next we'll `build a simple parser that uses this to build an -Abstract Syntax Tree `_. When we have that, we'll -include a driver so that you can use the lexer and parser together. +.. code-block:: python --------------- + yield EOFToken() -**`Next: Implementing a Parser and AST `_** diff --git a/docs/source/doc/kaleidoscope/PythonLangImpl2.rst b/docs/source/doc/kaleidoscope/PythonLangImpl2.rst index f918633..3a05ff8 100644 --- a/docs/source/doc/kaleidoscope/PythonLangImpl2.rst +++ b/docs/source/doc/kaleidoscope/PythonLangImpl2.rst @@ -36,16 +36,19 @@ language, and the AST should closely model the language. In Kaleidoscope, we have expressions, a prototype, and a function object. We'll start with expressions first: -{% highlight python %} # Base class for all expression nodes. class -ExpressionNode(object): pass -Expression class for numeric literals like "1.0". -================================================= +.. code-block:: python + + # Base class for all expression nodes. class + ExpressionNode(object): pass + + # Expression class for numeric literals like "1.0". + class NumberExpressionNode(ExpressionNode): def **init**\ (self, value): + self.value = value + + -class NumberExpressionNode(ExpressionNode): def **init**\ (self, value): -self.value = value -{% endhighlight %} The code above shows the definition of the base ExpressionNode class and one subclass which we use for numeric literals. The important thing to @@ -58,22 +61,23 @@ them. It would be very easy to add a virtual method to pretty print the code, for example. Here are the other expression AST node definitions that we'll use in the basic form of the Kaleidoscope language: -{% highlight python %} # Expression class for referencing a variable, -like "a". class VariableExpressionNode(ExpressionNode): def -**init**\ (self, name): self.name = name -Expression class for a binary operator. -======================================= +.. code-block:: python -class BinaryOperatorExpressionNode(ExpressionNode): def **init**\ (self, -operator, left, right): self.operator = operator self.left = left -self.right = right + # Expression class for referencing a variable, + like "a". class VariableExpressionNode(ExpressionNode): def + **init**\ (self, name): self.name = name + + # Expression class for a binary operator. + class BinaryOperatorExpressionNode(ExpressionNode): def **init**\ (self, + operator, left, right): self.operator = operator self.left = left + self.right = right + + # Expression class for function calls. + class CallExpressionNode(ExpressionNode): def **init**\ (self, callee, + args): self.callee = callee self.args = args -Expression class for function calls. -==================================== -class CallExpressionNode(ExpressionNode): def **init**\ (self, callee, -args): self.callee = callee self.args = args {% endhighlight %} This is all (intentionally) rather straight-forward: variables capture the variable name, binary operators capture their opcode (e.g. '+'), and @@ -89,17 +93,20 @@ Turing-complete; we'll fix that in a later installment. The two things we need next are a way to talk about the interface to a function, and a way to talk about functions themselves: -{% highlight python %} # This class represents the "prototype" for a -function, which captures its name, # and its argument names (thus -implicitly the number of arguments the function # takes). class -PrototypeNode(object): def **init**\ (self, name, args): self.name = -name self.args = args -This class represents a function definition itself. -=================================================== +.. code-block:: python + + # This class represents the "prototype" for a + function, which captures its name, # and its argument names (thus + implicitly the number of arguments the function # takes). class + PrototypeNode(object): def **init**\ (self, name, args): self.name = + name self.args = args + + # This class represents a function definition itself. + class FunctionNode(object): def **init**\ (self, prototype, body): + self.prototype = prototype self.body = body + -class FunctionNode(object): def **init**\ (self, prototype, body): -self.prototype = prototype self.body = body {% endhighlight %} In Kaleidoscope, functions are typed with just a count of their arguments. Since all values are double precision floating point, the @@ -120,22 +127,32 @@ build it. The idea here is that we want to parse something like ``x + y`` (which is returned as three tokens by the lexer) into an AST that could be generated with calls like this: -{% highlight python %} x = VariableExpressionNode('x') y = -VariableExpressionNode('y') result = BinaryOperatorExpressionNode('+', -x, y) {% endhighlight %} + +.. code-block:: python + + x = VariableExpressionNode('x') y = + VariableExpressionNode('y') result = BinaryOperatorExpressionNode('+', + x, y) + + In order to do this, we'll start by defining a lightweight ``Parser`` class with some basic helper routines: -{% highlight python %} class Parser(object): -def **init**\ (self, tokens, binop\_precedence): self.tokens = tokens -self.binop\_precedence = binop\_precedence self.Next() +.. code-block:: python + + class Parser(object): + + def **init**\ (self, tokens, binop_precedence): self.tokens = tokens + self.binop_precedence = binop_precedence self.Next() + + # Provide a simple token buffer. Parser.current is the current token the + # parser is looking at. Parser.Next() reads another token from the lexer + and # updates Parser.current with its results. def Next(self): + self.current = self.tokens.next() + -# Provide a simple token buffer. Parser.current is the current token the -# parser is looking at. Parser.Next() reads another token from the lexer -and # updates Parser.current with its results. def Next(self): -self.current = self.tokens.next() {% endhighlight %} This implements a simple token buffer around the lexer. This allows us to look one token ahead at what the lexer is returning. Every function @@ -157,9 +174,14 @@ We start with numeric literals, because they are the simplest to process. For each production in our grammar, we'll define a function which parses that production. For numeric literals, we have: -{% highlight python %} # numberexpr ::= number def -ParseNumberExpr(self): result = NumberExpressionNode(self.current.value) -self.Next() # consume the number. return result {% endhighlight %} + +.. code-block:: python + + # numberexpr ::= number def + ParseNumberExpr(self): result = NumberExpressionNode(self.current.value) + self.Next() # consume the number. return result + + This method is very simple: it expects to be called when the current token is a ``NumberToken``. It takes the current number value, creates a @@ -173,20 +195,25 @@ not part of the grammar production) ready to go. This is a fairly standard way to go for recursive descent parsers. For a better example, the parenthesis operator is defined like this: -{% highlight python %} # parenexpr ::= '(' expression ')' def -ParseParenExpr(self): self.Next() # eat '('. -:: +.. code-block:: python - contents = self.ParseExpression() + # parenexpr ::= '(' expression ')' def + ParseParenExpr(self): self.Next() # eat '('. + + :: + + contents = self.ParseExpression() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")".') + self.Next() # eat ')'. + + return contents + + - if self.current != CharacterToken(')'): - raise RuntimeError('Expected ")".') - self.Next() # eat ')'. - return contents - -{% endhighlight %} This function illustrates an interesting aspect of the parser. The function uses recursion by calling ``ParseExpression`` (we will soon see @@ -201,31 +228,36 @@ needed. The next simple production is for handling variable references and function calls: -{% highlight python %} # identifierexpr ::= identifier \| identifier '(' -expression\* ')' def ParseIdentifierExpr(self): identifier\_name = -self.current.name self.Next() # eat identifier. -:: +.. code-block:: python - if self.current != CharacterToken('('): # Simple variable reference. - return VariableExpressionNode(identifier_name); + # identifierexpr ::= identifier \| identifier '(' + expression\* ')' def ParseIdentifierExpr(self): identifier_name = + self.current.name self.Next() # eat identifier. + + :: + + if self.current != CharacterToken('('): # Simple variable reference. + return VariableExpressionNode(identifier_name); + + # Call. + self.Next() # eat '('. + args = [] + if self.current != CharacterToken(')'): + while True: + args.append(self.ParseExpression()) + if self.current == CharacterToken(')'): + break + elif self.current != CharacterToken(','): + raise RuntimeError('Expected ")" or "," in argument list.') + self.Next() + + self.Next() # eat ')'. + return CallExpressionNode(identifier_name, args) + + - # Call. - self.Next() # eat '('. - args = [] - if self.current != CharacterToken(')'): - while True: - args.append(self.ParseExpression()) - if self.current == CharacterToken(')'): - break - elif self.current != CharacterToken(','): - raise RuntimeError('Expected ")" or "," in argument list.') - self.Next() - self.Next() # eat ')'. - return CallExpressionNode(identifier_name, args) - -{% endhighlight %} This routine follows the same style as the other routines. It expects to be called if the current token is an ``IdentifierToken``. It also has @@ -243,13 +275,18 @@ that will become more clear `later in the tutorial `_. In order to parse an arbitrary primary expression, we need to determine what sort of expression it is: -{% highlight python %} # primary ::= identifierexpr \| numberexpr \| -parenexpr def ParsePrimary(self): if isinstance(self.current, -IdentifierToken): return self.ParseIdentifierExpr() elif -isinstance(self.current, NumberToken): return self.ParseNumberExpr(); -elif self.current == CharacterToken('('): return self.ParseParenExpr() -else: raise RuntimeError('Unknown token when expecting an expression.') -{% endhighlight %} + +.. code-block:: python + + # primary ::= identifierexpr \| numberexpr \| + parenexpr def ParsePrimary(self): if isinstance(self.current, + IdentifierToken): return self.ParseIdentifierExpr() elif + isinstance(self.current, NumberToken): return self.ParseNumberExpr(); + elif self.current == CharacterToken('('): return self.ParseParenExpr() + else: raise RuntimeError('Unknown token when expecting an expression.') + + + Now that you see the definition of this function, it is more obvious why we can assume the state of ``Parser.current`` in the various functions. @@ -278,19 +315,24 @@ recursion. To start with, we need a table of precedences. Remember the ``binop_precedence`` parameter we passed to the ``Parser`` constructor? Now is the time to use it: -{% highlight python %} def main(): # Install standard binary operators. -# 1 is lowest possible precedence. 40 is the highest. -operator\_precedence = { '<': 10, '+': 20, '-': 20, '\*': 40 } -# Run the main ``interpreter loop``. while True: +.. code-block:: python -:: + def main(): # Install standard binary operators. + # 1 is lowest possible precedence. 40 is the highest. + operator_precedence = { '<': 10, '+': 20, '-': 20, '\*': 40 } + + # Run the main ``interpreter loop``. while True: + + :: + + ... + + parser = Parser(Tokenize(raw), operator_precedence) + + - ... - parser = Parser(Tokenize(raw), operator_precedence) - -{% endhighlight %} For the basic form of Kaleidoscope, we will only support 4 binary operators (this can obviously be extended by you, our brave and intrepid @@ -302,11 +344,16 @@ hardcode the comparisons. We also define a helper function to get the precedence of the current token, or -1 if the token is not a binary operator: -{% highlight python %} # Gets the precedence of the current token, or -1 -if the token is not a binary # operator. def -GetCurrentTokenPrecedence(self): if isinstance(self.current, -CharacterToken): return self.binop\_precedence.get(self.current.char, --1) else: return -1 {% endhighlight %} + +.. code-block:: python + + # Gets the precedence of the current token, or -1 + if the token is not a binary # operator. def + GetCurrentTokenPrecedence(self): if isinstance(self.current, + CharacterToken): return self.binop_precedence.get(self.current.char, + -1) else: return -1 + + With the helper above defined, we can now start parsing binary expressions. The basic idea of operator precedence parsing is to break @@ -322,9 +369,14 @@ doesn't need to worry about nested subexpressions like (c+d) at all. To start, an expression is a primary expression potentially followed by a sequence of ``[binop,primaryexpr]`` pairs: -{% highlight python %} # expression ::= primary binoprhs def -ParseExpression(self): left = self.ParsePrimary() return -self.ParseBinOpRHS(left, 0) {% endhighlight %} + +.. code-block:: python + + # expression ::= primary binoprhs def + ParseExpression(self): left = self.ParsePrimary() return + self.ParseBinOpRHS(left, 0) + + ``ParseBinOpRHS`` is the function that parses the sequence of pairs for us. It takes a precedence and a pointer to an expression for the part @@ -341,19 +393,24 @@ is passed in a precedence of 40, it will not consume any tokens (because the precedence of '+' is only 20). With this in mind, ``ParseBinOpRHS`` starts with: -{% highlight python %} # binoprhs ::= (operator primary)\* def -ParseBinOpRHS(self, left, left\_precedence): # If this is a binary -operator, find its precedence. while True: precedence = -self.GetCurrentTokenPrecedence() -:: +.. code-block:: python + + # binoprhs ::= (operator primary)\* def + ParseBinOpRHS(self, left, left_precedence): # If this is a binary + operator, find its precedence. while True: precedence = + self.GetCurrentTokenPrecedence() + + :: + + # If this is a binary operator that binds at least as tightly as the + # current one, consume it; otherwise we are done. + if precedence < left_precedence: + return left + + - # If this is a binary operator that binds at least as tightly as the - # current one, consume it; otherwise we are done. - if precedence < left_precedence: - return left -{% endhighlight %} This code gets the precedence of the current token and checks to see if if is too low. Because we defined invalid tokens to have a precedence of @@ -362,15 +419,20 @@ stream runs out of binary operators. If this check succeeds, we know that the token is a binary operator and that it will be included in this expression: -{% highlight python %} binary\_operator = self.current.char self.Next() -# eat the operator. -:: +.. code-block:: python + + binary_operator = self.current.char self.Next() + # eat the operator. + + :: + + # Parse the primary expression after the binary operator. + right = self.ParsePrimary() + + - # Parse the primary expression after the binary operator. - right = self.ParsePrimary() -{% endhighlight %} As such, this code eats (and remembers) the binary operator and then parses the primary expression that follows. This builds up the whole @@ -383,10 +445,15 @@ In particular, we could have ``(a+b) binop unparsed`` or ``binop`` to determine its precedence and compare it to BinOp's precedence (which is '+' in this case): -{% highlight python %} # If binary\_operator binds less tightly with -right than the operator after # right, let the pending operator take -right as its left. next\_precedence = self.GetCurrentTokenPrecedence() -if precedence < next\_precedence: {% endhighlight %} + +.. code-block:: python + + # If binary_operator binds less tightly with + right than the operator after # right, let the pending operator take + right as its left. next_precedence = self.GetCurrentTokenPrecedence() + if precedence < next_precedence: + + If the precedence of the binop to the right of ``RHS`` is lower or equal to the precedence of our current operator, then we know that the @@ -395,15 +462,20 @@ current operator is ``+`` and the next operator is ``+``, we know that they have the same precedence. In this case we'll create the AST node for ``a+b``, and then continue parsing: -{% highlight python %} if precedence < next\_precedence: ... if body -omitted ... -:: +.. code-block:: python + + if precedence < next_precedence: ... if body + omitted ... + + :: + + # Merge left/right. + left = BinaryOperatorExpressionNode(binary_operator, left, right); + + - # Merge left/right. - left = BinaryOperatorExpressionNode(binary_operator, left, right); -{% endhighlight %} In our example above, this will turn ``a+b+`` into ``(a+b)`` and execute the next iteration of the loop, with ``+`` as the current token. The @@ -420,18 +492,23 @@ all of ``( c + d ) * e * f`` as the RHS expression variable. The code to do this is surprisingly simple (code from the above two blocks duplicated for context): -{% highlight python %} # If binary\_operator binds less tightly with -right than the operator after # right, let the pending operator take -right as its left. next\_precedence = self.GetCurrentTokenPrecedence() -if precedence < next\_precedence: right = self.ParseBinOpRHS(right, -precedence + 1) -:: +.. code-block:: python + + # If binary_operator binds less tightly with + right than the operator after # right, let the pending operator take + right as its left. next_precedence = self.GetCurrentTokenPrecedence() + if precedence < next_precedence: right = self.ParseBinOpRHS(right, + precedence + 1) + + :: + + # Merge left/right. + left = BinaryOperatorExpressionNode(binary_operator, left, right) + + - # Merge left/right. - left = BinaryOperatorExpressionNode(binary_operator, left, right) -{% endhighlight %} At this point, we know that the binary operator to the RHS of our primary has higher precedence than the binop we are currently parsing. @@ -466,57 +543,77 @@ well as function body definitions. The code to do this is straight-forward and not very interesting (once you've survived expressions): -{% highlight python %} # prototype ::= id '(' id\* ')' def -ParsePrototype(self): if not isinstance(self.current, IdentifierToken): -raise RuntimeError('Expected function name in prototype.') -:: +.. code-block:: python - function_name = self.current.name - self.Next() # eat function name. + # prototype ::= id '(' id\* ')' def + ParsePrototype(self): if not isinstance(self.current, IdentifierToken): + raise RuntimeError('Expected function name in prototype.') + + :: + + function_name = self.current.name + self.Next() # eat function name. + + if self.current != CharacterToken('('): + raise RuntimeError('Expected "(" in prototype.') + self.Next() # eat '('. + + arg_names = [] + while isinstance(self.current, IdentifierToken): + arg_names.append(self.current.name) + self.Next() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")" in prototype.') + + # Success. + self.Next() # eat ')'. + + return PrototypeNode(function_name, arg_names) + + - if self.current != CharacterToken('('): - raise RuntimeError('Expected "(" in prototype.') - self.Next() # eat '('. - arg_names = [] - while isinstance(self.current, IdentifierToken): - arg_names.append(self.current.name) - self.Next() - - if self.current != CharacterToken(')'): - raise RuntimeError('Expected ")" in prototype.') - - # Success. - self.Next() # eat ')'. - - return PrototypeNode(function_name, arg_names) - -{% endhighlight %} Given this, a function definition is very simple, just a prototype plus an expression to implement the body: -{% highlight python %} # definition ::= 'def' prototype expression def -ParseDefinition(self): self.Next() # eat def. proto = -self.ParsePrototype() body = self.ParseExpression() return -FunctionNode(proto, body) {% endhighlight %} + +.. code-block:: python + + # definition ::= 'def' prototype expression def + ParseDefinition(self): self.Next() # eat def. proto = + self.ParsePrototype() body = self.ParseExpression() return + FunctionNode(proto, body) + + In addition, we support 'extern' to declare functions like 'sin' and 'cos' as well as to support forward declaration of user functions. These 'extern's are just prototypes with no body: -{% highlight python %} # external ::= 'extern' prototype def -ParseExtern(self): self.Next() # eat extern. return -self.ParsePrototype() {% endhighlight %} + +.. code-block:: python + + # external ::= 'extern' prototype def + ParseExtern(self): self.Next() # eat extern. return + self.ParsePrototype() + + Finally, we'll also let the user type in arbitrary top-level expressions and evaluate them on the fly. We will handle this by defining anonymous nullary (zero argument) functions for them: -{% highlight python %} # toplevelexpr ::= expression def -ParseTopLevelExpr(self): proto = PrototypeNode('', []) return -FunctionNode(proto, self.ParseExpression()) {% endhighlight %} + +.. code-block:: python + + # toplevelexpr ::= expression def + ParseTopLevelExpr(self): proto = PrototypeNode('', []) return + FunctionNode(proto, self.ParseExpression()) + + Now that we have all the pieces, let's build a little driver that will let us actually *execute* this code we've built! @@ -530,24 +627,29 @@ The driver for this simply invokes all of the parsing pieces with a top-level dispatch loop. There isn't much interesting here, so I'll just include the top-level loop. See `below <#code>`_ for full code. -{% highlight python %} # Run the main "interpreter loop". while True: -print 'ready>', try: raw = raw\_input() except KeyboardInterrupt: return -:: +.. code-block:: python + + # Run the main "interpreter loop". while True: + print 'ready>', try: raw = raw_input() except KeyboardInterrupt: return + + :: + + parser = Parser(Tokenize(raw), operator_precedence) + while True: + # top ::= definition | external | expression | EOF + if isinstance(parser.current, EOFToken): + break + if isinstance(parser.current, DefToken): + parser.HandleDefinition() + elif isinstance(parser.current, ExternToken): + parser.HandleExtern() + else: + parser.HandleTopLevelExpression() + + - parser = Parser(Tokenize(raw), operator_precedence) - while True: - # top ::= definition | external | expression | EOF - if isinstance(parser.current, EOFToken): - break - if isinstance(parser.current, DefToken): - parser.HandleDefinition() - elif isinstance(parser.current, ExternToken): - parser.HandleExtern() - else: - parser.HandleTopLevelExpression() -{% endhighlight %} Here we create a new ``Parser`` for each line read, and try to parse out all the expressions, declarations and definitions in the line. We also @@ -564,12 +666,17 @@ lexer, parser, and AST builder. With this done, the executable will validate Kaleidoscope code and tell us if it is grammatically invalid. For example, here is a sample interaction: -{% highlight python %} $ python kaleidoscope.py ready> def foo(x y) -x+foo(y, 4.0) Parsed a function definition. ready> def foo(x y) x+y y -Parsed a function definition. Parsed a top-level expression. ready> def -foo(x y) x+y ) Parsed a function definition. Error: Unknown token when -expecting an expression. ready> extern sin(a); Parsed an extern. ready> -^C $ {% endhighlight %} + +.. code-block:: python + + $ python kaleidoscope.py ready> def foo(x y) + x+foo(y, 4.0) Parsed a function definition. ready> def foo(x y) x+y y + Parsed a function definition. Parsed a top-level expression. ready> def + foo(x y) x+y ) Parsed a function definition. Error: Unknown token when + expecting an expression. ready> extern sin(a); Parsed an extern. ready> + ^C $ + + There is a lot of room for extension here. You can define new AST nodes, extend the language in many ways, etc. In the `next @@ -585,296 +692,272 @@ Here is the complete code listing for this and the previous chapter. Note that it is fully self-contained: you don't need LLVM or any external libraries at all for this. -{% highlight python %} #!/usr/bin/env python -import re - -Lexer ------ - -The lexer yields one of these types for each token. -=================================================== - -class EOFToken(object): pass - -class DefToken(object): pass - -class ExternToken(object): pass - -class IdentifierToken(object): def **init**\ (self, name): self.name = -name - -class NumberToken(object): def **init**\ (self, value): self.value = -value - -class CharacterToken(object): def **init**\ (self, char): self.char = -char def **eq**\ (self, other): return isinstance(other, CharacterToken) -and self.char == other.char def **ne**\ (self, other): return not self -== other - -Regular expressions that tokens and comments of our language. -============================================================= - -REGEX\_NUMBER = re.compile('[0-9]+(?:.[0-9]+)?') REGEX\_IDENTIFIER = -re.compile('[a-zA-Z][a-zA-Z0-9]\ *') REGEX\_COMMENT = re.compile('#.*') - -def Tokenize(string): while string: # Skip whitespace. if -string[0].isspace(): string = string[1:] continue - -:: - - # Run regexes. - comment_match = REGEX_COMMENT.match(string) - number_match = REGEX_NUMBER.match(string) - identifier_match = REGEX_IDENTIFIER.match(string) - - # Check if any of the regexes matched and yield the appropriate result. - if comment_match: - comment = comment_match.group(0) - string = string[len(comment):] - elif number_match: - number = number_match.group(0) - yield NumberToken(float(number)) - string = string[len(number):] - elif identifier_match: - identifier = identifier_match.group(0) - # Check if we matched a keyword. - if identifier == 'def': - yield DefToken() - elif identifier == 'extern': - yield ExternToken() - else: - yield IdentifierToken(identifier) - string = string[len(identifier):] - else: - # Yield the ASCII value of the unknown character. - yield CharacterToken(string[0]) - string = string[1:] - -yield EOFToken() - -Abstract Syntax Tree (aka Parse Tree) -------------------------------------- - -Base class for all expression nodes. -==================================== - -class ExpressionNode(object): pass - -Expression class for numeric literals like "1.0". -================================================= - -class NumberExpressionNode(ExpressionNode): def **init**\ (self, value): -self.value = value - -Expression class for referencing a variable, like "a". -====================================================== - -class VariableExpressionNode(ExpressionNode): def **init**\ (self, -name): self.name = name - -Expression class for a binary operator. -======================================= - -class BinaryOperatorExpressionNode(ExpressionNode): def **init**\ (self, -operator, left, right): self.operator = operator self.left = left -self.right = right - -Expression class for function calls. -==================================== - -class CallExpressionNode(ExpressionNode): def **init**\ (self, callee, -args): self.callee = callee self.args = args - -This class represents the "prototype" for a function, which captures its name, -============================================================================== - -and its argument names (thus implicitly the number of arguments the function -============================================================================ - -takes). -======= - -class PrototypeNode(object): def **init**\ (self, name, args): self.name -= name self.args = args - -This class represents a function definition itself. -=================================================== - -class FunctionNode(object): def **init**\ (self, prototype, body): -self.prototype = prototype self.body = body - -Parser ------- - -class Parser(object): - -def **init**\ (self, tokens, binop\_precedence): self.tokens = tokens -self.binop\_precedence = binop\_precedence self.Next() - -# Provide a simple token buffer. Parser.current is the current token the -# parser is looking at. Parser.Next() reads another token from the lexer -and # updates Parser.current with its results. def Next(self): -self.current = self.tokens.next() - -# Gets the precedence of the current token, or -1 if the token is not a -binary # operator. def GetCurrentTokenPrecedence(self): if -isinstance(self.current, CharacterToken): return -self.binop\_precedence.get(self.current.char, -1) else: return -1 - -# identifierexpr ::= identifier \| identifier '(' expression\* ')' def -ParseIdentifierExpr(self): identifier\_name = self.current.name -self.Next() # eat identifier. - -:: - - if self.current != CharacterToken('('): # Simple variable reference. - return VariableExpressionNode(identifier_name) - - # Call. - self.Next() # eat '('. - args = [] - if self.current != CharacterToken(')'): - while True: - args.append(self.ParseExpression()) - if self.current == CharacterToken(')'): - break - elif self.current != CharacterToken(','): - raise RuntimeError('Expected ")" or "," in argument list.') - self.Next() - - self.Next() # eat ')'. - return CallExpressionNode(identifier_name, args) - -# numberexpr ::= number def ParseNumberExpr(self): result = -NumberExpressionNode(self.current.value) self.Next() # consume the -number. return result - -# parenexpr ::= '(' expression ')' def ParseParenExpr(self): self.Next() -# eat '('. - -:: - - contents = self.ParseExpression() - - if self.current != CharacterToken(')'): - raise RuntimeError('Expected ")".') - self.Next() # eat ')'. - - return contents - -# primary ::= identifierexpr \| numberexpr \| parenexpr def -ParsePrimary(self): if isinstance(self.current, IdentifierToken): return -self.ParseIdentifierExpr() elif isinstance(self.current, NumberToken): -return self.ParseNumberExpr() elif self.current == CharacterToken('('): -return self.ParseParenExpr() else: raise RuntimeError('Unknown token -when expecting an expression.') - -# binoprhs ::= (operator primary)\* def ParseBinOpRHS(self, left, -left\_precedence): # If this is a binary operator, find its precedence. -while True: precedence = self.GetCurrentTokenPrecedence() - -:: - - # If this is a binary operator that binds at least as tightly as the - # current one, consume it; otherwise we are done. - if precedence < left_precedence: - return left - - binary_operator = self.current.char - self.Next() # eat the operator. - - # Parse the primary expression after the binary operator. - right = self.ParsePrimary() - - # If binary_operator binds less tightly with right than the operator after - # right, let the pending operator take right as its left. - next_precedence = self.GetCurrentTokenPrecedence() - if precedence < next_precedence: - right = self.ParseBinOpRHS(right, precedence + 1) - - # Merge left/right. - left = BinaryOperatorExpressionNode(binary_operator, left, right) - -# expression ::= primary binoprhs def ParseExpression(self): left = -self.ParsePrimary() return self.ParseBinOpRHS(left, 0) - -# prototype ::= id '(' id\* ')' def ParsePrototype(self): if not -isinstance(self.current, IdentifierToken): raise RuntimeError('Expected -function name in prototype.') - -:: - - function_name = self.current.name - self.Next() # eat function name. - - if self.current != CharacterToken('('): - raise RuntimeError('Expected "(" in prototype.') - self.Next() # eat '('. - - arg_names = [] - while isinstance(self.current, IdentifierToken): - arg_names.append(self.current.name) - self.Next() - - if self.current != CharacterToken(')'): - raise RuntimeError('Expected ")" in prototype.') - - # Success. - self.Next() # eat ')'. - - return PrototypeNode(function_name, arg_names) - -# definition ::= 'def' prototype expression def ParseDefinition(self): -self.Next() # eat def. proto = self.ParsePrototype() body = -self.ParseExpression() return FunctionNode(proto, body) - -# toplevelexpr ::= expression def ParseTopLevelExpr(self): proto = -PrototypeNode('', []) return FunctionNode(proto, self.ParseExpression()) - -# external ::= 'extern' prototype def ParseExtern(self): self.Next() # -eat extern. return self.ParsePrototype() - -# Top-Level parsing def HandleDefinition(self): -self.Handle(self.ParseDefinition, 'Parsed a function definition.') - -def HandleExtern(self): self.Handle(self.ParseExtern, 'Parsed an -extern.') - -def HandleTopLevelExpression(self): self.Handle(self.ParseTopLevelExpr, -'Parsed a top-level expression.') - -def Handle(self, function, message): try: function() print message -except Exception, e: print 'Error:', e try: self.Next() # Skip for error -recovery. except: pass - -Main driver code. ------------------ - -def main(): # Install standard binary operators. # 1 is lowest possible -precedence. 40 is the highest. operator\_precedence = { '<': 10, '+': -20, '-': 20, '\*': 40 } - -# Run the main "interpreter loop". while True: print 'ready>', try: raw -= raw\_input() except KeyboardInterrupt: return - -:: - - parser = Parser(Tokenize(raw), operator_precedence) - while True: - # top ::= definition | external | expression | EOF - if isinstance(parser.current, EOFToken): - break - if isinstance(parser.current, DefToken): - parser.HandleDefinition() - elif isinstance(parser.current, ExternToken): - parser.HandleExtern() - else: - parser.HandleTopLevelExpression() - -if **name** == '**main**\ ': main() {% endhighlight %} - --------------- - -**`Next: Implementing Code Generation to LLVM -IR `_** +.. code-block:: python + + #!/usr/bin/env python + + import re + + Lexer + ----- + + # The lexer yields one of these types for each token. + class EOFToken(object): pass + + class DefToken(object): pass + + class ExternToken(object): pass + + class IdentifierToken(object): def **init**\ (self, name): self.name = + name + + class NumberToken(object): def **init**\ (self, value): self.value = + value + + class CharacterToken(object): def **init**\ (self, char): self.char = + char def **eq**\ (self, other): return isinstance(other, CharacterToken) + and self.char == other.char def **ne**\ (self, other): return not self + == other + + # Regular expressions that tokens and comments of our language. + REGEX_NUMBER = re.compile('[0-9]+(?:.[0-9]+)?') REGEX_IDENTIFIER = + re.compile('[a-zA-Z][a-zA-Z0-9]\ *') REGEX_COMMENT = re.compile('#.*') + + def Tokenize(string): while string: # Skip whitespace. if + string[0].isspace(): string = string[1:] continue + + :: + + # Run regexes. + comment_match = REGEX_COMMENT.match(string) + number_match = REGEX_NUMBER.match(string) + identifier_match = REGEX_IDENTIFIER.match(string) + + # Check if any of the regexes matched and yield the appropriate result. + if comment_match: + comment = comment_match.group(0) + string = string[len(comment):] + elif number_match: + number = number_match.group(0) + yield NumberToken(float(number)) + string = string[len(number):] + elif identifier_match: + identifier = identifier_match.group(0) + # Check if we matched a keyword. + if identifier == 'def': + yield DefToken() + elif identifier == 'extern': + yield ExternToken() + else: + yield IdentifierToken(identifier) + string = string[len(identifier):] + else: + # Yield the ASCII value of the unknown character. + yield CharacterToken(string[0]) + string = string[1:] + + yield EOFToken() + + Abstract Syntax Tree (aka Parse Tree) + ------------------------------------- + + # Base class for all expression nodes. + class ExpressionNode(object): pass + + # Expression class for numeric literals like "1.0". + class NumberExpressionNode(ExpressionNode): def **init**\ (self, value): + self.value = value + + # Expression class for referencing a variable, like "a". + class VariableExpressionNode(ExpressionNode): def **init**\ (self, + name): self.name = name + + # Expression class for a binary operator. + class BinaryOperatorExpressionNode(ExpressionNode): def **init**\ (self, + operator, left, right): self.operator = operator self.left = left + self.right = right + + # Expression class for function calls. + class CallExpressionNode(ExpressionNode): def **init**\ (self, callee, + args): self.callee = callee self.args = args + + # This class represents the "prototype" for a function, which captures its name, + # and its argument names (thus implicitly the number of arguments the function + # takes). + class PrototypeNode(object): def **init**\ (self, name, args): self.name + = name self.args = args + + # This class represents a function definition itself. + class FunctionNode(object): def **init**\ (self, prototype, body): + self.prototype = prototype self.body = body + + Parser + ------ + + class Parser(object): + + def **init**\ (self, tokens, binop_precedence): self.tokens = tokens + self.binop_precedence = binop_precedence self.Next() + + # Provide a simple token buffer. Parser.current is the current token the + # parser is looking at. Parser.Next() reads another token from the lexer + and # updates Parser.current with its results. def Next(self): + self.current = self.tokens.next() + + # Gets the precedence of the current token, or -1 if the token is not a + binary # operator. def GetCurrentTokenPrecedence(self): if + isinstance(self.current, CharacterToken): return + self.binop_precedence.get(self.current.char, -1) else: return -1 + + # identifierexpr ::= identifier \| identifier '(' expression\* ')' def + ParseIdentifierExpr(self): identifier_name = self.current.name + self.Next() # eat identifier. + + :: + + if self.current != CharacterToken('('): # Simple variable reference. + return VariableExpressionNode(identifier_name) + + # Call. + self.Next() # eat '('. + args = [] + if self.current != CharacterToken(')'): + while True: + args.append(self.ParseExpression()) + if self.current == CharacterToken(')'): + break + elif self.current != CharacterToken(','): + raise RuntimeError('Expected ")" or "," in argument list.') + self.Next() + + self.Next() # eat ')'. + return CallExpressionNode(identifier_name, args) + + # numberexpr ::= number def ParseNumberExpr(self): result = + NumberExpressionNode(self.current.value) self.Next() # consume the + number. return result + + # parenexpr ::= '(' expression ')' def ParseParenExpr(self): self.Next() + # eat '('. + + :: + + contents = self.ParseExpression() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")".') + self.Next() # eat ')'. + + return contents + + # primary ::= identifierexpr \| numberexpr \| parenexpr def + ParsePrimary(self): if isinstance(self.current, IdentifierToken): return + self.ParseIdentifierExpr() elif isinstance(self.current, NumberToken): + return self.ParseNumberExpr() elif self.current == CharacterToken('('): + return self.ParseParenExpr() else: raise RuntimeError('Unknown token + when expecting an expression.') + + # binoprhs ::= (operator primary)\* def ParseBinOpRHS(self, left, + left_precedence): # If this is a binary operator, find its precedence. + while True: precedence = self.GetCurrentTokenPrecedence() + + :: + + # If this is a binary operator that binds at least as tightly as the + # current one, consume it; otherwise we are done. + if precedence < left_precedence: + return left + + binary_operator = self.current.char + self.Next() # eat the operator. + + # Parse the primary expression after the binary operator. + right = self.ParsePrimary() + + # If binary_operator binds less tightly with right than the operator after + # right, let the pending operator take right as its left. + next_precedence = self.GetCurrentTokenPrecedence() + if precedence < next_precedence: + right = self.ParseBinOpRHS(right, precedence + 1) + + # Merge left/right. + left = BinaryOperatorExpressionNode(binary_operator, left, right) + + # expression ::= primary binoprhs def ParseExpression(self): left = + self.ParsePrimary() return self.ParseBinOpRHS(left, 0) + + # prototype ::= id '(' id\* ')' def ParsePrototype(self): if not + isinstance(self.current, IdentifierToken): raise RuntimeError('Expected + function name in prototype.') + + :: + + function_name = self.current.name + self.Next() # eat function name. + + if self.current != CharacterToken('('): + raise RuntimeError('Expected "(" in prototype.') + self.Next() # eat '('. + + arg_names = [] + while isinstance(self.current, IdentifierToken): + arg_names.append(self.current.name) + self.Next() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")" in prototype.') + + # Success. + self.Next() # eat ')'. + + return PrototypeNode(function_name, arg_names) + + # definition ::= 'def' prototype expression def ParseDefinition(self): + self.Next() # eat def. proto = self.ParsePrototype() body = + self.ParseExpression() return FunctionNode(proto, body) + + # toplevelexpr ::= expression def ParseTopLevelExpr(self): proto = + PrototypeNode('', []) return FunctionNode(proto, self.ParseExpression()) + + # external ::= 'extern' prototype def ParseExtern(self): self.Next() # + eat extern. return self.ParsePrototype() + + # Top-Level parsing def HandleDefinition(self): + self.Handle(self.ParseDefinition, 'Parsed a function definition.') + + def HandleExtern(self): self.Handle(self.ParseExtern, 'Parsed an + extern.') + + def HandleTopLevelExpression(self): self.Handle(self.ParseTopLevelExpr, + 'Parsed a top-level expression.') + + def Handle(self, function, message): try: function() print message + except Exception, e: print 'Error:', e try: self.Next() # Skip for error + recovery. except: pass + + Main driver code. + ----------------- + + def main(): # Install standard binary operators. # 1 is lowest possible + precedence. 40 is the highest. operator_precedence = { '<': 10, '+': + 20, '-': 20, '\*': 40 } + + # Run the main "interpreter loop". while True: print 'ready>', try: raw + = raw_input() except KeyboardInterrupt: return + + :: + + parser = Parser(Tokenize(raw), operator_precedence) + while True: + # top ::= definition | external | expression | EOF + if isinstance(parser.current, EOFToken): + break + if isinstance(parser.current, DefToken): + parser.HandleDefinition() + elif isinstance(parser.current, ExternToken): + parser.HandleExtern() + else: + parser.HandleTopLevelExpression() + + if **name** == '**main**\ ': main() diff --git a/docs/source/doc/kaleidoscope/PythonLangImpl3.rst b/docs/source/doc/kaleidoscope/PythonLangImpl3.rst index 562f0f3..549cb7b 100644 --- a/docs/source/doc/kaleidoscope/PythonLangImpl3.rst +++ b/docs/source/doc/kaleidoscope/PythonLangImpl3.rst @@ -31,23 +31,26 @@ Code Generation Setup # {#basics} In order to generate LLVM IR, we want some simple setup to get started. First we define code generation methods in each AST node class: -{% highlight python %} # Expression class for numeric literals like -"1.0". class NumberExpressionNode(ExpressionNode): -def **init**\ (self, value): self.value = value +.. code-block:: python -def CodeGen(self): ... + # Expression class for numeric literals like + "1.0". class NumberExpressionNode(ExpressionNode): + + def **init**\ (self, value): self.value = value + + def CodeGen(self): ... + + # Expression class for referencing a variable, like "a". + class VariableExpressionNode(ExpressionNode): + + def **init**\ (self, name): self.name = name + + def CodeGen(self): ... + + ... -Expression class for referencing a variable, like "a". -====================================================== -class VariableExpressionNode(ExpressionNode): - -def **init**\ (self, name): self.name = name - -def CodeGen(self): ... - -... {% endhighlight %} The ``CodeGen`` method says to emit IR for that AST node along with all the things it depends on, and they all return an LLVM Value object. @@ -64,21 +67,20 @@ Assignment `_ We will also need to define some global variables which we will be used during code generation: -{% highlight python %} # The LLVM module, which holds all the IR code. -g\_llvm\_module = Module.new('my cool jit') -The LLVM instruction builder. Created whenever a new function is entered. -========================================================================= +.. code-block:: python -g\_llvm\_builder = None + # The LLVM module, which holds all the IR code. + g_llvm_module = Module.new('my cool jit') + + # The LLVM instruction builder. Created whenever a new function is entered. + g_llvm_builder = None + + # A dictionary that keeps track of which values are defined in the current scope + # and what their LLVM representation is. + g_named_values = {} -A dictionary that keeps track of which values are defined in the current scope -============================================================================== -and what their LLVM representation is. -====================================== - -g\_named\_values = {} {% endhighlight %} ``g_llvm_module`` is the LLVM construct that contains all of the functions and global variables in a chunk of code. In many ways, it is @@ -112,8 +114,13 @@ Generating LLVM code for expression nodes is very straightforward: less than 35 lines of commented code for all four of our expression nodes. First we'll do numeric literals: -{% highlight python %} def CodeGen(self): return -Constant.real(Type.double(), self.value) {% endhighlight %} + +.. code-block:: python + + def CodeGen(self): return + Constant.real(Type.double(), self.value) + + In llvmpy, floating point numeric constants are represented with the ``llvm.core.ConstantFP`` class. To create one, we can use the static @@ -123,9 +130,14 @@ LLVM IR constants are all uniqued together and shared. For this reason, we create the constant through a factory method instead of instantiating one directly. -{% highlight python %} def CodeGen(self): if self.name in -g\_named\_values: return g\_named\_values[self.name] else: raise -RuntimeError('Unknown variable name: ' + self.name) {% endhighlight %} + +.. code-block:: python + + def CodeGen(self): if self.name in + g_named_values: return g_named_values[self.name] else: raise + RuntimeError('Unknown variable name: ' + self.name) + + References to variables are also quite simple using LLVM. In the simple version of Kaleidoscope, we assume that the variable has already been @@ -137,25 +149,30 @@ the value for it. In future chapters, we'll add support for `loop induction variables `_ in the symbol table, and for `local variables `_. -{% highlight python %} def CodeGen(self): left = self.left.CodeGen() -right = self.right.CodeGen() -:: +.. code-block:: python + + def CodeGen(self): left = self.left.CodeGen() + right = self.right.CodeGen() + + :: + + if self.operator == '+': + return g_llvm_builder.fadd(left, right, 'addtmp') + elif self.operator == '-': + return g_llvm_builder.fsub(left, right, 'subtmp') + elif self.operator == '*': + return g_llvm_builder.fmul(left, right, 'multmp') + elif self.operator == '<': + result = g_llvm_builder.fcmp(FCMP_ULT, left, right, 'cmptmp') + # Convert bool 0 or 1 to double 0.0 or 1.0. + return g_llvm_builder.uitofp(result, Type.double(), 'booltmp') + else: + raise RuntimeError('Unknown binary operator.') + + - if self.operator == '+': - return g_llvm_builder.fadd(left, right, 'addtmp') - elif self.operator == '-': - return g_llvm_builder.fsub(left, right, 'subtmp') - elif self.operator == '*': - return g_llvm_builder.fmul(left, right, 'multmp') - elif self.operator == '<': - result = g_llvm_builder.fcmp(FCMP_ULT, left, right, 'cmptmp') - # Convert bool 0 or 1 to double 0.0 or 1.0. - return g_llvm_builder.uitofp(result, Type.double(), 'booltmp') - else: - raise RuntimeError('Unknown binary operator.') -{% endhighlight %} Binary operators start to get more interesting. The basic idea here is that we recursively emit code for the left-hand side of the expression, @@ -193,21 +210,26 @@ treating the input as an unsigned value. In contrast, if we used the the Kaleidoscope ``<`` operator would return 0.0 and -1.0, depending on the input value. -{% highlight python %} def CodeGen(self): # Look up the name in the -global module table. callee = -g\_llvm\_module.get\_function\_named(self.callee) -:: +.. code-block:: python - # Check for argument mismatch error. - if len(callee.args) != len(self.args): - raise RuntimeError('Incorrect number of arguments passed.') + def CodeGen(self): # Look up the name in the + global module table. callee = + g_llvm_module.get_function_named(self.callee) + + :: + + # Check for argument mismatch error. + if len(callee.args) != len(self.args): + raise RuntimeError('Incorrect number of arguments passed.') + + arg_values = [i.CodeGen() for i in self.args] + + return g_llvm_builder.call(callee, arg_values, 'calltmp') + + - arg_values = [i.CodeGen() for i in self.args] - return g_llvm_builder.call(callee, arg_values, 'calltmp') - -{% endhighlight %} Code generation for function calls is quite straightforward with LLVM. The code above initially does a function name lookup in the LLVM @@ -242,15 +264,20 @@ let's talk about code generation for prototypes: they are used both for function bodies and external function declarations. The code starts with: -{% highlight python %} def CodeGen(self): # Make the function type, eg. -double(double,double). funct\_type = Type.function( Type.double(), -[Type.double()] \* len(self.args), False) -:: +.. code-block:: python + + def CodeGen(self): # Make the function type, eg. + double(double,double). funct_type = Type.function( Type.double(), + [Type.double()] \* len(self.args), False) + + :: + + function = Function.new(g_llvm_module, funct_type, self.name) + + - function = Function.new(g_llvm_module, funct_type, self.name) -{% endhighlight %} The call to ``Type.function`` creates the ``FunctionType`` that should be used for a given Prototype. Since all function arguments in @@ -272,11 +299,16 @@ the name the user specified: since ``g_llvm_module`` is specified, this name is registered in ``g_llvm_module``'s symbol table, which is used by the function call code above. -{% highlight python %} # If the name conflicted, there was already -something with the same name. # If it has a body, don't allow -redefinition or reextern. if function.name != self.name: -function.delete() function = -g\_llvm\_module.get\_function\_named(self.name) {% endhighlight %} + +.. code-block:: python + + # If the name conflicted, there was already + something with the same name. # If it has a body, don't allow + redefinition or reextern. if function.name != self.name: + function.delete() function = + g_llvm_module.get_function_named(self.name) + + The Module symbol table works just like the Function symbol table when it comes to name conflicts: if a new function is created with a name was @@ -298,18 +330,23 @@ function we just created (by calling ``delete``) and then calling ``get_function_named`` to get the existing function with the specified name. -{% highlight python %} # If the function already has a body, reject -this. if not function.is\_declaration: raise RuntimeError('Redefinition -of function.') -:: +.. code-block:: python + + # If the function already has a body, reject + this. if not function.is_declaration: raise RuntimeError('Redefinition + of function.') + + :: + + # If F took a different number of args, reject. + if len(callee.args) != len(self.args): + raise RuntimeError('Redeclaration of a function with different number ' + 'of args.') + + - # If F took a different number of args, reject. - if len(callee.args) != len(self.args): - raise RuntimeError('Redeclaration of a function with different number ' - 'of args.') -{% endhighlight %} In order to verify the logic above, we first check to see if the pre-existing function is a forward declaration. Since we don't allow @@ -318,16 +355,21 @@ case. If the previous reference to a function was an 'extern', we simply verify that the number of arguments for that definition and this one match up. If not, we emit an error. -{% highlight python %} # Set names for all arguments and add them to the -variables symbol table. for arg, arg\_name in zip(function.args, -self.args): arg.name = arg\_name # Add arguments to variable symbol -table. g\_named\_values[arg\_name] = arg -:: +.. code-block:: python + + # Set names for all arguments and add them to the + variables symbol table. for arg, arg_name in zip(function.args, + self.args): arg.name = arg_name # Add arguments to variable symbol + table. g_named_values[arg_name] = arg + + :: + + return function + + - return function -{% endhighlight %} The last bit of code for prototypes loops over all of the arguments in the function, setting the name of the LLVM Argument objects to match, @@ -338,15 +380,20 @@ would be very straight-forward with the mechanics we have already used above. Once this is all set up, it returns the Function object to the caller. -{% highlight python %} def CodeGen(self): # Clear scope. -g\_named\_values.clear() -:: +.. code-block:: python + + def CodeGen(self): # Clear scope. + g_named_values.clear() + + :: + + # Create a function object. + function = self.prototype.CodeGen() + + - # Create a function object. - function = self.prototype.CodeGen() -{% endhighlight %} Code generation for function definitions starts out simply enough: we just clear out the ``g_named_values`` dictionary to make sure that there @@ -354,32 +401,37 @@ isn't anything in it from the last function we compiled and codegen the prototype. Code generation of the prototype ensures that there is an LLVM Function object that is ready to go for us. -{% highlight python %} # Create a new basic block to start insertion -into. block = function.append\_basic\_block('entry') global -g\_llvm\_builder g\_llvm\_builder = Builder.new(block) {% endhighlight -%} -Now we get to the point where ``g_llvm_builder`` is set up. The first -line creates a new `basic -block `_ (named "entry"), -which is inserted into the function. The second line declares that the -global ``g_llvm_builder`` object is to be changed. The last line creates -a new builder that is set up to insert new instructions into the basic -block we just created. Basic blocks in LLVM are an important part of -functions that define the `Control Flow -Graph `_. Since we -don't have any control flow, our functions will only contain one block -at this point. We'll fix this in `Chapter 5 `_ :). +.. code-block:: python -{% highlight python %} # Finish off the function. try: return\_value = -self.body.CodeGen() g\_llvm\_builder.ret(return\_value) + # Create a new basic block to start insertion + into. block = function.append_basic_block('entry') global + g_llvm_builder g_llvm_builder = Builder.new(block) {% endhighlight + %} + + Now we get to the point where ``g_llvm_builder`` is set up. The first + line creates a new `basic + block `_ (named "entry"), + which is inserted into the function. The second line declares that the + global ``g_llvm_builder`` object is to be changed. The last line creates + a new builder that is set up to insert new instructions into the basic + block we just created. Basic blocks in LLVM are an important part of + functions that define the `Control Flow + Graph `_. Since we + don't have any control flow, our functions will only contain one block + at this point. We'll fix this in `Chapter 5 `_ :). + + {% highlight python %} # Finish off the function. try: return_value = + self.body.CodeGen() g_llvm_builder.ret(return_value) + + :: + + # Validate the generated code, checking for consistency. + function.verify() + + -:: - # Validate the generated code, checking for consistency. - function.verify() - -{% endhighlight %} Once the insertion point is set up, we call the ``CodeGen`` method for the root expression of the function. If no error happens, this emits @@ -392,13 +444,18 @@ checks on the generated code, to determine if our compiler is doing everything right. Using this is important: it can catch a lot of bugs. Once the function is finished and validated, we return it. -{% highlight python %} except: function.delete() raise -:: +.. code-block:: python + + except: function.delete() raise + + :: + + return function + + - return function -{% endhighlight %} The only piece left here is handling of the error case. For simplicity, we handle this by merely deleting the function we produced with the @@ -411,9 +468,14 @@ can return a previously defined forward declaration, our code can actually delete a forward declaration. There are a number of ways to fix this bug; see what you can come up with! Here is a testcase: -{% highlight python %} extern foo(a b) # ok, defines foo. def foo(a b) c -# error, 'c' is invalid. def bar() foo(1, 2) # error, unknown function -"foo" {% endhighlight %} + +.. code-block:: python + + extern foo(a b) # ok, defines foo. def foo(a b) c + # error, 'c' is invalid. def bar() foo(1, 2) # error, unknown function + "foo" + + -------------- @@ -426,8 +488,13 @@ CodeGen into the ``Handle*`` functions, and then dumps out the LLVM IR. This gives a nice way to look at the LLVM IR for simple functions. For example: -{% highlight bash %} ready> 4+5 Read a top-level expression: define -double @0() { entry: ret double 9.000000e+00 } {% endhighlight %} + +.. code-block:: bash + + ready> 4+5 Read a top-level expression: define + double @0() { entry: ret double 9.000000e+00 } + + Note how the parser turns the top-level expression into anonymous functions for us. This will be handy when we add JIT support in the next @@ -435,56 +502,76 @@ chapter. Also note that the code is very literally transcribed, no optimizations are being performed except simple constant folding done by the Builder. We will add optimizations explicitly in the next chapter. -{% highlight bash %} ready> def foo(a b) a\ *a + 2*\ a\ *b + b*\ b Read -a function definition: define double @foo(double %a, double %b) { entry: -%multmp = fmul double %a, %a ; [#uses=1] %multmp1 = fmul double -2.000000e+00, %a ; [#uses=1] %multmp2 = fmul double %multmp1, %b ; -[#uses=1] %addtmp = fadd double %multmp, %multmp2 ; [#uses=1] %multmp3 = -fmul double %b, %b ; [#uses=1] %addtmp4 = fadd double %addtmp, %multmp3 -; [#uses=1] ret double %addtmp4 } {% endhighlight %} + +.. code-block:: bash + + ready> def foo(a b) a\ *a + 2*\ a\ *b + b*\ b Read + a function definition: define double @foo(double %a, double %b) { entry: + %multmp = fmul double %a, %a ; [#uses=1] %multmp1 = fmul double + 2.000000e+00, %a ; [#uses=1] %multmp2 = fmul double %multmp1, %b ; + [#uses=1] %addtmp = fadd double %multmp, %multmp2 ; [#uses=1] %multmp3 = + fmul double %b, %b ; [#uses=1] %addtmp4 = fadd double %addtmp, %multmp3 + ; [#uses=1] ret double %addtmp4 } + + This shows some simple arithmetic. Notice the striking similarity to the LLVM builder calls that we use to create the instructions. -{% highlight bash %} ready> def bar(a) foo(a, 4.0) + bar(31337) Read a -function definition: define double @bar(double %a) { entry: %calltmp = -call double @foo(double %a, double 4.000000e+00) ; [#uses=1] %calltmp1 = -call double @bar(double 3.133700e+04) ; [#uses=1] %addtmp = fadd double -%calltmp, %calltmp1 ; [#uses=1] ret double %addtmp } {% endhighlight %} + +.. code-block:: bash + + ready> def bar(a) foo(a, 4.0) + bar(31337) Read a + function definition: define double @bar(double %a) { entry: %calltmp = + call double @foo(double %a, double 4.000000e+00) ; [#uses=1] %calltmp1 = + call double @bar(double 3.133700e+04) ; [#uses=1] %addtmp = fadd double + %calltmp, %calltmp1 ; [#uses=1] ret double %addtmp } + + This shows some function calls. Note that this function will take a long time to execute if you call it. In the future we'll add conditional control flow to actually make recursion useful :). -{% highlight bash %} ready> extern cos(x) Read extern: declare double -@cos(double) -ready> cos(1.234) Read a top-level expression: define double @1() { -entry: %calltmp = call double @cos(double 1.234000e+00) ; [#uses=1] ret -double %calltmp } {% endhighlight %} +.. code-block:: bash + + ready> extern cos(x) Read extern: declare double + @cos(double) + + ready> cos(1.234) Read a top-level expression: define double @1() { + entry: %calltmp = call double @cos(double 1.234000e+00) ; [#uses=1] ret + double %calltmp } + + This shows an extern for the libm "cos" function, and a call to it. -{% highlight bash %} ready> ^C ; ModuleID = 'my cool jit' -define double @0() { entry: ret double 9.000000e+00 } +.. code-block:: bash -define double @foo(double %a, double %b) { entry: %multmp = fmul double -%a, %a ; [#uses=1] %multmp1 = fmul double 2.000000e+00, %a ; [#uses=1] -%multmp2 = fmul double %multmp1, %b ; [#uses=1] %addtmp = fadd double -%multmp, %multmp2 ; [#uses=1] %multmp3 = fmul double %b, %b ; [#uses=1] -%addtmp4 = fadd double %addtmp, %multmp3 ; [#uses=1] ret double %addtmp4 -} + ready> ^C ; ModuleID = 'my cool jit' + + define double @0() { entry: ret double 9.000000e+00 } + + define double @foo(double %a, double %b) { entry: %multmp = fmul double + %a, %a ; [#uses=1] %multmp1 = fmul double 2.000000e+00, %a ; [#uses=1] + %multmp2 = fmul double %multmp1, %b ; [#uses=1] %addtmp = fadd double + %multmp, %multmp2 ; [#uses=1] %multmp3 = fmul double %b, %b ; [#uses=1] + %addtmp4 = fadd double %addtmp, %multmp3 ; [#uses=1] ret double %addtmp4 + } + + define double @bar(double %a) { entry: %calltmp = call double + @foo(double %a, double 4.000000e+00) ; [#uses=1] %calltmp1 = call double + @bar(double 3.133700e+04) ; [#uses=1] %addtmp = fadd double %calltmp, + %calltmp1 ; [#uses=1] ret double %addtmp } + + declare double @cos(double) + + define double @1() { entry: %calltmp = call double @cos(double + 1.234000e+00) ; [#uses=1] ret double %calltmp } -define double @bar(double %a) { entry: %calltmp = call double -@foo(double %a, double 4.000000e+00) ; [#uses=1] %calltmp1 = call double -@bar(double 3.133700e+04) ; [#uses=1] %addtmp = fadd double %calltmp, -%calltmp1 ; [#uses=1] ret double %addtmp } -declare double @cos(double) - -define double @1() { entry: %calltmp = call double @cos(double -1.234000e+00) ; [#uses=1] ret double %calltmp } {% endhighlight %} When you quit the current demo, it dumps out the IR for the entire module generated. Here you can see the big picture with all the @@ -505,419 +592,388 @@ the LLVM code generator. Because this uses the llvmpy libraries, you need to `download <../download.html>`_ and `install <../userguide.html#install>`_ them. -{% highlight python %} #!/usr/bin/env python -import re from llvm.core import Module, Constant, Type, Function, -Builder, FCMP\_ULT - -Globals -------- - -The LLVM module, which holds all the IR code. -============================================= - -g\_llvm\_module = Module.new('my cool jit') - -The LLVM instruction builder. Created whenever a new function is entered. -========================================================================= - -g\_llvm\_builder = None - -A dictionary that keeps track of which values are defined in the current scope -============================================================================== - -and what their LLVM representation is. -====================================== - -g\_named\_values = {} - -Lexer ------ - -The lexer yields one of these types for each token. -=================================================== - -class EOFToken(object): pass - -class DefToken(object): pass - -class ExternToken(object): pass - -class IdentifierToken(object): def **init**\ (self, name): self.name = -name - -class NumberToken(object): def **init**\ (self, value): self.value = -value - -class CharacterToken(object): def **init**\ (self, char): self.char = -char def **eq**\ (self, other): return isinstance(other, CharacterToken) -and self.char == other.char def **ne**\ (self, other): return not self -== other - -Regular expressions that tokens and comments of our language. -============================================================= - -REGEX\_NUMBER = re.compile('[0-9]+(?:.[0-9]+)?') REGEX\_IDENTIFIER = -re.compile('[a-zA-Z][a-zA-Z0-9]\ *') REGEX\_COMMENT = re.compile('#.*') - -def Tokenize(string): while string: # Skip whitespace. if -string[0].isspace(): string = string[1:] continue - -:: - - # Run regexes. - comment_match = REGEX_COMMENT.match(string) - number_match = REGEX_NUMBER.match(string) - identifier_match = REGEX_IDENTIFIER.match(string) - - # Check if any of the regexes matched and yield the appropriate result. - if comment_match: - comment = comment_match.group(0) - string = string[len(comment):] - elif number_match: - number = number_match.group(0) - yield NumberToken(float(number)) - string = string[len(number):] - elif identifier_match: - identifier = identifier_match.group(0) - # Check if we matched a keyword. - if identifier == 'def': - yield DefToken() - elif identifier == 'extern': - yield ExternToken() - else: - yield IdentifierToken(identifier) - string = string[len(identifier):] - else: - # Yield the ASCII value of the unknown character. - yield CharacterToken(string[0]) - string = string[1:] - -yield EOFToken() - -Abstract Syntax Tree (aka Parse Tree) -------------------------------------- - -Base class for all expression nodes. -==================================== - -class ExpressionNode(object): pass - -Expression class for numeric literals like "1.0". -================================================= - -class NumberExpressionNode(ExpressionNode): - -def **init**\ (self, value): self.value = value - -def CodeGen(self): return Constant.real(Type.double(), self.value) - -Expression class for referencing a variable, like "a". -====================================================== - -class VariableExpressionNode(ExpressionNode): - -def **init**\ (self, name): self.name = name - -def CodeGen(self): if self.name in g\_named\_values: return -g\_named\_values[self.name] else: raise RuntimeError('Unknown variable -name: ' + self.name) - -Expression class for a binary operator. -======================================= - -class BinaryOperatorExpressionNode(ExpressionNode): - -def **init**\ (self, operator, left, right): self.operator = operator -self.left = left self.right = right - -def CodeGen(self): left = self.left.CodeGen() right = -self.right.CodeGen() - -:: - - if self.operator == '+': - return g_llvm_builder.fadd(left, right, 'addtmp') - elif self.operator == '-': - return g_llvm_builder.fsub(left, right, 'subtmp') - elif self.operator == '*': - return g_llvm_builder.fmul(left, right, 'multmp') - elif self.operator == '<': - result = g_llvm_builder.fcmp(FCMP_ULT, left, right, 'cmptmp') - # Convert bool 0 or 1 to double 0.0 or 1.0. - return g_llvm_builder.uitofp(result, Type.double(), 'booltmp') - else: - raise RuntimeError('Unknown binary operator.') - -Expression class for function calls. -==================================== - -class CallExpressionNode(ExpressionNode): - -def **init**\ (self, callee, args): self.callee = callee self.args = -args - -def CodeGen(self): # Look up the name in the global module table. callee -= g\_llvm\_module.get\_function\_named(self.callee) - -:: - - # Check for argument mismatch error. - if len(callee.args) != len(self.args): - raise RuntimeError('Incorrect number of arguments passed.') - - arg_values = [i.CodeGen() for i in self.args] - - return g_llvm_builder.call(callee, arg_values, 'calltmp') - -This class represents the "prototype" for a function, which captures its name, -============================================================================== - -and its argument names (thus implicitly the number of arguments the function -============================================================================ - -takes). -======= - -class PrototypeNode(object): - -def **init**\ (self, name, args): self.name = name self.args = args - -def CodeGen(self): # Make the function type, eg. double(double,double). -funct\_type = Type.function( Type.double(), [Type.double()] \* -len(self.args), False) - -:: - - function = Function.new(g_llvm_module, funct_type, self.name) - - # If the name conflicted, there was already something with the same name. - # If it has a body, don't allow redefinition or reextern. - if function.name != self.name: - function.delete() - function = g_llvm_module.get_function_named(self.name) - - # If the function already has a body, reject this. - if not function.is_declaration: - raise RuntimeError('Redefinition of function.') - - # If F took a different number of args, reject. - if len(callee.args) != len(self.args): - raise RuntimeError('Redeclaration of a function with different number ' - 'of args.') - - # Set names for all arguments and add them to the variables symbol table. - for arg, arg_name in zip(function.args, self.args): - arg.name = arg_name - # Add arguments to variable symbol table. - g_named_values[arg_name] = arg - - return function - -This class represents a function definition itself. -=================================================== - -class FunctionNode(object): - -def **init**\ (self, prototype, body): self.prototype = prototype -self.body = body - -def CodeGen(self): # Clear scope. g\_named\_values.clear() - -:: - - # Create a function object. - function = self.prototype.CodeGen() - - # Create a new basic block to start insertion into. - block = function.append_basic_block('entry') - global g_llvm_builder - g_llvm_builder = Builder.new(block) - - # Finish off the function. - try: - return_value = self.body.CodeGen() - g_llvm_builder.ret(return_value) - - # Validate the generated code, checking for consistency. - function.verify() - except: - function.delete() - raise - - return function - -Parser ------- - -class Parser(object): - -def **init**\ (self, tokens, binop\_precedence): self.tokens = tokens -self.binop\_precedence = binop\_precedence self.Next() - -# Provide a simple token buffer. Parser.current is the current token the -# parser is looking at. Parser.Next() reads another token from the lexer -and # updates Parser.current with its results. def Next(self): -self.current = self.tokens.next() - -# Gets the precedence of the current token, or -1 if the token is not a -binary # operator. def GetCurrentTokenPrecedence(self): if -isinstance(self.current, CharacterToken): return -self.binop\_precedence.get(self.current.char, -1) else: return -1 - -# identifierexpr ::= identifier \| identifier '(' expression\* ')' def -ParseIdentifierExpr(self): identifier\_name = self.current.name -self.Next() # eat identifier. - -:: - - if self.current != CharacterToken('('): # Simple variable reference. - return VariableExpressionNode(identifier_name) - - # Call. - self.Next() # eat '('. - args = [] - if self.current != CharacterToken(')'): - while True: - args.append(self.ParseExpression()) - if self.current == CharacterToken(')'): - break - elif self.current != CharacterToken(','): - raise RuntimeError('Expected ")" or "," in argument list.') - self.Next() - - self.Next() # eat ')'. - return CallExpressionNode(identifier_name, args) - -# numberexpr ::= number def ParseNumberExpr(self): result = -NumberExpressionNode(self.current.value) self.Next() # consume the -number. return result - -# parenexpr ::= '(' expression ')' def ParseParenExpr(self): self.Next() -# eat '('. - -:: - - contents = self.ParseExpression() - - if self.current != CharacterToken(')'): - raise RuntimeError('Expected ")".') - self.Next() # eat ')'. - - return contents - -# primary ::= identifierexpr \| numberexpr \| parenexpr def -ParsePrimary(self): if isinstance(self.current, IdentifierToken): return -self.ParseIdentifierExpr() elif isinstance(self.current, NumberToken): -return self.ParseNumberExpr() elif self.current == CharacterToken('('): -return self.ParseParenExpr() else: raise RuntimeError('Unknown token -when expecting an expression.') - -# binoprhs ::= (operator primary)\* def ParseBinOpRHS(self, left, -left\_precedence): # If this is a binary operator, find its precedence. -while True: precedence = self.GetCurrentTokenPrecedence() - -:: - - # If this is a binary operator that binds at least as tightly as the - # current one, consume it; otherwise we are done. - if precedence < left_precedence: - return left - - binary_operator = self.current.char - self.Next() # eat the operator. - - # Parse the primary expression after the binary operator. - right = self.ParsePrimary() - - # If binary_operator binds less tightly with right than the operator after - # right, let the pending operator take right as its left. - next_precedence = self.GetCurrentTokenPrecedence() - if precedence < next_precedence: - right = self.ParseBinOpRHS(right, precedence + 1) - - # Merge left/right. - left = BinaryOperatorExpressionNode(binary_operator, left, right) - -# expression ::= primary binoprhs def ParseExpression(self): left = -self.ParsePrimary() return self.ParseBinOpRHS(left, 0) - -# prototype ::= id '(' id\* ')' def ParsePrototype(self): if not -isinstance(self.current, IdentifierToken): raise RuntimeError('Expected -function name in prototype.') - -:: - - function_name = self.current.name - self.Next() # eat function name. - - if self.current != CharacterToken('('): - raise RuntimeError('Expected "(" in prototype.') - self.Next() # eat '('. - - arg_names = [] - while isinstance(self.current, IdentifierToken): - arg_names.append(self.current.name) - self.Next() - - if self.current != CharacterToken(')'): - raise RuntimeError('Expected ")" in prototype.') - - # Success. - self.Next() # eat ')'. - - return PrototypeNode(function_name, arg_names) - -# definition ::= 'def' prototype expression def ParseDefinition(self): -self.Next() # eat def. proto = self.ParsePrototype() body = -self.ParseExpression() return FunctionNode(proto, body) - -# toplevelexpr ::= expression def ParseTopLevelExpr(self): proto = -PrototypeNode('', []) return FunctionNode(proto, self.ParseExpression()) - -# external ::= 'extern' prototype def ParseExtern(self): self.Next() # -eat extern. return self.ParsePrototype() - -# Top-Level parsing def HandleDefinition(self): -self.Handle(self.ParseDefinition, 'Read a function definition:') - -def HandleExtern(self): self.Handle(self.ParseExtern, 'Read an extern:') - -def HandleTopLevelExpression(self): self.Handle(self.ParseTopLevelExpr, -'Read a top-level expression:') - -def Handle(self, function, message): try: print message, -function().CodeGen() except Exception, e: print 'Error:', e try: -self.Next() # Skip for error recovery. except: pass - -Main driver code. ------------------ - -def main(): # Install standard binary operators. # 1 is lowest possible -precedence. 40 is the highest. operator\_precedence = { '<': 10, '+': -20, '-': 20, '\*': 40 } - -# Run the main "interpreter loop". while True: print 'ready>', try: raw -= raw\_input() except KeyboardInterrupt: break - -:: - - parser = Parser(Tokenize(raw), operator_precedence) - while True: - # top ::= definition | external | expression | EOF - if isinstance(parser.current, EOFToken): - break - if isinstance(parser.current, DefToken): - parser.HandleDefinition() - elif isinstance(parser.current, ExternToken): - parser.HandleExtern() - else: - parser.HandleTopLevelExpression() - -# Print out all of the generated code. print '', g\_llvm\_module - -if **name** == '**main**\ ': main() {% endhighlight %} - --------------- - -**`Next: Adding JIT and Optimizer Support `_** +.. code-block:: python + + #!/usr/bin/env python + + import re from llvm.core import Module, Constant, Type, Function, + Builder, FCMP_ULT + + Globals + ------- + + # The LLVM module, which holds all the IR code. + g_llvm_module = Module.new('my cool jit') + + # The LLVM instruction builder. Created whenever a new function is entered. + g_llvm_builder = None + + # A dictionary that keeps track of which values are defined in the current scope + # and what their LLVM representation is. + g_named_values = {} + + Lexer + ----- + + # The lexer yields one of these types for each token. + class EOFToken(object): pass + + class DefToken(object): pass + + class ExternToken(object): pass + + class IdentifierToken(object): def **init**\ (self, name): self.name = + name + + class NumberToken(object): def **init**\ (self, value): self.value = + value + + class CharacterToken(object): def **init**\ (self, char): self.char = + char def **eq**\ (self, other): return isinstance(other, CharacterToken) + and self.char == other.char def **ne**\ (self, other): return not self + == other + + # Regular expressions that tokens and comments of our language. + REGEX_NUMBER = re.compile('[0-9]+(?:.[0-9]+)?') REGEX_IDENTIFIER = + re.compile('[a-zA-Z][a-zA-Z0-9]\ *') REGEX_COMMENT = re.compile('#.*') + + def Tokenize(string): while string: # Skip whitespace. if + string[0].isspace(): string = string[1:] continue + + :: + + # Run regexes. + comment_match = REGEX_COMMENT.match(string) + number_match = REGEX_NUMBER.match(string) + identifier_match = REGEX_IDENTIFIER.match(string) + + # Check if any of the regexes matched and yield the appropriate result. + if comment_match: + comment = comment_match.group(0) + string = string[len(comment):] + elif number_match: + number = number_match.group(0) + yield NumberToken(float(number)) + string = string[len(number):] + elif identifier_match: + identifier = identifier_match.group(0) + # Check if we matched a keyword. + if identifier == 'def': + yield DefToken() + elif identifier == 'extern': + yield ExternToken() + else: + yield IdentifierToken(identifier) + string = string[len(identifier):] + else: + # Yield the ASCII value of the unknown character. + yield CharacterToken(string[0]) + string = string[1:] + + yield EOFToken() + + Abstract Syntax Tree (aka Parse Tree) + ------------------------------------- + + # Base class for all expression nodes. + class ExpressionNode(object): pass + + # Expression class for numeric literals like "1.0". + class NumberExpressionNode(ExpressionNode): + + def **init**\ (self, value): self.value = value + + def CodeGen(self): return Constant.real(Type.double(), self.value) + + # Expression class for referencing a variable, like "a". + class VariableExpressionNode(ExpressionNode): + + def **init**\ (self, name): self.name = name + + def CodeGen(self): if self.name in g_named_values: return + g_named_values[self.name] else: raise RuntimeError('Unknown variable + name: ' + self.name) + + # Expression class for a binary operator. + class BinaryOperatorExpressionNode(ExpressionNode): + + def **init**\ (self, operator, left, right): self.operator = operator + self.left = left self.right = right + + def CodeGen(self): left = self.left.CodeGen() right = + self.right.CodeGen() + + :: + + if self.operator == '+': + return g_llvm_builder.fadd(left, right, 'addtmp') + elif self.operator == '-': + return g_llvm_builder.fsub(left, right, 'subtmp') + elif self.operator == '*': + return g_llvm_builder.fmul(left, right, 'multmp') + elif self.operator == '<': + result = g_llvm_builder.fcmp(FCMP_ULT, left, right, 'cmptmp') + # Convert bool 0 or 1 to double 0.0 or 1.0. + return g_llvm_builder.uitofp(result, Type.double(), 'booltmp') + else: + raise RuntimeError('Unknown binary operator.') + + # Expression class for function calls. + class CallExpressionNode(ExpressionNode): + + def **init**\ (self, callee, args): self.callee = callee self.args = + args + + def CodeGen(self): # Look up the name in the global module table. callee + = g_llvm_module.get_function_named(self.callee) + + :: + + # Check for argument mismatch error. + if len(callee.args) != len(self.args): + raise RuntimeError('Incorrect number of arguments passed.') + + arg_values = [i.CodeGen() for i in self.args] + + return g_llvm_builder.call(callee, arg_values, 'calltmp') + + # This class represents the "prototype" for a function, which captures its name, + # and its argument names (thus implicitly the number of arguments the function + # takes). + class PrototypeNode(object): + + def **init**\ (self, name, args): self.name = name self.args = args + + def CodeGen(self): # Make the function type, eg. double(double,double). + funct_type = Type.function( Type.double(), [Type.double()] \* + len(self.args), False) + + :: + + function = Function.new(g_llvm_module, funct_type, self.name) + + # If the name conflicted, there was already something with the same name. + # If it has a body, don't allow redefinition or reextern. + if function.name != self.name: + function.delete() + function = g_llvm_module.get_function_named(self.name) + + # If the function already has a body, reject this. + if not function.is_declaration: + raise RuntimeError('Redefinition of function.') + + # If F took a different number of args, reject. + if len(callee.args) != len(self.args): + raise RuntimeError('Redeclaration of a function with different number ' + 'of args.') + + # Set names for all arguments and add them to the variables symbol table. + for arg, arg_name in zip(function.args, self.args): + arg.name = arg_name + # Add arguments to variable symbol table. + g_named_values[arg_name] = arg + + return function + + # This class represents a function definition itself. + class FunctionNode(object): + + def **init**\ (self, prototype, body): self.prototype = prototype + self.body = body + + def CodeGen(self): # Clear scope. g_named_values.clear() + + :: + + # Create a function object. + function = self.prototype.CodeGen() + + # Create a new basic block to start insertion into. + block = function.append_basic_block('entry') + global g_llvm_builder + g_llvm_builder = Builder.new(block) + + # Finish off the function. + try: + return_value = self.body.CodeGen() + g_llvm_builder.ret(return_value) + + # Validate the generated code, checking for consistency. + function.verify() + except: + function.delete() + raise + + return function + + Parser + ------ + + class Parser(object): + + def **init**\ (self, tokens, binop_precedence): self.tokens = tokens + self.binop_precedence = binop_precedence self.Next() + + # Provide a simple token buffer. Parser.current is the current token the + # parser is looking at. Parser.Next() reads another token from the lexer + and # updates Parser.current with its results. def Next(self): + self.current = self.tokens.next() + + # Gets the precedence of the current token, or -1 if the token is not a + binary # operator. def GetCurrentTokenPrecedence(self): if + isinstance(self.current, CharacterToken): return + self.binop_precedence.get(self.current.char, -1) else: return -1 + + # identifierexpr ::= identifier \| identifier '(' expression\* ')' def + ParseIdentifierExpr(self): identifier_name = self.current.name + self.Next() # eat identifier. + + :: + + if self.current != CharacterToken('('): # Simple variable reference. + return VariableExpressionNode(identifier_name) + + # Call. + self.Next() # eat '('. + args = [] + if self.current != CharacterToken(')'): + while True: + args.append(self.ParseExpression()) + if self.current == CharacterToken(')'): + break + elif self.current != CharacterToken(','): + raise RuntimeError('Expected ")" or "," in argument list.') + self.Next() + + self.Next() # eat ')'. + return CallExpressionNode(identifier_name, args) + + # numberexpr ::= number def ParseNumberExpr(self): result = + NumberExpressionNode(self.current.value) self.Next() # consume the + number. return result + + # parenexpr ::= '(' expression ')' def ParseParenExpr(self): self.Next() + # eat '('. + + :: + + contents = self.ParseExpression() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")".') + self.Next() # eat ')'. + + return contents + + # primary ::= identifierexpr \| numberexpr \| parenexpr def + ParsePrimary(self): if isinstance(self.current, IdentifierToken): return + self.ParseIdentifierExpr() elif isinstance(self.current, NumberToken): + return self.ParseNumberExpr() elif self.current == CharacterToken('('): + return self.ParseParenExpr() else: raise RuntimeError('Unknown token + when expecting an expression.') + + # binoprhs ::= (operator primary)\* def ParseBinOpRHS(self, left, + left_precedence): # If this is a binary operator, find its precedence. + while True: precedence = self.GetCurrentTokenPrecedence() + + :: + + # If this is a binary operator that binds at least as tightly as the + # current one, consume it; otherwise we are done. + if precedence < left_precedence: + return left + + binary_operator = self.current.char + self.Next() # eat the operator. + + # Parse the primary expression after the binary operator. + right = self.ParsePrimary() + + # If binary_operator binds less tightly with right than the operator after + # right, let the pending operator take right as its left. + next_precedence = self.GetCurrentTokenPrecedence() + if precedence < next_precedence: + right = self.ParseBinOpRHS(right, precedence + 1) + + # Merge left/right. + left = BinaryOperatorExpressionNode(binary_operator, left, right) + + # expression ::= primary binoprhs def ParseExpression(self): left = + self.ParsePrimary() return self.ParseBinOpRHS(left, 0) + + # prototype ::= id '(' id\* ')' def ParsePrototype(self): if not + isinstance(self.current, IdentifierToken): raise RuntimeError('Expected + function name in prototype.') + + :: + + function_name = self.current.name + self.Next() # eat function name. + + if self.current != CharacterToken('('): + raise RuntimeError('Expected "(" in prototype.') + self.Next() # eat '('. + + arg_names = [] + while isinstance(self.current, IdentifierToken): + arg_names.append(self.current.name) + self.Next() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")" in prototype.') + + # Success. + self.Next() # eat ')'. + + return PrototypeNode(function_name, arg_names) + + # definition ::= 'def' prototype expression def ParseDefinition(self): + self.Next() # eat def. proto = self.ParsePrototype() body = + self.ParseExpression() return FunctionNode(proto, body) + + # toplevelexpr ::= expression def ParseTopLevelExpr(self): proto = + PrototypeNode('', []) return FunctionNode(proto, self.ParseExpression()) + + # external ::= 'extern' prototype def ParseExtern(self): self.Next() # + eat extern. return self.ParsePrototype() + + # Top-Level parsing def HandleDefinition(self): + self.Handle(self.ParseDefinition, 'Read a function definition:') + + def HandleExtern(self): self.Handle(self.ParseExtern, 'Read an extern:') + + def HandleTopLevelExpression(self): self.Handle(self.ParseTopLevelExpr, + 'Read a top-level expression:') + + def Handle(self, function, message): try: print message, + function().CodeGen() except Exception, e: print 'Error:', e try: + self.Next() # Skip for error recovery. except: pass + + Main driver code. + ----------------- + + def main(): # Install standard binary operators. # 1 is lowest possible + precedence. 40 is the highest. operator_precedence = { '<': 10, '+': + 20, '-': 20, '\*': 40 } + + # Run the main "interpreter loop". while True: print 'ready>', try: raw + = raw_input() except KeyboardInterrupt: break + + :: + + parser = Parser(Tokenize(raw), operator_precedence) + while True: + # top ::= definition | external | expression | EOF + if isinstance(parser.current, EOFToken): + break + if isinstance(parser.current, DefToken): + parser.HandleDefinition() + elif isinstance(parser.current, ExternToken): + parser.HandleExtern() + else: + parser.HandleTopLevelExpression() + + # Print out all of the generated code. print '', g_llvm_module + + if **name** == '**main**\ ': main() diff --git a/docs/source/doc/kaleidoscope/PythonLangImpl4.rst b/docs/source/doc/kaleidoscope/PythonLangImpl4.rst index d9e32da..da6a5d8 100644 --- a/docs/source/doc/kaleidoscope/PythonLangImpl4.rst +++ b/docs/source/doc/kaleidoscope/PythonLangImpl4.rst @@ -25,17 +25,27 @@ Our demonstration for Chapter 3 is elegant and easy to extend. Unfortunately, it does not produce wonderful code. The LLVM Builder, however, does give us obvious optimizations when compiling simple code: -{% highlight bash %} ready> def test(x) 1+2+x Read function definition: -define double @test(double %x) { entry: %addtmp = fadd double -3.000000e+00, %x ret double %addtmp } {% endhighlight %} + +.. code-block:: bash + + ready> def test(x) 1+2+x Read function definition: + define double @test(double %x) { entry: %addtmp = fadd double + 3.000000e+00, %x ret double %addtmp } + + This code is not a literal transcription of the AST built by parsing the input. That would be: -{% highlight bash %} ready> def test(x) 1+2+x Read function definition: -define double @test(double %x) { entry: %addtmp = fadd double -2.000000e+00, 1.000000e+00 %addtmp1 = fadd double %addtmp, %x ret double -%addtmp1 } {% endhighlight %} + +.. code-block:: bash + + ready> def test(x) 1+2+x Read function definition: + define double @test(double %x) { entry: %addtmp = fadd double + 2.000000e+00, 1.000000e+00 %addtmp1 = fadd double %addtmp, %x ret double + %addtmp1 } + + Constant folding, as seen above, in particular, is a very common and very important optimization: so much so that many language implementors @@ -58,11 +68,16 @@ On the other hand, the ``Builder`` is limited by the fact that it does all of its analysis inline with the code as it is built. If you take a slightly more complex example: -{% highlight bash %} ready> def test(x) (1+2+x)\*(x+(1+2)) Read a -function definition: define double @test(double %x) { entry: %addtmp = -fadd double 3.000000e+00, %x ; [#uses=1] %addtmp1 = fadd double %x, -3.000000e+00 ; [#uses=1] %multmp = fmul double %addtmp, %addtmp1 ; -[#uses=1] ret double %multmp } {% endhighlight %} + +.. code-block:: bash + + ready> def test(x) (1+2+x)\*(x+(1+2)) Read a + function definition: define double @test(double %x) { entry: %addtmp = + fadd double 3.000000e+00, %x ; [#uses=1] %addtmp1 = fadd double %x, + 3.000000e+00 ; [#uses=1] %multmp = fmul double %addtmp, %addtmp1 ; + [#uses=1] ret double %multmp } + + In this case, the LHS and RHS of the multiplication are the same value. We'd really like to see this generate"``tmp = x+3; result = tmp*tmp;`` @@ -112,27 +127,30 @@ to hold and organize the LLVM optimizations that we want to run. Once we have that, we can add a set of optimizations to run. The code looks like this: -{% highlight python %} # The function optimization passes manager. -g\_llvm\_pass\_manager = FunctionPassManager.new(g\_llvm\_module) -The LLVM execution engine. -========================== +.. code-block:: python -g\_llvm\_executor = ExecutionEngine.new(g\_llvm\_module) + # The function optimization passes manager. + g_llvm_pass_manager = FunctionPassManager.new(g_llvm_module) + + # The LLVM execution engine. + g_llvm_executor = ExecutionEngine.new(g_llvm_module) + + ... + + def main(): # Set up the optimizer pipeline. Start with registering info + about how the # target lays out data structures. + g_llvm_pass_manager.add(g_llvm_executor.target_data) # Do simple + "peephole" optimizations and bit-twiddling optzns. + g_llvm_pass_manager.add(PASS_INSTRUCTION_COMBINING) # Reassociate + expressions. g_llvm_pass_manager.add(PASS_REASSOCIATE) # Eliminate + Common SubExpressions. g_llvm_pass_manager.add(PASS_GVN) # Simplify + the control flow graph (deleting unreachable blocks, etc). + g_llvm_pass_manager.add(PASS_CFG_SIMPLIFICATION) + + g_llvm_pass_manager.initialize() -... -def main(): # Set up the optimizer pipeline. Start with registering info -about how the # target lays out data structures. -g\_llvm\_pass\_manager.add(g\_llvm\_executor.target\_data) # Do simple -"peephole" optimizations and bit-twiddling optzns. -g\_llvm\_pass\_manager.add(PASS\_INSTRUCTION\_COMBINING) # Reassociate -expressions. g\_llvm\_pass\_manager.add(PASS\_REASSOCIATE) # Eliminate -Common SubExpressions. g\_llvm\_pass\_manager.add(PASS\_GVN) # Simplify -the control flow graph (deleting unreachable blocks, etc). -g\_llvm\_pass\_manager.add(PASS\_CFG\_SIMPLIFICATION) - -g\_llvm\_pass\_manager.initialize() {% endhighlight %} This code defines a ``FunctionPassManager``, ``g_llvm_pass_manager``. Once it is set up, we use a series of "add" calls to add a bunch of LLVM @@ -149,28 +167,38 @@ Once the pass manager is set up, we need to make use of it. We do this by running it after our newly created function is constructed (in ``FunctionNode.CodeGen``), but before it is returned to the client: -{% highlight python %} return\_value = self.body.CodeGen() -g\_llvm\_builder.ret(return\_value) -:: +.. code-block:: python - # Validate the generated code, checking for consistency. - function.verify() + return_value = self.body.CodeGen() + g_llvm_builder.ret(return_value) + + :: + + # Validate the generated code, checking for consistency. + function.verify() + + # Optimize the function. + g_llvm_pass_manager.run(function) + + - # Optimize the function. - g_llvm_pass_manager.run(function) -{% endhighlight %} As you can see, this is pretty straightforward. The ``FunctionPassManager`` optimizes and updates the LLVM Function in place, improving (hopefully) its body. With this in place, we can try our test above again: -{% highlight bash %} ready> def test(x) (1+2+x)\*(x+(1+2)) Read a -function definition: define double @test(double %x) { entry: %addtmp = -fadd double %x, 3.000000e+00 ; [#uses=2] %multmp = fmul double %addtmp, -%addtmp ; [#uses=1] ret double %multmp } {% endhighlight %} + +.. code-block:: bash + + ready> def test(x) (1+2+x)\*(x+(1+2)) Read a + function definition: define double @test(double %x) { entry: %addtmp = + fadd double %x, 3.000000e+00 ; [#uses=2] %multmp = fmul double %addtmp, + %addtmp ; [#uses=1] ret double %multmp } + + As expected, we now get our nicely optimized code, saving a floating point add instruction from every execution of this function. @@ -208,8 +236,13 @@ be able to call it from the command line. In order to do this, we first declare and initialize the JIT. This is done by adding and initializing a global variable: -{% highlight python %} # The LLVM execution engine. g\_llvm\_executor = -ExecutionEngine.new(g\_llvm\_module) {% endhighlight %} + +.. code-block:: python + + # The LLVM execution engine. g_llvm_executor = + ExecutionEngine.new(g_llvm_module) + + This creates an abstract "Execution Engine" which can be either a JIT compiler or the LLVM interpreter. LLVM will automatically pick a JIT @@ -222,38 +255,48 @@ compiled function and get its return value. In our case, this means that we can change the code that parses a top-level expression to look like this: -{% highlight python %} def HandleTopLevelExpression(self): try: function -= self.ParseTopLevelExpr().CodeGen() result = -g\_llvm\_executor.run\_function(function, []) print 'Evaluated to:', -result.as\_real(Type.double()) except Exception, e: print 'Error:', e -try: self.Next() # Skip for error recovery. except: pass {% endhighlight -%} -Recall that we compile top-level expressions into a self-contained LLVM -function that takes no arguments and returns the computed double. +.. code-block:: python -With just these two changes, lets see how Kaleidoscope works now! + def HandleTopLevelExpression(self): try: function + = self.ParseTopLevelExpr().CodeGen() result = + g_llvm_executor.run_function(function, []) print 'Evaluated to:', + result.as_real(Type.double()) except Exception, e: print 'Error:', e + try: self.Next() # Skip for error recovery. except: pass {% endhighlight + %} + + Recall that we compile top-level expressions into a self-contained LLVM + function that takes no arguments and returns the computed double. + + With just these two changes, lets see how Kaleidoscope works now! + + {% highlight python %} ready> 4+5 Read a top level expression: define + double @0() { entry: ret double 9.000000e+00 } + + Evaluated to: 9.0 -{% highlight python %} ready> 4+5 Read a top level expression: define -double @0() { entry: ret double 9.000000e+00 } -Evaluated to: 9.0 {% endhighlight %} Well this looks like it is basically working. The dump of the function shows the "no argument function that always returns double" that we synthesize for each top-level expression that is typed in. This demonstrates very basic functionality, but can we do more? -{% highlight python %} ready> def testfunc(x y) x + y\*2 Read a function -definition: define double @testfunc(double %x, double %y) { entry: -%multmp = fmul double %y, 2.000000e+00 ; [#uses=1] %addtmp = fadd double -%multmp, %x ; [#uses=1] ret double %addtmp } -ready> testfunc(4, 10) Read a top level expression: define double @0() { -entry: %calltmp = call double @testfunc(double 4.000000e+00, double -1.000000e+01) ; [#uses=1] ret double %calltmp } +.. code-block:: python + + ready> def testfunc(x y) x + y\*2 Read a function + definition: define double @testfunc(double %x, double %y) { entry: + %multmp = fmul double %y, 2.000000e+00 ; [#uses=1] %addtmp = fadd double + %multmp, %x ; [#uses=1] ret double %addtmp } + + ready> testfunc(4, 10) Read a top level expression: define double @0() { + entry: %calltmp = call double @testfunc(double 4.000000e+00, double + 1.000000e+01) ; [#uses=1] ret double %calltmp } + + *Evaluated to: 24.0* + -*Evaluated to: 24.0* {% endhighlight %} This illustrates that we can now call user code, but there is something a bit subtle going on here. Note that we only invoke the JIT on the @@ -269,23 +312,28 @@ etc. However, even with this simple code, we get some surprisingly powerful capabilities - check this out (I removed the dump of the anonymous functions, you should get the idea by now :) : -{% highlight bash %} ready> extern sin(x) Read an extern: declare double -@sin(double) -ready> extern cos(x) Read an extern: declare double @cos(double) +.. code-block:: bash -ready> sin(1.0) *Evaluated to: 0.841470984808* + ready> extern sin(x) Read an extern: declare double + @sin(double) + + ready> extern cos(x) Read an extern: declare double @cos(double) + + ready> sin(1.0) *Evaluated to: 0.841470984808* + + ready> def foo(x) sin(x)\ *sin(x) + cos(x)*\ cos(x) Read a function + definition: define double @foo(double %x) { entry: %calltmp = call + double @sin(double %x) ; [#uses=1] %calltmp1 = call double @sin(double + %x) ; [#uses=1] %multmp = fmul double %calltmp, %calltmp1 ; [#uses=1] + %calltmp2 = call double @cos(double %x) ; [#uses=1] %calltmp3 = call + double @cos(double %x) ; [#uses=1] %multmp4 = fmul double %calltmp2, + %calltmp3 ; [#uses=1] %addtmp = fadd double %multmp, %multmp4 ; + [#uses=1] ret double %addtmp } + + ready> foo(4.0) *Evaluated to: 1.000000* -ready> def foo(x) sin(x)\ *sin(x) + cos(x)*\ cos(x) Read a function -definition: define double @foo(double %x) { entry: %calltmp = call -double @sin(double %x) ; [#uses=1] %calltmp1 = call double @sin(double -%x) ; [#uses=1] %multmp = fmul double %calltmp, %calltmp1 ; [#uses=1] -%calltmp2 = call double @cos(double %x) ; [#uses=1] %calltmp3 = call -double @cos(double %x) ; [#uses=1] %multmp4 = fmul double %calltmp2, -%calltmp3 ; [#uses=1] %addtmp = fadd double %multmp, %multmp4 ; -[#uses=1] ret double %addtmp } -ready> foo(4.0) *Evaluated to: 1.000000* {% endhighlight %} Whoa, how does the JIT know about sin and cos? The answer is surprisingly simple: in this example, the JIT started execution of a @@ -301,27 +349,32 @@ One interesting application of this is that we can now extend the language by writing arbitrary C++ code to implement operations. For example, we can create a C file with the following simple function: -{% highlight c %} #include -double putchard(double x) { putchar((char)x); return 0; } {% -endhighlight %} +.. code-block:: c -We can then compile this into a shared library with GCC: + #include + + double putchard(double x) { putchar((char)x); return 0; } {% + endhighlight %} + + We can then compile this into a shared library with GCC: + + {% highlight bash %} gcc -shared -fPIC -o putchard.so putchard.c {% + endhighlight %} + + Now we can load this library into the Python process using + ``llvm.core.load_library_permanently`` and access it from Kaleidoscope + to produce simple output to the console: + + {% highlight python %} >>> import llvm.core >>> + llvm.core.load_library_permanently('/home/max/llvmpy-tutorial/putchard.so') + >>> import kaleidoscope >>> kaleidoscope.main() ready> extern + putchard(x) Read an extern: declare double @putchard(double) + + ready> putchard(65) + putchard(66) + putchard(67) + putchard(10) *ABC* + Evaluated to: 0.0 -{% highlight bash %} gcc -shared -fPIC -o putchard.so putchard.c {% -endhighlight %} -Now we can load this library into the Python process using -``llvm.core.load_library_permanently`` and access it from Kaleidoscope -to produce simple output to the console: - -{% highlight python %} >>> import llvm.core >>> -llvm.core.load\_library\_permanently('/home/max/llvmpy-tutorial/putchard.so') ->>> import kaleidoscope >>> kaleidoscope.main() ready> extern -putchard(x) Read an extern: declare double @putchard(double) - -ready> putchard(65) + putchard(66) + putchard(67) + putchard(10) *ABC* -Evaluated to: 0.0 {% endhighlight %} Similar code could be used to implement file I/O, console input, and many other capabilities in Kaleidoscope. @@ -341,450 +394,415 @@ Full Code Listing # {#code} Here is the complete code listing for our running example, enhanced with the LLVM JIT and optimizer: -{% highlight python %} #!/usr/bin/env python -import re from llvm.core import Module, Constant, Type, Function, -Builder, FCMP\_ULT from llvm.ee import ExecutionEngine, TargetData from -llvm.passes import FunctionPassManager from llvm.passes import -(PASS\_INSTRUCTION\_COMBINING, PASS\_REASSOCIATE, PASS\_GVN, -PASS\_CFG\_SIMPLIFICATION) - -Globals -------- - -The LLVM module, which holds all the IR code. -============================================= - -g\_llvm\_module = Module.new('my cool jit') - -The LLVM instruction builder. Created whenever a new function is entered. -========================================================================= - -g\_llvm\_builder = None - -A dictionary that keeps track of which values are defined in the current scope -============================================================================== - -and what their LLVM representation is. -====================================== - -g\_named\_values = {} - -The function optimization passes manager. -========================================= - -g\_llvm\_pass\_manager = FunctionPassManager.new(g\_llvm\_module) - -The LLVM execution engine. -========================== - -g\_llvm\_executor = ExecutionEngine.new(g\_llvm\_module) - -Lexer ------ - -The lexer yields one of these types for each token. -=================================================== - -class EOFToken(object): pass - -class DefToken(object): pass - -class ExternToken(object): pass - -class IdentifierToken(object): def **init**\ (self, name): self.name = -name - -class NumberToken(object): def **init**\ (self, value): self.value = -value - -class CharacterToken(object): def **init**\ (self, char): self.char = -char def **eq**\ (self, other): return isinstance(other, CharacterToken) -and self.char == other.char def **ne**\ (self, other): return not self -== other - -Regular expressions that tokens and comments of our language. -============================================================= - -REGEX\_NUMBER = re.compile('[0-9]+(?:.[0-9]+)?') REGEX\_IDENTIFIER = -re.compile('[a-zA-Z][a-zA-Z0-9]\ *') REGEX\_COMMENT = re.compile('#.*') - -def Tokenize(string): while string: # Skip whitespace. if -string[0].isspace(): string = string[1:] continue - -:: - - # Run regexes. - comment_match = REGEX_COMMENT.match(string) - number_match = REGEX_NUMBER.match(string) - identifier_match = REGEX_IDENTIFIER.match(string) - - # Check if any of the regexes matched and yield the appropriate result. - if comment_match: - comment = comment_match.group(0) - string = string[len(comment):] - elif number_match: - number = number_match.group(0) - yield NumberToken(float(number)) - string = string[len(number):] - elif identifier_match: - identifier = identifier_match.group(0) - # Check if we matched a keyword. - if identifier == 'def': - yield DefToken() - elif identifier == 'extern': - yield ExternToken() - else: - yield IdentifierToken(identifier) - string = string[len(identifier):] - else: - # Yield the ASCII value of the unknown character. - yield CharacterToken(string[0]) - string = string[1:] - -yield EOFToken() - -Abstract Syntax Tree (aka Parse Tree) -------------------------------------- - -Base class for all expression nodes. -==================================== - -class ExpressionNode(object): pass - -Expression class for numeric literals like "1.0". -================================================= - -class NumberExpressionNode(ExpressionNode): - -def **init**\ (self, value): self.value = value - -def CodeGen(self): return Constant.real(Type.double(), self.value) - -Expression class for referencing a variable, like "a". -====================================================== - -class VariableExpressionNode(ExpressionNode): - -def **init**\ (self, name): self.name = name - -def CodeGen(self): if self.name in g\_named\_values: return -g\_named\_values[self.name] else: raise RuntimeError('Unknown variable -name: ' + self.name) - -Expression class for a binary operator. -======================================= - -class BinaryOperatorExpressionNode(ExpressionNode): - -def **init**\ (self, operator, left, right): self.operator = operator -self.left = left self.right = right - -def CodeGen(self): left = self.left.CodeGen() right = -self.right.CodeGen() - -:: - - if self.operator == '+': - return g_llvm_builder.fadd(left, right, 'addtmp') - elif self.operator == '-': - return g_llvm_builder.fsub(left, right, 'subtmp') - elif self.operator == '*': - return g_llvm_builder.fmul(left, right, 'multmp') - elif self.operator == '<': - result = g_llvm_builder.fcmp(FCMP_ULT, left, right, 'cmptmp') - # Convert bool 0 or 1 to double 0.0 or 1.0. - return g_llvm_builder.uitofp(result, Type.double(), 'booltmp') - else: - raise RuntimeError('Unknown binary operator.') - -Expression class for function calls. -==================================== - -class CallExpressionNode(ExpressionNode): - -def **init**\ (self, callee, args): self.callee = callee self.args = -args - -def CodeGen(self): # Look up the name in the global module table. callee -= g\_llvm\_module.get\_function\_named(self.callee) - -:: - - # Check for argument mismatch error. - if len(callee.args) != len(self.args): - raise RuntimeError('Incorrect number of arguments passed.') - - arg_values = [i.CodeGen() for i in self.args] - - return g_llvm_builder.call(callee, arg_values, 'calltmp') - -This class represents the "prototype" for a function, which captures its name, -============================================================================== - -and its argument names (thus implicitly the number of arguments the function -============================================================================ - -takes). -======= - -class PrototypeNode(object): - -def **init**\ (self, name, args): self.name = name self.args = args - -def CodeGen(self): # Make the function type, eg. double(double,double). -funct\_type = Type.function( Type.double(), [Type.double()] \* -len(self.args), False) - -:: - - function = Function.new(g_llvm_module, funct_type, self.name) - - # If the name conflicted, there was already something with the same name. - # If it has a body, don't allow redefinition or reextern. - if function.name != self.name: - function.delete() - function = g_llvm_module.get_function_named(self.name) - - # If the function already has a body, reject this. - if not function.is_declaration: - raise RuntimeError('Redefinition of function.') - - # If F took a different number of args, reject. - if len(callee.args) != len(self.args): - raise RuntimeError('Redeclaration of a function with different number ' - 'of args.') - - # Set names for all arguments and add them to the variables symbol table. - for arg, arg_name in zip(function.args, self.args): - arg.name = arg_name - # Add arguments to variable symbol table. - g_named_values[arg_name] = arg - - return function - -This class represents a function definition itself. -=================================================== - -class FunctionNode(object): - -def **init**\ (self, prototype, body): self.prototype = prototype -self.body = body - -def CodeGen(self): # Clear scope. g\_named\_values.clear() - -:: - - # Create a function object. - function = self.prototype.CodeGen() - - # Create a new basic block to start insertion into. - block = function.append_basic_block('entry') - global g_llvm_builder - g_llvm_builder = Builder.new(block) - - # Finish off the function. - try: - return_value = self.body.CodeGen() - g_llvm_builder.ret(return_value) - - # Validate the generated code, checking for consistency. - function.verify() - - # Optimize the function. - g_llvm_pass_manager.run(function) - except: - function.delete() - raise - - return function - -Parser ------- - -class Parser(object): - -def **init**\ (self, tokens, binop\_precedence): self.tokens = tokens -self.binop\_precedence = binop\_precedence self.Next() - -# Provide a simple token buffer. Parser.current is the current token the -# parser is looking at. Parser.Next() reads another token from the lexer -and # updates Parser.current with its results. def Next(self): -self.current = self.tokens.next() - -# Gets the precedence of the current token, or -1 if the token is not a -binary # operator. def GetCurrentTokenPrecedence(self): if -isinstance(self.current, CharacterToken): return -self.binop\_precedence.get(self.current.char, -1) else: return -1 - -# identifierexpr ::= identifier \| identifier '(' expression\* ')' def -ParseIdentifierExpr(self): identifier\_name = self.current.name -self.Next() # eat identifier. - -:: - - if self.current != CharacterToken('('): # Simple variable reference. - return VariableExpressionNode(identifier_name) - - # Call. - self.Next() # eat '('. - args = [] - if self.current != CharacterToken(')'): - while True: - args.append(self.ParseExpression()) - if self.current == CharacterToken(')'): - break - elif self.current != CharacterToken(','): - raise RuntimeError('Expected ")" or "," in argument list.') - self.Next() - - self.Next() # eat ')'. - return CallExpressionNode(identifier_name, args) - -# numberexpr ::= number def ParseNumberExpr(self): result = -NumberExpressionNode(self.current.value) self.Next() # consume the -number. return result - -# parenexpr ::= '(' expression ')' def ParseParenExpr(self): self.Next() -# eat '('. - -:: - - contents = self.ParseExpression() - - if self.current != CharacterToken(')'): - raise RuntimeError('Expected ")".') - self.Next() # eat ')'. - - return contents - -# primary ::= identifierexpr \| numberexpr \| parenexpr def -ParsePrimary(self): if isinstance(self.current, IdentifierToken): return -self.ParseIdentifierExpr() elif isinstance(self.current, NumberToken): -return self.ParseNumberExpr() elif self.current == CharacterToken('('): -return self.ParseParenExpr() else: raise RuntimeError('Unknown token -when expecting an expression.') - -# binoprhs ::= (operator primary)\* def ParseBinOpRHS(self, left, -left\_precedence): # If this is a binary operator, find its precedence. -while True: precedence = self.GetCurrentTokenPrecedence() - -:: - - # If this is a binary operator that binds at least as tightly as the - # current one, consume it; otherwise we are done. - if precedence < left_precedence: - return left - - binary_operator = self.current.char - self.Next() # eat the operator. - - # Parse the primary expression after the binary operator. - right = self.ParsePrimary() - - # If binary_operator binds less tightly with right than the operator after - # right, let the pending operator take right as its left. - next_precedence = self.GetCurrentTokenPrecedence() - if precedence < next_precedence: - right = self.ParseBinOpRHS(right, precedence + 1) - - # Merge left/right. - left = BinaryOperatorExpressionNode(binary_operator, left, right) - -# expression ::= primary binoprhs def ParseExpression(self): left = -self.ParsePrimary() return self.ParseBinOpRHS(left, 0) - -# prototype ::= id '(' id\* ')' def ParsePrototype(self): if not -isinstance(self.current, IdentifierToken): raise RuntimeError('Expected -function name in prototype.') - -:: - - function_name = self.current.name - self.Next() # eat function name. - - if self.current != CharacterToken('('): - raise RuntimeError('Expected "(" in prototype.') - self.Next() # eat '('. - - arg_names = [] - while isinstance(self.current, IdentifierToken): - arg_names.append(self.current.name) - self.Next() - - if self.current != CharacterToken(')'): - raise RuntimeError('Expected ")" in prototype.') - - # Success. - self.Next() # eat ')'. - - return PrototypeNode(function_name, arg_names) - -# definition ::= 'def' prototype expression def ParseDefinition(self): -self.Next() # eat def. proto = self.ParsePrototype() body = -self.ParseExpression() return FunctionNode(proto, body) - -# toplevelexpr ::= expression def ParseTopLevelExpr(self): proto = -PrototypeNode('', []) return FunctionNode(proto, self.ParseExpression()) - -# external ::= 'extern' prototype def ParseExtern(self): self.Next() # -eat extern. return self.ParsePrototype() - -# Top-Level parsing def HandleDefinition(self): -self.Handle(self.ParseDefinition, 'Read a function definition:') - -def HandleExtern(self): self.Handle(self.ParseExtern, 'Read an extern:') - -def HandleTopLevelExpression(self): try: function = -self.ParseTopLevelExpr().CodeGen() result = -g\_llvm\_executor.run\_function(function, []) print 'Evaluated to:', -result.as\_real(Type.double()) except Exception, e: print 'Error:', e -try: self.Next() # Skip for error recovery. except: pass - -def Handle(self, function, message): try: print message, -function().CodeGen() except Exception, e: print 'Error:', e try: -self.Next() # Skip for error recovery. except: pass - -Main driver code. ------------------ - -def main(): # Set up the optimizer pipeline. Start with registering info -about how the # target lays out data structures. -g\_llvm\_pass\_manager.add(g\_llvm\_executor.target\_data) # Do simple -"peephole" optimizations and bit-twiddling optzns. -g\_llvm\_pass\_manager.add(PASS\_INSTRUCTION\_COMBINING) # Reassociate -expressions. g\_llvm\_pass\_manager.add(PASS\_REASSOCIATE) # Eliminate -Common SubExpressions. g\_llvm\_pass\_manager.add(PASS\_GVN) # Simplify -the control flow graph (deleting unreachable blocks, etc). -g\_llvm\_pass\_manager.add(PASS\_CFG\_SIMPLIFICATION) - -g\_llvm\_pass\_manager.initialize() - -# Install standard binary operators. # 1 is lowest possible precedence. -40 is the highest. operator\_precedence = { '<': 10, '+': 20, '-': 20, -'\*': 40 } - -# Run the main "interpreter loop". while True: print 'ready>', try: raw -= raw\_input() except KeyboardInterrupt: break - -:: - - parser = Parser(Tokenize(raw), operator_precedence) - while True: - # top ::= definition | external | expression | EOF - if isinstance(parser.current, EOFToken): - break - if isinstance(parser.current, DefToken): - parser.HandleDefinition() - elif isinstance(parser.current, ExternToken): - parser.HandleExtern() - else: - parser.HandleTopLevelExpression() - -# Print out all of the generated code. print '', g\_llvm\_module - -if **name** == '**main**\ ': main() {% endhighlight %} - --------------- - -**`Next: Extending the language: control flow `_** +.. code-block:: python + + #!/usr/bin/env python + + import re from llvm.core import Module, Constant, Type, Function, + Builder, FCMP_ULT from llvm.ee import ExecutionEngine, TargetData from + llvm.passes import FunctionPassManager from llvm.passes import + (PASS_INSTRUCTION_COMBINING, PASS_REASSOCIATE, PASS_GVN, + PASS_CFG_SIMPLIFICATION) + + Globals + ------- + + # The LLVM module, which holds all the IR code. + g_llvm_module = Module.new('my cool jit') + + # The LLVM instruction builder. Created whenever a new function is entered. + g_llvm_builder = None + + # A dictionary that keeps track of which values are defined in the current scope + # and what their LLVM representation is. + g_named_values = {} + + # The function optimization passes manager. + g_llvm_pass_manager = FunctionPassManager.new(g_llvm_module) + + # The LLVM execution engine. + g_llvm_executor = ExecutionEngine.new(g_llvm_module) + + Lexer + ----- + + # The lexer yields one of these types for each token. + class EOFToken(object): pass + + class DefToken(object): pass + + class ExternToken(object): pass + + class IdentifierToken(object): def **init**\ (self, name): self.name = + name + + class NumberToken(object): def **init**\ (self, value): self.value = + value + + class CharacterToken(object): def **init**\ (self, char): self.char = + char def **eq**\ (self, other): return isinstance(other, CharacterToken) + and self.char == other.char def **ne**\ (self, other): return not self + == other + + # Regular expressions that tokens and comments of our language. + REGEX_NUMBER = re.compile('[0-9]+(?:.[0-9]+)?') REGEX_IDENTIFIER = + re.compile('[a-zA-Z][a-zA-Z0-9]\ *') REGEX_COMMENT = re.compile('#.*') + + def Tokenize(string): while string: # Skip whitespace. if + string[0].isspace(): string = string[1:] continue + + :: + + # Run regexes. + comment_match = REGEX_COMMENT.match(string) + number_match = REGEX_NUMBER.match(string) + identifier_match = REGEX_IDENTIFIER.match(string) + + # Check if any of the regexes matched and yield the appropriate result. + if comment_match: + comment = comment_match.group(0) + string = string[len(comment):] + elif number_match: + number = number_match.group(0) + yield NumberToken(float(number)) + string = string[len(number):] + elif identifier_match: + identifier = identifier_match.group(0) + # Check if we matched a keyword. + if identifier == 'def': + yield DefToken() + elif identifier == 'extern': + yield ExternToken() + else: + yield IdentifierToken(identifier) + string = string[len(identifier):] + else: + # Yield the ASCII value of the unknown character. + yield CharacterToken(string[0]) + string = string[1:] + + yield EOFToken() + + Abstract Syntax Tree (aka Parse Tree) + ------------------------------------- + + # Base class for all expression nodes. + class ExpressionNode(object): pass + + # Expression class for numeric literals like "1.0". + class NumberExpressionNode(ExpressionNode): + + def **init**\ (self, value): self.value = value + + def CodeGen(self): return Constant.real(Type.double(), self.value) + + # Expression class for referencing a variable, like "a". + class VariableExpressionNode(ExpressionNode): + + def **init**\ (self, name): self.name = name + + def CodeGen(self): if self.name in g_named_values: return + g_named_values[self.name] else: raise RuntimeError('Unknown variable + name: ' + self.name) + + # Expression class for a binary operator. + class BinaryOperatorExpressionNode(ExpressionNode): + + def **init**\ (self, operator, left, right): self.operator = operator + self.left = left self.right = right + + def CodeGen(self): left = self.left.CodeGen() right = + self.right.CodeGen() + + :: + + if self.operator == '+': + return g_llvm_builder.fadd(left, right, 'addtmp') + elif self.operator == '-': + return g_llvm_builder.fsub(left, right, 'subtmp') + elif self.operator == '*': + return g_llvm_builder.fmul(left, right, 'multmp') + elif self.operator == '<': + result = g_llvm_builder.fcmp(FCMP_ULT, left, right, 'cmptmp') + # Convert bool 0 or 1 to double 0.0 or 1.0. + return g_llvm_builder.uitofp(result, Type.double(), 'booltmp') + else: + raise RuntimeError('Unknown binary operator.') + + # Expression class for function calls. + class CallExpressionNode(ExpressionNode): + + def **init**\ (self, callee, args): self.callee = callee self.args = + args + + def CodeGen(self): # Look up the name in the global module table. callee + = g_llvm_module.get_function_named(self.callee) + + :: + + # Check for argument mismatch error. + if len(callee.args) != len(self.args): + raise RuntimeError('Incorrect number of arguments passed.') + + arg_values = [i.CodeGen() for i in self.args] + + return g_llvm_builder.call(callee, arg_values, 'calltmp') + + # This class represents the "prototype" for a function, which captures its name, + # and its argument names (thus implicitly the number of arguments the function + # takes). + class PrototypeNode(object): + + def **init**\ (self, name, args): self.name = name self.args = args + + def CodeGen(self): # Make the function type, eg. double(double,double). + funct_type = Type.function( Type.double(), [Type.double()] \* + len(self.args), False) + + :: + + function = Function.new(g_llvm_module, funct_type, self.name) + + # If the name conflicted, there was already something with the same name. + # If it has a body, don't allow redefinition or reextern. + if function.name != self.name: + function.delete() + function = g_llvm_module.get_function_named(self.name) + + # If the function already has a body, reject this. + if not function.is_declaration: + raise RuntimeError('Redefinition of function.') + + # If F took a different number of args, reject. + if len(callee.args) != len(self.args): + raise RuntimeError('Redeclaration of a function with different number ' + 'of args.') + + # Set names for all arguments and add them to the variables symbol table. + for arg, arg_name in zip(function.args, self.args): + arg.name = arg_name + # Add arguments to variable symbol table. + g_named_values[arg_name] = arg + + return function + + # This class represents a function definition itself. + class FunctionNode(object): + + def **init**\ (self, prototype, body): self.prototype = prototype + self.body = body + + def CodeGen(self): # Clear scope. g_named_values.clear() + + :: + + # Create a function object. + function = self.prototype.CodeGen() + + # Create a new basic block to start insertion into. + block = function.append_basic_block('entry') + global g_llvm_builder + g_llvm_builder = Builder.new(block) + + # Finish off the function. + try: + return_value = self.body.CodeGen() + g_llvm_builder.ret(return_value) + + # Validate the generated code, checking for consistency. + function.verify() + + # Optimize the function. + g_llvm_pass_manager.run(function) + except: + function.delete() + raise + + return function + + Parser + ------ + + class Parser(object): + + def **init**\ (self, tokens, binop_precedence): self.tokens = tokens + self.binop_precedence = binop_precedence self.Next() + + # Provide a simple token buffer. Parser.current is the current token the + # parser is looking at. Parser.Next() reads another token from the lexer + and # updates Parser.current with its results. def Next(self): + self.current = self.tokens.next() + + # Gets the precedence of the current token, or -1 if the token is not a + binary # operator. def GetCurrentTokenPrecedence(self): if + isinstance(self.current, CharacterToken): return + self.binop_precedence.get(self.current.char, -1) else: return -1 + + # identifierexpr ::= identifier \| identifier '(' expression\* ')' def + ParseIdentifierExpr(self): identifier_name = self.current.name + self.Next() # eat identifier. + + :: + + if self.current != CharacterToken('('): # Simple variable reference. + return VariableExpressionNode(identifier_name) + + # Call. + self.Next() # eat '('. + args = [] + if self.current != CharacterToken(')'): + while True: + args.append(self.ParseExpression()) + if self.current == CharacterToken(')'): + break + elif self.current != CharacterToken(','): + raise RuntimeError('Expected ")" or "," in argument list.') + self.Next() + + self.Next() # eat ')'. + return CallExpressionNode(identifier_name, args) + + # numberexpr ::= number def ParseNumberExpr(self): result = + NumberExpressionNode(self.current.value) self.Next() # consume the + number. return result + + # parenexpr ::= '(' expression ')' def ParseParenExpr(self): self.Next() + # eat '('. + + :: + + contents = self.ParseExpression() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")".') + self.Next() # eat ')'. + + return contents + + # primary ::= identifierexpr \| numberexpr \| parenexpr def + ParsePrimary(self): if isinstance(self.current, IdentifierToken): return + self.ParseIdentifierExpr() elif isinstance(self.current, NumberToken): + return self.ParseNumberExpr() elif self.current == CharacterToken('('): + return self.ParseParenExpr() else: raise RuntimeError('Unknown token + when expecting an expression.') + + # binoprhs ::= (operator primary)\* def ParseBinOpRHS(self, left, + left_precedence): # If this is a binary operator, find its precedence. + while True: precedence = self.GetCurrentTokenPrecedence() + + :: + + # If this is a binary operator that binds at least as tightly as the + # current one, consume it; otherwise we are done. + if precedence < left_precedence: + return left + + binary_operator = self.current.char + self.Next() # eat the operator. + + # Parse the primary expression after the binary operator. + right = self.ParsePrimary() + + # If binary_operator binds less tightly with right than the operator after + # right, let the pending operator take right as its left. + next_precedence = self.GetCurrentTokenPrecedence() + if precedence < next_precedence: + right = self.ParseBinOpRHS(right, precedence + 1) + + # Merge left/right. + left = BinaryOperatorExpressionNode(binary_operator, left, right) + + # expression ::= primary binoprhs def ParseExpression(self): left = + self.ParsePrimary() return self.ParseBinOpRHS(left, 0) + + # prototype ::= id '(' id\* ')' def ParsePrototype(self): if not + isinstance(self.current, IdentifierToken): raise RuntimeError('Expected + function name in prototype.') + + :: + + function_name = self.current.name + self.Next() # eat function name. + + if self.current != CharacterToken('('): + raise RuntimeError('Expected "(" in prototype.') + self.Next() # eat '('. + + arg_names = [] + while isinstance(self.current, IdentifierToken): + arg_names.append(self.current.name) + self.Next() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")" in prototype.') + + # Success. + self.Next() # eat ')'. + + return PrototypeNode(function_name, arg_names) + + # definition ::= 'def' prototype expression def ParseDefinition(self): + self.Next() # eat def. proto = self.ParsePrototype() body = + self.ParseExpression() return FunctionNode(proto, body) + + # toplevelexpr ::= expression def ParseTopLevelExpr(self): proto = + PrototypeNode('', []) return FunctionNode(proto, self.ParseExpression()) + + # external ::= 'extern' prototype def ParseExtern(self): self.Next() # + eat extern. return self.ParsePrototype() + + # Top-Level parsing def HandleDefinition(self): + self.Handle(self.ParseDefinition, 'Read a function definition:') + + def HandleExtern(self): self.Handle(self.ParseExtern, 'Read an extern:') + + def HandleTopLevelExpression(self): try: function = + self.ParseTopLevelExpr().CodeGen() result = + g_llvm_executor.run_function(function, []) print 'Evaluated to:', + result.as_real(Type.double()) except Exception, e: print 'Error:', e + try: self.Next() # Skip for error recovery. except: pass + + def Handle(self, function, message): try: print message, + function().CodeGen() except Exception, e: print 'Error:', e try: + self.Next() # Skip for error recovery. except: pass + + Main driver code. + ----------------- + + def main(): # Set up the optimizer pipeline. Start with registering info + about how the # target lays out data structures. + g_llvm_pass_manager.add(g_llvm_executor.target_data) # Do simple + "peephole" optimizations and bit-twiddling optzns. + g_llvm_pass_manager.add(PASS_INSTRUCTION_COMBINING) # Reassociate + expressions. g_llvm_pass_manager.add(PASS_REASSOCIATE) # Eliminate + Common SubExpressions. g_llvm_pass_manager.add(PASS_GVN) # Simplify + the control flow graph (deleting unreachable blocks, etc). + g_llvm_pass_manager.add(PASS_CFG_SIMPLIFICATION) + + g_llvm_pass_manager.initialize() + + # Install standard binary operators. # 1 is lowest possible precedence. + 40 is the highest. operator_precedence = { '<': 10, '+': 20, '-': 20, + '\*': 40 } + + # Run the main "interpreter loop". while True: print 'ready>', try: raw + = raw_input() except KeyboardInterrupt: break + + :: + + parser = Parser(Tokenize(raw), operator_precedence) + while True: + # top ::= definition | external | expression | EOF + if isinstance(parser.current, EOFToken): + break + if isinstance(parser.current, DefToken): + parser.HandleDefinition() + elif isinstance(parser.current, ExternToken): + parser.HandleExtern() + else: + parser.HandleTopLevelExpression() + + # Print out all of the generated code. print '', g_llvm_module + + if **name** == '**main**\ ': main() diff --git a/docs/source/doc/kaleidoscope/PythonLangImpl5.rst b/docs/source/doc/kaleidoscope/PythonLangImpl5.rst index e66944e..d4d01fa 100644 --- a/docs/source/doc/kaleidoscope/PythonLangImpl5.rst +++ b/docs/source/doc/kaleidoscope/PythonLangImpl5.rst @@ -34,8 +34,13 @@ Before we get going on "how" we add this extension, lets talk about "what" we want. The basic idea is that we want to be able to write this sort of thing: -{% highlight python %} def fib(x) if x < 3 then 1 else fib(x-1) + -fib(x-2) {% endhighlight %} + +.. code-block:: python + + def fib(x) if x < 3 then 1 else fib(x-1) + + fib(x-2) + + In Kaleidoscope, every construct is an expression: there are no statements. As such, the if/then/else expression needs to return a value @@ -61,31 +66,46 @@ Lexer Extensions for If/Then/Else ## {#iflexer} The lexer extensions are straightforward. First we add new token classes for the relevant tokens: -{% highlight python %} class IfToken(object): pass class -ThenToken(object): pass class ElseToken(object): pass {% endhighlight %} + +.. code-block:: python + + class IfToken(object): pass class + ThenToken(object): pass class ElseToken(object): pass + + Once we have that, we recognize the new keywords in the lexer. This is pretty simple stuff: -{% highlight python %} ... if identifier == 'def': yield DefToken() elif -identifier == 'extern': yield ExternToken() elif identifier == 'if': -yield IfToken() elif identifier == 'then': yield ThenToken() elif -identifier == 'else': yield ElseToken() else: yield -IdentifierToken(identifier) {% endhighlight %} + +.. code-block:: python + + ... if identifier == 'def': yield DefToken() elif + identifier == 'extern': yield ExternToken() elif identifier == 'if': + yield IfToken() elif identifier == 'then': yield ThenToken() elif + identifier == 'else': yield ElseToken() else: yield + IdentifierToken(identifier) + + AST Extensions for If/Then/Else ## {#ifast} ------------------------------------------- To represent the new expression we add a new AST node for it: -{% highlight python %} # Expression class for if/then/else. class -IfExpressionNode(ExpressionNode): -def **init**\ (self, condition, then\_branch, else\_branch): -self.condition = condition self.then\_branch = then\_branch -self.else\_branch = else\_branch +.. code-block:: python + + # Expression class for if/then/else. class + IfExpressionNode(ExpressionNode): + + def **init**\ (self, condition, then_branch, else_branch): + self.condition = condition self.then_branch = then_branch + self.else_branch = else_branch + + def CodeGen(self): ... + -def CodeGen(self): ... {% endhighlight %} The AST node just has pointers to the various subexpressions. @@ -96,39 +116,49 @@ Now that we have the relevant tokens coming from the lexer and we have the AST node to build, our parsing logic is relatively straightforward. First we define a new parsing function: -{% highlight python %} # ifexpr ::= 'if' expression 'then' expression -'else' expression def ParseIfExpr(self): self.Next() # eat the if. -:: +.. code-block:: python - # condition. - condition = self.ParseExpression() + # ifexpr ::= 'if' expression 'then' expression + 'else' expression def ParseIfExpr(self): self.Next() # eat the if. + + :: + + # condition. + condition = self.ParseExpression() + + if not isinstance(self.current, ThenToken): + raise RuntimeError('Expected "then".') + self.Next() # eat the then. + + then_branch = self.ParseExpression() + + if not isinstance(self.current, ElseToken): + raise RuntimeError('Expected "else".') + self.Next() # eat the else. + + else_branch = self.ParseExpression() + + return IfExpressionNode(condition, then_branch, else_branch) + + - if not isinstance(self.current, ThenToken): - raise RuntimeError('Expected "then".') - self.Next() # eat the then. - then_branch = self.ParseExpression() - - if not isinstance(self.current, ElseToken): - raise RuntimeError('Expected "else".') - self.Next() # eat the else. - - else_branch = self.ParseExpression() - - return IfExpressionNode(condition, then_branch, else_branch) - -{% endhighlight %} Next we hook it up as a primary expression: -{% highlight python %} def ParsePrimary(self): if -isinstance(self.current, IdentifierToken): return -self.ParseIdentifierExpr() elif isinstance(self.current, NumberToken): -return self.ParseNumberExpr(); elif isinstance(self.current, IfToken): -return self.ParseIfExpr() elif self.current == CharacterToken('('): -return self.ParseParenExpr() else: raise RuntimeError('Unknown token -when expecting an expression.') {% endhighlight %} + +.. code-block:: python + + def ParsePrimary(self): if + isinstance(self.current, IdentifierToken): return + self.ParseIdentifierExpr() elif isinstance(self.current, NumberToken): + return self.ParseNumberExpr(); elif isinstance(self.current, IfToken): + return self.ParseIfExpr() elif self.current == CharacterToken('('): + return self.ParseParenExpr() else: raise RuntimeError('Unknown token + when expecting an expression.') + + LLVM IR for If/Then/Else ## {#ifir} ----------------------------------- @@ -142,19 +172,29 @@ described in previous chapters. To motivate the code we want to produce, lets take a look at a simple example. Consider: -{% highlight python %} extern foo(); extern bar(); def baz(x) if x then -foo() else bar(); {% endhighlight %} + +.. code-block:: python + + extern foo(); extern bar(); def baz(x) if x then + foo() else bar(); + + If you disable optimizations, the code you'll (soon) get from Kaleidoscope looks something like this: -{% highlight llvm %} declare double @foo() declare double @bar() define -double @baz(double %x) { entry: %ifcond = fcmp one double %x, -0.000000e+00 br i1 %ifcond, label %then, label %else then: ; preds = -%entry %calltmp1 = call double @bar() else: ; preds = %entry %calltmp1 = -call double @bar() br label %ifcont ifcont: ; preds = %else, %then -%iftmp = phi double [ %calltmp, %then ], [ %calltmp1, %else ] ret double -%iftmp } {% endhighlight %} + +.. code-block:: llvm + + declare double @foo() declare double @bar() define + double @baz(double %x) { entry: %ifcond = fcmp one double %x, + 0.000000e+00 br i1 %ifcond, label %then, label %else then: ; preds = + %entry %calltmp1 = call double @bar() else: ; preds = %entry %calltmp1 = + call double @bar() br label %ifcont ifcont: ; preds = %else, %then + %iftmp = phi double [ %calltmp, %then ], [ %calltmp1, %else ] ret double + %iftmp } + + To visualize the control flow graph, you can use a nifty feature of the LLVM `opt `_ tool. If you put this LLVM @@ -226,34 +266,44 @@ Code Generation for If/Then/Else ## {#ifcodegen} In order to generate code for this, we implement the ``Codegen`` method for ``IfExpressionNode``: -{% highlight python %} def CodeGen(self): condition = -self.condition.CodeGen() -:: +.. code-block:: python + + def CodeGen(self): condition = + self.condition.CodeGen() + + :: + + # Convert condition to a bool by comparing equal to 0.0. + condition_bool = g_llvm_builder.fcmp( + FCMP_ONE, condition, Constant.real(Type.double(), 0), 'ifcond') + + - # Convert condition to a bool by comparing equal to 0.0. - condition_bool = g_llvm_builder.fcmp( - FCMP_ONE, condition, Constant.real(Type.double(), 0), 'ifcond') -{% endhighlight %} This code is straightforward and similar to what we saw before. We emit the expression for the condition, then compare that value to zero to get a truth value as a 1-bit (bool) value. -{% highlight python %} function = g\_llvm\_builder.basic\_block.function -:: +.. code-block:: python - # Create blocks for the then and else cases. Insert the 'then' block at the - # end of the function. - then_block = function.append_basic_block('then') - else_block = function.append_basic_block('else') - merge_block = function.append_basic_block('ifcond') + function = g_llvm_builder.basic_block.function + + :: + + # Create blocks for the then and else cases. Insert the 'then' block at the + # end of the function. + then_block = function.append_basic_block('then') + else_block = function.append_basic_block('else') + merge_block = function.append_basic_block('ifcond') + + g_llvm_builder.cbranch(condition_bool, then_block, else_block) + + - g_llvm_builder.cbranch(condition_bool, then_block, else_block) -{% endhighlight %} This code creates the basic blocks that are related to the if/then/else statement, and correspond directly to the blocks in the example above. @@ -268,17 +318,22 @@ can emit the conditional branch that chooses between them. Note that creating new blocks does not implicitly affect the Builder, so it is still inserting into the block that the condition went into. -{% highlight python %} # Emit then value. -g\_llvm\_builder.position\_at\_end(then\_block) then\_value = -self.then\_branch.CodeGen() g\_llvm\_builder.branch(merge\_block) -:: +.. code-block:: python + + # Emit then value. + g_llvm_builder.position_at_end(then_block) then_value = + self.then_branch.CodeGen() g_llvm_builder.branch(merge_block) + + :: + + # Codegen of 'Then' can change the current block; update then_block for the + # PHI node. + then_block = g_llvm_builder.basic_block + + - # Codegen of 'Then' can change the current block; update then_block for the - # PHI node. - then_block = g_llvm_builder.basic_block -{% endhighlight %} After the conditional branch is inserted, we move the builder to start inserting into the "then" block. Strictly speaking, this call moves the @@ -310,17 +365,22 @@ expression. Because calling Codegen recursively could arbitrarily change the notion of the current block, we are required to get an up-to-date value for code that will set up the Phi node. -{% highlight python %} # Emit else block. -g\_llvm\_builder.position\_at\_end(else\_block) else\_value = -self.else\_branch.CodeGen() g\_llvm\_builder.branch(merge\_block) -:: +.. code-block:: python + + # Emit else block. + g_llvm_builder.position_at_end(else_block) else_value = + self.else_branch.CodeGen() g_llvm_builder.branch(merge_block) + + :: + + # Codegen of 'Else' can change the current block, update else_block for the + # PHI node. + else_block = g_llvm_builder.basic_block + + - # Codegen of 'Else' can change the current block, update else_block for the - # PHI node. - else_block = g_llvm_builder.basic_block -{% endhighlight %} Code generation for the 'else' block is basically identical to codegen for the 'then' block. The only significant difference is the first line, @@ -329,17 +389,22 @@ which adds the 'else' block to the function. Recall previously that the 'then' and 'else' blocks are emitted, we can finish up with the merge code: -{% highlight python %} # Emit merge block. -g\_llvm\_builder.position\_at\_end(merge\_block) phi = -g\_llvm\_builder.phi(Type.double(), 'iftmp') -phi.add\_incoming(then\_value, then\_block) -phi.add\_incoming(else\_value, else\_block) -:: +.. code-block:: python + + # Emit merge block. + g_llvm_builder.position_at_end(merge_block) phi = + g_llvm_builder.phi(Type.double(), 'iftmp') + phi.add_incoming(then_value, then_block) + phi.add_incoming(else_value, else_block) + + :: + + return phi + + - return phi -{% endhighlight %} The first line changes the insertion point so that newly created code will go into the "merge" block. Once that is done, we need to create the @@ -365,15 +430,20 @@ Now that we know how to add basic control flow constructs to the language, we have the tools to add more powerful things. Lets add something more aggressive, a 'for' expression: -{% highlight python %} extern putchard(char) def printstar(n) for i = 1, -i < n, 1.0 in putchard(42) # ascii 42 = '\*' -:: +.. code-block:: python + + extern putchard(char) def printstar(n) for i = 1, + i < n, 1.0 in putchard(42) # ascii 42 = '\*' + + :: + + # print 100 '*' characters + printstar(100) + + - # print 100 '*' characters - printstar(100) -{% endhighlight %} This expression defines a new variable (``i`` in this case) which iterates from a starting value, while the condition (``i < n`` in this @@ -391,29 +461,34 @@ Lexer Extensions for the 'for' Loop ## {#forlexer} The lexer extensions are the same sort of thing as for if/then/else: -{% highlight python %} ... -class ThenToken(object): pass class ElseToken(object): pass class -ForToken(object): pass class InToken(object): pass +.. code-block:: python -... + ... + + class ThenToken(object): pass class ElseToken(object): pass class + ForToken(object): pass class InToken(object): pass + + ... + + def Tokenize(string): + + :: + + ... + + elif identifier == 'else': + yield ElseToken() + elif identifier == 'for': + yield ForToken() + elif identifier == 'in': + yield InToken() + else: + yield IdentifierToken(identifier) + + -def Tokenize(string): -:: - - ... - - elif identifier == 'else': - yield ElseToken() - elif identifier == 'for': - yield ForToken() - elif identifier == 'in': - yield InToken() - else: - yield IdentifierToken(identifier) - -{% endhighlight %} AST Extensions for the 'for' Loop ## {#forast} ---------------------------------------------- @@ -421,14 +496,19 @@ AST Extensions for the 'for' Loop ## {#forast} The AST node is just as simple. It basically boils down to capturing the variable name and the constituent expressions in the node. -{% highlight python %} # Expression class for for/in. class -ForExpressionNode(ExpressionNode): -def **init**\ (self, loop\_variable, start, end, step, body): -self.loop\_variable = loop\_variable self.start = start self.end = end -self.step = step self.body = body +.. code-block:: python + + # Expression class for for/in. class + ForExpressionNode(ExpressionNode): + + def **init**\ (self, loop_variable, start, end, step, body): + self.loop_variable = loop_variable self.start = start self.end = end + self.step = step self.body = body + + def CodeGen(self): ... + -def CodeGen(self): ... {% endhighlight %} Parser Extensions for the 'for' Loop ## {#forparser} ---------------------------------------------------- @@ -438,46 +518,51 @@ is handling of the optional step value. The parser code handles it by checking to see if the second comma is present. If not, it sets the step value to null in the AST node: -{% highlight python %} # forexpr ::= 'for' identifier '=' expr ',' expr -(',' expr)? 'in' expression def ParseForExpr(self): self.Next() # eat -the for. -:: +.. code-block:: python - if not isinstance(self.current, IdentifierToken): - raise RuntimeError('Expected identifier after for.') + # forexpr ::= 'for' identifier '=' expr ',' expr + (',' expr)? 'in' expression def ParseForExpr(self): self.Next() # eat + the for. + + :: + + if not isinstance(self.current, IdentifierToken): + raise RuntimeError('Expected identifier after for.') + + loop_variable = self.current.name + self.Next() # eat the identifier. + + if self.current != CharacterToken('='): + raise RuntimeError('Expected "=" after for variable.') + self.Next() # eat the '='. + + start = self.ParseExpression() + + if self.current != CharacterToken(','): + raise RuntimeError('Expected "," after for start value.') + self.Next() # eat the ','. + + end = self.ParseExpression() + + # The step value is optional. + if self.current == CharacterToken(','): + self.Next() # eat the ','. + step = self.ParseExpression() + else: + step = None + + if not isinstance(self.current, InToken): + raise RuntimeError('Expected "in" after for variable specification.') + self.Next() # eat 'in'. + + body = self.ParseExpression() + + return ForExpressionNode(loop_variable, start, end, step, body) + + - loop_variable = self.current.name - self.Next() # eat the identifier. - if self.current != CharacterToken('='): - raise RuntimeError('Expected "=" after for variable.') - self.Next() # eat the '='. - - start = self.ParseExpression() - - if self.current != CharacterToken(','): - raise RuntimeError('Expected "," after for start value.') - self.Next() # eat the ','. - - end = self.ParseExpression() - - # The step value is optional. - if self.current == CharacterToken(','): - self.Next() # eat the ','. - step = self.ParseExpression() - else: - step = None - - if not isinstance(self.current, InToken): - raise RuntimeError('Expected "in" after for variable specification.') - self.Next() # eat 'in'. - - body = self.ParseExpression() - - return ForExpressionNode(loop_variable, start, end, step, body) - -{% endhighlight %} LLVM IR for the 'for' Loop ## {#forir} -------------------------------------- @@ -486,16 +571,21 @@ Now we get to the good part: the LLVM IR we want to generate for this thing. With the simple example above, we get this LLVM IR (note that this dump is generated with optimizations disabled for clarity): -{% highlight llvm %} declare double @putchard(double) define double -@printstar(double %n) { entry: ; initial value = 1.0 (inlined into phi) -br label %loop loop: ; preds = %loop, %entry %i = phi double [ -1.000000e+00, %entry ], [ %nextvar, %loop ] ; body %calltmp = call -double @putchard(double 4.200000e+01) ; increment %nextvar = fadd double -%i, 1.000000e+00 ; termination test %cmptmp = fcmp ult double %i, %n -%booltmp = uitofp i1 %cmptmp to double %loopcond = fcmp one double -%booltmp, 0.000000e+00 br i1 %loopcond, label %loop, label %afterloop -afterloop: ; preds = %loop ; loop always returns 0.0 ret double -0.000000e+00 } {% endhighlight %} + +.. code-block:: llvm + + declare double @putchard(double) define double + @printstar(double %n) { entry: ; initial value = 1.0 (inlined into phi) + br label %loop loop: ; preds = %loop, %entry %i = phi double [ + 1.000000e+00, %entry ], [ %nextvar, %loop ] ; body %calltmp = call + double @putchard(double 4.200000e+01) ; increment %nextvar = fadd double + %i, 1.000000e+00 ; termination test %cmptmp = fcmp ult double %i, %n + %booltmp = uitofp i1 %cmptmp to double %loopcond = fcmp one double + %booltmp, 0.000000e+00 br i1 %loopcond, label %loop, label %afterloop + afterloop: ; preds = %loop ; loop always returns 0.0 ret double + 0.000000e+00 } + + This loop contains all the same constructs we saw before: a phi node, several expressions, and some basic blocks. Lets see how this fits @@ -507,28 +597,33 @@ Code Generation for the 'for' Loop ## {#forcodegen} The first part of Codegen is very simple: we just output the start expression for the loop value: -{% highlight python %} def CodeGen(self): # Emit the start code first, -without 'variable' in scope. start\_value = self.start.CodeGen() {% -endhighlight %} -With this out of the way, the next step is to set up the LLVM basic -block for the start of the loop body. In the case above, the whole loop -body is one block, but remember that the body code itself could consist -of multiple blocks (e.g. if it contains an if/then/else or a for/in -expression). +.. code-block:: python -{% highlight python %} # Make the new basic block for the loop header, -inserting after current # block. function = -g\_llvm\_builder.basic\_block.function pre\_header\_block = -g\_llvm\_builder.basic\_block loop\_block = -function.append\_basic\_block('loop') + def CodeGen(self): # Emit the start code first, + without 'variable' in scope. start_value = self.start.CodeGen() {% + endhighlight %} + + With this out of the way, the next step is to set up the LLVM basic + block for the start of the loop body. In the case above, the whole loop + body is one block, but remember that the body code itself could consist + of multiple blocks (e.g. if it contains an if/then/else or a for/in + expression). + + {% highlight python %} # Make the new basic block for the loop header, + inserting after current # block. function = + g_llvm_builder.basic_block.function pre_header_block = + g_llvm_builder.basic_block loop_block = + function.append_basic_block('loop') + + :: + + # Insert an explicit fallthrough from the current block to the loop_block. + g_llvm_builder.branch(loop_block) + + -:: - # Insert an explicit fallthrough from the current block to the loop_block. - g_llvm_builder.branch(loop_block) - -{% endhighlight %} This code is similar to what we saw for if/then/else. Because we will need it to create the Phi node, we remember the block that falls through @@ -536,16 +631,21 @@ into the loop. Once we have that, we create the actual block that starts the loop and create an unconditional branch for the fall-through between the two blocks. -{% highlight python %} # Start insertion in loop\_block. -g\_llvm\_builder.position\_at\_end(loop\_block); -:: +.. code-block:: python + + # Start insertion in loop_block. + g_llvm_builder.position_at_end(loop_block); + + :: + + # Start the PHI node with an entry for start. + variable_phi = g_llvm_builder.phi(Type.double(), self.loop_variable) + variable_phi.add_incoming(start_value, pre_header_block) + + - # Start the PHI node with an entry for start. - variable_phi = g_llvm_builder.phi(Type.double(), self.loop_variable) - variable_phi.add_incoming(start_value, pre_header_block) -{% endhighlight %} Now that the "pre\_header\_block" for the loop is set up, we switch to emitting code for the loop body. To begin with, we move the insertion @@ -554,19 +654,24 @@ already know the incoming value for the starting value, we add it to the Phi node. Note that the Phi will eventually get a second value for the backedge, but we can't set it up yet (because it doesn't exist!). -{% highlight python %} # Within the loop, the variable is defined equal -to the PHI node. If it # shadows an existing variable, we have to -restore it, so save it now. old\_value = -g\_named\_values.get(self.loop\_variable, None) -g\_named\_values[self.loop\_variable] = variable\_phi -:: +.. code-block:: python + + # Within the loop, the variable is defined equal + to the PHI node. If it # shadows an existing variable, we have to + restore it, so save it now. old_value = + g_named_values.get(self.loop_variable, None) + g_named_values[self.loop_variable] = variable_phi + + :: + + # Emit the body of the loop. This, like any other expr, can change the + # current BB. Note that we ignore the value computed by the body. + self.body.CodeGen() + + - # Emit the body of the loop. This, like any other expr, can change the - # current BB. Note that we ignore the value computed by the body. - self.body.CodeGen() -{% endhighlight %} Now the code starts to get more interesting. Our 'for' loop introduces a new variable to the symbol table. This means that our symbol table can @@ -585,43 +690,58 @@ recursively codegen's the body. This allows the body to use the loop variable: any references to it will naturally find it in the symbol table. -{% highlight python %} # Emit the step value. if self.step: step\_value -= self.step.CodeGen() else: # If not specified, use 1.0. step\_value = -Constant.real(Type.double(), 1) -:: +.. code-block:: python + + # Emit the step value. if self.step: step_value + = self.step.CodeGen() else: # If not specified, use 1.0. step_value = + Constant.real(Type.double(), 1) + + :: + + next_value = g_llvm_builder.fadd(variable_phi, step_value, 'next') + + - next_value = g_llvm_builder.fadd(variable_phi, step_value, 'next') -{% endhighlight %} Now that the body is emitted, we compute the next value of the iteration variable by adding the step value, or 1.0 if it isn't present. ``next_value`` will be the value of the loop variable on the next iteration of the loop. -{% highlight python %} # Compute the end condition and convert it to a -bool by comparing to 0.0. end\_condition = self.end.CodeGen() -end\_condition\_bool = g\_llvm\_builder.fcmp( FCMP\_ONE, end\_condition, -Constant.real(Type.double(), 0), 'loopcond') {% endhighlight %} + +.. code-block:: python + + # Compute the end condition and convert it to a + bool by comparing to 0.0. end_condition = self.end.CodeGen() + end_condition_bool = g_llvm_builder.fcmp( FCMP_ONE, end_condition, + Constant.real(Type.double(), 0), 'loopcond') + + Finally, we evaluate the exit value of the loop, to determine whether the loop should exit. This mirrors the condition evaluation for the if/then/else statement. -{% highlight python %} # Create the "after loop" block and insert it. -loop\_end\_block = g\_llvm\_builder.basic\_block after\_block = -function.append\_basic\_block('afterloop') -:: +.. code-block:: python - # Insert the conditional branch into the end of loop_end_block. - g_llvm_builder.cbranch(end_condition_bool, loop_block, after_block) + # Create the "after loop" block and insert it. + loop_end_block = g_llvm_builder.basic_block after_block = + function.append_basic_block('afterloop') + + :: + + # Insert the conditional branch into the end of loop_end_block. + g_llvm_builder.cbranch(end_condition_bool, loop_block, after_block) + + # Any new code will be inserted in after_block. + g_llvm_builder.position_at_end(after_block) + + - # Any new code will be inserted in after_block. - g_llvm_builder.position_at_end(after_block) -{% endhighlight %} With the code for the body of the loop complete, we just need to finish up the control flow for it. This code remembers the end block (for the @@ -631,21 +751,26 @@ chooses between executing the loop again and exiting the loop. Any future code is emitted in the "afterloop" block, so it sets the insertion position to it. -{% highlight python %} # Add a new entry to the PHI node for the -backedge. variable\_phi.add\_incoming(next\_value, loop\_end\_block) -:: +.. code-block:: python - # Restore the unshadowed variable. - if old_value: - g_named_values[self.loop_variable] = old_value - else: - del g_named_values[self.loop_variable] + # Add a new entry to the PHI node for the + backedge. variable_phi.add_incoming(next_value, loop_end_block) + + :: + + # Restore the unshadowed variable. + if old_value: + g_named_values[self.loop_variable] = old_value + else: + del g_named_values[self.loop_variable] + + # for expr always returns 0.0. + return Constant.real(Type.double(), 0) + + - # for expr always returns 0.0. - return Constant.real(Type.double(), 0) -{% endhighlight %} The final code handles various cleanups: now that we have the "next\_value", we can add the incoming value to the loop PHI node. After @@ -669,658 +794,618 @@ Full Code Listing # {#code} Here is the complete code listing for our running example, enhanced with the if/then/else and for expressions: -{% highlight python %} #!/usr/bin/env python -import re from llvm.core import Module, Constant, Type, Function, -Builder from llvm.ee import ExecutionEngine, TargetData from llvm.passes -import FunctionPassManager - -from llvm.core import FCMP\_ULT, FCMP\_ONE from llvm.passes import -(PASS\_INSTRUCTION\_COMBINING, PASS\_REASSOCIATE, PASS\_GVN, -PASS\_CFG\_SIMPLIFICATION) - -Globals -------- - -The LLVM module, which holds all the IR code. -============================================= - -g\_llvm\_module = Module.new('my cool jit') - -The LLVM instruction builder. Created whenever a new function is entered. -========================================================================= - -g\_llvm\_builder = None - -A dictionary that keeps track of which values are defined in the current scope -============================================================================== - -and what their LLVM representation is. -====================================== - -g\_named\_values = {} - -The function optimization passes manager. -========================================= - -g\_llvm\_pass\_manager = FunctionPassManager.new(g\_llvm\_module) - -The LLVM execution engine. -========================== - -g\_llvm\_executor = ExecutionEngine.new(g\_llvm\_module) - -Lexer ------ - -The lexer yields one of these types for each token. -=================================================== - -class EOFToken(object): pass class DefToken(object): pass class -ExternToken(object): pass class IfToken(object): pass class -ThenToken(object): pass class ElseToken(object): pass class -ForToken(object): pass class InToken(object): pass - -class IdentifierToken(object): def **init**\ (self, name): self.name = -name - -class NumberToken(object): def **init**\ (self, value): self.value = -value - -class CharacterToken(object): def **init**\ (self, char): self.char = -char def **eq**\ (self, other): return isinstance(other, CharacterToken) -and self.char == other.char def **ne**\ (self, other): return not self -== other - -Regular expressions that tokens and comments of our language. -============================================================= - -REGEX\_NUMBER = re.compile('[0-9]+(?:.[0-9]+)?') REGEX\_IDENTIFIER = -re.compile('[a-zA-Z][a-zA-Z0-9]\ *') REGEX\_COMMENT = re.compile('#.*') - -def Tokenize(string): while string: # Skip whitespace. if -string[0].isspace(): string = string[1:] continue - -:: - - # Run regexes. - comment_match = REGEX_COMMENT.match(string) - number_match = REGEX_NUMBER.match(string) - identifier_match = REGEX_IDENTIFIER.match(string) - - # Check if any of the regexes matched and yield the appropriate result. - if comment_match: - comment = comment_match.group(0) - string = string[len(comment):] - elif number_match: - number = number_match.group(0) - yield NumberToken(float(number)) - string = string[len(number):] - elif identifier_match: - identifier = identifier_match.group(0) - # Check if we matched a keyword. - if identifier == 'def': - yield DefToken() - elif identifier == 'extern': - yield ExternToken() - elif identifier == 'if': - yield IfToken() - elif identifier == 'then': - yield ThenToken() - elif identifier == 'else': - yield ElseToken() - elif identifier == 'for': - yield ForToken() - elif identifier == 'in': - yield InToken() - else: - yield IdentifierToken(identifier) - string = string[len(identifier):] - else: - # Yield the ASCII value of the unknown character. - yield CharacterToken(string[0]) - string = string[1:] - -yield EOFToken() - -Abstract Syntax Tree (aka Parse Tree) -------------------------------------- - -Base class for all expression nodes. -==================================== - -class ExpressionNode(object): pass - -Expression class for numeric literals like "1.0". -================================================= - -class NumberExpressionNode(ExpressionNode): - -def **init**\ (self, value): self.value = value - -def CodeGen(self): return Constant.real(Type.double(), self.value) - -Expression class for referencing a variable, like "a". -====================================================== - -class VariableExpressionNode(ExpressionNode): - -def **init**\ (self, name): self.name = name - -def CodeGen(self): if self.name in g\_named\_values: return -g\_named\_values[self.name] else: raise RuntimeError('Unknown variable -name: ' + self.name) - -Expression class for a binary operator. -======================================= - -class BinaryOperatorExpressionNode(ExpressionNode): - -def **init**\ (self, operator, left, right): self.operator = operator -self.left = left self.right = right - -def CodeGen(self): left = self.left.CodeGen() right = -self.right.CodeGen() - -:: - - if self.operator == '+': - return g_llvm_builder.fadd(left, right, 'addtmp') - elif self.operator == '-': - return g_llvm_builder.fsub(left, right, 'subtmp') - elif self.operator == '*': - return g_llvm_builder.fmul(left, right, 'multmp') - elif self.operator == '<': - result = g_llvm_builder.fcmp(FCMP_ULT, left, right, 'cmptmp') - # Convert bool 0 or 1 to double 0.0 or 1.0. - return g_llvm_builder.uitofp(result, Type.double(), 'booltmp') - else: - raise RuntimeError('Unknown binary operator.') - -Expression class for function calls. -==================================== - -class CallExpressionNode(ExpressionNode): - -def **init**\ (self, callee, args): self.callee = callee self.args = -args - -def CodeGen(self): # Look up the name in the global module table. callee -= g\_llvm\_module.get\_function\_named(self.callee) - -:: - - # Check for argument mismatch error. - if len(callee.args) != len(self.args): - raise RuntimeError('Incorrect number of arguments passed.') - - arg_values = [i.CodeGen() for i in self.args] - - return g_llvm_builder.call(callee, arg_values, 'calltmp') - -Expression class for if/then/else. -================================== - -class IfExpressionNode(ExpressionNode): - -def **init**\ (self, condition, then\_branch, else\_branch): -self.condition = condition self.then\_branch = then\_branch -self.else\_branch = else\_branch - -def CodeGen(self): condition = self.condition.CodeGen() - -:: - - # Convert condition to a bool by comparing equal to 0.0. - condition_bool = g_llvm_builder.fcmp( - FCMP_ONE, condition, Constant.real(Type.double(), 0), 'ifcond') - - function = g_llvm_builder.basic_block.function - - # Create blocks for the then and else cases. Insert the 'then' block at the - # end of the function. - then_block = function.append_basic_block('then') - else_block = function.append_basic_block('else') - merge_block = function.append_basic_block('ifcond') - - g_llvm_builder.cbranch(condition_bool, then_block, else_block) - - # Emit then value. - g_llvm_builder.position_at_end(then_block) - then_value = self.then_branch.CodeGen() - g_llvm_builder.branch(merge_block) - - # Codegen of 'Then' can change the current block; update then_block for the - # PHI node. - then_block = g_llvm_builder.basic_block - - # Emit else block. - g_llvm_builder.position_at_end(else_block) - else_value = self.else_branch.CodeGen() - g_llvm_builder.branch(merge_block) - - # Codegen of 'Else' can change the current block, update else_block for the - # PHI node. - else_block = g_llvm_builder.basic_block - - # Emit merge block. - g_llvm_builder.position_at_end(merge_block) - phi = g_llvm_builder.phi(Type.double(), 'iftmp') - phi.add_incoming(then_value, then_block) - phi.add_incoming(else_value, else_block) - - return phi - -Expression class for for/in. -============================ - -class ForExpressionNode(ExpressionNode): - -def **init**\ (self, loop\_variable, start, end, step, body): -self.loop\_variable = loop\_variable self.start = start self.end = end -self.step = step self.body = body - -def CodeGen(self): # Output this as: # ... # start = startexpr # goto -loop # loop: # variable = phi [start, loopheader], [nextvariable, -loopend] # ... # bodyexpr # ... # loopend: # step = stepexpr # -nextvariable = variable + step # endcond = endexpr # br endcond, loop, -endloop # outloop: - -:: - - # Emit the start code first, without 'variable' in scope. - start_value = self.start.CodeGen() - - # Make the new basic block for the loop header, inserting after current - # block. - function = g_llvm_builder.basic_block.function - pre_header_block = g_llvm_builder.basic_block - loop_block = function.append_basic_block('loop') - - # Insert an explicit fallthrough from the current block to the loop_block. - g_llvm_builder.branch(loop_block) - - # Start insertion in loop_block. - g_llvm_builder.position_at_end(loop_block) - - # Start the PHI node with an entry for start. - variable_phi = g_llvm_builder.phi(Type.double(), self.loop_variable) - variable_phi.add_incoming(start_value, pre_header_block) - - # Within the loop, the variable is defined equal to the PHI node. If it - # shadows an existing variable, we have to restore it, so save it now. - old_value = g_named_values.get(self.loop_variable, None) - g_named_values[self.loop_variable] = variable_phi - - # Emit the body of the loop. This, like any other expr, can change the - # current BB. Note that we ignore the value computed by the body. - self.body.CodeGen() - - # Emit the step value. - if self.step: - step_value = self.step.CodeGen() - else: - # If not specified, use 1.0. - step_value = Constant.real(Type.double(), 1) - - next_value = g_llvm_builder.fadd(variable_phi, step_value, 'next') - - # Compute the end condition and convert it to a bool by comparing to 0.0. - end_condition = self.end.CodeGen() - end_condition_bool = g_llvm_builder.fcmp( - FCMP_ONE, end_condition, Constant.real(Type.double(), 0), 'loopcond') - - # Create the "after loop" block and insert it. - loop_end_block = g_llvm_builder.basic_block - after_block = function.append_basic_block('afterloop') - - # Insert the conditional branch into the end of loop_end_block. - g_llvm_builder.cbranch(end_condition_bool, loop_block, after_block) - - # Any new code will be inserted in after_block. - g_llvm_builder.position_at_end(after_block) - - # Add a new entry to the PHI node for the backedge. - variable_phi.add_incoming(next_value, loop_end_block) - - # Restore the unshadowed variable. - if old_value: - g_named_values[self.loop_variable] = old_value - else: - del g_named_values[self.loop_variable] - - # for expr always returns 0.0. - return Constant.real(Type.double(), 0) - -This class represents the "prototype" for a function, which captures its name, -============================================================================== - -and its argument names (thus implicitly the number of arguments the function -============================================================================ - -takes). -======= - -class PrototypeNode(object): - -def **init**\ (self, name, args): self.name = name self.args = args - -def CodeGen(self): # Make the function type, eg. double(double,double). -funct\_type = Type.function( Type.double(), [Type.double()] \* -len(self.args), False) - -:: - - function = Function.new(g_llvm_module, funct_type, self.name) - - # If the name conflicted, there was already something with the same name. - # If it has a body, don't allow redefinition or reextern. - if function.name != self.name: - function.delete() - function = g_llvm_module.get_function_named(self.name) - - # If the function already has a body, reject this. - if not function.is_declaration: - raise RuntimeError('Redefinition of function.') - - # If the function took a different number of args, reject. - if len(function.args) != len(self.args): - raise RuntimeError('Redeclaration of a function with different number ' - 'of args.') - - # Set names for all arguments and add them to the variables symbol table. - for arg, arg_name in zip(function.args, self.args): - arg.name = arg_name - # Add arguments to variable symbol table. - g_named_values[arg_name] = arg - - return function - -This class represents a function definition itself. -=================================================== - -class FunctionNode(object): - -def **init**\ (self, prototype, body): self.prototype = prototype -self.body = body - -def CodeGen(self): # Clear scope. g\_named\_values.clear() - -:: - - # Create a function object. - function = self.prototype.CodeGen() - - # Create a new basic block to start insertion into. - block = function.append_basic_block('entry') - global g_llvm_builder - g_llvm_builder = Builder.new(block) - - # Finish off the function. - try: - return_value = self.body.CodeGen() - g_llvm_builder.ret(return_value) - - # Validate the generated code, checking for consistency. - function.verify() - - # Optimize the function. - g_llvm_pass_manager.run(function) - except: - function.delete() - raise - - return function - -Parser ------- - -class Parser(object): - -def **init**\ (self, tokens, binop\_precedence): self.tokens = tokens -self.binop\_precedence = binop\_precedence self.Next() - -# Provide a simple token buffer. Parser.current is the current token the -# parser is looking at. Parser.Next() reads another token from the lexer -and # updates Parser.current with its results. def Next(self): -self.current = self.tokens.next() - -# Gets the precedence of the current token, or -1 if the token is not a -binary # operator. def GetCurrentTokenPrecedence(self): if -isinstance(self.current, CharacterToken): return -self.binop\_precedence.get(self.current.char, -1) else: return -1 - -# identifierexpr ::= identifier \| identifier '(' expression\* ')' def -ParseIdentifierExpr(self): identifier\_name = self.current.name -self.Next() # eat identifier. - -:: - - if self.current != CharacterToken('('): # Simple variable reference. - return VariableExpressionNode(identifier_name) - - # Call. - self.Next() # eat '('. - args = [] - if self.current != CharacterToken(')'): - while True: - args.append(self.ParseExpression()) - if self.current == CharacterToken(')'): - break - elif self.current != CharacterToken(','): - raise RuntimeError('Expected ")" or "," in argument list.') - self.Next() - - self.Next() # eat ')'. - return CallExpressionNode(identifier_name, args) - -# numberexpr ::= number def ParseNumberExpr(self): result = -NumberExpressionNode(self.current.value) self.Next() # consume the -number. return result - -# parenexpr ::= '(' expression ')' def ParseParenExpr(self): self.Next() -# eat '('. - -:: - - contents = self.ParseExpression() - - if self.current != CharacterToken(')'): - raise RuntimeError('Expected ")".') - self.Next() # eat ')'. - - return contents - -# ifexpr ::= 'if' expression 'then' expression 'else' expression def -ParseIfExpr(self): self.Next() # eat the if. - -:: - - # condition. - condition = self.ParseExpression() - - if not isinstance(self.current, ThenToken): - raise RuntimeError('Expected "then".') - self.Next() # eat the then. - - then_branch = self.ParseExpression() - - if not isinstance(self.current, ElseToken): - raise RuntimeError('Expected "else".') - self.Next() # eat the else. - - else_branch = self.ParseExpression() - - return IfExpressionNode(condition, then_branch, else_branch) - -# forexpr ::= 'for' identifier '=' expr ',' expr (',' expr)? 'in' -expression def ParseForExpr(self): self.Next() # eat the for. - -:: - - if not isinstance(self.current, IdentifierToken): - raise RuntimeError('Expected identifier after for.') - - loop_variable = self.current.name - self.Next() # eat the identifier. - - if self.current != CharacterToken('='): - raise RuntimeError('Expected "=" after for variable.') - self.Next() # eat the '='. - - start = self.ParseExpression() - - if self.current != CharacterToken(','): - raise RuntimeError('Expected "," after for start value.') - self.Next() # eat the ','. - - end = self.ParseExpression() - - # The step value is optional. - if self.current == CharacterToken(','): - self.Next() # eat the ','. - step = self.ParseExpression() - else: - step = None - - if not isinstance(self.current, InToken): - raise RuntimeError('Expected "in" after for variable specification.') - self.Next() # eat 'in'. - - body = self.ParseExpression() - - return ForExpressionNode(loop_variable, start, end, step, body) - -# primary ::= identifierexpr \| numberexpr \| parenexpr \| ifexpr \| -forexpr def ParsePrimary(self): if isinstance(self.current, -IdentifierToken): return self.ParseIdentifierExpr() elif -isinstance(self.current, NumberToken): return self.ParseNumberExpr() -elif isinstance(self.current, IfToken): return self.ParseIfExpr() elif -isinstance(self.current, ForToken): return self.ParseForExpr() elif -self.current == CharacterToken('('): return self.ParseParenExpr() else: -raise RuntimeError('Unknown token when expecting an expression.') - -# binoprhs ::= (operator primary)\* def ParseBinOpRHS(self, left, -left\_precedence): # If this is a binary operator, find its precedence. -while True: precedence = self.GetCurrentTokenPrecedence() - -:: - - # If this is a binary operator that binds at least as tightly as the - # current one, consume it; otherwise we are done. - if precedence < left_precedence: - return left - - binary_operator = self.current.char - self.Next() # eat the operator. - - # Parse the primary expression after the binary operator. - right = self.ParsePrimary() - - # If binary_operator binds less tightly with right than the operator after - # right, let the pending operator take right as its left. - next_precedence = self.GetCurrentTokenPrecedence() - if precedence < next_precedence: - right = self.ParseBinOpRHS(right, precedence + 1) - - # Merge left/right. - left = BinaryOperatorExpressionNode(binary_operator, left, right) - -# expression ::= primary binoprhs def ParseExpression(self): left = -self.ParsePrimary() return self.ParseBinOpRHS(left, 0) - -# prototype ::= id '(' id\* ')' def ParsePrototype(self): if not -isinstance(self.current, IdentifierToken): raise RuntimeError('Expected -function name in prototype.') - -:: - - function_name = self.current.name - self.Next() # eat function name. - - if self.current != CharacterToken('('): - raise RuntimeError('Expected "(" in prototype.') - self.Next() # eat '('. - - arg_names = [] - while isinstance(self.current, IdentifierToken): - arg_names.append(self.current.name) - self.Next() - - if self.current != CharacterToken(')'): - raise RuntimeError('Expected ")" in prototype.') - - # Success. - self.Next() # eat ')'. - - return PrototypeNode(function_name, arg_names) - -# definition ::= 'def' prototype expression def ParseDefinition(self): -self.Next() # eat def. proto = self.ParsePrototype() body = -self.ParseExpression() return FunctionNode(proto, body) - -# toplevelexpr ::= expression def ParseTopLevelExpr(self): proto = -PrototypeNode('', []) return FunctionNode(proto, self.ParseExpression()) - -# external ::= 'extern' prototype def ParseExtern(self): self.Next() # -eat extern. return self.ParsePrototype() - -# Top-Level parsing def HandleDefinition(self): -self.Handle(self.ParseDefinition, 'Read a function definition:') - -def HandleExtern(self): self.Handle(self.ParseExtern, 'Read an extern:') - -def HandleTopLevelExpression(self): try: function = -self.ParseTopLevelExpr().CodeGen() result = -g\_llvm\_executor.run\_function(function, []) print 'Evaluated to:', -result.as\_real(Type.double()) except Exception, e: print 'Error:', e -try: self.Next() # Skip for error recovery. except: pass - -def Handle(self, function, message): try: print message, -function().CodeGen() except Exception, e: print 'Error:', e try: -self.Next() # Skip for error recovery. except: pass - -Main driver code. ------------------ - -def main(): # Set up the optimizer pipeline. Start with registering info -about how the # target lays out data structures. -g\_llvm\_pass\_manager.add(g\_llvm\_executor.target\_data) # Do simple -"peephole" optimizations and bit-twiddling optzns. -g\_llvm\_pass\_manager.add(PASS\_INSTRUCTION\_COMBINING) # Reassociate -expressions. g\_llvm\_pass\_manager.add(PASS\_REASSOCIATE) # Eliminate -Common SubExpressions. g\_llvm\_pass\_manager.add(PASS\_GVN) # Simplify -the control flow graph (deleting unreachable blocks, etc). -g\_llvm\_pass\_manager.add(PASS\_CFG\_SIMPLIFICATION) - -g\_llvm\_pass\_manager.initialize() - -# Install standard binary operators. # 1 is lowest possible precedence. -40 is the highest. operator\_precedence = { '<': 10, '+': 20, '-': 20, -'\*': 40 } - -# Run the main "interpreter loop". while True: print 'ready>', try: raw -= raw\_input() except KeyboardInterrupt: break - -:: - - parser = Parser(Tokenize(raw), operator_precedence) - while True: - # top ::= definition | external | expression | EOF - if isinstance(parser.current, EOFToken): - break - if isinstance(parser.current, DefToken): - parser.HandleDefinition() - elif isinstance(parser.current, ExternToken): - parser.HandleExtern() - else: - parser.HandleTopLevelExpression() - -# Print out all of the generated code. print '', g\_llvm\_module - -if **name** == '**main**\ ': main() {% endhighlight %} - --------------- - -**`Next: Extending the language: user-defined -operators `_** +.. code-block:: python + + #!/usr/bin/env python + + import re from llvm.core import Module, Constant, Type, Function, + Builder from llvm.ee import ExecutionEngine, TargetData from llvm.passes + import FunctionPassManager + + from llvm.core import FCMP_ULT, FCMP_ONE from llvm.passes import + (PASS_INSTRUCTION_COMBINING, PASS_REASSOCIATE, PASS_GVN, + PASS_CFG_SIMPLIFICATION) + + Globals + ------- + + # The LLVM module, which holds all the IR code. + g_llvm_module = Module.new('my cool jit') + + # The LLVM instruction builder. Created whenever a new function is entered. + g_llvm_builder = None + + # A dictionary that keeps track of which values are defined in the current scope + # and what their LLVM representation is. + g_named_values = {} + + # The function optimization passes manager. + g_llvm_pass_manager = FunctionPassManager.new(g_llvm_module) + + # The LLVM execution engine. + g_llvm_executor = ExecutionEngine.new(g_llvm_module) + + Lexer + ----- + + # The lexer yields one of these types for each token. + class EOFToken(object): pass class DefToken(object): pass class + ExternToken(object): pass class IfToken(object): pass class + ThenToken(object): pass class ElseToken(object): pass class + ForToken(object): pass class InToken(object): pass + + class IdentifierToken(object): def **init**\ (self, name): self.name = + name + + class NumberToken(object): def **init**\ (self, value): self.value = + value + + class CharacterToken(object): def **init**\ (self, char): self.char = + char def **eq**\ (self, other): return isinstance(other, CharacterToken) + and self.char == other.char def **ne**\ (self, other): return not self + == other + + # Regular expressions that tokens and comments of our language. + REGEX_NUMBER = re.compile('[0-9]+(?:.[0-9]+)?') REGEX_IDENTIFIER = + re.compile('[a-zA-Z][a-zA-Z0-9]\ *') REGEX_COMMENT = re.compile('#.*') + + def Tokenize(string): while string: # Skip whitespace. if + string[0].isspace(): string = string[1:] continue + + :: + + # Run regexes. + comment_match = REGEX_COMMENT.match(string) + number_match = REGEX_NUMBER.match(string) + identifier_match = REGEX_IDENTIFIER.match(string) + + # Check if any of the regexes matched and yield the appropriate result. + if comment_match: + comment = comment_match.group(0) + string = string[len(comment):] + elif number_match: + number = number_match.group(0) + yield NumberToken(float(number)) + string = string[len(number):] + elif identifier_match: + identifier = identifier_match.group(0) + # Check if we matched a keyword. + if identifier == 'def': + yield DefToken() + elif identifier == 'extern': + yield ExternToken() + elif identifier == 'if': + yield IfToken() + elif identifier == 'then': + yield ThenToken() + elif identifier == 'else': + yield ElseToken() + elif identifier == 'for': + yield ForToken() + elif identifier == 'in': + yield InToken() + else: + yield IdentifierToken(identifier) + string = string[len(identifier):] + else: + # Yield the ASCII value of the unknown character. + yield CharacterToken(string[0]) + string = string[1:] + + yield EOFToken() + + Abstract Syntax Tree (aka Parse Tree) + ------------------------------------- + + # Base class for all expression nodes. + class ExpressionNode(object): pass + + # Expression class for numeric literals like "1.0". + class NumberExpressionNode(ExpressionNode): + + def **init**\ (self, value): self.value = value + + def CodeGen(self): return Constant.real(Type.double(), self.value) + + # Expression class for referencing a variable, like "a". + class VariableExpressionNode(ExpressionNode): + + def **init**\ (self, name): self.name = name + + def CodeGen(self): if self.name in g_named_values: return + g_named_values[self.name] else: raise RuntimeError('Unknown variable + name: ' + self.name) + + # Expression class for a binary operator. + class BinaryOperatorExpressionNode(ExpressionNode): + + def **init**\ (self, operator, left, right): self.operator = operator + self.left = left self.right = right + + def CodeGen(self): left = self.left.CodeGen() right = + self.right.CodeGen() + + :: + + if self.operator == '+': + return g_llvm_builder.fadd(left, right, 'addtmp') + elif self.operator == '-': + return g_llvm_builder.fsub(left, right, 'subtmp') + elif self.operator == '*': + return g_llvm_builder.fmul(left, right, 'multmp') + elif self.operator == '<': + result = g_llvm_builder.fcmp(FCMP_ULT, left, right, 'cmptmp') + # Convert bool 0 or 1 to double 0.0 or 1.0. + return g_llvm_builder.uitofp(result, Type.double(), 'booltmp') + else: + raise RuntimeError('Unknown binary operator.') + + # Expression class for function calls. + class CallExpressionNode(ExpressionNode): + + def **init**\ (self, callee, args): self.callee = callee self.args = + args + + def CodeGen(self): # Look up the name in the global module table. callee + = g_llvm_module.get_function_named(self.callee) + + :: + + # Check for argument mismatch error. + if len(callee.args) != len(self.args): + raise RuntimeError('Incorrect number of arguments passed.') + + arg_values = [i.CodeGen() for i in self.args] + + return g_llvm_builder.call(callee, arg_values, 'calltmp') + + # Expression class for if/then/else. + class IfExpressionNode(ExpressionNode): + + def **init**\ (self, condition, then_branch, else_branch): + self.condition = condition self.then_branch = then_branch + self.else_branch = else_branch + + def CodeGen(self): condition = self.condition.CodeGen() + + :: + + # Convert condition to a bool by comparing equal to 0.0. + condition_bool = g_llvm_builder.fcmp( + FCMP_ONE, condition, Constant.real(Type.double(), 0), 'ifcond') + + function = g_llvm_builder.basic_block.function + + # Create blocks for the then and else cases. Insert the 'then' block at the + # end of the function. + then_block = function.append_basic_block('then') + else_block = function.append_basic_block('else') + merge_block = function.append_basic_block('ifcond') + + g_llvm_builder.cbranch(condition_bool, then_block, else_block) + + # Emit then value. + g_llvm_builder.position_at_end(then_block) + then_value = self.then_branch.CodeGen() + g_llvm_builder.branch(merge_block) + + # Codegen of 'Then' can change the current block; update then_block for the + # PHI node. + then_block = g_llvm_builder.basic_block + + # Emit else block. + g_llvm_builder.position_at_end(else_block) + else_value = self.else_branch.CodeGen() + g_llvm_builder.branch(merge_block) + + # Codegen of 'Else' can change the current block, update else_block for the + # PHI node. + else_block = g_llvm_builder.basic_block + + # Emit merge block. + g_llvm_builder.position_at_end(merge_block) + phi = g_llvm_builder.phi(Type.double(), 'iftmp') + phi.add_incoming(then_value, then_block) + phi.add_incoming(else_value, else_block) + + return phi + + # Expression class for for/in. + class ForExpressionNode(ExpressionNode): + + def **init**\ (self, loop_variable, start, end, step, body): + self.loop_variable = loop_variable self.start = start self.end = end + self.step = step self.body = body + + def CodeGen(self): # Output this as: # ... # start = startexpr # goto + loop # loop: # variable = phi [start, loopheader], [nextvariable, + loopend] # ... # bodyexpr # ... # loopend: # step = stepexpr # + nextvariable = variable + step # endcond = endexpr # br endcond, loop, + endloop # outloop: + + :: + + # Emit the start code first, without 'variable' in scope. + start_value = self.start.CodeGen() + + # Make the new basic block for the loop header, inserting after current + # block. + function = g_llvm_builder.basic_block.function + pre_header_block = g_llvm_builder.basic_block + loop_block = function.append_basic_block('loop') + + # Insert an explicit fallthrough from the current block to the loop_block. + g_llvm_builder.branch(loop_block) + + # Start insertion in loop_block. + g_llvm_builder.position_at_end(loop_block) + + # Start the PHI node with an entry for start. + variable_phi = g_llvm_builder.phi(Type.double(), self.loop_variable) + variable_phi.add_incoming(start_value, pre_header_block) + + # Within the loop, the variable is defined equal to the PHI node. If it + # shadows an existing variable, we have to restore it, so save it now. + old_value = g_named_values.get(self.loop_variable, None) + g_named_values[self.loop_variable] = variable_phi + + # Emit the body of the loop. This, like any other expr, can change the + # current BB. Note that we ignore the value computed by the body. + self.body.CodeGen() + + # Emit the step value. + if self.step: + step_value = self.step.CodeGen() + else: + # If not specified, use 1.0. + step_value = Constant.real(Type.double(), 1) + + next_value = g_llvm_builder.fadd(variable_phi, step_value, 'next') + + # Compute the end condition and convert it to a bool by comparing to 0.0. + end_condition = self.end.CodeGen() + end_condition_bool = g_llvm_builder.fcmp( + FCMP_ONE, end_condition, Constant.real(Type.double(), 0), 'loopcond') + + # Create the "after loop" block and insert it. + loop_end_block = g_llvm_builder.basic_block + after_block = function.append_basic_block('afterloop') + + # Insert the conditional branch into the end of loop_end_block. + g_llvm_builder.cbranch(end_condition_bool, loop_block, after_block) + + # Any new code will be inserted in after_block. + g_llvm_builder.position_at_end(after_block) + + # Add a new entry to the PHI node for the backedge. + variable_phi.add_incoming(next_value, loop_end_block) + + # Restore the unshadowed variable. + if old_value: + g_named_values[self.loop_variable] = old_value + else: + del g_named_values[self.loop_variable] + + # for expr always returns 0.0. + return Constant.real(Type.double(), 0) + + # This class represents the "prototype" for a function, which captures its name, + # and its argument names (thus implicitly the number of arguments the function + # takes). + class PrototypeNode(object): + + def **init**\ (self, name, args): self.name = name self.args = args + + def CodeGen(self): # Make the function type, eg. double(double,double). + funct_type = Type.function( Type.double(), [Type.double()] \* + len(self.args), False) + + :: + + function = Function.new(g_llvm_module, funct_type, self.name) + + # If the name conflicted, there was already something with the same name. + # If it has a body, don't allow redefinition or reextern. + if function.name != self.name: + function.delete() + function = g_llvm_module.get_function_named(self.name) + + # If the function already has a body, reject this. + if not function.is_declaration: + raise RuntimeError('Redefinition of function.') + + # If the function took a different number of args, reject. + if len(function.args) != len(self.args): + raise RuntimeError('Redeclaration of a function with different number ' + 'of args.') + + # Set names for all arguments and add them to the variables symbol table. + for arg, arg_name in zip(function.args, self.args): + arg.name = arg_name + # Add arguments to variable symbol table. + g_named_values[arg_name] = arg + + return function + + # This class represents a function definition itself. + class FunctionNode(object): + + def **init**\ (self, prototype, body): self.prototype = prototype + self.body = body + + def CodeGen(self): # Clear scope. g_named_values.clear() + + :: + + # Create a function object. + function = self.prototype.CodeGen() + + # Create a new basic block to start insertion into. + block = function.append_basic_block('entry') + global g_llvm_builder + g_llvm_builder = Builder.new(block) + + # Finish off the function. + try: + return_value = self.body.CodeGen() + g_llvm_builder.ret(return_value) + + # Validate the generated code, checking for consistency. + function.verify() + + # Optimize the function. + g_llvm_pass_manager.run(function) + except: + function.delete() + raise + + return function + + Parser + ------ + + class Parser(object): + + def **init**\ (self, tokens, binop_precedence): self.tokens = tokens + self.binop_precedence = binop_precedence self.Next() + + # Provide a simple token buffer. Parser.current is the current token the + # parser is looking at. Parser.Next() reads another token from the lexer + and # updates Parser.current with its results. def Next(self): + self.current = self.tokens.next() + + # Gets the precedence of the current token, or -1 if the token is not a + binary # operator. def GetCurrentTokenPrecedence(self): if + isinstance(self.current, CharacterToken): return + self.binop_precedence.get(self.current.char, -1) else: return -1 + + # identifierexpr ::= identifier \| identifier '(' expression\* ')' def + ParseIdentifierExpr(self): identifier_name = self.current.name + self.Next() # eat identifier. + + :: + + if self.current != CharacterToken('('): # Simple variable reference. + return VariableExpressionNode(identifier_name) + + # Call. + self.Next() # eat '('. + args = [] + if self.current != CharacterToken(')'): + while True: + args.append(self.ParseExpression()) + if self.current == CharacterToken(')'): + break + elif self.current != CharacterToken(','): + raise RuntimeError('Expected ")" or "," in argument list.') + self.Next() + + self.Next() # eat ')'. + return CallExpressionNode(identifier_name, args) + + # numberexpr ::= number def ParseNumberExpr(self): result = + NumberExpressionNode(self.current.value) self.Next() # consume the + number. return result + + # parenexpr ::= '(' expression ')' def ParseParenExpr(self): self.Next() + # eat '('. + + :: + + contents = self.ParseExpression() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")".') + self.Next() # eat ')'. + + return contents + + # ifexpr ::= 'if' expression 'then' expression 'else' expression def + ParseIfExpr(self): self.Next() # eat the if. + + :: + + # condition. + condition = self.ParseExpression() + + if not isinstance(self.current, ThenToken): + raise RuntimeError('Expected "then".') + self.Next() # eat the then. + + then_branch = self.ParseExpression() + + if not isinstance(self.current, ElseToken): + raise RuntimeError('Expected "else".') + self.Next() # eat the else. + + else_branch = self.ParseExpression() + + return IfExpressionNode(condition, then_branch, else_branch) + + # forexpr ::= 'for' identifier '=' expr ',' expr (',' expr)? 'in' + expression def ParseForExpr(self): self.Next() # eat the for. + + :: + + if not isinstance(self.current, IdentifierToken): + raise RuntimeError('Expected identifier after for.') + + loop_variable = self.current.name + self.Next() # eat the identifier. + + if self.current != CharacterToken('='): + raise RuntimeError('Expected "=" after for variable.') + self.Next() # eat the '='. + + start = self.ParseExpression() + + if self.current != CharacterToken(','): + raise RuntimeError('Expected "," after for start value.') + self.Next() # eat the ','. + + end = self.ParseExpression() + + # The step value is optional. + if self.current == CharacterToken(','): + self.Next() # eat the ','. + step = self.ParseExpression() + else: + step = None + + if not isinstance(self.current, InToken): + raise RuntimeError('Expected "in" after for variable specification.') + self.Next() # eat 'in'. + + body = self.ParseExpression() + + return ForExpressionNode(loop_variable, start, end, step, body) + + # primary ::= identifierexpr \| numberexpr \| parenexpr \| ifexpr \| + forexpr def ParsePrimary(self): if isinstance(self.current, + IdentifierToken): return self.ParseIdentifierExpr() elif + isinstance(self.current, NumberToken): return self.ParseNumberExpr() + elif isinstance(self.current, IfToken): return self.ParseIfExpr() elif + isinstance(self.current, ForToken): return self.ParseForExpr() elif + self.current == CharacterToken('('): return self.ParseParenExpr() else: + raise RuntimeError('Unknown token when expecting an expression.') + + # binoprhs ::= (operator primary)\* def ParseBinOpRHS(self, left, + left_precedence): # If this is a binary operator, find its precedence. + while True: precedence = self.GetCurrentTokenPrecedence() + + :: + + # If this is a binary operator that binds at least as tightly as the + # current one, consume it; otherwise we are done. + if precedence < left_precedence: + return left + + binary_operator = self.current.char + self.Next() # eat the operator. + + # Parse the primary expression after the binary operator. + right = self.ParsePrimary() + + # If binary_operator binds less tightly with right than the operator after + # right, let the pending operator take right as its left. + next_precedence = self.GetCurrentTokenPrecedence() + if precedence < next_precedence: + right = self.ParseBinOpRHS(right, precedence + 1) + + # Merge left/right. + left = BinaryOperatorExpressionNode(binary_operator, left, right) + + # expression ::= primary binoprhs def ParseExpression(self): left = + self.ParsePrimary() return self.ParseBinOpRHS(left, 0) + + # prototype ::= id '(' id\* ')' def ParsePrototype(self): if not + isinstance(self.current, IdentifierToken): raise RuntimeError('Expected + function name in prototype.') + + :: + + function_name = self.current.name + self.Next() # eat function name. + + if self.current != CharacterToken('('): + raise RuntimeError('Expected "(" in prototype.') + self.Next() # eat '('. + + arg_names = [] + while isinstance(self.current, IdentifierToken): + arg_names.append(self.current.name) + self.Next() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")" in prototype.') + + # Success. + self.Next() # eat ')'. + + return PrototypeNode(function_name, arg_names) + + # definition ::= 'def' prototype expression def ParseDefinition(self): + self.Next() # eat def. proto = self.ParsePrototype() body = + self.ParseExpression() return FunctionNode(proto, body) + + # toplevelexpr ::= expression def ParseTopLevelExpr(self): proto = + PrototypeNode('', []) return FunctionNode(proto, self.ParseExpression()) + + # external ::= 'extern' prototype def ParseExtern(self): self.Next() # + eat extern. return self.ParsePrototype() + + # Top-Level parsing def HandleDefinition(self): + self.Handle(self.ParseDefinition, 'Read a function definition:') + + def HandleExtern(self): self.Handle(self.ParseExtern, 'Read an extern:') + + def HandleTopLevelExpression(self): try: function = + self.ParseTopLevelExpr().CodeGen() result = + g_llvm_executor.run_function(function, []) print 'Evaluated to:', + result.as_real(Type.double()) except Exception, e: print 'Error:', e + try: self.Next() # Skip for error recovery. except: pass + + def Handle(self, function, message): try: print message, + function().CodeGen() except Exception, e: print 'Error:', e try: + self.Next() # Skip for error recovery. except: pass + + Main driver code. + ----------------- + + def main(): # Set up the optimizer pipeline. Start with registering info + about how the # target lays out data structures. + g_llvm_pass_manager.add(g_llvm_executor.target_data) # Do simple + "peephole" optimizations and bit-twiddling optzns. + g_llvm_pass_manager.add(PASS_INSTRUCTION_COMBINING) # Reassociate + expressions. g_llvm_pass_manager.add(PASS_REASSOCIATE) # Eliminate + Common SubExpressions. g_llvm_pass_manager.add(PASS_GVN) # Simplify + the control flow graph (deleting unreachable blocks, etc). + g_llvm_pass_manager.add(PASS_CFG_SIMPLIFICATION) + + g_llvm_pass_manager.initialize() + + # Install standard binary operators. # 1 is lowest possible precedence. + 40 is the highest. operator_precedence = { '<': 10, '+': 20, '-': 20, + '\*': 40 } + + # Run the main "interpreter loop". while True: print 'ready>', try: raw + = raw_input() except KeyboardInterrupt: break + + :: + + parser = Parser(Tokenize(raw), operator_precedence) + while True: + # top ::= definition | external | expression | EOF + if isinstance(parser.current, EOFToken): + break + if isinstance(parser.current, DefToken): + parser.HandleDefinition() + elif isinstance(parser.current, ExternToken): + parser.HandleExtern() + else: + parser.HandleTopLevelExpression() + + # Print out all of the generated code. print '', g_llvm_module + + if **name** == '**main**\ ': main() diff --git a/docs/source/doc/kaleidoscope/PythonLangImpl6.rst b/docs/source/doc/kaleidoscope/PythonLangImpl6.rst index c7e354d..dfe95b6 100644 --- a/docs/source/doc/kaleidoscope/PythonLangImpl6.rst +++ b/docs/source/doc/kaleidoscope/PythonLangImpl6.rst @@ -50,23 +50,22 @@ The two specific features we'll add are programmable unary operators (right now, Kaleidoscope has no unary operators at all) as well as binary operators. An example of this is: -{% highlight python %} # Logical unary not. def unary!(v) if v then 0 -else 1 -Define > with the same precedence as <. -======================================= +.. code-block:: python -def binary> 10 (LHS RHS) RHS < LHS + # Logical unary not. def unary!(v) if v then 0 + else 1 + + # Define > with the same precedence as <. + def binary> 10 (LHS RHS) RHS < LHS + + # Binary "logical or", (note that it does not "short circuit"). + def binary\| 5 (LHS RHS) if LHS then 1 else if RHS then 1 else 0 + + # Define = with slightly lower precedence than relationals. + def binary= 9 (LHS RHS) !(LHS < RHS \| LHS > RHS) -Binary "logical or", (note that it does not "short circuit"). -============================================================= -def binary\| 5 (LHS RHS) if LHS then 1 else if RHS then 1 else 0 - -Define = with slightly lower precedence than relationals. -========================================================= - -def binary= 9 (LHS RHS) !(LHS < RHS \| LHS > RHS) {% endhighlight %} Many languages aspire to being able to implement their standard runtime library in the language itself. In Kaleidoscope, we can implement @@ -85,41 +84,46 @@ Adding support for user-defined binary operators is pretty simple with our current framework. We'll first add support for the unary/binary keywords: -{% highlight python %} class InToken(object): pass class -BinaryToken(object): pass class UnaryToken(object): pass ... def -Tokenize(string): ... elif identifier == 'in': yield InToken() elif -identifier == 'binary': yield BinaryToken() elif identifier == 'unary': -yield UnaryToken() else: yield IdentifierToken(identifier) {% -endhighlight %} -This just adds lexer support for the unary and binary keywords, like we -did in `previous chapters `_. One nice -thing about our current AST, is that we represent binary operators with -full generalisation by using their ASCII code as the opcode. For our -extended operators, we'll use this same representation, so we don't need -any new AST or parser support. +.. code-block:: python -On the other hand, we have to be able to represent the definitions of -these new operators, in the "def binary\| 5" part of the function -definition. In our grammar so far, the "name" for the function -definition is parsed as the "prototype" production and into the -``PrototypeNode``. To represent our new user-defined operators as -prototypes, we have to extend the ``PrototypeNode`` like this: + class InToken(object): pass class + BinaryToken(object): pass class UnaryToken(object): pass ... def + Tokenize(string): ... elif identifier == 'in': yield InToken() elif + identifier == 'binary': yield BinaryToken() elif identifier == 'unary': + yield UnaryToken() else: yield IdentifierToken(identifier) {% + endhighlight %} + + This just adds lexer support for the unary and binary keywords, like we + did in `previous chapters `_. One nice + thing about our current AST, is that we represent binary operators with + full generalisation by using their ASCII code as the opcode. For our + extended operators, we'll use this same representation, so we don't need + any new AST or parser support. + + On the other hand, we have to be able to represent the definitions of + these new operators, in the "def binary\| 5" part of the function + definition. In our grammar so far, the "name" for the function + definition is parsed as the "prototype" production and into the + ``PrototypeNode``. To represent our new user-defined operators as + prototypes, we have to extend the ``PrototypeNode`` like this: + + {% highlight python %} # This class represents the "prototype" for a + function, which captures its name, # and its argument names (thus + implicitly the number of arguments the function # takes), as well as if + it is an operator. class PrototypeNode(object): + + def **init**\ (self, name, args, is_operator=False, precedence=0): + self.name = name self.args = args self.is_operator = is_operator + self.precedence = precedence + + def IsBinaryOp(self): return self.is_operator and len(self.args) == 2 + + def GetOperatorName(self): assert self.is_operator return self.name[-1] + + def CodeGen(self): ... -{% highlight python %} # This class represents the "prototype" for a -function, which captures its name, # and its argument names (thus -implicitly the number of arguments the function # takes), as well as if -it is an operator. class PrototypeNode(object): -def **init**\ (self, name, args, is\_operator=False, precedence=0): -self.name = name self.args = args self.is\_operator = is\_operator -self.precedence = precedence - -def IsBinaryOp(self): return self.is\_operator and len(self.args) == 2 - -def GetOperatorName(self): assert self.is\_operator return self.name[-1] - -def CodeGen(self): ... {% endhighlight %} Basically, in addition to knowing a name for the prototype, we now keep track of whether it was an operator, and if it was, what precedence @@ -128,44 +132,49 @@ operators (as you'll see below, it just doesn't apply for unary operators). Now that we have a way to represent the prototype for a user-defined operator, we need to parse it: -{% highlight python %} # prototype # ::= id '(' id\* ')' # ::= binary -LETTER number? (id, id) # ::= unary LETTER (id) def -ParsePrototype(self): precedence = None if isinstance(self.current, -IdentifierToken): kind = 'normal' function\_name = self.current.name -self.Next() # eat function name. elif isinstance(self.current, -BinaryToken): kind = 'binary' self.Next() # eat 'binary'. if not -isinstance(self.current, CharacterToken): raise RuntimeError('Expected -an operator after "binary".') function\_name = 'binary' + -self.current.char self.Next() # eat the operator. if -isinstance(self.current, NumberToken): if not 1 <= self.current.value <= -100: raise RuntimeError('Invalid precedence: must be in range [1, -100].') precedence = self.current.value self.Next() # eat the -precedence. else: raise RuntimeError('Expected function name, "unary" or -"binary" in ' 'prototype.') -:: +.. code-block:: python - if self.current != CharacterToken('('): - raise RuntimeError('Expected "(" in prototype.') - self.Next() # eat '('. + # prototype # ::= id '(' id\* ')' # ::= binary + LETTER number? (id, id) # ::= unary LETTER (id) def + ParsePrototype(self): precedence = None if isinstance(self.current, + IdentifierToken): kind = 'normal' function_name = self.current.name + self.Next() # eat function name. elif isinstance(self.current, + BinaryToken): kind = 'binary' self.Next() # eat 'binary'. if not + isinstance(self.current, CharacterToken): raise RuntimeError('Expected + an operator after "binary".') function_name = 'binary' + + self.current.char self.Next() # eat the operator. if + isinstance(self.current, NumberToken): if not 1 <= self.current.value <= + 100: raise RuntimeError('Invalid precedence: must be in range [1, + 100].') precedence = self.current.value self.Next() # eat the + precedence. else: raise RuntimeError('Expected function name, "unary" or + "binary" in ' 'prototype.') + + :: + + if self.current != CharacterToken('('): + raise RuntimeError('Expected "(" in prototype.') + self.Next() # eat '('. + + arg_names = [] + while isinstance(self.current, IdentifierToken): + arg_names.append(self.current.name) + self.Next() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")" in prototype.') + + # Success. + self.Next() # eat ')'. + + if kind == 'binary' and len(arg_names) != 2: + raise RuntimeError('Invalid number of arguments for a binary operator.') + + return PrototypeNode(function_name, arg_names, kind != 'normal', precedence) + + - arg_names = [] - while isinstance(self.current, IdentifierToken): - arg_names.append(self.current.name) - self.Next() - if self.current != CharacterToken(')'): - raise RuntimeError('Expected ")" in prototype.') - - # Success. - self.Next() # eat ')'. - - if kind == 'binary' and len(arg_names) != 2: - raise RuntimeError('Invalid number of arguments for a binary operator.') - - return PrototypeNode(function_name, arg_names, kind != 'normal', precedence) - -{% endhighlight %} This is all fairly straightforward parsing code, and we have already seen a lot of similar code in the past. One interesting part about the @@ -178,26 +187,31 @@ The next interesting thing to add, is codegen support for these binary operators. Given our current structure, this is a simple addition of a default case for our existing binary operator node: -{% highlight python %} def CodeGen(self): left = self.left.CodeGen() -right = self.right.CodeGen() -:: +.. code-block:: python + + def CodeGen(self): left = self.left.CodeGen() + right = self.right.CodeGen() + + :: + + if self.operator == '+': + return g_llvm_builder.fadd(left, right, 'addtmp') + elif self.operator == '-': + return g_llvm_builder.fsub(left, right, 'subtmp') + elif self.operator == '*': + return g_llvm_builder.fmul(left, right, 'multmp') + elif self.operator == '<': + result = g_llvm_builder.fcmp(FCMP_ULT, left, right, 'cmptmp') + # Convert bool 0 or 1 to double 0.0 or 1.0. + return g_llvm_builder.uitofp(result, Type.double(), 'booltmp') + else: + function = g_llvm_module.get_function_named('binary' + self.operator) + return g_llvm_builder.call(function, [left, right], 'binop') + + - if self.operator == '+': - return g_llvm_builder.fadd(left, right, 'addtmp') - elif self.operator == '-': - return g_llvm_builder.fsub(left, right, 'subtmp') - elif self.operator == '*': - return g_llvm_builder.fmul(left, right, 'multmp') - elif self.operator == '<': - result = g_llvm_builder.fcmp(FCMP_ULT, left, right, 'cmptmp') - # Convert bool 0 or 1 to double 0.0 or 1.0. - return g_llvm_builder.uitofp(result, Type.double(), 'booltmp') - else: - function = g_llvm_module.get_function_named('binary' + self.operator) - return g_llvm_builder.call(function, [left, right], 'binop') -{% endhighlight %} As you can see above, the new code is actually really simple. It just does a lookup for the appropriate operator in the symbol table and @@ -209,32 +223,37 @@ The final piece of code we are missing, is a bit of top-level magic. We will need to make the dinary precedence map global and modify it whenever we define a new binary operator: -{% highlight python %} # The binary operator precedence chart. -g\_binop\_precedence = {} ... class FunctionNode(object): ... def -CodeGen(self): ... # Create a function object. function = -self.prototype.CodeGen() -:: +.. code-block:: python - # If this is a binary operator, install its precedence. - if self.prototype.IsBinaryOp(): - operator = self.prototype.GetOperatorName() - g_binop_precedence[operator] = self.prototype.precedence - ... - # Finish off the function. - try: - ... - except: - function.delete() - if self.prototype.IsBinaryOp(): - del g_binop_precedence[self.prototype.GetOperatorName()] - raise + # The binary operator precedence chart. + g_binop_precedence = {} ... class FunctionNode(object): ... def + CodeGen(self): ... # Create a function object. function = + self.prototype.CodeGen() + + :: + + # If this is a binary operator, install its precedence. + if self.prototype.IsBinaryOp(): + operator = self.prototype.GetOperatorName() + g_binop_precedence[operator] = self.prototype.precedence + ... + # Finish off the function. + try: + ... + except: + function.delete() + if self.prototype.IsBinaryOp(): + del g_binop_precedence[self.prototype.GetOperatorName()] + raise + + return function + + ... def main(): ... g_binop_precedence['<'] = 10 + g_binop_precedence['+'] = 20 g_binop_precedence['-'] = 20 + g_binop_precedence['\*'] = 40 ... - return function -... def main(): ... g\_binop\_precedence['<'] = 10 -g\_binop\_precedence['+'] = 20 g\_binop\_precedence['-'] = 20 -g\_binop\_precedence['\*'] = 40 ... {% endhighlight %} Basically, before CodeGening a function, if it is a user-defined operator, we register it in the precedence table. This allows the binary @@ -255,33 +274,43 @@ language, we'll need to add everything to support them. Above, we added simple support for the 'unary' keyword to the lexer. In addition to that, we need an AST node: -{% highlight python %} # Expression class for a unary operator. class -UnaryExpressionNode(ExpressionNode): -def **init**\ (self, operator, operand): self.operator = operator -self.operand = operand +.. code-block:: python + + # Expression class for a unary operator. class + UnaryExpressionNode(ExpressionNode): + + def **init**\ (self, operator, operand): self.operator = operator + self.operand = operand + + def CodeGen(self): ... + -def CodeGen(self): ... {% endhighlight %} This AST node is very simple and obvious by now. It directly mirrors the binary operator AST node, except that it only has one child. With this, we need to add the parsing logic. Parsing a unary operator is pretty simple: we'll add a new function to do it: -{% highlight python %} # unary ::= primary \| unary\_operator unary def -ParseUnary(self): # If the current token is not an operator, it must be -a primary expression. if (not isinstance(self.current, CharacterToken) -or self.current in [CharacterToken('('), CharacterToken(',')]): return -self.ParsePrimary() -:: +.. code-block:: python + + # unary ::= primary \| unary_operator unary def + ParseUnary(self): # If the current token is not an operator, it must be + a primary expression. if (not isinstance(self.current, CharacterToken) + or self.current in [CharacterToken('('), CharacterToken(',')]): return + self.ParsePrimary() + + :: + + # If this is a unary operator, read it. + operator = self.current.char + self.Next() # eat the operator. + return UnaryExpressionNode(operator, self.ParseUnary()) + + - # If this is a unary operator, read it. - operator = self.current.char - self.Next() # eat the operator. - return UnaryExpressionNode(operator, self.ParseUnary()) -{% endhighlight %} The grammar we add is pretty straightforward here. If we see a unary operator when parsing a primary operator, we eat the operator as a @@ -294,47 +323,62 @@ The problem with this function, is that we need to call ParseUnary from somewhere. To do this, we change previous callers of ParsePrimary to call ParseUnary instead: -{% highlight python %} # binoprhs ::= (binary\_operator unary)\* def -ParseBinOpRHS(self, left, left\_precedence): ... # Parse the unary -expression after the binary operator. right = self.ParseUnary() ... -# expression ::= unary binoprhs def ParseExpression(self): left = -self.ParseUnary() return self.ParseBinOpRHS(left, 0) {% endhighlight %} +.. code-block:: python + + # binoprhs ::= (binary_operator unary)\* def + ParseBinOpRHS(self, left, left_precedence): ... # Parse the unary + expression after the binary operator. right = self.ParseUnary() ... + + # expression ::= unary binoprhs def ParseExpression(self): left = + self.ParseUnary() return self.ParseBinOpRHS(left, 0) + + With these two simple changes, we are now able to parse unary operators and build the AST for them. Next up, we need to add parser support for prototypes, to parse the unary operator prototype. We extend the binary operator code above with: -{% highlight python %} # prototype # ::= id '(' id\* ')' # ::= binary -LETTER number? (id, id) # ::= unary LETTER (id) def -ParsePrototype(self): precedence = None if isinstance(self.current, -IdentifierToken): ... elif isinstance(self.current, UnaryToken): kind = -'unary' self.Next() # eat 'unary'. if not isinstance(self.current, -CharacterToken): raise RuntimeError('Expected an operator after -"unary".') function\_name = 'unary' + self.current.char self.Next() # -eat the operator. elif isinstance(self.current, BinaryToken): ... else: -raise RuntimeError('Expected function name, "unary" or "binary" in ' -'prototype.') ... if kind == 'unary' and len(arg\_names) != 1: raise -RuntimeError('Invalid number of arguments for a unary operator.') elif -kind == 'binary' and len(arg\_names) != 2: raise RuntimeError('Invalid -number of arguments for a binary operator.') -:: +.. code-block:: python + + # prototype # ::= id '(' id\* ')' # ::= binary + LETTER number? (id, id) # ::= unary LETTER (id) def + ParsePrototype(self): precedence = None if isinstance(self.current, + IdentifierToken): ... elif isinstance(self.current, UnaryToken): kind = + 'unary' self.Next() # eat 'unary'. if not isinstance(self.current, + CharacterToken): raise RuntimeError('Expected an operator after + "unary".') function_name = 'unary' + self.current.char self.Next() # + eat the operator. elif isinstance(self.current, BinaryToken): ... else: + raise RuntimeError('Expected function name, "unary" or "binary" in ' + 'prototype.') ... if kind == 'unary' and len(arg_names) != 1: raise + RuntimeError('Invalid number of arguments for a unary operator.') elif + kind == 'binary' and len(arg_names) != 2: raise RuntimeError('Invalid + number of arguments for a binary operator.') + + :: + + return PrototypeNode(function_name, arg_names, kind != 'normal', precedence) + + - return PrototypeNode(function_name, arg_names, kind != 'normal', precedence) -{% endhighlight %} As with binary operators, we name unary operators with a name that includes the operator character. This assists us at code generation time. Speaking of, the final piece we need to add is codegen support for unary operators. It looks like this: -{% highlight python %} class UnaryExpressionNode(ExpressionNode): ... -def CodeGen(self): operand = self.operand.CodeGen() function = -g\_llvm\_module.get\_function\_named('unary' + self.operator) return -g\_llvm\_builder.call(function, [operand], 'unop') {% endhighlight %} + +.. code-block:: python + + class UnaryExpressionNode(ExpressionNode): ... + def CodeGen(self): operand = self.operand.CodeGen() function = + g_llvm_module.get_function_named('unary' + self.operator) return + g_llvm_builder.call(function, [operand], 'unop') + + This code is similar to, but simpler than, the code for binary operators. It is simpler primarily because it doesn't need to handle any @@ -351,74 +395,77 @@ this, we can do a lot of interesting things, including I/O, math, and a bunch of other things. For example, we can now add a nice sequencing operator (assuming we import ``putchard`` as described in Chapter 4): -{% highlight python %} ready> def binary : 1 (x y) 0 # Low-precedence -operator that ignores operands. ... ready> extern putchard(x) ... ready> -def printd(x) putchard(x) : putchard(10) .. ready> printd(65) : -printd(66) : printd(67) A B C Evaluated to: 0.0 {% endhighlight %} + +.. code-block:: python + + ready> def binary : 1 (x y) 0 # Low-precedence + operator that ignores operands. ... ready> extern putchard(x) ... ready> + def printd(x) putchard(x) : putchard(10) .. ready> printd(65) : + printd(66) : printd(67) A B C Evaluated to: 0.0 + + We can also define a bunch of other "primitive" operations, such as: -{% highlight python %} # Logical unary not. def unary!(v) if v then 0 -else 1 -Unary negate. -============= +.. code-block:: python -def unary-(v) 0-v + # Logical unary not. def unary!(v) if v then 0 + else 1 + + # Unary negate. + def unary-(v) 0-v + + # Define > with the same precedence as <. + def binary> 10 (LHS RHS) RHS < LHS + + # Binary logical or, which does not short circuit. + def binary\| 5 (LHS RHS) if LHS then 1 else if RHS then 1 else 0 + + # Binary logical and, which does not short circuit. + def binary& 6 (LHS RHS) if !LHS then 0 else !!RHS + + # Define = with slightly lower precedence than relationals. + def binary = 9 (LHS RHS) !(LHS < RHS \| LHS > RHS) + + -Define > with the same precedence as <. -======================================= -def binary> 10 (LHS RHS) RHS < LHS - -Binary logical or, which does not short circuit. -================================================ - -def binary\| 5 (LHS RHS) if LHS then 1 else if RHS then 1 else 0 - -Binary logical and, which does not short circuit. -================================================= - -def binary& 6 (LHS RHS) if !LHS then 0 else !!RHS - -Define = with slightly lower precedence than relationals. -========================================================= - -def binary = 9 (LHS RHS) !(LHS < RHS \| LHS > RHS) - -{% endhighlight %} Given the previous if/then/else support, we can also define interesting functions for I/O. For example, the following prints out a character whose "density" reflects the value passed in: the lower the value, the denser the character: -{% highlight python %} ready> -extern putchard(char) def printdensity(d) if d > 8 then putchard(32) # ' -' else if d > 4 then putchard(46) # '.' else if d > 2 then putchard(43) -# '+' else putchard(42); # '*' ... ready> printdensity(1): -printdensity(2): printdensity(3) : printdensity(4): printdensity(5): -printdensity(9): putchard(10)*\ ++.. Evaluated to 0.000000 {% -endhighlight %} +.. code-block:: python -Based on these simple primitive operations, we can start to define more -interesting things. For example, here's a little function that solves -for the number of iterations it takes a function in the complex plane to -converge: + ready> + + extern putchard(char) def printdensity(d) if d > 8 then putchard(32) # ' + ' else if d > 4 then putchard(46) # '.' else if d > 2 then putchard(43) + # '+' else putchard(42); # '*' ... ready> printdensity(1): + printdensity(2): printdensity(3) : printdensity(4): printdensity(5): + printdensity(9): putchard(10)*\ ++.. Evaluated to 0.000000 {% + endhighlight %} + + Based on these simple primitive operations, we can start to define more + interesting things. For example, here's a little function that solves + for the number of iterations it takes a function in the complex plane to + converge: + + {% highlight python %} # determine whether the specific location + diverges. # Solve for z = z^2 + c in the complex plane. def + mandelconverger(real imag iters creal cimag) if iters > 255 \| + (real\ *real + imag*\ imag > 4) then iters else + mandelconverger(real\ *real - imag*\ imag + creal, 2\ *real*\ imag + + cimag, iters+1, creal, cimag) + + # return the number of iterations required for the iteration to escape + def mandelconverge(real imag) mandelconverger(real, imag, 0, real, imag) + -{% highlight python %} # determine whether the specific location -diverges. # Solve for z = z^2 + c in the complex plane. def -mandelconverger(real imag iters creal cimag) if iters > 255 \| -(real\ *real + imag*\ imag > 4) then iters else -mandelconverger(real\ *real - imag*\ imag + creal, 2\ *real*\ imag + -cimag, iters+1, creal, cimag) -return the number of iterations required for the iteration to escape -==================================================================== - -def mandelconverge(real imag) mandelconverger(real, imag, 0, real, imag) -{% endhighlight %} This "z = z2 + c" function is a beautiful little creature that is the basis for computation of the `Mandelbrot @@ -430,175 +477,181 @@ two-dimensional plane, you can see the Mandelbrot set. Given that we are limited to using putchard here, our amazing graphical output is limited, but we can whip together something using the density plotter above: -{% highlight python %} # compute and plot the mandlebrot set with the -specified 2 dimensional range # info. def mandelhelp(xmin xmax xstep -ymin ymax ystep) for y = ymin, y < ymax, ystep in ( (for x = xmin, x < -xmax, xstep in printdensity(mandleconverge(x,y))) : putchard(10) ) -mandel - This is a convenient helper function for ploting the mandelbrot set -============================================================================ +.. code-block:: python + + # compute and plot the mandlebrot set with the + specified 2 dimensional range # info. def mandelhelp(xmin xmax xstep + ymin ymax ystep) for y = ymin, y < ymax, ystep in ( (for x = xmin, x < + xmax, xstep in printdensity(mandleconverge(x,y))) : putchard(10) ) + + # mandel - This is a convenient helper function for ploting the mandelbrot set + # from the specified position with the specified Magnification. + def mandel(realstart imagstart realmag imagmag) mandelhelp(realstart, + realstart+realmag\ *78, realmag, imagstart, imagstart+imagmag*\ 40, + imagmag); -from the specified position with the specified Magnification. -============================================================= -def mandel(realstart imagstart realmag imagmag) mandelhelp(realstart, -realstart+realmag\ *78, realmag, imagstart, imagstart+imagmag*\ 40, -imagmag); {% endhighlight %} Given this, we can try plotting out the mandlebrot set! Lets try it out: -{% highlight bash %} ready> mandel(-2.3, -1.3, 0.05, 0.07) -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++...++++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++.. -...+++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++++.. -..+++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++++. -..++++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++++++.... -..++++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++....... -.....++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++. . ... -.++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++... -++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++++++.... -.+++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++..+++++.... -..+++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++. .......... -+++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\*\*\*\*\*\*\*\*\*++++++++.. .. -.++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\*\*\*\*\*\*\*++++++++++... -.++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* \*\*\*\*\*\*\*\*++++++++++.. -.++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* \*\*\*\*\*\*\*++++++..... -..++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* \*\*\*\*\*\*\*+........ -...++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* \*\*\*\*\*\*\*+... .... -...++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* \*\*\*\*\*\*\*+++++...... -..++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* \*\*\*\*\*\*\*++++++++++... -.++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\*\*\*\*\*\*\*++++++++++... -++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\*\*\*\*\*\*\*\*+++++++++.. .. -..++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\*\*\*\*\*\*\*\*\*\*\*++++++.. .......... -+++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++...+++..... -..+++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++++++.... -..++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++... -+++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++++.. . ... -.++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++....... -......+++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++++++.... -..++++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++++.. -..++++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++++.. -...+++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++.. -...+++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++....+++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -Evaluated to 0.0 ready> mandel(-2, -1, 0.02, 0.04) -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++++++++++ -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++++++++++++ -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++++++++++++ -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++++++++++++++ -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++++++++++++++++++++ -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++++++++++++++++... -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++++++++++++++++++....... -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++++++++++++++.......... -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++++++++++++++++... -... -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++++++++++++++...... -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++++++++++++++....... -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++++++++++++++++++.......... -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++++++++++++++++........... -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++++++++++++++++++......... -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++...........+++++.............. -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++++++.... -......................... -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++++++++++++++.... ......... -............ \*\*\*\*\*\*\*\*\*\*\*+++++++++++++++++++++..... ...... -\*\*\*\*\*\*\*\*+++++++++++++++++++++++....... -\*\*\*\*\*\*+++++++++++++++++++++++++........ -\*\*\*\*+++++++++++++++++++++++++....... -***+++++++++++++++++++++++.........**\ ++++++++++++++++...........*\ ++++++++++++................ -\*++++.................... -*++++....................*\ ++++++++++++................ -**++++++++++++++++...........**\ *+++++++++++++++++++++++......... -\*\*\*\*+++++++++++++++++++++++++....... -\*\*\*\*\*\*+++++++++++++++++++++++++........ -\*\*\*\*\*\*\*\*+++++++++++++++++++++++....... -\*\*\*\*\*\*\*\*\*\*\*+++++++++++++++++++++..... ...... -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++++++++++++++.... ......... -............ \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++++++.... -......................... -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++...........+++++.............. -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++++++++++++++++++......... -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++++++++++++++++........... -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++++++++++++++++++.......... -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++++++++++++++....... -Evaluated to: 0.0 ready> mandel(-0.9, -1.4, 0.02, 0.03) -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++++++++++++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++++++++...++++++++++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++++++++++.. . -.++++++++++++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++++++++++... -......++++++++++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++++++++++++++++... -.......+++++++++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\*\*\*\*\*\*\*\*\*\*++++++++++++++++++++.... .... -..++++++++++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\*\*\*\*\*\*\*\*++++++++++++++++++++++...... -...++++++++++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\*\*\*\*\*\*+++++++++++++++++++++++....... -.....++++++++++++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\*\*\*\*++++++++++++++++++++++++....... -.....+++++++++++++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -\*\*\*\*+++++++++++++++++++++++++.... . -.....+++++++++++++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -**+++++++++++++++++++++++++.... -...++++++++++++++++**\ \*\*\*\*\*\*\*\*\*\*\**\ +++++++++++++++++++++++....... -....++++++++++++++++\*\*\*\*\*\*\*\*\*\*\*\* -+++++++++++++++++++++.......... -.....++++++++++++++++\*\*\*\*\*\*\*\*\*\*\* -++++++++++++++++++............. -.......+++++++++++++++\*\*\*\*\*\*\*\*\*\* -+++++++++++++++................ -............++++++++++\*\*\*\*\*\*\*\*\*\* -+++++++++++++................. .................+++++\*\*\*\*\*\*\*\*\* -+++++++++++... .... .......... .+++++\*\*\*\*\*\*\*\* ++++++++++..... -........ ...+++++\*\*\*\*\*\*\* ++++++++...... ..++++++\*\*\*\*\*\* -+++++++........ ..+++++\*\*\*\*\*\* +++++.......... ..++++++\*\*\*\*\* -++++.......... ....++++++\*\*\*\*\* ++.......... ....+++++++\*\*\*\* -.......... ......+++++++\ **\* .......... .....+++++++**\ \* .......... -.....++++++\ **\* ......... .+++++++** ........ .+++++++\ *\* ...... -...+++++++* . ....++++++++\* ...++++++++\* ..+++++++++ ..+++++++++ -Evaluated to: 0.0 ready> ^C {% endhighlight %} +.. code-block:: bash + + ready> mandel(-2.3, -1.3, 0.05, 0.07) + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++...++++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++.. + ...+++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++++.. + ..+++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++++. + ..++++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++++++.... + ..++++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++....... + .....++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++. . ... + .++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++... + ++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++++++.... + .+++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++..+++++.... + ..+++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++. .......... + +++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*++++++++.. .. + .++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*++++++++++... + .++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* \*\*\*\*\*\*\*\*++++++++++.. + .++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* \*\*\*\*\*\*\*++++++..... + ..++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* \*\*\*\*\*\*\*+........ + ...++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* \*\*\*\*\*\*\*+... .... + ...++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* \*\*\*\*\*\*\*+++++...... + ..++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* \*\*\*\*\*\*\*++++++++++... + .++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*++++++++++... + ++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*+++++++++.. .. + ..++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*++++++.. .......... + +++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++...+++..... + ..+++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++++++.... + ..++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++... + +++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++++.. . ... + .++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++....... + ......+++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++++++.... + ..++++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++++.. + ..++++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++++.. + ...+++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++.. + ...+++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++....+++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + Evaluated to 0.0 ready> mandel(-2, -1, 0.02, 0.04) + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++++++++++ + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++++++++++++ + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++++++++++++ + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++++++++++++++ + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++++++++++++++++++++ + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++++++++++++++++... + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++++++++++++++++++....... + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++++++++++++++.......... + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++++++++++++++++... + ... + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++++++++++++++...... + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++++++++++++++....... + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++++++++++++++++++.......... + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++++++++++++++++........... + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++++++++++++++++++......... + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++...........+++++.............. + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++++++.... + ......................... + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++++++++++++++.... ......... + ............ \*\*\*\*\*\*\*\*\*\*\*+++++++++++++++++++++..... ...... + \*\*\*\*\*\*\*\*+++++++++++++++++++++++....... + \*\*\*\*\*\*+++++++++++++++++++++++++........ + \*\*\*\*+++++++++++++++++++++++++....... + ***+++++++++++++++++++++++.........**\ ++++++++++++++++...........*\ ++++++++++++................ + \*++++.................... + + *++++....................*\ ++++++++++++................ + **++++++++++++++++...........**\ *+++++++++++++++++++++++......... + \*\*\*\*+++++++++++++++++++++++++....... + \*\*\*\*\*\*+++++++++++++++++++++++++........ + \*\*\*\*\*\*\*\*+++++++++++++++++++++++....... + \*\*\*\*\*\*\*\*\*\*\*+++++++++++++++++++++..... ...... + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++++++++++++++.... ......... + ............ \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++++++.... + ......................... + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++...........+++++.............. + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++++++++++++++++++......... + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++++++++++++++++........... + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++++++++++++++++++.......... + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++++++++++++++....... + Evaluated to: 0.0 ready> mandel(-0.9, -1.4, 0.02, 0.03) + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++++++++++++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++++++++...++++++++++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++++++++++.. . + .++++++++++++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++++++++++... + ......++++++++++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++++++++++++++++... + .......+++++++++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*++++++++++++++++++++.... .... + ..++++++++++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*++++++++++++++++++++++...... + ...++++++++++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*+++++++++++++++++++++++....... + .....++++++++++++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*++++++++++++++++++++++++....... + .....+++++++++++++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*+++++++++++++++++++++++++.... . + .....+++++++++++++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + **+++++++++++++++++++++++++.... + ...++++++++++++++++**\ \*\*\*\*\*\*\*\*\*\*\**\ +++++++++++++++++++++++....... + ....++++++++++++++++\*\*\*\*\*\*\*\*\*\*\*\* + +++++++++++++++++++++.......... + .....++++++++++++++++\*\*\*\*\*\*\*\*\*\*\* + ++++++++++++++++++............. + .......+++++++++++++++\*\*\*\*\*\*\*\*\*\* + +++++++++++++++................ + ............++++++++++\*\*\*\*\*\*\*\*\*\* + +++++++++++++................. .................+++++\*\*\*\*\*\*\*\*\* + +++++++++++... .... .......... .+++++\*\*\*\*\*\*\*\* ++++++++++..... + ........ ...+++++\*\*\*\*\*\*\* ++++++++...... ..++++++\*\*\*\*\*\* + +++++++........ ..+++++\*\*\*\*\*\* +++++.......... ..++++++\*\*\*\*\* + ++++.......... ....++++++\*\*\*\*\* ++.......... ....+++++++\*\*\*\* + .......... ......+++++++\ **\* .......... .....+++++++**\ \* .......... + .....++++++\ **\* ......... .+++++++** ........ .+++++++\ *\* ...... + ...+++++++* . ....++++++++\* ...++++++++\* ..+++++++++ ..+++++++++ + Evaluated to: 0.0 ready> ^C + + At this point, you may be starting to realize that Kaleidoscope is a real and powerful language. It may not be self-similar :), but it can be @@ -627,722 +680,678 @@ Full Code Listing # {#code} Here is the complete code listing for our running example, enhanced with the if/then/else and for expressions: -{% highlight python %} #!/usr/bin/env python -import re from llvm.core import Module, Constant, Type, Function, -Builder from llvm.ee import ExecutionEngine, TargetData from llvm.passes -import FunctionPassManager - -from llvm.core import FCMP\_ULT, FCMP\_ONE from llvm.passes import -(PASS\_INSTRUCTION\_COMBINING, PASS\_REASSOCIATE, PASS\_GVN, -PASS\_CFG\_SIMPLIFICATION) - -Globals -------- - -The LLVM module, which holds all the IR code. -============================================= - -g\_llvm\_module = Module.new('my cool jit') - -The LLVM instruction builder. Created whenever a new function is entered. -========================================================================= - -g\_llvm\_builder = None - -A dictionary that keeps track of which values are defined in the current scope -============================================================================== - -and what their LLVM representation is. -====================================== - -g\_named\_values = {} - -The function optimization passes manager. -========================================= - -g\_llvm\_pass\_manager = FunctionPassManager.new(g\_llvm\_module) - -The LLVM execution engine. -========================== - -g\_llvm\_executor = ExecutionEngine.new(g\_llvm\_module) - -The binary operator precedence chart. -===================================== - -g\_binop\_precedence = {} - -Lexer ------ - -The lexer yields one of these types for each token. -=================================================== - -class EOFToken(object): pass class DefToken(object): pass class -ExternToken(object): pass class IfToken(object): pass class -ThenToken(object): pass class ElseToken(object): pass class -ForToken(object): pass class InToken(object): pass class -BinaryToken(object): pass class UnaryToken(object): pass - -class IdentifierToken(object): def **init**\ (self, name): self.name = -name - -class NumberToken(object): def **init**\ (self, value): self.value = -value - -class CharacterToken(object): def **init**\ (self, char): self.char = -char def **eq**\ (self, other): return isinstance(other, CharacterToken) -and self.char == other.char def **ne**\ (self, other): return not self -== other - -Regular expressions that tokens and comments of our language. -============================================================= - -REGEX\_NUMBER = re.compile('[0-9]+(?:.[0-9]+)?') REGEX\_IDENTIFIER = -re.compile('[a-zA-Z][a-zA-Z0-9]\ *') REGEX\_COMMENT = re.compile('#.*') - -def Tokenize(string): while string: # Skip whitespace. if -string[0].isspace(): string = string[1:] continue - -:: - - # Run regexes. - comment_match = REGEX_COMMENT.match(string) - number_match = REGEX_NUMBER.match(string) - identifier_match = REGEX_IDENTIFIER.match(string) - - # Check if any of the regexes matched and yield the appropriate result. - if comment_match: - comment = comment_match.group(0) - string = string[len(comment):] - elif number_match: - number = number_match.group(0) - yield NumberToken(float(number)) - string = string[len(number):] - elif identifier_match: - identifier = identifier_match.group(0) - # Check if we matched a keyword. - if identifier == 'def': - yield DefToken() - elif identifier == 'extern': - yield ExternToken() - elif identifier == 'if': - yield IfToken() - elif identifier == 'then': - yield ThenToken() - elif identifier == 'else': - yield ElseToken() - elif identifier == 'for': - yield ForToken() - elif identifier == 'in': - yield InToken() - elif identifier == 'binary': - yield BinaryToken() - elif identifier == 'unary': - yield UnaryToken() - else: - yield IdentifierToken(identifier) - string = string[len(identifier):] - else: - # Yield the ASCII value of the unknown character. - yield CharacterToken(string[0]) - string = string[1:] - -yield EOFToken() - -Abstract Syntax Tree (aka Parse Tree) -------------------------------------- - -Base class for all expression nodes. -==================================== - -class ExpressionNode(object): pass - -Expression class for numeric literals like "1.0". -================================================= - -class NumberExpressionNode(ExpressionNode): - -def **init**\ (self, value): self.value = value - -def CodeGen(self): return Constant.real(Type.double(), self.value) - -Expression class for referencing a variable, like "a". -====================================================== - -class VariableExpressionNode(ExpressionNode): - -def **init**\ (self, name): self.name = name - -def CodeGen(self): if self.name in g\_named\_values: return -g\_named\_values[self.name] else: raise RuntimeError('Unknown variable -name: ' + self.name) - -Expression class for a binary operator. -======================================= - -class BinaryOperatorExpressionNode(ExpressionNode): - -def **init**\ (self, operator, left, right): self.operator = operator -self.left = left self.right = right - -def CodeGen(self): left = self.left.CodeGen() right = -self.right.CodeGen() - -:: - - if self.operator == '+': - return g_llvm_builder.fadd(left, right, 'addtmp') - elif self.operator == '-': - return g_llvm_builder.fsub(left, right, 'subtmp') - elif self.operator == '*': - return g_llvm_builder.fmul(left, right, 'multmp') - elif self.operator == '<': - result = g_llvm_builder.fcmp(FCMP_ULT, left, right, 'cmptmp') - # Convert bool 0 or 1 to double 0.0 or 1.0. - return g_llvm_builder.uitofp(result, Type.double(), 'booltmp') - else: - function = g_llvm_module.get_function_named('binary' + self.operator) - return g_llvm_builder.call(function, [left, right], 'binop') - -Expression class for function calls. -==================================== - -class CallExpressionNode(ExpressionNode): - -def **init**\ (self, callee, args): self.callee = callee self.args = -args - -def CodeGen(self): # Look up the name in the global module table. callee -= g\_llvm\_module.get\_function\_named(self.callee) - -:: - - # Check for argument mismatch error. - if len(callee.args) != len(self.args): - raise RuntimeError('Incorrect number of arguments passed.') - - arg_values = [i.CodeGen() for i in self.args] - - return g_llvm_builder.call(callee, arg_values, 'calltmp') - -Expression class for if/then/else. -================================== - -class IfExpressionNode(ExpressionNode): - -def **init**\ (self, condition, then\_branch, else\_branch): -self.condition = condition self.then\_branch = then\_branch -self.else\_branch = else\_branch - -def CodeGen(self): condition = self.condition.CodeGen() - -:: - - # Convert condition to a bool by comparing equal to 0.0. - condition_bool = g_llvm_builder.fcmp( - FCMP_ONE, condition, Constant.real(Type.double(), 0), 'ifcond') - - function = g_llvm_builder.basic_block.function - - # Create blocks for the then and else cases. Insert the 'then' block at the - # end of the function. - then_block = function.append_basic_block('then') - else_block = function.append_basic_block('else') - merge_block = function.append_basic_block('ifcond') - - g_llvm_builder.cbranch(condition_bool, then_block, else_block) - - # Emit then value. - g_llvm_builder.position_at_end(then_block) - then_value = self.then_branch.CodeGen() - g_llvm_builder.branch(merge_block) - - # Codegen of 'Then' can change the current block; update then_block for the - # PHI node. - then_block = g_llvm_builder.basic_block - - # Emit else block. - g_llvm_builder.position_at_end(else_block) - else_value = self.else_branch.CodeGen() - g_llvm_builder.branch(merge_block) - - # Codegen of 'Else' can change the current block, update else_block for the - # PHI node. - else_block = g_llvm_builder.basic_block - - # Emit merge block. - g_llvm_builder.position_at_end(merge_block) - phi = g_llvm_builder.phi(Type.double(), 'iftmp') - phi.add_incoming(then_value, then_block) - phi.add_incoming(else_value, else_block) - - return phi - -Expression class for for/in. -============================ - -class ForExpressionNode(ExpressionNode): - -def **init**\ (self, loop\_variable, start, end, step, body): -self.loop\_variable = loop\_variable self.start = start self.end = end -self.step = step self.body = body - -def CodeGen(self): # Output this as: # ... # start = startexpr # goto -loop # loop: # variable = phi [start, loopheader], [nextvariable, -loopend] # ... # bodyexpr # ... # loopend: # step = stepexpr # -nextvariable = variable + step # endcond = endexpr # br endcond, loop, -endloop # outloop: - -:: - - # Emit the start code first, without 'variable' in scope. - start_value = self.start.CodeGen() - - # Make the new basic block for the loop header, inserting after current - # block. - function = g_llvm_builder.basic_block.function - pre_header_block = g_llvm_builder.basic_block - loop_block = function.append_basic_block('loop') - - # Insert an explicit fallthrough from the current block to the loop_block. - g_llvm_builder.branch(loop_block) - - # Start insertion in loop_block. - g_llvm_builder.position_at_end(loop_block) - - # Start the PHI node with an entry for start. - variable_phi = g_llvm_builder.phi(Type.double(), self.loop_variable) - variable_phi.add_incoming(start_value, pre_header_block) - - # Within the loop, the variable is defined equal to the PHI node. If it - # shadows an existing variable, we have to restore it, so save it now. - old_value = g_named_values.get(self.loop_variable, None) - g_named_values[self.loop_variable] = variable_phi - - # Emit the body of the loop. This, like any other expr, can change the - # current BB. Note that we ignore the value computed by the body. - self.body.CodeGen() - - # Emit the step value. - if self.step: - step_value = self.step.CodeGen() - else: - # If not specified, use 1.0. - step_value = Constant.real(Type.double(), 1) - - next_value = g_llvm_builder.fadd(variable_phi, step_value, 'next') - - # Compute the end condition and convert it to a bool by comparing to 0.0. - end_condition = self.end.CodeGen() - end_condition_bool = g_llvm_builder.fcmp( - FCMP_ONE, end_condition, Constant.real(Type.double(), 0), 'loopcond') - - # Create the "after loop" block and insert it. - loop_end_block = g_llvm_builder.basic_block - after_block = function.append_basic_block('afterloop') - - # Insert the conditional branch into the end of loop_end_block. - g_llvm_builder.cbranch(end_condition_bool, loop_block, after_block) - - # Any new code will be inserted in after_block. - g_llvm_builder.position_at_end(after_block) - - # Add a new entry to the PHI node for the backedge. - variable_phi.add_incoming(next_value, loop_end_block) - - # Restore the unshadowed variable. - if old_value: - g_named_values[self.loop_variable] = old_value - else: - del g_named_values[self.loop_variable] - - # for expr always returns 0.0. - return Constant.real(Type.double(), 0) - -Expression class for a unary operator. -====================================== - -class UnaryExpressionNode(ExpressionNode): - -def **init**\ (self, operator, operand): self.operator = operator -self.operand = operand - -def CodeGen(self): operand = self.operand.CodeGen() function = -g\_llvm\_module.get\_function\_named('unary' + self.operator) return -g\_llvm\_builder.call(function, [operand], 'unop') - -This class represents the "prototype" for a function, which captures its name, -============================================================================== - -and its argument names (thus implicitly the number of arguments the function -============================================================================ - -takes), as well as if it is an operator. -======================================== - -class PrototypeNode(object): - -def **init**\ (self, name, args, is\_operator=False, precedence=0): -self.name = name self.args = args self.is\_operator = is\_operator -self.precedence = precedence - -def IsBinaryOp(self): return self.is\_operator and len(self.args) == 2 - -def GetOperatorName(self): assert self.is\_operator return self.name[-1] - -def CodeGen(self): # Make the function type, eg. double(double,double). -funct\_type = Type.function( Type.double(), [Type.double()] \* -len(self.args), False) - -:: - - function = Function.new(g_llvm_module, funct_type, self.name) - - # If the name conflicted, there was already something with the same name. - # If it has a body, don't allow redefinition or reextern. - if function.name != self.name: - function.delete() - function = g_llvm_module.get_function_named(self.name) - - # If the function already has a body, reject this. - if not function.is_declaration: - raise RuntimeError('Redefinition of function.') - - # If the function took a different number of args, reject. - if len(function.args) != len(self.args): - raise RuntimeError('Redeclaration of a function with different number ' - 'of args.') - - # Set names for all arguments and add them to the variables symbol table. - for arg, arg_name in zip(function.args, self.args): - arg.name = arg_name - # Add arguments to variable symbol table. - g_named_values[arg_name] = arg - - return function - -This class represents a function definition itself. -=================================================== - -class FunctionNode(object): - -def **init**\ (self, prototype, body): self.prototype = prototype -self.body = body - -def CodeGen(self): # Clear scope. g\_named\_values.clear() - -:: - - # Create a function object. - function = self.prototype.CodeGen() - - # If this is a binary operator, install its precedence. - if self.prototype.IsBinaryOp(): - operator = self.prototype.GetOperatorName() - g_binop_precedence[operator] = self.prototype.precedence - - # Create a new basic block to start insertion into. - block = function.append_basic_block('entry') - global g_llvm_builder - g_llvm_builder = Builder.new(block) - - # Finish off the function. - try: - return_value = self.body.CodeGen() - g_llvm_builder.ret(return_value) - - # Validate the generated code, checking for consistency. - function.verify() - - # Optimize the function. - g_llvm_pass_manager.run(function) - except: - function.delete() - if self.prototype.IsBinaryOp(): - del g_binop_precedence[self.prototype.GetOperatorName()] - raise - - return function - -Parser ------- - -class Parser(object): - -def **init**\ (self, tokens): self.tokens = tokens self.Next() - -# Provide a simple token buffer. Parser.current is the current token the -# parser is looking at. Parser.Next() reads another token from the lexer -and # updates Parser.current with its results. def Next(self): -self.current = self.tokens.next() - -# Gets the precedence of the current token, or -1 if the token is not a -binary # operator. def GetCurrentTokenPrecedence(self): if -isinstance(self.current, CharacterToken): return -g\_binop\_precedence.get(self.current.char, -1) else: return -1 - -# identifierexpr ::= identifier \| identifier '(' expression\* ')' def -ParseIdentifierExpr(self): identifier\_name = self.current.name -self.Next() # eat identifier. - -:: - - if self.current != CharacterToken('('): # Simple variable reference. - return VariableExpressionNode(identifier_name) - - # Call. - self.Next() # eat '('. - args = [] - if self.current != CharacterToken(')'): - while True: - args.append(self.ParseExpression()) - if self.current == CharacterToken(')'): - break - elif self.current != CharacterToken(','): - raise RuntimeError('Expected ")" or "," in argument list.') - self.Next() - - self.Next() # eat ')'. - return CallExpressionNode(identifier_name, args) - -# numberexpr ::= number def ParseNumberExpr(self): result = -NumberExpressionNode(self.current.value) self.Next() # consume the -number. return result - -# parenexpr ::= '(' expression ')' def ParseParenExpr(self): self.Next() -# eat '('. - -:: - - contents = self.ParseExpression() - - if self.current != CharacterToken(')'): - raise RuntimeError('Expected ")".') - self.Next() # eat ')'. - - return contents - -# ifexpr ::= 'if' expression 'then' expression 'else' expression def -ParseIfExpr(self): self.Next() # eat the if. - -:: - - # condition. - condition = self.ParseExpression() - - if not isinstance(self.current, ThenToken): - raise RuntimeError('Expected "then".') - self.Next() # eat the then. - - then_branch = self.ParseExpression() - - if not isinstance(self.current, ElseToken): - raise RuntimeError('Expected "else".') - self.Next() # eat the else. - - else_branch = self.ParseExpression() - - return IfExpressionNode(condition, then_branch, else_branch) - -# forexpr ::= 'for' identifier '=' expr ',' expr (',' expr)? 'in' -expression def ParseForExpr(self): self.Next() # eat the for. - -:: - - if not isinstance(self.current, IdentifierToken): - raise RuntimeError('Expected identifier after for.') - - loop_variable = self.current.name - self.Next() # eat the identifier. - - if self.current != CharacterToken('='): - raise RuntimeError('Expected "=" after for variable.') - self.Next() # eat the '='. - - start = self.ParseExpression() - - if self.current != CharacterToken(','): - raise RuntimeError('Expected "," after for start value.') - self.Next() # eat the ','. - - end = self.ParseExpression() - - # The step value is optional. - if self.current == CharacterToken(','): - self.Next() # eat the ','. - step = self.ParseExpression() - else: - step = None - - if not isinstance(self.current, InToken): - raise RuntimeError('Expected "in" after for variable specification.') - self.Next() # eat 'in'. - - body = self.ParseExpression() - - return ForExpressionNode(loop_variable, start, end, step, body) - -# primary ::= identifierexpr \| numberexpr \| parenexpr \| ifexpr \| -forexpr def ParsePrimary(self): if isinstance(self.current, -IdentifierToken): return self.ParseIdentifierExpr() elif -isinstance(self.current, NumberToken): return self.ParseNumberExpr() -elif isinstance(self.current, IfToken): return self.ParseIfExpr() elif -isinstance(self.current, ForToken): return self.ParseForExpr() elif -self.current == CharacterToken('('): return self.ParseParenExpr() else: -raise RuntimeError('Unknown token when expecting an expression.') - -# unary ::= primary \| unary\_operator unary def ParseUnary(self): # If -the current token is not an operator, it must be a primary expression. -if (not isinstance(self.current, CharacterToken) or self.current in -[CharacterToken('('), CharacterToken(',')]): return self.ParsePrimary() - -:: - - # If this is a unary operator, read it. - operator = self.current.char - self.Next() # eat the operator. - return UnaryExpressionNode(operator, self.ParseUnary()) - -# binoprhs ::= (binary\_operator unary)\* def ParseBinOpRHS(self, left, -left\_precedence): # If this is a binary operator, find its precedence. -while True: precedence = self.GetCurrentTokenPrecedence() - -:: - - # If this is a binary operator that binds at least as tightly as the - # current one, consume it; otherwise we are done. - if precedence < left_precedence: - return left - - binary_operator = self.current.char - self.Next() # eat the operator. - - # Parse the unary expression after the binary operator. - right = self.ParseUnary() - - # If binary_operator binds less tightly with right than the operator after - # right, let the pending operator take right as its left. - next_precedence = self.GetCurrentTokenPrecedence() - if precedence < next_precedence: - right = self.ParseBinOpRHS(right, precedence + 1) - - # Merge left/right. - left = BinaryOperatorExpressionNode(binary_operator, left, right) - -# expression ::= unary binoprhs def ParseExpression(self): left = -self.ParseUnary() return self.ParseBinOpRHS(left, 0) - -# prototype # ::= id '(' id\* ')' # ::= binary LETTER number? (id, id) # -::= unary LETTER (id) def ParsePrototype(self): precedence = None if -isinstance(self.current, IdentifierToken): kind = 'normal' -function\_name = self.current.name self.Next() # eat function name. elif -isinstance(self.current, UnaryToken): kind = 'unary' self.Next() # eat -'unary'. if not isinstance(self.current, CharacterToken): raise -RuntimeError('Expected an operator after "unary".') function\_name = -'unary' + self.current.char self.Next() # eat the operator. elif -isinstance(self.current, BinaryToken): kind = 'binary' self.Next() # eat -'binary'. if not isinstance(self.current, CharacterToken): raise -RuntimeError('Expected an operator after "binary".') function\_name = -'binary' + self.current.char self.Next() # eat the operator. if -isinstance(self.current, NumberToken): if not 1 <= self.current.value <= -100: raise RuntimeError('Invalid precedence: must be in range [1, -100].') precedence = self.current.value self.Next() # eat the -precedence. else: raise RuntimeError('Expected function name, "unary" or -"binary" in ' 'prototype.') - -:: - - if self.current != CharacterToken('('): - raise RuntimeError('Expected "(" in prototype.') - self.Next() # eat '('. - - arg_names = [] - while isinstance(self.current, IdentifierToken): - arg_names.append(self.current.name) - self.Next() - - if self.current != CharacterToken(')'): - raise RuntimeError('Expected ")" in prototype.') - - # Success. - self.Next() # eat ')'. - - if kind == 'unary' and len(arg_names) != 1: - raise RuntimeError('Invalid number of arguments for a unary operator.') - elif kind == 'binary' and len(arg_names) != 2: - raise RuntimeError('Invalid number of arguments for a binary operator.') - - return PrototypeNode(function_name, arg_names, kind != 'normal', precedence) - -# definition ::= 'def' prototype expression def ParseDefinition(self): -self.Next() # eat def. proto = self.ParsePrototype() body = -self.ParseExpression() return FunctionNode(proto, body) - -# toplevelexpr ::= expression def ParseTopLevelExpr(self): proto = -PrototypeNode('', []) return FunctionNode(proto, self.ParseExpression()) - -# external ::= 'extern' prototype def ParseExtern(self): self.Next() # -eat extern. return self.ParsePrototype() - -# Top-Level parsing def HandleDefinition(self): -self.Handle(self.ParseDefinition, 'Read a function definition:') - -def HandleExtern(self): self.Handle(self.ParseExtern, 'Read an extern:') - -def HandleTopLevelExpression(self): try: function = -self.ParseTopLevelExpr().CodeGen() result = -g\_llvm\_executor.run\_function(function, []) print 'Evaluated to:', -result.as\_real(Type.double()) except Exception, e: print 'Error:', e -try: self.Next() # Skip for error recovery. except: pass - -def Handle(self, function, message): try: print message, -function().CodeGen() except Exception, e: print 'Error:', e try: -self.Next() # Skip for error recovery. except: pass - -Main driver code. ------------------ - -def main(): # Set up the optimizer pipeline. Start with registering info -about how the # target lays out data structures. -g\_llvm\_pass\_manager.add(g\_llvm\_executor.target\_data) # Do simple -"peephole" optimizations and bit-twiddling optzns. -g\_llvm\_pass\_manager.add(PASS\_INSTRUCTION\_COMBINING) # Reassociate -expressions. g\_llvm\_pass\_manager.add(PASS\_REASSOCIATE) # Eliminate -Common SubExpressions. g\_llvm\_pass\_manager.add(PASS\_GVN) # Simplify -the control flow graph (deleting unreachable blocks, etc). -g\_llvm\_pass\_manager.add(PASS\_CFG\_SIMPLIFICATION) - -g\_llvm\_pass\_manager.initialize() - -# Install standard binary operators. # 1 is lowest possible precedence. -40 is the highest. g\_binop\_precedence['<'] = 10 -g\_binop\_precedence['+'] = 20 g\_binop\_precedence['-'] = 20 -g\_binop\_precedence['\*'] = 40 - -# Run the main "interpreter loop". while True: print 'ready>', try: raw -= raw\_input() except KeyboardInterrupt: break - -:: - - parser = Parser(Tokenize(raw)) - while True: - # top ::= definition | external | expression | EOF - if isinstance(parser.current, EOFToken): - break - if isinstance(parser.current, DefToken): - parser.HandleDefinition() - elif isinstance(parser.current, ExternToken): - parser.HandleExtern() - else: - parser.HandleTopLevelExpression() - -# Print out all of the generated code. print '', g\_llvm\_module - -if **name** == '**main**\ ': main() {% endhighlight %} - --------------- - -**`Next: Extending the language: mutable variables / SSA -construction `_** +.. code-block:: python + + #!/usr/bin/env python + + import re from llvm.core import Module, Constant, Type, Function, + Builder from llvm.ee import ExecutionEngine, TargetData from llvm.passes + import FunctionPassManager + + from llvm.core import FCMP_ULT, FCMP_ONE from llvm.passes import + (PASS_INSTRUCTION_COMBINING, PASS_REASSOCIATE, PASS_GVN, + PASS_CFG_SIMPLIFICATION) + + Globals + ------- + + # The LLVM module, which holds all the IR code. + g_llvm_module = Module.new('my cool jit') + + # The LLVM instruction builder. Created whenever a new function is entered. + g_llvm_builder = None + + # A dictionary that keeps track of which values are defined in the current scope + # and what their LLVM representation is. + g_named_values = {} + + # The function optimization passes manager. + g_llvm_pass_manager = FunctionPassManager.new(g_llvm_module) + + # The LLVM execution engine. + g_llvm_executor = ExecutionEngine.new(g_llvm_module) + + # The binary operator precedence chart. + g_binop_precedence = {} + + Lexer + ----- + + # The lexer yields one of these types for each token. + class EOFToken(object): pass class DefToken(object): pass class + ExternToken(object): pass class IfToken(object): pass class + ThenToken(object): pass class ElseToken(object): pass class + ForToken(object): pass class InToken(object): pass class + BinaryToken(object): pass class UnaryToken(object): pass + + class IdentifierToken(object): def **init**\ (self, name): self.name = + name + + class NumberToken(object): def **init**\ (self, value): self.value = + value + + class CharacterToken(object): def **init**\ (self, char): self.char = + char def **eq**\ (self, other): return isinstance(other, CharacterToken) + and self.char == other.char def **ne**\ (self, other): return not self + == other + + # Regular expressions that tokens and comments of our language. + REGEX_NUMBER = re.compile('[0-9]+(?:.[0-9]+)?') REGEX_IDENTIFIER = + re.compile('[a-zA-Z][a-zA-Z0-9]\ *') REGEX_COMMENT = re.compile('#.*') + + def Tokenize(string): while string: # Skip whitespace. if + string[0].isspace(): string = string[1:] continue + + :: + + # Run regexes. + comment_match = REGEX_COMMENT.match(string) + number_match = REGEX_NUMBER.match(string) + identifier_match = REGEX_IDENTIFIER.match(string) + + # Check if any of the regexes matched and yield the appropriate result. + if comment_match: + comment = comment_match.group(0) + string = string[len(comment):] + elif number_match: + number = number_match.group(0) + yield NumberToken(float(number)) + string = string[len(number):] + elif identifier_match: + identifier = identifier_match.group(0) + # Check if we matched a keyword. + if identifier == 'def': + yield DefToken() + elif identifier == 'extern': + yield ExternToken() + elif identifier == 'if': + yield IfToken() + elif identifier == 'then': + yield ThenToken() + elif identifier == 'else': + yield ElseToken() + elif identifier == 'for': + yield ForToken() + elif identifier == 'in': + yield InToken() + elif identifier == 'binary': + yield BinaryToken() + elif identifier == 'unary': + yield UnaryToken() + else: + yield IdentifierToken(identifier) + string = string[len(identifier):] + else: + # Yield the ASCII value of the unknown character. + yield CharacterToken(string[0]) + string = string[1:] + + yield EOFToken() + + Abstract Syntax Tree (aka Parse Tree) + ------------------------------------- + + # Base class for all expression nodes. + class ExpressionNode(object): pass + + # Expression class for numeric literals like "1.0". + class NumberExpressionNode(ExpressionNode): + + def **init**\ (self, value): self.value = value + + def CodeGen(self): return Constant.real(Type.double(), self.value) + + # Expression class for referencing a variable, like "a". + class VariableExpressionNode(ExpressionNode): + + def **init**\ (self, name): self.name = name + + def CodeGen(self): if self.name in g_named_values: return + g_named_values[self.name] else: raise RuntimeError('Unknown variable + name: ' + self.name) + + # Expression class for a binary operator. + class BinaryOperatorExpressionNode(ExpressionNode): + + def **init**\ (self, operator, left, right): self.operator = operator + self.left = left self.right = right + + def CodeGen(self): left = self.left.CodeGen() right = + self.right.CodeGen() + + :: + + if self.operator == '+': + return g_llvm_builder.fadd(left, right, 'addtmp') + elif self.operator == '-': + return g_llvm_builder.fsub(left, right, 'subtmp') + elif self.operator == '*': + return g_llvm_builder.fmul(left, right, 'multmp') + elif self.operator == '<': + result = g_llvm_builder.fcmp(FCMP_ULT, left, right, 'cmptmp') + # Convert bool 0 or 1 to double 0.0 or 1.0. + return g_llvm_builder.uitofp(result, Type.double(), 'booltmp') + else: + function = g_llvm_module.get_function_named('binary' + self.operator) + return g_llvm_builder.call(function, [left, right], 'binop') + + # Expression class for function calls. + class CallExpressionNode(ExpressionNode): + + def **init**\ (self, callee, args): self.callee = callee self.args = + args + + def CodeGen(self): # Look up the name in the global module table. callee + = g_llvm_module.get_function_named(self.callee) + + :: + + # Check for argument mismatch error. + if len(callee.args) != len(self.args): + raise RuntimeError('Incorrect number of arguments passed.') + + arg_values = [i.CodeGen() for i in self.args] + + return g_llvm_builder.call(callee, arg_values, 'calltmp') + + # Expression class for if/then/else. + class IfExpressionNode(ExpressionNode): + + def **init**\ (self, condition, then_branch, else_branch): + self.condition = condition self.then_branch = then_branch + self.else_branch = else_branch + + def CodeGen(self): condition = self.condition.CodeGen() + + :: + + # Convert condition to a bool by comparing equal to 0.0. + condition_bool = g_llvm_builder.fcmp( + FCMP_ONE, condition, Constant.real(Type.double(), 0), 'ifcond') + + function = g_llvm_builder.basic_block.function + + # Create blocks for the then and else cases. Insert the 'then' block at the + # end of the function. + then_block = function.append_basic_block('then') + else_block = function.append_basic_block('else') + merge_block = function.append_basic_block('ifcond') + + g_llvm_builder.cbranch(condition_bool, then_block, else_block) + + # Emit then value. + g_llvm_builder.position_at_end(then_block) + then_value = self.then_branch.CodeGen() + g_llvm_builder.branch(merge_block) + + # Codegen of 'Then' can change the current block; update then_block for the + # PHI node. + then_block = g_llvm_builder.basic_block + + # Emit else block. + g_llvm_builder.position_at_end(else_block) + else_value = self.else_branch.CodeGen() + g_llvm_builder.branch(merge_block) + + # Codegen of 'Else' can change the current block, update else_block for the + # PHI node. + else_block = g_llvm_builder.basic_block + + # Emit merge block. + g_llvm_builder.position_at_end(merge_block) + phi = g_llvm_builder.phi(Type.double(), 'iftmp') + phi.add_incoming(then_value, then_block) + phi.add_incoming(else_value, else_block) + + return phi + + # Expression class for for/in. + class ForExpressionNode(ExpressionNode): + + def **init**\ (self, loop_variable, start, end, step, body): + self.loop_variable = loop_variable self.start = start self.end = end + self.step = step self.body = body + + def CodeGen(self): # Output this as: # ... # start = startexpr # goto + loop # loop: # variable = phi [start, loopheader], [nextvariable, + loopend] # ... # bodyexpr # ... # loopend: # step = stepexpr # + nextvariable = variable + step # endcond = endexpr # br endcond, loop, + endloop # outloop: + + :: + + # Emit the start code first, without 'variable' in scope. + start_value = self.start.CodeGen() + + # Make the new basic block for the loop header, inserting after current + # block. + function = g_llvm_builder.basic_block.function + pre_header_block = g_llvm_builder.basic_block + loop_block = function.append_basic_block('loop') + + # Insert an explicit fallthrough from the current block to the loop_block. + g_llvm_builder.branch(loop_block) + + # Start insertion in loop_block. + g_llvm_builder.position_at_end(loop_block) + + # Start the PHI node with an entry for start. + variable_phi = g_llvm_builder.phi(Type.double(), self.loop_variable) + variable_phi.add_incoming(start_value, pre_header_block) + + # Within the loop, the variable is defined equal to the PHI node. If it + # shadows an existing variable, we have to restore it, so save it now. + old_value = g_named_values.get(self.loop_variable, None) + g_named_values[self.loop_variable] = variable_phi + + # Emit the body of the loop. This, like any other expr, can change the + # current BB. Note that we ignore the value computed by the body. + self.body.CodeGen() + + # Emit the step value. + if self.step: + step_value = self.step.CodeGen() + else: + # If not specified, use 1.0. + step_value = Constant.real(Type.double(), 1) + + next_value = g_llvm_builder.fadd(variable_phi, step_value, 'next') + + # Compute the end condition and convert it to a bool by comparing to 0.0. + end_condition = self.end.CodeGen() + end_condition_bool = g_llvm_builder.fcmp( + FCMP_ONE, end_condition, Constant.real(Type.double(), 0), 'loopcond') + + # Create the "after loop" block and insert it. + loop_end_block = g_llvm_builder.basic_block + after_block = function.append_basic_block('afterloop') + + # Insert the conditional branch into the end of loop_end_block. + g_llvm_builder.cbranch(end_condition_bool, loop_block, after_block) + + # Any new code will be inserted in after_block. + g_llvm_builder.position_at_end(after_block) + + # Add a new entry to the PHI node for the backedge. + variable_phi.add_incoming(next_value, loop_end_block) + + # Restore the unshadowed variable. + if old_value: + g_named_values[self.loop_variable] = old_value + else: + del g_named_values[self.loop_variable] + + # for expr always returns 0.0. + return Constant.real(Type.double(), 0) + + # Expression class for a unary operator. + class UnaryExpressionNode(ExpressionNode): + + def **init**\ (self, operator, operand): self.operator = operator + self.operand = operand + + def CodeGen(self): operand = self.operand.CodeGen() function = + g_llvm_module.get_function_named('unary' + self.operator) return + g_llvm_builder.call(function, [operand], 'unop') + + # This class represents the "prototype" for a function, which captures its name, + # and its argument names (thus implicitly the number of arguments the function + # takes), as well as if it is an operator. + class PrototypeNode(object): + + def **init**\ (self, name, args, is_operator=False, precedence=0): + self.name = name self.args = args self.is_operator = is_operator + self.precedence = precedence + + def IsBinaryOp(self): return self.is_operator and len(self.args) == 2 + + def GetOperatorName(self): assert self.is_operator return self.name[-1] + + def CodeGen(self): # Make the function type, eg. double(double,double). + funct_type = Type.function( Type.double(), [Type.double()] \* + len(self.args), False) + + :: + + function = Function.new(g_llvm_module, funct_type, self.name) + + # If the name conflicted, there was already something with the same name. + # If it has a body, don't allow redefinition or reextern. + if function.name != self.name: + function.delete() + function = g_llvm_module.get_function_named(self.name) + + # If the function already has a body, reject this. + if not function.is_declaration: + raise RuntimeError('Redefinition of function.') + + # If the function took a different number of args, reject. + if len(function.args) != len(self.args): + raise RuntimeError('Redeclaration of a function with different number ' + 'of args.') + + # Set names for all arguments and add them to the variables symbol table. + for arg, arg_name in zip(function.args, self.args): + arg.name = arg_name + # Add arguments to variable symbol table. + g_named_values[arg_name] = arg + + return function + + # This class represents a function definition itself. + class FunctionNode(object): + + def **init**\ (self, prototype, body): self.prototype = prototype + self.body = body + + def CodeGen(self): # Clear scope. g_named_values.clear() + + :: + + # Create a function object. + function = self.prototype.CodeGen() + + # If this is a binary operator, install its precedence. + if self.prototype.IsBinaryOp(): + operator = self.prototype.GetOperatorName() + g_binop_precedence[operator] = self.prototype.precedence + + # Create a new basic block to start insertion into. + block = function.append_basic_block('entry') + global g_llvm_builder + g_llvm_builder = Builder.new(block) + + # Finish off the function. + try: + return_value = self.body.CodeGen() + g_llvm_builder.ret(return_value) + + # Validate the generated code, checking for consistency. + function.verify() + + # Optimize the function. + g_llvm_pass_manager.run(function) + except: + function.delete() + if self.prototype.IsBinaryOp(): + del g_binop_precedence[self.prototype.GetOperatorName()] + raise + + return function + + Parser + ------ + + class Parser(object): + + def **init**\ (self, tokens): self.tokens = tokens self.Next() + + # Provide a simple token buffer. Parser.current is the current token the + # parser is looking at. Parser.Next() reads another token from the lexer + and # updates Parser.current with its results. def Next(self): + self.current = self.tokens.next() + + # Gets the precedence of the current token, or -1 if the token is not a + binary # operator. def GetCurrentTokenPrecedence(self): if + isinstance(self.current, CharacterToken): return + g_binop_precedence.get(self.current.char, -1) else: return -1 + + # identifierexpr ::= identifier \| identifier '(' expression\* ')' def + ParseIdentifierExpr(self): identifier_name = self.current.name + self.Next() # eat identifier. + + :: + + if self.current != CharacterToken('('): # Simple variable reference. + return VariableExpressionNode(identifier_name) + + # Call. + self.Next() # eat '('. + args = [] + if self.current != CharacterToken(')'): + while True: + args.append(self.ParseExpression()) + if self.current == CharacterToken(')'): + break + elif self.current != CharacterToken(','): + raise RuntimeError('Expected ")" or "," in argument list.') + self.Next() + + self.Next() # eat ')'. + return CallExpressionNode(identifier_name, args) + + # numberexpr ::= number def ParseNumberExpr(self): result = + NumberExpressionNode(self.current.value) self.Next() # consume the + number. return result + + # parenexpr ::= '(' expression ')' def ParseParenExpr(self): self.Next() + # eat '('. + + :: + + contents = self.ParseExpression() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")".') + self.Next() # eat ')'. + + return contents + + # ifexpr ::= 'if' expression 'then' expression 'else' expression def + ParseIfExpr(self): self.Next() # eat the if. + + :: + + # condition. + condition = self.ParseExpression() + + if not isinstance(self.current, ThenToken): + raise RuntimeError('Expected "then".') + self.Next() # eat the then. + + then_branch = self.ParseExpression() + + if not isinstance(self.current, ElseToken): + raise RuntimeError('Expected "else".') + self.Next() # eat the else. + + else_branch = self.ParseExpression() + + return IfExpressionNode(condition, then_branch, else_branch) + + # forexpr ::= 'for' identifier '=' expr ',' expr (',' expr)? 'in' + expression def ParseForExpr(self): self.Next() # eat the for. + + :: + + if not isinstance(self.current, IdentifierToken): + raise RuntimeError('Expected identifier after for.') + + loop_variable = self.current.name + self.Next() # eat the identifier. + + if self.current != CharacterToken('='): + raise RuntimeError('Expected "=" after for variable.') + self.Next() # eat the '='. + + start = self.ParseExpression() + + if self.current != CharacterToken(','): + raise RuntimeError('Expected "," after for start value.') + self.Next() # eat the ','. + + end = self.ParseExpression() + + # The step value is optional. + if self.current == CharacterToken(','): + self.Next() # eat the ','. + step = self.ParseExpression() + else: + step = None + + if not isinstance(self.current, InToken): + raise RuntimeError('Expected "in" after for variable specification.') + self.Next() # eat 'in'. + + body = self.ParseExpression() + + return ForExpressionNode(loop_variable, start, end, step, body) + + # primary ::= identifierexpr \| numberexpr \| parenexpr \| ifexpr \| + forexpr def ParsePrimary(self): if isinstance(self.current, + IdentifierToken): return self.ParseIdentifierExpr() elif + isinstance(self.current, NumberToken): return self.ParseNumberExpr() + elif isinstance(self.current, IfToken): return self.ParseIfExpr() elif + isinstance(self.current, ForToken): return self.ParseForExpr() elif + self.current == CharacterToken('('): return self.ParseParenExpr() else: + raise RuntimeError('Unknown token when expecting an expression.') + + # unary ::= primary \| unary_operator unary def ParseUnary(self): # If + the current token is not an operator, it must be a primary expression. + if (not isinstance(self.current, CharacterToken) or self.current in + [CharacterToken('('), CharacterToken(',')]): return self.ParsePrimary() + + :: + + # If this is a unary operator, read it. + operator = self.current.char + self.Next() # eat the operator. + return UnaryExpressionNode(operator, self.ParseUnary()) + + # binoprhs ::= (binary_operator unary)\* def ParseBinOpRHS(self, left, + left_precedence): # If this is a binary operator, find its precedence. + while True: precedence = self.GetCurrentTokenPrecedence() + + :: + + # If this is a binary operator that binds at least as tightly as the + # current one, consume it; otherwise we are done. + if precedence < left_precedence: + return left + + binary_operator = self.current.char + self.Next() # eat the operator. + + # Parse the unary expression after the binary operator. + right = self.ParseUnary() + + # If binary_operator binds less tightly with right than the operator after + # right, let the pending operator take right as its left. + next_precedence = self.GetCurrentTokenPrecedence() + if precedence < next_precedence: + right = self.ParseBinOpRHS(right, precedence + 1) + + # Merge left/right. + left = BinaryOperatorExpressionNode(binary_operator, left, right) + + # expression ::= unary binoprhs def ParseExpression(self): left = + self.ParseUnary() return self.ParseBinOpRHS(left, 0) + + # prototype # ::= id '(' id\* ')' # ::= binary LETTER number? (id, id) # + ::= unary LETTER (id) def ParsePrototype(self): precedence = None if + isinstance(self.current, IdentifierToken): kind = 'normal' + function_name = self.current.name self.Next() # eat function name. elif + isinstance(self.current, UnaryToken): kind = 'unary' self.Next() # eat + 'unary'. if not isinstance(self.current, CharacterToken): raise + RuntimeError('Expected an operator after "unary".') function_name = + 'unary' + self.current.char self.Next() # eat the operator. elif + isinstance(self.current, BinaryToken): kind = 'binary' self.Next() # eat + 'binary'. if not isinstance(self.current, CharacterToken): raise + RuntimeError('Expected an operator after "binary".') function_name = + 'binary' + self.current.char self.Next() # eat the operator. if + isinstance(self.current, NumberToken): if not 1 <= self.current.value <= + 100: raise RuntimeError('Invalid precedence: must be in range [1, + 100].') precedence = self.current.value self.Next() # eat the + precedence. else: raise RuntimeError('Expected function name, "unary" or + "binary" in ' 'prototype.') + + :: + + if self.current != CharacterToken('('): + raise RuntimeError('Expected "(" in prototype.') + self.Next() # eat '('. + + arg_names = [] + while isinstance(self.current, IdentifierToken): + arg_names.append(self.current.name) + self.Next() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")" in prototype.') + + # Success. + self.Next() # eat ')'. + + if kind == 'unary' and len(arg_names) != 1: + raise RuntimeError('Invalid number of arguments for a unary operator.') + elif kind == 'binary' and len(arg_names) != 2: + raise RuntimeError('Invalid number of arguments for a binary operator.') + + return PrototypeNode(function_name, arg_names, kind != 'normal', precedence) + + # definition ::= 'def' prototype expression def ParseDefinition(self): + self.Next() # eat def. proto = self.ParsePrototype() body = + self.ParseExpression() return FunctionNode(proto, body) + + # toplevelexpr ::= expression def ParseTopLevelExpr(self): proto = + PrototypeNode('', []) return FunctionNode(proto, self.ParseExpression()) + + # external ::= 'extern' prototype def ParseExtern(self): self.Next() # + eat extern. return self.ParsePrototype() + + # Top-Level parsing def HandleDefinition(self): + self.Handle(self.ParseDefinition, 'Read a function definition:') + + def HandleExtern(self): self.Handle(self.ParseExtern, 'Read an extern:') + + def HandleTopLevelExpression(self): try: function = + self.ParseTopLevelExpr().CodeGen() result = + g_llvm_executor.run_function(function, []) print 'Evaluated to:', + result.as_real(Type.double()) except Exception, e: print 'Error:', e + try: self.Next() # Skip for error recovery. except: pass + + def Handle(self, function, message): try: print message, + function().CodeGen() except Exception, e: print 'Error:', e try: + self.Next() # Skip for error recovery. except: pass + + Main driver code. + ----------------- + + def main(): # Set up the optimizer pipeline. Start with registering info + about how the # target lays out data structures. + g_llvm_pass_manager.add(g_llvm_executor.target_data) # Do simple + "peephole" optimizations and bit-twiddling optzns. + g_llvm_pass_manager.add(PASS_INSTRUCTION_COMBINING) # Reassociate + expressions. g_llvm_pass_manager.add(PASS_REASSOCIATE) # Eliminate + Common SubExpressions. g_llvm_pass_manager.add(PASS_GVN) # Simplify + the control flow graph (deleting unreachable blocks, etc). + g_llvm_pass_manager.add(PASS_CFG_SIMPLIFICATION) + + g_llvm_pass_manager.initialize() + + # Install standard binary operators. # 1 is lowest possible precedence. + 40 is the highest. g_binop_precedence['<'] = 10 + g_binop_precedence['+'] = 20 g_binop_precedence['-'] = 20 + g_binop_precedence['\*'] = 40 + + # Run the main "interpreter loop". while True: print 'ready>', try: raw + = raw_input() except KeyboardInterrupt: break + + :: + + parser = Parser(Tokenize(raw)) + while True: + # top ::= definition | external | expression | EOF + if isinstance(parser.current, EOFToken): + break + if isinstance(parser.current, DefToken): + parser.HandleDefinition() + elif isinstance(parser.current, ExternToken): + parser.HandleExtern() + else: + parser.HandleTopLevelExpression() + + # Print out all of the generated code. print '', g_llvm_module + + if **name** == '**main**\ ': main() diff --git a/docs/source/doc/kaleidoscope/PythonLangImpl7.rst b/docs/source/doc/kaleidoscope/PythonLangImpl7.rst index cc44969..576b5b4 100644 --- a/docs/source/doc/kaleidoscope/PythonLangImpl7.rst +++ b/docs/source/doc/kaleidoscope/PythonLangImpl7.rst @@ -37,20 +37,30 @@ Why is this a hard problem? # {#why} To understand why mutable variables cause complexities in SSA construction, consider this extremely simple C example: -{% highlight python %} int G, H; int test(\_Bool Condition) { int X; if -(Condition) X = G; else X = H; return X; } {% endhighlight %} + +.. code-block:: python + + int G, H; int test(_Bool Condition) { int X; if + (Condition) X = G; else X = H; return X; } + + In this case, we have the variable "X", whose value depends on the path executed in the program. Because there are two different possible values for X before the return instruction, a PHI node is inserted to merge the two values. The LLVM IR that we want for this example looks like this: -{% highlight llvm %} @G = weak global i32 0 ; type of @G is i32\* @H = -weak global i32 0 ; type of @H is i32\* define i32 @test(i1 %Condition) -{ entry: br i1 %Condition, label %cond\_true, label %cond\_false -cond\_true: %X.0 = load i32\* @G br label %cond\_next cond\_false: %X.1 -= load i32\* @H br label %cond\_next cond\_next: %X.2 = phi i32 [ %X.1, -%cond\_false ], [ %X.0, %cond\_true ] ret i32 %X.2 } {% endhighlight %} + +.. code-block:: llvm + + @G = weak global i32 0 ; type of @G is i32\* @H = + weak global i32 0 ; type of @H is i32\* define i32 @test(i1 %Condition) + { entry: br i1 %Condition, label %cond_true, label %cond_false + cond_true: %X.0 = load i32\* @G br label %cond_next cond_false: %X.1 + = load i32\* @H br label %cond_next cond_next: %X.2 = phi i32 [ %X.1, + %cond_false ], [ %X.0, %cond_true ] ret i32 %X.2 } + + In this example, the loads from the G and H global variables are explicit in the LLVM IR, and they live in the then/else branches of the @@ -98,10 +108,15 @@ work the same way, except that instead of being declared with global variable definitions, they are declared with the `LLVM alloca instruction `_: -{% highlight python %} define i32 @example() { entry: %X = alloca i32 ; -type of %X is i32\ *. ... %tmp = load i32* %X ; load the stack value %X -from the stack. %tmp2 = add i32 %tmp, 1 ; increment it store i32 %tmp2, -i32\* %X ; store it back ... {% endhighlight %} + +.. code-block:: python + + define i32 @example() { entry: %X = alloca i32 ; + type of %X is i32\ *. ... %tmp = load i32* %X ; load the stack value %X + from the stack. %tmp2 = add i32 %tmp, 1 ; increment it store i32 %tmp2, + i32\* %X ; store it back ... + + This code shows an example of how you can declare and manipulate a stack variable in the LLVM IR. Stack memory allocated with the alloca @@ -110,68 +125,78 @@ to functions, you can store it in other variables, etc. In our example above, we could rewrite the example to use the alloca technique to avoid using a PHI node: -{% highlight llvm %} @G = weak global i32 0 ; type of @G is i32\* @H = -weak global i32 0 ; type of @H is i32\* define i32 @test(i1 %Condition) -{ entry: %X = alloca i32 ; type of %X is i32\ *. br i1 %Condition, label -%cond\_true, label %cond\_false cond\_true: %X.0 = load i32* @G store -i32 %X.0, i32\* %X ; Update X br label %cond\_next cond\_false: %X.1 = -load i32\* @H store i32 %X.1, i32\* %X ; Update X br label %cond\_next -cond\_next: %X.2 = load i32\* %X ; Read X ret i32 %X.2 } {% endhighlight -%} -With this, we have discovered a way to handle arbitrary mutable -variables without the need to create Phi nodes at all: - -.. raw:: html +.. code-block:: llvm + @G = weak global i32 0 ; type of @G is i32\* @H = + weak global i32 0 ; type of @H is i32\* define i32 @test(i1 %Condition) + { entry: %X = alloca i32 ; type of %X is i32\ *. br i1 %Condition, label + %cond_true, label %cond_false cond_true: %X.0 = load i32* @G store + i32 %X.0, i32\* %X ; Update X br label %cond_next cond_false: %X.1 = + load i32\* @H store i32 %X.1, i32\* %X ; Update X br label %cond_next + cond_next: %X.2 = load i32\* %X ; Read X ret i32 %X.2 } {% endhighlight + %} + + With this, we have discovered a way to handle arbitrary mutable + variables without the need to create Phi nodes at all: + + .. raw:: html +
  1. - -Each mutable variable becomes a stack allocation. - -.. raw:: html - + + Each mutable variable becomes a stack allocation. + + .. raw:: html +
  2. - -Each read of the variable becomes a load from the stack. - -.. raw:: html - + + Each read of the variable becomes a load from the stack. + + .. raw:: html +
  3. - -Each update of the variable becomes a store to the stack. - -.. raw:: html - + + Each update of the variable becomes a store to the stack. + + .. raw:: html +
  4. - -Taking the address of a variable just uses the stack address directly. - -.. raw:: html - + + Taking the address of a variable just uses the stack address directly. + + .. raw:: html +
+ + While this solution has solved our immediate problem, it introduced + another one: we have now apparently introduced a lot of stack traffic + for very simple and common operations, a major performance problem. + Fortunately for us, the LLVM optimizer has a highly-tuned optimization + pass named "mem2reg" that handles this case, promoting allocas like this + into SSA registers, inserting Phi nodes as appropriate. If you run this + example through the pass, for example, you'll get: + + {% highlight bash %} $ llvm-as < example.ll \| opt -mem2reg \| llvm-dis + -While this solution has solved our immediate problem, it introduced -another one: we have now apparently introduced a lot of stack traffic -for very simple and common operations, a major performance problem. -Fortunately for us, the LLVM optimizer has a highly-tuned optimization -pass named "mem2reg" that handles this case, promoting allocas like this -into SSA registers, inserting Phi nodes as appropriate. If you run this -example through the pass, for example, you'll get: -{% highlight bash %} $ llvm-as < example.ll \| opt -mem2reg \| llvm-dis -{% endhighlight %} -{% highlight llvm %} @G = weak global i32 0 @H = weak global i32 0 -define i32 @test(i1 %Condition) { entry: br i1 %Condition, label -%cond\_true, label %cond\_false cond\_true: %X.0 = load i32\* @G br -label %cond\_next cond\_false: %X.1 = load i32\* @H br label %cond\_next -cond\_next: %X.01 = phi i32 [ %X.1, %cond\_false ], [ %X.0, %cond\_true -] ret i32 %X.01 } {% endhighlight %} + +.. code-block:: llvm + + @G = weak global i32 0 @H = weak global i32 0 + define i32 @test(i1 %Condition) { entry: br i1 %Condition, label + %cond_true, label %cond_false cond_true: %X.0 = load i32\* @G br + label %cond_next cond_false: %X.1 = load i32\* @H br label %cond_next + cond_next: %X.01 = phi i32 [ %X.1, %cond_false ], [ %X.0, %cond_true + ] ret i32 %X.01 } + + The mem2reg pass implements the standard "iterated dominance frontier" algorithm for constructing SSA form and has a number of optimizations @@ -249,25 +274,24 @@ redefining those only goes so far :). Also, the ability to define new variables is a useful thing regardless of whether you will be mutating them. Here's a motivating example that shows how we could use these: -{% highlight python %} # Define ':' for sequencing: as a low-precedence -operator that ignores operands # and just returns the RHS. def binary : -1 (x y) y; -Recursive fib, we could do this before. -======================================= +.. code-block:: python -def fib(x) if (x < 3) then 1 else fib(x-1) + fib(x-2) + # Define ':' for sequencing: as a low-precedence + operator that ignores operands # and just returns the RHS. def binary : + 1 (x y) y; + + # Recursive fib, we could do this before. + def fib(x) if (x < 3) then 1 else fib(x-1) + fib(x-2) + + # Iterative fib. + def fibi(x) var a = 1, b = 1, c in (for i = 3, i < x in c = a + b : a = + b : b = c) : b + + # Call it. + fibi(10) -Iterative fib. -============== -def fibi(x) var a = 1, b = 1, c in (for i = 3, i < x in c = a + b : a = -b : b = c) : b - -Call it. -======== - -fibi(10) {% endhighlight %} In order to mutate variables, we have to change our existing variables to use the "alloca trick". Once we have that, we'll add our new @@ -298,12 +322,17 @@ allocas that we will store in ``g_named_values``. We'll use a helper function that ensures that the allocas are created in the entry block of the function: -{% highlight python %} # Creates an alloca instruction in the entry -block of the function. This is used # for mutable variables. def -CreateEntryBlockAlloca(function, var\_name): entry = -function.get\_entry\_basic\_block() builder = Builder.new(entry) -builder.position\_at\_beginning(entry) return -builder.alloca(Type.double(), var\_name) {% endhighlight %} + +.. code-block:: python + + # Creates an alloca instruction in the entry + block of the function. This is used # for mutable variables. def + CreateEntryBlockAlloca(function, var_name): entry = + function.get_entry_basic_block() builder = Builder.new(entry) + builder.position_at_beginning(entry) return + builder.alloca(Type.double(), var_name) + + This code creates a temporary ``llvm.core.Builder`` that is pointing at the first instruction of the entry block. It then creates an alloca with @@ -315,46 +344,51 @@ variable references. In our new scheme, variables live on the stack, so code generating a reference to them actually needs to produce a load from the stack slot: -{% highlight python %} def CodeGen(self): if self.name in -g\_named\_values: return -g\_llvm\_builder.load(g\_named\_values[self.name], self.name) else: -raise RuntimeError('Unknown variable name: ' + self.name) {% -endhighlight %} -As you can see, this is pretty straightforward. Now we need to update -the things that define the variables to set up the alloca. We'll start -with ``ForExpressionNode.CodeGen`` (see the `full code listing <#code>`_ -for the unabridged code): +.. code-block:: python -{% highlight python %} def CodeGen(self): function = -g\_llvm\_builder.basic\_block.function + def CodeGen(self): if self.name in + g_named_values: return + g_llvm_builder.load(g_named_values[self.name], self.name) else: + raise RuntimeError('Unknown variable name: ' + self.name) {% + endhighlight %} + + As you can see, this is pretty straightforward. Now we need to update + the things that define the variables to set up the alloca. We'll start + with ``ForExpressionNode.CodeGen`` (see the `full code listing <#code>`_ + for the unabridged code): + + {% highlight python %} def CodeGen(self): function = + g_llvm_builder.basic_block.function + + :: + + # Create an alloca for the variable in the entry block. + alloca = CreateEntryBlockAlloca(function, self.loop_variable) + + # Emit the start code first, without 'variable' in scope. + start_value = self.start.CodeGen() + + # Store the value into the alloca. + g_llvm_builder.store(start_value, alloca) + ... + # Compute the end condition. + end_condition = self.end.CodeGen() + + # Reload, increment, and restore the alloca. This handles the case where + # the body of the loop mutates the variable. + cur_value = g_llvm_builder.load(alloca, self.loop_variable) + next_value = g_llvm_builder.fadd(cur_value, step_value, 'nextvar') + g_llvm_builder.store(next_value, alloca) + + # Convert condition to a bool by comparing equal to 0.0. + end_condition_bool = g_llvm_builder.fcmp( + FCMP_ONE, end_condition, Constant.real(Type.double(), 0), 'loopcond') + ... + + -:: - # Create an alloca for the variable in the entry block. - alloca = CreateEntryBlockAlloca(function, self.loop_variable) - - # Emit the start code first, without 'variable' in scope. - start_value = self.start.CodeGen() - - # Store the value into the alloca. - g_llvm_builder.store(start_value, alloca) - ... - # Compute the end condition. - end_condition = self.end.CodeGen() - - # Reload, increment, and restore the alloca. This handles the case where - # the body of the loop mutates the variable. - cur_value = g_llvm_builder.load(alloca, self.loop_variable) - next_value = g_llvm_builder.fadd(cur_value, step_value, 'nextvar') - g_llvm_builder.store(next_value, alloca) - - # Convert condition to a bool by comparing equal to 0.0. - end_condition_bool = g_llvm_builder.fcmp( - FCMP_ONE, end_condition, Constant.real(Type.double(), 0), 'loopcond') - ... - -{% endhighlight %} This code is virtually identical to the code `before we allowed mutable variables `_. The big difference is @@ -364,12 +398,17 @@ access the variable as needed. To support mutable argument variables, we need to also make allocas for them. The code for this is also pretty simple: -{% highlight python %} class PrototypeNode(object): ... # Create an -alloca for each argument and register the argument in the symbol # table -so that references to it will succeed. def CreateArgumentAllocas(self, -function): for arg\_name, arg in zip(self.args, function.args): alloca = -CreateEntryBlockAlloca(function, arg\_name) g\_llvm\_builder.store(arg, -alloca) g\_named\_values[arg\_name] = alloca {% endhighlight %} + +.. code-block:: python + + class PrototypeNode(object): ... # Create an + alloca for each argument and register the argument in the symbol # table + so that references to it will succeed. def CreateArgumentAllocas(self, + function): for arg_name, arg in zip(self.args, function.args): alloca = + CreateEntryBlockAlloca(function, arg_name) g_llvm_builder.store(arg, + alloca) g_named_values[arg_name] = alloca + + For each argument, we make an alloca, store the input value to the function into the alloca, and register the alloca as the memory location @@ -379,56 +418,61 @@ right after it sets up the entry block for the function. The final missing piece is adding the mem2reg pass, which allows us to get good codegen once again: -{% highlight python %} from llvm.passes import -(PASS\_PROMOTE\_MEMORY\_TO\_REGISTER, PASS\_INSTRUCTION\_COMBINING, -PASS\_REASSOCIATE, PASS\_GVN, PASS\_CFG\_SIMPLIFICATION) ... def main(): -# Set up the optimizer pipeline. Start with registering info about how -the # target lays out data structures. -g\_llvm\_pass\_manager.add(g\_llvm\_executor.target\_data) # Promote -allocas to registers. -g\_llvm\_pass\_manager.add(PASS\_PROMOTE\_MEMORY\_TO\_REGISTER) # Do -simple "peephole" optimizations and bit-twiddling optzns. -g\_llvm\_pass\_manager.add(PASS\_INSTRUCTION\_COMBINING) # Reassociate -expressions. g\_llvm\_pass\_manager.add(PASS\_REASSOCIATE) {% -endhighlight %} -It is interesting to see what the code looks like before and after the -mem2reg optimization runs. For example, this is the before/after code -for our recursive fib function. Before the optimization: +.. code-block:: python -{% highlight llvm %} define double @fib(double %x) { entry: %x1 = alloca -double store double %x, double\* %x1 %x2 = load double\* %x1 %cmptmp = -fcmp ult double %x2, 3.000000e+00 %booltmp = uitofp i1 %cmptmp to double -%ifcond = fcmp one double %booltmp, 0.000000e+00 br i1 %ifcond, label -%then, label %else then: ; preds = %entry br label %ifcont else: ; preds -= %entry %x3 = load double\* %x1 %subtmp = fsub double %x3, 1.000000e+00 -%calltmp = call double @fib(double %subtmp) %x4 = load double\* %x1 -%subtmp5 = fsub double %x4, 2.000000e+00 %calltmp6 = call double -@fib(double %subtmp5) %addtmp = fadd double %calltmp, %calltmp6 br label -%ifcont ifcont: ; preds = %else, %then %iftmp = phi double [ -1.000000e+00, %then ], [ %addtmp, %else ] ret double %iftmp } {% -endhighlight %} + from llvm.passes import + (PASS_PROMOTE_MEMORY_TO_REGISTER, PASS_INSTRUCTION_COMBINING, + PASS_REASSOCIATE, PASS_GVN, PASS_CFG_SIMPLIFICATION) ... def main(): + # Set up the optimizer pipeline. Start with registering info about how + the # target lays out data structures. + g_llvm_pass_manager.add(g_llvm_executor.target_data) # Promote + allocas to registers. + g_llvm_pass_manager.add(PASS_PROMOTE_MEMORY_TO_REGISTER) # Do + simple "peephole" optimizations and bit-twiddling optzns. + g_llvm_pass_manager.add(PASS_INSTRUCTION_COMBINING) # Reassociate + expressions. g_llvm_pass_manager.add(PASS_REASSOCIATE) {% + endhighlight %} + + It is interesting to see what the code looks like before and after the + mem2reg optimization runs. For example, this is the before/after code + for our recursive fib function. Before the optimization: + + {% highlight llvm %} define double @fib(double %x) { entry: %x1 = alloca + double store double %x, double\* %x1 %x2 = load double\* %x1 %cmptmp = + fcmp ult double %x2, 3.000000e+00 %booltmp = uitofp i1 %cmptmp to double + %ifcond = fcmp one double %booltmp, 0.000000e+00 br i1 %ifcond, label + %then, label %else then: ; preds = %entry br label %ifcont else: ; preds + = %entry %x3 = load double\* %x1 %subtmp = fsub double %x3, 1.000000e+00 + %calltmp = call double @fib(double %subtmp) %x4 = load double\* %x1 + %subtmp5 = fsub double %x4, 2.000000e+00 %calltmp6 = call double + @fib(double %subtmp5) %addtmp = fadd double %calltmp, %calltmp6 br label + %ifcont ifcont: ; preds = %else, %then %iftmp = phi double [ + 1.000000e+00, %then ], [ %addtmp, %else ] ret double %iftmp } {% + endhighlight %} + + Here there is only one variable (x, the input argument) but you can + still see the extremely simple-minded code generation strategy we are + using. In the entry block, an alloca is created, and the initial input + value is stored into it. Each reference to the variable does a reload + from the stack. Also, note that we didn't modify the if/then/else + expression, so it still inserts a PHI node. While we could make an + alloca for it, it is actually easier to create a PHI node for it, so we + still just make the PHI. + + Here is the code after the mem2reg pass runs: + + {% highlight llvm %} define double @fib(double %x) { entry: %cmptmp = + fcmp ult double %x, 3.000000e+00 %booltmp = uitofp i1 %cmptmp to double + %ifcond = fcmp one double %booltmp, 0.000000e+00 br i1 %ifcond, label + %then, label %else then: br label %ifcont else: %subtmp = fsub double + %x, 1.000000e+00 %calltmp = call double @fib(double %subtmp) %subtmp5 = + fsub double %x, 2.000000e+00 %calltmp6 = call double @fib(double + %subtmp5) %addtmp = fadd double %calltmp, %calltmp6 br label %ifcont + ifcont: ; preds = %else, %then %iftmp = phi double [ 1.000000e+00, %then + ], [ %addtmp, %else ] ret double %iftmp } -Here there is only one variable (x, the input argument) but you can -still see the extremely simple-minded code generation strategy we are -using. In the entry block, an alloca is created, and the initial input -value is stored into it. Each reference to the variable does a reload -from the stack. Also, note that we didn't modify the if/then/else -expression, so it still inserts a PHI node. While we could make an -alloca for it, it is actually easier to create a PHI node for it, so we -still just make the PHI. -Here is the code after the mem2reg pass runs: - -{% highlight llvm %} define double @fib(double %x) { entry: %cmptmp = -fcmp ult double %x, 3.000000e+00 %booltmp = uitofp i1 %cmptmp to double -%ifcond = fcmp one double %booltmp, 0.000000e+00 br i1 %ifcond, label -%then, label %else then: br label %ifcont else: %subtmp = fsub double -%x, 1.000000e+00 %calltmp = call double @fib(double %subtmp) %subtmp5 = -fsub double %x, 2.000000e+00 %calltmp6 = call double @fib(double -%subtmp5) %addtmp = fadd double %calltmp, %calltmp6 br label %ifcont -ifcont: ; preds = %else, %then %iftmp = phi double [ 1.000000e+00, %then -], [ %addtmp, %else ] ret double %iftmp } {% endhighlight %} This is a trivial case for mem2reg, since there are no redefinitions of the variable. The point of showing this is to calm your tension about @@ -436,14 +480,19 @@ inserting such blatent inefficiencies :). After the rest of the optimizers run, we get: -{% highlight llvm %} define double @fib(double %x) { entry: %cmptmp = -fcmp ult double %x, 3.000000e+00 %booltmp = uitofp i1 %cmptmp to double -%ifcond = fcmp ueq double %booltmp, 0.000000e+00 br i1 %ifcond, label -%else, label %ifcont else: %subtmp = fsub double %x, 1.000000e+00 -%calltmp = call double @fib(double %subtmp) %subtmp5 = fsub double %x, -2.000000e+00 %calltmp6 = call double @fib(double %subtmp5) %addtmp = -fadd double %calltmp, %calltmp6 ret double %addtmp ifcont: ret double -1.000000e+00 } {% endhighlight %} + +.. code-block:: llvm + + define double @fib(double %x) { entry: %cmptmp = + fcmp ult double %x, 3.000000e+00 %booltmp = uitofp i1 %cmptmp to double + %ifcond = fcmp ueq double %booltmp, 0.000000e+00 br i1 %ifcond, label + %else, label %ifcont else: %subtmp = fsub double %x, 1.000000e+00 + %calltmp = call double @fib(double %subtmp) %subtmp5 = fsub double %x, + 2.000000e+00 %calltmp6 = call double @fib(double %subtmp5) %addtmp = + fadd double %calltmp, %calltmp6 ret double %addtmp ifcont: ret double + 1.000000e+00 } + + Here we see that the simplifycfg pass decided to clone the return instruction into the end of the 'else' block. This allowed it to @@ -462,45 +511,50 @@ simple. We will parse it just like any other binary operator, but handle it internally (instead of allowing the user to define it). The first step is to set a precedence: -{% highlight python %} def main(): ... # Install standard binary -operators. # 1 is lowest possible precedence. 40 is the highest. -g\_binop\_precedence['='] = 2 g\_binop\_precedence['<'] = 10 -g\_binop\_precedence['+'] = 20 g\_binop\_precedence['-'] = 20 {% -endhighlight %} -Now that the parser knows the precedence of the binary operator, it -takes care of all the parsing and AST generation. We just need to -implement codegen for the assignment operator. This looks like: +.. code-block:: python -{% highlight python %} class -BinaryOperatorExpressionNode(ExpressionNode): ... def CodeGen(self): # A -special case for '=' because we don't want to emit the LHS as an # -expression. if self.operator == '=': # Assignment requires the LHS to be -an identifier. if not isinstance(self.left, VariableExpressionNode): -raise RuntimeError('Destination of "=" must be a variable.') {% -endhighlight %} + def main(): ... # Install standard binary + operators. # 1 is lowest possible precedence. 40 is the highest. + g_binop_precedence['='] = 2 g_binop_precedence['<'] = 10 + g_binop_precedence['+'] = 20 g_binop_precedence['-'] = 20 {% + endhighlight %} + + Now that the parser knows the precedence of the binary operator, it + takes care of all the parsing and AST generation. We just need to + implement codegen for the assignment operator. This looks like: + + {% highlight python %} class + BinaryOperatorExpressionNode(ExpressionNode): ... def CodeGen(self): # A + special case for '=' because we don't want to emit the LHS as an # + expression. if self.operator == '=': # Assignment requires the LHS to be + an identifier. if not isinstance(self.left, VariableExpressionNode): + raise RuntimeError('Destination of "=" must be a variable.') {% + endhighlight %} + + Unlike the rest of the binary operators, our assignment operator doesn't + follow the "emit LHS, emit RHS, do computation" model. As such, it is + handled as a special case before the other binary operators are handled. + The other strange thing is that it requires the LHS to be a variable. It + is invalid to have ``(x+1) = expr`` -- only things like ``x = expr`` are + allowed. + + {% highlight python %} # Codegen the RHS. value = self.right.CodeGen() + + :: + + # Look up the name. + variable = g_named_values[self.left.name] + + # Store the value and return it. + g_llvm_builder.store(value, variable) + + return value + ... + + -Unlike the rest of the binary operators, our assignment operator doesn't -follow the "emit LHS, emit RHS, do computation" model. As such, it is -handled as a special case before the other binary operators are handled. -The other strange thing is that it requires the LHS to be a variable. It -is invalid to have ``(x+1) = expr`` -- only things like ``x = expr`` are -allowed. -{% highlight python %} # Codegen the RHS. value = self.right.CodeGen() - -:: - - # Look up the name. - variable = g_named_values[self.left.name] - - # Store the value and return it. - g_llvm_builder.store(value, variable) - - return value - ... - -{% endhighlight %} Once we have the variable, CodeGening the assignment is straightforward: we emit the RHS of the assignment, create a store, and return the @@ -510,19 +564,20 @@ computed value. Returning a value allows for chained assignments like Now that we have an assignment operator, we can mutate loop variables and arguments. For example, we can now run code like this: -{% highlight python %} # Function to print a double. extern printd(x) -Define ':' for sequencing: as a low-precedence operator that ignores operands -============================================================================= +.. code-block:: python -and just returns the RHS. -========================= + # Function to print a double. extern printd(x) + + # Define ':' for sequencing: as a low-precedence operator that ignores operands + # and just returns the RHS. + def binary : 1 (x y) y + + def test(x) printd(x) : x = 4 : printd(x) + + test(123) -def binary : 1 (x y) y -def test(x) printd(x) : x = 4 : printd(x) - -test(123) {% endhighlight %} When run, this example prints "123" and then "4", showing that we did actually mutate the value! Okay, we have now officially implemented our @@ -541,21 +596,31 @@ generator. The first step for adding our new 'var/in' construct is to extend the lexer. As before, this is pretty trivial, the code looks like this: -{% highlight python %} ... class UnaryToken(object): pass class -VarToken(object): pass ... def Tokenize(string): ... elif identifier == -'unary': yield UnaryToken() elif identifier == 'var': yield VarToken() -else: yield IdentifierToken(identifier) {% endhighlight %} + +.. code-block:: python + + ... class UnaryToken(object): pass class + VarToken(object): pass ... def Tokenize(string): ... elif identifier == + 'unary': yield UnaryToken() elif identifier == 'var': yield VarToken() + else: yield IdentifierToken(identifier) + + The next step is to define the AST node that we will construct. For var/in, it looks like this: -{% highlight python %} # Expression class for var/in. class -VarExpressionNode(ExpressionNode): -def **init**\ (self, variables, body): self.variables = variables -self.body = body +.. code-block:: python + + # Expression class for var/in. class + VarExpressionNode(ExpressionNode): + + def **init**\ (self, variables, body): self.variables = variables + self.body = body + + def CodeGen(self): ... + -def CodeGen(self): ... {% endhighlight %} var/in allows a list of names to be defined all at once, and each name can optionally have an initializer value. As such, we capture this @@ -565,105 +630,130 @@ allowed to access the variables defined by the var/in. With this in place, we can define the parser pieces. The first thing we do is add it as a primary expression: -{% highlight python %} # primary ::= # dentifierexpr \| numberexpr \| -parenexpr \| ifexpr \| forexpr \| varexpr def ParsePrimary(self): if -isinstance(self.current, IdentifierToken): return -self.ParseIdentifierExpr() elif isinstance(self.current, NumberToken): -return self.ParseNumberExpr() elif isinstance(self.current, IfToken): -return self.ParseIfExpr() elif isinstance(self.current, ForToken): -return self.ParseForExpr() elif isinstance(self.current, VarToken): -return self.ParseVarExpr() elif self.current == CharacterToken('('): -return self.ParseParenExpr() else: raise RuntimeError('Unknown token -when expecting an expression.') {% endhighlight %} + +.. code-block:: python + + # primary ::= # dentifierexpr \| numberexpr \| + parenexpr \| ifexpr \| forexpr \| varexpr def ParsePrimary(self): if + isinstance(self.current, IdentifierToken): return + self.ParseIdentifierExpr() elif isinstance(self.current, NumberToken): + return self.ParseNumberExpr() elif isinstance(self.current, IfToken): + return self.ParseIfExpr() elif isinstance(self.current, ForToken): + return self.ParseForExpr() elif isinstance(self.current, VarToken): + return self.ParseVarExpr() elif self.current == CharacterToken('('): + return self.ParseParenExpr() else: raise RuntimeError('Unknown token + when expecting an expression.') + + Next we define ParseVarExpr: -{% highlight python %} # varexpr ::= 'var' (identifier ('=' -expression)?)+ 'in' expression def ParseVarExpr(self): self.Next() # eat -'var'. -:: +.. code-block:: python - variables = {} + # varexpr ::= 'var' (identifier ('=' + expression)?)+ 'in' expression def ParseVarExpr(self): self.Next() # eat + 'var'. + + :: + + variables = {} + + # At least one variable name is required. + if not isinstance(self.current, IdentifierToken): + raise RuntimeError('Expected identifier after "var".') + + - # At least one variable name is required. - if not isinstance(self.current, IdentifierToken): - raise RuntimeError('Expected identifier after "var".') -{% endhighlight %} The first part of this code parses the list of identifier/expr pairs into the local ``variables`` list. -{% highlight python %} while True: var\_name = self.current.name -self.Next() # eat the identifier. -:: +.. code-block:: python - # Read the optional initializer. - if self.current == CharacterToken('='): - self.Next() # eat '='. - variables[var_name] = self.ParseExpression() - else: - variables[var_name] = None + while True: var_name = self.current.name + self.Next() # eat the identifier. + + :: + + # Read the optional initializer. + if self.current == CharacterToken('='): + self.Next() # eat '='. + variables[var_name] = self.ParseExpression() + else: + variables[var_name] = None + + # End of var list, exit loop. + if self.current != CharacterToken(','): + break + self.Next() # eat ','. + + if not isinstance(self.current, IdentifierToken): + raise RuntimeError('Expected identifier after "," in a var expression.') + + - # End of var list, exit loop. - if self.current != CharacterToken(','): - break - self.Next() # eat ','. - if not isinstance(self.current, IdentifierToken): - raise RuntimeError('Expected identifier after "," in a var expression.') - -{% endhighlight %} Once all the variables are parsed, we then parse the body and create the AST node: -{% highlight python %} # At this point, we have to have 'in'. if not -isinstance(self.current, InToken): raise RuntimeError('Expected "in" -keyword after "var".') self.Next() # eat 'in'. -:: +.. code-block:: python - body = self.ParseExpression() + # At this point, we have to have 'in'. if not + isinstance(self.current, InToken): raise RuntimeError('Expected "in" + keyword after "var".') self.Next() # eat 'in'. + + :: + + body = self.ParseExpression() + + return VarExpressionNode(variables, body) + + - return VarExpressionNode(variables, body) -{% endhighlight %} Now that we can parse and represent the code, we need to support emission of LLVM IR for it. This code starts out with: -{% highlight python %} class VarExpressionNode(ExpressionNode): ... def -CodeGen(self): old\_bindings = {} function = -g\_llvm\_builder.basic\_block.function -:: +.. code-block:: python - # Register all variables and emit their initializer. - for var_name, var_expression in self.variables.iteritems(): - # Emit the initializer before adding the variable to scope, this prevents - # the initializer from referencing the variable itself, and permits stuff - # like this: - # var a = 1 in - # var a = a in ... # refers to outer 'a'. - if var_expression is not None: - var_value = var_expression.CodeGen() - else: - var_value = Constant.real(Type.double(), 0) + class VarExpressionNode(ExpressionNode): ... def + CodeGen(self): old_bindings = {} function = + g_llvm_builder.basic_block.function + + :: + + # Register all variables and emit their initializer. + for var_name, var_expression in self.variables.iteritems(): + # Emit the initializer before adding the variable to scope, this prevents + # the initializer from referencing the variable itself, and permits stuff + # like this: + # var a = 1 in + # var a = a in ... # refers to outer 'a'. + if var_expression is not None: + var_value = var_expression.CodeGen() + else: + var_value = Constant.real(Type.double(), 0) + + alloca = CreateEntryBlockAlloca(function, var_name) + g_llvm_builder.store(var_value, alloca) + + # Remember the old variable binding so that we can restore the binding + # when we unrecurse. + old_bindings[var_name] = g_named_values.get(var_name, None) + + # Remember this binding. + g_named_values[var_name] = alloca + + - alloca = CreateEntryBlockAlloca(function, var_name) - g_llvm_builder.store(var_value, alloca) - # Remember the old variable binding so that we can restore the binding - # when we unrecurse. - old_bindings[var_name] = g_named_values.get(var_name, None) - - # Remember this binding. - g_named_values[var_name] = alloca - -{% endhighlight %} Basically it loops over all the variables, installing them one at a time. For each variable we put into the symbol table, we remember the @@ -674,22 +764,32 @@ the initializer, create the alloca, then update the symbol table to point to it. Once all the variables are installed in the symbol table, we evaluate the body of the var/in expression: -{% highlight python %} # Codegen the body, now that all vars are in -scope. body = self.body.CodeGen() {% endhighlight %} + +.. code-block:: python + + # Codegen the body, now that all vars are in + scope. body = self.body.CodeGen() + + Finally, before returning, we restore the previous variable bindings: -{% highlight python %} # Pop all our variables from scope. for var\_name -in self.variables: if old\_bindings[var\_name] is not None: -g\_named\_values[var\_name] = old\_bindings[var\_name] else: del -g\_named\_values[var\_name] -:: +.. code-block:: python + + # Pop all our variables from scope. for var_name + in self.variables: if old_bindings[var_name] is not None: + g_named_values[var_name] = old_bindings[var_name] else: del + g_named_values[var_name] + + :: + + # Return the body computation. + return body + + - # Return the body computation. - return body -{% endhighlight %} The end result of all of this is that we get properly scoped variable definitions, and we even (trivially) allow mutation of them :). @@ -708,854 +808,804 @@ Full Code Listing # {#code} Here is the complete code listing for our running example, enhanced with mutable variables and var/in support: -{% highlight python %} #!/usr/bin/env python -import re from llvm.core import Module, Constant, Type, Function, -Builder from llvm.ee import ExecutionEngine, TargetData from llvm.passes -import FunctionPassManager - -from llvm.core import FCMP\_ULT, FCMP\_ONE from llvm.passes import -(PASS\_PROMOTE\_MEMORY\_TO\_REGISTER, PASS\_INSTRUCTION\_COMBINING, -PASS\_REASSOCIATE, PASS\_GVN, PASS\_CFG\_SIMPLIFICATION) - -Globals -------- - -The LLVM module, which holds all the IR code. -============================================= - -g\_llvm\_module = Module.new('my cool jit') - -The LLVM instruction builder. Created whenever a new function is entered. -========================================================================= - -g\_llvm\_builder = None - -A dictionary that keeps track of which values are defined in the current scope -============================================================================== - -and what their LLVM representation is. -====================================== - -g\_named\_values = {} - -The function optimization passes manager. -========================================= - -g\_llvm\_pass\_manager = FunctionPassManager.new(g\_llvm\_module) - -The LLVM execution engine. -========================== - -g\_llvm\_executor = ExecutionEngine.new(g\_llvm\_module) - -The binary operator precedence chart. -===================================== - -g\_binop\_precedence = {} - -Creates an alloca instruction in the entry block of the function. This is used -============================================================================== - -for mutable variables. -====================== - -def CreateEntryBlockAlloca(function, var\_name): entry = -function.get\_entry\_basic\_block() builder = Builder.new(entry) -builder.position\_at\_beginning(entry) return -builder.alloca(Type.double(), var\_name) - -Lexer ------ - -The lexer yields one of these types for each token. -=================================================== - -class EOFToken(object): pass class DefToken(object): pass class -ExternToken(object): pass class IfToken(object): pass class -ThenToken(object): pass class ElseToken(object): pass class -ForToken(object): pass class InToken(object): pass class -BinaryToken(object): pass class UnaryToken(object): pass class -VarToken(object): pass - -class IdentifierToken(object): def **init**\ (self, name): self.name = -name - -class NumberToken(object): def **init**\ (self, value): self.value = -value - -class CharacterToken(object): def **init**\ (self, char): self.char = -char def **eq**\ (self, other): return isinstance(other, CharacterToken) -and self.char == other.char def **ne**\ (self, other): return not self -== other - -Regular expressions that tokens and comments of our language. -============================================================= - -REGEX\_NUMBER = re.compile('[0-9]+(?:.[0-9]+)?') REGEX\_IDENTIFIER = -re.compile('[a-zA-Z][a-zA-Z0-9]\ *') REGEX\_COMMENT = re.compile('#.*') - -def Tokenize(string): while string: # Skip whitespace. if -string[0].isspace(): string = string[1:] continue - -:: - - # Run regexes. - comment_match = REGEX_COMMENT.match(string) - number_match = REGEX_NUMBER.match(string) - identifier_match = REGEX_IDENTIFIER.match(string) - - # Check if any of the regexes matched and yield the appropriate result. - if comment_match: - comment = comment_match.group(0) - string = string[len(comment):] - elif number_match: - number = number_match.group(0) - yield NumberToken(float(number)) - string = string[len(number):] - elif identifier_match: - identifier = identifier_match.group(0) - # Check if we matched a keyword. - if identifier == 'def': - yield DefToken() - elif identifier == 'extern': - yield ExternToken() - elif identifier == 'if': - yield IfToken() - elif identifier == 'then': - yield ThenToken() - elif identifier == 'else': - yield ElseToken() - elif identifier == 'for': - yield ForToken() - elif identifier == 'in': - yield InToken() - elif identifier == 'binary': - yield BinaryToken() - elif identifier == 'unary': - yield UnaryToken() - elif identifier == 'var': - yield VarToken() - else: - yield IdentifierToken(identifier) - string = string[len(identifier):] - else: - # Yield the ASCII value of the unknown character. - yield CharacterToken(string[0]) - string = string[1:] - -yield EOFToken() - -Abstract Syntax Tree (aka Parse Tree) -------------------------------------- - -Base class for all expression nodes. -==================================== - -class ExpressionNode(object): pass - -Expression class for numeric literals like "1.0". -================================================= - -class NumberExpressionNode(ExpressionNode): - -def **init**\ (self, value): self.value = value - -def CodeGen(self): return Constant.real(Type.double(), self.value) - -Expression class for referencing a variable, like "a". -====================================================== - -class VariableExpressionNode(ExpressionNode): - -def **init**\ (self, name): self.name = name - -def CodeGen(self): if self.name in g\_named\_values: return -g\_llvm\_builder.load(g\_named\_values[self.name], self.name) else: -raise RuntimeError('Unknown variable name: ' + self.name) - -Expression class for a binary operator. -======================================= - -class BinaryOperatorExpressionNode(ExpressionNode): - -def **init**\ (self, operator, left, right): self.operator = operator -self.left = left self.right = right - -def CodeGen(self): # A special case for '=' because we don't want to -emit the LHS as an # expression. if self.operator == '=': # Assignment -requires the LHS to be an identifier. if not isinstance(self.left, -VariableExpressionNode): raise RuntimeError('Destination of "=" must be -a variable.') - -:: - - # Codegen the RHS. - value = self.right.CodeGen() - - # Look up the name. - variable = g_named_values[self.left.name] - - # Store the value and return it. - g_llvm_builder.store(value, variable) - - return value - - left = self.left.CodeGen() - right = self.right.CodeGen() - - if self.operator == '+': - return g_llvm_builder.fadd(left, right, 'addtmp') - elif self.operator == '-': - return g_llvm_builder.fsub(left, right, 'subtmp') - elif self.operator == '*': - return g_llvm_builder.fmul(left, right, 'multmp') - elif self.operator == '<': - result = g_llvm_builder.fcmp(FCMP_ULT, left, right, 'cmptmp') - # Convert bool 0 or 1 to double 0.0 or 1.0. - return g_llvm_builder.uitofp(result, Type.double(), 'booltmp') - else: - function = g_llvm_module.get_function_named('binary' + self.operator) - return g_llvm_builder.call(function, [left, right], 'binop') - -Expression class for function calls. -==================================== - -class CallExpressionNode(ExpressionNode): - -def **init**\ (self, callee, args): self.callee = callee self.args = -args - -def CodeGen(self): # Look up the name in the global module table. callee -= g\_llvm\_module.get\_function\_named(self.callee) - -:: - - # Check for argument mismatch error. - if len(callee.args) != len(self.args): - raise RuntimeError('Incorrect number of arguments passed.') - - arg_values = [i.CodeGen() for i in self.args] - - return g_llvm_builder.call(callee, arg_values, 'calltmp') - -Expression class for if/then/else. -================================== - -class IfExpressionNode(ExpressionNode): - -def **init**\ (self, condition, then\_branch, else\_branch): -self.condition = condition self.then\_branch = then\_branch -self.else\_branch = else\_branch - -def CodeGen(self): condition = self.condition.CodeGen() - -:: - - # Convert condition to a bool by comparing equal to 0.0. - condition_bool = g_llvm_builder.fcmp( - FCMP_ONE, condition, Constant.real(Type.double(), 0), 'ifcond') - - function = g_llvm_builder.basic_block.function - - # Create blocks for the then and else cases. Insert the 'then' block at the - # end of the function. - then_block = function.append_basic_block('then') - else_block = function.append_basic_block('else') - merge_block = function.append_basic_block('ifcond') - - g_llvm_builder.cbranch(condition_bool, then_block, else_block) - - # Emit then value. - g_llvm_builder.position_at_end(then_block) - then_value = self.then_branch.CodeGen() - g_llvm_builder.branch(merge_block) - - # Codegen of 'Then' can change the current block; update then_block for the - # PHI node. - then_block = g_llvm_builder.basic_block - - # Emit else block. - g_llvm_builder.position_at_end(else_block) - else_value = self.else_branch.CodeGen() - g_llvm_builder.branch(merge_block) - - # Codegen of 'Else' can change the current block, update else_block for the - # PHI node. - else_block = g_llvm_builder.basic_block - - # Emit merge block. - g_llvm_builder.position_at_end(merge_block) - phi = g_llvm_builder.phi(Type.double(), 'iftmp') - phi.add_incoming(then_value, then_block) - phi.add_incoming(else_value, else_block) - - return phi - -Expression class for for/in. -============================ - -class ForExpressionNode(ExpressionNode): - -def **init**\ (self, loop\_variable, start, end, step, body): -self.loop\_variable = loop\_variable self.start = start self.end = end -self.step = step self.body = body - -def CodeGen(self): # Output this as: # var = alloca double # ... # start -= startexpr # store start -> var # goto loop # loop: # ... # bodyexpr # -... # loopend: # step = stepexpr # endcond = endexpr # # curvar = load -var # nextvar = curvar + step # store nextvar -> var # br endcond, loop, -endloop # outloop: - -:: - - function = g_llvm_builder.basic_block.function - - # Create an alloca for the variable in the entry block. - alloca = CreateEntryBlockAlloca(function, self.loop_variable) - - # Emit the start code first, without 'variable' in scope. - start_value = self.start.CodeGen() - - # Store the value into the alloca. - g_llvm_builder.store(start_value, alloca) - - # Make the new basic block for the loop, inserting after current block. - loop_block = function.append_basic_block('loop') - - # Insert an explicit fall through from the current block to the loop_block. - g_llvm_builder.branch(loop_block) - - # Start insertion in loop_block. - g_llvm_builder.position_at_end(loop_block) - - # Within the loop, the variable is defined equal to the alloca. If it - # shadows an existing variable, we have to restore it, so save it now. - old_value = g_named_values.get(self.loop_variable, None) - g_named_values[self.loop_variable] = alloca - - # Emit the body of the loop. This, like any other expr, can change the - # current BB. Note that we ignore the value computed by the body. - self.body.CodeGen() - - # Emit the step value. - if self.step: - step_value = self.step.CodeGen() - else: - # If not specified, use 1.0. - step_value = Constant.real(Type.double(), 1) - - # Compute the end condition. - end_condition = self.end.CodeGen() - - # Reload, increment, and restore the alloca. This handles the case where - # the body of the loop mutates the variable. - cur_value = g_llvm_builder.load(alloca, self.loop_variable) - next_value = g_llvm_builder.fadd(cur_value, step_value, 'nextvar') - g_llvm_builder.store(next_value, alloca) - - # Convert condition to a bool by comparing equal to 0.0. - end_condition_bool = g_llvm_builder.fcmp( - FCMP_ONE, end_condition, Constant.real(Type.double(), 0), 'loopcond') - - # Create the "after loop" block and insert it. - after_block = function.append_basic_block('afterloop') - - # Insert the conditional branch into the end of loop_block. - g_llvm_builder.cbranch(end_condition_bool, loop_block, after_block) - - # Any new code will be inserted in after_block. - g_llvm_builder.position_at_end(after_block) - - # Restore the unshadowed variable. - if old_value is not None: - g_named_values[self.loop_variable] = old_value - else: - del g_named_values[self.loop_variable] - - # for expr always returns 0.0. - return Constant.real(Type.double(), 0) - -Expression class for a unary operator. -====================================== - -class UnaryExpressionNode(ExpressionNode): - -def **init**\ (self, operator, operand): self.operator = operator -self.operand = operand - -def CodeGen(self): operand = self.operand.CodeGen() function = -g\_llvm\_module.get\_function\_named('unary' + self.operator) return -g\_llvm\_builder.call(function, [operand], 'unop') - -Expression class for var/in. -============================ - -class VarExpressionNode(ExpressionNode): - -def **init**\ (self, variables, body): self.variables = variables -self.body = body - -def CodeGen(self): old\_bindings = {} function = -g\_llvm\_builder.basic\_block.function - -:: - - # Register all variables and emit their initializer. - for var_name, var_expression in self.variables.iteritems(): - # Emit the initializer before adding the variable to scope, this prevents - # the initializer from referencing the variable itself, and permits stuff - # like this: - # var a = 1 in - # var a = a in ... # refers to outer 'a'. - if var_expression is not None: - var_value = var_expression.CodeGen() - else: - var_value = Constant.real(Type.double(), 0) - - alloca = CreateEntryBlockAlloca(function, var_name) - g_llvm_builder.store(var_value, alloca) - - # Remember the old variable binding so that we can restore the binding - # when we unrecurse. - old_bindings[var_name] = g_named_values.get(var_name, None) - - # Remember this binding. - g_named_values[var_name] = alloca - - # Codegen the body, now that all vars are in scope. - body = self.body.CodeGen() - - # Pop all our variables from scope. - for var_name in self.variables: - if old_bindings[var_name] is not None: - g_named_values[var_name] = old_bindings[var_name] - else: - del g_named_values[var_name] - - # Return the body computation. - return body - -This class represents the "prototype" for a function, which captures its name, -============================================================================== - -and its argument names (thus implicitly the number of arguments the function -============================================================================ - -takes), as well as if it is an operator. -======================================== - -class PrototypeNode(object): - -def **init**\ (self, name, args, is\_operator=False, precedence=0): -self.name = name self.args = args self.is\_operator = is\_operator -self.precedence = precedence - -def IsBinaryOp(self): return self.is\_operator and len(self.args) == 2 - -def GetOperatorName(self): assert self.is\_operator return self.name[-1] - -def CodeGen(self): # Make the function type, eg. double(double,double). -funct\_type = Type.function( Type.double(), [Type.double()] \* -len(self.args), False) - -:: - - function = Function.new(g_llvm_module, funct_type, self.name) - - # If the name conflicted, there was already something with the same name. - # If it has a body, don't allow redefinition or reextern. - if function.name != self.name: - function.delete() - function = g_llvm_module.get_function_named(self.name) - - # If the function already has a body, reject this. - if not function.is_declaration: - raise RuntimeError('Redefinition of function.') - - # If the function took a different number of args, reject. - if len(function.args) != len(self.args): - raise RuntimeError('Redeclaration of a function with different number ' - 'of args.') - - # Set names for all arguments and add them to the variables symbol table. - for arg, arg_name in zip(function.args, self.args): - arg.name = arg_name - - return function - -# Create an alloca for each argument and register the argument in the -symbol # table so that references to it will succeed. def -CreateArgumentAllocas(self, function): for arg\_name, arg in -zip(self.args, function.args): alloca = CreateEntryBlockAlloca(function, -arg\_name) g\_llvm\_builder.store(arg, alloca) -g\_named\_values[arg\_name] = alloca - -This class represents a function definition itself. -=================================================== - -class FunctionNode(object): - -def **init**\ (self, prototype, body): self.prototype = prototype -self.body = body - -def CodeGen(self): # Clear scope. g\_named\_values.clear() - -:: - - # Create a function object. - function = self.prototype.CodeGen() - - # If this is a binary operator, install its precedence. - if self.prototype.IsBinaryOp(): - operator = self.prototype.GetOperatorName() - g_binop_precedence[operator] = self.prototype.precedence - - # Create a new basic block to start insertion into. - block = function.append_basic_block('entry') - global g_llvm_builder - g_llvm_builder = Builder.new(block) - - # Add all arguments to the symbol table and create their allocas. - self.prototype.CreateArgumentAllocas(function) - - # Finish off the function. - try: - return_value = self.body.CodeGen() - g_llvm_builder.ret(return_value) - - # Validate the generated code, checking for consistency. - function.verify() - - # Optimize the function. - g_llvm_pass_manager.run(function) - except: - function.delete() - if self.prototype.IsBinaryOp(): - del g_binop_precedence[self.prototype.GetOperatorName()] - raise - - return function - -Parser ------- - -class Parser(object): - -def **init**\ (self, tokens): self.tokens = tokens self.Next() - -# Provide a simple token buffer. Parser.current is the current token the -# parser is looking at. Parser.Next() reads another token from the lexer -and # updates Parser.current with its results. def Next(self): -self.current = self.tokens.next() - -# Gets the precedence of the current token, or -1 if the token is not a -binary # operator. def GetCurrentTokenPrecedence(self): if -isinstance(self.current, CharacterToken): return -g\_binop\_precedence.get(self.current.char, -1) else: return -1 - -# identifierexpr ::= identifier \| identifier '(' expression\* ')' def -ParseIdentifierExpr(self): identifier\_name = self.current.name -self.Next() # eat identifier. - -:: - - if self.current != CharacterToken('('): # Simple variable reference. - return VariableExpressionNode(identifier_name) - - # Call. - self.Next() # eat '('. - args = [] - if self.current != CharacterToken(')'): - while True: - args.append(self.ParseExpression()) - if self.current == CharacterToken(')'): - break - elif self.current != CharacterToken(','): - raise RuntimeError('Expected ")" or "," in argument list.') - self.Next() - - self.Next() # eat ')'. - return CallExpressionNode(identifier_name, args) - -# numberexpr ::= number def ParseNumberExpr(self): result = -NumberExpressionNode(self.current.value) self.Next() # consume the -number. return result - -# parenexpr ::= '(' expression ')' def ParseParenExpr(self): self.Next() -# eat '('. - -:: - - contents = self.ParseExpression() - - if self.current != CharacterToken(')'): - raise RuntimeError('Expected ")".') - self.Next() # eat ')'. - - return contents - -# ifexpr ::= 'if' expression 'then' expression 'else' expression def -ParseIfExpr(self): self.Next() # eat the if. - -:: - - # condition. - condition = self.ParseExpression() - - if not isinstance(self.current, ThenToken): - raise RuntimeError('Expected "then".') - self.Next() # eat the then. - - then_branch = self.ParseExpression() - - if not isinstance(self.current, ElseToken): - raise RuntimeError('Expected "else".') - self.Next() # eat the else. - - else_branch = self.ParseExpression() - - return IfExpressionNode(condition, then_branch, else_branch) - -# forexpr ::= 'for' identifier '=' expr ',' expr (',' expr)? 'in' -expression def ParseForExpr(self): self.Next() # eat the for. - -:: - - if not isinstance(self.current, IdentifierToken): - raise RuntimeError('Expected identifier after for.') - - loop_variable = self.current.name - self.Next() # eat the identifier. - - if self.current != CharacterToken('='): - raise RuntimeError('Expected "=" after for variable.') - self.Next() # eat the '='. - - start = self.ParseExpression() - - if self.current != CharacterToken(','): - raise RuntimeError('Expected "," after for start value.') - self.Next() # eat the ','. - - end = self.ParseExpression() - - # The step value is optional. - if self.current == CharacterToken(','): - self.Next() # eat the ','. - step = self.ParseExpression() - else: - step = None - - if not isinstance(self.current, InToken): - raise RuntimeError('Expected "in" after for variable specification.') - self.Next() # eat 'in'. - - body = self.ParseExpression() - - return ForExpressionNode(loop_variable, start, end, step, body) - -# varexpr ::= 'var' (identifier ('=' expression)?)+ 'in' expression def -ParseVarExpr(self): self.Next() # eat 'var'. - -:: - - variables = {} - - # At least one variable name is required. - if not isinstance(self.current, IdentifierToken): - raise RuntimeError('Expected identifier after "var".') - - while True: - var_name = self.current.name - self.Next() # eat the identifier. - - # Read the optional initializer. - if self.current == CharacterToken('='): - self.Next() # eat '='. - variables[var_name] = self.ParseExpression() - else: - variables[var_name] = None - - # End of var list, exit loop. - if self.current != CharacterToken(','): - break - self.Next() # eat ','. - - if not isinstance(self.current, IdentifierToken): - raise RuntimeError('Expected identifier after "," in a var expression.') - - # At this point, we have to have 'in'. - if not isinstance(self.current, InToken): - raise RuntimeError('Expected "in" keyword after "var".') - self.Next() # eat 'in'. - - body = self.ParseExpression() - - return VarExpressionNode(variables, body) - -# primary ::= # dentifierexpr \| numberexpr \| parenexpr \| ifexpr \| -forexpr \| varexpr def ParsePrimary(self): if isinstance(self.current, -IdentifierToken): return self.ParseIdentifierExpr() elif -isinstance(self.current, NumberToken): return self.ParseNumberExpr() -elif isinstance(self.current, IfToken): return self.ParseIfExpr() elif -isinstance(self.current, ForToken): return self.ParseForExpr() elif -isinstance(self.current, VarToken): return self.ParseVarExpr() elif -self.current == CharacterToken('('): return self.ParseParenExpr() else: -raise RuntimeError('Unknown token when expecting an expression.') - -# unary ::= primary \| unary\_operator unary def ParseUnary(self): # If -the current token is not an operator, it must be a primary expression. -if (not isinstance(self.current, CharacterToken) or self.current in -[CharacterToken('('), CharacterToken(',')]): return self.ParsePrimary() - -:: - - # If this is a unary operator, read it. - operator = self.current.char - self.Next() # eat the operator. - return UnaryExpressionNode(operator, self.ParseUnary()) - -# binoprhs ::= (binary\_operator unary)\* def ParseBinOpRHS(self, left, -left\_precedence): # If this is a binary operator, find its precedence. -while True: precedence = self.GetCurrentTokenPrecedence() - -:: - - # If this is a binary operator that binds at least as tightly as the - # current one, consume it; otherwise we are done. - if precedence < left_precedence: - return left - - binary_operator = self.current.char - self.Next() # eat the operator. - - # Parse the unary expression after the binary operator. - right = self.ParseUnary() - - # If binary_operator binds less tightly with right than the operator after - # right, let the pending operator take right as its left. - next_precedence = self.GetCurrentTokenPrecedence() - if precedence < next_precedence: - right = self.ParseBinOpRHS(right, precedence + 1) - - # Merge left/right. - left = BinaryOperatorExpressionNode(binary_operator, left, right) - -# expression ::= unary binoprhs def ParseExpression(self): left = -self.ParseUnary() return self.ParseBinOpRHS(left, 0) - -# prototype # ::= id '(' id\* ')' # ::= binary LETTER number? (id, id) # -::= unary LETTER (id) def ParsePrototype(self): precedence = None if -isinstance(self.current, IdentifierToken): kind = 'normal' -function\_name = self.current.name self.Next() # eat function name. elif -isinstance(self.current, UnaryToken): kind = 'unary' self.Next() # eat -'unary'. if not isinstance(self.current, CharacterToken): raise -RuntimeError('Expected an operator after "unary".') function\_name = -'unary' + self.current.char self.Next() # eat the operator. elif -isinstance(self.current, BinaryToken): kind = 'binary' self.Next() # eat -'binary'. if not isinstance(self.current, CharacterToken): raise -RuntimeError('Expected an operator after "binary".') function\_name = -'binary' + self.current.char self.Next() # eat the operator. if -isinstance(self.current, NumberToken): if not 1 <= self.current.value <= -100: raise RuntimeError('Invalid precedence: must be in range [1, -100].') precedence = self.current.value self.Next() # eat the -precedence. else: raise RuntimeError('Expected function name, "unary" or -"binary" in ' 'prototype.') - -:: - - if self.current != CharacterToken('('): - raise RuntimeError('Expected "(" in prototype.') - self.Next() # eat '('. - - arg_names = [] - while isinstance(self.current, IdentifierToken): - arg_names.append(self.current.name) - self.Next() - - if self.current != CharacterToken(')'): - raise RuntimeError('Expected ")" in prototype.') - - # Success. - self.Next() # eat ')'. - - if kind == 'unary' and len(arg_names) != 1: - raise RuntimeError('Invalid number of arguments for a unary operator.') - elif kind == 'binary' and len(arg_names) != 2: - raise RuntimeError('Invalid number of arguments for a binary operator.') - - return PrototypeNode(function_name, arg_names, kind != 'normal', precedence) - -# definition ::= 'def' prototype expression def ParseDefinition(self): -self.Next() # eat def. proto = self.ParsePrototype() body = -self.ParseExpression() return FunctionNode(proto, body) - -# toplevelexpr ::= expression def ParseTopLevelExpr(self): proto = -PrototypeNode('', []) return FunctionNode(proto, self.ParseExpression()) - -# external ::= 'extern' prototype def ParseExtern(self): self.Next() # -eat extern. return self.ParsePrototype() - -# Top-Level parsing def HandleDefinition(self): -self.Handle(self.ParseDefinition, 'Read a function definition:') - -def HandleExtern(self): self.Handle(self.ParseExtern, 'Read an extern:') - -def HandleTopLevelExpression(self): try: function = -self.ParseTopLevelExpr().CodeGen() result = -g\_llvm\_executor.run\_function(function, []) print 'Evaluated to:', -result.as\_real(Type.double()) except Exception, e: raise#print -'Error:', e try: self.Next() # Skip for error recovery. except: pass - -def Handle(self, function, message): try: print message, -function().CodeGen() except Exception, e: raise#print 'Error:', e try: -self.Next() # Skip for error recovery. except: pass - -Main driver code. ------------------ - -def main(): # Set up the optimizer pipeline. Start with registering info -about how the # target lays out data structures. -g\_llvm\_pass\_manager.add(g\_llvm\_executor.target\_data) # Promote -allocas to registers. -g\_llvm\_pass\_manager.add(PASS\_PROMOTE\_MEMORY\_TO\_REGISTER) # Do -simple "peephole" optimizations and bit-twiddling optzns. -g\_llvm\_pass\_manager.add(PASS\_INSTRUCTION\_COMBINING) # Reassociate -expressions. g\_llvm\_pass\_manager.add(PASS\_REASSOCIATE) # Eliminate -Common SubExpressions. g\_llvm\_pass\_manager.add(PASS\_GVN) # Simplify -the control flow graph (deleting unreachable blocks, etc). -g\_llvm\_pass\_manager.add(PASS\_CFG\_SIMPLIFICATION) - -g\_llvm\_pass\_manager.initialize() - -# Install standard binary operators. # 1 is lowest possible precedence. -40 is the highest. g\_binop\_precedence['='] = 2 -g\_binop\_precedence['<'] = 10 g\_binop\_precedence['+'] = 20 -g\_binop\_precedence['-'] = 20 g\_binop\_precedence['\*'] = 40 - -# Run the main "interpreter loop". while True: print 'ready<', try: raw -= raw\_input() except KeyboardInterrupt: break - -:: - - parser = Parser(Tokenize(raw)) - while True: - # top ::= definition | external | expression | EOF - if isinstance(parser.current, EOFToken): - break - if isinstance(parser.current, DefToken): - parser.HandleDefinition() - elif isinstance(parser.current, ExternToken): - parser.HandleExtern() - else: - parser.HandleTopLevelExpression() - -# Print out all of the generated code. print '', g\_llvm\_module - -if **name** == '**main**\ ': main() {% endhighlight %} - --------------- - -**`Next: Conclusion and other useful LLVM -tidbits `_** +.. code-block:: python + + #!/usr/bin/env python + + import re from llvm.core import Module, Constant, Type, Function, + Builder from llvm.ee import ExecutionEngine, TargetData from llvm.passes + import FunctionPassManager + + from llvm.core import FCMP_ULT, FCMP_ONE from llvm.passes import + (PASS_PROMOTE_MEMORY_TO_REGISTER, PASS_INSTRUCTION_COMBINING, + PASS_REASSOCIATE, PASS_GVN, PASS_CFG_SIMPLIFICATION) + + Globals + ------- + + # The LLVM module, which holds all the IR code. + g_llvm_module = Module.new('my cool jit') + + # The LLVM instruction builder. Created whenever a new function is entered. + g_llvm_builder = None + + # A dictionary that keeps track of which values are defined in the current scope + # and what their LLVM representation is. + g_named_values = {} + + # The function optimization passes manager. + g_llvm_pass_manager = FunctionPassManager.new(g_llvm_module) + + # The LLVM execution engine. + g_llvm_executor = ExecutionEngine.new(g_llvm_module) + + # The binary operator precedence chart. + g_binop_precedence = {} + + # Creates an alloca instruction in the entry block of the function. This is used + # for mutable variables. + def CreateEntryBlockAlloca(function, var_name): entry = + function.get_entry_basic_block() builder = Builder.new(entry) + builder.position_at_beginning(entry) return + builder.alloca(Type.double(), var_name) + + Lexer + ----- + + # The lexer yields one of these types for each token. + class EOFToken(object): pass class DefToken(object): pass class + ExternToken(object): pass class IfToken(object): pass class + ThenToken(object): pass class ElseToken(object): pass class + ForToken(object): pass class InToken(object): pass class + BinaryToken(object): pass class UnaryToken(object): pass class + VarToken(object): pass + + class IdentifierToken(object): def **init**\ (self, name): self.name = + name + + class NumberToken(object): def **init**\ (self, value): self.value = + value + + class CharacterToken(object): def **init**\ (self, char): self.char = + char def **eq**\ (self, other): return isinstance(other, CharacterToken) + and self.char == other.char def **ne**\ (self, other): return not self + == other + + # Regular expressions that tokens and comments of our language. + REGEX_NUMBER = re.compile('[0-9]+(?:.[0-9]+)?') REGEX_IDENTIFIER = + re.compile('[a-zA-Z][a-zA-Z0-9]\ *') REGEX_COMMENT = re.compile('#.*') + + def Tokenize(string): while string: # Skip whitespace. if + string[0].isspace(): string = string[1:] continue + + :: + + # Run regexes. + comment_match = REGEX_COMMENT.match(string) + number_match = REGEX_NUMBER.match(string) + identifier_match = REGEX_IDENTIFIER.match(string) + + # Check if any of the regexes matched and yield the appropriate result. + if comment_match: + comment = comment_match.group(0) + string = string[len(comment):] + elif number_match: + number = number_match.group(0) + yield NumberToken(float(number)) + string = string[len(number):] + elif identifier_match: + identifier = identifier_match.group(0) + # Check if we matched a keyword. + if identifier == 'def': + yield DefToken() + elif identifier == 'extern': + yield ExternToken() + elif identifier == 'if': + yield IfToken() + elif identifier == 'then': + yield ThenToken() + elif identifier == 'else': + yield ElseToken() + elif identifier == 'for': + yield ForToken() + elif identifier == 'in': + yield InToken() + elif identifier == 'binary': + yield BinaryToken() + elif identifier == 'unary': + yield UnaryToken() + elif identifier == 'var': + yield VarToken() + else: + yield IdentifierToken(identifier) + string = string[len(identifier):] + else: + # Yield the ASCII value of the unknown character. + yield CharacterToken(string[0]) + string = string[1:] + + yield EOFToken() + + Abstract Syntax Tree (aka Parse Tree) + ------------------------------------- + + # Base class for all expression nodes. + class ExpressionNode(object): pass + + # Expression class for numeric literals like "1.0". + class NumberExpressionNode(ExpressionNode): + + def **init**\ (self, value): self.value = value + + def CodeGen(self): return Constant.real(Type.double(), self.value) + + # Expression class for referencing a variable, like "a". + class VariableExpressionNode(ExpressionNode): + + def **init**\ (self, name): self.name = name + + def CodeGen(self): if self.name in g_named_values: return + g_llvm_builder.load(g_named_values[self.name], self.name) else: + raise RuntimeError('Unknown variable name: ' + self.name) + + # Expression class for a binary operator. + class BinaryOperatorExpressionNode(ExpressionNode): + + def **init**\ (self, operator, left, right): self.operator = operator + self.left = left self.right = right + + def CodeGen(self): # A special case for '=' because we don't want to + emit the LHS as an # expression. if self.operator == '=': # Assignment + requires the LHS to be an identifier. if not isinstance(self.left, + VariableExpressionNode): raise RuntimeError('Destination of "=" must be + a variable.') + + :: + + # Codegen the RHS. + value = self.right.CodeGen() + + # Look up the name. + variable = g_named_values[self.left.name] + + # Store the value and return it. + g_llvm_builder.store(value, variable) + + return value + + left = self.left.CodeGen() + right = self.right.CodeGen() + + if self.operator == '+': + return g_llvm_builder.fadd(left, right, 'addtmp') + elif self.operator == '-': + return g_llvm_builder.fsub(left, right, 'subtmp') + elif self.operator == '*': + return g_llvm_builder.fmul(left, right, 'multmp') + elif self.operator == '<': + result = g_llvm_builder.fcmp(FCMP_ULT, left, right, 'cmptmp') + # Convert bool 0 or 1 to double 0.0 or 1.0. + return g_llvm_builder.uitofp(result, Type.double(), 'booltmp') + else: + function = g_llvm_module.get_function_named('binary' + self.operator) + return g_llvm_builder.call(function, [left, right], 'binop') + + # Expression class for function calls. + class CallExpressionNode(ExpressionNode): + + def **init**\ (self, callee, args): self.callee = callee self.args = + args + + def CodeGen(self): # Look up the name in the global module table. callee + = g_llvm_module.get_function_named(self.callee) + + :: + + # Check for argument mismatch error. + if len(callee.args) != len(self.args): + raise RuntimeError('Incorrect number of arguments passed.') + + arg_values = [i.CodeGen() for i in self.args] + + return g_llvm_builder.call(callee, arg_values, 'calltmp') + + # Expression class for if/then/else. + class IfExpressionNode(ExpressionNode): + + def **init**\ (self, condition, then_branch, else_branch): + self.condition = condition self.then_branch = then_branch + self.else_branch = else_branch + + def CodeGen(self): condition = self.condition.CodeGen() + + :: + + # Convert condition to a bool by comparing equal to 0.0. + condition_bool = g_llvm_builder.fcmp( + FCMP_ONE, condition, Constant.real(Type.double(), 0), 'ifcond') + + function = g_llvm_builder.basic_block.function + + # Create blocks for the then and else cases. Insert the 'then' block at the + # end of the function. + then_block = function.append_basic_block('then') + else_block = function.append_basic_block('else') + merge_block = function.append_basic_block('ifcond') + + g_llvm_builder.cbranch(condition_bool, then_block, else_block) + + # Emit then value. + g_llvm_builder.position_at_end(then_block) + then_value = self.then_branch.CodeGen() + g_llvm_builder.branch(merge_block) + + # Codegen of 'Then' can change the current block; update then_block for the + # PHI node. + then_block = g_llvm_builder.basic_block + + # Emit else block. + g_llvm_builder.position_at_end(else_block) + else_value = self.else_branch.CodeGen() + g_llvm_builder.branch(merge_block) + + # Codegen of 'Else' can change the current block, update else_block for the + # PHI node. + else_block = g_llvm_builder.basic_block + + # Emit merge block. + g_llvm_builder.position_at_end(merge_block) + phi = g_llvm_builder.phi(Type.double(), 'iftmp') + phi.add_incoming(then_value, then_block) + phi.add_incoming(else_value, else_block) + + return phi + + # Expression class for for/in. + class ForExpressionNode(ExpressionNode): + + def **init**\ (self, loop_variable, start, end, step, body): + self.loop_variable = loop_variable self.start = start self.end = end + self.step = step self.body = body + + def CodeGen(self): # Output this as: # var = alloca double # ... # start + = startexpr # store start -> var # goto loop # loop: # ... # bodyexpr # + ... # loopend: # step = stepexpr # endcond = endexpr # # curvar = load + var # nextvar = curvar + step # store nextvar -> var # br endcond, loop, + endloop # outloop: + + :: + + function = g_llvm_builder.basic_block.function + + # Create an alloca for the variable in the entry block. + alloca = CreateEntryBlockAlloca(function, self.loop_variable) + + # Emit the start code first, without 'variable' in scope. + start_value = self.start.CodeGen() + + # Store the value into the alloca. + g_llvm_builder.store(start_value, alloca) + + # Make the new basic block for the loop, inserting after current block. + loop_block = function.append_basic_block('loop') + + # Insert an explicit fall through from the current block to the loop_block. + g_llvm_builder.branch(loop_block) + + # Start insertion in loop_block. + g_llvm_builder.position_at_end(loop_block) + + # Within the loop, the variable is defined equal to the alloca. If it + # shadows an existing variable, we have to restore it, so save it now. + old_value = g_named_values.get(self.loop_variable, None) + g_named_values[self.loop_variable] = alloca + + # Emit the body of the loop. This, like any other expr, can change the + # current BB. Note that we ignore the value computed by the body. + self.body.CodeGen() + + # Emit the step value. + if self.step: + step_value = self.step.CodeGen() + else: + # If not specified, use 1.0. + step_value = Constant.real(Type.double(), 1) + + # Compute the end condition. + end_condition = self.end.CodeGen() + + # Reload, increment, and restore the alloca. This handles the case where + # the body of the loop mutates the variable. + cur_value = g_llvm_builder.load(alloca, self.loop_variable) + next_value = g_llvm_builder.fadd(cur_value, step_value, 'nextvar') + g_llvm_builder.store(next_value, alloca) + + # Convert condition to a bool by comparing equal to 0.0. + end_condition_bool = g_llvm_builder.fcmp( + FCMP_ONE, end_condition, Constant.real(Type.double(), 0), 'loopcond') + + # Create the "after loop" block and insert it. + after_block = function.append_basic_block('afterloop') + + # Insert the conditional branch into the end of loop_block. + g_llvm_builder.cbranch(end_condition_bool, loop_block, after_block) + + # Any new code will be inserted in after_block. + g_llvm_builder.position_at_end(after_block) + + # Restore the unshadowed variable. + if old_value is not None: + g_named_values[self.loop_variable] = old_value + else: + del g_named_values[self.loop_variable] + + # for expr always returns 0.0. + return Constant.real(Type.double(), 0) + + # Expression class for a unary operator. + class UnaryExpressionNode(ExpressionNode): + + def **init**\ (self, operator, operand): self.operator = operator + self.operand = operand + + def CodeGen(self): operand = self.operand.CodeGen() function = + g_llvm_module.get_function_named('unary' + self.operator) return + g_llvm_builder.call(function, [operand], 'unop') + + # Expression class for var/in. + class VarExpressionNode(ExpressionNode): + + def **init**\ (self, variables, body): self.variables = variables + self.body = body + + def CodeGen(self): old_bindings = {} function = + g_llvm_builder.basic_block.function + + :: + + # Register all variables and emit their initializer. + for var_name, var_expression in self.variables.iteritems(): + # Emit the initializer before adding the variable to scope, this prevents + # the initializer from referencing the variable itself, and permits stuff + # like this: + # var a = 1 in + # var a = a in ... # refers to outer 'a'. + if var_expression is not None: + var_value = var_expression.CodeGen() + else: + var_value = Constant.real(Type.double(), 0) + + alloca = CreateEntryBlockAlloca(function, var_name) + g_llvm_builder.store(var_value, alloca) + + # Remember the old variable binding so that we can restore the binding + # when we unrecurse. + old_bindings[var_name] = g_named_values.get(var_name, None) + + # Remember this binding. + g_named_values[var_name] = alloca + + # Codegen the body, now that all vars are in scope. + body = self.body.CodeGen() + + # Pop all our variables from scope. + for var_name in self.variables: + if old_bindings[var_name] is not None: + g_named_values[var_name] = old_bindings[var_name] + else: + del g_named_values[var_name] + + # Return the body computation. + return body + + # This class represents the "prototype" for a function, which captures its name, + # and its argument names (thus implicitly the number of arguments the function + # takes), as well as if it is an operator. + class PrototypeNode(object): + + def **init**\ (self, name, args, is_operator=False, precedence=0): + self.name = name self.args = args self.is_operator = is_operator + self.precedence = precedence + + def IsBinaryOp(self): return self.is_operator and len(self.args) == 2 + + def GetOperatorName(self): assert self.is_operator return self.name[-1] + + def CodeGen(self): # Make the function type, eg. double(double,double). + funct_type = Type.function( Type.double(), [Type.double()] \* + len(self.args), False) + + :: + + function = Function.new(g_llvm_module, funct_type, self.name) + + # If the name conflicted, there was already something with the same name. + # If it has a body, don't allow redefinition or reextern. + if function.name != self.name: + function.delete() + function = g_llvm_module.get_function_named(self.name) + + # If the function already has a body, reject this. + if not function.is_declaration: + raise RuntimeError('Redefinition of function.') + + # If the function took a different number of args, reject. + if len(function.args) != len(self.args): + raise RuntimeError('Redeclaration of a function with different number ' + 'of args.') + + # Set names for all arguments and add them to the variables symbol table. + for arg, arg_name in zip(function.args, self.args): + arg.name = arg_name + + return function + + # Create an alloca for each argument and register the argument in the + symbol # table so that references to it will succeed. def + CreateArgumentAllocas(self, function): for arg_name, arg in + zip(self.args, function.args): alloca = CreateEntryBlockAlloca(function, + arg_name) g_llvm_builder.store(arg, alloca) + g_named_values[arg_name] = alloca + + # This class represents a function definition itself. + class FunctionNode(object): + + def **init**\ (self, prototype, body): self.prototype = prototype + self.body = body + + def CodeGen(self): # Clear scope. g_named_values.clear() + + :: + + # Create a function object. + function = self.prototype.CodeGen() + + # If this is a binary operator, install its precedence. + if self.prototype.IsBinaryOp(): + operator = self.prototype.GetOperatorName() + g_binop_precedence[operator] = self.prototype.precedence + + # Create a new basic block to start insertion into. + block = function.append_basic_block('entry') + global g_llvm_builder + g_llvm_builder = Builder.new(block) + + # Add all arguments to the symbol table and create their allocas. + self.prototype.CreateArgumentAllocas(function) + + # Finish off the function. + try: + return_value = self.body.CodeGen() + g_llvm_builder.ret(return_value) + + # Validate the generated code, checking for consistency. + function.verify() + + # Optimize the function. + g_llvm_pass_manager.run(function) + except: + function.delete() + if self.prototype.IsBinaryOp(): + del g_binop_precedence[self.prototype.GetOperatorName()] + raise + + return function + + Parser + ------ + + class Parser(object): + + def **init**\ (self, tokens): self.tokens = tokens self.Next() + + # Provide a simple token buffer. Parser.current is the current token the + # parser is looking at. Parser.Next() reads another token from the lexer + and # updates Parser.current with its results. def Next(self): + self.current = self.tokens.next() + + # Gets the precedence of the current token, or -1 if the token is not a + binary # operator. def GetCurrentTokenPrecedence(self): if + isinstance(self.current, CharacterToken): return + g_binop_precedence.get(self.current.char, -1) else: return -1 + + # identifierexpr ::= identifier \| identifier '(' expression\* ')' def + ParseIdentifierExpr(self): identifier_name = self.current.name + self.Next() # eat identifier. + + :: + + if self.current != CharacterToken('('): # Simple variable reference. + return VariableExpressionNode(identifier_name) + + # Call. + self.Next() # eat '('. + args = [] + if self.current != CharacterToken(')'): + while True: + args.append(self.ParseExpression()) + if self.current == CharacterToken(')'): + break + elif self.current != CharacterToken(','): + raise RuntimeError('Expected ")" or "," in argument list.') + self.Next() + + self.Next() # eat ')'. + return CallExpressionNode(identifier_name, args) + + # numberexpr ::= number def ParseNumberExpr(self): result = + NumberExpressionNode(self.current.value) self.Next() # consume the + number. return result + + # parenexpr ::= '(' expression ')' def ParseParenExpr(self): self.Next() + # eat '('. + + :: + + contents = self.ParseExpression() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")".') + self.Next() # eat ')'. + + return contents + + # ifexpr ::= 'if' expression 'then' expression 'else' expression def + ParseIfExpr(self): self.Next() # eat the if. + + :: + + # condition. + condition = self.ParseExpression() + + if not isinstance(self.current, ThenToken): + raise RuntimeError('Expected "then".') + self.Next() # eat the then. + + then_branch = self.ParseExpression() + + if not isinstance(self.current, ElseToken): + raise RuntimeError('Expected "else".') + self.Next() # eat the else. + + else_branch = self.ParseExpression() + + return IfExpressionNode(condition, then_branch, else_branch) + + # forexpr ::= 'for' identifier '=' expr ',' expr (',' expr)? 'in' + expression def ParseForExpr(self): self.Next() # eat the for. + + :: + + if not isinstance(self.current, IdentifierToken): + raise RuntimeError('Expected identifier after for.') + + loop_variable = self.current.name + self.Next() # eat the identifier. + + if self.current != CharacterToken('='): + raise RuntimeError('Expected "=" after for variable.') + self.Next() # eat the '='. + + start = self.ParseExpression() + + if self.current != CharacterToken(','): + raise RuntimeError('Expected "," after for start value.') + self.Next() # eat the ','. + + end = self.ParseExpression() + + # The step value is optional. + if self.current == CharacterToken(','): + self.Next() # eat the ','. + step = self.ParseExpression() + else: + step = None + + if not isinstance(self.current, InToken): + raise RuntimeError('Expected "in" after for variable specification.') + self.Next() # eat 'in'. + + body = self.ParseExpression() + + return ForExpressionNode(loop_variable, start, end, step, body) + + # varexpr ::= 'var' (identifier ('=' expression)?)+ 'in' expression def + ParseVarExpr(self): self.Next() # eat 'var'. + + :: + + variables = {} + + # At least one variable name is required. + if not isinstance(self.current, IdentifierToken): + raise RuntimeError('Expected identifier after "var".') + + while True: + var_name = self.current.name + self.Next() # eat the identifier. + + # Read the optional initializer. + if self.current == CharacterToken('='): + self.Next() # eat '='. + variables[var_name] = self.ParseExpression() + else: + variables[var_name] = None + + # End of var list, exit loop. + if self.current != CharacterToken(','): + break + self.Next() # eat ','. + + if not isinstance(self.current, IdentifierToken): + raise RuntimeError('Expected identifier after "," in a var expression.') + + # At this point, we have to have 'in'. + if not isinstance(self.current, InToken): + raise RuntimeError('Expected "in" keyword after "var".') + self.Next() # eat 'in'. + + body = self.ParseExpression() + + return VarExpressionNode(variables, body) + + # primary ::= # dentifierexpr \| numberexpr \| parenexpr \| ifexpr \| + forexpr \| varexpr def ParsePrimary(self): if isinstance(self.current, + IdentifierToken): return self.ParseIdentifierExpr() elif + isinstance(self.current, NumberToken): return self.ParseNumberExpr() + elif isinstance(self.current, IfToken): return self.ParseIfExpr() elif + isinstance(self.current, ForToken): return self.ParseForExpr() elif + isinstance(self.current, VarToken): return self.ParseVarExpr() elif + self.current == CharacterToken('('): return self.ParseParenExpr() else: + raise RuntimeError('Unknown token when expecting an expression.') + + # unary ::= primary \| unary_operator unary def ParseUnary(self): # If + the current token is not an operator, it must be a primary expression. + if (not isinstance(self.current, CharacterToken) or self.current in + [CharacterToken('('), CharacterToken(',')]): return self.ParsePrimary() + + :: + + # If this is a unary operator, read it. + operator = self.current.char + self.Next() # eat the operator. + return UnaryExpressionNode(operator, self.ParseUnary()) + + # binoprhs ::= (binary_operator unary)\* def ParseBinOpRHS(self, left, + left_precedence): # If this is a binary operator, find its precedence. + while True: precedence = self.GetCurrentTokenPrecedence() + + :: + + # If this is a binary operator that binds at least as tightly as the + # current one, consume it; otherwise we are done. + if precedence < left_precedence: + return left + + binary_operator = self.current.char + self.Next() # eat the operator. + + # Parse the unary expression after the binary operator. + right = self.ParseUnary() + + # If binary_operator binds less tightly with right than the operator after + # right, let the pending operator take right as its left. + next_precedence = self.GetCurrentTokenPrecedence() + if precedence < next_precedence: + right = self.ParseBinOpRHS(right, precedence + 1) + + # Merge left/right. + left = BinaryOperatorExpressionNode(binary_operator, left, right) + + # expression ::= unary binoprhs def ParseExpression(self): left = + self.ParseUnary() return self.ParseBinOpRHS(left, 0) + + # prototype # ::= id '(' id\* ')' # ::= binary LETTER number? (id, id) # + ::= unary LETTER (id) def ParsePrototype(self): precedence = None if + isinstance(self.current, IdentifierToken): kind = 'normal' + function_name = self.current.name self.Next() # eat function name. elif + isinstance(self.current, UnaryToken): kind = 'unary' self.Next() # eat + 'unary'. if not isinstance(self.current, CharacterToken): raise + RuntimeError('Expected an operator after "unary".') function_name = + 'unary' + self.current.char self.Next() # eat the operator. elif + isinstance(self.current, BinaryToken): kind = 'binary' self.Next() # eat + 'binary'. if not isinstance(self.current, CharacterToken): raise + RuntimeError('Expected an operator after "binary".') function_name = + 'binary' + self.current.char self.Next() # eat the operator. if + isinstance(self.current, NumberToken): if not 1 <= self.current.value <= + 100: raise RuntimeError('Invalid precedence: must be in range [1, + 100].') precedence = self.current.value self.Next() # eat the + precedence. else: raise RuntimeError('Expected function name, "unary" or + "binary" in ' 'prototype.') + + :: + + if self.current != CharacterToken('('): + raise RuntimeError('Expected "(" in prototype.') + self.Next() # eat '('. + + arg_names = [] + while isinstance(self.current, IdentifierToken): + arg_names.append(self.current.name) + self.Next() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")" in prototype.') + + # Success. + self.Next() # eat ')'. + + if kind == 'unary' and len(arg_names) != 1: + raise RuntimeError('Invalid number of arguments for a unary operator.') + elif kind == 'binary' and len(arg_names) != 2: + raise RuntimeError('Invalid number of arguments for a binary operator.') + + return PrototypeNode(function_name, arg_names, kind != 'normal', precedence) + + # definition ::= 'def' prototype expression def ParseDefinition(self): + self.Next() # eat def. proto = self.ParsePrototype() body = + self.ParseExpression() return FunctionNode(proto, body) + + # toplevelexpr ::= expression def ParseTopLevelExpr(self): proto = + PrototypeNode('', []) return FunctionNode(proto, self.ParseExpression()) + + # external ::= 'extern' prototype def ParseExtern(self): self.Next() # + eat extern. return self.ParsePrototype() + + # Top-Level parsing def HandleDefinition(self): + self.Handle(self.ParseDefinition, 'Read a function definition:') + + def HandleExtern(self): self.Handle(self.ParseExtern, 'Read an extern:') + + def HandleTopLevelExpression(self): try: function = + self.ParseTopLevelExpr().CodeGen() result = + g_llvm_executor.run_function(function, []) print 'Evaluated to:', + result.as_real(Type.double()) except Exception, e: raise#print + 'Error:', e try: self.Next() # Skip for error recovery. except: pass + + def Handle(self, function, message): try: print message, + function().CodeGen() except Exception, e: raise#print 'Error:', e try: + self.Next() # Skip for error recovery. except: pass + + Main driver code. + ----------------- + + def main(): # Set up the optimizer pipeline. Start with registering info + about how the # target lays out data structures. + g_llvm_pass_manager.add(g_llvm_executor.target_data) # Promote + allocas to registers. + g_llvm_pass_manager.add(PASS_PROMOTE_MEMORY_TO_REGISTER) # Do + simple "peephole" optimizations and bit-twiddling optzns. + g_llvm_pass_manager.add(PASS_INSTRUCTION_COMBINING) # Reassociate + expressions. g_llvm_pass_manager.add(PASS_REASSOCIATE) # Eliminate + Common SubExpressions. g_llvm_pass_manager.add(PASS_GVN) # Simplify + the control flow graph (deleting unreachable blocks, etc). + g_llvm_pass_manager.add(PASS_CFG_SIMPLIFICATION) + + g_llvm_pass_manager.initialize() + + # Install standard binary operators. # 1 is lowest possible precedence. + 40 is the highest. g_binop_precedence['='] = 2 + g_binop_precedence['<'] = 10 g_binop_precedence['+'] = 20 + g_binop_precedence['-'] = 20 g_binop_precedence['\*'] = 40 + + # Run the main "interpreter loop". while True: print 'ready<', try: raw + = raw_input() except KeyboardInterrupt: break + + :: + + parser = Parser(Tokenize(raw)) + while True: + # top ::= definition | external | expression | EOF + if isinstance(parser.current, EOFToken): + break + if isinstance(parser.current, DefToken): + parser.HandleDefinition() + elif isinstance(parser.current, ExternToken): + parser.HandleExtern() + else: + parser.HandleTopLevelExpression() + + # Print out all of the generated code. print '', g_llvm_module + + if **name** == '**main**\ ': main() diff --git a/docs/source/doc/kaleidoscope/PythonLangImpl8.rst b/docs/source/doc/kaleidoscope/PythonLangImpl8.rst index d9b81ac..e69de29 100644 --- a/docs/source/doc/kaleidoscope/PythonLangImpl8.rst +++ b/docs/source/doc/kaleidoscope/PythonLangImpl8.rst @@ -1,277 +0,0 @@ -***************************************************************** -Chapter 8: Conclusion and other useful LLVM tidbits -***************************************************************** - -Written by `Chris Lattner `_ - - -Tutorial Conclusion # {#conclusion} -=================================== - -Welcome to the the final chapter of the `Implementing a language with -LLVM `_ tutorial. In the -course of this tutorial, we have grown our little Kaleidoscope language -from being a useless toy, to being a semi-interesting (but probably -still useless) toy. :) - -It is interesting to see how far we've come, and how little code it has -taken. We built the entire lexer, parser, AST, code generator, and an -interactive run-loop (with a JIT!) by-hand in under 540 lines of -(non-comment/non-blank) code. - -Our little language supports a couple of interesting features: it -supports user defined binary and unary operators, it uses JIT -compilation for immediate evaluation, and it supports a few control flow -constructs with SSA construction. - -Part of the idea of this tutorial was to show you how easy and fun it -can be to define, build, and play with languages. Building a compiler -need not be a scary or mystical process! Now that you've seen some of -the basics, I strongly encourage you to take the code and hack on it. -For example, try adding: - -- **global variables** -- While global variables have questional value - in modern software engineering, they are often useful when putting - together quick little hacks like the Kaleidoscope compiler itself. - Fortunately, our current setup makes it very easy to add global - variables: just have value lookup check to see if an unresolved - variable is in the global variable symbol table before rejecting it. - To create a new global variable, make an instance of the LLVM - ``GlobalVariable`` class. - -- **typed variables** -- Kaleidoscope currently only supports variables - of type double. This gives the language a very nice elegance, because - only supporting one type means that you never have to specify types. - Different languages have different ways of handling this. The easiest - way is to require the user to specify types for every variable - definition, and record the type of the variable in the symbol table - along with its Value\*. - -- **arrays, structs, vectors, etc** -- Once you add types, you can - start extending the type system in all sorts of interesting ways. - Simple arrays are very easy and are quite useful for many different - applications. Adding them is mostly an exercise in learning how the - LLVM - `getelementptr `_ - instruction works: it is so nifty/unconventional, it `has its own - FAQ `_! If you add - support for recursive types (e.g. linked lists), make sure to read - the `section in the LLVM Programmer's - Manual `_ - that describes how to construct them. - -- **standard runtime** -- Our current language allows the user to - access arbitrary external functions, and we use it for things like - "putchard". As you extend the language to add higher-level - constructs, often these constructs make the most sense if they are - lowered to calls into a language-supplied runtime. For example, if - you add hash tables to the language, it would probably make sense to - add the routines to a runtime, instead of inlining them all the way. - -- **memory management** -- Currently we can only access the stack in - Kaleidoscope. It would also be useful to be able to allocate heap - memory, either with calls to the standard libc malloc/free interface - or with a garbage collector. If you would like to use garbage - collection, note that LLVM fully supports `Accurate Garbage - Collection `_ - including algorithms that move objects and need to scan/update the - stack. - -- **debugger support** -- LLVM supports generation of `DWARF Debug - info `_ which is - understood by common debuggers like GDB. Adding support for debug - info is fairly straightforward. The best way to understand it is to - compile some C/C++ code with "``llvm-gcc -g -O0``\ " and taking a - look at what it produces. - -- **exception handling support** - LLVM supports generation of `zero - cost exceptions `_ - which interoperate with code compiled in other languages. You could - also generate code by implicitly making every function return an - error value and checking it. You could also make explicit use of - setjmp/longjmp. There are many different ways to go here. - -- **object orientation, generics, database access, complex numbers, - geometric programming, ...** -- Really, there is no end of crazy - features that you can add to the language. - -- **unusual domains** -- We've been talking about applying LLVM to a - domain that many people are interested in: building a compiler for a - specific language. However, there are many other domains that can use - compiler technology that are not typically considered. For example, - LLVM has been used to implement OpenGL graphics acceleration, - translate C++ code to ActionScript, and many other cute and clever - things. Maybe you will be the first to JIT compile a regular - expression interpreter into native code with LLVM? - -Have fun - try doing something crazy and unusual. Building a language -like everyone else always has, is much less fun than trying something a -little crazy or off the wall and seeing how it turns out. If you get -stuck or want to talk about it, feel free to email the `llvmdev mailing -list `_: it has lots -of people who are interested in languages and are often willing to help -out. - -Before we end this tutorial, I want to talk about some "tips and tricks" -for generating LLVM IR. These are some of the more subtle things that -may not be obvious, but are very useful if you want to take advantage of -LLVM's capabilities. - --------------- - -Properties of the LLVM IR # {#llvmirproperties} -=============================================== - -We have a couple common questions about code in the LLVM IR form - let's -just get these out of the way right now, shall we? - -Target Independence ## {#targetindep} -------------------------------------- - -Kaleidoscope is an example of a "portable language": any program written -in Kaleidoscope will work the same way on any target that it runs on. -Many other languages have this property, e.g. LISP, Java, Haskell, -Javascript, Python, etc. (note that while these languages are portable, -not all their libraries are). - -One nice aspect of LLVM is that it is often capable of preserving target -independence in the IR: you can take the LLVM IR for a -Kaleidoscope-compiled program and run it on any target that LLVM -supports, even emitting C code and compiling that on targets that LLVM -doesn't support natively. You can trivially tell that the Kaleidoscope -compiler generates target-independent code because it never queries for -any target-specific information when generating code. - -The fact that LLVM provides a compact, target-independent, -representation for code gets a lot of people excited. Unfortunately, -these people are usually thinking about C or a language from the C -family when they are asking questions about language portability. I say -"unfortunately", because there is really no way to make (fully general) -C code portable, other than shipping the source code around (and of -course, C source code is not actually portable in general either - ever -port a really old application from 32- to 64-bits?). - -The problem with C (again, in its full generality) is that it is heavily -laden with target specific assumptions. As one simple example, the -preprocessor often destructively removes target-independence from the -code when it processes the input text: - -{% highlight c %} #ifdef **i386** int X = 1; #else int X = 42; #endif {% -endhighlight %} - -While it is possible to engineer more and more complex solutions to -problems like this, it cannot be solved in full generality in a way that -is better than shipping the actual source code. - -That said, there are interesting subsets of C that can be made portable. -If you are willing to fix primitive types to a fixed size (say int = -32-bits, and long = 64-bits), don't care about ABI compatibility with -existing binaries, and are willing to give up some other minor features, -you can have portable code. This can make sense for specialized domains -such as an in-kernel language. - -Safety Guarantees ## {#safety} ------------------------------- - -Many of the languages above are also "safe" languages: it is impossible -for a program written in Java to corrupt its address space and crash the -process (assuming the JVM has no bugs). Safety is an interesting -property that requires a combination of language design, runtime -support, and often operating system support. - -It is certainly possible to implement a safe language in LLVM, but LLVM -IR does not itself guarantee safety. The LLVM IR allows unsafe pointer -casts, use after free bugs, buffer over-runs, and a variety of other -problems. Safety needs to be implemented as a layer on top of LLVM and, -conveniently, several groups have investigated this. Ask on the `llvmdev -mailing list `_ if -you are interested in more details. - -Language-Specific Optimizations ## {#langspecific} --------------------------------------------------- - -One thing about LLVM that turns off many people is that it does not -solve all the world's problems in one system (sorry 'world hunger', -someone else will have to solve you some other day). One specific -complaint is that people perceive LLVM as being incapable of performing -high-level language-specific optimization: LLVM "loses too much -information". - -Unfortunately, this is really not the place to give you a full and -unified version of "Chris Lattner's theory of compiler design". Instead, -I'll make a few observations: - -First, you're right that LLVM does lose information. For example, as of -this writing, there is no way to distinguish in the LLVM IR whether an -SSA-value came from a C "int" or a C "long" on an ILP32 machine (other -than debug info). Both get compiled down to an 'i32' value and the -information about what it came from is lost. The more general issue -here, is that the LLVM type system uses "structural equivalence" instead -of "name equivalence". Another place this surprises people is if you -have two types in a high-level language that have the same structure -(e.g. two different structs that have a single int field): these types -will compile down into a single LLVM type and it will be impossible to -tell what it came from. - -Second, while LLVM does lose information, LLVM is not a fixed target: we -continue to enhance and improve it in many different ways. In addition -to adding new features (LLVM did not always support exceptions or debug -info), we also extend the IR to capture important information for -optimization (e.g. whether an argument is sign or zero extended, -information about pointers aliasing, etc). Many of the enhancements are -user-driven: people want LLVM to include some specific feature, so they -go ahead and extend it. - -Third, it is *possible and easy* to add language-specific optimizations, -and you have a number of choices in how to do it. As one trivial -example, it is easy to add language-specific optimization passes that -"know" things about code compiled for a language. In the case of the C -family, there is an optimization pass that "knows" about the standard C -library functions. If you call "exit(0)" in main(), it knows that it is -safe to optimize that into "return 0;" because C specifies what the -'exit' function does. - -In addition to simple library knowledge, it is possible to embed a -variety of other language-specific information into the LLVM IR. If you -have a specific need and run into a wall, please bring the topic up on -the llvmdev list. At the very worst, you can always treat LLVM as if it -were a "dumb code generator" and implement the high-level optimizations -you desire in your front-end, on the language-specific AST. - --------------- - -Tips and Tricks # {#tipsandtricks} -================================== - -There is a variety of useful tips and tricks that you come to know after -working on/with LLVM that aren't obvious at first glance. Instead of -letting everyone rediscover them, this section talks about some of these -issues. - -Implementing portable offsetof/sizeof ## {#offsetofsizeof} ----------------------------------------------------------- - -One interesting thing that comes up, if you are trying to keep the code -generated by your compiler "target independent", is that you often need -to know the size of some LLVM type or the offset of some field in an -llvm structure. For example, you might need to pass the size of a type -into a function that allocates memory. - -Unfortunately, this can vary widely across targets: for example the -width of a pointer is trivially target-specific. However, there is a -`clever way to use the getelementptr -instruction `_ -that allows you to compute this in a portable way. - -Garbage Collected Stack Frames ## {#gcstack} --------------------------------------------- - -Some languages want to explicitly manage their stack frames, often so -that they are garbage collected or to allow easy implementation of -closures. There are often better ways to implement these features than -explicit stack frames, but `LLVM does support -them `_, -if you want. It requires your front-end to convert the code into -`Continuation Passing -Style `_ and -the use of tail calls (which LLVM also supports). diff --git a/docs/source/doc/llvm.core.Constant.rst b/docs/source/doc/llvm.core.Constant.rst index 1656381..4f2ed08 100644 --- a/docs/source/doc/llvm.core.Constant.rst +++ b/docs/source/doc/llvm.core.Constant.rst @@ -11,344 +11,343 @@ created from Python constants. A constant expression is also a constant etc) can be specified, to yield a new ``Constant`` object. Let's see some examples: -{% highlight python %} #!/usr/bin/env python -ti = Type.int() # a 32-bit int type +.. code-block:: python -k1 = Constant.int(ti, 42) # "int k1 = 42;" k2 = k1.add( Constant.int( -ti, 10 ) ) # "int k2 = k1 + 10;" - -tr = Type.float() - -r1 = Constant.real(tr, "3.141592") # create from a string r2 = -Constant.real(tr, 1.61803399) # create from a Python float {% -endhighlight %} - -llvm.core.Constant -================== - -- This will become a table of contents (this text will be scraped). + #!/usr/bin/env python + + ti = Type.int() # a 32-bit int type + + k1 = Constant.int(ti, 42) # "int k1 = 42;" k2 = k1.add( Constant.int( + ti, 10 ) ) # "int k2 = k1 + 10;" + + tr = Type.float() + + r1 = Constant.real(tr, "3.141592") # create from a string r2 = + Constant.real(tr, 1.61803399) # create from a Python float {% + endhighlight %} + + # llvm.core.Constant + - This will become a table of contents (this text will be scraped). {:toc} - -Static factory methods ----------------------- - -``null(ty)`` -~~~~~~~~~~~~ - -A null value (all zeros) of type ``ty`` - -``all_ones(ty)`` -~~~~~~~~~~~~~~~~ - -All 1's value of type ``ty`` - -``undef(ty)`` -~~~~~~~~~~~~~ - -An undefined value of type ``ty`` - -``int(ty, value)`` -~~~~~~~~~~~~~~~~~~ - -Integer of type ``ty``, with value ``value`` (a Python int or long) - -``int_signextend(ty, value)`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Integer of signed type ``ty`` (use for signed types) - -``real(ty, value)`` -~~~~~~~~~~~~~~~~~~~ - -Floating point value of type ``ty``, with value ``value`` (a Python -float) - -``stringz(value)`` -~~~~~~~~~~~~~~~~~~ - -A null-terminated string. ``value`` is a Python string - -``string(value)`` -~~~~~~~~~~~~~~~~~ - -As ``string(ty)``, but not null terminated - -``array(ty, consts)`` -~~~~~~~~~~~~~~~~~~~~~ - -Array of type ``ty``, initialized with ``consts`` (an iterable yielding -``Constant`` objects of the appropriate type) - -``struct(ty, consts)`` -~~~~~~~~~~~~~~~~~~~~~~ - -Struct (unpacked) of type ``ty``, initialized with ``consts`` (an -iterable yielding ``Constant`` objects of the appropriate type) - -``packed_struct(ty, consts)`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -As ``struct(ty, consts)`` but packed - -``vector(consts)`` -~~~~~~~~~~~~~~~~~~ - -Vector, initialized with ``consts`` (an iterable yielding ``Constant`` -objects of the appropriate type) - -``sizeof(ty)`` -~~~~~~~~~~~~~~ - -Constant value representing the sizeof the type ``ty`` - -Methods -------- - -The following operations on constants are supported. For more details on -any operation, consult the `Constant -Expressions `_ -section of the LLVM Language Reference. - -``k.neg()`` -~~~~~~~~~~~ - -negation, same as ``0 - k`` - -``k.not_()`` -~~~~~~~~~~~~ - -1's complement of ``k``. Note trailing underscore. - -``k.add(k2)`` -~~~~~~~~~~~~~ - -``k + k2``, where ``k`` and ``k2`` are integers. - -``k.fadd(k2)`` -~~~~~~~~~~~~~~ - -``k + k2``, where ``k`` and ``k2`` are floating-point. - -``k.sub(k2)`` -~~~~~~~~~~~~~ - -``k - k2``, where ``k`` and ``k2`` are integers. - -``k.fsub(k2)`` -~~~~~~~~~~~~~~ - -``k - k2``, where ``k`` and ``k2`` are floating-point. - -``k.mul(k2)`` -~~~~~~~~~~~~~ - -``k * k2``, where ``k`` and ``k2`` are integers. - -``k.fmul(k2)`` -~~~~~~~~~~~~~~ - -``k * k2``, where ``k`` and ``k2`` are floating-point. - -``k.udiv(k2)`` -~~~~~~~~~~~~~~ - -Quotient of unsigned division of ``k`` with ``k2`` - -``k.sdiv(k2)`` -~~~~~~~~~~~~~~ - -Quotient of signed division of ``k`` with ``k2`` - -``k.fdiv(k2)`` -~~~~~~~~~~~~~~ - -Quotient of floating point division of ``k`` with ``k2`` - -``k.urem(k2)`` -~~~~~~~~~~~~~~ - -Reminder of unsigned division of ``k`` with ``k2`` - -``k.srem(k2)`` -~~~~~~~~~~~~~~ - -Reminder of signed division of ``k`` with ``k2`` - -``k.frem(k2)`` -~~~~~~~~~~~~~~ - -Reminder of floating point division of ``k`` with ``k2`` - -``k.and_(k2)`` -~~~~~~~~~~~~~~ - -Bitwise and of ``k`` and ``k2``. Note trailing underscore. - -``k.or_(k2)`` -~~~~~~~~~~~~~ - -Bitwise or of ``k`` and ``k2``. Note trailing underscore. - -``k.xor(k2)`` -~~~~~~~~~~~~~ - -Bitwise exclusive-or of ``k`` and ``k2``. - -``k.icmp(icmp, k2)`` -~~~~~~~~~~~~~~~~~~~~ - -Compare ``k`` with ``k2`` using the predicate ``icmp``. See -`here `_ for list of predicates for integer -operands. - -``k.fcmp(fcmp, k2)`` -~~~~~~~~~~~~~~~~~~~~ - -Compare ``k`` with ``k2`` using the predicate ``fcmp``. See -`here `_ for list of predicates for real -operands. - -``k.shl(k2)`` -~~~~~~~~~~~~~ - -Shift ``k`` left by ``k2`` bits. - -``k.lshr(k2)`` -~~~~~~~~~~~~~~ - -Shift ``k`` logically right by ``k2`` bits (new bits are 0s). - -``k.ashr(k2)`` -~~~~~~~~~~~~~~ - -Shift ``k`` arithmetically right by ``k2`` bits (new bits are same as -previous sign bit). - -``k.gep(indices)`` -~~~~~~~~~~~~~~~~~~ - -GEP, see `LLVM docs `_. - -``k.trunc(ty)`` -~~~~~~~~~~~~~~~ - -Truncate ``k`` to a type ``ty`` of lower bitwidth. - -``k.sext(ty)`` -~~~~~~~~~~~~~~ - -Sign extend ``k`` to a type ``ty`` of higher bitwidth, while extending -the sign bit. - -``k.zext(ty)`` -~~~~~~~~~~~~~~ - -Sign extend ``k`` to a type ``ty`` of higher bitwidth, all new bits are -0s. - -``k.fptrunc(ty)`` -~~~~~~~~~~~~~~~~~ - -Truncate floating point constant ``k`` to floating point type ``ty`` of -lower size than k's. - -``k.fpext(ty)`` -~~~~~~~~~~~~~~~ - -Extend floating point constant ``k`` to floating point type ``ty`` of -higher size than k's. - -``k.uitofp(ty)`` -~~~~~~~~~~~~~~~~ - -Convert an unsigned integer constant ``k`` to floating point constant of -type ``ty``. - -``k.sitofp(ty)`` -~~~~~~~~~~~~~~~~ - -Convert a signed integer constant ``k`` to floating point constant of -type ``ty``. - -``k.fptoui(ty)`` -~~~~~~~~~~~~~~~~ - -Convert a floating point constant ``k`` to an unsigned integer constant -of type ``ty``. - -``k.fptosi(ty)`` -~~~~~~~~~~~~~~~~ - -Convert a floating point constant ``k`` to a signed integer constant of -type ``ty``. - -``k.ptrtoint(ty)`` -~~~~~~~~~~~~~~~~~~ - -Convert a pointer constant ``k`` to an integer constant of type ``ty``. - -``k.inttoptr(ty)`` -~~~~~~~~~~~~~~~~~~ - -Convert an integer constant ``k`` to a pointer constant of type ``ty``. - -``k.bitcast(ty)`` -~~~~~~~~~~~~~~~~~ - -Convert ``k`` to a (equal-width) constant of type ``ty``. - -``k.select(cond,k2,k3)`` -~~~~~~~~~~~~~~~~~~~~~~~~ - -Replace value with ``k2`` if the 1-bit integer constant ``cond`` is 1, -else with ``k3``. - -``k.extract_element(idx)`` -~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Extract value at ``idx`` (integer constant) from a vector constant -``k``. - -``k.insert_element(k2,idx)`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Insert value ``k2`` (scalar constant) at index ``idx`` (integer -constant) of vector constant ``k``. - -``k.shuffle_vector(k2,mask)`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Shuffle vector constant ``k`` based on vector constants ``k2`` and -``mask``. - --------------- - -Other Constant Classes -====================== - -The following subclasses of ``Constant`` do not provide additional -methods, **they serve only to provide richer type information.** - -Subclass \| LLVM C++ Class \| Remarks \| ----------\|----------------\|---------\| ``ConstantExpr`` \| -``llvmConstantExpr`` \| A constant expression \| -``ConstantAggregateZero``\ \| ``llvmConstantAggregateZero``\ \| All-zero -constant \| ``ConstantInt``\ \| ``llvmConstantInt``\ \| An integer -constant \| ``ConstantFP``\ \| ``llvmConstantFP``\ \| A floating-point -constant \| ``ConstantArray``\ \| ``llvmConstantArray``\ \| An array -constant \| ``ConstantStruct``\ \| ``llvmConstantStruct``\ \| A -structure constant \| ``ConstantVector``\ \| ``llvmConstantVector``\ \| -A vector constant \| ``ConstantPointerNull``\ \| -``llvmConstantPointerNull``\ \| All-zero pointer constant \| -``UndefValue``\ \| ``llvmUndefValue``\ \| corresponds to ``undef`` of -LLVM IR \| - -These types are helpful in ``isinstance`` checks, like so: - -{% highlight python %} ti = Type.int(32) k1 = Constant.int(ti, 42) # -int32\_t k1 = 42; k2 = Constant.array(ti, [k1, k1]) # int32\_t k2[] = { -k1, k1 }; - -assert isinstance(k1, ConstantInt) assert isinstance(k2, ConstantArray) -{% endhighlight %} + + Static factory methods + ---------------------- + + ``null(ty)`` + ~~~~~~~~~~~~ + + A null value (all zeros) of type ``ty`` + + ``all_ones(ty)`` + ~~~~~~~~~~~~~~~~ + + All 1's value of type ``ty`` + + ``undef(ty)`` + ~~~~~~~~~~~~~ + + An undefined value of type ``ty`` + + ``int(ty, value)`` + ~~~~~~~~~~~~~~~~~~ + + Integer of type ``ty``, with value ``value`` (a Python int or long) + + ``int_signextend(ty, value)`` + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Integer of signed type ``ty`` (use for signed types) + + ``real(ty, value)`` + ~~~~~~~~~~~~~~~~~~~ + + Floating point value of type ``ty``, with value ``value`` (a Python + float) + + ``stringz(value)`` + ~~~~~~~~~~~~~~~~~~ + + A null-terminated string. ``value`` is a Python string + + ``string(value)`` + ~~~~~~~~~~~~~~~~~ + + As ``string(ty)``, but not null terminated + + ``array(ty, consts)`` + ~~~~~~~~~~~~~~~~~~~~~ + + Array of type ``ty``, initialized with ``consts`` (an iterable yielding + ``Constant`` objects of the appropriate type) + + ``struct(ty, consts)`` + ~~~~~~~~~~~~~~~~~~~~~~ + + Struct (unpacked) of type ``ty``, initialized with ``consts`` (an + iterable yielding ``Constant`` objects of the appropriate type) + + ``packed_struct(ty, consts)`` + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + As ``struct(ty, consts)`` but packed + + ``vector(consts)`` + ~~~~~~~~~~~~~~~~~~ + + Vector, initialized with ``consts`` (an iterable yielding ``Constant`` + objects of the appropriate type) + + ``sizeof(ty)`` + ~~~~~~~~~~~~~~ + + Constant value representing the sizeof the type ``ty`` + + Methods + ------- + + The following operations on constants are supported. For more details on + any operation, consult the `Constant + Expressions `_ + section of the LLVM Language Reference. + + ``k.neg()`` + ~~~~~~~~~~~ + + negation, same as ``0 - k`` + + ``k.not_()`` + ~~~~~~~~~~~~ + + 1's complement of ``k``. Note trailing underscore. + + ``k.add(k2)`` + ~~~~~~~~~~~~~ + + ``k + k2``, where ``k`` and ``k2`` are integers. + + ``k.fadd(k2)`` + ~~~~~~~~~~~~~~ + + ``k + k2``, where ``k`` and ``k2`` are floating-point. + + ``k.sub(k2)`` + ~~~~~~~~~~~~~ + + ``k - k2``, where ``k`` and ``k2`` are integers. + + ``k.fsub(k2)`` + ~~~~~~~~~~~~~~ + + ``k - k2``, where ``k`` and ``k2`` are floating-point. + + ``k.mul(k2)`` + ~~~~~~~~~~~~~ + + ``k * k2``, where ``k`` and ``k2`` are integers. + + ``k.fmul(k2)`` + ~~~~~~~~~~~~~~ + + ``k * k2``, where ``k`` and ``k2`` are floating-point. + + ``k.udiv(k2)`` + ~~~~~~~~~~~~~~ + + Quotient of unsigned division of ``k`` with ``k2`` + + ``k.sdiv(k2)`` + ~~~~~~~~~~~~~~ + + Quotient of signed division of ``k`` with ``k2`` + + ``k.fdiv(k2)`` + ~~~~~~~~~~~~~~ + + Quotient of floating point division of ``k`` with ``k2`` + + ``k.urem(k2)`` + ~~~~~~~~~~~~~~ + + Reminder of unsigned division of ``k`` with ``k2`` + + ``k.srem(k2)`` + ~~~~~~~~~~~~~~ + + Reminder of signed division of ``k`` with ``k2`` + + ``k.frem(k2)`` + ~~~~~~~~~~~~~~ + + Reminder of floating point division of ``k`` with ``k2`` + + ``k.and_(k2)`` + ~~~~~~~~~~~~~~ + + Bitwise and of ``k`` and ``k2``. Note trailing underscore. + + ``k.or_(k2)`` + ~~~~~~~~~~~~~ + + Bitwise or of ``k`` and ``k2``. Note trailing underscore. + + ``k.xor(k2)`` + ~~~~~~~~~~~~~ + + Bitwise exclusive-or of ``k`` and ``k2``. + + ``k.icmp(icmp, k2)`` + ~~~~~~~~~~~~~~~~~~~~ + + Compare ``k`` with ``k2`` using the predicate ``icmp``. See + `here `_ for list of predicates for integer + operands. + + ``k.fcmp(fcmp, k2)`` + ~~~~~~~~~~~~~~~~~~~~ + + Compare ``k`` with ``k2`` using the predicate ``fcmp``. See + `here `_ for list of predicates for real + operands. + + ``k.shl(k2)`` + ~~~~~~~~~~~~~ + + Shift ``k`` left by ``k2`` bits. + + ``k.lshr(k2)`` + ~~~~~~~~~~~~~~ + + Shift ``k`` logically right by ``k2`` bits (new bits are 0s). + + ``k.ashr(k2)`` + ~~~~~~~~~~~~~~ + + Shift ``k`` arithmetically right by ``k2`` bits (new bits are same as + previous sign bit). + + ``k.gep(indices)`` + ~~~~~~~~~~~~~~~~~~ + + GEP, see `LLVM docs `_. + + ``k.trunc(ty)`` + ~~~~~~~~~~~~~~~ + + Truncate ``k`` to a type ``ty`` of lower bitwidth. + + ``k.sext(ty)`` + ~~~~~~~~~~~~~~ + + Sign extend ``k`` to a type ``ty`` of higher bitwidth, while extending + the sign bit. + + ``k.zext(ty)`` + ~~~~~~~~~~~~~~ + + Sign extend ``k`` to a type ``ty`` of higher bitwidth, all new bits are + 0s. + + ``k.fptrunc(ty)`` + ~~~~~~~~~~~~~~~~~ + + Truncate floating point constant ``k`` to floating point type ``ty`` of + lower size than k's. + + ``k.fpext(ty)`` + ~~~~~~~~~~~~~~~ + + Extend floating point constant ``k`` to floating point type ``ty`` of + higher size than k's. + + ``k.uitofp(ty)`` + ~~~~~~~~~~~~~~~~ + + Convert an unsigned integer constant ``k`` to floating point constant of + type ``ty``. + + ``k.sitofp(ty)`` + ~~~~~~~~~~~~~~~~ + + Convert a signed integer constant ``k`` to floating point constant of + type ``ty``. + + ``k.fptoui(ty)`` + ~~~~~~~~~~~~~~~~ + + Convert a floating point constant ``k`` to an unsigned integer constant + of type ``ty``. + + ``k.fptosi(ty)`` + ~~~~~~~~~~~~~~~~ + + Convert a floating point constant ``k`` to a signed integer constant of + type ``ty``. + + ``k.ptrtoint(ty)`` + ~~~~~~~~~~~~~~~~~~ + + Convert a pointer constant ``k`` to an integer constant of type ``ty``. + + ``k.inttoptr(ty)`` + ~~~~~~~~~~~~~~~~~~ + + Convert an integer constant ``k`` to a pointer constant of type ``ty``. + + ``k.bitcast(ty)`` + ~~~~~~~~~~~~~~~~~ + + Convert ``k`` to a (equal-width) constant of type ``ty``. + + ``k.select(cond,k2,k3)`` + ~~~~~~~~~~~~~~~~~~~~~~~~ + + Replace value with ``k2`` if the 1-bit integer constant ``cond`` is 1, + else with ``k3``. + + ``k.extract_element(idx)`` + ~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Extract value at ``idx`` (integer constant) from a vector constant + ``k``. + + ``k.insert_element(k2,idx)`` + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Insert value ``k2`` (scalar constant) at index ``idx`` (integer + constant) of vector constant ``k``. + + ``k.shuffle_vector(k2,mask)`` + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Shuffle vector constant ``k`` based on vector constants ``k2`` and + ``mask``. + + -------------- + + # Other Constant Classes + The following subclasses of ``Constant`` do not provide additional + methods, **they serve only to provide richer type information.** + + Subclass \| LLVM C++ Class \| Remarks \| + ---------\|----------------\|---------\| ``ConstantExpr`` \| + ``llvmConstantExpr`` \| A constant expression \| + ``ConstantAggregateZero``\ \| ``llvmConstantAggregateZero``\ \| All-zero + constant \| ``ConstantInt``\ \| ``llvmConstantInt``\ \| An integer + constant \| ``ConstantFP``\ \| ``llvmConstantFP``\ \| A floating-point + constant \| ``ConstantArray``\ \| ``llvmConstantArray``\ \| An array + constant \| ``ConstantStruct``\ \| ``llvmConstantStruct``\ \| A + structure constant \| ``ConstantVector``\ \| ``llvmConstantVector``\ \| + A vector constant \| ``ConstantPointerNull``\ \| + ``llvmConstantPointerNull``\ \| All-zero pointer constant \| + ``UndefValue``\ \| ``llvmUndefValue``\ \| corresponds to ``undef`` of + LLVM IR \| + + These types are helpful in ``isinstance`` checks, like so: + + {% highlight python %} ti = Type.int(32) k1 = Constant.int(ti, 42) # + int32_t k1 = 42; k2 = Constant.array(ti, [k1, k1]) # int32_t k2[] = { + k1, k1 }; + + assert isinstance(k1, ConstantInt) assert isinstance(k2, ConstantArray) + diff --git a/docs/source/doc/llvm.core.FunctionType.rst b/docs/source/doc/llvm.core.FunctionType.rst index 6704ebe..8d40009 100644 --- a/docs/source/doc/llvm.core.FunctionType.rst +++ b/docs/source/doc/llvm.core.FunctionType.rst @@ -39,14 +39,10 @@ Returns an iterable object that yields `Type `_ objects that represent, in order, the types of the arguments accepted by the function. Used like this: -{% highlight python %} func\_type = Type.function( Type.int(), [ -Type.int(), Type.int() ] ) for arg in func\_type.args: assert arg.kind -== TYPE\_INTEGER assert arg == Type.int() assert func\_type.arg\_count -== len(func\_type.args) {% endhighlight %} -``arg_count`` -~~~~~~~~~~~~~ +.. code-block:: python -[read-only] - -The number of arguments. Same as ``len(obj.args)``, but faster. + func_type = Type.function( Type.int(), [ + Type.int(), Type.int() ] ) for arg in func_type.args: assert arg.kind + == TYPE_INTEGER assert arg == Type.int() assert func_type.arg_count + == len(func_type.args) diff --git a/docs/source/doc/llvm.core.GlobalVariable.rst b/docs/source/doc/llvm.core.GlobalVariable.rst index bee596d..392a6a0 100644 --- a/docs/source/doc/llvm.core.GlobalVariable.rst +++ b/docs/source/doc/llvm.core.GlobalVariable.rst @@ -11,93 +11,29 @@ marked as constants. Global variables can be created either by using the ``add_global_variable`` method of the `Module `_ class, or by using the static method ``GlobalVariable.new``. -{% highlight python %} # create a global variable using -add\_global\_variable method gv1 = -module\_obj.add\_global\_variable(Type.int(), "gv1") -or equivalently, using a static constructor method -================================================== +.. code-block:: python -gv2 = GlobalVariable.new(module\_obj, Type.int(), "gv2") {% endhighlight -%} - -Existing global variables of a module can be accessed by name using -``module_obj.get_global_variable_named(name)`` or -``GlobalVariable.get``. All existing global variables can be enumerated -via iterating over the property ``module_obj.global_variables``. - -{% highlight python %} # retrieve a reference to the global variable -gv1, # using the get\_global\_variable\_named method gv1 = -module\_obj.get\_global\_variable\_named("gv1") - -or equivalently, using the static ``get`` method: -================================================= - -gv2 = GlobalVariable.get(module\_obj, "gv2") - -list all global variables in a module -===================================== - -for gv in module\_obj.global\_variables: print gv.name, "of type", -gv.type {% endhighlight %} - -The initializer for a global variable can be set by assigning to the -``initializer`` property of the object. The ``is_global_constant`` -property can be used to indicate that the variable is a global constant. - -Global variables can be delete using the ``delete`` method. Do not use -the object after calling ``delete`` on it. - -{% highlight python %} # add an initializer 10 (32-bit integer) -gv.initializer = Constant.int( Type.int(), 10 ) - -delete the global -================= - -gv.delete() # DO NOT dereference \`gv' beyond this point! gv = None {% -endhighlight %} - -llvm.core.GlobalVariable -======================== - -Base Class ----------- - -- `llvm.core.GlobalValue `_ - -Static Constructors -------------------- - -``new(module_obj, ty, name)`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Create a global variable named ``name`` of type ``ty`` in the module -``module_obj`` and return a ``GlobalVariable`` object that represents -it. - -``get(module_obj, name)`` -~~~~~~~~~~~~~~~~~~~~~~~~~ - -Return a ``GlobalVariable`` object to represent the global variable -named ``name`` in the module ``module_obj`` or raise ``LLVMException`` -if such a variable does not exist. - -Properties ----------- - -``initializer`` -~~~~~~~~~~~~~~~ - -The intializer of the variable. Set to -`llvm.core.Constant `_ (or derived). Gets the -initializer constant, or ``None`` if none exists. ``global_constant`` -``True`` if the variable is a global constant, ``False`` otherwise. - -Methods -------- - -``delete()`` -~~~~~~~~~~~~ - -Deletes the global variable from it's module. **Do not hold any -references to this object after calling ``delete`` on it.** + # create a global variable using + add_global_variable method gv1 = + module_obj.add_global_variable(Type.int(), "gv1") + + # or equivalently, using a static constructor method + gv2 = GlobalVariable.new(module_obj, Type.int(), "gv2") {% endhighlight + %} + + Existing global variables of a module can be accessed by name using + ``module_obj.get_global_variable_named(name)`` or + ``GlobalVariable.get``. All existing global variables can be enumerated + via iterating over the property ``module_obj.global_variables``. + + {% highlight python %} # retrieve a reference to the global variable + gv1, # using the get_global_variable_named method gv1 = + module_obj.get_global_variable_named("gv1") + + # or equivalently, using the static ``get`` method: + gv2 = GlobalVariable.get(module_obj, "gv2") + + # list all global variables in a module + for gv in module_obj.global_variables: print gv.name, "of type", + gv.type diff --git a/docs/source/doc/llvm.core.Module.rst b/docs/source/doc/llvm.core.Module.rst index 19b810a..3dbd5c8 100644 --- a/docs/source/doc/llvm.core.Module.rst +++ b/docs/source/doc/llvm.core.Module.rst @@ -8,226 +8,12 @@ Modules are top-level container objects. You need to create a module object first, before you can add global variables, aliases or functions. Modules are created using the static method ``Module.new``: -{% highlight python %} #!/usr/bin/env python -from llvm import \* from llvm.core import \* +.. code-block:: python -create a module -=============== - -my\_module = Module.new('my\_module') {% endhighlight %} - -The constructor of the Module class should *not* be used to instantiate -a Module object. This is a common feature for all llvmpy classes. - - **Convention** - - *All* llvmpy objects are instantiated using static methods of - corresponding classes. Constructors *should not* be used. - - The argument ``my_module`` is a module identifier (a plain string). - A module can also be constructed via deserialization from a bit code - file, using the static method ``from_bitcode``. This method takes a - file-like object as argument, i.e., it should have a ``read()`` - method that returns the entire data in a single call, as is the case - with the builtin file object. Here is an example: - -{% highlight python %} # create a module from a bit code file bcfile = -file("test.bc") my\_module = Module.from\_bitcode(bcfile) {% -endhighlight %} - -There is corresponding serialization method also, called ``to_bitcode``: - -{% highlight python %} # write out a bit code file from the module -bcfile = file("test.bc", "w") my\_module.to\_bitcode(bcfile) {% -endhighlight %} - -Modules can also be constructed from LLVM assembly files (``.ll`` -files). The static method ``from_assembly`` can be used for this. -Similar to the ``from_bitcode`` method, this one also takes a file-like -object as argument: - -{% highlight python %} # create a module from an assembly file llfile = -file("test.ll") my\_module = Module.from\_assembly(llfile) {% -endhighlight %} - -Modules can be converted into their assembly representation by -stringifying them (see below). - --------------- - -llvm.core.Module -================ - -- This will become a table of contents (this text will be scraped). - {:toc} - -Static Constructors -------------------- - -``new(module_id)`` -~~~~~~~~~~~~~~~~~~ - -Create a new ``Module`` instance with given ``module_id``. The -``module_id`` should be a string. - -``from_bitcode(fileobj)`` -~~~~~~~~~~~~~~~~~~~~~~~~~ - -Create a new ``Module`` instance by deserializing the bitcode file -represented by the file-like object ``fileobj``. - -``from_assembly(fileobj)`` -~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Create a new ``Module`` instance by parsing the LLVM assembly file -represented by the file-like object ``fileobj``. - -Properties ----------- - -``data_layout`` -~~~~~~~~~~~~~~~ - -A string representing the ABI of the platform. - -``target`` -~~~~~~~~~~ - -A string like ``i386-pc-linux-gnu`` or ``i386-pc-solaris2.8``. - -``pointer_size`` -~~~~~~~~~~~~~~~~ - -[read-only] - -The size in bits of pointers, of the target platform. A value of zero -represents ``llvm::Module::AnyPointerSize``. - -``global_variables`` -~~~~~~~~~~~~~~~~~~~~ - -[read-only] - -An iterable that yields -`GlobalVariable `_ objects, that -represent the global variables of the module. - -``functions`` -~~~~~~~~~~~~~ - -[read-only] - -An iterable that yields `Function `_ objects, -that represent functions in the module. - -``id`` -~~~~~~ - -A string that represents the module identifier (name). - -Methods -------- - -``get_type_named(name)`` -~~~~~~~~~~~~~~~~~~~~~~~~ - -Return a `StructType `_ object for the given -name. - -The definition of this method was changed to work with LLVM 3.0+, in -which the type system was rewritten. See `LLVM -Blog `_. - -{% comment %} ++++++++REMOVED+++++++++++ ### ``add_type_name(name, ty)`` - -Add an alias (typedef) for the type ``ty`` with the name ``name``. - -``delete_type_name(name)`` -~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Delete an alias with the name ``name``. ++++++++END-REMOVED+++++++++++ -{% endcomment %} - -``add_global_variable(ty, name)`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Add a global variable of the type ``ty`` with the name ``name``. Returns -a `GlobalVariable `_ object. - -``get_global_variable_named(name)`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Get a `GlobalVariable `_ object -corresponding to the global variable with the name ``name``. Raises -``LLVMException`` if such a variable does not exist. - -``add_library(name)`` -~~~~~~~~~~~~~~~~~~~~~ - -Add a dependent library to the Module. This only adds a name to a list -of dependent library. **No linking is performed**. - -``add_function(ty, name)`` -~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Add a function named ``name`` with the function type ``ty``. ``ty`` must -of an object of type `FunctionType `_. - -``get_function_named(name)`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Get a `Function `_ object corresponding to the -function with the name ``name``. Raises ``LLVMException`` if such a -function does not exist. - -``get_or_insert_function(ty, name)`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Like ``get_function_named``, but adds the function first, if not present -(like ``add_function``). - -``verify()`` -~~~~~~~~~~~~ - -Verify the correctness of the module. Raises ``LLVMException`` on -errors. - -``to_bitcode(fileobj)`` -~~~~~~~~~~~~~~~~~~~~~~~ - -Write the bitcode representation of the module to the file-like object -``fileobj``. - -``link_in(other)`` -~~~~~~~~~~~~~~~~~~ - -Link in another module ``other`` into this module. Global variables, -functions etc. are matched and resolved. The ``other`` module is no -longer valid and should not be used after this operation. This API might -be replaced with a full-fledged Linker class in the future. - -Special Methods ---------------- - -``__str__`` -~~~~~~~~~~~ - -``Module`` objects can be stringified into it's LLVM assembly language -representation. - -``__eq__`` -~~~~~~~~~~ - -``Module`` objects can be compared for equality. Internally, this -converts both arguments into their LLVM assembly representations and -compares the resultant strings. - - **Convention** - - *All* llvmpy objects (where it makes sense), when stringified, - return the LLVM assembly representation. ``print module_obj`` for - example, prints the LLVM assembly form of the entire module. - - Such objects, when compared for equality, internally compare these - string representations. + #!/usr/bin/env python + + from llvm import \* from llvm.core import \* + + # create a module + my_module = Module.new('my_module') diff --git a/docs/source/doc/llvm.core.StructType.rst b/docs/source/doc/llvm.core.StructType.rst index df0df17..e69de29 100644 --- a/docs/source/doc/llvm.core.StructType.rst +++ b/docs/source/doc/llvm.core.StructType.rst @@ -1,84 +0,0 @@ -+---------------------------------+ -| layout: page | -+---------------------------------+ -| title: StructType (llvm.core) | -+---------------------------------+ - -llvm.core.StructType -==================== - -Base Class ----------- - -- `llvm.core.Type `_ - -Methods -------- - -``set_body(self, elems, packed=False)`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Define the body for opaque identified structure. - -``elems`` is an iterable of `llvm.core.Type `_ If -``packed`` is ``True``, creates a packed structure. - -Properties ----------- - -``is_identified`` -~~~~~~~~~~~~~~~~~ - -[read-only] - -``True`` if this is an identified structure. - -``is_literal`` -~~~~~~~~~~~~~~ - -[read-only] - -``True`` if this is a literal structure. - -``is_opaque`` -~~~~~~~~~~~~~ - -[read-only] - -``True`` if this is an opaque structure. Only identified structure can -be opaque. - -``packed`` -~~~~~~~~~~ - -[read-only] - -``True`` if the structure is packed (no padding between elements). - -``name`` -~~~~~~~~ - -Use in identified structure. If set to empty, the identified structure -is removed from the global context. - -``elements`` -~~~~~~~~~~~~ - -[read-only] - -Returns an iterable object that yields `Type `_ -objects that represent, in order, the types of the elements of the -structure. Used like this: - -{% highlight python %} struct\_type = Type.struct( [ Type.int(), -Type.int() ] ) for elem in struct\_type.elements: assert elem.kind == -TYPE\_INTEGER assert elem == Type.int() assert -struct\_type.element\_count == len(struct\_type.elements) {% -endhighlight %} - -``element_count`` -~~~~~~~~~~~~~~~~~ - -[read-only] - -The number of elements. Same as ``len(obj.elements)``, but faster. diff --git a/docs/source/doc/llvm.core.Type.rst b/docs/source/doc/llvm.core.Type.rst index 7cd43ae..58883d7 100644 --- a/docs/source/doc/llvm.core.Type.rst +++ b/docs/source/doc/llvm.core.Type.rst @@ -106,40 +106,23 @@ Properties A value (enum) representing the "type" of the object. It will be one of the following constants defined in ``llvm.core``: -{% highlight python %} # Warning: do not rely on actual numerical -values! TYPE\_VOID = 0 TYPE\_FLOAT = 1 TYPE\_DOUBLE = 2 TYPE\_X86\_FP80 -= 3 TYPE\_FP128 = 4 TYPE\_PPC\_FP128 = 5 TYPE\_LABEL = 6 TYPE\_INTEGER = -7 TYPE\_FUNCTION = 8 TYPE\_STRUCT = 9 TYPE\_ARRAY = 10 TYPE\_POINTER = -11 TYPE\_OPAQUE = 12 TYPE\_VECTOR = 13 TYPE\_METADATA = 14 TYPE\_UNION = -15 {% endhighlight %} + +.. code-block:: python + + # Warning: do not rely on actual numerical + values! TYPE_VOID = 0 TYPE_FLOAT = 1 TYPE_DOUBLE = 2 TYPE_X86_FP80 + = 3 TYPE_FP128 = 4 TYPE_PPC_FP128 = 5 TYPE_LABEL = 6 TYPE_INTEGER = + 7 TYPE_FUNCTION = 8 TYPE_STRUCT = 9 TYPE_ARRAY = 10 TYPE_POINTER = + 11 TYPE_OPAQUE = 12 TYPE_VECTOR = 13 TYPE_METADATA = 14 TYPE_UNION = + 15 + + Example: ^^^^^^^^ -{% highlight python %} assert Type.int().kind == TYPE\_INTEGER assert -Type.void().kind == TYPE\_VOID {% endhighlight %} -Methods -------- +.. code-block:: python -``refine`` -~~~~~~~~~~ - -Used for constructing self-referencing types. See the documentation of -`TypeHandle `_ objects. - -Special Methods ---------------- - -``__str__`` -~~~~~~~~~~~ - -``Type`` objects can be stringified into it's LLVM assembly language -representation. - -``__eq__`` -~~~~~~~~~~ - -``Type`` objects can be compared for equality. Internally, this converts -both arguments into their LLVM assembly representations and compares the -resultant strings. + assert Type.int().kind == TYPE_INTEGER assert + Type.void().kind == TYPE_VOID diff --git a/docs/source/doc/llvmpy_package.rst b/docs/source/doc/llvmpy_package.rst index fc690fc..0ac603a 100644 --- a/docs/source/doc/llvmpy_package.rst +++ b/docs/source/doc/llvmpy_package.rst @@ -80,15 +80,8 @@ Pythonically, modules are imported with the statement ``import llvm.core``. However, you might find it more convenient to import llvmpy modules thus: -{% highlight python %} from llvm import \* from llvm.core import \* from -llvm.ee import \* from llvm.passes import \* {% endhighlight %} -This avoids quite some typing. Both conventions work, however. +.. code-block:: python - **Tip** - - Python-style documentation strings (``__doc__``) are present in - llvmpy. You can use the ``help()`` of the interactive Python - interpreter or the ``object?`` of - `IPython `_ to get online help. - (Note: not complete yet!) + from llvm import \* from llvm.core import \* from + llvm.ee import \* from llvm.passes import \* diff --git a/docs/source/doc/types.rst b/docs/source/doc/types.rst index 2ca095c..f3b9da2 100644 --- a/docs/source/doc/types.rst +++ b/docs/source/doc/types.rst @@ -60,50 +60,43 @@ An Example Here is an example that demonstrates the creation of types: -{% highlight python %} #!/usr/bin/env python -integers -======== +.. code-block:: python -int\_ty = Type.int() bool\_ty = Type.int(1) int\_64bit = Type.int(64) + #!/usr/bin/env python + + # integers + int_ty = Type.int() bool_ty = Type.int(1) int_64bit = Type.int(64) + + # floats + sprec_real = Type.float() dprec_real = Type.double() + + # arrays and vectors + intar_ty = Type.array( int_ty, 10 ) # "typedef int intar_ty[10];" + twodim = Type.array( intar_ty , 10 ) # "typedef int twodim[10][10];" + vec = Type.array( int_ty, 10 ) + + # structures + s1_ty = Type.struct( [ int_ty, sprec_real ] ) # "struct s1_ty { int + v1; float v2; };" + + # pointers + intptr_ty = Type.pointer(int_ty) # "typedef int \*intptr_ty;" + + # functions + f1 = Type.function( int_ty, [ int_ty ] ) # functions that take 1 + int_ty and return 1 int_ty + + f2 = Type.function( Type.void(), [ int_ty, int_ty ] ) # functions that + take 2 int_tys and return nothing + + f3 = Type.function( Type.void(), ( int_ty, int_ty ) ) # same as f2; + any iterable can be used + + fnargs = [ Type.pointer( Type.int(8) ) ] printf = Type.function( + Type.int(), fnargs, True ) # variadic function -floats -====== -sprec\_real = Type.float() dprec\_real = Type.double() - -arrays and vectors -================== - -intar\_ty = Type.array( int\_ty, 10 ) # "typedef int intar\_ty[10];" -twodim = Type.array( intar\_ty , 10 ) # "typedef int twodim[10][10];" -vec = Type.array( int\_ty, 10 ) - -structures -========== - -s1\_ty = Type.struct( [ int\_ty, sprec\_real ] ) # "struct s1\_ty { int -v1; float v2; };" - -pointers -======== - -intptr\_ty = Type.pointer(int\_ty) # "typedef int \*intptr\_ty;" - -functions -========= - -f1 = Type.function( int\_ty, [ int\_ty ] ) # functions that take 1 -int\_ty and return 1 int\_ty - -f2 = Type.function( Type.void(), [ int\_ty, int\_ty ] ) # functions that -take 2 int\_tys and return nothing - -f3 = Type.function( Type.void(), ( int\_ty, int\_ty ) ) # same as f2; -any iterable can be used - -fnargs = [ Type.pointer( Type.int(8) ) ] printf = Type.function( -Type.int(), fnargs, True ) # variadic function {% endhighlight %} -------------- @@ -123,16 +116,8 @@ The following code defines a opaque structure, named "mystruct". The body is defined after the construction using ``StructType.set_body``. The second subtype is a pointer to a "mystruct" type. -{% highlight python %} ts = Type.opaque('mystruct') -ts.set\_body([Type.int(), Type.pointer(ts)]) {% endhighlight %} --------------- +.. code-block:: python -**Related Links** `llvm.core.Type `_, -`llvm.core.IntegerType `_, -`llvm.core.FunctionType `_, -`llvm.core.StructType `_, -`llvm.core.ArrayType `_, -`llvm.core.PointerType `_, -`llvm.core.VectorType `_, -`llvm.core.TypeHandle `_ + ts = Type.opaque('mystruct') + ts.set_body([Type.int(), Type.pointer(ts)]) From 83f24e90d31cff0bd8a294d277a81e8f7a059974 Mon Sep 17 00:00:00 2001 From: Maggie Mari Date: Fri, 10 Aug 2012 11:30:07 -0500 Subject: [PATCH 064/675] Cleaned up some of the highlightin in getting_started.rst and llvmpy-package.rst --- docs/_build/doctrees/doc/comparision.doctree | Bin 0 -> 19384 bytes docs/_build/doctrees/doc/examples.doctree | Bin 0 -> 2949 bytes .../doc/examples/JITTutorial1.doctree | Bin 0 -> 4052 bytes .../doc/examples/JITTutorial2.doctree | Bin 0 -> 5705 bytes .../doctrees/doc/examples/index.doctree | Bin 0 -> 3158 bytes docs/_build/doctrees/doc/firstexample.doctree | Bin 0 -> 10427 bytes docs/_build/doctrees/doc/functions.doctree | Bin 0 -> 27801 bytes .../doctrees/doc/getting_started.doctree | Bin 0 -> 22836 bytes .../doc/kaleidoscope/PythonLangImpl1.doctree | Bin 0 -> 49143 bytes .../doc/kaleidoscope/PythonLangImpl2.doctree | Bin 0 -> 104735 bytes .../doc/kaleidoscope/PythonLangImpl3.doctree | Bin 0 -> 106562 bytes .../doc/kaleidoscope/PythonLangImpl4.doctree | Bin 0 -> 78301 bytes .../doc/kaleidoscope/PythonLangImpl5.doctree | Bin 0 -> 122555 bytes .../doc/kaleidoscope/PythonLangImpl6.doctree | Bin 0 -> 123192 bytes .../doc/kaleidoscope/PythonLangImpl7.doctree | Bin 0 -> 140548 bytes .../doc/kaleidoscope/PythonLangImpl8.doctree | Bin 0 -> 2166 bytes .../doctrees/doc/kaleidoscope/index.doctree | Bin 0 -> 4715 bytes .../doctrees/doc/llvm.core.Argument.doctree | Bin 0 -> 16403 bytes .../doctrees/doc/llvm.core.ArrayType.doctree | Bin 0 -> 6680 bytes .../doctrees/doc/llvm.core.BasicBlock.doctree | Bin 0 -> 8950 bytes .../doctrees/doc/llvm.core.Builder.doctree | Bin 0 -> 84524 bytes .../doctrees/doc/llvm.core.Constant.doctree | Bin 0 -> 19588 bytes .../doctrees/doc/llvm.core.Function.doctree | Bin 0 -> 30776 bytes .../doc/llvm.core.FunctionType.doctree | Bin 0 -> 9718 bytes .../doc/llvm.core.GlobalValue.doctree | Bin 0 -> 26164 bytes .../doc/llvm.core.GlobalVariable.doctree | Bin 0 -> 8086 bytes .../doc/llvm.core.Instruction.doctree | Bin 0 -> 49238 bytes .../doc/llvm.core.IntegerType.doctree | Bin 0 -> 5769 bytes .../doctrees/doc/llvm.core.Module.doctree | Bin 0 -> 4380 bytes .../doc/llvm.core.PointerType.doctree | Bin 0 -> 7196 bytes .../doctrees/doc/llvm.core.StructType.doctree | Bin 0 -> 2148 bytes .../doctrees/doc/llvm.core.Type.doctree | Bin 0 -> 21715 bytes .../doctrees/doc/llvm.core.User.doctree | Bin 0 -> 9119 bytes .../doctrees/doc/llvm.core.Value.doctree | Bin 0 -> 10854 bytes .../doctrees/doc/llvm.core.VectorType.doctree | Bin 0 -> 7177 bytes .../doc/llvm.ee.EngineBuilder.doctree | Bin 0 -> 14033 bytes .../doc/llvm.ee.ExecutionEngine.doctree | Bin 0 -> 13526 bytes .../doctrees/doc/llvm.ee.GenericValue.doctree | Bin 0 -> 15924 bytes .../doctrees/doc/llvm.ee.TargetData.doctree | Bin 0 -> 11729 bytes .../llvm.passes.FunctionPassManager.doctree | Bin 0 -> 8953 bytes .../doc/llvm.passes.PassManager.doctree | Bin 0 -> 6289 bytes .../llvm.passes.PassManagerBuilder.doctree | Bin 0 -> 14720 bytes .../_build/doctrees/doc/llvm_concepts.doctree | Bin 0 -> 44370 bytes .../doctrees/doc/llvmpy_package.doctree | Bin 0 -> 26959 bytes docs/_build/doctrees/doc/types.doctree | Bin 0 -> 29126 bytes docs/_build/doctrees/doc/userguide.doctree | Bin 0 -> 3337 bytes docs/_build/doctrees/doc/values.doctree | Bin 0 -> 27612 bytes docs/_build/doctrees/environment.pickle | Bin 0 -> 189259 bytes docs/_build/doctrees/index.doctree | Bin 0 -> 5987 bytes docs/_build/html/.buildinfo | 4 + docs/_build/html/_sources/doc/comparision.txt | 147 ++ docs/_build/html/_sources/doc/examples.txt | 12 + .../_sources/doc/examples/JITTutorial1.txt | 36 + .../_sources/doc/examples/JITTutorial2.txt | 55 + .../html/_sources/doc/examples/index.txt | 10 + .../_build/html/_sources/doc/firstexample.txt | 125 ++ docs/_build/html/_sources/doc/functions.txt | 149 ++ .../html/_sources/doc/getting_started.txt | 112 ++ .../doc/kaleidoscope/PythonLangImpl1.txt | 323 ++++ .../doc/kaleidoscope/PythonLangImpl2.txt | 963 ++++++++++ .../doc/kaleidoscope/PythonLangImpl3.txt | 979 ++++++++++ .../doc/kaleidoscope/PythonLangImpl4.txt | 808 +++++++++ .../doc/kaleidoscope/PythonLangImpl5.txt | 1411 +++++++++++++++ .../doc/kaleidoscope/PythonLangImpl6.txt | 1357 ++++++++++++++ .../doc/kaleidoscope/PythonLangImpl7.txt | 1611 +++++++++++++++++ .../doc/kaleidoscope/PythonLangImpl8.txt | 0 .../html/_sources/doc/kaleidoscope/index.txt | 21 + .../html/_sources/doc/llvm.core.Argument.txt | 58 + .../html/_sources/doc/llvm.core.ArrayType.txt | 30 + .../_sources/doc/llvm.core.BasicBlock.txt | 44 + .../html/_sources/doc/llvm.core.Builder.txt | 411 +++++ .../html/_sources/doc/llvm.core.Constant.txt | 353 ++++ .../html/_sources/doc/llvm.core.Function.txt | 151 ++ .../_sources/doc/llvm.core.FunctionType.txt | 48 + .../_sources/doc/llvm.core.GlobalValue.txt | 97 + .../_sources/doc/llvm.core.GlobalVariable.txt | 39 + .../_sources/doc/llvm.core.Instruction.txt | 242 +++ .../_sources/doc/llvm.core.IntegerType.txt | 23 + .../html/_sources/doc/llvm.core.Module.txt | 19 + .../_sources/doc/llvm.core.PointerType.txt | 31 + .../_sources/doc/llvm.core.StructType.txt | 0 .../html/_sources/doc/llvm.core.Type.txt | 128 ++ .../html/_sources/doc/llvm.core.User.txt | 39 + .../html/_sources/doc/llvm.core.Value.txt | 65 + .../_sources/doc/llvm.core.VectorType.txt | 31 + .../_sources/doc/llvm.ee.EngineBuilder.txt | 56 + .../_sources/doc/llvm.ee.ExecutionEngine.txt | 62 + .../_sources/doc/llvm.ee.GenericValue.txt | 64 + .../html/_sources/doc/llvm.ee.TargetData.txt | 70 + .../doc/llvm.passes.FunctionPassManager.txt | 42 + .../_sources/doc/llvm.passes.PassManager.txt | 29 + .../doc/llvm.passes.PassManagerBuilder.txt | 72 + .../html/_sources/doc/llvm_concepts.txt | 236 +++ .../html/_sources/doc/llvmpy_package.txt | 89 + docs/_build/html/_sources/doc/types.txt | 123 ++ docs/_build/html/_sources/doc/userguide.txt | 17 + docs/_build/html/_sources/doc/values.txt | 78 + docs/_build/html/_sources/index.txt | 25 + docs/_build/html/_static/ajax-loader.gif | Bin 0 -> 673 bytes docs/_build/html/_static/basic.css | 540 ++++++ docs/_build/html/_static/comment-bright.png | Bin 0 -> 3500 bytes docs/_build/html/_static/comment-close.png | Bin 0 -> 3578 bytes docs/_build/html/_static/comment.png | Bin 0 -> 3445 bytes docs/_build/html/_static/default.css | 256 +++ docs/_build/html/_static/doctools.js | 247 +++ docs/_build/html/_static/down-pressed.png | Bin 0 -> 368 bytes docs/_build/html/_static/down.png | Bin 0 -> 363 bytes docs/_build/html/_static/file.png | Bin 0 -> 392 bytes docs/_build/html/_static/jquery.js | 154 ++ docs/_build/html/_static/minus.png | Bin 0 -> 199 bytes docs/_build/html/_static/plus.png | Bin 0 -> 199 bytes docs/_build/html/_static/pygments.css | 62 + docs/_build/html/_static/searchtools.js | 560 ++++++ docs/_build/html/_static/sidebar.js | 151 ++ docs/_build/html/_static/underscore.js | 23 + docs/_build/html/_static/up-pressed.png | Bin 0 -> 372 bytes docs/_build/html/_static/up.png | Bin 0 -> 363 bytes docs/_build/html/_static/websupport.js | 808 +++++++++ docs/_build/html/doc/comparision.html | 251 +++ docs/_build/html/doc/examples.html | 120 ++ .../html/doc/examples/JITTutorial1.html | 151 ++ .../html/doc/examples/JITTutorial2.html | 170 ++ docs/_build/html/doc/examples/index.html | 123 ++ docs/_build/html/doc/firstexample.html | 237 +++ docs/_build/html/doc/functions.html | 223 +++ docs/_build/html/doc/getting_started.html | 222 +++ .../doc/kaleidoscope/PythonLangImpl1.html | 362 ++++ .../doc/kaleidoscope/PythonLangImpl2.html | 897 +++++++++ .../doc/kaleidoscope/PythonLangImpl3.html | 954 ++++++++++ .../doc/kaleidoscope/PythonLangImpl4.html | 844 +++++++++ .../doc/kaleidoscope/PythonLangImpl5.html | 1337 ++++++++++++++ .../doc/kaleidoscope/PythonLangImpl6.html | 1361 ++++++++++++++ .../doc/kaleidoscope/PythonLangImpl7.html | 1558 ++++++++++++++++ .../doc/kaleidoscope/PythonLangImpl8.html | 105 ++ docs/_build/html/doc/kaleidoscope/index.html | 144 ++ docs/_build/html/doc/llvm.core.Argument.html | 164 ++ docs/_build/html/doc/llvm.core.ArrayType.html | 136 ++ .../_build/html/doc/llvm.core.BasicBlock.html | 154 ++ docs/_build/html/doc/llvm.core.Builder.html | 521 ++++++ docs/_build/html/doc/llvm.core.Constant.html | 444 +++++ docs/_build/html/doc/llvm.core.Function.html | 261 +++ .../html/doc/llvm.core.FunctionType.html | 150 ++ .../html/doc/llvm.core.GlobalValue.html | 196 ++ .../html/doc/llvm.core.GlobalVariable.html | 131 ++ .../html/doc/llvm.core.Instruction.html | 368 ++++ .../html/doc/llvm.core.IntegerType.html | 130 ++ docs/_build/html/doc/llvm.core.Module.html | 111 ++ .../html/doc/llvm.core.PointerType.html | 137 ++ .../_build/html/doc/llvm.core.StructType.html | 90 + docs/_build/html/doc/llvm.core.Type.html | 231 +++ docs/_build/html/doc/llvm.core.User.html | 143 ++ docs/_build/html/doc/llvm.core.Value.html | 171 ++ .../_build/html/doc/llvm.core.VectorType.html | 137 ++ .../html/doc/llvm.ee.EngineBuilder.html | 163 ++ .../html/doc/llvm.ee.ExecutionEngine.html | 171 ++ .../_build/html/doc/llvm.ee.GenericValue.html | 173 ++ docs/_build/html/doc/llvm.ee.TargetData.html | 191 ++ .../doc/llvm.passes.FunctionPassManager.html | 152 ++ .../html/doc/llvm.passes.PassManager.html | 138 ++ .../doc/llvm.passes.PassManagerBuilder.html | 182 ++ docs/_build/html/doc/llvm_concepts.html | 325 ++++ docs/_build/html/doc/llvmpy_package.html | 212 +++ docs/_build/html/doc/types.html | 206 +++ docs/_build/html/doc/userguide.html | 124 ++ docs/_build/html/doc/values.html | 164 ++ docs/_build/html/genindex.html | 96 + docs/_build/html/index.html | 137 ++ docs/_build/html/objects.inv | Bin 0 -> 202 bytes docs/_build/html/search.html | 100 + docs/_build/html/searchindex.js | 1 + docs/source/doc/getting_started.rst | 5 +- docs/source/doc/llvmpy_package.rst | 6 +- 172 files changed, 28972 insertions(+), 4 deletions(-) create mode 100644 docs/_build/doctrees/doc/comparision.doctree create mode 100644 docs/_build/doctrees/doc/examples.doctree create mode 100644 docs/_build/doctrees/doc/examples/JITTutorial1.doctree create mode 100644 docs/_build/doctrees/doc/examples/JITTutorial2.doctree create mode 100644 docs/_build/doctrees/doc/examples/index.doctree create mode 100644 docs/_build/doctrees/doc/firstexample.doctree create mode 100644 docs/_build/doctrees/doc/functions.doctree create mode 100644 docs/_build/doctrees/doc/getting_started.doctree create mode 100644 docs/_build/doctrees/doc/kaleidoscope/PythonLangImpl1.doctree create mode 100644 docs/_build/doctrees/doc/kaleidoscope/PythonLangImpl2.doctree create mode 100644 docs/_build/doctrees/doc/kaleidoscope/PythonLangImpl3.doctree create mode 100644 docs/_build/doctrees/doc/kaleidoscope/PythonLangImpl4.doctree create mode 100644 docs/_build/doctrees/doc/kaleidoscope/PythonLangImpl5.doctree create mode 100644 docs/_build/doctrees/doc/kaleidoscope/PythonLangImpl6.doctree create mode 100644 docs/_build/doctrees/doc/kaleidoscope/PythonLangImpl7.doctree create mode 100644 docs/_build/doctrees/doc/kaleidoscope/PythonLangImpl8.doctree create mode 100644 docs/_build/doctrees/doc/kaleidoscope/index.doctree create mode 100644 docs/_build/doctrees/doc/llvm.core.Argument.doctree create mode 100644 docs/_build/doctrees/doc/llvm.core.ArrayType.doctree create mode 100644 docs/_build/doctrees/doc/llvm.core.BasicBlock.doctree create mode 100644 docs/_build/doctrees/doc/llvm.core.Builder.doctree create mode 100644 docs/_build/doctrees/doc/llvm.core.Constant.doctree create mode 100644 docs/_build/doctrees/doc/llvm.core.Function.doctree create mode 100644 docs/_build/doctrees/doc/llvm.core.FunctionType.doctree create mode 100644 docs/_build/doctrees/doc/llvm.core.GlobalValue.doctree create mode 100644 docs/_build/doctrees/doc/llvm.core.GlobalVariable.doctree create mode 100644 docs/_build/doctrees/doc/llvm.core.Instruction.doctree create mode 100644 docs/_build/doctrees/doc/llvm.core.IntegerType.doctree create mode 100644 docs/_build/doctrees/doc/llvm.core.Module.doctree create mode 100644 docs/_build/doctrees/doc/llvm.core.PointerType.doctree create mode 100644 docs/_build/doctrees/doc/llvm.core.StructType.doctree create mode 100644 docs/_build/doctrees/doc/llvm.core.Type.doctree create mode 100644 docs/_build/doctrees/doc/llvm.core.User.doctree create mode 100644 docs/_build/doctrees/doc/llvm.core.Value.doctree create mode 100644 docs/_build/doctrees/doc/llvm.core.VectorType.doctree create mode 100644 docs/_build/doctrees/doc/llvm.ee.EngineBuilder.doctree create mode 100644 docs/_build/doctrees/doc/llvm.ee.ExecutionEngine.doctree create mode 100644 docs/_build/doctrees/doc/llvm.ee.GenericValue.doctree create mode 100644 docs/_build/doctrees/doc/llvm.ee.TargetData.doctree create mode 100644 docs/_build/doctrees/doc/llvm.passes.FunctionPassManager.doctree create mode 100644 docs/_build/doctrees/doc/llvm.passes.PassManager.doctree create mode 100644 docs/_build/doctrees/doc/llvm.passes.PassManagerBuilder.doctree create mode 100644 docs/_build/doctrees/doc/llvm_concepts.doctree create mode 100644 docs/_build/doctrees/doc/llvmpy_package.doctree create mode 100644 docs/_build/doctrees/doc/types.doctree create mode 100644 docs/_build/doctrees/doc/userguide.doctree create mode 100644 docs/_build/doctrees/doc/values.doctree create mode 100644 docs/_build/doctrees/environment.pickle create mode 100644 docs/_build/doctrees/index.doctree create mode 100644 docs/_build/html/.buildinfo create mode 100644 docs/_build/html/_sources/doc/comparision.txt create mode 100644 docs/_build/html/_sources/doc/examples.txt create mode 100644 docs/_build/html/_sources/doc/examples/JITTutorial1.txt create mode 100644 docs/_build/html/_sources/doc/examples/JITTutorial2.txt create mode 100644 docs/_build/html/_sources/doc/examples/index.txt create mode 100644 docs/_build/html/_sources/doc/firstexample.txt create mode 100644 docs/_build/html/_sources/doc/functions.txt create mode 100644 docs/_build/html/_sources/doc/getting_started.txt create mode 100644 docs/_build/html/_sources/doc/kaleidoscope/PythonLangImpl1.txt create mode 100644 docs/_build/html/_sources/doc/kaleidoscope/PythonLangImpl2.txt create mode 100644 docs/_build/html/_sources/doc/kaleidoscope/PythonLangImpl3.txt create mode 100644 docs/_build/html/_sources/doc/kaleidoscope/PythonLangImpl4.txt create mode 100644 docs/_build/html/_sources/doc/kaleidoscope/PythonLangImpl5.txt create mode 100644 docs/_build/html/_sources/doc/kaleidoscope/PythonLangImpl6.txt create mode 100644 docs/_build/html/_sources/doc/kaleidoscope/PythonLangImpl7.txt create mode 100644 docs/_build/html/_sources/doc/kaleidoscope/PythonLangImpl8.txt create mode 100644 docs/_build/html/_sources/doc/kaleidoscope/index.txt create mode 100644 docs/_build/html/_sources/doc/llvm.core.Argument.txt create mode 100644 docs/_build/html/_sources/doc/llvm.core.ArrayType.txt create mode 100644 docs/_build/html/_sources/doc/llvm.core.BasicBlock.txt create mode 100644 docs/_build/html/_sources/doc/llvm.core.Builder.txt create mode 100644 docs/_build/html/_sources/doc/llvm.core.Constant.txt create mode 100644 docs/_build/html/_sources/doc/llvm.core.Function.txt create mode 100644 docs/_build/html/_sources/doc/llvm.core.FunctionType.txt create mode 100644 docs/_build/html/_sources/doc/llvm.core.GlobalValue.txt create mode 100644 docs/_build/html/_sources/doc/llvm.core.GlobalVariable.txt create mode 100644 docs/_build/html/_sources/doc/llvm.core.Instruction.txt create mode 100644 docs/_build/html/_sources/doc/llvm.core.IntegerType.txt create mode 100644 docs/_build/html/_sources/doc/llvm.core.Module.txt create mode 100644 docs/_build/html/_sources/doc/llvm.core.PointerType.txt create mode 100644 docs/_build/html/_sources/doc/llvm.core.StructType.txt create mode 100644 docs/_build/html/_sources/doc/llvm.core.Type.txt create mode 100644 docs/_build/html/_sources/doc/llvm.core.User.txt create mode 100644 docs/_build/html/_sources/doc/llvm.core.Value.txt create mode 100644 docs/_build/html/_sources/doc/llvm.core.VectorType.txt create mode 100644 docs/_build/html/_sources/doc/llvm.ee.EngineBuilder.txt create mode 100644 docs/_build/html/_sources/doc/llvm.ee.ExecutionEngine.txt create mode 100644 docs/_build/html/_sources/doc/llvm.ee.GenericValue.txt create mode 100644 docs/_build/html/_sources/doc/llvm.ee.TargetData.txt create mode 100644 docs/_build/html/_sources/doc/llvm.passes.FunctionPassManager.txt create mode 100644 docs/_build/html/_sources/doc/llvm.passes.PassManager.txt create mode 100644 docs/_build/html/_sources/doc/llvm.passes.PassManagerBuilder.txt create mode 100644 docs/_build/html/_sources/doc/llvm_concepts.txt create mode 100644 docs/_build/html/_sources/doc/llvmpy_package.txt create mode 100644 docs/_build/html/_sources/doc/types.txt create mode 100644 docs/_build/html/_sources/doc/userguide.txt create mode 100644 docs/_build/html/_sources/doc/values.txt create mode 100644 docs/_build/html/_sources/index.txt create mode 100644 docs/_build/html/_static/ajax-loader.gif create mode 100644 docs/_build/html/_static/basic.css create mode 100644 docs/_build/html/_static/comment-bright.png create mode 100644 docs/_build/html/_static/comment-close.png create mode 100644 docs/_build/html/_static/comment.png create mode 100644 docs/_build/html/_static/default.css create mode 100644 docs/_build/html/_static/doctools.js create mode 100644 docs/_build/html/_static/down-pressed.png create mode 100644 docs/_build/html/_static/down.png create mode 100644 docs/_build/html/_static/file.png create mode 100644 docs/_build/html/_static/jquery.js create mode 100644 docs/_build/html/_static/minus.png create mode 100644 docs/_build/html/_static/plus.png create mode 100644 docs/_build/html/_static/pygments.css create mode 100644 docs/_build/html/_static/searchtools.js create mode 100644 docs/_build/html/_static/sidebar.js create mode 100644 docs/_build/html/_static/underscore.js create mode 100644 docs/_build/html/_static/up-pressed.png create mode 100644 docs/_build/html/_static/up.png create mode 100644 docs/_build/html/_static/websupport.js create mode 100644 docs/_build/html/doc/comparision.html create mode 100644 docs/_build/html/doc/examples.html create mode 100644 docs/_build/html/doc/examples/JITTutorial1.html create mode 100644 docs/_build/html/doc/examples/JITTutorial2.html create mode 100644 docs/_build/html/doc/examples/index.html create mode 100644 docs/_build/html/doc/firstexample.html create mode 100644 docs/_build/html/doc/functions.html create mode 100644 docs/_build/html/doc/getting_started.html create mode 100644 docs/_build/html/doc/kaleidoscope/PythonLangImpl1.html create mode 100644 docs/_build/html/doc/kaleidoscope/PythonLangImpl2.html create mode 100644 docs/_build/html/doc/kaleidoscope/PythonLangImpl3.html create mode 100644 docs/_build/html/doc/kaleidoscope/PythonLangImpl4.html create mode 100644 docs/_build/html/doc/kaleidoscope/PythonLangImpl5.html create mode 100644 docs/_build/html/doc/kaleidoscope/PythonLangImpl6.html create mode 100644 docs/_build/html/doc/kaleidoscope/PythonLangImpl7.html create mode 100644 docs/_build/html/doc/kaleidoscope/PythonLangImpl8.html create mode 100644 docs/_build/html/doc/kaleidoscope/index.html create mode 100644 docs/_build/html/doc/llvm.core.Argument.html create mode 100644 docs/_build/html/doc/llvm.core.ArrayType.html create mode 100644 docs/_build/html/doc/llvm.core.BasicBlock.html create mode 100644 docs/_build/html/doc/llvm.core.Builder.html create mode 100644 docs/_build/html/doc/llvm.core.Constant.html create mode 100644 docs/_build/html/doc/llvm.core.Function.html create mode 100644 docs/_build/html/doc/llvm.core.FunctionType.html create mode 100644 docs/_build/html/doc/llvm.core.GlobalValue.html create mode 100644 docs/_build/html/doc/llvm.core.GlobalVariable.html create mode 100644 docs/_build/html/doc/llvm.core.Instruction.html create mode 100644 docs/_build/html/doc/llvm.core.IntegerType.html create mode 100644 docs/_build/html/doc/llvm.core.Module.html create mode 100644 docs/_build/html/doc/llvm.core.PointerType.html create mode 100644 docs/_build/html/doc/llvm.core.StructType.html create mode 100644 docs/_build/html/doc/llvm.core.Type.html create mode 100644 docs/_build/html/doc/llvm.core.User.html create mode 100644 docs/_build/html/doc/llvm.core.Value.html create mode 100644 docs/_build/html/doc/llvm.core.VectorType.html create mode 100644 docs/_build/html/doc/llvm.ee.EngineBuilder.html create mode 100644 docs/_build/html/doc/llvm.ee.ExecutionEngine.html create mode 100644 docs/_build/html/doc/llvm.ee.GenericValue.html create mode 100644 docs/_build/html/doc/llvm.ee.TargetData.html create mode 100644 docs/_build/html/doc/llvm.passes.FunctionPassManager.html create mode 100644 docs/_build/html/doc/llvm.passes.PassManager.html create mode 100644 docs/_build/html/doc/llvm.passes.PassManagerBuilder.html create mode 100644 docs/_build/html/doc/llvm_concepts.html create mode 100644 docs/_build/html/doc/llvmpy_package.html create mode 100644 docs/_build/html/doc/types.html create mode 100644 docs/_build/html/doc/userguide.html create mode 100644 docs/_build/html/doc/values.html create mode 100644 docs/_build/html/genindex.html create mode 100644 docs/_build/html/index.html create mode 100644 docs/_build/html/objects.inv create mode 100644 docs/_build/html/search.html create mode 100644 docs/_build/html/searchindex.js diff --git a/docs/_build/doctrees/doc/comparision.doctree b/docs/_build/doctrees/doc/comparision.doctree new file mode 100644 index 0000000000000000000000000000000000000000..9c7f1216a5f3b38fb86ad65cfce76adc8a8ab52f GIT binary patch literal 19384 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 hBLBrmIrW1+R?{{Y`@uz~;p literal 0 HcmV?d00001 diff --git a/docs/_build/doctrees/doc/examples.doctree b/docs/_build/doctrees/doc/examples.doctree new file mode 100644 index 0000000000000000000000000000000000000000..bde8a5b6a26315010aba60ef1f7b68b325e8aff6 GIT binary patch literal 2949 zcmb_e`Fk8k5tU`Hw7b@2$94j;h;o??MA`s>gm6O=6V@Isml4M>%+B;~H=3)ad!!XG zB!Y{K7B#Rx>?auU@@+RnN``VHy-hMS43)L!sOD-&iE3 z%_knb!Sf}b>`*K5V_^<5q4`wFjh*$mxj8ZN<17+-(@(<9DB6oRO<~ep`H|)YN7ETy z^tDlVsM5p>#X$37$xT|x{9Fq!7Fzp5T-b8CO)Ei>=LqWQw8#U&ryXjCB1m)Je$7h` zo%M11AWcn@8sTZ<=Z2SiCuq?^Q=#USl2_#dtxs@m0oRtrwRMbZO;ayYn>=sOVvU<$L~Y-gT=feBYVR(2vqR0W$m}`I_qeneM84MeeXmQ+z8~!7wlMd( zbkcHozsnEEHJ=*e^OszHv0U&AIu)rzaHn??m(}v%2j#p3g)iyMCXbp&Nc*K=@S&2o zI`TrLmnWz7a^=ePtDD!3^s+7Ql;`AKa$Rmvqxzn^66hc9$a`FQuPg6!<^8U_UkPZ^hJL8%`$d2DwjhnOv`E4>zY3{5TJmE!PjgdH zo0B8_YK!*q8ZEzuR!th1T!^jx+|M$R^K1R-9GpoCuM2c0RWjQ4!*JYw^@nYKJ%YZW zYi(G{KmLAa2(zIsy32Ik_>NJTC_{l>$HH^|eKXqsc z1+8O#FF_elb*`X{%PzmQ;U&qW|80NJ}aSq5|HaU?ltwm*3fuPs^UXDySLzqflf< z^1FH`Y}p%7TU954zqSx`+T?zs2WcLI;CDN;d}I%msIQew)WpxRn6H=o9$M1}aX*c` z$w|#SF29$~+-5G-*Y9)r{d8{TxL3XUfXgnm0%a<5()>Y}JzG#(nz&fiE+2wv9U(mS zJKyELg_Whb0q($|rV49A3t?!>(^xbMmj|>w2{r~WELqYTNLM-h%7YgUh0&~B{xCJQ zFtC%M=H02z9ON(=0WDwmqXH(+QOa@2Nr%o(sPL>C0Qj!v6fo|<)oC8WxHEhwlE6wM zb7(0a1UL!@FY<_))}=Ao@{e)22q>i#~s;q=%UE;H1~is4Z)~4 z{#RnIL@3-dv}V)N_(URLgf#hCYJ{R+4EcsbYXV(q3wr=(hMxl@)E2GnjjY1?d9b${7IEesX-e}=aD^UK$snzdeae!&@8^jHjJt#%^DT$Y zTi$J#*{XR)U~+>oKBOjIY(4PsBO!m9&WMr11cs~&U32ppaI=5`HBdwTY+WlTZck~2 zSCAHVg+n?il0E*SQ|FawQH01N zj`&NKzEPG!WeU2@6T4J=8U18A!Cp~0TAlG%4(arGSbA2y{8hlT8l6(v*AQZcc>X#y z3NzSxjK4wc`g1GjZ{ll}OqYniMXl=OmIevmrd2Og+V6wPnwRf5)ItYm2&hKk_*XM^vKL~V!Rmsgg<2Dn)%*{a|49p0E7-UG LRr0@!{`P+Wp3+AI literal 0 HcmV?d00001 diff --git a/docs/_build/doctrees/doc/examples/JITTutorial1.doctree b/docs/_build/doctrees/doc/examples/JITTutorial1.doctree new file mode 100644 index 0000000000000000000000000000000000000000..282058385db04cc7b7b3d7fe850299b4dc493a7c GIT binary patch literal 4052 zcmeHK>3`ft8FrocSS5CxG)W6dsIqCxI@r6hU1&)u(53`Z(*=sB1d0$NX?7*7>zx_d zyN0C=P>8wj`z-f=$up96WACqgzOxZ{UGxT9mT4hW`R(a`I(4R zTlCQCJ(?ZSi56?5JP~@B3q>bKG^Y!~jr`1T2%OZ_@Kxfgr?(P7X4pTy^PQv^BNF-cF zofn1L)mh&0vs6cEQ6!x>-b?af2Ux34rP@4q#DFJxEL7*EJ3BiFT}C|KXai+>_nY_V z(ugj5Y(ewB37@X8g*pg&53{(|GV%%ya333y-C~PDksCQhR~@$C$6P5qHyyU#y;id2jn=3z}P6(H8w8E=S*mS~cPWZSJKIs%8 zEQhtdjcIc`Vt^9ee0v*PKZRqGycf zZ_UokT)WySl+7aoVoey=GrIyu`Sz?>~wNa_Uj*>i++P-dC*L*3s7B;t&EGU3Q z_0N9Je!2YJPQ`w!iPqR?t{#;h*Q{+C%+`E2O8fSfy|uaSMcR&1E&8aZHCqZ@$Q0_2 zpICb6LI`Gd@O>MPt*y;f%V>2=jrGCUOskS#v&Rps*SFr@pR8x=kn7SfD=A`^2La5C zGil@Tkb7ufQPXZmwolx4d+>V z&^DEbljfjl4W}hGATgXs44c-$w8SPP4ki)@O~8#j#lp-r#3Uv|3kN2Ossg-t_o$*g z7ir*nTt$9WBCRGqm%}o9cV4l*0^>zU%fpbtcP~^w%Pd3Fs-=_M-N1o4ZzIIkV9g!^ zo$@`DnE#vOb3ofF57z91T4vK2DnCZ%%R{8q%B4wmh5C_BS~^zD^g+{6H(PAMba0v} zdiIbl#yss87{BzPyYrY+RY9}HAc=3PoMQk##};!bFunE!eb_W1TCwWMsvA#^yYVC8 z<~uE7iuj!t`9E(F`Y2Yx^CNlzQ=QGAVV*8mfxut$f}PTmr>d99L`b^TWlIybQEtc= zNAxkah{tL(-X77%*@_w_UKYD!NkyM<=ngx3jH{GizvR$1J3l4vmPem-=w;UMBVBSG zMO}wJWx9)<9+RSS_kJ22XyV}m`t%uxUNLT&)dRmj+hvPUQ1hc5@S~-pz9?c2y~>ux z#wrIsH=?_2B}#)xf(f~xR(+urecqujutg;_h)Q44Ye&{R79Vy|8d$ILxByY4FJ|P7 z=u0hjZVUycrN0ZucNMvC<6)@IWB?v$MyW{s2n^)QU3OabFj6@PVIgDU>{6(8ezVij zSq2&!3EgXFvfl}H5_iaB4ItnPqndnZUCu>rVh~_wJ`@IBwyZ#Ya%`8xOn5~CiPV{~ zF?OfN=E~tseYP~7gOCpdg=`iSF=CAX%NrCk$>}S`#S&aM7JDM5T~MIY2m{nMt;lH% zt{U=K*8<7*99ycLsF_yU4Le=E+(Em-R0$Bwbz9tQqklVCK+<~cZDuCXZpupal z)RdwZ+;NFYkGHb3DSg1gZhFBURUw`7pQvn^Y zvtkf|(4(viRb%s2U^9=!-;4V6wK`X*xV=b4V7N4bWfd+vS|=#YM}jSJNAI-(!4Iks~frhmj1 z#`mWmvz`CR-Qy?h3}%A{;Wixxrl9Gk_gSMaQqX6U!k;1FvaB8e{d2UCsh3HY|AIYM zclrMQe!JoxWtRtHuLDWdpaK7i`iY&Ht$H?W`KK8G7fozdSO zvP)Gzii-9rfT=@wd=L5^s=fxltZ7BRci6?Ux}y{fsJy?5)Z{3jKcFE_;c|$Ut6uyO zFP6%PCzJ9|-NIuRre}S1W&QK^Om)%v%ZT0zSHklORe1EGTy2-Xj_7aU6>I@;x4)OS np^}1)FQ2$E;dTTj#v0>!tLPsN{gcg`vcWy>UnBZ=;kEw*BCn;P literal 0 HcmV?d00001 diff --git a/docs/_build/doctrees/doc/examples/JITTutorial2.doctree b/docs/_build/doctrees/doc/examples/JITTutorial2.doctree new file mode 100644 index 0000000000000000000000000000000000000000..ad688aae0021474eae0f489ef19324bca5f206c9 GIT binary patch literal 5705 zcmeHLX?q+;5msdD*s c5F;+$77kmDoDGwY(h{l;KX)t6fcQUCx$Q#vopOrgXXH~ z9%&aCh=G7bxbOSE@B6-f1;2;4=UA^~#o^(3_`+j<@s7H>j<=4ks%J-SC$dxN`Jxd< z4i}pG40tFtx@-PAjb^l~&T63*aM_Q!pxqgbT{|)|GGggLlyKdSg4p+LOL9l=q@gXn zD5UY0V6!4^3+YMljzZJn9YGTrO|t3ON(46pE`-$u!DTL<0K6|8!%{e z_qA0R*<^wzq8V7-uEzr_@tPO7Sd&rQw4+dZVVVX_-(L^neiOKfX2DwhZt|W5WVmQP zc6oI*l~LkZ{!$|mk`6w1oepL6k~W)=R#!nwhuMTEG^Up_&5|Im|kwsE9%<;gLi#ERR_fL8Ql+v^T;@_Ur~|q z$WUZlsv_f+aKWs5z&+$1W@Gt%T5w_HV%3s_I7T*CwXG|X4{YKHI2@|p0gRfO4;+T-6JC>Pc&1J zG}~U-(=c^6T*peJ0WNeI4YmKNKdtWGr9H$epctGL*} z&-$6Ac}=l1b5`X+#lK$AFX)3G#UJK()+Xxc(zRr+mDaT#$f?|!TT)oJkY|4`Z$X~} zS#Fz(vq4$Vt)wfo9`56~p+25DWjv(!8adTDeXcjB^@mSSvt#*!--h}oQFTKm z>5E=aG!=a=!Cd-}WSH9mM+M>X^5v@!r^r^GXl>*y7?q#7lX9cywVuhzRNyF*hGz$H z{qhr6FJ3S&KDnUx7W6)RCxaMDsuXUSu%4(?JDXVwN zYF>@+lvVW>{lAn|I)|3?bs4?B8aU48EhkUgW!F2sb-1B7sA_v&wZCl4=j+@@+nZO< zYEVJ1jJ|lzD7tj?=(|-@$0nXWf3mO^$Do@-*BcUVZhal-dq`QB{#r* zAZ^247MsSquck}092i$yOmjGzeJdYwS&QwrFxYjXNQRN*rjS-5>8X{w*o5k6)im~W zM%UbN_k>W8zQvuj)D+70NVHX=6D0vp=&da_HDHmCa?fP+Ha3Z$#gt}b^mevS^n-Tf zn-!%X)1Y^-*)0m>w=IL(?Cx#kW`1NFmtZEC}2~SutI?_qloSELdQcdBTeAdv-7PjPFr~*PW^6T&2zn13DI+DLQYT|$dEZU%Wm8rE1bTStNa z!Jvq^31YggRLsFO^D;p1N2>3I8Car(MZ|po0q9!jcMF0Ku8gs%Qi*aU@LbDXXtAR_ zNumU;IAj4)v-ota(DC8853zkpMS&|W1p2CZ`!E}GcsuRVjTYO-gEm)=?PGi4axQ6e zlO2mv8KP^^H4E$Mlv1mA{fVD?mm(?@~cjFSejIfyAi9|Km{Gs zK;E#DP$>*v+zRLuEp|}h-tqk0YbKUL&{uN$B$`bgFWz_RtV5q-v%KdaOA*$oD6#o8 zuo=gE(eb+UnbKE?xOEScN|exN!P)jBYt6(~$Ma3g!ImRms(kJSI|fUFL8jgGx>+>3 zpWkG=um_+ov`V{T!BYoz1U`LH!Pmn)#MMO3lMr(weF^!bFhNtFZ#+tizr4xz6qUtP z(Mw-}nkq(zqU@^>u?=|o8XHSxXYoP$I@8MQDxklC+g>>ABKjt)<&=v8Abg9>n2sl` zHlQqV`F4xdkiqEMJ6?~zgThpkR@>b09O=?`SFozv8b|a!HpW&jLG<_8L{$`jz*he! zOR^ub8Po=eJ&(#TOc;`Wbc5BpJjAL-x$ws@I1j6vK>q|Oq~c|e=;I9Ax literal 0 HcmV?d00001 diff --git a/docs/_build/doctrees/doc/examples/index.doctree b/docs/_build/doctrees/doc/examples/index.doctree new file mode 100644 index 0000000000000000000000000000000000000000..aaeddbac1734ae9eff501269ccf104c8820cb8c5 GIT binary patch literal 3158 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 literal 0 HcmV?d00001 diff --git a/docs/_build/doctrees/doc/functions.doctree b/docs/_build/doctrees/doc/functions.doctree new file mode 100644 index 0000000000000000000000000000000000000000..5739787356652a4184149c63252b4bc4cbf32c4e GIT binary patch literal 27801 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 literal 0 HcmV?d00001 diff --git a/docs/_build/doctrees/doc/getting_started.doctree b/docs/_build/doctrees/doc/getting_started.doctree new file mode 100644 index 0000000000000000000000000000000000000000..e5c651011fd9e21be3f844c6cdfe50c7506c27c8 GIT binary patch literal 22836 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

pGM+^s{@QZLd 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 literal 0 HcmV?d00001 diff --git a/docs/_build/doctrees/doc/kaleidoscope/PythonLangImpl1.doctree b/docs/_build/doctrees/doc/kaleidoscope/PythonLangImpl1.doctree new file mode 100644 index 0000000000000000000000000000000000000000..1912cd763304b93111d55ad170400308f06ca11e GIT binary patch literal 49143 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 ha?2x8zMj8esfDm(17B@!Ocp{y)D3bHM-r literal 0 HcmV?d00001 diff --git a/docs/_build/doctrees/doc/kaleidoscope/PythonLangImpl2.doctree b/docs/_build/doctrees/doc/kaleidoscope/PythonLangImpl2.doctree new file mode 100644 index 0000000000000000000000000000000000000000..11a5b399d3f3059fd6506cd05f2d844edd9f7f85 GIT binary patch literal 104735 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 g8fcB2w#Hr@s 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%0AHg1MI{aE!ypt4Z^i6ks})%B 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 S_Fi^i3w}h(!N2Xf{Qm>6J>YKu literal 0 HcmV?d00001 diff --git a/docs/_build/doctrees/doc/kaleidoscope/PythonLangImpl5.doctree b/docs/_build/doctrees/doc/kaleidoscope/PythonLangImpl5.doctree new file mode 100644 index 0000000000000000000000000000000000000000..7429f2649c808741d0a75abe16c1228b6b7da315 GIT binary patch literal 122555 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 literal 0 HcmV?d00001 diff --git a/docs/_build/doctrees/doc/kaleidoscope/PythonLangImpl7.doctree b/docs/_build/doctrees/doc/kaleidoscope/PythonLangImpl7.doctree new file mode 100644 index 0000000000000000000000000000000000000000..9a7253de5d88a77a396547f4c78bc7efbec8d5c9 GIT binary patch literal 140548 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 KCH_+k*8c_L%Pj%` literal 0 HcmV?d00001 diff --git a/docs/_build/doctrees/doc/kaleidoscope/index.doctree b/docs/_build/doctrees/doc/kaleidoscope/index.doctree new file mode 100644 index 0000000000000000000000000000000000000000..eba7b1d66c175ad0cdf42de48b77444e96c2afd6 GIT binary patch literal 4715 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 Du7

Y>*`|R$ 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 LR$_6iP4xdCZllvK literal 0 HcmV?d00001 diff --git a/docs/_build/doctrees/doc/llvm.core.ArrayType.doctree b/docs/_build/doctrees/doc/llvm.core.ArrayType.doctree new file mode 100644 index 0000000000000000000000000000000000000000..d6393243074b8752a72ccb699d7705d45c467371 GIT binary patch literal 6680 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 literal 0 HcmV?d00001 diff --git a/docs/_build/doctrees/doc/llvm.core.BasicBlock.doctree b/docs/_build/doctrees/doc/llvm.core.BasicBlock.doctree new file mode 100644 index 0000000000000000000000000000000000000000..80ff4683d4cfe5d5882c2beb16467edc56f98bff GIT binary patch literal 8950 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 bK;Hywp1y^v-mt?-Jw1d6Mc>9XDrNs4cuI-8 literal 0 HcmV?d00001 diff --git a/docs/_build/doctrees/doc/llvm.core.Builder.doctree b/docs/_build/doctrees/doc/llvm.core.Builder.doctree new file mode 100644 index 0000000000000000000000000000000000000000..0fe5abaa34806ca49a7f5f3170fa224cac4a97d3 GIT binary patch literal 84524 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
    +
  1. + + Each mutable variable becomes a stack allocation. + + .. raw:: html + +
  2. +
  3. + + Each read of the variable becomes a load from the stack. + + .. raw:: html + +
  4. +
  5. + + Each update of the variable becomes a store to the stack. + + .. raw:: html + +
  6. +
  7. + + Taking the address of a variable just uses the stack address directly. + + .. raw:: html + +
  8. +
+ + While this solution has solved our immediate problem, it introduced + another one: we have now apparently introduced a lot of stack traffic + for very simple and common operations, a major performance problem. + Fortunately for us, the LLVM optimizer has a highly-tuned optimization + pass named "mem2reg" that handles this case, promoting allocas like this + into SSA registers, inserting Phi nodes as appropriate. If you run this + example through the pass, for example, you'll get: + + {% highlight bash %} $ llvm-as < example.ll \| opt -mem2reg \| llvm-dis + + + + + +.. code-block:: llvm + + @G = weak global i32 0 @H = weak global i32 0 + define i32 @test(i1 %Condition) { entry: br i1 %Condition, label + %cond_true, label %cond_false cond_true: %X.0 = load i32\* @G br + label %cond_next cond_false: %X.1 = load i32\* @H br label %cond_next + cond_next: %X.01 = phi i32 [ %X.1, %cond_false ], [ %X.0, %cond_true + ] ret i32 %X.01 } + + + +The mem2reg pass implements the standard "iterated dominance frontier" +algorithm for constructing SSA form and has a number of optimizations +that speed up (very common) degenerate cases. The mem2reg optimization +pass is the answer to dealing with mutable variables, and we highly +recommend that you depend on it. Note that mem2reg only works on +variables in certain circumstances: + +- mem2reg is alloca-driven: it looks for allocas and if it can handle + them, it promotes them. It does not apply to global variables or heap + allocations. + +- mem2reg only looks for alloca instructions in the entry block of the + function. Being in the entry block guarantees that the alloca is only + executed once, which makes analysis simpler. + +- mem2reg only promotes allocas whose uses are direct loads and stores. + If the address of the stack object is passed to a function, or if any + funny pointer arithmetic is involved, the alloca will not be + promoted. + +- mem2reg only works on allocas of `first + class `_ + values (such as pointers, scalars and vectors), and only if the array + size of the allocation is 1 (or missing in the .ll file). mem2reg is + not capable of promoting structs or arrays to registers. Note that + the "scalarrepl" pass is more powerful and can promote structs, + "unions", and arrays in many cases. + +All of these properties are easy to satisfy for most imperative +languages, and we'll illustrate it below with Kaleidoscope. The final +question you may be asking is: should I bother with this nonsense for my +front-end? Wouldn't it be better if I just did SSA construction +directly, avoiding use of the mem2reg optimization pass? In short, we +strongly recommend that you use this technique for building SSA form, +unless there is an extremely good reason not to. Using this technique +is: + +- Proven and well tested: llvm-gcc and clang both use this technique + for local mutable variables. As such, the most common clients of LLVM + are using this to handle a bulk of their variables. You can be sure + that bugs are found fast and fixed early. + +- Extremely Fast: mem2reg has a number of special cases that make it + fast in common cases as well as fully general. For example, it has + fast-paths for variables that are only used in a single block, + variables that only have one assignment point, good heuristics to + avoid insertion of unneeded phi nodes, etc. + +- Needed for debug info generation: `Debug information in + LLVM `_ relies on + having the address of the variable exposed so that debug info can be + attached to it. This technique dovetails very naturally with this + style of debug info. + +If nothing else, this makes it much easier to get your front-end up and +running, and is very simple to implement. Lets extend Kaleidoscope with +mutable variables now! + +-------------- + +Mutable Variables in Kaleidoscope # {#kalvars} +============================================== + +Now that we know the sort of problem we want to tackle, lets see what +this looks like in the context of our little Kaleidoscope language. +We're going to add two features: + +- The ability to mutate variables with the '=' operator. +- The ability to define new variables. + +While the first item is really what this is about, we only have +variables for incoming arguments as well as for induction variables, and +redefining those only goes so far :). Also, the ability to define new +variables is a useful thing regardless of whether you will be mutating +them. Here's a motivating example that shows how we could use these: + + +.. code-block:: python + + # Define ':' for sequencing: as a low-precedence + operator that ignores operands # and just returns the RHS. def binary : + 1 (x y) y; + + # Recursive fib, we could do this before. + def fib(x) if (x < 3) then 1 else fib(x-1) + fib(x-2) + + # Iterative fib. + def fibi(x) var a = 1, b = 1, c in (for i = 3, i < x in c = a + b : a = + b : b = c) : b + + # Call it. + fibi(10) + + + +In order to mutate variables, we have to change our existing variables +to use the "alloca trick". Once we have that, we'll add our new +operator, then extend Kaleidoscope to support new variable definitions. + +-------------- + +Adjusting Existing Variables for Mutation # {#adjustments} +========================================================== + +The symbol table in Kaleidoscope is managed at code generation time by +the ``g_named_values`` map. This map currently keeps track of the LLVM +"Value" that holds the double value for the named variable. In order to +support mutation, we need to change this slightly, so that it holds the +*memory location* of the variable in question. Note that this change is +a refactoring: it changes the structure of the code, but does not (by +itself) change the behavior of the compiler. All of these changes are +isolated in the Kaleidoscope code generator. + +At this point in Kaleidoscope's development, it only supports variables +for two things: incoming arguments to functions and the induction +variable of 'for' loops. For consistency, we'll allow mutation of these +variables in addition to other user-defined variables. This means that +these will both need memory locations. + +To start our transformation of Kaleidoscope, we will need to create the +allocas that we will store in ``g_named_values``. We'll use a helper +function that ensures that the allocas are created in the entry block of +the function: + + +.. code-block:: python + + # Creates an alloca instruction in the entry + block of the function. This is used # for mutable variables. def + CreateEntryBlockAlloca(function, var_name): entry = + function.get_entry_basic_block() builder = Builder.new(entry) + builder.position_at_beginning(entry) return + builder.alloca(Type.double(), var_name) + + + +This code creates a temporary ``llvm.core.Builder`` that is pointing at +the first instruction of the entry block. It then creates an alloca with +the expected name and returns it. Because all values in Kaleidoscope are +doubles, there is no need to pass in a type to use. + +With this in place, the first functionality change we want to make is to +variable references. In our new scheme, variables live on the stack, so +code generating a reference to them actually needs to produce a load +from the stack slot: + + +.. code-block:: python + + def CodeGen(self): if self.name in + g_named_values: return + g_llvm_builder.load(g_named_values[self.name], self.name) else: + raise RuntimeError('Unknown variable name: ' + self.name) {% + endhighlight %} + + As you can see, this is pretty straightforward. Now we need to update + the things that define the variables to set up the alloca. We'll start + with ``ForExpressionNode.CodeGen`` (see the `full code listing <#code>`_ + for the unabridged code): + + {% highlight python %} def CodeGen(self): function = + g_llvm_builder.basic_block.function + + :: + + # Create an alloca for the variable in the entry block. + alloca = CreateEntryBlockAlloca(function, self.loop_variable) + + # Emit the start code first, without 'variable' in scope. + start_value = self.start.CodeGen() + + # Store the value into the alloca. + g_llvm_builder.store(start_value, alloca) + ... + # Compute the end condition. + end_condition = self.end.CodeGen() + + # Reload, increment, and restore the alloca. This handles the case where + # the body of the loop mutates the variable. + cur_value = g_llvm_builder.load(alloca, self.loop_variable) + next_value = g_llvm_builder.fadd(cur_value, step_value, 'nextvar') + g_llvm_builder.store(next_value, alloca) + + # Convert condition to a bool by comparing equal to 0.0. + end_condition_bool = g_llvm_builder.fcmp( + FCMP_ONE, end_condition, Constant.real(Type.double(), 0), 'loopcond') + ... + + + + + +This code is virtually identical to the code `before we allowed mutable +variables `_. The big difference is +that we no longer have to construct a PHI node, and we use load/store to +access the variable as needed. + +To support mutable argument variables, we need to also make allocas for +them. The code for this is also pretty simple: + + +.. code-block:: python + + class PrototypeNode(object): ... # Create an + alloca for each argument and register the argument in the symbol # table + so that references to it will succeed. def CreateArgumentAllocas(self, + function): for arg_name, arg in zip(self.args, function.args): alloca = + CreateEntryBlockAlloca(function, arg_name) g_llvm_builder.store(arg, + alloca) g_named_values[arg_name] = alloca + + + +For each argument, we make an alloca, store the input value to the +function into the alloca, and register the alloca as the memory location +for the argument. This method gets invoked by ``FunctionNode.CodeGen`` +right after it sets up the entry block for the function. + +The final missing piece is adding the mem2reg pass, which allows us to +get good codegen once again: + + +.. code-block:: python + + from llvm.passes import + (PASS_PROMOTE_MEMORY_TO_REGISTER, PASS_INSTRUCTION_COMBINING, + PASS_REASSOCIATE, PASS_GVN, PASS_CFG_SIMPLIFICATION) ... def main(): + # Set up the optimizer pipeline. Start with registering info about how + the # target lays out data structures. + g_llvm_pass_manager.add(g_llvm_executor.target_data) # Promote + allocas to registers. + g_llvm_pass_manager.add(PASS_PROMOTE_MEMORY_TO_REGISTER) # Do + simple "peephole" optimizations and bit-twiddling optzns. + g_llvm_pass_manager.add(PASS_INSTRUCTION_COMBINING) # Reassociate + expressions. g_llvm_pass_manager.add(PASS_REASSOCIATE) {% + endhighlight %} + + It is interesting to see what the code looks like before and after the + mem2reg optimization runs. For example, this is the before/after code + for our recursive fib function. Before the optimization: + + {% highlight llvm %} define double @fib(double %x) { entry: %x1 = alloca + double store double %x, double\* %x1 %x2 = load double\* %x1 %cmptmp = + fcmp ult double %x2, 3.000000e+00 %booltmp = uitofp i1 %cmptmp to double + %ifcond = fcmp one double %booltmp, 0.000000e+00 br i1 %ifcond, label + %then, label %else then: ; preds = %entry br label %ifcont else: ; preds + = %entry %x3 = load double\* %x1 %subtmp = fsub double %x3, 1.000000e+00 + %calltmp = call double @fib(double %subtmp) %x4 = load double\* %x1 + %subtmp5 = fsub double %x4, 2.000000e+00 %calltmp6 = call double + @fib(double %subtmp5) %addtmp = fadd double %calltmp, %calltmp6 br label + %ifcont ifcont: ; preds = %else, %then %iftmp = phi double [ + 1.000000e+00, %then ], [ %addtmp, %else ] ret double %iftmp } {% + endhighlight %} + + Here there is only one variable (x, the input argument) but you can + still see the extremely simple-minded code generation strategy we are + using. In the entry block, an alloca is created, and the initial input + value is stored into it. Each reference to the variable does a reload + from the stack. Also, note that we didn't modify the if/then/else + expression, so it still inserts a PHI node. While we could make an + alloca for it, it is actually easier to create a PHI node for it, so we + still just make the PHI. + + Here is the code after the mem2reg pass runs: + + {% highlight llvm %} define double @fib(double %x) { entry: %cmptmp = + fcmp ult double %x, 3.000000e+00 %booltmp = uitofp i1 %cmptmp to double + %ifcond = fcmp one double %booltmp, 0.000000e+00 br i1 %ifcond, label + %then, label %else then: br label %ifcont else: %subtmp = fsub double + %x, 1.000000e+00 %calltmp = call double @fib(double %subtmp) %subtmp5 = + fsub double %x, 2.000000e+00 %calltmp6 = call double @fib(double + %subtmp5) %addtmp = fadd double %calltmp, %calltmp6 br label %ifcont + ifcont: ; preds = %else, %then %iftmp = phi double [ 1.000000e+00, %then + ], [ %addtmp, %else ] ret double %iftmp } + + + +This is a trivial case for mem2reg, since there are no redefinitions of +the variable. The point of showing this is to calm your tension about +inserting such blatent inefficiencies :). + +After the rest of the optimizers run, we get: + + +.. code-block:: llvm + + define double @fib(double %x) { entry: %cmptmp = + fcmp ult double %x, 3.000000e+00 %booltmp = uitofp i1 %cmptmp to double + %ifcond = fcmp ueq double %booltmp, 0.000000e+00 br i1 %ifcond, label + %else, label %ifcont else: %subtmp = fsub double %x, 1.000000e+00 + %calltmp = call double @fib(double %subtmp) %subtmp5 = fsub double %x, + 2.000000e+00 %calltmp6 = call double @fib(double %subtmp5) %addtmp = + fadd double %calltmp, %calltmp6 ret double %addtmp ifcont: ret double + 1.000000e+00 } + + + +Here we see that the simplifycfg pass decided to clone the return +instruction into the end of the 'else' block. This allowed it to +eliminate some branches and the PHI node. + +Now that all symbol table references are updated to use stack variables, +we'll add the assignment operator. + +-------------- + +New Assignment Operator # {#assignment} +======================================= + +With our current framework, adding a new assignment operator is really +simple. We will parse it just like any other binary operator, but handle +it internally (instead of allowing the user to define it). The first +step is to set a precedence: + + +.. code-block:: python + + def main(): ... # Install standard binary + operators. # 1 is lowest possible precedence. 40 is the highest. + g_binop_precedence['='] = 2 g_binop_precedence['<'] = 10 + g_binop_precedence['+'] = 20 g_binop_precedence['-'] = 20 {% + endhighlight %} + + Now that the parser knows the precedence of the binary operator, it + takes care of all the parsing and AST generation. We just need to + implement codegen for the assignment operator. This looks like: + + {% highlight python %} class + BinaryOperatorExpressionNode(ExpressionNode): ... def CodeGen(self): # A + special case for '=' because we don't want to emit the LHS as an # + expression. if self.operator == '=': # Assignment requires the LHS to be + an identifier. if not isinstance(self.left, VariableExpressionNode): + raise RuntimeError('Destination of "=" must be a variable.') {% + endhighlight %} + + Unlike the rest of the binary operators, our assignment operator doesn't + follow the "emit LHS, emit RHS, do computation" model. As such, it is + handled as a special case before the other binary operators are handled. + The other strange thing is that it requires the LHS to be a variable. It + is invalid to have ``(x+1) = expr`` -- only things like ``x = expr`` are + allowed. + + {% highlight python %} # Codegen the RHS. value = self.right.CodeGen() + + :: + + # Look up the name. + variable = g_named_values[self.left.name] + + # Store the value and return it. + g_llvm_builder.store(value, variable) + + return value + ... + + + + + +Once we have the variable, CodeGening the assignment is straightforward: +we emit the RHS of the assignment, create a store, and return the +computed value. Returning a value allows for chained assignments like +``X = (Y = Z)``. + +Now that we have an assignment operator, we can mutate loop variables +and arguments. For example, we can now run code like this: + + +.. code-block:: python + + # Function to print a double. extern printd(x) + + # Define ':' for sequencing: as a low-precedence operator that ignores operands + # and just returns the RHS. + def binary : 1 (x y) y + + def test(x) printd(x) : x = 4 : printd(x) + + test(123) + + + +When run, this example prints "123" and then "4", showing that we did +actually mutate the value! Okay, we have now officially implemented our +goal: getting this to work requires SSA construction in the general +case. However, to be really useful, we want the ability to define our +own local variables. Let's add this next! + +-------------- + +User-defined Local Variables # {#localvars} +=========================================== + +Adding var/in is just like any other other extensions we made to +Kaleidoscope: we extend the lexer, the parser, the AST and the code +generator. The first step for adding our new 'var/in' construct is to +extend the lexer. As before, this is pretty trivial, the code looks like +this: + + +.. code-block:: python + + ... class UnaryToken(object): pass class + VarToken(object): pass ... def Tokenize(string): ... elif identifier == + 'unary': yield UnaryToken() elif identifier == 'var': yield VarToken() + else: yield IdentifierToken(identifier) + + + +The next step is to define the AST node that we will construct. For +var/in, it looks like this: + + +.. code-block:: python + + # Expression class for var/in. class + VarExpressionNode(ExpressionNode): + + def **init**\ (self, variables, body): self.variables = variables + self.body = body + + def CodeGen(self): ... + + + +var/in allows a list of names to be defined all at once, and each name +can optionally have an initializer value. As such, we capture this +information in the variables list. Also, var/in has a body, this body is +allowed to access the variables defined by the var/in. + +With this in place, we can define the parser pieces. The first thing we +do is add it as a primary expression: + + +.. code-block:: python + + # primary ::= # dentifierexpr \| numberexpr \| + parenexpr \| ifexpr \| forexpr \| varexpr def ParsePrimary(self): if + isinstance(self.current, IdentifierToken): return + self.ParseIdentifierExpr() elif isinstance(self.current, NumberToken): + return self.ParseNumberExpr() elif isinstance(self.current, IfToken): + return self.ParseIfExpr() elif isinstance(self.current, ForToken): + return self.ParseForExpr() elif isinstance(self.current, VarToken): + return self.ParseVarExpr() elif self.current == CharacterToken('('): + return self.ParseParenExpr() else: raise RuntimeError('Unknown token + when expecting an expression.') + + + +Next we define ParseVarExpr: + + +.. code-block:: python + + # varexpr ::= 'var' (identifier ('=' + expression)?)+ 'in' expression def ParseVarExpr(self): self.Next() # eat + 'var'. + + :: + + variables = {} + + # At least one variable name is required. + if not isinstance(self.current, IdentifierToken): + raise RuntimeError('Expected identifier after "var".') + + + + + +The first part of this code parses the list of identifier/expr pairs +into the local ``variables`` list. + + +.. code-block:: python + + while True: var_name = self.current.name + self.Next() # eat the identifier. + + :: + + # Read the optional initializer. + if self.current == CharacterToken('='): + self.Next() # eat '='. + variables[var_name] = self.ParseExpression() + else: + variables[var_name] = None + + # End of var list, exit loop. + if self.current != CharacterToken(','): + break + self.Next() # eat ','. + + if not isinstance(self.current, IdentifierToken): + raise RuntimeError('Expected identifier after "," in a var expression.') + + + + + +Once all the variables are parsed, we then parse the body and create the +AST node: + + +.. code-block:: python + + # At this point, we have to have 'in'. if not + isinstance(self.current, InToken): raise RuntimeError('Expected "in" + keyword after "var".') self.Next() # eat 'in'. + + :: + + body = self.ParseExpression() + + return VarExpressionNode(variables, body) + + + + + +Now that we can parse and represent the code, we need to support +emission of LLVM IR for it. This code starts out with: + + +.. code-block:: python + + class VarExpressionNode(ExpressionNode): ... def + CodeGen(self): old_bindings = {} function = + g_llvm_builder.basic_block.function + + :: + + # Register all variables and emit their initializer. + for var_name, var_expression in self.variables.iteritems(): + # Emit the initializer before adding the variable to scope, this prevents + # the initializer from referencing the variable itself, and permits stuff + # like this: + # var a = 1 in + # var a = a in ... # refers to outer 'a'. + if var_expression is not None: + var_value = var_expression.CodeGen() + else: + var_value = Constant.real(Type.double(), 0) + + alloca = CreateEntryBlockAlloca(function, var_name) + g_llvm_builder.store(var_value, alloca) + + # Remember the old variable binding so that we can restore the binding + # when we unrecurse. + old_bindings[var_name] = g_named_values.get(var_name, None) + + # Remember this binding. + g_named_values[var_name] = alloca + + + + + +Basically it loops over all the variables, installing them one at a +time. For each variable we put into the symbol table, we remember the +previous value that we replace in ``old_bindings``. + +There are more comments here than code. The basic idea is that we emit +the initializer, create the alloca, then update the symbol table to +point to it. Once all the variables are installed in the symbol table, +we evaluate the body of the var/in expression: + + +.. code-block:: python + + # Codegen the body, now that all vars are in + scope. body = self.body.CodeGen() + + + +Finally, before returning, we restore the previous variable bindings: + + +.. code-block:: python + + # Pop all our variables from scope. for var_name + in self.variables: if old_bindings[var_name] is not None: + g_named_values[var_name] = old_bindings[var_name] else: del + g_named_values[var_name] + + :: + + # Return the body computation. + return body + + + + + +The end result of all of this is that we get properly scoped variable +definitions, and we even (trivially) allow mutation of them :). + +With this, we completed what we set out to do. Our nice iterative fib +example from the intro compiles and runs just fine. The mem2reg pass +optimizes all of our stack variables into SSA registers, inserting PHI +nodes where needed, and our front-end remains simple: no "iterated +dominance frontier" computation anywhere in sight. + +-------------- + +Full Code Listing # {#code} +=========================== + +Here is the complete code listing for our running example, enhanced with +mutable variables and var/in support: + + +.. code-block:: python + + #!/usr/bin/env python + + import re from llvm.core import Module, Constant, Type, Function, + Builder from llvm.ee import ExecutionEngine, TargetData from llvm.passes + import FunctionPassManager + + from llvm.core import FCMP_ULT, FCMP_ONE from llvm.passes import + (PASS_PROMOTE_MEMORY_TO_REGISTER, PASS_INSTRUCTION_COMBINING, + PASS_REASSOCIATE, PASS_GVN, PASS_CFG_SIMPLIFICATION) + + Globals + ------- + + # The LLVM module, which holds all the IR code. + g_llvm_module = Module.new('my cool jit') + + # The LLVM instruction builder. Created whenever a new function is entered. + g_llvm_builder = None + + # A dictionary that keeps track of which values are defined in the current scope + # and what their LLVM representation is. + g_named_values = {} + + # The function optimization passes manager. + g_llvm_pass_manager = FunctionPassManager.new(g_llvm_module) + + # The LLVM execution engine. + g_llvm_executor = ExecutionEngine.new(g_llvm_module) + + # The binary operator precedence chart. + g_binop_precedence = {} + + # Creates an alloca instruction in the entry block of the function. This is used + # for mutable variables. + def CreateEntryBlockAlloca(function, var_name): entry = + function.get_entry_basic_block() builder = Builder.new(entry) + builder.position_at_beginning(entry) return + builder.alloca(Type.double(), var_name) + + Lexer + ----- + + # The lexer yields one of these types for each token. + class EOFToken(object): pass class DefToken(object): pass class + ExternToken(object): pass class IfToken(object): pass class + ThenToken(object): pass class ElseToken(object): pass class + ForToken(object): pass class InToken(object): pass class + BinaryToken(object): pass class UnaryToken(object): pass class + VarToken(object): pass + + class IdentifierToken(object): def **init**\ (self, name): self.name = + name + + class NumberToken(object): def **init**\ (self, value): self.value = + value + + class CharacterToken(object): def **init**\ (self, char): self.char = + char def **eq**\ (self, other): return isinstance(other, CharacterToken) + and self.char == other.char def **ne**\ (self, other): return not self + == other + + # Regular expressions that tokens and comments of our language. + REGEX_NUMBER = re.compile('[0-9]+(?:.[0-9]+)?') REGEX_IDENTIFIER = + re.compile('[a-zA-Z][a-zA-Z0-9]\ *') REGEX_COMMENT = re.compile('#.*') + + def Tokenize(string): while string: # Skip whitespace. if + string[0].isspace(): string = string[1:] continue + + :: + + # Run regexes. + comment_match = REGEX_COMMENT.match(string) + number_match = REGEX_NUMBER.match(string) + identifier_match = REGEX_IDENTIFIER.match(string) + + # Check if any of the regexes matched and yield the appropriate result. + if comment_match: + comment = comment_match.group(0) + string = string[len(comment):] + elif number_match: + number = number_match.group(0) + yield NumberToken(float(number)) + string = string[len(number):] + elif identifier_match: + identifier = identifier_match.group(0) + # Check if we matched a keyword. + if identifier == 'def': + yield DefToken() + elif identifier == 'extern': + yield ExternToken() + elif identifier == 'if': + yield IfToken() + elif identifier == 'then': + yield ThenToken() + elif identifier == 'else': + yield ElseToken() + elif identifier == 'for': + yield ForToken() + elif identifier == 'in': + yield InToken() + elif identifier == 'binary': + yield BinaryToken() + elif identifier == 'unary': + yield UnaryToken() + elif identifier == 'var': + yield VarToken() + else: + yield IdentifierToken(identifier) + string = string[len(identifier):] + else: + # Yield the ASCII value of the unknown character. + yield CharacterToken(string[0]) + string = string[1:] + + yield EOFToken() + + Abstract Syntax Tree (aka Parse Tree) + ------------------------------------- + + # Base class for all expression nodes. + class ExpressionNode(object): pass + + # Expression class for numeric literals like "1.0". + class NumberExpressionNode(ExpressionNode): + + def **init**\ (self, value): self.value = value + + def CodeGen(self): return Constant.real(Type.double(), self.value) + + # Expression class for referencing a variable, like "a". + class VariableExpressionNode(ExpressionNode): + + def **init**\ (self, name): self.name = name + + def CodeGen(self): if self.name in g_named_values: return + g_llvm_builder.load(g_named_values[self.name], self.name) else: + raise RuntimeError('Unknown variable name: ' + self.name) + + # Expression class for a binary operator. + class BinaryOperatorExpressionNode(ExpressionNode): + + def **init**\ (self, operator, left, right): self.operator = operator + self.left = left self.right = right + + def CodeGen(self): # A special case for '=' because we don't want to + emit the LHS as an # expression. if self.operator == '=': # Assignment + requires the LHS to be an identifier. if not isinstance(self.left, + VariableExpressionNode): raise RuntimeError('Destination of "=" must be + a variable.') + + :: + + # Codegen the RHS. + value = self.right.CodeGen() + + # Look up the name. + variable = g_named_values[self.left.name] + + # Store the value and return it. + g_llvm_builder.store(value, variable) + + return value + + left = self.left.CodeGen() + right = self.right.CodeGen() + + if self.operator == '+': + return g_llvm_builder.fadd(left, right, 'addtmp') + elif self.operator == '-': + return g_llvm_builder.fsub(left, right, 'subtmp') + elif self.operator == '*': + return g_llvm_builder.fmul(left, right, 'multmp') + elif self.operator == '<': + result = g_llvm_builder.fcmp(FCMP_ULT, left, right, 'cmptmp') + # Convert bool 0 or 1 to double 0.0 or 1.0. + return g_llvm_builder.uitofp(result, Type.double(), 'booltmp') + else: + function = g_llvm_module.get_function_named('binary' + self.operator) + return g_llvm_builder.call(function, [left, right], 'binop') + + # Expression class for function calls. + class CallExpressionNode(ExpressionNode): + + def **init**\ (self, callee, args): self.callee = callee self.args = + args + + def CodeGen(self): # Look up the name in the global module table. callee + = g_llvm_module.get_function_named(self.callee) + + :: + + # Check for argument mismatch error. + if len(callee.args) != len(self.args): + raise RuntimeError('Incorrect number of arguments passed.') + + arg_values = [i.CodeGen() for i in self.args] + + return g_llvm_builder.call(callee, arg_values, 'calltmp') + + # Expression class for if/then/else. + class IfExpressionNode(ExpressionNode): + + def **init**\ (self, condition, then_branch, else_branch): + self.condition = condition self.then_branch = then_branch + self.else_branch = else_branch + + def CodeGen(self): condition = self.condition.CodeGen() + + :: + + # Convert condition to a bool by comparing equal to 0.0. + condition_bool = g_llvm_builder.fcmp( + FCMP_ONE, condition, Constant.real(Type.double(), 0), 'ifcond') + + function = g_llvm_builder.basic_block.function + + # Create blocks for the then and else cases. Insert the 'then' block at the + # end of the function. + then_block = function.append_basic_block('then') + else_block = function.append_basic_block('else') + merge_block = function.append_basic_block('ifcond') + + g_llvm_builder.cbranch(condition_bool, then_block, else_block) + + # Emit then value. + g_llvm_builder.position_at_end(then_block) + then_value = self.then_branch.CodeGen() + g_llvm_builder.branch(merge_block) + + # Codegen of 'Then' can change the current block; update then_block for the + # PHI node. + then_block = g_llvm_builder.basic_block + + # Emit else block. + g_llvm_builder.position_at_end(else_block) + else_value = self.else_branch.CodeGen() + g_llvm_builder.branch(merge_block) + + # Codegen of 'Else' can change the current block, update else_block for the + # PHI node. + else_block = g_llvm_builder.basic_block + + # Emit merge block. + g_llvm_builder.position_at_end(merge_block) + phi = g_llvm_builder.phi(Type.double(), 'iftmp') + phi.add_incoming(then_value, then_block) + phi.add_incoming(else_value, else_block) + + return phi + + # Expression class for for/in. + class ForExpressionNode(ExpressionNode): + + def **init**\ (self, loop_variable, start, end, step, body): + self.loop_variable = loop_variable self.start = start self.end = end + self.step = step self.body = body + + def CodeGen(self): # Output this as: # var = alloca double # ... # start + = startexpr # store start -> var # goto loop # loop: # ... # bodyexpr # + ... # loopend: # step = stepexpr # endcond = endexpr # # curvar = load + var # nextvar = curvar + step # store nextvar -> var # br endcond, loop, + endloop # outloop: + + :: + + function = g_llvm_builder.basic_block.function + + # Create an alloca for the variable in the entry block. + alloca = CreateEntryBlockAlloca(function, self.loop_variable) + + # Emit the start code first, without 'variable' in scope. + start_value = self.start.CodeGen() + + # Store the value into the alloca. + g_llvm_builder.store(start_value, alloca) + + # Make the new basic block for the loop, inserting after current block. + loop_block = function.append_basic_block('loop') + + # Insert an explicit fall through from the current block to the loop_block. + g_llvm_builder.branch(loop_block) + + # Start insertion in loop_block. + g_llvm_builder.position_at_end(loop_block) + + # Within the loop, the variable is defined equal to the alloca. If it + # shadows an existing variable, we have to restore it, so save it now. + old_value = g_named_values.get(self.loop_variable, None) + g_named_values[self.loop_variable] = alloca + + # Emit the body of the loop. This, like any other expr, can change the + # current BB. Note that we ignore the value computed by the body. + self.body.CodeGen() + + # Emit the step value. + if self.step: + step_value = self.step.CodeGen() + else: + # If not specified, use 1.0. + step_value = Constant.real(Type.double(), 1) + + # Compute the end condition. + end_condition = self.end.CodeGen() + + # Reload, increment, and restore the alloca. This handles the case where + # the body of the loop mutates the variable. + cur_value = g_llvm_builder.load(alloca, self.loop_variable) + next_value = g_llvm_builder.fadd(cur_value, step_value, 'nextvar') + g_llvm_builder.store(next_value, alloca) + + # Convert condition to a bool by comparing equal to 0.0. + end_condition_bool = g_llvm_builder.fcmp( + FCMP_ONE, end_condition, Constant.real(Type.double(), 0), 'loopcond') + + # Create the "after loop" block and insert it. + after_block = function.append_basic_block('afterloop') + + # Insert the conditional branch into the end of loop_block. + g_llvm_builder.cbranch(end_condition_bool, loop_block, after_block) + + # Any new code will be inserted in after_block. + g_llvm_builder.position_at_end(after_block) + + # Restore the unshadowed variable. + if old_value is not None: + g_named_values[self.loop_variable] = old_value + else: + del g_named_values[self.loop_variable] + + # for expr always returns 0.0. + return Constant.real(Type.double(), 0) + + # Expression class for a unary operator. + class UnaryExpressionNode(ExpressionNode): + + def **init**\ (self, operator, operand): self.operator = operator + self.operand = operand + + def CodeGen(self): operand = self.operand.CodeGen() function = + g_llvm_module.get_function_named('unary' + self.operator) return + g_llvm_builder.call(function, [operand], 'unop') + + # Expression class for var/in. + class VarExpressionNode(ExpressionNode): + + def **init**\ (self, variables, body): self.variables = variables + self.body = body + + def CodeGen(self): old_bindings = {} function = + g_llvm_builder.basic_block.function + + :: + + # Register all variables and emit their initializer. + for var_name, var_expression in self.variables.iteritems(): + # Emit the initializer before adding the variable to scope, this prevents + # the initializer from referencing the variable itself, and permits stuff + # like this: + # var a = 1 in + # var a = a in ... # refers to outer 'a'. + if var_expression is not None: + var_value = var_expression.CodeGen() + else: + var_value = Constant.real(Type.double(), 0) + + alloca = CreateEntryBlockAlloca(function, var_name) + g_llvm_builder.store(var_value, alloca) + + # Remember the old variable binding so that we can restore the binding + # when we unrecurse. + old_bindings[var_name] = g_named_values.get(var_name, None) + + # Remember this binding. + g_named_values[var_name] = alloca + + # Codegen the body, now that all vars are in scope. + body = self.body.CodeGen() + + # Pop all our variables from scope. + for var_name in self.variables: + if old_bindings[var_name] is not None: + g_named_values[var_name] = old_bindings[var_name] + else: + del g_named_values[var_name] + + # Return the body computation. + return body + + # This class represents the "prototype" for a function, which captures its name, + # and its argument names (thus implicitly the number of arguments the function + # takes), as well as if it is an operator. + class PrototypeNode(object): + + def **init**\ (self, name, args, is_operator=False, precedence=0): + self.name = name self.args = args self.is_operator = is_operator + self.precedence = precedence + + def IsBinaryOp(self): return self.is_operator and len(self.args) == 2 + + def GetOperatorName(self): assert self.is_operator return self.name[-1] + + def CodeGen(self): # Make the function type, eg. double(double,double). + funct_type = Type.function( Type.double(), [Type.double()] \* + len(self.args), False) + + :: + + function = Function.new(g_llvm_module, funct_type, self.name) + + # If the name conflicted, there was already something with the same name. + # If it has a body, don't allow redefinition or reextern. + if function.name != self.name: + function.delete() + function = g_llvm_module.get_function_named(self.name) + + # If the function already has a body, reject this. + if not function.is_declaration: + raise RuntimeError('Redefinition of function.') + + # If the function took a different number of args, reject. + if len(function.args) != len(self.args): + raise RuntimeError('Redeclaration of a function with different number ' + 'of args.') + + # Set names for all arguments and add them to the variables symbol table. + for arg, arg_name in zip(function.args, self.args): + arg.name = arg_name + + return function + + # Create an alloca for each argument and register the argument in the + symbol # table so that references to it will succeed. def + CreateArgumentAllocas(self, function): for arg_name, arg in + zip(self.args, function.args): alloca = CreateEntryBlockAlloca(function, + arg_name) g_llvm_builder.store(arg, alloca) + g_named_values[arg_name] = alloca + + # This class represents a function definition itself. + class FunctionNode(object): + + def **init**\ (self, prototype, body): self.prototype = prototype + self.body = body + + def CodeGen(self): # Clear scope. g_named_values.clear() + + :: + + # Create a function object. + function = self.prototype.CodeGen() + + # If this is a binary operator, install its precedence. + if self.prototype.IsBinaryOp(): + operator = self.prototype.GetOperatorName() + g_binop_precedence[operator] = self.prototype.precedence + + # Create a new basic block to start insertion into. + block = function.append_basic_block('entry') + global g_llvm_builder + g_llvm_builder = Builder.new(block) + + # Add all arguments to the symbol table and create their allocas. + self.prototype.CreateArgumentAllocas(function) + + # Finish off the function. + try: + return_value = self.body.CodeGen() + g_llvm_builder.ret(return_value) + + # Validate the generated code, checking for consistency. + function.verify() + + # Optimize the function. + g_llvm_pass_manager.run(function) + except: + function.delete() + if self.prototype.IsBinaryOp(): + del g_binop_precedence[self.prototype.GetOperatorName()] + raise + + return function + + Parser + ------ + + class Parser(object): + + def **init**\ (self, tokens): self.tokens = tokens self.Next() + + # Provide a simple token buffer. Parser.current is the current token the + # parser is looking at. Parser.Next() reads another token from the lexer + and # updates Parser.current with its results. def Next(self): + self.current = self.tokens.next() + + # Gets the precedence of the current token, or -1 if the token is not a + binary # operator. def GetCurrentTokenPrecedence(self): if + isinstance(self.current, CharacterToken): return + g_binop_precedence.get(self.current.char, -1) else: return -1 + + # identifierexpr ::= identifier \| identifier '(' expression\* ')' def + ParseIdentifierExpr(self): identifier_name = self.current.name + self.Next() # eat identifier. + + :: + + if self.current != CharacterToken('('): # Simple variable reference. + return VariableExpressionNode(identifier_name) + + # Call. + self.Next() # eat '('. + args = [] + if self.current != CharacterToken(')'): + while True: + args.append(self.ParseExpression()) + if self.current == CharacterToken(')'): + break + elif self.current != CharacterToken(','): + raise RuntimeError('Expected ")" or "," in argument list.') + self.Next() + + self.Next() # eat ')'. + return CallExpressionNode(identifier_name, args) + + # numberexpr ::= number def ParseNumberExpr(self): result = + NumberExpressionNode(self.current.value) self.Next() # consume the + number. return result + + # parenexpr ::= '(' expression ')' def ParseParenExpr(self): self.Next() + # eat '('. + + :: + + contents = self.ParseExpression() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")".') + self.Next() # eat ')'. + + return contents + + # ifexpr ::= 'if' expression 'then' expression 'else' expression def + ParseIfExpr(self): self.Next() # eat the if. + + :: + + # condition. + condition = self.ParseExpression() + + if not isinstance(self.current, ThenToken): + raise RuntimeError('Expected "then".') + self.Next() # eat the then. + + then_branch = self.ParseExpression() + + if not isinstance(self.current, ElseToken): + raise RuntimeError('Expected "else".') + self.Next() # eat the else. + + else_branch = self.ParseExpression() + + return IfExpressionNode(condition, then_branch, else_branch) + + # forexpr ::= 'for' identifier '=' expr ',' expr (',' expr)? 'in' + expression def ParseForExpr(self): self.Next() # eat the for. + + :: + + if not isinstance(self.current, IdentifierToken): + raise RuntimeError('Expected identifier after for.') + + loop_variable = self.current.name + self.Next() # eat the identifier. + + if self.current != CharacterToken('='): + raise RuntimeError('Expected "=" after for variable.') + self.Next() # eat the '='. + + start = self.ParseExpression() + + if self.current != CharacterToken(','): + raise RuntimeError('Expected "," after for start value.') + self.Next() # eat the ','. + + end = self.ParseExpression() + + # The step value is optional. + if self.current == CharacterToken(','): + self.Next() # eat the ','. + step = self.ParseExpression() + else: + step = None + + if not isinstance(self.current, InToken): + raise RuntimeError('Expected "in" after for variable specification.') + self.Next() # eat 'in'. + + body = self.ParseExpression() + + return ForExpressionNode(loop_variable, start, end, step, body) + + # varexpr ::= 'var' (identifier ('=' expression)?)+ 'in' expression def + ParseVarExpr(self): self.Next() # eat 'var'. + + :: + + variables = {} + + # At least one variable name is required. + if not isinstance(self.current, IdentifierToken): + raise RuntimeError('Expected identifier after "var".') + + while True: + var_name = self.current.name + self.Next() # eat the identifier. + + # Read the optional initializer. + if self.current == CharacterToken('='): + self.Next() # eat '='. + variables[var_name] = self.ParseExpression() + else: + variables[var_name] = None + + # End of var list, exit loop. + if self.current != CharacterToken(','): + break + self.Next() # eat ','. + + if not isinstance(self.current, IdentifierToken): + raise RuntimeError('Expected identifier after "," in a var expression.') + + # At this point, we have to have 'in'. + if not isinstance(self.current, InToken): + raise RuntimeError('Expected "in" keyword after "var".') + self.Next() # eat 'in'. + + body = self.ParseExpression() + + return VarExpressionNode(variables, body) + + # primary ::= # dentifierexpr \| numberexpr \| parenexpr \| ifexpr \| + forexpr \| varexpr def ParsePrimary(self): if isinstance(self.current, + IdentifierToken): return self.ParseIdentifierExpr() elif + isinstance(self.current, NumberToken): return self.ParseNumberExpr() + elif isinstance(self.current, IfToken): return self.ParseIfExpr() elif + isinstance(self.current, ForToken): return self.ParseForExpr() elif + isinstance(self.current, VarToken): return self.ParseVarExpr() elif + self.current == CharacterToken('('): return self.ParseParenExpr() else: + raise RuntimeError('Unknown token when expecting an expression.') + + # unary ::= primary \| unary_operator unary def ParseUnary(self): # If + the current token is not an operator, it must be a primary expression. + if (not isinstance(self.current, CharacterToken) or self.current in + [CharacterToken('('), CharacterToken(',')]): return self.ParsePrimary() + + :: + + # If this is a unary operator, read it. + operator = self.current.char + self.Next() # eat the operator. + return UnaryExpressionNode(operator, self.ParseUnary()) + + # binoprhs ::= (binary_operator unary)\* def ParseBinOpRHS(self, left, + left_precedence): # If this is a binary operator, find its precedence. + while True: precedence = self.GetCurrentTokenPrecedence() + + :: + + # If this is a binary operator that binds at least as tightly as the + # current one, consume it; otherwise we are done. + if precedence < left_precedence: + return left + + binary_operator = self.current.char + self.Next() # eat the operator. + + # Parse the unary expression after the binary operator. + right = self.ParseUnary() + + # If binary_operator binds less tightly with right than the operator after + # right, let the pending operator take right as its left. + next_precedence = self.GetCurrentTokenPrecedence() + if precedence < next_precedence: + right = self.ParseBinOpRHS(right, precedence + 1) + + # Merge left/right. + left = BinaryOperatorExpressionNode(binary_operator, left, right) + + # expression ::= unary binoprhs def ParseExpression(self): left = + self.ParseUnary() return self.ParseBinOpRHS(left, 0) + + # prototype # ::= id '(' id\* ')' # ::= binary LETTER number? (id, id) # + ::= unary LETTER (id) def ParsePrototype(self): precedence = None if + isinstance(self.current, IdentifierToken): kind = 'normal' + function_name = self.current.name self.Next() # eat function name. elif + isinstance(self.current, UnaryToken): kind = 'unary' self.Next() # eat + 'unary'. if not isinstance(self.current, CharacterToken): raise + RuntimeError('Expected an operator after "unary".') function_name = + 'unary' + self.current.char self.Next() # eat the operator. elif + isinstance(self.current, BinaryToken): kind = 'binary' self.Next() # eat + 'binary'. if not isinstance(self.current, CharacterToken): raise + RuntimeError('Expected an operator after "binary".') function_name = + 'binary' + self.current.char self.Next() # eat the operator. if + isinstance(self.current, NumberToken): if not 1 <= self.current.value <= + 100: raise RuntimeError('Invalid precedence: must be in range [1, + 100].') precedence = self.current.value self.Next() # eat the + precedence. else: raise RuntimeError('Expected function name, "unary" or + "binary" in ' 'prototype.') + + :: + + if self.current != CharacterToken('('): + raise RuntimeError('Expected "(" in prototype.') + self.Next() # eat '('. + + arg_names = [] + while isinstance(self.current, IdentifierToken): + arg_names.append(self.current.name) + self.Next() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")" in prototype.') + + # Success. + self.Next() # eat ')'. + + if kind == 'unary' and len(arg_names) != 1: + raise RuntimeError('Invalid number of arguments for a unary operator.') + elif kind == 'binary' and len(arg_names) != 2: + raise RuntimeError('Invalid number of arguments for a binary operator.') + + return PrototypeNode(function_name, arg_names, kind != 'normal', precedence) + + # definition ::= 'def' prototype expression def ParseDefinition(self): + self.Next() # eat def. proto = self.ParsePrototype() body = + self.ParseExpression() return FunctionNode(proto, body) + + # toplevelexpr ::= expression def ParseTopLevelExpr(self): proto = + PrototypeNode('', []) return FunctionNode(proto, self.ParseExpression()) + + # external ::= 'extern' prototype def ParseExtern(self): self.Next() # + eat extern. return self.ParsePrototype() + + # Top-Level parsing def HandleDefinition(self): + self.Handle(self.ParseDefinition, 'Read a function definition:') + + def HandleExtern(self): self.Handle(self.ParseExtern, 'Read an extern:') + + def HandleTopLevelExpression(self): try: function = + self.ParseTopLevelExpr().CodeGen() result = + g_llvm_executor.run_function(function, []) print 'Evaluated to:', + result.as_real(Type.double()) except Exception, e: raise#print + 'Error:', e try: self.Next() # Skip for error recovery. except: pass + + def Handle(self, function, message): try: print message, + function().CodeGen() except Exception, e: raise#print 'Error:', e try: + self.Next() # Skip for error recovery. except: pass + + Main driver code. + ----------------- + + def main(): # Set up the optimizer pipeline. Start with registering info + about how the # target lays out data structures. + g_llvm_pass_manager.add(g_llvm_executor.target_data) # Promote + allocas to registers. + g_llvm_pass_manager.add(PASS_PROMOTE_MEMORY_TO_REGISTER) # Do + simple "peephole" optimizations and bit-twiddling optzns. + g_llvm_pass_manager.add(PASS_INSTRUCTION_COMBINING) # Reassociate + expressions. g_llvm_pass_manager.add(PASS_REASSOCIATE) # Eliminate + Common SubExpressions. g_llvm_pass_manager.add(PASS_GVN) # Simplify + the control flow graph (deleting unreachable blocks, etc). + g_llvm_pass_manager.add(PASS_CFG_SIMPLIFICATION) + + g_llvm_pass_manager.initialize() + + # Install standard binary operators. # 1 is lowest possible precedence. + 40 is the highest. g_binop_precedence['='] = 2 + g_binop_precedence['<'] = 10 g_binop_precedence['+'] = 20 + g_binop_precedence['-'] = 20 g_binop_precedence['\*'] = 40 + + # Run the main "interpreter loop". while True: print 'ready<', try: raw + = raw_input() except KeyboardInterrupt: break + + :: + + parser = Parser(Tokenize(raw)) + while True: + # top ::= definition | external | expression | EOF + if isinstance(parser.current, EOFToken): + break + if isinstance(parser.current, DefToken): + parser.HandleDefinition() + elif isinstance(parser.current, ExternToken): + parser.HandleExtern() + else: + parser.HandleTopLevelExpression() + + # Print out all of the generated code. print '', g_llvm_module + + if **name** == '**main**\ ': main() diff --git a/docs/_build/html/_sources/doc/kaleidoscope/PythonLangImpl8.txt b/docs/_build/html/_sources/doc/kaleidoscope/PythonLangImpl8.txt new file mode 100644 index 0000000..e69de29 diff --git a/docs/_build/html/_sources/doc/kaleidoscope/index.txt b/docs/_build/html/_sources/doc/kaleidoscope/index.txt new file mode 100644 index 0000000..6099fea --- /dev/null +++ b/docs/_build/html/_sources/doc/kaleidoscope/index.txt @@ -0,0 +1,21 @@ +Kaleidoscope +-------------- + +Implementing a Language with LLVM + +The LLVM `Kaleidoscope `_ tutorial +has been ported to llvmpy by Max Shawabkeh. + +.. toctree:: + :titlesonly: + :numbered: + + PythonLangImpl1.rst + PythonLangImpl2.rst + PythonLangImpl3.rst + PythonLangImpl4.rst + PythonLangImpl5.rst + PythonLangImpl6.rst + PythonLangImpl7.rst + PythonLangImpl8.rst + diff --git a/docs/_build/html/_sources/doc/llvm.core.Argument.txt b/docs/_build/html/_sources/doc/llvm.core.Argument.txt new file mode 100644 index 0000000..2481665 --- /dev/null +++ b/docs/_build/html/_sources/doc/llvm.core.Argument.txt @@ -0,0 +1,58 @@ ++-------------------------------+ +| layout: page | ++-------------------------------+ +| title: Argument (llvm.core) | ++-------------------------------+ + +The ``args`` property of ``llvm.core.Function`` objects yields +``llvm.core.Argument`` objects. This allows for setting attributes for +functions arguments. ``Argument`` objects cannot be constructed from +user code, the only way to get a reference to these are from +``Function`` objects. + +The method ``add_attribute`` and ``remove_attribute`` can be used to add +or remove the following attributes: + +Value\| Equivalent LLVM Assembly Keyword \| +-----\|----------------------------------\| ``ATTR_ZEXT``\ \| +``zeroext`` \| ``ATTR_SEXT``\ \| ``signext`` \| ``ATTR_IN_REG``\ \| +``inreg`` \| ``ATTR_BY_VAL``\ \| ``byval`` \| ``ATTR_STRUCT_RET``\ \| +``sret`` \| ``ATTR_NO_ALIAS``\ \| ``noalias`` \| ``ATTR_NO_CAPTURE``\ \| +``nocapture`` \| ``ATTR_NEST``\ \| ``nest`` \| + +These method work exactly like the `corresponding +methods `_ of the ``Function`` class above. Refer +`LLVM docs `_ for +information on what each attribute means. + +The alignment of any argument can be set via the ``alignment`` property, +to any power of 2. + +llvm.core.Argument +================== + +Base Class +---------- + +- `llvm.core.Value `_ + +Properties +---------- + +``alignment`` +~~~~~~~~~~~~~ + +The alignment of the argument. Must be a power of 2. + +Methods +------- + +``add_attribute(attr)`` +~~~~~~~~~~~~~~~~~~~~~~~ + +Add an attribute ``attr`` to the argument, from the set listed above. + +``remove_attribute(attr)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Remove the attribute ``attr`` of the argument. diff --git a/docs/_build/html/_sources/doc/llvm.core.ArrayType.txt b/docs/_build/html/_sources/doc/llvm.core.ArrayType.txt new file mode 100644 index 0000000..f8b5e0c --- /dev/null +++ b/docs/_build/html/_sources/doc/llvm.core.ArrayType.txt @@ -0,0 +1,30 @@ ++--------------------------------+ +| layout: page | ++--------------------------------+ +| title: ArrayType (llvm.core) | ++--------------------------------+ + +llvm.core.ArrayType +=================== + +Base Class +---------- + +- `llvm.core.Type `_ + +Properties +---------- + +``element`` +~~~~~~~~~~~ + +[read-only] + +A ``Type`` object representing the type of the element of the array. + +``count`` +~~~~~~~~~ + +[read-only] + +The number of elements in the array. diff --git a/docs/_build/html/_sources/doc/llvm.core.BasicBlock.txt b/docs/_build/html/_sources/doc/llvm.core.BasicBlock.txt new file mode 100644 index 0000000..74806a6 --- /dev/null +++ b/docs/_build/html/_sources/doc/llvm.core.BasicBlock.txt @@ -0,0 +1,44 @@ ++---------------------------------+ +| layout: page | ++---------------------------------+ +| title: BasicBlock (llvm.core) | ++---------------------------------+ + +A basicblock is a list of instructions. A wellformed basicblock should +end with a terminator. ``Function.verify()`` will verify that. A +terminator is either a branch instruction or return instruction. It is +not possible to have instructions after a branch or return instruction. + +llvm.core.BasicBlock +==================== + +Base Class +---------- + +- `llvm.core.Value `_ + +Methods +------- + +``delete(self)`` +~~~~~~~~~~~~~~~~ + +Delete this basicblock from the function (``self.function``). + +``insert_before(self, name)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +TODO + +Proporties +---------- + +``function`` +~~~~~~~~~~~~ + +The parent function of this basicblock. + +``instructions`` +~~~~~~~~~~~~~~~~ + +A list of instructions in this basicblock. diff --git a/docs/_build/html/_sources/doc/llvm.core.Builder.txt b/docs/_build/html/_sources/doc/llvm.core.Builder.txt new file mode 100644 index 0000000..1e90908 --- /dev/null +++ b/docs/_build/html/_sources/doc/llvm.core.Builder.txt @@ -0,0 +1,411 @@ ++------------------------------+ +| layout: page | ++------------------------------+ +| title: Builder (llvm.core) | ++------------------------------+ + +The ``Builder`` class corresponds to the +`IRBuilder `_ +in C++ llvm. It provides an uniform API to populating +`BasicBlocks `_. Most of the methods in +``Builder`` correspond to the instructions in the LLVM IR. See `LLVM +documentation `_ for detail. These +methods have the ``name`` argument for overiding the name of the result +variable. When it is an empty string (default value), LLVM will set a +numeric ID for the result variable. + +llvm.core.Builder +================= + +- This will become a table of contents (this text will be scraped). + {:toc} + +Static Factor Method +-------------------- + +``new(basic_block)`` +~~~~~~~~~~~~~~~~~~~~ + +Create an instance of ``Builder`` at +`BasicBlock `_. + +Methods +------- + +``add(self, lhs, rhs, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that computes ``lhs+rhs`` for integer values only. + +``alloca(self, ty, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that allocates stack memory for a value of type +``ty``. + +``alloca_array(self, ty, size, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that allocates stack memory for a ``size`` +elements array of type ``ty``. + +``and_(self, lhs, rhs, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that computes ``lhs & rhs``. + +``ashr(self, lhs, rhs, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that computes ``lhs >> rhs`` using arithmetic +shift. + +``bitcast(self, value, dest_ty, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that cast ``value`` to type ``dest_ty``. + +``branch(self, bblk)`` +~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that branch to basicblock ``bblk``. + +``call(self, fn, args, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that call function ``fn`` with a iterable of +arguments ``args``. + +``cbranch(self, if_value, then_blk, else_blk)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that conditionally branch base on the predicate +``if_value``. If ``if_value`` is ``True``, branch to ``then_blk``; +Otherwise, branch to ``else_blk``. + +``extract_element(self, vec_val, idx_val, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that extracts an element from a value ``vec_val`` +of `llvm.core.VectorType `_ at index +``idx_val``. + +``extract_value(self, retval, idx, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that extracts an element from an aggregate value +``retval`` at index ``idx``. + +``fadd(self, lhs, rhs, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that computes ``lhs + rhs`` for floating-point +values. + +``fcmp(self, rpred, lhs, rhs, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that compares ``lhs`` and ``rhs`` using the +comparision operation defined by ``rpred``. See +`here `_ for a list of comparators. + +``fdiv(self, lhs, rhs, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that computes ``lhs / rhs`` for floating-point +values. + +``fmul(self, lhs, rhs, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that computes ``lhs * rhs`` for floating-point +values. + +``fpext(self, value, dest_ty, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that extends ``value`` to a float type +``dest_ty``. + +``fptosi(self, value, dest_ty, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that converts a floating-point value ``value`` to +a signed integer type ``dest_ty``. + +``fptoui(self, value, dest_ty, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that converts a floating-point value ``value`` to +an unsigned integer type ``dest_ty``. + +``fptrunc(self, value, dest_ty, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that truncates a floating-point value ``value`` to +a float type ``dest_ty``. + +``free(self, ptr)`` +~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that call performs heap deallocation on pointer +``ptr``. + +``frem(self, lhs, rhs, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that computes ``lhs % rhs`` for floating-point +values. + +``fsub(self, lhs, rhs, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that computes ``lhs - rhs`` for floating-point +values. + +``gep(self, ptr, indices, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +See `GEP `_. + +``getresult(self, retval, idx, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +same as ``extract_value``. + +``icmp(self, ipred, lhs, rhs, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that compares ``lhs`` and ``rhs`` using the +comparision operation defined by ``ipred``. See +`here `_ for a list of comparators. + +``insert_element(self, vec_val, elt_val, idx_val, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that inserts a value ``elt_val`` into ``vec_val`` +of `llvm.core.VectorType `_ at index +``idx_val``. + +``inttoptr(self, value, dest_ty, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that converts an integer ``value`` to pointer +``dest_ty``. + +``invoke(self, func, args, then_blk, catch_blk, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +See `invoke `_ + +``load(self, ptr, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that loads a value at the memory pointed by +``ptr``. + +``lshr(self, lhs, rhs, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that computes ``lhs >> rhs`` using logical shift. + +``malloc(self, ty, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that allocates heap memory of type ``ty``. The +instruction returns a pointer that points to a value of type ``ty``. + +``malloc_array(self, ty, size, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Similar to ``malloc`` but allocates an array of ``size`` elements. + +``mul(self, lhs, rhs, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that computes ``lhs * rhs`` for integer types. + +``neg(self, val, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that computes ``0 - val``. + +``not_(self, val, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that computes an one's complement of ``val``. + +``or_(self, lhs, rhs, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that computes ``lhs | rhs``. + +``phi(self, ty, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Create a PHI node of type ``ty``. + +``position_at_beginning(self, bblk)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Position the builder at the beginning of the given block. Next +instruction inserted will be first one in the block. + +``position_at_end(self, bblk)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Position the builder at the end of the given block. Next instruction +inserted will be last one in the block. + +``position_before(self, instr)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Position the builder before the given instruction. The instruction can +belong to a basic block other than the current one. + +``ptrtoint(self, value, dest_ty, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that converts a pointer to an integer ``value`` of +type ``dest_ty``. + +``ret(self, value)`` +~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that returns ``value``. + +``ret_many(self, values)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that returns ``values`` which is an iterable of +`llvm.core.Value `_. + +``ret_void(self)`` +~~~~~~~~~~~~~~~~~~ + +Insert an instruction that returns nothing (void). + +``sdiv(self, lhs, rhs, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that computes ``lhs / rhs`` for signed integers. + +``select(self, cond, then_value, else_value, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that computes ``cond ? then_value : else_value``. + +``sext(self, value, dest_ty, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that sign extends an integer ``value`` to type +``dest_ty``. + +``shl(self, lhs, rhs, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that computes ``lhs << rhs``. + +``shuffle_vector(self, vecA, vecB, mask, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that performs a vector shuffle base on the two +vectors -- ``vecA`` and ``vecB``, base on a bit mask ``mask``. The mask +must be a constant. + +See `LLVM document `_ +for detail. + +``sitofp(self, value, dest_ty, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that converts a signed integer ``value`` to a +floating-point type ``dest_ty``. + +``srem(self, lhs, rhs, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that computes ``lhs % rhs`` for signed integers. + +``store(self, value, ptr)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that stores ``value`` into the memory pointed by +``ptr``. + +``sub(self, lhs, rhs, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that computes ``lhs - rhs``. + +``switch(self, value, else_blk, n=10)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that transfer control flow depending on the +``value``. ``else_blk`` is the default case. ``n`` sets the number of +additional cases. + +This method returns an instance of +`SwitchInstruction `_ for adding +cases to the switch. + +``trunc(self, value, dest_ty, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that truncates an integer ``value`` to the +destination integer type ``dest_ty``. + +``udiv(self, lhs, rhs, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that computes ``lhs / rhs`` for unsigned integers. + +``uitofp(self, value, dest_ty, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that converts an unsigned integer ``value`` to a +floating-point type ``dest_ty``. + +``unreachable(self)`` +~~~~~~~~~~~~~~~~~~~~~ + +Insert an unreachabe instruction, which has no defined semantics. See +`LLVM document `_ for +detail. + +``urem(self, lhs, rhs, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that computes ``lhs % rhs`` for unsigned integers. + +``vaarg(self, list_val, ty, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This is used to access variable arguments given as ``list_val`` of type +``ty``. see `LLVM +document `_ about +variable argument intrinsics. + +``xor(self, lhs, rhs, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that computes ``lhs xor rhs``. + +``zext(self, value, dest_ty, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Insert an instruction that zero extends ``value`` to type ``dest_ty``. + +Properties +---------- + +``basic_block`` +~~~~~~~~~~~~~~~ + +The `BasicBlock `_ where the builder is +positioned. + +``block`` +~~~~~~~~~ + +Deprecated. Same as ``basic_block`` diff --git a/docs/_build/html/_sources/doc/llvm.core.Constant.txt b/docs/_build/html/_sources/doc/llvm.core.Constant.txt new file mode 100644 index 0000000..4f2ed08 --- /dev/null +++ b/docs/_build/html/_sources/doc/llvm.core.Constant.txt @@ -0,0 +1,353 @@ ++-------------------------------+ +| layout: page | ++-------------------------------+ +| title: Constant (llvm.core) | ++-------------------------------+ + +``Constant``-s represents constants that appear within the code. The +values of such objects are known at creation time. Constants can be +created from Python constants. A constant expression is also a constant +-- given a ``Constant`` object, an operation (like addition, subtraction +etc) can be specified, to yield a new ``Constant`` object. Let's see +some examples: + + +.. code-block:: python + + #!/usr/bin/env python + + ti = Type.int() # a 32-bit int type + + k1 = Constant.int(ti, 42) # "int k1 = 42;" k2 = k1.add( Constant.int( + ti, 10 ) ) # "int k2 = k1 + 10;" + + tr = Type.float() + + r1 = Constant.real(tr, "3.141592") # create from a string r2 = + Constant.real(tr, 1.61803399) # create from a Python float {% + endhighlight %} + + # llvm.core.Constant + - This will become a table of contents (this text will be scraped). + {:toc} + + Static factory methods + ---------------------- + + ``null(ty)`` + ~~~~~~~~~~~~ + + A null value (all zeros) of type ``ty`` + + ``all_ones(ty)`` + ~~~~~~~~~~~~~~~~ + + All 1's value of type ``ty`` + + ``undef(ty)`` + ~~~~~~~~~~~~~ + + An undefined value of type ``ty`` + + ``int(ty, value)`` + ~~~~~~~~~~~~~~~~~~ + + Integer of type ``ty``, with value ``value`` (a Python int or long) + + ``int_signextend(ty, value)`` + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Integer of signed type ``ty`` (use for signed types) + + ``real(ty, value)`` + ~~~~~~~~~~~~~~~~~~~ + + Floating point value of type ``ty``, with value ``value`` (a Python + float) + + ``stringz(value)`` + ~~~~~~~~~~~~~~~~~~ + + A null-terminated string. ``value`` is a Python string + + ``string(value)`` + ~~~~~~~~~~~~~~~~~ + + As ``string(ty)``, but not null terminated + + ``array(ty, consts)`` + ~~~~~~~~~~~~~~~~~~~~~ + + Array of type ``ty``, initialized with ``consts`` (an iterable yielding + ``Constant`` objects of the appropriate type) + + ``struct(ty, consts)`` + ~~~~~~~~~~~~~~~~~~~~~~ + + Struct (unpacked) of type ``ty``, initialized with ``consts`` (an + iterable yielding ``Constant`` objects of the appropriate type) + + ``packed_struct(ty, consts)`` + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + As ``struct(ty, consts)`` but packed + + ``vector(consts)`` + ~~~~~~~~~~~~~~~~~~ + + Vector, initialized with ``consts`` (an iterable yielding ``Constant`` + objects of the appropriate type) + + ``sizeof(ty)`` + ~~~~~~~~~~~~~~ + + Constant value representing the sizeof the type ``ty`` + + Methods + ------- + + The following operations on constants are supported. For more details on + any operation, consult the `Constant + Expressions `_ + section of the LLVM Language Reference. + + ``k.neg()`` + ~~~~~~~~~~~ + + negation, same as ``0 - k`` + + ``k.not_()`` + ~~~~~~~~~~~~ + + 1's complement of ``k``. Note trailing underscore. + + ``k.add(k2)`` + ~~~~~~~~~~~~~ + + ``k + k2``, where ``k`` and ``k2`` are integers. + + ``k.fadd(k2)`` + ~~~~~~~~~~~~~~ + + ``k + k2``, where ``k`` and ``k2`` are floating-point. + + ``k.sub(k2)`` + ~~~~~~~~~~~~~ + + ``k - k2``, where ``k`` and ``k2`` are integers. + + ``k.fsub(k2)`` + ~~~~~~~~~~~~~~ + + ``k - k2``, where ``k`` and ``k2`` are floating-point. + + ``k.mul(k2)`` + ~~~~~~~~~~~~~ + + ``k * k2``, where ``k`` and ``k2`` are integers. + + ``k.fmul(k2)`` + ~~~~~~~~~~~~~~ + + ``k * k2``, where ``k`` and ``k2`` are floating-point. + + ``k.udiv(k2)`` + ~~~~~~~~~~~~~~ + + Quotient of unsigned division of ``k`` with ``k2`` + + ``k.sdiv(k2)`` + ~~~~~~~~~~~~~~ + + Quotient of signed division of ``k`` with ``k2`` + + ``k.fdiv(k2)`` + ~~~~~~~~~~~~~~ + + Quotient of floating point division of ``k`` with ``k2`` + + ``k.urem(k2)`` + ~~~~~~~~~~~~~~ + + Reminder of unsigned division of ``k`` with ``k2`` + + ``k.srem(k2)`` + ~~~~~~~~~~~~~~ + + Reminder of signed division of ``k`` with ``k2`` + + ``k.frem(k2)`` + ~~~~~~~~~~~~~~ + + Reminder of floating point division of ``k`` with ``k2`` + + ``k.and_(k2)`` + ~~~~~~~~~~~~~~ + + Bitwise and of ``k`` and ``k2``. Note trailing underscore. + + ``k.or_(k2)`` + ~~~~~~~~~~~~~ + + Bitwise or of ``k`` and ``k2``. Note trailing underscore. + + ``k.xor(k2)`` + ~~~~~~~~~~~~~ + + Bitwise exclusive-or of ``k`` and ``k2``. + + ``k.icmp(icmp, k2)`` + ~~~~~~~~~~~~~~~~~~~~ + + Compare ``k`` with ``k2`` using the predicate ``icmp``. See + `here `_ for list of predicates for integer + operands. + + ``k.fcmp(fcmp, k2)`` + ~~~~~~~~~~~~~~~~~~~~ + + Compare ``k`` with ``k2`` using the predicate ``fcmp``. See + `here `_ for list of predicates for real + operands. + + ``k.shl(k2)`` + ~~~~~~~~~~~~~ + + Shift ``k`` left by ``k2`` bits. + + ``k.lshr(k2)`` + ~~~~~~~~~~~~~~ + + Shift ``k`` logically right by ``k2`` bits (new bits are 0s). + + ``k.ashr(k2)`` + ~~~~~~~~~~~~~~ + + Shift ``k`` arithmetically right by ``k2`` bits (new bits are same as + previous sign bit). + + ``k.gep(indices)`` + ~~~~~~~~~~~~~~~~~~ + + GEP, see `LLVM docs `_. + + ``k.trunc(ty)`` + ~~~~~~~~~~~~~~~ + + Truncate ``k`` to a type ``ty`` of lower bitwidth. + + ``k.sext(ty)`` + ~~~~~~~~~~~~~~ + + Sign extend ``k`` to a type ``ty`` of higher bitwidth, while extending + the sign bit. + + ``k.zext(ty)`` + ~~~~~~~~~~~~~~ + + Sign extend ``k`` to a type ``ty`` of higher bitwidth, all new bits are + 0s. + + ``k.fptrunc(ty)`` + ~~~~~~~~~~~~~~~~~ + + Truncate floating point constant ``k`` to floating point type ``ty`` of + lower size than k's. + + ``k.fpext(ty)`` + ~~~~~~~~~~~~~~~ + + Extend floating point constant ``k`` to floating point type ``ty`` of + higher size than k's. + + ``k.uitofp(ty)`` + ~~~~~~~~~~~~~~~~ + + Convert an unsigned integer constant ``k`` to floating point constant of + type ``ty``. + + ``k.sitofp(ty)`` + ~~~~~~~~~~~~~~~~ + + Convert a signed integer constant ``k`` to floating point constant of + type ``ty``. + + ``k.fptoui(ty)`` + ~~~~~~~~~~~~~~~~ + + Convert a floating point constant ``k`` to an unsigned integer constant + of type ``ty``. + + ``k.fptosi(ty)`` + ~~~~~~~~~~~~~~~~ + + Convert a floating point constant ``k`` to a signed integer constant of + type ``ty``. + + ``k.ptrtoint(ty)`` + ~~~~~~~~~~~~~~~~~~ + + Convert a pointer constant ``k`` to an integer constant of type ``ty``. + + ``k.inttoptr(ty)`` + ~~~~~~~~~~~~~~~~~~ + + Convert an integer constant ``k`` to a pointer constant of type ``ty``. + + ``k.bitcast(ty)`` + ~~~~~~~~~~~~~~~~~ + + Convert ``k`` to a (equal-width) constant of type ``ty``. + + ``k.select(cond,k2,k3)`` + ~~~~~~~~~~~~~~~~~~~~~~~~ + + Replace value with ``k2`` if the 1-bit integer constant ``cond`` is 1, + else with ``k3``. + + ``k.extract_element(idx)`` + ~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Extract value at ``idx`` (integer constant) from a vector constant + ``k``. + + ``k.insert_element(k2,idx)`` + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Insert value ``k2`` (scalar constant) at index ``idx`` (integer + constant) of vector constant ``k``. + + ``k.shuffle_vector(k2,mask)`` + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Shuffle vector constant ``k`` based on vector constants ``k2`` and + ``mask``. + + -------------- + + # Other Constant Classes + The following subclasses of ``Constant`` do not provide additional + methods, **they serve only to provide richer type information.** + + Subclass \| LLVM C++ Class \| Remarks \| + ---------\|----------------\|---------\| ``ConstantExpr`` \| + ``llvmConstantExpr`` \| A constant expression \| + ``ConstantAggregateZero``\ \| ``llvmConstantAggregateZero``\ \| All-zero + constant \| ``ConstantInt``\ \| ``llvmConstantInt``\ \| An integer + constant \| ``ConstantFP``\ \| ``llvmConstantFP``\ \| A floating-point + constant \| ``ConstantArray``\ \| ``llvmConstantArray``\ \| An array + constant \| ``ConstantStruct``\ \| ``llvmConstantStruct``\ \| A + structure constant \| ``ConstantVector``\ \| ``llvmConstantVector``\ \| + A vector constant \| ``ConstantPointerNull``\ \| + ``llvmConstantPointerNull``\ \| All-zero pointer constant \| + ``UndefValue``\ \| ``llvmUndefValue``\ \| corresponds to ``undef`` of + LLVM IR \| + + These types are helpful in ``isinstance`` checks, like so: + + {% highlight python %} ti = Type.int(32) k1 = Constant.int(ti, 42) # + int32_t k1 = 42; k2 = Constant.array(ti, [k1, k1]) # int32_t k2[] = { + k1, k1 }; + + assert isinstance(k1, ConstantInt) assert isinstance(k2, ConstantArray) + diff --git a/docs/_build/html/_sources/doc/llvm.core.Function.txt b/docs/_build/html/_sources/doc/llvm.core.Function.txt new file mode 100644 index 0000000..1d6070c --- /dev/null +++ b/docs/_build/html/_sources/doc/llvm.core.Function.txt @@ -0,0 +1,151 @@ ++-------------------------------+ +| layout: page | ++-------------------------------+ +| title: Function (llvm.core) | ++-------------------------------+ + +llvm.core.Function +================== + +- This will become a table of contents (this text will be scraped). + {:toc} + +Base Class +---------- + +- `llvm.core.GlobalValue `_ + +Static Constructors +------------------- + +``new(module_obj, func_ty, name)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Create a function named ``name`` of type ``func_ty`` in the module +``module_obj`` and return a ``Function`` object that represents it. + +``get(module_obj, name)`` +~~~~~~~~~~~~~~~~~~~~~~~~~ + +Return a ``Function`` object to represent the function named ``name`` in +the module ``module_obj`` or raise ``LLVMException`` if such a function +does not exist. + +``get_or_insert(module_obj, func_ty, name)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Similar to ``get``, except that if the function does not exist it is +added first, as though with ``new``. + +``intrinsic(module_obj, intrinsic_id, types)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Create and return a ``Function`` object that refers to an intrinsic +function, as described `here `_. + +Properties +---------- + +``calling_convention`` +~~~~~~~~~~~~~~~~~~~~~~ + +The calling convention for the function, as listed +`here `_. + +``collector`` +~~~~~~~~~~~~~ + +A string holding the name of the garbage collection algorithm. See `LLVM +docs `_. + +``does_not_throw`` +~~~~~~~~~~~~~~~~~~ + +Setting to True sets the ``ATTR_NO_UNWIND`` attribute, False removes it. +Shortcut to using ``f.add_attribute(ATTR_NO_UNWIND)`` and +``f.remove_attribute(ATTR_NO_UNWIND)``. + +``args`` +~~~~~~~~ + +[read-only] + +List of `llvm.core.Argument `_ objects +representing the formal arguments of the function. + +``basic_block_count`` +~~~~~~~~~~~~~~~~~~~~~ + +[read-only] + +Number of basic blocks belonging to this function. Same as +``len(f.basic_blocks)`` but faster if you just want the count. + +``entry_basic_block`` +~~~~~~~~~~~~~~~~~~~~~ + +[read-only] + +The `llvm.core.BasicBlock `_ object +representing the entry basic block for this function, or ``None`` if +there are no basic blocks. + +``basic_blocks`` +~~~~~~~~~~~~~~~~ + +[read-only] + +List of `llvm.core.BasicBlock `_ objects +representing the basic blocks belonging to this function. + +``intrinsic_id`` +~~~~~~~~~~~~~~~~ + +[read-only] + +Returns the ID of the intrinsic if this object represents an intrinsic +instruction. Otherwise 0. + +Methods +------- + +``delete()`` +~~~~~~~~~~~~ + +Deletes the function from it's module. Do not hold any references to +this object after calling ``delete`` on it. + +``append_basic_block(name)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Add a new basic block named ``name``, and return a corresponding +`llvm.core.BasicBlock `_ object. Note that if +this is not the entry basic block, you'll have to add appropriate branch +instructions from other basic blocks yourself. + +``add_attribute(attr)`` +~~~~~~~~~~~~~~~~~~~~~~~ + +Add an attribute ``attr`` to the function, from the set listed above. + +``remove_attribute(attr)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Remove the attribute ``attr`` of the function. + +``viewCFG()`` +~~~~~~~~~~~~~ + +Displays the control flow graph using the GraphViz tool. + +``viewCFGOnly()`` +~~~~~~~~~~~~~~~~~ + +Displays the control flow graph using the GraphViz tool, but omitting +function bodies. + +``verify()`` +~~~~~~~~~~~~ + +Verifies the function. See `LLVM +docs `_. diff --git a/docs/_build/html/_sources/doc/llvm.core.FunctionType.txt b/docs/_build/html/_sources/doc/llvm.core.FunctionType.txt new file mode 100644 index 0000000..8d40009 --- /dev/null +++ b/docs/_build/html/_sources/doc/llvm.core.FunctionType.txt @@ -0,0 +1,48 @@ ++-----------------------------------+ +| layout: page | ++-----------------------------------+ +| title: FunctionType (llvm.core) | ++-----------------------------------+ + +llvm.core.FunctionType +====================== + +Base Class +---------- + +- `llvm.core.Type `_ + +Properties +---------- + +``return_type`` +~~~~~~~~~~~~~~~ + +[read-only] + +A `Type `_ object, representing the return type of +the function. + +``vararg`` +~~~~~~~~~~ + +[read-only] + +``True`` if the function is variadic. + +``args`` +~~~~~~~~ + +[read-only] + +Returns an iterable object that yields `Type `_ +objects that represent, in order, the types of the arguments accepted by +the function. Used like this: + + +.. code-block:: python + + func_type = Type.function( Type.int(), [ + Type.int(), Type.int() ] ) for arg in func_type.args: assert arg.kind + == TYPE_INTEGER assert arg == Type.int() assert func_type.arg_count + == len(func_type.args) diff --git a/docs/_build/html/_sources/doc/llvm.core.GlobalValue.txt b/docs/_build/html/_sources/doc/llvm.core.GlobalValue.txt new file mode 100644 index 0000000..70dee7b --- /dev/null +++ b/docs/_build/html/_sources/doc/llvm.core.GlobalValue.txt @@ -0,0 +1,97 @@ ++----------------------------------+ +| layout: page | ++----------------------------------+ +| title: GlobalValue (llvm.core) | ++----------------------------------+ + +The class ``llvm.core.GlobalValue`` represents module-scope aliases, +variables and functions. Global variables are represented by the +sub-class `llvm.core.GlobalVariable `_ +and functions by `llvm.core.Function `_. + +Global values have the read-write properties ``linkage``, ``section``, +``visibility`` and ``alignment``. Use one of the following constants +(from llvm.core) as values for ``linkage`` (see `LLVM +documentaion `_ for +details on each): + +Value \| Equivalent LLVM Assembly Keyword \| +------\|----------------------------------\| ``LINKAGE_EXTERNAL`` \| +``externally_visible`` \| ``LINKAGE_AVAILABLE_EXTERNALLY`` \| +``available_externally`` \| ``LINKAGE_LINKONCE_ANY`` \| ``linkonce`` \| +``LINKAGE_LINKONCE_ODR`` \| ``linkonce_odr`` \| ``LINKAGE_WEAK_ANY`` \| +``weak`` \| ``LINKAGE_WEAK_ODR`` \| ``weak_odr`` \| +``LINKAGE_APPENDING`` \| ``appending`` \| ``LINKAGE_INTERNAL`` \| +``internal`` \| ``LINKAGE_PRIVATE`` \| ``private`` \| +``LINKAGE_DLLIMPORT`` \| ``dllimport`` \| ``LINKAGE_DLLEXPORT`` \| +``dllexport`` \| ``LINKAGE_EXTERNAL_WEAK`` \| ``extern_weak`` \| +``LINKAGE_GHOST`` \| deprecated -- do not use \| ``LINKAGE_COMMON`` \| +``common`` \| ``LINKAGE_LINKER_PRIVATE`` \| ``linker_private`` \| + +The ``section`` property can be assigned strings (like ".rodata"), which +will be used if the target supports it. Visibility property can be set +to one of thse constants (from llvm.core, see also `LLVM +docs `_): + +Value \| Equivalent LLVM Assembly Keyword \| +------\|----------------------------------\| ``VISIBILITY_DEFAULT`` \| +``default`` \| ``VISIBILITY_HIDDEN`` \| ``hidden`` \| +``VISIBILITY_PROTECTED`` \| ``protected`` \| + +The ``alignment`` property can be 0 (default), or can be set to a power +of 2. The read-only property ``is_declaration`` can be used to check if +the global is a declaration or not. The module to which the global +belongs to can be retrieved using the ``module`` property (read-only). + +llvm.core.GlobalValue +===================== + +- This will become a table of contents (this text will be scraped). + {:toc} + +Base Class +---------- + +- `llvm.core.Constant `_ + +Properties +---------- + +``linkage`` +~~~~~~~~~~~ + +The linkage type, takes one of the constants listed above (LINKAGE\_\*). + +``section`` +~~~~~~~~~~~ + +A string like ".rodata", indicating the section into which the global is +placed into. + +``visibility`` +~~~~~~~~~~~~~~ + +The visibility type, takes one of the constants listed above +(VISIBILITY\_\*). + +``alignment`` +~~~~~~~~~~~~~ + +A power-of-2 integer indicating the boundary to align to. + +``is_declaration`` +~~~~~~~~~~~~~~~~~~ + +[read-only] + +``True`` if the global is a declaration, ``False`` otherwise. + +``module`` +~~~~~~~~~~ + +[read-only] + +:: + + The module object to which this global belongs to. + diff --git a/docs/_build/html/_sources/doc/llvm.core.GlobalVariable.txt b/docs/_build/html/_sources/doc/llvm.core.GlobalVariable.txt new file mode 100644 index 0000000..392a6a0 --- /dev/null +++ b/docs/_build/html/_sources/doc/llvm.core.GlobalVariable.txt @@ -0,0 +1,39 @@ ++-------------------------------------+ +| layout: page | ++-------------------------------------+ +| title: GlobalVariable (llvm.core) | ++-------------------------------------+ + +Global variables (``llvm.core.GlobalVariable``) are subclasses of +`llvm.core.GlobalValue `_ and represent +module-level variables. These can have optional initializers and can be +marked as constants. Global variables can be created either by using the +``add_global_variable`` method of the `Module `_ +class, or by using the static method ``GlobalVariable.new``. + + +.. code-block:: python + + # create a global variable using + add_global_variable method gv1 = + module_obj.add_global_variable(Type.int(), "gv1") + + # or equivalently, using a static constructor method + gv2 = GlobalVariable.new(module_obj, Type.int(), "gv2") {% endhighlight + %} + + Existing global variables of a module can be accessed by name using + ``module_obj.get_global_variable_named(name)`` or + ``GlobalVariable.get``. All existing global variables can be enumerated + via iterating over the property ``module_obj.global_variables``. + + {% highlight python %} # retrieve a reference to the global variable + gv1, # using the get_global_variable_named method gv1 = + module_obj.get_global_variable_named("gv1") + + # or equivalently, using the static ``get`` method: + gv2 = GlobalVariable.get(module_obj, "gv2") + + # list all global variables in a module + for gv in module_obj.global_variables: print gv.name, "of type", + gv.type diff --git a/docs/_build/html/_sources/doc/llvm.core.Instruction.txt b/docs/_build/html/_sources/doc/llvm.core.Instruction.txt new file mode 100644 index 0000000..95aeb81 --- /dev/null +++ b/docs/_build/html/_sources/doc/llvm.core.Instruction.txt @@ -0,0 +1,242 @@ ++----------------------------------+ +| layout: page | ++----------------------------------+ +| title: Instruction (llvm.core) | ++----------------------------------+ + +An ``llvm.core.Instruction`` object represents an LLVM instruction. This +class is the root of a small hierarchy: + +:: + + Instruction + CallOrInvokeInstruction + PHINode + SwitchInstruction + CompareInstruction + +Instructions are not created directly, but via a builder. The builder +both creates instructions and adds them to a basic block at the same +time. One way of getting instruction objects are from basic blocks. + +Being derived from `llvm.core.User `_, the +instruction is-a user, i.e., an instruction in turn uses other values. +The values an instruction uses are its operands. These may be accessed +using ``operands`` property from the +`llvm.core.User `_ base. + +The name of the instruction (like ``add``, ``mul`` etc) can be got via +the ``opcode_name`` property. The ``basic_block`` property gives the +basic block to which the instruction belongs to. Note that llvmpy does +not allow free-standing instruction objects (i.e., all instructions are +created contained within a basic block). + +Classes of instructions can be got via the properties ``is_terminator``, +``is_binary_op``, ``is_shift`` etc. See below for the full list. + +- This will become a table of contents (this text will be scraped). + {:toc} + +llvm.core.Instruction +===================== + +Base Class +---------- + +- `llvm.core.User `_ + +Properties +---------- + +``basic_block`` +~~~~~~~~~~~~~~~ + +[read-only] The basic block to which this instruction belongs to. + +``is_terminator`` +~~~~~~~~~~~~~~~~~ + +[read-only] True if the instruction is a terminator instruction. + +``is_binary_op`` +~~~~~~~~~~~~~~~~ + +[read-only] True if the instruction is a binary operator. + +``is_shift`` +~~~~~~~~~~~~ + +[read-only] True if the instruction is a shift instruction. + +``is_cast`` +~~~~~~~~~~~ + +[read-only] True if the instruction is a cast instruction. + +``is_logical_shift`` +~~~~~~~~~~~~~~~~~~~~ + +[read-only] True if the instruction is a logical shift instruction. + +``is_arithmetic_shift`` +~~~~~~~~~~~~~~~~~~~~~~~ + +[read-only] True if the instruction is an arithmetic shift instruction. + +``is_associative`` +~~~~~~~~~~~~~~~~~~ + +[read-only] True if the instruction is associative. + +``is_commutative`` +~~~~~~~~~~~~~~~~~~ + +[read-only] True if the instruction is commutative. + +``is_volatile`` +~~~~~~~~~~~~~~~ + +[read-only] True if the instruction is a volatile load or store. + +``opcode`` +~~~~~~~~~~ + +[read-only] The numeric opcode value of the instruction. Do not rely on +the absolute value of this number, it may change with LLVM version. + +``opcode_name`` +~~~~~~~~~~~~~~~ + +[read-only] The name of the instruction, like ``add``, ``sub`` etc. + +-------------- + +llvm.core.CallOrInvokeInstruction +================================= + +The ``llvm.core.CallOrInvokeInstruction`` is a subclass of +``llvm.core.Instruction``, and represents either a ``call`` or an +``invoke`` instruction. + +Base Class +---------- + +- ``llvm.core.Instruction`` + +Properties +---------- + +``calling_convention`` Get or set the calling convention. See +`here `_ for possible values. + +Methods +------- + +``add_parameter_attribute(idx, attr)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Add an attribute ``attr`` to the ``idx``-th argument. See +`here `_ for possible values of ``attr``. + +``remove_parameter_attribute(idx, attr)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Remove an attribute ``attr`` from the ``idx``-th argument. See +`here `_ for possible values of ``attr``. + +``set_parameter_alignment(idx, align)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Set the alignment of the ``idx``-th argument to ``align``. ``align`` +should be a power of two. + +-------------- + +llvm.core.PHINode +================= + +The ``llvm.core.PHINode`` is a subclass of ``llvm.core.Instruction``, +and represents the ``phi`` instruction. When created (using +``Builder.phi``) the phi node contains no incoming blocks (nor their +corresponding values). To add an incoming arc to the phi node, use the +``add_incoming`` method, which takes a source block +(`llvm.core.BasicBlock `_ object) and a value +(object of `llvm.core.Value `_ or of a class +derived from it) that the phi node will take on if control branches in +from that block. + +Base Class +---------- + +- ``llvm.core.Instruction`` + +Properties +---------- + +``incoming_count`` [read-only] The number of incoming arcs for this phi +node. + +Methods +------- + +``add_incoming(value, block)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Add an incoming arc, from the +`llvm.core.BasicBlock `_ object ``block``, +with the corresponding value ``value``. ``value`` should be an object of +`llvm.core.Value `_ (or of a descendent class). + +``get_incoming_value(idx)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Returns the ``idx``-th incoming arc's value. + +``get_incoming_block(idx)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Returns the ``idx``-th incoming arc's block. + +llvm.core.SwitchInstruction # {#switchinstr} +============================================ + +(TODO describe) + +Base Class +---------- + +- ``llvm.core.Instruction`` + +Methods +------- + +``add_case(const, block)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Add another case to the switch statement. When the expression being +evaluated equals ``const``, then control branches to ``block``. Here +``const`` must be of type +`llvm.core.ConstantInt `_. + +-------------- + +llvm.core.CompareInstruction +============================ + +(TODO describe) + +Base Class +---------- + +- ``llvm.core.Instruction`` + +Properties +---------- + +``predicate`` +~~~~~~~~~~~~~ + +[read-only] + +The predicate of the compare instruction, one of the ``ICMP_*`` or +``FCMP_*`` constants. diff --git a/docs/_build/html/_sources/doc/llvm.core.IntegerType.txt b/docs/_build/html/_sources/doc/llvm.core.IntegerType.txt new file mode 100644 index 0000000..f62907c --- /dev/null +++ b/docs/_build/html/_sources/doc/llvm.core.IntegerType.txt @@ -0,0 +1,23 @@ ++----------------------------------+ +| layout: page | ++----------------------------------+ +| title: IntegerType (llvm.core) | ++----------------------------------+ + +llvm.core.IntegerType +===================== + +Base Class +---------- + +- `llvm.core.Type `_ + +Properties +---------- + +``width`` +~~~~~~~~~ + +[read-only] + +The width of the integer type, in number of bits. diff --git a/docs/_build/html/_sources/doc/llvm.core.Module.txt b/docs/_build/html/_sources/doc/llvm.core.Module.txt new file mode 100644 index 0000000..3dbd5c8 --- /dev/null +++ b/docs/_build/html/_sources/doc/llvm.core.Module.txt @@ -0,0 +1,19 @@ ++-----------------------------+ +| layout: page | ++-----------------------------+ +| title: Module (llvm.core) | ++-----------------------------+ + +Modules are top-level container objects. You need to create a module +object first, before you can add global variables, aliases or functions. +Modules are created using the static method ``Module.new``: + + +.. code-block:: python + + #!/usr/bin/env python + + from llvm import \* from llvm.core import \* + + # create a module + my_module = Module.new('my_module') diff --git a/docs/_build/html/_sources/doc/llvm.core.PointerType.txt b/docs/_build/html/_sources/doc/llvm.core.PointerType.txt new file mode 100644 index 0000000..a869fba --- /dev/null +++ b/docs/_build/html/_sources/doc/llvm.core.PointerType.txt @@ -0,0 +1,31 @@ ++----------------------------------+ +| layout: page | ++----------------------------------+ +| title: PointerType (llvm.core) | ++----------------------------------+ + +llvm.core.PointerType +===================== + +Base Class +---------- + +- `llvm.core.Type `_ + +Properties +---------- + +``address_space`` +~~~~~~~~~~~~~~~~~ + +[read-only] + +The address space of the pointer. + +``pointee`` +~~~~~~~~~~~ + +[read-only] + +A `Type `_ object representing the type of the +value pointed to. diff --git a/docs/_build/html/_sources/doc/llvm.core.StructType.txt b/docs/_build/html/_sources/doc/llvm.core.StructType.txt new file mode 100644 index 0000000..e69de29 diff --git a/docs/_build/html/_sources/doc/llvm.core.Type.txt b/docs/_build/html/_sources/doc/llvm.core.Type.txt new file mode 100644 index 0000000..58883d7 --- /dev/null +++ b/docs/_build/html/_sources/doc/llvm.core.Type.txt @@ -0,0 +1,128 @@ ++---------------------------+ +| layout: page | ++---------------------------+ +| title: Type (llvm.core) | ++---------------------------+ + +llvm.core.Type +============== + +- This will become a table of contents (this text will be scraped). + {:toc} + +Static Constructors +------------------- + +``int(n)`` +~~~~~~~~~~ + +Create an integer type of bit width ``n``. + +``float()`` +~~~~~~~~~~~ + +Create a 32-bit floating point type. + +``double()`` +~~~~~~~~~~~~ + +Create a 64-bit floating point type. + +``x86_fp80()`` +~~~~~~~~~~~~~~ + +Create a 80-bit 80x87-style floating point type. + +``fp128()`` +~~~~~~~~~~~ + +Create a 128-bit floating point type (112-bit mantissa). + +``ppc_fp128()`` +~~~~~~~~~~~~~~~ + +Create a 128-bit float (two 64-bits). + +``function(ret, params, vararg=False)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Create a function type, having the return type ``ret`` (must be a +``Type``), accepting the parameters ``params``, where ``params`` is an +iterable, that yields ``Type`` objects representing the type of each +function argument in order. If ``vararg`` is ``True``, function is +variadic. + +``struct(eltys, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Create an unpacked structure. ``eltys`` is an iterable, that yields +``Type`` objects representing the type of each element in order. + +If ``name`` is evaulates ``True`` (not empty), create an *identified +structure*; otherwise, create a *literal structure* by default. + +``packed_struct(eltys, name='')`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Like ``struct(eltys)``, but creates a packed struct. + +``array(elty, count)`` +~~~~~~~~~~~~~~~~~~~~~~ + +Creates an array type, holding ``count`` elements, each of type ``elty`` +(which should be a ``Type``). + +``pointer(pty, addrspc=0)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Create a pointer to type ``pty`` (which should be a ``Type``). +``addrspc`` is an integer that represents the address space of the +pointer (see LLVM docs or ask on llvm-dev for more info). + +``void()`` +~~~~~~~~~~ + +Creates a void type. Used for function return types. + +``label()`` +~~~~~~~~~~~ + +Creates a label type. + +``opaque(name)`` +~~~~~~~~~~~~~~~~ + +Opaque `StructType `_, used for creating +self-referencing types. + +Properties +---------- + +``kind`` +~~~~~~~~ + +[read-only] + +A value (enum) representing the "type" of the object. It will be one of +the following constants defined in ``llvm.core``: + + +.. code-block:: python + + # Warning: do not rely on actual numerical + values! TYPE_VOID = 0 TYPE_FLOAT = 1 TYPE_DOUBLE = 2 TYPE_X86_FP80 + = 3 TYPE_FP128 = 4 TYPE_PPC_FP128 = 5 TYPE_LABEL = 6 TYPE_INTEGER = + 7 TYPE_FUNCTION = 8 TYPE_STRUCT = 9 TYPE_ARRAY = 10 TYPE_POINTER = + 11 TYPE_OPAQUE = 12 TYPE_VECTOR = 13 TYPE_METADATA = 14 TYPE_UNION = + 15 + + + +Example: +^^^^^^^^ + + +.. code-block:: python + + assert Type.int().kind == TYPE_INTEGER assert + Type.void().kind == TYPE_VOID diff --git a/docs/_build/html/_sources/doc/llvm.core.User.txt b/docs/_build/html/_sources/doc/llvm.core.User.txt new file mode 100644 index 0000000..0762729 --- /dev/null +++ b/docs/_build/html/_sources/doc/llvm.core.User.txt @@ -0,0 +1,39 @@ ++---------------------------+ +| layout: page | ++---------------------------+ +| title: User (llvm.core) | ++---------------------------+ + +``User``-s are values that refer to other values. The values so refered +can be retrived by the properties of ``User``. This is the reverse of +the ``Value.uses``. Together these can be used to traverse the use-def +chains of the SSA. + +-------------- + +llvm.core.User # {#user} +======================== + +Base Class +---------- + +- `llvm.core.Value `_ + +Properties +---------- + +``operands`` +~~~~~~~~~~~~ + +[read-only] + +The list of operands (values, of type +`llvm.core.Value `_) that this value refers to. + +``operand_count`` +~~~~~~~~~~~~~~~~~ + +[read-only] + +The number of operands that this value referes to. Same as +``len(uses.operands)`` but faster if you just want the count. diff --git a/docs/_build/html/_sources/doc/llvm.core.Value.txt b/docs/_build/html/_sources/doc/llvm.core.Value.txt new file mode 100644 index 0000000..fdff4cc --- /dev/null +++ b/docs/_build/html/_sources/doc/llvm.core.Value.txt @@ -0,0 +1,65 @@ ++----------------------------+ +| layout: page | ++----------------------------+ +| title: Value (llvm.core) | ++----------------------------+ + +llvm.core.Value +=============== + +- This will become a table of contents (this text will be scraped). + {:toc} + +Properties +---------- + +``name`` +~~~~~~~~ + +The name of the value. + +``type`` +~~~~~~~~ + +[read-only] + +An ``llvm.core.Type`` object representing the type of the value. + +``uses`` +~~~~~~~~ + +[read-only] + +The list of values (``llvm.core.Value``) that use this value. + +``use_count`` +~~~~~~~~~~~~~ + +[read-only] + +The number of values that use (refer) this value. Same as +``len(val.uses)`` but faster if you just want the count. + +``value_id`` +~~~~~~~~~~~~ + +[read-only] + +Returns ``llvmValuegetValueID()``. Refer LLVM documentation for more +info. + +Special Methods +--------------- + +``__str__`` +~~~~~~~~~~~ + +``Value`` objects can be stringified into it's LLVM assembly language +representation. + +``__eq__`` +~~~~~~~~~~ + +``Value`` objects can be compared for equality. Internally, this +converts both arguments into their LLVM assembly representations and +compares the resultant strings. diff --git a/docs/_build/html/_sources/doc/llvm.core.VectorType.txt b/docs/_build/html/_sources/doc/llvm.core.VectorType.txt new file mode 100644 index 0000000..19b98e6 --- /dev/null +++ b/docs/_build/html/_sources/doc/llvm.core.VectorType.txt @@ -0,0 +1,31 @@ ++---------------------------------+ +| layout: page | ++---------------------------------+ +| title: VectorType (llvm.core) | ++---------------------------------+ + +llvm.core.VectorType +==================== + +Base Class +---------- + +- `llvm.core.Type `_ + +Properties +---------- + +``element`` +~~~~~~~~~~~ + +[read-only] + +A `Type `_ object representing the type of the +element of the vector. + +``count`` +~~~~~~~~~ + +[read-only] + +The number of elements in the vector. diff --git a/docs/_build/html/_sources/doc/llvm.ee.EngineBuilder.txt b/docs/_build/html/_sources/doc/llvm.ee.EngineBuilder.txt new file mode 100644 index 0000000..e317acc --- /dev/null +++ b/docs/_build/html/_sources/doc/llvm.ee.EngineBuilder.txt @@ -0,0 +1,56 @@ ++----------------------------------+ +| layout: page | ++----------------------------------+ +| title: EngineBuilder (llvm.ee) | ++----------------------------------+ + +llvm.ee.EngineBuilder +===================== + +A convenient class for building +`llvm.ee.ExecutionEngine `_. Each +``EngineBuilder`` instance can only create one ``ExecutionEngine``. + +Methods +------- + +``create(self)`` +~~~~~~~~~~~~~~~~ + +Create and return a new +`ExecutionEngine `_ instance. + +Raise ``llvm.LLVMException`` if the builder cannot create an +``ExecutionEngine`` base on the given configuration. + +``force_interpreter(self)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Force the output the output ``ExecutionEngine`` to be an LLVM IR +interpreter. + +``force_jit(self)`` +~~~~~~~~~~~~~~~~~~~ + +Force the output the output ``ExecutionEngine`` to be a JIT engine. + +``opt(self, level)`` +~~~~~~~~~~~~~~~~~~~~ + +Set the code generation optimization level for a JIT engine. Valid value +of ``level`` is 0-3, inclusive. The default setting is 2. To use vector +instructions, such as SSE on Intel processors, ``level`` must be 3 +(aggressive). + +Static Factory Methods +---------------------- + +``new(module)`` +~~~~~~~~~~~~~~~ + +Create a new EngineBuilder. ``module`` must be a +`llvm.core.Module `_ instance. Its ownership is +transferred to the resulting +`ExecutionEngine `_. Therefore, it is +impossible to create more than one ``ExecutionEngine`` with a single +``EngineBuilder`` diff --git a/docs/_build/html/_sources/doc/llvm.ee.ExecutionEngine.txt b/docs/_build/html/_sources/doc/llvm.ee.ExecutionEngine.txt new file mode 100644 index 0000000..718358c --- /dev/null +++ b/docs/_build/html/_sources/doc/llvm.ee.ExecutionEngine.txt @@ -0,0 +1,62 @@ ++------------------------------------+ +| layout: page | ++------------------------------------+ +| title: ExecutionEngine (llvm.ee) | ++------------------------------------+ + +llvm.ee.ExecutionEngine +======================= + +Methods +------- + +``add_module(self, module)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Add a new module to the ExecutionEngine. The ownership is of ``module`` +is transferred. When the ``ExecutionEngine`` is destroyed, the module is +destroyed. + +``free_machine_code_for(self, fn)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Release memory used for the machine code generated for the function +``fn``. + +``get_pointer_to_function(self, fn)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Obtain the pointer to the function ``fn``. This forces the +ExecutionEngine to generate the machine code in lazy mode. + +If ``fn`` is not defined, ``ExecutionEngine`` will lookup the symbol +through ``dlsym``. + +The returned function pointer can be wrapped as a ``ctypes`` function. + +``remove_module(self, module)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Remove the ``module``. + +``run_function(self, fn, args)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Execute the function ``fn`` with an iterable of arguments ``args`` which +are of ``GenericValue``. This method returns whatever that is returned +by ``fn`` as a ``GenericValue``. + +``run_static_ctors(self)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +``run_static_dtors(self)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Properties +---------- + +``target_data`` +~~~~~~~~~~~~~~~ + +Access the `TargetData `_ instance associated +with the ``ExecutionEngine``. diff --git a/docs/_build/html/_sources/doc/llvm.ee.GenericValue.txt b/docs/_build/html/_sources/doc/llvm.ee.GenericValue.txt new file mode 100644 index 0000000..8680093 --- /dev/null +++ b/docs/_build/html/_sources/doc/llvm.ee.GenericValue.txt @@ -0,0 +1,64 @@ ++---------------------------------+ +| layout: page | ++---------------------------------+ +| title: GenericValue (llvm.ee) | ++---------------------------------+ + +llvm.ee.GenericValue +==================== + +- This will become a table of contents (this text will be scraped). + {:toc} + +Methods +------- + +``as_int(self)`` +~~~~~~~~~~~~~~~~ + +Return the value of this ``GenericValue`` instance as an unsigned +integer + +``as_int_signed(self)`` +~~~~~~~~~~~~~~~~~~~~~~~ + +Return the value of this ``GenericValue`` instance as a signed integer. + +``as_pointer(self)`` +~~~~~~~~~~~~~~~~~~~~ + +Return the value of this ``GenericValue`` instance as a pointer. The +type of the return value is ``int``. + +``as_real(self, ty)`` +~~~~~~~~~~~~~~~~~~~~~ + +Return the value of this ``GenericValue`` instance as a real number +which type is specified by ``ty``. ``ty`` must be a +`Type `_ instance of a real number type. + +Static Factory Methods +---------------------- + +``int(ty, intval)`` +~~~~~~~~~~~~~~~~~~~ + +Create a ``GenericValue`` instance with a ``int`` value, which is +zero-extended if necessary. The type of the value is specified by +``ty``, which is a `Type `_ instance. + +``int_signed(ty, intval)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Create a ``GenericValue`` instance with a ``int`` value, which is +sign-extended if necessary. The type of the value is specified by +``ty``, which is a `Type `_ instance. + +``pointer(ty, addr)`` or ``pointer(addr)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Create a ``GenericValue`` instance with a ``int`` value, which is +representing a pointer value. + +The two argument version is **deprecated**. The old code never used +``ty`` anyway. diff --git a/docs/_build/html/_sources/doc/llvm.ee.TargetData.txt b/docs/_build/html/_sources/doc/llvm.ee.TargetData.txt new file mode 100644 index 0000000..5a774b8 --- /dev/null +++ b/docs/_build/html/_sources/doc/llvm.ee.TargetData.txt @@ -0,0 +1,70 @@ ++-------------------------------+ +| layout: page | ++-------------------------------+ +| title: TargetData (llvm.ee) | ++-------------------------------+ + +llvm.ee.TargetData +================== + +- This will become a table of contents (this text will be scraped). + {:toc} + +Methods +------- + +``abi_alignment(self, ty)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Returns the minimum ABI-required alignment for the specified type +``ty``. + +``abi_size(self, ty)`` +~~~~~~~~~~~~~~~~~~~~~~ + +``callframe_alignment(self, ty)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Returns the minimum ABI-required alignment for the specified type ``ty`` +when it is part of a call frame. + +``element_at_offset(self, ty, ofs)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +``offset_of_element(self, ty, el)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +``preferred_alignment(self, ty_or_gv)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +``size(self, ty)`` +~~~~~~~~~~~~~~~~~~ + +``store_size(self, ty)`` +~~~~~~~~~~~~~~~~~~~~~~~~ + +``__str__(self)`` +~~~~~~~~~~~~~~~~~ + +Returns the string representation. + +Static Factory Methods +---------------------- + +``new(strrep)`` +~~~~~~~~~~~~~~~ + +Construct a new ``TargetData`` instance from the string representation + +Properties +---------- + +``byte_order`` +~~~~~~~~~~~~~~ + +``pointer_size`` +~~~~~~~~~~~~~~~~ + +``target_integer_type`` +~~~~~~~~~~~~~~~~~~~~~~~ + diff --git a/docs/_build/html/_sources/doc/llvm.passes.FunctionPassManager.txt b/docs/_build/html/_sources/doc/llvm.passes.FunctionPassManager.txt new file mode 100644 index 0000000..137cf74 --- /dev/null +++ b/docs/_build/html/_sources/doc/llvm.passes.FunctionPassManager.txt @@ -0,0 +1,42 @@ ++--------------------------------------------+ +| layout: page | ++--------------------------------------------+ +| title: FunctionPassManager (llvm.passes) | ++--------------------------------------------+ + +llvm.passes.FunctionPassManager +=============================== + +Base Classes +------------ + +- `llvm.passes.PassManager `_ + +Methods +------- + +``finalize(self)`` +~~~~~~~~~~~~~~~~~~ + +Finalizes all associated function passes in the LLVM system. + +Beware that this destroys all associated passes even if another pass +manager is using those passes. This may result is a segfault. + +``initialize(self)`` +~~~~~~~~~~~~~~~~~~~~ + +Initializes all associated function passes in the LLVM system. + +``run(self, fn)`` +~~~~~~~~~~~~~~~~~ + +Run all passes on the given function ``fn``. + +Static Factory Methods +---------------------- + +``new(module)`` +~~~~~~~~~~~~~~~ + +Create a ``FunctionPassManager`` instance for a given ``module``. diff --git a/docs/_build/html/_sources/doc/llvm.passes.PassManager.txt b/docs/_build/html/_sources/doc/llvm.passes.PassManager.txt new file mode 100644 index 0000000..e0a2536 --- /dev/null +++ b/docs/_build/html/_sources/doc/llvm.passes.PassManager.txt @@ -0,0 +1,29 @@ ++------------------------------------+ +| layout: page | ++------------------------------------+ +| title: PassManager (llvm.passes) | ++------------------------------------+ + +llvm.passes.PassManager +======================= + +Methods +------- + +``add(self, tgt_data_or_pass_id)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Add a pass by its ID. A pass IDs are defined as ``PASS_*``. + +``run(self, module)`` +~~~~~~~~~~~~~~~~~~~~~ + +Run all passes on the given ``module``. + +Static Factory Methods +---------------------- + +``new()`` +~~~~~~~~~ + +Creates a new ``PassManager`` instance. diff --git a/docs/_build/html/_sources/doc/llvm.passes.PassManagerBuilder.txt b/docs/_build/html/_sources/doc/llvm.passes.PassManagerBuilder.txt new file mode 100644 index 0000000..99e1935 --- /dev/null +++ b/docs/_build/html/_sources/doc/llvm.passes.PassManagerBuilder.txt @@ -0,0 +1,72 @@ ++-------------------------------------------+ +| layout: page | ++-------------------------------------------+ +| title: PassManagerBuilder (llvm.passes) | ++-------------------------------------------+ + +llvm.passes.PassManagerBuilder +============================== + +Provide a simple API to populate pass managers for language like C/C++. +Refer to `LLVM API +Documentation `_ +for detail. + +Methods +------- + +``populate(self, pm)`` +~~~~~~~~~~~~~~~~~~~~~~ + +Populate a `FunctionPassManager `_ +or `PassManager `_ given as ``pm``. + +``use_inliner_with_threshold(self, threshold)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Use an inliner pass with the given ``threshold``. + +Properties +---------- + +The following properties can be overriden to customize how pass managers +are populated. + +``disable_simplify_lib_calls`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Boolean. Default is ``False``. + +``disable_unit_at_a_time`` +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Boolean. Default is ``False``. + +``disable_unroll_loops`` +~~~~~~~~~~~~~~~~~~~~~~~~ + +Boolean. Default is ``False``. + +``opt_level`` +~~~~~~~~~~~~~ + +Default is ``2``. Valid values are 0-3. Corresponds to O0, O1, O2, O3 as +in C/C++ optimization options. + +``size_level`` +~~~~~~~~~~~~~~ + +Default is ``0``. + +``vectorize`` +~~~~~~~~~~~~~ + +Default is ``False``. + +Static Factory Methods +---------------------- + +``new()`` +~~~~~~~~~ + +Creates a new ``PassManagerBuilder`` instance. diff --git a/docs/_build/html/_sources/doc/llvm_concepts.txt b/docs/_build/html/_sources/doc/llvm_concepts.txt new file mode 100644 index 0000000..c5f74aa --- /dev/null +++ b/docs/_build/html/_sources/doc/llvm_concepts.txt @@ -0,0 +1,236 @@ +******************** +LLVM Concepts +******************** + +This section explains a few concepts related to LLVM, not specific to +llvmpy. + +.. toctree:: + :hidden: + + + + +Intermediate Representation +=========================== + +The intermediate representation, or IR for short, is an in-memory data +structure that represents executable code. The IR data structures allow +for creation of types, constants, functions, function arguments, +instructions, global variables and so on. For example, to create a +function *sum* that takes two integers and returns their sum, we need to +follow these steps: + +- create an integer type *ti* of required bitwidth +- create a function type *tf* which takes two *ti* -s and returns + another *ti* +- create a function of type *tf* named *sum* +- add a *basic block* to the function +- using a helper object called an *instruction builder*, add two + instructions into the basic block: . an instruction to add the two + arguments and store the result into a temporary variable . a return + instruction to return the value of the temporary variable + +(A basic block is a block of instructions.) + +LLVM has it's own instruction set; the instructions used above (*add* +and *ret*) are from this set. The LLVM instructions are at a higher +level than the usual assembly language; for example there are +instructions related to variable argument handling, exception handling, +and garbage collection. These allow high-level languages to be +represented cleanly in the IR. + + +SSA Form and PHI Nodes +====================== + +All LLVM instructions are represented in the *Static Single Assignment* +(SSA) form. Essentially, this means that any variable can be assigned to +only once. Such a representation facilitates better optimization, among +other benefits. + +A consequence of single assignment are PHI (Φ) nodes. These are required +when a variable can be assigned a different value based on the path of +control flow. For example, the value of *b* at the end of execution of +the snippet below: + +.. code-block:: c + + a = 1; + if (v < 10) + a = 2; + b = a; + +cannot be determined statically. The value of '2' cannot be assigned to +the 'original' *a*, since *a* can be assigned to only once. There are +two *a* 's in there, and the last assignment has to choose between which +version to pick. This is accomplished by adding a PHI node: + +.. code-block:: c + + a1 = 1; + if (v < 10) + a2 = 2; + b = PHI(a1, a2); + +The PHI node selects *a1* or *a2*, depending on where the control +reached the PHI node. The argument *a1* of the PHI node is associated +with the block *"a1 = 1;"* and *a2* with the block *"a2 = 2;"*. + +PHI nodes have to be explicitly created in the LLVM IR. Accordingly the +LLVM instruction set has an instruction called *phi*. + + +LLVM Assembly Language +====================== + +The LLVM IR can be represented offline in two formats + +- a textual, human-readable form, similar to assembly language, called + the LLVM assembly language (files with .ll extension) +- a binary form, called the LLVM bitcode (files with .bc extension) + +All three formats (the in-memory IR, the LLVM assembly language and the +LLVM bitcode) represent the *same* information. Each format can be +converted into the other two formats (using LLVM APIs). + +The `LLVM demo page `_ lets you type in C or +C++ code, converts it into LLVM IR and outputs the IR as LLVM assembly +language code. + +Just to get a feel of the LLVM assembly language, here's a function in +C, and the corresponding LLVM assembly (as generated by the demo page): + +.. code-block:: c + + /* compute sum of 1..n */ + unsigned sum(unsigned n) { + if (n == 0) + return 0; + else + return n + sum(n-1); + } + +The corresponding LLVM assembly: + +.. code-block:: llvm + + ; ModuleID = '/tmp/webcompile/_7149_0.bc' + target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64" + target triple = "x86_64-linux-gnu" + + define i32 @sum(i32 %n) nounwind readnone { + entry: + %0 = icmp eq i32 %n, 0 ; [#uses=1] + br i1 %0, label %bb2, label %bb1 + + bb1: ; preds = %entry + %1 = add i32 %n, -1 ; [#uses=2] + %2 = icmp eq i32 %1, 0 ; [#uses=1] + br i1 %2, label %sum.exit, label %bb1.i + + bb1.i: ; preds = %bb1 + %3 = add i32 %n, -2 ; [#uses=1] + %4 = tail call i32 @sum(i32 %3) nounwind ; [#uses=1] + %5 = add i32 %4, %1 ; [#uses=1] + br label %sum.exit + + sum.exit: ; preds = %bb1.i, %bb1 + %6 = phi i32 [ %5, %bb1.i ], [ 0, %bb1 ] ; [#uses=1] + %7 = add i32 %6, %n ; [#uses=1] + ret i32 %7 + + bb2: ; preds = %entry + ret i32 0 + } + +Note the usage of SSA form. The long string called ``target datalayout`` +is a specification of the platform ABI (like endianness, sizes of types, +alignment etc.). + +The `LLVM Language Reference `_ +defines the LLVM assembly language including the entire instruction set. + + +Modules +======= + +`Modules <./llvm.core.Module.html>`_, in the LLVM IR, are similar to a +single *C* language source file (.c file). A module contains: + +- functions (declarations and definitions) +- global variables and constants +- global type aliases for structures + +Modules are top-level containers; all executable code representation is +contained within modules. Modules may be combined (linked) together to +give a bigger resultant module. During this process LLVM attempts to +reconcile the references between the combined modules. + + +Optimization and Passes +======================= + +LLVM provides quite a few optimization algorithms that work on the IR. +These algorithms are organized as *passes*. Each pass does something +specific, like combining redundant instructions. Passes need not always +optimize the IR, it can also do other operations like inserting +instrumentation code, or analyzing the IR (the result of which can be +used by passes that do optimizations) or even printing call graphs. + +This LLVM `documentation page `_ +describes all the available passes, and what they do. + +LLVM does not automatically choose to run any passes, anytime. Passes +have to be explicitly selected and run on each module. This gives you +the flexibility to choose transformations and optimizations that are +most suitable for the code in the module. + +There is an LLVM binary called +`opt `_, which lets you run passes on +bitcode files from the command line. You can write your own passes (in +C/C++, as a shared library). This can be loaded and executed by +opt+. +(Although llvmpy does not allow you to write your own passes, it does +allow you to navigate the entire IR at any stage, and perform any +transforms on it as you like.) + +A "pass manager" is responsible for loading passes, selecting the +correct objects to run them on (for example, a pass may work only on +functions, individually) and actually runs them. ``opt`` is a +command-line wrapper for the pass manager. + +LLVM defines two kinds of pass managers: + +- The + `FunctionPassManager `_ + manages function or basic-block passes. These lighter weight passes + can be used immediately after each generated function to reduce + memory footprint. + +- The + `PassManager `_ + manages module passes for optimizing the entire module. + + +Bitcode +======= + +LLVM IR can be represented as a bitcode format for disk storage. It is +`suitable for fast loading by JIT +compiler `_. See `LLVM +documentation `_ for detail +about the bitcode format. + + +Execution Engine, JIT and Interpreter +===================================== + +The *execution engine* implements execution of LLVM IR through an +interpreter or a JIT dynamic compiler. An *execution engine* can contain +multiple modules. + + **Note** + + Inter-module reference is not possible. That is module ``A`` cannot + call a function in module ``B``, directly. + diff --git a/docs/_build/html/_sources/doc/llvmpy_package.txt b/docs/_build/html/_sources/doc/llvmpy_package.txt new file mode 100644 index 0000000..eac3814 --- /dev/null +++ b/docs/_build/html/_sources/doc/llvmpy_package.txt @@ -0,0 +1,89 @@ +*********************** +The llvmpy Package +*********************** + +The llvmpy is a Python package, consisting of 6 modules, that wrap over +enough LLVM APIs to allow the implementation of your own compiler/VM +backend in pure Python. If you're come this far, you probably know why +this is a good idea. + +Out of the 6 modules, one is an "extension" module (i.e., it is written +in C), and another one is a small private utility module, which leaves 4 +public modules. These are: + +- *llvm* -- top-level package, common classes (like exceptions) +- *llvm.core* -- IR-related APIs +- *llvm.ee* -- execution engine related APIs +- *llvm.passes* -- pass manager and passes related APIs + +The modules contain only classes and (integer) constants. Mostly simple +Python constructs are used (deliberately) -- +`property() `_ and +`property +decorators `_ are +probably the most exotic animals around. All classes are "new style" +classes. The APIs are designed to be navigable (and guessable!) once you +know a few conventions. These conventions are highlighted in the +sections below. + +Here is a quick overview of the contents of each package: + +llvm +---- + +- LLVMException -- exception class (currently the only one) + +llvm.core +--------- + +- `Module `_ -- represents an LLVM Module +- `Type `_ -- represents an LLVM Type +- `Value `_ -- represents an LLVM Value, including: + globals, constants, variables, arguments, functions, instructions, + etc.. +- `BasicBlock `_ -- another derived of + Value, represents an LLVM basic block +- `Builder `_ -- used for creating + instructions, wraps LLVM IRBuilder helper class +- constants *TYPE\_\** that represents various types +- constants *CC\_\** that represent calling conventions +- constants *ICMP\_\** and *FCMP\_\** that represent integer and real + comparison predicates (like less than, greater than etc.) +- constants *LINKAGE\_\** that represent linkage of symbols (external, + internal etc.) +- constants *VISIBILITY\_\** that represents visibility of symbols + (default, hidden, protected) +- constants *ATTR\_\** that represent function parameter attributes + +llvm.ee +------- + +- `ExecutionEngine `_ -- represents an + execution engine (which can be an either an interpreter or a JIT) +- `TargetData `_ -- represents the ABI of the + target platform (details like sizes and alignment of primitive types, + endinanness etc) + +llvm.passes +----------- + +- `PassManager `_ -- represents an LLVM + pass manager +- `FunctionPassManager `_ -- + represents an LLVM function pass manager +- constants *PASS\_\** that represent various passes + +A note on the importing of these modules +---------------------------------------- + +Pythonically, modules are imported with the statement +``import llvm.core``. However, you might find it more convenient to +import llvmpy modules thus: + + +.. code-block:: python + + from llvm import * + from llvm.core import * + from llvm.ee import * + from llvm.passes import * diff --git a/docs/_build/html/_sources/doc/types.txt b/docs/_build/html/_sources/doc/types.txt new file mode 100644 index 0000000..f3b9da2 --- /dev/null +++ b/docs/_build/html/_sources/doc/types.txt @@ -0,0 +1,123 @@ ++----------------+ +| layout: page | ++----------------+ +| title: Types | ++----------------+ + +Types are what you think they are. A instance of +`llvm.core.Type `_, or one of its derived classes, +represent a type. llvmpy does not use as many classes to represent +types as does LLVM itself. Some types are represented using +`llvm.core.Type `_ itself and the rest are +represented using derived classes of +`llvm.core.Type `_. As usual, an instance is +created via one of the static methods of `Type `_. +These methods return an instance of either +`llvm.core.Type `_ itself or one of its derived +classes. + +The following table lists all the available types along with the static +method which has to be used to construct it and the name of the class +whose object is actually returned by the static method. + +Name \| Constructor Method \| Class \| +-----\|:------------------:\|:-----:\| integer of bitwidth *n* \| +Type.int(n) \| `IntegerType `_ \| 32-bit +float \| Type.float() \| `Type `_ \| 64-bit double +\| Type.double() \| `Type `_ \| 80-bit float \| +Type.x86\_fp80() \| `Type `_ \| 128-bit float +(112-bit mantissa) \| Type.fp128() \| `Type `_ \| +128-bit float (two 64-bits) \| Type.ppc\_fp128() \| +`Type `_ \| function \| Type.function(r, p, v) \| +`FunctionType `_ \| unpacked struct \| +Type.struct(eltys, name) \| `StructType `_ \| +packed struct \| Type.packed\_struct(eltys, name) \| +`StructType `_ \| opaque struct \| +Type.opaque(name) \| `StructType `_ \| array +\| Type.array(elty, count) \| `ArrayType `_ \| +pointer to value of type *pty* \| Type.pointer(pty, addrspc) \| +`PointerType `_ \| vector \| +Type.vector(elty, count) \| `VectorType `_ \| +void \| Type.void() \| `Type `_ \| label \| +Type.label() \| `Type `_ \| + +The class hierarchy is: + +:: + + Type + IntegerType + FunctionType + StructType + ArrayType + PointerType + VectorType + +-------------- + +An Example +---------- + +Here is an example that demonstrates the creation of types: + + +.. code-block:: python + + #!/usr/bin/env python + + # integers + int_ty = Type.int() bool_ty = Type.int(1) int_64bit = Type.int(64) + + # floats + sprec_real = Type.float() dprec_real = Type.double() + + # arrays and vectors + intar_ty = Type.array( int_ty, 10 ) # "typedef int intar_ty[10];" + twodim = Type.array( intar_ty , 10 ) # "typedef int twodim[10][10];" + vec = Type.array( int_ty, 10 ) + + # structures + s1_ty = Type.struct( [ int_ty, sprec_real ] ) # "struct s1_ty { int + v1; float v2; };" + + # pointers + intptr_ty = Type.pointer(int_ty) # "typedef int \*intptr_ty;" + + # functions + f1 = Type.function( int_ty, [ int_ty ] ) # functions that take 1 + int_ty and return 1 int_ty + + f2 = Type.function( Type.void(), [ int_ty, int_ty ] ) # functions that + take 2 int_tys and return nothing + + f3 = Type.function( Type.void(), ( int_ty, int_ty ) ) # same as f2; + any iterable can be used + + fnargs = [ Type.pointer( Type.int(8) ) ] printf = Type.function( + Type.int(), fnargs, True ) # variadic function + + + +-------------- + +Another Example: Recursive Type +------------------------------- + +The type system was rewritten in LLVM 3.0. The old opaque type was +removed. Instead, identified ``StructType`` can now be defined without a +body. Doing so creates a opaque structure. One can then set the body +after the construction of a structure. + +(See `LLVM +Blog `_ +for detail about the new type system.) + +The following code defines a opaque structure, named "mystruct". The +body is defined after the construction using ``StructType.set_body``. +The second subtype is a pointer to a "mystruct" type. + + +.. code-block:: python + + ts = Type.opaque('mystruct') + ts.set_body([Type.int(), Type.pointer(ts)]) diff --git a/docs/_build/html/_sources/doc/userguide.txt b/docs/_build/html/_sources/doc/userguide.txt new file mode 100644 index 0000000..1bb4b4f --- /dev/null +++ b/docs/_build/html/_sources/doc/userguide.txt @@ -0,0 +1,17 @@ +************ +User Guide +************ + +llvmpy provides Python bindings for LLVM. This document explains how +you can setup and use it. A working knowledge of Python and a basic idea +of LLVM is assumed. + +.. toctree:: + :maxdepth: 1 + + getting_started.rst + llvm_concepts.rst + llvmpy_package.rst + + + diff --git a/docs/_build/html/_sources/doc/values.txt b/docs/_build/html/_sources/doc/values.txt new file mode 100644 index 0000000..a999740 --- /dev/null +++ b/docs/_build/html/_sources/doc/values.txt @@ -0,0 +1,78 @@ ++-----------------+ +| layout: page | ++-----------------+ +| title: Values | ++-----------------+ + +`llvm.core.Value `_ is the base class of all +values computed by a program that may be used as operands to other +values. A value has a type associated with it (an object of +`llvm.core.Type `_). + +The class hierarchy is: + +:: + + Value + User + Constant + ConstantExpr + ConstantAggregateZero + ConstantInt + ConstantFP + ConstantArray + ConstantStruct + ConstantVector + ConstantPointerNull + UndefValue + GlobalValue + GlobalVariable + Function + Instruction + CallOrInvokeInstruction + PHINode + SwitchInstruction + CompareInstruction + Argument + BasicBlock + +The `Value `_ class is abstract, it's not meant to +be instantiated. `User `_ is a +`Value `_ that in turn uses (i.e., can refer to) +other values (for e.g., a constant expression 1+2 refers to two constant +values 1 and 2). + +`Constant `_-s represent constants that appear +within code or as initializers of globals. They are constructed using +static methods of `Constant `_. Various types +of constants are represented by various subclasses of +`Constant `_. However, most of them are empty +and do not provide any additional attributes or methods over +`Constant `_. + +The `Function `_ object represents an instance of a +function type. Such objects contain +`Argument `_ objects, which represent the +actual, local-variable-like arguments of the function (not to be +confused with the arguments returned by a function *type* object -- +these represent the *type* of the arguments). + +The various `Instruction `_-s are created by +the `Builder `_ class. Most instructions are +represented by `Instruction `_ itself, but +there are a few subclasses that represent interesting instructions. + +`Value `_ objects have a type (read-only), and a +name (read-write). + +**Related Links** `functions `_, +`comparision `_, +`llvm.core.Value `_, +`llvm.core.User `_, +`llvm.core.Constant `_, +`llvm.core.GlobalValue `_, +`llvm.core.GlobalVariable `_, +`llvm.core.Argument `_, +`llvm.core.Instruction `_, +`llvm.core.Builder `_, +`llvm.core.BasicBlock `_ diff --git a/docs/_build/html/_sources/index.txt b/docs/_build/html/_sources/index.txt new file mode 100644 index 0000000..fbca2ec --- /dev/null +++ b/docs/_build/html/_sources/index.txt @@ -0,0 +1,25 @@ +.. llvmpy documentation master file, created by + sphinx-quickstart on Wed Aug 8 17:33:58 2012. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Documentation for llvmpy +================= + +Contents: + +.. toctree:: + :titlesonly: + :maxdepth: 2 + + doc/userguide.rst + doc/examples.rst + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` + diff --git a/docs/_build/html/_static/ajax-loader.gif b/docs/_build/html/_static/ajax-loader.gif new file mode 100644 index 0000000000000000000000000000000000000000..61faf8cab23993bd3e1560bff0668bd628642330 GIT binary patch literal 673 zcmZ?wbhEHb6krfw_{6~Q|Nno%(3)e{?)x>&1u}A`t?OF7Z|1gRivOgXi&7IyQd1Pl zGfOfQ60;I3a`F>X^fL3(@);C=vM_KlFfb_o=k{|A33hf2a5d61U}gjg=>Rd%XaNQW zW@Cw{|b%Y*pl8F?4B9 zlo4Fz*0kZGJabY|>}Okf0}CCg{u4`zEPY^pV?j2@h+|igy0+Kz6p;@SpM4s6)XEMg z#3Y4GX>Hjlml5ftdH$4x0JGdn8~MX(U~_^d!Hi)=HU{V%g+mi8#UGbE-*ao8f#h+S z2a0-5+vc7MU$e-NhmBjLIC1v|)9+Im8x1yacJ7{^tLX(ZhYi^rpmXm0`@ku9b53aN zEXH@Y3JaztblgpxbJt{AtE1ad1Ca>{v$rwwvK(>{m~Gf_=-Ro7Fk{#;i~+{{>QtvI yb2P8Zac~?~=sRA>$6{!(^3;ZP0TPFR(G_-UDU(8Jl0?(IXu$~#4A!880|o%~Al1tN literal 0 HcmV?d00001 diff --git a/docs/_build/html/_static/basic.css b/docs/_build/html/_static/basic.css new file mode 100644 index 0000000..f0379f3 --- /dev/null +++ b/docs/_build/html/_static/basic.css @@ -0,0 +1,540 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar input[type="text"] { + width: 170px; +} + +div.sphinxsidebar input[type="submit"] { + width: 30px; +} + +img { + border: 0; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li div.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable dl, table.indextable dd { + margin-top: 0; + margin-bottom: 0; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- general body styles --------------------------------------------------- */ + +a.headerlink { + visibility: hidden; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.field-list ul { + padding-left: 1em; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px 7px 0 7px; + background-color: #ffe; + width: 40%; + float: right; +} + +p.sidebar-title { + font-weight: bold; +} + +/* -- topics ---------------------------------------------------------------- */ + +div.topic { + border: 1px solid #ccc; + padding: 7px 7px 0 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +div.admonition dl { + margin-bottom: 0; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + border: 0; + border-collapse: collapse; +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +table.field-list td, table.field-list th { + border: 0 !important; +} + +table.footnote td, table.footnote th { + border: 0 !important; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +dl { + margin-bottom: 15px; +} + +dd p { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +dt:target, .highlighted { + background-color: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.refcount { + color: #060; +} + +.optional { + font-size: 1.3em; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +td.linenos pre { + padding: 5px 0px; + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + margin-left: 0.5em; +} + +table.highlighttable td { + padding: 0 0.5em 0 0.5em; +} + +tt.descname { + background-color: transparent; + font-weight: bold; + font-size: 1.2em; +} + +tt.descclassname { + background-color: transparent; +} + +tt.xref, a tt { + background-color: transparent; + font-weight: bold; +} + +h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/docs/_build/html/_static/comment-bright.png b/docs/_build/html/_static/comment-bright.png new file mode 100644 index 0000000000000000000000000000000000000000..551517b8c83b76f734ff791f847829a760ad1903 GIT binary patch literal 3500 zcmV;d4O8-oP)Oz@Z0f2-7z;ux~O9+4z06=<WDR*FRcSTFz- zW=q650N5=6FiBTtNC2?60Km==3$g$R3;-}uh=nNt1bYBr$Ri_o0EC$U6h`t_Jn<{8 z5a%iY0C<_QJh>z}MS)ugEpZ1|S1ukX&Pf+56gFW3VVXcL!g-k)GJ!M?;PcD?0HBc- z5#WRK{dmp}uFlRjj{U%*%WZ25jX z{P*?XzTzZ-GF^d31o+^>%=Ap99M6&ogks$0k4OBs3;+Bb(;~!4V!2o<6ys46agIcq zjPo+3B8fthDa9qy|77CdEc*jK-!%ZRYCZvbku9iQV*~a}ClFY4z~c7+0P?$U!PF=S z1Au6Q;m>#f??3%Vpd|o+W=WE9003S@Bra6Svp>fO002awfhw>;8}z{#EWidF!3EsG z3;bXU&9EIRU@z1_9W=mEXoiz;4lcq~xDGvV5BgyU zp1~-*fe8db$Osc*A=-!mVv1NJjtCc-h4>-CNCXm#Bp}I%6j35eku^v$Qi@a{RY)E3 zJ#qp$hg?Rwkvqr$GJ^buyhkyVfwECO)C{#lxu`c9ghrwZ&}4KmnvWKso6vH!8a<3Q zq36)6Xb;+tK10Vaz~~qUGsJ8#F2=(`u{bOVlVi)VBCHIn#u~6ztOL7=^<&SmcLWlF zMZgI*1b0FpVIDz9SWH+>*hr`#93(Um+6gxa1B6k+CnA%mOSC4s5&6UzVlpv@SV$}* z))J2sFA#f(L&P^E5{W}HC%KRUNwK6<(h|}}(r!{C=`5+6G)NjFlgZj-YqAG9lq?`C z$c5yc>d>VnA`E_*3F2Qp##d8RZb=H01_mm@+|Cqnc9PsG(F5HIG_C zt)aG3uTh7n6Et<2In9F>NlT@zqLtGcXcuVrX|L#Xx)I%#9!{6gSJKPrN9dR61N3(c z4Tcqi$B1Vr8Jidf7-t!G7_XR2rWwr)$3XQ?}=hpK0&Z&W{| zep&sA23f;Q!%st`QJ}G3cbou<7-yIK2z4nfCCCtN2-XOGSWo##{8Q{ATurxr~;I`ytDs%xbip}RzP zziy}Qn4Z2~fSycmr`~zJ=lUFdFa1>gZThG6M+{g7vkW8#+YHVaJjFF}Z#*3@$J_By zLtVo_L#1JrVVB{Ak-5=4qt!-@Mh}c>#$4kh<88)m#-k<%CLtzEP3leVno>={htGUuD;o7bD)w_sX$S}eAxwzy?UvgBH(S?;#HZiQMoS*2K2 zT3xe7t(~nU*1N5{rxB;QPLocnp4Ml>u<^FZwyC!nu;thW+pe~4wtZn|Vi#w(#jeBd zlf9FDx_yoPJqHbk*$%56S{;6Kv~mM9!g3B(KJ}#RZ#@)!hR|78Dq|Iq-afF%KE1Brn_fm;Im z_u$xr8UFki1L{Ox>G0o)(&RAZ;=|I=wN2l97;cLaHH6leTB-XXa*h%dBOEvi`+x zi?=Txl?TadvyiL>SuF~-LZ;|cS}4~l2eM~nS7yJ>iOM;atDY;(?aZ^v+mJV$@1Ote z62cPUlD4IWOIIx&SmwQ~YB{nzae3Pc;}r!fhE@iwJh+OsDs9zItL;~pu715HdQEGA zUct(O!LkCy1<%NCg+}G`0PgpNm-?d@-hMgNe6^V+j6x$b<6@S<$+<4_1hi}Ti zncS4LsjI}fWY1>OX6feMEuLErma3QLmkw?X+1j)X-&VBk_4Y;EFPF_I+q;9dL%E~B zJh;4Nr^(LEJ3myURP{Rblsw%57T)g973R8o)DE9*xN#~;4_o$q%o z4K@u`jhx2fBXC4{U8Qn{*%*B$Ge=nny$HAYq{=vy|sI0 z_vss+H_qMky?OB#|JK!>IX&II^LlUh#rO5!7TtbwC;iULyV-Xq?ybB}ykGP{?LpZ? z-G|jbTmIbG@7#ZCz;~eY(cDM(28Dyq{*m>M4?_iynUBkc4TkHUI6gT!;y-fz>HMcd z&t%Ugo)`Y2{>!cx7B7DI)$7;J(U{Spm-3gBzioV_{p!H$8L!*M!p0uH$#^p{Ui4P` z?ZJ24cOCDe-w#jZd?0@)|7iKK^;6KN`;!@ylm7$*nDhK&GcDTy000JJOGiWi{{a60 z|De66lK=n!32;bRa{vGf6951U69E94oEQKA00(qQO+^RV2niQ93PPz|JOBU!-bqA3 zR5;6pl1pe^WfX zkSdl!omi0~*ntl;2q{jA^;J@WT8O!=A(Gck8fa>hn{#u{`Tyg)!KXI6l>4dj==iVKK6+%4zaRizy(5eryC3d2 z+5Y_D$4}k5v2=Siw{=O)SWY2HJwR3xX1*M*9G^XQ*TCNXF$Vj(kbMJXK0DaS_Sa^1 z?CEa!cFWDhcwxy%a?i@DN|G6-M#uuWU>lss@I>;$xmQ|`u3f;MQ|pYuHxxvMeq4TW;>|7Z2*AsqT=`-1O~nTm6O&pNEK?^cf9CX= zkq5|qAoE7un3V z^yy=@%6zqN^x`#qW+;e7j>th{6GV}sf*}g7{(R#T)yg-AZh0C&U;WA`AL$qz8()5^ zGFi2`g&L7!c?x+A2oOaG0c*Bg&YZt8cJ{jq_W{uTdA-<;`@iP$$=$H?gYIYc_q^*$ z#k(Key`d40R3?+GmgK8hHJcwiQ~r4By@w9*PuzR>x3#(F?YW_W5pPc(t(@-Y{psOt zz2!UE_5S)bLF)Oz@Z0f2-7z;ux~O9+4z06=<WDR*FRcSTFz- zW=q650N5=6FiBTtNC2?60Km==3$g$R3;-}uh=nNt1bYBr$Ri_o0EC$U6h`t_Jn<{8 z5a%iY0C<_QJh>z}MS)ugEpZ1|S1ukX&Pf+56gFW3VVXcL!g-k)GJ!M?;PcD?0HBc- z5#WRK{dmp}uFlRjj{U%*%WZ25jX z{P*?XzTzZ-GF^d31o+^>%=Ap99M6&ogks$0k4OBs3;+Bb(;~!4V!2o<6ys46agIcq zjPo+3B8fthDa9qy|77CdEc*jK-!%ZRYCZvbku9iQV*~a}ClFY4z~c7+0P?$U!PF=S z1Au6Q;m>#f??3%Vpd|o+W=WE9003S@Bra6Svp>fO002awfhw>;8}z{#EWidF!3EsG z3;bXU&9EIRU@z1_9W=mEXoiz;4lcq~xDGvV5BgyU zp1~-*fe8db$Osc*A=-!mVv1NJjtCc-h4>-CNCXm#Bp}I%6j35eku^v$Qi@a{RY)E3 zJ#qp$hg?Rwkvqr$GJ^buyhkyVfwECO)C{#lxu`c9ghrwZ&}4KmnvWKso6vH!8a<3Q zq36)6Xb;+tK10Vaz~~qUGsJ8#F2=(`u{bOVlVi)VBCHIn#u~6ztOL7=^<&SmcLWlF zMZgI*1b0FpVIDz9SWH+>*hr`#93(Um+6gxa1B6k+CnA%mOSC4s5&6UzVlpv@SV$}* z))J2sFA#f(L&P^E5{W}HC%KRUNwK6<(h|}}(r!{C=`5+6G)NjFlgZj-YqAG9lq?`C z$c5yc>d>VnA`E_*3F2Qp##d8RZb=H01_mm@+|Cqnc9PsG(F5HIG_C zt)aG3uTh7n6Et<2In9F>NlT@zqLtGcXcuVrX|L#Xx)I%#9!{6gSJKPrN9dR61N3(c z4Tcqi$B1Vr8Jidf7-t!G7_XR2rWwr)$3XQ?}=hpK0&Z&W{| zep&sA23f;Q!%st`QJ}G3cbou<7-yIK2z4nfCCCtN2-XOGSWo##{8Q{ATurxr~;I`ytDs%xbip}RzP zziy}Qn4Z2~fSycmr`~zJ=lUFdFa1>gZThG6M+{g7vkW8#+YHVaJjFF}Z#*3@$J_By zLtVo_L#1JrVVB{Ak-5=4qt!-@Mh}c>#$4kh<88)m#-k<%CLtzEP3leVno>={htGUuD;o7bD)w_sX$S}eAxwzy?UvgBH(S?;#HZiQMoS*2K2 zT3xe7t(~nU*1N5{rxB;QPLocnp4Ml>u<^FZwyC!nu;thW+pe~4wtZn|Vi#w(#jeBd zlf9FDx_yoPJqHbk*$%56S{;6Kv~mM9!g3B(KJ}#RZ#@)!hR|78Dq|Iq-afF%KE1Brn_fm;Im z_u$xr8UFki1L{Ox>G0o)(&RAZ;=|I=wN2l97;cLaHH6leTB-XXa*h%dBOEvi`+x zi?=Txl?TadvyiL>SuF~-LZ;|cS}4~l2eM~nS7yJ>iOM;atDY;(?aZ^v+mJV$@1Ote z62cPUlD4IWOIIx&SmwQ~YB{nzae3Pc;}r!fhE@iwJh+OsDs9zItL;~pu715HdQEGA zUct(O!LkCy1<%NCg+}G`0PgpNm-?d@-hMgNe6^V+j6x$b<6@S<$+<4_1hi}Ti zncS4LsjI}fWY1>OX6feMEuLErma3QLmkw?X+1j)X-&VBk_4Y;EFPF_I+q;9dL%E~B zJh;4Nr^(LEJ3myURP{Rblsw%57T)g973R8o)DE9*xN#~;4_o$q%o z4K@u`jhx2fBXC4{U8Qn{*%*B$Ge=nny$HAYq{=vy|sI0 z_vss+H_qMky?OB#|JK!>IX&II^LlUh#rO5!7TtbwC;iULyV-Xq?ybB}ykGP{?LpZ? z-G|jbTmIbG@7#ZCz;~eY(cDM(28Dyq{*m>M4?_iynUBkc4TkHUI6gT!;y-fz>HMcd z&t%Ugo)`Y2{>!cx7B7DI)$7;J(U{Spm-3gBzioV_{p!H$8L!*M!p0uH$#^p{Ui4P` z?ZJ24cOCDe-w#jZd?0@)|7iKK^;6KN`;!@ylm7$*nDhK&GcDTy000JJOGiWi{{a60 z|De66lK=n!32;bRa{vGf6951U69E94oEQKA00(qQO+^RV2oe()A>y0J-2easEJ;K` zR5;6Jl3z%jbr{D#&+mQTbB>-f&3W<<%ayjKi&ZjBc2N<@)`~{dMXWB0(ajbV85_gJ zf(EU`iek}4Bt%55ix|sVMm1u8KvB#hnmU~_r<Ogd(A5vg_omvd-#L!=(BMVklxVqhdT zofSj`QA^|)G*lu58>#vhvA)%0Or&dIsb%b)st*LV8`ANnOipDbh%_*c7`d6# z21*z~Xd?ovgf>zq(o0?Et~9ti+pljZC~#_KvJhA>u91WRaq|uqBBKP6V0?p-NL59w zrK0w($_m#SDPQ!Z$nhd^JO|f+7k5xca94d2OLJ&sSxlB7F%NtrF@@O7WWlkHSDtor zzD?u;b&KN$*MnHx;JDy9P~G<{4}9__s&MATBV4R+MuA8TjlZ3ye&qZMCUe8ihBnHI zhMSu zSERHwrmBb$SWVr+)Yk2k^FgTMR6mP;@FY2{}BeV|SUo=mNk<-XSOHNErw>s{^rR-bu$@aN7= zj~-qXcS2!BA*(Q**BOOl{FggkyHdCJi_Fy>?_K+G+DYwIn8`29DYPg&s4$}7D`fv? zuyJ2sMfJX(I^yrf6u!(~9anf(AqAk&ke}uL0SIb-H!SaDQvd(}07*qoM6N<$g1Ha7 A2LJ#7 literal 0 HcmV?d00001 diff --git a/docs/_build/html/_static/comment.png b/docs/_build/html/_static/comment.png new file mode 100644 index 0000000000000000000000000000000000000000..92feb52b8824c6b0f59b658b1196c61de9162a95 GIT binary patch literal 3445 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 Xn!ZpXD%P(H00000NkvXXu0mjf= 0 && !jQuery(node.parentNode).hasClass(className)) { + var span = document.createElement("span"); + span.className = className; + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + node.parentNode.insertBefore(span, node.parentNode.insertBefore( + document.createTextNode(val.substr(pos + text.length)), + node.nextSibling)); + node.nodeValue = val.substr(0, pos); + } + } + else if (!jQuery(node).is("button, select, textarea")) { + jQuery.each(node.childNodes, function() { + highlight(this); + }); + } + } + return this.each(function() { + highlight(this); + }); +}; + +/** + * Small JavaScript module for the documentation. + */ +var Documentation = { + + init : function() { + this.fixFirefoxAnchorBug(); + this.highlightSearchWords(); + this.initIndexTable(); + }, + + /** + * i18n support + */ + TRANSLATIONS : {}, + PLURAL_EXPR : function(n) { return n == 1 ? 0 : 1; }, + LOCALE : 'unknown', + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext : function(string) { + var translated = Documentation.TRANSLATIONS[string]; + if (typeof translated == 'undefined') + return string; + return (typeof translated == 'string') ? translated : translated[0]; + }, + + ngettext : function(singular, plural, n) { + var translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated == 'undefined') + return (n == 1) ? singular : plural; + return translated[Documentation.PLURALEXPR(n)]; + }, + + addTranslations : function(catalog) { + for (var key in catalog.messages) + this.TRANSLATIONS[key] = catalog.messages[key]; + this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')'); + this.LOCALE = catalog.locale; + }, + + /** + * add context elements like header anchor links + */ + addContextElements : function() { + $('div[id] > :header:first').each(function() { + $('\u00B6'). + attr('href', '#' + this.id). + attr('title', _('Permalink to this headline')). + appendTo(this); + }); + $('dt[id]').each(function() { + $('\u00B6'). + attr('href', '#' + this.id). + attr('title', _('Permalink to this definition')). + appendTo(this); + }); + }, + + /** + * workaround a firefox stupidity + */ + fixFirefoxAnchorBug : function() { + if (document.location.hash && $.browser.mozilla) + window.setTimeout(function() { + document.location.href += ''; + }, 10); + }, + + /** + * highlight the search words provided in the url in the text + */ + highlightSearchWords : function() { + var params = $.getQueryParameters(); + var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : []; + if (terms.length) { + var body = $('div.body'); + window.setTimeout(function() { + $.each(terms, function() { + body.highlightText(this.toLowerCase(), 'highlighted'); + }); + }, 10); + $('') + .appendTo($('#searchbox')); + } + }, + + /** + * init the domain index toggle buttons + */ + initIndexTable : function() { + var togglers = $('img.toggler').click(function() { + var src = $(this).attr('src'); + var idnum = $(this).attr('id').substr(7); + $('tr.cg-' + idnum).toggle(); + if (src.substr(-9) == 'minus.png') + $(this).attr('src', src.substr(0, src.length-9) + 'plus.png'); + else + $(this).attr('src', src.substr(0, src.length-8) + 'minus.png'); + }).css('display', ''); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) { + togglers.click(); + } + }, + + /** + * helper function to hide the search marks again + */ + hideSearchWords : function() { + $('#searchbox .highlight-link').fadeOut(300); + $('span.highlighted').removeClass('highlighted'); + }, + + /** + * make the url absolute + */ + makeURL : function(relativeURL) { + return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL; + }, + + /** + * get the current relative url + */ + getCurrentURL : function() { + var path = document.location.pathname; + var parts = path.split(/\//); + $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() { + if (this == '..') + parts.pop(); + }); + var url = parts.join('/'); + return path.substring(url.lastIndexOf('/') + 1, path.length - 1); + } +}; + +// quick alias for translations +_ = Documentation.gettext; + +$(document).ready(function() { + Documentation.init(); +}); diff --git a/docs/_build/html/_static/down-pressed.png b/docs/_build/html/_static/down-pressed.png new file mode 100644 index 0000000000000000000000000000000000000000..6f7ad782782e4f8e39b0c6e15c7344700cdd2527 GIT binary patch literal 368 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|*pj^6U4S$Y z{B+)352QE?JR*yM+OLB!qm#z$3ZNi+iKnkC`z>}Z23@f-Ava~9&<9T!#}JFtXD=!G zGdl{fK6ro2OGiOl+hKvH6i=D3%%Y^j`yIkRn!8O>@bG)IQR0{Kf+mxNd=_WScA8u_ z3;8(7x2){m9`nt+U(Nab&1G)!{`SPVpDX$w8McLTzAJ39wprG3p4XLq$06M`%}2Yk zRPPsbES*dnYm1wkGL;iioAUB*Or2kz6(-M_r_#Me-`{mj$Z%( literal 0 HcmV?d00001 diff --git a/docs/_build/html/_static/down.png b/docs/_build/html/_static/down.png new file mode 100644 index 0000000000000000000000000000000000000000..3003a88770de3977d47a2ba69893436a2860f9e7 GIT binary patch literal 363 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|*pj^6U4S$Y z{B+)352QE?JR*yM+OLB!qm#z$3ZNi+iKnkC`z>}xaV3tUZ$qnrLa#kt978NlpS`ru z&)HFc^}^>{UOEce+71h5nn>6&w6A!ieNbu1wh)UGh{8~et^#oZ1# z>T7oM=FZ~xXWnTo{qnXm$ZLOlqGswI_m2{XwVK)IJmBjW{J3-B3x@C=M{ShWt#fYS9M?R;8K$~YwlIqwf>VA7q=YKcwf2DS4Zj5inDKXXB1zl=(YO3ST6~rDq)&z z*o>z)=hxrfG-cDBW0G$!?6{M<$@{_4{m1o%Ub!naEtn|@^frU1tDnm{r-UW|!^@B8 literal 0 HcmV?d00001 diff --git a/docs/_build/html/_static/file.png b/docs/_build/html/_static/file.png new file mode 100644 index 0000000000000000000000000000000000000000..d18082e397e7e54f20721af768c4c2983258f1b4 GIT binary patch literal 392 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4%caKYZ?lYt_f1s;*b z3=G`DAk4@xYmNj^kiEpy*OmP$HyOL$D9)yc9|lc|nKf<9@eUiWd>3GuTC!a5vdfWYEazjncPj5ZQX%+1 zt8B*4=d)!cdDz4wr^#OMYfqGz$1LDFF>|#>*O?AGil(WEs?wLLy{Gj2J_@opDm%`dlax3yA*@*N$G&*ukFv>P8+2CBWO(qz zD0k1@kN>hhb1_6`&wrCswzINE(evt-5C1B^STi2@PmdKI;Vst0PQB6!2kdN literal 0 HcmV?d00001 diff --git a/docs/_build/html/_static/jquery.js b/docs/_build/html/_static/jquery.js new file mode 100644 index 0000000..7c24308 --- /dev/null +++ b/docs/_build/html/_static/jquery.js @@ -0,0 +1,154 @@ +/*! + * jQuery JavaScript Library v1.4.2 + * http://jquery.com/ + * + * Copyright 2010, John Resig + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * Includes Sizzle.js + * http://sizzlejs.com/ + * Copyright 2010, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * + * Date: Sat Feb 13 22:33:48 2010 -0500 + */ +(function(A,w){function ma(){if(!c.isReady){try{s.documentElement.doScroll("left")}catch(a){setTimeout(ma,1);return}c.ready()}}function Qa(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}function X(a,b,d,f,e,j){var i=a.length;if(typeof b==="object"){for(var o in b)X(a,o,b[o],f,e,d);return a}if(d!==w){f=!j&&f&&c.isFunction(d);for(o=0;o)[^>]*$|^#([\w-]+)$/,Ua=/^.[^:#\[\.,]*$/,Va=/\S/, +Wa=/^(\s|\u00A0)+|(\s|\u00A0)+$/g,Xa=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,P=navigator.userAgent,xa=false,Q=[],L,$=Object.prototype.toString,aa=Object.prototype.hasOwnProperty,ba=Array.prototype.push,R=Array.prototype.slice,ya=Array.prototype.indexOf;c.fn=c.prototype={init:function(a,b){var d,f;if(!a)return this;if(a.nodeType){this.context=this[0]=a;this.length=1;return this}if(a==="body"&&!b){this.context=s;this[0]=s.body;this.selector="body";this.length=1;return this}if(typeof a==="string")if((d=Ta.exec(a))&& +(d[1]||!b))if(d[1]){f=b?b.ownerDocument||b:s;if(a=Xa.exec(a))if(c.isPlainObject(b)){a=[s.createElement(a[1])];c.fn.attr.call(a,b,true)}else a=[f.createElement(a[1])];else{a=sa([d[1]],[f]);a=(a.cacheable?a.fragment.cloneNode(true):a.fragment).childNodes}return c.merge(this,a)}else{if(b=s.getElementById(d[2])){if(b.id!==d[2])return T.find(a);this.length=1;this[0]=b}this.context=s;this.selector=a;return this}else if(!b&&/^\w+$/.test(a)){this.selector=a;this.context=s;a=s.getElementsByTagName(a);return c.merge(this, +a)}else return!b||b.jquery?(b||T).find(a):c(b).find(a);else if(c.isFunction(a))return T.ready(a);if(a.selector!==w){this.selector=a.selector;this.context=a.context}return c.makeArray(a,this)},selector:"",jquery:"1.4.2",length:0,size:function(){return this.length},toArray:function(){return R.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this.slice(a)[0]:this[a]},pushStack:function(a,b,d){var f=c();c.isArray(a)?ba.apply(f,a):c.merge(f,a);f.prevObject=this;f.context=this.context;if(b=== +"find")f.selector=this.selector+(this.selector?" ":"")+d;else if(b)f.selector=this.selector+"."+b+"("+d+")";return f},each:function(a,b){return c.each(this,a,b)},ready:function(a){c.bindReady();if(c.isReady)a.call(s,c);else Q&&Q.push(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(R.apply(this,arguments),"slice",R.call(arguments).join(","))},map:function(a){return this.pushStack(c.map(this, +function(b,d){return a.call(b,d,b)}))},end:function(){return this.prevObject||c(null)},push:ba,sort:[].sort,splice:[].splice};c.fn.init.prototype=c.fn;c.extend=c.fn.extend=function(){var a=arguments[0]||{},b=1,d=arguments.length,f=false,e,j,i,o;if(typeof a==="boolean"){f=a;a=arguments[1]||{};b=2}if(typeof a!=="object"&&!c.isFunction(a))a={};if(d===b){a=this;--b}for(;b
a"; +var e=d.getElementsByTagName("*"),j=d.getElementsByTagName("a")[0];if(!(!e||!e.length||!j)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(j.getAttribute("style")),hrefNormalized:j.getAttribute("href")==="/a",opacity:/^0.55$/.test(j.style.opacity),cssFloat:!!j.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:s.createElement("select").appendChild(s.createElement("option")).selected, +parentNode:d.removeChild(d.appendChild(s.createElement("div"))).parentNode===null,deleteExpando:true,checkClone:false,scriptEval:false,noCloneEvent:true,boxModel:null};b.type="text/javascript";try{b.appendChild(s.createTextNode("window."+f+"=1;"))}catch(i){}a.insertBefore(b,a.firstChild);if(A[f]){c.support.scriptEval=true;delete A[f]}try{delete b.test}catch(o){c.support.deleteExpando=false}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function k(){c.support.noCloneEvent= +false;d.detachEvent("onclick",k)});d.cloneNode(true).fireEvent("onclick")}d=s.createElement("div");d.innerHTML="";a=s.createDocumentFragment();a.appendChild(d.firstChild);c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var k=s.createElement("div");k.style.width=k.style.paddingLeft="1px";s.body.appendChild(k);c.boxModel=c.support.boxModel=k.offsetWidth===2;s.body.removeChild(k).style.display="none"});a=function(k){var n= +s.createElement("div");k="on"+k;var r=k in n;if(!r){n.setAttribute(k,"return;");r=typeof n[k]==="function"}return r};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=e=j=null}})();c.props={"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"};var G="jQuery"+J(),Ya=0,za={};c.extend({cache:{},expando:G,noData:{embed:true,object:true, +applet:true},data:function(a,b,d){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var f=a[G],e=c.cache;if(!f&&typeof b==="string"&&d===w)return null;f||(f=++Ya);if(typeof b==="object"){a[G]=f;e[f]=c.extend(true,{},b)}else if(!e[f]){a[G]=f;e[f]={}}a=e[f];if(d!==w)a[b]=d;return typeof b==="string"?a[b]:a}},removeData:function(a,b){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var d=a[G],f=c.cache,e=f[d];if(b){if(e){delete e[b];c.isEmptyObject(e)&&c.removeData(a)}}else{if(c.support.deleteExpando)delete a[c.expando]; +else a.removeAttribute&&a.removeAttribute(c.expando);delete f[d]}}}});c.fn.extend({data:function(a,b){if(typeof a==="undefined"&&this.length)return c.data(this[0]);else if(typeof a==="object")return this.each(function(){c.data(this,a)});var d=a.split(".");d[1]=d[1]?"."+d[1]:"";if(b===w){var f=this.triggerHandler("getData"+d[1]+"!",[d[0]]);if(f===w&&this.length)f=c.data(this[0],a);return f===w&&d[1]?this.data(d[0]):f}else return this.trigger("setData"+d[1]+"!",[d[0],b]).each(function(){c.data(this, +a,b)})},removeData:function(a){return this.each(function(){c.removeData(this,a)})}});c.extend({queue:function(a,b,d){if(a){b=(b||"fx")+"queue";var f=c.data(a,b);if(!d)return f||[];if(!f||c.isArray(d))f=c.data(a,b,c.makeArray(d));else f.push(d);return f}},dequeue:function(a,b){b=b||"fx";var d=c.queue(a,b),f=d.shift();if(f==="inprogress")f=d.shift();if(f){b==="fx"&&d.unshift("inprogress");f.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!=="string"){b=a;a="fx"}if(b=== +w)return c.queue(this[0],a);return this.each(function(){var d=c.queue(this,a,b);a==="fx"&&d[0]!=="inprogress"&&c.dequeue(this,a)})},dequeue:function(a){return this.each(function(){c.dequeue(this,a)})},delay:function(a,b){a=c.fx?c.fx.speeds[a]||a:a;b=b||"fx";return this.queue(b,function(){var d=this;setTimeout(function(){c.dequeue(d,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var Aa=/[\n\t]/g,ca=/\s+/,Za=/\r/g,$a=/href|src|style/,ab=/(button|input)/i,bb=/(button|input|object|select|textarea)/i, +cb=/^(a|area)$/i,Ba=/radio|checkbox/;c.fn.extend({attr:function(a,b){return X(this,a,b,true,c.attr)},removeAttr:function(a){return this.each(function(){c.attr(this,a,"");this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(c.isFunction(a))return this.each(function(n){var r=c(this);r.addClass(a.call(this,n,r.attr("class")))});if(a&&typeof a==="string")for(var b=(a||"").split(ca),d=0,f=this.length;d-1)return true;return false},val:function(a){if(a===w){var b=this[0];if(b){if(c.nodeName(b,"option"))return(b.attributes.value||{}).specified?b.value:b.text;if(c.nodeName(b,"select")){var d=b.selectedIndex,f=[],e=b.options;b=b.type==="select-one";if(d<0)return null;var j=b?d:0;for(d=b?d+1:e.length;j=0;else if(c.nodeName(this,"select")){var u=c.makeArray(r);c("option",this).each(function(){this.selected= +c.inArray(c(this).val(),u)>=0});if(!u.length)this.selectedIndex=-1}else this.value=r}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},attr:function(a,b,d,f){if(!a||a.nodeType===3||a.nodeType===8)return w;if(f&&b in c.attrFn)return c(a)[b](d);f=a.nodeType!==1||!c.isXMLDoc(a);var e=d!==w;b=f&&c.props[b]||b;if(a.nodeType===1){var j=$a.test(b);if(b in a&&f&&!j){if(e){b==="type"&&ab.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed"); +a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&&b.specified?b.value:bb.test(a.nodeName)||cb.test(a.nodeName)&&a.href?0:w;return a[b]}if(!c.support.style&&f&&b==="style"){if(e)a.style.cssText=""+d;return a.style.cssText}e&&a.setAttribute(b,""+d);a=!c.support.hrefNormalized&&f&&j?a.getAttribute(b,2):a.getAttribute(b);return a===null?w:a}return c.style(a,b,d)}});var O=/\.(.*)$/,db=function(a){return a.replace(/[^\w\s\.\|`]/g, +function(b){return"\\"+b})};c.event={add:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){if(a.setInterval&&a!==A&&!a.frameElement)a=A;var e,j;if(d.handler){e=d;d=e.handler}if(!d.guid)d.guid=c.guid++;if(j=c.data(a)){var i=j.events=j.events||{},o=j.handle;if(!o)j.handle=o=function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(o.elem,arguments):w};o.elem=a;b=b.split(" ");for(var k,n=0,r;k=b[n++];){j=e?c.extend({},e):{handler:d,data:f};if(k.indexOf(".")>-1){r=k.split("."); +k=r.shift();j.namespace=r.slice(0).sort().join(".")}else{r=[];j.namespace=""}j.type=k;j.guid=d.guid;var u=i[k],z=c.event.special[k]||{};if(!u){u=i[k]=[];if(!z.setup||z.setup.call(a,f,r,o)===false)if(a.addEventListener)a.addEventListener(k,o,false);else a.attachEvent&&a.attachEvent("on"+k,o)}if(z.add){z.add.call(a,j);if(!j.handler.guid)j.handler.guid=d.guid}u.push(j);c.event.global[k]=true}a=null}}},global:{},remove:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){var e,j=0,i,o,k,n,r,u,z=c.data(a), +C=z&&z.events;if(z&&C){if(b&&b.type){d=b.handler;b=b.type}if(!b||typeof b==="string"&&b.charAt(0)==="."){b=b||"";for(e in C)c.event.remove(a,e+b)}else{for(b=b.split(" ");e=b[j++];){n=e;i=e.indexOf(".")<0;o=[];if(!i){o=e.split(".");e=o.shift();k=new RegExp("(^|\\.)"+c.map(o.slice(0).sort(),db).join("\\.(?:.*\\.)?")+"(\\.|$)")}if(r=C[e])if(d){n=c.event.special[e]||{};for(B=f||0;B=0){a.type= +e=e.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();c.event.global[e]&&c.each(c.cache,function(){this.events&&this.events[e]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType===8)return w;a.result=w;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(f=c.data(d,"handle"))&&f.apply(d,b);f=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+e]&&d["on"+e].apply(d,b)===false)a.result=false}catch(j){}if(!a.isPropagationStopped()&& +f)c.event.trigger(a,b,f,true);else if(!a.isDefaultPrevented()){f=a.target;var i,o=c.nodeName(f,"a")&&e==="click",k=c.event.special[e]||{};if((!k._default||k._default.call(d,a)===false)&&!o&&!(f&&f.nodeName&&c.noData[f.nodeName.toLowerCase()])){try{if(f[e]){if(i=f["on"+e])f["on"+e]=null;c.event.triggered=true;f[e]()}}catch(n){}if(i)f["on"+e]=i;c.event.triggered=false}}},handle:function(a){var b,d,f,e;a=arguments[0]=c.event.fix(a||A.event);a.currentTarget=this;b=a.type.indexOf(".")<0&&!a.exclusive; +if(!b){d=a.type.split(".");a.type=d.shift();f=new RegExp("(^|\\.)"+d.slice(0).sort().join("\\.(?:.*\\.)?")+"(\\.|$)")}e=c.data(this,"events");d=e[a.type];if(e&&d){d=d.slice(0);e=0;for(var j=d.length;e-1?c.map(a.options,function(f){return f.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d},fa=function(a,b){var d=a.target,f,e;if(!(!da.test(d.nodeName)||d.readOnly)){f=c.data(d,"_change_data");e=Fa(d);if(a.type!=="focusout"||d.type!=="radio")c.data(d,"_change_data", +e);if(!(f===w||e===f))if(f!=null||e){a.type="change";return c.event.trigger(a,b,d)}}};c.event.special.change={filters:{focusout:fa,click:function(a){var b=a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return fa.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return fa.call(this,a)},beforeactivate:function(a){a=a.target;c.data(a, +"_change_data",Fa(a))}},setup:function(){if(this.type==="file")return false;for(var a in ea)c.event.add(this,a+".specialChange",ea[a]);return da.test(this.nodeName)},teardown:function(){c.event.remove(this,".specialChange");return da.test(this.nodeName)}};ea=c.event.special.change.filters}s.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(f){f=c.event.fix(f);f.type=b;return c.event.handle.call(this,f)}c.event.special[b]={setup:function(){this.addEventListener(a, +d,true)},teardown:function(){this.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,f,e){if(typeof d==="object"){for(var j in d)this[b](j,f,d[j],e);return this}if(c.isFunction(f)){e=f;f=w}var i=b==="one"?c.proxy(e,function(k){c(this).unbind(k,i);return e.apply(this,arguments)}):e;if(d==="unload"&&b!=="one")this.one(d,f,e);else{j=0;for(var o=this.length;j0){y=t;break}}t=t[g]}m[q]=y}}}var f=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, +e=0,j=Object.prototype.toString,i=false,o=true;[0,0].sort(function(){o=false;return 0});var k=function(g,h,l,m){l=l||[];var q=h=h||s;if(h.nodeType!==1&&h.nodeType!==9)return[];if(!g||typeof g!=="string")return l;for(var p=[],v,t,y,S,H=true,M=x(h),I=g;(f.exec(""),v=f.exec(I))!==null;){I=v[3];p.push(v[1]);if(v[2]){S=v[3];break}}if(p.length>1&&r.exec(g))if(p.length===2&&n.relative[p[0]])t=ga(p[0]+p[1],h);else for(t=n.relative[p[0]]?[h]:k(p.shift(),h);p.length;){g=p.shift();if(n.relative[g])g+=p.shift(); +t=ga(g,t)}else{if(!m&&p.length>1&&h.nodeType===9&&!M&&n.match.ID.test(p[0])&&!n.match.ID.test(p[p.length-1])){v=k.find(p.shift(),h,M);h=v.expr?k.filter(v.expr,v.set)[0]:v.set[0]}if(h){v=m?{expr:p.pop(),set:z(m)}:k.find(p.pop(),p.length===1&&(p[0]==="~"||p[0]==="+")&&h.parentNode?h.parentNode:h,M);t=v.expr?k.filter(v.expr,v.set):v.set;if(p.length>0)y=z(t);else H=false;for(;p.length;){var D=p.pop();v=D;if(n.relative[D])v=p.pop();else D="";if(v==null)v=h;n.relative[D](y,v,M)}}else y=[]}y||(y=t);y||k.error(D|| +g);if(j.call(y)==="[object Array]")if(H)if(h&&h.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&E(h,y[g])))l.push(t[g])}else for(g=0;y[g]!=null;g++)y[g]&&y[g].nodeType===1&&l.push(t[g]);else l.push.apply(l,y);else z(y,l);if(S){k(S,q,l,m);k.uniqueSort(l)}return l};k.uniqueSort=function(g){if(B){i=o;g.sort(B);if(i)for(var h=1;h":function(g,h){var l=typeof h==="string";if(l&&!/\W/.test(h)){h=h.toLowerCase();for(var m=0,q=g.length;m=0))l||m.push(v);else if(l)h[p]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()}, +CHILD:function(g){if(g[1]==="nth"){var h=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=h[1]+(h[2]||1)-0;g[3]=h[3]-0}g[0]=e++;return g},ATTR:function(g,h,l,m,q,p){h=g[1].replace(/\\/g,"");if(!p&&n.attrMap[h])g[1]=n.attrMap[h];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,h,l,m,q){if(g[1]==="not")if((f.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=k(g[3],null,null,h);else{g=k.filter(g[3],h,l,true^q);l||m.push.apply(m, +g);return false}else if(n.match.POS.test(g[0])||n.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled===true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,h,l){return!!k(l[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)}, +text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"===g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}}, +setFilters:{first:function(g,h){return h===0},last:function(g,h,l,m){return h===m.length-1},even:function(g,h){return h%2===0},odd:function(g,h){return h%2===1},lt:function(g,h,l){return hl[3]-0},nth:function(g,h,l){return l[3]-0===h},eq:function(g,h,l){return l[3]-0===h}},filter:{PSEUDO:function(g,h,l,m){var q=h[1],p=n.filters[q];if(p)return p(g,l,h,m);else if(q==="contains")return(g.textContent||g.innerText||a([g])||"").indexOf(h[3])>=0;else if(q==="not"){h= +h[3];l=0;for(m=h.length;l=0}},ID:function(g,h){return g.nodeType===1&&g.getAttribute("id")===h},TAG:function(g,h){return h==="*"&&g.nodeType===1||g.nodeName.toLowerCase()===h},CLASS:function(g,h){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(h)>-1},ATTR:function(g,h){var l=h[1];g=n.attrHandle[l]?n.attrHandle[l](g):g[l]!=null?g[l]:g.getAttribute(l);l=g+"";var m=h[2];h=h[4];return g==null?m==="!=":m=== +"="?l===h:m==="*="?l.indexOf(h)>=0:m==="~="?(" "+l+" ").indexOf(h)>=0:!h?l&&g!==false:m==="!="?l!==h:m==="^="?l.indexOf(h)===0:m==="$="?l.substr(l.length-h.length)===h:m==="|="?l===h||l.substr(0,h.length+1)===h+"-":false},POS:function(g,h,l,m){var q=n.setFilters[h[2]];if(q)return q(g,l,h,m)}}},r=n.match.POS;for(var u in n.match){n.match[u]=new RegExp(n.match[u].source+/(?![^\[]*\])(?![^\(]*\))/.source);n.leftMatch[u]=new RegExp(/(^(?:.|\r|\n)*?)/.source+n.match[u].source.replace(/\\(\d+)/g,function(g, +h){return"\\"+(h-0+1)}))}var z=function(g,h){g=Array.prototype.slice.call(g,0);if(h){h.push.apply(h,g);return h}return g};try{Array.prototype.slice.call(s.documentElement.childNodes,0)}catch(C){z=function(g,h){h=h||[];if(j.call(g)==="[object Array]")Array.prototype.push.apply(h,g);else if(typeof g.length==="number")for(var l=0,m=g.length;l";var l=s.documentElement;l.insertBefore(g,l.firstChild);if(s.getElementById(h)){n.find.ID=function(m,q,p){if(typeof q.getElementById!=="undefined"&&!p)return(q=q.getElementById(m[1]))?q.id===m[1]||typeof q.getAttributeNode!=="undefined"&& +q.getAttributeNode("id").nodeValue===m[1]?[q]:w:[]};n.filter.ID=function(m,q){var p=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&p&&p.nodeValue===q}}l.removeChild(g);l=g=null})();(function(){var g=s.createElement("div");g.appendChild(s.createComment(""));if(g.getElementsByTagName("*").length>0)n.find.TAG=function(h,l){l=l.getElementsByTagName(h[1]);if(h[1]==="*"){h=[];for(var m=0;l[m];m++)l[m].nodeType===1&&h.push(l[m]);l=h}return l};g.innerHTML=""; +if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")n.attrHandle.href=function(h){return h.getAttribute("href",2)};g=null})();s.querySelectorAll&&function(){var g=k,h=s.createElement("div");h.innerHTML="

";if(!(h.querySelectorAll&&h.querySelectorAll(".TEST").length===0)){k=function(m,q,p,v){q=q||s;if(!v&&q.nodeType===9&&!x(q))try{return z(q.querySelectorAll(m),p)}catch(t){}return g(m,q,p,v)};for(var l in g)k[l]=g[l];h=null}}(); +(function(){var g=s.createElement("div");g.innerHTML="
";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){n.order.splice(1,0,"CLASS");n.find.CLASS=function(h,l,m){if(typeof l.getElementsByClassName!=="undefined"&&!m)return l.getElementsByClassName(h[1])};g=null}}})();var E=s.compareDocumentPosition?function(g,h){return!!(g.compareDocumentPosition(h)&16)}: +function(g,h){return g!==h&&(g.contains?g.contains(h):true)},x=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false},ga=function(g,h){var l=[],m="",q;for(h=h.nodeType?[h]:h;q=n.match.PSEUDO.exec(g);){m+=q[0];g=g.replace(n.match.PSEUDO,"")}g=n.relative[g]?g+"*":g;q=0;for(var p=h.length;q=0===d})};c.fn.extend({find:function(a){for(var b=this.pushStack("","find",a),d=0,f=0,e=this.length;f0)for(var j=d;j0},closest:function(a,b){if(c.isArray(a)){var d=[],f=this[0],e,j= +{},i;if(f&&a.length){e=0;for(var o=a.length;e-1:c(f).is(e)){d.push({selector:i,elem:f});delete j[i]}}f=f.parentNode}}return d}var k=c.expr.match.POS.test(a)?c(a,b||this.context):null;return this.map(function(n,r){for(;r&&r.ownerDocument&&r!==b;){if(k?k.index(r)>-1:c(r).is(a))return r;r=r.parentNode}return null})},index:function(a){if(!a||typeof a=== +"string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){a=typeof a==="string"?c(a,b||this.context):c.makeArray(a);b=c.merge(this.get(),a);return this.pushStack(qa(a[0])||qa(b[0])?b:c.unique(b))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode", +d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a,2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")? +a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a,b){c.fn[a]=function(d,f){var e=c.map(this,b,d);eb.test(a)||(f=d);if(f&&typeof f==="string")e=c.filter(f,e);e=this.length>1?c.unique(e):e;if((this.length>1||gb.test(f))&&fb.test(a))e=e.reverse();return this.pushStack(e,a,R.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return c.find.matches(a,b)},dir:function(a,b,d){var f=[];for(a=a[b];a&&a.nodeType!==9&&(d===w||a.nodeType!==1||!c(a).is(d));){a.nodeType=== +1&&f.push(a);a=a[b]}return f},nth:function(a,b,d){b=b||1;for(var f=0;a;a=a[d])if(a.nodeType===1&&++f===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var Ja=/ jQuery\d+="(?:\d+|null)"/g,V=/^\s+/,Ka=/(<([\w:]+)[^>]*?)\/>/g,hb=/^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i,La=/<([\w:]+)/,ib=/"},F={option:[1,""],legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"],area:[1,"",""],_default:[0,"",""]};F.optgroup=F.option;F.tbody=F.tfoot=F.colgroup=F.caption=F.thead;F.th=F.td;if(!c.support.htmlSerialize)F._default=[1,"div
","
"];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d= +c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==w)return this.empty().append((this[0]&&this[0].ownerDocument||s).createTextNode(a));return c.text(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this}, +wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})}, +prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b, +this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},remove:function(a,b){for(var d=0,f;(f=this[d])!=null;d++)if(!a||c.filter(a,[f]).length){if(!b&&f.nodeType===1){c.cleanData(f.getElementsByTagName("*"));c.cleanData([f])}f.parentNode&&f.parentNode.removeChild(f)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName("*"));b.firstChild;)b.removeChild(b.firstChild); +return this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,f=this.ownerDocument;if(!d){d=f.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(Ja,"").replace(/=([^="'>\s]+\/)>/g,'="$1">').replace(V,"")],f)[0]}else return this.cloneNode(true)});if(a===true){ra(this,b);ra(this.find("*"),b.find("*"))}return b},html:function(a){if(a===w)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(Ja, +""):null;else if(typeof a==="string"&&!ta.test(a)&&(c.support.leadingWhitespace||!V.test(a))&&!F[(La.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Ka,Ma);try{for(var b=0,d=this.length;b0||e.cacheable||this.length>1?k.cloneNode(true):k)}o.length&&c.each(o,Qa)}return this}});c.fragments={};c.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var f=[];d=c(d);var e=this.length===1&&this[0].parentNode;if(e&&e.nodeType===11&&e.childNodes.length===1&&d.length===1){d[b](this[0]); +return this}else{e=0;for(var j=d.length;e0?this.clone(true):this).get();c.fn[b].apply(c(d[e]),i);f=f.concat(i)}return this.pushStack(f,a,d.selector)}}});c.extend({clean:function(a,b,d,f){b=b||s;if(typeof b.createElement==="undefined")b=b.ownerDocument||b[0]&&b[0].ownerDocument||s;for(var e=[],j=0,i;(i=a[j])!=null;j++){if(typeof i==="number")i+="";if(i){if(typeof i==="string"&&!jb.test(i))i=b.createTextNode(i);else if(typeof i==="string"){i=i.replace(Ka,Ma);var o=(La.exec(i)||["", +""])[1].toLowerCase(),k=F[o]||F._default,n=k[0],r=b.createElement("div");for(r.innerHTML=k[1]+i+k[2];n--;)r=r.lastChild;if(!c.support.tbody){n=ib.test(i);o=o==="table"&&!n?r.firstChild&&r.firstChild.childNodes:k[1]===""&&!n?r.childNodes:[];for(k=o.length-1;k>=0;--k)c.nodeName(o[k],"tbody")&&!o[k].childNodes.length&&o[k].parentNode.removeChild(o[k])}!c.support.leadingWhitespace&&V.test(i)&&r.insertBefore(b.createTextNode(V.exec(i)[0]),r.firstChild);i=r.childNodes}if(i.nodeType)e.push(i);else e= +c.merge(e,i)}}if(d)for(j=0;e[j];j++)if(f&&c.nodeName(e[j],"script")&&(!e[j].type||e[j].type.toLowerCase()==="text/javascript"))f.push(e[j].parentNode?e[j].parentNode.removeChild(e[j]):e[j]);else{e[j].nodeType===1&&e.splice.apply(e,[j+1,0].concat(c.makeArray(e[j].getElementsByTagName("script"))));d.appendChild(e[j])}return e},cleanData:function(a){for(var b,d,f=c.cache,e=c.event.special,j=c.support.deleteExpando,i=0,o;(o=a[i])!=null;i++)if(d=o[c.expando]){b=f[d];if(b.events)for(var k in b.events)e[k]? +c.event.remove(o,k):Ca(o,k,b.handle);if(j)delete o[c.expando];else o.removeAttribute&&o.removeAttribute(c.expando);delete f[d]}}});var kb=/z-?index|font-?weight|opacity|zoom|line-?height/i,Na=/alpha\([^)]*\)/,Oa=/opacity=([^)]*)/,ha=/float/i,ia=/-([a-z])/ig,lb=/([A-Z])/g,mb=/^-?\d+(?:px)?$/i,nb=/^-?\d/,ob={position:"absolute",visibility:"hidden",display:"block"},pb=["Left","Right"],qb=["Top","Bottom"],rb=s.defaultView&&s.defaultView.getComputedStyle,Pa=c.support.cssFloat?"cssFloat":"styleFloat",ja= +function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){return X(this,a,b,true,function(d,f,e){if(e===w)return c.curCSS(d,f);if(typeof e==="number"&&!kb.test(f))e+="px";c.style(d,f,e)})};c.extend({style:function(a,b,d){if(!a||a.nodeType===3||a.nodeType===8)return w;if((b==="width"||b==="height")&&parseFloat(d)<0)d=w;var f=a.style||a,e=d!==w;if(!c.support.opacity&&b==="opacity"){if(e){f.zoom=1;b=parseInt(d,10)+""==="NaN"?"":"alpha(opacity="+d*100+")";a=f.filter||c.curCSS(a,"filter")||"";f.filter= +Na.test(a)?a.replace(Na,b):b}return f.filter&&f.filter.indexOf("opacity=")>=0?parseFloat(Oa.exec(f.filter)[1])/100+"":""}if(ha.test(b))b=Pa;b=b.replace(ia,ja);if(e)f[b]=d;return f[b]},css:function(a,b,d,f){if(b==="width"||b==="height"){var e,j=b==="width"?pb:qb;function i(){e=b==="width"?a.offsetWidth:a.offsetHeight;f!=="border"&&c.each(j,function(){f||(e-=parseFloat(c.curCSS(a,"padding"+this,true))||0);if(f==="margin")e+=parseFloat(c.curCSS(a,"margin"+this,true))||0;else e-=parseFloat(c.curCSS(a, +"border"+this+"Width",true))||0})}a.offsetWidth!==0?i():c.swap(a,ob,i);return Math.max(0,Math.round(e))}return c.curCSS(a,b,d)},curCSS:function(a,b,d){var f,e=a.style;if(!c.support.opacity&&b==="opacity"&&a.currentStyle){f=Oa.test(a.currentStyle.filter||"")?parseFloat(RegExp.$1)/100+"":"";return f===""?"1":f}if(ha.test(b))b=Pa;if(!d&&e&&e[b])f=e[b];else if(rb){if(ha.test(b))b="float";b=b.replace(lb,"-$1").toLowerCase();e=a.ownerDocument.defaultView;if(!e)return null;if(a=e.getComputedStyle(a,null))f= +a.getPropertyValue(b);if(b==="opacity"&&f==="")f="1"}else if(a.currentStyle){d=b.replace(ia,ja);f=a.currentStyle[b]||a.currentStyle[d];if(!mb.test(f)&&nb.test(f)){b=e.left;var j=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;e.left=d==="fontSize"?"1em":f||0;f=e.pixelLeft+"px";e.left=b;a.runtimeStyle.left=j}}return f},swap:function(a,b,d){var f={};for(var e in b){f[e]=a.style[e];a.style[e]=b[e]}d.call(a);for(e in b)a.style[e]=f[e]}});if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b= +a.offsetWidth,d=a.offsetHeight,f=a.nodeName.toLowerCase()==="tr";return b===0&&d===0&&!f?true:b>0&&d>0&&!f?false:c.curCSS(a,"display")==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var sb=J(),tb=//gi,ub=/select|textarea/i,vb=/color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week/i,N=/=\?(&|$)/,ka=/\?/,wb=/(\?|&)_=.*?(&|$)/,xb=/^(\w+:)?\/\/([^\/?#]+)/,yb=/%20/g,zb=c.fn.load;c.fn.extend({load:function(a,b,d){if(typeof a!== +"string")return zb.call(this,a);else if(!this.length)return this;var f=a.indexOf(" ");if(f>=0){var e=a.slice(f,a.length);a=a.slice(0,f)}f="GET";if(b)if(c.isFunction(b)){d=b;b=null}else if(typeof b==="object"){b=c.param(b,c.ajaxSettings.traditional);f="POST"}var j=this;c.ajax({url:a,type:f,dataType:"html",data:b,complete:function(i,o){if(o==="success"||o==="notmodified")j.html(e?c("
").append(i.responseText.replace(tb,"")).find(e):i.responseText);d&&j.each(d,[i.responseText,o,i])}});return this}, +serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||ub.test(this.nodeName)||vb.test(this.type))}).map(function(a,b){a=c(this).val();return a==null?null:c.isArray(a)?c.map(a,function(d){return{name:b.name,value:d}}):{name:b.name,value:a}}).get()}});c.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "), +function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:f})},getScript:function(a,b){return c.get(a,null,b,"script")},getJSON:function(a,b,d){return c.get(a,b,d,"json")},post:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:f})},ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url:location.href, +global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:A.XMLHttpRequest&&(A.location.protocol!=="file:"||!A.ActiveXObject)?function(){return new A.XMLHttpRequest}:function(){try{return new A.ActiveXObject("Microsoft.XMLHTTP")}catch(a){}},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},etag:{},ajax:function(a){function b(){e.success&& +e.success.call(k,o,i,x);e.global&&f("ajaxSuccess",[x,e])}function d(){e.complete&&e.complete.call(k,x,i);e.global&&f("ajaxComplete",[x,e]);e.global&&!--c.active&&c.event.trigger("ajaxStop")}function f(q,p){(e.context?c(e.context):c.event).trigger(q,p)}var e=c.extend(true,{},c.ajaxSettings,a),j,i,o,k=a&&a.context||e,n=e.type.toUpperCase();if(e.data&&e.processData&&typeof e.data!=="string")e.data=c.param(e.data,e.traditional);if(e.dataType==="jsonp"){if(n==="GET")N.test(e.url)||(e.url+=(ka.test(e.url)? +"&":"?")+(e.jsonp||"callback")+"=?");else if(!e.data||!N.test(e.data))e.data=(e.data?e.data+"&":"")+(e.jsonp||"callback")+"=?";e.dataType="json"}if(e.dataType==="json"&&(e.data&&N.test(e.data)||N.test(e.url))){j=e.jsonpCallback||"jsonp"+sb++;if(e.data)e.data=(e.data+"").replace(N,"="+j+"$1");e.url=e.url.replace(N,"="+j+"$1");e.dataType="script";A[j]=A[j]||function(q){o=q;b();d();A[j]=w;try{delete A[j]}catch(p){}z&&z.removeChild(C)}}if(e.dataType==="script"&&e.cache===null)e.cache=false;if(e.cache=== +false&&n==="GET"){var r=J(),u=e.url.replace(wb,"$1_="+r+"$2");e.url=u+(u===e.url?(ka.test(e.url)?"&":"?")+"_="+r:"")}if(e.data&&n==="GET")e.url+=(ka.test(e.url)?"&":"?")+e.data;e.global&&!c.active++&&c.event.trigger("ajaxStart");r=(r=xb.exec(e.url))&&(r[1]&&r[1]!==location.protocol||r[2]!==location.host);if(e.dataType==="script"&&n==="GET"&&r){var z=s.getElementsByTagName("head")[0]||s.documentElement,C=s.createElement("script");C.src=e.url;if(e.scriptCharset)C.charset=e.scriptCharset;if(!j){var B= +false;C.onload=C.onreadystatechange=function(){if(!B&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){B=true;b();d();C.onload=C.onreadystatechange=null;z&&C.parentNode&&z.removeChild(C)}}}z.insertBefore(C,z.firstChild);return w}var E=false,x=e.xhr();if(x){e.username?x.open(n,e.url,e.async,e.username,e.password):x.open(n,e.url,e.async);try{if(e.data||a&&a.contentType)x.setRequestHeader("Content-Type",e.contentType);if(e.ifModified){c.lastModified[e.url]&&x.setRequestHeader("If-Modified-Since", +c.lastModified[e.url]);c.etag[e.url]&&x.setRequestHeader("If-None-Match",c.etag[e.url])}r||x.setRequestHeader("X-Requested-With","XMLHttpRequest");x.setRequestHeader("Accept",e.dataType&&e.accepts[e.dataType]?e.accepts[e.dataType]+", */*":e.accepts._default)}catch(ga){}if(e.beforeSend&&e.beforeSend.call(k,x,e)===false){e.global&&!--c.active&&c.event.trigger("ajaxStop");x.abort();return false}e.global&&f("ajaxSend",[x,e]);var g=x.onreadystatechange=function(q){if(!x||x.readyState===0||q==="abort"){E|| +d();E=true;if(x)x.onreadystatechange=c.noop}else if(!E&&x&&(x.readyState===4||q==="timeout")){E=true;x.onreadystatechange=c.noop;i=q==="timeout"?"timeout":!c.httpSuccess(x)?"error":e.ifModified&&c.httpNotModified(x,e.url)?"notmodified":"success";var p;if(i==="success")try{o=c.httpData(x,e.dataType,e)}catch(v){i="parsererror";p=v}if(i==="success"||i==="notmodified")j||b();else c.handleError(e,x,i,p);d();q==="timeout"&&x.abort();if(e.async)x=null}};try{var h=x.abort;x.abort=function(){x&&h.call(x); +g("abort")}}catch(l){}e.async&&e.timeout>0&&setTimeout(function(){x&&!E&&g("timeout")},e.timeout);try{x.send(n==="POST"||n==="PUT"||n==="DELETE"?e.data:null)}catch(m){c.handleError(e,x,null,m);d()}e.async||g();return x}},handleError:function(a,b,d,f){if(a.error)a.error.call(a.context||a,b,d,f);if(a.global)(a.context?c(a.context):c.event).trigger("ajaxError",[b,a,f])},active:0,httpSuccess:function(a){try{return!a.status&&location.protocol==="file:"||a.status>=200&&a.status<300||a.status===304||a.status=== +1223||a.status===0}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"),f=a.getResponseHeader("Etag");if(d)c.lastModified[b]=d;if(f)c.etag[b]=f;return a.status===304||a.status===0},httpData:function(a,b,d){var f=a.getResponseHeader("content-type")||"",e=b==="xml"||!b&&f.indexOf("xml")>=0;a=e?a.responseXML:a.responseText;e&&a.documentElement.nodeName==="parsererror"&&c.error("parsererror");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="string")if(b=== +"json"||!b&&f.indexOf("json")>=0)a=c.parseJSON(a);else if(b==="script"||!b&&f.indexOf("javascript")>=0)c.globalEval(a);return a},param:function(a,b){function d(i,o){if(c.isArray(o))c.each(o,function(k,n){b||/\[\]$/.test(i)?f(i,n):d(i+"["+(typeof n==="object"||c.isArray(n)?k:"")+"]",n)});else!b&&o!=null&&typeof o==="object"?c.each(o,function(k,n){d(i+"["+k+"]",n)}):f(i,o)}function f(i,o){o=c.isFunction(o)?o():o;e[e.length]=encodeURIComponent(i)+"="+encodeURIComponent(o)}var e=[];if(b===w)b=c.ajaxSettings.traditional; +if(c.isArray(a)||a.jquery)c.each(a,function(){f(this.name,this.value)});else for(var j in a)d(j,a[j]);return e.join("&").replace(yb,"+")}});var la={},Ab=/toggle|show|hide/,Bb=/^([+-]=)?([\d+-.]+)(.*)$/,W,va=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b){if(a||a===0)return this.animate(K("show",3),a,b);else{a=0;for(b=this.length;a").appendTo("body");f=e.css("display");if(f==="none")f="block";e.remove();la[d]=f}c.data(this[a],"olddisplay",f)}}a=0;for(b=this.length;a=0;f--)if(d[f].elem===this){b&&d[f](true);d.splice(f,1)}});b||this.dequeue();return this}});c.each({slideDown:K("show",1),slideUp:K("hide",1),slideToggle:K("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(a,b){c.fn[a]=function(d,f){return this.animate(b,d,f)}});c.extend({speed:function(a,b,d){var f=a&&typeof a==="object"?a:{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};f.duration=c.fx.off?0:typeof f.duration=== +"number"?f.duration:c.fx.speeds[f.duration]||c.fx.speeds._default;f.old=f.complete;f.complete=function(){f.queue!==false&&c(this).dequeue();c.isFunction(f.old)&&f.old.call(this)};return f},easing:{linear:function(a,b,d,f){return d+f*a},swing:function(a,b,d,f){return(-Math.cos(a*Math.PI)/2+0.5)*f+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this);(c.fx.step[this.prop]|| +c.fx.step._default)(this);if((this.prop==="height"||this.prop==="width")&&this.elem.style)this.elem.style.display="block"},cur:function(a){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];return(a=parseFloat(c.css(this.elem,this.prop,a)))&&a>-10000?a:parseFloat(c.curCSS(this.elem,this.prop))||0},custom:function(a,b,d){function f(j){return e.step(j)}this.startTime=J();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.now=this.start; +this.pos=this.state=0;var e=this;f.elem=this.elem;if(f()&&c.timers.push(f)&&!W)W=setInterval(c.fx.tick,13)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(a){var b=J(),d=true;if(a||b>=this.options.duration+this.startTime){this.now= +this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var f in this.options.curAnim)if(this.options.curAnim[f]!==true)d=false;if(d){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;a=c.data(this.elem,"olddisplay");this.elem.style.display=a?a:this.options.display;if(c.css(this.elem,"display")==="none")this.elem.style.display="block"}this.options.hide&&c(this.elem).hide();if(this.options.hide||this.options.show)for(var e in this.options.curAnim)c.style(this.elem, +e,this.options.orig[e]);this.options.complete.call(this.elem)}return false}else{e=b-this.startTime;this.state=e/this.options.duration;a=this.options.easing||(c.easing.swing?"swing":"linear");this.pos=c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||a](this.state,e,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a=c.timers,b=0;b
"; +a.insertBefore(b,a.firstChild);d=b.firstChild;f=d.firstChild;e=d.nextSibling.firstChild.firstChild;this.doesNotAddBorder=f.offsetTop!==5;this.doesAddBorderForTableAndCells=e.offsetTop===5;f.style.position="fixed";f.style.top="20px";this.supportsFixedPosition=f.offsetTop===20||f.offsetTop===15;f.style.position=f.style.top="";d.style.overflow="hidden";d.style.position="relative";this.subtractsBorderForOverflowNotVisible=f.offsetTop===-5;this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==j;a.removeChild(b); +c.offset.initialize=c.noop},bodyOffset:function(a){var b=a.offsetTop,d=a.offsetLeft;c.offset.initialize();if(c.offset.doesNotIncludeMarginInBodyOffset){b+=parseFloat(c.curCSS(a,"marginTop",true))||0;d+=parseFloat(c.curCSS(a,"marginLeft",true))||0}return{top:b,left:d}},setOffset:function(a,b,d){if(/static/.test(c.curCSS(a,"position")))a.style.position="relative";var f=c(a),e=f.offset(),j=parseInt(c.curCSS(a,"top",true),10)||0,i=parseInt(c.curCSS(a,"left",true),10)||0;if(c.isFunction(b))b=b.call(a, +d,e);d={top:b.top-e.top+j,left:b.left-e.left+i};"using"in b?b.using.call(a,d):f.css(d)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),f=/^body|html$/i.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.curCSS(a,"marginTop",true))||0;d.left-=parseFloat(c.curCSS(a,"marginLeft",true))||0;f.top+=parseFloat(c.curCSS(b[0],"borderTopWidth",true))||0;f.left+=parseFloat(c.curCSS(b[0],"borderLeftWidth",true))||0;return{top:d.top- +f.top,left:d.left-f.left}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||s.body;a&&!/^body|html$/i.test(a.nodeName)&&c.css(a,"position")==="static";)a=a.offsetParent;return a})}});c.each(["Left","Top"],function(a,b){var d="scroll"+b;c.fn[d]=function(f){var e=this[0],j;if(!e)return null;if(f!==w)return this.each(function(){if(j=wa(this))j.scrollTo(!a?f:c(j).scrollLeft(),a?f:c(j).scrollTop());else this[d]=f});else return(j=wa(e))?"pageXOffset"in j?j[a?"pageYOffset": +"pageXOffset"]:c.support.boxModel&&j.document.documentElement[d]||j.document.body[d]:e[d]}});c.each(["Height","Width"],function(a,b){var d=b.toLowerCase();c.fn["inner"+b]=function(){return this[0]?c.css(this[0],d,false,"padding"):null};c.fn["outer"+b]=function(f){return this[0]?c.css(this[0],d,false,f?"margin":"border"):null};c.fn[d]=function(f){var e=this[0];if(!e)return f==null?null:this;if(c.isFunction(f))return this.each(function(j){var i=c(this);i[d](f.call(this,j,i[d]()))});return"scrollTo"in +e&&e.document?e.document.compatMode==="CSS1Compat"&&e.document.documentElement["client"+b]||e.document.body["client"+b]:e.nodeType===9?Math.max(e.documentElement["client"+b],e.body["scroll"+b],e.documentElement["scroll"+b],e.body["offset"+b],e.documentElement["offset"+b]):f===w?c.css(e,d):this.css(d,typeof f==="string"?f:f+"px")}});A.jQuery=A.$=c})(window); diff --git a/docs/_build/html/_static/minus.png b/docs/_build/html/_static/minus.png new file mode 100644 index 0000000000000000000000000000000000000000..da1c5620d10c047525a467a425abe9ff5269cfc2 GIT binary patch literal 199 zcmeAS@N?(olHy`uVBq!ia0vp^+#t-s1SHkYJtzcHoCO|{#XvD(5N2eUHAey{$X?>< z>&kweokM_|(Po{+Q=kw>iEBiObAE1aYF-J$w=>iB1I2R$WLpMkF=>bh=@O1TaS?83{1OVknK< z>&kweokM`jkU7Va11Q8%;u=xnoS&PUnpeW`?aZ|OK(QcC7sn8Z%gHvy&v=;Q4jejg zV8NnAO`-4Z@2~&zopr02WF_WB>pF literal 0 HcmV?d00001 diff --git a/docs/_build/html/_static/pygments.css b/docs/_build/html/_static/pygments.css new file mode 100644 index 0000000..1a14f2a --- /dev/null +++ b/docs/_build/html/_static/pygments.css @@ -0,0 +1,62 @@ +.highlight .hll { background-color: #ffffcc } +.highlight { background: #eeffcc; } +.highlight .c { color: #408090; font-style: italic } /* Comment */ +.highlight .err { border: 1px solid #FF0000 } /* Error */ +.highlight .k { color: #007020; font-weight: bold } /* Keyword */ +.highlight .o { color: #666666 } /* Operator */ +.highlight .cm { color: #408090; font-style: italic } /* Comment.Multiline */ +.highlight .cp { color: #007020 } /* Comment.Preproc */ +.highlight .c1 { color: #408090; font-style: italic } /* Comment.Single */ +.highlight .cs { color: #408090; background-color: #fff0f0 } /* Comment.Special */ +.highlight .gd { color: #A00000 } /* Generic.Deleted */ +.highlight .ge { font-style: italic } /* Generic.Emph */ +.highlight .gr { color: #FF0000 } /* Generic.Error */ +.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ +.highlight .gi { color: #00A000 } /* Generic.Inserted */ +.highlight .go { color: #303030 } /* Generic.Output */ +.highlight .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */ +.highlight .gs { font-weight: bold } /* Generic.Strong */ +.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ +.highlight .gt { color: #0040D0 } /* Generic.Traceback */ +.highlight .kc { color: #007020; font-weight: bold } /* Keyword.Constant */ +.highlight .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */ +.highlight .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */ +.highlight .kp { color: #007020 } /* Keyword.Pseudo */ +.highlight .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */ +.highlight .kt { color: #902000 } /* Keyword.Type */ +.highlight .m { color: #208050 } /* Literal.Number */ +.highlight .s { color: #4070a0 } /* Literal.String */ +.highlight .na { color: #4070a0 } /* Name.Attribute */ +.highlight .nb { color: #007020 } /* Name.Builtin */ +.highlight .nc { color: #0e84b5; font-weight: bold } /* Name.Class */ +.highlight .no { color: #60add5 } /* Name.Constant */ +.highlight .nd { color: #555555; font-weight: bold } /* Name.Decorator */ +.highlight .ni { color: #d55537; font-weight: bold } /* Name.Entity */ +.highlight .ne { color: #007020 } /* Name.Exception */ +.highlight .nf { color: #06287e } /* Name.Function */ +.highlight .nl { color: #002070; font-weight: bold } /* Name.Label */ +.highlight .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */ +.highlight .nt { color: #062873; font-weight: bold } /* Name.Tag */ +.highlight .nv { color: #bb60d5 } /* Name.Variable */ +.highlight .ow { color: #007020; font-weight: bold } /* Operator.Word */ +.highlight .w { color: #bbbbbb } /* Text.Whitespace */ +.highlight .mf { color: #208050 } /* Literal.Number.Float */ +.highlight .mh { color: #208050 } /* Literal.Number.Hex */ +.highlight .mi { color: #208050 } /* Literal.Number.Integer */ +.highlight .mo { color: #208050 } /* Literal.Number.Oct */ +.highlight .sb { color: #4070a0 } /* Literal.String.Backtick */ +.highlight .sc { color: #4070a0 } /* Literal.String.Char */ +.highlight .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */ +.highlight .s2 { color: #4070a0 } /* Literal.String.Double */ +.highlight .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */ +.highlight .sh { color: #4070a0 } /* Literal.String.Heredoc */ +.highlight .si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */ +.highlight .sx { color: #c65d09 } /* Literal.String.Other */ +.highlight .sr { color: #235388 } /* Literal.String.Regex */ +.highlight .s1 { color: #4070a0 } /* Literal.String.Single */ +.highlight .ss { color: #517918 } /* Literal.String.Symbol */ +.highlight .bp { color: #007020 } /* Name.Builtin.Pseudo */ +.highlight .vc { color: #bb60d5 } /* Name.Variable.Class */ +.highlight .vg { color: #bb60d5 } /* Name.Variable.Global */ +.highlight .vi { color: #bb60d5 } /* Name.Variable.Instance */ +.highlight .il { color: #208050 } /* Literal.Number.Integer.Long */ \ No newline at end of file diff --git a/docs/_build/html/_static/searchtools.js b/docs/_build/html/_static/searchtools.js new file mode 100644 index 0000000..663be4c --- /dev/null +++ b/docs/_build/html/_static/searchtools.js @@ -0,0 +1,560 @@ +/* + * searchtools.js_t + * ~~~~~~~~~~~~~~~~ + * + * Sphinx JavaScript utilties for the full-text search. + * + * :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/** + * helper function to return a node containing the + * search summary for a given text. keywords is a list + * of stemmed words, hlwords is the list of normal, unstemmed + * words. the first one is used to find the occurance, the + * latter for highlighting it. + */ + +jQuery.makeSearchSummary = function(text, keywords, hlwords) { + var textLower = text.toLowerCase(); + var start = 0; + $.each(keywords, function() { + var i = textLower.indexOf(this.toLowerCase()); + if (i > -1) + start = i; + }); + start = Math.max(start - 120, 0); + var excerpt = ((start > 0) ? '...' : '') + + $.trim(text.substr(start, 240)) + + ((start + 240 - text.length) ? '...' : ''); + var rv = $('
').text(excerpt); + $.each(hlwords, function() { + rv = rv.highlightText(this, 'highlighted'); + }); + return rv; +} + + +/** + * Porter Stemmer + */ +var Stemmer = function() { + + var step2list = { + ational: 'ate', + tional: 'tion', + enci: 'ence', + anci: 'ance', + izer: 'ize', + bli: 'ble', + alli: 'al', + entli: 'ent', + eli: 'e', + ousli: 'ous', + ization: 'ize', + ation: 'ate', + ator: 'ate', + alism: 'al', + iveness: 'ive', + fulness: 'ful', + ousness: 'ous', + aliti: 'al', + iviti: 'ive', + biliti: 'ble', + logi: 'log' + }; + + var step3list = { + icate: 'ic', + ative: '', + alize: 'al', + iciti: 'ic', + ical: 'ic', + ful: '', + ness: '' + }; + + var c = "[^aeiou]"; // consonant + var v = "[aeiouy]"; // vowel + var C = c + "[^aeiouy]*"; // consonant sequence + var V = v + "[aeiou]*"; // vowel sequence + + var mgr0 = "^(" + C + ")?" + V + C; // [C]VC... is m>0 + var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1 + var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1 + var s_v = "^(" + C + ")?" + v; // vowel in stem + + this.stemWord = function (w) { + var stem; + var suffix; + var firstch; + var origword = w; + + if (w.length < 3) + return w; + + var re; + var re2; + var re3; + var re4; + + firstch = w.substr(0,1); + if (firstch == "y") + w = firstch.toUpperCase() + w.substr(1); + + // Step 1a + re = /^(.+?)(ss|i)es$/; + re2 = /^(.+?)([^s])s$/; + + if (re.test(w)) + w = w.replace(re,"$1$2"); + else if (re2.test(w)) + w = w.replace(re2,"$1$2"); + + // Step 1b + re = /^(.+?)eed$/; + re2 = /^(.+?)(ed|ing)$/; + if (re.test(w)) { + var fp = re.exec(w); + re = new RegExp(mgr0); + if (re.test(fp[1])) { + re = /.$/; + w = w.replace(re,""); + } + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1]; + re2 = new RegExp(s_v); + if (re2.test(stem)) { + w = stem; + re2 = /(at|bl|iz)$/; + re3 = new RegExp("([^aeiouylsz])\\1$"); + re4 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re2.test(w)) + w = w + "e"; + else if (re3.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + else if (re4.test(w)) + w = w + "e"; + } + } + + // Step 1c + re = /^(.+?)y$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(s_v); + if (re.test(stem)) + w = stem + "i"; + } + + // Step 2 + re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step2list[suffix]; + } + + // Step 3 + re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step3list[suffix]; + } + + // Step 4 + re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/; + re2 = /^(.+?)(s|t)(ion)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + if (re.test(stem)) + w = stem; + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1] + fp[2]; + re2 = new RegExp(mgr1); + if (re2.test(stem)) + w = stem; + } + + // Step 5 + re = /^(.+?)e$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + re2 = new RegExp(meq1); + re3 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re.test(stem) || (re2.test(stem) && !(re3.test(stem)))) + w = stem; + } + re = /ll$/; + re2 = new RegExp(mgr1); + if (re.test(w) && re2.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + + // and turn initial Y back to y + if (firstch == "y") + w = firstch.toLowerCase() + w.substr(1); + return w; + } +} + + +/** + * Search Module + */ +var Search = { + + _index : null, + _queued_query : null, + _pulse_status : -1, + + init : function() { + var params = $.getQueryParameters(); + if (params.q) { + var query = params.q[0]; + $('input[name="q"]')[0].value = query; + this.performSearch(query); + } + }, + + loadIndex : function(url) { + $.ajax({type: "GET", url: url, data: null, success: null, + dataType: "script", cache: true}); + }, + + setIndex : function(index) { + var q; + this._index = index; + if ((q = this._queued_query) !== null) { + this._queued_query = null; + Search.query(q); + } + }, + + hasIndex : function() { + return this._index !== null; + }, + + deferQuery : function(query) { + this._queued_query = query; + }, + + stopPulse : function() { + this._pulse_status = 0; + }, + + startPulse : function() { + if (this._pulse_status >= 0) + return; + function pulse() { + Search._pulse_status = (Search._pulse_status + 1) % 4; + var dotString = ''; + for (var i = 0; i < Search._pulse_status; i++) + dotString += '.'; + Search.dots.text(dotString); + if (Search._pulse_status > -1) + window.setTimeout(pulse, 500); + }; + pulse(); + }, + + /** + * perform a search for something + */ + performSearch : function(query) { + // create the required interface elements + this.out = $('#search-results'); + this.title = $('

' + _('Searching') + '

').appendTo(this.out); + this.dots = $('').appendTo(this.title); + this.status = $('

').appendTo(this.out); + this.output = $('

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 literal 0 HcmV?d00001 diff --git a/docs/_build/doctrees/doc/llvm.core.FunctionType.doctree b/docs/_build/doctrees/doc/llvm.core.FunctionType.doctree new file mode 100644 index 0000000000000000000000000000000000000000..a9bba68a5d12409639ee3ff9d7147c624e83acc0 GIT binary patch literal 9718 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 Ka=2DTJN^%R!x{Mi literal 0 HcmV?d00001 diff --git a/docs/_build/doctrees/doc/llvm.core.GlobalVariable.doctree b/docs/_build/doctrees/doc/llvm.core.GlobalVariable.doctree new file mode 100644 index 0000000000000000000000000000000000000000..463325884d3a0a7ed701d0501d6a6caf6ec428c7 GIT binary patch literal 8086 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 literal 0 HcmV?d00001 diff --git a/docs/_build/doctrees/doc/llvm.core.Instruction.doctree b/docs/_build/doctrees/doc/llvm.core.Instruction.doctree new file mode 100644 index 0000000000000000000000000000000000000000..e2925bb3142918de4bb78132b064aa3b541f64ec GIT binary patch literal 49238 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 literal 0 HcmV?d00001 diff --git a/docs/_build/doctrees/doc/llvm.core.PointerType.doctree b/docs/_build/doctrees/doc/llvm.core.PointerType.doctree new file mode 100644 index 0000000000000000000000000000000000000000..4eac0417a648ddd7d6d1007f70b8b7652fdf7f4d GIT binary patch literal 7196 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 literal 0 HcmV?d00001 diff --git a/docs/_build/doctrees/doc/llvm.core.StructType.doctree b/docs/_build/doctrees/doc/llvm.core.StructType.doctree new file mode 100644 index 0000000000000000000000000000000000000000..4bdce111f3c294d22ea5b6157c0196730e3618ab GIT binary patch literal 2148 zcmcIl`Fq<$5KU8@*iP*vy*S!Zu0jgLDo~)5qa1BH0^&%gltYNMw6>N=yPDlq90P(D z==U}MHM5eOr1?I69bgCgQK2;@42>#u#Ifr` zH|CMj%$>$1AC9xas*zGwD$7G-nYMUr;|MIeYej6ZS7IO9Q6kcqGU0N7E6~ww(qvqP zIasoqNi$M9;~J0q(A&$W9lR4Io`g0%x|9Y_m3SIf%rqOSG@L~md^EtvVD%w1)#=9r zd;(4$3J90Y2jZ=1N1AcW<+_AnoyGh3h2_*5LSzlyJzREdst}&?6WpD7DftX`a(LE+au~Uh?6X z9z_&N;uku_SKv%yZGP4BtWxAG!R=_E^w>*mmU{Rqbclh7yVUp^W$ouYcQtTQH==}> zedrsjMIJ^fb7nO7I!S7kyJH6D4QSCHJ;gVnmohmn$Z`}PbG!ocEyvHGO+VHzT)G_N2CVWOK|M@9FHA$x=S0y$q~u79@ry<> zGTyc@!YYkEWsXwCwnCmUk%la$?yZRY@&TNqO0vDy+ZR7Hx#Q}qT{z0+Hh%3lb>)T^ zG1ZZ!_>H4)Cs$-PLH5;>r3N>ttsEybnJS5zif`@0QavR?XJQ0`>8yIdY`5u(L&W2^ z&?@X`{R-ZJZgbrE`a3!;d+1b=>xM}90hYs97&as-8(x0&p+k+F(}iLO1DaGF z%ZA}Z#5Td7HrmjC*hd&b3vS({tAB>Y*~nzD>4D+eco`dy1<|R6cb%Ipt8$MnA`cfu z=B4R&mQOv>+;}x=_gsA*P}lOorqxAcZ_ywhXk&2*%QPV@-?6UGhyOO888V$syO~R<@(UeTza9>&4U>3mX%G^Q{h1JI5(n%Df zq<&bUJwhE?>FLS>b!l}cvzg|+fF$YK8g3=`#^54O&ST7n|VgZYmjomA5 zC+DHdELne8&}70%i92hwEsDI3o(6TgUjt~n@lkD<-va9UYIW`p?s`?zV9|vXZsv9I z_dA<&b94WPP0IWC@Q)Jz9Kzy^<+}m2YRLD30y?v0Veqd2|Aqx;c4Fn967Lto!N1O4 BCFuYF literal 0 HcmV?d00001 diff --git a/docs/_build/doctrees/doc/llvm.core.Type.doctree b/docs/_build/doctrees/doc/llvm.core.Type.doctree new file mode 100644 index 0000000000000000000000000000000000000000..a45218ce686d3b06564c81d68380fd50a7f0e1d9 GIT binary patch literal 21715 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 A=Kufz literal 0 HcmV?d00001 diff --git a/docs/_build/doctrees/doc/llvm.core.User.doctree b/docs/_build/doctrees/doc/llvm.core.User.doctree new file mode 100644 index 0000000000000000000000000000000000000000..39fa2f252568d650d1df399d852f570afdaa06a9 GIT binary patch literal 9119 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 literal 0 HcmV?d00001 diff --git a/docs/_build/doctrees/doc/llvm.core.VectorType.doctree b/docs/_build/doctrees/doc/llvm.core.VectorType.doctree new file mode 100644 index 0000000000000000000000000000000000000000..243cc07f17560c9a11a03ec40e1803c329099e4d GIT binary patch literal 7177 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 literal 0 HcmV?d00001 diff --git a/docs/_build/doctrees/doc/llvm.ee.EngineBuilder.doctree b/docs/_build/doctrees/doc/llvm.ee.EngineBuilder.doctree new file mode 100644 index 0000000000000000000000000000000000000000..99140f6796f99e17535422c0506a416158b3840d GIT binary patch literal 14033 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 literal 0 HcmV?d00001 diff --git a/docs/_build/doctrees/doc/llvm.ee.ExecutionEngine.doctree b/docs/_build/doctrees/doc/llvm.ee.ExecutionEngine.doctree new file mode 100644 index 0000000000000000000000000000000000000000..945c17868fe4d59562a3e025ea0b700bc08eea56 GIT binary patch literal 13526 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 literal 0 HcmV?d00001 diff --git a/docs/_build/doctrees/doc/llvm.ee.GenericValue.doctree b/docs/_build/doctrees/doc/llvm.ee.GenericValue.doctree new file mode 100644 index 0000000000000000000000000000000000000000..05da898df91180ee5c2646ba5a043fb76ac4a236 GIT binary patch literal 15924 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 literal 0 HcmV?d00001 diff --git a/docs/_build/doctrees/doc/llvm.ee.TargetData.doctree b/docs/_build/doctrees/doc/llvm.ee.TargetData.doctree new file mode 100644 index 0000000000000000000000000000000000000000..34860a0ace4f29752e58ac8fc2705ccaf278bb3f GIT binary patch literal 11729 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 literal 0 HcmV?d00001 diff --git a/docs/_build/doctrees/doc/llvm.passes.PassManager.doctree b/docs/_build/doctrees/doc/llvm.passes.PassManager.doctree new file mode 100644 index 0000000000000000000000000000000000000000..8d5dcc5e4150d960716ef390224627d05c57f128 GIT binary patch literal 6289 zcmcIo2b3Je5mmahrwfueWr>wQXb*I^2Z$u1kPwJNhd^p^gk^7br*C`E?96u0j812} zZDfp%j1$H-&N$<2oG>s%N^c zol~~`auhmlFzop@4>ELHGofg;vp5MM5h&_Mq$<8(#n|6?utP)wd&;56aBgcpDygd@466yT>B7Ac#sq z=!A&K_lh>34CH(*dsuJHQUNbkc@V&>K=u}7AL}hgN+Hx@;76*=W&aq<*u3m3xaxay z!5CX;MWH|G`=RHDyoeZ7C>M^-W*tO`gWwlwc|=aMvyL>N0nx#h5Enx+7v^8e#bVLP z7RO8sB}@#Z3zvv4wh}xH5f4M4VTfoL@|8gta%{O&WLO_Kh&5sgwWo~9>L#yQSj9i7ZuGaEMq*Yl{N$6QNi?xFzup!roIjlXAubl~^cnvN% zWzfj$sE-3*c|J$qZ(-i z^0)%)D7&T<<%R<5ELr8fib`Rqz~)lch6}7MR?Qb8HqUiDE=R_Ikkr0BUd$2T@PwJs zhZW^VwTwIw9B$O|q?`b80`^bNiQ$46Dv09>VnadX3v6E5cZ1Q{kys;E6V@p$`5=WF zFK6VbKs!y#O?9->ThKb8JmuJ-7(JR0Hv&T#xLWe<>5M!R*k@^Zb{+ei zT;d~~h07oy!IPU?JXHQvMxG0VEn04^Bb;|QgtI8dZ8M!fIVm`CJ|Hg8a(f-(!oxvq zA&AkL5GYEkqO6+8$cq58L(4J1jL%2mxz@BFg`2W9w6we!VO${Aign-Tp@NoI*OiNhQ@)%Snh?Z;rDchD$btv#cP`(QZD^ouu3(bFu63VNQaNik5=-AbcXjFd$+g1UTTtPDq6)o%pUj?jU)M(Vj_u zz{|ArX5?N(=xSMw>A;4RB(@{bkRGMgZ;C?J#9|BeET!nMA~7=BDUvo;Ero3u%g6v` zLM*tFu<8^Q9^$TLJ zZ_@IGy3Ju&g<-v$#C@@9B(V`D%sYBHAuR5$YCnN{aHAy<~0kuL#bw`loN3hidf z@5@?&)`**^O<5vD?rvOwR}~|$}OftSVv+~zB(q48v0f(UqeBkj-WT&cGkkS z76jSSbk+%j?Dnn0+0C(J`_>?f7j+gNH+XMBG009#?A*L-SMk`1iDCKL1~yEuzpgci zkljX07Os9y%g>WD zkEIOzcPDjpkCtDcC2<|4J`!JFY;_9Dh_5dtb(DNhe;Jm)qUBdplJ2RK)KEuX)AH+N zC#@sckLxHcrF*sfMvBn1e}A*d5BV*z#FWyvMW-pHr72C{iA(7|Ex${K=mfPZK0$3u zPEhG~{yoHhZ(}WezsW>WOLgEMAdE*r`ys;rk(NJ(Q9;P}#Tyj0$NgIVB#kLGXmR7)vE%A_+ zzadW_q!ja{td(3Sk$mY{^$AwY8HxFtJ%1w#5__b21}@=4uz}c zKo5)Nnnm;CMKg3_XX|}IKj^f?x!$b`681UWzhx}Tx>{n?d6{z(_+7tR@GW9VBp}36oxRzIma1?~P&D9{J zY!3I-vGk)0!xWBQt=80W24jAlnxf11aaV1CY!oR*fS4Y6rU2BCQOpR-4HLCtQfp&9 ziC6K6LFGwLOpURXNHoS)2*9_IgJOIuEYEiFa|CLvpWF_xP{6(m4%G1^ZnJqQs;CnP ziS_epiBq9WyF3t_hw4Pg53*G_?AD_2f8lQ=pmuVt9IBJ(riV^TUQ{jar*2axLxx=T z*-^DttQT&ePJtXfh~bChP5O!Qsj+hJl%+h11-RU*s?&__03~bEaZS#PA+I77RQV=6 zWSw|6v~Fahtxl)g1$@7Q0ULTM3KAC2Am}#Mj_J^(Q&DFcNRw&Q^gbtWFdB2G&*K*kLUygWV8}v0hWMhZ4k$bUsyKedpOjfJY`f&(ze^ zaBUj%Y0vCDHs6jrig<6}E;lS}^qYE!K-1wdMsa2o8nLeQ%@Qa9 Y)q-+xW$jd{cA&1ojaGYcjY`A+1tq{h?EnA( literal 0 HcmV?d00001 diff --git a/docs/_build/doctrees/doc/llvm.passes.PassManagerBuilder.doctree b/docs/_build/doctrees/doc/llvm.passes.PassManagerBuilder.doctree new file mode 100644 index 0000000000000000000000000000000000000000..465bd172f629d560dabf305b72eef93916e3e70d GIT binary patch literal 14720 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 G-S`jML(p{q literal 0 HcmV?d00001 diff --git a/docs/_build/doctrees/doc/values.doctree b/docs/_build/doctrees/doc/values.doctree new file mode 100644 index 0000000000000000000000000000000000000000..b3f14913e926458c1be16bbdadf129494880ac23 GIT binary patch literal 27612 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 Bt-=5R literal 0 HcmV?d00001 diff --git a/docs/_build/doctrees/index.doctree b/docs/_build/doctrees/index.doctree new file mode 100644 index 0000000000000000000000000000000000000000..e216ed08e02432d21a37f782eef318cb13b375a6 GIT binary patch literal 5987 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 literal 0 HcmV?d00001 diff --git a/docs/_build/html/.buildinfo b/docs/_build/html/.buildinfo new file mode 100644 index 0000000..f0c2afc --- /dev/null +++ b/docs/_build/html/.buildinfo @@ -0,0 +1,4 @@ +# Sphinx build info version 1 +# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. +config: 37862f52ab1a5aee0638e82db6615f29 +tags: fbb0d17656682115ca4d033fb2f83ba1 diff --git a/docs/_build/html/_sources/doc/comparision.txt b/docs/_build/html/_sources/doc/comparision.txt new file mode 100644 index 0000000..2f1b87b --- /dev/null +++ b/docs/_build/html/_sources/doc/comparision.txt @@ -0,0 +1,147 @@ ++--------------------------------+ +| layout: page | ++--------------------------------+ +| title: Comparison Operations | ++--------------------------------+ + +Integer Comparision # {#icmp} +============================= + +Predicates for use with ``icmp`` instruction are listed below. All of +these are integer constants defined in the ``llvm.core`` module. + +``ICMP_EQ`` +----------- + +Equality + +``ICMP_NE`` +----------- + +Inequality + +``ICMP_UGT`` +------------ + +Unsigned greater than + +``ICMP_UGE`` +------------ + +Unsigned greater than or equal + +``ICMP_ULT`` +------------ + +Unsigned less than + +``ICMP_ULE`` +------------ + +Unsigned less than or equal + +``ICMP_SGT`` +------------ + +Signed greater than + +``ICMP_SGE`` +------------ + +Signed greater than or equal + +``ICMP_SLT`` +------------ + +Signed less than + +``ICMP_SLE`` +------------ + +Signed less than or equal + +Float Comparision # {#fcmp} +=========================== + +Predicates for use with ``fcmp`` instruction are listed below. All of +these are integer constants defined in the ``llvm.core`` module. + +``FCMP_FALSE`` +-------------- + +Always false + +``FCMP_OEQ`` +------------ + +True if ordered and equal + +``FCMP_OGT`` +------------ + +True if ordered and greater than + +``FCMP_OGE`` +------------ + +True if ordered and greater than or equal + +``FCMP_OLT`` +------------ + +True if ordered and less than + +``FCMP_OLE`` +------------ + +True if ordered and less than or equal + +``FCMP_ONE`` +------------ + +True if ordered and operands are unequal + +``FCMP_ORD`` +------------ + +True if ordered (no NaNs) + +``FCMP_UNO`` +------------ + +True if unordered: ``isnan(X) | isnan(Y)`` + +``FCMP_UEQ`` +------------ + +True if unordered or equal + +``FCMP_UGT`` +------------ + +True if unordered or greater than + +``FCMP_UGE`` +------------ + +True if unordered, greater than or equal + +``FCMP_ULT`` +------------ + +True if unordered, or less than + +``FCMP_ULE`` +------------ + +True if unordered, less than or equal + +``FCMP_UNE`` +------------ + +True if unordered or not equal + +``FCMP_TRUE`` +------------- + +Always true diff --git a/docs/_build/html/_sources/doc/examples.txt b/docs/_build/html/_sources/doc/examples.txt new file mode 100644 index 0000000..9e01700 --- /dev/null +++ b/docs/_build/html/_sources/doc/examples.txt @@ -0,0 +1,12 @@ +******************************** +Examples and LLVM Tutorials +******************************** + +.. toctree:: + :maxdepth: 1 + + firstexample.rst + examples/index.rst + kaleidoscope/index.rst + + diff --git a/docs/_build/html/_sources/doc/examples/JITTutorial1.txt b/docs/_build/html/_sources/doc/examples/JITTutorial1.txt new file mode 100644 index 0000000..09f3c33 --- /dev/null +++ b/docs/_build/html/_sources/doc/examples/JITTutorial1.txt @@ -0,0 +1,36 @@ +A First Function +================== + +.. code-block:: python + + #!/usr/bin/env python + + from llvm.core import * + + #create a module + module = Module.new("tut1") + + #create a function type taking 3 32-bit integers, return a 32-bit integer + ty_int = Type.int(32) + func_type = Type.function(ty_int, (ty_int,)*3) + + #create a function of that type + mul_add = Function.new (module, func_type, "mul_add") + mul_add.calling_convention = CC_C + x = mul_add.args[0]; x.name = "x" + y = mul_add.args[1]; y.name = "y" + z = mul_add.args[2]; z.name = "z" + + #implement the function + + #new block + blk = mul_add.append_basic_block("entry") + + #IR builder + bldr = Builder.new(blk) + tmp_1 = bldr.mul(x, y, "tmp_1") + tmp_2 = bldr.add(tmp_1, z, "tmp_2") + + bldr.ret(tmp_2) + + print module diff --git a/docs/_build/html/_sources/doc/examples/JITTutorial2.txt b/docs/_build/html/_sources/doc/examples/JITTutorial2.txt new file mode 100644 index 0000000..a9a9979 --- /dev/null +++ b/docs/_build/html/_sources/doc/examples/JITTutorial2.txt @@ -0,0 +1,55 @@ +A More Complicated Function +==================== + +.. code-block:: python + + #!/usr/bin/env python + + from llvm.core import * + + #create a module + module = Module.new("tut2") + + #create a function type taking 2 integers, return a 32-bit integer + ty_int = Type.int(32) + func_type = Type.function(ty_int, (ty_int, ty_int)) + + #create a function of that type + gcd = Function.new(module, func_type, "gcd") + + #name function args + x = gcd.args[0]; x.name = "x" + y = gcd.args[1]; y.name = "y" + + #implement the function + + #blocks... + entry = gcd.append_basic_block("entry") + ret = gcd.append_basic_block("return") + cond_false = gcd.append_basic_block("cond_false") + cond_true = gcd.append_basic_block("cond_true") + cond_false_2 = gcd.append_basic_block("cond_false_2") + + #create a llvm::IRBuilder + bldr = Builder.new(entry) + x_eq_y = bldr.icmp(IPRED_EQ, x, y, "tmp") + bldr.cbranch(x_eq_y, ret, cond_false) + + bldr.position_at_end (ret) + bldr.ret(x) + + bldr.position_at_end(cond_false) + x_lt_y = bldr.icmp(IPRED_ULT, x, y, "tmp") + bldr.cbranch(x_lt_y, cond_true, cond_false_2) + + bldr.position_at_end(cond_true) + y_sub_x = bldr.sub(y, x, "tmp") + recur_1 = bldr.call(gcd, (x, y_sub_x,), "tmp") + bldr.ret(recur_1) + + bldr.position_at_end(cond_false_2) + x_sub_y = bldr.sub(x, y, "x_sub_y") + recur_2 = bldr.call(gcd, (x_sub_y, y,), "tmp") + bldr.ret(recur_2) + + print module diff --git a/docs/_build/html/_sources/doc/examples/index.txt b/docs/_build/html/_sources/doc/examples/index.txt new file mode 100644 index 0000000..0cd3532 --- /dev/null +++ b/docs/_build/html/_sources/doc/examples/index.txt @@ -0,0 +1,10 @@ +LLVM Tutorials +============== + +The following JIT tutorials were contributed by Sebastien Binet. + +.. toctree:: + :titlesonly: + + JITTutorial1.rst + JITTutorial2.rst diff --git a/docs/_build/html/_sources/doc/firstexample.txt b/docs/_build/html/_sources/doc/firstexample.txt new file mode 100644 index 0000000..0f6a4d0 --- /dev/null +++ b/docs/_build/html/_sources/doc/firstexample.txt @@ -0,0 +1,125 @@ +Examples +======== + +A Simple Function +----------------- + +Let's create a (LLVM) module containing a single function, corresponding +to the ``C`` function: + +.. code-block:: c + + int sum(int a, int b) + { + return a + b; + } + +Here's how it looks in llvmpy: + +.. code-block:: python + + #!/usr/bin/env python + + # Import the llvmpy modules. + from llvm import * + from llvm.core import * + + # Create an (empty) module. + my_module = Module.new('my_module') + + # All the types involved here are "int"s. This type is represented + # by an object of the llvm.core.Type class: + ty_int = Type.int() # by default 32 bits + + # We need to represent the class of functions that accept two integers + # and return an integer. This is represented by an object of the + # function type (llvm.core.FunctionType): + ty_func = Type.function(ty_int, [ty_int, ty_int]) + + # Now we need a function named 'sum' of this type. Functions are not + # free-standing (in llvmpy); it needs to be contained in a module. + + f_sum = my_module.add_function(ty_func, "sum") + + # Let's name the function arguments as 'a' and 'b'. + f_sum.args[0].name = "a" + f_sum.args[1].name = "b" + + # Our function needs a "basic block" -- a set of instructions that + # end with a terminator (like return, branch etc.). By convention + # the first block is called "entry". + bb = f_sum.append_basic_block("entry") + + # Let's add instructions into the block. For this, we need an + # instruction builder: + builder = Builder.new(bb) + + # OK, now for the instructions themselves. We'll create an add + # instruction that returns the sum as a value, which we'll use + # a ret instruction to return. + tmp = builder.add(f_sum.args[0], f_sum.args[1], "tmp") + builder.ret(tmp) + + # We've completed the definition now! Let's see the LLVM assembly + # language representation of what we've created: + + print my_module + +Here is the output: + +.. code-block:: llvm + + ; ModuleID = 'my_module' + + define i32 @sum(i32 %a, i32 %b) { + entry: + %tmp = add i32 %a, %b ; [#uses=1] + ret i32 %tmp + } + +Adding JIT Compilation +---------------------- + +Let's compile this function in-memory and run it. + +.. code-block:: python + + #!/usr/bin/env python + + # Import the llvmpy modules. + + from llvm import * + from llvm.core import * + from llvm.ee import * # new import: ee = Execution Engine + + #Create a module, as in the previous example. + my_module = Module.new('my_module') + ty_int = Type.int() # by default 32 bits + ty_func = Type.function(ty_int, [ty_int, ty_int]) + f_sum = my_module.add_function(ty_func, "sum") + f_sum.args[0].name = "a" + f_sum.args[1].name = "b" + bb = f_sum.append_basic_block("entry") + builder = Builder.new(bb) + tmp = builder.add(f_sum.args[0], f_sum.args[1], "tmp") + builder.ret(tmp) + + # Create an execution engine object. This will create a JIT compiler + # on platforms that support it, or an interpreter otherwise. + ee = ExecutionEngine.new(my_module) + + # The arguments needs to be passed as "GenericValue" objects. + arg1 = GenericValue.int(ty_int, 100) + arg2 = GenericValue.int(ty_int, 42) + + # Now let's compile and run! + retval = ee.run_function(f_sum, [arg1, arg2]) + + # The return value is also GenericValue. Let's print it. + print "returned", retval.as_int() + +And here's the output: + +:: + + returned 142 diff --git a/docs/_build/html/_sources/doc/functions.txt b/docs/_build/html/_sources/doc/functions.txt new file mode 100644 index 0000000..8922dd0 --- /dev/null +++ b/docs/_build/html/_sources/doc/functions.txt @@ -0,0 +1,149 @@ ++--------------------+ +| layout: page | ++--------------------+ +| title: Functions | ++--------------------+ + +Functions are represented by +`llvm.core.Function `_ objects. They are +contained within modules, and can be created either with the method +``module_obj.add_function`` or the static constructor ``Function.new``. +References to functions already present in a module can be retrieved via +``module.get_function_named`` or by the static constructor method +``Function.get``. All functions in a module can be enumerated by +iterating over ``module_obj.functions``. + + +.. code-block:: python + + # create a type, representing functions that take + an integer and return # a floating point value. ft = Type.function( + Type.float(), [ Type.int() ] ) + + # create a function of this type + f1 = module_obj.add_function(ft, "func1") + + # or equivalently, like this: + f2 = Function.new(module_obj, ft, "func2") + + # get a reference to an existing function + f3 = module_obj.get_function_named("func3") + + # or like this: + f4 = Function.get(module_obj, "func4") + + # list all function names in a module + for f in module_obj.functions: print f.name + + + +Intrinsic +========= + +References to intrinsic functions can be got via the static constructor +``intrinsic``. This returns a ``Function`` object, calling which is +equivalent to invoking the intrinsic. The ``intrinsic`` method has to be +called with a module object, an intrinsic ID (which is a numeric +constant) and a list of the types of arguments (which LLVM uses to +resolve overloaded intrinsic functions). + + +.. code-block:: python + + # get a reference to the llvm.bswap intrinsic + bswap = Function.intrinsic(mod, INTR_BSWAP, [Type.int()]) + + # call it + builder.call(bswap, [value]) + + + +Here, the constant ``INTR_BSWAP``, available from ``llvm.core``, +represents the LLVM intrinsic +`llvm.bswap `_. The +``[Type.int()]`` selects the version of ``llvm.bswap`` that has a single +32-bit integer argument. The list of intrinsic IDs defined as integer +constants in ``llvm.core``. These are: + +{% include intrinsics.csv %} + +There are also target-specific intrinsics (which correspond to that +target's CPU instructions) available, but are omitted here for brevity. +Full list can be seen from +[*intrinsic\_ids.py](https://github.com/numba/llvmpy/blob/master/llvm/*\ intrinsic\_ids.py). +See the `LLVM Language +Reference `_ for more information +on the intrinsics, and the +`test `_ +directory in the source distribution for more examples. The intrinsic ID +can be retrieved from a function object with the read-only property +``intrinsic_id``. + + **Auto-generation of Intrinsic IDs** + + A script (tool/intrgen.py in source tree) generates the intrinsic + IDs automatically. This is necessary when compiling llvmpy with a + different version of LLVM. + +Calling Convention # {#callconv} +================================ + +The function's calling convention can be set using the +``calling_convention`` property. The following (integer) constants +defined in ``llvm.core`` can be used as values: + +Value \| Equivalent LLVM Assembly Keyword \| +------\|----------------------------------\| ``CC_C`` \| ``ccc`` \| +``CC_FASTCALL`` \| ``fastcc`` \| ``CC_COLDCALL`` \| ``coldcc`` \| +``CC_X86_STDCALL`` \| ``x86_stdcallcc`` \| ``CC_X86_FASTCALL`` \| +``x86_fastcallcc`` \| + +See the `LLVM docs `_ +for more information on each. Backend-specific numbered conventions can +be directly passed as integers. + +An arbitrary string identifying which garbage collector to use can be +set or got with the property ``collector``. + +The value objects corresponding to the arguments of a function can be +got using the read-only property ``args``. These can be iterated over, +and also be indexed via integers. An example: + + +.. code-block:: python + + # list all argument names and types for arg in + fn.args: print arg.name, "of type", arg.type + + # change the name of the first argument + fn.args[0].name = "objptr" + + + +Basic blocks (see later) are contained within functions. When newly +created, a function has no basic blocks. They have to be added +explicitly, using the ``append_basic_block`` method, which adds a new, +empty basic block as the last one in the function. The first basic block +of the function can be retrieved using the ``get_entry_basic_block`` +method. The existing basic blocks can be enumerated by iterating over +using the read-only property ``basic_blocks``. The number of basic +blocks can be got via ``basic_block_count`` method. Note that +``get_entry_basic_block`` is slightly faster than ``basic_blocks[0]`` +and so is ``basic_block_count``, over ``len(f.basic_blocks)``. + + +.. code-block:: python + + # add a basic block b1 = + fn.append_basic_block("entry") + + # get the first one + b2 = fn.get_entry_basic_block() b2 = fn.basic_mdblocks[0] # slower + than previous method + + # print names of all basic blocks + for b in fn.basic_blocks: print b.name + + # get number of basic blocks + n = fn.basic_block_count n = len(fn.basic_blocks) # slower than + previous method diff --git a/docs/_build/html/_sources/doc/getting_started.txt b/docs/_build/html/_sources/doc/getting_started.txt new file mode 100644 index 0000000..d3a470b --- /dev/null +++ b/docs/_build/html/_sources/doc/getting_started.txt @@ -0,0 +1,112 @@ + +Introduction +============ + +`LLVM `_ (Low-Level Virtual Machine) provides +enough infrastructure to use it as the backend for your compiled, or +JIT-compiled language. It provides extensive optimization support, and +static and dynamic (JIT) backends for many platforms. See the website at +http://www.llvm.org/ to discover more. + +Python bindings for LLVM provides a gentler learning curve for working +with the LLVM APIs. It should also be easier to create working +prototypes and experimental languages using this medium. + +Together with `clang `_ or +`llvm-gcc `_ it also a provides a +means to quickly instrument C and C++ sources. For e.g., llvm-gcc can be +used to generate the LLVM assembly for a given C source file, which can +then be loaded and manipulated (adding profiling code to every function, +say) using a llvmpy based Python script. + +License +------- + +Both LLVM and llvmpy are distributed under (different) permissive open +source licenses. llvmpy uses the `new BSD +license `_. More +information is available +`here `_. + +Platforms +--------- + +llvmpy has been built/tested/reported to work on various GNU/Linux +flavours, BSD, Mac OS X; on i386 and amd64 architectures. Windows is not +supported, for a variety of reasons. + +Versions +-------- + +llvmpy 0.8.2 requires version 3.1 of LLVM. It may not work with +previous versions. + +llvmpy has been built and tested with Python 2.7. It should work with +earlier versions. It has not been tried with Python 3.x (patches +welcome). + + +Installation +============ + +The Git repo of llvmpy is at https://github.com/numba/llvmpy.git. +You'll need to build and install it before it can be used. At least the +following will be required for this: + +- C and C++ compilers (gcc/g++) +- Python itself +- Python development files (headers and libraries) +- LLVM, either installed or built + +On debian-based systems, the first three can be installed with the +command ``sudo apt-get install gcc g++ python python-dev``. Ensure that +your distro's repository has the appropriate version of LLVM! + +It does not matter which compiler LLVM itself was built with (``g++``, +``llvm-g++`` or any other); llvmpy can be built with any compiler. It +has been tried only with gcc/g++ though. + + +LLVM and ``--enable-pic`` +------------------------- + +The result of an LLVM build is a set of static libraries and object +files. The llvmpy contains an extension package that is built into a +shared object (\_core.so) which links to these static libraries and +object files. It is therefore required that the LLVM libraries and +object files be built with the ``-fPIC`` option (generate position +independent code). Be sure to use the ``--enable-pic`` option while +configuring LLVM (default is no PIC), like this: + +.. code-block:: bash + + $ ~/llvm ./configure --enable-pic --enable-optimized + +llvm-config +----------- + +In order to build llvmpy, it's build script needs to know from where it +can invoke the llvm helper program, ``llvm-config``. If you've installed +LLVM, then this will be available in your ``PATH``, and nothing further +needs to be done. If you've built LLVM yourself, or for any reason +``llvm-config`` is not in your ``PATH``, you'll need to pass the full +path of ``llvm-config`` to the build script. + +You'll need to be 'root' to install llvmpy. Remember that your ``PATH`` +is different from that of 'root', so even if ``llvm-config`` is in your +``PATH``, it may not be available when you do ``sudo``. + +Steps +----- + +Get 3.1 version of LLVM, build it. Make sure '--enable-pic' is passed to +LLVM's 'configure'. + +Get llvmpy and install it: + + +.. code-block:: bash + + $ git clone git@github.com:numba/llvmpy.git + $ cd llvmpy + $ python setup.py install diff --git a/docs/_build/html/_sources/doc/kaleidoscope/PythonLangImpl1.txt b/docs/_build/html/_sources/doc/kaleidoscope/PythonLangImpl1.txt new file mode 100644 index 0000000..9259d42 --- /dev/null +++ b/docs/_build/html/_sources/doc/kaleidoscope/PythonLangImpl1.txt @@ -0,0 +1,323 @@ +************************************************* +Chapter 1: Tutorial Introduction and the Lexer +************************************************* + +Written by `Chris Lattner `_ and `Max +Shawabkeh `_ + +Introduction +========= + +Welcome to the "Implementing a language with LLVM" tutorial. This +tutorial runs through the implementation of a simple language, showing +how fun and easy it can be. This tutorial will get you up and started as +well as help to build a framework you can extend to other languages. The +code in this tutorial can also be used as a playground to hack on other +LLVM specific things. + +It is useful to point out ahead of time that this tutorial is really +about teaching compiler techniques and LLVM specifically, *not* about +teaching modern and sane software engineering principles. In practice, +this means that we'll take a number of shortcuts to simplify the +exposition. If you dig in and use the code as a basis for future +projects, fixing its deficiencies shouldn't be hard. + +We've tried to put this tutorial together in a way that makes chapters +easy to skip over if you are already familiar with or are uninterested +in the various pieces. The structure of the tutorial is: + +- **`Chapter 1 <#language>`_: Introduction to the Kaleidoscope + language, and the definition of its Lexer** -- This shows where we + are going and the basic functionality that we want it to do. In order + to make this tutorial maximally understandable and hackable, we + choose to implement everything in Python instead of using lexer and + parser generators. LLVM obviously works just fine with such tools, + feel free to use one if you prefer. + +- **`Chapter 2 `_: Implementing a Parser and + AST** -- With the lexer in place, we can talk about parsing + techniques and basic AST construction. This tutorial describes + recursive descent parsing and operator precedence parsing. Nothing in + Chapters 1 or 2 is LLVM-specific, the code doesn't even import the + LLVM modules at this point. :) + +- **`Chapter 3 `_: Code generation to LLVM IR** + -- With the AST ready, we can show off how easy generation of LLVM IR + really is. + +- **`Chapter 4 `_: Adding JIT and Optimizer + support** -- Because a lot of people are interested in using LLVM as + a JIT, we'll dive right into it and show you the 3 lines it takes to + add JIT support. LLVM is also useful in many other ways, but this is + one simple and "sexy" way to shows off its power. :) + +- **`Chapter 5 `_: Extending the Language: + Control Flow** -- With the language up and running, we show how to + extend it with control flow operations (if/then/else and a 'for' + loop). This gives us a chance to talk about simple SSA construction + and control flow. + +- **`Chapter 6 `_: Extending the Language: + User-defined Operators** -- This is a silly but fun chapter that + talks about extending the language to let the user program define + their own arbitrary unary and binary operators (with assignable + precedence!). This lets us build a significant piece of the + "language" as library routines. + +- **`Chapter 7 `_: Extending the Language: + Mutable Variables** -- This chapter talks about adding user-defined + local variables along with an assignment operator. The interesting + part about this is how easy and trivial it is to construct SSA form + in LLVM: no, LLVM does *not* require your front-end to construct SSA + form! + +- **`Chapter 8 `_: Conclusion and other useful + LLVM tidbits** -- This chapter wraps up the series by talking about + potential ways to extend the language, but also includes a bunch of + pointers to info about "special topics" like adding garbage + collection support, exceptions, debugging, support for "spaghetti + stacks", and a bunch of other tips and tricks. + +By the end of the tutorial, we'll have written a bit less than 540 lines +of non-comment, non-blank, lines of code. With this small amount of +code, we'll have built up a very reasonable compiler for a non-trivial +language including a hand-written lexer, parser, AST, as well as code +generation support with a JIT compiler. While other systems may have +interesting "hello world" tutorials, I think the breadth of this +tutorial is a great testament to the strengths of LLVM and why you +should consider it if you're interested in language or compiler design. + +A note about this tutorial: we expect you to extend the language and +play with it on your own. Take the code and go crazy hacking away at it, +compilers don't need to be scary creatures - it can be a lot of fun to +play with languages! + +-------------- + +The Basic Language # {#language} +================================ + +This tutorial will be illustrated with a toy language that we'll call +"`Kaleidoscope `_\ " (derived +from "meaning beautiful, form, and view"). Kaleidoscope is a procedural +language that allows you to define functions, use conditionals, math, +etc. Over the course of the tutorial, we'll extend Kaleidoscope to +support the if/then/else construct, a for loop, user defined operators, +JIT compilation with a simple command line interface, etc. + +Because we want to keep things simple, the only datatype in Kaleidoscope +is a 64-bit floating point type. As such, all values are implicitly +double precision and the language doesn't require type declarations. +This gives the language a very nice and simple syntax. For example, the +following simple example computes `Fibonacci +numbers `_: + + +.. code-block:: + + # Compute the x'th fibonacci number. + def fib(x): + if x < 3: + return 1 + else: + return fib(x-1)+fib(x-2) + + # This expression will compute the 40th number. + fib(40) + + + +We also allow Kaleidoscope to call into standard library functions (the +LLVM JIT makes this completely trivial). This means that you can use the +'extern' keyword to define a function before you use it (this is also +useful for mutually recursive functions). For example: + + +.. code-block:: + + extern sin(arg); + extern cos(arg); + extern atan2(arg1 arg2); + + atan2(sin(0.4), cos(42)) + + + +A more interesting example is included in Chapter 6 where we write a +little Kaleidoscope application that +`displays `_ a Mandelbrot Set at various +levels of magnification. + +Lets dive into the implementation of this language! + +-------------- + +The Lexer # {#lexer} +==================== + +When it comes to implementing a language, the first thing needed is the +ability to process a text file and recognize what it says. The +traditional way to do this is to use a +`lexer `_" (aka +'scanner') to break the input up into "tokens". Each token returned by +the lexer includes a token type and potentially some metadata (e.g. the +numeric value of a number). First, we define the possibilities: + + +.. code-block:: python + + # The lexer yields one of these types for each token. + class EOFToken(object): pass + + class DefToken(object): pass + + class ExternToken(object): pass + + class IdentifierToken(object): + def __init__(self, name): + self.name = name + + class NumberToken(object): + def __init__(self, value): + self.value = value + + class CharacterToken(object): + def __init__(self, char): + self.char = char + def __eq__(self, other): + return isinstance(other, CharacterToken) and self.char == other.char + def __ne__(self, other): + return not self == other + + +Each token yielded by our lexer will be of one of the above types. For +simple tokens that are always the same, like the "def" keyword, the +lexer will yield ``DefToken()``>. Identifiers, numbers and characters, +on the other hand, have extra data, so when the lexer encounteres the +number 123.45, it will emit it as ``NumberToken(123.45)``. An identifier +``foo`` will be emitted as ``IdentifierToken('foo')``. And finally, an +unknown character like '+' will be returned as ``CharacterToken('+')``. +You may notice that we overload the equality and inequality operators +for the characters; this will later simplify character comparisons in +the parser code. + +The actual implementation of the lexer is a single function called +``Tokenize``, which takes a string and +`yields `_ +tokens. For simplicity, we will use `regular +expressions `_ to parse out the +tokens. This is terribly inefficient, but perfectly sufficient for our +needs. + +First, we define the regular expressions for our tokens. Numbers and +strings of digits, optionally followed by a period and another string of +digits. Identifiers (and keywords) are alphanumeric string starting with +a letter and comments are anything between a hash (``#``) and the end of +the line. + + +.. code-block:: python + + import re + + ... + + # Regular expressions that tokens and comments of our language. + REGEX_NUMBER = re.compile('[0-9]+(?:.[0-9]+)?') + REGEX_IDENTIFIER = re.compile('[a-zA-Z][a-zA-Z0-9]\ *') + REGEX_COMMENT = re.compile('#.*') + + +Next, let's start defining the ``Tokenize`` function itself. The first +thing we need to do is set up a loop that scans the string, while +ignoring whitespace between tokens: + + +.. code-block:: python + + def Tokenize(string): + while string: # Skip whitespace. + if string[0].isspace(): + string = string[1:] + continue + + :: + + ... + + + + + +Next we want to find out what the next token is. For this we run the +regexes we defined above on the remainder of the string. To simplify the +rest of the code, we run all three regexes each time. As mentioned +above, inefficiencies are ignored for the purpose of this tutorial: + + +.. code-block:: python + + # Run regexes. + comment_match = REGEX_COMMENT.match(string) + number_match = REGEX_NUMBER.match(string) + identifier_match = REGEX_IDENTIFIER.match(string) + + +Now we check if any of the regexes matched. For comments, we simply +ignore the captured match: + + +.. code-block:: python + + # Check if any of the regexes matched and yield + # the appropriate result. + if comment_match: + comment = comment_match.group(0) + string = string[len(comment):] + +For numbers, we yield the captured match, converted to a float and +tagged with the appropriate token type: + +.. code-block:: python + + elif number_match: + number = number_match.group(0) + yield NumberToken(float(number)) + string = string[len(number):] + +The identifier case is a little more complex. We have to check for +keywords to decide whether we have captured an identifier or a keyword: + +.. code-block:: python + + elif identifier_match: + identifier = identifier_match.group(0) + # Check if we matched a keyword. + if identifier == 'def': + yield DefToken() + elif identifier == 'extern': + yield ExternToken() + else: + yield IdentifierToken(identifier) + string = string[len(identifier):] + + +Finally, if we haven't recognized a comment, a number of an identifier, +we yield the current character as an "unknown character" token. This is +used, for example, for operators like ``+`` or ``*``: + + +.. code-block:: python + + else: # Yield the unknown character. + yield CharacterToken(string[0]) + string = string[1:] + + +Once we're done with the loop, we return a final end-of-file token: + + +.. code-block:: python + + yield EOFToken() + diff --git a/docs/_build/html/_sources/doc/kaleidoscope/PythonLangImpl2.txt b/docs/_build/html/_sources/doc/kaleidoscope/PythonLangImpl2.txt new file mode 100644 index 0000000..3a05ff8 --- /dev/null +++ b/docs/_build/html/_sources/doc/kaleidoscope/PythonLangImpl2.txt @@ -0,0 +1,963 @@ +*************************************************** +Chapter 2: Implementing a Parser and AST +*************************************************** + +Written by `Chris Lattner `_ and `Max +Shawabkeh `_ + +Introduction # {#intro} +======================= + +Welcome to Chapter 2 of the `Implementing a language with +LLVM `_ tutorial. This +chapter shows you how to use the lexer, built in `Chapter +1 `_, to build a full +`parser `_ for our Kaleidoscope +language. Once we have a parser, we'll define and build an `Abstract +Syntax Tree `_ (AST). + +The parser we will build uses a combination of `Recursive Descent +Parsing `_ and +`Operator-Precedence +Parsing `_ to +parse the Kaleidoscope language (the latter for binary expressions and +the former for everything else). Before we get to parsing though, lets +talk about the output of the parser: the Abstract Syntax Tree. + +-------------- + +The Abstract Syntax Tree (AST) # {#ast} +======================================= + +The AST for a program captures its behavior in such a way that it is +easy for later stages of the compiler (e.g. code generation) to +interpret. We basically want one object for each construct in the +language, and the AST should closely model the language. In +Kaleidoscope, we have expressions, a prototype, and a function object. +We'll start with expressions first: + + +.. code-block:: python + + # Base class for all expression nodes. class + ExpressionNode(object): pass + + # Expression class for numeric literals like "1.0". + class NumberExpressionNode(ExpressionNode): def **init**\ (self, value): + self.value = value + + + + + +The code above shows the definition of the base ExpressionNode class and +one subclass which we use for numeric literals. The important thing to +note about this code is that the NumberExpressionNode class captures the +numeric value of the literal as an instance variable. This allows later +phases of the compiler to know what the stored numeric value is. + +Right now we only create the AST, so there are no useful methods on +them. It would be very easy to add a virtual method to pretty print the +code, for example. Here are the other expression AST node definitions +that we'll use in the basic form of the Kaleidoscope language: + + +.. code-block:: python + + # Expression class for referencing a variable, + like "a". class VariableExpressionNode(ExpressionNode): def + **init**\ (self, name): self.name = name + + # Expression class for a binary operator. + class BinaryOperatorExpressionNode(ExpressionNode): def **init**\ (self, + operator, left, right): self.operator = operator self.left = left + self.right = right + + # Expression class for function calls. + class CallExpressionNode(ExpressionNode): def **init**\ (self, callee, + args): self.callee = callee self.args = args + + + +This is all (intentionally) rather straight-forward: variables capture +the variable name, binary operators capture their opcode (e.g. '+'), and +calls capture a function name as well as a list of any argument +expressions. One thing that is nice about our AST is that it captures +the language features without talking about the syntax of the language. +Note that there is no discussion about precedence of binary operators, +lexical structure, etc. + +For our basic language, these are all of the expression nodes we'll +define. Because it doesn't have conditional control flow, it isn't +Turing-complete; we'll fix that in a later installment. The two things +we need next are a way to talk about the interface to a function, and a +way to talk about functions themselves: + + +.. code-block:: python + + # This class represents the "prototype" for a + function, which captures its name, # and its argument names (thus + implicitly the number of arguments the function # takes). class + PrototypeNode(object): def **init**\ (self, name, args): self.name = + name self.args = args + + # This class represents a function definition itself. + class FunctionNode(object): def **init**\ (self, prototype, body): + self.prototype = prototype self.body = body + + + +In Kaleidoscope, functions are typed with just a count of their +arguments. Since all values are double precision floating point, the +type of each argument doesn't need to be stored anywhere. In a more +aggressive and realistic language, the ``ExpressionNode`` class would +probably have a type field. + +With this scaffolding, we can now talk about parsing expressions and +function bodies in Kaleidoscope. + +-------------- + +Parser Basics # {#parserbasics} +=============================== + +Now that we have an AST to build, we need to define the parser code to +build it. The idea here is that we want to parse something like +``x + y`` (which is returned as three tokens by the lexer) into an AST +that could be generated with calls like this: + + +.. code-block:: python + + x = VariableExpressionNode('x') y = + VariableExpressionNode('y') result = BinaryOperatorExpressionNode('+', + x, y) + + + +In order to do this, we'll start by defining a lightweight ``Parser`` +class with some basic helper routines: + + +.. code-block:: python + + class Parser(object): + + def **init**\ (self, tokens, binop_precedence): self.tokens = tokens + self.binop_precedence = binop_precedence self.Next() + + # Provide a simple token buffer. Parser.current is the current token the + # parser is looking at. Parser.Next() reads another token from the lexer + and # updates Parser.current with its results. def Next(self): + self.current = self.tokens.next() + + + +This implements a simple token buffer around the lexer. This allows us +to look one token ahead at what the lexer is returning. Every function +in our parser will assume that ``self.current`` is the current token +that needs to be parsed. Note that the first token is read as soon as +the parser is instantiated. Let us ignore the ``binop_precedence`` +parameter for now. It will be explained when we start `parsing binary +operators <#parserbinops>`_. + +With these basic helper functions, we can implement the first piece of +our grammar: numeric literals. + +-------------- + +Basic Expression Parsing # {#parserprimexprs} +============================================= + +We start with numeric literals, because they are the simplest to +process. For each production in our grammar, we'll define a function +which parses that production. For numeric literals, we have: + + +.. code-block:: python + + # numberexpr ::= number def + ParseNumberExpr(self): result = NumberExpressionNode(self.current.value) + self.Next() # consume the number. return result + + + +This method is very simple: it expects to be called when the current +token is a ``NumberToken``. It takes the current number value, creates a +``NumberExpressionNode``, advances to the next token, and finally +returns. + +There are some interesting aspects to this. The most important one is +that this routine eats all of the tokens that correspond to the +production and returns the lexer buffer with the next token (which is +not part of the grammar production) ready to go. This is a fairly +standard way to go for recursive descent parsers. For a better example, +the parenthesis operator is defined like this: + + +.. code-block:: python + + # parenexpr ::= '(' expression ')' def + ParseParenExpr(self): self.Next() # eat '('. + + :: + + contents = self.ParseExpression() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")".') + self.Next() # eat ')'. + + return contents + + + + + +This function illustrates an interesting aspect of the parser. The +function uses recursion by calling ``ParseExpression`` (we will soon see +that ``ParseExpression`` can call ``ParseParenExpr``). This is powerful +because it allows us to handle recursive grammars, and keeps each +production very simple. Note that parentheses do not cause construction +of AST nodes themselves. While we could do it this way, the most +important role of parentheses are to guide the parser and provide +grouping. Once the parser constructs the AST, parentheses are not +needed. + +The next simple production is for handling variable references and +function calls: + + +.. code-block:: python + + # identifierexpr ::= identifier \| identifier '(' + expression\* ')' def ParseIdentifierExpr(self): identifier_name = + self.current.name self.Next() # eat identifier. + + :: + + if self.current != CharacterToken('('): # Simple variable reference. + return VariableExpressionNode(identifier_name); + + # Call. + self.Next() # eat '('. + args = [] + if self.current != CharacterToken(')'): + while True: + args.append(self.ParseExpression()) + if self.current == CharacterToken(')'): + break + elif self.current != CharacterToken(','): + raise RuntimeError('Expected ")" or "," in argument list.') + self.Next() + + self.Next() # eat ')'. + return CallExpressionNode(identifier_name, args) + + + + + +This routine follows the same style as the other routines. It expects to +be called if the current token is an ``IdentifierToken``. It also has +recursion and error handling. One interesting aspect of this is that it +uses *look-ahead* to determine if the current identifier is a stand +alone variable reference or if it is a function call expression. It +handles this by checking to see if the token after the identifier is a +'(' token, constructing either a ``VariableExpressionNode`` or +``CallExpressionNode`` as appropriate. + +Now that we have all of our simple expression-parsing logic in place, we +can define a helper function to wrap it together into one entry point. +We call this class of expressions "primary" expressions, for reasons +that will become more clear `later in the +tutorial `_. In order to parse an arbitrary +primary expression, we need to determine what sort of expression it is: + + +.. code-block:: python + + # primary ::= identifierexpr \| numberexpr \| + parenexpr def ParsePrimary(self): if isinstance(self.current, + IdentifierToken): return self.ParseIdentifierExpr() elif + isinstance(self.current, NumberToken): return self.ParseNumberExpr(); + elif self.current == CharacterToken('('): return self.ParseParenExpr() + else: raise RuntimeError('Unknown token when expecting an expression.') + + + + +Now that you see the definition of this function, it is more obvious why +we can assume the state of ``Parser.current`` in the various functions. +This uses look-ahead to determine which sort of expression is being +inspected, and then parses it with a function call. + +Now that basic expressions are handled, we need to handle binary +expressions. They are a bit more complex. + +-------------- + +Binary Expression Parsing # {#parserbinops} +=========================================== + +Binary expressions are significantly harder to parse because they are +often ambiguous. For example, when given the string ``x+y*z``, the +parser can choose to parse it as either ``(x+y)*z`` or ``x+(y*z)``. With +common definitions from mathematics, we expect the later parse, because +``*`` (multiplication) has higher *precedence* than ``+`` (addition). + +There are many ways to handle this, but an elegant and efficient way is +to use `Operator-Precedence +Parsing `_. +This parsing technique uses the precedence of binary operators to guide +recursion. To start with, we need a table of precedences. Remember the +``binop_precedence`` parameter we passed to the ``Parser`` constructor? +Now is the time to use it: + + +.. code-block:: python + + def main(): # Install standard binary operators. + # 1 is lowest possible precedence. 40 is the highest. + operator_precedence = { '<': 10, '+': 20, '-': 20, '\*': 40 } + + # Run the main ``interpreter loop``. while True: + + :: + + ... + + parser = Parser(Tokenize(raw), operator_precedence) + + + + + +For the basic form of Kaleidoscope, we will only support 4 binary +operators (this can obviously be extended by you, our brave and intrepid +reader). Having a dictionary makes it easy to add new operators and +makes it clear that the algorithm doesn't depend on the specific +operators involved, but it would be easy enough to eliminate the map and +hardcode the comparisons. + +We also define a helper function to get the precedence of the current +token, or -1 if the token is not a binary operator: + + +.. code-block:: python + + # Gets the precedence of the current token, or -1 + if the token is not a binary # operator. def + GetCurrentTokenPrecedence(self): if isinstance(self.current, + CharacterToken): return self.binop_precedence.get(self.current.char, + -1) else: return -1 + + + +With the helper above defined, we can now start parsing binary +expressions. The basic idea of operator precedence parsing is to break +down an expression with potentially ambiguous binary operators into +pieces. Consider, for example, the expression ``a+b+(c+d)*e*f+g``. +Operator precedence parsing considers this as a stream of primary +expressions separated by binary operators. As such, it will first parse +the leading primary expression ``a``, then it will see the pairs +``[+, b] [+, (c+d)] [*, e] [*, f] and [+, g]``. Note that because +parentheses are primary expressions, the binary expression parser +doesn't need to worry about nested subexpressions like (c+d) at all. + +To start, an expression is a primary expression potentially followed by +a sequence of ``[binop,primaryexpr]`` pairs: + + +.. code-block:: python + + # expression ::= primary binoprhs def + ParseExpression(self): left = self.ParsePrimary() return + self.ParseBinOpRHS(left, 0) + + + +``ParseBinOpRHS`` is the function that parses the sequence of pairs for +us. It takes a precedence and a pointer to an expression for the part +that has been parsed so far. Note that ``x`` is a perfectly valid +expression: As such, ``binoprhs`` is allowed to be empty, in which case +it returns the expression that is passed into it. In our example above, +the code passes the expression for ``a`` into ``ParseBinOpRHS`` and the +current token is ``+``. + +The precedence value passed into ``ParseBinOpRHS`` indicates the \* +minimal operator precedence\* that the function is allowed to eat. For +example, if the current pair stream is ``[+, x]`` and ``ParseBinOpRHS`` +is passed in a precedence of 40, it will not consume any tokens (because +the precedence of '+' is only 20). With this in mind, ``ParseBinOpRHS`` +starts with: + + +.. code-block:: python + + # binoprhs ::= (operator primary)\* def + ParseBinOpRHS(self, left, left_precedence): # If this is a binary + operator, find its precedence. while True: precedence = + self.GetCurrentTokenPrecedence() + + :: + + # If this is a binary operator that binds at least as tightly as the + # current one, consume it; otherwise we are done. + if precedence < left_precedence: + return left + + + + + +This code gets the precedence of the current token and checks to see if +if is too low. Because we defined invalid tokens to have a precedence of +-1, this check implicitly knows that the pair-stream ends when the token +stream runs out of binary operators. If this check succeeds, we know +that the token is a binary operator and that it will be included in this +expression: + + +.. code-block:: python + + binary_operator = self.current.char self.Next() + # eat the operator. + + :: + + # Parse the primary expression after the binary operator. + right = self.ParsePrimary() + + + + + +As such, this code eats (and remembers) the binary operator and then +parses the primary expression that follows. This builds up the whole +pair, the first of which is ``[+, b]`` for the running example. + +Now that we parsed the left-hand side of an expression and one pair of +the RHS sequence, we have to decide which way the expression associates. +In particular, we could have ``(a+b) binop unparsed`` or +``a + (b binop unparsed)``. To determine this, we look ahead at +``binop`` to determine its precedence and compare it to BinOp's +precedence (which is '+' in this case): + + +.. code-block:: python + + # If binary_operator binds less tightly with + right than the operator after # right, let the pending operator take + right as its left. next_precedence = self.GetCurrentTokenPrecedence() + if precedence < next_precedence: + + + +If the precedence of the binop to the right of ``RHS`` is lower or equal +to the precedence of our current operator, then we know that the +parentheses associate as ``(a+b) binop ...``. In our example, the +current operator is ``+`` and the next operator is ``+``, we know that +they have the same precedence. In this case we'll create the AST node +for ``a+b``, and then continue parsing: + + +.. code-block:: python + + if precedence < next_precedence: ... if body + omitted ... + + :: + + # Merge left/right. + left = BinaryOperatorExpressionNode(binary_operator, left, right); + + + + + +In our example above, this will turn ``a+b+`` into ``(a+b)`` and execute +the next iteration of the loop, with ``+`` as the current token. The +code above will eat, remember, and parse ``(c+d)`` as the primary +expression, which makes the current pair equal to ``[+, (c+d)]``. It +will then evaluate the 'if' conditional above with ``*`` as the binop to +the right of the primary. In this case, the precedence of ``*`` is +higher than the precedence of ``+`` so the if condition will be entered. + +The critical question left here is +``how can the if condition parse the right hand side in full``? In +particular, to build the AST correctly for our example, it needs to get +all of ``( c + d ) * e * f`` as the RHS expression variable. The code to +do this is surprisingly simple (code from the above two blocks +duplicated for context): + + +.. code-block:: python + + # If binary_operator binds less tightly with + right than the operator after # right, let the pending operator take + right as its left. next_precedence = self.GetCurrentTokenPrecedence() + if precedence < next_precedence: right = self.ParseBinOpRHS(right, + precedence + 1) + + :: + + # Merge left/right. + left = BinaryOperatorExpressionNode(binary_operator, left, right) + + + + + +At this point, we know that the binary operator to the RHS of our +primary has higher precedence than the binop we are currently parsing. +As such, we know that any sequence of pairs whose operators are all +higher precedence than ``+`` should be parsed together and returned as +``RHS``. To do this, we recursively invoke the ``ParseBinOpRHS`` +function specifying ``precedence + 1`` as the minimum precedence +required for it to continue. In our example above, this will cause it to +return the AST node for ``(c+d)*e*f`` as RHS, which is then set as the +RHS of the '+' expression. + +Finally, on the next iteration of the while loop, the ``+g`` piece is +parsed and added to the AST. With this little bit of code (11 +non-trivial lines), we correctly handle fully general binary expression +parsing in a very elegant way. This was a whirlwind tour of this code, +and it is somewhat subtle. I recommend running through it with a few +tough examples to see how it works. + +This wraps up handling of expressions. At this point, we can point the +parser at an arbitrary token stream and build an expression from it, +stopping at the first token that is not part of the expression. Next up +we need to handle function definitions, etc. + +-------------- + +Parsing the Rest # {#parsertop} +=============================== + +The next thing missing is handling of function prototypes. In +Kaleidoscope, these are used both for 'extern' function declarations as +well as function body definitions. The code to do this is +straight-forward and not very interesting (once you've survived +expressions): + + +.. code-block:: python + + # prototype ::= id '(' id\* ')' def + ParsePrototype(self): if not isinstance(self.current, IdentifierToken): + raise RuntimeError('Expected function name in prototype.') + + :: + + function_name = self.current.name + self.Next() # eat function name. + + if self.current != CharacterToken('('): + raise RuntimeError('Expected "(" in prototype.') + self.Next() # eat '('. + + arg_names = [] + while isinstance(self.current, IdentifierToken): + arg_names.append(self.current.name) + self.Next() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")" in prototype.') + + # Success. + self.Next() # eat ')'. + + return PrototypeNode(function_name, arg_names) + + + + + +Given this, a function definition is very simple, just a prototype plus +an expression to implement the body: + + +.. code-block:: python + + # definition ::= 'def' prototype expression def + ParseDefinition(self): self.Next() # eat def. proto = + self.ParsePrototype() body = self.ParseExpression() return + FunctionNode(proto, body) + + + +In addition, we support 'extern' to declare functions like 'sin' and +'cos' as well as to support forward declaration of user functions. These +'extern's are just prototypes with no body: + + +.. code-block:: python + + # external ::= 'extern' prototype def + ParseExtern(self): self.Next() # eat extern. return + self.ParsePrototype() + + + +Finally, we'll also let the user type in arbitrary top-level expressions +and evaluate them on the fly. We will handle this by defining anonymous +nullary (zero argument) functions for them: + + +.. code-block:: python + + # toplevelexpr ::= expression def + ParseTopLevelExpr(self): proto = PrototypeNode('', []) return + FunctionNode(proto, self.ParseExpression()) + + + +Now that we have all the pieces, let's build a little driver that will +let us actually *execute* this code we've built! + +-------------- + +The Driver # {#driver} +====================== + +The driver for this simply invokes all of the parsing pieces with a +top-level dispatch loop. There isn't much interesting here, so I'll just +include the top-level loop. See `below <#code>`_ for full code. + + +.. code-block:: python + + # Run the main "interpreter loop". while True: + print 'ready>', try: raw = raw_input() except KeyboardInterrupt: return + + :: + + parser = Parser(Tokenize(raw), operator_precedence) + while True: + # top ::= definition | external | expression | EOF + if isinstance(parser.current, EOFToken): + break + if isinstance(parser.current, DefToken): + parser.HandleDefinition() + elif isinstance(parser.current, ExternToken): + parser.HandleExtern() + else: + parser.HandleTopLevelExpression() + + + + + +Here we create a new ``Parser`` for each line read, and try to parse out +all the expressions, declarations and definitions in the line. We also +allow the user to quit using Ctrl+C. + +-------------- + +Conclusions # {#conclusions} +============================ + +With just under 330 lines of commented code (200 lines of non-comment, +non-blank code), we fully defined our minimal language, including a +lexer, parser, and AST builder. With this done, the executable will +validate Kaleidoscope code and tell us if it is grammatically invalid. +For example, here is a sample interaction: + + +.. code-block:: python + + $ python kaleidoscope.py ready> def foo(x y) + x+foo(y, 4.0) Parsed a function definition. ready> def foo(x y) x+y y + Parsed a function definition. Parsed a top-level expression. ready> def + foo(x y) x+y ) Parsed a function definition. Error: Unknown token when + expecting an expression. ready> extern sin(a); Parsed an extern. ready> + ^C $ + + + +There is a lot of room for extension here. You can define new AST nodes, +extend the language in many ways, etc. In the `next +installment `_, we will describe how to generate +LLVM Intermediate Representation (IR) from the AST. + +-------------- + +Full Code Listing # {#code} +=========================== + +Here is the complete code listing for this and the previous chapter. +Note that it is fully self-contained: you don't need LLVM or any +external libraries at all for this. + + +.. code-block:: python + + #!/usr/bin/env python + + import re + + Lexer + ----- + + # The lexer yields one of these types for each token. + class EOFToken(object): pass + + class DefToken(object): pass + + class ExternToken(object): pass + + class IdentifierToken(object): def **init**\ (self, name): self.name = + name + + class NumberToken(object): def **init**\ (self, value): self.value = + value + + class CharacterToken(object): def **init**\ (self, char): self.char = + char def **eq**\ (self, other): return isinstance(other, CharacterToken) + and self.char == other.char def **ne**\ (self, other): return not self + == other + + # Regular expressions that tokens and comments of our language. + REGEX_NUMBER = re.compile('[0-9]+(?:.[0-9]+)?') REGEX_IDENTIFIER = + re.compile('[a-zA-Z][a-zA-Z0-9]\ *') REGEX_COMMENT = re.compile('#.*') + + def Tokenize(string): while string: # Skip whitespace. if + string[0].isspace(): string = string[1:] continue + + :: + + # Run regexes. + comment_match = REGEX_COMMENT.match(string) + number_match = REGEX_NUMBER.match(string) + identifier_match = REGEX_IDENTIFIER.match(string) + + # Check if any of the regexes matched and yield the appropriate result. + if comment_match: + comment = comment_match.group(0) + string = string[len(comment):] + elif number_match: + number = number_match.group(0) + yield NumberToken(float(number)) + string = string[len(number):] + elif identifier_match: + identifier = identifier_match.group(0) + # Check if we matched a keyword. + if identifier == 'def': + yield DefToken() + elif identifier == 'extern': + yield ExternToken() + else: + yield IdentifierToken(identifier) + string = string[len(identifier):] + else: + # Yield the ASCII value of the unknown character. + yield CharacterToken(string[0]) + string = string[1:] + + yield EOFToken() + + Abstract Syntax Tree (aka Parse Tree) + ------------------------------------- + + # Base class for all expression nodes. + class ExpressionNode(object): pass + + # Expression class for numeric literals like "1.0". + class NumberExpressionNode(ExpressionNode): def **init**\ (self, value): + self.value = value + + # Expression class for referencing a variable, like "a". + class VariableExpressionNode(ExpressionNode): def **init**\ (self, + name): self.name = name + + # Expression class for a binary operator. + class BinaryOperatorExpressionNode(ExpressionNode): def **init**\ (self, + operator, left, right): self.operator = operator self.left = left + self.right = right + + # Expression class for function calls. + class CallExpressionNode(ExpressionNode): def **init**\ (self, callee, + args): self.callee = callee self.args = args + + # This class represents the "prototype" for a function, which captures its name, + # and its argument names (thus implicitly the number of arguments the function + # takes). + class PrototypeNode(object): def **init**\ (self, name, args): self.name + = name self.args = args + + # This class represents a function definition itself. + class FunctionNode(object): def **init**\ (self, prototype, body): + self.prototype = prototype self.body = body + + Parser + ------ + + class Parser(object): + + def **init**\ (self, tokens, binop_precedence): self.tokens = tokens + self.binop_precedence = binop_precedence self.Next() + + # Provide a simple token buffer. Parser.current is the current token the + # parser is looking at. Parser.Next() reads another token from the lexer + and # updates Parser.current with its results. def Next(self): + self.current = self.tokens.next() + + # Gets the precedence of the current token, or -1 if the token is not a + binary # operator. def GetCurrentTokenPrecedence(self): if + isinstance(self.current, CharacterToken): return + self.binop_precedence.get(self.current.char, -1) else: return -1 + + # identifierexpr ::= identifier \| identifier '(' expression\* ')' def + ParseIdentifierExpr(self): identifier_name = self.current.name + self.Next() # eat identifier. + + :: + + if self.current != CharacterToken('('): # Simple variable reference. + return VariableExpressionNode(identifier_name) + + # Call. + self.Next() # eat '('. + args = [] + if self.current != CharacterToken(')'): + while True: + args.append(self.ParseExpression()) + if self.current == CharacterToken(')'): + break + elif self.current != CharacterToken(','): + raise RuntimeError('Expected ")" or "," in argument list.') + self.Next() + + self.Next() # eat ')'. + return CallExpressionNode(identifier_name, args) + + # numberexpr ::= number def ParseNumberExpr(self): result = + NumberExpressionNode(self.current.value) self.Next() # consume the + number. return result + + # parenexpr ::= '(' expression ')' def ParseParenExpr(self): self.Next() + # eat '('. + + :: + + contents = self.ParseExpression() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")".') + self.Next() # eat ')'. + + return contents + + # primary ::= identifierexpr \| numberexpr \| parenexpr def + ParsePrimary(self): if isinstance(self.current, IdentifierToken): return + self.ParseIdentifierExpr() elif isinstance(self.current, NumberToken): + return self.ParseNumberExpr() elif self.current == CharacterToken('('): + return self.ParseParenExpr() else: raise RuntimeError('Unknown token + when expecting an expression.') + + # binoprhs ::= (operator primary)\* def ParseBinOpRHS(self, left, + left_precedence): # If this is a binary operator, find its precedence. + while True: precedence = self.GetCurrentTokenPrecedence() + + :: + + # If this is a binary operator that binds at least as tightly as the + # current one, consume it; otherwise we are done. + if precedence < left_precedence: + return left + + binary_operator = self.current.char + self.Next() # eat the operator. + + # Parse the primary expression after the binary operator. + right = self.ParsePrimary() + + # If binary_operator binds less tightly with right than the operator after + # right, let the pending operator take right as its left. + next_precedence = self.GetCurrentTokenPrecedence() + if precedence < next_precedence: + right = self.ParseBinOpRHS(right, precedence + 1) + + # Merge left/right. + left = BinaryOperatorExpressionNode(binary_operator, left, right) + + # expression ::= primary binoprhs def ParseExpression(self): left = + self.ParsePrimary() return self.ParseBinOpRHS(left, 0) + + # prototype ::= id '(' id\* ')' def ParsePrototype(self): if not + isinstance(self.current, IdentifierToken): raise RuntimeError('Expected + function name in prototype.') + + :: + + function_name = self.current.name + self.Next() # eat function name. + + if self.current != CharacterToken('('): + raise RuntimeError('Expected "(" in prototype.') + self.Next() # eat '('. + + arg_names = [] + while isinstance(self.current, IdentifierToken): + arg_names.append(self.current.name) + self.Next() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")" in prototype.') + + # Success. + self.Next() # eat ')'. + + return PrototypeNode(function_name, arg_names) + + # definition ::= 'def' prototype expression def ParseDefinition(self): + self.Next() # eat def. proto = self.ParsePrototype() body = + self.ParseExpression() return FunctionNode(proto, body) + + # toplevelexpr ::= expression def ParseTopLevelExpr(self): proto = + PrototypeNode('', []) return FunctionNode(proto, self.ParseExpression()) + + # external ::= 'extern' prototype def ParseExtern(self): self.Next() # + eat extern. return self.ParsePrototype() + + # Top-Level parsing def HandleDefinition(self): + self.Handle(self.ParseDefinition, 'Parsed a function definition.') + + def HandleExtern(self): self.Handle(self.ParseExtern, 'Parsed an + extern.') + + def HandleTopLevelExpression(self): self.Handle(self.ParseTopLevelExpr, + 'Parsed a top-level expression.') + + def Handle(self, function, message): try: function() print message + except Exception, e: print 'Error:', e try: self.Next() # Skip for error + recovery. except: pass + + Main driver code. + ----------------- + + def main(): # Install standard binary operators. # 1 is lowest possible + precedence. 40 is the highest. operator_precedence = { '<': 10, '+': + 20, '-': 20, '\*': 40 } + + # Run the main "interpreter loop". while True: print 'ready>', try: raw + = raw_input() except KeyboardInterrupt: return + + :: + + parser = Parser(Tokenize(raw), operator_precedence) + while True: + # top ::= definition | external | expression | EOF + if isinstance(parser.current, EOFToken): + break + if isinstance(parser.current, DefToken): + parser.HandleDefinition() + elif isinstance(parser.current, ExternToken): + parser.HandleExtern() + else: + parser.HandleTopLevelExpression() + + if **name** == '**main**\ ': main() diff --git a/docs/_build/html/_sources/doc/kaleidoscope/PythonLangImpl3.txt b/docs/_build/html/_sources/doc/kaleidoscope/PythonLangImpl3.txt new file mode 100644 index 0000000..549cb7b --- /dev/null +++ b/docs/_build/html/_sources/doc/kaleidoscope/PythonLangImpl3.txt @@ -0,0 +1,979 @@ +******************************************* +Chapter 3: Code generation to LLVM IR +******************************************* + +Written by `Chris Lattner `_ and `Max +Shawabkeh `_ + +Introduction # {#intro} +======================= + +Welcome to Chapter 3 of the `Implementing a language with +LLVM `_ tutorial. This +chapter shows you how to transform the `Abstract Syntax +Tree `_, built in Chapter 2, into LLVM IR. This +will teach you a little bit about how LLVM does things, as well as +demonstrate how easy it is to use. It's much more work to build a lexer +and parser than it is to generate LLVM IR code. :) + +**Please note**: the code in this chapter and later requires llvmpy 0.6 +and LLVM 2.7. Earlier versions will most likely not work with it. Also +note that you need to use a version of this tutorial that matches your +llvmpy release: If you are using an official llvmpy release, use the +version of the documentation on the `llvmpy examples +page `_ + +-------------- + +Code Generation Setup # {#basics} +================================= + +In order to generate LLVM IR, we want some simple setup to get started. +First we define code generation methods in each AST node class: + + +.. code-block:: python + + # Expression class for numeric literals like + "1.0". class NumberExpressionNode(ExpressionNode): + + def **init**\ (self, value): self.value = value + + def CodeGen(self): ... + + # Expression class for referencing a variable, like "a". + class VariableExpressionNode(ExpressionNode): + + def **init**\ (self, name): self.name = name + + def CodeGen(self): ... + + ... + + + +The ``CodeGen`` method says to emit IR for that AST node along with all +the things it depends on, and they all return an LLVM Value object. +"Value" is the class used to represent a "`Static Single Assignment +(SSA) `_ +register" or "SSA value" in LLVM. The most distinct aspect of SSA values +is that their value is computed as the related instruction executes, and +it does not get a new value until (and if) the instruction re-executes. +In other words, there is no way to "change" an SSA value. For more +information, please read up on `Static Single +Assignment `_ +- the concepts are really quite natural once you grok them. + +We will also need to define some global variables which we will be used +during code generation: + + +.. code-block:: python + + # The LLVM module, which holds all the IR code. + g_llvm_module = Module.new('my cool jit') + + # The LLVM instruction builder. Created whenever a new function is entered. + g_llvm_builder = None + + # A dictionary that keeps track of which values are defined in the current scope + # and what their LLVM representation is. + g_named_values = {} + + + +``g_llvm_module`` is the LLVM construct that contains all of the +functions and global variables in a chunk of code. In many ways, it is +the top-level structure that the LLVM IR uses to contain code. + +``g_llvm_builder`` is a helper object that makes it easy to generate +LLVM instructions. Instances of the +`llvm.core.Builder `_ class keep track of the +current place to insert instructions and have methods to create new +instructions. Note that we do not initialize this variable; instead, it +will be initialized whenever we start generating code for a function. + +Finally, ``g_named_values`` is a dictionary that keeps track of which +values are defined in the current scope and what their LLVM +representation is. In other words, it is a symbol table for the code. In +this form of Kaleidoscope, the only things that can be referenced are +function parameters. As such, function parameters will be in this map +when generating code for their function body. + +With these basics in place, we can start talking about how to generate +code for each expression. Note that this assumes that ``g_llvm_builder`` +has been set up to generate code *into* something. For now, we'll assume +that this has already been done, and we'll just use it to emit code. + +-------------- + +Expression Code Generation # {#exprs} +===================================== + +Generating LLVM code for expression nodes is very straightforward: less +than 35 lines of commented code for all four of our expression nodes. +First we'll do numeric literals: + + +.. code-block:: python + + def CodeGen(self): return + Constant.real(Type.double(), self.value) + + + +In llvmpy, floating point numeric constants are represented with the +``llvm.core.ConstantFP`` class. To create one, we can use the static +``real()`` method in the ``llvm.core.Constant`` class. This code +basically just creates and returns a ``ConstantFP``. Note that in the +LLVM IR constants are all uniqued together and shared. For this reason, +we create the constant through a factory method instead of instantiating +one directly. + + +.. code-block:: python + + def CodeGen(self): if self.name in + g_named_values: return g_named_values[self.name] else: raise + RuntimeError('Unknown variable name: ' + self.name) + + + +References to variables are also quite simple using LLVM. In the simple +version of Kaleidoscope, we assume that the variable has already been +emitted somewhere and its value is available. In practice, the only +values that can be in the ``g_named_values`` dictionary are function +arguments. This code simply checks to see that the specified name is in +the map (if not, an unknown variable is being referenced) and returns +the value for it. In future chapters, we'll add support for `loop +induction variables `_ in the symbol table, +and for `local variables `_. + + +.. code-block:: python + + def CodeGen(self): left = self.left.CodeGen() + right = self.right.CodeGen() + + :: + + if self.operator == '+': + return g_llvm_builder.fadd(left, right, 'addtmp') + elif self.operator == '-': + return g_llvm_builder.fsub(left, right, 'subtmp') + elif self.operator == '*': + return g_llvm_builder.fmul(left, right, 'multmp') + elif self.operator == '<': + result = g_llvm_builder.fcmp(FCMP_ULT, left, right, 'cmptmp') + # Convert bool 0 or 1 to double 0.0 or 1.0. + return g_llvm_builder.uitofp(result, Type.double(), 'booltmp') + else: + raise RuntimeError('Unknown binary operator.') + + + + + +Binary operators start to get more interesting. The basic idea here is +that we recursively emit code for the left-hand side of the expression, +then the right-hand side, then we compute the result of the binary +expression depending on which operator is being used. + +In the example above, the LLVM builder class is starting to show its +value. ``g_llvm_builder`` knows where to insert the newly created +instruction, all you have to do is specify what instruction to create +(e.g. with ``add``), which operands to use (``left`` and ``right`` here) +and optionally provide a name for the generated instruction. + +One nice thing about LLVM is that the name is just a hint. For instance, +if the code above emits multiple "addtmp" variables, LLVM will +automatically provide each one with an increasing, unique numeric +suffix. Local value names for instructions are purely optional, but it +makes it much easier to read the IR dumps. + +`LLVM instructions `_ are +constrained by strict rules: for example, the Left and Right operators +of an `add instruction `_ +must have the same type, and the result type of the add must match the +operand types. Because all values in Kaleidoscope are doubles, this +makes for very simple code for add, sub and mul. + +On the other hand, LLVM specifies that the `fcmp +instruction `_ always +returns an 'i1' value (a one bit integer). The problem with this is that +Kaleidoscope wants the value to be a 0.0 or 1.0 value. In order to get +these semantics, we combine the fcmp instruction with a `uitofp +instruction `_. This +instruction converts its input integer into a floating point value by +treating the input as an unsigned value. In contrast, if we used the +`sitofp instruction `_, +the Kaleidoscope ``<`` operator would return 0.0 and -1.0, depending on +the input value. + + +.. code-block:: python + + def CodeGen(self): # Look up the name in the + global module table. callee = + g_llvm_module.get_function_named(self.callee) + + :: + + # Check for argument mismatch error. + if len(callee.args) != len(self.args): + raise RuntimeError('Incorrect number of arguments passed.') + + arg_values = [i.CodeGen() for i in self.args] + + return g_llvm_builder.call(callee, arg_values, 'calltmp') + + + + + +Code generation for function calls is quite straightforward with LLVM. +The code above initially does a function name lookup in the LLVM +Module's symbol table. Recall that the LLVM Module is the container that +holds all of the functions we are JIT'ing. By giving each function the +same name as what the user specifies, we can use the LLVM symbol table +to resolve function names for us. + +Once we have the function to call, we codegen each argument that is to +be passed in, and create an LLVM `call +instruction `_. Note that +LLVM uses the native C calling conventions by default, allowing these +calls to also call into standard library functions like "sin" and "cos", +with no additional effort. + +This wraps up our handling of the four basic expressions that we have so +far in Kaleidoscope. Feel free to go in and add some more. For example, +by browsing the `LLVM language +reference `_ you'll find several +other interesting instructions that are really easy to plug into our +basic framework. + +-------------- + +Function Code Generation # {#funcs} +=================================== + +Code generation for prototypes and functions must handle a number of +details, which make their code less beautiful than expression code +generation, but allows us to illustrate some important points. First, +let's talk about code generation for prototypes: they are used both for +function bodies and external function declarations. The code starts +with: + + +.. code-block:: python + + def CodeGen(self): # Make the function type, eg. + double(double,double). funct_type = Type.function( Type.double(), + [Type.double()] \* len(self.args), False) + + :: + + function = Function.new(g_llvm_module, funct_type, self.name) + + + + + +The call to ``Type.function`` creates the ``FunctionType`` that should +be used for a given Prototype. Since all function arguments in +Kaleidoscope are of type double, the first line creates a list of "N" +LLVM double types. It then uses the ``Type.function`` method to create a +function type that takes "N" doubles as arguments, returns one double as +a result, and that is not vararg (the False parameter indicates this). +Note that Types in LLVM are uniqued just like Constants are, so you +don't instantiate them directly. + +The final line above actually creates the function that the prototype +will correspond to. This indicates the type and name to use, as well as +which module to insert into. Note that by default, the function will +have `external +linkage <`_, which means +that the function may be defined outside the current module and/or that +it is callable by functions outside the module. The name passed in is +the name the user specified: since ``g_llvm_module`` is specified, this +name is registered in ``g_llvm_module``'s symbol table, which is used by +the function call code above. + + +.. code-block:: python + + # If the name conflicted, there was already + something with the same name. # If it has a body, don't allow + redefinition or reextern. if function.name != self.name: + function.delete() function = + g_llvm_module.get_function_named(self.name) + + + +The Module symbol table works just like the Function symbol table when +it comes to name conflicts: if a new function is created with a name was +previously added to the symbol table, it will get implicitly renamed +when added to the Module. The code above exploits this fact to determine +if there was a previous definition of this function. + +In Kaleidoscope, we choose to allow redefinitions of functions in two +cases: first, we want to allow 'extern'ing a function more than once, as +long as the prototypes for the externs match (since all arguments have +the same type, we just have to check that the number of arguments +match). Second, we want to allow 'extern'ing a function and then +defining a body for it. This is useful when defining mutually recursive +functions. + +In order to implement this, the code above first checks to see if there +is a collision on the name of the function. If so, it deletes the +function we just created (by calling ``delete``) and then calling +``get_function_named`` to get the existing function with the specified +name. + + +.. code-block:: python + + # If the function already has a body, reject + this. if not function.is_declaration: raise RuntimeError('Redefinition + of function.') + + :: + + # If F took a different number of args, reject. + if len(callee.args) != len(self.args): + raise RuntimeError('Redeclaration of a function with different number ' + 'of args.') + + + + + +In order to verify the logic above, we first check to see if the +pre-existing function is a forward declaration. Since we don't allow +anything after a full definition of the function, the code rejects this +case. If the previous reference to a function was an 'extern', we simply +verify that the number of arguments for that definition and this one +match up. If not, we emit an error. + + +.. code-block:: python + + # Set names for all arguments and add them to the + variables symbol table. for arg, arg_name in zip(function.args, + self.args): arg.name = arg_name # Add arguments to variable symbol + table. g_named_values[arg_name] = arg + + :: + + return function + + + + + +The last bit of code for prototypes loops over all of the arguments in +the function, setting the name of the LLVM Argument objects to match, +and registering the arguments in the ``g_named_values`` map for future +use by the ``VariableExpressionNode``. Note that we don't check for +conflicting argument names here (e.g. "extern foo(a b a)"). Doing so +would be very straight-forward with the mechanics we have already used +above. Once this is all set up, it returns the Function object to the +caller. + + +.. code-block:: python + + def CodeGen(self): # Clear scope. + g_named_values.clear() + + :: + + # Create a function object. + function = self.prototype.CodeGen() + + + + + +Code generation for function definitions starts out simply enough: we +just clear out the ``g_named_values`` dictionary to make sure that there +isn't anything in it from the last function we compiled and codegen the +prototype. Code generation of the prototype ensures that there is an +LLVM Function object that is ready to go for us. + + +.. code-block:: python + + # Create a new basic block to start insertion + into. block = function.append_basic_block('entry') global + g_llvm_builder g_llvm_builder = Builder.new(block) {% endhighlight + %} + + Now we get to the point where ``g_llvm_builder`` is set up. The first + line creates a new `basic + block `_ (named "entry"), + which is inserted into the function. The second line declares that the + global ``g_llvm_builder`` object is to be changed. The last line creates + a new builder that is set up to insert new instructions into the basic + block we just created. Basic blocks in LLVM are an important part of + functions that define the `Control Flow + Graph `_. Since we + don't have any control flow, our functions will only contain one block + at this point. We'll fix this in `Chapter 5 `_ :). + + {% highlight python %} # Finish off the function. try: return_value = + self.body.CodeGen() g_llvm_builder.ret(return_value) + + :: + + # Validate the generated code, checking for consistency. + function.verify() + + + + + +Once the insertion point is set up, we call the ``CodeGen`` method for +the root expression of the function. If no error happens, this emits +code to compute the expression into the entry block and returns the +value that was computed. Assuming no error, we then create an LLVM `ret +instruction `_, which +completes the function. Once the function is built, we call ``verify``, +which is provided by LLVM. This function does a variety of consistency +checks on the generated code, to determine if our compiler is doing +everything right. Using this is important: it can catch a lot of bugs. +Once the function is finished and validated, we return it. + + +.. code-block:: python + + except: function.delete() raise + + :: + + return function + + + + + +The only piece left here is handling of the error case. For simplicity, +we handle this by merely deleting the function we produced with the +``delete`` method. This allows the user to redefine a function that they +incorrectly typed in before: if we didn't delete it, it would live in +the symbol table, with a body, preventing future redefinition. + +This code does have a bug, though. Since the ``PrototypeNode::CodeGen`` +can return a previously defined forward declaration, our code can +actually delete a forward declaration. There are a number of ways to fix +this bug; see what you can come up with! Here is a testcase: + + +.. code-block:: python + + extern foo(a b) # ok, defines foo. def foo(a b) c + # error, 'c' is invalid. def bar() foo(1, 2) # error, unknown function + "foo" + + + +-------------- + +Driver Changes and Closing Thoughts # {#driver} +=============================================== + +For now, code generation to LLVM doesn't really get us much, except that +we can look at the pretty IR calls. The sample code inserts calls to +CodeGen into the ``Handle*`` functions, and then dumps out the LLVM IR. +This gives a nice way to look at the LLVM IR for simple functions. For +example: + + +.. code-block:: bash + + ready> 4+5 Read a top-level expression: define + double @0() { entry: ret double 9.000000e+00 } + + + +Note how the parser turns the top-level expression into anonymous +functions for us. This will be handy when we add JIT support in the next +chapter. Also note that the code is very literally transcribed, no +optimizations are being performed except simple constant folding done by +the Builder. We will add optimizations explicitly in the next chapter. + + +.. code-block:: bash + + ready> def foo(a b) a\ *a + 2*\ a\ *b + b*\ b Read + a function definition: define double @foo(double %a, double %b) { entry: + %multmp = fmul double %a, %a ; [#uses=1] %multmp1 = fmul double + 2.000000e+00, %a ; [#uses=1] %multmp2 = fmul double %multmp1, %b ; + [#uses=1] %addtmp = fadd double %multmp, %multmp2 ; [#uses=1] %multmp3 = + fmul double %b, %b ; [#uses=1] %addtmp4 = fadd double %addtmp, %multmp3 + ; [#uses=1] ret double %addtmp4 } + + + +This shows some simple arithmetic. Notice the striking similarity to the +LLVM builder calls that we use to create the instructions. + + +.. code-block:: bash + + ready> def bar(a) foo(a, 4.0) + bar(31337) Read a + function definition: define double @bar(double %a) { entry: %calltmp = + call double @foo(double %a, double 4.000000e+00) ; [#uses=1] %calltmp1 = + call double @bar(double 3.133700e+04) ; [#uses=1] %addtmp = fadd double + %calltmp, %calltmp1 ; [#uses=1] ret double %addtmp } + + + +This shows some function calls. Note that this function will take a long +time to execute if you call it. In the future we'll add conditional +control flow to actually make recursion useful :). + + +.. code-block:: bash + + ready> extern cos(x) Read extern: declare double + @cos(double) + + ready> cos(1.234) Read a top-level expression: define double @1() { + entry: %calltmp = call double @cos(double 1.234000e+00) ; [#uses=1] ret + double %calltmp } + + + +This shows an extern for the libm "cos" function, and a call to it. + + +.. code-block:: bash + + ready> ^C ; ModuleID = 'my cool jit' + + define double @0() { entry: ret double 9.000000e+00 } + + define double @foo(double %a, double %b) { entry: %multmp = fmul double + %a, %a ; [#uses=1] %multmp1 = fmul double 2.000000e+00, %a ; [#uses=1] + %multmp2 = fmul double %multmp1, %b ; [#uses=1] %addtmp = fadd double + %multmp, %multmp2 ; [#uses=1] %multmp3 = fmul double %b, %b ; [#uses=1] + %addtmp4 = fadd double %addtmp, %multmp3 ; [#uses=1] ret double %addtmp4 + } + + define double @bar(double %a) { entry: %calltmp = call double + @foo(double %a, double 4.000000e+00) ; [#uses=1] %calltmp1 = call double + @bar(double 3.133700e+04) ; [#uses=1] %addtmp = fadd double %calltmp, + %calltmp1 ; [#uses=1] ret double %addtmp } + + declare double @cos(double) + + define double @1() { entry: %calltmp = call double @cos(double + 1.234000e+00) ; [#uses=1] ret double %calltmp } + + + +When you quit the current demo, it dumps out the IR for the entire +module generated. Here you can see the big picture with all the +functions referencing each other. + +This wraps up the third chapter of the Kaleidoscope tutorial. Up next, +we'll describe how to `add JIT codegen and optimizer +support `_ to this so we can actually start +running code! + +-------------- + +Full Code Listing # {#code} +=========================== + +Here is the complete code listing for our running example, enhanced with +the LLVM code generator. Because this uses the llvmpy libraries, you +need to `download <../download.html>`_ and +`install <../userguide.html#install>`_ them. + + +.. code-block:: python + + #!/usr/bin/env python + + import re from llvm.core import Module, Constant, Type, Function, + Builder, FCMP_ULT + + Globals + ------- + + # The LLVM module, which holds all the IR code. + g_llvm_module = Module.new('my cool jit') + + # The LLVM instruction builder. Created whenever a new function is entered. + g_llvm_builder = None + + # A dictionary that keeps track of which values are defined in the current scope + # and what their LLVM representation is. + g_named_values = {} + + Lexer + ----- + + # The lexer yields one of these types for each token. + class EOFToken(object): pass + + class DefToken(object): pass + + class ExternToken(object): pass + + class IdentifierToken(object): def **init**\ (self, name): self.name = + name + + class NumberToken(object): def **init**\ (self, value): self.value = + value + + class CharacterToken(object): def **init**\ (self, char): self.char = + char def **eq**\ (self, other): return isinstance(other, CharacterToken) + and self.char == other.char def **ne**\ (self, other): return not self + == other + + # Regular expressions that tokens and comments of our language. + REGEX_NUMBER = re.compile('[0-9]+(?:.[0-9]+)?') REGEX_IDENTIFIER = + re.compile('[a-zA-Z][a-zA-Z0-9]\ *') REGEX_COMMENT = re.compile('#.*') + + def Tokenize(string): while string: # Skip whitespace. if + string[0].isspace(): string = string[1:] continue + + :: + + # Run regexes. + comment_match = REGEX_COMMENT.match(string) + number_match = REGEX_NUMBER.match(string) + identifier_match = REGEX_IDENTIFIER.match(string) + + # Check if any of the regexes matched and yield the appropriate result. + if comment_match: + comment = comment_match.group(0) + string = string[len(comment):] + elif number_match: + number = number_match.group(0) + yield NumberToken(float(number)) + string = string[len(number):] + elif identifier_match: + identifier = identifier_match.group(0) + # Check if we matched a keyword. + if identifier == 'def': + yield DefToken() + elif identifier == 'extern': + yield ExternToken() + else: + yield IdentifierToken(identifier) + string = string[len(identifier):] + else: + # Yield the ASCII value of the unknown character. + yield CharacterToken(string[0]) + string = string[1:] + + yield EOFToken() + + Abstract Syntax Tree (aka Parse Tree) + ------------------------------------- + + # Base class for all expression nodes. + class ExpressionNode(object): pass + + # Expression class for numeric literals like "1.0". + class NumberExpressionNode(ExpressionNode): + + def **init**\ (self, value): self.value = value + + def CodeGen(self): return Constant.real(Type.double(), self.value) + + # Expression class for referencing a variable, like "a". + class VariableExpressionNode(ExpressionNode): + + def **init**\ (self, name): self.name = name + + def CodeGen(self): if self.name in g_named_values: return + g_named_values[self.name] else: raise RuntimeError('Unknown variable + name: ' + self.name) + + # Expression class for a binary operator. + class BinaryOperatorExpressionNode(ExpressionNode): + + def **init**\ (self, operator, left, right): self.operator = operator + self.left = left self.right = right + + def CodeGen(self): left = self.left.CodeGen() right = + self.right.CodeGen() + + :: + + if self.operator == '+': + return g_llvm_builder.fadd(left, right, 'addtmp') + elif self.operator == '-': + return g_llvm_builder.fsub(left, right, 'subtmp') + elif self.operator == '*': + return g_llvm_builder.fmul(left, right, 'multmp') + elif self.operator == '<': + result = g_llvm_builder.fcmp(FCMP_ULT, left, right, 'cmptmp') + # Convert bool 0 or 1 to double 0.0 or 1.0. + return g_llvm_builder.uitofp(result, Type.double(), 'booltmp') + else: + raise RuntimeError('Unknown binary operator.') + + # Expression class for function calls. + class CallExpressionNode(ExpressionNode): + + def **init**\ (self, callee, args): self.callee = callee self.args = + args + + def CodeGen(self): # Look up the name in the global module table. callee + = g_llvm_module.get_function_named(self.callee) + + :: + + # Check for argument mismatch error. + if len(callee.args) != len(self.args): + raise RuntimeError('Incorrect number of arguments passed.') + + arg_values = [i.CodeGen() for i in self.args] + + return g_llvm_builder.call(callee, arg_values, 'calltmp') + + # This class represents the "prototype" for a function, which captures its name, + # and its argument names (thus implicitly the number of arguments the function + # takes). + class PrototypeNode(object): + + def **init**\ (self, name, args): self.name = name self.args = args + + def CodeGen(self): # Make the function type, eg. double(double,double). + funct_type = Type.function( Type.double(), [Type.double()] \* + len(self.args), False) + + :: + + function = Function.new(g_llvm_module, funct_type, self.name) + + # If the name conflicted, there was already something with the same name. + # If it has a body, don't allow redefinition or reextern. + if function.name != self.name: + function.delete() + function = g_llvm_module.get_function_named(self.name) + + # If the function already has a body, reject this. + if not function.is_declaration: + raise RuntimeError('Redefinition of function.') + + # If F took a different number of args, reject. + if len(callee.args) != len(self.args): + raise RuntimeError('Redeclaration of a function with different number ' + 'of args.') + + # Set names for all arguments and add them to the variables symbol table. + for arg, arg_name in zip(function.args, self.args): + arg.name = arg_name + # Add arguments to variable symbol table. + g_named_values[arg_name] = arg + + return function + + # This class represents a function definition itself. + class FunctionNode(object): + + def **init**\ (self, prototype, body): self.prototype = prototype + self.body = body + + def CodeGen(self): # Clear scope. g_named_values.clear() + + :: + + # Create a function object. + function = self.prototype.CodeGen() + + # Create a new basic block to start insertion into. + block = function.append_basic_block('entry') + global g_llvm_builder + g_llvm_builder = Builder.new(block) + + # Finish off the function. + try: + return_value = self.body.CodeGen() + g_llvm_builder.ret(return_value) + + # Validate the generated code, checking for consistency. + function.verify() + except: + function.delete() + raise + + return function + + Parser + ------ + + class Parser(object): + + def **init**\ (self, tokens, binop_precedence): self.tokens = tokens + self.binop_precedence = binop_precedence self.Next() + + # Provide a simple token buffer. Parser.current is the current token the + # parser is looking at. Parser.Next() reads another token from the lexer + and # updates Parser.current with its results. def Next(self): + self.current = self.tokens.next() + + # Gets the precedence of the current token, or -1 if the token is not a + binary # operator. def GetCurrentTokenPrecedence(self): if + isinstance(self.current, CharacterToken): return + self.binop_precedence.get(self.current.char, -1) else: return -1 + + # identifierexpr ::= identifier \| identifier '(' expression\* ')' def + ParseIdentifierExpr(self): identifier_name = self.current.name + self.Next() # eat identifier. + + :: + + if self.current != CharacterToken('('): # Simple variable reference. + return VariableExpressionNode(identifier_name) + + # Call. + self.Next() # eat '('. + args = [] + if self.current != CharacterToken(')'): + while True: + args.append(self.ParseExpression()) + if self.current == CharacterToken(')'): + break + elif self.current != CharacterToken(','): + raise RuntimeError('Expected ")" or "," in argument list.') + self.Next() + + self.Next() # eat ')'. + return CallExpressionNode(identifier_name, args) + + # numberexpr ::= number def ParseNumberExpr(self): result = + NumberExpressionNode(self.current.value) self.Next() # consume the + number. return result + + # parenexpr ::= '(' expression ')' def ParseParenExpr(self): self.Next() + # eat '('. + + :: + + contents = self.ParseExpression() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")".') + self.Next() # eat ')'. + + return contents + + # primary ::= identifierexpr \| numberexpr \| parenexpr def + ParsePrimary(self): if isinstance(self.current, IdentifierToken): return + self.ParseIdentifierExpr() elif isinstance(self.current, NumberToken): + return self.ParseNumberExpr() elif self.current == CharacterToken('('): + return self.ParseParenExpr() else: raise RuntimeError('Unknown token + when expecting an expression.') + + # binoprhs ::= (operator primary)\* def ParseBinOpRHS(self, left, + left_precedence): # If this is a binary operator, find its precedence. + while True: precedence = self.GetCurrentTokenPrecedence() + + :: + + # If this is a binary operator that binds at least as tightly as the + # current one, consume it; otherwise we are done. + if precedence < left_precedence: + return left + + binary_operator = self.current.char + self.Next() # eat the operator. + + # Parse the primary expression after the binary operator. + right = self.ParsePrimary() + + # If binary_operator binds less tightly with right than the operator after + # right, let the pending operator take right as its left. + next_precedence = self.GetCurrentTokenPrecedence() + if precedence < next_precedence: + right = self.ParseBinOpRHS(right, precedence + 1) + + # Merge left/right. + left = BinaryOperatorExpressionNode(binary_operator, left, right) + + # expression ::= primary binoprhs def ParseExpression(self): left = + self.ParsePrimary() return self.ParseBinOpRHS(left, 0) + + # prototype ::= id '(' id\* ')' def ParsePrototype(self): if not + isinstance(self.current, IdentifierToken): raise RuntimeError('Expected + function name in prototype.') + + :: + + function_name = self.current.name + self.Next() # eat function name. + + if self.current != CharacterToken('('): + raise RuntimeError('Expected "(" in prototype.') + self.Next() # eat '('. + + arg_names = [] + while isinstance(self.current, IdentifierToken): + arg_names.append(self.current.name) + self.Next() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")" in prototype.') + + # Success. + self.Next() # eat ')'. + + return PrototypeNode(function_name, arg_names) + + # definition ::= 'def' prototype expression def ParseDefinition(self): + self.Next() # eat def. proto = self.ParsePrototype() body = + self.ParseExpression() return FunctionNode(proto, body) + + # toplevelexpr ::= expression def ParseTopLevelExpr(self): proto = + PrototypeNode('', []) return FunctionNode(proto, self.ParseExpression()) + + # external ::= 'extern' prototype def ParseExtern(self): self.Next() # + eat extern. return self.ParsePrototype() + + # Top-Level parsing def HandleDefinition(self): + self.Handle(self.ParseDefinition, 'Read a function definition:') + + def HandleExtern(self): self.Handle(self.ParseExtern, 'Read an extern:') + + def HandleTopLevelExpression(self): self.Handle(self.ParseTopLevelExpr, + 'Read a top-level expression:') + + def Handle(self, function, message): try: print message, + function().CodeGen() except Exception, e: print 'Error:', e try: + self.Next() # Skip for error recovery. except: pass + + Main driver code. + ----------------- + + def main(): # Install standard binary operators. # 1 is lowest possible + precedence. 40 is the highest. operator_precedence = { '<': 10, '+': + 20, '-': 20, '\*': 40 } + + # Run the main "interpreter loop". while True: print 'ready>', try: raw + = raw_input() except KeyboardInterrupt: break + + :: + + parser = Parser(Tokenize(raw), operator_precedence) + while True: + # top ::= definition | external | expression | EOF + if isinstance(parser.current, EOFToken): + break + if isinstance(parser.current, DefToken): + parser.HandleDefinition() + elif isinstance(parser.current, ExternToken): + parser.HandleExtern() + else: + parser.HandleTopLevelExpression() + + # Print out all of the generated code. print '', g_llvm_module + + if **name** == '**main**\ ': main() diff --git a/docs/_build/html/_sources/doc/kaleidoscope/PythonLangImpl4.txt b/docs/_build/html/_sources/doc/kaleidoscope/PythonLangImpl4.txt new file mode 100644 index 0000000..da6a5d8 --- /dev/null +++ b/docs/_build/html/_sources/doc/kaleidoscope/PythonLangImpl4.txt @@ -0,0 +1,808 @@ +************************************************* +Chapter 4: Adding JIT and Optimizer Support +************************************************* + +Written by `Chris Lattner `_ and `Max +Shawabkeh `_ + +Introduction # {#intro} +======================= + +Welcome to Chapter 4 of the `Implementing a language with +LLVM `_ tutorial. Chapters +1-3 described the implementation of a simple language and added support +for generating LLVM IR. This chapter describes two new techniques: +adding optimizer support to your language, and adding JIT compiler +support. These additions will demonstrate how to get nice, efficient +code for the Kaleidoscope language. + +-------------- + +Trivial Constant Folding # {#trivialconstfold} +============================================== + +Our demonstration for Chapter 3 is elegant and easy to extend. +Unfortunately, it does not produce wonderful code. The LLVM Builder, +however, does give us obvious optimizations when compiling simple code: + + +.. code-block:: bash + + ready> def test(x) 1+2+x Read function definition: + define double @test(double %x) { entry: %addtmp = fadd double + 3.000000e+00, %x ret double %addtmp } + + + +This code is not a literal transcription of the AST built by parsing the +input. That would be: + + +.. code-block:: bash + + ready> def test(x) 1+2+x Read function definition: + define double @test(double %x) { entry: %addtmp = fadd double + 2.000000e+00, 1.000000e+00 %addtmp1 = fadd double %addtmp, %x ret double + %addtmp1 } + + + +Constant folding, as seen above, in particular, is a very common and +very important optimization: so much so that many language implementors +implement constant folding support in their AST representation. + +With LLVM, you don't need this support in the AST. Since all calls to +build LLVM IR go through the LLVM IR builder, the builder itself checked +to see if there was a constant folding opportunity when you call it. If +so, it just does the constant fold and return the constant instead of +creating an instruction. + +Well, that was easy :). In practice, we recommend always using +``llvm.core.Builder`` when generating code like this. It has no +"syntactic overhead" for its use (you don't have to uglify your compiler +with constant checks everywhere) and it can dramatically reduce the +amount of LLVM IR that is generated in some cases (particular for +languages with a macro preprocessor or that use a lot of constants). + +On the other hand, the ``Builder`` is limited by the fact that it does +all of its analysis inline with the code as it is built. If you take a +slightly more complex example: + + +.. code-block:: bash + + ready> def test(x) (1+2+x)\*(x+(1+2)) Read a + function definition: define double @test(double %x) { entry: %addtmp = + fadd double 3.000000e+00, %x ; [#uses=1] %addtmp1 = fadd double %x, + 3.000000e+00 ; [#uses=1] %multmp = fmul double %addtmp, %addtmp1 ; + [#uses=1] ret double %multmp } + + + +In this case, the LHS and RHS of the multiplication are the same value. +We'd really like to see this generate"``tmp = x+3; result = tmp*tmp;`` +instead of computing ``x+3`` twice. + +Unfortunately, no amount of local analysis will be able to detect and +correct this. This requires two transformations: reassociation of +expressions (to make the add's lexically identical) and Common +Subexpression Elimination (CSE) to delete the redundant add instruction. +Fortunately, LLVM provides a broad range of optimizations that you can +use, in the form of "passes". + +-------------- + +LLVM Optimization Passes # {#optimizerpasses} +============================================= + +LLVM provides many optimization passes, which do many different sorts of +things and have different tradeoffs. Unlike other systems, LLVM doesn't +hold to the mistaken notion that one set of optimizations is right for +all languages and for all situations. LLVM allows a compiler implementor +to make complete decisions about what optimizations to use, in which +order, and in what situation. + +As a concrete example, LLVM supports both "whole module" passes, which +look across as large of body of code as they can (often a whole file, +but if run at link time, this can be a substantial portion of the whole +program). It also supports and includes "per-function" passes which just +operate on a single function at a time, without looking at other +functions. For more information on passes and how they are run, see the +`How to Write a Pass `_ +document and the `List of LLVM +Passes `_. + +For Kaleidoscope, we are currently generating functions on the fly, one +at a time, as the user types them in. We aren't shooting for the +ultimate optimization experience in this setting, but we also want to +catch the easy and quick stuff where possible. As such, we will choose +to run a few per-function optimizations as the user types the function +in. If we wanted to make a "static Kaleidoscope compiler", we would use +exactly the code we have now, except that we would defer running the +optimizer until the entire file has been parsed. + +In order to get per-function optimizations going, we need to set up a +`FunctionPassManager `_ +to hold and organize the LLVM optimizations that we want to run. Once we +have that, we can add a set of optimizations to run. The code looks like +this: + + +.. code-block:: python + + # The function optimization passes manager. + g_llvm_pass_manager = FunctionPassManager.new(g_llvm_module) + + # The LLVM execution engine. + g_llvm_executor = ExecutionEngine.new(g_llvm_module) + + ... + + def main(): # Set up the optimizer pipeline. Start with registering info + about how the # target lays out data structures. + g_llvm_pass_manager.add(g_llvm_executor.target_data) # Do simple + "peephole" optimizations and bit-twiddling optzns. + g_llvm_pass_manager.add(PASS_INSTRUCTION_COMBINING) # Reassociate + expressions. g_llvm_pass_manager.add(PASS_REASSOCIATE) # Eliminate + Common SubExpressions. g_llvm_pass_manager.add(PASS_GVN) # Simplify + the control flow graph (deleting unreachable blocks, etc). + g_llvm_pass_manager.add(PASS_CFG_SIMPLIFICATION) + + g_llvm_pass_manager.initialize() + + + +This code defines a ``FunctionPassManager``, ``g_llvm_pass_manager``. +Once it is set up, we use a series of "add" calls to add a bunch of LLVM +passes. The first pass is basically boilerplate, it adds a pass so that +later optimizations know how the data structures in the program are laid +out. (The "``g_llvm_executor``\ " variable is related to the JIT, which +we will get to in the next section.) In this case, we choose to add 4 +optimization passes. The passes we chose here are a pretty standard set +of "cleanup" optimizations that are useful for a wide variety of code. I +won't delve into what they do but, believe me, they are a good starting +place :). + +Once the pass manager is set up, we need to make use of it. We do this +by running it after our newly created function is constructed (in +``FunctionNode.CodeGen``), but before it is returned to the client: + + +.. code-block:: python + + return_value = self.body.CodeGen() + g_llvm_builder.ret(return_value) + + :: + + # Validate the generated code, checking for consistency. + function.verify() + + # Optimize the function. + g_llvm_pass_manager.run(function) + + + + + +As you can see, this is pretty straightforward. The +``FunctionPassManager`` optimizes and updates the LLVM Function in +place, improving (hopefully) its body. With this in place, we can try +our test above again: + + +.. code-block:: bash + + ready> def test(x) (1+2+x)\*(x+(1+2)) Read a + function definition: define double @test(double %x) { entry: %addtmp = + fadd double %x, 3.000000e+00 ; [#uses=2] %multmp = fmul double %addtmp, + %addtmp ; [#uses=1] ret double %multmp } + + + +As expected, we now get our nicely optimized code, saving a floating +point add instruction from every execution of this function. + +LLVM provides a wide variety of optimizations that can be used in +certain circumstances. Some `documentation about the various +passes `_ is available, but it +isn't very complete. Another good source of ideas can come from looking +at the passes that ``llvm-gcc`` or ``llvm-ld`` run to get started. The +``opt`` tool allows you to experiment with passes from the command line, +so you can see if they do anything. + +Now that we have reasonable code coming out of our front-end, lets talk +about executing it! + +-------------- + +Adding a JIT Compiler # {#jit} +============================== + +Code that is available in LLVM IR can have a wide variety of tools +applied to it. For example, you can run optimizations on it (as we did +above), you can dump it out in textual or binary forms, you can compile +the code to an assembly file (.s) for some target, or you can JIT +compile it. The nice thing about the LLVM IR representation is that it +is the "common currency" between many different parts of the compiler. + +In this section, we'll add JIT compiler support to our interpreter. The +basic idea that we want for Kaleidoscope is to have the user enter +function bodies as they do now, but immediately evaluate the top-level +expressions they type in. For example, if they type in "1 + 2", we +should evaluate and print out 3. If they define a function, they should +be able to call it from the command line. + +In order to do this, we first declare and initialize the JIT. This is +done by adding and initializing a global variable: + + +.. code-block:: python + + # The LLVM execution engine. g_llvm_executor = + ExecutionEngine.new(g_llvm_module) + + + +This creates an abstract "Execution Engine" which can be either a JIT +compiler or the LLVM interpreter. LLVM will automatically pick a JIT +compiler for you if one is available for your platform, otherwise it +will fall back to the interpreter. + +Once the ``ExecutionEngine`` is created, the JIT is ready to be used. We +can use the ``run_function`` method of the execution engine to execute a +compiled function and get its return value. In our case, this means that +we can change the code that parses a top-level expression to look like +this: + + +.. code-block:: python + + def HandleTopLevelExpression(self): try: function + = self.ParseTopLevelExpr().CodeGen() result = + g_llvm_executor.run_function(function, []) print 'Evaluated to:', + result.as_real(Type.double()) except Exception, e: print 'Error:', e + try: self.Next() # Skip for error recovery. except: pass {% endhighlight + %} + + Recall that we compile top-level expressions into a self-contained LLVM + function that takes no arguments and returns the computed double. + + With just these two changes, lets see how Kaleidoscope works now! + + {% highlight python %} ready> 4+5 Read a top level expression: define + double @0() { entry: ret double 9.000000e+00 } + + Evaluated to: 9.0 + + + +Well this looks like it is basically working. The dump of the function +shows the "no argument function that always returns double" that we +synthesize for each top-level expression that is typed in. This +demonstrates very basic functionality, but can we do more? + + +.. code-block:: python + + ready> def testfunc(x y) x + y\*2 Read a function + definition: define double @testfunc(double %x, double %y) { entry: + %multmp = fmul double %y, 2.000000e+00 ; [#uses=1] %addtmp = fadd double + %multmp, %x ; [#uses=1] ret double %addtmp } + + ready> testfunc(4, 10) Read a top level expression: define double @0() { + entry: %calltmp = call double @testfunc(double 4.000000e+00, double + 1.000000e+01) ; [#uses=1] ret double %calltmp } + + *Evaluated to: 24.0* + + + +This illustrates that we can now call user code, but there is something +a bit subtle going on here. Note that we only invoke the JIT on the +anonymous functions that *call testfunc*, but we never invoked it on +*testfunc* itself. What actually happened here is that the JIT scanned +for all non-JIT'd functions transitively called from the anonymous +function and compiled all of them before returning from +``run_function()``. + +The JIT provides a number of other more advanced interfaces for things +like freeing allocated machine code, rejit'ing functions to update them, +etc. However, even with this simple code, we get some surprisingly +powerful capabilities - check this out (I removed the dump of the +anonymous functions, you should get the idea by now :) : + + +.. code-block:: bash + + ready> extern sin(x) Read an extern: declare double + @sin(double) + + ready> extern cos(x) Read an extern: declare double @cos(double) + + ready> sin(1.0) *Evaluated to: 0.841470984808* + + ready> def foo(x) sin(x)\ *sin(x) + cos(x)*\ cos(x) Read a function + definition: define double @foo(double %x) { entry: %calltmp = call + double @sin(double %x) ; [#uses=1] %calltmp1 = call double @sin(double + %x) ; [#uses=1] %multmp = fmul double %calltmp, %calltmp1 ; [#uses=1] + %calltmp2 = call double @cos(double %x) ; [#uses=1] %calltmp3 = call + double @cos(double %x) ; [#uses=1] %multmp4 = fmul double %calltmp2, + %calltmp3 ; [#uses=1] %addtmp = fadd double %multmp, %multmp4 ; + [#uses=1] ret double %addtmp } + + ready> foo(4.0) *Evaluated to: 1.000000* + + + +Whoa, how does the JIT know about sin and cos? The answer is +surprisingly simple: in this example, the JIT started execution of a +function and got to a function call. It realized that the function was +not yet JIT compiled and invoked the standard set of routines to resolve +the function. In this case, there is no body defined for the function, +so the JIT ended up calling ``dlsym("sin")`` on the Python process that +is hosting our Kaleidoscope prompt. Since ``sin`` is defined within the +JIT's address space, it simply patches up calls in the module to call +the libm version of ``sin`` directly. + +One interesting application of this is that we can now extend the +language by writing arbitrary C++ code to implement operations. For +example, we can create a C file with the following simple function: + + +.. code-block:: c + + #include + + double putchard(double x) { putchar((char)x); return 0; } {% + endhighlight %} + + We can then compile this into a shared library with GCC: + + {% highlight bash %} gcc -shared -fPIC -o putchard.so putchard.c {% + endhighlight %} + + Now we can load this library into the Python process using + ``llvm.core.load_library_permanently`` and access it from Kaleidoscope + to produce simple output to the console: + + {% highlight python %} >>> import llvm.core >>> + llvm.core.load_library_permanently('/home/max/llvmpy-tutorial/putchard.so') + >>> import kaleidoscope >>> kaleidoscope.main() ready> extern + putchard(x) Read an extern: declare double @putchard(double) + + ready> putchard(65) + putchard(66) + putchard(67) + putchard(10) *ABC* + Evaluated to: 0.0 + + + +Similar code could be used to implement file I/O, console input, and +many other capabilities in Kaleidoscope. + +This completes the JIT and optimizer chapter of the Kaleidoscope +tutorial. At this point, we can compile a non-Turing-complete +programming language, optimize and JIT compile it in a user-driven way. +Next up we'll look into `extending the language with control flow +constructs `_, tackling some interesting LLVM IR +issues along the way. + +-------------- + +Full Code Listing # {#code} +=========================== + +Here is the complete code listing for our running example, enhanced with +the LLVM JIT and optimizer: + + +.. code-block:: python + + #!/usr/bin/env python + + import re from llvm.core import Module, Constant, Type, Function, + Builder, FCMP_ULT from llvm.ee import ExecutionEngine, TargetData from + llvm.passes import FunctionPassManager from llvm.passes import + (PASS_INSTRUCTION_COMBINING, PASS_REASSOCIATE, PASS_GVN, + PASS_CFG_SIMPLIFICATION) + + Globals + ------- + + # The LLVM module, which holds all the IR code. + g_llvm_module = Module.new('my cool jit') + + # The LLVM instruction builder. Created whenever a new function is entered. + g_llvm_builder = None + + # A dictionary that keeps track of which values are defined in the current scope + # and what their LLVM representation is. + g_named_values = {} + + # The function optimization passes manager. + g_llvm_pass_manager = FunctionPassManager.new(g_llvm_module) + + # The LLVM execution engine. + g_llvm_executor = ExecutionEngine.new(g_llvm_module) + + Lexer + ----- + + # The lexer yields one of these types for each token. + class EOFToken(object): pass + + class DefToken(object): pass + + class ExternToken(object): pass + + class IdentifierToken(object): def **init**\ (self, name): self.name = + name + + class NumberToken(object): def **init**\ (self, value): self.value = + value + + class CharacterToken(object): def **init**\ (self, char): self.char = + char def **eq**\ (self, other): return isinstance(other, CharacterToken) + and self.char == other.char def **ne**\ (self, other): return not self + == other + + # Regular expressions that tokens and comments of our language. + REGEX_NUMBER = re.compile('[0-9]+(?:.[0-9]+)?') REGEX_IDENTIFIER = + re.compile('[a-zA-Z][a-zA-Z0-9]\ *') REGEX_COMMENT = re.compile('#.*') + + def Tokenize(string): while string: # Skip whitespace. if + string[0].isspace(): string = string[1:] continue + + :: + + # Run regexes. + comment_match = REGEX_COMMENT.match(string) + number_match = REGEX_NUMBER.match(string) + identifier_match = REGEX_IDENTIFIER.match(string) + + # Check if any of the regexes matched and yield the appropriate result. + if comment_match: + comment = comment_match.group(0) + string = string[len(comment):] + elif number_match: + number = number_match.group(0) + yield NumberToken(float(number)) + string = string[len(number):] + elif identifier_match: + identifier = identifier_match.group(0) + # Check if we matched a keyword. + if identifier == 'def': + yield DefToken() + elif identifier == 'extern': + yield ExternToken() + else: + yield IdentifierToken(identifier) + string = string[len(identifier):] + else: + # Yield the ASCII value of the unknown character. + yield CharacterToken(string[0]) + string = string[1:] + + yield EOFToken() + + Abstract Syntax Tree (aka Parse Tree) + ------------------------------------- + + # Base class for all expression nodes. + class ExpressionNode(object): pass + + # Expression class for numeric literals like "1.0". + class NumberExpressionNode(ExpressionNode): + + def **init**\ (self, value): self.value = value + + def CodeGen(self): return Constant.real(Type.double(), self.value) + + # Expression class for referencing a variable, like "a". + class VariableExpressionNode(ExpressionNode): + + def **init**\ (self, name): self.name = name + + def CodeGen(self): if self.name in g_named_values: return + g_named_values[self.name] else: raise RuntimeError('Unknown variable + name: ' + self.name) + + # Expression class for a binary operator. + class BinaryOperatorExpressionNode(ExpressionNode): + + def **init**\ (self, operator, left, right): self.operator = operator + self.left = left self.right = right + + def CodeGen(self): left = self.left.CodeGen() right = + self.right.CodeGen() + + :: + + if self.operator == '+': + return g_llvm_builder.fadd(left, right, 'addtmp') + elif self.operator == '-': + return g_llvm_builder.fsub(left, right, 'subtmp') + elif self.operator == '*': + return g_llvm_builder.fmul(left, right, 'multmp') + elif self.operator == '<': + result = g_llvm_builder.fcmp(FCMP_ULT, left, right, 'cmptmp') + # Convert bool 0 or 1 to double 0.0 or 1.0. + return g_llvm_builder.uitofp(result, Type.double(), 'booltmp') + else: + raise RuntimeError('Unknown binary operator.') + + # Expression class for function calls. + class CallExpressionNode(ExpressionNode): + + def **init**\ (self, callee, args): self.callee = callee self.args = + args + + def CodeGen(self): # Look up the name in the global module table. callee + = g_llvm_module.get_function_named(self.callee) + + :: + + # Check for argument mismatch error. + if len(callee.args) != len(self.args): + raise RuntimeError('Incorrect number of arguments passed.') + + arg_values = [i.CodeGen() for i in self.args] + + return g_llvm_builder.call(callee, arg_values, 'calltmp') + + # This class represents the "prototype" for a function, which captures its name, + # and its argument names (thus implicitly the number of arguments the function + # takes). + class PrototypeNode(object): + + def **init**\ (self, name, args): self.name = name self.args = args + + def CodeGen(self): # Make the function type, eg. double(double,double). + funct_type = Type.function( Type.double(), [Type.double()] \* + len(self.args), False) + + :: + + function = Function.new(g_llvm_module, funct_type, self.name) + + # If the name conflicted, there was already something with the same name. + # If it has a body, don't allow redefinition or reextern. + if function.name != self.name: + function.delete() + function = g_llvm_module.get_function_named(self.name) + + # If the function already has a body, reject this. + if not function.is_declaration: + raise RuntimeError('Redefinition of function.') + + # If F took a different number of args, reject. + if len(callee.args) != len(self.args): + raise RuntimeError('Redeclaration of a function with different number ' + 'of args.') + + # Set names for all arguments and add them to the variables symbol table. + for arg, arg_name in zip(function.args, self.args): + arg.name = arg_name + # Add arguments to variable symbol table. + g_named_values[arg_name] = arg + + return function + + # This class represents a function definition itself. + class FunctionNode(object): + + def **init**\ (self, prototype, body): self.prototype = prototype + self.body = body + + def CodeGen(self): # Clear scope. g_named_values.clear() + + :: + + # Create a function object. + function = self.prototype.CodeGen() + + # Create a new basic block to start insertion into. + block = function.append_basic_block('entry') + global g_llvm_builder + g_llvm_builder = Builder.new(block) + + # Finish off the function. + try: + return_value = self.body.CodeGen() + g_llvm_builder.ret(return_value) + + # Validate the generated code, checking for consistency. + function.verify() + + # Optimize the function. + g_llvm_pass_manager.run(function) + except: + function.delete() + raise + + return function + + Parser + ------ + + class Parser(object): + + def **init**\ (self, tokens, binop_precedence): self.tokens = tokens + self.binop_precedence = binop_precedence self.Next() + + # Provide a simple token buffer. Parser.current is the current token the + # parser is looking at. Parser.Next() reads another token from the lexer + and # updates Parser.current with its results. def Next(self): + self.current = self.tokens.next() + + # Gets the precedence of the current token, or -1 if the token is not a + binary # operator. def GetCurrentTokenPrecedence(self): if + isinstance(self.current, CharacterToken): return + self.binop_precedence.get(self.current.char, -1) else: return -1 + + # identifierexpr ::= identifier \| identifier '(' expression\* ')' def + ParseIdentifierExpr(self): identifier_name = self.current.name + self.Next() # eat identifier. + + :: + + if self.current != CharacterToken('('): # Simple variable reference. + return VariableExpressionNode(identifier_name) + + # Call. + self.Next() # eat '('. + args = [] + if self.current != CharacterToken(')'): + while True: + args.append(self.ParseExpression()) + if self.current == CharacterToken(')'): + break + elif self.current != CharacterToken(','): + raise RuntimeError('Expected ")" or "," in argument list.') + self.Next() + + self.Next() # eat ')'. + return CallExpressionNode(identifier_name, args) + + # numberexpr ::= number def ParseNumberExpr(self): result = + NumberExpressionNode(self.current.value) self.Next() # consume the + number. return result + + # parenexpr ::= '(' expression ')' def ParseParenExpr(self): self.Next() + # eat '('. + + :: + + contents = self.ParseExpression() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")".') + self.Next() # eat ')'. + + return contents + + # primary ::= identifierexpr \| numberexpr \| parenexpr def + ParsePrimary(self): if isinstance(self.current, IdentifierToken): return + self.ParseIdentifierExpr() elif isinstance(self.current, NumberToken): + return self.ParseNumberExpr() elif self.current == CharacterToken('('): + return self.ParseParenExpr() else: raise RuntimeError('Unknown token + when expecting an expression.') + + # binoprhs ::= (operator primary)\* def ParseBinOpRHS(self, left, + left_precedence): # If this is a binary operator, find its precedence. + while True: precedence = self.GetCurrentTokenPrecedence() + + :: + + # If this is a binary operator that binds at least as tightly as the + # current one, consume it; otherwise we are done. + if precedence < left_precedence: + return left + + binary_operator = self.current.char + self.Next() # eat the operator. + + # Parse the primary expression after the binary operator. + right = self.ParsePrimary() + + # If binary_operator binds less tightly with right than the operator after + # right, let the pending operator take right as its left. + next_precedence = self.GetCurrentTokenPrecedence() + if precedence < next_precedence: + right = self.ParseBinOpRHS(right, precedence + 1) + + # Merge left/right. + left = BinaryOperatorExpressionNode(binary_operator, left, right) + + # expression ::= primary binoprhs def ParseExpression(self): left = + self.ParsePrimary() return self.ParseBinOpRHS(left, 0) + + # prototype ::= id '(' id\* ')' def ParsePrototype(self): if not + isinstance(self.current, IdentifierToken): raise RuntimeError('Expected + function name in prototype.') + + :: + + function_name = self.current.name + self.Next() # eat function name. + + if self.current != CharacterToken('('): + raise RuntimeError('Expected "(" in prototype.') + self.Next() # eat '('. + + arg_names = [] + while isinstance(self.current, IdentifierToken): + arg_names.append(self.current.name) + self.Next() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")" in prototype.') + + # Success. + self.Next() # eat ')'. + + return PrototypeNode(function_name, arg_names) + + # definition ::= 'def' prototype expression def ParseDefinition(self): + self.Next() # eat def. proto = self.ParsePrototype() body = + self.ParseExpression() return FunctionNode(proto, body) + + # toplevelexpr ::= expression def ParseTopLevelExpr(self): proto = + PrototypeNode('', []) return FunctionNode(proto, self.ParseExpression()) + + # external ::= 'extern' prototype def ParseExtern(self): self.Next() # + eat extern. return self.ParsePrototype() + + # Top-Level parsing def HandleDefinition(self): + self.Handle(self.ParseDefinition, 'Read a function definition:') + + def HandleExtern(self): self.Handle(self.ParseExtern, 'Read an extern:') + + def HandleTopLevelExpression(self): try: function = + self.ParseTopLevelExpr().CodeGen() result = + g_llvm_executor.run_function(function, []) print 'Evaluated to:', + result.as_real(Type.double()) except Exception, e: print 'Error:', e + try: self.Next() # Skip for error recovery. except: pass + + def Handle(self, function, message): try: print message, + function().CodeGen() except Exception, e: print 'Error:', e try: + self.Next() # Skip for error recovery. except: pass + + Main driver code. + ----------------- + + def main(): # Set up the optimizer pipeline. Start with registering info + about how the # target lays out data structures. + g_llvm_pass_manager.add(g_llvm_executor.target_data) # Do simple + "peephole" optimizations and bit-twiddling optzns. + g_llvm_pass_manager.add(PASS_INSTRUCTION_COMBINING) # Reassociate + expressions. g_llvm_pass_manager.add(PASS_REASSOCIATE) # Eliminate + Common SubExpressions. g_llvm_pass_manager.add(PASS_GVN) # Simplify + the control flow graph (deleting unreachable blocks, etc). + g_llvm_pass_manager.add(PASS_CFG_SIMPLIFICATION) + + g_llvm_pass_manager.initialize() + + # Install standard binary operators. # 1 is lowest possible precedence. + 40 is the highest. operator_precedence = { '<': 10, '+': 20, '-': 20, + '\*': 40 } + + # Run the main "interpreter loop". while True: print 'ready>', try: raw + = raw_input() except KeyboardInterrupt: break + + :: + + parser = Parser(Tokenize(raw), operator_precedence) + while True: + # top ::= definition | external | expression | EOF + if isinstance(parser.current, EOFToken): + break + if isinstance(parser.current, DefToken): + parser.HandleDefinition() + elif isinstance(parser.current, ExternToken): + parser.HandleExtern() + else: + parser.HandleTopLevelExpression() + + # Print out all of the generated code. print '', g_llvm_module + + if **name** == '**main**\ ': main() diff --git a/docs/_build/html/_sources/doc/kaleidoscope/PythonLangImpl5.txt b/docs/_build/html/_sources/doc/kaleidoscope/PythonLangImpl5.txt new file mode 100644 index 0000000..d4d01fa --- /dev/null +++ b/docs/_build/html/_sources/doc/kaleidoscope/PythonLangImpl5.txt @@ -0,0 +1,1411 @@ +***************************************************** +Chapter 5: Extending the Language: Control Flow +***************************************************** + +Written by `Chris Lattner `_ and `Max +Shawabkeh `_ + +Introduction # {#intro} +======================= + +Welcome to Chapter 5 of the `Implementing a language with +LLVM `_ tutorial. Parts +1-4 described the implementation of the simple Kaleidoscope language and +included support for generating LLVM IR, followed by optimizations and a +JIT compiler. Unfortunately, as presented, Kaleidoscope is mostly +useless: it has no control flow other than call and return. This means +that you can't have conditional branches in the code, significantly +limiting its power. In this episode of "build that compiler", we'll +extend Kaleidoscope to have an if/then/else expression plus a simple +'for' loop. + +-------------- + +If/Then/Else # {#ifthen} +======================== + +Extending Kaleidoscope to support if/then/else is quite straightforward. +It basically requires adding lexer support for this "new" concept to the +lexer, parser, AST, and LLVM code emitter. This example is nice, because +it shows how easy it is to "grow" a language over time, incrementally +extending it as new ideas are discovered. + +Before we get going on "how" we add this extension, lets talk about +"what" we want. The basic idea is that we want to be able to write this +sort of thing: + + +.. code-block:: python + + def fib(x) if x < 3 then 1 else fib(x-1) + + fib(x-2) + + + +In Kaleidoscope, every construct is an expression: there are no +statements. As such, the if/then/else expression needs to return a value +like any other. Since we're using a mostly functional form, we'll have +it evaluate its conditional, then return the 'then' or 'else' value +based on how the condition was resolved. This is very similar to the C +"?:" expression. + +The semantics of the if/then/else expression is that it evaluates the +condition to a boolean equality value: 0.0 is considered to be false and +everything else is considered to be true. If the condition is true, the +first subexpression is evaluated and returned, if the condition is +false, the second subexpression is evaluated and returned. Since +Kaleidoscope allows side-effects, this behavior is important to nail +down. + +Now that we know what we "want", let's break this down into its +constituent pieces. + +Lexer Extensions for If/Then/Else ## {#iflexer} +----------------------------------------------- + +The lexer extensions are straightforward. First we add new token classes +for the relevant tokens: + + +.. code-block:: python + + class IfToken(object): pass class + ThenToken(object): pass class ElseToken(object): pass + + + +Once we have that, we recognize the new keywords in the lexer. This is +pretty simple stuff: + + +.. code-block:: python + + ... if identifier == 'def': yield DefToken() elif + identifier == 'extern': yield ExternToken() elif identifier == 'if': + yield IfToken() elif identifier == 'then': yield ThenToken() elif + identifier == 'else': yield ElseToken() else: yield + IdentifierToken(identifier) + + + +AST Extensions for If/Then/Else ## {#ifast} +------------------------------------------- + +To represent the new expression we add a new AST node for it: + + +.. code-block:: python + + # Expression class for if/then/else. class + IfExpressionNode(ExpressionNode): + + def **init**\ (self, condition, then_branch, else_branch): + self.condition = condition self.then_branch = then_branch + self.else_branch = else_branch + + def CodeGen(self): ... + + + +The AST node just has pointers to the various subexpressions. + +Parser Extensions for If/Then/Else ## {#ifparser} +------------------------------------------------- + +Now that we have the relevant tokens coming from the lexer and we have +the AST node to build, our parsing logic is relatively straightforward. +First we define a new parsing function: + + +.. code-block:: python + + # ifexpr ::= 'if' expression 'then' expression + 'else' expression def ParseIfExpr(self): self.Next() # eat the if. + + :: + + # condition. + condition = self.ParseExpression() + + if not isinstance(self.current, ThenToken): + raise RuntimeError('Expected "then".') + self.Next() # eat the then. + + then_branch = self.ParseExpression() + + if not isinstance(self.current, ElseToken): + raise RuntimeError('Expected "else".') + self.Next() # eat the else. + + else_branch = self.ParseExpression() + + return IfExpressionNode(condition, then_branch, else_branch) + + + + + +Next we hook it up as a primary expression: + + +.. code-block:: python + + def ParsePrimary(self): if + isinstance(self.current, IdentifierToken): return + self.ParseIdentifierExpr() elif isinstance(self.current, NumberToken): + return self.ParseNumberExpr(); elif isinstance(self.current, IfToken): + return self.ParseIfExpr() elif self.current == CharacterToken('('): + return self.ParseParenExpr() else: raise RuntimeError('Unknown token + when expecting an expression.') + + + +LLVM IR for If/Then/Else ## {#ifir} +----------------------------------- + +Now that we have it parsing and building the AST, the final piece is +adding LLVM code generation support. This is the most interesting part +of the if/then/else example, because this is where it starts to +introduce new concepts. All of the code above has been thoroughly +described in previous chapters. + +To motivate the code we want to produce, lets take a look at a simple +example. Consider: + + +.. code-block:: python + + extern foo(); extern bar(); def baz(x) if x then + foo() else bar(); + + + +If you disable optimizations, the code you'll (soon) get from +Kaleidoscope looks something like this: + + +.. code-block:: llvm + + declare double @foo() declare double @bar() define + double @baz(double %x) { entry: %ifcond = fcmp one double %x, + 0.000000e+00 br i1 %ifcond, label %then, label %else then: ; preds = + %entry %calltmp1 = call double @bar() else: ; preds = %entry %calltmp1 = + call double @bar() br label %ifcont ifcont: ; preds = %else, %then + %iftmp = phi double [ %calltmp, %then ], [ %calltmp1, %else ] ret double + %iftmp } + + + +To visualize the control flow graph, you can use a nifty feature of the +LLVM `opt `_ tool. If you put this LLVM +IR into "t.ll" and run ``llvm-as < t.ll | opt -analyze -view-cfg``, a +`window will pop +up `_ and +you'll see this graph: + +Another way to get this is to call "``function.viewCFG()``\ " or +"``function.viewCFGOnly()``\ " (where F is a "``llvm.core.Function``\ ") +either by inserting actual calls into the code and recompiling or by +calling these in the debugger. LLVM has many nice features for +visualizing various graphs, but note that these are available only if +your LLVM was built with Graphviz support (accomplished by having +Graphviz and Ghostview installed when building LLVM). + +Getting back to the generated code, it is fairly simple: the entry block +evaluates the conditional expression ("x" in our case here) and compares +the result to 0.0 with the +`fcmp `_ one instruction +('one' is "Ordered and Not Equal"). Based on the result of this +expression, the code jumps to either the "then" or "else" blocks, which +contain the expressions for the true/false cases. + +Once the then/else blocks are finished executing, they both branch back +to the 'ifcont' block to execute the code that happens after the +if/then/else. In this case the only thing left to do is to return to the +caller of the function. The question then becomes: how does the code +know which expression to return? + +The answer to this question involves an important SSA operation: the +`Phi +operation `_. +If you're not familiar with SSA, `the wikipedia +article `_ +is a good introduction and there are various other introductions to it +available on your favorite search engine. The short version is that +"execution" of the Phi operation requires "remembering" which block +control came from. The Phi operation takes on the value corresponding to +the input control block. In this case, if control comes in from the +"then" block, it gets the value of "calltmp". If control comes from the +"else" block, it gets the value of "calltmp1". + +At this point, you are probably starting to think "Oh no! This means my +simple and elegant front-end will have to start generating SSA form in +order to use LLVM!". Fortunately, this is not the case, and we strongly +advise *not* implementing an SSA construction algorithm in your +front-end unless there is an amazingly good reason to do so. In +practice, there are two sorts of values that float around in code +written for your average imperative programming language that might need +Phi nodes: + +1. Code that involves user variables: ``x = 1; x = x + 1;`` +2. Values that are implicit in the structure of your AST, such as the + Phi node in this case. + +In `Chapter 7 `_ of this tutorial ("mutable +variables"), we'll talk about #1 in depth. For now, just believe me that +you don't need SSA construction to handle this case. For #2, you have +the choice of using the techniques that we will describe for #1, or you +can insert Phi nodes directly, if convenient. In this case, it is really +really easy to generate the Phi node, so we choose to do it directly. + +Okay, enough of the motivation and overview, lets generate code! + +Code Generation for If/Then/Else ## {#ifcodegen} +------------------------------------------------ + +In order to generate code for this, we implement the ``Codegen`` method +for ``IfExpressionNode``: + + +.. code-block:: python + + def CodeGen(self): condition = + self.condition.CodeGen() + + :: + + # Convert condition to a bool by comparing equal to 0.0. + condition_bool = g_llvm_builder.fcmp( + FCMP_ONE, condition, Constant.real(Type.double(), 0), 'ifcond') + + + + + +This code is straightforward and similar to what we saw before. We emit +the expression for the condition, then compare that value to zero to get +a truth value as a 1-bit (bool) value. + + +.. code-block:: python + + function = g_llvm_builder.basic_block.function + + :: + + # Create blocks for the then and else cases. Insert the 'then' block at the + # end of the function. + then_block = function.append_basic_block('then') + else_block = function.append_basic_block('else') + merge_block = function.append_basic_block('ifcond') + + g_llvm_builder.cbranch(condition_bool, then_block, else_block) + + + + + +This code creates the basic blocks that are related to the if/then/else +statement, and correspond directly to the blocks in the example above. +The first line gets the current Function object that is being built. It +gets this by asking the builder for the current BasicBlock, and asking +that block for its "parent" (the function it is currently embedded +into). + +Once it has that, it creates three block which are automatically +inserted into the end of the function. Once the blocks are created, we +can emit the conditional branch that chooses between them. Note that +creating new blocks does not implicitly affect the Builder, so it is +still inserting into the block that the condition went into. + + +.. code-block:: python + + # Emit then value. + g_llvm_builder.position_at_end(then_block) then_value = + self.then_branch.CodeGen() g_llvm_builder.branch(merge_block) + + :: + + # Codegen of 'Then' can change the current block; update then_block for the + # PHI node. + then_block = g_llvm_builder.basic_block + + + + + +After the conditional branch is inserted, we move the builder to start +inserting into the "then" block. Strictly speaking, this call moves the +insertion point to be at the end of the specified block. However, since +the "then" block is empty, it also starts out by inserting at the +beginning of the block. :) + +Once the insertion point is set, we recursively codegen the "then" +expression from the AST. To finish off the "then" block, we create an +unconditional branch to the merge block. One interesting (and very +important) aspect of the LLVM IR is that it `requires all basic blocks +to be +"terminated" `_ +with a `control flow +instruction `_ such +as return or branch. This means that all control flow, *including +fallthroughs* must be made explicit in the LLVM IR. If you violate this +rule, the verifier will emit an error. + +The final line here is quite subtle, but is very important. The basic +issue is that when we create the Phi node in the merge block, we need to +set up the block/value pairs that indicate how the Phi will work. +Importantly, the Phi node expects to have an entry for each predecessor +of the block in the CFG. Why then, are we getting the current block when +we just set it to then\_block 5 lines above? The problem is that the +"Then" expression may actually itself change the block that the Builder +is emitting into if, for example, it contains a nested "if/then/else" +expression. Because calling Codegen recursively could arbitrarily change +the notion of the current block, we are required to get an up-to-date +value for code that will set up the Phi node. + + +.. code-block:: python + + # Emit else block. + g_llvm_builder.position_at_end(else_block) else_value = + self.else_branch.CodeGen() g_llvm_builder.branch(merge_block) + + :: + + # Codegen of 'Else' can change the current block, update else_block for the + # PHI node. + else_block = g_llvm_builder.basic_block + + + + + +Code generation for the 'else' block is basically identical to codegen +for the 'then' block. The only significant difference is the first line, +which adds the 'else' block to the function. Recall previously that the +'else' block was created, but not added to the function. Now that the +'then' and 'else' blocks are emitted, we can finish up with the merge +code: + + +.. code-block:: python + + # Emit merge block. + g_llvm_builder.position_at_end(merge_block) phi = + g_llvm_builder.phi(Type.double(), 'iftmp') + phi.add_incoming(then_value, then_block) + phi.add_incoming(else_value, else_block) + + :: + + return phi + + + + + +The first line changes the insertion point so that newly created code +will go into the "merge" block. Once that is done, we need to create the +PHI node and set up the block/value pairs for the PHI. + +Finally, the CodeGen function returns the phi node as the value computed +by the if/then/else expression. In our example above, this returned +value will feed into the code for the top-level function, which will +create the return instruction. + +Overall, we now have the ability to execute conditional code in +Kaleidoscope. With this extension, Kaleidoscope is a fairly complete +language that can calculate a wide variety of numeric functions. Next up +we'll add another useful expression that is familiar from non-functional +languages... + +-------------- + +'for' Loop Expression # {#for} +============================== + +Now that we know how to add basic control flow constructs to the +language, we have the tools to add more powerful things. Lets add +something more aggressive, a 'for' expression: + + +.. code-block:: python + + extern putchard(char) def printstar(n) for i = 1, + i < n, 1.0 in putchard(42) # ascii 42 = '\*' + + :: + + # print 100 '*' characters + printstar(100) + + + + + +This expression defines a new variable (``i`` in this case) which +iterates from a starting value, while the condition (``i < n`` in this +case) is true, incrementing by an optional step value ("1.0" in this +case). If the step value is omitted, it defaults to 1.0. While the loop +is true, it executes its body expression. Because we don't have anything +better to return, we'll just define the loop as always returning 0.0. In +the future when we have mutable variables, it will get more useful. + +As before, lets talk about the changes that we need to Kaleidoscope to +support this. + +Lexer Extensions for the 'for' Loop ## {#forlexer} +-------------------------------------------------- + +The lexer extensions are the same sort of thing as for if/then/else: + + +.. code-block:: python + + ... + + class ThenToken(object): pass class ElseToken(object): pass class + ForToken(object): pass class InToken(object): pass + + ... + + def Tokenize(string): + + :: + + ... + + elif identifier == 'else': + yield ElseToken() + elif identifier == 'for': + yield ForToken() + elif identifier == 'in': + yield InToken() + else: + yield IdentifierToken(identifier) + + + + + +AST Extensions for the 'for' Loop ## {#forast} +---------------------------------------------- + +The AST node is just as simple. It basically boils down to capturing the +variable name and the constituent expressions in the node. + + +.. code-block:: python + + # Expression class for for/in. class + ForExpressionNode(ExpressionNode): + + def **init**\ (self, loop_variable, start, end, step, body): + self.loop_variable = loop_variable self.start = start self.end = end + self.step = step self.body = body + + def CodeGen(self): ... + + + +Parser Extensions for the 'for' Loop ## {#forparser} +---------------------------------------------------- + +The parser code is also fairly standard. The only interesting thing here +is handling of the optional step value. The parser code handles it by +checking to see if the second comma is present. If not, it sets the step +value to null in the AST node: + + +.. code-block:: python + + # forexpr ::= 'for' identifier '=' expr ',' expr + (',' expr)? 'in' expression def ParseForExpr(self): self.Next() # eat + the for. + + :: + + if not isinstance(self.current, IdentifierToken): + raise RuntimeError('Expected identifier after for.') + + loop_variable = self.current.name + self.Next() # eat the identifier. + + if self.current != CharacterToken('='): + raise RuntimeError('Expected "=" after for variable.') + self.Next() # eat the '='. + + start = self.ParseExpression() + + if self.current != CharacterToken(','): + raise RuntimeError('Expected "," after for start value.') + self.Next() # eat the ','. + + end = self.ParseExpression() + + # The step value is optional. + if self.current == CharacterToken(','): + self.Next() # eat the ','. + step = self.ParseExpression() + else: + step = None + + if not isinstance(self.current, InToken): + raise RuntimeError('Expected "in" after for variable specification.') + self.Next() # eat 'in'. + + body = self.ParseExpression() + + return ForExpressionNode(loop_variable, start, end, step, body) + + + + + +LLVM IR for the 'for' Loop ## {#forir} +-------------------------------------- + +Now we get to the good part: the LLVM IR we want to generate for this +thing. With the simple example above, we get this LLVM IR (note that +this dump is generated with optimizations disabled for clarity): + + +.. code-block:: llvm + + declare double @putchard(double) define double + @printstar(double %n) { entry: ; initial value = 1.0 (inlined into phi) + br label %loop loop: ; preds = %loop, %entry %i = phi double [ + 1.000000e+00, %entry ], [ %nextvar, %loop ] ; body %calltmp = call + double @putchard(double 4.200000e+01) ; increment %nextvar = fadd double + %i, 1.000000e+00 ; termination test %cmptmp = fcmp ult double %i, %n + %booltmp = uitofp i1 %cmptmp to double %loopcond = fcmp one double + %booltmp, 0.000000e+00 br i1 %loopcond, label %loop, label %afterloop + afterloop: ; preds = %loop ; loop always returns 0.0 ret double + 0.000000e+00 } + + + +This loop contains all the same constructs we saw before: a phi node, +several expressions, and some basic blocks. Lets see how this fits +together. + +Code Generation for the 'for' Loop ## {#forcodegen} +--------------------------------------------------- + +The first part of Codegen is very simple: we just output the start +expression for the loop value: + + +.. code-block:: python + + def CodeGen(self): # Emit the start code first, + without 'variable' in scope. start_value = self.start.CodeGen() {% + endhighlight %} + + With this out of the way, the next step is to set up the LLVM basic + block for the start of the loop body. In the case above, the whole loop + body is one block, but remember that the body code itself could consist + of multiple blocks (e.g. if it contains an if/then/else or a for/in + expression). + + {% highlight python %} # Make the new basic block for the loop header, + inserting after current # block. function = + g_llvm_builder.basic_block.function pre_header_block = + g_llvm_builder.basic_block loop_block = + function.append_basic_block('loop') + + :: + + # Insert an explicit fallthrough from the current block to the loop_block. + g_llvm_builder.branch(loop_block) + + + + + +This code is similar to what we saw for if/then/else. Because we will +need it to create the Phi node, we remember the block that falls through +into the loop. Once we have that, we create the actual block that starts +the loop and create an unconditional branch for the fall-through between +the two blocks. + + +.. code-block:: python + + # Start insertion in loop_block. + g_llvm_builder.position_at_end(loop_block); + + :: + + # Start the PHI node with an entry for start. + variable_phi = g_llvm_builder.phi(Type.double(), self.loop_variable) + variable_phi.add_incoming(start_value, pre_header_block) + + + + + +Now that the "pre\_header\_block" for the loop is set up, we switch to +emitting code for the loop body. To begin with, we move the insertion +point and create the PHI node for the loop induction variable. Since we +already know the incoming value for the starting value, we add it to the +Phi node. Note that the Phi will eventually get a second value for the +backedge, but we can't set it up yet (because it doesn't exist!). + + +.. code-block:: python + + # Within the loop, the variable is defined equal + to the PHI node. If it # shadows an existing variable, we have to + restore it, so save it now. old_value = + g_named_values.get(self.loop_variable, None) + g_named_values[self.loop_variable] = variable_phi + + :: + + # Emit the body of the loop. This, like any other expr, can change the + # current BB. Note that we ignore the value computed by the body. + self.body.CodeGen() + + + + + +Now the code starts to get more interesting. Our 'for' loop introduces a +new variable to the symbol table. This means that our symbol table can +now contain either function arguments or loop variables. To handle this, +before we codegen the body of the loop, we add the loop variable as the +current value for its name. Note that it is possible that there is a +variable of the same name in the outer scope. It would be easy to make +this an error (emit an error and return null if there is already an +entry for VarName) but we choose to allow shadowing of variables. In +order to handle this correctly, we remember the Value that we are +potentially shadowing in ``old_value`` (which will be None if there is +no shadowed variable). + +Once the loop variable is set into the symbol table, the code +recursively codegen's the body. This allows the body to use the loop +variable: any references to it will naturally find it in the symbol +table. + + +.. code-block:: python + + # Emit the step value. if self.step: step_value + = self.step.CodeGen() else: # If not specified, use 1.0. step_value = + Constant.real(Type.double(), 1) + + :: + + next_value = g_llvm_builder.fadd(variable_phi, step_value, 'next') + + + + + +Now that the body is emitted, we compute the next value of the iteration +variable by adding the step value, or 1.0 if it isn't present. +``next_value`` will be the value of the loop variable on the next +iteration of the loop. + + +.. code-block:: python + + # Compute the end condition and convert it to a + bool by comparing to 0.0. end_condition = self.end.CodeGen() + end_condition_bool = g_llvm_builder.fcmp( FCMP_ONE, end_condition, + Constant.real(Type.double(), 0), 'loopcond') + + + +Finally, we evaluate the exit value of the loop, to determine whether +the loop should exit. This mirrors the condition evaluation for the +if/then/else statement. + + +.. code-block:: python + + # Create the "after loop" block and insert it. + loop_end_block = g_llvm_builder.basic_block after_block = + function.append_basic_block('afterloop') + + :: + + # Insert the conditional branch into the end of loop_end_block. + g_llvm_builder.cbranch(end_condition_bool, loop_block, after_block) + + # Any new code will be inserted in after_block. + g_llvm_builder.position_at_end(after_block) + + + + + +With the code for the body of the loop complete, we just need to finish +up the control flow for it. This code remembers the end block (for the +phi node), then creates the block for the loop exit ("afterloop"). Based +on the value of the exit condition, it creates a conditional branch that +chooses between executing the loop again and exiting the loop. Any +future code is emitted in the "afterloop" block, so it sets the +insertion position to it. + + +.. code-block:: python + + # Add a new entry to the PHI node for the + backedge. variable_phi.add_incoming(next_value, loop_end_block) + + :: + + # Restore the unshadowed variable. + if old_value: + g_named_values[self.loop_variable] = old_value + else: + del g_named_values[self.loop_variable] + + # for expr always returns 0.0. + return Constant.real(Type.double(), 0) + + + + + +The final code handles various cleanups: now that we have the +"next\_value", we can add the incoming value to the loop PHI node. After +that, we remove the loop variable from the symbol table, so that it +isn't in scope after the for loop. Finally, code generation of the for +loop always returns 0.0, so that is what we return from +``ForExpressionNode::CodeGen``. + +With this, we conclude the "adding control flow to Kaleidoscope" chapter +of the tutorial. In this chapter we added two control flow constructs, +and used them to motivate a couple of aspects of the LLVM IR that are +important for front-end implementors to know. In the next chapter of our +saga, we will get a bit crazier and add `user-defined +operators `_ to our poor innocent language. + +-------------- + +Full Code Listing # {#code} +=========================== + +Here is the complete code listing for our running example, enhanced with +the if/then/else and for expressions: + + +.. code-block:: python + + #!/usr/bin/env python + + import re from llvm.core import Module, Constant, Type, Function, + Builder from llvm.ee import ExecutionEngine, TargetData from llvm.passes + import FunctionPassManager + + from llvm.core import FCMP_ULT, FCMP_ONE from llvm.passes import + (PASS_INSTRUCTION_COMBINING, PASS_REASSOCIATE, PASS_GVN, + PASS_CFG_SIMPLIFICATION) + + Globals + ------- + + # The LLVM module, which holds all the IR code. + g_llvm_module = Module.new('my cool jit') + + # The LLVM instruction builder. Created whenever a new function is entered. + g_llvm_builder = None + + # A dictionary that keeps track of which values are defined in the current scope + # and what their LLVM representation is. + g_named_values = {} + + # The function optimization passes manager. + g_llvm_pass_manager = FunctionPassManager.new(g_llvm_module) + + # The LLVM execution engine. + g_llvm_executor = ExecutionEngine.new(g_llvm_module) + + Lexer + ----- + + # The lexer yields one of these types for each token. + class EOFToken(object): pass class DefToken(object): pass class + ExternToken(object): pass class IfToken(object): pass class + ThenToken(object): pass class ElseToken(object): pass class + ForToken(object): pass class InToken(object): pass + + class IdentifierToken(object): def **init**\ (self, name): self.name = + name + + class NumberToken(object): def **init**\ (self, value): self.value = + value + + class CharacterToken(object): def **init**\ (self, char): self.char = + char def **eq**\ (self, other): return isinstance(other, CharacterToken) + and self.char == other.char def **ne**\ (self, other): return not self + == other + + # Regular expressions that tokens and comments of our language. + REGEX_NUMBER = re.compile('[0-9]+(?:.[0-9]+)?') REGEX_IDENTIFIER = + re.compile('[a-zA-Z][a-zA-Z0-9]\ *') REGEX_COMMENT = re.compile('#.*') + + def Tokenize(string): while string: # Skip whitespace. if + string[0].isspace(): string = string[1:] continue + + :: + + # Run regexes. + comment_match = REGEX_COMMENT.match(string) + number_match = REGEX_NUMBER.match(string) + identifier_match = REGEX_IDENTIFIER.match(string) + + # Check if any of the regexes matched and yield the appropriate result. + if comment_match: + comment = comment_match.group(0) + string = string[len(comment):] + elif number_match: + number = number_match.group(0) + yield NumberToken(float(number)) + string = string[len(number):] + elif identifier_match: + identifier = identifier_match.group(0) + # Check if we matched a keyword. + if identifier == 'def': + yield DefToken() + elif identifier == 'extern': + yield ExternToken() + elif identifier == 'if': + yield IfToken() + elif identifier == 'then': + yield ThenToken() + elif identifier == 'else': + yield ElseToken() + elif identifier == 'for': + yield ForToken() + elif identifier == 'in': + yield InToken() + else: + yield IdentifierToken(identifier) + string = string[len(identifier):] + else: + # Yield the ASCII value of the unknown character. + yield CharacterToken(string[0]) + string = string[1:] + + yield EOFToken() + + Abstract Syntax Tree (aka Parse Tree) + ------------------------------------- + + # Base class for all expression nodes. + class ExpressionNode(object): pass + + # Expression class for numeric literals like "1.0". + class NumberExpressionNode(ExpressionNode): + + def **init**\ (self, value): self.value = value + + def CodeGen(self): return Constant.real(Type.double(), self.value) + + # Expression class for referencing a variable, like "a". + class VariableExpressionNode(ExpressionNode): + + def **init**\ (self, name): self.name = name + + def CodeGen(self): if self.name in g_named_values: return + g_named_values[self.name] else: raise RuntimeError('Unknown variable + name: ' + self.name) + + # Expression class for a binary operator. + class BinaryOperatorExpressionNode(ExpressionNode): + + def **init**\ (self, operator, left, right): self.operator = operator + self.left = left self.right = right + + def CodeGen(self): left = self.left.CodeGen() right = + self.right.CodeGen() + + :: + + if self.operator == '+': + return g_llvm_builder.fadd(left, right, 'addtmp') + elif self.operator == '-': + return g_llvm_builder.fsub(left, right, 'subtmp') + elif self.operator == '*': + return g_llvm_builder.fmul(left, right, 'multmp') + elif self.operator == '<': + result = g_llvm_builder.fcmp(FCMP_ULT, left, right, 'cmptmp') + # Convert bool 0 or 1 to double 0.0 or 1.0. + return g_llvm_builder.uitofp(result, Type.double(), 'booltmp') + else: + raise RuntimeError('Unknown binary operator.') + + # Expression class for function calls. + class CallExpressionNode(ExpressionNode): + + def **init**\ (self, callee, args): self.callee = callee self.args = + args + + def CodeGen(self): # Look up the name in the global module table. callee + = g_llvm_module.get_function_named(self.callee) + + :: + + # Check for argument mismatch error. + if len(callee.args) != len(self.args): + raise RuntimeError('Incorrect number of arguments passed.') + + arg_values = [i.CodeGen() for i in self.args] + + return g_llvm_builder.call(callee, arg_values, 'calltmp') + + # Expression class for if/then/else. + class IfExpressionNode(ExpressionNode): + + def **init**\ (self, condition, then_branch, else_branch): + self.condition = condition self.then_branch = then_branch + self.else_branch = else_branch + + def CodeGen(self): condition = self.condition.CodeGen() + + :: + + # Convert condition to a bool by comparing equal to 0.0. + condition_bool = g_llvm_builder.fcmp( + FCMP_ONE, condition, Constant.real(Type.double(), 0), 'ifcond') + + function = g_llvm_builder.basic_block.function + + # Create blocks for the then and else cases. Insert the 'then' block at the + # end of the function. + then_block = function.append_basic_block('then') + else_block = function.append_basic_block('else') + merge_block = function.append_basic_block('ifcond') + + g_llvm_builder.cbranch(condition_bool, then_block, else_block) + + # Emit then value. + g_llvm_builder.position_at_end(then_block) + then_value = self.then_branch.CodeGen() + g_llvm_builder.branch(merge_block) + + # Codegen of 'Then' can change the current block; update then_block for the + # PHI node. + then_block = g_llvm_builder.basic_block + + # Emit else block. + g_llvm_builder.position_at_end(else_block) + else_value = self.else_branch.CodeGen() + g_llvm_builder.branch(merge_block) + + # Codegen of 'Else' can change the current block, update else_block for the + # PHI node. + else_block = g_llvm_builder.basic_block + + # Emit merge block. + g_llvm_builder.position_at_end(merge_block) + phi = g_llvm_builder.phi(Type.double(), 'iftmp') + phi.add_incoming(then_value, then_block) + phi.add_incoming(else_value, else_block) + + return phi + + # Expression class for for/in. + class ForExpressionNode(ExpressionNode): + + def **init**\ (self, loop_variable, start, end, step, body): + self.loop_variable = loop_variable self.start = start self.end = end + self.step = step self.body = body + + def CodeGen(self): # Output this as: # ... # start = startexpr # goto + loop # loop: # variable = phi [start, loopheader], [nextvariable, + loopend] # ... # bodyexpr # ... # loopend: # step = stepexpr # + nextvariable = variable + step # endcond = endexpr # br endcond, loop, + endloop # outloop: + + :: + + # Emit the start code first, without 'variable' in scope. + start_value = self.start.CodeGen() + + # Make the new basic block for the loop header, inserting after current + # block. + function = g_llvm_builder.basic_block.function + pre_header_block = g_llvm_builder.basic_block + loop_block = function.append_basic_block('loop') + + # Insert an explicit fallthrough from the current block to the loop_block. + g_llvm_builder.branch(loop_block) + + # Start insertion in loop_block. + g_llvm_builder.position_at_end(loop_block) + + # Start the PHI node with an entry for start. + variable_phi = g_llvm_builder.phi(Type.double(), self.loop_variable) + variable_phi.add_incoming(start_value, pre_header_block) + + # Within the loop, the variable is defined equal to the PHI node. If it + # shadows an existing variable, we have to restore it, so save it now. + old_value = g_named_values.get(self.loop_variable, None) + g_named_values[self.loop_variable] = variable_phi + + # Emit the body of the loop. This, like any other expr, can change the + # current BB. Note that we ignore the value computed by the body. + self.body.CodeGen() + + # Emit the step value. + if self.step: + step_value = self.step.CodeGen() + else: + # If not specified, use 1.0. + step_value = Constant.real(Type.double(), 1) + + next_value = g_llvm_builder.fadd(variable_phi, step_value, 'next') + + # Compute the end condition and convert it to a bool by comparing to 0.0. + end_condition = self.end.CodeGen() + end_condition_bool = g_llvm_builder.fcmp( + FCMP_ONE, end_condition, Constant.real(Type.double(), 0), 'loopcond') + + # Create the "after loop" block and insert it. + loop_end_block = g_llvm_builder.basic_block + after_block = function.append_basic_block('afterloop') + + # Insert the conditional branch into the end of loop_end_block. + g_llvm_builder.cbranch(end_condition_bool, loop_block, after_block) + + # Any new code will be inserted in after_block. + g_llvm_builder.position_at_end(after_block) + + # Add a new entry to the PHI node for the backedge. + variable_phi.add_incoming(next_value, loop_end_block) + + # Restore the unshadowed variable. + if old_value: + g_named_values[self.loop_variable] = old_value + else: + del g_named_values[self.loop_variable] + + # for expr always returns 0.0. + return Constant.real(Type.double(), 0) + + # This class represents the "prototype" for a function, which captures its name, + # and its argument names (thus implicitly the number of arguments the function + # takes). + class PrototypeNode(object): + + def **init**\ (self, name, args): self.name = name self.args = args + + def CodeGen(self): # Make the function type, eg. double(double,double). + funct_type = Type.function( Type.double(), [Type.double()] \* + len(self.args), False) + + :: + + function = Function.new(g_llvm_module, funct_type, self.name) + + # If the name conflicted, there was already something with the same name. + # If it has a body, don't allow redefinition or reextern. + if function.name != self.name: + function.delete() + function = g_llvm_module.get_function_named(self.name) + + # If the function already has a body, reject this. + if not function.is_declaration: + raise RuntimeError('Redefinition of function.') + + # If the function took a different number of args, reject. + if len(function.args) != len(self.args): + raise RuntimeError('Redeclaration of a function with different number ' + 'of args.') + + # Set names for all arguments and add them to the variables symbol table. + for arg, arg_name in zip(function.args, self.args): + arg.name = arg_name + # Add arguments to variable symbol table. + g_named_values[arg_name] = arg + + return function + + # This class represents a function definition itself. + class FunctionNode(object): + + def **init**\ (self, prototype, body): self.prototype = prototype + self.body = body + + def CodeGen(self): # Clear scope. g_named_values.clear() + + :: + + # Create a function object. + function = self.prototype.CodeGen() + + # Create a new basic block to start insertion into. + block = function.append_basic_block('entry') + global g_llvm_builder + g_llvm_builder = Builder.new(block) + + # Finish off the function. + try: + return_value = self.body.CodeGen() + g_llvm_builder.ret(return_value) + + # Validate the generated code, checking for consistency. + function.verify() + + # Optimize the function. + g_llvm_pass_manager.run(function) + except: + function.delete() + raise + + return function + + Parser + ------ + + class Parser(object): + + def **init**\ (self, tokens, binop_precedence): self.tokens = tokens + self.binop_precedence = binop_precedence self.Next() + + # Provide a simple token buffer. Parser.current is the current token the + # parser is looking at. Parser.Next() reads another token from the lexer + and # updates Parser.current with its results. def Next(self): + self.current = self.tokens.next() + + # Gets the precedence of the current token, or -1 if the token is not a + binary # operator. def GetCurrentTokenPrecedence(self): if + isinstance(self.current, CharacterToken): return + self.binop_precedence.get(self.current.char, -1) else: return -1 + + # identifierexpr ::= identifier \| identifier '(' expression\* ')' def + ParseIdentifierExpr(self): identifier_name = self.current.name + self.Next() # eat identifier. + + :: + + if self.current != CharacterToken('('): # Simple variable reference. + return VariableExpressionNode(identifier_name) + + # Call. + self.Next() # eat '('. + args = [] + if self.current != CharacterToken(')'): + while True: + args.append(self.ParseExpression()) + if self.current == CharacterToken(')'): + break + elif self.current != CharacterToken(','): + raise RuntimeError('Expected ")" or "," in argument list.') + self.Next() + + self.Next() # eat ')'. + return CallExpressionNode(identifier_name, args) + + # numberexpr ::= number def ParseNumberExpr(self): result = + NumberExpressionNode(self.current.value) self.Next() # consume the + number. return result + + # parenexpr ::= '(' expression ')' def ParseParenExpr(self): self.Next() + # eat '('. + + :: + + contents = self.ParseExpression() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")".') + self.Next() # eat ')'. + + return contents + + # ifexpr ::= 'if' expression 'then' expression 'else' expression def + ParseIfExpr(self): self.Next() # eat the if. + + :: + + # condition. + condition = self.ParseExpression() + + if not isinstance(self.current, ThenToken): + raise RuntimeError('Expected "then".') + self.Next() # eat the then. + + then_branch = self.ParseExpression() + + if not isinstance(self.current, ElseToken): + raise RuntimeError('Expected "else".') + self.Next() # eat the else. + + else_branch = self.ParseExpression() + + return IfExpressionNode(condition, then_branch, else_branch) + + # forexpr ::= 'for' identifier '=' expr ',' expr (',' expr)? 'in' + expression def ParseForExpr(self): self.Next() # eat the for. + + :: + + if not isinstance(self.current, IdentifierToken): + raise RuntimeError('Expected identifier after for.') + + loop_variable = self.current.name + self.Next() # eat the identifier. + + if self.current != CharacterToken('='): + raise RuntimeError('Expected "=" after for variable.') + self.Next() # eat the '='. + + start = self.ParseExpression() + + if self.current != CharacterToken(','): + raise RuntimeError('Expected "," after for start value.') + self.Next() # eat the ','. + + end = self.ParseExpression() + + # The step value is optional. + if self.current == CharacterToken(','): + self.Next() # eat the ','. + step = self.ParseExpression() + else: + step = None + + if not isinstance(self.current, InToken): + raise RuntimeError('Expected "in" after for variable specification.') + self.Next() # eat 'in'. + + body = self.ParseExpression() + + return ForExpressionNode(loop_variable, start, end, step, body) + + # primary ::= identifierexpr \| numberexpr \| parenexpr \| ifexpr \| + forexpr def ParsePrimary(self): if isinstance(self.current, + IdentifierToken): return self.ParseIdentifierExpr() elif + isinstance(self.current, NumberToken): return self.ParseNumberExpr() + elif isinstance(self.current, IfToken): return self.ParseIfExpr() elif + isinstance(self.current, ForToken): return self.ParseForExpr() elif + self.current == CharacterToken('('): return self.ParseParenExpr() else: + raise RuntimeError('Unknown token when expecting an expression.') + + # binoprhs ::= (operator primary)\* def ParseBinOpRHS(self, left, + left_precedence): # If this is a binary operator, find its precedence. + while True: precedence = self.GetCurrentTokenPrecedence() + + :: + + # If this is a binary operator that binds at least as tightly as the + # current one, consume it; otherwise we are done. + if precedence < left_precedence: + return left + + binary_operator = self.current.char + self.Next() # eat the operator. + + # Parse the primary expression after the binary operator. + right = self.ParsePrimary() + + # If binary_operator binds less tightly with right than the operator after + # right, let the pending operator take right as its left. + next_precedence = self.GetCurrentTokenPrecedence() + if precedence < next_precedence: + right = self.ParseBinOpRHS(right, precedence + 1) + + # Merge left/right. + left = BinaryOperatorExpressionNode(binary_operator, left, right) + + # expression ::= primary binoprhs def ParseExpression(self): left = + self.ParsePrimary() return self.ParseBinOpRHS(left, 0) + + # prototype ::= id '(' id\* ')' def ParsePrototype(self): if not + isinstance(self.current, IdentifierToken): raise RuntimeError('Expected + function name in prototype.') + + :: + + function_name = self.current.name + self.Next() # eat function name. + + if self.current != CharacterToken('('): + raise RuntimeError('Expected "(" in prototype.') + self.Next() # eat '('. + + arg_names = [] + while isinstance(self.current, IdentifierToken): + arg_names.append(self.current.name) + self.Next() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")" in prototype.') + + # Success. + self.Next() # eat ')'. + + return PrototypeNode(function_name, arg_names) + + # definition ::= 'def' prototype expression def ParseDefinition(self): + self.Next() # eat def. proto = self.ParsePrototype() body = + self.ParseExpression() return FunctionNode(proto, body) + + # toplevelexpr ::= expression def ParseTopLevelExpr(self): proto = + PrototypeNode('', []) return FunctionNode(proto, self.ParseExpression()) + + # external ::= 'extern' prototype def ParseExtern(self): self.Next() # + eat extern. return self.ParsePrototype() + + # Top-Level parsing def HandleDefinition(self): + self.Handle(self.ParseDefinition, 'Read a function definition:') + + def HandleExtern(self): self.Handle(self.ParseExtern, 'Read an extern:') + + def HandleTopLevelExpression(self): try: function = + self.ParseTopLevelExpr().CodeGen() result = + g_llvm_executor.run_function(function, []) print 'Evaluated to:', + result.as_real(Type.double()) except Exception, e: print 'Error:', e + try: self.Next() # Skip for error recovery. except: pass + + def Handle(self, function, message): try: print message, + function().CodeGen() except Exception, e: print 'Error:', e try: + self.Next() # Skip for error recovery. except: pass + + Main driver code. + ----------------- + + def main(): # Set up the optimizer pipeline. Start with registering info + about how the # target lays out data structures. + g_llvm_pass_manager.add(g_llvm_executor.target_data) # Do simple + "peephole" optimizations and bit-twiddling optzns. + g_llvm_pass_manager.add(PASS_INSTRUCTION_COMBINING) # Reassociate + expressions. g_llvm_pass_manager.add(PASS_REASSOCIATE) # Eliminate + Common SubExpressions. g_llvm_pass_manager.add(PASS_GVN) # Simplify + the control flow graph (deleting unreachable blocks, etc). + g_llvm_pass_manager.add(PASS_CFG_SIMPLIFICATION) + + g_llvm_pass_manager.initialize() + + # Install standard binary operators. # 1 is lowest possible precedence. + 40 is the highest. operator_precedence = { '<': 10, '+': 20, '-': 20, + '\*': 40 } + + # Run the main "interpreter loop". while True: print 'ready>', try: raw + = raw_input() except KeyboardInterrupt: break + + :: + + parser = Parser(Tokenize(raw), operator_precedence) + while True: + # top ::= definition | external | expression | EOF + if isinstance(parser.current, EOFToken): + break + if isinstance(parser.current, DefToken): + parser.HandleDefinition() + elif isinstance(parser.current, ExternToken): + parser.HandleExtern() + else: + parser.HandleTopLevelExpression() + + # Print out all of the generated code. print '', g_llvm_module + + if **name** == '**main**\ ': main() diff --git a/docs/_build/html/_sources/doc/kaleidoscope/PythonLangImpl6.txt b/docs/_build/html/_sources/doc/kaleidoscope/PythonLangImpl6.txt new file mode 100644 index 0000000..dfe95b6 --- /dev/null +++ b/docs/_build/html/_sources/doc/kaleidoscope/PythonLangImpl6.txt @@ -0,0 +1,1357 @@ +********************************************************************** +Chapter 6: Extending the Language: User-defined Operators +********************************************************************** + +Written by `Chris Lattner `_ and `Max +Shawabkeh `_ + +Introduction # {#intro} +======================= + +Welcome to Chapter 6 of the `Implementing a language with +LLVM `_ tutorial. At this +point in our tutorial, we now have a fully functional language that is +fairly minimal, but also useful. There is still one big problem with it, +however. Our language doesn't have many useful operators (like division, +logical negation, or even any comparisons besides less-than). + +This chapter of the tutorial takes a wild digression into adding +user-defined operators to the simple and beautiful Kaleidoscope +language. This digression now gives us a simple and ugly language in +some ways, but also a powerful one at the same time. One of the great +things about creating your own language is that you get to decide what +is good or bad. In this tutorial we'll assume that it is okay to use +this as a way to show some interesting parsing techniques. + +At the end of this tutorial, we'll run through an example Kaleidoscope +application that `renders the Mandelbrot set <#example>`_. This gives an +example of what you can build with Kaleidoscope and its feature set. + +User-defined Operators: the Idea # {#idea} +========================================== + +The "operator overloading" that we will add to Kaleidoscope is more +general than languages like C++. In C++, you are only allowed to +redefine existing operators: you can't programatically change the +grammar, introduce new operators, change precedence levels, etc. In this +chapter, we will add this capability to Kaleidoscope, which will let the +user round out the set of operators that are supported. + +The point of going into user-defined operators in a tutorial like this +is to show the power and flexibility of using a hand-written parser. +Thus far, the parser we have been implementing uses recursive descent +for most parts of the grammar and operator precedence parsing for the +expressions. See `Chapter 2 `_ for details. +Without using operator precedence parsing, it would be very difficult to +allow the programmer to introduce new operators into the grammar: the +grammar is dynamically extensible as the JIT runs. + +The two specific features we'll add are programmable unary operators +(right now, Kaleidoscope has no unary operators at all) as well as +binary operators. An example of this is: + + +.. code-block:: python + + # Logical unary not. def unary!(v) if v then 0 + else 1 + + # Define > with the same precedence as <. + def binary> 10 (LHS RHS) RHS < LHS + + # Binary "logical or", (note that it does not "short circuit"). + def binary\| 5 (LHS RHS) if LHS then 1 else if RHS then 1 else 0 + + # Define = with slightly lower precedence than relationals. + def binary= 9 (LHS RHS) !(LHS < RHS \| LHS > RHS) + + + +Many languages aspire to being able to implement their standard runtime +library in the language itself. In Kaleidoscope, we can implement +significant parts of the language in the library! + +We will break down implementation of these features into two parts: +implementing support for user-defined binary operators and adding unary +operators. + +-------------- + +User-defined Binary Operators # {#binary} +========================================= + +Adding support for user-defined binary operators is pretty simple with +our current framework. We'll first add support for the unary/binary +keywords: + + +.. code-block:: python + + class InToken(object): pass class + BinaryToken(object): pass class UnaryToken(object): pass ... def + Tokenize(string): ... elif identifier == 'in': yield InToken() elif + identifier == 'binary': yield BinaryToken() elif identifier == 'unary': + yield UnaryToken() else: yield IdentifierToken(identifier) {% + endhighlight %} + + This just adds lexer support for the unary and binary keywords, like we + did in `previous chapters `_. One nice + thing about our current AST, is that we represent binary operators with + full generalisation by using their ASCII code as the opcode. For our + extended operators, we'll use this same representation, so we don't need + any new AST or parser support. + + On the other hand, we have to be able to represent the definitions of + these new operators, in the "def binary\| 5" part of the function + definition. In our grammar so far, the "name" for the function + definition is parsed as the "prototype" production and into the + ``PrototypeNode``. To represent our new user-defined operators as + prototypes, we have to extend the ``PrototypeNode`` like this: + + {% highlight python %} # This class represents the "prototype" for a + function, which captures its name, # and its argument names (thus + implicitly the number of arguments the function # takes), as well as if + it is an operator. class PrototypeNode(object): + + def **init**\ (self, name, args, is_operator=False, precedence=0): + self.name = name self.args = args self.is_operator = is_operator + self.precedence = precedence + + def IsBinaryOp(self): return self.is_operator and len(self.args) == 2 + + def GetOperatorName(self): assert self.is_operator return self.name[-1] + + def CodeGen(self): ... + + + +Basically, in addition to knowing a name for the prototype, we now keep +track of whether it was an operator, and if it was, what precedence +level the operator is at. The precedence is only used for binary +operators (as you'll see below, it just doesn't apply for unary +operators). Now that we have a way to represent the prototype for a +user-defined operator, we need to parse it: + + +.. code-block:: python + + # prototype # ::= id '(' id\* ')' # ::= binary + LETTER number? (id, id) # ::= unary LETTER (id) def + ParsePrototype(self): precedence = None if isinstance(self.current, + IdentifierToken): kind = 'normal' function_name = self.current.name + self.Next() # eat function name. elif isinstance(self.current, + BinaryToken): kind = 'binary' self.Next() # eat 'binary'. if not + isinstance(self.current, CharacterToken): raise RuntimeError('Expected + an operator after "binary".') function_name = 'binary' + + self.current.char self.Next() # eat the operator. if + isinstance(self.current, NumberToken): if not 1 <= self.current.value <= + 100: raise RuntimeError('Invalid precedence: must be in range [1, + 100].') precedence = self.current.value self.Next() # eat the + precedence. else: raise RuntimeError('Expected function name, "unary" or + "binary" in ' 'prototype.') + + :: + + if self.current != CharacterToken('('): + raise RuntimeError('Expected "(" in prototype.') + self.Next() # eat '('. + + arg_names = [] + while isinstance(self.current, IdentifierToken): + arg_names.append(self.current.name) + self.Next() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")" in prototype.') + + # Success. + self.Next() # eat ')'. + + if kind == 'binary' and len(arg_names) != 2: + raise RuntimeError('Invalid number of arguments for a binary operator.') + + return PrototypeNode(function_name, arg_names, kind != 'normal', precedence) + + + + + +This is all fairly straightforward parsing code, and we have already +seen a lot of similar code in the past. One interesting part about the +code above is the couple lines that set up ``function_name`` for +operators. This builds names like "binary@" for a newly defined "@" +operator. This then takes advantage of the fact that symbol names in the +LLVM symbol table are allowed to have any character in them. + +The next interesting thing to add, is codegen support for these binary +operators. Given our current structure, this is a simple addition of a +default case for our existing binary operator node: + + +.. code-block:: python + + def CodeGen(self): left = self.left.CodeGen() + right = self.right.CodeGen() + + :: + + if self.operator == '+': + return g_llvm_builder.fadd(left, right, 'addtmp') + elif self.operator == '-': + return g_llvm_builder.fsub(left, right, 'subtmp') + elif self.operator == '*': + return g_llvm_builder.fmul(left, right, 'multmp') + elif self.operator == '<': + result = g_llvm_builder.fcmp(FCMP_ULT, left, right, 'cmptmp') + # Convert bool 0 or 1 to double 0.0 or 1.0. + return g_llvm_builder.uitofp(result, Type.double(), 'booltmp') + else: + function = g_llvm_module.get_function_named('binary' + self.operator) + return g_llvm_builder.call(function, [left, right], 'binop') + + + + + +As you can see above, the new code is actually really simple. It just +does a lookup for the appropriate operator in the symbol table and +generates a function call to it. Since user-defined operators are just +built as normal functions (because the "prototype" boils down to a +function with the right name) everything falls into place. + +The final piece of code we are missing, is a bit of top-level magic. We +will need to make the dinary precedence map global and modify it +whenever we define a new binary operator: + + +.. code-block:: python + + # The binary operator precedence chart. + g_binop_precedence = {} ... class FunctionNode(object): ... def + CodeGen(self): ... # Create a function object. function = + self.prototype.CodeGen() + + :: + + # If this is a binary operator, install its precedence. + if self.prototype.IsBinaryOp(): + operator = self.prototype.GetOperatorName() + g_binop_precedence[operator] = self.prototype.precedence + ... + # Finish off the function. + try: + ... + except: + function.delete() + if self.prototype.IsBinaryOp(): + del g_binop_precedence[self.prototype.GetOperatorName()] + raise + + return function + + ... def main(): ... g_binop_precedence['<'] = 10 + g_binop_precedence['+'] = 20 g_binop_precedence['-'] = 20 + g_binop_precedence['\*'] = 40 ... + + + +Basically, before CodeGening a function, if it is a user-defined +operator, we register it in the precedence table. This allows the binary +operator parsing logic we already have in place to handle it. Since we +are working on a fully-general operator precedence parser, this is all +we need to do to "extend the grammar". + +Now we have useful user-defined binary operators. This builds a lot on +the previous framework we built for other operators. Adding unary +operators is a bit more challenging, because we don't have any framework +for it yet - let's see what it takes. + +User-defined Unary Operators # {#unary} +======================================= + +Since we don't currently support unary operators in the Kaleidoscope +language, we'll need to add everything to support them. Above, we added +simple support for the 'unary' keyword to the lexer. In addition to +that, we need an AST node: + + +.. code-block:: python + + # Expression class for a unary operator. class + UnaryExpressionNode(ExpressionNode): + + def **init**\ (self, operator, operand): self.operator = operator + self.operand = operand + + def CodeGen(self): ... + + + +This AST node is very simple and obvious by now. It directly mirrors the +binary operator AST node, except that it only has one child. With this, +we need to add the parsing logic. Parsing a unary operator is pretty +simple: we'll add a new function to do it: + + +.. code-block:: python + + # unary ::= primary \| unary_operator unary def + ParseUnary(self): # If the current token is not an operator, it must be + a primary expression. if (not isinstance(self.current, CharacterToken) + or self.current in [CharacterToken('('), CharacterToken(',')]): return + self.ParsePrimary() + + :: + + # If this is a unary operator, read it. + operator = self.current.char + self.Next() # eat the operator. + return UnaryExpressionNode(operator, self.ParseUnary()) + + + + + +The grammar we add is pretty straightforward here. If we see a unary +operator when parsing a primary operator, we eat the operator as a +prefix and parse the remaining piece as another unary operator. This +allows us to handle multiple unary operators (e.g. ``!!x``). Note that +unary operators can't have ambiguous parses like binary operators can, +so there is no need for precedence information. + +The problem with this function, is that we need to call ParseUnary from +somewhere. To do this, we change previous callers of ParsePrimary to +call ParseUnary instead: + + +.. code-block:: python + + # binoprhs ::= (binary_operator unary)\* def + ParseBinOpRHS(self, left, left_precedence): ... # Parse the unary + expression after the binary operator. right = self.ParseUnary() ... + + # expression ::= unary binoprhs def ParseExpression(self): left = + self.ParseUnary() return self.ParseBinOpRHS(left, 0) + + + +With these two simple changes, we are now able to parse unary operators +and build the AST for them. Next up, we need to add parser support for +prototypes, to parse the unary operator prototype. We extend the binary +operator code above with: + + +.. code-block:: python + + # prototype # ::= id '(' id\* ')' # ::= binary + LETTER number? (id, id) # ::= unary LETTER (id) def + ParsePrototype(self): precedence = None if isinstance(self.current, + IdentifierToken): ... elif isinstance(self.current, UnaryToken): kind = + 'unary' self.Next() # eat 'unary'. if not isinstance(self.current, + CharacterToken): raise RuntimeError('Expected an operator after + "unary".') function_name = 'unary' + self.current.char self.Next() # + eat the operator. elif isinstance(self.current, BinaryToken): ... else: + raise RuntimeError('Expected function name, "unary" or "binary" in ' + 'prototype.') ... if kind == 'unary' and len(arg_names) != 1: raise + RuntimeError('Invalid number of arguments for a unary operator.') elif + kind == 'binary' and len(arg_names) != 2: raise RuntimeError('Invalid + number of arguments for a binary operator.') + + :: + + return PrototypeNode(function_name, arg_names, kind != 'normal', precedence) + + + + + +As with binary operators, we name unary operators with a name that +includes the operator character. This assists us at code generation +time. Speaking of, the final piece we need to add is codegen support for +unary operators. It looks like this: + + +.. code-block:: python + + class UnaryExpressionNode(ExpressionNode): ... + def CodeGen(self): operand = self.operand.CodeGen() function = + g_llvm_module.get_function_named('unary' + self.operator) return + g_llvm_builder.call(function, [operand], 'unop') + + + +This code is similar to, but simpler than, the code for binary +operators. It is simpler primarily because it doesn't need to handle any +predefined operators. + +-------------- + +Kicking the Tires # {#example} +============================== + +It is somewhat hard to believe, but with a few simple extensions we've +covered in the last chapters, we have grown a real-ish language. With +this, we can do a lot of interesting things, including I/O, math, and a +bunch of other things. For example, we can now add a nice sequencing +operator (assuming we import ``putchard`` as described in Chapter 4): + + +.. code-block:: python + + ready> def binary : 1 (x y) 0 # Low-precedence + operator that ignores operands. ... ready> extern putchard(x) ... ready> + def printd(x) putchard(x) : putchard(10) .. ready> printd(65) : + printd(66) : printd(67) A B C Evaluated to: 0.0 + + + +We can also define a bunch of other "primitive" operations, such as: + + +.. code-block:: python + + # Logical unary not. def unary!(v) if v then 0 + else 1 + + # Unary negate. + def unary-(v) 0-v + + # Define > with the same precedence as <. + def binary> 10 (LHS RHS) RHS < LHS + + # Binary logical or, which does not short circuit. + def binary\| 5 (LHS RHS) if LHS then 1 else if RHS then 1 else 0 + + # Binary logical and, which does not short circuit. + def binary& 6 (LHS RHS) if !LHS then 0 else !!RHS + + # Define = with slightly lower precedence than relationals. + def binary = 9 (LHS RHS) !(LHS < RHS \| LHS > RHS) + + + + + +Given the previous if/then/else support, we can also define interesting +functions for I/O. For example, the following prints out a character +whose "density" reflects the value passed in: the lower the value, the +denser the character: + + +.. code-block:: python + + ready> + + extern putchard(char) def printdensity(d) if d > 8 then putchard(32) # ' + ' else if d > 4 then putchard(46) # '.' else if d > 2 then putchard(43) + # '+' else putchard(42); # '*' ... ready> printdensity(1): + printdensity(2): printdensity(3) : printdensity(4): printdensity(5): + printdensity(9): putchard(10)*\ ++.. Evaluated to 0.000000 {% + endhighlight %} + + Based on these simple primitive operations, we can start to define more + interesting things. For example, here's a little function that solves + for the number of iterations it takes a function in the complex plane to + converge: + + {% highlight python %} # determine whether the specific location + diverges. # Solve for z = z^2 + c in the complex plane. def + mandelconverger(real imag iters creal cimag) if iters > 255 \| + (real\ *real + imag*\ imag > 4) then iters else + mandelconverger(real\ *real - imag*\ imag + creal, 2\ *real*\ imag + + cimag, iters+1, creal, cimag) + + # return the number of iterations required for the iteration to escape + def mandelconverge(real imag) mandelconverger(real, imag, 0, real, imag) + + + + +This "z = z2 + c" function is a beautiful little creature that is the +basis for computation of the `Mandelbrot +Set `_. Our +``mandelconverge`` function returns the number of iterations that it +takes for a complex orbit to escape, saturating to 255. This is not a +very useful function by itself, but if you plot its value over a +two-dimensional plane, you can see the Mandelbrot set. Given that we are +limited to using putchard here, our amazing graphical output is limited, +but we can whip together something using the density plotter above: + + +.. code-block:: python + + # compute and plot the mandlebrot set with the + specified 2 dimensional range # info. def mandelhelp(xmin xmax xstep + ymin ymax ystep) for y = ymin, y < ymax, ystep in ( (for x = xmin, x < + xmax, xstep in printdensity(mandleconverge(x,y))) : putchard(10) ) + + # mandel - This is a convenient helper function for ploting the mandelbrot set + # from the specified position with the specified Magnification. + def mandel(realstart imagstart realmag imagmag) mandelhelp(realstart, + realstart+realmag\ *78, realmag, imagstart, imagstart+imagmag*\ 40, + imagmag); + + + +Given this, we can try plotting out the mandlebrot set! Lets try it out: + + +.. code-block:: bash + + ready> mandel(-2.3, -1.3, 0.05, 0.07) + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++...++++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++.. + ...+++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++++.. + ..+++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++++. + ..++++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++++++.... + ..++++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++....... + .....++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++. . ... + .++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++... + ++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++++++.... + .+++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++..+++++.... + ..+++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++. .......... + +++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*++++++++.. .. + .++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*++++++++++... + .++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* \*\*\*\*\*\*\*\*++++++++++.. + .++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* \*\*\*\*\*\*\*++++++..... + ..++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* \*\*\*\*\*\*\*+........ + ...++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* \*\*\*\*\*\*\*+... .... + ...++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* \*\*\*\*\*\*\*+++++...... + ..++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* \*\*\*\*\*\*\*++++++++++... + .++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*++++++++++... + ++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*+++++++++.. .. + ..++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*++++++.. .......... + +++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++...+++..... + ..+++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++++++.... + ..++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++... + +++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++++.. . ... + .++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++....... + ......+++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++++++.... + ..++++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++++.. + ..++++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++++.. + ...+++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++.. + ...+++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++....+++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + Evaluated to 0.0 ready> mandel(-2, -1, 0.02, 0.04) + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++++++++++ + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++++++++++++ + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++++++++++++ + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++++++++++++++ + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++++++++++++++++++++ + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++++++++++++++++... + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++++++++++++++++++....... + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++++++++++++++.......... + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++++++++++++++++... + ... + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++++++++++++++...... + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++++++++++++++....... + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++++++++++++++++++.......... + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++++++++++++++++........... + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++++++++++++++++++......... + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++...........+++++.............. + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++++++.... + ......................... + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++++++++++++++.... ......... + ............ \*\*\*\*\*\*\*\*\*\*\*+++++++++++++++++++++..... ...... + \*\*\*\*\*\*\*\*+++++++++++++++++++++++....... + \*\*\*\*\*\*+++++++++++++++++++++++++........ + \*\*\*\*+++++++++++++++++++++++++....... + ***+++++++++++++++++++++++.........**\ ++++++++++++++++...........*\ ++++++++++++................ + \*++++.................... + + *++++....................*\ ++++++++++++................ + **++++++++++++++++...........**\ *+++++++++++++++++++++++......... + \*\*\*\*+++++++++++++++++++++++++....... + \*\*\*\*\*\*+++++++++++++++++++++++++........ + \*\*\*\*\*\*\*\*+++++++++++++++++++++++....... + \*\*\*\*\*\*\*\*\*\*\*+++++++++++++++++++++..... ...... + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++++++++++++++.... ......... + ............ \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++++++.... + ......................... + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++...........+++++.............. + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++++++++++++++++++......... + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++++++++++++++++........... + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++++++++++++++++++.......... + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++++++++++++++....... + Evaluated to: 0.0 ready> mandel(-0.9, -1.4, 0.02, 0.03) + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++++++++++++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++++++++...++++++++++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++++++++++.. . + .++++++++++++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*++++++++++++++++... + ......++++++++++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*\*\*+++++++++++++++++++... + .......+++++++++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*\*\*++++++++++++++++++++.... .... + ..++++++++++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*\*\*++++++++++++++++++++++...... + ...++++++++++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*\*\*+++++++++++++++++++++++....... + .....++++++++++++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*\*\*++++++++++++++++++++++++....... + .....+++++++++++++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + \*\*\*\*+++++++++++++++++++++++++.... . + .....+++++++++++++++\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* + **+++++++++++++++++++++++++.... + ...++++++++++++++++**\ \*\*\*\*\*\*\*\*\*\*\**\ +++++++++++++++++++++++....... + ....++++++++++++++++\*\*\*\*\*\*\*\*\*\*\*\* + +++++++++++++++++++++.......... + .....++++++++++++++++\*\*\*\*\*\*\*\*\*\*\* + ++++++++++++++++++............. + .......+++++++++++++++\*\*\*\*\*\*\*\*\*\* + +++++++++++++++................ + ............++++++++++\*\*\*\*\*\*\*\*\*\* + +++++++++++++................. .................+++++\*\*\*\*\*\*\*\*\* + +++++++++++... .... .......... .+++++\*\*\*\*\*\*\*\* ++++++++++..... + ........ ...+++++\*\*\*\*\*\*\* ++++++++...... ..++++++\*\*\*\*\*\* + +++++++........ ..+++++\*\*\*\*\*\* +++++.......... ..++++++\*\*\*\*\* + ++++.......... ....++++++\*\*\*\*\* ++.......... ....+++++++\*\*\*\* + .......... ......+++++++\ **\* .......... .....+++++++**\ \* .......... + .....++++++\ **\* ......... .+++++++** ........ .+++++++\ *\* ...... + ...+++++++* . ....++++++++\* ...++++++++\* ..+++++++++ ..+++++++++ + Evaluated to: 0.0 ready> ^C + + + +At this point, you may be starting to realize that Kaleidoscope is a +real and powerful language. It may not be self-similar :), but it can be +used to plot things that are! + +With this, we conclude the "adding user-defined operators" chapter of +the tutorial. We have successfully augmented our language, adding the +ability to extend the language in the library, and we have shown how +this can be used to build a simple but interesting end-user application +in Kaleidoscope. At this point, Kaleidoscope can build a variety of +applications that are functional and can call functions with +side-effects, but it can't actually define and mutate a variable itself. + +Strikingly, variable mutation is an important feature of some languages, +and it is not at all obvious how to `add support for mutable +variables `_ without having to add an "SSA +construction" phase to your front-end. In the next chapter, we will +describe how you can add variable mutation without building SSA in your +front-end. + +-------------- + +Full Code Listing # {#code} +=========================== + +Here is the complete code listing for our running example, enhanced with +the if/then/else and for expressions: + + +.. code-block:: python + + #!/usr/bin/env python + + import re from llvm.core import Module, Constant, Type, Function, + Builder from llvm.ee import ExecutionEngine, TargetData from llvm.passes + import FunctionPassManager + + from llvm.core import FCMP_ULT, FCMP_ONE from llvm.passes import + (PASS_INSTRUCTION_COMBINING, PASS_REASSOCIATE, PASS_GVN, + PASS_CFG_SIMPLIFICATION) + + Globals + ------- + + # The LLVM module, which holds all the IR code. + g_llvm_module = Module.new('my cool jit') + + # The LLVM instruction builder. Created whenever a new function is entered. + g_llvm_builder = None + + # A dictionary that keeps track of which values are defined in the current scope + # and what their LLVM representation is. + g_named_values = {} + + # The function optimization passes manager. + g_llvm_pass_manager = FunctionPassManager.new(g_llvm_module) + + # The LLVM execution engine. + g_llvm_executor = ExecutionEngine.new(g_llvm_module) + + # The binary operator precedence chart. + g_binop_precedence = {} + + Lexer + ----- + + # The lexer yields one of these types for each token. + class EOFToken(object): pass class DefToken(object): pass class + ExternToken(object): pass class IfToken(object): pass class + ThenToken(object): pass class ElseToken(object): pass class + ForToken(object): pass class InToken(object): pass class + BinaryToken(object): pass class UnaryToken(object): pass + + class IdentifierToken(object): def **init**\ (self, name): self.name = + name + + class NumberToken(object): def **init**\ (self, value): self.value = + value + + class CharacterToken(object): def **init**\ (self, char): self.char = + char def **eq**\ (self, other): return isinstance(other, CharacterToken) + and self.char == other.char def **ne**\ (self, other): return not self + == other + + # Regular expressions that tokens and comments of our language. + REGEX_NUMBER = re.compile('[0-9]+(?:.[0-9]+)?') REGEX_IDENTIFIER = + re.compile('[a-zA-Z][a-zA-Z0-9]\ *') REGEX_COMMENT = re.compile('#.*') + + def Tokenize(string): while string: # Skip whitespace. if + string[0].isspace(): string = string[1:] continue + + :: + + # Run regexes. + comment_match = REGEX_COMMENT.match(string) + number_match = REGEX_NUMBER.match(string) + identifier_match = REGEX_IDENTIFIER.match(string) + + # Check if any of the regexes matched and yield the appropriate result. + if comment_match: + comment = comment_match.group(0) + string = string[len(comment):] + elif number_match: + number = number_match.group(0) + yield NumberToken(float(number)) + string = string[len(number):] + elif identifier_match: + identifier = identifier_match.group(0) + # Check if we matched a keyword. + if identifier == 'def': + yield DefToken() + elif identifier == 'extern': + yield ExternToken() + elif identifier == 'if': + yield IfToken() + elif identifier == 'then': + yield ThenToken() + elif identifier == 'else': + yield ElseToken() + elif identifier == 'for': + yield ForToken() + elif identifier == 'in': + yield InToken() + elif identifier == 'binary': + yield BinaryToken() + elif identifier == 'unary': + yield UnaryToken() + else: + yield IdentifierToken(identifier) + string = string[len(identifier):] + else: + # Yield the ASCII value of the unknown character. + yield CharacterToken(string[0]) + string = string[1:] + + yield EOFToken() + + Abstract Syntax Tree (aka Parse Tree) + ------------------------------------- + + # Base class for all expression nodes. + class ExpressionNode(object): pass + + # Expression class for numeric literals like "1.0". + class NumberExpressionNode(ExpressionNode): + + def **init**\ (self, value): self.value = value + + def CodeGen(self): return Constant.real(Type.double(), self.value) + + # Expression class for referencing a variable, like "a". + class VariableExpressionNode(ExpressionNode): + + def **init**\ (self, name): self.name = name + + def CodeGen(self): if self.name in g_named_values: return + g_named_values[self.name] else: raise RuntimeError('Unknown variable + name: ' + self.name) + + # Expression class for a binary operator. + class BinaryOperatorExpressionNode(ExpressionNode): + + def **init**\ (self, operator, left, right): self.operator = operator + self.left = left self.right = right + + def CodeGen(self): left = self.left.CodeGen() right = + self.right.CodeGen() + + :: + + if self.operator == '+': + return g_llvm_builder.fadd(left, right, 'addtmp') + elif self.operator == '-': + return g_llvm_builder.fsub(left, right, 'subtmp') + elif self.operator == '*': + return g_llvm_builder.fmul(left, right, 'multmp') + elif self.operator == '<': + result = g_llvm_builder.fcmp(FCMP_ULT, left, right, 'cmptmp') + # Convert bool 0 or 1 to double 0.0 or 1.0. + return g_llvm_builder.uitofp(result, Type.double(), 'booltmp') + else: + function = g_llvm_module.get_function_named('binary' + self.operator) + return g_llvm_builder.call(function, [left, right], 'binop') + + # Expression class for function calls. + class CallExpressionNode(ExpressionNode): + + def **init**\ (self, callee, args): self.callee = callee self.args = + args + + def CodeGen(self): # Look up the name in the global module table. callee + = g_llvm_module.get_function_named(self.callee) + + :: + + # Check for argument mismatch error. + if len(callee.args) != len(self.args): + raise RuntimeError('Incorrect number of arguments passed.') + + arg_values = [i.CodeGen() for i in self.args] + + return g_llvm_builder.call(callee, arg_values, 'calltmp') + + # Expression class for if/then/else. + class IfExpressionNode(ExpressionNode): + + def **init**\ (self, condition, then_branch, else_branch): + self.condition = condition self.then_branch = then_branch + self.else_branch = else_branch + + def CodeGen(self): condition = self.condition.CodeGen() + + :: + + # Convert condition to a bool by comparing equal to 0.0. + condition_bool = g_llvm_builder.fcmp( + FCMP_ONE, condition, Constant.real(Type.double(), 0), 'ifcond') + + function = g_llvm_builder.basic_block.function + + # Create blocks for the then and else cases. Insert the 'then' block at the + # end of the function. + then_block = function.append_basic_block('then') + else_block = function.append_basic_block('else') + merge_block = function.append_basic_block('ifcond') + + g_llvm_builder.cbranch(condition_bool, then_block, else_block) + + # Emit then value. + g_llvm_builder.position_at_end(then_block) + then_value = self.then_branch.CodeGen() + g_llvm_builder.branch(merge_block) + + # Codegen of 'Then' can change the current block; update then_block for the + # PHI node. + then_block = g_llvm_builder.basic_block + + # Emit else block. + g_llvm_builder.position_at_end(else_block) + else_value = self.else_branch.CodeGen() + g_llvm_builder.branch(merge_block) + + # Codegen of 'Else' can change the current block, update else_block for the + # PHI node. + else_block = g_llvm_builder.basic_block + + # Emit merge block. + g_llvm_builder.position_at_end(merge_block) + phi = g_llvm_builder.phi(Type.double(), 'iftmp') + phi.add_incoming(then_value, then_block) + phi.add_incoming(else_value, else_block) + + return phi + + # Expression class for for/in. + class ForExpressionNode(ExpressionNode): + + def **init**\ (self, loop_variable, start, end, step, body): + self.loop_variable = loop_variable self.start = start self.end = end + self.step = step self.body = body + + def CodeGen(self): # Output this as: # ... # start = startexpr # goto + loop # loop: # variable = phi [start, loopheader], [nextvariable, + loopend] # ... # bodyexpr # ... # loopend: # step = stepexpr # + nextvariable = variable + step # endcond = endexpr # br endcond, loop, + endloop # outloop: + + :: + + # Emit the start code first, without 'variable' in scope. + start_value = self.start.CodeGen() + + # Make the new basic block for the loop header, inserting after current + # block. + function = g_llvm_builder.basic_block.function + pre_header_block = g_llvm_builder.basic_block + loop_block = function.append_basic_block('loop') + + # Insert an explicit fallthrough from the current block to the loop_block. + g_llvm_builder.branch(loop_block) + + # Start insertion in loop_block. + g_llvm_builder.position_at_end(loop_block) + + # Start the PHI node with an entry for start. + variable_phi = g_llvm_builder.phi(Type.double(), self.loop_variable) + variable_phi.add_incoming(start_value, pre_header_block) + + # Within the loop, the variable is defined equal to the PHI node. If it + # shadows an existing variable, we have to restore it, so save it now. + old_value = g_named_values.get(self.loop_variable, None) + g_named_values[self.loop_variable] = variable_phi + + # Emit the body of the loop. This, like any other expr, can change the + # current BB. Note that we ignore the value computed by the body. + self.body.CodeGen() + + # Emit the step value. + if self.step: + step_value = self.step.CodeGen() + else: + # If not specified, use 1.0. + step_value = Constant.real(Type.double(), 1) + + next_value = g_llvm_builder.fadd(variable_phi, step_value, 'next') + + # Compute the end condition and convert it to a bool by comparing to 0.0. + end_condition = self.end.CodeGen() + end_condition_bool = g_llvm_builder.fcmp( + FCMP_ONE, end_condition, Constant.real(Type.double(), 0), 'loopcond') + + # Create the "after loop" block and insert it. + loop_end_block = g_llvm_builder.basic_block + after_block = function.append_basic_block('afterloop') + + # Insert the conditional branch into the end of loop_end_block. + g_llvm_builder.cbranch(end_condition_bool, loop_block, after_block) + + # Any new code will be inserted in after_block. + g_llvm_builder.position_at_end(after_block) + + # Add a new entry to the PHI node for the backedge. + variable_phi.add_incoming(next_value, loop_end_block) + + # Restore the unshadowed variable. + if old_value: + g_named_values[self.loop_variable] = old_value + else: + del g_named_values[self.loop_variable] + + # for expr always returns 0.0. + return Constant.real(Type.double(), 0) + + # Expression class for a unary operator. + class UnaryExpressionNode(ExpressionNode): + + def **init**\ (self, operator, operand): self.operator = operator + self.operand = operand + + def CodeGen(self): operand = self.operand.CodeGen() function = + g_llvm_module.get_function_named('unary' + self.operator) return + g_llvm_builder.call(function, [operand], 'unop') + + # This class represents the "prototype" for a function, which captures its name, + # and its argument names (thus implicitly the number of arguments the function + # takes), as well as if it is an operator. + class PrototypeNode(object): + + def **init**\ (self, name, args, is_operator=False, precedence=0): + self.name = name self.args = args self.is_operator = is_operator + self.precedence = precedence + + def IsBinaryOp(self): return self.is_operator and len(self.args) == 2 + + def GetOperatorName(self): assert self.is_operator return self.name[-1] + + def CodeGen(self): # Make the function type, eg. double(double,double). + funct_type = Type.function( Type.double(), [Type.double()] \* + len(self.args), False) + + :: + + function = Function.new(g_llvm_module, funct_type, self.name) + + # If the name conflicted, there was already something with the same name. + # If it has a body, don't allow redefinition or reextern. + if function.name != self.name: + function.delete() + function = g_llvm_module.get_function_named(self.name) + + # If the function already has a body, reject this. + if not function.is_declaration: + raise RuntimeError('Redefinition of function.') + + # If the function took a different number of args, reject. + if len(function.args) != len(self.args): + raise RuntimeError('Redeclaration of a function with different number ' + 'of args.') + + # Set names for all arguments and add them to the variables symbol table. + for arg, arg_name in zip(function.args, self.args): + arg.name = arg_name + # Add arguments to variable symbol table. + g_named_values[arg_name] = arg + + return function + + # This class represents a function definition itself. + class FunctionNode(object): + + def **init**\ (self, prototype, body): self.prototype = prototype + self.body = body + + def CodeGen(self): # Clear scope. g_named_values.clear() + + :: + + # Create a function object. + function = self.prototype.CodeGen() + + # If this is a binary operator, install its precedence. + if self.prototype.IsBinaryOp(): + operator = self.prototype.GetOperatorName() + g_binop_precedence[operator] = self.prototype.precedence + + # Create a new basic block to start insertion into. + block = function.append_basic_block('entry') + global g_llvm_builder + g_llvm_builder = Builder.new(block) + + # Finish off the function. + try: + return_value = self.body.CodeGen() + g_llvm_builder.ret(return_value) + + # Validate the generated code, checking for consistency. + function.verify() + + # Optimize the function. + g_llvm_pass_manager.run(function) + except: + function.delete() + if self.prototype.IsBinaryOp(): + del g_binop_precedence[self.prototype.GetOperatorName()] + raise + + return function + + Parser + ------ + + class Parser(object): + + def **init**\ (self, tokens): self.tokens = tokens self.Next() + + # Provide a simple token buffer. Parser.current is the current token the + # parser is looking at. Parser.Next() reads another token from the lexer + and # updates Parser.current with its results. def Next(self): + self.current = self.tokens.next() + + # Gets the precedence of the current token, or -1 if the token is not a + binary # operator. def GetCurrentTokenPrecedence(self): if + isinstance(self.current, CharacterToken): return + g_binop_precedence.get(self.current.char, -1) else: return -1 + + # identifierexpr ::= identifier \| identifier '(' expression\* ')' def + ParseIdentifierExpr(self): identifier_name = self.current.name + self.Next() # eat identifier. + + :: + + if self.current != CharacterToken('('): # Simple variable reference. + return VariableExpressionNode(identifier_name) + + # Call. + self.Next() # eat '('. + args = [] + if self.current != CharacterToken(')'): + while True: + args.append(self.ParseExpression()) + if self.current == CharacterToken(')'): + break + elif self.current != CharacterToken(','): + raise RuntimeError('Expected ")" or "," in argument list.') + self.Next() + + self.Next() # eat ')'. + return CallExpressionNode(identifier_name, args) + + # numberexpr ::= number def ParseNumberExpr(self): result = + NumberExpressionNode(self.current.value) self.Next() # consume the + number. return result + + # parenexpr ::= '(' expression ')' def ParseParenExpr(self): self.Next() + # eat '('. + + :: + + contents = self.ParseExpression() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")".') + self.Next() # eat ')'. + + return contents + + # ifexpr ::= 'if' expression 'then' expression 'else' expression def + ParseIfExpr(self): self.Next() # eat the if. + + :: + + # condition. + condition = self.ParseExpression() + + if not isinstance(self.current, ThenToken): + raise RuntimeError('Expected "then".') + self.Next() # eat the then. + + then_branch = self.ParseExpression() + + if not isinstance(self.current, ElseToken): + raise RuntimeError('Expected "else".') + self.Next() # eat the else. + + else_branch = self.ParseExpression() + + return IfExpressionNode(condition, then_branch, else_branch) + + # forexpr ::= 'for' identifier '=' expr ',' expr (',' expr)? 'in' + expression def ParseForExpr(self): self.Next() # eat the for. + + :: + + if not isinstance(self.current, IdentifierToken): + raise RuntimeError('Expected identifier after for.') + + loop_variable = self.current.name + self.Next() # eat the identifier. + + if self.current != CharacterToken('='): + raise RuntimeError('Expected "=" after for variable.') + self.Next() # eat the '='. + + start = self.ParseExpression() + + if self.current != CharacterToken(','): + raise RuntimeError('Expected "," after for start value.') + self.Next() # eat the ','. + + end = self.ParseExpression() + + # The step value is optional. + if self.current == CharacterToken(','): + self.Next() # eat the ','. + step = self.ParseExpression() + else: + step = None + + if not isinstance(self.current, InToken): + raise RuntimeError('Expected "in" after for variable specification.') + self.Next() # eat 'in'. + + body = self.ParseExpression() + + return ForExpressionNode(loop_variable, start, end, step, body) + + # primary ::= identifierexpr \| numberexpr \| parenexpr \| ifexpr \| + forexpr def ParsePrimary(self): if isinstance(self.current, + IdentifierToken): return self.ParseIdentifierExpr() elif + isinstance(self.current, NumberToken): return self.ParseNumberExpr() + elif isinstance(self.current, IfToken): return self.ParseIfExpr() elif + isinstance(self.current, ForToken): return self.ParseForExpr() elif + self.current == CharacterToken('('): return self.ParseParenExpr() else: + raise RuntimeError('Unknown token when expecting an expression.') + + # unary ::= primary \| unary_operator unary def ParseUnary(self): # If + the current token is not an operator, it must be a primary expression. + if (not isinstance(self.current, CharacterToken) or self.current in + [CharacterToken('('), CharacterToken(',')]): return self.ParsePrimary() + + :: + + # If this is a unary operator, read it. + operator = self.current.char + self.Next() # eat the operator. + return UnaryExpressionNode(operator, self.ParseUnary()) + + # binoprhs ::= (binary_operator unary)\* def ParseBinOpRHS(self, left, + left_precedence): # If this is a binary operator, find its precedence. + while True: precedence = self.GetCurrentTokenPrecedence() + + :: + + # If this is a binary operator that binds at least as tightly as the + # current one, consume it; otherwise we are done. + if precedence < left_precedence: + return left + + binary_operator = self.current.char + self.Next() # eat the operator. + + # Parse the unary expression after the binary operator. + right = self.ParseUnary() + + # If binary_operator binds less tightly with right than the operator after + # right, let the pending operator take right as its left. + next_precedence = self.GetCurrentTokenPrecedence() + if precedence < next_precedence: + right = self.ParseBinOpRHS(right, precedence + 1) + + # Merge left/right. + left = BinaryOperatorExpressionNode(binary_operator, left, right) + + # expression ::= unary binoprhs def ParseExpression(self): left = + self.ParseUnary() return self.ParseBinOpRHS(left, 0) + + # prototype # ::= id '(' id\* ')' # ::= binary LETTER number? (id, id) # + ::= unary LETTER (id) def ParsePrototype(self): precedence = None if + isinstance(self.current, IdentifierToken): kind = 'normal' + function_name = self.current.name self.Next() # eat function name. elif + isinstance(self.current, UnaryToken): kind = 'unary' self.Next() # eat + 'unary'. if not isinstance(self.current, CharacterToken): raise + RuntimeError('Expected an operator after "unary".') function_name = + 'unary' + self.current.char self.Next() # eat the operator. elif + isinstance(self.current, BinaryToken): kind = 'binary' self.Next() # eat + 'binary'. if not isinstance(self.current, CharacterToken): raise + RuntimeError('Expected an operator after "binary".') function_name = + 'binary' + self.current.char self.Next() # eat the operator. if + isinstance(self.current, NumberToken): if not 1 <= self.current.value <= + 100: raise RuntimeError('Invalid precedence: must be in range [1, + 100].') precedence = self.current.value self.Next() # eat the + precedence. else: raise RuntimeError('Expected function name, "unary" or + "binary" in ' 'prototype.') + + :: + + if self.current != CharacterToken('('): + raise RuntimeError('Expected "(" in prototype.') + self.Next() # eat '('. + + arg_names = [] + while isinstance(self.current, IdentifierToken): + arg_names.append(self.current.name) + self.Next() + + if self.current != CharacterToken(')'): + raise RuntimeError('Expected ")" in prototype.') + + # Success. + self.Next() # eat ')'. + + if kind == 'unary' and len(arg_names) != 1: + raise RuntimeError('Invalid number of arguments for a unary operator.') + elif kind == 'binary' and len(arg_names) != 2: + raise RuntimeError('Invalid number of arguments for a binary operator.') + + return PrototypeNode(function_name, arg_names, kind != 'normal', precedence) + + # definition ::= 'def' prototype expression def ParseDefinition(self): + self.Next() # eat def. proto = self.ParsePrototype() body = + self.ParseExpression() return FunctionNode(proto, body) + + # toplevelexpr ::= expression def ParseTopLevelExpr(self): proto = + PrototypeNode('', []) return FunctionNode(proto, self.ParseExpression()) + + # external ::= 'extern' prototype def ParseExtern(self): self.Next() # + eat extern. return self.ParsePrototype() + + # Top-Level parsing def HandleDefinition(self): + self.Handle(self.ParseDefinition, 'Read a function definition:') + + def HandleExtern(self): self.Handle(self.ParseExtern, 'Read an extern:') + + def HandleTopLevelExpression(self): try: function = + self.ParseTopLevelExpr().CodeGen() result = + g_llvm_executor.run_function(function, []) print 'Evaluated to:', + result.as_real(Type.double()) except Exception, e: print 'Error:', e + try: self.Next() # Skip for error recovery. except: pass + + def Handle(self, function, message): try: print message, + function().CodeGen() except Exception, e: print 'Error:', e try: + self.Next() # Skip for error recovery. except: pass + + Main driver code. + ----------------- + + def main(): # Set up the optimizer pipeline. Start with registering info + about how the # target lays out data structures. + g_llvm_pass_manager.add(g_llvm_executor.target_data) # Do simple + "peephole" optimizations and bit-twiddling optzns. + g_llvm_pass_manager.add(PASS_INSTRUCTION_COMBINING) # Reassociate + expressions. g_llvm_pass_manager.add(PASS_REASSOCIATE) # Eliminate + Common SubExpressions. g_llvm_pass_manager.add(PASS_GVN) # Simplify + the control flow graph (deleting unreachable blocks, etc). + g_llvm_pass_manager.add(PASS_CFG_SIMPLIFICATION) + + g_llvm_pass_manager.initialize() + + # Install standard binary operators. # 1 is lowest possible precedence. + 40 is the highest. g_binop_precedence['<'] = 10 + g_binop_precedence['+'] = 20 g_binop_precedence['-'] = 20 + g_binop_precedence['\*'] = 40 + + # Run the main "interpreter loop". while True: print 'ready>', try: raw + = raw_input() except KeyboardInterrupt: break + + :: + + parser = Parser(Tokenize(raw)) + while True: + # top ::= definition | external | expression | EOF + if isinstance(parser.current, EOFToken): + break + if isinstance(parser.current, DefToken): + parser.HandleDefinition() + elif isinstance(parser.current, ExternToken): + parser.HandleExtern() + else: + parser.HandleTopLevelExpression() + + # Print out all of the generated code. print '', g_llvm_module + + if **name** == '**main**\ ': main() diff --git a/docs/_build/html/_sources/doc/kaleidoscope/PythonLangImpl7.txt b/docs/_build/html/_sources/doc/kaleidoscope/PythonLangImpl7.txt new file mode 100644 index 0000000..576b5b4 --- /dev/null +++ b/docs/_build/html/_sources/doc/kaleidoscope/PythonLangImpl7.txt @@ -0,0 +1,1611 @@ +******************************************************************************* +Chapter 7: Extending the Language: Mutable Variables / SSA construction +******************************************************************************* + +Written by `Chris Lattner `_ and `Max +Shawabkeh `_ + +Introduction # {#intro} +======================= + +Welcome to Chapter 7 of the `Implementing a language with +LLVM `_ tutorial. In +chapters 1 through 6, we've built a very respectable, albeit simple, +`functional programming +language `_. In our +journey, we learned some parsing techniques, how to build and represent +an AST, how to build LLVM IR, and how to optimize the resultant code as +well as JIT compile it. + +While Kaleidoscope is interesting as a functional language, the fact +that it is functional makes it "too easy" to generate LLVM IR for it. In +particular, a functional language makes it very easy to build LLVM IR +directly in `SSA +form `_. +Since LLVM requires that the input code be in SSA form, this is a very +nice property and it is often unclear to newcomers how to generate code +for an imperative language with mutable variables. + +The short (and happy) summary of this chapter is that there is no need +for your front-end to build SSA form: LLVM provides highly tuned and +well tested support for this, though the way it works is a bit +unexpected for some. + +Why is this a hard problem? # {#why} +==================================== + +To understand why mutable variables cause complexities in SSA +construction, consider this extremely simple C example: + + +.. code-block:: python + + int G, H; int test(_Bool Condition) { int X; if + (Condition) X = G; else X = H; return X; } + + + +In this case, we have the variable "X", whose value depends on the path +executed in the program. Because there are two different possible values +for X before the return instruction, a PHI node is inserted to merge the +two values. The LLVM IR that we want for this example looks like this: + + +.. code-block:: llvm + + @G = weak global i32 0 ; type of @G is i32\* @H = + weak global i32 0 ; type of @H is i32\* define i32 @test(i1 %Condition) + { entry: br i1 %Condition, label %cond_true, label %cond_false + cond_true: %X.0 = load i32\* @G br label %cond_next cond_false: %X.1 + = load i32\* @H br label %cond_next cond_next: %X.2 = phi i32 [ %X.1, + %cond_false ], [ %X.0, %cond_true ] ret i32 %X.2 } + + + +In this example, the loads from the G and H global variables are +explicit in the LLVM IR, and they live in the then/else branches of the +if statement (cond\_true/cond\_false). In order to merge the incoming +values, the X.2 phi node in the cond\_next block selects the right value +to use based on where control flow is coming from: if control flow comes +from the cond\_false block, X.2 gets the value of X.1. Alternatively, if +control flow comes from cond\_true, it gets the value of X.0. The intent +of this chapter is not to explain the details of SSA form. For more +information, see one of the many `online +references `_. + +The question for this article is "who places the phi nodes when lowering +assignments to mutable variables?". The issue here is that LLVM +*requires* that its IR be in SSA form: there is no "non-ssa" mode for +it. However, SSA construction requires non-trivial algorithms and data +structures, so it is inconvenient and wasteful for every front-end to +have to reproduce this logic. + +Memory in LLVM # {#memory} +========================== + +The 'trick' here is that while LLVM does require all register values to +be in SSA form, it does not require (or permit) memory objects to be in +SSA form. In the example above, note that the loads from G and H are +direct accesses to G and H: they are not renamed or versioned. This +differs from some other compiler systems, which do try to version memory +objects. In LLVM, instead of encoding dataflow analysis of memory into +the LLVM IR, it is handled with `Analysis +Passes `_ which are +computed on demand. + +With this in mind, the high-level idea is that we want to make a stack +variable (which lives in memory, because it is on the stack) for each +mutable object in a function. To take advantage of this trick, we need +to talk about how LLVM represents stack variables. + +In LLVM, all memory accesses are explicit with load/store instructions, +and it is carefully designed not to have (or need) an "address-of" +operator. Notice how the type of the @G/@H global variables is actually +"i32\ *" even though the variable is defined as "i32". What this means +is that @G defines*\ space\* for an i32 in the global data area, but its +*name* actually refers to the address for that space. Stack variables +work the same way, except that instead of being declared with global +variable definitions, they are declared with the `LLVM alloca +instruction `_: + + +.. code-block:: python + + define i32 @example() { entry: %X = alloca i32 ; + type of %X is i32\ *. ... %tmp = load i32* %X ; load the stack value %X + from the stack. %tmp2 = add i32 %tmp, 1 ; increment it store i32 %tmp2, + i32\* %X ; store it back ... + + + +This code shows an example of how you can declare and manipulate a stack +variable in the LLVM IR. Stack memory allocated with the alloca +instruction is fully general: you can pass the address of the stack slot +to functions, you can store it in other variables, etc. In our example +above, we could rewrite the example to use the alloca technique to avoid +using a PHI node: + + +.. code-block:: llvm + + @G = weak global i32 0 ; type of @G is i32\* @H = + weak global i32 0 ; type of @H is i32\* define i32 @test(i1 %Condition) + { entry: %X = alloca i32 ; type of %X is i32\ *. br i1 %Condition, label + %cond_true, label %cond_false cond_true: %X.0 = load i32* @G store + i32 %X.0, i32\* %X ; Update X br label %cond_next cond_false: %X.1 = + load i32\* @H store i32 %X.1, i32\* %X ; Update X br label %cond_next + cond_next: %X.2 = load i32\* %X ; Read X ret i32 %X.2 } {% endhighlight + %} + + With this, we have discovered a way to handle arbitrary mutable + variables without the need to create Phi nodes at all: + + .. raw:: html + +