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 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 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 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 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 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}