def codegen(context, builder, signature, args): data, idx, ch = args if bitsize < 32: ch = builder.trunc(ch, IntType(bitsize)) ptr = builder.bitcast(data, IntType(bitsize).as_pointer()) builder.store(ch, builder.gep(ptr, [idx])) return context.get_dummy_value()
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()
def visit_Boolean(self, node: Boolean) -> Constant: """Converts the boolean type to an integer (i1) constant. Args: nodo (Boolean): a token represeting a literal boolean type Returns: Constant: a constant of type IntType (1) representing the Boolean type: 1 = True and 0 = False """ if node.token.type == TokenType.FALSE: return Constant(IntType(1), 0) else: return Constant(IntType(1), 1)
def emit_IF(self): then_block = self.function.append_basic_block() else_block = self.function.append_basic_block() exit_block = self.function.append_basic_block() self.builder.cbranch(self.builder.trunc(self.pop(), IntType(1)), then_block, else_block) self.set_block(then_block) self.blocks.append([then_block, else_block, exit_block])
def test_array_repr(): int8 = IntType(8) tp = ArrayType(int8, 3) int8_1 = Constant(int8, 1) tp1 = tp.gep(int8_1) print(tp1, type(tp1)) values = [Constant(int8, x) for x in (5, 10, -15)] c = Constant(tp, values) print(c) assert str(c) == "[3 x i8] [i8 5, i8 10, i8 -15]" c = Constant(tp, bytearray(b"\x01\x02\x03")) print(c) assert str(c) == '[3 x i8] c"\\01\\02\\03"'
def visit_String(self, node: String) -> Constant: """Converts the literal string to an array of characters. Args: node (String): a token represeting a string (literal) Returns: Constant: a constant containing a array of characters """ content = node.value return Constant(ArrayType(IntType(8), len(content)), bytearray(content.encode("utf8")))
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)
''' from collections import ChainMap from functools import partialmethod # LLVM imports. Don't change this. from llvmlite.ir import (Module, IRBuilder, Function, IntType, DoubleType, VoidType, Constant, GlobalVariable, FunctionType) # Declare the LLVM type objects that you want to use for the low-level # in our intermediate code. Basically, you're going to need to # declare the integer, float, and char types here. These correspond # to the types being used the intermediate code being created by # the ircode.py file. int_type = IntType(32) # 32-bit integer float_type = DoubleType() # 64-bit float byte_type = IntType(8) # 8-bit integer void_type = VoidType() # Void type. This is a special type # used for internal functions returning # no value LLVM_TYPE_MAPPING = { 'I': int_type, 'F': float_type, 'B': byte_type, None: void_type } # The following class is going to generate the LLVM instruction stream.
def emit_CBRANCH(self, test, true_label, false_label): true_block = self.basicblocks[true_label] false_block = self.basicblocks[false_label] self.builder.cbranch(self.builder.trunc(self.temps[test], IntType(1)), true_block, false_block)
# 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)
def emit_ALLOCI(self, name): var = self.builder.alloca(IntType(32), name=name) self.builder.store(Constant(int_type, 0), var) self.vars[name] = var
import math import sys import unittest from llvmlite.ir import ( Constant, FloatType, DoubleType, LiteralStructType, IntType, ArrayType, HalfType, ) from llvmlite.tests import TestCase int8 = IntType(8) int16 = IntType(16) PY36_OR_LATER = sys.version_info[:2] >= (3, 6) class TestValueRepr(TestCase): def test_double_repr(self): def check_repr(val, expected): c = Constant(DoubleType(), val) self.assertEqual(str(c), expected) check_repr(math.pi, "double 0x400921fb54442d18") check_repr(float("inf"), "double 0x7ff0000000000000") check_repr(float("-inf"), "double 0xfff0000000000000")
from collections import ChainMap # LLVM imports. Don't change this. from llvmlite.ir import ( Module, IRBuilder, Function, IntType, DoubleType, VoidType, Constant, GlobalVariable, FunctionType ) # Declare the LLVM type objects that you want to use for the low-level # in our intermediate code. Basically, you're going to need to # declare the integer, float, and char types here. These correspond # to the types being used the intermediate code being created by # the ircode.py file. int_type = IntType(32) # 32-bit integer float_type = DoubleType() # 64-bit float void_type = VoidType() # Void type. This is a special type # used for internal functions returning # no value # Mapping of Wabbit names to LLVM types typemap = { 'int': int_type, 'float' : float_type, 'char': int_type, 'bool': int_type, None: void_type } # The following class is going to generate the LLVM instruction stream.
def cast_to_byte(self, value): return self.builder.trunc(value, IntType(1))
def emit_CBRANCH(self, test_target, true_label, false_label): true_block = self.get_block(true_label) false_block = self.get_block(false_label) testvar = self.temps[test_target] self.builder.cbranch(self.builder.trunc(testvar, IntType(1)), true_block, false_block)
def emit_CBREAK(self): next_block = self.function.append_basic_block() self.builder.cbranch(self.builder.trunc(self.pop(), IntType(1)), self.blocks[-1][1], next_block) self.set_block(next_block)
# 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
# llvmgen.py code = [('VARI', 'x'), ('CONSTI', 4), ('STORE', 'x'), ('VARI', 'y'), ('CONSTI', 5), ('STORE', 'y'), ('VARI', 'd'), ('LOAD', 'x'), ('LOAD', 'x'), ('MULI', ), ('LOAD', 'y'), ('LOAD', 'y'), ('MULI', ), ('ADDI', ), ('STORE', 'd'), ('LOAD', 'd'), ('PRINTI', )] from llvmlite.ir import (Module, Function, FunctionType, IntType, VoidType, Constant, IRBuilder) int_type = IntType(32) void_type = VoidType() class LLVMGenerator: 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 = {} def emit(self, code):
def codegen(context, builder, signature, args): data, idx = args ptr = builder.bitcast(data, IntType(bitsize).as_pointer()) ch = builder.load(builder.gep(ptr, [idx])) return builder.zext(ch, IntType(32))
def emit_CBRANCH(self, test, label1, label2): tmp = self.builder.trunc(self.temps[test], IntType(1), 'tmp') self.builder.cbranch(tmp, self.blocks[label1], self.blocks[label2])
# 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)
# hellollvm.py from llvmlite.ir import (Module, Function, FunctionType, IntType, Constant, IRBuilder) from llvmlite.ir import DoubleType 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)) 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) # Sum the values and return the result d2 = builder.fadd(xsquared, ysquared) builder.ret(d2)
# 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)
# total = total + n; # n = n - 1; # } # return total; # } # from llvmlite.ir import ( Module, IRBuilder, IntType, Function, FunctionType, Constant ) mod = Module('example') # Declare the f function with our loop f_func = Function(mod, FunctionType(IntType(32), [IntType(32)]), name='f') block = f_func.append_basic_block("entry") builder = IRBuilder(block) # Copy the argument to a local variable. For reasons, that are # complicated, we copy the function argument to a local variable # allocated on the stack (this makes mutations of the variable # easier when looping). n_var = builder.alloca(IntType(32), name='n') builder.store(f_func.args[0], n_var) # Allocate the result variable total_var = builder.alloca(IntType(32), name='total')