swamp_code_gen/
layout.rs

1/*
2 * Copyright (c) Peter Bjorklund. All rights reserved. https://github.com/swamp/swamp
3 * Licensed under the MIT License. See LICENSE in the project root for license information.
4 */
5
6use 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/// # Errors
21///
22#[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    //info!("layout variables");
36    //    let return_placed_type_pointer = layout_type(exp_return_type).create_mutable_pointer();
37    //let return_placed_type = allocator.allocate_type(return_placed_type_pointer); //reserve(return_placed_type_pointer, &mut allocator);
38
39    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 frame_register_allocator = RegisterPool::new(1, 127);
44
45    //info!(len = variables.len(), "variables");
46
47    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        //info!(var_ref.assigned_name, ?frame_register_allocator, "allocating local variable");
52        let vm_type = if basic_type.is_aggregate() {
53            // TODO: Should have a check if the variable needs the storage (if it is in an assignment in a copy)
54            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                //trace!(?var_ref.assigned_name, ?var_frame_placed_type, "laying out");
73                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                // even if it is an aggregate, parameters do not need any frame memory, they are allocated elsewhere
89                VmType::new_contained_in_register(basic_type)
90            }
91        } else {
92            // If it is a scalar, then it is in a register no matter if it is a parameter or local
93            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        //info!(unique_id=?var_ref.unique_id_within_function, name=?var_ref.assigned_name, "insert variable");
103        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}