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