Exemple #1
0
    def __init__(self):
        self.module = Module('hello')
        self._print_int = Function(self.module,
                                   FunctionType(void_type, [int_type]),
                                   name='_print_int')

        self.function = Function(self.module,
                                 FunctionType(int_type, []),
                                 name='main')
        self.block = self.function.append_basic_block('entry')
        self.builder = IRBuilder(self.block)

        self.stack = []
        self.vars = {}
Exemple #2
0
    def __init__(self):
        # Perform the basic LLVM initialization.  You need the following parts:
        #
        #    1.  A top-level Module object
        #    2.  A Function instance in which to insert code
        #    3.  A Builder instance to generate instructions
        #
        # Note: For project 5, we don't have any user-defined
        # functions so we're just going to emit all LLVM code into a top
        # level function void main() { ... }.   This will get changed later.

        self.module = Module('module')
        self.function = Function(self.module,
                                 FunctionType(void_type, []),
                                 name='main')

        self.block = self.function.append_basic_block('entry')
        self.builder = IRBuilder(self.block)

        # Dictionary that holds all of the global variable/function declarations.
        # Any declaration in the Gone source code is going to get an entry here
        self.vars = {}

        # Dictionary that holds all of the temporary registers created in
        # the intermediate code.
        self.temps = {}

        # Initialize the runtime library functions (see below)
        self.declare_runtime_library()
Exemple #3
0
    def declare_runtime_library(self):
        # Certain functions such as I/O and string handling are often easier
        # to implement in an external C library.  This method should make
        # the LLVM declarations for any runtime functions to be used
        # during code generation.    Please note that runtime function
        # functions are implemented in C in a separate file wabbitrt.c

        self.runtime = {}

        # Declare runtime functions
        functions = [
            ('_print_int', void_type, [int_type]),
            ('_print_float', void_type, [float_type]),
            ('_print_byte', void_type, [int_type]),
            ('_grow', int_type, [int_type]),
            ('_peeki', int_type, [int_type]),
            ('_peekf', float_type, [int_type]),
            ('_peekb', int_type, [int_type]),
            ('_pokei', void_type, [int_type, int_type]),
            ('_pokef', void_type, [int_type, float_type]),
            ('_pokeb', void_type, [int_type, int_type]),
            ]
        for name, rettype, args in functions:
            self.runtime[name] = Function(self.module,
                                          FunctionType(rettype, args),
                                          name=name)
Exemple #4
0
    def declare_function(self, funcname, argtypes, rettype):
        self.function = Function(self.module,
                                 FunctionType(rettype, argtypes),
                                 name=funcname)

        # Insert a reference in global namespace
        self.globals[funcname] = self.function
Exemple #5
0
    def declare_runtime_library(self):
        self.runtime = {}

        self.runtime['_print_int'] = Function(self.module,
                                              FunctionType(
                                                  void_type, [int_type]),
                                              name="_print_int")

        self.runtime['_print_float'] = Function(self.module,
                                                FunctionType(
                                                    void_type, [float_type]),
                                                name="_print_float")

        self.runtime['_print_byte'] = Function(self.module,
                                               FunctionType(
                                                   void_type, [byte_type]),
                                               name="_print_byte")
Exemple #6
0
    def visit_Writeln(self, node: Writeln) -> None:
        """Converts the contents of the command writeln to LLVM ir code and adds the
        print call to the operating system.

        Args:
            node (Writeln): content passed in the command writeln
        """

        self.printf_counter += 1
        output_operation_type = "%s"

        if isinstance(node.content[0], BinaryOperator):
            self._create_instruct("BinaryOperator", is_printf=True)

        writeln_content = self.visit(node.content[0])

        if isinstance(writeln_content, VarSymbol):
            content = self.GLOBAL_MEMORY[writeln_content.name]
        else:
            content = writeln_content

        content_type = type(content.type).__name__

        if self.builder.block.is_terminated:
            self._create_instruct(typ=content_type, is_printf=True)

        if isinstance(content.type, DoubleType):
            output_operation_type = "%f"

        output_format = f"{output_operation_type}\n\0"
        printf_format = Constant(
            ArrayType(IntType(8), len(output_format)),
            bytearray(output_format.encode("utf8")),
        )

        fstr = GlobalVariable(self.module,
                              printf_format.type,
                              name=f"fstr_{self.printf_counter}")
        fstr.linkage = "internal"
        fstr.global_constant = True
        fstr.initializer = printf_format

        writeln_type = FunctionType(IntType(32), [], var_arg=True)
        writeln = Function(
            self.module,
            writeln_type,
            name=f"printf_{content_type}_{self.printf_counter}",
        )

        body = self.builder.alloca(content.type)
        temp_loaded = self.builder.load(body)
        self.builder.store(temp_loaded, body)

        void_pointer_type = IntType(8).as_pointer()
        casted_arg = self.builder.bitcast(fstr, void_pointer_type)
        self.builder.call(writeln, [casted_arg, body])
        self.builder.ret_void()
