Skip to content
This repository has been archived by the owner on Feb 4, 2020. It is now read-only.

Commit

Permalink
Implement chapter 8 - Compiling to Object Code (#1)
Browse files Browse the repository at this point in the history
* Duplicate chapter7.py as start code for chapter 8(Compiling to Object Code).

* Implement compiling to object code.

* Update README.rst for missing chapters.

* Fix typo.

* Update chapter title in the source code.

* Combine chapter 7 and chapter 8.

* Separate the object code compilation and output to file in order to unittest.

* Add unittest for `compile_to_object_code`.
  • Loading branch information
thebusytypist authored and eliben committed Nov 21, 2016
1 parent dc57118 commit 93c7559
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 3 deletions.
4 changes: 2 additions & 2 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ into Python, using the `llvmlite <https://github.com/numba/llvmlite>`_ package
that exposes LLVM to Python.

This repository is fairly complete - the whole Kaleidoscope language is
implemented. The only thing missing is Chapter 8 - Debug Information, because
``llvlite`` does not yet support convenient emission of debug info.
implemented. The only thing missing is Chapter 9 - Adding Debug Information,
because ``llvmlite`` does not yet support convenient emission of debug info.

How to use this code
--------------------
Expand Down
53 changes: 52 additions & 1 deletion chapter7.py → chapter7and8.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Chapter 7 - Mutable variables
# Chapter 7 & 8 - Mutable variables and Compiling to Object Code

from collections import namedtuple
from ctypes import CFUNCTYPE, c_double
Expand Down Expand Up @@ -938,6 +938,31 @@ def evaluate(self, codestr, optimize=True, llvmdump=False):
result = fptr()
return result

def compile_to_object_code(self):
# Compile to object code for native target.
#
# We use the small code model here,
# rather than the default one `jitdefault`.
#
# The reason is that only ELF format is supported
# under the `jitdefault` code model on Windows.
# However, COFF is commonly used by compilers on Windows.
#
# Please refer to https://github.com/numba/llvmlite/issues/181
# for more information about this issue.
#
# Also refer to
# http://eli.thegreenplace.net/2012/01/03/
# understanding-the-x64-code-models/
# for more information about code model.
target_machine = self.target.create_target_machine(
codemodel='small')

# Convert LLVM IR into in-memory representation
llvmmod = llvm.parse_assembly(str(self.codegen.module))

return target_machine.emit_object(llvmmod)

def _add_builtins(self, module):
# The C++ tutorial adds putchard() simply by defining it in the host C++
# code, which is then accessible to the JIT. It doesn't work as simply
Expand Down Expand Up @@ -1060,6 +1085,24 @@ def foo(a b)
self.assertEqual(e.evaluate('foo(2, 3)'), 605)
self.assertEqual(e.evaluate('foo(10, 20)'), 20030)

def test_compiling_to_object_code(self):
e = KaleidoscopeEvaluator()
e.evaluate('def adder(a b) a + b')
obj = e.compile_to_object_code()
obj_format = llvm.get_object_format()

# Check the magic number of object format.
elf_magic = b'\x7fELF'
macho_magic = b'\xfe\xed\xfa\xcf'
if obj[:4] == elf_magic:
self.assertEqual(obj_format, 'ELF')
elif obj[:4] == macho_magic:
self.assertEqual(obj_format, 'MachO')
else:
# There are too many variations of COFF magic number.
# Assume all other formats are COFF.
self.assertEqual(obj_format, 'COFF')


if __name__ == '__main__':
# Evaluate some code.
Expand All @@ -1071,3 +1114,11 @@ def foo(x y z)
s1 * s2
''')
print(kalei.evaluate('foo(1, 2, 3)'))

obj = kalei.compile_to_object_code()

# Output object code to a file.
filename = 'output.o'
with open(filename, 'wb') as obj_file:
obj_file.write(obj)
print('Wrote ' + filename)

0 comments on commit 93c7559

Please sign in to comment.