swamp_code_gen/
lib.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 */
5pub mod alloc;
6mod anon_struct;
7mod assignment;
8mod bin_op;
9mod block;
10mod call;
11pub mod code_bld;
12pub mod constants;
13pub mod ctx;
14pub mod disasm;
15mod enum_variants;
16mod equal;
17mod err;
18mod expr;
19mod func;
20mod guard;
21mod host;
22mod init;
23mod initializer_list;
24mod initializer_pair_list;
25pub mod intr;
26mod iter;
27pub mod layout;
28mod literal;
29mod location;
30mod logical;
31mod lvalue;
32mod map;
33mod match_expr;
34mod postfix;
35pub mod prelude;
36pub mod reg_pool;
37mod relational;
38mod rvalue;
39mod sparse;
40pub mod state;
41mod statement;
42pub mod top_state;
43mod transfer;
44mod transfer_instr;
45mod transformer;
46mod tuple;
47mod variable;
48mod vec;
49mod when;
50
51pub const MAX_REGISTER_INDEX_FOR_PARAMETERS: u8 = 6;
52
53use crate::alloc::StackFrameAllocator;
54use crate::reg_pool::TempRegister;
55use seq_map::SeqMap;
56use source_map_node::Node;
57use swamp_semantic::intr::IntrinsicFunction;
58use swamp_semantic::{
59    ArgumentExpression, ConstantId, ConstantRef, Expression, ExpressionKind,
60    InternalFunctionDefinitionRef, InternalFunctionId, VariableScopes,
61};
62use swamp_types::TypeRef;
63use swamp_vm_isa::{InstructionPosition, MemorySize};
64use swamp_vm_layout::LayoutCache;
65use swamp_vm_types::types::{
66    BasicTypeRef, FrameMemoryInfo, FramePlacedType, FunctionInfoKind, HeapPlacedType,
67    TypedRegister, VmType,
68};
69use swamp_vm_types::{
70    CountU16, FrameMemoryRegion, InstructionRange, TempFrameMemoryAddress, ZFlagPolarity,
71};
72
73#[derive(Clone)]
74pub struct SpilledRegister {
75    pub register: TypedRegister,
76    pub frame_memory_region: FrameMemoryRegion,
77}
78
79#[derive(Clone)]
80pub enum RepresentationOfRegisters {
81    Individual(Vec<TypedRegister>),
82    Range { start_reg: u8, count: u8 },
83    Mask(u8),
84}
85
86#[derive(Clone)]
87pub struct SpilledRegisterRegion {
88    pub registers: RepresentationOfRegisters,
89    pub frame_memory_region: FrameMemoryRegion,
90}
91
92#[derive(Clone)]
93pub struct SpilledRegisterScope {
94    pub regions: Vec<SpilledRegisterRegion>,
95}
96
97pub struct ArgumentAndTempScope {
98    pub argument_registers: SpilledRegisterRegion,
99    pub scratch_registers: Option<SpilledRegisterRegion>,
100}
101
102pub struct SpilledRegisterScopes {
103    pub stack: Vec<SpilledRegisterScope>,
104}
105
106impl Default for SpilledRegisterScopes {
107    fn default() -> Self {
108        Self::new()
109    }
110}
111
112impl SpilledRegisterScopes {
113    #[must_use]
114    pub const fn new() -> Self {
115        Self { stack: Vec::new() }
116    }
117    pub fn push(&mut self, scope: SpilledRegisterScope) {
118        self.stack.push(scope);
119    }
120
121    pub fn pop(&mut self) -> SpilledRegisterScope {
122        self.stack.pop().unwrap()
123    }
124}
125
126pub enum DetailedLocationResolved {
127    Register(TypedRegister),
128    TempRegister(TempRegister),
129}
130
131impl DetailedLocationResolved {
132    #[must_use]
133    pub const fn register(&self) -> &TypedRegister {
134        match self {
135            Self::Register(reg) => reg,
136            Self::TempRegister(reg) => reg.register(),
137        }
138    }
139}
140
141#[derive(Clone)]
142pub enum FunctionIpKind {
143    Normal(InternalFunctionId),
144    Constant(ConstantId),
145}
146
147#[derive(Clone)]
148pub struct FunctionIp {
149    ip_range: InstructionRange,
150    pub kind: FunctionIpKind,
151}
152
153#[derive(PartialEq, Eq, Debug)]
154pub enum FlagStateKind {
155    TFlagIsIndeterminate,
156    TFlagIsTrueWhenSet,
157    TFlagIsTrueWhenClear,
158}
159
160pub struct FlagState {
161    pub kind: FlagStateKind,
162}
163
164impl FlagState {
165    pub(crate) fn invert_polarity(&self) -> Self {
166        Self {
167            kind: self.kind.invert_polarity(),
168        }
169    }
170}
171
172impl FlagStateKind {
173    pub(crate) fn invert_polarity(&self) -> Self {
174        match self {
175            Self::TFlagIsIndeterminate => {
176                panic!("can not invert polarity. status is unknown")
177            }
178            Self::TFlagIsTrueWhenSet => Self::TFlagIsTrueWhenClear,
179            Self::TFlagIsTrueWhenClear => Self::TFlagIsTrueWhenSet,
180        }
181    }
182
183    pub(crate) fn polarity(&self) -> ZFlagPolarity {
184        match self {
185            Self::TFlagIsIndeterminate => panic!("polarity is undefined"),
186            Self::TFlagIsTrueWhenSet => ZFlagPolarity::TrueWhenSet,
187            Self::TFlagIsTrueWhenClear => ZFlagPolarity::TrueWhenClear,
188        }
189    }
190}
191
192impl FlagState {
193    pub(crate) fn polarity(&self) -> ZFlagPolarity {
194        self.kind.polarity()
195    }
196}
197
198impl Default for FlagState {
199    fn default() -> Self {
200        Self {
201            kind: FlagStateKind::TFlagIsIndeterminate,
202        }
203    }
204}
205
206pub struct SlicePairInfo {
207    pub addr: TempFrameMemoryAddress,
208    pub key_size: MemorySize,
209    pub value_size: MemorySize,
210    pub element_count: CountU16,
211    pub element_size: MemorySize,
212}
213
214#[derive(Clone, Debug)]
215pub struct GenFunctionInfo {
216    pub ip_range: InstructionRange,
217    pub return_type: BasicTypeRef,
218    pub params: Vec<BasicTypeRef>,
219    pub internal_function_definition: InternalFunctionDefinitionRef,
220}
221
222impl GenFunctionInfo {
223    #[must_use]
224    pub fn return_type(&self) -> &TypeRef {
225        &self.internal_function_definition.signature.return_type
226    }
227}
228
229pub struct ConstantInfo {
230    pub ip_range: InstructionRange,
231    pub constant_ref: ConstantRef,
232    pub return_type: BasicTypeRef,
233    pub target_constant_memory: HeapPlacedType,
234}
235
236pub struct FunctionIps {
237    ranges: Vec<FunctionIp>,
238}
239
240impl Default for FunctionIps {
241    fn default() -> Self {
242        Self::new()
243    }
244}
245
246impl FunctionIps {
247    #[must_use]
248    pub const fn new() -> Self {
249        Self { ranges: Vec::new() }
250    }
251
252    #[must_use]
253    pub fn get_function_end_from_start(&self, ip: InstructionPosition) -> Option<FunctionIp> {
254        for range in &self.ranges {
255            if range.ip_range.start.0 == ip.0 {
256                return Some(range.clone());
257            }
258        }
259
260        None
261    }
262}
263
264pub fn reserve(
265    ty: &TypeRef,
266    layout_cache: &mut LayoutCache,
267    allocator: &mut StackFrameAllocator,
268) -> FramePlacedType {
269    allocator.reserve(layout_cache, ty)
270}
271
272pub struct FrameAndVariableInfo {
273    pub frame_memory: FrameMemoryInfo,
274    pub return_type: VmType,
275    parameter_and_variable_offsets: SeqMap<usize, TypedRegister>,
276    local_frame_allocator: StackFrameAllocator,
277}
278
279#[derive(Debug)]
280pub struct FunctionInData {
281    pub function_name_node: Node,
282    pub kind: FunctionInfoKind,
283    pub assigned_name: String,
284    pub function_variables: VariableScopes,
285    pub return_type: TypeRef,
286    pub expression: Expression,
287}
288
289fn single_intrinsic_fn(
290    body: &Expression,
291) -> Option<(&IntrinsicFunction, &Vec<ArgumentExpression>)> {
292    let ExpressionKind::Block(block_expressions) = &body.kind else {
293        return None;
294    };
295
296    if block_expressions.is_empty() {
297        return None;
298    }
299    if let ExpressionKind::IntrinsicCallEx(found_intrinsic_fn, arguments) =
300        &block_expressions[0].kind
301    {
302        Some((found_intrinsic_fn, arguments))
303    } else {
304        None
305    }
306}