Exemple #7
0
    def declare_runtime_library(self):
        # Certain functions such as I/O and string handling are often easier
        # to implement in an external C library.  This method should make
        # the LLVM declarations for any runtime functions to be used
        # during code generation.    Please note that runtime function
        # functions are implemented in C in a separate file gonert.c

        self.runtime = {}

        # Declare printing functions
        self.runtime['_print_int'] = Function(self.module,
                                              FunctionType(void_type, [int_type]),
                                              name="_print_int")

        self.runtime['_print_float'] = Function(self.module,
                                                FunctionType(void_type, [float_type]),
                                                name="_print_float")

        self.runtime['_print_byte'] = Function(self.module,
                                                FunctionType(void_type, [byte_type]),
                                                name="_print_byte")
Exemple #8
0
    def generate_code(self, ir_function):
        # Given a sequence of SSA intermediate code tuples, generate LLVM
        # instructions using the current builder (self.builder).  Each
        # opcode tuple (opcode, args) is dispatched to a method of the
        # form self.emit_opcode(args)
        # print(ir_function)
        self.function = Function(
            self.module,
            FunctionType(LLVM_TYPE_MAPPING[ir_function.return_type], [
                LLVM_TYPE_MAPPING[ptype] for _, ptype in ir_function.parameters
            ]),
            name=ir_function.name)

        self.block = self.function.append_basic_block('entry')
        self.builder = IRBuilder(self.block)

        # Save the function as a global to be referenced later on another
        # function
        self.globals[ir_function.name] = self.function

        # All local variables are stored here
        self.locals = {}

        self.vars = ChainMap(self.locals, self.globals)

        # Dictionary that holds all of the temporary registers created in
        # the intermediate code.
        self.temps = {}

        # Setup the function parameters
        for n, (pname, ptype) in enumerate(ir_function.parameters):
            self.vars[pname] = self.builder.alloca(LLVM_TYPE_MAPPING[ptype],
                                                   name=pname)
            self.builder.store(self.function.args[n], self.vars[pname])

        # Allocate the return value and return_block
        if ir_function.return_type:
            self.vars['return'] = self.builder.alloca(
                LLVM_TYPE_MAPPING[ir_function.return_type], name='return')
        self.return_block = self.function.append_basic_block('return')

        for opcode, *args in ir_function.code:
            if hasattr(self, 'emit_' + opcode):
                getattr(self, 'emit_' + opcode)(*args)
            else:
                print('Warning: No emit_' + opcode + '() method')

        if not self.block.is_terminated:
            self.builder.branch(self.return_block)

        self.builder.position_at_end(self.return_block)
        self.builder.ret(self.builder.load(self.vars['return'], 'return'))
Exemple #9
0
    def generate_functions(self, functions):
        type_dict = {
            'int': int_type,
            'float': float_type,
            'byte': byte_type,
            'bool': int_type,
            'void': void_type
        }
        for function in functions:
            # register function
            name = function.name if function.name != 'main' else '_gone_main'
            return_type = type_dict[function.return_type]
            param_types = [type_dict[t] for t in function.param_types]
            function_type = FunctionType(return_type, param_types)
            self.function = Function(self.module, function_type, name=name)
            self.globals[name] = self.function
            self.blocks = {}
            self.block = self.function.append_basic_block('entry')
            self.blocks['entry'] = self.block
            self.builder = IRBuilder(self.block)

            # local scope
            self.vars = self.vars.new_child()
            self.temps = {}
            for n, (param_name, param_type) in enumerate(
                    zip(function.param_names, param_types)):
                var = self.builder.alloca(param_type, name=param_name)
                var.initializer = Constant(param_type, 0)
                self.vars[param_name] = var
                self.builder.store(self.function.args[n],
                                   self.vars[param_name])

            # alloc return var / block
            if function.return_type != 'void':
                self.vars['return'] = self.builder.alloca(return_type,
                                                          name='return')
            self.return_block = self.function.append_basic_block('return')

            # generate instructions
            self.generate_code(function)

            # return
            if not self.block.is_terminated:
                self.builder.branch(self.return_block)

            self.builder.position_at_end(self.return_block)
            if function.return_type != 'void':
                self.builder.ret(
                    self.builder.load(self.vars['return'], 'return'))
            else:
                self.builder.ret_void()
            self.vars = self.vars.parents
