def _define_nrt_incref(module, atomic_incr): """ Implement NRT_incref in the module """ fn_incref = module.get_or_insert_function(incref_decref_ty, name="NRT_incref") # Cannot inline this for refcount pruning to work fn_incref.attributes.add('noinline') builder = ir.IRBuilder(fn_incref.append_basic_block()) [ptr] = fn_incref.args is_null = builder.icmp_unsigned("==", ptr, cgutils.get_null_value(ptr.type)) with cgutils.if_unlikely(builder, is_null): builder.ret_void() if _debug_print: cgutils.printf(builder, "*** NRT_Incref %zu [%p]\n", builder.load(ptr), ptr) builder.call(atomic_incr, [builder.bitcast(ptr, atomic_incr.args[0].type)]) builder.ret_void()
def _imp_dtor(context, module): """Define the dtor for list""" llvoidptr = context.get_value_type(types.voidptr) llsize = context.get_value_type(types.uintp) fnty = ir.FunctionType(ir.VoidType(), [llvoidptr, llsize, llvoidptr],) fname = "_numba_list_dtor" fn = module.get_or_insert_function(fnty, name=fname) if fn.is_declaration: # Set linkage fn.linkage = "linkonce_odr" # Define builder = ir.IRBuilder(fn.append_basic_block()) lp = builder.bitcast(fn.args[0], ll_list_type.as_pointer()) l = builder.load(lp) _call_list_free(context, builder, l) builder.ret_void() return fn
def check(likely): block = self.block(name='one') builder = ir.IRBuilder(block) z = ir.Constant(int1, 0) with builder.if_else(z, likely=likely) as (then, otherwise): with then: builder.branch(block) with otherwise: builder.ret_void() self.check_func_body(builder.function, """\ one: br i1 0, label %"one.if", label %"one.else", !prof !0 one.if: br label %"one" one.else: ret void one.endif: """) return builder
def emit_procedure(self, procedure): identifier, subprogram = procedure try: existing_func = self.module.get_global(identifier) return existing_func except KeyError: pass fnty = ir.FunctionType(ir.VoidType(), ()) func = ir.Function(self.module, fnty, identifier) block = func.append_basic_block('entry') builder = ir.IRBuilder(block) self.emit_subprogram(subprogram.content, builder) builder.ret_void() return func
def visit_Subroutine(self, node): self._current_scope = node._scope fn = ir.FunctionType( ir.VoidType(), [ir.IntType(64).as_pointer(), ir.IntType(64).as_pointer()]) func = ir.Function(self.module, fn, name=node.name) block = func.append_basic_block(name='.entry') builder = ir.IRBuilder(block) old = [self.func, self.builder] self.func, self.builder = func, builder for n, arg in enumerate(node.args): self._current_scope.resolve(arg.arg)["ptr"] = self.func.args[n] self.visit_sequence(node.body) self.builder.ret_void() self.func, self.builder = old self._current_scope = node._scope.parent_scope
def _define_atomic_inc_dec(module, op, ordering): """Define a llvm function for atomic increment/decrement to the given module Argument ``op`` is the operation "add"/"sub". Argument ``ordering`` is the memory ordering. The generated function returns the new value. """ ftype = ir.FunctionType(_word_type, [_word_type.as_pointer()]) fn_atomic = ir.Function(module, ftype, name="nrt_atomic_{0}".format(op)) [ptr] = fn_atomic.args bb = fn_atomic.append_basic_block() builder = ir.IRBuilder(bb) ONE = ir.Constant(_word_type, 1) oldval = builder.atomic_rmw(op, ptr, ONE, ordering=ordering) # Perform the operation on the old value so that we can pretend returning # the "new" value. res = getattr(builder, op)(oldval, ONE) builder.ret(res) return fn_atomic
def test_switch(self): block = self.block(name='my_block') builder = ir.IRBuilder(block) a, b = builder.function.args[:2] bb_onzero = builder.function.append_basic_block(name='onzero') bb_onone = builder.function.append_basic_block(name='onone') bb_ontwo = builder.function.append_basic_block(name='ontwo') bb_else = builder.function.append_basic_block(name='otherwise') sw = builder.switch(a, bb_else) sw.add_case(ir.Constant(int32, 0), bb_onzero) sw.add_case(ir.Constant(int32, 1), bb_onone) # A plain Python value gets converted into the right IR constant sw.add_case(2, bb_ontwo) self.assertTrue(block.is_terminated) self.check_block( block, """\ my_block: switch i32 %".1", label %"otherwise" [i32 0, label %"onzero" i32 1, label %"onone" i32 2, label %"ontwo"] """)
def dynamic_array_length(self, dyn_array_ptr, array_type): # START dyn_array_length_type = ir.FunctionType(type_map[INT], [dyn_array_ptr]) dyn_array_length = ir.Function(self.module, dyn_array_length_type, '{}.array.length'.format(str(array_type))) dyn_array_length.args[0].name = 'self' dyn_array_length_entry = dyn_array_length.append_basic_block('entry') builder = ir.IRBuilder(dyn_array_length_entry) self.builder = builder builder.position_at_end(dyn_array_length_entry) array_ptr = builder.alloca(dyn_array_ptr) builder.store(dyn_array_length.args[0], array_ptr) size_ptr = builder.gep(builder.load(array_ptr), [zero_32, zero_32], inbounds=True) # CLOSE self.define('{}.array.length'.format(str(array_type)), dyn_array_length) builder.ret(builder.load(size_ptr))
def dynamic_array_append(self, dyn_array_ptr, array_type): # START dyn_array_append_type = ir.FunctionType(type_map[VOID], [dyn_array_ptr, array_type]) dyn_array_append = ir.Function(self.module, dyn_array_append_type, '{}.array.append'.format(str(array_type))) dyn_array_append.args[0].name = 'self' dyn_array_append_entry = dyn_array_append.append_basic_block('entry') builder = ir.IRBuilder(dyn_array_append_entry) self.builder = builder dyn_array_append_exit = dyn_array_append.append_basic_block('exit') builder.position_at_end(dyn_array_append_entry) array_ptr = builder.alloca(dyn_array_ptr) builder.store(dyn_array_append.args[0], array_ptr) value_ptr = builder.alloca(array_type) builder.store(dyn_array_append.args[1], value_ptr) # BODY builder.call( self.module.get_global('{}.array.double_capacity_if_full'.format( str(array_type))), [builder.load(array_ptr)]) size_ptr = builder.gep(builder.load(array_ptr), [zero_32, zero_32], inbounds=True) size_val = builder.load(size_ptr) size_val = builder.add(size_val, one) builder.store(size_val, size_ptr) data_ptr = builder.gep(builder.load(array_ptr), [zero_32, two_32], inbounds=True) data_element_ptr = builder.gep(builder.load(data_ptr), [size_val], inbounds=True) builder.store(builder.load(value_ptr), data_element_ptr) builder.branch(dyn_array_append_exit) # CLOSE self.define('{}.array.append'.format(str(array_type)), dyn_array_append) builder.position_at_end(dyn_array_append_exit) builder.ret_void()
def eval(self, node, builder=None): if builder is None: builder = self.builder identifier = Node(self.name) node.children.extend([ Node("FUNCTION"), Node('type', self.typ), identifier, Node("{"), Node("block"), Node("}") ]) int_ = ir.IntType(32) flt_ = ir.FloatType() f_typ = {'int': int_, 'float': flt_} f_args = [f_typ[i.typ] for i in self.args.get_args()] fnty = ir.FunctionType(f_typ[self.typ], f_args) func = ir.Function(self.module, fnty, name=self.name) fnctns[self.name] = func block = func.append_basic_block(name="entry") f_builder = ir.IRBuilder(block) self.state.variables[f_builder.function] = {} self.state.variables[f_builder.function]['args'] = {} types_dict = {ir.IntType(32): 'INT', ir.FloatType(): 'FLT', str: 'STR'} for arg_ in range(len(func.args)): var_name = self.args.get_args()[arg_].name.getstr() var_type = func.args[arg_].type alloc = f_builder.alloca(var_type, size=None, name=var_name) if f_builder.function not in self.state.variables.keys(): self.state.variables[f_builder.function] = {} self.state.variables[f_builder.function][var_name] = { 'value': func.args[arg_], 'type': types_dict[var_type], 'ptr': alloc } f_builder.store(func.args[arg_], alloc) # print(self.state.variables) self.block.eval(Node('block'), builder=f_builder)
def visit_FunctionDef(self, node): # 引数の内容をたどる for a in (node.args.args): self.visit(a) # 関数の返り値と引数、関数名をセット self.fnty = ir.FunctionType( self.ret_type, tuple(self.arg_types)) self.func = ir.Function(self.module, self.fnty, node.name) self.func_name = node.name # entry bb_entry = self.func.append_basic_block() self.builder = ir.IRBuilder() self.builder.position_at_end(bb_entry) # 関数の内容をたどる for b in node.body: self.visit(b)
def test_union(builder: AstBuilder): cases = [ ('float', itype, False), ('float', ftype, True), ('int', itype, True), ('int', ftype, False), ('a', ftype, False), ('b', itype, False), ] for (name, type, should_work) in cases: try: union_obj = builder.call( builder.reference('FloatOrInt'), [builder.named_arg(name, builder.value(3, type))]) type_trace(union_obj, ctx) show_result(union_obj, ctx) bind = builder.bind('val', union_obj) module = ir.Module(name='test') # -- dummy main function fun = ir.Function(module, ftype=ir.FunctionType(ir.VoidType(), []), name='main') block = fun.append_basic_block('main_block') irbuilder = ir.IRBuilder(block) # ---- llvm_union = llvm_codegen(module=module, scope=ctx, expr=bind, builder=irbuilder) print() print(llvm_union.expr) except Exception as e: is_error(should_work, e) print('-' * 80)
def test_as_arg(self): """ - Is as_arg() and from_arg() implemented? - Are they the inverse of each other? """ fnty = ir.FunctionType(ir.VoidType(), []) function = ir.Function(self.module, fnty, name="test_as_arg") builder = ir.IRBuilder() builder.position_at_end(function.append_basic_block()) undef_value = ir.Constant(self.datamodel.get_value_type(), None) args = self.datamodel.as_argument(builder, undef_value) self.assertIsNot(args, NotImplemented, "as_argument returned " "NotImplementedError") if isinstance(args, (tuple, list)): def recur_tuplize(args, func=None): for arg in args: if isinstance(arg, (tuple, list)): yield tuple(recur_tuplize(arg, func=func)) else: if func is None: yield arg else: yield func(arg) argtypes = tuple(recur_tuplize(args, func=lambda x: x.type)) exptypes = tuple(recur_tuplize( self.datamodel.get_argument_type())) self.assertEqual(exptypes, argtypes) else: self.assertEqual(args.type, self.datamodel.get_argument_type()) rev_value = self.datamodel.from_argument(builder, args) self.assertEqual(rev_value.type, self.datamodel.get_value_type()) builder.ret_void() # end function # Ensure valid LLVM generation materialized = ll.parse_assembly(str(self.module)) str(materialized)
def gen_new_fields(self, cls: Class): name = cls.qualified_name.replace('.', '_') + '_init' if name in self.methods: return self.methods[name] cls_type = gen_class_struct(cls) func_type = ir.FunctionType(ir.VoidType(), [cls_type.as_pointer()]) func = ir.Function(self.module, func_type, name=name) self.methods[name] = func if cls.is_native: return self.methods[name] with self.new_env(): from cgen import RuntimeGen builder = ir.IRBuilder(func.append_basic_block('entry')) func = self.gen_new_fields(cls.superclass) builder.call(func, [ builder.bitcast(builder.function.args[0], func.ftype.args[0]) ]) ptr = builder.gep(builder.function.args[0], [ir.Constant(int32, 0), ir.Constant(int32, 0)], inbounds=True, name='classId_ptr') builder.store(ir.Constant(int32, RuntimeGen().classes.index(cls)), ptr) for field in cls.fields: if field.initializer: value = self.expr(field.initializer) ptr = self.builder.gep(self.builder.function.args[0], [ ir.Constant(int32, 0), ir.Constant( int32, field.owner.inherited_fields.index(field) + 1) ], inbounds=True, name=field.name + '_ptr') builder.store(value, ptr) builder.ret_void() return self.methods[name]
def test_float_comparisons(self): block = self.block(name='my_block') builder = ir.IRBuilder(block) a, b = builder.function.args[:2] builder.fcmp_ordered('==', a, b, 'c') builder.fcmp_ordered('!=', a, b, 'd') builder.fcmp_ordered('<', a, b, 'e') builder.fcmp_ordered('<=', a, b, 'f') builder.fcmp_ordered('>', a, b, 'g') builder.fcmp_ordered('>=', a, b, 'h') builder.fcmp_unordered('==', a, b, 'i') builder.fcmp_unordered('!=', a, b, 'j') builder.fcmp_unordered('<', a, b, 'k') builder.fcmp_unordered('<=', a, b, 'l') builder.fcmp_unordered('>', a, b, 'm') builder.fcmp_unordered('>=', a, b, 'n') # fcmp_ordered and fcmp_unordered are the same for these cases builder.fcmp_ordered('ord', a, b, 'u') builder.fcmp_ordered('uno', a, b, 'v') builder.fcmp_unordered('ord', a, b, 'w') builder.fcmp_unordered('uno', a, b, 'x') self.assertFalse(block.is_terminated) self.check_block( block, """\ my_block: %"c" = fcmp oeq i32 %".1", %".2" %"d" = fcmp one i32 %".1", %".2" %"e" = fcmp olt i32 %".1", %".2" %"f" = fcmp ole i32 %".1", %".2" %"g" = fcmp ogt i32 %".1", %".2" %"h" = fcmp oge i32 %".1", %".2" %"i" = fcmp ueq i32 %".1", %".2" %"j" = fcmp une i32 %".1", %".2" %"k" = fcmp ult i32 %".1", %".2" %"l" = fcmp ule i32 %".1", %".2" %"m" = fcmp ugt i32 %".1", %".2" %"n" = fcmp uge i32 %".1", %".2" %"u" = fcmp ord i32 %".1", %".2" %"v" = fcmp uno i32 %".1", %".2" %"w" = fcmp ord i32 %".1", %".2" %"x" = fcmp uno i32 %".1", %".2" """)
def gen_function_declaration(self, root): name = TppSemantic.get_function_name(root) body = TppSemantic.get_function_body(root) fn = self.module.get_global(name) self.current_scope = name entryBlock = fn.append_basic_block('entry') self.builder = ir.IRBuilder(entryBlock) i = 0 for var_symbol in self.context.symbols: if isinstance( var_symbol, VarSymbol ) and var_symbol.used and var_symbol.scope == fn.name and var_symbol.parameter: fn.args[i].name = var_symbol.name type_ = self.type_to_llvmlite_type(var_symbol.type_, var_symbol.index_list) a = self.builder.alloca(type_, name=var_symbol.name) self.builder.store(fn.args[i], a) a.align = 4 var_symbol.llvm_ref = a i += 1 self._traverse(body) fn_symbol = self.context.get_symbol(name, '@global') if fn_symbol.type_ == "vazio": self.builder.ret_void() self.current_scope = '@global' if self.last_block and not self.builder.block.is_terminated: if fn_symbol.type_ == "vazio": self.builder.ret_void() elif fn_symbol.type_ == "inteiro": self.builder.ret(ir.Constant(ir.IntType(32), 0)) else: self.builder.ret(ir.Constant(ir.DoubleType(), 0.0)) self.last_block = None
def test_binops_with_overflow(self): block = self.block(name='my_block') builder = ir.IRBuilder(block) a, b = builder.function.args[:2] builder.sadd_with_overflow(a, b, 'c') builder.smul_with_overflow(a, b, 'd') builder.ssub_with_overflow(a, b, 'e') builder.uadd_with_overflow(a, b, 'f') builder.umul_with_overflow(a, b, 'g') builder.usub_with_overflow(a, b, 'h') self.check_block( block, """\ my_block: %"c" = call {i32, i1} (i32, i32)* @"llvm.sadd.with.overflow.i32"(i32 %".1", i32 %".2") %"d" = call {i32, i1} (i32, i32)* @"llvm.smul.with.overflow.i32"(i32 %".1", i32 %".2") %"e" = call {i32, i1} (i32, i32)* @"llvm.ssub.with.overflow.i32"(i32 %".1", i32 %".2") %"f" = call {i32, i1} (i32, i32)* @"llvm.uadd.with.overflow.i32"(i32 %".1", i32 %".2") %"g" = call {i32, i1} (i32, i32)* @"llvm.umul.with.overflow.i32"(i32 %".1", i32 %".2") %"h" = call {i32, i1} (i32, i32)* @"llvm.usub.with.overflow.i32"(i32 %".1", i32 %".2") """)
def _codegen_FunctionAST(self, node): # Reset the symbol table. Prototype generation will pre-populate it with # function arguments. self.func_symtab = {} # Create the function skeleton from the prototype. func = self._codegen(node.proto) # Create the entry BB in the function and set the builder to it. bb_entry = func.append_basic_block('entry') self.builder = ir.IRBuilder(bb_entry) # Add all arguments to the symbol table and create their allocas for i, arg in enumerate(func.args): arg.name = node.proto.argnames[i] alloca = self.builder.alloca(ir.DoubleType(), name=arg.name) self.builder.store(arg, alloca) self.func_symtab[arg.name] = alloca retval = self._codegen(node.body) self.builder.ret(retval) return func
def gen_new(self, cls): name = cls.qualified_name.replace('.', '_') + '_new' if name in self.methods: return self.methods[name] cls_type = gen_class_struct(cls) return_type = cls_type.as_pointer() func_type = ir.FunctionType(return_type, []) func = ir.Function(self.module, func_type, name=name) self.methods[name] = func if cls.is_native: return self.methods[name] with self.new_env(): builder = ir.IRBuilder(func.append_basic_block('entry')) ret = builder.call(self.functions['new'], [ir.Constant(int32, cls_type.size)]) ret = builder.bitcast(ret, return_type) builder.call(self.gen_new_fields(cls), [ret]) builder.ret(builder.bitcast(ret, return_type)) return self.methods[name]
def compile(self, error_logger): """Compile the whole program as an LLVM module.""" global_scope = Scope() module = ir.Module() ir.Function( module, ir.FunctionType(i32_t, [ir.IntType(8).as_pointer()], var_arg=True), "printf") main_function = ir.Function(module, ir.FunctionType(i32_t, []), name="main") block = main_function.append_basic_block() builder = ir.IRBuilder(block) _compile_logging_errors(self.parts, global_scope, builder, error_logger) builder.ret(i32_t(0)) return module
def generate(self, module, scope): self.function = self._create_function(module) # Adds itself to scope scope[self.name] = self # Append block block = self.function.append_basic_block(self.name) builder = ir.IRBuilder(block) with scope() as scop: # allocate parameters self._allocate_args(builder, scop) # generate body block = builder.append_basic_block('body') builder.branch(block) with builder.goto_block(block): self.block.generate(builder, scop) return builder
def dynamic_array_append(compiler, dyn_array_struct_ptr): # START dyn_array_append_type = ir.FunctionType( type_map[VOID], [dyn_array_struct_ptr, type_map[INT]]) dyn_array_append = ir.Function(compiler.module, dyn_array_append_type, 'dyn_array_append') dyn_array_append_entry = dyn_array_append.append_basic_block('entry') builder = ir.IRBuilder(dyn_array_append_entry) compiler.builder = builder dyn_array_append_exit = dyn_array_append.append_basic_block('exit') builder.position_at_end(dyn_array_append_entry) array_ptr = builder.alloca(dyn_array_struct_ptr) builder.store(dyn_array_append.args[0], array_ptr) value_ptr = builder.alloca(type_map[INT]) builder.store(dyn_array_append.args[1], value_ptr) # BODY builder.call( compiler.module.get_global('dyn_array_double_capacity_if_full'), [builder.load(array_ptr)]) size_ptr = builder.gep(builder.load(array_ptr), [zero_32, zero_32], inbounds=True) size_val = builder.load(size_ptr) size_val = builder.add(size_val, one) builder.store(size_val, size_ptr) data_ptr = builder.gep(builder.load(array_ptr), [zero_32, two_32], inbounds=True) data_element_ptr = builder.gep(builder.load(data_ptr), [size_val], inbounds=True) builder.store(builder.load(value_ptr), data_element_ptr) builder.branch(dyn_array_append_exit) # CLOSE builder.position_at_end(dyn_array_append_exit) builder.ret_void()
def convert_var(exp, irb=ir.IRBuilder(), value=None): if exp['varname'] == 'M': # This shouldn't happen anymore assert False return M, lambda irb: irb.load(M) if exp['varid'] not in vars: if exp['varname'] == 'rsp_0': typ = pointertype else: typ = ir.IntType(int(exp['width'])) # Use registers for temporaries if exp['varname'] == "": if value is not None: vars[exp['varid']] = None exps[exp['varid']] = lambda irb: value else: varname = "v%d" % int(exp['varid']) print( "WARNING: %s accessed before defined. This should not happen." % exp, file=sys.stderr) assert False vars[exp['varid']] = irb.alloca(typ, name=varname) exps[exp['varid']] = lambda irb: irb.load(vars[exp['varid']]) else: varname = "pharos.reg." + exp['varname'] var = ir.GlobalVariable(module, typ, varname) var.initializer = ir.Constant(typ, None) var.linkage = 'internal' vars[exp['varid']] = var if exp['varname'] == 'rsp_0': # Most of the time we don't want to access rsp as a pointer exps[exp['varid']] = lambda irb: irb.ptrtoint( irb.load(vars[exp['varid']]), ir.IntType(int(exp['width'])) ) else: exps[exp['varid']] = lambda irb: irb.load(vars[exp['varid']]) return (vars[exp['varid']], exps[exp['varid']])
def test_helper_fclamp(mode): with pnlvm.LLVMBuilderContext() as ctx: local_vec = copy.deepcopy(VECTOR) double_ptr_ty = ctx.float_ty.as_pointer() func_ty = ir.FunctionType(ir.VoidType(), (double_ptr_ty, ctx.int32_ty, double_ptr_ty)) # Create clamp function custom_name = ctx.get_unique_name("clamp") function = ir.Function(ctx.module, func_ty, name=custom_name) vec, count, bounds = function.args block = function.append_basic_block(name="entry") builder = ir.IRBuilder(block) tst_min = builder.load(builder.gep(bounds, [ctx.int32_ty(0)])) tst_max = builder.load(builder.gep(bounds, [ctx.int32_ty(1)])) index = None with pnlvm.helpers.for_loop_zero_inc(builder, count, "linear") as (b1, index): val_ptr = b1.gep(vec, [index]) val = b1.load(val_ptr) val = pnlvm.helpers.fclamp(b1, val, tst_min, tst_max) b1.store(val, val_ptr) builder.ret_void() ref = np.clip(VECTOR, TST_MIN, TST_MAX) bounds = np.asfarray([TST_MIN, TST_MAX]) bin_f = pnlvm.LLVMBinaryFunction.get(custom_name) if mode == 'CPU': ct_ty = pnlvm._convert_llvm_ir_to_ctype(double_ptr_ty) ct_vec = local_vec.ctypes.data_as(ct_ty) ct_bounds = bounds.ctypes.data_as(ct_ty) bin_f(ct_vec, DIM_X, ct_bounds) else: bin_f.cuda_wrap_call(local_vec, np.int32(DIM_X), bounds) assert np.array_equal(local_vec, ref)
def declaracao_funcao(self, no): self.variaveis = self.variaveisGlobais args = [] nomes = [] if len(no.filhos) > 1: nome = no.filhos[1].valor self.escopo = nome if no.filhos[1].filhos[0] is not None: args = self.tipoDaFuncao(no.filhos[1].filhos[0], []) nomes = self.nomeDaFuncao(no.filhos[1].filhos[0], []) tipo = no.filhos[0].tipo if tipo == 'inteiro': t_func = ir.FunctionType(ir.IntType(32), (args)) else: t_func = ir.FunctionType(ir.FloatType(), (args)) else: nome = no.filhos[0].valor self.escopo = nome if no.filhos[0].filhos[0] is not None: args = self.tipoDaFuncao(no.filhos[0].filhos[0], []) nomes = self.nomeDaFuncao(no.filhos[0].filhos[0], []) t_func = ir.FunctionType(ir.VoidType(), (args)) func = ir.Function(self.module, t_func, nome) self.funcs.append(func) argumentos_llvm = func.args self.funcllvm = func entryBlock = func.append_basic_block('entry' + nome) builder = ir.IRBuilder(entryBlock) for x in range(0, len(argumentos_llvm)): if str(argumentos_llvm[x].tipo) == 'i32': var = builder.alloca(ir.IntType(32), name=str(nomes[x])) var.align = 4 self.variaveis.append(var) elif str(argumentos_llvm[x].tipo) == 'float': var = builder.alloca(ir.FloatType(), name=str(nomes[x])) var.align = 4 self.variaveis.append(var) self.redirecionamentoDoNo(no, builder) endBasicBlock = func.append_basic_block('exit' + nome) self.endBlock = endBasicBlock self.retorna(no, builder)
def visitForexpr(self, ctx: sadbeepParser.ForexprContext): self.visitAssign(ctx.init()) block_while = self.builder.append_basic_block(name='loop') block_next = self.builder.append_basic_block(name='next') self.builder.branch(block_while) # End the current block # Switch contex for the loop block with self.builder.goto_block(block_while): if self.visit(ctx.expr()).type != self.visit(ctx.cond).type: raise TypeError( f"{self.file_name} com erros na linha {ctx.start.line}:{ctx.start.column}" f" ({ctx.getText()}). Tipos diferentes!") if self.visit(ctx.expr()).type.__class__ == ir.FloatType: zero = ir.Constant(ir.FloatType(), 0) result = self.builder.fcmp_unordered('<', zero, self.visit(ctx.cond), name='tmp_w_cmp_float') elif self.visit(ctx.expr()).type.__class__ == ir.IntType: zero = ir.Constant(ir.IntType(32), 0) result = self.builder.icmp_signed('<', zero, self.visit(ctx.cond), name='tmp_w_cmp_float') else: raise TypeError( f"{self.file_name}:{ctx.start.line}:{ctx.start.column} - Tipo não reconhecido e/ou tratado!" ) with self.builder.if_then(result): # Execute if 0 < cond self.visit(ctx.block()) # Build while body self.visitAssign(ctx.finish()) self.builder.branch(block_while) # Loop self.builder.branch(block_next) # End loop ################################# self.builder = ir.IRBuilder( block_next) # Set the builder for the next block out of the loop
def test_cache(self): def times2(i): return 2*i def times3(i): return i*3 with self._context_builder_sig_args() as ( context, builder, sig, args, ): # Ensure the cache is empty to begin with self.assertEqual(0, len(context.cached_internal_func)) # After one compile, it should contain one entry context.compile_internal(builder, times2, sig, args) self.assertEqual(1, len(context.cached_internal_func)) # After a second compilation of the same thing, it should still contain # one entry context.compile_internal(builder, times2, sig, args) self.assertEqual(1, len(context.cached_internal_func)) # After compilation of another function, the cache should have grown by # one more. context.compile_internal(builder, times3, sig, args) self.assertEqual(2, len(context.cached_internal_func)) sig2 = typing.signature(types.float64, types.float64) llvm_fnty2 = context.call_conv.get_function_type(sig2.return_type, sig2.args) function2 = cgutils.get_or_insert_function(builder.module, llvm_fnty2, 'test_fn_2') args2 = context.call_conv.get_arguments(function2) assert function2.is_declaration entry_block2 = function2.append_basic_block('entry') builder2 = ir.IRBuilder(entry_block2) # Ensure that the same function with a different signature does not # reuse an entry from the cache in error context.compile_internal(builder2, times3, sig2, args2) self.assertEqual(3, len(context.cached_internal_func))
def compile(self, module: ir.Module, builder: ir.IRBuilder, symbols: SymbolTable) -> ir.Value: if not self.compiled: self.compiled = True parameters = [] for p in self.parameters: ir_type = p[1].ir_type if isinstance(p[1], Class): ir_type = ir_type.as_pointer() parameters.append(ir_type) self.func_type = ir.FunctionType(self.ret_type.ir_type, parameters) self.func = ir.Function(module, self.func_type, name=self.ID) symbols = SymbolTable(parent=symbols) for i, p in enumerate(self.parameters): self.func.args[i].name = p[0] symbols.add_symbol(p[0], self.func.args[i]) block = self.func.append_basic_block('entry') builder = ir.IRBuilder(block) self.block.compile(module, builder, symbols) block = builder.block if not builder.block.is_terminated: if self.ret_type == UnitType: builder.ret_void() else: builder.unreachable() return self.func else: return self.func
def visitFuncdef(self, ctx: EasyParser.FuncdefContext): """ This function handles function traslation :param ctx: :return: """ #It resets symbolic table -> so no global variables are allowed self.funcs_symtab.reset() funcname = str(ctx.NAME()) param = utils.getVarArgList(ctx.varparameters().varargslist()) arg_types = list(map(lambda x: x[1], param)) functype = ir.FunctionType(utils.getDtype(ctx.d_type()), arg_types) if funcname in self.module.globals: utils.printError(ctx, "Function already declared") sys.exit(0) else: func = ir.Function(self.module, functype, funcname) entry = func.append_basic_block('entry') self.builder = ir.IRBuilder(entry) for i, arg in enumerate(func.args): alloca = self.alloc(*param[i]) self.builder.store(arg, alloca) self.funcs_symtab.set(ctx, param[i][0], alloca) self.generateCode(ctx.block()) # Build the inner body of function if not self.builder.block.is_terminated: if functype.return_type == ir.VoidType(): # if the function is void type, we automatcaly # add return void self.builder.ret_void() else: utils.printError( ctx, "Function :{} is not terminated!!! " "by return statement".format(funcname)) sys.exit(0)
def build_ir(self): assert not self.captured_context.is_terminated with self.captured_context.use_pos(self.ast.pos): if self.ast.is_extern: if self.captured_symbol_table.has_extern_func( self.ast.identifier): extern_concrete_func = self.captured_symbol_table.get_extern_func( self.ast.identifier) if not extern_concrete_func.has_same_signature_as(self): raise_error( 'Cannot redefine extern func %r previously declared as %s with new signature %s' % (self.ast.identifier, extern_concrete_func.signature.to_signature_str(), self.signature.to_signature_str()), self.ast.pos) else: self.captured_symbol_table.add_extern_func( self.ast.identifier, self) return if self.ast.is_inline: # check symbol tables without emitting ir self.ast.build_body_ir( parent_symbol_table=self.captured_symbol_table, concrete_func=self, body_context=self.captured_context.copy_without_builder()) else: assert not self.is_inline if self.captured_context.emits_ir: body_block = self.ir_func.append_basic_block(name='entry') body_context = self.captured_context.copy_with_func( self, builder=ir.IRBuilder(body_block)) else: body_context = self.captured_context.copy_with_func( self, builder=None) # proceed without emitting ir. self.ast.build_body_ir( parent_symbol_table=self.captured_symbol_table, concrete_func=self, body_context=body_context, ir_func_args=self.ir_func.args if body_context.emits_ir else None)