from __future__ import annotations import llvmlite.ir as ir class MemoryOpsMixin: def _register_local_heap_ptr(self, val, ClassName=None, VarName=None): if isinstance(val.type, ir.PointerType): pointee = val.type.pointee if isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): self._local_heap_ptrs.append((val, 'struct', ClassName)) elif isinstance(pointee, ir.IntType) and pointee.width == 8: self._local_heap_ptrs.append((val, 'i8', ClassName)) if VarName: self._var_to_heap_ptr[VarName] = val def _unregister_local_heap_ptr(self, val): self._local_heap_ptrs = [(v, t, cn) for v, t, cn in self._local_heap_ptrs if v is not val] def _emit_local_heap_frees(self): if not self._local_heap_ptrs or not self.builder: return # 创建一个集合来跟踪已经删除的对象 deleted_objects = set() for ptr, ptr_type, ClassName in self._local_heap_ptrs: # 先检查指针是否为 null if ptr_type == 'i8': # 对于 i8* 类型的指针,加载其值并检查是否为 null Loaded_ptr = self.builder.load(ptr, name="load_ptr") null_ptr = ir.Constant(ir.PointerType(ir.IntType(8)), None) is_null = self.builder.icmp_unsigned('==', Loaded_ptr, null_ptr, name="is_null") # 创建一个基本块来处理非 null 的情况 not_null_block = self.builder.append_basic_block(name="not_null") # 创建一个基本块来处理下一个对象 next_block = self.builder.append_basic_block(name="next") # 如果指针为 null,跳转到下一个对象 self.builder.cbranch(is_null, next_block, not_null_block) # 切换到非 null 的基本块 self.builder.position_at_end(not_null_block) # 然后调用 __del__ 方法 if ClassName and self._has_function(f'{ClassName}.__del__'): if isinstance(ptr.type, ir.PointerType) and isinstance(ptr.type.pointee, ir.IntType) and ptr.type.pointee.width == 8: cast_ptr = self.builder.bitcast(ptr, ir.PointerType(self.structs[ClassName]), name=f"cast_{ClassName}") else: cast_ptr = ptr if cast_ptr not in deleted_objects: self.builder.call(self._get_function(f'{ClassName}.__del__'), [cast_ptr], name=f"call_{ClassName}.__del__") deleted_objects.add(cast_ptr) # 最后释放内存 if ptr_type == 'struct': raw = self.builder.bitcast(ptr, ir.PointerType(ir.IntType(8)), name="local_free_cast") elif ptr_type == 'i8': raw = ptr else: continue free_type = ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8))]) free_func = self._get_or_declare_func('free', free_type) self.builder.call(free_func, [raw]) # 如果是 i8* 类型的指针,跳转到下一个对象 if ptr_type == 'i8': self.builder.branch(next_block) # 切换到下一个对象的基本块 self.builder.position_at_end(next_block) self._local_heap_ptrs = [] def _RegisterTempPtr(self, val): if isinstance(val.type, ir.PointerType): pointee = val.type.pointee if isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): for CN, ST in self.structs.items(): if pointee == ST: self._temp_struct_ptrs.append(val) return elif isinstance(pointee, ir.IntType) and pointee.width == 8: self._temp_struct_ptrs.append(val) def _UnregisterTempPtr(self, val): self._temp_struct_ptrs = [t for t in self._temp_struct_ptrs if t is not val] def _EmitTempFrees(self): if not self._temp_struct_ptrs or not self.builder: return for ptr in self._temp_struct_ptrs: if isinstance(ptr.type, ir.PointerType) and isinstance(ptr.type.pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): raw = self.builder.bitcast(ptr, ir.PointerType(ir.IntType(8)), name="free_cast") elif isinstance(ptr.type, ir.PointerType) and isinstance(ptr.type.pointee, ir.IntType) and ptr.type.pointee.width == 8: raw = ptr else: continue free_type = ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8))]) free_func = self._get_or_declare_func('free', free_type) self.builder.call(free_func, [raw]) self._temp_struct_ptrs = [] def _ZeroConst(self, typ): if isinstance(typ, ir.PointerType): return ir.Constant(typ, None) return ir.Constant(typ, 0) def _alloca(self, typ, name='', align=None, size=None): if align is None: align = self._get_align(typ) if size is not None: instr = self.builder.alloca(typ, size=size, name=name) else: instr = self.builder.alloca(typ, name=name) if align: instr.align = align return instr def _allocaEntry(self, typ, name='', align=None): if align is None: align = self._get_align(typ) saved_block = self.builder.block entry_block = self.func.entry_basic_block if entry_block.instructions: first_instr = entry_block.instructions[0] self.builder.position_before(first_instr) instr = self.builder.alloca(typ, name=name) if align: instr.align = align self.builder.position_at_end(saved_block) else: self.builder.position_at_start(entry_block) instr = self.builder.alloca(typ, name=name) if align: instr.align = align self.builder.position_at_end(saved_block) return instr def _load(self, ptr, name='', align=None): if align is None: if isinstance(ptr.type, ir.PointerType): align = self._get_align(ptr.type.pointee) else: align = 0 if isinstance(ptr.type, ir.PointerType): pointee_type = ptr.type.pointee if isinstance(pointee_type, ir.IdentifiedStructType) and pointee_type.name in self.typedef_int_widths: width = self.typedef_int_widths[pointee_type.name] if width > 0: actual_type = ir.IntType(width) bitcast_ptr = self.builder.bitcast(ptr, ir.PointerType(actual_type), name="typedef_bitcast_Load") return self.builder.load(bitcast_ptr, name=name, align=align) return self.builder.load(ptr, name=name, align=align) def _Load_var(self, name): if name in self._direct_values: return self._direct_values[name] if name in self.variables and self.variables[name] is not None: VarPtr = self.variables[name] if isinstance(VarPtr, ir.GlobalVariable) and isinstance(VarPtr.type, ir.PointerType) and isinstance(VarPtr.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)): return VarPtr if isinstance(VarPtr.type, ir.PointerType) and isinstance(VarPtr.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)): return VarPtr return self._load(VarPtr, name=name) if name in self.global_vars and name in self.module.globals: GVar = self.module.globals[name] self.variables[name] = GVar if isinstance(GVar, ir.Function): return GVar if isinstance(GVar.type, ir.PointerType) and isinstance(GVar.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)): return GVar return self._load(GVar, name=name) if name in self.module.globals: GVar = self.module.globals[name] self.variables[name] = GVar if isinstance(GVar, ir.Function): return GVar if isinstance(GVar.type, ir.PointerType) and isinstance(GVar.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)): return GVar return self._load(GVar, name=name) return None def _store_var(self, name, value): if name in self._direct_values: old_val = self._direct_values.pop(name) if name not in self.variables or self.variables[name] is None: var = self.builder.alloca(old_val.type, name=name) self._store(old_val, var) self.variables[name] = var if name in self.variables and self.variables[name] is not None: self._store(value, self.variables[name]) else: var = self.builder.alloca(value.type, name=name) self._store(value, var) self.variables[name] = var def _ensure_alloca(self, name, llvm_type): if name in self._direct_values: val = self._direct_values.pop(name) var = self.builder.alloca(llvm_type, name=name) self._store(val, var) self.variables[name] = var return var if name in self.variables and self.variables[name] is not None: return self.variables[name] var = self.builder.alloca(llvm_type, name=name) self.variables[name] = var return var def _coerce_value(self, val, target_type): if val.type == target_type: return val if isinstance(target_type, ir.IdentifiedStructType) and target_type.name in self.typedef_int_widths: if isinstance(val.type, ir.IntType): return val if isinstance(target_type, ir.IntType) and isinstance(val.type, ir.IntType): if target_type.width < val.type.width: return self.builder.trunc(val, target_type, name="trunc_store") else: # 使用 sext(符号扩展)以正确处理负数 return self.builder.sext(val, target_type, name="sext_store") if isinstance(target_type, ir.PointerType) and isinstance(val.type, ir.PointerType): if isinstance(val, ir.Constant) and val.constant is None: return ir.Constant(target_type, None) return self.builder.bitcast(val, target_type, name="ptr_bitcast_store") if isinstance(target_type, ir.PointerType) and isinstance(val.type, ir.IntType): if val.type.width < 64: val = self.builder.zext(val, ir.IntType(64), name="zext_ptr_store") return self.builder.inttoptr(val, target_type, name="int_to_ptr_store") if isinstance(target_type, ir.IntType) and isinstance(val.type, ir.PointerType): if isinstance(val.type.pointee, ir.IntType) and val.type.pointee.width == target_type.width: return self.builder.load(val, name="load_ptr_as_int_store") if target_type.width <= 8 and isinstance(val.type.pointee, ir.IntType): Loaded = self.builder.load(val, name="load_ptr_byte_store") if Loaded.type != target_type: if isinstance(Loaded.type, ir.IntType) and isinstance(target_type, ir.IntType): if target_type.width < Loaded.type.width: return self.builder.trunc(Loaded, target_type, name="trunc_ptr_byte_store") return self.builder.zext(Loaded, target_type, name="zext_ptr_byte_store") return Loaded return self.builder.ptrtoint(val, target_type, name="ptr_to_int_store") if isinstance(target_type, ir.FloatType) and isinstance(val.type, ir.DoubleType): return self.builder.fptrunc(val, target_type, name="fptrunc_store") if isinstance(target_type, ir.DoubleType) and isinstance(val.type, ir.FloatType): return self.builder.fpext(val, target_type, name="fpext_store") if isinstance(target_type, ir.IntType) and isinstance(val.type, (ir.FloatType, ir.DoubleType)): return self.builder.fptosi(val, target_type, name="fptosi_store") if isinstance(target_type, (ir.FloatType, ir.DoubleType)) and isinstance(val.type, ir.IntType): return self.builder.sitofp(val, target_type, name="sitofp_store") if isinstance(target_type, ir.ArrayType) and isinstance(val.type, ir.ArrayType): if target_type.count == val.type.count and target_type.element == val.type.element: return val if (isinstance(target_type.element, ir.IntType) and target_type.element.width == 8 and isinstance(val.type.element, ir.IntType) and val.type.element.width == 8): if target_type.count > val.type.count: padded = list(val.constant) if hasattr(val, 'constant') else [] if padded and len(padded) == val.type.count: padded.extend([ir.Constant(ir.IntType(8), 0)] * (target_type.count - val.type.count)) return ir.Constant(target_type, padded) elif target_type.count < val.type.count: trimmed = list(val.constant) if hasattr(val, 'constant') else [] if trimmed and len(trimmed) == val.type.count: return ir.Constant(target_type, trimmed[:target_type.count]) if isinstance(val.type, ir.PointerType) and not isinstance(target_type, ir.PointerType): if val.type.pointee == target_type: return self.builder.load(val, name="Load_struct_for_store") if isinstance(val.type.pointee, ir.IdentifiedStructType) and isinstance(target_type, ir.IdentifiedStructType): if val.type.pointee.name == target_type.name: Loaded = self.builder.load(val, name="Load_struct_for_store") if Loaded.type == target_type: return Loaded return None def _store(self, val, ptr, align=None): if align is None: if isinstance(ptr.type, ir.PointerType): align = self._get_align(ptr.type.pointee) else: align = 0 if isinstance(ptr.type, ir.PointerType): target_type = ptr.type.pointee if isinstance(target_type, ir.IdentifiedStructType) and target_type.name in self.typedef_int_widths: if isinstance(val.type, ir.IntType): width = self.typedef_int_widths[target_type.name] if width > 0: actual_type = ir.IntType(width) bitcast_ptr = self.builder.bitcast(ptr, ir.PointerType(actual_type), name="typedef_bitcast") if val.type.width != actual_type.width: if val.type.width > actual_type.width: val = self.builder.trunc(val, actual_type, name="trunc_typedef") else: val = self.builder.zext(val, actual_type, name="zext_typedef") return self.builder.store(val, bitcast_ptr, align=align) if val.type != target_type: if isinstance(val, ir.Constant) and val.constant is None: if isinstance(target_type, ir.PointerType): val = ir.Constant(target_type, None) elif isinstance(target_type, ir.IdentifiedStructType): val = ir.Constant(ir.PointerType(target_type), None) ptr = self.builder.bitcast(ptr, ir.PointerType(ir.PointerType(target_type)), name="null_struct_ptr_cast") else: coerced = self._coerce_value(val, target_type) if coerced is not None: val = coerced else: src_info = self._get_node_info() raise TypeError(f"cannot store {val.type} to {ptr.type}: mismatching types{src_info}") return self.builder.store(val, ptr, align=align) def _get_var_ptr(self, name): if name in self._reg_values: val = self._reg_values[name] var = self._alloca(val.type, name=name) self._store(val, var) self.variables[name] = var del self._reg_values[name] return var if name in self.variables and self.variables[name] is not None: return self.variables[name] return None