Exemple #10
0
    def emit_FUNCTION(self, f_name, arguments, return_type):
        arguments = eval(arguments)
        argtypes = list(map(lambda z: z[0], arguments))

        f_func = Function(self.module,
                          FunctionType(
                            type_lookup[return_type],
                            argtypes
                          ),
                          name=f_name)
        self.current_func = f_func

        self.block = self.current_func.append_basic_block('entry')

        self.return_block = self.current_func.append_basic_block('return')
        self.return_var = self.builder.alloca(type_lookup[return_type], name='return')
        self.funcs[f_name] = self.current_func
Exemple #11
0
    def generate_code(self, ir_function):
        self.function = Function(
            self.module,
            FunctionType(LLVM_TYPE_MAPPING[ir_function.return_type], [
                LLVM_TYPE_MAPPING[ptype] for _, ptype in ir_function.parameters
            ]),
            name=ir_function.name)

        self.block = self.function.append_basic_block('entry')
        self.builder = IRBuilder(self.block)

        self.globals[ir_function.name] = self.function

        self.locals = {}

        self.vars = ChainMap(self.locals, self.globals)

        self.temps = {}

        for n, (pname, ptype) in enumerate(ir_function.parameters):
            self.vars[pname] = self.builder.alloca(LLVM_TYPE_MAPPING[ptype],
                                                   name=pname)
            self.builder.store(self.function.args[n], self.vars[pname])

        if ir_function.return_type:
            self.vars['return'] = self.builder.alloca(
                LLVM_TYPE_MAPPING[ir_function.return_type], name='return')
        self.return_block = self.function.append_basic_block('return')

        for opcode, *args in ir_function.code:
            if hasattr(self, 'emit_' + opcode):
                getattr(self, 'emit_' + opcode)(*args)
            else:
                print('Warning: No emit_' + opcode + '() method')

        if not self.block.is_terminated:
            self.builder.branch(self.return_block)

        self.builder.position_at_end(self.return_block)
        self.builder.ret(self.builder.load(self.vars['return'], 'return'))
Exemple #12
0
    def generate_function(self, name, return_type, arg_types, arg_names,
                          ircode):
        self.function = Function(self.module,
                                 FunctionType(return_type, arg_types),
                                 name=name)

        self.globals[name] = self.function

        self.block = self.function.append_basic_block('entry')
        self.builder = IRBuilder(self.block)

        self.locals = {}
        self.vars = ChainMap(self.locals, self.globals)

        # Have to declare local variables for holding function arguments
        for n, (name, ty) in enumerate(zip(arg_names, arg_types)):
            self.locals[name] = self.builder.alloca(ty, name=name)
            self.builder.store(self.function.args[n], self.locals[name])

        # Dictionary that holds all of the temporary registers created in
        # the intermediate code.
        self.temps = {}

        # Make the exit block for function return
        self.return_block = self.function.append_basic_block('return')
        if return_type != void_type:
            self.return_var = self.builder.alloca(return_type, name='return')

        self.generate_code(ircode)

        if not self.block.is_terminated:
            self.builder.branch(self.return_block)

        self.builder.position_at_end(self.return_block)
        if return_type != void_type:
            self.builder.ret(self.builder.load(self.return_var))
        else:
            self.builder.ret_void()
