1use crate::alloc::StackFrameAllocator;
7use crate::FrameAndVariableInfo;
8use seq_map::SeqMap;
9use source_map_node::Node;
10use std::fmt::Write;
11use swamp_semantic::{VariableScopes, VariableType};
12use swamp_types::TypeRef;
13use swamp_vm_isa::MemorySize;
14use swamp_vm_layout::LayoutCache;
15use swamp_vm_types::types::{
16 FrameAddressInfo, FrameMemoryInfo, TypedRegister, VariableInfo, VariableInfoKind,
17 VariableRegister, VmType,
18};
19use swamp_vm_types::{FrameMemoryAddress, FrameMemoryRegion};
20
21#[allow(clippy::too_many_lines)]
24#[must_use]
25pub fn layout_variables(
26 layout_cache: &mut LayoutCache,
27 _node: &Node,
28 scopes: &VariableScopes,
29 exp_return_type: &TypeRef,
30) -> FrameAndVariableInfo {
31 let mut local_frame_allocator = StackFrameAllocator::new(FrameMemoryRegion::new(
32 FrameMemoryAddress(0),
33 MemorySize(1024 * 1024 * 1024),
34 ));
35
36 let mut enter_comment = "variables:\n".to_string();
37 let mut frame_memory_infos = Vec::new();
38
39 let mut all_variable_unique_to_register = SeqMap::new();
40
41 let mut variable_registers_for_debug_info = Vec::new();
42 for var_ref in &scopes.all_variables {
43 let basic_type = layout_cache.layout(&var_ref.resolved_type);
44
45 let vm_type = if basic_type.is_reg_copy() {
46 VmType::new_contained_in_register(basic_type)
48 } else {
49 swamp_vm_layout::check_type_size(
51 &basic_type,
52 &format!("variable '{}'", var_ref.assigned_name),
53 );
54
55 let kind = match var_ref.variable_type {
56 VariableType::Local => VariableInfoKind::Variable(VariableInfo {
57 is_mutable: var_ref.is_mutable(),
58 name: var_ref.assigned_name.clone(),
59 }),
60 VariableType::Parameter => VariableInfoKind::Parameter(VariableInfo {
61 is_mutable: var_ref.is_mutable(),
62 name: var_ref.assigned_name.clone(),
63 }),
64 };
65
66 if matches!(var_ref.variable_type, VariableType::Local) {
67 let var_frame_placed_type = local_frame_allocator.allocate_type(&basic_type);
68 writeln!(
70 &mut enter_comment,
71 " {}:{} {}",
72 var_frame_placed_type.addr(),
73 var_frame_placed_type.size().0,
74 var_ref.assigned_name
75 )
76 .unwrap();
77
78 frame_memory_infos.push(FrameAddressInfo {
79 kind,
80 frame_placed_type: var_frame_placed_type.clone(),
81 });
82 VmType::new_frame_placed(var_frame_placed_type)
83 } else {
84 VmType::new_contained_in_register(basic_type)
86 }
87 };
88
89 let typed_register = TypedRegister {
90 index: var_ref.virtual_register,
91 ty: vm_type,
92 comment: String::new(),
93 };
94
95 all_variable_unique_to_register
97 .insert(var_ref.unique_id_within_function, typed_register.clone())
98 .unwrap();
99
100 let var_register = VariableRegister {
101 unique_id_in_function: var_ref.unique_id_within_function,
102 variable: VariableInfo {
103 is_mutable: var_ref.is_mutable(),
104 name: var_ref.assigned_name.clone(),
105 },
106 register: typed_register.clone(),
107 };
108 variable_registers_for_debug_info.push(var_register);
109 }
110
111 let variable_space = local_frame_allocator.addr().as_size();
112
113 let frame_size = local_frame_allocator.addr().as_size();
114
115 let return_type_ref = TypeRef::from(exp_return_type.clone());
116 let return_type = VmType::new_contained_in_register(layout_cache.layout(&return_type_ref));
117
118 FrameAndVariableInfo {
119 frame_memory: FrameMemoryInfo {
120 infos: frame_memory_infos,
121 total_frame_size: frame_size,
122 variable_frame_size: frame_size,
123 frame_size_for_variables_except_temp: variable_space,
124 variable_registers: variable_registers_for_debug_info,
125 },
126 local_frame_allocator,
127 return_type,
128 parameter_and_variable_offsets: all_variable_unique_to_register,
129 }
130}