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::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/// # Errors
22///
23#[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            // If it is a scalar, then it is in a register no matter if it is a parameter or local
47            VmType::new_contained_in_register(basic_type)
48        } else {
49            // TODO: Should have a check if the variable needs the storage (if it is in an assignment in a copy)
50            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                //trace!(?var_ref.assigned_name, ?var_frame_placed_type, "laying out");
69                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                // even if it is an aggregate, parameters do not need any frame memory, they are allocated elsewhere
85                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        //info!(unique_id=?var_ref.unique_id_within_function, name=?var_ref.assigned_name, "insert variable");
96        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}