Exemple #13
0
    def _create_instruct(self, typ: str, is_printf: bool = False) -> None:
        """Create a new Function instruction and attach it to a new Basic Block Entry.

        Args:
            typ (str): node type.
            is_printf (bool, optional): Defaults to False.
        """

        if is_printf or typ in ["String", "ArrayType"]:
            self.str_counter += 1
            self.func_name = f"_{typ}.{self.str_counter}"
            func_type = FunctionType(VoidType(), [])
        elif typ == "Boolean":
            self.bool_counter += 1
            self.func_name = f"_{typ}.{self.bool_counter}"
            func_type = FunctionType(IntType(1), [])
        else:
            self.expr_counter += 1
            self.func_name = f"_{typ}_Expr.{self.expr_counter}"
            func_type = FunctionType(DoubleType(), [])

        main_func = Function(self.module, func_type, self.func_name)
        bb_entry = main_func.append_basic_block("entry")
        self.builder = IRBuilder(bb_entry)
Exemple #14
0
# hellollvm.py

from llvmlite.ir import (
    Module, Function, FunctionType, IntType,
    Constant, IRBuilder
    )

mod = Module('hello')
hello_func = Function(mod, 
                      FunctionType(IntType(32), []), 
                      name='hello')
block = hello_func.append_basic_block('entry')
builder = IRBuilder(block)
builder.ret(Constant(IntType(32), 37))

# A user-defined function
from llvmlite.ir import DoubleType

ty_double = DoubleType()
dsquared_func = Function(mod, 
                         FunctionType(ty_double, [ty_double, ty_double]), 
                         name='dsquared')
block = dsquared_func.append_basic_block('entry')
builder = IRBuilder(block)

# Get the function args
x, y = dsquared_func.args

# Compute temporary values for x*x and y*y
xsquared = builder.fmul(x, x)
ysquared = builder.fmul(y, y)
# hello_llvm.py
from llvmlite.ir import (Module, Function, FunctionType, IntType, IRBuilder,
                         Constant)

mod = Module('hello')
int_type = IntType(32)
hello_func = Function(mod, FunctionType(int_type, []), name='hello')
block = hello_func.append_basic_block('entry')
builder = IRBuilder(block)
builder.ret(Constant(IntType(32), 37))
print(mod)
Exemple #16
0
# A sample of executing an integer < in LLVM

from llvmlite.ir import (Module, Function, FunctionType, IntType, IRBuilder)

mod = Module('example')

# Define a function:
#
#    func lessthan(x int, y int) bool {
#         return x < y;
#    }
#
# Note: The result of boolean operations is a 1-bit integer

func = Function(mod,
                FunctionType(IntType(1),
                             [IntType(32), IntType(32)]),
                name='lessthan')

block = func.append_basic_block("entry")
builder = IRBuilder(block)

# The icmp_signed() instruction is used for all comparisons on
# integers.  For floating point, use fcmp_ordered().  The compare operation
# takes an operator expressed as a string such as '<', '>', '==',
# etc.

result = builder.icmp_signed('<', func.args[0], func.args[1])
builder.ret(result)

# ---- Test Code
Exemple #17
0
#     func f(a int, b int) int {
#          var c int;
#          if a < b {
#               c = a + b;
#          } else {
#               c = a - b;
#          }
#          return c;
#     }
#

from llvmlite.ir import (Module, IRBuilder, IntType, Function, FunctionType)

mod = Module('example')
f_func = Function(mod,
                  FunctionType(IntType(32),
                               [IntType(32), IntType(32)]),
                  name='f')

block = f_func.append_basic_block("entry")
builder = IRBuilder(block)

# Get the arguments
a_var, b_var = f_func.args

# Allocate the result variable
c_var = builder.alloca(IntType(32), name='c')

# Perform the comparison
testvar = builder.icmp_signed('<', a_var, b_var)

# Make three blocks
Exemple #18
0
# hellollvm.py

from llvmlite.ir import (
    Module, Function, FunctionType, IntType, VoidType,
    Constant, IRBuilder
    )

mod = Module('hello')

int_type = IntType(32)
void_type = VoidType()

_print_int = Function(mod, 
                      FunctionType(void_type, [int_type]), 
                      name='_print_int')

hello_func = Function(mod, FunctionType(int_type, []), name='hello')
block = hello_func.append_basic_block('entry')
builder = IRBuilder(block)

x = builder.alloca(int_type, name='x')
y = builder.alloca(int_type, name='y')
builder.store(Constant(int_type, 4), x)
builder.store(Constant(int_type, 5), y)
t1 = builder.load(x)
t2 = builder.load(x)
t3 = builder.mul(t1, t2)
t4 = builder.load(y)
t5 = builder.load(y)
t6 = builder.mul(t4, t5)
t7 = builder.add(t3, t6)