def build_or_get_function(self, parent, volpe_args): module: ir.Module = parent.builder.module func_args = unwrap(self.args()) if not isinstance(volpe_args, VolpeObject): func_args = ir.LiteralStructType([func_args]) for func in module.functions: if func.name == self.name: break else: func_type = ir.FunctionType(unwrap(self.ret()), func_args) func = ir.Function(module, func_type, self.name) volpe_func_type = ir.FunctionType(unwrap( self.ret()), [ir.LiteralStructType([]), unwrap(self.args())]) volpe_func = ir.Function(module, volpe_func_type, str(next(module.func_count))) with build_func(volpe_func) as (b, args): b: ir.IRBuilder args = [args[1]] if isinstance(volpe_args, VolpeObject): args = [ b.extract_value(args[0], i) for i in range(len(volpe_args.type_dict)) ] b.ret(b.call(func, args)) return volpe_func
def constant_array(self, tree: TypeTree): value = self.visit(tree.children[0]) array_value = unwrap(tree.return_type)(ir.Undefined) if tree.return_type.count == 0: return array_value array_value = self.builder.insert_element(array_value, value, int64(0)) mask = ir.VectorType( int32, tree.return_type.count)([0] * tree.return_type.count) return self.builder.shuffle_vector( array_value, unwrap(tree.return_type)(ir.Undefined), mask)
def volpe_llvm(tree: TypeTree, verbose=False, more_verbose=False, console=False): if more_verbose: print(tree.pretty()) arg_scope = {} def scope(name, local_tree: TypeTree): if name in arg_scope: return arg_scope[name] raise VolpeError(f"variable `{name}` not found", local_tree) AnnotateScope(tree, scope) if verbose: print(tree.pretty()) module = ir.Module("program") module.func_count = itertools.count() run_func = ir.Function( module, ir.FunctionType(unknown, [unwrap(tree.return_type).as_pointer()]), "run") with build_func(run_func) as (b, args): arg_scope = {} def scope(name): return arg_scope[name] def ret(value): b.store(value, args[0], 8) b.ret_void() LLVMScope(b, tree, scope, ret, None) return str(module)
def determine_c_type(volpe_type): """Interpret the volpe type and return a corresponding C type.""" if DEBUG_BUFFER: return get_padding(64) # Simple types: if volpe_type == int1: return c_bool if volpe_type == int64: return c_int64 if volpe_type == flt64: return c_double if volpe_type == char: return c_char # Aggregate types: if isinstance(volpe_type, VolpeObject): # Create fields with padding in between to counteract abi incompatibility. # Fields begin with '*' to avoid name collision with Structure attributes. fields = [] pos = 0 for i, (key, value) in enumerate(volpe_type.type_dict.items()): ll_type = unwrap(volpe_type)._get_ll_pointer_type( target_data).element_type pad_needed = target_data.get_element_offset(ll_type, i) - pos if pad_needed != 0: fields.append((f"*pad_at_{pos}_size_{pad_needed}", get_padding(pad_needed))) pos += pad_needed c_type = determine_c_type(value) fields.append((f"*{key}", c_type)) pos += sizeof(c_type) class CObject(Structure): _fields_ = fields def __repr__(self): # Filter out padding fields. keys = [key for (key, _) in self._fields_ if key[:4] != "*pad"] # Field names are being shown only if they don't begin with an underscore. res = "{" + ", ".join( [("" if key[1] == "_" else f"{key[1:]}: ") + get_repr(getattr(self, key)) for key in keys]) + "}" return res return CObject if isinstance(volpe_type, VolpeArray): class CArray(Structure): _fields_ = [ ("elements", determine_c_type(volpe_type.element) * volpe_type.count) ] def __repr__(self): if volpe_type.element == char: try: return f'"{bytes(self).decode(ENCODING)}"' except UnicodeDecodeError: # if not valid ascii, use default repr, but replace b' ' with b" " return f'"{repr(self.elements[:])[2:-1]}"' else: return repr(self.elements[:]) return CArray if isinstance(volpe_type, VolpeClosure): class CFunc(Structure): _fields_ = [(key, determine_c_type(value)) for key, value in volpe_type.env.items()] def __repr__(self): return f"closure (line {volpe_type.tree.meta.line})" return CFunc # Unknown type return None
def object(self, tree: TypeTree): value = unwrap(tree.return_type)(ir.Undefined) for i, child in enumerate(tree.children): key, attribute = get_obj_key_value(child, i) value = self.builder.insert_value(value, self.visit(attribute), i) return value
def block(self, tree: TypeTree): with options(self.builder, unwrap(tree.return_type)) as (ret, phi): self.__class__(self.builder, tree, self.get_scope, ret, None) return phi
def func(self, tree: TypeTree): closure = unwrap(tree.return_type)(ir.Undefined) for i, name in enumerate(tree.return_type.env.keys()): closure = self.builder.insert_value(closure, self.get_scope(name), i) return closure
def make_pointer(self, tree: TypeTree): value = self.visit(tree.children[0]) ptr = self.builder.alloca(value.type) self.builder.store(value, ptr) return self.builder.bitcast(ptr, unwrap(tree.return_type))
def array(self, tree: TypeTree): array_value = unwrap(tree.return_type)(ir.Undefined) for i, ret in enumerate(self.visit_children(tree)): array_value = self.builder.insert_element(array_value, ret, int64(i)) return array_value