nessa/
translation.rs

1use crate::{compilation::CompiledNessaExpr, context::NessaContext, operations::{Operator, ADD_BINOP_ID, ANDB_BINOP_ID, AND_BINOP_ID, ASSIGN_BINOP_ID, DEREF_UNOP_ID, DIV_BINOP_ID, EQ_BINOP_ID, GTEQ_BINOP_ID, GT_BINOP_ID, LTEQ_BINOP_ID, LT_BINOP_ID, MOD_BINOP_ID, MUL_BINOP_ID, NEG_UNOP_ID, NEQ_BINOP_ID, NOT_UNOP_ID, ORB_BINOP_ID, OR_BINOP_ID, SHL_BINOP_ID, SHR_BINOP_ID, SUB_BINOP_ID, XOR_BINOP_ID}, types::{Type, BOOL_ID, FLOAT_ID, INT, INT_ID, STR_ID}};
2
3fn load_unop_opcodes<F: Fn(&Type) -> Option<CompiledNessaExpr>>(ctx: &mut NessaContext, id: usize, f: F) {
4    if let Operator::Unary { operations, .. } = &ctx.unary_ops[id] {
5        for (ov_id, op_ov) in operations.iter().enumerate() {
6            if let Some(opcode) = f(&op_ov.args) {
7                let mut offset = op_ov.args.is_ref() as usize;
8
9                if opcode.needs_float() {
10                    offset += (*op_ov.args.deref_type() == INT) as usize;
11                }
12
13                ctx.cache.opcodes.unary.insert((id, ov_id), (opcode, offset));
14            }
15        }
16    }
17}
18
19fn load_binop_opcodes<F: Fn(&Type, &Type) -> Option<CompiledNessaExpr>>(ctx: &mut NessaContext, id: usize, f: F) {
20    if let Operator::Binary { operations, .. } = &ctx.binary_ops[id] {
21        for (ov_id, op_ov) in operations.iter().enumerate() {
22            if let Type::And(types) = &op_ov.args {
23                if let Some(opcode) = f(&types[0], &types[1]) {
24                    let mut offset = (types[0].is_ref() as usize) + (types[1].is_ref() as usize);
25
26                    if opcode.needs_float() {
27                        offset += (*types[0].deref_type() == INT) as usize;
28                        offset += (*types[1].deref_type() == INT) as usize;
29                    }
30
31                    ctx.cache.opcodes.binary.insert((id, ov_id), (opcode, offset));
32                }
33                
34            } else {
35                unreachable!();
36            }
37        }
38    }
39}
40
41pub fn load_optimized_binop_opcodes(ctx: &mut NessaContext) {
42    use CompiledNessaExpr::*;
43
44    // Arithmetic and Bitwise
45    let ids = [
46        ADD_BINOP_ID, SUB_BINOP_ID, MUL_BINOP_ID, DIV_BINOP_ID, MOD_BINOP_ID,
47        LT_BINOP_ID, GT_BINOP_ID, LTEQ_BINOP_ID, GTEQ_BINOP_ID, EQ_BINOP_ID, NEQ_BINOP_ID,
48        ANDB_BINOP_ID, ORB_BINOP_ID, XOR_BINOP_ID, SHL_BINOP_ID, SHR_BINOP_ID
49    ];
50
51    let opcodes = [
52        (Addi, Addf), (Subi, Subf), (Muli, Mulf), (Divi, Divf), (Modi, Modf),
53        (Lti, Ltf), (Gti, Gtf), (Lteqi, Lteqf), (Gteqi, Gteqf), (Eqi, Eqf), (Neqi, Neqf),
54        (AndB, Halt), (OrB, Halt), (XorB, Halt), (Shl, Halt), (Shr, Halt)
55    ];
56
57    for (id, (i_opcode, f_opcode)) in ids.iter().zip(opcodes) {
58        load_binop_opcodes(ctx, *id, |a, b| {
59            return match (a.deref_type(), b.deref_type()) {
60                (Type::Basic(INT_ID), Type::Basic(INT_ID)) => Some(i_opcode.clone()),
61                (Type::Basic(FLOAT_ID), Type::Basic(FLOAT_ID)) => Some(f_opcode.clone()),
62                (Type::Basic(INT_ID), Type::Basic(FLOAT_ID)) => Some(f_opcode.clone()),
63                (Type::Basic(FLOAT_ID), Type::Basic(INT_ID)) => Some(f_opcode.clone()),
64                _ => None
65            }
66        });
67    }
68
69    // String opcodes
70    let ids = [
71        EQ_BINOP_ID, NEQ_BINOP_ID, ADD_BINOP_ID
72    ];
73
74    let opcodes = [
75        EqStr, NeqStr, AddStr
76    ];
77    
78    for (id, opcode) in ids.iter().zip(opcodes) {
79        load_binop_opcodes(ctx, *id, |a, b| {
80            return match (a.deref_type(), b.deref_type()) {
81                (Type::Basic(STR_ID), Type::Basic(STR_ID)) => Some(opcode.clone()),
82                _ => None
83            }
84        });
85    }
86
87    // Bool opcodes
88    let ids = [
89        EQ_BINOP_ID, NEQ_BINOP_ID
90    ];
91
92    let opcodes = [
93        EqBool, NeqBool
94    ];
95    
96    for (id, opcode) in ids.iter().zip(opcodes) {
97        load_binop_opcodes(ctx, *id, |a, b| {
98            return match (a.deref_type(), b.deref_type()) {
99                (Type::Basic(BOOL_ID), Type::Basic(BOOL_ID)) => Some(opcode.clone()),
100                _ => None
101            }
102        });
103    }
104
105    // Logical
106    let ids = [OR_BINOP_ID, AND_BINOP_ID, XOR_BINOP_ID];
107    let opcodes = [Or, And, Xor];
108
109    for (id, opcode) in ids.iter().zip(opcodes) {
110        load_binop_opcodes(ctx, *id, |a, b| {
111            return match (a.deref_type(), b.deref_type()) {
112                (Type::Basic(BOOL_ID), Type::Basic(BOOL_ID)) => Some(opcode.clone()),
113                _ => None
114            }
115        });
116    }
117
118    // Other
119    ctx.cache.opcodes.binary.insert((ASSIGN_BINOP_ID, 0), (Assign, 0));
120}
121
122pub fn load_optimized_unop_opcodes(ctx: &mut NessaContext) {
123    use CompiledNessaExpr::*;
124
125    ctx.cache.opcodes.unary.insert((DEREF_UNOP_ID, 0), (Copy, 0));
126    ctx.cache.opcodes.unary.insert((DEREF_UNOP_ID, 1), (Copy, 0));
127
128    let ids = [NEG_UNOP_ID, NOT_UNOP_ID];
129    let opcodes = [(Negi, Negf), (NotB, Halt)];
130
131    for (id, (i_opcode, f_opcode)) in ids.iter().zip(opcodes) {
132        load_unop_opcodes(ctx, *id, |a| {
133            return match a.deref_type() {
134                Type::Basic(INT_ID) => Some(i_opcode.clone()),
135                Type::Basic(FLOAT_ID) => Some(f_opcode.clone()),
136                _ => None
137            }
138        });
139    }
140
141    let ids = [NOT_UNOP_ID];
142    let opcodes = [Not];
143
144    for (id, opcode) in ids.iter().zip(opcodes) {
145        load_unop_opcodes(ctx, *id, |a| {
146            return match a.deref_type() {
147                Type::Basic(BOOL_ID) => Some(opcode.clone()),
148                _ => None
149            }
150        });
151    }
152}
153
154pub fn load_optimized_fn_opcodes(ctx: &mut NessaContext) {
155    use CompiledNessaExpr::*;
156
157    let deref_id = ctx.get_function_id("deref".into()).unwrap();
158    ctx.cache.opcodes.functions.insert((deref_id, 0), (Copy, 0));
159    ctx.cache.opcodes.functions.insert((deref_id, 1), (Copy, 0));
160    
161    let demut_id = ctx.get_function_id("demut".into()).unwrap();
162    ctx.cache.opcodes.functions.insert((demut_id, 0), (Demut, 0));
163
164    let move_id = ctx.get_function_id("move".into()).unwrap();
165    ctx.cache.opcodes.functions.insert((move_id, 0), (Move, 0));
166
167    let ref_id = ctx.get_function_id("ref".into()).unwrap();
168    ctx.cache.opcodes.functions.insert((ref_id, 0), (Ref, 0));
169
170    let mut_id = ctx.get_function_id("mut".into()).unwrap();
171    ctx.cache.opcodes.functions.insert((mut_id, 0), (Mut, 0));
172
173    let inc_id = ctx.get_function_id("inc".into()).unwrap();
174    ctx.cache.opcodes.functions.insert((inc_id, 0), (Inc, 0));
175
176    let dec_id = ctx.get_function_id("dec".into()).unwrap();
177    ctx.cache.opcodes.functions.insert((dec_id, 0), (Dec, 0));
178}
179
180pub fn load_optimized_opcodes(ctx: &mut NessaContext) {
181    load_optimized_unop_opcodes(ctx);
182    load_optimized_binop_opcodes(ctx);
183    load_optimized_fn_opcodes(ctx);
184}